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

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.

99
dist/scorm-again.js vendored

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

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": {

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;
}

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({

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;