@citolab/qti-components 7.0.2 → 7.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/cdn/index.global.js +1 -1
- package/cdn/index.js +314 -212
- package/dist/custom-element-eslint-rules.js +8 -16
- package/dist/custom-elements.json +382 -199
- package/dist/index.d.ts +102 -63
- package/dist/index.js +592 -500
- package/dist/index.js.map +1 -1
- package/dist/item.css +34 -82
- package/dist/loader/index.d.ts +1 -1
- package/dist/loader/index.js +5 -0
- package/dist/loader/index.js.map +1 -1
- package/dist/qti-components-jsx.d.ts +109 -112
- package/dist/qti-simple-choice-CfgBEvdI.d.ts +1143 -0
- package/dist/qti-simple-choice-D0GiMrqD.d.ts +1168 -0
- package/dist/{qti-simple-choice-DG8ImdPz.d.ts → qti-simple-choice-UTrFa_RQ.d.ts} +9 -17
- package/dist/qti-simple-choice-zEsDq3c0.d.ts +1147 -0
- package/dist/transformers/index.d.ts +1 -0
- package/dist/transformers/index.js +5 -0
- package/dist/transformers/index.js.map +1 -1
- package/dist/vscode.css-custom-data.json +1 -37
- package/dist/vscode.html-custom-data.json +36 -21
- package/package.json +7 -4
- package/readme.md +55 -0
- package/README.md +0 -85
package/dist/item.css
CHANGED
|
@@ -2346,20 +2346,6 @@ qti-response-declaration {
|
|
|
2346
2346
|
|
|
2347
2347
|
& qti-gap {
|
|
2348
2348
|
|
|
2349
|
-
&[enabled] {
|
|
2350
|
-
|
|
2351
|
-
/* Light theme override */
|
|
2352
|
-
.qti-selections-light & {
|
|
2353
|
-
border-color: var(--qti-light-border-active);
|
|
2354
|
-
}
|
|
2355
|
-
|
|
2356
|
-
/* Dark theme override */
|
|
2357
|
-
.qti-selections-dark & {
|
|
2358
|
-
border-color: var(--qti-dark-border-active);
|
|
2359
|
-
}
|
|
2360
|
-
background-color: var(--qti-bg-active)
|
|
2361
|
-
}
|
|
2362
|
-
|
|
2363
2349
|
&[disabled] {
|
|
2364
2350
|
|
|
2365
2351
|
&:not(:empty) {
|
|
@@ -2377,6 +2363,20 @@ qti-response-declaration {
|
|
|
2377
2363
|
outline: 4px solid var(--qti-disabled-bg)
|
|
2378
2364
|
}
|
|
2379
2365
|
|
|
2366
|
+
&[enabled] {
|
|
2367
|
+
|
|
2368
|
+
/* Light theme override */
|
|
2369
|
+
.qti-selections-light & {
|
|
2370
|
+
border-color: var(--qti-light-border-active);
|
|
2371
|
+
}
|
|
2372
|
+
|
|
2373
|
+
/* Dark theme override */
|
|
2374
|
+
.qti-selections-dark & {
|
|
2375
|
+
border-color: var(--qti-dark-border-active);
|
|
2376
|
+
}
|
|
2377
|
+
background-color: var(--qti-bg-active)
|
|
2378
|
+
}
|
|
2379
|
+
|
|
2380
2380
|
&[active] {
|
|
2381
2381
|
|
|
2382
2382
|
/* Light theme override */
|
|
@@ -2759,12 +2759,22 @@ qti-response-declaration {
|
|
|
2759
2759
|
}
|
|
2760
2760
|
|
|
2761
2761
|
qti-match-interaction:not(.qti-match-tabular) {
|
|
2762
|
+
&:state(--dragzone-enabled) qti-simple-match-set:first-of-type {
|
|
2763
|
+
background-color: var(--qti-bg-active);
|
|
2764
|
+
}
|
|
2765
|
+
|
|
2766
|
+
&:state(--dragzone-active) qti-simple-match-set:first-of-type {
|
|
2767
|
+
border-color: var(--qti-border-active);
|
|
2768
|
+
background-color: var(--qti-bg-active);
|
|
2769
|
+
}
|
|
2770
|
+
|
|
2762
2771
|
/* The draggables */
|
|
2763
2772
|
& qti-simple-match-set:first-of-type {
|
|
2764
2773
|
display: flex;
|
|
2765
2774
|
flex-wrap: wrap;
|
|
2766
2775
|
align-items: flex-start; /* Prevents children from stretching */
|
|
2767
2776
|
gap: var(--qti-gap-size);
|
|
2777
|
+
border: 2px solid transparent;
|
|
2768
2778
|
|
|
2769
2779
|
& qti-simple-associable-choice {
|
|
2770
2780
|
|
|
@@ -3156,6 +3166,16 @@ qti-response-declaration {
|
|
|
3156
3166
|
}
|
|
3157
3167
|
|
|
3158
3168
|
qti-associate-interaction {
|
|
3169
|
+
/* General styles for active and enabled states */
|
|
3170
|
+
&:state(--dragzone-active) slot[name='qti-simple-associable-choice'] {
|
|
3171
|
+
border-color: var(--qti-border-active);
|
|
3172
|
+
background-color: var(--qti-bg-active);
|
|
3173
|
+
}
|
|
3174
|
+
|
|
3175
|
+
&:state(--dragzone-enabled) slot[name='qti-simple-associable-choice'] {
|
|
3176
|
+
background-color: var(--qti-bg-active);
|
|
3177
|
+
}
|
|
3178
|
+
|
|
3159
3179
|
& qti-simple-associable-choice, /* drags when in lightdom */
|
|
3160
3180
|
&::part(qti-simple-associable-choice) /* drags when in shadowdom */ {
|
|
3161
3181
|
|
|
@@ -3458,76 +3478,8 @@ qti-response-declaration {
|
|
|
3458
3478
|
}
|
|
3459
3479
|
|
|
3460
3480
|
qti-slider-interaction {
|
|
3461
|
-
display: block;
|
|
3462
|
-
|
|
3463
3481
|
--qti-tick-color: rgb(229 231 235 / 100%);
|
|
3464
3482
|
--qti-tick-width: 1px;
|
|
3465
|
-
|
|
3466
|
-
&::part(slider) {
|
|
3467
|
-
margin-left: 2rem; /* mx-8 */
|
|
3468
|
-
margin-right: 2rem;
|
|
3469
|
-
padding-bottom: 1rem; /* pb-4 */
|
|
3470
|
-
padding-top: 1.25rem; /* pt-5 */
|
|
3471
|
-
}
|
|
3472
|
-
|
|
3473
|
-
--show-bounds: true;
|
|
3474
|
-
|
|
3475
|
-
&::part(bounds) {
|
|
3476
|
-
display: flex;
|
|
3477
|
-
width: 100%;
|
|
3478
|
-
justify-content: space-between;
|
|
3479
|
-
margin-bottom: 0.5rem; /* mb-2 */
|
|
3480
|
-
}
|
|
3481
|
-
|
|
3482
|
-
--show-ticks: true;
|
|
3483
|
-
|
|
3484
|
-
&::part(ticks) {
|
|
3485
|
-
margin-left: 0.125rem; /* mx-0.5 */
|
|
3486
|
-
margin-right: 0.125rem;
|
|
3487
|
-
margin-bottom: 0.25rem; /* mb-1 */
|
|
3488
|
-
height: 0.5rem; /* h-2 */
|
|
3489
|
-
background: linear-gradient(to right, var(--qti-tick-color) var(--qti-tick-width), transparent 1px) repeat-x 0
|
|
3490
|
-
center / calc(calc(100% - var(--qti-tick-width)) / ((var(--max) - var(--min)) / var(--step))) 100%;
|
|
3491
|
-
}
|
|
3492
|
-
|
|
3493
|
-
&::part(rail) {
|
|
3494
|
-
display: flex;
|
|
3495
|
-
align-items: center;
|
|
3496
|
-
box-sizing: border-box;
|
|
3497
|
-
height: 0.375rem; /* h-1.5 */
|
|
3498
|
-
width: 100%;
|
|
3499
|
-
cursor: pointer;
|
|
3500
|
-
border-radius: 9999px; /* rounded-full */
|
|
3501
|
-
border: 1px solid #d1d5db; /* border-gray-300 */
|
|
3502
|
-
background-color: #e5e7eb; /* bg-gray-200 */
|
|
3503
|
-
}
|
|
3504
|
-
|
|
3505
|
-
&::part(knob) {
|
|
3506
|
-
background-color: var(--qti-primary);
|
|
3507
|
-
position: relative;
|
|
3508
|
-
height: 1rem; /* h-4 */
|
|
3509
|
-
width: 1rem; /* w-4 */
|
|
3510
|
-
transform-origin: center;
|
|
3511
|
-
transform: translateX(-50%);
|
|
3512
|
-
cursor: pointer;
|
|
3513
|
-
border-radius: 9999px; /* rounded-full */
|
|
3514
|
-
left: var(--value-percentage);
|
|
3515
|
-
}
|
|
3516
|
-
|
|
3517
|
-
--show-value: true;
|
|
3518
|
-
|
|
3519
|
-
&::part(value) {
|
|
3520
|
-
position: absolute;
|
|
3521
|
-
bottom: 2rem; /* bottom-8 */
|
|
3522
|
-
left: 0.5rem; /* left-2 */
|
|
3523
|
-
transform: translateX(-50%);
|
|
3524
|
-
cursor: pointer;
|
|
3525
|
-
border-radius: 0.25rem; /* rounded */
|
|
3526
|
-
background-color: #f3f4f6; /* bg-gray-100 */
|
|
3527
|
-
padding: 0.25rem 0.5rem; /* px-2 py-1 */
|
|
3528
|
-
text-align: center;
|
|
3529
|
-
color: #6b7280; /* text-gray-500 */
|
|
3530
|
-
}
|
|
3531
3483
|
}
|
|
3532
3484
|
|
|
3533
3485
|
qti-select-point-interaction {
|
package/dist/loader/index.d.ts
CHANGED
package/dist/loader/index.js
CHANGED
|
@@ -250,6 +250,7 @@ var qtiTransformTest = () => {
|
|
|
250
250
|
return new Promise((resolve, _) => {
|
|
251
251
|
loadXML(uri).then((xml2) => {
|
|
252
252
|
xmlFragment = xml2;
|
|
253
|
+
api.path(uri.substring(0, uri.lastIndexOf("/")));
|
|
253
254
|
return resolve(api);
|
|
254
255
|
});
|
|
255
256
|
});
|
|
@@ -258,6 +259,10 @@ var qtiTransformTest = () => {
|
|
|
258
259
|
xmlFragment = parseXML(xmlString);
|
|
259
260
|
return api;
|
|
260
261
|
},
|
|
262
|
+
path: (location) => {
|
|
263
|
+
setLocation(xmlFragment, location);
|
|
264
|
+
return api;
|
|
265
|
+
},
|
|
261
266
|
fn(fn) {
|
|
262
267
|
fn(xmlFragment);
|
|
263
268
|
return api;
|
package/dist/loader/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/lib/qti-transformers/qti-transformers.ts","../../src/lib/qti-transformers/qti-transform-item.ts","../../src/lib/qti-transformers/qti-transform-manifest.ts","../../src/lib/qti-transformers/qti-transform-test.ts","../../src/lib/qti-loader/qti-loader.ts"],"sourcesContent":["const xml = String.raw;\n\n/* <!-- convert CDATA to comments -->\n <xsl:template match=\"text()[contains(., 'CDATA')]\">\n <xsl:comment>\n <xsl:value-of select=\".\"/>\n </xsl:comment>\n</xsl:template>\n*/\n\n/*\n <!-- remove xml comments -->\n <xsl:template match=\"comment()\" />\n */\n\nconst xmlToHTML = xml`<xsl:stylesheet version=\"1.0\" xmlns:xsl=\"http://www.w3.org/1999/XSL/Transform\">\n<xsl:output method=\"html\" version=\"5.0\" encoding=\"UTF-8\" indent=\"yes\" />\n <xsl:template match=\"@*|node()\">\n <xsl:copy>\n <xsl:apply-templates select=\"@*|node()\"/>\n </xsl:copy>\n </xsl:template>\n\n <!-- remove existing namespaces -->\n <xsl:template match=\"*\">\n <!-- remove element prefix -->\n <xsl:element name=\"{local-name()}\">\n <!-- process attributes -->\n <xsl:for-each select=\"@*\">\n <!-- remove attribute prefix -->\n <xsl:attribute name=\"{local-name()}\">\n <xsl:value-of select=\".\"/>\n </xsl:attribute>\n </xsl:for-each>\n <xsl:apply-templates/>\n </xsl:element>\n</xsl:template>\n</xsl:stylesheet>`;\n\n// Function to extend elements with a specific tag name by adding an extension suffix\nexport function extendElementName(xmlFragment: XMLDocument, tagName: string, extension: string) {\n xmlFragment.querySelectorAll(tagName).forEach(element => {\n const newTagName = `${tagName}-${extension}`;\n const newElement = createElementWithNewTagName(element, newTagName);\n element.replaceWith(newElement);\n });\n}\n\n// Function to extend any element with a specific class pattern (e.g., \"extend:suffix\")\nexport function extendElementsWithClass(xmlFragment: XMLDocument, classNamePattern: string) {\n xmlFragment.querySelectorAll('*').forEach(element => {\n const classList = element.classList;\n if (classList) {\n classList.forEach(className => {\n if (className.startsWith(`${classNamePattern}:`)) {\n const suffix = className.slice(`${classNamePattern}:`.length);\n const newTagName = `${element.nodeName}-${suffix}`;\n const newElement = createElementWithNewTagName(element, newTagName);\n element.replaceWith(newElement);\n }\n });\n }\n });\n}\n\n// Helper function to create a new element with a new tag name and copy attributes and children\nfunction createElementWithNewTagName(element, newTagName) {\n const newElement = document.createElement(newTagName);\n // Copy attributes\n for (const attr of element.attributes) {\n newElement.setAttribute(attr.name, attr.value);\n }\n // Copy child nodes\n while (element.firstChild) {\n newElement.appendChild(element.firstChild);\n }\n return newElement;\n}\n\nexport function itemsFromTest(xmlFragment: DocumentFragment) {\n const items: { identifier: string; href: string; category: string }[] = [];\n xmlFragment.querySelectorAll('qti-assessment-item-ref').forEach(el => {\n const identifier = el.getAttribute('identifier');\n const href = el.getAttribute('href');\n const category = el.getAttribute('category');\n items.push({ identifier, href, category });\n });\n return items;\n}\n\nlet currentRequest: XMLHttpRequest | null = null;\n\nexport function loadXML(url, cancelPreviousRequest = false) {\n if (cancelPreviousRequest && currentRequest !== null) {\n currentRequest.abort(); // Abort the ongoing request if there is one\n }\n\n return new Promise<XMLDocument | null>((resolve, reject) => {\n const xhr = new XMLHttpRequest();\n currentRequest = xhr; // Store the current request\n\n xhr.open('GET', url, true);\n xhr.responseType = 'document';\n\n xhr.onload = () => {\n if (xhr.status >= 200 && xhr.status < 300) {\n resolve(xhr.responseXML);\n } else {\n reject(xhr.statusText);\n }\n };\n\n xhr.onerror = () => {\n reject(xhr.statusText);\n };\n\n xhr.send();\n });\n}\n\nexport function parseXML(xmlDocument: string) {\n const parser = new DOMParser();\n const xmlFragment = parser.parseFromString(xmlDocument, 'text/xml');\n return xmlFragment;\n}\n\nexport function toHTML(xmlFragment: Document): DocumentFragment {\n const processor = new XSLTProcessor();\n const xsltDocument = new DOMParser().parseFromString(xmlToHTML, 'text/xml');\n processor.importStylesheet(xsltDocument);\n const itemHTMLFragment = processor.transformToFragment(xmlFragment, document);\n return itemHTMLFragment;\n}\n\nexport function setLocation(xmlFragment: DocumentFragment, location: string) {\n if (!location.endsWith('/')) {\n location += '/';\n }\n\n xmlFragment.querySelectorAll('[src],[href],[primary-path]').forEach(elWithSrc => {\n let attr: 'src' | 'href' | 'primary-path' | '' = '';\n\n if (elWithSrc.getAttribute('src')) {\n attr = 'src';\n }\n if (elWithSrc.getAttribute('href')) {\n attr = 'href';\n }\n if (elWithSrc.getAttribute('primary-path')) {\n attr = 'primary-path';\n }\n const attrValue = elWithSrc.getAttribute(attr)?.trim();\n\n if (!attrValue.startsWith('data:') && !attrValue.startsWith('http')) {\n const newSrcValue = location + encodeURI(attrValue);\n elWithSrc.setAttribute(attr, newSrcValue);\n }\n });\n}\n\nexport function convertCDATAtoComment(xmlFragment: DocumentFragment) {\n const cdataElements = xmlFragment.querySelectorAll('qti-custom-operator[class=\"js.org\"] > qti-base-value');\n cdataElements.forEach(element => {\n const commentText = document.createComment(element.textContent);\n element.replaceChild(commentText, element.firstChild);\n });\n}\n\nexport function stripStyleSheets(xmlFragment: DocumentFragment) {\n // remove qti-stylesheet tag\n xmlFragment.querySelectorAll('qti-stylesheet').forEach(stylesheet => stylesheet.remove());\n}\n","/**\n * Browser based QTI-XML to HTML transformer.\n * Returns an object with methods to load, parse, transform and serialize QTI XML items.\n * @returns An object with methods to load, parse, transform and serialize QTI XML items.\n * @example\n * const qtiTransformer = qtiTransformItem();\n * await qtiTransformer.load('path/to/xml/file.xml');\n * qtiTransformer.path('/assessmentItem/itemBody');\n * const html = qtiTransformer.html();\n * const xml = qtiTransformer.xml();\n * const htmldoc = qtiTransformer.htmldoc();\n * const xmldoc = qtiTransformer.xmldoc();\n *\n * qtiTransformItem().parse(storyXML).html()\n */\n\nimport {\n convertCDATAtoComment,\n extendElementName,\n extendElementsWithClass,\n loadXML,\n parseXML,\n setLocation,\n stripStyleSheets,\n toHTML\n} from './qti-transformers';\n\nexport type transformItemApi = {\n load: (uri: string, cancelPreviousRequest?: boolean) => Promise<transformItemApi>;\n parse: (xmlString: string) => transformItemApi;\n path: (location: string) => transformItemApi;\n fn: (fn: (xmlFragment: XMLDocument) => void) => transformItemApi;\n pciHooks: (uri: string) => transformItemApi;\n extendElementName: (elementName: string, extend: string) => transformItemApi;\n extendElementsWithClass: (param?: string) => transformItemApi;\n customInteraction: (baseRef: string, baseItem: string) => transformItemApi;\n convertCDATAtoComment: () => transformItemApi;\n stripStyleSheets: () => transformItemApi;\n html: () => string;\n xml: () => string;\n htmlDoc: () => DocumentFragment;\n xmlDoc: () => XMLDocument;\n};\n\nexport const qtiTransformItem = () => {\n let xmlFragment: XMLDocument;\n\n const api: transformItemApi = {\n async load(uri: string, cancelPreviousRequest = false): Promise<typeof api> {\n return new Promise<typeof api>(resolve => {\n loadXML(uri, cancelPreviousRequest).then(xml => {\n xmlFragment = xml;\n // set the base path for images and other resources,\n // you probably want to set the base path to the document root else you can use the path method to set it\n api.path(uri.substring(0, uri.lastIndexOf('/')));\n return resolve(api);\n });\n });\n },\n parse(xmlString: string): typeof api {\n xmlFragment = parseXML(xmlString);\n return api;\n },\n path: (location: string): typeof api => {\n setLocation(xmlFragment, location);\n return api;\n },\n fn(fn: (xmlFragment: XMLDocument) => void): typeof api {\n fn(xmlFragment);\n return api;\n },\n pciHooks(uri: string): typeof api {\n const attributes = ['hook', 'module'];\n const documentPath = uri.substring(0, uri.lastIndexOf('/'));\n for (const attribute of attributes) {\n const srcAttributes = xmlFragment.querySelectorAll('[' + attribute + ']');\n srcAttributes.forEach(node => {\n const srcValue = node.getAttribute(attribute)!;\n if (!srcValue.startsWith('data:') && !srcValue.startsWith('http')) {\n // Just paste the relative path of the src location after the documentrootPath\n // old pcis can have a .js, new pci's don't\n node.setAttribute('base-url', uri);\n node.setAttribute(\n 'module',\n documentPath + '/' + encodeURI(srcValue + (srcValue.endsWith('.js') ? '' : '.js'))\n );\n }\n });\n }\n return api;\n },\n extendElementName: (tagName: string, extension: string): typeof api => {\n extendElementName(xmlFragment, tagName, extension);\n return api;\n },\n extendElementsWithClass: (param: string = 'extend'): typeof api => {\n extendElementsWithClass(xmlFragment, param);\n return api;\n },\n customInteraction(baseRef: string, baseItem: string): typeof api {\n const qtiCustomInteraction = xmlFragment.querySelector('qti-custom-interaction');\n const qtiCustomInteractionObject = qtiCustomInteraction.querySelector('object');\n\n qtiCustomInteraction.setAttribute('data-base-ref', baseRef);\n qtiCustomInteraction.setAttribute('data-base-item', baseRef + baseItem);\n qtiCustomInteraction.setAttribute('data', qtiCustomInteractionObject.getAttribute('data'));\n qtiCustomInteraction.setAttribute('width', qtiCustomInteractionObject.getAttribute('width'));\n qtiCustomInteraction.setAttribute('height', qtiCustomInteractionObject.getAttribute('height'));\n\n qtiCustomInteraction.removeChild(qtiCustomInteractionObject);\n return api;\n },\n convertCDATAtoComment(): typeof api {\n convertCDATAtoComment(xmlFragment);\n return api;\n },\n stripStyleSheets(): typeof api {\n stripStyleSheets(xmlFragment);\n return api;\n },\n html() {\n return new XMLSerializer().serializeToString(toHTML(xmlFragment));\n },\n xml(): string {\n return new XMLSerializer().serializeToString(xmlFragment);\n },\n htmlDoc() {\n return toHTML(xmlFragment);\n },\n xmlDoc(): XMLDocument {\n return xmlFragment; // new XMLSerializer().serializeToString(xmlFragment);\n }\n };\n return api;\n};\n","import { loadXML, parseXML } from './qti-transformers';\n\nexport const qtiTransformManifest = (): {\n load: (uri: string) => Promise<typeof api>;\n assessmentTest: () => { href: string; identifier: string };\n} => {\n let xmlFragment: XMLDocument;\n\n const api = {\n async load(uri) {\n return new Promise<typeof api>(resolve => {\n loadXML(uri).then(xml => {\n xmlFragment = xml;\n return resolve(api);\n });\n });\n },\n parse(xmlString: string) {\n xmlFragment = parseXML(xmlString);\n },\n assessmentTest() {\n const el = xmlFragment.querySelector('resource[type=\"imsqti_test_xmlv3p0\"]');\n return { href: el.getAttribute('href'), identifier: el.getAttribute('identifier') };\n }\n };\n return api;\n};\n","/**\n * Returns an object with methods to load, parse and transform QTI tests.\n * @returns An object with methods to load, parse and transform QTI tests.\n * @example\n * const qtiTransformer = qtiTransformTest();\n * await qtiTransformer.load('https://example.com/test.xml');\n * const items = qtiTransformer.items();\n * const html = qtiTransformer.html();\n * const xml = qtiTransformer.xml();\n */\n\nimport { itemsFromTest, loadXML, parseXML, toHTML } from './qti-transformers';\n\nexport type transformTestApi = {\n load: (uri: string) => Promise<transformTestApi>;\n parse: (xmlString: string) => transformTestApi;\n fn: (fn: (xmlFragment: XMLDocument) => void) => transformTestApi;\n items: () => { identifier: string; href: string; category: string }[];\n html: () => string;\n xml: () => string;\n htmlDoc: () => DocumentFragment;\n xmlDoc: () => XMLDocument;\n};\n\nexport const qtiTransformTest = (): transformTestApi => {\n let xmlFragment: XMLDocument;\n\n const api: transformTestApi = {\n async load(uri) {\n return new Promise<transformTestApi>((resolve, _) => {\n loadXML(uri).then(xml => {\n xmlFragment = xml;\n return resolve(api);\n });\n });\n },\n parse(xmlString: string) {\n xmlFragment = parseXML(xmlString);\n return api;\n },\n fn(fn: (xmlFragment: XMLDocument) => void) {\n fn(xmlFragment);\n return api;\n },\n items() {\n return itemsFromTest(xmlFragment);\n },\n html() {\n return new XMLSerializer().serializeToString(toHTML(xmlFragment));\n },\n xml(): string {\n return new XMLSerializer().serializeToString(xmlFragment);\n },\n htmlDoc() {\n return toHTML(xmlFragment);\n },\n xmlDoc(): XMLDocument {\n return xmlFragment;\n }\n };\n return api;\n};\n","import { QtiAssessmentItem } from '../qti-components';\nimport { qtiTransformItem, qtiTransformTest } from '../qti-transformers';\nimport { qtiTransformManifest } from '../qti-transformers/qti-transform-manifest';\n\nexport type ManifestInfo = {\n testIdentifier: string;\n testHTMLDoc: DocumentFragment;\n testURI: string;\n testURL: string;\n items: {\n identifier: string;\n href: string;\n category: string;\n }[];\n};\n\n// Utility function to ensure package URIs end with a '/'\n// const normalizeUri = (uri: string) => (uri.endsWith('/') ? uri : `${uri}/`);\n\n// Fetches assessment data from the manifest\nexport const getManifestInfo = async (manifestURL: string): Promise<ManifestInfo> => {\n const baseURI = manifestURL.substring(0, manifestURL.lastIndexOf('/'));\n\n const test = await qtiTransformManifest()\n .load(`${manifestURL}`)\n .then(api => api.assessmentTest());\n\n const testHTMLDoc = await qtiTransformTest()\n .load(`${baseURI}/${test.href}`)\n .then(api => api.htmlDoc());\n\n const items = await qtiTransformTest()\n .load(`${baseURI}/${test.href}`)\n .then(api => api.items());\n\n const testURL = `${baseURI}/${test.href}`;\n const testURI = `${baseURI}/${test.href.substring(0, test.href.lastIndexOf('/'))}`;\n\n return {\n testHTMLDoc,\n testURI,\n testURL,\n items,\n testIdentifier: test.identifier\n };\n};\n\n// Fetches a single item by URI\nexport const getItemByUri = async (itemUri: string): Promise<QtiAssessmentItem> =>\n qtiTransformItem()\n .load(itemUri)\n .then(api => api.htmlDoc().firstElementChild as QtiAssessmentItem);\n"],"mappings":"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","names":["xml","xml","xml"]}
|
|
1
|
+
{"version":3,"sources":["../../src/lib/qti-transformers/qti-transformers.ts","../../src/lib/qti-transformers/qti-transform-item.ts","../../src/lib/qti-transformers/qti-transform-manifest.ts","../../src/lib/qti-transformers/qti-transform-test.ts","../../src/lib/qti-loader/qti-loader.ts"],"sourcesContent":["const xml = String.raw;\n\n/* <!-- convert CDATA to comments -->\n <xsl:template match=\"text()[contains(., 'CDATA')]\">\n <xsl:comment>\n <xsl:value-of select=\".\"/>\n </xsl:comment>\n</xsl:template>\n*/\n\n/*\n <!-- remove xml comments -->\n <xsl:template match=\"comment()\" />\n */\n\nconst xmlToHTML = xml`<xsl:stylesheet version=\"1.0\" xmlns:xsl=\"http://www.w3.org/1999/XSL/Transform\">\n<xsl:output method=\"html\" version=\"5.0\" encoding=\"UTF-8\" indent=\"yes\" />\n <xsl:template match=\"@*|node()\">\n <xsl:copy>\n <xsl:apply-templates select=\"@*|node()\"/>\n </xsl:copy>\n </xsl:template>\n\n <!-- remove existing namespaces -->\n <xsl:template match=\"*\">\n <!-- remove element prefix -->\n <xsl:element name=\"{local-name()}\">\n <!-- process attributes -->\n <xsl:for-each select=\"@*\">\n <!-- remove attribute prefix -->\n <xsl:attribute name=\"{local-name()}\">\n <xsl:value-of select=\".\"/>\n </xsl:attribute>\n </xsl:for-each>\n <xsl:apply-templates/>\n </xsl:element>\n</xsl:template>\n</xsl:stylesheet>`;\n\n// Function to extend elements with a specific tag name by adding an extension suffix\nexport function extendElementName(xmlFragment: XMLDocument, tagName: string, extension: string) {\n xmlFragment.querySelectorAll(tagName).forEach(element => {\n const newTagName = `${tagName}-${extension}`;\n const newElement = createElementWithNewTagName(element, newTagName);\n element.replaceWith(newElement);\n });\n}\n\n// Function to extend any element with a specific class pattern (e.g., \"extend:suffix\")\nexport function extendElementsWithClass(xmlFragment: XMLDocument, classNamePattern: string) {\n xmlFragment.querySelectorAll('*').forEach(element => {\n const classList = element.classList;\n if (classList) {\n classList.forEach(className => {\n if (className.startsWith(`${classNamePattern}:`)) {\n const suffix = className.slice(`${classNamePattern}:`.length);\n const newTagName = `${element.nodeName}-${suffix}`;\n const newElement = createElementWithNewTagName(element, newTagName);\n element.replaceWith(newElement);\n }\n });\n }\n });\n}\n\n// Helper function to create a new element with a new tag name and copy attributes and children\nfunction createElementWithNewTagName(element, newTagName) {\n const newElement = document.createElement(newTagName);\n // Copy attributes\n for (const attr of element.attributes) {\n newElement.setAttribute(attr.name, attr.value);\n }\n // Copy child nodes\n while (element.firstChild) {\n newElement.appendChild(element.firstChild);\n }\n return newElement;\n}\n\nexport function itemsFromTest(xmlFragment: DocumentFragment) {\n const items: { identifier: string; href: string; category: string }[] = [];\n xmlFragment.querySelectorAll('qti-assessment-item-ref').forEach(el => {\n const identifier = el.getAttribute('identifier');\n const href = el.getAttribute('href');\n const category = el.getAttribute('category');\n items.push({ identifier, href, category });\n });\n return items;\n}\n\nlet currentRequest: XMLHttpRequest | null = null;\n\nexport function loadXML(url, cancelPreviousRequest = false) {\n if (cancelPreviousRequest && currentRequest !== null) {\n currentRequest.abort(); // Abort the ongoing request if there is one\n }\n\n return new Promise<XMLDocument | null>((resolve, reject) => {\n const xhr = new XMLHttpRequest();\n currentRequest = xhr; // Store the current request\n\n xhr.open('GET', url, true);\n xhr.responseType = 'document';\n\n xhr.onload = () => {\n if (xhr.status >= 200 && xhr.status < 300) {\n resolve(xhr.responseXML);\n } else {\n reject(xhr.statusText);\n }\n };\n\n xhr.onerror = () => {\n reject(xhr.statusText);\n };\n\n xhr.send();\n });\n}\n\nexport function parseXML(xmlDocument: string) {\n const parser = new DOMParser();\n const xmlFragment = parser.parseFromString(xmlDocument, 'text/xml');\n return xmlFragment;\n}\n\nexport function toHTML(xmlFragment: Document): DocumentFragment {\n const processor = new XSLTProcessor();\n const xsltDocument = new DOMParser().parseFromString(xmlToHTML, 'text/xml');\n processor.importStylesheet(xsltDocument);\n const itemHTMLFragment = processor.transformToFragment(xmlFragment, document);\n return itemHTMLFragment;\n}\n\nexport function setLocation(xmlFragment: DocumentFragment, location: string) {\n if (!location.endsWith('/')) {\n location += '/';\n }\n\n xmlFragment.querySelectorAll('[src],[href],[primary-path]').forEach(elWithSrc => {\n let attr: 'src' | 'href' | 'primary-path' | '' = '';\n\n if (elWithSrc.getAttribute('src')) {\n attr = 'src';\n }\n if (elWithSrc.getAttribute('href')) {\n attr = 'href';\n }\n if (elWithSrc.getAttribute('primary-path')) {\n attr = 'primary-path';\n }\n const attrValue = elWithSrc.getAttribute(attr)?.trim();\n\n if (!attrValue.startsWith('data:') && !attrValue.startsWith('http')) {\n const newSrcValue = location + encodeURI(attrValue);\n elWithSrc.setAttribute(attr, newSrcValue);\n }\n });\n}\n\nexport function convertCDATAtoComment(xmlFragment: DocumentFragment) {\n const cdataElements = xmlFragment.querySelectorAll('qti-custom-operator[class=\"js.org\"] > qti-base-value');\n cdataElements.forEach(element => {\n const commentText = document.createComment(element.textContent);\n element.replaceChild(commentText, element.firstChild);\n });\n}\n\nexport function stripStyleSheets(xmlFragment: DocumentFragment) {\n // remove qti-stylesheet tag\n xmlFragment.querySelectorAll('qti-stylesheet').forEach(stylesheet => stylesheet.remove());\n}\n","/**\n * Browser based QTI-XML to HTML transformer.\n * Returns an object with methods to load, parse, transform and serialize QTI XML items.\n * @returns An object with methods to load, parse, transform and serialize QTI XML items.\n * @example\n * const qtiTransformer = qtiTransformItem();\n * await qtiTransformer.load('path/to/xml/file.xml');\n * qtiTransformer.path('/assessmentItem/itemBody');\n * const html = qtiTransformer.html();\n * const xml = qtiTransformer.xml();\n * const htmldoc = qtiTransformer.htmldoc();\n * const xmldoc = qtiTransformer.xmldoc();\n *\n * qtiTransformItem().parse(storyXML).html()\n */\n\nimport {\n convertCDATAtoComment,\n extendElementName,\n extendElementsWithClass,\n loadXML,\n parseXML,\n setLocation,\n stripStyleSheets,\n toHTML\n} from './qti-transformers';\n\nexport type transformItemApi = {\n load: (uri: string, cancelPreviousRequest?: boolean) => Promise<transformItemApi>;\n parse: (xmlString: string) => transformItemApi;\n path: (location: string) => transformItemApi;\n fn: (fn: (xmlFragment: XMLDocument) => void) => transformItemApi;\n pciHooks: (uri: string) => transformItemApi;\n extendElementName: (elementName: string, extend: string) => transformItemApi;\n extendElementsWithClass: (param?: string) => transformItemApi;\n customInteraction: (baseRef: string, baseItem: string) => transformItemApi;\n convertCDATAtoComment: () => transformItemApi;\n stripStyleSheets: () => transformItemApi;\n html: () => string;\n xml: () => string;\n htmlDoc: () => DocumentFragment;\n xmlDoc: () => XMLDocument;\n};\n\nexport const qtiTransformItem = () => {\n let xmlFragment: XMLDocument;\n\n const api: transformItemApi = {\n async load(uri: string, cancelPreviousRequest = false): Promise<typeof api> {\n return new Promise<typeof api>(resolve => {\n loadXML(uri, cancelPreviousRequest).then(xml => {\n xmlFragment = xml;\n // set the base path for images and other resources,\n // you probably want to set the base path to the document root else you can use the path method to set it\n api.path(uri.substring(0, uri.lastIndexOf('/')));\n return resolve(api);\n });\n });\n },\n parse(xmlString: string): typeof api {\n xmlFragment = parseXML(xmlString);\n return api;\n },\n path: (location: string): typeof api => {\n setLocation(xmlFragment, location);\n return api;\n },\n fn(fn: (xmlFragment: XMLDocument) => void): typeof api {\n fn(xmlFragment);\n return api;\n },\n pciHooks(uri: string): typeof api {\n const attributes = ['hook', 'module'];\n const documentPath = uri.substring(0, uri.lastIndexOf('/'));\n for (const attribute of attributes) {\n const srcAttributes = xmlFragment.querySelectorAll('[' + attribute + ']');\n srcAttributes.forEach(node => {\n const srcValue = node.getAttribute(attribute)!;\n if (!srcValue.startsWith('data:') && !srcValue.startsWith('http')) {\n // Just paste the relative path of the src location after the documentrootPath\n // old pcis can have a .js, new pci's don't\n node.setAttribute('base-url', uri);\n node.setAttribute(\n 'module',\n documentPath + '/' + encodeURI(srcValue + (srcValue.endsWith('.js') ? '' : '.js'))\n );\n }\n });\n }\n return api;\n },\n extendElementName: (tagName: string, extension: string): typeof api => {\n extendElementName(xmlFragment, tagName, extension);\n return api;\n },\n extendElementsWithClass: (param: string = 'extend'): typeof api => {\n extendElementsWithClass(xmlFragment, param);\n return api;\n },\n customInteraction(baseRef: string, baseItem: string): typeof api {\n const qtiCustomInteraction = xmlFragment.querySelector('qti-custom-interaction');\n const qtiCustomInteractionObject = qtiCustomInteraction.querySelector('object');\n\n qtiCustomInteraction.setAttribute('data-base-ref', baseRef);\n qtiCustomInteraction.setAttribute('data-base-item', baseRef + baseItem);\n qtiCustomInteraction.setAttribute('data', qtiCustomInteractionObject.getAttribute('data'));\n qtiCustomInteraction.setAttribute('width', qtiCustomInteractionObject.getAttribute('width'));\n qtiCustomInteraction.setAttribute('height', qtiCustomInteractionObject.getAttribute('height'));\n\n qtiCustomInteraction.removeChild(qtiCustomInteractionObject);\n return api;\n },\n convertCDATAtoComment(): typeof api {\n convertCDATAtoComment(xmlFragment);\n return api;\n },\n stripStyleSheets(): typeof api {\n stripStyleSheets(xmlFragment);\n return api;\n },\n html() {\n return new XMLSerializer().serializeToString(toHTML(xmlFragment));\n },\n xml(): string {\n return new XMLSerializer().serializeToString(xmlFragment);\n },\n htmlDoc() {\n return toHTML(xmlFragment);\n },\n xmlDoc(): XMLDocument {\n return xmlFragment; // new XMLSerializer().serializeToString(xmlFragment);\n }\n };\n return api;\n};\n","import { loadXML, parseXML } from './qti-transformers';\n\nexport const qtiTransformManifest = (): {\n load: (uri: string) => Promise<typeof api>;\n assessmentTest: () => { href: string; identifier: string };\n} => {\n let xmlFragment: XMLDocument;\n\n const api = {\n async load(uri) {\n return new Promise<typeof api>(resolve => {\n loadXML(uri).then(xml => {\n xmlFragment = xml;\n return resolve(api);\n });\n });\n },\n parse(xmlString: string) {\n xmlFragment = parseXML(xmlString);\n },\n assessmentTest() {\n const el = xmlFragment.querySelector('resource[type=\"imsqti_test_xmlv3p0\"]');\n return { href: el.getAttribute('href'), identifier: el.getAttribute('identifier') };\n }\n };\n return api;\n};\n","/**\n * Returns an object with methods to load, parse and transform QTI tests.\n * @returns An object with methods to load, parse and transform QTI tests.\n * @example\n * const qtiTransformer = qtiTransformTest();\n * await qtiTransformer.load('https://example.com/test.xml');\n * const items = qtiTransformer.items();\n * const html = qtiTransformer.html();\n * const xml = qtiTransformer.xml();\n */\n\nimport { itemsFromTest, loadXML, parseXML, setLocation, toHTML } from './qti-transformers';\n\nexport type transformTestApi = {\n load: (uri: string) => Promise<transformTestApi>;\n parse: (xmlString: string) => transformTestApi;\n path: (location: string) => transformTestApi;\n fn: (fn: (xmlFragment: XMLDocument) => void) => transformTestApi;\n items: () => { identifier: string; href: string; category: string }[];\n html: () => string;\n xml: () => string;\n htmlDoc: () => DocumentFragment;\n xmlDoc: () => XMLDocument;\n};\n\nexport const qtiTransformTest = (): transformTestApi => {\n let xmlFragment: XMLDocument;\n\n const api: transformTestApi = {\n async load(uri) {\n return new Promise<transformTestApi>((resolve, _) => {\n loadXML(uri).then(xml => {\n xmlFragment = xml;\n\n api.path(uri.substring(0, uri.lastIndexOf('/')));\n return resolve(api);\n });\n });\n },\n parse(xmlString: string) {\n xmlFragment = parseXML(xmlString);\n return api;\n },\n path: (location: string): typeof api => {\n setLocation(xmlFragment, location);\n return api;\n },\n fn(fn: (xmlFragment: XMLDocument) => void) {\n fn(xmlFragment);\n return api;\n },\n items() {\n return itemsFromTest(xmlFragment);\n },\n html() {\n return new XMLSerializer().serializeToString(toHTML(xmlFragment));\n },\n xml(): string {\n return new XMLSerializer().serializeToString(xmlFragment);\n },\n htmlDoc() {\n return toHTML(xmlFragment);\n },\n xmlDoc(): XMLDocument {\n return xmlFragment;\n }\n };\n return api;\n};\n","import { QtiAssessmentItem } from '../qti-components';\nimport { qtiTransformItem, qtiTransformTest } from '../qti-transformers';\nimport { qtiTransformManifest } from '../qti-transformers/qti-transform-manifest';\n\nexport type ManifestInfo = {\n testIdentifier: string;\n testHTMLDoc: DocumentFragment;\n testURI: string;\n testURL: string;\n items: {\n identifier: string;\n href: string;\n category: string;\n }[];\n};\n\n// Utility function to ensure package URIs end with a '/'\n// const normalizeUri = (uri: string) => (uri.endsWith('/') ? uri : `${uri}/`);\n\n// Fetches assessment data from the manifest\nexport const getManifestInfo = async (manifestURL: string): Promise<ManifestInfo> => {\n const baseURI = manifestURL.substring(0, manifestURL.lastIndexOf('/'));\n\n const test = await qtiTransformManifest()\n .load(`${manifestURL}`)\n .then(api => api.assessmentTest());\n\n const testHTMLDoc = await qtiTransformTest()\n .load(`${baseURI}/${test.href}`)\n .then(api => api.htmlDoc());\n\n const items = await qtiTransformTest()\n .load(`${baseURI}/${test.href}`)\n .then(api => api.items());\n\n const testURL = `${baseURI}/${test.href}`;\n const testURI = `${baseURI}/${test.href.substring(0, test.href.lastIndexOf('/'))}`;\n\n return {\n testHTMLDoc,\n testURI,\n testURL,\n items,\n testIdentifier: test.identifier\n };\n};\n\n// Fetches a single item by URI\nexport const getItemByUri = async (itemUri: string): Promise<QtiAssessmentItem> =>\n qtiTransformItem()\n .load(itemUri)\n .then(api => api.htmlDoc().firstElementChild as QtiAssessmentItem);\n"],"mappings":"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","names":["xml","xml","xml"]}
|
|
@@ -501,6 +501,23 @@ export type QtiChoiceInteractionProps = {
|
|
|
501
501
|
"onqti-interaction-response"?: (e: CustomEvent<CustomEvent>) => void;
|
|
502
502
|
};
|
|
503
503
|
|
|
504
|
+
export type QtiUploadInteractionProps = {
|
|
505
|
+
/** */
|
|
506
|
+
"response-identifier"?: string;
|
|
507
|
+
/** */
|
|
508
|
+
disabled?: boolean;
|
|
509
|
+
/** */
|
|
510
|
+
readonly?: boolean;
|
|
511
|
+
/** */
|
|
512
|
+
value?: string | string[];
|
|
513
|
+
/** */
|
|
514
|
+
correctResponse?: string | string[];
|
|
515
|
+
/** */
|
|
516
|
+
"onqti-interaction-response"?: (e: CustomEvent<CustomEvent>) => void;
|
|
517
|
+
/** */
|
|
518
|
+
"onqti-register-interaction"?: (e: CustomEvent<CustomEvent>) => void;
|
|
519
|
+
};
|
|
520
|
+
|
|
504
521
|
export type QtiOutcomeProcessingProps = {};
|
|
505
522
|
|
|
506
523
|
export type QtiPortableCustomInteractionProps = {
|
|
@@ -563,10 +580,6 @@ export type QtiAssociateInteractionProps = {
|
|
|
563
580
|
/** */
|
|
564
581
|
readonly?: boolean;
|
|
565
582
|
/** */
|
|
566
|
-
dragDropApi?: TouchDragAndDrop;
|
|
567
|
-
/** */
|
|
568
|
-
configuration?: InteractionConfiguration;
|
|
569
|
-
/** */
|
|
570
583
|
value?: string | string[];
|
|
571
584
|
/** */
|
|
572
585
|
correctResponse?: string | string[];
|
|
@@ -644,10 +657,6 @@ export type QtiGapMatchInteractionProps = {
|
|
|
644
657
|
/** */
|
|
645
658
|
correctResponse?: string | string[];
|
|
646
659
|
/** */
|
|
647
|
-
dragDropApi?: TouchDragAndDrop;
|
|
648
|
-
/** */
|
|
649
|
-
configuration?: InteractionConfiguration;
|
|
650
|
-
/** */
|
|
651
660
|
value?: string | string[];
|
|
652
661
|
/** */
|
|
653
662
|
"onqti-register-interaction"?: (e: CustomEvent<CustomEvent>) => void;
|
|
@@ -721,10 +730,6 @@ export type QtiGraphicGapMatchInteractionProps = {
|
|
|
721
730
|
/** */
|
|
722
731
|
readonly?: boolean;
|
|
723
732
|
/** */
|
|
724
|
-
dragDropApi?: TouchDragAndDrop;
|
|
725
|
-
/** */
|
|
726
|
-
configuration?: InteractionConfiguration;
|
|
727
|
-
/** */
|
|
728
733
|
value?: string | string[];
|
|
729
734
|
/** */
|
|
730
735
|
correctResponse?: string | string[];
|
|
@@ -779,6 +784,8 @@ export type QtiHotspotInteractionProps = {
|
|
|
779
784
|
};
|
|
780
785
|
|
|
781
786
|
export type QtiMatchInteractionProps = {
|
|
787
|
+
/** */
|
|
788
|
+
class?: string;
|
|
782
789
|
/** */
|
|
783
790
|
"response-identifier"?: string;
|
|
784
791
|
/** */
|
|
@@ -790,28 +797,10 @@ export type QtiMatchInteractionProps = {
|
|
|
790
797
|
/** */
|
|
791
798
|
readonly?: boolean;
|
|
792
799
|
/** */
|
|
793
|
-
rows?: QtiSimpleAssociableChoice[];
|
|
794
|
-
/** */
|
|
795
|
-
cols?: QtiSimpleAssociableChoice[];
|
|
796
|
-
/** */
|
|
797
|
-
lastCheckedRadio?: HTMLInputElement | null;
|
|
798
|
-
/** */
|
|
799
|
-
_response?: string | string[];
|
|
800
|
-
/** */
|
|
801
800
|
value?: string | string[];
|
|
802
801
|
/** */
|
|
803
|
-
correctOptions?: string[];
|
|
804
|
-
/** */
|
|
805
|
-
handleRadioClick?: string;
|
|
806
|
-
/** */
|
|
807
|
-
handleRadioChange?: string;
|
|
808
|
-
/** */
|
|
809
802
|
correctResponse?: string | string[];
|
|
810
803
|
/** */
|
|
811
|
-
dragDropApi?: TouchDragAndDrop;
|
|
812
|
-
/** */
|
|
813
|
-
configuration?: InteractionConfiguration;
|
|
814
|
-
/** */
|
|
815
804
|
"onqti-register-interaction"?: (e: CustomEvent<CustomEvent>) => void;
|
|
816
805
|
/** */
|
|
817
806
|
"onqti-interaction-response"?: (e: CustomEvent<CustomEvent>) => void;
|
|
@@ -860,10 +849,6 @@ export type QtiOrderInteractionProps = {
|
|
|
860
849
|
/** */
|
|
861
850
|
correctResponse?: string | string[];
|
|
862
851
|
/** */
|
|
863
|
-
dragDropApi?: TouchDragAndDrop;
|
|
864
|
-
/** */
|
|
865
|
-
configuration?: InteractionConfiguration;
|
|
866
|
-
/** */
|
|
867
852
|
value?: string | string[];
|
|
868
853
|
/** */
|
|
869
854
|
"onqti-register-interaction"?: (e: CustomEvent<CustomEvent>) => void;
|
|
@@ -906,10 +891,6 @@ export type QtiSelectPointInteractionProps = {
|
|
|
906
891
|
};
|
|
907
892
|
|
|
908
893
|
export type QtiSliderInteractionProps = {
|
|
909
|
-
/** */
|
|
910
|
-
"step-label"?: boolean;
|
|
911
|
-
/** */
|
|
912
|
-
reverse?: boolean;
|
|
913
894
|
/** */
|
|
914
895
|
"lower-bound"?: number;
|
|
915
896
|
/** */
|
|
@@ -917,27 +898,9 @@ export type QtiSliderInteractionProps = {
|
|
|
917
898
|
/** */
|
|
918
899
|
step?: number;
|
|
919
900
|
/** */
|
|
920
|
-
|
|
921
|
-
/** */
|
|
922
|
-
disabled?: boolean;
|
|
923
|
-
/** */
|
|
924
|
-
readonly?: boolean;
|
|
925
|
-
/** */
|
|
926
|
-
csLive?: CSSStyleDeclaration;
|
|
927
|
-
/** */
|
|
928
|
-
_handleDisabledChange?: string;
|
|
929
|
-
/** */
|
|
930
|
-
_handleReadonlyChange?: string;
|
|
901
|
+
value?: string;
|
|
931
902
|
/** */
|
|
932
|
-
|
|
933
|
-
/** */
|
|
934
|
-
response?: string;
|
|
935
|
-
/** */
|
|
936
|
-
correctResponse?: string | string[];
|
|
937
|
-
/** emitted when the interaction wants to register itself */
|
|
938
|
-
"onqti-register-interaction"?: (e: CustomEvent<CustomEvent>) => void;
|
|
939
|
-
/** emitted when the interaction changes */
|
|
940
|
-
"onqti-interaction-response"?: (e: CustomEvent<CustomEvent>) => void;
|
|
903
|
+
onchange?: (e: CustomEvent<Event>) => void;
|
|
941
904
|
};
|
|
942
905
|
|
|
943
906
|
export type QtiCustomOperatorProps = {
|
|
@@ -1135,8 +1098,6 @@ export type QtiTestPartProps = {
|
|
|
1135
1098
|
};
|
|
1136
1099
|
|
|
1137
1100
|
export type QtiTestProps = {
|
|
1138
|
-
/** the relative location to the QTI assessment.xml file */
|
|
1139
|
-
testURL?: string;
|
|
1140
1101
|
/** */
|
|
1141
1102
|
context?: TestContext;
|
|
1142
1103
|
};
|
|
@@ -1210,8 +1171,12 @@ export type TestItemLinkProps = {
|
|
|
1210
1171
|
};
|
|
1211
1172
|
|
|
1212
1173
|
export type TestContainerProps = {
|
|
1213
|
-
/**
|
|
1174
|
+
/** URL of the item to load */
|
|
1214
1175
|
"test-url"?: string;
|
|
1176
|
+
/** A parsed HTML document */
|
|
1177
|
+
testDoc?: DocumentFragment;
|
|
1178
|
+
/** The raw XML string */
|
|
1179
|
+
testXML?: string;
|
|
1215
1180
|
};
|
|
1216
1181
|
|
|
1217
1182
|
export type TestPagingButtonsStampProps = {
|
|
@@ -1233,17 +1198,15 @@ export type TestPagingButtonsStampProps = {
|
|
|
1233
1198
|
"onqti-request-test-item"?: (e: CustomEvent<CustomEvent>) => void;
|
|
1234
1199
|
};
|
|
1235
1200
|
|
|
1236
|
-
export type QtiItemProps = {
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
/**
|
|
1240
|
-
|
|
1241
|
-
/**
|
|
1242
|
-
|
|
1243
|
-
/**
|
|
1244
|
-
|
|
1245
|
-
/** */
|
|
1246
|
-
"onqti-item-connected"?: (e: CustomEvent<CustomEvent>) => void;
|
|
1201
|
+
export type QtiItemProps = {};
|
|
1202
|
+
|
|
1203
|
+
export type ItemContainerProps = {
|
|
1204
|
+
/** URL of the item to load */
|
|
1205
|
+
"item-url"?: string;
|
|
1206
|
+
/** A parsed HTML document */
|
|
1207
|
+
itemDoc?: DocumentFragment;
|
|
1208
|
+
/** The raw XML string */
|
|
1209
|
+
itemXML?: string;
|
|
1247
1210
|
};
|
|
1248
1211
|
|
|
1249
1212
|
export type CustomElements = {
|
|
@@ -1697,6 +1660,17 @@ export type CustomElements = {
|
|
|
1697
1660
|
*/
|
|
1698
1661
|
"qti-choice-interaction": Partial<QtiChoiceInteractionProps & BaseProps & BaseEvents>;
|
|
1699
1662
|
|
|
1663
|
+
/**
|
|
1664
|
+
*
|
|
1665
|
+
* ---
|
|
1666
|
+
*
|
|
1667
|
+
*
|
|
1668
|
+
* ### **Events:**
|
|
1669
|
+
* - **qti-interaction-response**
|
|
1670
|
+
* - **qti-register-interaction**
|
|
1671
|
+
*/
|
|
1672
|
+
"qti-upload-interaction": Partial<QtiUploadInteractionProps & BaseProps & BaseEvents>;
|
|
1673
|
+
|
|
1700
1674
|
/**
|
|
1701
1675
|
*
|
|
1702
1676
|
* ---
|
|
@@ -1883,30 +1857,12 @@ export type CustomElements = {
|
|
|
1883
1857
|
"qti-select-point-interaction": Partial<QtiSelectPointInteractionProps & BaseProps & BaseEvents>;
|
|
1884
1858
|
|
|
1885
1859
|
/**
|
|
1886
|
-
*
|
|
1860
|
+
*
|
|
1887
1861
|
* ---
|
|
1888
1862
|
*
|
|
1889
1863
|
*
|
|
1890
1864
|
* ### **Events:**
|
|
1891
|
-
* - **
|
|
1892
|
-
* - **qti-interaction-response** - emitted when the interaction changes
|
|
1893
|
-
*
|
|
1894
|
-
* ### **Slots:**
|
|
1895
|
-
* - _default_ - The default slot where <qti-simple-choice> must be placed.
|
|
1896
|
-
* - **prompt** - slot where the prompt is placed.
|
|
1897
|
-
*
|
|
1898
|
-
* ### **CSS Properties:**
|
|
1899
|
-
* - **--show-value** - shows the current value while sliding _(default: undefined)_
|
|
1900
|
-
* - **--show-ticks** - shows the ticks according to steps _(default: undefined)_
|
|
1901
|
-
* - **--show-bounds** - shows value for lower and upper boundary _(default: undefined)_
|
|
1902
|
-
*
|
|
1903
|
-
* ### **CSS Parts:**
|
|
1904
|
-
* - **slider** - -- slider inluding, bounds and ticks and value, use it for paddings and margins
|
|
1905
|
-
* - **bounds** - -- div for bounds, containing two divs for with min, and max bounds value
|
|
1906
|
-
* - **ticks** - -- div for ticks, use lineair gradient and exposed css variables for styling
|
|
1907
|
-
* - **rail** - -- div for rail, style according to needs
|
|
1908
|
-
* - **knob** - -- div, should be relative or absolute
|
|
1909
|
-
* - **value** - -- div, containing value
|
|
1865
|
+
* - **change**
|
|
1910
1866
|
*/
|
|
1911
1867
|
"qti-slider-interaction": Partial<QtiSliderInteractionProps & BaseProps & BaseEvents>;
|
|
1912
1868
|
|
|
@@ -2064,30 +2020,47 @@ export type CustomElements = {
|
|
|
2064
2020
|
*
|
|
2065
2021
|
* ### Example Usage
|
|
2066
2022
|
*
|
|
2067
|
-
* Minimal
|
|
2068
|
-
* ```html
|
|
2069
|
-
* <qti-test test="./path/to/assessment.xml">
|
|
2070
|
-
* <test-container></test-container>
|
|
2071
|
-
* </qti-test>
|
|
2072
|
-
* ```
|
|
2023
|
+
* Minimal example including navigation:
|
|
2073
2024
|
*
|
|
2074
|
-
* With navigation buttons:
|
|
2075
2025
|
* ```html
|
|
2076
|
-
* <qti-test
|
|
2026
|
+
* <qti-test>
|
|
2077
2027
|
* <test-container test-url="./path/to/assessment.xml"></test-container>
|
|
2078
|
-
* <
|
|
2028
|
+
* <nav class="flex">
|
|
2079
2029
|
* <test-prev></test-prev>
|
|
2080
2030
|
* <test-next></test-next>
|
|
2081
|
-
* </
|
|
2031
|
+
* </nav>
|
|
2082
2032
|
* </qti-test>
|
|
2083
2033
|
* ```
|
|
2084
2034
|
*
|
|
2035
|
+
* Use the following file structure
|
|
2036
|
+
* A qti-test loads a QTI3.0 assessmenttest.xml file from a package folder.
|
|
2037
|
+
*
|
|
2038
|
+
* ```plaintext
|
|
2039
|
+
* Root/
|
|
2040
|
+
* ├── index.html
|
|
2041
|
+
* └── /assets/api/examples/
|
|
2042
|
+
* ├── assessmenttest.xml
|
|
2043
|
+
* └── imsmanifest.xml
|
|
2044
|
+
*
|
|
2045
|
+
* ```
|
|
2046
|
+
*
|
|
2047
|
+
* ### Test components
|
|
2048
|
+
*
|
|
2049
|
+
* Use test components inside the qti-test component for added functionality.
|
|
2050
|
+
* ### Test next
|
|
2051
|
+
* `<test-next> | TestNext`
|
|
2052
|
+
*
|
|
2053
|
+
* ### Test prev
|
|
2054
|
+
*
|
|
2055
|
+
* `<test-prev> | TestPrev`
|
|
2056
|
+
* ### Test components
|
|
2057
|
+
*
|
|
2085
2058
|
* You can use normal class names to style the elements.
|
|
2086
2059
|
* And you can use the `test-prev` and `test-next` elements to navigate through the test.
|
|
2087
2060
|
* ---
|
|
2088
2061
|
*
|
|
2089
2062
|
*/
|
|
2090
|
-
"qti-
|
|
2063
|
+
"qti-test": Partial<QtiTestProps & BaseProps & BaseEvents>;
|
|
2091
2064
|
|
|
2092
2065
|
/**
|
|
2093
2066
|
* Represents a custom element for navigating to the next test item.
|
|
@@ -2134,16 +2107,16 @@ export type CustomElements = {
|
|
|
2134
2107
|
"test-item-link": Partial<TestItemLinkProps & BaseProps & BaseEvents>;
|
|
2135
2108
|
|
|
2136
2109
|
/**
|
|
2137
|
-
* `<test-container>` is a custom element designed for hosting the qti-assessment-
|
|
2110
|
+
* `<test-container>` is a custom element designed for hosting the qti-assessment-item.
|
|
2138
2111
|
* The `qti-assessment-test` will be placed inside the shadow DOM of this element.
|
|
2112
|
+
* The element loads the item from the provided URL and renders it inside the shadow DOM.
|
|
2139
2113
|
*
|
|
2140
|
-
* ###
|
|
2141
|
-
*
|
|
2142
|
-
* You can style the container by adding a class to the element.
|
|
2114
|
+
* ### Styling
|
|
2115
|
+
* Add a class to the element for styling.
|
|
2143
2116
|
*
|
|
2144
2117
|
* ```html
|
|
2145
|
-
* <qti-test
|
|
2146
|
-
* <test-container class="
|
|
2118
|
+
* <qti-test>
|
|
2119
|
+
* <test-container class="m-4 bg-white" test-url="./path/to/item.xml"></test-container>
|
|
2147
2120
|
* </qti-test>
|
|
2148
2121
|
* ```
|
|
2149
2122
|
* ---
|
|
@@ -2163,12 +2136,36 @@ export type CustomElements = {
|
|
|
2163
2136
|
"test-paging-buttons-stamp": Partial<TestPagingButtonsStampProps & BaseProps & BaseEvents>;
|
|
2164
2137
|
|
|
2165
2138
|
/**
|
|
2139
|
+
* `<qti-item>` is a custom element designed for rendering a single `qti-assessment-item`.
|
|
2140
|
+
* It can also host some functionalities to interact with the item like scoring, showing feedback, etc.
|
|
2141
|
+
* Placing a mandatory `<item-container>` inside '<qti-item>' will load or parse the item and render it.
|
|
2142
|
+
* See `<item-container>` for more details.
|
|
2166
2143
|
*
|
|
2144
|
+
* ```html
|
|
2145
|
+
* <qti-item>
|
|
2146
|
+
* <item-container class="m-4 bg-white" item-url="./path/to/item.xml"></item-container>
|
|
2147
|
+
* </qti-item>
|
|
2148
|
+
* ```
|
|
2167
2149
|
* ---
|
|
2168
2150
|
*
|
|
2169
|
-
*
|
|
2170
|
-
* ### **Events:**
|
|
2171
|
-
* - **qti-item-connected**
|
|
2172
2151
|
*/
|
|
2173
2152
|
"qti-item": Partial<QtiItemProps & BaseProps & BaseEvents>;
|
|
2153
|
+
|
|
2154
|
+
/**
|
|
2155
|
+
* `<item-container>` is a custom element designed for hosting the qti-assessment-item.
|
|
2156
|
+
* The `qti-assessment-item` will be placed inside the shadow DOM of this element.
|
|
2157
|
+
* The element loads the item from the provided URL and renders it inside the shadow DOM.
|
|
2158
|
+
*
|
|
2159
|
+
* ### Styling
|
|
2160
|
+
* Add a class to the element for styling.
|
|
2161
|
+
*
|
|
2162
|
+
* ```html
|
|
2163
|
+
* <qti-item>
|
|
2164
|
+
* <item-container class="m-4 bg-white" item-url="./path/to/item.xml"></item-container>
|
|
2165
|
+
* </qti-item>
|
|
2166
|
+
* ```
|
|
2167
|
+
* ---
|
|
2168
|
+
*
|
|
2169
|
+
*/
|
|
2170
|
+
"item-container": Partial<ItemContainerProps & BaseProps & BaseEvents>;
|
|
2174
2171
|
};
|