Skip to content

Commit

Permalink
feat(router): auxiliary routes
Browse files Browse the repository at this point in the history
Closes #2775
  • Loading branch information
btford committed Aug 10, 2015
1 parent 96e34c1 commit ac6227e
Show file tree
Hide file tree
Showing 24 changed files with 1,470 additions and 974 deletions.
3 changes: 2 additions & 1 deletion modules/angular2/router.ts
Expand Up @@ -19,7 +19,8 @@ export * from './src/router/route_config_decorator';
export * from './src/router/route_definition';
export {OnActivate, OnDeactivate, OnReuse, CanDeactivate, CanReuse} from './src/router/interfaces';
export {CanActivate} from './src/router/lifecycle_annotations';
export {Instruction} from './src/router/instruction';
export {Instruction, ComponentInstruction} from './src/router/instruction';
export {Url} from './src/router/url_parser';

import {LocationStrategy} from './src/router/location_strategy';
import {HTML5LocationStrategy} from './src/router/html5_location_strategy';
Expand Down
19 changes: 0 additions & 19 deletions modules/angular2/src/router/helpers.ts

This file was deleted.

102 changes: 76 additions & 26 deletions modules/angular2/src/router/instruction.ts
Expand Up @@ -6,9 +6,11 @@ import {
List,
ListWrapper
} from 'angular2/src/facade/collection';
import {isPresent, isBlank, normalizeBlank} from 'angular2/src/facade/lang';
import {isPresent, isBlank, normalizeBlank, Type} from 'angular2/src/facade/lang';
import {Promise} from 'angular2/src/facade/async';

import {PathRecognizer} from './path_recognizer';
import {Url} from './url_parser';

