@citolab/qti-components 7.13.0 → 7.14.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/cdn/index.global.js +1 -1
- package/cdn/index.js +103 -103
- package/custom-elements.json +1128 -315
- package/dist/chunks/{chunk-IHE5M7QU.js → chunk-7567ZPN6.js} +4 -4
- package/dist/chunks/chunk-7567ZPN6.js.map +1 -0
- package/dist/chunks/{chunk-TFNRSY74.js → chunk-TISKSGJE.js} +24 -19
- package/dist/chunks/chunk-TISKSGJE.js.map +1 -0
- package/dist/chunks/{chunk-WFUXZ4UT.js → chunk-XBPO6E25.js} +27 -37
- package/dist/chunks/chunk-XBPO6E25.js.map +1 -0
- package/dist/chunks/{chunk-XI7S3HP2.js → chunk-XEKFVRIO.js} +363 -337
- package/dist/chunks/chunk-XEKFVRIO.js.map +1 -0
- package/dist/exports/qti-test.d.ts +2 -2
- package/dist/index.d.ts +3 -3
- package/dist/index.js +47 -36
- package/dist/index.js.map +1 -1
- package/dist/qti-components/index.d.ts +10 -9
- package/dist/qti-components/index.js +4 -2
- package/dist/qti-components-jsx.d.ts +15 -15
- package/dist/qti-item/index.js +2 -2
- package/dist/qti-loader/index.js +2 -2
- package/dist/qti-loader/index.js.map +1 -1
- package/dist/qti-test/index.d.ts +3 -3
- package/dist/qti-test/index.js +3 -3
- package/dist/{qti-test-DEJqAn7G.d.ts → qti-test-Db7oNIWY.d.ts} +1 -1
- package/dist/{qti-transform-test-DkSRdVBF.d.ts → qti-transform-test-Bz9A3hmD.d.ts} +2 -5
- package/dist/qti-transformers/index.d.ts +3 -3
- package/dist/qti-transformers/index.js +1 -1
- package/dist/vscode.html-custom-data.json +4 -21
- package/package.json +10 -1
- package/dist/chunks/chunk-IHE5M7QU.js.map +0 -1
- package/dist/chunks/chunk-TFNRSY74.js.map +0 -1
- package/dist/chunks/chunk-WFUXZ4UT.js.map +0 -1
- package/dist/chunks/chunk-XI7S3HP2.js.map +0 -1
|
@@ -1,16 +1,16 @@
|
|
|
1
|
-
import {
|
|
2
|
-
item_default
|
|
3
|
-
} from "./chunk-PT5ASWGQ.js";
|
|
4
1
|
import {
|
|
5
2
|
QtiModalFeedback
|
|
6
3
|
} from "./chunk-YD7FVKDP.js";
|
|
4
|
+
import {
|
|
5
|
+
item_default
|
|
6
|
+
} from "./chunk-PT5ASWGQ.js";
|
|
7
7
|
import {
|
|
8
8
|
watch
|
|
9
9
|
} from "./chunk-ELDMXTUQ.js";
|
|
10
10
|
import {
|
|
11
11
|
qtiTransformItem,
|
|
12
12
|
qtiTransformTest
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-XBPO6E25.js";
|
|
14
14
|
import {
|
|
15
15
|
qtiContext
|
|
16
16
|
} from "./chunk-H6KHXSIO.js";
|
|
@@ -38,14 +38,6 @@ import { customElement } from "lit/decorators.js";
|
|
|
38
38
|
|
|
39
39
|
// src/lib/qti-test/core/mixins/test-navigation.mixin.ts
|
|
40
40
|
import { property } from "lit/decorators.js";
|
|
41
|
-
var NavigationErrorType = /* @__PURE__ */ ((NavigationErrorType2) => {
|
|
42
|
-
NavigationErrorType2["ITEM_NOT_FOUND"] = "item-not-found";
|
|
43
|
-
NavigationErrorType2["SECTION_NOT_FOUND"] = "section-not-found";
|
|
44
|
-
NavigationErrorType2["LOAD_ERROR"] = "load-error";
|
|
45
|
-
NavigationErrorType2["NETWORK_ERROR"] = "network-error";
|
|
46
|
-
NavigationErrorType2["TIMEOUT_ERROR"] = "timeout-error";
|
|
47
|
-
return NavigationErrorType2;
|
|
48
|
-
})(NavigationErrorType || {});
|
|
49
41
|
var TestNavigationMixin = (superClass) => {
|
|
50
42
|
class TestNavigationClass extends superClass {
|
|
51
43
|
constructor(...args) {
|
|
@@ -53,378 +45,423 @@ var TestNavigationMixin = (superClass) => {
|
|
|
53
45
|
this.navigate = null;
|
|
54
46
|
this.cacheTransform = false;
|
|
55
47
|
this.requestTimeout = 3e4;
|
|
56
|
-
this.showLoadingIndicators = true;
|
|
57
48
|
this.postLoadTransformCallback = null;
|
|
58
49
|
this.postLoadTestTransformCallback = null;
|
|
59
|
-
|
|
60
|
-
this.
|
|
61
|
-
this.
|
|
62
|
-
|
|
63
|
-
this.
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
this._cancelActiveRequests();
|
|
75
|
-
this._targetNavigation = { type: detail.type, id: detail.id };
|
|
76
|
-
if (detail.type === "item") {
|
|
77
|
-
await this._navigateToItem(detail.id);
|
|
78
|
-
} else if (detail.type === "section") {
|
|
79
|
-
await this._navigateToSection(detail.id);
|
|
80
|
-
}
|
|
81
|
-
if (this._lastNavigationRequestId !== navigationRequestId) {
|
|
82
|
-
console.log("Navigation was superseded by a newer request");
|
|
83
|
-
return;
|
|
84
|
-
}
|
|
85
|
-
} catch (error) {
|
|
86
|
-
if (this._lastNavigationRequestId === navigationRequestId) {
|
|
87
|
-
const navError = this._normalizeError(error, detail.type, detail.id);
|
|
88
|
-
this._lastError = navError;
|
|
89
|
-
this._dispatchErrorEvent(navError);
|
|
90
|
-
console.error(`Navigation error (${navError.type}):`, navError.message, navError.details);
|
|
91
|
-
}
|
|
92
|
-
} finally {
|
|
93
|
-
if (this._lastNavigationRequestId === navigationRequestId) {
|
|
94
|
-
this._navigationInProgress = false;
|
|
95
|
-
this._dispatchStatusEvent({ loading: false, type: detail.type, id: detail.id });
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
);
|
|
100
|
-
this.addEventListener("qti-assessment-test-connected", (e) => {
|
|
101
|
-
this._testElement = e.detail;
|
|
102
|
-
this._initializeNavigation();
|
|
103
|
-
});
|
|
50
|
+
// Navigation state tracking
|
|
51
|
+
this._activeController = null;
|
|
52
|
+
this._loadResults = [];
|
|
53
|
+
// Simple loading progress tracking
|
|
54
|
+
this._loadingState = {
|
|
55
|
+
expectedItems: 0,
|
|
56
|
+
connectedItems: 0,
|
|
57
|
+
expectedStimulus: 0,
|
|
58
|
+
loadedStimulus: 0,
|
|
59
|
+
isComplete: false
|
|
60
|
+
};
|
|
61
|
+
// Track loaded/loading stimulus hrefs to prevent duplicates
|
|
62
|
+
this._loadedStimulusHrefs = /* @__PURE__ */ new Set();
|
|
63
|
+
this._loadingStimulusHrefs = /* @__PURE__ */ new Set();
|
|
64
|
+
this._bindEventHandlers();
|
|
104
65
|
}
|
|
66
|
+
// ===========================================
|
|
67
|
+
// PUBLIC API
|
|
68
|
+
// ===========================================
|
|
105
69
|
/**
|
|
106
|
-
*
|
|
70
|
+
* Navigate to a specific item or section
|
|
71
|
+
* @param type - Navigation type ('item' or 'section')
|
|
72
|
+
* @param id - Target identifier (optional, falls back to first available)
|
|
107
73
|
*/
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
if (
|
|
111
|
-
id = this._testElement.querySelector("qti-assessment-section")?.identifier;
|
|
112
|
-
}
|
|
113
|
-
if (this.navigate === "item") {
|
|
114
|
-
id = this.sessionContext.navItemRefId ?? this._testElement.querySelector("qti-assessment-item-ref")?.identifier;
|
|
115
|
-
}
|
|
116
|
-
if (id) {
|
|
74
|
+
navigateTo(type, id) {
|
|
75
|
+
const targetId = id || this._getDefaultNavigationId(type);
|
|
76
|
+
if (targetId) {
|
|
117
77
|
this.dispatchEvent(
|
|
118
78
|
new CustomEvent("qti-request-navigation", {
|
|
119
|
-
detail: { type
|
|
79
|
+
detail: { type, id: targetId },
|
|
120
80
|
bubbles: true,
|
|
121
81
|
composed: true
|
|
122
82
|
})
|
|
123
83
|
);
|
|
124
84
|
}
|
|
125
85
|
}
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
86
|
+
// ===========================================
|
|
87
|
+
// EVENT HANDLER SETUP
|
|
88
|
+
// ===========================================
|
|
89
|
+
_bindEventHandlers() {
|
|
90
|
+
this.addEventListener("qti-request-navigation", this._handleNavigationRequest.bind(this));
|
|
91
|
+
this.addEventListener("qti-assessment-test-connected", this._handleTestConnected.bind(this));
|
|
92
|
+
this.addEventListener("qti-assessment-item-connected", this._handleItemConnected.bind(this));
|
|
93
|
+
this.addEventListener("qti-assessment-stimulus-ref-connected", this._handleStimulusRefConnected.bind(this));
|
|
94
|
+
}
|
|
95
|
+
_handleTestConnected(e) {
|
|
96
|
+
this._testElement = e.detail;
|
|
97
|
+
this._initializeNavigation();
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Handle item connection events - track connected items and discover stimulus references
|
|
101
|
+
*/
|
|
102
|
+
_handleItemConnected(e) {
|
|
103
|
+
const itemRef = e.detail;
|
|
104
|
+
this._loadingState.connectedItems++;
|
|
105
|
+
const stimulusRefs = itemRef.querySelectorAll("qti-assessment-stimulus-ref");
|
|
106
|
+
this._loadingState.expectedStimulus += stimulusRefs.length;
|
|
107
|
+
this._checkLoadingComplete();
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Handle stimulus reference connection events with duplicate prevention
|
|
111
|
+
*/
|
|
112
|
+
async _handleStimulusRefConnected(e) {
|
|
113
|
+
e.preventDefault();
|
|
114
|
+
const { element, item } = e;
|
|
115
|
+
console.info("Stimulus ref connected:", {
|
|
116
|
+
identifier: element.identifier,
|
|
117
|
+
href: element.href,
|
|
118
|
+
item: item.identifier
|
|
119
|
+
});
|
|
120
|
+
if (this._loadedStimulusHrefs.has(element.href)) {
|
|
121
|
+
console.info("Stimulus already loaded, skipping:", element.href);
|
|
122
|
+
this._loadingState.loadedStimulus++;
|
|
123
|
+
this._checkLoadingComplete();
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
if (this._loadingStimulusHrefs.has(element.href)) {
|
|
127
|
+
console.info("Stimulus already loading, skipping duplicate:", element.href);
|
|
128
|
+
this._loadingState.loadedStimulus++;
|
|
129
|
+
this._checkLoadingComplete();
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
this._loadingStimulusHrefs.add(element.href);
|
|
133
|
+
console.info("Starting stimulus load:", element.href);
|
|
134
|
+
try {
|
|
135
|
+
await this._loadStimulusRef(element, item);
|
|
136
|
+
this._loadedStimulusHrefs.add(element.href);
|
|
137
|
+
this._loadingState.loadedStimulus++;
|
|
138
|
+
console.info("Stimulus loaded successfully:", element.href);
|
|
139
|
+
this._checkLoadingComplete();
|
|
140
|
+
} catch (error) {
|
|
141
|
+
if (error.name !== "AbortError") {
|
|
142
|
+
console.warn(`Failed to load stimulus ${element.identifier}:`, error);
|
|
133
143
|
}
|
|
144
|
+
this._loadingState.loadedStimulus++;
|
|
145
|
+
this._checkLoadingComplete();
|
|
146
|
+
} finally {
|
|
147
|
+
this._loadingStimulusHrefs.delete(element.href);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
// ===========================================
|
|
151
|
+
// NAVIGATION FLOW
|
|
152
|
+
// ===========================================
|
|
153
|
+
_getDefaultNavigationId(type) {
|
|
154
|
+
if (type === "section") {
|
|
155
|
+
return this._testElement?.querySelector("qti-assessment-section")?.identifier;
|
|
156
|
+
}
|
|
157
|
+
return this.sessionContext?.navItemRefId ?? this._testElement?.querySelector("qti-assessment-item-ref")?.identifier;
|
|
158
|
+
}
|
|
159
|
+
_initializeNavigation() {
|
|
160
|
+
if (!this.navigate) return;
|
|
161
|
+
const id = this._getDefaultNavigationId(this.navigate);
|
|
162
|
+
if (id) {
|
|
163
|
+
this.navigateTo(this.navigate, id);
|
|
134
164
|
}
|
|
135
|
-
this.dispatchEvent(
|
|
136
|
-
new CustomEvent("qti-request-navigation", {
|
|
137
|
-
detail: { type, id },
|
|
138
|
-
bubbles: true,
|
|
139
|
-
composed: true
|
|
140
|
-
})
|
|
141
|
-
);
|
|
142
165
|
}
|
|
143
166
|
/**
|
|
144
|
-
*
|
|
167
|
+
* Main navigation request handler with proper lifecycle management
|
|
145
168
|
*/
|
|
146
|
-
async
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
);
|
|
150
|
-
if (!itemRefEl) {
|
|
151
|
-
throw {
|
|
152
|
-
type: "item-not-found" /* ITEM_NOT_FOUND */,
|
|
153
|
-
message: `Item with identifier "${itemId}" not found.`,
|
|
154
|
-
itemId
|
|
155
|
-
};
|
|
156
|
-
}
|
|
157
|
-
const navPartId = itemRefEl.closest("qti-test-part")?.identifier;
|
|
158
|
-
const navSectionId = itemRefEl.closest("qti-assessment-section")?.identifier;
|
|
159
|
-
this.sessionContext = {
|
|
160
|
-
...this.sessionContext,
|
|
161
|
-
navPartId,
|
|
162
|
-
navSectionId,
|
|
163
|
-
navItemRefId: itemId,
|
|
164
|
-
navItemLoading: true
|
|
165
|
-
};
|
|
169
|
+
async _handleNavigationRequest({ detail }) {
|
|
170
|
+
if (!detail?.id) return;
|
|
171
|
+
this._cancelPreviousNavigation();
|
|
166
172
|
try {
|
|
167
|
-
|
|
173
|
+
this._dispatchLoadingStarted(detail.type, detail.id);
|
|
174
|
+
this._activeController = new AbortController();
|
|
175
|
+
await this._executeNavigation(detail.type, detail.id);
|
|
176
|
+
} catch (error) {
|
|
177
|
+
this._handleNavigationError(error, detail.type, detail.id);
|
|
168
178
|
} finally {
|
|
169
|
-
this.
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
179
|
+
this._activeController = null;
|
|
180
|
+
this._dispatchLoadingEnded(detail.type, detail.id);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
_handleNavigationError(error, type, id) {
|
|
184
|
+
if (error.name !== "AbortError") {
|
|
185
|
+
this._dispatchError(this._createNavigationError(error, type, id));
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
async _executeNavigation(type, id) {
|
|
189
|
+
if (type === "item") {
|
|
190
|
+
await this._navigateToItem(id);
|
|
191
|
+
} else {
|
|
192
|
+
await this._navigateToSection(id);
|
|
173
193
|
}
|
|
174
194
|
}
|
|
175
195
|
/**
|
|
176
|
-
*
|
|
196
|
+
* Navigate to specific item with simple state tracking
|
|
197
|
+
*/
|
|
198
|
+
async _navigateToItem(itemId) {
|
|
199
|
+
const itemRef = this._findItemRef(itemId);
|
|
200
|
+
this._updateSessionContext(itemRef, itemId);
|
|
201
|
+
this._resetLoadingState();
|
|
202
|
+
this._loadingState.expectedItems = 1;
|
|
203
|
+
await this._loadItems([itemId]);
|
|
204
|
+
await this._waitForLoadingComplete();
|
|
205
|
+
this._dispatchTestLoaded(this._loadResults);
|
|
206
|
+
}
|
|
207
|
+
/**
|
|
208
|
+
* Navigate to section with simple state tracking
|
|
177
209
|
*/
|
|
178
210
|
async _navigateToSection(sectionId) {
|
|
179
|
-
const
|
|
180
|
-
|
|
181
|
-
);
|
|
182
|
-
if (!sectionRefEl) {
|
|
183
|
-
throw {
|
|
184
|
-
type: "section-not-found" /* SECTION_NOT_FOUND */,
|
|
185
|
-
message: `Section with identifier "${sectionId}" not found.`,
|
|
186
|
-
sectionId
|
|
187
|
-
};
|
|
188
|
-
}
|
|
189
|
-
const navPartId = sectionRefEl.closest("qti-test-part")?.identifier;
|
|
211
|
+
const sectionEl = this._findSection(sectionId);
|
|
212
|
+
const navPartId = sectionEl?.closest("qti-test-part")?.identifier;
|
|
190
213
|
this.sessionContext = {
|
|
191
214
|
...this.sessionContext,
|
|
192
215
|
navPartId,
|
|
193
216
|
navSectionId: sectionId,
|
|
194
|
-
navItemRefId: null
|
|
195
|
-
navItemLoading: true
|
|
217
|
+
navItemRefId: null
|
|
196
218
|
};
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
navItemLoading: false
|
|
204
|
-
};
|
|
205
|
-
}
|
|
219
|
+
const itemIds = this._getSectionItemIds(sectionId);
|
|
220
|
+
this._resetLoadingState();
|
|
221
|
+
this._loadingState.expectedItems = itemIds.length;
|
|
222
|
+
await this._loadItems(itemIds);
|
|
223
|
+
await this._waitForLoadingComplete();
|
|
224
|
+
this._dispatchTestLoaded(this._loadResults);
|
|
206
225
|
}
|
|
226
|
+
// ===========================================
|
|
227
|
+
// LOADING STATE MANAGEMENT
|
|
228
|
+
// ===========================================
|
|
207
229
|
/**
|
|
208
|
-
*
|
|
230
|
+
* Reset loading state for new navigation
|
|
209
231
|
*/
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
232
|
+
_resetLoadingState() {
|
|
233
|
+
this._loadingState = {
|
|
234
|
+
expectedItems: 0,
|
|
235
|
+
connectedItems: 0,
|
|
236
|
+
expectedStimulus: 0,
|
|
237
|
+
loadedStimulus: 0,
|
|
238
|
+
isComplete: false
|
|
239
|
+
};
|
|
240
|
+
this._loadedStimulusHrefs.clear();
|
|
241
|
+
this._loadingStimulusHrefs.clear();
|
|
242
|
+
}
|
|
243
|
+
/**
|
|
244
|
+
* Check if loading is complete and dispatch events accordingly
|
|
245
|
+
*/
|
|
246
|
+
_checkLoadingComplete() {
|
|
247
|
+
const allItemsConnected = this._loadingState.connectedItems >= this._loadingState.expectedItems;
|
|
248
|
+
const allStimulusLoaded = this._loadingState.loadedStimulus >= this._loadingState.expectedStimulus;
|
|
249
|
+
if (allItemsConnected && allStimulusLoaded && !this._loadingState.isComplete) {
|
|
250
|
+
this._loadingState.isComplete = true;
|
|
251
|
+
console.info("Loading complete:", this._loadingState);
|
|
227
252
|
}
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
253
|
+
}
|
|
254
|
+
/**
|
|
255
|
+
* Wait for loading to complete with simple polling
|
|
256
|
+
*/
|
|
257
|
+
async _waitForLoadingComplete() {
|
|
258
|
+
while (!this._loadingState.isComplete) {
|
|
259
|
+
await new Promise((resolve) => setTimeout(resolve, 10));
|
|
234
260
|
}
|
|
235
|
-
return {
|
|
236
|
-
type: "load-error" /* LOAD_ERROR */,
|
|
237
|
-
message: `Failed to load ${navigationType}: ${id}`,
|
|
238
|
-
details: error,
|
|
239
|
-
itemId: navigationType === "item" ? id : void 0,
|
|
240
|
-
sectionId: navigationType === "section" ? id : void 0
|
|
241
|
-
};
|
|
242
261
|
}
|
|
243
262
|
/**
|
|
244
|
-
*
|
|
263
|
+
* Get current loading progress for external consumption
|
|
245
264
|
*/
|
|
246
|
-
|
|
247
|
-
this.
|
|
248
|
-
new CustomEvent("qti-navigation-error", {
|
|
249
|
-
detail: error,
|
|
250
|
-
bubbles: true,
|
|
251
|
-
composed: true
|
|
252
|
-
})
|
|
253
|
-
);
|
|
265
|
+
getLoadingProgress() {
|
|
266
|
+
return { ...this._loadingState };
|
|
254
267
|
}
|
|
255
268
|
/**
|
|
256
|
-
*
|
|
269
|
+
* Load stimulus reference with simple tracking
|
|
257
270
|
*/
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
);
|
|
271
|
+
async _loadStimulusRef(element, item) {
|
|
272
|
+
console.info("Loading stimulus:", element.href);
|
|
273
|
+
const stimulus = await this._loadStimulus(element.href);
|
|
274
|
+
console.info("Stimulus loaded, applying content:", stimulus ? "has content" : "no content");
|
|
275
|
+
this._applyStimulusContent(stimulus, element, item);
|
|
276
|
+
}
|
|
277
|
+
_applyStimulusContent(stimulus, element, item) {
|
|
278
|
+
if (!stimulus) {
|
|
279
|
+
console.warn("No stimulus content to apply");
|
|
280
|
+
return;
|
|
281
|
+
}
|
|
282
|
+
const elements = stimulus.querySelectorAll("qti-stimulus-body, qti-stylesheet");
|
|
283
|
+
console.info(`Found ${elements.length} stimulus elements to apply for ${element.identifier}`);
|
|
284
|
+
if (elements.length === 0) {
|
|
285
|
+
console.warn("No qti-stimulus-body or qti-stylesheet elements found in stimulus");
|
|
286
|
+
return;
|
|
287
|
+
}
|
|
288
|
+
let targets = [];
|
|
289
|
+
const specificTarget = document.querySelector(
|
|
290
|
+
`qti-assessment-item[identifier="${item.identifier}"] [data-stimulus-idref="${element.identifier}"]`
|
|
291
|
+
);
|
|
292
|
+
if (specificTarget) {
|
|
293
|
+
targets.push(specificTarget);
|
|
294
|
+
console.info("Found specific target:", specificTarget);
|
|
295
|
+
} else {
|
|
296
|
+
const allTargetsWithId = Array.from(this.querySelectorAll(`[data-stimulus-idref="${element.identifier}"]`));
|
|
297
|
+
if (allTargetsWithId.length > 0) {
|
|
298
|
+
targets = allTargetsWithId;
|
|
299
|
+
console.info("Found targets by identifier:", allTargetsWithId.length);
|
|
300
|
+
} else {
|
|
301
|
+
const allStimulusTargets = Array.from(this.querySelectorAll("[data-stimulus-idref]"));
|
|
302
|
+
targets = allStimulusTargets;
|
|
303
|
+
console.info("Using fallback targets:", allStimulusTargets.length);
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
if (targets.length === 0) {
|
|
307
|
+
console.warn("No targets found for stimulus content");
|
|
308
|
+
return;
|
|
267
309
|
}
|
|
310
|
+
targets.forEach((target, index) => {
|
|
311
|
+
target.innerHTML = "";
|
|
312
|
+
const clonedElements = Array.from(elements).map((el) => el.cloneNode(true));
|
|
313
|
+
target.append(...clonedElements);
|
|
314
|
+
console.info(`Applied stimulus content to target ${index + 1}/${targets.length}`);
|
|
315
|
+
});
|
|
268
316
|
}
|
|
317
|
+
// ===========================================
|
|
318
|
+
// LOADING INFRASTRUCTURE
|
|
319
|
+
// ===========================================
|
|
269
320
|
/**
|
|
270
|
-
*
|
|
321
|
+
* Cancel previous navigation and clean up all state
|
|
271
322
|
*/
|
|
272
|
-
|
|
273
|
-
if (this.
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
if (request && request.readyState !== 4) {
|
|
277
|
-
request.abort();
|
|
278
|
-
}
|
|
279
|
-
});
|
|
280
|
-
this._activeRequests = [];
|
|
323
|
+
_cancelPreviousNavigation() {
|
|
324
|
+
if (this._activeController) {
|
|
325
|
+
this._activeController.abort();
|
|
326
|
+
console.info("Previous navigation request cancelled");
|
|
281
327
|
}
|
|
328
|
+
this._clearNavigationState();
|
|
329
|
+
}
|
|
330
|
+
_clearNavigationState() {
|
|
331
|
+
this._clearLoadedItems();
|
|
332
|
+
this._resetLoadingState();
|
|
333
|
+
this._loadResults = [];
|
|
282
334
|
}
|
|
283
335
|
/**
|
|
284
|
-
* Load items with
|
|
336
|
+
* Load items with simple tracking
|
|
285
337
|
*/
|
|
286
338
|
async _loadItems(itemIds) {
|
|
287
339
|
if (!this._testElement || itemIds.length === 0) return;
|
|
288
|
-
const
|
|
289
|
-
(id) => this._testElement.querySelector(`qti-assessment-item-ref[identifier="${id}"]`)
|
|
290
|
-
);
|
|
291
|
-
const missingItems = itemRefEls.reduce((missing, el, index) => {
|
|
292
|
-
if (!el) missing.push(itemIds[index]);
|
|
293
|
-
return missing;
|
|
294
|
-
}, []);
|
|
295
|
-
if (missingItems.length > 0) {
|
|
296
|
-
const error = {
|
|
297
|
-
type: "item-not-found" /* ITEM_NOT_FOUND */,
|
|
298
|
-
message: `One or more items not found: ${missingItems.join(", ")}`,
|
|
299
|
-
details: { missingItems }
|
|
300
|
-
};
|
|
301
|
-
throw error;
|
|
302
|
-
}
|
|
340
|
+
const itemRefs = itemIds.map((id) => this._findItemRef(id));
|
|
303
341
|
this._clearLoadedItems();
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
name: "TimeoutError",
|
|
310
|
-
message: `Request for item ${itemRef.identifier} timed out after ${this.requestTimeout}ms`
|
|
311
|
-
});
|
|
312
|
-
}, this.requestTimeout);
|
|
313
|
-
});
|
|
314
|
-
try {
|
|
315
|
-
const { promise, request } = qtiTransformItem(this.cacheTransform).load(itemRef.href);
|
|
316
|
-
if (request instanceof XMLHttpRequest) {
|
|
317
|
-
this._activeRequests.push(request);
|
|
318
|
-
}
|
|
319
|
-
const loadedTransformer = await Promise.race([promise, timeoutPromise]);
|
|
320
|
-
let finalTransformer = loadedTransformer;
|
|
321
|
-
if (this.postLoadTransformCallback) {
|
|
322
|
-
finalTransformer = await this.postLoadTransformCallback(loadedTransformer, itemRef);
|
|
323
|
-
}
|
|
324
|
-
return {
|
|
325
|
-
itemRef,
|
|
326
|
-
doc: finalTransformer.htmlDoc(),
|
|
327
|
-
request
|
|
328
|
-
};
|
|
329
|
-
} catch (error) {
|
|
330
|
-
if (error instanceof DOMException && error.name === "AbortError" || error && error.name === "TimeoutError") {
|
|
331
|
-
console.log(
|
|
332
|
-
`Request for item ${itemRef.identifier} was ${error.name === "TimeoutError" ? "timed out" : "aborted"}`
|
|
333
|
-
);
|
|
334
|
-
return null;
|
|
335
|
-
}
|
|
336
|
-
error.itemId = itemRef.identifier;
|
|
337
|
-
throw error;
|
|
338
|
-
}
|
|
342
|
+
this._clearStimulusRef();
|
|
343
|
+
const results = await Promise.all(itemRefs.map((ref) => this._loadSingleItem(ref)));
|
|
344
|
+
const validResults = results.filter(Boolean);
|
|
345
|
+
validResults.forEach(({ itemRef, doc }) => {
|
|
346
|
+
if (itemRef && doc) itemRef.xmlDoc = doc;
|
|
339
347
|
});
|
|
348
|
+
this._loadResults = validResults;
|
|
349
|
+
}
|
|
350
|
+
async _loadSingleItem(itemRef) {
|
|
340
351
|
try {
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
requestAnimationFrame(() => {
|
|
348
|
-
this.dispatchEvent(
|
|
349
|
-
new CustomEvent("qti-test-loaded", {
|
|
350
|
-
detail: validResults.map(({ itemRef }) => ({
|
|
351
|
-
identifier: itemRef?.identifier,
|
|
352
|
-
element: itemRef
|
|
353
|
-
})),
|
|
354
|
-
bubbles: true,
|
|
355
|
-
composed: true
|
|
356
|
-
})
|
|
357
|
-
);
|
|
358
|
-
});
|
|
359
|
-
if (validResults.length === 0 && itemIds.length > 0) {
|
|
360
|
-
throw {
|
|
361
|
-
type: "load-error" /* LOAD_ERROR */,
|
|
362
|
-
message: "All item requests failed to load",
|
|
363
|
-
details: { itemIds }
|
|
364
|
-
};
|
|
352
|
+
let transformer = await qtiTransformItem(this.cacheTransform).load(
|
|
353
|
+
itemRef.href,
|
|
354
|
+
this._activeController?.signal
|
|
355
|
+
);
|
|
356
|
+
if (this.postLoadTransformCallback) {
|
|
357
|
+
transformer = await this.postLoadTransformCallback(transformer, itemRef);
|
|
365
358
|
}
|
|
366
|
-
return
|
|
359
|
+
return { itemRef, doc: transformer.htmlDoc() };
|
|
367
360
|
} catch (error) {
|
|
368
|
-
|
|
369
|
-
|
|
361
|
+
if (error.name === "AbortError") {
|
|
362
|
+
console.info(`Item load for ${itemRef.identifier} was aborted`);
|
|
363
|
+
throw error;
|
|
364
|
+
}
|
|
365
|
+
console.warn(`Failed to load item ${itemRef.identifier}:`, error);
|
|
366
|
+
return null;
|
|
370
367
|
}
|
|
371
368
|
}
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
369
|
+
async _loadStimulus(href) {
|
|
370
|
+
const transformer = await qtiTransformItem().load(href, this._activeController?.signal);
|
|
371
|
+
return transformer.htmlDoc();
|
|
372
|
+
}
|
|
373
|
+
// ===========================================
|
|
374
|
+
// UTILITIES
|
|
375
|
+
// ===========================================
|
|
376
|
+
_findItemRef(itemId) {
|
|
377
|
+
const itemRef = this._testElement?.querySelector(
|
|
378
|
+
`qti-assessment-item-ref[identifier="${itemId}"]`
|
|
378
379
|
);
|
|
379
|
-
if (!
|
|
380
|
-
throw {
|
|
381
|
-
type: "section-not-found" /* SECTION_NOT_FOUND */,
|
|
382
|
-
message: `Section with identifier "${navSectionId}" not found.`,
|
|
383
|
-
sectionId: navSectionId
|
|
384
|
-
};
|
|
380
|
+
if (!itemRef) {
|
|
381
|
+
throw new Error(`Item with identifier "${itemId}" not found`);
|
|
385
382
|
}
|
|
383
|
+
return itemRef;
|
|
384
|
+
}
|
|
385
|
+
_findSection(sectionId) {
|
|
386
|
+
return this._testElement?.querySelector(`qti-assessment-section[identifier="${sectionId}"]`) || null;
|
|
387
|
+
}
|
|
388
|
+
_updateSessionContext(itemRef, itemId) {
|
|
389
|
+
const navPartId = itemRef.closest("qti-test-part")?.identifier;
|
|
390
|
+
const navSectionId = itemRef.closest("qti-assessment-section")?.identifier;
|
|
391
|
+
this.sessionContext = {
|
|
392
|
+
...this.sessionContext,
|
|
393
|
+
navPartId,
|
|
394
|
+
navSectionId,
|
|
395
|
+
navItemRefId: itemId
|
|
396
|
+
};
|
|
397
|
+
}
|
|
398
|
+
_getSectionItemIds(sectionId) {
|
|
386
399
|
return Array.from(
|
|
387
400
|
this._testElement.querySelectorAll(
|
|
388
|
-
`qti-assessment-section[identifier="${
|
|
401
|
+
`qti-assessment-section[identifier="${sectionId}"] > qti-assessment-item-ref`
|
|
389
402
|
)
|
|
390
|
-
).map((
|
|
403
|
+
).map((ref) => ref.identifier).filter(Boolean);
|
|
391
404
|
}
|
|
392
|
-
/**
|
|
393
|
-
* Clears all loaded items
|
|
394
|
-
*/
|
|
395
405
|
_clearLoadedItems() {
|
|
396
|
-
const
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
Array.from(itemRefEls || []).forEach((itemElement) => {
|
|
400
|
-
itemElement.xmlDoc = null;
|
|
406
|
+
const itemRefs = this._testElement?.querySelectorAll("qti-assessment-item-ref");
|
|
407
|
+
Array.from(itemRefs || []).forEach((element) => {
|
|
408
|
+
element.xmlDoc = null;
|
|
401
409
|
});
|
|
402
410
|
}
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
411
|
+
_clearStimulusRef() {
|
|
412
|
+
this.querySelectorAll("[data-stimulus-idref]").forEach((el) => el.innerHTML = "");
|
|
413
|
+
}
|
|
414
|
+
_createNavigationError(error, type, id) {
|
|
415
|
+
return {
|
|
416
|
+
message: error.message || `Failed to load ${type}: ${id}`,
|
|
417
|
+
details: error,
|
|
418
|
+
itemId: type === "item" ? id : void 0,
|
|
419
|
+
sectionId: type === "section" ? id : void 0
|
|
420
|
+
};
|
|
421
|
+
}
|
|
422
|
+
// ===========================================
|
|
423
|
+
// EVENT DISPATCHING
|
|
424
|
+
// ===========================================
|
|
425
|
+
_dispatchLoadingStarted(type, id) {
|
|
426
|
+
this.dispatchEvent(
|
|
427
|
+
new CustomEvent("qti-navigation-loading-started", {
|
|
428
|
+
detail: { type, id },
|
|
429
|
+
bubbles: true,
|
|
430
|
+
composed: true
|
|
431
|
+
})
|
|
432
|
+
);
|
|
433
|
+
}
|
|
434
|
+
_dispatchLoadingEnded(type, id) {
|
|
435
|
+
this.dispatchEvent(
|
|
436
|
+
new CustomEvent("qti-navigation-loading-ended", {
|
|
437
|
+
detail: { type, id },
|
|
438
|
+
bubbles: true,
|
|
439
|
+
composed: true
|
|
440
|
+
})
|
|
441
|
+
);
|
|
442
|
+
}
|
|
443
|
+
_dispatchError(error) {
|
|
444
|
+
this.dispatchEvent(
|
|
445
|
+
new CustomEvent("qti-navigation-error", {
|
|
446
|
+
detail: error,
|
|
447
|
+
bubbles: true,
|
|
448
|
+
composed: true
|
|
449
|
+
})
|
|
450
|
+
);
|
|
451
|
+
}
|
|
452
|
+
_dispatchTestLoaded(results) {
|
|
453
|
+
requestAnimationFrame(() => {
|
|
420
454
|
this.dispatchEvent(
|
|
421
|
-
new CustomEvent("qti-
|
|
422
|
-
detail:
|
|
455
|
+
new CustomEvent("qti-test-loaded", {
|
|
456
|
+
detail: results.map(({ itemRef }) => ({
|
|
457
|
+
identifier: itemRef?.identifier,
|
|
458
|
+
element: itemRef
|
|
459
|
+
})),
|
|
423
460
|
bubbles: true,
|
|
424
461
|
composed: true
|
|
425
462
|
})
|
|
426
463
|
);
|
|
427
|
-
}
|
|
464
|
+
});
|
|
428
465
|
}
|
|
429
466
|
}
|
|
430
467
|
__decorateClass([
|
|
@@ -437,18 +474,10 @@ var TestNavigationMixin = (superClass) => {
|
|
|
437
474
|
property({ type: Number })
|
|
438
475
|
], TestNavigationClass.prototype, "requestTimeout", 2);
|
|
439
476
|
__decorateClass([
|
|
440
|
-
property({
|
|
441
|
-
], TestNavigationClass.prototype, "showLoadingIndicators", 2);
|
|
442
|
-
__decorateClass([
|
|
443
|
-
property({ type: Function })
|
|
477
|
+
property({ attribute: false })
|
|
444
478
|
], TestNavigationClass.prototype, "postLoadTransformCallback", 2);
|
|
445
479
|
__decorateClass([
|
|
446
|
-
property({
|
|
447
|
-
type: Function,
|
|
448
|
-
hasChanged: (newVal, oldVal) => {
|
|
449
|
-
return newVal !== oldVal;
|
|
450
|
-
}
|
|
451
|
-
})
|
|
480
|
+
property({ attribute: false })
|
|
452
481
|
], TestNavigationClass.prototype, "postLoadTestTransformCallback", 2);
|
|
453
482
|
return TestNavigationClass;
|
|
454
483
|
};
|
|
@@ -704,7 +733,6 @@ QtiTest = __decorateClass([
|
|
|
704
733
|
// src/lib/qti-test/core/qti-assessment-test/qti-assessment-item-ref.ts
|
|
705
734
|
import { LitElement as LitElement2 } from "lit";
|
|
706
735
|
import { property as property3 } from "lit/decorators.js";
|
|
707
|
-
import { prepareTemplate } from "@heximal/templates";
|
|
708
736
|
var stringToBooleanConverter = {
|
|
709
737
|
fromAttribute(value) {
|
|
710
738
|
return value === "true";
|
|
@@ -729,8 +757,6 @@ var QtiAssessmentItemRef = class extends LitElement2 {
|
|
|
729
757
|
}
|
|
730
758
|
async connectedCallback() {
|
|
731
759
|
super.connectedCallback();
|
|
732
|
-
const templateElement = this.getRootNode().host.closest("qti-test").querySelector("template[item-ref]");
|
|
733
|
-
if (templateElement) this.myTemplate = prepareTemplate(templateElement);
|
|
734
760
|
await this.updateComplete;
|
|
735
761
|
this.dispatchEvent(
|
|
736
762
|
new CustomEvent("qti-assessment-item-ref-connected", {
|
|
@@ -1667,7 +1693,7 @@ TestShowCorrectResponse = __decorateClass([
|
|
|
1667
1693
|
// src/lib/qti-test/components/test-paging-buttons-stamp.ts
|
|
1668
1694
|
import { html as html13, LitElement as LitElement13 } from "lit";
|
|
1669
1695
|
import { customElement as customElement12 } from "lit/decorators.js";
|
|
1670
|
-
import { prepareTemplate
|
|
1696
|
+
import { prepareTemplate } from "@heximal/templates";
|
|
1671
1697
|
import { consume as consume8 } from "@lit/context";
|
|
1672
1698
|
var TestPagingButtonsStamp = class extends LitElement13 {
|
|
1673
1699
|
createRenderRoot() {
|
|
@@ -1681,7 +1707,7 @@ var TestPagingButtonsStamp = class extends LitElement13 {
|
|
|
1681
1707
|
connectedCallback() {
|
|
1682
1708
|
super.connectedCallback();
|
|
1683
1709
|
const templateElement = this.querySelector("template");
|
|
1684
|
-
this.myTemplate =
|
|
1710
|
+
this.myTemplate = prepareTemplate(templateElement);
|
|
1685
1711
|
}
|
|
1686
1712
|
render() {
|
|
1687
1713
|
if (!this.computedContext) return html13``;
|
|
@@ -1716,7 +1742,7 @@ var TestContainer = class extends LitElement14 {
|
|
|
1716
1742
|
try {
|
|
1717
1743
|
let api = await qtiTransformTest().load(this.testURL);
|
|
1718
1744
|
const qtiTest = this.closest("qti-test");
|
|
1719
|
-
if (qtiTest
|
|
1745
|
+
if (qtiTest?.postLoadTestTransformCallback) {
|
|
1720
1746
|
const tempDoc = api.htmlDoc();
|
|
1721
1747
|
const testElement = tempDoc.querySelector("qti-assessment-test");
|
|
1722
1748
|
if (testElement) {
|
|
@@ -1860,7 +1886,7 @@ TestPrintVariables = __decorateClass([
|
|
|
1860
1886
|
// src/lib/qti-test/components/test-section-buttons-stamp.ts
|
|
1861
1887
|
import { html as html16, LitElement as LitElement16 } from "lit";
|
|
1862
1888
|
import { customElement as customElement15 } from "lit/decorators.js";
|
|
1863
|
-
import { prepareTemplate as
|
|
1889
|
+
import { prepareTemplate as prepareTemplate2 } from "@heximal/templates";
|
|
1864
1890
|
import { consume as consume10 } from "@lit/context";
|
|
1865
1891
|
var TestSectionButtonsStamp = class extends LitElement16 {
|
|
1866
1892
|
createRenderRoot() {
|
|
@@ -1874,7 +1900,7 @@ var TestSectionButtonsStamp = class extends LitElement16 {
|
|
|
1874
1900
|
connectedCallback() {
|
|
1875
1901
|
super.connectedCallback();
|
|
1876
1902
|
const templateElement = this.querySelector("template");
|
|
1877
|
-
this.myTemplate =
|
|
1903
|
+
this.myTemplate = prepareTemplate2(templateElement);
|
|
1878
1904
|
}
|
|
1879
1905
|
render() {
|
|
1880
1906
|
if (!this.computedContext) return html16``;
|
|
@@ -1949,7 +1975,7 @@ TestPrintContext = __decorateClass([
|
|
|
1949
1975
|
// src/lib/qti-test/components/test-stamp.ts
|
|
1950
1976
|
import { html as html19, LitElement as LitElement19, nothing } from "lit";
|
|
1951
1977
|
import { customElement as customElement18, property as property15, state as state5 } from "lit/decorators.js";
|
|
1952
|
-
import { prepareTemplate as
|
|
1978
|
+
import { prepareTemplate as prepareTemplate3 } from "@heximal/templates";
|
|
1953
1979
|
import { consume as consume12 } from "@lit/context";
|
|
1954
1980
|
var TestStamp = class extends LitElement19 {
|
|
1955
1981
|
constructor() {
|
|
@@ -1978,7 +2004,7 @@ var TestStamp = class extends LitElement19 {
|
|
|
1978
2004
|
this.myTemplate = null;
|
|
1979
2005
|
return;
|
|
1980
2006
|
}
|
|
1981
|
-
this.myTemplate =
|
|
2007
|
+
this.myTemplate = prepareTemplate3(templateElement);
|
|
1982
2008
|
}
|
|
1983
2009
|
willUpdate(_changedProperties) {
|
|
1984
2010
|
if (!this.computedContext) {
|
|
@@ -2038,7 +2064,7 @@ TestStamp = __decorateClass([
|
|
|
2038
2064
|
import { html as html20, LitElement as LitElement20, nothing as nothing2 } from "lit";
|
|
2039
2065
|
import { consume as consume13 } from "@lit/context";
|
|
2040
2066
|
import { customElement as customElement19, property as property16 } from "lit/decorators.js";
|
|
2041
|
-
import { prepareTemplate as
|
|
2067
|
+
import { prepareTemplate as prepareTemplate4 } from "@heximal/templates";
|
|
2042
2068
|
var TestScoringButtons = class extends LitElement20 {
|
|
2043
2069
|
constructor() {
|
|
2044
2070
|
super();
|
|
@@ -2063,7 +2089,7 @@ var TestScoringButtons = class extends LitElement20 {
|
|
|
2063
2089
|
this.myTemplate = null;
|
|
2064
2090
|
return;
|
|
2065
2091
|
}
|
|
2066
|
-
this.myTemplate =
|
|
2092
|
+
this.myTemplate = prepareTemplate4(templateElement);
|
|
2067
2093
|
}
|
|
2068
2094
|
_changeOutcomeScore(value) {
|
|
2069
2095
|
const testPart = this.computedContext?.testParts.find((testPart2) => testPart2.active);
|
|
@@ -2109,7 +2135,7 @@ TestScoringButtons = __decorateClass([
|
|
|
2109
2135
|
import { consume as consume14 } from "@lit/context";
|
|
2110
2136
|
import { html as html21, LitElement as LitElement21, nothing as nothing3 } from "lit";
|
|
2111
2137
|
import { customElement as customElement20 } from "lit/decorators.js";
|
|
2112
|
-
import { prepareTemplate as
|
|
2138
|
+
import { prepareTemplate as prepareTemplate5 } from "@heximal/templates";
|
|
2113
2139
|
var TestViewToggle = class extends LitElement21 {
|
|
2114
2140
|
createRenderRoot() {
|
|
2115
2141
|
return this;
|
|
@@ -2121,7 +2147,7 @@ var TestViewToggle = class extends LitElement21 {
|
|
|
2121
2147
|
this.myTemplate = null;
|
|
2122
2148
|
return;
|
|
2123
2149
|
}
|
|
2124
|
-
this.myTemplate =
|
|
2150
|
+
this.myTemplate = prepareTemplate5(templateElement);
|
|
2125
2151
|
}
|
|
2126
2152
|
_switchView(view) {
|
|
2127
2153
|
this.dispatchEvent(
|
|
@@ -2263,4 +2289,4 @@ export {
|
|
|
2263
2289
|
TestScoringFeedback,
|
|
2264
2290
|
TestCheckItem
|
|
2265
2291
|
};
|
|
2266
|
-
//# sourceMappingURL=chunk-
|
|
2292
|
+
//# sourceMappingURL=chunk-XEKFVRIO.js.map
|