@qti-editor/core 1.3.1 → 1.4.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.
@@ -10,12 +10,16 @@ export interface ComposerItemContext {
10
10
  lang?: string;
11
11
  title?: string;
12
12
  itemBody?: Document;
13
+ items?: Array<{
14
+ identifier?: string;
15
+ title?: string;
16
+ }>;
13
17
  }
14
18
  export interface ResponseDeclaration {
15
19
  identifier: string;
16
20
  cardinality: 'single' | 'multiple' | 'ordered';
17
21
  baseType: 'identifier' | 'directedPair' | 'point' | 'string';
18
- correctResponse?: string;
22
+ correctResponse?: string | string[];
19
23
  stringMapping?: {
20
24
  defaultValue: number;
21
25
  entries: Array<{
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/composer/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,wBAAwB,CAAC;AAErE,MAAM,WAAW,mBAAmB;IAClC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,QAAQ,CAAC;CACrB;AAED,MAAM,WAAW,mBAAmB;IAClC,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,QAAQ,GAAG,UAAU,GAAG,SAAS,CAAC;IAC/C,QAAQ,EAAE,YAAY,GAAG,cAAc,GAAG,OAAO,GAAG,QAAQ,CAAC;IAC7D,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,aAAa,CAAC,EAAE;QACd,YAAY,EAAE,MAAM,CAAC;QACrB,OAAO,EAAE,KAAK,CAAC;YACb,MAAM,EAAE,MAAM,CAAC;YACf,WAAW,EAAE,MAAM,CAAC;YACpB,aAAa,EAAE,OAAO,CAAC;SACxB,CAAC,CAAC;KACJ,CAAC;IACF,sBAAsB,CAAC,EAAE,sBAAsB,CAAC;IAChD,WAAW,CAAC,EAAE;QACZ,YAAY,EAAE,MAAM,CAAC;QACrB,OAAO,EAAE,KAAK,CAAC;YACb,KAAK,EAAE,QAAQ,GAAG,MAAM,CAAC;YACzB,MAAM,EAAE,MAAM,CAAC;YACf,WAAW,EAAE,MAAM,CAAC;SACrB,CAAC,CAAC;KACJ,CAAC;IACF,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAoCD,wBAAgB,2BAA2B,CAAC,YAAY,CAAC,EAAE,OAAO,GAAG,IAAI,GAAG,mBAAmB,EAAE,CAOhG;AAkFD,wBAAgB,sBAAsB,CAAC,WAAW,CAAC,EAAE,mBAAmB,GAAG,MAAM,CAqHhF;AAED;;;;;;;;GAQG;AACH,wBAAgB,+BAA+B,CAAC,WAAW,CAAC,EAAE,mBAAmB,GAAG,MAAM,CAkCzF;AAED;;;GAGG;AACH,wBAAgB,4BAA4B,CAAC,WAAW,CAAC,EAAE,mBAAmB,GAAG,MAAM,CAUtF;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,WAAW,CAAC,EAAE,mBAAmB,GAAG,MAAM,CAK5E;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,WAAW,CAAC,EAAE,mBAAmB,GAAG,KAAK,CAAC;IAAE,UAAU,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,CAAC,CAyChI;AAgMD,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CA4B7C"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/composer/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,wBAAwB,CAAC;AAErE,MAAM,WAAW,mBAAmB;IAClC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,QAAQ,CAAC;IACpB,KAAK,CAAC,EAAE,KAAK,CAAC;QAAE,UAAU,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACxD;AAED,MAAM,WAAW,mBAAmB;IAClC,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,QAAQ,GAAG,UAAU,GAAG,SAAS,CAAC;IAC/C,QAAQ,EAAE,YAAY,GAAG,cAAc,GAAG,OAAO,GAAG,QAAQ,CAAC;IAC7D,eAAe,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IACpC,aAAa,CAAC,EAAE;QACd,YAAY,EAAE,MAAM,CAAC;QACrB,OAAO,EAAE,KAAK,CAAC;YACb,MAAM,EAAE,MAAM,CAAC;YACf,WAAW,EAAE,MAAM,CAAC;YACpB,aAAa,EAAE,OAAO,CAAC;SACxB,CAAC,CAAC;KACJ,CAAC;IACF,sBAAsB,CAAC,EAAE,sBAAsB,CAAC;IAChD,WAAW,CAAC,EAAE;QACZ,YAAY,EAAE,MAAM,CAAC;QACrB,OAAO,EAAE,KAAK,CAAC;YACb,KAAK,EAAE,QAAQ,GAAG,MAAM,CAAC;YACzB,MAAM,EAAE,MAAM,CAAC;YACf,WAAW,EAAE,MAAM,CAAC;SACrB,CAAC,CAAC;KACJ,CAAC;IACF,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAiED,wBAAgB,2BAA2B,CAAC,YAAY,CAAC,EAAE,OAAO,GAAG,IAAI,GAAG,mBAAmB,EAAE,CAOhG;AAkFD,wBAAgB,sBAAsB,CAAC,WAAW,CAAC,EAAE,mBAAmB,GAAG,MAAM,CAyHhF;AAED;;;;;;;;GAQG;AACH,wBAAgB,+BAA+B,CAAC,WAAW,CAAC,EAAE,mBAAmB,GAAG,MAAM,CAmCzF;AAED;;;GAGG;AACH,wBAAgB,4BAA4B,CAAC,WAAW,CAAC,EAAE,mBAAmB,GAAG,MAAM,CAUtF;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,WAAW,CAAC,EAAE,mBAAmB,GAAG,MAAM,CAK5E;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,WAAW,CAAC,EAAE,mBAAmB,GAAG,KAAK,CAAC;IAAE,UAAU,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,CAAC,CAiChI;AAoKD,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CA4B7C"}
@@ -10,27 +10,52 @@ const XSI_NS = 'http://www.w3.org/2001/XMLSchema-instance';
10
10
  const XML_NS = 'http://www.w3.org/XML/1998/namespace';
11
11
  const SCHEMA_LOCATION = 'http://www.imsglobal.org/xsd/imsqtiasi_v3p0 https://purl.imsglobal.org/spec/qti/v3p0/schema/xsd/imsqti_asiv3p0p1_v1p0.xsd';
12
12
  const MATCH_CORRECT_TEMPLATE = 'https://purl.imsglobal.org/spec/qti/v3p0/rptemplates/match_correct';
13
+ const TEXT_ENTRY_INTERACTION_TAG = 'qti-text-entry-interaction';
14
+ const SELECT_POINT_INTERACTION_TAG = 'qti-select-point-interaction';
15
+ const EDITOR_DATA_ATTRIBUTE_MAPPINGS = [
16
+ { source: 'correct-response', target: 'data-correct-response' },
17
+ { source: 'correctResponse', target: 'data-correct-response' },
18
+ { source: 'correctAnswer', target: 'data-correct-response' },
19
+ { source: 'score', target: 'data-score' },
20
+ ];
21
+ const TEXT_ENTRY_DATA_ATTRIBUTE_MAPPINGS = [
22
+ { source: 'case-sensitive', target: 'data-case-sensitive' },
23
+ ];
24
+ const SELECT_POINT_DATA_ATTRIBUTE_MAPPINGS = [
25
+ { source: 'area-mappings', target: 'data-area-mappings' },
26
+ ];
13
27
  function parseCorrectResponseValues(declaration) {
14
- if (!declaration.correctResponse)
28
+ const value = declaration.correctResponse;
29
+ if (value == null)
15
30
  return [];
31
+ if (Array.isArray(value)) {
32
+ return value.map(v => v.trim()).filter(Boolean);
33
+ }
16
34
  if (declaration.cardinality === 'single') {
17
- return [declaration.correctResponse];
35
+ return value.length > 0 ? [value] : [];
18
36
  }
19
- if (declaration.cardinality === 'ordered') {
20
- try {
21
- const parsed = JSON.parse(declaration.correctResponse);
22
- if (Array.isArray(parsed)) {
23
- return parsed
24
- .filter((value) => typeof value === 'string')
25
- .map(value => value.trim())
26
- .filter(Boolean);
27
- }
28
- }
29
- catch {
30
- // Fall back to comma-separated parsing for malformed or legacy values.
31
- }
37
+ return value.split(',').map(v => v.trim()).filter(Boolean);
38
+ }
39
+ function copyEditorDataAttribute(sourceElement, targetElement, source, target) {
40
+ const value = sourceElement.getAttribute(source);
41
+ if (value == null || value.length === 0 || targetElement.hasAttribute(target))
42
+ return;
43
+ targetElement.setAttribute(target, value);
44
+ }
45
+ function preserveEditorDataAttributes(sourceElement, targetElement, tagName) {
46
+ EDITOR_DATA_ATTRIBUTE_MAPPINGS.forEach(({ source, target }) => {
47
+ copyEditorDataAttribute(sourceElement, targetElement, source, target);
48
+ });
49
+ if (tagName === TEXT_ENTRY_INTERACTION_TAG) {
50
+ TEXT_ENTRY_DATA_ATTRIBUTE_MAPPINGS.forEach(({ source, target }) => {
51
+ copyEditorDataAttribute(sourceElement, targetElement, source, target);
52
+ });
53
+ }
54
+ if (tagName === SELECT_POINT_INTERACTION_TAG) {
55
+ SELECT_POINT_DATA_ATTRIBUTE_MAPPINGS.forEach(({ source, target }) => {
56
+ copyEditorDataAttribute(sourceElement, targetElement, source, target);
57
+ });
32
58
  }
33
- return declaration.correctResponse.split(',').map(v => v.trim()).filter(Boolean);
34
59
  }
35
60
  export function extractResponseDeclarations(itemBodyRoot) {
36
61
  if (!itemBodyRoot)
@@ -128,7 +153,7 @@ export function buildAssessmentItemXml(itemContext) {
128
153
  const composedItemBody = sourceBodyRoot != null
129
154
  ? xmlDoc.importNode(sourceBodyRoot, true)
130
155
  : xmlDoc.createElementNS(QTI_NS, 'qti-item-body');
131
- const { declarations, responseTemplate, maxScore } = composeAndNormalizeItemBody(composedItemBody, xmlDoc);
156
+ const { declarations, responseTemplate, maxScore, hasAutomatedProcessing } = composeAndNormalizeItemBody(composedItemBody, xmlDoc);
132
157
  declarations.forEach(declaration => {
133
158
  const responseDeclaration = xmlDoc.createElementNS(QTI_NS, 'qti-response-declaration');
134
159
  responseDeclaration.setAttribute('identifier', declaration.identifier);
@@ -182,7 +207,7 @@ export function buildAssessmentItemXml(itemContext) {
182
207
  outcomeDeclaration.appendChild(scoreDefaultValue);
183
208
  root.appendChild(outcomeDeclaration);
184
209
  const maxScoreOutcomeDeclaration = xmlDoc.createElementNS(QTI_NS, 'qti-outcome-declaration');
185
- maxScoreOutcomeDeclaration.setAttribute('identifier', 'MAX_SCORE');
210
+ maxScoreOutcomeDeclaration.setAttribute('identifier', 'MAXSCORE');
186
211
  maxScoreOutcomeDeclaration.setAttribute('cardinality', 'single');
187
212
  maxScoreOutcomeDeclaration.setAttribute('base-type', 'float');
188
213
  const maxScoreDefaultValue = xmlDoc.createElementNS(QTI_NS, 'qti-default-value');
@@ -193,17 +218,20 @@ export function buildAssessmentItemXml(itemContext) {
193
218
  root.appendChild(maxScoreOutcomeDeclaration);
194
219
  }
195
220
  root.appendChild(composedItemBody);
196
- if (maxScore > 0) {
197
- if (declarations.length === 1) {
221
+ if (maxScore > 0 && hasAutomatedProcessing) {
222
+ const single = declarations.length === 1 ? declarations[0] : null;
223
+ const canUseTemplate = single !== null &&
224
+ !(single.responseProcessingKind === 'match_correct' && (single.score ?? 1) !== 1);
225
+ if (canUseTemplate) {
198
226
  const responseProcessing = xmlDoc.createElementNS(QTI_NS, 'qti-response-processing');
199
227
  responseProcessing.setAttribute('template', responseTemplate);
200
228
  root.appendChild(responseProcessing);
201
229
  }
202
- else if (declarations.length > 1) {
230
+ else {
203
231
  root.appendChild(buildMultiInteractionResponseProcessing(xmlDoc, declarations));
204
232
  }
205
233
  }
206
- return new XMLSerializer().serializeToString(xmlDoc);
234
+ return new XMLSerializer().serializeToString(xmlDoc).replace(/\s+xmlns=""/g, '');
207
235
  }
208
236
  /**
209
237
  * Build multiple QTI assessment items from a single editor document.
@@ -228,12 +256,13 @@ export function buildMultipleAssessmentItemsXml(itemContext) {
228
256
  const lang = itemContext.lang?.trim() || 'en';
229
257
  const itemXmls = fragments.map((fragmentBody, index) => {
230
258
  const itemNumber = index + 1;
259
+ const perItem = itemContext.items?.[index];
231
260
  const fragmentDoc = document.implementation.createDocument(QTI_NS, 'qti-item-body', null);
232
261
  const importedFragment = fragmentDoc.importNode(fragmentBody, true);
233
262
  fragmentDoc.replaceChild(importedFragment, fragmentDoc.documentElement);
234
263
  const fragmentContext = {
235
- identifier: `${baseIdentifier}-${itemNumber}`,
236
- title: `${baseTitle} ${itemNumber}`,
264
+ identifier: perItem?.identifier?.trim() || `${baseIdentifier}-${itemNumber}`,
265
+ title: perItem?.title?.trim() || `${baseTitle} ${itemNumber}`,
237
266
  lang,
238
267
  itemBody: fragmentDoc,
239
268
  };
@@ -278,33 +307,27 @@ export function getItemFragmentXmls(itemContext) {
278
307
  const fragments = splitItemBodyAtDividers(itemContext.itemBody);
279
308
  // If only one fragment (no dividers), return single item
280
309
  if (fragments.length <= 1) {
281
- const xml = buildAssessmentItemXml(itemContext);
282
- return [{
283
- identifier: itemContext.identifier?.trim() || 'item-1',
284
- title: itemContext.title?.trim() || 'Untitled Item',
285
- xml,
286
- }];
310
+ const perItem = itemContext.items?.[0];
311
+ const identifier = perItem?.identifier?.trim() || itemContext.identifier?.trim() || 'item-1';
312
+ const title = perItem?.title?.trim() || itemContext.title?.trim() || 'Untitled Item';
313
+ const xml = buildAssessmentItemXml({ ...itemContext, identifier, title });
314
+ return [{ identifier, title, xml }];
287
315
  }
288
316
  const baseIdentifier = itemContext.identifier?.trim() || 'item';
289
317
  const baseTitle = itemContext.title?.trim() || 'Untitled Item';
290
318
  const lang = itemContext.lang?.trim() || 'en';
291
319
  return fragments.map((fragmentBody, index) => {
292
320
  const itemNumber = index + 1;
321
+ const perItem = itemContext.items?.[index];
322
+ const identifier = perItem?.identifier?.trim() || `${baseIdentifier}-${itemNumber}`;
323
+ const title = perItem?.title?.trim() || `${baseTitle} ${itemNumber}`;
293
324
  const fragmentDoc = document.implementation.createDocument(QTI_NS, 'qti-item-body', null);
294
325
  const importedFragment = fragmentDoc.importNode(fragmentBody, true);
295
326
  fragmentDoc.replaceChild(importedFragment, fragmentDoc.documentElement);
296
- const identifier = `${baseIdentifier}-${itemNumber}`;
297
- const title = `${baseTitle} ${itemNumber}`;
298
- const fragmentContext = {
299
- identifier,
300
- title,
301
- lang,
302
- itemBody: fragmentDoc,
303
- };
304
327
  return {
305
328
  identifier,
306
329
  title,
307
- xml: buildAssessmentItemXml(fragmentContext),
330
+ xml: buildAssessmentItemXml({ identifier, title, lang, itemBody: fragmentDoc }),
308
331
  };
309
332
  });
310
333
  }
@@ -320,6 +343,7 @@ function composeAndNormalizeItemBody(itemBody, xmlDoc) {
320
343
  const isInteractionCandidate = tagName.endsWith('-interaction') || element.hasAttribute('response-identifier');
321
344
  if (handler) {
322
345
  const composeResult = handler.compose(element, xmlDoc);
346
+ preserveEditorDataAttributes(element, composeResult.normalizedElement, tagName);
323
347
  composeResult.warnings.forEach(warning => {
324
348
  console.warn(`[QTI Composer] ${warning.message}`);
325
349
  });
@@ -342,14 +366,17 @@ function composeAndNormalizeItemBody(itemBody, xmlDoc) {
342
366
  if (composeResult.responseDeclaration) {
343
367
  maxScore += composeResult.responseDeclaration.score ?? 1;
344
368
  }
345
- if (composeResult.responseDeclaration && !seenIdentifiers.has(composeResult.responseDeclaration.identifier)) {
369
+ if (composeResult.responseDeclaration) {
370
+ const declaration = composeResult.responseDeclaration;
371
+ if (seenIdentifiers.has(declaration.identifier)) {
372
+ const freshId = `RESPONSE_${crypto.randomUUID()}`;
373
+ composeResult.normalizedElement.setAttribute('response-identifier', freshId);
374
+ declaration.identifier = freshId;
375
+ }
346
376
  const responseProcessingKind = composeResult
347
377
  .responseProcessingKind;
348
- declarations.push({
349
- ...composeResult.responseDeclaration,
350
- responseProcessingKind,
351
- });
352
- seenIdentifiers.add(composeResult.responseDeclaration.identifier);
378
+ declarations.push({ ...declaration, responseProcessingKind });
379
+ seenIdentifiers.add(declaration.identifier);
353
380
  }
354
381
  if (composeResult.responseProcessingTemplate && composeResult.responseDeclaration) {
355
382
  templateCandidates.add(composeResult.responseProcessingTemplate);
@@ -366,16 +393,17 @@ function composeAndNormalizeItemBody(itemBody, xmlDoc) {
366
393
  itemBody.querySelectorAll('[score]').forEach(element => {
367
394
  element.removeAttribute('score');
368
395
  });
369
- normalizeResponseIdentifiers(itemBody, declarations);
370
396
  if (declarations.length === 1 && templateCandidates.size === 1) {
371
- return { declarations, responseTemplate: Array.from(templateCandidates)[0], maxScore };
397
+ return { declarations, responseTemplate: Array.from(templateCandidates)[0], maxScore, hasAutomatedProcessing: true };
372
398
  }
373
- return { declarations, responseTemplate: MATCH_CORRECT_TEMPLATE, maxScore };
399
+ return { declarations, responseTemplate: MATCH_CORRECT_TEMPLATE, maxScore, hasAutomatedProcessing: templateCandidates.size > 0 };
374
400
  }
375
401
  function buildMultiInteractionResponseProcessing(xmlDoc, declarations) {
376
402
  const responseProcessing = xmlDoc.createElementNS(QTI_NS, 'qti-response-processing');
377
403
  declarations.forEach(declaration => {
378
- const kind = declaration.responseProcessingKind ?? 'match_correct';
404
+ if (declaration.responseProcessingKind === undefined)
405
+ return;
406
+ const kind = declaration.responseProcessingKind;
379
407
  if (kind === 'match_correct') {
380
408
  responseProcessing.appendChild(createMatchCorrectContribution(xmlDoc, declaration.identifier, declaration.score ?? 1));
381
409
  return;
@@ -408,16 +436,12 @@ function createMatchCorrectContribution(xmlDoc, responseIdentifier, score = 1) {
408
436
  }
409
437
  function createMapResponseContribution(xmlDoc, responseIdentifier) {
410
438
  const mapResponse = xmlDoc.createElementNS(QTI_NS, 'qti-map-response');
411
- const variable = xmlDoc.createElementNS(QTI_NS, 'qti-variable');
412
- variable.setAttribute('identifier', responseIdentifier);
413
- mapResponse.appendChild(variable);
439
+ mapResponse.setAttribute('identifier', responseIdentifier);
414
440
  return createScoreIncrement(xmlDoc, mapResponse);
415
441
  }
416
442
  function createMapResponsePointContribution(xmlDoc, responseIdentifier) {
417
443
  const mapResponsePoint = xmlDoc.createElementNS(QTI_NS, 'qti-map-response-point');
418
- const variable = xmlDoc.createElementNS(QTI_NS, 'qti-variable');
419
- variable.setAttribute('identifier', responseIdentifier);
420
- mapResponsePoint.appendChild(variable);
444
+ mapResponsePoint.setAttribute('identifier', responseIdentifier);
421
445
  return createScoreIncrement(xmlDoc, mapResponsePoint);
422
446
  }
423
447
  function createScoreIncrement(xmlDoc, contribution) {
@@ -431,34 +455,6 @@ function createScoreIncrement(xmlDoc, contribution) {
431
455
  setOutcomeValue.appendChild(sum);
432
456
  return setOutcomeValue;
433
457
  }
434
- function normalizeResponseIdentifiers(itemBody, declarations) {
435
- if (declarations.length === 0)
436
- return;
437
- const identifierMap = new Map();
438
- if (declarations.length === 1) {
439
- identifierMap.set(declarations[0].identifier, 'RESPONSE');
440
- }
441
- else {
442
- declarations.forEach((declaration, index) => {
443
- identifierMap.set(declaration.identifier, `RESPONSE${index + 1}`);
444
- });
445
- }
446
- itemBody.querySelectorAll('[response-identifier]').forEach(interaction => {
447
- const currentIdentifier = interaction.getAttribute('response-identifier')?.trim();
448
- if (!currentIdentifier)
449
- return;
450
- const mappedIdentifier = identifierMap.get(currentIdentifier);
451
- if (mappedIdentifier) {
452
- interaction.setAttribute('response-identifier', mappedIdentifier);
453
- }
454
- });
455
- declarations.forEach(declaration => {
456
- const mappedIdentifier = identifierMap.get(declaration.identifier);
457
- if (mappedIdentifier) {
458
- declaration.identifier = mappedIdentifier;
459
- }
460
- });
461
- }
462
458
  export function formatXml(xml) {
463
459
  const PADDING = ' ';
464
460
  const reg = /(>)(<)(\/*)/g;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@qti-editor/core",
3
- "version": "1.3.1",
3
+ "version": "1.4.0",
4
4
  "description": "QTI semantics, composer registry, and XML export orchestration for QTI Editor",
5
5
  "repository": {
6
6
  "type": "git",
@@ -24,19 +24,19 @@
24
24
  }
25
25
  },
26
26
  "dependencies": {
27
- "@qti-editor/interfaces": "1.2.0",
28
- "@qti-editor/interaction-associate": "1.2.1",
29
- "@qti-editor/interaction-choice": "1.2.1",
30
- "@qti-editor/interaction-extended-text": "1.2.1",
31
- "@qti-editor/interaction-gap-match": "1.1.0",
32
- "@qti-editor/interaction-hottext": "1.2.2",
33
- "@qti-editor/interaction-inline-choice": "1.2.1",
34
- "@qti-editor/interaction-match": "1.2.0",
35
- "@qti-editor/interaction-order": "0.6.0",
36
- "@qti-editor/interaction-select-point": "1.2.0",
37
- "@qti-editor/interaction-shared": "1.3.0",
38
- "@qti-editor/interaction-text-entry": "1.2.0",
39
- "@qti-editor/qti-item-divider": "1.1.0"
27
+ "@qti-editor/interfaces": "1.2.1",
28
+ "@qti-editor/interaction-associate": "1.2.3",
29
+ "@qti-editor/interaction-choice": "1.2.2",
30
+ "@qti-editor/interaction-extended-text": "1.3.0",
31
+ "@qti-editor/interaction-gap-match": "1.1.1",
32
+ "@qti-editor/interaction-hottext": "1.2.3",
33
+ "@qti-editor/interaction-inline-choice": "1.3.0",
34
+ "@qti-editor/interaction-match": "1.2.1",
35
+ "@qti-editor/interaction-order": "0.6.1",
36
+ "@qti-editor/interaction-select-point": "1.2.1",
37
+ "@qti-editor/interaction-shared": "1.3.1",
38
+ "@qti-editor/interaction-text-entry": "1.2.1",
39
+ "@qti-editor/qti-item-divider": "1.1.2"
40
40
  },
41
41
  "devDependencies": {
42
42
  "@types/node": "^20.0.0",