feat(router): update recognize to handle matrix parameters
This commit is contained in:
parent
79830f1c75
commit
446657bdd5
|
@ -45,12 +45,13 @@ function _constructSegment(componentResolver: ComponentResolver,
|
|||
matched: _MatchResult): Promise<TreeNode<RouteSegment>[]> {
|
||||
return componentResolver.resolveComponent(matched.route.component)
|
||||
.then(factory => {
|
||||
let urlOutlet = matched.consumedUrlSegments[0].outlet;
|
||||
let segment = new RouteSegment(matched.consumedUrlSegments, matched.parameters,
|
||||
matched.consumedUrlSegments[0].outlet,
|
||||
isBlank(urlOutlet) ? DEFAULT_OUTLET_NAME : urlOutlet,
|
||||
matched.route.component, factory);
|
||||
|
||||
if (isPresent(matched.leftOverUrl)) {
|
||||
return _recognize(componentResolver, matched.route.component, matched.leftOverUrl)
|
||||
if (matched.leftOverUrl.length > 0) {
|
||||
return _recognizeMany(componentResolver, matched.route.component, matched.leftOverUrl)
|
||||
.then(children => [new TreeNode<RouteSegment>(segment, children)]);
|
||||
} else {
|
||||
return [new TreeNode<RouteSegment>(segment, [])];
|
||||
|
@ -78,12 +79,13 @@ function _matchWithParts(route: RouteMetadata, url: TreeNode<UrlSegment>): _Matc
|
|||
|
||||
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 (isBlank(current)) return null;
|
||||
if (!isPosParam && p != current.value.segment) return null;
|
||||
if (isLastSegment) {
|
||||
lastSegment = current;
|
||||
|
@ -101,10 +103,18 @@ function _matchWithParts(route: RouteMetadata, url: TreeNode<UrlSegment>): _Matc
|
|||
current = ListWrapper.first(current.children);
|
||||
}
|
||||
|
||||
let parameters = <{[key: string]: string}>StringMapWrapper.merge(lastSegment.value.parameters,
|
||||
positionalParams);
|
||||
if (isPresent(current) && isBlank(current.value.segment)) {
|
||||
lastParent = lastSegment;
|
||||
lastSegment = current;
|
||||
}
|
||||
|
||||
let p = lastSegment.value.parameters;
|
||||
let parameters =
|
||||
<{[key: string]: string}>StringMapWrapper.merge(isBlank(p) ? {} : p, positionalParams);
|
||||
let axuUrlSubtrees = isPresent(lastParent) ? lastParent.children.slice(1) : [];
|
||||
return new _MatchResult(route, consumedUrlSegments, parameters, current, axuUrlSubtrees);
|
||||
|
||||
return new _MatchResult(route, consumedUrlSegments, parameters, lastSegment.children,
|
||||
axuUrlSubtrees);
|
||||
}
|
||||
|
||||
function _checkOutletNameUniqueness(nodes: TreeNode<RouteSegment>[]): TreeNode<RouteSegment>[] {
|
||||
|
@ -123,8 +133,8 @@ function _checkOutletNameUniqueness(nodes: TreeNode<RouteSegment>[]): TreeNode<R
|
|||
|
||||
class _MatchResult {
|
||||
constructor(public route: RouteMetadata, public consumedUrlSegments: UrlSegment[],
|
||||
public parameters: {[key: string]: string}, public leftOverUrl: TreeNode<UrlSegment>,
|
||||
public aux: TreeNode<UrlSegment>[]) {}
|
||||
public parameters: {[key: string]: string},
|
||||
public leftOverUrl: TreeNode<UrlSegment>[], public aux: TreeNode<UrlSegment>[]) {}
|
||||
}
|
||||
|
||||
function _readMetadata(componentType: Type) {
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import {ComponentFactory} from 'angular2/core';
|
||||
import {StringMapWrapper, ListWrapper} from 'angular2/src/facade/collection';
|
||||
import {Type, isBlank, isPresent} from 'angular2/src/facade/lang';
|
||||
import {DEFAULT_OUTLET_NAME} from './constants';
|
||||
import {Type, isBlank, isPresent, stringify} from 'angular2/src/facade/lang';
|
||||
|
||||
export class Tree<T> {
|
||||
/** @internal */
|
||||
|
@ -59,18 +58,21 @@ export class TreeNode<T> {
|
|||
}
|
||||
|
||||
export class UrlSegment {
|
||||
constructor(public segment: string, public parameters: {[key: string]: string},
|
||||
constructor(public segment: any, public parameters: {[key: string]: string},
|
||||
public outlet: string) {}
|
||||
|
||||
toString(): string {
|
||||
let outletPrefix = this.outlet == DEFAULT_OUTLET_NAME ? "" : `${this.outlet}:`;
|
||||
return `${outletPrefix}${this.segment}${_serializeParams(this.parameters)}`;
|
||||
let outletPrefix = isBlank(this.outlet) ? "" : `${this.outlet}:`;
|
||||
let segmentPrefix = isBlank(this.segment) ? "" : this.segment;
|
||||
return `${outletPrefix}${segmentPrefix}${_serializeParams(this.parameters)}`;
|
||||
}
|
||||
}
|
||||
|
||||
function _serializeParams(params: {[key: string]: string}): string {
|
||||
let res = "";
|
||||
StringMapWrapper.forEach(params, (v, k) => res += `;${k}=${v}`);
|
||||
if (isPresent(params)) {
|
||||
StringMapWrapper.forEach(params, (v, k) => res += `;${k}=${v}`);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
@ -94,10 +96,23 @@ export class RouteSegment {
|
|||
get stringifiedUrlSegments(): string { return this.urlSegments.map(s => s.toString()).join("/"); }
|
||||
}
|
||||
|
||||
export function serializeRouteSegmentTree(tree: Tree<RouteSegment>): 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 equalSegments(a: RouteSegment, b: RouteSegment): boolean {
|
||||
if (isBlank(a) && !isBlank(b)) return false;
|
||||
if (!isBlank(a) && isBlank(b)) return false;
|
||||
return a._type === b._type && StringMapWrapper.equals(a.parameters, b.parameters);
|
||||
if (a._type !== b._type) return false;
|
||||
if (isBlank(a.parameters) && !isBlank(b.parameters)) return false;
|
||||
if (!isBlank(a.parameters) && isBlank(b.parameters)) return false;
|
||||
return StringMapWrapper.equals(a.parameters, b.parameters);
|
||||
}
|
||||
|
||||
export function routeSegmentComponentFactory(a: RouteSegment): ComponentFactory {
|
||||
|
|
|
@ -19,7 +19,7 @@ import {recognize} from 'angular2/src/alt_router/recognize';
|
|||
import {Routes, Route} from 'angular2/alt_router';
|
||||
import {provide, Component, ComponentResolver} from 'angular2/core';
|
||||
import {UrlSegment, Tree} from 'angular2/src/alt_router/segments';
|
||||
import {DefaultRouterUrlParser} from 'angular2/src/alt_router/router_url_parser';
|
||||
import {DefaultRouterUrlSerializer} from 'angular2/src/alt_router/router_url_serializer';
|
||||
import {DEFAULT_OUTLET_NAME} from 'angular2/src/alt_router/constants';
|
||||
|
||||
export function main() {
|
||||
|
@ -100,6 +100,23 @@ export function main() {
|
|||
});
|
||||
}));
|
||||
|
||||
it('should handle non top-level aux routes',
|
||||
inject([AsyncTestCompleter, ComponentResolver], (async, resolver) => {
|
||||
recognize(resolver, ComponentA, tree('b/paramB/d(e)'))
|
||||
.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, resolver) => {
|
||||
recognize(resolver, ComponentA, tree("b/paramB;b1=1;b2=2(/d;d1=1;d2=2)"))
|
||||
|
@ -143,7 +160,7 @@ export function main() {
|
|||
}
|
||||
|
||||
function tree(url: string): Tree<UrlSegment> {
|
||||
return new DefaultRouterUrlParser().parse(url);
|
||||
return new DefaultRouterUrlSerializer().parse(url);
|
||||
}
|
||||
|
||||
function stringifyUrl(segments: UrlSegment[]): string[] {
|
||||
|
@ -164,7 +181,11 @@ class ComponentC {
|
|||
}
|
||||
|
||||
@Component({selector: 'b', template: 't'})
|
||||
@Routes([new Route({path: "c/:c", component: ComponentC})])
|
||||
@Routes([
|
||||
new Route({path: "d", component: ComponentD}),
|
||||
new Route({path: "e", component: ComponentE}),
|
||||
new Route({path: "c/:c", component: ComponentC})
|
||||
])
|
||||
class ComponentB {
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue