@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.
- package/LICENSE.md +674 -0
- package/dist/abstract/interaction.d.ts +87 -0
- package/dist/abstract/interaction.js +371 -0
- package/dist/abstract/interaction.js.map +1 -0
- package/dist/abstract/qti-condition-expression.d.ts +5 -0
- package/dist/abstract/qti-condition-expression.js +11 -0
- package/dist/abstract/qti-condition-expression.js.map +1 -0
- package/dist/abstract/qti-expression.d.ts +17 -0
- package/dist/abstract/qti-expression.js +141 -0
- package/dist/abstract/qti-expression.js.map +1 -0
- package/dist/abstract/qti-feedback.d.ts +11 -0
- package/dist/abstract/qti-feedback.js +58 -0
- package/dist/abstract/qti-feedback.js.map +1 -0
- package/dist/abstract/qti-variable-declaration.d.ts +6 -0
- package/dist/abstract/qti-variable-declaration.js +18 -0
- package/dist/abstract/qti-variable-declaration.js.map +1 -0
- package/dist/context/computed-item.context.d.ts +19 -0
- package/dist/context/computed-item.context.js +3 -0
- package/dist/context/computed-item.context.js.map +1 -0
- package/dist/context/computed.context.d.ts +29 -0
- package/dist/context/computed.context.js +3 -0
- package/dist/context/computed.context.js.map +1 -0
- package/dist/context/config.context.d.ts +12 -0
- package/dist/context/config.context.js +3 -0
- package/dist/context/config.context.js.map +1 -0
- package/dist/context/item.context.d.ts +12 -0
- package/dist/context/item.context.js +17 -0
- package/dist/context/item.context.js.map +1 -0
- package/dist/context/qti-assessment-item.context.d.ts +4 -0
- package/dist/context/qti-assessment-item.context.js +3 -0
- package/dist/context/qti-assessment-item.context.js.map +1 -0
- package/dist/context/qti.context.d.ts +12 -0
- package/dist/context/qti.context.js +3 -0
- package/dist/context/qti.context.js.map +1 -0
- package/dist/context/session.context.d.ts +13 -0
- package/dist/context/session.context.js +4 -0
- package/dist/context/session.context.js.map +1 -0
- package/dist/context/test.context.d.ts +12 -0
- package/dist/context/test.context.js +4 -0
- package/dist/context/test.context.js.map +1 -0
- package/dist/index.d.ts +19 -0
- package/dist/index.js +20 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/expression-result.d.ts +18 -0
- package/dist/lib/expression-result.js +2 -0
- package/dist/lib/expression-result.js.map +1 -0
- package/dist/lib/interaction.interface.d.ts +20 -0
- package/dist/lib/interaction.interface.js +2 -0
- package/dist/lib/interaction.interface.js.map +1 -0
- package/dist/lib/qti-rule-base.d.ts +13 -0
- package/dist/lib/qti-rule-base.js +7 -0
- package/dist/lib/qti-rule-base.js.map +1 -0
- package/dist/lib/variables.d.ts +50 -0
- package/dist/lib/variables.js +2 -0
- package/dist/lib/variables.js.map +1 -0
- package/dist/utils/scoring-helper.d.ts +25 -0
- package/dist/utils/scoring-helper.js +129 -0
- package/dist/utils/scoring-helper.js.map +1 -0
- package/dist/utils/utils.d.ts +4 -0
- package/dist/utils/utils.js +28 -0
- package/dist/utils/utils.js.map +1 -0
- 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,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
|
+
}
|