refactor(router): misc refactoring (#13330)
This commit is contained in:
@ -9,8 +9,6 @@
|
|||||||
import {Injector, THROW_IF_NOT_FOUND} from '../di/injector';
|
import {Injector, THROW_IF_NOT_FOUND} from '../di/injector';
|
||||||
import {AppView} from './view';
|
import {AppView} from './view';
|
||||||
|
|
||||||
const _UNDEFINED = new Object();
|
|
||||||
|
|
||||||
export class ElementInjector extends Injector {
|
export class ElementInjector extends Injector {
|
||||||
constructor(private _view: AppView<any>, private _nodeIndex: number) { super(); }
|
constructor(private _view: AppView<any>, private _nodeIndex: number) { super(); }
|
||||||
|
|
||||||
|
@ -9,7 +9,6 @@
|
|||||||
import {ApplicationRef} from '../application_ref';
|
import {ApplicationRef} from '../application_ref';
|
||||||
import {ChangeDetectorRef, ChangeDetectorStatus} from '../change_detection/change_detection';
|
import {ChangeDetectorRef, ChangeDetectorStatus} from '../change_detection/change_detection';
|
||||||
import {Injector, THROW_IF_NOT_FOUND} from '../di/injector';
|
import {Injector, THROW_IF_NOT_FOUND} from '../di/injector';
|
||||||
import {ListWrapper} from '../facade/collection';
|
|
||||||
import {isPresent} from '../facade/lang';
|
import {isPresent} from '../facade/lang';
|
||||||
import {WtfScopeFn, wtfCreateScope, wtfLeave} from '../profile/profile';
|
import {WtfScopeFn, wtfCreateScope, wtfLeave} from '../profile/profile';
|
||||||
import {DirectRenderer, RenderComponentType, RenderDebugInfo, Renderer} from '../render/api';
|
import {DirectRenderer, RenderComponentType, RenderDebugInfo, Renderer} from '../render/api';
|
||||||
|
@ -18,7 +18,7 @@ import {map} from 'rxjs/operator/map';
|
|||||||
import {mergeMap} from 'rxjs/operator/mergeMap';
|
import {mergeMap} from 'rxjs/operator/mergeMap';
|
||||||
import {EmptyError} from 'rxjs/util/EmptyError';
|
import {EmptyError} from 'rxjs/util/EmptyError';
|
||||||
|
|
||||||
import {Route, Routes, UrlMatchResult} from './config';
|
import {Route, Routes} from './config';
|
||||||
import {LoadedRouterConfig, RouterConfigLoader} from './router_config_loader';
|
import {LoadedRouterConfig, RouterConfigLoader} from './router_config_loader';
|
||||||
import {NavigationCancelingError, PRIMARY_OUTLET, Params, defaultUrlMatcher} from './shared';
|
import {NavigationCancelingError, PRIMARY_OUTLET, Params, defaultUrlMatcher} from './shared';
|
||||||
import {UrlSegment, UrlSegmentGroup, UrlSerializer, UrlTree} from './url_tree';
|
import {UrlSegment, UrlSegmentGroup, UrlSerializer, UrlTree} from './url_tree';
|
||||||
@ -54,7 +54,6 @@ function canLoadFails(route: Route): Observable<LoadedRouterConfig> {
|
|||||||
`Cannot load children because the guard of the route "path: '${route.path}'" returned false`)));
|
`Cannot load children because the guard of the route "path: '${route.path}'" returned false`)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export function applyRedirects(
|
export function applyRedirects(
|
||||||
injector: Injector, configLoader: RouterConfigLoader, urlSerializer: UrlSerializer,
|
injector: Injector, configLoader: RouterConfigLoader, urlSerializer: UrlSerializer,
|
||||||
urlTree: UrlTree, config: Routes): Observable<UrlTree> {
|
urlTree: UrlTree, config: Routes): Observable<UrlTree> {
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
import {ActivatedRoute} from './router_state';
|
import {ActivatedRoute} from './router_state';
|
||||||
import {PRIMARY_OUTLET, Params} from './shared';
|
import {PRIMARY_OUTLET, Params} from './shared';
|
||||||
import {UrlSegment, UrlSegmentGroup, UrlTree} from './url_tree';
|
import {UrlSegment, UrlSegmentGroup, UrlTree} from './url_tree';
|
||||||
import {forEach, shallowEqual} from './utils/collection';
|
import {forEach, shallowEqual, last} from './utils/collection';
|
||||||
|
|
||||||
export function createUrlTree(
|
export function createUrlTree(
|
||||||
route: ActivatedRoute, urlTree: UrlTree, commands: any[], queryParams: Params,
|
route: ActivatedRoute, urlTree: UrlTree, commands: any[], queryParams: Params,
|
||||||
@ -18,36 +18,24 @@ export function createUrlTree(
|
|||||||
return tree(urlTree.root, urlTree.root, urlTree, queryParams, fragment);
|
return tree(urlTree.root, urlTree.root, urlTree, queryParams, fragment);
|
||||||
}
|
}
|
||||||
|
|
||||||
const normalizedCommands = normalizeCommands(commands);
|
const nav = computeNavigation(commands);
|
||||||
validateCommands(normalizedCommands);
|
|
||||||
|
|
||||||
if (navigateToRoot(normalizedCommands)) {
|
if (nav.toRoot()) {
|
||||||
return tree(urlTree.root, new UrlSegmentGroup([], {}), urlTree, queryParams, fragment);
|
return tree(urlTree.root, new UrlSegmentGroup([], {}), urlTree, queryParams, fragment);
|
||||||
}
|
}
|
||||||
|
|
||||||
const startingPosition = findStartingPosition(normalizedCommands, urlTree, route);
|
const startingPosition = findStartingPosition(nav, urlTree, route);
|
||||||
|
|
||||||
const segmentGroup = startingPosition.processChildren ?
|
const segmentGroup = startingPosition.processChildren ?
|
||||||
updateSegmentGroupChildren(
|
updateSegmentGroupChildren(
|
||||||
startingPosition.segmentGroup, startingPosition.index, normalizedCommands.commands) :
|
startingPosition.segmentGroup, startingPosition.index, nav.commands) :
|
||||||
updateSegmentGroup(
|
updateSegmentGroup(
|
||||||
startingPosition.segmentGroup, startingPosition.index, normalizedCommands.commands);
|
startingPosition.segmentGroup, startingPosition.index, nav.commands);
|
||||||
return tree(startingPosition.segmentGroup, segmentGroup, urlTree, queryParams, fragment);
|
return tree(startingPosition.segmentGroup, segmentGroup, urlTree, queryParams, fragment);
|
||||||
}
|
}
|
||||||
|
|
||||||
function validateCommands(n: NormalizedNavigationCommands): void {
|
|
||||||
if (n.isAbsolute && n.commands.length > 0 && isMatrixParams(n.commands[0])) {
|
|
||||||
throw new Error('Root segment cannot have matrix parameters');
|
|
||||||
}
|
|
||||||
|
|
||||||
const c = n.commands.filter(c => typeof c === 'object' && c.outlets !== undefined);
|
|
||||||
if (c.length > 0 && c[0] !== n.commands[n.commands.length - 1]) {
|
|
||||||
throw new Error('{outlets:{}} has to be the last command');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function isMatrixParams(command: any): boolean {
|
function isMatrixParams(command: any): boolean {
|
||||||
return typeof command === 'object' && command.outlets === undefined &&
|
return typeof command === 'object' && !command.outlets && !command.segmentPath;
|
||||||
command.segmentPath === undefined;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function tree(
|
function tree(
|
||||||
@ -55,11 +43,11 @@ function tree(
|
|||||||
queryParams: Params, fragment: string): UrlTree {
|
queryParams: Params, fragment: string): UrlTree {
|
||||||
if (urlTree.root === oldSegmentGroup) {
|
if (urlTree.root === oldSegmentGroup) {
|
||||||
return new UrlTree(newSegmentGroup, stringify(queryParams), fragment);
|
return new UrlTree(newSegmentGroup, stringify(queryParams), fragment);
|
||||||
} else {
|
|
||||||
return new UrlTree(
|
|
||||||
replaceSegment(urlTree.root, oldSegmentGroup, newSegmentGroup), stringify(queryParams),
|
|
||||||
fragment);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return new UrlTree(
|
||||||
|
replaceSegment(urlTree.root, oldSegmentGroup, newSegmentGroup), stringify(queryParams),
|
||||||
|
fragment);
|
||||||
}
|
}
|
||||||
|
|
||||||
function replaceSegment(
|
function replaceSegment(
|
||||||
@ -76,72 +64,71 @@ function replaceSegment(
|
|||||||
return new UrlSegmentGroup(current.segments, children);
|
return new UrlSegmentGroup(current.segments, children);
|
||||||
}
|
}
|
||||||
|
|
||||||
function navigateToRoot(normalizedChange: NormalizedNavigationCommands): boolean {
|
class Navigation {
|
||||||
return normalizedChange.isAbsolute && normalizedChange.commands.length === 1 &&
|
constructor(public isAbsolute: boolean, public numberOfDoubleDots: number, public commands: any[]) {
|
||||||
normalizedChange.commands[0] == '/';
|
if (isAbsolute && commands.length > 0 && isMatrixParams(commands[0])) {
|
||||||
|
throw new Error('Root segment cannot have matrix parameters');
|
||||||
|
}
|
||||||
|
|
||||||
|
const cmdWithOutlet = commands.find(c => typeof c === 'object' && c.outlets);
|
||||||
|
if (cmdWithOutlet && cmdWithOutlet !== last(commands)) {
|
||||||
|
throw new Error('{outlets:{}} has to be the last command');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public toRoot(): boolean {
|
||||||
|
return this.isAbsolute && this.commands.length === 1 && this.commands[0] == '/';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class NormalizedNavigationCommands {
|
/** Transforms commands to a normalized `Navigation` */
|
||||||
constructor(
|
function computeNavigation(commands: any[]): Navigation {
|
||||||
public isAbsolute: boolean, public numberOfDoubleDots: number, public commands: any[]) {}
|
if ((typeof commands[0] === 'string') && commands.length === 1 && commands[0] === '/') {
|
||||||
}
|
return new Navigation(true, 0, commands);
|
||||||
|
|
||||||
function normalizeCommands(commands: any[]): NormalizedNavigationCommands {
|
|
||||||
if ((typeof commands[0] === 'string') && commands.length === 1 && commands[0] == '/') {
|
|
||||||
return new NormalizedNavigationCommands(true, 0, commands);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let numberOfDoubleDots = 0;
|
let numberOfDoubleDots = 0;
|
||||||
let isAbsolute = false;
|
let isAbsolute = false;
|
||||||
const res: any[] = [];
|
|
||||||
|
|
||||||
for (let i = 0; i < commands.length; ++i) {
|
const res: any[] = commands.reduce((res, cmd, cmdIdx) => {
|
||||||
const c = commands[i];
|
if (typeof cmd === 'object') {
|
||||||
|
if (cmd.outlets) {
|
||||||
|
const outlets: {[k: string]: any} = {};
|
||||||
|
forEach(cmd.outlets, (commands: any, name: string) => {
|
||||||
|
outlets[name] = typeof commands === 'string' ? commands.split('/') : commands;
|
||||||
|
});
|
||||||
|
return [...res, {outlets}];
|
||||||
|
}
|
||||||
|
|
||||||
if (typeof c === 'object' && c.outlets !== undefined) {
|
if (cmd.segmentPath) {
|
||||||
const r: {[k: string]: any} = {};
|
return [...res, cmd.segmentPath];
|
||||||
forEach(c.outlets, (commands: any, name: string) => {
|
}
|
||||||
if (typeof commands === 'string') {
|
}
|
||||||
r[name] = commands.split('/');
|
|
||||||
} else {
|
if (!(typeof cmd === 'string')) {
|
||||||
r[name] = commands;
|
return [...res, cmd];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cmdIdx === 0) {
|
||||||
|
cmd.split('/').forEach((urlPart, partIndex) => {
|
||||||
|
if (partIndex == 0 && urlPart === '.') {
|
||||||
|
// skip './a'
|
||||||
|
} else if (partIndex == 0 && urlPart === '') { // '/a'
|
||||||
|
isAbsolute = true;
|
||||||
|
} else if (urlPart === '..') { // '../a'
|
||||||
|
numberOfDoubleDots++;
|
||||||
|
} else if (urlPart != '') {
|
||||||
|
res.push(urlPart);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
res.push({outlets: r});
|
|
||||||
continue;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeof c === 'object' && c.segmentPath !== undefined) {
|
return [...res, cmd];
|
||||||
res.push(c.segmentPath);
|
}, []);
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!(typeof c === 'string')) {
|
return new Navigation(isAbsolute, numberOfDoubleDots, res);
|
||||||
res.push(c);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (i === 0) {
|
|
||||||
const parts = c.split('/');
|
|
||||||
for (let j = 0; j < parts.length; ++j) {
|
|
||||||
const cc = parts[j];
|
|
||||||
|
|
||||||
if (j == 0 && cc == '.') { // './a'
|
|
||||||
// skip it
|
|
||||||
} else if (j == 0 && cc == '') { // '/a'
|
|
||||||
isAbsolute = true;
|
|
||||||
} else if (cc == '..') { // '../a'
|
|
||||||
numberOfDoubleDots++;
|
|
||||||
} else if (cc != '') {
|
|
||||||
res.push(cc);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
res.push(c);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return new NormalizedNavigationCommands(isAbsolute, numberOfDoubleDots, res);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class Position {
|
class Position {
|
||||||
@ -150,19 +137,19 @@ class Position {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function findStartingPosition(
|
function findStartingPosition(nav: Navigation, tree: UrlTree, route: ActivatedRoute): Position {
|
||||||
normalizedChange: NormalizedNavigationCommands, urlTree: UrlTree,
|
if (nav.isAbsolute) {
|
||||||
route: ActivatedRoute): Position {
|
return new Position(tree.root, true, 0);
|
||||||
if (normalizedChange.isAbsolute) {
|
|
||||||
return new Position(urlTree.root, true, 0);
|
|
||||||
} else if (route.snapshot._lastPathIndex === -1) {
|
|
||||||
return new Position(route.snapshot._urlSegment, true, 0);
|
|
||||||
} else {
|
|
||||||
const modifier = isMatrixParams(normalizedChange.commands[0]) ? 0 : 1;
|
|
||||||
const index = route.snapshot._lastPathIndex + modifier;
|
|
||||||
return createPositionApplyingDoubleDots(
|
|
||||||
route.snapshot._urlSegment, index, normalizedChange.numberOfDoubleDots);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (route.snapshot._lastPathIndex === -1) {
|
||||||
|
return new Position(route.snapshot._urlSegment, true, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
const modifier = isMatrixParams(nav.commands[0]) ? 0 : 1;
|
||||||
|
const index = route.snapshot._lastPathIndex + modifier;
|
||||||
|
return createPositionApplyingDoubleDots(route.snapshot._urlSegment, index, nav.numberOfDoubleDots);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function createPositionApplyingDoubleDots(
|
function createPositionApplyingDoubleDots(
|
||||||
@ -276,7 +263,7 @@ function createNewSegmentGroup(
|
|||||||
let i = 0;
|
let i = 0;
|
||||||
while (i < commands.length) {
|
while (i < commands.length) {
|
||||||
if (typeof commands[i] === 'object' && commands[i].outlets !== undefined) {
|
if (typeof commands[i] === 'object' && commands[i].outlets !== undefined) {
|
||||||
const children = createNewSegmentChldren(commands[i].outlets);
|
const children = createNewSegmentChildren(commands[i].outlets);
|
||||||
return new UrlSegmentGroup(paths, children);
|
return new UrlSegmentGroup(paths, children);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -301,7 +288,7 @@ function createNewSegmentGroup(
|
|||||||
return new UrlSegmentGroup(paths, {});
|
return new UrlSegmentGroup(paths, {});
|
||||||
}
|
}
|
||||||
|
|
||||||
function createNewSegmentChldren(outlets: {[name: string]: any}): any {
|
function createNewSegmentChildren(outlets: {[name: string]: any}): any {
|
||||||
const children: {[key: string]: UrlSegmentGroup} = {};
|
const children: {[key: string]: UrlSegmentGroup} = {};
|
||||||
forEach(outlets, (commands: any, outlet: string) => {
|
forEach(outlets, (commands: any, outlet: string) => {
|
||||||
if (commands !== null) {
|
if (commands !== null) {
|
||||||
|
@ -12,9 +12,12 @@ import {ROUTES} from './router_config_loader';
|
|||||||
import {ROUTER_PROVIDERS} from './router_module';
|
import {ROUTER_PROVIDERS} from './router_module';
|
||||||
import {flatten} from './utils/collection';
|
import {flatten} from './utils/collection';
|
||||||
|
|
||||||
export var __router_private__:
|
export const __router_private__: {
|
||||||
{ROUTER_PROVIDERS: typeof ROUTER_PROVIDERS; ROUTES: typeof ROUTES; flatten: typeof flatten;} = {
|
ROUTER_PROVIDERS: typeof ROUTER_PROVIDERS,
|
||||||
ROUTER_PROVIDERS: ROUTER_PROVIDERS,
|
ROUTES: typeof ROUTES,
|
||||||
ROUTES: ROUTES,
|
flatten: typeof flatten,
|
||||||
flatten: flatten
|
} = {
|
||||||
};
|
ROUTER_PROVIDERS: ROUTER_PROVIDERS,
|
||||||
|
ROUTES: ROUTES,
|
||||||
|
flatten: flatten,
|
||||||
|
};
|
||||||
|
@ -7,4 +7,4 @@
|
|||||||
*/
|
*/
|
||||||
import {__platform_browser_private__ as r} from '@angular/platform-browser';
|
import {__platform_browser_private__ as r} from '@angular/platform-browser';
|
||||||
|
|
||||||
export var getDOM: typeof r.getDOM = r.getDOM;
|
export const getDOM: typeof r.getDOM = r.getDOM;
|
||||||
|
@ -11,9 +11,9 @@ import {Observable} from 'rxjs/Observable';
|
|||||||
import {Observer} from 'rxjs/Observer';
|
import {Observer} from 'rxjs/Observer';
|
||||||
import {of } from 'rxjs/observable/of';
|
import {of } from 'rxjs/observable/of';
|
||||||
|
|
||||||
import {Data, ResolveData, Route, Routes, UrlMatchResult} from './config';
|
import {Data, ResolveData, Route, Routes} from './config';
|
||||||
import {ActivatedRouteSnapshot, RouterStateSnapshot, inheritedParamsDataResolve} from './router_state';
|
import {ActivatedRouteSnapshot, RouterStateSnapshot, inheritedParamsDataResolve} from './router_state';
|
||||||
import {PRIMARY_OUTLET, Params, defaultUrlMatcher} from './shared';
|
import {PRIMARY_OUTLET, defaultUrlMatcher} from './shared';
|
||||||
import {UrlSegment, UrlSegmentGroup, UrlTree, mapChildrenIntoArray} from './url_tree';
|
import {UrlSegment, UrlSegmentGroup, UrlTree, mapChildrenIntoArray} from './url_tree';
|
||||||
import {forEach, last, merge} from './utils/collection';
|
import {forEach, last, merge} from './utils/collection';
|
||||||
import {TreeNode} from './utils/tree';
|
import {TreeNode} from './utils/tree';
|
||||||
|
@ -11,7 +11,6 @@ import {ComponentRef} from '@angular/core';
|
|||||||
import {ActivatedRoute, ActivatedRouteSnapshot} from './router_state';
|
import {ActivatedRoute, ActivatedRouteSnapshot} from './router_state';
|
||||||
import {TreeNode} from './utils/tree';
|
import {TreeNode} from './utils/tree';
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @whatItDoes Represents the detached route tree.
|
* @whatItDoes Represents the detached route tree.
|
||||||
*
|
*
|
||||||
@ -22,43 +21,30 @@ import {TreeNode} from './utils/tree';
|
|||||||
*/
|
*/
|
||||||
export type DetachedRouteHandle = {};
|
export type DetachedRouteHandle = {};
|
||||||
|
|
||||||
/**
|
/** @internal */
|
||||||
* @internal
|
|
||||||
*/
|
|
||||||
export type DetachedRouteHandleInternal = {
|
export type DetachedRouteHandleInternal = {
|
||||||
componentRef: ComponentRef<any>,
|
componentRef: ComponentRef<any>,
|
||||||
route: TreeNode<ActivatedRoute>
|
route: TreeNode<ActivatedRoute>,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @whatItDoes Provides a way to customize when activated routes get reused.
|
* @whatItDoes Provides a way to customize when activated routes get reused.
|
||||||
*
|
*
|
||||||
* @experimental
|
* @experimental
|
||||||
*/
|
*/
|
||||||
export abstract class RouteReuseStrategy {
|
export abstract class RouteReuseStrategy {
|
||||||
/**
|
/** Determines if this route (and its subtree) should be detached to be reused later */
|
||||||
* Determines if this route (and its subtree) should be detached to be reused later.
|
|
||||||
*/
|
|
||||||
abstract shouldDetach(route: ActivatedRouteSnapshot): boolean;
|
abstract shouldDetach(route: ActivatedRouteSnapshot): boolean;
|
||||||
|
|
||||||
/**
|
/** Stores the detached route */
|
||||||
* Stores the detached route.
|
|
||||||
*/
|
|
||||||
abstract store(route: ActivatedRouteSnapshot, handle: DetachedRouteHandle): void;
|
abstract store(route: ActivatedRouteSnapshot, handle: DetachedRouteHandle): void;
|
||||||
|
|
||||||
/**
|
/** Determines if this route (and its subtree) should be reattached */
|
||||||
* Determines if this route (and its subtree) should be reattached.
|
|
||||||
*/
|
|
||||||
abstract shouldAttach(route: ActivatedRouteSnapshot): boolean;
|
abstract shouldAttach(route: ActivatedRouteSnapshot): boolean;
|
||||||
|
|
||||||
/**
|
/** Retrieves the previously stored route */
|
||||||
* Retrieves the previously stored route.
|
|
||||||
*/
|
|
||||||
abstract retrieve(route: ActivatedRouteSnapshot): DetachedRouteHandle;
|
abstract retrieve(route: ActivatedRouteSnapshot): DetachedRouteHandle;
|
||||||
|
|
||||||
/**
|
/** Determines if a route should be reused */
|
||||||
* Determines if a route should be reused.
|
|
||||||
*/
|
|
||||||
abstract shouldReuseRoute(future: ActivatedRouteSnapshot, curr: ActivatedRouteSnapshot): boolean;
|
abstract shouldReuseRoute(future: ActivatedRouteSnapshot, curr: ActivatedRouteSnapshot): boolean;
|
||||||
}
|
}
|
@ -13,7 +13,6 @@ import {Observable} from 'rxjs/Observable';
|
|||||||
import {Subject} from 'rxjs/Subject';
|
import {Subject} from 'rxjs/Subject';
|
||||||
import {Subscription} from 'rxjs/Subscription';
|
import {Subscription} from 'rxjs/Subscription';
|
||||||
import {from} from 'rxjs/observable/from';
|
import {from} from 'rxjs/observable/from';
|
||||||
import {fromPromise} from 'rxjs/observable/fromPromise';
|
|
||||||
import {of } from 'rxjs/observable/of';
|
import {of } from 'rxjs/observable/of';
|
||||||
import {concatMap} from 'rxjs/operator/concatMap';
|
import {concatMap} from 'rxjs/operator/concatMap';
|
||||||
import {every} from 'rxjs/operator/every';
|
import {every} from 'rxjs/operator/every';
|
||||||
@ -148,7 +147,6 @@ export class NavigationStart {
|
|||||||
constructor(
|
constructor(
|
||||||
/** @docsNotRequired */
|
/** @docsNotRequired */
|
||||||
public id: number,
|
public id: number,
|
||||||
|
|
||||||
/** @docsNotRequired */
|
/** @docsNotRequired */
|
||||||
public url: string) {}
|
public url: string) {}
|
||||||
|
|
||||||
@ -166,10 +164,8 @@ export class NavigationEnd {
|
|||||||
constructor(
|
constructor(
|
||||||
/** @docsNotRequired */
|
/** @docsNotRequired */
|
||||||
public id: number,
|
public id: number,
|
||||||
|
|
||||||
/** @docsNotRequired */
|
/** @docsNotRequired */
|
||||||
public url: string,
|
public url: string,
|
||||||
|
|
||||||
/** @docsNotRequired */
|
/** @docsNotRequired */
|
||||||
public urlAfterRedirects: string) {}
|
public urlAfterRedirects: string) {}
|
||||||
|
|
||||||
@ -189,10 +185,8 @@ export class NavigationCancel {
|
|||||||
constructor(
|
constructor(
|
||||||
/** @docsNotRequired */
|
/** @docsNotRequired */
|
||||||
public id: number,
|
public id: number,
|
||||||
|
|
||||||
/** @docsNotRequired */
|
/** @docsNotRequired */
|
||||||
public url: string,
|
public url: string,
|
||||||
|
|
||||||
/** @docsNotRequired */
|
/** @docsNotRequired */
|
||||||
public reason: string) {}
|
public reason: string) {}
|
||||||
|
|
||||||
@ -210,10 +204,8 @@ export class NavigationError {
|
|||||||
constructor(
|
constructor(
|
||||||
/** @docsNotRequired */
|
/** @docsNotRequired */
|
||||||
public id: number,
|
public id: number,
|
||||||
|
|
||||||
/** @docsNotRequired */
|
/** @docsNotRequired */
|
||||||
public url: string,
|
public url: string,
|
||||||
|
|
||||||
/** @docsNotRequired */
|
/** @docsNotRequired */
|
||||||
public error: any) {}
|
public error: any) {}
|
||||||
|
|
||||||
@ -233,7 +225,6 @@ export class RoutesRecognized {
|
|||||||
constructor(
|
constructor(
|
||||||
/** @docsNotRequired */
|
/** @docsNotRequired */
|
||||||
public id: number,
|
public id: number,
|
||||||
|
|
||||||
/** @docsNotRequired */
|
/** @docsNotRequired */
|
||||||
public url: string,
|
public url: string,
|
||||||
/** @docsNotRequired */
|
/** @docsNotRequired */
|
||||||
@ -282,7 +273,7 @@ type NavigationParams = {
|
|||||||
resolve: any,
|
resolve: any,
|
||||||
reject: any,
|
reject: any,
|
||||||
promise: Promise<boolean>,
|
promise: Promise<boolean>,
|
||||||
imperative: boolean
|
imperative: boolean,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -312,9 +303,8 @@ export class Router {
|
|||||||
private currentUrlTree: UrlTree;
|
private currentUrlTree: UrlTree;
|
||||||
private rawUrlTree: UrlTree;
|
private rawUrlTree: UrlTree;
|
||||||
|
|
||||||
private navigations: BehaviorSubject<NavigationParams> =
|
private navigations = new BehaviorSubject<NavigationParams>(null);
|
||||||
new BehaviorSubject<NavigationParams>(null);
|
private routerEvents = new Subject<Event>();
|
||||||
private routerEvents: Subject<Event> = new Subject<Event>();
|
|
||||||
|
|
||||||
private currentRouterState: RouterState;
|
private currentRouterState: RouterState;
|
||||||
private locationSubscription: Subscription;
|
private locationSubscription: Subscription;
|
||||||
@ -353,7 +343,6 @@ export class Router {
|
|||||||
this.rawUrlTree = this.currentUrlTree;
|
this.rawUrlTree = this.currentUrlTree;
|
||||||
this.configLoader = new RouterConfigLoader(loader, compiler);
|
this.configLoader = new RouterConfigLoader(loader, compiler);
|
||||||
this.currentRouterState = createEmptyState(this.currentUrlTree, this.rootComponentType);
|
this.currentRouterState = createEmptyState(this.currentUrlTree, this.rootComponentType);
|
||||||
|
|
||||||
this.processNavigations();
|
this.processNavigations();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -403,19 +392,13 @@ export class Router {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** The current route state */
|
||||||
* Returns the current route state.
|
|
||||||
*/
|
|
||||||
get routerState(): RouterState { return this.currentRouterState; }
|
get routerState(): RouterState { return this.currentRouterState; }
|
||||||
|
|
||||||
/**
|
/** The current url */
|
||||||
* Returns the current url.
|
|
||||||
*/
|
|
||||||
get url(): string { return this.serializeUrl(this.currentUrlTree); }
|
get url(): string { return this.serializeUrl(this.currentUrlTree); }
|
||||||
|
|
||||||
/**
|
/** An observable of router events */
|
||||||
* Returns an observable of route events
|
|
||||||
*/
|
|
||||||
get events(): Observable<Event> { return this.routerEvents; }
|
get events(): Observable<Event> { return this.routerEvents; }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -428,7 +411,7 @@ export class Router {
|
|||||||
* { path: 'team/:id', component: TeamCmp, children: [
|
* { path: 'team/:id', component: TeamCmp, children: [
|
||||||
* { path: 'simple', component: SimpleCmp },
|
* { path: 'simple', component: SimpleCmp },
|
||||||
* { path: 'user/:name', component: UserCmp }
|
* { path: 'user/:name', component: UserCmp }
|
||||||
* ] }
|
* ]}
|
||||||
* ]);
|
* ]);
|
||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
@ -437,14 +420,10 @@ export class Router {
|
|||||||
this.config = config;
|
this.config = config;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** @docsNotRequired */
|
||||||
* @docsNotRequired
|
|
||||||
*/
|
|
||||||
ngOnDestroy() { this.dispose(); }
|
ngOnDestroy() { this.dispose(); }
|
||||||
|
|
||||||
/**
|
/** Disposes of the router */
|
||||||
* Disposes of the router.
|
|
||||||
*/
|
|
||||||
dispose(): void {
|
dispose(): void {
|
||||||
if (this.locationSubscription) {
|
if (this.locationSubscription) {
|
||||||
this.locationSubscription.unsubscribe();
|
this.locationSubscription.unsubscribe();
|
||||||
@ -496,7 +475,7 @@ export class Router {
|
|||||||
createUrlTree(
|
createUrlTree(
|
||||||
commands: any[], {relativeTo, queryParams, fragment, preserveQueryParams,
|
commands: any[], {relativeTo, queryParams, fragment, preserveQueryParams,
|
||||||
preserveFragment}: NavigationExtras = {}): UrlTree {
|
preserveFragment}: NavigationExtras = {}): UrlTree {
|
||||||
const a = relativeTo ? relativeTo : this.routerState.root;
|
const a = relativeTo || this.routerState.root;
|
||||||
const q = preserveQueryParams ? this.currentUrlTree.queryParams : queryParams;
|
const q = preserveQueryParams ? this.currentUrlTree.queryParams : queryParams;
|
||||||
const f = preserveFragment ? this.currentUrlTree.fragment : fragment;
|
const f = preserveFragment ? this.currentUrlTree.fragment : fragment;
|
||||||
return createUrlTree(a, this.currentUrlTree, commands, q, f);
|
return createUrlTree(a, this.currentUrlTree, commands, q, f);
|
||||||
@ -506,9 +485,9 @@ export class Router {
|
|||||||
* Navigate based on the provided url. This navigation is always absolute.
|
* Navigate based on the provided url. This navigation is always absolute.
|
||||||
*
|
*
|
||||||
* Returns a promise that:
|
* Returns a promise that:
|
||||||
* - is resolved with 'true' when navigation succeeds
|
* - resolves to 'true' when navigation succeeds,
|
||||||
* - is resolved with 'false' when navigation fails
|
* - resolves to 'false' when navigation fails,
|
||||||
* - is rejected when an error happens
|
* - is rejected when an error happens.
|
||||||
*
|
*
|
||||||
* ### Usage
|
* ### Usage
|
||||||
*
|
*
|
||||||
@ -527,11 +506,11 @@ export class Router {
|
|||||||
if (url instanceof UrlTree) {
|
if (url instanceof UrlTree) {
|
||||||
return this.scheduleNavigation(
|
return this.scheduleNavigation(
|
||||||
this.urlHandlingStrategy.merge(url, this.rawUrlTree), true, extras);
|
this.urlHandlingStrategy.merge(url, this.rawUrlTree), true, extras);
|
||||||
} else {
|
|
||||||
const urlTree = this.urlSerializer.parse(url);
|
|
||||||
return this.scheduleNavigation(
|
|
||||||
this.urlHandlingStrategy.merge(urlTree, this.rawUrlTree), true, extras);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const urlTree = this.urlSerializer.parse(url);
|
||||||
|
return this.scheduleNavigation(
|
||||||
|
this.urlHandlingStrategy.merge(urlTree, this.rawUrlTree), true, extras);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -539,9 +518,9 @@ export class Router {
|
|||||||
* If no starting route is provided, the navigation is absolute.
|
* If no starting route is provided, the navigation is absolute.
|
||||||
*
|
*
|
||||||
* Returns a promise that:
|
* Returns a promise that:
|
||||||
* - is resolved with 'true' when navigation succeeds
|
* - resolves to 'true' when navigation succeeds,
|
||||||
* - is resolved with 'false' when navigation fails
|
* - resolves to 'false' when navigation fails,
|
||||||
* - is rejected when an error happens
|
* - is rejected when an error happens.
|
||||||
*
|
*
|
||||||
* ### Usage
|
* ### Usage
|
||||||
*
|
*
|
||||||
@ -549,11 +528,11 @@ export class Router {
|
|||||||
* router.navigate(['team', 33, 'user', 11], {relativeTo: route});
|
* router.navigate(['team', 33, 'user', 11], {relativeTo: route});
|
||||||
*
|
*
|
||||||
* // Navigate without updating the URL
|
* // Navigate without updating the URL
|
||||||
* router.navigate(['team', 33, 'user', 11], {relativeTo: route, skipLocationChange: true });
|
* router.navigate(['team', 33, 'user', 11], {relativeTo: route, skipLocationChange: true});
|
||||||
* ```
|
* ```
|
||||||
*
|
*
|
||||||
* In opposite to `navigateByUrl`, `navigate` always takes a delta
|
* In opposite to `navigateByUrl`, `navigate` always takes a delta that is applied to the current
|
||||||
* that is applied to the current URL.
|
* URL.
|
||||||
*/
|
*/
|
||||||
navigate(commands: any[], extras: NavigationExtras = {skipLocationChange: false}):
|
navigate(commands: any[], extras: NavigationExtras = {skipLocationChange: false}):
|
||||||
Promise<boolean> {
|
Promise<boolean> {
|
||||||
@ -563,19 +542,13 @@ export class Router {
|
|||||||
return this.navigateByUrl(this.createUrlTree(commands, extras), extras);
|
return this.navigateByUrl(this.createUrlTree(commands, extras), extras);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** Serializes a {@link UrlTree} into a string */
|
||||||
* Serializes a {@link UrlTree} into a string.
|
|
||||||
*/
|
|
||||||
serializeUrl(url: UrlTree): string { return this.urlSerializer.serialize(url); }
|
serializeUrl(url: UrlTree): string { return this.urlSerializer.serialize(url); }
|
||||||
|
|
||||||
/**
|
/** Parses a string into a {@link UrlTree} */
|
||||||
* Parses a string into a {@link UrlTree}.
|
|
||||||
*/
|
|
||||||
parseUrl(url: string): UrlTree { return this.urlSerializer.parse(url); }
|
parseUrl(url: string): UrlTree { return this.urlSerializer.parse(url); }
|
||||||
|
|
||||||
/**
|
/** Returns whether the url is activated */
|
||||||
* Returns if the url is activated or not.
|
|
||||||
*/
|
|
||||||
isActive(url: string|UrlTree, exact: boolean): boolean {
|
isActive(url: string|UrlTree, exact: boolean): boolean {
|
||||||
if (url instanceof UrlTree) {
|
if (url instanceof UrlTree) {
|
||||||
return containsTree(this.currentUrlTree, url, exact);
|
return containsTree(this.currentUrlTree, url, exact);
|
||||||
|
@ -16,7 +16,6 @@ import {UrlSegment, UrlSegmentGroup, UrlTree, equalSegments} from './url_tree';
|
|||||||
import {merge, shallowEqual, shallowEqualArrays} from './utils/collection';
|
import {merge, shallowEqual, shallowEqualArrays} from './utils/collection';
|
||||||
import {Tree, TreeNode} from './utils/tree';
|
import {Tree, TreeNode} from './utils/tree';
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @whatItDoes Represents the state of the router.
|
* @whatItDoes Represents the state of the router.
|
||||||
*
|
*
|
||||||
@ -45,14 +44,10 @@ import {Tree, TreeNode} from './utils/tree';
|
|||||||
* @stable
|
* @stable
|
||||||
*/
|
*/
|
||||||
export class RouterState extends Tree<ActivatedRoute> {
|
export class RouterState extends Tree<ActivatedRoute> {
|
||||||
/**
|
/** @internal */
|
||||||
* @internal
|
|
||||||
*/
|
|
||||||
constructor(
|
constructor(
|
||||||
root: TreeNode<ActivatedRoute>,
|
root: TreeNode<ActivatedRoute>,
|
||||||
/**
|
/** The current snapshot of the router state */
|
||||||
* The current snapshot of the router state.
|
|
||||||
*/
|
|
||||||
public snapshot: RouterStateSnapshot) {
|
public snapshot: RouterStateSnapshot) {
|
||||||
super(root);
|
super(root);
|
||||||
setRouterStateSnapshot<RouterState, ActivatedRoute>(this, root);
|
setRouterStateSnapshot<RouterState, ActivatedRoute>(this, root);
|
||||||
@ -90,17 +85,18 @@ export function createEmptyStateSnapshot(
|
|||||||
/**
|
/**
|
||||||
* @whatItDoes Contains the information about a route associated with a component loaded in an
|
* @whatItDoes Contains the information about a route associated with a component loaded in an
|
||||||
* outlet.
|
* outlet.
|
||||||
* ActivatedRoute can also be used to traverse the router state tree.
|
* An `ActivatedRoute` can also be used to traverse the router state tree.
|
||||||
*
|
*
|
||||||
* @howToUse
|
* @howToUse
|
||||||
*
|
*
|
||||||
* ```
|
* ```
|
||||||
* @Component({templateUrl:'./my-component.html'})
|
* @Component({...})
|
||||||
* class MyComponent {
|
* class MyComponent {
|
||||||
* constructor(route: ActivatedRoute) {
|
* constructor(route: ActivatedRoute) {
|
||||||
* const id: Observable<string> = route.params.map(p => p.id);
|
* const id: Observable<string> = route.params.map(p => p.id);
|
||||||
* const url: Observable<string> = route.url.map(s => s.join(''));
|
* const url: Observable<string> = route.url.map(segments => segments.join(''));
|
||||||
* const user = route.data.map(d => d.user); //includes `data` and `resolve`
|
* // route.data includes both `data` and `resolve`
|
||||||
|
* const user = route.data.map(d => d.user);
|
||||||
* }
|
* }
|
||||||
* }
|
* }
|
||||||
* ```
|
* ```
|
||||||
@ -108,112 +104,64 @@ export function createEmptyStateSnapshot(
|
|||||||
* @stable
|
* @stable
|
||||||
*/
|
*/
|
||||||
export class ActivatedRoute {
|
export class ActivatedRoute {
|
||||||
|
/** The current snapshot of this route */
|
||||||
|
snapshot: ActivatedRouteSnapshot;
|
||||||
/** @internal */
|
/** @internal */
|
||||||
_futureSnapshot: ActivatedRouteSnapshot;
|
_futureSnapshot: ActivatedRouteSnapshot;
|
||||||
|
|
||||||
/**
|
|
||||||
* The current snapshot of this route.
|
|
||||||
*/
|
|
||||||
snapshot: ActivatedRouteSnapshot;
|
|
||||||
|
|
||||||
/** @internal */
|
/** @internal */
|
||||||
_routerState: RouterState;
|
_routerState: RouterState;
|
||||||
|
|
||||||
/**
|
/** @internal */
|
||||||
* @internal
|
|
||||||
*/
|
|
||||||
constructor(
|
constructor(
|
||||||
/**
|
/** An observable of the URL segments matched by this route */
|
||||||
* The URL segments matched by this route. The observable will emit a new value when
|
|
||||||
* the array of segments changes.
|
|
||||||
*/
|
|
||||||
public url: Observable<UrlSegment[]>,
|
public url: Observable<UrlSegment[]>,
|
||||||
|
/** An observable of the matrix parameters scoped to this route */
|
||||||
/**
|
|
||||||
* The matrix parameters scoped to this route. The observable will emit a new value when
|
|
||||||
* the set of the parameters changes.
|
|
||||||
*/
|
|
||||||
public params: Observable<Params>,
|
public params: Observable<Params>,
|
||||||
|
/** An observable of the query parameters shared by all the routes */
|
||||||
/**
|
|
||||||
* The query parameters shared by all the routes. The observable will emit a new value when
|
|
||||||
* the set of the parameters changes.
|
|
||||||
*/
|
|
||||||
public queryParams: Observable<Params>,
|
public queryParams: Observable<Params>,
|
||||||
|
/** An observable of the URL fragment shared by all the routes */
|
||||||
/**
|
|
||||||
* The URL fragment shared by all the routes. The observable will emit a new value when
|
|
||||||
* the URL fragment changes.
|
|
||||||
*/
|
|
||||||
public fragment: Observable<string>,
|
public fragment: Observable<string>,
|
||||||
|
/** An observable of the static and resolved data of this route. */
|
||||||
/**
|
|
||||||
* The static and resolved data of this route. The observable will emit a new value when
|
|
||||||
* any of the resolvers returns a new object.
|
|
||||||
*/
|
|
||||||
public data: Observable<Data>,
|
public data: Observable<Data>,
|
||||||
|
/** The outlet name of the route. It's a constant */
|
||||||
/**
|
|
||||||
* The outlet name of the route. It's a constant.
|
|
||||||
*/
|
|
||||||
public outlet: string,
|
public outlet: string,
|
||||||
|
/** The component of the route. It's a constant */
|
||||||
/**
|
// TODO(vsavkin): remove |string
|
||||||
* The component of the route. It's a constant.
|
public component: Type<any>|string, futureSnapshot: ActivatedRouteSnapshot) {
|
||||||
*/
|
|
||||||
public component: Type<any>|string, // TODO: vsavkin: remove |string
|
|
||||||
futureSnapshot: ActivatedRouteSnapshot) {
|
|
||||||
this._futureSnapshot = futureSnapshot;
|
this._futureSnapshot = futureSnapshot;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** The configuration used to match this route */
|
||||||
* The configuration used to match this route.
|
|
||||||
*/
|
|
||||||
get routeConfig(): Route { return this._futureSnapshot.routeConfig; }
|
get routeConfig(): Route { return this._futureSnapshot.routeConfig; }
|
||||||
|
|
||||||
/**
|
/** The root of the router state */
|
||||||
* The root of the router state.
|
|
||||||
*/
|
|
||||||
get root(): ActivatedRoute { return this._routerState.root; }
|
get root(): ActivatedRoute { return this._routerState.root; }
|
||||||
|
|
||||||
/**
|
/** The parent of this route in the router state tree */
|
||||||
* The parent of this route in the router state tree.
|
|
||||||
*/
|
|
||||||
get parent(): ActivatedRoute { return this._routerState.parent(this); }
|
get parent(): ActivatedRoute { return this._routerState.parent(this); }
|
||||||
|
|
||||||
/**
|
/** The first child of this route in the router state tree */
|
||||||
* The first child of this route in the router state tree.
|
|
||||||
*/
|
|
||||||
get firstChild(): ActivatedRoute { return this._routerState.firstChild(this); }
|
get firstChild(): ActivatedRoute { return this._routerState.firstChild(this); }
|
||||||
|
|
||||||
/**
|
/** The children of this route in the router state tree */
|
||||||
* The children of this route in the router state tree.
|
|
||||||
*/
|
|
||||||
get children(): ActivatedRoute[] { return this._routerState.children(this); }
|
get children(): ActivatedRoute[] { return this._routerState.children(this); }
|
||||||
|
|
||||||
/**
|
/** The path from the root of the router state tree to this route */
|
||||||
* The path from the root of the router state tree to this route.
|
|
||||||
*/
|
|
||||||
get pathFromRoot(): ActivatedRoute[] { return this._routerState.pathFromRoot(this); }
|
get pathFromRoot(): ActivatedRoute[] { return this._routerState.pathFromRoot(this); }
|
||||||
|
|
||||||
/**
|
|
||||||
* @docsNotRequired
|
|
||||||
*/
|
|
||||||
toString(): string {
|
toString(): string {
|
||||||
return this.snapshot ? this.snapshot.toString() : `Future(${this._futureSnapshot})`;
|
return this.snapshot ? this.snapshot.toString() : `Future(${this._futureSnapshot})`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** @internal */
|
||||||
* @internal
|
|
||||||
*/
|
|
||||||
export type Inherited = {
|
export type Inherited = {
|
||||||
params: Params; data: Data; resolve: Data;
|
params: Params,
|
||||||
|
data: Data,
|
||||||
|
resolve: Data,
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** @internal */
|
||||||
* @internal
|
|
||||||
*/
|
|
||||||
export function
|
export function
|
||||||
inheritedParamsDataResolve(route: ActivatedRouteSnapshot):
|
inheritedParamsDataResolve(route: ActivatedRouteSnapshot):
|
||||||
Inherited {
|
Inherited {
|
||||||
@ -269,59 +217,32 @@ inheritedParamsDataResolve(route: ActivatedRouteSnapshot):
|
|||||||
export class ActivatedRouteSnapshot {
|
export class ActivatedRouteSnapshot {
|
||||||
/** @internal **/
|
/** @internal **/
|
||||||
_routeConfig: Route;
|
_routeConfig: Route;
|
||||||
|
|
||||||
/** @internal **/
|
/** @internal **/
|
||||||
_urlSegment: UrlSegmentGroup;
|
_urlSegment: UrlSegmentGroup;
|
||||||
|
|
||||||
/** @internal */
|
/** @internal */
|
||||||
_lastPathIndex: number;
|
_lastPathIndex: number;
|
||||||
|
|
||||||
/** @internal */
|
/** @internal */
|
||||||
_resolve: ResolveData;
|
_resolve: ResolveData;
|
||||||
|
|
||||||
/** @internal */
|
/** @internal */
|
||||||
_resolvedData: Data;
|
_resolvedData: Data;
|
||||||
|
|
||||||
/** @internal */
|
/** @internal */
|
||||||
_routerState: RouterStateSnapshot;
|
_routerState: RouterStateSnapshot;
|
||||||
|
|
||||||
/**
|
/** @internal */
|
||||||
* @internal
|
|
||||||
*/
|
|
||||||
constructor(
|
constructor(
|
||||||
/**
|
/** The URL segments matched by this route */
|
||||||
* The URL segments matched by this route.
|
|
||||||
*/
|
|
||||||
public url: UrlSegment[],
|
public url: UrlSegment[],
|
||||||
|
/** The matrix parameters scoped to this route */
|
||||||
/**
|
|
||||||
* The matrix parameters scoped to this route.
|
|
||||||
*/
|
|
||||||
public params: Params,
|
public params: Params,
|
||||||
|
/** The query parameters shared by all the routes */
|
||||||
/**
|
|
||||||
* The query parameters shared by all the routes.
|
|
||||||
*/
|
|
||||||
public queryParams: Params,
|
public queryParams: Params,
|
||||||
|
/** The URL fragment shared by all the routes */
|
||||||
/**
|
|
||||||
* The URL fragment shared by all the routes.
|
|
||||||
*/
|
|
||||||
public fragment: string,
|
public fragment: string,
|
||||||
|
/** The static and resolved data of this route */
|
||||||
/**
|
|
||||||
* The static and resolved data of this route.
|
|
||||||
*/
|
|
||||||
public data: Data,
|
public data: Data,
|
||||||
|
/** The outlet name of the route */
|
||||||
/**
|
|
||||||
* The outlet name of the route.
|
|
||||||
*/
|
|
||||||
public outlet: string,
|
public outlet: string,
|
||||||
|
/** The component of the route */
|
||||||
/**
|
|
||||||
* The component of the route.
|
|
||||||
*/
|
|
||||||
public component: Type<any>|string, routeConfig: Route, urlSegment: UrlSegmentGroup,
|
public component: Type<any>|string, routeConfig: Route, urlSegment: UrlSegmentGroup,
|
||||||
lastPathIndex: number, resolve: ResolveData) {
|
lastPathIndex: number, resolve: ResolveData) {
|
||||||
this._routeConfig = routeConfig;
|
this._routeConfig = routeConfig;
|
||||||
@ -330,41 +251,26 @@ export class ActivatedRouteSnapshot {
|
|||||||
this._resolve = resolve;
|
this._resolve = resolve;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** The configuration used to match this route */
|
||||||
* The configuration used to match this route.
|
|
||||||
*/
|
|
||||||
get routeConfig(): Route { return this._routeConfig; }
|
get routeConfig(): Route { return this._routeConfig; }
|
||||||
|
|
||||||
/**
|
/** The root of the router state */
|
||||||
* The root of the router state.
|
|
||||||
*/
|
|
||||||
get root(): ActivatedRouteSnapshot { return this._routerState.root; }
|
get root(): ActivatedRouteSnapshot { return this._routerState.root; }
|
||||||
|
|
||||||
/**
|
/** The parent of this route in the router state tree */
|
||||||
* The parent of this route in the router state tree.
|
|
||||||
*/
|
|
||||||
get parent(): ActivatedRouteSnapshot { return this._routerState.parent(this); }
|
get parent(): ActivatedRouteSnapshot { return this._routerState.parent(this); }
|
||||||
|
|
||||||
/**
|
/** The first child of this route in the router state tree */
|
||||||
* The first child of this route in the router state tree.
|
|
||||||
*/
|
|
||||||
get firstChild(): ActivatedRouteSnapshot { return this._routerState.firstChild(this); }
|
get firstChild(): ActivatedRouteSnapshot { return this._routerState.firstChild(this); }
|
||||||
|
|
||||||
/**
|
/** The children of this route in the router state tree */
|
||||||
* The children of this route in the router state tree.
|
|
||||||
*/
|
|
||||||
get children(): ActivatedRouteSnapshot[] { return this._routerState.children(this); }
|
get children(): ActivatedRouteSnapshot[] { return this._routerState.children(this); }
|
||||||
|
|
||||||
/**
|
/** The path from the root of the router state tree to this route */
|
||||||
* The path from the root of the router state tree to this route.
|
|
||||||
*/
|
|
||||||
get pathFromRoot(): ActivatedRouteSnapshot[] { return this._routerState.pathFromRoot(this); }
|
get pathFromRoot(): ActivatedRouteSnapshot[] { return this._routerState.pathFromRoot(this); }
|
||||||
|
|
||||||
/**
|
|
||||||
* @docsNotRequired
|
|
||||||
*/
|
|
||||||
toString(): string {
|
toString(): string {
|
||||||
const url = this.url.map(s => s.toString()).join('/');
|
const url = this.url.map(segment => segment.toString()).join('/');
|
||||||
const matched = this._routeConfig ? this._routeConfig.path : '';
|
const matched = this._routeConfig ? this._routeConfig.path : '';
|
||||||
return `Route(url:'${url}', path:'${matched}')`;
|
return `Route(url:'${url}', path:'${matched}')`;
|
||||||
}
|
}
|
||||||
@ -396,11 +302,8 @@ export class ActivatedRouteSnapshot {
|
|||||||
* @stable
|
* @stable
|
||||||
*/
|
*/
|
||||||
export class RouterStateSnapshot extends Tree<ActivatedRouteSnapshot> {
|
export class RouterStateSnapshot extends Tree<ActivatedRouteSnapshot> {
|
||||||
/**
|
/** @internal */
|
||||||
* @internal
|
|
||||||
*/
|
|
||||||
constructor(
|
constructor(
|
||||||
|
|
||||||
/** The url from which this snapshot was created */
|
/** The url from which this snapshot was created */
|
||||||
public url: string, root: TreeNode<ActivatedRouteSnapshot>) {
|
public url: string, root: TreeNode<ActivatedRouteSnapshot>) {
|
||||||
super(root);
|
super(root);
|
||||||
|
@ -17,10 +17,10 @@ export function containsTree(container: UrlTree, containee: UrlTree, exact: bool
|
|||||||
if (exact) {
|
if (exact) {
|
||||||
return equalQueryParams(container.queryParams, containee.queryParams) &&
|
return equalQueryParams(container.queryParams, containee.queryParams) &&
|
||||||
equalSegmentGroups(container.root, containee.root);
|
equalSegmentGroups(container.root, containee.root);
|
||||||
} else {
|
|
||||||
return containsQueryParams(container.queryParams, containee.queryParams) &&
|
|
||||||
containsSegmentGroup(container.root, containee.root);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return containsQueryParams(container.queryParams, containee.queryParams) &&
|
||||||
|
containsSegmentGroup(container.root, containee.root);
|
||||||
}
|
}
|
||||||
|
|
||||||
function equalQueryParams(
|
function equalQueryParams(
|
||||||
@ -83,7 +83,7 @@ function containsSegmentGroupHelper(
|
|||||||
* class MyComponent {
|
* class MyComponent {
|
||||||
* constructor(router: Router) {
|
* constructor(router: Router) {
|
||||||
* const tree: UrlTree =
|
* const tree: UrlTree =
|
||||||
* router.parseUrl('/team/33/(user/victor//support:help)?debug=true#fragment');
|
* router.parseUrl('/team/33/(user/victor//support:help)?debug=true#fragment');
|
||||||
* const f = tree.fragment; // return 'fragment'
|
* const f = tree.fragment; // return 'fragment'
|
||||||
* const q = tree.queryParams; // returns {debug: 'true'}
|
* const q = tree.queryParams; // returns {debug: 'true'}
|
||||||
* const g: UrlSegmentGroup = tree.root.children[PRIMARY_OUTLET];
|
* const g: UrlSegmentGroup = tree.root.children[PRIMARY_OUTLET];
|
||||||
@ -103,79 +103,49 @@ function containsSegmentGroupHelper(
|
|||||||
* @stable
|
* @stable
|
||||||
*/
|
*/
|
||||||
export class UrlTree {
|
export class UrlTree {
|
||||||
/**
|
/** @internal */
|
||||||
* @internal
|
|
||||||
*/
|
|
||||||
constructor(
|
constructor(
|
||||||
/**
|
/** The root segment group of the URL tree */
|
||||||
* The root segment group of the URL tree.
|
|
||||||
*/
|
|
||||||
public root: UrlSegmentGroup,
|
public root: UrlSegmentGroup,
|
||||||
/**
|
/** The query params of the URL */
|
||||||
* The query params of the URL.
|
|
||||||
*/
|
|
||||||
public queryParams: {[key: string]: string},
|
public queryParams: {[key: string]: string},
|
||||||
/**
|
/** The fragment of the URL */
|
||||||
* The fragment of the URL.
|
|
||||||
*/
|
|
||||||
public fragment: string) {}
|
public fragment: string) {}
|
||||||
|
|
||||||
/**
|
/** @docsNotRequired */
|
||||||
* @docsNotRequired
|
|
||||||
*/
|
|
||||||
toString(): string { return new DefaultUrlSerializer().serialize(this); }
|
toString(): string { return new DefaultUrlSerializer().serialize(this); }
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @whatItDoes Represents the parsed URL segment.
|
* @whatItDoes Represents the parsed URL segment group.
|
||||||
*
|
*
|
||||||
* See {@link UrlTree} for more information.
|
* See {@link UrlTree} for more information.
|
||||||
*
|
*
|
||||||
* @stable
|
* @stable
|
||||||
*/
|
*/
|
||||||
export class UrlSegmentGroup {
|
export class UrlSegmentGroup {
|
||||||
/**
|
/** @internal */
|
||||||
* @internal
|
|
||||||
*/
|
|
||||||
_sourceSegment: UrlSegmentGroup;
|
_sourceSegment: UrlSegmentGroup;
|
||||||
|
/** @internal */
|
||||||
/**
|
|
||||||
* @internal
|
|
||||||
*/
|
|
||||||
_segmentIndexShift: number;
|
_segmentIndexShift: number;
|
||||||
|
/** The parent node in the url tree */
|
||||||
/**
|
parent: UrlSegmentGroup = null;
|
||||||
* The parent node in the url tree.
|
|
||||||
*/
|
|
||||||
public parent: UrlSegmentGroup = null;
|
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
/**
|
/** The URL segments of this group. See {@link UrlSegment} for more information */
|
||||||
* The URL segments of this group. See {@link UrlSegment} for more information.
|
|
||||||
*/
|
|
||||||
public segments: UrlSegment[],
|
public segments: UrlSegment[],
|
||||||
/**
|
/** The list of children of this group */
|
||||||
* The list of children of this group.
|
public children: {[key: string]: UrlSegmentGroup}) {
|
||||||
*/
|
|
||||||
public children: {[key: string]: UrlSegmentGroup}
|
|
||||||
|
|
||||||
) {
|
|
||||||
forEach(children, (v: any, k: any) => v.parent = this);
|
forEach(children, (v: any, k: any) => v.parent = this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** Wether the segment has child segments */
|
||||||
* Return true if the segment has child segments
|
|
||||||
*/
|
|
||||||
hasChildren(): boolean { return this.numberOfChildren > 0; }
|
hasChildren(): boolean { return this.numberOfChildren > 0; }
|
||||||
|
|
||||||
/**
|
/** Number of child segments */
|
||||||
* Returns the number of child sements.
|
|
||||||
*/
|
|
||||||
get numberOfChildren(): number { return Object.keys(this.children).length; }
|
get numberOfChildren(): number { return Object.keys(this.children).length; }
|
||||||
|
|
||||||
/**
|
/** @docsNotRequired */
|
||||||
* @docsNotRequired
|
|
||||||
*/
|
|
||||||
toString(): string { return serializePaths(this); }
|
toString(): string { return serializePaths(this); }
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -200,26 +170,20 @@ export class UrlSegmentGroup {
|
|||||||
*
|
*
|
||||||
* @description
|
* @description
|
||||||
*
|
*
|
||||||
* A UrlSegment is a part of a URL between the two slashes. It contains a path and
|
* A UrlSegment is a part of a URL between the two slashes. It contains a path and the matrix
|
||||||
* the matrix parameters associated with the segment.
|
* parameters associated with the segment.
|
||||||
*
|
*
|
||||||
* @stable
|
* @stable
|
||||||
*/
|
*/
|
||||||
export class UrlSegment {
|
export class UrlSegment {
|
||||||
constructor(
|
constructor(
|
||||||
/**
|
/** The path part of a URL segment */
|
||||||
* The path part of a URL segment.
|
|
||||||
*/
|
|
||||||
public path: string,
|
public path: string,
|
||||||
|
|
||||||
/**
|
/** The matrix parameters associated with a segment */
|
||||||
* The matrix parameters associated with a segment.
|
public parameters: {[name: string]: string}) {}
|
||||||
*/
|
|
||||||
public parameters: {[key: string]: string}) {}
|
|
||||||
|
|
||||||
/**
|
/** @docsNotRequired */
|
||||||
* @docsNotRequired
|
|
||||||
*/
|
|
||||||
toString(): string { return serializePath(this); }
|
toString(): string { return serializePath(this); }
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -268,14 +232,10 @@ export function mapChildrenIntoArray<T>(
|
|||||||
* @stable
|
* @stable
|
||||||
*/
|
*/
|
||||||
export abstract class UrlSerializer {
|
export abstract class UrlSerializer {
|
||||||
/**
|
/** Parse a url into a {@link UrlTree} */
|
||||||
* Parse a url into a {@link UrlTree}.
|
|
||||||
*/
|
|
||||||
abstract parse(url: string): UrlTree;
|
abstract parse(url: string): UrlTree;
|
||||||
|
|
||||||
/**
|
/** Converts a {@link UrlTree} into a url */
|
||||||
* Converts a {@link UrlTree} into a url.
|
|
||||||
*/
|
|
||||||
abstract serialize(tree: UrlTree): string;
|
abstract serialize(tree: UrlTree): string;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -298,17 +258,13 @@ export abstract class UrlSerializer {
|
|||||||
* @stable
|
* @stable
|
||||||
*/
|
*/
|
||||||
export class DefaultUrlSerializer implements UrlSerializer {
|
export class DefaultUrlSerializer implements UrlSerializer {
|
||||||
/**
|
/** Parses a url into a {@link UrlTree} */
|
||||||
* Parse a url into a {@link UrlTree}.
|
|
||||||
*/
|
|
||||||
parse(url: string): UrlTree {
|
parse(url: string): UrlTree {
|
||||||
const p = new UrlParser(url);
|
const p = new UrlParser(url);
|
||||||
return new UrlTree(p.parseRootSegment(), p.parseQueryParams(), p.parseFragment());
|
return new UrlTree(p.parseRootSegment(), p.parseQueryParams(), p.parseFragment());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** Converts a {@link UrlTree} into a url */
|
||||||
* Converts a {@link UrlTree} into a url.
|
|
||||||
*/
|
|
||||||
serialize(tree: UrlTree): string {
|
serialize(tree: UrlTree): string {
|
||||||
const segment = `/${serializeSegment(tree.root, true)}`;
|
const segment = `/${serializeSegment(tree.root, true)}`;
|
||||||
const query = serializeQueryParams(tree.queryParams);
|
const query = serializeQueryParams(tree.queryParams);
|
||||||
@ -383,6 +339,7 @@ function serializeQueryParams(params: {[key: string]: any}): string {
|
|||||||
class Pair<A, B> {
|
class Pair<A, B> {
|
||||||
constructor(public first: A, public second: B) {}
|
constructor(public first: A, public second: B) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
function pairs<T>(obj: {[key: string]: T}): Pair<string, T>[] {
|
function pairs<T>(obj: {[key: string]: T}): Pair<string, T>[] {
|
||||||
const res: Pair<string, T>[] = [];
|
const res: Pair<string, T>[] = [];
|
||||||
for (const prop in obj) {
|
for (const prop in obj) {
|
||||||
@ -436,9 +393,9 @@ class UrlParser {
|
|||||||
|
|
||||||
if (this.remaining === '' || this.remaining.startsWith('?') || this.remaining.startsWith('#')) {
|
if (this.remaining === '' || this.remaining.startsWith('?') || this.remaining.startsWith('#')) {
|
||||||
return new UrlSegmentGroup([], {});
|
return new UrlSegmentGroup([], {});
|
||||||
} else {
|
|
||||||
return new UrlSegmentGroup([], this.parseChildren());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return new UrlSegmentGroup([], this.parseChildren());
|
||||||
}
|
}
|
||||||
|
|
||||||
parseChildren(): {[key: string]: UrlSegmentGroup} {
|
parseChildren(): {[key: string]: UrlSegmentGroup} {
|
||||||
@ -508,9 +465,9 @@ class UrlParser {
|
|||||||
parseFragment(): string {
|
parseFragment(): string {
|
||||||
if (this.peekStartsWith('#')) {
|
if (this.peekStartsWith('#')) {
|
||||||
return decodeURI(this.remaining.substring(1));
|
return decodeURI(this.remaining.substring(1));
|
||||||
} else {
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
parseMatrixParams(): {[key: string]: any} {
|
parseMatrixParams(): {[key: string]: any} {
|
||||||
|
@ -60,7 +60,7 @@ export function last<T>(a: T[]): T {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function and(bools: boolean[]): boolean {
|
export function and(bools: boolean[]): boolean {
|
||||||
return bools.reduce((a, b) => a && b, true);
|
return !bools.some(v => !v);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function merge<V>(m1: {[key: string]: V}, m2: {[key: string]: V}): {[key: string]: V} {
|
export function merge<V>(m1: {[key: string]: V}, m2: {[key: string]: V}): {[key: string]: V} {
|
||||||
@ -81,8 +81,7 @@ export function merge<V>(m1: {[key: string]: V}, m2: {[key: string]: V}): {[key:
|
|||||||
return m;
|
return m;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function forEach<K, V>(
|
export function forEach<K, V>(map: {[key: string]: V}, callback: (v: V, k: string) => void): void {
|
||||||
map: {[key: string]: V}, callback: /*(V, K) => void*/ Function): void {
|
|
||||||
for (const prop in map) {
|
for (const prop in map) {
|
||||||
if (map.hasOwnProperty(prop)) {
|
if (map.hasOwnProperty(prop)) {
|
||||||
callback(map[prop], prop);
|
callback(map[prop], prop);
|
||||||
@ -117,9 +116,9 @@ export function waitForMap<A, B>(
|
|||||||
const concatted$ = concatAll.call(of (...waitFor));
|
const concatted$ = concatAll.call(of (...waitFor));
|
||||||
const last$ = l.last.call(concatted$);
|
const last$ = l.last.call(concatted$);
|
||||||
return map.call(last$, () => res);
|
return map.call(last$, () => res);
|
||||||
} else {
|
|
||||||
return of (res);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return of (res);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function andObservables(observables: Observable<Observable<any>>): Observable<boolean> {
|
export function andObservables(observables: Observable<Observable<any>>): Observable<boolean> {
|
||||||
@ -130,9 +129,11 @@ export function andObservables(observables: Observable<Observable<any>>): Observ
|
|||||||
export function wrapIntoObservable<T>(value: T | Promise<T>| Observable<T>): Observable<T> {
|
export function wrapIntoObservable<T>(value: T | Promise<T>| Observable<T>): Observable<T> {
|
||||||
if (value instanceof Observable) {
|
if (value instanceof Observable) {
|
||||||
return value;
|
return value;
|
||||||
} else if (value instanceof Promise) {
|
|
||||||
return fromPromise(value);
|
|
||||||
} else {
|
|
||||||
return of (value);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (value instanceof Promise) {
|
||||||
|
return fromPromise(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
return of (value);
|
||||||
}
|
}
|
4
tools/public_api_guard/router/index.d.ts
vendored
4
tools/public_api_guard/router/index.d.ts
vendored
@ -366,13 +366,13 @@ export declare abstract class UrlHandlingStrategy {
|
|||||||
/** @stable */
|
/** @stable */
|
||||||
export declare class UrlSegment {
|
export declare class UrlSegment {
|
||||||
parameters: {
|
parameters: {
|
||||||
[key: string]: string;
|
[name: string]: string;
|
||||||
};
|
};
|
||||||
path: string;
|
path: string;
|
||||||
constructor(
|
constructor(
|
||||||
path: string,
|
path: string,
|
||||||
parameters: {
|
parameters: {
|
||||||
[key: string]: string;
|
[name: string]: string;
|
||||||
});
|
});
|
||||||
toString(): string;
|
toString(): string;
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user