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.
Files changed (77) hide show
  1. package/.github/workflows/stale.yml +14 -0
  2. package/.run/{Mocha Unit Tests.run.xml → Mocha Unit Tests (watch).run.xml } +1 -1
  3. package/.run/Template Mocha.run.xml +17 -0
  4. package/README.md +180 -72
  5. package/dist/aicc.js +1520 -1149
  6. package/dist/aicc.js.map +1 -1
  7. package/dist/aicc.min.js +1 -1
  8. package/dist/aicc.min.js.map +1 -1
  9. package/dist/scorm-again.js +2812 -2205
  10. package/dist/scorm-again.js.map +1 -1
  11. package/dist/scorm-again.min.js +1 -1
  12. package/dist/scorm-again.min.js.map +1 -1
  13. package/dist/scorm12.js +1129 -842
  14. package/dist/scorm12.js.map +1 -1
  15. package/dist/scorm12.min.js +1 -1
  16. package/dist/scorm12.min.js.map +1 -1
  17. package/dist/scorm2004.js +1921 -1564
  18. package/dist/scorm2004.js.map +1 -1
  19. package/dist/scorm2004.min.js +1 -1
  20. package/dist/scorm2004.min.js.map +1 -1
  21. package/package.json +20 -17
  22. package/src/AICC.ts +15 -17
  23. package/src/BaseAPI.ts +283 -420
  24. package/src/Scorm12API.ts +133 -41
  25. package/src/Scorm2004API.ts +224 -120
  26. package/src/cmi/aicc/attempts.ts +94 -0
  27. package/src/cmi/aicc/cmi.ts +100 -0
  28. package/src/cmi/aicc/core.ts +360 -0
  29. package/src/cmi/aicc/evaluation.ts +157 -0
  30. package/src/cmi/aicc/paths.ts +180 -0
  31. package/src/cmi/aicc/student_data.ts +86 -0
  32. package/src/cmi/aicc/student_demographics.ts +367 -0
  33. package/src/cmi/aicc/student_preferences.ts +176 -0
  34. package/src/cmi/aicc/tries.ts +116 -0
  35. package/src/cmi/aicc/validation.ts +25 -0
  36. package/src/cmi/common/array.ts +77 -0
  37. package/src/cmi/common/base_cmi.ts +46 -0
  38. package/src/cmi/common/score.ts +203 -0
  39. package/src/cmi/common/validation.ts +60 -0
  40. package/src/cmi/scorm12/cmi.ts +224 -0
  41. package/src/cmi/scorm12/interactions.ts +368 -0
  42. package/src/cmi/scorm12/nav.ts +54 -0
  43. package/src/cmi/scorm12/objectives.ts +112 -0
  44. package/src/cmi/scorm12/student_data.ts +130 -0
  45. package/src/cmi/scorm12/student_preference.ts +158 -0
  46. package/src/cmi/scorm12/validation.ts +48 -0
  47. package/src/cmi/scorm2004/adl.ts +272 -0
  48. package/src/cmi/scorm2004/cmi.ts +599 -0
  49. package/src/cmi/scorm2004/comments.ts +163 -0
  50. package/src/cmi/scorm2004/interactions.ts +466 -0
  51. package/src/cmi/scorm2004/learner_preference.ts +152 -0
  52. package/src/cmi/scorm2004/objectives.ts +212 -0
  53. package/src/cmi/scorm2004/score.ts +78 -0
  54. package/src/cmi/scorm2004/validation.ts +42 -0
  55. package/src/constants/default_settings.ts +82 -0
  56. package/src/constants/enums.ts +17 -0
  57. package/src/constants/regex.ts +2 -2
  58. package/src/constants/response_constants.ts +2 -0
  59. package/src/exceptions.ts +22 -1
  60. package/src/helpers/scheduled_commit.ts +42 -0
  61. package/src/interfaces/IBaseAPI.ts +35 -0
  62. package/src/types/api_types.ts +50 -0
  63. package/src/utilities/debounce.ts +31 -0
  64. package/src/utilities.ts +56 -0
  65. package/test/AICC.spec.ts +11 -1
  66. package/test/Scorm12API.spec.ts +372 -9
  67. package/test/Scorm2004API.spec.ts +558 -2
  68. package/test/cmi/aicc_cmi.spec.ts +188 -11
  69. package/test/cmi/scorm12_cmi.spec.ts +5 -5
  70. package/test/cmi/scorm2004_cmi.spec.ts +8 -8
  71. package/test/cmi_helpers.ts +1 -1
  72. package/test/types/api_types.spec.ts +126 -0
  73. package/test/utilities/debounce.spec.ts +56 -0
  74. package/src/cmi/aicc_cmi.ts +0 -1248
  75. package/src/cmi/common.ts +0 -411
  76. package/src/cmi/scorm12_cmi.ts +0 -1426
  77. package/src/cmi/scorm2004_cmi.ts +0 -1874
