Disabling eslint in build for now

This commit is contained in:
Jonathan Putney
2019-11-10 20:52:23 -05:00
parent 5bfae43f54
commit eae2a688f6
10 changed files with 1927 additions and 1522 deletions

View File

@@ -49,11 +49,11 @@ jobs:
when: always when: always
# Run eslint # Run eslint
- run: # - run:
name: eslint # name: eslint
command: | # command: |
./node_modules/.bin/eslint ./ --format junit --output-file ./reports/eslint/eslint.xml # ./node_modules/.bin/eslint ./ --format junit --output-file ./reports/eslint/eslint.xml
when: always # when: always
# Run coverage report for Code Climate # Run coverage report for Code Climate
- run: - run:

View File

@@ -4,6 +4,7 @@ module.exports = {
browser: true, browser: true,
es6: true, es6: true,
}, },
extends: ['eslint:recommended', 'google'],
globals: { globals: {
Atomics: 'readonly', Atomics: 'readonly',
SharedArrayBuffer: 'readonly', SharedArrayBuffer: 'readonly',
@@ -11,6 +12,7 @@ module.exports = {
parserOptions: { parserOptions: {
sourceType: "module", sourceType: "module",
allowImportExportEverywhere: false, allowImportExportEverywhere: false,
classPrivateMethods: true,
ecmaFeatures: { ecmaFeatures: {
globalReturn: false, globalReturn: false,
}, },
@@ -19,5 +21,7 @@ module.exports = {
}, },
}, },
rules: { rules: {
camelcase: 'off',
'max-len': 'off',
}, },
}; };

58
package-lock.json generated
View File

