scorm-again 3.0.3 → 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 +133 -68
- 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 +20 -5
- 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 +133 -68
- 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 +261 -166
- 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 +14 -6
- 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 +261 -166
- 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 +46 -25
package/dist/esm/scorm2004.js
CHANGED
|
@@ -940,6 +940,11 @@ const scorm2004_regex = {
|
|
|
940
940
|
progress_range: "0#1"
|
|
941
941
|
};
|
|
942
942
|
|
|
943
|
+
const PERFORMANCE_STEP_NAME = "^$|" + scorm2004_regex.CMIShortIdentifier;
|
|
944
|
+
const PERFORMANCE_CHARACTERSTRING = "(?![\\s\\S]*(?:\\[,\\]|\\[\\.\\]|\\[:\\]))[\\s\\S]{1,250}";
|
|
945
|
+
const PERFORMANCE_NUMERIC_RANGE = "(?:-?\\d+(?:\\.\\d+)?)?\\[:\\](?:-?\\d+(?:\\.\\d+)?)?";
|
|
946
|
+
const CR_PERFORMANCE_STEP_ANSWER = "^(?:|" + PERFORMANCE_NUMERIC_RANGE + "|" + PERFORMANCE_CHARACTERSTRING + ")$";
|
|
947
|
+
const LR_PERFORMANCE_STEP_ANSWER = "^(?:|" + PERFORMANCE_CHARACTERSTRING + ")$";
|
|
943
948
|
const LearnerResponses = {
|
|
944
949
|
"true-false": {
|
|
945
950
|
format: "^true$|^false$",
|
|
@@ -974,8 +979,8 @@ const LearnerResponses = {
|
|
|
974
979
|
unique: false
|
|
975
980
|
},
|
|
976
981
|
performance: {
|
|
977
|
-
format:
|
|
978
|
-
format2:
|
|
982
|
+
format: PERFORMANCE_STEP_NAME,
|
|
983
|
+
format2: LR_PERFORMANCE_STEP_ANSWER,
|
|
979
984
|
max: 250,
|
|
980
985
|
delimiter: "[,]",
|
|
981
986
|
delimiter2: "[.]",
|
|
@@ -1051,10 +1056,10 @@ const CorrectResponses = {
|
|
|
1051
1056
|
delimiter2: "[.]",
|
|
1052
1057
|
unique: false,
|
|
1053
1058
|
duplicate: false,
|
|
1054
|
-
// step_name
|
|
1055
|
-
format:
|
|
1056
|
-
// step_answer
|
|
1057
|
-
format2:
|
|
1059
|
+
// step_name: optional short_identifier_type
|
|
1060
|
+
format: PERFORMANCE_STEP_NAME,
|
|
1061
|
+
// step_answer: optional characterstring (spaces allowed) or numeric range
|
|
1062
|
+
format2: CR_PERFORMANCE_STEP_ANSWER
|
|
1058
1063
|
},
|
|
1059
1064
|
sequencing: {
|
|
1060
1065
|
max: 36,
|
|
@@ -2098,6 +2103,7 @@ class ActivityTreeQueries {
|
|
|
2098
2103
|
constructor(activityTree) {
|
|
2099
2104
|
this.activityTree = activityTree;
|
|
2100
2105
|
}
|
|
2106
|
+
activityTree;
|
|
2101
2107
|
/**
|
|
2102
2108
|
* Check if activity is in the activity tree
|
|
2103
2109
|
* @param {Activity} activity - Activity to check
|
|
@@ -2297,6 +2303,8 @@ class ChoiceConstraintValidator {
|
|
|
2297
2303
|
this.activityTree = activityTree;
|
|
2298
2304
|
this.treeQueries = treeQueries;
|
|
2299
2305
|
}
|
|
2306
|
+
activityTree;
|
|
2307
|
+
treeQueries;
|
|
2300
2308
|
/**
|
|
2301
2309
|
* Main entry point - consolidates ALL constraint validation for choice navigation
|
|
2302
2310
|
* @param {Activity | null} currentActivity - Current activity (may be null if no session started)
|
|
@@ -3649,6 +3657,8 @@ class FlowTraversalService {
|
|
|
3649
3657
|
this.activityTree = activityTree;
|
|
3650
3658
|
this.ruleEngine = ruleEngine;
|
|
3651
3659
|
}
|
|
3660
|
+
activityTree;
|
|
3661
|
+
ruleEngine;
|
|
3652
3662
|
/**
|
|
3653
3663
|
* Flow Subprocess (SB.2.3)
|
|
3654
3664
|
* Traverses the activity tree in the specified direction to find a deliverable activity
|
|
@@ -3947,6 +3957,8 @@ class FlowRequestHandler {
|
|
|
3947
3957
|
this.activityTree = activityTree;
|
|
3948
3958
|
this.traversalService = traversalService;
|
|
3949
3959
|
}
|
|
3960
|
+
activityTree;
|
|
3961
|
+
traversalService;
|
|
3950
3962
|
/**
|
|
3951
3963
|
* Start Sequencing Request Process (SB.2.5)
|
|
3952
3964
|
* Initiates a new sequencing session from the root
|
|
@@ -4078,6 +4090,10 @@ class ChoiceRequestHandler {
|
|
|
4078
4090
|
this.traversalService = traversalService;
|
|
4079
4091
|
this.treeQueries = treeQueries;
|
|
4080
4092
|
}
|
|
4093
|
+
activityTree;
|
|
4094
|
+
constraintValidator;
|
|
4095
|
+
traversalService;
|
|
4096
|
+
treeQueries;
|
|
4081
4097
|
/**
|
|
4082
4098
|
* Choice Sequencing Request Process (SB.2.9)
|
|
4083
4099
|
* Processes a choice navigation request to a specific activity
|
|
@@ -4291,6 +4307,8 @@ class ExitRequestHandler {
|
|
|
4291
4307
|
this.activityTree = activityTree;
|
|
4292
4308
|
this.ruleEngine = ruleEngine;
|
|
4293
4309
|
}
|
|
4310
|
+
activityTree;
|
|
4311
|
+
ruleEngine;
|
|
4294
4312
|
/**
|
|
4295
4313
|
* Exit Sequencing Request Process (SB.2.11)
|
|
4296
4314
|
* @param {Activity} currentActivity - The current activity
|
|
@@ -4406,6 +4424,8 @@ class RetryRequestHandler {
|
|
|
4406
4424
|
this.activityTree = activityTree;
|
|
4407
4425
|
this.traversalService = traversalService;
|
|
4408
4426
|
}
|
|
4427
|
+
activityTree;
|
|
4428
|
+
traversalService;
|
|
4409
4429
|
/**
|
|
4410
4430
|
* Retry Sequencing Request Process (SB.2.10)
|
|
4411
4431
|
* @param {Activity} currentActivity - The current activity
|
|
@@ -5348,7 +5368,19 @@ class CMIValueAccessService {
|
|
|
5348
5368
|
if (!scorm2004) {
|
|
5349
5369
|
if (isFinalAttribute) {
|
|
5350
5370
|
if (typeof attribute === "undefined" || !this.context.checkObjectHasProperty(refObject, attribute)) {
|
|
5351
|
-
|
|
5371
|
+
if (attribute === "_children") {
|
|
5372
|
+
this.context.throwSCORMError(
|
|
5373
|
+
CMIElement,
|
|
5374
|
+
getErrorCode(this.context.errorCodes, "CHILDREN_ERROR")
|
|
5375
|
+
);
|
|
5376
|
+
} else if (attribute === "_count") {
|
|
5377
|
+
this.context.throwSCORMError(
|
|
5378
|
+
CMIElement,
|
|
5379
|
+
getErrorCode(this.context.errorCodes, "COUNT_ERROR")
|
|
5380
|
+
);
|
|
5381
|
+
} else {
|
|
5382
|
+
this.context.throwSCORMError(CMIElement, invalidErrorCode, invalidErrorMessage);
|
|
5383
|
+
}
|
|
5352
5384
|
return { error: true };
|
|
5353
5385
|
}
|
|
5354
5386
|
}
|
|
@@ -5540,7 +5572,8 @@ class LoggingService {
|
|
|
5540
5572
|
getNumericLevel(level) {
|
|
5541
5573
|
if (level === void 0) return LogLevelEnum.NONE;
|
|
5542
5574
|
if (typeof level === "number") return level;
|
|
5543
|
-
|
|
5575
|
+
const normalized = typeof level === "string" ? level.toUpperCase() : level;
|
|
5576
|
+
switch (normalized) {
|
|
5544
5577
|
case "1":
|
|
5545
5578
|
case "DEBUG":
|
|
5546
5579
|
return LogLevelEnum.DEBUG;
|
|
@@ -5913,6 +5946,7 @@ class OfflineStorageService {
|
|
|
5913
5946
|
window.addEventListener("offline", this.boundOnlineStatusChangeHandler);
|
|
5914
5947
|
window.addEventListener("scorm-again:network-status", this.boundCustomNetworkStatusHandler);
|
|
5915
5948
|
}
|
|
5949
|
+
apiLog;
|
|
5916
5950
|
settings;
|
|
5917
5951
|
error_codes;
|
|
5918
5952
|
storeName = "scorm_again_offline_data";
|
|
@@ -15750,7 +15784,8 @@ class BaseAPI {
|
|
|
15750
15784
|
if (errorCode === 143) returnValue = global_constants.SCORM_FALSE;
|
|
15751
15785
|
} else {
|
|
15752
15786
|
const result = this.storeData(false);
|
|
15753
|
-
|
|
15787
|
+
const errorCode = result.errorCode ?? 0;
|
|
15788
|
+
if (errorCode > 0) {
|
|
15754
15789
|
if (result.errorMessage) {
|
|
15755
15790
|
this.apiLog(
|
|
15756
15791
|
"commit",
|
|
@@ -15765,12 +15800,12 @@ class BaseAPI {
|
|
|
15765
15800
|
LogLevelEnum.DEBUG
|
|
15766
15801
|
);
|
|
15767
15802
|
}
|
|
15768
|
-
this.throwSCORMError("api",
|
|
15803
|
+
this.throwSCORMError("api", errorCode);
|
|
15769
15804
|
}
|
|
15770
15805
|
const resultValue = result?.result ?? global_constants.SCORM_FALSE;
|
|
15771
15806
|
returnValue = typeof resultValue === "boolean" ? String(resultValue) : resultValue;
|
|
15772
15807
|
this.apiLog(callbackName, " Result: " + returnValue, LogLevelEnum.DEBUG, "HttpRequest");
|
|
15773
|
-
if (checkTerminated) this.lastErrorCode = "0";
|
|
15808
|
+
if (checkTerminated && errorCode === 0) this.lastErrorCode = "0";
|
|
15774
15809
|
this.processListeners(callbackName);
|
|
15775
15810
|
if (this.settings.enableOfflineSupport && this._offlineStorageService && this._offlineStorageService.isDeviceOnline() && this._courseId) {
|
|
15776
15811
|
this._offlineStorageService.hasPendingOfflineData(this._courseId).then((hasPendingData) => {
|
|
@@ -16542,6 +16577,49 @@ class CMILearnerPreference extends BaseCMI {
|
|
|
16542
16577
|
}
|
|
16543
16578
|
}
|
|
16544
16579
|
|
|
16580
|
+
function stripBrackets(delim) {
|
|
16581
|
+
return delim.replace(/[[\]]/g, "");
|
|
16582
|
+
}
|
|
16583
|
+
function escapeRegex(s) {
|
|
16584
|
+
return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
16585
|
+
}
|
|
16586
|
+
function splitDelimited(value, bracketed) {
|
|
16587
|
+
if (!bracketed) {
|
|
16588
|
+
return [value];
|
|
16589
|
+
}
|
|
16590
|
+
if (value.includes(bracketed)) {
|
|
16591
|
+
return value.split(bracketed);
|
|
16592
|
+
}
|
|
16593
|
+
const bare = stripBrackets(bracketed);
|
|
16594
|
+
if (!bare) {
|
|
16595
|
+
return [value];
|
|
16596
|
+
}
|
|
16597
|
+
const splitRe = new RegExp(`(?<!\\\\)${escapeRegex(bare)}`, "g");
|
|
16598
|
+
const unescapeRe = new RegExp(`\\\\${escapeRegex(bare)}`, "g");
|
|
16599
|
+
return value.split(splitRe).map((part) => part.replace(unescapeRe, bare));
|
|
16600
|
+
}
|
|
16601
|
+
function splitFirstDelimited(value, bracketed) {
|
|
16602
|
+
if (!bracketed) {
|
|
16603
|
+
return [value];
|
|
16604
|
+
}
|
|
16605
|
+
if (value.includes(bracketed)) {
|
|
16606
|
+
const idx = value.indexOf(bracketed);
|
|
16607
|
+
return [value.slice(0, idx), value.slice(idx + bracketed.length)];
|
|
16608
|
+
}
|
|
16609
|
+
const bare = stripBrackets(bracketed);
|
|
16610
|
+
if (!bare) {
|
|
16611
|
+
return [value];
|
|
16612
|
+
}
|
|
16613
|
+
const splitRe = new RegExp(`(?<!\\\\)${escapeRegex(bare)}`);
|
|
16614
|
+
const unescapeRe = new RegExp(`\\\\${escapeRegex(bare)}`, "g");
|
|
16615
|
+
const parts = value.split(splitRe);
|
|
16616
|
+
const first = (parts[0] ?? "").replace(unescapeRe, bare);
|
|
16617
|
+
if (parts.length === 1) {
|
|
16618
|
+
return [first];
|
|
16619
|
+
}
|
|
16620
|
+
return [first, parts.slice(1).join(bare).replace(unescapeRe, bare)];
|
|
16621
|
+
}
|
|
16622
|
+
|
|
16545
16623
|
class CMIInteractions extends CMIArray {
|
|
16546
16624
|
/**
|
|
16547
16625
|
* Constructor for `cmi.interactions` Array
|
|
@@ -16751,8 +16829,7 @@ class CMIInteractionsObject extends BaseCMI {
|
|
|
16751
16829
|
const response_type = LearnerResponses[this.type];
|
|
16752
16830
|
if (response_type) {
|
|
16753
16831
|
if (response_type?.delimiter) {
|
|
16754
|
-
|
|
16755
|
-
nodes = learner_response.split(delimiter);
|
|
16832
|
+
nodes = splitDelimited(learner_response, response_type.delimiter);
|
|
16756
16833
|
} else {
|
|
16757
16834
|
nodes[0] = learner_response;
|
|
16758
16835
|
}
|
|
@@ -16760,10 +16837,10 @@ class CMIInteractionsObject extends BaseCMI {
|
|
|
16760
16837
|
const formatRegex = new RegExp(response_type.format);
|
|
16761
16838
|
for (let i = 0; i < nodes.length; i++) {
|
|
16762
16839
|
if (response_type?.delimiter2) {
|
|
16763
|
-
const
|
|
16764
|
-
const values =
|
|
16840
|
+
const node = nodes[i] ?? "";
|
|
16841
|
+
const values = this.type === "performance" ? splitFirstDelimited(node, response_type.delimiter2) : splitDelimited(node, response_type.delimiter2);
|
|
16765
16842
|
if (values?.length === 2) {
|
|
16766
|
-
if (this.type === "performance" &&
|
|
16843
|
+
if (this.type === "performance" && values[0] === "" && values[1] === "") {
|
|
16767
16844
|
throw new Scorm2004ValidationError(
|
|
16768
16845
|
this._cmi_element + ".learner_response",
|
|
16769
16846
|
scorm2004_errors.TYPE_MISMATCH
|
|
@@ -16982,30 +17059,13 @@ class CMIInteractionsObjectivesObject extends BaseCMI {
|
|
|
16982
17059
|
return result;
|
|
16983
17060
|
}
|
|
16984
17061
|
}
|
|
16985
|
-
|
|
16986
|
-
|
|
16987
|
-
|
|
16988
|
-
|
|
16989
|
-
|
|
16990
|
-
}
|
|
16991
|
-
function splitUnescaped(text, delim) {
|
|
16992
|
-
const reDelim = escapeRegex(delim);
|
|
16993
|
-
const splitRe = new RegExp(`(?<!\\\\)${reDelim}`, "g");
|
|
16994
|
-
const unescapeRe = new RegExp(`\\\\${reDelim}`, "g");
|
|
16995
|
-
return text.split(splitRe).map((part) => part.replace(unescapeRe, delim));
|
|
16996
|
-
}
|
|
16997
|
-
function splitFirstUnescaped(text, delim) {
|
|
16998
|
-
const reDelim = escapeRegex(delim);
|
|
16999
|
-
const splitRe = new RegExp(`(?<!\\\\)${reDelim}`);
|
|
17000
|
-
const unescapeRe = new RegExp(`\\\\${reDelim}`, "g");
|
|
17001
|
-
const parts = text.split(splitRe);
|
|
17002
|
-
const firstPart = parts[0] ?? "";
|
|
17003
|
-
if (parts.length === 1) {
|
|
17004
|
-
return [firstPart.replace(unescapeRe, delim)];
|
|
17062
|
+
const RESPONSE_PREFIX_RE = /^\{(?:lang|case_matters|order_matters)=[^}]+\}/;
|
|
17063
|
+
function stripResponsePrefixes(node) {
|
|
17064
|
+
let result = node;
|
|
17065
|
+
while (RESPONSE_PREFIX_RE.test(result)) {
|
|
17066
|
+
result = result.replace(RESPONSE_PREFIX_RE, "");
|
|
17005
17067
|
}
|
|
17006
|
-
|
|
17007
|
-
const part2 = parts.slice(1).join(delim).replace(unescapeRe, delim);
|
|
17008
|
-
return [part1, part2];
|
|
17068
|
+
return result;
|
|
17009
17069
|
}
|
|
17010
17070
|
function validatePattern(type, pattern, responseDef) {
|
|
17011
17071
|
if (pattern.trim() !== pattern) {
|
|
@@ -17014,8 +17074,7 @@ function validatePattern(type, pattern, responseDef) {
|
|
|
17014
17074
|
scorm2004_errors.TYPE_MISMATCH
|
|
17015
17075
|
);
|
|
17016
17076
|
}
|
|
17017
|
-
const
|
|
17018
|
-
const rawNodes = subDelim1 ? splitUnescaped(pattern, subDelim1) : [pattern];
|
|
17077
|
+
const rawNodes = responseDef.delimiter ? splitDelimited(pattern, responseDef.delimiter) : [pattern];
|
|
17019
17078
|
for (const raw of rawNodes) {
|
|
17020
17079
|
if (raw.trim() !== raw) {
|
|
17021
17080
|
throw new Scorm2004ValidationError(
|
|
@@ -17027,20 +17086,14 @@ function validatePattern(type, pattern, responseDef) {
|
|
|
17027
17086
|
if (type === "fill-in" && pattern === "") {
|
|
17028
17087
|
return;
|
|
17029
17088
|
}
|
|
17030
|
-
const
|
|
17031
|
-
let nodes;
|
|
17032
|
-
if (delim1) {
|
|
17033
|
-
nodes = splitUnescaped(pattern, delim1);
|
|
17034
|
-
} else {
|
|
17035
|
-
nodes = [pattern];
|
|
17036
|
-
}
|
|
17089
|
+
const nodes = responseDef.delimiter ? splitDelimited(pattern, responseDef.delimiter) : [pattern];
|
|
17037
17090
|
if (!responseDef.delimiter && pattern.includes(",")) {
|
|
17038
17091
|
throw new Scorm2004ValidationError(
|
|
17039
17092
|
"cmi.interactions.n.correct_responses.n.pattern",
|
|
17040
17093
|
scorm2004_errors.TYPE_MISMATCH
|
|
17041
17094
|
);
|
|
17042
17095
|
}
|
|
17043
|
-
if (responseDef.unique || responseDef.duplicate === false) {
|
|
17096
|
+
if (type !== "numeric" && (responseDef.unique || responseDef.duplicate === false)) {
|
|
17044
17097
|
const seen = new Set(nodes);
|
|
17045
17098
|
if (seen.size !== nodes.length) {
|
|
17046
17099
|
throw new Scorm2004ValidationError(
|
|
@@ -17072,8 +17125,7 @@ function validatePattern(type, pattern, responseDef) {
|
|
|
17072
17125
|
scorm2004_errors.TYPE_MISMATCH
|
|
17073
17126
|
);
|
|
17074
17127
|
}
|
|
17075
|
-
const
|
|
17076
|
-
const parts = value.split(new RegExp(`(?<!\\\\)${escapeRegex(delim)}`, "g")).map((n) => n.replace(new RegExp(`\\\\${escapeRegex(delim)}`, "g"), delim));
|
|
17128
|
+
const parts = splitDelimited(value, delimBracketed);
|
|
17077
17129
|
if (parts.length !== 2 || parts[0] === "" || parts[1] === "") {
|
|
17078
17130
|
throw new Scorm2004ValidationError(
|
|
17079
17131
|
"cmi.interactions.n.correct_responses.n.pattern",
|
|
@@ -17090,15 +17142,17 @@ function validatePattern(type, pattern, responseDef) {
|
|
|
17090
17142
|
for (const node of nodes) {
|
|
17091
17143
|
switch (type) {
|
|
17092
17144
|
case "numeric": {
|
|
17093
|
-
|
|
17094
|
-
|
|
17095
|
-
|
|
17096
|
-
|
|
17097
|
-
|
|
17098
|
-
|
|
17099
|
-
|
|
17145
|
+
if (node === "") {
|
|
17146
|
+
const bracketedRange = nodes.length >= 2 && !!responseDef.delimiter && pattern.includes(responseDef.delimiter);
|
|
17147
|
+
if (!bracketedRange) {
|
|
17148
|
+
throw new Scorm2004ValidationError(
|
|
17149
|
+
"cmi.interactions.n.correct_responses.n.pattern",
|
|
17150
|
+
scorm2004_errors.TYPE_MISMATCH
|
|
17151
|
+
);
|
|
17152
|
+
}
|
|
17153
|
+
break;
|
|
17100
17154
|
}
|
|
17101
|
-
|
|
17155
|
+
checkSingle(node);
|
|
17102
17156
|
break;
|
|
17103
17157
|
}
|
|
17104
17158
|
case "performance": {
|
|
@@ -17109,8 +17163,8 @@ function validatePattern(type, pattern, responseDef) {
|
|
|
17109
17163
|
scorm2004_errors.TYPE_MISMATCH
|
|
17110
17164
|
);
|
|
17111
17165
|
}
|
|
17112
|
-
const
|
|
17113
|
-
const parts =
|
|
17166
|
+
const record = stripResponsePrefixes(node);
|
|
17167
|
+
const parts = splitFirstDelimited(record, delimBracketed);
|
|
17114
17168
|
if (parts.length !== 2) {
|
|
17115
17169
|
throw new Scorm2004ValidationError(
|
|
17116
17170
|
"cmi.interactions.n.correct_responses.n.pattern",
|
|
@@ -17118,7 +17172,7 @@ function validatePattern(type, pattern, responseDef) {
|
|
|
17118
17172
|
);
|
|
17119
17173
|
}
|
|
17120
17174
|
const [part1, part2] = parts;
|
|
17121
|
-
if (part1 === ""
|
|
17175
|
+
if (part1 === "" && part2 === "") {
|
|
17122
17176
|
throw new Scorm2004ValidationError(
|
|
17123
17177
|
"cmi.interactions.n.correct_responses.n.pattern",
|
|
17124
17178
|
scorm2004_errors.TYPE_MISMATCH
|
|
@@ -20182,7 +20236,7 @@ class Scorm2004ResponseValidator {
|
|
|
20182
20236
|
checkValidResponseType(CMIElement, response_type, value, interaction_type) {
|
|
20183
20237
|
let nodes = [];
|
|
20184
20238
|
if (response_type?.delimiter) {
|
|
20185
|
-
nodes = String(value)
|
|
20239
|
+
nodes = splitDelimited(String(value), response_type.delimiter);
|
|
20186
20240
|
} else {
|
|
20187
20241
|
nodes[0] = value;
|
|
20188
20242
|
}
|
|
@@ -20304,22 +20358,30 @@ class Scorm2004ResponseValidator {
|
|
|
20304
20358
|
nodes[i] = this.removeCorrectResponsePrefixes(CMIElement, nodes[i]);
|
|
20305
20359
|
}
|
|
20306
20360
|
if (response?.delimiter2) {
|
|
20307
|
-
const values = nodes[i].
|
|
20361
|
+
const values = interaction_type === "performance" ? splitFirstDelimited(nodes[i], response.delimiter2) : splitDelimited(nodes[i], response.delimiter2);
|
|
20308
20362
|
if (values.length === 2) {
|
|
20309
|
-
|
|
20310
|
-
if (!matches) {
|
|
20363
|
+
if (interaction_type === "performance" && values[0] === "" && values[1] === "") {
|
|
20311
20364
|
this.context.throwSCORMError(
|
|
20312
20365
|
CMIElement,
|
|
20313
20366
|
scorm2004_errors.TYPE_MISMATCH,
|
|
20314
20367
|
`${interaction_type}: ${value}`
|
|
20315
20368
|
);
|
|
20316
20369
|
} else {
|
|
20317
|
-
|
|
20370
|
+
const matches = values[0]?.match(formatRegex);
|
|
20371
|
+
if (!matches) {
|
|
20318
20372
|
this.context.throwSCORMError(
|
|
20319
20373
|
CMIElement,
|
|
20320
20374
|
scorm2004_errors.TYPE_MISMATCH,
|
|
20321
20375
|
`${interaction_type}: ${value}`
|
|
20322
20376
|
);
|
|
20377
|
+
} else {
|
|
20378
|
+
if (!response.format2 || !values[1]?.match(new RegExp(response.format2))) {
|
|
20379
|
+
this.context.throwSCORMError(
|
|
20380
|
+
CMIElement,
|
|
20381
|
+
scorm2004_errors.TYPE_MISMATCH,
|
|
20382
|
+
`${interaction_type}: ${value}`
|
|
20383
|
+
);
|
|
20384
|
+
}
|
|
20323
20385
|
}
|
|
20324
20386
|
}
|
|
20325
20387
|
} else {
|
|
@@ -20330,6 +20392,9 @@ class Scorm2004ResponseValidator {
|
|
|
20330
20392
|
);
|
|
20331
20393
|
}
|
|
20332
20394
|
} else {
|
|
20395
|
+
if (interaction_type === "numeric" && nodes.length > 1 && nodes[i] === "" && !!response.delimiter && String(value).includes(response.delimiter)) {
|
|
20396
|
+
continue;
|
|
20397
|
+
}
|
|
20333
20398
|
const matches = nodes[i].match(formatRegex);
|
|
20334
20399
|
if (!matches && value !== "" || !matches && interaction_type === "true-false") {
|
|
20335
20400
|
this.context.throwSCORMError(
|
|
@@ -20339,7 +20404,7 @@ class Scorm2004ResponseValidator {
|
|
|
20339
20404
|
);
|
|
20340
20405
|
} else {
|
|
20341
20406
|
if (interaction_type === "numeric" && nodes.length > 1) {
|
|
20342
|
-
if (Number(nodes[0]) > Number(nodes[1])) {
|
|
20407
|
+
if (nodes[0] !== "" && nodes[1] !== "" && Number(nodes[0]) > Number(nodes[1])) {
|
|
20343
20408
|
this.context.throwSCORMError(
|
|
20344
20409
|
CMIElement,
|
|
20345
20410
|
scorm2004_errors.TYPE_MISMATCH,
|