@citolab/qti-components 7.17.0 → 7.17.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.
@@ -1,10 +1,10 @@
1
1
  import {
2
2
  QtiModalFeedback
3
- } from "./chunk-O4XIWHTF.js";
3
+ } from "./chunk-3IHVFNP6.js";
4
4
  import {
5
5
  item_default,
6
6
  m
7
- } from "./chunk-W4SQRNWO.js";
7
+ } from "./chunk-3PDF4K62.js";
8
8
  import {
9
9
  watch
10
10
  } from "./chunk-2ZEJ3RR5.js";
@@ -49,6 +49,7 @@ var TestNavigationMixin = (superClass) => {
49
49
  // Navigation state tracking
50
50
  this._activeController = null;
51
51
  this._loadResults = [];
52
+ this._navigationId = 0;
52
53
  // Simple loading progress tracking
53
54
  this._loadingState = {
54
55
  expectedItems: 0,
@@ -168,14 +169,18 @@ var TestNavigationMixin = (superClass) => {
168
169
  async _handleNavigationRequest({ detail }) {
169
170
  if (!detail?.id) return;
170
171
  this._cancelPreviousNavigation();
172
+ const navigationId = ++this._navigationId;
173
+ const controller = new AbortController();
171
174
  try {
172
175
  this._dispatchLoadingStarted(detail.type, detail.id);
173
- this._activeController = new AbortController();
174
- await this._executeNavigation(detail.type, detail.id);
176
+ this._activeController = controller;
177
+ await this._executeNavigation(detail.type, detail.id, navigationId, controller);
175
178
  } catch (error) {
176
179
  this._handleNavigationError(error, detail.type, detail.id);
177
180
  } finally {
178
- this._activeController = null;
181
+ if (this._activeController === controller) {
182
+ this._activeController = null;
183
+ }
179
184
  this._dispatchLoadingEnded(detail.type, detail.id);
180
185
  }
181
186
  }
@@ -184,29 +189,30 @@ var TestNavigationMixin = (superClass) => {
184
189
  this._dispatchError(this._createNavigationError(error, type, id));
185
190
  }
186
191
  }
187
- async _executeNavigation(type, id) {
192
+ async _executeNavigation(type, id, navigationId, controller) {
188
193
  if (type === "item") {
189
- await this._navigateToItem(id);
194
+ await this._navigateToItem(id, navigationId, controller);
190
195
  } else {
191
- await this._navigateToSection(id);
196
+ await this._navigateToSection(id, navigationId, controller);
192
197
  }
193
198
  }
194
199
  /**
195
200
  * Navigate to specific item with simple state tracking
196
201
  */
197
- async _navigateToItem(itemId) {
202
+ async _navigateToItem(itemId, navigationId, controller) {
198
203
  const itemRef = this._findItemRef(itemId);
199
204
  this._updateSessionContext(itemRef, itemId);
200
205
  this._resetLoadingState();
201
206
  this._loadingState.expectedItems = 1;
202
- await this._loadItems([itemId]);
203
- await this._waitForLoadingComplete();
207
+ await this._loadItems([itemId], navigationId, controller);
208
+ await this._waitForLoadingComplete(navigationId, controller);
209
+ if (this._isStaleNavigation(navigationId, controller)) return;
204
210
  this._dispatchTestLoaded(this._loadResults);
205
211
  }
206
212
  /**
207
213
  * Navigate to section with simple state tracking
208
214
  */
209
- async _navigateToSection(sectionId) {
215
+ async _navigateToSection(sectionId, navigationId, controller) {
210
216
  const sectionEl = this._findSection(sectionId);
211
217
  const navPartId = sectionEl?.closest("qti-test-part")?.identifier;
212
218
  this.sessionContext = {
@@ -218,8 +224,9 @@ var TestNavigationMixin = (superClass) => {
218
224
  const itemIds = this._getSectionItemIds(sectionId);
219
225
  this._resetLoadingState();
220
226
  this._loadingState.expectedItems = itemIds.length;
221
- await this._loadItems(itemIds);
222
- await this._waitForLoadingComplete();
227
+ await this._loadItems(itemIds, navigationId, controller);
228
+ await this._waitForLoadingComplete(navigationId, controller);
229
+ if (this._isStaleNavigation(navigationId, controller)) return;
223
230
  this._dispatchTestLoaded(this._loadResults);
224
231
  }
225
232
  // ===========================================
@@ -252,8 +259,9 @@ var TestNavigationMixin = (superClass) => {
252
259
  /**
253
260
  * Wait for loading to complete with simple polling
254
261
  */
255
- async _waitForLoadingComplete() {
262
+ async _waitForLoadingComplete(navigationId, controller) {
256
263
  while (!this._loadingState.isComplete) {
264
+ if (this._isStaleNavigation(navigationId, controller)) return;
257
265
  await new Promise((resolve) => setTimeout(resolve, 10));
258
266
  }
259
267
  }
@@ -333,27 +341,28 @@ var TestNavigationMixin = (superClass) => {
333
341
  /**
334
342
  * Load items with simple tracking
335
343
  */
336
- async _loadItems(itemIds) {
344
+ async _loadItems(itemIds, navigationId, controller) {
337
345
  if (!this._testElement || itemIds.length === 0) return;
338
346
  const itemRefs = itemIds.map((id) => this._findItemRef(id));
339
347
  this._clearLoadedItems();
340
348
  this._clearStimulusRef();
341
- const results = await Promise.all(itemRefs.map((ref) => this._loadSingleItem(ref)));
349
+ const results = await Promise.all(itemRefs.map((ref) => this._loadSingleItem(ref, navigationId, controller)));
342
350
  const validResults = results.filter(Boolean);
351
+ if (this._isStaleNavigation(navigationId, controller)) return;
343
352
  validResults.forEach(({ itemRef, doc }) => {
344
353
  if (itemRef && doc) itemRef.xmlDoc = doc;
345
354
  });
346
355
  this._loadResults = validResults;
347
356
  }
348
- async _loadSingleItem(itemRef) {
357
+ async _loadSingleItem(itemRef, navigationId, controller) {
349
358
  try {
350
- let transformer = await qtiTransformItem(this.cacheTransform).load(
351
- itemRef.href,
352
- this._activeController?.signal
353
- );
359
+ let transformer = await qtiTransformItem(this.cacheTransform).load(itemRef.href, controller.signal);
354
360
  if (this.postLoadTransformCallback) {
355
361
  transformer = await this.postLoadTransformCallback(transformer, itemRef);
356
362
  }
363
+ if (this._isStaleNavigation(navigationId, controller)) {
364
+ return null;
365
+ }
357
366
  return { itemRef, doc: transformer.htmlDoc() };
358
367
  } catch (error) {
359
368
  if (error.name === "AbortError") {
@@ -409,6 +418,9 @@ var TestNavigationMixin = (superClass) => {
409
418
  _clearStimulusRef() {
410
419
  this.querySelectorAll("[data-stimulus-idref]").forEach((el) => el.innerHTML = "");
411
420
  }
421
+ _isStaleNavigation(navigationId, controller) {
422
+ return controller.signal.aborted || navigationId !== this._navigationId;
423
+ }
412
424
  _createNavigationError(error, type, id) {
413
425
  return {
414
426
  message: error.message || `Failed to load ${type}: ${id}`,
@@ -3327,4 +3339,4 @@ lit-html/node/private-ssr-support.js:
3327
3339
  * SPDX-License-Identifier: BSD-3-Clause
3328
3340
  *)
3329
3341
  */
3330
- //# sourceMappingURL=chunk-352OTVTY.js.map
3342
+ //# sourceMappingURL=chunk-ERONHL4R.js.map