export class RouteParams {
constructor(public params: StringMap<string, string>) {}
Expand All @@ -18,34 +20,82 @@ export class RouteParams {


/**
* An `Instruction` represents the component hierarchy of the application based on a given route
* `Instruction` is a tree of `ComponentInstructions`, with all the information needed
* to transition each component in the app to a given route, including all auxiliary routes.
*
* This is a public API.
*/
export class Instruction {
// "capturedUrl" is the part of the URL captured by this instruction
// "accumulatedUrl" is the part of the URL captured by this instruction and all children
accumulatedUrl: string;
reuse: boolean = false;
specificity: number;

constructor(public component: any, public capturedUrl: string,
private _recognizer: PathRecognizer, public child: Instruction = null,
private _params: StringMap<string, any> = null) {
this.accumulatedUrl = capturedUrl;
this.specificity = _recognizer.specificity;
if (isPresent(child)) {
this.child = child;
this.specificity += child.specificity;
var childUrl = child.accumulatedUrl;
if (isPresent(childUrl)) {
this.accumulatedUrl += childUrl;
}
}
constructor(public component: ComponentInstruction, public child: Instruction,
public auxInstruction: StringMap<string, Instruction>) {}

replaceChild(child: Instruction): Instruction {
return new Instruction(this.component, child, this.auxInstruction);
}
}

/**
* Represents a partially completed instruction during recognition that only has the
* primary (non-aux) route instructions matched.
*
* `PrimaryInstruction` is an internal class used by `RouteRecognizer` while it's
* figuring out where to navigate.
*/
export class PrimaryInstruction {
constructor(public component: ComponentInstruction, public child: PrimaryInstruction,
public auxUrls: List<Url>) {}
}

export function stringifyInstruction(instruction: Instruction): string {
var params = instruction.component.urlParams.length > 0 ?
('?' + instruction.component.urlParams.join('&')) :
'';

return instruction.component.urlPath + stringifyAux(instruction) +
stringifyPrimary(instruction.child) + params;
}

function stringifyPrimary(instruction: Instruction): string {
if (isBlank(instruction)) {
return '';
}
var params = instruction.component.urlParams.length > 0 ?
(';' + instruction.component.urlParams.join(';')) :
'';
return '/' + instruction.component.urlPath + params + stringifyAux(instruction) +
stringifyPrimary(instruction.child);
}

params(): StringMap<string, string> {
if (isBlank(this._params)) {
this._params = this._recognizer.parseParams(this.capturedUrl);
}
return this._params;
function stringifyAux(instruction: Instruction): string {
var routes = [];
StringMapWrapper.forEach(instruction.auxInstruction, (auxInstruction, _) => {
routes.push(stringifyPrimary(auxInstruction));
});
if (routes.length > 0) {
return '(' + routes.join('//') + ')';
}
return '';
}


/**
* A `ComponentInstruction` represents the route state for a single component. An `Instruction` is
* composed of a tree of these `ComponentInstruction`s.
*
* `ComponentInstructions` is a public API. Instances of `ComponentInstruction` are passed
* to route lifecycle hooks, like {@link CanActivate}.
*/
export class ComponentInstruction {
reuse: boolean = false;

constructor(public urlPath: string, public urlParams: List<string>,
private _recognizer: PathRecognizer, public params: StringMap<string, any> = null) {}

get componentType() { return this._recognizer.handler.componentType; }

resolveComponentType(): Promise<Type> { return this._recognizer.handler.resolveComponentType(); }

get specificity() { return this._recognizer.specificity; }

get terminal() { return this._recognizer.terminal; }
}
12 changes: 6 additions & 6 deletions modules/angular2/src/router/interfaces.ts
@@ -1,4 +1,4 @@
import {Instruction} from './instruction';
import {ComponentInstruction} from './instruction';
import {global} from 'angular2/src/facade/lang';

// This is here only so that after TS transpilation the file is not empty.
Expand All @@ -11,33 +11,33 @@ var __ignore_me = global;
* Defines route lifecycle method [onActivate]
*/
export interface OnActivate {
onActivate(nextInstruction: Instruction, prevInstruction: Instruction): any;
onActivate(nextInstruction: ComponentInstruction, prevInstruction: ComponentInstruction): any;
}

/**
* Defines route lifecycle method [onReuse]
*/
export interface OnReuse {
onReuse(nextInstruction: Instruction, prevInstruction: Instruction): any;
onReuse(nextInstruction: ComponentInstruction, prevInstruction: ComponentInstruction): any;
}

/**
* Defines route lifecycle method [onDeactivate]
*/
export interface OnDeactivate {
onDeactivate(nextInstruction: Instruction, prevInstruction: Instruction): any;
onDeactivate(nextInstruction: ComponentInstruction, prevInstruction: ComponentInstruction): any;
}

/**
* Defines route lifecycle method [canReuse]
*/
export interface CanReuse {
canReuse(nextInstruction: Instruction, prevInstruction: Instruction): any;
canReuse(nextInstruction: ComponentInstruction, prevInstruction: ComponentInstruction): any;
}

/**
* Defines route lifecycle method [canDeactivate]
*/
export interface CanDeactivate {
canDeactivate(nextInstruction: Instruction, prevInstruction: Instruction): any;
canDeactivate(nextInstruction: ComponentInstruction, prevInstruction: ComponentInstruction): any;
}
4 changes: 2 additions & 2 deletions modules/angular2/src/router/lifecycle_annotations.ts
Expand Up @@ -6,7 +6,7 @@
import {makeDecorator} from 'angular2/src/util/decorators';
import {CanActivate as CanActivateAnnotation} from './lifecycle_annotations_impl';
import {Promise} from 'angular2/src/facade/async';
import {Instruction} from 'angular2/src/router/instruction';
import {ComponentInstruction} from 'angular2/src/router/instruction';

export {
canReuse,
Expand All @@ -17,5 +17,5 @@ export {
} from './lifecycle_annotations_impl';

export var CanActivate:
(hook: (next: Instruction, prev: Instruction) => Promise<boolean>| boolean) => ClassDecorator =
(hook: (next: ComponentInstruction, prev: ComponentInstruction) => Promise<boolean>| boolean) => ClassDecorator =
makeDecorator(CanActivateAnnotation);

0 comments on commit ac6227e

Please sign in to comment.