cleanup(router): removes router
This commit is contained in:
parent
65be81baf8
commit
af2f5c3d7d
1
build.sh
1
build.sh
|
@ -49,7 +49,6 @@ for PACKAGE in \
|
|||
platform-browser-dynamic \
|
||||
platform-server \
|
||||
http \
|
||||
router \
|
||||
router-deprecated \
|
||||
upgrade \
|
||||
compiler-cli
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import {beforeEach, ddescribe, describe, expect, iit, it} from '@angular/core/testing/testing_internal';
|
||||
import * as ts from 'typescript';
|
||||
|
||||
import {ReflectorHost, ReflectorHostContext} from '../src/reflector_host';
|
||||
import {ReflectorHost} from '../src/reflector_host';
|
||||
|
||||
import {Directory, Entry, MockCompilerHost, MockContext} from './mocks';
|
||||
|
||||
|
@ -64,11 +64,13 @@ describe('reflector_host', () => {
|
|||
});
|
||||
|
||||
it('should be able to produce a symbol for an exported symbol', () => {
|
||||
expect(reflectorHost.findDeclaration('@angular/router', 'foo', 'main.ts')).toBeDefined();
|
||||
expect(reflectorHost.findDeclaration('@angular/router-deprecated', 'foo', 'main.ts'))
|
||||
.toBeDefined();
|
||||
});
|
||||
|
||||
it('should be able to produce a symbol for values space only reference', () => {
|
||||
expect(reflectorHost.findDeclaration('@angular/router/src/providers', 'foo', 'main.ts'))
|
||||
expect(
|
||||
reflectorHost.findDeclaration('@angular/router-deprecated/src/providers', 'foo', 'main.ts'))
|
||||
.toBeDefined();
|
||||
});
|
||||
|
||||
|
@ -90,7 +92,7 @@ const FILES: Entry = {
|
|||
'src': {
|
||||
'main.ts': `
|
||||
import * as c from '@angular/core';
|
||||
import * as r from '@angular/router';
|
||||
import * as r from '@angular/router-deprecated';
|
||||
import * as u from './lib/utils';
|
||||
import * as cs from './lib/collections';
|
||||
import * as u2 from './lib2/utils2';
|
||||
|
@ -105,7 +107,8 @@ const FILES: Entry = {
|
|||
'core.d.ts': dummyModule,
|
||||
'core.metadata.json':
|
||||
`{"__symbolic":"module", "version": 1, "metadata": {"foo": {"__symbolic": "class"}}}`,
|
||||
'router': {'index.d.ts': dummyModule, 'src': {'providers.d.ts': dummyModule}}
|
||||
'router-deprecated':
|
||||
{'index.d.ts': dummyModule, 'src': {'providers.d.ts': dummyModule}}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import {isDevMode} from '@angular/core';
|
||||
|
||||
import {beforeEach, ddescribe, describe, expect, iit, inject, it, xdescribe, xit} from '../testing';
|
||||
|
||||
export function main() {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import {beforeEach, ddescribe, describe, expect, iit, inject, it, xit} from '@angular/core/testing/testing_internal';
|
||||
import {fakeAsync, flushMicrotasks, Log, tick, discardPeriodicTasks,} from '@angular/core/testing';
|
||||
import {TimerWrapper, PromiseWrapper} from '../../router/src/facade/async';
|
||||
import {BaseException} from '../../router/src/facade/exceptions';
|
||||
import {TimerWrapper, PromiseWrapper} from '../../router-deprecated/src/facade/async';
|
||||
import {BaseException} from '../../router-deprecated/src/facade/exceptions';
|
||||
import {Parser} from '../../compiler/src/expression_parser/parser';
|
||||
|
||||
export function main() {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import {SpyObject} from '@angular/core/testing/testing_internal';
|
||||
|
||||
import {MapWrapper} from '../../platform-browser/src/facade/collection';
|
||||
import {RegExpWrapper} from '../../router/src/facade/lang';
|
||||
import {RegExpWrapper} from '../../router-deprecated/src/facade/lang';
|
||||
import {beforeEach, containsRegexp, ddescribe, describe, expect, iit, it, tick} from '../testing';
|
||||
|
||||
class TestObj {
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
import {it, iit, xit, describe, ddescribe, xdescribe, expect, beforeEach, beforeEachProviders, inject,} from '@angular/core/testing';
|
||||
import {async, fakeAsync, flushMicrotasks, Log, tick,} from '@angular/core/testing';
|
||||
|
||||
import {ROUTER_FAKE_PROVIDERS} from '@angular/router/testing';
|
||||
import {ROUTER_DIRECTIVES, Routes, Route} from '@angular/router';
|
||||
import {ROUTER_DIRECTIVES, Route} from '@angular/router-deprecated';
|
||||
|
||||
|
||||
import {Component, bind} from '@angular/core';
|
||||
|
@ -37,10 +36,6 @@ class BadTemplateUrl {
|
|||
`<a [routerLink]="['One']">one</a> <a [routerLink]="['Two']">two</a><router-outlet></router-outlet>`,
|
||||
directives: [ROUTER_DIRECTIVES]
|
||||
})
|
||||
@Routes([
|
||||
new Route({path: '/One', component: BadTemplateUrl}),
|
||||
new Route({path: '/Two', component: ExternalTemplateComp}),
|
||||
])
|
||||
class TestRouterComponent {
|
||||
}
|
||||
|
||||
|
@ -169,15 +164,4 @@ export function main() {
|
|||
10000); // Long timeout here because this test makes an actual XHR, and is slow on Edge.
|
||||
});
|
||||
});
|
||||
|
||||
describe('apps with router components', () => {
|
||||
beforeEachProviders(() => [ROUTER_FAKE_PROVIDERS]);
|
||||
|
||||
it('should build without a problem',
|
||||
async(inject([TestComponentBuilder], (tcb: TestComponentBuilder) => {
|
||||
tcb.createAsync(TestRouterComponent).then((fixture) => {
|
||||
expect(fixture.nativeElement).toHaveText('one two');
|
||||
});
|
||||
})));
|
||||
});
|
||||
}
|
||||
|
|
|
@ -1,16 +0,0 @@
|
|||
/**
|
||||
* @module
|
||||
* @description
|
||||
* Maps application URLs into application states, to support deep-linking and navigation.
|
||||
*/
|
||||
|
||||
export {ROUTER_DIRECTIVES} from './src/directives/router_directives';
|
||||
export {RouterLink} from './src/directives/router_link';
|
||||
export {RouterOutlet} from './src/directives/router_outlet';
|
||||
export {CanDeactivate, OnActivate} from './src/interfaces';
|
||||
export {Routes} from './src/metadata/decorators';
|
||||
export {Route} from './src/metadata/metadata';
|
||||
export {Router, RouterOutletMap} from './src/router';
|
||||
export {ROUTER_PROVIDERS} from './src/router_providers';
|
||||
export {DefaultRouterUrlSerializer, RouterUrlSerializer} from './src/router_url_serializer';
|
||||
export {RouteSegment, RouteTree, Tree, UrlSegment, UrlTree} from './src/segments';
|
|
@ -1,19 +0,0 @@
|
|||
{
|
||||
"name": "@angular/router",
|
||||
"version": "0.0.0-PLACEHOLDER",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"jsnext:main": "esm/index.js",
|
||||
"typins": "index.d.ts",
|
||||
"author": "angular",
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"@angular/core": "0.0.0-PLACEHOLDER",
|
||||
"@angular/common": "0.0.0-PLACEHOLDER",
|
||||
"@angular/platform-browser": "0.0.0-PLACEHOLDER"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/angular/angular.git"
|
||||
}
|
||||
}
|
|
@ -1 +0,0 @@
|
|||
export './platform-browser.dart' show DomAdapter, setRootDomAdapter;
|
|
@ -1,4 +0,0 @@
|
|||
import {__platform_browser_private__ as _} from '@angular/platform-browser';
|
||||
|
||||
export type DomAdapter = typeof _.DomAdapter;
|
||||
export var getDOM: typeof _.getDOM = _.getDOM;
|
|
@ -1,19 +0,0 @@
|
|||
|
||||
export default {
|
||||
entry: '../../../dist/packages-dist/router/esm/index.js',
|
||||
dest: '../../../dist/packages-dist/router/esm/router.umd.js',
|
||||
format: 'umd',
|
||||
moduleName: 'ng.router',
|
||||
globals: {
|
||||
'@angular/core': 'ng.core',
|
||||
'@angular/common': 'ng.common',
|
||||
'@angular/platform-browser': 'ng.platformBrowser',
|
||||
'rxjs/Subject': 'Rx',
|
||||
'rxjs/observable/PromiseObservable': 'Rx', // this is wrong, but this stuff has changed in rxjs b.6 so we need to fix it when we update.
|
||||
'rxjs/operator/toPromise': 'Rx.Observable.prototype',
|
||||
'rxjs/Observable': 'Rx'
|
||||
},
|
||||
plugins: [
|
||||
// nodeResolve({ jsnext: true, main: true }),
|
||||
]
|
||||
}
|
|
@ -1,5 +0,0 @@
|
|||
/**
|
||||
* Name of the default outlet outlet.
|
||||
* @type {string}
|
||||
*/
|
||||
export const DEFAULT_OUTLET_NAME = '__DEFAULT';
|
|
@ -1,4 +0,0 @@
|
|||
import {__core_private__ as _} from '@angular/core';
|
||||
|
||||
export var makeDecorator: typeof _.makeDecorator = _.makeDecorator;
|
||||
export var reflector: typeof _.reflector = _.reflector;
|
|
@ -1,25 +0,0 @@
|
|||
import {RouterLink} from './router_link';
|
||||
import {RouterOutlet} from './router_outlet';
|
||||
|
||||
/**
|
||||
* A list of directives. To use the router directives like {@link RouterOutlet} and
|
||||
* {@link RouterLink}, add this to your `directives` array in the {@link View} decorator of your
|
||||
* component.
|
||||
*
|
||||
* ```
|
||||
* import {Component} from '@angular/core';
|
||||
* import {ROUTER_DIRECTIVES, Routes} from '@angular/router';
|
||||
*
|
||||
* @Component({directives: [ROUTER_DIRECTIVES]})
|
||||
* @Routes([
|
||||
* {...},
|
||||
* ])
|
||||
* class AppCmp {
|
||||
* // ...
|
||||
* }
|
||||
*
|
||||
* bootstrap(AppCmp);
|
||||
* ```
|
||||
*/
|
||||
|
||||
export const ROUTER_DIRECTIVES: any[] = /*@ts2dart_const*/[RouterOutlet, RouterLink];
|
|
@ -1,95 +0,0 @@
|
|||
import {LocationStrategy} from '@angular/common';
|
||||
import {Directive, HostBinding, HostListener, Input, OnDestroy} from '@angular/core';
|
||||
|
||||
import {ObservableWrapper} from '../facade/async';
|
||||
import {isArray, isPresent, isString} from '../facade/lang';
|
||||
import {Router} from '../router';
|
||||
import {RouteSegment} from '../segments';
|
||||
|
||||
|
||||
/**
|
||||
* The RouterLink directive lets you link to specific parts of your app.
|
||||
*
|
||||
* Consider the following route configuration:
|
||||
|
||||
* ```
|
||||
* @Routes([
|
||||
* { path: '/user', component: UserCmp }
|
||||
* ]);
|
||||
* class MyComp {}
|
||||
* ```
|
||||
*
|
||||
* When linking to this `User` route, you can write:
|
||||
*
|
||||
* ```
|
||||
* <a [routerLink]="['/user']">link to user component</a>
|
||||
* ```
|
||||
*
|
||||
* RouterLink expects the value to be an array of path segments, followed by the params
|
||||
* for that level of routing. For instance `['/team', {teamId: 1}, 'user', {userId: 2}]`
|
||||
* means that we want to generate a link to `/team;teamId=1/user;userId=2`.
|
||||
*
|
||||
* The first segment name can be prepended with `/`, `./`, or `../`.
|
||||
* If the segment begins with `/`, the router will look up the route from the root of the app.
|
||||
* If the segment begins with `./`, or doesn't begin with a slash, the router will
|
||||
* instead look in the current component's children for the route.
|
||||
* And if the segment begins with `../`, the router will go up one segment in the url.
|
||||
*
|
||||
* See {@link Router.createUrlTree} for more information.
|
||||
*/
|
||||
@Directive({selector: '[routerLink]'})
|
||||
export class RouterLink implements OnDestroy {
|
||||
@Input() target: string;
|
||||
private _commands: any[] = [];
|
||||
private _subscription: any;
|
||||
|
||||
// the url displayed on the anchor element.
|
||||
@HostBinding() href: string;
|
||||
@HostBinding('class.router-link-active') isActive: boolean = false;
|
||||
|
||||
constructor(
|
||||
private _routeSegment: RouteSegment, private _router: Router,
|
||||
private _locationStrategy: LocationStrategy) {
|
||||
// because auxiliary links take existing primary and auxiliary routes into account,
|
||||
// we need to update the link whenever params or other routes change.
|
||||
this._subscription =
|
||||
ObservableWrapper.subscribe(_router.changes, (_) => { this._updateTargetUrlAndHref(); });
|
||||
}
|
||||
|
||||
ngOnDestroy() { ObservableWrapper.dispose(this._subscription); }
|
||||
|
||||
@Input()
|
||||
set routerLink(data: any[]|any) {
|
||||
if (isArray(data)) {
|
||||
this._commands = <any[]>data;
|
||||
} else {
|
||||
this._commands = [data];
|
||||
}
|
||||
this._updateTargetUrlAndHref();
|
||||
}
|
||||
|
||||
|
||||
@HostListener('click', ['$event.button', '$event.ctrlKey', '$event.metaKey'])
|
||||
onClick(button: number, ctrlKey: boolean, metaKey: boolean): boolean {
|
||||
if (button != 0 || ctrlKey || metaKey) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (isString(this.target) && this.target != '_self') {
|
||||
return true;
|
||||
}
|
||||
|
||||
this._router.navigate(this._commands, this._routeSegment);
|
||||
return false;
|
||||
}
|
||||
|
||||
private _updateTargetUrlAndHref(): void {
|
||||
let tree = this._router.createUrlTree(this._commands, this._routeSegment);
|
||||
if (isPresent(tree)) {
|
||||
this.href = this._locationStrategy.prepareExternalUrl(this._router.serializeUrl(tree));
|
||||
this.isActive = this._router.urlTree.contains(tree);
|
||||
} else {
|
||||
this.isActive = false;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,60 +0,0 @@
|
|||
import {Attribute, ComponentFactory, ComponentRef, Directive, ReflectiveInjector, ResolvedReflectiveProvider, ViewContainerRef} from '@angular/core';
|
||||
|
||||
import {DEFAULT_OUTLET_NAME} from '../constants';
|
||||
import {isBlank, isPresent} from '../facade/lang';
|
||||
import {RouterOutletMap} from '../router';
|
||||
|
||||
|
||||
/**
|
||||
* A router outlet is a placeholder that Angular dynamically fills based on the application's route.
|
||||
*
|
||||
* ## Use
|
||||
*
|
||||
* ```
|
||||
* <router-outlet></router-outlet>
|
||||
* ```
|
||||
*
|
||||
* Outlets can be named.
|
||||
*
|
||||
* ```
|
||||
* <router-outlet name="right"></router-outlet>
|
||||
* ```
|
||||
*/
|
||||
@Directive({selector: 'router-outlet'})
|
||||
export class RouterOutlet {
|
||||
private _activated: ComponentRef<any>;
|
||||
public outletMap: RouterOutletMap;
|
||||
|
||||
constructor(
|
||||
parentOutletMap: RouterOutletMap, private _location: ViewContainerRef,
|
||||
@Attribute('name') name: string) {
|
||||
parentOutletMap.registerOutlet(isBlank(name) ? DEFAULT_OUTLET_NAME : name, this);
|
||||
}
|
||||
|
||||
deactivate(): void {
|
||||
this._activated.destroy();
|
||||
this._activated = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the loaded component.
|
||||
*/
|
||||
get component(): Object { return isPresent(this._activated) ? this._activated.instance : null; }
|
||||
|
||||
/**
|
||||
* Returns true is the outlet is not empty.
|
||||
*/
|
||||
get isActivated(): boolean { return isPresent(this._activated); }
|
||||
|
||||
/**
|
||||
* Called by the Router to instantiate a new component.
|
||||
*/
|
||||
activate(
|
||||
factory: ComponentFactory<any>, providers: ResolvedReflectiveProvider[],
|
||||
outletMap: RouterOutletMap): ComponentRef<any> {
|
||||
this.outletMap = outletMap;
|
||||
let inj = ReflectiveInjector.fromResolvedProviders(providers, this._location.parentInjector);
|
||||
this._activated = this._location.createComponent(factory, this._location.length, inj, []);
|
||||
return this._activated;
|
||||
}
|
||||
}
|
|
@ -1 +0,0 @@
|
|||
../../facade/src
|
|
@ -1,27 +0,0 @@
|
|||
import {RouteSegment, RouteTree, Tree} from './segments';
|
||||
|
||||
|
||||
/**
|
||||
* Defines route lifecycle method `routerOnActivate`, which is called by the router at the end of a
|
||||
* successful route navigation.
|
||||
*
|
||||
* The `routerOnActivate` hook is called with the current and previous {@link RouteSegment}s of the
|
||||
* component and with the corresponding route trees.
|
||||
*/
|
||||
export interface OnActivate {
|
||||
routerOnActivate(
|
||||
curr: RouteSegment, prev?: RouteSegment, currTree?: RouteTree, prevTree?: RouteTree): void;
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines route lifecycle method `routerOnDeactivate`, which is called by the router before
|
||||
* destroying a component as part of a route change.
|
||||
*
|
||||
* The `routerOnDeactivate` hook is called with two {@link RouteTree}s, representing the current
|
||||
* and the future state of the application.
|
||||
*
|
||||
* `routerOnDeactivate` must return a promise. The route change will wait until the promise settles.
|
||||
*/
|
||||
export interface CanDeactivate {
|
||||
routerCanDeactivate(currTree?: RouteTree, futureTree?: RouteTree): Promise<boolean>;
|
||||
}
|
|
@ -1,6 +0,0 @@
|
|||
import './interfaces.dart';
|
||||
bool hasLifecycleHook(String name, Object obj) {
|
||||
if (name == "routerOnActivate") return obj is OnActivate;
|
||||
if (name == "routerCanDeactivate") return obj is CanDeactivate;
|
||||
return false;
|
||||
}
|
|
@ -1,8 +0,0 @@
|
|||
import {Type, isBlank} from './facade/lang';
|
||||
|
||||
export function hasLifecycleHook(name: string, obj: Object): boolean {
|
||||
if (isBlank(obj)) return false;
|
||||
let type = obj.constructor;
|
||||
if (!(type instanceof Type)) return false;
|
||||
return name in (<any>type).prototype;
|
||||
}
|
|
@ -1,213 +0,0 @@
|
|||
import {ListWrapper, StringMapWrapper} from './facade/collection';
|
||||
import {BaseException} from './facade/exceptions';
|
||||
import {isBlank, isPresent, isString, isStringMap} from './facade/lang';
|
||||
import {RouteSegment, RouteTree, Tree, TreeNode, UrlSegment, UrlTree, rootNode} from './segments';
|
||||
|
||||
export function link(
|
||||
segment: RouteSegment, routeTree: RouteTree, urlTree: UrlTree, commands: any[]): UrlTree {
|
||||
if (commands.length === 0) return urlTree;
|
||||
|
||||
let normalizedCommands = _normalizeCommands(commands);
|
||||
if (_navigateToRoot(normalizedCommands)) {
|
||||
return new UrlTree(new TreeNode<UrlSegment>(urlTree.root, []));
|
||||
}
|
||||
|
||||
let startingNode = _findStartingNode(normalizedCommands, urlTree, segment, routeTree);
|
||||
let updated = normalizedCommands.commands.length > 0 ?
|
||||
_updateMany(ListWrapper.clone(startingNode.children), normalizedCommands.commands) :
|
||||
[];
|
||||
let newRoot = _constructNewTree(rootNode(urlTree), startingNode, updated);
|
||||
|
||||
return new UrlTree(newRoot);
|
||||
}
|
||||
|
||||
function _navigateToRoot(normalizedChange: _NormalizedNavigationCommands): boolean {
|
||||
return normalizedChange.isAbsolute && normalizedChange.commands.length === 1 &&
|
||||
normalizedChange.commands[0] == '/';
|
||||
}
|
||||
|
||||
class _NormalizedNavigationCommands {
|
||||
constructor(
|
||||
public isAbsolute: boolean, public numberOfDoubleDots: number, public commands: any[]) {}
|
||||
}
|
||||
|
||||
function _normalizeCommands(commands: any[]): _NormalizedNavigationCommands {
|
||||
if (isString(commands[0]) && commands.length === 1 && commands[0] == '/') {
|
||||
return new _NormalizedNavigationCommands(true, 0, commands);
|
||||
}
|
||||
|
||||
let numberOfDoubleDots = 0;
|
||||
let isAbsolute = false;
|
||||
let res: any[] /** TODO #9100 */ = [];
|
||||
|
||||
for (let i = 0; i < commands.length; ++i) {
|
||||
let c = commands[i];
|
||||
|
||||
if (!isString(c)) {
|
||||
res.push(c);
|
||||
continue;
|
||||
}
|
||||
|
||||
let parts = c.split('/');
|
||||
for (let j = 0; j < parts.length; ++j) {
|
||||
let cc = parts[j];
|
||||
|
||||
// first exp is treated in a special way
|
||||
if (i == 0) {
|
||||
if (j == 0 && cc == '.') { // './a'
|
||||
// skip it
|
||||
} else if (j == 0 && cc == '') { // '/a'
|
||||
isAbsolute = true;
|
||||
} else if (cc == '..') { // '../a'
|
||||
numberOfDoubleDots++;
|
||||
} else if (cc != '') {
|
||||
res.push(cc);
|
||||
}
|
||||
|
||||
} else {
|
||||
if (cc != '') {
|
||||
res.push(cc);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return new _NormalizedNavigationCommands(isAbsolute, numberOfDoubleDots, res);
|
||||
}
|
||||
|
||||
function _findUrlSegment(
|
||||
segment: RouteSegment, routeTree: RouteTree, urlTree: UrlTree,
|
||||
numberOfDoubleDots: number): UrlSegment {
|
||||
let s = segment;
|
||||
while (s.urlSegments.length === 0) {
|
||||
s = routeTree.parent(s);
|
||||
}
|
||||
let urlSegment = ListWrapper.last(s.urlSegments);
|
||||
let path = urlTree.pathFromRoot(urlSegment);
|
||||
if (path.length <= numberOfDoubleDots) {
|
||||
throw new BaseException('Invalid number of \'../\'');
|
||||
}
|
||||
return path[path.length - 1 - numberOfDoubleDots];
|
||||
}
|
||||
|
||||
function _findStartingNode(
|
||||
normalizedChange: _NormalizedNavigationCommands, urlTree: UrlTree, segment: RouteSegment,
|
||||
routeTree: RouteTree): TreeNode<UrlSegment> {
|
||||
if (normalizedChange.isAbsolute) {
|
||||
return rootNode(urlTree);
|
||||
} else {
|
||||
let urlSegment =
|
||||
_findUrlSegment(segment, routeTree, urlTree, normalizedChange.numberOfDoubleDots);
|
||||
return _findMatchingNode(urlSegment, rootNode(urlTree));
|
||||
}
|
||||
}
|
||||
|
||||
function _findMatchingNode(segment: UrlSegment, node: TreeNode<UrlSegment>): TreeNode<UrlSegment> {
|
||||
if (node.value === segment) return node;
|
||||
for (var c of node.children) {
|
||||
let r = _findMatchingNode(segment, c);
|
||||
if (isPresent(r)) return r;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
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)));
|
||||
}
|
||||
}
|
||||
|
||||
function _update(node: TreeNode<UrlSegment>, commands: any[]): TreeNode<UrlSegment> {
|
||||
let rest = commands.slice(1);
|
||||
let next = rest.length === 0 ? null : rest[0];
|
||||
let outlet = _outlet(commands);
|
||||
let segment = _segment(commands);
|
||||
|
||||
// reach the end of the tree => create new tree nodes.
|
||||
if (isBlank(node) && !isStringMap(next)) {
|
||||
let urlSegment = new UrlSegment(segment, {}, outlet);
|
||||
let children = rest.length === 0 ? [] : [_update(null, rest)];
|
||||
return new TreeNode<UrlSegment>(urlSegment, children);
|
||||
|
||||
} else if (isBlank(node) && isStringMap(next)) {
|
||||
let urlSegment = new UrlSegment(segment, _stringify(next), outlet);
|
||||
return _recurse(urlSegment, node, rest.slice(1));
|
||||
|
||||
// different outlet => preserve the subtree
|
||||
} else if (outlet != node.value.outlet) {
|
||||
return node;
|
||||
|
||||
// params command
|
||||
} else if (isStringMap(segment)) {
|
||||
let newSegment = new UrlSegment(node.value.segment, _stringify(segment), node.value.outlet);
|
||||
return _recurse(newSegment, node, rest);
|
||||
|
||||
// next one is a params command && can reuse the node
|
||||
} else if (isStringMap(next) && _compare(segment, _stringify(next), node.value)) {
|
||||
return _recurse(node.value, node, rest.slice(1));
|
||||
|
||||
// next one is a params command && cannot reuse the node
|
||||
} else if (isStringMap(next)) {
|
||||
let urlSegment = new UrlSegment(segment, _stringify(next), outlet);
|
||||
return _recurse(urlSegment, node, rest.slice(1));
|
||||
|
||||
// next one is not a params command && can reuse the node
|
||||
} else if (_compare(segment, {}, node.value)) {
|
||||
return _recurse(node.value, node, rest);
|
||||
|
||||
// next one is not a params command && cannot reuse the node
|
||||
} else {
|
||||
let urlSegment = new UrlSegment(segment, {}, outlet);
|
||||
return _recurse(urlSegment, node, rest);
|
||||
}
|
||||
}
|
||||
|
||||
function _stringify(params: {[key: string]: any}): {[key: string]: string} {
|
||||
let res = {};
|
||||
StringMapWrapper.forEach(
|
||||
params, (v: any /** TODO #9100 */, k: any /** TODO #9100 */) =>
|
||||
(res as any /** TODO #9100 */)[k] = v.toString());
|
||||
return res;
|
||||
}
|
||||
|
||||
function _compare(path: string, params: {[key: string]: any}, segment: UrlSegment): boolean {
|
||||
return path == segment.segment && StringMapWrapper.equals(params, segment.parameters);
|
||||
}
|
||||
|
||||
function _recurse(
|
||||
urlSegment: UrlSegment, node: TreeNode<UrlSegment>, rest: any[]): TreeNode<UrlSegment> {
|
||||
if (rest.length === 0) {
|
||||
return new TreeNode<UrlSegment>(urlSegment, []);
|
||||
}
|
||||
return new TreeNode<UrlSegment>(urlSegment, _updateMany(ListWrapper.clone(node.children), rest));
|
||||
}
|
||||
|
||||
function _updateMany(nodes: TreeNode<UrlSegment>[], commands: any[]): TreeNode<UrlSegment>[] {
|
||||
let outlet = _outlet(commands);
|
||||
let nodesInRightOutlet = nodes.filter(c => c.value.outlet == outlet);
|
||||
if (nodesInRightOutlet.length > 0) {
|
||||
let nodeRightOutlet = nodesInRightOutlet[0]; // there can be only one
|
||||
nodes[nodes.indexOf(nodeRightOutlet)] = _update(nodeRightOutlet, commands);
|
||||
} else {
|
||||
nodes.push(_update(null, commands));
|
||||
}
|
||||
|
||||
return nodes;
|
||||
}
|
||||
|
||||
function _segment(commands: any[]): any {
|
||||
if (!isString(commands[0])) return commands[0];
|
||||
let parts = commands[0].toString().split(':');
|
||||
return parts.length > 1 ? parts[1] : commands[0];
|
||||
}
|
||||
|
||||
function _outlet(commands: any[]): string {
|
||||
if (!isString(commands[0])) return null;
|
||||
let parts = commands[0].toString().split(':');
|
||||
return parts.length > 1 ? parts[0] : null;
|
||||
}
|
|
@ -1,13 +0,0 @@
|
|||
library angular.alt_router.decorators;
|
||||
|
||||
import 'metadata.dart';
|
||||
export 'metadata.dart';
|
||||
|
||||
/**
|
||||
* Defines routes for a given component.
|
||||
*
|
||||
* It takes an array of {@link RouteMetadata}s.
|
||||
*/
|
||||
class Routes extends RoutesMetadata {
|
||||
const Routes(List<RouteMetadata> routes): super(routes);
|
||||
}
|
|
@ -1,22 +0,0 @@
|
|||
import {makeDecorator} from '../core_private';
|
||||
|
||||
import {RouteMetadata, RoutesMetadata} from './metadata';
|
||||
|
||||
|
||||
/**
|
||||
* Defines routes for a given component.
|
||||
*
|
||||
* It takes an array of {@link RouteMetadata}s.
|
||||
*/
|
||||
export interface RoutesFactory {
|
||||
(routes: RouteMetadata[]): any;
|
||||
new (routes: RouteMetadata[]): RoutesMetadata;
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines routes for a given component.
|
||||
*
|
||||
* It takes an array of {@link RouteMetadata}s.
|
||||
* @Annotation
|
||||
*/
|
||||
export var Routes: RoutesFactory = <RoutesFactory>makeDecorator(RoutesMetadata);
|
|
@ -1,51 +0,0 @@
|
|||
import {Type} from '@angular/core';
|
||||
import {stringify} from '../facade/lang';
|
||||
|
||||
/**
|
||||
* Information about a route.
|
||||
*
|
||||
* It has the following properties:
|
||||
* - `path` is a string that uses the route matcher DSL.
|
||||
* - `component` a component type.
|
||||
*
|
||||
* ### Example
|
||||
* ```
|
||||
* import {Routes} from '@angular/router';
|
||||
*
|
||||
* @Routes([
|
||||
* {path: '/home', component: HomeCmp}
|
||||
* ])
|
||||
* class MyApp {}
|
||||
* ```
|
||||
*
|
||||
* @ts2dart_const
|
||||
*/
|
||||
export abstract class RouteMetadata {
|
||||
abstract get path(): string;
|
||||
abstract get component(): Type|string;
|
||||
}
|
||||
|
||||
/**
|
||||
* See {@link RouteMetadata} for more information.
|
||||
* @ts2dart_const
|
||||
*/
|
||||
export class Route implements RouteMetadata {
|
||||
path: string;
|
||||
component: Type|string;
|
||||
constructor({path, component}: {path?: string, component?: Type|string} = {}) {
|
||||
this.path = path;
|
||||
this.component = component;
|
||||
}
|
||||
toString(): string { return `@Route(${this.path}, ${stringify(this.component)})`; }
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines routes for a given component.
|
||||
*
|
||||
* It takes an array of {@link RouteMetadata}s.
|
||||
* @ts2dart_const
|
||||
*/
|
||||
export class RoutesMetadata {
|
||||
constructor(public routes: RouteMetadata[]) {}
|
||||
toString(): string { return `@Routes(${this.routes})`; }
|
||||
}
|
|
@ -1,210 +0,0 @@
|
|||
import {BaseException, ComponentFactory, ComponentResolver} from '@angular/core';
|
||||
|
||||
import {DEFAULT_OUTLET_NAME} from './constants';
|
||||
import {reflector} from './core_private';
|
||||
import {ListWrapper, StringMapWrapper} from './facade/collection';
|
||||
import {Type, isBlank, isPresent, stringify} from './facade/lang';
|
||||
import {PromiseWrapper} from './facade/promise';
|
||||
import {RouteMetadata, RoutesMetadata} from './metadata/metadata';
|
||||
import {RouteSegment, RouteTree, Tree, TreeNode, UrlSegment, UrlTree, equalUrlSegments, rootNode} from './segments';
|
||||
|
||||
export function recognize(
|
||||
componentResolver: ComponentResolver, rootComponent: Type, url: UrlTree,
|
||||
existingTree: RouteTree): Promise<RouteTree> {
|
||||
let matched = new _MatchResult(rootComponent, [url.root], {}, rootNode(url).children, []);
|
||||
return _constructSegment(componentResolver, matched, rootNode(existingTree))
|
||||
.then(roots => new RouteTree(roots[0]));
|
||||
}
|
||||
|
||||
function _recognize(
|
||||
componentResolver: ComponentResolver, parentComponent: Type, url: TreeNode<UrlSegment>,
|
||||
existingSegments: TreeNode<RouteSegment>[]): Promise<TreeNode<RouteSegment>[]> {
|
||||
let metadata = _readMetadata(parentComponent); // should read from the factory instead
|
||||
if (isBlank(metadata)) {
|
||||
throw new BaseException(
|
||||
`Component '${stringify(parentComponent)}' does not have route configuration`);
|
||||
}
|
||||
|
||||
let match: any /** TODO #9100 */;
|
||||
try {
|
||||
match = _match(metadata, url);
|
||||
} catch (e) {
|
||||
return PromiseWrapper.reject(e, null);
|
||||
}
|
||||
|
||||
let segmentsWithRightOutlet = existingSegments.filter(r => r.value.outlet == match.outlet);
|
||||
let segmentWithRightOutlet =
|
||||
segmentsWithRightOutlet.length > 0 ? segmentsWithRightOutlet[0] : null;
|
||||
|
||||
let main = _constructSegment(componentResolver, match, segmentWithRightOutlet);
|
||||
let aux = _recognizeMany(componentResolver, parentComponent, match.aux, existingSegments)
|
||||
.then(_checkOutletNameUniqueness);
|
||||
return PromiseWrapper.all([main, aux]).then(ListWrapper.flatten);
|
||||
}
|
||||
|
||||
function _recognizeMany(
|
||||
componentResolver: ComponentResolver, parentComponent: Type, urls: TreeNode<UrlSegment>[],
|
||||
existingSegments: TreeNode<RouteSegment>[]): Promise<TreeNode<RouteSegment>[]> {
|
||||
let recognized =
|
||||
urls.map(u => _recognize(componentResolver, parentComponent, u, existingSegments));
|
||||
return PromiseWrapper.all(recognized).then(ListWrapper.flatten);
|
||||
}
|
||||
|
||||
function _constructSegment(
|
||||
componentResolver: ComponentResolver, matched: _MatchResult,
|
||||
existingSegment: TreeNode<RouteSegment>): Promise<TreeNode<RouteSegment>[]> {
|
||||
return componentResolver.resolveComponent(matched.component).then(factory => {
|
||||
let segment = _createOrReuseSegment(matched, factory, existingSegment);
|
||||
let existingChildren = isPresent(existingSegment) ? existingSegment.children : [];
|
||||
|
||||
if (matched.leftOverUrl.length > 0) {
|
||||
return _recognizeMany(
|
||||
componentResolver, factory.componentType, matched.leftOverUrl, existingChildren)
|
||||
.then(children => [new TreeNode<RouteSegment>(segment, children)]);
|
||||
} else {
|
||||
return _recognizeLeftOvers(componentResolver, factory.componentType, existingChildren)
|
||||
.then(children => [new TreeNode<RouteSegment>(segment, children)]);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function _createOrReuseSegment(
|
||||
matched: _MatchResult, factory: ComponentFactory<any>,
|
||||
segmentNode: TreeNode<RouteSegment>): RouteSegment {
|
||||
let segment = isPresent(segmentNode) ? segmentNode.value : null;
|
||||
|
||||
if (isPresent(segment) && equalUrlSegments(segment.urlSegments, matched.consumedUrlSegments) &&
|
||||
StringMapWrapper.equals(segment.parameters, matched.parameters) &&
|
||||
segment.outlet == matched.outlet && factory.componentType == segment.type) {
|
||||
return segment;
|
||||
} else {
|
||||
return new RouteSegment(
|
||||
matched.consumedUrlSegments, matched.parameters, matched.outlet, factory.componentType,
|
||||
factory);
|
||||
}
|
||||
}
|
||||
|
||||
function _recognizeLeftOvers(
|
||||
componentResolver: ComponentResolver, parentComponent: Type,
|
||||
existingSegments: TreeNode<RouteSegment>[]): Promise<TreeNode<RouteSegment>[]> {
|
||||
return componentResolver.resolveComponent(parentComponent).then(factory => {
|
||||
let metadata = _readMetadata(factory.componentType);
|
||||
if (isBlank(metadata)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
let r = (<any[]>metadata.routes).filter(r => r.path == '' || r.path == '/');
|
||||
if (r.length === 0) {
|
||||
return PromiseWrapper.resolve([]);
|
||||
} else {
|
||||
let segmentsWithMatchingOutlet =
|
||||
existingSegments.filter(r => r.value.outlet == DEFAULT_OUTLET_NAME);
|
||||
let segmentWithMatchingOutlet =
|
||||
segmentsWithMatchingOutlet.length > 0 ? segmentsWithMatchingOutlet[0] : null;
|
||||
let existingChildren =
|
||||
isPresent(segmentWithMatchingOutlet) ? segmentWithMatchingOutlet.children : [];
|
||||
|
||||
return _recognizeLeftOvers(componentResolver, r[0].component, existingChildren)
|
||||
.then(children => {
|
||||
return componentResolver.resolveComponent(r[0].component).then(factory => {
|
||||
let segment = _createOrReuseSegment(
|
||||
new _MatchResult(r[0].component, [], {}, [], []), factory,
|
||||
segmentWithMatchingOutlet);
|
||||
return [new TreeNode<RouteSegment>(segment, children)];
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function _match(metadata: RoutesMetadata, url: TreeNode<UrlSegment>): _MatchResult {
|
||||
for (let r of metadata.routes) {
|
||||
let matchingResult = _matchWithParts(r, url);
|
||||
if (isPresent(matchingResult)) {
|
||||
return matchingResult;
|
||||
}
|
||||
}
|
||||
let availableRoutes = metadata.routes.map(r => `'${r.path}'`).join(', ');
|
||||
throw new BaseException(
|
||||
`Cannot match any routes. Current segment: '${url.value}'. Available routes: [${availableRoutes}].`);
|
||||
}
|
||||
|
||||
function _matchWithParts(route: RouteMetadata, url: TreeNode<UrlSegment>): _MatchResult {
|
||||
let path = route.path.startsWith('/') ? route.path.substring(1) : route.path;
|
||||
|
||||
if (path == '*') {
|
||||
return new _MatchResult(route.component, [], null, [], []);
|
||||
}
|
||||
|
||||
let parts = path.split('/');
|
||||
let positionalParams = {};
|
||||
let consumedUrlSegments: any[] /** TODO #9100 */ = [];
|
||||
|
||||
let lastParent: TreeNode<UrlSegment> = null;
|
||||
let lastSegment: TreeNode<UrlSegment> = null;
|
||||
|
||||
let current = url;
|
||||
for (let i = 0; i < parts.length; ++i) {
|
||||
if (isBlank(current)) return null;
|
||||
|
||||
let p = parts[i];
|
||||
let isLastSegment = i === parts.length - 1;
|
||||
let isLastParent = i === parts.length - 2;
|
||||
let isPosParam = p.startsWith(':');
|
||||
|
||||
if (!isPosParam && p != current.value.segment) return null;
|
||||
if (isLastSegment) {
|
||||
lastSegment = current;
|
||||
}
|
||||
if (isLastParent) {
|
||||
lastParent = current;
|
||||
}
|
||||
|
||||
if (isPosParam) {
|
||||
(positionalParams as any /** TODO #9100 */)[p.substring(1)] = current.value.segment;
|
||||
}
|
||||
|
||||
consumedUrlSegments.push(current.value);
|
||||
|
||||
current = ListWrapper.first(current.children);
|
||||
}
|
||||
|
||||
let p = lastSegment.value.parameters;
|
||||
let parameters = <{[key: string]: string}>StringMapWrapper.merge(p, positionalParams);
|
||||
let axuUrlSubtrees = isPresent(lastParent) ? lastParent.children.slice(1) : [];
|
||||
|
||||
return new _MatchResult(
|
||||
route.component, consumedUrlSegments, parameters, lastSegment.children, axuUrlSubtrees);
|
||||
}
|
||||
|
||||
function _checkOutletNameUniqueness(nodes: TreeNode<RouteSegment>[]): TreeNode<RouteSegment>[] {
|
||||
let names = {};
|
||||
nodes.forEach(n => {
|
||||
let segmentWithSameOutletName = (names as any /** TODO #9100 */)[n.value.outlet];
|
||||
if (isPresent(segmentWithSameOutletName)) {
|
||||
let p = segmentWithSameOutletName.stringifiedUrlSegments;
|
||||
let c = n.value.stringifiedUrlSegments;
|
||||
throw new BaseException(`Two segments cannot have the same outlet name: '${p}' and '${c}'.`);
|
||||
}
|
||||
(names as any /** TODO #9100 */)[n.value.outlet] = n.value;
|
||||
});
|
||||
return nodes;
|
||||
}
|
||||
|
||||
class _MatchResult {
|
||||
constructor(
|
||||
public component: Type|string, public consumedUrlSegments: UrlSegment[],
|
||||
public parameters: {[key: string]: string}, public leftOverUrl: TreeNode<UrlSegment>[],
|
||||
public aux: TreeNode<UrlSegment>[]) {}
|
||||
|
||||
get outlet(): string {
|
||||
return this.consumedUrlSegments.length === 0 || isBlank(this.consumedUrlSegments[0].outlet) ?
|
||||
DEFAULT_OUTLET_NAME :
|
||||
this.consumedUrlSegments[0].outlet;
|
||||
}
|
||||
}
|
||||
|
||||
function _readMetadata(componentType: Type) {
|
||||
let metadata = reflector.annotations(componentType).filter(f => f instanceof RoutesMetadata);
|
||||
return ListWrapper.first(metadata);
|
||||
}
|
|
@ -1,282 +0,0 @@
|
|||
import {Location} from '@angular/common';
|
||||
import {BaseException, ComponentResolver, ReflectiveInjector, provide} from '@angular/core';
|
||||
|
||||
import {DEFAULT_OUTLET_NAME} from './constants';
|
||||
import {RouterOutlet} from './directives/router_outlet';
|
||||
import {EventEmitter, Observable, ObservableWrapper, PromiseWrapper} from './facade/async';
|
||||
import {ListWrapper, StringMapWrapper} from './facade/collection';
|
||||
import {Type, isBlank, isPresent} from './facade/lang';
|
||||
import {CanDeactivate} from './interfaces';
|
||||
import {hasLifecycleHook} from './lifecycle_reflector';
|
||||
import {link} from './link';
|
||||
import {recognize} from './recognize';
|
||||
import {RouterUrlSerializer} from './router_url_serializer';
|
||||
import {RouteSegment, RouteTree, TreeNode, UrlSegment, UrlTree, createEmptyRouteTree, rootNode, routeSegmentComponentFactory, serializeRouteSegmentTree} from './segments';
|
||||
|
||||
export class RouterOutletMap {
|
||||
/** @internal */
|
||||
_outlets: {[name: string]: RouterOutlet} = {};
|
||||
registerOutlet(name: string, outlet: RouterOutlet): void { this._outlets[name] = outlet; }
|
||||
}
|
||||
|
||||
/**
|
||||
* The `Router` is responsible for mapping URLs to components.
|
||||
*
|
||||
* You can see the state of the router by inspecting the read-only fields `router.urlTree`
|
||||
* and `router.routeTree`.
|
||||
*/
|
||||
export class Router {
|
||||
private _routeTree: RouteTree;
|
||||
private _urlTree: UrlTree;
|
||||
private _locationSubscription: any;
|
||||
private _changes: EventEmitter<void> = new EventEmitter<void>();
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
constructor(
|
||||
private _rootComponent: Object, private _rootComponentType: Type,
|
||||
private _componentResolver: ComponentResolver, private _urlSerializer: RouterUrlSerializer,
|
||||
private _routerOutletMap: RouterOutletMap, private _location: Location) {
|
||||
this._routeTree = createEmptyRouteTree(this._rootComponentType);
|
||||
this._setUpLocationChangeListener();
|
||||
this.navigateByUrl(this._location.path());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current url tree.
|
||||
*/
|
||||
get urlTree(): UrlTree { return this._urlTree; }
|
||||
|
||||
/**
|
||||
* Returns the current route tree.
|
||||
*/
|
||||
get routeTree(): RouteTree { return this._routeTree; }
|
||||
|
||||
/**
|
||||
* An observable or url changes from the router.
|
||||
*/
|
||||
get changes(): Observable<void> { return this._changes; }
|
||||
|
||||
/**
|
||||
* Navigate based on the provided url. This navigation is always absolute.
|
||||
*
|
||||
* ### Usage
|
||||
*
|
||||
* ```
|
||||
* router.navigateByUrl("/team/33/user/11");
|
||||
* ```
|
||||
*/
|
||||
navigateByUrl(url: string): Promise<void> {
|
||||
return this._navigate(this._urlSerializer.parse(url));
|
||||
}
|
||||
|
||||
/**
|
||||
* Navigate based on the provided array of commands and a starting point.
|
||||
* If no segment is provided, the navigation is absolute.
|
||||
*
|
||||
* ### Usage
|
||||
*
|
||||
* ```
|
||||
* router.navigate(['team', 33, 'team', '11], segment);
|
||||
* ```
|
||||
*/
|
||||
navigate(commands: any[], segment?: RouteSegment): Promise<void> {
|
||||
return this._navigate(this.createUrlTree(commands, segment));
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
dispose(): void { ObservableWrapper.dispose(this._locationSubscription); }
|
||||
|
||||
/**
|
||||
* Applies an array of commands to the current url tree and creates
|
||||
* a new url tree.
|
||||
*
|
||||
* When given a segment, applies the given commands starting from the segment.
|
||||
* When not given a segment, applies the given command starting from the root.
|
||||
*
|
||||
* ### Usage
|
||||
*
|
||||
* ```
|
||||
* // create /team/33/user/11
|
||||
* router.createUrlTree(['/team', 33, 'user', 11]);
|
||||
*
|
||||
* // create /team/33;expand=true/user/11
|
||||
* router.createUrlTree(['/team', 33, {expand: true}, 'user', 11]);
|
||||
*
|
||||
* // you can collapse static fragments like this
|
||||
* router.createUrlTree(['/team/33/user', userId]);
|
||||
*
|
||||
* // assuming the current url is `/team/33/user/11` and the segment points to `user/11`
|
||||
*
|
||||
* // navigate to /team/33/user/11/details
|
||||
* router.createUrlTree(['details'], segment);
|
||||
*
|
||||
* // navigate to /team/33/user/22
|
||||
* router.createUrlTree(['../22'], segment);
|
||||
*
|
||||
* // navigate to /team/44/user/22
|
||||
* router.createUrlTree(['../../team/44/user/22'], segment);
|
||||
* ```
|
||||
*/
|
||||
createUrlTree(commands: any[], segment?: RouteSegment): UrlTree {
|
||||
let s = isPresent(segment) ? segment : this._routeTree.root;
|
||||
return link(s, this._routeTree, this.urlTree, commands);
|
||||
}
|
||||
|
||||
/**
|
||||
* Serializes a {@link UrlTree} into a string.
|
||||
*/
|
||||
serializeUrl(url: UrlTree): string { return this._urlSerializer.serialize(url); }
|
||||
|
||||
private _setUpLocationChangeListener(): void {
|
||||
this._locationSubscription = this._location.subscribe(
|
||||
(change) => { this._navigate(this._urlSerializer.parse(change['url']), change['pop']); });
|
||||
}
|
||||
|
||||
private _navigate(url: UrlTree, preventPushState?: boolean): Promise<void> {
|
||||
this._urlTree = url;
|
||||
return recognize(this._componentResolver, this._rootComponentType, url, this._routeTree)
|
||||
.then(currTree => {
|
||||
return new _ActivateSegments(currTree, this._routeTree)
|
||||
.activate(this._routerOutletMap, this._rootComponent)
|
||||
.then(updated => {
|
||||
if (updated) {
|
||||
this._routeTree = currTree;
|
||||
if (isBlank(preventPushState) || !preventPushState) {
|
||||
let path = this._urlSerializer.serialize(this._urlTree);
|
||||
if (this._location.isCurrentPathEqualTo(path)) {
|
||||
this._location.replaceState(path);
|
||||
} else {
|
||||
this._location.go(path);
|
||||
}
|
||||
}
|
||||
this._changes.emit(null);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class _ActivateSegments {
|
||||
private deactivations: Object[][] = [];
|
||||
private performMutation: boolean = true;
|
||||
|
||||
constructor(private currTree: RouteTree, private prevTree: RouteTree) {}
|
||||
|
||||
activate(parentOutletMap: RouterOutletMap, rootComponent: Object): Promise<boolean> {
|
||||
let prevRoot = isPresent(this.prevTree) ? rootNode(this.prevTree) : null;
|
||||
let currRoot = rootNode(this.currTree);
|
||||
|
||||
return this.canDeactivate(currRoot, prevRoot, parentOutletMap, rootComponent).then(res => {
|
||||
this.performMutation = true;
|
||||
if (res) {
|
||||
this.activateChildSegments(currRoot, prevRoot, parentOutletMap, [rootComponent]);
|
||||
}
|
||||
return res;
|
||||
});
|
||||
}
|
||||
|
||||
private canDeactivate(
|
||||
currRoot: TreeNode<RouteSegment>, prevRoot: TreeNode<RouteSegment>,
|
||||
outletMap: RouterOutletMap, rootComponent: Object): Promise<boolean> {
|
||||
this.performMutation = false;
|
||||
this.activateChildSegments(currRoot, prevRoot, outletMap, [rootComponent]);
|
||||
|
||||
let allPaths = PromiseWrapper.all(this.deactivations.map(r => this.checkCanDeactivatePath(r)));
|
||||
return allPaths.then((values: boolean[]) => values.filter(v => v).length === values.length);
|
||||
}
|
||||
|
||||
private checkCanDeactivatePath(path: Object[]): Promise<boolean> {
|
||||
let curr = PromiseWrapper.resolve(true);
|
||||
for (let p of ListWrapper.reversed(path)) {
|
||||
curr = curr.then(_ => {
|
||||
if (hasLifecycleHook('routerCanDeactivate', p)) {
|
||||
return (<CanDeactivate>p).routerCanDeactivate(this.prevTree, this.currTree);
|
||||
} else {
|
||||
return _;
|
||||
}
|
||||
});
|
||||
}
|
||||
return curr;
|
||||
}
|
||||
|
||||
private activateChildSegments(
|
||||
currNode: TreeNode<RouteSegment>, prevNode: TreeNode<RouteSegment>,
|
||||
outletMap: RouterOutletMap, components: Object[]): void {
|
||||
let prevChildren = isPresent(prevNode) ? prevNode.children.reduce((m, c) => {
|
||||
(m as any /** TODO #9100 */)[c.value.outlet] = c;
|
||||
return m;
|
||||
}, {}) : {};
|
||||
|
||||
currNode.children.forEach(c => {
|
||||
this.activateSegments(
|
||||
c, (prevChildren as any /** TODO #9100 */)[c.value.outlet], outletMap, components);
|
||||
StringMapWrapper.delete(prevChildren, c.value.outlet);
|
||||
});
|
||||
|
||||
StringMapWrapper.forEach(
|
||||
prevChildren, (v: any /** TODO #9100 */, k: any /** TODO #9100 */) =>
|
||||
this.deactivateOutlet(outletMap._outlets[k], components));
|
||||
}
|
||||
|
||||
activateSegments(
|
||||
currNode: TreeNode<RouteSegment>, prevNode: TreeNode<RouteSegment>,
|
||||
parentOutletMap: RouterOutletMap, components: Object[]): void {
|
||||
let curr = currNode.value;
|
||||
let prev = isPresent(prevNode) ? prevNode.value : null;
|
||||
let outlet = this.getOutlet(parentOutletMap, currNode.value);
|
||||
|
||||
if (curr === prev) {
|
||||
this.activateChildSegments(
|
||||
currNode, prevNode, outlet.outletMap, components.concat([outlet.component]));
|
||||
} else {
|
||||
this.deactivateOutlet(outlet, components);
|
||||
if (this.performMutation) {
|
||||
let outletMap = new RouterOutletMap();
|
||||
let component = this.activateNewSegments(outletMap, curr, prev, outlet);
|
||||
this.activateChildSegments(currNode, prevNode, outletMap, components.concat([component]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private activateNewSegments(
|
||||
outletMap: RouterOutletMap, curr: RouteSegment, prev: RouteSegment,
|
||||
outlet: RouterOutlet): Object {
|
||||
let resolved = ReflectiveInjector.resolve(
|
||||
[{provide: RouterOutletMap, useValue: outletMap}, {provide: RouteSegment, useValue: curr}]);
|
||||
let ref = outlet.activate(routeSegmentComponentFactory(curr), resolved, outletMap);
|
||||
if (hasLifecycleHook('routerOnActivate', ref.instance)) {
|
||||
ref.instance.routerOnActivate(curr, prev, this.currTree, this.prevTree);
|
||||
}
|
||||
return ref.instance;
|
||||
}
|
||||
|
||||
private getOutlet(outletMap: RouterOutletMap, segment: RouteSegment): RouterOutlet {
|
||||
let outlet = outletMap._outlets[segment.outlet];
|
||||
if (isBlank(outlet)) {
|
||||
if (segment.outlet == DEFAULT_OUTLET_NAME) {
|
||||
throw new BaseException(`Cannot find default outlet`);
|
||||
} else {
|
||||
throw new BaseException(`Cannot find the outlet ${segment.outlet}`);
|
||||
}
|
||||
}
|
||||
return outlet;
|
||||
}
|
||||
|
||||
private deactivateOutlet(outlet: RouterOutlet, components: Object[]): void {
|
||||
if (isPresent(outlet) && outlet.isActivated) {
|
||||
StringMapWrapper.forEach(
|
||||
outlet.outletMap._outlets, (v: any /** TODO #9100 */, k: any /** TODO #9100 */) =>
|
||||
this.deactivateOutlet(v, components));
|
||||
if (this.performMutation) {
|
||||
outlet.deactivate();
|
||||
} else {
|
||||
this.deactivations.push(components.concat([outlet.component]));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,26 +0,0 @@
|
|||
import {ROUTER_PROVIDERS_COMMON} from './router_providers_common';
|
||||
|
||||
/**
|
||||
* A list of providers. To use the router, you must add this to your application.
|
||||
*
|
||||
* ```
|
||||
* import {Component} from '@angular/core';
|
||||
* import {
|
||||
* ROUTER_DIRECTIVES,
|
||||
* ROUTER_PROVIDERS,
|
||||
* Routes
|
||||
* } from '@angular/router';
|
||||
*
|
||||
* @Component({directives: [ROUTER_DIRECTIVES]})
|
||||
* @Routes([
|
||||
* {...},
|
||||
* ])
|
||||
* class AppCmp {
|
||||
* // ...
|
||||
* }
|
||||
*
|
||||
* bootstrap(AppCmp, [ROUTER_PROVIDERS]);
|
||||
* ```
|
||||
*/
|
||||
// TODO: merge with router_providers_common.ts
|
||||
export const ROUTER_PROVIDERS: any[] = /*@ts2dart_const*/[ROUTER_PROVIDERS_COMMON];
|
|
@ -1,40 +0,0 @@
|
|||
import {Location, LocationStrategy, PathLocationStrategy} from '@angular/common';
|
||||
import {ApplicationRef, BaseException, ComponentResolver} from '@angular/core';
|
||||
|
||||
import {Router, RouterOutletMap} from './router';
|
||||
import {DefaultRouterUrlSerializer, RouterUrlSerializer} from './router_url_serializer';
|
||||
import {RouteSegment} from './segments';
|
||||
|
||||
|
||||
/**
|
||||
* The Platform agnostic ROUTER PROVIDERS
|
||||
*/
|
||||
export const ROUTER_PROVIDERS_COMMON: any[] = /*@ts2dart_const*/[
|
||||
RouterOutletMap,
|
||||
/*@ts2dart_Provider*/ {provide: RouterUrlSerializer, useClass: DefaultRouterUrlSerializer},
|
||||
/*@ts2dart_Provider*/ {provide: LocationStrategy, useClass: PathLocationStrategy}, Location,
|
||||
/*@ts2dart_Provider*/ {
|
||||
provide: Router,
|
||||
useFactory: routerFactory,
|
||||
deps: /*@ts2dart_const*/
|
||||
[ApplicationRef, ComponentResolver, RouterUrlSerializer, RouterOutletMap, Location],
|
||||
},
|
||||
/*@ts2dart_Provider*/ {provide: RouteSegment, useFactory: routeSegmentFactory, deps: [Router]}
|
||||
];
|
||||
|
||||
export function routerFactory(
|
||||
app: ApplicationRef, componentResolver: ComponentResolver, urlSerializer: RouterUrlSerializer,
|
||||
routerOutletMap: RouterOutletMap, location: Location): Router {
|
||||
if (app.componentTypes.length == 0) {
|
||||
throw new BaseException('Bootstrap at least one component before injecting Router.');
|
||||
}
|
||||
// TODO: vsavkin this should not be null
|
||||
let router = new Router(
|
||||
null, app.componentTypes[0], componentResolver, urlSerializer, routerOutletMap, location);
|
||||
app.registerDisposeListener(() => router.dispose());
|
||||
return router;
|
||||
}
|
||||
|
||||
export function routeSegmentFactory(router: Router): RouteSegment {
|
||||
return router.routeTree.root;
|
||||
}
|
|
@ -1,201 +0,0 @@
|
|||
import {BaseException} from '@angular/core';
|
||||
|
||||
import {RegExpWrapper, isBlank, isPresent} from './facade/lang';
|
||||
import {Tree, TreeNode, UrlSegment, UrlTree, rootNode} from './segments';
|
||||
|
||||
|
||||
/**
|
||||
* Defines a way to serialize/deserialize a url tree.
|
||||
*/
|
||||
export abstract class RouterUrlSerializer {
|
||||
/**
|
||||
* Parse a url into a {@Link UrlTree}
|
||||
*/
|
||||
abstract parse(url: string): UrlTree;
|
||||
|
||||
/**
|
||||
* Converts a {@Link UrlTree} into a url
|
||||
*/
|
||||
abstract serialize(tree: UrlTree): string;
|
||||
}
|
||||
|
||||
/**
|
||||
* A default implementation of the serialization.
|
||||
*/
|
||||
export class DefaultRouterUrlSerializer extends RouterUrlSerializer {
|
||||
parse(url: string): UrlTree {
|
||||
let root = new _UrlParser().parse(url);
|
||||
return new UrlTree(root);
|
||||
}
|
||||
|
||||
serialize(tree: UrlTree): string { return _serializeUrlTreeNode(rootNode(tree)); }
|
||||
}
|
||||
|
||||
function _serializeUrlTreeNode(node: TreeNode<UrlSegment>): string {
|
||||
return `${node.value}${_serializeChildren(node)}`;
|
||||
}
|
||||
|
||||
function _serializeUrlTreeNodes(nodes: TreeNode<UrlSegment>[]): string {
|
||||
let main = nodes[0].value.toString();
|
||||
let auxNodes = nodes.slice(1);
|
||||
let aux = auxNodes.length > 0 ? `(${auxNodes.map(_serializeUrlTreeNode).join("//")})` : '';
|
||||
let children = _serializeChildren(nodes[0]);
|
||||
return `${main}${aux}${children}`;
|
||||
}
|
||||
|
||||
function _serializeChildren(node: TreeNode<UrlSegment>): string {
|
||||
if (node.children.length > 0) {
|
||||
return `/${_serializeUrlTreeNodes(node.children)}`;
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
var SEGMENT_RE = RegExpWrapper.create('^[^\\/\\(\\)\\?;=&#]+');
|
||||
function matchUrlSegment(str: string): string {
|
||||
var match = RegExpWrapper.firstMatch(SEGMENT_RE, str);
|
||||
return isPresent(match) ? match[0] : '';
|
||||
}
|
||||
var QUERY_PARAM_VALUE_RE = RegExpWrapper.create('^[^\\(\\)\\?;&#]+');
|
||||
function matchUrlQueryParamValue(str: string): string {
|
||||
var match = RegExpWrapper.firstMatch(QUERY_PARAM_VALUE_RE, str);
|
||||
return isPresent(match) ? match[0] : '';
|
||||
}
|
||||
|
||||
class _UrlParser {
|
||||
private _remaining: string;
|
||||
|
||||
peekStartsWith(str: string): boolean { return this._remaining.startsWith(str); }
|
||||
|
||||
capture(str: string): void {
|
||||
if (!this._remaining.startsWith(str)) {
|
||||
throw new BaseException(`Expected "${str}".`);
|
||||
}
|
||||
this._remaining = this._remaining.substring(str.length);
|
||||
}
|
||||
|
||||
parse(url: string): TreeNode<UrlSegment> {
|
||||
this._remaining = url;
|
||||
if (url == '' || url == '/') {
|
||||
return new TreeNode<UrlSegment>(new UrlSegment('', {}, null), []);
|
||||
} else {
|
||||
return this.parseRoot();
|
||||
}
|
||||
}
|
||||
|
||||
parseRoot(): TreeNode<UrlSegment> {
|
||||
let segments = this.parseSegments();
|
||||
return new TreeNode<UrlSegment>(new UrlSegment('', {}, null), segments);
|
||||
}
|
||||
|
||||
parseSegments(outletName: string = null): TreeNode<UrlSegment>[] {
|
||||
if (this._remaining.length == 0) {
|
||||
return [];
|
||||
}
|
||||
if (this.peekStartsWith('/')) {
|
||||
this.capture('/');
|
||||
}
|
||||
var path = matchUrlSegment(this._remaining);
|
||||
this.capture(path);
|
||||
|
||||
|
||||
if (path.indexOf(':') > -1) {
|
||||
let parts = path.split(':');
|
||||
outletName = parts[0];
|
||||
path = parts[1];
|
||||
}
|
||||
|
||||
var matrixParams: {[key: string]: any} = {};
|
||||
if (this.peekStartsWith(';')) {
|
||||
matrixParams = this.parseMatrixParams();
|
||||
}
|
||||
|
||||
var aux: any[] /** TODO #9100 */ = [];
|
||||
if (this.peekStartsWith('(')) {
|
||||
aux = this.parseAuxiliaryRoutes();
|
||||
}
|
||||
|
||||
var children: TreeNode<UrlSegment>[] = [];
|
||||
if (this.peekStartsWith('/') && !this.peekStartsWith('//')) {
|
||||
this.capture('/');
|
||||
children = this.parseSegments();
|
||||
}
|
||||
|
||||
let segment = new UrlSegment(path, matrixParams, outletName);
|
||||
let node = new TreeNode<UrlSegment>(segment, children);
|
||||
return [node].concat(aux);
|
||||
}
|
||||
|
||||
parseQueryParams(): {[key: string]: any} {
|
||||
var params: {[key: string]: any} = {};
|
||||
this.capture('?');
|
||||
this.parseQueryParam(params);
|
||||
while (this._remaining.length > 0 && this.peekStartsWith('&')) {
|
||||
this.capture('&');
|
||||
this.parseQueryParam(params);
|
||||
}
|
||||
return params;
|
||||
}
|
||||
|
||||
parseMatrixParams(): {[key: string]: any} {
|
||||
var params: {[key: string]: any} = {};
|
||||
while (this._remaining.length > 0 && this.peekStartsWith(';')) {
|
||||
this.capture(';');
|
||||
this.parseParam(params);
|
||||
}
|
||||
return params;
|
||||
}
|
||||
|
||||
parseParam(params: {[key: string]: any}): void {
|
||||
var key = matchUrlSegment(this._remaining);
|
||||
if (isBlank(key)) {
|
||||
return;
|
||||
}
|
||||
this.capture(key);
|
||||
var value: any = 'true';
|
||||
if (this.peekStartsWith('=')) {
|
||||
this.capture('=');
|
||||
var valueMatch = matchUrlSegment(this._remaining);
|
||||
if (isPresent(valueMatch)) {
|
||||
value = valueMatch;
|
||||
this.capture(value);
|
||||
}
|
||||
}
|
||||
|
||||
params[key] = value;
|
||||
}
|
||||
|
||||
parseQueryParam(params: {[key: string]: any}): void {
|
||||
var key = matchUrlSegment(this._remaining);
|
||||
if (isBlank(key)) {
|
||||
return;
|
||||
}
|
||||
this.capture(key);
|
||||
var value: any = 'true';
|
||||
if (this.peekStartsWith('=')) {
|
||||
this.capture('=');
|
||||
var valueMatch = matchUrlQueryParamValue(this._remaining);
|
||||
if (isPresent(valueMatch)) {
|
||||
value = valueMatch;
|
||||
this.capture(value);
|
||||
}
|
||||
}
|
||||
|
||||
params[key] = value;
|
||||
}
|
||||
|
||||
parseAuxiliaryRoutes(): TreeNode<UrlSegment>[] {
|
||||
var segments: any[] /** TODO #9100 */ = [];
|
||||
this.capture('(');
|
||||
|
||||
while (!this.peekStartsWith(')') && this._remaining.length > 0) {
|
||||
segments = segments.concat(this.parseSegments('aux'));
|
||||
if (this.peekStartsWith('//')) {
|
||||
this.capture('//');
|
||||
}
|
||||
}
|
||||
this.capture(')');
|
||||
|
||||
return segments;
|
||||
}
|
||||
}
|
|
@ -1,157 +0,0 @@
|
|||
import {ComponentFactory, Type} from '@angular/core';
|
||||
|
||||
import {DEFAULT_OUTLET_NAME} from './constants';
|
||||
import {ListWrapper, StringMapWrapper} from './facade/collection';
|
||||
import {NumberWrapper, isBlank, isPresent, stringify} from './facade/lang';
|
||||
|
||||
export class Tree<T> {
|
||||
/** @internal */
|
||||
_root: TreeNode<T>;
|
||||
|
||||
constructor(root: TreeNode<T>) { this._root = root; }
|
||||
|
||||
get root(): T { return this._root.value; }
|
||||
|
||||
parent(t: T): T {
|
||||
let p = this.pathFromRoot(t);
|
||||
return p.length > 1 ? p[p.length - 2] : null;
|
||||
}
|
||||
|
||||
children(t: T): T[] {
|
||||
let n = _findNode(t, this._root);
|
||||
return isPresent(n) ? n.children.map(t => t.value) : null;
|
||||
}
|
||||
|
||||
firstChild(t: T): T {
|
||||
let n = _findNode(t, this._root);
|
||||
return isPresent(n) && n.children.length > 0 ? n.children[0].value : null;
|
||||
}
|
||||
|
||||
pathFromRoot(t: T): T[] { return _findPath(t, this._root, []).map(s => s.value); }
|
||||
|
||||
contains(tree: Tree<T>): boolean { return _contains(this._root, tree._root); }
|
||||
}
|
||||
|
||||
export class UrlTree extends Tree<UrlSegment> {
|
||||
constructor(root: TreeNode<UrlSegment>) { super(root); }
|
||||
}
|
||||
|
||||
export class RouteTree extends Tree<RouteSegment> {
|
||||
constructor(root: TreeNode<RouteSegment>) { super(root); }
|
||||
}
|
||||
|
||||
export function rootNode<T>(tree: Tree<T>): TreeNode<T> {
|
||||
return tree._root;
|
||||
}
|
||||
|
||||
function _findNode<T>(expected: T, c: TreeNode<T>): TreeNode<T> {
|
||||
if (expected === c.value) return c;
|
||||
for (let cc of c.children) {
|
||||
let r = _findNode(expected, cc);
|
||||
if (isPresent(r)) return r;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function _findPath<T>(expected: T, c: TreeNode<T>, collected: TreeNode<T>[]): TreeNode<T>[] {
|
||||
collected.push(c);
|
||||
if (expected === c.value) return collected;
|
||||
|
||||
for (let cc of c.children) {
|
||||
let r = _findPath(expected, cc, ListWrapper.clone(collected));
|
||||
if (isPresent(r)) return r;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
function _contains<T>(tree: TreeNode<T>, subtree: TreeNode<T>): boolean {
|
||||
if (tree.value !== subtree.value) return false;
|
||||
|
||||
for (let subtreeNode of subtree.children) {
|
||||
let s = tree.children.filter(child => child.value === subtreeNode.value);
|
||||
if (s.length === 0) return false;
|
||||
if (!_contains(s[0], subtreeNode)) return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
export class TreeNode<T> {
|
||||
constructor(public value: T, public children: TreeNode<T>[]) {}
|
||||
}
|
||||
|
||||
export class UrlSegment {
|
||||
constructor(
|
||||
public segment: any, public parameters: {[key: string]: string}, public outlet: string) {}
|
||||
|
||||
toString(): string {
|
||||
let outletPrefix = isBlank(this.outlet) ? '' : `${this.outlet}:`;
|
||||
return `${outletPrefix}${this.segment}${_serializeParams(this.parameters)}`;
|
||||
}
|
||||
}
|
||||
|
||||
function _serializeParams(params: {[key: string]: string}): string {
|
||||
let res = '';
|
||||
StringMapWrapper.forEach(
|
||||
params, (v: any /** TODO #9100 */, k: any /** TODO #9100 */) => res += `;${k}=${v}`);
|
||||
return res;
|
||||
}
|
||||
|
||||
export class RouteSegment {
|
||||
/** @internal */
|
||||
_type: Type;
|
||||
|
||||
/** @internal */
|
||||
_componentFactory: ComponentFactory<any>;
|
||||
|
||||
constructor(
|
||||
public urlSegments: UrlSegment[], public parameters: {[key: string]: string},
|
||||
public outlet: string, type: Type, componentFactory: ComponentFactory<any>) {
|
||||
this._type = type;
|
||||
this._componentFactory = componentFactory;
|
||||
}
|
||||
|
||||
getParam(param: string): string {
|
||||
return isPresent(this.parameters) ? this.parameters[param] : null;
|
||||
}
|
||||
|
||||
getParamAsNumber(param: string): number {
|
||||
return isPresent(this.parameters) ? NumberWrapper.parseFloat(this.parameters[param]) : null;
|
||||
}
|
||||
|
||||
get type(): Type { return this._type; }
|
||||
|
||||
get stringifiedUrlSegments(): string { return this.urlSegments.map(s => s.toString()).join('/'); }
|
||||
}
|
||||
|
||||
export function createEmptyRouteTree(type: Type): RouteTree {
|
||||
let root = new RouteSegment([new UrlSegment('', {}, null)], {}, DEFAULT_OUTLET_NAME, type, null);
|
||||
return new RouteTree(new TreeNode<RouteSegment>(root, []));
|
||||
}
|
||||
|
||||
export function serializeRouteSegmentTree(tree: RouteTree): string {
|
||||
return _serializeRouteSegmentTree(tree._root);
|
||||
}
|
||||
|
||||
function _serializeRouteSegmentTree(node: TreeNode<RouteSegment>): string {
|
||||
let v = node.value;
|
||||
let children = node.children.map(c => _serializeRouteSegmentTree(c)).join(', ');
|
||||
return `${v.outlet}:${v.stringifiedUrlSegments}(${stringify(v.type)}) [${children}]`;
|
||||
}
|
||||
|
||||
export function equalUrlSegments(a: UrlSegment[], b: UrlSegment[]): boolean {
|
||||
if (a.length !== b.length) return false;
|
||||
|
||||
for (let i = 0; i < a.length; ++i) {
|
||||
if (a[i].segment != b[i].segment) return false;
|
||||
if (a[i].outlet != b[i].outlet) return false;
|
||||
if (!StringMapWrapper.equals(a[i].parameters, b[i].parameters)) return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
export function routeSegmentComponentFactory(a: RouteSegment): ComponentFactory<any> {
|
||||
return a._componentFactory;
|
||||
}
|
|
@ -1,381 +0,0 @@
|
|||
import {Location} from '@angular/common';
|
||||
import {SpyLocation} from '@angular/common/testing';
|
||||
import {ComponentFixture, TestComponentBuilder} from '@angular/compiler/testing';
|
||||
import {Component, ComponentResolver, provide} from '@angular/core';
|
||||
import {fakeAsync, tick} from '@angular/core/testing';
|
||||
import {AsyncTestCompleter, beforeEach, beforeEachProviders, ddescribe, describe, expect, iit, inject, it, xdescribe, xit} from '@angular/core/testing/testing_internal';
|
||||
import {CanDeactivate, DefaultRouterUrlSerializer, OnActivate, ROUTER_DIRECTIVES, Route, RouteSegment, Router, RouterOutletMap, RouterUrlSerializer, Routes} from '@angular/router';
|
||||
|
||||
import {getDOM} from '../platform_browser_private';
|
||||
import {PromiseWrapper} from '../src/facade/async';
|
||||
|
||||
export function main() {
|
||||
describe('navigation', () => {
|
||||
beforeEachProviders(
|
||||
() =>
|
||||
[{provide: RouterUrlSerializer, useClass: DefaultRouterUrlSerializer}, RouterOutletMap,
|
||||
{provide: Location, useClass: SpyLocation}, {
|
||||
provide: RouteSegment,
|
||||
useFactory: (r: any /** TODO #9100 */) => r.routeTree.root,
|
||||
deps: [Router]
|
||||
},
|
||||
{
|
||||
provide: Router,
|
||||
useFactory:
|
||||
(resolver: any /** TODO #9100 */, urlParser: any /** TODO #9100 */,
|
||||
outletMap: any /** TODO #9100 */, location: any /** TODO #9100 */) =>
|
||||
new Router(
|
||||
'RootComponent', RootCmp, resolver, urlParser, outletMap, location),
|
||||
deps: [ComponentResolver, RouterUrlSerializer, RouterOutletMap, Location]
|
||||
}]);
|
||||
|
||||
it('should update location when navigating',
|
||||
fakeAsync(inject(
|
||||
[Router, TestComponentBuilder, Location],
|
||||
(router: any /** TODO #9100 */, tcb: any /** TODO #9100 */,
|
||||
location: any /** TODO #9100 */) => {
|
||||
let fixture = tcb.createFakeAsync(RootCmp);
|
||||
|
||||
router.navigateByUrl('/team/22/user/victor');
|
||||
advance(fixture);
|
||||
expect(location.path()).toEqual('/team/22/user/victor');
|
||||
|
||||
router.navigateByUrl('/team/33/simple');
|
||||
advance(fixture);
|
||||
|
||||
expect(location.path()).toEqual('/team/33/simple');
|
||||
})));
|
||||
|
||||
it('should navigate back and forward',
|
||||
fakeAsync(inject(
|
||||
[Router, TestComponentBuilder, Location],
|
||||
(router: any /** TODO #9100 */, tcb: any /** TODO #9100 */,
|
||||
location: any /** TODO #9100 */) => {
|
||||
let fixture = tcb.createFakeAsync(RootCmp);
|
||||
|
||||
router.navigateByUrl('/team/33/simple');
|
||||
advance(fixture);
|
||||
|
||||
router.navigateByUrl('/team/22/user/victor');
|
||||
advance(fixture);
|
||||
|
||||
location.back();
|
||||
advance(fixture);
|
||||
expect(location.path()).toEqual('/team/33/simple');
|
||||
|
||||
location.forward();
|
||||
advance(fixture);
|
||||
expect(location.path()).toEqual('/team/22/user/victor');
|
||||
})));
|
||||
|
||||
it('should navigate when locations changes',
|
||||
fakeAsync(inject(
|
||||
[Router, TestComponentBuilder, Location],
|
||||
(router: any /** TODO #9100 */, tcb: any /** TODO #9100 */,
|
||||
location: any /** TODO #9100 */) => {
|
||||
let fixture = tcb.createFakeAsync(RootCmp);
|
||||
|
||||
router.navigateByUrl('/team/22/user/victor');
|
||||
advance(fixture);
|
||||
|
||||
location.simulateHashChange('/team/22/user/fedor');
|
||||
advance(fixture);
|
||||
|
||||
expect(fixture.debugElement.nativeElement)
|
||||
.toHaveText('team 22 { hello fedor, aux: }');
|
||||
})));
|
||||
|
||||
it('should support nested routes',
|
||||
fakeAsync(inject(
|
||||
[Router, TestComponentBuilder],
|
||||
(router: any /** TODO #9100 */, tcb: any /** TODO #9100 */) => {
|
||||
let fixture = tcb.createFakeAsync(RootCmp);
|
||||
|
||||
router.navigateByUrl('/team/22/user/victor');
|
||||
advance(fixture);
|
||||
|
||||
expect(fixture.debugElement.nativeElement)
|
||||
.toHaveText('team 22 { hello victor, aux: }');
|
||||
})));
|
||||
|
||||
it('should support aux routes',
|
||||
fakeAsync(inject(
|
||||
[Router, TestComponentBuilder],
|
||||
(router: any /** TODO #9100 */, tcb: any /** TODO #9100 */) => {
|
||||
let fixture = tcb.createFakeAsync(RootCmp);
|
||||
|
||||
router.navigateByUrl('/team/22/user/victor(/simple)');
|
||||
advance(fixture);
|
||||
|
||||
expect(fixture.debugElement.nativeElement)
|
||||
.toHaveText('team 22 { hello victor, aux: simple }');
|
||||
})));
|
||||
|
||||
it('should deactivate outlets',
|
||||
fakeAsync(inject(
|
||||
[Router, TestComponentBuilder],
|
||||
(router: any /** TODO #9100 */, tcb: any /** TODO #9100 */) => {
|
||||
let fixture = tcb.createFakeAsync(RootCmp);
|
||||
|
||||
router.navigateByUrl('/team/22/user/victor(/simple)');
|
||||
advance(fixture);
|
||||
|
||||
router.navigateByUrl('/team/22/user/victor');
|
||||
advance(fixture);
|
||||
|
||||
expect(fixture.debugElement.nativeElement)
|
||||
.toHaveText('team 22 { hello victor, aux: }');
|
||||
})));
|
||||
|
||||
it('should deactivate nested outlets',
|
||||
fakeAsync(inject(
|
||||
[Router, TestComponentBuilder],
|
||||
(router: any /** TODO #9100 */, tcb: any /** TODO #9100 */) => {
|
||||
let fixture = tcb.createFakeAsync(RootCmp);
|
||||
|
||||
router.navigateByUrl('/team/22/user/victor(/simple)');
|
||||
advance(fixture);
|
||||
|
||||
router.navigateByUrl('/');
|
||||
advance(fixture);
|
||||
|
||||
expect(fixture.debugElement.nativeElement).toHaveText('');
|
||||
})));
|
||||
|
||||
it('should update nested routes when url changes',
|
||||
fakeAsync(inject(
|
||||
[Router, TestComponentBuilder],
|
||||
(router: any /** TODO #9100 */, tcb: any /** TODO #9100 */) => {
|
||||
let fixture = tcb.createFakeAsync(RootCmp);
|
||||
|
||||
router.navigateByUrl('/team/22/user/victor');
|
||||
advance(fixture);
|
||||
let team1 = fixture.debugElement.children[1].componentInstance;
|
||||
|
||||
router.navigateByUrl('/team/22/user/fedor');
|
||||
advance(fixture);
|
||||
let team2 = fixture.debugElement.children[1].componentInstance;
|
||||
|
||||
expect(team1).toBe(team2);
|
||||
expect(fixture.debugElement.nativeElement)
|
||||
.toHaveText('team 22 { hello fedor, aux: }');
|
||||
})));
|
||||
|
||||
it('should not deactivate the route if can deactivate returns false',
|
||||
fakeAsync(inject(
|
||||
[Router, TestComponentBuilder, Location],
|
||||
(router: any /** TODO #9100 */, tcb: any /** TODO #9100 */,
|
||||
location: any /** TODO #9100 */) => {
|
||||
let fixture = tcb.createFakeAsync(RootCmp);
|
||||
|
||||
router.navigateByUrl('/team/22/cannotDeactivate');
|
||||
advance(fixture);
|
||||
|
||||
router.navigateByUrl('/team/22/user/fedor');
|
||||
advance(fixture);
|
||||
|
||||
expect(fixture.debugElement.nativeElement)
|
||||
.toHaveText('team 22 { cannotDeactivate, aux: }');
|
||||
|
||||
expect(location.path()).toEqual('/team/22/cannotDeactivate');
|
||||
})));
|
||||
|
||||
if (getDOM().supportsDOMEvents()) {
|
||||
it('should support absolute router links',
|
||||
fakeAsync(inject(
|
||||
[Router, TestComponentBuilder],
|
||||
(router: any /** TODO #9100 */, tcb: any /** TODO #9100 */) => {
|
||||
let fixture = tcb.createFakeAsync(RootCmp);
|
||||
advance(fixture);
|
||||
|
||||
router.navigateByUrl('/team/22/link');
|
||||
advance(fixture);
|
||||
expect(fixture.debugElement.nativeElement).toHaveText('team 22 { link, aux: }');
|
||||
|
||||
let native = getDOM().querySelector(fixture.debugElement.nativeElement, 'a');
|
||||
expect(getDOM().getAttribute(native, 'href')).toEqual('/team/33/simple');
|
||||
getDOM().dispatchEvent(native, getDOM().createMouseEvent('click'));
|
||||
advance(fixture);
|
||||
|
||||
expect(fixture.debugElement.nativeElement).toHaveText('team 33 { simple, aux: }');
|
||||
})));
|
||||
|
||||
it('should support relative router links',
|
||||
fakeAsync(inject(
|
||||
[Router, TestComponentBuilder],
|
||||
(router: any /** TODO #9100 */, tcb: any /** TODO #9100 */) => {
|
||||
let fixture = tcb.createFakeAsync(RootCmp);
|
||||
advance(fixture);
|
||||
|
||||
router.navigateByUrl('/team/22/relativelink');
|
||||
advance(fixture);
|
||||
expect(fixture.debugElement.nativeElement)
|
||||
.toHaveText('team 22 { relativelink { }, aux: }');
|
||||
|
||||
let native = getDOM().querySelector(fixture.debugElement.nativeElement, 'a');
|
||||
expect(getDOM().getAttribute(native, 'href'))
|
||||
.toEqual('/team/22/relativelink/simple');
|
||||
getDOM().dispatchEvent(native, getDOM().createMouseEvent('click'));
|
||||
advance(fixture);
|
||||
|
||||
expect(fixture.debugElement.nativeElement)
|
||||
.toHaveText('team 22 { relativelink { simple }, aux: }');
|
||||
})));
|
||||
|
||||
it('should set the router-link-active class',
|
||||
fakeAsync(inject(
|
||||
[Router, TestComponentBuilder],
|
||||
(router: any /** TODO #9100 */, tcb: any /** TODO #9100 */) => {
|
||||
let fixture = tcb.createFakeAsync(RootCmp);
|
||||
advance(fixture);
|
||||
|
||||
router.navigateByUrl('/team/22/relativelink');
|
||||
advance(fixture);
|
||||
expect(fixture.debugElement.nativeElement)
|
||||
.toHaveText('team 22 { relativelink { }, aux: }');
|
||||
let link = getDOM().querySelector(fixture.debugElement.nativeElement, 'a');
|
||||
expect(getDOM().hasClass(link, 'router-link-active')).toEqual(false);
|
||||
|
||||
getDOM().dispatchEvent(link, getDOM().createMouseEvent('click'));
|
||||
advance(fixture);
|
||||
|
||||
expect(getDOM().hasClass(link, 'router-link-active')).toEqual(true);
|
||||
})));
|
||||
|
||||
it('should update router links when router changes',
|
||||
fakeAsync(inject(
|
||||
[Router, TestComponentBuilder],
|
||||
(router: any /** TODO #9100 */, tcb: any /** TODO #9100 */) => {
|
||||
let fixture = tcb.createFakeAsync(RootCmp);
|
||||
advance(fixture);
|
||||
|
||||
router.navigateByUrl('/team/22/link(simple)');
|
||||
advance(fixture);
|
||||
expect(fixture.debugElement.nativeElement)
|
||||
.toHaveText('team 22 { link, aux: simple }');
|
||||
|
||||
let native = getDOM().querySelector(fixture.debugElement.nativeElement, 'a');
|
||||
expect(getDOM().getAttribute(native, 'href')).toEqual('/team/33/simple(aux:simple)');
|
||||
|
||||
router.navigateByUrl('/team/22/link(simple2)');
|
||||
advance(fixture);
|
||||
|
||||
expect(getDOM().getAttribute(native, 'href'))
|
||||
.toEqual('/team/33/simple(aux:simple2)');
|
||||
})));
|
||||
|
||||
it('should support top-level link',
|
||||
fakeAsync(inject(
|
||||
[Router, TestComponentBuilder],
|
||||
(router: any /** TODO #9100 */, tcb: any /** TODO #9100 */) => {
|
||||
let fixture = tcb.createFakeAsync(LinkCmp);
|
||||
advance(fixture);
|
||||
expect(fixture.debugElement.nativeElement).toHaveText('link');
|
||||
})));
|
||||
|
||||
it('should replace state when path is equal to current path',
|
||||
fakeAsync(inject(
|
||||
[Router, TestComponentBuilder, Location],
|
||||
(router: any /** TODO #9100 */, tcb: any /** TODO #9100 */,
|
||||
location: any /** TODO #9100 */) => {
|
||||
let fixture = tcb.createFakeAsync(RootCmp);
|
||||
|
||||
router.navigateByUrl('/team/33/simple');
|
||||
advance(fixture);
|
||||
|
||||
router.navigateByUrl('/team/22/user/victor');
|
||||
advance(fixture);
|
||||
|
||||
router.navigateByUrl('/team/22/user/victor');
|
||||
advance(fixture);
|
||||
|
||||
location.back();
|
||||
advance(fixture);
|
||||
expect(location.path()).toEqual('/team/33/simple');
|
||||
})));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function advance(fixture: ComponentFixture<any>): void {
|
||||
tick();
|
||||
fixture.detectChanges();
|
||||
}
|
||||
|
||||
function compileRoot(tcb: TestComponentBuilder): Promise<ComponentFixture<any>> {
|
||||
return tcb.createAsync(RootCmp);
|
||||
}
|
||||
|
||||
@Component({selector: 'user-cmp', template: `hello {{user}}`})
|
||||
class UserCmp implements OnActivate {
|
||||
user: string;
|
||||
routerOnActivate(
|
||||
s: RouteSegment, a?: any /** TODO #9100 */, b?: any /** TODO #9100 */,
|
||||
c?: any /** TODO #9100 */) {
|
||||
this.user = s.getParam('name');
|
||||
}
|
||||
}
|
||||
|
||||
@Component({selector: 'cannot-deactivate', template: `cannotDeactivate`})
|
||||
class CanDeactivateCmp implements CanDeactivate {
|
||||
routerCanDeactivate(a?: any /** TODO #9100 */, b?: any /** TODO #9100 */): Promise<boolean> {
|
||||
return PromiseWrapper.resolve(false);
|
||||
}
|
||||
}
|
||||
|
||||
@Component({selector: 'simple-cmp', template: `simple`})
|
||||
class SimpleCmp {
|
||||
}
|
||||
|
||||
@Component({selector: 'simple2-cmp', template: `simple2`})
|
||||
class Simple2Cmp {
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'link-cmp',
|
||||
template: `<a [routerLink]="['/team', '33', 'simple']">link</a>`,
|
||||
directives: ROUTER_DIRECTIVES
|
||||
})
|
||||
class LinkCmp {
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'link-cmp',
|
||||
template: `<a [routerLink]="['./simple']">relativelink</a> { <router-outlet></router-outlet> }`,
|
||||
directives: ROUTER_DIRECTIVES
|
||||
})
|
||||
@Routes([new Route({path: 'simple', component: SimpleCmp})])
|
||||
class RelativeLinkCmp {
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'team-cmp',
|
||||
template:
|
||||
`team {{id}} { <router-outlet></router-outlet>, aux: <router-outlet name="aux"></router-outlet> }`,
|
||||
directives: [ROUTER_DIRECTIVES]
|
||||
})
|
||||
@Routes([
|
||||
new Route({path: 'user/:name', component: UserCmp}),
|
||||
new Route({path: 'simple', component: SimpleCmp}),
|
||||
new Route({path: 'simple2', component: Simple2Cmp}),
|
||||
new Route({path: 'link', component: LinkCmp}),
|
||||
new Route({path: 'relativelink', component: RelativeLinkCmp}),
|
||||
new Route({path: 'cannotDeactivate', component: CanDeactivateCmp})
|
||||
])
|
||||
class TeamCmp implements OnActivate {
|
||||
id: string;
|
||||
routerOnActivate(
|
||||
s: RouteSegment, a?: any /** TODO #9100 */, b?: any /** TODO #9100 */,
|
||||
c?: any /** TODO #9100 */) {
|
||||
this.id = s.getParam('id');
|
||||
}
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'root-cmp',
|
||||
template: `<router-outlet></router-outlet>`,
|
||||
directives: [ROUTER_DIRECTIVES]
|
||||
})
|
||||
@Routes([new Route({path: 'team/:id', component: TeamCmp})])
|
||||
class RootCmp {
|
||||
}
|
|
@ -1,190 +0,0 @@
|
|||
import {AsyncTestCompleter, beforeEach, beforeEachProviders, ddescribe, describe, expect, iit, inject, it, xdescribe, xit} from '@angular/core/testing/testing_internal';
|
||||
|
||||
import {link} from '../src/link';
|
||||
import {DefaultRouterUrlSerializer} from '../src/router_url_serializer';
|
||||
import {RouteSegment, RouteTree, TreeNode, UrlSegment, UrlTree} from '../src/segments';
|
||||
|
||||
export function main() {
|
||||
describe('link', () => {
|
||||
let parser = new DefaultRouterUrlSerializer();
|
||||
|
||||
it('should return the original tree when given an empty array', () => {
|
||||
let p = parser.parse('/');
|
||||
let tree = s(p.root);
|
||||
let t = link(tree.root, tree, p, []);
|
||||
expect(t).toBe(p);
|
||||
});
|
||||
|
||||
it('should navigate to the root', () => {
|
||||
let p = parser.parse('/');
|
||||
let tree = s(p.root);
|
||||
let t = link(tree.root, tree, p, ['/']);
|
||||
expect(parser.serialize(t)).toEqual('');
|
||||
});
|
||||
|
||||
it('should support nested segments', () => {
|
||||
let p = parser.parse('/a/b');
|
||||
let tree = s(p.firstChild(p.root));
|
||||
let t = link(tree.root, tree, p, ['/one', 11, 'two', 22]);
|
||||
expect(parser.serialize(t)).toEqual('/one/11/two/22');
|
||||
});
|
||||
|
||||
it('should preserve siblings', () => {
|
||||
let p = parser.parse('/a/11/b(c)');
|
||||
let tree = s(p.root);
|
||||
let t = link(tree.root, tree, p, ['/a', 11, 'd']);
|
||||
expect(parser.serialize(t)).toEqual('/a/11/d(aux:c)');
|
||||
});
|
||||
|
||||
it('should update matrix parameters', () => {
|
||||
let p = parser.parse('/a;aa=11');
|
||||
let tree = s(p.root);
|
||||
let t = link(tree.root, tree, p, ['/a', {aa: 22, bb: 33}]);
|
||||
expect(parser.serialize(t)).toEqual('/a;aa=22;bb=33');
|
||||
});
|
||||
|
||||
it('should create matrix parameters', () => {
|
||||
let p = parser.parse('/a');
|
||||
let tree = s(p.root);
|
||||
let t = link(tree.root, tree, p, ['/a', {aa: 22, bb: 33}]);
|
||||
expect(parser.serialize(t)).toEqual('/a;aa=22;bb=33');
|
||||
});
|
||||
|
||||
it('should create matrix parameters together with other segments', () => {
|
||||
let p = parser.parse('/a');
|
||||
let tree = s(p.root);
|
||||
let t = link(tree.root, tree, p, ['/a', '/b', {aa: 22, bb: 33}]);
|
||||
expect(parser.serialize(t)).toEqual('/a/b;aa=22;bb=33');
|
||||
});
|
||||
|
||||
describe('node reuse', () => {
|
||||
it('should reuse nodes when path is the same', () => {
|
||||
let p = parser.parse('/a/b');
|
||||
let tree = s(p.root);
|
||||
let t = link(tree.root, tree, p, ['/a/c']);
|
||||
|
||||
expect(t.root).toBe(p.root);
|
||||
expect(t.firstChild(t.root)).toBe(p.firstChild(p.root));
|
||||
expect(t.firstChild(t.firstChild(t.root))).not.toBe(p.firstChild(p.firstChild(p.root)));
|
||||
});
|
||||
|
||||
it('should create new node when params are the same', () => {
|
||||
let p = parser.parse('/a;x=1');
|
||||
let tree = s(p.root);
|
||||
let t = link(tree.root, tree, p, ['/a', {'x': 1}]);
|
||||
|
||||
expect(t.firstChild(t.root)).toBe(p.firstChild(p.root));
|
||||
});
|
||||
|
||||
it('should create new node when params are different', () => {
|
||||
let p = parser.parse('/a;x=1');
|
||||
let tree = s(p.root);
|
||||
let t = link(tree.root, tree, p, ['/a', {'x': 2}]);
|
||||
|
||||
expect(t.firstChild(t.root)).not.toBe(p.firstChild(p.root));
|
||||
});
|
||||
});
|
||||
|
||||
describe('relative navigation', () => {
|
||||
it('should work', () => {
|
||||
let p = parser.parse('/a(ap)/c(cp)');
|
||||
let c = p.firstChild(p.root);
|
||||
let tree = s(c);
|
||||
let t = link(tree.root, tree, p, ['c2']);
|
||||
expect(parser.serialize(t)).toEqual('/a(aux:ap)/c2(aux:cp)');
|
||||
});
|
||||
|
||||
it('should work when the first command starts with a ./', () => {
|
||||
let p = parser.parse('/a(ap)/c(cp)');
|
||||
let c = p.firstChild(p.root);
|
||||
let tree = s(c);
|
||||
let t = link(tree.root, tree, p, ['./c2']);
|
||||
expect(parser.serialize(t)).toEqual('/a(aux:ap)/c2(aux:cp)');
|
||||
});
|
||||
|
||||
it('should work when the first command is ./)', () => {
|
||||
let p = parser.parse('/a(ap)/c(cp)');
|
||||
let c = p.firstChild(p.root);
|
||||
let tree = s(c);
|
||||
let t = link(tree.root, tree, p, ['./', 'c2']);
|
||||
expect(parser.serialize(t)).toEqual('/a(aux:ap)/c2(aux:cp)');
|
||||
});
|
||||
|
||||
it('should work when given params', () => {
|
||||
let p = parser.parse('/a(ap)/c(cp)');
|
||||
let c = p.firstChild(p.root);
|
||||
let tree = s(c);
|
||||
let t = link(tree.root, tree, p, [{'x': 99}]);
|
||||
|
||||
expect(parser.serialize(t)).toEqual('/a(aux:ap)/c;x=99(aux:cp)');
|
||||
});
|
||||
|
||||
it('should support going to a parent', () => {
|
||||
let p = parser.parse('/a(ap)/c(cp)');
|
||||
let a = p.firstChild(p.root);
|
||||
let tree = s(a);
|
||||
let t = link(tree.root, tree, p, ['../a2']);
|
||||
expect(parser.serialize(t)).toEqual('/a2(aux:ap)');
|
||||
});
|
||||
|
||||
it('should support going to a parent (nested case)', () => {
|
||||
let p = parser.parse('/a/c');
|
||||
let c = p.firstChild(p.firstChild(p.root));
|
||||
let tree = s(c);
|
||||
let t = link(tree.root, tree, p, ['../c2']);
|
||||
expect(parser.serialize(t)).toEqual('/a/c2');
|
||||
});
|
||||
|
||||
it('should work when given ../', () => {
|
||||
let p = parser.parse('/a/c');
|
||||
let c = p.firstChild(p.firstChild(p.root));
|
||||
let tree = s(c);
|
||||
let t = link(tree.root, tree, p, ['../']);
|
||||
expect(parser.serialize(t)).toEqual('/a');
|
||||
});
|
||||
|
||||
it('should navigate to the root', () => {
|
||||
let p = parser.parse('/a/c');
|
||||
let c = p.firstChild(p.root);
|
||||
let tree = s(c);
|
||||
let t = link(tree.root, tree, p, ['../']);
|
||||
expect(parser.serialize(t)).toEqual('');
|
||||
});
|
||||
|
||||
it('should support setting matrix params', () => {
|
||||
let p = parser.parse('/a(ap)/c(cp)');
|
||||
let c = p.firstChild(p.root);
|
||||
let tree = s(c);
|
||||
let t = link(tree.root, tree, p, ['../', {'x': 5}]);
|
||||
expect(parser.serialize(t)).toEqual('/a;x=5(aux:ap)');
|
||||
});
|
||||
|
||||
it('should throw when too many ..', () => {
|
||||
let p = parser.parse('/a(ap)/c(cp)');
|
||||
let c = p.firstChild(p.root);
|
||||
let tree = s(c);
|
||||
|
||||
expect(() => link(tree.root, tree, p, ['../../']))
|
||||
.toThrowError('Invalid number of \'../\'');
|
||||
});
|
||||
|
||||
it('should work when the provided segment doesn\'t have url segments', () => {
|
||||
let p = parser.parse('/a(ap)/c(cp)');
|
||||
let c = p.firstChild(p.root);
|
||||
|
||||
let child = new RouteSegment([], {'one': '1'}, null, null, null);
|
||||
let root = new TreeNode<RouteSegment>(
|
||||
new RouteSegment([c], {}, null, null, null), [new TreeNode<RouteSegment>(child, [])]);
|
||||
let tree = new RouteTree(root);
|
||||
|
||||
let t = link(child, tree, p, ['./c2']);
|
||||
expect(parser.serialize(t)).toEqual('/a(aux:ap)/c2(aux:cp)');
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function s(u: UrlSegment): RouteTree {
|
||||
let root = new TreeNode<RouteSegment>(new RouteSegment([u], {}, null, null, null), []);
|
||||
return new RouteTree(root);
|
||||
}
|
|
@ -1,261 +0,0 @@
|
|||
import {Component, ComponentResolver, provide} from '@angular/core';
|
||||
import {AsyncTestCompleter, beforeEach, beforeEachProviders, ddescribe, describe, expect, iit, inject, it, xdescribe, xit} from '@angular/core/testing/testing_internal';
|
||||
import {Route, Routes} from '@angular/router';
|
||||
|
||||
import {DEFAULT_OUTLET_NAME} from '../src/constants';
|
||||
import {recognize} from '../src/recognize';
|
||||
import {DefaultRouterUrlSerializer} from '../src/router_url_serializer';
|
||||
import {RouteTree, UrlSegment, UrlTree, createEmptyRouteTree} from '../src/segments';
|
||||
|
||||
export function main() {
|
||||
describe('recognize', () => {
|
||||
let emptyRouteTree = createEmptyRouteTree(ComponentA);
|
||||
|
||||
it('should handle position args',
|
||||
inject(
|
||||
[AsyncTestCompleter, ComponentResolver],
|
||||
(async: AsyncTestCompleter, resolver: any /** TODO #9100 */) => {
|
||||
recognize(resolver, ComponentA, tree('b/paramB/c/paramC/d'), emptyRouteTree)
|
||||
.then(r => {
|
||||
let a = r.root;
|
||||
expect(stringifyUrl(a.urlSegments)).toEqual(['']);
|
||||
expect(a.type).toBe(ComponentA);
|
||||
|
||||
let b = r.firstChild(r.root);
|
||||
expect(stringifyUrl(b.urlSegments)).toEqual(['b', 'paramB']);
|
||||
expect(b.type).toBe(ComponentB);
|
||||
|
||||
let c = r.firstChild(r.firstChild(r.root));
|
||||
expect(stringifyUrl(c.urlSegments)).toEqual(['c', 'paramC']);
|
||||
expect(c.type).toBe(ComponentC);
|
||||
|
||||
let d = r.firstChild(r.firstChild(r.firstChild(r.root)));
|
||||
expect(stringifyUrl(d.urlSegments)).toEqual(['d']);
|
||||
expect(d.type).toBe(ComponentD);
|
||||
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
|
||||
it('should support empty routes',
|
||||
inject(
|
||||
[AsyncTestCompleter, ComponentResolver],
|
||||
(async: AsyncTestCompleter, resolver: any /** TODO #9100 */) => {
|
||||
recognize(resolver, ComponentA, tree('f'), emptyRouteTree).then(r => {
|
||||
let a = r.root;
|
||||
expect(stringifyUrl(a.urlSegments)).toEqual(['']);
|
||||
expect(a.type).toBe(ComponentA);
|
||||
|
||||
let f = r.firstChild(r.root);
|
||||
expect(stringifyUrl(f.urlSegments)).toEqual(['f']);
|
||||
expect(f.type).toBe(ComponentF);
|
||||
|
||||
let d = r.firstChild(r.firstChild(r.root));
|
||||
expect(stringifyUrl(d.urlSegments)).toEqual([]);
|
||||
expect(d.type).toBe(ComponentD);
|
||||
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
|
||||
it('should handle aux routes',
|
||||
inject(
|
||||
[AsyncTestCompleter, ComponentResolver],
|
||||
(async: AsyncTestCompleter, resolver: any /** TODO #9100 */) => {
|
||||
recognize(resolver, ComponentA, tree('b/paramB(/d//right:d)'), emptyRouteTree)
|
||||
.then(r => {
|
||||
let c = r.children(r.root);
|
||||
expect(stringifyUrl(c[0].urlSegments)).toEqual(['b', 'paramB']);
|
||||
expect(c[0].outlet).toEqual(DEFAULT_OUTLET_NAME);
|
||||
expect(c[0].type).toBe(ComponentB);
|
||||
|
||||
expect(stringifyUrl(c[1].urlSegments)).toEqual(['d']);
|
||||
expect(c[1].outlet).toEqual('aux');
|
||||
expect(c[1].type).toBe(ComponentD);
|
||||
|
||||
expect(stringifyUrl(c[2].urlSegments)).toEqual(['d']);
|
||||
expect(c[2].outlet).toEqual('right');
|
||||
expect(c[2].type).toBe(ComponentD);
|
||||
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
|
||||
it('should error when two segments with the same outlet name',
|
||||
inject(
|
||||
[AsyncTestCompleter, ComponentResolver],
|
||||
(async: AsyncTestCompleter, resolver: any /** TODO #9100 */) => {
|
||||
recognize(resolver, ComponentA, tree('b/paramB(right:d//right:e)'), emptyRouteTree)
|
||||
.catch(e => {
|
||||
expect(e.message).toEqual(
|
||||
'Two segments cannot have the same outlet name: \'right:d\' and \'right:e\'.');
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
|
||||
it('should handle nested aux routes',
|
||||
inject(
|
||||
[AsyncTestCompleter, ComponentResolver],
|
||||
(async: AsyncTestCompleter, resolver: any /** TODO #9100 */) => {
|
||||
recognize(resolver, ComponentA, tree('b/paramB(/d(right:e))'), emptyRouteTree)
|
||||
.then(r => {
|
||||
let c = r.children(r.root);
|
||||
expect(stringifyUrl(c[0].urlSegments)).toEqual(['b', 'paramB']);
|
||||
expect(c[0].outlet).toEqual(DEFAULT_OUTLET_NAME);
|
||||
expect(c[0].type).toBe(ComponentB);
|
||||
|
||||
expect(stringifyUrl(c[1].urlSegments)).toEqual(['d']);
|
||||
expect(c[1].outlet).toEqual('aux');
|
||||
expect(c[1].type).toBe(ComponentD);
|
||||
|
||||
expect(stringifyUrl(c[2].urlSegments)).toEqual(['e']);
|
||||
expect(c[2].outlet).toEqual('right');
|
||||
expect(c[2].type).toBe(ComponentE);
|
||||
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
|
||||
it('should handle non top-level aux routes',
|
||||
inject(
|
||||
[AsyncTestCompleter, ComponentResolver],
|
||||
(async: AsyncTestCompleter, resolver: any /** TODO #9100 */) => {
|
||||
recognize(resolver, ComponentA, tree('b/paramB/d(e)'), emptyRouteTree).then(r => {
|
||||
let c = r.children(r.firstChild(r.root));
|
||||
expect(stringifyUrl(c[0].urlSegments)).toEqual(['d']);
|
||||
expect(c[0].outlet).toEqual(DEFAULT_OUTLET_NAME);
|
||||
expect(c[0].type).toBe(ComponentD);
|
||||
|
||||
expect(stringifyUrl(c[1].urlSegments)).toEqual(['e']);
|
||||
expect(c[1].outlet).toEqual('aux');
|
||||
expect(c[1].type).toBe(ComponentE);
|
||||
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
|
||||
it('should handle matrix parameters',
|
||||
inject(
|
||||
[AsyncTestCompleter, ComponentResolver],
|
||||
(async: AsyncTestCompleter, resolver: any /** TODO #9100 */) => {
|
||||
recognize(
|
||||
resolver, ComponentA, tree('b/paramB;b1=1;b2=2(/d;d1=1;d2=2)'), emptyRouteTree)
|
||||
.then(r => {
|
||||
let c = r.children(r.root);
|
||||
expect(c[0].parameters).toEqual({'b': 'paramB', 'b1': '1', 'b2': '2'});
|
||||
expect(c[1].parameters).toEqual({'d1': '1', 'd2': '2'});
|
||||
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
|
||||
it('should match a wildcard',
|
||||
inject(
|
||||
[AsyncTestCompleter, ComponentResolver],
|
||||
(async: AsyncTestCompleter, resolver: any /** TODO #9100 */) => {
|
||||
recognize(resolver, ComponentG, tree('a;aa=1/b;bb=2'), emptyRouteTree).then(r => {
|
||||
let c = r.children(r.root);
|
||||
expect(c.length).toEqual(1);
|
||||
expect(stringifyUrl(c[0].urlSegments)).toEqual([]);
|
||||
expect(c[0].parameters).toEqual(null);
|
||||
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
|
||||
it('should error when no matching routes',
|
||||
inject(
|
||||
[AsyncTestCompleter, ComponentResolver],
|
||||
(async: AsyncTestCompleter, resolver: any /** TODO #9100 */) => {
|
||||
recognize(resolver, ComponentA, tree('invalid'), emptyRouteTree).catch(e => {
|
||||
expect(e.message).toContain('Cannot match any routes');
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
|
||||
it('should handle no matching routes (too short)',
|
||||
inject(
|
||||
[AsyncTestCompleter, ComponentResolver],
|
||||
(async: AsyncTestCompleter, resolver: any /** TODO #9100 */) => {
|
||||
recognize(resolver, ComponentA, tree('b'), emptyRouteTree).catch(e => {
|
||||
expect(e.message).toContain('Cannot match any routes');
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
|
||||
it('should error when a component doesn\'t have @Routes',
|
||||
inject(
|
||||
[AsyncTestCompleter, ComponentResolver],
|
||||
(async: AsyncTestCompleter, resolver: any /** TODO #9100 */) => {
|
||||
recognize(resolver, ComponentA, tree('d/invalid'), emptyRouteTree).catch(e => {
|
||||
expect(e.message).toEqual(
|
||||
'Component \'ComponentD\' does not have route configuration');
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
|
||||
it('should reuse existing segments',
|
||||
inject(
|
||||
[AsyncTestCompleter, ComponentResolver],
|
||||
(async: AsyncTestCompleter, resolver: any /** TODO #9100 */) => {
|
||||
recognize(resolver, ComponentA, tree('/b/1/d'), emptyRouteTree).then(t1 => {
|
||||
recognize(resolver, ComponentA, tree('/b/1/e'), t1).then(t2 => {
|
||||
expect(t1.root).toBe(t2.root);
|
||||
expect(t1.firstChild(t1.root)).toBe(t2.firstChild(t2.root));
|
||||
expect(t1.firstChild(t1.firstChild(t1.root)))
|
||||
.not.toBe(t2.firstChild(t2.firstChild(t2.root)));
|
||||
|
||||
async.done();
|
||||
});
|
||||
});
|
||||
}));
|
||||
});
|
||||
}
|
||||
|
||||
function tree(url: string): UrlTree {
|
||||
return new DefaultRouterUrlSerializer().parse(url);
|
||||
}
|
||||
|
||||
function stringifyUrl(segments: UrlSegment[]): string[] {
|
||||
return segments.map(s => s.segment);
|
||||
}
|
||||
|
||||
@Component({selector: 'd', template: 't'})
|
||||
class ComponentD {
|
||||
}
|
||||
|
||||
@Component({selector: 'e', template: 't'})
|
||||
class ComponentE {
|
||||
}
|
||||
|
||||
@Component({selector: 'f', template: 't'})
|
||||
@Routes([new Route({path: '/', component: ComponentD})])
|
||||
class ComponentF {
|
||||
}
|
||||
|
||||
@Component({selector: 'c', template: 't'})
|
||||
@Routes([new Route({path: 'd', component: ComponentD})])
|
||||
class ComponentC {
|
||||
}
|
||||
|
||||
@Component({selector: 'b', template: 't'})
|
||||
@Routes([
|
||||
new Route({path: 'd', component: ComponentD}), new Route({path: 'e', component: ComponentE}),
|
||||
new Route({path: 'c/:c', component: ComponentC})
|
||||
])
|
||||
class ComponentB {
|
||||
}
|
||||
|
||||
@Component({selector: 'g', template: 't'})
|
||||
@Routes(
|
||||
[new Route({path: 'd', component: ComponentD}), new Route({path: '*', component: ComponentE})])
|
||||
class ComponentG {
|
||||
}
|
||||
|
||||
@Component({selector: 'a', template: 't'})
|
||||
@Routes([
|
||||
new Route({path: 'b/:b', component: ComponentB}), new Route({path: 'd', component: ComponentD}),
|
||||
new Route({path: 'e', component: ComponentE}), new Route({path: 'f', component: ComponentF})
|
||||
])
|
||||
class ComponentA {
|
||||
}
|
|
@ -1,49 +0,0 @@
|
|||
import {Location, LocationStrategy} from '@angular/common';
|
||||
import {MockLocationStrategy, SpyLocation} from '@angular/common/testing';
|
||||
import {Component, ComponentResolver, provide} from '@angular/core';
|
||||
import {AsyncTestCompleter, beforeEach, beforeEachProviders, ddescribe, describe, expect, iit, inject, it, xdescribe, xit} from '@angular/core/testing/testing_internal';
|
||||
import {CanDeactivate, DefaultRouterUrlSerializer, OnActivate, ROUTER_DIRECTIVES, Route, RouteSegment, Router, RouterOutletMap, RouterUrlSerializer, Routes} from '@angular/router';
|
||||
|
||||
import {RouterLink} from '../src/directives/router_link';
|
||||
|
||||
export function main() {
|
||||
describe('RouterLink', () => {
|
||||
beforeEachProviders(
|
||||
() =>
|
||||
[{provide: RouterUrlSerializer, useClass: DefaultRouterUrlSerializer}, RouterOutletMap,
|
||||
{provide: Location, useClass: SpyLocation},
|
||||
{provide: LocationStrategy, useClass: MockLocationStrategy}, {
|
||||
provide: Router,
|
||||
useFactory:
|
||||
(resolver: any /** TODO #9100 */, urlParser: any /** TODO #9100 */,
|
||||
outletMap: any /** TODO #9100 */, location: any /** TODO #9100 */) =>
|
||||
new Router(
|
||||
'RootComponent', RootCmp, resolver, urlParser, outletMap, location),
|
||||
deps: [ComponentResolver, RouterUrlSerializer, RouterOutletMap, Location]
|
||||
}]);
|
||||
|
||||
describe('routerLink=', () => {
|
||||
it('should accept an array of commands',
|
||||
inject(
|
||||
[Router, LocationStrategy],
|
||||
(router: any /** TODO #9100 */, locationStrategy: any /** TODO #9100 */) => {
|
||||
let link = new RouterLink(null, router, locationStrategy);
|
||||
link.routerLink = ['/one', 11];
|
||||
expect(link.href).toEqual('/one/11');
|
||||
}));
|
||||
|
||||
it('should accept a single command',
|
||||
inject(
|
||||
[Router, LocationStrategy],
|
||||
(router: any /** TODO #9100 */, locationStrategy: any /** TODO #9100 */) => {
|
||||
let link = new RouterLink(null, router, locationStrategy);
|
||||
link.routerLink = '/one/11';
|
||||
expect(link.href).toEqual('/one/11');
|
||||
}));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@Component({template: ''})
|
||||
class RootCmp {
|
||||
}
|
|
@ -1,92 +0,0 @@
|
|||
import {AsyncTestCompleter, beforeEach, beforeEachProviders, ddescribe, describe, expect, iit, inject, it, xdescribe, xit} from '@angular/core/testing/testing_internal';
|
||||
|
||||
import {DefaultRouterUrlSerializer} from '../src/router_url_serializer';
|
||||
import {UrlSegment} from '../src/segments';
|
||||
|
||||
export function main() {
|
||||
describe('url serializer', () => {
|
||||
let url = new DefaultRouterUrlSerializer();
|
||||
|
||||
it('should parse the root url', () => {
|
||||
let tree = url.parse('/');
|
||||
expectSegment(tree.root, '');
|
||||
expect(url.serialize(tree)).toEqual('');
|
||||
});
|
||||
|
||||
it('should parse non-empty urls', () => {
|
||||
let tree = url.parse('one/two');
|
||||
expectSegment(tree.firstChild(tree.root), 'one');
|
||||
expectSegment(tree.firstChild(tree.firstChild(tree.root)), 'two');
|
||||
expect(url.serialize(tree)).toEqual('/one/two');
|
||||
});
|
||||
|
||||
it('should parse multiple aux routes', () => {
|
||||
let tree = url.parse('/one/two(/three//right:four)/five');
|
||||
let c = tree.children(tree.firstChild(tree.root));
|
||||
|
||||
expectSegment(c[0], 'two');
|
||||
expectSegment(c[1], 'aux:three');
|
||||
expectSegment(c[2], 'right:four');
|
||||
|
||||
expectSegment(tree.firstChild(c[0]), 'five');
|
||||
|
||||
expect(url.serialize(tree)).toEqual('/one/two(aux:three//right:four)/five');
|
||||
});
|
||||
|
||||
it('should parse aux routes that have aux routes', () => {
|
||||
let tree = url.parse('/one(/two(/three))');
|
||||
let c = tree.children(tree.root);
|
||||
|
||||
expectSegment(c[0], 'one');
|
||||
expectSegment(c[1], 'aux:two');
|
||||
expectSegment(c[2], 'aux:three');
|
||||
|
||||
expect(url.serialize(tree)).toEqual('/one(aux:two//aux:three)');
|
||||
});
|
||||
|
||||
it('should parse aux routes that have children', () => {
|
||||
let tree = url.parse('/one(/two/three)');
|
||||
let c = tree.children(tree.root);
|
||||
|
||||
expectSegment(c[0], 'one');
|
||||
expectSegment(c[1], 'aux:two');
|
||||
expectSegment(tree.firstChild(c[1]), 'three');
|
||||
|
||||
expect(url.serialize(tree)).toEqual('/one(aux:two/three)');
|
||||
});
|
||||
|
||||
it('should parse an empty aux route definition', () => {
|
||||
let tree = url.parse('/one()');
|
||||
let c = tree.children(tree.root);
|
||||
|
||||
expectSegment(c[0], 'one');
|
||||
expect(tree.children(c[0]).length).toEqual(0);
|
||||
|
||||
expect(url.serialize(tree)).toEqual('/one');
|
||||
});
|
||||
|
||||
it('should parse key-value matrix params', () => {
|
||||
let tree = url.parse('/one;a=11a;b=11b(/two;c=22//right:three;d=33)');
|
||||
let c = tree.children(tree.root);
|
||||
|
||||
expectSegment(c[0], 'one;a=11a;b=11b');
|
||||
expectSegment(c[1], 'aux:two;c=22');
|
||||
expectSegment(c[2], 'right:three;d=33');
|
||||
|
||||
expect(url.serialize(tree)).toEqual('/one;a=11a;b=11b(aux:two;c=22//right:three;d=33)');
|
||||
});
|
||||
|
||||
it('should parse key only matrix params', () => {
|
||||
let tree = url.parse('/one;a');
|
||||
|
||||
let c = tree.firstChild(tree.root);
|
||||
expectSegment(c, 'one;a=true');
|
||||
|
||||
expect(url.serialize(tree)).toEqual('/one;a=true');
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function expectSegment(segment: UrlSegment, expected: string): void {
|
||||
expect(segment.toString()).toEqual(expected);
|
||||
}
|
|
@ -1,54 +0,0 @@
|
|||
import {AsyncTestCompleter, beforeEach, beforeEachProviders, ddescribe, describe, expect, iit, inject, it, xdescribe, xit} from '@angular/core/testing/testing_internal';
|
||||
|
||||
import {Tree, TreeNode} from '../src/segments';
|
||||
|
||||
export function main() {
|
||||
describe('tree', () => {
|
||||
it('should return the root of the tree', () => {
|
||||
let t = new Tree<any>(new TreeNode<number>(1, []));
|
||||
expect(t.root).toEqual(1);
|
||||
});
|
||||
|
||||
it('should return the parent of a node', () => {
|
||||
let t = new Tree<any>(new TreeNode<number>(1, [new TreeNode<number>(2, [])]));
|
||||
expect(t.parent(1)).toEqual(null);
|
||||
expect(t.parent(2)).toEqual(1);
|
||||
});
|
||||
|
||||
it('should return the children of a node', () => {
|
||||
let t = new Tree<any>(new TreeNode<number>(1, [new TreeNode<number>(2, [])]));
|
||||
expect(t.children(1)).toEqual([2]);
|
||||
expect(t.children(2)).toEqual([]);
|
||||
});
|
||||
|
||||
it('should return the first child of a node', () => {
|
||||
let t = new Tree<any>(new TreeNode<number>(1, [new TreeNode<number>(2, [])]));
|
||||
expect(t.firstChild(1)).toEqual(2);
|
||||
expect(t.firstChild(2)).toEqual(null);
|
||||
});
|
||||
|
||||
it('should return the path to the root', () => {
|
||||
let t = new Tree<any>(new TreeNode<number>(1, [new TreeNode<number>(2, [])]));
|
||||
expect(t.pathFromRoot(2)).toEqual([1, 2]);
|
||||
});
|
||||
|
||||
describe('contains', () => {
|
||||
it('should work', () => {
|
||||
let tree = new Tree<any>(
|
||||
new TreeNode<number>(1, [new TreeNode<number>(2, []), new TreeNode<number>(3, [])]));
|
||||
let subtree1 = new Tree<any>(new TreeNode<number>(1, []));
|
||||
let subtree2 = new Tree<any>(new TreeNode<number>(1, [new TreeNode<number>(2, [])]));
|
||||
let subtree3 = new Tree<any>(new TreeNode<number>(1, [new TreeNode<number>(3, [])]));
|
||||
let notSubtree1 = new Tree<any>(new TreeNode<number>(1, [new TreeNode<number>(4, [])]));
|
||||
let notSubtree2 = new Tree<any>(
|
||||
new TreeNode<number>(1, [new TreeNode<number>(2, [new TreeNode<number>(4, [])])]));
|
||||
|
||||
expect(tree.contains(subtree1)).toEqual(true);
|
||||
expect(tree.contains(subtree2)).toEqual(true);
|
||||
expect(tree.contains(subtree3)).toEqual(true);
|
||||
expect(tree.contains(notSubtree1)).toEqual(false);
|
||||
expect(tree.contains(notSubtree2)).toEqual(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
|
@ -1 +0,0 @@
|
|||
export * from './testing/router_testing_providers';
|
|
@ -1,35 +0,0 @@
|
|||
import {Location} from '@angular/common';
|
||||
import {SpyLocation} from '@angular/common/testing';
|
||||
import {Component, ComponentResolver} from '@angular/core';
|
||||
|
||||
import {Router, RouterOutletMap} from '../src/router';
|
||||
import {DefaultRouterUrlSerializer, RouterUrlSerializer} from '../src/router_url_serializer';
|
||||
import {RouteSegment} from '../src/segments';
|
||||
|
||||
@Component({selector: 'fake-app-root-comp', template: `<span></span>`})
|
||||
class FakeAppRootCmp {
|
||||
}
|
||||
|
||||
function routerFactory(
|
||||
componentResolver: ComponentResolver, urlSerializer: RouterUrlSerializer,
|
||||
routerOutletMap: RouterOutletMap, location: Location): Router {
|
||||
return new Router(
|
||||
null, FakeAppRootCmp, componentResolver, urlSerializer, routerOutletMap, location);
|
||||
}
|
||||
|
||||
export const ROUTER_FAKE_PROVIDERS: any[] = /*@ts2dart_const*/[
|
||||
RouterOutletMap,
|
||||
/* @ts2dart_Provider */ {provide: Location, useClass: SpyLocation},
|
||||
/* @ts2dart_Provider */ {provide: RouterUrlSerializer, useClass: DefaultRouterUrlSerializer},
|
||||
/* @ts2dart_Provider */ {
|
||||
provide: Router,
|
||||
useFactory: routerFactory,
|
||||
deps: /*@ts2dart_const*/
|
||||
[ComponentResolver, RouterUrlSerializer, RouterOutletMap, Location]
|
||||
},
|
||||
/*@ts2dart_Provider*/ {
|
||||
provide: RouteSegment,
|
||||
useFactory: (r: any /** TODO #9100 */) => r.routeTree.root,
|
||||
deps: [Router]
|
||||
}
|
||||
];
|
|
@ -1,26 +0,0 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"baseUrl": ".",
|
||||
"declaration": true,
|
||||
"stripInternal": true,
|
||||
"experimentalDecorators": true,
|
||||
"module": "es2015",
|
||||
"moduleResolution": "node",
|
||||
"outDir": "../../../dist/packages-dist/router/esm",
|
||||
"paths": {
|
||||
"@angular/core": ["../../../dist/packages-dist/core/"],
|
||||
"@angular/common": ["../../../dist/packages-dist/common/"],
|
||||
"@angular/common/testing": ["../../../dist/packages-dist/common/testing/"],
|
||||
"@angular/platform-browser": ["../../../dist/packages-dist/platform-browser/"]
|
||||
},
|
||||
"rootDir": ".",
|
||||
"sourceMap": true,
|
||||
"inlineSources": true,
|
||||
"target": "es2015"
|
||||
},
|
||||
"files": [
|
||||
"index.ts",
|
||||
"testing.ts",
|
||||
"../../../node_modules/zone.js/dist/zone.js.d.ts"
|
||||
]
|
||||
}
|
|
@ -1,27 +0,0 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"baseUrl": ".",
|
||||
"declaration": true,
|
||||
"stripInternal": true,
|
||||
"experimentalDecorators": true,
|
||||
"module": "commonjs",
|
||||
"moduleResolution": "node",
|
||||
"outDir": "../../../dist/packages-dist/router/",
|
||||
"paths": {
|
||||
"@angular/core": ["../../../dist/packages-dist/core/"],
|
||||
"@angular/common": ["../../../dist/packages-dist/common/"],
|
||||
"@angular/common/testing": ["../../../dist/packages-dist/common/testing/"],
|
||||
"@angular/platform-browser": ["../../../dist/packages-dist/platform-browser/"]
|
||||
},
|
||||
"rootDir": ".",
|
||||
"sourceMap": true,
|
||||
"inlineSources": true,
|
||||
"lib": ["es6", "dom"],
|
||||
"target": "es5"
|
||||
},
|
||||
"files": [
|
||||
"index.ts",
|
||||
"testing.ts",
|
||||
"../../../node_modules/zone.js/dist/zone.js.d.ts"
|
||||
]
|
||||
}
|
|
@ -1,3 +0,0 @@
|
|||
library playground.e2e_test.routing.routing_spec;
|
||||
|
||||
main() {}
|
|
@ -1,86 +0,0 @@
|
|||
import {verifyNoBrowserErrors} from '@angular/platform-browser/testing_e2e';
|
||||
|
||||
function waitForElement(selector: any /** TODO #9100 */) {
|
||||
var EC = (<any>protractor).ExpectedConditions;
|
||||
// Waits for the element with id 'abc' to be present on the dom.
|
||||
browser.wait(EC.presenceOf($(selector)), 20000);
|
||||
}
|
||||
|
||||
describe('alt-routing inbox-app', () => {
|
||||
var URL = 'all/playground/src/alt_routing/';
|
||||
|
||||
afterEach(verifyNoBrowserErrors);
|
||||
|
||||
describe('index view', () => {
|
||||
it('should list out the current collection of items', () => {
|
||||
browser.get(URL);
|
||||
waitForElement('.inbox-item-record');
|
||||
expect(element.all(by.css('.inbox-item-record')).count()).toEqual(200);
|
||||
});
|
||||
|
||||
it('should build a link which points to the detail page', () => {
|
||||
browser.get(URL);
|
||||
waitForElement('#item-15');
|
||||
expect(element(by.css('#item-15')).getAttribute('href')).toMatch(/\/detail\/15$/);
|
||||
element(by.css('#item-15')).click();
|
||||
waitForElement('#record-id');
|
||||
expect(browser.getCurrentUrl()).toMatch(/\/detail\/15$/);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
describe('drafts view', () => {
|
||||
it('should navigate to the drafts view when the drafts link is clicked', () => {
|
||||
browser.get(URL);
|
||||
waitForElement('.inbox-item-record');
|
||||
element(by.linkText('Drafts')).click();
|
||||
waitForElement('.page-title');
|
||||
expect(element(by.css('.page-title')).getText()).toEqual('Drafts');
|
||||
});
|
||||
|
||||
it('should navigate to email details', () => {
|
||||
browser.get(URL);
|
||||
element(by.linkText('Drafts')).click();
|
||||
waitForElement('.inbox-item-record');
|
||||
expect(element.all(by.css('.inbox-item-record')).count()).toEqual(2);
|
||||
expect(element(by.css('#item-201')).getAttribute('href')).toMatch(/\/detail\/201$/);
|
||||
element(by.css('#item-201')).click();
|
||||
waitForElement('#record-id');
|
||||
expect(browser.getCurrentUrl()).toMatch(/\/detail\/201$/);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
describe('detail view', () => {
|
||||
it('should navigate to the detail view when an email is clicked', () => {
|
||||
browser.get(URL);
|
||||
waitForElement('#item-10');
|
||||
element(by.css('#item-10')).click();
|
||||
waitForElement('#record-id');
|
||||
var recordId = element(by.css("#record-id"));
|
||||
browser.wait(protractor.until.elementTextIs(recordId, "ID: 10"), 5000);
|
||||
expect(recordId.getText()).toEqual('ID: 10');
|
||||
});
|
||||
|
||||
it('should navigate back to the email inbox page when the back button is clicked', () => {
|
||||
browser.get(URL);
|
||||
waitForElement('#item-10');
|
||||
element(by.css('#item-10')).click();
|
||||
waitForElement('.back-button');
|
||||
element(by.css('.back-button')).click();
|
||||
expect(browser.getCurrentUrl()).toMatch(/\/$/);
|
||||
});
|
||||
|
||||
it('should navigate back to index and sort the page items based on the provided querystring param',
|
||||
() => {
|
||||
browser.get(URL);
|
||||
waitForElement('#item-10');
|
||||
element(by.css('#item-10')).click();
|
||||
waitForElement('.sort-button');
|
||||
element(by.css('.sort-button')).click();
|
||||
expect(browser.getCurrentUrl()).toContain(';sort=date');
|
||||
waitForElement('.inbox-item-record');
|
||||
expect(element(by.css(".inbox-item-record > a")).getAttribute("id")).toEqual("item-137");
|
||||
});
|
||||
})
|
||||
});
|
|
@ -30,7 +30,6 @@ transformers:
|
|||
- web/src/person_management/index.dart
|
||||
- web/src/relative_assets/index.dart
|
||||
- web/src/routing/index.dart
|
||||
- web/src/alt_routing/index.dart
|
||||
- web/src/sourcemap/index.dart
|
||||
- web/src/svg/index.dart
|
||||
- web/src/template_driven_forms/index.dart
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,11 +0,0 @@
|
|||
<div>
|
||||
<h2 class="page-title">Drafts</h2>
|
||||
|
||||
<ol class="inbox-list">
|
||||
<li *ngFor="let item of items" class="inbox-item-record">
|
||||
<a id="item-{{ item.id }}"
|
||||
[routerLink]="['/detail', item.id]">
|
||||
{{ item.subject }}</a>
|
||||
</li>
|
||||
</ol>
|
||||
</div>
|
|
@ -1,5 +0,0 @@
|
|||
<inbox-side-menu class="inbox-aside">
|
||||
<a [routerLink]="['/inbox']" class="link" [class.active]="inboxPageActive()">Inbox</a>
|
||||
<a [routerLink]="['/drafts']" class="link" [class.active]="draftsPageActive()">Drafts</a>
|
||||
</inbox-side-menu>
|
||||
<router-outlet></router-outlet>
|
|
@ -1,167 +0,0 @@
|
|||
import {Component, Injectable} from '@angular/core';
|
||||
import {
|
||||
Routes,
|
||||
Route,
|
||||
Router,
|
||||
ROUTER_DIRECTIVES,
|
||||
ROUTER_PROVIDERS,
|
||||
OnActivate,
|
||||
RouteSegment,
|
||||
RouteTree,
|
||||
UrlTree
|
||||
} from '@angular/router';
|
||||
import * as db from './data';
|
||||
import {Location} from '@angular/common';
|
||||
import {PromiseWrapper} from '@angular/core/src/facade/async';
|
||||
import {isPresent, DateWrapper} from '@angular/core/src/facade/lang';
|
||||
import {PromiseCompleter} from '@angular/core/src/facade/promise';
|
||||
|
||||
class InboxRecord {
|
||||
id: string = '';
|
||||
subject: string = '';
|
||||
content: string = '';
|
||||
email: string = '';
|
||||
firstName: string = '';
|
||||
lastName: string = '';
|
||||
date: string;
|
||||
draft: boolean = false;
|
||||
|
||||
constructor(data: {
|
||||
id: string,
|
||||
subject: string,
|
||||
content: string,
|
||||
email: string,
|
||||
firstName: string,
|
||||
lastName: string,
|
||||
date: string, draft?: boolean
|
||||
} = null) {
|
||||
if (isPresent(data)) {
|
||||
this.setData(data);
|
||||
}
|
||||
}
|
||||
|
||||
setData(record: {
|
||||
id: string,
|
||||
subject: string,
|
||||
content: string,
|
||||
email: string,
|
||||
firstName: string,
|
||||
lastName: string,
|
||||
date: string, draft?: boolean
|
||||
}) {
|
||||
this.id = record['id'];
|
||||
this.subject = record['subject'];
|
||||
this.content = record['content'];
|
||||
this.email = record['email'];
|
||||
this.firstName = (record as any /** TODO #9100 */)['first-name'];
|
||||
this.lastName = (record as any /** TODO #9100 */)['last-name'];
|
||||
this.date = record['date'];
|
||||
this.draft = record['draft'] == true;
|
||||
}
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
class DbService {
|
||||
getData(): Promise<any[]> {
|
||||
var p = new PromiseCompleter<any[]>();
|
||||
p.resolve(db.data);
|
||||
return p.promise;
|
||||
}
|
||||
|
||||
drafts(): Promise<any[]> {
|
||||
return this.getData().then(
|
||||
(data: any[]): any[] =>
|
||||
data.filter(record => isPresent(record['draft']) && record['draft'] == true));
|
||||
}
|
||||
|
||||
emails(): Promise<any[]> {
|
||||
return this.getData().then((data: any[]): any[] =>
|
||||
data.filter(record => !isPresent(record['draft'])));
|
||||
}
|
||||
|
||||
email(id: any /** TODO #9100 */): Promise<any> {
|
||||
return PromiseWrapper.then(this.getData(), (data: any[]) => {
|
||||
for (var i = 0; i < data.length; i++) {
|
||||
var entry = data[i];
|
||||
if (entry['id'] == id) {
|
||||
return entry;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Component(
|
||||
{selector: 'inbox-detail', directives: ROUTER_DIRECTIVES, templateUrl: 'app/inbox-detail.html'})
|
||||
class InboxDetailCmp implements OnActivate {
|
||||
record: InboxRecord = new InboxRecord();
|
||||
ready: boolean = false;
|
||||
|
||||
constructor(private _db: DbService) {}
|
||||
|
||||
routerOnActivate(curr: RouteSegment, prev?: RouteSegment, currTree?: RouteTree,
|
||||
prevTree?: RouteTree): void {
|
||||
let id = curr.getParam("id");
|
||||
this._db.email(id).then(data => this.record.setData(data));
|
||||
}
|
||||
}
|
||||
|
||||
@Component({selector: 'inbox', templateUrl: 'app/inbox.html', directives: ROUTER_DIRECTIVES})
|
||||
class InboxCmp implements OnActivate {
|
||||
items: InboxRecord[] = [];
|
||||
ready: boolean = false;
|
||||
|
||||
constructor(private _db: DbService) {}
|
||||
|
||||
routerOnActivate(curr: RouteSegment, prev?: RouteSegment, currTree?: RouteTree,
|
||||
prevTree?: RouteTree): void {
|
||||
var sortType = curr.getParam('sort');
|
||||
var sortEmailsByDate = isPresent(sortType) && sortType == "date";
|
||||
|
||||
PromiseWrapper.then(this._db.emails(), (emails: any[]) => {
|
||||
this.ready = true;
|
||||
this.items = emails.map(data => new InboxRecord(data));
|
||||
|
||||
if (sortEmailsByDate) {
|
||||
this.items.sort((a: InboxRecord, b: InboxRecord) =>
|
||||
DateWrapper.toMillis(DateWrapper.fromISOString(a.date)) <
|
||||
DateWrapper.toMillis(DateWrapper.fromISOString(b.date)) ?
|
||||
-1 :
|
||||
1);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Component({selector: 'drafts', templateUrl: 'app/drafts.html', directives: ROUTER_DIRECTIVES})
|
||||
class DraftsCmp {
|
||||
items: InboxRecord[] = [];
|
||||
ready: boolean = false;
|
||||
|
||||
constructor(db: DbService) {
|
||||
PromiseWrapper.then(db.drafts(), (drafts: any[]) => {
|
||||
this.ready = true;
|
||||
this.items = drafts.map(data => new InboxRecord(data));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'inbox-app',
|
||||
providers: [DbService, ROUTER_PROVIDERS],
|
||||
templateUrl: 'app/inbox-app.html',
|
||||
directives: ROUTER_DIRECTIVES,
|
||||
})
|
||||
@Routes([
|
||||
new Route({path: '/', component: InboxCmp}),
|
||||
new Route({path: '/inbox', component: InboxCmp}),
|
||||
new Route({path: '/drafts', component: DraftsCmp}),
|
||||
new Route({path: '/detail/:id', component: InboxDetailCmp})
|
||||
])
|
||||
export class InboxApp {
|
||||
constructor(private _location: Location) {}
|
||||
inboxPageActive() { return this._location.path() == ''; }
|
||||
draftsPageActive() { return this._location.path() == '/drafts'; }
|
||||
}
|
|
@ -1,24 +0,0 @@
|
|||
<div>
|
||||
<h2 class="page-title">{{ record.subject }}</h2>
|
||||
|
||||
<ul>
|
||||
<li id="record-id">ID: {{ record.id }}</li>
|
||||
<li id="record-name">Name: {{ record.firstName }} {{ record.lastName }}</li>
|
||||
<li id="record-email">Email: {{ record.email }}</li>
|
||||
<li id="record-date">Date: {{ record.date }}</li>
|
||||
</ul>
|
||||
|
||||
<p>
|
||||
{{ record.content }}
|
||||
</p>
|
||||
|
||||
<span class="btn medium primary">
|
||||
<a [routerLink]="record.draft ? ['/drafts'] : ['/']" class="back-button">Back</a>
|
||||
</span>
|
||||
|
||||
<hr />
|
||||
|
||||
<a [routerLink]="['/inbox', { sort: 'date'} ]" class="sort-button">
|
||||
View Latest Messages
|
||||
</a>
|
||||
</div>
|
|
@ -1,10 +0,0 @@
|
|||
<div>
|
||||
<h2 class="page-title">Inbox</h2>
|
||||
|
||||
<ol class="inbox-list">
|
||||
<li *ngFor="let item of items" class="inbox-item-record">
|
||||
<a id="item-{{ item.id }}"
|
||||
[routerLink]="['/detail', item.id]">{{ item.subject }}</a>
|
||||
</li>
|
||||
</ol>
|
||||
</div>
|
|
@ -1,57 +0,0 @@
|
|||
body {
|
||||
background:#eee;
|
||||
color:black;
|
||||
}
|
||||
|
||||
.inbox-list,
|
||||
.inbox-list li {
|
||||
list-style:none;
|
||||
padding:0;
|
||||
margin:0;
|
||||
}
|
||||
|
||||
.inbox-list a {
|
||||
padding:5px;
|
||||
display:block;
|
||||
}
|
||||
|
||||
inbox, drafts, inbox-side-menu {
|
||||
display:block;
|
||||
}
|
||||
|
||||
inbox-side-menu .link {
|
||||
display:block;
|
||||
text-align:center;
|
||||
padding:1em;
|
||||
}
|
||||
|
||||
inbox-side-menu .link.active {
|
||||
background:white;
|
||||
}
|
||||
|
||||
inbox-side-menu .link:hover {
|
||||
background:#eee;
|
||||
}
|
||||
|
||||
inbox-side-menu {
|
||||
position:fixed;
|
||||
left:0;
|
||||
top:0;
|
||||
bottom:0;
|
||||
width:200px;
|
||||
background:#ddd;
|
||||
}
|
||||
|
||||
inbox-side-menu a {
|
||||
display: block;
|
||||
}
|
||||
|
||||
inbox, drafts, inbox-detail {
|
||||
padding:1em;
|
||||
margin-left:200px;
|
||||
}
|
||||
|
||||
inbox-detail {
|
||||
display:block;
|
||||
margin-left:200px;
|
||||
}
|
|
@ -1,14 +0,0 @@
|
|||
<!doctype html>
|
||||
<html>
|
||||
<title>Routing Example</title>
|
||||
<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/gumby/2.6.0/css/gumby.css" />
|
||||
<link rel="stylesheet" type="text/css" href="./css/app.css" />
|
||||
<base href="/all/playground/src/alt_routing/">
|
||||
<body>
|
||||
<inbox-app>
|
||||
Loading...
|
||||
</inbox-app>
|
||||
|
||||
<script src="../bootstrap.js"></script>
|
||||
</body>
|
||||
</html>
|
|
@ -1,9 +0,0 @@
|
|||
import {InboxApp} from './app/inbox-app';
|
||||
import {bootstrap} from '@angular/platform-browser-dynamic';
|
||||
import {HashLocationStrategy, LocationStrategy} from '@angular/common';
|
||||
import {ROUTER_PROVIDERS} from '@angular/router-deprecated';
|
||||
|
||||
export function main() {
|
||||
bootstrap(InboxApp,
|
||||
[ROUTER_PROVIDERS, {provide: LocationStrategy, useClass: HashLocationStrategy}]);
|
||||
}
|
|
@ -25,7 +25,6 @@ declare var System: any;
|
|||
'@angular/platform-browser-dynamic': '/packages-dist/platform-browser-dynamic/bundles/platform-browser-dynamic.umd.js',
|
||||
'@angular/http': '/packages-dist/http/bundles/http.umd.js',
|
||||
'@angular/upgrade': '/packages-dist/upgrade/bundles/upgrade.umd.js',
|
||||
'@angular/router': '/packages-dist/router/bundles/router.umd.js',
|
||||
'@angular/router-deprecated': '/packages-dist/router-deprecated/bundles/router-deprecated.umd.js',
|
||||
'@angular/core/src/facade': '/all/@angular/core/src/facade',
|
||||
'rxjs': location.pathname.replace(/\w+\.html$/i, '') + 'rxjs'
|
||||
|
@ -50,8 +49,7 @@ declare var System: any;
|
|||
'@angular/compiler': {main: 'index.js', defaultExtension: 'js'},
|
||||
'@angular/common': {main: 'index.js', defaultExtension: 'js'},
|
||||
'@angular/platform-browser': {main: 'index.js', defaultExtension: 'js'},
|
||||
'@angular/platform-browser-dynamic': {main: 'index.js', defaultExtension: 'js'},
|
||||
'@angular/router': {main: 'index.js', defaultExtension: 'js'},
|
||||
'@angular/platform-browser-dynamic': {main: 'index.js', defaultExtension: 'js'}
|
||||
// 'rxjs': {
|
||||
// defaultExtension: 'js'
|
||||
// }
|
||||
|
|
|
@ -16,7 +16,7 @@ System.config({
|
|||
'@angular/compiler': {main: 'index.js', defaultExtension: 'js'},
|
||||
'@angular/common': {main: 'index.js', defaultExtension: 'js'},
|
||||
'@angular/platform-browser': {main: 'index.js', defaultExtension: 'js'},
|
||||
'@angular/router': {main: 'index.js', defaultExtension: 'js'},
|
||||
'@angular/router-deprecated': {main: 'index.js', defaultExtension: 'js'},
|
||||
'rxjs': {
|
||||
defaultExtension: 'js'
|
||||
}
|
||||
|
|
|
@ -16,7 +16,7 @@ System.config({
|
|||
'@angular/common': {main: 'index.js', defaultExtension: 'js'},
|
||||
'@angular/platform-browser': {main: 'index.js', defaultExtension: 'js'},
|
||||
'@angular/platform-browser-dynamic': {main: 'index.js', defaultExtension: 'js'},
|
||||
'@angular/router': {main: 'index.js', defaultExtension: 'js'},
|
||||
'@angular/router-deprecated': {main: 'index.js', defaultExtension: 'js'},
|
||||
'rxjs': {
|
||||
defaultExtension: 'js'
|
||||
}
|
||||
|
|
|
@ -16,7 +16,7 @@ System.config({
|
|||
'@angular/common': {main: 'index.js', defaultExtension: 'js'},
|
||||
'@angular/platform-browser': {main: 'index.js', defaultExtension: 'js'},
|
||||
'@angular/platform-browser-dynamic': {main: 'index.js', defaultExtension: 'js'},
|
||||
'@angular/router': {main: 'index.js', defaultExtension: 'js'},
|
||||
'@angular/router-deprecated': {main: 'index.js', defaultExtension: 'js'},
|
||||
'rxjs': {
|
||||
defaultExtension: 'js'
|
||||
},
|
||||
|
|
|
@ -16,7 +16,7 @@ System.config({
|
|||
'@angular/common': {main: 'index.js', defaultExtension: 'js'},
|
||||
'@angular/platform-browser': {main: 'index.js', defaultExtension: 'js'},
|
||||
'@angular/platform-browser-dynamic': {main: 'index.js', defaultExtension: 'js'},
|
||||
'@angular/router': {main: 'index.js', defaultExtension: 'js'},
|
||||
'@angular/router-deprecated': {main: 'index.js', defaultExtension: 'js'},
|
||||
'rxjs': {
|
||||
defaultExtension: 'js'
|
||||
},
|
||||
|
|
|
@ -16,7 +16,6 @@ System.config({
|
|||
'@angular/common': {main: 'index.js', defaultExtension: 'js'},
|
||||
'@angular/platform-browser': {main: 'index.js', defaultExtension: 'js'},
|
||||
'@angular/platform-browser-dynamic': {main: 'index.js', defaultExtension: 'js'},
|
||||
'@angular/router': {main: 'index.js', defaultExtension: 'js'},
|
||||
'@angular/router-deprecated': {main: 'index.js', defaultExtension: 'js'},
|
||||
'rxjs': {
|
||||
defaultExtension: 'js'
|
||||
|
|
|
@ -16,7 +16,7 @@ System.config({
|
|||
'@angular/common': {main: 'index.js', defaultExtension: 'js'},
|
||||
'@angular/platform-browser': {main: 'index.js', defaultExtension: 'js'},
|
||||
'@angular/platform-browser-dynamic': {main: 'index.js', defaultExtension: 'js'},
|
||||
'@angular/router': {main: 'index.js', defaultExtension: 'js'},
|
||||
'@angular/router-deprecated': {main: 'index.js', defaultExtension: 'js'},
|
||||
'rxjs': {
|
||||
defaultExtension: 'js'
|
||||
}
|
||||
|
|
|
@ -26,7 +26,6 @@ for PACKAGE in \
|
|||
http \
|
||||
platform-browser \
|
||||
platform-server \
|
||||
router \
|
||||
router-deprecated \
|
||||
upgrade
|
||||
do
|
||||
|
|
|
@ -64,7 +64,6 @@ $DART_SDK/bin/dart $DDC_DIR/bin/dartdevc.dart \
|
|||
src/person_management/index.dart \
|
||||
src/relative_assets/index.dart \
|
||||
src/routing/index.dart \
|
||||
src/alt_routing/index.dart \
|
||||
src/sourcemap/index.dart \
|
||||
src/svg/index.dart \
|
||||
src/template_driven_forms/index.dart \
|
||||
|
|
|
@ -41,10 +41,6 @@ System.config({
|
|||
main: 'index.js',
|
||||
defaultExtension: 'js'
|
||||
},
|
||||
'@angular/router': {
|
||||
main: 'index.js',
|
||||
defaultExtension: 'js'
|
||||
},
|
||||
'@angular/router-deprecated': {
|
||||
main: 'index.js',
|
||||
defaultExtension: 'js'
|
||||
|
|
|
@ -52,7 +52,6 @@ const kServedPaths = [
|
|||
'playground/src/key_events',
|
||||
'playground/src/relative_assets',
|
||||
'playground/src/routing',
|
||||
'playground/src/alt_routing',
|
||||
'playground/src/sourcemap',
|
||||
'playground/src/svg',
|
||||
'playground/src/todo',
|
||||
|
|
|
@ -10,10 +10,8 @@ import * as platformBrowserDynmic from '@angular/platform-browser-dynamic';
|
|||
import * as platformBrowser from '@angular/platform-browser/testing';
|
||||
import * as platfomrServerTesting from '@angular/platform-server';
|
||||
import * as platfomrServer from '@angular/platform-server/testing';
|
||||
import * as router from '@angular/router';
|
||||
import * as routerDeprecatedTesting from '@angular/router-deprecated';
|
||||
import * as routerDeprecated from '@angular/router-deprecated/testing';
|
||||
import * as routerTesting from '@angular/router/testing';
|
||||
import * as upgrade from '@angular/upgrade';
|
||||
|
||||
export default {
|
||||
|
@ -29,8 +27,6 @@ export default {
|
|||
platformBrowserDynmic,
|
||||
platfomrServer,
|
||||
platfomrServerTesting,
|
||||
router,
|
||||
routerTesting,
|
||||
routerDeprecated,
|
||||
routerDeprecatedTesting,
|
||||
upgrade
|
||||
|
|
|
@ -3,7 +3,7 @@ set -ex -o pipefail
|
|||
|
||||
# These ones can be `npm link`ed for fast development
|
||||
LINKABLE_PKGS=(
|
||||
$(pwd)/dist/packages-dist/{common,core,compiler,compiler-cli,http,router,router-deprecated,upgrade,platform-{browser,browser-dynamic,server}}
|
||||
$(pwd)/dist/packages-dist/{common,core,compiler,compiler-cli,http,router-deprecated,upgrade,platform-{browser,browser-dynamic,server}}
|
||||
)
|
||||
|
||||
TMPDIR=${TMPDIR:-/tmp/angular-build/}
|
||||
|
|
Loading…
Reference in New Issue