Adding ability to deregister event listeners

This commit is contained in:
Jonathan Putney
2020-12-14 12:17:43 -05:00
parent cae17ee511
commit 28fe544ef5
8 changed files with 309 additions and 19 deletions
+20
View File
@@ -177,6 +177,16 @@ window.API.on("LMSSetValue.cmi.*", function(CMIElement, value) {
});
```
You also have to ability to remove specific callback listeners:
```javascript
window.API.off("LMSInitialize", callback);
```
Or, you can clear all callbacks for a particular event:
```javascript
window.API.clear("LMSInitialize");
```
### SCORM 2004 Listeners
For convenience, hooks are available for all the SCORM API Signature functions:
@@ -220,6 +230,16 @@ window.API_1484_11.on("SetValue.cmi.* ", function(CMIElement, value) {
});
```
You also have to ability to remove specific callback listeners:
```javascript
window.API_1484_11.off("Initialize", callback);
```
Or, you can clear all callbacks for a particular event:
```javascript
window.API_1484_11.clear("Initialize");
```
### Total Time Calculation
The APIs provide a convenience method `getCurrentTotalTime()` that can be used for calculating the current `total_time` value, based on the current `session_time` and the `total_time` supplied when the module was launched. This works for both ISO 8601 duration time formats in SCORM 2004 as well as the HH:MM:SS format in SCORM 1.2 and AICC, and outputs the correct format based on the version used.
+90 -9
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "scorm-again",
"version": "1.4.5",
"version": "1.5.0",
"description": "A modern SCORM JavaScript run-time library for AICC, SCORM 1.2, and SCORM 2004",
"main": "dist/scorm-again.min.js",
"directories": {
+64 -7
View File
@@ -772,6 +772,66 @@ export default class BaseAPI {
CMIElement: CMIElement,
callback: callback,
});
this.apiLog('on', functionName, `Added event listener: ${this.listenerArray.length}`, global_constants.LOG_LEVEL_INFO);
}
}
/**
* Provides a mechanism for detaching a specific SCORM event listener
*
* @param {string} listenerName
* @param {function} callback
*/
off(listenerName: String, callback: function) {
if (!callback) return;
const listenerFunctions = listenerName.split(' ');
for (let i = 0; i < listenerFunctions.length; i++) {
const listenerSplit = listenerFunctions[i].split('.');
if (listenerSplit.length === 0) return;
const functionName = listenerSplit[0];
let CMIElement = null;
if (listenerSplit.length > 1) {
CMIElement = listenerName.replace(functionName + '.', '');
}
const removeIndex = this.listenerArray.findIndex((obj) =>
obj.functionName === functionName &&
obj.CMIElement === CMIElement &&
obj.callback === callback
);
if (removeIndex !== -1) {
this.listenerArray.splice(removeIndex, 1);
this.apiLog('off', functionName, `Removed event listener: ${this.listenerArray.length}`, global_constants.LOG_LEVEL_INFO);
}
}
}
/**
* Provides a mechanism for clearing all listeners from a specific SCORM event
*
* @param {string} listenerName
*/
clear(listenerName: String) {
const listenerFunctions = listenerName.split(' ');
for (let i = 0; i < listenerFunctions.length; i++) {
const listenerSplit = listenerFunctions[i].split('.');
if (listenerSplit.length === 0) return;
const functionName = listenerSplit[0];
let CMIElement = null;
if (listenerSplit.length > 1) {
CMIElement = listenerName.replace(functionName + '.', '');
}
this.listenerArray = this.listenerArray.filter((obj) =>
obj.functionName !== functionName &&
obj.CMIElement !== CMIElement,
);
}
}
@@ -1023,13 +1083,6 @@ export default class BaseAPI {
} else {
result = JSON.parse(httpReq.responseText);
}
if (result.result === true ||
result.result === global_constants.SCORM_TRUE) {
api.processListeners('CommitSuccess');
} else {
api.processListeners('CommitError');
}
};
}
try {
@@ -1053,10 +1106,12 @@ export default class BaseAPI {
result = {};
result.result = global_constants.SCORM_TRUE;
result.errorCode = 0;
api.processListeners('CommitSuccess');
return result;
}
} catch (e) {
console.error(e);
api.processListeners('CommitError');
return genericError;
}
} else {
@@ -1081,11 +1136,13 @@ export default class BaseAPI {
}
} catch (e) {
console.error(e);
api.processListeners('CommitError');
return genericError;
}
}
if (typeof result === 'undefined') {
api.processListeners('CommitError');
return genericError;
}
+56
View File
@@ -448,6 +448,62 @@ describe('SCORM 1.2 API Tests', () => {
clock.tick(2000);
expect(callback.called).to.be.true;
});
it('Should clear all event listeners for CommitSuccess',
() => {
const scorm12API = api({
lmsCommitUrl: '/scorm12',
autocommit: true,
autocommitSeconds: 1,
});
scorm12API.lmsInitialize();
const callback = sinon.spy();
const callback2 = sinon.spy();
scorm12API.on('CommitSuccess', callback);
scorm12API.on('CommitSuccess', callback2);
scorm12API.lmsSetValue('cmi.core.session_time', '00:01:00');
clock.tick(2000);
expect(callback.calledOnce).to.be.true;
expect(callback2.calledOnce).to.be.true;
scorm12API.clear('CommitSuccess');
scorm12API.lmsSetValue('cmi.core.session_time', '00:01:00');
clock.tick(2000);
expect(callback.calledTwice).to.be.false;
expect(callback2.calledTwice).to.be.false;
});
it('Should clear only the specific event listener for CommitSuccess',
() => {
const scorm12API = api({
lmsCommitUrl: '/scorm12',
autocommit: true,
autocommitSeconds: 1,
});
scorm12API.lmsInitialize();
const callback = sinon.spy(() => 1);
const callback2 = sinon.spy(() => 2);
const callback3 = sinon.spy(() => 3);
scorm12API.on('CommitSuccess', callback);
scorm12API.on('CommitSuccess', callback2);
scorm12API.on('LMSSetValue', callback3);
scorm12API.lmsSetValue('cmi.core.session_time', '00:01:00');
clock.tick(2000);
expect(callback.calledOnce).to.be.true;
expect(callback2.calledOnce).to.be.true;
expect(callback3.calledOnce).to.be.true;
scorm12API.off('CommitSuccess', callback);
scorm12API.lmsSetValue('cmi.core.session_time', '00:01:00');
clock.tick(2000);
expect(callback.calledTwice).to.be.false; // removed callback should not be called a second time
expect(callback2.calledTwice).to.be.true;
expect(callback3.calledTwice).to.be.true;
});
it('Should handle CommitError event',
() => {
const scorm12API = api({
+76
View File
@@ -38,6 +38,10 @@ describe('SCORM 2004 API Tests', () => {
server.post('/scorm2004/error', () => {
return [500, {'Content-Type': 'application/json'}, '{}'];
}, false);
server.unhandledRequest = function(verb, path, request) {
// do nothing
};
});
after(() => {
@@ -645,6 +649,62 @@ describe('SCORM 2004 API Tests', () => {
clock.tick(2000);
expect(callback.called).to.be.true;
});
it('Should clear all event listeners for CommitSuccess',
() => {
const scorm2004API = api({
lmsCommitUrl: '/scorm2004',
autocommit: true,
autocommitSeconds: 1,
});
scorm2004API.lmsInitialize();
const callback = sinon.spy();
const callback2 = sinon.spy();
scorm2004API.on('CommitSuccess', callback);
scorm2004API.on('CommitSuccess', callback2);
scorm2004API.lmsSetValue('cmi.session_time', 'PT1M0S');
clock.tick(2000);
expect(callback.calledOnce).to.be.true;
expect(callback2.calledOnce).to.be.true;
scorm2004API.clear('CommitSuccess');
scorm2004API.lmsSetValue('cmi.session_time', 'PT1M0S');
clock.tick(2000);
expect(callback.calledTwice).to.be.false;
expect(callback2.calledTwice).to.be.false;
});
it('Should clear only the specific event listener for CommitSuccess',
() => {
const scorm2004API = api({
lmsCommitUrl: '/scorm2004',
autocommit: true,
autocommitSeconds: 1,
});
scorm2004API.lmsInitialize();
const callback = sinon.spy(() => 1);
const callback2 = sinon.spy(() => 2);
const callback3 = sinon.spy(() => 3);
scorm2004API.on('CommitSuccess', callback);
scorm2004API.on('CommitSuccess', callback2);
scorm2004API.on('SetValue', callback3);
scorm2004API.lmsSetValue('cmi.session_time', 'PT1M0S');
clock.tick(2000);
expect(callback.calledOnce).to.be.true;
expect(callback2.calledOnce).to.be.true;
expect(callback3.calledOnce).to.be.true;
scorm2004API.off('CommitSuccess', callback);
scorm2004API.lmsSetValue('cmi.session_time', 'PT1M0S');
clock.tick(2000);
expect(callback.calledTwice).to.be.false; // removed callback should not be called a second time
expect(callback2.calledTwice).to.be.true;
expect(callback3.calledTwice).to.be.true;
});
it('Should handle CommitError event',
() => {
const scorm2004API = api({
@@ -657,6 +717,22 @@ describe('SCORM 2004 API Tests', () => {
const callback = sinon.spy();
scorm2004API.on('CommitError', callback);
scorm2004API.lmsSetValue('cmi.session_time', 'PT1M0S');
clock.tick(2000);
expect(callback.called).to.be.true;
});
it('Should handle CommitError event when offline',
() => {
const scorm2004API = api({
lmsCommitUrl: '/scorm2004/does_not_exist',
autocommit: true,
autocommitSeconds: 1,
});
scorm2004API.lmsInitialize();
const callback = sinon.spy();
scorm2004API.on('CommitError', callback);
scorm2004API.lmsSetValue('cmi.session_time', 'PT1M0S');
clock.tick(2000);
expect(callback.called).to.be.true;