Removed circular dependencies between APIs and CMI objects
No longer directly setting error codes on the API when a read/write or data validation fails, throwing exceptions instead that can then be caught by the APi.
This commit is contained in:
247
src/BaseAPI.js
247
src/BaseAPI.js
@@ -14,8 +14,6 @@ const api_constants = {
|
||||
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.
|
||||
@@ -31,14 +29,13 @@ export default class BaseAPI {
|
||||
* @param {object} error_codes
|
||||
*/
|
||||
constructor(error_codes) {
|
||||
_self = this;
|
||||
_self.currentState = api_constants.STATE_NOT_INITIALIZED;
|
||||
_self.apiLogLevel = api_constants.LOG_LEVEL_ERROR;
|
||||
_self.lastErrorCode = 0;
|
||||
_self.listenerArray = [];
|
||||
this.currentState = api_constants.STATE_NOT_INITIALIZED;
|
||||
this.apiLogLevel = api_constants.LOG_LEVEL_ERROR;
|
||||
this.lastErrorCode = 0;
|
||||
this.listenerArray = [];
|
||||
|
||||
_self.#timeout = null;
|
||||
_self.#error_codes = error_codes;
|
||||
this.#timeout = null;
|
||||
this.#error_codes = error_codes;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -54,20 +51,20 @@ export default class BaseAPI {
|
||||
terminationMessage?: String) {
|
||||
let returnValue = api_constants.SCORM_FALSE;
|
||||
|
||||
if (_self.isInitialized()) {
|
||||
_self.throwSCORMError(_self.#error_codes.INITIALIZED, initializeMessage);
|
||||
} else if (_self.isTerminated()) {
|
||||
_self.throwSCORMError(_self.#error_codes.TERMINATED, terminationMessage);
|
||||
if (this.isInitialized()) {
|
||||
this.throwSCORMError(this.#error_codes.INITIALIZED, initializeMessage);
|
||||
} else if (this.isTerminated()) {
|
||||
this.throwSCORMError(this.#error_codes.TERMINATED, terminationMessage);
|
||||
} else {
|
||||
_self.currentState = api_constants.STATE_INITIALIZED;
|
||||
_self.lastErrorCode = 0;
|
||||
this.currentState = api_constants.STATE_INITIALIZED;
|
||||
this.lastErrorCode = 0;
|
||||
returnValue = api_constants.SCORM_TRUE;
|
||||
_self.processListeners(callbackName);
|
||||
this.processListeners(callbackName);
|
||||
}
|
||||
|
||||
_self.apiLog(callbackName, null, 'returned: ' + returnValue,
|
||||
this.apiLog(callbackName, null, 'returned: ' + returnValue,
|
||||
api_constants.LOG_LEVEL_INFO);
|
||||
_self.clearSCORMError(returnValue);
|
||||
this.clearSCORMError(returnValue);
|
||||
|
||||
return returnValue;
|
||||
}
|
||||
@@ -83,18 +80,18 @@ export default class BaseAPI {
|
||||
checkTerminated: boolean) {
|
||||
let returnValue = api_constants.SCORM_FALSE;
|
||||
|
||||
if (_self.checkState(checkTerminated,
|
||||
_self.#error_codes.TERMINATION_BEFORE_INIT,
|
||||
_self.#error_codes.MULTIPLE_TERMINATION)) {
|
||||
if (checkTerminated) _self.lastErrorCode = 0;
|
||||
_self.currentState = api_constants.STATE_TERMINATED;
|
||||
if (this.checkState(checkTerminated,
|
||||
this.#error_codes.TERMINATION_BEFORE_INIT,
|
||||
this.#error_codes.MULTIPLE_TERMINATION)) {
|
||||
if (checkTerminated) this.lastErrorCode = 0;
|
||||
this.currentState = api_constants.STATE_TERMINATED;
|
||||
returnValue = api_constants.SCORM_TRUE;
|
||||
_self.processListeners(callbackName);
|
||||
this.processListeners(callbackName);
|
||||
}
|
||||
|
||||
_self.apiLog(callbackName, null, 'returned: ' + returnValue,
|
||||
this.apiLog(callbackName, null, 'returned: ' + returnValue,
|
||||
api_constants.LOG_LEVEL_INFO);
|
||||
_self.clearSCORMError(returnValue);
|
||||
this.clearSCORMError(returnValue);
|
||||
|
||||
return returnValue;
|
||||
}
|
||||
@@ -113,17 +110,17 @@ export default class BaseAPI {
|
||||
CMIElement: String) {
|
||||
let returnValue = '';
|
||||
|
||||
if (_self.checkState(checkTerminated,
|
||||
_self.#error_codes.RETRIEVE_BEFORE_INIT,
|
||||
_self.#error_codes.RETRIEVE_AFTER_TERM)) {
|
||||
if (checkTerminated) _self.lastErrorCode = 0;
|
||||
returnValue = _self.getCMIValue(CMIElement);
|
||||
_self.processListeners(callbackName, CMIElement);
|
||||
if (this.checkState(checkTerminated,
|
||||
this.#error_codes.RETRIEVE_BEFORE_INIT,
|
||||
this.#error_codes.RETRIEVE_AFTER_TERM)) {
|
||||
if (checkTerminated) this.lastErrorCode = 0;
|
||||
returnValue = this.getCMIValue(CMIElement);
|
||||
this.processListeners(callbackName, CMIElement);
|
||||
}
|
||||
|
||||
_self.apiLog(callbackName, CMIElement, ': returned: ' + returnValue,
|
||||
this.apiLog(callbackName, CMIElement, ': returned: ' + returnValue,
|
||||
api_constants.LOG_LEVEL_INFO);
|
||||
_self.clearSCORMError(returnValue);
|
||||
this.clearSCORMError(returnValue);
|
||||
|
||||
return returnValue;
|
||||
}
|
||||
@@ -144,17 +141,17 @@ export default class BaseAPI {
|
||||
value) {
|
||||
let returnValue = '';
|
||||
|
||||
if (_self.checkState(checkTerminated, _self.#error_codes.STORE_BEFORE_INIT,
|
||||
_self.#error_codes.STORE_AFTER_TERM)) {
|
||||
if (checkTerminated) _self.lastErrorCode = 0;
|
||||
returnValue = _self.setCMIValue(CMIElement, value);
|
||||
_self.processListeners(callbackName, CMIElement, value);
|
||||
if (this.checkState(checkTerminated, this.#error_codes.STORE_BEFORE_INIT,
|
||||
this.#error_codes.STORE_AFTER_TERM)) {
|
||||
if (checkTerminated) this.lastErrorCode = 0;
|
||||
returnValue = this.setCMIValue(CMIElement, value);
|
||||
this.processListeners(callbackName, CMIElement, value);
|
||||
}
|
||||
|
||||
_self.apiLog(callbackName, CMIElement,
|
||||
this.apiLog(callbackName, CMIElement,
|
||||
': ' + value + ': result: ' + returnValue,
|
||||
api_constants.LOG_LEVEL_INFO);
|
||||
_self.clearSCORMError(returnValue);
|
||||
this.clearSCORMError(returnValue);
|
||||
|
||||
return returnValue;
|
||||
}
|
||||
@@ -170,16 +167,16 @@ export default class BaseAPI {
|
||||
checkTerminated: boolean) {
|
||||
let returnValue = api_constants.SCORM_FALSE;
|
||||
|
||||
if (_self.checkState(checkTerminated, _self.#error_codes.COMMIT_BEFORE_INIT,
|
||||
_self.#error_codes.COMMIT_AFTER_TERM)) {
|
||||
if (checkTerminated) _self.lastErrorCode = 0;
|
||||
if (this.checkState(checkTerminated, this.#error_codes.COMMIT_BEFORE_INIT,
|
||||
this.#error_codes.COMMIT_AFTER_TERM)) {
|
||||
if (checkTerminated) this.lastErrorCode = 0;
|
||||
returnValue = api_constants.SCORM_TRUE;
|
||||
_self.processListeners(callbackName);
|
||||
this.processListeners(callbackName);
|
||||
}
|
||||
|
||||
_self.apiLog(callbackName, null, 'returned: ' + returnValue,
|
||||
this.apiLog(callbackName, null, 'returned: ' + returnValue,
|
||||
api_constants.LOG_LEVEL_INFO);
|
||||
_self.clearSCORMError(returnValue);
|
||||
this.clearSCORMError(returnValue);
|
||||
|
||||
return returnValue;
|
||||
}
|
||||
@@ -190,11 +187,11 @@ export default class BaseAPI {
|
||||
* @return {string}
|
||||
*/
|
||||
getLastError(callbackName: String) {
|
||||
const returnValue = String(_self.lastErrorCode);
|
||||
const returnValue = String(this.lastErrorCode);
|
||||
|
||||
_self.processListeners(callbackName);
|
||||
this.processListeners(callbackName);
|
||||
|
||||
_self.apiLog(callbackName, null, 'returned: ' + returnValue,
|
||||
this.apiLog(callbackName, null, 'returned: ' + returnValue,
|
||||
api_constants.LOG_LEVEL_INFO);
|
||||
|
||||
return returnValue;
|
||||
@@ -211,11 +208,11 @@ export default class BaseAPI {
|
||||
let returnValue = '';
|
||||
|
||||
if (CMIErrorCode !== null && CMIErrorCode !== '') {
|
||||
returnValue = _self.getLmsErrorMessageDetails(CMIErrorCode);
|
||||
_self.processListeners(callbackName);
|
||||
returnValue = this.getLmsErrorMessageDetails(CMIErrorCode);
|
||||
this.processListeners(callbackName);
|
||||
}
|
||||
|
||||
_self.apiLog(callbackName, null, 'returned: ' + returnValue,
|
||||
this.apiLog(callbackName, null, 'returned: ' + returnValue,
|
||||
api_constants.LOG_LEVEL_INFO);
|
||||
|
||||
return returnValue;
|
||||
@@ -232,11 +229,11 @@ export default class BaseAPI {
|
||||
let returnValue = '';
|
||||
|
||||
if (CMIErrorCode !== null && CMIErrorCode !== '') {
|
||||
returnValue = _self.getLmsErrorMessageDetails(CMIErrorCode, true);
|
||||
_self.processListeners(callbackName);
|
||||
returnValue = this.getLmsErrorMessageDetails(CMIErrorCode, true);
|
||||
this.processListeners(callbackName);
|
||||
}
|
||||
|
||||
_self.apiLog(callbackName, null, 'returned: ' + returnValue,
|
||||
this.apiLog(callbackName, null, 'returned: ' + returnValue,
|
||||
api_constants.LOG_LEVEL_INFO);
|
||||
|
||||
return returnValue;
|
||||
@@ -254,11 +251,11 @@ export default class BaseAPI {
|
||||
checkTerminated: boolean,
|
||||
beforeInitError: number,
|
||||
afterTermError?: number) {
|
||||
if (_self.isNotInitialized()) {
|
||||
_self.throwSCORMError(beforeInitError);
|
||||
if (this.isNotInitialized()) {
|
||||
this.throwSCORMError(beforeInitError);
|
||||
return false;
|
||||
} else if (checkTerminated && _self.isTerminated()) {
|
||||
_self.throwSCORMError(afterTermError);
|
||||
} else if (checkTerminated && this.isTerminated()) {
|
||||
this.throwSCORMError(afterTermError);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -278,9 +275,9 @@ export default class BaseAPI {
|
||||
CMIElement: String,
|
||||
logMessage: String,
|
||||
messageLevel: number) {
|
||||
logMessage = _self.formatMessage(functionName, CMIElement, logMessage);
|
||||
logMessage = this.formatMessage(functionName, CMIElement, logMessage);
|
||||
|
||||
if (messageLevel >= _self.apiLogLevel) {
|
||||
if (messageLevel >= this.apiLogLevel) {
|
||||
switch (messageLevel) {
|
||||
case api_constants.LOG_LEVEL_ERROR:
|
||||
console.error(logMessage);
|
||||
@@ -402,8 +399,8 @@ export default class BaseAPI {
|
||||
|
||||
const invalidErrorMessage = `The data model element passed to ${methodName} (${CMIElement}) is not a valid SCORM data model element.`;
|
||||
const invalidErrorCode = scorm2004 ?
|
||||
_self.#error_codes.UNDEFINED_DATA_MODEL :
|
||||
_self.#error_codes.GENERAL;
|
||||
this.#error_codes.UNDEFINED_DATA_MODEL :
|
||||
this.#error_codes.GENERAL;
|
||||
|
||||
for (let i = 0; i < structure.length; i++) {
|
||||
const attribute = structure[i];
|
||||
@@ -411,15 +408,15 @@ export default class BaseAPI {
|
||||
if (i === structure.length - 1) {
|
||||
if (scorm2004 && (attribute.substr(0, 8) === '{target=') &&
|
||||
(typeof refObject._isTargetValid == 'function')) {
|
||||
_self.throwSCORMError(_self.#error_codes.READ_ONLY_ELEMENT);
|
||||
this.throwSCORMError(this.#error_codes.READ_ONLY_ELEMENT);
|
||||
} else if (!{}.hasOwnProperty.call(refObject, attribute)) {
|
||||
_self.throwSCORMError(invalidErrorCode, invalidErrorMessage);
|
||||
this.throwSCORMError(invalidErrorCode, invalidErrorMessage);
|
||||
} else {
|
||||
if (_self.stringContains(CMIElement, '.correct_responses')) {
|
||||
_self.validateCorrectResponse(CMIElement, value);
|
||||
if (this.stringContains(CMIElement, '.correct_responses')) {
|
||||
this.validateCorrectResponse(CMIElement, value);
|
||||
}
|
||||
|
||||
if (!scorm2004 || _self.lastErrorCode === 0) {
|
||||
if (!scorm2004 || this.lastErrorCode === 0) {
|
||||
refObject[attribute] = value;
|
||||
returnValue = api_constants.SCORM_TRUE;
|
||||
}
|
||||
@@ -427,7 +424,7 @@ export default class BaseAPI {
|
||||
} else {
|
||||
refObject = refObject[attribute];
|
||||
if (!refObject) {
|
||||
_self.throwSCORMError(invalidErrorCode, invalidErrorMessage);
|
||||
this.throwSCORMError(invalidErrorCode, invalidErrorMessage);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -441,10 +438,10 @@ export default class BaseAPI {
|
||||
if (item) {
|
||||
refObject = item;
|
||||
} else {
|
||||
const newChild = _self.getChildElement(CMIElement, value);
|
||||
const newChild = this.getChildElement(CMIElement, value);
|
||||
|
||||
if (!newChild) {
|
||||
_self.throwSCORMError(invalidErrorCode, invalidErrorMessage);
|
||||
this.throwSCORMError(invalidErrorCode, invalidErrorMessage);
|
||||
} else {
|
||||
refObject.childArray.push(newChild);
|
||||
refObject = newChild;
|
||||
@@ -459,7 +456,7 @@ export default class BaseAPI {
|
||||
}
|
||||
|
||||
if (returnValue === api_constants.SCORM_FALSE) {
|
||||
_self.apiLog(methodName, null,
|
||||
this.apiLog(methodName, null,
|
||||
`There was an error setting the value for: ${CMIElement}, value of: ${value}`,
|
||||
api_constants.LOG_LEVEL_WARNING);
|
||||
}
|
||||
@@ -512,7 +509,7 @@ export default class BaseAPI {
|
||||
if (!scorm2004) {
|
||||
if (i === structure.length - 1) {
|
||||
if (!{}.hasOwnProperty.call(refObject, attribute)) {
|
||||
_self.throwSCORMError(101,
|
||||
this.throwSCORMError(101,
|
||||
'getCMIValue did not find a value for: ' + CMIElement);
|
||||
}
|
||||
}
|
||||
@@ -523,7 +520,7 @@ export default class BaseAPI {
|
||||
substr(8, String(attribute).length - 9);
|
||||
return refObject._isTargetValid(target);
|
||||
} else if (!{}.hasOwnProperty.call(refObject, attribute)) {
|
||||
_self.throwSCORMError(401,
|
||||
this.throwSCORMError(401,
|
||||
'The data model element passed to GetValue (' + CMIElement +
|
||||
') is not a valid SCORM data model element.');
|
||||
return '';
|
||||
@@ -536,9 +533,9 @@ export default class BaseAPI {
|
||||
if (refObject === null || refObject === undefined) {
|
||||
if (!scorm2004) {
|
||||
if (attribute === '_children') {
|
||||
_self.throwSCORMError(202);
|
||||
this.throwSCORMError(202);
|
||||
} else if (attribute === '_count') {
|
||||
_self.throwSCORMError(203);
|
||||
this.throwSCORMError(203);
|
||||
}
|
||||
}
|
||||
return '';
|
||||
@@ -553,7 +550,7 @@ export default class BaseAPI {
|
||||
* @return {boolean}
|
||||
*/
|
||||
isInitialized() {
|
||||
return _self.currentState === api_constants.STATE_INITIALIZED;
|
||||
return this.currentState === api_constants.STATE_INITIALIZED;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -562,7 +559,7 @@ export default class BaseAPI {
|
||||
* @return {boolean}
|
||||
*/
|
||||
isNotInitialized() {
|
||||
return _self.currentState === api_constants.STATE_NOT_INITIALIZED;
|
||||
return this.currentState === api_constants.STATE_NOT_INITIALIZED;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -571,7 +568,7 @@ export default class BaseAPI {
|
||||
* @return {boolean}
|
||||
*/
|
||||
isTerminated() {
|
||||
return _self.currentState === api_constants.STATE_TERMINATED;
|
||||
return this.currentState === api_constants.STATE_TERMINATED;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -595,7 +592,7 @@ export default class BaseAPI {
|
||||
CMIElement = listenerName.replace(functionName + '.', '');
|
||||
}
|
||||
|
||||
_self.listenerArray.push({
|
||||
this.listenerArray.push({
|
||||
functionName: functionName,
|
||||
CMIElement: CMIElement,
|
||||
callback: callback,
|
||||
@@ -611,8 +608,8 @@ export default class BaseAPI {
|
||||
* @param {*} value
|
||||
*/
|
||||
processListeners(functionName: String, CMIElement: String, value: any) {
|
||||
for (let i = 0; i < _self.listenerArray.length; i++) {
|
||||
const listener = _self.listenerArray[i];
|
||||
for (let i = 0; i < this.listenerArray.length; i++) {
|
||||
const listener = this.listenerArray[i];
|
||||
const functionsMatch = listener.functionName === functionName;
|
||||
const listenerHasCMIElement = !!listener.CMIElement;
|
||||
const CMIElementsMatch = listener.CMIElement === CMIElement;
|
||||
@@ -631,13 +628,13 @@ export default class BaseAPI {
|
||||
*/
|
||||
throwSCORMError(errorNumber: number, message: String) {
|
||||
if (!message) {
|
||||
message = _self.getLmsErrorMessageDetails(errorNumber);
|
||||
message = this.getLmsErrorMessageDetails(errorNumber);
|
||||
}
|
||||
|
||||
_self.apiLog('throwSCORMError', null, errorNumber + ': ' + message,
|
||||
this.apiLog('throwSCORMError', null, errorNumber + ': ' + message,
|
||||
api_constants.LOG_LEVEL_ERROR);
|
||||
|
||||
_self.lastErrorCode = String(errorNumber);
|
||||
this.lastErrorCode = String(errorNumber);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -647,7 +644,7 @@ export default class BaseAPI {
|
||||
*/
|
||||
clearSCORMError(success: String) {
|
||||
if (success !== api_constants.SCORM_FALSE) {
|
||||
_self.lastErrorCode = 0;
|
||||
this.lastErrorCode = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -658,7 +655,7 @@ export default class BaseAPI {
|
||||
* @param {string} CMIElement
|
||||
*/
|
||||
loadFromJSON(json, CMIElement) {
|
||||
if (!_self.isNotInitialized()) {
|
||||
if (!this.isNotInitialized()) {
|
||||
console.error(
|
||||
'loadFromJSON can only be called before the call to lmsInitialize.');
|
||||
return;
|
||||
@@ -673,13 +670,13 @@ export default class BaseAPI {
|
||||
|
||||
if (value['childArray']) {
|
||||
for (let i = 0; i < value['childArray'].length; i++) {
|
||||
_self.loadFromJSON(value['childArray'][i],
|
||||
this.loadFromJSON(value['childArray'][i],
|
||||
currentCMIElement + '.' + i);
|
||||
}
|
||||
} else if (value.constructor === Object) {
|
||||
_self.loadFromJSON(value, currentCMIElement);
|
||||
this.loadFromJSON(value, currentCMIElement);
|
||||
} else {
|
||||
_self.setCMIValue(currentCMIElement, value);
|
||||
this.setCMIValue(currentCMIElement, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -691,68 +688,28 @@ export default class BaseAPI {
|
||||
* @return {string}
|
||||
*/
|
||||
renderCMIToJSON() {
|
||||
const cmi = _self.cmi;
|
||||
const cmi = this.cmi;
|
||||
// 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});
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the value matches the proper format. If not, throw proper error code.
|
||||
*
|
||||
* @param {string} value
|
||||
* @param {string} regexPattern
|
||||
* @return {boolean}
|
||||
*/
|
||||
checkValidFormat(value: String, regexPattern: String) {
|
||||
const formatRegex = new RegExp(regexPattern);
|
||||
if (!value || !value.match(formatRegex)) {
|
||||
_self.throwSCORMError(_self.#error_codes.TYPE_MISMATCH);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the value matches the proper range. If not, throw proper error code.
|
||||
*
|
||||
* @param {*} value
|
||||
* @param {string} rangePattern
|
||||
* @return {boolean}
|
||||
*/
|
||||
checkValidRange(value: any, rangePattern: String) {
|
||||
const ranges = rangePattern.split('#');
|
||||
value = value * 1.0;
|
||||
if (value >= ranges[0]) {
|
||||
if ((ranges[1] === '*') || (value <= ranges[1])) {
|
||||
_self.clearSCORMError(api_constants.SCORM_TRUE);
|
||||
return true;
|
||||
} else {
|
||||
_self.throwSCORMError(_self.#error_codes.VALUE_OUT_OF_RANGE);
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
_self.throwSCORMError(_self.#error_codes.VALUE_OUT_OF_RANGE);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Throws a SCORM error
|
||||
*
|
||||
* @param {number} when - the number of milliseconds to wait before committing
|
||||
*/
|
||||
scheduleCommit(when: number) {
|
||||
_self.#timeout = new ScheduledCommit(this, when);
|
||||
this.#timeout = new ScheduledCommit(this, when);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears and cancels any currently scheduled commits
|
||||
*/
|
||||
clearScheduledCommit() {
|
||||
if (_self.#timeout) {
|
||||
_self.#timeout.cancel();
|
||||
_self.#timeout = null;
|
||||
if (this.#timeout) {
|
||||
this.#timeout.cancel();
|
||||
this.#timeout = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -771,26 +728,26 @@ class ScheduledCommit {
|
||||
* @param {number} when
|
||||
*/
|
||||
constructor(API: any, when: number) {
|
||||
_self.#API = API;
|
||||
_self.#timeout = setTimeout(_self.#wrapper, when);
|
||||
this.#API = API;
|
||||
this.#timeout = setTimeout(this.#wrapper, when);
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancel any currently scheduled commit
|
||||
*/
|
||||
cancel() {
|
||||
_self.#cancelled = true;
|
||||
if (_self.#timeout) {
|
||||
clearTimeout(_self.#timeout);
|
||||
this.#cancelled = true;
|
||||
if (this.#timeout) {
|
||||
clearTimeout(this.#timeout);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrap the API commit call to check if the call has already been cancelled
|
||||
*/
|
||||
#wrapper = () => {
|
||||
if (!_self.#cancelled) {
|
||||
_self.#API.commit();
|
||||
#wrapper() {
|
||||
if (!this.#cancelled) {
|
||||
this.#API.commit();
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,12 +18,11 @@ import {valid_languages} from './constants/language_constants';
|
||||
import {scorm2004_regex} from './regex';
|
||||
|
||||
const constants = scorm2004_constants;
|
||||
let _self;
|
||||
|
||||
/**
|
||||
* API class for SCORM 2004
|
||||
*/
|
||||
class Scorm2004API extends BaseAPI {
|
||||
export default class Scorm2004API extends BaseAPI {
|
||||
#version: '1.0';
|
||||
|
||||
/**
|
||||
@@ -32,19 +31,18 @@ class Scorm2004API extends BaseAPI {
|
||||
constructor() {
|
||||
super(scorm2004_error_codes);
|
||||
|
||||
_self = this;
|
||||
_self.cmi = new CMI(_self);
|
||||
_self.adl = new ADL(_self);
|
||||
this.cmi = new CMI(this);
|
||||
this.adl = new ADL(this);
|
||||
|
||||
// Rename functions to match 2004 Spec and expose to modules
|
||||
_self.Initialize = _self.lmsInitialize;
|
||||
_self.Terminate = _self.lmsTerminate;
|
||||
_self.GetValue = _self.lmsGetValue;
|
||||
_self.SetValue = _self.lmsSetValue;
|
||||
_self.Commit = _self.lmsCommit;
|
||||
_self.GetLastError = _self.lmsGetLastError;
|
||||
_self.GetErrorString = _self.lmsGetErrorString;
|
||||
_self.GetDiagnostic = _self.lmsGetDiagnostic;
|
||||
this.Initialize = this.lmsInitialize;
|
||||
this.Terminate = this.lmsTerminate;
|
||||
this.GetValue = this.lmsGetValue;
|
||||
this.SetValue = this.lmsSetValue;
|
||||
this.Commit = this.lmsCommit;
|
||||
this.GetLastError = this.lmsGetLastError;
|
||||
this.GetErrorString = this.lmsGetErrorString;
|
||||
this.GetDiagnostic = this.lmsGetDiagnostic;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -59,14 +57,14 @@ class Scorm2004API extends BaseAPI {
|
||||
* @return {string} bool
|
||||
*/
|
||||
lmsInitialize() {
|
||||
return _self.initialize('Initialize');
|
||||
return this.initialize('Initialize');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {string} bool
|
||||
*/
|
||||
lmsTerminate() {
|
||||
return _self.terminate('Terminate', true);
|
||||
return this.terminate('Terminate', true);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -74,7 +72,7 @@ class Scorm2004API extends BaseAPI {
|
||||
* @return {string}
|
||||
*/
|
||||
lmsGetValue(CMIElement) {
|
||||
return _self.getValue('GetValue', true, CMIElement);
|
||||
return this.getValue('GetValue', true, CMIElement);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -83,7 +81,7 @@ class Scorm2004API extends BaseAPI {
|
||||
* @return {string}
|
||||
*/
|
||||
lmsSetValue(CMIElement, value) {
|
||||
return _self.setValue('SetValue', true, CMIElement, value);
|
||||
return this.setValue('SetValue', true, CMIElement, value);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -92,7 +90,7 @@ class Scorm2004API extends BaseAPI {
|
||||
* @return {string} bool
|
||||
*/
|
||||
lmsCommit() {
|
||||
return _self.commit('Commit');
|
||||
return this.commit('Commit');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -101,7 +99,7 @@ class Scorm2004API extends BaseAPI {
|
||||
* @return {string}
|
||||
*/
|
||||
lmsGetLastError() {
|
||||
return _self.getLastError('GetLastError');
|
||||
return this.getLastError('GetLastError');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -111,7 +109,7 @@ class Scorm2004API extends BaseAPI {
|
||||
* @return {string}
|
||||
*/
|
||||
lmsGetErrorString(CMIErrorCode) {
|
||||
return _self.getErrorString('GetErrorString', CMIErrorCode);
|
||||
return this.getErrorString('GetErrorString', CMIErrorCode);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -121,7 +119,7 @@ class Scorm2004API extends BaseAPI {
|
||||
* @return {string}
|
||||
*/
|
||||
lmsGetDiagnostic(CMIErrorCode) {
|
||||
return _self.getDiagnostic('GetDiagnostic', CMIErrorCode);
|
||||
return this.getDiagnostic('GetDiagnostic', CMIErrorCode);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -131,7 +129,7 @@ class Scorm2004API extends BaseAPI {
|
||||
* @param {any} value
|
||||
*/
|
||||
setCMIValue(CMIElement, value) {
|
||||
_self._commonSetCMIValue('SetValue', true, CMIElement, value);
|
||||
this._commonSetCMIValue('SetValue', true, CMIElement, value);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -144,23 +142,23 @@ class Scorm2004API extends BaseAPI {
|
||||
getChildElement(CMIElement, value) {
|
||||
let newChild;
|
||||
|
||||
if (_self.stringContains(CMIElement, 'cmi.objectives')) {
|
||||
if (this.stringContains(CMIElement, 'cmi.objectives')) {
|
||||
newChild = new CMIObjectivesObject(this);
|
||||
} else if (_self.stringContains(CMIElement, '.correct_responses')) {
|
||||
} else if (this.stringContains(CMIElement, '.correct_responses')) {
|
||||
const parts = CMIElement.split('.');
|
||||
const index = Number(parts[2]);
|
||||
const interaction = _self.cmi.interactions.childArray[index];
|
||||
const interaction = this.cmi.interactions.childArray[index];
|
||||
if (typeof interaction.type === 'undefined') {
|
||||
_self.throwSCORMError(scorm2004_error_codes.DEPENDENCY_NOT_ESTABLISHED);
|
||||
this.throwSCORMError(scorm2004_error_codes.DEPENDENCY_NOT_ESTABLISHED);
|
||||
} else {
|
||||
const interaction_type = interaction.type;
|
||||
const interaction_count = interaction.correct_responses._count;
|
||||
if (interaction_type === 'choice') {
|
||||
for (let i = 0; i < interaction_count && _self.lastErrorCode ===
|
||||
for (let i = 0; i < interaction_count && this.lastErrorCode ===
|
||||
0; i++) {
|
||||
const response = interaction.correct_responses.childArray[i];
|
||||
if (response.pattern === value) {
|
||||
_self.throwSCORMError(scorm2004_error_codes.GENERAL_SET_FAILURE);
|
||||
this.throwSCORMError(scorm2004_error_codes.GENERAL_SET_FAILURE);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -174,22 +172,22 @@ class Scorm2004API extends BaseAPI {
|
||||
}
|
||||
|
||||
if (nodes.length > 0 && nodes.length <= response_type.max) {
|
||||
_self.#checkCorrectResponseValue(interaction_type, nodes, value);
|
||||
this.#checkCorrectResponseValue(interaction_type, nodes, value);
|
||||
} else if (nodes.length > response_type.max) {
|
||||
_self.throwSCORMError(scorm2004_error_codes.GENERAL_SET_FAILURE,
|
||||
this.throwSCORMError(scorm2004_error_codes.GENERAL_SET_FAILURE,
|
||||
'Data Model Element Pattern Too Long');
|
||||
}
|
||||
}
|
||||
if (_self.lastErrorCode === 0) {
|
||||
if (this.lastErrorCode === 0) {
|
||||
newChild = new CMIInteractionsCorrectResponsesObject(this);
|
||||
}
|
||||
} else if (_self.stringContains(CMIElement, '.objectives')) {
|
||||
} else if (this.stringContains(CMIElement, '.objectives')) {
|
||||
newChild = new CMIInteractionsObjectivesObject(this);
|
||||
} else if (_self.stringContains(CMIElement, 'cmi.interactions')) {
|
||||
} else if (this.stringContains(CMIElement, 'cmi.interactions')) {
|
||||
newChild = new CMIInteractionsObject(this);
|
||||
} else if (_self.stringContains(CMIElement, 'cmi.comments_from_learner')) {
|
||||
} else if (this.stringContains(CMIElement, 'cmi.comments_from_learner')) {
|
||||
newChild = new CMICommentsFromLearnerObject(this);
|
||||
} else if (_self.stringContains(CMIElement, 'cmi.comments_from_lms')) {
|
||||
} else if (this.stringContains(CMIElement, 'cmi.comments_from_lms')) {
|
||||
newChild = new CMICommentsFromLMSObject(this);
|
||||
}
|
||||
|
||||
@@ -205,15 +203,15 @@ class Scorm2004API extends BaseAPI {
|
||||
const parts = CMIElement.split('.');
|
||||
const index = Number(parts[2]);
|
||||
const pattern_index = Number(parts[4]);
|
||||
const interaction = _self.cmi.interactions.childArray[index];
|
||||
const interaction = this.cmi.interactions.childArray[index];
|
||||
|
||||
const interaction_type = interaction.type;
|
||||
const interaction_count = interaction.correct_responses._count;
|
||||
if (interaction_type === 'choice') {
|
||||
for (let i = 0; i < interaction_count && _self.lastErrorCode === 0; i++) {
|
||||
for (let i = 0; i < interaction_count && this.lastErrorCode === 0; i++) {
|
||||
const response = interaction.correct_responses.childArray[i];
|
||||
if (response.pattern === value) {
|
||||
_self.throwSCORMError(scorm2004_error_codes.GENERAL_SET_FAILURE);
|
||||
this.throwSCORMError(scorm2004_error_codes.GENERAL_SET_FAILURE);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -229,26 +227,26 @@ class Scorm2004API extends BaseAPI {
|
||||
}
|
||||
|
||||
if (nodes.length > 0 && nodes.length <= response_type.max) {
|
||||
_self.#checkCorrectResponseValue(interaction_type, nodes, value);
|
||||
this.#checkCorrectResponseValue(interaction_type, nodes, value);
|
||||
} else if (nodes.length > response_type.max) {
|
||||
_self.throwSCORMError(scorm2004_error_codes.GENERAL_SET_FAILURE,
|
||||
this.throwSCORMError(scorm2004_error_codes.GENERAL_SET_FAILURE,
|
||||
'Data Model Element Pattern Too Long');
|
||||
}
|
||||
|
||||
if (_self.lastErrorCode === 0 &&
|
||||
if (this.lastErrorCode === 0 &&
|
||||
(!response_type.duplicate ||
|
||||
!_self.#checkDuplicatedPattern(interaction.correct_responses,
|
||||
!this.#checkDuplicatedPattern(interaction.correct_responses,
|
||||
pattern_index, value)) ||
|
||||
(_self.lastErrorCode === 0 && value === '')) {
|
||||
(this.lastErrorCode === 0 && value === '')) {
|
||||
// do nothing, we want the inverse
|
||||
} else {
|
||||
if (_self.lastErrorCode === 0) {
|
||||
_self.throwSCORMError(scorm2004_error_codes.GENERAL_SET_FAILURE,
|
||||
if (this.lastErrorCode === 0) {
|
||||
this.throwSCORMError(scorm2004_error_codes.GENERAL_SET_FAILURE,
|
||||
'Data Model Element Pattern Already Exists');
|
||||
}
|
||||
}
|
||||
} else {
|
||||
_self.throwSCORMError(scorm2004_error_codes.GENERAL_SET_FAILURE,
|
||||
this.throwSCORMError(scorm2004_error_codes.GENERAL_SET_FAILURE,
|
||||
'Data Model Element Collection Limit Reached');
|
||||
}
|
||||
}
|
||||
@@ -260,7 +258,7 @@ class Scorm2004API extends BaseAPI {
|
||||
* @return {*}
|
||||
*/
|
||||
getCMIValue(CMIElement) {
|
||||
return _self._commonGetCMIValue('GetValue', true, CMIElement);
|
||||
return this._commonGetCMIValue('GetValue', true, CMIElement);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -311,10 +309,10 @@ class Scorm2004API extends BaseAPI {
|
||||
#checkCorrectResponseValue = (interaction_type, nodes, value) => {
|
||||
const response = correct_responses[interaction_type];
|
||||
const formatRegex = new RegExp(response.format);
|
||||
for (let i = 0; i < nodes.length && _self.lastErrorCode === 0; i++) {
|
||||
for (let i = 0; i < nodes.length && this.lastErrorCode === 0; i++) {
|
||||
if (interaction_type.match(
|
||||
'^(fill-in|long-fill-in|matching|performance|sequencing)$')) {
|
||||
nodes[i] = _self.#removeCorrectResponsePrefixes(nodes[i]);
|
||||
nodes[i] = this.#removeCorrectResponsePrefixes(nodes[i]);
|
||||
}
|
||||
|
||||
if (response.delimiter2 !== undefined) {
|
||||
@@ -322,30 +320,30 @@ class Scorm2004API extends BaseAPI {
|
||||
if (values.length === 2) {
|
||||
const matches = values[0].match(formatRegex);
|
||||
if (!matches) {
|
||||
_self.throwSCORMError(scorm2004_error_codes.TYPE_MISMATCH);
|
||||
this.throwSCORMError(scorm2004_error_codes.TYPE_MISMATCH);
|
||||
} else {
|
||||
if (!values[1].match(new RegExp(response.format2))) {
|
||||
_self.throwSCORMError(scorm2004_error_codes.TYPE_MISMATCH);
|
||||
this.throwSCORMError(scorm2004_error_codes.TYPE_MISMATCH);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
_self.throwSCORMError(scorm2004_error_codes.TYPE_MISMATCH);
|
||||
this.throwSCORMError(scorm2004_error_codes.TYPE_MISMATCH);
|
||||
}
|
||||
} else {
|
||||
const matches = nodes[i].match(formatRegex);
|
||||
if ((!matches && value !== '') ||
|
||||
(!matches && interaction_type === 'true-false')) {
|
||||
_self.throwSCORMError(scorm2004_error_codes.TYPE_MISMATCH);
|
||||
this.throwSCORMError(scorm2004_error_codes.TYPE_MISMATCH);
|
||||
} else {
|
||||
if (interaction_type === 'numeric' && nodes.length > 1) {
|
||||
if (Number(nodes[0]) > Number(nodes[1])) {
|
||||
_self.throwSCORMError(scorm2004_error_codes.TYPE_MISMATCH);
|
||||
this.throwSCORMError(scorm2004_error_codes.TYPE_MISMATCH);
|
||||
}
|
||||
} else {
|
||||
if (nodes[i] !== '' && response.unique) {
|
||||
for (let j = 0; j < i && _self.lastErrorCode === 0; j++) {
|
||||
for (let j = 0; j < i && this.lastErrorCode === 0; j++) {
|
||||
if (nodes[i] === nodes[j]) {
|
||||
_self.throwSCORMError(scorm2004_error_codes.TYPE_MISMATCH);
|
||||
this.throwSCORMError(scorm2004_error_codes.TYPE_MISMATCH);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -377,7 +375,7 @@ class Scorm2004API extends BaseAPI {
|
||||
const lang = langMatches[3];
|
||||
if (lang !== undefined && lang.length > 0) {
|
||||
if (valid_languages[lang.toLowerCase()] === undefined) {
|
||||
_self.throwSCORMError(scorm2004_error_codes.TYPE_MISMATCH);
|
||||
this.throwSCORMError(scorm2004_error_codes.TYPE_MISMATCH);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -386,7 +384,7 @@ class Scorm2004API extends BaseAPI {
|
||||
case 'case_matters':
|
||||
if (!seenLang && !seenOrder && !seenCase) {
|
||||
if (matches[3] !== 'true' && matches[3] !== 'false') {
|
||||
_self.throwSCORMError(scorm2004_error_codes.TYPE_MISMATCH);
|
||||
this.throwSCORMError(scorm2004_error_codes.TYPE_MISMATCH);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -395,7 +393,7 @@ class Scorm2004API extends BaseAPI {
|
||||
case 'order_matters':
|
||||
if (!seenCase && !seenLang && !seenOrder) {
|
||||
if (matches[3] !== 'true' && matches[3] !== 'false') {
|
||||
_self.throwSCORMError(scorm2004_error_codes.TYPE_MISMATCH);
|
||||
this.throwSCORMError(scorm2004_error_codes.TYPE_MISMATCH);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -417,8 +415,8 @@ class Scorm2004API extends BaseAPI {
|
||||
*/
|
||||
replaceWithAnotherScormAPI(newAPI) {
|
||||
// Data Model
|
||||
_self.cmi = newAPI.cmi;
|
||||
_self.adl = newAPI.adl;
|
||||
this.cmi = newAPI.cmi;
|
||||
this.adl = newAPI.adl;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -427,8 +425,8 @@ class Scorm2004API extends BaseAPI {
|
||||
* @return {string} ISO8601 Duration
|
||||
*/
|
||||
getCurrentTotalTime() {
|
||||
const totalTime = _self.cmi.total_time;
|
||||
const sessionTime = _self.cmi.session_time;
|
||||
const totalTime = this.cmi.total_time;
|
||||
const sessionTime = this.cmi.session_time;
|
||||
|
||||
return Util.addTwoDurations(totalTime, sessionTime,
|
||||
scorm2004_regex.CMITimespan);
|
||||
|
||||
@@ -3,31 +3,38 @@ import {BaseCMI, CMIArray, CMIScore} from './common';
|
||||
import {aicc_constants} from '../constants/api_constants';
|
||||
import {aicc_regex} from '../regex';
|
||||
import {scorm12_error_codes} from '../constants/error_codes';
|
||||
import {ValidationError} from '../exceptions';
|
||||
import {check12ValidFormat} from './scorm12_cmi';
|
||||
import {throwReadOnlyError} from './scorm12_cmi';
|
||||
import {throwWriteOnlyError} from './scorm12_cmi';
|
||||
|
||||
const constants = aicc_constants;
|
||||
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 {
|
||||
/**
|
||||
* Constructor for AICC CMI object
|
||||
* @param {AICC} API
|
||||
* @param {boolean} initialized
|
||||
*/
|
||||
constructor(API) {
|
||||
super(API, constants.cmi_children);
|
||||
constructor(initialized: boolean) {
|
||||
super(constants.cmi_children);
|
||||
|
||||
this.student_data = new AICCCMIStudentData(API);
|
||||
this.evaluation = new CMIEvaluation(API);
|
||||
if (initialized) this.initialize();
|
||||
|
||||
this.student_data = new AICCCMIStudentData();
|
||||
this.evaluation = new CMIEvaluation();
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the API has been initialized after the CMI has been created
|
||||
*/
|
||||
initialize() {
|
||||
super.initialize();
|
||||
this.student_data?.initialize();
|
||||
this.evaluation?.initialize();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,12 +44,19 @@ export class CMI extends Scorm12CMI.CMI {
|
||||
class CMIEvaluation extends BaseCMI {
|
||||
/**
|
||||
* Constructor for AICC Evaluation object
|
||||
* @param {AICC} API
|
||||
*/
|
||||
constructor(API) {
|
||||
super(API);
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.comments = new CMIEvaluationComments(API);
|
||||
this.comments = new CMIEvaluationComments();
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the API has been initialized after the CMI has been created
|
||||
*/
|
||||
initialize() {
|
||||
super.initialize();
|
||||
this.comments?.initialize();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,10 +66,9 @@ class CMIEvaluation extends BaseCMI {
|
||||
class CMIEvaluationComments extends CMIArray {
|
||||
/**
|
||||
* Constructor for AICC Evaluation Comments object
|
||||
* @param {AICC} API
|
||||
*/
|
||||
constructor(API) {
|
||||
super(API, constants.comments_children,
|
||||
constructor() {
|
||||
super(constants.comments_children,
|
||||
scorm12_error_codes.INVALID_SET_VALUE);
|
||||
}
|
||||
}
|
||||
@@ -66,12 +79,19 @@ class CMIEvaluationComments extends CMIArray {
|
||||
class AICCCMIStudentData extends Scorm12CMI.CMIStudentData {
|
||||
/**
|
||||
* Constructor for AICC StudentData object
|
||||
* @param {AICC} API
|
||||
*/
|
||||
constructor(API) {
|
||||
super(API, constants.student_data_children);
|
||||
constructor() {
|
||||
super(constants.student_data_children);
|
||||
|
||||
this.tries = new CMITries(API);
|
||||
this.tries = new CMITries();
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the API has been initialized after the CMI has been created
|
||||
*/
|
||||
initialize() {
|
||||
super.initialize();
|
||||
this.tries?.initialize();
|
||||
}
|
||||
|
||||
#tries_during_lesson = '';
|
||||
@@ -86,13 +106,13 @@ class AICCCMIStudentData extends Scorm12CMI.CMIStudentData {
|
||||
|
||||
/**
|
||||
* Setter for #tries_during_lesson. Sets an error if trying to set after
|
||||
* API initialization.
|
||||
* initialization.
|
||||
* @param {string} tries_during_lesson
|
||||
*/
|
||||
set tries_during_lesson(tries_during_lesson) {
|
||||
this.API.isNotInitialized() ?
|
||||
!this.initialized ?
|
||||
this.#tries_during_lesson = tries_during_lesson :
|
||||
throwReadOnlyError(this.API);
|
||||
throwReadOnlyError();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -102,10 +122,9 @@ class AICCCMIStudentData extends Scorm12CMI.CMIStudentData {
|
||||
export class CMITries extends CMIArray {
|
||||
/**
|
||||
* Constructor for inline Tries Array class
|
||||
* @param {AICC} API
|
||||
*/
|
||||
constructor(API) {
|
||||
super(API, aicc_constants.tries_children);
|
||||
constructor() {
|
||||
super(aicc_constants.tries_children);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -115,12 +134,19 @@ export class CMITries extends CMIArray {
|
||||
export class CMITriesObject extends BaseCMI {
|
||||
/**
|
||||
* Constructor for AICC Tries object
|
||||
* @param {AICC} API
|
||||
*/
|
||||
constructor(API) {
|
||||
super(API);
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.score = new CMIScore(API);
|
||||
this.score = new CMIScore();
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the API has been initialized after the CMI has been created
|
||||
*/
|
||||
initialize() {
|
||||
super.initialize();
|
||||
this.score?.initialize();
|
||||
}
|
||||
|
||||
#status = '';
|
||||
@@ -139,7 +165,7 @@ export class CMITriesObject extends BaseCMI {
|
||||
* @param {string} status
|
||||
*/
|
||||
set status(status) {
|
||||
if (this.API.checkValidFormat(status, regex.CMIStatus2)) {
|
||||
if (check12ValidFormat(status, regex.CMIStatus2)) {
|
||||
this.#status = status;
|
||||
}
|
||||
}
|
||||
@@ -157,7 +183,7 @@ export class CMITriesObject extends BaseCMI {
|
||||
* @param {string} time
|
||||
*/
|
||||
set time(time) {
|
||||
if (this.API.checkValidFormat(time, regex.CMITime)) {
|
||||
if (check12ValidFormat(time, regex.CMITime)) {
|
||||
this.#time = time;
|
||||
}
|
||||
}
|
||||
@@ -169,10 +195,9 @@ export class CMITriesObject extends BaseCMI {
|
||||
export class CMIEvaluationCommentsObject extends BaseCMI {
|
||||
/**
|
||||
* Constructor for Evaluation Comments
|
||||
* @param {AICC} API
|
||||
*/
|
||||
constructor(API) {
|
||||
super(API);
|
||||
constructor() {
|
||||
super();
|
||||
}
|
||||
|
||||
#content = '';
|
||||
@@ -192,7 +217,7 @@ export class CMIEvaluationCommentsObject extends BaseCMI {
|
||||
* @param {string} content
|
||||
*/
|
||||
set content(content) {
|
||||
if (this.API.checkValidFormat(content, regex.CMIString256)) {
|
||||
if (check12ValidFormat(content, regex.CMIString256)) {
|
||||
this.#content = content;
|
||||
}
|
||||
}
|
||||
@@ -210,7 +235,7 @@ export class CMIEvaluationCommentsObject extends BaseCMI {
|
||||
* @param {string} location
|
||||
*/
|
||||
set location(location) {
|
||||
if (this.API.checkValidFormat(location, regex.CMIString256)) {
|
||||
if (check12ValidFormat(location, regex.CMIString256)) {
|
||||
this.#location = location;
|
||||
}
|
||||
}
|
||||
@@ -228,7 +253,7 @@ export class CMIEvaluationCommentsObject extends BaseCMI {
|
||||
* @param {string} time
|
||||
*/
|
||||
set time(time) {
|
||||
if (this.API.checkValidFormat(time, regex.CMITime)) {
|
||||
if (check12ValidFormat(time, regex.CMITime)) {
|
||||
this.#time = time;
|
||||
}
|
||||
}
|
||||
@@ -240,10 +265,9 @@ export class CMIEvaluationCommentsObject extends BaseCMI {
|
||||
export class NAV extends BaseCMI {
|
||||
/**
|
||||
* Constructor for NAV object
|
||||
* @param {AICC} API
|
||||
*/
|
||||
constructor(API) {
|
||||
super(API);
|
||||
constructor() {
|
||||
super();
|
||||
}
|
||||
|
||||
#event = '';
|
||||
@@ -253,9 +277,7 @@ export class NAV extends BaseCMI {
|
||||
* @return {string}
|
||||
*/
|
||||
get event() {
|
||||
return (!this.jsonString) ?
|
||||
this.API.throwSCORMError(scorm12_error_codes.WRITE_ONLY_ELEMENT) :
|
||||
this.#event;
|
||||
return (!this.jsonString) ? throwWriteOnlyError() : this.#event;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -263,7 +285,7 @@ export class NAV extends BaseCMI {
|
||||
* @param {string} event
|
||||
*/
|
||||
set event(event) {
|
||||
if (this.API.checkValidFormat(event, regex.NAVEvent)) {
|
||||
if (check12ValidFormat(event, regex.NAVEvent)) {
|
||||
this.#event = event;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,20 +1,68 @@
|
||||
// @flow
|
||||
import {scorm12_constants} from '../constants/api_constants';
|
||||
import {scorm12_error_codes} from '../constants/error_codes';
|
||||
import {ValidationError} from '../exceptions';
|
||||
|
||||
/**
|
||||
* Check if the value matches the proper format. If not, throw proper error code.
|
||||
*
|
||||
* @param {string} value
|
||||
* @param {string} regexPattern
|
||||
* @param {number} errorCode
|
||||
* @return {boolean}
|
||||
*/
|
||||
export function checkValidFormat(
|
||||
value: String, regexPattern: String, errorCode: number) {
|
||||
const formatRegex = new RegExp(regexPattern);
|
||||
if (!value || !value.match(formatRegex)) {
|
||||
throw new ValidationError(errorCode);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the value matches the proper range. If not, throw proper error code.
|
||||
*
|
||||
* @param {*} value
|
||||
* @param {string} rangePattern
|
||||
* @param {number} errorCode
|
||||
* @return {boolean}
|
||||
*/
|
||||
export function checkValidRange(
|
||||
value: any, rangePattern: String, errorCode: number) {
|
||||
const ranges = rangePattern.split('#');
|
||||
value = value * 1.0;
|
||||
if (value >= ranges[0]) {
|
||||
if ((ranges[1] === '*') || (value <= ranges[1])) {
|
||||
return true;
|
||||
} else {
|
||||
throw new ValidationError(errorCode);
|
||||
}
|
||||
} else {
|
||||
throw new ValidationError(errorCode);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Base class for API cmi objects
|
||||
*/
|
||||
export class BaseCMI {
|
||||
jsonString = false;
|
||||
API;
|
||||
#initialized = false;
|
||||
|
||||
/**
|
||||
* Constructor for base cmi
|
||||
* @param {BaseAPI} API
|
||||
* Getter for #initialized
|
||||
* @return {boolean}
|
||||
*/
|
||||
constructor(API: any) {
|
||||
this.API = API;
|
||||
get initialized() {
|
||||
return this.#initialized;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the API has been initialized after the CMI has been created
|
||||
*/
|
||||
initialize() {
|
||||
this.#initialized = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,29 +72,48 @@ export class BaseCMI {
|
||||
export class CMIScore extends BaseCMI {
|
||||
/**
|
||||
* Constructor for *.score
|
||||
* @param {BaseAPI} API
|
||||
* @param {string} score_children
|
||||
* @param {string} score_range
|
||||
* @param {string} max
|
||||
* @param {number} invalidErrorCode
|
||||
* @param {number} invalidTypeCode
|
||||
* @param {number} invalidRangeCode
|
||||
*/
|
||||
constructor(API, score_children?, score_range?, invalidErrorCode) {
|
||||
super(API);
|
||||
constructor(
|
||||
{
|
||||
score_children,
|
||||
score_range,
|
||||
max,
|
||||
invalidErrorCode,
|
||||
invalidTypeCode,
|
||||
invalidRangeCode,
|
||||
}) {
|
||||
super();
|
||||
|
||||
this.#_children = score_children ?
|
||||
score_children :
|
||||
scorm12_constants.score_children;
|
||||
this.#_score_range = score_range ? score_range : false;
|
||||
this.#max = max ? max : '100';
|
||||
this.#_invalid_error_code = invalidErrorCode ?
|
||||
invalidErrorCode :
|
||||
scorm12_error_codes.INVALID_SET_VALUE;
|
||||
this.#_invalid_type_code = invalidTypeCode ?
|
||||
invalidTypeCode :
|
||||
scorm12_error_codes.TYPE_MISMATCH;
|
||||
this.#_invalid_range_code = invalidRangeCode ?
|
||||
invalidRangeCode :
|
||||
scorm12_error_codes.VALUE_OUT_OF_RANGE;
|
||||
}
|
||||
|
||||
#_children;
|
||||
#_score_range;
|
||||
#_invalid_error_code;
|
||||
#_invalid_type_code;
|
||||
#_invalid_range_code;
|
||||
#raw = '';
|
||||
#min = '';
|
||||
#max = '100';
|
||||
#max;
|
||||
|
||||
/**
|
||||
* Getter for _children
|
||||
@@ -63,7 +130,7 @@ export class CMIScore extends BaseCMI {
|
||||
* @private
|
||||
*/
|
||||
set _children(_children) {
|
||||
this.API.throwSCORMError(this.#_invalid_error_code);
|
||||
throw new ValidationError(this.#_invalid_error_code);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -79,9 +146,11 @@ export class CMIScore extends BaseCMI {
|
||||
* @param {string} raw
|
||||
*/
|
||||
set raw(raw) {
|
||||
if (this.API.checkValidFormat(raw, scorm12_constants.CMIDecimal) &&
|
||||
if (checkValidFormat(raw, scorm12_constants.CMIDecimal,
|
||||
this.#_invalid_type_code) &&
|
||||
(!this.#_score_range ||
|
||||
this.API.checkValidRange(raw, this.#_score_range))) {
|
||||
checkValidRange(raw, this.#_score_range,
|
||||
this.#_invalid_range_code))) {
|
||||
this.#raw = raw;
|
||||
}
|
||||
}
|
||||
@@ -99,9 +168,11 @@ export class CMIScore extends BaseCMI {
|
||||
* @param {string} min
|
||||
*/
|
||||
set min(min) {
|
||||
if (this.API.checkValidFormat(min, scorm12_constants.CMIDecimal) &&
|
||||
if (checkValidFormat(min, scorm12_constants.CMIDecimal,
|
||||
this.#_invalid_type_code) &&
|
||||
(!this.#_score_range ||
|
||||
this.API.checkValidRange(min, this.#_score_range))) {
|
||||
checkValidRange(min, this.#_score_range,
|
||||
this.#_invalid_range_code))) {
|
||||
this.#min = min;
|
||||
}
|
||||
}
|
||||
@@ -119,9 +190,11 @@ export class CMIScore extends BaseCMI {
|
||||
* @param {string} max
|
||||
*/
|
||||
set max(max) {
|
||||
if (this.API.checkValidFormat(max, scorm12_constants.CMIDecimal) &&
|
||||
if (checkValidFormat(max, scorm12_constants.CMIDecimal,
|
||||
this.#_invalid_type_code) &&
|
||||
(!this.#_score_range ||
|
||||
this.API.checkValidRange(max, this.#_score_range))) {
|
||||
checkValidRange(max, this.#_score_range,
|
||||
this.#_invalid_range_code))) {
|
||||
this.#max = max;
|
||||
}
|
||||
}
|
||||
@@ -145,12 +218,11 @@ export class CMIScore extends BaseCMI {
|
||||
export class CMIArray extends BaseCMI {
|
||||
/**
|
||||
* Constructor cmi *.n arrays
|
||||
* @param {BaseAPI} API
|
||||
* @param {string} children
|
||||
* @param {number} errorCode
|
||||
*/
|
||||
constructor({API, children, errorCode}) {
|
||||
super(API);
|
||||
constructor({children, errorCode}) {
|
||||
super();
|
||||
this.#_children = children;
|
||||
this.#errorCode = errorCode;
|
||||
this.childArray = [];
|
||||
@@ -174,7 +246,7 @@ export class CMIArray extends BaseCMI {
|
||||
* @private
|
||||
*/
|
||||
set _children(_children) {
|
||||
this.API.throwSCORMError(this.#errorCode);
|
||||
throw new ValidationError(this.#errorCode);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -192,7 +264,7 @@ export class CMIArray extends BaseCMI {
|
||||
* @private
|
||||
*/
|
||||
set _count(_count) {
|
||||
this.API.throwSCORMError(this.#errorCode);
|
||||
throw new ValidationError(this.#errorCode);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,34 +1,60 @@
|
||||
// @flow
|
||||
import {BaseCMI, CMIArray, CMIScore} from './common';
|
||||
import {
|
||||
BaseCMI,
|
||||
checkValidFormat,
|
||||
checkValidRange,
|
||||
CMIArray,
|
||||
CMIScore,
|
||||
} from './common';
|
||||
import {scorm12_constants} from '../constants/api_constants';
|
||||
import {scorm12_error_codes} from '../constants/error_codes';
|
||||
import {scorm12_regex} from '../regex';
|
||||
import {ValidationError} from '../exceptions';
|
||||
|
||||
const constants = scorm12_constants;
|
||||
const regex = scorm12_regex;
|
||||
|
||||
/**
|
||||
* Helper method for throwing Read Only error
|
||||
* @param {Scorm12API} API
|
||||
*/
|
||||
function throwReadOnlyError(API) {
|
||||
API.throwSCORMError(scorm12_error_codes.READ_ONLY_ELEMENT);
|
||||
export function throwReadOnlyError() {
|
||||
throw new ValidationError(scorm12_error_codes.READ_ONLY_ELEMENT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method for throwing Write Only error
|
||||
* @param {Scorm12API} API
|
||||
*/
|
||||
function throwWriteOnlyError(API) {
|
||||
API.throwSCORMError(scorm12_error_codes.WRITE_ONLY_ELEMENT);
|
||||
export function throwWriteOnlyError() {
|
||||
throw new ValidationError(scorm12_error_codes.WRITE_ONLY_ELEMENT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method for throwing Invalid Set error
|
||||
* @param {Scorm12API} API
|
||||
*/
|
||||
function throwInvalidValueError(API) {
|
||||
API.throwSCORMError(scorm12_error_codes.INVALID_SET_VALUE);
|
||||
function throwInvalidValueError() {
|
||||
throw new ValidationError(scorm12_error_codes.INVALID_SET_VALUE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method, no reason to have to pass the same error codes every time
|
||||
* @param {*} value
|
||||
* @param {string} regexPattern
|
||||
* @return {boolean}
|
||||
*/
|
||||
export function check12ValidFormat(value: String, regexPattern: String) {
|
||||
return checkValidFormat(value, regexPattern,
|
||||
scorm12_error_codes.TYPE_MISMATCH);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method, no reason to have to pass the same error codes every time
|
||||
* @param {*} value
|
||||
* @param {string} rangePattern
|
||||
* @return {boolean}
|
||||
*/
|
||||
export function check12ValidRange(value: any, rangePattern: String) {
|
||||
return checkValidRange(value, rangePattern,
|
||||
scorm12_error_codes.VALUE_OUT_OF_RANGE);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -46,21 +72,33 @@ export class CMI extends BaseCMI {
|
||||
|
||||
/**
|
||||
* Constructor for the SCORM 1.2 cmi object
|
||||
* @param {Scorm12API} API
|
||||
* @param {string} cmi_children
|
||||
* @param {string} student_data
|
||||
* @param {(CMIStudentData|AICCCMIStudentData)} student_data
|
||||
* @param {boolean} initialized
|
||||
*/
|
||||
constructor(API, cmi_children, student_data) {
|
||||
super(API);
|
||||
constructor(cmi_children, student_data, initialized: boolean) {
|
||||
super();
|
||||
|
||||
if (initialized) this.initialize();
|
||||
|
||||
this.#_children = cmi_children ? cmi_children : constants.cmi_children;
|
||||
this.core = new CMICore(API);
|
||||
this.objectives = new CMIObjectives(API);
|
||||
this.student_data = student_data ?
|
||||
student_data :
|
||||
new CMIStudentData(API);
|
||||
this.student_preference = new CMIStudentPreference(API);
|
||||
this.interactions = new CMIInteractions(API);
|
||||
this.core = new CMICore();
|
||||
this.objectives = new CMIObjectives();
|
||||
this.student_data = student_data ? student_data : new CMIStudentData();
|
||||
this.student_preference = new CMIStudentPreference();
|
||||
this.interactions = new CMIInteractions();
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the API has been initialized after the CMI has been created
|
||||
*/
|
||||
initialize() {
|
||||
super.initialize();
|
||||
this.core?.initialize();
|
||||
this.objectives?.initialize();
|
||||
this.student_data?.initialize();
|
||||
this.student_preference?.initialize();
|
||||
this.interactions?.initialize();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -112,7 +150,7 @@ export class CMI extends BaseCMI {
|
||||
* @private
|
||||
*/
|
||||
set _version(_version) {
|
||||
throwInvalidValueError(this.API);
|
||||
throwInvalidValueError();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -130,7 +168,7 @@ export class CMI extends BaseCMI {
|
||||
* @private
|
||||
*/
|
||||
set _children(_children) {
|
||||
throwInvalidValueError(this.API);
|
||||
throwInvalidValueError();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -146,7 +184,7 @@ export class CMI extends BaseCMI {
|
||||
* @param {string} suspend_data
|
||||
*/
|
||||
set suspend_data(suspend_data) {
|
||||
if (this.API.checkValidFormat(suspend_data, regex.CMIString4096)) {
|
||||
if (check12ValidFormat(suspend_data, regex.CMIString4096)) {
|
||||
this.#suspend_data = suspend_data;
|
||||
}
|
||||
}
|
||||
@@ -160,13 +198,11 @@ export class CMI extends BaseCMI {
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter for #launch_data. Can only be called before API initialization.
|
||||
* Setter for #launch_data. Can only be called before initialization.
|
||||
* @param {string} launch_data
|
||||
*/
|
||||
set launch_data(launch_data) {
|
||||
this.API.isNotInitialized() ?
|
||||
this.#launch_data = launch_data :
|
||||
throwReadOnlyError(this.API);
|
||||
!this.initialized ? this.#launch_data = launch_data : throwReadOnlyError();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -182,7 +218,7 @@ export class CMI extends BaseCMI {
|
||||
* @param {string} comments
|
||||
*/
|
||||
set comments(comments) {
|
||||
if (this.API.checkValidFormat(comments, regex.CMIString4096)) {
|
||||
if (check12ValidFormat(comments, regex.CMIString4096)) {
|
||||
this.#comments = comments;
|
||||
}
|
||||
}
|
||||
@@ -196,13 +232,11 @@ export class CMI extends BaseCMI {
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter for #comments_from_lms. Can only be called before API initialization.
|
||||
* Setter for #comments_from_lms. Can only be called before initialization.
|
||||
* @param {string} comments_from_lms
|
||||
*/
|
||||
set comments_from_lms(comments_from_lms) {
|
||||
this.API.isNotInitialized() ?
|
||||
this.#comments_from_lms = comments_from_lms :
|
||||
throwReadOnlyError(this.API);
|
||||
!this.initialized ? this.#comments_from_lms = comments_from_lms : throwReadOnlyError();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -212,13 +246,26 @@ export class CMI extends BaseCMI {
|
||||
class CMICore extends BaseCMI {
|
||||
/**
|
||||
* Constructor for cmi.core
|
||||
* @param {Scorm12API} API
|
||||
*/
|
||||
constructor(API) {
|
||||
super(API);
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.score = new Scorm12CMIScore(API, constants.score_children,
|
||||
regex.score_range);
|
||||
this.score = new Scorm12CMIScore(
|
||||
{
|
||||
score_children: constants.score_children,
|
||||
score_range: regex.score_range,
|
||||
invalidErrorCode: scorm12_error_codes.INVALID_SET_VALUE,
|
||||
invalidTypeCode: scorm12_error_codes.TYPE_MISMATCH,
|
||||
invalidRangeCode: scorm12_error_codes.VALUE_OUT_OF_RANGE,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the API has been initialized after the CMI has been created
|
||||
*/
|
||||
initialize() {
|
||||
super.initialize();
|
||||
this.score?.initialize();
|
||||
}
|
||||
|
||||
#_children = constants.core_children;
|
||||
@@ -248,7 +295,7 @@ class CMICore extends BaseCMI {
|
||||
* @private
|
||||
*/
|
||||
set _children(_children) {
|
||||
throwInvalidValueError(this.API);
|
||||
throwInvalidValueError();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -260,13 +307,11 @@ class CMICore extends BaseCMI {
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter for #student_id. Can only be called before API initialization.
|
||||
* Setter for #student_id. Can only be called before initialization.
|
||||
* @param {string} student_id
|
||||
*/
|
||||
set student_id(student_id) {
|
||||
this.API.isNotInitialized() ?
|
||||
this.#student_id = student_id :
|
||||
throwReadOnlyError(this.API);
|
||||
!this.initialized ? this.#student_id = student_id : throwReadOnlyError();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -278,13 +323,11 @@ class CMICore extends BaseCMI {
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter for #student_name. Can only be called before API initialization.
|
||||
* Setter for #student_name. Can only be called before initialization.
|
||||
* @param {string} student_name
|
||||
*/
|
||||
set student_name(student_name) {
|
||||
this.API.isNotInitialized() ?
|
||||
this.#student_name = student_name :
|
||||
throwReadOnlyError(this.API);
|
||||
!this.initialized ? this.#student_name = student_name : throwReadOnlyError();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -300,7 +343,7 @@ class CMICore extends BaseCMI {
|
||||
* @param {string} lesson_location
|
||||
*/
|
||||
set lesson_location(lesson_location) {
|
||||
if (this.API.checkValidFormat(lesson_location, regex.CMIString256)) {
|
||||
if (check12ValidFormat(lesson_location, regex.CMIString256)) {
|
||||
this.#lesson_location = lesson_location;
|
||||
}
|
||||
}
|
||||
@@ -314,13 +357,11 @@ class CMICore extends BaseCMI {
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter for #credit. Can only be called before API initialization.
|
||||
* Setter for #credit. Can only be called before initialization.
|
||||
* @param {string} credit
|
||||
*/
|
||||
set credit(credit) {
|
||||
this.API.isNotInitialized() ?
|
||||
this.#credit = credit :
|
||||
throwReadOnlyError(this.API);
|
||||
!this.initialized ? this.#credit = credit : throwReadOnlyError();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -336,7 +377,7 @@ class CMICore extends BaseCMI {
|
||||
* @param {string} lesson_status
|
||||
*/
|
||||
set lesson_status(lesson_status) {
|
||||
if (this.API.checkValidFormat(lesson_status, regex.CMIStatus)) {
|
||||
if (check12ValidFormat(lesson_status, regex.CMIStatus)) {
|
||||
this.#lesson_status = lesson_status;
|
||||
}
|
||||
}
|
||||
@@ -350,13 +391,11 @@ class CMICore extends BaseCMI {
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter for #entry. Can only be called before API initialization.
|
||||
* Setter for #entry. Can only be called before initialization.
|
||||
* @param {string} entry
|
||||
*/
|
||||
set entry(entry) {
|
||||
this.API.isNotInitialized() ?
|
||||
this.#entry = entry :
|
||||
throwReadOnlyError(this.API);
|
||||
!this.initialized ? this.#entry = entry : throwReadOnlyError();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -368,13 +407,11 @@ class CMICore extends BaseCMI {
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter for #total_time. Can only be called before API initialization.
|
||||
* Setter for #total_time. Can only be called before initialization.
|
||||
* @param {string} total_time
|
||||
*/
|
||||
set total_time(total_time) {
|
||||
this.API.isNotInitialized() ?
|
||||
this.#total_time = total_time :
|
||||
throwReadOnlyError(this.API);
|
||||
!this.initialized ? this.#total_time = total_time : throwReadOnlyError();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -386,13 +423,11 @@ class CMICore extends BaseCMI {
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter for #lesson_mode. Can only be called before API initialization.
|
||||
* Setter for #lesson_mode. Can only be called before initialization.
|
||||
* @param {string} lesson_mode
|
||||
*/
|
||||
set lesson_mode(lesson_mode) {
|
||||
this.API.isNotInitialized() ?
|
||||
this.#lesson_mode = lesson_mode :
|
||||
throwReadOnlyError(this.API);
|
||||
!this.initialized ? this.#lesson_mode = lesson_mode : throwReadOnlyError();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -400,7 +435,7 @@ class CMICore extends BaseCMI {
|
||||
* @return {*}
|
||||
*/
|
||||
get exit() {
|
||||
return (!this.jsonString) ? throwWriteOnlyError(this.API) : this.#exit;
|
||||
return (!this.jsonString) ? throwWriteOnlyError() : this.#exit;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -408,7 +443,7 @@ class CMICore extends BaseCMI {
|
||||
* @param {string} exit
|
||||
*/
|
||||
set exit(exit) {
|
||||
if (this.API.checkValidFormat(exit, regex.CMIExit)) {
|
||||
if (check12ValidFormat(exit, regex.CMIExit)) {
|
||||
this.#exit = exit;
|
||||
}
|
||||
}
|
||||
@@ -418,9 +453,7 @@ class CMICore extends BaseCMI {
|
||||
* @return {*}
|
||||
*/
|
||||
get session_time() {
|
||||
return (!this.jsonString) ?
|
||||
throwWriteOnlyError(this.API) :
|
||||
this.#session_time;
|
||||
return (!this.jsonString) ? throwWriteOnlyError() : this.#session_time;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -428,7 +461,7 @@ class CMICore extends BaseCMI {
|
||||
* @param {string} session_time
|
||||
*/
|
||||
set session_time(session_time) {
|
||||
if (this.API.checkValidFormat(session_time, regex.CMITimespan)) {
|
||||
if (check12ValidFormat(session_time, regex.CMITimespan)) {
|
||||
this.#session_time = session_time;
|
||||
}
|
||||
}
|
||||
@@ -478,11 +511,9 @@ class CMICore extends BaseCMI {
|
||||
class CMIObjectives extends CMIArray {
|
||||
/**
|
||||
* Constructor for cmi.objectives
|
||||
* @param {Scorm12API} API
|
||||
*/
|
||||
constructor(API) {
|
||||
constructor() {
|
||||
super({
|
||||
API: API,
|
||||
children: constants.objectives_children,
|
||||
errorCode: scorm12_error_codes.INVALID_SET_VALUE,
|
||||
});
|
||||
@@ -500,11 +531,10 @@ export class CMIStudentData extends BaseCMI {
|
||||
|
||||
/**
|
||||
* Constructor for cmi.student_data
|
||||
* @param {Scorm12API} API
|
||||
* @param {string} student_data_children
|
||||
*/
|
||||
constructor(API, student_data_children) {
|
||||
super(API);
|
||||
constructor(student_data_children) {
|
||||
super();
|
||||
|
||||
this.#_children = student_data_children ?
|
||||
student_data_children :
|
||||
@@ -526,7 +556,7 @@ export class CMIStudentData extends BaseCMI {
|
||||
* @private
|
||||
*/
|
||||
set _children(_children) {
|
||||
throwInvalidValueError(this.API);
|
||||
throwInvalidValueError();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -538,13 +568,11 @@ export class CMIStudentData extends BaseCMI {
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter for #master_score. Can only be called before API initialization.
|
||||
* Setter for #master_score. Can only be called before initialization.
|
||||
* @param {string} mastery_score
|
||||
*/
|
||||
set mastery_score(mastery_score) {
|
||||
this.API.isNotInitialized() ?
|
||||
this.#mastery_score = mastery_score :
|
||||
throwReadOnlyError(this.API);
|
||||
!this.initialized ? this.#mastery_score = mastery_score : throwReadOnlyError();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -556,13 +584,11 @@ export class CMIStudentData extends BaseCMI {
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter for #max_time_allowed. Can only be called before API initialization.
|
||||
* Setter for #max_time_allowed. Can only be called before initialization.
|
||||
* @param {string} max_time_allowed
|
||||
*/
|
||||
set max_time_allowed(max_time_allowed) {
|
||||
this.API.isNotInitialized() ?
|
||||
this.#max_time_allowed = max_time_allowed :
|
||||
throwReadOnlyError(this.API);
|
||||
!this.initialized ? this.#max_time_allowed = max_time_allowed : throwReadOnlyError();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -574,13 +600,11 @@ export class CMIStudentData extends BaseCMI {
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter for #time_limit_action. Can only be called before API initialization.
|
||||
* Setter for #time_limit_action. Can only be called before initialization.
|
||||
* @param {string} time_limit_action
|
||||
*/
|
||||
set time_limit_action(time_limit_action) {
|
||||
this.API.isNotInitialized() ?
|
||||
this.#time_limit_action = time_limit_action :
|
||||
throwReadOnlyError(this.API);
|
||||
!this.initialized ? this.#time_limit_action = time_limit_action : throwReadOnlyError();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -612,10 +636,9 @@ export class CMIStudentData extends BaseCMI {
|
||||
class CMIStudentPreference extends BaseCMI {
|
||||
/**
|
||||
* Constructor for cmi.student_preference
|
||||
* @param {Scorm12API} API
|
||||
*/
|
||||
constructor(API) {
|
||||
super(API);
|
||||
constructor() {
|
||||
super();
|
||||
}
|
||||
|
||||
#_children = constants.student_preference_children;
|
||||
@@ -639,7 +662,7 @@ class CMIStudentPreference extends BaseCMI {
|
||||
* @private
|
||||
*/
|
||||
set _children(_children) {
|
||||
throwInvalidValueError(this.API);
|
||||
throwInvalidValueError();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -655,8 +678,8 @@ class CMIStudentPreference extends BaseCMI {
|
||||
* @param {string} audio
|
||||
*/
|
||||
set audio(audio) {
|
||||
if (this.API.checkValidFormat(audio, regex.CMISInteger) &&
|
||||
this.API.checkValidRange(audio, regex.audio_range)) {
|
||||
if (check12ValidFormat(audio, regex.CMISInteger) &&
|
||||
check12ValidRange(audio, regex.audio_range)) {
|
||||
this.#audio = audio;
|
||||
}
|
||||
}
|
||||
@@ -674,7 +697,7 @@ class CMIStudentPreference extends BaseCMI {
|
||||
* @param {string} language
|
||||
*/
|
||||
set language(language) {
|
||||
if (this.API.checkValidFormat(language, regex.CMIString256)) {
|
||||
if (check12ValidFormat(language, regex.CMIString256)) {
|
||||
this.#language = language;
|
||||
}
|
||||
}
|
||||
@@ -692,8 +715,8 @@ class CMIStudentPreference extends BaseCMI {
|
||||
* @param {string} speed
|
||||
*/
|
||||
set speed(speed) {
|
||||
if (this.API.checkValidFormat(speed, regex.CMISInteger) &&
|
||||
this.API.checkValidRange(speed, regex.speed_range)) {
|
||||
if (check12ValidFormat(speed, regex.CMISInteger) &&
|
||||
check12ValidRange(speed, regex.speed_range)) {
|
||||
this.#speed = speed;
|
||||
}
|
||||
}
|
||||
@@ -711,8 +734,8 @@ class CMIStudentPreference extends BaseCMI {
|
||||
* @param {string} text
|
||||
*/
|
||||
set text(text) {
|
||||
if (this.API.checkValidFormat(text, regex.CMISInteger) &&
|
||||
this.API.checkValidRange(text, regex.text_range)) {
|
||||
if (check12ValidFormat(text, regex.CMISInteger) &&
|
||||
check12ValidRange(text, regex.text_range)) {
|
||||
this.#text = text;
|
||||
}
|
||||
}
|
||||
@@ -748,11 +771,9 @@ class CMIStudentPreference extends BaseCMI {
|
||||
class CMIInteractions extends CMIArray {
|
||||
/**
|
||||
* Constructor for cmi.interactions
|
||||
* @param {Scorm12API} API
|
||||
*/
|
||||
constructor(API) {
|
||||
constructor() {
|
||||
super({
|
||||
API: API,
|
||||
children: constants.interactions_children,
|
||||
errorCode: scorm12_error_codes.INVALID_SET_VALUE,
|
||||
});
|
||||
@@ -765,23 +786,29 @@ class CMIInteractions extends CMIArray {
|
||||
export class CMIInteractionsObject extends BaseCMI {
|
||||
/**
|
||||
* Constructor for cmi.interactions.n object
|
||||
* @param {Scorm12API} API
|
||||
*/
|
||||
constructor(API) {
|
||||
super(API);
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.objectives = new CMIArray({
|
||||
API: API,
|
||||
errorCode: 402,
|
||||
errorCode: scorm12_error_codes.INVALID_SET_VALUE,
|
||||
children: constants.objectives_children,
|
||||
});
|
||||
this.correct_responses = new CMIArray({
|
||||
API: API,
|
||||
errorCode: 402,
|
||||
errorCode: scorm12_error_codes.INVALID_SET_VALUE,
|
||||
children: constants.correct_responses_children,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the API has been initialized after the CMI has been created
|
||||
*/
|
||||
initialize() {
|
||||
super.initialize();
|
||||
this.objectives?.initialize();
|
||||
this.correct_responses?.initialize();
|
||||
}
|
||||
|
||||
#id: '';
|
||||
#time: '';
|
||||
#type: '';
|
||||
@@ -795,7 +822,7 @@ export class CMIInteractionsObject extends BaseCMI {
|
||||
* @return {*}
|
||||
*/
|
||||
get id() {
|
||||
return (!this.jsonString) ? throwWriteOnlyError(this.API) : this.#id;
|
||||
return (!this.jsonString) ? throwWriteOnlyError() : this.#id;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -803,7 +830,7 @@ export class CMIInteractionsObject extends BaseCMI {
|
||||
* @param {string} id
|
||||
*/
|
||||
set id(id) {
|
||||
if (this.API.checkValidFormat(id, regex.CMIIdentifier)) {
|
||||
if (check12ValidFormat(id, regex.CMIIdentifier)) {
|
||||
this.#id = id;
|
||||
}
|
||||
}
|
||||
@@ -813,7 +840,7 @@ export class CMIInteractionsObject extends BaseCMI {
|
||||
* @return {*}
|
||||
*/
|
||||
get time() {
|
||||
return (!this.jsonString) ? throwWriteOnlyError(this.API) : this.#time;
|
||||
return (!this.jsonString) ? throwWriteOnlyError() : this.#time;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -821,7 +848,7 @@ export class CMIInteractionsObject extends BaseCMI {
|
||||
* @param {string} time
|
||||
*/
|
||||
set time(time) {
|
||||
if (this.API.checkValidFormat(time, regex.CMITime)) {
|
||||
if (check12ValidFormat(time, regex.CMITime)) {
|
||||
this.#time = time;
|
||||
}
|
||||
}
|
||||
@@ -831,7 +858,7 @@ export class CMIInteractionsObject extends BaseCMI {
|
||||
* @return {*}
|
||||
*/
|
||||
get type() {
|
||||
return (!this.jsonString) ? throwWriteOnlyError(this.API) : this.#type;
|
||||
return (!this.jsonString) ? throwWriteOnlyError() : this.#type;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -839,7 +866,7 @@ export class CMIInteractionsObject extends BaseCMI {
|
||||
* @param {string} type
|
||||
*/
|
||||
set type(type) {
|
||||
if (this.API.checkValidFormat(type, regex.CMIType)) {
|
||||
if (check12ValidFormat(type, regex.CMIType)) {
|
||||
this.#type = type;
|
||||
}
|
||||
}
|
||||
@@ -850,7 +877,7 @@ export class CMIInteractionsObject extends BaseCMI {
|
||||
*/
|
||||
get weighting() {
|
||||
return (!this.jsonString) ?
|
||||
throwWriteOnlyError(this.API) :
|
||||
throwWriteOnlyError() :
|
||||
this.#weighting;
|
||||
}
|
||||
|
||||
@@ -859,8 +886,8 @@ export class CMIInteractionsObject extends BaseCMI {
|
||||
* @param {string} weighting
|
||||
*/
|
||||
set weighting(weighting) {
|
||||
if (this.API.checkValidFormat(weighting, regex.CMIDecimal) &&
|
||||
this.API.checkValidRange(weighting, regex.weighting_range)) {
|
||||
if (check12ValidFormat(weighting, regex.CMIDecimal) &&
|
||||
check12ValidRange(weighting, regex.weighting_range)) {
|
||||
this.#weighting = weighting;
|
||||
}
|
||||
}
|
||||
@@ -870,9 +897,7 @@ export class CMIInteractionsObject extends BaseCMI {
|
||||
* @return {*}
|
||||
*/
|
||||
get student_response() {
|
||||
return (!this.jsonString) ?
|
||||
throwWriteOnlyError(this.API) :
|
||||
this.#student_response;
|
||||
return (!this.jsonString) ? throwWriteOnlyError() : this.#student_response;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -880,7 +905,7 @@ export class CMIInteractionsObject extends BaseCMI {
|
||||
* @param {string} student_response
|
||||
*/
|
||||
set student_response(student_response) {
|
||||
if (this.API.checkValidFormat(student_response, regex.CMIFeedback)) {
|
||||
if (check12ValidFormat(student_response, regex.CMIFeedback)) {
|
||||
this.#student_response = student_response;
|
||||
}
|
||||
}
|
||||
@@ -890,9 +915,7 @@ export class CMIInteractionsObject extends BaseCMI {
|
||||
* @return {*}
|
||||
*/
|
||||
get result() {
|
||||
return (!this.jsonString) ?
|
||||
throwWriteOnlyError(this.API) :
|
||||
this.#result;
|
||||
return (!this.jsonString) ? throwWriteOnlyError() : this.#result;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -900,7 +923,7 @@ export class CMIInteractionsObject extends BaseCMI {
|
||||
* @param {string} result
|
||||
*/
|
||||
set result(result) {
|
||||
if (this.API.checkValidFormat(result, regex.CMIResult)) {
|
||||
if (check12ValidFormat(result, regex.CMIResult)) {
|
||||
this.#result = result;
|
||||
}
|
||||
}
|
||||
@@ -910,9 +933,7 @@ export class CMIInteractionsObject extends BaseCMI {
|
||||
* @return {*}
|
||||
*/
|
||||
get latency() {
|
||||
return (!this.jsonString) ?
|
||||
throwWriteOnlyError(this.API) :
|
||||
this.#latency;
|
||||
return (!this.jsonString) ? throwWriteOnlyError() : this.#latency;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -920,7 +941,7 @@ export class CMIInteractionsObject extends BaseCMI {
|
||||
* @param {string} latency
|
||||
*/
|
||||
set latency(latency) {
|
||||
if (this.API.checkValidFormat(latency, regex.CMITimespan)) {
|
||||
if (check12ValidFormat(latency, regex.CMITimespan)) {
|
||||
this.#latency = latency;
|
||||
}
|
||||
}
|
||||
@@ -966,12 +987,11 @@ export class CMIInteractionsObject extends BaseCMI {
|
||||
export class CMIObjectivesObject extends BaseCMI {
|
||||
/**
|
||||
* Constructor for cmi.objectives.n
|
||||
* @param {Scorm12API} API
|
||||
*/
|
||||
constructor(API) {
|
||||
super(API);
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.score = new Scorm12CMIScore(API);
|
||||
this.score = new Scorm12CMIScore();
|
||||
}
|
||||
|
||||
#id: '';
|
||||
@@ -990,7 +1010,7 @@ export class CMIObjectivesObject extends BaseCMI {
|
||||
* @param {string} id
|
||||
*/
|
||||
set id(id) {
|
||||
if (this.API.checkValidFormat(id, regex.CMIIdentifier)) {
|
||||
if (check12ValidFormat(id, regex.CMIIdentifier)) {
|
||||
this.#id = id;
|
||||
}
|
||||
}
|
||||
@@ -1008,7 +1028,7 @@ export class CMIObjectivesObject extends BaseCMI {
|
||||
* @param {string} status
|
||||
*/
|
||||
set status(status) {
|
||||
if (this.API.checkValidFormat(status, regex.CMIStatus2)) {
|
||||
if (check12ValidFormat(status, regex.CMIStatus2)) {
|
||||
this.#status = status;
|
||||
}
|
||||
}
|
||||
@@ -1041,10 +1061,9 @@ export class CMIObjectivesObject extends BaseCMI {
|
||||
export class CMIInteractionsObjectivesObject extends BaseCMI {
|
||||
/**
|
||||
* Constructor for cmi.interactions.n.objectives.n
|
||||
* @param {Scorm12API} API
|
||||
*/
|
||||
constructor(API) {
|
||||
super(API);
|
||||
constructor() {
|
||||
super();
|
||||
}
|
||||
|
||||
#id: '';
|
||||
@@ -1062,7 +1081,7 @@ export class CMIInteractionsObjectivesObject extends BaseCMI {
|
||||
* @param {string} id
|
||||
*/
|
||||
set id(id) {
|
||||
if (this.API.checkValidFormat(id, regex.CMIIdentifier)) {
|
||||
if (check12ValidFormat(id, regex.CMIIdentifier)) {
|
||||
this.#id = id;
|
||||
}
|
||||
}
|
||||
@@ -1091,10 +1110,9 @@ export class CMIInteractionsObjectivesObject extends BaseCMI {
|
||||
export class CMIInteractionsCorrectResponsesObject extends BaseCMI {
|
||||
/**
|
||||
* Constructor for cmi.interactions.correct_responses.n
|
||||
* @param {Scorm12API} API
|
||||
*/
|
||||
constructor(API) {
|
||||
super(API);
|
||||
constructor() {
|
||||
super();
|
||||
}
|
||||
|
||||
#pattern: '';
|
||||
@@ -1112,7 +1130,7 @@ export class CMIInteractionsCorrectResponsesObject extends BaseCMI {
|
||||
* @param {string} pattern
|
||||
*/
|
||||
set pattern(pattern) {
|
||||
if (this.API.checkValidFormat(pattern, regex.CMIFeedback)) {
|
||||
if (check12ValidFormat(pattern, regex.CMIFeedback)) {
|
||||
this.#pattern = pattern;
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
33
src/exceptions.js
Normal file
33
src/exceptions.js
Normal file
@@ -0,0 +1,33 @@
|
||||
// @flow
|
||||
|
||||
/**
|
||||
* Data Validation Exception
|
||||
*/
|
||||
export class ValidationError extends Error {
|
||||
/**
|
||||
* Constructor to take in an error message and code
|
||||
* @param {number} errorCode
|
||||
*/
|
||||
constructor(errorCode: number) {
|
||||
super(errorCode);
|
||||
this.#errorCode = errorCode;
|
||||
}
|
||||
|
||||
#errorCode;
|
||||
|
||||
/**
|
||||
* Getter for #errorCode
|
||||
* @return {number}
|
||||
*/
|
||||
get errorCode() {
|
||||
return this.#errorCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Trying to override the default Error message
|
||||
* @return {string}
|
||||
*/
|
||||
get message() {
|
||||
return this.#errorCode + '';
|
||||
}
|
||||
}
|
||||
@@ -1,29 +1,27 @@
|
||||
import {expect, assert} from 'chai';
|
||||
import {expect} from 'chai';
|
||||
import {describe, it, beforeEach, afterEach} from 'mocha';
|
||||
import AICC from '../../src/AICC';
|
||||
import {aicc_constants} from '../../src/constants/api_constants';
|
||||
import {scorm12_error_codes} from '../../src/constants/error_codes';
|
||||
import {CMI} from '../../src/cmi/aicc_cmi';
|
||||
|
||||
let API;
|
||||
let cmi;
|
||||
|
||||
const checkFieldConstraintSize = ({fieldName, limit, expectedValue = ''}) => {
|
||||
describe(`Field: ${fieldName}`, () => {
|
||||
it(`Should be able to read from ${fieldName}`, () => {
|
||||
expect(eval(`API.${fieldName}`)).to.equal(expectedValue);
|
||||
expect(eval(`${fieldName}`)).to.equal(expectedValue);
|
||||
});
|
||||
|
||||
it(`Should be able to write upto ${limit} characters to ${fieldName}`,
|
||||
() => {
|
||||
eval(`API.${fieldName} = 'x'.repeat(${limit})`);
|
||||
expect(0).to.equal(API.lastErrorCode);
|
||||
expect(() => eval(`${fieldName} = 'x'.repeat(${limit})`)).
|
||||
to.not.throw();
|
||||
});
|
||||
|
||||
it(`Should fail to write more than ${limit} characters to ${fieldName}`,
|
||||
() => {
|
||||
eval(`API.${fieldName} = 'x'.repeat(${limit + 1})`);
|
||||
expect(scorm12_error_codes.TYPE_MISMATCH + '').
|
||||
to.
|
||||
equal(API.lastErrorCode);
|
||||
expect(() => eval(`${fieldName} = 'x'.repeat(${limit + 1})`)).
|
||||
to.throw(scorm12_error_codes.TYPE_MISMATCH + '');
|
||||
});
|
||||
});
|
||||
};
|
||||
@@ -31,14 +29,12 @@ const checkFieldConstraintSize = ({fieldName, limit, expectedValue = ''}) => {
|
||||
const checkInvalidSet = ({fieldName, expectedValue = ''}) => {
|
||||
describe(`Field: ${fieldName}`, () => {
|
||||
it(`Should be able to read from ${fieldName}`, () => {
|
||||
expect(eval(`API.${fieldName}`)).to.equal(expectedValue);
|
||||
expect(eval(`${fieldName}`)).to.equal(expectedValue);
|
||||
});
|
||||
|
||||
it(`Should fail to write to ${fieldName}`, () => {
|
||||
eval(`API.${fieldName} = 'xxx'`);
|
||||
expect(API.lastErrorCode).
|
||||
to.
|
||||
equal(scorm12_error_codes.INVALID_SET_VALUE + '');
|
||||
expect(() => eval(`${fieldName} = 'xxx'`)).
|
||||
to.throw(scorm12_error_codes.INVALID_SET_VALUE + '');
|
||||
});
|
||||
});
|
||||
};
|
||||
@@ -46,14 +42,12 @@ const checkInvalidSet = ({fieldName, expectedValue = ''}) => {
|
||||
const checkReadOnly = ({fieldName, expectedValue = ''}) => {
|
||||
describe(`Field: ${fieldName}`, () => {
|
||||
it(`Should be able to read from ${fieldName}`, () => {
|
||||
expect(eval(`API.${fieldName}`)).to.equal(expectedValue);
|
||||
expect(eval(`${fieldName}`)).to.equal(expectedValue);
|
||||
});
|
||||
|
||||
it(`Should fail to write to ${fieldName}`, () => {
|
||||
eval(`API.${fieldName} = 'xxx'`);
|
||||
expect(API.lastErrorCode).
|
||||
to.
|
||||
equal(scorm12_error_codes.READ_ONLY_ELEMENT + '');
|
||||
expect(() => eval(`${fieldName} = 'xxx'`)).
|
||||
to.throw(scorm12_error_codes.READ_ONLY_ELEMENT + '');
|
||||
});
|
||||
});
|
||||
};
|
||||
@@ -61,7 +55,7 @@ const checkReadOnly = ({fieldName, expectedValue = ''}) => {
|
||||
const checkRead = ({fieldName, expectedValue = ''}) => {
|
||||
describe(`Field: ${fieldName}`, () => {
|
||||
it(`Should be able to read from ${fieldName}`, () => {
|
||||
expect(eval(`API.${fieldName}`)).to.equal(expectedValue);
|
||||
expect(eval(`${fieldName}`)).to.equal(expectedValue);
|
||||
});
|
||||
});
|
||||
};
|
||||
@@ -69,12 +63,12 @@ const checkRead = ({fieldName, expectedValue = ''}) => {
|
||||
const checkReadAndWrite = ({fieldName, expectedValue = '', valueToTest = 'xxx'}) => {
|
||||
describe(`Field: ${fieldName}`, () => {
|
||||
it(`Should be able to read from ${fieldName}`, () => {
|
||||
expect(eval(`API.${fieldName}`)).to.equal(expectedValue);
|
||||
expect(eval(`${fieldName}`)).to.equal(expectedValue);
|
||||
});
|
||||
|
||||
it(`Should successfully write to ${fieldName}`, () => {
|
||||
eval(`API.${fieldName} = '${valueToTest}'`);
|
||||
expect(API.lastErrorCode).to.equal(0);
|
||||
expect(() => eval(`${fieldName} = '${valueToTest}'`)).
|
||||
to.not.throw();
|
||||
});
|
||||
});
|
||||
};
|
||||
@@ -82,15 +76,12 @@ const checkReadAndWrite = ({fieldName, expectedValue = '', valueToTest = 'xxx'})
|
||||
const checkWriteOnly = ({fieldName, valueToTest = 'xxx'}) => {
|
||||
describe(`Field: ${fieldName}`, () => {
|
||||
it(`Should fail to read from ${fieldName}`, () => {
|
||||
eval(`API.${fieldName}`);
|
||||
expect(API.lastErrorCode).
|
||||
to.
|
||||
equal(scorm12_error_codes.WRITE_ONLY_ELEMENT + '');
|
||||
expect(() => eval(`${fieldName}`)).
|
||||
to.throw(scorm12_error_codes.WRITE_ONLY_ELEMENT + '');
|
||||
});
|
||||
|
||||
it(`Should successfully write to ${fieldName}`, () => {
|
||||
eval(`API.${fieldName} = '${valueToTest}'`);
|
||||
expect(API.lastErrorCode).to.equal(0);
|
||||
expect(() => eval(`${fieldName} = '${valueToTest}'`)).to.not.throw();
|
||||
});
|
||||
});
|
||||
};
|
||||
@@ -98,8 +89,7 @@ const checkWriteOnly = ({fieldName, valueToTest = 'xxx'}) => {
|
||||
const checkWrite = ({fieldName, valueToTest = 'xxx'}) => {
|
||||
describe(`Field: ${fieldName}`, () => {
|
||||
it(`Should successfully write to ${fieldName}`, () => {
|
||||
eval(`API.${fieldName} = '${valueToTest}'`);
|
||||
expect(API.lastErrorCode).to.equal(0);
|
||||
expect(() => eval(`${fieldName} = '${valueToTest}'`)).to.not.throw();
|
||||
});
|
||||
});
|
||||
};
|
||||
@@ -110,8 +100,8 @@ const checkValidValues = ({fieldName, expectedError, validValues, invalidValues}
|
||||
if ({}.hasOwnProperty.call(validValues, idx)) {
|
||||
it(`Should successfully write '${validValues[idx]}' to ${fieldName}`,
|
||||
() => {
|
||||
eval(`API.${fieldName} = '${validValues[idx]}'`);
|
||||
expect(API.lastErrorCode).to.equal(0);
|
||||
expect(() => eval(`${fieldName} = '${validValues[idx]}'`)).
|
||||
to.not.throw();
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -120,8 +110,8 @@ const checkValidValues = ({fieldName, expectedError, validValues, invalidValues}
|
||||
if ({}.hasOwnProperty.call(invalidValues, idx)) {
|
||||
it(`Should fail to write '${invalidValues[idx]}' to ${fieldName}`,
|
||||
() => {
|
||||
eval(`API.${fieldName} = '${invalidValues[idx]}'`);
|
||||
expect(API.lastErrorCode).to.equal(expectedError + '');
|
||||
expect(() => eval(`${fieldName} = '${invalidValues[idx]}'`)).
|
||||
to.throw(expectedError + '');
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -130,30 +120,12 @@ const checkValidValues = ({fieldName, expectedError, validValues, invalidValues}
|
||||
|
||||
describe('AICC CMI Tests', () => {
|
||||
describe('CMI Spec Tests', () => {
|
||||
beforeEach('Create the API object', () => {
|
||||
API = new AICC();
|
||||
API.lmsInitialize();
|
||||
});
|
||||
afterEach('Destroy API object', () => {
|
||||
API = null;
|
||||
});
|
||||
|
||||
it('lmsInitialize should create CMI object', () => {
|
||||
assert(API.cmi !== undefined, 'CMI object is created');
|
||||
});
|
||||
|
||||
it('Exporting CMI to JSON produces proper Object', () => {
|
||||
expect(
|
||||
JSON.parse(API.renderCMIToJSON()).cmi?.core !== undefined,
|
||||
).to.be.true;
|
||||
});
|
||||
|
||||
describe('Pre-Initialize Tests', () => {
|
||||
beforeEach('Create the API object', () => {
|
||||
API = new AICC();
|
||||
cmi = new CMI();
|
||||
});
|
||||
afterEach('Destroy API object', () => {
|
||||
API = null;
|
||||
cmi = null;
|
||||
});
|
||||
|
||||
/**
|
||||
@@ -409,11 +381,11 @@ describe('AICC CMI Tests', () => {
|
||||
|
||||
describe('Post-Initialize Tests', () => {
|
||||
beforeEach('Create the API object', () => {
|
||||
API = new AICC();
|
||||
API.lmsInitialize();
|
||||
cmi = new CMI();
|
||||
cmi.initialize();
|
||||
});
|
||||
afterEach('Destroy API object', () => {
|
||||
API = null;
|
||||
cmi = null;
|
||||
});
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,29 +1,27 @@
|
||||
import {expect, assert} from 'chai';
|
||||
import {expect} from 'chai';
|
||||
import {describe, it, beforeEach, afterEach} from 'mocha';
|
||||
import Scorm12API from '../../src/Scorm12API';
|
||||
import {scorm12_constants} from '../../src/constants/api_constants';
|
||||
import {scorm12_error_codes} from '../../src/constants/error_codes';
|
||||
import {CMI} from '../../src/cmi/scorm12_cmi';
|
||||
|
||||
let API;
|
||||
let cmi;
|
||||
|
||||
const checkFieldConstraintSize = ({fieldName, limit, expectedValue = ''}) => {
|
||||
describe(`Field: ${fieldName}`, () => {
|
||||
it(`Should be able to read from ${fieldName}`, () => {
|
||||
expect(eval(`API.${fieldName}`)).to.equal(expectedValue);
|
||||
expect(eval(`${fieldName}`)).to.equal(expectedValue);
|
||||
});
|
||||
|
||||
it(`Should be able to write upto ${limit} characters to ${fieldName}`,
|
||||
() => {
|
||||
eval(`API.${fieldName} = 'x'.repeat(${limit})`);
|
||||
expect(0).to.equal(API.lastErrorCode);
|
||||
expect(() => eval(`${fieldName} = 'x'.repeat(${limit})`)).
|
||||
to.not.throw();
|
||||
});
|
||||
|
||||
it(`Should fail to write more than ${limit} characters to ${fieldName}`,
|
||||
() => {
|
||||
eval(`API.${fieldName} = 'x'.repeat(${limit + 1})`);
|
||||
expect(scorm12_error_codes.TYPE_MISMATCH + '').
|
||||
to.
|
||||
equal(API.lastErrorCode);
|
||||
expect(() => eval(`${fieldName} = 'x'.repeat(${limit + 1})`)).
|
||||
to.throw(scorm12_error_codes.TYPE_MISMATCH + '');
|
||||
});
|
||||
});
|
||||
};
|
||||
@@ -31,14 +29,12 @@ const checkFieldConstraintSize = ({fieldName, limit, expectedValue = ''}) => {
|
||||
const checkInvalidSet = ({fieldName, expectedValue = ''}) => {
|
||||
describe(`Field: ${fieldName}`, () => {
|
||||
it(`Should be able to read from ${fieldName}`, () => {
|
||||
expect(eval(`API.${fieldName}`)).to.equal(expectedValue);
|
||||
expect(eval(`${fieldName}`)).to.equal(expectedValue);
|
||||
});
|
||||
|
||||
it(`Should fail to write to ${fieldName}`, () => {
|
||||
eval(`API.${fieldName} = 'xxx'`);
|
||||
expect(API.lastErrorCode).
|
||||
to.
|
||||
equal(scorm12_error_codes.INVALID_SET_VALUE + '');
|
||||
expect(() => eval(`${fieldName} = 'xxx'`)).
|
||||
to.throw(scorm12_error_codes.INVALID_SET_VALUE + '');
|
||||
});
|
||||
});
|
||||
};
|
||||
@@ -46,14 +42,12 @@ const checkInvalidSet = ({fieldName, expectedValue = ''}) => {
|
||||
const checkReadOnly = ({fieldName, expectedValue = ''}) => {
|
||||
describe(`Field: ${fieldName}`, () => {
|
||||
it(`Should be able to read from ${fieldName}`, () => {
|
||||
expect(eval(`API.${fieldName}`)).to.equal(expectedValue);
|
||||
expect(eval(`${fieldName}`)).to.equal(expectedValue);
|
||||
});
|
||||
|
||||
it(`Should fail to write to ${fieldName}`, () => {
|
||||
eval(`API.${fieldName} = 'xxx'`);
|
||||
expect(API.lastErrorCode).
|
||||
to.
|
||||
equal(scorm12_error_codes.READ_ONLY_ELEMENT + '');
|
||||
expect(() => eval(`${fieldName} = 'xxx'`)).
|
||||
to.throw(scorm12_error_codes.READ_ONLY_ELEMENT + '');
|
||||
});
|
||||
});
|
||||
};
|
||||
@@ -61,7 +55,7 @@ const checkReadOnly = ({fieldName, expectedValue = ''}) => {
|
||||
const checkRead = ({fieldName, expectedValue = ''}) => {
|
||||
describe(`Field: ${fieldName}`, () => {
|
||||
it(`Should be able to read from ${fieldName}`, () => {
|
||||
expect(eval(`API.${fieldName}`)).to.equal(expectedValue);
|
||||
expect(eval(`${fieldName}`)).to.equal(expectedValue);
|
||||
});
|
||||
});
|
||||
};
|
||||
@@ -69,12 +63,12 @@ const checkRead = ({fieldName, expectedValue = ''}) => {
|
||||
const checkReadAndWrite = ({fieldName, expectedValue = '', valueToTest = 'xxx'}) => {
|
||||
describe(`Field: ${fieldName}`, () => {
|
||||
it(`Should be able to read from ${fieldName}`, () => {
|
||||
expect(eval(`API.${fieldName}`)).to.equal(expectedValue);
|
||||
expect(eval(`${fieldName}`)).to.equal(expectedValue);
|
||||
});
|
||||
|
||||
it(`Should successfully write to ${fieldName}`, () => {
|
||||
eval(`API.${fieldName} = '${valueToTest}'`);
|
||||
expect(API.lastErrorCode).to.equal(0);
|
||||
expect(() => eval(`${fieldName} = '${valueToTest}'`)).
|
||||
to.not.throw();
|
||||
});
|
||||
});
|
||||
};
|
||||
@@ -82,15 +76,12 @@ const checkReadAndWrite = ({fieldName, expectedValue = '', valueToTest = 'xxx'})
|
||||
const checkWriteOnly = ({fieldName, valueToTest = 'xxx'}) => {
|
||||
describe(`Field: ${fieldName}`, () => {
|
||||
it(`Should fail to read from ${fieldName}`, () => {
|
||||
eval(`API.${fieldName}`);
|
||||
expect(API.lastErrorCode).
|
||||
to.
|
||||
equal(scorm12_error_codes.WRITE_ONLY_ELEMENT + '');
|
||||
expect(() => eval(`${fieldName}`)).
|
||||
to.throw(scorm12_error_codes.WRITE_ONLY_ELEMENT + '');
|
||||
});
|
||||
|
||||
it(`Should successfully write to ${fieldName}`, () => {
|
||||
eval(`API.${fieldName} = '${valueToTest}'`);
|
||||
expect(API.lastErrorCode).to.equal(0);
|
||||
expect(() => eval(`${fieldName} = '${valueToTest}'`)).to.not.throw();
|
||||
});
|
||||
});
|
||||
};
|
||||
@@ -98,8 +89,7 @@ const checkWriteOnly = ({fieldName, valueToTest = 'xxx'}) => {
|
||||
const checkWrite = ({fieldName, valueToTest = 'xxx'}) => {
|
||||
describe(`Field: ${fieldName}`, () => {
|
||||
it(`Should successfully write to ${fieldName}`, () => {
|
||||
eval(`API.${fieldName} = '${valueToTest}'`);
|
||||
expect(API.lastErrorCode).to.equal(0);
|
||||
expect(() => eval(`${fieldName} = '${valueToTest}'`)).to.not.throw();
|
||||
});
|
||||
});
|
||||
};
|
||||
@@ -110,8 +100,8 @@ const checkValidValues = ({fieldName, expectedError, validValues, invalidValues}
|
||||
if ({}.hasOwnProperty.call(validValues, idx)) {
|
||||
it(`Should successfully write '${validValues[idx]}' to ${fieldName}`,
|
||||
() => {
|
||||
eval(`API.${fieldName} = '${validValues[idx]}'`);
|
||||
expect(API.lastErrorCode).to.equal(0);
|
||||
expect(() => eval(`${fieldName} = '${validValues[idx]}'`)).
|
||||
to.not.throw();
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -120,8 +110,8 @@ const checkValidValues = ({fieldName, expectedError, validValues, invalidValues}
|
||||
if ({}.hasOwnProperty.call(invalidValues, idx)) {
|
||||
it(`Should fail to write '${invalidValues[idx]}' to ${fieldName}`,
|
||||
() => {
|
||||
eval(`API.${fieldName} = '${invalidValues[idx]}'`);
|
||||
expect(API.lastErrorCode).to.equal(expectedError + '');
|
||||
expect(() => eval(`${fieldName} = '${invalidValues[idx]}'`)).
|
||||
to.throw(expectedError + '');
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -130,30 +120,12 @@ const checkValidValues = ({fieldName, expectedError, validValues, invalidValues}
|
||||
|
||||
describe('SCORM 1.2 CMI Tests', () => {
|
||||
describe('CMI Spec Tests', () => {
|
||||
beforeEach('Create the API object', () => {
|
||||
API = new Scorm12API();
|
||||
API.lmsInitialize();
|
||||
});
|
||||
afterEach('Destroy API object', () => {
|
||||
API = null;
|
||||
});
|
||||
|
||||
it('lmsInitialize should create CMI object', () => {
|
||||
assert(API.cmi !== undefined, 'CMI object is created');
|
||||
});
|
||||
|
||||
it('Exporting CMI to JSON produces proper Object', () => {
|
||||
expect(
|
||||
JSON.parse(API.renderCMIToJSON()).cmi?.core !== undefined,
|
||||
).to.be.true;
|
||||
});
|
||||
|
||||
describe('Pre-Initialize Tests', () => {
|
||||
beforeEach('Create the API object', () => {
|
||||
API = new Scorm12API();
|
||||
cmi = new CMI();
|
||||
});
|
||||
afterEach('Destroy API object', () => {
|
||||
API = null;
|
||||
cmi = null;
|
||||
});
|
||||
|
||||
/**
|
||||
@@ -408,11 +380,11 @@ describe('SCORM 1.2 CMI Tests', () => {
|
||||
|
||||
describe('Post-Initialize Tests', () => {
|
||||
beforeEach('Create the API object', () => {
|
||||
API = new Scorm12API();
|
||||
API.lmsInitialize();
|
||||
cmi = new CMI();
|
||||
cmi.initialize();
|
||||
});
|
||||
afterEach('Destroy API object', () => {
|
||||
API = null;
|
||||
cmi = null;
|
||||
});
|
||||
|
||||
/**
|
||||
|
||||
156
test/cmi/scorm2004_cmi.spec.js
Normal file
156
test/cmi/scorm2004_cmi.spec.js
Normal file
@@ -0,0 +1,156 @@
|
||||
import {expect} from 'chai';
|
||||
import {describe, it, beforeEach, afterEach} from 'mocha';
|
||||
import {scorm2004_error_codes} from '../../src/constants/error_codes';
|
||||
import {scorm2004_constants} from '../../src/constants/api_constants';
|
||||
import {CMI} from '../../src/cmi/scorm2004_cmi';
|
||||
|
||||
let cmi;
|
||||
|
||||
const checkFieldConstraintSize = ({fieldName, limit, expectedValue = ''}) => {
|
||||
describe(`Field: ${fieldName}`, () => {
|
||||
it(`Should be able to read from ${fieldName}`, () => {
|
||||
expect(eval(`${fieldName}`)).to.equal(expectedValue);
|
||||
});
|
||||
|
||||
it(`Should be able to write upto ${limit} characters to ${fieldName}`,
|
||||
() => {
|
||||
expect(() => eval(`${fieldName} = 'x'.repeat(${limit})`)).
|
||||
to.not.throw();
|
||||
});
|
||||
|
||||
it(`Should fail to write more than ${limit} characters to ${fieldName}`,
|
||||
() => {
|
||||
expect(() => eval(`${fieldName} = 'x'.repeat(${limit + 1})`)).
|
||||
to.throw(scorm2004_error_codes.TYPE_MISMATCH + '');
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
const checkInvalidSet = ({fieldName, expectedValue = ''}) => {
|
||||
describe(`Field: ${fieldName}`, () => {
|
||||
it(`Should be able to read from ${fieldName}`, () => {
|
||||
expect(eval(`${fieldName}`)).to.equal(expectedValue);
|
||||
});
|
||||
|
||||
it(`Should fail to write to ${fieldName}`, () => {
|
||||
expect(() => eval(`${fieldName} = 'xxx'`)).
|
||||
to.throw(scorm2004_error_codes.INVALID_SET_VALUE + '');
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
const checkReadOnly = ({fieldName, expectedValue = ''}) => {
|
||||
describe(`Field: ${fieldName}`, () => {
|
||||
it(`Should be able to read from ${fieldName}`, () => {
|
||||
expect(eval(`${fieldName}`)).to.equal(expectedValue);
|
||||
});
|
||||
|
||||
it(`Should fail to write to ${fieldName}`, () => {
|
||||
expect(() => eval(`${fieldName} = 'xxx'`)).
|
||||
to.throw(scorm2004_error_codes.READ_ONLY_ELEMENT + '');
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
const checkRead = ({fieldName, expectedValue = ''}) => {
|
||||
describe(`Field: ${fieldName}`, () => {
|
||||
it(`Should be able to read from ${fieldName}`, () => {
|
||||
expect(eval(`${fieldName}`)).to.equal(expectedValue);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
const checkReadAndWrite = ({fieldName, expectedValue = '', valueToTest = 'xxx'}) => {
|
||||
describe(`Field: ${fieldName}`, () => {
|
||||
it(`Should be able to read from ${fieldName}`, () => {
|
||||
expect(eval(`${fieldName}`)).to.equal(expectedValue);
|
||||
});
|
||||
|
||||
it(`Should successfully write to ${fieldName}`, () => {
|
||||
expect(() => eval(`${fieldName} = '${valueToTest}'`)).
|
||||
to.not.throw();
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
const checkWriteOnly = ({fieldName, valueToTest = 'xxx'}) => {
|
||||
describe(`Field: ${fieldName}`, () => {
|
||||
it(`Should fail to read from ${fieldName}`, () => {
|
||||
expect(() => eval(`${fieldName}`)).
|
||||
to.throw(scorm2004_error_codes.WRITE_ONLY_ELEMENT + '');
|
||||
});
|
||||
|
||||
it(`Should successfully write to ${fieldName}`, () => {
|
||||
expect(() => eval(`${fieldName} = '${valueToTest}'`)).to.not.throw();
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
const checkWrite = ({fieldName, valueToTest = 'xxx'}) => {
|
||||
describe(`Field: ${fieldName}`, () => {
|
||||
it(`Should successfully write to ${fieldName}`, () => {
|
||||
expect(() => eval(`${fieldName} = '${valueToTest}'`)).to.not.throw();
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
const checkValidValues = ({fieldName, expectedError, validValues, invalidValues}) => {
|
||||
describe(`Field: ${fieldName}`, () => {
|
||||
for (const idx in validValues) {
|
||||
if ({}.hasOwnProperty.call(validValues, idx)) {
|
||||
it(`Should successfully write '${validValues[idx]}' to ${fieldName}`,
|
||||
() => {
|
||||
expect(() => eval(`${fieldName} = '${validValues[idx]}'`)).
|
||||
to.not.throw();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
for (const idx in invalidValues) {
|
||||
if ({}.hasOwnProperty.call(invalidValues, idx)) {
|
||||
it(`Should fail to write '${invalidValues[idx]}' to ${fieldName}`,
|
||||
() => {
|
||||
expect(() => eval(`${fieldName} = '${invalidValues[idx]}'`)).
|
||||
to.throw(expectedError + '');
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
describe('SCORM 2004 CMI Tests', () => {
|
||||
describe('CMI Spec Tests', () => {
|
||||
describe('Pre-Initialize Tests', () => {
|
||||
beforeEach('Create the API object', () => {
|
||||
cmi = new CMI();
|
||||
});
|
||||
afterEach('Destroy API object', () => {
|
||||
cmi = null;
|
||||
});
|
||||
|
||||
/**
|
||||
* Base CMI Properties
|
||||
*/
|
||||
checkReadOnly({fieldName: 'cmi._version', expectedValue: '1.0'});
|
||||
checkReadOnly({
|
||||
fieldName: 'cmi._children',
|
||||
expectedValue: scorm2004_constants.cmi_children,
|
||||
});
|
||||
checkValidValues({
|
||||
fieldName: 'cmi.completion_status',
|
||||
expectedError: scorm2004_error_codes.TYPE_MISMATCH,
|
||||
validValues: [
|
||||
'completed',
|
||||
'incomplete',
|
||||
'not attempted',
|
||||
'unknown',
|
||||
],
|
||||
invalidValues: [
|
||||
'complete',
|
||||
'passed',
|
||||
'failed',
|
||||
],
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user