-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Patrick de Klein
committed
Dec 20, 2024
1 parent
59ccdf3
commit db80599
Showing
19 changed files
with
498 additions
and
349 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
<?xml version="1.0" encoding="UTF-8"?> | ||
<?xml-model href="https://purl.imsglobal.org/spec/qti/v3p0/schema/xsd/imsqti_asiv3p0_v1p0.xsd" type="application/xml" schematypens="http://purl.oclc.org/dsdl/schematron"?> | ||
<qti-assessment-item xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||
xmlns="http://www.imsglobal.org/xsd/imsqtiasi_v3p0" | ||
xsi:schemaLocation="http://www.imsglobal.org/xsd/imsqtiasi_v3p0 https://purl.imsglobal.org/spec/qti/v3p0/schema/xsd/imsqti_asiv3p0_v1p0.xsd" | ||
identifier="ITM-choice" title="Unattended Luggage" adaptive="false" time-dependent="false"> | ||
<qti-response-declaration identifier="RESPONSE" cardinality="single" base-type="identifier"> | ||
<qti-correct-response> | ||
<qti-value>ChoiceA</qti-value> | ||
</qti-correct-response> | ||
</qti-response-declaration> | ||
<qti-outcome-declaration identifier="SCORE" cardinality="single" base-type="float"> | ||
<qti-default-value> | ||
<qti-value>0</qti-value> | ||
</qti-default-value> | ||
</qti-outcome-declaration> | ||
|
||
<qti-outcome-declaration identifier="MAXSCORE" cardinality="single" base-type="float"> | ||
<qti-default-value> | ||
<qti-value>1</qti-value> | ||
</qti-default-value> | ||
</qti-outcome-declaration> | ||
<qti-item-body> | ||
<p>Look at the text in the picture.</p> | ||
<p> | ||
<img src="./img/sign.png" alt="NEVER LEAVE LUGGAGE UNATTENDED" /> | ||
</p> | ||
<qti-choice-interaction response-identifier="RESPONSE" shuffle="false" max-choices="1"> | ||
<qti-prompt>What does it say?</qti-prompt> | ||
<qti-simple-choice identifier="ChoiceA">You must stay with your luggage at all times.</qti-simple-choice> | ||
<qti-simple-choice identifier="ChoiceB">Do not let someone else look after your luggage.</qti-simple-choice> | ||
<qti-simple-choice identifier="ChoiceC">Remember your luggage when you leave.</qti-simple-choice> | ||
</qti-choice-interaction> | ||
</qti-item-body> | ||
<qti-response-processing | ||
template="https://purl.imsglobal.org/spec/qti/v3p0/rptemplates/match_correct.xml" /> | ||
</qti-assessment-item> |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export * from './item-container'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,122 @@ | ||
import type { Meta, StoryObj } from '@storybook/web-components'; | ||
import { html } from 'lit'; | ||
import { ItemContainer } from '../components/item-container'; | ||
import { qtiTransformItem } from '../../qti-transformers'; | ||
import { expect } from '@storybook/test'; | ||
import { within } from 'shadow-dom-testing-library'; | ||
import { getWcStorybookHelpers } from 'wc-storybook-helpers'; | ||
|
||
const { events, args, argTypes, template } = getWcStorybookHelpers('item-container'); | ||
|
||
type Story = StoryObj<ItemContainer & typeof args>; | ||
|
||
const meta: Meta<typeof ItemContainer & { 'item-url': string }> = { | ||
component: 'item-container', | ||
args: { ...args, 'item-url': '/qti-item/example-choice-item.xml' }, | ||
argTypes, | ||
parameters: { | ||
actions: { | ||
handles: events | ||
} | ||
}, | ||
tags: ['autodocs', 'new'] | ||
}; | ||
export default meta; | ||
|
||
export const ItemURL: Story = { | ||
render: args => { | ||
return html`<qti-item>${template(args)}</qti-item>`; | ||
}, | ||
play: async ({ canvasElement }) => { | ||
const canvas = within(canvasElement); | ||
const assessmentItem = await canvas.findByShadowTitle('Unattended Luggage'); | ||
expect(assessmentItem).toBeInTheDocument(); | ||
} | ||
}; | ||
|
||
export const ItemDoc: Story = { | ||
render: (_, { loaded: { itemDoc } }) => { | ||
return html` | ||
<qti-item> | ||
<item-container .itemDoc=${itemDoc}></item-container> | ||
</qti-item> | ||
`; | ||
}, | ||
loaders: [ | ||
async ({ args }) => { | ||
console.log('args', args); | ||
const itemDoc = qtiTransformItem() | ||
.load(args['item-url']) | ||
.then(api => api.htmlDoc()); | ||
return { itemDoc }; | ||
} | ||
], | ||
play: ItemURL.play, | ||
tags: ['!autodocs'] | ||
}; | ||
|
||
export const ItemXML: Story = { | ||
render: (_, { loaded: { itemXML } }) => { | ||
return html` | ||
<qti-item> | ||
<item-container .itemXML=${itemXML}></item-container> | ||
</qti-item> | ||
`; | ||
}, | ||
loaders: [ | ||
async ({ args }) => { | ||
const itemXML = await qtiTransformItem() | ||
.load(args['item-url']) | ||
.then(api => api.xml()); | ||
return { itemXML }; | ||
} | ||
], | ||
play: ItemURL.play, | ||
tags: ['!autodocs'] | ||
}; | ||
|
||
export const ItemWithTemplate: Story = { | ||
render: args => { | ||
return html` | ||
<qti-item> | ||
<item-container item-url=${args['item-url']}> | ||
<template> | ||
<style> | ||
qti-simple-choice { | ||
border: 2px solid blue; | ||
} | ||
</style> | ||
</template> | ||
</item-container> | ||
</qti-item> | ||
`; | ||
}, | ||
play: ItemURL.play, | ||
tags: ['!autodocs'] | ||
}; | ||
|
||
export const ItemWithTemplateScale: Story = { | ||
render: args => { | ||
return html` | ||
<qti-item> | ||
<item-container item-url=${args['item-url']}> | ||
<template> | ||
<style> | ||
qti-assessment-item { | ||
padding: 1rem; | ||
display: block; | ||
aspect-ratio: 4 / 3; | ||
width: 800px; | ||
border: 2px solid blue; | ||
transform: scale(0.5); | ||
transform-origin: top left; | ||
} | ||
</style> | ||
</template> | ||
</item-container> | ||
</qti-item> | ||
`; | ||
}, | ||
play: ItemURL.play, | ||
tags: ['!autodocs'] | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
import { LitElement, html } from 'lit'; | ||
import { customElement, property, state } from 'lit/decorators.js'; | ||
import { until } from 'lit/directives/until.js'; | ||
import { watch } from '../../decorators/watch'; | ||
import itemCss from '../../../item.css?inline'; | ||
import { qtiTransformItem } from '../../qti-transformers'; | ||
|
||
/** | ||
* `<item-container>` is a custom element designed for hosting the qti-assessment-item. | ||
* The `qti-assessment-item` will be placed inside the shadow DOM of this element. | ||
* The element loads the item from the provided URL and renders it inside the shadow DOM. | ||
* | ||
* ### Styling | ||
* Add a class to the element for styling. | ||
* | ||
* ```html | ||
* <qti-item> | ||
* <item-container class="m-4 bg-white" item-url="./path/to/item.xml"></item-container> | ||
* </qti-item> | ||
* ``` | ||
*/ | ||
@customElement('item-container') | ||
export class ItemContainer extends LitElement { | ||
/** URL of the item to load */ | ||
@property({ type: String, attribute: 'item-url' }) | ||
itemURL: string = null; | ||
|
||
/** A parsed HTML document */ | ||
@state() | ||
itemDoc: DocumentFragment = null; | ||
|
||
/** The raw XML string */ | ||
@state() | ||
itemXML: string = null; | ||
|
||
/** Template content if provided */ | ||
private templateContent = null; | ||
|
||
@watch('itemURL', { waitUntilFirstUpdate: true }) | ||
protected async handleItemURLChange() { | ||
if (!this.itemURL) return; | ||
try { | ||
const api = await qtiTransformItem().load(this.itemURL); | ||
this.itemDoc = api.htmlDoc(); | ||
} catch (error) { | ||
console.error('Error loading or parsing XML:', error); | ||
} | ||
} | ||
|
||
@watch('itemXML', { waitUntilFirstUpdate: true }) | ||
protected handleItemXMLChange() { | ||
if (!this.itemXML) return; | ||
try { | ||
this.itemDoc = qtiTransformItem().parse(this.itemXML).htmlDoc(); | ||
} catch (error) { | ||
console.error('Error parsing XML:', error); | ||
} | ||
} | ||
|
||
async connectedCallback(): Promise<void> { | ||
super.connectedCallback(); | ||
this.initializeTemplateContent(); | ||
this.applyStyles(); | ||
if (this.itemURL) { | ||
this.handleItemURLChange(); | ||
} | ||
if (this.itemXML) { | ||
this.handleItemXMLChange(); | ||
} | ||
} | ||
|
||
private initializeTemplateContent() { | ||
const template = this.querySelector('template') as HTMLTemplateElement; | ||
this.templateContent = template ? template.content : html``; | ||
} | ||
|
||
private applyStyles() { | ||
const sheet = new CSSStyleSheet(); | ||
sheet.replaceSync(itemCss); | ||
this.shadowRoot.adoptedStyleSheets = [sheet]; | ||
} | ||
|
||
render() { | ||
return html` | ||
${this.templateContent} | ||
<slot></slot> | ||
${until(this.itemDoc, html`<span>Loading...</span>`)} | ||
`; | ||
} | ||
} | ||
|
||
declare global { | ||
interface HTMLElementTagNameMap { | ||
'item-container': ItemContainer; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,2 @@ | ||
export * from './qti-item'; | ||
export * from './qti-item.mixin'; | ||
|
||
export * from './components'; |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
import type { Meta, StoryObj } from '@storybook/web-components'; | ||
import { html } from 'lit'; | ||
import { getWcStorybookHelpers } from 'wc-storybook-helpers'; | ||
import { QtiItem } from './qti-item'; | ||
|
||
const { events, args, argTypes, template } = getWcStorybookHelpers('qti-item'); | ||
|
||
type Story = StoryObj<QtiItem & typeof args>; | ||
|
||
const meta: Meta<typeof QtiItem> = { | ||
component: 'qti-item', | ||
subcomponents: { ItemContainer: 'item-container' }, | ||
args, | ||
argTypes, | ||
parameters: { | ||
actions: { | ||
handles: events | ||
} | ||
}, | ||
tags: ['autodocs', 'new'] | ||
}; | ||
export default meta; | ||
|
||
export const Default: Story = { | ||
render: args => { | ||
return html`${template(args, html`<item-container item-url="/qti-item/example-choice-item.xml"></item-container>`)}`; | ||
} | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.