@citolab/qti-components 7.13.0 → 7.14.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 (33) hide show
  1. package/cdn/index.global.js +1 -1
  2. package/cdn/index.js +103 -103
  3. package/custom-elements.json +1128 -315
  4. package/dist/chunks/{chunk-IHE5M7QU.js → chunk-CNLDFJAA.js} +4 -4
  5. package/dist/chunks/chunk-CNLDFJAA.js.map +1 -0
  6. package/dist/chunks/{chunk-WFUXZ4UT.js → chunk-LJ4KAG72.js} +26 -36
  7. package/dist/chunks/chunk-LJ4KAG72.js.map +1 -0
  8. package/dist/chunks/{chunk-TFNRSY74.js → chunk-SJGUMIKK.js} +24 -19
  9. package/dist/chunks/chunk-SJGUMIKK.js.map +1 -0
  10. package/dist/chunks/{chunk-XI7S3HP2.js → chunk-XD7DR5YG.js} +363 -337
  11. package/dist/chunks/chunk-XD7DR5YG.js.map +1 -0
  12. package/dist/exports/qti-test.d.ts +2 -2
  13. package/dist/index.d.ts +3 -3
  14. package/dist/index.js +47 -36
  15. package/dist/index.js.map +1 -1
  16. package/dist/qti-components/index.d.ts +10 -9
  17. package/dist/qti-components/index.js +4 -2
  18. package/dist/qti-components-jsx.d.ts +15 -15
  19. package/dist/qti-item/index.js +2 -2
  20. package/dist/qti-loader/index.js +2 -2
  21. package/dist/qti-loader/index.js.map +1 -1
  22. package/dist/qti-test/index.d.ts +3 -3
  23. package/dist/qti-test/index.js +3 -3
  24. package/dist/{qti-test-DEJqAn7G.d.ts → qti-test-Db7oNIWY.d.ts} +1 -1
  25. package/dist/{qti-transform-test-DkSRdVBF.d.ts → qti-transform-test-Bz9A3hmD.d.ts} +2 -5
  26. package/dist/qti-transformers/index.d.ts +3 -3
  27. package/dist/qti-transformers/index.js +1 -1
  28. package/dist/vscode.html-custom-data.json +4 -21
  29. package/package.json +10 -1
  30. package/dist/chunks/chunk-IHE5M7QU.js.map +0 -1
  31. package/dist/chunks/chunk-TFNRSY74.js.map +0 -1
  32. package/dist/chunks/chunk-WFUXZ4UT.js.map +0 -1
  33. package/dist/chunks/chunk-XI7S3HP2.js.map +0 -1
@@ -6,7 +6,7 @@ import {
6
6
  } from "./chunk-ELDMXTUQ.js";
7
7
  import {
8
8
  qtiTransformItem
9
- } from "./chunk-WFUXZ4UT.js";
9
+ } from "./chunk-LJ4KAG72.js";
10
10
  import {
11
11
  computedItemContext
12
12
  } from "./chunk-4OGJBG35.js";