@@ -0,0 +1,100 @@
1
+ import * as Scorm12CMI from "../scorm12/cmi";
2
+ import APIConstants from "../../constants/api_constants";
3
+ import { CMIEvaluation } from "./evaluation";
4
+ import { AICCStudentPreferences } from "./student_preferences";
5
+ import { CMIStudentDemographics } from "./student_demographics";
6
+ import { AICCCMIStudentData } from "./student_data";
7
+ import { CMIPaths } from "./paths";
8
+ import { CMICore } from "./core";
9
+ import { CMIObjectives } from "../scorm12/objectives";
10
+ import { CMIStudentData } from "../scorm12/student_data";
11
+ import { CMIStudentPreference } from "../scorm12/student_preference";
12
+ import { CMIInteractions } from "../scorm12/interactions";
13
+
14
+ /**
15
+ * CMI Class for AICC
16
+ */
17
+ export class CMI extends Scorm12CMI.CMI {
18
+ /**
19
+ * Constructor for AICC CMI object
20
+ * @param {boolean} initialized
21
+ */
22
+ constructor(initialized: boolean = false) {
23
+ super(APIConstants.aicc.cmi_children);
24
+ if (initialized) this.initialize();
25
+ this.student_preference = new AICCStudentPreferences();
26
+ this.student_data = new AICCCMIStudentData();
27
+ this.student_demographics = new CMIStudentDemographics();
28
+ this.evaluation = new CMIEvaluation();
29
+ this.paths = new CMIPaths();
30
+ }
31
+
32
+ public student_data: AICCCMIStudentData;
33
+ public student_preference: AICCStudentPreferences;
34
+ public student_demographics: CMIStudentDemographics;
35
+ public evaluation: CMIEvaluation;
36
+ public paths: CMIPaths;
37
+
38
+ /**
39
+ * Called when the API has been initialized after the CMI has been created
40
+ */
41
+ initialize() {
42
+ super.initialize();
43
+ this.student_preference?.initialize();
44
+ this.student_data?.initialize();
45
+ this.student_demographics?.initialize();
46
+ this.evaluation?.initialize();
47
+ this.paths?.initialize();
48
+ }
49
+
50
+ /**
51
+ * toJSON for cmi
52
+ *
53
+ * @return {
54
+ * {
55
+ * suspend_data: string,
56
+ * launch_data: string,
57
+ * comments: string,
58
+ * comments_from_lms: string,
59
+ * core: CMICore,
60
+ * objectives: CMIObjectives,
61
+ * student_data: CMIStudentData,
62
+ * student_preference: CMIStudentPreference,
63
+ * interactions: CMIInteractions,
64
+ * paths: CMIPaths
65
+ * }
66
+ * }
67
+ */
68
+ toJSON(): {
69
+ suspend_data: string;
70
+ launch_data: string;
71
+ comments: string;
72
+ comments_from_lms: string;
73
+ core: CMICore;
74
+ objectives: CMIObjectives;
75
+ student_data: CMIStudentData;
76
+ student_preference: CMIStudentPreference;
77
+ student_demographics: CMIStudentDemographics;
78
+ interactions: CMIInteractions;
79
+ evaluation: CMIEvaluation;
80
+ paths: CMIPaths;
81
+ } {
82
+ this.jsonString = true;
83
+ const result = {
84
+ suspend_data: this.suspend_data,
85
+ launch_data: this.launch_data,
86
+ comments: this.comments,
87
+ comments_from_lms: this.comments_from_lms,
88
+ core: this.core,
89
+ objectives: this.objectives,
90
+ student_data: this.student_data,
91
+ student_preference: this.student_preference,
92
+ student_demographics: this.student_demographics,
93
+ interactions: this.interactions,
94
+ evaluation: this.evaluation,
95
+ paths: this.paths,
96
+ };
97
+ delete this.jsonString;
98
+ return result;
99
+ }
100
+ }
@@ -0,0 +1,360 @@
1
+ import { BaseCMI } from "../common/base_cmi";
2
+ import { CMIScore } from "../common/score";
3
+ import APIConstants from "../../constants/api_constants";
4
+ import Regex from "../../constants/regex";
5
+ import ErrorCodes from "../../constants/error_codes";
6
+ import { Scorm12ValidationError } from "../../exceptions";
7
+ import { check12ValidFormat } from "../scorm12/validation";
8
+ import * as Util from "../../utilities";
9
+
10
+ /**
11
+ * Class representing the `cmi.core` object
12
+ * @extends BaseCMI
13
+ */
14
+ export class CMICore extends BaseCMI {
15
+ /**
16
+ * Constructor for `cmi.core`
17
+ */
18
+ constructor() {
19
+ super();
20
+ this.score = new CMIScore({
21
+ score_children: APIConstants.scorm12.score_children,
22
+ score_range: Regex.scorm12.score_range,
23
+ invalidErrorCode: ErrorCodes.scorm12.INVALID_SET_VALUE,
24
+ invalidTypeCode: ErrorCodes.scorm12.TYPE_MISMATCH,
25
+ invalidRangeCode: ErrorCodes.scorm12.VALUE_OUT_OF_RANGE,
26
+ errorClass: Scorm12ValidationError,
27
+ });
28
+ }
29
+
30
+ public readonly score: CMIScore;
31
+
32
+ /**
33
+ * Called when the API has been initialized after the CMI has been created
34
+ */
35
+ initialize() {
36
+ super.initialize();
37
+ this.score?.initialize();
38
+ }
39
+
40
+ private __children = APIConstants.scorm12.core_children;
41
+ private _student_id = "";
42
+ private _student_name = "";
43
+ private _lesson_location = "";
44
+ private _credit = "";
45
+ private _lesson_status = "not attempted";
46
+ private _entry = "";
47
+ private _total_time = "";
48
+ private _lesson_mode = "normal";
49
+ private _exit = "";
50
+ private _session_time = "00:00:00";
51
+ private _suspend_data = "";
52
+
53
+ /**
54
+ * Getter for __children
55
+ * @return {string}
56
+ * @private
57
+ */
58
+ get _children(): string {
59
+ return this.__children;
60
+ }
61
+
62
+ /**
63
+ * Setter for __children. Just throws an error.
64
+ * @param {string} _children
65
+ * @private
66
+ */
67
+ set _children(_children: string) {
68
+ throw new Scorm12ValidationError(ErrorCodes.scorm12.INVALID_SET_VALUE);
69
+ }
70
+
71
+ /**
72
+ * Getter for _student_id
73
+ * @return {string}
74
+ */
75
+ get student_id(): string {
76
+ return this._student_id;
77
+ }
78
+
79
+ /**
80
+ * Setter for _student_id. Can only be called before initialization.
81
+ * @param {string} student_id
82
+ */
83
+ set student_id(student_id: string) {
84
+ if (this.initialized) {
85
+ throw new Scorm12ValidationError(ErrorCodes.scorm12.READ_ONLY_ELEMENT);
86
+ } else {
87
+ this._student_id = student_id;
88
+ }
89
+ }
90
+
91
+ /**
92
+ * Getter for _student_name
93
+ * @return {string}
94
+ */
95
+ get student_name(): string {
96
+ return this._student_name;
97
+ }
98
+
99
+ /**
100
+ * Setter for _student_name. Can only be called before initialization.
101
+ * @param {string} student_name
102
+ */
103
+ set student_name(student_name: string) {
104
+ if (this.initialized) {
105
+ throw new Scorm12ValidationError(ErrorCodes.scorm12.READ_ONLY_ELEMENT);
106
+ } else {
107
+ this._student_name = student_name;
108
+ }
109
+ }
110
+
111
+ /**
112
+ * Getter for _lesson_location
113
+ * @return {string}
114
+ */
115
+ get lesson_location(): string {
116
+ return this._lesson_location;
117
+ }
118
+
119
+ /**
120
+ * Setter for _lesson_location
121
+ * @param {string} lesson_location
122
+ */
123
+ set lesson_location(lesson_location: string) {
124
+ if (check12ValidFormat(lesson_location, Regex.scorm12.CMIString256, true)) {
125
+ this._lesson_location = lesson_location;
126
+ }
127
+ }
128
+
129
+ /**
130
+ * Getter for _credit
131
+ * @return {string}
132
+ */
133
+ get credit(): string {
134
+ return this._credit;
135
+ }
136
+
137
+ /**
138
+ * Setter for _credit. Can only be called before initialization.
139
+ * @param {string} credit
140
+ */
141
+ set credit(credit: string) {
142
+ if (this.initialized) {
143
+ throw new Scorm12ValidationError(ErrorCodes.scorm12.READ_ONLY_ELEMENT);
144
+ } else {
145
+ this._credit = credit;
146
+ }
147
+ }
148
+
149
+ /**
150
+ * Getter for _lesson_status
151
+ * @return {string}
152
+ */
153
+ get lesson_status(): string {
154
+ return this._lesson_status;
155
+ }
156
+
157
+ /**
158
+ * Setter for _lesson_status
159
+ * @param {string} lesson_status
160
+ */
161
+ set lesson_status(lesson_status: string) {
162
+ if (this.initialized) {
163
+ if (check12ValidFormat(lesson_status, Regex.scorm12.CMIStatus)) {
164
+ this._lesson_status = lesson_status;
165
+ }
166
+ } else {
167
+ if (check12ValidFormat(lesson_status, Regex.scorm12.CMIStatus2)) {
168
+ this._lesson_status = lesson_status;
169
+ }
170
+ }
171
+ }
172
+
173
+ /**
174
+ * Getter for _entry
175
+ * @return {string}
176
+ */
177
+ get entry(): string {
178
+ return this._entry;
179
+ }
180
+
181
+ /**
182
+ * Setter for _entry. Can only be called before initialization.
183
+ * @param {string} entry
184
+ */
185
+ set entry(entry: string) {
186
+ if (this.initialized) {
187
+ throw new Scorm12ValidationError(ErrorCodes.scorm12.READ_ONLY_ELEMENT);
188
+ } else {
189
+ this._entry = entry;
190
+ }
191
+ }
192
+
193
+ /**
194
+ * Getter for _total_time
195
+ * @return {string}
196
+ */
197
+ get total_time(): string {
198
+ return this._total_time;
199
+ }
200
+
201
+ /**
202
+ * Setter for _total_time. Can only be called before initialization.
203
+ * @param {string} total_time
204
+ */
205
+ set total_time(total_time: string) {
206
+ if (this.initialized) {
207
+ throw new Scorm12ValidationError(ErrorCodes.scorm12.READ_ONLY_ELEMENT);
208
+ } else {
209
+ this._total_time = total_time;
210
+ }
211
+ }
212
+
213
+ /**
214
+ * Getter for _lesson_mode
215
+ * @return {string}
216
+ */
217
+ get lesson_mode(): string {
218
+ return this._lesson_mode;
219
+ }
220
+
221
+ /**
222
+ * Setter for _lesson_mode. Can only be called before initialization.
223
+ * @param {string} lesson_mode
224
+ */
225
+ set lesson_mode(lesson_mode: string) {
226
+ if (this.initialized) {
227
+ throw new Scorm12ValidationError(ErrorCodes.scorm12.READ_ONLY_ELEMENT);
228
+ } else {
229
+ this._lesson_mode = lesson_mode;
230
+ }
231
+ }
232
+
233
+ /**
234
+ * Getter for _exit. Should only be called during JSON export.
235
+ * @return {string}
236
+ */
237
+ get exit(): string {
238
+ if (!this.jsonString) {
239
+ throw new Scorm12ValidationError(ErrorCodes.scorm12.WRITE_ONLY_ELEMENT);
240
+ }
241
+ return this._exit;
242
+ }
243
+
244
+ /**
245
+ * Setter for _exit
246
+ * @param {string} exit
247
+ */
248
+ set exit(exit: string) {
249
+ if (check12ValidFormat(exit, Regex.scorm12.CMIExit, true)) {
250
+ this._exit = exit;
251
+ }
252
+ }
253
+
254
+ /**
255
+ * Getter for _session_time. Should only be called during JSON export.
256
+ * @return {string}
257
+ */
258
+ get session_time(): string {
259
+ if (!this.jsonString) {
260
+ throw new Scorm12ValidationError(ErrorCodes.scorm12.WRITE_ONLY_ELEMENT);
261
+ }
262
+ return this._session_time;
263
+ }
264
+
265
+ /**
266
+ * Setter for _session_time
267
+ * @param {string} session_time
268
+ */
269
+ set session_time(session_time: string) {
270
+ if (check12ValidFormat(session_time, Regex.scorm12.CMITimespan)) {
271
+ this._session_time = session_time;
272
+ }
273
+ }
274
+
275
+ /**
276
+ * Getter for _suspend_data
277
+ * @return {string}
278
+ */
279
+ get suspend_data(): string {
280
+ return this._suspend_data;
281
+ }
282
+
283
+ /**
284
+ * Setter for _suspend_data
285
+ * @param {string} suspend_data
286
+ */
287
+ set suspend_data(suspend_data: string) {
288
+ if (check12ValidFormat(suspend_data, Regex.scorm12.CMIString4096, true)) {
289
+ this._suspend_data = suspend_data;
290
+ }
291
+ }
292
+
293
+ /**
294
+ * Adds the current session time to the existing total time.
295
+ * @param {number} start_time
296
+ * @return {string}
297
+ */
298
+ getCurrentTotalTime(start_time: number | undefined): string {
299
+ let sessionTime = this._session_time;
300
+ const startTime = start_time;
301
+
302
+ if (typeof startTime !== "undefined" && startTime !== null) {
303
+ const seconds = new Date().getTime() - startTime;
304
+ sessionTime = Util.getSecondsAsHHMMSS(seconds / 1000);
305
+ }
306
+
307
+ return Util.addHHMMSSTimeStrings(
308
+ this._total_time,
309
+ sessionTime,
310
+ new RegExp(Regex.scorm12.CMITimespan),
311
+ );
312
+ }
313
+
314
+ /**
315
+ * toJSON for cmi.core
316
+ *
317
+ * @return {
318
+ * {
319
+ * student_name: string,
320
+ * entry: string,
321
+ * exit: string,
322
+ * score: CMIScore,
323
+ * student_id: string,
324
+ * lesson_mode: string,
325
+ * lesson_location: string,
326
+ * lesson_status: string,
327
+ * credit: string,
328
+ * session_time: string
329
+ * }
330
+ * }
331
+ */
332
+ toJSON(): {
333
+ student_name: string;
334
+ entry: string;
335
+ exit: string;
336
+ score: CMIScore;
337
+ student_id: string;
338
+ lesson_mode: string;
339
+ lesson_location: string;
340
+ lesson_status: string;
341
+ credit: string;
342
+ session_time: string;
343
+ } {
344
+ this.jsonString = true;
345
+ const result = {
346
+ student_id: this.student_id,
347
+ student_name: this.student_name,
348
+ lesson_location: this.lesson_location,
349
+ credit: this.credit,
350
+ lesson_status: this.lesson_status,
351
+ entry: this.entry,
352
+ lesson_mode: this.lesson_mode,
353
+ exit: this.exit,
354
+ session_time: this.session_time,
355
+ score: this.score,
356
+ };
357
+ delete this.jsonString;
358
+ return result;
359
+ }
360
+ }
@@ -0,0 +1,157 @@
1
+ import { CMIArray } from "../common/array";
2
+ import { AICCValidationError } from "../../exceptions";
3
+ import { BaseCMI } from "../common/base_cmi";
4
+ import APIConstants from "../../constants/api_constants";
5
+ import ErrorCodes from "../../constants/error_codes";
6
+ import { checkAICCValidFormat } from "./validation";
7
+ import Regex from "../../constants/regex";
8
+
9
+ /**
10
+ * AICC Evaluation object
11
+ */
12
+ export class CMIEvaluation extends BaseCMI {
13
+ /**
14
+ * Constructor for AICC Evaluation object
15
+ */
16
+ constructor() {
17
+ super();
18
+ this.comments = new CMIEvaluationComments();
19
+ }
20
+
21
+ public comments: CMIEvaluationComments;
22
+
23
+ /**
24
+ * Called when the API has been initialized after the CMI has been created
25
+ */
26
+ initialize() {
27
+ super.initialize();
28
+ this.comments?.initialize();
29
+ }
30
+
31
+ /**
32
+ * toJSON for cmi.evaluation object
33
+ * @return {{comments: CMIEvaluationComments}}
34
+ */
35
+ toJSON(): {
36
+ comments: CMIEvaluationComments;
37
+ } {
38
+ this.jsonString = true;
39
+ const result = {
40
+ comments: this.comments,
41
+ };
42
+ delete this.jsonString;
43
+ return result;
44
+ }
45
+ }
46
+
47
+ /**
48
+ * Class representing AICC's cmi.evaluation.comments object
49
+ */
50
+
51
+ class CMIEvaluationComments extends CMIArray {
52
+ /**
53
+ * Constructor for AICC Evaluation Comments object
54
+ */
55
+ constructor() {
56
+ super({
57
+ children: APIConstants.aicc.comments_children,
58
+ errorCode: ErrorCodes.scorm12.INVALID_SET_VALUE,
59
+ errorClass: AICCValidationError,
60
+ });
61
+ }
62
+ }
63
+
64
+ /**
65
+ * Class for AICC Evaluation Comments
66
+ */
67
+ export class CMIEvaluationCommentsObject extends BaseCMI {
68
+ /**
69
+ * Constructor for Evaluation Comments
70
+ */
71
+ constructor() {
72
+ super();
73
+ }
74
+
75
+ private _content = "";
76
+ private _location = "";
77
+ private _time = "";
78
+
79
+ /**
80
+ * Getter for _content
81
+ * @return {string}
82
+ */
83
+ get content(): string {
84
+ return this._content;
85
+ }
86
+
87
+ /**
88
+ * Setter for _content
89
+ * @param {string} content
90
+ */
91
+ set content(content: string) {
92
+ if (checkAICCValidFormat(content, Regex.aicc.CMIString256)) {
93
+ this._content = content;
94
+ }
95
+ }
96
+
97
+ /**
98
+ * Getter for _location
99
+ * @return {string}
100
+ */
101
+ get location(): string {
102
+ return this._location;
103
+ }
104
+
105
+ /**
106
+ * Setter for _location
107
+ * @param {string} location
108
+ */
109
+ set location(location: string) {
110
+ if (checkAICCValidFormat(location, Regex.aicc.CMIString256)) {
111
+ this._location = location;
112
+ }
113
+ }
114
+
115
+ /**
116
+ * Getter for _time
117
+ * @return {string}
118
+ */
119
+ get time(): string {
120
+ return this._time;
121
+ }
122
+
123
+ /**
124
+ * Setting for _time
125
+ * @param {string} time
126
+ */
127
+ set time(time: string) {
128
+ if (checkAICCValidFormat(time, Regex.aicc.CMITime)) {
129
+ this._time = time;
130
+ }
131
+ }
132
+
133
+ /**
134
+ * toJSON for cmi.evaluation.comments.n object
135
+ * @return {
136
+ * {
137
+ * content: string,
138
+ * location: string,
139
+ * time: string
140
+ * }
141
+ * }
142
+ */
143
+ toJSON(): {
144
+ content: string;
145
+ location: string;
146
+ time: string;
147
+ } {
148
+ this.jsonString = true;
149
+ const result = {
150
+ content: this.content,
151
+ location: this.location,
152
+ time: this.time,
153
+ };
154
+ delete this.jsonString;
155
+ return result;
156
+ }
157
+ }