parent
d828664d0c
commit
286a249a9a
|
@ -34,8 +34,7 @@ import {List} from './src/facade/collection';
|
||||||
export const routerDirectives: List<any> = CONST_EXPR([RouterOutlet, RouterLink]);
|
export const routerDirectives: List<any> = CONST_EXPR([RouterOutlet, RouterLink]);
|
||||||
|
|
||||||
export var routerInjectables: List<any> = [
|
export var routerInjectables: List<any> = [
|
||||||
bind(RouteRegistry)
|
RouteRegistry,
|
||||||
.toFactory((appRoot) => new RouteRegistry(appRoot), [appComponentTypeToken]),
|
|
||||||
Pipeline,
|
Pipeline,
|
||||||
bind(LocationStrategy).toClass(HTML5LocationStrategy),
|
bind(LocationStrategy).toClass(HTML5LocationStrategy),
|
||||||
Location,
|
Location,
|
||||||
|
|
|
@ -32,8 +32,6 @@ import {Injectable} from 'angular2/di';
|
||||||
export class RouteRegistry {
|
export class RouteRegistry {
|
||||||
private _rules: Map<any, RouteRecognizer> = new Map();
|
private _rules: Map<any, RouteRecognizer> = new Map();
|
||||||
|
|
||||||
constructor(private _rootHostComponent: any) {}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Given a component and a configuration object, add the route to this registry
|
* 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`.
|
* generates a url with a leading slash relative to the provided `parentComponent`.
|
||||||
*/
|
*/
|
||||||
generate(linkParams: List<any>, parentComponent): string {
|
generate(linkParams: List<any>, parentComponent): string {
|
||||||
let normalizedLinkParams = splitAndFlattenLinkParams(linkParams);
|
let url = '';
|
||||||
let url = '/';
|
|
||||||
|
|
||||||
let componentCursor = parentComponent;
|
let componentCursor = parentComponent;
|
||||||
|
for (let i = 0; i < linkParams.length; i += 1) {
|
||||||
// The first segment should be either '.' (generate from parent) or '' (generate from root).
|
let segment = linkParams[i];
|
||||||
// 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];
|
|
||||||
if (!isString(segment)) {
|
if (!isString(segment)) {
|
||||||
throw new BaseException(`Unexpected segment "${segment}" in link DSL. Expected a string.`);
|
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;
|
let params = null;
|
||||||
if (i + 1 < normalizedLinkParams.length) {
|
if (i + 1 < linkParams.length) {
|
||||||
let nextSegment = normalizedLinkParams[i + 1];
|
let nextSegment = linkParams[i + 1];
|
||||||
if (isStringMap(nextSegment)) {
|
if (isStringMap(nextSegment)) {
|
||||||
params = nextSegment;
|
params = nextSegment;
|
||||||
i += 1;
|
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 {Promise, PromiseWrapper, EventEmitter, ObservableWrapper} from 'angular2/src/facade/async';
|
||||||
import {Map, MapWrapper, List, ListWrapper} from 'angular2/src/facade/collection';
|
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 {RouteRegistry} from './route_registry';
|
||||||
import {Pipeline} from './pipeline';
|
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 _registry to registry since it is accessed from subclasses
|
||||||
// todo(jeffbcross): rename _pipeline to pipeline 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) {}
|
public hostComponent: any) {}
|
||||||
|
|
||||||
|
|
||||||
|
@ -88,9 +96,9 @@ export class Router {
|
||||||
config(config: StringMap<string, any>| List<StringMap<string, any>>): Promise<any> {
|
config(config: StringMap<string, any>| List<StringMap<string, any>>): Promise<any> {
|
||||||
if (isArray(config)) {
|
if (isArray(config)) {
|
||||||
(<List<any>>config)
|
(<List<any>>config)
|
||||||
.forEach((configObject) => { this._registry.config(this.hostComponent, configObject); });
|
.forEach((configObject) => { this.registry.config(this.hostComponent, configObject); });
|
||||||
} else {
|
} else {
|
||||||
this._registry.config(this.hostComponent, config);
|
this.registry.config(this.hostComponent, config);
|
||||||
}
|
}
|
||||||
return this.renavigate();
|
return this.renavigate();
|
||||||
}
|
}
|
||||||
|
@ -170,7 +178,7 @@ export class Router {
|
||||||
* Given a URL, returns an instruction representing the component graph
|
* Given a URL, returns an instruction representing the component graph
|
||||||
*/
|
*/
|
||||||
recognize(url: string): Promise<Instruction> {
|
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.
|
* app's base href.
|
||||||
*/
|
*/
|
||||||
generate(linkParams: List<any>): string {
|
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);
|
super(registry, pipeline, null, hostComponent);
|
||||||
this._location = location;
|
this._location = location;
|
||||||
this._location.subscribe((change) => this.navigate(change['url']));
|
this._location.subscribe((change) => this.navigate(change['url']));
|
||||||
this._registry.configFromComponent(hostComponent);
|
this.registry.configFromComponent(hostComponent);
|
||||||
this.navigate(location.path());
|
this.navigate(location.path());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -216,7 +265,7 @@ export class RootRouter extends Router {
|
||||||
|
|
||||||
class ChildRouter extends Router {
|
class ChildRouter extends Router {
|
||||||
constructor(parent: Router, hostComponent) {
|
constructor(parent: Router, hostComponent) {
|
||||||
super(parent._registry, parent._pipeline, parent, hostComponent);
|
super(parent.registry, parent._pipeline, parent, hostComponent);
|
||||||
this.parent = parent;
|
this.parent = parent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -226,3 +275,18 @@ class ChildRouter extends Router {
|
||||||
return this.parent.navigate(url);
|
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}`,
|
* 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}`.
|
* 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 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
|
* 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
|
* @exportedAs angular2/router
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -18,7 +18,7 @@ import {
|
||||||
import {Injector, bind} from 'angular2/di';
|
import {Injector, bind} from 'angular2/di';
|
||||||
import {Component, View} from 'angular2/src/core/annotations/decorators';
|
import {Component, View} from 'angular2/src/core/annotations/decorators';
|
||||||
import * as annotations from 'angular2/src/core/annotations_impl/view';
|
import * as annotations from 'angular2/src/core/annotations_impl/view';
|
||||||
import {CONST} from 'angular2/src/facade/lang';
|
import {CONST, NumberWrapper} from 'angular2/src/facade/lang';
|
||||||
|
|
||||||
import {RootRouter} from 'angular2/src/router/router';
|
import {RootRouter} from 'angular2/src/router/router';
|
||||||
import {Pipeline} from 'angular2/src/router/pipeline';
|
import {Pipeline} from 'angular2/src/router/pipeline';
|
||||||
|
@ -42,7 +42,7 @@ export function main() {
|
||||||
|
|
||||||
beforeEachBindings(() => [
|
beforeEachBindings(() => [
|
||||||
Pipeline,
|
Pipeline,
|
||||||
bind(RouteRegistry).toFactory(() => new RouteRegistry(MyComp)),
|
RouteRegistry,
|
||||||
DirectiveResolver,
|
DirectiveResolver,
|
||||||
bind(Location).toClass(SpyLocation),
|
bind(Location).toClass(SpyLocation),
|
||||||
bind(Router)
|
bind(Router)
|
||||||
|
@ -185,6 +185,49 @@ export function main() {
|
||||||
});
|
});
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
|
||||||
|
it('should generate link hrefs from a child to its sibling',
|
||||||
|
inject([AsyncTestCompleter], (async) => {
|
||||||
|
compile()
|
||||||
|
.then((_) => rtr.config(
|
||||||
|
{'path': '/page/:number', 'component': SiblingPageCmp, 'as': 'page'}))
|
||||||
|
.then((_) => rtr.navigate('/page/1'))
|
||||||
|
.then((_) => {
|
||||||
|
rootTC.detectChanges();
|
||||||
|
expect(DOM.getAttribute(rootTC.componentViewChildren[1]
|
||||||
|
.componentViewChildren[0]
|
||||||
|
.children[0]
|
||||||
|
.nativeElement,
|
||||||
|
'href'))
|
||||||
|
.toEqual('/page/2');
|
||||||
|
async.done();
|
||||||
|
});
|
||||||
|
}));
|
||||||
|
|
||||||
|
it('should generate relative links preserving the existing parent route',
|
||||||
|
inject([AsyncTestCompleter], (async) => {
|
||||||
|
compile()
|
||||||
|
.then((_) =>
|
||||||
|
rtr.config({'path': '/book/:title/...', 'component': BookCmp, 'as': 'book'}))
|
||||||
|
.then((_) => rtr.navigate('/book/1984/page/1'))
|
||||||
|
.then((_) => {
|
||||||
|
rootTC.detectChanges();
|
||||||
|
expect(DOM.getAttribute(
|
||||||
|
rootTC.componentViewChildren[1].componentViewChildren[0].nativeElement,
|
||||||
|
'href'))
|
||||||
|
.toEqual('/book/1984/page/100');
|
||||||
|
|
||||||
|
expect(DOM.getAttribute(rootTC.componentViewChildren[1]
|
||||||
|
.componentViewChildren[2]
|
||||||
|
.componentViewChildren[0]
|
||||||
|
.children[0]
|
||||||
|
.nativeElement,
|
||||||
|
'href'))
|
||||||
|
.toEqual('/book/1984/page/2');
|
||||||
|
async.done();
|
||||||
|
});
|
||||||
|
}));
|
||||||
|
|
||||||
describe('when clicked', () => {
|
describe('when clicked', () => {
|
||||||
|
|
||||||
var clickOnElement = function(view) {
|
var clickOnElement = function(view) {
|
||||||
|
@ -266,6 +309,34 @@ class UserCmp {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Component({selector: 'page-cmp'})
|
||||||
|
@View({
|
||||||
|
template:
|
||||||
|
`page #{{pageNumber}} | <a href="hello" [router-link]="[\'../page\', {number: nextPage}]">next</a>`,
|
||||||
|
directives: [RouterLink]
|
||||||
|
})
|
||||||
|
class SiblingPageCmp {
|
||||||
|
pageNumber: number;
|
||||||
|
nextPage: number;
|
||||||
|
constructor(params: RouteParams) {
|
||||||
|
this.pageNumber = NumberWrapper.parseInt(params.get('number'), 10);
|
||||||
|
this.nextPage = this.pageNumber + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Component({selector: 'book-cmp'})
|
||||||
|
@View({
|
||||||
|
template: `<a href="hello" [router-link]="[\'./page\', {number: 100}]">{{title}}</a> |
|
||||||
|
<router-outlet></router-outlet>`,
|
||||||
|
directives: [RouterLink, RouterOutlet]
|
||||||
|
})
|
||||||
|
@RouteConfig([{path: '/page/:number', component: SiblingPageCmp, 'as': 'page'}])
|
||||||
|
class BookCmp {
|
||||||
|
title: string;
|
||||||
|
constructor(params: RouteParams) { this.title = params.get('title'); }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@Component({selector: 'parent-cmp'})
|
@Component({selector: 'parent-cmp'})
|
||||||
@View({template: "inner { <router-outlet></router-outlet> }", directives: [RouterOutlet]})
|
@View({template: "inner { <router-outlet></router-outlet> }", directives: [RouterOutlet]})
|
||||||
@RouteConfig([{path: '/b', component: HelloCmp}])
|
@RouteConfig([{path: '/b', component: HelloCmp}])
|
||||||
|
|
|
@ -20,7 +20,7 @@ export function main() {
|
||||||
describe('RouteRegistry', () => {
|
describe('RouteRegistry', () => {
|
||||||
var registry, rootHostComponent = new Object();
|
var registry, rootHostComponent = new Object();
|
||||||
|
|
||||||
beforeEach(() => { registry = new RouteRegistry(rootHostComponent); });
|
beforeEach(() => { registry = new RouteRegistry(); });
|
||||||
|
|
||||||
it('should match the full URL', inject([AsyncTestCompleter], (async) => {
|
it('should match the full URL', inject([AsyncTestCompleter], (async) => {
|
||||||
registry.config(rootHostComponent, {'path': '/', 'component': DummyCompA});
|
registry.config(rootHostComponent, {'path': '/', 'component': DummyCompA});
|
||||||
|
@ -37,9 +37,9 @@ export function main() {
|
||||||
registry.config(rootHostComponent,
|
registry.config(rootHostComponent,
|
||||||
{'path': '/first/...', 'component': DummyParentComp, 'as': 'firstCmp'});
|
{'path': '/first/...', 'component': DummyParentComp, 'as': 'firstCmp'});
|
||||||
|
|
||||||
expect(registry.generate(['./firstCmp/secondCmp'], rootHostComponent))
|
expect(registry.generate(['firstCmp', 'secondCmp'], rootHostComponent))
|
||||||
.toEqual('/first/second');
|
.toEqual('first/second');
|
||||||
expect(registry.generate(['./secondCmp'], DummyParentComp)).toEqual('/second');
|
expect(registry.generate(['secondCmp'], DummyParentComp)).toEqual('second');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should generate URLs with params', () => {
|
it('should generate URLs with params', () => {
|
||||||
|
@ -47,20 +47,9 @@ export function main() {
|
||||||
rootHostComponent,
|
rootHostComponent,
|
||||||
{'path': '/first/:param/...', 'component': DummyParentParamComp, 'as': 'firstCmp'});
|
{'path': '/first/:param/...', 'component': DummyParentParamComp, 'as': 'firstCmp'});
|
||||||
|
|
||||||
var url = registry.generate(['./firstCmp', {param: 'one'}, 'secondCmp', {param: 'two'}],
|
var url = registry.generate(['firstCmp', {param: 'one'}, 'secondCmp', {param: 'two'}],
|
||||||
rootHostComponent);
|
rootHostComponent);
|
||||||
expect(url).toEqual('/first/one/second/two');
|
expect(url).toEqual('first/one/second/two');
|
||||||
});
|
|
||||||
|
|
||||||
it('should generate URLs from the root component when the path starts with /', () => {
|
|
||||||
registry.config(rootHostComponent,
|
|
||||||
{'path': '/first/...', 'component': DummyParentComp, 'as': 'firstCmp'});
|
|
||||||
|
|
||||||
expect(registry.generate(['/firstCmp', 'secondCmp'], rootHostComponent))
|
|
||||||
.toEqual('/first/second');
|
|
||||||
expect(registry.generate(['/firstCmp', 'secondCmp'], DummyParentComp))
|
|
||||||
.toEqual('/first/second');
|
|
||||||
expect(registry.generate(['/firstCmp/secondCmp'], DummyParentComp)).toEqual('/first/second');
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should generate URLs of loaded components after they are loaded',
|
it('should generate URLs of loaded components after they are loaded',
|
||||||
|
@ -71,30 +60,17 @@ export function main() {
|
||||||
'as': 'firstCmp'
|
'as': 'firstCmp'
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(() => registry.generate(['/firstCmp/secondCmp'], rootHostComponent))
|
expect(() => registry.generate(['firstCmp', 'secondCmp'], rootHostComponent))
|
||||||
.toThrowError('Could not find route config for "secondCmp".');
|
.toThrowError('Could not find route config for "secondCmp".');
|
||||||
|
|
||||||
registry.recognize('/first/second', rootHostComponent)
|
registry.recognize('/first/second', rootHostComponent)
|
||||||
.then((_) => {
|
.then((_) => {
|
||||||
expect(registry.generate(['/firstCmp/secondCmp'], rootHostComponent))
|
expect(registry.generate(['firstCmp', 'secondCmp'], rootHostComponent))
|
||||||
.toEqual('/first/second');
|
.toEqual('first/second');
|
||||||
async.done();
|
async.done();
|
||||||
});
|
});
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it('should throw when linkParams does not start with a "/" or "./"', () => {
|
|
||||||
expect(() => registry.generate(['firstCmp', 'secondCmp'], rootHostComponent))
|
|
||||||
.toThrowError(
|
|
||||||
`Link "${ListWrapper.toJSON(['firstCmp', 'secondCmp'])}" must start with "/" or "./"`);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should throw when linkParams does not include a route name', () => {
|
|
||||||
expect(() => registry.generate(['./'], rootHostComponent))
|
|
||||||
.toThrowError(`Link "${ListWrapper.toJSON(['./'])}" must include a route name.`);
|
|
||||||
expect(() => registry.generate(['/'], rootHostComponent))
|
|
||||||
.toThrowError(`Link "${ListWrapper.toJSON(['/'])}" must include a route name.`);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should prefer static segments to dynamic', inject([AsyncTestCompleter], (async) => {
|
it('should prefer static segments to dynamic', inject([AsyncTestCompleter], (async) => {
|
||||||
registry.config(rootHostComponent, {'path': '/:site', 'component': DummyCompB});
|
registry.config(rootHostComponent, {'path': '/:site', 'component': DummyCompB});
|
||||||
registry.config(rootHostComponent, {'path': '/home', 'component': DummyCompA});
|
registry.config(rootHostComponent, {'path': '/home', 'component': DummyCompA});
|
||||||
|
|
|
@ -14,6 +14,7 @@ import {
|
||||||
import {IMPLEMENTS} from 'angular2/src/facade/lang';
|
import {IMPLEMENTS} from 'angular2/src/facade/lang';
|
||||||
|
|
||||||
import {Promise, PromiseWrapper} from 'angular2/src/facade/async';
|
import {Promise, PromiseWrapper} from 'angular2/src/facade/async';
|
||||||
|
import {ListWrapper} from 'angular2/src/facade/collection';
|
||||||
import {Router, RootRouter} from 'angular2/src/router/router';
|
import {Router, RootRouter} from 'angular2/src/router/router';
|
||||||
import {Pipeline} from 'angular2/src/router/pipeline';
|
import {Pipeline} from 'angular2/src/router/pipeline';
|
||||||
import {RouterOutlet} from 'angular2/src/router/router_outlet';
|
import {RouterOutlet} from 'angular2/src/router/router_outlet';
|
||||||
|
@ -21,6 +22,7 @@ import {SpyLocation} from 'angular2/src/mock/location_mock';
|
||||||
import {Location} from 'angular2/src/router/location';
|
import {Location} from 'angular2/src/router/location';
|
||||||
|
|
||||||
import {RouteRegistry} from 'angular2/src/router/route_registry';
|
import {RouteRegistry} from 'angular2/src/router/route_registry';
|
||||||
|
import {RouteConfig} from 'angular2/src/router/route_config_decorator';
|
||||||
import {DirectiveResolver} from 'angular2/src/core/compiler/directive_resolver';
|
import {DirectiveResolver} from 'angular2/src/core/compiler/directive_resolver';
|
||||||
|
|
||||||
import {bind} from 'angular2/di';
|
import {bind} from 'angular2/di';
|
||||||
|
@ -31,7 +33,7 @@ export function main() {
|
||||||
|
|
||||||
beforeEachBindings(() => [
|
beforeEachBindings(() => [
|
||||||
Pipeline,
|
Pipeline,
|
||||||
bind(RouteRegistry).toFactory(() => new RouteRegistry(AppCmp)),
|
RouteRegistry,
|
||||||
DirectiveResolver,
|
DirectiveResolver,
|
||||||
bind(Location).toClass(SpyLocation),
|
bind(Location).toClass(SpyLocation),
|
||||||
bind(Router)
|
bind(Router)
|
||||||
|
@ -74,6 +76,7 @@ export function main() {
|
||||||
});
|
});
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
|
||||||
it('should navigate after being configured', inject([AsyncTestCompleter], (async) => {
|
it('should navigate after being configured', inject([AsyncTestCompleter], (async) => {
|
||||||
var outlet = makeDummyOutlet();
|
var outlet = makeDummyOutlet();
|
||||||
|
|
||||||
|
@ -88,6 +91,30 @@ export function main() {
|
||||||
async.done();
|
async.done();
|
||||||
});
|
});
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
|
||||||
|
it('should throw when linkParams does not start with a "/" or "./"', () => {
|
||||||
|
expect(() => router.generate(['firstCmp', 'secondCmp']))
|
||||||
|
.toThrowError(
|
||||||
|
`Link "${ListWrapper.toJSON(['firstCmp', 'secondCmp'])}" must start with "/", "./", or "../"`);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
it('should throw when linkParams does not include a route name', () => {
|
||||||
|
expect(() => router.generate(['./']))
|
||||||
|
.toThrowError(`Link "${ListWrapper.toJSON(['./'])}" must include a route name.`);
|
||||||
|
expect(() => router.generate(['/']))
|
||||||
|
.toThrowError(`Link "${ListWrapper.toJSON(['/'])}" must include a route name.`);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
it('should generate URLs from the root component when the path starts with /', () => {
|
||||||
|
router.config({'path': '/first/...', 'component': DummyParentComp, 'as': 'firstCmp'});
|
||||||
|
|
||||||
|
expect(router.generate(['/firstCmp', 'secondCmp'])).toEqual('/first/second');
|
||||||
|
expect(router.generate(['/firstCmp', 'secondCmp'])).toEqual('/first/second');
|
||||||
|
expect(router.generate(['/firstCmp/secondCmp'])).toEqual('/first/second');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -99,6 +126,10 @@ class DummyOutlet extends SpyObject {
|
||||||
|
|
||||||
class DummyComponent {}
|
class DummyComponent {}
|
||||||
|
|
||||||
|
@RouteConfig([{'path': '/second', 'component': DummyComponent, 'as': 'secondCmp'}])
|
||||||
|
class DummyParentComp {
|
||||||
|
}
|
||||||
|
|
||||||
function makeDummyOutlet() {
|
function makeDummyOutlet() {
|
||||||
var ref = new DummyOutlet();
|
var ref = new DummyOutlet();
|
||||||
ref.spy('activate').andCallFake((_) => PromiseWrapper.resolve(true));
|
ref.spy('activate').andCallFake((_) => PromiseWrapper.resolve(true));
|
||||||
|
|
Loading…
Reference in New Issue