Skip to content

Commit

Permalink
Merge branch 'dev' of https://github.com/Citolab/qti-components into dev
Browse files Browse the repository at this point in the history
  • Loading branch information
Patrick de Klein committed Nov 11, 2024
2 parents 5b07b13 + 2c3558e commit 3385795
Show file tree
Hide file tree
Showing 2 changed files with 116 additions and 111 deletions.
4 changes: 1 addition & 3 deletions src/lib/qti-loader/qti-loader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,4 @@ export const getManifestInfo = async (manifestURL: string): Promise<ManifestInfo
export const getItemByUri = async (itemUri: string): Promise<QtiAssessmentItem> =>
qtiTransformItem()
.load(itemUri)
.then(
api => api.path(itemUri.substring(0, itemUri.lastIndexOf('/'))).htmlDoc().firstElementChild as QtiAssessmentItem
);
.then(api => api.htmlDoc().firstElementChild as QtiAssessmentItem);
223 changes: 115 additions & 108 deletions src/lib/qti-transformers/qti-transform-item.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@


/**
* Browser based QTI-XML to HTML transformer.
* Returns an object with methods to load, parse, transform and serialize QTI XML items.
Expand All @@ -16,113 +14,122 @@
* qtiTransformItem().parse(storyXML).html()
*/

import { convertCDATAtoComment, extendElementName, extendElementsWithClass, loadXML, parseXML, setLocation, stripStyleSheets, toHTML } from "./qti-transformers";
import {
convertCDATAtoComment,
extendElementName,
extendElementsWithClass,
loadXML,
parseXML,
setLocation,
stripStyleSheets,
toHTML
} from './qti-transformers';

export type transformItemApi = {
load: (uri: string, cancelPreviousRequest?: boolean) => Promise<transformItemApi>;
parse: (xmlString: string) => transformItemApi;
path: (location: string) => transformItemApi;
fn: (fn: (xmlFragment: XMLDocument) => void) => transformItemApi;
pciHooks: (uri: string) => transformItemApi;
extendElementName: (elementName: string, extend: string) => transformItemApi;
extendElementsWithClass: (param?: string) => transformItemApi;
customInteraction: (baseRef: string, baseItem: string) => transformItemApi;
convertCDATAtoComment: () => transformItemApi;
stripStyleSheets: () => transformItemApi;
html: () => string;
xml: () => string;
htmlDoc: () => DocumentFragment;
xmlDoc: () => XMLDocument;
};

