cleanup(router): fix tslint errors
This commit is contained in:
parent
8a1cdc2dd5
commit
6988a550ea
|
@ -1,10 +1,12 @@
|
|||
import { RouterOutletMap } from './router_outlet_map';
|
||||
import { UrlSerializer, DefaultUrlSerializer } from './url_serializer';
|
||||
import { ActivatedRoute } from './router_state';
|
||||
import { Router } from './router';
|
||||
import { RouterConfig } from './config';
|
||||
import { ComponentResolver, ApplicationRef, Injector, APP_INITIALIZER } from '@angular/core';
|
||||
import { LocationStrategy, PathLocationStrategy, Location } from '@angular/common';
|
||||
import {Location, LocationStrategy, PathLocationStrategy} from '@angular/common';
|
||||
import {APP_INITIALIZER, ApplicationRef, ComponentResolver, Injector} from '@angular/core';
|
||||
|
||||
import {RouterConfig} from './config';
|
||||
import {Router} from './router';
|
||||
import {RouterOutletMap} from './router_outlet_map';
|
||||
import {ActivatedRoute} from './router_state';
|
||||
import {DefaultUrlSerializer, UrlSerializer} from './url_serializer';
|
||||
|
||||
|
||||
/**
|
||||
* A list of {@link Provider}s. To use the router, you must add this to your application.
|
||||
|
@ -24,7 +26,7 @@ import { LocationStrategy, PathLocationStrategy, Location } from '@angular/commo
|
|||
* bootstrap(AppCmp, [provideRouter(router)]);
|
||||
* ```
|
||||
*/
|
||||
export function provideRouter(config: RouterConfig):any[] {
|
||||
export function provideRouter(config: RouterConfig): any[] {
|
||||
return [
|
||||
Location,
|
||||
{provide: LocationStrategy, useClass: PathLocationStrategy},
|
||||
|
@ -34,20 +36,27 @@ export function provideRouter(config: RouterConfig):any[] {
|
|||
provide: Router,
|
||||
useFactory: (ref, resolver, urlSerializer, outletMap, location, injector) => {
|
||||
if (ref.componentTypes.length == 0) {
|
||||
throw new Error("Bootstrap at least one component before injecting Router.");
|
||||
throw new Error('Bootstrap at least one component before injecting Router.');
|
||||
}
|
||||
const componentType = ref.componentTypes[0];
|
||||
const r = new Router(componentType, resolver, urlSerializer, outletMap, location, injector, config);
|
||||
const r = new Router(
|
||||
componentType, resolver, urlSerializer, outletMap, location, injector, config);
|
||||
ref.registerDisposeListener(() => r.dispose());
|
||||
return r;
|
||||
},
|
||||
deps: [ApplicationRef, ComponentResolver, UrlSerializer, RouterOutletMap, Location, Injector]
|
||||
deps:
|
||||
[ApplicationRef, ComponentResolver, UrlSerializer, RouterOutletMap, Location, Injector]
|
||||
},
|
||||
|
||||
RouterOutletMap,
|
||||
{provide: ActivatedRoute, useFactory: (r) => r.routerState.root, deps: [Router]},
|
||||
|
||||
|
||||
// Trigger initial navigation
|
||||
{provide: APP_INITIALIZER, multi: true, useFactory: (router: Router) => router.initialNavigation(), deps: [Router]},
|
||||
{
|
||||
provide: APP_INITIALIZER,
|
||||
multi: true,
|
||||
useFactory: (router: Router) => router.initialNavigation(),
|
||||
deps: [Router]
|
||||
},
|
||||
];
|
||||
}
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
import { Type } from '@angular/core';
|
||||
import {Type} from '@angular/core';
|
||||
|
||||
export type RouterConfig = Route[];
|
||||
|
||||
export interface Route {
|
||||
index?: boolean;
|
||||
path?: string;
|
||||
component: Type | string;
|
||||
component: Type|string;
|
||||
outlet?: string;
|
||||
canActivate?: any[];
|
||||
canDeactivate?: any[];
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import { RouterStateSnapshot, ActivatedRouteSnapshot, RouterState, ActivatedRoute } from './router_state';
|
||||
import { TreeNode } from './utils/tree';
|
||||
import { BehaviorSubject } from 'rxjs/BehaviorSubject';
|
||||
import {BehaviorSubject} from 'rxjs/BehaviorSubject';
|
||||
|
||||
import {ActivatedRoute, ActivatedRouteSnapshot, RouterState, RouterStateSnapshot} from './router_state';
|
||||
import {TreeNode} from './utils/tree';
|
||||
|
||||
export function createRouterState(curr: RouterStateSnapshot, prevState: RouterState): RouterState {
|
||||
const root = createNode(curr._root, prevState ? prevState._root : undefined);
|
||||
|
@ -9,11 +10,12 @@ export function createRouterState(curr: RouterStateSnapshot, prevState: RouterSt
|
|||
return new RouterState(root, queryParams, fragment, curr);
|
||||
}
|
||||
|
||||
function createNode(curr:TreeNode<ActivatedRouteSnapshot>, prevState?:TreeNode<ActivatedRoute>):TreeNode<ActivatedRoute> {
|
||||
function createNode(curr: TreeNode<ActivatedRouteSnapshot>, prevState?: TreeNode<ActivatedRoute>):
|
||||
TreeNode<ActivatedRoute> {
|
||||
if (prevState && equalRouteSnapshots(prevState.value.snapshot, curr.value)) {
|
||||
const value = prevState.value;
|
||||
value._futureSnapshot = curr.value;
|
||||
|
||||
|
||||
const children = createOrReuseChildren(curr, prevState);
|
||||
return new TreeNode<ActivatedRoute>(value, children);
|
||||
|
||||
|
@ -24,9 +26,11 @@ function createNode(curr:TreeNode<ActivatedRouteSnapshot>, prevState?:TreeNode<A
|
|||
}
|
||||
}
|
||||
|
||||
function createOrReuseChildren(curr:TreeNode<ActivatedRouteSnapshot>, prevState:TreeNode<ActivatedRoute>) {
|
||||
function createOrReuseChildren(
|
||||
curr: TreeNode<ActivatedRouteSnapshot>, prevState: TreeNode<ActivatedRoute>) {
|
||||
return curr.children.map(child => {
|
||||
const index = prevState.children.findIndex(p => equalRouteSnapshots(p.value.snapshot, child.value));
|
||||
const index =
|
||||
prevState.children.findIndex(p => equalRouteSnapshots(p.value.snapshot, child.value));
|
||||
if (index >= 0) {
|
||||
return createNode(child, prevState.children[index]);
|
||||
} else {
|
||||
|
@ -35,8 +39,9 @@ function createOrReuseChildren(curr:TreeNode<ActivatedRouteSnapshot>, prevState:
|
|||
});
|
||||
}
|
||||
|
||||
function createActivatedRoute(c:ActivatedRouteSnapshot) {
|
||||
return new ActivatedRoute(new BehaviorSubject(c.urlSegments), new BehaviorSubject(c.params), c.outlet, c.component, c);
|
||||
function createActivatedRoute(c: ActivatedRouteSnapshot) {
|
||||
return new ActivatedRoute(
|
||||
new BehaviorSubject(c.urlSegments), new BehaviorSubject(c.params), c.outlet, c.component, c);
|
||||
}
|
||||
|
||||
function equalRouteSnapshots(a: ActivatedRouteSnapshot, b: ActivatedRouteSnapshot): boolean {
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
import { UrlTree, UrlSegment, equalUrlSegments } from './url_tree';
|
||||
import { TreeNode } from './utils/tree';
|
||||
import { forEach, shallowEqual } from './utils/collection';
|
||||
import { RouterState, ActivatedRoute } from './router_state';
|
||||
import { Params, PRIMARY_OUTLET } from './shared';
|
||||
import {ActivatedRoute} from './router_state';
|
||||
import {PRIMARY_OUTLET, Params} from './shared';
|
||||
import {UrlSegment, UrlTree} from './url_tree';
|
||||
import {forEach, shallowEqual} from './utils/collection';
|
||||
import {TreeNode} from './utils/tree';
|
||||
|
||||
export function createUrlTree(route: ActivatedRoute, urlTree: UrlTree, commands: any[],
|
||||
queryParams: Params | undefined, fragment: string | undefined): UrlTree {
|
||||
export function createUrlTree(
|
||||
route: ActivatedRoute, urlTree: UrlTree, commands: any[], queryParams: Params | undefined,
|
||||
fragment: string | undefined): UrlTree {
|
||||
if (commands.length === 0) {
|
||||
return tree(urlTree._root, urlTree, queryParams, fragment);
|
||||
}
|
||||
|
@ -24,7 +25,9 @@ export function createUrlTree(route: ActivatedRoute, urlTree: UrlTree, commands:
|
|||
return tree(newRoot, urlTree, queryParams, fragment);
|
||||
}
|
||||
|
||||
function tree(root: TreeNode<UrlSegment>, urlTree: UrlTree, queryParams: Params | undefined, fragment: string | undefined): UrlTree {
|
||||
function tree(
|
||||
root: TreeNode<UrlSegment>, urlTree: UrlTree, queryParams: Params | undefined,
|
||||
fragment: string | undefined): UrlTree {
|
||||
const q = queryParams ? stringify(queryParams) : urlTree.queryParams;
|
||||
const f = fragment ? fragment : urlTree.fragment;
|
||||
return new UrlTree(root, q, f);
|
||||
|
@ -32,16 +35,16 @@ function tree(root: TreeNode<UrlSegment>, urlTree: UrlTree, queryParams: Params
|
|||
|
||||
function navigateToRoot(normalizedChange: NormalizedNavigationCommands): boolean {
|
||||
return normalizedChange.isAbsolute && normalizedChange.commands.length === 1 &&
|
||||
normalizedChange.commands[0] == "/";
|
||||
normalizedChange.commands[0] == '/';
|
||||
}
|
||||
|
||||
class NormalizedNavigationCommands {
|
||||
constructor(public isAbsolute: boolean, public numberOfDoubleDots: number,
|
||||
public commands: any[]) {}
|
||||
constructor(
|
||||
public isAbsolute: boolean, public numberOfDoubleDots: number, public commands: any[]) {}
|
||||
}
|
||||
|
||||
function normalizeCommands(commands: any[]): NormalizedNavigationCommands {
|
||||
if ((typeof commands[0] === "string") && commands.length === 1 && commands[0] == "/") {
|
||||
if ((typeof commands[0] === 'string') && commands.length === 1 && commands[0] == '/') {
|
||||
return new NormalizedNavigationCommands(true, 0, commands);
|
||||
}
|
||||
|
||||
|
@ -52,7 +55,7 @@ function normalizeCommands(commands: any[]): NormalizedNavigationCommands {
|
|||
for (let i = 0; i < commands.length; ++i) {
|
||||
const c = commands[i];
|
||||
|
||||
if (!(typeof c === "string")) {
|
||||
if (!(typeof c === 'string')) {
|
||||
res.push(c);
|
||||
continue;
|
||||
}
|
||||
|
@ -63,11 +66,11 @@ function normalizeCommands(commands: any[]): NormalizedNavigationCommands {
|
|||
|
||||
// first exp is treated in a special way
|
||||
if (i == 0) {
|
||||
if (j == 0 && cc == ".") { // './a'
|
||||
if (j == 0 && cc == '.') { // './a'
|
||||
// skip it
|
||||
} else if (j == 0 && cc == "") { // '/a'
|
||||
} else if (j == 0 && cc == '') { // '/a'
|
||||
isAbsolute = true;
|
||||
} else if (cc == "..") { // '../a'
|
||||
} else if (cc == '..') { // '../a'
|
||||
numberOfDoubleDots++;
|
||||
} else if (cc != '') {
|
||||
res.push(cc);
|
||||
|
@ -84,22 +87,23 @@ function normalizeCommands(commands: any[]): NormalizedNavigationCommands {
|
|||
return new NormalizedNavigationCommands(isAbsolute, numberOfDoubleDots, res);
|
||||
}
|
||||
|
||||
function findStartingNode(normalizedChange: NormalizedNavigationCommands, urlTree: UrlTree,
|
||||
route: ActivatedRoute): TreeNode<UrlSegment> {
|
||||
function findStartingNode(
|
||||
normalizedChange: NormalizedNavigationCommands, urlTree: UrlTree,
|
||||
route: ActivatedRoute): TreeNode<UrlSegment> {
|
||||
if (normalizedChange.isAbsolute) {
|
||||
return urlTree._root;
|
||||
} else {
|
||||
const urlSegment =
|
||||
findUrlSegment(route, urlTree, normalizedChange.numberOfDoubleDots);
|
||||
const urlSegment = findUrlSegment(route, urlTree, normalizedChange.numberOfDoubleDots);
|
||||
return findMatchingNode(urlSegment, urlTree._root);
|
||||
}
|
||||
}
|
||||
|
||||
function findUrlSegment(route: ActivatedRoute, urlTree: UrlTree, numberOfDoubleDots: number): UrlSegment {
|
||||
function findUrlSegment(
|
||||
route: ActivatedRoute, urlTree: UrlTree, numberOfDoubleDots: number): UrlSegment {
|
||||
const urlSegment = route.snapshot._lastUrlSegment;
|
||||
const path = urlTree.pathFromRoot(urlSegment);
|
||||
if (path.length <= numberOfDoubleDots) {
|
||||
throw new Error("Invalid number of '../'");
|
||||
throw new Error('Invalid number of \'../\'');
|
||||
}
|
||||
return path[path.length - 1 - numberOfDoubleDots];
|
||||
}
|
||||
|
@ -113,13 +117,14 @@ function findMatchingNode(segment: UrlSegment, node: TreeNode<UrlSegment>): Tree
|
|||
throw new Error(`Cannot find url segment '${segment}'`);
|
||||
}
|
||||
|
||||
function constructNewTree(node: TreeNode<UrlSegment>, original: TreeNode<UrlSegment>,
|
||||
updated: TreeNode<UrlSegment>[]): TreeNode<UrlSegment> {
|
||||
function constructNewTree(
|
||||
node: TreeNode<UrlSegment>, original: TreeNode<UrlSegment>,
|
||||
updated: TreeNode<UrlSegment>[]): TreeNode<UrlSegment> {
|
||||
if (node === original) {
|
||||
return new TreeNode<UrlSegment>(node.value, updated);
|
||||
} else {
|
||||
return new TreeNode<UrlSegment>(
|
||||
node.value, node.children.map(c => constructNewTree(c, original, updated)));
|
||||
node.value, node.children.map(c => constructNewTree(c, original, updated)));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -136,18 +141,18 @@ function updateMany(nodes: TreeNode<UrlSegment>[], commands: any[]): TreeNode<Ur
|
|||
}
|
||||
|
||||
function getPath(commands: any[]): any {
|
||||
if (!(typeof commands[0] === "string")) return commands[0];
|
||||
const parts = commands[0].toString().split(":");
|
||||
if (!(typeof commands[0] === 'string')) return commands[0];
|
||||
const parts = commands[0].toString().split(':');
|
||||
return parts.length > 1 ? parts[1] : commands[0];
|
||||
}
|
||||
|
||||
function getOutlet(commands: any[]): string {
|
||||
if (!(typeof commands[0] === "string")) return PRIMARY_OUTLET;
|
||||
const parts = commands[0].toString().split(":");
|
||||
if (!(typeof commands[0] === 'string')) return PRIMARY_OUTLET;
|
||||
const parts = commands[0].toString().split(':');
|
||||
return parts.length > 1 ? parts[0] : PRIMARY_OUTLET;
|
||||
}
|
||||
|
||||
function update(node: TreeNode<UrlSegment>|null, commands: any[]): TreeNode<UrlSegment> {
|
||||
function update(node: TreeNode<UrlSegment>| null, commands: any[]): TreeNode<UrlSegment> {
|
||||
const rest = commands.slice(1);
|
||||
const next = rest.length === 0 ? null : rest[0];
|
||||
const outlet = getOutlet(commands);
|
||||
|
@ -202,8 +207,8 @@ function compare(path: string, params: {[key: string]: any}, segment: UrlSegment
|
|||
return path == segment.path && shallowEqual(params, segment.parameters);
|
||||
}
|
||||
|
||||
function recurse(urlSegment: UrlSegment, node: TreeNode<UrlSegment> | null,
|
||||
rest: any[]): TreeNode<UrlSegment> {
|
||||
function recurse(
|
||||
urlSegment: UrlSegment, node: TreeNode<UrlSegment>| null, rest: any[]): TreeNode<UrlSegment> {
|
||||
if (rest.length === 0) {
|
||||
return new TreeNode<UrlSegment>(urlSegment, []);
|
||||
}
|
||||
|
|
|
@ -1,13 +1,9 @@
|
|||
import {
|
||||
Directive,
|
||||
HostListener,
|
||||
HostBinding,
|
||||
Input,
|
||||
OnChanges
|
||||
} from '@angular/core';
|
||||
import {Directive, HostBinding, HostListener, Input, OnChanges} from '@angular/core';
|
||||
|
||||
import {Router} from '../router';
|
||||
import {ActivatedRoute} from '../router_state';
|
||||
|
||||
|
||||
/**
|
||||
* The RouterLink directive lets you link to specific parts of your app.
|
||||
*
|
||||
|
@ -37,7 +33,7 @@ import {ActivatedRoute} from '../router_state';
|
|||
export class RouterLink implements OnChanges {
|
||||
@Input() target: string;
|
||||
private commands: any[] = [];
|
||||
@Input() queryParams: {[k:string]:any};
|
||||
@Input() queryParams: {[k: string]: any};
|
||||
@Input() fragment: string;
|
||||
|
||||
// the url displayed on the anchor element.
|
||||
|
@ -49,7 +45,7 @@ export class RouterLink implements OnChanges {
|
|||
constructor(private router: Router, private route: ActivatedRoute) {}
|
||||
|
||||
@Input()
|
||||
set routerLink(data: any[] | string) {
|
||||
set routerLink(data: any[]|string) {
|
||||
if (Array.isArray(data)) {
|
||||
this.commands = <any>data;
|
||||
} else {
|
||||
|
@ -57,30 +53,24 @@ export class RouterLink implements OnChanges {
|
|||
}
|
||||
}
|
||||
|
||||
ngOnChanges(changes:{}):any {
|
||||
this.updateTargetUrlAndHref();
|
||||
}
|
||||
ngOnChanges(changes: {}): any { this.updateTargetUrlAndHref(); }
|
||||
|
||||
@HostListener("click")
|
||||
@HostListener('click')
|
||||
onClick(): boolean {
|
||||
// If no target, or if target is _self, prevent default browser behavior
|
||||
if (!(typeof this.target === "string") || this.target == '_self') {
|
||||
this.router.navigate(this.commands, {
|
||||
relativeTo: this.route,
|
||||
queryParams: this.queryParams,
|
||||
fragment: this.fragment
|
||||
});
|
||||
if (!(typeof this.target === 'string') || this.target == '_self') {
|
||||
this.router.navigate(
|
||||
this.commands,
|
||||
{relativeTo: this.route, queryParams: this.queryParams, fragment: this.fragment});
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private updateTargetUrlAndHref(): void {
|
||||
const tree = this.router.createUrlTree(this.commands, {
|
||||
relativeTo: this.route,
|
||||
queryParams: this.queryParams,
|
||||
fragment: this.fragment
|
||||
});
|
||||
const tree = this.router.createUrlTree(
|
||||
this.commands,
|
||||
{relativeTo: this.route, queryParams: this.queryParams, fragment: this.fragment});
|
||||
if (tree) {
|
||||
this.href = this.router.serializeUrl(tree);
|
||||
}
|
||||
|
|
|
@ -1,23 +1,24 @@
|
|||
import {Injector, Directive, ViewContainerRef, Attribute, ComponentRef, ComponentFactory, ResolvedReflectiveProvider, ReflectiveInjector} from '@angular/core';
|
||||
import {RouterOutletMap} from '../router_outlet_map';
|
||||
import {PRIMARY_OUTLET} from '../shared';
|
||||
import {Attribute, ComponentFactory, ComponentRef, Directive, ReflectiveInjector, ResolvedReflectiveProvider, ViewContainerRef} from "@angular/core";
|
||||
import {RouterOutletMap} from "../router_outlet_map";
|
||||
import {PRIMARY_OUTLET} from "../shared";
|
||||
|
||||
@Directive({selector: 'router-outlet'})
|
||||
export class RouterOutlet {
|
||||
private activated:ComponentRef<any>|null;
|
||||
public outletMap:RouterOutletMap;
|
||||
private activated: ComponentRef<any>|null;
|
||||
public outletMap: RouterOutletMap;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
constructor(parentOutletMap:RouterOutletMap, private location:ViewContainerRef,
|
||||
@Attribute('name') name:string) {
|
||||
constructor(
|
||||
parentOutletMap: RouterOutletMap, private location: ViewContainerRef,
|
||||
@Attribute('name') name: string) {
|
||||
parentOutletMap.registerOutlet(name ? name : PRIMARY_OUTLET, this);
|
||||
}
|
||||
|
||||
get isActivated(): boolean { return !!this.activated; }
|
||||
get component(): Object {
|
||||
if (!this.activated) throw new Error("Outlet is not activated");
|
||||
if (!this.activated) throw new Error('Outlet is not activated');
|
||||
return this.activated.instance;
|
||||
}
|
||||
|
||||
|
@ -28,8 +29,9 @@ export class RouterOutlet {
|
|||
}
|
||||
}
|
||||
|
||||
activate(factory: ComponentFactory<any>, providers: ResolvedReflectiveProvider[],
|
||||
outletMap: RouterOutletMap): void {
|
||||
activate(
|
||||
factory: ComponentFactory<any>, providers: ResolvedReflectiveProvider[],
|
||||
outletMap: RouterOutletMap): void {
|
||||
this.outletMap = outletMap;
|
||||
const inj = ReflectiveInjector.fromResolvedProviders(providers, this.location.parentInjector);
|
||||
this.activated = this.location.createComponent(factory, this.location.length, inj, []);
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
export { Router, Event, NavigationStart, NavigationEnd, NavigationCancel, NavigationError } from './router';
|
||||
export { UrlSerializer, DefaultUrlSerializer } from './url_serializer';
|
||||
export { RouterState, ActivatedRoute, RouterStateSnapshot, ActivatedRouteSnapshot } from './router_state';
|
||||
export { UrlTree, UrlSegment} from './url_tree';
|
||||
export { RouterOutletMap } from './router_outlet_map';
|
||||
export { RouterConfig, Route } from './config';
|
||||
export { Params, PRIMARY_OUTLET } from './shared';
|
||||
export { provideRouter } from './router_providers';
|
||||
export { CanActivate, CanDeactivate } from './interfaces';
|
||||
import {RouterLink} from './directives/router_link';
|
||||
import {RouterOutlet} from './directives/router_outlet';
|
||||
|
||||
import { RouterOutlet } from './directives/router_outlet';
|
||||
import { RouterLink } from './directives/router_link';
|
||||
export {Route, RouterConfig} from './config';
|
||||
export {CanActivate, CanDeactivate} from './interfaces';
|
||||
export {Event, NavigationCancel, NavigationEnd, NavigationError, NavigationStart, Router} from './router';
|
||||
export {RouterOutletMap} from './router_outlet_map';
|
||||
export {provideRouter} from './router_providers';
|
||||
export {ActivatedRoute, ActivatedRouteSnapshot, RouterState, RouterStateSnapshot} from './router_state';
|
||||
export {PRIMARY_OUTLET, Params} from './shared';
|
||||
export {DefaultUrlSerializer, UrlSerializer} from './url_serializer';
|
||||
export {UrlSegment, UrlTree} from './url_tree';
|
||||
|
||||
export const ROUTER_DIRECTIVES = [RouterOutlet, RouterLink];
|
|
@ -5,12 +5,14 @@ import {ActivatedRouteSnapshot, RouterStateSnapshot} from './router_state';
|
|||
* An interface a class can implement to be a guard deciding if a route can be activated.
|
||||
*/
|
||||
export interface CanActivate {
|
||||
canActivate(route:ActivatedRouteSnapshot, state:RouterStateSnapshot):Observable<boolean> | boolean;
|
||||
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot):
|
||||
Observable<boolean>|boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* An interface a class can implement to be a guard deciding if a route can be deactivated.
|
||||
*/
|
||||
export interface CanDeactivate<T> {
|
||||
canDeactivate(component:T, route:ActivatedRouteSnapshot, state:RouterStateSnapshot):Observable<boolean> | boolean;
|
||||
canDeactivate(component: T, route: ActivatedRouteSnapshot, state: RouterStateSnapshot):
|
||||
Observable<boolean>|boolean;
|
||||
}
|
|
@ -1,26 +1,31 @@
|
|||
import { UrlTree, UrlSegment } from './url_tree';
|
||||
import { flatten, first, merge } from './utils/collection';
|
||||
import { TreeNode } from './utils/tree';
|
||||
import { RouterStateSnapshot, ActivatedRouteSnapshot } from './router_state';
|
||||
import { PRIMARY_OUTLET } from './shared';
|
||||
import { RouterConfig, Route } from './config';
|
||||
import { Type } from '@angular/core';
|
||||
import { Observable } from 'rxjs/Observable';
|
||||
import {Type} from '@angular/core';
|
||||
import {Observable} from 'rxjs/Observable';
|
||||
|
||||
import {Route, RouterConfig} from './config';
|
||||
import {ActivatedRouteSnapshot, RouterStateSnapshot} from './router_state';
|
||||
import {PRIMARY_OUTLET} from './shared';
|
||||
import {UrlSegment, UrlTree} from './url_tree';
|
||||
import {first, flatten, merge} from './utils/collection';
|
||||
import {TreeNode} from './utils/tree';
|
||||
|
||||
class CannotRecognize {}
|
||||
|
||||
export function recognize(rootComponentType: Type, config: RouterConfig, url: UrlTree): Observable<RouterStateSnapshot> {
|
||||
export function recognize(
|
||||
rootComponentType: Type, config: RouterConfig, url: UrlTree): Observable<RouterStateSnapshot> {
|
||||
try {
|
||||
const match = new MatchResult(rootComponentType, config, [url.root], {}, url._root.children, [], PRIMARY_OUTLET, null, url.root);
|
||||
const match = new MatchResult(
|
||||
rootComponentType, config, [url.root], {}, url._root.children, [], PRIMARY_OUTLET, null,
|
||||
url.root);
|
||||
const roots = constructActivatedRoute(match);
|
||||
const res = new RouterStateSnapshot(roots[0], url.queryParams, url.fragment);
|
||||
return new Observable<RouterStateSnapshot>(obs => {
|
||||
obs.next(res);
|
||||
obs.complete();
|
||||
});
|
||||
} catch(e) {
|
||||
} catch (e) {
|
||||
if (e instanceof CannotRecognize) {
|
||||
return new Observable<RouterStateSnapshot>(obs => obs.error(new Error("Cannot match any routes")));
|
||||
return new Observable<RouterStateSnapshot>(
|
||||
obs => obs.error(new Error('Cannot match any routes')));
|
||||
} else {
|
||||
return new Observable<RouterStateSnapshot>(obs => obs.error(e));
|
||||
}
|
||||
|
@ -30,7 +35,8 @@ export function recognize(rootComponentType: Type, config: RouterConfig, url: Ur
|
|||
function constructActivatedRoute(match: MatchResult): TreeNode<ActivatedRouteSnapshot>[] {
|
||||
const activatedRoute = createActivatedRouteSnapshot(match);
|
||||
const children = match.leftOverUrl.length > 0 ?
|
||||
recognizeMany(match.children, match.leftOverUrl) : recognizeLeftOvers(match.children, match.lastUrlSegment);
|
||||
recognizeMany(match.children, match.leftOverUrl) :
|
||||
recognizeLeftOvers(match.children, match.lastUrlSegment);
|
||||
checkOutletNameUniqueness(children);
|
||||
children.sort((a, b) => {
|
||||
if (a.value.outlet === PRIMARY_OUTLET) return -1;
|
||||
|
@ -40,23 +46,28 @@ function constructActivatedRoute(match: MatchResult): TreeNode<ActivatedRouteSna
|
|||
return [new TreeNode<ActivatedRouteSnapshot>(activatedRoute, children)];
|
||||
}
|
||||
|
||||
function recognizeLeftOvers(config: Route[], lastUrlSegment: UrlSegment): TreeNode<ActivatedRouteSnapshot>[] {
|
||||
function recognizeLeftOvers(
|
||||
config: Route[], lastUrlSegment: UrlSegment): TreeNode<ActivatedRouteSnapshot>[] {
|
||||
if (!config) return [];
|
||||
const mIndex = matchIndex(config, [], lastUrlSegment);
|
||||
return mIndex ? constructActivatedRoute(mIndex) : [];
|
||||
}
|
||||
|
||||
function recognizeMany(config: Route[], urls: TreeNode<UrlSegment>[]): TreeNode<ActivatedRouteSnapshot>[] {
|
||||
function recognizeMany(
|
||||
config: Route[], urls: TreeNode<UrlSegment>[]): TreeNode<ActivatedRouteSnapshot>[] {
|
||||
return flatten(urls.map(url => recognizeOne(config, url)));
|
||||
}
|
||||
|
||||
function createActivatedRouteSnapshot(match: MatchResult): ActivatedRouteSnapshot {
|
||||
return new ActivatedRouteSnapshot(match.consumedUrlSegments, match.parameters, match.outlet, match.component, match.route, match.lastUrlSegment);
|
||||
return new ActivatedRouteSnapshot(
|
||||
match.consumedUrlSegments, match.parameters, match.outlet, match.component, match.route,
|
||||
match.lastUrlSegment);
|
||||
}
|
||||
|
||||
function recognizeOne(config: Route[], url: TreeNode<UrlSegment>): TreeNode<ActivatedRouteSnapshot>[] {
|
||||
function recognizeOne(
|
||||
config: Route[], url: TreeNode<UrlSegment>): TreeNode<ActivatedRouteSnapshot>[] {
|
||||
const matches = match(config, url);
|
||||
for(let match of matches) {
|
||||
for (let match of matches) {
|
||||
try {
|
||||
const primary = constructActivatedRoute(match);
|
||||
const secondary = recognizeMany(config, match.secondary);
|
||||
|
@ -64,7 +75,7 @@ function recognizeOne(config: Route[], url: TreeNode<UrlSegment>): TreeNode<Acti
|
|||
checkOutletNameUniqueness(res);
|
||||
return res;
|
||||
} catch (e) {
|
||||
if (! (e instanceof CannotRecognize)) {
|
||||
if (!(e instanceof CannotRecognize)) {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
@ -72,13 +83,14 @@ function recognizeOne(config: Route[], url: TreeNode<UrlSegment>): TreeNode<Acti
|
|||
throw new CannotRecognize();
|
||||
}
|
||||
|
||||
function checkOutletNameUniqueness(nodes: TreeNode<ActivatedRouteSnapshot>[]): TreeNode<ActivatedRouteSnapshot>[] {
|
||||
function checkOutletNameUniqueness(nodes: TreeNode<ActivatedRouteSnapshot>[]):
|
||||
TreeNode<ActivatedRouteSnapshot>[] {
|
||||
let names = {};
|
||||
nodes.forEach(n => {
|
||||
let routeWithSameOutletName = names[n.value.outlet];
|
||||
if (routeWithSameOutletName) {
|
||||
const p = routeWithSameOutletName.urlSegments.map(s => s.toString()).join("/");
|
||||
const c = n.value.urlSegments.map(s => s.toString()).join("/");
|
||||
const p = routeWithSameOutletName.urlSegments.map(s => s.toString()).join('/');
|
||||
const c = n.value.urlSegments.map(s => s.toString()).join('/');
|
||||
throw new Error(`Two segments cannot have the same outlet name: '${p}' and '${c}'.`);
|
||||
}
|
||||
names[n.value.outlet] = n.value;
|
||||
|
@ -99,13 +111,18 @@ function match(config: Route[], url: TreeNode<UrlSegment>): MatchResult[] {
|
|||
return res;
|
||||
}
|
||||
|
||||
function createIndexMatch(r: Route, leftOverUrls:TreeNode<UrlSegment>[], lastUrlSegment:UrlSegment): MatchResult {
|
||||
function createIndexMatch(
|
||||
r: Route, leftOverUrls: TreeNode<UrlSegment>[], lastUrlSegment: UrlSegment): MatchResult {
|
||||
const outlet = r.outlet ? r.outlet : PRIMARY_OUTLET;
|
||||
const children = r.children ? r.children : [];
|
||||
return new MatchResult(r.component, children, [], lastUrlSegment.parameters, leftOverUrls, [], outlet, r, lastUrlSegment);
|
||||
return new MatchResult(
|
||||
r.component, children, [], lastUrlSegment.parameters, leftOverUrls, [], outlet, r,
|
||||
lastUrlSegment);
|
||||
}
|
||||
|
||||
function matchIndex(config: Route[], leftOverUrls: TreeNode<UrlSegment>[], lastUrlSegment: UrlSegment): MatchResult | null {
|
||||
function matchIndex(
|
||||
config: Route[], leftOverUrls: TreeNode<UrlSegment>[], lastUrlSegment: UrlSegment): MatchResult|
|
||||
null {
|
||||
for (let r of config) {
|
||||
if (r.index) {
|
||||
return createIndexMatch(r, leftOverUrls, lastUrlSegment);
|
||||
|
@ -114,23 +131,24 @@ function matchIndex(config: Route[], leftOverUrls: TreeNode<UrlSegment>[], lastU
|
|||
return null;
|
||||
}
|
||||
|
||||
function matchWithParts(route: Route, url: TreeNode<UrlSegment>): MatchResult | null {
|
||||
function matchWithParts(route: Route, url: TreeNode<UrlSegment>): MatchResult|null {
|
||||
if (!route.path) return null;
|
||||
if ((route.outlet ? route.outlet : PRIMARY_OUTLET) !== url.value.outlet) return null;
|
||||
|
||||
const path = route.path.startsWith("/") ? route.path.substring(1) : route.path;
|
||||
if (path === "**") {
|
||||
const path = route.path.startsWith('/') ? route.path.substring(1) : route.path;
|
||||
if (path === '**') {
|
||||
const consumedUrl = [];
|
||||
let u:TreeNode<UrlSegment>|null = url;
|
||||
let u: TreeNode<UrlSegment>|null = url;
|
||||
while (u) {
|
||||
consumedUrl.push(u.value);
|
||||
u = first(u.children);
|
||||
}
|
||||
const last = consumedUrl[consumedUrl.length - 1];
|
||||
return new MatchResult(route.component, [], consumedUrl, last.parameters, [], [], PRIMARY_OUTLET, route, last);
|
||||
return new MatchResult(
|
||||
route.component, [], consumedUrl, last.parameters, [], [], PRIMARY_OUTLET, route, last);
|
||||
}
|
||||
|
||||
const parts = path.split("/");
|
||||
const parts = path.split('/');
|
||||
const positionalParams = {};
|
||||
const consumedUrlSegments = [];
|
||||
|
||||
|
@ -144,7 +162,7 @@ function matchWithParts(route: Route, url: TreeNode<UrlSegment>): MatchResult |
|
|||
const p = parts[i];
|
||||
const isLastSegment = i === parts.length - 1;
|
||||
const isLastParent = i === parts.length - 2;
|
||||
const isPosParam = p.startsWith(":");
|
||||
const isPosParam = p.startsWith(':');
|
||||
|
||||
if (!isPosParam && p != current.value.path) return null;
|
||||
if (isLastSegment) {
|
||||
|
@ -163,7 +181,7 @@ function matchWithParts(route: Route, url: TreeNode<UrlSegment>): MatchResult |
|
|||
current = first(current.children);
|
||||
}
|
||||
|
||||
if (!lastSegment) throw "Cannot be reached";
|
||||
if (!lastSegment) throw 'Cannot be reached';
|
||||
|
||||
const p = lastSegment.value.parameters;
|
||||
const parameters = <{[key: string]: string}>merge(p, positionalParams);
|
||||
|
@ -171,19 +189,15 @@ function matchWithParts(route: Route, url: TreeNode<UrlSegment>): MatchResult |
|
|||
const children = route.children ? route.children : [];
|
||||
const outlet = route.outlet ? route.outlet : PRIMARY_OUTLET;
|
||||
|
||||
return new MatchResult(route.component, children, consumedUrlSegments, parameters, lastSegment.children,
|
||||
secondarySubtrees, outlet, route, lastSegment.value);
|
||||
return new MatchResult(
|
||||
route.component, children, consumedUrlSegments, parameters, lastSegment.children,
|
||||
secondarySubtrees, outlet, route, lastSegment.value);
|
||||
}
|
||||
|
||||
class MatchResult {
|
||||
constructor(public component: Type | string,
|
||||
public children: Route[],
|
||||
public consumedUrlSegments: UrlSegment[],
|
||||
public parameters: {[key: string]: string},
|
||||
public leftOverUrl: TreeNode<UrlSegment>[],
|
||||
public secondary: TreeNode<UrlSegment>[],
|
||||
public outlet: string,
|
||||
public route: Route | null,
|
||||
public lastUrlSegment: UrlSegment
|
||||
) {}
|
||||
constructor(
|
||||
public component: Type|string, public children: Route[],
|
||||
public consumedUrlSegments: UrlSegment[], public parameters: {[key: string]: string},
|
||||
public leftOverUrl: TreeNode<UrlSegment>[], public secondary: TreeNode<UrlSegment>[],
|
||||
public outlet: string, public route: Route|null, public lastUrlSegment: UrlSegment) {}
|
||||
}
|
|
@ -1,28 +1,33 @@
|
|||
import { RouterStateSnapshot, ActivatedRouteSnapshot } from './router_state';
|
||||
import { TreeNode } from './utils/tree';
|
||||
import { ComponentResolver } from '@angular/core';
|
||||
import { Observable } from 'rxjs/Observable';
|
||||
import 'rxjs/add/operator/map';
|
||||
import {forkJoin} from 'rxjs/observable/forkJoin';
|
||||
import {fromPromise} from 'rxjs/observable/fromPromise';
|
||||
import 'rxjs/add/operator/toPromise';
|
||||
|
||||
export function resolve(resolver: ComponentResolver, state: RouterStateSnapshot): Observable<RouterStateSnapshot> {
|
||||
import {ComponentResolver} from '@angular/core';
|
||||
import {Observable} from 'rxjs/Observable';
|
||||
import {forkJoin} from 'rxjs/observable/forkJoin';
|
||||
import {fromPromise} from 'rxjs/observable/fromPromise';
|
||||
|
||||
import {ActivatedRouteSnapshot, RouterStateSnapshot} from './router_state';
|
||||
import {TreeNode} from './utils/tree';
|
||||
|
||||
export function resolve(
|
||||
resolver: ComponentResolver, state: RouterStateSnapshot): Observable<RouterStateSnapshot> {
|
||||
return resolveNode(resolver, state._root).map(_ => state);
|
||||
}
|
||||
|
||||
function resolveNode(resolver: ComponentResolver, node: TreeNode<ActivatedRouteSnapshot>): Observable<any> {
|
||||
function resolveNode(
|
||||
resolver: ComponentResolver, node: TreeNode<ActivatedRouteSnapshot>): Observable<any> {
|
||||
if (node.children.length === 0) {
|
||||
return fromPromise(resolver.resolveComponent(<any>node.value.component).then(factory => {
|
||||
node.value._resolvedComponentFactory = factory;
|
||||
return node.value;
|
||||
}));
|
||||
|
||||
|
||||
} else {
|
||||
const c = node.children.map(c => resolveNode(resolver, c).toPromise());
|
||||
return forkJoin(c).map(_ => resolver.resolveComponent(<any>node.value.component).then(factory => {
|
||||
node.value._resolvedComponentFactory = factory;
|
||||
return node.value;
|
||||
}));
|
||||
return forkJoin(c).map(
|
||||
_ => resolver.resolveComponent(<any>node.value.component).then(factory => {
|
||||
node.value._resolvedComponentFactory = factory;
|
||||
return node.value;
|
||||
}));
|
||||
}
|
||||
}
|
|
@ -1,50 +1,64 @@
|
|||
import { ComponentResolver, ReflectiveInjector, Type, Injector } from '@angular/core';
|
||||
import { Location } from '@angular/common';
|
||||
import { UrlSerializer } from './url_serializer';
|
||||
import { RouterOutletMap } from './router_outlet_map';
|
||||
import { recognize } from './recognize';
|
||||
import { resolve } from './resolve';
|
||||
import { createRouterState } from './create_router_state';
|
||||
import { TreeNode } from './utils/tree';
|
||||
import { UrlTree, createEmptyUrlTree } from './url_tree';
|
||||
import { PRIMARY_OUTLET, Params } from './shared';
|
||||
import { createEmptyState, RouterState, RouterStateSnapshot, ActivatedRoute, ActivatedRouteSnapshot, advanceActivatedRoute} from './router_state';
|
||||
import { RouterConfig } from './config';
|
||||
import { RouterOutlet } from './directives/router_outlet';
|
||||
import { createUrlTree } from './create_url_tree';
|
||||
import { forEach, and, shallowEqual } from './utils/collection';
|
||||
import { Observable } from 'rxjs/Observable';
|
||||
import { Subscription } from 'rxjs/Subscription';
|
||||
import { Subject } from 'rxjs/Subject';
|
||||
import 'rxjs/add/operator/map';
|
||||
import 'rxjs/add/operator/scan';
|
||||
import 'rxjs/add/operator/mergeMap';
|
||||
import 'rxjs/add/operator/concat';
|
||||
import 'rxjs/add/operator/concatMap';
|
||||
import {of} from 'rxjs/observable/of';
|
||||
import {forkJoin} from 'rxjs/observable/forkJoin';
|
||||
|
||||
export interface NavigationExtras { relativeTo?: ActivatedRoute; queryParams?: Params; fragment?: string; }
|
||||
import {Location} from '@angular/common';
|
||||
import {ComponentResolver, Injector, ReflectiveInjector, Type} from '@angular/core';
|
||||
import {Observable} from 'rxjs/Observable';
|
||||
import {Subject} from 'rxjs/Subject';
|
||||
import {Subscription} from 'rxjs/Subscription';
|
||||
import {forkJoin} from 'rxjs/observable/forkJoin';
|
||||
import {of } from 'rxjs/observable/of';
|
||||
|
||||
import {RouterConfig} from './config';
|
||||
import {createRouterState} from './create_router_state';
|
||||
import {createUrlTree} from './create_url_tree';
|
||||
import {RouterOutlet} from './directives/router_outlet';
|
||||
import {recognize} from './recognize';
|
||||
import {resolve} from './resolve';
|
||||
import {RouterOutletMap} from './router_outlet_map';
|
||||
import {ActivatedRoute, ActivatedRouteSnapshot, RouterState, RouterStateSnapshot, advanceActivatedRoute, createEmptyState} from './router_state';
|
||||
import {PRIMARY_OUTLET, Params} from './shared';
|
||||
import {UrlSerializer} from './url_serializer';
|
||||
import {UrlTree, createEmptyUrlTree} from './url_tree';
|
||||
import {and, forEach, shallowEqual} from './utils/collection';
|
||||
import {TreeNode} from './utils/tree';
|
||||
|
||||
export interface NavigationExtras {
|
||||
relativeTo?: ActivatedRoute;
|
||||
queryParams?: Params;
|
||||
fragment?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* An event triggered when a navigation starts
|
||||
*/
|
||||
export class NavigationStart { constructor(public id:number, public url:UrlTree) {} }
|
||||
export class NavigationStart {
|
||||
constructor(public id: number, public url: UrlTree) {}
|
||||
}
|
||||
|
||||
/**
|
||||
* An event triggered when a navigation ends successfully
|
||||
*/
|
||||
export class NavigationEnd { constructor(public id:number, public url:UrlTree) {} }
|
||||
export class NavigationEnd {
|
||||
constructor(public id: number, public url: UrlTree) {}
|
||||
}
|
||||
|
||||
/**
|
||||
* An event triggered when a navigation is canceled
|
||||
*/
|
||||
export class NavigationCancel { constructor(public id:number, public url:UrlTree) {} }
|
||||
export class NavigationCancel {
|
||||
constructor(public id: number, public url: UrlTree) {}
|
||||
}
|
||||
|
||||
/**
|
||||
* An event triggered when a navigation fails due to unexpected error
|
||||
*/
|
||||
export class NavigationError { constructor(public id:number, public url:UrlTree, public error:any) {} }
|
||||
export class NavigationError {
|
||||
constructor(public id: number, public url: UrlTree, public error: any) {}
|
||||
}
|
||||
|
||||
export type Event = NavigationStart | NavigationEnd | NavigationCancel | NavigationError;
|
||||
|
||||
|
@ -61,7 +75,10 @@ export class Router {
|
|||
/**
|
||||
* @internal
|
||||
*/
|
||||
constructor(private rootComponentType:Type, private resolver: ComponentResolver, private urlSerializer: UrlSerializer, private outletMap: RouterOutletMap, private location: Location, private injector: Injector, private config: RouterConfig) {
|
||||
constructor(
|
||||
private rootComponentType: Type, private resolver: ComponentResolver,
|
||||
private urlSerializer: UrlSerializer, private outletMap: RouterOutletMap,
|
||||
private location: Location, private injector: Injector, private config: RouterConfig) {
|
||||
this.routerEvents = new Subject<Event>();
|
||||
this.currentUrlTree = createEmptyUrlTree();
|
||||
this.currentRouterState = createEmptyState(this.rootComponentType);
|
||||
|
@ -70,7 +87,7 @@ export class Router {
|
|||
/**
|
||||
* @internal
|
||||
*/
|
||||
initialNavigation():void {
|
||||
initialNavigation(): void {
|
||||
this.setUpLocationChangeListener();
|
||||
this.navigateByUrl(this.location.path());
|
||||
}
|
||||
|
@ -78,23 +95,17 @@ export class Router {
|
|||
/**
|
||||
* Returns the current route state.
|
||||
*/
|
||||
get routerState(): RouterState {
|
||||
return this.currentRouterState;
|
||||
}
|
||||
get routerState(): RouterState { return this.currentRouterState; }
|
||||
|
||||
/**
|
||||
* Returns the current url tree.
|
||||
*/
|
||||
get urlTree(): UrlTree {
|
||||
return this.currentUrlTree;
|
||||
}
|
||||
get urlTree(): UrlTree { return this.currentUrlTree; }
|
||||
|
||||
/**
|
||||
* Returns an observable of route events
|
||||
*/
|
||||
get events(): Observable<Event> {
|
||||
return this.routerEvents;
|
||||
}
|
||||
get events(): Observable<Event> { return this.routerEvents; }
|
||||
|
||||
/**
|
||||
* Navigate based on the provided url. This navigation is always absolute.
|
||||
|
@ -129,9 +140,7 @@ export class Router {
|
|||
* ]);
|
||||
* ```
|
||||
*/
|
||||
resetConfig(config: RouterConfig): void {
|
||||
this.config = config;
|
||||
}
|
||||
resetConfig(config: RouterConfig): void { this.config = config; }
|
||||
|
||||
/**
|
||||
* @internal
|
||||
|
@ -169,7 +178,8 @@ export class Router {
|
|||
* router.createUrlTree(['../../team/44/user/22'], {relativeTo: route});
|
||||
* ```
|
||||
*/
|
||||
createUrlTree(commands: any[], {relativeTo, queryParams, fragment}: NavigationExtras = {}): UrlTree {
|
||||
createUrlTree(commands: any[], {relativeTo, queryParams, fragment}: NavigationExtras = {}):
|
||||
UrlTree {
|
||||
const a = relativeTo ? relativeTo : this.routerState.root;
|
||||
return createUrlTree(a, this.currentUrlTree, commands, queryParams, fragment);
|
||||
}
|
||||
|
@ -204,8 +214,8 @@ export class Router {
|
|||
*/
|
||||
parseUrl(url: string): UrlTree { return this.urlSerializer.parse(url); }
|
||||
|
||||
private scheduleNavigation(url: UrlTree, pop: boolean):Promise<boolean> {
|
||||
const id = ++ this.navigationId;
|
||||
private scheduleNavigation(url: UrlTree, pop: boolean): Promise<boolean> {
|
||||
const id = ++this.navigationId;
|
||||
this.routerEvents.next(new NavigationStart(id, url));
|
||||
return Promise.resolve().then((_) => this.runNavigate(url, false, id));
|
||||
}
|
||||
|
@ -216,7 +226,7 @@ export class Router {
|
|||
});
|
||||
}
|
||||
|
||||
private runNavigate(url: UrlTree, pop: boolean, id: number):Promise<boolean> {
|
||||
private runNavigate(url: UrlTree, pop: boolean, id: number): Promise<boolean> {
|
||||
if (id !== this.navigationId) {
|
||||
this.routerEvents.next(new NavigationCancel(id, url));
|
||||
return Promise.resolve(false);
|
||||
|
@ -224,69 +234,85 @@ export class Router {
|
|||
|
||||
return new Promise((resolvePromise, rejectPromise) => {
|
||||
let state;
|
||||
recognize(this.rootComponentType, this.config, url).mergeMap((newRouterStateSnapshot) => {
|
||||
return resolve(this.resolver, newRouterStateSnapshot);
|
||||
recognize(this.rootComponentType, this.config, url)
|
||||
.mergeMap((newRouterStateSnapshot) => {
|
||||
return resolve(this.resolver, newRouterStateSnapshot);
|
||||
|
||||
}).map((routerStateSnapshot) => {
|
||||
return createRouterState(routerStateSnapshot, this.currentRouterState);
|
||||
})
|
||||
.map((routerStateSnapshot) => {
|
||||
return createRouterState(routerStateSnapshot, this.currentRouterState);
|
||||
|
||||
}).map((newState:RouterState) => {
|
||||
state = newState;
|
||||
})
|
||||
.map((newState: RouterState) => {
|
||||
state = newState;
|
||||
|
||||
}).mergeMap(_ => {
|
||||
return new GuardChecks(state.snapshot, this.currentRouterState.snapshot, this.injector).check(this.outletMap);
|
||||
})
|
||||
.mergeMap(_ => {
|
||||
return new GuardChecks(state.snapshot, this.currentRouterState.snapshot, this.injector)
|
||||
.check(this.outletMap);
|
||||
|
||||
}).forEach((shouldActivate) => {
|
||||
if (!shouldActivate || id !== this.navigationId) {
|
||||
this.routerEvents.next(new NavigationCancel(id, url));
|
||||
return Promise.resolve(false);
|
||||
}
|
||||
})
|
||||
.forEach((shouldActivate) => {
|
||||
if (!shouldActivate || id !== this.navigationId) {
|
||||
this.routerEvents.next(new NavigationCancel(id, url));
|
||||
return Promise.resolve(false);
|
||||
}
|
||||
|
||||
new ActivateRoutes(state, this.currentRouterState).activate(this.outletMap);
|
||||
new ActivateRoutes(state, this.currentRouterState).activate(this.outletMap);
|
||||
|
||||
this.currentUrlTree = url;
|
||||
this.currentRouterState = state;
|
||||
if (!pop) {
|
||||
this.location.go(this.urlSerializer.serialize(url));
|
||||
}
|
||||
}).then(() => {
|
||||
this.routerEvents.next(new NavigationEnd(id, url));
|
||||
resolvePromise(true);
|
||||
this.currentUrlTree = url;
|
||||
this.currentRouterState = state;
|
||||
if (!pop) {
|
||||
this.location.go(this.urlSerializer.serialize(url));
|
||||
}
|
||||
})
|
||||
.then(
|
||||
() => {
|
||||
this.routerEvents.next(new NavigationEnd(id, url));
|
||||
resolvePromise(true);
|
||||
|
||||
}, e => {
|
||||
this.routerEvents.next(new NavigationError(id, url, e));
|
||||
rejectPromise(e);
|
||||
});
|
||||
},
|
||||
e => {
|
||||
this.routerEvents.next(new NavigationError(id, url, e));
|
||||
rejectPromise(e);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
class CanActivate { constructor(public route: ActivatedRouteSnapshot) {}}
|
||||
class CanDeactivate { constructor(public component: Object, public route: ActivatedRouteSnapshot) {}}
|
||||
class CanActivate {
|
||||
constructor(public route: ActivatedRouteSnapshot) {}
|
||||
}
|
||||
class CanDeactivate {
|
||||
constructor(public component: Object, public route: ActivatedRouteSnapshot) {}
|
||||
}
|
||||
|
||||
class GuardChecks {
|
||||
private checks = [];
|
||||
constructor(private future: RouterStateSnapshot, private curr: RouterStateSnapshot, private injector: Injector) {}
|
||||
constructor(
|
||||
private future: RouterStateSnapshot, private curr: RouterStateSnapshot,
|
||||
private injector: Injector) {}
|
||||
|
||||
check(parentOutletMap: RouterOutletMap): Observable<boolean> {
|
||||
const futureRoot = this.future._root;
|
||||
const currRoot = this.curr ? this.curr._root : null;
|
||||
this.traverseChildRoutes(futureRoot, currRoot, parentOutletMap);
|
||||
if (this.checks.length === 0) return of(true);
|
||||
if (this.checks.length === 0) return of (true);
|
||||
return forkJoin(this.checks.map(s => {
|
||||
if (s instanceof CanActivate) {
|
||||
return this.runCanActivate(s.route);
|
||||
} else if (s instanceof CanDeactivate) {
|
||||
return this.runCanDeactivate(s.component, s.route);
|
||||
} else {
|
||||
throw new Error("Cannot be reached");
|
||||
}
|
||||
})).map(and);
|
||||
if (s instanceof CanActivate) {
|
||||
return this.runCanActivate(s.route);
|
||||
} else if (s instanceof CanDeactivate) {
|
||||
return this.runCanDeactivate(s.component, s.route);
|
||||
} else {
|
||||
throw new Error('Cannot be reached');
|
||||
}
|
||||
}))
|
||||
.map(and);
|
||||
}
|
||||
|
||||
private traverseChildRoutes(futureNode: TreeNode<ActivatedRouteSnapshot>,
|
||||
currNode: TreeNode<ActivatedRouteSnapshot> | null,
|
||||
outletMap: RouterOutletMap | null): void {
|
||||
private traverseChildRoutes(
|
||||
futureNode: TreeNode<ActivatedRouteSnapshot>, currNode: TreeNode<ActivatedRouteSnapshot>|null,
|
||||
outletMap: RouterOutletMap|null): void {
|
||||
const prevChildren = nodeChildrenAsMap(currNode);
|
||||
futureNode.children.forEach(c => {
|
||||
this.traverseRoutes(c, prevChildren[c.value.outlet], outletMap);
|
||||
|
@ -295,8 +321,9 @@ class GuardChecks {
|
|||
forEach(prevChildren, (v, k) => this.deactivateOutletAndItChildren(v, outletMap._outlets[k]));
|
||||
}
|
||||
|
||||
traverseRoutes(futureNode: TreeNode<ActivatedRouteSnapshot>, currNode: TreeNode<ActivatedRouteSnapshot> | null,
|
||||
parentOutletMap: RouterOutletMap | null): void {
|
||||
traverseRoutes(
|
||||
futureNode: TreeNode<ActivatedRouteSnapshot>, currNode: TreeNode<ActivatedRouteSnapshot>|null,
|
||||
parentOutletMap: RouterOutletMap|null): void {
|
||||
const future = futureNode.value;
|
||||
const curr = currNode ? currNode.value : null;
|
||||
const outlet = parentOutletMap ? parentOutletMap._outlets[futureNode.value.outlet] : null;
|
||||
|
@ -315,35 +342,39 @@ class GuardChecks {
|
|||
|
||||
private deactivateOutletAndItChildren(route: ActivatedRouteSnapshot, outlet: RouterOutlet): void {
|
||||
if (outlet && outlet.isActivated) {
|
||||
forEach(outlet.outletMap._outlets, (v, k) => this.deactivateOutletAndItChildren(v, outlet.outletMap._outlets[k]));
|
||||
forEach(
|
||||
outlet.outletMap._outlets,
|
||||
(v, k) => this.deactivateOutletAndItChildren(v, outlet.outletMap._outlets[k]));
|
||||
this.checks.push(new CanDeactivate(outlet.component, route));
|
||||
}
|
||||
}
|
||||
|
||||
private runCanActivate(future: ActivatedRouteSnapshot): Observable<boolean> {
|
||||
const canActivate = future._routeConfig ? future._routeConfig.canActivate : null;
|
||||
if (!canActivate || canActivate.length === 0) return of(true);
|
||||
if (!canActivate || canActivate.length === 0) return of (true);
|
||||
return forkJoin(canActivate.map(c => {
|
||||
const guard = this.injector.get(c);
|
||||
if (guard.canActivate) {
|
||||
return wrapIntoObservable(guard.canActivate(future, this.future));
|
||||
} else {
|
||||
return wrapIntoObservable(guard(future, this.future));
|
||||
}
|
||||
})).map(and);
|
||||
const guard = this.injector.get(c);
|
||||
if (guard.canActivate) {
|
||||
return wrapIntoObservable(guard.canActivate(future, this.future));
|
||||
} else {
|
||||
return wrapIntoObservable(guard(future, this.future));
|
||||
}
|
||||
}))
|
||||
.map(and);
|
||||
}
|
||||
|
||||
private runCanDeactivate(component: Object, curr: ActivatedRouteSnapshot): Observable<boolean> {
|
||||
const canDeactivate = curr._routeConfig ? curr._routeConfig.canDeactivate : null;
|
||||
if (!canDeactivate || canDeactivate.length === 0) return of(true);
|
||||
if (!canDeactivate || canDeactivate.length === 0) return of (true);
|
||||
return forkJoin(canDeactivate.map(c => {
|
||||
const guard = this.injector.get(c);
|
||||
if (guard.canDeactivate) {
|
||||
return wrapIntoObservable(guard.canDeactivate(component, curr, this.curr));
|
||||
} else {
|
||||
return wrapIntoObservable(guard(component, curr, this.curr));
|
||||
}
|
||||
})).map(and);
|
||||
const guard = this.injector.get(c);
|
||||
if (guard.canDeactivate) {
|
||||
return wrapIntoObservable(guard.canDeactivate(component, curr, this.curr));
|
||||
} else {
|
||||
return wrapIntoObservable(guard(component, curr, this.curr));
|
||||
}
|
||||
}))
|
||||
.map(and);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -351,14 +382,14 @@ function wrapIntoObservable<T>(value: T | Observable<T>): Observable<T> {
|
|||
if (value instanceof Observable) {
|
||||
return value;
|
||||
} else {
|
||||
return of(value);
|
||||
return of (value);
|
||||
}
|
||||
}
|
||||
|
||||
class ActivateRoutes {
|
||||
constructor(private futureState: RouterState, private currState: RouterState) {}
|
||||
|
||||
activate(parentOutletMap: RouterOutletMap):void {
|
||||
activate(parentOutletMap: RouterOutletMap): void {
|
||||
const futureRoot = this.futureState._root;
|
||||
const currRoot = this.currState ? this.currState._root : null;
|
||||
|
||||
|
@ -366,9 +397,9 @@ class ActivateRoutes {
|
|||
this.activateChildRoutes(futureRoot, currRoot, parentOutletMap);
|
||||
}
|
||||
|
||||
private activateChildRoutes(futureNode: TreeNode<ActivatedRoute>,
|
||||
currNode: TreeNode<ActivatedRoute> | null,
|
||||
outletMap: RouterOutletMap): void {
|
||||
private activateChildRoutes(
|
||||
futureNode: TreeNode<ActivatedRoute>, currNode: TreeNode<ActivatedRoute>|null,
|
||||
outletMap: RouterOutletMap): void {
|
||||
const prevChildren = nodeChildrenAsMap(currNode);
|
||||
futureNode.children.forEach(c => {
|
||||
this.activateRoutes(c, prevChildren[c.value.outlet], outletMap);
|
||||
|
@ -377,8 +408,9 @@ class ActivateRoutes {
|
|||
forEach(prevChildren, (v, k) => this.deactivateOutletAndItChildren(outletMap._outlets[k]));
|
||||
}
|
||||
|
||||
activateRoutes(futureNode: TreeNode<ActivatedRoute>, currNode: TreeNode<ActivatedRoute> | null,
|
||||
parentOutletMap: RouterOutletMap): void {
|
||||
activateRoutes(
|
||||
futureNode: TreeNode<ActivatedRoute>, currNode: TreeNode<ActivatedRoute>|null,
|
||||
parentOutletMap: RouterOutletMap): void {
|
||||
const future = futureNode.value;
|
||||
const curr = currNode ? currNode.value : null;
|
||||
const outlet = getOutlet(parentOutletMap, futureNode.value);
|
||||
|
@ -394,7 +426,8 @@ class ActivateRoutes {
|
|||
}
|
||||
}
|
||||
|
||||
private activateNewRoutes(outletMap: RouterOutletMap, future: ActivatedRoute, outlet: RouterOutlet): void {
|
||||
private activateNewRoutes(
|
||||
outletMap: RouterOutletMap, future: ActivatedRoute, outlet: RouterOutlet): void {
|
||||
const resolved = ReflectiveInjector.resolve([
|
||||
{provide: ActivatedRoute, useValue: future},
|
||||
{provide: RouterOutletMap, useValue: outletMap}
|
||||
|
@ -421,15 +454,11 @@ function pushQueryParamsAndFragment(state: RouterState): void {
|
|||
}
|
||||
}
|
||||
|
||||
function nodeChildrenAsMap(node: TreeNode<any>|null) {
|
||||
return node ?
|
||||
node.children.reduce(
|
||||
(m, c) => {
|
||||
m[c.value.outlet] = c;
|
||||
return m;
|
||||
},
|
||||
{}) :
|
||||
{};
|
||||
function nodeChildrenAsMap(node: TreeNode<any>| null) {
|
||||
return node ? node.children.reduce((m, c) => {
|
||||
m[c.value.outlet] = c;
|
||||
return m;
|
||||
}, {}) : {};
|
||||
}
|
||||
|
||||
function getOutlet(outletMap: RouterOutletMap, route: ActivatedRoute): RouterOutlet {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { RouterOutlet } from './directives/router_outlet';
|
||||
import {RouterOutlet} from './directives/router_outlet';
|
||||
|
||||
/**
|
||||
* @internal
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
import { RouterConfig } from './config';
|
||||
import * as common from './common_router_providers';
|
||||
import {BrowserPlatformLocation} from '@angular/platform-browser';
|
||||
import {PlatformLocation} from '@angular/common';
|
||||
import {BrowserPlatformLocation} from '@angular/platform-browser';
|
||||
|
||||
import * as common from './common_router_providers';
|
||||
import {RouterConfig} from './config';
|
||||
|
||||
|
||||
/**
|
||||
* A list of {@link Provider}s. To use the router, you must add this to your application.
|
||||
|
@ -13,7 +15,7 @@ import {PlatformLocation} from '@angular/common';
|
|||
* class AppCmp {
|
||||
* // ...
|
||||
* }
|
||||
*
|
||||
*
|
||||
* const router = [
|
||||
* {path: '/home', component: Home}
|
||||
* ];
|
||||
|
@ -21,9 +23,8 @@ import {PlatformLocation} from '@angular/common';
|
|||
* bootstrap(AppCmp, [provideRouter(router)]);
|
||||
* ```
|
||||
*/
|
||||
export function provideRouter(config: RouterConfig):any[] {
|
||||
export function provideRouter(config: RouterConfig): any[] {
|
||||
return [
|
||||
{provide: PlatformLocation, useClass: BrowserPlatformLocation},
|
||||
...common.provideRouter(config)
|
||||
{provide: PlatformLocation, useClass: BrowserPlatformLocation}, ...common.provideRouter(config)
|
||||
];
|
||||
}
|
||||
|
|
|
@ -1,11 +1,13 @@
|
|||
import { Tree, TreeNode } from './utils/tree';
|
||||
import { shallowEqual } from './utils/collection';
|
||||
import { UrlSegment } from './url_tree';
|
||||
import { Route } from './config';
|
||||
import { Params, PRIMARY_OUTLET } from './shared';
|
||||
import { Observable } from 'rxjs/Observable';
|
||||
import { BehaviorSubject } from 'rxjs/BehaviorSubject';
|
||||
import { Type, ComponentFactory } from '@angular/core';
|
||||
import {ComponentFactory, Type} from '@angular/core';
|
||||
import {BehaviorSubject} from 'rxjs/BehaviorSubject';
|
||||
import {Observable} from 'rxjs/Observable';
|
||||
|
||||
import {Route} from './config';
|
||||
import {PRIMARY_OUTLET, Params} from './shared';
|
||||
import {UrlSegment} from './url_tree';
|
||||
import {shallowEqual} from './utils/collection';
|
||||
import {Tree, TreeNode} from './utils/tree';
|
||||
|
||||
|
||||
/**
|
||||
* The state of the router.
|
||||
|
@ -26,34 +28,41 @@ export class RouterState extends Tree<ActivatedRoute> {
|
|||
/**
|
||||
* @internal
|
||||
*/
|
||||
constructor(root: TreeNode<ActivatedRoute>, public queryParams: Observable<Params>, public fragment: Observable<string>, public snapshot: RouterStateSnapshot) {
|
||||
constructor(
|
||||
root: TreeNode<ActivatedRoute>, public queryParams: Observable<Params>,
|
||||
public fragment: Observable<string>, public snapshot: RouterStateSnapshot) {
|
||||
super(root);
|
||||
}
|
||||
}
|
||||
|
||||
export function createEmptyState(rootComponent: Type): RouterState {
|
||||
const snapshot = createEmptyStateSnapshot(rootComponent);
|
||||
const emptyUrl = new BehaviorSubject([new UrlSegment("", {}, PRIMARY_OUTLET)]);
|
||||
const emptyUrl = new BehaviorSubject([new UrlSegment('', {}, PRIMARY_OUTLET)]);
|
||||
const emptyParams = new BehaviorSubject({});
|
||||
const emptyQueryParams = new BehaviorSubject({});
|
||||
const fragment = new BehaviorSubject("");
|
||||
const activated = new ActivatedRoute(emptyUrl, emptyParams, PRIMARY_OUTLET, rootComponent, snapshot.root);
|
||||
const fragment = new BehaviorSubject('');
|
||||
const activated =
|
||||
new ActivatedRoute(emptyUrl, emptyParams, PRIMARY_OUTLET, rootComponent, snapshot.root);
|
||||
activated.snapshot = snapshot.root;
|
||||
return new RouterState(new TreeNode<ActivatedRoute>(activated, []), emptyQueryParams, fragment, snapshot);
|
||||
return new RouterState(
|
||||
new TreeNode<ActivatedRoute>(activated, []), emptyQueryParams, fragment, snapshot);
|
||||
}
|
||||
|
||||
function createEmptyStateSnapshot(rootComponent: Type): RouterStateSnapshot {
|
||||
const rootUrlSegment = new UrlSegment("", {}, PRIMARY_OUTLET);
|
||||
const rootUrlSegment = new UrlSegment('', {}, PRIMARY_OUTLET);
|
||||
const emptyUrl = [rootUrlSegment];
|
||||
const emptyParams = {};
|
||||
const emptyQueryParams = {};
|
||||
const fragment = "";
|
||||
const activated = new ActivatedRouteSnapshot(emptyUrl, emptyParams, PRIMARY_OUTLET, rootComponent, null, rootUrlSegment);
|
||||
return new RouterStateSnapshot(new TreeNode<ActivatedRouteSnapshot>(activated, []), emptyQueryParams, fragment);
|
||||
const fragment = '';
|
||||
const activated = new ActivatedRouteSnapshot(
|
||||
emptyUrl, emptyParams, PRIMARY_OUTLET, rootComponent, null, rootUrlSegment);
|
||||
return new RouterStateSnapshot(
|
||||
new TreeNode<ActivatedRouteSnapshot>(activated, []), emptyQueryParams, fragment);
|
||||
}
|
||||
|
||||
/**
|
||||
* Contains the information about a component loaded in an outlet. The information is provided through
|
||||
* Contains the information about a component loaded in an outlet. The information is provided
|
||||
* through
|
||||
* the params and urlSegments observables.
|
||||
*
|
||||
* ### Usage
|
||||
|
@ -74,12 +83,10 @@ export class ActivatedRoute {
|
|||
/**
|
||||
* @internal
|
||||
*/
|
||||
constructor(public urlSegments: Observable<UrlSegment[]>,
|
||||
public params: Observable<Params>,
|
||||
public outlet: string,
|
||||
public component: Type | string,
|
||||
futureSnapshot: ActivatedRouteSnapshot
|
||||
) {
|
||||
constructor(
|
||||
public urlSegments: Observable<UrlSegment[]>, public params: Observable<Params>,
|
||||
public outlet: string, public component: Type|string,
|
||||
futureSnapshot: ActivatedRouteSnapshot) {
|
||||
this._futureSnapshot = futureSnapshot;
|
||||
}
|
||||
}
|
||||
|
@ -102,9 +109,9 @@ export class ActivatedRouteSnapshot {
|
|||
* @internal
|
||||
*/
|
||||
_resolvedComponentFactory: ComponentFactory<any>;
|
||||
|
||||
|
||||
/** @internal **/
|
||||
_routeConfig: Route | null;
|
||||
_routeConfig: Route|null;
|
||||
|
||||
/** @internal **/
|
||||
_lastUrlSegment: UrlSegment;
|
||||
|
@ -112,12 +119,9 @@ export class ActivatedRouteSnapshot {
|
|||
/**
|
||||
* @internal
|
||||
*/
|
||||
constructor(public urlSegments: UrlSegment[],
|
||||
public params: Params,
|
||||
public outlet: string,
|
||||
public component: Type | string,
|
||||
routeConfig: Route | null,
|
||||
lastUrlSegment: UrlSegment) {
|
||||
constructor(
|
||||
public urlSegments: UrlSegment[], public params: Params, public outlet: string,
|
||||
public component: Type|string, routeConfig: Route|null, lastUrlSegment: UrlSegment) {
|
||||
this._routeConfig = routeConfig;
|
||||
this._lastUrlSegment = lastUrlSegment;
|
||||
}
|
||||
|
@ -140,7 +144,9 @@ export class RouterStateSnapshot extends Tree<ActivatedRouteSnapshot> {
|
|||
/**
|
||||
* @internal
|
||||
*/
|
||||
constructor(root: TreeNode<ActivatedRouteSnapshot>, public queryParams: Params, public fragment: string | null) {
|
||||
constructor(
|
||||
root: TreeNode<ActivatedRouteSnapshot>, public queryParams: Params,
|
||||
public fragment: string|null) {
|
||||
super(root);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,9 +2,11 @@
|
|||
* Name of the primary outlet.
|
||||
* @type {string}
|
||||
*/
|
||||
export const PRIMARY_OUTLET: string = "PRIMARY_OUTLET";
|
||||
export const PRIMARY_OUTLET = 'PRIMARY_OUTLET';
|
||||
|
||||
/**
|
||||
* A collection of parameters.
|
||||
*/
|
||||
export type Params = { [key: string]: string };
|
||||
export type Params = {
|
||||
[key: string]: string
|
||||
};
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import { UrlTree, UrlSegment } from './url_tree';
|
||||
import { PRIMARY_OUTLET } from './shared';
|
||||
import { TreeNode } from './utils/tree';
|
||||
import {PRIMARY_OUTLET} from './shared';
|
||||
import {UrlSegment, UrlTree} from './url_tree';
|
||||
import {TreeNode} from './utils/tree';
|
||||
|
||||
|
||||
/**
|
||||
* Defines a way to serialize/deserialize a url tree.
|
||||
|
@ -26,7 +27,7 @@ export class DefaultUrlSerializer implements UrlSerializer {
|
|||
return new UrlTree(p.parseRootSegment(), p.parseQueryParams(), p.parseFragment());
|
||||
}
|
||||
|
||||
serialize(tree: UrlTree): string {
|
||||
serialize(tree: UrlTree): string {
|
||||
const node = serializeUrlTreeNode(tree._root);
|
||||
const query = serializeQueryParams(tree.queryParams);
|
||||
const fragment = tree.fragment !== null ? `#${tree.fragment}` : '';
|
||||
|
@ -41,7 +42,8 @@ function serializeUrlTreeNode(node: TreeNode<UrlSegment>): string {
|
|||
function serializeUrlTreeNodes(nodes: TreeNode<UrlSegment>[]): string {
|
||||
const primary = serializeSegment(nodes[0].value);
|
||||
const secondaryNodes = nodes.slice(1);
|
||||
const secondary = secondaryNodes.length > 0 ? `(${secondaryNodes.map(serializeUrlTreeNode).join("//")})` : "";
|
||||
const secondary =
|
||||
secondaryNodes.length > 0 ? `(${secondaryNodes.map(serializeUrlTreeNode).join("//")})` : '';
|
||||
const children = serializeChildren(nodes[0]);
|
||||
return `${primary}${secondary}${children}`;
|
||||
}
|
||||
|
@ -50,7 +52,7 @@ function serializeChildren(node: TreeNode<UrlSegment>): string {
|
|||
if (node.children.length > 0) {
|
||||
return `/${serializeUrlTreeNodes(node.children)}`;
|
||||
} else {
|
||||
return "";
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -60,16 +62,18 @@ export function serializeSegment(segment: UrlSegment): string {
|
|||
}
|
||||
|
||||
function serializeParams(params: {[key: string]: string}): string {
|
||||
return pairs(params).map(p => `;${p.first}=${p.second}`).join("");
|
||||
return pairs(params).map(p => `;${p.first}=${p.second}`).join('');
|
||||
}
|
||||
|
||||
function serializeQueryParams(params: {[key: string]: string}): string {
|
||||
const strs = pairs(params).map(p => `${p.first}=${p.second}`);
|
||||
return strs.length > 0 ? `?${strs.join("&")}` : "";
|
||||
return strs.length > 0 ? `?${strs.join("&")}` : '';
|
||||
}
|
||||
|
||||
class Pair<A,B> { constructor(public first:A, public second:B) {} }
|
||||
function pairs<T>(obj: {[key: string]: T}):Pair<string,T>[] {
|
||||
class Pair<A, B> {
|
||||
constructor(public first: A, public second: B) {}
|
||||
}
|
||||
function pairs<T>(obj: {[key: string]: T}): Pair<string, T>[] {
|
||||
const res = [];
|
||||
for (let prop in obj) {
|
||||
if (obj.hasOwnProperty(prop)) {
|
||||
|
@ -106,7 +110,7 @@ class UrlParser {
|
|||
}
|
||||
|
||||
parseRootSegment(): TreeNode<UrlSegment> {
|
||||
if (this.remaining == '' || this.remaining == '/') {
|
||||
if (this.remaining == '' || this.remaining == '/') {
|
||||
return new TreeNode<UrlSegment>(new UrlSegment('', {}, PRIMARY_OUTLET), []);
|
||||
} else {
|
||||
const segments = this.parseSegments(false);
|
||||
|
@ -126,17 +130,17 @@ class UrlParser {
|
|||
|
||||
let outletName;
|
||||
if (hasOutletName) {
|
||||
if (path.indexOf(":") === -1) {
|
||||
throw new Error("Not outlet name is provided");
|
||||
if (path.indexOf(':') === -1) {
|
||||
throw new Error('Not outlet name is provided');
|
||||
}
|
||||
if (path.indexOf(":") > -1 && hasOutletName) {
|
||||
let parts = path.split(":");
|
||||
if (path.indexOf(':') > -1 && hasOutletName) {
|
||||
let parts = path.split(':');
|
||||
outletName = parts[0];
|
||||
path = parts[1];
|
||||
}
|
||||
} else {
|
||||
if (path.indexOf(":") > -1) {
|
||||
throw new Error("Not outlet name is allowed");
|
||||
if (path.indexOf(':') > -1) {
|
||||
throw new Error('Not outlet name is allowed');
|
||||
}
|
||||
outletName = PRIMARY_OUTLET;
|
||||
}
|
||||
|
@ -175,7 +179,7 @@ class UrlParser {
|
|||
return params;
|
||||
}
|
||||
|
||||
parseFragment(): string | null {
|
||||
parseFragment(): string|null {
|
||||
if (this.peekStartsWith('#')) {
|
||||
return this.remaining.substring(1);
|
||||
} else {
|
||||
|
@ -198,7 +202,7 @@ class UrlParser {
|
|||
return;
|
||||
}
|
||||
this.capture(key);
|
||||
var value: any = "true";
|
||||
var value: any = 'true';
|
||||
if (this.peekStartsWith('=')) {
|
||||
this.capture('=');
|
||||
var valueMatch = matchUrlSegment(this.remaining);
|
||||
|
@ -217,7 +221,7 @@ class UrlParser {
|
|||
return;
|
||||
}
|
||||
this.capture(key);
|
||||
var value: any = "true";
|
||||
var value: any = 'true';
|
||||
if (this.peekStartsWith('=')) {
|
||||
this.capture('=');
|
||||
var valueMatch = matchUrlQueryParamValue(this.remaining);
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
import { Tree, TreeNode } from './utils/tree';
|
||||
import { shallowEqual } from './utils/collection';
|
||||
import { PRIMARY_OUTLET } from './shared';
|
||||
import {PRIMARY_OUTLET} from './shared';
|
||||
import {shallowEqual} from './utils/collection';
|
||||
import {Tree, TreeNode} from './utils/tree';
|
||||
|
||||
export function createEmptyUrlTree() {
|
||||
return new UrlTree(new TreeNode<UrlSegment>(new UrlSegment("", {}, PRIMARY_OUTLET), []), {}, null);
|
||||
return new UrlTree(
|
||||
new TreeNode<UrlSegment>(new UrlSegment('', {}, PRIMARY_OUTLET), []), {}, null);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -13,7 +14,9 @@ export class UrlTree extends Tree<UrlSegment> {
|
|||
/**
|
||||
* @internal
|
||||
*/
|
||||
constructor(root: TreeNode<UrlSegment>, public queryParams: {[key: string]: string}, public fragment: string | null) {
|
||||
constructor(
|
||||
root: TreeNode<UrlSegment>, public queryParams: {[key: string]: string},
|
||||
public fragment: string|null) {
|
||||
super(root);
|
||||
}
|
||||
}
|
||||
|
@ -22,7 +25,8 @@ export class UrlSegment {
|
|||
/**
|
||||
* @internal
|
||||
*/
|
||||
constructor(public path: string, public parameters: {[key: string]: string}, public outlet: string) {}
|
||||
constructor(
|
||||
public path: string, public parameters: {[key: string]: string}, public outlet: string) {}
|
||||
|
||||
toString() {
|
||||
const params = [];
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
export function shallowEqual(a: {[x:string]:any}, b: {[x:string]:any}): boolean {
|
||||
export function shallowEqual(a: {[x: string]: any}, b: {[x: string]: any}): boolean {
|
||||
var k1 = Object.keys(a);
|
||||
var k2 = Object.keys(b);
|
||||
if (k1.length != k2.length) {
|
||||
|
@ -24,12 +24,12 @@ export function flatten<T>(a: T[][]): T[] {
|
|||
return target;
|
||||
}
|
||||
|
||||
export function first<T>(a: T[]): T | null {
|
||||
export function first<T>(a: T[]): T|null {
|
||||
return a.length > 0 ? a[0] : null;
|
||||
}
|
||||
|
||||
export function and(bools: boolean[]): boolean {
|
||||
return bools.reduce((a,b) => a && b, true);
|
||||
return bools.reduce((a, b) => a && b, true);
|
||||
}
|
||||
|
||||
export function merge<V>(m1: {[key: string]: V}, m2: {[key: string]: V}): {[key: string]: V} {
|
||||
|
@ -50,7 +50,8 @@ export function merge<V>(m1: {[key: string]: V}, m2: {[key: string]: V}): {[key:
|
|||
return m;
|
||||
}
|
||||
|
||||
export function forEach<K, V>(map: {[key: string]: V}, callback: /*(V, K) => void*/ Function): void {
|
||||
export function forEach<K, V>(
|
||||
map: {[key: string]: V}, callback: /*(V, K) => void*/ Function): void {
|
||||
for (var prop in map) {
|
||||
if (map.hasOwnProperty(prop)) {
|
||||
callback(map[prop], prop);
|
||||
|
|
|
@ -6,7 +6,7 @@ export class Tree<T> {
|
|||
|
||||
get root(): T { return this._root.value; }
|
||||
|
||||
parent(t: T): T | null {
|
||||
parent(t: T): T|null {
|
||||
const p = this.pathFromRoot(t);
|
||||
return p.length > 1 ? p[p.length - 2] : null;
|
||||
}
|
||||
|
@ -16,7 +16,7 @@ export class Tree<T> {
|
|||
return n ? n.children.map(t => t.value) : [];
|
||||
}
|
||||
|
||||
firstChild(t: T): T | null {
|
||||
firstChild(t: T): T|null {
|
||||
const n = findNode(t, this._root);
|
||||
return n && n.children.length > 0 ? n.children[0].value : null;
|
||||
}
|
||||
|
@ -34,7 +34,7 @@ export class Tree<T> {
|
|||
contains(tree: Tree<T>): boolean { return contains(this._root, tree._root); }
|
||||
}
|
||||
|
||||
function findNode<T>(expected: T, c: TreeNode<T>): TreeNode<T> | null {
|
||||
function findNode<T>(expected: T, c: TreeNode<T>): TreeNode<T>|null {
|
||||
if (expected === c.value) return c;
|
||||
for (let cc of c.children) {
|
||||
const r = findNode(expected, cc);
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
{
|
||||
"rulesDirectory": ["node_modules/codelyzer"],
|
||||
"rules": {
|
||||
"max-line-length": [true, 100],
|
||||
"no-inferrable-types": true,
|
||||
"class-name": true,
|
||||
"comment-format": [
|
||||
|
@ -12,14 +11,13 @@
|
|||
true,
|
||||
"spaces"
|
||||
],
|
||||
"eofline": true,
|
||||
"no-duplicate-variable": true,
|
||||
"no-eval": true,
|
||||
"no-arg": true,
|
||||
"no-internal-module": true,
|
||||
"no-trailing-whitespace": true,
|
||||
"no-bitwise": true,
|
||||
"no-shadowed-variable": true,
|
||||
"no-shadowed-variable": false,
|
||||
"no-unused-expression": true,
|
||||
"no-unused-variable": true,
|
||||
"one-line": [
|
||||
|
@ -29,11 +27,6 @@
|
|||
"check-open-brace",
|
||||
"check-whitespace"
|
||||
],
|
||||
"quotemark": [
|
||||
true,
|
||||
"single",
|
||||
"avoid-escape"
|
||||
],
|
||||
"semicolon": [true, "always"],
|
||||
"typedef-whitespace": [
|
||||
true,
|
||||
|
@ -45,12 +38,12 @@
|
|||
"variable-declaration": "nospace"
|
||||
}
|
||||
],
|
||||
"curly": true,
|
||||
"curly": false,
|
||||
"variable-name": [
|
||||
true,
|
||||
"ban-keywords",
|
||||
"check-format",
|
||||
"allow-trailing-underscore"
|
||||
"allow-leading-underscore"
|
||||
],
|
||||
"whitespace": [
|
||||
true,
|
||||
|
@ -62,10 +55,6 @@
|
|||
],
|
||||
"component-selector-name": [true, "kebab-case"],
|
||||
"component-selector-type": [true, "element"],
|
||||
"host-parameter-decorator": true,
|
||||
"input-parameter-decorator": true,
|
||||
"output-parameter-decorator": true,
|
||||
"attribute-parameter-decorator": true,
|
||||
"input-property-directive": true,
|
||||
"output-property-directive": true
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue