@pie-element/mc-populated-blank 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,103 @@
1
+ import McPopulatedBlankComponent from './McPopulatedBlank.svelte';
2
+ import { isComplete as isControllerComplete } from '../controller';
3
+
4
+ const SvelteElementClass = (McPopulatedBlankComponent as any).element;
5
+
6
+ class McPopulatedBlankElement extends SvelteElementClass {
7
+ _internalSession: any = null;
8
+ _model: any = null;
9
+ _options: any = null;
10
+ audioComplete = false;
11
+
12
+ _dispatchModelSet = () => {
13
+ this.dispatchEvent(
14
+ new CustomEvent('model-set', {
15
+ bubbles: true,
16
+ composed: true,
17
+ detail: {
18
+ complete: this._isComplete(),
19
+ component: this.tagName.toLowerCase(),
20
+ hasModel: this._model !== undefined,
21
+ },
22
+ })
23
+ );
24
+ };
25
+
26
+ _dispatchSessionChanged = () => {
27
+ this.dispatchEvent(
28
+ new CustomEvent('session-changed', {
29
+ bubbles: true,
30
+ composed: true,
31
+ detail: {
32
+ complete: this._isComplete(),
33
+ component: this.tagName.toLowerCase(),
34
+ },
35
+ })
36
+ );
37
+ };
38
+
39
+ set model(m: any) {
40
+ this._model = m;
41
+ this.audioComplete = false;
42
+ super.model = m;
43
+ this._dispatchModelSet();
44
+ }
45
+
46
+ get model() {
47
+ return this._model;
48
+ }
49
+
50
+ set session(s: any) {
51
+ this._internalSession = s;
52
+ super.session = s;
53
+ this._dispatchSessionChanged();
54
+ }
55
+
56
+ get session() {
57
+ return this._internalSession;
58
+ }
59
+
60
+ set options(o: any) {
61
+ this._options = o;
62
+ super.options = o;
63
+ }
64
+
65
+ get options() {
66
+ return this._options;
67
+ }
68
+
69
+ onSessionChange = (updatedSession: any) => {
70
+ this._internalSession = updatedSession;
71
+ super.session = updatedSession;
72
+ this._dispatchSessionChanged();
73
+ };
74
+
75
+ onAudioStarted = () => {
76
+ this._internalSession = {
77
+ ...(this._internalSession || {}),
78
+ audioStartTime: new Date().getTime(),
79
+ };
80
+ };
81
+
82
+ onAudioEnded = () => {
83
+ this.audioComplete = true;
84
+ this._internalSession = {
85
+ ...(this._internalSession || {}),
86
+ audioEndTime: new Date().getTime(),
87
+ };
88
+ this._dispatchSessionChanged();
89
+ };
90
+
91
+ _isComplete = () => {
92
+ return isControllerComplete(this._model, this._internalSession, this.audioComplete);
93
+ };
94
+
95
+ connectedCallback() {
96
+ super.connectedCallback();
97
+ (this as any).onSessionChange = this.onSessionChange;
98
+ (this as any).onAudioStarted = this.onAudioStarted;
99
+ (this as any).onAudioEnded = this.onAudioEnded;
100
+ }
101
+ }
102
+
103
+ export default McPopulatedBlankElement;
@@ -0,0 +1,13 @@
1
+ /**
2
+ * IIFE entry for mc-populated-blank delivery custom element.
3
+ */
4
+ import Element from './delivery';
5
+
6
+ if (typeof window !== 'undefined' && !customElements.get('mc-populated-blank-element')) {
7
+ customElements.define(
8
+ 'mc-populated-blank-element',
9
+ Element as unknown as CustomElementConstructor
10
+ );
11
+ }
12
+
13
+ export default Element;
package/src/index.ts ADDED
@@ -0,0 +1 @@
1
+ export { default } from './delivery/index';
@@ -0,0 +1,95 @@
1
+ <svelte:options
2
+ customElement={{
3
+ shadow: 'none',
4
+ props: {
5
+ model: { type: 'Object' },
6
+ },
7
+ }}
8
+ />
9
+
10
+ <script lang="ts">
11
+ const BLANK_TOKEN = '{{blank}}';
12
+
13
+ let { model = null }: { model?: any } = $props();
14
+
15
+ let prompt = $state('');
16
+ let template = $state('');
17
+ $effect(() => {
18
+ prompt = model?.prompt || '';
19
+ template = model?.template || '';
20
+ });
21
+
22
+ const parts = $derived.by(() => {
23
+ const idx = template.indexOf(BLANK_TOKEN);
24
+ if (idx < 0) return { before: template, after: '' };
25
+ return { before: template.slice(0, idx), after: template.slice(idx + BLANK_TOKEN.length) };
26
+ });
27
+
28
+ const choices = $derived(Array.isArray(model?.choices) ? model.choices : []);
29
+ const correct = $derived(model?.choices?.find((c: any) => c.id === model?.correctChoiceId));
30
+ const mode = $derived(model?.choiceMode || 'text');
31
+ const isAudioOnlyMode = $derived(model?.interactionMode === 'audio_mc_only');
32
+ const showAnswerKey = $derived(model?.printAnswerKey !== false);
33
+ </script>
34
+
35
+ <div class="p-4 print:p-0">
36
+ {#if prompt && model?.promptEnabled !== false}
37
+ <div class="mb-4 prose prose-sm">{@html prompt}</div>
38
+ {/if}
39
+
40
+ {#if model?.sentenceHtml}
41
+ <div class="mb-2 prose prose-sm">{@html model.sentenceHtml}</div>
42
+ {/if}
43
+
44
+ {#if !isAudioOnlyMode}
45
+ <div class="mb-4 prose prose-sm">
46
+ {@html parts.before}
47
+ <span class="inline-block min-w-[6rem] border-b-2 border-gray-600 print:border-black px-1">
48
+ {#if showAnswerKey && mode === 'image' && correct?.imageUrl}
49
+ <img src={correct.imageUrl} alt={correct.imageAlt || ''} class="max-h-14 object-contain" />
50
+ {:else if showAnswerKey && correct?.labelHtml}
51
+ {@html correct.labelHtml}
52
+ {:else}
53
+ ________
54
+ {/if}
55
+ </span>
56
+ {@html parts.after}
57
+ </div>
58
+ {/if}
59
+
60
+ {#if model?.hasAudio}
61
+ <div class="text-sm mb-4">
62
+ {#if model?.audioUrl}
63
+ <div><strong>Audio:</strong> {model.audioUrl}</div>
64
+ {/if}
65
+ {#if model?.audioTranscript}
66
+ <div><strong>Transcript:</strong> {model.audioTranscript}</div>
67
+ {/if}
68
+ </div>
69
+ {/if}
70
+
71
+ <ul class="text-sm list-disc pl-5">
72
+ {#each choices as c}
73
+ <li>
74
+ {#if mode === 'image'}
75
+ <span class="font-medium">{c.id}</span>
76
+ {#if showAnswerKey && c.id === model?.correctChoiceId}(key){/if}
77
+ {:else}
78
+ {@html c.labelHtml || ''}
79
+ {#if showAnswerKey && c.id === model?.correctChoiceId}
80
+ <span class="font-medium"> (key)</span>
81
+ {/if}
82
+ {/if}
83
+ </li>
84
+ {/each}
85
+ </ul>
86
+ </div>
87
+
88
+ <style>
89
+ .prose :global(p) {
90
+ margin: 0.5em 0;
91
+ }
92
+ .prose :global(strong) {
93
+ font-weight: 600;
94
+ }
95
+ </style>
@@ -0,0 +1,18 @@
1
+ import PrintComponent from './Print.svelte';
2
+
3
+ const SvelteElementClass = (PrintComponent as any).element;
4
+
5
+ class McPopulatedBlankPrint extends SvelteElementClass {
6
+ private _model: any = null;
7
+
8
+ set model(m: any) {
9
+ this._model = m;
10
+ super.model = m;
11
+ }
12
+
13
+ get model() {
14
+ return this._model;
15
+ }
16
+ }
17
+
18
+ export default McPopulatedBlankPrint;