@citolab/qti-components 8.1.0 → 9.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (63) hide show
  1. package/cdn/index.global.js +1 -1
  2. package/cdn/index.js +288 -182
  3. package/dist/base.d.ts +5 -5
  4. package/dist/base.js +1 -1
  5. package/dist/{chunk-TXIB3SKC.js → chunk-3MQNPN7A.js} +3 -3
  6. package/dist/{chunk-6V3A7NQP.js → chunk-3NPCS4IT.js} +2 -2
  7. package/dist/{chunk-MK2I3MQB.js → chunk-3VQSUWCK.js} +175 -15
  8. package/dist/chunk-3VQSUWCK.js.map +1 -0
  9. package/dist/{chunk-4XR2JHCP.js → chunk-5BXJRO5O.js} +1816 -551
  10. package/dist/chunk-5BXJRO5O.js.map +1 -0
  11. package/dist/{chunk-NZLW6EX7.js → chunk-DXEWBTJB.js} +2 -2
  12. package/dist/{chunk-Q52IJELT.js → chunk-GBDTBHUQ.js} +602 -263
  13. package/dist/chunk-GBDTBHUQ.js.map +1 -0
  14. package/dist/chunk-KCK27QBP.js +11 -0
  15. package/dist/chunk-KCK27QBP.js.map +1 -0
  16. package/dist/chunk-MKZ374OJ.js +179 -0
  17. package/dist/chunk-MKZ374OJ.js.map +1 -0
  18. package/dist/{chunk-3IACYIU2.js → chunk-RT6WZ3P7.js} +2 -2
  19. package/dist/chunk-TLTYXWW7.js +7 -0
  20. package/dist/chunk-TLTYXWW7.js.map +1 -0
  21. package/dist/{chunk-EKXZI26R.js → chunk-WCWJPIUQ.js} +58 -6
  22. package/dist/chunk-WCWJPIUQ.js.map +1 -0
  23. package/dist/{chunk-6XJUP55A.js → chunk-WKWCOV5P.js} +3 -3
  24. package/dist/chunk-WKWCOV5P.js.map +1 -0
  25. package/dist/{chunk-CF3DXJWM.js → chunk-WTV7NQHO.js} +731 -715
  26. package/dist/chunk-WTV7NQHO.js.map +1 -0
  27. package/dist/{computed.types.d-DpKIYO6e.d.ts → computed.types.d-CJarqC6s.d.ts} +12 -0
  28. package/dist/corrections.d.ts +14 -4
  29. package/dist/corrections.js +82 -7
  30. package/dist/corrections.js.map +1 -1
  31. package/dist/elements.d.ts +1 -1
  32. package/dist/elements.js +3 -3
  33. package/dist/index.d.ts +5 -5
  34. package/dist/index.js +26 -24
  35. package/dist/interactions.js +14 -15
  36. package/dist/item.css +81 -0
  37. package/dist/item.d.ts +1 -1
  38. package/dist/item.js +4 -4
  39. package/dist/loader.d.ts +1 -1
  40. package/dist/processing.d.ts +29 -3
  41. package/dist/processing.js +3 -2
  42. package/dist/qti-components-jsx.d.ts +7883 -7250
  43. package/dist/{qti-condition-expression.d-aMvBvpc6.d.ts → qti-condition-expression.d-CYwXOUb1.d.ts} +1 -1
  44. package/dist/{qti-expression.d-BietT_8b.d.ts → qti-expression.d-B_-m9emA.d.ts} +11 -1
  45. package/dist/{qti-feedback.d-DZbad0RN.d.ts → qti-feedback.d-B1EIF-fU.d.ts} +1 -0
  46. package/dist/{qti-test.d-_YAlhDbt.d.ts → qti-test.d-C6lCEMRB.d.ts} +38 -3
  47. package/dist/test.d.ts +5 -5
  48. package/dist/test.js +7 -5
  49. package/package.json +9 -9
  50. package/dist/chunk-4XR2JHCP.js.map +0 -1
  51. package/dist/chunk-6XJUP55A.js.map +0 -1
  52. package/dist/chunk-CF3DXJWM.js.map +0 -1
  53. package/dist/chunk-EKXZI26R.js.map +0 -1
  54. package/dist/chunk-IXPDMYKH.js +0 -1420
  55. package/dist/chunk-IXPDMYKH.js.map +0 -1
  56. package/dist/chunk-IYC7LZV6.js +0 -7
  57. package/dist/chunk-IYC7LZV6.js.map +0 -1
  58. package/dist/chunk-MK2I3MQB.js.map +0 -1
  59. package/dist/chunk-Q52IJELT.js.map +0 -1
  60. /package/dist/{chunk-TXIB3SKC.js.map → chunk-3MQNPN7A.js.map} +0 -0
  61. /package/dist/{chunk-6V3A7NQP.js.map → chunk-3NPCS4IT.js.map} +0 -0
  62. /package/dist/{chunk-NZLW6EX7.js.map → chunk-DXEWBTJB.js.map} +0 -0
  63. /package/dist/{chunk-3IACYIU2.js.map → chunk-RT6WZ3P7.js.map} +0 -0
@@ -1,9 +1,9 @@
1
1
  import {
2
2
  QtiModalFeedback
3
- } from "./chunk-6XJUP55A.js";
3
+ } from "./chunk-WKWCOV5P.js";
4
4
  import {
5
5
  item_default
6
- } from "./chunk-IYC7LZV6.js";
6
+ } from "./chunk-TLTYXWW7.js";
7
7
  import {
8
8
  watch
9
9
  } from "./chunk-4DB4SC5K.js";
@@ -20,7 +20,7 @@ import {
20
20
  qtiContext,
21
21
  sessionContext,
22
22
  testContext
23
- } from "./chunk-EKXZI26R.js";
23
+ } from "./chunk-WCWJPIUQ.js";
24
24
 
25
25
  // ../qti-test/dist/components/qti-assessment-item-ref/qti-assessment-item-ref.js
26
26
  import { LitElement } from "lit";
@@ -191,9 +191,72 @@ __decorate3([
191
191
  consume2({ context: testContext, subscribe: true })
192
192
  ], QtiAssessmentTest.prototype, "_testContext", void 0);
193
193
 
194
+ // ../qti-test/dist/components/qti-item-session-control/qti-item-session-control.js
195
+ import { html as html3, LitElement as LitElement4 } from "lit";
196
+ import { property as property4 } from "lit/decorators.js";
197
+ var __decorate4 = function(decorators, target, key, desc) {
198
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
199
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
200
+ 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;
201
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
202
+ };
203
+ var stringToBooleanConverter3 = {
204
+ fromAttribute(value) {
205
+ return value === "true";
206
+ },
207
+ toAttribute(value) {
208
+ return value ? "true" : "false";
209
+ }
210
+ };
211
+ var QtiItemSessionControl = class extends LitElement4 {
212
+ constructor() {
213
+ super(...arguments);
214
+ this.maxAttempts = 1;
215
+ this.showFeedback = false;
216
+ this.allowReview = true;
217
+ this.showSolution = false;
218
+ this.allowComment = false;
219
+ this.allowSkipping = true;
220
+ this.validateResponses = false;
221
+ }
222
+ async connectedCallback() {
223
+ super.connectedCallback();
224
+ await this.updateComplete;
225
+ this.dispatchEvent(new CustomEvent("qti-item-session-control-connected", {
226
+ detail: this,
227
+ bubbles: true,
228
+ composed: true
229
+ }));
230
+ }
231
+ render() {
232
+ return html3`<slot></slot>`;
233
+ }
234
+ };
235
+ __decorate4([
236
+ property4({ type: Number, attribute: "max-attempts" })
237
+ ], QtiItemSessionControl.prototype, "maxAttempts", void 0);
238
+ __decorate4([
239
+ property4({ type: Boolean, converter: stringToBooleanConverter3, attribute: "show-feedback" })
240
+ ], QtiItemSessionControl.prototype, "showFeedback", void 0);
241
+ __decorate4([
242
+ property4({ type: Boolean, converter: stringToBooleanConverter3, attribute: "allow-review" })
243
+ ], QtiItemSessionControl.prototype, "allowReview", void 0);
244
+ __decorate4([
245
+ property4({ type: Boolean, converter: stringToBooleanConverter3, attribute: "show-solution" })
246
+ ], QtiItemSessionControl.prototype, "showSolution", void 0);
247
+ __decorate4([
248
+ property4({ type: Boolean, converter: stringToBooleanConverter3, attribute: "allow-comment" })
249
+ ], QtiItemSessionControl.prototype, "allowComment", void 0);
250
+ __decorate4([
251
+ property4({ type: Boolean, converter: stringToBooleanConverter3, attribute: "allow-skipping" })
252
+ ], QtiItemSessionControl.prototype, "allowSkipping", void 0);
253
+ __decorate4([
254
+ property4({ type: Boolean, converter: stringToBooleanConverter3, attribute: "validate-responses" })
255
+ ], QtiItemSessionControl.prototype, "validateResponses", void 0);
256
+
194
257
  // ../qti-test/dist/components/qti-outcome-processing/qti-outcome-processing.js
