@angular/router 17.0.0-next.2 → 17.0.0-next.3
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/esm2022/src/apply_redirects.mjs +8 -3
- package/esm2022/src/components/empty_outlet.mjs +3 -3
- package/esm2022/src/directives/router_link.mjs +3 -3
- package/esm2022/src/directives/router_link_active.mjs +3 -3
- package/esm2022/src/directives/router_outlet.mjs +6 -6
- package/esm2022/src/navigation_transition.mjs +13 -9
- package/esm2022/src/operators/resolve_data.mjs +2 -5
- package/esm2022/src/page_title_strategy.mjs +6 -6
- package/esm2022/src/recognize.mjs +34 -50
- package/esm2022/src/route_reuse_strategy.mjs +6 -6
- package/esm2022/src/router.mjs +57 -226
- package/esm2022/src/router_config_loader.mjs +3 -3
- package/esm2022/src/router_module.mjs +4 -4
- package/esm2022/src/router_outlet_context.mjs +3 -3
- package/esm2022/src/router_preloader.mjs +9 -9
- package/esm2022/src/router_scroller.mjs +3 -3
- package/esm2022/src/state_manager.mjs +244 -0
- package/esm2022/src/url_handling_strategy.mjs +6 -6
- package/esm2022/src/url_tree.mjs +3 -3
- package/esm2022/src/utils/collection.mjs +9 -3
- package/esm2022/src/version.mjs +1 -1
- package/esm2022/testing/src/router_testing_harness.mjs +6 -6
- package/esm2022/testing/src/router_testing_module.mjs +4 -4
- package/fesm2022/router.mjs +421 -366
- package/fesm2022/router.mjs.map +1 -1
- package/fesm2022/testing.mjs +11 -11
- package/fesm2022/upgrade.mjs +1 -1
- package/index.d.ts +16 -63
- package/package.json +4 -4
- package/testing/index.d.ts +1 -1
- package/upgrade/index.d.ts +1 -1
package/fesm2022/router.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @license Angular v17.0.0-next.
|
|
2
|
+
* @license Angular v17.0.0-next.3
|
|
3
3
|
* (c) 2010-2022 Google LLC. https://angular.io/
|
|
4
4
|
* License: MIT
|
|
5
5
|
*/
|
|
@@ -114,8 +114,8 @@ function shallowEqualArrays(a, b) {
|
|
|
114
114
|
function shallowEqual(a, b) {
|
|
115
115
|
// While `undefined` should never be possible, it would sometimes be the case in IE 11
|
|
116
116
|
// and pre-chromium Edge. The check below accounts for this edge case.
|
|
117
|
-
const k1 = a ?
|
|
118
|
-
const k2 = b ?
|
|
117
|
+
const k1 = a ? getDataKeys(a) : undefined;
|
|
118
|
+
const k2 = b ? getDataKeys(b) : undefined;
|
|
119
119
|
if (!k1 || !k2 || k1.length != k2.length) {
|
|
120
120
|
return false;
|
|
121
121
|
}
|
|
@@ -128,6 +128,12 @@ function shallowEqual(a, b) {
|
|
|
128
128
|
}
|
|
129
129
|
return true;
|
|
130
130
|
}
|
|
131
|
+
/**
|
|
132
|
+
* Gets the keys of an object, including `symbol` keys.
|
|
133
|
+
*/
|
|
134
|
+
function getDataKeys(obj) {
|
|
135
|
+
return [...Object.keys(obj), ...Object.getOwnPropertySymbols(obj)];
|
|
136
|
+
}
|
|
131
137
|
/**
|
|
132
138
|
* Test equality for arrays of strings or a string.
|
|
133
139
|
*/
|
|
@@ -419,10 +425,10 @@ function mapChildrenIntoArray(segment, fn) {
|
|
|
419
425
|
* @publicApi
|
|
420
426
|
*/
|
|
421
427
|
class UrlSerializer {
|
|
422
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.0.0-next.
|
|
423
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.0.0-next.
|
|
428
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.0.0-next.3", ngImport: i0, type: UrlSerializer, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
429
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.0.0-next.3", ngImport: i0, type: UrlSerializer, providedIn: 'root', useFactory: () => new DefaultUrlSerializer() }); }
|
|
424
430
|
}
|
|
425
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.0.0-next.
|
|
431
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.0.0-next.3", ngImport: i0, type: UrlSerializer, decorators: [{
|
|
426
432
|
type: Injectable,
|
|
427
433
|
args: [{ providedIn: 'root', useFactory: () => new DefaultUrlSerializer() }]
|
|
428
434
|
}] });
|
|
@@ -1779,10 +1785,10 @@ class ChildrenOutletContexts {
|
|
|
1779
1785
|
getContext(childName) {
|
|
1780
1786
|
return this.contexts.get(childName) || null;
|
|
1781
1787
|
}
|
|
1782
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.0.0-next.
|
|
1783
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.0.0-next.
|
|
1788
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.0.0-next.3", ngImport: i0, type: ChildrenOutletContexts, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
1789
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.0.0-next.3", ngImport: i0, type: ChildrenOutletContexts, providedIn: 'root' }); }
|
|
1784
1790
|
}
|
|
1785
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.0.0-next.
|
|
1791
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.0.0-next.3", ngImport: i0, type: ChildrenOutletContexts, decorators: [{
|
|
1786
1792
|
type: Injectable,
|
|
1787
1793
|
args: [{ providedIn: 'root' }]
|
|
1788
1794
|
}] });
|
|
@@ -2489,10 +2495,10 @@ class RouterOutlet {
|
|
|
2489
2495
|
this.inputBinder?.bindActivatedRouteToOutletComponent(this);
|
|
2490
2496
|
this.activateEvents.emit(this.activated.instance);
|
|
2491
2497
|
}
|
|
2492
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.0.0-next.
|
|
2493
|
-
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "17.0.0-next.
|
|
2498
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.0.0-next.3", ngImport: i0, type: RouterOutlet, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
2499
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "17.0.0-next.3", type: RouterOutlet, isStandalone: true, selector: "router-outlet", inputs: { name: "name" }, outputs: { activateEvents: "activate", deactivateEvents: "deactivate", attachEvents: "attach", detachEvents: "detach" }, exportAs: ["outlet"], usesOnChanges: true, ngImport: i0 }); }
|
|
2494
2500
|
}
|
|
2495
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.0.0-next.
|
|
2501
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.0.0-next.3", ngImport: i0, type: RouterOutlet, decorators: [{
|
|
2496
2502
|
type: Directive,
|
|
2497
2503
|
args: [{
|
|
2498
2504
|
selector: 'router-outlet',
|
|
@@ -2595,10 +2601,10 @@ class RoutedComponentInputBinder {
|
|
|
2595
2601
|
});
|
|
2596
2602
|
this.outletDataSubscriptions.set(outlet, dataSubscription);
|
|
2597
2603
|
}
|
|
2598
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.0.0-next.
|
|
2599
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.0.0-next.
|
|
2604
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.0.0-next.3", ngImport: i0, type: RoutedComponentInputBinder, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
2605
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.0.0-next.3", ngImport: i0, type: RoutedComponentInputBinder }); }
|
|
2600
2606
|
}
|
|
2601
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.0.0-next.
|
|
2607
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.0.0-next.3", ngImport: i0, type: RoutedComponentInputBinder, decorators: [{
|
|
2602
2608
|
type: Injectable
|
|
2603
2609
|
}] });
|
|
2604
2610
|
|
|
@@ -2678,10 +2684,10 @@ function isNavigationCancelingError$1(error) {
|
|
|
2678
2684
|
* to this `EmptyOutletComponent`.
|
|
2679
2685
|
*/
|
|
2680
2686
|
class ɵEmptyOutletComponent {
|
|
2681
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.0.0-next.
|
|
2682
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.0.0-next.
|
|
2687
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.0.0-next.3", ngImport: i0, type: ɵEmptyOutletComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
2688
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.0.0-next.3", type: ɵEmptyOutletComponent, isStandalone: true, selector: "ng-component", ngImport: i0, template: `<router-outlet></router-outlet>`, isInline: true, dependencies: [{ kind: "directive", type: RouterOutlet, selector: "router-outlet", inputs: ["name"], outputs: ["activate", "deactivate", "attach", "detach"], exportAs: ["outlet"] }] }); }
|
|
2683
2689
|
}
|
|
2684
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.0.0-next.
|
|
2690
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.0.0-next.3", ngImport: i0, type: ɵEmptyOutletComponent, decorators: [{
|
|
2685
2691
|
type: Component,
|
|
2686
2692
|
args: [{
|
|
2687
2693
|
template: `<router-outlet></router-outlet>`,
|
|
@@ -3419,8 +3425,9 @@ class NoMatch {
|
|
|
3419
3425
|
this.segmentGroup = segmentGroup || null;
|
|
3420
3426
|
}
|
|
3421
3427
|
}
|
|
3422
|
-
class AbsoluteRedirect {
|
|
3428
|
+
class AbsoluteRedirect extends Error {
|
|
3423
3429
|
constructor(urlTree) {
|
|
3430
|
+
super();
|
|
3424
3431
|
this.urlTree = urlTree;
|
|
3425
3432
|
}
|
|
3426
3433
|
}
|
|
@@ -3462,7 +3469,11 @@ class ApplyRedirects {
|
|
|
3462
3469
|
}
|
|
3463
3470
|
}
|
|
3464
3471
|
applyRedirectCommands(segments, redirectTo, posParams) {
|
|
3465
|
-
|
|
3472
|
+
const newTree = this.applyRedirectCreateUrlTree(redirectTo, this.urlSerializer.parse(redirectTo), segments, posParams);
|
|
3473
|
+
if (redirectTo.startsWith('/')) {
|
|
3474
|
+
throw new AbsoluteRedirect(newTree);
|
|
3475
|
+
}
|
|
3476
|
+
return newTree;
|
|
3466
3477
|
}
|
|
3467
3478
|
applyRedirectCreateUrlTree(redirectTo, urlTree, segments, posParams) {
|
|
3468
3479
|
const newRoot = this.createSegmentGroup(redirectTo, urlTree.root, segments, posParams);
|
|
@@ -3642,6 +3653,13 @@ function noLeftoversInUrl(segmentGroup, segments, outlet) {
|
|
|
3642
3653
|
return segments.length === 0 && !segmentGroup.children[outlet];
|
|
3643
3654
|
}
|
|
3644
3655
|
|
|
3656
|
+
/**
|
|
3657
|
+
* Class used to indicate there were no additional route config matches but that all segments of
|
|
3658
|
+
* the URL were consumed during matching so the route was URL matched. When this happens, we still
|
|
3659
|
+
* try to match child configs in case there are empty path children.
|
|
3660
|
+
*/
|
|
3661
|
+
class NoLeftoversInUrl {
|
|
3662
|
+
}
|
|
3645
3663
|
function recognize$1(injector, configLoader, rootComponentType, config, urlTree, urlSerializer, paramsInheritanceStrategy = 'emptyOnly') {
|
|
3646
3664
|
return new Recognizer(injector, configLoader, rootComponentType, config, urlTree, paramsInheritanceStrategy, urlSerializer)
|
|
3647
3665
|
.recognize();
|
|
@@ -3713,7 +3731,8 @@ class Recognizer {
|
|
|
3713
3731
|
if (segmentGroup.segments.length === 0 && segmentGroup.hasChildren()) {
|
|
3714
3732
|
return this.processChildren(injector, config, segmentGroup);
|
|
3715
3733
|
}
|
|
3716
|
-
return this.processSegment(injector, config, segmentGroup, segmentGroup.segments, outlet, true)
|
|
3734
|
+
return this.processSegment(injector, config, segmentGroup, segmentGroup.segments, outlet, true)
|
|
3735
|
+
.pipe(map(child => child instanceof TreeNode ? [child] : []));
|
|
3717
3736
|
}
|
|
3718
3737
|
/**
|
|
3719
3738
|
* Matches every child outlet in the `segmentGroup` to a `Route` in the config. Returns `null` if
|
|
@@ -3775,7 +3794,7 @@ class Recognizer {
|
|
|
3775
3794
|
}), first((x) => !!x), catchError(e => {
|
|
3776
3795
|
if (isEmptyError(e)) {
|
|
3777
3796
|
if (noLeftoversInUrl(segmentGroup, segments, outlet)) {
|
|
3778
|
-
return of(
|
|
3797
|
+
return of(new NoLeftoversInUrl());
|
|
3779
3798
|
}
|
|
3780
3799
|
return noMatch$1(segmentGroup);
|
|
3781
3800
|
}
|
|
@@ -3786,7 +3805,7 @@ class Recognizer {
|
|
|
3786
3805
|
if (!isImmediateMatch(route, rawSegment, segments, outlet))
|
|
3787
3806
|
return noMatch$1(rawSegment);
|
|
3788
3807
|
if (route.redirectTo === undefined) {
|
|
3789
|
-
return this.matchSegmentAgainstRoute(injector, rawSegment, route, segments, outlet
|
|
3808
|
+
return this.matchSegmentAgainstRoute(injector, rawSegment, route, segments, outlet);
|
|
3790
3809
|
}
|
|
3791
3810
|
if (allowRedirects && this.allowRedirects) {
|
|
3792
3811
|
return this.expandSegmentAgainstRouteUsingRedirect(injector, rawSegment, routes, route, segments, outlet);
|
|
@@ -3794,45 +3813,20 @@ class Recognizer {
|
|
|
3794
3813
|
return noMatch$1(rawSegment);
|
|
3795
3814
|
}
|
|
3796
3815
|
expandSegmentAgainstRouteUsingRedirect(injector, segmentGroup, routes, route, segments, outlet) {
|
|
3797
|
-
|
|
3798
|
-
|
|
3799
|
-
}
|
|
3800
|
-
return this.expandRegularSegmentAgainstRouteUsingRedirect(injector, segmentGroup, routes, route, segments, outlet);
|
|
3801
|
-
}
|
|
3802
|
-
expandWildCardWithParamsAgainstRouteUsingRedirect(injector, routes, route, outlet) {
|
|
3803
|
-
const newTree = this.applyRedirects.applyRedirectCommands([], route.redirectTo, {});
|
|
3804
|
-
if (route.redirectTo.startsWith('/')) {
|
|
3805
|
-
return absoluteRedirect(newTree);
|
|
3806
|
-
}
|
|
3807
|
-
return this.applyRedirects.lineralizeSegments(route, newTree)
|
|
3808
|
-
.pipe(mergeMap((newSegments) => {
|
|
3809
|
-
const group = new UrlSegmentGroup(newSegments, {});
|
|
3810
|
-
return this.processSegment(injector, routes, group, newSegments, outlet, false);
|
|
3811
|
-
}));
|
|
3812
|
-
}
|
|
3813
|
-
expandRegularSegmentAgainstRouteUsingRedirect(injector, segmentGroup, routes, route, segments, outlet) {
|
|
3814
|
-
const { matched, consumedSegments, remainingSegments, positionalParamSegments } = match(segmentGroup, route, segments);
|
|
3816
|
+
const { matched, consumedSegments, positionalParamSegments, remainingSegments, } = route.path === '**' ? createWildcardMatchResult(segments) :
|
|
3817
|
+
match(segmentGroup, route, segments);
|
|
3815
3818
|
if (!matched)
|
|
3816
3819
|
return noMatch$1(segmentGroup);
|
|
3817
3820
|
const newTree = this.applyRedirects.applyRedirectCommands(consumedSegments, route.redirectTo, positionalParamSegments);
|
|
3818
|
-
if (route.redirectTo.startsWith('/')) {
|
|
3819
|
-
return absoluteRedirect(newTree);
|
|
3820
|
-
}
|
|
3821
3821
|
return this.applyRedirects.lineralizeSegments(route, newTree)
|
|
3822
3822
|
.pipe(mergeMap((newSegments) => {
|
|
3823
3823
|
return this.processSegment(injector, routes, segmentGroup, newSegments.concat(remainingSegments), outlet, false);
|
|
3824
3824
|
}));
|
|
3825
3825
|
}
|
|
3826
|
-
matchSegmentAgainstRoute(injector, rawSegment, route, segments, outlet
|
|
3826
|
+
matchSegmentAgainstRoute(injector, rawSegment, route, segments, outlet) {
|
|
3827
3827
|
let matchResult;
|
|
3828
3828
|
if (route.path === '**') {
|
|
3829
|
-
|
|
3830
|
-
const snapshot = new ActivatedRouteSnapshot(segments, params, Object.freeze({ ...this.urlTree.queryParams }), this.urlTree.fragment, getData(route), getOutlet(route), route.component ?? route._loadedComponent ?? null, route, getResolve(route));
|
|
3831
|
-
matchResult = of({
|
|
3832
|
-
snapshot,
|
|
3833
|
-
consumedSegments: [],
|
|
3834
|
-
remainingSegments: [],
|
|
3835
|
-
});
|
|
3829
|
+
matchResult = of(createWildcardMatchResult(segments));
|
|
3836
3830
|
// Prior versions of the route matching algorithm would stop matching at the wildcard route.
|
|
3837
3831
|
// We should investigate a better strategy for any existing children. Otherwise, these
|
|
3838
3832
|
// child segments are silently dropped from the navigation.
|
|
@@ -3840,18 +3834,10 @@ class Recognizer {
|
|
|
3840
3834
|
rawSegment.children = {};
|
|
3841
3835
|
}
|
|
3842
3836
|
else {
|
|
3843
|
-
matchResult =
|
|
3844
|
-
matchWithChecks(rawSegment, route, segments, injector, this.urlSerializer)
|
|
3845
|
-
.pipe(map(({ matched, consumedSegments, remainingSegments, parameters }) => {
|
|
3846
|
-
if (!matched) {
|
|
3847
|
-
return null;
|
|
3848
|
-
}
|
|
3849
|
-
const snapshot = new ActivatedRouteSnapshot(consumedSegments, parameters, Object.freeze({ ...this.urlTree.queryParams }), this.urlTree.fragment, getData(route), getOutlet(route), route.component ?? route._loadedComponent ?? null, route, getResolve(route));
|
|
3850
|
-
return { snapshot, consumedSegments, remainingSegments };
|
|
3851
|
-
}));
|
|
3837
|
+
matchResult = matchWithChecks(rawSegment, route, segments, injector, this.urlSerializer);
|
|
3852
3838
|
}
|
|
3853
3839
|
return matchResult.pipe(switchMap((result) => {
|
|
3854
|
-
if (result
|
|
3840
|
+
if (!result.matched) {
|
|
3855
3841
|
return noMatch$1(rawSegment);
|
|
3856
3842
|
}
|
|
3857
3843
|
// If the route has an injector created from providers, we should start using that.
|
|
@@ -3859,7 +3845,8 @@ class Recognizer {
|
|
|
3859
3845
|
return this.getChildConfig(injector, route, segments)
|
|
3860
3846
|
.pipe(switchMap(({ routes: childConfig }) => {
|
|
3861
3847
|
const childInjector = route._loadedInjector ?? injector;
|
|
3862
|
-
const {
|
|
3848
|
+
const { consumedSegments, remainingSegments, parameters } = result;
|
|
3849
|
+
const snapshot = new ActivatedRouteSnapshot(consumedSegments, parameters, Object.freeze({ ...this.urlTree.queryParams }), this.urlTree.fragment, getData(route), getOutlet(route), route.component ?? route._loadedComponent ?? null, route, getResolve(route));
|
|
3863
3850
|
const { segmentGroup, slicedSegments } = split(rawSegment, consumedSegments, remainingSegments, childConfig);
|
|
3864
3851
|
if (slicedSegments.length === 0 && segmentGroup.hasChildren()) {
|
|
3865
3852
|
return this.processChildren(childInjector, childConfig, segmentGroup)
|
|
@@ -3867,11 +3854,11 @@ class Recognizer {
|
|
|
3867
3854
|
if (children === null) {
|
|
3868
3855
|
return null;
|
|
3869
3856
|
}
|
|
3870
|
-
return
|
|
3857
|
+
return new TreeNode(snapshot, children);
|
|
3871
3858
|
}));
|
|
3872
3859
|
}
|
|
3873
3860
|
if (childConfig.length === 0 && slicedSegments.length === 0) {
|
|
3874
|
-
return of(
|
|
3861
|
+
return of(new TreeNode(snapshot, []));
|
|
3875
3862
|
}
|
|
3876
3863
|
const matchedOnOutlet = getOutlet(route) === outlet;
|
|
3877
3864
|
// If we matched a config due to empty path match on a different outlet, we need to
|
|
@@ -3884,8 +3871,8 @@ class Recognizer {
|
|
|
3884
3871
|
// Notice that the children of the named outlet are configured with the primary outlet
|
|
3885
3872
|
return this
|
|
3886
3873
|
.processSegment(childInjector, childConfig, segmentGroup, slicedSegments, matchedOnOutlet ? PRIMARY_OUTLET : outlet, true)
|
|
3887
|
-
.pipe(map(
|
|
3888
|
-
return
|
|
3874
|
+
.pipe(map(child => {
|
|
3875
|
+
return new TreeNode(snapshot, child instanceof TreeNode ? [child] : []);
|
|
3889
3876
|
}));
|
|
3890
3877
|
}));
|
|
3891
3878
|
}));
|
|
@@ -3980,6 +3967,15 @@ function getData(route) {
|
|
|
3980
3967
|
function getResolve(route) {
|
|
3981
3968
|
return route.resolve || {};
|
|
3982
3969
|
}
|
|
3970
|
+
function createWildcardMatchResult(segments) {
|
|
3971
|
+
return {
|
|
3972
|
+
matched: true,
|
|
3973
|
+
parameters: segments.length > 0 ? last(segments).parameters : {},
|
|
3974
|
+
consumedSegments: segments,
|
|
3975
|
+
remainingSegments: [],
|
|
3976
|
+
positionalParamSegments: {},
|
|
3977
|
+
};
|
|
3978
|
+
}
|
|
3983
3979
|
|
|
3984
3980
|
function recognize(injector, configLoader, rootComponentType, config, serializer, paramsInheritanceStrategy) {
|
|
3985
3981
|
return mergeMap(t => recognize$1(injector, configLoader, rootComponentType, config, t.extractedUrl, serializer, paramsInheritanceStrategy)
|
|
@@ -4025,9 +4021,6 @@ function resolveNode(resolve, futureARS, futureRSS, injector) {
|
|
|
4025
4021
|
data[key] = value;
|
|
4026
4022
|
}))), takeLast(1), mapTo(data), catchError((e) => isEmptyError(e) ? EMPTY : throwError(e)));
|
|
4027
4023
|
}
|
|
4028
|
-
function getDataKeys(obj) {
|
|
4029
|
-
return [...Object.keys(obj), ...Object.getOwnPropertySymbols(obj)];
|
|
4030
|
-
}
|
|
4031
4024
|
function getResolver(injectionToken, futureARS, futureRSS, injector) {
|
|
4032
4025
|
const closestInjector = getClosestRouteInjector(futureARS) ?? injector;
|
|
4033
4026
|
const resolver = getTokenOrFunctionIdentity(injectionToken, closestInjector);
|
|
@@ -4099,10 +4092,10 @@ class TitleStrategy {
|
|
|
4099
4092
|
getResolvedTitleForRoute(snapshot) {
|
|
4100
4093
|
return snapshot.data[RouteTitleKey];
|
|
4101
4094
|
}
|
|
4102
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.0.0-next.
|
|
4103
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.0.0-next.
|
|
4095
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.0.0-next.3", ngImport: i0, type: TitleStrategy, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
4096
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.0.0-next.3", ngImport: i0, type: TitleStrategy, providedIn: 'root', useFactory: () => inject(DefaultTitleStrategy) }); }
|
|
4104
4097
|
}
|
|
4105
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.0.0-next.
|
|
4098
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.0.0-next.3", ngImport: i0, type: TitleStrategy, decorators: [{
|
|
4106
4099
|
type: Injectable,
|
|
4107
4100
|
args: [{ providedIn: 'root', useFactory: () => inject(DefaultTitleStrategy) }]
|
|
4108
4101
|
}] });
|
|
@@ -4125,10 +4118,10 @@ class DefaultTitleStrategy extends TitleStrategy {
|
|
|
4125
4118
|
this.title.setTitle(title);
|
|
4126
4119
|
}
|
|
4127
4120
|
}
|
|
4128
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.0.0-next.
|
|
4129
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.0.0-next.
|
|
4121
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.0.0-next.3", ngImport: i0, type: DefaultTitleStrategy, deps: [{ token: i1.Title }], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
4122
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.0.0-next.3", ngImport: i0, type: DefaultTitleStrategy, providedIn: 'root' }); }
|
|
4130
4123
|
}
|
|
4131
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.0.0-next.
|
|
4124
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.0.0-next.3", ngImport: i0, type: DefaultTitleStrategy, decorators: [{
|
|
4132
4125
|
type: Injectable,
|
|
4133
4126
|
args: [{ providedIn: 'root' }]
|
|
4134
4127
|
}], ctorParameters: function () { return [{ type: i1.Title }]; } });
|
|
@@ -4242,10 +4235,10 @@ class RouterConfigLoader {
|
|
|
4242
4235
|
}
|
|
4243
4236
|
}));
|
|
4244
4237
|
}
|
|
4245
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.0.0-next.
|
|
4246
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.0.0-next.
|
|
4238
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.0.0-next.3", ngImport: i0, type: RouterConfigLoader, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
4239
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.0.0-next.3", ngImport: i0, type: RouterConfigLoader, providedIn: 'root' }); }
|
|
4247
4240
|
}
|
|
4248
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.0.0-next.
|
|
4241
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.0.0-next.3", ngImport: i0, type: RouterConfigLoader, decorators: [{
|
|
4249
4242
|
type: Injectable,
|
|
4250
4243
|
args: [{ providedIn: 'root' }]
|
|
4251
4244
|
}] });
|
|
@@ -4261,6 +4254,42 @@ function maybeUnwrapDefaultExport(input) {
|
|
|
4261
4254
|
return isWrappedDefaultExport(input) ? input['default'] : input;
|
|
4262
4255
|
}
|
|
4263
4256
|
|
|
4257
|
+
/**
|
|
4258
|
+
* @description
|
|
4259
|
+
*
|
|
4260
|
+
* Provides a way to migrate AngularJS applications to Angular.
|
|
4261
|
+
*
|
|
4262
|
+
* @publicApi
|
|
4263
|
+
*/
|
|
4264
|
+
class UrlHandlingStrategy {
|
|
4265
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.0.0-next.3", ngImport: i0, type: UrlHandlingStrategy, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
4266
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.0.0-next.3", ngImport: i0, type: UrlHandlingStrategy, providedIn: 'root', useFactory: () => inject(DefaultUrlHandlingStrategy) }); }
|
|
4267
|
+
}
|
|
4268
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.0.0-next.3", ngImport: i0, type: UrlHandlingStrategy, decorators: [{
|
|
4269
|
+
type: Injectable,
|
|
4270
|
+
args: [{ providedIn: 'root', useFactory: () => inject(DefaultUrlHandlingStrategy) }]
|
|
4271
|
+
}] });
|
|
4272
|
+
/**
|
|
4273
|
+
* @publicApi
|
|
4274
|
+
*/
|
|
4275
|
+
class DefaultUrlHandlingStrategy {
|
|
4276
|
+
shouldProcessUrl(url) {
|
|
4277
|
+
return true;
|
|
4278
|
+
}
|
|
4279
|
+
extract(url) {
|
|
4280
|
+
return url;
|
|
4281
|
+
}
|
|
4282
|
+
merge(newUrlPart, wholeUrl) {
|
|
4283
|
+
return newUrlPart;
|
|
4284
|
+
}
|
|
4285
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.0.0-next.3", ngImport: i0, type: DefaultUrlHandlingStrategy, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
4286
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.0.0-next.3", ngImport: i0, type: DefaultUrlHandlingStrategy, providedIn: 'root' }); }
|
|
4287
|
+
}
|
|
4288
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.0.0-next.3", ngImport: i0, type: DefaultUrlHandlingStrategy, decorators: [{
|
|
4289
|
+
type: Injectable,
|
|
4290
|
+
args: [{ providedIn: 'root' }]
|
|
4291
|
+
}] });
|
|
4292
|
+
|
|
4264
4293
|
class NavigationTransitions {
|
|
4265
4294
|
get hasRequestedNavigation() {
|
|
4266
4295
|
return this.navigationId !== 0;
|
|
@@ -4287,6 +4316,7 @@ class NavigationTransitions {
|
|
|
4287
4316
|
this.titleStrategy = inject(TitleStrategy);
|
|
4288
4317
|
this.options = inject(ROUTER_CONFIGURATION, { optional: true }) || {};
|
|
4289
4318
|
this.paramsInheritanceStrategy = this.options.paramsInheritanceStrategy || 'emptyOnly';
|
|
4319
|
+
this.urlHandlingStrategy = inject(UrlHandlingStrategy);
|
|
4290
4320
|
this.navigationId = 0;
|
|
4291
4321
|
/**
|
|
4292
4322
|
* Hook that enables you to pause navigation after the preactivation phase.
|
|
@@ -4315,8 +4345,8 @@ class NavigationTransitions {
|
|
|
4315
4345
|
currentUrlTree: initialUrlTree,
|
|
4316
4346
|
currentRawUrl: initialUrlTree,
|
|
4317
4347
|
currentBrowserUrl: initialUrlTree,
|
|
4318
|
-
extractedUrl:
|
|
4319
|
-
urlAfterRedirects:
|
|
4348
|
+
extractedUrl: this.urlHandlingStrategy.extract(initialUrlTree),
|
|
4349
|
+
urlAfterRedirects: this.urlHandlingStrategy.extract(initialUrlTree),
|
|
4320
4350
|
rawUrl: initialUrlTree,
|
|
4321
4351
|
extras: {},
|
|
4322
4352
|
resolve: null,
|
|
@@ -4333,7 +4363,7 @@ class NavigationTransitions {
|
|
|
4333
4363
|
});
|
|
4334
4364
|
return this.transitions.pipe(filter(t => t.id !== 0),
|
|
4335
4365
|
// Extract URL
|
|
4336
|
-
map(t => ({ ...t, extractedUrl:
|
|
4366
|
+
map(t => ({ ...t, extractedUrl: this.urlHandlingStrategy.extract(t.rawUrl) })),
|
|
4337
4367
|
// Using switchMap so we cancel executing navigations when a new one comes in
|
|
4338
4368
|
switchMap(overallTransitionState => {
|
|
4339
4369
|
this.currentTransition = overallTransitionState;
|
|
@@ -4372,7 +4402,7 @@ class NavigationTransitions {
|
|
|
4372
4402
|
t.resolve(null);
|
|
4373
4403
|
return EMPTY;
|
|
4374
4404
|
}
|
|
4375
|
-
if (
|
|
4405
|
+
if (this.urlHandlingStrategy.shouldProcessUrl(t.rawUrl)) {
|
|
4376
4406
|
return of(t).pipe(
|
|
4377
4407
|
// Fire NavigationStart event
|
|
4378
4408
|
switchMap(t => {
|
|
@@ -4401,7 +4431,7 @@ class NavigationTransitions {
|
|
|
4401
4431
|
}));
|
|
4402
4432
|
}
|
|
4403
4433
|
else if (urlTransition &&
|
|
4404
|
-
|
|
4434
|
+
this.urlHandlingStrategy.shouldProcessUrl(t.currentRawUrl)) {
|
|
4405
4435
|
/* When the current URL shouldn't be processed, but the previous one
|
|
4406
4436
|
* was, we handle this "error condition" by navigating to the
|
|
4407
4437
|
* previously successful URL, but leaving the URL intact.*/
|
|
@@ -4415,6 +4445,7 @@ class NavigationTransitions {
|
|
|
4415
4445
|
urlAfterRedirects: extractedUrl,
|
|
4416
4446
|
extras: { ...extras, skipLocationChange: false, replaceUrl: false },
|
|
4417
4447
|
};
|
|
4448
|
+
this.currentNavigation.finalUrl = extractedUrl;
|
|
4418
4449
|
return of(overallTransitionState);
|
|
4419
4450
|
}
|
|
4420
4451
|
else {
|
|
@@ -4503,6 +4534,7 @@ class NavigationTransitions {
|
|
|
4503
4534
|
const targetRouterState = createRouterState(router.routeReuseStrategy, t.targetSnapshot, t.currentRouterState);
|
|
4504
4535
|
this.currentTransition =
|
|
4505
4536
|
overallTransitionState = { ...t, targetRouterState };
|
|
4537
|
+
this.currentNavigation.targetRouterState = targetRouterState;
|
|
4506
4538
|
return overallTransitionState;
|
|
4507
4539
|
}), tap(() => {
|
|
4508
4540
|
this.events.next(new BeforeActivateRoutes());
|
|
@@ -4586,10 +4618,10 @@ class NavigationTransitions {
|
|
|
4586
4618
|
this.events.next(navCancel);
|
|
4587
4619
|
t.resolve(false);
|
|
4588
4620
|
}
|
|
4589
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.0.0-next.
|
|
4590
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.0.0-next.
|
|
4621
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.0.0-next.3", ngImport: i0, type: NavigationTransitions, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
4622
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.0.0-next.3", ngImport: i0, type: NavigationTransitions, providedIn: 'root' }); }
|
|
4591
4623
|
}
|
|
4592
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.0.0-next.
|
|
4624
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.0.0-next.3", ngImport: i0, type: NavigationTransitions, decorators: [{
|
|
4593
4625
|
type: Injectable,
|
|
4594
4626
|
args: [{ providedIn: 'root' }]
|
|
4595
4627
|
}], ctorParameters: function () { return []; } });
|
|
@@ -4605,10 +4637,10 @@ function isBrowserTriggeredNavigation(source) {
|
|
|
4605
4637
|
* @publicApi
|
|
4606
4638
|
*/
|
|
4607
4639
|
class RouteReuseStrategy {
|
|
4608
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.0.0-next.
|
|
4609
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.0.0-next.
|
|
4640
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.0.0-next.3", ngImport: i0, type: RouteReuseStrategy, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
4641
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.0.0-next.3", ngImport: i0, type: RouteReuseStrategy, providedIn: 'root', useFactory: () => inject(DefaultRouteReuseStrategy) }); }
|
|
4610
4642
|
}
|
|
4611
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.0.0-next.
|
|
4643
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.0.0-next.3", ngImport: i0, type: RouteReuseStrategy, decorators: [{
|
|
4612
4644
|
type: Injectable,
|
|
4613
4645
|
args: [{ providedIn: 'root', useFactory: () => inject(DefaultRouteReuseStrategy) }]
|
|
4614
4646
|
}] });
|
|
@@ -4659,46 +4691,238 @@ class BaseRouteReuseStrategy {
|
|
|
4659
4691
|
}
|
|
4660
4692
|
}
|
|
4661
4693
|
class DefaultRouteReuseStrategy extends BaseRouteReuseStrategy {
|
|
4662
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.0.0-next.
|
|
4663
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.0.0-next.
|
|
4694
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.0.0-next.3", ngImport: i0, type: DefaultRouteReuseStrategy, deps: null, target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
4695
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.0.0-next.3", ngImport: i0, type: DefaultRouteReuseStrategy, providedIn: 'root' }); }
|
|
4664
4696
|
}
|
|
4665
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.0.0-next.
|
|
4697
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.0.0-next.3", ngImport: i0, type: DefaultRouteReuseStrategy, decorators: [{
|
|
4666
4698
|
type: Injectable,
|
|
4667
4699
|
args: [{ providedIn: 'root' }]
|
|
4668
4700
|
}] });
|
|
4669
4701
|
|
|
4670
|
-
|
|
4671
|
-
|
|
4672
|
-
|
|
4673
|
-
|
|
4674
|
-
|
|
4675
|
-
|
|
4676
|
-
|
|
4677
|
-
|
|
4678
|
-
|
|
4679
|
-
|
|
4680
|
-
|
|
4681
|
-
|
|
4682
|
-
|
|
4683
|
-
|
|
4684
|
-
|
|
4685
|
-
|
|
4686
|
-
|
|
4687
|
-
|
|
4688
|
-
|
|
4689
|
-
|
|
4690
|
-
|
|
4702
|
+
class StateManager {
|
|
4703
|
+
constructor() {
|
|
4704
|
+
this.location = inject(Location);
|
|
4705
|
+
this.urlSerializer = inject(UrlSerializer);
|
|
4706
|
+
this.options = inject(ROUTER_CONFIGURATION, { optional: true }) || {};
|
|
4707
|
+
this.canceledNavigationResolution = this.options.canceledNavigationResolution || 'replace';
|
|
4708
|
+
// These are currently writable via the Router public API but are deprecated and should be made
|
|
4709
|
+
// `private readonly` in the future.
|
|
4710
|
+
this.urlHandlingStrategy = inject(UrlHandlingStrategy);
|
|
4711
|
+
this.urlUpdateStrategy = this.options.urlUpdateStrategy || 'deferred';
|
|
4712
|
+
/**
|
|
4713
|
+
* Represents the activated `UrlTree` that the `Router` is configured to handle (through
|
|
4714
|
+
* `UrlHandlingStrategy`). That is, after we find the route config tree that we're going to
|
|
4715
|
+
* activate, run guards, and are just about to activate the route, we set the currentUrlTree.
|
|
4716
|
+
*
|
|
4717
|
+
* This should match the `browserUrlTree` when a navigation succeeds. If the
|
|
4718
|
+
* `UrlHandlingStrategy.shouldProcessUrl` is `false`, only the `browserUrlTree` is updated.
|
|
4719
|
+
* @internal
|
|
4720
|
+
*/
|
|
4721
|
+
this.currentUrlTree = new UrlTree();
|
|
4722
|
+
/**
|
|
4723
|
+
* Meant to represent the entire browser url after a successful navigation. In the life of a
|
|
4724
|
+
* navigation transition:
|
|
4725
|
+
* 1. The rawUrl represents the full URL that's being navigated to
|
|
4726
|
+
* 2. We apply redirects, which might only apply to _part_ of the URL (due to
|
|
4727
|
+
* `UrlHandlingStrategy`).
|
|
4728
|
+
* 3. Right before activation (because we assume activation will succeed), we update the
|
|
4729
|
+
* rawUrlTree to be a combination of the urlAfterRedirects (again, this might only apply to part
|
|
4730
|
+
* of the initial url) and the rawUrl of the transition (which was the original navigation url in
|
|
4731
|
+
* its full form).
|
|
4732
|
+
* @internal
|
|
4733
|
+
*
|
|
4734
|
+
* Note that this is _only_ here to support `UrlHandlingStrategy.extract` and
|
|
4735
|
+
* `UrlHandlingStrategy.shouldProcessUrl`. If those didn't exist, we could get by with
|
|
4736
|
+
* `currentUrlTree` alone. If a new Router were to be provided (i.e. one that works with the
|
|
4737
|
+
* browser navigation API), we should think about whether this complexity should be carried over.
|
|
4738
|
+
*
|
|
4739
|
+
* - extract: `rawUrlTree` is needed because `extract` may only return part
|
|
4740
|
+
* of the navigation URL. Thus, `currentUrlTree` may only represent _part_ of the browser URL.
|
|
4741
|
+
* When a navigation gets cancelled and we need to reset the URL or a new navigation occurs, we
|
|
4742
|
+
* need to know the _whole_ browser URL, not just the part handled by UrlHandlingStrategy.
|
|
4743
|
+
* - shouldProcessUrl: When this returns `false`, the router just ignores the navigation but still
|
|
4744
|
+
* updates the `rawUrlTree` with the assumption that the navigation was caused by the location
|
|
4745
|
+
* change listener due to a URL update by the AngularJS router. In this case, we still need to
|
|
4746
|
+
* know what the browser's URL is for future navigations.
|
|
4747
|
+
*
|
|
4748
|
+
*/
|
|
4749
|
+
this.rawUrlTree = this.currentUrlTree;
|
|
4750
|
+
/**
|
|
4751
|
+
* Meant to represent the part of the browser url that the `Router` is set up to handle (via the
|
|
4752
|
+
* `UrlHandlingStrategy`). This value is updated immediately after the browser url is updated (or
|
|
4753
|
+
* the browser url update is skipped via `skipLocationChange`). With that, note that
|
|
4754
|
+
* `browserUrlTree` _may not_ reflect the actual browser URL for two reasons:
|
|
4755
|
+
*
|
|
4756
|
+
* 1. `UrlHandlingStrategy` only handles part of the URL
|
|
4757
|
+
* 2. `skipLocationChange` does not update the browser url.
|
|
4758
|
+
*
|
|
4759
|
+
* So to reiterate, `browserUrlTree` only represents the Router's internal understanding of the
|
|
4760
|
+
* current route, either before guards with `urlUpdateStrategy === 'eager'` or right before
|
|
4761
|
+
* activation with `'deferred'`.
|
|
4762
|
+
*
|
|
4763
|
+
* This should match the `currentUrlTree` when the navigation succeeds.
|
|
4764
|
+
* @internal
|
|
4765
|
+
*/
|
|
4766
|
+
this.browserUrlTree = this.currentUrlTree;
|
|
4767
|
+
/**
|
|
4768
|
+
* The id of the currently active page in the router.
|
|
4769
|
+
* Updated to the transition's target id on a successful navigation.
|
|
4770
|
+
*
|
|
4771
|
+
* This is used to track what page the router last activated. When an attempted navigation fails,
|
|
4772
|
+
* the router can then use this to compute how to restore the state back to the previously active
|
|
4773
|
+
* page.
|
|
4774
|
+
*/
|
|
4775
|
+
this.currentPageId = 0;
|
|
4776
|
+
this.lastSuccessfulId = -1;
|
|
4777
|
+
this.routerState = createEmptyState(this.currentUrlTree, null);
|
|
4778
|
+
this.stateMemento = this.createStateMemento();
|
|
4691
4779
|
}
|
|
4692
|
-
|
|
4693
|
-
|
|
4780
|
+
/**
|
|
4781
|
+
* The ɵrouterPageId of whatever page is currently active in the browser history. This is
|
|
4782
|
+
* important for computing the target page id for new navigations because we need to ensure each
|
|
4783
|
+
* page id in the browser history is 1 more than the previous entry.
|
|
4784
|
+
*/
|
|
4785
|
+
get browserPageId() {
|
|
4786
|
+
if (this.canceledNavigationResolution !== 'computed') {
|
|
4787
|
+
return this.currentPageId;
|
|
4788
|
+
}
|
|
4789
|
+
return this.location.getState()?.ɵrouterPageId ?? this.currentPageId;
|
|
4694
4790
|
}
|
|
4695
|
-
|
|
4696
|
-
return
|
|
4791
|
+
createStateMemento() {
|
|
4792
|
+
return {
|
|
4793
|
+
rawUrlTree: this.rawUrlTree,
|
|
4794
|
+
browserUrlTree: this.browserUrlTree,
|
|
4795
|
+
currentUrlTree: this.currentUrlTree,
|
|
4796
|
+
routerState: this.routerState,
|
|
4797
|
+
};
|
|
4798
|
+
}
|
|
4799
|
+
handleNavigationEvent(e, currentTransition) {
|
|
4800
|
+
if (e instanceof NavigationStart) {
|
|
4801
|
+
this.stateMemento = this.createStateMemento();
|
|
4802
|
+
// If the source of the navigation is from a browser event, the URL is
|
|
4803
|
+
// already updated. We already need to sync the internal state.
|
|
4804
|
+
if (isBrowserTriggeredNavigation(currentTransition.trigger)) {
|
|
4805
|
+
this.browserUrlTree = currentTransition.extractedUrl;
|
|
4806
|
+
}
|
|
4807
|
+
}
|
|
4808
|
+
else if (e instanceof NavigationSkipped) {
|
|
4809
|
+
this.rawUrlTree = currentTransition.initialUrl;
|
|
4810
|
+
}
|
|
4811
|
+
else if (e instanceof RoutesRecognized) {
|
|
4812
|
+
if (this.urlUpdateStrategy === 'eager') {
|
|
4813
|
+
if (!currentTransition.extras.skipLocationChange) {
|
|
4814
|
+
const rawUrl = this.urlHandlingStrategy.merge(currentTransition.finalUrl, currentTransition.initialUrl);
|
|
4815
|
+
this.setBrowserUrl(rawUrl, currentTransition);
|
|
4816
|
+
}
|
|
4817
|
+
this.browserUrlTree = currentTransition.finalUrl;
|
|
4818
|
+
}
|
|
4819
|
+
}
|
|
4820
|
+
else if (e instanceof BeforeActivateRoutes) {
|
|
4821
|
+
this.currentUrlTree = currentTransition.finalUrl;
|
|
4822
|
+
this.rawUrlTree =
|
|
4823
|
+
this.urlHandlingStrategy.merge(currentTransition.finalUrl, currentTransition.initialUrl);
|
|
4824
|
+
this.routerState = currentTransition.targetRouterState;
|
|
4825
|
+
if (this.urlUpdateStrategy === 'deferred') {
|
|
4826
|
+
if (!currentTransition.extras.skipLocationChange) {
|
|
4827
|
+
this.setBrowserUrl(this.rawUrlTree, currentTransition);
|
|
4828
|
+
}
|
|
4829
|
+
this.browserUrlTree = currentTransition.finalUrl;
|
|
4830
|
+
}
|
|
4831
|
+
}
|
|
4832
|
+
else if (e instanceof NavigationCancel &&
|
|
4833
|
+
(e.code === 3 /* NavigationCancellationCode.GuardRejected */ ||
|
|
4834
|
+
e.code === 2 /* NavigationCancellationCode.NoDataFromResolver */)) {
|
|
4835
|
+
this.restoreHistory(currentTransition);
|
|
4836
|
+
}
|
|
4837
|
+
else if (e instanceof NavigationError) {
|
|
4838
|
+
this.restoreHistory(currentTransition, true);
|
|
4839
|
+
}
|
|
4840
|
+
else if (e instanceof NavigationEnd) {
|
|
4841
|
+
this.lastSuccessfulId = e.id;
|
|
4842
|
+
this.currentPageId = this.browserPageId;
|
|
4843
|
+
}
|
|
4844
|
+
}
|
|
4845
|
+
setBrowserUrl(url, transition) {
|
|
4846
|
+
const path = this.urlSerializer.serialize(url);
|
|
4847
|
+
if (this.location.isCurrentPathEqualTo(path) || !!transition.extras.replaceUrl) {
|
|
4848
|
+
// replacements do not update the target page
|
|
4849
|
+
const currentBrowserPageId = this.browserPageId;
|
|
4850
|
+
const state = {
|
|
4851
|
+
...transition.extras.state,
|
|
4852
|
+
...this.generateNgRouterState(transition.id, currentBrowserPageId)
|
|
4853
|
+
};
|
|
4854
|
+
this.location.replaceState(path, '', state);
|
|
4855
|
+
}
|
|
4856
|
+
else {
|
|
4857
|
+
const state = {
|
|
4858
|
+
...transition.extras.state,
|
|
4859
|
+
...this.generateNgRouterState(transition.id, this.browserPageId + 1)
|
|
4860
|
+
};
|
|
4861
|
+
this.location.go(path, '', state);
|
|
4862
|
+
}
|
|
4863
|
+
}
|
|
4864
|
+
/**
|
|
4865
|
+
* Performs the necessary rollback action to restore the browser URL to the
|
|
4866
|
+
* state before the transition.
|
|
4867
|
+
* @internal
|
|
4868
|
+
*/
|
|
4869
|
+
restoreHistory(navigation, restoringFromCaughtError = false) {
|
|
4870
|
+
if (this.canceledNavigationResolution === 'computed') {
|
|
4871
|
+
const currentBrowserPageId = this.browserPageId;
|
|
4872
|
+
const targetPagePosition = this.currentPageId - currentBrowserPageId;
|
|
4873
|
+
if (targetPagePosition !== 0) {
|
|
4874
|
+
this.location.historyGo(targetPagePosition);
|
|
4875
|
+
}
|
|
4876
|
+
else if (this.currentUrlTree === navigation.finalUrl && targetPagePosition === 0) {
|
|
4877
|
+
// We got to the activation stage (where currentUrlTree is set to the navigation's
|
|
4878
|
+
// finalUrl), but we weren't moving anywhere in history (skipLocationChange or replaceUrl).
|
|
4879
|
+
// We still need to reset the router state back to what it was when the navigation started.
|
|
4880
|
+
this.resetState(navigation);
|
|
4881
|
+
// TODO(atscott): resetting the `browserUrlTree` should really be done in `resetState`.
|
|
4882
|
+
// Investigate if this can be done by running TGP.
|
|
4883
|
+
this.browserUrlTree = this.stateMemento.browserUrlTree;
|
|
4884
|
+
this.resetUrlToCurrentUrlTree();
|
|
4885
|
+
}
|
|
4886
|
+
else {
|
|
4887
|
+
// The browser URL and router state was not updated before the navigation cancelled so
|
|
4888
|
+
// there's no restoration needed.
|
|
4889
|
+
}
|
|
4890
|
+
}
|
|
4891
|
+
else if (this.canceledNavigationResolution === 'replace') {
|
|
4892
|
+
// TODO(atscott): It seems like we should _always_ reset the state here. It would be a no-op
|
|
4893
|
+
// for `deferred` navigations that haven't change the internal state yet because guards
|
|
4894
|
+
// reject. For 'eager' navigations, it seems like we also really should reset the state
|
|
4895
|
+
// because the navigation was cancelled. Investigate if this can be done by running TGP.
|
|
4896
|
+
if (restoringFromCaughtError) {
|
|
4897
|
+
this.resetState(navigation);
|
|
4898
|
+
}
|
|
4899
|
+
this.resetUrlToCurrentUrlTree();
|
|
4900
|
+
}
|
|
4901
|
+
}
|
|
4902
|
+
resetState(navigation) {
|
|
4903
|
+
this.routerState = this.stateMemento.routerState;
|
|
4904
|
+
this.currentUrlTree = this.stateMemento.currentUrlTree;
|
|
4905
|
+
// Note here that we use the urlHandlingStrategy to get the reset `rawUrlTree` because it may be
|
|
4906
|
+
// configured to handle only part of the navigation URL. This means we would only want to reset
|
|
4907
|
+
// the part of the navigation handled by the Angular router rather than the whole URL. In
|
|
4908
|
+
// addition, the URLHandlingStrategy may be configured to specifically preserve parts of the URL
|
|
4909
|
+
// when merging, such as the query params so they are not lost on a refresh.
|
|
4910
|
+
this.rawUrlTree =
|
|
4911
|
+
this.urlHandlingStrategy.merge(this.currentUrlTree, navigation.finalUrl ?? this.rawUrlTree);
|
|
4912
|
+
}
|
|
4913
|
+
resetUrlToCurrentUrlTree() {
|
|
4914
|
+
this.location.replaceState(this.urlSerializer.serialize(this.rawUrlTree), '', this.generateNgRouterState(this.lastSuccessfulId, this.currentPageId));
|
|
4915
|
+
}
|
|
4916
|
+
generateNgRouterState(navigationId, routerPageId) {
|
|
4917
|
+
if (this.canceledNavigationResolution === 'computed') {
|
|
4918
|
+
return { navigationId, ɵrouterPageId: routerPageId };
|
|
4919
|
+
}
|
|
4920
|
+
return { navigationId };
|
|
4697
4921
|
}
|
|
4698
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.0.0-next.
|
|
4699
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.0.0-next.
|
|
4922
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.0.0-next.3", ngImport: i0, type: StateManager, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
4923
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.0.0-next.3", ngImport: i0, type: StateManager, providedIn: 'root' }); }
|
|
4700
4924
|
}
|
|
4701
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.0.0-next.
|
|
4925
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.0.0-next.3", ngImport: i0, type: StateManager, decorators: [{
|
|
4702
4926
|
type: Injectable,
|
|
4703
4927
|
args: [{ providedIn: 'root' }]
|
|
4704
4928
|
}] });
|
|
@@ -4775,21 +4999,14 @@ const subsetMatchOptions = {
|
|
|
4775
4999
|
* @publicApi
|
|
4776
5000
|
*/
|
|
4777
5001
|
class Router {
|
|
4778
|
-
|
|
4779
|
-
|
|
4780
|
-
get navigationId() {
|
|
4781
|
-
return this.navigationTransitions.navigationId;
|
|
5002
|
+
get currentUrlTree() {
|
|
5003
|
+
return this.stateManager.currentUrlTree;
|
|
4782
5004
|
}
|
|
4783
|
-
|
|
4784
|
-
|
|
4785
|
-
|
|
4786
|
-
|
|
4787
|
-
|
|
4788
|
-
get browserPageId() {
|
|
4789
|
-
if (this.canceledNavigationResolution !== 'computed') {
|
|
4790
|
-
return this.currentPageId;
|
|
4791
|
-
}
|
|
4792
|
-
return this.location.getState()?.ɵrouterPageId ?? this.currentPageId;
|
|
5005
|
+
get rawUrlTree() {
|
|
5006
|
+
return this.stateManager.rawUrlTree;
|
|
5007
|
+
}
|
|
5008
|
+
get browserUrlTree() {
|
|
5009
|
+
return this.stateManager.browserUrlTree;
|
|
4793
5010
|
}
|
|
4794
5011
|
/**
|
|
4795
5012
|
* An event stream for routing events.
|
|
@@ -4801,27 +5018,30 @@ class Router {
|
|
|
4801
5018
|
// the change.
|
|
4802
5019
|
return this._events;
|
|
4803
5020
|
}
|
|
5021
|
+
/**
|
|
5022
|
+
* The current state of routing in this NgModule.
|
|
5023
|
+
*/
|
|
5024
|
+
get routerState() {
|
|
5025
|
+
return this.stateManager.routerState;
|
|
5026
|
+
}
|
|
4804
5027
|
constructor() {
|
|
4805
5028
|
this.disposed = false;
|
|
4806
|
-
/**
|
|
4807
|
-
* The id of the currently active page in the router.
|
|
4808
|
-
* Updated to the transition's target id on a successful navigation.
|
|
4809
|
-
*
|
|
4810
|
-
* This is used to track what page the router last activated. When an attempted navigation fails,
|
|
4811
|
-
* the router can then use this to compute how to restore the state back to the previously active
|
|
4812
|
-
* page.
|
|
4813
|
-
*/
|
|
4814
|
-
this.currentPageId = 0;
|
|
4815
|
-
this.console = inject(ɵConsole);
|
|
4816
5029
|
this.isNgZoneEnabled = false;
|
|
5030
|
+
this.console = inject(ɵConsole);
|
|
5031
|
+
this.stateManager = inject(StateManager);
|
|
5032
|
+
this.options = inject(ROUTER_CONFIGURATION, { optional: true }) || {};
|
|
5033
|
+
this.pendingTasks = inject(ɵInitialRenderPendingTasks);
|
|
5034
|
+
this.urlUpdateStrategy = this.options.urlUpdateStrategy || 'deferred';
|
|
5035
|
+
this.navigationTransitions = inject(NavigationTransitions);
|
|
5036
|
+
this.urlSerializer = inject(UrlSerializer);
|
|
5037
|
+
this.location = inject(Location);
|
|
5038
|
+
this.urlHandlingStrategy = inject(UrlHandlingStrategy);
|
|
4817
5039
|
/**
|
|
4818
5040
|
* The private `Subject` type for the public events exposed in the getter. This is used internally
|
|
4819
5041
|
* to push events to. The separate field allows us to expose separate types in the public API
|
|
4820
5042
|
* (i.e., an Observable rather than the Subject).
|
|
4821
5043
|
*/
|
|
4822
5044
|
this._events = new Subject();
|
|
4823
|
-
this.options = inject(ROUTER_CONFIGURATION, { optional: true }) || {};
|
|
4824
|
-
this.pendingTasks = inject(ɵInitialRenderPendingTasks);
|
|
4825
5045
|
/**
|
|
4826
5046
|
* A handler for navigation errors in this NgModule.
|
|
4827
5047
|
*
|
|
@@ -4844,15 +5064,6 @@ class Router {
|
|
|
4844
5064
|
* false otherwise.
|
|
4845
5065
|
*/
|
|
4846
5066
|
this.navigated = false;
|
|
4847
|
-
this.lastSuccessfulId = -1;
|
|
4848
|
-
/**
|
|
4849
|
-
* A strategy for extracting and merging URLs.
|
|
4850
|
-
* Used for AngularJS to Angular migrations.
|
|
4851
|
-
*
|
|
4852
|
-
* @deprecated Configure using `providers` instead:
|
|
4853
|
-
* `{provide: UrlHandlingStrategy, useClass: MyStrategy}`.
|
|
4854
|
-
*/
|
|
4855
|
-
this.urlHandlingStrategy = inject(UrlHandlingStrategy);
|
|
4856
5067
|
/**
|
|
4857
5068
|
* A strategy for re-using routes.
|
|
4858
5069
|
*
|
|
@@ -4870,37 +5081,7 @@ class Router {
|
|
|
4870
5081
|
* @see {@link RouterModule}
|
|
4871
5082
|
*/
|
|
4872
5083
|
this.onSameUrlNavigation = this.options.onSameUrlNavigation || 'ignore';
|
|
4873
|
-
this.urlUpdateStrategy = this.options.urlUpdateStrategy || 'deferred';
|
|
4874
|
-
/**
|
|
4875
|
-
* Configures how the Router attempts to restore state when a navigation is cancelled.
|
|
4876
|
-
*
|
|
4877
|
-
* 'replace' - Always uses `location.replaceState` to set the browser state to the state of the
|
|
4878
|
-
* router before the navigation started. This means that if the URL of the browser is updated
|
|
4879
|
-
* _before_ the navigation is canceled, the Router will simply replace the item in history rather
|
|
4880
|
-
* than trying to restore to the previous location in the session history. This happens most
|
|
4881
|
-
* frequently with `urlUpdateStrategy: 'eager'` and navigations with the browser back/forward
|
|
4882
|
-
* buttons.
|
|
4883
|
-
*
|
|
4884
|
-
* 'computed' - Will attempt to return to the same index in the session history that corresponds
|
|
4885
|
-
* to the Angular route when the navigation gets cancelled. For example, if the browser back
|
|
4886
|
-
* button is clicked and the navigation is cancelled, the Router will trigger a forward navigation
|
|
4887
|
-
* and vice versa.
|
|
4888
|
-
*
|
|
4889
|
-
* Note: the 'computed' option is incompatible with any `UrlHandlingStrategy` which only
|
|
4890
|
-
* handles a portion of the URL because the history restoration navigates to the previous place in
|
|
4891
|
-
* the browser history rather than simply resetting a portion of the URL.
|
|
4892
|
-
*
|
|
4893
|
-
* The default value is `replace`.
|
|
4894
|
-
*
|
|
4895
|
-
* @see {@link withRouterConfig}
|
|
4896
|
-
* @see {@link provideRouter}
|
|
4897
|
-
* @see {@link RouterModule}
|
|
4898
|
-
*/
|
|
4899
|
-
this.canceledNavigationResolution = this.options.canceledNavigationResolution || 'replace';
|
|
4900
5084
|
this.config = inject(ROUTES, { optional: true })?.flat() ?? [];
|
|
4901
|
-
this.navigationTransitions = inject(NavigationTransitions);
|
|
4902
|
-
this.urlSerializer = inject(UrlSerializer);
|
|
4903
|
-
this.location = inject(Location);
|
|
4904
5085
|
/**
|
|
4905
5086
|
* Indicates whether the application has opted in to binding Router data to component inputs.
|
|
4906
5087
|
*
|
|
@@ -4911,94 +5092,48 @@ class Router {
|
|
|
4911
5092
|
this.eventsSubscription = new Subscription();
|
|
4912
5093
|
this.isNgZoneEnabled = inject(NgZone) instanceof NgZone && NgZone.isInAngularZone();
|
|
4913
5094
|
this.resetConfig(this.config);
|
|
4914
|
-
this.currentUrlTree = new UrlTree();
|
|
4915
|
-
this.rawUrlTree = this.currentUrlTree;
|
|
4916
|
-
this.browserUrlTree = this.currentUrlTree;
|
|
4917
|
-
this.routerState = createEmptyState(this.currentUrlTree, null);
|
|
4918
5095
|
this.navigationTransitions.setupNavigations(this, this.currentUrlTree, this.routerState)
|
|
4919
|
-
.subscribe(
|
|
4920
|
-
|
|
4921
|
-
|
|
4922
|
-
|
|
4923
|
-
this.console.warn(`Unhandled Navigation Error: ${e}`);
|
|
5096
|
+
.subscribe({
|
|
5097
|
+
error: (e) => {
|
|
5098
|
+
this.console.warn(ngDevMode ? `Unhandled Navigation Error: ${e}` : e);
|
|
5099
|
+
}
|
|
4924
5100
|
});
|
|
4925
5101
|
this.subscribeToNavigationEvents();
|
|
4926
5102
|
}
|
|
4927
5103
|
subscribeToNavigationEvents() {
|
|
4928
5104
|
const subscription = this.navigationTransitions.events.subscribe(e => {
|
|
4929
5105
|
try {
|
|
4930
|
-
const
|
|
4931
|
-
|
|
4932
|
-
|
|
4933
|
-
|
|
4934
|
-
|
|
4935
|
-
return;
|
|
4936
|
-
}
|
|
4937
|
-
if (e instanceof NavigationStart) {
|
|
4938
|
-
// If the source of the navigation is from a browser event, the URL is
|
|
4939
|
-
// already updated. We already need to sync the internal state.
|
|
4940
|
-
if (isBrowserTriggeredNavigation(currentTransition.source)) {
|
|
4941
|
-
this.browserUrlTree = currentTransition.extractedUrl;
|
|
4942
|
-
}
|
|
4943
|
-
}
|
|
4944
|
-
else if (e instanceof NavigationSkipped) {
|
|
4945
|
-
this.rawUrlTree = currentTransition.rawUrl;
|
|
4946
|
-
}
|
|
4947
|
-
else if (e instanceof RoutesRecognized) {
|
|
4948
|
-
if (this.urlUpdateStrategy === 'eager') {
|
|
4949
|
-
if (!currentTransition.extras.skipLocationChange) {
|
|
4950
|
-
const rawUrl = this.urlHandlingStrategy.merge(currentTransition.urlAfterRedirects, currentTransition.rawUrl);
|
|
4951
|
-
this.setBrowserUrl(rawUrl, currentTransition);
|
|
4952
|
-
}
|
|
4953
|
-
this.browserUrlTree = currentTransition.urlAfterRedirects;
|
|
4954
|
-
}
|
|
4955
|
-
}
|
|
4956
|
-
else if (e instanceof BeforeActivateRoutes) {
|
|
4957
|
-
this.currentUrlTree = currentTransition.urlAfterRedirects;
|
|
4958
|
-
this.rawUrlTree = this.urlHandlingStrategy.merge(currentTransition.urlAfterRedirects, currentTransition.rawUrl);
|
|
4959
|
-
this.routerState = currentTransition.targetRouterState;
|
|
4960
|
-
if (this.urlUpdateStrategy === 'deferred') {
|
|
4961
|
-
if (!currentTransition.extras.skipLocationChange) {
|
|
4962
|
-
this.setBrowserUrl(this.rawUrlTree, currentTransition);
|
|
4963
|
-
}
|
|
4964
|
-
this.browserUrlTree = currentTransition.urlAfterRedirects;
|
|
4965
|
-
}
|
|
4966
|
-
}
|
|
4967
|
-
else if (e instanceof NavigationCancel) {
|
|
4968
|
-
if (e.code !== 0 /* NavigationCancellationCode.Redirect */ &&
|
|
5106
|
+
const currentTransition = this.navigationTransitions.currentTransition;
|
|
5107
|
+
const currentNavigation = this.navigationTransitions.currentNavigation;
|
|
5108
|
+
if (currentTransition !== null && currentNavigation !== null) {
|
|
5109
|
+
this.stateManager.handleNavigationEvent(e, currentNavigation);
|
|
5110
|
+
if (e instanceof NavigationCancel && e.code !== 0 /* NavigationCancellationCode.Redirect */ &&
|
|
4969
5111
|
e.code !== 1 /* NavigationCancellationCode.SupersededByNewNavigation */) {
|
|
4970
5112
|
// It seems weird that `navigated` is set to `true` when the navigation is rejected,
|
|
4971
5113
|
// however it's how things were written initially. Investigation would need to be done
|
|
4972
5114
|
// to determine if this can be removed.
|
|
4973
5115
|
this.navigated = true;
|
|
4974
5116
|
}
|
|
4975
|
-
if (e
|
|
4976
|
-
|
|
4977
|
-
|
|
5117
|
+
else if (e instanceof NavigationEnd) {
|
|
5118
|
+
this.navigated = true;
|
|
5119
|
+
}
|
|
5120
|
+
else if (e instanceof RedirectRequest) {
|
|
5121
|
+
const mergedTree = this.urlHandlingStrategy.merge(e.url, currentTransition.currentRawUrl);
|
|
5122
|
+
const extras = {
|
|
5123
|
+
skipLocationChange: currentTransition.extras.skipLocationChange,
|
|
5124
|
+
// The URL is already updated at this point if we have 'eager' URL
|
|
5125
|
+
// updates or if the navigation was triggered by the browser (back
|
|
5126
|
+
// button, URL bar, etc). We want to replace that item in history
|
|
5127
|
+
// if the navigation is rejected.
|
|
5128
|
+
replaceUrl: this.urlUpdateStrategy === 'eager' ||
|
|
5129
|
+
isBrowserTriggeredNavigation(currentTransition.source)
|
|
5130
|
+
};
|
|
5131
|
+
this.scheduleNavigation(mergedTree, IMPERATIVE_NAVIGATION, null, extras, {
|
|
5132
|
+
resolve: currentTransition.resolve,
|
|
5133
|
+
reject: currentTransition.reject,
|
|
5134
|
+
promise: currentTransition.promise
|
|
5135
|
+
});
|
|
4978
5136
|
}
|
|
4979
|
-
}
|
|
4980
|
-
else if (e instanceof RedirectRequest) {
|
|
4981
|
-
const mergedTree = this.urlHandlingStrategy.merge(e.url, currentTransition.currentRawUrl);
|
|
4982
|
-
const extras = {
|
|
4983
|
-
skipLocationChange: currentTransition.extras.skipLocationChange,
|
|
4984
|
-
// The URL is already updated at this point if we have 'eager' URL
|
|
4985
|
-
// updates or if the navigation was triggered by the browser (back
|
|
4986
|
-
// button, URL bar, etc). We want to replace that item in history
|
|
4987
|
-
// if the navigation is rejected.
|
|
4988
|
-
replaceUrl: this.urlUpdateStrategy === 'eager' ||
|
|
4989
|
-
isBrowserTriggeredNavigation(currentTransition.source)
|
|
4990
|
-
};
|
|
4991
|
-
this.scheduleNavigation(mergedTree, IMPERATIVE_NAVIGATION, null, extras, {
|
|
4992
|
-
resolve: currentTransition.resolve,
|
|
4993
|
-
reject: currentTransition.reject,
|
|
4994
|
-
promise: currentTransition.promise
|
|
4995
|
-
});
|
|
4996
|
-
}
|
|
4997
|
-
if (e instanceof NavigationError) {
|
|
4998
|
-
this.restoreHistory(currentTransition, true);
|
|
4999
|
-
}
|
|
5000
|
-
if (e instanceof NavigationEnd) {
|
|
5001
|
-
this.navigated = true;
|
|
5002
5137
|
}
|
|
5003
5138
|
// Note that it's important to have the Router process the events _before_ the event is
|
|
5004
5139
|
// pushed through the public observable. This ensures the correct router state is in place
|
|
@@ -5120,7 +5255,6 @@ class Router {
|
|
|
5120
5255
|
(typeof ngDevMode === 'undefined' || ngDevMode) && validateConfig(config);
|
|
5121
5256
|
this.config = config.map(standardizeConfig);
|
|
5122
5257
|
this.navigated = false;
|
|
5123
|
-
this.lastSuccessfulId = -1;
|
|
5124
5258
|
}
|
|
5125
5259
|
/** @nodoc */
|
|
5126
5260
|
ngOnDestroy() {
|
|
@@ -5337,7 +5471,6 @@ class Router {
|
|
|
5337
5471
|
return result;
|
|
5338
5472
|
}, {});
|
|
5339
5473
|
}
|
|
5340
|
-
/** @internal */
|
|
5341
5474
|
scheduleNavigation(rawUrl, source, restoredState, extras, priorPromise) {
|
|
5342
5475
|
if (this.disposed) {
|
|
5343
5476
|
return Promise.resolve(false);
|
|
@@ -5383,88 +5516,10 @@ class Router {
|
|
|
5383
5516
|
return Promise.reject(e);
|
|
5384
5517
|
});
|
|
5385
5518
|
}
|
|
5386
|
-
|
|
5387
|
-
|
|
5388
|
-
const path = this.urlSerializer.serialize(url);
|
|
5389
|
-
if (this.location.isCurrentPathEqualTo(path) || !!transition.extras.replaceUrl) {
|
|
5390
|
-
// replacements do not update the target page
|
|
5391
|
-
const currentBrowserPageId = this.browserPageId;
|
|
5392
|
-
const state = {
|
|
5393
|
-
...transition.extras.state,
|
|
5394
|
-
...this.generateNgRouterState(transition.id, currentBrowserPageId)
|
|
5395
|
-
};
|
|
5396
|
-
this.location.replaceState(path, '', state);
|
|
5397
|
-
}
|
|
5398
|
-
else {
|
|
5399
|
-
const state = {
|
|
5400
|
-
...transition.extras.state,
|
|
5401
|
-
...this.generateNgRouterState(transition.id, this.browserPageId + 1)
|
|
5402
|
-
};
|
|
5403
|
-
this.location.go(path, '', state);
|
|
5404
|
-
}
|
|
5405
|
-
}
|
|
5406
|
-
/**
|
|
5407
|
-
* Performs the necessary rollback action to restore the browser URL to the
|
|
5408
|
-
* state before the transition.
|
|
5409
|
-
* @internal
|
|
5410
|
-
*/
|
|
5411
|
-
restoreHistory(transition, restoringFromCaughtError = false) {
|
|
5412
|
-
if (this.canceledNavigationResolution === 'computed') {
|
|
5413
|
-
const currentBrowserPageId = this.browserPageId;
|
|
5414
|
-
const targetPagePosition = this.currentPageId - currentBrowserPageId;
|
|
5415
|
-
if (targetPagePosition !== 0) {
|
|
5416
|
-
this.location.historyGo(targetPagePosition);
|
|
5417
|
-
}
|
|
5418
|
-
else if (this.currentUrlTree === this.getCurrentNavigation()?.finalUrl &&
|
|
5419
|
-
targetPagePosition === 0) {
|
|
5420
|
-
// We got to the activation stage (where currentUrlTree is set to the navigation's
|
|
5421
|
-
// finalUrl), but we weren't moving anywhere in history (skipLocationChange or replaceUrl).
|
|
5422
|
-
// We still need to reset the router state back to what it was when the navigation started.
|
|
5423
|
-
this.resetState(transition);
|
|
5424
|
-
// TODO(atscott): resetting the `browserUrlTree` should really be done in `resetState`.
|
|
5425
|
-
// Investigate if this can be done by running TGP.
|
|
5426
|
-
this.browserUrlTree = transition.currentUrlTree;
|
|
5427
|
-
this.resetUrlToCurrentUrlTree();
|
|
5428
|
-
}
|
|
5429
|
-
else {
|
|
5430
|
-
// The browser URL and router state was not updated before the navigation cancelled so
|
|
5431
|
-
// there's no restoration needed.
|
|
5432
|
-
}
|
|
5433
|
-
}
|
|
5434
|
-
else if (this.canceledNavigationResolution === 'replace') {
|
|
5435
|
-
// TODO(atscott): It seems like we should _always_ reset the state here. It would be a no-op
|
|
5436
|
-
// for `deferred` navigations that haven't change the internal state yet because guards
|
|
5437
|
-
// reject. For 'eager' navigations, it seems like we also really should reset the state
|
|
5438
|
-
// because the navigation was cancelled. Investigate if this can be done by running TGP.
|
|
5439
|
-
if (restoringFromCaughtError) {
|
|
5440
|
-
this.resetState(transition);
|
|
5441
|
-
}
|
|
5442
|
-
this.resetUrlToCurrentUrlTree();
|
|
5443
|
-
}
|
|
5444
|
-
}
|
|
5445
|
-
resetState(t) {
|
|
5446
|
-
this.routerState = t.currentRouterState;
|
|
5447
|
-
this.currentUrlTree = t.currentUrlTree;
|
|
5448
|
-
// Note here that we use the urlHandlingStrategy to get the reset `rawUrlTree` because it may be
|
|
5449
|
-
// configured to handle only part of the navigation URL. This means we would only want to reset
|
|
5450
|
-
// the part of the navigation handled by the Angular router rather than the whole URL. In
|
|
5451
|
-
// addition, the URLHandlingStrategy may be configured to specifically preserve parts of the URL
|
|
5452
|
-
// when merging, such as the query params so they are not lost on a refresh.
|
|
5453
|
-
this.rawUrlTree = this.urlHandlingStrategy.merge(this.currentUrlTree, t.rawUrl);
|
|
5454
|
-
}
|
|
5455
|
-
resetUrlToCurrentUrlTree() {
|
|
5456
|
-
this.location.replaceState(this.urlSerializer.serialize(this.rawUrlTree), '', this.generateNgRouterState(this.lastSuccessfulId, this.currentPageId));
|
|
5457
|
-
}
|
|
5458
|
-
generateNgRouterState(navigationId, routerPageId) {
|
|
5459
|
-
if (this.canceledNavigationResolution === 'computed') {
|
|
5460
|
-
return { navigationId, ɵrouterPageId: routerPageId };
|
|
5461
|
-
}
|
|
5462
|
-
return { navigationId };
|
|
5463
|
-
}
|
|
5464
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.0.0-next.2", ngImport: i0, type: Router, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
5465
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.0.0-next.2", ngImport: i0, type: Router, providedIn: 'root' }); }
|
|
5519
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.0.0-next.3", ngImport: i0, type: Router, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
5520
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.0.0-next.3", ngImport: i0, type: Router, providedIn: 'root' }); }
|
|
5466
5521
|
}
|
|
5467
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.0.0-next.
|
|
5522
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.0.0-next.3", ngImport: i0, type: Router, decorators: [{
|
|
5468
5523
|
type: Injectable,
|
|
5469
5524
|
args: [{ providedIn: 'root' }]
|
|
5470
5525
|
}], ctorParameters: function () { return []; } });
|
|
@@ -5735,10 +5790,10 @@ class RouterLink {
|
|
|
5735
5790
|
preserveFragment: this.preserveFragment,
|
|
5736
5791
|
});
|
|
5737
5792
|
}
|
|
5738
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.0.0-next.
|
|
5739
|
-
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "16.1.0", version: "17.0.0-next.
|
|
5793
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.0.0-next.3", ngImport: i0, type: RouterLink, deps: [{ token: Router }, { token: ActivatedRoute }, { token: 'tabindex', attribute: true }, { token: i0.Renderer2 }, { token: i0.ElementRef }, { token: i3.LocationStrategy }], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
5794
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "16.1.0", version: "17.0.0-next.3", type: RouterLink, isStandalone: true, selector: "[routerLink]", inputs: { target: "target", queryParams: "queryParams", fragment: "fragment", queryParamsHandling: "queryParamsHandling", state: "state", relativeTo: "relativeTo", preserveFragment: ["preserveFragment", "preserveFragment", booleanAttribute], skipLocationChange: ["skipLocationChange", "skipLocationChange", booleanAttribute], replaceUrl: ["replaceUrl", "replaceUrl", booleanAttribute], routerLink: "routerLink" }, host: { listeners: { "click": "onClick($event.button,$event.ctrlKey,$event.shiftKey,$event.altKey,$event.metaKey)" }, properties: { "attr.target": "this.target" } }, usesOnChanges: true, ngImport: i0 }); }
|
|
5740
5795
|
}
|
|
5741
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.0.0-next.
|
|
5796
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.0.0-next.3", ngImport: i0, type: RouterLink, decorators: [{
|
|
5742
5797
|
type: Directive,
|
|
5743
5798
|
args: [{
|
|
5744
5799
|
selector: '[routerLink]',
|
|
@@ -5961,10 +6016,10 @@ class RouterLinkActive {
|
|
|
5961
6016
|
const isActiveCheckFn = this.isLinkActive(this.router);
|
|
5962
6017
|
return this.link && isActiveCheckFn(this.link) || this.links.some(isActiveCheckFn);
|
|
5963
6018
|
}
|
|
5964
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.0.0-next.
|
|
5965
|
-
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "17.0.0-next.
|
|
6019
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.0.0-next.3", ngImport: i0, type: RouterLinkActive, deps: [{ token: Router }, { token: i0.ElementRef }, { token: i0.Renderer2 }, { token: i0.ChangeDetectorRef }, { token: RouterLink, optional: true }], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
6020
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "17.0.0-next.3", type: RouterLinkActive, isStandalone: true, selector: "[routerLinkActive]", inputs: { routerLinkActiveOptions: "routerLinkActiveOptions", ariaCurrentWhenActive: "ariaCurrentWhenActive", routerLinkActive: "routerLinkActive" }, outputs: { isActiveChange: "isActiveChange" }, queries: [{ propertyName: "links", predicate: RouterLink, descendants: true }], exportAs: ["routerLinkActive"], usesOnChanges: true, ngImport: i0 }); }
|
|
5966
6021
|
}
|
|
5967
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.0.0-next.
|
|
6022
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.0.0-next.3", ngImport: i0, type: RouterLinkActive, decorators: [{
|
|
5968
6023
|
type: Directive,
|
|
5969
6024
|
args: [{
|
|
5970
6025
|
selector: '[routerLinkActive]',
|
|
@@ -6016,10 +6071,10 @@ class PreloadAllModules {
|
|
|
6016
6071
|
preload(route, fn) {
|
|
6017
6072
|
return fn().pipe(catchError(() => of(null)));
|
|
6018
6073
|
}
|
|
6019
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.0.0-next.
|
|
6020
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.0.0-next.
|
|
6074
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.0.0-next.3", ngImport: i0, type: PreloadAllModules, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
6075
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.0.0-next.3", ngImport: i0, type: PreloadAllModules, providedIn: 'root' }); }
|
|
6021
6076
|
}
|
|
6022
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.0.0-next.
|
|
6077
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.0.0-next.3", ngImport: i0, type: PreloadAllModules, decorators: [{
|
|
6023
6078
|
type: Injectable,
|
|
6024
6079
|
args: [{ providedIn: 'root' }]
|
|
6025
6080
|
}] });
|
|
@@ -6036,10 +6091,10 @@ class NoPreloading {
|
|
|
6036
6091
|
preload(route, fn) {
|
|
6037
6092
|
return of(null);
|
|
6038
6093
|
}
|
|
6039
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.0.0-next.
|
|
6040
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.0.0-next.
|
|
6094
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.0.0-next.3", ngImport: i0, type: NoPreloading, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
6095
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.0.0-next.3", ngImport: i0, type: NoPreloading, providedIn: 'root' }); }
|
|
6041
6096
|
}
|
|
6042
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.0.0-next.
|
|
6097
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.0.0-next.3", ngImport: i0, type: NoPreloading, decorators: [{
|
|
6043
6098
|
type: Injectable,
|
|
6044
6099
|
args: [{ providedIn: 'root' }]
|
|
6045
6100
|
}] });
|
|
@@ -6132,10 +6187,10 @@ class RouterPreloader {
|
|
|
6132
6187
|
}
|
|
6133
6188
|
});
|
|
6134
6189
|
}
|
|
6135
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.0.0-next.
|
|
6136
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.0.0-next.
|
|
6190
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.0.0-next.3", ngImport: i0, type: RouterPreloader, deps: [{ token: Router }, { token: i0.Compiler }, { token: i0.EnvironmentInjector }, { token: PreloadingStrategy }, { token: RouterConfigLoader }], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
6191
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.0.0-next.3", ngImport: i0, type: RouterPreloader, providedIn: 'root' }); }
|
|
6137
6192
|
}
|
|
6138
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.0.0-next.
|
|
6193
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.0.0-next.3", ngImport: i0, type: RouterPreloader, decorators: [{
|
|
6139
6194
|
type: Injectable,
|
|
6140
6195
|
args: [{ providedIn: 'root' }]
|
|
6141
6196
|
}], ctorParameters: function () { return [{ type: Router }, { type: i0.Compiler }, { type: i0.EnvironmentInjector }, { type: PreloadingStrategy }, { type: RouterConfigLoader }]; } });
|
|
@@ -6228,10 +6283,10 @@ class RouterScroller {
|
|
|
6228
6283
|
this.routerEventsSubscription?.unsubscribe();
|
|
6229
6284
|
this.scrollEventsSubscription?.unsubscribe();
|
|
6230
6285
|
}
|
|
6231
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.0.0-next.
|
|
6232
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.0.0-next.
|
|
6286
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.0.0-next.3", ngImport: i0, type: RouterScroller, deps: "invalid", target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
6287
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.0.0-next.3", ngImport: i0, type: RouterScroller }); }
|
|
6233
6288
|
}
|
|
6234
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.0.0-next.
|
|
6289
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.0.0-next.3", ngImport: i0, type: RouterScroller, decorators: [{
|
|
6235
6290
|
type: Injectable
|
|
6236
6291
|
}], ctorParameters: function () { return [{ type: UrlSerializer }, { type: NavigationTransitions }, { type: i3.ViewportScroller }, { type: i0.NgZone }, { type: undefined }]; } });
|
|
6237
6292
|
|
|
@@ -6838,11 +6893,11 @@ class RouterModule {
|
|
|
6838
6893
|
providers: [{ provide: ROUTES, multi: true, useValue: routes }],
|
|
6839
6894
|
};
|
|
6840
6895
|
}
|
|
6841
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.0.0-next.
|
|
6842
|
-
static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "17.0.0-next.
|
|
6843
|
-
static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "17.0.0-next.
|
|
6896
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.0.0-next.3", ngImport: i0, type: RouterModule, deps: [{ token: ROUTER_FORROOT_GUARD, optional: true }], target: i0.ɵɵFactoryTarget.NgModule }); }
|
|
6897
|
+
static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "17.0.0-next.3", ngImport: i0, type: RouterModule, imports: [RouterOutlet, RouterLink, RouterLinkActive, ɵEmptyOutletComponent], exports: [RouterOutlet, RouterLink, RouterLinkActive, ɵEmptyOutletComponent] }); }
|
|
6898
|
+
static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "17.0.0-next.3", ngImport: i0, type: RouterModule }); }
|
|
6844
6899
|
}
|
|
6845
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.0.0-next.
|
|
6900
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.0.0-next.3", ngImport: i0, type: RouterModule, decorators: [{
|
|
6846
6901
|
type: NgModule,
|
|
6847
6902
|
args: [{
|
|
6848
6903
|
imports: ROUTER_DIRECTIVES,
|
|
@@ -6987,7 +7042,7 @@ function mapToResolve(provider) {
|
|
|
6987
7042
|
/**
|
|
6988
7043
|
* @publicApi
|
|
6989
7044
|
*/
|
|
6990
|
-
const VERSION = new Version('17.0.0-next.
|
|
7045
|
+
const VERSION = new Version('17.0.0-next.3');
|
|
6991
7046
|
|
|
6992
7047
|
/**
|
|
6993
7048
|
* @module
|