export const qtiTransformItem = () => {
let xmlFragment: XMLDocument;

const api: transformItemApi = {
async load(uri: string, cancelPreviousRequest = false): Promise<typeof api> {
return new Promise<typeof api>((resolve, reject) => {
loadXML(uri, cancelPreviousRequest).then(xml => {
xmlFragment = xml;
// set the base path for images and other resources,
// you probably want to set the base path to the document root else you can use the path method to set it
api.path(uri.substring(0, uri.lastIndexOf('/')));
return resolve(api);
});
load: (uri: string, cancelPreviousRequest?: boolean) => Promise<transformItemApi>;
parse: (xmlString: string) => transformItemApi;
path: (location: string) => transformItemApi;
fn: (fn: (xmlFragment: XMLDocument) => void) => transformItemApi;
pciHooks: (uri: string) => transformItemApi;
extendElementName: (elementName: string, extend: string) => transformItemApi;
extendElementsWithClass: (param?: string) => transformItemApi;
customInteraction: (baseRef: string, baseItem: string) => transformItemApi;
convertCDATAtoComment: () => transformItemApi;
stripStyleSheets: () => transformItemApi;
html: () => string;
xml: () => string;
htmlDoc: () => DocumentFragment;
xmlDoc: () => XMLDocument;
};

export const qtiTransformItem = () => {
let xmlFragment: XMLDocument;

const api: transformItemApi = {
async load(uri: string, cancelPreviousRequest = false): Promise<typeof api> {
return new Promise<typeof api>((resolve, reject) => {
loadXML(uri, cancelPreviousRequest).then(xml => {
xmlFragment = xml;
// set the base path for images and other resources,
// you probably want to set the base path to the document root else you can use the path method to set it
api.path(uri.substring(0, uri.lastIndexOf('/')));
return resolve(api);
});
});
},
parse(xmlString: string): typeof api {
xmlFragment = parseXML(xmlString);
return api;
},
path: (location: string): typeof api => {
setLocation(xmlFragment, location);
return api;
},
fn(fn: (xmlFragment: XMLDocument) => void): typeof api {
fn(xmlFragment);
return api;
},
pciHooks(uri: string): typeof api {
const attributes = ['hook', 'module'];
const documentPath = uri.substring(0, uri.lastIndexOf('/'));
for (const attribute of attributes) {
const srcAttributes = xmlFragment.querySelectorAll('[' + attribute + ']');
srcAttributes.forEach(node => {
const srcValue = node.getAttribute(attribute)!;
if (!srcValue.startsWith('data:') && !srcValue.startsWith('http')) {
// Just paste the relative path of the src location after the documentrootPath
// old pcis can have a .js, new pci's don't
node.setAttribute('base-url', uri);
node.setAttribute(
'module',
documentPath + '/' + encodeURI(srcValue + (srcValue.endsWith('.js') ? '' : '.js'))
);
}
});
},
parse(xmlString: string): typeof api {
xmlFragment = parseXML(xmlString);
return api;
},
path: (location: string): typeof api => {
setLocation(xmlFragment, location);
return api;
},
fn(fn: (xmlFragment: XMLDocument) => void): typeof api {
fn(xmlFragment);
return api;
},
pciHooks(uri: string): typeof api {
const attributes = ['hook', 'module'];
const documentPath = uri.substring(0, uri.lastIndexOf('/'));
for (const attribute of attributes) {
const srcAttributes = xmlFragment.querySelectorAll('[' + attribute + ']');
srcAttributes.forEach(node => {
const srcValue = node.getAttribute(attribute)!;
if (!srcValue.startsWith('data:') && !srcValue.startsWith('http')) {
// Just paste the relative path of the src location after the documentrootPath
// old pcis can have a .js, new pci's don't
node.setAttribute('base-url', uri);
node.setAttribute(
'module',
documentPath + '/' + encodeURI(srcValue + (srcValue.endsWith('.js') ? '' : '.js'))
);
}
});
}
return api;
},
extendElementName: (tagName: string, extension: string): typeof api => {
extendElementName(xmlFragment, tagName, extension);
return api;
},
extendElementsWithClass: (param: string = 'extend'): typeof api => {
extendElementsWithClass(xmlFragment, param);
return api;
},
customInteraction(baseRef: string, baseItem: string): typeof api {
const qtiCustomInteraction = xmlFragment.querySelector('qti-custom-interaction');
const qtiCustomInteractionObject = qtiCustomInteraction.querySelector('object');

qtiCustomInteraction.setAttribute('data-base-ref', baseRef);
qtiCustomInteraction.setAttribute('data-base-item', baseRef + baseItem);
qtiCustomInteraction.setAttribute('data', qtiCustomInteractionObject.getAttribute('data'));
qtiCustomInteraction.setAttribute('width', qtiCustomInteractionObject.getAttribute('width'));
qtiCustomInteraction.setAttribute('height', qtiCustomInteractionObject.getAttribute('height'));

qtiCustomInteraction.removeChild(qtiCustomInteractionObject);
return api;
},
convertCDATAtoComment(): typeof api {
convertCDATAtoComment(xmlFragment);
return api;
},
stripStyleSheets(): typeof api {
stripStyleSheets(xmlFragment);
return api;
},
html() {
return new XMLSerializer().serializeToString(toHTML(xmlFragment));
},
xml(): string {
return new XMLSerializer().serializeToString(xmlFragment);
},
htmlDoc() {
return toHTML(xmlFragment);
},
xmlDoc(): XMLDocument {
return xmlFragment; // new XMLSerializer().serializeToString(xmlFragment);
}
};
return api;
};
return api;
},
extendElementName: (tagName: string, extension: string): typeof api => {
extendElementName(xmlFragment, tagName, extension);
return api;
},
extendElementsWithClass: (param: string = 'extend'): typeof api => {
extendElementsWithClass(xmlFragment, param);
return api;
},
customInteraction(baseRef: string, baseItem: string): typeof api {
const qtiCustomInteraction = xmlFragment.querySelector('qti-custom-interaction');
const qtiCustomInteractionObject = qtiCustomInteraction.querySelector('object');

qtiCustomInteraction.setAttribute('data-base-ref', baseRef);
qtiCustomInteraction.setAttribute('data-base-item', baseRef + baseItem);
qtiCustomInteraction.setAttribute('data', qtiCustomInteractionObject.getAttribute('data'));
qtiCustomInteraction.setAttribute('width', qtiCustomInteractionObject.getAttribute('width'));
qtiCustomInteraction.setAttribute('height', qtiCustomInteractionObject.getAttribute('height'));

qtiCustomInteraction.removeChild(qtiCustomInteractionObject);
return api;
},
convertCDATAtoComment(): typeof api {
convertCDATAtoComment(xmlFragment);
return api;
},
stripStyleSheets(): typeof api {
stripStyleSheets(xmlFragment);
return api;
},
html() {
return new XMLSerializer().serializeToString(toHTML(xmlFragment));
},
xml(): string {
return new XMLSerializer().serializeToString(xmlFragment);
},
htmlDoc() {
return toHTML(xmlFragment);
},
xmlDoc(): XMLDocument {
return xmlFragment; // new XMLSerializer().serializeToString(xmlFragment);
}
};
return api;
};

0 comments on commit 3385795

Please sign in to comment.