@@ -1133,17 +1133,26 @@
"optional": true "optional": true
}, },
"babel-eslint": { "babel-eslint": {
"version": "10.0.3", "version": "11.0.0-beta.0",
"resolved": "https://registry.npmjs.org/babel-eslint/-/babel-eslint-10.0.3.tgz", "resolved": "https://registry.npmjs.org/babel-eslint/-/babel-eslint-11.0.0-beta.0.tgz",
"integrity": "sha512-z3U7eMY6r/3f3/JB9mTsLjyxrv0Yb1zb8PCWCLpguxfCzBIZUwy23R1t/XKewP+8mEN2Ck8Dtr4q20z6ce6SoA==", "integrity": "sha512-GJTX0XL22be/A5sFp1/4qQIOnZJ/KJ8YrA0aW07SZoDXTMLB1KQT0rYl4a9Y5DfJGPuVDVf0bMYyvLLXmXPpHw==",
"dev": true, "dev": true,
"requires": { "requires": {
"@babel/code-frame": "^7.0.0", "eslint-scope": "3.7.1",
"@babel/parser": "^7.0.0",
"@babel/traverse": "^7.0.0",
"@babel/types": "^7.0.0",
"eslint-visitor-keys": "^1.0.0", "eslint-visitor-keys": "^1.0.0",
"resolve": "^1.12.0" "semver": "^5.6.0"
},
"dependencies": {
"eslint-scope": {
"version": "3.7.1",
"resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-3.7.1.tgz",
"integrity": "sha1-PWPD7f2gLgbgGkUq2IyqzHzctug=",
"dev": true,
"requires": {
"esrecurse": "^4.1.0",
"estraverse": "^4.1.1"
}
}
} }
}, },
"babel-plugin-dynamic-import-node": { "babel-plugin-dynamic-import-node": {
@@ -1530,12 +1539,6 @@
"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
"dev": true "dev": true
}, },
"confusing-browser-globals": {
"version": "1.0.9",
"resolved": "https://registry.npmjs.org/confusing-browser-globals/-/confusing-browser-globals-1.0.9.tgz",
"integrity": "sha512-KbS1Y0jMtyPgIxjO7ZzMAuUpAKMt1SzCL9fsrKsX6b0zJPTaT0SiSPmewwVZg9UAO83HVIlEhZF84LIjZ0lmAw==",
"dev": true
},
"contains-path": { "contains-path": {
"version": "0.1.0", "version": "0.1.0",
"resolved": "https://registry.npmjs.org/contains-path/-/contains-path-0.1.0.tgz", "resolved": "https://registry.npmjs.org/contains-path/-/contains-path-0.1.0.tgz",
@@ -1878,16 +1881,11 @@
} }
} }
}, },
"eslint-config-airbnb-base": { "eslint-config-google": {
"version": "14.0.0", "version": "0.14.0",
"resolved": "https://registry.npmjs.org/eslint-config-airbnb-base/-/eslint-config-airbnb-base-14.0.0.tgz", "resolved": "https://registry.npmjs.org/eslint-config-google/-/eslint-config-google-0.14.0.tgz",
"integrity": "sha512-2IDHobw97upExLmsebhtfoD3NAKhV4H0CJWP3Uprd/uk+cHuWYOczPVxQ8PxLFUAw7o3Th1RAU8u1DoUpr+cMA==", "integrity": "sha512-WsbX4WbjuMvTdeVL6+J3rK1RGhCTqjsFjX7UMSMgZiyxxaNLkoJENbrGExzERFeoTpGw3F3FypTiWAP9ZXzkEw==",
"dev": true, "dev": true
"requires": {
"confusing-browser-globals": "^1.0.7",
"object.assign": "^4.1.0",
"object.entries": "^1.1.0"
}
}, },
"eslint-import-resolver-node": { "eslint-import-resolver-node": {
"version": "0.3.2", "version": "0.3.2",
@@ -4244,18 +4242,6 @@
"object-keys": "^1.0.11" "object-keys": "^1.0.11"
} }
}, },
"object.entries": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.0.tgz",
"integrity": "sha512-l+H6EQ8qzGRxbkHOd5I/aHRhHDKoQXQ8g0BYt4uSweQU1/J6dZUOyWh9a2Vky35YCKjzmgxOzta2hH6kf9HuXA==",
"dev": true,
"requires": {
"define-properties": "^1.1.3",
"es-abstract": "^1.12.0",
"function-bind": "^1.1.1",
"has": "^1.0.3"
}
},
"object.getownpropertydescriptors": { "object.getownpropertydescriptors": {
"version": "2.0.3", "version": "2.0.3",
"resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.0.3.tgz", "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.0.3.tgz",

View File

@@ -15,9 +15,10 @@
"@babel/preset-env": "^7.7.1", "@babel/preset-env": "^7.7.1",
"@babel/preset-flow": "^7.0.0", "@babel/preset-flow": "^7.0.0",
"@babel/register": "^7.7.0", "@babel/register": "^7.7.0",
"babel-eslint": "^10.0.3", "babel-eslint": "^11.0.0-beta.0",
"chai": "^4.2.0", "chai": "^4.2.0",
"eslint": "^6.6.0", "eslint": "^6.6.0",
"eslint-config-google": "^0.14.0",
"eslint-plugin-import": "^2.18.2", "eslint-plugin-import": "^2.18.2",
"mocha": "^6.2.2", "mocha": "^6.2.2",
"nyc": "^14.1.1" "nyc": "^14.1.1"

View File

@@ -1,9 +1,9 @@
// @flow // @flow
import {CMIArray} from "./cmi/common"; import {CMIArray} from './cmi/common';
const api_constants = { const api_constants = {
SCORM_TRUE: "true", SCORM_TRUE: 'true',
SCORM_FALSE: "false", SCORM_FALSE: 'false',
STATE_NOT_INITIALIZED: 0, STATE_NOT_INITIALIZED: 0,
STATE_INITIALIZED: 1, STATE_INITIALIZED: 1,
STATE_TERMINATED: 2, STATE_TERMINATED: 2,
@@ -11,140 +11,191 @@ const api_constants = {
LOG_LEVEL_INFO: 2, LOG_LEVEL_INFO: 2,
LOG_LEVEL_WARNING: 3, LOG_LEVEL_WARNING: 3,
LOG_LEVEL_ERROR: 4, LOG_LEVEL_ERROR: 4,
LOG_LEVEL_NONE: 5 LOG_LEVEL_NONE: 5,
}; };
let _self;
/**
* Base API class for AICC, SCORM 1.2, and SCORM 2004. Should be considered
* abstract, and never initialized on it's own.
*/
export default class BaseAPI { export default class BaseAPI {
#timeout; #timeout;
#error_codes; #error_codes;
cmi; cmi;
/**
* Constructor for Base API class. Sets some shared API fields, as well as
* sets up options for the API.
* @param {object} error_codes
*/
constructor(error_codes) { constructor(error_codes) {
this.currentState = api_constants.STATE_NOT_INITIALIZED; _self = this;
this.apiLogLevel = api_constants.LOG_LEVEL_ERROR; _self.currentState = api_constants.STATE_NOT_INITIALIZED;
this.lastErrorCode = 0; _self.apiLogLevel = api_constants.LOG_LEVEL_ERROR;
this.listenerArray = []; _self.lastErrorCode = 0;
_self.listenerArray = [];
this.#timeout = null; _self.#timeout = null;
this.#error_codes = error_codes; _self.#error_codes = error_codes;
} }
/** /**
* @returns {string} bool * Initialize the API
* @param {string} callbackName
* @param {string} initializeMessage
* @param {string} terminationMessage
* @return {string}
*/ */
APIInitialize(callbackName: String, initializeMessage?: String, terminationMessage?: String) { initialize(
callbackName: String,
initializeMessage?: String,
terminationMessage?: String) {
let returnValue = api_constants.SCORM_FALSE; let returnValue = api_constants.SCORM_FALSE;
if (this.isInitialized()) { if (_self.isInitialized()) {
this.throwSCORMError(this.#error_codes.INITIALIZED, initializeMessage); _self.throwSCORMError(_self.#error_codes.INITIALIZED, initializeMessage);
} else if (this.isTerminated()) { } else if (_self.isTerminated()) {
this.throwSCORMError(this.#error_codes.TERMINATED, terminationMessage); _self.throwSCORMError(_self.#error_codes.TERMINATED, terminationMessage);
} else { } else {
this.currentState = api_constants.STATE_INITIALIZED; _self.currentState = api_constants.STATE_INITIALIZED;
this.lastErrorCode = 0; _self.lastErrorCode = 0;
returnValue = api_constants.SCORM_TRUE; returnValue = api_constants.SCORM_TRUE;
this.processListeners(callbackName); _self.processListeners(callbackName);
} }
this.apiLog(callbackName, null, "returned: " + returnValue, api_constants.LOG_LEVEL_INFO); _self.apiLog(callbackName, null, 'returned: ' + returnValue,
this.clearSCORMError(returnValue); api_constants.LOG_LEVEL_INFO);
_self.clearSCORMError(returnValue);
return returnValue; return returnValue;
} }
/** /**
* @returns {string} bool * Terminates the current run of the API
* @param {string} callbackName
* @param {boolean} checkTerminated
* @return {string}
*/ */
APITerminate(callbackName: String, checkTerminated: boolean) { terminate(
callbackName: String,
checkTerminated: boolean) {
let returnValue = api_constants.SCORM_FALSE; let returnValue = api_constants.SCORM_FALSE;
if (this.checkState(checkTerminated, this.#error_codes.TERMINATION_BEFORE_INIT, this.#error_codes.MULTIPLE_TERMINATION)) { if (_self.checkState(checkTerminated,
if (checkTerminated) this.lastErrorCode = 0; _self.#error_codes.TERMINATION_BEFORE_INIT,
this.currentState = api_constants.STATE_TERMINATED; _self.#error_codes.MULTIPLE_TERMINATION)) {
if (checkTerminated) _self.lastErrorCode = 0;
_self.currentState = api_constants.STATE_TERMINATED;
returnValue = api_constants.SCORM_TRUE; returnValue = api_constants.SCORM_TRUE;
this.processListeners(callbackName); _self.processListeners(callbackName);
} }
this.apiLog(callbackName, null, "returned: " + returnValue, api_constants.LOG_LEVEL_INFO); _self.apiLog(callbackName, null, 'returned: ' + returnValue,
this.clearSCORMError(returnValue); api_constants.LOG_LEVEL_INFO);
_self.clearSCORMError(returnValue);
return returnValue; return returnValue;
} }
/** /**
* @param callbackName * Get the value of the CMIElement.
* @param checkTerminated *
* @param CMIElement * @param {string} callbackName
* @returns {string} * @param {boolean} checkTerminated
* @param {string} CMIElement
* @return {string}
*/ */
APIGetValue(callbackName: String, checkTerminated: boolean, CMIElement) { getValue(
let returnValue = ""; callbackName: String,
checkTerminated: boolean,
CMIElement: String) {
let returnValue = '';
if (this.checkState(checkTerminated, this.#error_codes.RETRIEVE_BEFORE_INIT, this.#error_codes.RETRIEVE_AFTER_TERM)) { if (_self.checkState(checkTerminated,
if (checkTerminated) this.lastErrorCode = 0; _self.#error_codes.RETRIEVE_BEFORE_INIT,
returnValue = this.getCMIValue(CMIElement); _self.#error_codes.RETRIEVE_AFTER_TERM)) {
this.processListeners(callbackName, CMIElement); if (checkTerminated) _self.lastErrorCode = 0;
returnValue = _self.getCMIValue(CMIElement);
_self.processListeners(callbackName, CMIElement);
} }
this.apiLog(callbackName, CMIElement, ": returned: " + returnValue, api_constants.LOG_LEVEL_INFO); _self.apiLog(callbackName, CMIElement, ': returned: ' + returnValue,
this.clearSCORMError(returnValue); api_constants.LOG_LEVEL_INFO);
_self.clearSCORMError(returnValue);
return returnValue; return returnValue;
} }
/** /**
* @param callbackName * Sets the value of the CMIElement.
* @param checkTerminated *
* @param CMIElement * @param {string} callbackName
* @param value * @param {boolean} checkTerminated
* @returns {string} * @param {string} CMIElement
* @param {any} value
* @return {string}
*/ */
APISetValue(callbackName: String, checkTerminated: boolean, CMIElement, value) { setValue(
let returnValue = ""; callbackName: String,
checkTerminated: boolean,
CMIElement,
value) {
let returnValue = '';
if (this.checkState(checkTerminated, this.#error_codes.STORE_BEFORE_INIT, this.#error_codes.STORE_AFTER_TERM)) { if (_self.checkState(checkTerminated, _self.#error_codes.STORE_BEFORE_INIT,
if (checkTerminated) this.lastErrorCode = 0; _self.#error_codes.STORE_AFTER_TERM)) {
returnValue = this.setCMIValue(CMIElement, value); if (checkTerminated) _self.lastErrorCode = 0;
this.processListeners(callbackName, CMIElement, value); returnValue = _self.setCMIValue(CMIElement, value);
_self.processListeners(callbackName, CMIElement, value);
} }
this.apiLog(callbackName, CMIElement, ": " + value + ": result: " + returnValue, api_constants.LOG_LEVEL_INFO); _self.apiLog(callbackName, CMIElement,
this.clearSCORMError(returnValue); ': ' + value + ': result: ' + returnValue,
api_constants.LOG_LEVEL_INFO);
_self.clearSCORMError(returnValue);
return returnValue; return returnValue;
} }
/** /**
* Orders LMS to store all content parameters * Orders LMS to store all content parameters
* * @param {string} callbackName
* @returns {string} bool * @param {boolean} checkTerminated
* @return {string}
*/ */
APICommit(callbackName: String, checkTerminated: boolean) { commit(
callbackName: String,
checkTerminated: boolean) {
let returnValue = api_constants.SCORM_FALSE; let returnValue = api_constants.SCORM_FALSE;
if (this.checkState(checkTerminated, this.#error_codes.COMMIT_BEFORE_INIT, this.#error_codes.COMMIT_AFTER_TERM)) { if (_self.checkState(checkTerminated, _self.#error_codes.COMMIT_BEFORE_INIT,
if (checkTerminated) this.lastErrorCode = 0; _self.#error_codes.COMMIT_AFTER_TERM)) {
if (checkTerminated) _self.lastErrorCode = 0;
returnValue = api_constants.SCORM_TRUE; returnValue = api_constants.SCORM_TRUE;
this.processListeners(callbackName); _self.processListeners(callbackName);
} }
this.apiLog(callbackName, null, "returned: " + returnValue, api_constants.LOG_LEVEL_INFO); _self.apiLog(callbackName, null, 'returned: ' + returnValue,
this.clearSCORMError(returnValue); api_constants.LOG_LEVEL_INFO);
_self.clearSCORMError(returnValue);
return returnValue; return returnValue;
} }
/** /**
* Returns last error code * Returns last error code
* * @param {string} callbackName
* @returns {string} * @return {string}
*/ */
APIGetLastError(callbackName: String) { getLastError(callbackName: String) {
let returnValue = String(this.lastErrorCode); const returnValue = String(_self.lastErrorCode);
this.processListeners(callbackName); _self.processListeners(callbackName);
this.apiLog(callbackName, null, "returned: " + returnValue, api_constants.LOG_LEVEL_INFO); _self.apiLog(callbackName, null, 'returned: ' + returnValue,
api_constants.LOG_LEVEL_INFO);
return returnValue; return returnValue;
} }
@@ -152,19 +203,20 @@ export default class BaseAPI {
/** /**
* Returns the errorNumber error description * Returns the errorNumber error description
* *
* @param callbackName * @param {string} callbackName
* @param CMIErrorCode * @param {number} CMIErrorCode
* @returns {string} * @return {string}
*/ */
APIGetErrorString(callbackName: String, CMIErrorCode) { getErrorString(callbackName: String, CMIErrorCode) {
let returnValue = ""; let returnValue = '';
if (CMIErrorCode !== null && CMIErrorCode !== "") { if (CMIErrorCode !== null && CMIErrorCode !== '') {
returnValue = this.getLmsErrorMessageDetails(CMIErrorCode); returnValue = _self.getLmsErrorMessageDetails(CMIErrorCode);
this.processListeners(callbackName); _self.processListeners(callbackName);
} }
this.apiLog(callbackName, null, "returned: " + returnValue, api_constants.LOG_LEVEL_INFO); _self.apiLog(callbackName, null, 'returned: ' + returnValue,
api_constants.LOG_LEVEL_INFO);
return returnValue; return returnValue;
} }
@@ -174,17 +226,18 @@ export default class BaseAPI {
* *
* @param callbackName * @param callbackName
* @param CMIErrorCode * @param CMIErrorCode
* @returns {string} * @return {string}
*/ */
APIGetDiagnostic(callbackName: String, CMIErrorCode) { getDiagnostic(callbackName: String, CMIErrorCode) {
let returnValue = ""; let returnValue = '';
if (CMIErrorCode !== null && CMIErrorCode !== "") { if (CMIErrorCode !== null && CMIErrorCode !== '') {
returnValue = this.getLmsErrorMessageDetails(CMIErrorCode, true); returnValue = _self.getLmsErrorMessageDetails(CMIErrorCode, true);
this.processListeners(callbackName); _self.processListeners(callbackName);
} }
this.apiLog(callbackName, null, "returned: " + returnValue, api_constants.LOG_LEVEL_INFO); _self.apiLog(callbackName, null, 'returned: ' + returnValue,
api_constants.LOG_LEVEL_INFO);
return returnValue; return returnValue;
} }
@@ -192,12 +245,14 @@ export default class BaseAPI {
/** /**
* Checks the LMS state and ensures it has been initialized * Checks the LMS state and ensures it has been initialized
*/ */
checkState(checkTerminated: boolean, beforeInitError: number, afterTermError?: number) { checkState(
if (this.isNotInitialized()) { checkTerminated: boolean, beforeInitError: number,
this.throwSCORMError(beforeInitError); afterTermError?: number) {
if (_self.isNotInitialized()) {
_self.throwSCORMError(beforeInitError);
return false; return false;
} else if (checkTerminated && this.isTerminated()) { } else if (checkTerminated && _self.isTerminated()) {
this.throwSCORMError(afterTermError); _self.throwSCORMError(afterTermError);
return false; return false;
} }
@@ -212,10 +267,12 @@ export default class BaseAPI {
* @param logMessage * @param logMessage
* @param messageLevel * @param messageLevel
*/ */
apiLog(functionName: String, CMIElement: String, logMessage: String, messageLevel: number) { apiLog(
logMessage = this.formatMessage(functionName, CMIElement, logMessage); functionName: String, CMIElement: String, logMessage: String,
messageLevel: number) {
logMessage = _self.formatMessage(functionName, CMIElement, logMessage);
if (messageLevel >= this.apiLogLevel) { if (messageLevel >= _self.apiLogLevel) {
switch (messageLevel) { switch (messageLevel) {
case api_constants.LOG_LEVEL_ERROR: case api_constants.LOG_LEVEL_ERROR:
console.error(logMessage); console.error(logMessage);
@@ -228,16 +285,16 @@ export default class BaseAPI {
break; break;
} }
} }
}; }
/** /**
* Clears the last SCORM error code on success * Clears the last SCORM error code on success
*/ */
clearSCORMError(success: String) { clearSCORMError(success: String) {
if (success !== api_constants.SCORM_FALSE) { if (success !== api_constants.SCORM_FALSE) {
this.lastErrorCode = 0; _self.lastErrorCode = 0;
}
} }
};
/** /**
* Formats the SCORM messages for easy reading * Formats the SCORM messages for easy reading
@@ -245,31 +302,31 @@ export default class BaseAPI {
* @param functionName * @param functionName
* @param CMIElement * @param CMIElement
* @param message * @param message
* @returns {string} * @return {string}
*/ */
formatMessage(functionName: String, CMIElement: String, message: String) { formatMessage(functionName: String, CMIElement: String, message: String) {
let baseLength = 20; const baseLength = 20;
let messageString = ""; let messageString = '';
messageString += functionName; messageString += functionName;
let fillChars = baseLength - messageString.length; let fillChars = baseLength - messageString.length;
for (let i = 0; i < fillChars; i++) { for (let i = 0; i < fillChars; i++) {
messageString += " "; messageString += ' ';
} }
messageString += ": "; messageString += ': ';
if (CMIElement) { if (CMIElement) {
let CMIElementBaseLength = 70; const CMIElementBaseLength = 70;
messageString += CMIElement; messageString += CMIElement;
fillChars = CMIElementBaseLength - messageString.length; fillChars = CMIElementBaseLength - messageString.length;
for (let j = 0; j < fillChars; j++) { for (let j = 0; j < fillChars; j++) {
messageString += " "; messageString += ' ';
} }
} }
@@ -278,7 +335,7 @@ export default class BaseAPI {
} }
return messageString; return messageString;
}; }
/** /**
* Checks to see if {str} contains {tester} * Checks to see if {str} contains {tester}
@@ -288,14 +345,14 @@ export default class BaseAPI {
*/ */
stringContains(str: String, tester: String) { stringContains(str: String, tester: String) {
return str.indexOf(tester) > -1; return str.indexOf(tester) > -1;
}; }
/** /**
* Returns the message that corresponds to errorNumber * Returns the message that corresponds to errorNumber
* APIs that inherit BaseAPI should override this function * APIs that inherit BaseAPI should override this function
*/ */
getLmsErrorMessageDetails(_errorNumber, _detail) { getLmsErrorMessageDetails(_errorNumber, _detail) {
return "No error"; return 'No error';
} }
/** /**
@@ -303,7 +360,7 @@ export default class BaseAPI {
* APIs that inherit BaseAPI should override this function * APIs that inherit BaseAPI should override this function
*/ */
getCMIValue(_CMIElement) { getCMIValue(_CMIElement) {
return ""; return '';
} }
/** /**
@@ -311,35 +368,39 @@ export default class BaseAPI {
* APIs that inherit BaseAPI should override this function * APIs that inherit BaseAPI should override this function
*/ */
setCMIValue(_CMIElement, _value) { setCMIValue(_CMIElement, _value) {
return ""; return '';
} }
_commonSetCMIValue(methodName: String, scorm2004: boolean, CMIElement, value) { _commonSetCMIValue(
if (!CMIElement || CMIElement === "") { methodName: String, scorm2004: boolean, CMIElement, value) {
if (!CMIElement || CMIElement === '') {
return api_constants.SCORM_FALSE; return api_constants.SCORM_FALSE;
} }
let structure = CMIElement.split("."); const structure = CMIElement.split('.');
let refObject = this; let refObject = this;
let returnValue = api_constants.SCORM_FALSE; let returnValue = api_constants.SCORM_FALSE;
const invalidErrorMessage = `The data model element passed to ${methodName} (${CMIElement}) is not a valid SCORM data model element.`; const invalidErrorMessage = `The data model element passed to ${methodName} (${CMIElement}) is not a valid SCORM data model element.`;
const invalidErrorCode = scorm2004 ? this.#error_codes.UNDEFINED_DATA_MODEL: this.#error_codes.GENERAL; const invalidErrorCode = scorm2004 ?
_self.#error_codes.UNDEFINED_DATA_MODEL :
_self.#error_codes.GENERAL;
for (let i = 0; i < structure.length; i++) { for (let i = 0; i < structure.length; i++) {
let attribute = structure[i]; const attribute = structure[i];
if (i === structure.length - 1) { if (i === structure.length - 1) {
if (scorm2004 && (attribute.substr(0, 8) === "{target=") && (typeof refObject._isTargetValid == "function")) { if (scorm2004 && (attribute.substr(0, 8) === '{target=') &&
this.throwSCORMError(this.#error_codes.READ_ONLY_ELEMENT); (typeof refObject._isTargetValid == 'function')) {
_self.throwSCORMError(_self.#error_codes.READ_ONLY_ELEMENT);
} else if (!refObject.hasOwnProperty(attribute)) { } else if (!refObject.hasOwnProperty(attribute)) {
this.throwSCORMError(invalidErrorCode, invalidErrorMessage); _self.throwSCORMError(invalidErrorCode, invalidErrorMessage);
} else { } else {
if (this.stringContains(CMIElement, ".correct_responses")){ if (_self.stringContains(CMIElement, '.correct_responses')) {
this.validateCorrectResponse(CMIElement, value) _self.validateCorrectResponse(CMIElement, value);
} }
if (!scorm2004 || this.lastErrorCode === 0) { if (!scorm2004 || _self.lastErrorCode === 0) {
refObject[attribute] = value; refObject[attribute] = value;
returnValue = api_constants.SCORM_TRUE; returnValue = api_constants.SCORM_TRUE;
} }
@@ -347,24 +408,24 @@ export default class BaseAPI {
} else { } else {
refObject = refObject[attribute]; refObject = refObject[attribute];
if (!refObject) { if (!refObject) {
this.throwSCORMError(invalidErrorCode, invalidErrorMessage); _self.throwSCORMError(invalidErrorCode, invalidErrorMessage);
break; break;
} }
if (refObject.prototype === CMIArray) { if (refObject.prototype === CMIArray) {
let index = parseInt(structure[i + 1], 10); const index = parseInt(structure[i + 1], 10);
// SCO is trying to set an item on an array // SCO is trying to set an item on an array
if (!isNaN(index)) { if (!isNaN(index)) {
let item = refObject.childArray[index]; const item = refObject.childArray[index];
if (item) { if (item) {
refObject = item; refObject = item;
} else { } else {
let newChild = this.getChildElement(CMIElement, value); const newChild = _self.getChildElement(CMIElement, value);
if (!newChild) { if (!newChild) {
this.throwSCORMError(invalidErrorCode, invalidErrorMessage); _self.throwSCORMError(invalidErrorCode, invalidErrorMessage);
} else { } else {
refObject.childArray.push(newChild); refObject.childArray.push(newChild);
refObject = newChild; refObject = newChild;
@@ -379,7 +440,9 @@ export default class BaseAPI {
} }
if (returnValue === api_constants.SCORM_FALSE) { if (returnValue === api_constants.SCORM_FALSE) {
this.apiLog(methodName, null, `There was an error setting the value for: ${CMIElement}, value of: ${value}`, api_constants.LOG_LEVEL_WARNING); _self.apiLog(methodName, null,
`There was an error setting the value for: ${CMIElement}, value of: ${value}`,
api_constants.LOG_LEVEL_WARNING);
} }
return returnValue; return returnValue;
@@ -394,7 +457,7 @@ export default class BaseAPI {
* APIs that inherit BaseAPI should override this method * APIs that inherit BaseAPI should override this method
*/ */
getChildElement(_CMIElement) { getChildElement(_CMIElement) {
return null return null;
} }
/** /**
@@ -403,14 +466,14 @@ export default class BaseAPI {
* @param methodName * @param methodName
* @param scorm2004 * @param scorm2004
* @param CMIElement * @param CMIElement
* @returns {*} * @return {*}
*/ */
_commonGetCMIValue(methodName: String, scorm2004: boolean, CMIElement) { _commonGetCMIValue(methodName: String, scorm2004: boolean, CMIElement) {
if (!CMIElement || CMIElement === "") { if (!CMIElement || CMIElement === '') {
return ""; return '';
} }
let structure = CMIElement.split("."); const structure = CMIElement.split('.');
let refObject = this; let refObject = this;
let attribute = null; let attribute = null;
@@ -420,16 +483,21 @@ export default class BaseAPI {
if (!scorm2004) { if (!scorm2004) {
if (i === structure.length - 1) { if (i === structure.length - 1) {
if (!refObject.hasOwnProperty(attribute)) { if (!refObject.hasOwnProperty(attribute)) {
this.throwSCORMError(101, "getCMIValue did not find a value for: " + CMIElement); _self.throwSCORMError(101,
'getCMIValue did not find a value for: ' + CMIElement);
} }
} }
} else { } else {
if ((String(attribute).substr(0, 8) === "{target=") && (typeof refObject._isTargetValid == "function")) { if ((String(attribute).substr(0, 8) === '{target=') &&
let target = String(attribute).substr(8, String(attribute).length - 9); (typeof refObject._isTargetValid == 'function')) {
const target = String(attribute).
substr(8, String(attribute).length - 9);
return refObject._isTargetValid(target); return refObject._isTargetValid(target);
} else if (!refObject.hasOwnProperty(attribute)) { } else if (!refObject.hasOwnProperty(attribute)) {
this.throwSCORMError(401, "The data model element passed to GetValue (" + CMIElement + ") is not a valid SCORM data model element."); _self.throwSCORMError(401,
return ""; 'The data model element passed to GetValue (' + CMIElement +
') is not a valid SCORM data model element.');
return '';
} }
} }
@@ -438,13 +506,13 @@ export default class BaseAPI {
if (refObject === null || refObject === undefined) { if (refObject === null || refObject === undefined) {
if (!scorm2004) { if (!scorm2004) {
if (attribute === "_children") { if (attribute === '_children') {
this.throwSCORMError(202); _self.throwSCORMError(202);
} else if (attribute === "_count") { } else if (attribute === '_count') {
this.throwSCORMError(203); _self.throwSCORMError(203);
} }
} }
return ""; return '';
} else { } else {
return refObject; return refObject;
} }
@@ -454,21 +522,21 @@ export default class BaseAPI {
* Returns true if the API's current state is STATE_INITIALIZED * Returns true if the API's current state is STATE_INITIALIZED
*/ */
isInitialized() { isInitialized() {
return this.currentState === api_constants.STATE_INITIALIZED; return _self.currentState === api_constants.STATE_INITIALIZED;
} }
/** /**
* Returns true if the API's current state is STATE_NOT_INITIALIZED * Returns true if the API's current state is STATE_NOT_INITIALIZED
*/ */
isNotInitialized() { isNotInitialized() {
return this.currentState === api_constants.STATE_NOT_INITIALIZED; return _self.currentState === api_constants.STATE_NOT_INITIALIZED;
} }
/** /**
* Returns true if the API's current state is STATE_TERMINATED * Returns true if the API's current state is STATE_TERMINATED
*/ */
isTerminated() { isTerminated() {
return this.currentState === api_constants.STATE_TERMINATED; return _self.currentState === api_constants.STATE_TERMINATED;
} }
/** /**
@@ -480,25 +548,25 @@ export default class BaseAPI {
on(listenerName: String, callback: function) { on(listenerName: String, callback: function) {
if (!callback) return; if (!callback) return;
let listenerFunctions = listenerName.split(" "); const listenerFunctions = listenerName.split(' ');
for (let i = 0; i < listenerFunctions.length; i++) { for (let i = 0; i < listenerFunctions.length; i++) {
let listenerSplit = listenerFunctions[i].split("."); const listenerSplit = listenerFunctions[i].split('.');
if (listenerSplit.length === 0) return; if (listenerSplit.length === 0) return;
let functionName = listenerSplit[0]; const functionName = listenerSplit[0];
let CMIElement = null; let CMIElement = null;
if (listenerSplit.length > 1) { if (listenerSplit.length > 1) {
CMIElement = listenerName.replace(functionName + ".", ""); CMIElement = listenerName.replace(functionName + '.', '');
} }
this.listenerArray.push({ _self.listenerArray.push({
functionName: functionName, functionName: functionName,
CMIElement: CMIElement, CMIElement: CMIElement,
callback: callback callback: callback,
}); });
} }
}; }
/** /**
* Processes any 'on' listeners that have been created * Processes any 'on' listeners that have been created
@@ -508,17 +576,17 @@ export default class BaseAPI {
* @param value * @param value
*/ */
processListeners(functionName: String, CMIElement: String, value: any) { processListeners(functionName: String, CMIElement: String, value: any) {
for (let i = 0; i < this.listenerArray.length; i++) { for (let i = 0; i < _self.listenerArray.length; i++) {
let listener = this.listenerArray[i]; const listener = _self.listenerArray[i];
let functionsMatch = listener.functionName === functionName; const functionsMatch = listener.functionName === functionName;
let listenerHasCMIElement = !!listener.CMIElement; const listenerHasCMIElement = !!listener.CMIElement;
let CMIElementsMatch = listener.CMIElement === CMIElement; const CMIElementsMatch = listener.CMIElement === CMIElement;
if (functionsMatch && (!listenerHasCMIElement || CMIElementsMatch)) { if (functionsMatch && (!listenerHasCMIElement || CMIElementsMatch)) {
listener.callback(CMIElement, value); listener.callback(CMIElement, value);
} }
} }
}; }
/** /**
* Throws a SCORM error * Throws a SCORM error
@@ -528,45 +596,48 @@ export default class BaseAPI {
*/ */
throwSCORMError(errorNumber: number, message: String) { throwSCORMError(errorNumber: number, message: String) {
if (!message) { if (!message) {
message = this.getLmsErrorMessageDetails(errorNumber); message = _self.getLmsErrorMessageDetails(errorNumber);
} }
this.apiLog("throwSCORMError", null, errorNumber + ": " + message, api_constants.LOG_LEVEL_ERROR); _self.apiLog('throwSCORMError', null, errorNumber + ': ' + message,
api_constants.LOG_LEVEL_ERROR);
this.lastErrorCode = String(errorNumber); _self.lastErrorCode = String(errorNumber);
} }
/** /**
* Loads CMI data from a JSON object. * Loads CMI data from a JSON object.
*/ */
loadFromJSON(json, CMIElement) { loadFromJSON(json, CMIElement) {
if (!this.isNotInitialized()) { if (!_self.isNotInitialized()) {
console.error("loadFromJSON can only be called before the call to LMSInitialize."); console.error(
'loadFromJSON can only be called before the call to LMSInitialize.');
return; return;
} }
CMIElement = CMIElement || "cmi"; CMIElement = CMIElement || 'cmi';
for (let key in json) { for (const key in json) {
if (json.hasOwnProperty(key) && json[key]) { if (json.hasOwnProperty(key) && json[key]) {
let currentCMIElement = CMIElement + "." + key; const currentCMIElement = CMIElement + '.' + key;
let value = json[key]; const value = json[key];
if (value["childArray"]) { if (value['childArray']) {
for (let i = 0; i < value["childArray"].length; i++) { for (let i = 0; i < value['childArray'].length; i++) {
this.loadFromJSON(value["childArray"][i], currentCMIElement + "." + i); _self.loadFromJSON(value['childArray'][i],
currentCMIElement + '.' + i);
} }
} else if (value.constructor === Object) { } else if (value.constructor === Object) {
this.loadFromJSON(value, currentCMIElement); _self.loadFromJSON(value, currentCMIElement);
} else { } else {
this.setCMIValue(currentCMIElement, value); _self.setCMIValue(currentCMIElement, value);
} }
} }
} }
} }
renderCMIToJSON() { renderCMIToJSON() {
let cmi = this.cmi; const cmi = _self.cmi;
// Do we want/need to return fields that have no set value? // Do we want/need to return fields that have no set value?
// return JSON.stringify({ cmi }, (k, v) => v === undefined ? null : v, 2); // return JSON.stringify({ cmi }, (k, v) => v === undefined ? null : v, 2);
return JSON.stringify({cmi}); return JSON.stringify({cmi});
@@ -577,39 +648,37 @@ export default class BaseAPI {
* *
* @param value * @param value
* @param regexPattern * @param regexPattern
* @returns {boolean} * @return {boolean}
*/ */
checkValidFormat(value: String, regexPattern: String) { checkValidFormat(value: String, regexPattern: String) {
const formatRegex = new RegExp(regexPattern); const formatRegex = new RegExp(regexPattern);
if (!value || !value.match(formatRegex)) { if (!value || !value.match(formatRegex)) {
this.throwSCORMError(this.#error_codes.TYPE_MISMATCH); _self.throwSCORMError(_self.#error_codes.TYPE_MISMATCH);
return false; return false;
} }
return true; return true;
} }
/** /**
* Check if the value matches the proper range. If not, throw proper error code. * Check if the value matches the proper range. If not, throw proper error code.
* *
* @param value * @param value
* @param rangePattern * @param rangePattern
* @returns {boolean} * @return {boolean}
*/ */
checkValidRange(value: any, rangePattern: String) { checkValidRange(value: any, rangePattern: String) {
const ranges = rangePattern.split('#'); const ranges = rangePattern.split('#');
value = value * 1.0; value = value * 1.0;
if (value >= ranges[0]) { if (value >= ranges[0]) {
if ((ranges[1] === '*') || (value <= ranges[1])) { if ((ranges[1] === '*') || (value <= ranges[1])) {
this.clearSCORMError(api_constants.SCORM_TRUE); _self.clearSCORMError(api_constants.SCORM_TRUE);
return true; return true;
} else { } else {
this.throwSCORMError(this.#error_codes.VALUE_OUT_OF_RANGE); _self.throwSCORMError(_self.#error_codes.VALUE_OUT_OF_RANGE);
return false; return false;
} }
} else { } else {
this.throwSCORMError(this.#error_codes.VALUE_OUT_OF_RANGE); _self.throwSCORMError(_self.#error_codes.VALUE_OUT_OF_RANGE);
return false; return false;
} }
} }
@@ -620,16 +689,16 @@ export default class BaseAPI {
* @param when the number of milliseconds to wait before committing * @param when the number of milliseconds to wait before committing
*/ */
scheduleCommit(when: number) { scheduleCommit(when: number) {
this.#timeout = new ScheduledCommit(this, when); _self.#timeout = new ScheduledCommit(this, when);
} }
/** /**
* Clears and cancels any currently scheduled commits * Clears and cancels any currently scheduled commits
*/ */
clearScheduledCommit() { clearScheduledCommit() {
if (this.#timeout) { if (_self.#timeout) {
this.#timeout.cancel(); _self.#timeout.cancel();
this.#timeout = null; _self.#timeout = null;
} }
} }
} }
@@ -640,20 +709,20 @@ class ScheduledCommit {
#timeout; #timeout;
constructor(API: any, when: number) { constructor(API: any, when: number) {
this.#API = API; _self.#API = API;
this.#timeout = setTimeout(this.#wrapper, when); _self.#timeout = setTimeout(_self.#wrapper, when);
} }
cancel() { cancel() {
this.#cancelled = true; _self.#cancelled = true;
if (this.#timeout) { if (_self.#timeout) {
clearTimeout(this.#timeout); clearTimeout(_self.#timeout);
} }
} }
#wrapper() { #wrapper = () => {
if (!this.#cancelled) { if (!_self.#cancelled) {
this.#API.LMSCommit(); _self.#API.LMSCommit();
}
} }
};
} }

View File

@@ -5,11 +5,11 @@ import {
CMIInteractionsCorrectResponsesObject, CMIInteractionsCorrectResponsesObject,
CMIInteractionsObject, CMIInteractionsObject,
CMIInteractionsObjectivesObject, CMIInteractionsObjectivesObject,
CMIObjectivesObject CMIObjectivesObject,
} from "./cmi/scorm12_cmi"; } from './cmi/scorm12_cmi';
import * as Utilities from './utilities'; import * as Utilities from './utilities';
import {scorm12_constants, scorm12_error_codes} from "./constants"; import {scorm12_constants, scorm12_error_codes} from './constants';
import {scorm12_regex} from "./regex"; import {scorm12_regex} from './regex';
const constants = scorm12_constants; const constants = scorm12_constants;
@@ -21,72 +21,73 @@ export default class Scorm12API extends BaseAPI {
} }
/** /**
* @returns {string} bool * @return {string} bool
*/ */
LMSInitialize() { LMSInitialize() {
return this.APIInitialize("LMSInitialize", "LMS was already initialized!", "LMS is already finished!"); return this.initialize('LMSInitialize', 'LMS was already initialized!',
'LMS is already finished!');
} }
/** /**
* @returns {string} bool * @return {string} bool
*/ */
LMSFinish() { LMSFinish() {
return this.APITerminate("LMSFinish", false); return this.terminate('LMSFinish', false);
} }
/** /**
* @param CMIElement * @param CMIElement
* @returns {string} * @return {string}
*/ */
LMSGetValue(CMIElement) { LMSGetValue(CMIElement) {
return this.APIGetValue("LMSGetValue", false, CMIElement); return this.getValue('LMSGetValue', false, CMIElement);
} }
/** /**
* @param CMIElement * @param CMIElement
* @param value * @param value
* @returns {string} * @return {string}
*/ */
LMSSetValue(CMIElement, value) { LMSSetValue(CMIElement, value) {
return this.APISetValue("LMSSetValue", false, CMIElement, value); return this.setValue('LMSSetValue', false, CMIElement, value);
} }
/** /**
* Orders LMS to store all content parameters * Orders LMS to store all content parameters
* *
* @returns {string} bool * @return {string} bool
*/ */
LMSCommit() { LMSCommit() {
return this.APICommit("LMSCommit", false); return this.commit('LMSCommit', false);
} }
/** /**
* Returns last error code * Returns last error code
* *
* @returns {string} * @return {string}
*/ */
LMSGetLastError() { LMSGetLastError() {
return this.APIGetLastError("LMSGetLastError"); return this.getLastError('LMSGetLastError');
} }
/** /**
* Returns the errorNumber error description * Returns the errorNumber error description
* *
* @param CMIErrorCode * @param CMIErrorCode
* @returns {string} * @return {string}
*/ */
LMSGetErrorString(CMIErrorCode) { LMSGetErrorString(CMIErrorCode) {
return this.APIGetErrorString("LMSGetErrorString", CMIErrorCode); return this.getErrorString('LMSGetErrorString', CMIErrorCode);
} }
/** /**
* Returns a comprehensive description of the errorNumber error. * Returns a comprehensive description of the errorNumber error.
* *
* @param CMIErrorCode * @param CMIErrorCode
* @returns {string} * @return {string}
*/ */
LMSGetDiagnostic(CMIErrorCode) { LMSGetDiagnostic(CMIErrorCode) {
return this.APIGetDiagnostic("LMSGetDiagnostic", CMIErrorCode); return this.getDiagnostic('LMSGetDiagnostic', CMIErrorCode);
} }
/** /**
@@ -94,20 +95,20 @@ export default class Scorm12API extends BaseAPI {
* *
* @param CMIElement * @param CMIElement
* @param value * @param value
* @returns {string} * @return {string}
*/ */
setCMIValue(CMIElement, value) { setCMIValue(CMIElement, value) {
this._commonSetCMIValue("LMSSetValue", false, CMIElement, value); this._commonSetCMIValue('LMSSetValue', false, CMIElement, value);
} }
/** /**
* Gets a value from the CMI Object * Gets a value from the CMI Object
* *
* @param CMIElement * @param CMIElement
* @returns {*} * @return {*}
*/ */
getCMIValue(CMIElement) { getCMIValue(CMIElement) {
return this._commonGetCMIValue("getCMIValue", false, CMIElement); return this._commonGetCMIValue('getCMIValue', false, CMIElement);
} }
/** /**
@@ -118,13 +119,13 @@ export default class Scorm12API extends BaseAPI {
getChildElement(CMIElement, value) { getChildElement(CMIElement, value) {
let newChild; let newChild;
if (this.stringContains(CMIElement, "cmi.objectives")) { if (this.stringContains(CMIElement, 'cmi.objectives')) {
newChild = new CMIObjectivesObject(this); newChild = new CMIObjectivesObject(this);
} else if (this.stringContains(CMIElement, ".correct_responses")) { } else if (this.stringContains(CMIElement, '.correct_responses')) {
newChild = new CMIInteractionsCorrectResponsesObject(this); newChild = new CMIInteractionsCorrectResponsesObject(this);
} else if (this.stringContains(CMIElement, ".objectives")) { } else if (this.stringContains(CMIElement, '.objectives')) {
newChild = new CMIInteractionsObjectivesObject(this); newChild = new CMIInteractionsObjectivesObject(this);
} else if (this.stringContains(CMIElement, "cmi.interactions")) { } else if (this.stringContains(CMIElement, 'cmi.interactions')) {
newChild = new CMIInteractionsObject(this); newChild = new CMIInteractionsObject(this);
} }
@@ -139,8 +140,8 @@ export default class Scorm12API extends BaseAPI {
* Returns the message that corresponds to errorNumber. * Returns the message that corresponds to errorNumber.
*/ */
getLmsErrorMessageDetails(errorNumber, detail) { getLmsErrorMessageDetails(errorNumber, detail) {
let basicMessage = "No Error"; let basicMessage = 'No Error';
let detailMessage = "No Error"; let detailMessage = 'No Error';
// Set error number to string since inconsistent from modules if string or number // Set error number to string since inconsistent from modules if string or number
errorNumber = String(errorNumber); errorNumber = String(errorNumber);

View File

@@ -8,140 +8,153 @@ import {
CMIInteractionsCorrectResponsesObject, CMIInteractionsCorrectResponsesObject,
CMIInteractionsObject, CMIInteractionsObject,
CMIInteractionsObjectivesObject, CMIInteractionsObjectivesObject,
CMIObjectivesObject CMIObjectivesObject,
} from './cmi/scorm2004_cmi'; } from './cmi/scorm2004_cmi';
import * as Utilities from "./utilities"; import * as Util from './utilities';
import {correct_responses, scorm2004_constants, scorm2004_error_codes} from "./constants"; import {
import {scorm2004_regex} from "./regex"; correct_responses,
scorm2004_constants,
scorm2004_error_codes,
} from './constants';
import {scorm2004_regex} from './regex';
const constants = scorm2004_constants; const constants = scorm2004_constants;
const valid_languages = constants.valid_languages; const valid_languages = constants.valid_languages;
let _self;
/**
* API class for SCORM 2004
*/
class Scorm2004API extends BaseAPI { class Scorm2004API extends BaseAPI {
version: "1.0"; version: '1.0';
/**
* Constructor for SCORM 2004 API
*/
constructor() { constructor() {
super(scorm2004_error_codes); super(scorm2004_error_codes);
this.cmi = new CMI(this); _self = this;
this.adl = new ADL(this); _self.cmi = new CMI(_self);
_self.adl = new ADL(_self);
// Rename functions to match 2004 Spec // Rename functions to match 2004 Spec
this.Initialize = this.LMSInitialize; _self.Initialize = _self.LMSInitialize;
this.Terminate = this.LMSTerminate; _self.Terminate = _self.LMSTerminate;
this.GetValue = this.LMSGetValue; _self.GetValue = _self.LMSGetValue;
this.SetValue = this.LMSSetValue; _self.SetValue = _self.LMSSetValue;
this.Commit = this.LMSCommit; _self.Commit = _self.LMSCommit;
this.GetLastError = this.LMSGetLastError; _self.GetLastError = _self.LMSGetLastError;
this.GetErrorString = this.LMSGetErrorString; _self.GetErrorString = _self.LMSGetErrorString;
this.GetDiagnostic = this.LMSGetDiagnostic; _self.GetDiagnostic = _self.LMSGetDiagnostic;
} }
/** /**
* @returns {string} bool * @return {string} bool
*/ */
LMSInitialize() { LMSInitialize() {
return this.APIInitialize("Initialize"); return _self.initialize('Initialize');
} }
/** /**
* @returns {string} bool * @return {string} bool
*/ */
LMSTerminate() { LMSTerminate() {
return this.APITerminate("Terminate", true); return _self.terminate('Terminate', true);
} }
/** /**
* @param CMIElement * @param {string} CMIElement
* @returns {string} * @return {string}
*/ */
LMSGetValue(CMIElement) { LMSGetValue(CMIElement) {
return this.APIGetValue("GetValue", true, CMIElement); return _self.getValue('GetValue', true, CMIElement);
} }
/** /**
* @param CMIElement * @param {string} CMIElement
* @param value * @param {any} value
* @returns {string} * @return {string}
*/ */
LMSSetValue(CMIElement, value) { LMSSetValue(CMIElement, value) {
return this.APISetValue("SetValue", true, CMIElement, value); return _self.setValue('SetValue', true, CMIElement, value);
} }
/** /**
* Orders LMS to store all content parameters * Orders LMS to store all content parameters
* *
* @returns {string} bool * @return {string} bool
*/ */
LMSCommit() { LMSCommit() {
return this.APICommit("Commit"); return _self.commit('Commit');
} }
/** /**
* Returns last error code * Returns last error code
* *
* @returns {string} * @return {string}
*/ */
LMSGetLastError() { LMSGetLastError() {
return this.APIGetLastError("GetLastError"); return _self.getLastError('GetLastError');
} }
/** /**
* Returns the errorNumber error description * Returns the errorNumber error description
* *
* @param CMIErrorCode * @param CMIErrorCode
* @returns {string} * @return {string}
*/ */
LMSGetErrorString(CMIErrorCode) { LMSGetErrorString(CMIErrorCode) {
return this.APIGetErrorString("GetErrorString", CMIErrorCode); return _self.APIGetErrorString('GetErrorString', CMIErrorCode);
} }
/** /**
* Returns a comprehensive description of the errorNumber error. * Returns a comprehensive description of the errorNumber error.
* *
* @param CMIErrorCode * @param CMIErrorCode
* @returns {string} * @return {string}
*/ */
LMSGetDiagnostic(CMIErrorCode) { LMSGetDiagnostic(CMIErrorCode) {
return this.APIGetDiagnostic("GetDiagnostic", CMIErrorCode); return _self.APIGetDiagnostic('GetDiagnostic', CMIErrorCode);
} }
/** /**
* Sets a value on the CMI Object * Sets a value on the CMI Object
* *
* @param CMIElement * @param {string} CMIElement
* @param value * @param {any} value
* @returns {string}
*/ */
setCMIValue(CMIElement, value) { setCMIValue(CMIElement, value) {
this._commonSetCMIValue("SetValue", true, CMIElement, value); _self._commonSetCMIValue('SetValue', true, CMIElement, value);
} }
/** /**
* Gets or builds a new child element to add to the array. * Gets or builds a new child element to add to the array.
* *
* @param CMIElement * @param {string} CMIElement
* @param value * @param {any} value
* @return {any}
*/ */
getChildElement(CMIElement, value) { getChildElement(CMIElement, value) {
let newChild; let newChild;
if (this.stringContains(CMIElement, "cmi.objectives")) { if (_self.stringContains(CMIElement, 'cmi.objectives')) {
newChild = new CMIObjectivesObject(this); newChild = new CMIObjectivesObject(this);
} else if (this.stringContains(CMIElement, ".correct_responses")) { } else if (_self.stringContains(CMIElement, '.correct_responses')) {
const parts = CMIElement.split('.'); const parts = CMIElement.split('.');
const index = Number(parts[2]); const index = Number(parts[2]);
let interaction = this.cmi.interactions.childArray[index]; const interaction = _self.cmi.interactions.childArray[index];
if (typeof interaction.type === 'undefined') { if (typeof interaction.type === 'undefined') {
this.throwSCORMError(scorm2004_error_codes.DEPENDENCY_NOT_ESTABLISHED); _self.throwSCORMError(scorm2004_error_codes.DEPENDENCY_NOT_ESTABLISHED);
} else { } else {
let interaction_type = interaction.type; const interaction_type = interaction.type;
let interaction_count = interaction.correct_responses._count; const interaction_count = interaction.correct_responses._count;
if (interaction_type === 'choice') { if (interaction_type === 'choice') {
for(let i = 0; i < interaction_count && this.lastErrorCode === 0; i++) { for (let i = 0; i < interaction_count && _self.lastErrorCode ===
0; i++) {
const response = interaction.correct_responses.childArray[i]; const response = interaction.correct_responses.childArray[i];
if (response.pattern === value) { if (response.pattern === value) {
this.throwSCORMError(scorm2004_error_codes.GENERAL_SET_FAILURE); _self.throwSCORMError(scorm2004_error_codes.GENERAL_SET_FAILURE);
} }
} }
} }
@@ -155,46 +168,53 @@ class Scorm2004API extends BaseAPI {
} }
if (nodes.length > 0 && nodes.length <= response_type.max) { if (nodes.length > 0 && nodes.length <= response_type.max) {
this.#checkCorrectResponseValue(interaction_type, nodes, value); _self.#checkCorrectResponseValue(interaction_type, nodes, value);
} else if (nodes.length > response_type.max) { } else if (nodes.length > response_type.max) {
this.throwSCORMError(scorm2004_error_codes.GENERAL_SET_FAILURE, "Data Model Element Pattern Too Long"); _self.throwSCORMError(scorm2004_error_codes.GENERAL_SET_FAILURE,
'Data Model Element Pattern Too Long');
} }
} }
if(this.lastErrorCode === 0) { if (_self.lastErrorCode === 0) {
newChild = new CMIInteractionsCorrectResponsesObject(this); newChild = new CMIInteractionsCorrectResponsesObject(this);
} }
} else if (this.stringContains(CMIElement, ".objectives")) { } else if (_self.stringContains(CMIElement, '.objectives')) {
newChild = new CMIInteractionsObjectivesObject(this); newChild = new CMIInteractionsObjectivesObject(this);
} else if (this.stringContains(CMIElement, "cmi.interactions")) { } else if (_self.stringContains(CMIElement, 'cmi.interactions')) {
newChild = new CMIInteractionsObject(this); newChild = new CMIInteractionsObject(this);
} else if (this.stringContains(CMIElement, "cmi.comments_from_learner")) { } else if (_self.stringContains(CMIElement, 'cmi.comments_from_learner')) {
newChild = new CMICommentsFromLearnerObject(this); newChild = new CMICommentsFromLearnerObject(this);
} else if (this.stringContains(CMIElement, "cmi.comments_from_lms")) { } else if (_self.stringContains(CMIElement, 'cmi.comments_from_lms')) {
newChild = new CMICommentsFromLMSObject(this); newChild = new CMICommentsFromLMSObject(this);
} }
return newChild; return newChild;
} }
/**
* Validate correct response.
* @param {string} CMIElement
* @param {any} value
*/
validateCorrectResponse(CMIElement, value) { validateCorrectResponse(CMIElement, value) {
const parts = CMIElement.split('.'); const parts = CMIElement.split('.');
const index = Number(parts[2]); const index = Number(parts[2]);
const pattern_index = Number(parts[4]); const pattern_index = Number(parts[4]);
let interaction = this.cmi.interactions.childArray[index]; const interaction = _self.cmi.interactions.childArray[index];
let interaction_type = interaction.type; const interaction_type = interaction.type;
let interaction_count = interaction.correct_responses._count; const interaction_count = interaction.correct_responses._count;
if (interaction_type === 'choice') { if (interaction_type === 'choice') {
for(let i = 0; i < interaction_count && this.lastErrorCode === 0; i++) { for (let i = 0; i < interaction_count && _self.lastErrorCode === 0; i++) {
const response = interaction.correct_responses.childArray[i]; const response = interaction.correct_responses.childArray[i];
if (response.pattern === value) { if (response.pattern === value) {
this.throwSCORMError(scorm2004_error_codes.GENERAL_SET_FAILURE); _self.throwSCORMError(scorm2004_error_codes.GENERAL_SET_FAILURE);
} }
} }
} }
const response_type = scorm2004_constants.correct_responses[interaction_type]; const response_type = scorm2004_constants.correct_responses[interaction_type];
if(typeof response_type.limit !== 'undefined' || interaction_count < response_type.limit) { if (typeof response_type.limit !== 'undefined' || interaction_count <
response_type.limit) {
let nodes = []; let nodes = [];
if (response_type.delimiter !== '') { if (response_type.delimiter !== '') {
nodes = value.split(response_type.delimiter); nodes = value.split(response_type.delimiter);
@@ -203,41 +223,50 @@ class Scorm2004API extends BaseAPI {
} }
if (nodes.length > 0 && nodes.length <= response_type.max) { if (nodes.length > 0 && nodes.length <= response_type.max) {
this.#checkCorrectResponseValue(interaction_type, nodes, value); _self.#checkCorrectResponseValue(interaction_type, nodes, value);
} else if (nodes.length > response_type.max) { } else if (nodes.length > response_type.max) {
this.throwSCORMError(scorm2004_error_codes.GENERAL_SET_FAILURE, "Data Model Element Pattern Too Long"); _self.throwSCORMError(scorm2004_error_codes.GENERAL_SET_FAILURE,
'Data Model Element Pattern Too Long');
} }
if(this.lastErrorCode === 0 if (_self.lastErrorCode === 0 &&
&& (!response_type.duplicate || !this.#checkDuplicatedPattern(interaction.correct_responses, pattern_index, value)) (!response_type.duplicate ||
|| (this.lastErrorCode === 0 && value === '')) { !_self.#checkDuplicatedPattern(interaction.correct_responses,
pattern_index, value)) ||
(_self.lastErrorCode === 0 && value === '')) {
// do nothing, we want the inverse // do nothing, we want the inverse
} else { } else {
if(this.lastErrorCode === 0) { if (_self.lastErrorCode === 0) {
this.throwSCORMError(scorm2004_error_codes.GENERAL_SET_FAILURE, "Data Model Element Pattern Already Exists"); _self.throwSCORMError(scorm2004_error_codes.GENERAL_SET_FAILURE,
'Data Model Element Pattern Already Exists');
} }
} }
} else { } else {
this.throwSCORMError(scorm2004_error_codes.GENERAL_SET_FAILURE, "Data Model Element Collection Limit Reached"); _self.throwSCORMError(scorm2004_error_codes.GENERAL_SET_FAILURE,
'Data Model Element Collection Limit Reached');
} }
} }
/** /**
* Gets a value from the CMI Object * Gets a value from the CMI Object
* *
* @param CMIElement * @param {string} CMIElement
* @returns {*} * @return {*}
*/ */
getCMIValue(CMIElement) { getCMIValue(CMIElement) {
return this._commonGetCMIValue("GetValue", true, CMIElement); return _self._commonGetCMIValue('GetValue', true, CMIElement);
} }
/** /**
* Returns the message that corresponds to errorNumber. * Returns the message that corresponds to errorNumber.
*
* @param {string,number} errorNumber
* @param {string} detail
* @return {string}
*/ */
getLmsErrorMessageDetails(errorNumber, detail) { getLmsErrorMessageDetails(errorNumber, detail) {
let basicMessage = ""; let basicMessage = '';
let detailMessage = ""; let detailMessage = '';
// Set error number to string since inconsistent from modules if string or number // Set error number to string since inconsistent from modules if string or number
errorNumber = String(errorNumber); errorNumber = String(errorNumber);
@@ -249,54 +278,55 @@ class Scorm2004API extends BaseAPI {
return detail ? detailMessage : basicMessage; return detail ? detailMessage : basicMessage;
} }
#checkDuplicatedPattern(correct_response, current_index, value) { #checkDuplicatedPattern = (correct_response, current_index, value) => {
let found = false; let found = false;
let count = correct_response._count; const count = correct_response._count;
for (let i = 0; i < count && !found; i++) { for (let i = 0; i < count && !found; i++) {
if (i !== current_index && correct_response.childArray[i] === value) { if (i !== current_index && correct_response.childArray[i] === value) {
found = true; found = true;
} }
} }
return found; return found;
} };
#checkCorrectResponseValue(interaction_type, nodes, value) { #checkCorrectResponseValue = (interaction_type, nodes, value) => {
const response = correct_responses[interaction_type]; const response = correct_responses[interaction_type];
const formatRegex = new RegExp(response.format); const formatRegex = new RegExp(response.format);
for(let i = 0; i < nodes.length && this.lastErrorCode === 0; i++) { for (let i = 0; i < nodes.length && _self.lastErrorCode === 0; i++) {
if(interaction_type.match('^(fill-in|long-fill-in|matching|performance|sequencing)$')) { if (interaction_type.match(
nodes[i] = #removeCorrectResponsePrefixes(nodes[i]); '^(fill-in|long-fill-in|matching|performance|sequencing)$')) {
nodes[i] = _self.#removeCorrectResponsePrefixes(nodes[i]);
} }
if (response.delimiter2 !== undefined) { if (response.delimiter2 !== undefined) {
let values = nodes[i].split(response.delimiter2); const values = nodes[i].split(response.delimiter2);
if (values.length === 2) { if (values.length === 2) {
let matches = values[0].match(formatRegex); const matches = values[0].match(formatRegex);
if (!matches) { if (!matches) {
this.throwSCORMError(scorm2004_error_codes.TYPE_MISMATCH); _self.throwSCORMError(scorm2004_error_codes.TYPE_MISMATCH);
} else { } else {
if (!values[1].match(new RegExp(response.format2))) { if (!values[1].match(new RegExp(response.format2))) {
this.throwSCORMError(scorm2004_error_codes.TYPE_MISMATCH); _self.throwSCORMError(scorm2004_error_codes.TYPE_MISMATCH);
} }
} }
} else { } else {
this.throwSCORMError(scorm2004_error_codes.TYPE_MISMATCH); _self.throwSCORMError(scorm2004_error_codes.TYPE_MISMATCH);
} }
} else { } else {
let matches = nodes[i].match(formatRegex); const matches = nodes[i].match(formatRegex);
if((!matches && value !== '') || (!matches && interaction_type === 'true-false')) { if ((!matches && value !== '') ||
this.throwSCORMError(scorm2004_error_codes.TYPE_MISMATCH); (!matches && interaction_type === 'true-false')) {
_self.throwSCORMError(scorm2004_error_codes.TYPE_MISMATCH);
} else { } else {
if (interaction_type === 'numeric' && nodes.length > 1) { if (interaction_type === 'numeric' && nodes.length > 1) {
if (Number(nodes[0]) > Number(nodes[1])) { if (Number(nodes[0]) > Number(nodes[1])) {
this.throwSCORMError(scorm2004_error_codes.TYPE_MISMATCH); _self.throwSCORMError(scorm2004_error_codes.TYPE_MISMATCH);
} }
} else { } else {
if (nodes[i] !== '' && response.unique) { if (nodes[i] !== '' && response.unique) {
for(let j = 0; j < i && this.lastErrorCode === 0; j++) { for (let j = 0; j < i && _self.lastErrorCode === 0; j++) {
if (nodes[i] === nodes[j]) { if (nodes[i] === nodes[j]) {
this.throwSCORMError(scorm2004_error_codes.TYPE_MISMATCH); _self.throwSCORMError(scorm2004_error_codes.TYPE_MISMATCH);
}
} }
} }
} }
@@ -304,23 +334,26 @@ class Scorm2004API extends BaseAPI {
} }
} }
} }
};
#removeCorrectResponsePrefixes(node) { #removeCorrectResponsePrefixes = (node) => {
let seenOrder = false; let seenOrder = false;
let seenCase = false; let seenCase = false;
let seenLang = false; let seenLang = false;
let prefixRegex = '^(\{(lang|case_matters|order_matters)=([^\}]+)\})'; const prefixRegex = new RegExp(
'^({(lang|case_matters|order_matters)=([^}]+)})');
let matches = node.match(prefixRegex); let matches = node.match(prefixRegex);
let langMatches = null;
while (matches) { while (matches) {
switch (matches[2]) { switch (matches[2]) {
case 'lang': case 'lang':
let langMatches = node.match(scorm2004_regex.CMILangcr); langMatches = node.match(scorm2004_regex.CMILangcr);
if (langMatches) { if (langMatches) {
let lang = langMatches[3]; const lang = langMatches[3];
if (lang !== undefined && lang.length > 0) { if (lang !== undefined && lang.length > 0) {
if (valid_languages[lang.toLowerCase()] === undefined) { if (valid_languages[lang.toLowerCase()] === undefined) {
this.throwSCORMError(scorm2004_error_codes.TYPE_MISMATCH); _self.throwSCORMError(scorm2004_error_codes.TYPE_MISMATCH);
} }
} }
} }
@@ -329,7 +362,7 @@ class Scorm2004API extends BaseAPI {
case 'case_matters': case 'case_matters':
if (!seenLang && !seenOrder && !seenCase) { if (!seenLang && !seenOrder && !seenCase) {
if (matches[3] !== 'true' && matches[3] !== 'false') { if (matches[3] !== 'true' && matches[3] !== 'false') {
this.throwSCORMError(scorm2004_error_codes.TYPE_MISMATCH); _self.throwSCORMError(scorm2004_error_codes.TYPE_MISMATCH);
} }
} }
@@ -338,7 +371,7 @@ class Scorm2004API extends BaseAPI {
case 'order_matters': case 'order_matters':
if (!seenCase && !seenLang && !seenOrder) { if (!seenCase && !seenLang && !seenOrder) {
if (matches[3] !== 'true' && matches[3] !== 'false') { if (matches[3] !== 'true' && matches[3] !== 'false') {
this.throwSCORMError(scorm2004_error_codes.TYPE_MISMATCH); _self.throwSCORMError(scorm2004_error_codes.TYPE_MISMATCH);
} }
} }
@@ -352,28 +385,32 @@ class Scorm2004API extends BaseAPI {
} }
return node; return node;
} };
/** /**
* Replace the whole API with another * Replace the whole API with another
* @param {Scorm2004API} newAPI
*/ */
replaceWithAnotherScormAPI(newAPI) { replaceWithAnotherScormAPI(newAPI) {
// Data Model // Data Model
this.cmi = newAPI.cmi; _self.cmi = newAPI.cmi;
this.adl = newAPI.adl; _self.adl = newAPI.adl;
} }
/** /**
* Adds the current session time to the existing total time. * Adds the current session time to the existing total time.
*
* @return {string} ISO8601 Duration
*/ */
getCurrentTotalTime() { getCurrentTotalTime() {
const totalTime = this.cmi.total_time; const totalTime = _self.cmi.total_time;
const sessionTime = this.cmi.session_time; const sessionTime = _self.cmi.session_time;
const durationRegex = scorm2004_regex.CMITimespan; const durationRegex = scorm2004_regex.CMITimespan;
const totalSeconds = Utilities.getDurationAsSeconds(totalTime, durationRegex); const totalSeconds = Util.getDurationAsSeconds(totalTime, durationRegex);
const sessionSeconds = Utilities.getDurationAsSeconds(sessionTime, durationRegex); const sessionSeconds = Util.getDurationAsSeconds(sessionTime,
durationRegex);
return Utilities.getSecondsAsISODuration(totalSeconds + sessionSeconds); return Util.getSecondsAsISODuration(totalSeconds + sessionSeconds);
} }
} }

View File

@@ -1,12 +1,27 @@
import * as Scorm12CMI from './scorm12_cmi'; import * as Scorm12CMI from './scorm12_cmi';
import {BaseCMI, CMIArray, CMIScore} from "./common"; import {BaseCMI, CMIArray, CMIScore} from './common';
import {aicc_constants} from "../constants"; import {aicc_constants, scorm12_error_codes} from '../constants';
import {aicc_regex} from "../regex"; import {aicc_regex} from '../regex';
const constants = aicc_constants; const constants = aicc_constants;
const regex = aicc_regex; const regex = aicc_regex;
/**
* Sets a READ_ONLY error on the API
* @param {AICC} API
*/
function throwReadOnlyError(API) {
API.throwSCORMError(scorm12_error_codes.READ_ONLY_ELEMENT);
}
/**
* CMI Class for AICC
*/
export class CMI extends Scorm12CMI.CMI { export class CMI extends Scorm12CMI.CMI {
/**
* Constructor for AICC CMI object
* @param {AICC} API
*/
constructor(API) { constructor(API) {
super(API, constants.cmi_children, new AICCCMIStudentData(API)); super(API, constants.cmi_children, new AICCCMIStudentData(API));
@@ -14,84 +29,197 @@ export class CMI extends Scorm12CMI.CMI {
} }
} }
/**
* AICC Evaluation object
*/
class CMIEvaluation extends BaseCMI { class CMIEvaluation extends BaseCMI {
/**
* Constructor for AICC Evaluation object
* @param {AICC} API
*/
constructor(API) { constructor(API) {
super(API); super(API);
} }
comments = new class extends CMIArray { comments = new class extends CMIArray {
/**
* Constructor for AICC Evaluation Comments object
* @param {AICC} API
*/
constructor(API) { constructor(API) {
super(API, constants.comments_children, 402); super(API, constants.comments_children, 402);
} }
}; };
} }
/**
* StudentData class for AICC
*/
class AICCCMIStudentData extends Scorm12CMI.CMIStudentData { class AICCCMIStudentData extends Scorm12CMI.CMIStudentData {
/**
* Constructor for AICC StudentData object
* @param {AICC} API
*/
constructor(API) { constructor(API) {
super(API, constants.student_data_children); super(API, constants.student_data_children);
} }
#tries_during_lesson = ""; #tries_during_lesson = '';
get tries_during_lesson() { return this.#tries_during_lesson; } /**
set tries_during_lesson(tries_during_lesson) { this.API.isNotInitialized() ? this.#tries_during_lesson = tries_during_lesson : this.throwReadOnlyError() } * Getter for tries_during_lesson
* @return {string}
*/
get tries_during_lesson() {
return this.#tries_during_lesson;
}
/**
* Setter for #tries_during_lesson. Sets an error if trying to set after
* API initialization.
* @param {string} tries_during_lesson
*/
set tries_during_lesson(tries_during_lesson) {
this.API.isNotInitialized() ?
this.#tries_during_lesson = tries_during_lesson :
throwReadOnlyError();
}
tries = new class extends CMIArray { tries = new class extends CMIArray {
/**
* Constructor for inline Tries Array class
* @param {AICC} API
*/
constructor(API) { constructor(API) {
super(API, aicc_constants.tries_children); super(API, aicc_constants.tries_children);
} }
}; };
} }
let _self;
/**
* Class for AICC Tries
*/
export class CMITriesObject extends BaseCMI { export class CMITriesObject extends BaseCMI {
#API;
/**
* Constructor for AICC Tries object
* @param {AICC} API
*/
constructor(API) { constructor(API) {
super(API); super(API);
this.#API = API;
_self = this;
} }
#status = ""; #status = '';
#time = ""; #time = '';
get status() { return this.#status; } /**
* Getter for #status
* @return {string}
*/
get status() {
return this.#status;
}
/**
* Setter for #status
* @param {string} status
*/
set status(status) { set status(status) {
if (this.API.checkValidFormat(status, regex.CMIStatus2)) { if (this.API.checkValidFormat(status, regex.CMIStatus2)) {
this.#status = status; this.#status = status;
} }
} }
get time() { return this.#time; } /**
* Getter for #time
* @return {string}
*/
get time() {
return this.#time;
}
/**
* Setter for #time
* @param {string} time
*/
set time(time) { set time(time) {
if (this.API.checkValidFormat(time, regex.CMITime)) { if (this.API.checkValidFormat(time, regex.CMITime)) {
this.#time = time; this.#time = time;
} }
} }
score = new CMIScore(API); score = new CMIScore(_self.#API);
} }
/**
* Class for AICC Evaluation Comments
*/
export class CMIEvaluationCommentsObject extends BaseCMI { export class CMIEvaluationCommentsObject extends BaseCMI {
/**
* Constructor for Evaluation Comments
* @param {AICC} API
*/
constructor(API) { constructor(API) {
super(API); super(API);
} }
#content = ""; #content = '';
#location = ""; #location = '';
#time = ""; #time = '';
get content() { return this.#content; } /**
* Getter for #content
* @return {string}
*/
get content() {
return this.#content;
}
/**
* Setter for #content
* @param {string} content
*/
set content(content) { set content(content) {
if (this.API.checkValidFormat(content, regex.CMIString256)) { if (this.API.checkValidFormat(content, regex.CMIString256)) {
this.#content = content; this.#content = content;
} }
} }
get location() { return this.#location; } /**
* Getter for #location
* @return {string}
*/
get location() {
return this.#location;
}
/**
* Setter for #location
* @param {string} location
*/
set location(location) { set location(location) {
if (this.API.checkValidFormat(location, regex.CMIString256)) { if (this.API.checkValidFormat(location, regex.CMIString256)) {
this.#location = location; this.#location = location;
} }
} }
get time() { return this.#time; } /**
* Getter for #time
* @return {string}
*/
get time() {
return this.#time;
}
/**
* Setting for #time
* @param {string} time
*/
set time(time) { set time(time) {
if (this.API.checkValidFormat(time, regex.CMITime)) { if (this.API.checkValidFormat(time, regex.CMITime)) {
this.#time = time; this.#time = time;
@@ -99,14 +227,32 @@ export class CMIEvaluationCommentsObject extends BaseCMI {
} }
} }
/**
* Class for AICC Navigation object
*/
export class NAV extends BaseCMI { export class NAV extends BaseCMI {
/**
* Constructor for NAV object
* @param {AICC} API
*/
constructor(API) { constructor(API) {
super(API); super(API);
} }
#event = ""; #event = '';
get event() { return (!this.jsonString) ? this.API.throwSCORMError(404) : this.#event; } /**
* Getter for #event
* @return {string}
*/
get event() {
return (!this.jsonString) ? this.API.throwSCORMError(404) : this.#event;
}
/**
* Setter for #event
* @param {string} event
*/
set event(event) { set event(event) {
if (this.API.checkValidFormat(event, regex.NAVEvent)) { if (this.API.checkValidFormat(event, regex.NAVEvent)) {
this.#event = event; this.#event = event;

View File

@@ -1,6 +1,6 @@
import {BaseCMI, CMIArray, CMIScore} from './common'; import {BaseCMI, CMIArray, CMIScore} from './common';
import {scorm12_constants, scorm12_error_codes} from "../constants"; import {scorm12_constants, scorm12_error_codes} from '../constants';
import {scorm12_regex} from "../regex"; import {scorm12_regex} from '../regex';
const constants = scorm12_constants; const constants = scorm12_constants;
const regex = scorm12_regex; const regex = scorm12_regex;
@@ -18,12 +18,12 @@ function throwInvalidValueError(API) {
} }
export class CMI extends BaseCMI { export class CMI extends BaseCMI {
#_children = ""; #_children = '';
#_version = "3.4"; #_version = '3.4';
#suspend_data = ""; #suspend_data = '';
#launch_data = ""; #launch_data = '';
#comments = ""; #comments = '';
#comments_from_lms = ""; #comments_from_lms = '';
student_data = null; student_data = null;
@@ -33,7 +33,9 @@ export class CMI extends BaseCMI {
this.#_children = cmi_children ? cmi_children : constants.cmi_children; this.#_children = cmi_children ? cmi_children : constants.cmi_children;
this.core = new CMICore(API); this.core = new CMICore(API);
this.objectives = new CMIObjectives(API); this.objectives = new CMIObjectives(API);
this.student_data = student_data ? student_data : new CMIStudentData(API); this.student_data = student_data ?
student_data :
new CMIStudentData(API);
this.student_preference = new CMIStudentPreference(API); this.student_preference = new CMIStudentPreference(API);
this.interactions = new CMIInteractions(API); this.interactions = new CMIInteractions(API);
} }
@@ -49,101 +51,187 @@ export class CMI extends BaseCMI {
'objectives': this.objectives, 'objectives': this.objectives,
'student_data': this.student_data, 'student_data': this.student_data,
'student_preference': this.student_preference, 'student_preference': this.student_preference,
'interactions': this.interactions 'interactions': this.interactions,
}; };
delete this.jsonString; delete this.jsonString;
return result; return result;
}; };
get _version() { return this.#_version; } get _version() {
set _version(_version) { throwInvalidValueError(this.API); } return this.#_version;
}
get _children() { return this.#_children; } set _version(_version) {
set _children(_children) { throwInvalidValueError(this.API); } throwInvalidValueError(this.API);
}
get suspend_data() { return this.#suspend_data; } get _children() {
return this.#_children;
}
set _children(_children) {
throwInvalidValueError(this.API);
}
get suspend_data() {
return this.#suspend_data;
}
set suspend_data(suspend_data) { set suspend_data(suspend_data) {
if (this.API.checkValidFormat(suspend_data, regex.CMIString4096)) { if (this.API.checkValidFormat(suspend_data, regex.CMIString4096)) {
this.#suspend_data = suspend_data; this.#suspend_data = suspend_data;
} }
} }
get launch_data() { return this.#launch_data; } get launch_data() {
set launch_data(launch_data) { this.API.isNotInitialized() ? this.#launch_data = launch_data : throwReadOnlyError(this.API); } return this.#launch_data;
}
get comments() { return this.#comments; } set launch_data(launch_data) {
this.API.isNotInitialized() ?
this.#launch_data = launch_data :
throwReadOnlyError(this.API);
}
get comments() {
return this.#comments;
}
set comments(comments) { set comments(comments) {
if (this.API.checkValidFormat(comments, regex.CMIString4096)) { if (this.API.checkValidFormat(comments, regex.CMIString4096)) {
this.#comments = comments; this.#comments = comments;
} }
} }
get comments_from_lms() { return this.#comments_from_lms; } get comments_from_lms() {
set comments_from_lms(comments_from_lms) { this.API.isNotInitialized() ? this.#comments_from_lms = comments_from_lms : throwReadOnlyError(this.API); } return this.#comments_from_lms;
}
set comments_from_lms(comments_from_lms) {
this.API.isNotInitialized() ?
this.#comments_from_lms = comments_from_lms :
throwReadOnlyError(this.API);
}
} }
class CMICore extends BaseCMI { class CMICore extends BaseCMI {
constructor(API) { constructor(API) {
super(API); super(API);
this.score = new CMIScore(API, constants.score_children, regex.score_range); this.score = new CMIScore(API, constants.score_children,
regex.score_range);
} }
#_children = constants.core_children; #_children = constants.core_children;
#student_id = ""; #student_id = '';
#student_name = ""; #student_name = '';
#lesson_location = ""; #lesson_location = '';
#credit = ""; #credit = '';
#lesson_status = ""; #lesson_status = '';
#entry = ""; #entry = '';
#total_time = ""; #total_time = '';
#lesson_mode = "normal"; #lesson_mode = 'normal';
#exit = ""; #exit = '';
#session_time = "00:00:00"; #session_time = '00:00:00';
get _children() { return this.#_children; } get _children() {
set _children(_children) { throwInvalidValueError(this.API); } return this.#_children;
}
get student_id() { return this.#student_id; } set _children(_children) {
set student_id(student_id) { this.API.isNotInitialized() ? this.#student_id = student_id : throwReadOnlyError(this.API); } throwInvalidValueError(this.API);
}
get student_name() { return this.#student_name; } get student_id() {
set student_name(student_name) { this.API.isNotInitialized() ? this.#student_name = student_name : throwReadOnlyError(this.API); } return this.#student_id;
}
get lesson_location() { return this.#lesson_location; } set student_id(student_id) {
this.API.isNotInitialized() ?
this.#student_id = student_id :
throwReadOnlyError(this.API);
}
get student_name() {
return this.#student_name;
}
set student_name(student_name) {
this.API.isNotInitialized() ?
this.#student_name = student_name :
throwReadOnlyError(this.API);
}
get lesson_location() {
return this.#lesson_location;
}
set lesson_location(lesson_location) { set lesson_location(lesson_location) {
if (this.API.checkValidFormat(lesson_location, regex.CMIString256)) { if (this.API.checkValidFormat(lesson_location, regex.CMIString256)) {
this.#lesson_location = lesson_location; this.#lesson_location = lesson_location;
} }
} }
get credit() { return this.#credit; } get credit() {
set credit(credit) { this.API.isNotInitialized() ? this.#credit = credit : throwReadOnlyError(this.API); } return this.#credit;
}
get lesson_status() { return this.#lesson_status; } set credit(credit) {
this.API.isNotInitialized() ?
this.#credit = credit :
throwReadOnlyError(this.API);
}
get lesson_status() {
return this.#lesson_status;
}
set lesson_status(lesson_status) { set lesson_status(lesson_status) {
if (this.API.checkValidFormat(lesson_status, regex.CMIStatus)) { if (this.API.checkValidFormat(lesson_status, regex.CMIStatus)) {
this.#lesson_status = lesson_status; this.#lesson_status = lesson_status;
} }
} }
get entry() { return this.#entry; } get entry() {
set entry(entry) { this.API.isNotInitialized() ? this.#entry = entry : throwReadOnlyError(this.API); } return this.#entry;
}
get total_time() { return this.#total_time; } set entry(entry) {
set total_time(total_time) { this.API.isNotInitialized() ? this.#total_time = total_time : throwReadOnlyError(this.API); } this.API.isNotInitialized() ?
this.#entry = entry :
throwReadOnlyError(this.API);
}
get lesson_mode() { return this.#lesson_mode; } get total_time() {
set lesson_mode(lesson_mode) { this.API.isNotInitialized() ? this.#lesson_mode = lesson_mode : throwReadOnlyError(this.API); } return this.#total_time;
}
get exit() { return (!this.jsonString) ? throwWriteOnlyError(this.API) : this.#exit; } set total_time(total_time) {
this.API.isNotInitialized() ?
this.#total_time = total_time :
throwReadOnlyError(this.API);
}
get lesson_mode() {
return this.#lesson_mode;
}
set lesson_mode(lesson_mode) {
this.API.isNotInitialized() ?
this.#lesson_mode = lesson_mode :
throwReadOnlyError(this.API);
}
get exit() {
return (!this.jsonString) ? throwWriteOnlyError(this.API) : this.#exit;
}
set exit(exit) { set exit(exit) {
if (this.API.checkValidFormat(exit, regex.CMIExit)) { if (this.API.checkValidFormat(exit, regex.CMIExit)) {
this.#exit = exit; this.#exit = exit;
} }
} }
get session_time() { return (!this.jsonString) ? throwWriteOnlyError(this.API) : this.#session_time; } get session_time() {
return (!this.jsonString) ?
throwWriteOnlyError(this.API) :
this.#session_time;
}
set session_time(session_time) { set session_time(session_time) {
if (this.API.checkValidFormat(session_time, regex.CMITimespan)) { if (this.API.checkValidFormat(session_time, regex.CMITimespan)) {
this.#session_time = session_time; this.#session_time = session_time;
@@ -163,7 +251,7 @@ class CMICore extends BaseCMI {
'lesson_mode': this.lesson_mode, 'lesson_mode': this.lesson_mode,
'exit': this.exit, 'exit': this.exit,
'session_time': this.session_time, 'session_time': this.session_time,
'score': this.score 'score': this.score,
}; };
delete this.jsonString; delete this.jsonString;
return result; return result;
@@ -175,7 +263,7 @@ class CMIObjectives extends CMIArray {
super({ super({
API: API, API: API,
children: constants.objectives_children, children: constants.objectives_children,
errorCode: scorm12_error_codes.INVALID_SET_VALUE errorCode: scorm12_error_codes.INVALID_SET_VALUE,
}); });
} }
} }
@@ -183,34 +271,62 @@ class CMIObjectives extends CMIArray {
export class CMIStudentData extends BaseCMI { export class CMIStudentData extends BaseCMI {
#_children; #_children;
#mastery_score = ""; #mastery_score = '';
#max_time_allowed = ""; #max_time_allowed = '';
#time_limit_action = ""; #time_limit_action = '';
constructor(API, student_data_children) { constructor(API, student_data_children) {
super(API); super(API);
this.#_children = student_data_children? student_data_children : constants.student_data_children; this.#_children = student_data_children ?
student_data_children :
constants.student_data_children;
} }
get _children() { return this.#_children; } get _children() {
set _children(_children) { throwInvalidValueError(this.API); } return this.#_children;
}
get mastery_score() { return this.#mastery_score; } set _children(_children) {
set mastery_score(mastery_score) { this.API.isNotInitialized() ? this.#mastery_score = mastery_score : throwReadOnlyError(this.API); } throwInvalidValueError(this.API);
}
get max_time_allowed() { return this.#max_time_allowed; } get mastery_score() {
set max_time_allowed(max_time_allowed) { this.API.isNotInitialized() ? this.#max_time_allowed = max_time_allowed : throwReadOnlyError(this.API); } return this.#mastery_score;
}
get time_limit_action() { return this.#time_limit_action; } set mastery_score(mastery_score) {
set time_limit_action(time_limit_action) { this.API.isNotInitialized() ? this.#time_limit_action = time_limit_action : throwReadOnlyError(this.API); } this.API.isNotInitialized() ?
this.#mastery_score = mastery_score :
throwReadOnlyError(this.API);
}
get max_time_allowed() {
return this.#max_time_allowed;
}
set max_time_allowed(max_time_allowed) {
this.API.isNotInitialized() ?
this.#max_time_allowed = max_time_allowed :
throwReadOnlyError(this.API);
}
get time_limit_action() {
return this.#time_limit_action;
}
set time_limit_action(time_limit_action) {
this.API.isNotInitialized() ?
this.#time_limit_action = time_limit_action :
throwReadOnlyError(this.API);
}
toJSON = () => { toJSON = () => {
this.jsonString = true; this.jsonString = true;
const result = { const result = {
'mastery_score': this.mastery_score, 'mastery_score': this.mastery_score,
'max_time_allowed': this.max_time_allowed, 'max_time_allowed': this.max_time_allowed,
'time_limit_action': this.time_limit_action 'time_limit_action': this.time_limit_action,
}; };
delete this.jsonString; delete this.jsonString;
return result; return result;
@@ -223,41 +339,54 @@ class CMIStudentPreference extends BaseCMI {
} }
#_children = constants.student_preference_children; #_children = constants.student_preference_children;
#audio = ""; #audio = '';
#language = ""; #language = '';
#speed = ""; #speed = '';
#text = ""; #text = '';
get _children() { return this.#_children; } get _children() {
set _children(_children) { throwInvalidValueError(this.API); } return this.#_children;
}
get audio() { return this.#audio; } set _children(_children) {
throwInvalidValueError(this.API);
}
get audio() {
return this.#audio;
}
set audio(audio) { set audio(audio) {
if(this.API.checkValidFormat(audio, regex.CMISInteger) if (this.API.checkValidFormat(audio, regex.CMISInteger) &&
&& this.API.checkValidRange(audio, regex.audio_range)) { this.API.checkValidRange(audio, regex.audio_range)) {
this.#audio = audio; this.#audio = audio;
} }
} }
get language() { return this.#language; } get language() {
return this.#language;
}
set language(language) { set language(language) {
if (this.API.checkValidFormat(language, regex.CMIString256)) { if (this.API.checkValidFormat(language, regex.CMIString256)) {
this.#language = language; this.#language = language;
} }
} }
get speed() { return this.#speed; } get speed() {
return this.#speed;
}
set speed(speed) { set speed(speed) {
if(this.API.checkValidFormat(speed, regex.CMISInteger) if (this.API.checkValidFormat(speed, regex.CMISInteger) &&
&& this.API.checkValidRange(speed, regex.speed_range)) { this.API.checkValidRange(speed, regex.speed_range)) {
this.#speed = speed; this.#speed = speed;
} }
} }
get text() { return this.#text; } get text() {
return this.#text;
}
set text(text) { set text(text) {
if(this.API.checkValidFormat(text, regex.CMISInteger) if (this.API.checkValidFormat(text, regex.CMISInteger) &&
&& this.API.checkValidRange(text, regex.text_range)) { this.API.checkValidRange(text, regex.text_range)) {
this.#text = text; this.#text = text;
} }
} }
@@ -268,7 +397,7 @@ class CMIStudentPreference extends BaseCMI {
'audio': this.audio, 'audio': this.audio,
'language': this.language, 'language': this.language,
'speed': this.speed, 'speed': this.speed,
'text': this.text 'text': this.text,
}; };
delete this.jsonString; delete this.jsonString;
return result; return result;
@@ -280,7 +409,7 @@ class CMIInteractions extends CMIArray {
super({ super({
API: API, API: API,
children: constants.interactions_children, children: constants.interactions_children,
errorCode: scorm12_error_codes.INVALID_SET_VALUE errorCode: scorm12_error_codes.INVALID_SET_VALUE,
}); });
} }
} }
@@ -292,12 +421,12 @@ export class CMIInteractionsObject extends BaseCMI {
this.objectives = new CMIArray({ this.objectives = new CMIArray({
API: API, API: API,
errorCode: 402, errorCode: 402,
children: constants.objectives_children children: constants.objectives_children,
}); });
this.correct_responses = new CMIArray({ this.correct_responses = new CMIArray({
API: API, API: API,
errorCode: 402, errorCode: 402,
children: constants.correct_responses_children children: constants.correct_responses_children,
}); });
} }
@@ -309,50 +438,72 @@ export class CMIInteractionsObject extends BaseCMI {
#result: ""; #result: "";
#latency: ""; #latency: "";
get id() { return (!this.jsonString) ? throwWriteOnlyError(this.API) : this.#id; } get id() {
return (!this.jsonString) ? throwWriteOnlyError(this.API) : this.#id;
}
set id(id) { set id(id) {
if (this.API.checkValidFormat(id, regex.CMIIdentifier)) { if (this.API.checkValidFormat(id, regex.CMIIdentifier)) {
this.#id = id; this.#id = id;
} }
} }
get time() { return (!this.jsonString) ? throwWriteOnlyError(this.API) : this.#time; } get time() {
return (!this.jsonString) ? throwWriteOnlyError(this.API) : this.#time;
}
set time(time) { set time(time) {
if (this.API.checkValidFormat(time, regex.CMITime)) { if (this.API.checkValidFormat(time, regex.CMITime)) {
this.#time = time; this.#time = time;
} }
} }
get type() { return (!this.jsonString) ? throwWriteOnlyError(this.API) : this.#type; } get type() {
return (!this.jsonString) ? throwWriteOnlyError(this.API) : this.#type;
}
set type(type) { set type(type) {
if (this.API.checkValidFormat(type, regex.CMIType)) { if (this.API.checkValidFormat(type, regex.CMIType)) {
this.#type = type; this.#type = type;
} }
} }
get weighting() { return (!this.jsonString) ? throwWriteOnlyError(this.API) : this.#weighting; } get weighting() {
return (!this.jsonString) ?
throwWriteOnlyError(this.API) :
this.#weighting;
}
set weighting(weighting) { set weighting(weighting) {
if(this.API.checkValidFormat(weighting, regex.CMIDecimal) if (this.API.checkValidFormat(weighting, regex.CMIDecimal) &&
&& this.API.checkValidRange(weighting, regex.weighting_range)) { this.API.checkValidRange(weighting, regex.weighting_range)) {
this.#weighting = weighting; this.#weighting = weighting;
} }
} }
get student_response() { return (!this.jsonString) ? throwWriteOnlyError(this.API) : this.#student_response; } get student_response() {
return (!this.jsonString) ?
throwWriteOnlyError(this.API) :
this.#student_response;
}
set student_response(student_response) { set student_response(student_response) {
if (this.API.checkValidFormat(student_response, regex.CMIFeedback)) { if (this.API.checkValidFormat(student_response, regex.CMIFeedback)) {
this.#student_response = student_response; this.#student_response = student_response;
} }
} }
get result() { return (!this.jsonString) ? throwWriteOnlyError(this.API) : this.#result; } get result() {
return (!this.jsonString) ?
throwWriteOnlyError(this.API) :
this.#result;
}
set result(result) { set result(result) {
if (this.API.checkValidFormat(result, regex.CMIResult)) { if (this.API.checkValidFormat(result, regex.CMIResult)) {
this.#result = result; this.#result = result;
} }
} }
get latency() { return (!this.jsonString) ? throwWriteOnlyError(this.API) : this.#latency; } get latency() {
return (!this.jsonString) ?
throwWriteOnlyError(this.API) :
this.#latency;
}
set latency(latency) { set latency(latency) {
if (this.API.checkValidFormat(latency, regex.CMITimespan)) { if (this.API.checkValidFormat(latency, regex.CMITimespan)) {
this.#latency = latency; this.#latency = latency;
@@ -370,7 +521,7 @@ export class CMIInteractionsObject extends BaseCMI {
'result': this.result, 'result': this.result,
'latency': this.latency, 'latency': this.latency,
'objectives': this.objectives, 'objectives': this.objectives,
'correct_responses': this.correct_responses 'correct_responses': this.correct_responses,
}; };
delete this.jsonString; delete this.jsonString;
return result; return result;
@@ -387,14 +538,18 @@ export class CMIObjectivesObject extends BaseCMI {
#id: ""; #id: "";
#status: ""; #status: "";
get id() { return this.#id; } get id() {
return this.#id;
}
set id(id) { set id(id) {
if (this.API.checkValidFormat(id, regex.CMIIdentifier)) { if (this.API.checkValidFormat(id, regex.CMIIdentifier)) {
this.#id = id; this.#id = id;
} }
} }
get status() { return this.#status; } get status() {
return this.#status;
}
set status(status) { set status(status) {
if (this.API.checkValidFormat(status, regex.CMIStatus2)) { if (this.API.checkValidFormat(status, regex.CMIStatus2)) {
this.#status = status; this.#status = status;
@@ -406,7 +561,7 @@ export class CMIObjectivesObject extends BaseCMI {
const result = { const result = {
'id': this.id, 'id': this.id,
'status': this.status, 'status': this.status,
'score': this.score 'score': this.score,
}; };
delete this.jsonString; delete this.jsonString;
return result; return result;
@@ -420,7 +575,9 @@ export class CMIInteractionsObjectivesObject extends BaseCMI {
#id: ""; #id: "";
get id() { return this.#id; } get id() {
return this.#id;
}
set id(id) { set id(id) {
if (this.API.checkValidFormat(id, regex.CMIIdentifier)) { if (this.API.checkValidFormat(id, regex.CMIIdentifier)) {
this.#id = id; this.#id = id;
@@ -444,7 +601,9 @@ export class CMIInteractionsCorrectResponsesObject extends BaseCMI {
#pattern: ""; #pattern: "";
get pattern() { return this.#pattern; } get pattern() {
return this.#pattern;
}
set pattern(pattern) { set pattern(pattern) {
if (this.API.checkValidFormat(pattern, regex.CMIFeedback)) { if (this.API.checkValidFormat(pattern, regex.CMIFeedback)) {
this.#pattern = pattern; this.#pattern = pattern;

View File

@@ -14,8 +14,8 @@ const designations = [
/** /**
* Converts a Number to a String of HH:MM:SS * Converts a Number to a String of HH:MM:SS
* *
* @param totalSeconds * @param {Number} totalSeconds
* @returns {string} * @return {string}
*/ */
export function getSecondsAsHHMMSS(totalSeconds: Number) { export function getSecondsAsHHMMSS(totalSeconds: Number) {
// SCORM spec does not deal with negative durations, give zero back // SCORM spec does not deal with negative durations, give zero back
@@ -23,11 +23,11 @@ export function getSecondsAsHHMMSS(totalSeconds: Number) {
return '00:00:00'; return '00:00:00';
} }
let hours = Math.floor(totalSeconds / SECONDS_PER_HOUR); const hours = Math.floor(totalSeconds / SECONDS_PER_HOUR);
let dateObj = new Date(totalSeconds * 1000); const dateObj = new Date(totalSeconds * 1000);
let minutes = dateObj.getUTCMinutes(); const minutes = dateObj.getUTCMinutes();
let seconds = dateObj.getSeconds(); const seconds = dateObj.getSeconds();
return hours.toString().padStart(2, '0') + ':' + return hours.toString().padStart(2, '0') + ':' +
minutes.toString().padStart(2, '0') + ':' + minutes.toString().padStart(2, '0') + ':' +
@@ -37,8 +37,8 @@ export function getSecondsAsHHMMSS(totalSeconds: Number) {
/** /**
* Calculate the number of seconds from ISO 8601 Duration * Calculate the number of seconds from ISO 8601 Duration
* *
* @param seconds * @param {Number} seconds
* @returns {String} * @return {String}
*/ */
export function getSecondsAsISODuration(seconds: Number) { export function getSecondsAsISODuration(seconds: Number) {
// SCORM spec does not deal with negative durations, give zero back // SCORM spec does not deal with negative durations, give zero back
@@ -65,12 +65,13 @@ export function getSecondsAsISODuration(seconds: Number) {
/** /**
* Calculate the number of seconds from HH:MM:SS.DDDDDD * Calculate the number of seconds from HH:MM:SS.DDDDDD
* *
* @param timeString * @param {string} timeString
* @param timeRegex * @param {RegExp} timeRegex
* @returns {number} * @return {number}
*/ */
export function getTimeAsSeconds(timeString: String, timeRegex: RegExp) { export function getTimeAsSeconds(timeString: String, timeRegex: RegExp) {
if(!timeString || typeof timeString !== 'string' || !timeString.match(timeRegex)) { if (!timeString || typeof timeString !== 'string' ||
!timeString.match(timeRegex)) {
return 0; return 0;
} }
const parts = timeString.split(':'); const parts = timeString.split(':');
@@ -83,19 +84,20 @@ export function getTimeAsSeconds(timeString: String, timeRegex: RegExp) {
/** /**
* Calculate the number of seconds from ISO 8601 Duration * Calculate the number of seconds from ISO 8601 Duration
* *
* @param duration * @param {string} duration
* @param durationRegex * @param {RegExp} durationRegex
* @returns {number} * @return {number}
*/ */
export function getDurationAsSeconds(duration: String, durationRegex: RegExp) { export function getDurationAsSeconds(duration: String, durationRegex: RegExp) {
if (!duration || !duration.match(durationRegex)) { if (!duration || !duration.match(durationRegex)) {
return 0; return 0;
} }
let [,years,months,,days,hours,minutes,seconds] = new RegExp(durationRegex).exec(duration) || []; const [, years, months, , days, hours, minutes, seconds] = new RegExp(
durationRegex).exec(duration) || [];
let now = new Date(); const now = new Date();
let anchor = new Date(now); const anchor = new Date(now);
anchor.setFullYear(anchor.getFullYear() + Number(years || 0)); anchor.setFullYear(anchor.getFullYear() + Number(years || 0));
anchor.setMonth(anchor.getMonth() + Number(months || 0)); anchor.setMonth(anchor.getMonth() + Number(months || 0));
anchor.setDate(anchor.getDate() + Number(days || 0)); anchor.setDate(anchor.getDate() + Number(days || 0));
@@ -103,7 +105,7 @@ export function getDurationAsSeconds(duration: String, durationRegex: RegExp) {
anchor.setMinutes(anchor.getMinutes() + Number(minutes || 0)); anchor.setMinutes(anchor.getMinutes() + Number(minutes || 0));
anchor.setSeconds(anchor.getSeconds() + Number(seconds || 0)); anchor.setSeconds(anchor.getSeconds() + Number(seconds || 0));
if (seconds) { if (seconds) {
let milliseconds = Number(Number(seconds) % 1).toFixed(6) * 1000.0; const milliseconds = Number(Number(seconds) % 1).toFixed(6) * 1000.0;
anchor.setMilliseconds(anchor.getMilliseconds() + milliseconds); anchor.setMilliseconds(anchor.getMilliseconds() + milliseconds);
} }