@qti-components/base 1.0.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.
Files changed (62) hide show
  1. package/LICENSE.md +674 -0
  2. package/dist/abstract/interaction.d.ts +87 -0
  3. package/dist/abstract/interaction.js +371 -0
  4. package/dist/abstract/interaction.js.map +1 -0
  5. package/dist/abstract/qti-condition-expression.d.ts +5 -0
  6. package/dist/abstract/qti-condition-expression.js +11 -0
  7. package/dist/abstract/qti-condition-expression.js.map +1 -0
  8. package/dist/abstract/qti-expression.d.ts +17 -0
  9. package/dist/abstract/qti-expression.js +141 -0
  10. package/dist/abstract/qti-expression.js.map +1 -0
  11. package/dist/abstract/qti-feedback.d.ts +11 -0
  12. package/dist/abstract/qti-feedback.js +58 -0
  13. package/dist/abstract/qti-feedback.js.map +1 -0
  14. package/dist/abstract/qti-variable-declaration.d.ts +6 -0
  15. package/dist/abstract/qti-variable-declaration.js +18 -0
  16. package/dist/abstract/qti-variable-declaration.js.map +1 -0
  17. package/dist/context/computed-item.context.d.ts +19 -0
  18. package/dist/context/computed-item.context.js +3 -0
  19. package/dist/context/computed-item.context.js.map +1 -0
  20. package/dist/context/computed.context.d.ts +29 -0
  21. package/dist/context/computed.context.js +3 -0
  22. package/dist/context/computed.context.js.map +1 -0
  23. package/dist/context/config.context.d.ts +12 -0
  24. package/dist/context/config.context.js +3 -0
  25. package/dist/context/config.context.js.map +1 -0
  26. package/dist/context/item.context.d.ts +12 -0
  27. package/dist/context/item.context.js +17 -0
  28. package/dist/context/item.context.js.map +1 -0
  29. package/dist/context/qti-assessment-item.context.d.ts +4 -0
  30. package/dist/context/qti-assessment-item.context.js +3 -0
  31. package/dist/context/qti-assessment-item.context.js.map +1 -0
  32. package/dist/context/qti.context.d.ts +12 -0
  33. package/dist/context/qti.context.js +3 -0
  34. package/dist/context/qti.context.js.map +1 -0
  35. package/dist/context/session.context.d.ts +13 -0
  36. package/dist/context/session.context.js +4 -0
  37. package/dist/context/session.context.js.map +1 -0
  38. package/dist/context/test.context.d.ts +12 -0
  39. package/dist/context/test.context.js +4 -0
  40. package/dist/context/test.context.js.map +1 -0
  41. package/dist/index.d.ts +19 -0
  42. package/dist/index.js +20 -0
  43. package/dist/index.js.map +1 -0
  44. package/dist/lib/expression-result.d.ts +18 -0
  45. package/dist/lib/expression-result.js +2 -0
  46. package/dist/lib/expression-result.js.map +1 -0
  47. package/dist/lib/interaction.interface.d.ts +20 -0
  48. package/dist/lib/interaction.interface.js +2 -0
  49. package/dist/lib/interaction.interface.js.map +1 -0
  50. package/dist/lib/qti-rule-base.d.ts +13 -0
  51. package/dist/lib/qti-rule-base.js +7 -0
  52. package/dist/lib/qti-rule-base.js.map +1 -0
  53. package/dist/lib/variables.d.ts +50 -0
  54. package/dist/lib/variables.js +2 -0
  55. package/dist/lib/variables.js.map +1 -0
  56. package/dist/utils/scoring-helper.d.ts +25 -0
  57. package/dist/utils/scoring-helper.js +129 -0
  58. package/dist/utils/scoring-helper.js.map +1 -0
  59. package/dist/utils/utils.d.ts +4 -0
  60. package/dist/utils/utils.js +28 -0
  61. package/dist/utils/utils.js.map +1 -0
  62. package/package.json +38 -0
