@angular/core 20.0.0-next.0 → 20.0.0-next.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/fesm2022/core.mjs +6448 -6198
- package/fesm2022/core.mjs.map +1 -1
- package/fesm2022/primitives/di.mjs +45 -0
- package/fesm2022/primitives/di.mjs.map +1 -0
- package/fesm2022/primitives/event-dispatch.mjs +2 -2
- package/fesm2022/primitives/signals.mjs +2 -2
- package/fesm2022/rxjs-interop.mjs +2 -2
- package/fesm2022/testing.mjs +280 -119
- package/fesm2022/testing.mjs.map +1 -1
- package/index.d.ts +138 -51
- package/package.json +11 -1
- package/primitives/di/index.d.ts +99 -0
- package/primitives/event-dispatch/index.d.ts +2 -2
- package/primitives/signals/index.d.ts +2 -2
- package/rxjs-interop/index.d.ts +2 -2
- package/schematics/bundles/{apply_import_manager-0959b78c.js → apply_import_manager-e2a7fe5b.js} +4 -4
- package/schematics/bundles/{checker-cf6f7980.js → checker-af521da6.js} +346 -234
- package/schematics/bundles/cleanup-unused-imports.js +8 -8
- package/schematics/bundles/{compiler_host-cc1379e9.js → compiler_host-5a29293c.js} +3 -3
- package/schematics/bundles/control-flow-migration.js +4 -4
- package/schematics/bundles/explicit-standalone-flag.js +6 -6
- package/schematics/bundles/{imports-31a38653.js → imports-047fbbc8.js} +2 -2
- package/schematics/bundles/{index-42d84d69.js → index-1bef3025.js} +5 -5
- package/schematics/bundles/{index-6675d6bc.js → index-ef1bffbb.js} +5 -5
- package/schematics/bundles/inject-migration.js +8 -8
- package/schematics/bundles/{leading_space-6e7a8ec6.js → leading_space-f8944434.js} +2 -2
- package/schematics/bundles/{migrate_ts_type_references-5089e4ef.js → migrate_ts_type_references-2a3e9e6b.js} +13 -15
- package/schematics/bundles/{ng_decorators-6878e227.js → ng_decorators-b0d8b324.js} +3 -3
- package/schematics/bundles/{nodes-ffdce442.js → nodes-7758dbf6.js} +2 -2
- package/schematics/bundles/output-migration.js +8 -8
- package/schematics/bundles/pending-tasks.js +6 -6
- package/schematics/bundles/{program-362689f0.js → program-a449f9bf.js} +14 -14
- package/schematics/bundles/{project_paths-7d2daa1e.js → project_paths-17dc204d.js} +4 -4
- package/schematics/bundles/{project_tsconfig_paths-6c9cde78.js → project_tsconfig_paths-b558633b.js} +2 -2
- package/schematics/bundles/{property_name-42030525.js → property_name-ac18447e.js} +2 -2
- package/schematics/bundles/provide-initializer.js +6 -6
- package/schematics/bundles/route-lazy-loading.js +6 -6
- package/schematics/bundles/self-closing-tags-migration.js +44 -28
- package/schematics/bundles/signal-input-migration.js +10 -10
- package/schematics/bundles/signal-queries-migration.js +10 -10
- package/schematics/bundles/signals.js +10 -10
- package/schematics/bundles/standalone-migration.js +10 -10
- package/testing/index.d.ts +25 -14
package/fesm2022/testing.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @license Angular v20.0.0-next.
|
|
3
|
-
* (c) 2010-
|
|
2
|
+
* @license Angular v20.0.0-next.1
|
|
3
|
+
* (c) 2010-2025 Google LLC. https://angular.io/
|
|
4
4
|
* License: MIT
|
|
5
5
|
*/
|
|
6
6
|
|
|
@@ -175,10 +175,10 @@ class TestBedApplicationErrorHandler {
|
|
|
175
175
|
throw e;
|
|
176
176
|
}
|
|
177
177
|
}
|
|
178
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.0-next.
|
|
179
|
-
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.0.0-next.
|
|
178
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.0-next.1", ngImport: i0, type: TestBedApplicationErrorHandler, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
179
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.0.0-next.1", ngImport: i0, type: TestBedApplicationErrorHandler });
|
|
180
180
|
}
|
|
181
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.0-next.
|
|
181
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.0-next.1", ngImport: i0, type: TestBedApplicationErrorHandler, decorators: [{
|
|
182
182
|
type: Injectable
|
|
183
183
|
}] });
|
|
184
184
|
|
|
@@ -2337,8 +2337,9 @@ class FakeNavigation {
|
|
|
2337
2337
|
currentEntryIndex = 0;
|
|
2338
2338
|
/**
|
|
2339
2339
|
* The current navigate event.
|
|
2340
|
+
* @internal
|
|
2340
2341
|
*/
|
|
2341
|
-
navigateEvent =
|
|
2342
|
+
navigateEvent = null;
|
|
2342
2343
|
/**
|
|
2343
2344
|
* A Map of pending traversals, so that traversals to the same entry can be
|
|
2344
2345
|
* re-used.
|
|
@@ -2361,7 +2362,10 @@ class FakeNavigation {
|
|
|
2361
2362
|
synchronousTraversals = false;
|
|
2362
2363
|
/** Whether to allow a call to setInitialEntryForTesting. */
|
|
2363
2364
|
canSetInitialEntry = true;
|
|
2364
|
-
/**
|
|
2365
|
+
/**
|
|
2366
|
+
* `EventTarget` to dispatch events.
|
|
2367
|
+
* @internal
|
|
2368
|
+
*/
|
|
2365
2369
|
eventTarget;
|
|
2366
2370
|
/** The next unique id for created entries. Replace recreates this id. */
|
|
2367
2371
|
nextId = 0;
|
|
@@ -2393,7 +2397,7 @@ class FakeNavigation {
|
|
|
2393
2397
|
throw new Error('setInitialEntryForTesting can only be called before any ' + 'navigation has occurred');
|
|
2394
2398
|
}
|
|
2395
2399
|
const currentInitialEntry = this.entriesArr[0];
|
|
2396
|
-
this.entriesArr[0] = new FakeNavigationHistoryEntry(new URL(url).toString(), {
|
|
2400
|
+
this.entriesArr[0] = new FakeNavigationHistoryEntry(this.window.document.createElement('div'), new URL(url).toString(), {
|
|
2397
2401
|
index: 0,
|
|
2398
2402
|
key: currentInitialEntry?.key ?? String(this.nextKey++),
|
|
2399
2403
|
id: currentInitialEntry?.id ?? String(this.nextId++),
|
|
@@ -2441,7 +2445,7 @@ class FakeNavigation {
|
|
|
2441
2445
|
sameDocument: hashChange,
|
|
2442
2446
|
historyState: null,
|
|
2443
2447
|
});
|
|
2444
|
-
const result = new InternalNavigationResult();
|
|
2448
|
+
const result = new InternalNavigationResult(this);
|
|
2445
2449
|
this.userAgentNavigate(destination, result, {
|
|
2446
2450
|
navigationType,
|
|
2447
2451
|
cancelable: true,
|
|
@@ -2473,7 +2477,7 @@ class FakeNavigation {
|
|
|
2473
2477
|
sameDocument: true,
|
|
2474
2478
|
historyState: data,
|
|
2475
2479
|
});
|
|
2476
|
-
const result = new InternalNavigationResult();
|
|
2480
|
+
const result = new InternalNavigationResult(this);
|
|
2477
2481
|
this.userAgentNavigate(destination, result, {
|
|
2478
2482
|
navigationType,
|
|
2479
2483
|
cancelable: true,
|
|
@@ -2481,7 +2485,6 @@ class FakeNavigation {
|
|
|
2481
2485
|
// Always false for pushState() or replaceState().
|
|
2482
2486
|
userInitiated: false,
|
|
2483
2487
|
hashChange,
|
|
2484
|
-
skipPopState: true,
|
|
2485
2488
|
});
|
|
2486
2489
|
}
|
|
2487
2490
|
/** Equivalent to `navigation.traverseTo()`. */
|
|
@@ -2523,11 +2526,11 @@ class FakeNavigation {
|
|
|
2523
2526
|
sameDocument: entry.sameDocument,
|
|
2524
2527
|
});
|
|
2525
2528
|
this.prospectiveEntryIndex = entry.index;
|
|
2526
|
-
const result = new InternalNavigationResult();
|
|
2529
|
+
const result = new InternalNavigationResult(this);
|
|
2527
2530
|
this.traversalQueue.set(entry.key, result);
|
|
2528
2531
|
this.runTraversal(() => {
|
|
2529
2532
|
this.traversalQueue.delete(entry.key);
|
|
2530
|
-
this.userAgentNavigate(destination, result, {
|
|
2533
|
+
const event = this.userAgentNavigate(destination, result, {
|
|
2531
2534
|
navigationType: 'traverse',
|
|
2532
2535
|
cancelable: true,
|
|
2533
2536
|
canIntercept: true,
|
|
@@ -2536,6 +2539,8 @@ class FakeNavigation {
|
|
|
2536
2539
|
hashChange,
|
|
2537
2540
|
info: options?.info,
|
|
2538
2541
|
});
|
|
2542
|
+
// Note this does not pay attention at all to the commit status of the event (and thus, does not support deferred commit for traversals)
|
|
2543
|
+
this.userAgentTraverse(event);
|
|
2539
2544
|
});
|
|
2540
2545
|
return {
|
|
2541
2546
|
committed: result.committed,
|
|
@@ -2604,8 +2609,8 @@ class FakeNavigation {
|
|
|
2604
2609
|
index: entry.index,
|
|
2605
2610
|
sameDocument: entry.sameDocument,
|
|
2606
2611
|
});
|
|
2607
|
-
const result = new InternalNavigationResult();
|
|
2608
|
-
this.userAgentNavigate(destination, result, {
|
|
2612
|
+
const result = new InternalNavigationResult(this);
|
|
2613
|
+
const event = this.userAgentNavigate(destination, result, {
|
|
2609
2614
|
navigationType: 'traverse',
|
|
2610
2615
|
cancelable: true,
|
|
2611
2616
|
canIntercept: true,
|
|
@@ -2613,6 +2618,8 @@ class FakeNavigation {
|
|
|
2613
2618
|
userInitiated: false,
|
|
2614
2619
|
hashChange,
|
|
2615
2620
|
});
|
|
2621
|
+
// Note this does not pay attention at all to the commit status of the event (and thus, does not support deferred commit for traversals)
|
|
2622
|
+
this.userAgentTraverse(event);
|
|
2616
2623
|
});
|
|
2617
2624
|
}
|
|
2618
2625
|
/** Runs a traversal synchronously or asynchronously */
|
|
@@ -2663,9 +2670,9 @@ class FakeNavigation {
|
|
|
2663
2670
|
this.canSetInitialEntry = false;
|
|
2664
2671
|
if (this.navigateEvent) {
|
|
2665
2672
|
this.navigateEvent.cancel(new DOMException('Navigation was aborted', 'AbortError'));
|
|
2666
|
-
this.navigateEvent =
|
|
2673
|
+
this.navigateEvent = null;
|
|
2667
2674
|
}
|
|
2668
|
-
|
|
2675
|
+
return dispatchNavigateEvent({
|
|
2669
2676
|
navigationType: options.navigationType,
|
|
2670
2677
|
cancelable: options.cancelable,
|
|
2671
2678
|
canIntercept: options.canIntercept,
|
|
@@ -2675,78 +2682,103 @@ class FakeNavigation {
|
|
|
2675
2682
|
destination,
|
|
2676
2683
|
info: options.info,
|
|
2677
2684
|
sameDocument: destination.sameDocument,
|
|
2678
|
-
skipPopState: options.skipPopState,
|
|
2679
2685
|
result,
|
|
2680
|
-
userAgentCommit: () => {
|
|
2681
|
-
this.userAgentCommit();
|
|
2682
|
-
},
|
|
2683
2686
|
});
|
|
2684
|
-
this.navigateEvent = navigateEvent;
|
|
2685
|
-
this.eventTarget.dispatchEvent(navigateEvent);
|
|
2686
|
-
navigateEvent.dispatchedNavigateEvent();
|
|
2687
|
-
if (navigateEvent.commitOption === 'immediate') {
|
|
2688
|
-
navigateEvent.commit(/* internal= */ true);
|
|
2689
|
-
}
|
|
2690
2687
|
}
|
|
2691
|
-
/**
|
|
2692
|
-
|
|
2693
|
-
|
|
2694
|
-
|
|
2695
|
-
|
|
2688
|
+
/**
|
|
2689
|
+
* Implementation to commit a navigation.
|
|
2690
|
+
* https://whatpr.org/html/10919/nav-history-apis.html#navigateevent-commit
|
|
2691
|
+
* @internal
|
|
2692
|
+
*/
|
|
2693
|
+
commitNavigateEvent(navigateEvent) {
|
|
2694
|
+
navigateEvent.interceptionState = 'committed';
|
|
2696
2695
|
const from = this.currentEntry;
|
|
2697
|
-
if (!
|
|
2696
|
+
if (!from) {
|
|
2697
|
+
throw new Error('cannot commit navigation when current entry is null');
|
|
2698
|
+
}
|
|
2699
|
+
if (!navigateEvent.sameDocument) {
|
|
2698
2700
|
const error = new Error('Cannot navigate to a non-same-document URL.');
|
|
2699
|
-
|
|
2701
|
+
navigateEvent.cancel(error);
|
|
2700
2702
|
throw error;
|
|
2701
2703
|
}
|
|
2702
|
-
|
|
2703
|
-
|
|
2704
|
-
this.
|
|
2705
|
-
navigationType: this.navigateEvent.navigationType,
|
|
2706
|
-
});
|
|
2704
|
+
// "If navigationType is "push" or "replace", then run the URL and history update steps given document and event's destination's URL, with serialiedData set to event's classic history API state and historyHandling set to navigationType."
|
|
2705
|
+
if (navigateEvent.navigationType === 'push' || navigateEvent.navigationType === 'replace') {
|
|
2706
|
+
this.urlAndHistoryUpdateSteps(navigateEvent);
|
|
2707
2707
|
}
|
|
2708
|
-
else if (
|
|
2709
|
-
this.
|
|
2708
|
+
else if (navigateEvent.navigationType === 'reload') {
|
|
2709
|
+
this.updateNavigationEntriesForSameDocumentNavigation(navigateEvent);
|
|
2710
2710
|
}
|
|
2711
|
-
|
|
2712
|
-
|
|
2713
|
-
from,
|
|
2714
|
-
navigationType: this.navigateEvent.navigationType,
|
|
2715
|
-
});
|
|
2716
|
-
this.eventTarget.dispatchEvent(currentEntryChangeEvent);
|
|
2717
|
-
if (!this.navigateEvent.skipPopState) {
|
|
2718
|
-
const popStateEvent = createPopStateEvent({
|
|
2719
|
-
state: this.navigateEvent.destination.getHistoryState(),
|
|
2720
|
-
});
|
|
2721
|
-
this.window.dispatchEvent(popStateEvent);
|
|
2711
|
+
else if (navigateEvent.navigationType === 'traverse') {
|
|
2712
|
+
// "If navigationType is "traverse", then this event firing is happening as part of the traversal process, and that process will take care of performing the appropriate session history entry updates."
|
|
2722
2713
|
}
|
|
2723
2714
|
}
|
|
2724
|
-
/**
|
|
2725
|
-
|
|
2726
|
-
|
|
2727
|
-
|
|
2728
|
-
|
|
2729
|
-
|
|
2730
|
-
|
|
2731
|
-
|
|
2732
|
-
|
|
2733
|
-
|
|
2734
|
-
|
|
2735
|
-
|
|
2736
|
-
|
|
2737
|
-
|
|
2738
|
-
|
|
2715
|
+
/**
|
|
2716
|
+
* Implementation for a push or replace navigation.
|
|
2717
|
+
* https://whatpr.org/html/10919/browsing-the-web.html#url-and-history-update-steps
|
|
2718
|
+
* https://whatpr.org/html/10919/nav-history-apis.html#update-the-navigation-api-entries-for-a-same-document-navigation
|
|
2719
|
+
*/
|
|
2720
|
+
urlAndHistoryUpdateSteps(navigateEvent) {
|
|
2721
|
+
this.updateNavigationEntriesForSameDocumentNavigation(navigateEvent);
|
|
2722
|
+
}
|
|
2723
|
+
/**
|
|
2724
|
+
* Implementation for a traverse navigation.
|
|
2725
|
+
*
|
|
2726
|
+
* https://whatpr.org/html/10919/browsing-the-web.html#apply-the-traverse-history-step
|
|
2727
|
+
* ...
|
|
2728
|
+
* > Let updateDocument be an algorithm step which performs update document for history step application given targetEntry's document, targetEntry, changingNavigableContinuation's update-only, scriptHistoryLength, scriptHistoryIndex, navigationType, entriesForNavigationAPI, and previousEntry.
|
|
2729
|
+
* > If targetEntry's document is equal to displayedDocument, then perform updateDocument.
|
|
2730
|
+
* https://whatpr.org/html/10919/browsing-the-web.html#update-document-for-history-step-application
|
|
2731
|
+
* which then goes to https://whatpr.org/html/10919/nav-history-apis.html#update-the-navigation-api-entries-for-a-same-document-navigation
|
|
2732
|
+
*/
|
|
2733
|
+
userAgentTraverse(navigateEvent) {
|
|
2734
|
+
this.updateNavigationEntriesForSameDocumentNavigation(navigateEvent);
|
|
2735
|
+
// Happens as part of "updating the document" steps https://whatpr.org/html/10919/browsing-the-web.html#updating-the-document
|
|
2736
|
+
const popStateEvent = createPopStateEvent({
|
|
2737
|
+
state: navigateEvent.destination.getHistoryState(),
|
|
2739
2738
|
});
|
|
2740
|
-
|
|
2741
|
-
|
|
2739
|
+
this.window.dispatchEvent(popStateEvent);
|
|
2740
|
+
// TODO(atscott): If oldURL's fragment is not equal to entry's URL's fragment, then queue a global task to fire an event named hashchange
|
|
2741
|
+
}
|
|
2742
|
+
/** https://whatpr.org/html/10919/nav-history-apis.html#update-the-navigation-api-entries-for-a-same-document-navigation */
|
|
2743
|
+
updateNavigationEntriesForSameDocumentNavigation({ destination, navigationType, result, }) {
|
|
2744
|
+
const oldCurrentNHE = this.currentEntry;
|
|
2745
|
+
const disposedNHEs = [];
|
|
2746
|
+
if (navigationType === 'traverse') {
|
|
2747
|
+
this.currentEntryIndex = destination.index;
|
|
2748
|
+
if (this.currentEntryIndex === -1) {
|
|
2749
|
+
throw new Error('unexpected current entry index');
|
|
2750
|
+
}
|
|
2742
2751
|
}
|
|
2743
|
-
else {
|
|
2744
|
-
this.
|
|
2752
|
+
else if (navigationType === 'push') {
|
|
2753
|
+
this.currentEntryIndex++;
|
|
2754
|
+
this.prospectiveEntryIndex = this.currentEntryIndex; // prospectiveEntryIndex isn't in the spec but is an implementation detail
|
|
2755
|
+
disposedNHEs.push(...this.entriesArr.splice(this.currentEntryIndex));
|
|
2756
|
+
}
|
|
2757
|
+
else if (navigationType === 'replace') {
|
|
2758
|
+
disposedNHEs.push(oldCurrentNHE);
|
|
2759
|
+
}
|
|
2760
|
+
if (navigationType === 'push' || navigationType === 'replace') {
|
|
2761
|
+
const index = this.currentEntryIndex;
|
|
2762
|
+
const key = navigationType === 'push' ? String(this.nextKey++) : this.currentEntry.key;
|
|
2763
|
+
const newNHE = new FakeNavigationHistoryEntry(this.window.document.createElement('div'), destination.url, {
|
|
2764
|
+
id: String(this.nextId++),
|
|
2765
|
+
key,
|
|
2766
|
+
index,
|
|
2767
|
+
sameDocument: true,
|
|
2768
|
+
state: destination.getState(),
|
|
2769
|
+
historyState: destination.getHistoryState(),
|
|
2770
|
+
});
|
|
2771
|
+
this.entriesArr[this.currentEntryIndex] = newNHE;
|
|
2772
|
+
}
|
|
2773
|
+
result.committedResolve(this.currentEntry);
|
|
2774
|
+
const currentEntryChangeEvent = createFakeNavigationCurrentEntryChangeEvent({
|
|
2775
|
+
from: oldCurrentNHE,
|
|
2776
|
+
navigationType: navigationType,
|
|
2777
|
+
});
|
|
2778
|
+
this.eventTarget.dispatchEvent(currentEntryChangeEvent);
|
|
2779
|
+
for (const disposedNHE of disposedNHEs) {
|
|
2780
|
+
disposedNHE.dispose();
|
|
2745
2781
|
}
|
|
2746
|
-
}
|
|
2747
|
-
/** Implementation for a traverse navigation. */
|
|
2748
|
-
userAgentTraverse(destination) {
|
|
2749
|
-
this.currentEntryIndex = destination.index;
|
|
2750
2782
|
}
|
|
2751
2783
|
/** Utility method for finding entries with the given `key`. */
|
|
2752
2784
|
findEntry(key) {
|
|
@@ -2789,8 +2821,13 @@ class FakeNavigation {
|
|
|
2789
2821
|
get onnavigateerror() {
|
|
2790
2822
|
throw new Error('unimplemented');
|
|
2791
2823
|
}
|
|
2824
|
+
_transition = null;
|
|
2825
|
+
/** @internal */
|
|
2826
|
+
set transition(t) {
|
|
2827
|
+
this._transition = t;
|
|
2828
|
+
}
|
|
2792
2829
|
get transition() {
|
|
2793
|
-
|
|
2830
|
+
return this._transition;
|
|
2794
2831
|
}
|
|
2795
2832
|
updateCurrentEntry(_options) {
|
|
2796
2833
|
throw new Error('unimplemented');
|
|
@@ -2803,6 +2840,7 @@ class FakeNavigation {
|
|
|
2803
2840
|
* Fake equivalent of `NavigationHistoryEntry`.
|
|
2804
2841
|
*/
|
|
2805
2842
|
class FakeNavigationHistoryEntry {
|
|
2843
|
+
eventTarget;
|
|
2806
2844
|
url;
|
|
2807
2845
|
sameDocument;
|
|
2808
2846
|
id;
|
|
@@ -2812,7 +2850,8 @@ class FakeNavigationHistoryEntry {
|
|
|
2812
2850
|
historyState;
|
|
2813
2851
|
// tslint:disable-next-line:no-any
|
|
2814
2852
|
ondispose = null;
|
|
2815
|
-
constructor(url, { id, key, index, sameDocument, state, historyState, }) {
|
|
2853
|
+
constructor(eventTarget, url, { id, key, index, sameDocument, state, historyState, }) {
|
|
2854
|
+
this.eventTarget = eventTarget;
|
|
2816
2855
|
this.url = url;
|
|
2817
2856
|
this.id = id;
|
|
2818
2857
|
this.key = key;
|
|
@@ -2832,21 +2871,34 @@ class FakeNavigationHistoryEntry {
|
|
|
2832
2871
|
: this.historyState;
|
|
2833
2872
|
}
|
|
2834
2873
|
addEventListener(type, callback, options) {
|
|
2835
|
-
|
|
2874
|
+
this.eventTarget.addEventListener(type, callback, options);
|
|
2836
2875
|
}
|
|
2837
2876
|
removeEventListener(type, callback, options) {
|
|
2838
|
-
|
|
2877
|
+
this.eventTarget.removeEventListener(type, callback, options);
|
|
2839
2878
|
}
|
|
2840
2879
|
dispatchEvent(event) {
|
|
2841
|
-
|
|
2880
|
+
return this.eventTarget.dispatchEvent(event);
|
|
2881
|
+
}
|
|
2882
|
+
/** internal */
|
|
2883
|
+
dispose() {
|
|
2884
|
+
const disposeEvent = new Event('disposed');
|
|
2885
|
+
this.dispatchEvent(disposeEvent);
|
|
2886
|
+
// release current listeners
|
|
2887
|
+
this.eventTarget = null;
|
|
2842
2888
|
}
|
|
2843
2889
|
}
|
|
2844
2890
|
/**
|
|
2845
2891
|
* Create a fake equivalent of `NavigateEvent`. This is not a class because ES5
|
|
2846
2892
|
* transpiled JavaScript cannot extend native Event.
|
|
2893
|
+
*
|
|
2894
|
+
* https://html.spec.whatwg.org/multipage/nav-history-apis.html#navigate-event-firing
|
|
2847
2895
|
*/
|
|
2848
|
-
function
|
|
2896
|
+
function dispatchNavigateEvent({ cancelable, canIntercept, userInitiated, hashChange, navigationType, signal, destination, info, sameDocument, result, }) {
|
|
2897
|
+
const { navigation } = result;
|
|
2849
2898
|
const event = new Event('navigate', { bubbles: false, cancelable });
|
|
2899
|
+
event.focusResetBehavior = null;
|
|
2900
|
+
event.scrollBehavior = null;
|
|
2901
|
+
event.interceptionState = 'none';
|
|
2850
2902
|
event.canIntercept = canIntercept;
|
|
2851
2903
|
event.userInitiated = userInitiated;
|
|
2852
2904
|
event.hashChange = hashChange;
|
|
@@ -2856,71 +2908,151 @@ function createFakeNavigateEvent({ cancelable, canIntercept, userInitiated, hash
|
|
|
2856
2908
|
event.info = info;
|
|
2857
2909
|
event.downloadRequest = null;
|
|
2858
2910
|
event.formData = null;
|
|
2911
|
+
event.result = result;
|
|
2859
2912
|
event.sameDocument = sameDocument;
|
|
2860
|
-
event.skipPopState = skipPopState;
|
|
2861
2913
|
event.commitOption = 'immediate';
|
|
2862
|
-
let
|
|
2863
|
-
let interceptCalled = false;
|
|
2914
|
+
let handlersFinished = [Promise.resolve()];
|
|
2864
2915
|
let dispatchedNavigateEvent = false;
|
|
2865
|
-
let commitCalled = false;
|
|
2866
2916
|
event.intercept = function (options) {
|
|
2867
|
-
|
|
2917
|
+
if (!this.canIntercept) {
|
|
2918
|
+
throw new DOMException(`Cannot intercept when canIntercept is 'false'`, 'SecurityError');
|
|
2919
|
+
}
|
|
2920
|
+
this.interceptionState = 'intercepted';
|
|
2868
2921
|
event.sameDocument = true;
|
|
2869
2922
|
const handler = options?.handler;
|
|
2870
2923
|
if (handler) {
|
|
2871
|
-
|
|
2872
|
-
}
|
|
2873
|
-
if (options?.commit) {
|
|
2874
|
-
event.commitOption = options.commit;
|
|
2924
|
+
handlersFinished.push(handler());
|
|
2875
2925
|
}
|
|
2876
|
-
//
|
|
2926
|
+
// override old options with new ones. UA _may_ report a console warning if new options differ from previous
|
|
2927
|
+
event.commitOption = options?.commit ?? event.commitOption;
|
|
2928
|
+
event.scrollBehavior = options?.scroll ?? event.scrollBehavior;
|
|
2929
|
+
event.focusResetBehavior = options?.focusReset ?? event.focusResetBehavior;
|
|
2877
2930
|
};
|
|
2878
2931
|
event.scroll = function () {
|
|
2879
|
-
|
|
2932
|
+
if (event.interceptionState !== 'committed') {
|
|
2933
|
+
throw new DOMException(`Failed to execute 'scroll' on 'NavigateEvent': scroll() must be ` +
|
|
2934
|
+
`called after commit() and interception options must specify manual scroll.`, 'InvalidStateError');
|
|
2935
|
+
}
|
|
2936
|
+
processScrollBehavior(event);
|
|
2880
2937
|
};
|
|
2881
2938
|
event.commit = function (internal = false) {
|
|
2882
|
-
if (!internal &&
|
|
2939
|
+
if (!internal && this.interceptionState !== 'intercepted') {
|
|
2883
2940
|
throw new DOMException(`Failed to execute 'commit' on 'NavigateEvent': intercept() must be ` +
|
|
2884
|
-
`called before commit().`, 'InvalidStateError');
|
|
2941
|
+
`called before commit() and commit() cannot be already called.`, 'InvalidStateError');
|
|
2942
|
+
}
|
|
2943
|
+
if (!internal && event.commitOption !== 'after-transition') {
|
|
2944
|
+
throw new DOMException(`Failed to execute 'commit' on 'NavigateEvent': commit() may not be ` +
|
|
2945
|
+
`called if commit behavior is not "after-transition",.`, 'InvalidStateError');
|
|
2885
2946
|
}
|
|
2886
2947
|
if (!dispatchedNavigateEvent) {
|
|
2887
2948
|
throw new DOMException(`Failed to execute 'commit' on 'NavigateEvent': commit() may not be ` +
|
|
2888
2949
|
`called during event dispatch.`, 'InvalidStateError');
|
|
2889
2950
|
}
|
|
2890
|
-
|
|
2891
|
-
|
|
2892
|
-
}
|
|
2893
|
-
commitCalled = true;
|
|
2894
|
-
userAgentCommit();
|
|
2951
|
+
this.interceptionState = 'committed';
|
|
2952
|
+
result.navigation.commitNavigateEvent(event);
|
|
2895
2953
|
};
|
|
2896
2954
|
// Internal only.
|
|
2897
2955
|
event.cancel = function (reason) {
|
|
2898
2956
|
result.committedReject(reason);
|
|
2899
2957
|
result.finishedReject(reason);
|
|
2900
2958
|
};
|
|
2901
|
-
|
|
2902
|
-
|
|
2959
|
+
function dispatch() {
|
|
2960
|
+
navigation.navigateEvent = event;
|
|
2961
|
+
navigation.eventTarget.dispatchEvent(event);
|
|
2903
2962
|
dispatchedNavigateEvent = true;
|
|
2904
|
-
if (event.
|
|
2905
|
-
|
|
2906
|
-
|
|
2907
|
-
|
|
2908
|
-
|
|
2909
|
-
}
|
|
2910
|
-
}, () => { });
|
|
2963
|
+
if (event.interceptionState !== 'none') {
|
|
2964
|
+
navigation.transition = new InternalNavigationTransition(navigation.currentEntry, navigationType);
|
|
2965
|
+
if (event.commitOption !== 'after-transition') {
|
|
2966
|
+
event.commit(/** internal */ true);
|
|
2967
|
+
}
|
|
2911
2968
|
}
|
|
2912
|
-
|
|
2913
|
-
|
|
2969
|
+
else {
|
|
2970
|
+
// In the spec, this isn't really part of the navigate API. Instead, the navigate event firing returns "true" to indicate
|
|
2971
|
+
// navigation steps should "continue" (https://whatpr.org/html/10919/browsing-the-web.html#beginning-navigation)
|
|
2972
|
+
event.commit(/** internal */ true);
|
|
2973
|
+
}
|
|
2974
|
+
Promise.all(handlersFinished).then(() => {
|
|
2975
|
+
// Follows steps outlined under "Wait for all of promisesList, with the following success steps:"
|
|
2976
|
+
// in the spec https://html.spec.whatwg.org/multipage/nav-history-apis.html#navigate-event-firing.
|
|
2977
|
+
if (result.signal.aborted) {
|
|
2978
|
+
return;
|
|
2979
|
+
}
|
|
2980
|
+
if (event !== navigation.navigateEvent) {
|
|
2981
|
+
throw new Error("Navigation's ongoing event not equal to resolved event");
|
|
2982
|
+
}
|
|
2983
|
+
navigation.navigateEvent = null;
|
|
2984
|
+
if (event.interceptionState === 'intercepted') {
|
|
2985
|
+
navigation.commitNavigateEvent(event);
|
|
2986
|
+
}
|
|
2987
|
+
finishNavigationEvent(event, true);
|
|
2988
|
+
const navigatesuccessEvent = new Event('navigatesuccess', { bubbles: false, cancelable });
|
|
2989
|
+
navigation.eventTarget.dispatchEvent(navigatesuccessEvent);
|
|
2990
|
+
result.finishedResolve();
|
|
2991
|
+
if (navigation.transition !== null) {
|
|
2992
|
+
navigation.transition.finishedResolve();
|
|
2993
|
+
}
|
|
2994
|
+
navigation.transition = null;
|
|
2914
2995
|
}, (reason) => {
|
|
2996
|
+
if (result.signal.aborted) {
|
|
2997
|
+
return;
|
|
2998
|
+
}
|
|
2999
|
+
if (event !== navigation.navigateEvent) {
|
|
3000
|
+
throw new Error("Navigation's ongoing event not equal to resolved event");
|
|
3001
|
+
}
|
|
3002
|
+
navigation.navigateEvent = null;
|
|
3003
|
+
event.interceptionState = 'rejected'; // TODO(atscott): this is not in the spec https://github.com/whatwg/html/issues/11087
|
|
3004
|
+
finishNavigationEvent(event, false);
|
|
3005
|
+
const navigateerrorEvent = new Event('navigateerror', { bubbles: false, cancelable });
|
|
3006
|
+
navigation.eventTarget.dispatchEvent(navigateerrorEvent);
|
|
2915
3007
|
result.finishedReject(reason);
|
|
3008
|
+
if (navigation.transition !== null) {
|
|
3009
|
+
navigation.transition.finishedResolve();
|
|
3010
|
+
}
|
|
3011
|
+
navigation.transition = null;
|
|
2916
3012
|
});
|
|
2917
|
-
}
|
|
2918
|
-
|
|
2919
|
-
event.userAgentNavigated = function (entry) {
|
|
2920
|
-
result.committedResolve(entry);
|
|
2921
|
-
};
|
|
3013
|
+
}
|
|
3014
|
+
dispatch();
|
|
2922
3015
|
return event;
|
|
2923
3016
|
}
|
|
3017
|
+
/** https://whatpr.org/html/10919/nav-history-apis.html#navigateevent-finish */
|
|
3018
|
+
function finishNavigationEvent(event, didFulfill) {
|
|
3019
|
+
if (event.interceptionState === 'intercepted' || event.interceptionState === 'finished') {
|
|
3020
|
+
throw new Error('Attempting to finish navigation event that was incomplete or already finished');
|
|
3021
|
+
}
|
|
3022
|
+
if (event.interceptionState === 'none') {
|
|
3023
|
+
return;
|
|
3024
|
+
}
|
|
3025
|
+
if (didFulfill) {
|
|
3026
|
+
// TODO(atscott): https://github.com/whatwg/html/issues/11087 focus reset is not guarded by didFulfill in the spec
|
|
3027
|
+
potentiallyResetFocus(event);
|
|
3028
|
+
potentiallyResetScroll(event);
|
|
3029
|
+
}
|
|
3030
|
+
event.interceptionState = 'finished';
|
|
3031
|
+
}
|
|
3032
|
+
/** https://whatpr.org/html/10919/nav-history-apis.html#potentially-reset-the-focus */
|
|
3033
|
+
function potentiallyResetFocus(event) {
|
|
3034
|
+
if (event.interceptionState !== 'committed' && event.interceptionState !== 'scrolled') {
|
|
3035
|
+
throw new Error('cannot reset focus if navigation event is not committed or scrolled');
|
|
3036
|
+
}
|
|
3037
|
+
// TODO(atscott): The rest of the steps
|
|
3038
|
+
}
|
|
3039
|
+
function potentiallyResetScroll(event) {
|
|
3040
|
+
if (event.interceptionState !== 'committed' && event.interceptionState !== 'scrolled') {
|
|
3041
|
+
throw new Error('cannot reset scroll if navigation event is not committed or scrolled');
|
|
3042
|
+
}
|
|
3043
|
+
if (event.interceptionState === 'scrolled' || event.scrollBehavior === 'manual') {
|
|
3044
|
+
return;
|
|
3045
|
+
}
|
|
3046
|
+
processScrollBehavior(event);
|
|
3047
|
+
}
|
|
3048
|
+
/* https://whatpr.org/html/10919/nav-history-apis.html#process-scroll-behavior */
|
|
3049
|
+
function processScrollBehavior(event) {
|
|
3050
|
+
if (event.interceptionState !== 'committed') {
|
|
3051
|
+
throw new Error('invalid event interception state when processing scroll behavior');
|
|
3052
|
+
}
|
|
3053
|
+
event.interceptionState = 'scrolled';
|
|
3054
|
+
// TODO(atscott): the rest of the steps
|
|
3055
|
+
}
|
|
2924
3056
|
/**
|
|
2925
3057
|
* Create a fake equivalent of `NavigationCurrentEntryChange`. This does not use
|
|
2926
3058
|
* a class because ES5 transpiled JavaScript cannot extend native Event.
|
|
@@ -2980,8 +3112,28 @@ function isHashChange(from, to) {
|
|
|
2980
3112
|
to.pathname === from.pathname &&
|
|
2981
3113
|
to.search === from.search);
|
|
2982
3114
|
}
|
|
2983
|
-
|
|
3115
|
+
class InternalNavigationTransition {
|
|
3116
|
+
from;
|
|
3117
|
+
navigationType;
|
|
3118
|
+
finished;
|
|
3119
|
+
finishedResolve;
|
|
3120
|
+
finishedReject;
|
|
3121
|
+
constructor(from, navigationType) {
|
|
3122
|
+
this.from = from;
|
|
3123
|
+
this.navigationType = navigationType;
|
|
3124
|
+
this.finished = new Promise((resolve, reject) => {
|
|
3125
|
+
this.finishedReject = reject;
|
|
3126
|
+
this.finishedResolve = resolve;
|
|
3127
|
+
});
|
|
3128
|
+
}
|
|
3129
|
+
}
|
|
3130
|
+
/**
|
|
3131
|
+
* Internal utility class for representing the result of a navigation.
|
|
3132
|
+
* Generally equivalent to the "apiMethodTracker" in the spec.
|
|
3133
|
+
*/
|
|
2984
3134
|
class InternalNavigationResult {
|
|
3135
|
+
navigation;
|
|
3136
|
+
committedTo = null;
|
|
2985
3137
|
committedResolve;
|
|
2986
3138
|
committedReject;
|
|
2987
3139
|
finishedResolve;
|
|
@@ -2992,13 +3144,22 @@ class InternalNavigationResult {
|
|
|
2992
3144
|
return this.abortController.signal;
|
|
2993
3145
|
}
|
|
2994
3146
|
abortController = new AbortController();
|
|
2995
|
-
constructor() {
|
|
3147
|
+
constructor(navigation) {
|
|
3148
|
+
this.navigation = navigation;
|
|
2996
3149
|
this.committed = new Promise((resolve, reject) => {
|
|
2997
|
-
this.committedResolve =
|
|
3150
|
+
this.committedResolve = (entry) => {
|
|
3151
|
+
this.committedTo = entry;
|
|
3152
|
+
resolve(entry);
|
|
3153
|
+
};
|
|
2998
3154
|
this.committedReject = reject;
|
|
2999
3155
|
});
|
|
3000
3156
|
this.finished = new Promise(async (resolve, reject) => {
|
|
3001
|
-
this.finishedResolve =
|
|
3157
|
+
this.finishedResolve = () => {
|
|
3158
|
+
if (this.committedTo === null) {
|
|
3159
|
+
throw new Error('NavigateEvent should have been committed before resolving finished promise.');
|
|
3160
|
+
}
|
|
3161
|
+
resolve(this.committedTo);
|
|
3162
|
+
};
|
|
3002
3163
|
this.finishedReject = (reason) => {
|
|
3003
3164
|
reject(reason);
|
|
3004
3165
|
this.abortController.abort(reason);
|