@citolab/qti-components 7.28.1 → 8.0.1
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/cdn/index.global.js +1 -1
- package/cdn/index.js +6316 -2710
- package/dist/base.d.ts +100 -15
- package/dist/base.js +27 -6
- package/dist/chunk-3AJOQCDU.js +11 -0
- package/dist/chunk-3AJOQCDU.js.map +1 -0
- package/dist/chunk-64XSIBGO.js +241 -0
- package/dist/chunk-64XSIBGO.js.map +1 -0
- package/dist/chunk-7HC5SMCU.js +102 -0
- package/dist/chunk-7HC5SMCU.js.map +1 -0
- package/dist/{chunk-SP6S2WMG.js → chunk-7V4HJFHW.js} +3 -3
- package/dist/{chunk-SP6S2WMG.js.map → chunk-7V4HJFHW.js.map} +1 -1
- package/dist/chunk-CAO4JRLY.js +11 -0
- package/dist/chunk-CAO4JRLY.js.map +1 -0
- package/dist/{chunk-MPC7LIPC.js → chunk-F4BNJWYN.js} +4264 -3647
- package/dist/chunk-F4BNJWYN.js.map +1 -0
- package/dist/{chunk-3XV26R5M.js → chunk-H3J7LFRO.js} +829 -1005
- package/dist/chunk-H3J7LFRO.js.map +1 -0
- package/dist/{chunk-3WBG257S.js → chunk-IJD53WY6.js} +96 -74
- package/dist/chunk-IJD53WY6.js.map +1 -0
- package/dist/chunk-LVBIQDPM.js +1374 -0
- package/dist/chunk-LVBIQDPM.js.map +1 -0
- package/dist/{chunk-REI3AMCZ.js → chunk-NA2N2WSG.js} +1303 -1193
- package/dist/chunk-NA2N2WSG.js.map +1 -0
- package/dist/chunk-QECOPVPO.js +294 -0
- package/dist/chunk-QECOPVPO.js.map +1 -0
- package/dist/{chunk-HFCZFWSH.js → chunk-RXGDQDOV.js} +1993 -1764
- package/dist/chunk-RXGDQDOV.js.map +1 -0
- package/dist/chunk-V5G7X53Y.js +11 -0
- package/dist/chunk-V5G7X53Y.js.map +1 -0
- package/dist/{chunk-WDO2TRFM.js → chunk-WVVMNF74.js} +851 -925
- package/dist/chunk-WVVMNF74.js.map +1 -0
- package/dist/{chunk-FLJAKWXL.js → chunk-X3E5HXG2.js} +2 -2
- package/dist/chunk-XU7HNT4F.js +1608 -0
- package/dist/chunk-XU7HNT4F.js.map +1 -0
- package/dist/{computed-item.context-DfsW_96S.d.ts → computed-item.types.d-BKZdSLLJ.d.ts} +2 -5
- package/dist/{computed.context-DHbxad0N.d.ts → computed.types.d-rKLSPvVG.d.ts} +2 -5
- package/dist/config.context.d-BvU9r-Mg.d.ts +91 -0
- package/dist/corrections.d.ts +432 -0
- package/dist/corrections.js +84 -0
- package/dist/elements.d.ts +8 -14
- package/dist/elements.js +6 -5
- package/dist/index.d.ts +51 -16
- package/dist/index.js +193 -76
- package/dist/interaction.d-D4MstYRz.d.ts +115 -0
- package/dist/interaction.interface.d-CvjHM2bi.d.ts +46 -0
- package/dist/interactions.d.ts +1206 -552
- package/dist/interactions.js +19 -15
- package/dist/item.css +4228 -1656
- package/dist/item.d.ts +13 -55
- package/dist/item.js +6 -11
- package/dist/{variables-CMYcDbyW.d.ts → item.types.d-QU7LljEK.d.ts} +13 -1
- package/dist/loader.d.ts +4 -4
- package/dist/loader.js +2 -3
- package/dist/processing.d.ts +6 -7
- package/dist/processing.js +2 -3
- package/dist/qti-components-jsx.d.ts +5348 -2709
- package/dist/qti-components-jsx.js +1 -0
- package/dist/qti-condition-expression.d-aMvBvpc6.d.ts +8 -0
- package/dist/{qti-condition-expression-Dam-RER6.d.ts → qti-expression.d-BietT_8b.d.ts} +14 -9
- package/dist/{qti-feedback-ChmXhZuf.d.ts → qti-feedback.d-DZbad0RN.d.ts} +1 -1
- package/dist/{qti-transform-test-DoZaWItm.d.ts → qti-transform-test.d-BL7GGFJj.d.ts} +2 -2
- package/dist/response.d-_8y4kjGP.d.ts +106 -0
- package/dist/test.d.ts +199 -39
- package/dist/test.js +34 -11
- package/dist/transformers.d.ts +1 -1
- package/dist/transformers.js +1 -2
- package/package.json +24 -17
- package/custom-elements.json +0 -43251
- package/dist/chunk-3WBG257S.js.map +0 -1
- package/dist/chunk-3XV26R5M.js.map +0 -1
- package/dist/chunk-AQ5RJFM6.js +0 -3673
- package/dist/chunk-AQ5RJFM6.js.map +0 -1
- package/dist/chunk-HFCZFWSH.js.map +0 -1
- package/dist/chunk-MPC7LIPC.js.map +0 -1
- package/dist/chunk-QXBXORM3.js +0 -27
- package/dist/chunk-REI3AMCZ.js.map +0 -1
- package/dist/chunk-RLTYVS2I.js +0 -530
- package/dist/chunk-RLTYVS2I.js.map +0 -1
- package/dist/chunk-WDO2TRFM.js.map +0 -1
- package/dist/config.context-BjZ2bZSY.d.ts +0 -42
- package/dist/interaction-Bgzlw7Iu.d.ts +0 -110
- package/dist/item.context-CkUeDcaO.d.ts +0 -15
- package/dist/test.context-CByZZjkR.d.ts +0 -15
- /package/dist/{chunk-FLJAKWXL.js.map → chunk-X3E5HXG2.js.map} +0 -0
- /package/dist/{chunk-QXBXORM3.js.map → corrections.js.map} +0 -0
- /package/dist/{qti-rule-base-ajOnfGXY.d.ts → qti-rule-base.d-ajOnfGXY.d.ts} +0 -0
- /package/dist/{qti.context-CejJMlfZ.d.ts → qti.context.d-CejJMlfZ.d.ts} +0 -0
|
@@ -0,0 +1,1608 @@
|
|
|
1
|
+
import {
|
|
2
|
+
QtiTest,
|
|
3
|
+
TestCheckItem,
|
|
4
|
+
TestNavigation
|
|
5
|
+
} from "./chunk-RXGDQDOV.js";
|
|
6
|
+
import {
|
|
7
|
+
QtiAssessmentItem
|
|
8
|
+
} from "./chunk-WVVMNF74.js";
|
|
9
|
+
import {
|
|
10
|
+
QtiAssociateInteraction,
|
|
11
|
+
QtiChoiceInteraction,
|
|
12
|
+
QtiExtendedTextInteraction,
|
|
13
|
+
QtiGapMatchInteraction,
|
|
14
|
+
QtiGapText,
|
|
15
|
+
QtiGraphicAssociateInteraction,
|
|
16
|
+
QtiGraphicGapMatchInteraction,
|
|
17
|
+
QtiGraphicOrderInteraction,
|
|
18
|
+
QtiHotspotChoice,
|
|
19
|
+
QtiHotspotInteraction,
|
|
20
|
+
QtiHottext,
|
|
21
|
+
QtiHottextInteraction,
|
|
22
|
+
QtiInlineChoiceInteraction,
|
|
23
|
+
QtiMatchInteraction,
|
|
24
|
+
QtiOrderInteraction,
|
|
25
|
+
QtiPortableCustomInteraction,
|
|
26
|
+
QtiSelectPointInteraction,
|
|
27
|
+
QtiSimpleAssociableChoice,
|
|
28
|
+
QtiSimpleChoice,
|
|
29
|
+
QtiSliderInteraction,
|
|
30
|
+
QtiTextEntryInteraction,
|
|
31
|
+
c as c2,
|
|
32
|
+
o
|
|
33
|
+
} from "./chunk-F4BNJWYN.js";
|
|
34
|
+
import {
|
|
35
|
+
QtiItem
|
|
36
|
+
} from "./chunk-QECOPVPO.js";
|
|
37
|
+
import {
|
|
38
|
+
watch
|
|
39
|
+
} from "./chunk-64XSIBGO.js";
|
|
40
|
+
import {
|
|
41
|
+
A,
|
|
42
|
+
ScoringHelper,
|
|
43
|
+
T,
|
|
44
|
+
b,
|
|
45
|
+
c,
|
|
46
|
+
computedContext,
|
|
47
|
+
computedItemContext,
|
|
48
|
+
configContext,
|
|
49
|
+
i,
|
|
50
|
+
i2,
|
|
51
|
+
n2 as n,
|
|
52
|
+
r,
|
|
53
|
+
responseAttributeConverter
|
|
54
|
+
} from "./chunk-H3J7LFRO.js";
|
|
55
|
+
|
|
56
|
+
// ../qti-corrections/dist/mixins/correct-response.mixin.js
|
|
57
|
+
var __decorate = function(decorators, target, key, desc) {
|
|
58
|
+
var c3 = arguments.length, r2 = c3 < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
59
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r2 = Reflect.decorate(decorators, target, key, desc);
|
|
60
|
+
else for (var i3 = decorators.length - 1; i3 >= 0; i3--) if (d = decorators[i3]) r2 = (c3 < 3 ? d(r2) : c3 > 3 ? d(target, key, r2) : d(target, key)) || r2;
|
|
61
|
+
return c3 > 3 && r2 && Object.defineProperty(target, key, r2), r2;
|
|
62
|
+
};
|
|
63
|
+
var Correctness;
|
|
64
|
+
(function(Correctness2) {
|
|
65
|
+
Correctness2["Correct"] = "correct";
|
|
66
|
+
Correctness2["PartiallyCorrect"] = "partially-correct";
|
|
67
|
+
Correctness2["Incorrect"] = "incorrect";
|
|
68
|
+
})(Correctness || (Correctness = {}));
|
|
69
|
+
var CorrectResponseMixin = (superClass) => {
|
|
70
|
+
class CorrectResponseMixinClass extends superClass {
|
|
71
|
+
constructor() {
|
|
72
|
+
super(...arguments);
|
|
73
|
+
this.showCorrectResponse = false;
|
|
74
|
+
this._handleShowCorrectResponseChange = (_, show) => {
|
|
75
|
+
this.toggleInternalCorrectResponse(show);
|
|
76
|
+
};
|
|
77
|
+
this.showFullCorrectResponse = false;
|
|
78
|
+
this._handleShowFullCorrectResponseChange = (_, show) => {
|
|
79
|
+
this.toggleFullCorrectResponse(show);
|
|
80
|
+
};
|
|
81
|
+
this.showCandidateCorrection = false;
|
|
82
|
+
this._handleShowCandidateCorrectionChange = (_, show) => {
|
|
83
|
+
this.toggleCandidateCorrection(show);
|
|
84
|
+
};
|
|
85
|
+
this._correctResponse = null;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* The correct response for this interaction. Can be set as a comma-separated
|
|
89
|
+
* string via attribute or as string/string[] via property.
|
|
90
|
+
*
|
|
91
|
+
* @example
|
|
92
|
+
* ```html
|
|
93
|
+
* <qti-choice-interaction correct-response="A,B">
|
|
94
|
+
* ```
|
|
95
|
+
*/
|
|
96
|
+
set correctResponseAttr(val) {
|
|
97
|
+
this._correctResponse = val;
|
|
98
|
+
}
|
|
99
|
+
get correctResponseAttr() {
|
|
100
|
+
return this._correctResponse;
|
|
101
|
+
}
|
|
102
|
+
get isFullCorrectResponse() {
|
|
103
|
+
return this._isFullCorrectResponse;
|
|
104
|
+
}
|
|
105
|
+
get registersWithItem() {
|
|
106
|
+
return !this.isFullCorrectResponse && super.registersWithItem;
|
|
107
|
+
}
|
|
108
|
+
set isFullCorrectResponse(val) {
|
|
109
|
+
this._isFullCorrectResponse = val;
|
|
110
|
+
if (val) {
|
|
111
|
+
this.setAttribute("inert", "");
|
|
112
|
+
this.setAttribute("response-identifier", this.responseIdentifier + "_cr");
|
|
113
|
+
this.setAttribute("answer-key", "");
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
get correctResponse() {
|
|
117
|
+
const responseVariable = this.responseVariable;
|
|
118
|
+
if (responseVariable?.correctResponse) {
|
|
119
|
+
return responseVariable.correctResponse;
|
|
120
|
+
}
|
|
121
|
+
return this._correctResponse;
|
|
122
|
+
}
|
|
123
|
+
set correctResponse(val) {
|
|
124
|
+
const oldVal = this._correctResponse;
|
|
125
|
+
this._correctResponse = val;
|
|
126
|
+
if (val === null || val === void 0) {
|
|
127
|
+
this.removeAttribute("correct-response");
|
|
128
|
+
} else {
|
|
129
|
+
this.setAttribute("correct-response", Array.isArray(val) ? val.join(",") : val);
|
|
130
|
+
}
|
|
131
|
+
this.requestUpdate("_correctResponse", oldVal);
|
|
132
|
+
}
|
|
133
|
+
// ─── correctness getter ───────────────────────────────────────────────────
|
|
134
|
+
get correctness() {
|
|
135
|
+
const correctResponse = this.correctResponse;
|
|
136
|
+
if (!correctResponse)
|
|
137
|
+
return null;
|
|
138
|
+
const currentResponse = this.response;
|
|
139
|
+
if (currentResponse === null || currentResponse === void 0 || currentResponse === "" || Array.isArray(currentResponse) && currentResponse.length === 0) {
|
|
140
|
+
return null;
|
|
141
|
+
}
|
|
142
|
+
const correctArr = Array.isArray(correctResponse) ? correctResponse : [correctResponse];
|
|
143
|
+
const responseArr = Array.isArray(currentResponse) ? currentResponse : [currentResponse];
|
|
144
|
+
const filteredResponseArr = responseArr.filter((r2) => r2 !== "");
|
|
145
|
+
if (filteredResponseArr.length === 0)
|
|
146
|
+
return null;
|
|
147
|
+
const correctCount = filteredResponseArr.filter((r2) => correctArr.includes(r2)).length;
|
|
148
|
+
const incorrectCount = filteredResponseArr.filter((r2) => !correctArr.includes(r2)).length;
|
|
149
|
+
if (correctCount === correctArr.length && incorrectCount === 0 && filteredResponseArr.length === correctArr.length) {
|
|
150
|
+
return Correctness.Correct;
|
|
151
|
+
}
|
|
152
|
+
if (correctCount > 0 && (correctCount < correctArr.length || incorrectCount > 0)) {
|
|
153
|
+
return Correctness.PartiallyCorrect;
|
|
154
|
+
}
|
|
155
|
+
return Correctness.Incorrect;
|
|
156
|
+
}
|
|
157
|
+
// ─── correctionPart ───────────────────────────────────────────────────────
|
|
158
|
+
get correctionPart() {
|
|
159
|
+
return "correction";
|
|
160
|
+
}
|
|
161
|
+
// ─── toggle methods ───────────────────────────────────────────────────────
|
|
162
|
+
toggleCorrectResponse(show) {
|
|
163
|
+
const correctionConfig = this.configContext;
|
|
164
|
+
const correctResponseMode = correctionConfig?.correctResponseMode || "internal";
|
|
165
|
+
if (correctResponseMode === "full") {
|
|
166
|
+
this.toggleFullCorrectResponse(show);
|
|
167
|
+
} else {
|
|
168
|
+
this.toggleInternalCorrectResponse(show);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Whether the full correct response is withheld from a candidate who is already correct.
|
|
173
|
+
*
|
|
174
|
+
* Withheld by default, unless the item configures `fullCorrectResponseOnlyWhenIncorrect: false`
|
|
175
|
+
* — the behaviour `show-full-correct-response` has always had, on the reasoning that a correct
|
|
176
|
+
* answer already *is* the key.
|
|
177
|
+
*
|
|
178
|
+
* An interaction that routes its internal mode here overrides this to false: there, the caller
|
|
179
|
+
* asked to show the correct response, and silently showing nothing is worse than showing the
|
|
180
|
+
* candidate the answer they already gave.
|
|
181
|
+
*/
|
|
182
|
+
get withholdsFullCorrectResponseWhenCorrect() {
|
|
183
|
+
return this.configContext?.fullCorrectResponseOnlyWhenIncorrect !== false;
|
|
184
|
+
}
|
|
185
|
+
async toggleFullCorrectResponse(show) {
|
|
186
|
+
const nextSibling = this.nextSibling;
|
|
187
|
+
const nextSiblingIsFullCorrectResponse = nextSibling instanceof HTMLDivElement && nextSibling?.classList.contains("full-correct-response");
|
|
188
|
+
const correctResponse = this.correctResponse;
|
|
189
|
+
if (!correctResponse) {
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
192
|
+
const showFullCorrectResponse = show && (!this.withholdsFullCorrectResponseWhenCorrect || this.correctness !== Correctness.Correct);
|
|
193
|
+
if (!showFullCorrectResponse) {
|
|
194
|
+
if (!nextSiblingIsFullCorrectResponse) {
|
|
195
|
+
return;
|
|
196
|
+
}
|
|
197
|
+
this.parentElement?.removeChild(nextSibling);
|
|
198
|
+
return;
|
|
199
|
+
}
|
|
200
|
+
if (nextSiblingIsFullCorrectResponse) {
|
|
201
|
+
return;
|
|
202
|
+
}
|
|
203
|
+
const clone = this.cloneNode(true);
|
|
204
|
+
clone.removeAttribute("show-full-correct-response");
|
|
205
|
+
clone.removeAttribute("show-correct-response");
|
|
206
|
+
clone.removeAttribute("show-candidate-correction");
|
|
207
|
+
const containerDiv = document.createElement("div");
|
|
208
|
+
containerDiv.classList.add("full-correct-response");
|
|
209
|
+
if (this.isInline) {
|
|
210
|
+
containerDiv.classList.add("full-correct-response-inline");
|
|
211
|
+
} else {
|
|
212
|
+
containerDiv.classList.add("full-correct-response-block");
|
|
213
|
+
}
|
|
214
|
+
containerDiv.role = "full-correct-response";
|
|
215
|
+
containerDiv.appendChild(clone);
|
|
216
|
+
clone.isFullCorrectResponse = true;
|
|
217
|
+
this.parentElement?.insertBefore(containerDiv, this.nextSibling);
|
|
218
|
+
await clone.updateComplete;
|
|
219
|
+
clone.response = Array.isArray(correctResponse) ? [...correctResponse] : correctResponse;
|
|
220
|
+
}
|
|
221
|
+
toggleInternalCorrectResponse(show) {
|
|
222
|
+
this._internals.states.delete("show-correct-response");
|
|
223
|
+
if (show && this.correctResponse) {
|
|
224
|
+
this._internals.states.add("show-correct-response");
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
toggleCandidateCorrection(show) {
|
|
228
|
+
if (!show) {
|
|
229
|
+
return;
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
// ─── Lifecycle ────────────────────────────────────────────────────────────
|
|
233
|
+
firstUpdated() {
|
|
234
|
+
super.firstUpdated();
|
|
235
|
+
if (this.isFullCorrectResponse) {
|
|
236
|
+
return;
|
|
237
|
+
}
|
|
238
|
+
if (this.showCorrectResponse) {
|
|
239
|
+
this.toggleInternalCorrectResponse(true);
|
|
240
|
+
}
|
|
241
|
+
if (this.showFullCorrectResponse) {
|
|
242
|
+
this.toggleFullCorrectResponse(true);
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
__decorate([
|
|
247
|
+
n({
|
|
248
|
+
attribute: "correct-response",
|
|
249
|
+
reflect: true,
|
|
250
|
+
converter: responseAttributeConverter({ emptyAs: null })
|
|
251
|
+
})
|
|
252
|
+
], CorrectResponseMixinClass.prototype, "correctResponseAttr", null);
|
|
253
|
+
__decorate([
|
|
254
|
+
n({ type: Boolean, attribute: "show-correct-response", reflect: true })
|
|
255
|
+
], CorrectResponseMixinClass.prototype, "showCorrectResponse", void 0);
|
|
256
|
+
__decorate([
|
|
257
|
+
watch("showCorrectResponse", { waitUntilFirstUpdate: true })
|
|
258
|
+
], CorrectResponseMixinClass.prototype, "_handleShowCorrectResponseChange", void 0);
|
|
259
|
+
__decorate([
|
|
260
|
+
n({ type: Boolean, attribute: "show-full-correct-response", reflect: true })
|
|
261
|
+
], CorrectResponseMixinClass.prototype, "showFullCorrectResponse", void 0);
|
|
262
|
+
__decorate([
|
|
263
|
+
watch("showFullCorrectResponse", { waitUntilFirstUpdate: true })
|
|
264
|
+
], CorrectResponseMixinClass.prototype, "_handleShowFullCorrectResponseChange", void 0);
|
|
265
|
+
__decorate([
|
|
266
|
+
n({ type: Boolean, attribute: "show-candidate-correction", reflect: true })
|
|
267
|
+
], CorrectResponseMixinClass.prototype, "showCandidateCorrection", void 0);
|
|
268
|
+
__decorate([
|
|
269
|
+
watch("showCandidateCorrection", { waitUntilFirstUpdate: true })
|
|
270
|
+
], CorrectResponseMixinClass.prototype, "_handleShowCandidateCorrectionChange", void 0);
|
|
271
|
+
__decorate([
|
|
272
|
+
r()
|
|
273
|
+
], CorrectResponseMixinClass.prototype, "_isFullCorrectResponse", void 0);
|
|
274
|
+
__decorate([
|
|
275
|
+
r()
|
|
276
|
+
], CorrectResponseMixinClass.prototype, "_correctResponse", void 0);
|
|
277
|
+
return CorrectResponseMixinClass;
|
|
278
|
+
};
|
|
279
|
+
|
|
280
|
+
// ../qti-corrections/dist/styles/correction.styles.js
|
|
281
|
+
var correctionPart = i`
|
|
282
|
+
/* Nothing at all until the item judges this element. */
|
|
283
|
+
[part~='correction'] {
|
|
284
|
+
display: none;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
[part~='correction-correct'],
|
|
288
|
+
[part~='correction-incorrect'],
|
|
289
|
+
[part~='correction-partially-correct'] {
|
|
290
|
+
display: inline-flex;
|
|
291
|
+
flex: 0 0 auto;
|
|
292
|
+
|
|
293
|
+
/*
|
|
294
|
+
* The badge aligns ITSELF, and that is the whole of the vertical story.
|
|
295
|
+
*
|
|
296
|
+
* It is a flex item with a definite height, so left alone its cross-axis position is decided by
|
|
297
|
+
* whatever its host says — and the hosts disagree: qti-simple-associable-choice defaults to
|
|
298
|
+
* align-items: normal, and qti-gap-text gates center behind :not([part~='drag']), so the
|
|
299
|
+
* same chip centred its badge in the bank and top-aligned it once placed. align-self settles it
|
|
300
|
+
* from the badge's side, in one line, without touching a single container.
|
|
301
|
+
*
|
|
302
|
+
* This replaces an align-items/justify-content: center pair that had never done anything: the
|
|
303
|
+
* badge is empty — a mask painted over a background — so centring its CONTENTS centres nothing.
|
|
304
|
+
*/
|
|
305
|
+
align-self: center;
|
|
306
|
+
|
|
307
|
+
box-sizing: border-box;
|
|
308
|
+
width: var(--qti-correction-size, 1em);
|
|
309
|
+
height: var(--qti-correction-size, 1em);
|
|
310
|
+
margin-left: var(--qti-glyph-gap, 0.5em);
|
|
311
|
+
|
|
312
|
+
pointer-events: none;
|
|
313
|
+
}
|
|
314
|
+
`;
|
|
315
|
+
|
|
316
|
+
// ../qti-corrections/dist/mixins/candidate-correction.mixin.js
|
|
317
|
+
var __decorate2 = function(decorators, target, key, desc) {
|
|
318
|
+
var c3 = arguments.length, r2 = c3 < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
319
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r2 = Reflect.decorate(decorators, target, key, desc);
|
|
320
|
+
else for (var i3 = decorators.length - 1; i3 >= 0; i3--) if (d = decorators[i3]) r2 = (c3 < 3 ? d(r2) : c3 > 3 ? d(target, key, r2) : d(target, key)) || r2;
|
|
321
|
+
return c3 > 3 && r2 && Object.defineProperty(target, key, r2), r2;
|
|
322
|
+
};
|
|
323
|
+
var CandidateCorrectionMixin = (superClass) => {
|
|
324
|
+
class CandidateCorrectionMixinClass extends CorrectResponseMixin(superClass) {
|
|
325
|
+
constructor() {
|
|
326
|
+
super(...arguments);
|
|
327
|
+
this._candidateCorrection = null;
|
|
328
|
+
}
|
|
329
|
+
get correctionPart() {
|
|
330
|
+
return this._candidateCorrection ? `correction correction-${this._candidateCorrection}` : "correction";
|
|
331
|
+
}
|
|
332
|
+
toggleCandidateCorrection(show) {
|
|
333
|
+
if (this.showCandidateCorrection !== show) {
|
|
334
|
+
this.showCandidateCorrection = show;
|
|
335
|
+
}
|
|
336
|
+
super.toggleCandidateCorrection(show);
|
|
337
|
+
const internals = this._internals;
|
|
338
|
+
internals.states.delete("candidate-correct");
|
|
339
|
+
internals.states.delete("candidate-partially-correct");
|
|
340
|
+
internals.states.delete("candidate-incorrect");
|
|
341
|
+
let verdict = null;
|
|
342
|
+
if (show) {
|
|
343
|
+
if (this.correctness === Correctness.Correct) {
|
|
344
|
+
internals.states.add("candidate-correct");
|
|
345
|
+
verdict = "correct";
|
|
346
|
+
}
|
|
347
|
+
if (this.correctness === Correctness.PartiallyCorrect) {
|
|
348
|
+
internals.states.add("candidate-partially-correct");
|
|
349
|
+
verdict = "partially-correct";
|
|
350
|
+
}
|
|
351
|
+
if (this.correctness === Correctness.Incorrect) {
|
|
352
|
+
internals.states.add("candidate-incorrect");
|
|
353
|
+
verdict = "incorrect";
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
if (this._candidateCorrection !== verdict) {
|
|
357
|
+
this._candidateCorrection = verdict;
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
connectedCallback() {
|
|
361
|
+
super.connectedCallback?.();
|
|
362
|
+
queueMicrotask(() => {
|
|
363
|
+
if (!this.isConnected || this.isFullCorrectResponse) {
|
|
364
|
+
return;
|
|
365
|
+
}
|
|
366
|
+
if (this.showCandidateCorrection) {
|
|
367
|
+
this.toggleCandidateCorrection(true);
|
|
368
|
+
}
|
|
369
|
+
});
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
__decorate2([
|
|
373
|
+
r()
|
|
374
|
+
], CandidateCorrectionMixinClass.prototype, "_candidateCorrection", void 0);
|
|
375
|
+
return CandidateCorrectionMixinClass;
|
|
376
|
+
};
|
|
377
|
+
|
|
378
|
+
// ../qti-corrections/dist/mixins/choice-correction.mixin.js
|
|
379
|
+
var ChoiceCorrectionMixin = (superClass) => {
|
|
380
|
+
class ChoiceCorrectionMixinClass extends CandidateCorrectionMixin(superClass) {
|
|
381
|
+
toggleInternalCorrectResponse(show) {
|
|
382
|
+
super.toggleInternalCorrectResponse(show);
|
|
383
|
+
const correctResponse = this.correctResponse;
|
|
384
|
+
const correctResponses = correctResponse ? Array.isArray(correctResponse) ? correctResponse : [correctResponse] : [];
|
|
385
|
+
for (const choice of this._choiceElements) {
|
|
386
|
+
choice.internals.states.delete("correct-response");
|
|
387
|
+
choice.internals.states.delete("incorrect-response");
|
|
388
|
+
if (show && correctResponses.length > 0) {
|
|
389
|
+
choice.internals.states.add(correctResponses.includes(choice.identifier) ? "correct-response" : "incorrect-response");
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
toggleCandidateCorrection(show) {
|
|
394
|
+
super.toggleCandidateCorrection(show);
|
|
395
|
+
for (const choice of this._choiceElements) {
|
|
396
|
+
choice.candidateCorrection = null;
|
|
397
|
+
}
|
|
398
|
+
if (!show || !this.correctResponse) {
|
|
399
|
+
return;
|
|
400
|
+
}
|
|
401
|
+
const correctResponses = Array.isArray(this.correctResponse) ? this.correctResponse : [this.correctResponse];
|
|
402
|
+
const candidateResponses = Array.isArray(this.response) ? this.response : this.response ? [this.response] : [];
|
|
403
|
+
for (const choice of this._choiceElements) {
|
|
404
|
+
if (!candidateResponses.includes(choice.identifier)) {
|
|
405
|
+
continue;
|
|
406
|
+
}
|
|
407
|
+
choice.candidateCorrection = correctResponses.includes(choice.identifier) ? "correct" : "incorrect";
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
return ChoiceCorrectionMixinClass;
|
|
412
|
+
};
|
|
413
|
+
|
|
414
|
+
// ../qti-corrections/dist/mixins/active-element-correction.mixin.js
|
|
415
|
+
var ActiveElementCorrectionMixin = (superClass) => {
|
|
416
|
+
class ActiveElementCorrectionMixinClass extends superClass {
|
|
417
|
+
#candidateCorrection = null;
|
|
418
|
+
get candidateCorrection() {
|
|
419
|
+
return this.#candidateCorrection;
|
|
420
|
+
}
|
|
421
|
+
set candidateCorrection(value) {
|
|
422
|
+
if (this.#candidateCorrection === value)
|
|
423
|
+
return;
|
|
424
|
+
const previous = this.#candidateCorrection;
|
|
425
|
+
this.#candidateCorrection = value;
|
|
426
|
+
const states = this.internals.states;
|
|
427
|
+
states.delete("candidate-correct");
|
|
428
|
+
states.delete("candidate-incorrect");
|
|
429
|
+
states.delete("candidate-partially-correct");
|
|
430
|
+
if (value)
|
|
431
|
+
states.add(`candidate-${value}`);
|
|
432
|
+
this.requestUpdate("candidateCorrection", previous);
|
|
433
|
+
}
|
|
434
|
+
get correctionPart() {
|
|
435
|
+
return this.#candidateCorrection ? `correction correction-${this.#candidateCorrection}` : "correction";
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
return ActiveElementCorrectionMixinClass;
|
|
439
|
+
};
|
|
440
|
+
|
|
441
|
+
// ../qti-corrections/dist/elements/qti-gap-text-correction.js
|
|
442
|
+
var QtiGapTextCorrection = class extends ActiveElementCorrectionMixin(QtiGapText) {
|
|
443
|
+
static {
|
|
444
|
+
this.styles = [QtiGapText.styles, correctionPart];
|
|
445
|
+
}
|
|
446
|
+
render() {
|
|
447
|
+
return T`<div part="control"></div>
|
|
448
|
+
<slot part="label"></slot>
|
|
449
|
+
<span part=${this.correctionPart} aria-hidden="true"></span>`;
|
|
450
|
+
}
|
|
451
|
+
};
|
|
452
|
+
|
|
453
|
+
// ../qti-corrections/dist/elements/qti-hotspot-choice-correction.js
|
|
454
|
+
var __decorate3 = function(decorators, target, key, desc) {
|
|
455
|
+
var c3 = arguments.length, r2 = c3 < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
456
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r2 = Reflect.decorate(decorators, target, key, desc);
|
|
457
|
+
else for (var i3 = decorators.length - 1; i3 >= 0; i3--) if (d = decorators[i3]) r2 = (c3 < 3 ? d(r2) : c3 > 3 ? d(target, key, r2) : d(target, key)) || r2;
|
|
458
|
+
return c3 > 3 && r2 && Object.defineProperty(target, key, r2), r2;
|
|
459
|
+
};
|
|
460
|
+
var QtiHotspotChoiceCorrection = class extends ActiveElementCorrectionMixin(QtiHotspotChoice) {
|
|
461
|
+
constructor() {
|
|
462
|
+
super(...arguments);
|
|
463
|
+
this.orderCorrect = null;
|
|
464
|
+
}
|
|
465
|
+
};
|
|
466
|
+
__decorate3([
|
|
467
|
+
n({ attribute: "aria-ordercorrectvalue", type: Number, reflect: true })
|
|
468
|
+
], QtiHotspotChoiceCorrection.prototype, "orderCorrect", void 0);
|
|
469
|
+
|
|
470
|
+
// ../qti-corrections/dist/elements/qti-hottext-correction.js
|
|
471
|
+
var QtiHottextCorrection = class extends ActiveElementCorrectionMixin(QtiHottext) {
|
|
472
|
+
static {
|
|
473
|
+
this.styles = [QtiHottext.styles, correctionPart];
|
|
474
|
+
}
|
|
475
|
+
render() {
|
|
476
|
+
return T`<div part="control"><div part="control-mark"></div></div>
|
|
477
|
+
<slot part="label"></slot>
|
|
478
|
+
<span part=${this.correctionPart} aria-hidden="true"></span>`;
|
|
479
|
+
}
|
|
480
|
+
};
|
|
481
|
+
|
|
482
|
+
// ../qti-corrections/dist/elements/qti-simple-associable-choice-correction.js
|
|
483
|
+
var QtiSimpleAssociableChoiceCorrection = class extends ActiveElementCorrectionMixin(QtiSimpleAssociableChoice) {
|
|
484
|
+
static {
|
|
485
|
+
this.styles = [QtiSimpleAssociableChoice.styles, correctionPart];
|
|
486
|
+
}
|
|
487
|
+
render() {
|
|
488
|
+
return T`
|
|
489
|
+
<div part="control"></div>
|
|
490
|
+
<slot part="label"></slot>
|
|
491
|
+
<span part=${this.correctionPart} aria-hidden="true"></span>
|
|
492
|
+
<div part="drop">
|
|
493
|
+
${c2(this.drags, (node) => node.getAttribute("identifier"), (node) => node)}
|
|
494
|
+
</div>
|
|
495
|
+
`;
|
|
496
|
+
}
|
|
497
|
+
};
|
|
498
|
+
|
|
499
|
+
// ../qti-corrections/dist/elements/qti-simple-choice-correction.js
|
|
500
|
+
var QtiSimpleChoiceCorrection = class extends ActiveElementCorrectionMixin(QtiSimpleChoice) {
|
|
501
|
+
static {
|
|
502
|
+
this.styles = [QtiSimpleChoice.styles, correctionPart];
|
|
503
|
+
}
|
|
504
|
+
render() {
|
|
505
|
+
return T`<div part="control" tabindex="0"><div part="control-mark"></div></div>
|
|
506
|
+
${this.marker ? T`<div id="label" part="marker">${this.marker}</div>` : A}
|
|
507
|
+
<slot part="label"></slot>
|
|
508
|
+
<span part=${this.correctionPart} aria-hidden="true"></span>`;
|
|
509
|
+
}
|
|
510
|
+
};
|
|
511
|
+
|
|
512
|
+
// ../qti-corrections/dist/components/qti-assessment-item-correction.js
|
|
513
|
+
var QtiAssessmentItemCorrection = class extends QtiAssessmentItem {
|
|
514
|
+
showCorrectResponse(show) {
|
|
515
|
+
for (const interaction of this.interactionElements) {
|
|
516
|
+
interaction.toggleCorrectResponse?.(show);
|
|
517
|
+
}
|
|
518
|
+
this.updateControlState("item-show-correct-response", show);
|
|
519
|
+
}
|
|
520
|
+
showCandidateCorrection(show) {
|
|
521
|
+
for (const interaction of this.interactionElements) {
|
|
522
|
+
interaction.toggleCandidateCorrection?.(show);
|
|
523
|
+
}
|
|
524
|
+
this.updateControlState("item-show-candidate-correction", show);
|
|
525
|
+
}
|
|
526
|
+
afterResponseVariableUpdated() {
|
|
527
|
+
this.showCandidateCorrection(false);
|
|
528
|
+
}
|
|
529
|
+
updateControlState(selector, shown) {
|
|
530
|
+
let root = this.getRootNode();
|
|
531
|
+
while (true) {
|
|
532
|
+
root.querySelectorAll(selector).forEach((control) => control.shown = shown);
|
|
533
|
+
if (!(root instanceof ShadowRoot))
|
|
534
|
+
return;
|
|
535
|
+
root = root.host.getRootNode();
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
};
|
|
539
|
+
|
|
540
|
+
// ../qti-corrections/dist/components/qti-item-correction.js
|
|
541
|
+
var QtiItemCorrection = class extends QtiItem {
|
|
542
|
+
#onShowCorrectResponse = (event) => {
|
|
543
|
+
const show = event.detail;
|
|
544
|
+
this.assessmentItem?.showCorrectResponse?.(show);
|
|
545
|
+
this.updateControlState("item-show-correct-response", show);
|
|
546
|
+
};
|
|
547
|
+
#onShowCandidateCorrection = (event) => {
|
|
548
|
+
const show = event.detail;
|
|
549
|
+
this.assessmentItem?.showCandidateCorrection?.(show);
|
|
550
|
+
this.updateControlState("item-show-candidate-correction", show);
|
|
551
|
+
};
|
|
552
|
+
#onSwitchCorrectResponseMode = (event) => {
|
|
553
|
+
this.assessmentItem?.showCorrectResponse?.(false);
|
|
554
|
+
this.configContext = {
|
|
555
|
+
...this.configContext,
|
|
556
|
+
correctResponseMode: event.detail
|
|
557
|
+
};
|
|
558
|
+
};
|
|
559
|
+
constructor() {
|
|
560
|
+
super();
|
|
561
|
+
this.addEventListener("item-show-correct-response", this.#onShowCorrectResponse);
|
|
562
|
+
this.addEventListener("item-show-candidate-correction", this.#onShowCandidateCorrection);
|
|
563
|
+
this.addEventListener("item-switch-correct-response-mode", this.#onSwitchCorrectResponseMode);
|
|
564
|
+
}
|
|
565
|
+
updateControlState(selector, shown) {
|
|
566
|
+
this.querySelectorAll(selector).forEach((control) => control.shown = shown);
|
|
567
|
+
}
|
|
568
|
+
disconnectedCallback() {
|
|
569
|
+
this.removeEventListener("item-show-correct-response", this.#onShowCorrectResponse);
|
|
570
|
+
this.removeEventListener("item-show-candidate-correction", this.#onShowCandidateCorrection);
|
|
571
|
+
this.removeEventListener("item-switch-correct-response-mode", this.#onSwitchCorrectResponseMode);
|
|
572
|
+
super.disconnectedCallback();
|
|
573
|
+
}
|
|
574
|
+
};
|
|
575
|
+
|
|
576
|
+
// ../qti-corrections/dist/components/test-correction-elements.js
|
|
577
|
+
var TestNavigationCorrection = class extends TestNavigation {
|
|
578
|
+
#onShowCorrectResponse = (event) => {
|
|
579
|
+
this.activeAssessmentItem?.showCorrectResponse?.(event.detail);
|
|
580
|
+
};
|
|
581
|
+
#onShowCandidateCorrection = (event) => {
|
|
582
|
+
this.activeAssessmentItem?.showCandidateCorrection?.(event.detail);
|
|
583
|
+
};
|
|
584
|
+
constructor() {
|
|
585
|
+
super();
|
|
586
|
+
this.addEventListener("test-show-correct-response", this.#onShowCorrectResponse);
|
|
587
|
+
this.addEventListener("test-show-candidate-correction", this.#onShowCandidateCorrection);
|
|
588
|
+
}
|
|
589
|
+
disconnectedCallback() {
|
|
590
|
+
this.removeEventListener("test-show-correct-response", this.#onShowCorrectResponse);
|
|
591
|
+
this.removeEventListener("test-show-candidate-correction", this.#onShowCandidateCorrection);
|
|
592
|
+
super.disconnectedCallback();
|
|
593
|
+
}
|
|
594
|
+
};
|
|
595
|
+
var QtiTestCorrection = class extends QtiTest {
|
|
596
|
+
updateAssessmentItemView(assessmentItem, view) {
|
|
597
|
+
assessmentItem.showCorrectResponse?.(view === "scorer");
|
|
598
|
+
}
|
|
599
|
+
};
|
|
600
|
+
var TestCheckItemCorrection = class extends TestCheckItem {
|
|
601
|
+
constructor() {
|
|
602
|
+
super();
|
|
603
|
+
this.addEventListener("click", () => {
|
|
604
|
+
this.dispatchEvent(new CustomEvent("test-show-correct-response", { detail: true, bubbles: true }));
|
|
605
|
+
});
|
|
606
|
+
}
|
|
607
|
+
};
|
|
608
|
+
|
|
609
|
+
// ../qti-corrections/dist/components/item-correct-response-mode/item-correct-response-mode.js
|
|
610
|
+
var __decorate4 = function(decorators, target, key, desc) {
|
|
611
|
+
var c3 = arguments.length, r2 = c3 < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
612
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r2 = Reflect.decorate(decorators, target, key, desc);
|
|
613
|
+
else for (var i3 = decorators.length - 1; i3 >= 0; i3--) if (d = decorators[i3]) r2 = (c3 < 3 ? d(r2) : c3 > 3 ? d(target, key, r2) : d(target, key)) || r2;
|
|
614
|
+
return c3 > 3 && r2 && Object.defineProperty(target, key, r2), r2;
|
|
615
|
+
};
|
|
616
|
+
var ItemCorrectResponseMode = class extends i2 {
|
|
617
|
+
constructor() {
|
|
618
|
+
super(...arguments);
|
|
619
|
+
this.label = "Correct response mode";
|
|
620
|
+
this._options = {
|
|
621
|
+
internal: "Internal",
|
|
622
|
+
full: "Full (copy)"
|
|
623
|
+
};
|
|
624
|
+
}
|
|
625
|
+
#switchMode(view) {
|
|
626
|
+
this.dispatchEvent(new CustomEvent("item-switch-correct-response-mode", {
|
|
627
|
+
detail: view,
|
|
628
|
+
bubbles: true
|
|
629
|
+
}));
|
|
630
|
+
}
|
|
631
|
+
render() {
|
|
632
|
+
return T`
|
|
633
|
+
<label part="label" for="modeSelect">${this.label}</label>
|
|
634
|
+
<select
|
|
635
|
+
part="select"
|
|
636
|
+
id="modeSelect"
|
|
637
|
+
@change=${(e) => {
|
|
638
|
+
const el = e.target;
|
|
639
|
+
this.#switchMode(el.value);
|
|
640
|
+
}}
|
|
641
|
+
>
|
|
642
|
+
${Object.keys(this._options).map((value) => T`<option value="${value}" ?selected=${value === this.itemContext?.correctResponseMode}>
|
|
643
|
+
${this._options[value]}
|
|
644
|
+
</option>`)}
|
|
645
|
+
</select>
|
|
646
|
+
`;
|
|
647
|
+
}
|
|
648
|
+
};
|
|
649
|
+
__decorate4([
|
|
650
|
+
c({ context: configContext, subscribe: true })
|
|
651
|
+
], ItemCorrectResponseMode.prototype, "itemContext", void 0);
|
|
652
|
+
__decorate4([
|
|
653
|
+
n({ type: String })
|
|
654
|
+
], ItemCorrectResponseMode.prototype, "label", void 0);
|
|
655
|
+
__decorate4([
|
|
656
|
+
r()
|
|
657
|
+
], ItemCorrectResponseMode.prototype, "_options", void 0);
|
|
658
|
+
|
|
659
|
+
// ../qti-corrections/dist/components/styles.js
|
|
660
|
+
var form = i`
|
|
661
|
+
display: inline-flex;
|
|
662
|
+
align-items: center;
|
|
663
|
+
cursor: pointer;
|
|
664
|
+
padding: 0.5rem 1rem;
|
|
665
|
+
border-radius: 0.25rem;
|
|
666
|
+
user-select: none;
|
|
667
|
+
`;
|
|
668
|
+
var btn = i`
|
|
669
|
+
background-color: lightgray;
|
|
670
|
+
${form};
|
|
671
|
+
`;
|
|
672
|
+
var dis = i`
|
|
673
|
+
cursor: not-allowed;
|
|
674
|
+
opacity: 0.8;
|
|
675
|
+
`;
|
|
676
|
+
var ind = i`
|
|
677
|
+
${form};
|
|
678
|
+
border: 1px solid gray;
|
|
679
|
+
`;
|
|
680
|
+
|
|
681
|
+
// ../qti-corrections/dist/components/item-show-candidate-correction/item-show-candidate-correction.js
|
|
682
|
+
var __decorate5 = function(decorators, target, key, desc) {
|
|
683
|
+
var c3 = arguments.length, r2 = c3 < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
684
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r2 = Reflect.decorate(decorators, target, key, desc);
|
|
685
|
+
else for (var i3 = decorators.length - 1; i3 >= 0; i3--) if (d = decorators[i3]) r2 = (c3 < 3 ? d(r2) : c3 > 3 ? d(target, key, r2) : d(target, key)) || r2;
|
|
686
|
+
return c3 > 3 && r2 && Object.defineProperty(target, key, r2), r2;
|
|
687
|
+
};
|
|
688
|
+
var ItemShowCandidateCorrection = class extends i2 {
|
|
689
|
+
static {
|
|
690
|
+
this.styles = i`
|
|
691
|
+
:host {
|
|
692
|
+
${btn};
|
|
693
|
+
}
|
|
694
|
+
:host([disabled]) {
|
|
695
|
+
${dis};
|
|
696
|
+
}
|
|
697
|
+
`;
|
|
698
|
+
}
|
|
699
|
+
#hasCorrectResponse;
|
|
700
|
+
// correct response is removed on certain point
|
|
701
|
+
#previousActiveItem;
|
|
702
|
+
// Store previous active item reference
|
|
703
|
+
constructor() {
|
|
704
|
+
super();
|
|
705
|
+
this.shown = false;
|
|
706
|
+
this.disabled = false;
|
|
707
|
+
this.showCandidateCorrectionText = "Show candidate correction";
|
|
708
|
+
this.hideCandidateCorrectionText = "Hide candidate correction";
|
|
709
|
+
this.noCorrectResponseText = "No correct response specified";
|
|
710
|
+
this.#hasCorrectResponse = false;
|
|
711
|
+
this.#previousActiveItem = "";
|
|
712
|
+
}
|
|
713
|
+
updated() {
|
|
714
|
+
if (!this.#hasCorrectResponse || this.#previousActiveItem !== this.computedContext?.identifier) {
|
|
715
|
+
this.#previousActiveItem = this.computedContext?.identifier;
|
|
716
|
+
const containsCorrectResponse = !!this.computedContext?.variables.some((v) => v["correctResponse"]);
|
|
717
|
+
const containsMapping = !!this.computedContext?.variables.some((v) => {
|
|
718
|
+
return v["mapping"]?.mapEntries?.length > 0 || v["areaMapping"]?.areaMapEntries?.length > 0;
|
|
719
|
+
});
|
|
720
|
+
this.#hasCorrectResponse = containsCorrectResponse || containsMapping;
|
|
721
|
+
}
|
|
722
|
+
this.disabled = !this.#hasCorrectResponse;
|
|
723
|
+
}
|
|
724
|
+
#toggleState() {
|
|
725
|
+
if (this.disabled)
|
|
726
|
+
return;
|
|
727
|
+
this.dispatchEvent(new CustomEvent("item-show-candidate-correction", {
|
|
728
|
+
detail: !this.shown,
|
|
729
|
+
bubbles: true
|
|
730
|
+
}));
|
|
731
|
+
}
|
|
732
|
+
#getDisplayedText() {
|
|
733
|
+
return this.disabled ? this.noCorrectResponseText : this.shown ? this.hideCandidateCorrectionText : this.showCandidateCorrectionText;
|
|
734
|
+
}
|
|
735
|
+
render() {
|
|
736
|
+
return T` <div @click="${this.#toggleState}">${this.#getDisplayedText()}</div> `;
|
|
737
|
+
}
|
|
738
|
+
};
|
|
739
|
+
__decorate5([
|
|
740
|
+
c({ context: computedItemContext, subscribe: true })
|
|
741
|
+
], ItemShowCandidateCorrection.prototype, "computedContext", void 0);
|
|
742
|
+
__decorate5([
|
|
743
|
+
n({ type: Boolean, reflect: true })
|
|
744
|
+
], ItemShowCandidateCorrection.prototype, "shown", void 0);
|
|
745
|
+
__decorate5([
|
|
746
|
+
n({ type: Boolean, reflect: true })
|
|
747
|
+
], ItemShowCandidateCorrection.prototype, "disabled", void 0);
|
|
748
|
+
__decorate5([
|
|
749
|
+
n({ type: String })
|
|
750
|
+
], ItemShowCandidateCorrection.prototype, "showCandidateCorrectionText", void 0);
|
|
751
|
+
__decorate5([
|
|
752
|
+
n({ type: String })
|
|
753
|
+
], ItemShowCandidateCorrection.prototype, "hideCandidateCorrectionText", void 0);
|
|
754
|
+
__decorate5([
|
|
755
|
+
n({ type: String })
|
|
756
|
+
], ItemShowCandidateCorrection.prototype, "noCorrectResponseText", void 0);
|
|
757
|
+
|
|
758
|
+
// ../qti-corrections/dist/components/item-show-correct-response/item-show-correct-response.js
|
|
759
|
+
var __decorate6 = function(decorators, target, key, desc) {
|
|
760
|
+
var c3 = arguments.length, r2 = c3 < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
761
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r2 = Reflect.decorate(decorators, target, key, desc);
|
|
762
|
+
else for (var i3 = decorators.length - 1; i3 >= 0; i3--) if (d = decorators[i3]) r2 = (c3 < 3 ? d(r2) : c3 > 3 ? d(target, key, r2) : d(target, key)) || r2;
|
|
763
|
+
return c3 > 3 && r2 && Object.defineProperty(target, key, r2), r2;
|
|
764
|
+
};
|
|
765
|
+
var ItemShowCorrectResponse = class extends i2 {
|
|
766
|
+
constructor() {
|
|
767
|
+
super(...arguments);
|
|
768
|
+
this.shown = false;
|
|
769
|
+
this.disabled = false;
|
|
770
|
+
this.showCorrectText = "Show correct response";
|
|
771
|
+
this.hideCorrectText = "Hide correct response";
|
|
772
|
+
this.noCorrectResponseText = "No correct response specified";
|
|
773
|
+
this.#hasCorrectResponse = false;
|
|
774
|
+
this.#previousActiveItem = "";
|
|
775
|
+
}
|
|
776
|
+
static {
|
|
777
|
+
this.styles = i`
|
|
778
|
+
:host {
|
|
779
|
+
${btn};
|
|
780
|
+
}
|
|
781
|
+
:host([disabled]) {
|
|
782
|
+
${dis};
|
|
783
|
+
}
|
|
784
|
+
`;
|
|
785
|
+
}
|
|
786
|
+
#hasCorrectResponse;
|
|
787
|
+
// correct response is removed on certain point
|
|
788
|
+
#previousActiveItem;
|
|
789
|
+
// Store previous active item reference
|
|
790
|
+
updated() {
|
|
791
|
+
if (!this.#hasCorrectResponse || this.#previousActiveItem !== this.computedContext?.identifier) {
|
|
792
|
+
this.#previousActiveItem = this.computedContext?.identifier;
|
|
793
|
+
const containsCorrectResponse = !!this.computedContext?.variables.some((v) => v["correctResponse"]);
|
|
794
|
+
const containsMapping = !!this.computedContext?.variables.some((v) => {
|
|
795
|
+
return v["mapping"]?.mapEntries?.length > 0 || v["areaMapping"]?.areaMapEntries?.length > 0;
|
|
796
|
+
});
|
|
797
|
+
this.#hasCorrectResponse = containsCorrectResponse || containsMapping;
|
|
798
|
+
}
|
|
799
|
+
this.disabled = !this.#hasCorrectResponse;
|
|
800
|
+
}
|
|
801
|
+
#toggleState() {
|
|
802
|
+
if (this.disabled)
|
|
803
|
+
return;
|
|
804
|
+
this.dispatchEvent(new CustomEvent("item-show-correct-response", {
|
|
805
|
+
detail: !this.shown,
|
|
806
|
+
bubbles: true
|
|
807
|
+
}));
|
|
808
|
+
}
|
|
809
|
+
#getDisplayedText() {
|
|
810
|
+
return this.disabled ? this.noCorrectResponseText : this.shown ? this.hideCorrectText : this.showCorrectText;
|
|
811
|
+
}
|
|
812
|
+
render() {
|
|
813
|
+
return T` <div @click="${this.#toggleState}">${this.#getDisplayedText()}</div> `;
|
|
814
|
+
}
|
|
815
|
+
};
|
|
816
|
+
__decorate6([
|
|
817
|
+
c({ context: computedItemContext, subscribe: true })
|
|
818
|
+
], ItemShowCorrectResponse.prototype, "computedContext", void 0);
|
|
819
|
+
__decorate6([
|
|
820
|
+
n({ type: Boolean, reflect: true })
|
|
821
|
+
], ItemShowCorrectResponse.prototype, "shown", void 0);
|
|
822
|
+
__decorate6([
|
|
823
|
+
n({ type: Boolean, reflect: true })
|
|
824
|
+
], ItemShowCorrectResponse.prototype, "disabled", void 0);
|
|
825
|
+
__decorate6([
|
|
826
|
+
n({ type: String })
|
|
827
|
+
], ItemShowCorrectResponse.prototype, "showCorrectText", void 0);
|
|
828
|
+
__decorate6([
|
|
829
|
+
n({ type: String })
|
|
830
|
+
], ItemShowCorrectResponse.prototype, "hideCorrectText", void 0);
|
|
831
|
+
__decorate6([
|
|
832
|
+
n({ type: String })
|
|
833
|
+
], ItemShowCorrectResponse.prototype, "noCorrectResponseText", void 0);
|
|
834
|
+
|
|
835
|
+
// ../qti-corrections/dist/components/test-show-correct-response/test-show-correct-response.js
|
|
836
|
+
var __decorate7 = function(decorators, target, key, desc) {
|
|
837
|
+
var c3 = arguments.length, r2 = c3 < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
838
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r2 = Reflect.decorate(decorators, target, key, desc);
|
|
839
|
+
else for (var i3 = decorators.length - 1; i3 >= 0; i3--) if (d = decorators[i3]) r2 = (c3 < 3 ? d(r2) : c3 > 3 ? d(target, key, r2) : d(target, key)) || r2;
|
|
840
|
+
return c3 > 3 && r2 && Object.defineProperty(target, key, r2), r2;
|
|
841
|
+
};
|
|
842
|
+
var TestShowCorrectResponse = class extends i2 {
|
|
843
|
+
constructor() {
|
|
844
|
+
super(...arguments);
|
|
845
|
+
this.shown = false;
|
|
846
|
+
this.disabled = false;
|
|
847
|
+
this.showCorrectText = "Show correct response";
|
|
848
|
+
this.hideCorrectText = "Hide correct response";
|
|
849
|
+
this.noCorrectResponseText = "No correct response specified";
|
|
850
|
+
}
|
|
851
|
+
static {
|
|
852
|
+
this.styles = i`
|
|
853
|
+
:host {
|
|
854
|
+
${btn};
|
|
855
|
+
}
|
|
856
|
+
:host([disabled]) {
|
|
857
|
+
${dis};
|
|
858
|
+
}
|
|
859
|
+
`;
|
|
860
|
+
}
|
|
861
|
+
#previousActiveItem;
|
|
862
|
+
// Store previous active item reference
|
|
863
|
+
willUpdate(_changedProperties) {
|
|
864
|
+
const activeItem = this.computedContext?.testParts.flatMap((testPart) => testPart.sections.flatMap((section) => section.items)).find((item) => item.active);
|
|
865
|
+
if (this.#previousActiveItem !== activeItem) {
|
|
866
|
+
this.shown = false;
|
|
867
|
+
this.#previousActiveItem = activeItem;
|
|
868
|
+
}
|
|
869
|
+
if (activeItem) {
|
|
870
|
+
const containsCorrectResponse = !!activeItem?.variables?.some((v) => v["correctResponse"]);
|
|
871
|
+
const containsMapping = !!activeItem?.variables?.some((v) => {
|
|
872
|
+
return v["mapping"]?.mapEntries?.length > 0 || v["areaMapping"]?.areaMapEntries?.length > 0;
|
|
873
|
+
});
|
|
874
|
+
this.disabled = !containsCorrectResponse && !containsMapping;
|
|
875
|
+
} else {
|
|
876
|
+
this.disabled = true;
|
|
877
|
+
}
|
|
878
|
+
}
|
|
879
|
+
#toggleState() {
|
|
880
|
+
if (this.disabled)
|
|
881
|
+
return;
|
|
882
|
+
this.shown = !this.shown;
|
|
883
|
+
this.dispatchEvent(new CustomEvent("test-show-correct-response", {
|
|
884
|
+
detail: this.shown,
|
|
885
|
+
bubbles: true
|
|
886
|
+
}));
|
|
887
|
+
}
|
|
888
|
+
#getDisplayedText() {
|
|
889
|
+
return this.disabled ? this.noCorrectResponseText : this.shown ? this.hideCorrectText : this.showCorrectText;
|
|
890
|
+
}
|
|
891
|
+
render() {
|
|
892
|
+
return T` <div @click="${this.#toggleState}">${this.#getDisplayedText()}</div> `;
|
|
893
|
+
}
|
|
894
|
+
};
|
|
895
|
+
__decorate7([
|
|
896
|
+
c({ context: computedContext, subscribe: true })
|
|
897
|
+
], TestShowCorrectResponse.prototype, "computedContext", void 0);
|
|
898
|
+
__decorate7([
|
|
899
|
+
n({ type: Boolean, reflect: true })
|
|
900
|
+
], TestShowCorrectResponse.prototype, "shown", void 0);
|
|
901
|
+
__decorate7([
|
|
902
|
+
n({ type: Boolean, reflect: true })
|
|
903
|
+
], TestShowCorrectResponse.prototype, "disabled", void 0);
|
|
904
|
+
__decorate7([
|
|
905
|
+
n({ type: String })
|
|
906
|
+
], TestShowCorrectResponse.prototype, "showCorrectText", void 0);
|
|
907
|
+
__decorate7([
|
|
908
|
+
n({ type: String })
|
|
909
|
+
], TestShowCorrectResponse.prototype, "hideCorrectText", void 0);
|
|
910
|
+
__decorate7([
|
|
911
|
+
n({ type: String })
|
|
912
|
+
], TestShowCorrectResponse.prototype, "noCorrectResponseText", void 0);
|
|
913
|
+
|
|
914
|
+
// ../qti-corrections/dist/mixins/drag-drop-correction.mixin.js
|
|
915
|
+
var DragDropCorrectionMixin = (superClass) => {
|
|
916
|
+
class DragDropCorrectionMixinClass extends CandidateCorrectionMixin(superClass) {
|
|
917
|
+
toggleInternalCorrectResponse(show) {
|
|
918
|
+
if (!this.showFullCorrectResponse) {
|
|
919
|
+
this.toggleFullCorrectResponse(show);
|
|
920
|
+
}
|
|
921
|
+
}
|
|
922
|
+
afterCache() {
|
|
923
|
+
super.afterCache();
|
|
924
|
+
if (this.showCorrectResponse)
|
|
925
|
+
this.toggleInternalCorrectResponse(true);
|
|
926
|
+
if (this.showCandidateCorrection)
|
|
927
|
+
this.toggleCandidateCorrection(true);
|
|
928
|
+
if (this.showFullCorrectResponse)
|
|
929
|
+
this.toggleFullCorrectResponse(true);
|
|
930
|
+
}
|
|
931
|
+
}
|
|
932
|
+
return DragDropCorrectionMixinClass;
|
|
933
|
+
};
|
|
934
|
+
|
|
935
|
+
// ../qti-corrections/dist/interactions/qti-associate-interaction-correction.js
|
|
936
|
+
var QtiAssociateInteractionCorrection = class extends DragDropCorrectionMixin(QtiAssociateInteraction) {
|
|
937
|
+
};
|
|
938
|
+
|
|
939
|
+
// ../qti-corrections/dist/interactions/qti-choice-interaction-correction.js
|
|
940
|
+
var QtiChoiceInteractionCorrection = class extends ChoiceCorrectionMixin(QtiChoiceInteraction) {
|
|
941
|
+
};
|
|
942
|
+
|
|
943
|
+
// ../qti-corrections/dist/interactions/qti-extended-text-interaction-correction.js
|
|
944
|
+
var __decorate8 = function(decorators, target, key, desc) {
|
|
945
|
+
var c3 = arguments.length, r2 = c3 < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
946
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r2 = Reflect.decorate(decorators, target, key, desc);
|
|
947
|
+
else for (var i3 = decorators.length - 1; i3 >= 0; i3--) if (d = decorators[i3]) r2 = (c3 < 3 ? d(r2) : c3 > 3 ? d(target, key, r2) : d(target, key)) || r2;
|
|
948
|
+
return c3 > 3 && r2 && Object.defineProperty(target, key, r2), r2;
|
|
949
|
+
};
|
|
950
|
+
var QtiExtendedTextInteractionCorrection = class extends ActiveElementCorrectionMixin(QtiExtendedTextInteraction) {
|
|
951
|
+
static {
|
|
952
|
+
this.styles = [
|
|
953
|
+
QtiExtendedTextInteraction.styles,
|
|
954
|
+
correctionPart,
|
|
955
|
+
i`
|
|
956
|
+
/*
|
|
957
|
+
* Placement only — the glyph itself is the theme's, keyed on ::part(correction-*). That split
|
|
958
|
+
* is the contract in correction.styles.ts, which deliberately leaves the shared badge in flow
|
|
959
|
+
* and invites a component to lift it out if it wants a corner badge.
|
|
960
|
+
*
|
|
961
|
+
* A textarea is a box the candidate writes in, so the badge goes over its top-left corner
|
|
962
|
+
* rather than trailing the text the way a chip's does, and the theme reserves the gutter for it
|
|
963
|
+
* (padding-left on ::part(textarea)).
|
|
964
|
+
*
|
|
965
|
+
* Anchored to the TEXTAREA, not to the host. The badge's containing block is :host, and the
|
|
966
|
+
* host also contains the prompt slot — so a plain top: 0.85rem measured from the host lands on
|
|
967
|
+
* the prompt and the badge floats above the field, which is exactly what it did. Only the
|
|
968
|
+
* vertical offset needs anchoring: the textarea spans the host's full width, so the left
|
|
969
|
+
* offset is the same measured from either.
|
|
970
|
+
*/
|
|
971
|
+
[part~='textarea'] {
|
|
972
|
+
anchor-name: --qti-extended-text-field;
|
|
973
|
+
}
|
|
974
|
+
|
|
975
|
+
[part~='correction'] {
|
|
976
|
+
position: absolute;
|
|
977
|
+
position-anchor: --qti-extended-text-field;
|
|
978
|
+
margin: 0;
|
|
979
|
+
width: var(--qti-correction-size);
|
|
980
|
+
|
|
981
|
+
/*
|
|
982
|
+
* One FIELD line tall, not square — this is what puts the glyph on the text rather than near
|
|
983
|
+
* it. The mask is drawn center / contain, so in a box exactly one line high it centres itself
|
|
984
|
+
* on that line while the width still governs the glyph's size.
|
|
985
|
+
*
|
|
986
|
+
* Not 1lh: that unit resolves against the BADGE's own inherited line-height (measured 18.4px),
|
|
987
|
+
* not the textarea's (24px), so it landed a third of a line low. --qti-field-line-height is
|
|
988
|
+
* the same number @mixin field-typography gives the field, so the two cannot drift.
|
|
989
|
+
*/
|
|
990
|
+
height: calc(var(--qti-correction-size) * var(--qti-field-line-height));
|
|
991
|
+
|
|
992
|
+
/* Inset exactly as the text is: the same trailing token the two field-shaped interactions
|
|
993
|
+
use, read here as a LEADING inset because this badge lives in a left gutter. */
|
|
994
|
+
left: var(--qti-correction-inset);
|
|
995
|
+
|
|
996
|
+
/* Anchored to the field's first line: its top edge plus the field's own padding-top. */
|
|
997
|
+
top: calc(anchor(top) + var(--qti-spacing));
|
|
998
|
+
}
|
|
999
|
+
|
|
1000
|
+
/*
|
|
1001
|
+
* Fallback for engines without anchor positioning, where the top above does not parse and the
|
|
1002
|
+
* badge would fall to its static position below the field. The bottom of the gutter needs no
|
|
1003
|
+
* knowledge of where the field starts, and the gutter runs the full height, so the badge still
|
|
1004
|
+
* clears the text.
|
|
1005
|
+
*
|
|
1006
|
+
* Scoped by @supports rather than declared alongside. Both were set at first, on the assumption
|
|
1007
|
+
* that top + height over-constrains the box and bottom is ignored — it is not: measured, the
|
|
1008
|
+
* bottom won and put the badge on the third line.
|
|
1009
|
+
*/
|
|
1010
|
+
@supports not (anchor-name: --probe) {
|
|
1011
|
+
[part~='correction'] {
|
|
1012
|
+
top: auto;
|
|
1013
|
+
bottom: var(--qti-correction-inset);
|
|
1014
|
+
}
|
|
1015
|
+
}
|
|
1016
|
+
`
|
|
1017
|
+
];
|
|
1018
|
+
}
|
|
1019
|
+
/** The badge goes between the field and the validation message; everything else is the base's. */
|
|
1020
|
+
render() {
|
|
1021
|
+
return T`${this.renderPrompt()}${this.renderTextarea()}
|
|
1022
|
+
<span part=${this.correctionPart} aria-hidden="true"></span>
|
|
1023
|
+
${this.renderValidationMessage()}`;
|
|
1024
|
+
}
|
|
1025
|
+
};
|
|
1026
|
+
__decorate8([
|
|
1027
|
+
n({ attribute: "candidate-correction", reflect: true, noAccessor: true })
|
|
1028
|
+
], QtiExtendedTextInteractionCorrection.prototype, "candidateCorrection", void 0);
|
|
1029
|
+
|
|
1030
|
+
// ../qti-corrections/dist/interactions/shared.js
|
|
1031
|
+
var parsePairs = (response) => {
|
|
1032
|
+
if (!response)
|
|
1033
|
+
return [];
|
|
1034
|
+
const entries = Array.isArray(response) ? response : [response];
|
|
1035
|
+
return entries.map((entry) => {
|
|
1036
|
+
const [source, target] = entry.split(" ");
|
|
1037
|
+
return { source, target };
|
|
1038
|
+
});
|
|
1039
|
+
};
|
|
1040
|
+
|
|
1041
|
+
// ../qti-corrections/dist/interactions/qti-gap-match-interaction-correction.js
|
|
1042
|
+
var QtiGapMatchInteractionCorrection = class extends DragDropCorrectionMixin(QtiGapMatchInteraction) {
|
|
1043
|
+
toggleCandidateCorrection(show) {
|
|
1044
|
+
super.toggleCandidateCorrection(show);
|
|
1045
|
+
const matches = parsePairs(this.correctResponse);
|
|
1046
|
+
for (const target of this.querySelectorAll("qti-gap")) {
|
|
1047
|
+
const targetId = target.getAttribute("identifier");
|
|
1048
|
+
const selectedChoices = target.drags;
|
|
1049
|
+
for (const choice of selectedChoices) {
|
|
1050
|
+
choice.candidateCorrection = null;
|
|
1051
|
+
if (show && matches.some((match) => match.source === choice.identifier && match.target === targetId)) {
|
|
1052
|
+
choice.candidateCorrection = "correct";
|
|
1053
|
+
} else if (show) {
|
|
1054
|
+
choice.candidateCorrection = "incorrect";
|
|
1055
|
+
}
|
|
1056
|
+
}
|
|
1057
|
+
}
|
|
1058
|
+
}
|
|
1059
|
+
};
|
|
1060
|
+
|
|
1061
|
+
// ../qti-corrections/dist/interactions/qti-graphic-associate-interaction-correction.js
|
|
1062
|
+
var QtiGraphicAssociateInteractionCorrection = class extends CandidateCorrectionMixin(QtiGraphicAssociateInteraction) {
|
|
1063
|
+
#correctLines = [];
|
|
1064
|
+
toggleInternalCorrectResponse(show) {
|
|
1065
|
+
super.toggleInternalCorrectResponse(show);
|
|
1066
|
+
const response = this.correctResponse;
|
|
1067
|
+
const previous = this.#correctLines;
|
|
1068
|
+
this.#correctLines = show && response ? Array.isArray(response) ? [...response] : [response] : [];
|
|
1069
|
+
this.requestUpdate("correctLines", previous);
|
|
1070
|
+
}
|
|
1071
|
+
renderSupplementalLines() {
|
|
1072
|
+
return c2(this.#correctLines, (line) => line, (line) => b`
|
|
1073
|
+
<line
|
|
1074
|
+
part="correct-line"
|
|
1075
|
+
x1=${parseInt(this.querySelector(`[identifier=${line.split(" ")[0]}]`).style.left)}
|
|
1076
|
+
y1=${parseInt(this.querySelector(`[identifier=${line.split(" ")[0]}]`).style.top)}
|
|
1077
|
+
x2=${parseInt(this.querySelector(`[identifier=${line.split(" ")[1]}]`).style.left)}
|
|
1078
|
+
y2=${parseInt(this.querySelector(`[identifier=${line.split(" ")[1]}]`).style.top)}
|
|
1079
|
+
stroke="var(--qti-correct)"
|
|
1080
|
+
stroke-width="3"
|
|
1081
|
+
stroke-dasharray="5,5"
|
|
1082
|
+
/>
|
|
1083
|
+
`);
|
|
1084
|
+
}
|
|
1085
|
+
};
|
|
1086
|
+
|
|
1087
|
+
// ../qti-corrections/dist/interactions/qti-graphic-gap-match-interaction-correction.js
|
|
1088
|
+
var QtiGraphicGapMatchInteractionCorrection = class extends DragDropCorrectionMixin(QtiGraphicGapMatchInteraction) {
|
|
1089
|
+
};
|
|
1090
|
+
|
|
1091
|
+
// ../qti-corrections/dist/interactions/qti-graphic-order-interaction-correction.js
|
|
1092
|
+
var QtiGraphicOrderInteractionCorrection = class extends CandidateCorrectionMixin(QtiGraphicOrderInteraction) {
|
|
1093
|
+
resolvePinColor(choice) {
|
|
1094
|
+
const correctableChoice = choice;
|
|
1095
|
+
if (correctableChoice.matches(":state(candidate-incorrect)"))
|
|
1096
|
+
return "var(--qti-incorrect)";
|
|
1097
|
+
if (correctableChoice.matches(":state(candidate-correct)"))
|
|
1098
|
+
return "var(--qti-correct)";
|
|
1099
|
+
if (correctableChoice.matches(":state(correct-response)"))
|
|
1100
|
+
return "var(--qti-answer-border)";
|
|
1101
|
+
return super.resolvePinColor(choice);
|
|
1102
|
+
}
|
|
1103
|
+
toggleInternalCorrectResponse(show) {
|
|
1104
|
+
super.toggleInternalCorrectResponse(show);
|
|
1105
|
+
const response = this.correctResponse;
|
|
1106
|
+
const correctOrder = response ? Array.isArray(response) ? response : [response] : [];
|
|
1107
|
+
for (const hotspot of this._choiceElements) {
|
|
1108
|
+
const index = correctOrder.indexOf(hotspot.identifier);
|
|
1109
|
+
hotspot.orderCorrect = show && index >= 0 ? index + 1 : null;
|
|
1110
|
+
}
|
|
1111
|
+
this.refreshLocatorPins();
|
|
1112
|
+
}
|
|
1113
|
+
toggleCandidateCorrection(show) {
|
|
1114
|
+
super.toggleCandidateCorrection(show);
|
|
1115
|
+
const response = this.correctResponse;
|
|
1116
|
+
const correctOrder = response ? Array.isArray(response) ? response : [response] : [];
|
|
1117
|
+
for (const hotspot of this._choiceElements) {
|
|
1118
|
+
hotspot.candidateCorrection = null;
|
|
1119
|
+
if (show && hotspot.order != null) {
|
|
1120
|
+
hotspot.candidateCorrection = correctOrder[hotspot.order - 1] === hotspot.identifier ? "correct" : "incorrect";
|
|
1121
|
+
}
|
|
1122
|
+
}
|
|
1123
|
+
this.refreshLocatorPins();
|
|
1124
|
+
}
|
|
1125
|
+
};
|
|
1126
|
+
|
|
1127
|
+
// ../qti-corrections/dist/interactions/qti-hotspot-interaction-correction.js
|
|
1128
|
+
var QtiHotspotInteractionCorrection = class extends ChoiceCorrectionMixin(QtiHotspotInteraction) {
|
|
1129
|
+
};
|
|
1130
|
+
|
|
1131
|
+
// ../qti-corrections/dist/interactions/qti-hottext-interaction-correction.js
|
|
1132
|
+
var QtiHottextInteractionCorrection = class extends ChoiceCorrectionMixin(QtiHottextInteraction) {
|
|
1133
|
+
};
|
|
1134
|
+
|
|
1135
|
+
// ../qti-corrections/dist/interactions/qti-inline-choice-interaction-correction.js
|
|
1136
|
+
var QtiInlineChoiceInteractionCorrection = class extends CandidateCorrectionMixin(QtiInlineChoiceInteraction) {
|
|
1137
|
+
static get styles() {
|
|
1138
|
+
return [
|
|
1139
|
+
QtiInlineChoiceInteraction.styles,
|
|
1140
|
+
correctionPart,
|
|
1141
|
+
i`
|
|
1142
|
+
/*
|
|
1143
|
+
* Only the TRAILING inset — the leading gap is the shared --qti-glyph-gap, like every other
|
|
1144
|
+
* badge. This used to set both margins to --qti-gap (1rem), twice everyone else's 0.5em, on
|
|
1145
|
+
* the one token qti-variables.css calls "the page's rhythm … an order of magnitude too wide
|
|
1146
|
+
* for a glyph sitting inside a line".
|
|
1147
|
+
*
|
|
1148
|
+
* The trailing inset is needed here, and in text-entry, because these two put the field's box
|
|
1149
|
+
* on the HOST while its padding sits on an inner element (::part(trigger), ::part(input)) —
|
|
1150
|
+
* so a badge that is a child of the host falls outside that padding and lands on the border.
|
|
1151
|
+
* Chips, choices and hottext carry their padding on the host, so their badge is already inset
|
|
1152
|
+
* by it and needs nothing.
|
|
1153
|
+
*/
|
|
1154
|
+
[part~='correction'] {
|
|
1155
|
+
margin-inline-end: var(--qti-correction-inset);
|
|
1156
|
+
}
|
|
1157
|
+
`
|
|
1158
|
+
];
|
|
1159
|
+
}
|
|
1160
|
+
/**
|
|
1161
|
+
* Internal mode defers to the full correct response, exactly as text-entry does.
|
|
1162
|
+
*
|
|
1163
|
+
* There is no room beside a dropdown for an answer key: the interaction sits inside a line of
|
|
1164
|
+
* running text, so a marker next to the field competes with the sentence around it, and when the
|
|
1165
|
+
* candidate happened to pick the correct option it printed the same word twice. The full variant
|
|
1166
|
+
* puts the key in a `div.full-correct-response-inline` after the field instead — one already-themed
|
|
1167
|
+
* presentation for both inline interactions rather than a second one only these two use.
|
|
1168
|
+
*
|
|
1169
|
+
* `super` is deliberately not called: its `show-correct-response` host state paints the dashed
|
|
1170
|
+
* outline in qti-states.css, and this element is no longer the thing presenting the key — the
|
|
1171
|
+
* wrapper beside it is. Leaving the state off keeps internal mode looking identical to an item
|
|
1172
|
+
* authored with `show-full-correct-response`.
|
|
1173
|
+
*
|
|
1174
|
+
* The guard stops the two entry points rendering two wrappers: `showFullCorrectResponse` has its
|
|
1175
|
+
* own watcher, so with both flags set this would otherwise run a second time.
|
|
1176
|
+
*/
|
|
1177
|
+
toggleInternalCorrectResponse(show) {
|
|
1178
|
+
if (!this.showFullCorrectResponse)
|
|
1179
|
+
this.toggleFullCorrectResponse(show);
|
|
1180
|
+
}
|
|
1181
|
+
/**
|
|
1182
|
+
* The key is shown whether or not the candidate was right.
|
|
1183
|
+
*
|
|
1184
|
+
* The base withholds it from a correct candidate, on the reasoning that their answer already is
|
|
1185
|
+
* the key. That reasoning does not survive contact with this element: asking for the correct
|
|
1186
|
+
* response and being shown nothing is indistinguishable from the feature being broken, and it is
|
|
1187
|
+
* the only inline interaction where the answer and the key are the same short phrase, so there is
|
|
1188
|
+
* no visual clue either. Show it, and let the correctness badge say who was right.
|
|
1189
|
+
*/
|
|
1190
|
+
get withholdsFullCorrectResponseWhenCorrect() {
|
|
1191
|
+
return false;
|
|
1192
|
+
}
|
|
1193
|
+
/** The badge trails the validation message; everything else is the base's. */
|
|
1194
|
+
render() {
|
|
1195
|
+
return T`
|
|
1196
|
+
${this.renderTrigger()} ${this.renderMenu()} ${this.renderValidationMessage()}
|
|
1197
|
+
<span part=${this.correctionPart} aria-hidden="true"></span>
|
|
1198
|
+
`;
|
|
1199
|
+
}
|
|
1200
|
+
};
|
|
1201
|
+
|
|
1202
|
+
// ../qti-corrections/dist/interactions/qti-match-interaction-correction.js
|
|
1203
|
+
var QtiMatchInteractionCorrection = class extends DragDropCorrectionMixin(QtiMatchInteraction) {
|
|
1204
|
+
#correctPairs = /* @__PURE__ */ new Set();
|
|
1205
|
+
toggleCandidateCorrection(show) {
|
|
1206
|
+
super.toggleCandidateCorrection(show);
|
|
1207
|
+
const matches = parsePairs(this.correctResponse);
|
|
1208
|
+
this.#correctPairs = show ? new Set(matches.map((match) => `${match.source} ${match.target}`)) : /* @__PURE__ */ new Set();
|
|
1209
|
+
for (const target of this.targetChoices) {
|
|
1210
|
+
const targetId = target.getAttribute("identifier");
|
|
1211
|
+
const selectedChoices = target.drags;
|
|
1212
|
+
for (const choice of selectedChoices) {
|
|
1213
|
+
choice.candidateCorrection = null;
|
|
1214
|
+
if (show) {
|
|
1215
|
+
choice.candidateCorrection = this.#correctPairs.has(`${choice.identifier} ${targetId}`) ? "correct" : "incorrect";
|
|
1216
|
+
}
|
|
1217
|
+
}
|
|
1218
|
+
}
|
|
1219
|
+
this.requestUpdate();
|
|
1220
|
+
}
|
|
1221
|
+
getCellStateVariant(value, checked) {
|
|
1222
|
+
if (!this.showCandidateCorrection || !checked)
|
|
1223
|
+
return "";
|
|
1224
|
+
return this.#correctPairs.has(value) ? "correct" : "incorrect";
|
|
1225
|
+
}
|
|
1226
|
+
};
|
|
1227
|
+
|
|
1228
|
+
// ../qti-corrections/dist/utils/longest-increasing-subsequence.js
|
|
1229
|
+
function findLongestIncreasingSubsequenceIndices(sequence) {
|
|
1230
|
+
if (sequence.length === 0) {
|
|
1231
|
+
return /* @__PURE__ */ new Set();
|
|
1232
|
+
}
|
|
1233
|
+
const lengthEndingAt = new Array(sequence.length).fill(1);
|
|
1234
|
+
const predecessorIndex = new Array(sequence.length).fill(-1);
|
|
1235
|
+
for (let currentIndex = 0; currentIndex < sequence.length; currentIndex++) {
|
|
1236
|
+
for (let previousIndex = 0; previousIndex < currentIndex; previousIndex++) {
|
|
1237
|
+
if (sequence[previousIndex] < sequence[currentIndex] && lengthEndingAt[previousIndex] + 1 > lengthEndingAt[currentIndex]) {
|
|
1238
|
+
lengthEndingAt[currentIndex] = lengthEndingAt[previousIndex] + 1;
|
|
1239
|
+
predecessorIndex[currentIndex] = previousIndex;
|
|
1240
|
+
}
|
|
1241
|
+
}
|
|
1242
|
+
}
|
|
1243
|
+
let bestEndIndex = 0;
|
|
1244
|
+
for (let index = 1; index < sequence.length; index++) {
|
|
1245
|
+
if (lengthEndingAt[index] > lengthEndingAt[bestEndIndex]) {
|
|
1246
|
+
bestEndIndex = index;
|
|
1247
|
+
}
|
|
1248
|
+
}
|
|
1249
|
+
const resultIndices = /* @__PURE__ */ new Set();
|
|
1250
|
+
for (let index = bestEndIndex; index !== -1; index = predecessorIndex[index]) {
|
|
1251
|
+
resultIndices.add(index);
|
|
1252
|
+
}
|
|
1253
|
+
return resultIndices;
|
|
1254
|
+
}
|
|
1255
|
+
function findCorrectlyPlacedIdentifiers(candidateOrder, correctOrder) {
|
|
1256
|
+
const rankByIdentifier = new Map(correctOrder.map((identifier, position) => [identifier, position]));
|
|
1257
|
+
const knownIdentifiers = candidateOrder.filter((identifier) => rankByIdentifier.has(identifier));
|
|
1258
|
+
const rankSequence = knownIdentifiers.map((identifier) => rankByIdentifier.get(identifier));
|
|
1259
|
+
const winningIndices = findLongestIncreasingSubsequenceIndices(rankSequence);
|
|
1260
|
+
const result = /* @__PURE__ */ new Set();
|
|
1261
|
+
winningIndices.forEach((index) => result.add(knownIdentifiers[index]));
|
|
1262
|
+
return result;
|
|
1263
|
+
}
|
|
1264
|
+
|
|
1265
|
+
// ../qti-corrections/dist/interactions/qti-order-interaction-correction.js
|
|
1266
|
+
var QtiOrderInteractionCorrection = class extends DragDropCorrectionMixin(QtiOrderInteraction) {
|
|
1267
|
+
toggleCandidateCorrection(show) {
|
|
1268
|
+
super.toggleCandidateCorrection(show);
|
|
1269
|
+
const dropTargets = Array.from(this.shadowRoot.querySelectorAll(`[part~='drop']`));
|
|
1270
|
+
const placedChoices = dropTargets.flatMap((drop) => this.chipsIn(drop));
|
|
1271
|
+
for (const choice of placedChoices)
|
|
1272
|
+
choice.candidateCorrection = null;
|
|
1273
|
+
if (!show)
|
|
1274
|
+
return;
|
|
1275
|
+
const response = this.correctResponse;
|
|
1276
|
+
const entries = response ? Array.isArray(response) ? response : [response] : [];
|
|
1277
|
+
const correctOrder = entries.map((entry, index) => {
|
|
1278
|
+
const [identifier, dropId] = entry.split(" ");
|
|
1279
|
+
const parsed = dropId?.startsWith("droplist") ? parseInt(dropId.slice("droplist".length), 10) : index;
|
|
1280
|
+
return { identifier, dropIndex: Number.isNaN(parsed) ? index : parsed };
|
|
1281
|
+
}).filter((entry) => entry.identifier).sort((a, b2) => a.dropIndex - b2.dropIndex).map((entry) => entry.identifier);
|
|
1282
|
+
if (correctOrder.length === 0)
|
|
1283
|
+
return;
|
|
1284
|
+
const placedEntries = placedChoices.map((choice) => ({ choice, identifier: choice.getAttribute("identifier") })).filter((entry) => Boolean(entry.identifier));
|
|
1285
|
+
const correctlyPlaced = findCorrectlyPlacedIdentifiers(placedEntries.map((entry) => entry.identifier), correctOrder);
|
|
1286
|
+
for (const { choice, identifier } of placedEntries) {
|
|
1287
|
+
choice.candidateCorrection = correctlyPlaced.has(identifier) ? "correct" : "incorrect";
|
|
1288
|
+
}
|
|
1289
|
+
}
|
|
1290
|
+
};
|
|
1291
|
+
|
|
1292
|
+
// ../qti-corrections/dist/interactions/qti-portable-custom-interaction-correction.js
|
|
1293
|
+
var QtiPortableCustomInteractionCorrection = class extends CandidateCorrectionMixin(QtiPortableCustomInteraction) {
|
|
1294
|
+
toggleInternalCorrectResponse(show) {
|
|
1295
|
+
super.toggleInternalCorrectResponse(show);
|
|
1296
|
+
const responseVariable = this.responseVariable;
|
|
1297
|
+
const sourceResponse = responseVariable?.correctResponse ?? this.correctResponse;
|
|
1298
|
+
this.correctResponse = show ? sourceResponse : responseVariable?.cardinality === "single" ? "" : [];
|
|
1299
|
+
const containerId = `correct-response-container-${this.responseIdentifier}`;
|
|
1300
|
+
this.parentElement?.querySelectorAll(`#${containerId}`).forEach((element) => element.remove());
|
|
1301
|
+
if (!show) {
|
|
1302
|
+
this.enable();
|
|
1303
|
+
return;
|
|
1304
|
+
}
|
|
1305
|
+
this.disable();
|
|
1306
|
+
if (!this.correctResponse)
|
|
1307
|
+
return;
|
|
1308
|
+
const container = document.createElement("div");
|
|
1309
|
+
container.id = containerId;
|
|
1310
|
+
container.className = "pci-correct-response-container";
|
|
1311
|
+
Object.assign(container.style, {
|
|
1312
|
+
position: "relative",
|
|
1313
|
+
marginTop: "20px",
|
|
1314
|
+
border: "2px solid green",
|
|
1315
|
+
padding: "16px",
|
|
1316
|
+
borderRadius: "4px",
|
|
1317
|
+
backgroundColor: "rgba(0, 128, 0, 0.05)"
|
|
1318
|
+
});
|
|
1319
|
+
const label = document.createElement("div");
|
|
1320
|
+
label.textContent = "Correct Response:";
|
|
1321
|
+
Object.assign(label.style, { fontWeight: "bold", marginBottom: "10px", color: "green" });
|
|
1322
|
+
container.append(label);
|
|
1323
|
+
const viewer = this.cloneNode(false);
|
|
1324
|
+
viewer.removeAttribute("id");
|
|
1325
|
+
viewer.removeAttribute("show-correct-response");
|
|
1326
|
+
viewer.removeAttribute("show-full-correct-response");
|
|
1327
|
+
viewer.removeAttribute("show-candidate-correction");
|
|
1328
|
+
viewer.isFullCorrectResponse = true;
|
|
1329
|
+
const originalResponseId = this.responseIdentifier;
|
|
1330
|
+
viewer.responseIdentifier = `${originalResponseId}-correct`;
|
|
1331
|
+
for (const child of Array.from(this.children)) {
|
|
1332
|
+
if (child.tagName.startsWith("QTI-"))
|
|
1333
|
+
viewer.append(child.cloneNode(true));
|
|
1334
|
+
}
|
|
1335
|
+
const correctResponse = this.correctResponse;
|
|
1336
|
+
const cardinality = responseVariable?.cardinality ?? (Array.isArray(correctResponse) ? "multiple" : "single");
|
|
1337
|
+
const baseType = responseVariable?.baseType ?? "string";
|
|
1338
|
+
viewer.status = "solution";
|
|
1339
|
+
viewer.responseDeclaration = {
|
|
1340
|
+
baseType,
|
|
1341
|
+
cardinality,
|
|
1342
|
+
correctResponse: { value: correctResponse }
|
|
1343
|
+
};
|
|
1344
|
+
viewer.addEventListener("qti-portable-custom-interaction-loaded", () => {
|
|
1345
|
+
const value = viewer.responseVariablesToQtiVariableJSON(correctResponse, cardinality, baseType);
|
|
1346
|
+
viewer.sendMessageToIframe("setBoundTo", { [originalResponseId]: value });
|
|
1347
|
+
viewer.sendMessageToIframe("setState", { state: "review" });
|
|
1348
|
+
}, { once: true });
|
|
1349
|
+
viewer.style.pointerEvents = "none";
|
|
1350
|
+
container.append(viewer);
|
|
1351
|
+
this.after(container);
|
|
1352
|
+
}
|
|
1353
|
+
};
|
|
1354
|
+
|
|
1355
|
+
// ../qti-corrections/dist/interactions/qti-select-point-interaction-correction.js
|
|
1356
|
+
var QtiSelectPointInteractionCorrection = class extends CandidateCorrectionMixin(QtiSelectPointInteraction) {
|
|
1357
|
+
#correctAreas = [];
|
|
1358
|
+
#responseCorrection = [];
|
|
1359
|
+
static {
|
|
1360
|
+
this.styles = [
|
|
1361
|
+
QtiSelectPointInteraction.styles,
|
|
1362
|
+
i`
|
|
1363
|
+
[part~='correct'] {
|
|
1364
|
+
--qti-select-point-marker-color: var(--qti-correct);
|
|
1365
|
+
}
|
|
1366
|
+
[part~='incorrect'] {
|
|
1367
|
+
--qti-select-point-marker-color: var(--qti-incorrect);
|
|
1368
|
+
}
|
|
1369
|
+
`
|
|
1370
|
+
];
|
|
1371
|
+
}
|
|
1372
|
+
toggleCandidateCorrection(show) {
|
|
1373
|
+
super.toggleCandidateCorrection(show);
|
|
1374
|
+
const previous = this.#responseCorrection;
|
|
1375
|
+
this.#responseCorrection = [];
|
|
1376
|
+
if (!show) {
|
|
1377
|
+
this.requestUpdate("responseCorrection", previous);
|
|
1378
|
+
return;
|
|
1379
|
+
}
|
|
1380
|
+
const areaEntries = this._effectiveAreaEntries;
|
|
1381
|
+
const baseType = this.responseVariable?.baseType;
|
|
1382
|
+
const response = this.correctResponse;
|
|
1383
|
+
for (const point of this.responsePoints) {
|
|
1384
|
+
let correct = areaEntries.some((area) => ScoringHelper.isPointInArea(`${point.x} ${point.y}`, `${area.shape},${area.coords}`, baseType));
|
|
1385
|
+
if (!areaEntries.length && response) {
|
|
1386
|
+
const expected = Array.isArray(response) ? response : [response];
|
|
1387
|
+
correct = expected.some((entry) => {
|
|
1388
|
+
const [x, y] = entry.split(" ").map(Number);
|
|
1389
|
+
return Number.isFinite(x) && Number.isFinite(y) && Math.hypot(point.x - x, point.y - y) <= 10;
|
|
1390
|
+
});
|
|
1391
|
+
}
|
|
1392
|
+
this.#responseCorrection.push(correct);
|
|
1393
|
+
}
|
|
1394
|
+
this.requestUpdate("responseCorrection", previous);
|
|
1395
|
+
}
|
|
1396
|
+
toggleInternalCorrectResponse(show) {
|
|
1397
|
+
super.toggleInternalCorrectResponse(show);
|
|
1398
|
+
if (!show) {
|
|
1399
|
+
const previous2 = this.#correctAreas;
|
|
1400
|
+
this.#correctAreas = [];
|
|
1401
|
+
this.requestUpdate("correctAreas", previous2);
|
|
1402
|
+
return;
|
|
1403
|
+
}
|
|
1404
|
+
let entries = this._effectiveAreaEntries;
|
|
1405
|
+
if (!entries.length) {
|
|
1406
|
+
const response = this.correctResponse;
|
|
1407
|
+
const values = response ? Array.isArray(response) ? response : [response] : [];
|
|
1408
|
+
if (values.some((value) => value.split(" ").length < 2)) {
|
|
1409
|
+
console.error("No valid correct responses found.");
|
|
1410
|
+
return;
|
|
1411
|
+
}
|
|
1412
|
+
entries = values.map((value) => ({
|
|
1413
|
+
shape: "circle",
|
|
1414
|
+
coords: `${value.split(" ").join(",")},10`,
|
|
1415
|
+
defaultValue: 1,
|
|
1416
|
+
mappedValue: 1
|
|
1417
|
+
}));
|
|
1418
|
+
}
|
|
1419
|
+
const previous = this.#correctAreas;
|
|
1420
|
+
this.#correctAreas = entries.map((entry) => ({ shape: entry.shape, coords: entry.coords }));
|
|
1421
|
+
this.requestUpdate("correctAreas", previous);
|
|
1422
|
+
}
|
|
1423
|
+
pointPart(_point, index) {
|
|
1424
|
+
const verdict = this.#responseCorrection[index];
|
|
1425
|
+
return verdict === void 0 ? "point" : `point ${verdict ? "correct" : "incorrect"}`;
|
|
1426
|
+
}
|
|
1427
|
+
renderSupplementalLayer() {
|
|
1428
|
+
return c2(this.#correctAreas, (area) => `${area.shape}:${area.coords}`, (area, index) => T`<div
|
|
1429
|
+
style=${o({
|
|
1430
|
+
position: "absolute",
|
|
1431
|
+
pointerEvents: "none",
|
|
1432
|
+
backgroundColor: "var(--qti-correct)",
|
|
1433
|
+
opacity: "0.5"
|
|
1434
|
+
})}
|
|
1435
|
+
data-correction-area
|
|
1436
|
+
data-coord=${area.coords}
|
|
1437
|
+
data-shape=${area.shape}
|
|
1438
|
+
alt=${`correct-response-${index + 1}`}
|
|
1439
|
+
></div>`);
|
|
1440
|
+
}
|
|
1441
|
+
updated(changedProperties) {
|
|
1442
|
+
super.updated(changedProperties);
|
|
1443
|
+
if (changedProperties.has("correctAreas")) {
|
|
1444
|
+
this.positionOverlayElements(this.shadowRoot.querySelectorAll("[data-correction-area]"));
|
|
1445
|
+
}
|
|
1446
|
+
}
|
|
1447
|
+
};
|
|
1448
|
+
|
|
1449
|
+
// ../qti-corrections/dist/interactions/qti-slider-interaction-correction.js
|
|
1450
|
+
var QtiSliderInteractionCorrection = class extends CandidateCorrectionMixin(QtiSliderInteraction) {
|
|
1451
|
+
#correctResponseNumber = null;
|
|
1452
|
+
static {
|
|
1453
|
+
this.styles = [
|
|
1454
|
+
QtiSliderInteraction.styles,
|
|
1455
|
+
i`
|
|
1456
|
+
[part='knob-correct'] {
|
|
1457
|
+
background-color: var(--qti-correct-light);
|
|
1458
|
+
border: 2px solid var(--qti-correct);
|
|
1459
|
+
position: relative;
|
|
1460
|
+
height: 1rem;
|
|
1461
|
+
width: 1rem;
|
|
1462
|
+
transform-origin: center;
|
|
1463
|
+
transform: translateX(-50%);
|
|
1464
|
+
cursor: pointer;
|
|
1465
|
+
border-radius: 9999px;
|
|
1466
|
+
left: var(--value-percentage-correct);
|
|
1467
|
+
}
|
|
1468
|
+
`
|
|
1469
|
+
];
|
|
1470
|
+
}
|
|
1471
|
+
toggleInternalCorrectResponse(show) {
|
|
1472
|
+
super.toggleInternalCorrectResponse(show);
|
|
1473
|
+
const response = this.correctResponse;
|
|
1474
|
+
const raw = Array.isArray(response) ? response[0] : response;
|
|
1475
|
+
const value = show && raw ? parseFloat(raw) : NaN;
|
|
1476
|
+
const previous = this.#correctResponseNumber;
|
|
1477
|
+
this.#correctResponseNumber = Number.isFinite(value) ? value : null;
|
|
1478
|
+
if (this.#correctResponseNumber !== null) {
|
|
1479
|
+
const percentage = (this.#correctResponseNumber - this.min) / (this.max - this.min) * 100;
|
|
1480
|
+
this.style.setProperty("--value-percentage-correct", `${percentage}%`);
|
|
1481
|
+
} else {
|
|
1482
|
+
this.style.removeProperty("--value-percentage-correct");
|
|
1483
|
+
}
|
|
1484
|
+
this.requestUpdate("correctResponseNumber", previous);
|
|
1485
|
+
}
|
|
1486
|
+
renderRailSupplement() {
|
|
1487
|
+
return this.#correctResponseNumber === null ? A : T`<div id="knob-correct" part="knob-correct">
|
|
1488
|
+
<div id="value" part="value">${this.#correctResponseNumber}</div>
|
|
1489
|
+
</div>`;
|
|
1490
|
+
}
|
|
1491
|
+
};
|
|
1492
|
+
|
|
1493
|
+
// ../qti-corrections/dist/interactions/qti-text-entry-interaction-correction.js
|
|
1494
|
+
var QtiTextEntryInteractionCorrection = class extends CandidateCorrectionMixin(QtiTextEntryInteraction) {
|
|
1495
|
+
static {
|
|
1496
|
+
this.styles = [
|
|
1497
|
+
QtiTextEntryInteraction.styles,
|
|
1498
|
+
correctionPart,
|
|
1499
|
+
i`
|
|
1500
|
+
/*
|
|
1501
|
+
* The trailing inset only — size and leading gap come from the shared sheet.
|
|
1502
|
+
*
|
|
1503
|
+
* This block used to also set position: static; translate: none (dead: nothing positions this
|
|
1504
|
+
* badge) and size it with --qti-control-size, the radio/checkbox token — 1rem, absolute, where
|
|
1505
|
+
* every other badge is 1em and scales with the text it annotates. The two agreed only while the
|
|
1506
|
+
* item's font-size happened to equal the root's.
|
|
1507
|
+
*
|
|
1508
|
+
* The inset is needed because the field's box is the HOST while its padding is on ::part(input),
|
|
1509
|
+
* so the badge — a child of the host — falls outside that padding and lands flush on the border.
|
|
1510
|
+
* Measured at 0px from the border, against 16px for a choice and 12.8px for a chip.
|
|
1511
|
+
*/
|
|
1512
|
+
[part~='correction'] {
|
|
1513
|
+
margin-inline-end: var(--qti-correction-inset);
|
|
1514
|
+
}
|
|
1515
|
+
:host {
|
|
1516
|
+
position: relative;
|
|
1517
|
+
anchor-name: --text-entry-host, --qti-correction-anchor;
|
|
1518
|
+
}
|
|
1519
|
+
[part='correct'] {
|
|
1520
|
+
position: absolute;
|
|
1521
|
+
position-anchor: --text-entry-host;
|
|
1522
|
+
position-area: top span-right;
|
|
1523
|
+
margin-bottom: 0.25rem;
|
|
1524
|
+
padding: var(--qti-padding-box);
|
|
1525
|
+
background-color: var(--qti-bg);
|
|
1526
|
+
white-space: nowrap;
|
|
1527
|
+
}
|
|
1528
|
+
`
|
|
1529
|
+
];
|
|
1530
|
+
}
|
|
1531
|
+
get correctness() {
|
|
1532
|
+
const variable = this.responseVariable;
|
|
1533
|
+
if (!variable)
|
|
1534
|
+
return super.correctness;
|
|
1535
|
+
if (variable.value === null)
|
|
1536
|
+
return Correctness.Incorrect;
|
|
1537
|
+
if (variable.mapping) {
|
|
1538
|
+
const maxScore = variable.mapping.mapEntries.reduce((maximum, entry) => Math.max(entry.mappedValue, maximum), 0);
|
|
1539
|
+
for (const entry of variable.mapping.mapEntries) {
|
|
1540
|
+
let expected = entry.mapKey;
|
|
1541
|
+
let actual = variable.value;
|
|
1542
|
+
if (!entry.caseSensitive) {
|
|
1543
|
+
expected = expected.toLowerCase();
|
|
1544
|
+
actual = actual.toLowerCase();
|
|
1545
|
+
}
|
|
1546
|
+
if (expected !== actual)
|
|
1547
|
+
continue;
|
|
1548
|
+
if (entry.mappedValue === maxScore)
|
|
1549
|
+
return Correctness.Correct;
|
|
1550
|
+
if (entry.mappedValue <= (variable.mapping.defaultValue || 0))
|
|
1551
|
+
return Correctness.Incorrect;
|
|
1552
|
+
return Correctness.PartiallyCorrect;
|
|
1553
|
+
}
|
|
1554
|
+
}
|
|
1555
|
+
return variable.correctResponse === variable.value ? Correctness.Correct : Correctness.Incorrect;
|
|
1556
|
+
}
|
|
1557
|
+
toggleInternalCorrectResponse(show) {
|
|
1558
|
+
if (!this.showFullCorrectResponse)
|
|
1559
|
+
this.toggleFullCorrectResponse(show);
|
|
1560
|
+
}
|
|
1561
|
+
/** The badge goes between the field and the validation message; everything else is the base's. */
|
|
1562
|
+
render() {
|
|
1563
|
+
return T`
|
|
1564
|
+
${this.renderAnswer()} ${this.renderInput()}
|
|
1565
|
+
<span part=${this.correctionPart} aria-hidden="true"></span>
|
|
1566
|
+
${this.renderValidationMessage()}
|
|
1567
|
+
`;
|
|
1568
|
+
}
|
|
1569
|
+
};
|
|
1570
|
+
|
|
1571
|
+
export {
|
|
1572
|
+
Correctness,
|
|
1573
|
+
CorrectResponseMixin,
|
|
1574
|
+
correctionPart,
|
|
1575
|
+
CandidateCorrectionMixin,
|
|
1576
|
+
ChoiceCorrectionMixin,
|
|
1577
|
+
QtiGapTextCorrection,
|
|
1578
|
+
QtiHotspotChoiceCorrection,
|
|
1579
|
+
QtiHottextCorrection,
|
|
1580
|
+
QtiSimpleAssociableChoiceCorrection,
|
|
1581
|
+
QtiSimpleChoiceCorrection,
|
|
1582
|
+
QtiAssessmentItemCorrection,
|
|
1583
|
+
QtiItemCorrection,
|
|
1584
|
+
TestNavigationCorrection,
|
|
1585
|
+
QtiTestCorrection,
|
|
1586
|
+
TestCheckItemCorrection,
|
|
1587
|
+
ItemCorrectResponseMode,
|
|
1588
|
+
ItemShowCandidateCorrection,
|
|
1589
|
+
ItemShowCorrectResponse,
|
|
1590
|
+
TestShowCorrectResponse,
|
|
1591
|
+
QtiAssociateInteractionCorrection,
|
|
1592
|
+
QtiChoiceInteractionCorrection,
|
|
1593
|
+
QtiExtendedTextInteractionCorrection,
|
|
1594
|
+
QtiGapMatchInteractionCorrection,
|
|
1595
|
+
QtiGraphicAssociateInteractionCorrection,
|
|
1596
|
+
QtiGraphicGapMatchInteractionCorrection,
|
|
1597
|
+
QtiGraphicOrderInteractionCorrection,
|
|
1598
|
+
QtiHotspotInteractionCorrection,
|
|
1599
|
+
QtiHottextInteractionCorrection,
|
|
1600
|
+
QtiInlineChoiceInteractionCorrection,
|
|
1601
|
+
QtiMatchInteractionCorrection,
|
|
1602
|
+
QtiOrderInteractionCorrection,
|
|
1603
|
+
QtiPortableCustomInteractionCorrection,
|
|
1604
|
+
QtiSelectPointInteractionCorrection,
|
|
1605
|
+
QtiSliderInteractionCorrection,
|
|
1606
|
+
QtiTextEntryInteractionCorrection
|
|
1607
|
+
};
|
|
1608
|
+
//# sourceMappingURL=chunk-XU7HNT4F.js.map
|