scorm-again 3.0.4 → 3.0.5
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/README.md +19 -4
- package/dist/esm/scorm-again.js +115 -67
- package/dist/esm/scorm-again.js.map +1 -1
- package/dist/esm/scorm-again.min.js +1 -1
- package/dist/esm/scorm-again.min.js.map +1 -1
- package/dist/esm/scorm12.js +17 -4
- package/dist/esm/scorm12.js.map +1 -1
- package/dist/esm/scorm12.min.js +1 -1
- package/dist/esm/scorm12.min.js.map +1 -1
- package/dist/esm/scorm2004.js +115 -67
- package/dist/esm/scorm2004.js.map +1 -1
- package/dist/esm/scorm2004.min.js +1 -1
- package/dist/esm/scorm2004.min.js.map +1 -1
- package/dist/scorm-again.js +102 -64
- 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 +11 -4
- 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 +102 -64
- package/dist/scorm2004.js.map +1 -1
- package/dist/scorm2004.min.js +1 -1
- package/dist/scorm2004.min.js.map +1 -1
- package/dist/types/cmi/scorm2004/interaction_delimiters.d.ts +4 -0
- package/package.json +42 -21
package/dist/scorm2004.js
CHANGED
|
@@ -943,6 +943,11 @@ this.Scorm2004API = (function () {
|
|
|
943
943
|
progress_range: "0#1"
|
|
944
944
|
};
|
|
945
945
|
|
|
946
|
+
const PERFORMANCE_STEP_NAME = "^$|" + scorm2004_regex.CMIShortIdentifier;
|
|
947
|
+
const PERFORMANCE_CHARACTERSTRING = "(?![\\s\\S]*(?:\\[,\\]|\\[\\.\\]|\\[:\\]))[\\s\\S]{1,250}";
|
|
948
|
+
const PERFORMANCE_NUMERIC_RANGE = "(?:-?\\d+(?:\\.\\d+)?)?\\[:\\](?:-?\\d+(?:\\.\\d+)?)?";
|
|
949
|
+
const CR_PERFORMANCE_STEP_ANSWER = "^(?:|" + PERFORMANCE_NUMERIC_RANGE + "|" + PERFORMANCE_CHARACTERSTRING + ")$";
|
|
950
|
+
const LR_PERFORMANCE_STEP_ANSWER = "^(?:|" + PERFORMANCE_CHARACTERSTRING + ")$";
|
|
946
951
|
const LearnerResponses = {
|
|
947
952
|
"true-false": {
|
|
948
953
|
format: "^true$|^false$",
|
|
@@ -977,8 +982,8 @@ this.Scorm2004API = (function () {
|
|
|
977
982
|
unique: false
|
|
978
983
|
},
|
|
979
984
|
performance: {
|
|
980
|
-
format:
|
|
981
|
-
format2:
|
|
985
|
+
format: PERFORMANCE_STEP_NAME,
|
|
986
|
+
format2: LR_PERFORMANCE_STEP_ANSWER,
|
|
982
987
|
max: 250,
|
|
983
988
|
delimiter: "[,]",
|
|
984
989
|
delimiter2: "[.]",
|
|
@@ -1054,10 +1059,10 @@ this.Scorm2004API = (function () {
|
|
|
1054
1059
|
delimiter2: "[.]",
|
|
1055
1060
|
unique: false,
|
|
1056
1061
|
duplicate: false,
|
|
1057
|
-
// step_name
|
|
1058
|
-
format:
|
|
1059
|
-
// step_answer
|
|
1060
|
-
format2:
|
|
1062
|
+
// step_name: optional short_identifier_type
|
|
1063
|
+
format: PERFORMANCE_STEP_NAME,
|
|
1064
|
+
// step_answer: optional characterstring (spaces allowed) or numeric range
|
|
1065
|
+
format2: CR_PERFORMANCE_STEP_ANSWER
|
|
1061
1066
|
},
|
|
1062
1067
|
sequencing: {
|
|
1063
1068
|
max: 36,
|
|
@@ -5082,7 +5087,13 @@ this.Scorm2004API = (function () {
|
|
|
5082
5087
|
if (!scorm2004) {
|
|
5083
5088
|
if (isFinalAttribute) {
|
|
5084
5089
|
if (typeof attribute === "undefined" || !this.context.checkObjectHasProperty(refObject, attribute)) {
|
|
5085
|
-
|
|
5090
|
+
if (attribute === "_children") {
|
|
5091
|
+
this.context.throwSCORMError(CMIElement, getErrorCode(this.context.errorCodes, "CHILDREN_ERROR"));
|
|
5092
|
+
} else if (attribute === "_count") {
|
|
5093
|
+
this.context.throwSCORMError(CMIElement, getErrorCode(this.context.errorCodes, "COUNT_ERROR"));
|
|
5094
|
+
} else {
|
|
5095
|
+
this.context.throwSCORMError(CMIElement, invalidErrorCode, invalidErrorMessage);
|
|
5096
|
+
}
|
|
5086
5097
|
return {
|
|
5087
5098
|
error: true
|
|
5088
5099
|
};
|
|
@@ -15336,19 +15347,20 @@ ${stackTrace}`);
|
|
|
15336
15347
|
if (errorCode === 143) returnValue = global_constants.SCORM_FALSE;
|
|
15337
15348
|
} else {
|
|
15338
15349
|
const result = this.storeData(false);
|
|
15339
|
-
|
|
15350
|
+
const errorCode = result.errorCode ?? 0;
|
|
15351
|
+
if (errorCode > 0) {
|
|
15340
15352
|
if (result.errorMessage) {
|
|
15341
15353
|
this.apiLog("commit", `Commit failed with error: ${result.errorMessage}`, LogLevelEnum.ERROR);
|
|
15342
15354
|
}
|
|
15343
15355
|
if (result.errorDetails) {
|
|
15344
15356
|
this.apiLog("commit", `Error details: ${JSON.stringify(result.errorDetails)}`, LogLevelEnum.DEBUG);
|
|
15345
15357
|
}
|
|
15346
|
-
this.throwSCORMError("api",
|
|
15358
|
+
this.throwSCORMError("api", errorCode);
|
|
15347
15359
|
}
|
|
15348
15360
|
const resultValue = result?.result ?? global_constants.SCORM_FALSE;
|
|
15349
15361
|
returnValue = typeof resultValue === "boolean" ? String(resultValue) : resultValue;
|
|
15350
15362
|
this.apiLog(callbackName, " Result: " + returnValue, LogLevelEnum.DEBUG, "HttpRequest");
|
|
15351
|
-
if (checkTerminated) this.lastErrorCode = "0";
|
|
15363
|
+
if (checkTerminated && errorCode === 0) this.lastErrorCode = "0";
|
|
15352
15364
|
this.processListeners(callbackName);
|
|
15353
15365
|
if (this.settings.enableOfflineSupport && this._offlineStorageService && this._offlineStorageService.isDeviceOnline() && this._courseId) {
|
|
15354
15366
|
this._offlineStorageService.hasPendingOfflineData(this._courseId).then(hasPendingData => {
|
|
@@ -16065,6 +16077,49 @@ ${stackTrace}`);
|
|
|
16065
16077
|
}
|
|
16066
16078
|
}
|
|
16067
16079
|
|
|
16080
|
+
function stripBrackets(delim) {
|
|
16081
|
+
return delim.replace(/[[\]]/g, "");
|
|
16082
|
+
}
|
|
16083
|
+
function escapeRegex(s) {
|
|
16084
|
+
return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
16085
|
+
}
|
|
16086
|
+
function splitDelimited(value, bracketed) {
|
|
16087
|
+
if (!bracketed) {
|
|
16088
|
+
return [value];
|
|
16089
|
+
}
|
|
16090
|
+
if (value.includes(bracketed)) {
|
|
16091
|
+
return value.split(bracketed);
|
|
16092
|
+
}
|
|
16093
|
+
const bare = stripBrackets(bracketed);
|
|
16094
|
+
if (!bare) {
|
|
16095
|
+
return [value];
|
|
16096
|
+
}
|
|
16097
|
+
const splitRe = new RegExp(`(?<!\\\\)${escapeRegex(bare)}`, "g");
|
|
16098
|
+
const unescapeRe = new RegExp(`\\\\${escapeRegex(bare)}`, "g");
|
|
16099
|
+
return value.split(splitRe).map(part => part.replace(unescapeRe, bare));
|
|
16100
|
+
}
|
|
16101
|
+
function splitFirstDelimited(value, bracketed) {
|
|
16102
|
+
if (!bracketed) {
|
|
16103
|
+
return [value];
|
|
16104
|
+
}
|
|
16105
|
+
if (value.includes(bracketed)) {
|
|
16106
|
+
const idx = value.indexOf(bracketed);
|
|
16107
|
+
return [value.slice(0, idx), value.slice(idx + bracketed.length)];
|
|
16108
|
+
}
|
|
16109
|
+
const bare = stripBrackets(bracketed);
|
|
16110
|
+
if (!bare) {
|
|
16111
|
+
return [value];
|
|
16112
|
+
}
|
|
16113
|
+
const splitRe = new RegExp(`(?<!\\\\)${escapeRegex(bare)}`);
|
|
16114
|
+
const unescapeRe = new RegExp(`\\\\${escapeRegex(bare)}`, "g");
|
|
16115
|
+
const parts = value.split(splitRe);
|
|
16116
|
+
const first = (parts[0] ?? "").replace(unescapeRe, bare);
|
|
16117
|
+
if (parts.length === 1) {
|
|
16118
|
+
return [first];
|
|
16119
|
+
}
|
|
16120
|
+
return [first, parts.slice(1).join(bare).replace(unescapeRe, bare)];
|
|
16121
|
+
}
|
|
16122
|
+
|
|
16068
16123
|
var __defProp$m = Object.defineProperty;
|
|
16069
16124
|
var __defNormalProp$m = (obj, key, value) => key in obj ? __defProp$m(obj, key, {
|
|
16070
16125
|
enumerable: true,
|
|
@@ -16260,8 +16315,7 @@ ${stackTrace}`);
|
|
|
16260
16315
|
const response_type = LearnerResponses[this.type];
|
|
16261
16316
|
if (response_type) {
|
|
16262
16317
|
if (response_type?.delimiter) {
|
|
16263
|
-
|
|
16264
|
-
nodes = learner_response.split(delimiter);
|
|
16318
|
+
nodes = splitDelimited(learner_response, response_type.delimiter);
|
|
16265
16319
|
} else {
|
|
16266
16320
|
nodes[0] = learner_response;
|
|
16267
16321
|
}
|
|
@@ -16269,10 +16323,10 @@ ${stackTrace}`);
|
|
|
16269
16323
|
const formatRegex = new RegExp(response_type.format);
|
|
16270
16324
|
for (let i = 0; i < nodes.length; i++) {
|
|
16271
16325
|
if (response_type?.delimiter2) {
|
|
16272
|
-
const
|
|
16273
|
-
const values =
|
|
16326
|
+
const node = nodes[i] ?? "";
|
|
16327
|
+
const values = this.type === "performance" ? splitFirstDelimited(node, response_type.delimiter2) : splitDelimited(node, response_type.delimiter2);
|
|
16274
16328
|
if (values?.length === 2) {
|
|
16275
|
-
if (this.type === "performance" &&
|
|
16329
|
+
if (this.type === "performance" && values[0] === "" && values[1] === "") {
|
|
16276
16330
|
throw new Scorm2004ValidationError(this._cmi_element + ".learner_response", scorm2004_errors.TYPE_MISMATCH);
|
|
16277
16331
|
}
|
|
16278
16332
|
if (!values[0]?.match(formatRegex)) {
|
|
@@ -16453,37 +16507,19 @@ ${stackTrace}`);
|
|
|
16453
16507
|
return result;
|
|
16454
16508
|
}
|
|
16455
16509
|
}
|
|
16456
|
-
|
|
16457
|
-
|
|
16458
|
-
|
|
16459
|
-
|
|
16460
|
-
|
|
16461
|
-
}
|
|
16462
|
-
function splitUnescaped(text, delim) {
|
|
16463
|
-
const reDelim = escapeRegex(delim);
|
|
16464
|
-
const splitRe = new RegExp(`(?<!\\\\)${reDelim}`, "g");
|
|
16465
|
-
const unescapeRe = new RegExp(`\\\\${reDelim}`, "g");
|
|
16466
|
-
return text.split(splitRe).map(part => part.replace(unescapeRe, delim));
|
|
16467
|
-
}
|
|
16468
|
-
function splitFirstUnescaped(text, delim) {
|
|
16469
|
-
const reDelim = escapeRegex(delim);
|
|
16470
|
-
const splitRe = new RegExp(`(?<!\\\\)${reDelim}`);
|
|
16471
|
-
const unescapeRe = new RegExp(`\\\\${reDelim}`, "g");
|
|
16472
|
-
const parts = text.split(splitRe);
|
|
16473
|
-
const firstPart = parts[0] ?? "";
|
|
16474
|
-
if (parts.length === 1) {
|
|
16475
|
-
return [firstPart.replace(unescapeRe, delim)];
|
|
16510
|
+
const RESPONSE_PREFIX_RE = /^\{(?:lang|case_matters|order_matters)=[^}]+\}/;
|
|
16511
|
+
function stripResponsePrefixes(node) {
|
|
16512
|
+
let result = node;
|
|
16513
|
+
while (RESPONSE_PREFIX_RE.test(result)) {
|
|
16514
|
+
result = result.replace(RESPONSE_PREFIX_RE, "");
|
|
16476
16515
|
}
|
|
16477
|
-
|
|
16478
|
-
const part2 = parts.slice(1).join(delim).replace(unescapeRe, delim);
|
|
16479
|
-
return [part1, part2];
|
|
16516
|
+
return result;
|
|
16480
16517
|
}
|
|
16481
16518
|
function validatePattern(type, pattern, responseDef) {
|
|
16482
16519
|
if (pattern.trim() !== pattern) {
|
|
16483
16520
|
throw new Scorm2004ValidationError("cmi.interactions.n.correct_responses.n.pattern", scorm2004_errors.TYPE_MISMATCH);
|
|
16484
16521
|
}
|
|
16485
|
-
const
|
|
16486
|
-
const rawNodes = subDelim1 ? splitUnescaped(pattern, subDelim1) : [pattern];
|
|
16522
|
+
const rawNodes = responseDef.delimiter ? splitDelimited(pattern, responseDef.delimiter) : [pattern];
|
|
16487
16523
|
for (const raw of rawNodes) {
|
|
16488
16524
|
if (raw.trim() !== raw) {
|
|
16489
16525
|
throw new Scorm2004ValidationError("cmi.interactions.n.correct_responses.n.pattern", scorm2004_errors.TYPE_MISMATCH);
|
|
@@ -16492,17 +16528,11 @@ ${stackTrace}`);
|
|
|
16492
16528
|
if (type === "fill-in" && pattern === "") {
|
|
16493
16529
|
return;
|
|
16494
16530
|
}
|
|
16495
|
-
const
|
|
16496
|
-
let nodes;
|
|
16497
|
-
if (delim1) {
|
|
16498
|
-
nodes = splitUnescaped(pattern, delim1);
|
|
16499
|
-
} else {
|
|
16500
|
-
nodes = [pattern];
|
|
16501
|
-
}
|
|
16531
|
+
const nodes = responseDef.delimiter ? splitDelimited(pattern, responseDef.delimiter) : [pattern];
|
|
16502
16532
|
if (!responseDef.delimiter && pattern.includes(",")) {
|
|
16503
16533
|
throw new Scorm2004ValidationError("cmi.interactions.n.correct_responses.n.pattern", scorm2004_errors.TYPE_MISMATCH);
|
|
16504
16534
|
}
|
|
16505
|
-
if (responseDef.unique || responseDef.duplicate === false) {
|
|
16535
|
+
if (type !== "numeric" && (responseDef.unique || responseDef.duplicate === false)) {
|
|
16506
16536
|
const seen = new Set(nodes);
|
|
16507
16537
|
if (seen.size !== nodes.length) {
|
|
16508
16538
|
throw new Scorm2004ValidationError("cmi.interactions.n.correct_responses.n.pattern", scorm2004_errors.TYPE_MISMATCH);
|
|
@@ -16522,8 +16552,7 @@ ${stackTrace}`);
|
|
|
16522
16552
|
if (!delimBracketed) {
|
|
16523
16553
|
throw new Scorm2004ValidationError("cmi.interactions.n.correct_responses.n.pattern", scorm2004_errors.TYPE_MISMATCH);
|
|
16524
16554
|
}
|
|
16525
|
-
const
|
|
16526
|
-
const parts = value.split(new RegExp(`(?<!\\\\)${escapeRegex(delim)}`, "g")).map(n => n.replace(new RegExp(`\\\\${escapeRegex(delim)}`, "g"), delim));
|
|
16555
|
+
const parts = splitDelimited(value, delimBracketed);
|
|
16527
16556
|
if (parts.length !== 2 || parts[0] === "" || parts[1] === "") {
|
|
16528
16557
|
throw new Scorm2004ValidationError("cmi.interactions.n.correct_responses.n.pattern", scorm2004_errors.TYPE_MISMATCH);
|
|
16529
16558
|
}
|
|
@@ -16535,12 +16564,14 @@ ${stackTrace}`);
|
|
|
16535
16564
|
switch (type) {
|
|
16536
16565
|
case "numeric":
|
|
16537
16566
|
{
|
|
16538
|
-
|
|
16539
|
-
|
|
16540
|
-
|
|
16541
|
-
|
|
16567
|
+
if (node === "") {
|
|
16568
|
+
const bracketedRange = nodes.length >= 2 && !!responseDef.delimiter && pattern.includes(responseDef.delimiter);
|
|
16569
|
+
if (!bracketedRange) {
|
|
16570
|
+
throw new Scorm2004ValidationError("cmi.interactions.n.correct_responses.n.pattern", scorm2004_errors.TYPE_MISMATCH);
|
|
16571
|
+
}
|
|
16572
|
+
break;
|
|
16542
16573
|
}
|
|
16543
|
-
|
|
16574
|
+
checkSingle(node);
|
|
16544
16575
|
break;
|
|
16545
16576
|
}
|
|
16546
16577
|
case "performance":
|
|
@@ -16549,13 +16580,13 @@ ${stackTrace}`);
|
|
|
16549
16580
|
if (!delimBracketed) {
|
|
16550
16581
|
throw new Scorm2004ValidationError("cmi.interactions.n.correct_responses.n.pattern", scorm2004_errors.TYPE_MISMATCH);
|
|
16551
16582
|
}
|
|
16552
|
-
const
|
|
16553
|
-
const parts =
|
|
16583
|
+
const record = stripResponsePrefixes(node);
|
|
16584
|
+
const parts = splitFirstDelimited(record, delimBracketed);
|
|
16554
16585
|
if (parts.length !== 2) {
|
|
16555
16586
|
throw new Scorm2004ValidationError("cmi.interactions.n.correct_responses.n.pattern", scorm2004_errors.TYPE_MISMATCH);
|
|
16556
16587
|
}
|
|
16557
16588
|
const [part1, part2] = parts;
|
|
16558
|
-
if (part1 === ""
|
|
16589
|
+
if (part1 === "" && part2 === "") {
|
|
16559
16590
|
throw new Scorm2004ValidationError("cmi.interactions.n.correct_responses.n.pattern", scorm2004_errors.TYPE_MISMATCH);
|
|
16560
16591
|
}
|
|
16561
16592
|
if (part1 === void 0 || !fmt1.test(part1)) {
|
|
@@ -19510,7 +19541,7 @@ ${stackTrace}`);
|
|
|
19510
19541
|
checkValidResponseType(CMIElement, response_type, value, interaction_type) {
|
|
19511
19542
|
let nodes = [];
|
|
19512
19543
|
if (response_type?.delimiter) {
|
|
19513
|
-
nodes = String(value)
|
|
19544
|
+
nodes = splitDelimited(String(value), response_type.delimiter);
|
|
19514
19545
|
} else {
|
|
19515
19546
|
nodes[0] = value;
|
|
19516
19547
|
}
|
|
@@ -19608,26 +19639,33 @@ ${stackTrace}`);
|
|
|
19608
19639
|
nodes[i] = this.removeCorrectResponsePrefixes(CMIElement, nodes[i]);
|
|
19609
19640
|
}
|
|
19610
19641
|
if (response?.delimiter2) {
|
|
19611
|
-
const values = nodes[i].
|
|
19642
|
+
const values = interaction_type === "performance" ? splitFirstDelimited(nodes[i], response.delimiter2) : splitDelimited(nodes[i], response.delimiter2);
|
|
19612
19643
|
if (values.length === 2) {
|
|
19613
|
-
|
|
19614
|
-
if (!matches) {
|
|
19644
|
+
if (interaction_type === "performance" && values[0] === "" && values[1] === "") {
|
|
19615
19645
|
this.context.throwSCORMError(CMIElement, scorm2004_errors.TYPE_MISMATCH, `${interaction_type}: ${value}`);
|
|
19616
19646
|
} else {
|
|
19617
|
-
|
|
19647
|
+
const matches = values[0]?.match(formatRegex);
|
|
19648
|
+
if (!matches) {
|
|
19618
19649
|
this.context.throwSCORMError(CMIElement, scorm2004_errors.TYPE_MISMATCH, `${interaction_type}: ${value}`);
|
|
19650
|
+
} else {
|
|
19651
|
+
if (!response.format2 || !values[1]?.match(new RegExp(response.format2))) {
|
|
19652
|
+
this.context.throwSCORMError(CMIElement, scorm2004_errors.TYPE_MISMATCH, `${interaction_type}: ${value}`);
|
|
19653
|
+
}
|
|
19619
19654
|
}
|
|
19620
19655
|
}
|
|
19621
19656
|
} else {
|
|
19622
19657
|
this.context.throwSCORMError(CMIElement, scorm2004_errors.TYPE_MISMATCH, `${interaction_type}: ${value}`);
|
|
19623
19658
|
}
|
|
19624
19659
|
} else {
|
|
19660
|
+
if (interaction_type === "numeric" && nodes.length > 1 && nodes[i] === "" && !!response.delimiter && String(value).includes(response.delimiter)) {
|
|
19661
|
+
continue;
|
|
19662
|
+
}
|
|
19625
19663
|
const matches = nodes[i].match(formatRegex);
|
|
19626
19664
|
if (!matches && value !== "" || !matches && interaction_type === "true-false") {
|
|
19627
19665
|
this.context.throwSCORMError(CMIElement, scorm2004_errors.TYPE_MISMATCH, `${interaction_type}: ${value}`);
|
|
19628
19666
|
} else {
|
|
19629
19667
|
if (interaction_type === "numeric" && nodes.length > 1) {
|
|
19630
|
-
if (Number(nodes[0]) > Number(nodes[1])) {
|
|
19668
|
+
if (nodes[0] !== "" && nodes[1] !== "" && Number(nodes[0]) > Number(nodes[1])) {
|
|
19631
19669
|
this.context.throwSCORMError(CMIElement, scorm2004_errors.TYPE_MISMATCH, `${interaction_type}: ${value}`);
|
|
19632
19670
|
}
|
|
19633
19671
|
} else {
|