Adding new selfReportSessionTime setting

This commit is contained in:
Jonathan Putney
2020-06-26 14:50:33 -04:00
parent aa03f6affb
commit ca94ee9fb5
12 changed files with 643 additions and 500 deletions
+1
View File
@@ -52,6 +52,7 @@ The APIs include several settings to customize the functionality of each API:
| `autoProgress` | false | true/false | In case Sequencing is being used, you can tell the API to automatically throw the `SequenceNext` event.| | `autoProgress` | false | true/false | In case Sequencing is being used, you can tell the API to automatically throw the `SequenceNext` event.|
| `logLevel` | 4 | int<br><br>1 => DEBUG<br>2 => INFO<br>3 => WARN<br>4 => ERROR<br>5 => NONE | By default, the APIs only log error messages. | | `logLevel` | 4 | int<br><br>1 => DEBUG<br>2 => INFO<br>3 => WARN<br>4 => ERROR<br>5 => NONE | By default, the APIs only log error messages. |
| `mastery_override` | false | true/false | (SCORM 1.2) Used to override a module's `cmi.core.lesson_status` so that a pass/fail is determined based on a mastery score and the user's raw score, rather than using whatever status is provided by the module. An example of this would be if a module is published using a `Complete/Incomplete` final status, but the LMS always wants to receive a `Passed/Failed` for quizzes, then we can use this setting to override the given final status. | | `mastery_override` | false | true/false | (SCORM 1.2) Used to override a module's `cmi.core.lesson_status` so that a pass/fail is determined based on a mastery score and the user's raw score, rather than using whatever status is provided by the module. An example of this would be if a module is published using a `Complete/Incomplete` final status, but the LMS always wants to receive a `Passed/Failed` for quizzes, then we can use this setting to override the given final status. |
| `selfReportSessionTime` | false | true/false | Should the API override the default `session_time` reported by the module? Useful when modules don't properly report time. |
| `responseHandler` | function | | A function to properly tranform the response from the LMS to the correct format. The APIs expect the result from the LMS to be in the following format (errorCode is optional): `{ "result": true, "errorCode": 0 }` | | `responseHandler` | function | | A function to properly tranform the response from the LMS to the correct format. The APIs expect the result from the LMS to be in the following format (errorCode is optional): `{ "result": true, "errorCode": 0 }` |
## Initial Values ## Initial Values
+73 -20
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
File diff suppressed because one or more lines are too long
+7 -7
View File
File diff suppressed because one or more lines are too long
+484 -439
View File
File diff suppressed because it is too large Load Diff
+3 -3
View File
@@ -1,6 +1,6 @@
{ {
"name": "scorm-again", "name": "scorm-again",
"version": "1.1.4", "version": "1.2.0",
"description": "A modern SCORM JavaScript run-time library for AICC, SCORM 1.2, and SCORM 2004", "description": "A modern SCORM JavaScript run-time library for AICC, SCORM 1.2, and SCORM 2004",
"main": "dist/scorm-again.min.js", "main": "dist/scorm-again.min.js",
"directories": { "directories": {
@@ -21,7 +21,7 @@
"babelify": "^10.0.0", "babelify": "^10.0.0",
"browserify": "^16.5.1", "browserify": "^16.5.1",
"chai": "^4.2.0", "chai": "^4.2.0",
"eslint": "^6.8.0", "eslint": "^7.3.1",
"eslint-config-google": "^0.14.0", "eslint-config-google": "^0.14.0",
"eslint-plugin-import": "^2.21.2", "eslint-plugin-import": "^2.21.2",
"grunt": "^1.1.0", "grunt": "^1.1.0",
@@ -33,7 +33,7 @@
"jsdoc-babel": "^0.5.0", "jsdoc-babel": "^0.5.0",
"minifyify": "^7.3.5", "minifyify": "^7.3.5",
"minimist": "^1.2.5", "minimist": "^1.2.5",
"mocha": "^7.1.2", "mocha": "^8.0.1",
"mocha-junit-reporter": "^2.0.0", "mocha-junit-reporter": "^2.0.0",
"mochawesome": "^6.1.1", "mochawesome": "^6.1.1",
"nyc": "^15.1.0" "nyc": "^15.1.0"
+11 -2
View File
@@ -23,6 +23,7 @@ export default class BaseAPI {
commitRequestDataType: 'application/json;charset=UTF-8', commitRequestDataType: 'application/json;charset=UTF-8',
autoProgress: false, autoProgress: false,
logLevel: global_constants.LOG_LEVEL_ERROR, logLevel: global_constants.LOG_LEVEL_ERROR,
selfReportSessionTime: false,
responseHandler: function(xhr) { responseHandler: function(xhr) {
let result; let result;
if (typeof xhr !== 'undefined') { if (typeof xhr !== 'undefined') {
@@ -62,6 +63,7 @@ export default class BaseAPI {
this.settings = settings; this.settings = settings;
this.apiLogLevel = this.settings.logLevel; this.apiLogLevel = this.settings.logLevel;
this.selfReportSessionTime = this.settings.selfReportSessionTime;
} }
/** /**
@@ -82,6 +84,10 @@ export default class BaseAPI {
} else if (this.isTerminated()) { } else if (this.isTerminated()) {
this.throwSCORMError(this.#error_codes.TERMINATED, terminationMessage); this.throwSCORMError(this.#error_codes.TERMINATED, terminationMessage);
} else { } else {
if (this.selfReportSessionTime) {
this.cmi.setStartTime();
}
this.currentState = global_constants.STATE_INITIALIZED; this.currentState = global_constants.STATE_INITIALIZED;
this.lastErrorCode = 0; this.lastErrorCode = 0;
returnValue = global_constants.SCORM_TRUE; returnValue = global_constants.SCORM_TRUE;
@@ -767,8 +773,11 @@ export default class BaseAPI {
const functionsMatch = listener.functionName === functionName; const functionsMatch = listener.functionName === functionName;
const listenerHasCMIElement = !!listener.CMIElement; const listenerHasCMIElement = !!listener.CMIElement;
let CMIElementsMatch = false; let CMIElementsMatch = false;
if (CMIElement && listener.CMIElement && listener.CMIElement.substring(listener.CMIElement.length - 1) === '*') { if (CMIElement && listener.CMIElement &&
CMIElementsMatch = CMIElement.indexOf(listener.CMIElement.substring(0, listener.CMIElement.length - 1)) === 0; listener.CMIElement.substring(listener.CMIElement.length - 1) ===
'*') {
CMIElementsMatch = CMIElement.indexOf(listener.CMIElement.substring(0,
listener.CMIElement.length - 1)) === 0;
} else { } else {
CMIElementsMatch = listener.CMIElement === CMIElement; CMIElementsMatch = listener.CMIElement === CMIElement;
} }
+17
View File
@@ -62,6 +62,7 @@ export function checkValidRange(
export class BaseCMI { export class BaseCMI {
jsonString = false; jsonString = false;
#initialized = false; #initialized = false;
#start_time;
/** /**
* Constructor for BaseCMI, just marks the class as abstract * Constructor for BaseCMI, just marks the class as abstract
@@ -80,12 +81,28 @@ export class BaseCMI {
return this.#initialized; return this.#initialized;
} }
/**
* Getter for #start_time
* @return {Number}
*/
get start_time() {
return this.#start_time;
}
/** /**
* Called when the API has been initialized after the CMI has been created * Called when the API has been initialized after the CMI has been created
*/ */
initialize() { initialize() {
this.#initialized = true; this.#initialized = true;
} }
/**
* Called when the player should override the 'session_time' provided by
* the module
*/
setStartTime() {
this.#start_time = new Date().getTime();
}
} }
/** /**
+13 -4
View File
@@ -11,6 +11,7 @@ import ErrorCodes from '../constants/error_codes';
import Regex from '../constants/regex'; import Regex from '../constants/regex';
import {ValidationError} from '../exceptions'; import {ValidationError} from '../exceptions';
import * as Utilities from '../utilities'; import * as Utilities from '../utilities';
import * as Util from '../utilities';
const scorm12_constants = APIConstants.scorm12; const scorm12_constants = APIConstants.scorm12;
const scorm12_regex = Regex.scorm12; const scorm12_regex = Regex.scorm12;
@@ -254,7 +255,7 @@ export class CMI extends BaseCMI {
* @return {string} * @return {string}
*/ */
getCurrentTotalTime() { getCurrentTotalTime() {
return this.core.getCurrentTotalTime(); return this.core.getCurrentTotalTime(this.start_time);
} }
} }
@@ -508,13 +509,21 @@ class CMICore extends BaseCMI {
/** /**
* Adds the current session time to the existing total time. * Adds the current session time to the existing total time.
* * @param {Number} start_time
* @return {string} * @return {string}
*/ */
getCurrentTotalTime() { getCurrentTotalTime(start_time: Number) {
let sessionTime = this.#session_time;
const startTime = start_time;
if (typeof startTime !== 'undefined' || startTime === null) {
const seconds = new Date().getTime() - startTime;
sessionTime = Util.getSecondsAsHHMMSS(seconds / 1000);
}
return Utilities.addHHMMSSTimeStrings( return Utilities.addHHMMSSTimeStrings(
this.#total_time, this.#total_time,
this.#session_time, sessionTime,
new RegExp(scorm12_regex.CMITimespan), new RegExp(scorm12_regex.CMITimespan),
); );
} }
+17 -5
View File
@@ -431,7 +431,8 @@ export class CMI extends BaseCMI {
* @param {string} suspend_data * @param {string} suspend_data
*/ */
set suspend_data(suspend_data) { set suspend_data(suspend_data) {
if (check2004ValidFormat(suspend_data, scorm2004_regex.CMIString64000, true)) { if (check2004ValidFormat(suspend_data, scorm2004_regex.CMIString64000,
true)) {
this.#suspend_data = suspend_data; this.#suspend_data = suspend_data;
} }
} }
@@ -476,9 +477,17 @@ export class CMI extends BaseCMI {
* @return {string} ISO8601 Duration * @return {string} ISO8601 Duration
*/ */
getCurrentTotalTime() { getCurrentTotalTime() {
let sessionTime = this.#session_time;
const startTime = this.start_time;
if (typeof startTime !== 'undefined' || startTime === null) {
const seconds = new Date().getTime() - startTime;
sessionTime = Util.getSecondsAsISODuration(seconds / 1000);
}
return Util.addTwoDurations( return Util.addTwoDurations(
this.#total_time, this.#total_time,
this.#session_time, sessionTime,
scorm2004_regex.CMITimespan, scorm2004_regex.CMITimespan,
); );
} }
@@ -966,7 +975,8 @@ export class CMIInteractionsObject extends BaseCMI {
* @param {string} description * @param {string} description
*/ */
set description(description) { set description(description) {
if (check2004ValidFormat(description, scorm2004_regex.CMILangString250, true)) { if (check2004ValidFormat(description, scorm2004_regex.CMILangString250,
true)) {
this.#description = description; this.#description = description;
} }
} }
@@ -1121,7 +1131,8 @@ export class CMIObjectivesObject extends BaseCMI {
* @param {string} description * @param {string} description
*/ */
set description(description) { set description(description) {
if (check2004ValidFormat(description, scorm2004_regex.CMILangString250, true)) { if (check2004ValidFormat(description, scorm2004_regex.CMILangString250,
true)) {
this.#description = description; this.#description = description;
} }
} }
@@ -1257,7 +1268,8 @@ export class CMICommentsObject extends BaseCMI {
if (this.initialized && this.#readOnlyAfterInit) { if (this.initialized && this.#readOnlyAfterInit) {
throwReadOnlyError(); throwReadOnlyError();
} else { } else {
if (check2004ValidFormat(comment, scorm2004_regex.CMILangString4000, true)) { if (check2004ValidFormat(comment, scorm2004_regex.CMILangString4000,
true)) {
this.#comment = comment; this.#comment = comment;
} }
} }
-3
View File
@@ -317,9 +317,6 @@ describe('SCORM 1.2 API Tests', () => {
cmiExport.cmi.core.total_time, cmiExport.cmi.core.total_time,
).to.equal('36:34:55'); ).to.equal('36:34:55');
}); });
});
describe('renderCommitCMI()', () => {
it('if the user passes, should calculate total time when terminateCommit passed', it('if the user passes, should calculate total time when terminateCommit passed',
() => { () => {
const scorm12API = api(); const scorm12API = api();
+2 -2
View File
@@ -7,8 +7,8 @@ import {scorm2004_values} from './field_values';
const scorm2004_error_codes = ErrorCodes.scorm2004; const scorm2004_error_codes = ErrorCodes.scorm2004;
const api = (startingData) => { const api = (settings = {}, startingData = {}) => {
const API = new Scorm2004API(); const API = new Scorm2004API(settings);
API.apiLogLevel = 1; API.apiLogLevel = 1;
if (startingData) { if (startingData) {
API.startingData = startingData; API.startingData = startingData;