@citolab/qti-components 7.28.0 → 8.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.
Files changed (83) hide show
  1. package/cdn/index.global.js +1 -1
  2. package/cdn/index.js +6178 -2946
  3. package/dist/base.d.ts +9 -50
  4. package/dist/base.js +31 -6
  5. package/dist/chunk-5QYII4OZ.js +1374 -0
  6. package/dist/chunk-5QYII4OZ.js.map +1 -0
  7. package/dist/{chunk-FK2IVMS3.js → chunk-5SJS36BI.js} +4264 -3647
  8. package/dist/chunk-5SJS36BI.js.map +1 -0
  9. package/dist/chunk-64XSIBGO.js +241 -0
  10. package/dist/chunk-64XSIBGO.js.map +1 -0
  11. package/dist/{chunk-F6WP6WEF.js → chunk-7V4HJFHW.js} +3 -3
  12. package/dist/{chunk-F6WP6WEF.js.map → chunk-7V4HJFHW.js.map} +1 -1
  13. package/dist/{chunk-Z2SUBRH5.js → chunk-H3J7LFRO.js} +834 -1005
  14. package/dist/chunk-H3J7LFRO.js.map +1 -0
  15. package/dist/chunk-IJD53WY6.js +719 -0
  16. package/dist/chunk-IJD53WY6.js.map +1 -0
  17. package/dist/chunk-KYEZRYO6.js +1608 -0
  18. package/dist/chunk-KYEZRYO6.js.map +1 -0
  19. package/dist/{chunk-PINGOK2F.js → chunk-LZJHHZQ2.js} +1979 -1775
  20. package/dist/chunk-LZJHHZQ2.js.map +1 -0
  21. package/dist/chunk-MGF5F3S2.js +11 -0
  22. package/dist/chunk-MGF5F3S2.js.map +1 -0
  23. package/dist/chunk-MJVPNN7W.js +11 -0
  24. package/dist/chunk-MJVPNN7W.js.map +1 -0
  25. package/dist/{chunk-YLIYPNMK.js → chunk-NA2N2WSG.js} +1303 -1193
  26. package/dist/chunk-NA2N2WSG.js.map +1 -0
  27. package/dist/chunk-V5G7X53Y.js +11 -0
  28. package/dist/chunk-V5G7X53Y.js.map +1 -0
  29. package/dist/chunk-W4QZPCNC.js +294 -0
  30. package/dist/chunk-W4QZPCNC.js.map +1 -0
  31. package/dist/chunk-WCQ26LV7.js +102 -0
  32. package/dist/chunk-WCQ26LV7.js.map +1 -0
  33. package/dist/{chunk-OQ77SE2W.js → chunk-WVVMNF74.js} +851 -925
  34. package/dist/chunk-WVVMNF74.js.map +1 -0
  35. package/dist/{chunk-N7S3GNUP.js → chunk-X3E5HXG2.js} +2 -2
  36. package/dist/corrections.d.ts +1 -0
  37. package/dist/corrections.js +84 -0
  38. package/dist/elements.d.ts +1 -399
  39. package/dist/elements.js +6 -5
  40. package/dist/index.d.ts +9 -23
  41. package/dist/index.js +189 -76
  42. package/dist/interactions.d.ts +1 -915
  43. package/dist/interactions.js +19 -15
  44. package/dist/item.css +4118 -1920
  45. package/dist/item.d.ts +1 -127
  46. package/dist/item.js +6 -11
  47. package/dist/loader.d.ts +1 -22
  48. package/dist/loader.js +2 -3
  49. package/dist/processing.d.ts +1 -731
  50. package/dist/processing.js +2 -3
  51. package/dist/qti-components-jsx.d.ts +5394 -2718
  52. package/dist/test.d.ts +1 -537
  53. package/dist/test.js +26 -11
  54. package/dist/transformers.d.ts +1 -18
  55. package/dist/transformers.js +1 -2
  56. package/package.json +20 -16
  57. package/custom-elements.json +0 -43161
  58. package/dist/chunk-BPIDAS3T.js +0 -495
  59. package/dist/chunk-BPIDAS3T.js.map +0 -1
  60. package/dist/chunk-FK2IVMS3.js.map +0 -1
  61. package/dist/chunk-LQZCSHN5.js +0 -3673
  62. package/dist/chunk-LQZCSHN5.js.map +0 -1
  63. package/dist/chunk-OQ77SE2W.js.map +0 -1
  64. package/dist/chunk-PINGOK2F.js.map +0 -1
  65. package/dist/chunk-QXBXORM3.js +0 -27
  66. package/dist/chunk-U2FLSHK7.js +0 -510
  67. package/dist/chunk-U2FLSHK7.js.map +0 -1
  68. package/dist/chunk-YLIYPNMK.js.map +0 -1
  69. package/dist/chunk-Z2SUBRH5.js.map +0 -1
  70. package/dist/computed-item.context-DfsW_96S.d.ts +0 -22
  71. package/dist/computed.context-DHbxad0N.d.ts +0 -45
  72. package/dist/config.context-BjZ2bZSY.d.ts +0 -42
  73. package/dist/interaction-Bgzlw7Iu.d.ts +0 -110
  74. package/dist/item.context-CkUeDcaO.d.ts +0 -15
  75. package/dist/qti-condition-expression-B1BYmCcq.d.ts +0 -26
  76. package/dist/qti-feedback-ChmXhZuf.d.ts +0 -21
  77. package/dist/qti-rule-base-ajOnfGXY.d.ts +0 -16
  78. package/dist/qti-transform-test-DMx816H0.d.ts +0 -68
  79. package/dist/qti.context-B8PSyIWm.d.ts +0 -14
  80. package/dist/test.context-CByZZjkR.d.ts +0 -15
  81. package/dist/variables-CMYcDbyW.d.ts +0 -70
  82. /package/dist/{chunk-N7S3GNUP.js.map → chunk-X3E5HXG2.js.map} +0 -0
  83. /package/dist/{chunk-QXBXORM3.js.map → corrections.js.map} +0 -0
