You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
5589 lines
192 KiB
5589 lines
192 KiB
import {
|
|
Title
|
|
} from "./chunk-Y4CEYMY2.js";
|
|
import "./chunk-X7WBA24Z.js";
|
|
import {
|
|
DOCUMENT,
|
|
HashLocationStrategy,
|
|
LOCATION_INITIALIZED,
|
|
Location,
|
|
LocationStrategy,
|
|
PathLocationStrategy,
|
|
ViewportScroller
|
|
} from "./chunk-OSQBUYO6.js";
|
|
import {
|
|
APP_BOOTSTRAP_LISTENER,
|
|
APP_INITIALIZER,
|
|
ApplicationRef,
|
|
Attribute,
|
|
BehaviorSubject,
|
|
ChangeDetectorRef,
|
|
Compiler,
|
|
Component,
|
|
ConnectableObservable,
|
|
Console,
|
|
ContentChildren,
|
|
Directive,
|
|
EMPTY,
|
|
ENVIRONMENT_INITIALIZER,
|
|
ElementRef,
|
|
EmptyError,
|
|
EnvironmentInjector,
|
|
EventEmitter,
|
|
HostBinding,
|
|
HostListener,
|
|
InitialRenderPendingTasks,
|
|
Inject,
|
|
InjectFlags,
|
|
Injectable,
|
|
InjectionToken,
|
|
Injector,
|
|
Input,
|
|
NgModule,
|
|
NgModuleFactory$1,
|
|
NgZone,
|
|
Optional,
|
|
Output,
|
|
Renderer2,
|
|
RuntimeError,
|
|
SkipSelf,
|
|
Subject,
|
|
Subscription,
|
|
Version,
|
|
ViewContainerRef,
|
|
afterNextRender,
|
|
booleanAttribute,
|
|
catchError,
|
|
combineLatest,
|
|
concat,
|
|
concatMap,
|
|
createEnvironmentInjector,
|
|
defaultIfEmpty,
|
|
defer,
|
|
filter,
|
|
finalize,
|
|
first,
|
|
from,
|
|
inject,
|
|
isInjectable,
|
|
isNgModule,
|
|
isObservable,
|
|
isPromise,
|
|
isStandalone,
|
|
last,
|
|
makeEnvironmentProviders,
|
|
map,
|
|
mapTo,
|
|
mergeAll,
|
|
mergeMap,
|
|
of,
|
|
pipe,
|
|
refCount,
|
|
reflectComponentType,
|
|
runInInjectionContext,
|
|
scan,
|
|
setClassMetadata,
|
|
startWith,
|
|
switchMap,
|
|
take,
|
|
takeLast,
|
|
takeUntil,
|
|
tap,
|
|
throwError,
|
|
ɵɵInputTransformsFeature,
|
|
ɵɵNgOnChangesFeature,
|
|
ɵɵStandaloneFeature,
|
|
ɵɵattribute,
|
|
ɵɵcontentQuery,
|
|
ɵɵdefineComponent,
|
|
ɵɵdefineDirective,
|
|
ɵɵdefineInjectable,
|
|
ɵɵdefineInjector,
|
|
ɵɵdefineNgModule,
|
|
ɵɵdirectiveInject,
|
|
ɵɵelement,
|
|
ɵɵgetInheritedFactory,
|
|
ɵɵinject,
|
|
ɵɵinjectAttribute,
|
|
ɵɵinvalidFactory,
|
|
ɵɵlistener,
|
|
ɵɵloadQuery,
|
|
ɵɵqueryRefresh,
|
|
ɵɵsanitizeUrlOrResourceUrl
|
|
} from "./chunk-FGESKT7O.js";
|
|
import {
|
|
__spreadProps,
|
|
__spreadValues
|
|
} from "./chunk-HSNDBVJ3.js";
|
|
|
|
// node_modules/@angular/router/fesm2022/router.mjs
|
|
var PRIMARY_OUTLET = "primary";
|
|
var RouteTitleKey = Symbol("RouteTitle");
|
|
var ParamsAsMap = class {
|
|
constructor(params) {
|
|
this.params = params || {};
|
|
}
|
|
has(name) {
|
|
return Object.prototype.hasOwnProperty.call(this.params, name);
|
|
}
|
|
get(name) {
|
|
if (this.has(name)) {
|
|
const v = this.params[name];
|
|
return Array.isArray(v) ? v[0] : v;
|
|
}
|
|
return null;
|
|
}
|
|
getAll(name) {
|
|
if (this.has(name)) {
|
|
const v = this.params[name];
|
|
return Array.isArray(v) ? v : [v];
|
|
}
|
|
return [];
|
|
}
|
|
get keys() {
|
|
return Object.keys(this.params);
|
|
}
|
|
};
|
|
function convertToParamMap(params) {
|
|
return new ParamsAsMap(params);
|
|
}
|
|
function defaultUrlMatcher(segments, segmentGroup, route) {
|
|
const parts = route.path.split("/");
|
|
if (parts.length > segments.length) {
|
|
return null;
|
|
}
|
|
if (route.pathMatch === "full" && (segmentGroup.hasChildren() || parts.length < segments.length)) {
|
|
return null;
|
|
}
|
|
const posParams = {};
|
|
for (let index = 0; index < parts.length; index++) {
|
|
const part = parts[index];
|
|
const segment = segments[index];
|
|
const isParameter = part.startsWith(":");
|
|
if (isParameter) {
|
|
posParams[part.substring(1)] = segment;
|
|
} else if (part !== segment.path) {
|
|
return null;
|
|
}
|
|
}
|
|
return {
|
|
consumed: segments.slice(0, parts.length),
|
|
posParams
|
|
};
|
|
}
|
|
function shallowEqualArrays(a, b) {
|
|
if (a.length !== b.length)
|
|
return false;
|
|
for (let i = 0; i < a.length; ++i) {
|
|
if (!shallowEqual(a[i], b[i]))
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
function shallowEqual(a, b) {
|
|
const k1 = a ? getDataKeys(a) : void 0;
|
|
const k2 = b ? getDataKeys(b) : void 0;
|
|
if (!k1 || !k2 || k1.length != k2.length) {
|
|
return false;
|
|
}
|
|
let key;
|
|
for (let i = 0; i < k1.length; i++) {
|
|
key = k1[i];
|
|
if (!equalArraysOrString(a[key], b[key])) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
function getDataKeys(obj) {
|
|
return [...Object.keys(obj), ...Object.getOwnPropertySymbols(obj)];
|
|
}
|
|
function equalArraysOrString(a, b) {
|
|
if (Array.isArray(a) && Array.isArray(b)) {
|
|
if (a.length !== b.length)
|
|
return false;
|
|
const aSorted = [...a].sort();
|
|
const bSorted = [...b].sort();
|
|
return aSorted.every((val, index) => bSorted[index] === val);
|
|
} else {
|
|
return a === b;
|
|
}
|
|
}
|
|
function last2(a) {
|
|
return a.length > 0 ? a[a.length - 1] : null;
|
|
}
|
|
function wrapIntoObservable(value) {
|
|
if (isObservable(value)) {
|
|
return value;
|
|
}
|
|
if (isPromise(value)) {
|
|
return from(Promise.resolve(value));
|
|
}
|
|
return of(value);
|
|
}
|
|
var pathCompareMap = {
|
|
"exact": equalSegmentGroups,
|
|
"subset": containsSegmentGroup
|
|
};
|
|
var paramCompareMap = {
|
|
"exact": equalParams,
|
|
"subset": containsParams,
|
|
"ignored": () => true
|
|
};
|
|
function containsTree(container, containee, options) {
|
|
return pathCompareMap[options.paths](container.root, containee.root, options.matrixParams) && paramCompareMap[options.queryParams](container.queryParams, containee.queryParams) && !(options.fragment === "exact" && container.fragment !== containee.fragment);
|
|
}
|
|
function equalParams(container, containee) {
|
|
return shallowEqual(container, containee);
|
|
}
|
|
function equalSegmentGroups(container, containee, matrixParams) {
|
|
if (!equalPath(container.segments, containee.segments))
|
|
return false;
|
|
if (!matrixParamsMatch(container.segments, containee.segments, matrixParams)) {
|
|
return false;
|
|
}
|
|
if (container.numberOfChildren !== containee.numberOfChildren)
|
|
return false;
|
|
for (const c in containee.children) {
|
|
if (!container.children[c])
|
|
return false;
|
|
if (!equalSegmentGroups(container.children[c], containee.children[c], matrixParams))
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
function containsParams(container, containee) {
|
|
return Object.keys(containee).length <= Object.keys(container).length && Object.keys(containee).every((key) => equalArraysOrString(container[key], containee[key]));
|
|
}
|
|
function containsSegmentGroup(container, containee, matrixParams) {
|
|
return containsSegmentGroupHelper(container, containee, containee.segments, matrixParams);
|
|
}
|
|
function containsSegmentGroupHelper(container, containee, containeePaths, matrixParams) {
|
|
if (container.segments.length > containeePaths.length) {
|
|
const current = container.segments.slice(0, containeePaths.length);
|
|
if (!equalPath(current, containeePaths))
|
|
return false;
|
|
if (containee.hasChildren())
|
|
return false;
|
|
if (!matrixParamsMatch(current, containeePaths, matrixParams))
|
|
return false;
|
|
return true;
|
|
} else if (container.segments.length === containeePaths.length) {
|
|
if (!equalPath(container.segments, containeePaths))
|
|
return false;
|
|
if (!matrixParamsMatch(container.segments, containeePaths, matrixParams))
|
|
return false;
|
|
for (const c in containee.children) {
|
|
if (!container.children[c])
|
|
return false;
|
|
if (!containsSegmentGroup(container.children[c], containee.children[c], matrixParams)) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
} else {
|
|
const current = containeePaths.slice(0, container.segments.length);
|
|
const next = containeePaths.slice(container.segments.length);
|
|
if (!equalPath(container.segments, current))
|
|
return false;
|
|
if (!matrixParamsMatch(container.segments, current, matrixParams))
|
|
return false;
|
|
if (!container.children[PRIMARY_OUTLET])
|
|
return false;
|
|
return containsSegmentGroupHelper(container.children[PRIMARY_OUTLET], containee, next, matrixParams);
|
|
}
|
|
}
|
|
function matrixParamsMatch(containerPaths, containeePaths, options) {
|
|
return containeePaths.every((containeeSegment, i) => {
|
|
return paramCompareMap[options](containerPaths[i].parameters, containeeSegment.parameters);
|
|
});
|
|
}
|
|
var UrlTree = class {
|
|
constructor(root = new UrlSegmentGroup([], {}), queryParams = {}, fragment = null) {
|
|
this.root = root;
|
|
this.queryParams = queryParams;
|
|
this.fragment = fragment;
|
|
if (typeof ngDevMode === "undefined" || ngDevMode) {
|
|
if (root.segments.length > 0) {
|
|
throw new RuntimeError(4015, "The root `UrlSegmentGroup` should not contain `segments`. Instead, these segments belong in the `children` so they can be associated with a named outlet.");
|
|
}
|
|
}
|
|
}
|
|
get queryParamMap() {
|
|
if (!this._queryParamMap) {
|
|
this._queryParamMap = convertToParamMap(this.queryParams);
|
|
}
|
|
return this._queryParamMap;
|
|
}
|
|
/** @docsNotRequired */
|
|
toString() {
|
|
return DEFAULT_SERIALIZER.serialize(this);
|
|
}
|
|
};
|
|
var UrlSegmentGroup = class {
|
|
constructor(segments, children) {
|
|
this.segments = segments;
|
|
this.children = children;
|
|
this.parent = null;
|
|
Object.values(children).forEach((v) => v.parent = this);
|
|
}
|
|
/** Whether the segment has child segments */
|
|
hasChildren() {
|
|
return this.numberOfChildren > 0;
|
|
}
|
|
/** Number of child segments */
|
|
get numberOfChildren() {
|
|
return Object.keys(this.children).length;
|
|
}
|
|
/** @docsNotRequired */
|
|
toString() {
|
|
return serializePaths(this);
|
|
}
|
|
};
|
|
var UrlSegment = class {
|
|
constructor(path, parameters) {
|
|
this.path = path;
|
|
this.parameters = parameters;
|
|
}
|
|
get parameterMap() {
|
|
if (!this._parameterMap) {
|
|
this._parameterMap = convertToParamMap(this.parameters);
|
|
}
|
|
return this._parameterMap;
|
|
}
|
|
/** @docsNotRequired */
|
|
toString() {
|
|
return serializePath(this);
|
|
}
|
|
};
|
|
function equalSegments(as, bs) {
|
|
return equalPath(as, bs) && as.every((a, i) => shallowEqual(a.parameters, bs[i].parameters));
|
|
}
|
|
function equalPath(as, bs) {
|
|
if (as.length !== bs.length)
|
|
return false;
|
|
return as.every((a, i) => a.path === bs[i].path);
|
|
}
|
|
function mapChildrenIntoArray(segment, fn) {
|
|
let res = [];
|
|
Object.entries(segment.children).forEach(([childOutlet, child]) => {
|
|
if (childOutlet === PRIMARY_OUTLET) {
|
|
res = res.concat(fn(child, childOutlet));
|
|
}
|
|
});
|
|
Object.entries(segment.children).forEach(([childOutlet, child]) => {
|
|
if (childOutlet !== PRIMARY_OUTLET) {
|
|
res = res.concat(fn(child, childOutlet));
|
|
}
|
|
});
|
|
return res;
|
|
}
|
|
var _UrlSerializer = class _UrlSerializer {
|
|
};
|
|
_UrlSerializer.ɵfac = function UrlSerializer_Factory(t) {
|
|
return new (t || _UrlSerializer)();
|
|
};
|
|
_UrlSerializer.ɵprov = ɵɵdefineInjectable({
|
|
token: _UrlSerializer,
|
|
factory: () => (() => new DefaultUrlSerializer())(),
|
|
providedIn: "root"
|
|
});
|
|
var UrlSerializer = _UrlSerializer;
|
|
(() => {
|
|
(typeof ngDevMode === "undefined" || ngDevMode) && setClassMetadata(UrlSerializer, [{
|
|
type: Injectable,
|
|
args: [{
|
|
providedIn: "root",
|
|
useFactory: () => new DefaultUrlSerializer()
|
|
}]
|
|
}], null, null);
|
|
})();
|
|
var DefaultUrlSerializer = class {
|
|
/** Parses a url into a `UrlTree` */
|
|
parse(url) {
|
|
const p = new UrlParser(url);
|
|
return new UrlTree(p.parseRootSegment(), p.parseQueryParams(), p.parseFragment());
|
|
}
|
|
/** Converts a `UrlTree` into a url */
|
|
serialize(tree2) {
|
|
const segment = `/${serializeSegment(tree2.root, true)}`;
|
|
const query = serializeQueryParams(tree2.queryParams);
|
|
const fragment = typeof tree2.fragment === `string` ? `#${encodeUriFragment(tree2.fragment)}` : "";
|
|
return `${segment}${query}${fragment}`;
|
|
}
|
|
};
|
|
var DEFAULT_SERIALIZER = new DefaultUrlSerializer();
|
|
function serializePaths(segment) {
|
|
return segment.segments.map((p) => serializePath(p)).join("/");
|
|
}
|
|
function serializeSegment(segment, root) {
|
|
if (!segment.hasChildren()) {
|
|
return serializePaths(segment);
|
|
}
|
|
if (root) {
|
|
const primary = segment.children[PRIMARY_OUTLET] ? serializeSegment(segment.children[PRIMARY_OUTLET], false) : "";
|
|
const children = [];
|
|
Object.entries(segment.children).forEach(([k, v]) => {
|
|
if (k !== PRIMARY_OUTLET) {
|
|
children.push(`${k}:${serializeSegment(v, false)}`);
|
|
}
|
|
});
|
|
return children.length > 0 ? `${primary}(${children.join("//")})` : primary;
|
|
} else {
|
|
const children = mapChildrenIntoArray(segment, (v, k) => {
|
|
if (k === PRIMARY_OUTLET) {
|
|
return [serializeSegment(segment.children[PRIMARY_OUTLET], false)];
|
|
}
|
|
return [`${k}:${serializeSegment(v, false)}`];
|
|
});
|
|
if (Object.keys(segment.children).length === 1 && segment.children[PRIMARY_OUTLET] != null) {
|
|
return `${serializePaths(segment)}/${children[0]}`;
|
|
}
|
|
return `${serializePaths(segment)}/(${children.join("//")})`;
|
|
}
|
|
}
|
|
function encodeUriString(s) {
|
|
return encodeURIComponent(s).replace(/%40/g, "@").replace(/%3A/gi, ":").replace(/%24/g, "$").replace(/%2C/gi, ",");
|
|
}
|
|
function encodeUriQuery(s) {
|
|
return encodeUriString(s).replace(/%3B/gi, ";");
|
|
}
|
|
function encodeUriFragment(s) {
|
|
return encodeURI(s);
|
|
}
|
|
function encodeUriSegment(s) {
|
|
return encodeUriString(s).replace(/\(/g, "%28").replace(/\)/g, "%29").replace(/%26/gi, "&");
|
|
}
|
|
function decode(s) {
|
|
return decodeURIComponent(s);
|
|
}
|
|
function decodeQuery(s) {
|
|
return decode(s.replace(/\+/g, "%20"));
|
|
}
|
|
function serializePath(path) {
|
|
return `${encodeUriSegment(path.path)}${serializeMatrixParams(path.parameters)}`;
|
|
}
|
|
function serializeMatrixParams(params) {
|
|
return Object.keys(params).map((key) => `;${encodeUriSegment(key)}=${encodeUriSegment(params[key])}`).join("");
|
|
}
|
|
function serializeQueryParams(params) {
|
|
const strParams = Object.keys(params).map((name) => {
|
|
const value = params[name];
|
|
return Array.isArray(value) ? value.map((v) => `${encodeUriQuery(name)}=${encodeUriQuery(v)}`).join("&") : `${encodeUriQuery(name)}=${encodeUriQuery(value)}`;
|
|
}).filter((s) => !!s);
|
|
return strParams.length ? `?${strParams.join("&")}` : "";
|
|
}
|
|
var SEGMENT_RE = /^[^\/()?;#]+/;
|
|
function matchSegments(str) {
|
|
const match2 = str.match(SEGMENT_RE);
|
|
return match2 ? match2[0] : "";
|
|
}
|
|
var MATRIX_PARAM_SEGMENT_RE = /^[^\/()?;=#]+/;
|
|
function matchMatrixKeySegments(str) {
|
|
const match2 = str.match(MATRIX_PARAM_SEGMENT_RE);
|
|
return match2 ? match2[0] : "";
|
|
}
|
|
var QUERY_PARAM_RE = /^[^=?&#]+/;
|
|
function matchQueryParams(str) {
|
|
const match2 = str.match(QUERY_PARAM_RE);
|
|
return match2 ? match2[0] : "";
|
|
}
|
|
var QUERY_PARAM_VALUE_RE = /^[^&#]+/;
|
|
function matchUrlQueryParamValue(str) {
|
|
const match2 = str.match(QUERY_PARAM_VALUE_RE);
|
|
return match2 ? match2[0] : "";
|
|
}
|
|
var UrlParser = class {
|
|
constructor(url) {
|
|
this.url = url;
|
|
this.remaining = url;
|
|
}
|
|
parseRootSegment() {
|
|
this.consumeOptional("/");
|
|
if (this.remaining === "" || this.peekStartsWith("?") || this.peekStartsWith("#")) {
|
|
return new UrlSegmentGroup([], {});
|
|
}
|
|
return new UrlSegmentGroup([], this.parseChildren());
|
|
}
|
|
parseQueryParams() {
|
|
const params = {};
|
|
if (this.consumeOptional("?")) {
|
|
do {
|
|
this.parseQueryParam(params);
|
|
} while (this.consumeOptional("&"));
|
|
}
|
|
return params;
|
|
}
|
|
parseFragment() {
|
|
return this.consumeOptional("#") ? decodeURIComponent(this.remaining) : null;
|
|
}
|
|
parseChildren() {
|
|
if (this.remaining === "") {
|
|
return {};
|
|
}
|
|
this.consumeOptional("/");
|
|
const segments = [];
|
|
if (!this.peekStartsWith("(")) {
|
|
segments.push(this.parseSegment());
|
|
}
|
|
while (this.peekStartsWith("/") && !this.peekStartsWith("//") && !this.peekStartsWith("/(")) {
|
|
this.capture("/");
|
|
segments.push(this.parseSegment());
|
|
}
|
|
let children = {};
|
|
if (this.peekStartsWith("/(")) {
|
|
this.capture("/");
|
|
children = this.parseParens(true);
|
|
}
|
|
let res = {};
|
|
if (this.peekStartsWith("(")) {
|
|
res = this.parseParens(false);
|
|
}
|
|
if (segments.length > 0 || Object.keys(children).length > 0) {
|
|
res[PRIMARY_OUTLET] = new UrlSegmentGroup(segments, children);
|
|
}
|
|
return res;
|
|
}
|
|
// parse a segment with its matrix parameters
|
|
// ie `name;k1=v1;k2`
|
|
parseSegment() {
|
|
const path = matchSegments(this.remaining);
|
|
if (path === "" && this.peekStartsWith(";")) {
|
|
throw new RuntimeError(4009, (typeof ngDevMode === "undefined" || ngDevMode) && `Empty path url segment cannot have parameters: '${this.remaining}'.`);
|
|
}
|
|
this.capture(path);
|
|
return new UrlSegment(decode(path), this.parseMatrixParams());
|
|
}
|
|
parseMatrixParams() {
|
|
const params = {};
|
|
while (this.consumeOptional(";")) {
|
|
this.parseParam(params);
|
|
}
|
|
return params;
|
|
}
|
|
parseParam(params) {
|
|
const key = matchMatrixKeySegments(this.remaining);
|
|
if (!key) {
|
|
return;
|
|
}
|
|
this.capture(key);
|
|
let value = "";
|
|
if (this.consumeOptional("=")) {
|
|
const valueMatch = matchSegments(this.remaining);
|
|
if (valueMatch) {
|
|
value = valueMatch;
|
|
this.capture(value);
|
|
}
|
|
}
|
|
params[decode(key)] = decode(value);
|
|
}
|
|
// Parse a single query parameter `name[=value]`
|
|
parseQueryParam(params) {
|
|
const key = matchQueryParams(this.remaining);
|
|
if (!key) {
|
|
return;
|
|
}
|
|
this.capture(key);
|
|
let value = "";
|
|
if (this.consumeOptional("=")) {
|
|
const valueMatch = matchUrlQueryParamValue(this.remaining);
|
|
if (valueMatch) {
|
|
value = valueMatch;
|
|
this.capture(value);
|
|
}
|
|
}
|
|
const decodedKey = decodeQuery(key);
|
|
const decodedVal = decodeQuery(value);
|
|
if (params.hasOwnProperty(decodedKey)) {
|
|
let currentVal = params[decodedKey];
|
|
if (!Array.isArray(currentVal)) {
|
|
currentVal = [currentVal];
|
|
params[decodedKey] = currentVal;
|
|
}
|
|
currentVal.push(decodedVal);
|
|
} else {
|
|
params[decodedKey] = decodedVal;
|
|
}
|
|
}
|
|
// parse `(a/b//outlet_name:c/d)`
|
|
parseParens(allowPrimary) {
|
|
const segments = {};
|
|
this.capture("(");
|
|
while (!this.consumeOptional(")") && this.remaining.length > 0) {
|
|
const path = matchSegments(this.remaining);
|
|
const next = this.remaining[path.length];
|
|
if (next !== "/" && next !== ")" && next !== ";") {
|
|
throw new RuntimeError(4010, (typeof ngDevMode === "undefined" || ngDevMode) && `Cannot parse url '${this.url}'`);
|
|
}
|
|
let outletName = void 0;
|
|
if (path.indexOf(":") > -1) {
|
|
outletName = path.slice(0, path.indexOf(":"));
|
|
this.capture(outletName);
|
|
this.capture(":");
|
|
} else if (allowPrimary) {
|
|
outletName = PRIMARY_OUTLET;
|
|
}
|
|
const children = this.parseChildren();
|
|
segments[outletName] = Object.keys(children).length === 1 ? children[PRIMARY_OUTLET] : new UrlSegmentGroup([], children);
|
|
this.consumeOptional("//");
|
|
}
|
|
return segments;
|
|
}
|
|
peekStartsWith(str) {
|
|
return this.remaining.startsWith(str);
|
|
}
|
|
// Consumes the prefix when it is present and returns whether it has been consumed
|
|
consumeOptional(str) {
|
|
if (this.peekStartsWith(str)) {
|
|
this.remaining = this.remaining.substring(str.length);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
capture(str) {
|
|
if (!this.consumeOptional(str)) {
|
|
throw new RuntimeError(4011, (typeof ngDevMode === "undefined" || ngDevMode) && `Expected "${str}".`);
|
|
}
|
|
}
|
|
};
|
|
function createRoot(rootCandidate) {
|
|
return rootCandidate.segments.length > 0 ? new UrlSegmentGroup([], {
|
|
[PRIMARY_OUTLET]: rootCandidate
|
|
}) : rootCandidate;
|
|
}
|
|
function squashSegmentGroup(segmentGroup) {
|
|
const newChildren = {};
|
|
for (const childOutlet of Object.keys(segmentGroup.children)) {
|
|
const child = segmentGroup.children[childOutlet];
|
|
const childCandidate = squashSegmentGroup(child);
|
|
if (childOutlet === PRIMARY_OUTLET && childCandidate.segments.length === 0 && childCandidate.hasChildren()) {
|
|
for (const [grandChildOutlet, grandChild] of Object.entries(childCandidate.children)) {
|
|
newChildren[grandChildOutlet] = grandChild;
|
|
}
|
|
} else if (childCandidate.segments.length > 0 || childCandidate.hasChildren()) {
|
|
newChildren[childOutlet] = childCandidate;
|
|
}
|
|
}
|
|
const s = new UrlSegmentGroup(segmentGroup.segments, newChildren);
|
|
return mergeTrivialChildren(s);
|
|
}
|
|
function mergeTrivialChildren(s) {
|
|
if (s.numberOfChildren === 1 && s.children[PRIMARY_OUTLET]) {
|
|
const c = s.children[PRIMARY_OUTLET];
|
|
return new UrlSegmentGroup(s.segments.concat(c.segments), c.children);
|
|
}
|
|
return s;
|
|
}
|
|
function isUrlTree(v) {
|
|
return v instanceof UrlTree;
|
|
}
|
|
function createUrlTreeFromSnapshot(relativeTo, commands, queryParams = null, fragment = null) {
|
|
const relativeToUrlSegmentGroup = createSegmentGroupFromRoute(relativeTo);
|
|
return createUrlTreeFromSegmentGroup(relativeToUrlSegmentGroup, commands, queryParams, fragment);
|
|
}
|
|
function createSegmentGroupFromRoute(route) {
|
|
let targetGroup;
|
|
function createSegmentGroupFromRouteRecursive(currentRoute) {
|
|
const childOutlets = {};
|
|
for (const childSnapshot of currentRoute.children) {
|
|
const root = createSegmentGroupFromRouteRecursive(childSnapshot);
|
|
childOutlets[childSnapshot.outlet] = root;
|
|
}
|
|
const segmentGroup = new UrlSegmentGroup(currentRoute.url, childOutlets);
|
|
if (currentRoute === route) {
|
|
targetGroup = segmentGroup;
|
|
}
|
|
return segmentGroup;
|
|
}
|
|
const rootCandidate = createSegmentGroupFromRouteRecursive(route.root);
|
|
const rootSegmentGroup = createRoot(rootCandidate);
|
|
return targetGroup ?? rootSegmentGroup;
|
|
}
|
|
function createUrlTreeFromSegmentGroup(relativeTo, commands, queryParams, fragment) {
|
|
let root = relativeTo;
|
|
while (root.parent) {
|
|
root = root.parent;
|
|
}
|
|
if (commands.length === 0) {
|
|
return tree(root, root, root, queryParams, fragment);
|
|
}
|
|
const nav = computeNavigation(commands);
|
|
if (nav.toRoot()) {
|
|
return tree(root, root, new UrlSegmentGroup([], {}), queryParams, fragment);
|
|
}
|
|
const position = findStartingPositionForTargetGroup(nav, root, relativeTo);
|
|
const newSegmentGroup = position.processChildren ? updateSegmentGroupChildren(position.segmentGroup, position.index, nav.commands) : updateSegmentGroup(position.segmentGroup, position.index, nav.commands);
|
|
return tree(root, position.segmentGroup, newSegmentGroup, queryParams, fragment);
|
|
}
|
|
function isMatrixParams(command) {
|
|
return typeof command === "object" && command != null && !command.outlets && !command.segmentPath;
|
|
}
|
|
function isCommandWithOutlets(command) {
|
|
return typeof command === "object" && command != null && command.outlets;
|
|
}
|
|
function tree(oldRoot, oldSegmentGroup, newSegmentGroup, queryParams, fragment) {
|
|
let qp = {};
|
|
if (queryParams) {
|
|
Object.entries(queryParams).forEach(([name, value]) => {
|
|
qp[name] = Array.isArray(value) ? value.map((v) => `${v}`) : `${value}`;
|
|
});
|
|
}
|
|
let rootCandidate;
|
|
if (oldRoot === oldSegmentGroup) {
|
|
rootCandidate = newSegmentGroup;
|
|
} else {
|
|
rootCandidate = replaceSegment(oldRoot, oldSegmentGroup, newSegmentGroup);
|
|
}
|
|
const newRoot = createRoot(squashSegmentGroup(rootCandidate));
|
|
return new UrlTree(newRoot, qp, fragment);
|
|
}
|
|
function replaceSegment(current, oldSegment, newSegment) {
|
|
const children = {};
|
|
Object.entries(current.children).forEach(([outletName, c]) => {
|
|
if (c === oldSegment) {
|
|
children[outletName] = newSegment;
|
|
} else {
|
|
children[outletName] = replaceSegment(c, oldSegment, newSegment);
|
|
}
|
|
});
|
|
return new UrlSegmentGroup(current.segments, children);
|
|
}
|
|
var Navigation = class {
|
|
constructor(isAbsolute, numberOfDoubleDots, commands) {
|
|
this.isAbsolute = isAbsolute;
|
|
this.numberOfDoubleDots = numberOfDoubleDots;
|
|
this.commands = commands;
|
|
if (isAbsolute && commands.length > 0 && isMatrixParams(commands[0])) {
|
|
throw new RuntimeError(4003, (typeof ngDevMode === "undefined" || ngDevMode) && "Root segment cannot have matrix parameters");
|
|
}
|
|
const cmdWithOutlet = commands.find(isCommandWithOutlets);
|
|
if (cmdWithOutlet && cmdWithOutlet !== last2(commands)) {
|
|
throw new RuntimeError(4004, (typeof ngDevMode === "undefined" || ngDevMode) && "{outlets:{}} has to be the last command");
|
|
}
|
|
}
|
|
toRoot() {
|
|
return this.isAbsolute && this.commands.length === 1 && this.commands[0] == "/";
|
|
}
|
|
};
|
|
function computeNavigation(commands) {
|
|
if (typeof commands[0] === "string" && commands.length === 1 && commands[0] === "/") {
|
|
return new Navigation(true, 0, commands);
|
|
}
|
|
let numberOfDoubleDots = 0;
|
|
let isAbsolute = false;
|
|
const res = commands.reduce((res2, cmd, cmdIdx) => {
|
|
if (typeof cmd === "object" && cmd != null) {
|
|
if (cmd.outlets) {
|
|
const outlets = {};
|
|
Object.entries(cmd.outlets).forEach(([name, commands2]) => {
|
|
outlets[name] = typeof commands2 === "string" ? commands2.split("/") : commands2;
|
|
});
|
|
return [...res2, {
|
|
outlets
|
|
}];
|
|
}
|
|
if (cmd.segmentPath) {
|
|
return [...res2, cmd.segmentPath];
|
|
}
|
|
}
|
|
if (!(typeof cmd === "string")) {
|
|
return [...res2, cmd];
|
|
}
|
|
if (cmdIdx === 0) {
|
|
cmd.split("/").forEach((urlPart, partIndex) => {
|
|
if (partIndex == 0 && urlPart === ".") {
|
|
} else if (partIndex == 0 && urlPart === "") {
|
|
isAbsolute = true;
|
|
} else if (urlPart === "..") {
|
|
numberOfDoubleDots++;
|
|
} else if (urlPart != "") {
|
|
res2.push(urlPart);
|
|
}
|
|
});
|
|
return res2;
|
|
}
|
|
return [...res2, cmd];
|
|
}, []);
|
|
return new Navigation(isAbsolute, numberOfDoubleDots, res);
|
|
}
|
|
var Position = class {
|
|
constructor(segmentGroup, processChildren, index) {
|
|
this.segmentGroup = segmentGroup;
|
|
this.processChildren = processChildren;
|
|
this.index = index;
|
|
}
|
|
};
|
|
function findStartingPositionForTargetGroup(nav, root, target) {
|
|
if (nav.isAbsolute) {
|
|
return new Position(root, true, 0);
|
|
}
|
|
if (!target) {
|
|
return new Position(root, false, NaN);
|
|
}
|
|
if (target.parent === null) {
|
|
return new Position(target, true, 0);
|
|
}
|
|
const modifier = isMatrixParams(nav.commands[0]) ? 0 : 1;
|
|
const index = target.segments.length - 1 + modifier;
|
|
return createPositionApplyingDoubleDots(target, index, nav.numberOfDoubleDots);
|
|
}
|
|
function createPositionApplyingDoubleDots(group, index, numberOfDoubleDots) {
|
|
let g = group;
|
|
let ci = index;
|
|
let dd = numberOfDoubleDots;
|
|
while (dd > ci) {
|
|
dd -= ci;
|
|
g = g.parent;
|
|
if (!g) {
|
|
throw new RuntimeError(4005, (typeof ngDevMode === "undefined" || ngDevMode) && "Invalid number of '../'");
|
|
}
|
|
ci = g.segments.length;
|
|
}
|
|
return new Position(g, false, ci - dd);
|
|
}
|
|
function getOutlets(commands) {
|
|
if (isCommandWithOutlets(commands[0])) {
|
|
return commands[0].outlets;
|
|
}
|
|
return {
|
|
[PRIMARY_OUTLET]: commands
|
|
};
|
|
}
|
|
function updateSegmentGroup(segmentGroup, startIndex, commands) {
|
|
if (!segmentGroup) {
|
|
segmentGroup = new UrlSegmentGroup([], {});
|
|
}
|
|
if (segmentGroup.segments.length === 0 && segmentGroup.hasChildren()) {
|
|
return updateSegmentGroupChildren(segmentGroup, startIndex, commands);
|
|
}
|
|
const m = prefixedWith(segmentGroup, startIndex, commands);
|
|
const slicedCommands = commands.slice(m.commandIndex);
|
|
if (m.match && m.pathIndex < segmentGroup.segments.length) {
|
|
const g = new UrlSegmentGroup(segmentGroup.segments.slice(0, m.pathIndex), {});
|
|
g.children[PRIMARY_OUTLET] = new UrlSegmentGroup(segmentGroup.segments.slice(m.pathIndex), segmentGroup.children);
|
|
return updateSegmentGroupChildren(g, 0, slicedCommands);
|
|
} else if (m.match && slicedCommands.length === 0) {
|
|
return new UrlSegmentGroup(segmentGroup.segments, {});
|
|
} else if (m.match && !segmentGroup.hasChildren()) {
|
|
return createNewSegmentGroup(segmentGroup, startIndex, commands);
|
|
} else if (m.match) {
|
|
return updateSegmentGroupChildren(segmentGroup, 0, slicedCommands);
|
|
} else {
|
|
return createNewSegmentGroup(segmentGroup, startIndex, commands);
|
|
}
|
|
}
|
|
function updateSegmentGroupChildren(segmentGroup, startIndex, commands) {
|
|
if (commands.length === 0) {
|
|
return new UrlSegmentGroup(segmentGroup.segments, {});
|
|
} else {
|
|
const outlets = getOutlets(commands);
|
|
const children = {};
|
|
if (Object.keys(outlets).some((o) => o !== PRIMARY_OUTLET) && segmentGroup.children[PRIMARY_OUTLET] && segmentGroup.numberOfChildren === 1 && segmentGroup.children[PRIMARY_OUTLET].segments.length === 0) {
|
|
const childrenOfEmptyChild = updateSegmentGroupChildren(segmentGroup.children[PRIMARY_OUTLET], startIndex, commands);
|
|
return new UrlSegmentGroup(segmentGroup.segments, childrenOfEmptyChild.children);
|
|
}
|
|
Object.entries(outlets).forEach(([outlet, commands2]) => {
|
|
if (typeof commands2 === "string") {
|
|
commands2 = [commands2];
|
|
}
|
|
if (commands2 !== null) {
|
|
children[outlet] = updateSegmentGroup(segmentGroup.children[outlet], startIndex, commands2);
|
|
}
|
|
});
|
|
Object.entries(segmentGroup.children).forEach(([childOutlet, child]) => {
|
|
if (outlets[childOutlet] === void 0) {
|
|
children[childOutlet] = child;
|
|
}
|
|
});
|
|
return new UrlSegmentGroup(segmentGroup.segments, children);
|
|
}
|
|
}
|
|
function prefixedWith(segmentGroup, startIndex, commands) {
|
|
let currentCommandIndex = 0;
|
|
let currentPathIndex = startIndex;
|
|
const noMatch2 = {
|
|
match: false,
|
|
pathIndex: 0,
|
|
commandIndex: 0
|
|
};
|
|
while (currentPathIndex < segmentGroup.segments.length) {
|
|
if (currentCommandIndex >= commands.length)
|
|
return noMatch2;
|
|
const path = segmentGroup.segments[currentPathIndex];
|
|
const command = commands[currentCommandIndex];
|
|
if (isCommandWithOutlets(command)) {
|
|
break;
|
|
}
|
|
const curr = `${command}`;
|
|
const next = currentCommandIndex < commands.length - 1 ? commands[currentCommandIndex + 1] : null;
|
|
if (currentPathIndex > 0 && curr === void 0)
|
|
break;
|
|
if (curr && next && typeof next === "object" && next.outlets === void 0) {
|
|
if (!compare(curr, next, path))
|
|
return noMatch2;
|
|
currentCommandIndex += 2;
|
|
} else {
|
|
if (!compare(curr, {}, path))
|
|
return noMatch2;
|
|
currentCommandIndex++;
|
|
}
|
|
currentPathIndex++;
|
|
}
|
|
return {
|
|
match: true,
|
|
pathIndex: currentPathIndex,
|
|
commandIndex: currentCommandIndex
|
|
};
|
|
}
|
|
function createNewSegmentGroup(segmentGroup, startIndex, commands) {
|
|
const paths = segmentGroup.segments.slice(0, startIndex);
|
|
let i = 0;
|
|
while (i < commands.length) {
|
|
const command = commands[i];
|
|
if (isCommandWithOutlets(command)) {
|
|
const children = createNewSegmentChildren(command.outlets);
|
|
return new UrlSegmentGroup(paths, children);
|
|
}
|
|
if (i === 0 && isMatrixParams(commands[0])) {
|
|
const p = segmentGroup.segments[startIndex];
|
|
paths.push(new UrlSegment(p.path, stringify(commands[0])));
|
|
i++;
|
|
continue;
|
|
}
|
|
const curr = isCommandWithOutlets(command) ? command.outlets[PRIMARY_OUTLET] : `${command}`;
|
|
const next = i < commands.length - 1 ? commands[i + 1] : null;
|
|
if (curr && next && isMatrixParams(next)) {
|
|
paths.push(new UrlSegment(curr, stringify(next)));
|
|
i += 2;
|
|
} else {
|
|
paths.push(new UrlSegment(curr, {}));
|
|
i++;
|
|
}
|
|
}
|
|
return new UrlSegmentGroup(paths, {});
|
|
}
|
|
function createNewSegmentChildren(outlets) {
|
|
const children = {};
|
|
Object.entries(outlets).forEach(([outlet, commands]) => {
|
|
if (typeof commands === "string") {
|
|
commands = [commands];
|
|
}
|
|
if (commands !== null) {
|
|
children[outlet] = createNewSegmentGroup(new UrlSegmentGroup([], {}), 0, commands);
|
|
}
|
|
});
|
|
return children;
|
|
}
|
|
function stringify(params) {
|
|
const res = {};
|
|
Object.entries(params).forEach(([k, v]) => res[k] = `${v}`);
|
|
return res;
|
|
}
|
|
function compare(path, params, segment) {
|
|
return path == segment.path && shallowEqual(params, segment.parameters);
|
|
}
|
|
var IMPERATIVE_NAVIGATION = "imperative";
|
|
var RouterEvent = class {
|
|
constructor(id, url) {
|
|
this.id = id;
|
|
this.url = url;
|
|
}
|
|
};
|
|
var NavigationStart = class extends RouterEvent {
|
|
constructor(id, url, navigationTrigger = "imperative", restoredState = null) {
|
|
super(id, url);
|
|
this.type = 0;
|
|
this.navigationTrigger = navigationTrigger;
|
|
this.restoredState = restoredState;
|
|
}
|
|
/** @docsNotRequired */
|
|
toString() {
|
|
return `NavigationStart(id: ${this.id}, url: '${this.url}')`;
|
|
}
|
|
};
|
|
var NavigationEnd = class extends RouterEvent {
|
|
constructor(id, url, urlAfterRedirects) {
|
|
super(id, url);
|
|
this.urlAfterRedirects = urlAfterRedirects;
|
|
this.type = 1;
|
|
}
|
|
/** @docsNotRequired */
|
|
toString() {
|
|
return `NavigationEnd(id: ${this.id}, url: '${this.url}', urlAfterRedirects: '${this.urlAfterRedirects}')`;
|
|
}
|
|
};
|
|
var NavigationCancel = class extends RouterEvent {
|
|
constructor(id, url, reason, code) {
|
|
super(id, url);
|
|
this.reason = reason;
|
|
this.code = code;
|
|
this.type = 2;
|
|
}
|
|
/** @docsNotRequired */
|
|
toString() {
|
|
return `NavigationCancel(id: ${this.id}, url: '${this.url}')`;
|
|
}
|
|
};
|
|
var NavigationSkipped = class extends RouterEvent {
|
|
constructor(id, url, reason, code) {
|
|
super(id, url);
|
|
this.reason = reason;
|
|
this.code = code;
|
|
this.type = 16;
|
|
}
|
|
};
|
|
var NavigationError = class extends RouterEvent {
|
|
constructor(id, url, error, target) {
|
|
super(id, url);
|
|
this.error = error;
|
|
this.target = target;
|
|
this.type = 3;
|
|
}
|
|
/** @docsNotRequired */
|
|
toString() {
|
|
return `NavigationError(id: ${this.id}, url: '${this.url}', error: ${this.error})`;
|
|
}
|
|
};
|
|
var RoutesRecognized = class extends RouterEvent {
|
|
constructor(id, url, urlAfterRedirects, state) {
|
|
super(id, url);
|
|
this.urlAfterRedirects = urlAfterRedirects;
|
|
this.state = state;
|
|
this.type = 4;
|
|
}
|
|
/** @docsNotRequired */
|
|
toString() {
|
|
return `RoutesRecognized(id: ${this.id}, url: '${this.url}', urlAfterRedirects: '${this.urlAfterRedirects}', state: ${this.state})`;
|
|
}
|
|
};
|
|
var GuardsCheckStart = class extends RouterEvent {
|
|
constructor(id, url, urlAfterRedirects, state) {
|
|
super(id, url);
|
|
this.urlAfterRedirects = urlAfterRedirects;
|
|
this.state = state;
|
|
this.type = 7;
|
|
}
|
|
toString() {
|
|
return `GuardsCheckStart(id: ${this.id}, url: '${this.url}', urlAfterRedirects: '${this.urlAfterRedirects}', state: ${this.state})`;
|
|
}
|
|
};
|
|
var GuardsCheckEnd = class extends RouterEvent {
|
|
constructor(id, url, urlAfterRedirects, state, shouldActivate) {
|
|
super(id, url);
|
|
this.urlAfterRedirects = urlAfterRedirects;
|
|
this.state = state;
|
|
this.shouldActivate = shouldActivate;
|
|
this.type = 8;
|
|
}
|
|
toString() {
|
|
return `GuardsCheckEnd(id: ${this.id}, url: '${this.url}', urlAfterRedirects: '${this.urlAfterRedirects}', state: ${this.state}, shouldActivate: ${this.shouldActivate})`;
|
|
}
|
|
};
|
|
var ResolveStart = class extends RouterEvent {
|
|
constructor(id, url, urlAfterRedirects, state) {
|
|
super(id, url);
|
|
this.urlAfterRedirects = urlAfterRedirects;
|
|
this.state = state;
|
|
this.type = 5;
|
|
}
|
|
toString() {
|
|
return `ResolveStart(id: ${this.id}, url: '${this.url}', urlAfterRedirects: '${this.urlAfterRedirects}', state: ${this.state})`;
|
|
}
|
|
};
|
|
var ResolveEnd = class extends RouterEvent {
|
|
constructor(id, url, urlAfterRedirects, state) {
|
|
super(id, url);
|
|
this.urlAfterRedirects = urlAfterRedirects;
|
|
this.state = state;
|
|
this.type = 6;
|
|
}
|
|
toString() {
|
|
return `ResolveEnd(id: ${this.id}, url: '${this.url}', urlAfterRedirects: '${this.urlAfterRedirects}', state: ${this.state})`;
|
|
}
|
|
};
|
|
var RouteConfigLoadStart = class {
|
|
constructor(route) {
|
|
this.route = route;
|
|
this.type = 9;
|
|
}
|
|
toString() {
|
|
return `RouteConfigLoadStart(path: ${this.route.path})`;
|
|
}
|
|
};
|
|
var RouteConfigLoadEnd = class {
|
|
constructor(route) {
|
|
this.route = route;
|
|
this.type = 10;
|
|
}
|
|
toString() {
|
|
return `RouteConfigLoadEnd(path: ${this.route.path})`;
|
|
}
|
|
};
|
|
var ChildActivationStart = class {
|
|
constructor(snapshot) {
|
|
this.snapshot = snapshot;
|
|
this.type = 11;
|
|
}
|
|
toString() {
|
|
const path = this.snapshot.routeConfig && this.snapshot.routeConfig.path || "";
|
|
return `ChildActivationStart(path: '${path}')`;
|
|
}
|
|
};
|
|
var ChildActivationEnd = class {
|
|
constructor(snapshot) {
|
|
this.snapshot = snapshot;
|
|
this.type = 12;
|
|
}
|
|
toString() {
|
|
const path = this.snapshot.routeConfig && this.snapshot.routeConfig.path || "";
|
|
return `ChildActivationEnd(path: '${path}')`;
|
|
}
|
|
};
|
|
var ActivationStart = class {
|
|
constructor(snapshot) {
|
|
this.snapshot = snapshot;
|
|
this.type = 13;
|
|
}
|
|
toString() {
|
|
const path = this.snapshot.routeConfig && this.snapshot.routeConfig.path || "";
|
|
return `ActivationStart(path: '${path}')`;
|
|
}
|
|
};
|
|
var ActivationEnd = class {
|
|
constructor(snapshot) {
|
|
this.snapshot = snapshot;
|
|
this.type = 14;
|
|
}
|
|
toString() {
|
|
const path = this.snapshot.routeConfig && this.snapshot.routeConfig.path || "";
|
|
return `ActivationEnd(path: '${path}')`;
|
|
}
|
|
};
|
|
var Scroll = class {
|
|
constructor(routerEvent, position, anchor) {
|
|
this.routerEvent = routerEvent;
|
|
this.position = position;
|
|
this.anchor = anchor;
|
|
this.type = 15;
|
|
}
|
|
toString() {
|
|
const pos = this.position ? `${this.position[0]}, ${this.position[1]}` : null;
|
|
return `Scroll(anchor: '${this.anchor}', position: '${pos}')`;
|
|
}
|
|
};
|
|
var BeforeActivateRoutes = class {
|
|
};
|
|
var RedirectRequest = class {
|
|
constructor(url) {
|
|
this.url = url;
|
|
}
|
|
};
|
|
function stringifyEvent(routerEvent) {
|
|
switch (routerEvent.type) {
|
|
case 14:
|
|
return `ActivationEnd(path: '${routerEvent.snapshot.routeConfig?.path || ""}')`;
|
|
case 13:
|
|
return `ActivationStart(path: '${routerEvent.snapshot.routeConfig?.path || ""}')`;
|
|
case 12:
|
|
return `ChildActivationEnd(path: '${routerEvent.snapshot.routeConfig?.path || ""}')`;
|
|
case 11:
|
|
return `ChildActivationStart(path: '${routerEvent.snapshot.routeConfig?.path || ""}')`;
|
|
case 8:
|
|
return `GuardsCheckEnd(id: ${routerEvent.id}, url: '${routerEvent.url}', urlAfterRedirects: '${routerEvent.urlAfterRedirects}', state: ${routerEvent.state}, shouldActivate: ${routerEvent.shouldActivate})`;
|
|
case 7:
|
|
return `GuardsCheckStart(id: ${routerEvent.id}, url: '${routerEvent.url}', urlAfterRedirects: '${routerEvent.urlAfterRedirects}', state: ${routerEvent.state})`;
|
|
case 2:
|
|
return `NavigationCancel(id: ${routerEvent.id}, url: '${routerEvent.url}')`;
|
|
case 16:
|
|
return `NavigationSkipped(id: ${routerEvent.id}, url: '${routerEvent.url}')`;
|
|
case 1:
|
|
return `NavigationEnd(id: ${routerEvent.id}, url: '${routerEvent.url}', urlAfterRedirects: '${routerEvent.urlAfterRedirects}')`;
|
|
case 3:
|
|
return `NavigationError(id: ${routerEvent.id}, url: '${routerEvent.url}', error: ${routerEvent.error})`;
|
|
case 0:
|
|
return `NavigationStart(id: ${routerEvent.id}, url: '${routerEvent.url}')`;
|
|
case 6:
|
|
return `ResolveEnd(id: ${routerEvent.id}, url: '${routerEvent.url}', urlAfterRedirects: '${routerEvent.urlAfterRedirects}', state: ${routerEvent.state})`;
|
|
case 5:
|
|
return `ResolveStart(id: ${routerEvent.id}, url: '${routerEvent.url}', urlAfterRedirects: '${routerEvent.urlAfterRedirects}', state: ${routerEvent.state})`;
|
|
case 10:
|
|
return `RouteConfigLoadEnd(path: ${routerEvent.route.path})`;
|
|
case 9:
|
|
return `RouteConfigLoadStart(path: ${routerEvent.route.path})`;
|
|
case 4:
|
|
return `RoutesRecognized(id: ${routerEvent.id}, url: '${routerEvent.url}', urlAfterRedirects: '${routerEvent.urlAfterRedirects}', state: ${routerEvent.state})`;
|
|
case 15:
|
|
const pos = routerEvent.position ? `${routerEvent.position[0]}, ${routerEvent.position[1]}` : null;
|
|
return `Scroll(anchor: '${routerEvent.anchor}', position: '${pos}')`;
|
|
}
|
|
}
|
|
var OutletContext = class {
|
|
constructor() {
|
|
this.outlet = null;
|
|
this.route = null;
|
|
this.injector = null;
|
|
this.children = new ChildrenOutletContexts();
|
|
this.attachRef = null;
|
|
}
|
|
};
|
|
var _ChildrenOutletContexts = class _ChildrenOutletContexts {
|
|
constructor() {
|
|
this.contexts = /* @__PURE__ */ new Map();
|
|
}
|
|
/** Called when a `RouterOutlet` directive is instantiated */
|
|
onChildOutletCreated(childName, outlet) {
|
|
const context = this.getOrCreateContext(childName);
|
|
context.outlet = outlet;
|
|
this.contexts.set(childName, context);
|
|
}
|
|
/**
|
|
* Called when a `RouterOutlet` directive is destroyed.
|
|
* We need to keep the context as the outlet could be destroyed inside a NgIf and might be
|
|
* re-created later.
|
|
*/
|
|
onChildOutletDestroyed(childName) {
|
|
const context = this.getContext(childName);
|
|
if (context) {
|
|
context.outlet = null;
|
|
context.attachRef = null;
|
|
}
|
|
}
|
|
/**
|
|
* Called when the corresponding route is deactivated during navigation.
|
|
* Because the component get destroyed, all children outlet are destroyed.
|
|
*/
|
|
onOutletDeactivated() {
|
|
const contexts = this.contexts;
|
|
this.contexts = /* @__PURE__ */ new Map();
|
|
return contexts;
|
|
}
|
|
onOutletReAttached(contexts) {
|
|
this.contexts = contexts;
|
|
}
|
|
getOrCreateContext(childName) {
|
|
let context = this.getContext(childName);
|
|
if (!context) {
|
|
context = new OutletContext();
|
|
this.contexts.set(childName, context);
|
|
}
|
|
return context;
|
|
}
|
|
getContext(childName) {
|
|
return this.contexts.get(childName) || null;
|
|
}
|
|
};
|
|
_ChildrenOutletContexts.ɵfac = function ChildrenOutletContexts_Factory(t) {
|
|
return new (t || _ChildrenOutletContexts)();
|
|
};
|
|
_ChildrenOutletContexts.ɵprov = ɵɵdefineInjectable({
|
|
token: _ChildrenOutletContexts,
|
|
factory: _ChildrenOutletContexts.ɵfac,
|
|
providedIn: "root"
|
|
});
|
|
var ChildrenOutletContexts = _ChildrenOutletContexts;
|
|
(() => {
|
|
(typeof ngDevMode === "undefined" || ngDevMode) && setClassMetadata(ChildrenOutletContexts, [{
|
|
type: Injectable,
|
|
args: [{
|
|
providedIn: "root"
|
|
}]
|
|
}], null, null);
|
|
})();
|
|
var Tree = class {
|
|
constructor(root) {
|
|
this._root = root;
|
|
}
|
|
get root() {
|
|
return this._root.value;
|
|
}
|
|
/**
|
|
* @internal
|
|
*/
|
|
parent(t) {
|
|
const p = this.pathFromRoot(t);
|
|
return p.length > 1 ? p[p.length - 2] : null;
|
|
}
|
|
/**
|
|
* @internal
|
|
*/
|
|
children(t) {
|
|
const n = findNode(t, this._root);
|
|
return n ? n.children.map((t2) => t2.value) : [];
|
|
}
|
|
/**
|
|
* @internal
|
|
*/
|
|
firstChild(t) {
|
|
const n = findNode(t, this._root);
|
|
return n && n.children.length > 0 ? n.children[0].value : null;
|
|
}
|
|
/**
|
|
* @internal
|
|
*/
|
|
siblings(t) {
|
|
const p = findPath(t, this._root);
|
|
if (p.length < 2)
|
|
return [];
|
|
const c = p[p.length - 2].children.map((c2) => c2.value);
|
|
return c.filter((cc) => cc !== t);
|
|
}
|
|
/**
|
|
* @internal
|
|
*/
|
|
pathFromRoot(t) {
|
|
return findPath(t, this._root).map((s) => s.value);
|
|
}
|
|
};
|
|
function findNode(value, node) {
|
|
if (value === node.value)
|
|
return node;
|
|
for (const child of node.children) {
|
|
const node2 = findNode(value, child);
|
|
if (node2)
|
|
return node2;
|
|
}
|
|
return null;
|
|
}
|
|
function findPath(value, node) {
|
|
if (value === node.value)
|
|
return [node];
|
|
for (const child of node.children) {
|
|
const path = findPath(value, child);
|
|
if (path.length) {
|
|
path.unshift(node);
|
|
return path;
|
|
}
|
|
}
|
|
return [];
|
|
}
|
|
var TreeNode = class {
|
|
constructor(value, children) {
|
|
this.value = value;
|
|
this.children = children;
|
|
}
|
|
toString() {
|
|
return `TreeNode(${this.value})`;
|
|
}
|
|
};
|
|
function nodeChildrenAsMap(node) {
|
|
const map2 = {};
|
|
if (node) {
|
|
node.children.forEach((child) => map2[child.value.outlet] = child);
|
|
}
|
|
return map2;
|
|
}
|
|
var RouterState = class extends Tree {
|
|
/** @internal */
|
|
constructor(root, snapshot) {
|
|
super(root);
|
|
this.snapshot = snapshot;
|
|
setRouterState(this, root);
|
|
}
|
|
toString() {
|
|
return this.snapshot.toString();
|
|
}
|
|
};
|
|
function createEmptyState(urlTree, rootComponent) {
|
|
const snapshot = createEmptyStateSnapshot(urlTree, rootComponent);
|
|
const emptyUrl = new BehaviorSubject([new UrlSegment("", {})]);
|
|
const emptyParams = new BehaviorSubject({});
|
|
const emptyData = new BehaviorSubject({});
|
|
const emptyQueryParams = new BehaviorSubject({});
|
|
const fragment = new BehaviorSubject("");
|
|
const activated = new ActivatedRoute(emptyUrl, emptyParams, emptyQueryParams, fragment, emptyData, PRIMARY_OUTLET, rootComponent, snapshot.root);
|
|
activated.snapshot = snapshot.root;
|
|
return new RouterState(new TreeNode(activated, []), snapshot);
|
|
}
|
|
function createEmptyStateSnapshot(urlTree, rootComponent) {
|
|
const emptyParams = {};
|
|
const emptyData = {};
|
|
const emptyQueryParams = {};
|
|
const fragment = "";
|
|
const activated = new ActivatedRouteSnapshot([], emptyParams, emptyQueryParams, fragment, emptyData, PRIMARY_OUTLET, rootComponent, null, {});
|
|
return new RouterStateSnapshot("", new TreeNode(activated, []));
|
|
}
|
|
var ActivatedRoute = class {
|
|
/** @internal */
|
|
constructor(urlSubject, paramsSubject, queryParamsSubject, fragmentSubject, dataSubject, outlet, component, futureSnapshot) {
|
|
this.urlSubject = urlSubject;
|
|
this.paramsSubject = paramsSubject;
|
|
this.queryParamsSubject = queryParamsSubject;
|
|
this.fragmentSubject = fragmentSubject;
|
|
this.dataSubject = dataSubject;
|
|
this.outlet = outlet;
|
|
this.component = component;
|
|
this._futureSnapshot = futureSnapshot;
|
|
this.title = this.dataSubject?.pipe(map((d) => d[RouteTitleKey])) ?? of(void 0);
|
|
this.url = urlSubject;
|
|
this.params = paramsSubject;
|
|
this.queryParams = queryParamsSubject;
|
|
this.fragment = fragmentSubject;
|
|
this.data = dataSubject;
|
|
}
|
|
/** The configuration used to match this route. */
|
|
get routeConfig() {
|
|
return this._futureSnapshot.routeConfig;
|
|
}
|
|
/** The root of the router state. */
|
|
get root() {
|
|
return this._routerState.root;
|
|
}
|
|
/** The parent of this route in the router state tree. */
|
|
get parent() {
|
|
return this._routerState.parent(this);
|
|
}
|
|
/** The first child of this route in the router state tree. */
|
|
get firstChild() {
|
|
return this._routerState.firstChild(this);
|
|
}
|
|
/** The children of this route in the router state tree. */
|
|
get children() {
|
|
return this._routerState.children(this);
|
|
}
|
|
/** The path from the root of the router state tree to this route. */
|
|
get pathFromRoot() {
|
|
return this._routerState.pathFromRoot(this);
|
|
}
|
|
/**
|
|
* An Observable that contains a map of the required and optional parameters
|
|
* specific to the route.
|
|
* The map supports retrieving single and multiple values from the same parameter.
|
|
*/
|
|
get paramMap() {
|
|
if (!this._paramMap) {
|
|
this._paramMap = this.params.pipe(map((p) => convertToParamMap(p)));
|
|
}
|
|
return this._paramMap;
|
|
}
|
|
/**
|
|
* An Observable that contains a map of the query parameters available to all routes.
|
|
* The map supports retrieving single and multiple values from the query parameter.
|
|
*/
|
|
get queryParamMap() {
|
|
if (!this._queryParamMap) {
|
|
this._queryParamMap = this.queryParams.pipe(map((p) => convertToParamMap(p)));
|
|
}
|
|
return this._queryParamMap;
|
|
}
|
|
toString() {
|
|
return this.snapshot ? this.snapshot.toString() : `Future(${this._futureSnapshot})`;
|
|
}
|
|
};
|
|
function getInherited(route, parent, paramsInheritanceStrategy = "emptyOnly") {
|
|
let inherited;
|
|
const {
|
|
routeConfig
|
|
} = route;
|
|
if (parent !== null && (paramsInheritanceStrategy === "always" || // inherit parent data if route is empty path
|
|
routeConfig?.path === "" || // inherit parent data if parent was componentless
|
|
!parent.component && !parent.routeConfig?.loadComponent)) {
|
|
inherited = {
|
|
params: __spreadValues(__spreadValues({}, parent.params), route.params),
|
|
data: __spreadValues(__spreadValues({}, parent.data), route.data),
|
|
resolve: __spreadValues(__spreadValues(__spreadValues(__spreadValues({}, route.data), parent.data), routeConfig?.data), route._resolvedData)
|
|
};
|
|
} else {
|
|
inherited = {
|
|
params: route.params,
|
|
data: route.data,
|
|
resolve: __spreadValues(__spreadValues({}, route.data), route._resolvedData ?? {})
|
|
};
|
|
}
|
|
if (routeConfig && hasStaticTitle(routeConfig)) {
|
|
inherited.resolve[RouteTitleKey] = routeConfig.title;
|
|
}
|
|
return inherited;
|
|
}
|
|
var ActivatedRouteSnapshot = class {
|
|
/** The resolved route title */
|
|
get title() {
|
|
return this.data?.[RouteTitleKey];
|
|
}
|
|
/** @internal */
|
|
constructor(url, params, queryParams, fragment, data, outlet, component, routeConfig, resolve) {
|
|
this.url = url;
|
|
this.params = params;
|
|
this.queryParams = queryParams;
|
|
this.fragment = fragment;
|
|
this.data = data;
|
|
this.outlet = outlet;
|
|
this.component = component;
|
|
this.routeConfig = routeConfig;
|
|
this._resolve = resolve;
|
|
}
|
|
/** The root of the router state */
|
|
get root() {
|
|
return this._routerState.root;
|
|
}
|
|
/** The parent of this route in the router state tree */
|
|
get parent() {
|
|
return this._routerState.parent(this);
|
|
}
|
|
/** The first child of this route in the router state tree */
|
|
get firstChild() {
|
|
return this._routerState.firstChild(this);
|
|
}
|
|
/** The children of this route in the router state tree */
|
|
get children() {
|
|
return this._routerState.children(this);
|
|
}
|
|
/** The path from the root of the router state tree to this route */
|
|
get pathFromRoot() {
|
|
return this._routerState.pathFromRoot(this);
|
|
}
|
|
get paramMap() {
|
|
if (!this._paramMap) {
|
|
this._paramMap = convertToParamMap(this.params);
|
|
}
|
|
return this._paramMap;
|
|
}
|
|
get queryParamMap() {
|
|
if (!this._queryParamMap) {
|
|
this._queryParamMap = convertToParamMap(this.queryParams);
|
|
}
|
|
return this._queryParamMap;
|
|
}
|
|
toString() {
|
|
const url = this.url.map((segment) => segment.toString()).join("/");
|
|
const matched = this.routeConfig ? this.routeConfig.path : "";
|
|
return `Route(url:'${url}', path:'${matched}')`;
|
|
}
|
|
};
|
|
var RouterStateSnapshot = class extends Tree {
|
|
/** @internal */
|
|
constructor(url, root) {
|
|
super(root);
|
|
this.url = url;
|
|
setRouterState(this, root);
|
|
}
|
|
toString() {
|
|
return serializeNode(this._root);
|
|
}
|
|
};
|
|
function setRouterState(state, node) {
|
|
node.value._routerState = state;
|
|
node.children.forEach((c) => setRouterState(state, c));
|
|
}
|
|
function serializeNode(node) {
|
|
const c = node.children.length > 0 ? ` { ${node.children.map(serializeNode).join(", ")} } ` : "";
|
|
return `${node.value}${c}`;
|
|
}
|
|
function advanceActivatedRoute(route) {
|
|
if (route.snapshot) {
|
|
const currentSnapshot = route.snapshot;
|
|
const nextSnapshot = route._futureSnapshot;
|
|
route.snapshot = nextSnapshot;
|
|
if (!shallowEqual(currentSnapshot.queryParams, nextSnapshot.queryParams)) {
|
|
route.queryParamsSubject.next(nextSnapshot.queryParams);
|
|
}
|
|
if (currentSnapshot.fragment !== nextSnapshot.fragment) {
|
|
route.fragmentSubject.next(nextSnapshot.fragment);
|
|
}
|
|
if (!shallowEqual(currentSnapshot.params, nextSnapshot.params)) {
|
|
route.paramsSubject.next(nextSnapshot.params);
|
|
}
|
|
if (!shallowEqualArrays(currentSnapshot.url, nextSnapshot.url)) {
|
|
route.urlSubject.next(nextSnapshot.url);
|
|
}
|
|
if (!shallowEqual(currentSnapshot.data, nextSnapshot.data)) {
|
|
route.dataSubject.next(nextSnapshot.data);
|
|
}
|
|
} else {
|
|
route.snapshot = route._futureSnapshot;
|
|
route.dataSubject.next(route._futureSnapshot.data);
|
|
}
|
|
}
|
|
function equalParamsAndUrlSegments(a, b) {
|
|
const equalUrlParams = shallowEqual(a.params, b.params) && equalSegments(a.url, b.url);
|
|
const parentsMismatch = !a.parent !== !b.parent;
|
|
return equalUrlParams && !parentsMismatch && (!a.parent || equalParamsAndUrlSegments(a.parent, b.parent));
|
|
}
|
|
function hasStaticTitle(config) {
|
|
return typeof config.title === "string" || config.title === null;
|
|
}
|
|
var _RouterOutlet = class _RouterOutlet {
|
|
constructor() {
|
|
this.activated = null;
|
|
this._activatedRoute = null;
|
|
this.name = PRIMARY_OUTLET;
|
|
this.activateEvents = new EventEmitter();
|
|
this.deactivateEvents = new EventEmitter();
|
|
this.attachEvents = new EventEmitter();
|
|
this.detachEvents = new EventEmitter();
|
|
this.parentContexts = inject(ChildrenOutletContexts);
|
|
this.location = inject(ViewContainerRef);
|
|
this.changeDetector = inject(ChangeDetectorRef);
|
|
this.environmentInjector = inject(EnvironmentInjector);
|
|
this.inputBinder = inject(INPUT_BINDER, {
|
|
optional: true
|
|
});
|
|
this.supportsBindingToComponentInputs = true;
|
|
}
|
|
/** @internal */
|
|
get activatedComponentRef() {
|
|
return this.activated;
|
|
}
|
|
/** @nodoc */
|
|
ngOnChanges(changes) {
|
|
if (changes["name"]) {
|
|
const {
|
|
firstChange,
|
|
previousValue
|
|
} = changes["name"];
|
|
if (firstChange) {
|
|
return;
|
|
}
|
|
if (this.isTrackedInParentContexts(previousValue)) {
|
|
this.deactivate();
|
|
this.parentContexts.onChildOutletDestroyed(previousValue);
|
|
}
|
|
this.initializeOutletWithName();
|
|
}
|
|
}
|
|
/** @nodoc */
|
|
ngOnDestroy() {
|
|
if (this.isTrackedInParentContexts(this.name)) {
|
|
this.parentContexts.onChildOutletDestroyed(this.name);
|
|
}
|
|
this.inputBinder?.unsubscribeFromRouteData(this);
|
|
}
|
|
isTrackedInParentContexts(outletName) {
|
|
return this.parentContexts.getContext(outletName)?.outlet === this;
|
|
}
|
|
/** @nodoc */
|
|
ngOnInit() {
|
|
this.initializeOutletWithName();
|
|
}
|
|
initializeOutletWithName() {
|
|
this.parentContexts.onChildOutletCreated(this.name, this);
|
|
if (this.activated) {
|
|
return;
|
|
}
|
|
const context = this.parentContexts.getContext(this.name);
|
|
if (context?.route) {
|
|
if (context.attachRef) {
|
|
this.attach(context.attachRef, context.route);
|
|
} else {
|
|
this.activateWith(context.route, context.injector);
|
|
}
|
|
}
|
|
}
|
|
get isActivated() {
|
|
return !!this.activated;
|
|
}
|
|
/**
|
|
* @returns The currently activated component instance.
|
|
* @throws An error if the outlet is not activated.
|
|
*/
|
|
get component() {
|
|
if (!this.activated)
|
|
throw new RuntimeError(4012, (typeof ngDevMode === "undefined" || ngDevMode) && "Outlet is not activated");
|
|
return this.activated.instance;
|
|
}
|
|
get activatedRoute() {
|
|
if (!this.activated)
|
|
throw new RuntimeError(4012, (typeof ngDevMode === "undefined" || ngDevMode) && "Outlet is not activated");
|
|
return this._activatedRoute;
|
|
}
|
|
get activatedRouteData() {
|
|
if (this._activatedRoute) {
|
|
return this._activatedRoute.snapshot.data;
|
|
}
|
|
return {};
|
|
}
|
|
/**
|
|
* Called when the `RouteReuseStrategy` instructs to detach the subtree
|
|
*/
|
|
detach() {
|
|
if (!this.activated)
|
|
throw new RuntimeError(4012, (typeof ngDevMode === "undefined" || ngDevMode) && "Outlet is not activated");
|
|
this.location.detach();
|
|
const cmp = this.activated;
|
|
this.activated = null;
|
|
this._activatedRoute = null;
|
|
this.detachEvents.emit(cmp.instance);
|
|
return cmp;
|
|
}
|
|
/**
|
|
* Called when the `RouteReuseStrategy` instructs to re-attach a previously detached subtree
|
|
*/
|
|
attach(ref, activatedRoute) {
|
|
this.activated = ref;
|
|
this._activatedRoute = activatedRoute;
|
|
this.location.insert(ref.hostView);
|
|
this.inputBinder?.bindActivatedRouteToOutletComponent(this);
|
|
this.attachEvents.emit(ref.instance);
|
|
}
|
|
deactivate() {
|
|
if (this.activated) {
|
|
const c = this.component;
|
|
this.activated.destroy();
|
|
this.activated = null;
|
|
this._activatedRoute = null;
|
|
this.deactivateEvents.emit(c);
|
|
}
|
|
}
|
|
activateWith(activatedRoute, environmentInjector) {
|
|
if (this.isActivated) {
|
|
throw new RuntimeError(4013, (typeof ngDevMode === "undefined" || ngDevMode) && "Cannot activate an already activated outlet");
|
|
}
|
|
this._activatedRoute = activatedRoute;
|
|
const location = this.location;
|
|
const snapshot = activatedRoute.snapshot;
|
|
const component = snapshot.component;
|
|
const childContexts = this.parentContexts.getOrCreateContext(this.name).children;
|
|
const injector = new OutletInjector(activatedRoute, childContexts, location.injector);
|
|
this.activated = location.createComponent(component, {
|
|
index: location.length,
|
|
injector,
|
|
environmentInjector: environmentInjector ?? this.environmentInjector
|
|
});
|
|
this.changeDetector.markForCheck();
|
|
this.inputBinder?.bindActivatedRouteToOutletComponent(this);
|
|
this.activateEvents.emit(this.activated.instance);
|
|
}
|
|
};
|
|
_RouterOutlet.ɵfac = function RouterOutlet_Factory(t) {
|
|
return new (t || _RouterOutlet)();
|
|
};
|
|
_RouterOutlet.ɵdir = ɵɵdefineDirective({
|
|
type: _RouterOutlet,
|
|
selectors: [["router-outlet"]],
|
|
inputs: {
|
|
name: "name"
|
|
},
|
|
outputs: {
|
|
activateEvents: "activate",
|
|
deactivateEvents: "deactivate",
|
|
attachEvents: "attach",
|
|
detachEvents: "detach"
|
|
},
|
|
exportAs: ["outlet"],
|
|
standalone: true,
|
|
features: [ɵɵNgOnChangesFeature]
|
|
});
|
|
var RouterOutlet = _RouterOutlet;
|
|
(() => {
|
|
(typeof ngDevMode === "undefined" || ngDevMode) && setClassMetadata(RouterOutlet, [{
|
|
type: Directive,
|
|
args: [{
|
|
selector: "router-outlet",
|
|
exportAs: "outlet",
|
|
standalone: true
|
|
}]
|
|
}], null, {
|
|
name: [{
|
|
type: Input
|
|
}],
|
|
activateEvents: [{
|
|
type: Output,
|
|
args: ["activate"]
|
|
}],
|
|
deactivateEvents: [{
|
|
type: Output,
|
|
args: ["deactivate"]
|
|
}],
|
|
attachEvents: [{
|
|
type: Output,
|
|
args: ["attach"]
|
|
}],
|
|
detachEvents: [{
|
|
type: Output,
|
|
args: ["detach"]
|
|
}]
|
|
});
|
|
})();
|
|
var OutletInjector = class {
|
|
constructor(route, childContexts, parent) {
|
|
this.route = route;
|
|
this.childContexts = childContexts;
|
|
this.parent = parent;
|
|
}
|
|
get(token, notFoundValue) {
|
|
if (token === ActivatedRoute) {
|
|
return this.route;
|
|
}
|
|
if (token === ChildrenOutletContexts) {
|
|
return this.childContexts;
|
|
}
|
|
return this.parent.get(token, notFoundValue);
|
|
}
|
|
};
|
|
var INPUT_BINDER = new InjectionToken("");
|
|
var _RoutedComponentInputBinder = class _RoutedComponentInputBinder {
|
|
constructor() {
|
|
this.outletDataSubscriptions = /* @__PURE__ */ new Map();
|
|
}
|
|
bindActivatedRouteToOutletComponent(outlet) {
|
|
this.unsubscribeFromRouteData(outlet);
|
|
this.subscribeToRouteData(outlet);
|
|
}
|
|
unsubscribeFromRouteData(outlet) {
|
|
this.outletDataSubscriptions.get(outlet)?.unsubscribe();
|
|
this.outletDataSubscriptions.delete(outlet);
|
|
}
|
|
subscribeToRouteData(outlet) {
|
|
const {
|
|
activatedRoute
|
|
} = outlet;
|
|
const dataSubscription = combineLatest([activatedRoute.queryParams, activatedRoute.params, activatedRoute.data]).pipe(switchMap(([queryParams, params, data], index) => {
|
|
data = __spreadValues(__spreadValues(__spreadValues({}, queryParams), params), data);
|
|
if (index === 0) {
|
|
return of(data);
|
|
}
|
|
return Promise.resolve(data);
|
|
})).subscribe((data) => {
|
|
if (!outlet.isActivated || !outlet.activatedComponentRef || outlet.activatedRoute !== activatedRoute || activatedRoute.component === null) {
|
|
this.unsubscribeFromRouteData(outlet);
|
|
return;
|
|
}
|
|
const mirror = reflectComponentType(activatedRoute.component);
|
|
if (!mirror) {
|
|
this.unsubscribeFromRouteData(outlet);
|
|
return;
|
|
}
|
|
for (const {
|
|
templateName
|
|
} of mirror.inputs) {
|
|
outlet.activatedComponentRef.setInput(templateName, data[templateName]);
|
|
}
|
|
});
|
|
this.outletDataSubscriptions.set(outlet, dataSubscription);
|
|
}
|
|
};
|
|
_RoutedComponentInputBinder.ɵfac = function RoutedComponentInputBinder_Factory(t) {
|
|
return new (t || _RoutedComponentInputBinder)();
|
|
};
|
|
_RoutedComponentInputBinder.ɵprov = ɵɵdefineInjectable({
|
|
token: _RoutedComponentInputBinder,
|
|
factory: _RoutedComponentInputBinder.ɵfac
|
|
});
|
|
var RoutedComponentInputBinder = _RoutedComponentInputBinder;
|
|
(() => {
|
|
(typeof ngDevMode === "undefined" || ngDevMode) && setClassMetadata(RoutedComponentInputBinder, [{
|
|
type: Injectable
|
|
}], null, null);
|
|
})();
|
|
function createRouterState(routeReuseStrategy, curr, prevState) {
|
|
const root = createNode(routeReuseStrategy, curr._root, prevState ? prevState._root : void 0);
|
|
return new RouterState(root, curr);
|
|
}
|
|
function createNode(routeReuseStrategy, curr, prevState) {
|
|
if (prevState && routeReuseStrategy.shouldReuseRoute(curr.value, prevState.value.snapshot)) {
|
|
const value = prevState.value;
|
|
value._futureSnapshot = curr.value;
|
|
const children = createOrReuseChildren(routeReuseStrategy, curr, prevState);
|
|
return new TreeNode(value, children);
|
|
} else {
|
|
if (routeReuseStrategy.shouldAttach(curr.value)) {
|
|
const detachedRouteHandle = routeReuseStrategy.retrieve(curr.value);
|
|
if (detachedRouteHandle !== null) {
|
|
const tree2 = detachedRouteHandle.route;
|
|
tree2.value._futureSnapshot = curr.value;
|
|
tree2.children = curr.children.map((c) => createNode(routeReuseStrategy, c));
|
|
return tree2;
|
|
}
|
|
}
|
|
const value = createActivatedRoute(curr.value);
|
|
const children = curr.children.map((c) => createNode(routeReuseStrategy, c));
|
|
return new TreeNode(value, children);
|
|
}
|
|
}
|
|
function createOrReuseChildren(routeReuseStrategy, curr, prevState) {
|
|
return curr.children.map((child) => {
|
|
for (const p of prevState.children) {
|
|
if (routeReuseStrategy.shouldReuseRoute(child.value, p.value.snapshot)) {
|
|
return createNode(routeReuseStrategy, child, p);
|
|
}
|
|
}
|
|
return createNode(routeReuseStrategy, child);
|
|
});
|
|
}
|
|
function createActivatedRoute(c) {
|
|
return new ActivatedRoute(new BehaviorSubject(c.url), new BehaviorSubject(c.params), new BehaviorSubject(c.queryParams), new BehaviorSubject(c.fragment), new BehaviorSubject(c.data), c.outlet, c.component, c);
|
|
}
|
|
var NAVIGATION_CANCELING_ERROR = "ngNavigationCancelingError";
|
|
function redirectingNavigationError(urlSerializer, redirect) {
|
|
const {
|
|
redirectTo,
|
|
navigationBehaviorOptions
|
|
} = isUrlTree(redirect) ? {
|
|
redirectTo: redirect,
|
|
navigationBehaviorOptions: void 0
|
|
} : redirect;
|
|
const error = navigationCancelingError(ngDevMode && `Redirecting to "${urlSerializer.serialize(redirectTo)}"`, 0, redirect);
|
|
error.url = redirectTo;
|
|
error.navigationBehaviorOptions = navigationBehaviorOptions;
|
|
return error;
|
|
}
|
|
function navigationCancelingError(message, code, redirectUrl) {
|
|
const error = new Error("NavigationCancelingError: " + (message || ""));
|
|
error[NAVIGATION_CANCELING_ERROR] = true;
|
|
error.cancellationCode = code;
|
|
if (redirectUrl) {
|
|
error.url = redirectUrl;
|
|
}
|
|
return error;
|
|
}
|
|
function isRedirectingNavigationCancelingError$1(error) {
|
|
return isNavigationCancelingError$1(error) && isUrlTree(error.url);
|
|
}
|
|
function isNavigationCancelingError$1(error) {
|
|
return error && error[NAVIGATION_CANCELING_ERROR];
|
|
}
|
|
var _ɵEmptyOutletComponent = class _ɵEmptyOutletComponent {
|
|
};
|
|
_ɵEmptyOutletComponent.ɵfac = function ɵEmptyOutletComponent_Factory(t) {
|
|
return new (t || _ɵEmptyOutletComponent)();
|
|
};
|
|
_ɵEmptyOutletComponent.ɵcmp = ɵɵdefineComponent({
|
|
type: _ɵEmptyOutletComponent,
|
|
selectors: [["ng-component"]],
|
|
standalone: true,
|
|
features: [ɵɵStandaloneFeature],
|
|
decls: 1,
|
|
vars: 0,
|
|
template: function ɵEmptyOutletComponent_Template(rf, ctx) {
|
|
if (rf & 1) {
|
|
ɵɵelement(0, "router-outlet");
|
|
}
|
|
},
|
|
dependencies: [RouterOutlet],
|
|
encapsulation: 2
|
|
});
|
|
var ɵEmptyOutletComponent = _ɵEmptyOutletComponent;
|
|
(() => {
|
|
(typeof ngDevMode === "undefined" || ngDevMode) && setClassMetadata(ɵEmptyOutletComponent, [{
|
|
type: Component,
|
|
args: [{
|
|
template: `<router-outlet></router-outlet>`,
|
|
imports: [RouterOutlet],
|
|
standalone: true
|
|
}]
|
|
}], null, null);
|
|
})();
|
|
function getOrCreateRouteInjectorIfNeeded(route, currentInjector) {
|
|
if (route.providers && !route._injector) {
|
|
route._injector = createEnvironmentInjector(route.providers, currentInjector, `Route: ${route.path}`);
|
|
}
|
|
return route._injector ?? currentInjector;
|
|
}
|
|
function validateConfig(config, parentPath = "", requireStandaloneComponents = false) {
|
|
for (let i = 0; i < config.length; i++) {
|
|
const route = config[i];
|
|
const fullPath = getFullPath(parentPath, route);
|
|
validateNode(route, fullPath, requireStandaloneComponents);
|
|
}
|
|
}
|
|
function assertStandalone(fullPath, component) {
|
|
if (component && isNgModule(component)) {
|
|
throw new RuntimeError(4014, `Invalid configuration of route '${fullPath}'. You are using 'loadComponent' with a module, but it must be used with standalone components. Use 'loadChildren' instead.`);
|
|
} else if (component && !isStandalone(component)) {
|
|
throw new RuntimeError(4014, `Invalid configuration of route '${fullPath}'. The component must be standalone.`);
|
|
}
|
|
}
|
|
function validateNode(route, fullPath, requireStandaloneComponents) {
|
|
if (typeof ngDevMode === "undefined" || ngDevMode) {
|
|
if (!route) {
|
|
throw new RuntimeError(4014, `
|
|
Invalid configuration of route '${fullPath}': Encountered undefined route.
|
|
The reason might be an extra comma.
|
|
|
|
Example:
|
|
const routes: Routes = [
|
|
{ path: '', redirectTo: '/dashboard', pathMatch: 'full' },
|
|
{ path: 'dashboard', component: DashboardComponent },, << two commas
|
|
{ path: 'detail/:id', component: HeroDetailComponent }
|
|
];
|
|
`);
|
|
}
|
|
if (Array.isArray(route)) {
|
|
throw new RuntimeError(4014, `Invalid configuration of route '${fullPath}': Array cannot be specified`);
|
|
}
|
|
if (!route.redirectTo && !route.component && !route.loadComponent && !route.children && !route.loadChildren && route.outlet && route.outlet !== PRIMARY_OUTLET) {
|
|
throw new RuntimeError(4014, `Invalid configuration of route '${fullPath}': a componentless route without children or loadChildren cannot have a named outlet set`);
|
|
}
|
|
if (route.redirectTo && route.children) {
|
|
throw new RuntimeError(4014, `Invalid configuration of route '${fullPath}': redirectTo and children cannot be used together`);
|
|
}
|
|
if (route.redirectTo && route.loadChildren) {
|
|
throw new RuntimeError(4014, `Invalid configuration of route '${fullPath}': redirectTo and loadChildren cannot be used together`);
|
|
}
|
|
if (route.children && route.loadChildren) {
|
|
throw new RuntimeError(4014, `Invalid configuration of route '${fullPath}': children and loadChildren cannot be used together`);
|
|
}
|
|
if (route.redirectTo && (route.component || route.loadComponent)) {
|
|
throw new RuntimeError(4014, `Invalid configuration of route '${fullPath}': redirectTo and component/loadComponent cannot be used together`);
|
|
}
|
|
if (route.component && route.loadComponent) {
|
|
throw new RuntimeError(4014, `Invalid configuration of route '${fullPath}': component and loadComponent cannot be used together`);
|
|
}
|
|
if (route.redirectTo && route.canActivate) {
|
|
throw new RuntimeError(4014, `Invalid configuration of route '${fullPath}': redirectTo and canActivate cannot be used together. Redirects happen before activation so canActivate will never be executed.`);
|
|
}
|
|
if (route.path && route.matcher) {
|
|
throw new RuntimeError(4014, `Invalid configuration of route '${fullPath}': path and matcher cannot be used together`);
|
|
}
|
|
if (route.redirectTo === void 0 && !route.component && !route.loadComponent && !route.children && !route.loadChildren) {
|
|
throw new RuntimeError(4014, `Invalid configuration of route '${fullPath}'. One of the following must be provided: component, loadComponent, redirectTo, children or loadChildren`);
|
|
}
|
|
if (route.path === void 0 && route.matcher === void 0) {
|
|
throw new RuntimeError(4014, `Invalid configuration of route '${fullPath}': routes must have either a path or a matcher specified`);
|
|
}
|
|
if (typeof route.path === "string" && route.path.charAt(0) === "/") {
|
|
throw new RuntimeError(4014, `Invalid configuration of route '${fullPath}': path cannot start with a slash`);
|
|
}
|
|
if (route.path === "" && route.redirectTo !== void 0 && route.pathMatch === void 0) {
|
|
const exp = `The default value of 'pathMatch' is 'prefix', but often the intent is to use 'full'.`;
|
|
throw new RuntimeError(4014, `Invalid configuration of route '{path: "${fullPath}", redirectTo: "${route.redirectTo}"}': please provide 'pathMatch'. ${exp}`);
|
|
}
|
|
if (requireStandaloneComponents) {
|
|
assertStandalone(fullPath, route.component);
|
|
}
|
|
}
|
|
if (route.children) {
|
|
validateConfig(route.children, fullPath, requireStandaloneComponents);
|
|
}
|
|
}
|
|
function getFullPath(parentPath, currentRoute) {
|
|
if (!currentRoute) {
|
|
return parentPath;
|
|
}
|
|
if (!parentPath && !currentRoute.path) {
|
|
return "";
|
|
} else if (parentPath && !currentRoute.path) {
|
|
return `${parentPath}/`;
|
|
} else if (!parentPath && currentRoute.path) {
|
|
return currentRoute.path;
|
|
} else {
|
|
return `${parentPath}/${currentRoute.path}`;
|
|
}
|
|
}
|
|
function standardizeConfig(r) {
|
|
const children = r.children && r.children.map(standardizeConfig);
|
|
const c = children ? __spreadProps(__spreadValues({}, r), {
|
|
children
|
|
}) : __spreadValues({}, r);
|
|
if (!c.component && !c.loadComponent && (children || c.loadChildren) && c.outlet && c.outlet !== PRIMARY_OUTLET) {
|
|
c.component = ɵEmptyOutletComponent;
|
|
}
|
|
return c;
|
|
}
|
|
function getOutlet(route) {
|
|
return route.outlet || PRIMARY_OUTLET;
|
|
}
|
|
function sortByMatchingOutlets(routes, outletName) {
|
|
const sortedConfig = routes.filter((r) => getOutlet(r) === outletName);
|
|
sortedConfig.push(...routes.filter((r) => getOutlet(r) !== outletName));
|
|
return sortedConfig;
|
|
}
|
|
function getClosestRouteInjector(snapshot) {
|
|
if (!snapshot)
|
|
return null;
|
|
if (snapshot.routeConfig?._injector) {
|
|
return snapshot.routeConfig._injector;
|
|
}
|
|
for (let s = snapshot.parent; s; s = s.parent) {
|
|
const route = s.routeConfig;
|
|
if (route?._loadedInjector)
|
|
return route._loadedInjector;
|
|
if (route?._injector)
|
|
return route._injector;
|
|
}
|
|
return null;
|
|
}
|
|
var warnedAboutUnsupportedInputBinding = false;
|
|
var activateRoutes = (rootContexts, routeReuseStrategy, forwardEvent, inputBindingEnabled) => map((t) => {
|
|
new ActivateRoutes(routeReuseStrategy, t.targetRouterState, t.currentRouterState, forwardEvent, inputBindingEnabled).activate(rootContexts);
|
|
return t;
|
|
});
|
|
var ActivateRoutes = class {
|
|
constructor(routeReuseStrategy, futureState, currState, forwardEvent, inputBindingEnabled) {
|
|
this.routeReuseStrategy = routeReuseStrategy;
|
|
this.futureState = futureState;
|
|
this.currState = currState;
|
|
this.forwardEvent = forwardEvent;
|
|
this.inputBindingEnabled = inputBindingEnabled;
|
|
}
|
|
activate(parentContexts) {
|
|
const futureRoot = this.futureState._root;
|
|
const currRoot = this.currState ? this.currState._root : null;
|
|
this.deactivateChildRoutes(futureRoot, currRoot, parentContexts);
|
|
advanceActivatedRoute(this.futureState.root);
|
|
this.activateChildRoutes(futureRoot, currRoot, parentContexts);
|
|
}
|
|
// De-activate the child route that are not re-used for the future state
|
|
deactivateChildRoutes(futureNode, currNode, contexts) {
|
|
const children = nodeChildrenAsMap(currNode);
|
|
futureNode.children.forEach((futureChild) => {
|
|
const childOutletName = futureChild.value.outlet;
|
|
this.deactivateRoutes(futureChild, children[childOutletName], contexts);
|
|
delete children[childOutletName];
|
|
});
|
|
Object.values(children).forEach((v) => {
|
|
this.deactivateRouteAndItsChildren(v, contexts);
|
|
});
|
|
}
|
|
deactivateRoutes(futureNode, currNode, parentContext) {
|
|
const future = futureNode.value;
|
|
const curr = currNode ? currNode.value : null;
|
|
if (future === curr) {
|
|
if (future.component) {
|
|
const context = parentContext.getContext(future.outlet);
|
|
if (context) {
|
|
this.deactivateChildRoutes(futureNode, currNode, context.children);
|
|
}
|
|
} else {
|
|
this.deactivateChildRoutes(futureNode, currNode, parentContext);
|
|
}
|
|
} else {
|
|
if (curr) {
|
|
this.deactivateRouteAndItsChildren(currNode, parentContext);
|
|
}
|
|
}
|
|
}
|
|
deactivateRouteAndItsChildren(route, parentContexts) {
|
|
if (route.value.component && this.routeReuseStrategy.shouldDetach(route.value.snapshot)) {
|
|
this.detachAndStoreRouteSubtree(route, parentContexts);
|
|
} else {
|
|
this.deactivateRouteAndOutlet(route, parentContexts);
|
|
}
|
|
}
|
|
detachAndStoreRouteSubtree(route, parentContexts) {
|
|
const context = parentContexts.getContext(route.value.outlet);
|
|
const contexts = context && route.value.component ? context.children : parentContexts;
|
|
const children = nodeChildrenAsMap(route);
|
|
for (const childOutlet of Object.keys(children)) {
|
|
this.deactivateRouteAndItsChildren(children[childOutlet], contexts);
|
|
}
|
|
if (context && context.outlet) {
|
|
const componentRef = context.outlet.detach();
|
|
const contexts2 = context.children.onOutletDeactivated();
|
|
this.routeReuseStrategy.store(route.value.snapshot, {
|
|
componentRef,
|
|
route,
|
|
contexts: contexts2
|
|
});
|
|
}
|
|
}
|
|
deactivateRouteAndOutlet(route, parentContexts) {
|
|
const context = parentContexts.getContext(route.value.outlet);
|
|
const contexts = context && route.value.component ? context.children : parentContexts;
|
|
const children = nodeChildrenAsMap(route);
|
|
for (const childOutlet of Object.keys(children)) {
|
|
this.deactivateRouteAndItsChildren(children[childOutlet], contexts);
|
|
}
|
|
if (context) {
|
|
if (context.outlet) {
|
|
context.outlet.deactivate();
|
|
context.children.onOutletDeactivated();
|
|
}
|
|
context.attachRef = null;
|
|
context.route = null;
|
|
}
|
|
}
|
|
activateChildRoutes(futureNode, currNode, contexts) {
|
|
const children = nodeChildrenAsMap(currNode);
|
|
futureNode.children.forEach((c) => {
|
|
this.activateRoutes(c, children[c.value.outlet], contexts);
|
|
this.forwardEvent(new ActivationEnd(c.value.snapshot));
|
|
});
|
|
if (futureNode.children.length) {
|
|
this.forwardEvent(new ChildActivationEnd(futureNode.value.snapshot));
|
|
}
|
|
}
|
|
activateRoutes(futureNode, currNode, parentContexts) {
|
|
const future = futureNode.value;
|
|
const curr = currNode ? currNode.value : null;
|
|
advanceActivatedRoute(future);
|
|
if (future === curr) {
|
|
if (future.component) {
|
|
const context = parentContexts.getOrCreateContext(future.outlet);
|
|
this.activateChildRoutes(futureNode, currNode, context.children);
|
|
} else {
|
|
this.activateChildRoutes(futureNode, currNode, parentContexts);
|
|
}
|
|
} else {
|
|
if (future.component) {
|
|
const context = parentContexts.getOrCreateContext(future.outlet);
|
|
if (this.routeReuseStrategy.shouldAttach(future.snapshot)) {
|
|
const stored = this.routeReuseStrategy.retrieve(future.snapshot);
|
|
this.routeReuseStrategy.store(future.snapshot, null);
|
|
context.children.onOutletReAttached(stored.contexts);
|
|
context.attachRef = stored.componentRef;
|
|
context.route = stored.route.value;
|
|
if (context.outlet) {
|
|
context.outlet.attach(stored.componentRef, stored.route.value);
|
|
}
|
|
advanceActivatedRoute(stored.route.value);
|
|
this.activateChildRoutes(futureNode, null, context.children);
|
|
} else {
|
|
const injector = getClosestRouteInjector(future.snapshot);
|
|
context.attachRef = null;
|
|
context.route = future;
|
|
context.injector = injector;
|
|
if (context.outlet) {
|
|
context.outlet.activateWith(future, context.injector);
|
|
}
|
|
this.activateChildRoutes(futureNode, null, context.children);
|
|
}
|
|
} else {
|
|
this.activateChildRoutes(futureNode, null, parentContexts);
|
|
}
|
|
}
|
|
if (typeof ngDevMode === "undefined" || ngDevMode) {
|
|
const context = parentContexts.getOrCreateContext(future.outlet);
|
|
const outlet = context.outlet;
|
|
if (outlet && this.inputBindingEnabled && !outlet.supportsBindingToComponentInputs && !warnedAboutUnsupportedInputBinding) {
|
|
console.warn(`'withComponentInputBinding' feature is enabled but this application is using an outlet that may not support binding to component inputs.`);
|
|
warnedAboutUnsupportedInputBinding = true;
|
|
}
|
|
}
|
|
}
|
|
};
|
|
var CanActivate = class {
|
|
constructor(path) {
|
|
this.path = path;
|
|
this.route = this.path[this.path.length - 1];
|
|
}
|
|
};
|
|
var CanDeactivate = class {
|
|
constructor(component, route) {
|
|
this.component = component;
|
|
this.route = route;
|
|
}
|
|
};
|
|
function getAllRouteGuards(future, curr, parentContexts) {
|
|
const futureRoot = future._root;
|
|
const currRoot = curr ? curr._root : null;
|
|
return getChildRouteGuards(futureRoot, currRoot, parentContexts, [futureRoot.value]);
|
|
}
|
|
function getCanActivateChild(p) {
|
|
const canActivateChild = p.routeConfig ? p.routeConfig.canActivateChild : null;
|
|
if (!canActivateChild || canActivateChild.length === 0)
|
|
return null;
|
|
return {
|
|
node: p,
|
|
guards: canActivateChild
|
|
};
|
|
}
|
|
function getTokenOrFunctionIdentity(tokenOrFunction, injector) {
|
|
const NOT_FOUND = Symbol();
|
|
const result = injector.get(tokenOrFunction, NOT_FOUND);
|
|
if (result === NOT_FOUND) {
|
|
if (typeof tokenOrFunction === "function" && !isInjectable(tokenOrFunction)) {
|
|
return tokenOrFunction;
|
|
} else {
|
|
return injector.get(tokenOrFunction);
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
function getChildRouteGuards(futureNode, currNode, contexts, futurePath, checks = {
|
|
canDeactivateChecks: [],
|
|
canActivateChecks: []
|
|
}) {
|
|
const prevChildren = nodeChildrenAsMap(currNode);
|
|
futureNode.children.forEach((c) => {
|
|
getRouteGuards(c, prevChildren[c.value.outlet], contexts, futurePath.concat([c.value]), checks);
|
|
delete prevChildren[c.value.outlet];
|
|
});
|
|
Object.entries(prevChildren).forEach(([k, v]) => deactivateRouteAndItsChildren(v, contexts.getContext(k), checks));
|
|
return checks;
|
|
}
|
|
function getRouteGuards(futureNode, currNode, parentContexts, futurePath, checks = {
|
|
canDeactivateChecks: [],
|
|
canActivateChecks: []
|
|
}) {
|
|
const future = futureNode.value;
|
|
const curr = currNode ? currNode.value : null;
|
|
const context = parentContexts ? parentContexts.getContext(futureNode.value.outlet) : null;
|
|
if (curr && future.routeConfig === curr.routeConfig) {
|
|
const shouldRun = shouldRunGuardsAndResolvers(curr, future, future.routeConfig.runGuardsAndResolvers);
|
|
if (shouldRun) {
|
|
checks.canActivateChecks.push(new CanActivate(futurePath));
|
|
} else {
|
|
future.data = curr.data;
|
|
future._resolvedData = curr._resolvedData;
|
|
}
|
|
if (future.component) {
|
|
getChildRouteGuards(futureNode, currNode, context ? context.children : null, futurePath, checks);
|
|
} else {
|
|
getChildRouteGuards(futureNode, currNode, parentContexts, futurePath, checks);
|
|
}
|
|
if (shouldRun && context && context.outlet && context.outlet.isActivated) {
|
|
checks.canDeactivateChecks.push(new CanDeactivate(context.outlet.component, curr));
|
|
}
|
|
} else {
|
|
if (curr) {
|
|
deactivateRouteAndItsChildren(currNode, context, checks);
|
|
}
|
|
checks.canActivateChecks.push(new CanActivate(futurePath));
|
|
if (future.component) {
|
|
getChildRouteGuards(futureNode, null, context ? context.children : null, futurePath, checks);
|
|
} else {
|
|
getChildRouteGuards(futureNode, null, parentContexts, futurePath, checks);
|
|
}
|
|
}
|
|
return checks;
|
|
}
|
|
function shouldRunGuardsAndResolvers(curr, future, mode) {
|
|
if (typeof mode === "function") {
|
|
return mode(curr, future);
|
|
}
|
|
switch (mode) {
|
|
case "pathParamsChange":
|
|
return !equalPath(curr.url, future.url);
|
|
case "pathParamsOrQueryParamsChange":
|
|
return !equalPath(curr.url, future.url) || !shallowEqual(curr.queryParams, future.queryParams);
|
|
case "always":
|
|
return true;
|
|
case "paramsOrQueryParamsChange":
|
|
return !equalParamsAndUrlSegments(curr, future) || !shallowEqual(curr.queryParams, future.queryParams);
|
|
case "paramsChange":
|
|
default:
|
|
return !equalParamsAndUrlSegments(curr, future);
|
|
}
|
|
}
|
|
function deactivateRouteAndItsChildren(route, context, checks) {
|
|
const children = nodeChildrenAsMap(route);
|
|
const r = route.value;
|
|
Object.entries(children).forEach(([childName, node]) => {
|
|
if (!r.component) {
|
|
deactivateRouteAndItsChildren(node, context, checks);
|
|
} else if (context) {
|
|
deactivateRouteAndItsChildren(node, context.children.getContext(childName), checks);
|
|
} else {
|
|
deactivateRouteAndItsChildren(node, null, checks);
|
|
}
|
|
});
|
|
if (!r.component) {
|
|
checks.canDeactivateChecks.push(new CanDeactivate(null, r));
|
|
} else if (context && context.outlet && context.outlet.isActivated) {
|
|
checks.canDeactivateChecks.push(new CanDeactivate(context.outlet.component, r));
|
|
} else {
|
|
checks.canDeactivateChecks.push(new CanDeactivate(null, r));
|
|
}
|
|
}
|
|
function isFunction(v) {
|
|
return typeof v === "function";
|
|
}
|
|
function isBoolean(v) {
|
|
return typeof v === "boolean";
|
|
}
|
|
function isCanLoad(guard) {
|
|
return guard && isFunction(guard.canLoad);
|
|
}
|
|
function isCanActivate(guard) {
|
|
return guard && isFunction(guard.canActivate);
|
|
}
|
|
function isCanActivateChild(guard) {
|
|
return guard && isFunction(guard.canActivateChild);
|
|
}
|
|
function isCanDeactivate(guard) {
|
|
return guard && isFunction(guard.canDeactivate);
|
|
}
|
|
function isCanMatch(guard) {
|
|
return guard && isFunction(guard.canMatch);
|
|
}
|
|
function isEmptyError(e) {
|
|
return e instanceof EmptyError || e?.name === "EmptyError";
|
|
}
|
|
var INITIAL_VALUE = Symbol("INITIAL_VALUE");
|
|
function prioritizedGuardValue() {
|
|
return switchMap((obs) => {
|
|
return combineLatest(obs.map((o) => o.pipe(take(1), startWith(INITIAL_VALUE)))).pipe(map((results) => {
|
|
for (const result of results) {
|
|
if (result === true) {
|
|
continue;
|
|
} else if (result === INITIAL_VALUE) {
|
|
return INITIAL_VALUE;
|
|
} else if (result === false || result instanceof UrlTree) {
|
|
return result;
|
|
}
|
|
}
|
|
return true;
|
|
}), filter((item) => item !== INITIAL_VALUE), take(1));
|
|
});
|
|
}
|
|
function checkGuards(injector, forwardEvent) {
|
|
return mergeMap((t) => {
|
|
const {
|
|
targetSnapshot,
|
|
currentSnapshot,
|
|
guards: {
|
|
canActivateChecks,
|
|
canDeactivateChecks
|
|
}
|
|
} = t;
|
|
if (canDeactivateChecks.length === 0 && canActivateChecks.length === 0) {
|
|
return of(__spreadProps(__spreadValues({}, t), {
|
|
guardsResult: true
|
|
}));
|
|
}
|
|
return runCanDeactivateChecks(canDeactivateChecks, targetSnapshot, currentSnapshot, injector).pipe(mergeMap((canDeactivate) => {
|
|
return canDeactivate && isBoolean(canDeactivate) ? runCanActivateChecks(targetSnapshot, canActivateChecks, injector, forwardEvent) : of(canDeactivate);
|
|
}), map((guardsResult) => __spreadProps(__spreadValues({}, t), {
|
|
guardsResult
|
|
})));
|
|
});
|
|
}
|
|
function runCanDeactivateChecks(checks, futureRSS, currRSS, injector) {
|
|
return from(checks).pipe(mergeMap((check) => runCanDeactivate(check.component, check.route, currRSS, futureRSS, injector)), first((result) => {
|
|
return result !== true;
|
|
}, true));
|
|
}
|
|
function runCanActivateChecks(futureSnapshot, checks, injector, forwardEvent) {
|
|
return from(checks).pipe(concatMap((check) => {
|
|
return concat(fireChildActivationStart(check.route.parent, forwardEvent), fireActivationStart(check.route, forwardEvent), runCanActivateChild(futureSnapshot, check.path, injector), runCanActivate(futureSnapshot, check.route, injector));
|
|
}), first((result) => {
|
|
return result !== true;
|
|
}, true));
|
|
}
|
|
function fireActivationStart(snapshot, forwardEvent) {
|
|
if (snapshot !== null && forwardEvent) {
|
|
forwardEvent(new ActivationStart(snapshot));
|
|
}
|
|
return of(true);
|
|
}
|
|
function fireChildActivationStart(snapshot, forwardEvent) {
|
|
if (snapshot !== null && forwardEvent) {
|
|
forwardEvent(new ChildActivationStart(snapshot));
|
|
}
|
|
return of(true);
|
|
}
|
|
function runCanActivate(futureRSS, futureARS, injector) {
|
|
const canActivate = futureARS.routeConfig ? futureARS.routeConfig.canActivate : null;
|
|
if (!canActivate || canActivate.length === 0)
|
|
return of(true);
|
|
const canActivateObservables = canActivate.map((canActivate2) => {
|
|
return defer(() => {
|
|
const closestInjector = getClosestRouteInjector(futureARS) ?? injector;
|
|
const guard = getTokenOrFunctionIdentity(canActivate2, closestInjector);
|
|
const guardVal = isCanActivate(guard) ? guard.canActivate(futureARS, futureRSS) : runInInjectionContext(closestInjector, () => guard(futureARS, futureRSS));
|
|
return wrapIntoObservable(guardVal).pipe(first());
|
|
});
|
|
});
|
|
return of(canActivateObservables).pipe(prioritizedGuardValue());
|
|
}
|
|
function runCanActivateChild(futureRSS, path, injector) {
|
|
const futureARS = path[path.length - 1];
|
|
const canActivateChildGuards = path.slice(0, path.length - 1).reverse().map((p) => getCanActivateChild(p)).filter((_) => _ !== null);
|
|
const canActivateChildGuardsMapped = canActivateChildGuards.map((d) => {
|
|
return defer(() => {
|
|
const guardsMapped = d.guards.map((canActivateChild) => {
|
|
const closestInjector = getClosestRouteInjector(d.node) ?? injector;
|
|
const guard = getTokenOrFunctionIdentity(canActivateChild, closestInjector);
|
|
const guardVal = isCanActivateChild(guard) ? guard.canActivateChild(futureARS, futureRSS) : runInInjectionContext(closestInjector, () => guard(futureARS, futureRSS));
|
|
return wrapIntoObservable(guardVal).pipe(first());
|
|
});
|
|
return of(guardsMapped).pipe(prioritizedGuardValue());
|
|
});
|
|
});
|
|
return of(canActivateChildGuardsMapped).pipe(prioritizedGuardValue());
|
|
}
|
|
function runCanDeactivate(component, currARS, currRSS, futureRSS, injector) {
|
|
const canDeactivate = currARS && currARS.routeConfig ? currARS.routeConfig.canDeactivate : null;
|
|
if (!canDeactivate || canDeactivate.length === 0)
|
|
return of(true);
|
|
const canDeactivateObservables = canDeactivate.map((c) => {
|
|
const closestInjector = getClosestRouteInjector(currARS) ?? injector;
|
|
const guard = getTokenOrFunctionIdentity(c, closestInjector);
|
|
const guardVal = isCanDeactivate(guard) ? guard.canDeactivate(component, currARS, currRSS, futureRSS) : runInInjectionContext(closestInjector, () => guard(component, currARS, currRSS, futureRSS));
|
|
return wrapIntoObservable(guardVal).pipe(first());
|
|
});
|
|
return of(canDeactivateObservables).pipe(prioritizedGuardValue());
|
|
}
|
|
function runCanLoadGuards(injector, route, segments, urlSerializer) {
|
|
const canLoad = route.canLoad;
|
|
if (canLoad === void 0 || canLoad.length === 0) {
|
|
return of(true);
|
|
}
|
|
const canLoadObservables = canLoad.map((injectionToken) => {
|
|
const guard = getTokenOrFunctionIdentity(injectionToken, injector);
|
|
const guardVal = isCanLoad(guard) ? guard.canLoad(route, segments) : runInInjectionContext(injector, () => guard(route, segments));
|
|
return wrapIntoObservable(guardVal);
|
|
});
|
|
return of(canLoadObservables).pipe(prioritizedGuardValue(), redirectIfUrlTree(urlSerializer));
|
|
}
|
|
function redirectIfUrlTree(urlSerializer) {
|
|
return pipe(tap((result) => {
|
|
if (!isUrlTree(result))
|
|
return;
|
|
throw redirectingNavigationError(urlSerializer, result);
|
|
}), map((result) => result === true));
|
|
}
|
|
function runCanMatchGuards(injector, route, segments, urlSerializer) {
|
|
const canMatch = route.canMatch;
|
|
if (!canMatch || canMatch.length === 0)
|
|
return of(true);
|
|
const canMatchObservables = canMatch.map((injectionToken) => {
|
|
const guard = getTokenOrFunctionIdentity(injectionToken, injector);
|
|
const guardVal = isCanMatch(guard) ? guard.canMatch(route, segments) : runInInjectionContext(injector, () => guard(route, segments));
|
|
return wrapIntoObservable(guardVal);
|
|
});
|
|
return of(canMatchObservables).pipe(prioritizedGuardValue(), redirectIfUrlTree(urlSerializer));
|
|
}
|
|
var NoMatch = class {
|
|
constructor(segmentGroup) {
|
|
this.segmentGroup = segmentGroup || null;
|
|
}
|
|
};
|
|
var AbsoluteRedirect = class extends Error {
|
|
constructor(urlTree) {
|
|
super();
|
|
this.urlTree = urlTree;
|
|
}
|
|
};
|
|
function noMatch$1(segmentGroup) {
|
|
return throwError(new NoMatch(segmentGroup));
|
|
}
|
|
function namedOutletsRedirect(redirectTo) {
|
|
return throwError(new RuntimeError(4e3, (typeof ngDevMode === "undefined" || ngDevMode) && `Only absolute redirects can have named outlets. redirectTo: '${redirectTo}'`));
|
|
}
|
|
function canLoadFails(route) {
|
|
return throwError(navigationCancelingError(
|
|
(typeof ngDevMode === "undefined" || ngDevMode) && `Cannot load children because the guard of the route "path: '${route.path}'" returned false`,
|
|
3
|
|
/* NavigationCancellationCode.GuardRejected */
|
|
));
|
|
}
|
|
var ApplyRedirects = class {
|
|
constructor(urlSerializer, urlTree) {
|
|
this.urlSerializer = urlSerializer;
|
|
this.urlTree = urlTree;
|
|
}
|
|
lineralizeSegments(route, urlTree) {
|
|
let res = [];
|
|
let c = urlTree.root;
|
|
while (true) {
|
|
res = res.concat(c.segments);
|
|
if (c.numberOfChildren === 0) {
|
|
return of(res);
|
|
}
|
|
if (c.numberOfChildren > 1 || !c.children[PRIMARY_OUTLET]) {
|
|
return namedOutletsRedirect(route.redirectTo);
|
|
}
|
|
c = c.children[PRIMARY_OUTLET];
|
|
}
|
|
}
|
|
applyRedirectCommands(segments, redirectTo, posParams) {
|
|
const newTree = this.applyRedirectCreateUrlTree(redirectTo, this.urlSerializer.parse(redirectTo), segments, posParams);
|
|
if (redirectTo.startsWith("/")) {
|
|
throw new AbsoluteRedirect(newTree);
|
|
}
|
|
return newTree;
|
|
}
|
|
applyRedirectCreateUrlTree(redirectTo, urlTree, segments, posParams) {
|
|
const newRoot = this.createSegmentGroup(redirectTo, urlTree.root, segments, posParams);
|
|
return new UrlTree(newRoot, this.createQueryParams(urlTree.queryParams, this.urlTree.queryParams), urlTree.fragment);
|
|
}
|
|
createQueryParams(redirectToParams, actualParams) {
|
|
const res = {};
|
|
Object.entries(redirectToParams).forEach(([k, v]) => {
|
|
const copySourceValue = typeof v === "string" && v.startsWith(":");
|
|
if (copySourceValue) {
|
|
const sourceName = v.substring(1);
|
|
res[k] = actualParams[sourceName];
|
|
} else {
|
|
res[k] = v;
|
|
}
|
|
});
|
|
return res;
|
|
}
|
|
createSegmentGroup(redirectTo, group, segments, posParams) {
|
|
const updatedSegments = this.createSegments(redirectTo, group.segments, segments, posParams);
|
|
let children = {};
|
|
Object.entries(group.children).forEach(([name, child]) => {
|
|
children[name] = this.createSegmentGroup(redirectTo, child, segments, posParams);
|
|
});
|
|
return new UrlSegmentGroup(updatedSegments, children);
|
|
}
|
|
createSegments(redirectTo, redirectToSegments, actualSegments, posParams) {
|
|
return redirectToSegments.map((s) => s.path.startsWith(":") ? this.findPosParam(redirectTo, s, posParams) : this.findOrReturn(s, actualSegments));
|
|
}
|
|
findPosParam(redirectTo, redirectToUrlSegment, posParams) {
|
|
const pos = posParams[redirectToUrlSegment.path.substring(1)];
|
|
if (!pos)
|
|
throw new RuntimeError(4001, (typeof ngDevMode === "undefined" || ngDevMode) && `Cannot redirect to '${redirectTo}'. Cannot find '${redirectToUrlSegment.path}'.`);
|
|
return pos;
|
|
}
|
|
findOrReturn(redirectToUrlSegment, actualSegments) {
|
|
let idx = 0;
|
|
for (const s of actualSegments) {
|
|
if (s.path === redirectToUrlSegment.path) {
|
|
actualSegments.splice(idx);
|
|
return s;
|
|
}
|
|
idx++;
|
|
}
|
|
return redirectToUrlSegment;
|
|
}
|
|
};
|
|
var noMatch = {
|
|
matched: false,
|
|
consumedSegments: [],
|
|
remainingSegments: [],
|
|
parameters: {},
|
|
positionalParamSegments: {}
|
|
};
|
|
function matchWithChecks(segmentGroup, route, segments, injector, urlSerializer) {
|
|
const result = match(segmentGroup, route, segments);
|
|
if (!result.matched) {
|
|
return of(result);
|
|
}
|
|
injector = getOrCreateRouteInjectorIfNeeded(route, injector);
|
|
return runCanMatchGuards(injector, route, segments, urlSerializer).pipe(map((v) => v === true ? result : __spreadValues({}, noMatch)));
|
|
}
|
|
function match(segmentGroup, route, segments) {
|
|
if (route.path === "**") {
|
|
return createWildcardMatchResult(segments);
|
|
}
|
|
if (route.path === "") {
|
|
if (route.pathMatch === "full" && (segmentGroup.hasChildren() || segments.length > 0)) {
|
|
return __spreadValues({}, noMatch);
|
|
}
|
|
return {
|
|
matched: true,
|
|
consumedSegments: [],
|
|
remainingSegments: segments,
|
|
parameters: {},
|
|
positionalParamSegments: {}
|
|
};
|
|
}
|
|
const matcher = route.matcher || defaultUrlMatcher;
|
|
const res = matcher(segments, segmentGroup, route);
|
|
if (!res)
|
|
return __spreadValues({}, noMatch);
|
|
const posParams = {};
|
|
Object.entries(res.posParams ?? {}).forEach(([k, v]) => {
|
|
posParams[k] = v.path;
|
|
});
|
|
const parameters = res.consumed.length > 0 ? __spreadValues(__spreadValues({}, posParams), res.consumed[res.consumed.length - 1].parameters) : posParams;
|
|
return {
|
|
matched: true,
|
|
consumedSegments: res.consumed,
|
|
remainingSegments: segments.slice(res.consumed.length),
|
|
// TODO(atscott): investigate combining parameters and positionalParamSegments
|
|
parameters,
|
|
positionalParamSegments: res.posParams ?? {}
|
|
};
|
|
}
|
|
function createWildcardMatchResult(segments) {
|
|
return {
|
|
matched: true,
|
|
parameters: segments.length > 0 ? last2(segments).parameters : {},
|
|
consumedSegments: segments,
|
|
remainingSegments: [],
|
|
positionalParamSegments: {}
|
|
};
|
|
}
|
|
function split(segmentGroup, consumedSegments, slicedSegments, config) {
|
|
if (slicedSegments.length > 0 && containsEmptyPathMatchesWithNamedOutlets(segmentGroup, slicedSegments, config)) {
|
|
const s2 = new UrlSegmentGroup(consumedSegments, createChildrenForEmptyPaths(config, new UrlSegmentGroup(slicedSegments, segmentGroup.children)));
|
|
return {
|
|
segmentGroup: s2,
|
|
slicedSegments: []
|
|
};
|
|
}
|
|
if (slicedSegments.length === 0 && containsEmptyPathMatches(segmentGroup, slicedSegments, config)) {
|
|
const s2 = new UrlSegmentGroup(segmentGroup.segments, addEmptyPathsToChildrenIfNeeded(segmentGroup, consumedSegments, slicedSegments, config, segmentGroup.children));
|
|
return {
|
|
segmentGroup: s2,
|
|
slicedSegments
|
|
};
|
|
}
|
|
const s = new UrlSegmentGroup(segmentGroup.segments, segmentGroup.children);
|
|
return {
|
|
segmentGroup: s,
|
|
slicedSegments
|
|
};
|
|
}
|
|
function addEmptyPathsToChildrenIfNeeded(segmentGroup, consumedSegments, slicedSegments, routes, children) {
|
|
const res = {};
|
|
for (const r of routes) {
|
|
if (emptyPathMatch(segmentGroup, slicedSegments, r) && !children[getOutlet(r)]) {
|
|
const s = new UrlSegmentGroup([], {});
|
|
res[getOutlet(r)] = s;
|
|
}
|
|
}
|
|
return __spreadValues(__spreadValues({}, children), res);
|
|
}
|
|
function createChildrenForEmptyPaths(routes, primarySegment) {
|
|
const res = {};
|
|
res[PRIMARY_OUTLET] = primarySegment;
|
|
for (const r of routes) {
|
|
if (r.path === "" && getOutlet(r) !== PRIMARY_OUTLET) {
|
|
const s = new UrlSegmentGroup([], {});
|
|
res[getOutlet(r)] = s;
|
|
}
|
|
}
|
|
return res;
|
|
}
|
|
function containsEmptyPathMatchesWithNamedOutlets(segmentGroup, slicedSegments, routes) {
|
|
return routes.some((r) => emptyPathMatch(segmentGroup, slicedSegments, r) && getOutlet(r) !== PRIMARY_OUTLET);
|
|
}
|
|
function containsEmptyPathMatches(segmentGroup, slicedSegments, routes) {
|
|
return routes.some((r) => emptyPathMatch(segmentGroup, slicedSegments, r));
|
|
}
|
|
function emptyPathMatch(segmentGroup, slicedSegments, r) {
|
|
if ((segmentGroup.hasChildren() || slicedSegments.length > 0) && r.pathMatch === "full") {
|
|
return false;
|
|
}
|
|
return r.path === "";
|
|
}
|
|
function isImmediateMatch(route, rawSegment, segments, outlet) {
|
|
if (getOutlet(route) !== outlet && (outlet === PRIMARY_OUTLET || !emptyPathMatch(rawSegment, segments, route))) {
|
|
return false;
|
|
}
|
|
return match(rawSegment, route, segments).matched;
|
|
}
|
|
function noLeftoversInUrl(segmentGroup, segments, outlet) {
|
|
return segments.length === 0 && !segmentGroup.children[outlet];
|
|
}
|
|
var NoLeftoversInUrl = class {
|
|
};
|
|
function recognize$1(injector, configLoader, rootComponentType, config, urlTree, urlSerializer, paramsInheritanceStrategy = "emptyOnly") {
|
|
return new Recognizer(injector, configLoader, rootComponentType, config, urlTree, paramsInheritanceStrategy, urlSerializer).recognize();
|
|
}
|
|
var MAX_ALLOWED_REDIRECTS = 31;
|
|
var Recognizer = class {
|
|
constructor(injector, configLoader, rootComponentType, config, urlTree, paramsInheritanceStrategy, urlSerializer) {
|
|
this.injector = injector;
|
|
this.configLoader = configLoader;
|
|
this.rootComponentType = rootComponentType;
|
|
this.config = config;
|
|
this.urlTree = urlTree;
|
|
this.paramsInheritanceStrategy = paramsInheritanceStrategy;
|
|
this.urlSerializer = urlSerializer;
|
|
this.applyRedirects = new ApplyRedirects(this.urlSerializer, this.urlTree);
|
|
this.absoluteRedirectCount = 0;
|
|
this.allowRedirects = true;
|
|
}
|
|
noMatchError(e) {
|
|
return new RuntimeError(4002, typeof ngDevMode === "undefined" || ngDevMode ? `Cannot match any routes. URL Segment: '${e.segmentGroup}'` : `'${e.segmentGroup}'`);
|
|
}
|
|
recognize() {
|
|
const rootSegmentGroup = split(this.urlTree.root, [], [], this.config).segmentGroup;
|
|
return this.match(rootSegmentGroup).pipe(map((children) => {
|
|
const root = new ActivatedRouteSnapshot([], Object.freeze({}), Object.freeze(__spreadValues({}, this.urlTree.queryParams)), this.urlTree.fragment, {}, PRIMARY_OUTLET, this.rootComponentType, null, {});
|
|
const rootNode = new TreeNode(root, children);
|
|
const routeState = new RouterStateSnapshot("", rootNode);
|
|
const tree2 = createUrlTreeFromSnapshot(root, [], this.urlTree.queryParams, this.urlTree.fragment);
|
|
tree2.queryParams = this.urlTree.queryParams;
|
|
routeState.url = this.urlSerializer.serialize(tree2);
|
|
this.inheritParamsAndData(routeState._root, null);
|
|
return {
|
|
state: routeState,
|
|
tree: tree2
|
|
};
|
|
}));
|
|
}
|
|
match(rootSegmentGroup) {
|
|
const expanded$ = this.processSegmentGroup(this.injector, this.config, rootSegmentGroup, PRIMARY_OUTLET);
|
|
return expanded$.pipe(catchError((e) => {
|
|
if (e instanceof AbsoluteRedirect) {
|
|
this.urlTree = e.urlTree;
|
|
return this.match(e.urlTree.root);
|
|
}
|
|
if (e instanceof NoMatch) {
|
|
throw this.noMatchError(e);
|
|
}
|
|
throw e;
|
|
}));
|
|
}
|
|
inheritParamsAndData(routeNode, parent) {
|
|
const route = routeNode.value;
|
|
const i = getInherited(route, parent, this.paramsInheritanceStrategy);
|
|
route.params = Object.freeze(i.params);
|
|
route.data = Object.freeze(i.data);
|
|
routeNode.children.forEach((n) => this.inheritParamsAndData(n, route));
|
|
}
|
|
processSegmentGroup(injector, config, segmentGroup, outlet) {
|
|
if (segmentGroup.segments.length === 0 && segmentGroup.hasChildren()) {
|
|
return this.processChildren(injector, config, segmentGroup);
|
|
}
|
|
return this.processSegment(injector, config, segmentGroup, segmentGroup.segments, outlet, true).pipe(map((child) => child instanceof TreeNode ? [child] : []));
|
|
}
|
|
/**
|
|
* Matches every child outlet in the `segmentGroup` to a `Route` in the config. Returns `null` if
|
|
* we cannot find a match for _any_ of the children.
|
|
*
|
|
* @param config - The `Routes` to match against
|
|
* @param segmentGroup - The `UrlSegmentGroup` whose children need to be matched against the
|
|
* config.
|
|
*/
|
|
processChildren(injector, config, segmentGroup) {
|
|
const childOutlets = [];
|
|
for (const child of Object.keys(segmentGroup.children)) {
|
|
if (child === "primary") {
|
|
childOutlets.unshift(child);
|
|
} else {
|
|
childOutlets.push(child);
|
|
}
|
|
}
|
|
return from(childOutlets).pipe(concatMap((childOutlet) => {
|
|
const child = segmentGroup.children[childOutlet];
|
|
const sortedConfig = sortByMatchingOutlets(config, childOutlet);
|
|
return this.processSegmentGroup(injector, sortedConfig, child, childOutlet);
|
|
}), scan((children, outletChildren) => {
|
|
children.push(...outletChildren);
|
|
return children;
|
|
}), defaultIfEmpty(null), last(), mergeMap((children) => {
|
|
if (children === null)
|
|
return noMatch$1(segmentGroup);
|
|
const mergedChildren = mergeEmptyPathMatches(children);
|
|
if (typeof ngDevMode === "undefined" || ngDevMode) {
|
|
checkOutletNameUniqueness(mergedChildren);
|
|
}
|
|
sortActivatedRouteSnapshots(mergedChildren);
|
|
return of(mergedChildren);
|
|
}));
|
|
}
|
|
processSegment(injector, routes, segmentGroup, segments, outlet, allowRedirects) {
|
|
return from(routes).pipe(concatMap((r) => {
|
|
return this.processSegmentAgainstRoute(r._injector ?? injector, routes, r, segmentGroup, segments, outlet, allowRedirects).pipe(catchError((e) => {
|
|
if (e instanceof NoMatch) {
|
|
return of(null);
|
|
}
|
|
throw e;
|
|
}));
|
|
}), first((x) => !!x), catchError((e) => {
|
|
if (isEmptyError(e)) {
|
|
if (noLeftoversInUrl(segmentGroup, segments, outlet)) {
|
|
return of(new NoLeftoversInUrl());
|
|
}
|
|
return noMatch$1(segmentGroup);
|
|
}
|
|
throw e;
|
|
}));
|
|
}
|
|
processSegmentAgainstRoute(injector, routes, route, rawSegment, segments, outlet, allowRedirects) {
|
|
if (!isImmediateMatch(route, rawSegment, segments, outlet))
|
|
return noMatch$1(rawSegment);
|
|
if (route.redirectTo === void 0) {
|
|
return this.matchSegmentAgainstRoute(injector, rawSegment, route, segments, outlet);
|
|
}
|
|
if (this.allowRedirects && allowRedirects) {
|
|
return this.expandSegmentAgainstRouteUsingRedirect(injector, rawSegment, routes, route, segments, outlet);
|
|
}
|
|
return noMatch$1(rawSegment);
|
|
}
|
|
expandSegmentAgainstRouteUsingRedirect(injector, segmentGroup, routes, route, segments, outlet) {
|
|
const {
|
|
matched,
|
|
consumedSegments,
|
|
positionalParamSegments,
|
|
remainingSegments
|
|
} = match(segmentGroup, route, segments);
|
|
if (!matched)
|
|
return noMatch$1(segmentGroup);
|
|
if (route.redirectTo.startsWith("/")) {
|
|
this.absoluteRedirectCount++;
|
|
if (this.absoluteRedirectCount > MAX_ALLOWED_REDIRECTS) {
|
|
if (ngDevMode) {
|
|
throw new RuntimeError(4016, `Detected possible infinite redirect when redirecting from '${this.urlTree}' to '${route.redirectTo}'.
|
|
This is currently a dev mode only error but will become a call stack size exceeded error in production in a future major version.`);
|
|
}
|
|
this.allowRedirects = false;
|
|
}
|
|
}
|
|
const newTree = this.applyRedirects.applyRedirectCommands(consumedSegments, route.redirectTo, positionalParamSegments);
|
|
return this.applyRedirects.lineralizeSegments(route, newTree).pipe(mergeMap((newSegments) => {
|
|
return this.processSegment(injector, routes, segmentGroup, newSegments.concat(remainingSegments), outlet, false);
|
|
}));
|
|
}
|
|
matchSegmentAgainstRoute(injector, rawSegment, route, segments, outlet) {
|
|
const matchResult = matchWithChecks(rawSegment, route, segments, injector, this.urlSerializer);
|
|
if (route.path === "**") {
|
|
rawSegment.children = {};
|
|
}
|
|
return matchResult.pipe(switchMap((result) => {
|
|
if (!result.matched) {
|
|
return noMatch$1(rawSegment);
|
|
}
|
|
injector = route._injector ?? injector;
|
|
return this.getChildConfig(injector, route, segments).pipe(switchMap(({
|
|
routes: childConfig
|
|
}) => {
|
|
const childInjector = route._loadedInjector ?? injector;
|
|
const {
|
|
consumedSegments,
|
|
remainingSegments,
|
|
parameters
|
|
} = result;
|
|
const snapshot = new ActivatedRouteSnapshot(consumedSegments, parameters, Object.freeze(__spreadValues({}, this.urlTree.queryParams)), this.urlTree.fragment, getData(route), getOutlet(route), route.component ?? route._loadedComponent ?? null, route, getResolve(route));
|
|
const {
|
|
segmentGroup,
|
|
slicedSegments
|
|
} = split(rawSegment, consumedSegments, remainingSegments, childConfig);
|
|
if (slicedSegments.length === 0 && segmentGroup.hasChildren()) {
|
|
return this.processChildren(childInjector, childConfig, segmentGroup).pipe(map((children) => {
|
|
if (children === null) {
|
|
return null;
|
|
}
|
|
return new TreeNode(snapshot, children);
|
|
}));
|
|
}
|
|
if (childConfig.length === 0 && slicedSegments.length === 0) {
|
|
return of(new TreeNode(snapshot, []));
|
|
}
|
|
const matchedOnOutlet = getOutlet(route) === outlet;
|
|
return this.processSegment(childInjector, childConfig, segmentGroup, slicedSegments, matchedOnOutlet ? PRIMARY_OUTLET : outlet, true).pipe(map((child) => {
|
|
return new TreeNode(snapshot, child instanceof TreeNode ? [child] : []);
|
|
}));
|
|
}));
|
|
}));
|
|
}
|
|
getChildConfig(injector, route, segments) {
|
|
if (route.children) {
|
|
return of({
|
|
routes: route.children,
|
|
injector
|
|
});
|
|
}
|
|
if (route.loadChildren) {
|
|
if (route._loadedRoutes !== void 0) {
|
|
return of({
|
|
routes: route._loadedRoutes,
|
|
injector: route._loadedInjector
|
|
});
|
|
}
|
|
return runCanLoadGuards(injector, route, segments, this.urlSerializer).pipe(mergeMap((shouldLoadResult) => {
|
|
if (shouldLoadResult) {
|
|
return this.configLoader.loadChildren(injector, route).pipe(tap((cfg) => {
|
|
route._loadedRoutes = cfg.routes;
|
|
route._loadedInjector = cfg.injector;
|
|
}));
|
|
}
|
|
return canLoadFails(route);
|
|
}));
|
|
}
|
|
return of({
|
|
routes: [],
|
|
injector
|
|
});
|
|
}
|
|
};
|
|
function sortActivatedRouteSnapshots(nodes) {
|
|
nodes.sort((a, b) => {
|
|
if (a.value.outlet === PRIMARY_OUTLET)
|
|
return -1;
|
|
if (b.value.outlet === PRIMARY_OUTLET)
|
|
return 1;
|
|
return a.value.outlet.localeCompare(b.value.outlet);
|
|
});
|
|
}
|
|
function hasEmptyPathConfig(node) {
|
|
const config = node.value.routeConfig;
|
|
return config && config.path === "";
|
|
}
|
|
function mergeEmptyPathMatches(nodes) {
|
|
const result = [];
|
|
const mergedNodes = /* @__PURE__ */ new Set();
|
|
for (const node of nodes) {
|
|
if (!hasEmptyPathConfig(node)) {
|
|
result.push(node);
|
|
continue;
|
|
}
|
|
const duplicateEmptyPathNode = result.find((resultNode) => node.value.routeConfig === resultNode.value.routeConfig);
|
|
if (duplicateEmptyPathNode !== void 0) {
|
|
duplicateEmptyPathNode.children.push(...node.children);
|
|
mergedNodes.add(duplicateEmptyPathNode);
|
|
} else {
|
|
result.push(node);
|
|
}
|
|
}
|
|
for (const mergedNode of mergedNodes) {
|
|
const mergedChildren = mergeEmptyPathMatches(mergedNode.children);
|
|
result.push(new TreeNode(mergedNode.value, mergedChildren));
|
|
}
|
|
return result.filter((n) => !mergedNodes.has(n));
|
|
}
|
|
function checkOutletNameUniqueness(nodes) {
|
|
const names = {};
|
|
nodes.forEach((n) => {
|
|
const routeWithSameOutletName = names[n.value.outlet];
|
|
if (routeWithSameOutletName) {
|
|
const p = routeWithSameOutletName.url.map((s) => s.toString()).join("/");
|
|
const c = n.value.url.map((s) => s.toString()).join("/");
|
|
throw new RuntimeError(4006, (typeof ngDevMode === "undefined" || ngDevMode) && `Two segments cannot have the same outlet name: '${p}' and '${c}'.`);
|
|
}
|
|
names[n.value.outlet] = n.value;
|
|
});
|
|
}
|
|
function getData(route) {
|
|
return route.data || {};
|
|
}
|
|
function getResolve(route) {
|
|
return route.resolve || {};
|
|
}
|
|
function recognize(injector, configLoader, rootComponentType, config, serializer, paramsInheritanceStrategy) {
|
|
return mergeMap((t) => recognize$1(injector, configLoader, rootComponentType, config, t.extractedUrl, serializer, paramsInheritanceStrategy).pipe(map(({
|
|
state: targetSnapshot,
|
|
tree: urlAfterRedirects
|
|
}) => {
|
|
return __spreadProps(__spreadValues({}, t), {
|
|
targetSnapshot,
|
|
urlAfterRedirects
|
|
});
|
|
})));
|
|
}
|
|
function resolveData(paramsInheritanceStrategy, injector) {
|
|
return mergeMap((t) => {
|
|
const {
|
|
targetSnapshot,
|
|
guards: {
|
|
canActivateChecks
|
|
}
|
|
} = t;
|
|
if (!canActivateChecks.length) {
|
|
return of(t);
|
|
}
|
|
const routesWithResolversToRun = new Set(canActivateChecks.map((check) => check.route));
|
|
const routesNeedingDataUpdates = /* @__PURE__ */ new Set();
|
|
for (const route of routesWithResolversToRun) {
|
|
if (routesNeedingDataUpdates.has(route)) {
|
|
continue;
|
|
}
|
|
for (const newRoute of flattenRouteTree(route)) {
|
|
routesNeedingDataUpdates.add(newRoute);
|
|
}
|
|
}
|
|
let routesProcessed = 0;
|
|
return from(routesNeedingDataUpdates).pipe(concatMap((route) => {
|
|
if (routesWithResolversToRun.has(route)) {
|
|
return runResolve(route, targetSnapshot, paramsInheritanceStrategy, injector);
|
|
} else {
|
|
route.data = getInherited(route, route.parent, paramsInheritanceStrategy).resolve;
|
|
return of(void 0);
|
|
}
|
|
}), tap(() => routesProcessed++), takeLast(1), mergeMap((_) => routesProcessed === routesNeedingDataUpdates.size ? of(t) : EMPTY));
|
|
});
|
|
}
|
|
function flattenRouteTree(route) {
|
|
const descendants = route.children.map((child) => flattenRouteTree(child)).flat();
|
|
return [route, ...descendants];
|
|
}
|
|
function runResolve(futureARS, futureRSS, paramsInheritanceStrategy, injector) {
|
|
const config = futureARS.routeConfig;
|
|
const resolve = futureARS._resolve;
|
|
if (config?.title !== void 0 && !hasStaticTitle(config)) {
|
|
resolve[RouteTitleKey] = config.title;
|
|
}
|
|
return resolveNode(resolve, futureARS, futureRSS, injector).pipe(map((resolvedData) => {
|
|
futureARS._resolvedData = resolvedData;
|
|
futureARS.data = getInherited(futureARS, futureARS.parent, paramsInheritanceStrategy).resolve;
|
|
return null;
|
|
}));
|
|
}
|
|
function resolveNode(resolve, futureARS, futureRSS, injector) {
|
|
const keys = getDataKeys(resolve);
|
|
if (keys.length === 0) {
|
|
return of({});
|
|
}
|
|
const data = {};
|
|
return from(keys).pipe(mergeMap((key) => getResolver(resolve[key], futureARS, futureRSS, injector).pipe(first(), tap((value) => {
|
|
data[key] = value;
|
|
}))), takeLast(1), mapTo(data), catchError((e) => isEmptyError(e) ? EMPTY : throwError(e)));
|
|
}
|
|
function getResolver(injectionToken, futureARS, futureRSS, injector) {
|
|
const closestInjector = getClosestRouteInjector(futureARS) ?? injector;
|
|
const resolver = getTokenOrFunctionIdentity(injectionToken, closestInjector);
|
|
const resolverValue = resolver.resolve ? resolver.resolve(futureARS, futureRSS) : runInInjectionContext(closestInjector, () => resolver(futureARS, futureRSS));
|
|
return wrapIntoObservable(resolverValue);
|
|
}
|
|
function switchTap(next) {
|
|
return switchMap((v) => {
|
|
const nextResult = next(v);
|
|
if (nextResult) {
|
|
return from(nextResult).pipe(map(() => v));
|
|
}
|
|
return of(v);
|
|
});
|
|
}
|
|
var _TitleStrategy = class _TitleStrategy {
|
|
/**
|
|
* @returns The `title` of the deepest primary route.
|
|
*/
|
|
buildTitle(snapshot) {
|
|
let pageTitle;
|
|
let route = snapshot.root;
|
|
while (route !== void 0) {
|
|
pageTitle = this.getResolvedTitleForRoute(route) ?? pageTitle;
|
|
route = route.children.find((child) => child.outlet === PRIMARY_OUTLET);
|
|
}
|
|
return pageTitle;
|
|
}
|
|
/**
|
|
* Given an `ActivatedRouteSnapshot`, returns the final value of the
|
|
* `Route.title` property, which can either be a static string or a resolved value.
|
|
*/
|
|
getResolvedTitleForRoute(snapshot) {
|
|
return snapshot.data[RouteTitleKey];
|
|
}
|
|
};
|
|
_TitleStrategy.ɵfac = function TitleStrategy_Factory(t) {
|
|
return new (t || _TitleStrategy)();
|
|
};
|
|
_TitleStrategy.ɵprov = ɵɵdefineInjectable({
|
|
token: _TitleStrategy,
|
|
factory: () => (() => inject(DefaultTitleStrategy))(),
|
|
providedIn: "root"
|
|
});
|
|
var TitleStrategy = _TitleStrategy;
|
|
(() => {
|
|
(typeof ngDevMode === "undefined" || ngDevMode) && setClassMetadata(TitleStrategy, [{
|
|
type: Injectable,
|
|
args: [{
|
|
providedIn: "root",
|
|
useFactory: () => inject(DefaultTitleStrategy)
|
|
}]
|
|
}], null, null);
|
|
})();
|
|
var _DefaultTitleStrategy = class _DefaultTitleStrategy extends TitleStrategy {
|
|
constructor(title) {
|
|
super();
|
|
this.title = title;
|
|
}
|
|
/**
|
|
* Sets the title of the browser to the given value.
|
|
*
|
|
* @param title The `pageTitle` from the deepest primary route.
|
|
*/
|
|
updateTitle(snapshot) {
|
|
const title = this.buildTitle(snapshot);
|
|
if (title !== void 0) {
|
|
this.title.setTitle(title);
|
|
}
|
|
}
|
|
};
|
|
_DefaultTitleStrategy.ɵfac = function DefaultTitleStrategy_Factory(t) {
|
|
return new (t || _DefaultTitleStrategy)(ɵɵinject(Title));
|
|
};
|
|
_DefaultTitleStrategy.ɵprov = ɵɵdefineInjectable({
|
|
token: _DefaultTitleStrategy,
|
|
factory: _DefaultTitleStrategy.ɵfac,
|
|
providedIn: "root"
|
|
});
|
|
var DefaultTitleStrategy = _DefaultTitleStrategy;
|
|
(() => {
|
|
(typeof ngDevMode === "undefined" || ngDevMode) && setClassMetadata(DefaultTitleStrategy, [{
|
|
type: Injectable,
|
|
args: [{
|
|
providedIn: "root"
|
|
}]
|
|
}], () => [{
|
|
type: Title
|
|
}], null);
|
|
})();
|
|
var ROUTER_CONFIGURATION = new InjectionToken(typeof ngDevMode === "undefined" || ngDevMode ? "router config" : "", {
|
|
providedIn: "root",
|
|
factory: () => ({})
|
|
});
|
|
var ROUTES = new InjectionToken("ROUTES");
|
|
var _RouterConfigLoader = class _RouterConfigLoader {
|
|
constructor() {
|
|
this.componentLoaders = /* @__PURE__ */ new WeakMap();
|
|
this.childrenLoaders = /* @__PURE__ */ new WeakMap();
|
|
this.compiler = inject(Compiler);
|
|
}
|
|
loadComponent(route) {
|
|
if (this.componentLoaders.get(route)) {
|
|
return this.componentLoaders.get(route);
|
|
} else if (route._loadedComponent) {
|
|
return of(route._loadedComponent);
|
|
}
|
|
if (this.onLoadStartListener) {
|
|
this.onLoadStartListener(route);
|
|
}
|
|
const loadRunner = wrapIntoObservable(route.loadComponent()).pipe(map(maybeUnwrapDefaultExport), tap((component) => {
|
|
if (this.onLoadEndListener) {
|
|
this.onLoadEndListener(route);
|
|
}
|
|
(typeof ngDevMode === "undefined" || ngDevMode) && assertStandalone(route.path ?? "", component);
|
|
route._loadedComponent = component;
|
|
}), finalize(() => {
|
|
this.componentLoaders.delete(route);
|
|
}));
|
|
const loader = new ConnectableObservable(loadRunner, () => new Subject()).pipe(refCount());
|
|
this.componentLoaders.set(route, loader);
|
|
return loader;
|
|
}
|
|
loadChildren(parentInjector, route) {
|
|
if (this.childrenLoaders.get(route)) {
|
|
return this.childrenLoaders.get(route);
|
|
} else if (route._loadedRoutes) {
|
|
return of({
|
|
routes: route._loadedRoutes,
|
|
injector: route._loadedInjector
|
|
});
|
|
}
|
|
if (this.onLoadStartListener) {
|
|
this.onLoadStartListener(route);
|
|
}
|
|
const moduleFactoryOrRoutes$ = loadChildren(route, this.compiler, parentInjector, this.onLoadEndListener);
|
|
const loadRunner = moduleFactoryOrRoutes$.pipe(finalize(() => {
|
|
this.childrenLoaders.delete(route);
|
|
}));
|
|
const loader = new ConnectableObservable(loadRunner, () => new Subject()).pipe(refCount());
|
|
this.childrenLoaders.set(route, loader);
|
|
return loader;
|
|
}
|
|
};
|
|
_RouterConfigLoader.ɵfac = function RouterConfigLoader_Factory(t) {
|
|
return new (t || _RouterConfigLoader)();
|
|
};
|
|
_RouterConfigLoader.ɵprov = ɵɵdefineInjectable({
|
|
token: _RouterConfigLoader,
|
|
factory: _RouterConfigLoader.ɵfac,
|
|
providedIn: "root"
|
|
});
|
|
var RouterConfigLoader = _RouterConfigLoader;
|
|
(() => {
|
|
(typeof ngDevMode === "undefined" || ngDevMode) && setClassMetadata(RouterConfigLoader, [{
|
|
type: Injectable,
|
|
args: [{
|
|
providedIn: "root"
|
|
}]
|
|
}], null, null);
|
|
})();
|
|
function loadChildren(route, compiler, parentInjector, onLoadEndListener) {
|
|
return wrapIntoObservable(route.loadChildren()).pipe(map(maybeUnwrapDefaultExport), mergeMap((t) => {
|
|
if (t instanceof NgModuleFactory$1 || Array.isArray(t)) {
|
|
return of(t);
|
|
} else {
|
|
return from(compiler.compileModuleAsync(t));
|
|
}
|
|
}), map((factoryOrRoutes) => {
|
|
if (onLoadEndListener) {
|
|
onLoadEndListener(route);
|
|
}
|
|
let injector;
|
|
let rawRoutes;
|
|
let requireStandaloneComponents = false;
|
|
if (Array.isArray(factoryOrRoutes)) {
|
|
rawRoutes = factoryOrRoutes;
|
|
requireStandaloneComponents = true;
|
|
} else {
|
|
injector = factoryOrRoutes.create(parentInjector).injector;
|
|
rawRoutes = injector.get(ROUTES, [], {
|
|
optional: true,
|
|
self: true
|
|
}).flat();
|
|
}
|
|
const routes = rawRoutes.map(standardizeConfig);
|
|
(typeof ngDevMode === "undefined" || ngDevMode) && validateConfig(routes, route.path, requireStandaloneComponents);
|
|
return {
|
|
routes,
|
|
injector
|
|
};
|
|
}));
|
|
}
|
|
function isWrappedDefaultExport(value) {
|
|
return value && typeof value === "object" && "default" in value;
|
|
}
|
|
function maybeUnwrapDefaultExport(input) {
|
|
return isWrappedDefaultExport(input) ? input["default"] : input;
|
|
}
|
|
var _UrlHandlingStrategy = class _UrlHandlingStrategy {
|
|
};
|
|
_UrlHandlingStrategy.ɵfac = function UrlHandlingStrategy_Factory(t) {
|
|
return new (t || _UrlHandlingStrategy)();
|
|
};
|
|
_UrlHandlingStrategy.ɵprov = ɵɵdefineInjectable({
|
|
token: _UrlHandlingStrategy,
|
|
factory: () => (() => inject(DefaultUrlHandlingStrategy))(),
|
|
providedIn: "root"
|
|
});
|
|
var UrlHandlingStrategy = _UrlHandlingStrategy;
|
|
(() => {
|
|
(typeof ngDevMode === "undefined" || ngDevMode) && setClassMetadata(UrlHandlingStrategy, [{
|
|
type: Injectable,
|
|
args: [{
|
|
providedIn: "root",
|
|
useFactory: () => inject(DefaultUrlHandlingStrategy)
|
|
}]
|
|
}], null, null);
|
|
})();
|
|
var _DefaultUrlHandlingStrategy = class _DefaultUrlHandlingStrategy {
|
|
shouldProcessUrl(url) {
|
|
return true;
|
|
}
|
|
extract(url) {
|
|
return url;
|
|
}
|
|
merge(newUrlPart, wholeUrl) {
|
|
return newUrlPart;
|
|
}
|
|
};
|
|
_DefaultUrlHandlingStrategy.ɵfac = function DefaultUrlHandlingStrategy_Factory(t) {
|
|
return new (t || _DefaultUrlHandlingStrategy)();
|
|
};
|
|
_DefaultUrlHandlingStrategy.ɵprov = ɵɵdefineInjectable({
|
|
token: _DefaultUrlHandlingStrategy,
|
|
factory: _DefaultUrlHandlingStrategy.ɵfac,
|
|
providedIn: "root"
|
|
});
|
|
var DefaultUrlHandlingStrategy = _DefaultUrlHandlingStrategy;
|
|
(() => {
|
|
(typeof ngDevMode === "undefined" || ngDevMode) && setClassMetadata(DefaultUrlHandlingStrategy, [{
|
|
type: Injectable,
|
|
args: [{
|
|
providedIn: "root"
|
|
}]
|
|
}], null, null);
|
|
})();
|
|
var CREATE_VIEW_TRANSITION = new InjectionToken(ngDevMode ? "view transition helper" : "");
|
|
var VIEW_TRANSITION_OPTIONS = new InjectionToken(ngDevMode ? "view transition options" : "");
|
|
function createViewTransition(injector, from2, to) {
|
|
const transitionOptions = injector.get(VIEW_TRANSITION_OPTIONS);
|
|
const document = injector.get(DOCUMENT);
|
|
return injector.get(NgZone).runOutsideAngular(() => {
|
|
if (!document.startViewTransition || transitionOptions.skipNextTransition) {
|
|
transitionOptions.skipNextTransition = false;
|
|
return Promise.resolve();
|
|
}
|
|
let resolveViewTransitionStarted;
|
|
const viewTransitionStarted = new Promise((resolve) => {
|
|
resolveViewTransitionStarted = resolve;
|
|
});
|
|
const transition = document.startViewTransition(() => {
|
|
resolveViewTransitionStarted();
|
|
return createRenderPromise(injector);
|
|
});
|
|
const {
|
|
onViewTransitionCreated
|
|
} = transitionOptions;
|
|
if (onViewTransitionCreated) {
|
|
runInInjectionContext(injector, () => onViewTransitionCreated({
|
|
transition,
|
|
from: from2,
|
|
to
|
|
}));
|
|
}
|
|
return viewTransitionStarted;
|
|
});
|
|
}
|
|
function createRenderPromise(injector) {
|
|
return new Promise((resolve) => {
|
|
afterNextRender(resolve, {
|
|
injector
|
|
});
|
|
});
|
|
}
|
|
var _NavigationTransitions = class _NavigationTransitions {
|
|
get hasRequestedNavigation() {
|
|
return this.navigationId !== 0;
|
|
}
|
|
constructor() {
|
|
this.currentNavigation = null;
|
|
this.currentTransition = null;
|
|
this.lastSuccessfulNavigation = null;
|
|
this.events = new Subject();
|
|
this.transitionAbortSubject = new Subject();
|
|
this.configLoader = inject(RouterConfigLoader);
|
|
this.environmentInjector = inject(EnvironmentInjector);
|
|
this.urlSerializer = inject(UrlSerializer);
|
|
this.rootContexts = inject(ChildrenOutletContexts);
|
|
this.location = inject(Location);
|
|
this.inputBindingEnabled = inject(INPUT_BINDER, {
|
|
optional: true
|
|
}) !== null;
|
|
this.titleStrategy = inject(TitleStrategy);
|
|
this.options = inject(ROUTER_CONFIGURATION, {
|
|
optional: true
|
|
}) || {};
|
|
this.paramsInheritanceStrategy = this.options.paramsInheritanceStrategy || "emptyOnly";
|
|
this.urlHandlingStrategy = inject(UrlHandlingStrategy);
|
|
this.createViewTransition = inject(CREATE_VIEW_TRANSITION, {
|
|
optional: true
|
|
});
|
|
this.navigationId = 0;
|
|
this.afterPreactivation = () => of(void 0);
|
|
this.rootComponentType = null;
|
|
const onLoadStart = (r) => this.events.next(new RouteConfigLoadStart(r));
|
|
const onLoadEnd = (r) => this.events.next(new RouteConfigLoadEnd(r));
|
|
this.configLoader.onLoadEndListener = onLoadEnd;
|
|
this.configLoader.onLoadStartListener = onLoadStart;
|
|
}
|
|
complete() {
|
|
this.transitions?.complete();
|
|
}
|
|
handleNavigationRequest(request) {
|
|
const id = ++this.navigationId;
|
|
this.transitions?.next(__spreadProps(__spreadValues(__spreadValues({}, this.transitions.value), request), {
|
|
id
|
|
}));
|
|
}
|
|
setupNavigations(router, initialUrlTree, initialRouterState) {
|
|
this.transitions = new BehaviorSubject({
|
|
id: 0,
|
|
currentUrlTree: initialUrlTree,
|
|
currentRawUrl: initialUrlTree,
|
|
extractedUrl: this.urlHandlingStrategy.extract(initialUrlTree),
|
|
urlAfterRedirects: this.urlHandlingStrategy.extract(initialUrlTree),
|
|
rawUrl: initialUrlTree,
|
|
extras: {},
|
|
resolve: null,
|
|
reject: null,
|
|
promise: Promise.resolve(true),
|
|
source: IMPERATIVE_NAVIGATION,
|
|
restoredState: null,
|
|
currentSnapshot: initialRouterState.snapshot,
|
|
targetSnapshot: null,
|
|
currentRouterState: initialRouterState,
|
|
targetRouterState: null,
|
|
guards: {
|
|
canActivateChecks: [],
|
|
canDeactivateChecks: []
|
|
},
|
|
guardsResult: null
|
|
});
|
|
return this.transitions.pipe(
|
|
filter((t) => t.id !== 0),
|
|
// Extract URL
|
|
map((t) => __spreadProps(__spreadValues({}, t), {
|
|
extractedUrl: this.urlHandlingStrategy.extract(t.rawUrl)
|
|
})),
|
|
// Using switchMap so we cancel executing navigations when a new one comes in
|
|
switchMap((overallTransitionState) => {
|
|
this.currentTransition = overallTransitionState;
|
|
let completed = false;
|
|
let errored = false;
|
|
return of(overallTransitionState).pipe(
|
|
// Store the Navigation object
|
|
tap((t) => {
|
|
this.currentNavigation = {
|
|
id: t.id,
|
|
initialUrl: t.rawUrl,
|
|
extractedUrl: t.extractedUrl,
|
|
trigger: t.source,
|
|
extras: t.extras,
|
|
previousNavigation: !this.lastSuccessfulNavigation ? null : __spreadProps(__spreadValues({}, this.lastSuccessfulNavigation), {
|
|
previousNavigation: null
|
|
})
|
|
};
|
|
}),
|
|
switchMap((t) => {
|
|
const urlTransition = !router.navigated || this.isUpdatingInternalState() || this.isUpdatedBrowserUrl();
|
|
const onSameUrlNavigation = t.extras.onSameUrlNavigation ?? router.onSameUrlNavigation;
|
|
if (!urlTransition && onSameUrlNavigation !== "reload") {
|
|
const reason = typeof ngDevMode === "undefined" || ngDevMode ? `Navigation to ${t.rawUrl} was ignored because it is the same as the current Router URL.` : "";
|
|
this.events.next(new NavigationSkipped(
|
|
t.id,
|
|
this.urlSerializer.serialize(t.rawUrl),
|
|
reason,
|
|
0
|
|
/* NavigationSkippedCode.IgnoredSameUrlNavigation */
|
|
));
|
|
t.resolve(null);
|
|
return EMPTY;
|
|
}
|
|
if (this.urlHandlingStrategy.shouldProcessUrl(t.rawUrl)) {
|
|
return of(t).pipe(
|
|
// Fire NavigationStart event
|
|
switchMap((t2) => {
|
|
const transition = this.transitions?.getValue();
|
|
this.events.next(new NavigationStart(t2.id, this.urlSerializer.serialize(t2.extractedUrl), t2.source, t2.restoredState));
|
|
if (transition !== this.transitions?.getValue()) {
|
|
return EMPTY;
|
|
}
|
|
return Promise.resolve(t2);
|
|
}),
|
|
// Recognize
|
|
recognize(this.environmentInjector, this.configLoader, this.rootComponentType, router.config, this.urlSerializer, this.paramsInheritanceStrategy),
|
|
// Update URL if in `eager` update mode
|
|
tap((t2) => {
|
|
overallTransitionState.targetSnapshot = t2.targetSnapshot;
|
|
overallTransitionState.urlAfterRedirects = t2.urlAfterRedirects;
|
|
this.currentNavigation = __spreadProps(__spreadValues({}, this.currentNavigation), {
|
|
finalUrl: t2.urlAfterRedirects
|
|
});
|
|
const routesRecognized = new RoutesRecognized(t2.id, this.urlSerializer.serialize(t2.extractedUrl), this.urlSerializer.serialize(t2.urlAfterRedirects), t2.targetSnapshot);
|
|
this.events.next(routesRecognized);
|
|
})
|
|
);
|
|
} else if (urlTransition && this.urlHandlingStrategy.shouldProcessUrl(t.currentRawUrl)) {
|
|
const {
|
|
id,
|
|
extractedUrl,
|
|
source,
|
|
restoredState,
|
|
extras
|
|
} = t;
|
|
const navStart = new NavigationStart(id, this.urlSerializer.serialize(extractedUrl), source, restoredState);
|
|
this.events.next(navStart);
|
|
const targetSnapshot = createEmptyState(extractedUrl, this.rootComponentType).snapshot;
|
|
this.currentTransition = overallTransitionState = __spreadProps(__spreadValues({}, t), {
|
|
targetSnapshot,
|
|
urlAfterRedirects: extractedUrl,
|
|
extras: __spreadProps(__spreadValues({}, extras), {
|
|
skipLocationChange: false,
|
|
replaceUrl: false
|
|
})
|
|
});
|
|
this.currentNavigation.finalUrl = extractedUrl;
|
|
return of(overallTransitionState);
|
|
} else {
|
|
const reason = typeof ngDevMode === "undefined" || ngDevMode ? `Navigation was ignored because the UrlHandlingStrategy indicated neither the current URL ${t.currentRawUrl} nor target URL ${t.rawUrl} should be processed.` : "";
|
|
this.events.next(new NavigationSkipped(
|
|
t.id,
|
|
this.urlSerializer.serialize(t.extractedUrl),
|
|
reason,
|
|
1
|
|
/* NavigationSkippedCode.IgnoredByUrlHandlingStrategy */
|
|
));
|
|
t.resolve(null);
|
|
return EMPTY;
|
|
}
|
|
}),
|
|
// --- GUARDS ---
|
|
tap((t) => {
|
|
const guardsStart = new GuardsCheckStart(t.id, this.urlSerializer.serialize(t.extractedUrl), this.urlSerializer.serialize(t.urlAfterRedirects), t.targetSnapshot);
|
|
this.events.next(guardsStart);
|
|
}),
|
|
map((t) => {
|
|
this.currentTransition = overallTransitionState = __spreadProps(__spreadValues({}, t), {
|
|
guards: getAllRouteGuards(t.targetSnapshot, t.currentSnapshot, this.rootContexts)
|
|
});
|
|
return overallTransitionState;
|
|
}),
|
|
checkGuards(this.environmentInjector, (evt) => this.events.next(evt)),
|
|
tap((t) => {
|
|
overallTransitionState.guardsResult = t.guardsResult;
|
|
if (isUrlTree(t.guardsResult)) {
|
|
throw redirectingNavigationError(this.urlSerializer, t.guardsResult);
|
|
}
|
|
const guardsEnd = new GuardsCheckEnd(t.id, this.urlSerializer.serialize(t.extractedUrl), this.urlSerializer.serialize(t.urlAfterRedirects), t.targetSnapshot, !!t.guardsResult);
|
|
this.events.next(guardsEnd);
|
|
}),
|
|
filter((t) => {
|
|
if (!t.guardsResult) {
|
|
this.cancelNavigationTransition(
|
|
t,
|
|
"",
|
|
3
|
|
/* NavigationCancellationCode.GuardRejected */
|
|
);
|
|
return false;
|
|
}
|
|
return true;
|
|
}),
|
|
// --- RESOLVE ---
|
|
switchTap((t) => {
|
|
if (t.guards.canActivateChecks.length) {
|
|
return of(t).pipe(tap((t2) => {
|
|
const resolveStart = new ResolveStart(t2.id, this.urlSerializer.serialize(t2.extractedUrl), this.urlSerializer.serialize(t2.urlAfterRedirects), t2.targetSnapshot);
|
|
this.events.next(resolveStart);
|
|
}), switchMap((t2) => {
|
|
let dataResolved = false;
|
|
return of(t2).pipe(resolveData(this.paramsInheritanceStrategy, this.environmentInjector), tap({
|
|
next: () => dataResolved = true,
|
|
complete: () => {
|
|
if (!dataResolved) {
|
|
this.cancelNavigationTransition(
|
|
t2,
|
|
typeof ngDevMode === "undefined" || ngDevMode ? `At least one route resolver didn't emit any value.` : "",
|
|
2
|
|
/* NavigationCancellationCode.NoDataFromResolver */
|
|
);
|
|
}
|
|
}
|
|
}));
|
|
}), tap((t2) => {
|
|
const resolveEnd = new ResolveEnd(t2.id, this.urlSerializer.serialize(t2.extractedUrl), this.urlSerializer.serialize(t2.urlAfterRedirects), t2.targetSnapshot);
|
|
this.events.next(resolveEnd);
|
|
}));
|
|
}
|
|
return void 0;
|
|
}),
|
|
// --- LOAD COMPONENTS ---
|
|
switchTap((t) => {
|
|
const loadComponents = (route) => {
|
|
const loaders = [];
|
|
if (route.routeConfig?.loadComponent && !route.routeConfig._loadedComponent) {
|
|
loaders.push(this.configLoader.loadComponent(route.routeConfig).pipe(tap((loadedComponent) => {
|
|
route.component = loadedComponent;
|
|
}), map(() => void 0)));
|
|
}
|
|
for (const child of route.children) {
|
|
loaders.push(...loadComponents(child));
|
|
}
|
|
return loaders;
|
|
};
|
|
return combineLatest(loadComponents(t.targetSnapshot.root)).pipe(defaultIfEmpty(), take(1));
|
|
}),
|
|
switchTap(() => this.afterPreactivation()),
|
|
switchMap(() => {
|
|
const {
|
|
currentSnapshot,
|
|
targetSnapshot
|
|
} = overallTransitionState;
|
|
const viewTransitionStarted = this.createViewTransition?.(this.environmentInjector, currentSnapshot.root, targetSnapshot.root);
|
|
return viewTransitionStarted ? from(viewTransitionStarted).pipe(map(() => overallTransitionState)) : of(overallTransitionState);
|
|
}),
|
|
map((t) => {
|
|
const targetRouterState = createRouterState(router.routeReuseStrategy, t.targetSnapshot, t.currentRouterState);
|
|
this.currentTransition = overallTransitionState = __spreadProps(__spreadValues({}, t), {
|
|
targetRouterState
|
|
});
|
|
this.currentNavigation.targetRouterState = targetRouterState;
|
|
return overallTransitionState;
|
|
}),
|
|
tap(() => {
|
|
this.events.next(new BeforeActivateRoutes());
|
|
}),
|
|
activateRoutes(this.rootContexts, router.routeReuseStrategy, (evt) => this.events.next(evt), this.inputBindingEnabled),
|
|
// Ensure that if some observable used to drive the transition doesn't
|
|
// complete, the navigation still finalizes This should never happen, but
|
|
// this is done as a safety measure to avoid surfacing this error (#49567).
|
|
take(1),
|
|
tap({
|
|
next: (t) => {
|
|
completed = true;
|
|
this.lastSuccessfulNavigation = this.currentNavigation;
|
|
this.events.next(new NavigationEnd(t.id, this.urlSerializer.serialize(t.extractedUrl), this.urlSerializer.serialize(t.urlAfterRedirects)));
|
|
this.titleStrategy?.updateTitle(t.targetRouterState.snapshot);
|
|
t.resolve(true);
|
|
},
|
|
complete: () => {
|
|
completed = true;
|
|
}
|
|
}),
|
|
// There used to be a lot more logic happening directly within the
|
|
// transition Observable. Some of this logic has been refactored out to
|
|
// other places but there may still be errors that happen there. This gives
|
|
// us a way to cancel the transition from the outside. This may also be
|
|
// required in the future to support something like the abort signal of the
|
|
// Navigation API where the navigation gets aborted from outside the
|
|
// transition.
|
|
takeUntil(this.transitionAbortSubject.pipe(tap((err) => {
|
|
throw err;
|
|
}))),
|
|
finalize(() => {
|
|
if (!completed && !errored) {
|
|
const cancelationReason = typeof ngDevMode === "undefined" || ngDevMode ? `Navigation ID ${overallTransitionState.id} is not equal to the current navigation id ${this.navigationId}` : "";
|
|
this.cancelNavigationTransition(
|
|
overallTransitionState,
|
|
cancelationReason,
|
|
1
|
|
/* NavigationCancellationCode.SupersededByNewNavigation */
|
|
);
|
|
}
|
|
if (this.currentNavigation?.id === overallTransitionState.id) {
|
|
this.currentNavigation = null;
|
|
}
|
|
}),
|
|
catchError((e) => {
|
|
errored = true;
|
|
if (isNavigationCancelingError$1(e)) {
|
|
this.events.next(new NavigationCancel(overallTransitionState.id, this.urlSerializer.serialize(overallTransitionState.extractedUrl), e.message, e.cancellationCode));
|
|
if (!isRedirectingNavigationCancelingError$1(e)) {
|
|
overallTransitionState.resolve(false);
|
|
} else {
|
|
this.events.next(new RedirectRequest(e.url));
|
|
}
|
|
} else {
|
|
this.events.next(new NavigationError(overallTransitionState.id, this.urlSerializer.serialize(overallTransitionState.extractedUrl), e, overallTransitionState.targetSnapshot ?? void 0));
|
|
try {
|
|
overallTransitionState.resolve(router.errorHandler(e));
|
|
} catch (ee) {
|
|
overallTransitionState.reject(ee);
|
|
}
|
|
}
|
|
return EMPTY;
|
|
})
|
|
);
|
|
})
|
|
);
|
|
}
|
|
cancelNavigationTransition(t, reason, code) {
|
|
const navCancel = new NavigationCancel(t.id, this.urlSerializer.serialize(t.extractedUrl), reason, code);
|
|
this.events.next(navCancel);
|
|
t.resolve(false);
|
|
}
|
|
/**
|
|
* @returns Whether we're navigating to somewhere that is not what the Router is
|
|
* currently set to.
|
|
*/
|
|
isUpdatingInternalState() {
|
|
return this.currentTransition?.extractedUrl.toString() !== this.currentTransition?.currentUrlTree.toString();
|
|
}
|
|
/**
|
|
* @returns Whether we're updating the browser URL to something new (navigation is going
|
|
* to somewhere not displayed in the URL bar and we will update the URL
|
|
* bar if navigation succeeds).
|
|
*/
|
|
isUpdatedBrowserUrl() {
|
|
const extractedBrowserUrl = this.urlHandlingStrategy.extract(this.urlSerializer.parse(this.location.path(true)));
|
|
return extractedBrowserUrl.toString() !== this.currentTransition?.extractedUrl.toString() && !this.currentTransition?.extras.skipLocationChange;
|
|
}
|
|
};
|
|
_NavigationTransitions.ɵfac = function NavigationTransitions_Factory(t) {
|
|
return new (t || _NavigationTransitions)();
|
|
};
|
|
_NavigationTransitions.ɵprov = ɵɵdefineInjectable({
|
|
token: _NavigationTransitions,
|
|
factory: _NavigationTransitions.ɵfac,
|
|
providedIn: "root"
|
|
});
|
|
var NavigationTransitions = _NavigationTransitions;
|
|
(() => {
|
|
(typeof ngDevMode === "undefined" || ngDevMode) && setClassMetadata(NavigationTransitions, [{
|
|
type: Injectable,
|
|
args: [{
|
|
providedIn: "root"
|
|
}]
|
|
}], () => [], null);
|
|
})();
|
|
function isBrowserTriggeredNavigation(source) {
|
|
return source !== IMPERATIVE_NAVIGATION;
|
|
}
|
|
var _RouteReuseStrategy = class _RouteReuseStrategy {
|
|
};
|
|
_RouteReuseStrategy.ɵfac = function RouteReuseStrategy_Factory(t) {
|
|
return new (t || _RouteReuseStrategy)();
|
|
};
|
|
_RouteReuseStrategy.ɵprov = ɵɵdefineInjectable({
|
|
token: _RouteReuseStrategy,
|
|
factory: () => (() => inject(DefaultRouteReuseStrategy))(),
|
|
providedIn: "root"
|
|
});
|
|
var RouteReuseStrategy = _RouteReuseStrategy;
|
|
(() => {
|
|
(typeof ngDevMode === "undefined" || ngDevMode) && setClassMetadata(RouteReuseStrategy, [{
|
|
type: Injectable,
|
|
args: [{
|
|
providedIn: "root",
|
|
useFactory: () => inject(DefaultRouteReuseStrategy)
|
|
}]
|
|
}], null, null);
|
|
})();
|
|
var BaseRouteReuseStrategy = class {
|
|
/**
|
|
* Whether the given route should detach for later reuse.
|
|
* Always returns false for `BaseRouteReuseStrategy`.
|
|
* */
|
|
shouldDetach(route) {
|
|
return false;
|
|
}
|
|
/**
|
|
* A no-op; the route is never stored since this strategy never detaches routes for later re-use.
|
|
*/
|
|
store(route, detachedTree) {
|
|
}
|
|
/** Returns `false`, meaning the route (and its subtree) is never reattached */
|
|
shouldAttach(route) {
|
|
return false;
|
|
}
|
|
/** Returns `null` because this strategy does not store routes for later re-use. */
|
|
retrieve(route) {
|
|
return null;
|
|
}
|
|
/**
|
|
* Determines if a route should be reused.
|
|
* This strategy returns `true` when the future route config and current route config are
|
|
* identical.
|
|
*/
|
|
shouldReuseRoute(future, curr) {
|
|
return future.routeConfig === curr.routeConfig;
|
|
}
|
|
};
|
|
var _DefaultRouteReuseStrategy = class _DefaultRouteReuseStrategy extends BaseRouteReuseStrategy {
|
|
};
|
|
_DefaultRouteReuseStrategy.ɵfac = (() => {
|
|
let ɵDefaultRouteReuseStrategy_BaseFactory;
|
|
return function DefaultRouteReuseStrategy_Factory(t) {
|
|
return (ɵDefaultRouteReuseStrategy_BaseFactory || (ɵDefaultRouteReuseStrategy_BaseFactory = ɵɵgetInheritedFactory(_DefaultRouteReuseStrategy)))(t || _DefaultRouteReuseStrategy);
|
|
};
|
|
})();
|
|
_DefaultRouteReuseStrategy.ɵprov = ɵɵdefineInjectable({
|
|
token: _DefaultRouteReuseStrategy,
|
|
factory: _DefaultRouteReuseStrategy.ɵfac,
|
|
providedIn: "root"
|
|
});
|
|
var DefaultRouteReuseStrategy = _DefaultRouteReuseStrategy;
|
|
(() => {
|
|
(typeof ngDevMode === "undefined" || ngDevMode) && setClassMetadata(DefaultRouteReuseStrategy, [{
|
|
type: Injectable,
|
|
args: [{
|
|
providedIn: "root"
|
|
}]
|
|
}], null, null);
|
|
})();
|
|
var _StateManager = class _StateManager {
|
|
};
|
|
_StateManager.ɵfac = function StateManager_Factory(t) {
|
|
return new (t || _StateManager)();
|
|
};
|
|
_StateManager.ɵprov = ɵɵdefineInjectable({
|
|
token: _StateManager,
|
|
factory: () => (() => inject(HistoryStateManager))(),
|
|
providedIn: "root"
|
|
});
|
|
var StateManager = _StateManager;
|
|
(() => {
|
|
(typeof ngDevMode === "undefined" || ngDevMode) && setClassMetadata(StateManager, [{
|
|
type: Injectable,
|
|
args: [{
|
|
providedIn: "root",
|
|
useFactory: () => inject(HistoryStateManager)
|
|
}]
|
|
}], null, null);
|
|
})();
|
|
var _HistoryStateManager = class _HistoryStateManager extends StateManager {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.location = inject(Location);
|
|
this.urlSerializer = inject(UrlSerializer);
|
|
this.options = inject(ROUTER_CONFIGURATION, {
|
|
optional: true
|
|
}) || {};
|
|
this.canceledNavigationResolution = this.options.canceledNavigationResolution || "replace";
|
|
this.urlHandlingStrategy = inject(UrlHandlingStrategy);
|
|
this.urlUpdateStrategy = this.options.urlUpdateStrategy || "deferred";
|
|
this.currentUrlTree = new UrlTree();
|
|
this.rawUrlTree = this.currentUrlTree;
|
|
this.currentPageId = 0;
|
|
this.lastSuccessfulId = -1;
|
|
this.routerState = createEmptyState(this.currentUrlTree, null);
|
|
this.stateMemento = this.createStateMemento();
|
|
}
|
|
getCurrentUrlTree() {
|
|
return this.currentUrlTree;
|
|
}
|
|
getRawUrlTree() {
|
|
return this.rawUrlTree;
|
|
}
|
|
restoredState() {
|
|
return this.location.getState();
|
|
}
|
|
/**
|
|
* The ɵrouterPageId of whatever page is currently active in the browser history. This is
|
|
* important for computing the target page id for new navigations because we need to ensure each
|
|
* page id in the browser history is 1 more than the previous entry.
|
|
*/
|
|
get browserPageId() {
|
|
if (this.canceledNavigationResolution !== "computed") {
|
|
return this.currentPageId;
|
|
}
|
|
return this.restoredState()?.ɵrouterPageId ?? this.currentPageId;
|
|
}
|
|
getRouterState() {
|
|
return this.routerState;
|
|
}
|
|
createStateMemento() {
|
|
return {
|
|
rawUrlTree: this.rawUrlTree,
|
|
currentUrlTree: this.currentUrlTree,
|
|
routerState: this.routerState
|
|
};
|
|
}
|
|
registerNonRouterCurrentEntryChangeListener(listener) {
|
|
return this.location.subscribe((event) => {
|
|
if (event["type"] === "popstate") {
|
|
listener(event["url"], event.state);
|
|
}
|
|
});
|
|
}
|
|
handleRouterEvent(e, currentTransition) {
|
|
if (e instanceof NavigationStart) {
|
|
this.stateMemento = this.createStateMemento();
|
|
} else if (e instanceof NavigationSkipped) {
|
|
this.rawUrlTree = currentTransition.initialUrl;
|
|
} else if (e instanceof RoutesRecognized) {
|
|
if (this.urlUpdateStrategy === "eager") {
|
|
if (!currentTransition.extras.skipLocationChange) {
|
|
const rawUrl = this.urlHandlingStrategy.merge(currentTransition.finalUrl, currentTransition.initialUrl);
|
|
this.setBrowserUrl(rawUrl, currentTransition);
|
|
}
|
|
}
|
|
} else if (e instanceof BeforeActivateRoutes) {
|
|
this.currentUrlTree = currentTransition.finalUrl;
|
|
this.rawUrlTree = this.urlHandlingStrategy.merge(currentTransition.finalUrl, currentTransition.initialUrl);
|
|
this.routerState = currentTransition.targetRouterState;
|
|
if (this.urlUpdateStrategy === "deferred") {
|
|
if (!currentTransition.extras.skipLocationChange) {
|
|
this.setBrowserUrl(this.rawUrlTree, currentTransition);
|
|
}
|
|
}
|
|
} else if (e instanceof NavigationCancel && (e.code === 3 || e.code === 2)) {
|
|
this.restoreHistory(currentTransition);
|
|
} else if (e instanceof NavigationError) {
|
|
this.restoreHistory(currentTransition, true);
|
|
} else if (e instanceof NavigationEnd) {
|
|
this.lastSuccessfulId = e.id;
|
|
this.currentPageId = this.browserPageId;
|
|
}
|
|
}
|
|
setBrowserUrl(url, transition) {
|
|
const path = this.urlSerializer.serialize(url);
|
|
if (this.location.isCurrentPathEqualTo(path) || !!transition.extras.replaceUrl) {
|
|
const currentBrowserPageId = this.browserPageId;
|
|
const state = __spreadValues(__spreadValues({}, transition.extras.state), this.generateNgRouterState(transition.id, currentBrowserPageId));
|
|
this.location.replaceState(path, "", state);
|
|
} else {
|
|
const state = __spreadValues(__spreadValues({}, transition.extras.state), this.generateNgRouterState(transition.id, this.browserPageId + 1));
|
|
this.location.go(path, "", state);
|
|
}
|
|
}
|
|
/**
|
|
* Performs the necessary rollback action to restore the browser URL to the
|
|
* state before the transition.
|
|
*/
|
|
restoreHistory(navigation, restoringFromCaughtError = false) {
|
|
if (this.canceledNavigationResolution === "computed") {
|
|
const currentBrowserPageId = this.browserPageId;
|
|
const targetPagePosition = this.currentPageId - currentBrowserPageId;
|
|
if (targetPagePosition !== 0) {
|
|
this.location.historyGo(targetPagePosition);
|
|
} else if (this.currentUrlTree === navigation.finalUrl && targetPagePosition === 0) {
|
|
this.resetState(navigation);
|
|
this.resetUrlToCurrentUrlTree();
|
|
} else {
|
|
}
|
|
} else if (this.canceledNavigationResolution === "replace") {
|
|
if (restoringFromCaughtError) {
|
|
this.resetState(navigation);
|
|
}
|
|
this.resetUrlToCurrentUrlTree();
|
|
}
|
|
}
|
|
resetState(navigation) {
|
|
this.routerState = this.stateMemento.routerState;
|
|
this.currentUrlTree = this.stateMemento.currentUrlTree;
|
|
this.rawUrlTree = this.urlHandlingStrategy.merge(this.currentUrlTree, navigation.finalUrl ?? this.rawUrlTree);
|
|
}
|
|
resetUrlToCurrentUrlTree() {
|
|
this.location.replaceState(this.urlSerializer.serialize(this.rawUrlTree), "", this.generateNgRouterState(this.lastSuccessfulId, this.currentPageId));
|
|
}
|
|
generateNgRouterState(navigationId, routerPageId) {
|
|
if (this.canceledNavigationResolution === "computed") {
|
|
return {
|
|
navigationId,
|
|
ɵrouterPageId: routerPageId
|
|
};
|
|
}
|
|
return {
|
|
navigationId
|
|
};
|
|
}
|
|
};
|
|
_HistoryStateManager.ɵfac = (() => {
|
|
let ɵHistoryStateManager_BaseFactory;
|
|
return function HistoryStateManager_Factory(t) {
|
|
return (ɵHistoryStateManager_BaseFactory || (ɵHistoryStateManager_BaseFactory = ɵɵgetInheritedFactory(_HistoryStateManager)))(t || _HistoryStateManager);
|
|
};
|
|
})();
|
|
_HistoryStateManager.ɵprov = ɵɵdefineInjectable({
|
|
token: _HistoryStateManager,
|
|
factory: _HistoryStateManager.ɵfac,
|
|
providedIn: "root"
|
|
});
|
|
var HistoryStateManager = _HistoryStateManager;
|
|
(() => {
|
|
(typeof ngDevMode === "undefined" || ngDevMode) && setClassMetadata(HistoryStateManager, [{
|
|
type: Injectable,
|
|
args: [{
|
|
providedIn: "root"
|
|
}]
|
|
}], null, null);
|
|
})();
|
|
var NavigationResult;
|
|
(function(NavigationResult2) {
|
|
NavigationResult2[NavigationResult2["COMPLETE"] = 0] = "COMPLETE";
|
|
NavigationResult2[NavigationResult2["FAILED"] = 1] = "FAILED";
|
|
NavigationResult2[NavigationResult2["REDIRECTING"] = 2] = "REDIRECTING";
|
|
})(NavigationResult || (NavigationResult = {}));
|
|
function afterNextNavigation(router, action) {
|
|
router.events.pipe(filter((e) => e instanceof NavigationEnd || e instanceof NavigationCancel || e instanceof NavigationError || e instanceof NavigationSkipped), map((e) => {
|
|
if (e instanceof NavigationEnd || e instanceof NavigationSkipped) {
|
|
return NavigationResult.COMPLETE;
|
|
}
|
|
const redirecting = e instanceof NavigationCancel ? e.code === 0 || e.code === 1 : false;
|
|
return redirecting ? NavigationResult.REDIRECTING : NavigationResult.FAILED;
|
|
}), filter((result) => result !== NavigationResult.REDIRECTING), take(1)).subscribe(() => {
|
|
action();
|
|
});
|
|
}
|
|
function defaultErrorHandler(error) {
|
|
throw error;
|
|
}
|
|
var exactMatchOptions = {
|
|
paths: "exact",
|
|
fragment: "ignored",
|
|
matrixParams: "ignored",
|
|
queryParams: "exact"
|
|
};
|
|
var subsetMatchOptions = {
|
|
paths: "subset",
|
|
fragment: "ignored",
|
|
matrixParams: "ignored",
|
|
queryParams: "subset"
|
|
};
|
|
var _Router = class _Router {
|
|
get currentUrlTree() {
|
|
return this.stateManager.getCurrentUrlTree();
|
|
}
|
|
get rawUrlTree() {
|
|
return this.stateManager.getRawUrlTree();
|
|
}
|
|
/**
|
|
* An event stream for routing events.
|
|
*/
|
|
get events() {
|
|
return this._events;
|
|
}
|
|
/**
|
|
* The current state of routing in this NgModule.
|
|
*/
|
|
get routerState() {
|
|
return this.stateManager.getRouterState();
|
|
}
|
|
constructor() {
|
|
this.disposed = false;
|
|
this.isNgZoneEnabled = false;
|
|
this.console = inject(Console);
|
|
this.stateManager = inject(StateManager);
|
|
this.options = inject(ROUTER_CONFIGURATION, {
|
|
optional: true
|
|
}) || {};
|
|
this.pendingTasks = inject(InitialRenderPendingTasks);
|
|
this.urlUpdateStrategy = this.options.urlUpdateStrategy || "deferred";
|
|
this.navigationTransitions = inject(NavigationTransitions);
|
|
this.urlSerializer = inject(UrlSerializer);
|
|
this.location = inject(Location);
|
|
this.urlHandlingStrategy = inject(UrlHandlingStrategy);
|
|
this._events = new Subject();
|
|
this.errorHandler = this.options.errorHandler || defaultErrorHandler;
|
|
this.navigated = false;
|
|
this.routeReuseStrategy = inject(RouteReuseStrategy);
|
|
this.onSameUrlNavigation = this.options.onSameUrlNavigation || "ignore";
|
|
this.config = inject(ROUTES, {
|
|
optional: true
|
|
})?.flat() ?? [];
|
|
this.componentInputBindingEnabled = !!inject(INPUT_BINDER, {
|
|
optional: true
|
|
});
|
|
this.eventsSubscription = new Subscription();
|
|
this.isNgZoneEnabled = inject(NgZone) instanceof NgZone && NgZone.isInAngularZone();
|
|
this.resetConfig(this.config);
|
|
this.navigationTransitions.setupNavigations(this, this.currentUrlTree, this.routerState).subscribe({
|
|
error: (e) => {
|
|
this.console.warn(ngDevMode ? `Unhandled Navigation Error: ${e}` : e);
|
|
}
|
|
});
|
|
this.subscribeToNavigationEvents();
|
|
}
|
|
subscribeToNavigationEvents() {
|
|
const subscription = this.navigationTransitions.events.subscribe((e) => {
|
|
try {
|
|
const currentTransition = this.navigationTransitions.currentTransition;
|
|
const currentNavigation = this.navigationTransitions.currentNavigation;
|
|
if (currentTransition !== null && currentNavigation !== null) {
|
|
this.stateManager.handleRouterEvent(e, currentNavigation);
|
|
if (e instanceof NavigationCancel && e.code !== 0 && e.code !== 1) {
|
|
this.navigated = true;
|
|
} else if (e instanceof NavigationEnd) {
|
|
this.navigated = true;
|
|
} else if (e instanceof RedirectRequest) {
|
|
const mergedTree = this.urlHandlingStrategy.merge(e.url, currentTransition.currentRawUrl);
|
|
const extras = {
|
|
skipLocationChange: currentTransition.extras.skipLocationChange,
|
|
// The URL is already updated at this point if we have 'eager' URL
|
|
// updates or if the navigation was triggered by the browser (back
|
|
// button, URL bar, etc). We want to replace that item in history
|
|
// if the navigation is rejected.
|
|
replaceUrl: this.urlUpdateStrategy === "eager" || isBrowserTriggeredNavigation(currentTransition.source)
|
|
};
|
|
this.scheduleNavigation(mergedTree, IMPERATIVE_NAVIGATION, null, extras, {
|
|
resolve: currentTransition.resolve,
|
|
reject: currentTransition.reject,
|
|
promise: currentTransition.promise
|
|
});
|
|
}
|
|
}
|
|
if (isPublicRouterEvent(e)) {
|
|
this._events.next(e);
|
|
}
|
|
} catch (e2) {
|
|
this.navigationTransitions.transitionAbortSubject.next(e2);
|
|
}
|
|
});
|
|
this.eventsSubscription.add(subscription);
|
|
}
|
|
/** @internal */
|
|
resetRootComponentType(rootComponentType) {
|
|
this.routerState.root.component = rootComponentType;
|
|
this.navigationTransitions.rootComponentType = rootComponentType;
|
|
}
|
|
/**
|
|
* Sets up the location change listener and performs the initial navigation.
|
|
*/
|
|
initialNavigation() {
|
|
this.setUpLocationChangeListener();
|
|
if (!this.navigationTransitions.hasRequestedNavigation) {
|
|
this.navigateToSyncWithBrowser(this.location.path(true), IMPERATIVE_NAVIGATION, this.stateManager.restoredState());
|
|
}
|
|
}
|
|
/**
|
|
* Sets up the location change listener. This listener detects navigations triggered from outside
|
|
* the Router (the browser back/forward buttons, for example) and schedules a corresponding Router
|
|
* navigation so that the correct events, guards, etc. are triggered.
|
|
*/
|
|
setUpLocationChangeListener() {
|
|
if (!this.nonRouterCurrentEntryChangeSubscription) {
|
|
this.nonRouterCurrentEntryChangeSubscription = this.stateManager.registerNonRouterCurrentEntryChangeListener((url, state) => {
|
|
setTimeout(() => {
|
|
this.navigateToSyncWithBrowser(url, "popstate", state);
|
|
}, 0);
|
|
});
|
|
}
|
|
}
|
|
/**
|
|
* Schedules a router navigation to synchronize Router state with the browser state.
|
|
*
|
|
* This is done as a response to a popstate event and the initial navigation. These
|
|
* two scenarios represent times when the browser URL/state has been updated and
|
|
* the Router needs to respond to ensure its internal state matches.
|
|
*/
|
|
navigateToSyncWithBrowser(url, source, state) {
|
|
const extras = {
|
|
replaceUrl: true
|
|
};
|
|
const restoredState = state?.navigationId ? state : null;
|
|
if (state) {
|
|
const stateCopy = __spreadValues({}, state);
|
|
delete stateCopy.navigationId;
|
|
delete stateCopy.ɵrouterPageId;
|
|
if (Object.keys(stateCopy).length !== 0) {
|
|
extras.state = stateCopy;
|
|
}
|
|
}
|
|
const urlTree = this.parseUrl(url);
|
|
this.scheduleNavigation(urlTree, source, restoredState, extras);
|
|
}
|
|
/** The current URL. */
|
|
get url() {
|
|
return this.serializeUrl(this.currentUrlTree);
|
|
}
|
|
/**
|
|
* Returns the current `Navigation` object when the router is navigating,
|
|
* and `null` when idle.
|
|
*/
|
|
getCurrentNavigation() {
|
|
return this.navigationTransitions.currentNavigation;
|
|
}
|
|
/**
|
|
* The `Navigation` object of the most recent navigation to succeed and `null` if there
|
|
* has not been a successful navigation yet.
|
|
*/
|
|
get lastSuccessfulNavigation() {
|
|
return this.navigationTransitions.lastSuccessfulNavigation;
|
|
}
|
|
/**
|
|
* Resets the route configuration used for navigation and generating links.
|
|
*
|
|
* @param config The route array for the new configuration.
|
|
*
|
|
* @usageNotes
|
|
*
|
|
* ```
|
|
* router.resetConfig([
|
|
* { path: 'team/:id', component: TeamCmp, children: [
|
|
* { path: 'simple', component: SimpleCmp },
|
|
* { path: 'user/:name', component: UserCmp }
|
|
* ]}
|
|
* ]);
|
|
* ```
|
|
*/
|
|
resetConfig(config) {
|
|
(typeof ngDevMode === "undefined" || ngDevMode) && validateConfig(config);
|
|
this.config = config.map(standardizeConfig);
|
|
this.navigated = false;
|
|
}
|
|
/** @nodoc */
|
|
ngOnDestroy() {
|
|
this.dispose();
|
|
}
|
|
/** Disposes of the router. */
|
|
dispose() {
|
|
this.navigationTransitions.complete();
|
|
if (this.nonRouterCurrentEntryChangeSubscription) {
|
|
this.nonRouterCurrentEntryChangeSubscription.unsubscribe();
|
|
this.nonRouterCurrentEntryChangeSubscription = void 0;
|
|
}
|
|
this.disposed = true;
|
|
this.eventsSubscription.unsubscribe();
|
|
}
|
|
/**
|
|
* Appends URL segments to the current URL tree to create a new URL tree.
|
|
*
|
|
* @param commands An array of URL fragments with which to construct the new URL tree.
|
|
* If the path is static, can be the literal URL string. For a dynamic path, pass an array of path
|
|
* segments, followed by the parameters for each segment.
|
|
* The fragments are applied to the current URL tree or the one provided in the `relativeTo`
|
|
* property of the options object, if supplied.
|
|
* @param navigationExtras Options that control the navigation strategy.
|
|
* @returns The new URL tree.
|
|
*
|
|
* @usageNotes
|
|
*
|
|
* ```
|
|
* // create /team/33/user/11
|
|
* router.createUrlTree(['/team', 33, 'user', 11]);
|
|
*
|
|
* // create /team/33;expand=true/user/11
|
|
* router.createUrlTree(['/team', 33, {expand: true}, 'user', 11]);
|
|
*
|
|
* // you can collapse static segments like this (this works only with the first passed-in value):
|
|
* router.createUrlTree(['/team/33/user', userId]);
|
|
*
|
|
* // If the first segment can contain slashes, and you do not want the router to split it,
|
|
* // you can do the following:
|
|
* router.createUrlTree([{segmentPath: '/one/two'}]);
|
|
*
|
|
* // create /team/33/(user/11//right:chat)
|
|
* router.createUrlTree(['/team', 33, {outlets: {primary: 'user/11', right: 'chat'}}]);
|
|
*
|
|
* // remove the right secondary node
|
|
* router.createUrlTree(['/team', 33, {outlets: {primary: 'user/11', right: null}}]);
|
|
*
|
|
* // assuming the current url is `/team/33/user/11` and the route points to `user/11`
|
|
*
|
|
* // navigate to /team/33/user/11/details
|
|
* router.createUrlTree(['details'], {relativeTo: route});
|
|
*
|
|
* // navigate to /team/33/user/22
|
|
* router.createUrlTree(['../22'], {relativeTo: route});
|
|
*
|
|
* // navigate to /team/44/user/22
|
|
* router.createUrlTree(['../../team/44/user/22'], {relativeTo: route});
|
|
*
|
|
* Note that a value of `null` or `undefined` for `relativeTo` indicates that the
|
|
* tree should be created relative to the root.
|
|
* ```
|
|
*/
|
|
createUrlTree(commands, navigationExtras = {}) {
|
|
const {
|
|
relativeTo,
|
|
queryParams,
|
|
fragment,
|
|
queryParamsHandling,
|
|
preserveFragment
|
|
} = navigationExtras;
|
|
const f = preserveFragment ? this.currentUrlTree.fragment : fragment;
|
|
let q = null;
|
|
switch (queryParamsHandling) {
|
|
case "merge":
|
|
q = __spreadValues(__spreadValues({}, this.currentUrlTree.queryParams), queryParams);
|
|
break;
|
|
case "preserve":
|
|
q = this.currentUrlTree.queryParams;
|
|
break;
|
|
default:
|
|
q = queryParams || null;
|
|
}
|
|
if (q !== null) {
|
|
q = this.removeEmptyProps(q);
|
|
}
|
|
let relativeToUrlSegmentGroup;
|
|
try {
|
|
const relativeToSnapshot = relativeTo ? relativeTo.snapshot : this.routerState.snapshot.root;
|
|
relativeToUrlSegmentGroup = createSegmentGroupFromRoute(relativeToSnapshot);
|
|
} catch (e) {
|
|
if (typeof commands[0] !== "string" || !commands[0].startsWith("/")) {
|
|
commands = [];
|
|
}
|
|
relativeToUrlSegmentGroup = this.currentUrlTree.root;
|
|
}
|
|
return createUrlTreeFromSegmentGroup(relativeToUrlSegmentGroup, commands, q, f ?? null);
|
|
}
|
|
/**
|
|
* Navigates to a view using an absolute route path.
|
|
*
|
|
* @param url An absolute path for a defined route. The function does not apply any delta to the
|
|
* current URL.
|
|
* @param extras An object containing properties that modify the navigation strategy.
|
|
*
|
|
* @returns A Promise that resolves to 'true' when navigation succeeds,
|
|
* to 'false' when navigation fails, or is rejected on error.
|
|
*
|
|
* @usageNotes
|
|
*
|
|
* The following calls request navigation to an absolute path.
|
|
*
|
|
* ```
|
|
* router.navigateByUrl("/team/33/user/11");
|
|
*
|
|
* // Navigate without updating the URL
|
|
* router.navigateByUrl("/team/33/user/11", { skipLocationChange: true });
|
|
* ```
|
|
*
|
|
* @see [Routing and Navigation guide](guide/router)
|
|
*
|
|
*/
|
|
navigateByUrl(url, extras = {
|
|
skipLocationChange: false
|
|
}) {
|
|
if (typeof ngDevMode === "undefined" || ngDevMode) {
|
|
if (this.isNgZoneEnabled && !NgZone.isInAngularZone()) {
|
|
this.console.warn(`Navigation triggered outside Angular zone, did you forget to call 'ngZone.run()'?`);
|
|
}
|
|
}
|
|
const urlTree = isUrlTree(url) ? url : this.parseUrl(url);
|
|
const mergedTree = this.urlHandlingStrategy.merge(urlTree, this.rawUrlTree);
|
|
return this.scheduleNavigation(mergedTree, IMPERATIVE_NAVIGATION, null, extras);
|
|
}
|
|
/**
|
|
* Navigate based on the provided array of commands and a starting point.
|
|
* If no starting route is provided, the navigation is absolute.
|
|
*
|
|
* @param commands An array of URL fragments with which to construct the target URL.
|
|
* If the path is static, can be the literal URL string. For a dynamic path, pass an array of path
|
|
* segments, followed by the parameters for each segment.
|
|
* The fragments are applied to the current URL or the one provided in the `relativeTo` property
|
|
* of the options object, if supplied.
|
|
* @param extras An options object that determines how the URL should be constructed or
|
|
* interpreted.
|
|
*
|
|
* @returns A Promise that resolves to `true` when navigation succeeds, to `false` when navigation
|
|
* fails,
|
|
* or is rejected on error.
|
|
*
|
|
* @usageNotes
|
|
*
|
|
* The following calls request navigation to a dynamic route path relative to the current URL.
|
|
*
|
|
* ```
|
|
* router.navigate(['team', 33, 'user', 11], {relativeTo: route});
|
|
*
|
|
* // Navigate without updating the URL, overriding the default behavior
|
|
* router.navigate(['team', 33, 'user', 11], {relativeTo: route, skipLocationChange: true});
|
|
* ```
|
|
*
|
|
* @see [Routing and Navigation guide](guide/router)
|
|
*
|
|
*/
|
|
navigate(commands, extras = {
|
|
skipLocationChange: false
|
|
}) {
|
|
validateCommands(commands);
|
|
return this.navigateByUrl(this.createUrlTree(commands, extras), extras);
|
|
}
|
|
/** Serializes a `UrlTree` into a string */
|
|
serializeUrl(url) {
|
|
return this.urlSerializer.serialize(url);
|
|
}
|
|
/** Parses a string into a `UrlTree` */
|
|
parseUrl(url) {
|
|
try {
|
|
return this.urlSerializer.parse(url);
|
|
} catch {
|
|
return this.urlSerializer.parse("/");
|
|
}
|
|
}
|
|
isActive(url, matchOptions) {
|
|
let options;
|
|
if (matchOptions === true) {
|
|
options = __spreadValues({}, exactMatchOptions);
|
|
} else if (matchOptions === false) {
|
|
options = __spreadValues({}, subsetMatchOptions);
|
|
} else {
|
|
options = matchOptions;
|
|
}
|
|
if (isUrlTree(url)) {
|
|
return containsTree(this.currentUrlTree, url, options);
|
|
}
|
|
const urlTree = this.parseUrl(url);
|
|
return containsTree(this.currentUrlTree, urlTree, options);
|
|
}
|
|
removeEmptyProps(params) {
|
|
return Object.keys(params).reduce((result, key) => {
|
|
const value = params[key];
|
|
if (value !== null && value !== void 0) {
|
|
result[key] = value;
|
|
}
|
|
return result;
|
|
}, {});
|
|
}
|
|
scheduleNavigation(rawUrl, source, restoredState, extras, priorPromise) {
|
|
if (this.disposed) {
|
|
return Promise.resolve(false);
|
|
}
|
|
let resolve;
|
|
let reject;
|
|
let promise;
|
|
if (priorPromise) {
|
|
resolve = priorPromise.resolve;
|
|
reject = priorPromise.reject;
|
|
promise = priorPromise.promise;
|
|
} else {
|
|
promise = new Promise((res, rej) => {
|
|
resolve = res;
|
|
reject = rej;
|
|
});
|
|
}
|
|
const taskId = this.pendingTasks.add();
|
|
afterNextNavigation(this, () => {
|
|
queueMicrotask(() => this.pendingTasks.remove(taskId));
|
|
});
|
|
this.navigationTransitions.handleNavigationRequest({
|
|
source,
|
|
restoredState,
|
|
currentUrlTree: this.currentUrlTree,
|
|
currentRawUrl: this.currentUrlTree,
|
|
rawUrl,
|
|
extras,
|
|
resolve,
|
|
reject,
|
|
promise,
|
|
currentSnapshot: this.routerState.snapshot,
|
|
currentRouterState: this.routerState
|
|
});
|
|
return promise.catch((e) => {
|
|
return Promise.reject(e);
|
|
});
|
|
}
|
|
};
|
|
_Router.ɵfac = function Router_Factory(t) {
|
|
return new (t || _Router)();
|
|
};
|
|
_Router.ɵprov = ɵɵdefineInjectable({
|
|
token: _Router,
|
|
factory: _Router.ɵfac,
|
|
providedIn: "root"
|
|
});
|
|
var Router = _Router;
|
|
(() => {
|
|
(typeof ngDevMode === "undefined" || ngDevMode) && setClassMetadata(Router, [{
|
|
type: Injectable,
|
|
args: [{
|
|
providedIn: "root"
|
|
}]
|
|
}], () => [], null);
|
|
})();
|
|
function validateCommands(commands) {
|
|
for (let i = 0; i < commands.length; i++) {
|
|
const cmd = commands[i];
|
|
if (cmd == null) {
|
|
throw new RuntimeError(4008, (typeof ngDevMode === "undefined" || ngDevMode) && `The requested path contains ${cmd} segment at index ${i}`);
|
|
}
|
|
}
|
|
}
|
|
function isPublicRouterEvent(e) {
|
|
return !(e instanceof BeforeActivateRoutes) && !(e instanceof RedirectRequest);
|
|
}
|
|
var _RouterLink = class _RouterLink {
|
|
constructor(router, route, tabIndexAttribute, renderer, el, locationStrategy) {
|
|
this.router = router;
|
|
this.route = route;
|
|
this.tabIndexAttribute = tabIndexAttribute;
|
|
this.renderer = renderer;
|
|
this.el = el;
|
|
this.locationStrategy = locationStrategy;
|
|
this.href = null;
|
|
this.commands = null;
|
|
this.onChanges = new Subject();
|
|
this.preserveFragment = false;
|
|
this.skipLocationChange = false;
|
|
this.replaceUrl = false;
|
|
const tagName = el.nativeElement.tagName?.toLowerCase();
|
|
this.isAnchorElement = tagName === "a" || tagName === "area";
|
|
if (this.isAnchorElement) {
|
|
this.subscription = router.events.subscribe((s) => {
|
|
if (s instanceof NavigationEnd) {
|
|
this.updateHref();
|
|
}
|
|
});
|
|
} else {
|
|
this.setTabIndexIfNotOnNativeEl("0");
|
|
}
|
|
}
|
|
/**
|
|
* Modifies the tab index if there was not a tabindex attribute on the element during
|
|
* instantiation.
|
|
*/
|
|
setTabIndexIfNotOnNativeEl(newTabIndex) {
|
|
if (this.tabIndexAttribute != null || this.isAnchorElement) {
|
|
return;
|
|
}
|
|
this.applyAttributeValue("tabindex", newTabIndex);
|
|
}
|
|
/** @nodoc */
|
|
ngOnChanges(changes) {
|
|
if (this.isAnchorElement) {
|
|
this.updateHref();
|
|
}
|
|
this.onChanges.next(this);
|
|
}
|
|
/**
|
|
* Commands to pass to {@link Router#createUrlTree}.
|
|
* - **array**: commands to pass to {@link Router#createUrlTree}.
|
|
* - **string**: shorthand for array of commands with just the string, i.e. `['/route']`
|
|
* - **null|undefined**: effectively disables the `routerLink`
|
|
* @see {@link Router#createUrlTree}
|
|
*/
|
|
set routerLink(commands) {
|
|
if (commands != null) {
|
|
this.commands = Array.isArray(commands) ? commands : [commands];
|
|
this.setTabIndexIfNotOnNativeEl("0");
|
|
} else {
|
|
this.commands = null;
|
|
this.setTabIndexIfNotOnNativeEl(null);
|
|
}
|
|
}
|
|
/** @nodoc */
|
|
onClick(button, ctrlKey, shiftKey, altKey, metaKey) {
|
|
if (this.urlTree === null) {
|
|
return true;
|
|
}
|
|
if (this.isAnchorElement) {
|
|
if (button !== 0 || ctrlKey || shiftKey || altKey || metaKey) {
|
|
return true;
|
|
}
|
|
if (typeof this.target === "string" && this.target != "_self") {
|
|
return true;
|
|
}
|
|
}
|
|
const extras = {
|
|
skipLocationChange: this.skipLocationChange,
|
|
replaceUrl: this.replaceUrl,
|
|
state: this.state
|
|
};
|
|
this.router.navigateByUrl(this.urlTree, extras);
|
|
return !this.isAnchorElement;
|
|
}
|
|
/** @nodoc */
|
|
ngOnDestroy() {
|
|
this.subscription?.unsubscribe();
|
|
}
|
|
updateHref() {
|
|
this.href = this.urlTree !== null && this.locationStrategy ? this.locationStrategy?.prepareExternalUrl(this.router.serializeUrl(this.urlTree)) : null;
|
|
const sanitizedValue = this.href === null ? null : (
|
|
// This class represents a directive that can be added to both `<a>` elements,
|
|
// as well as other elements. As a result, we can't define security context at
|
|
// compile time. So the security context is deferred to runtime.
|
|
// The `ɵɵsanitizeUrlOrResourceUrl` selects the necessary sanitizer function
|
|
// based on the tag and property names. The logic mimics the one from
|
|
// `packages/compiler/src/schema/dom_security_schema.ts`, which is used at compile time.
|
|
//
|
|
// Note: we should investigate whether we can switch to using `@HostBinding('attr.href')`
|
|
// instead of applying a value via a renderer, after a final merge of the
|
|
// `RouterLinkWithHref` directive.
|
|
ɵɵsanitizeUrlOrResourceUrl(this.href, this.el.nativeElement.tagName.toLowerCase(), "href")
|
|
);
|
|
this.applyAttributeValue("href", sanitizedValue);
|
|
}
|
|
applyAttributeValue(attrName, attrValue) {
|
|
const renderer = this.renderer;
|
|
const nativeElement = this.el.nativeElement;
|
|
if (attrValue !== null) {
|
|
renderer.setAttribute(nativeElement, attrName, attrValue);
|
|
} else {
|
|
renderer.removeAttribute(nativeElement, attrName);
|
|
}
|
|
}
|
|
get urlTree() {
|
|
if (this.commands === null) {
|
|
return null;
|
|
}
|
|
return this.router.createUrlTree(this.commands, {
|
|
// If the `relativeTo` input is not defined, we want to use `this.route` by default.
|
|
// Otherwise, we should use the value provided by the user in the input.
|
|
relativeTo: this.relativeTo !== void 0 ? this.relativeTo : this.route,
|
|
queryParams: this.queryParams,
|
|
fragment: this.fragment,
|
|
queryParamsHandling: this.queryParamsHandling,
|
|
preserveFragment: this.preserveFragment
|
|
});
|
|
}
|
|
};
|
|
_RouterLink.ɵfac = function RouterLink_Factory(t) {
|
|
return new (t || _RouterLink)(ɵɵdirectiveInject(Router), ɵɵdirectiveInject(ActivatedRoute), ɵɵinjectAttribute("tabindex"), ɵɵdirectiveInject(Renderer2), ɵɵdirectiveInject(ElementRef), ɵɵdirectiveInject(LocationStrategy));
|
|
};
|
|
_RouterLink.ɵdir = ɵɵdefineDirective({
|
|
type: _RouterLink,
|
|
selectors: [["", "routerLink", ""]],
|
|
hostVars: 1,
|
|
hostBindings: function RouterLink_HostBindings(rf, ctx) {
|
|
if (rf & 1) {
|
|
ɵɵlistener("click", function RouterLink_click_HostBindingHandler($event) {
|
|
return ctx.onClick($event.button, $event.ctrlKey, $event.shiftKey, $event.altKey, $event.metaKey);
|
|
});
|
|
}
|
|
if (rf & 2) {
|
|
ɵɵattribute("target", ctx.target);
|
|
}
|
|
},
|
|
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"
|
|
},
|
|
standalone: true,
|
|
features: [ɵɵInputTransformsFeature, ɵɵNgOnChangesFeature]
|
|
});
|
|
var RouterLink = _RouterLink;
|
|
(() => {
|
|
(typeof ngDevMode === "undefined" || ngDevMode) && setClassMetadata(RouterLink, [{
|
|
type: Directive,
|
|
args: [{
|
|
selector: "[routerLink]",
|
|
standalone: true
|
|
}]
|
|
}], () => [{
|
|
type: Router
|
|
}, {
|
|
type: ActivatedRoute
|
|
}, {
|
|
type: void 0,
|
|
decorators: [{
|
|
type: Attribute,
|
|
args: ["tabindex"]
|
|
}]
|
|
}, {
|
|
type: Renderer2
|
|
}, {
|
|
type: ElementRef
|
|
}, {
|
|
type: LocationStrategy
|
|
}], {
|
|
target: [{
|
|
type: HostBinding,
|
|
args: ["attr.target"]
|
|
}, {
|
|
type: Input
|
|
}],
|
|
queryParams: [{
|
|
type: Input
|
|
}],
|
|
fragment: [{
|
|
type: Input
|
|
}],
|
|
queryParamsHandling: [{
|
|
type: Input
|
|
}],
|
|
state: [{
|
|
type: Input
|
|
}],
|
|
relativeTo: [{
|
|
type: Input
|
|
}],
|
|
preserveFragment: [{
|
|
type: Input,
|
|
args: [{
|
|
transform: booleanAttribute
|
|
}]
|
|
}],
|
|
skipLocationChange: [{
|
|
type: Input,
|
|
args: [{
|
|
transform: booleanAttribute
|
|
}]
|
|
}],
|
|
replaceUrl: [{
|
|
type: Input,
|
|
args: [{
|
|
transform: booleanAttribute
|
|
}]
|
|
}],
|
|
routerLink: [{
|
|
type: Input
|
|
}],
|
|
onClick: [{
|
|
type: HostListener,
|
|
args: ["click", ["$event.button", "$event.ctrlKey", "$event.shiftKey", "$event.altKey", "$event.metaKey"]]
|
|
}]
|
|
});
|
|
})();
|
|
var _RouterLinkActive = class _RouterLinkActive {
|
|
get isActive() {
|
|
return this._isActive;
|
|
}
|
|
constructor(router, element, renderer, cdr, link) {
|
|
this.router = router;
|
|
this.element = element;
|
|
this.renderer = renderer;
|
|
this.cdr = cdr;
|
|
this.link = link;
|
|
this.classes = [];
|
|
this._isActive = false;
|
|
this.routerLinkActiveOptions = {
|
|
exact: false
|
|
};
|
|
this.isActiveChange = new EventEmitter();
|
|
this.routerEventsSubscription = router.events.subscribe((s) => {
|
|
if (s instanceof NavigationEnd) {
|
|
this.update();
|
|
}
|
|
});
|
|
}
|
|
/** @nodoc */
|
|
ngAfterContentInit() {
|
|
of(this.links.changes, of(null)).pipe(mergeAll()).subscribe((_) => {
|
|
this.update();
|
|
this.subscribeToEachLinkOnChanges();
|
|
});
|
|
}
|
|
subscribeToEachLinkOnChanges() {
|
|
this.linkInputChangesSubscription?.unsubscribe();
|
|
const allLinkChanges = [...this.links.toArray(), this.link].filter((link) => !!link).map((link) => link.onChanges);
|
|
this.linkInputChangesSubscription = from(allLinkChanges).pipe(mergeAll()).subscribe((link) => {
|
|
if (this._isActive !== this.isLinkActive(this.router)(link)) {
|
|
this.update();
|
|
}
|
|
});
|
|
}
|
|
set routerLinkActive(data) {
|
|
const classes = Array.isArray(data) ? data : data.split(" ");
|
|
this.classes = classes.filter((c) => !!c);
|
|
}
|
|
/** @nodoc */
|
|
ngOnChanges(changes) {
|
|
this.update();
|
|
}
|
|
/** @nodoc */
|
|
ngOnDestroy() {
|
|
this.routerEventsSubscription.unsubscribe();
|
|
this.linkInputChangesSubscription?.unsubscribe();
|
|
}
|
|
update() {
|
|
if (!this.links || !this.router.navigated)
|
|
return;
|
|
queueMicrotask(() => {
|
|
const hasActiveLinks = this.hasActiveLinks();
|
|
if (this._isActive !== hasActiveLinks) {
|
|
this._isActive = hasActiveLinks;
|
|
this.cdr.markForCheck();
|
|
this.classes.forEach((c) => {
|
|
if (hasActiveLinks) {
|
|
this.renderer.addClass(this.element.nativeElement, c);
|
|
} else {
|
|
this.renderer.removeClass(this.element.nativeElement, c);
|
|
}
|
|
});
|
|
if (hasActiveLinks && this.ariaCurrentWhenActive !== void 0) {
|
|
this.renderer.setAttribute(this.element.nativeElement, "aria-current", this.ariaCurrentWhenActive.toString());
|
|
} else {
|
|
this.renderer.removeAttribute(this.element.nativeElement, "aria-current");
|
|
}
|
|
this.isActiveChange.emit(hasActiveLinks);
|
|
}
|
|
});
|
|
}
|
|
isLinkActive(router) {
|
|
const options = isActiveMatchOptions(this.routerLinkActiveOptions) ? this.routerLinkActiveOptions : (
|
|
// While the types should disallow `undefined` here, it's possible without strict inputs
|
|
this.routerLinkActiveOptions.exact || false
|
|
);
|
|
return (link) => link.urlTree ? router.isActive(link.urlTree, options) : false;
|
|
}
|
|
hasActiveLinks() {
|
|
const isActiveCheckFn = this.isLinkActive(this.router);
|
|
return this.link && isActiveCheckFn(this.link) || this.links.some(isActiveCheckFn);
|
|
}
|
|
};
|
|
_RouterLinkActive.ɵfac = function RouterLinkActive_Factory(t) {
|
|
return new (t || _RouterLinkActive)(ɵɵdirectiveInject(Router), ɵɵdirectiveInject(ElementRef), ɵɵdirectiveInject(Renderer2), ɵɵdirectiveInject(ChangeDetectorRef), ɵɵdirectiveInject(RouterLink, 8));
|
|
};
|
|
_RouterLinkActive.ɵdir = ɵɵdefineDirective({
|
|
type: _RouterLinkActive,
|
|
selectors: [["", "routerLinkActive", ""]],
|
|
contentQueries: function RouterLinkActive_ContentQueries(rf, ctx, dirIndex) {
|
|
if (rf & 1) {
|
|
ɵɵcontentQuery(dirIndex, RouterLink, 5);
|
|
}
|
|
if (rf & 2) {
|
|
let _t;
|
|
ɵɵqueryRefresh(_t = ɵɵloadQuery()) && (ctx.links = _t);
|
|
}
|
|
},
|
|
inputs: {
|
|
routerLinkActiveOptions: "routerLinkActiveOptions",
|
|
ariaCurrentWhenActive: "ariaCurrentWhenActive",
|
|
routerLinkActive: "routerLinkActive"
|
|
},
|
|
outputs: {
|
|
isActiveChange: "isActiveChange"
|
|
},
|
|
exportAs: ["routerLinkActive"],
|
|
standalone: true,
|
|
features: [ɵɵNgOnChangesFeature]
|
|
});
|
|
var RouterLinkActive = _RouterLinkActive;
|
|
(() => {
|
|
(typeof ngDevMode === "undefined" || ngDevMode) && setClassMetadata(RouterLinkActive, [{
|
|
type: Directive,
|
|
args: [{
|
|
selector: "[routerLinkActive]",
|
|
exportAs: "routerLinkActive",
|
|
standalone: true
|
|
}]
|
|
}], () => [{
|
|
type: Router
|
|
}, {
|
|
type: ElementRef
|
|
}, {
|
|
type: Renderer2
|
|
}, {
|
|
type: ChangeDetectorRef
|
|
}, {
|
|
type: RouterLink,
|
|
decorators: [{
|
|
type: Optional
|
|
}]
|
|
}], {
|
|
links: [{
|
|
type: ContentChildren,
|
|
args: [RouterLink, {
|
|
descendants: true
|
|
}]
|
|
}],
|
|
routerLinkActiveOptions: [{
|
|
type: Input
|
|
}],
|
|
ariaCurrentWhenActive: [{
|
|
type: Input
|
|
}],
|
|
isActiveChange: [{
|
|
type: Output
|
|
}],
|
|
routerLinkActive: [{
|
|
type: Input
|
|
}]
|
|
});
|
|
})();
|
|
function isActiveMatchOptions(options) {
|
|
return !!options.paths;
|
|
}
|
|
var PreloadingStrategy = class {
|
|
};
|
|
var _PreloadAllModules = class _PreloadAllModules {
|
|
preload(route, fn) {
|
|
return fn().pipe(catchError(() => of(null)));
|
|
}
|
|
};
|
|
_PreloadAllModules.ɵfac = function PreloadAllModules_Factory(t) {
|
|
return new (t || _PreloadAllModules)();
|
|
};
|
|
_PreloadAllModules.ɵprov = ɵɵdefineInjectable({
|
|
token: _PreloadAllModules,
|
|
factory: _PreloadAllModules.ɵfac,
|
|
providedIn: "root"
|
|
});
|
|
var PreloadAllModules = _PreloadAllModules;
|
|
(() => {
|
|
(typeof ngDevMode === "undefined" || ngDevMode) && setClassMetadata(PreloadAllModules, [{
|
|
type: Injectable,
|
|
args: [{
|
|
providedIn: "root"
|
|
}]
|
|
}], null, null);
|
|
})();
|
|
var _NoPreloading = class _NoPreloading {
|
|
preload(route, fn) {
|
|
return of(null);
|
|
}
|
|
};
|
|
_NoPreloading.ɵfac = function NoPreloading_Factory(t) {
|
|
return new (t || _NoPreloading)();
|
|
};
|
|
_NoPreloading.ɵprov = ɵɵdefineInjectable({
|
|
token: _NoPreloading,
|
|
factory: _NoPreloading.ɵfac,
|
|
providedIn: "root"
|
|
});
|
|
var NoPreloading = _NoPreloading;
|
|
(() => {
|
|
(typeof ngDevMode === "undefined" || ngDevMode) && setClassMetadata(NoPreloading, [{
|
|
type: Injectable,
|
|
args: [{
|
|
providedIn: "root"
|
|
}]
|
|
}], null, null);
|
|
})();
|
|
var _RouterPreloader = class _RouterPreloader {
|
|
constructor(router, compiler, injector, preloadingStrategy, loader) {
|
|
this.router = router;
|
|
this.injector = injector;
|
|
this.preloadingStrategy = preloadingStrategy;
|
|
this.loader = loader;
|
|
}
|
|
setUpPreloading() {
|
|
this.subscription = this.router.events.pipe(filter((e) => e instanceof NavigationEnd), concatMap(() => this.preload())).subscribe(() => {
|
|
});
|
|
}
|
|
preload() {
|
|
return this.processRoutes(this.injector, this.router.config);
|
|
}
|
|
/** @nodoc */
|
|
ngOnDestroy() {
|
|
if (this.subscription) {
|
|
this.subscription.unsubscribe();
|
|
}
|
|
}
|
|
processRoutes(injector, routes) {
|
|
const res = [];
|
|
for (const route of routes) {
|
|
if (route.providers && !route._injector) {
|
|
route._injector = createEnvironmentInjector(route.providers, injector, `Route: ${route.path}`);
|
|
}
|
|
const injectorForCurrentRoute = route._injector ?? injector;
|
|
const injectorForChildren = route._loadedInjector ?? injectorForCurrentRoute;
|
|
if (route.loadChildren && !route._loadedRoutes && route.canLoad === void 0 || route.loadComponent && !route._loadedComponent) {
|
|
res.push(this.preloadConfig(injectorForCurrentRoute, route));
|
|
}
|
|
if (route.children || route._loadedRoutes) {
|
|
res.push(this.processRoutes(injectorForChildren, route.children ?? route._loadedRoutes));
|
|
}
|
|
}
|
|
return from(res).pipe(mergeAll());
|
|
}
|
|
preloadConfig(injector, route) {
|
|
return this.preloadingStrategy.preload(route, () => {
|
|
let loadedChildren$;
|
|
if (route.loadChildren && route.canLoad === void 0) {
|
|
loadedChildren$ = this.loader.loadChildren(injector, route);
|
|
} else {
|
|
loadedChildren$ = of(null);
|
|
}
|
|
const recursiveLoadChildren$ = loadedChildren$.pipe(mergeMap((config) => {
|
|
if (config === null) {
|
|
return of(void 0);
|
|
}
|
|
route._loadedRoutes = config.routes;
|
|
route._loadedInjector = config.injector;
|
|
return this.processRoutes(config.injector ?? injector, config.routes);
|
|
}));
|
|
if (route.loadComponent && !route._loadedComponent) {
|
|
const loadComponent$ = this.loader.loadComponent(route);
|
|
return from([recursiveLoadChildren$, loadComponent$]).pipe(mergeAll());
|
|
} else {
|
|
return recursiveLoadChildren$;
|
|
}
|
|
});
|
|
}
|
|
};
|
|
_RouterPreloader.ɵfac = function RouterPreloader_Factory(t) {
|
|
return new (t || _RouterPreloader)(ɵɵinject(Router), ɵɵinject(Compiler), ɵɵinject(EnvironmentInjector), ɵɵinject(PreloadingStrategy), ɵɵinject(RouterConfigLoader));
|
|
};
|
|
_RouterPreloader.ɵprov = ɵɵdefineInjectable({
|
|
token: _RouterPreloader,
|
|
factory: _RouterPreloader.ɵfac,
|
|
providedIn: "root"
|
|
});
|
|
var RouterPreloader = _RouterPreloader;
|
|
(() => {
|
|
(typeof ngDevMode === "undefined" || ngDevMode) && setClassMetadata(RouterPreloader, [{
|
|
type: Injectable,
|
|
args: [{
|
|
providedIn: "root"
|
|
}]
|
|
}], () => [{
|
|
type: Router
|
|
}, {
|
|
type: Compiler
|
|
}, {
|
|
type: EnvironmentInjector
|
|
}, {
|
|
type: PreloadingStrategy
|
|
}, {
|
|
type: RouterConfigLoader
|
|
}], null);
|
|
})();
|
|
var ROUTER_SCROLLER = new InjectionToken("");
|
|
var _RouterScroller = class _RouterScroller {
|
|
/** @nodoc */
|
|
constructor(urlSerializer, transitions, viewportScroller, zone, options = {}) {
|
|
this.urlSerializer = urlSerializer;
|
|
this.transitions = transitions;
|
|
this.viewportScroller = viewportScroller;
|
|
this.zone = zone;
|
|
this.options = options;
|
|
this.lastId = 0;
|
|
this.lastSource = "imperative";
|
|
this.restoredId = 0;
|
|
this.store = {};
|
|
options.scrollPositionRestoration = options.scrollPositionRestoration || "disabled";
|
|
options.anchorScrolling = options.anchorScrolling || "disabled";
|
|
}
|
|
init() {
|
|
if (this.options.scrollPositionRestoration !== "disabled") {
|
|
this.viewportScroller.setHistoryScrollRestoration("manual");
|
|
}
|
|
this.routerEventsSubscription = this.createScrollEvents();
|
|
this.scrollEventsSubscription = this.consumeScrollEvents();
|
|
}
|
|
createScrollEvents() {
|
|
return this.transitions.events.subscribe((e) => {
|
|
if (e instanceof NavigationStart) {
|
|
this.store[this.lastId] = this.viewportScroller.getScrollPosition();
|
|
this.lastSource = e.navigationTrigger;
|
|
this.restoredId = e.restoredState ? e.restoredState.navigationId : 0;
|
|
} else if (e instanceof NavigationEnd) {
|
|
this.lastId = e.id;
|
|
this.scheduleScrollEvent(e, this.urlSerializer.parse(e.urlAfterRedirects).fragment);
|
|
} else if (e instanceof NavigationSkipped && e.code === 0) {
|
|
this.lastSource = void 0;
|
|
this.restoredId = 0;
|
|
this.scheduleScrollEvent(e, this.urlSerializer.parse(e.url).fragment);
|
|
}
|
|
});
|
|
}
|
|
consumeScrollEvents() {
|
|
return this.transitions.events.subscribe((e) => {
|
|
if (!(e instanceof Scroll))
|
|
return;
|
|
if (e.position) {
|
|
if (this.options.scrollPositionRestoration === "top") {
|
|
this.viewportScroller.scrollToPosition([0, 0]);
|
|
} else if (this.options.scrollPositionRestoration === "enabled") {
|
|
this.viewportScroller.scrollToPosition(e.position);
|
|
}
|
|
} else {
|
|
if (e.anchor && this.options.anchorScrolling === "enabled") {
|
|
this.viewportScroller.scrollToAnchor(e.anchor);
|
|
} else if (this.options.scrollPositionRestoration !== "disabled") {
|
|
this.viewportScroller.scrollToPosition([0, 0]);
|
|
}
|
|
}
|
|
});
|
|
}
|
|
scheduleScrollEvent(routerEvent, anchor) {
|
|
this.zone.runOutsideAngular(() => {
|
|
setTimeout(() => {
|
|
this.zone.run(() => {
|
|
this.transitions.events.next(new Scroll(routerEvent, this.lastSource === "popstate" ? this.store[this.restoredId] : null, anchor));
|
|
});
|
|
}, 0);
|
|
});
|
|
}
|
|
/** @nodoc */
|
|
ngOnDestroy() {
|
|
this.routerEventsSubscription?.unsubscribe();
|
|
this.scrollEventsSubscription?.unsubscribe();
|
|
}
|
|
};
|
|
_RouterScroller.ɵfac = function RouterScroller_Factory(t) {
|
|
ɵɵinvalidFactory();
|
|
};
|
|
_RouterScroller.ɵprov = ɵɵdefineInjectable({
|
|
token: _RouterScroller,
|
|
factory: _RouterScroller.ɵfac
|
|
});
|
|
var RouterScroller = _RouterScroller;
|
|
(() => {
|
|
(typeof ngDevMode === "undefined" || ngDevMode) && setClassMetadata(RouterScroller, [{
|
|
type: Injectable
|
|
}], () => [{
|
|
type: UrlSerializer
|
|
}, {
|
|
type: NavigationTransitions
|
|
}, {
|
|
type: ViewportScroller
|
|
}, {
|
|
type: NgZone
|
|
}, {
|
|
type: void 0
|
|
}], null);
|
|
})();
|
|
function provideRouter(routes, ...features) {
|
|
return makeEnvironmentProviders([{
|
|
provide: ROUTES,
|
|
multi: true,
|
|
useValue: routes
|
|
}, typeof ngDevMode === "undefined" || ngDevMode ? {
|
|
provide: ROUTER_IS_PROVIDED,
|
|
useValue: true
|
|
} : [], {
|
|
provide: ActivatedRoute,
|
|
useFactory: rootRoute,
|
|
deps: [Router]
|
|
}, {
|
|
provide: APP_BOOTSTRAP_LISTENER,
|
|
multi: true,
|
|
useFactory: getBootstrapListener
|
|
}, features.map((feature) => feature.ɵproviders)]);
|
|
}
|
|
function rootRoute(router) {
|
|
return router.routerState.root;
|
|
}
|
|
function routerFeature(kind, providers) {
|
|
return {
|
|
ɵkind: kind,
|
|
ɵproviders: providers
|
|
};
|
|
}
|
|
var ROUTER_IS_PROVIDED = new InjectionToken("", {
|
|
providedIn: "root",
|
|
factory: () => false
|
|
});
|
|
var routerIsProvidedDevModeCheck = {
|
|
provide: ENVIRONMENT_INITIALIZER,
|
|
multi: true,
|
|
useFactory() {
|
|
return () => {
|
|
if (!inject(ROUTER_IS_PROVIDED)) {
|
|
console.warn("`provideRoutes` was called without `provideRouter` or `RouterModule.forRoot`. This is likely a mistake.");
|
|
}
|
|
};
|
|
}
|
|
};
|
|
function provideRoutes(routes) {
|
|
return [{
|
|
provide: ROUTES,
|
|
multi: true,
|
|
useValue: routes
|
|
}, typeof ngDevMode === "undefined" || ngDevMode ? routerIsProvidedDevModeCheck : []];
|
|
}
|
|
function withInMemoryScrolling(options = {}) {
|
|
const providers = [{
|
|
provide: ROUTER_SCROLLER,
|
|
useFactory: () => {
|
|
const viewportScroller = inject(ViewportScroller);
|
|
const zone = inject(NgZone);
|
|
const transitions = inject(NavigationTransitions);
|
|
const urlSerializer = inject(UrlSerializer);
|
|
return new RouterScroller(urlSerializer, transitions, viewportScroller, zone, options);
|
|
}
|
|
}];
|
|
return routerFeature(4, providers);
|
|
}
|
|
function getBootstrapListener() {
|
|
const injector = inject(Injector);
|
|
return (bootstrappedComponentRef) => {
|
|
const ref = injector.get(ApplicationRef);
|
|
if (bootstrappedComponentRef !== ref.components[0]) {
|
|
return;
|
|
}
|
|
const router = injector.get(Router);
|
|
const bootstrapDone = injector.get(BOOTSTRAP_DONE);
|
|
if (injector.get(INITIAL_NAVIGATION) === 1) {
|
|
router.initialNavigation();
|
|
}
|
|
injector.get(ROUTER_PRELOADER, null, InjectFlags.Optional)?.setUpPreloading();
|
|
injector.get(ROUTER_SCROLLER, null, InjectFlags.Optional)?.init();
|
|
router.resetRootComponentType(ref.componentTypes[0]);
|
|
if (!bootstrapDone.closed) {
|
|
bootstrapDone.next();
|
|
bootstrapDone.complete();
|
|
bootstrapDone.unsubscribe();
|
|
}
|
|
};
|
|
}
|
|
var BOOTSTRAP_DONE = new InjectionToken(typeof ngDevMode === "undefined" || ngDevMode ? "bootstrap done indicator" : "", {
|
|
factory: () => {
|
|
return new Subject();
|
|
}
|
|
});
|
|
var INITIAL_NAVIGATION = new InjectionToken(typeof ngDevMode === "undefined" || ngDevMode ? "initial navigation" : "", {
|
|
providedIn: "root",
|
|
factory: () => 1
|
|
/* InitialNavigation.EnabledNonBlocking */
|
|
});
|
|
function withEnabledBlockingInitialNavigation() {
|
|
const providers = [{
|
|
provide: INITIAL_NAVIGATION,
|
|
useValue: 0
|
|
/* InitialNavigation.EnabledBlocking */
|
|
}, {
|
|
provide: APP_INITIALIZER,
|
|
multi: true,
|
|
deps: [Injector],
|
|
useFactory: (injector) => {
|
|
const locationInitialized = injector.get(LOCATION_INITIALIZED, Promise.resolve());
|
|
return () => {
|
|
return locationInitialized.then(() => {
|
|
return new Promise((resolve) => {
|
|
const router = injector.get(Router);
|
|
const bootstrapDone = injector.get(BOOTSTRAP_DONE);
|
|
afterNextNavigation(router, () => {
|
|
resolve(true);
|
|
});
|
|
injector.get(NavigationTransitions).afterPreactivation = () => {
|
|
resolve(true);
|
|
return bootstrapDone.closed ? of(void 0) : bootstrapDone;
|
|
};
|
|
router.initialNavigation();
|
|
});
|
|
});
|
|
};
|
|
}
|
|
}];
|
|
return routerFeature(2, providers);
|
|
}
|
|
function withDisabledInitialNavigation() {
|
|
const providers = [{
|
|
provide: APP_INITIALIZER,
|
|
multi: true,
|
|
useFactory: () => {
|
|
const router = inject(Router);
|
|
return () => {
|
|
router.setUpLocationChangeListener();
|
|
};
|
|
}
|
|
}, {
|
|
provide: INITIAL_NAVIGATION,
|
|
useValue: 2
|
|
/* InitialNavigation.Disabled */
|
|
}];
|
|
return routerFeature(3, providers);
|
|
}
|
|
function withDebugTracing() {
|
|
let providers = [];
|
|
if (typeof ngDevMode === "undefined" || ngDevMode) {
|
|
providers = [{
|
|
provide: ENVIRONMENT_INITIALIZER,
|
|
multi: true,
|
|
useFactory: () => {
|
|
const router = inject(Router);
|
|
return () => router.events.subscribe((e) => {
|
|
console.group?.(`Router Event: ${e.constructor.name}`);
|
|
console.log(stringifyEvent(e));
|
|
console.log(e);
|
|
console.groupEnd?.();
|
|
});
|
|
}
|
|
}];
|
|
} else {
|
|
providers = [];
|
|
}
|
|
return routerFeature(1, providers);
|
|
}
|
|
var ROUTER_PRELOADER = new InjectionToken(typeof ngDevMode === "undefined" || ngDevMode ? "router preloader" : "");
|
|
function withPreloading(preloadingStrategy) {
|
|
const providers = [{
|
|
provide: ROUTER_PRELOADER,
|
|
useExisting: RouterPreloader
|
|
}, {
|
|
provide: PreloadingStrategy,
|
|
useExisting: preloadingStrategy
|
|
}];
|
|
return routerFeature(0, providers);
|
|
}
|
|
function withRouterConfig(options) {
|
|
const providers = [{
|
|
provide: ROUTER_CONFIGURATION,
|
|
useValue: options
|
|
}];
|
|
return routerFeature(5, providers);
|
|
}
|
|
function withHashLocation() {
|
|
const providers = [{
|
|
provide: LocationStrategy,
|
|
useClass: HashLocationStrategy
|
|
}];
|
|
return routerFeature(6, providers);
|
|
}
|
|
function withNavigationErrorHandler(fn) {
|
|
const providers = [{
|
|
provide: ENVIRONMENT_INITIALIZER,
|
|
multi: true,
|
|
useValue: () => {
|
|
const injector = inject(EnvironmentInjector);
|
|
inject(Router).events.subscribe((e) => {
|
|
if (e instanceof NavigationError) {
|
|
runInInjectionContext(injector, () => fn(e));
|
|
}
|
|
});
|
|
}
|
|
}];
|
|
return routerFeature(7, providers);
|
|
}
|
|
function withComponentInputBinding() {
|
|
const providers = [RoutedComponentInputBinder, {
|
|
provide: INPUT_BINDER,
|
|
useExisting: RoutedComponentInputBinder
|
|
}];
|
|
return routerFeature(8, providers);
|
|
}
|
|
function withViewTransitions(options) {
|
|
const providers = [{
|
|
provide: CREATE_VIEW_TRANSITION,
|
|
useValue: createViewTransition
|
|
}, {
|
|
provide: VIEW_TRANSITION_OPTIONS,
|
|
useValue: __spreadValues({
|
|
skipNextTransition: !!options?.skipInitialTransition
|
|
}, options)
|
|
}];
|
|
return routerFeature(9, providers);
|
|
}
|
|
var ROUTER_DIRECTIVES = [RouterOutlet, RouterLink, RouterLinkActive, ɵEmptyOutletComponent];
|
|
var ROUTER_FORROOT_GUARD = new InjectionToken(typeof ngDevMode === "undefined" || ngDevMode ? "router duplicate forRoot guard" : "ROUTER_FORROOT_GUARD");
|
|
var ROUTER_PROVIDERS = [
|
|
Location,
|
|
{
|
|
provide: UrlSerializer,
|
|
useClass: DefaultUrlSerializer
|
|
},
|
|
Router,
|
|
ChildrenOutletContexts,
|
|
{
|
|
provide: ActivatedRoute,
|
|
useFactory: rootRoute,
|
|
deps: [Router]
|
|
},
|
|
RouterConfigLoader,
|
|
// Only used to warn when `provideRoutes` is used without `RouterModule` or `provideRouter`. Can
|
|
// be removed when `provideRoutes` is removed.
|
|
typeof ngDevMode === "undefined" || ngDevMode ? {
|
|
provide: ROUTER_IS_PROVIDED,
|
|
useValue: true
|
|
} : []
|
|
];
|
|
var _RouterModule = class _RouterModule {
|
|
constructor(guard) {
|
|
}
|
|
/**
|
|
* Creates and configures a module with all the router providers and directives.
|
|
* Optionally sets up an application listener to perform an initial navigation.
|
|
*
|
|
* When registering the NgModule at the root, import as follows:
|
|
*
|
|
* ```
|
|
* @NgModule({
|
|
* imports: [RouterModule.forRoot(ROUTES)]
|
|
* })
|
|
* class MyNgModule {}
|
|
* ```
|
|
*
|
|
* @param routes An array of `Route` objects that define the navigation paths for the application.
|
|
* @param config An `ExtraOptions` configuration object that controls how navigation is performed.
|
|
* @return The new `NgModule`.
|
|
*
|
|
*/
|
|
static forRoot(routes, config) {
|
|
return {
|
|
ngModule: _RouterModule,
|
|
providers: [ROUTER_PROVIDERS, typeof ngDevMode === "undefined" || ngDevMode ? config?.enableTracing ? withDebugTracing().ɵproviders : [] : [], {
|
|
provide: ROUTES,
|
|
multi: true,
|
|
useValue: routes
|
|
}, {
|
|
provide: ROUTER_FORROOT_GUARD,
|
|
useFactory: provideForRootGuard,
|
|
deps: [[Router, new Optional(), new SkipSelf()]]
|
|
}, {
|
|
provide: ROUTER_CONFIGURATION,
|
|
useValue: config ? config : {}
|
|
}, config?.useHash ? provideHashLocationStrategy() : providePathLocationStrategy(), provideRouterScroller(), config?.preloadingStrategy ? withPreloading(config.preloadingStrategy).ɵproviders : [], config?.initialNavigation ? provideInitialNavigation(config) : [], config?.bindToComponentInputs ? withComponentInputBinding().ɵproviders : [], config?.enableViewTransitions ? withViewTransitions().ɵproviders : [], provideRouterInitializer()]
|
|
};
|
|
}
|
|
/**
|
|
* Creates a module with all the router directives and a provider registering routes,
|
|
* without creating a new Router service.
|
|
* When registering for submodules and lazy-loaded submodules, create the NgModule as follows:
|
|
*
|
|
* ```
|
|
* @NgModule({
|
|
* imports: [RouterModule.forChild(ROUTES)]
|
|
* })
|
|
* class MyNgModule {}
|
|
* ```
|
|
*
|
|
* @param routes An array of `Route` objects that define the navigation paths for the submodule.
|
|
* @return The new NgModule.
|
|
*
|
|
*/
|
|
static forChild(routes) {
|
|
return {
|
|
ngModule: _RouterModule,
|
|
providers: [{
|
|
provide: ROUTES,
|
|
multi: true,
|
|
useValue: routes
|
|
}]
|
|
};
|
|
}
|
|
};
|
|
_RouterModule.ɵfac = function RouterModule_Factory(t) {
|
|
return new (t || _RouterModule)(ɵɵinject(ROUTER_FORROOT_GUARD, 8));
|
|
};
|
|
_RouterModule.ɵmod = ɵɵdefineNgModule({
|
|
type: _RouterModule,
|
|
imports: [RouterOutlet, RouterLink, RouterLinkActive, ɵEmptyOutletComponent],
|
|
exports: [RouterOutlet, RouterLink, RouterLinkActive, ɵEmptyOutletComponent]
|
|
});
|
|
_RouterModule.ɵinj = ɵɵdefineInjector({});
|
|
var RouterModule = _RouterModule;
|
|
(() => {
|
|
(typeof ngDevMode === "undefined" || ngDevMode) && setClassMetadata(RouterModule, [{
|
|
type: NgModule,
|
|
args: [{
|
|
imports: ROUTER_DIRECTIVES,
|
|
exports: ROUTER_DIRECTIVES
|
|
}]
|
|
}], () => [{
|
|
type: void 0,
|
|
decorators: [{
|
|
type: Optional
|
|
}, {
|
|
type: Inject,
|
|
args: [ROUTER_FORROOT_GUARD]
|
|
}]
|
|
}], null);
|
|
})();
|
|
function provideRouterScroller() {
|
|
return {
|
|
provide: ROUTER_SCROLLER,
|
|
useFactory: () => {
|
|
const viewportScroller = inject(ViewportScroller);
|
|
const zone = inject(NgZone);
|
|
const config = inject(ROUTER_CONFIGURATION);
|
|
const transitions = inject(NavigationTransitions);
|
|
const urlSerializer = inject(UrlSerializer);
|
|
if (config.scrollOffset) {
|
|
viewportScroller.setOffset(config.scrollOffset);
|
|
}
|
|
return new RouterScroller(urlSerializer, transitions, viewportScroller, zone, config);
|
|
}
|
|
};
|
|
}
|
|
function provideHashLocationStrategy() {
|
|
return {
|
|
provide: LocationStrategy,
|
|
useClass: HashLocationStrategy
|
|
};
|
|
}
|
|
function providePathLocationStrategy() {
|
|
return {
|
|
provide: LocationStrategy,
|
|
useClass: PathLocationStrategy
|
|
};
|
|
}
|
|
function provideForRootGuard(router) {
|
|
if ((typeof ngDevMode === "undefined" || ngDevMode) && router) {
|
|
throw new RuntimeError(4007, `The Router was provided more than once. This can happen if 'forRoot' is used outside of the root injector. Lazy loaded modules should use RouterModule.forChild() instead.`);
|
|
}
|
|
return "guarded";
|
|
}
|
|
function provideInitialNavigation(config) {
|
|
return [config.initialNavigation === "disabled" ? withDisabledInitialNavigation().ɵproviders : [], config.initialNavigation === "enabledBlocking" ? withEnabledBlockingInitialNavigation().ɵproviders : []];
|
|
}
|
|
var ROUTER_INITIALIZER = new InjectionToken(typeof ngDevMode === "undefined" || ngDevMode ? "Router Initializer" : "");
|
|
function provideRouterInitializer() {
|
|
return [
|
|
// ROUTER_INITIALIZER token should be removed. It's public API but shouldn't be. We can just
|
|
// have `getBootstrapListener` directly attached to APP_BOOTSTRAP_LISTENER.
|
|
{
|
|
provide: ROUTER_INITIALIZER,
|
|
useFactory: getBootstrapListener
|
|
},
|
|
{
|
|
provide: APP_BOOTSTRAP_LISTENER,
|
|
multi: true,
|
|
useExisting: ROUTER_INITIALIZER
|
|
}
|
|
];
|
|
}
|
|
function mapToCanMatch(providers) {
|
|
return providers.map((provider) => (...params) => inject(provider).canMatch(...params));
|
|
}
|
|
function mapToCanActivate(providers) {
|
|
return providers.map((provider) => (...params) => inject(provider).canActivate(...params));
|
|
}
|
|
function mapToCanActivateChild(providers) {
|
|
return providers.map((provider) => (...params) => inject(provider).canActivateChild(...params));
|
|
}
|
|
function mapToCanDeactivate(providers) {
|
|
return providers.map((provider) => (...params) => inject(provider).canDeactivate(...params));
|
|
}
|
|
function mapToResolve(provider) {
|
|
return (...params) => inject(provider).resolve(...params);
|
|
}
|
|
var VERSION = new Version("17.0.7");
|
|
export {
|
|
ActivatedRoute,
|
|
ActivatedRouteSnapshot,
|
|
ActivationEnd,
|
|
ActivationStart,
|
|
BaseRouteReuseStrategy,
|
|
ChildActivationEnd,
|
|
ChildActivationStart,
|
|
ChildrenOutletContexts,
|
|
DefaultTitleStrategy,
|
|
DefaultUrlSerializer,
|
|
GuardsCheckEnd,
|
|
GuardsCheckStart,
|
|
NavigationCancel,
|
|
NavigationEnd,
|
|
NavigationError,
|
|
NavigationSkipped,
|
|
NavigationStart,
|
|
NoPreloading,
|
|
OutletContext,
|
|
PRIMARY_OUTLET,
|
|
PreloadAllModules,
|
|
PreloadingStrategy,
|
|
ROUTER_CONFIGURATION,
|
|
ROUTER_INITIALIZER,
|
|
ROUTES,
|
|
ResolveEnd,
|
|
ResolveStart,
|
|
RouteConfigLoadEnd,
|
|
RouteConfigLoadStart,
|
|
RouteReuseStrategy,
|
|
Router,
|
|
RouterEvent,
|
|
RouterLink,
|
|
RouterLinkActive,
|
|
RouterLink as RouterLinkWithHref,
|
|
RouterModule,
|
|
RouterOutlet,
|
|
RouterPreloader,
|
|
RouterState,
|
|
RouterStateSnapshot,
|
|
RoutesRecognized,
|
|
Scroll,
|
|
TitleStrategy,
|
|
UrlHandlingStrategy,
|
|
UrlSegment,
|
|
UrlSegmentGroup,
|
|
UrlSerializer,
|
|
UrlTree,
|
|
VERSION,
|
|
convertToParamMap,
|
|
createUrlTreeFromSnapshot,
|
|
defaultUrlMatcher,
|
|
mapToCanActivate,
|
|
mapToCanActivateChild,
|
|
mapToCanDeactivate,
|
|
mapToCanMatch,
|
|
mapToResolve,
|
|
provideRouter,
|
|
provideRoutes,
|
|
withComponentInputBinding,
|
|
withDebugTracing,
|
|
withDisabledInitialNavigation,
|
|
withEnabledBlockingInitialNavigation,
|
|
withHashLocation,
|
|
withInMemoryScrolling,
|
|
withNavigationErrorHandler,
|
|
withPreloading,
|
|
withRouterConfig,
|
|
withViewTransitions,
|
|
ɵEmptyOutletComponent,
|
|
ROUTER_PROVIDERS as ɵROUTER_PROVIDERS,
|
|
afterNextNavigation as ɵafterNextNavigation,
|
|
loadChildren as ɵloadChildren
|
|
};
|
|
/*! Bundled license information:
|
|
|
|
@angular/router/fesm2022/router.mjs:
|
|
(**
|
|
* @license Angular v17.0.7
|
|
* (c) 2010-2022 Google LLC. https://angular.io/
|
|
* License: MIT
|
|
*)
|
|
*/
|
|
//# sourceMappingURL=@angular_router.js.map
|
|
|