From fa5bfe4b64a6f4e66fc30c68777e1dea9d630355 Mon Sep 17 00:00:00 2001 From: vsavkin Date: Wed, 27 Apr 2016 15:37:11 -0700 Subject: [PATCH] feat(router): add link that support only absolute urls --- modules/angular2/src/alt_router/link.ts | 64 ++++++++++++++++++ modules/angular2/test/alt_router/link_spec.ts | 67 +++++++++++++++++++ 2 files changed, 131 insertions(+) create mode 100644 modules/angular2/src/alt_router/link.ts create mode 100644 modules/angular2/test/alt_router/link_spec.ts diff --git a/modules/angular2/src/alt_router/link.ts b/modules/angular2/src/alt_router/link.ts new file mode 100644 index 0000000000..5c228964c8 --- /dev/null +++ b/modules/angular2/src/alt_router/link.ts @@ -0,0 +1,64 @@ +import {Tree, TreeNode, UrlSegment, RouteSegment, rootNode} from './segments'; +import {isBlank, isString, isStringMap} from 'angular2/src/facade/lang'; +import {ListWrapper} from 'angular2/src/facade/collection'; + +export function link(segment: RouteSegment, tree: Tree, + change: any[]): Tree { + if (change.length === 0) return tree; + let normalizedChange = (change.length === 1 && change[0] == "/") ? change : ["/"].concat(change); + return new Tree(_update(rootNode(tree), normalizedChange)); +} + +function _update(node: TreeNode, changes: any[]): TreeNode { + let rest = changes.slice(1); + let outlet = _outlet(changes); + let segment = _segment(changes); + if (isString(segment) && segment[0] == "/") segment = segment.substring(1); + + // reach the end of the tree => create new tree nodes. + if (isBlank(node)) { + let urlSegment = new UrlSegment(segment, null, outlet); + let children = rest.length === 0 ? [] : [_update(null, rest)]; + return new TreeNode(urlSegment, children); + + // different outlet => preserve the subtree + } else if (outlet != node.value.outlet) { + return node; + + // same outlet => modify the subtree + } else { + let urlSegment = isStringMap(segment) ? new UrlSegment(null, segment, null) : + new UrlSegment(segment, null, outlet); + if (rest.length === 0) { + return new TreeNode(urlSegment, []); + } + + return new TreeNode(urlSegment, + _updateMany(ListWrapper.clone(node.children), rest)); + } +} + +function _updateMany(nodes: TreeNode[], changes: any[]): TreeNode[] { + let outlet = _outlet(changes); + 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, changes); + } else { + nodes.push(_update(null, changes)); + } + + return nodes; +} + +function _segment(changes: any[]): any { + if (!isString(changes[0])) return changes[0]; + let parts = changes[0].toString().split(":"); + return parts.length > 1 ? parts[1] : changes[0]; +} + +function _outlet(changes: any[]): string { + if (!isString(changes[0])) return null; + let parts = changes[0].toString().split(":"); + return parts.length > 1 ? parts[0] : null; +} diff --git a/modules/angular2/test/alt_router/link_spec.ts b/modules/angular2/test/alt_router/link_spec.ts new file mode 100644 index 0000000000..3426cbbdeb --- /dev/null +++ b/modules/angular2/test/alt_router/link_spec.ts @@ -0,0 +1,67 @@ +import { + ComponentFixture, + AsyncTestCompleter, + TestComponentBuilder, + beforeEach, + ddescribe, + xdescribe, + describe, + el, + expect, + iit, + inject, + beforeEachProviders, + it, + xit +} from 'angular2/testing_internal'; + +import {RouteSegment, UrlSegment, Tree} from 'angular2/src/alt_router/segments'; +import {link} from 'angular2/src/alt_router/link'; +import {DefaultRouterUrlSerializer} from 'angular2/src/alt_router/router_url_serializer'; + +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 t = link(s(p.root), p, []); + expect(t).toBe(p); + }); + + it("should support going to root", () => { + let p = parser.parse("/"); + let t = link(s(p.root), p, ["/"]); + expect(parser.serialize(t)).toEqual(""); + }); + + it("should support positional params", () => { + let p = parser.parse("/"); + let t = link(s(p.root), p, ["/one", 11, "two", 22]); + expect(parser.serialize(t)).toEqual("/one/11/two/22"); + }); + + it("should preserve route siblings when changing the main route", () => { + let p = parser.parse("/a/11/b(c)"); + let t = link(s(p.root), p, ["/a", 11, 'd']); + expect(parser.serialize(t)).toEqual("/a/11/d(aux:c)"); + }); + + it("should preserve route siblings when changing a aux route", () => { + let p = parser.parse("/a/11/b(c)"); + let t = link(s(p.root), p, ["/a", 11, 'aux:d']); + expect(parser.serialize(t)).toEqual("/a/11/b(aux:d)"); + }); + + + it('should update parameters', () => { + let p = parser.parse("/a;aa=11"); + let t = link(s(p.root), p, ["/a", {aa: 22, bb: 33}]); + expect(parser.serialize(t)).toEqual("/a;aa=22;bb=33"); + }); + }); +} + +function s(u: UrlSegment): RouteSegment { + return new RouteSegment([u], {}, null, null, null); +} \ No newline at end of file