@@ -33,8 +33,8 @@ var ItemContainer = class extends LitElement {
33
33
  async handleItemURLChange() {
34
34
  if (!this.itemURL) return;
35
35
  try {
36
- const { promise: api } = await qtiTransformItem().load(this.itemURL);
37
- this.itemDoc = (await api).htmlDoc();
36
+ const api = await qtiTransformItem().load(this.itemURL);
37
+ this.itemDoc = api.htmlDoc();
38
38
  } catch (error) {
39
39
  console.error("Error loading or parsing XML:", error);
40
40
  }
@@ -362,4 +362,4 @@ export {
362
362
  ItemShowCorrectResponse,
363
363
  QtiItem
364
364
  };
365
- //# sourceMappingURL=chunk-IHE5M7QU.js.map
365
+ //# sourceMappingURL=chunk-CNLDFJAA.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/lib/qti-item/components/item-container.ts","../../src/lib/qti-item/components/print-item-variables.ts","../../src/lib/qti-item/components/item-show-correct-response.ts","../../src/lib/qti-item/components/styles.ts","../../src/lib/qti-item/core/qti-item.ts"],"sourcesContent":["import { LitElement, html } from 'lit';\nimport { customElement, property, state } from 'lit/decorators.js';\nimport { until } from 'lit/directives/until.js';\n\nimport { watch } from '../../decorators/watch';\nimport itemCss from '../../../item.css?inline';\nimport { qtiTransformItem } from '../../qti-transformers';\n\n/**\n * `<item-container>` is a custom element designed for hosting the qti-assessment-item.\n * The `qti-assessment-item` will be placed inside the shadow DOM of this element.\n * The element loads the item from the provided URL and renders it inside the shadow DOM.\n *\n * ### Styling\n * Add a class to the element for styling.\n *\n * ```html\n * <qti-item>\n * <item-container class=\"m-4 bg-white\" item-url=\"./path/to/item.xml\"></item-container>\n * </qti-item>\n * ```\n */\n@customElement('item-container')\nexport class ItemContainer extends LitElement {\n /** URL of the item to load */\n @property({ type: String, attribute: 'item-url' })\n itemURL: string = null;\n\n /** A parsed HTML document */\n @state()\n itemDoc: DocumentFragment = null;\n\n /** The raw XML string */\n @state()\n itemXML: string = null;\n\n /** Template content if provided */\n private templateContent = null;\n\n @watch('itemURL', { waitUntilFirstUpdate: true })\n protected async handleItemURLChange() {\n if (!this.itemURL) return;\n try {\n const api = await qtiTransformItem().load(this.itemURL);\n this.itemDoc = api.htmlDoc();\n } catch (error) {\n console.error('Error loading or parsing XML:', error);\n }\n }\n\n @watch('itemXML', { waitUntilFirstUpdate: true })\n protected handleItemXMLChange() {\n if (!this.itemXML) return;\n try {\n this.itemDoc = qtiTransformItem().parse(this.itemXML).htmlDoc();\n } catch (error) {\n console.error('Error parsing XML:', error);\n }\n }\n\n async connectedCallback(): Promise<void> {\n super.connectedCallback();\n this.initializeTemplateContent();\n this.applyStyles();\n if (this.itemURL) {\n this.handleItemURLChange();\n }\n if (this.itemXML) {\n this.handleItemXMLChange();\n }\n }\n\n private initializeTemplateContent() {\n const template = this.querySelector('template') as HTMLTemplateElement;\n this.templateContent = template ? template.content : html``;\n }\n\n private applyStyles() {\n const sheet = new CSSStyleSheet();\n sheet.replaceSync(itemCss);\n this.shadowRoot.adoptedStyleSheets = [sheet];\n }\n\n render() {\n return html`\n ${this.templateContent}\n <slot></slot>\n ${until(this.itemDoc, html`<span>Loading...</span>`)}\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'item-container': ItemContainer;\n }\n}\n","import { consume } from '@lit/context';\nimport { css, html, LitElement } from 'lit';\nimport { customElement } from 'lit/decorators.js';\n\nimport { computedItemContext } from '../../exports/computed-item.context';\n\nimport type { ResponseVariable } from '../../exports/variables';\nimport type { ComputedItemContext } from '../../exports/computed-item.context';\n\n@customElement('print-item-variables')\nexport class PrintItemVariables extends LitElement {\n @consume({ context: computedItemContext, subscribe: true })\n protected computedContext?: ComputedItemContext;\n\n static styles = css`\n table {\n width: 100%;\n border-collapse: collapse;\n margin: 20px 0;\n font-size: 14px;\n text-align: left;\n }\n th,\n td {\n border: 1px solid #ddd;\n padding: 8px;\n }\n th {\n background-color: #f4f4f4;\n font-weight: bold;\n }\n h3 {\n margin-top: 20px;\n font-size: 16px;\n }\n `;\n\n render() {\n const activeItem = this.computedContext;\n\n if (!activeItem || !activeItem.variables) return html``;\n\n const responseVariables: ResponseVariable[] = activeItem.variables.filter(v => v.type === 'response');\n const outcomeVariables = activeItem.variables.filter(v => v.type === 'outcome');\n\n const renderTable = (variables: ResponseVariable[], title: string) => html`\n <h3>${title}</h3>\n <table>\n <thead>\n <tr>\n <th>Identifier</th>\n <th>Value</th>\n <th>Cardinality</th>\n <th>Base Type</th>\n <th>Correct Response / Mappings</th>\n </tr>\n </thead>\n <tbody>\n ${variables.map(v => {\n const correctResponse = v.correctResponse\n ? Array.isArray(v.correctResponse)\n ? v.correctResponse.join(', ')\n : v.correctResponse\n : '';\n\n const mapEntries = v.mapping?.mapEntries?.map(m => `${m.mapKey}=${m.mappedValue}pt`).join(', ') || '';\n\n const areaMapEntries =\n v.areaMapping?.areaMapEntries?.map(m => `${m.shape}(${m.coords})=${m.mappedValue}pt`).join(', ') || '';\n\n return html`\n <tr>\n <td>${v.identifier}</td>\n <td>${Array.isArray(v.value) ? v.value.join(', ') : v.value}</td>\n <td>${v.cardinality}</td>\n <td>${v.baseType}</td>\n <td>${correctResponse || mapEntries || areaMapEntries}</td>\n </tr>\n `;\n })}\n </tbody>\n </table>\n `;\n\n return html`\n ${renderTable(responseVariables, 'Response Variables')} ${renderTable(outcomeVariables, 'Outcome Variables')}\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'print-item-variables': PrintItemVariables;\n }\n}\n","import { css, html, LitElement } from 'lit';\nimport { customElement, property } from 'lit/decorators.js';\nimport { consume } from '@lit/context';\n\nimport * as styles from './styles';\nimport { computedItemContext } from '../../exports/computed-item.context';\n\nimport type { ComputedItemContext } from '../../exports/computed-item.context';\n\n@customElement('item-show-correct-response')\nexport class ItemShowCorrectResponse extends LitElement {\n @consume({ context: computedItemContext, subscribe: true })\n public computedContext?: ComputedItemContext;\n\n static styles = css`\n :host {\n ${styles.btn};\n }\n :host([disabled]) {\n ${styles.dis};\n }\n `;\n\n @property({ type: Boolean, reflect: true }) shown = false;\n @property({ type: Boolean, reflect: true }) disabled = false; // Reflects to `disabled` attribute\n @property({ type: String }) showCorrectText = 'Show correct response';\n @property({ type: String }) hideCorrectText = 'Hide correct response';\n @property({ type: String }) noCorrectResponseText = 'No correct response specified';\n\n private _hasCorrectResponse = false; // correct response is removed on certain point\n private _previousActiveItem = ''; // Store previous active item reference\n\n updated() {\n if (!this._hasCorrectResponse || this._previousActiveItem !== this.computedContext?.identifier) {\n this._previousActiveItem = this.computedContext?.identifier;\n const containsCorrectResponse = !!this.computedContext?.variables.some(v => v['correctResponse']);\n const containsMapping = !!this.computedContext?.variables.some(v => {\n return v['mapping']?.mapEntries?.length > 0 || v['areaMapping']?.areaMapEntries?.length > 0;\n });\n this._hasCorrectResponse = containsCorrectResponse || containsMapping;\n }\n this.disabled = !this._hasCorrectResponse;\n }\n\n private _toggleState() {\n if (this.disabled) return; // Prevent toggle if disabled\n\n this.dispatchEvent(\n new CustomEvent('item-show-correct-response', {\n detail: !this.shown,\n bubbles: true\n })\n );\n }\n\n private _getDisplayedText(): string {\n return this.disabled ? this.noCorrectResponseText : this.shown ? this.hideCorrectText : this.showCorrectText;\n }\n\n render() {\n return html` <div @click=\"${this._toggleState}\">${this._getDisplayedText()}</div> `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'item-show-correct-response': ItemShowCorrectResponse;\n }\n}\n","// /* eslint-disable lit-plugin(no-invalid-css) */\nimport { css } from 'lit';\n\nexport const form = css`\n display: inline-flex;\n align-items: center;\n cursor: pointer;\n padding: 0.5rem 1rem;\n border-radius: 0.25rem;\n user-select: none;\n`;\n\nexport const btn = css`\n background-color: lightgray;\n ${form};\n`;\n\nexport const dis = css`\n cursor: not-allowed;\n opacity: 0.8;\n`;\n\nexport const ind = css`\n ${form};\n border: 1px solid gray;\n`;\n","import { provide } from '@lit/context';\nimport { html, LitElement } from 'lit';\nimport { customElement, state } from 'lit/decorators.js';\n\nimport { computedItemContext } from '../../exports/computed-item.context';\nimport { configContext } from '../../exports/config.context.ts';\n\nimport type { QtiAssessmentItem } from '../../qti-components/qti-assessment-item/qti-assessment-item.ts';\nimport type { ConfigContext, CorrectResponseMode } from '../../exports/config.context.ts';\nimport type { ItemContext } from '../../exports/item.context';\nimport type { VariableDeclaration } from '../../exports/variables';\nimport type { ComputedItemContext } from '../../exports/computed-item.context';\n\n/**\n * `<qti-item>` is a custom element designed for rendering a single `qti-assessment-item`.\n * It can also host some functionalities to interact with the item like scoring, showing feedback, etc.\n * Placing a mandatory `<item-container>` inside '<qti-item>' will load or parse the item and render it.\n * See `<item-container>` for more details.\n *\n * ```html\n * <qti-item>\n * <item-container class=\"m-4 bg-white\" item-url=\"./path/to/item.xml\"></item-container>\n * </qti-item>\n * ```\n */\n@customElement('qti-item')\nexport class QtiItem extends LitElement {\n @state()\n @provide({ context: computedItemContext })\n public computedContext: ComputedItemContext;\n private _qtiAssessmentItem?: QtiAssessmentItem;\n\n @state()\n @provide({ context: configContext })\n public configContext: ConfigContext = {};\n\n // Store event handlers as instance properties\n private _onItemContextChanged = this._handleItemContextChanged.bind(this);\n private _onAssessmentItemConnected = this._handleAssessmentItemConnected.bind(this);\n\n private _onHandleShowCorrectResponse = this._handleShowCorrectResponse.bind(this);\n private _onHandleShowCandidateCorrection = this._handleShowCandidateCorrection.bind(this);\n private _onHandleSwitchCorrectResponseMode = this._handleSwitchCorrectResponseMode.bind(this);\n\n constructor() {\n super();\n this.addEventListener('qti-item-context-updated', this._onItemContextChanged);\n this.addEventListener('qti-assessment-item-connected', this._onAssessmentItemConnected);\n this.addEventListener('item-show-correct-response', this._onHandleShowCorrectResponse);\n this.addEventListener('item-show-candidate-correction', this._onHandleShowCandidateCorrection);\n this.addEventListener('item-switch-correct-response-mode', this._onHandleSwitchCorrectResponseMode);\n }\n\n private _handleItemContextChanged(e: CustomEvent<{ itemContext: ItemContext }>) {\n this._updateItemVariablesInTestContext(e.detail.itemContext.identifier, e.detail?.itemContext?.variables || []);\n }\n\n private _handleAssessmentItemConnected(e: CustomEvent<QtiAssessmentItem>) {\n const fullVariables = (e.detail as any)._context.variables;\n this._qtiAssessmentItem = e.detail;\n this.computedContext =\n this.computedContext?.identifier === this._qtiAssessmentItem.identifier\n ? { ...this.computedContext, title: this._qtiAssessmentItem.title }\n : ({\n identifier: this._qtiAssessmentItem.identifier,\n title: this._qtiAssessmentItem.title,\n adaptive: this._qtiAssessmentItem.getAttribute('adaptive')?.toLowerCase() === 'true' || false,\n variables: fullVariables,\n correctResponseMode: 'internal'\n } as ComputedItemContext);\n this._updateItemVariablesInTestContext(this._qtiAssessmentItem.identifier, fullVariables || []);\n }\n\n private _handleShowCorrectResponse(e: CustomEvent<boolean>) {\n if (this._qtiAssessmentItem) {\n this._qtiAssessmentItem.showCorrectResponse(e.detail);\n }\n }\n\n private _handleShowCandidateCorrection(e: CustomEvent<boolean>) {\n if (this._qtiAssessmentItem) {\n this._qtiAssessmentItem.showCandidateCorrection(e.detail);\n }\n }\n\n private _handleSwitchCorrectResponseMode(e: CustomEvent<CorrectResponseMode>) {\n // Switch off the correct response first\n this._handleShowCorrectResponse(new CustomEvent('item-show-correct-response', { detail: false, bubbles: true }));\n\n this.configContext = {\n ...this.configContext,\n correctResponseMode: e.detail\n };\n }\n\n private _updateItemVariablesInTestContext(\n identifier: string,\n variables: readonly VariableDeclaration<string | string[] | null>[]\n ): void {\n const rawscore = variables?.find(vr => vr.identifier == 'SCORE')?.value;\n const score = parseFloat(rawscore?.toString());\n const completionStatus = variables?.find(v => v.identifier === 'completionStatus')?.value;\n\n const correct = score !== undefined && !isNaN(score) && score > 0;\n const incorrect = score !== undefined && !isNaN(score) && score <= 0;\n const completed = completionStatus === 'completed';\n this.computedContext = {\n ...this.computedContext,\n identifier,\n correct,\n incorrect,\n completed,\n variables\n };\n }\n\n render() {\n return html`<slot></slot>`;\n }\n\n override disconnectedCallback() {\n super.disconnectedCallback();\n this.removeEventListener('qti-item-context-changed', this._onItemContextChanged);\n this.removeEventListener('qti-assessment-item-connected', this._onAssessmentItemConnected);\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'qti-item': QtiItem;\n }\n}\n"],"mappings":"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","names":["html","LitElement","customElement","LitElement","html","customElement","css","html","LitElement","customElement","property","consume","css","LitElement","html","css","consume","property","customElement","html","LitElement","customElement","state","LitElement","html","state","customElement"]}
@@ -65,24 +65,21 @@ function itemsFromTest(xmlFragment) {
65
65
  });
66
66
  return items;
67
67
  }
