scorm-again 1.7.0 → 2.0.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/.babelrc +18 -7
- package/.github/dependabot.yml +5 -0
- package/.github/workflows/main.yml +79 -0
- package/.jsdoc.json +4 -5
- package/.mocharc.json +8 -0
- package/.run/Mocha Unit Tests.run.xml +5 -2
- package/CONTRIBUTING.md +1 -1
- package/README.md +14 -1
- package/dist/aicc.js +3661 -7170
- package/dist/aicc.js.map +1 -1
- package/dist/aicc.min.js +2 -40
- package/dist/aicc.min.js.map +1 -0
- package/dist/scorm-again.js +5671 -10695
- package/dist/scorm-again.js.map +1 -1
- package/dist/scorm-again.min.js +2 -52
- package/dist/scorm-again.min.js.map +1 -0
- package/dist/scorm12.js +2871 -5433
- package/dist/scorm12.js.map +1 -1
- package/dist/scorm12.min.js +2 -34
- package/dist/scorm12.min.js.map +1 -0
- package/dist/scorm2004.js +3868 -6797
- package/dist/scorm2004.js.map +1 -1
- package/dist/scorm2004.min.js +2 -40
- package/dist/scorm2004.min.js.map +1 -0
- package/eslint.config.js +21 -0
- package/package.json +73 -35
- package/results.json +34254 -0
- package/src/{AICC.js → AICC.ts} +27 -21
- package/src/BaseAPI.ts +1449 -0
- package/src/Scorm12API.ts +360 -0
- package/src/{Scorm2004API.js → Scorm2004API.ts} +245 -163
- package/src/cmi/aicc_cmi.ts +1248 -0
- package/src/cmi/common.ts +411 -0
- package/src/cmi/scorm12_cmi.ts +1426 -0
- package/src/cmi/scorm2004_cmi.ts +1874 -0
- package/src/constants/api_constants.ts +318 -0
- package/src/constants/error_codes.ts +88 -0
- package/src/constants/language_constants.ts +394 -0
- package/src/constants/regex.ts +97 -0
- package/src/constants/{response_constants.js → response_constants.ts} +67 -62
- package/src/exceptions.ts +133 -0
- package/src/exports/aicc.js +1 -1
- package/src/exports/scorm-again.js +3 -3
- package/src/exports/scorm12.js +1 -1
- package/src/exports/scorm2004.js +1 -1
- package/src/{utilities.js → utilities.ts} +114 -74
- package/tea.yaml +6 -0
- package/test/{AICC.spec.js → AICC.spec.ts} +70 -72
- package/test/Scorm12API.spec.ts +580 -0
- package/test/Scorm2004API.spec.ts +812 -0
- package/test/api_helpers.ts +176 -0
- package/test/cmi/{aicc_cmi.spec.js → aicc_cmi.spec.ts} +193 -209
- package/test/cmi/{scorm12_cmi.spec.js → scorm12_cmi.spec.ts} +251 -269
- package/test/cmi/scorm2004_cmi.spec.ts +1031 -0
- package/test/cmi_helpers.ts +207 -0
- package/test/exceptions.spec.ts +79 -0
- package/test/field_values.ts +202 -0
- package/test/utilities.spec.ts +322 -0
- package/tsconfig.json +18 -0
- package/webpack.config.js +65 -0
- package/.circleci/config.yml +0 -99
- package/.codeclimate.yml +0 -7
- package/.eslintrc.js +0 -36
- package/src/.flowconfig +0 -11
- package/src/BaseAPI.js +0 -1275
- package/src/Scorm12API.js +0 -308
- package/src/cmi/aicc_cmi.js +0 -1141
- package/src/cmi/common.js +0 -328
- package/src/cmi/scorm12_cmi.js +0 -1312
- package/src/cmi/scorm2004_cmi.js +0 -1692
- package/src/constants/api_constants.js +0 -218
- package/src/constants/error_codes.js +0 -87
- package/src/constants/language_constants.js +0 -76
- package/src/constants/regex.js +0 -84
- package/src/exceptions.js +0 -104
- package/test/Scorm12API.spec.js +0 -528
- package/test/Scorm2004API.spec.js +0 -775
- package/test/abstract_classes.spec.js +0 -17
- package/test/api_helpers.js +0 -128
- package/test/cmi/scorm2004_cmi.spec.js +0 -1066
- package/test/cmi_helpers.js +0 -161
- package/test/exceptions.spec.js +0 -71
- package/test/field_values.js +0 -353
- package/test/utilities.spec.js +0 -339
- package/webpack.js +0 -78
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
import BaseAPI from './BaseAPI';
|
|
1
|
+
import BaseAPI, { RefObject, ResultObject, Settings } from "./BaseAPI";
|
|
3
2
|
import {
|
|
4
3
|
ADL,
|
|
5
4
|
CMI,
|
|
@@ -8,45 +7,46 @@ import {
|
|
|
8
7
|
CMIInteractionsObject,
|
|
9
8
|
CMIInteractionsObjectivesObject,
|
|
10
9
|
CMIObjectivesObject,
|
|
11
|
-
} from
|
|
12
|
-
import * as Utilities from
|
|
13
|
-
import APIConstants from
|
|
14
|
-
import ErrorCodes from
|
|
15
|
-
import
|
|
16
|
-
import ValidLanguages from
|
|
17
|
-
import Regex from
|
|
10
|
+
} from "./cmi/scorm2004_cmi";
|
|
11
|
+
import * as Utilities from "./utilities";
|
|
12
|
+
import APIConstants from "./constants/api_constants";
|
|
13
|
+
import ErrorCodes from "./constants/error_codes";
|
|
14
|
+
import { CorrectResponses, ResponseType } from "./constants/response_constants";
|
|
15
|
+
import ValidLanguages from "./constants/language_constants";
|
|
16
|
+
import Regex from "./constants/regex";
|
|
17
|
+
import { BaseCMI, CMIArray } from "./cmi/common";
|
|
18
18
|
|
|
19
19
|
const scorm2004_constants = APIConstants.scorm2004;
|
|
20
20
|
const global_constants = APIConstants.global;
|
|
21
21
|
const scorm2004_error_codes = ErrorCodes.scorm2004;
|
|
22
|
-
const correct_responses =
|
|
22
|
+
const correct_responses = CorrectResponses;
|
|
23
23
|
const scorm2004_regex = Regex.scorm2004;
|
|
24
24
|
|
|
25
25
|
/**
|
|
26
26
|
* API class for SCORM 2004
|
|
27
27
|
*/
|
|
28
28
|
export default class Scorm2004API extends BaseAPI {
|
|
29
|
-
|
|
29
|
+
private _version: string = "1.0";
|
|
30
30
|
|
|
31
31
|
/**
|
|
32
32
|
* Constructor for SCORM 2004 API
|
|
33
|
-
* @param {
|
|
33
|
+
* @param {Settings} settings
|
|
34
34
|
*/
|
|
35
|
-
constructor(settings
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
mastery_override
|
|
39
|
-
}
|
|
40
|
-
}
|
|
35
|
+
constructor(settings?: Settings) {
|
|
36
|
+
if (settings) {
|
|
37
|
+
if (settings.mastery_override === undefined) {
|
|
38
|
+
settings.mastery_override = false;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
41
|
|
|
42
|
-
super(scorm2004_error_codes,
|
|
42
|
+
super(scorm2004_error_codes, settings);
|
|
43
43
|
|
|
44
44
|
this.cmi = new CMI();
|
|
45
45
|
this.adl = new ADL();
|
|
46
46
|
|
|
47
47
|
// Rename functions to match 2004 Spec and expose to modules
|
|
48
48
|
this.Initialize = this.lmsInitialize;
|
|
49
|
-
this.Terminate = this.
|
|
49
|
+
this.Terminate = this.lmsFinish;
|
|
50
50
|
this.GetValue = this.lmsGetValue;
|
|
51
51
|
this.SetValue = this.lmsSetValue;
|
|
52
52
|
this.Commit = this.lmsCommit;
|
|
@@ -55,55 +55,67 @@ export default class Scorm2004API extends BaseAPI {
|
|
|
55
55
|
this.GetDiagnostic = this.lmsGetDiagnostic;
|
|
56
56
|
}
|
|
57
57
|
|
|
58
|
+
public cmi: CMI;
|
|
59
|
+
public adl: ADL;
|
|
60
|
+
|
|
61
|
+
public Initialize: () => string;
|
|
62
|
+
public Terminate: () => string;
|
|
63
|
+
public GetValue: (CMIElement: string) => string;
|
|
64
|
+
public SetValue: (CMIElement: string, value: any) => string;
|
|
65
|
+
public Commit: () => string;
|
|
66
|
+
public GetLastError: () => string;
|
|
67
|
+
public GetErrorString: (CMIErrorCode: string | number) => string;
|
|
68
|
+
public GetDiagnostic: (CMIErrorCode: string | number) => string;
|
|
69
|
+
|
|
58
70
|
/**
|
|
59
|
-
* Getter for
|
|
71
|
+
* Getter for _version
|
|
60
72
|
* @return {string}
|
|
61
73
|
*/
|
|
62
|
-
get version() {
|
|
63
|
-
return this
|
|
74
|
+
get version(): string {
|
|
75
|
+
return this._version;
|
|
64
76
|
}
|
|
65
77
|
|
|
66
78
|
/**
|
|
67
79
|
* @return {string} bool
|
|
68
80
|
*/
|
|
69
|
-
lmsInitialize() {
|
|
81
|
+
lmsInitialize(): string {
|
|
70
82
|
this.cmi.initialize();
|
|
71
|
-
return this.initialize(
|
|
83
|
+
return this.initialize("Initialize");
|
|
72
84
|
}
|
|
73
85
|
|
|
74
86
|
/**
|
|
75
87
|
* @return {string} bool
|
|
76
88
|
*/
|
|
77
|
-
|
|
78
|
-
const result = this.terminate(
|
|
89
|
+
lmsFinish(): string {
|
|
90
|
+
const result = this.terminate("Terminate", true);
|
|
79
91
|
|
|
80
92
|
if (result === global_constants.SCORM_TRUE) {
|
|
81
|
-
if (this.adl.nav.request !==
|
|
93
|
+
if (this.adl.nav.request !== "_none_") {
|
|
82
94
|
switch (this.adl.nav.request) {
|
|
83
|
-
case
|
|
84
|
-
this.processListeners(
|
|
95
|
+
case "continue":
|
|
96
|
+
this.processListeners("SequenceNext");
|
|
85
97
|
break;
|
|
86
|
-
case
|
|
87
|
-
this.processListeners(
|
|
98
|
+
case "previous":
|
|
99
|
+
this.processListeners("SequencePrevious");
|
|
88
100
|
break;
|
|
89
|
-
case
|
|
90
|
-
this.processListeners(
|
|
101
|
+
case "choice":
|
|
102
|
+
this.processListeners("SequenceChoice");
|
|
91
103
|
break;
|
|
92
|
-
case
|
|
93
|
-
this.processListeners(
|
|
104
|
+
case "exit":
|
|
105
|
+
this.processListeners("SequenceExit");
|
|
94
106
|
break;
|
|
95
|
-
case
|
|
96
|
-
this.processListeners(
|
|
107
|
+
case "exitAll":
|
|
108
|
+
this.processListeners("SequenceExitAll");
|
|
97
109
|
break;
|
|
98
|
-
case
|
|
99
|
-
this.processListeners(
|
|
110
|
+
case "abandon":
|
|
111
|
+
this.processListeners("SequenceAbandon");
|
|
100
112
|
break;
|
|
101
|
-
case
|
|
102
|
-
this.processListeners(
|
|
113
|
+
case "abandonAll":
|
|
114
|
+
this.processListeners("SequenceAbandonAll");
|
|
103
115
|
break;
|
|
104
116
|
}
|
|
105
117
|
} else if (this.settings.autoProgress) {
|
|
106
|
-
this.processListeners(
|
|
118
|
+
this.processListeners("SequenceNext");
|
|
107
119
|
}
|
|
108
120
|
}
|
|
109
121
|
|
|
@@ -114,8 +126,8 @@ export default class Scorm2004API extends BaseAPI {
|
|
|
114
126
|
* @param {string} CMIElement
|
|
115
127
|
* @return {string}
|
|
116
128
|
*/
|
|
117
|
-
lmsGetValue(CMIElement) {
|
|
118
|
-
return this.getValue(
|
|
129
|
+
lmsGetValue(CMIElement: string): string {
|
|
130
|
+
return this.getValue("GetValue", true, CMIElement);
|
|
119
131
|
}
|
|
120
132
|
|
|
121
133
|
/**
|
|
@@ -123,8 +135,8 @@ export default class Scorm2004API extends BaseAPI {
|
|
|
123
135
|
* @param {any} value
|
|
124
136
|
* @return {string}
|
|
125
137
|
*/
|
|
126
|
-
lmsSetValue(CMIElement, value) {
|
|
127
|
-
return this.setValue(
|
|
138
|
+
lmsSetValue(CMIElement: string, value: any): string {
|
|
139
|
+
return this.setValue("SetValue", "Commit", true, CMIElement, value);
|
|
128
140
|
}
|
|
129
141
|
|
|
130
142
|
/**
|
|
@@ -132,8 +144,8 @@ export default class Scorm2004API extends BaseAPI {
|
|
|
132
144
|
*
|
|
133
145
|
* @return {string} bool
|
|
134
146
|
*/
|
|
135
|
-
lmsCommit() {
|
|
136
|
-
return this.commit(
|
|
147
|
+
lmsCommit(): string {
|
|
148
|
+
return this.commit("Commit");
|
|
137
149
|
}
|
|
138
150
|
|
|
139
151
|
/**
|
|
@@ -141,8 +153,8 @@ export default class Scorm2004API extends BaseAPI {
|
|
|
141
153
|
*
|
|
142
154
|
* @return {string}
|
|
143
155
|
*/
|
|
144
|
-
lmsGetLastError() {
|
|
145
|
-
return this.getLastError(
|
|
156
|
+
lmsGetLastError(): string {
|
|
157
|
+
return this.getLastError("GetLastError");
|
|
146
158
|
}
|
|
147
159
|
|
|
148
160
|
/**
|
|
@@ -151,8 +163,8 @@ export default class Scorm2004API extends BaseAPI {
|
|
|
151
163
|
* @param {(string|number)} CMIErrorCode
|
|
152
164
|
* @return {string}
|
|
153
165
|
*/
|
|
154
|
-
lmsGetErrorString(CMIErrorCode) {
|
|
155
|
-
return this.getErrorString(
|
|
166
|
+
lmsGetErrorString(CMIErrorCode: string | number): string {
|
|
167
|
+
return this.getErrorString("GetErrorString", CMIErrorCode);
|
|
156
168
|
}
|
|
157
169
|
|
|
158
170
|
/**
|
|
@@ -161,8 +173,8 @@ export default class Scorm2004API extends BaseAPI {
|
|
|
161
173
|
* @param {(string|number)} CMIErrorCode
|
|
162
174
|
* @return {string}
|
|
163
175
|
*/
|
|
164
|
-
lmsGetDiagnostic(CMIErrorCode) {
|
|
165
|
-
return this.getDiagnostic(
|
|
176
|
+
lmsGetDiagnostic(CMIErrorCode: string | number): string {
|
|
177
|
+
return this.getDiagnostic("GetDiagnostic", CMIErrorCode);
|
|
166
178
|
}
|
|
167
179
|
|
|
168
180
|
/**
|
|
@@ -172,8 +184,8 @@ export default class Scorm2004API extends BaseAPI {
|
|
|
172
184
|
* @param {any} value
|
|
173
185
|
* @return {string}
|
|
174
186
|
*/
|
|
175
|
-
setCMIValue(CMIElement, value) {
|
|
176
|
-
return this._commonSetCMIValue(
|
|
187
|
+
setCMIValue(CMIElement: string, value: any): string {
|
|
188
|
+
return this._commonSetCMIValue("SetValue", true, CMIElement, value);
|
|
177
189
|
}
|
|
178
190
|
|
|
179
191
|
/**
|
|
@@ -182,22 +194,30 @@ export default class Scorm2004API extends BaseAPI {
|
|
|
182
194
|
* @param {string} CMIElement
|
|
183
195
|
* @param {any} value
|
|
184
196
|
* @param {boolean} foundFirstIndex
|
|
185
|
-
* @return {
|
|
197
|
+
* @return {BaseCMI|null}
|
|
186
198
|
*/
|
|
187
|
-
getChildElement(
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
199
|
+
getChildElement(
|
|
200
|
+
CMIElement: string,
|
|
201
|
+
value: any,
|
|
202
|
+
foundFirstIndex: boolean,
|
|
203
|
+
): BaseCMI | null {
|
|
204
|
+
if (this.stringMatches(CMIElement, "cmi\\.objectives\\.\\d+")) {
|
|
205
|
+
return new CMIObjectivesObject();
|
|
206
|
+
} else if (
|
|
207
|
+
foundFirstIndex &&
|
|
208
|
+
this.stringMatches(
|
|
209
|
+
CMIElement,
|
|
210
|
+
"cmi\\.interactions\\.\\d+\\.correct_responses\\.\\d+",
|
|
211
|
+
)
|
|
212
|
+
) {
|
|
213
|
+
const parts = CMIElement.split(".");
|
|
195
214
|
const index = Number(parts[2]);
|
|
196
215
|
const interaction = this.cmi.interactions.childArray[index];
|
|
197
216
|
if (this.isInitialized()) {
|
|
198
217
|
if (!interaction.type) {
|
|
199
218
|
this.throwSCORMError(
|
|
200
|
-
|
|
219
|
+
scorm2004_error_codes.DEPENDENCY_NOT_ESTABLISHED,
|
|
220
|
+
);
|
|
201
221
|
} else {
|
|
202
222
|
this.checkDuplicateChoiceResponse(interaction, value);
|
|
203
223
|
|
|
@@ -205,29 +225,40 @@ export default class Scorm2004API extends BaseAPI {
|
|
|
205
225
|
if (response_type) {
|
|
206
226
|
this.checkValidResponseType(response_type, value, interaction.type);
|
|
207
227
|
} else {
|
|
208
|
-
this.throwSCORMError(
|
|
209
|
-
|
|
228
|
+
this.throwSCORMError(
|
|
229
|
+
scorm2004_error_codes.GENERAL_SET_FAILURE,
|
|
230
|
+
"Incorrect Response Type: " + interaction.type,
|
|
231
|
+
);
|
|
210
232
|
}
|
|
211
233
|
}
|
|
212
234
|
}
|
|
213
|
-
if (this.lastErrorCode === 0) {
|
|
214
|
-
|
|
235
|
+
if (this.lastErrorCode === "0") {
|
|
236
|
+
return new CMIInteractionsCorrectResponsesObject();
|
|
215
237
|
}
|
|
216
|
-
} else if (
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
238
|
+
} else if (
|
|
239
|
+
foundFirstIndex &&
|
|
240
|
+
this.stringMatches(
|
|
241
|
+
CMIElement,
|
|
242
|
+
"cmi\\.interactions\\.\\d+\\.objectives\\.\\d+",
|
|
243
|
+
)
|
|
244
|
+
) {
|
|
245
|
+
return new CMIInteractionsObjectivesObject();
|
|
246
|
+
} else if (
|
|
247
|
+
!foundFirstIndex &&
|
|
248
|
+
this.stringMatches(CMIElement, "cmi\\.interactions\\.\\d+")
|
|
249
|
+
) {
|
|
250
|
+
return new CMIInteractionsObject();
|
|
251
|
+
} else if (
|
|
252
|
+
this.stringMatches(CMIElement, "cmi\\.comments_from_learner\\.\\d+")
|
|
253
|
+
) {
|
|
254
|
+
return new CMICommentsObject();
|
|
255
|
+
} else if (
|
|
256
|
+
this.stringMatches(CMIElement, "cmi\\.comments_from_lms\\.\\d+")
|
|
257
|
+
) {
|
|
258
|
+
return new CMICommentsObject(true);
|
|
228
259
|
}
|
|
229
260
|
|
|
230
|
-
return
|
|
261
|
+
return null;
|
|
231
262
|
}
|
|
232
263
|
|
|
233
264
|
/**
|
|
@@ -236,7 +267,11 @@ export default class Scorm2004API extends BaseAPI {
|
|
|
236
267
|
* @param {any} value
|
|
237
268
|
* @param {string} interaction_type
|
|
238
269
|
*/
|
|
239
|
-
checkValidResponseType(
|
|
270
|
+
checkValidResponseType(
|
|
271
|
+
response_type: ResponseType,
|
|
272
|
+
value: any,
|
|
273
|
+
interaction_type: string,
|
|
274
|
+
) {
|
|
240
275
|
let nodes = [];
|
|
241
276
|
if (response_type?.delimiter) {
|
|
242
277
|
nodes = String(value).split(response_type.delimiter);
|
|
@@ -247,8 +282,10 @@ export default class Scorm2004API extends BaseAPI {
|
|
|
247
282
|
if (nodes.length > 0 && nodes.length <= response_type.max) {
|
|
248
283
|
this.checkCorrectResponseValue(interaction_type, nodes, value);
|
|
249
284
|
} else if (nodes.length > response_type.max) {
|
|
250
|
-
this.throwSCORMError(
|
|
251
|
-
|
|
285
|
+
this.throwSCORMError(
|
|
286
|
+
scorm2004_error_codes.GENERAL_SET_FAILURE,
|
|
287
|
+
"Data Model Element Pattern Too Long",
|
|
288
|
+
);
|
|
252
289
|
}
|
|
253
290
|
}
|
|
254
291
|
|
|
@@ -257,11 +294,14 @@ export default class Scorm2004API extends BaseAPI {
|
|
|
257
294
|
* @param {CMIInteractionsObject} interaction
|
|
258
295
|
* @param {any} value
|
|
259
296
|
*/
|
|
260
|
-
checkDuplicateChoiceResponse(interaction, value) {
|
|
297
|
+
checkDuplicateChoiceResponse(interaction: CMIInteractionsObject, value: any) {
|
|
261
298
|
const interaction_count = interaction.correct_responses._count;
|
|
262
|
-
if (interaction.type ===
|
|
263
|
-
for (
|
|
264
|
-
|
|
299
|
+
if (interaction.type === "choice") {
|
|
300
|
+
for (
|
|
301
|
+
let i = 0;
|
|
302
|
+
i < interaction_count && this.lastErrorCode === "0";
|
|
303
|
+
i++
|
|
304
|
+
) {
|
|
265
305
|
const response = interaction.correct_responses.childArray[i];
|
|
266
306
|
if (response.pattern === value) {
|
|
267
307
|
this.throwSCORMError(scorm2004_error_codes.GENERAL_SET_FAILURE);
|
|
@@ -275,8 +315,8 @@ export default class Scorm2004API extends BaseAPI {
|
|
|
275
315
|
* @param {string} CMIElement
|
|
276
316
|
* @param {*} value
|
|
277
317
|
*/
|
|
278
|
-
validateCorrectResponse(CMIElement, value) {
|
|
279
|
-
const parts = CMIElement.split(
|
|
318
|
+
validateCorrectResponse(CMIElement: string, value: any) {
|
|
319
|
+
const parts = CMIElement.split(".");
|
|
280
320
|
const index = Number(parts[2]);
|
|
281
321
|
const pattern_index = Number(parts[4]);
|
|
282
322
|
const interaction = this.cmi.interactions.childArray[index];
|
|
@@ -285,25 +325,36 @@ export default class Scorm2004API extends BaseAPI {
|
|
|
285
325
|
this.checkDuplicateChoiceResponse(interaction, value);
|
|
286
326
|
|
|
287
327
|
const response_type = correct_responses[interaction.type];
|
|
288
|
-
if (
|
|
289
|
-
|
|
328
|
+
if (
|
|
329
|
+
typeof response_type.limit === "undefined" ||
|
|
330
|
+
interaction_count <= response_type.limit
|
|
331
|
+
) {
|
|
290
332
|
this.checkValidResponseType(response_type, value, interaction.type);
|
|
291
333
|
|
|
292
|
-
if (
|
|
334
|
+
if (
|
|
335
|
+
(this.lastErrorCode === "0" &&
|
|
293
336
|
(!response_type.duplicate ||
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
337
|
+
!this.checkDuplicatedPattern(
|
|
338
|
+
interaction.correct_responses,
|
|
339
|
+
pattern_index,
|
|
340
|
+
value,
|
|
341
|
+
))) ||
|
|
342
|
+
(this.lastErrorCode === "0" && value === "")
|
|
343
|
+
) {
|
|
297
344
|
// do nothing, we want the inverse
|
|
298
345
|
} else {
|
|
299
|
-
if (this.lastErrorCode === 0) {
|
|
300
|
-
this.throwSCORMError(
|
|
301
|
-
|
|
346
|
+
if (this.lastErrorCode === "0") {
|
|
347
|
+
this.throwSCORMError(
|
|
348
|
+
scorm2004_error_codes.GENERAL_SET_FAILURE,
|
|
349
|
+
"Data Model Element Pattern Already Exists",
|
|
350
|
+
);
|
|
302
351
|
}
|
|
303
352
|
}
|
|
304
353
|
} else {
|
|
305
|
-
this.throwSCORMError(
|
|
306
|
-
|
|
354
|
+
this.throwSCORMError(
|
|
355
|
+
scorm2004_error_codes.GENERAL_SET_FAILURE,
|
|
356
|
+
"Data Model Element Collection Limit Reached",
|
|
357
|
+
);
|
|
307
358
|
}
|
|
308
359
|
}
|
|
309
360
|
|
|
@@ -313,8 +364,8 @@ export default class Scorm2004API extends BaseAPI {
|
|
|
313
364
|
* @param {string} CMIElement
|
|
314
365
|
* @return {*}
|
|
315
366
|
*/
|
|
316
|
-
getCMIValue(CMIElement) {
|
|
317
|
-
return this._commonGetCMIValue(
|
|
367
|
+
getCMIValue(CMIElement: string): any {
|
|
368
|
+
return this._commonGetCMIValue("GetValue", true, CMIElement);
|
|
318
369
|
}
|
|
319
370
|
|
|
320
371
|
/**
|
|
@@ -324,15 +375,20 @@ export default class Scorm2004API extends BaseAPI {
|
|
|
324
375
|
* @param {boolean} detail
|
|
325
376
|
* @return {string}
|
|
326
377
|
*/
|
|
327
|
-
getLmsErrorMessageDetails(
|
|
328
|
-
|
|
329
|
-
|
|
378
|
+
getLmsErrorMessageDetails(
|
|
379
|
+
errorNumber: string | number,
|
|
380
|
+
detail: boolean,
|
|
381
|
+
): string {
|
|
382
|
+
let basicMessage = "";
|
|
383
|
+
let detailMessage = "";
|
|
330
384
|
|
|
331
385
|
// Set error number to string since inconsistent from modules if string or number
|
|
332
386
|
errorNumber = String(errorNumber);
|
|
333
387
|
if (scorm2004_constants.error_descriptions[errorNumber]) {
|
|
334
|
-
basicMessage =
|
|
335
|
-
|
|
388
|
+
basicMessage =
|
|
389
|
+
scorm2004_constants.error_descriptions[errorNumber].basicMessage;
|
|
390
|
+
detailMessage =
|
|
391
|
+
scorm2004_constants.error_descriptions[errorNumber].detailMessage;
|
|
336
392
|
}
|
|
337
393
|
|
|
338
394
|
return detail ? detailMessage : basicMessage;
|
|
@@ -345,7 +401,11 @@ export default class Scorm2004API extends BaseAPI {
|
|
|
345
401
|
* @param {*} value
|
|
346
402
|
* @return {boolean}
|
|
347
403
|
*/
|
|
348
|
-
checkDuplicatedPattern
|
|
404
|
+
checkDuplicatedPattern(
|
|
405
|
+
correct_response: CMIArray,
|
|
406
|
+
current_index: number,
|
|
407
|
+
value: any,
|
|
408
|
+
): boolean {
|
|
349
409
|
let found = false;
|
|
350
410
|
const count = correct_response._count;
|
|
351
411
|
for (let i = 0; i < count && !found; i++) {
|
|
@@ -354,7 +414,7 @@ export default class Scorm2004API extends BaseAPI {
|
|
|
354
414
|
}
|
|
355
415
|
}
|
|
356
416
|
return found;
|
|
357
|
-
}
|
|
417
|
+
}
|
|
358
418
|
|
|
359
419
|
/**
|
|
360
420
|
* Checks for a valid correct_response value
|
|
@@ -362,12 +422,19 @@ export default class Scorm2004API extends BaseAPI {
|
|
|
362
422
|
* @param {Array} nodes
|
|
363
423
|
* @param {*} value
|
|
364
424
|
*/
|
|
365
|
-
checkCorrectResponseValue(
|
|
425
|
+
checkCorrectResponseValue(
|
|
426
|
+
interaction_type: string,
|
|
427
|
+
nodes: Array<any>,
|
|
428
|
+
value: any,
|
|
429
|
+
) {
|
|
366
430
|
const response = correct_responses[interaction_type];
|
|
367
431
|
const formatRegex = new RegExp(response.format);
|
|
368
|
-
for (let i = 0; i < nodes.length && this.lastErrorCode === 0; i++) {
|
|
369
|
-
if (
|
|
370
|
-
|
|
432
|
+
for (let i = 0; i < nodes.length && this.lastErrorCode === "0"; i++) {
|
|
433
|
+
if (
|
|
434
|
+
interaction_type.match(
|
|
435
|
+
"^(fill-in|long-fill-in|matching|performance|sequencing)$",
|
|
436
|
+
)
|
|
437
|
+
) {
|
|
371
438
|
nodes[i] = this.removeCorrectResponsePrefixes(nodes[i]);
|
|
372
439
|
}
|
|
373
440
|
|
|
@@ -378,7 +445,10 @@ export default class Scorm2004API extends BaseAPI {
|
|
|
378
445
|
if (!matches) {
|
|
379
446
|
this.throwSCORMError(scorm2004_error_codes.TYPE_MISMATCH);
|
|
380
447
|
} else {
|
|
381
|
-
if (
|
|
448
|
+
if (
|
|
449
|
+
!response.format2 ||
|
|
450
|
+
!values[1].match(new RegExp(response.format2))
|
|
451
|
+
) {
|
|
382
452
|
this.throwSCORMError(scorm2004_error_codes.TYPE_MISMATCH);
|
|
383
453
|
}
|
|
384
454
|
}
|
|
@@ -387,17 +457,19 @@ export default class Scorm2004API extends BaseAPI {
|
|
|
387
457
|
}
|
|
388
458
|
} else {
|
|
389
459
|
const matches = nodes[i].match(formatRegex);
|
|
390
|
-
if (
|
|
391
|
-
|
|
460
|
+
if (
|
|
461
|
+
(!matches && value !== "") ||
|
|
462
|
+
(!matches && interaction_type === "true-false")
|
|
463
|
+
) {
|
|
392
464
|
this.throwSCORMError(scorm2004_error_codes.TYPE_MISMATCH);
|
|
393
465
|
} else {
|
|
394
|
-
if (interaction_type ===
|
|
466
|
+
if (interaction_type === "numeric" && nodes.length > 1) {
|
|
395
467
|
if (Number(nodes[0]) > Number(nodes[1])) {
|
|
396
468
|
this.throwSCORMError(scorm2004_error_codes.TYPE_MISMATCH);
|
|
397
469
|
}
|
|
398
470
|
} else {
|
|
399
|
-
if (nodes[i] !==
|
|
400
|
-
for (let j = 0; j < i && this.lastErrorCode === 0; j++) {
|
|
471
|
+
if (nodes[i] !== "" && response.unique) {
|
|
472
|
+
for (let j = 0; j < i && this.lastErrorCode === "0"; j++) {
|
|
401
473
|
if (nodes[i] === nodes[j]) {
|
|
402
474
|
this.throwSCORMError(scorm2004_error_codes.TYPE_MISMATCH);
|
|
403
475
|
}
|
|
@@ -414,41 +486,42 @@ export default class Scorm2004API extends BaseAPI {
|
|
|
414
486
|
* @param {string} node
|
|
415
487
|
* @return {*}
|
|
416
488
|
*/
|
|
417
|
-
removeCorrectResponsePrefixes(node) {
|
|
489
|
+
removeCorrectResponsePrefixes(node: string): any {
|
|
418
490
|
let seenOrder = false;
|
|
419
491
|
let seenCase = false;
|
|
420
492
|
let seenLang = false;
|
|
421
493
|
|
|
422
494
|
const prefixRegex = new RegExp(
|
|
423
|
-
|
|
495
|
+
"^({(lang|case_matters|order_matters)=([^}]+)})",
|
|
496
|
+
);
|
|
424
497
|
let matches = node.match(prefixRegex);
|
|
425
498
|
let langMatches = null;
|
|
426
499
|
while (matches) {
|
|
427
500
|
switch (matches[2]) {
|
|
428
|
-
case
|
|
501
|
+
case "lang":
|
|
429
502
|
langMatches = node.match(scorm2004_regex.CMILangcr);
|
|
430
503
|
if (langMatches) {
|
|
431
504
|
const lang = langMatches[3];
|
|
432
505
|
if (lang !== undefined && lang.length > 0) {
|
|
433
|
-
if (ValidLanguages
|
|
506
|
+
if (!ValidLanguages.includes(lang.toLowerCase())) {
|
|
434
507
|
this.throwSCORMError(scorm2004_error_codes.TYPE_MISMATCH);
|
|
435
508
|
}
|
|
436
509
|
}
|
|
437
510
|
}
|
|
438
511
|
seenLang = true;
|
|
439
512
|
break;
|
|
440
|
-
case
|
|
513
|
+
case "case_matters":
|
|
441
514
|
if (!seenLang && !seenOrder && !seenCase) {
|
|
442
|
-
if (matches[3] !==
|
|
515
|
+
if (matches[3] !== "true" && matches[3] !== "false") {
|
|
443
516
|
this.throwSCORMError(scorm2004_error_codes.TYPE_MISMATCH);
|
|
444
517
|
}
|
|
445
518
|
}
|
|
446
519
|
|
|
447
520
|
seenCase = true;
|
|
448
521
|
break;
|
|
449
|
-
case
|
|
522
|
+
case "order_matters":
|
|
450
523
|
if (!seenCase && !seenLang && !seenOrder) {
|
|
451
|
-
if (matches[3] !==
|
|
524
|
+
if (matches[3] !== "true" && matches[3] !== "false") {
|
|
452
525
|
this.throwSCORMError(scorm2004_error_codes.TYPE_MISMATCH);
|
|
453
526
|
}
|
|
454
527
|
}
|
|
@@ -458,7 +531,7 @@ export default class Scorm2004API extends BaseAPI {
|
|
|
458
531
|
default:
|
|
459
532
|
break;
|
|
460
533
|
}
|
|
461
|
-
node = node.
|
|
534
|
+
node = node.substring(matches[1].length);
|
|
462
535
|
matches = node.match(prefixRegex);
|
|
463
536
|
}
|
|
464
537
|
|
|
@@ -469,7 +542,7 @@ export default class Scorm2004API extends BaseAPI {
|
|
|
469
542
|
* Replace the whole API with another
|
|
470
543
|
* @param {Scorm2004API} newAPI
|
|
471
544
|
*/
|
|
472
|
-
replaceWithAnotherScormAPI(newAPI) {
|
|
545
|
+
replaceWithAnotherScormAPI(newAPI: Scorm2004API) {
|
|
473
546
|
// Data Model
|
|
474
547
|
this.cmi = newAPI.cmi;
|
|
475
548
|
this.adl = newAPI.adl;
|
|
@@ -481,26 +554,26 @@ export default class Scorm2004API extends BaseAPI {
|
|
|
481
554
|
* @param {boolean} terminateCommit
|
|
482
555
|
* @return {object|Array}
|
|
483
556
|
*/
|
|
484
|
-
renderCommitCMI(terminateCommit: boolean) {
|
|
485
|
-
const cmiExport = this.renderCMIToJSONObject();
|
|
557
|
+
renderCommitCMI(terminateCommit: boolean): object | Array<any> {
|
|
558
|
+
const cmiExport: RefObject = this.renderCMIToJSONObject();
|
|
486
559
|
|
|
487
560
|
if (terminateCommit) {
|
|
488
561
|
cmiExport.cmi.total_time = this.cmi.getCurrentTotalTime();
|
|
489
562
|
}
|
|
490
563
|
|
|
491
564
|
const result = [];
|
|
492
|
-
const flattened = Utilities.flatten(cmiExport);
|
|
565
|
+
const flattened: RefObject = Utilities.flatten(cmiExport);
|
|
493
566
|
switch (this.settings.dataCommitFormat) {
|
|
494
|
-
case
|
|
567
|
+
case "flattened":
|
|
495
568
|
return Utilities.flatten(cmiExport);
|
|
496
|
-
case
|
|
569
|
+
case "params":
|
|
497
570
|
for (const item in flattened) {
|
|
498
571
|
if ({}.hasOwnProperty.call(flattened, item)) {
|
|
499
572
|
result.push(`${item}=${flattened[item]}`);
|
|
500
573
|
}
|
|
501
574
|
}
|
|
502
575
|
return result;
|
|
503
|
-
case
|
|
576
|
+
case "json":
|
|
504
577
|
default:
|
|
505
578
|
return cmiExport;
|
|
506
579
|
}
|
|
@@ -510,28 +583,24 @@ export default class Scorm2004API extends BaseAPI {
|
|
|
510
583
|
* Attempts to store the data to the LMS
|
|
511
584
|
*
|
|
512
585
|
* @param {boolean} terminateCommit
|
|
513
|
-
* @return {
|
|
586
|
+
* @return {ResultObject}
|
|
514
587
|
*/
|
|
515
|
-
storeData(terminateCommit: boolean) {
|
|
588
|
+
storeData(terminateCommit: boolean): ResultObject {
|
|
516
589
|
if (terminateCommit) {
|
|
517
|
-
if (this.cmi.mode ===
|
|
518
|
-
if (this.cmi.credit ===
|
|
590
|
+
if (this.cmi.mode === "normal") {
|
|
591
|
+
if (this.cmi.credit === "credit") {
|
|
519
592
|
if (this.cmi.completion_threshold && this.cmi.progress_measure) {
|
|
520
593
|
if (this.cmi.progress_measure >= this.cmi.completion_threshold) {
|
|
521
|
-
|
|
522
|
-
this.cmi.completion_status = 'completed';
|
|
594
|
+
this.cmi.completion_status = "completed";
|
|
523
595
|
} else {
|
|
524
|
-
|
|
525
|
-
this.cmi.completion_status = 'incomplete';
|
|
596
|
+
this.cmi.completion_status = "incomplete";
|
|
526
597
|
}
|
|
527
598
|
}
|
|
528
599
|
if (this.cmi.scaled_passing_score && this.cmi.score.scaled) {
|
|
529
600
|
if (this.cmi.score.scaled >= this.cmi.scaled_passing_score) {
|
|
530
|
-
|
|
531
|
-
this.cmi.success_status = 'passed';
|
|
601
|
+
this.cmi.success_status = "passed";
|
|
532
602
|
} else {
|
|
533
|
-
|
|
534
|
-
this.cmi.success_status = 'failed';
|
|
603
|
+
this.cmi.success_status = "failed";
|
|
535
604
|
}
|
|
536
605
|
}
|
|
537
606
|
}
|
|
@@ -539,34 +608,47 @@ export default class Scorm2004API extends BaseAPI {
|
|
|
539
608
|
}
|
|
540
609
|
|
|
541
610
|
let navRequest = false;
|
|
542
|
-
if (
|
|
543
|
-
|
|
611
|
+
if (
|
|
612
|
+
this.adl.nav.request !== this.startingData?.adl?.nav?.request &&
|
|
613
|
+
this.adl.nav.request !== "_none_"
|
|
614
|
+
) {
|
|
544
615
|
this.adl.nav.request = encodeURIComponent(this.adl.nav.request);
|
|
545
616
|
navRequest = true;
|
|
546
617
|
}
|
|
547
618
|
|
|
548
|
-
const commitObject = this.renderCommitCMI(
|
|
549
|
-
|
|
619
|
+
const commitObject = this.renderCommitCMI(
|
|
620
|
+
terminateCommit || this.settings.alwaysSendTotalTime,
|
|
621
|
+
);
|
|
550
622
|
|
|
551
623
|
if (this.apiLogLevel === global_constants.LOG_LEVEL_DEBUG) {
|
|
552
|
-
console.debug(
|
|
553
|
-
|
|
624
|
+
console.debug(
|
|
625
|
+
"Commit (terminated: " + (terminateCommit ? "yes" : "no") + "): ",
|
|
626
|
+
);
|
|
554
627
|
console.debug(commitObject);
|
|
555
628
|
}
|
|
556
|
-
if (this.settings.lmsCommitUrl) {
|
|
557
|
-
const result = this.processHttpRequest(
|
|
558
|
-
|
|
629
|
+
if (typeof this.settings.lmsCommitUrl === "string") {
|
|
630
|
+
const result = this.processHttpRequest(
|
|
631
|
+
this.settings.lmsCommitUrl,
|
|
632
|
+
commitObject,
|
|
633
|
+
terminateCommit,
|
|
634
|
+
);
|
|
559
635
|
|
|
560
636
|
// check if this is a sequencing call, and then call the necessary JS
|
|
561
637
|
{
|
|
562
|
-
if (
|
|
563
|
-
|
|
638
|
+
if (
|
|
639
|
+
navRequest &&
|
|
640
|
+
result.navRequest !== undefined &&
|
|
641
|
+
result.navRequest !== ""
|
|
642
|
+
) {
|
|
564
643
|
Function(`"use strict";(() => { ${result.navRequest} })()`)();
|
|
565
644
|
}
|
|
566
645
|
}
|
|
567
646
|
return result;
|
|
568
647
|
} else {
|
|
569
|
-
return
|
|
648
|
+
return {
|
|
649
|
+
result: global_constants.SCORM_TRUE,
|
|
650
|
+
errorCode: 0,
|
|
651
|
+
};
|
|
570
652
|
}
|
|
571
653
|
}
|
|
572
654
|
}
|