@citolab/qti-components 7.3.17 → 7.3.19
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/chunks/chunk-23JT53R2.js +1 -0
- package/cdn/chunks/chunk-2OA2G5PN.js +5 -0
- package/cdn/chunks/chunk-3HIY5HSB.js +1 -0
- package/cdn/chunks/chunk-3ZLIRREM.js +1466 -0
- package/cdn/chunks/chunk-4F3OLGZ4.js +5 -0
- package/cdn/chunks/chunk-4VCDR5BV.js +1460 -0
- package/cdn/chunks/chunk-5RZUSJSN.js +5 -0
- package/cdn/chunks/chunk-6IY26BVE.js +23 -0
- package/cdn/chunks/chunk-7HEAECQ2.js +1466 -0
- package/cdn/chunks/chunk-7T6OJ2OQ.js +1482 -0
- package/cdn/chunks/chunk-ALSHUDQZ.js +5 -0
- package/cdn/chunks/chunk-B7NVY4AR.js +23 -0
- package/cdn/chunks/chunk-BFMN6REI.js +5 -0
- package/cdn/chunks/chunk-BSK7IIBZ.js +1 -0
- package/cdn/chunks/chunk-CSEUTSSH.js +5 -0
- package/cdn/chunks/chunk-CYSQXIRZ.js +5 -0
- package/cdn/chunks/chunk-E6IOJ4MV.js +23 -0
- package/cdn/chunks/chunk-ECKBRC27.js +1482 -0
- package/cdn/chunks/chunk-ECLB2ECD.js +5 -0
- package/cdn/chunks/chunk-FDOVZYP4.js +5 -0
- package/cdn/chunks/chunk-FVIBMJDJ.js +5 -0
- package/cdn/chunks/chunk-GTSQO7SP.js +1 -0
- package/cdn/chunks/chunk-GVZHKB2Y.js +1482 -0
- package/cdn/chunks/chunk-IMHR3S57.js +1 -0
- package/cdn/chunks/chunk-JG53AUXR.js +1 -0
- package/cdn/chunks/chunk-JVW572MO.js +1 -0
- package/cdn/chunks/chunk-KM5SOM7G.js +1482 -0
- package/cdn/chunks/chunk-KY6SSNGO.js +5 -0
- package/cdn/chunks/chunk-M544CJHK.js +5 -0
- package/cdn/chunks/chunk-N223O4WD.js +5 -0
- package/cdn/chunks/chunk-N4LMZHIZ.js +5 -0
- package/cdn/chunks/chunk-ODYPYZCY.js +5 -0
- package/cdn/chunks/chunk-OGVSHQLH.js +1460 -0
- package/cdn/chunks/chunk-P5MQE2M6.js +5 -0
- package/cdn/chunks/chunk-QNBLY7TQ.js +1460 -0
- package/cdn/chunks/chunk-RKU2XDKG.js +2 -0
- package/cdn/chunks/chunk-SVVO2SFS.js +1 -0
- package/cdn/chunks/chunk-UYFLYVQK.js +5 -0
- package/cdn/chunks/chunk-UZZLQGLW.js +1460 -0
- package/cdn/chunks/chunk-V2NH5MXS.js +5 -0
- package/cdn/chunks/chunk-VB3GRBCX.js +1 -0
- package/cdn/chunks/chunk-XHSJOTCJ.js +5 -0
- package/cdn/chunks/chunk-XLFLYMNJ.js +1482 -0
- package/cdn/exports/qti-test.js +0 -0
- package/cdn/index.global.js +1 -1
- package/cdn/index.js +1 -1
- package/cdn/qti-components/index.js +1 -1
- package/cdn/qti-item/components/item-container.js +1 -1
- package/cdn/qti-item/core/index.js +1 -1
- package/cdn/qti-loader/index.js +1 -1
- package/cdn/qti-test/components/index.js +1 -1
- package/cdn/qti-test/components/test-container.js +1 -1
- package/cdn/qti-test/components/test-navigation.js +1 -1
- package/cdn/qti-test/components/test-scoring-buttons.js +1 -1
- package/cdn/qti-test/components/test-scoring-feedback.js +1 -1
- package/cdn/qti-test/core/index.js +1 -1
- package/cdn/qti-transformers/index.js +1 -1
- package/dist/chunks/chunk-2EGQQQHL.js +31 -0
- package/dist/chunks/chunk-2EGQQQHL.js.map +1 -0
- package/dist/chunks/chunk-45FDEM7M.js +94 -0
- package/dist/chunks/chunk-45FDEM7M.js.map +1 -0
- package/dist/chunks/chunk-4B4DRCXO.js +94 -0
- package/dist/chunks/chunk-4B4DRCXO.js.map +1 -0
- package/dist/chunks/chunk-4MTF6JXS.js +913 -0
- package/dist/chunks/chunk-4MTF6JXS.js.map +1 -0
- package/dist/chunks/chunk-5IYIGX6A.js +94 -0
- package/dist/chunks/chunk-5IYIGX6A.js.map +1 -0
- package/dist/chunks/chunk-5QP5YUXY.js +913 -0
- package/dist/chunks/chunk-5QP5YUXY.js.map +1 -0
- package/dist/chunks/chunk-5XONMCVB.js +8012 -0
- package/dist/chunks/chunk-5XONMCVB.js.map +1 -0
- package/dist/chunks/chunk-AH3ZDQHQ.js +913 -0
- package/dist/chunks/chunk-AH3ZDQHQ.js.map +1 -0
- package/dist/chunks/chunk-BAZMB7Z3.js +8009 -0
- package/dist/chunks/chunk-BAZMB7Z3.js.map +1 -0
- package/dist/chunks/chunk-BO6KBXLI.js +913 -0
- package/dist/chunks/chunk-BO6KBXLI.js.map +1 -0
- package/dist/chunks/chunk-BXUNJ6XB.js +78 -0
- package/dist/chunks/chunk-BXUNJ6XB.js.map +1 -0
- package/dist/chunks/chunk-CTESMSQO.js +56 -0
- package/dist/chunks/chunk-CTESMSQO.js.map +1 -0
- package/dist/chunks/chunk-CVMIO3DA.js +913 -0
- package/dist/chunks/chunk-CVMIO3DA.js.map +1 -0
- package/dist/chunks/chunk-DJWEI2NH.js +502 -0
- package/dist/chunks/chunk-DJWEI2NH.js.map +1 -0
- package/dist/chunks/chunk-E6V3JHVT.js +31 -0
- package/dist/chunks/chunk-E6V3JHVT.js.map +1 -0
- package/dist/chunks/chunk-EFY3NEXY.js +94 -0
- package/dist/chunks/chunk-EFY3NEXY.js.map +1 -0
- package/dist/chunks/chunk-EXBK4TXV.js +273 -0
- package/dist/chunks/chunk-EXBK4TXV.js.map +1 -0
- package/dist/chunks/chunk-FXO6HW6L.js +8084 -0
- package/dist/chunks/chunk-FXO6HW6L.js.map +1 -0
- package/dist/chunks/chunk-GIY6GNXQ.js +913 -0
- package/dist/chunks/chunk-GIY6GNXQ.js.map +1 -0
- package/dist/chunks/chunk-GT6TR4B6.js +94 -0
- package/dist/chunks/chunk-GT6TR4B6.js.map +1 -0
- package/dist/chunks/chunk-H67RKRFW.js +94 -0
- package/dist/chunks/chunk-H67RKRFW.js.map +1 -0
- package/dist/chunks/chunk-I5EA6DJB.js +92 -0
- package/dist/chunks/chunk-I5EA6DJB.js.map +1 -0
- package/dist/chunks/chunk-LU5A5PN5.js +8084 -0
- package/dist/chunks/chunk-LU5A5PN5.js.map +1 -0
- package/dist/chunks/chunk-NBENQI27.js +273 -0
- package/dist/chunks/chunk-NBENQI27.js.map +1 -0
- package/dist/chunks/chunk-NEAO4XCM.js +913 -0
- package/dist/chunks/chunk-NEAO4XCM.js.map +1 -0
- package/dist/chunks/chunk-NHJUBMZ4.js +913 -0
- package/dist/chunks/chunk-NHJUBMZ4.js.map +1 -0
- package/dist/chunks/chunk-NPZ3WHOS.js +94 -0
- package/dist/chunks/chunk-NPZ3WHOS.js.map +1 -0
- package/dist/chunks/chunk-OGAKPUCC.js +502 -0
- package/dist/chunks/chunk-OGAKPUCC.js.map +1 -0
- package/dist/chunks/chunk-OP5LKZIM.js +913 -0
- package/dist/chunks/chunk-OP5LKZIM.js.map +1 -0
- package/dist/chunks/chunk-RL3NBBKW.js +913 -0
- package/dist/chunks/chunk-RL3NBBKW.js.map +1 -0
- package/dist/chunks/chunk-SA3X6RSE.js +8002 -0
- package/dist/chunks/chunk-SA3X6RSE.js.map +1 -0
- package/dist/chunks/chunk-SV356YP4.js +31 -0
- package/dist/chunks/chunk-SV356YP4.js.map +1 -0
- package/dist/chunks/chunk-TU6COU44.js +82 -0
- package/dist/chunks/chunk-TU6COU44.js.map +1 -0
- package/dist/chunks/chunk-VEASE2VL.js +913 -0
- package/dist/chunks/chunk-VEASE2VL.js.map +1 -0
- package/dist/chunks/chunk-VFPUMDJK.js +8002 -0
- package/dist/chunks/chunk-VFPUMDJK.js.map +1 -0
- package/dist/chunks/chunk-VHSCCVNF.js +8024 -0
- package/dist/chunks/chunk-VHSCCVNF.js.map +1 -0
- package/dist/chunks/chunk-VRR4ODZY.js +8009 -0
- package/dist/chunks/chunk-VRR4ODZY.js.map +1 -0
- package/dist/chunks/chunk-WFUXZ4UT.js +502 -0
- package/dist/chunks/chunk-WFUXZ4UT.js.map +1 -0
- package/dist/chunks/chunk-WOCRTIKW.js +8012 -0
- package/dist/chunks/chunk-WOCRTIKW.js.map +1 -0
- package/dist/chunks/chunk-Y3UM2YVB.js +8025 -0
- package/dist/chunks/chunk-Y3UM2YVB.js.map +1 -0
- package/dist/chunks/chunk-YRYQIUNT.js +913 -0
- package/dist/chunks/chunk-YRYQIUNT.js.map +1 -0
- package/dist/exports/computed-item.context.d.ts +1 -1
- package/dist/exports/computed.context.d.ts +2 -2
- package/dist/exports/interaction.d.ts +1 -1
- package/dist/exports/item.context.d.ts +1 -1
- package/dist/exports/qti-assessment-item.context.d.ts +1 -1
- package/dist/exports/qti-condition-expression.d.ts +1 -1
- package/dist/exports/qti-expression.d.ts +1 -1
- package/dist/exports/qti-test.d.ts +34 -0
- package/dist/exports/qti-test.js +1 -0
- package/dist/exports/qti-test.js.map +1 -0
- package/dist/exports/session.context.d.ts +2 -2
- package/dist/exports/test.context.d.ts +1 -1
- package/dist/exports/variables.d.ts +1 -1
- package/dist/index.d.ts +4 -3
- package/dist/index.js +24 -24
- package/dist/qti-components/index.d.ts +2 -2
- package/dist/qti-components/index.js +2 -2
- package/dist/qti-item/components/item-container.js +2 -2
- package/dist/qti-item/components/item-show-correct-response.d.ts +1 -1
- package/dist/qti-item/components/print-item-variables.d.ts +1 -1
- package/dist/qti-item/core/index.d.ts +1 -1
- package/dist/qti-item/core/index.js +3 -3
- package/dist/qti-loader/index.d.ts +1 -1
- package/dist/qti-loader/index.js +2 -2
- package/dist/qti-response-declaration-BSUPHx0G.d.ts +1358 -0
- package/dist/qti-response-declaration-CIPGNbno.d.ts +1361 -0
- package/dist/qti-response-declaration-CXb5CI4-.d.ts +1361 -0
- package/dist/qti-response-declaration-DNXsTvKe.d.ts +1358 -0
- package/dist/qti-response-declaration-q716ty5y.d.ts +1358 -0
- package/dist/qti-test/components/index.d.ts +2 -2
- package/dist/qti-test/components/index.js +13 -13
- package/dist/qti-test/components/test-container.js +2 -2
- package/dist/qti-test/components/test-navigation.d.ts +2 -2
- package/dist/qti-test/components/test-navigation.js +1 -1
- package/dist/qti-test/components/test-next.d.ts +2 -2
- package/dist/qti-test/components/test-prev.d.ts +2 -2
- package/dist/qti-test/components/test-print-context.d.ts +2 -2
- package/dist/qti-test/components/test-print-item-variables.d.ts +2 -2
- package/dist/qti-test/components/test-scoring-buttons.d.ts +2 -2
- package/dist/qti-test/components/test-scoring-buttons.js +1 -1
- package/dist/qti-test/components/test-scoring-feedback.d.ts +2 -2
- package/dist/qti-test/components/test-scoring-feedback.js +1 -1
- package/dist/qti-test/components/test-show-correct-response.d.ts +2 -2
- package/dist/qti-test/core/index.d.ts +5 -4
- package/dist/qti-test/core/index.js +3 -3
- package/dist/qti-test-feedback-D-vBFqJ5.d.ts +91 -0
- package/dist/qti-test-feedback-DTIDvsS-.d.ts +91 -0
- package/dist/qti-test-feedback-Ddb0QQyz.d.ts +91 -0
- package/dist/qti-test-feedback-TcrkevLg.d.ts +91 -0
- package/dist/qti-test-feedback-hJuvW_Ei.d.ts +91 -0
- package/dist/qti-transformers/index.d.ts +17 -1
- package/dist/qti-transformers/index.js +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,913 @@
|
|
|
1
|
+
import {
|
|
2
|
+
INITIAL_SESSION_CONTEXT,
|
|
3
|
+
sessionContext
|
|
4
|
+
} from "./chunk-22IRJWWY.js";
|
|
5
|
+
import {
|
|
6
|
+
INITIAL_TEST_CONTEXT,
|
|
7
|
+
testContext
|
|
8
|
+
} from "./chunk-CJADUWEC.js";
|
|
9
|
+
import {
|
|
10
|
+
QtiModalFeedback
|
|
11
|
+
} from "./chunk-VRR4ODZY.js";
|
|
12
|
+
import {
|
|
13
|
+
qtiTransformItem
|
|
14
|
+
} from "./chunk-DJWEI2NH.js";
|
|
15
|
+
import {
|
|
16
|
+
__decorateClass
|
|
17
|
+
} from "./chunk-H2JE6IVU.js";
|
|
18
|
+
|
|
19
|
+
// src/lib/qti-test/core/qti-test.ts
|
|
20
|
+
import { html } from "lit";
|
|
21
|
+
import { customElement } from "lit/decorators.js";
|
|
22
|
+
|
|
23
|
+
// src/lib/qti-test/core/mixins/test-navigation.mixin.ts
|
|
24
|
+
import { property } from "lit/decorators.js";
|
|
25
|
+
var NavigationErrorType = /* @__PURE__ */ ((NavigationErrorType2) => {
|
|
26
|
+
NavigationErrorType2["ITEM_NOT_FOUND"] = "item-not-found";
|
|
27
|
+
NavigationErrorType2["SECTION_NOT_FOUND"] = "section-not-found";
|
|
28
|
+
NavigationErrorType2["LOAD_ERROR"] = "load-error";
|
|
29
|
+
NavigationErrorType2["NETWORK_ERROR"] = "network-error";
|
|
30
|
+
NavigationErrorType2["TIMEOUT_ERROR"] = "timeout-error";
|
|
31
|
+
return NavigationErrorType2;
|
|
32
|
+
})(NavigationErrorType || {});
|
|
33
|
+
var TestNavigationMixin = (superClass) => {
|
|
34
|
+
class TestNavigationClass extends superClass {
|
|
35
|
+
constructor(...args) {
|
|
36
|
+
super(...args);
|
|
37
|
+
this.navigate = null;
|
|
38
|
+
this.cacheTransform = false;
|
|
39
|
+
this.requestTimeout = 3e4;
|
|
40
|
+
this.showLoadingIndicators = true;
|
|
41
|
+
this._activeRequests = [];
|
|
42
|
+
this._navigationInProgress = false;
|
|
43
|
+
this._lastError = null;
|
|
44
|
+
this._lastNavigationRequestId = null;
|
|
45
|
+
this._targetNavigation = null;
|
|
46
|
+
this.addEventListener(
|
|
47
|
+
"qti-request-navigation",
|
|
48
|
+
async ({ detail }) => {
|
|
49
|
+
if (!detail?.id) return;
|
|
50
|
+
const navigationRequestId = `nav_${Date.now()}_${Math.random()}`;
|
|
51
|
+
this._lastNavigationRequestId = navigationRequestId;
|
|
52
|
+
try {
|
|
53
|
+
this._navigationInProgress = true;
|
|
54
|
+
this._lastError = null;
|
|
55
|
+
this._dispatchStatusEvent({ loading: true, type: detail.type, id: detail.id });
|
|
56
|
+
this._cancelActiveRequests();
|
|
57
|
+
this._targetNavigation = { type: detail.type, id: detail.id };
|
|
58
|
+
if (detail.type === "item") {
|
|
59
|
+
await this._navigateToItem(detail.id);
|
|
60
|
+
} else if (detail.type === "section") {
|
|
61
|
+
await this._navigateToSection(detail.id);
|
|
62
|
+
}
|
|
63
|
+
if (this._lastNavigationRequestId !== navigationRequestId) {
|
|
64
|
+
console.log("Navigation was superseded by a newer request");
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
} catch (error) {
|
|
68
|
+
if (this._lastNavigationRequestId === navigationRequestId) {
|
|
69
|
+
const navError = this._normalizeError(error, detail.type, detail.id);
|
|
70
|
+
this._lastError = navError;
|
|
71
|
+
this._dispatchErrorEvent(navError);
|
|
72
|
+
console.error(`Navigation error (${navError.type}):`, navError.message, navError.details);
|
|
73
|
+
}
|
|
74
|
+
} finally {
|
|
75
|
+
if (this._lastNavigationRequestId === navigationRequestId) {
|
|
76
|
+
this._navigationInProgress = false;
|
|
77
|
+
this._dispatchStatusEvent({ loading: false, type: detail.type, id: detail.id });
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
);
|
|
82
|
+
this.addEventListener("qti-assessment-test-connected", (e) => {
|
|
83
|
+
this._testElement = e.detail;
|
|
84
|
+
this._initializeNavigation();
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Initialize navigation when test is first connected
|
|
89
|
+
*/
|
|
90
|
+
_initializeNavigation() {
|
|
91
|
+
let id;
|
|
92
|
+
if (this.navigate === "section") {
|
|
93
|
+
id = this._testElement.querySelector("qti-assessment-section")?.identifier;
|
|
94
|
+
}
|
|
95
|
+
if (this.navigate === "item") {
|
|
96
|
+
id = this.sessionContext.navItemRefId ?? this._testElement.querySelector("qti-assessment-item-ref")?.identifier;
|
|
97
|
+
}
|
|
98
|
+
if (id) {
|
|
99
|
+
this.dispatchEvent(
|
|
100
|
+
new CustomEvent("qti-request-navigation", {
|
|
101
|
+
detail: { type: this.navigate === "section" ? "section" : "item", id },
|
|
102
|
+
bubbles: true,
|
|
103
|
+
composed: true
|
|
104
|
+
})
|
|
105
|
+
);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
navigateTo(type, id) {
|
|
109
|
+
if (!id) {
|
|
110
|
+
if (type === "section") {
|
|
111
|
+
id = this._testElement?.querySelector("qti-assessment-section")?.identifier;
|
|
112
|
+
}
|
|
113
|
+
if (type === "item") {
|
|
114
|
+
id = this._testElement?.querySelector("qti-assessment-item-ref")?.identifier;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
this.dispatchEvent(
|
|
118
|
+
new CustomEvent("qti-request-navigation", {
|
|
119
|
+
detail: { type, id },
|
|
120
|
+
bubbles: true,
|
|
121
|
+
composed: true
|
|
122
|
+
})
|
|
123
|
+
);
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Navigates to a specific item
|
|
127
|
+
*/
|
|
128
|
+
async _navigateToItem(itemId) {
|
|
129
|
+
const itemRefEl = this._testElement?.querySelector(
|
|
130
|
+
`qti-assessment-item-ref[identifier="${itemId}"]`
|
|
131
|
+
);
|
|
132
|
+
if (!itemRefEl) {
|
|
133
|
+
throw {
|
|
134
|
+
type: "item-not-found" /* ITEM_NOT_FOUND */,
|
|
135
|
+
message: `Item with identifier "${itemId}" not found.`,
|
|
136
|
+
itemId
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
const navPartId = itemRefEl.closest("qti-test-part")?.identifier;
|
|
140
|
+
const navSectionId = itemRefEl.closest("qti-assessment-section")?.identifier;
|
|
141
|
+
this.sessionContext = {
|
|
142
|
+
...this.sessionContext,
|
|
143
|
+
navPartId,
|
|
144
|
+
navSectionId,
|
|
145
|
+
navItemRefId: itemId,
|
|
146
|
+
navItemLoading: true
|
|
147
|
+
};
|
|
148
|
+
try {
|
|
149
|
+
await this._loadItems([itemId]);
|
|
150
|
+
} finally {
|
|
151
|
+
this.sessionContext = {
|
|
152
|
+
...this.sessionContext,
|
|
153
|
+
navItemLoading: false
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Navigates to a specific section
|
|
159
|
+
*/
|
|
160
|
+
async _navigateToSection(sectionId) {
|
|
161
|
+
const sectionRefEl = this._testElement?.querySelector(
|
|
162
|
+
`qti-assessment-section[identifier="${sectionId}"]`
|
|
163
|
+
);
|
|
164
|
+
if (!sectionRefEl) {
|
|
165
|
+
throw {
|
|
166
|
+
type: "section-not-found" /* SECTION_NOT_FOUND */,
|
|
167
|
+
message: `Section with identifier "${sectionId}" not found.`,
|
|
168
|
+
sectionId
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
const navPartId = sectionRefEl.closest("qti-test-part")?.identifier;
|
|
172
|
+
this.sessionContext = {
|
|
173
|
+
...this.sessionContext,
|
|
174
|
+
navPartId,
|
|
175
|
+
navSectionId: sectionId,
|
|
176
|
+
navItemRefId: null,
|
|
177
|
+
navItemLoading: true
|
|
178
|
+
};
|
|
179
|
+
try {
|
|
180
|
+
const itemIds = this._getSectionItemIds(sectionId);
|
|
181
|
+
await this._loadItems(itemIds);
|
|
182
|
+
} finally {
|
|
183
|
+
this.sessionContext = {
|
|
184
|
+
...this.sessionContext,
|
|
185
|
+
navItemLoading: false
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
/**
|
|
190
|
+
* Normalize different error types into a consistent NavigationError format
|
|
191
|
+
*/
|
|
192
|
+
_normalizeError(error, navigationType, id) {
|
|
193
|
+
if (error && error.type && Object.values(NavigationErrorType).includes(error.type)) {
|
|
194
|
+
return error;
|
|
195
|
+
}
|
|
196
|
+
if (error instanceof DOMException && error.name === "AbortError") {
|
|
197
|
+
return {
|
|
198
|
+
type: "network-error" /* NETWORK_ERROR */,
|
|
199
|
+
message: "Navigation was cancelled because a new navigation was requested.",
|
|
200
|
+
details: error
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
if (error.name === "TimeoutError" || error.message && error.message.includes("timeout")) {
|
|
204
|
+
return {
|
|
205
|
+
type: "timeout-error" /* TIMEOUT_ERROR */,
|
|
206
|
+
message: "Request timed out. Please check your network connection.",
|
|
207
|
+
details: error
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
if (error instanceof TypeError && error.message.includes("network")) {
|
|
211
|
+
return {
|
|
212
|
+
type: "network-error" /* NETWORK_ERROR */,
|
|
213
|
+
message: "A network error occurred. Please check your connection.",
|
|
214
|
+
details: error
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
return {
|
|
218
|
+
type: "load-error" /* LOAD_ERROR */,
|
|
219
|
+
message: `Failed to load ${navigationType}: ${id}`,
|
|
220
|
+
details: error,
|
|
221
|
+
itemId: navigationType === "item" ? id : void 0,
|
|
222
|
+
sectionId: navigationType === "section" ? id : void 0
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
/**
|
|
226
|
+
* Dispatch error event to notify the UI
|
|
227
|
+
*/
|
|
228
|
+
_dispatchErrorEvent(error) {
|
|
229
|
+
this.dispatchEvent(
|
|
230
|
+
new CustomEvent("qti-navigation-error", {
|
|
231
|
+
detail: error,
|
|
232
|
+
bubbles: true,
|
|
233
|
+
composed: true
|
|
234
|
+
})
|
|
235
|
+
);
|
|
236
|
+
}
|
|
237
|
+
/**
|
|
238
|
+
* Dispatch status event to indicate loading state
|
|
239
|
+
*/
|
|
240
|
+
_dispatchStatusEvent(status) {
|
|
241
|
+
if (this.showLoadingIndicators) {
|
|
242
|
+
this.dispatchEvent(
|
|
243
|
+
new CustomEvent("qti-navigation-status", {
|
|
244
|
+
detail: status,
|
|
245
|
+
bubbles: true,
|
|
246
|
+
composed: true
|
|
247
|
+
})
|
|
248
|
+
);
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
/**
|
|
252
|
+
* Cancels all active HTTP requests
|
|
253
|
+
*/
|
|
254
|
+
_cancelActiveRequests() {
|
|
255
|
+
if (this._activeRequests.length > 0) {
|
|
256
|
+
console.info(`Cancelling ${this._activeRequests.length} pending requests`);
|
|
257
|
+
this._activeRequests.forEach((request) => {
|
|
258
|
+
if (request && request.readyState !== 4) {
|
|
259
|
+
request.abort();
|
|
260
|
+
}
|
|
261
|
+
});
|
|
262
|
+
this._activeRequests = [];
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
/**
|
|
266
|
+
* Load items with improved error handling and timeout
|
|
267
|
+
*/
|
|
268
|
+
async _loadItems(itemIds) {
|
|
269
|
+
if (!this._testElement || itemIds.length === 0) return;
|
|
270
|
+
const itemRefEls = itemIds.map(
|
|
271
|
+
(id) => this._testElement.querySelector(`qti-assessment-item-ref[identifier="${id}"]`)
|
|
272
|
+
);
|
|
273
|
+
const missingItems = itemRefEls.reduce((missing, el, index) => {
|
|
274
|
+
if (!el) missing.push(itemIds[index]);
|
|
275
|
+
return missing;
|
|
276
|
+
}, []);
|
|
277
|
+
if (missingItems.length > 0) {
|
|
278
|
+
const error = {
|
|
279
|
+
type: "item-not-found" /* ITEM_NOT_FOUND */,
|
|
280
|
+
message: `One or more items not found: ${missingItems.join(", ")}`,
|
|
281
|
+
details: { missingItems }
|
|
282
|
+
};
|
|
283
|
+
throw error;
|
|
284
|
+
}
|
|
285
|
+
this._clearLoadedItems();
|
|
286
|
+
const itemLoadPromises = itemRefEls.map(async (itemRef) => {
|
|
287
|
+
if (!itemRef) return null;
|
|
288
|
+
const timeoutPromise = new Promise((_, reject) => {
|
|
289
|
+
setTimeout(() => {
|
|
290
|
+
reject({
|
|
291
|
+
name: "TimeoutError",
|
|
292
|
+
message: `Request for item ${itemRef.identifier} timed out after ${this.requestTimeout}ms`
|
|
293
|
+
});
|
|
294
|
+
}, this.requestTimeout);
|
|
295
|
+
});
|
|
296
|
+
try {
|
|
297
|
+
const { promise, request } = qtiTransformItem(this.cacheTransform).load(itemRef.href);
|
|
298
|
+
if (request instanceof XMLHttpRequest) {
|
|
299
|
+
this._activeRequests.push(request);
|
|
300
|
+
}
|
|
301
|
+
const apiResult = await Promise.race([promise, timeoutPromise]);
|
|
302
|
+
return {
|
|
303
|
+
itemRef,
|
|
304
|
+
doc: apiResult.htmlDoc(),
|
|
305
|
+
request
|
|
306
|
+
};
|
|
307
|
+
} catch (error) {
|
|
308
|
+
if (error instanceof DOMException && error.name === "AbortError" || error && error.name === "TimeoutError") {
|
|
309
|
+
console.log(
|
|
310
|
+
`Request for item ${itemRef.identifier} was ${error.name === "TimeoutError" ? "timed out" : "aborted"}`
|
|
311
|
+
);
|
|
312
|
+
return null;
|
|
313
|
+
}
|
|
314
|
+
error.itemId = itemRef.identifier;
|
|
315
|
+
throw error;
|
|
316
|
+
}
|
|
317
|
+
});
|
|
318
|
+
try {
|
|
319
|
+
const results = await Promise.all(itemLoadPromises);
|
|
320
|
+
const validResults = results.filter((result) => result !== null);
|
|
321
|
+
validResults.forEach(({ itemRef, doc }) => {
|
|
322
|
+
if (itemRef && doc) itemRef.xmlDoc = doc;
|
|
323
|
+
});
|
|
324
|
+
this._activeRequests = [];
|
|
325
|
+
requestAnimationFrame(() => {
|
|
326
|
+
this.dispatchEvent(
|
|
327
|
+
new CustomEvent("qti-test-loaded", {
|
|
328
|
+
detail: validResults.map(({ itemRef }) => ({
|
|
329
|
+
identifier: itemRef?.identifier,
|
|
330
|
+
element: itemRef
|
|
331
|
+
})),
|
|
332
|
+
bubbles: true,
|
|
333
|
+
composed: true
|
|
334
|
+
})
|
|
335
|
+
);
|
|
336
|
+
});
|
|
337
|
+
if (validResults.length === 0 && itemIds.length > 0) {
|
|
338
|
+
throw {
|
|
339
|
+
type: "load-error" /* LOAD_ERROR */,
|
|
340
|
+
message: "All item requests failed to load",
|
|
341
|
+
details: { itemIds }
|
|
342
|
+
};
|
|
343
|
+
}
|
|
344
|
+
return validResults;
|
|
345
|
+
} catch (error) {
|
|
346
|
+
console.error("Error loading items:", error);
|
|
347
|
+
throw error;
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
/**
|
|
351
|
+
* Gets all item IDs in a section
|
|
352
|
+
*/
|
|
353
|
+
_getSectionItemIds(navSectionId) {
|
|
354
|
+
const sectionRefEl = this._testElement?.querySelector(
|
|
355
|
+
`qti-assessment-section[identifier="${navSectionId}"]`
|
|
356
|
+
);
|
|
357
|
+
if (!sectionRefEl) {
|
|
358
|
+
throw {
|
|
359
|
+
type: "section-not-found" /* SECTION_NOT_FOUND */,
|
|
360
|
+
message: `Section with identifier "${navSectionId}" not found.`,
|
|
361
|
+
sectionId: navSectionId
|
|
362
|
+
};
|
|
363
|
+
}
|
|
364
|
+
return Array.from(
|
|
365
|
+
this._testElement.querySelectorAll(
|
|
366
|
+
`qti-assessment-section[identifier="${navSectionId}"] > qti-assessment-item-ref`
|
|
367
|
+
)
|
|
368
|
+
).map((itemRef) => itemRef.identifier);
|
|
369
|
+
}
|
|
370
|
+
/**
|
|
371
|
+
* Clears all loaded items
|
|
372
|
+
*/
|
|
373
|
+
_clearLoadedItems() {
|
|
374
|
+
const itemRefEls = this._testElement?.querySelectorAll(
|
|
375
|
+
`qti-assessment-test qti-assessment-item-ref`
|
|
376
|
+
);
|
|
377
|
+
Array.from(itemRefEls || []).forEach((itemElement) => {
|
|
378
|
+
itemElement.xmlDoc = null;
|
|
379
|
+
});
|
|
380
|
+
}
|
|
381
|
+
/**
|
|
382
|
+
* Retry the last failed navigation
|
|
383
|
+
*/
|
|
384
|
+
retryNavigation() {
|
|
385
|
+
if (this._lastError) {
|
|
386
|
+
const type = this._lastError.itemId ? "item" : "section";
|
|
387
|
+
const id = this._lastError.itemId || this._lastError.sectionId;
|
|
388
|
+
if (id) {
|
|
389
|
+
this.dispatchEvent(
|
|
390
|
+
new CustomEvent("qti-request-navigation", {
|
|
391
|
+
detail: { type, id },
|
|
392
|
+
bubbles: true,
|
|
393
|
+
composed: true
|
|
394
|
+
})
|
|
395
|
+
);
|
|
396
|
+
}
|
|
397
|
+
} else if (this._targetNavigation) {
|
|
398
|
+
this.dispatchEvent(
|
|
399
|
+
new CustomEvent("qti-request-navigation", {
|
|
400
|
+
detail: this._targetNavigation,
|
|
401
|
+
bubbles: true,
|
|
402
|
+
composed: true
|
|
403
|
+
})
|
|
404
|
+
);
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
__decorateClass([
|
|
409
|
+
property({ type: String })
|
|
410
|
+
], TestNavigationClass.prototype, "navigate", 2);
|
|
411
|
+
__decorateClass([
|
|
412
|
+
property({ type: Boolean, attribute: "cache-transform" })
|
|
413
|
+
], TestNavigationClass.prototype, "cacheTransform", 2);
|
|
414
|
+
__decorateClass([
|
|
415
|
+
property({ type: Number })
|
|
416
|
+
], TestNavigationClass.prototype, "requestTimeout", 2);
|
|
417
|
+
__decorateClass([
|
|
418
|
+
property({ type: Boolean })
|
|
419
|
+
], TestNavigationClass.prototype, "showLoadingIndicators", 2);
|
|
420
|
+
return TestNavigationClass;
|
|
421
|
+
};
|
|
422
|
+
|
|
423
|
+
// src/lib/qti-test/core/mixins/test-view.mixin.ts
|
|
424
|
+
var TestViewMixin = (superClass) => {
|
|
425
|
+
class TestViewClass extends superClass {
|
|
426
|
+
constructor(...args) {
|
|
427
|
+
super(...args);
|
|
428
|
+
this.sessionContext = { ...this.sessionContext, view: "candidate" };
|
|
429
|
+
this.addEventListener("on-test-switch-view", (e) => {
|
|
430
|
+
this.sessionContext = { ...this.sessionContext, view: e.detail };
|
|
431
|
+
this._updateElementView();
|
|
432
|
+
});
|
|
433
|
+
this.addEventListener("qti-assessment-test-connected", () => {
|
|
434
|
+
this._updateElementView();
|
|
435
|
+
});
|
|
436
|
+
this.addEventListener("qti-assessment-item-connected", (e) => {
|
|
437
|
+
this._updateElementView();
|
|
438
|
+
this._setCorrectResponseVisibility(e.detail);
|
|
439
|
+
});
|
|
440
|
+
}
|
|
441
|
+
willUpdate(changedProperties) {
|
|
442
|
+
super.willUpdate(changedProperties);
|
|
443
|
+
if (changedProperties.has("sessionContext")) {
|
|
444
|
+
this._updateElementView();
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
// Method to handle view updates for elements based on the current context view
|
|
448
|
+
_updateElementView() {
|
|
449
|
+
if (this._testElement) {
|
|
450
|
+
const viewElements = Array.from(this._testElement.querySelectorAll("[view]"));
|
|
451
|
+
viewElements.forEach((element) => {
|
|
452
|
+
element.classList.toggle("show", element.getAttribute("view") === this.sessionContext.view);
|
|
453
|
+
});
|
|
454
|
+
const assessmentItemRef = this._testElement.querySelector(
|
|
455
|
+
`qti-assessment-item-ref[identifier="${this.sessionContext.navItemRefId}"]`
|
|
456
|
+
);
|
|
457
|
+
const assessmentItem = assessmentItemRef?.assessmentItem;
|
|
458
|
+
if (assessmentItem) {
|
|
459
|
+
assessmentItem.showCorrectResponse(this.sessionContext.view === "scorer");
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
// Event handler for connected QTI assessment items
|
|
464
|
+
_setCorrectResponseVisibility(assessmentItem) {
|
|
465
|
+
assessmentItem.showCorrectResponse(this.sessionContext.view === "scorer");
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
return TestViewClass;
|
|
469
|
+
};
|
|
470
|
+
|
|
471
|
+
// src/lib/qti-test/core/test-base.ts
|
|
472
|
+
import { provide } from "@lit/context";
|
|
473
|
+
import { LitElement } from "lit";
|
|
474
|
+
import { property as property2 } from "lit/decorators.js";
|
|
475
|
+
var TestBase = class extends LitElement {
|
|
476
|
+
constructor() {
|
|
477
|
+
super();
|
|
478
|
+
this.testContext = INITIAL_TEST_CONTEXT;
|
|
479
|
+
this.sessionContext = INITIAL_SESSION_CONTEXT;
|
|
480
|
+
/**
|
|
481
|
+
* Updates the variables of an assessment item in the test context.
|
|
482
|
+
* - Matches the assessment item with the corresponding test context item.
|
|
483
|
+
* - If the item is not found, logs a warning.
|
|
484
|
+
* - Updates variables in the test context if exactly one variable exists.
|
|
485
|
+
* - Otherwise, syncs the assessment item's variables with the test context.
|
|
486
|
+
*
|
|
487
|
+
* @param assessmentItem - The assessment item to update.
|
|
488
|
+
*/
|
|
489
|
+
this._updateItemInTestContext = (assessmentItem) => {
|
|
490
|
+
const context = assessmentItem._context;
|
|
491
|
+
const identifier = context.identifier;
|
|
492
|
+
const fullVariables = context.variables;
|
|
493
|
+
const itemContext = this.testContext.items.find((i) => i?.identifier === identifier);
|
|
494
|
+
if (!itemContext) {
|
|
495
|
+
console.warn(`Item IDs between assessment.xml and item.xml should match: ${identifier} is not found!`);
|
|
496
|
+
return;
|
|
497
|
+
}
|
|
498
|
+
if (itemContext.variables?.length === 1) {
|
|
499
|
+
this._updateItemVariablesInTestContext(identifier, fullVariables);
|
|
500
|
+
} else {
|
|
501
|
+
assessmentItem.variables = [...itemContext.variables || []];
|
|
502
|
+
}
|
|
503
|
+
};
|
|
504
|
+
this.addEventListener("qti-assessment-test-connected", (e) => {
|
|
505
|
+
this.testContext = INITIAL_TEST_CONTEXT;
|
|
506
|
+
this.sessionContext = INITIAL_SESSION_CONTEXT;
|
|
507
|
+
if (this.testContext && this.testContext.items.length > 0) return;
|
|
508
|
+
this._testElement = e.detail;
|
|
509
|
+
const items = Array.from(this._testElement.querySelectorAll("qti-assessment-item-ref")).map((itemRef) => {
|
|
510
|
+
return {
|
|
511
|
+
href: itemRef.href,
|
|
512
|
+
identifier: itemRef.identifier,
|
|
513
|
+
category: itemRef.category,
|
|
514
|
+
variables: [
|
|
515
|
+
{
|
|
516
|
+
identifier: "completionStatus",
|
|
517
|
+
value: "not_attempted",
|
|
518
|
+
type: "outcome"
|
|
519
|
+
}
|
|
520
|
+
]
|
|
521
|
+
};
|
|
522
|
+
});
|
|
523
|
+
this.testContext = { ...this.testContext, items };
|
|
524
|
+
});
|
|
525
|
+
this.addEventListener("qti-assessment-item-connected", (e) => {
|
|
526
|
+
const assessmentItem = e.detail;
|
|
527
|
+
const assessmentRefId = assessmentItem.closest("qti-assessment-item-ref")?.identifier;
|
|
528
|
+
if (assessmentRefId) {
|
|
529
|
+
assessmentItem.assessmentItemRefId = assessmentRefId;
|
|
530
|
+
}
|
|
531
|
+
this._updateItemInTestContext(e.detail);
|
|
532
|
+
});
|
|
533
|
+
this.addEventListener("qti-item-context-updated", (e) => {
|
|
534
|
+
this._updateItemVariablesInTestContext(e.detail.itemContext.identifier, e.detail.itemContext.variables);
|
|
535
|
+
});
|
|
536
|
+
}
|
|
537
|
+
updateItemVariables(itemRefID, variables) {
|
|
538
|
+
const itemContext = this.testContext.items.find((item) => item.identifier === itemRefID);
|
|
539
|
+
if (itemContext) {
|
|
540
|
+
itemContext.variables = itemContext.variables.map((variable) => {
|
|
541
|
+
const updatedVariable = variables.find((v) => v.identifier === variable.identifier);
|
|
542
|
+
return updatedVariable ? { ...variable, ...updatedVariable } : variable;
|
|
543
|
+
});
|
|
544
|
+
}
|
|
545
|
+
const itemRef = this._testElement.querySelector(
|
|
546
|
+
`qti-assessment-item-ref[identifier="${itemRefID}"]`
|
|
547
|
+
);
|
|
548
|
+
if (itemRef && itemRef.assessmentItem) {
|
|
549
|
+
if (itemRef.assessmentItem) {
|
|
550
|
+
itemRef.assessmentItem.variables = variables;
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
_updateItemVariablesInTestContext(identifier, variables) {
|
|
555
|
+
this.testContext = {
|
|
556
|
+
...this.testContext,
|
|
557
|
+
// Spread existing test context properties
|
|
558
|
+
items: this.testContext.items.map((itemContext) => {
|
|
559
|
+
if (itemContext.identifier !== identifier) {
|
|
560
|
+
return itemContext;
|
|
561
|
+
}
|
|
562
|
+
return {
|
|
563
|
+
...itemContext,
|
|
564
|
+
// Keep other properties of the item context
|
|
565
|
+
variables: variables.map((variable) => {
|
|
566
|
+
const matchingVariable = itemContext.variables.find((v) => v.identifier === variable.identifier);
|
|
567
|
+
return matchingVariable ? { ...matchingVariable, ...variable } : variable;
|
|
568
|
+
})
|
|
569
|
+
};
|
|
570
|
+
})
|
|
571
|
+
};
|
|
572
|
+
this.dispatchEvent(
|
|
573
|
+
new CustomEvent("qti-test-context-updated", { detail: this.testContext, bubbles: false, composed: false })
|
|
574
|
+
);
|
|
575
|
+
}
|
|
576
|
+
};
|
|
577
|
+
__decorateClass([
|
|
578
|
+
property2({ attribute: false, type: Object }),
|
|
579
|
+
provide({ context: testContext })
|
|
580
|
+
], TestBase.prototype, "testContext", 2);
|
|
581
|
+
__decorateClass([
|
|
582
|
+
property2({ attribute: false, type: Object }),
|
|
583
|
+
provide({ context: sessionContext })
|
|
584
|
+
], TestBase.prototype, "sessionContext", 2);
|
|
585
|
+
|
|
586
|
+
// src/lib/qti-test/core/mixins/test-processing.mixin.ts
|
|
587
|
+
var TestProcessingMixin = (superClass) => {
|
|
588
|
+
class TestProcessingElement extends superClass {
|
|
589
|
+
constructor(...args) {
|
|
590
|
+
super(...args);
|
|
591
|
+
this.addEventListener("qti-register-variable", (e) => {
|
|
592
|
+
this.testContext = {
|
|
593
|
+
...this.testContext,
|
|
594
|
+
testOutcomeVariables: [...this.testContext.testOutcomeVariables || [], e.detail.variable]
|
|
595
|
+
};
|
|
596
|
+
e.stopPropagation();
|
|
597
|
+
});
|
|
598
|
+
this.addEventListener(
|
|
599
|
+
"qti-set-outcome-value",
|
|
600
|
+
(e) => {
|
|
601
|
+
const { outcomeIdentifier, value } = e.detail;
|
|
602
|
+
this.updateOutcomeVariable(outcomeIdentifier, value);
|
|
603
|
+
e.stopPropagation();
|
|
604
|
+
}
|
|
605
|
+
);
|
|
606
|
+
}
|
|
607
|
+
outcomeProcessing() {
|
|
608
|
+
const outcomeProcessor = this.querySelector("qti-outcome-processing");
|
|
609
|
+
if (!outcomeProcessor) return false;
|
|
610
|
+
outcomeProcessor?.process();
|
|
611
|
+
return true;
|
|
612
|
+
}
|
|
613
|
+
/* --------------------------- ENABLED WHEN UNIT TESTING OUTCOME PROCESSING ------------------------------------ */
|
|
614
|
+
updateOutcomeVariable(identifier, value) {
|
|
615
|
+
const outcomeVariable = this.getOutcome(identifier);
|
|
616
|
+
if (!outcomeVariable) {
|
|
617
|
+
console.warn(`Can not set qti-outcome-identifier: ${identifier}, it is not available`);
|
|
618
|
+
return;
|
|
619
|
+
}
|
|
620
|
+
this.testContext = {
|
|
621
|
+
...this.testContext,
|
|
622
|
+
testOutcomeVariables: this.testContext.testOutcomeVariables?.map((v) => {
|
|
623
|
+
if (v.identifier !== identifier) {
|
|
624
|
+
return v;
|
|
625
|
+
}
|
|
626
|
+
return {
|
|
627
|
+
...v,
|
|
628
|
+
value: outcomeVariable.cardinality === "single" ? value : [...v.value, value]
|
|
629
|
+
};
|
|
630
|
+
})
|
|
631
|
+
};
|
|
632
|
+
}
|
|
633
|
+
getOutcome(identifier) {
|
|
634
|
+
return this.getVariable(identifier);
|
|
635
|
+
}
|
|
636
|
+
getVariable(identifier) {
|
|
637
|
+
return this.testContext.testOutcomeVariables?.find((v) => v.identifier === identifier) || null;
|
|
638
|
+
}
|
|
639
|
+
/* --------------------------- ENABLED WHEN UNIT TESTING OUTCOME PROCESSING ------------------------------------ */
|
|
640
|
+
}
|
|
641
|
+
return TestProcessingElement;
|
|
642
|
+
};
|
|
643
|
+
|
|
644
|
+
// src/lib/qti-test/core/qti-test.ts
|
|
645
|
+
var QtiTest = class extends TestNavigationMixin(TestViewMixin(TestProcessingMixin(TestBase))) {
|
|
646
|
+
// export class QtiTest extends TestLoaderMixin(TestNavigationMixin(TestViewMixin(TestBase))) {
|
|
647
|
+
/**
|
|
648
|
+
* Renders the component's template.
|
|
649
|
+
* Provides a default `<slot>` for content projection.
|
|
650
|
+
*/
|
|
651
|
+
async connectedCallback() {
|
|
652
|
+
super.connectedCallback();
|
|
653
|
+
await this.updateComplete;
|
|
654
|
+
this.dispatchEvent(new CustomEvent("qti-test-connected", { detail: this }));
|
|
655
|
+
}
|
|
656
|
+
render() {
|
|
657
|
+
return html`<slot></slot>`;
|
|
658
|
+
}
|
|
659
|
+
};
|
|
660
|
+
QtiTest = __decorateClass([
|
|
661
|
+
customElement("qti-test")
|
|
662
|
+
], QtiTest);
|
|
663
|
+
|
|
664
|
+
// src/lib/qti-test/core/qti-assessment-test/qti-assessment-item-ref.ts
|
|
665
|
+
import { LitElement as LitElement2 } from "lit";
|
|
666
|
+
import { property as property3 } from "lit/decorators.js";
|
|
667
|
+
import { prepareTemplate } from "@heximal/templates";
|
|
668
|
+
var stringToBooleanConverter = {
|
|
669
|
+
fromAttribute(value) {
|
|
670
|
+
return value === "true";
|
|
671
|
+
},
|
|
672
|
+
toAttribute(value) {
|
|
673
|
+
return value ? "true" : "false";
|
|
674
|
+
}
|
|
675
|
+
};
|
|
676
|
+
var QtiAssessmentItemRef = class extends LitElement2 {
|
|
677
|
+
constructor() {
|
|
678
|
+
super(...arguments);
|
|
679
|
+
// @consume({ context: computedContext, subscribe: true })
|
|
680
|
+
// private computedContext: ComputedContext;
|
|
681
|
+
this.weigths = /* @__PURE__ */ new Map();
|
|
682
|
+
}
|
|
683
|
+
// the XMLDocument
|
|
684
|
+
createRenderRoot() {
|
|
685
|
+
return this;
|
|
686
|
+
}
|
|
687
|
+
get assessmentItem() {
|
|
688
|
+
return this.renderRoot?.querySelector("qti-assessment-item");
|
|
689
|
+
}
|
|
690
|
+
async connectedCallback() {
|
|
691
|
+
super.connectedCallback();
|
|
692
|
+
const templateElement = this.getRootNode().host.closest("qti-test").querySelector("template[item-ref]");
|
|
693
|
+
if (templateElement) this.myTemplate = prepareTemplate(templateElement);
|
|
694
|
+
await this.updateComplete;
|
|
695
|
+
this.dispatchEvent(
|
|
696
|
+
new CustomEvent("qti-assessment-item-ref-connected", {
|
|
697
|
+
bubbles: true,
|
|
698
|
+
composed: true,
|
|
699
|
+
detail: { identifier: this.identifier, href: this.href, category: this.category }
|
|
700
|
+
})
|
|
701
|
+
);
|
|
702
|
+
}
|
|
703
|
+
render() {
|
|
704
|
+
return this.myTemplate ? this.myTemplate({ xmlDoc: this.xmlDoc }) : this.xmlDoc;
|
|
705
|
+
}
|
|
706
|
+
};
|
|
707
|
+
__decorateClass([
|
|
708
|
+
property3({ type: String })
|
|
709
|
+
], QtiAssessmentItemRef.prototype, "category", 2);
|
|
710
|
+
__decorateClass([
|
|
711
|
+
property3({ type: String })
|
|
712
|
+
], QtiAssessmentItemRef.prototype, "identifier", 2);
|
|
713
|
+
__decorateClass([
|
|
714
|
+
property3({ type: Boolean, converter: stringToBooleanConverter })
|
|
715
|
+
], QtiAssessmentItemRef.prototype, "required", 2);
|
|
716
|
+
__decorateClass([
|
|
717
|
+
property3({ type: Boolean, converter: stringToBooleanConverter })
|
|
718
|
+
], QtiAssessmentItemRef.prototype, "fixed", 2);
|
|
719
|
+
__decorateClass([
|
|
720
|
+
property3({ type: String })
|
|
721
|
+
], QtiAssessmentItemRef.prototype, "href", 2);
|
|
722
|
+
__decorateClass([
|
|
723
|
+
property3({ type: Object, attribute: false })
|
|
724
|
+
], QtiAssessmentItemRef.prototype, "xmlDoc", 2);
|
|
725
|
+
if (!customElements.get("qti-assessment-item-ref")) {
|
|
726
|
+
customElements.define("qti-assessment-item-ref", QtiAssessmentItemRef);
|
|
727
|
+
}
|
|
728
|
+
|
|
729
|
+
// src/lib/qti-test/core/qti-assessment-test/qti-assessment-section.ts
|
|
730
|
+
import { consume } from "@lit/context";
|
|
731
|
+
import { html as html2, LitElement as LitElement3 } from "lit";
|
|
732
|
+
import { property as property4 } from "lit/decorators.js";
|
|
733
|
+
var stringToBooleanConverter2 = {
|
|
734
|
+
fromAttribute(value) {
|
|
735
|
+
return value === "true";
|
|
736
|
+
},
|
|
737
|
+
toAttribute(value) {
|
|
738
|
+
return value ? "true" : "false";
|
|
739
|
+
}
|
|
740
|
+
};
|
|
741
|
+
var QtiAssessmentSection = class extends LitElement3 {
|
|
742
|
+
constructor() {
|
|
743
|
+
super(...arguments);
|
|
744
|
+
this._title = "";
|
|
745
|
+
}
|
|
746
|
+
get title() {
|
|
747
|
+
return this._title;
|
|
748
|
+
}
|
|
749
|
+
set title(value) {
|
|
750
|
+
this._title = value;
|
|
751
|
+
this.removeAttribute("title");
|
|
752
|
+
this.setAttribute("data-title", value);
|
|
753
|
+
}
|
|
754
|
+
async connectedCallback() {
|
|
755
|
+
super.connectedCallback();
|
|
756
|
+
await this.updateComplete;
|
|
757
|
+
this.dispatchEvent(
|
|
758
|
+
new Event("qti-assessment-section-connected", {
|
|
759
|
+
bubbles: true,
|
|
760
|
+
composed: true
|
|
761
|
+
})
|
|
762
|
+
);
|
|
763
|
+
}
|
|
764
|
+
render() {
|
|
765
|
+
return html2`<slot name="qti-rubric-block"></slot><slot></slot>`;
|
|
766
|
+
}
|
|
767
|
+
};
|
|
768
|
+
__decorateClass([
|
|
769
|
+
property4({ type: String })
|
|
770
|
+
], QtiAssessmentSection.prototype, "identifier", 2);
|
|
771
|
+
__decorateClass([
|
|
772
|
+
property4({ type: String })
|
|
773
|
+
], QtiAssessmentSection.prototype, "required", 2);
|
|
774
|
+
__decorateClass([
|
|
775
|
+
property4({ type: Boolean, converter: stringToBooleanConverter2 })
|
|
776
|
+
], QtiAssessmentSection.prototype, "fixed", 2);
|
|
777
|
+
__decorateClass([
|
|
778
|
+
property4({ type: Boolean, converter: stringToBooleanConverter2 })
|
|
779
|
+
], QtiAssessmentSection.prototype, "visible", 2);
|
|
780
|
+
__decorateClass([
|
|
781
|
+
property4({ type: Boolean, converter: stringToBooleanConverter2, attribute: "keep-together" })
|
|
782
|
+
], QtiAssessmentSection.prototype, "keepTogether", 2);
|
|
783
|
+
__decorateClass([
|
|
784
|
+
consume({ context: testContext, subscribe: true })
|
|
785
|
+
], QtiAssessmentSection.prototype, "_testContext", 2);
|
|
786
|
+
if (!customElements.get("qti-assessment-section")) {
|
|
787
|
+
customElements.define("qti-assessment-section", QtiAssessmentSection);
|
|
788
|
+
}
|
|
789
|
+
|
|
790
|
+
// src/lib/qti-test/core/qti-assessment-test/qti-assessment-test.ts
|
|
791
|
+
import { consume as consume2 } from "@lit/context";
|
|
792
|
+
import { html as html3, LitElement as LitElement4 } from "lit";
|
|
793
|
+
import { customElement as customElement2, property as property5 } from "lit/decorators.js";
|
|
794
|
+
var QtiAssessmentTest = class extends LitElement4 {
|
|
795
|
+
constructor() {
|
|
796
|
+
super(...arguments);
|
|
797
|
+
this._title = "";
|
|
798
|
+
}
|
|
799
|
+
get title() {
|
|
800
|
+
return this._title;
|
|
801
|
+
}
|
|
802
|
+
set title(value) {
|
|
803
|
+
this._title = value;
|
|
804
|
+
this.removeAttribute("title");
|
|
805
|
+
this.setAttribute("data-title", value);
|
|
806
|
+
}
|
|
807
|
+
async connectedCallback() {
|
|
808
|
+
super.connectedCallback();
|
|
809
|
+
await this.updateComplete;
|
|
810
|
+
this.dispatchEvent(
|
|
811
|
+
new CustomEvent("qti-assessment-test-connected", {
|
|
812
|
+
detail: this,
|
|
813
|
+
bubbles: true,
|
|
814
|
+
composed: true
|
|
815
|
+
})
|
|
816
|
+
);
|
|
817
|
+
}
|
|
818
|
+
render() {
|
|
819
|
+
return html3` <slot></slot>`;
|
|
820
|
+
}
|
|
821
|
+
};
|
|
822
|
+
__decorateClass([
|
|
823
|
+
property5({ type: String })
|
|
824
|
+
], QtiAssessmentTest.prototype, "identifier", 2);
|
|
825
|
+
__decorateClass([
|
|
826
|
+
property5({ type: String })
|
|
827
|
+
], QtiAssessmentTest.prototype, "title", 1);
|
|
828
|
+
__decorateClass([
|
|
829
|
+
consume2({ context: testContext, subscribe: true })
|
|
830
|
+
], QtiAssessmentTest.prototype, "_testContext", 2);
|
|
831
|
+
QtiAssessmentTest = __decorateClass([
|
|
832
|
+
customElement2("qti-assessment-test")
|
|
833
|
+
], QtiAssessmentTest);
|
|
834
|
+
|
|
835
|
+
// src/lib/qti-test/core/qti-assessment-test/qti-test-part.ts
|
|
836
|
+
import { html as html4, LitElement as LitElement5 } from "lit";
|
|
837
|
+
import { customElement as customElement3, property as property6 } from "lit/decorators.js";
|
|
838
|
+
var QtiTestPart = class extends LitElement5 {
|
|
839
|
+
constructor() {
|
|
840
|
+
super(...arguments);
|
|
841
|
+
this.identifier = "";
|
|
842
|
+
this.class = "";
|
|
843
|
+
this.navigationMode = "nonlinear";
|
|
844
|
+
this.submissionMode = "individual";
|
|
845
|
+
this._title = "";
|
|
846
|
+
}
|
|
847
|
+
get title() {
|
|
848
|
+
return this._title;
|
|
849
|
+
}
|
|
850
|
+
set title(value) {
|
|
851
|
+
this._title = value;
|
|
852
|
+
this.removeAttribute("title");
|
|
853
|
+
this.setAttribute("data-title", value);
|
|
854
|
+
}
|
|
855
|
+
async connectedCallback() {
|
|
856
|
+
super.connectedCallback();
|
|
857
|
+
await this.updateComplete;
|
|
858
|
+
this.dispatchEvent(
|
|
859
|
+
new Event("qti-test-part-connected", {
|
|
860
|
+
bubbles: true,
|
|
861
|
+
composed: true
|
|
862
|
+
})
|
|
863
|
+
);
|
|
864
|
+
}
|
|
865
|
+
render() {
|
|
866
|
+
return html4` <slot></slot>`;
|
|
867
|
+
}
|
|
868
|
+
};
|
|
869
|
+
__decorateClass([
|
|
870
|
+
property6({ type: String })
|
|
871
|
+
], QtiTestPart.prototype, "identifier", 2);
|
|
872
|
+
__decorateClass([
|
|
873
|
+
property6({ type: String })
|
|
874
|
+
], QtiTestPart.prototype, "class", 2);
|
|
875
|
+
__decorateClass([
|
|
876
|
+
property6({ type: String, attribute: "navigation-mode" })
|
|
877
|
+
], QtiTestPart.prototype, "navigationMode", 2);
|
|
878
|
+
__decorateClass([
|
|
879
|
+
property6({ type: String, attribute: "submission-mode" })
|
|
880
|
+
], QtiTestPart.prototype, "submissionMode", 2);
|
|
881
|
+
QtiTestPart = __decorateClass([
|
|
882
|
+
customElement3("qti-test-part")
|
|
883
|
+
], QtiTestPart);
|
|
884
|
+
if (!customElements.get("qti-test-part")) {
|
|
885
|
+
customElements.define("qti-test-part", QtiTestPart);
|
|
886
|
+
}
|
|
887
|
+
|
|
888
|
+
// src/lib/qti-test/core/qti-assessment-test/qti-test-feedback.ts
|
|
889
|
+
import { customElement as customElement4 } from "lit/decorators.js";
|
|
890
|
+
import { css, html as html5 } from "lit";
|
|
891
|
+
var QtiTestFeedback = class extends QtiModalFeedback {
|
|
892
|
+
render() {
|
|
893
|
+
return html5``;
|
|
894
|
+
}
|
|
895
|
+
};
|
|
896
|
+
QtiTestFeedback.styles = css`
|
|
897
|
+
:host {
|
|
898
|
+
color: gray;
|
|
899
|
+
}
|
|
900
|
+
`;
|
|
901
|
+
QtiTestFeedback = __decorateClass([
|
|
902
|
+
customElement4("qti-test-feedback")
|
|
903
|
+
], QtiTestFeedback);
|
|
904
|
+
|
|
905
|
+
export {
|
|
906
|
+
QtiTest,
|
|
907
|
+
QtiAssessmentItemRef,
|
|
908
|
+
QtiAssessmentSection,
|
|
909
|
+
QtiAssessmentTest,
|
|
910
|
+
QtiTestPart,
|
|
911
|
+
QtiTestFeedback
|
|
912
|
+
};
|
|
913
|
+
//# sourceMappingURL=chunk-GIY6GNXQ.js.map
|