68
- function loadXML(url) {
69
- const xhr = new XMLHttpRequest();
70
- const promise = new Promise((resolve, reject) => {
71
- xhr.open("GET", url, true);
72
- xhr.responseType = "document";
73
- xhr.onload = () => {
74
- if (xhr.status >= 200 && xhr.status < 300) {
75
- resolve(xhr.responseXML);
76
- } else {
77
- reject(xhr.statusText);
78
- }
79
- };
80
- xhr.onerror = () => {
81
- reject(xhr.statusText);
82
- };
83
- xhr.send();
68
+ function loadXML(url, signal) {
69
+ return fetch(url, { signal }).then((response) => {
70
+ if (!response.ok) {
71
+ throw new Error(`HTTP error! status: ${response.status}`);
72
+ }
73
+ return response.text();
74
+ }).then((text) => {
75
+ const parser = new DOMParser();
76
+ return parser.parseFromString(text, "text/xml");
77
+ }).catch((error) => {
78
+ if (error.name === "AbortError") {
79
+ throw error;
80
+ }
81
+ throw new Error(`Failed to load XML: ${error.message}`);
84
82
  });
85
- return { promise, xhr };
86
83
  }
87
84
  function parseXML(xmlDocument) {
88
85
  const parser = new DOMParser();
@@ -153,27 +150,20 @@ var qtiTransformItem = (cache = false) => {
153
150
  let xmlFragment;
154
151
  let xmlUri = "";
155
152
  const api = {
156
- load(uri) {
153
+ load(uri, signal) {
157
154
  xmlUri = uri;
158
155
  const fullKey = encodeURI(uri);
159
156
  if (cache) {
160
157
  if (sessionStorage.getItem(fullKey)) {
161
- return {
162
- promise: Promise.resolve(api.parse(sessionStorage.getItem(fullKey))),
163
- request: null
164
- };
158
+ return Promise.resolve(api.parse(sessionStorage.getItem(fullKey)));
165
159
  }
166
160
  }
167
- const { promise, xhr } = loadXML(uri);
168
- const a = new Promise((resolve) => {
169
- promise.then((xml2) => {
170
- xmlFragment = xml2;
171
- api.shuffleInteractions();
172
- if (cache) sessionStorage.setItem(fullKey, new XMLSerializer().serializeToString(xmlFragment));
173
- return resolve(api);
174
- });
161
+ return loadXML(uri, signal).then((xml2) => {
162
+ xmlFragment = xml2;
163
+ api.shuffleInteractions();
164
+ if (cache) sessionStorage.setItem(fullKey, new XMLSerializer().serializeToString(xmlFragment));
165
+ return api;
175
166
  });
176
- return { promise: a, request: xhr };
177
167
  },
178
168
  parse(xmlString) {
179
169
  xmlFragment = parseXML(xmlString);
@@ -431,9 +421,9 @@ var qtiTransformItem = (cache = false) => {
431
421
  var qtiTransformManifest = () => {
432
422
  let xmlFragment;
433
423
  const api = {
434
- async load(uri) {
424
+ async load(uri, signal) {
435
425
  return new Promise((resolve) => {
436
- loadXML(uri).promise.then((xml2) => {
426
+ loadXML(uri, signal).then((xml2) => {
437
427
  xmlFragment = xml2;
438
428
  return resolve(api);
439
429
  });
@@ -454,9 +444,9 @@ var qtiTransformManifest = () => {
454
444
  var qtiTransformTest = () => {
455
445
  let xmlFragment;
456
446
  const api = {
457
- async load(uri) {
447
+ async load(uri, signal) {
458
448
  return new Promise((resolve, _) => {
459
- loadXML(uri).promise.then((xml2) => {
449
+ loadXML(uri, signal).then((xml2) => {
460
450
  xmlFragment = xml2;
461
451
  api.path(uri.substring(0, uri.lastIndexOf("/")));
462
452
  return resolve(api);
@@ -499,4 +489,4 @@ export {
499
489
  qtiTransformManifest,
500
490
  qtiTransformTest
501
491
  };
502
- //# sourceMappingURL=chunk-WFUXZ4UT.js.map
492
+ //# sourceMappingURL=chunk-LJ4KAG72.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/lib/qti-transformers/qti-transformers.ts","../../src/lib/qti-transformers/qti-transform-item.ts","../../src/lib/qti-transformers/qti-transform-manifest.ts","../../src/lib/qti-transformers/qti-transform-test.ts"],"sourcesContent":["const xml = String.raw;\n\n/* <!-- convert CDATA to comments -->\n <xsl:template match=\"text()[contains(., 'CDATA')]\">\n <xsl:comment>\n <xsl:value-of select=\".\"/>\n </xsl:comment>\n</xsl:template>\n*/\n\n/*\n <!-- remove xml comments -->\n <xsl:template match=\"comment()\" />\n */\n\nconst xmlToHTML = xml`<xsl:stylesheet version=\"1.0\" xmlns:xsl=\"http://www.w3.org/1999/XSL/Transform\">\n<xsl:output method=\"html\" version=\"5.0\" encoding=\"UTF-8\" indent=\"yes\" />\n <xsl:template match=\"@*|node()\">\n <xsl:copy>\n <xsl:apply-templates select=\"@*|node()\"/>\n </xsl:copy>\n </xsl:template>\n\n <!-- remove existing namespaces -->\n <xsl:template match=\"*\">\n <!-- remove element prefix -->\n <xsl:element name=\"{local-name()}\">\n <!-- process attributes -->\n <xsl:for-each select=\"@*\">\n <!-- remove attribute prefix -->\n <xsl:attribute name=\"{local-name()}\">\n <xsl:value-of select=\".\"/>\n </xsl:attribute>\n </xsl:for-each>\n <xsl:apply-templates/>\n </xsl:element>\n</xsl:template>\n</xsl:stylesheet>`;\n\n// Function to extend elements with a specific tag name by adding an extension suffix\nexport function extendElementName(xmlFragment: XMLDocument, tagName: string, extension: string) {\n xmlFragment.querySelectorAll(tagName).forEach(element => {\n const newTagName = `${tagName}-${extension}`;\n const newElement = createElementWithNewTagName(element, newTagName);\n element.replaceWith(newElement);\n });\n}\n\n// Function to extend any element with a specific class pattern (e.g., \"extend:suffix\")\nexport function extendElementsWithClass(xmlFragment: XMLDocument, classNamePattern: string) {\n xmlFragment.querySelectorAll('*').forEach(element => {\n const classList = element.classList;\n if (classList) {\n classList.forEach(className => {\n if (className.startsWith(`${classNamePattern}:`)) {\n const suffix = className.slice(`${classNamePattern}:`.length);\n const newTagName = `${element.nodeName}-${suffix}`;\n const newElement = createElementWithNewTagName(element, newTagName);\n element.replaceWith(newElement);\n }\n });\n }\n });\n}\n\n// Helper function to create a new element with a new tag name and copy attributes and children\nfunction createElementWithNewTagName(element, newTagName) {\n const newElement = document.createElement(newTagName);\n // Copy attributes\n for (const attr of element.attributes) {\n newElement.setAttribute(attr.name, attr.value);\n }\n // Copy child nodes\n while (element.firstChild) {\n newElement.appendChild(element.firstChild);\n }\n return newElement;\n}\n\nexport function itemsFromTest(xmlFragment: DocumentFragment) {\n const items: { identifier: string; href: string; category: string }[] = [];\n xmlFragment.querySelectorAll('qti-assessment-item-ref').forEach(el => {\n const identifier = el.getAttribute('identifier');\n const href = el.getAttribute('href');\n const category = el.getAttribute('category');\n items.push({ identifier, href, category });\n });\n return items;\n}\n\n// let currentRequest: XMLHttpRequest | null = null;\n\nexport function loadXML(url: string, signal?: AbortSignal): Promise<XMLDocument | null> {\n return fetch(url, { signal })\n .then(response => {\n if (!response.ok) {\n throw new Error(`HTTP error! status: ${response.status}`);\n }\n return response.text();\n })\n .then(text => {\n const parser = new DOMParser();\n return parser.parseFromString(text, 'text/xml');\n })\n .catch(error => {\n if (error.name === 'AbortError') {\n throw error;\n }\n throw new Error(`Failed to load XML: ${error.message}`);\n });\n}\n\nexport function parseXML(xmlDocument: string) {\n const parser = new DOMParser();\n const xmlFragment = parser.parseFromString(xmlDocument, 'text/xml');\n return xmlFragment;\n}\n\nexport function toHTML(xmlFragment: Document): DocumentFragment {\n const processor = new XSLTProcessor();\n const xsltDocument = new DOMParser().parseFromString(xmlToHTML, 'text/xml');\n processor.importStylesheet(xsltDocument);\n const itemHTMLFragment = processor.transformToFragment(xmlFragment, document);\n return itemHTMLFragment;\n}\n\nexport function setLocation(xmlFragment: DocumentFragment, location: string) {\n if (!location.endsWith('/')) {\n location += '/';\n }\n\n xmlFragment.querySelectorAll('[src],[href],[primary-path]').forEach(elWithSrc => {\n let attr: 'src' | 'href' | 'primary-path' | '' = '';\n\n if (elWithSrc.getAttribute('src')) {\n attr = 'src';\n }\n if (elWithSrc.getAttribute('href')) {\n attr = 'href';\n }\n if (elWithSrc.getAttribute('primary-path')) {\n attr = 'primary-path';\n }\n const attrValue = elWithSrc.getAttribute(attr)?.trim();\n\n if (!/^(data:|https?:|blob:)/.test(attrValue)) {\n const newSrcValue = location + encodeURI(attrValue);\n elWithSrc.setAttribute(attr, newSrcValue);\n }\n });\n}\n\nexport function convertCDATAtoComment(xmlFragment: DocumentFragment) {\n const cdataElements = xmlFragment.querySelectorAll('qti-custom-operator[class=\"js.org\"] > qti-base-value');\n cdataElements.forEach(element => {\n const commentText = document.createComment(element.textContent);\n element.replaceChild(commentText, element.firstChild);\n });\n}\n\nexport function stripStyleSheets(xmlFragment: DocumentFragment) {\n // remove qti-stylesheet tag\n xmlFragment.querySelectorAll('qti-stylesheet').forEach(stylesheet => stylesheet.remove());\n}\n\nexport function getShuffleQuerySelectorByTagName(tagName: string) {\n switch (tagName) {\n case 'qti-choice-interaction':\n case 'qti-order-interaction':\n return 'qti-simple-choice';\n case 'qti-inline-choice-interaction':\n return 'qti-inline-choice';\n case 'qti-match-interaction':\n return [\n 'qti-simple-match-set:first-of-type qti-simple-associable-choice',\n 'qti-simple-match-set:last-of-type > qti-simple-associable-choice'\n ];\n case 'qti-gap-match-interaction':\n return 'qti-gap-text';\n case 'qti-associate-interaction':\n return 'qti-simple-associable-choice';\n default:\n }\n}\n","/**\n * Browser based QTI-XML to HTML transformer.\n * Returns an object with methods to load, parse, transform and serialize QTI XML items.\n * @returns An object with methods to load, parse, transform and serialize QTI XML items.\n * @example\n * const qtiTransformer = qtiTransformItem();\n * await qtiTransformer.load('path/to/xml/file.xml');\n * qtiTransformer.path('/assessmentItem/itemBody');\n * const html = qtiTransformer.html();\n * const xml = qtiTransformer.xml();\n * const htmldoc = qtiTransformer.htmldoc();\n * const xmldoc = qtiTransformer.xmldoc();\n *\n * qtiTransformItem().parse(storyXML).html()\n */\nimport {\n convertCDATAtoComment,\n extendElementName,\n extendElementsWithClass,\n getShuffleQuerySelectorByTagName,\n loadXML,\n parseXML,\n setLocation,\n stripStyleSheets,\n toHTML\n} from './qti-transformers';\n\n// Type definition for module resolution config\nexport interface ModuleResolutionConfig {\n waitSeconds?: number;\n context?: string;\n catchError?: boolean;\n urlArgs?: string;\n paths: {\n [key: string]: string | string[];\n };\n shim?: {\n [key: string]: {\n deps?: string[]; // Array of dependencies\n exports?: string; // The global variable to use as the module's value\n };\n };\n}\n\nexport type transformItemApi = {\n load: (uri: string, signal?: AbortSignal) => Promise<transformItemApi>;\n parse: (xmlString: string) => transformItemApi;\n path: (location: string) => transformItemApi;\n fn: (fn: (xmlFragment: XMLDocument) => void) => transformItemApi;\n pciHooks: (uri: string) => transformItemApi;\n configurePci: (\n baseUrl: string,\n getModuleResolutionConfig: (baseUrl: string, fileUrl: string) => Promise<ModuleResolutionConfig>,\n selector?: string\n ) => Promise<transformItemApi>;\n extendElementName: (elementName: string, extend: string) => transformItemApi;\n extendElementsWithClass: (param?: string) => transformItemApi;\n customInteraction: (baseRef: string, baseItem: string) => transformItemApi;\n convertCDATAtoComment: () => transformItemApi;\n shuffleInteractions: () => transformItemApi;\n stripStyleSheets: () => transformItemApi;\n html: () => string;\n xml: () => string;\n htmlDoc: () => DocumentFragment;\n xmlDoc: () => XMLDocument;\n};\n\nexport const qtiTransformItem = (cache: boolean = false) => {\n let xmlFragment: XMLDocument;\n let xmlUri = '';\n\n const api: transformItemApi = {\n load(uri: string, signal?: AbortSignal) {\n xmlUri = uri;\n const fullKey = encodeURI(uri);\n if (cache) {\n if (sessionStorage.getItem(fullKey)) {\n return Promise.resolve(api.parse(sessionStorage.getItem(fullKey)!));\n }\n }\n return loadXML(uri, signal).then(xml => {\n xmlFragment = xml;\n api.shuffleInteractions();\n if (cache) sessionStorage.setItem(fullKey, new XMLSerializer().serializeToString(xmlFragment));\n return api;\n });\n },\n parse(xmlString: string): typeof api {\n xmlFragment = parseXML(xmlString);\n return api;\n },\n path: (location: string): typeof api => {\n setLocation(xmlFragment, location);\n xmlUri = null;\n return api;\n },\n fn(fn: (xmlFragment: XMLDocument) => void): typeof api {\n fn(xmlFragment);\n return api;\n },\n pciHooks(uri: string): typeof api {\n const attributes = ['hook', 'module'];\n const documentPath = uri.substring(0, uri.lastIndexOf('/'));\n for (const attribute of attributes) {\n const srcAttributes = xmlFragment.querySelectorAll('[' + attribute + ']');\n srcAttributes.forEach(node => {\n const srcValue = node.getAttribute(attribute)!;\n if (!srcValue.startsWith('data:') && !srcValue.startsWith('http')) {\n // Just paste the relative path of the src location after the documentrootPath\n // old pcis can have a .js, new pci's don't\n node.setAttribute('base-url', uri);\n node.setAttribute(\n 'module',\n documentPath + '/' + encodeURI(srcValue + (srcValue.endsWith('.js') ? '' : '.js'))\n );\n }\n });\n }\n return api;\n },\n async configurePci(\n baseUrl: string,\n getModuleResolutionConfig: (baseUrl: string, fileUrl: string) => Promise<ModuleResolutionConfig>,\n selector = 'qti-portable-custom-interaction'\n ): Promise<typeof api> {\n const customInteractionTypeIdentifiers: string[] = [];\n const portableCustomInteractions = xmlFragment.querySelectorAll(selector);\n\n const moduleResolutionConfig = await getModuleResolutionConfig(baseUrl, '/modules/module_resolution.js');\n const moduleResolutionFallbackConfig = await getModuleResolutionConfig(\n baseUrl,\n '/modules/fallback_module_resolution.js'\n );\n\n if (portableCustomInteractions.length > 0) {\n for (const interaction of Array.from(portableCustomInteractions)) {\n // set data-base-url\n interaction.setAttribute('data-base-url', baseUrl);\n\n let customInteractionTypeIdentifier = interaction.getAttribute('custom-interaction-type-identifier');\n if (\n customInteractionTypeIdentifier &&\n customInteractionTypeIdentifiers.includes(customInteractionTypeIdentifier)\n ) {\n customInteractionTypeIdentifier = customInteractionTypeIdentifier + customInteractionTypeIdentifiers.length;\n interaction.setAttribute('custom-interaction-type-identifier', customInteractionTypeIdentifier);\n customInteractionTypeIdentifiers.push(customInteractionTypeIdentifier);\n }\n if (customInteractionTypeIdentifier) {\n customInteractionTypeIdentifiers.push(customInteractionTypeIdentifier);\n }\n\n // Check if qti-interaction-modules already exists\n let modulesElement = interaction.querySelector('qti-interaction-modules');\n\n // If it exists and has primary-configuration, handle that format\n if (modulesElement && modulesElement.getAttribute('primary-configuration')) {\n const primaryConfigPath = modulesElement.getAttribute('primary-configuration');\n if (primaryConfigPath) {\n try {\n // Load the primary configuration\n const primaryConfig = await getModuleResolutionConfig(baseUrl, `/${primaryConfigPath}`);\n\n // Get existing module elements that only have id attributes\n const existingModules = Array.from(modulesElement.querySelectorAll('qti-interaction-module'));\n\n // Update existing modules with paths from config\n for (const moduleEl of existingModules) {\n const moduleId = moduleEl.getAttribute('id');\n if (moduleId && primaryConfig.paths && primaryConfig.paths[moduleId]) {\n const primaryPath = primaryConfig.paths[moduleId];\n const primaryPathString = Array.isArray(primaryPath) ? primaryPath[0] : primaryPath;\n moduleEl.setAttribute('primary-path', primaryPathString);\n\n // Check for fallback path\n if (\n moduleResolutionFallbackConfig &&\n moduleResolutionFallbackConfig.paths &&\n moduleResolutionFallbackConfig.paths[moduleId]\n ) {\n const fallbackPath = moduleResolutionFallbackConfig.paths[moduleId];\n if (Array.isArray(fallbackPath)) {\n moduleEl.setAttribute('fallback-path', fallbackPath[0]);\n } else {\n moduleEl.setAttribute('fallback-path', fallbackPath);\n }\n }\n }\n }\n\n // Add any additional modules from primary config that aren't already present\n if (primaryConfig.paths) {\n for (const moduleId in primaryConfig.paths) {\n const existingModule = modulesElement.querySelector(`qti-interaction-module[id=\"${moduleId}\"]`);\n if (!existingModule) {\n const newModuleElement = xmlFragment.createElement('qti-interaction-module');\n newModuleElement.setAttribute('id', moduleId);\n const primaryPathString = Array.isArray(primaryConfig.paths[moduleId])\n ? primaryConfig.paths[moduleId][0]\n : primaryConfig.paths[moduleId];\n newModuleElement.setAttribute('primary-path', primaryPathString);\n\n // Check for fallback path\n if (\n moduleResolutionFallbackConfig &&\n moduleResolutionFallbackConfig.paths &&\n moduleResolutionFallbackConfig.paths[moduleId]\n ) {\n const fallbackPath = moduleResolutionFallbackConfig.paths[moduleId];\n if (Array.isArray(fallbackPath)) {\n newModuleElement.setAttribute('fallback-path', fallbackPath[0]);\n } else {\n newModuleElement.setAttribute('fallback-path', fallbackPath);\n }\n }\n\n modulesElement.appendChild(newModuleElement);\n }\n }\n }\n\n // Apply urlArgs if present in config\n if (primaryConfig.urlArgs) {\n modulesElement.setAttribute('url-args', primaryConfig.urlArgs);\n }\n } catch (error) {\n console.warn(`Failed to load primary configuration: ${primaryConfigPath}`, error);\n }\n }\n } else {\n // Original logic for when there's no existing qti-interaction-modules or no primary-configuration\n if (moduleResolutionConfig) {\n // Create qti-interaction-modules if it doesn't exist\n if (interaction.querySelector('qti-interaction-modules') === null) {\n modulesElement = xmlFragment.createElement('qti-interaction-modules');\n interaction.appendChild(modulesElement);\n } else {\n modulesElement = interaction.querySelector('qti-interaction-modules');\n }\n\n for (const module in moduleResolutionConfig.paths) {\n const path = moduleResolutionConfig.paths[module];\n let fallbackPath: string | string[] = '';\n\n if (\n moduleResolutionFallbackConfig &&\n moduleResolutionFallbackConfig.paths &&\n moduleResolutionFallbackConfig.paths[module]\n ) {\n fallbackPath = moduleResolutionFallbackConfig.paths[module];\n }\n\n const primaryArray = Array.isArray(path) ? path : [path];\n const fallbackPathArray = Array.isArray(fallbackPath) ? fallbackPath : [fallbackPath];\n\n // create an array with primary and fallback paths.\n const paths = primaryArray.map((primaryPath, i) => {\n const fallbackPath = fallbackPathArray.length > i ? fallbackPathArray[i] : '';\n return {\n primaryPath,\n fallbackPath\n };\n });\n\n // check if all fallbackPath elements are in the array: paths, otherwise add\n for (const fallbackPath of fallbackPathArray) {\n if (!paths.some(p => p.fallbackPath === fallbackPath)) {\n paths.push({\n primaryPath: primaryArray.length > 0 ? primaryArray[0] : fallbackPath,\n fallbackPath\n });\n }\n }\n\n // add the paths to the qti-interaction-modules\n for (const path of paths) {\n const moduleElement = xmlFragment.createElement('qti-interaction-module');\n if (path.fallbackPath) {\n moduleElement.setAttribute('fallback-path', path.fallbackPath);\n }\n moduleElement.setAttribute('id', module);\n moduleElement.setAttribute('primary-path', path.primaryPath);\n\n if (modulesElement) {\n modulesElement.appendChild(moduleElement);\n }\n }\n }\n }\n }\n }\n }\n\n return api;\n },\n shuffleInteractions(): typeof api {\n const shuffleElements = xmlFragment.querySelectorAll(`[shuffle=\"true\"]`);\n const shuffleInteractions = Array.from(shuffleElements).filter(e =>\n e.tagName?.toLowerCase().endsWith('-interaction')\n );\n\n for (const shuffleInteraction of shuffleInteractions) {\n const query = getShuffleQuerySelectorByTagName(shuffleInteraction.tagName.toLowerCase());\n const queries = Array.isArray(query) ? query : [query];\n\n for (const q of queries) {\n const choices = Array.from(shuffleInteraction.querySelectorAll(q)) as HTMLElement[];\n\n const fixedChoices = choices\n .map((choice, originalOrder) => ({\n element: choice,\n fixed: choice.hasAttribute('fixed') && choice.getAttribute('fixed') === 'true',\n originalOrder\n }))\n .filter(choice => choice.fixed);\n\n const nonFixedChoices = choices.filter(\n choice => !choice.hasAttribute('fixed') || choice.getAttribute('fixed') !== 'true'\n );\n\n if (nonFixedChoices.length <= 1) {\n console.warn('Shuffling is not possible with fewer than 2 non-fixed elements.');\n return api;\n }\n\n const originalOrder = [...nonFixedChoices];\n let shuffled = false;\n let attempts = 0;\n\n while (!shuffled && attempts < 20) {\n attempts++;\n for (let i = nonFixedChoices.length - 1; i > 0; i--) {\n const j = Math.floor(Math.random() * (i + 1));\n [nonFixedChoices[i], nonFixedChoices[j]] = [nonFixedChoices[j], nonFixedChoices[i]];\n }\n shuffled = !nonFixedChoices.every((choice, index) => choice === originalOrder[index]);\n }\n\n if (!shuffled) {\n console.warn('Failed to shuffle the choices after multiple attempts.');\n return null;\n }\n\n // Remove the shuffle attribute\n shuffleInteraction.removeAttribute('shuffle');\n\n // Reorder the elements in the DOM\n let nonFixedIndex = 0;\n for (const nonFixedChoice of nonFixedChoices) {\n nonFixedChoice.parentElement.insertBefore(nonFixedChoice, fixedChoices[nonFixedIndex]?.element);\n nonFixedIndex++;\n }\n for (const fixedChoice of fixedChoices) {\n fixedChoice.element.parentElement.insertBefore(\n fixedChoice.element,\n nonFixedChoices[fixedChoice.originalOrder]\n );\n }\n }\n }\n\n return api;\n },\n extendElementName: (tagName: string, extension: string): typeof api => {\n extendElementName(xmlFragment, tagName, extension);\n return api;\n },\n extendElementsWithClass: (param: string = 'extend'): typeof api => {\n extendElementsWithClass(xmlFragment, param);\n return api;\n },\n customInteraction(baseRef: string, baseItem: string): typeof api {\n const qtiCustomInteraction = xmlFragment.querySelector('qti-custom-interaction');\n const qtiCustomInteractionObject = qtiCustomInteraction.querySelector('object');\n\n qtiCustomInteraction.setAttribute('data-base-ref', baseRef);\n qtiCustomInteraction.setAttribute('data-base-item', baseRef + baseItem);\n qtiCustomInteraction.setAttribute('data', qtiCustomInteractionObject.getAttribute('data'));\n qtiCustomInteraction.setAttribute('width', qtiCustomInteractionObject.getAttribute('width'));\n qtiCustomInteraction.setAttribute('height', qtiCustomInteractionObject.getAttribute('height'));\n\n qtiCustomInteraction.removeChild(qtiCustomInteractionObject);\n return api;\n },\n convertCDATAtoComment(): typeof api {\n convertCDATAtoComment(xmlFragment);\n return api;\n },\n stripStyleSheets(): typeof api {\n stripStyleSheets(xmlFragment);\n return api;\n },\n html() {\n if (xmlUri !== null) {\n setLocation(xmlFragment, xmlUri.substring(0, xmlUri.lastIndexOf('/')));\n }\n return new XMLSerializer().serializeToString(toHTML(xmlFragment));\n },\n xml(): string {\n return new XMLSerializer().serializeToString(xmlFragment);\n },\n htmlDoc() {\n if (xmlUri !== null) {\n setLocation(xmlFragment, xmlUri.substring(0, xmlUri.lastIndexOf('/')));\n }\n return toHTML(xmlFragment);\n },\n xmlDoc(): XMLDocument {\n return xmlFragment; // new XMLSerializer().serializeToString(xmlFragment);\n }\n };\n return api;\n};\n","import { loadXML, parseXML } from './qti-transformers';\n\nexport const qtiTransformManifest = (): {\n load: (uri: string, signal?: AbortSignal) => Promise<typeof api>;\n assessmentTest: () => { href: string; identifier: string };\n} => {\n let xmlFragment: XMLDocument;\n\n const api = {\n async load(uri, signal) {\n return new Promise<typeof api>(resolve => {\n loadXML(uri, signal).then(xml => {\n xmlFragment = xml;\n return resolve(api);\n });\n });\n },\n parse(xmlString: string) {\n xmlFragment = parseXML(xmlString);\n },\n assessmentTest() {\n const el = xmlFragment.querySelector('resource[type=\"imsqti_test_xmlv3p0\"]');\n return { href: el.getAttribute('href'), identifier: el.getAttribute('identifier') };\n }\n };\n return api;\n};\n","/**\n * Returns an object with methods to load, parse and transform QTI tests.\n * @returns An object with methods to load, parse and transform QTI tests.\n * @example\n * const qtiTransformer = qtiTransformTest();\n * await qtiTransformer.load('https://example.com/test.xml');\n * const items = qtiTransformer.items();\n * const html = qtiTransformer.html();\n * const xml = qtiTransformer.xml();\n */\n\nimport { itemsFromTest, loadXML, parseXML, setLocation, toHTML } from './qti-transformers';\n\nexport type transformTestApi = {\n load: (uri: string, signal?: AbortSignal) => Promise<transformTestApi>;\n parse: (xmlString: string) => transformTestApi;\n path: (location: string) => transformTestApi;\n fn: (fn: (xmlFragment: XMLDocument) => void) => transformTestApi;\n items: () => { identifier: string; href: string; category: string }[];\n html: () => string;\n xml: () => string;\n htmlDoc: () => DocumentFragment;\n xmlDoc: () => XMLDocument;\n};\n\nexport const qtiTransformTest = (): transformTestApi => {\n let xmlFragment: XMLDocument;\n\n const api: transformTestApi = {\n async load(uri, signal) {\n return new Promise<transformTestApi>((resolve, _) => {\n loadXML(uri, signal).then(xml => {\n xmlFragment = xml;\n\n api.path(uri.substring(0, uri.lastIndexOf('/')));\n return resolve(api);\n });\n });\n },\n parse(xmlString: string) {\n xmlFragment = parseXML(xmlString);\n return api;\n },\n path: (location: string): typeof api => {\n setLocation(xmlFragment, location);\n return api;\n },\n fn(fn: (xmlFragment: XMLDocument) => void) {\n fn(xmlFragment);\n return api;\n },\n items() {\n return itemsFromTest(xmlFragment);\n },\n html() {\n return new XMLSerializer().serializeToString(toHTML(xmlFragment));\n },\n xml(): string {\n return new XMLSerializer().serializeToString(xmlFragment);\n },\n htmlDoc() {\n return toHTML(xmlFragment);\n },\n xmlDoc(): XMLDocument {\n return xmlFragment;\n }\n };\n return api;\n};\n"],"mappings":"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","names":["xml","fallbackPath","path","originalOrder","xml","xml"]}
@@ -9,7 +9,7 @@ import {
9
9
  } from "./chunk-ELDMXTUQ.js";
10
10
  import {
11
11
  qtiTransformItem
12
- } from "./chunk-WFUXZ4UT.js";
12
+ } from "./chunk-LJ4KAG72.js";
13
13
  import {
14
14
  QtiConditionExpression
15
15
  } from "./chunk-SV4K25ZI.js";
@@ -188,7 +188,6 @@ var QtiAssessmentItem = class extends LitElement {
188
188
  this._attachEventListeners();
189
189
  super.connectedCallback();
190
190
  this.updateComplete.then(() => {
191
- this._processTemplates();
192
191
  this.dispatchEvent(
193
192
  new CustomEvent("qti-assessment-item-connected", {
194
193
  bubbles: true,
@@ -196,6 +195,7 @@ var QtiAssessmentItem = class extends LitElement {
196
195
  detail: this
197
196
  })
198
197
  );
198
+ this._processTemplates();
199
199
  });
200
200
  }
201
201
  disconnectedCallback() {
@@ -426,6 +426,16 @@ QtiAssessmentItem = __decorateClass([
426
426
  // src/lib/qti-components/qti-assessment-stimulus-ref/qti-assessment-stimulus-ref.ts
427
427
  import { LitElement as LitElement2 } from "lit";
428
428
  import { customElement as customElement2, property as property2 } from "lit/decorators.js";
429
+ var QtiAssessmentStimulusRefConnectedEvent = class _QtiAssessmentStimulusRefConnectedEvent extends Event {
430
+ constructor(element, item) {
431
+ super(_QtiAssessmentStimulusRefConnectedEvent.eventName, { bubbles: true, composed: true, cancelable: true });
432
+ this.element = element;
433
+ this.item = item;
434
+ }
435
+ static {
436
+ this.eventName = "qti-assessment-stimulus-ref-connected";
437
+ }
438
+ };
429
439
  var QtiAssessmentStimulusRef = class extends LitElement2 {
430
440
  constructor() {
431
441
  super(...arguments);
@@ -434,24 +444,18 @@ var QtiAssessmentStimulusRef = class extends LitElement2 {
434
444
  }
435
445
  /**
436
446
  * Lifecycle method called when the element is connected to the DOM.
437
- * Loads and appends the stimulus if the 'qti-assessment-stimulus-ref-connected' event is not prevented.
447
+ * First checks if there's a data-stimulus-idref element. If found, loads the stimulus directly.
448
+ * If not found, delegates to the delivery platform via an event.
438
449
  */
439
450
  async connectedCallback() {
440
451
  super.connectedCallback();
441
- const event = new Event("qti-assessment-stimulus-ref-connected", {
442
- cancelable: true,
443
- bubbles: true,
444
- composed: true
445
- });
446
- const isNotPrevented = this.dispatchEvent(event);
447
- if (isNotPrevented) {
448
- const item = this.closest("qti-assessment-item");
449
- const stimulusRef = item.querySelector(`[data-stimulus-idref=${this.identifier}]`);
450
- if (stimulusRef) {
451
- await this.updateStimulusRef(stimulusRef);
452
- } else {
453
- console.warn(`Stimulus with data-stimulus-idref ${this.identifier} not found`);
454
- }
452
+ await this.updateComplete;
453
+ const item = this.closest("qti-assessment-item");
454
+ const event = new QtiAssessmentStimulusRefConnectedEvent(this, item);
455
+ this.dispatchEvent(event);
456
+ const stimulusRef = item?.querySelector(`[data-stimulus-idref="${this.identifier}"]`);
457
+ if (!event.defaultPrevented && stimulusRef) {
458
+ await this.updateStimulusRef(stimulusRef);
455
459
  }
456
460
  }
457
461
  /**
@@ -459,7 +463,7 @@ var QtiAssessmentStimulusRef = class extends LitElement2 {
459
463
  * @param stimulusRef - The element to which the stimulus will be appended.
460
464
  */
461
465
  async updateStimulusRef(stimulusRef) {
462
- const stimulus = await qtiTransformItem().load(this.href).promise.then((api) => api.htmlDoc());
466
+ const stimulus = await qtiTransformItem().load(this.href).then((api) => api.htmlDoc());
463
467
  if (stimulus) {
464
468
  const elements = stimulus.querySelectorAll("qti-stimulus-body, qti-stylesheet");
465
469
  stimulusRef.innerHTML = "";
@@ -8726,6 +8730,7 @@ QtiResponseDeclaration = __decorateClass([
8726
8730
 
8727
8731
  export {
8728
8732
  QtiAssessmentItem,
8733
+ QtiAssessmentStimulusRefConnectedEvent,
8729
8734
  QtiAssessmentStimulusRef,
8730
8735
  QtiCompanionMaterialsInfo,
8731
8736
  QtiCustomOperator,
@@ -8822,4 +8827,4 @@ export {
8822
8827
  QtiOutcomeDeclaration,
8823
8828
  QtiResponseDeclaration
8824
8829
  };
8825
- //# sourceMappingURL=chunk-TFNRSY74.js.map
8830
+ //# sourceMappingURL=chunk-SJGUMIKK.js.map