@ -32,8 +32,6 @@ import {Injectable} from 'angular2/di';
|
||||
export class RouteRegistry {
|
||||
private _rules: Map<any, RouteRecognizer> = new Map();
|
||||
|
||||
constructor(private _rootHostComponent: any) {}
|
||||
|
||||
/**
|
||||
* Given a component and a configuration object, add the route to this registry
|
||||
*/
|
||||
@ -144,41 +142,22 @@ export class RouteRegistry {
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a list with component names and params like: `['./user', {id: 3 }]`
|
||||
* Given a normalized list with component names and params like: `['user', {id: 3 }]`
|
||||
* generates a url with a leading slash relative to the provided `parentComponent`.
|
||||
*/
|
||||
generate(linkParams: List<any>, parentComponent): string {
|
||||
let normalizedLinkParams = splitAndFlattenLinkParams(linkParams);
|
||||
let url = '/';
|
||||
|
||||
let url = '';
|
||||
let componentCursor = parentComponent;
|
||||
|
||||
// The first segment should be either '.' (generate from parent) or '' (generate from root).
|
||||
// When we normalize above, we strip all the slashes, './' becomes '.' and '/' becomes ''.
|
||||
if (normalizedLinkParams[0] == '') {
|
||||
componentCursor = this._rootHostComponent;
|
||||
} else if (normalizedLinkParams[0] != '.') {
|
||||
throw new BaseException(
|
||||
`Link "${ListWrapper.toJSON(linkParams)}" must start with "/" or "./"`);
|
||||
}
|
||||
|
||||
if (normalizedLinkParams[normalizedLinkParams.length - 1] == '') {
|
||||
ListWrapper.removeLast(normalizedLinkParams);
|
||||
}
|
||||
|
||||
if (normalizedLinkParams.length < 2) {
|
||||
let msg = `Link "${ListWrapper.toJSON(linkParams)}" must include a route name.`;
|
||||
throw new BaseException(msg);
|
||||
}
|
||||
|
||||
for (let i = 1; i < normalizedLinkParams.length; i += 1) {
|
||||
let segment = normalizedLinkParams[i];
|
||||
for (let i = 0; i < linkParams.length; i += 1) {
|
||||
let segment = linkParams[i];
|
||||
if (!isString(segment)) {
|
||||
throw new BaseException(`Unexpected segment "${segment}" in link DSL. Expected a string.`);
|
||||
} else if (segment == '' || segment == '.' || segment == '..') {
|
||||
throw new BaseException(`"${segment}/" is only allowed at the beginning of a link DSL.`);
|
||||
}
|
||||
let params = null;
|
||||
if (i + 1 < normalizedLinkParams.length) {
|
||||
let nextSegment = normalizedLinkParams[i + 1];
|
||||
if (i + 1 < linkParams.length) {
|
||||
let nextSegment = linkParams[i + 1];
|
||||
if (isStringMap(nextSegment)) {
|
||||
params = nextSegment;
|
||||
i += 1;
|
||||
@ -274,18 +253,3 @@ function assertTerminalComponent(component, path) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Given: ['/a/b', {c: 2}]
|
||||
* Returns: ['', 'a', 'b', {c: 2}]
|
||||
*/
|
||||
var SLASH = new RegExp('/');
|
||||
function splitAndFlattenLinkParams(linkParams: List<any>): List<any> {
|
||||
return ListWrapper.reduce(linkParams, (accumulation, item) => {
|
||||
if (isString(item)) {
|
||||
return ListWrapper.concat(accumulation, StringWrapper.split(item, SLASH));
|
||||
}
|
||||
accumulation.push(item);
|
||||
return accumulation;
|
||||
}, []);
|
||||
}
|
||||
|
@ -1,6 +1,14 @@
|
||||
import {Promise, PromiseWrapper, EventEmitter, ObservableWrapper} from 'angular2/src/facade/async';
|
||||
import {Map, MapWrapper, List, ListWrapper} from 'angular2/src/facade/collection';
|
||||
import {isBlank, isPresent, Type, isArray} from 'angular2/src/facade/lang';
|
||||
import {
|
||||
isBlank,
|
||||
isString,
|
||||
StringWrapper,
|
||||
isPresent,
|
||||
Type,
|
||||
isArray,
|
||||
BaseException
|
||||
} from 'angular2/src/facade/lang';
|
||||
|
||||
import {RouteRegistry} from './route_registry';
|
||||
import {Pipeline} from './pipeline';
|
||||
@ -42,7 +50,7 @@ export class Router {
|
||||
|
||||
// todo(jeffbcross): rename _registry to registry since it is accessed from subclasses
|
||||
// todo(jeffbcross): rename _pipeline to pipeline since it is accessed from subclasses
|
||||
constructor(public _registry: RouteRegistry, public _pipeline: Pipeline, public parent: Router,
|
||||
constructor(public registry: RouteRegistry, public _pipeline: Pipeline, public parent: Router,
|
||||
public hostComponent: any) {}
|
||||
|
||||
|
||||
@ -88,9 +96,9 @@ export class Router {
|
||||
config(config: StringMap<string, any>| List<StringMap<string, any>>): Promise<any> {
|
||||
if (isArray(config)) {
|
||||
(<List<any>>config)
|
||||
.forEach((configObject) => { this._registry.config(this.hostComponent, configObject); });
|
||||
.forEach((configObject) => { this.registry.config(this.hostComponent, configObject); });
|
||||
} else {
|
||||
this._registry.config(this.hostComponent, config);
|
||||
this.registry.config(this.hostComponent, config);
|
||||
}
|
||||
return this.renavigate();
|
||||
}
|
||||
@ -170,7 +178,7 @@ export class Router {
|
||||
* Given a URL, returns an instruction representing the component graph
|
||||
*/
|
||||
recognize(url: string): Promise<Instruction> {
|
||||
return this._registry.recognize(url, this.hostComponent);
|
||||
return this.registry.recognize(url, this.hostComponent);
|
||||
}
|
||||
|
||||
|
||||
@ -192,7 +200,48 @@ export class Router {
|
||||
* app's base href.
|
||||
*/
|
||||
generate(linkParams: List<any>): string {
|
||||
return this._registry.generate(linkParams, this.hostComponent);
|
||||
let normalizedLinkParams = splitAndFlattenLinkParams(linkParams);
|
||||
|
||||
var first = ListWrapper.first(normalizedLinkParams);
|
||||
var rest = ListWrapper.slice(normalizedLinkParams, 1);
|
||||
|
||||
var router = this;
|
||||
|
||||
// The first segment should be either '.' (generate from parent) or '' (generate from root).
|
||||
// When we normalize above, we strip all the slashes, './' becomes '.' and '/' becomes ''.
|
||||
if (first == '') {
|
||||
while (isPresent(router.parent)) {
|
||||
router = router.parent;
|
||||
}
|
||||
} else if (first == '..') {
|
||||
router = router.parent;
|
||||
while (ListWrapper.first(rest) == '..') {
|
||||
rest = ListWrapper.slice(rest, 1);
|
||||
router = router.parent;
|
||||
if (isBlank(router)) {
|
||||
throw new BaseException(
|
||||
`Link "${ListWrapper.toJSON(linkParams)}" has too many "../" segments.`);
|
||||
}
|
||||
}
|
||||
} else if (first != '.') {
|
||||
throw new BaseException(
|
||||
`Link "${ListWrapper.toJSON(linkParams)}" must start with "/", "./", or "../"`);
|
||||
}
|
||||
|
||||
if (rest[rest.length - 1] == '') {
|
||||
ListWrapper.removeLast(rest);
|
||||
}
|
||||
|
||||
if (rest.length < 1) {
|
||||
let msg = `Link "${ListWrapper.toJSON(linkParams)}" must include a route name.`;
|
||||
throw new BaseException(msg);
|
||||
}
|
||||
|
||||
let url = '';
|
||||
if (isPresent(router.parent) && isPresent(router.parent._currentInstruction)) {
|
||||
url = router.parent._currentInstruction.capturedUrl;
|
||||
}
|
||||
return url + '/' + this.registry.generate(rest, router.hostComponent);
|
||||
}
|
||||
}
|
||||
|
||||
@ -204,7 +253,7 @@ export class RootRouter extends Router {
|
||||
super(registry, pipeline, null, hostComponent);
|
||||
this._location = location;
|
||||
this._location.subscribe((change) => this.navigate(change['url']));
|
||||
this._registry.configFromComponent(hostComponent);
|
||||
this.registry.configFromComponent(hostComponent);
|
||||
this.navigate(location.path());
|
||||
}
|
||||
|
||||
@ -216,7 +265,7 @@ export class RootRouter extends Router {
|
||||
|
||||
class ChildRouter extends Router {
|
||||
constructor(parent: Router, hostComponent) {
|
||||
super(parent._registry, parent._pipeline, parent, hostComponent);
|
||||
super(parent.registry, parent._pipeline, parent, hostComponent);
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
@ -226,3 +275,18 @@ class ChildRouter extends Router {
|
||||
return this.parent.navigate(url);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Given: ['/a/b', {c: 2}]
|
||||
* Returns: ['', 'a', 'b', {c: 2}]
|
||||
*/
|
||||
var SLASH = new RegExp('/');
|
||||
function splitAndFlattenLinkParams(linkParams: List<any>): List<any> {
|
||||
return ListWrapper.reduce(linkParams, (accumulation, item) => {
|
||||
if (isString(item)) {
|
||||
return ListWrapper.concat(accumulation, StringWrapper.split(item, SLASH));
|
||||
}
|
||||
accumulation.push(item);
|
||||
return accumulation;
|
||||
}, []);
|
||||
}
|
||||
|
@ -27,10 +27,11 @@ import {Location} from './location';
|
||||
* means that we want to generate a link for the `team` route with params `{teamId: 1}`,
|
||||
* and with a child route `user` with params `{userId: 2}`.
|
||||
*
|
||||
* The first route name should be prepended with either `./` or `/`.
|
||||
* The first route name should be prepended with `/`, `./`, or `../`.
|
||||
* If the route begins with `/`, the router will look up the route from the root of the app.
|
||||
* If the route begins with `./`, the router will instead look in the current component's
|
||||
* children for the route.
|
||||
* children for the route. And if the route begins with `../`, the router will look at the
|
||||
* current component's parent.
|
||||
*
|
||||
* @exportedAs angular2/router
|
||||
*/
|
||||
|
Reference in New Issue
Block a user