2015-05-29 14:58:41 -07:00
|
|
|
import {
|
|
|
|
Map,
|
|
|
|
MapWrapper,
|
|
|
|
StringMap,
|
|
|
|
StringMapWrapper,
|
|
|
|
List,
|
|
|
|
ListWrapper
|
|
|
|
} from 'angular2/src/facade/collection';
|
2015-04-17 09:59:56 -07:00
|
|
|
import {Promise, PromiseWrapper} from 'angular2/src/facade/async';
|
2015-05-14 15:24:35 +02:00
|
|
|
import {isPresent, normalizeBlank} from 'angular2/src/facade/lang';
|
2015-04-17 09:59:56 -07:00
|
|
|
|
|
|
|
export class RouteParams {
|
2015-05-29 14:58:41 -07:00
|
|
|
constructor(public params: StringMap<string, string>) {}
|
2015-05-14 15:24:35 +02:00
|
|
|
|
2015-05-29 14:58:41 -07:00
|
|
|
get(param: string): string { return normalizeBlank(StringMapWrapper.get(this.params, param)); }
|
2015-04-17 09:59:56 -07:00
|
|
|
}
|
|
|
|
|
2015-05-15 02:05:57 -07:00
|
|
|
/**
|
|
|
|
* An `Instruction` represents the component hierarchy of the application based on a given route
|
|
|
|
*/
|
2015-04-17 09:59:56 -07:00
|
|
|
export class Instruction {
|
2015-05-29 14:58:41 -07:00
|
|
|
component: any;
|
|
|
|
private _children: StringMap<string, Instruction>;
|
2015-05-14 13:01:48 -07:00
|
|
|
|
|
|
|
// the part of the URL captured by this instruction
|
2015-05-29 14:58:41 -07:00
|
|
|
capturedUrl: string;
|
2015-05-14 13:01:48 -07:00
|
|
|
|
|
|
|
// the part of the URL captured by this instruction and all children
|
2015-05-29 14:58:41 -07:00
|
|
|
accumulatedUrl: string;
|
|
|
|
|
|
|
|
params: StringMap<string, string>;
|
|
|
|
reuse: boolean;
|
|
|
|
specificity: number;
|
|
|
|
|
|
|
|
constructor({params, component, children, matchedUrl, parentSpecificity}: {
|
|
|
|
params?: StringMap<string, any>,
|
|
|
|
component?: any,
|
|
|
|
children?: StringMap<string, Instruction>,
|
|
|
|
matchedUrl?: string,
|
|
|
|
parentSpecificity?: number
|
|
|
|
} = {}) {
|
2015-05-07 21:10:12 -07:00
|
|
|
this.reuse = false;
|
2015-05-14 13:01:48 -07:00
|
|
|
this.capturedUrl = matchedUrl;
|
|
|
|
this.accumulatedUrl = matchedUrl;
|
2015-05-15 02:05:57 -07:00
|
|
|
this.specificity = parentSpecificity;
|
2015-04-17 09:59:56 -07:00
|
|
|
if (isPresent(children)) {
|
|
|
|
this._children = children;
|
|
|
|
var childUrl;
|
|
|
|
StringMapWrapper.forEach(this._children, (child, _) => {
|
2015-05-14 13:01:48 -07:00
|
|
|
childUrl = child.accumulatedUrl;
|
2015-05-15 02:05:57 -07:00
|
|
|
this.specificity += child.specificity;
|
2015-04-17 09:59:56 -07:00
|
|
|
});
|
|
|
|
if (isPresent(childUrl)) {
|
2015-05-14 13:01:48 -07:00
|
|
|
this.accumulatedUrl += childUrl;
|
2015-04-17 09:59:56 -07:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
this._children = StringMapWrapper.create();
|
|
|
|
}
|
|
|
|
this.component = component;
|
|
|
|
this.params = params;
|
|
|
|
}
|
|
|
|
|
2015-05-29 14:58:41 -07:00
|
|
|
hasChild(outletName: string): boolean {
|
2015-05-14 13:01:48 -07:00
|
|
|
return StringMapWrapper.contains(this._children, outletName);
|
|
|
|
}
|
|
|
|
|
2015-05-15 02:05:57 -07:00
|
|
|
/**
|
|
|
|
* Returns the child instruction with the given outlet name
|
|
|
|
*/
|
2015-05-29 14:58:41 -07:00
|
|
|
getChild(outletName: string): Instruction {
|
2015-04-17 09:59:56 -07:00
|
|
|
return StringMapWrapper.get(this._children, outletName);
|
|
|
|
}
|
|
|
|
|
2015-05-15 02:05:57 -07:00
|
|
|
/**
|
|
|
|
* (child:Instruction, outletName:string) => {}
|
|
|
|
*/
|
2015-05-29 14:58:41 -07:00
|
|
|
forEachChild(fn: Function): void { StringMapWrapper.forEach(this._children, fn); }
|
2015-04-17 09:59:56 -07:00
|
|
|
|
|
|
|
/**
|
2015-05-07 21:10:12 -07:00
|
|
|
* Does a synchronous, breadth-first traversal of the graph of instructions.
|
|
|
|
* Takes a function with signature:
|
2015-05-15 02:05:57 -07:00
|
|
|
* (child:Instruction, outletName:string) => {}
|
2015-04-17 09:59:56 -07:00
|
|
|
*/
|
2015-05-29 14:58:41 -07:00
|
|
|
traverseSync(fn: Function): void {
|
2015-05-14 13:01:48 -07:00
|
|
|
this.forEachChild(fn);
|
2015-04-17 09:59:56 -07:00
|
|
|
this.forEachChild((childInstruction, _) => childInstruction.traverseSync(fn));
|
|
|
|
}
|
2015-05-07 21:10:12 -07:00
|
|
|
|
|
|
|
|
|
|
|
/**
|
2015-05-29 14:58:41 -07:00
|
|
|
* Takes a currently active instruction and sets a reuse flag on each of this instruction's
|
|
|
|
* children
|
2015-05-07 21:10:12 -07:00
|
|
|
*/
|
2015-05-29 14:58:41 -07:00
|
|
|
reuseComponentsFrom(oldInstruction: Instruction): void {
|
2015-05-14 13:01:48 -07:00
|
|
|
this.traverseSync((childInstruction, outletName) => {
|
|
|
|
var oldInstructionChild = oldInstruction.getChild(outletName);
|
2015-05-07 21:10:12 -07:00
|
|
|
if (shouldReuseComponent(childInstruction, oldInstructionChild)) {
|
|
|
|
childInstruction.reuse = true;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-05-29 14:58:41 -07:00
|
|
|
function shouldReuseComponent(instr1: Instruction, instr2: Instruction): boolean {
|
2015-05-07 21:10:12 -07:00
|
|
|
return instr1.component == instr2.component &&
|
2015-05-29 14:58:41 -07:00
|
|
|
StringMapWrapper.equals(instr1.params, instr2.params);
|
2015-04-17 09:59:56 -07:00
|
|
|
}
|
|
|
|
|
2015-05-29 14:58:41 -07:00
|
|
|
function mapObjAsync(obj: StringMap<string, any>, fn): Promise<List<any>> {
|
2015-04-17 09:59:56 -07:00
|
|
|
return PromiseWrapper.all(mapObj(obj, fn));
|
|
|
|
}
|
|
|
|
|
2015-05-29 14:58:41 -07:00
|
|
|
function mapObj(obj: StringMap<any, any>, fn: Function): List<any> {
|
2015-04-17 09:59:56 -07:00
|
|
|
var result = ListWrapper.create();
|
|
|
|
StringMapWrapper.forEach(obj, (value, key) => ListWrapper.push(result, fn(value, key)));
|
|
|
|
return result;
|
|
|
|
}
|