195
- import { css, html as html3, LitElement as LitElement4 } from "lit";
196
- var QtiOutcomeProcessing = class extends LitElement4 {
258
+ import { css, html as html4, LitElement as LitElement5 } from "lit";
259
+ var QtiOutcomeProcessing = class extends LitElement5 {
197
260
  static {
198
261
  this.styles = [
199
262
  css`
@@ -204,7 +267,7 @@ var QtiOutcomeProcessing = class extends LitElement4 {
204
267
  ];
205
268
  }
206
269
  render() {
207
- return html3`<slot></slot>`;
270
+ return html4`<slot></slot>`;
208
271
  }
209
272
  process() {
210
273
  const logic = new QtiOutcomeProcessingProcessor();
@@ -221,7 +284,7 @@ var QtiOutcomeProcessingProcessor = class {
221
284
  };
222
285
 
223
286
  // ../qti-test/dist/components/qti-test-feedback/qti-test-feedback.js
224
- import { css as css2, html as html4 } from "lit";
287
+ import { css as css2, html as html5 } from "lit";
225
288
  var QtiTestFeedback = class extends QtiModalFeedback {
226
289
  static {
227
290
  this.styles = css2`
@@ -231,20 +294,20 @@ var QtiTestFeedback = class extends QtiModalFeedback {
231
294
  `;
232
295
  }
233
296
  render() {
234
- return html4``;
297
+ return html5``;
235
298
  }
236
299
  };
237
300
 
238
301
  // ../qti-test/dist/components/qti-test-part/qti-test-part.js
239
- import { html as html5, LitElement as LitElement5 } from "lit";
240
- import { property as property4 } from "lit/decorators.js";
241
- var __decorate4 = function(decorators, target, key, desc) {
302
+ import { html as html6, LitElement as LitElement6 } from "lit";
303
+ import { property as property5 } from "lit/decorators.js";
304
+ var __decorate5 = function(decorators, target, key, desc) {
242
305
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
243
306
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
244
307
  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;
245
308
  return c > 3 && r && Object.defineProperty(target, key, r), r;
246
309
  };
247
- var QtiTestPart = class extends LitElement5 {
310
+ var QtiTestPart = class extends LitElement6 {
248
311
  constructor() {
249
312
  super(...arguments);
250
313
  this.identifier = "";
@@ -271,25 +334,25 @@ var QtiTestPart = class extends LitElement5 {
271
334
  }));
272
335
  }
273
336
  render() {
274
- return html5` <slot></slot>`;
337
+ return html6` <slot></slot>`;
275
338
  }
276
339
  };
277
- __decorate4([
278
- property4({ type: String })
340
+ __decorate5([
341
+ property5({ type: String })
279
342
  ], QtiTestPart.prototype, "identifier", void 0);
280
- __decorate4([
281
- property4({ type: String })
343
+ __decorate5([
344
+ property5({ type: String })
282
345
  ], QtiTestPart.prototype, "class", void 0);
283
- __decorate4([
284
- property4({ type: String, attribute: "navigation-mode" })
346
+ __decorate5([
347
+ property5({ type: String, attribute: "navigation-mode" })
285
348
  ], QtiTestPart.prototype, "navigationMode", void 0);
286
- __decorate4([
287
- property4({ type: String, attribute: "submission-mode" })
349
+ __decorate5([
350
+ property5({ type: String, attribute: "submission-mode" })
288
351
  ], QtiTestPart.prototype, "submissionMode", void 0);
289
352
 
290
353
  // ../qti-test/dist/components/qti-test-variables/qti-test-variables.js
291
354
  import { consume as consume3 } from "@lit/context";
292
- var __decorate5 = function(decorators, target, key, desc) {
355
+ var __decorate6 = function(decorators, target, key, desc) {
293
356
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
294
357
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
295
358
  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;
@@ -334,7 +397,7 @@ var QtiTestVariables = class extends QtiExpression {
334
397
  return this.getResult();
335
398
  }
336
399
  };
337
- __decorate5([
400
+ __decorate6([
338
401
  consume3({ context: testContext, subscribe: true })
339
402
  ], QtiTestVariables.prototype, "_testContext", void 0);
340
403
  var QtiTestVariablesExpression = class {
@@ -362,12 +425,12 @@ var QtiTestVariablesExpression = class {
362
425
 
363
426
  // ../qti-test/dist/components/qti-test/qti-test.js
364
427
  import { provide as provide2 } from "@lit/context";
365
- import { html as html6, LitElement as LitElement7 } from "lit";
428
+ import { html as html7, LitElement as LitElement8 } from "lit";
366
429
  import { state } from "lit/decorators.js";
367
430
 
368
431
  // ../qti-test/dist/mixins/test-navigation.mixin.js
369
- import { property as property5 } from "lit/decorators.js";
370
- var __decorate6 = function(decorators, target, key, desc) {
432
+ import { property as property6 } from "lit/decorators.js";
433
+ var __decorate7 = function(decorators, target, key, desc) {
371
434
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
372
435
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
373
436
  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;
@@ -845,17 +908,17 @@ var TestNavigationMixin = (superClass) => {
845
908
  });
846
909
  }
847
910
  }
848
- __decorate6([
849
- property5({ type: String })
911
+ __decorate7([
912
+ property6({ type: String })
850
913
  ], TestNavigationClass.prototype, "navigate", void 0);
851
- __decorate6([
852
- property5({ type: Number })
914
+ __decorate7([
915
+ property6({ type: Number })
853
916
  ], TestNavigationClass.prototype, "requestTimeout", void 0);
854
- __decorate6([
855
- property5({ attribute: false })
917
+ __decorate7([
918
+ property6({ attribute: false })
856
919
  ], TestNavigationClass.prototype, "postLoadTransformCallback", void 0);
857
- __decorate6([
858
- property5({ attribute: false })
920
+ __decorate7([
921
+ property6({ attribute: false })
859
922
  ], TestNavigationClass.prototype, "postLoadTestTransformCallback", void 0);
860
923
  return TestNavigationClass;
861
924
  };
@@ -910,9 +973,9 @@ var TestViewMixin = (superClass) => {
910
973
 
911
974
  // ../qti-test/dist/mixins/test-base.js
912
975
  import { provide } from "@lit/context";
913
- import { LitElement as LitElement6 } from "lit";
914
- import { property as property6 } from "lit/decorators.js";
915
- var __decorate7 = function(decorators, target, key, desc) {
976
+ import { LitElement as LitElement7 } from "lit";
977
+ import { property as property7 } from "lit/decorators.js";
978
+ var __decorate8 = function(decorators, target, key, desc) {
916
979
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
917
980
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
918
981
  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;
@@ -964,11 +1027,11 @@ var TestBaseMixin = (superClass) => {
964
1027
  }
965
1028
  }
966
1029
  _initializeEventListeners() {
967
- this.addEventListener("qti-assessment-test-connected", (e) => {
1030
+ this.addEventListener("qti-testdoc-loaded", () => {
968
1031
  this.testContext = INITIAL_TEST_CONTEXT;
969
1032
  this.sessionContext = INITIAL_SESSION_CONTEXT;
970
- if (this.testContext && this.testContext.items.length > 0)
971
- return;
1033
+ });
1034
+ this.addEventListener("qti-assessment-test-connected", (e) => {
972
1035
  this._testElement = e.detail;
973
1036
  const items = Array.from(this._testElement.querySelectorAll("qti-assessment-item-ref")).map((itemRef) => {
974
1037
  return {
@@ -1020,17 +1083,17 @@ var TestBaseMixin = (superClass) => {
1020
1083
  this.dispatchEvent(new CustomEvent("qti-test-context-updated", { detail: this.testContext, bubbles: false, composed: false }));
1021
1084
  }
1022
1085
  }
1023
- __decorate7([
1024
- property6({ attribute: false, type: Object }),
1086
+ __decorate8([
1087
+ property7({ attribute: false, type: Object }),
1025
1088
  provide({ context: testContext })
1026
1089
  ], TestBaseClass.prototype, "testContext", void 0);
1027
- __decorate7([
1028
- property6({ attribute: false, type: Object }),
1090
+ __decorate8([
1091
+ property7({ attribute: false, type: Object }),
1029
1092
  provide({ context: sessionContext })
1030
1093
  ], TestBaseClass.prototype, "sessionContext", void 0);
1031
1094
  return TestBaseClass;
1032
1095
  };
1033
- var TestBase = class extends TestBaseMixin(LitElement6) {
1096
+ var TestBase = class extends TestBaseMixin(LitElement7) {
1034
1097
  };
1035
1098
 
1036
1099
  // ../qti-test/dist/mixins/test-processing.mixin.js
@@ -1089,13 +1152,13 @@ var TestProcessingMixin = (superClass) => {
1089
1152
  };
1090
1153
 
1091
1154
  // ../qti-test/dist/components/qti-test/qti-test.js
1092
- var __decorate8 = function(decorators, target, key, desc) {
1155
+ var __decorate9 = function(decorators, target, key, desc) {
1093
1156
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
1094
1157
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
1095
1158
  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;
1096
1159
  return c > 3 && r && Object.defineProperty(target, key, r), r;
1097
1160
  };
1098
- var QtiTest = class extends TestNavigationMixin(TestViewMixin(TestProcessingMixin(TestBaseMixin(LitElement7)))) {
1161
+ var QtiTest = class extends TestNavigationMixin(TestViewMixin(TestProcessingMixin(TestBaseMixin(LitElement8)))) {
1099
1162
  constructor() {
1100
1163
  super(...arguments);
1101
1164
  this.configContext = {};
@@ -1110,16 +1173,16 @@ var QtiTest = class extends TestNavigationMixin(TestViewMixin(TestProcessingMixi
1110
1173
  this.dispatchEvent(new CustomEvent("qti-test-connected", { detail: this }));
1111
1174
  }
1112
1175
  render() {
1113
- return html6`<slot></slot>`;
1176
+ return html7`<slot></slot>`;
1114
1177
  }
1115
1178
  };
1116
- __decorate8([
1179
+ __decorate9([
1117
1180
  state(),
1118
1181
  provide2({ context: configContext })
1119
1182
  ], QtiTest.prototype, "configContext", void 0);
1120
1183
 
1121
1184
  // ../qti-test/dist/components/test-check-item/test-check-item.js
1122
- import { css as css4, html as html7, LitElement as LitElement8 } from "lit";
1185
+ import { css as css4, html as html8, LitElement as LitElement9 } from "lit";
1123
1186
 
1124
1187
  // ../qti-test/dist/components/styles.js
1125
1188
  import { css as css3 } from "lit";
@@ -1145,7 +1208,7 @@ var ind = css3`
1145
1208
  `;
1146
1209
 
1147
1210
  // ../qti-test/dist/components/test-check-item/test-check-item.js
1148
- var TestCheckItem = class extends LitElement8 {
1211
+ var TestCheckItem = class extends LitElement9 {
1149
1212
  static {
1150
1213
  this.styles = css4`
1151
1214
  :host {
@@ -1169,22 +1232,22 @@ var TestCheckItem = class extends LitElement8 {
1169
1232
  });
1170
1233
  }
1171
1234
  render() {
1172
- return html7` <slot></slot> `;
1235
+ return html8` <slot></slot> `;
1173
1236
  }
1174
1237
  };
1175
1238
 
1176
1239
  // ../qti-test/dist/components/test-container/test-container.js
1177
1240
  import { consume as consume4 } from "@lit/context";
1178
- import { LitElement as LitElement9, html as html8 } from "lit";
1179
- import { property as property7, state as state2 } from "lit/decorators.js";
1241
+ import { LitElement as LitElement10, html as html9 } from "lit";
1242
+ import { property as property8, state as state2 } from "lit/decorators.js";
1180
1243
  import { until } from "lit/directives/until.js";
1181
- var __decorate9 = function(decorators, target, key, desc) {
1244
+ var __decorate10 = function(decorators, target, key, desc) {
1182
1245
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
1183
1246
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
1184
1247
  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;
1185
1248
  return c > 3 && r && Object.defineProperty(target, key, r), r;
1186
1249
  };
1187
- var TestContainer = class extends LitElement9 {
1250
+ var TestContainer = class extends LitElement10 {
1188
1251
  constructor() {
1189
1252
  super(...arguments);
1190
1253
  this.customElementRegistry = null;
@@ -1224,17 +1287,34 @@ var TestContainer = class extends LitElement9 {
1224
1287
  api = await qtiTest.postLoadTestTransformCallback(api, testElement);
1225
1288
  }
1226
1289
  }
1227
- this.testDoc = api.htmlDoc(this.#resolvedCustomElementRegistry ?? void 0);
1290
+ this.#setTestDoc(api.htmlDoc(this.#resolvedCustomElementRegistry ?? void 0));
1228
1291
  } catch (error) {
1229
1292
  console.error("Error loading or parsing XML:", error);
1230
1293
  }
1231
1294
  }
1295
+ /**
1296
+ * Assign a new test document and announce it.
1297
+ *
1298
+ * The announcement has to happen here rather than on
1299
+ * `qti-assessment-test-connected`, because by then the new document's
1300
+ * children have already connected and registered themselves — a host that
1301
+ * resets its context on that event throws those registrations away. Lit's
1302
+ * re-render is async, so a handler running now still gets in before any child
1303
+ * of the new `qti-assessment-test` connects.
1304
+ */
1305
+ #setTestDoc(testDoc) {
1306
+ this.testDoc = testDoc;
1307
+ this.dispatchEvent(new CustomEvent("qti-testdoc-loaded", {
1308
+ bubbles: true,
1309
+ composed: true
1310
+ }));
1311
+ }
1232
1312
  handleTestXMLChange() {
1233
1313
  if (!this.testXML)
1234
1314
  return;
1235
1315
  try {
1236
1316
  const explicitSeed = this.qtiContext?.QTI_CONTEXT?.seed;
1237
- this.testDoc = qtiTransformTest().parse(this.testXML).shuffleOrdering(explicitSeed).htmlDoc(this.#resolvedCustomElementRegistry ?? void 0);
1317
+ this.#setTestDoc(qtiTransformTest().parse(this.testXML).shuffleOrdering(explicitSeed).htmlDoc(this.#resolvedCustomElementRegistry ?? void 0));
1238
1318
  } catch (error) {
1239
1319
  console.error("Error parsing XML:", error);
1240
1320
  }
@@ -1252,7 +1332,7 @@ var TestContainer = class extends LitElement9 {
1252
1332
  }
1253
1333
  #initializeTemplateContent() {
1254
1334
  const template = this.querySelector("template");
1255
- this.#templateContent = template ? template.content : html8``;
1335
+ this.#templateContent = template ? template.content : html9``;
1256
1336
  }
1257
1337
  #applyStyles() {
1258
1338
  const sheet = new CSSStyleSheet();
@@ -1260,39 +1340,52 @@ var TestContainer = class extends LitElement9 {
1260
1340
  this.shadowRoot.adoptedStyleSheets = [sheet];
1261
1341
  }
1262
1342
  render() {
1263
- return html8`
1343
+ return html9`
1264
1344
  ${this.#templateContent}
1265
1345
  <slot></slot>
1266
- ${until(this.testDoc, html8`<span>Loading...</span>`)}
1346
+ ${until(this.testDoc, html9`<span>Loading...</span>`)}
1267
1347
  `;
1268
1348
  }
1269
1349
  };
1270
- __decorate9([
1271
- property7({ attribute: false })
1350
+ __decorate10([
1351
+ property8({ attribute: false })
1272
1352
  ], TestContainer.prototype, "customElementRegistry", void 0);
1273
- __decorate9([
1274
- property7({ type: String, attribute: "test-url" })
1353
+ __decorate10([
1354
+ property8({ type: String, attribute: "test-url" })
1275
1355
  ], TestContainer.prototype, "testURL", void 0);
1276
- __decorate9([
1356
+ __decorate10([
1277
1357
  state2()
1278
1358
  ], TestContainer.prototype, "testDoc", void 0);
1279
- __decorate9([
1359
+ __decorate10([
1280
1360
  state2()
1281
1361
  ], TestContainer.prototype, "testXML", void 0);
1282
- __decorate9([
1362
+ __decorate10([
1283
1363
  state2(),
1284
1364
  consume4({ context: qtiContext, subscribe: true })
1285
1365
  ], TestContainer.prototype, "qtiContext", void 0);
1286
- __decorate9([
1366
+ __decorate10([
1287
1367
  watch("testURL", { waitUntilFirstUpdate: true })
1288
1368
  ], TestContainer.prototype, "handleTestURLChange", null);
1289
- __decorate9([
1369
+ __decorate10([
1290
1370
  watch("testXML", { waitUntilFirstUpdate: true })
1291
1371
  ], TestContainer.prototype, "handleTestXMLChange", null);
1292
1372
 
1293
1373
  // ../qti-test/dist/components/test-end-attempt/test-end-attempt.js
1294
- import { css as css5, html as html9, LitElement as LitElement10 } from "lit";
1295
- var TestEndAttempt = class extends LitElement10 {
1374
+ import { css as css5, html as html10, LitElement as LitElement11 } from "lit";
1375
+ import { property as property9 } from "lit/decorators.js";
1376
+ import { consume as consume5 } from "@lit/context";
1377
+ var __decorate11 = function(decorators, target, key, desc) {
1378
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
1379
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
1380
+ 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;
1381
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
1382
+ };
1383
+ var TestEndAttempt = class extends LitElement11 {
1384
+ _handleTestElementChange(_oldValue, newValue) {
1385
+ if (newValue) {
1386
+ this.requestUpdate();
1387
+ }
1388
+ }
1296
1389
  static {
1297
1390
  this.styles = css5`
1298
1391
  :host {
@@ -1305,23 +1398,69 @@ var TestEndAttempt = class extends LitElement10 {
1305
1398
  }
1306
1399
  constructor() {
1307
1400
  super();
1308
- this.addEventListener("click", () => this.dispatchEvent(new CustomEvent("test-end-attempt", { bubbles: true })));
1401
+ this._internalDisabled = false;
1402
+ this.addEventListener("click", (e) => {
1403
+ e.preventDefault();
1404
+ if (!this._internalDisabled) {
1405
+ this.dispatchEvent(new CustomEvent("test-end-attempt", { bubbles: true }));
1406
+ }
1407
+ });
1408
+ }
1409
+ willUpdate(_changedProperties) {
1410
+ this.checkDisabled();
1411
+ }
1412
+ checkDisabled() {
1413
+ const testPart = this.computedContext?.testParts.find((testPart2) => testPart2.active);
1414
+ if (!testPart)
1415
+ return;
1416
+ const sectionItems = testPart.sections.flatMap((section) => section.items);
1417
+ const itemIndex = sectionItems.findIndex((item) => item.active);
1418
+ const activeItem = sectionItems[itemIndex];
1419
+ if (!activeItem) {
1420
+ this._internalDisabled = false;
1421
+ return;
1422
+ }
1423
+ const maxAttempts = activeItem.maxAttempts ?? 1;
1424
+ const numAttempts = activeItem.numAttempts || 0;
1425
+ if (!activeItem.adaptive && activeItem.optimal) {
1426
+ this._internalDisabled = true;
1427
+ return;
1428
+ }
1429
+ if (!activeItem.adaptive && maxAttempts > 0 && numAttempts >= maxAttempts) {
1430
+ this._internalDisabled = true;
1431
+ return;
1432
+ }
1433
+ if (activeItem.allowSkipping === false) {
1434
+ this._internalDisabled = activeItem.valid === false || activeItem.isDefaultResponse;
1435
+ } else {
1436
+ this._internalDisabled = false;
1437
+ }
1309
1438
  }
1310
1439
  render() {
1311
- return html9` <slot></slot> `;
1440
+ return html10` <slot></slot> `;
1312
1441
  }
1313
1442
  };
1443
+ __decorate11([
1444
+ consume5({ context: computedContext, subscribe: true }),
1445
+ property9({ attribute: false })
1446
+ ], TestEndAttempt.prototype, "computedContext", void 0);
1447
+ __decorate11([
1448
+ property9({ type: Boolean, reflect: true, attribute: "disabled" })
1449
+ ], TestEndAttempt.prototype, "_internalDisabled", void 0);
1450
+ __decorate11([
1451
+ watch("computedContext")
1452
+ ], TestEndAttempt.prototype, "_handleTestElementChange", null);
1314
1453
 
1315
1454
  // ../qti-test/dist/components/test-item-link/test-item-link.js
1316
- import { css as css6, html as html10, LitElement as LitElement11 } from "lit";
1317
- import { property as property8 } from "lit/decorators.js";
1318
- var __decorate10 = function(decorators, target, key, desc) {
1455
+ import { css as css6, html as html11, LitElement as LitElement12 } from "lit";
1456
+ import { property as property10 } from "lit/decorators.js";
1457
+ var __decorate12 = function(decorators, target, key, desc) {
1319
1458
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
1320
1459
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
1321
1460
  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;
1322
1461
  return c > 3 && r && Object.defineProperty(target, key, r), r;
1323
1462
  };
1324
- var TestItemLink = class extends LitElement11 {
1463
+ var TestItemLink = class extends LitElement12 {
1325
1464
  static {
1326
1465
  this.styles = css6`
1327
1466
  :host {
@@ -1348,18 +1487,18 @@ var TestItemLink = class extends LitElement11 {
1348
1487
  }));
1349
1488
  }
1350
1489
  render() {
1351
- return html10` <slot></slot> `;
1490
+ return html11` <slot></slot> `;
1352
1491
  }
1353
1492
  };
1354
- __decorate10([
1355
- property8({ type: String, attribute: "item-id" })
1493
+ __decorate12([
1494
+ property10({ type: String, attribute: "item-id" })
1356
1495
  ], TestItemLink.prototype, "itemId", void 0);
1357
1496
 
1358
1497
  // ../qti-test/dist/components/test-item-to-speech/test-item-to-speech.js
1359
- import { html as html11, LitElement as LitElement12, css as css7 } from "lit";
1360
- import { consume as consume5, provide as provide3, createContext } from "@lit/context";
1361
- import { property as property9, state as state3 } from "lit/decorators.js";
1362
- var __decorate11 = function(decorators, target, key, desc) {
1498
+ import { html as html12, LitElement as LitElement13, css as css7 } from "lit";
1499
+ import { consume as consume6, provide as provide3, createContext } from "@lit/context";
1500
+ import { property as property11, state as state3 } from "lit/decorators.js";
1501
+ var __decorate13 = function(decorators, target, key, desc) {
1363
1502
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
1364
1503
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
1365
1504
  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;
@@ -1379,7 +1518,7 @@ function getHighlightSheet() {
1379
1518
  return highlightSheet;
1380
1519
  }
1381
1520
  var ttsContext = createContext(/* @__PURE__ */ Symbol("tts-context"));
1382
- var TtsButtonBase = class extends LitElement12 {
1521
+ var TtsButtonBase = class extends LitElement13 {
1383
1522
  static {
1384
1523
  this.styles = css7`
1385
1524
  :host {
@@ -1403,10 +1542,10 @@ var TtsButtonBase = class extends LitElement12 {
1403
1542
  }
1404
1543
  }
1405
1544
  };
1406
- __decorate11([
1407
- consume5({ context: ttsContext, subscribe: true })
1545
+ __decorate13([
1546
+ consume6({ context: ttsContext, subscribe: true })
1408
1547
  ], TtsButtonBase.prototype, "_tts", void 0);
1409
- var TestItemToSpeech = class extends LitElement12 {
1548
+ var TestItemToSpeech = class extends LitElement13 {
1410
1549
  #internals;
1411
1550
  #itemElements;
1412
1551
  #boundHandleItemConnected;
@@ -1480,7 +1619,7 @@ var TestItemToSpeech = class extends LitElement12 {
1480
1619
  this.#itemElements.clear();
1481
1620
  }
1482
1621
  render() {
1483
- return html11`<slot></slot>`;
1622
+ return html12`<slot></slot>`;
1484
1623
  }
1485
1624
  #handleItemConnected(event) {
1486
1625
  const item = event.detail;
@@ -1702,13 +1841,13 @@ var TestItemToSpeech = class extends LitElement12 {
1702
1841
  }
1703
1842
  }
1704
1843
  };
1705
- __decorate11([
1706
- property9({ type: String })
1844
+ __decorate13([
1845
+ property11({ type: String })
1707
1846
  ], TestItemToSpeech.prototype, "language", void 0);
1708
- __decorate11([
1709
- consume5({ context: sessionContext, subscribe: true })
1847
+ __decorate13([
1848
+ consume6({ context: sessionContext, subscribe: true })
1710
1849
  ], TestItemToSpeech.prototype, "_sessionContext", void 0);
1711
- __decorate11([
1850
+ __decorate13([
1712
1851
  state3(),
1713
1852
  provide3({ context: ttsContext })
1714
1853
  ], TestItemToSpeech.prototype, "_ttsContext", void 0);
@@ -1725,16 +1864,16 @@ var TestTtsPlay = class extends TtsButtonBase {
1725
1864
  }
1726
1865
  render() {
1727
1866
  const playing = this._tts?.state === "playing";
1728
- return html11`
1867
+ return html12`
1729
1868
  <button part="button" @click=${this.#toggle}>
1730
- ${playing ? html11`<slot name="pause">⏸</slot>` : html11`<slot name="play">▶</slot>`}
1869
+ ${playing ? html12`<slot name="pause">⏸</slot>` : html12`<slot name="play">▶</slot>`}
1731
1870
  </button>
1732
1871
  `;
1733
1872
  }
1734
1873
  };
1735
1874
  var TestTtsPause = class extends TtsButtonBase {
1736
1875
  render() {
1737
- return html11`
1876
+ return html12`
1738
1877
  <button part="button" ?disabled=${this._tts?.state !== "playing"} @click=${() => this._tts?.pause()}>
1739
1878
  <slot>⏸</slot>
1740
1879
  </button>
@@ -1743,7 +1882,7 @@ var TestTtsPause = class extends TtsButtonBase {
1743
1882
  };
1744
1883
  var TestTtsResume = class extends TtsButtonBase {
1745
1884
  render() {
1746
- return html11`
1885
+ return html12`
1747
1886
  <button part="button" ?disabled=${this._tts?.state !== "paused"} @click=${() => this._tts?.resume()}>
1748
1887
  <slot>▶</slot>
1749
1888
  </button>
@@ -1752,7 +1891,7 @@ var TestTtsResume = class extends TtsButtonBase {
1752
1891
  };
1753
1892
  var TestTtsStop = class extends TtsButtonBase {
1754
1893
  render() {
1755
- return html11`
1894
+ return html12`
1756
1895
  <button part="button" ?disabled=${this._tts?.state === "idle"} @click=${() => this._tts?.stop()}>
1757
1896
  <slot>■</slot>
1758
1897
  </button>
@@ -1763,7 +1902,7 @@ var TestTtsPrev = class extends TtsButtonBase {
1763
1902
  render() {
1764
1903
  const atStart = (this._tts?.currentElementIndex ?? 0) === 0;
1765
1904
  const noElements = (this._tts?.elementCount ?? 0) === 0;
1766
- return html11`
1905
+ return html12`
1767
1906
  <button part="button" ?disabled=${noElements || atStart} @click=${() => this._tts?.prevElement()}>
1768
1907
  <slot>◀◀</slot>
1769
1908
  </button>
@@ -1774,7 +1913,7 @@ var TestTtsNext = class extends TtsButtonBase {
1774
1913
  render() {
1775
1914
  const atEnd = (this._tts?.elementCount ?? 0) > 0 && (this._tts?.currentElementIndex ?? 0) >= (this._tts?.elementCount ?? 0) - 1;
1776
1915
  const noElements = (this._tts?.elementCount ?? 0) === 0;
1777
- return html11`
1916
+ return html12`
1778
1917
  <button part="button" ?disabled=${noElements || atEnd} @click=${() => this._tts?.nextElement()}>
1779
1918
  <slot>▶▶</slot>
1780
1919
  </button>
@@ -1783,17 +1922,25 @@ var TestTtsNext = class extends TtsButtonBase {
1783
1922
  };
1784
1923
 
1785
1924
  // ../qti-test/dist/components/test-navigation/test-navigation.js
1786
- import { consume as consume6, provide as provide4 } from "@lit/context";
1787
- import { html as html12, LitElement as LitElement13 } from "lit";
1788
- import { property as property10, state as state4 } from "lit/decorators.js";
1789
- var __decorate12 = function(decorators, target, key, desc) {
1925
+ import { consume as consume7, provide as provide4 } from "@lit/context";
1926
+ import { html as html13, LitElement as LitElement14 } from "lit";
1927
+ import { property as property12, state as state4 } from "lit/decorators.js";
1928
+ var __decorate14 = function(decorators, target, key, desc) {
1790
1929
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
1791
1930
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
1792
1931
  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;
1793
1932
  return c > 3 && r && Object.defineProperty(target, key, r), r;
1794
1933
  };
1795
- var TestNavigation = class extends LitElement13 {
1934
+ var TestNavigation = class extends LitElement14 {
1796
1935
  #testElement;
1936
+ /**
1937
+ * Whether each item's last *ended attempt* reached the optimal outcome, keyed
1938
+ * by item-ref id. Written from #handleItemContextUpdated when processResponse
1939
+ * ends an attempt — never on a plain selection. Mirrors how inline feedback
1940
+ * only re-evaluates when an attempt is processed, so a freshly-picked answer
1941
+ * doesn't flip `done` until the candidate ends the attempt.
1942
+ */
1943
+ #optimality;
1797
1944
  constructor() {
1798
1945
  super();
1799
1946
  this.identifier = void 0;
@@ -1807,12 +1954,52 @@ var TestNavigation = class extends LitElement13 {
1807
1954
  };
1808
1955
  this.configContext = {};
1809
1956
  this.autoScoreItems = false;
1957
+ this.#optimality = /* @__PURE__ */ new Map();
1810
1958
  this.addEventListener("qti-assessment-test-connected", this.#handleTestConnected.bind(this));
1811
1959
  this.addEventListener("qti-assessment-item-connected", this.#handleItemConnected.bind(this));
1812
1960
  this.addEventListener("qti-interaction-changed", this.#handleInteractionChanged.bind(this));
1961
+ this.addEventListener("qti-item-context-updated", this.#handleItemContextUpdated.bind(this));
1813
1962
  this.addEventListener("test-end-attempt", this.#handleTestEndAttempt.bind(this));
1814
1963
  this.addEventListener("test-update-outcome-variable", this.#handleTestUpdateOutcomeVariable.bind(this));
1815
1964
  }
1965
+ /**
1966
+ * Latch whether an item reached its optimal outcome whenever it has just ended
1967
+ * an attempt. processResponse — fired by test-end-attempt, autoscore, or an
1968
+ * in-item end-attempt interaction — flags its context update with
1969
+ * `responseProcessed`; a plain selection updates the context without it, so
1970
+ * `done` can't flip until the candidate actually ends the attempt.
1971
+ */
1972
+ #handleItemContextUpdated(event) {
1973
+ if (!event.detail?.responseProcessed)
1974
+ return;
1975
+ const itemContext = event.detail.itemContext;
1976
+ if (!itemContext?.identifier)
1977
+ return;
1978
+ const optimality = this.#assessOptimality(itemContext);
1979
+ this.#optimality.set(itemContext.identifier, optimality);
1980
+ const computedItem = this.computedItemFor(itemContext.identifier);
1981
+ const numAttempts = Number(itemContext.variables?.find((v) => v.identifier === "numAttempts")?.value) || 0;
1982
+ this.afterAttemptEnded(event.composedPath()[0]?.closest("qti-assessment-item"), computedItem, this.#isItemDone(numAttempts, optimality, computedItem?.maxAttempts));
1983
+ }
1984
+ /**
1985
+ * Extension point for presentation packages reacting to an ended attempt.
1986
+ * `done` is settled here — from the freshly latched optimality and the
1987
+ * session-control cascade — because the computed context only catches up on
1988
+ * the next update, after this event has finished bubbling.
1989
+ */
1990
+ afterAttemptEnded(_assessmentItem, _computedItem, _done) {
1991
+ }
1992
+ /** The computed-context entry for an item, from the session-control cascade. */
1993
+ computedItemFor(identifier) {
1994
+ return this.computedContext?.testParts?.flatMap((part) => part.sections).flatMap((section) => section.items).find((i) => i.identifier === identifier);
1995
+ }
1996
+ /** The assessment item for an item-ref id, if it has been rendered. */
1997
+ #assessmentItemFor(identifier) {
1998
+ if (!identifier)
1999
+ return void 0;
2000
+ const itemRef = this.#testElement?.querySelector(`qti-assessment-item-ref[identifier="${identifier}"]`);
2001
+ return itemRef?.assessmentItem ?? void 0;
2002
+ }
1816
2003
  /** The currently active assessment item, exposed for optional presentation extensions. */
1817
2004
  get activeAssessmentItem() {
1818
2005
  if (!this.#testElement || !this._sessionContext?.navItemRefId)
@@ -1826,19 +2013,23 @@ var TestNavigation = class extends LitElement13 {
1826
2013
  * @param {CustomEvent} event - The custom event object.
1827
2014
  */
1828
2015
  #handleTestEndAttempt(_event) {
1829
- const qtiItemEl = this.#testElement.querySelector(`qti-assessment-item-ref[identifier="${this._sessionContext.navItemRefId}"]`);
1830
- const qtiAssessmentItemEl = qtiItemEl.assessmentItem;
2016
+ const qtiAssessmentItemEl = this.activeAssessmentItem;
2017
+ if (!qtiAssessmentItemEl)
2018
+ return;
1831
2019
  const reportValidityAfterScoring = this.configContext?.reportValidityAfterScoring === true ? true : false;
1832
2020
  qtiAssessmentItemEl.processResponse(true, reportValidityAfterScoring);
1833
2021
  }
1834
2022
  #handleTestUpdateOutcomeVariable(event) {
1835
- const qtiItemEl = this.#testElement.querySelector(`qti-assessment-item-ref[identifier="${event.detail.assessmentItemRefId}"]`);
1836
- const qtiAssessmentItemEl = qtiItemEl.assessmentItem;
2023
+ const qtiAssessmentItemEl = this.#assessmentItemFor(event.detail?.assessmentItemRefId);
2024
+ if (!qtiAssessmentItemEl)
2025
+ return;
1837
2026
  qtiAssessmentItemEl.setOutcomeVariable(event.detail.outcomeVariableId, event.detail.value);
1838
2027
  }
1839
2028
  #handleInteractionChanged(_event) {
1840
2029
  if (this.autoScoreItems) {
1841
2030
  const assessmentItem = _event.composedPath()[0].closest("qti-assessment-item");
2031
+ if (!assessmentItem)
2032
+ return;
1842
2033
  const scoreOutcomeIdentifier = assessmentItem.variables.find((v) => v.identifier === "SCORE");
1843
2034
  if (scoreOutcomeIdentifier && scoreOutcomeIdentifier.externalScored === null && assessmentItem.adaptive === "false") {
1844
2035
  const reportValidityAfterScoring = this.configContext?.reportValidityAfterScoring === true ? true : false;
@@ -1847,11 +2038,12 @@ var TestNavigation = class extends LitElement13 {
1847
2038
  }
1848
2039
  }
1849
2040
  render() {
1850
- return html12`<slot></slot>`;
2041
+ return html13`<slot></slot>`;
1851
2042
  }
1852
2043
  /* PK: on test connected we can build the computed context */
1853
2044
  #handleTestConnected(event) {
1854
2045
  this.#testElement = event.detail;
2046
+ this.#optimality.clear();
1855
2047
  if (!this.qtiContext.QTI_CONTEXT?.testIdentifier) {
1856
2048
  const currentContext = this.qtiContext.QTI_CONTEXT || {
1857
2049
  testIdentifier: "",
@@ -1887,27 +2079,50 @@ var TestNavigation = class extends LitElement13 {
1887
2079
  view: this._sessionContext?.view,
1888
2080
  testParts: testPartElements.map((testPart) => {
1889
2081
  const sectionElements = [...testPart.querySelectorAll(`qti-assessment-section`)];
2082
+ const testPartSessionControl = testPart.querySelector(":scope > qti-item-session-control");
2083
+ const partAllowSkipping = testPartSessionControl ? testPartSessionControl.allowSkipping : true;
2084
+ const partMaxAttempts = testPartSessionControl ? testPartSessionControl.maxAttempts : 1;
2085
+ const partShowFeedback = testPartSessionControl ? testPartSessionControl.showFeedback : false;
2086
+ const partShowSolution = testPartSessionControl ? testPartSessionControl.showSolution : false;
1890
2087
  return {
1891
2088
  active: false,
1892
2089
  identifier: testPart.identifier,
1893
2090
  navigationMode: testPart.navigationMode,
1894
2091
  submissionMode: testPart.submissionMode,
2092
+ allowSkipping: partAllowSkipping,
1895
2093
  sections: sectionElements.map((section) => {
1896
2094
  const itemElements = [...section.querySelectorAll(`qti-assessment-item-ref`)];
2095
+ const sectionSessionControl = section.querySelector(":scope > qti-item-session-control");
2096
+ const sectionAllowSkipping = sectionSessionControl ? sectionSessionControl.allowSkipping : partAllowSkipping;
2097
+ const sectionMaxAttempts = sectionSessionControl ? sectionSessionControl.maxAttempts : partMaxAttempts;
2098
+ const sectionShowFeedback = sectionSessionControl ? sectionSessionControl.showFeedback : partShowFeedback;
2099
+ const sectionShowSolution = sectionSessionControl ? sectionSessionControl.showSolution : partShowSolution;
1897
2100
  return {
1898
2101
  active: false,
1899
2102
  identifier: section.identifier,
1900
2103
  title: section.title,
1901
2104
  navigationMode: section.navigationMode,
1902
2105
  submissionMode: section.submissionMode,
1903
- items: itemElements.map((item) => ({
1904
- ...this.initContext?.find((i) => i.identifier === item.identifier),
1905
- active: false,
1906
- identifier: item.identifier,
1907
- categories: item.category ? item.category?.split(" ") : [],
1908
- href: item.href,
1909
- variables: []
1910
- }))
2106
+ allowSkipping: sectionAllowSkipping,
2107
+ items: itemElements.map((item) => {
2108
+ const itemSessionControl = item.querySelector(":scope > qti-item-session-control");
2109
+ const itemAllowSkipping = itemSessionControl ? itemSessionControl.allowSkipping : sectionAllowSkipping;
2110
+ const itemMaxAttempts = itemSessionControl ? itemSessionControl.maxAttempts : sectionMaxAttempts;
2111
+ const itemShowFeedback = itemSessionControl ? itemSessionControl.showFeedback : sectionShowFeedback;
2112
+ const itemShowSolution = itemSessionControl ? itemSessionControl.showSolution : sectionShowSolution;
2113
+ return {
2114
+ ...this.initContext?.find((i) => i.identifier === item.identifier),
2115
+ active: false,
2116
+ identifier: item.identifier,
2117
+ categories: item.category ? item.category?.split(" ") : [],
2118
+ href: item.href,
2119
+ variables: [],
2120
+ allowSkipping: itemAllowSkipping,
2121
+ maxAttempts: itemMaxAttempts,
2122
+ showFeedback: itemShowFeedback,
2123
+ showSolution: itemShowSolution
2124
+ };
2125
+ })
1911
2126
  };
1912
2127
  })
1913
2128
  };
@@ -2024,11 +2239,50 @@ var TestNavigation = class extends LitElement13 {
2024
2239
  const score = rawscore === void 0 || rawscore === null ? null : parseFloat(rawscore?.toString());
2025
2240
  const completionStatus = computedItem.variables?.find((v) => v.identifier === "completionStatus")?.value;
2026
2241
  const response = computedItem.variables?.find((v) => v.identifier === "RESPONSE")?.value || "";
2027
- const numAttempts = computedItem.variables?.find((v) => v.identifier === "numAttempts")?.value || 0;
2242
+ const numAttempts = Number(computedItem.variables?.find((v) => v.identifier === "numAttempts")?.value) || 0;
2028
2243
  const active = this._sessionContext?.navItemRefId === computedItem.identifier || false;
2244
+ const valid = this.#assessmentItemFor(computedItem.identifier)?.validate(false) ?? true;
2245
+ const responseVars = itemContext?.variables?.filter((v) => v.type === "response") || [];
2246
+ const isDefaultResponse = responseVars.every((v) => {
2247
+ if (v.value === void 0 || v.value === null) {
2248
+ return true;
2249
+ }
2250
+ let fallbackValue;
2251
+ switch (v.baseType) {
2252
+ case "integer":
2253
+ case "float":
2254
+ case "duration":
2255
+ fallbackValue = "0";
2256
+ break;
2257
+ case "boolean":
2258
+ fallbackValue = "false";
2259
+ break;
2260
+ case "string":
2261
+ case "directedPair":
2262
+ case "identifier":
2263
+ case "pair":
2264
+ case "record":
2265
+ default:
2266
+ fallbackValue = "";
2267
+ break;
2268
+ }
2269
+ const defaultValue = v.defaultValue ?? fallbackValue;
2270
+ if (Array.isArray(v.value)) {
2271
+ const dv = Array.isArray(defaultValue) ? defaultValue : [defaultValue];
2272
+ return v.value.length === dv.length && v.value.every((val, i) => val === dv[i]);
2273
+ }
2274
+ return v.value === defaultValue;
2275
+ });
2029
2276
  const index = item.categories.includes(this.configContext?.infoItemCategory) ? null : itemIndex++;
2030
2277
  const rawMaxScore = item.variables?.find((vr) => vr.identifier == "MAXSCORE")?.value;
2031
2278
  const maxScore = rawMaxScore === void 0 || rawMaxScore === null ? null : parseFloat(rawMaxScore?.toString());
2279
+ let optimality = this.#optimality.get(computedItem.identifier);
2280
+ if (optimality === void 0) {
2281
+ optimality = itemContext ? this.#assessOptimality(itemContext) : "unscored";
2282
+ if (numAttempts > 0)
2283
+ this.#optimality.set(computedItem.identifier, optimality);
2284
+ }
2285
+ const done = this.#isItemDone(numAttempts, optimality, computedItem.maxAttempts);
2032
2286
  return {
2033
2287
  ...computedItem,
2034
2288
  completionStatus,
@@ -2037,7 +2291,16 @@ var TestNavigation = class extends LitElement13 {
2037
2291
  response,
2038
2292
  index,
2039
2293
  active,
2040
- maxScore
2294
+ valid,
2295
+ isDefaultResponse,
2296
+ maxScore,
2297
+ done,
2298
+ // Reflects the last *ended* attempt only. Read the latch directly
2299
+ // (not the `optimality` local) — the latch is written solely on
2300
+ // responseProcessed / restore-seed (line above, guarded by
2301
+ // numAttempts > 0), so a freshly-picked mid-attempt selection
2302
+ // computed live is never stored and never counts as optimal.
2303
+ optimal: this.#optimality.get(computedItem.identifier) === "optimal"
2041
2304
  // type,
2042
2305
  // correct,
2043
2306
  // incorrect,
@@ -2054,48 +2317,123 @@ var TestNavigation = class extends LitElement13 {
2054
2317
  bubbles: true
2055
2318
  }));
2056
2319
  }
2320
+ /**
2321
+ * Decide whether an item should be treated as "the candidate is done with it"
2322
+ * for the purpose of gating forward navigation and further attempts.
2323
+ *
2324
+ * - The candidate must have actually ended an attempt (numAttempts > 0).
2325
+ * - Once attempted, the item is done if they reached the optimal outcome
2326
+ * ('optimal'), or there's nothing to improve on ('unscored'). It is only *not*
2327
+ * done while a better attempt is still possible ('suboptimal') and attempts
2328
+ * remain — see #assessOptimality for how "optimal" is determined.
2329
+ *
2330
+ * `optimality` reflects the last *ended attempt* (see #optimality), not the
2331
+ * live selection — so a freshly-picked optimal answer doesn't count as done
2332
+ * until test-end-attempt evaluates it.
2333
+ */
2334
+ #isItemDone(numAttempts, optimality, maxAttempts) {
2335
+ if (numAttempts === 0)
2336
+ return false;
2337
+ if (optimality !== "suboptimal")
2338
+ return true;
2339
+ const max = maxAttempts ?? 1;
2340
+ return max > 0 && numAttempts >= max;
2341
+ }
2342
+ /**
2343
+ * Decide whether an item's submission is as good as it can get — i.e. the
2344
+ * candidate reached the *optimal* outcome, so there's no reason to make them
2345
+ * try again. 'optimal' means best achievable, 'suboptimal' means a better
2346
+ * attempt is still possible, 'unscored' means there's nothing to judge against.
2347
+ * ("optimal" is the spec's own word — a qti-correct-response is defined as
2348
+ * "the (or an) optimal value".)
2349
+ *
2350
+ * Two signals, in order of authority:
2351
+ * 1. The scored outcome: optimal ⟺ SCORE has reached its maximum (MAXSCORE).
2352
+ * This correctly handles partial-credit / qti-mapping items, where an exact
2353
+ * response match would under- or over-judge.
2354
+ * 2. The declared qti-correct-response, for items that aren't scored (no
2355
+ * SCORE/MAXSCORE) — an exact match is the best available proxy. Bookkeeping
2356
+ * variables like numAttempts can be typed 'response' but never declare a
2357
+ * correctResponse, so we filter on a declared correctResponse.
2358
+ *
2359
+ * Items with neither a comparable score nor a correctResponse (essays, info
2360
+ * items, etc.) are 'unscored' — there's no optimal value to require, so one
2361
+ * attempt is enough.
2362
+ */
2363
+ #assessOptimality(item) {
2364
+ const variables = item.variables ?? [];
2365
+ const score = this.#numericVariable(variables, "SCORE");
2366
+ const maxScore = this.#numericVariable(variables, "MAXSCORE");
2367
+ if (score !== null && maxScore !== null) {
2368
+ return score >= maxScore ? "optimal" : "suboptimal";
2369
+ }
2370
+ const responseVars = variables.filter((v) => v.type === "response" && v.correctResponse !== void 0 && v.correctResponse !== null);
2371
+ if (responseVars.length === 0)
2372
+ return "unscored";
2373
+ const allMatch = responseVars.every((v) => {
2374
+ const expected = v.correctResponse;
2375
+ const actual = v.value;
2376
+ if (actual === void 0 || actual === null)
2377
+ return false;
2378
+ if (Array.isArray(expected) && Array.isArray(actual)) {
2379
+ return expected.length === actual.length && expected.every((e) => actual.includes(e));
2380
+ }
2381
+ if (Array.isArray(expected) || Array.isArray(actual))
2382
+ return false;
2383
+ return expected === actual;
2384
+ });
2385
+ return allMatch ? "optimal" : "suboptimal";
2386
+ }
2387
+ /** Read a single numeric outcome value, or null when absent / non-numeric. */
2388
+ #numericVariable(variables, identifier) {
2389
+ const raw = variables?.find((v) => v.identifier === identifier)?.value;
2390
+ if (raw === void 0 || raw === null || Array.isArray(raw))
2391
+ return null;
2392
+ const parsed = parseFloat(raw.toString());
2393
+ return Number.isNaN(parsed) ? null : parsed;
2394
+ }
2057
2395
  };
2058
- __decorate12([
2059
- property10({ type: String })
2396
+ __decorate14([
2397
+ property12({ type: String })
2060
2398
  ], TestNavigation.prototype, "identifier", void 0);
2061
- __decorate12([
2399
+ __decorate14([
2062
2400
  state4()
2063
2401
  ], TestNavigation.prototype, "initContext", void 0);
2064
- __decorate12([
2402
+ __decorate14([
2065
2403
  state4(),
2066
2404
  provide4({ context: qtiContext })
2067
2405
  ], TestNavigation.prototype, "qtiContext", void 0);
2068
- __decorate12([
2406
+ __decorate14([
2069
2407
  state4(),
2070
- consume6({ context: configContext, subscribe: true })
2408
+ consume7({ context: configContext, subscribe: true })
2071
2409
  ], TestNavigation.prototype, "configContext", void 0);
2072
- __decorate12([
2410
+ __decorate14([
2073
2411
  state4(),
2074
- consume6({ context: testContext, subscribe: true })
2412
+ consume7({ context: testContext, subscribe: true })
2075
2413
  ], TestNavigation.prototype, "_testContext", void 0);
2076
- __decorate12([
2414
+ __decorate14([
2077
2415
  state4(),
2078
- consume6({ context: sessionContext, subscribe: true })
2416
+ consume7({ context: sessionContext, subscribe: true })
2079
2417
  ], TestNavigation.prototype, "_sessionContext", void 0);
2080
- __decorate12([
2418
+ __decorate14([
2081
2419
  state4(),
2082
2420
  provide4({ context: computedContext })
2083
2421
  ], TestNavigation.prototype, "computedContext", void 0);
2084
- __decorate12([
2085
- property10({ type: Boolean, attribute: "auto-score-items" })
2422
+ __decorate14([
2423
+ property12({ type: Boolean, attribute: "auto-score-items" })
2086
2424
  ], TestNavigation.prototype, "autoScoreItems", void 0);
2087
2425
 
2088
2426
  // ../qti-test/dist/components/test-next/test-next.js
2089
- import { css as css8, html as html13, LitElement as LitElement14 } from "lit";
2090
- import { property as property11 } from "lit/decorators.js";
2091
- import { consume as consume7 } from "@lit/context";
2092
- var __decorate13 = function(decorators, target, key, desc) {
2427
+ import { css as css8, html as html14, LitElement as LitElement15 } from "lit";
2428
+ import { property as property13 } from "lit/decorators.js";
2429
+ import { consume as consume8 } from "@lit/context";
2430
+ var __decorate15 = function(decorators, target, key, desc) {
2093
2431
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
2094
2432
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
2095
2433
  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;
2096
2434
  return c > 3 && r && Object.defineProperty(target, key, r), r;
2097
2435
  };
2098
- var TestNext = class extends LitElement14 {
2436
+ var TestNext = class extends LitElement15 {
2099
2437
  _handleTestElementChange(_oldValue, newValue) {
2100
2438
  if (newValue) {
2101
2439
  this.requestUpdate();
@@ -2147,8 +2485,7 @@ var TestNext = class extends LitElement14 {
2147
2485
  const submissionMode = activeSection?.submissionMode || testPart.submissionMode;
2148
2486
  const activeItem = this.sectionItems[this.itemIndex];
2149
2487
  const isLinearIndividual = navigationMode === "linear" && submissionMode === "individual";
2150
- const numAttempts = Number(activeItem?.variables.find((v) => v.identifier === "numAttempts")?.value) || 0;
2151
- this._internalDisabled = !this.computedContext || this.itemIndex < 0 || this.itemIndex >= (this.sectionItems?.length ?? 0) - 1 || isLinearIndividual && numAttempts === 0;
2488
+ this._internalDisabled = !this.computedContext || this.itemIndex < 0 || this.itemIndex >= (this.sectionItems?.length ?? 0) - 1 || isLinearIndividual && !activeItem?.done;
2152
2489
  }
2153
2490
  _requestItem(identifier) {
2154
2491
  this.dispatchEvent(new CustomEvent("qti-request-navigation", {
@@ -2161,21 +2498,21 @@ var TestNext = class extends LitElement14 {
2161
2498
  }));
2162
2499
  }
2163
2500
  render() {
2164
- return html13`<slot></slot>`;
2501
+ return html14`<slot></slot>`;
2165
2502
  }
2166
2503
  };
2167
- __decorate13([
2168
- property11({ type: Boolean, reflect: true, attribute: "disabled" })
2504
+ __decorate15([
2505
+ property13({ type: Boolean, reflect: true, attribute: "disabled" })
2169
2506
  ], TestNext.prototype, "_internalDisabled", void 0);
2170
- __decorate13([
2171
- consume7({ context: computedContext, subscribe: true })
2507
+ __decorate15([
2508
+ consume8({ context: computedContext, subscribe: true })
2172
2509
  ], TestNext.prototype, "computedContext", void 0);
2173
- __decorate13([
2510
+ __decorate15([
2174
2511
  watch("computedContext")
2175
2512
  ], TestNext.prototype, "_handleTestElementChange", null);
2176
2513
 
2177
2514
  // ../qti-test/dist/components/test-paging-buttons-stamp/test-paging-buttons-stamp.js
2178
- import { html as html14, LitElement as LitElement15 } from "lit";
2515
+ import { html as html15, LitElement as LitElement16 } from "lit";
2179
2516
 
2180
2517
  // ../../node_modules/.pnpm/@heximal+templates@0.1.5/node_modules/@heximal/templates/index.js
2181
2518
  import { render as renderLit, nothing } from "lit-html";
@@ -2782,18 +3119,18 @@ var EvalAstFactory = class {
2782
3119
  }
2783
3120
  const value = this.right.evaluate(scope);
2784
3121
  let receiver = void 0;
2785
- let property18;
3122
+ let property20;
2786
3123
  if (this.left.type === "Getter") {
2787
3124
  receiver = this.left.receiver.evaluate(scope);
2788
- property18 = this.left.name;
3125
+ property20 = this.left.name;
2789
3126
  } else if (this.left.type === "Index") {
2790
3127
  receiver = this.left.receiver.evaluate(scope);
2791
- property18 = this.left.argument.evaluate(scope);
3128
+ property20 = this.left.argument.evaluate(scope);
2792
3129
  } else if (this.left.type === "ID") {
2793
3130
  receiver = scope;
2794
- property18 = this.left.value;
3131
+ property20 = this.left.value;
2795
3132
  }
2796
- return receiver === void 0 ? void 0 : receiver[property18] = value;
3133
+ return receiver === void 0 ? void 0 : receiver[property20] = value;
2797
3134
  }
2798
3135
  return f(this.left.evaluate(scope), this.right.evaluate(scope));
2799
3136
  },
@@ -3246,14 +3583,14 @@ var makeLitTemplate = (template) => {
3246
3583
  };
3247
3584
 
3248
3585
  // ../qti-test/dist/components/test-paging-buttons-stamp/test-paging-buttons-stamp.js
3249
- import { consume as consume8 } from "@lit/context";
3250
- var __decorate14 = function(decorators, target, key, desc) {
3586
+ import { consume as consume9 } from "@lit/context";
3587
+ var __decorate16 = function(decorators, target, key, desc) {
3251
3588
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3252
3589
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
3253
3590
  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;
3254
3591
  return c > 3 && r && Object.defineProperty(target, key, r), r;
3255
3592
  };
3256
- var TestPagingButtonsStamp = class extends LitElement15 {
3593
+ var TestPagingButtonsStamp = class extends LitElement16 {
3257
3594
  #internals;
3258
3595
  createRenderRoot() {
3259
3596
  return this;
@@ -3270,26 +3607,26 @@ var TestPagingButtonsStamp = class extends LitElement15 {
3270
3607
  }
3271
3608
  render() {
3272
3609
  if (!this.computedContext)
3273
- return html14``;
3610
+ return html15``;
3274
3611
  const items = this.computedContext.testParts.flatMap((testPart) => testPart.sections.flatMap((section) => section.items));
3275
- return html14` ${items.map((item) => this.myTemplate({ item, view: this.computedContext.view }))} `;
3612
+ return html15` ${items.map((item) => this.myTemplate({ item, view: this.computedContext.view }))} `;
3276
3613
  }
3277
3614
  };
3278
- __decorate14([
3279
- consume8({ context: computedContext, subscribe: true })
3615
+ __decorate16([
3616
+ consume9({ context: computedContext, subscribe: true })
3280
3617
  ], TestPagingButtonsStamp.prototype, "computedContext", void 0);
3281
3618
 
3282
3619
  // ../qti-test/dist/components/test-prev/test-prev.js
3283
- import { css as css9, html as html15, LitElement as LitElement16 } from "lit";
3284
- import { property as property12 } from "lit/decorators.js";
3285
- import { consume as consume9 } from "@lit/context";
3286
- var __decorate15 = function(decorators, target, key, desc) {
3620
+ import { css as css9, html as html16, LitElement as LitElement17 } from "lit";
3621
+ import { property as property14 } from "lit/decorators.js";
3622
+ import { consume as consume10 } from "@lit/context";
3623
+ var __decorate17 = function(decorators, target, key, desc) {
3287
3624
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3288
3625
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
3289
3626
  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;
3290
3627
  return c > 3 && r && Object.defineProperty(target, key, r), r;
3291
3628
  };
3292
- var TestPrev = class extends LitElement16 {
3629
+ var TestPrev = class extends LitElement17 {
3293
3630
  _handleTestElementChange(_oldValue, newValue) {
3294
3631
  if (newValue) {
3295
3632
  this.requestUpdate();
@@ -3341,49 +3678,49 @@ var TestPrev = class extends LitElement16 {
3341
3678
  }));
3342
3679
  }
3343
3680
  render() {
3344
- return html15`<slot></slot>`;
3681
+ return html16`<slot></slot>`;
3345
3682
  }
3346
3683
  };
3347
- __decorate15([
3348
- property12({ type: Boolean, reflect: true, attribute: "disabled" })
3684
+ __decorate17([
3685
+ property14({ type: Boolean, reflect: true, attribute: "disabled" })
3349
3686
  ], TestPrev.prototype, "_internalDisabled", void 0);
3350
- __decorate15([
3351
- consume9({ context: computedContext, subscribe: true })
3687
+ __decorate17([
3688
+ consume10({ context: computedContext, subscribe: true })
3352
3689
  ], TestPrev.prototype, "computedContext", void 0);
3353
- __decorate15([
3690
+ __decorate17([
3354
3691
  watch("computedContext")
3355
3692
  ], TestPrev.prototype, "_handleTestElementChange", null);
3356
3693
 
3357
3694
  // ../qti-test/dist/components/test-print-context/test-print-context.js
3358
- import { html as html16, LitElement as LitElement17 } from "lit";
3359
- import { consume as consume10 } from "@lit/context";
3695
+ import { html as html17, LitElement as LitElement18 } from "lit";
3696
+ import { consume as consume11 } from "@lit/context";
3360
3697
  import { state as state5 } from "lit/decorators.js";
3361
- var __decorate16 = function(decorators, target, key, desc) {
3698
+ var __decorate18 = function(decorators, target, key, desc) {
3362
3699
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3363
3700
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
3364
3701
  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;
3365
3702
  return c > 3 && r && Object.defineProperty(target, key, r), r;
3366
3703
  };
3367
- var TestPrintContext = class extends LitElement17 {
3704
+ var TestPrintContext = class extends LitElement18 {
3368
3705
  render() {
3369
- return html16` <small><pre>${JSON.stringify(this.computedContext, null, 2)}</pre></small> `;
3706
+ return html17` <small><pre>${JSON.stringify(this.computedContext, null, 2)}</pre></small> `;
3370
3707
  }
3371
3708
  };
3372
- __decorate16([
3709
+ __decorate18([
3373
3710
  state5(),
3374
- consume10({ context: computedContext, subscribe: true })
3711
+ consume11({ context: computedContext, subscribe: true })
3375
3712
  ], TestPrintContext.prototype, "computedContext", void 0);
3376
3713
 
3377
3714
  // ../qti-test/dist/components/test-print-item-variables/test-print-item-variables.js
3378
- import { html as html17, css as css10, LitElement as LitElement18 } from "lit";
3379
- import { consume as consume11 } from "@lit/context";
3380
- var __decorate17 = function(decorators, target, key, desc) {
3715
+ import { html as html18, css as css10, LitElement as LitElement19 } from "lit";
3716
+ import { consume as consume12 } from "@lit/context";
3717
+ var __decorate19 = function(decorators, target, key, desc) {
3381
3718
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3382
3719
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
3383
3720
  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;
3384
3721
  return c > 3 && r && Object.defineProperty(target, key, r), r;
3385
3722
  };
3386
- var TestPrintVariables = class extends LitElement18 {
3723
+ var TestPrintVariables = class extends LitElement19 {
3387
3724
  static {
3388
3725
  this.styles = css10`
3389
3726
  table {
@@ -3411,10 +3748,10 @@ var TestPrintVariables = class extends LitElement18 {
3411
3748
  render() {
3412
3749
  const activeItem = this.computedContext?.testParts.flatMap((testPart) => testPart.sections.flatMap((section) => section.items)).find((item) => item.active);
3413
3750
  if (!activeItem || !activeItem.variables)
3414
- return html17``;
3751
+ return html18``;
3415
3752
  const responseVariables = activeItem.variables.filter((v) => v.type === "response");
3416
3753
  const outcomeVariables = activeItem.variables.filter((v) => v.type === "outcome");
3417
- const renderTable = (variables, title) => html17`
3754
+ const renderTable = (variables, title) => html18`
3418
3755
  <h3>${title}</h3>
3419
3756
  <table>
3420
3757
  <thead>
@@ -3431,7 +3768,7 @@ var TestPrintVariables = class extends LitElement18 {
3431
3768
  const correctResponse = v.correctResponse ? Array.isArray(v.correctResponse) ? v.correctResponse.join(", ") : v.correctResponse : "";
3432
3769
  const mapEntries = v.mapping?.mapEntries?.map((m) => `${m.mapKey}=${m.mappedValue}pt`).join(", ") || "";
3433
3770
  const areaMapEntries = v.areaMapping?.areaMapEntries?.map((m) => `${m.shape}(${m.coords})=${m.mappedValue}pt`).join(", ") || "";
3434
- return html17`
3771
+ return html18`
3435
3772
  <tr>
3436
3773
  <td>${v.identifier}</td>
3437
3774
  <td>${Array.isArray(v.value) ? v.value.join(", ") : v.value}</td>
@@ -3444,26 +3781,26 @@ var TestPrintVariables = class extends LitElement18 {
3444
3781
  </tbody>
3445
3782
  </table>
3446
3783
  `;
3447
- return html17`
3784
+ return html18`
3448
3785
  ${renderTable(responseVariables, "Response Variables")} ${renderTable(outcomeVariables, "Outcome Variables")}
3449
3786
  `;
3450
3787
  }
3451
3788
  };
3452
- __decorate17([
3453
- consume11({ context: computedContext, subscribe: true })
3789
+ __decorate19([
3790
+ consume12({ context: computedContext, subscribe: true })
3454
3791
  ], TestPrintVariables.prototype, "computedContext", void 0);
3455
3792
 
3456
3793
  // ../qti-test/dist/components/test-scoring-buttons/test-scoring-buttons.js
3457
- import { html as html18, LitElement as LitElement19, nothing as nothing2 } from "lit";
3458
- import { consume as consume12 } from "@lit/context";
3459
- import { property as property13 } from "lit/decorators.js";
3460
- var __decorate18 = function(decorators, target, key, desc) {
3794
+ import { html as html19, LitElement as LitElement20, nothing as nothing2 } from "lit";
3795
+ import { consume as consume13 } from "@lit/context";
3796
+ import { property as property15 } from "lit/decorators.js";
3797
+ var __decorate20 = function(decorators, target, key, desc) {
3461
3798
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3462
3799
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
3463
3800
  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;
3464
3801
  return c > 3 && r && Object.defineProperty(target, key, r), r;
3465
3802
  };
3466
- var TestScoringButtons = class extends LitElement19 {
3803
+ var TestScoringButtons = class extends LitElement20 {
3467
3804
  createRenderRoot() {
3468
3805
  return this;
3469
3806
  }
@@ -3492,7 +3829,7 @@ var TestScoringButtons = class extends LitElement19 {
3492
3829
  render() {
3493
3830
  const activeItem = this.computedContext?.testParts.flatMap((testPart) => testPart.sections.flatMap((section) => section.items)).find((item) => item.active);
3494
3831
  if (!activeItem || !activeItem.variables)
3495
- return html18``;
3832
+ return html19``;
3496
3833
  const maxScore = activeItem.variables.find((vr) => vr.identifier == "MAXSCORE")?.value;
3497
3834
  const scoreOutcome = activeItem.variables.find((vr) => vr.identifier == "SCORE");
3498
3835
  const score = scoreOutcome?.value;
@@ -3500,7 +3837,7 @@ var TestScoringButtons = class extends LitElement19 {
3500
3837
  if (!maxScore || !scoreOutcome)
3501
3838
  return nothing2;
3502
3839
  const scores = [...Array(Number(maxScore) + 1).keys()];
3503
- return html18`${this.myTemplate ? this.myTemplate({ scores, score, disabled }) : nothing2}`;
3840
+ return html19`${this.myTemplate ? this.myTemplate({ scores, score, disabled }) : nothing2}`;
3504
3841
  }
3505
3842
  constructor() {
3506
3843
  super();
@@ -3516,27 +3853,27 @@ var TestScoringButtons = class extends LitElement19 {
3516
3853
  });
3517
3854
  }
3518
3855
  };
3519
- __decorate18([
3520
- property13({ type: String, attribute: "view" })
3856
+ __decorate20([
3857
+ property15({ type: String, attribute: "view" })
3521
3858
  ], TestScoringButtons.prototype, "view", void 0);
3522
- __decorate18([
3523
- property13({ type: Boolean })
3859
+ __decorate20([
3860
+ property15({ type: Boolean })
3524
3861
  ], TestScoringButtons.prototype, "disabled", void 0);
3525
- __decorate18([
3526
- consume12({ context: computedContext, subscribe: true })
3862
+ __decorate20([
3863
+ consume13({ context: computedContext, subscribe: true })
3527
3864
  ], TestScoringButtons.prototype, "computedContext", void 0);
3528
3865
 
3529
3866
  // ../qti-test/dist/components/test-scoring-feedback/test-scoring-feedback.js
3530
- import { consume as consume13 } from "@lit/context";
3531
- import { html as html19, LitElement as LitElement20 } from "lit";
3532
- import { property as property14 } from "lit/decorators.js";
3533
- var __decorate19 = function(decorators, target, key, desc) {
3867
+ import { consume as consume14 } from "@lit/context";
3868
+ import { html as html20, LitElement as LitElement21 } from "lit";
3869
+ import { property as property16 } from "lit/decorators.js";
3870
+ var __decorate21 = function(decorators, target, key, desc) {
3534
3871
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3535
3872
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
3536
3873
  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;
3537
3874
  return c > 3 && r && Object.defineProperty(target, key, r), r;
3538
3875
  };
3539
- var TestScoringFeedback = class extends LitElement20 {
3876
+ var TestScoringFeedback = class extends LitElement21 {
3540
3877
  constructor() {
3541
3878
  super(...arguments);
3542
3879
  this.view = null;
@@ -3544,9 +3881,9 @@ var TestScoringFeedback = class extends LitElement20 {
3544
3881
  render() {
3545
3882
  const activeItem = this.computedContext?.testParts.flatMap((testPart) => testPart.sections.flatMap((section) => section.items)).find((item) => item.active);
3546
3883
  if (!activeItem || !activeItem.variables)
3547
- return html19``;
3884
+ return html20``;
3548
3885
  if (activeItem["category"] === "dep-informational")
3549
- return html19`<div>${this.dataset.informational}</div>`;
3886
+ return html20`<div>${this.dataset.informational}</div>`;
3550
3887
  const completionStatus = activeItem?.variables.find((v) => v.identifier === "completionStatus")?.value;
3551
3888
  const scoreOutcome = activeItem?.variables.find((vr) => vr.identifier == "SCORE");
3552
3889
  const score = parseFloat(scoreOutcome?.value);
@@ -3566,26 +3903,26 @@ var TestScoringFeedback = class extends LitElement20 {
3566
3903
  }
3567
3904
  return this.dataset.inProgress;
3568
3905
  };
3569
- return html19`<div>${feedbackText()}</div>`;
3906
+ return html20`<div>${feedbackText()}</div>`;
3570
3907
  }
3571
3908
  };
3572
- __decorate19([
3573
- consume13({ context: computedContext, subscribe: true })
3909
+ __decorate21([
3910
+ consume14({ context: computedContext, subscribe: true })
3574
3911
  ], TestScoringFeedback.prototype, "computedContext", void 0);
3575
- __decorate19([
3576
- property14({ type: String, attribute: "view" })
3912
+ __decorate21([
3913
+ property16({ type: String, attribute: "view" })
3577
3914
  ], TestScoringFeedback.prototype, "view", void 0);
3578
3915
 
3579
3916
  // ../qti-test/dist/components/test-section-buttons-stamp/test-section-buttons-stamp.js
3580
- import { html as html20, LitElement as LitElement21 } from "lit";
3581
- import { consume as consume14 } from "@lit/context";
3582
- var __decorate20 = function(decorators, target, key, desc) {
3917
+ import { html as html21, LitElement as LitElement22 } from "lit";
3918
+ import { consume as consume15 } from "@lit/context";
3919
+ var __decorate22 = function(decorators, target, key, desc) {
3583
3920
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3584
3921
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
3585
3922
  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;
3586
3923
  return c > 3 && r && Object.defineProperty(target, key, r), r;
3587
3924
  };
3588
- var TestSectionButtonsStamp = class extends LitElement21 {
3925
+ var TestSectionButtonsStamp = class extends LitElement22 {
3589
3926
  #internals;
3590
3927
  createRenderRoot() {
3591
3928
  return this;
@@ -3602,25 +3939,25 @@ var TestSectionButtonsStamp = class extends LitElement21 {
3602
3939
  }
3603
3940
  render() {
3604
3941
  if (!this.computedContext)
3605
- return html20``;
3942
+ return html21``;
3606
3943
  const sections = this.computedContext.testParts.flatMap((testPart) => testPart.sections);
3607
- return html20` ${sections.map((item) => this.myTemplate({ item }))} `;
3944
+ return html21` ${sections.map((item) => this.myTemplate({ item }))} `;
3608
3945
  }
3609
3946
  };
3610
- __decorate20([
3611
- consume14({ context: computedContext, subscribe: true })
3947
+ __decorate22([
3948
+ consume15({ context: computedContext, subscribe: true })
3612
3949
  ], TestSectionButtonsStamp.prototype, "computedContext", void 0);
3613
3950
 
3614
3951
  // ../qti-test/dist/components/test-section-link/test-section-link.js
3615
- import { css as css11, html as html21, LitElement as LitElement22 } from "lit";
3616
- import { property as property15 } from "lit/decorators.js";
3617
- var __decorate21 = function(decorators, target, key, desc) {
3952
+ import { css as css11, html as html22, LitElement as LitElement23 } from "lit";
3953
+ import { property as property17 } from "lit/decorators.js";
3954
+ var __decorate23 = function(decorators, target, key, desc) {
3618
3955
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3619
3956
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
3620
3957
  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;
3621
3958
  return c > 3 && r && Object.defineProperty(target, key, r), r;
3622
3959
  };
3623
- var TestSectionLink = class extends LitElement22 {
3960
+ var TestSectionLink = class extends LitElement23 {
3624
3961
  static {
3625
3962
  this.styles = css11`
3626
3963
  :host {
@@ -3647,24 +3984,24 @@ var TestSectionLink = class extends LitElement22 {
3647
3984
  this.addEventListener("click", () => this.#requestItem(this.sectionId));
3648
3985
  }
3649
3986
  render() {
3650
- return html21` <slot></slot> `;
3987
+ return html22` <slot></slot> `;
3651
3988
  }
3652
3989
  };
3653
- __decorate21([
3654
- property15({ type: String, attribute: "section-id" })
3990
+ __decorate23([
3991
+ property17({ type: String, attribute: "section-id" })
3655
3992
  ], TestSectionLink.prototype, "sectionId", void 0);
3656
3993
 
3657
3994
  // ../qti-test/dist/components/test-stamp/test-stamp.js
3658
- import { html as html22, LitElement as LitElement23, nothing as nothing3 } from "lit";
3659
- import { property as property16, state as state6 } from "lit/decorators.js";
3660
- import { consume as consume15 } from "@lit/context";
3661
- var __decorate22 = function(decorators, target, key, desc) {
3995
+ import { html as html23, LitElement as LitElement24, nothing as nothing3 } from "lit";
3996
+ import { property as property18, state as state6 } from "lit/decorators.js";
3997
+ import { consume as consume16 } from "@lit/context";
3998
+ var __decorate24 = function(decorators, target, key, desc) {
3662
3999
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3663
4000
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
3664
4001
  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;
3665
4002
  return c > 3 && r && Object.defineProperty(target, key, r), r;
3666
4003
  };
3667
- var TestStamp = class extends LitElement23 {
4004
+ var TestStamp = class extends LitElement24 {
3668
4005
  constructor() {
3669
4006
  super(...arguments);
3670
4007
  this.debug = false;
@@ -3727,33 +4064,33 @@ var TestStamp = class extends LitElement23 {
3727
4064
  }));
3728
4065
  }
3729
4066
  render() {
3730
- return html22` ${this.debug ? html22`<small><pre>${JSON.stringify(this.stampContext, null, 2)}</pre></small>` : nothing3}
4067
+ return html23` ${this.debug ? html23`<small><pre>${JSON.stringify(this.stampContext, null, 2)}</pre></small>` : nothing3}
3731
4068
  ${this.myTemplate ? this.myTemplate(this.stampContext) : nothing3}`;
3732
4069
  }
3733
4070
  };
3734
- __decorate22([
3735
- property16({ type: Boolean, reflect: true })
4071
+ __decorate24([
4072
+ property18({ type: Boolean, reflect: true })
3736
4073
  ], TestStamp.prototype, "debug", void 0);
3737
- __decorate22([
4074
+ __decorate24([
3738
4075
  state6(),
3739
- consume15({ context: computedContext, subscribe: true })
4076
+ consume16({ context: computedContext, subscribe: true })
3740
4077
  ], TestStamp.prototype, "computedContext", void 0);
3741
- __decorate22([
4078
+ __decorate24([
3742
4079
  state6()
3743
4080
  ], TestStamp.prototype, "stampContext", void 0);
3744
4081
 
3745
4082
  // ../qti-test/dist/components/test-view-toggle/test-view.js
3746
- import { html as html23, LitElement as LitElement24 } from "lit";
3747
- import { property as property17, state as state7 } from "lit/decorators.js";
3748
- import { consume as consume16 } from "@lit/context";
3749
- var __decorate23 = function(decorators, target, key, desc) {
4083
+ import { html as html24, LitElement as LitElement25 } from "lit";
4084
+ import { property as property19, state as state7 } from "lit/decorators.js";
4085
+ import { consume as consume17 } from "@lit/context";
4086
+ var __decorate25 = function(decorators, target, key, desc) {
3750
4087
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3751
4088
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
3752
4089
  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;
3753
4090
  return c > 3 && r && Object.defineProperty(target, key, r), r;
3754
4091
  };
3755
4092
  var _a;
3756
- var TestView = class extends LitElement24 {
4093
+ var TestView = class extends LitElement25 {
3757
4094
  constructor() {
3758
4095
  super(...arguments);
3759
4096
  this.label = "view";
@@ -3785,7 +4122,7 @@ var TestView = class extends LitElement24 {
3785
4122
  }));
3786
4123
  }
3787
4124
  render() {
3788
- return html23`
4125
+ return html24`
3789
4126
  <label part="label" for="viewSelect">${this.label}</label>
3790
4127
  <select
3791
4128
  part="select"
@@ -3795,38 +4132,38 @@ var TestView = class extends LitElement24 {
3795
4132
  this._switchView(el.value);
3796
4133
  }}
3797
4134
  >
3798
- ${this._viewOptions.map((v) => html23`<option value="${v}" ?selected=${v === this.sessionContext.view}>${v}</option>`)}
4135
+ ${this._viewOptions.map((v) => html24`<option value="${v}" ?selected=${v === this.sessionContext.view}>${v}</option>`)}
3799
4136
  </select>
3800
4137
  `;
3801
4138
  }
3802
4139
  };
3803
4140
  _a = TestView;
3804
- __decorate23([
3805
- consume16({ context: sessionContext, subscribe: true })
4141
+ __decorate25([
4142
+ consume17({ context: sessionContext, subscribe: true })
3806
4143
  ], TestView.prototype, "sessionContext", void 0);
3807
- __decorate23([
3808
- property17({ type: String })
4144
+ __decorate25([
4145
+ property19({ type: String })
3809
4146
  ], TestView.prototype, "label", void 0);
3810
- __decorate23([
3811
- property17({ type: String, attribute: "view-options" })
4147
+ __decorate25([
4148
+ property19({ type: String, attribute: "view-options" })
3812
4149
  ], TestView.prototype, "viewOptions", void 0);
3813
- __decorate23([
4150
+ __decorate25([
3814
4151
  watch("viewOptions", { waitUntilFirstUpdate: true })
3815
4152
  ], TestView.prototype, "_handleViewOptionsChange", void 0);
3816
- __decorate23([
4153
+ __decorate25([
3817
4154
  state7()
3818
4155
  ], TestView.prototype, "_viewOptions", void 0);
3819
4156
 
3820
4157
  // ../qti-test/dist/components/test-view-toggle/test-view-toggle.js
3821
- import { consume as consume17 } from "@lit/context";
3822
- import { html as html24, LitElement as LitElement25, nothing as nothing4 } from "lit";
3823
- var __decorate24 = function(decorators, target, key, desc) {
4158
+ import { consume as consume18 } from "@lit/context";
4159
+ import { html as html25, LitElement as LitElement26, nothing as nothing4 } from "lit";
4160
+ var __decorate26 = function(decorators, target, key, desc) {
3824
4161
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3825
4162
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
3826
4163
  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;
3827
4164
  return c > 3 && r && Object.defineProperty(target, key, r), r;
3828
4165
  };
3829
- var TestViewToggle = class extends LitElement25 {
4166
+ var TestViewToggle = class extends LitElement26 {
3830
4167
  createRenderRoot() {
3831
4168
  return this;
3832
4169
  }
@@ -3856,13 +4193,13 @@ var TestViewToggle = class extends LitElement25 {
3856
4193
  });
3857
4194
  }
3858
4195
  render() {
3859
- return html24`${this.myTemplate ? this.myTemplate({
4196
+ return html25`${this.myTemplate ? this.myTemplate({
3860
4197
  view: this.sessionContext?.view
3861
4198
  }) : nothing4}`;
3862
4199
  }
3863
4200
  };
3864
- __decorate24([
3865
- consume17({ context: sessionContext, subscribe: true })
4201
+ __decorate26([
4202
+ consume18({ context: sessionContext, subscribe: true })
3866
4203
  ], TestViewToggle.prototype, "sessionContext", void 0);
3867
4204
 
3868
4205
  // ../qti-test/dist/elements.js
@@ -3870,6 +4207,7 @@ var qtiTestElements = [
3870
4207
  { tag: "qti-assessment-item-ref", ctor: QtiAssessmentItemRef },
3871
4208
  { tag: "qti-assessment-section", ctor: QtiAssessmentSection },
3872
4209
  { tag: "qti-assessment-test", ctor: QtiAssessmentTest },
4210
+ { tag: "qti-item-session-control", ctor: QtiItemSessionControl },
3873
4211
  { tag: "qti-outcome-processing", ctor: QtiOutcomeProcessing },
3874
4212
  { tag: "qti-test", ctor: QtiTest },
3875
4213
  { tag: "qti-test-feedback", ctor: QtiTestFeedback },
@@ -3905,6 +4243,7 @@ export {
3905
4243
  QtiAssessmentItemRef,
3906
4244
  QtiAssessmentSection,
3907
4245
  QtiAssessmentTest,
4246
+ QtiItemSessionControl,
3908
4247
  QtiOutcomeProcessing,
3909
4248
  QtiOutcomeProcessingProcessor,
3910
4249
  QtiTestFeedback,
@@ -3951,4 +4290,4 @@ export {
3951
4290
  * Portions Copyright (c) 2013, the Dart project authors.
3952
4291
  *)
3953
4292
  */
3954
- //# sourceMappingURL=chunk-Q52IJELT.js.map
4293
+ //# sourceMappingURL=chunk-GBDTBHUQ.js.map