@@ -0,0 +1,87 @@
1
+ import { LitElement } from 'lit';
2
+ import type { ConfigContext } from '../context/config.context';
3
+ import type { ResponseVariable } from '../lib/variables';
4
+ import type { IInteraction } from '../lib/interaction.interface';
5
+ export declare enum Correctness {
6
+ Correct = "correct",
7
+ PartiallyCorrect = "partially-correct",
8
+ Incorrect = "incorrect"
9
+ }
10
+ export declare abstract class Interaction extends LitElement implements IInteraction {
11
+ private _context;
12
+ protected configContext: ConfigContext;
13
+ static formAssociated: boolean;
14
+ protected _internals: ElementInternals;
15
+ get internals(): ElementInternals;
16
+ responseIdentifier: string;
17
+ disabled: boolean;
18
+ readonly: boolean;
19
+ name: any;
20
+ /**
21
+ * The correct response for this interaction. Can be set as a comma-separated
22
+ * string via attribute or as string/string[] via property.
23
+ *
24
+ * @example
25
+ * ```html
26
+ * <qti-choice-interaction correct-response="A,B">
27
+ * ```
28
+ */
29
+ set correctResponseAttr(val: string | null);
30
+ get correctResponseAttr(): string | null;
31
+ /**
32
+ * Shows which choices are correct with inline indicators.
33
+ * Adds `correct-response` / `incorrect-response` states to choices.
34
+ */
35
+ showCorrectResponse: boolean;
36
+ protected _handleShowCorrectResponseChange: (_: boolean, show: boolean) => void;
37
+ /**
38
+ * Shows a cloned interaction with the correct answers filled in.
39
+ * Creates a disabled copy positioned after this interaction.
40
+ */
41
+ showFullCorrectResponse: boolean;
42
+ protected _handleShowFullCorrectResponseChange: (_: boolean, show: boolean) => void;
43
+ /**
44
+ * Shows feedback on candidate's selections compared to correct response.
45
+ * Adds `candidate-correct` / `candidate-incorrect` states to choices.
46
+ */
47
+ showCandidateCorrection: boolean;
48
+ protected _handleShowCandidateCorrectionChange: (_: boolean, show: boolean) => void;
49
+ protected _isFullCorrectResponse: boolean;
50
+ get isFullCorrectResponse(): Readonly<boolean>;
51
+ set isFullCorrectResponse(val: Readonly<boolean>);
52
+ protected _correctResponse: string | string[] | null;
53
+ /**
54
+ * Get/set correct response programmatically.
55
+ * This property syncs with the `correct-response` attribute.
56
+ */
57
+ get correctResponse(): Readonly<string | string[] | null>;
58
+ set correctResponse(val: Readonly<string | string[] | null>);
59
+ /**
60
+ * Returns the correctness of the current response compared to correct response.
61
+ * Works in both standalone mode (using `correct-response` attribute) and
62
+ * item context mode (using responseVariable).
63
+ */
64
+ get correctness(): Readonly<Correctness | null>;
65
+ get isInline(): boolean;
66
+ get responseVariable(): ResponseVariable | undefined;
67
+ toggleCorrectResponse(show: boolean): void;
68
+ protected toggleFullCorrectResponse(show: boolean): Promise<void>;
69
+ protected toggleInternalCorrectResponse(show: boolean): void;
70
+ toggleCandidateCorrection(show: boolean): void;
71
+ constructor();
72
+ abstract validate(): boolean;
73
+ get value(): string | null;
74
+ set value(val: string | null);
75
+ abstract get response(): string | string[] | null;
76
+ abstract set response(val: string | string[] | null);
77
+ reportValidity(): boolean;
78
+ reset(): void;
79
+ /**
80
+ * Called by the browser when the associated form is reset.
81
+ * Part of the Form-Associated Custom Elements API.
82
+ */
83
+ formResetCallback(): void;
84
+ connectedCallback(): void;
85
+ protected firstUpdated(): void;
86
+ saveResponse(value: string | string[], state?: string | null): void;
87
+ }
@@ -0,0 +1,371 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ import { property, state } from 'lit/decorators.js';
8
+ import { LitElement } from 'lit';
9
+ import { consume } from '@lit/context';
10
+ import { watch } from '@qti-components/utilities';
11
+ import { configContext } from '../context/config.context';
12
+ import { itemContext } from '../context/qti-assessment-item.context';
13
+ export var Correctness;
14
+ (function (Correctness) {
15
+ Correctness["Correct"] = "correct";
16
+ Correctness["PartiallyCorrect"] = "partially-correct";
17
+ Correctness["Incorrect"] = "incorrect";
18
+ })(Correctness || (Correctness = {}));
19
+ export class Interaction extends LitElement {
20
+ static { this.formAssociated = true; }
21
+ get internals() {
22
+ return this._internals;
23
+ }
24
+ // ═══════════════════════════════════════════════════════════════════════════════
25
+ // CORRECT RESPONSE - Standalone mode attributes
26
+ // ═══════════════════════════════════════════════════════════════════════════════
27
+ /**
28
+ * The correct response for this interaction. Can be set as a comma-separated
29
+ * string via attribute or as string/string[] via property.
30
+ *
31
+ * @example
32
+ * ```html
33
+ * <qti-choice-interaction correct-response="A,B">
34
+ * ```
35
+ */
36
+ set correctResponseAttr(val) {
37
+ if (val === null) {
38
+ this._correctResponse = null;
39
+ }
40
+ else if (val.includes(',')) {
41
+ this._correctResponse = val.split(',').map(v => v.trim());
42
+ }
43
+ else {
44
+ this._correctResponse = val;
45
+ }
46
+ }
47
+ get correctResponseAttr() {
48
+ if (this._correctResponse === null || this._correctResponse === undefined) {
49
+ return null;
50
+ }
51
+ return Array.isArray(this._correctResponse) ? this._correctResponse.join(',') : this._correctResponse;
52
+ }
53
+ get isFullCorrectResponse() {
54
+ return this._isFullCorrectResponse;
55
+ }
56
+ set isFullCorrectResponse(val) {
57
+ this._isFullCorrectResponse = val;
58
+ if (val) {
59
+ this.disabled = true;
60
+ this.setAttribute('inert', '');
61
+ this.setAttribute('response-identifier', this.responseIdentifier + '_cr');
62
+ }
63
+ }
64
+ /**
65
+ * Get/set correct response programmatically.
66
+ * This property syncs with the `correct-response` attribute.
67
+ */
68
+ get correctResponse() {
69
+ // In standalone mode, use the local _correctResponse
70
+ // In item context mode, prefer responseVariable.correctResponse
71
+ const responseVariable = this.responseVariable;
72
+ if (responseVariable?.correctResponse) {
73
+ return responseVariable.correctResponse;
74
+ }
75
+ return this._correctResponse;
76
+ }
77
+ set correctResponse(val) {
78
+ const oldVal = this._correctResponse;
79
+ this._correctResponse = val;
80
+ // Sync to attribute
81
+ if (val === null || val === undefined) {
82
+ this.removeAttribute('correct-response');
83
+ }
84
+ else {
85
+ this.setAttribute('correct-response', Array.isArray(val) ? val.join(',') : val);
86
+ }
87
+ this.requestUpdate('_correctResponse', oldVal);
88
+ }
89
+ /**
90
+ * Returns the correctness of the current response compared to correct response.
91
+ * Works in both standalone mode (using `correct-response` attribute) and
92
+ * item context mode (using responseVariable).
93
+ */
94
+ get correctness() {
95
+ const correctResponse = this.correctResponse;
96
+ if (!correctResponse)
97
+ return null;
98
+ const currentResponse = this.response;
99
+ // No response yet (null, undefined, empty string, or empty array)
100
+ if (currentResponse === null ||
101
+ currentResponse === undefined ||
102
+ currentResponse === '' ||
103
+ (Array.isArray(currentResponse) && currentResponse.length === 0)) {
104
+ return null;
105
+ }
106
+ // Normalize both to arrays for comparison
107
+ const correctArr = Array.isArray(correctResponse) ? correctResponse : [correctResponse];
108
+ const responseArr = Array.isArray(currentResponse) ? currentResponse : [currentResponse];
109
+ // Filter out empty strings
110
+ const filteredResponseArr = responseArr.filter(r => r !== '');
111
+ if (filteredResponseArr.length === 0)
112
+ return null;
113
+ // Check for partial correctness - some correct selections but not all, or extra incorrect selections
114
+ const correctCount = filteredResponseArr.filter(r => correctArr.includes(r)).length;
115
+ const incorrectCount = filteredResponseArr.filter(r => !correctArr.includes(r)).length;
116
+ // All responses are correct and we have all correct answers
117
+ if (correctCount === correctArr.length &&
118
+ incorrectCount === 0 &&
119
+ filteredResponseArr.length === correctArr.length) {
120
+ return Correctness.Correct;
121
+ }
122
+ // Some correct responses but not complete or has incorrect responses
123
+ if (correctCount > 0 && (correctCount < correctArr.length || incorrectCount > 0)) {
124
+ return Correctness.PartiallyCorrect;
125
+ }
126
+ return Correctness.Incorrect;
127
+ }
128
+ get isInline() {
129
+ return false;
130
+ }
131
+ get responseVariable() {
132
+ // In standalone mode (no item context), return undefined
133
+ if (!this._context?.variables) {
134
+ return undefined;
135
+ }
136
+ // Get all response variables
137
+ const responseVariables = this._context.variables.filter(v => v.type === 'response');
138
+ // Get the response identifier for this interaction
139
+ const responseIdentifier = this.getAttribute('response-identifier');
140
+ // Return the matching response variable for this interaction
141
+ return responseVariables.find(v => v.identifier === responseIdentifier);
142
+ }
143
+ toggleCorrectResponse(show) {
144
+ const correctResponseMode = this?.configContext?.correctResponseMode || 'internal';
145
+ if (correctResponseMode === 'full') {
146
+ this.toggleFullCorrectResponse(show);
147
+ }
148
+ else {
149
+ this.toggleInternalCorrectResponse(show);
150
+ }
151
+ }
152
+ async toggleFullCorrectResponse(show) {
153
+ const nextSibling = this.nextSibling;
154
+ const nextSiblingIsFullCorrectResponse = nextSibling instanceof HTMLDivElement && nextSibling?.classList.contains('full-correct-response');
155
+ // Get correct response from either responseVariable (item context) or local property (standalone)
156
+ const correctResponse = this.correctResponse;
157
+ if (!correctResponse) {
158
+ return;
159
+ }
160
+ const showFullCorrectResponse = show &&
161
+ (this?.configContext?.fullCorrectResponseOnlyWhenIncorrect === false || this.correctness !== Correctness.Correct);
162
+ if (!showFullCorrectResponse) {
163
+ if (!nextSiblingIsFullCorrectResponse) {
164
+ return;
165
+ }
166
+ // Remove cloned interaction
167
+ this.parentElement?.removeChild(nextSibling);
168
+ return;
169
+ }
170
+ if (nextSiblingIsFullCorrectResponse) {
171
+ return; // Already exists
172
+ }
173
+ // Add a clone of interaction with the correct response
174
+ const clone = this.cloneNode(true);
175
+ // Remove attributes that could cause issues on the clone
176
+ clone.removeAttribute('show-full-correct-response');
177
+ clone.removeAttribute('show-correct-response');
178
+ clone.removeAttribute('show-candidate-correction');
179
+ const containerDiv = document.createElement('div');
180
+ containerDiv.classList.add('full-correct-response');
181
+ if (this.isInline) {
182
+ containerDiv.classList.add('full-correct-response-inline');
183
+ }
184
+ else {
185
+ containerDiv.classList.add('full-correct-response-block');
186
+ }
187
+ containerDiv.role = 'full-correct-response';
188
+ containerDiv.appendChild(clone);
189
+ clone.isFullCorrectResponse = true;
190
+ this.parentElement?.insertBefore(containerDiv, this.nextSibling);
191
+ await clone.updateComplete;
192
+ clone.response = Array.isArray(correctResponse) ? [...correctResponse] : correctResponse;
193
+ }
194
+ toggleInternalCorrectResponse(show) {
195
+ // This method is meant to be overridden by mixins like ChoicesMixin
196
+ // In the base class, we just update internal state for CSS states
197
+ this._internals.states.delete('show-correct-response');
198
+ if (show && this.correctResponse) {
199
+ this._internals.states.add('show-correct-response');
200
+ }
201
+ }
202
+ toggleCandidateCorrection(show) {
203
+ this._internals.states.delete('candidate-correct');
204
+ this._internals.states.delete('candidate-partially-correct');
205
+ this._internals.states.delete('candidate-incorrect');
206
+ if (!show) {
207
+ return;
208
+ }
209
+ // correctness getter now works in both standalone and item context modes
210
+ if (this.correctness === Correctness.Correct) {
211
+ this._internals.states.add('candidate-correct');
212
+ }
213
+ if (this.correctness === Correctness.PartiallyCorrect) {
214
+ this._internals.states.add('candidate-partially-correct');
215
+ }
216
+ if (this.correctness === Correctness.Incorrect) {
217
+ this._internals.states.add('candidate-incorrect');
218
+ }
219
+ }
220
+ constructor() {
221
+ super();
222
+ this.disabled = false;
223
+ this.readonly = false;
224
+ /**
225
+ * Shows which choices are correct with inline indicators.
226
+ * Adds `correct-response` / `incorrect-response` states to choices.
227
+ */
228
+ this.showCorrectResponse = false;
229
+ this._handleShowCorrectResponseChange = (_, show) => {
230
+ this.toggleInternalCorrectResponse(show);
231
+ };
232
+ /**
233
+ * Shows a cloned interaction with the correct answers filled in.
234
+ * Creates a disabled copy positioned after this interaction.
235
+ */
236
+ this.showFullCorrectResponse = false;
237
+ this._handleShowFullCorrectResponseChange = (_, show) => {
238
+ this.toggleFullCorrectResponse(show);
239
+ };
240
+ /**
241
+ * Shows feedback on candidate's selections compared to correct response.
242
+ * Adds `candidate-correct` / `candidate-incorrect` states to choices.
243
+ */
244
+ this.showCandidateCorrection = false;
245
+ this._handleShowCandidateCorrectionChange = (_, show) => {
246
+ this.toggleCandidateCorrection(show);
247
+ };
248
+ /* PK: Correct response */
249
+ this._correctResponse = null;
250
+ this._internals = this.attachInternals();
251
+ }
252
+ get value() {
253
+ return JSON.stringify(this.response);
254
+ }
255
+ set value(val) {
256
+ this.response = val ? JSON.parse(val) : null;
257
+ }
258
+ reportValidity() {
259
+ return this._internals.reportValidity();
260
+ }
261
+ reset() {
262
+ this.response = null;
263
+ }
264
+ /**
265
+ * Called by the browser when the associated form is reset.
266
+ * Part of the Form-Associated Custom Elements API.
267
+ */
268
+ formResetCallback() {
269
+ this.reset();
270
+ }
271
+ // attributeChangedCallback(name: string, _old: string | null, value: string | null): void {
272
+ // super.attributeChangedCallback(name, _old, value);
273
+ // // changing attributes in lit is not a thing, they are defined in the QTI XML and will never change
274
+ // // except in storybook where we can change the value of the attribute
275
+ // // this can make the internal state out of sync with the attribute
276
+ // // so we reset the value to null to force the internal state to be reset
277
+ // const attributeNamesToExclude = ['style', 'class'];
278
+ // if (!attributeNamesToExclude.includes(name)) {
279
+ // this.reset();
280
+ // }
281
+ // }
282
+ connectedCallback() {
283
+ super.connectedCallback();
284
+ if (this.isFullCorrectResponse) {
285
+ return;
286
+ }
287
+ this.dispatchEvent(new CustomEvent('qti-register-interaction', {
288
+ bubbles: true,
289
+ composed: true,
290
+ cancelable: false,
291
+ detail: {
292
+ interactionElement: this,
293
+ responseIdentifier: this.responseIdentifier
294
+ }
295
+ }));
296
+ }
297
+ firstUpdated() {
298
+ // Skip for full correct response clones to avoid infinite loops
299
+ if (this.isFullCorrectResponse) {
300
+ return;
301
+ }
302
+ // Apply initial correct response display states after first render
303
+ if (this.showCorrectResponse) {
304
+ this.toggleInternalCorrectResponse(true);
305
+ }
306
+ if (this.showFullCorrectResponse) {
307
+ this.toggleFullCorrectResponse(true);
308
+ }
309
+ if (this.showCandidateCorrection) {
310
+ this.toggleCandidateCorrection(true);
311
+ }
312
+ }
313
+ saveResponse(value, state) {
314
+ this.dispatchEvent(new CustomEvent('qti-interaction-response', {
315
+ bubbles: true,
316
+ composed: true,
317
+ cancelable: false,
318
+ detail: {
319
+ responseIdentifier: this.responseIdentifier,
320
+ response: Array.isArray(value) ? [...value] : value,
321
+ ...(state !== undefined ? { state } : {})
322
+ }
323
+ }));
324
+ }
325
+ }
326
+ __decorate([
327
+ consume({ context: itemContext, subscribe: true })
328
+ ], Interaction.prototype, "_context", void 0);
329
+ __decorate([
330
+ consume({ context: configContext, subscribe: true })
331
+ ], Interaction.prototype, "configContext", void 0);
332
+ __decorate([
333
+ property({ type: String, attribute: 'response-identifier' })
334
+ ], Interaction.prototype, "responseIdentifier", void 0);
335
+ __decorate([
336
+ property({ reflect: true, type: Boolean })
337
+ ], Interaction.prototype, "disabled", void 0);
338
+ __decorate([
339
+ property({ reflect: true, type: Boolean })
340
+ ], Interaction.prototype, "readonly", void 0);
341
+ __decorate([
342
+ property({ type: String })
343
+ ], Interaction.prototype, "name", void 0);
344
+ __decorate([
345
+ property({ type: String, attribute: 'correct-response', reflect: true })
346
+ ], Interaction.prototype, "correctResponseAttr", null);
347
+ __decorate([
348
+ property({ type: Boolean, attribute: 'show-correct-response', reflect: true })
349
+ ], Interaction.prototype, "showCorrectResponse", void 0);
350
+ __decorate([
351
+ watch('showCorrectResponse', { waitUntilFirstUpdate: true })
352
+ ], Interaction.prototype, "_handleShowCorrectResponseChange", void 0);
353
+ __decorate([
354
+ property({ type: Boolean, attribute: 'show-full-correct-response', reflect: true })
355
+ ], Interaction.prototype, "showFullCorrectResponse", void 0);
356
+ __decorate([
357
+ watch('showFullCorrectResponse', { waitUntilFirstUpdate: true })
358
+ ], Interaction.prototype, "_handleShowFullCorrectResponseChange", void 0);
359
+ __decorate([
360
+ property({ type: Boolean, attribute: 'show-candidate-correction', reflect: true })
361
+ ], Interaction.prototype, "showCandidateCorrection", void 0);
362
+ __decorate([
363
+ watch('showCandidateCorrection', { waitUntilFirstUpdate: true })
364
+ ], Interaction.prototype, "_handleShowCandidateCorrectionChange", void 0);
365
+ __decorate([
366
+ state()
367
+ ], Interaction.prototype, "_isFullCorrectResponse", void 0);
368
+ __decorate([
369
+ state()
370
+ ], Interaction.prototype, "_correctResponse", void 0);
371
+ //# sourceMappingURL=interaction.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"interaction.js","sourceRoot":"","sources":["../../src/abstract/interaction.ts"],"names":[],"mappings":"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","sourcesContent":["import { property, state } from 'lit/decorators.js';\nimport { LitElement } from 'lit';\nimport { consume } from '@lit/context';\n\nimport { watch } from '@qti-components/utilities';\n\nimport { configContext } from '../context/config.context';\nimport { itemContext } from '../context/qti-assessment-item.context';\n\nimport type { ConfigContext } from '../context/config.context';\nimport type { ResponseVariable } from '../lib/variables';\nimport type { IInteraction } from '../lib/interaction.interface';\nimport type { ItemContext } from '../context/item.context';\n\nexport enum Correctness {\n Correct = 'correct',\n PartiallyCorrect = 'partially-correct',\n Incorrect = 'incorrect'\n}\n\nexport abstract class Interaction extends LitElement implements IInteraction {\n @consume({ context: itemContext, subscribe: true })\n private _context: ItemContext;\n\n @consume({ context: configContext, subscribe: true })\n protected configContext: ConfigContext;\n\n static formAssociated = true;\n protected _internals: ElementInternals;\n\n get internals(): ElementInternals {\n return this._internals;\n }\n\n @property({ type: String, attribute: 'response-identifier' }) responseIdentifier: string;\n\n @property({ reflect: true, type: Boolean }) disabled = false;\n\n @property({ reflect: true, type: Boolean }) readonly = false;\n\n @property({ type: String }) name;\n\n // ═══════════════════════════════════════════════════════════════════════════════\n // CORRECT RESPONSE - Standalone mode attributes\n // ═══════════════════════════════════════════════════════════════════════════════\n\n /**\n * The correct response for this interaction. Can be set as a comma-separated\n * string via attribute or as string/string[] via property.\n *\n * @example\n * ```html\n * <qti-choice-interaction correct-response=\"A,B\">\n * ```\n */\n @property({ type: String, attribute: 'correct-response', reflect: true })\n set correctResponseAttr(val: string | null) {\n if (val === null) {\n this._correctResponse = null;\n } else if (val.includes(',')) {\n this._correctResponse = val.split(',').map(v => v.trim());\n } else {\n this._correctResponse = val;\n }\n }\n\n get correctResponseAttr(): string | null {\n if (this._correctResponse === null || this._correctResponse === undefined) {\n return null;\n }\n return Array.isArray(this._correctResponse) ? this._correctResponse.join(',') : this._correctResponse;\n }\n\n /**\n * Shows which choices are correct with inline indicators.\n * Adds `correct-response` / `incorrect-response` states to choices.\n */\n @property({ type: Boolean, attribute: 'show-correct-response', reflect: true })\n showCorrectResponse = false;\n\n @watch('showCorrectResponse', { waitUntilFirstUpdate: true })\n protected _handleShowCorrectResponseChange = (_: boolean, show: boolean) => {\n this.toggleInternalCorrectResponse(show);\n };\n\n /**\n * Shows a cloned interaction with the correct answers filled in.\n * Creates a disabled copy positioned after this interaction.\n */\n @property({ type: Boolean, attribute: 'show-full-correct-response', reflect: true })\n showFullCorrectResponse = false;\n\n @watch('showFullCorrectResponse', { waitUntilFirstUpdate: true })\n protected _handleShowFullCorrectResponseChange = (_: boolean, show: boolean) => {\n this.toggleFullCorrectResponse(show);\n };\n\n /**\n * Shows feedback on candidate's selections compared to correct response.\n * Adds `candidate-correct` / `candidate-incorrect` states to choices.\n */\n @property({ type: Boolean, attribute: 'show-candidate-correction', reflect: true })\n showCandidateCorrection = false;\n\n @watch('showCandidateCorrection', { waitUntilFirstUpdate: true })\n protected _handleShowCandidateCorrectionChange = (_: boolean, show: boolean) => {\n this.toggleCandidateCorrection(show);\n };\n\n // ═══════════════════════════════════════════════════════════════════════════════\n\n @state()\n protected _isFullCorrectResponse: boolean;\n\n get isFullCorrectResponse(): Readonly<boolean> {\n return this._isFullCorrectResponse;\n }\n\n set isFullCorrectResponse(val: Readonly<boolean>) {\n this._isFullCorrectResponse = val as boolean;\n if (val) {\n this.disabled = true;\n this.setAttribute('inert', '');\n this.setAttribute('response-identifier', this.responseIdentifier + '_cr');\n }\n }\n\n /* PK: Correct response */\n @state()\n protected _correctResponse: string | string[] | null = null;\n\n /**\n * Get/set correct response programmatically.\n * This property syncs with the `correct-response` attribute.\n */\n get correctResponse(): Readonly<string | string[] | null> {\n // In standalone mode, use the local _correctResponse\n // In item context mode, prefer responseVariable.correctResponse\n const responseVariable = this.responseVariable;\n if (responseVariable?.correctResponse) {\n return responseVariable.correctResponse;\n }\n return this._correctResponse;\n }\n\n set correctResponse(val: Readonly<string | string[] | null>) {\n const oldVal = this._correctResponse;\n this._correctResponse = val as string | string[] | null;\n // Sync to attribute\n if (val === null || val === undefined) {\n this.removeAttribute('correct-response');\n } else {\n this.setAttribute('correct-response', Array.isArray(val) ? val.join(',') : (val as string));\n }\n this.requestUpdate('_correctResponse', oldVal);\n }\n\n /**\n * Returns the correctness of the current response compared to correct response.\n * Works in both standalone mode (using `correct-response` attribute) and\n * item context mode (using responseVariable).\n */\n get correctness(): Readonly<Correctness | null> {\n const correctResponse = this.correctResponse;\n if (!correctResponse) return null;\n\n const currentResponse = this.response;\n // No response yet (null, undefined, empty string, or empty array)\n if (\n currentResponse === null ||\n currentResponse === undefined ||\n currentResponse === '' ||\n (Array.isArray(currentResponse) && currentResponse.length === 0)\n ) {\n return null;\n }\n\n // Normalize both to arrays for comparison\n const correctArr = Array.isArray(correctResponse) ? correctResponse : [correctResponse];\n const responseArr = Array.isArray(currentResponse) ? currentResponse : [currentResponse];\n\n // Filter out empty strings\n const filteredResponseArr = responseArr.filter(r => r !== '');\n if (filteredResponseArr.length === 0) return null;\n\n // Check for partial correctness - some correct selections but not all, or extra incorrect selections\n const correctCount = filteredResponseArr.filter(r => correctArr.includes(r)).length;\n const incorrectCount = filteredResponseArr.filter(r => !correctArr.includes(r)).length;\n\n // All responses are correct and we have all correct answers\n if (\n correctCount === correctArr.length &&\n incorrectCount === 0 &&\n filteredResponseArr.length === correctArr.length\n ) {\n return Correctness.Correct;\n }\n\n // Some correct responses but not complete or has incorrect responses\n if (correctCount > 0 && (correctCount < correctArr.length || incorrectCount > 0)) {\n return Correctness.PartiallyCorrect;\n }\n\n return Correctness.Incorrect;\n }\n\n get isInline(): boolean {\n return false;\n }\n\n get responseVariable(): ResponseVariable | undefined {\n // In standalone mode (no item context), return undefined\n if (!this._context?.variables) {\n return undefined;\n }\n\n // Get all response variables\n const responseVariables = this._context.variables.filter(v => v.type === 'response') as ResponseVariable[];\n\n // Get the response identifier for this interaction\n const responseIdentifier = this.getAttribute('response-identifier');\n\n // Return the matching response variable for this interaction\n return responseVariables.find(v => v.identifier === responseIdentifier);\n }\n\n public toggleCorrectResponse(show: boolean): void {\n const correctResponseMode = this?.configContext?.correctResponseMode || 'internal';\n\n if (correctResponseMode === 'full') {\n this.toggleFullCorrectResponse(show);\n } else {\n this.toggleInternalCorrectResponse(show);\n }\n }\n\n protected async toggleFullCorrectResponse(show: boolean): Promise<void> {\n const nextSibling = this.nextSibling;\n const nextSiblingIsFullCorrectResponse =\n nextSibling instanceof HTMLDivElement && nextSibling?.classList.contains('full-correct-response');\n\n // Get correct response from either responseVariable (item context) or local property (standalone)\n const correctResponse = this.correctResponse;\n\n if (!correctResponse) {\n return;\n }\n\n const showFullCorrectResponse =\n show &&\n (this?.configContext?.fullCorrectResponseOnlyWhenIncorrect === false || this.correctness !== Correctness.Correct);\n\n if (!showFullCorrectResponse) {\n if (!nextSiblingIsFullCorrectResponse) {\n return;\n }\n // Remove cloned interaction\n this.parentElement?.removeChild(nextSibling);\n return;\n }\n\n if (nextSiblingIsFullCorrectResponse) {\n return; // Already exists\n }\n\n // Add a clone of interaction with the correct response\n const clone = this.cloneNode(true) as Interaction;\n\n // Remove attributes that could cause issues on the clone\n clone.removeAttribute('show-full-correct-response');\n clone.removeAttribute('show-correct-response');\n clone.removeAttribute('show-candidate-correction');\n\n const containerDiv = document.createElement('div');\n containerDiv.classList.add('full-correct-response');\n if (this.isInline) {\n containerDiv.classList.add('full-correct-response-inline');\n } else {\n containerDiv.classList.add('full-correct-response-block');\n }\n containerDiv.role = 'full-correct-response';\n containerDiv.appendChild(clone);\n\n clone.isFullCorrectResponse = true;\n\n this.parentElement?.insertBefore(containerDiv, this.nextSibling);\n await clone.updateComplete;\n\n clone.response = Array.isArray(correctResponse) ? ([...correctResponse] as string[]) : (correctResponse as string);\n }\n\n protected toggleInternalCorrectResponse(show: boolean): void {\n // This method is meant to be overridden by mixins like ChoicesMixin\n // In the base class, we just update internal state for CSS states\n this._internals.states.delete('show-correct-response');\n if (show && this.correctResponse) {\n this._internals.states.add('show-correct-response');\n }\n }\n\n public toggleCandidateCorrection(show: boolean): void {\n this._internals.states.delete('candidate-correct');\n this._internals.states.delete('candidate-partially-correct');\n this._internals.states.delete('candidate-incorrect');\n\n if (!show) {\n return;\n }\n\n // correctness getter now works in both standalone and item context modes\n if (this.correctness === Correctness.Correct) {\n this._internals.states.add('candidate-correct');\n }\n if (this.correctness === Correctness.PartiallyCorrect) {\n this._internals.states.add('candidate-partially-correct');\n }\n if (this.correctness === Correctness.Incorrect) {\n this._internals.states.add('candidate-incorrect');\n }\n }\n\n constructor() {\n super();\n this._internals = this.attachInternals();\n }\n\n abstract validate(): boolean;\n\n get value(): string | null {\n return JSON.stringify(this.response);\n }\n\n set value(val: string | null) {\n this.response = val ? JSON.parse(val) : null;\n }\n\n abstract get response(): string | string[] | null;\n abstract set response(val: string | string[] | null);\n\n public reportValidity(): boolean {\n return this._internals.reportValidity();\n }\n\n public reset(): void {\n this.response = null;\n }\n\n /**\n * Called by the browser when the associated form is reset.\n * Part of the Form-Associated Custom Elements API.\n */\n public formResetCallback(): void {\n this.reset();\n }\n\n // attributeChangedCallback(name: string, _old: string | null, value: string | null): void {\n // super.attributeChangedCallback(name, _old, value);\n // // changing attributes in lit is not a thing, they are defined in the QTI XML and will never change\n // // except in storybook where we can change the value of the attribute\n // // this can make the internal state out of sync with the attribute\n // // so we reset the value to null to force the internal state to be reset\n // const attributeNamesToExclude = ['style', 'class'];\n // if (!attributeNamesToExclude.includes(name)) {\n // this.reset();\n // }\n // }\n\n public override connectedCallback(): void {\n super.connectedCallback();\n\n if (this.isFullCorrectResponse) {\n return;\n }\n\n this.dispatchEvent(\n new CustomEvent('qti-register-interaction', {\n bubbles: true,\n composed: true,\n cancelable: false,\n detail: {\n interactionElement: this,\n responseIdentifier: this.responseIdentifier\n }\n })\n );\n }\n\n protected override firstUpdated(): void {\n // Skip for full correct response clones to avoid infinite loops\n if (this.isFullCorrectResponse) {\n return;\n }\n\n // Apply initial correct response display states after first render\n if (this.showCorrectResponse) {\n this.toggleInternalCorrectResponse(true);\n }\n if (this.showFullCorrectResponse) {\n this.toggleFullCorrectResponse(true);\n }\n if (this.showCandidateCorrection) {\n this.toggleCandidateCorrection(true);\n }\n }\n\n public saveResponse(value: string | string[], state?: string | null): void {\n this.dispatchEvent(\n new CustomEvent('qti-interaction-response', {\n bubbles: true,\n composed: true,\n cancelable: false,\n detail: {\n responseIdentifier: this.responseIdentifier,\n response: Array.isArray(value) ? [...value] : value,\n ...(state !== undefined ? { state } : {})\n }\n })\n );\n }\n}\n"]}
@@ -0,0 +1,5 @@
1
+ import { QtiExpression } from './qti-expression';
2
+ export declare abstract class QtiConditionExpression extends QtiExpression<boolean> {
3
+ calculate(): Readonly<boolean>;
4
+ getResult(): Readonly<boolean>;
5
+ }
@@ -0,0 +1,11 @@
1
+ import { QtiExpression } from './qti-expression';
2
+ export class QtiConditionExpression extends QtiExpression {
3
+ calculate() {
4
+ this.result = this.getResult();
5
+ return this.result;
6
+ }
7
+ getResult() {
8
+ throw new Error('Not implemented');
9
+ }
10
+ }
11
+ //# sourceMappingURL=qti-condition-expression.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"qti-condition-expression.js","sourceRoot":"","sources":["../../src/abstract/qti-condition-expression.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAEjD,MAAM,OAAgB,sBAAuB,SAAQ,aAAsB;IACzD,SAAS;QACvB,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,SAAS,EAAE,CAAC;QAC/B,OAAO,IAAI,CAAC,MAAM,CAAC;IACrB,CAAC;IAEe,SAAS;QACvB,MAAM,IAAI,KAAK,CAAC,iBAAiB,CAAC,CAAC;IACrC,CAAC;CACF","sourcesContent":["import { QtiExpression } from './qti-expression';\n\nexport abstract class QtiConditionExpression extends QtiExpression<boolean> {\n public override calculate(): Readonly<boolean> {\n this.result = this.getResult();\n return this.result;\n }\n\n public override getResult(): Readonly<boolean> {\n throw new Error('Not implemented');\n }\n}\n"]}
@@ -0,0 +1,17 @@
1
+ import { LitElement } from 'lit';
2
+ import type { QtiContext, QtiContextType } from '../context/qti.context';
3
+ import type { ResponseVariable, VariableDeclaration } from '../lib/variables';
4
+ import type { ItemContext } from '../context/item.context';
5
+ export interface QtiExpressionBase<T> {
6
+ calculate(): Readonly<T>;
7
+ }
8
+ export declare abstract class QtiExpression<T> extends LitElement implements QtiExpressionBase<T> {
9
+ protected result: any;
10
+ static styles: import("lit").CSSResult;
11
+ render(): import("lit").TemplateResult<1>;
12
+ calculate(): Readonly<T>;
13
+ protected getResult(): Readonly<T>;
14
+ protected context?: ItemContext;
15
+ protected qtiContext?: QtiContext;
16
+ getVariables: () => (ResponseVariable | VariableDeclaration<QtiContextType>)[];
17
+ }