@qti-components/portable-custom-interaction 1.3.0 → 1.3.1
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.
|
@@ -90,8 +90,9 @@ export class QtiPortableCustomInteraction extends Interaction {
|
|
|
90
90
|
break;
|
|
91
91
|
case 'resize':
|
|
92
92
|
if (typeof data.height === 'number' && this.iframe) {
|
|
93
|
+
// Only the height follows the content. The width stays 100% of the host, so the PCI keeps
|
|
94
|
+
// following the item's layout when it gets narrower (a column that stacks, a resized window).
|
|
93
95
|
this.iframe.style.height = `${data.height}px`;
|
|
94
|
-
this.iframe.style.width = `${data.width}px`;
|
|
95
96
|
}
|
|
96
97
|
break;
|
|
97
98
|
case 'console':
|
|
@@ -809,6 +810,8 @@ export class QtiPortableCustomInteraction extends Interaction {
|
|
|
809
810
|
}
|
|
810
811
|
#pci-container {
|
|
811
812
|
width: 100%;
|
|
813
|
+
/* Keeps the first and last child's margins inside, so scrollHeight is the full height. */
|
|
814
|
+
display: flow-root;
|
|
812
815
|
}
|
|
813
816
|
qti-interaction-markup {
|
|
814
817
|
display: block;
|
|
@@ -1562,7 +1565,8 @@ export class QtiPortableCustomInteraction extends Interaction {
|
|
|
1562
1565
|
let previousHeight = 0;
|
|
1563
1566
|
const notifyResize = () => {
|
|
1564
1567
|
const container = document.getElementById('pci-container');
|
|
1565
|
-
|
|
1568
|
+
// The content's own height (subpixel, rounded up) or what overflows it, e.g. an open popup.
|
|
1569
|
+
const newHeight = Math.max(Math.ceil(container.getBoundingClientRect().height), container.scrollHeight);
|
|
1566
1570
|
if (newHeight !== previousHeight) {
|
|
1567
1571
|
previousHeight = newHeight;
|
|
1568
1572
|
clearTimeout(resizeTimeout);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"qti-portable-custom-interaction.js","sourceRoot":"","sources":["../src/qti-portable-custom-interaction.ts"],"names":[],"mappings":"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","sourcesContent":["import { css, html } from 'lit';\nimport { property, state } from 'lit/decorators.js';\nimport { consume } from '@lit/context';\n\nimport {\n Interaction,\n isRecordValue,\n itemContext,\n qtiContext,\n readRecordFieldValues,\n removeDoubleSlashes,\n responseAttributeConverter\n} from '@qti-components/base';\nimport nativeCss from '@qti-components/theme/native-css';\n\nimport styles from './qti-portable-custom-interaction.styles';\nimport {\n coerceBaseValue,\n recordFromQtiVariableJSON,\n recordResponseToQtiVariableJSON,\n recordToQtiVariableJSON\n} from './record-response';\nimport requireJsSource from './vendor/require-js';\n\nimport type { CSSResultGroup } from 'lit';\nimport type { BaseType, Cardinality, ItemContext, QtiContext, RecordValue } from '@qti-components/base';\nimport type { PciInteractionStatus, PciResponseDeclaration, QtiVariableJSON, ResponseVariableType } from './interface';\n\n/** Text for an inline `<script>`: a `</script` inside it would end the element early. */\nexport const inlineScriptText = (text: string) => text.replace(/<\\/(script)/gi, '<\\\\/$1');\n\n/** Text for an inline `<style>`: a `</style` inside it would end the element early. */\nexport const inlineStyleText = (text: string) => text.replace(/<\\/(style)/gi, '<\\\\/$1');\n\n/** Statuses in which the item is showing the correct response, so a PCI may legitimately see it. */\nconst STATUSES_SHOWING_CORRECT_RESPONSE: PciInteractionStatus[] = ['solution', 'review'];\n\n/** A response value as this interaction holds it: a record response is its field map. */\ntype PciResponseValue = string | string[] | RecordValue;\n\n/**\n * Whether a response variable actually declares a correct response.\n *\n * Non-single cardinality yields `[]` for an empty `<qti-correct-response>`, which is \"no correct\n * response\" and must not be reported as one. A record's correct response is a field map.\n */\nfunction hasCorrectResponseValue(value: PciResponseValue | null | undefined): boolean {\n if (value === null || value === undefined) return false;\n if (Array.isArray(value)) return value.length > 0;\n if (isRecordValue(value)) return Object.keys(value).length > 0;\n return value !== '';\n}\n\nexport class QtiPortableCustomInteraction extends Interaction {\n #value: PciResponseValue;\n\n protected _iframeLoaded = false;\n protected _interactionReady = false;\n protected _pendingMessages: Array<{ method: string; params: any }> = [];\n protected iframe: HTMLIFrameElement;\n protected _iframeMessageOrigin: string | null = null;\n\n // This implementation always renders inside an iframe.\n static override styles: CSSResultGroup = [\n styles,\n css`\n :host {\n display: block;\n width: 100%;\n min-height: 50px;\n }\n `\n ];\n\n @property({ type: String, attribute: 'module' })\n module: string;\n\n @property({ type: String, attribute: 'custom-interaction-type-identifier' })\n customInteractionTypeIdentifier: string;\n\n @property({ type: String, attribute: 'data-require-paths' })\n requirePathsJson: string = '';\n\n @property({ type: String, attribute: 'data-require-shim' })\n requireShimJson: string = '';\n\n /** A RequireJS to load in the iframe instead of the inlined copy (src/vendor/require-js.ts). */\n @property({ type: String, attribute: 'data-require-js-url' })\n requireJsUrl: string = '';\n\n @property({ type: String, attribute: 'data-base-url' })\n baseUrl: string = '';\n\n @property({ type: Boolean, attribute: 'data-use-default-paths' })\n useDefaultPaths = false;\n\n /**\n * Item lifecycle status handed to the PCI in its `getInstance` configuration.\n * A delivery engine sets `solution` to let a PCI render the correct response.\n */\n @property({ type: String, attribute: 'data-status' })\n status: PciInteractionStatus = 'interacting';\n\n #responseDeclaration: PciResponseDeclaration | null = null;\n\n /**\n * Response declaration passed into the PCI configuration, so a PCI can render\n * the correct response itself instead of having it pushed in as a response.\n *\n * Derived from the item context, unless a host sets it explicitly - the\n * correct response viewer does, since it has no response declaration of its own.\n *\n * See https://github.com/1EdTech/qti-project-management/issues/210\n */\n set responseDeclaration(declaration: PciResponseDeclaration | null) {\n this.#responseDeclaration = declaration;\n }\n\n get responseDeclaration(): PciResponseDeclaration | null {\n if (this.#responseDeclaration) {\n return this.#responseDeclaration;\n }\n\n const variable = this.responseVariable;\n if (!variable) {\n return null;\n }\n\n const declaration: PciResponseDeclaration = {\n baseType: variable.baseType,\n cardinality: variable.cardinality\n };\n\n const correctResponse = variable.correctResponse as PciResponseValue | null | undefined;\n if (hasCorrectResponseValue(correctResponse)) {\n declaration.correctResponse = { value: correctResponse };\n }\n\n return declaration;\n }\n\n /**\n * The declaration as it goes into the PCI configuration.\n *\n * `correctResponse` is withheld unless the item is actually showing a solution. A PCI is\n * third-party code running in an iframe, and there is no reason for it to hold the answer key\n * while the candidate is still working - the use case this field exists for only applies once\n * the status says the correct response is being shown.\n *\n * The filter sits here rather than in the `responseDeclaration` getter so it also covers a\n * declaration a host set explicitly, not just the one derived from the item context.\n */\n #responseDeclarationForStatus(): PciResponseDeclaration | null {\n const declaration = this.responseDeclaration;\n if (!declaration?.correctResponse) {\n return declaration;\n }\n if (STATUSES_SHOWING_CORRECT_RESPONSE.includes(this.status)) {\n return declaration;\n }\n\n const { correctResponse: _withheld, ...rest } = declaration;\n return rest;\n }\n\n @state()\n private _errorMessage: string = null;\n\n @consume({ context: itemContext, subscribe: true })\n @state()\n protected context?: ItemContext;\n\n @consume({ context: qtiContext, subscribe: true })\n @state()\n protected qtiContext?: QtiContext;\n\n @property({ attribute: 'response', reflect: false, converter: responseAttributeConverter({ emptyAs: null }) })\n response: string | string[] | null = null;\n\n #parsedRequirePaths: Record<string, string | string[]> = null;\n #parsedRequireShim: Record<string, any> = null;\n #pciValidity: boolean | null = null;\n #pciCustomValidityMessage = '';\n\n /**\n * Parse the require paths JSON string into an object\n */\n #getRequirePaths(): Record<string, string | string[]> {\n if (this.#parsedRequirePaths === null && this.requirePathsJson) {\n try {\n const parsedJson = JSON.parse(this.requirePathsJson);\n if (Array.isArray(parsedJson) || !parsedJson || typeof parsedJson !== 'object') {\n throw new Error('Require paths must be a JSON object.');\n }\n this.#parsedRequirePaths = parsedJson;\n } catch (e) {\n console.error('Error parsing require paths JSON:', e);\n this._errorMessage = `Error parsing require paths JSON: ${e.message}`;\n this.#parsedRequirePaths = {};\n }\n }\n return this.#parsedRequirePaths || {};\n }\n\n /**\n * Parse the require shim JSON string into an object\n */\n #getRequireShim(): Record<string, any> {\n if (this.#parsedRequireShim === null && this.requireShimJson) {\n try {\n this.#parsedRequireShim = JSON.parse(this.requireShimJson);\n } catch (e) {\n console.error('Error parsing require shim JSON:', e);\n this._errorMessage = `Error parsing require shim JSON: ${e.message}`;\n this.#parsedRequireShim = {};\n }\n }\n return this.#parsedRequireShim || {};\n }\n\n /**\n * Get the final require paths by combining defaults with user-provided paths\n */\n #getFinalRequirePaths(): Record<string, string | string[]> {\n // Return only user-provided paths to keep PCI completely self-contained\n return this.#getRequirePaths();\n }\n\n /**\n * Get the final require shim\n */\n #getFinalRequireShim(): Record<string, any> {\n return this.#getRequireShim();\n }\n\n /**\n * Converts QtiVariableJSON to a string, a string array, or for a record its field map\n */\n #convertQtiVariableJSON(input: QtiVariableJSON): PciResponseValue | null {\n if (input && Array.isArray(input.record)) {\n const record = recordFromQtiVariableJSON(input.record);\n return Object.keys(record).length ? record : null;\n }\n for (const topLevelKey in input) {\n // eslint-disable-next-line no-prototype-builtins\n if (input.hasOwnProperty(topLevelKey)) {\n const nestedObject = input[topLevelKey as 'list' | 'base'];\n if (nestedObject) {\n for (const nestedKey in nestedObject) {\n // eslint-disable-next-line no-prototype-builtins\n if (nestedObject.hasOwnProperty(nestedKey)) {\n const value = nestedObject[nestedKey as keyof typeof nestedObject];\n if (Array.isArray(value)) {\n return value.map(String); // Convert each element in the array to string\n } else if (value !== undefined && value !== null) {\n return String(value); // Convert the single value to string\n }\n }\n }\n }\n }\n }\n return null;\n }\n\n /**\n * Get direct child elements by tag name\n */\n private getDirectChildrenByTag(tagName: string): Element[] {\n const needle = tagName.toLowerCase();\n return Array.from(this.children).filter(child => child.tagName.toLowerCase() === needle);\n }\n\n /**\n * Normalize an input into a list form\n */\n private normalizeListValue(value: unknown): unknown[] {\n if (value === null || value === undefined) return [];\n return Array.isArray(value) ? value : [value];\n }\n\n /**\n * Convert a variable value to QtiVariableJSON\n */\n private variableToQtiVariableJSON(value: unknown, cardinality: Cardinality, baseType: BaseType): QtiVariableJSON {\n if (cardinality === 'record' || baseType === 'record') {\n return recordToQtiVariableJSON(value);\n }\n\n if (cardinality !== 'single') {\n const listValues = this.normalizeListValue(value).map(v => coerceBaseValue(v, baseType));\n return { list: { [baseType]: listValues } };\n }\n\n return { base: { [baseType]: coerceBaseValue(value, baseType) } };\n }\n\n /**\n * Extract default QTI_CONTEXT values from qti-context-declaration elements\n */\n private getQtiContextDefaultsFromItem(): Record<string, unknown> {\n const itemElement = this.closest('qti-assessment-item');\n if (!itemElement) return {};\n\n const defaults: Record<string, unknown> = {};\n const contextDeclarations = itemElement.querySelectorAll('qti-context-declaration[identifier=\"QTI_CONTEXT\"]');\n\n contextDeclarations.forEach(declaration => {\n const defaultValueElement = declaration.querySelector('qti-default-value');\n if (!defaultValueElement) return;\n\n const { value, baseTypes } = readRecordFieldValues(defaultValueElement.querySelectorAll('qti-value'));\n for (const [fieldIdentifier, textContent] of Object.entries(value)) {\n defaults[fieldIdentifier] = coerceBaseValue(textContent, baseTypes[fieldIdentifier] ?? 'string');\n }\n });\n\n return defaults;\n }\n\n /**\n * Build a QTI_CONTEXT record for PCI consumption\n */\n private getQtiContextRecord(): QtiVariableJSON | null {\n const defaults = this.getQtiContextDefaultsFromItem();\n const runtime = this.qtiContext?.QTI_CONTEXT || {};\n const merged: Record<string, unknown> = { ...defaults, ...runtime };\n if (!Object.keys(merged).length) return null;\n\n const normalized = {\n candidateIdentifier: merged.candidateIdentifier ?? '',\n testIdentifier: merged.testIdentifier ?? '',\n environmentIdentifier: merged.environmentIdentifier ?? '',\n ...merged\n };\n\n return recordToQtiVariableJSON(normalized);\n }\n\n /**\n * Collect template variables referenced by qti-template-variable children\n */\n private getTemplateVariables(): Record<string, QtiVariableJSON> {\n const templateVariables: Record<string, QtiVariableJSON> = {};\n const templateVariableElements = this.getDirectChildrenByTag('qti-template-variable');\n if (!templateVariableElements.length) return templateVariables;\n\n templateVariableElements.forEach(el => {\n const identifier = el.getAttribute('template-identifier') || el.getAttribute('identifier') || '';\n if (!identifier) return;\n\n const variable = this.context?.variables?.find(v => v.identifier === identifier);\n if (!variable) return;\n\n const cardinality = (variable.cardinality || 'single') as Cardinality;\n const baseType = (variable.baseType || 'string') as BaseType;\n templateVariables[identifier] = this.variableToQtiVariableJSON(variable.value, cardinality, baseType);\n });\n\n return templateVariables;\n }\n\n /**\n * Collect context variables referenced by qti-context-variable children\n */\n private getContextVariables(): Record<string, QtiVariableJSON> {\n const contextVariables: Record<string, QtiVariableJSON> = {};\n const contextVariableElements = this.getDirectChildrenByTag('qti-context-variable');\n if (!contextVariableElements.length) return contextVariables;\n\n contextVariableElements.forEach(el => {\n const identifier = el.getAttribute('identifier') || '';\n if (!identifier) return;\n\n if (identifier === 'QTI_CONTEXT') {\n const record = this.getQtiContextRecord();\n if (record) contextVariables[identifier] = record;\n return;\n }\n\n const variable = this.context?.variables?.find(v => v.identifier === identifier);\n if (!variable) return;\n\n const cardinality = (variable.cardinality || 'single') as Cardinality;\n const baseType = (variable.baseType || 'string') as BaseType;\n contextVariables[identifier] = this.variableToQtiVariableJSON(variable.value, cardinality, baseType);\n });\n\n return contextVariables;\n }\n\n /**\n * Adds hyphenated versions of camelCase keys to properties object\n */\n #addHyphenatedKeys(properties: Record<string, any>): Record<string, any> {\n const updatedProperties = { ...properties };\n\n for (const key in properties) {\n if (Object.prototype.hasOwnProperty.call(properties, key)) {\n const hyphenatedKey = key.replace(/[A-Z]/g, char => `-${char.toLowerCase()}`);\n updatedProperties[hyphenatedKey] = properties[key];\n }\n }\n\n return updatedProperties;\n }\n\n #toNestedProperties(properties: Record<string, any>): Record<string, any> {\n const nestedProperties = { ...properties };\n\n const setNestedValue = (root: Record<string, any>, path: string[], value: any): void => {\n let cursor = root;\n\n for (let i = 0; i < path.length; i += 1) {\n const segment = path[i];\n const isLast = i === path.length - 1;\n\n if (isLast) {\n cursor[segment] = value;\n return;\n }\n\n if (!cursor[segment] || typeof cursor[segment] !== 'object' || Array.isArray(cursor[segment])) {\n cursor[segment] = {};\n }\n\n cursor = cursor[segment];\n }\n };\n\n for (const [key, value] of Object.entries(properties)) {\n if (!key.includes('__')) continue;\n const path = key.split('__').filter(Boolean);\n if (path.length < 2) continue;\n setNestedValue(nestedProperties, path, value);\n }\n\n return nestedProperties;\n }\n\n /**\n * Converts response variables to QtiVariableJSON\n */\n protected responseVariablesToQtiVariableJSON(\n input: PciResponseValue,\n cardinality: Cardinality,\n baseType: BaseType,\n fieldBaseTypes?: Record<string, BaseType>\n ): QtiVariableJSON {\n if (cardinality === 'record') {\n // A record declaration has no base-type: the fields carry their own, declared or inferred.\n return recordResponseToQtiVariableJSON(input, fieldBaseTypes);\n }\n if (cardinality !== 'single') {\n const list = { list: {} };\n list.list[baseType] = input;\n return list;\n } else {\n const base = { base: {} };\n base.base[baseType] = input;\n return base;\n }\n }\n\n #hasNonEmptyResponse(): boolean {\n if (this.response === null || this.response === undefined) return false;\n if (isRecordValue(this.response)) {\n return Object.values(this.response).some(v => v !== '' && v !== null && v !== undefined);\n }\n if (Array.isArray(this.response)) {\n if (this.response.length === 0) return false;\n return this.response.some(v => v !== '' && v !== null && v !== undefined);\n }\n return this.response !== '';\n }\n\n #setInteractionValidity(isValid: boolean, customMessage?: string): void {\n const fallbackMessage = this.dataset.invalidresponsemessage || 'Invalid response.';\n const message = isValid ? '' : customMessage && customMessage.trim().length > 0 ? customMessage : fallbackMessage;\n this._internals.setValidity(isValid ? {} : { customError: true }, message);\n }\n\n validate(): boolean {\n const isValid = typeof this.#pciValidity === 'boolean' ? this.#pciValidity : this.#hasNonEmptyResponse();\n this.#setInteractionValidity(isValid, this.#pciCustomValidityMessage);\n return isValid;\n }\n\n override set value(v: string | null) {\n if (v === null) {\n this.#value = [];\n } else {\n this.#value = Array.isArray(v) ? v : v.split(',');\n }\n // PCI handles response setting via boundTo property during initialization\n // No need to call setResponse directly\n }\n\n override get value(): string | null {\n if (this.#value === null || this.#value === undefined) return null;\n if (isRecordValue(this.#value)) return JSON.stringify(this.#value);\n return Array.isArray(this.#value) ? this.#value.join(',') : String(this.#value);\n }\n\n set boundTo(newValue: Record<string, ResponseVariableType>) {\n if (!newValue || !newValue[this.responseIdentifier]) {\n return;\n }\n\n const value = this.#convertQtiVariableJSON(newValue[this.responseIdentifier]);\n this.#value = value;\n\n // No direct call to setResponse - PCI will handle this during initialization\n // through the boundTo property in the config\n\n this.saveResponse(value as string | string[]);\n }\n\n get boundTo(): Record<string, QtiVariableJSON> {\n const responseVariable: Record<string, QtiVariableJSON> = {};\n const variable = this.context?.variables?.find(v => v.identifier === this.responseIdentifier);\n if (variable) {\n const cardinality = variable.cardinality || 'single';\n const baseType = variable.baseType || 'string';\n const value = (variable.value || null) as PciResponseValue;\n const fieldBaseTypes = (variable as { fieldBaseTypes?: Record<string, BaseType> }).fieldBaseTypes;\n const responseVal = this.responseVariablesToQtiVariableJSON(value, cardinality, baseType, fieldBaseTypes);\n responseVariable[this.responseIdentifier] = responseVal;\n }\n\n return responseVariable;\n }\n\n /**\n * Unescape HTML entities in a string\n */\n #unescapeHtml(str: string): string {\n if (!str) return str;\n\n return str\n .replace(/&/g, '&')\n .replace(/</g, '<')\n .replace(/>/g, '>')\n .replace(/"/g, '\"')\n .replace(/'/g, \"'\")\n .replace(///g, '/')\n .replace(/`/g, '`')\n .replace(/=/g, '=');\n }\n\n /**\n * Unescape HTML entities in all values of an object\n */\n #unescapeDataAttributes(obj: Record<string, any>): Record<string, any> {\n const unescaped: Record<string, any> = {};\n\n for (const [key, value] of Object.entries(obj)) {\n if (typeof value === 'string') {\n unescaped[key] = this.#unescapeHtml(value);\n } else {\n unescaped[key] = value;\n }\n }\n\n return unescaped;\n }\n\n override disconnectedCallback(): void {\n super.disconnectedCallback();\n window.removeEventListener('message', this.handleIframeMessage);\n }\n\n /**\n * IFRAME MODE: Send message to iframe\n */\n protected sendMessageToIframe(method: string, params: any) {\n const targetWindow = this.iframe?.contentWindow;\n if (!this._iframeLoaded || !targetWindow) {\n this._pendingMessages.push({ method, params });\n return;\n }\n targetWindow.postMessage(\n {\n source: 'qti-portable-custom-interaction',\n responseIdentifier: this.responseIdentifier,\n method,\n params\n },\n '*'\n );\n }\n\n /**\n * IFRAME MODE: Process pending messages\n */\n #processPendingMessages() {\n if (this._pendingMessages.length) {\n this._pendingMessages.forEach(message => {\n this.sendMessageToIframe(message.method, message.params);\n });\n this._pendingMessages = [];\n }\n }\n\n /**\n * IFRAME MODE: Handle iframe messages\n */\n protected handleIframeMessage = (event: MessageEvent) => {\n const { data } = event;\n // Ensure the message is from our iframe\n if (!data || data.source !== 'qti-pci-iframe') {\n return;\n }\n if (!this.iframe?.contentWindow || event.source !== this.iframe.contentWindow) {\n return;\n }\n if (data.responseIdentifier && data.responseIdentifier !== this.responseIdentifier) {\n return;\n }\n if (this._iframeMessageOrigin === null) {\n this._iframeMessageOrigin = event.origin;\n } else if (event.origin !== this._iframeMessageOrigin) {\n return;\n }\n switch (data.method) {\n case 'iframeReady':\n this._interactionReady = true;\n this.#initializeInteraction();\n this.#processPendingMessages();\n this.dispatchEvent(\n new CustomEvent('qti-portable-custom-interaction-loaded', {\n bubbles: true\n })\n );\n break;\n\n case 'resize':\n if (typeof data.height === 'number' && this.iframe) {\n this.iframe.style.height = `${data.height}px`;\n this.iframe.style.width = `${data.width}px`;\n }\n break;\n case 'console':\n this.dispatchEvent(\n new CustomEvent('qti-pci-console', {\n detail: {\n level: data.level,\n args: data.args\n },\n bubbles: true\n })\n );\n break;\n\n case 'interactionChanged': {\n const raw = data?.params?.value;\n const converted = raw && typeof raw === 'object' ? this.#convertQtiVariableJSON(raw as QtiVariableJSON) : null;\n const pciValid = typeof data?.params?.valid === 'boolean' ? (data.params.valid as boolean) : null;\n const pciCustomValidity =\n typeof data?.params?.customValidity === 'string' ? (data.params.customValidity as string) : null;\n if (pciValid !== null) {\n this.#pciValidity = pciValid;\n if (pciValid && pciCustomValidity === null) {\n this.#pciCustomValidityMessage = '';\n }\n }\n if (pciCustomValidity !== null) {\n this.#pciCustomValidityMessage = pciCustomValidity;\n }\n // PCI state \"should\" be an opaque string, but a lot of existing PCIs (including the\n // IMS conformance examples) return a structured object from getState().\n //\n // We store a string in itemContext.state, so we serialize non-string states with a\n // prefix to safely round-trip them without accidentally parsing user-provided strings.\n const stateRaw = data?.params?.state as unknown;\n let state: string | null | undefined;\n if (stateRaw === undefined) {\n state = undefined;\n } else if (stateRaw === null) {\n state = null;\n } else if (typeof stateRaw === 'string') {\n state = stateRaw;\n } else {\n try {\n state = `__qti_json__::${JSON.stringify(stateRaw)}`;\n } catch {\n state = null;\n }\n }\n\n // Treat null/undefined or unconvertible responses as \"cleared\".\n // The iframe side is responsible for not emitting an initial clear on load.\n if (converted === null) {\n const cardinality = this.responseVariable?.cardinality;\n // A record has no empty literal: a cleared record is NULL.\n const emptyResponse = cardinality === 'record' ? null : cardinality === 'single' ? '' : [];\n this.response = emptyResponse;\n this.validate();\n this.saveResponse(emptyResponse, state);\n break;\n }\n\n // A record response travels as its field map; the shared response types only say string | string[].\n const response = converted as string | string[];\n this.response = response;\n this.validate();\n this.saveResponse(response, state);\n break;\n }\n case 'error':\n this._errorMessage = data.params.message;\n console.error('Error from PCI iframe:', data.params.message);\n break;\n }\n };\n\n /**\n * IFRAME MODE: Create iframe element\n */\n protected createIframe() {\n this._interactionReady = false;\n this.iframe = document.createElement('iframe');\n this.iframe.id = `pci-iframe-${this.responseIdentifier}`;\n this.iframe.setAttribute('title', 'QTI PCI Iframe');\n this.iframe.setAttribute('aria-label', 'QTI PCI Iframe');\n this.iframe.setAttribute('aria-hidden', 'false');\n this.iframe.setAttribute('role', 'application');\n this.iframe.style.width = '100%';\n this.iframe.style.border = 'none';\n this.iframe.style.display = 'block';\n\n // Handle iframe load event\n this.iframe.onload = () => {\n this._iframeLoaded = true;\n this.#addMarkupToIframe();\n // Send initialization data to iframe\n this.#sendIframeInitData();\n };\n\n // Create a unique name for the iframe\n const iframeName = `qti-pci-${this.responseIdentifier}-${Date.now()}`;\n this.iframe.name = iframeName;\n\n // Generate iframe HTML content with all required scripts\n const iframeContent = this.generateIframeContent();\n\n // Use `srcdoc` rather than a `blob:` (or `data:`) URL. Both of those give the iframe document\n // a URL that is out of scope for any http(s) Service Worker registration, so a player that\n // serves package resources through a Service Worker (CacheStorage, virtual paths) would see\n // every request made from inside the PCI - module scripts, images, media, stylesheets, fetches -\n // bypass it and hit the network instead. An `srcdoc` frame inherits this document's URL and\n // stays controlled by the same Service Worker. It is same-origin either way, and messages are\n // posted with a `'*'` target origin, so nothing about postMessage changes.\n this.iframe.srcdoc = iframeContent;\n\n // Append iframe to component\n this.appendChild(this.iframe);\n }\n\n /**\n * IFRAME MODE: Send initialization data to iframe\n */\n #sendIframeInitData() {\n // Once iframe is loaded, send initialization data\n const properties = this.#addHyphenatedKeys(\n this.#toNestedProperties(this.#unescapeDataAttributes({ ...this.dataset }))\n );\n const storedStateRaw = this.context?.state?.[this.responseIdentifier];\n const storedState = typeof storedStateRaw === 'string' && storedStateRaw.length > 0 ? storedStateRaw : null;\n const initData = {\n module: this.module,\n customInteractionTypeIdentifier: this.customInteractionTypeIdentifier,\n baseUrl: !this.baseUrl\n ? window.location.origin\n : this.baseUrl.startsWith('http') || this.baseUrl.startsWith('blob') || this.baseUrl.startsWith('base64')\n ? this.baseUrl\n : removeDoubleSlashes(`${window.location.origin}${this.baseUrl}`),\n responseIdentifier: this.responseIdentifier,\n properties,\n contextVariables: this.getContextVariables(),\n templateVariables: this.getTemplateVariables(),\n dataAttributes: { ...this.dataset },\n interactionModules: this.#getInteractionModules(),\n boundTo: storedState ? null : this.boundTo,\n responseDeclaration: this.#responseDeclarationForStatus(),\n status: this.status,\n state: storedState\n };\n\n this.sendMessageToIframe('initialize', initData);\n }\n\n /**\n * IFRAME MODE: Get interaction modules from DOM\n */\n #getInteractionModules() {\n const modules = [];\n const interactionModules = this.querySelector('qti-interaction-modules');\n\n if (interactionModules) {\n const moduleElements = interactionModules.querySelectorAll('qti-interaction-module');\n for (const module of moduleElements) {\n modules.push({\n id: module.getAttribute('id'),\n primaryPath: module.getAttribute('primary-path'),\n fallbackPath: module.getAttribute('fallback-path')\n });\n }\n }\n\n return modules;\n }\n\n /**\n * IFRAME MODE: Add markup, stylesheets, and properties to iframe\n */\n #addMarkupToIframe() {\n // Get interaction markup if any\n const markup = this.querySelector('qti-interaction-markup');\n if (markup) {\n this.sendMessageToIframe('setMarkup', markup.innerHTML);\n }\n\n const stylesheets = Array.from(this.querySelectorAll('qti-stylesheet'));\n if (stylesheets.length) {\n const stylesheetsHtml = stylesheets.map(sheet => sheet.outerHTML).join('\\n');\n this.sendMessageToIframe('setStylesheets', stylesheetsHtml);\n }\n\n // Get properties if any\n const properties = this.querySelector('properties');\n if (properties) {\n this.sendMessageToIframe('setProperties', properties.innerHTML);\n }\n }\n\n /**\n * IFRAME MODE: Initialize the interaction\n */\n #initializeInteraction() {\n // No explicit action needed, as the PCI will initialize\n // with the boundTo property already provided\n }\n\n override connectedCallback(): void {\n super.connectedCallback();\n this.#pciValidity = null;\n this.#pciCustomValidityMessage = '';\n // Reflect any pre-existing response (e.g. restored session) for validation/completionStatus.\n // Don't clobber a value already set via the `response=\"...\"` attribute.\n const currentResponse = this.response;\n const hasResponse = Array.isArray(currentResponse) ? currentResponse.length > 0 : !!currentResponse;\n if (!hasResponse) {\n this.response = (this.responseVariable?.value as string | string[] | null) ?? null;\n }\n window.addEventListener('message', this.handleIframeMessage);\n this.createIframe();\n }\n\n /**\n * IFRAME MODE: Generate iframe HTML content\n */\n protected generateIframeContent(): string {\n const parentStyles = window.getComputedStyle(document.body);\n\n // Get the configured require paths and shim\n const requirePaths = JSON.stringify(this.#getFinalRequirePaths());\n const requireShim = JSON.stringify(this.#getFinalRequireShim());\n const iframeBaseUrl = this.dataset.baseUrl\n ? this.dataset.baseUrl.startsWith('/')\n ? `${window.location.origin}${this.dataset.baseUrl}`\n : this.dataset.baseUrl\n : '';\n // `data-base-url` names the directory the item was loaded from, so it is also the base every\n // relative URL inside the interaction should resolve against - the markup's `src`/`href`, the\n // stylesheets, and whatever the PCI module resolves itself. Anchoring `<base>` at the site\n // origin instead would send `../assets/x.png` to `/assets/x.png`. Normalise to a trailing\n // slash: without one the last segment counts as a filename and gets dropped.\n const iframeBaseHref = iframeBaseUrl\n ? iframeBaseUrl.endsWith('/')\n ? iframeBaseUrl\n : `${iframeBaseUrl}/`\n : `${window.location.origin}/`;\n const forwardConsole = this.dataset.forwardConsole === 'true';\n // Everything the iframe needs is inline: RequireJS (it loads the PCI module) and the QTI 3 shared vocabulary\n // (qti-layout-row, qti-well, …) that interaction markup may use, both from this version of qti-components. No\n // public CDN is involved. The qti-components bundle and the full item.css are not needed to run a PCI (the markup\n // is plain HTML); a host that wants them in the iframe anyway names its own copy with these attributes.\n const componentsCdnUrl = this.dataset.componentsCdnUrl;\n const componentsCssUrl = this.dataset.componentsCssUrl;\n const requireJsTag = this.requireJsUrl\n ? `<script src=\"${this.requireJsUrl}\"></script>`\n : `<script>${inlineScriptText(requireJsSource)}</script>`;\n\n // Extract just the font-related properties you want to copy\n const fontStyles = `\n font-family: ${parentStyles.getPropertyValue('font-family')};\n font-size: ${parentStyles.getPropertyValue('font-size')};\n line-height: ${parentStyles.getPropertyValue('line-height')};\n font-weight: ${parentStyles.getPropertyValue('font-weight')};\n color: ${parentStyles.getPropertyValue('color')};\n `;\n\n // The language of the interaction (the item's xml:lang, or the page's lang), so a PCI that reads\n // `lang` in its iframe shows its own texts in the item's language.\n const langHost = this.closest('[lang], [xml\\\\:lang]');\n const iframeLang =\n [langHost?.getAttribute('lang'), langHost?.getAttribute('xml:lang'), document.documentElement.lang]\n .map(l => (l ?? '').trim())\n .find(l => /^[A-Za-z]{1,8}(-[A-Za-z0-9]{1,8})*$/.test(l)) ?? 'en';\n\n return /* html */ `<!DOCTYPE html>\n <html lang=\"${iframeLang}\">\n <head>\n <meta charset=\"utf-8\" />\n <title>QTI PCI Container</title>\n <base href=\"${iframeBaseHref}\" />\n ${componentsCdnUrl ? `<script type=\"module\">import '${componentsCdnUrl}';</script>` : ''}\n <style>${inlineStyleText(nativeCss)}</style>\n <style>\n body, html {\n margin: 0;\n padding: 0;\n width: 100%;\n height: auto;\n overflow: hidden;\n /* Add the extracted font styles here */\n ${fontStyles}\n };\n .qti-customInteraction {\n width: 100%;\n height: 100%;\n }\n #pci-container {\n width: 100%;\n }\n qti-interaction-markup {\n display: block;\n width: 100%;\n min-height: 50px;\n }\n </style>\n ${componentsCssUrl ? `<link href=\"${componentsCssUrl}\" rel=\"stylesheet\" />` : ''}\n ${requireJsTag}\n <script>\n const forwardConsole = ${forwardConsole ? 'true' : 'false'};\n if (forwardConsole) {\n const originalLog = console.log.bind(console);\n const originalError = console.error.bind(console);\n const stringifyArgs = args =>\n args.map(arg => {\n if (typeof arg === 'string') return arg;\n try {\n return JSON.stringify(arg);\n } catch (e) {\n return String(arg);\n }\n });\n console.log = (...args) => {\n originalLog(...args);\n window.parent.postMessage(\n {\n source: 'qti-pci-iframe',\n responseIdentifier: (window.PCIManager && window.PCIManager.responseIdentifier) || null,\n method: 'console',\n level: 'log',\n args: stringifyArgs(args)\n },\n '*'\n );\n };\n console.error = (...args) => {\n originalError(...args);\n window.parent.postMessage(\n {\n source: 'qti-pci-iframe',\n responseIdentifier: (window.PCIManager && window.PCIManager.responseIdentifier) || null,\n method: 'console',\n level: 'error',\n args: stringifyArgs(args)\n },\n '*'\n );\n };\n }\n // Define standard paths and shims\n window.requirePaths = ${requirePaths};\n\n window.requireShim = ${requireShim};\n\n // Single initial RequireJS configuration with error handling\n window.requirejs.config({\n catchError: true,\n waitSeconds: 30,\n paths: window.requirePaths,\n baseUrl: '${iframeBaseUrl}',\n shim: window.requireShim,\n onNodeCreated: function (node, config, moduleName, url) {\n // Add error handler to script node\n node.addEventListener('error', function (evt) {\n console.error('Script load error for module:', moduleName, 'URL:', url, 'Event:', evt);\n });\n },\n onError: function (err) {\n console.error('RequireJS error:', {\n type: err.requireType,\n modules: err.requireModules,\n error: err\n });\n\n if (err.requireType === 'scripterror') {\n console.error('Script error usually indicates a network or CORS issue with:', err.requireModules);\n }\n\n // Notify parent window about the error\n window.parent.postMessage(\n {\n source: 'qti-pci-iframe',\n responseIdentifier: (window.PCIManager && window.PCIManager.responseIdentifier) || null,\n method: 'error',\n params: {\n message: 'RequireJS ' + err.requireType + ' error for modules: ' + err.requireModules,\n details: {\n type: err.requireType,\n modules: err.requireModules,\n error: err.toString()\n }\n }\n },\n '*'\n );\n }\n });\n\n // PCI Manager for iframe implementation\n window.PCIManager = {\n pciInstance: null,\n pciConfig: null,\n container: null,\n markupEl: null,\n propertiesEl: null,\n customInteractionTypeIdentifier: null,\n responseIdentifier: null,\n pendingBoundTo: null,\n pendingMarkup: null,\n pendingProperties: null,\n pendingState: null,\n pendingStylesheets: null,\n stylesheetKeys: {},\n interactionChangedViaEvent: false,\n eventBridgeAttached: false,\n lastResponseStr: null,\n hadResponse: false,\n\n initialize: function (config) {\n this.customInteractionTypeIdentifier = config.customInteractionTypeIdentifier;\n this.responseIdentifier = config.responseIdentifier;\n this.container = document.getElementById('pci-container');\n this.container.classList.add('qti-customInteraction');\n\n function qtiVariableHasValue(qtiVar) {\n if (!qtiVar) return false;\n if (qtiVar.base) {\n for (const k in qtiVar.base) {\n if (!Object.prototype.hasOwnProperty.call(qtiVar.base, k)) continue;\n const v = qtiVar.base[k];\n if (v !== null && v !== undefined && v !== '') return true;\n }\n }\n if (qtiVar.list) {\n for (const k in qtiVar.list) {\n if (!Object.prototype.hasOwnProperty.call(qtiVar.list, k)) continue;\n const v = qtiVar.list[k];\n if (Array.isArray(v) && v.some(x => x !== null && x !== undefined && x !== '')) return true;\n }\n }\n if (Array.isArray(qtiVar.record) && qtiVar.record.length > 0) return true;\n return false;\n }\n\n const initialBoundTo = config.boundTo && config.boundTo[this.responseIdentifier];\n this.hadResponse = qtiVariableHasValue(initialBoundTo);\n this.lastResponseStr = this.hadResponse ? JSON.stringify(initialBoundTo) : null;\n // Ensure expected DOM structure exists (markup + properties)\n this.markupEl = this.container.querySelector('qti-interaction-markup');\n if (!this.markupEl) {\n this.markupEl = document.createElement('qti-interaction-markup');\n this.container.appendChild(this.markupEl);\n }\n this.markupEl.classList.add('qti-customInteraction');\n this.propertiesEl = this.container.querySelector('properties');\n if (!this.propertiesEl) {\n this.propertiesEl = document.createElement('properties');\n this.propertiesEl.style.display = 'none';\n this.container.appendChild(this.propertiesEl);\n } else {\n this.propertiesEl.style.display = 'none';\n }\n\n // Apply any markup/properties that arrived before initialization\n if (this.pendingMarkup !== null) {\n this.setMarkup(this.pendingMarkup);\n this.pendingMarkup = null;\n }\n if (this.pendingProperties !== null) {\n this.setProperties(this.pendingProperties);\n this.pendingProperties = null;\n }\n if (this.pendingStylesheets !== null) {\n this.setStylesheets(this.pendingStylesheets);\n this.pendingStylesheets = null;\n }\n\n // Bridge qti-interaction-changed events (preferred over polling)\n if (!this.eventBridgeAttached) {\n this.eventBridgeAttached = true;\n const self = this;\n this.container.addEventListener(\n 'qti-interaction-changed',\n function (evt) {\n try {\n self.interactionChangedViaEvent = true;\n const value = evt && evt.detail ? evt.detail.value : undefined;\n if (value !== undefined) {\n const validFromEvent =\n evt && evt.detail && typeof evt.detail.valid === 'boolean' ? evt.detail.valid : undefined;\n let valid = validFromEvent;\n if (valid === undefined && self.pciInstance && typeof self.pciInstance.checkValidity === 'function') {\n try {\n valid = self.pciInstance.checkValidity();\n } catch (e) {\n // Keep undefined on PCI validity read errors.\n }\n }\n const customValidityFromEvent =\n evt && evt.detail && typeof evt.detail.customValidity === 'string'\n ? evt.detail.customValidity\n : undefined;\n let customValidity = customValidityFromEvent;\n if (\n customValidity === undefined &&\n self.pciInstance &&\n typeof self.pciInstance.getCustomValidity === 'function'\n ) {\n try {\n customValidity = self.pciInstance.getCustomValidity();\n } catch (e) {\n // Keep undefined on PCI custom validity read errors.\n }\n }\n const state =\n self.pciInstance && typeof self.pciInstance.getState === 'function'\n ? self.pciInstance.getState()\n : null;\n self.notifyInteractionChanged(value, state, valid, customValidity);\n }\n } catch (e) {\n // ignore bridge errors, polling fallback may still work\n }\n },\n true\n );\n }\n\n function getResolvablePath(path, basePath) {\n if (Array.isArray(path)) {\n return path.map(p => getResolvablePathString(p, basePath));\n } else {\n return getResolvablePathString(path, basePath);\n }\n }\n\n function removeDoubleSlashes(str) {\n return str\n .replace(/([^:\\\\/])\\\\/\\\\/+/g, '$1/')\n .replace(/\\\\/\\\\//g, '/')\n .replace('http:/', 'http://')\n .replace('https:/', 'https://');\n }\n\n function ensureDirectoryBasePath(basePath) {\n if (!basePath) return basePath;\n if (basePath.endsWith('/')) return basePath;\n return basePath + '/';\n }\n\n\n\n function combineRequireResolvePaths(path1, path2, baseUrl) {\n path1 = getResolvablePath(path1, baseUrl);\n const path1Array = Array.isArray(path1) ? path1 : [path1];\n if (!path2) {\n return path1Array;\n }\n path2 = getResolvablePath(path2, baseUrl);\n const path2Array = Array.isArray(path2) ? path2 : [path2];\n return path1Array.concat(path2Array).filter((value, index, self) => self.indexOf(value) === index);\n }\n\n // Update paths with modules from the config\n if (config.interactionModules && config.interactionModules.length > 0) {\n config.interactionModules.forEach(module => {\n if (module.id && module.primaryPath) {\n const currentPath = window.requirePaths[module.id] || [];\n const currentPaths = Array.isArray(currentPath) ? currentPath : [currentPath];\n const newPath = combineRequireResolvePaths(\n module.primaryPath,\n module.fallbackPath,\n config.baseUrl\n );\n window.requirePaths[module.id] = newPath.concat(currentPaths)\n .filter((value, index, self) => self.indexOf(value) === index);\n }\n });\n }\n\n // The ONLY other requirejs.config call - with the context for this specific PCI\n window.requirejs.config({\n context: this.customInteractionTypeIdentifier,\n paths: window.requirePaths,\n shim: window.requireShim\n });\n\n // Define qtiCustomInteractionContext for the PCI\n define('qtiCustomInteractionContext', () => {\n return {\n register: pciInstance => {\n this.pciInstance = pciInstance;\n // Configure PCI instance\n const pciConfig = {\n properties: config.properties || {},\n contextVariables: config.contextVariables || {},\n templateVariables: config.templateVariables || {},\n onready: pciInstance => {\n this.pciInstance = pciInstance;\n // Apply any pending updates that arrived before onready\n if (this.pendingBoundTo) {\n this.applyBoundTo(this.pendingBoundTo);\n this.pendingBoundTo = null;\n }\n if (this.pendingState && typeof this.pciInstance.setState === 'function') {\n this.pciInstance.setState(this.pendingState);\n this.pendingState = null;\n }\n this.notifyReady();\n },\n ondone: (pciInstance, response, state, status) => {\n const valid =\n this.pciInstance && typeof this.pciInstance.checkValidity === 'function'\n ? this.pciInstance.checkValidity()\n : undefined;\n const customValidity =\n this.pciInstance && typeof this.pciInstance.getCustomValidity === 'function'\n ? this.pciInstance.getCustomValidity()\n : undefined;\n this.notifyInteractionChanged(\n response,\n typeof state === 'string' ? state : null,\n valid,\n customValidity\n );\n },\n responseIdentifier: config.responseIdentifier,\n boundTo: config.boundTo,\n responseDeclaration: config.responseDeclaration || undefined,\n status: config.status || 'interacting'\n };\n\n if (pciInstance.getInstance) {\n const dom = this.markupEl || this.container;\n // Round-trip support for object states (stored as a prefixed JSON string by the host).\n // For strict string-based PCIs we pass the original string through unchanged.\n let restoredState = config.state;\n if (typeof restoredState === 'string' && restoredState.indexOf('__qti_json__::') === 0) {\n try {\n restoredState = JSON.parse(restoredState.substring('__qti_json__::'.length));\n } catch (e) {\n // If parsing fails, fall back to the raw string.\n restoredState = config.state;\n }\n }\n // Keep the configuration around next to the instance, it carries the\n // status and response declaration this PCI was constructed with.\n this.pciConfig = pciConfig;\n pciInstance.getInstance(dom, pciConfig, restoredState || undefined);\n } else {\n this.notifyError('Loaded PCI module has no getInstance().');\n }\n },\n notifyReady: () => {\n PCIManager.notifyReady();\n }\n };\n });\n\n function getResolvablePathString(path, basePath) {\n path = path.replace(/\\\\.js$/, '');\n if (/^[a-z][a-z0-9+.-]*:/i.test(path) || !basePath) {\n return path;\n }\n\n if (path.startsWith('/') && !path.startsWith('//')) {\n path = path.slice(1);\n }\n\n try {\n const resolved = new URL(path, ensureDirectoryBasePath(basePath)).toString();\n return resolved.replace(/\\\\.js$/, '');\n } catch (error) {\n return removeDoubleSlashes(ensureDirectoryBasePath(basePath) + path);\n }\n }\n\n // Load the PCI module\n this.loadModule(config.module);\n },\n\n loadModule: function (modulePath) {\n try {\n // Get the context-specific require\n const contextRequire = window.requirejs.config({\n context: this.customInteractionTypeIdentifier\n });\n contextRequire(['require'], require => {\n // Now load the actual module\n require([modulePath], () => {}, err => {\n console.error('Error loading module:', modulePath, err);\n this.notifyError('Module load error: ' + err.toString());\n });\n });\n } catch (error) {\n console.error('Exception in loadModule:', modulePath);\n console.error(error);\n this.notifyError('Error in require call: ' + error.toString());\n }\n },\n\n notifyReady: function () {\n window.parent.postMessage(\n {\n source: 'qti-pci-iframe',\n responseIdentifier: this.responseIdentifier,\n method: 'iframeReady'\n },\n '*'\n );\n },\n\n notifyInteractionChanged: function (response, state, valid, customValidity) {\n window.parent.postMessage(\n {\n source: 'qti-pci-iframe',\n responseIdentifier: this.responseIdentifier,\n method: 'interactionChanged',\n params: {\n value: response,\n state: state,\n valid: typeof valid === 'boolean' ? valid : undefined,\n customValidity: typeof customValidity === 'string' ? customValidity : undefined\n }\n },\n '*'\n );\n },\n\n notifyError: function (message) {\n console.error('PCI Error:', message);\n window.parent.postMessage(\n {\n source: 'qti-pci-iframe',\n responseIdentifier: this.responseIdentifier,\n method: 'error',\n params: { message: message }\n },\n '*'\n );\n },\n\n setMarkup: function (markupHtml) {\n if (!this.container) {\n this.container = document.getElementById('pci-container');\n }\n if (!this.container) {\n this.pendingMarkup = markupHtml;\n return;\n }\n this.markupEl = this.container.querySelector('qti-interaction-markup');\n if (!this.markupEl) {\n this.markupEl = document.createElement('qti-interaction-markup');\n this.container.appendChild(this.markupEl);\n }\n this.markupEl.classList.add('qti-customInteraction');\n this.markupEl.innerHTML = markupHtml || '';\n },\n\n setProperties: function (propertiesHtml) {\n if (!this.container) {\n this.container = document.getElementById('pci-container');\n }\n if (!this.container) {\n this.pendingProperties = propertiesHtml;\n return;\n }\n this.propertiesEl = this.container.querySelector('properties');\n if (!this.propertiesEl) {\n this.propertiesEl = document.createElement('properties');\n this.container.appendChild(this.propertiesEl);\n }\n this.propertiesEl.style.display = 'none';\n this.propertiesEl.innerHTML = propertiesHtml || '';\n },\n\n minifyCss: function (cssContent) {\n return cssContent\n .replace(/\\\\/\\\\*[\\\\s\\\\S]*?\\\\*\\\\//g, '')\n .replace(/\\\\s+/g, ' ')\n .replace(/\\\\s*([{}:;])\\\\s*/g, '$1')\n .trim();\n },\n\n setStylesheets: function (stylesheetsHtml) {\n if (!stylesheetsHtml) return;\n if (!this.container) {\n this.container = document.getElementById('pci-container');\n }\n const target = this.container || document.body;\n if (!target) return;\n target.insertAdjacentHTML('afterbegin', stylesheetsHtml);\n },\n\n\n applyBoundTo: function (boundTo) {\n if (!this.pciInstance || typeof this.pciInstance.setResponse !== 'function') return;\n const value = boundTo && (boundTo[this.responseIdentifier] || boundTo[Object.keys(boundTo)[0]]);\n if (value) this.pciInstance.setResponse(value);\n }\n };\n\n // Set up message listener for communication with parent\n let expectedParentOrigin = null;\n window.addEventListener('message', function (event) {\n const { data } = event;\n\n // Ensure the message is from our parent\n if (event.source !== window.parent || !data || data.source !== 'qti-portable-custom-interaction') {\n return;\n }\n if (expectedParentOrigin === null) {\n expectedParentOrigin = event.origin;\n } else if (event.origin !== expectedParentOrigin) {\n return;\n }\n\n function deepQuerySelector(root, selector) {\n if (!root) return null;\n try {\n const direct = root.querySelector ? root.querySelector(selector) : null;\n if (direct) return direct;\n } catch (e) {\n // ignore invalid selector for this root\n }\n if (!root.querySelectorAll) return null;\n const nodes = root.querySelectorAll('*');\n for (const node of nodes) {\n if (node && node.shadowRoot) {\n const found = deepQuerySelector(node.shadowRoot, selector);\n if (found) return found;\n }\n }\n return null;\n }\n\n function deepFindElementByExactText(root, text) {\n if (!root || !text) return null;\n if (root.querySelectorAll) {\n const nodes = root.querySelectorAll('*');\n for (const node of nodes) {\n if ((node.textContent || '').trim() === text) return node;\n if (node.shadowRoot) {\n const found = deepFindElementByExactText(node.shadowRoot, text);\n if (found) return found;\n }\n }\n }\n return null;\n }\n\n switch (data.method) {\n case 'initialize':\n PCIManager.initialize(data.params);\n break;\n\n case 'setMarkup':\n PCIManager.setMarkup(data.params);\n break;\n\n case 'setBoundTo':\n if (PCIManager.pciInstance) {\n PCIManager.applyBoundTo(data.params);\n } else {\n PCIManager.pendingBoundTo = data.params;\n }\n break;\n\n case 'setProperties':\n PCIManager.setProperties(data.params);\n break;\n\n case 'setStylesheets':\n PCIManager.setStylesheets(data.params);\n break;\n\n case 'setState':\n if (PCIManager.pciInstance && typeof PCIManager.pciInstance.setState === 'function') {\n PCIManager.pciInstance.setState((data.params && data.params.state) || data.params);\n } else {\n PCIManager.pendingState = (data.params && data.params.state) || data.params;\n }\n break;\n\n case 'getContent': {\n const messageId = data.params && data.params.messageId;\n const collectShadowHtml = root => {\n const parts = [];\n if (!root || !root.querySelectorAll) return parts;\n const nodes = root.querySelectorAll('*');\n for (const node of nodes) {\n if (node && node.shadowRoot) {\n parts.push(node.shadowRoot.innerHTML || '');\n parts.push(...collectShadowHtml(node.shadowRoot));\n }\n }\n return parts;\n };\n const shadowHtml = collectShadowHtml(document).join('\\\\n');\n window.parent.postMessage(\n {\n source: 'qti-pci-iframe',\n responseIdentifier: PCIManager.responseIdentifier,\n method: 'getContentResponse',\n messageId: messageId,\n content: (document.documentElement ? document.documentElement.outerHTML : '') + '\\\\n' + shadowHtml\n },\n '*'\n );\n break;\n }\n\n case 'simulateClick': {\n const messageId = data.params && data.params.messageId;\n const x = data.params && data.params.x;\n const y = data.params && data.params.y;\n const el = typeof x === 'number' && typeof y === 'number' ? document.elementFromPoint(x, y) : null;\n const target = (el && el.closest && el.closest('.hitbox')) || document.querySelector('.hitbox') || el;\n if (target) {\n const evt = new MouseEvent('click', {\n bubbles: true,\n clientX: x,\n clientY: y,\n screenX: x,\n screenY: y,\n view: window\n });\n target.dispatchEvent(evt);\n }\n window.parent.postMessage(\n {\n source: 'qti-pci-iframe',\n responseIdentifier: PCIManager.responseIdentifier,\n method: 'clickResponse',\n messageId: messageId\n },\n '*'\n );\n break;\n }\n\n case 'getBoundingRect': {\n const messageId = data.params && data.params.messageId;\n const selector = data.params && data.params.selector;\n const el = selector ? deepQuerySelector(document, selector) : null;\n const rect = el && typeof el.getBoundingClientRect === 'function' ? el.getBoundingClientRect() : null;\n window.parent.postMessage(\n {\n source: 'qti-pci-iframe',\n responseIdentifier: PCIManager.responseIdentifier,\n method: 'getBoundingRectResponse',\n messageId: messageId,\n rect: rect\n ? {\n left: rect.left,\n top: rect.top,\n width: rect.width,\n height: rect.height\n }\n : null\n },\n '*'\n );\n break;\n }\n\n case 'clickOnSelector': {\n const messageId = data.params && data.params.messageId;\n const selector = data.params && data.params.selector;\n const el = selector ? deepQuerySelector(document, selector) : null;\n const success = !!el;\n if (el && typeof el.click === 'function') el.click();\n window.parent.postMessage(\n {\n source: 'qti-pci-iframe',\n responseIdentifier: PCIManager.responseIdentifier,\n method: 'clickSelectorResponse',\n messageId: messageId,\n success: success\n },\n '*'\n );\n break;\n }\n\n case 'clickOnElementByText': {\n const messageId = data.params && data.params.messageId;\n const text = data.params && data.params.text;\n const target = text ? deepFindElementByExactText(document, text) : null;\n const success = !!target;\n if (target && typeof target.click === 'function') target.click();\n window.parent.postMessage(\n {\n source: 'qti-pci-iframe',\n responseIdentifier: PCIManager.responseIdentifier,\n method: 'clickTextResponse',\n messageId: messageId,\n success: success\n },\n '*'\n );\n break;\n }\n\n case 'setValueElement': {\n const messageId = data.params && data.params.messageId;\n const selector = data.params && data.params.selector;\n const value = data.params && data.params.value;\n const el = selector ? deepQuerySelector(document, selector) : null;\n let success = false;\n if (el && 'value' in el) {\n try {\n el.value = value;\n el.dispatchEvent(new Event('input', { bubbles: true }));\n el.dispatchEvent(new Event('change', { bubbles: true }));\n success = true;\n } catch (e) {\n success = false;\n }\n }\n window.parent.postMessage(\n {\n source: 'qti-pci-iframe',\n responseIdentifier: PCIManager.responseIdentifier,\n method: 'setValueResponse',\n messageId: messageId,\n success: success\n },\n '*'\n );\n break;\n }\n\n case 'console':\n window.parent.postMessage(\n {\n source: 'qti-pci-iframe',\n responseIdentifier: PCIManager.responseIdentifier,\n method: 'console',\n level: data.level,\n args: data.args\n },\n '*'\n );\n break;\n }\n });\n\n let resizeTimeout;\n let previousHeight = 0;\n const notifyResize = () => {\n const container = document.getElementById('pci-container');\n const newHeight = container.scrollHeight + 100;\n if (newHeight !== previousHeight) {\n previousHeight = newHeight;\n clearTimeout(resizeTimeout);\n resizeTimeout = setTimeout(() => {\n window.parent.postMessage(\n {\n source: 'qti-pci-iframe',\n responseIdentifier: PCIManager.responseIdentifier,\n method: 'resize',\n height: newHeight,\n width: container.scrollWidth\n },\n '*'\n );\n }, 100); // Adjust debounce time as needed\n }\n };\n\n function setupResizeObserver() {\n const container = document.getElementById('pci-container');\n if (!container || !(container instanceof Element)) {\n console.warn('ResizeObserver: document.container is not an Element');\n return;\n }\n\n const resizeObserver = new ResizeObserver(() => {\n notifyResize();\n });\n\n resizeObserver.observe(container);\n }\n\n // Run setup once DOM is ready\n if (document.readyState === 'loading') {\n document.addEventListener('DOMContentLoaded', () => {\n notifyResize(); // initial resize\n setupResizeObserver();\n });\n } else {\n notifyResize();\n setupResizeObserver();\n }\n\n window.addEventListener('load', () => {\n notifyResize();\n });\n let lastResponseStr = '';\n setInterval(() => {\n if (PCIManager.interactionChangedViaEvent) return;\n if (PCIManager.pciInstance && PCIManager.pciInstance.getResponse) {\n const response = PCIManager.pciInstance.getResponse();\n const valid =\n PCIManager.pciInstance && typeof PCIManager.pciInstance.checkValidity === 'function'\n ? PCIManager.pciInstance.checkValidity()\n : undefined;\n const customValidity =\n PCIManager.pciInstance && typeof PCIManager.pciInstance.getCustomValidity === 'function'\n ? PCIManager.pciInstance.getCustomValidity()\n : undefined;\n if (response === undefined) {\n // Don't emit an initial empty on load; only emit a clear if we previously had a value\n if (!PCIManager.hadResponse) return;\n PCIManager.hadResponse = false;\n PCIManager.lastResponseStr = null;\n const state =\n PCIManager.pciInstance && typeof PCIManager.pciInstance.getState === 'function'\n ? PCIManager.pciInstance.getState()\n : null;\n window.parent.postMessage(\n {\n source: 'qti-pci-iframe',\n responseIdentifier: PCIManager.responseIdentifier,\n method: 'interactionChanged',\n params: { value: null, state: state, valid: valid, customValidity: customValidity }\n },\n '*'\n );\n return;\n }\n\n const responseStr = JSON.stringify(response);\n\n if (responseStr !== PCIManager.lastResponseStr) {\n PCIManager.lastResponseStr = responseStr;\n PCIManager.hadResponse = true;\n const state =\n PCIManager.pciInstance && typeof PCIManager.pciInstance.getState === 'function'\n ? PCIManager.pciInstance.getState()\n : null;\n window.parent.postMessage(\n {\n source: 'qti-pci-iframe',\n responseIdentifier: PCIManager.responseIdentifier,\n method: 'interactionChanged',\n params: { value: response, state: state, valid: valid, customValidity: customValidity }\n },\n '*'\n );\n }\n }\n }, 500); // Check every 500ms\n </script>\n </head>\n <body>\n <div id=\"pci-container\"></div>\n </body>\n </html>`;\n }\n\n /**\n * Method to disable the PCI for review mode\n * This can be used when showing the correct response\n */\n public disable() {\n // First, store the current state of the PCI\n this.#previousState = {\n pointerEvents: this.style.pointerEvents,\n position: this.style.position\n };\n\n this.sendMessageToIframe('setState', { state: 'disabled' });\n\n // Add an overlay to prevent interaction if not already there\n const existingOverlay = this.querySelector('.pci-interaction-overlay');\n if (!existingOverlay) {\n const overlay = document.createElement('div');\n overlay.className = 'pci-interaction-overlay';\n overlay.style.position = 'absolute';\n overlay.style.top = '0';\n overlay.style.left = '0';\n overlay.style.width = '100%';\n overlay.style.height = '100%';\n overlay.style.backgroundColor = 'rgba(200, 200, 200, 0.3)';\n overlay.style.zIndex = '100';\n overlay.style.pointerEvents = 'all';\n overlay.style.cursor = 'not-allowed';\n\n // Make sure the container is relatively positioned\n if (getComputedStyle(this).position === 'static') {\n this.style.position = 'relative';\n }\n\n this.appendChild(overlay);\n }\n }\n\n /**\n * Method to enable the PCI for interactive mode\n */\n public enable() {\n // Remove any overlays\n const overlay = this.querySelector('.pci-interaction-overlay');\n if (overlay) {\n overlay.remove();\n }\n\n // Restore previous state if available\n if (this.#previousState) {\n if (this.#previousState.pointerEvents) {\n this.style.pointerEvents = this.#previousState.pointerEvents;\n }\n if (this.#previousState.position) {\n this.style.position = this.#previousState.position;\n }\n this.#previousState = null;\n }\n\n this.sendMessageToIframe('setState', { state: 'interacting' });\n }\n\n // Add this property to store the previous state\n #previousState: {\n pointerEvents?: string;\n position?: string;\n } = null;\n\n override render() {\n return html`\n <slot></slot>\n ${this._errorMessage\n ? html`<div style=\"color:red\">\n <h1>Error</h1>\n ${this._errorMessage}\n </div>`\n : ''}\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'qti-portable-custom-interaction': QtiPortableCustomInteraction;\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"qti-portable-custom-interaction.js","sourceRoot":"","sources":["../src/qti-portable-custom-interaction.ts"],"names":[],"mappings":"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","sourcesContent":["import { css, html } from 'lit';\nimport { property, state } from 'lit/decorators.js';\nimport { consume } from '@lit/context';\n\nimport {\n Interaction,\n isRecordValue,\n itemContext,\n qtiContext,\n readRecordFieldValues,\n removeDoubleSlashes,\n responseAttributeConverter\n} from '@qti-components/base';\nimport nativeCss from '@qti-components/theme/native-css';\n\nimport styles from './qti-portable-custom-interaction.styles';\nimport {\n coerceBaseValue,\n recordFromQtiVariableJSON,\n recordResponseToQtiVariableJSON,\n recordToQtiVariableJSON\n} from './record-response';\nimport requireJsSource from './vendor/require-js';\n\nimport type { CSSResultGroup } from 'lit';\nimport type { BaseType, Cardinality, ItemContext, QtiContext, RecordValue } from '@qti-components/base';\nimport type { PciInteractionStatus, PciResponseDeclaration, QtiVariableJSON, ResponseVariableType } from './interface';\n\n/** Text for an inline `<script>`: a `</script` inside it would end the element early. */\nexport const inlineScriptText = (text: string) => text.replace(/<\\/(script)/gi, '<\\\\/$1');\n\n/** Text for an inline `<style>`: a `</style` inside it would end the element early. */\nexport const inlineStyleText = (text: string) => text.replace(/<\\/(style)/gi, '<\\\\/$1');\n\n/** Statuses in which the item is showing the correct response, so a PCI may legitimately see it. */\nconst STATUSES_SHOWING_CORRECT_RESPONSE: PciInteractionStatus[] = ['solution', 'review'];\n\n/** A response value as this interaction holds it: a record response is its field map. */\ntype PciResponseValue = string | string[] | RecordValue;\n\n/**\n * Whether a response variable actually declares a correct response.\n *\n * Non-single cardinality yields `[]` for an empty `<qti-correct-response>`, which is \"no correct\n * response\" and must not be reported as one. A record's correct response is a field map.\n */\nfunction hasCorrectResponseValue(value: PciResponseValue | null | undefined): boolean {\n if (value === null || value === undefined) return false;\n if (Array.isArray(value)) return value.length > 0;\n if (isRecordValue(value)) return Object.keys(value).length > 0;\n return value !== '';\n}\n\nexport class QtiPortableCustomInteraction extends Interaction {\n #value: PciResponseValue;\n\n protected _iframeLoaded = false;\n protected _interactionReady = false;\n protected _pendingMessages: Array<{ method: string; params: any }> = [];\n protected iframe: HTMLIFrameElement;\n protected _iframeMessageOrigin: string | null = null;\n\n // This implementation always renders inside an iframe.\n static override styles: CSSResultGroup = [\n styles,\n css`\n :host {\n display: block;\n width: 100%;\n min-height: 50px;\n }\n `\n ];\n\n @property({ type: String, attribute: 'module' })\n module: string;\n\n @property({ type: String, attribute: 'custom-interaction-type-identifier' })\n customInteractionTypeIdentifier: string;\n\n @property({ type: String, attribute: 'data-require-paths' })\n requirePathsJson: string = '';\n\n @property({ type: String, attribute: 'data-require-shim' })\n requireShimJson: string = '';\n\n /** A RequireJS to load in the iframe instead of the inlined copy (src/vendor/require-js.ts). */\n @property({ type: String, attribute: 'data-require-js-url' })\n requireJsUrl: string = '';\n\n @property({ type: String, attribute: 'data-base-url' })\n baseUrl: string = '';\n\n @property({ type: Boolean, attribute: 'data-use-default-paths' })\n useDefaultPaths = false;\n\n /**\n * Item lifecycle status handed to the PCI in its `getInstance` configuration.\n * A delivery engine sets `solution` to let a PCI render the correct response.\n */\n @property({ type: String, attribute: 'data-status' })\n status: PciInteractionStatus = 'interacting';\n\n #responseDeclaration: PciResponseDeclaration | null = null;\n\n /**\n * Response declaration passed into the PCI configuration, so a PCI can render\n * the correct response itself instead of having it pushed in as a response.\n *\n * Derived from the item context, unless a host sets it explicitly - the\n * correct response viewer does, since it has no response declaration of its own.\n *\n * See https://github.com/1EdTech/qti-project-management/issues/210\n */\n set responseDeclaration(declaration: PciResponseDeclaration | null) {\n this.#responseDeclaration = declaration;\n }\n\n get responseDeclaration(): PciResponseDeclaration | null {\n if (this.#responseDeclaration) {\n return this.#responseDeclaration;\n }\n\n const variable = this.responseVariable;\n if (!variable) {\n return null;\n }\n\n const declaration: PciResponseDeclaration = {\n baseType: variable.baseType,\n cardinality: variable.cardinality\n };\n\n const correctResponse = variable.correctResponse as PciResponseValue | null | undefined;\n if (hasCorrectResponseValue(correctResponse)) {\n declaration.correctResponse = { value: correctResponse };\n }\n\n return declaration;\n }\n\n /**\n * The declaration as it goes into the PCI configuration.\n *\n * `correctResponse` is withheld unless the item is actually showing a solution. A PCI is\n * third-party code running in an iframe, and there is no reason for it to hold the answer key\n * while the candidate is still working - the use case this field exists for only applies once\n * the status says the correct response is being shown.\n *\n * The filter sits here rather than in the `responseDeclaration` getter so it also covers a\n * declaration a host set explicitly, not just the one derived from the item context.\n */\n #responseDeclarationForStatus(): PciResponseDeclaration | null {\n const declaration = this.responseDeclaration;\n if (!declaration?.correctResponse) {\n return declaration;\n }\n if (STATUSES_SHOWING_CORRECT_RESPONSE.includes(this.status)) {\n return declaration;\n }\n\n const { correctResponse: _withheld, ...rest } = declaration;\n return rest;\n }\n\n @state()\n private _errorMessage: string = null;\n\n @consume({ context: itemContext, subscribe: true })\n @state()\n protected context?: ItemContext;\n\n @consume({ context: qtiContext, subscribe: true })\n @state()\n protected qtiContext?: QtiContext;\n\n @property({ attribute: 'response', reflect: false, converter: responseAttributeConverter({ emptyAs: null }) })\n response: string | string[] | null = null;\n\n #parsedRequirePaths: Record<string, string | string[]> = null;\n #parsedRequireShim: Record<string, any> = null;\n #pciValidity: boolean | null = null;\n #pciCustomValidityMessage = '';\n\n /**\n * Parse the require paths JSON string into an object\n */\n #getRequirePaths(): Record<string, string | string[]> {\n if (this.#parsedRequirePaths === null && this.requirePathsJson) {\n try {\n const parsedJson = JSON.parse(this.requirePathsJson);\n if (Array.isArray(parsedJson) || !parsedJson || typeof parsedJson !== 'object') {\n throw new Error('Require paths must be a JSON object.');\n }\n this.#parsedRequirePaths = parsedJson;\n } catch (e) {\n console.error('Error parsing require paths JSON:', e);\n this._errorMessage = `Error parsing require paths JSON: ${e.message}`;\n this.#parsedRequirePaths = {};\n }\n }\n return this.#parsedRequirePaths || {};\n }\n\n /**\n * Parse the require shim JSON string into an object\n */\n #getRequireShim(): Record<string, any> {\n if (this.#parsedRequireShim === null && this.requireShimJson) {\n try {\n this.#parsedRequireShim = JSON.parse(this.requireShimJson);\n } catch (e) {\n console.error('Error parsing require shim JSON:', e);\n this._errorMessage = `Error parsing require shim JSON: ${e.message}`;\n this.#parsedRequireShim = {};\n }\n }\n return this.#parsedRequireShim || {};\n }\n\n /**\n * Get the final require paths by combining defaults with user-provided paths\n */\n #getFinalRequirePaths(): Record<string, string | string[]> {\n // Return only user-provided paths to keep PCI completely self-contained\n return this.#getRequirePaths();\n }\n\n /**\n * Get the final require shim\n */\n #getFinalRequireShim(): Record<string, any> {\n return this.#getRequireShim();\n }\n\n /**\n * Converts QtiVariableJSON to a string, a string array, or for a record its field map\n */\n #convertQtiVariableJSON(input: QtiVariableJSON): PciResponseValue | null {\n if (input && Array.isArray(input.record)) {\n const record = recordFromQtiVariableJSON(input.record);\n return Object.keys(record).length ? record : null;\n }\n for (const topLevelKey in input) {\n // eslint-disable-next-line no-prototype-builtins\n if (input.hasOwnProperty(topLevelKey)) {\n const nestedObject = input[topLevelKey as 'list' | 'base'];\n if (nestedObject) {\n for (const nestedKey in nestedObject) {\n // eslint-disable-next-line no-prototype-builtins\n if (nestedObject.hasOwnProperty(nestedKey)) {\n const value = nestedObject[nestedKey as keyof typeof nestedObject];\n if (Array.isArray(value)) {\n return value.map(String); // Convert each element in the array to string\n } else if (value !== undefined && value !== null) {\n return String(value); // Convert the single value to string\n }\n }\n }\n }\n }\n }\n return null;\n }\n\n /**\n * Get direct child elements by tag name\n */\n private getDirectChildrenByTag(tagName: string): Element[] {\n const needle = tagName.toLowerCase();\n return Array.from(this.children).filter(child => child.tagName.toLowerCase() === needle);\n }\n\n /**\n * Normalize an input into a list form\n */\n private normalizeListValue(value: unknown): unknown[] {\n if (value === null || value === undefined) return [];\n return Array.isArray(value) ? value : [value];\n }\n\n /**\n * Convert a variable value to QtiVariableJSON\n */\n private variableToQtiVariableJSON(value: unknown, cardinality: Cardinality, baseType: BaseType): QtiVariableJSON {\n if (cardinality === 'record' || baseType === 'record') {\n return recordToQtiVariableJSON(value);\n }\n\n if (cardinality !== 'single') {\n const listValues = this.normalizeListValue(value).map(v => coerceBaseValue(v, baseType));\n return { list: { [baseType]: listValues } };\n }\n\n return { base: { [baseType]: coerceBaseValue(value, baseType) } };\n }\n\n /**\n * Extract default QTI_CONTEXT values from qti-context-declaration elements\n */\n private getQtiContextDefaultsFromItem(): Record<string, unknown> {\n const itemElement = this.closest('qti-assessment-item');\n if (!itemElement) return {};\n\n const defaults: Record<string, unknown> = {};\n const contextDeclarations = itemElement.querySelectorAll('qti-context-declaration[identifier=\"QTI_CONTEXT\"]');\n\n contextDeclarations.forEach(declaration => {\n const defaultValueElement = declaration.querySelector('qti-default-value');\n if (!defaultValueElement) return;\n\n const { value, baseTypes } = readRecordFieldValues(defaultValueElement.querySelectorAll('qti-value'));\n for (const [fieldIdentifier, textContent] of Object.entries(value)) {\n defaults[fieldIdentifier] = coerceBaseValue(textContent, baseTypes[fieldIdentifier] ?? 'string');\n }\n });\n\n return defaults;\n }\n\n /**\n * Build a QTI_CONTEXT record for PCI consumption\n */\n private getQtiContextRecord(): QtiVariableJSON | null {\n const defaults = this.getQtiContextDefaultsFromItem();\n const runtime = this.qtiContext?.QTI_CONTEXT || {};\n const merged: Record<string, unknown> = { ...defaults, ...runtime };\n if (!Object.keys(merged).length) return null;\n\n const normalized = {\n candidateIdentifier: merged.candidateIdentifier ?? '',\n testIdentifier: merged.testIdentifier ?? '',\n environmentIdentifier: merged.environmentIdentifier ?? '',\n ...merged\n };\n\n return recordToQtiVariableJSON(normalized);\n }\n\n /**\n * Collect template variables referenced by qti-template-variable children\n */\n private getTemplateVariables(): Record<string, QtiVariableJSON> {\n const templateVariables: Record<string, QtiVariableJSON> = {};\n const templateVariableElements = this.getDirectChildrenByTag('qti-template-variable');\n if (!templateVariableElements.length) return templateVariables;\n\n templateVariableElements.forEach(el => {\n const identifier = el.getAttribute('template-identifier') || el.getAttribute('identifier') || '';\n if (!identifier) return;\n\n const variable = this.context?.variables?.find(v => v.identifier === identifier);\n if (!variable) return;\n\n const cardinality = (variable.cardinality || 'single') as Cardinality;\n const baseType = (variable.baseType || 'string') as BaseType;\n templateVariables[identifier] = this.variableToQtiVariableJSON(variable.value, cardinality, baseType);\n });\n\n return templateVariables;\n }\n\n /**\n * Collect context variables referenced by qti-context-variable children\n */\n private getContextVariables(): Record<string, QtiVariableJSON> {\n const contextVariables: Record<string, QtiVariableJSON> = {};\n const contextVariableElements = this.getDirectChildrenByTag('qti-context-variable');\n if (!contextVariableElements.length) return contextVariables;\n\n contextVariableElements.forEach(el => {\n const identifier = el.getAttribute('identifier') || '';\n if (!identifier) return;\n\n if (identifier === 'QTI_CONTEXT') {\n const record = this.getQtiContextRecord();\n if (record) contextVariables[identifier] = record;\n return;\n }\n\n const variable = this.context?.variables?.find(v => v.identifier === identifier);\n if (!variable) return;\n\n const cardinality = (variable.cardinality || 'single') as Cardinality;\n const baseType = (variable.baseType || 'string') as BaseType;\n contextVariables[identifier] = this.variableToQtiVariableJSON(variable.value, cardinality, baseType);\n });\n\n return contextVariables;\n }\n\n /**\n * Adds hyphenated versions of camelCase keys to properties object\n */\n #addHyphenatedKeys(properties: Record<string, any>): Record<string, any> {\n const updatedProperties = { ...properties };\n\n for (const key in properties) {\n if (Object.prototype.hasOwnProperty.call(properties, key)) {\n const hyphenatedKey = key.replace(/[A-Z]/g, char => `-${char.toLowerCase()}`);\n updatedProperties[hyphenatedKey] = properties[key];\n }\n }\n\n return updatedProperties;\n }\n\n #toNestedProperties(properties: Record<string, any>): Record<string, any> {\n const nestedProperties = { ...properties };\n\n const setNestedValue = (root: Record<string, any>, path: string[], value: any): void => {\n let cursor = root;\n\n for (let i = 0; i < path.length; i += 1) {\n const segment = path[i];\n const isLast = i === path.length - 1;\n\n if (isLast) {\n cursor[segment] = value;\n return;\n }\n\n if (!cursor[segment] || typeof cursor[segment] !== 'object' || Array.isArray(cursor[segment])) {\n cursor[segment] = {};\n }\n\n cursor = cursor[segment];\n }\n };\n\n for (const [key, value] of Object.entries(properties)) {\n if (!key.includes('__')) continue;\n const path = key.split('__').filter(Boolean);\n if (path.length < 2) continue;\n setNestedValue(nestedProperties, path, value);\n }\n\n return nestedProperties;\n }\n\n /**\n * Converts response variables to QtiVariableJSON\n */\n protected responseVariablesToQtiVariableJSON(\n input: PciResponseValue,\n cardinality: Cardinality,\n baseType: BaseType,\n fieldBaseTypes?: Record<string, BaseType>\n ): QtiVariableJSON {\n if (cardinality === 'record') {\n // A record declaration has no base-type: the fields carry their own, declared or inferred.\n return recordResponseToQtiVariableJSON(input, fieldBaseTypes);\n }\n if (cardinality !== 'single') {\n const list = { list: {} };\n list.list[baseType] = input;\n return list;\n } else {\n const base = { base: {} };\n base.base[baseType] = input;\n return base;\n }\n }\n\n #hasNonEmptyResponse(): boolean {\n if (this.response === null || this.response === undefined) return false;\n if (isRecordValue(this.response)) {\n return Object.values(this.response).some(v => v !== '' && v !== null && v !== undefined);\n }\n if (Array.isArray(this.response)) {\n if (this.response.length === 0) return false;\n return this.response.some(v => v !== '' && v !== null && v !== undefined);\n }\n return this.response !== '';\n }\n\n #setInteractionValidity(isValid: boolean, customMessage?: string): void {\n const fallbackMessage = this.dataset.invalidresponsemessage || 'Invalid response.';\n const message = isValid ? '' : customMessage && customMessage.trim().length > 0 ? customMessage : fallbackMessage;\n this._internals.setValidity(isValid ? {} : { customError: true }, message);\n }\n\n validate(): boolean {\n const isValid = typeof this.#pciValidity === 'boolean' ? this.#pciValidity : this.#hasNonEmptyResponse();\n this.#setInteractionValidity(isValid, this.#pciCustomValidityMessage);\n return isValid;\n }\n\n override set value(v: string | null) {\n if (v === null) {\n this.#value = [];\n } else {\n this.#value = Array.isArray(v) ? v : v.split(',');\n }\n // PCI handles response setting via boundTo property during initialization\n // No need to call setResponse directly\n }\n\n override get value(): string | null {\n if (this.#value === null || this.#value === undefined) return null;\n if (isRecordValue(this.#value)) return JSON.stringify(this.#value);\n return Array.isArray(this.#value) ? this.#value.join(',') : String(this.#value);\n }\n\n set boundTo(newValue: Record<string, ResponseVariableType>) {\n if (!newValue || !newValue[this.responseIdentifier]) {\n return;\n }\n\n const value = this.#convertQtiVariableJSON(newValue[this.responseIdentifier]);\n this.#value = value;\n\n // No direct call to setResponse - PCI will handle this during initialization\n // through the boundTo property in the config\n\n this.saveResponse(value as string | string[]);\n }\n\n get boundTo(): Record<string, QtiVariableJSON> {\n const responseVariable: Record<string, QtiVariableJSON> = {};\n const variable = this.context?.variables?.find(v => v.identifier === this.responseIdentifier);\n if (variable) {\n const cardinality = variable.cardinality || 'single';\n const baseType = variable.baseType || 'string';\n const value = (variable.value || null) as PciResponseValue;\n const fieldBaseTypes = (variable as { fieldBaseTypes?: Record<string, BaseType> }).fieldBaseTypes;\n const responseVal = this.responseVariablesToQtiVariableJSON(value, cardinality, baseType, fieldBaseTypes);\n responseVariable[this.responseIdentifier] = responseVal;\n }\n\n return responseVariable;\n }\n\n /**\n * Unescape HTML entities in a string\n */\n #unescapeHtml(str: string): string {\n if (!str) return str;\n\n return str\n .replace(/&/g, '&')\n .replace(/</g, '<')\n .replace(/>/g, '>')\n .replace(/"/g, '\"')\n .replace(/'/g, \"'\")\n .replace(///g, '/')\n .replace(/`/g, '`')\n .replace(/=/g, '=');\n }\n\n /**\n * Unescape HTML entities in all values of an object\n */\n #unescapeDataAttributes(obj: Record<string, any>): Record<string, any> {\n const unescaped: Record<string, any> = {};\n\n for (const [key, value] of Object.entries(obj)) {\n if (typeof value === 'string') {\n unescaped[key] = this.#unescapeHtml(value);\n } else {\n unescaped[key] = value;\n }\n }\n\n return unescaped;\n }\n\n override disconnectedCallback(): void {\n super.disconnectedCallback();\n window.removeEventListener('message', this.handleIframeMessage);\n }\n\n /**\n * IFRAME MODE: Send message to iframe\n */\n protected sendMessageToIframe(method: string, params: any) {\n const targetWindow = this.iframe?.contentWindow;\n if (!this._iframeLoaded || !targetWindow) {\n this._pendingMessages.push({ method, params });\n return;\n }\n targetWindow.postMessage(\n {\n source: 'qti-portable-custom-interaction',\n responseIdentifier: this.responseIdentifier,\n method,\n params\n },\n '*'\n );\n }\n\n /**\n * IFRAME MODE: Process pending messages\n */\n #processPendingMessages() {\n if (this._pendingMessages.length) {\n this._pendingMessages.forEach(message => {\n this.sendMessageToIframe(message.method, message.params);\n });\n this._pendingMessages = [];\n }\n }\n\n /**\n * IFRAME MODE: Handle iframe messages\n */\n protected handleIframeMessage = (event: MessageEvent) => {\n const { data } = event;\n // Ensure the message is from our iframe\n if (!data || data.source !== 'qti-pci-iframe') {\n return;\n }\n if (!this.iframe?.contentWindow || event.source !== this.iframe.contentWindow) {\n return;\n }\n if (data.responseIdentifier && data.responseIdentifier !== this.responseIdentifier) {\n return;\n }\n if (this._iframeMessageOrigin === null) {\n this._iframeMessageOrigin = event.origin;\n } else if (event.origin !== this._iframeMessageOrigin) {\n return;\n }\n switch (data.method) {\n case 'iframeReady':\n this._interactionReady = true;\n this.#initializeInteraction();\n this.#processPendingMessages();\n this.dispatchEvent(\n new CustomEvent('qti-portable-custom-interaction-loaded', {\n bubbles: true\n })\n );\n break;\n\n case 'resize':\n if (typeof data.height === 'number' && this.iframe) {\n // Only the height follows the content. The width stays 100% of the host, so the PCI keeps\n // following the item's layout when it gets narrower (a column that stacks, a resized window).\n this.iframe.style.height = `${data.height}px`;\n }\n break;\n case 'console':\n this.dispatchEvent(\n new CustomEvent('qti-pci-console', {\n detail: {\n level: data.level,\n args: data.args\n },\n bubbles: true\n })\n );\n break;\n\n case 'interactionChanged': {\n const raw = data?.params?.value;\n const converted = raw && typeof raw === 'object' ? this.#convertQtiVariableJSON(raw as QtiVariableJSON) : null;\n const pciValid = typeof data?.params?.valid === 'boolean' ? (data.params.valid as boolean) : null;\n const pciCustomValidity =\n typeof data?.params?.customValidity === 'string' ? (data.params.customValidity as string) : null;\n if (pciValid !== null) {\n this.#pciValidity = pciValid;\n if (pciValid && pciCustomValidity === null) {\n this.#pciCustomValidityMessage = '';\n }\n }\n if (pciCustomValidity !== null) {\n this.#pciCustomValidityMessage = pciCustomValidity;\n }\n // PCI state \"should\" be an opaque string, but a lot of existing PCIs (including the\n // IMS conformance examples) return a structured object from getState().\n //\n // We store a string in itemContext.state, so we serialize non-string states with a\n // prefix to safely round-trip them without accidentally parsing user-provided strings.\n const stateRaw = data?.params?.state as unknown;\n let state: string | null | undefined;\n if (stateRaw === undefined) {\n state = undefined;\n } else if (stateRaw === null) {\n state = null;\n } else if (typeof stateRaw === 'string') {\n state = stateRaw;\n } else {\n try {\n state = `__qti_json__::${JSON.stringify(stateRaw)}`;\n } catch {\n state = null;\n }\n }\n\n // Treat null/undefined or unconvertible responses as \"cleared\".\n // The iframe side is responsible for not emitting an initial clear on load.\n if (converted === null) {\n const cardinality = this.responseVariable?.cardinality;\n // A record has no empty literal: a cleared record is NULL.\n const emptyResponse = cardinality === 'record' ? null : cardinality === 'single' ? '' : [];\n this.response = emptyResponse;\n this.validate();\n this.saveResponse(emptyResponse, state);\n break;\n }\n\n // A record response travels as its field map; the shared response types only say string | string[].\n const response = converted as string | string[];\n this.response = response;\n this.validate();\n this.saveResponse(response, state);\n break;\n }\n case 'error':\n this._errorMessage = data.params.message;\n console.error('Error from PCI iframe:', data.params.message);\n break;\n }\n };\n\n /**\n * IFRAME MODE: Create iframe element\n */\n protected createIframe() {\n this._interactionReady = false;\n this.iframe = document.createElement('iframe');\n this.iframe.id = `pci-iframe-${this.responseIdentifier}`;\n this.iframe.setAttribute('title', 'QTI PCI Iframe');\n this.iframe.setAttribute('aria-label', 'QTI PCI Iframe');\n this.iframe.setAttribute('aria-hidden', 'false');\n this.iframe.setAttribute('role', 'application');\n this.iframe.style.width = '100%';\n this.iframe.style.border = 'none';\n this.iframe.style.display = 'block';\n\n // Handle iframe load event\n this.iframe.onload = () => {\n this._iframeLoaded = true;\n this.#addMarkupToIframe();\n // Send initialization data to iframe\n this.#sendIframeInitData();\n };\n\n // Create a unique name for the iframe\n const iframeName = `qti-pci-${this.responseIdentifier}-${Date.now()}`;\n this.iframe.name = iframeName;\n\n // Generate iframe HTML content with all required scripts\n const iframeContent = this.generateIframeContent();\n\n // Use `srcdoc` rather than a `blob:` (or `data:`) URL. Both of those give the iframe document\n // a URL that is out of scope for any http(s) Service Worker registration, so a player that\n // serves package resources through a Service Worker (CacheStorage, virtual paths) would see\n // every request made from inside the PCI - module scripts, images, media, stylesheets, fetches -\n // bypass it and hit the network instead. An `srcdoc` frame inherits this document's URL and\n // stays controlled by the same Service Worker. It is same-origin either way, and messages are\n // posted with a `'*'` target origin, so nothing about postMessage changes.\n this.iframe.srcdoc = iframeContent;\n\n // Append iframe to component\n this.appendChild(this.iframe);\n }\n\n /**\n * IFRAME MODE: Send initialization data to iframe\n */\n #sendIframeInitData() {\n // Once iframe is loaded, send initialization data\n const properties = this.#addHyphenatedKeys(\n this.#toNestedProperties(this.#unescapeDataAttributes({ ...this.dataset }))\n );\n const storedStateRaw = this.context?.state?.[this.responseIdentifier];\n const storedState = typeof storedStateRaw === 'string' && storedStateRaw.length > 0 ? storedStateRaw : null;\n const initData = {\n module: this.module,\n customInteractionTypeIdentifier: this.customInteractionTypeIdentifier,\n baseUrl: !this.baseUrl\n ? window.location.origin\n : this.baseUrl.startsWith('http') || this.baseUrl.startsWith('blob') || this.baseUrl.startsWith('base64')\n ? this.baseUrl\n : removeDoubleSlashes(`${window.location.origin}${this.baseUrl}`),\n responseIdentifier: this.responseIdentifier,\n properties,\n contextVariables: this.getContextVariables(),\n templateVariables: this.getTemplateVariables(),\n dataAttributes: { ...this.dataset },\n interactionModules: this.#getInteractionModules(),\n boundTo: storedState ? null : this.boundTo,\n responseDeclaration: this.#responseDeclarationForStatus(),\n status: this.status,\n state: storedState\n };\n\n this.sendMessageToIframe('initialize', initData);\n }\n\n /**\n * IFRAME MODE: Get interaction modules from DOM\n */\n #getInteractionModules() {\n const modules = [];\n const interactionModules = this.querySelector('qti-interaction-modules');\n\n if (interactionModules) {\n const moduleElements = interactionModules.querySelectorAll('qti-interaction-module');\n for (const module of moduleElements) {\n modules.push({\n id: module.getAttribute('id'),\n primaryPath: module.getAttribute('primary-path'),\n fallbackPath: module.getAttribute('fallback-path')\n });\n }\n }\n\n return modules;\n }\n\n /**\n * IFRAME MODE: Add markup, stylesheets, and properties to iframe\n */\n #addMarkupToIframe() {\n // Get interaction markup if any\n const markup = this.querySelector('qti-interaction-markup');\n if (markup) {\n this.sendMessageToIframe('setMarkup', markup.innerHTML);\n }\n\n const stylesheets = Array.from(this.querySelectorAll('qti-stylesheet'));\n if (stylesheets.length) {\n const stylesheetsHtml = stylesheets.map(sheet => sheet.outerHTML).join('\\n');\n this.sendMessageToIframe('setStylesheets', stylesheetsHtml);\n }\n\n // Get properties if any\n const properties = this.querySelector('properties');\n if (properties) {\n this.sendMessageToIframe('setProperties', properties.innerHTML);\n }\n }\n\n /**\n * IFRAME MODE: Initialize the interaction\n */\n #initializeInteraction() {\n // No explicit action needed, as the PCI will initialize\n // with the boundTo property already provided\n }\n\n override connectedCallback(): void {\n super.connectedCallback();\n this.#pciValidity = null;\n this.#pciCustomValidityMessage = '';\n // Reflect any pre-existing response (e.g. restored session) for validation/completionStatus.\n // Don't clobber a value already set via the `response=\"...\"` attribute.\n const currentResponse = this.response;\n const hasResponse = Array.isArray(currentResponse) ? currentResponse.length > 0 : !!currentResponse;\n if (!hasResponse) {\n this.response = (this.responseVariable?.value as string | string[] | null) ?? null;\n }\n window.addEventListener('message', this.handleIframeMessage);\n this.createIframe();\n }\n\n /**\n * IFRAME MODE: Generate iframe HTML content\n */\n protected generateIframeContent(): string {\n const parentStyles = window.getComputedStyle(document.body);\n\n // Get the configured require paths and shim\n const requirePaths = JSON.stringify(this.#getFinalRequirePaths());\n const requireShim = JSON.stringify(this.#getFinalRequireShim());\n const iframeBaseUrl = this.dataset.baseUrl\n ? this.dataset.baseUrl.startsWith('/')\n ? `${window.location.origin}${this.dataset.baseUrl}`\n : this.dataset.baseUrl\n : '';\n // `data-base-url` names the directory the item was loaded from, so it is also the base every\n // relative URL inside the interaction should resolve against - the markup's `src`/`href`, the\n // stylesheets, and whatever the PCI module resolves itself. Anchoring `<base>` at the site\n // origin instead would send `../assets/x.png` to `/assets/x.png`. Normalise to a trailing\n // slash: without one the last segment counts as a filename and gets dropped.\n const iframeBaseHref = iframeBaseUrl\n ? iframeBaseUrl.endsWith('/')\n ? iframeBaseUrl\n : `${iframeBaseUrl}/`\n : `${window.location.origin}/`;\n const forwardConsole = this.dataset.forwardConsole === 'true';\n // Everything the iframe needs is inline: RequireJS (it loads the PCI module) and the QTI 3 shared vocabulary\n // (qti-layout-row, qti-well, …) that interaction markup may use, both from this version of qti-components. No\n // public CDN is involved. The qti-components bundle and the full item.css are not needed to run a PCI (the markup\n // is plain HTML); a host that wants them in the iframe anyway names its own copy with these attributes.\n const componentsCdnUrl = this.dataset.componentsCdnUrl;\n const componentsCssUrl = this.dataset.componentsCssUrl;\n const requireJsTag = this.requireJsUrl\n ? `<script src=\"${this.requireJsUrl}\"></script>`\n : `<script>${inlineScriptText(requireJsSource)}</script>`;\n\n // Extract just the font-related properties you want to copy\n const fontStyles = `\n font-family: ${parentStyles.getPropertyValue('font-family')};\n font-size: ${parentStyles.getPropertyValue('font-size')};\n line-height: ${parentStyles.getPropertyValue('line-height')};\n font-weight: ${parentStyles.getPropertyValue('font-weight')};\n color: ${parentStyles.getPropertyValue('color')};\n `;\n\n // The language of the interaction (the item's xml:lang, or the page's lang), so a PCI that reads\n // `lang` in its iframe shows its own texts in the item's language.\n const langHost = this.closest('[lang], [xml\\\\:lang]');\n const iframeLang =\n [langHost?.getAttribute('lang'), langHost?.getAttribute('xml:lang'), document.documentElement.lang]\n .map(l => (l ?? '').trim())\n .find(l => /^[A-Za-z]{1,8}(-[A-Za-z0-9]{1,8})*$/.test(l)) ?? 'en';\n\n return /* html */ `<!DOCTYPE html>\n <html lang=\"${iframeLang}\">\n <head>\n <meta charset=\"utf-8\" />\n <title>QTI PCI Container</title>\n <base href=\"${iframeBaseHref}\" />\n ${componentsCdnUrl ? `<script type=\"module\">import '${componentsCdnUrl}';</script>` : ''}\n <style>${inlineStyleText(nativeCss)}</style>\n <style>\n body, html {\n margin: 0;\n padding: 0;\n width: 100%;\n height: auto;\n overflow: hidden;\n /* Add the extracted font styles here */\n ${fontStyles}\n };\n .qti-customInteraction {\n width: 100%;\n height: 100%;\n }\n #pci-container {\n width: 100%;\n /* Keeps the first and last child's margins inside, so scrollHeight is the full height. */\n display: flow-root;\n }\n qti-interaction-markup {\n display: block;\n width: 100%;\n min-height: 50px;\n }\n </style>\n ${componentsCssUrl ? `<link href=\"${componentsCssUrl}\" rel=\"stylesheet\" />` : ''}\n ${requireJsTag}\n <script>\n const forwardConsole = ${forwardConsole ? 'true' : 'false'};\n if (forwardConsole) {\n const originalLog = console.log.bind(console);\n const originalError = console.error.bind(console);\n const stringifyArgs = args =>\n args.map(arg => {\n if (typeof arg === 'string') return arg;\n try {\n return JSON.stringify(arg);\n } catch (e) {\n return String(arg);\n }\n });\n console.log = (...args) => {\n originalLog(...args);\n window.parent.postMessage(\n {\n source: 'qti-pci-iframe',\n responseIdentifier: (window.PCIManager && window.PCIManager.responseIdentifier) || null,\n method: 'console',\n level: 'log',\n args: stringifyArgs(args)\n },\n '*'\n );\n };\n console.error = (...args) => {\n originalError(...args);\n window.parent.postMessage(\n {\n source: 'qti-pci-iframe',\n responseIdentifier: (window.PCIManager && window.PCIManager.responseIdentifier) || null,\n method: 'console',\n level: 'error',\n args: stringifyArgs(args)\n },\n '*'\n );\n };\n }\n // Define standard paths and shims\n window.requirePaths = ${requirePaths};\n\n window.requireShim = ${requireShim};\n\n // Single initial RequireJS configuration with error handling\n window.requirejs.config({\n catchError: true,\n waitSeconds: 30,\n paths: window.requirePaths,\n baseUrl: '${iframeBaseUrl}',\n shim: window.requireShim,\n onNodeCreated: function (node, config, moduleName, url) {\n // Add error handler to script node\n node.addEventListener('error', function (evt) {\n console.error('Script load error for module:', moduleName, 'URL:', url, 'Event:', evt);\n });\n },\n onError: function (err) {\n console.error('RequireJS error:', {\n type: err.requireType,\n modules: err.requireModules,\n error: err\n });\n\n if (err.requireType === 'scripterror') {\n console.error('Script error usually indicates a network or CORS issue with:', err.requireModules);\n }\n\n // Notify parent window about the error\n window.parent.postMessage(\n {\n source: 'qti-pci-iframe',\n responseIdentifier: (window.PCIManager && window.PCIManager.responseIdentifier) || null,\n method: 'error',\n params: {\n message: 'RequireJS ' + err.requireType + ' error for modules: ' + err.requireModules,\n details: {\n type: err.requireType,\n modules: err.requireModules,\n error: err.toString()\n }\n }\n },\n '*'\n );\n }\n });\n\n // PCI Manager for iframe implementation\n window.PCIManager = {\n pciInstance: null,\n pciConfig: null,\n container: null,\n markupEl: null,\n propertiesEl: null,\n customInteractionTypeIdentifier: null,\n responseIdentifier: null,\n pendingBoundTo: null,\n pendingMarkup: null,\n pendingProperties: null,\n pendingState: null,\n pendingStylesheets: null,\n stylesheetKeys: {},\n interactionChangedViaEvent: false,\n eventBridgeAttached: false,\n lastResponseStr: null,\n hadResponse: false,\n\n initialize: function (config) {\n this.customInteractionTypeIdentifier = config.customInteractionTypeIdentifier;\n this.responseIdentifier = config.responseIdentifier;\n this.container = document.getElementById('pci-container');\n this.container.classList.add('qti-customInteraction');\n\n function qtiVariableHasValue(qtiVar) {\n if (!qtiVar) return false;\n if (qtiVar.base) {\n for (const k in qtiVar.base) {\n if (!Object.prototype.hasOwnProperty.call(qtiVar.base, k)) continue;\n const v = qtiVar.base[k];\n if (v !== null && v !== undefined && v !== '') return true;\n }\n }\n if (qtiVar.list) {\n for (const k in qtiVar.list) {\n if (!Object.prototype.hasOwnProperty.call(qtiVar.list, k)) continue;\n const v = qtiVar.list[k];\n if (Array.isArray(v) && v.some(x => x !== null && x !== undefined && x !== '')) return true;\n }\n }\n if (Array.isArray(qtiVar.record) && qtiVar.record.length > 0) return true;\n return false;\n }\n\n const initialBoundTo = config.boundTo && config.boundTo[this.responseIdentifier];\n this.hadResponse = qtiVariableHasValue(initialBoundTo);\n this.lastResponseStr = this.hadResponse ? JSON.stringify(initialBoundTo) : null;\n // Ensure expected DOM structure exists (markup + properties)\n this.markupEl = this.container.querySelector('qti-interaction-markup');\n if (!this.markupEl) {\n this.markupEl = document.createElement('qti-interaction-markup');\n this.container.appendChild(this.markupEl);\n }\n this.markupEl.classList.add('qti-customInteraction');\n this.propertiesEl = this.container.querySelector('properties');\n if (!this.propertiesEl) {\n this.propertiesEl = document.createElement('properties');\n this.propertiesEl.style.display = 'none';\n this.container.appendChild(this.propertiesEl);\n } else {\n this.propertiesEl.style.display = 'none';\n }\n\n // Apply any markup/properties that arrived before initialization\n if (this.pendingMarkup !== null) {\n this.setMarkup(this.pendingMarkup);\n this.pendingMarkup = null;\n }\n if (this.pendingProperties !== null) {\n this.setProperties(this.pendingProperties);\n this.pendingProperties = null;\n }\n if (this.pendingStylesheets !== null) {\n this.setStylesheets(this.pendingStylesheets);\n this.pendingStylesheets = null;\n }\n\n // Bridge qti-interaction-changed events (preferred over polling)\n if (!this.eventBridgeAttached) {\n this.eventBridgeAttached = true;\n const self = this;\n this.container.addEventListener(\n 'qti-interaction-changed',\n function (evt) {\n try {\n self.interactionChangedViaEvent = true;\n const value = evt && evt.detail ? evt.detail.value : undefined;\n if (value !== undefined) {\n const validFromEvent =\n evt && evt.detail && typeof evt.detail.valid === 'boolean' ? evt.detail.valid : undefined;\n let valid = validFromEvent;\n if (valid === undefined && self.pciInstance && typeof self.pciInstance.checkValidity === 'function') {\n try {\n valid = self.pciInstance.checkValidity();\n } catch (e) {\n // Keep undefined on PCI validity read errors.\n }\n }\n const customValidityFromEvent =\n evt && evt.detail && typeof evt.detail.customValidity === 'string'\n ? evt.detail.customValidity\n : undefined;\n let customValidity = customValidityFromEvent;\n if (\n customValidity === undefined &&\n self.pciInstance &&\n typeof self.pciInstance.getCustomValidity === 'function'\n ) {\n try {\n customValidity = self.pciInstance.getCustomValidity();\n } catch (e) {\n // Keep undefined on PCI custom validity read errors.\n }\n }\n const state =\n self.pciInstance && typeof self.pciInstance.getState === 'function'\n ? self.pciInstance.getState()\n : null;\n self.notifyInteractionChanged(value, state, valid, customValidity);\n }\n } catch (e) {\n // ignore bridge errors, polling fallback may still work\n }\n },\n true\n );\n }\n\n function getResolvablePath(path, basePath) {\n if (Array.isArray(path)) {\n return path.map(p => getResolvablePathString(p, basePath));\n } else {\n return getResolvablePathString(path, basePath);\n }\n }\n\n function removeDoubleSlashes(str) {\n return str\n .replace(/([^:\\\\/])\\\\/\\\\/+/g, '$1/')\n .replace(/\\\\/\\\\//g, '/')\n .replace('http:/', 'http://')\n .replace('https:/', 'https://');\n }\n\n function ensureDirectoryBasePath(basePath) {\n if (!basePath) return basePath;\n if (basePath.endsWith('/')) return basePath;\n return basePath + '/';\n }\n\n\n\n function combineRequireResolvePaths(path1, path2, baseUrl) {\n path1 = getResolvablePath(path1, baseUrl);\n const path1Array = Array.isArray(path1) ? path1 : [path1];\n if (!path2) {\n return path1Array;\n }\n path2 = getResolvablePath(path2, baseUrl);\n const path2Array = Array.isArray(path2) ? path2 : [path2];\n return path1Array.concat(path2Array).filter((value, index, self) => self.indexOf(value) === index);\n }\n\n // Update paths with modules from the config\n if (config.interactionModules && config.interactionModules.length > 0) {\n config.interactionModules.forEach(module => {\n if (module.id && module.primaryPath) {\n const currentPath = window.requirePaths[module.id] || [];\n const currentPaths = Array.isArray(currentPath) ? currentPath : [currentPath];\n const newPath = combineRequireResolvePaths(\n module.primaryPath,\n module.fallbackPath,\n config.baseUrl\n );\n window.requirePaths[module.id] = newPath.concat(currentPaths)\n .filter((value, index, self) => self.indexOf(value) === index);\n }\n });\n }\n\n // The ONLY other requirejs.config call - with the context for this specific PCI\n window.requirejs.config({\n context: this.customInteractionTypeIdentifier,\n paths: window.requirePaths,\n shim: window.requireShim\n });\n\n // Define qtiCustomInteractionContext for the PCI\n define('qtiCustomInteractionContext', () => {\n return {\n register: pciInstance => {\n this.pciInstance = pciInstance;\n // Configure PCI instance\n const pciConfig = {\n properties: config.properties || {},\n contextVariables: config.contextVariables || {},\n templateVariables: config.templateVariables || {},\n onready: pciInstance => {\n this.pciInstance = pciInstance;\n // Apply any pending updates that arrived before onready\n if (this.pendingBoundTo) {\n this.applyBoundTo(this.pendingBoundTo);\n this.pendingBoundTo = null;\n }\n if (this.pendingState && typeof this.pciInstance.setState === 'function') {\n this.pciInstance.setState(this.pendingState);\n this.pendingState = null;\n }\n this.notifyReady();\n },\n ondone: (pciInstance, response, state, status) => {\n const valid =\n this.pciInstance && typeof this.pciInstance.checkValidity === 'function'\n ? this.pciInstance.checkValidity()\n : undefined;\n const customValidity =\n this.pciInstance && typeof this.pciInstance.getCustomValidity === 'function'\n ? this.pciInstance.getCustomValidity()\n : undefined;\n this.notifyInteractionChanged(\n response,\n typeof state === 'string' ? state : null,\n valid,\n customValidity\n );\n },\n responseIdentifier: config.responseIdentifier,\n boundTo: config.boundTo,\n responseDeclaration: config.responseDeclaration || undefined,\n status: config.status || 'interacting'\n };\n\n if (pciInstance.getInstance) {\n const dom = this.markupEl || this.container;\n // Round-trip support for object states (stored as a prefixed JSON string by the host).\n // For strict string-based PCIs we pass the original string through unchanged.\n let restoredState = config.state;\n if (typeof restoredState === 'string' && restoredState.indexOf('__qti_json__::') === 0) {\n try {\n restoredState = JSON.parse(restoredState.substring('__qti_json__::'.length));\n } catch (e) {\n // If parsing fails, fall back to the raw string.\n restoredState = config.state;\n }\n }\n // Keep the configuration around next to the instance, it carries the\n // status and response declaration this PCI was constructed with.\n this.pciConfig = pciConfig;\n pciInstance.getInstance(dom, pciConfig, restoredState || undefined);\n } else {\n this.notifyError('Loaded PCI module has no getInstance().');\n }\n },\n notifyReady: () => {\n PCIManager.notifyReady();\n }\n };\n });\n\n function getResolvablePathString(path, basePath) {\n path = path.replace(/\\\\.js$/, '');\n if (/^[a-z][a-z0-9+.-]*:/i.test(path) || !basePath) {\n return path;\n }\n\n if (path.startsWith('/') && !path.startsWith('//')) {\n path = path.slice(1);\n }\n\n try {\n const resolved = new URL(path, ensureDirectoryBasePath(basePath)).toString();\n return resolved.replace(/\\\\.js$/, '');\n } catch (error) {\n return removeDoubleSlashes(ensureDirectoryBasePath(basePath) + path);\n }\n }\n\n // Load the PCI module\n this.loadModule(config.module);\n },\n\n loadModule: function (modulePath) {\n try {\n // Get the context-specific require\n const contextRequire = window.requirejs.config({\n context: this.customInteractionTypeIdentifier\n });\n contextRequire(['require'], require => {\n // Now load the actual module\n require([modulePath], () => {}, err => {\n console.error('Error loading module:', modulePath, err);\n this.notifyError('Module load error: ' + err.toString());\n });\n });\n } catch (error) {\n console.error('Exception in loadModule:', modulePath);\n console.error(error);\n this.notifyError('Error in require call: ' + error.toString());\n }\n },\n\n notifyReady: function () {\n window.parent.postMessage(\n {\n source: 'qti-pci-iframe',\n responseIdentifier: this.responseIdentifier,\n method: 'iframeReady'\n },\n '*'\n );\n },\n\n notifyInteractionChanged: function (response, state, valid, customValidity) {\n window.parent.postMessage(\n {\n source: 'qti-pci-iframe',\n responseIdentifier: this.responseIdentifier,\n method: 'interactionChanged',\n params: {\n value: response,\n state: state,\n valid: typeof valid === 'boolean' ? valid : undefined,\n customValidity: typeof customValidity === 'string' ? customValidity : undefined\n }\n },\n '*'\n );\n },\n\n notifyError: function (message) {\n console.error('PCI Error:', message);\n window.parent.postMessage(\n {\n source: 'qti-pci-iframe',\n responseIdentifier: this.responseIdentifier,\n method: 'error',\n params: { message: message }\n },\n '*'\n );\n },\n\n setMarkup: function (markupHtml) {\n if (!this.container) {\n this.container = document.getElementById('pci-container');\n }\n if (!this.container) {\n this.pendingMarkup = markupHtml;\n return;\n }\n this.markupEl = this.container.querySelector('qti-interaction-markup');\n if (!this.markupEl) {\n this.markupEl = document.createElement('qti-interaction-markup');\n this.container.appendChild(this.markupEl);\n }\n this.markupEl.classList.add('qti-customInteraction');\n this.markupEl.innerHTML = markupHtml || '';\n },\n\n setProperties: function (propertiesHtml) {\n if (!this.container) {\n this.container = document.getElementById('pci-container');\n }\n if (!this.container) {\n this.pendingProperties = propertiesHtml;\n return;\n }\n this.propertiesEl = this.container.querySelector('properties');\n if (!this.propertiesEl) {\n this.propertiesEl = document.createElement('properties');\n this.container.appendChild(this.propertiesEl);\n }\n this.propertiesEl.style.display = 'none';\n this.propertiesEl.innerHTML = propertiesHtml || '';\n },\n\n minifyCss: function (cssContent) {\n return cssContent\n .replace(/\\\\/\\\\*[\\\\s\\\\S]*?\\\\*\\\\//g, '')\n .replace(/\\\\s+/g, ' ')\n .replace(/\\\\s*([{}:;])\\\\s*/g, '$1')\n .trim();\n },\n\n setStylesheets: function (stylesheetsHtml) {\n if (!stylesheetsHtml) return;\n if (!this.container) {\n this.container = document.getElementById('pci-container');\n }\n const target = this.container || document.body;\n if (!target) return;\n target.insertAdjacentHTML('afterbegin', stylesheetsHtml);\n },\n\n\n applyBoundTo: function (boundTo) {\n if (!this.pciInstance || typeof this.pciInstance.setResponse !== 'function') return;\n const value = boundTo && (boundTo[this.responseIdentifier] || boundTo[Object.keys(boundTo)[0]]);\n if (value) this.pciInstance.setResponse(value);\n }\n };\n\n // Set up message listener for communication with parent\n let expectedParentOrigin = null;\n window.addEventListener('message', function (event) {\n const { data } = event;\n\n // Ensure the message is from our parent\n if (event.source !== window.parent || !data || data.source !== 'qti-portable-custom-interaction') {\n return;\n }\n if (expectedParentOrigin === null) {\n expectedParentOrigin = event.origin;\n } else if (event.origin !== expectedParentOrigin) {\n return;\n }\n\n function deepQuerySelector(root, selector) {\n if (!root) return null;\n try {\n const direct = root.querySelector ? root.querySelector(selector) : null;\n if (direct) return direct;\n } catch (e) {\n // ignore invalid selector for this root\n }\n if (!root.querySelectorAll) return null;\n const nodes = root.querySelectorAll('*');\n for (const node of nodes) {\n if (node && node.shadowRoot) {\n const found = deepQuerySelector(node.shadowRoot, selector);\n if (found) return found;\n }\n }\n return null;\n }\n\n function deepFindElementByExactText(root, text) {\n if (!root || !text) return null;\n if (root.querySelectorAll) {\n const nodes = root.querySelectorAll('*');\n for (const node of nodes) {\n if ((node.textContent || '').trim() === text) return node;\n if (node.shadowRoot) {\n const found = deepFindElementByExactText(node.shadowRoot, text);\n if (found) return found;\n }\n }\n }\n return null;\n }\n\n switch (data.method) {\n case 'initialize':\n PCIManager.initialize(data.params);\n break;\n\n case 'setMarkup':\n PCIManager.setMarkup(data.params);\n break;\n\n case 'setBoundTo':\n if (PCIManager.pciInstance) {\n PCIManager.applyBoundTo(data.params);\n } else {\n PCIManager.pendingBoundTo = data.params;\n }\n break;\n\n case 'setProperties':\n PCIManager.setProperties(data.params);\n break;\n\n case 'setStylesheets':\n PCIManager.setStylesheets(data.params);\n break;\n\n case 'setState':\n if (PCIManager.pciInstance && typeof PCIManager.pciInstance.setState === 'function') {\n PCIManager.pciInstance.setState((data.params && data.params.state) || data.params);\n } else {\n PCIManager.pendingState = (data.params && data.params.state) || data.params;\n }\n break;\n\n case 'getContent': {\n const messageId = data.params && data.params.messageId;\n const collectShadowHtml = root => {\n const parts = [];\n if (!root || !root.querySelectorAll) return parts;\n const nodes = root.querySelectorAll('*');\n for (const node of nodes) {\n if (node && node.shadowRoot) {\n parts.push(node.shadowRoot.innerHTML || '');\n parts.push(...collectShadowHtml(node.shadowRoot));\n }\n }\n return parts;\n };\n const shadowHtml = collectShadowHtml(document).join('\\\\n');\n window.parent.postMessage(\n {\n source: 'qti-pci-iframe',\n responseIdentifier: PCIManager.responseIdentifier,\n method: 'getContentResponse',\n messageId: messageId,\n content: (document.documentElement ? document.documentElement.outerHTML : '') + '\\\\n' + shadowHtml\n },\n '*'\n );\n break;\n }\n\n case 'simulateClick': {\n const messageId = data.params && data.params.messageId;\n const x = data.params && data.params.x;\n const y = data.params && data.params.y;\n const el = typeof x === 'number' && typeof y === 'number' ? document.elementFromPoint(x, y) : null;\n const target = (el && el.closest && el.closest('.hitbox')) || document.querySelector('.hitbox') || el;\n if (target) {\n const evt = new MouseEvent('click', {\n bubbles: true,\n clientX: x,\n clientY: y,\n screenX: x,\n screenY: y,\n view: window\n });\n target.dispatchEvent(evt);\n }\n window.parent.postMessage(\n {\n source: 'qti-pci-iframe',\n responseIdentifier: PCIManager.responseIdentifier,\n method: 'clickResponse',\n messageId: messageId\n },\n '*'\n );\n break;\n }\n\n case 'getBoundingRect': {\n const messageId = data.params && data.params.messageId;\n const selector = data.params && data.params.selector;\n const el = selector ? deepQuerySelector(document, selector) : null;\n const rect = el && typeof el.getBoundingClientRect === 'function' ? el.getBoundingClientRect() : null;\n window.parent.postMessage(\n {\n source: 'qti-pci-iframe',\n responseIdentifier: PCIManager.responseIdentifier,\n method: 'getBoundingRectResponse',\n messageId: messageId,\n rect: rect\n ? {\n left: rect.left,\n top: rect.top,\n width: rect.width,\n height: rect.height\n }\n : null\n },\n '*'\n );\n break;\n }\n\n case 'clickOnSelector': {\n const messageId = data.params && data.params.messageId;\n const selector = data.params && data.params.selector;\n const el = selector ? deepQuerySelector(document, selector) : null;\n const success = !!el;\n if (el && typeof el.click === 'function') el.click();\n window.parent.postMessage(\n {\n source: 'qti-pci-iframe',\n responseIdentifier: PCIManager.responseIdentifier,\n method: 'clickSelectorResponse',\n messageId: messageId,\n success: success\n },\n '*'\n );\n break;\n }\n\n case 'clickOnElementByText': {\n const messageId = data.params && data.params.messageId;\n const text = data.params && data.params.text;\n const target = text ? deepFindElementByExactText(document, text) : null;\n const success = !!target;\n if (target && typeof target.click === 'function') target.click();\n window.parent.postMessage(\n {\n source: 'qti-pci-iframe',\n responseIdentifier: PCIManager.responseIdentifier,\n method: 'clickTextResponse',\n messageId: messageId,\n success: success\n },\n '*'\n );\n break;\n }\n\n case 'setValueElement': {\n const messageId = data.params && data.params.messageId;\n const selector = data.params && data.params.selector;\n const value = data.params && data.params.value;\n const el = selector ? deepQuerySelector(document, selector) : null;\n let success = false;\n if (el && 'value' in el) {\n try {\n el.value = value;\n el.dispatchEvent(new Event('input', { bubbles: true }));\n el.dispatchEvent(new Event('change', { bubbles: true }));\n success = true;\n } catch (e) {\n success = false;\n }\n }\n window.parent.postMessage(\n {\n source: 'qti-pci-iframe',\n responseIdentifier: PCIManager.responseIdentifier,\n method: 'setValueResponse',\n messageId: messageId,\n success: success\n },\n '*'\n );\n break;\n }\n\n case 'console':\n window.parent.postMessage(\n {\n source: 'qti-pci-iframe',\n responseIdentifier: PCIManager.responseIdentifier,\n method: 'console',\n level: data.level,\n args: data.args\n },\n '*'\n );\n break;\n }\n });\n\n let resizeTimeout;\n let previousHeight = 0;\n const notifyResize = () => {\n const container = document.getElementById('pci-container');\n // The content's own height (subpixel, rounded up) or what overflows it, e.g. an open popup.\n const newHeight = Math.max(Math.ceil(container.getBoundingClientRect().height), container.scrollHeight);\n if (newHeight !== previousHeight) {\n previousHeight = newHeight;\n clearTimeout(resizeTimeout);\n resizeTimeout = setTimeout(() => {\n window.parent.postMessage(\n {\n source: 'qti-pci-iframe',\n responseIdentifier: PCIManager.responseIdentifier,\n method: 'resize',\n height: newHeight,\n width: container.scrollWidth\n },\n '*'\n );\n }, 100); // Adjust debounce time as needed\n }\n };\n\n function setupResizeObserver() {\n const container = document.getElementById('pci-container');\n if (!container || !(container instanceof Element)) {\n console.warn('ResizeObserver: document.container is not an Element');\n return;\n }\n\n const resizeObserver = new ResizeObserver(() => {\n notifyResize();\n });\n\n resizeObserver.observe(container);\n }\n\n // Run setup once DOM is ready\n if (document.readyState === 'loading') {\n document.addEventListener('DOMContentLoaded', () => {\n notifyResize(); // initial resize\n setupResizeObserver();\n });\n } else {\n notifyResize();\n setupResizeObserver();\n }\n\n window.addEventListener('load', () => {\n notifyResize();\n });\n let lastResponseStr = '';\n setInterval(() => {\n if (PCIManager.interactionChangedViaEvent) return;\n if (PCIManager.pciInstance && PCIManager.pciInstance.getResponse) {\n const response = PCIManager.pciInstance.getResponse();\n const valid =\n PCIManager.pciInstance && typeof PCIManager.pciInstance.checkValidity === 'function'\n ? PCIManager.pciInstance.checkValidity()\n : undefined;\n const customValidity =\n PCIManager.pciInstance && typeof PCIManager.pciInstance.getCustomValidity === 'function'\n ? PCIManager.pciInstance.getCustomValidity()\n : undefined;\n if (response === undefined) {\n // Don't emit an initial empty on load; only emit a clear if we previously had a value\n if (!PCIManager.hadResponse) return;\n PCIManager.hadResponse = false;\n PCIManager.lastResponseStr = null;\n const state =\n PCIManager.pciInstance && typeof PCIManager.pciInstance.getState === 'function'\n ? PCIManager.pciInstance.getState()\n : null;\n window.parent.postMessage(\n {\n source: 'qti-pci-iframe',\n responseIdentifier: PCIManager.responseIdentifier,\n method: 'interactionChanged',\n params: { value: null, state: state, valid: valid, customValidity: customValidity }\n },\n '*'\n );\n return;\n }\n\n const responseStr = JSON.stringify(response);\n\n if (responseStr !== PCIManager.lastResponseStr) {\n PCIManager.lastResponseStr = responseStr;\n PCIManager.hadResponse = true;\n const state =\n PCIManager.pciInstance && typeof PCIManager.pciInstance.getState === 'function'\n ? PCIManager.pciInstance.getState()\n : null;\n window.parent.postMessage(\n {\n source: 'qti-pci-iframe',\n responseIdentifier: PCIManager.responseIdentifier,\n method: 'interactionChanged',\n params: { value: response, state: state, valid: valid, customValidity: customValidity }\n },\n '*'\n );\n }\n }\n }, 500); // Check every 500ms\n </script>\n </head>\n <body>\n <div id=\"pci-container\"></div>\n </body>\n </html>`;\n }\n\n /**\n * Method to disable the PCI for review mode\n * This can be used when showing the correct response\n */\n public disable() {\n // First, store the current state of the PCI\n this.#previousState = {\n pointerEvents: this.style.pointerEvents,\n position: this.style.position\n };\n\n this.sendMessageToIframe('setState', { state: 'disabled' });\n\n // Add an overlay to prevent interaction if not already there\n const existingOverlay = this.querySelector('.pci-interaction-overlay');\n if (!existingOverlay) {\n const overlay = document.createElement('div');\n overlay.className = 'pci-interaction-overlay';\n overlay.style.position = 'absolute';\n overlay.style.top = '0';\n overlay.style.left = '0';\n overlay.style.width = '100%';\n overlay.style.height = '100%';\n overlay.style.backgroundColor = 'rgba(200, 200, 200, 0.3)';\n overlay.style.zIndex = '100';\n overlay.style.pointerEvents = 'all';\n overlay.style.cursor = 'not-allowed';\n\n // Make sure the container is relatively positioned\n if (getComputedStyle(this).position === 'static') {\n this.style.position = 'relative';\n }\n\n this.appendChild(overlay);\n }\n }\n\n /**\n * Method to enable the PCI for interactive mode\n */\n public enable() {\n // Remove any overlays\n const overlay = this.querySelector('.pci-interaction-overlay');\n if (overlay) {\n overlay.remove();\n }\n\n // Restore previous state if available\n if (this.#previousState) {\n if (this.#previousState.pointerEvents) {\n this.style.pointerEvents = this.#previousState.pointerEvents;\n }\n if (this.#previousState.position) {\n this.style.position = this.#previousState.position;\n }\n this.#previousState = null;\n }\n\n this.sendMessageToIframe('setState', { state: 'interacting' });\n }\n\n // Add this property to store the previous state\n #previousState: {\n pointerEvents?: string;\n position?: string;\n } = null;\n\n override render() {\n return html`\n <slot></slot>\n ${this._errorMessage\n ? html`<div style=\"color:red\">\n <h1>Error</h1>\n ${this._errorMessage}\n </div>`\n : ''}\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'qti-portable-custom-interaction': QtiPortableCustomInteraction;\n }\n}\n"]}
|
package/package.json
CHANGED