@@ -0,0 +1,719 @@
1
+ // ../qti-transformers/dist/item/cdata.js
2
+ function convertCDATAtoComment(xmlFragment) {
3
+ const cdataElements = xmlFragment.querySelectorAll('qti-custom-operator[class="js.org"] > qti-base-value');
4
+ cdataElements.forEach((element) => {
5
+ const commentText = document.createComment(element.textContent);
6
+ element.replaceChild(commentText, element.firstChild);
7
+ });
8
+ }
9
+
10
+ // ../qti-transformers/dist/item/configure-pci.js
11
+ async function configurePci(xmlFragment, baseUrl, getModuleResolutionConfig, selector = "qti-portable-custom-interaction") {
12
+ const customInteractionTypeIdentifiers = [];
13
+ const portableCustomInteractions = xmlFragment.querySelectorAll(selector);
14
+ if (portableCustomInteractions.length === 0) {
15
+ return;
16
+ }
17
+ let moduleResolutionConfig = null;
18
+ let moduleResolutionFallbackConfig = null;
19
+ const ensureDefaultModuleResolutionConfigs = async () => {
20
+ if (moduleResolutionConfig === null) {
21
+ try {
22
+ moduleResolutionConfig = await getModuleResolutionConfig(baseUrl, "/modules/module_resolution.js");
23
+ } catch {
24
+ moduleResolutionConfig = null;
25
+ }
26
+ }
27
+ if (moduleResolutionFallbackConfig === null) {
28
+ try {
29
+ moduleResolutionFallbackConfig = await getModuleResolutionConfig(baseUrl, "/modules/fallback_module_resolution.js");
30
+ } catch {
31
+ moduleResolutionFallbackConfig = null;
32
+ }
33
+ }
34
+ };
35
+ for (const interaction of Array.from(portableCustomInteractions)) {
36
+ interaction.setAttribute("data-base-url", baseUrl);
37
+ let customInteractionTypeIdentifier = interaction.getAttribute("custom-interaction-type-identifier");
38
+ if (customInteractionTypeIdentifier && customInteractionTypeIdentifiers.includes(customInteractionTypeIdentifier)) {
39
+ customInteractionTypeIdentifier = customInteractionTypeIdentifier + customInteractionTypeIdentifiers.length;
40
+ interaction.setAttribute("custom-interaction-type-identifier", customInteractionTypeIdentifier);
41
+ customInteractionTypeIdentifiers.push(customInteractionTypeIdentifier);
42
+ }
43
+ if (customInteractionTypeIdentifier) {
44
+ customInteractionTypeIdentifiers.push(customInteractionTypeIdentifier);
45
+ }
46
+ let modulesElement = interaction.querySelector("qti-interaction-modules");
47
+ if (modulesElement && modulesElement.getAttribute("primary-configuration")) {
48
+ await ensureDefaultModuleResolutionConfigs();
49
+ const primaryConfigPath = modulesElement.getAttribute("primary-configuration");
50
+ if (primaryConfigPath) {
51
+ try {
52
+ const primaryConfig = await getModuleResolutionConfig(baseUrl, `/${primaryConfigPath}`);
53
+ const existingModules = Array.from(modulesElement.querySelectorAll("qti-interaction-module"));
54
+ for (const moduleEl of existingModules) {
55
+ const moduleId = moduleEl.getAttribute("id");
56
+ if (moduleId && primaryConfig.paths && primaryConfig.paths[moduleId]) {
57
+ const primaryPath = primaryConfig.paths[moduleId];
58
+ const primaryPathString = Array.isArray(primaryPath) ? primaryPath[0] : primaryPath;
59
+ moduleEl.setAttribute("primary-path", primaryPathString);
60
+ if (moduleResolutionFallbackConfig && moduleResolutionFallbackConfig.paths && moduleResolutionFallbackConfig.paths[moduleId]) {
61
+ const fallbackPath = moduleResolutionFallbackConfig.paths[moduleId];
62
+ if (Array.isArray(fallbackPath)) {
63
+ moduleEl.setAttribute("fallback-path", fallbackPath[0]);
64
+ } else {
65
+ moduleEl.setAttribute("fallback-path", fallbackPath);
66
+ }
67
+ }
68
+ }
69
+ }
70
+ if (primaryConfig.paths) {
71
+ for (const moduleId in primaryConfig.paths) {
72
+ const existingModule = modulesElement.querySelector(`qti-interaction-module[id="${moduleId}"]`);
73
+ if (!existingModule) {
74
+ const newModuleElement = xmlFragment.createElement("qti-interaction-module");
75
+ newModuleElement.setAttribute("id", moduleId);
76
+ const primaryPathString = Array.isArray(primaryConfig.paths[moduleId]) ? primaryConfig.paths[moduleId][0] : primaryConfig.paths[moduleId];
77
+ newModuleElement.setAttribute("primary-path", primaryPathString);
78
+ if (moduleResolutionFallbackConfig && moduleResolutionFallbackConfig.paths && moduleResolutionFallbackConfig.paths[moduleId]) {
79
+ const fallbackPath = moduleResolutionFallbackConfig.paths[moduleId];
80
+ if (Array.isArray(fallbackPath)) {
81
+ newModuleElement.setAttribute("fallback-path", fallbackPath[0]);
82
+ } else {
83
+ newModuleElement.setAttribute("fallback-path", fallbackPath);
84
+ }
85
+ }
86
+ modulesElement.appendChild(newModuleElement);
87
+ }
88
+ }
89
+ }
90
+ if (primaryConfig.urlArgs) {
91
+ modulesElement.setAttribute("url-args", primaryConfig.urlArgs);
92
+ }
93
+ } catch (error) {
94
+ console.warn(`Failed to load primary configuration: ${primaryConfigPath}`, error);
95
+ }
96
+ }
97
+ } else {
98
+ await ensureDefaultModuleResolutionConfigs();
99
+ if (moduleResolutionConfig) {
100
+ if (interaction.querySelector("qti-interaction-modules") === null) {
101
+ modulesElement = xmlFragment.createElement("qti-interaction-modules");
102
+ interaction.appendChild(modulesElement);
103
+ } else {
104
+ modulesElement = interaction.querySelector("qti-interaction-modules");
105
+ }
106
+ for (const module in moduleResolutionConfig.paths) {
107
+ const path = moduleResolutionConfig.paths[module];
108
+ let fallbackPath = "";
109
+ if (moduleResolutionFallbackConfig && moduleResolutionFallbackConfig.paths && moduleResolutionFallbackConfig.paths[module]) {
110
+ fallbackPath = moduleResolutionFallbackConfig.paths[module];
111
+ }
112
+ const primaryArray = Array.isArray(path) ? path : [path];
113
+ const fallbackPathArray = Array.isArray(fallbackPath) ? fallbackPath : [fallbackPath];
114
+ const paths = primaryArray.map((primaryPath, i) => {
115
+ const fallbackPath2 = fallbackPathArray.length > i ? fallbackPathArray[i] : "";
116
+ return {
117
+ primaryPath,
118
+ fallbackPath: fallbackPath2
119
+ };
120
+ });
121
+ for (const fallbackPath2 of fallbackPathArray) {
122
+ if (!paths.some((p) => p.fallbackPath === fallbackPath2)) {
123
+ paths.push({
124
+ primaryPath: primaryArray.length > 0 ? primaryArray[0] : fallbackPath2,
125
+ fallbackPath: fallbackPath2
126
+ });
127
+ }
128
+ }
129
+ for (const path2 of paths) {
130
+ const moduleElement = xmlFragment.createElement("qti-interaction-module");
131
+ if (path2.fallbackPath) {
132
+ moduleElement.setAttribute("fallback-path", path2.fallbackPath);
133
+ }
134
+ moduleElement.setAttribute("id", module);
135
+ moduleElement.setAttribute("primary-path", path2.primaryPath);
136
+ if (modulesElement) {
137
+ modulesElement.appendChild(moduleElement);
138
+ }
139
+ }
140
+ }
141
+ }
142
+ }
143
+ }
144
+ }
145
+
146
+ // ../qti-transformers/dist/item/extend.js
147
+ function extendElementName(xmlFragment, tagName, extension) {
148
+ const allElements = Array.from(xmlFragment.getElementsByTagName("*"));
149
+ const matchingElements = allElements.filter((element) => element.localName === tagName || element.localName?.toLowerCase() === tagName.toLowerCase());
150
+ matchingElements.forEach((element) => {
151
+ const newTagName = `${tagName}-${extension}`;
152
+ const newElement = createElementWithNewTagName(element, newTagName);
153
+ element.replaceWith(newElement);
154
+ });
155
+ }
156
+ function extendElementsWithClass(xmlFragment, classNamePattern) {
157
+ xmlFragment.querySelectorAll("*").forEach((element) => {
158
+ const classList = element.classList;
159
+ if (classList) {
160
+ classList.forEach((className) => {
161
+ if (className.startsWith(`${classNamePattern}:`)) {
162
+ const suffix = className.slice(`${classNamePattern}:`.length);
163
+ const newTagName = `${element.nodeName}-${suffix}`;
164
+ const newElement = createElementWithNewTagName(element, newTagName);
165
+ element.replaceWith(newElement);
166
+ }
167
+ });
168
+ }
169
+ });
170
+ }
171
+ function createElementWithNewTagName(element, newTagName) {
172
+ const newElement = element.ownerDocument.createElement(newTagName);
173
+ for (const attr of element.attributes) {
174
+ newElement.setAttribute(attr.name, attr.value);
175
+ }
176
+ while (element.firstChild) {
177
+ newElement.appendChild(element.firstChild);
178
+ }
179
+ return newElement;
180
+ }
181
+
182
+ // ../qti-transformers/dist/item/pci-hooks.js
183
+ function pciHooks(xmlFragment, uri) {
184
+ const attributes = ["hook", "module"];
185
+ const documentPath = uri.substring(0, uri.lastIndexOf("/"));
186
+ for (const attribute of attributes) {
187
+ const srcAttributes = xmlFragment.querySelectorAll("[" + attribute + "]");
188
+ srcAttributes.forEach((node) => {
189
+ const srcValue = node.getAttribute(attribute);
190
+ if (!srcValue.startsWith("data:") && !srcValue.startsWith("http")) {
191
+ node.setAttribute("base-url", uri);
192
+ node.setAttribute("module", documentPath + "/" + encodeURI(srcValue + (srcValue.endsWith(".js") ? "" : ".js")));
193
+ }
194
+ });
195
+ }
196
+ }
197
+
198
+ // ../qti-transformers/dist/shared/prng.js
199
+ var SeededRandom = class _SeededRandom {
200
+ #state;
201
+ constructor(seed) {
202
+ if (!(seed instanceof Uint8Array)) {
203
+ throw new TypeError("SeededRandom seed must be a Uint8Array.");
204
+ }
205
+ if (seed.length > 32) {
206
+ throw new RangeError("SeededRandom seed must be 32 bytes or less.");
207
+ }
208
+ const paddedSeed = new Uint8Array(32);
209
+ paddedSeed.set(seed, 32 - seed.length);
210
+ this.#state = hashBytes(paddedSeed);
211
+ }
212
+ static fromSeed(seed) {
213
+ if (seed.length !== 32) {
214
+ throw new RangeError("SeededRandom.fromSeed requires a 32-byte seed.");
215
+ }
216
+ return new _SeededRandom(seed);
217
+ }
218
+ static fromFixed(byte) {
219
+ if (typeof byte !== "number") {
220
+ throw new TypeError("SeededRandom.fromFixed requires a number.");
221
+ }
222
+ if (!Number.isInteger(byte) || byte < 0 || byte > 255) {
223
+ throw new RangeError("SeededRandom.fromFixed requires an integer from 0 to 255.");
224
+ }
225
+ const seed = new Uint8Array(32);
226
+ seed[31] = byte;
227
+ return new _SeededRandom(seed);
228
+ }
229
+ static fromSeedKey(seedKey) {
230
+ const random = new _SeededRandom(new Uint8Array());
231
+ random.#state = hashString(`${seedKey}`);
232
+ return random;
233
+ }
234
+ random() {
235
+ this.#state |= 0;
236
+ this.#state = this.#state + 1831565813 | 0;
237
+ let t = Math.imul(this.#state ^ this.#state >>> 15, 1 | this.#state);
238
+ t = t + Math.imul(t ^ t >>> 7, 61 | t) ^ t;
239
+ return ((t ^ t >>> 14) >>> 0) / 4294967296;
240
+ }
241
+ };
242
+ function createSeededRandom(seedKey) {
243
+ return SeededRandom.fromSeedKey(seedKey);
244
+ }
245
+ function hashString(seedKey) {
246
+ let h = 1779033703 ^ seedKey.length;
247
+ for (let i = 0; i < seedKey.length; i++) {
248
+ h = Math.imul(h ^ seedKey.charCodeAt(i), 3432918353);
249
+ h = h << 13 | h >>> 19;
250
+ }
251
+ return finalizeHash(h);
252
+ }
253
+ function hashBytes(seed) {
254
+ let h = 1779033703 ^ seed.length;
255
+ for (let i = 0; i < seed.length; i++) {
256
+ h = Math.imul(h ^ seed[i], 3432918353);
257
+ h = h << 13 | h >>> 19;
258
+ }
259
+ return finalizeHash(h);
260
+ }
261
+ function finalizeHash(hash) {
262
+ let h = Math.imul(hash ^ hash >>> 16, 2246822507);
263
+ h = Math.imul(h ^ h >>> 13, 3266489909);
264
+ return (h ^ h >>> 16) >>> 0;
265
+ }
266
+
267
+ // ../qti-transformers/dist/shared/shuffle.js
268
+ var randomValue = (source) => typeof source === "function" ? source() : source.random();
269
+ function shuffleKeepingFixed(units, random) {
270
+ const movable = units.filter((unit) => !unit.fixed);
271
+ for (let i = movable.length - 1; i > 0; i--) {
272
+ const j = Math.floor(randomValue(random) * (i + 1));
273
+ [movable[i], movable[j]] = [movable[j], movable[i]];
274
+ }
275
+ let movableIndex = 0;
276
+ return units.map((unit) => unit.fixed ? unit : movable[movableIndex++]);
277
+ }
278
+
279
+ // ../qti-transformers/dist/item/shuffle-interactions.js
280
+ function getShuffleQuerySelectorByTagName(tagName) {
281
+ switch (tagName) {
282
+ case "qti-choice-interaction":
283
+ case "qti-order-interaction":
284
+ return "qti-simple-choice";
285
+ case "qti-inline-choice-interaction":
286
+ return "qti-inline-choice";
287
+ case "qti-match-interaction":
288
+ return [
289
+ "qti-simple-match-set:first-of-type qti-simple-associable-choice",
290
+ "qti-simple-match-set:last-of-type > qti-simple-associable-choice"
291
+ ];
292
+ case "qti-gap-match-interaction":
293
+ return "qti-gap-text";
294
+ case "qti-associate-interaction":
295
+ return "qti-simple-associable-choice";
296
+ default:
297
+ return null;
298
+ }
299
+ }
300
+ function shuffleInteractions(xmlFragment, seed) {
301
+ const shuffleElements = xmlFragment.querySelectorAll(`[shuffle="true"]`);
302
+ const shuffleInteractions2 = Array.from(shuffleElements).filter((e) => e.tagName?.toLowerCase().endsWith("-interaction"));
303
+ const seeded = seed != null && `${seed}`.length > 0;
304
+ const itemId = xmlFragment.querySelector?.("qti-assessment-item")?.getAttribute("identifier") ?? "";
305
+ let interactionIndex = 0;
306
+ for (const shuffleInteraction of shuffleInteractions2) {
307
+ const responseId = shuffleInteraction.getAttribute("response-identifier") ?? `${interactionIndex}`;
308
+ interactionIndex++;
309
+ const query = getShuffleQuerySelectorByTagName(shuffleInteraction.tagName.toLowerCase());
310
+ const queries = Array.isArray(query) ? query : [query];
311
+ let shuffledAny = false;
312
+ let queryIndex = 0;
313
+ for (const q of queries) {
314
+ if (!q)
315
+ continue;
316
+ const random = seeded ? createSeededRandom(`${seed}:${itemId}:${responseId}:${queryIndex}`) : Math.random;
317
+ queryIndex++;
318
+ const choices = Array.from(shuffleInteraction.querySelectorAll(q)).filter((choice) => choice.parentElement !== null);
319
+ if (choices.filter((choice) => choice.getAttribute("fixed") !== "true").length <= 1) {
320
+ console.warn("Shuffling is not possible with fewer than 2 non-fixed elements.");
321
+ continue;
322
+ }
323
+ const parent = choices[0].parentElement;
324
+ if (!parent || choices.some((choice) => choice.parentElement !== parent)) {
325
+ console.warn("Shuffling is not possible when choices do not share the same parent element.");
326
+ continue;
327
+ }
328
+ const anchor = choices[choices.length - 1].nextSibling;
329
+ const orderedChoices = shuffleKeepingFixed(choices.map((choice) => ({
330
+ element: choice,
331
+ fixed: choice.getAttribute("fixed") === "true"
332
+ })), random);
333
+ for (const choice of choices) {
334
+ choice.remove();
335
+ }
336
+ for (const { element } of orderedChoices) {
337
+ parent.insertBefore(element, anchor);
338
+ }
339
+ shuffledAny = true;
340
+ }
341
+ if (shuffledAny) {
342
+ shuffleInteraction.removeAttribute("shuffle");
343
+ }
344
+ }
345
+ }
346
+
347
+ // ../qti-transformers/dist/item/stylesheets.js
348
+ function stripStyleSheets(xmlFragment) {
349
+ xmlFragment.querySelectorAll("qti-stylesheet").forEach((stylesheet) => stylesheet.remove());
350
+ }
351
+
352
+ // ../qti-transformers/dist/shared/missing-seed-warning.js
353
+ var missingSeedWarned = false;
354
+ function warnMissingSeed(scope, fallbackSeed) {
355
+ if (missingSeedWarned)
356
+ return;
357
+ missingSeedWarned = true;
358
+ console.warn(`[${scope}] No QTI_CONTEXT.seed provided; using "${fallbackSeed}" as deterministic fallback seed.`);
359
+ }
360
+
361
+ // ../qti-transformers/dist/shared/xml.js
362
+ function loadXML(url, signal) {
363
+ return fetch(url, { signal }).then((response) => {
364
+ if (!response.ok) {
365
+ throw new Error(`HTTP error! status: ${response.status}`);
366
+ }
367
+ return response.text();
368
+ }).then((text) => {
369
+ const parser = new DOMParser();
370
+ return parser.parseFromString(text, "text/xml");
371
+ }).catch((error) => {
372
+ if (error.name === "AbortError") {
373
+ throw error;
374
+ }
375
+ throw new Error(`Failed to load XML: ${error.message}`);
376
+ });
377
+ }
378
+ function parseXML(xmlDocument) {
379
+ const parser = new DOMParser();
380
+ const xmlFragment = parser.parseFromString(xmlDocument, "text/xml");
381
+ return xmlFragment;
382
+ }
383
+ function stripNamespaces(node, doc, registry) {
384
+ if (node.nodeType === Node.ELEMENT_NODE) {
385
+ const el = node;
386
+ let newEl;
387
+ if (!el.namespaceURI || el.namespaceURI.startsWith("http://www.imsglobal.org/xsd/qti/") || el.namespaceURI.startsWith("http://www.imsglobal.org/xsd/imsqti")) {
388
+ newEl = registry ? doc.createElement(el.localName, { customElementRegistry: registry }) : doc.createElement(el.localName);
389
+ } else {
390
+ newEl = doc.createElementNS(el.namespaceURI, el.tagName);
391
+ }
392
+ for (let i = 0; i < el.attributes.length; i++) {
393
+ const attr = el.attributes[i];
394
+ newEl.setAttribute(attr.localName, attr.value);
395
+ }
396
+ for (let i = 0; i < el.childNodes.length; i++) {
397
+ newEl.appendChild(stripNamespaces(el.childNodes[i], doc, registry));
398
+ }
399
+ return newEl;
400
+ }
401
+ return node.cloneNode(false);
402
+ }
403
+ function toHTML(xmlFragment, registry) {
404
+ const fragment = document.createDocumentFragment();
405
+ for (let i = 0; i < xmlFragment.childNodes.length; i++) {
406
+ fragment.appendChild(stripNamespaces(xmlFragment.childNodes[i], document, registry));
407
+ }
408
+ return fragment;
409
+ }
410
+ function setLocation(xmlFragment, location) {
411
+ if (!location.endsWith("/")) {
412
+ location += "/";
413
+ }
414
+ const allElements = xmlFragment.querySelectorAll("*");
415
+ allElements.forEach((el) => {
416
+ for (const attr of ["src", "href", "srcset", "poster"]) {
417
+ const attrValue = el.getAttribute(attr)?.trim();
418
+ if (attrValue && !/^(data:|https?:|blob:)/.test(attrValue)) {
419
+ const newValue = location + encodeURI(attrValue);
420
+ el.setAttribute(attr, newValue);
421
+ }
422
+ }
423
+ });
424
+ }
425
+
426
+ // ../qti-transformers/dist/qti-transform-item.js
427
+ var qtiTransformItem = () => {
428
+ let xmlFragment;
429
+ let xmlUri = "";
430
+ const api = {
431
+ load(uri, signal) {
432
+ xmlUri = uri;
433
+ return loadXML(uri, signal).then((xml) => {
434
+ xmlFragment = xml;
435
+ return api;
436
+ });
437
+ },
438
+ parse(xmlString) {
439
+ xmlFragment = parseXML(xmlString);
440
+ xmlUri = "";
441
+ return api;
442
+ },
443
+ path: (location) => {
444
+ setLocation(xmlFragment, location);
445
+ xmlUri = null;
446
+ return api;
447
+ },
448
+ fn(fn) {
449
+ fn(xmlFragment);
450
+ return api;
451
+ },
452
+ pciHooks(uri) {
453
+ pciHooks(xmlFragment, uri);
454
+ return api;
455
+ },
456
+ async configurePci(baseUrl, getModuleResolutionConfig, selector = "qti-portable-custom-interaction") {
457
+ await configurePci(xmlFragment, baseUrl, getModuleResolutionConfig, selector);
458
+ return api;
459
+ },
460
+ shuffleInteractions(seed) {
461
+ const normalizedSeed = typeof seed === "string" ? seed.trim() : seed;
462
+ if (normalizedSeed === null || normalizedSeed === void 0 || normalizedSeed === "") {
463
+ const fallbackSeed = xmlUri || "default-item-seed";
464
+ warnMissingSeed("qtiTransformItem", fallbackSeed);
465
+ shuffleInteractions(xmlFragment, fallbackSeed);
466
+ return api;
467
+ }
468
+ shuffleInteractions(xmlFragment, normalizedSeed);
469
+ return api;
470
+ },
471
+ extendElementName: (tagName, extension) => {
472
+ extendElementName(xmlFragment, tagName, extension);
473
+ return api;
474
+ },
475
+ extendElementsWithClass: (param = "extend") => {
476
+ extendElementsWithClass(xmlFragment, param);
477
+ return api;
478
+ },
479
+ customInteraction(baseRef, baseItem) {
480
+ const qtiCustomInteraction = xmlFragment.querySelector("qti-custom-interaction");
481
+ const qtiCustomInteractionObject = qtiCustomInteraction.querySelector("object");
482
+ qtiCustomInteraction.setAttribute("data-base-ref", baseRef);
483
+ qtiCustomInteraction.setAttribute("data-base-item", baseRef + baseItem);
484
+ qtiCustomInteraction.setAttribute("data", qtiCustomInteractionObject.getAttribute("data"));
485
+ qtiCustomInteraction.setAttribute("width", qtiCustomInteractionObject.getAttribute("width"));
486
+ qtiCustomInteraction.setAttribute("height", qtiCustomInteractionObject.getAttribute("height"));
487
+ qtiCustomInteraction.removeChild(qtiCustomInteractionObject);
488
+ return api;
489
+ },
490
+ convertCDATAtoComment() {
491
+ convertCDATAtoComment(xmlFragment);
492
+ return api;
493
+ },
494
+ stripStyleSheets() {
495
+ stripStyleSheets(xmlFragment);
496
+ return api;
497
+ },
498
+ html() {
499
+ if (xmlUri !== null) {
500
+ setLocation(xmlFragment, xmlUri.substring(0, xmlUri.lastIndexOf("/")));
501
+ }
502
+ return new XMLSerializer().serializeToString(toHTML(xmlFragment));
503
+ },
504
+ xml() {
505
+ return new XMLSerializer().serializeToString(xmlFragment);
506
+ },
507
+ htmlDoc(registry) {
508
+ if (xmlUri !== null) {
509
+ setLocation(xmlFragment, xmlUri.substring(0, xmlUri.lastIndexOf("/")));
510
+ }
511
+ return toHTML(xmlFragment, registry);
512
+ },
513
+ xmlDoc() {
514
+ return xmlFragment;
515
+ }
516
+ };
517
+ return api;
518
+ };
519
+
520
+ // ../qti-transformers/dist/qti-transform-manifest.js
521
+ var qtiTransformManifest = () => {
522
+ let xmlFragment;
523
+ const api = {
524
+ async load(uri, signal) {
525
+ return new Promise((resolve) => {
526
+ loadXML(uri, signal).then((xml) => {
527
+ xmlFragment = xml;
528
+ return resolve(api);
529
+ });
530
+ });
531
+ },
532
+ parse(xmlString) {
533
+ xmlFragment = parseXML(xmlString);
534
+ },
535
+ assessmentTest() {
536
+ const el = xmlFragment.querySelector('resource[type="imsqti_test_xmlv3p0"]');
537
+ return { href: el.getAttribute("href"), identifier: el.getAttribute("identifier") };
538
+ }
539
+ };
540
+ return api;
541
+ };
542
+
543
+ // ../qti-transformers/dist/test/items.js
544
+ function itemsFromTest(xmlFragment) {
545
+ const items = [];
546
+ xmlFragment.querySelectorAll("qti-assessment-item-ref").forEach((el) => {
547
+ const identifier = el.getAttribute("identifier");
548
+ const href = el.getAttribute("href");
549
+ const category = el.getAttribute("category");
550
+ items.push({ identifier, href, category });
551
+ });
552
+ return items;
553
+ }
554
+
555
+ // ../qti-transformers/dist/test/shuffle-sections.js
556
+ var isLocal = (el, ...names) => names.includes(el.localName) || names.includes(el.localName?.toLowerCase?.());
557
+ var isItemRef = (el) => isLocal(el, "qti-assessment-item-ref", "assessmentitemref");
558
+ var isSection = (el) => isLocal(el, "qti-assessment-section", "assessmentsection");
559
+ var attrIsTrue = (el, ...names) => names.some((n) => {
560
+ const v = (el.getAttribute(n) ?? "").trim().toLowerCase();
561
+ return v === "true" || v === "1";
562
+ });
563
+ var attrIsFalse = (el, ...names) => names.some((n) => {
564
+ const v = (el.getAttribute(n) ?? "").trim().toLowerCase();
565
+ return v === "false" || v === "0";
566
+ });
567
+ var isOrdering = (el) => isLocal(el, "qti-ordering", "ordering");
568
+ var isSelection = (el) => isLocal(el, "qti-selection", "selection");
569
+ var shuffleOrderingElements = (section) => Array.from(section.children).filter((child) => isOrdering(child) && attrIsTrue(child, "shuffle"));
570
+ var rngFor = (seed, key) => createSeededRandom(`${seed}:${key}`);
571
+ function collectItemRefsDeep(section) {
572
+ const itemRefs = [];
573
+ const dropped = [];
574
+ const walk = (el) => {
575
+ for (const child of Array.from(el.children)) {
576
+ if (isItemRef(child)) {
577
+ itemRefs.push(child);
578
+ } else if (isSection(child)) {
579
+ walk(child);
580
+ } else if (!isOrdering(child) && !isSelection(child)) {
581
+ dropped.push(child.localName);
582
+ }
583
+ }
584
+ };
585
+ walk(section);
586
+ return { itemRefs, dropped };
587
+ }
588
+ function warnDroppedChildren(section, dropped) {
589
+ if (dropped.length === 0)
590
+ return;
591
+ const identifier = section.getAttribute("identifier") ?? "(no identifier)";
592
+ console.warn(`[qtiTransformTest] Subsection "${identifier}" is consumed by section ordering; discarding its ${[...new Set(dropped)].join(", ")}.`);
593
+ }
594
+ function orderSection(section, seed) {
595
+ for (const child of Array.from(section.children)) {
596
+ if (isSection(child)) {
597
+ orderSection(child, seed);
598
+ }
599
+ }
600
+ const orderingEls = shuffleOrderingElements(section);
601
+ if (orderingEls.length === 0) {
602
+ return;
603
+ }
604
+ const units = [];
605
+ const toDetach = [];
606
+ for (const child of Array.from(section.children)) {
607
+ if (isItemRef(child)) {
608
+ units.push({ nodes: [child], fixed: attrIsTrue(child, "fixed") });
609
+ toDetach.push(child);
610
+ } else if (isSection(child)) {
611
+ const { itemRefs, dropped } = collectItemRefsDeep(child);
612
+ warnDroppedChildren(child, dropped);
613
+ if (attrIsFalse(child, "keep-together", "keeptogether")) {
614
+ for (const itemRef of itemRefs) {
615
+ units.push({ nodes: [itemRef], fixed: attrIsTrue(itemRef, "fixed") });
616
+ }
617
+ } else if (itemRefs.length > 0) {
618
+ units.push({ nodes: itemRefs, fixed: attrIsTrue(child, "fixed") });
619
+ }
620
+ toDetach.push(child);
621
+ }
622
+ }
623
+ const anchor = toDetach.length > 0 ? toDetach[toDetach.length - 1].nextSibling : null;
624
+ const sectionKey = section.getAttribute("identifier") ?? "";
625
+ const ordered = shuffleKeepingFixed(units, rngFor(seed, sectionKey));
626
+ for (const el of toDetach) {
627
+ el.remove();
628
+ }
629
+ for (const unit of ordered) {
630
+ for (const node of unit.nodes) {
631
+ section.insertBefore(node, anchor);
632
+ }
633
+ }
634
+ for (const orderingEl of orderingEls) {
635
+ orderingEl.remove();
636
+ }
637
+ }
638
+ function hasShuffleOrdering(doc) {
639
+ return Array.from(doc.getElementsByTagName("*")).some((el) => isOrdering(el) && attrIsTrue(el, "shuffle"));
640
+ }
641
+ function shuffleSectionsOrdering(doc, seed) {
642
+ const sections = Array.from(doc.getElementsByTagName("*")).filter((el) => isSection(el));
643
+ for (const section of sections) {
644
+ if (!section.parentNode)
645
+ continue;
646
+ const parent = section.parentElement;
647
+ if (parent && isSection(parent))
648
+ continue;
649
+ orderSection(section, seed);
650
+ }
651
+ }
652
+
653
+ // ../qti-transformers/dist/qti-transform-test.js
654
+ var qtiTransformTest = () => {
655
+ let xmlFragment;
656
+ let xmlUri = "";
657
+ const api = {
658
+ async load(uri, signal) {
659
+ return new Promise((resolve, _) => {
660
+ loadXML(uri, signal).then((xml) => {
661
+ xmlFragment = xml;
662
+ xmlUri = uri;
663
+ api.path(uri.substring(0, uri.lastIndexOf("/")));
664
+ return resolve(api);
665
+ });
666
+ });
667
+ },
668
+ parse(xmlString) {
669
+ xmlFragment = parseXML(xmlString);
670
+ xmlUri = "";
671
+ return api;
672
+ },
673
+ path: (location) => {
674
+ setLocation(xmlFragment, location);
675
+ return api;
676
+ },
677
+ fn(fn) {
678
+ fn(xmlFragment);
679
+ return api;
680
+ },
681
+ shuffleOrdering(seed) {
682
+ if (!hasShuffleOrdering(xmlFragment)) {
683
+ return api;
684
+ }
685
+ const normalizedSeed = typeof seed === "string" ? seed.trim() : seed;
686
+ if (normalizedSeed === null || normalizedSeed === void 0 || normalizedSeed === "") {
687
+ const fallbackSeed = xmlUri || "default-test-seed";
688
+ warnMissingSeed("qtiTransformTest", fallbackSeed);
689
+ shuffleSectionsOrdering(xmlFragment, fallbackSeed);
690
+ return api;
691
+ }
692
+ shuffleSectionsOrdering(xmlFragment, normalizedSeed);
693
+ return api;
694
+ },
695
+ items() {
696
+ return itemsFromTest(xmlFragment);
697
+ },
698
+ html() {
699
+ return new XMLSerializer().serializeToString(toHTML(xmlFragment));
700
+ },
701
+ xml() {
702
+ return new XMLSerializer().serializeToString(xmlFragment);
703
+ },
704
+ htmlDoc(registry) {
705
+ return toHTML(xmlFragment, registry);
706
+ },
707
+ xmlDoc() {
708
+ return xmlFragment;
709
+ }
710
+ };
711
+ return api;
712
+ };
713
+
714
+ export {
715
+ qtiTransformItem,
716
+ qtiTransformManifest,
717
+ qtiTransformTest
718
+ };
719
+ //# sourceMappingURL=chunk-IJD53WY6.js.map