scorm-again 2.0.0 → 2.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/stale.yml +14 -0
- package/.run/{Mocha Unit Tests.run.xml → Mocha Unit Tests (watch).run.xml } +1 -1
- package/.run/Template Mocha.run.xml +17 -0
- package/README.md +180 -72
- package/dist/aicc.js +1520 -1149
- package/dist/aicc.js.map +1 -1
- package/dist/aicc.min.js +1 -1
- package/dist/aicc.min.js.map +1 -1
- package/dist/scorm-again.js +2812 -2205
- package/dist/scorm-again.js.map +1 -1
- package/dist/scorm-again.min.js +1 -1
- package/dist/scorm-again.min.js.map +1 -1
- package/dist/scorm12.js +1129 -842
- package/dist/scorm12.js.map +1 -1
- package/dist/scorm12.min.js +1 -1
- package/dist/scorm12.min.js.map +1 -1
- package/dist/scorm2004.js +1921 -1564
- package/dist/scorm2004.js.map +1 -1
- package/dist/scorm2004.min.js +1 -1
- package/dist/scorm2004.min.js.map +1 -1
- package/package.json +20 -17
- package/src/AICC.ts +15 -17
- package/src/BaseAPI.ts +283 -420
- package/src/Scorm12API.ts +133 -41
- package/src/Scorm2004API.ts +224 -120
- package/src/cmi/aicc/attempts.ts +94 -0
- package/src/cmi/aicc/cmi.ts +100 -0
- package/src/cmi/aicc/core.ts +360 -0
- package/src/cmi/aicc/evaluation.ts +157 -0
- package/src/cmi/aicc/paths.ts +180 -0
- package/src/cmi/aicc/student_data.ts +86 -0
- package/src/cmi/aicc/student_demographics.ts +367 -0
- package/src/cmi/aicc/student_preferences.ts +176 -0
- package/src/cmi/aicc/tries.ts +116 -0
- package/src/cmi/aicc/validation.ts +25 -0
- package/src/cmi/common/array.ts +77 -0
- package/src/cmi/common/base_cmi.ts +46 -0
- package/src/cmi/common/score.ts +203 -0
- package/src/cmi/common/validation.ts +60 -0
- package/src/cmi/scorm12/cmi.ts +224 -0
- package/src/cmi/scorm12/interactions.ts +368 -0
- package/src/cmi/scorm12/nav.ts +54 -0
- package/src/cmi/scorm12/objectives.ts +112 -0
- package/src/cmi/scorm12/student_data.ts +130 -0
- package/src/cmi/scorm12/student_preference.ts +158 -0
- package/src/cmi/scorm12/validation.ts +48 -0
- package/src/cmi/scorm2004/adl.ts +272 -0
- package/src/cmi/scorm2004/cmi.ts +599 -0
- package/src/cmi/scorm2004/comments.ts +163 -0
- package/src/cmi/scorm2004/interactions.ts +466 -0
- package/src/cmi/scorm2004/learner_preference.ts +152 -0
- package/src/cmi/scorm2004/objectives.ts +212 -0
- package/src/cmi/scorm2004/score.ts +78 -0
- package/src/cmi/scorm2004/validation.ts +42 -0
- package/src/constants/default_settings.ts +82 -0
- package/src/constants/enums.ts +17 -0
- package/src/constants/regex.ts +2 -2
- package/src/constants/response_constants.ts +2 -0
- package/src/exceptions.ts +22 -1
- package/src/helpers/scheduled_commit.ts +42 -0
- package/src/interfaces/IBaseAPI.ts +35 -0
- package/src/types/api_types.ts +50 -0
- package/src/utilities/debounce.ts +31 -0
- package/src/utilities.ts +56 -0
- package/test/AICC.spec.ts +11 -1
- package/test/Scorm12API.spec.ts +372 -9
- package/test/Scorm2004API.spec.ts +558 -2
- package/test/cmi/aicc_cmi.spec.ts +188 -11
- package/test/cmi/scorm12_cmi.spec.ts +5 -5
- package/test/cmi/scorm2004_cmi.spec.ts +8 -8
- package/test/cmi_helpers.ts +1 -1
- package/test/types/api_types.spec.ts +126 -0
- package/test/utilities/debounce.spec.ts +56 -0
- package/src/cmi/aicc_cmi.ts +0 -1248
- package/src/cmi/common.ts +0 -411
- package/src/cmi/scorm12_cmi.ts +0 -1426
- package/src/cmi/scorm2004_cmi.ts +0 -1874
package/src/BaseAPI.ts
CHANGED
|
@@ -1,154 +1,25 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { CMIArray } from "./cmi/common/array";
|
|
2
2
|
import { ValidationError } from "./exceptions";
|
|
3
3
|
import ErrorCodes, { ErrorCode } from "./constants/error_codes";
|
|
4
4
|
import APIConstants from "./constants/api_constants";
|
|
5
|
-
import { unflatten } from "./utilities";
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
*/
|
|
18
|
-
function debounce<T extends (...args: any[]) => void>(
|
|
19
|
-
func: T,
|
|
20
|
-
wait: number,
|
|
21
|
-
immediate = false,
|
|
22
|
-
): (...args: Parameters<T>) => void {
|
|
23
|
-
let timeout: ReturnType<typeof setTimeout> | null;
|
|
24
|
-
|
|
25
|
-
return function (this: any, ...args: Parameters<T>) {
|
|
26
|
-
const context = this;
|
|
27
|
-
|
|
28
|
-
const later = () => {
|
|
29
|
-
timeout = null;
|
|
30
|
-
if (!immediate) func.apply(context, args);
|
|
31
|
-
};
|
|
32
|
-
|
|
33
|
-
const callNow = immediate && !timeout;
|
|
34
|
-
|
|
35
|
-
if (timeout) clearTimeout(timeout);
|
|
36
|
-
timeout = setTimeout(later, wait);
|
|
37
|
-
|
|
38
|
-
if (callNow) func.apply(context, args);
|
|
39
|
-
};
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
export type Settings = {
|
|
43
|
-
autocommit: boolean;
|
|
44
|
-
autocommitSeconds: number;
|
|
45
|
-
asyncCommit: boolean;
|
|
46
|
-
sendBeaconCommit: boolean;
|
|
47
|
-
lmsCommitUrl: boolean | string;
|
|
48
|
-
dataCommitFormat: string;
|
|
49
|
-
commitRequestDataType: string;
|
|
50
|
-
autoProgress: boolean;
|
|
51
|
-
logLevel: number;
|
|
52
|
-
selfReportSessionTime: boolean;
|
|
53
|
-
alwaysSendTotalTime: boolean;
|
|
54
|
-
strict_errors: boolean;
|
|
55
|
-
xhrHeaders: RefObject;
|
|
56
|
-
xhrWithCredentials: boolean;
|
|
57
|
-
responseHandler: (response: Response) => Promise<ResultObject>;
|
|
58
|
-
requestHandler: (commitObject: any) => any;
|
|
59
|
-
onLogMessage: (messageLevel: number, logMessage: string) => void;
|
|
60
|
-
mastery_override?: boolean;
|
|
61
|
-
};
|
|
62
|
-
|
|
63
|
-
export type RefObject = {
|
|
64
|
-
[key: string]: any;
|
|
65
|
-
};
|
|
66
|
-
|
|
67
|
-
export type ResultObject = {
|
|
68
|
-
result: string;
|
|
69
|
-
errorCode: number;
|
|
70
|
-
navRequest?: string;
|
|
71
|
-
};
|
|
72
|
-
|
|
73
|
-
export const DefaultSettings: Settings = {
|
|
74
|
-
autocommit: false,
|
|
75
|
-
autocommitSeconds: 10,
|
|
76
|
-
asyncCommit: false,
|
|
77
|
-
sendBeaconCommit: false,
|
|
78
|
-
lmsCommitUrl: false,
|
|
79
|
-
dataCommitFormat: "json",
|
|
80
|
-
commitRequestDataType: "application/json;charset=UTF-8",
|
|
81
|
-
autoProgress: false,
|
|
82
|
-
logLevel: global_constants.LOG_LEVEL_ERROR,
|
|
83
|
-
selfReportSessionTime: false,
|
|
84
|
-
alwaysSendTotalTime: false,
|
|
85
|
-
strict_errors: true,
|
|
86
|
-
xhrHeaders: {},
|
|
87
|
-
xhrWithCredentials: false,
|
|
88
|
-
responseHandler: async function (response: Response): Promise<ResultObject> {
|
|
89
|
-
if (typeof response !== "undefined") {
|
|
90
|
-
const httpResult = JSON.parse(await response.text());
|
|
91
|
-
if (
|
|
92
|
-
httpResult === null ||
|
|
93
|
-
!{}.hasOwnProperty.call(httpResult, "result")
|
|
94
|
-
) {
|
|
95
|
-
if (response.status === 200) {
|
|
96
|
-
return {
|
|
97
|
-
result: global_constants.SCORM_TRUE,
|
|
98
|
-
errorCode: 0,
|
|
99
|
-
};
|
|
100
|
-
} else {
|
|
101
|
-
return {
|
|
102
|
-
result: global_constants.SCORM_FALSE,
|
|
103
|
-
errorCode: 101,
|
|
104
|
-
};
|
|
105
|
-
}
|
|
106
|
-
} else {
|
|
107
|
-
return {
|
|
108
|
-
result: httpResult.result,
|
|
109
|
-
errorCode: httpResult.errorCode
|
|
110
|
-
? httpResult.errorCode
|
|
111
|
-
: httpResult.result === global_constants.SCORM_TRUE
|
|
112
|
-
? 0
|
|
113
|
-
: 101,
|
|
114
|
-
};
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
return {
|
|
118
|
-
result: global_constants.SCORM_FALSE,
|
|
119
|
-
errorCode: 101,
|
|
120
|
-
};
|
|
121
|
-
},
|
|
122
|
-
requestHandler: function (commitObject) {
|
|
123
|
-
return commitObject;
|
|
124
|
-
},
|
|
125
|
-
onLogMessage: function (messageLevel, logMessage) {
|
|
126
|
-
switch (messageLevel) {
|
|
127
|
-
case global_constants.LOG_LEVEL_ERROR:
|
|
128
|
-
console.error(logMessage);
|
|
129
|
-
break;
|
|
130
|
-
case global_constants.LOG_LEVEL_WARNING:
|
|
131
|
-
console.warn(logMessage);
|
|
132
|
-
break;
|
|
133
|
-
case global_constants.LOG_LEVEL_INFO:
|
|
134
|
-
console.info(logMessage);
|
|
135
|
-
break;
|
|
136
|
-
case global_constants.LOG_LEVEL_DEBUG:
|
|
137
|
-
if (console.debug) {
|
|
138
|
-
console.debug(logMessage);
|
|
139
|
-
} else {
|
|
140
|
-
console.log(logMessage);
|
|
141
|
-
}
|
|
142
|
-
break;
|
|
143
|
-
}
|
|
144
|
-
},
|
|
145
|
-
};
|
|
5
|
+
import { formatMessage, stringMatches, unflatten } from "./utilities";
|
|
6
|
+
import { BaseCMI } from "./cmi/common/base_cmi";
|
|
7
|
+
import { debounce } from "./utilities/debounce";
|
|
8
|
+
import {
|
|
9
|
+
RefObject,
|
|
10
|
+
CommitObject,
|
|
11
|
+
ResultObject,
|
|
12
|
+
Settings,
|
|
13
|
+
} from "./types/api_types";
|
|
14
|
+
import { DefaultSettings } from "./constants/default_settings";
|
|
15
|
+
import { IBaseAPI } from "./interfaces/IBaseAPI";
|
|
16
|
+
import { ScheduledCommit } from "./helpers/scheduled_commit";
|
|
146
17
|
|
|
147
18
|
/**
|
|
148
19
|
* Base API class for AICC, SCORM 1.2, and SCORM 2004. Should be considered
|
|
149
20
|
* abstract, and never initialized on its own.
|
|
150
21
|
*/
|
|
151
|
-
export default abstract class BaseAPI {
|
|
22
|
+
export default abstract class BaseAPI implements IBaseAPI {
|
|
152
23
|
private _timeout?: ScheduledCommit;
|
|
153
24
|
private readonly _error_codes: ErrorCode;
|
|
154
25
|
private _settings: Settings = DefaultSettings;
|
|
@@ -163,7 +34,7 @@ export default abstract class BaseAPI {
|
|
|
163
34
|
if (new.target === BaseAPI) {
|
|
164
35
|
throw new TypeError("Cannot construct BaseAPI instances directly");
|
|
165
36
|
}
|
|
166
|
-
this.currentState =
|
|
37
|
+
this.currentState = APIConstants.global.STATE_NOT_INITIALIZED;
|
|
167
38
|
this.lastErrorCode = "0";
|
|
168
39
|
this.listenerArray = [];
|
|
169
40
|
|
|
@@ -185,6 +56,21 @@ export default abstract class BaseAPI {
|
|
|
185
56
|
public apiLogLevel: number;
|
|
186
57
|
public selfReportSessionTime: boolean;
|
|
187
58
|
|
|
59
|
+
abstract reset(settings?: Settings): void;
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Common reset method for all APIs. New settings are merged with the existing settings.
|
|
63
|
+
* @param {Settings} settings
|
|
64
|
+
* @protected
|
|
65
|
+
*/
|
|
66
|
+
commonReset(settings?: Settings): void {
|
|
67
|
+
this.settings = { ...this.settings, ...settings };
|
|
68
|
+
|
|
69
|
+
this.currentState = APIConstants.global.STATE_NOT_INITIALIZED;
|
|
70
|
+
this.lastErrorCode = "0";
|
|
71
|
+
this.listenerArray = [];
|
|
72
|
+
}
|
|
73
|
+
|
|
188
74
|
/**
|
|
189
75
|
* Initialize the API
|
|
190
76
|
* @param {string} callbackName
|
|
@@ -197,7 +83,7 @@ export default abstract class BaseAPI {
|
|
|
197
83
|
initializeMessage?: string,
|
|
198
84
|
terminationMessage?: string,
|
|
199
85
|
): string {
|
|
200
|
-
let returnValue =
|
|
86
|
+
let returnValue = APIConstants.global.SCORM_FALSE;
|
|
201
87
|
|
|
202
88
|
if (this.isInitialized()) {
|
|
203
89
|
this.throwSCORMError(this._error_codes.INITIALIZED, initializeMessage);
|
|
@@ -208,16 +94,16 @@ export default abstract class BaseAPI {
|
|
|
208
94
|
this.cmi.setStartTime();
|
|
209
95
|
}
|
|
210
96
|
|
|
211
|
-
this.currentState =
|
|
97
|
+
this.currentState = APIConstants.global.STATE_INITIALIZED;
|
|
212
98
|
this.lastErrorCode = "0";
|
|
213
|
-
returnValue =
|
|
99
|
+
returnValue = APIConstants.global.SCORM_TRUE;
|
|
214
100
|
this.processListeners(callbackName);
|
|
215
101
|
}
|
|
216
102
|
|
|
217
103
|
this.apiLog(
|
|
218
104
|
callbackName,
|
|
219
105
|
"returned: " + returnValue,
|
|
220
|
-
|
|
106
|
+
APIConstants.global.LOG_LEVEL_INFO,
|
|
221
107
|
);
|
|
222
108
|
this.clearSCORMError(returnValue);
|
|
223
109
|
|
|
@@ -240,6 +126,78 @@ export default abstract class BaseAPI {
|
|
|
240
126
|
|
|
241
127
|
abstract lmsGetDiagnostic(CMIErrorCode: string | number): string;
|
|
242
128
|
|
|
129
|
+
/**
|
|
130
|
+
* Abstract method for validating that a response is correct.
|
|
131
|
+
*
|
|
132
|
+
* @param {string} _CMIElement
|
|
133
|
+
* @param {any} _value
|
|
134
|
+
*/
|
|
135
|
+
abstract validateCorrectResponse(_CMIElement: string, _value: any): void;
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Gets or builds a new child element to add to the array.
|
|
139
|
+
* APIs that inherit BaseAPI should override this method.
|
|
140
|
+
*
|
|
141
|
+
* @param {string} _CMIElement - unused
|
|
142
|
+
* @param {*} _value - unused
|
|
143
|
+
* @param {boolean} _foundFirstIndex - unused
|
|
144
|
+
* @return {BaseCMI|null}
|
|
145
|
+
* @abstract
|
|
146
|
+
*/
|
|
147
|
+
abstract getChildElement(
|
|
148
|
+
_CMIElement: string,
|
|
149
|
+
_value: any,
|
|
150
|
+
_foundFirstIndex: boolean,
|
|
151
|
+
): BaseCMI | null;
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Attempts to store the data to the LMS, logs data if no LMS configured
|
|
155
|
+
* APIs that inherit BaseAPI should override this function
|
|
156
|
+
*
|
|
157
|
+
* @param {boolean} _calculateTotalTime
|
|
158
|
+
* @return {ResultObject}
|
|
159
|
+
* @abstract
|
|
160
|
+
*/
|
|
161
|
+
abstract storeData(_calculateTotalTime: boolean): Promise<ResultObject>;
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Render the cmi object to the proper format for LMS commit
|
|
165
|
+
* APIs that inherit BaseAPI should override this function
|
|
166
|
+
*
|
|
167
|
+
* @param {boolean} _terminateCommit
|
|
168
|
+
* @return {RefObject|Array}
|
|
169
|
+
* @abstract
|
|
170
|
+
*/
|
|
171
|
+
abstract renderCommitCMI(_terminateCommit: boolean): RefObject | Array<any>;
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* Render the commit object to the shortened format for LMS commit
|
|
175
|
+
* @param {boolean} _terminateCommit
|
|
176
|
+
* @return {CommitObject}
|
|
177
|
+
*/
|
|
178
|
+
abstract renderCommitObject(_terminateCommit: boolean): CommitObject;
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Logging for all SCORM actions
|
|
182
|
+
*
|
|
183
|
+
* @param {string} functionName
|
|
184
|
+
* @param {string} logMessage
|
|
185
|
+
* @param {number} messageLevel
|
|
186
|
+
* @param {string} CMIElement
|
|
187
|
+
*/
|
|
188
|
+
apiLog(
|
|
189
|
+
functionName: string,
|
|
190
|
+
logMessage: string,
|
|
191
|
+
messageLevel: number,
|
|
192
|
+
CMIElement?: string,
|
|
193
|
+
) {
|
|
194
|
+
logMessage = formatMessage(functionName, logMessage, CMIElement);
|
|
195
|
+
|
|
196
|
+
if (messageLevel >= this.apiLogLevel) {
|
|
197
|
+
this.settings.onLogMessage(messageLevel, logMessage);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
243
201
|
/**
|
|
244
202
|
* Getter for _error_codes
|
|
245
203
|
* @return {ErrorCode}
|
|
@@ -270,8 +228,11 @@ export default abstract class BaseAPI {
|
|
|
270
228
|
* @param {boolean} checkTerminated
|
|
271
229
|
* @return {string}
|
|
272
230
|
*/
|
|
273
|
-
terminate(
|
|
274
|
-
|
|
231
|
+
async terminate(
|
|
232
|
+
callbackName: string,
|
|
233
|
+
checkTerminated: boolean,
|
|
234
|
+
): Promise<string> {
|
|
235
|
+
let returnValue = APIConstants.global.SCORM_FALSE;
|
|
275
236
|
|
|
276
237
|
if (
|
|
277
238
|
this.checkState(
|
|
@@ -280,27 +241,27 @@ export default abstract class BaseAPI {
|
|
|
280
241
|
this._error_codes.MULTIPLE_TERMINATION,
|
|
281
242
|
)
|
|
282
243
|
) {
|
|
283
|
-
this.currentState =
|
|
244
|
+
this.currentState = APIConstants.global.STATE_TERMINATED;
|
|
284
245
|
|
|
285
|
-
const result: ResultObject = this.storeData(true);
|
|
246
|
+
const result: ResultObject = await this.storeData(true);
|
|
286
247
|
if (typeof result.errorCode !== "undefined" && result.errorCode > 0) {
|
|
287
248
|
this.throwSCORMError(result.errorCode);
|
|
288
249
|
}
|
|
289
250
|
returnValue =
|
|
290
251
|
typeof result !== "undefined" && result.result
|
|
291
252
|
? result.result
|
|
292
|
-
:
|
|
253
|
+
: APIConstants.global.SCORM_FALSE;
|
|
293
254
|
|
|
294
255
|
if (checkTerminated) this.lastErrorCode = "0";
|
|
295
256
|
|
|
296
|
-
returnValue =
|
|
257
|
+
returnValue = APIConstants.global.SCORM_TRUE;
|
|
297
258
|
this.processListeners(callbackName);
|
|
298
259
|
}
|
|
299
260
|
|
|
300
261
|
this.apiLog(
|
|
301
262
|
callbackName,
|
|
302
263
|
"returned: " + returnValue,
|
|
303
|
-
|
|
264
|
+
APIConstants.global.LOG_LEVEL_INFO,
|
|
304
265
|
);
|
|
305
266
|
this.clearSCORMError(returnValue);
|
|
306
267
|
|
|
@@ -341,9 +302,14 @@ export default abstract class BaseAPI {
|
|
|
341
302
|
this.apiLog(
|
|
342
303
|
callbackName,
|
|
343
304
|
": returned: " + returnValue,
|
|
344
|
-
|
|
305
|
+
APIConstants.global.LOG_LEVEL_INFO,
|
|
345
306
|
CMIElement,
|
|
346
307
|
);
|
|
308
|
+
|
|
309
|
+
if (returnValue === undefined) {
|
|
310
|
+
return "";
|
|
311
|
+
}
|
|
312
|
+
|
|
347
313
|
this.clearSCORMError(returnValue);
|
|
348
314
|
|
|
349
315
|
return returnValue;
|
|
@@ -369,7 +335,7 @@ export default abstract class BaseAPI {
|
|
|
369
335
|
if (value !== undefined) {
|
|
370
336
|
value = String(value);
|
|
371
337
|
}
|
|
372
|
-
let returnValue: string =
|
|
338
|
+
let returnValue: string = APIConstants.global.SCORM_FALSE;
|
|
373
339
|
|
|
374
340
|
if (
|
|
375
341
|
this.checkState(
|
|
@@ -388,7 +354,7 @@ export default abstract class BaseAPI {
|
|
|
388
354
|
}
|
|
389
355
|
|
|
390
356
|
if (returnValue === undefined) {
|
|
391
|
-
returnValue =
|
|
357
|
+
returnValue = APIConstants.global.SCORM_FALSE;
|
|
392
358
|
}
|
|
393
359
|
|
|
394
360
|
// If we didn't have any errors while setting the data, go ahead and
|
|
@@ -405,7 +371,7 @@ export default abstract class BaseAPI {
|
|
|
405
371
|
this.apiLog(
|
|
406
372
|
callbackName,
|
|
407
373
|
": " + value + ": result: " + returnValue,
|
|
408
|
-
|
|
374
|
+
APIConstants.global.LOG_LEVEL_INFO,
|
|
409
375
|
CMIElement,
|
|
410
376
|
);
|
|
411
377
|
this.clearSCORMError(returnValue);
|
|
@@ -419,10 +385,13 @@ export default abstract class BaseAPI {
|
|
|
419
385
|
* @param {boolean} checkTerminated
|
|
420
386
|
* @return {string}
|
|
421
387
|
*/
|
|
422
|
-
commit(
|
|
388
|
+
async commit(
|
|
389
|
+
callbackName: string,
|
|
390
|
+
checkTerminated: boolean = false,
|
|
391
|
+
): Promise<string> {
|
|
423
392
|
this.clearScheduledCommit();
|
|
424
393
|
|
|
425
|
-
let returnValue =
|
|
394
|
+
let returnValue = APIConstants.global.SCORM_FALSE;
|
|
426
395
|
|
|
427
396
|
if (
|
|
428
397
|
this.checkState(
|
|
@@ -431,19 +400,19 @@ export default abstract class BaseAPI {
|
|
|
431
400
|
this._error_codes.COMMIT_AFTER_TERM,
|
|
432
401
|
)
|
|
433
402
|
) {
|
|
434
|
-
const result = this.storeData(false);
|
|
403
|
+
const result = await this.storeData(false);
|
|
435
404
|
if (result.errorCode && result.errorCode > 0) {
|
|
436
405
|
this.throwSCORMError(result.errorCode);
|
|
437
406
|
}
|
|
438
407
|
returnValue =
|
|
439
408
|
typeof result !== "undefined" && result.result
|
|
440
409
|
? result.result
|
|
441
|
-
:
|
|
410
|
+
: APIConstants.global.SCORM_FALSE;
|
|
442
411
|
|
|
443
412
|
this.apiLog(
|
|
444
413
|
callbackName,
|
|
445
414
|
" Result: " + returnValue,
|
|
446
|
-
|
|
415
|
+
APIConstants.global.LOG_LEVEL_DEBUG,
|
|
447
416
|
"HttpRequest",
|
|
448
417
|
);
|
|
449
418
|
|
|
@@ -455,7 +424,7 @@ export default abstract class BaseAPI {
|
|
|
455
424
|
this.apiLog(
|
|
456
425
|
callbackName,
|
|
457
426
|
"returned: " + returnValue,
|
|
458
|
-
|
|
427
|
+
APIConstants.global.LOG_LEVEL_INFO,
|
|
459
428
|
);
|
|
460
429
|
this.clearSCORMError(returnValue);
|
|
461
430
|
|
|
@@ -475,7 +444,7 @@ export default abstract class BaseAPI {
|
|
|
475
444
|
this.apiLog(
|
|
476
445
|
callbackName,
|
|
477
446
|
"returned: " + returnValue,
|
|
478
|
-
|
|
447
|
+
APIConstants.global.LOG_LEVEL_INFO,
|
|
479
448
|
);
|
|
480
449
|
|
|
481
450
|
return returnValue;
|
|
@@ -499,7 +468,7 @@ export default abstract class BaseAPI {
|
|
|
499
468
|
this.apiLog(
|
|
500
469
|
callbackName,
|
|
501
470
|
"returned: " + returnValue,
|
|
502
|
-
|
|
471
|
+
APIConstants.global.LOG_LEVEL_INFO,
|
|
503
472
|
);
|
|
504
473
|
|
|
505
474
|
return returnValue;
|
|
@@ -523,7 +492,7 @@ export default abstract class BaseAPI {
|
|
|
523
492
|
this.apiLog(
|
|
524
493
|
callbackName,
|
|
525
494
|
"returned: " + returnValue,
|
|
526
|
-
|
|
495
|
+
APIConstants.global.LOG_LEVEL_INFO,
|
|
527
496
|
);
|
|
528
497
|
|
|
529
498
|
return returnValue;
|
|
@@ -553,104 +522,6 @@ export default abstract class BaseAPI {
|
|
|
553
522
|
return true;
|
|
554
523
|
}
|
|
555
524
|
|
|
556
|
-
/**
|
|
557
|
-
* Logging for all SCORM actions
|
|
558
|
-
*
|
|
559
|
-
* @param {string} functionName
|
|
560
|
-
* @param {string} logMessage
|
|
561
|
-
* @param {number}messageLevel
|
|
562
|
-
* @param {string} CMIElement
|
|
563
|
-
*/
|
|
564
|
-
apiLog(
|
|
565
|
-
functionName: string,
|
|
566
|
-
logMessage: string,
|
|
567
|
-
messageLevel: number,
|
|
568
|
-
CMIElement?: string,
|
|
569
|
-
) {
|
|
570
|
-
logMessage = this.formatMessage(functionName, logMessage, CMIElement);
|
|
571
|
-
|
|
572
|
-
if (messageLevel >= this.apiLogLevel) {
|
|
573
|
-
this.settings.onLogMessage(messageLevel, logMessage);
|
|
574
|
-
}
|
|
575
|
-
}
|
|
576
|
-
|
|
577
|
-
/**
|
|
578
|
-
* Formats the SCORM messages for easy reading
|
|
579
|
-
*
|
|
580
|
-
* @param {string} functionName
|
|
581
|
-
* @param {string} message
|
|
582
|
-
* @param {string} CMIElement
|
|
583
|
-
* @return {string}
|
|
584
|
-
*/
|
|
585
|
-
formatMessage(
|
|
586
|
-
functionName: string,
|
|
587
|
-
message: string,
|
|
588
|
-
CMIElement?: string,
|
|
589
|
-
): string {
|
|
590
|
-
const baseLength = 20;
|
|
591
|
-
let messageString = "";
|
|
592
|
-
|
|
593
|
-
messageString += functionName;
|
|
594
|
-
|
|
595
|
-
let fillChars = baseLength - messageString.length;
|
|
596
|
-
|
|
597
|
-
for (let i = 0; i < fillChars; i++) {
|
|
598
|
-
messageString += " ";
|
|
599
|
-
}
|
|
600
|
-
|
|
601
|
-
messageString += ": ";
|
|
602
|
-
|
|
603
|
-
if (CMIElement) {
|
|
604
|
-
const CMIElementBaseLength = 70;
|
|
605
|
-
|
|
606
|
-
messageString += CMIElement;
|
|
607
|
-
|
|
608
|
-
fillChars = CMIElementBaseLength - messageString.length;
|
|
609
|
-
|
|
610
|
-
for (let j = 0; j < fillChars; j++) {
|
|
611
|
-
messageString += " ";
|
|
612
|
-
}
|
|
613
|
-
}
|
|
614
|
-
|
|
615
|
-
if (message) {
|
|
616
|
-
messageString += message;
|
|
617
|
-
}
|
|
618
|
-
|
|
619
|
-
return messageString;
|
|
620
|
-
}
|
|
621
|
-
|
|
622
|
-
/**
|
|
623
|
-
* Checks to see if {str} contains {tester}
|
|
624
|
-
*
|
|
625
|
-
* @param {string} str String to check against
|
|
626
|
-
* @param {string} tester String to check for
|
|
627
|
-
* @return {boolean}
|
|
628
|
-
*/
|
|
629
|
-
stringMatches(str: string, tester: string): boolean {
|
|
630
|
-
return str?.match(tester) !== null;
|
|
631
|
-
}
|
|
632
|
-
|
|
633
|
-
/**
|
|
634
|
-
* Check to see if the specific object has the given property
|
|
635
|
-
* @param {RefObject} refObject
|
|
636
|
-
* @param {string} attribute
|
|
637
|
-
* @return {boolean}
|
|
638
|
-
* @private
|
|
639
|
-
*/
|
|
640
|
-
private _checkObjectHasProperty(
|
|
641
|
-
refObject: RefObject,
|
|
642
|
-
attribute: string,
|
|
643
|
-
): boolean {
|
|
644
|
-
return (
|
|
645
|
-
Object.hasOwnProperty.call(refObject, attribute) ||
|
|
646
|
-
Object.getOwnPropertyDescriptor(
|
|
647
|
-
Object.getPrototypeOf(refObject),
|
|
648
|
-
attribute,
|
|
649
|
-
) != null ||
|
|
650
|
-
attribute in refObject
|
|
651
|
-
);
|
|
652
|
-
}
|
|
653
|
-
|
|
654
525
|
/**
|
|
655
526
|
* Returns the message that corresponds to errorNumber
|
|
656
527
|
* APIs that inherit BaseAPI should override this function
|
|
@@ -710,12 +581,12 @@ export default abstract class BaseAPI {
|
|
|
710
581
|
value: any,
|
|
711
582
|
): string {
|
|
712
583
|
if (!CMIElement || CMIElement === "") {
|
|
713
|
-
return
|
|
584
|
+
return APIConstants.global.SCORM_FALSE;
|
|
714
585
|
}
|
|
715
586
|
|
|
716
587
|
const structure = CMIElement.split(".");
|
|
717
588
|
let refObject: RefObject = this;
|
|
718
|
-
let returnValue =
|
|
589
|
+
let returnValue = APIConstants.global.SCORM_FALSE;
|
|
719
590
|
let foundFirstIndex = false;
|
|
720
591
|
|
|
721
592
|
const invalidErrorMessage = `The data model element passed to ${methodName} (${CMIElement}) is not a valid SCORM data model element.`;
|
|
@@ -727,25 +598,28 @@ export default abstract class BaseAPI {
|
|
|
727
598
|
const attribute = structure[idx];
|
|
728
599
|
|
|
729
600
|
if (idx === structure.length - 1) {
|
|
730
|
-
if (
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
601
|
+
if (scorm2004 && attribute.substring(0, 8) === "{target=") {
|
|
602
|
+
if (this.isInitialized()) {
|
|
603
|
+
this.throwSCORMError(this._error_codes.READ_ONLY_ELEMENT);
|
|
604
|
+
} else {
|
|
605
|
+
refObject = {
|
|
606
|
+
...refObject,
|
|
607
|
+
attribute: value,
|
|
608
|
+
};
|
|
609
|
+
}
|
|
736
610
|
} else if (!this._checkObjectHasProperty(refObject, attribute)) {
|
|
737
611
|
this.throwSCORMError(invalidErrorCode, invalidErrorMessage);
|
|
738
612
|
} else {
|
|
739
613
|
if (
|
|
740
|
-
|
|
741
|
-
this.
|
|
614
|
+
stringMatches(CMIElement, "\\.correct_responses\\.\\d+") &&
|
|
615
|
+
this.isInitialized()
|
|
742
616
|
) {
|
|
743
617
|
this.validateCorrectResponse(CMIElement, value);
|
|
744
618
|
}
|
|
745
619
|
|
|
746
620
|
if (!scorm2004 || this.lastErrorCode === "0") {
|
|
747
621
|
refObject[attribute] = value;
|
|
748
|
-
returnValue =
|
|
622
|
+
returnValue = APIConstants.global.SCORM_TRUE;
|
|
749
623
|
}
|
|
750
624
|
}
|
|
751
625
|
} else {
|
|
@@ -790,41 +664,17 @@ export default abstract class BaseAPI {
|
|
|
790
664
|
}
|
|
791
665
|
}
|
|
792
666
|
|
|
793
|
-
if (returnValue ===
|
|
667
|
+
if (returnValue === APIConstants.global.SCORM_FALSE) {
|
|
794
668
|
this.apiLog(
|
|
795
669
|
methodName,
|
|
796
670
|
`There was an error setting the value for: ${CMIElement}, value of: ${value}`,
|
|
797
|
-
|
|
671
|
+
APIConstants.global.LOG_LEVEL_WARNING,
|
|
798
672
|
);
|
|
799
673
|
}
|
|
800
674
|
|
|
801
675
|
return returnValue;
|
|
802
676
|
}
|
|
803
677
|
|
|
804
|
-
/**
|
|
805
|
-
* Abstract method for validating that a response is correct.
|
|
806
|
-
*
|
|
807
|
-
* @param {string} _CMIElement
|
|
808
|
-
* @param {any} _value
|
|
809
|
-
*/
|
|
810
|
-
abstract validateCorrectResponse(_CMIElement: string, _value: any): void;
|
|
811
|
-
|
|
812
|
-
/**
|
|
813
|
-
* Gets or builds a new child element to add to the array.
|
|
814
|
-
* APIs that inherit BaseAPI should override this method.
|
|
815
|
-
*
|
|
816
|
-
* @param {string} _CMIElement - unused
|
|
817
|
-
* @param {*} _value - unused
|
|
818
|
-
* @param {boolean} _foundFirstIndex - unused
|
|
819
|
-
* @return {BaseCMI|null}
|
|
820
|
-
* @abstract
|
|
821
|
-
*/
|
|
822
|
-
abstract getChildElement(
|
|
823
|
-
_CMIElement: string,
|
|
824
|
-
_value: any,
|
|
825
|
-
_foundFirstIndex: boolean,
|
|
826
|
-
): BaseCMI | null;
|
|
827
|
-
|
|
828
678
|
/**
|
|
829
679
|
* Gets a value from the CMI Object
|
|
830
680
|
*
|
|
@@ -910,9 +760,9 @@ export default abstract class BaseAPI {
|
|
|
910
760
|
if (refObject === null || refObject === undefined) {
|
|
911
761
|
if (!scorm2004) {
|
|
912
762
|
if (attribute === "_children") {
|
|
913
|
-
this.throwSCORMError(
|
|
763
|
+
this.throwSCORMError(ErrorCodes.scorm12.CHILDREN_ERROR);
|
|
914
764
|
} else if (attribute === "_count") {
|
|
915
|
-
this.throwSCORMError(
|
|
765
|
+
this.throwSCORMError(ErrorCodes.scorm12.COUNT_ERROR);
|
|
916
766
|
}
|
|
917
767
|
}
|
|
918
768
|
} else {
|
|
@@ -926,7 +776,7 @@ export default abstract class BaseAPI {
|
|
|
926
776
|
* @return {boolean}
|
|
927
777
|
*/
|
|
928
778
|
isInitialized(): boolean {
|
|
929
|
-
return this.currentState ===
|
|
779
|
+
return this.currentState === APIConstants.global.STATE_INITIALIZED;
|
|
930
780
|
}
|
|
931
781
|
|
|
932
782
|
/**
|
|
@@ -935,7 +785,7 @@ export default abstract class BaseAPI {
|
|
|
935
785
|
* @return {boolean}
|
|
936
786
|
*/
|
|
937
787
|
isNotInitialized(): boolean {
|
|
938
|
-
return this.currentState ===
|
|
788
|
+
return this.currentState === APIConstants.global.STATE_NOT_INITIALIZED;
|
|
939
789
|
}
|
|
940
790
|
|
|
941
791
|
/**
|
|
@@ -944,7 +794,7 @@ export default abstract class BaseAPI {
|
|
|
944
794
|
* @return {boolean}
|
|
945
795
|
*/
|
|
946
796
|
isTerminated(): boolean {
|
|
947
|
-
return this.currentState ===
|
|
797
|
+
return this.currentState === APIConstants.global.STATE_TERMINATED;
|
|
948
798
|
}
|
|
949
799
|
|
|
950
800
|
/**
|
|
@@ -977,7 +827,7 @@ export default abstract class BaseAPI {
|
|
|
977
827
|
this.apiLog(
|
|
978
828
|
"on",
|
|
979
829
|
`Added event listener: ${this.listenerArray.length}`,
|
|
980
|
-
|
|
830
|
+
APIConstants.global.LOG_LEVEL_INFO,
|
|
981
831
|
functionName,
|
|
982
832
|
);
|
|
983
833
|
}
|
|
@@ -1015,7 +865,7 @@ export default abstract class BaseAPI {
|
|
|
1015
865
|
this.apiLog(
|
|
1016
866
|
"off",
|
|
1017
867
|
`Removed event listener: ${this.listenerArray.length}`,
|
|
1018
|
-
|
|
868
|
+
APIConstants.global.LOG_LEVEL_INFO,
|
|
1019
869
|
functionName,
|
|
1020
870
|
);
|
|
1021
871
|
}
|
|
@@ -1058,7 +908,7 @@ export default abstract class BaseAPI {
|
|
|
1058
908
|
this.apiLog(
|
|
1059
909
|
functionName,
|
|
1060
910
|
value,
|
|
1061
|
-
|
|
911
|
+
APIConstants.global.LOG_LEVEL_INFO,
|
|
1062
912
|
CMIElement,
|
|
1063
913
|
);
|
|
1064
914
|
for (let i = 0; i < this.listenerArray.length; i++) {
|
|
@@ -1083,7 +933,7 @@ export default abstract class BaseAPI {
|
|
|
1083
933
|
this.apiLog(
|
|
1084
934
|
"processListeners",
|
|
1085
935
|
`Processing listener: ${listener.functionName}`,
|
|
1086
|
-
|
|
936
|
+
APIConstants.global.LOG_LEVEL_INFO,
|
|
1087
937
|
CMIElement,
|
|
1088
938
|
);
|
|
1089
939
|
listener.callback(CMIElement, value);
|
|
@@ -1105,7 +955,7 @@ export default abstract class BaseAPI {
|
|
|
1105
955
|
this.apiLog(
|
|
1106
956
|
"throwSCORMError",
|
|
1107
957
|
errorNumber + ": " + message,
|
|
1108
|
-
|
|
958
|
+
APIConstants.global.LOG_LEVEL_ERROR,
|
|
1109
959
|
);
|
|
1110
960
|
|
|
1111
961
|
this.lastErrorCode = String(errorNumber);
|
|
@@ -1117,27 +967,21 @@ export default abstract class BaseAPI {
|
|
|
1117
967
|
* @param {string} success
|
|
1118
968
|
*/
|
|
1119
969
|
clearSCORMError(success: string) {
|
|
1120
|
-
if (success !== undefined && success !==
|
|
970
|
+
if (success !== undefined && success !== APIConstants.global.SCORM_FALSE) {
|
|
1121
971
|
this.lastErrorCode = "0";
|
|
1122
972
|
}
|
|
1123
973
|
}
|
|
1124
974
|
|
|
1125
|
-
/**
|
|
1126
|
-
* Attempts to store the data to the LMS, logs data if no LMS configured
|
|
1127
|
-
* APIs that inherit BaseAPI should override this function
|
|
1128
|
-
*
|
|
1129
|
-
* @param {boolean} _calculateTotalTime
|
|
1130
|
-
* @return {ResultObject}
|
|
1131
|
-
* @abstract
|
|
1132
|
-
*/
|
|
1133
|
-
abstract storeData(_calculateTotalTime: boolean): ResultObject;
|
|
1134
|
-
|
|
1135
975
|
/**
|
|
1136
976
|
* Load the CMI from a flattened JSON object
|
|
1137
977
|
* @param {RefObject} json
|
|
1138
978
|
* @param {string} CMIElement
|
|
1139
979
|
*/
|
|
1140
|
-
loadFromFlattenedJSON(json: RefObject, CMIElement
|
|
980
|
+
loadFromFlattenedJSON(json: RefObject, CMIElement?: string) {
|
|
981
|
+
if (!CMIElement) {
|
|
982
|
+
// by default, we start from a blank string because we're expecting each element to start with `cmi`
|
|
983
|
+
CMIElement = "";
|
|
984
|
+
}
|
|
1141
985
|
if (!this.isNotInitialized()) {
|
|
1142
986
|
console.error(
|
|
1143
987
|
"loadFromFlattenedJSON can only be called before the call to lmsInitialize.",
|
|
@@ -1146,12 +990,12 @@ export default abstract class BaseAPI {
|
|
|
1146
990
|
}
|
|
1147
991
|
|
|
1148
992
|
/**
|
|
1149
|
-
*
|
|
993
|
+
* Tests two strings against a given regular expression pattern and determines a numeric or null result based on the matching criterion.
|
|
1150
994
|
*
|
|
1151
|
-
* @param {string} a
|
|
1152
|
-
* @param {string} c
|
|
1153
|
-
* @param {RegExp} a_pattern
|
|
1154
|
-
* @return {number}
|
|
995
|
+
* @param {string} a - The first string to be tested against the pattern.
|
|
996
|
+
* @param {string} c - The second string to be tested against the pattern.
|
|
997
|
+
* @param {RegExp} a_pattern - The regular expression pattern to test the strings against.
|
|
998
|
+
* @return {number | null} A numeric result based on the matching criterion, or null if the strings do not match the pattern.
|
|
1155
999
|
*/
|
|
1156
1000
|
function testPattern(
|
|
1157
1001
|
a: string,
|
|
@@ -1265,8 +1109,10 @@ export default abstract class BaseAPI {
|
|
|
1265
1109
|
renderCMIToJSONString(): string {
|
|
1266
1110
|
const cmi = this.cmi;
|
|
1267
1111
|
// Do we want/need to return fields that have no set value?
|
|
1268
|
-
|
|
1269
|
-
|
|
1112
|
+
if (this.settings.sendFullCommit) {
|
|
1113
|
+
return JSON.stringify({ cmi });
|
|
1114
|
+
}
|
|
1115
|
+
return JSON.stringify({ cmi }, (k, v) => (v === undefined ? null : v), 2);
|
|
1270
1116
|
}
|
|
1271
1117
|
|
|
1272
1118
|
/**
|
|
@@ -1274,89 +1120,71 @@ export default abstract class BaseAPI {
|
|
|
1274
1120
|
* @return {object}
|
|
1275
1121
|
*/
|
|
1276
1122
|
renderCMIToJSONObject(): object {
|
|
1277
|
-
// Do we want/need to return fields that have no set value?
|
|
1278
|
-
// return JSON.stringify({ cmi }, (k, v) => v === undefined ? null : v, 2);
|
|
1279
1123
|
return JSON.parse(this.renderCMIToJSONString());
|
|
1280
1124
|
}
|
|
1281
1125
|
|
|
1282
|
-
/**
|
|
1283
|
-
* Render the cmi object to the proper format for LMS commit
|
|
1284
|
-
* APIs that inherit BaseAPI should override this function
|
|
1285
|
-
*
|
|
1286
|
-
* @param {boolean} _terminateCommit
|
|
1287
|
-
* @return {RefObject|Array}
|
|
1288
|
-
* @abstract
|
|
1289
|
-
*/
|
|
1290
|
-
abstract renderCommitCMI(_terminateCommit: boolean): RefObject | Array<any>;
|
|
1291
|
-
|
|
1292
1126
|
/**
|
|
1293
1127
|
* Send the request to the LMS
|
|
1294
1128
|
* @param {string} url
|
|
1295
|
-
* @param {RefObject|Array} params
|
|
1129
|
+
* @param {CommitObject|RefObject|Array} params
|
|
1296
1130
|
* @param {boolean} immediate
|
|
1297
1131
|
* @return {ResultObject}
|
|
1298
1132
|
*/
|
|
1299
|
-
processHttpRequest(
|
|
1133
|
+
async processHttpRequest(
|
|
1300
1134
|
url: string,
|
|
1301
|
-
params: RefObject | Array<any>,
|
|
1135
|
+
params: CommitObject | RefObject | Array<any>,
|
|
1302
1136
|
immediate: boolean = false,
|
|
1303
|
-
): ResultObject {
|
|
1137
|
+
): Promise<ResultObject> {
|
|
1304
1138
|
const api = this;
|
|
1305
1139
|
const genericError: ResultObject = {
|
|
1306
|
-
result:
|
|
1140
|
+
result: APIConstants.global.SCORM_FALSE,
|
|
1307
1141
|
errorCode: this.error_codes.GENERAL,
|
|
1308
1142
|
};
|
|
1309
1143
|
|
|
1144
|
+
// if we are terminating the module or closing the browser window/tab, we need to make this fetch ASAP.
|
|
1145
|
+
// Some browsers, especially Chrome, do not like synchronous requests to be made when the window is closing.
|
|
1146
|
+
if (immediate) {
|
|
1147
|
+
this.performFetch(url, params).then(async (response) => {
|
|
1148
|
+
await this.transformResponse(response);
|
|
1149
|
+
});
|
|
1150
|
+
return {
|
|
1151
|
+
result: APIConstants.global.SCORM_TRUE,
|
|
1152
|
+
errorCode: 0,
|
|
1153
|
+
};
|
|
1154
|
+
}
|
|
1155
|
+
|
|
1310
1156
|
const process = async (
|
|
1311
1157
|
url: string,
|
|
1312
|
-
params: RefObject | Array<any>,
|
|
1158
|
+
params: CommitObject | RefObject | Array<any>,
|
|
1313
1159
|
settings: Settings,
|
|
1314
1160
|
): Promise<ResultObject> => {
|
|
1315
1161
|
try {
|
|
1316
1162
|
params = settings.requestHandler(params);
|
|
1317
|
-
const response = await
|
|
1318
|
-
method: "POST",
|
|
1319
|
-
body:
|
|
1320
|
-
params instanceof Array ? params.join("&") : JSON.stringify(params),
|
|
1321
|
-
headers: {
|
|
1322
|
-
...settings.xhrHeaders,
|
|
1323
|
-
"Content-Type": settings.commitRequestDataType,
|
|
1324
|
-
},
|
|
1325
|
-
credentials: settings.xhrWithCredentials ? "include" : undefined,
|
|
1326
|
-
keepalive: true,
|
|
1327
|
-
});
|
|
1328
|
-
|
|
1329
|
-
const result =
|
|
1330
|
-
typeof settings.responseHandler === "function"
|
|
1331
|
-
? await settings.responseHandler(response)
|
|
1332
|
-
: await response.json();
|
|
1163
|
+
const response = await this.performFetch(url, params);
|
|
1333
1164
|
|
|
1334
|
-
|
|
1335
|
-
response.status >= 200 &&
|
|
1336
|
-
response.status <= 299 &&
|
|
1337
|
-
(result.result === true ||
|
|
1338
|
-
result.result === global_constants.SCORM_TRUE)
|
|
1339
|
-
) {
|
|
1340
|
-
api.processListeners("CommitSuccess");
|
|
1341
|
-
} else {
|
|
1342
|
-
api.processListeners("CommitError");
|
|
1343
|
-
}
|
|
1344
|
-
|
|
1345
|
-
return result;
|
|
1165
|
+
return this.transformResponse(response);
|
|
1346
1166
|
} catch (e) {
|
|
1347
|
-
this.apiLog(
|
|
1167
|
+
this.apiLog(
|
|
1168
|
+
"processHttpRequest",
|
|
1169
|
+
e,
|
|
1170
|
+
APIConstants.global.LOG_LEVEL_ERROR,
|
|
1171
|
+
);
|
|
1348
1172
|
api.processListeners("CommitError");
|
|
1349
1173
|
return genericError;
|
|
1350
1174
|
}
|
|
1351
1175
|
};
|
|
1352
1176
|
|
|
1353
|
-
|
|
1354
|
-
|
|
1177
|
+
if (this.settings.asyncCommit) {
|
|
1178
|
+
const debouncedProcess = debounce(process, 500, immediate);
|
|
1179
|
+
debouncedProcess(url, params, this.settings);
|
|
1355
1180
|
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1181
|
+
return {
|
|
1182
|
+
result: APIConstants.global.SCORM_TRUE,
|
|
1183
|
+
errorCode: 0,
|
|
1184
|
+
};
|
|
1185
|
+
} else {
|
|
1186
|
+
return await process(url, params, this.settings);
|
|
1187
|
+
}
|
|
1360
1188
|
}
|
|
1361
1189
|
|
|
1362
1190
|
/**
|
|
@@ -1370,7 +1198,7 @@ export default abstract class BaseAPI {
|
|
|
1370
1198
|
this.apiLog(
|
|
1371
1199
|
"scheduleCommit",
|
|
1372
1200
|
"scheduled",
|
|
1373
|
-
|
|
1201
|
+
APIConstants.global.LOG_LEVEL_DEBUG,
|
|
1374
1202
|
"",
|
|
1375
1203
|
);
|
|
1376
1204
|
}
|
|
@@ -1385,16 +1213,44 @@ export default abstract class BaseAPI {
|
|
|
1385
1213
|
this.apiLog(
|
|
1386
1214
|
"clearScheduledCommit",
|
|
1387
1215
|
"cleared",
|
|
1388
|
-
|
|
1216
|
+
APIConstants.global.LOG_LEVEL_DEBUG,
|
|
1389
1217
|
"",
|
|
1390
1218
|
);
|
|
1391
1219
|
}
|
|
1392
1220
|
}
|
|
1393
1221
|
|
|
1394
|
-
|
|
1222
|
+
/**
|
|
1223
|
+
* Check to see if the specific object has the given property
|
|
1224
|
+
* @param {RefObject} refObject
|
|
1225
|
+
* @param {string} attribute
|
|
1226
|
+
* @return {boolean}
|
|
1227
|
+
* @private
|
|
1228
|
+
*/
|
|
1229
|
+
private _checkObjectHasProperty(
|
|
1230
|
+
refObject: RefObject,
|
|
1231
|
+
attribute: string,
|
|
1232
|
+
): boolean {
|
|
1233
|
+
return (
|
|
1234
|
+
Object.hasOwnProperty.call(refObject, attribute) ||
|
|
1235
|
+
Object.getOwnPropertyDescriptor(
|
|
1236
|
+
Object.getPrototypeOf(refObject),
|
|
1237
|
+
attribute,
|
|
1238
|
+
) != null ||
|
|
1239
|
+
attribute in refObject
|
|
1240
|
+
);
|
|
1241
|
+
}
|
|
1242
|
+
|
|
1243
|
+
/**
|
|
1244
|
+
* Handles the error that occurs when trying to access a value
|
|
1245
|
+
* @param {any} e
|
|
1246
|
+
* @param {string} returnValue
|
|
1247
|
+
* @return {string}
|
|
1248
|
+
* @private
|
|
1249
|
+
*/
|
|
1250
|
+
private handleValueAccessException(e: any, returnValue: string): string {
|
|
1395
1251
|
if (e instanceof ValidationError) {
|
|
1396
1252
|
this.lastErrorCode = String(e.errorCode);
|
|
1397
|
-
returnValue =
|
|
1253
|
+
returnValue = APIConstants.global.SCORM_FALSE;
|
|
1398
1254
|
} else {
|
|
1399
1255
|
if (e instanceof Error && e.message) {
|
|
1400
1256
|
console.error(e.message);
|
|
@@ -1405,45 +1261,52 @@ export default abstract class BaseAPI {
|
|
|
1405
1261
|
}
|
|
1406
1262
|
return returnValue;
|
|
1407
1263
|
}
|
|
1408
|
-
}
|
|
1409
|
-
|
|
1410
|
-
/**
|
|
1411
|
-
* Private class that wraps a timeout call to the commit() function
|
|
1412
|
-
*/
|
|
1413
|
-
class ScheduledCommit {
|
|
1414
|
-
private _API;
|
|
1415
|
-
private _cancelled = false;
|
|
1416
|
-
private readonly _timeout;
|
|
1417
|
-
private readonly _callback;
|
|
1418
1264
|
|
|
1419
1265
|
/**
|
|
1420
|
-
*
|
|
1421
|
-
* @param {
|
|
1422
|
-
* @param {
|
|
1423
|
-
* @
|
|
1266
|
+
* Perform the fetch request to the LMS
|
|
1267
|
+
* @param {string} url
|
|
1268
|
+
* @param {RefObject|Array} params
|
|
1269
|
+
* @return {Promise<Response>}
|
|
1270
|
+
* @private
|
|
1424
1271
|
*/
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1272
|
+
private async performFetch(
|
|
1273
|
+
url: string,
|
|
1274
|
+
params: RefObject | Array<any>,
|
|
1275
|
+
): Promise<Response> {
|
|
1276
|
+
return fetch(url, {
|
|
1277
|
+
method: "POST",
|
|
1278
|
+
body: params instanceof Array ? params.join("&") : JSON.stringify(params),
|
|
1279
|
+
headers: {
|
|
1280
|
+
...this.settings.xhrHeaders,
|
|
1281
|
+
"Content-Type": this.settings.commitRequestDataType,
|
|
1282
|
+
},
|
|
1283
|
+
credentials: this.settings.xhrWithCredentials ? "include" : undefined,
|
|
1284
|
+
keepalive: true,
|
|
1285
|
+
});
|
|
1429
1286
|
}
|
|
1430
1287
|
|
|
1431
1288
|
/**
|
|
1432
|
-
*
|
|
1289
|
+
* Transforms the response from the LMS to a ResultObject
|
|
1290
|
+
* @param {Response} response
|
|
1291
|
+
* @return {Promise<ResultObject>}
|
|
1292
|
+
* @private
|
|
1433
1293
|
*/
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
}
|
|
1294
|
+
private async transformResponse(response: Response): Promise<ResultObject> {
|
|
1295
|
+
const result =
|
|
1296
|
+
typeof this.settings.responseHandler === "function"
|
|
1297
|
+
? await this.settings.responseHandler(response)
|
|
1298
|
+
: await response.json();
|
|
1440
1299
|
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1300
|
+
if (
|
|
1301
|
+
response.status >= 200 &&
|
|
1302
|
+
response.status <= 299 &&
|
|
1303
|
+
(result.result === true ||
|
|
1304
|
+
result.result === APIConstants.global.SCORM_TRUE)
|
|
1305
|
+
) {
|
|
1306
|
+
this.processListeners("CommitSuccess");
|
|
1307
|
+
} else {
|
|
1308
|
+
this.processListeners("CommitError");
|
|
1447
1309
|
}
|
|
1310
|
+
return result;
|
|
1448
1311
|
}
|
|
1449
1312
|
}
|