From 4f17dbc721684e0254755bbbc40674dc25cabcbd Mon Sep 17 00:00:00 2001 From: vsavkin Date: Thu, 4 Aug 2016 17:19:23 -0700 Subject: [PATCH] fix(router): add segmentPath to the link DSL --- .../@angular/router/src/create_url_tree.ts | 21 ++++++++-------- modules/@angular/router/src/router.ts | 7 +++++- modules/@angular/router/src/url_tree.ts | 25 +++++++++++-------- .../router/test/create_url_tree.spec.ts | 10 ++++++-- .../router/test/url_serializer.spec.ts | 17 +++++++++---- 5 files changed, 52 insertions(+), 28 deletions(-) diff --git a/modules/@angular/router/src/create_url_tree.ts b/modules/@angular/router/src/create_url_tree.ts index 6682128797..75d8704afb 100644 --- a/modules/@angular/router/src/create_url_tree.ts +++ b/modules/@angular/router/src/create_url_tree.ts @@ -101,17 +101,21 @@ function normalizeCommands(commands: any[]): NormalizedNavigationCommands { continue; } + if (typeof c === 'object' && c.segmentPath !== undefined) { + res.push(c.segmentPath); + continue; + } + if (!(typeof c === 'string')) { res.push(c); continue; } - const parts = c.split('/'); - for (let j = 0; j < parts.length; ++j) { - let cc = parts[j]; + if (i === 0) { + const 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' @@ -121,12 +125,9 @@ function normalizeCommands(commands: any[]): NormalizedNavigationCommands { } else if (cc != '') { res.push(cc); } - - } else { - if (cc != '') { - res.push(cc); - } } + } else { + res.push(c); } } diff --git a/modules/@angular/router/src/router.ts b/modules/@angular/router/src/router.ts index e1194a24fd..7163dbfb9c 100644 --- a/modules/@angular/router/src/router.ts +++ b/modules/@angular/router/src/router.ts @@ -220,9 +220,14 @@ export class Router { * // create /team/33;expand=true/user/11 * router.createUrlTree(['/team', 33, {expand: true}, 'user', 11]); * - * // you can collapse static fragments like this + * // you can collapse static segments like this (this works only with the first passed-in value): * router.createUrlTree(['/team/33/user', userId]); * + * If the first segment can contain slashes, and you do not want the router to split it, you + * can do the following: + * + * router.createUrlTree([{segmentPath: '/one/two'}]); + * * // create /team/33/(user/11//aux:chat) * router.createUrlTree(['/team', 33, {outlets: {primary: 'user/11', right: 'chat'}}]); * diff --git a/modules/@angular/router/src/url_tree.ts b/modules/@angular/router/src/url_tree.ts index beac8fd6f1..a9ce7d1d4d 100644 --- a/modules/@angular/router/src/url_tree.ts +++ b/modules/@angular/router/src/url_tree.ts @@ -225,19 +225,24 @@ function serializeSegment(segment: UrlSegmentGroup, root: boolean): string { } } +export function encode(s: string): string { + return encodeURIComponent(s); +} + +export function decode(s: string): string { + return decodeURIComponent(s); +} + export function serializePath(path: UrlSegment): string { - return `${encodeURIComponent(path.path)}${serializeParams(path.parameters)}`; + return `${encode(path.path)}${serializeParams(path.parameters)}`; } function serializeParams(params: {[key: string]: string}): string { - return pairs(params) - .map(p => `;${encodeURIComponent(p.first)}=${encodeURIComponent(p.second)}`) - .join(''); + return pairs(params).map(p => `;${encode(p.first)}=${encode(p.second)}`).join(''); } function serializeQueryParams(params: {[key: string]: string}): string { - const strs = - pairs(params).map(p => `${encodeURIComponent(p.first)}=${encodeURIComponent(p.second)}`); + const strs = pairs(params).map(p => `${encode(p.first)}=${encode(p.second)}`); return strs.length > 0 ? `?${strs.join("&")}` : ''; } @@ -348,7 +353,7 @@ class UrlParser { if (this.peekStartsWith(';')) { matrixParams = this.parseMatrixParams(); } - return new UrlSegment(decodeURIComponent(path), matrixParams); + return new UrlSegment(decode(path), matrixParams); } parseQueryParams(): {[key: string]: any} { @@ -366,7 +371,7 @@ class UrlParser { parseFragment(): string { if (this.peekStartsWith('#')) { - return decodeURIComponent(this.remaining.substring(1)); + return decode(this.remaining.substring(1)); } else { return null; } @@ -397,7 +402,7 @@ class UrlParser { } } - params[decodeURIComponent(key)] = decodeURIComponent(value); + params[decode(key)] = decode(value); } parseQueryParam(params: {[key: string]: any}): void { @@ -415,7 +420,7 @@ class UrlParser { this.capture(value); } } - params[decodeURIComponent(key)] = decodeURIComponent(value); + params[decode(key)] = decode(value); } parseParens(allowPrimary: boolean): {[key: string]: UrlSegmentGroup} { diff --git a/modules/@angular/router/test/create_url_tree.spec.ts b/modules/@angular/router/test/create_url_tree.spec.ts index b9da704efb..21d33d91d8 100644 --- a/modules/@angular/router/test/create_url_tree.spec.ts +++ b/modules/@angular/router/test/create_url_tree.spec.ts @@ -13,7 +13,7 @@ import {ActivatedRoute, ActivatedRouteSnapshot, advanceActivatedRoute} from '../ import {PRIMARY_OUTLET, Params} from '../src/shared'; import {DefaultUrlSerializer, UrlSegment, UrlSegmentGroup, UrlTree} from '../src/url_tree'; -describe('createUrlTree', () => { +fdescribe('createUrlTree', () => { const serializer = new DefaultUrlSerializer(); it('should navigate to the root', () => { @@ -42,6 +42,12 @@ describe('createUrlTree', () => { expect(params[1].path).toEqual('11'); }); + it('should support first segments contaings slashes', () => { + const p = serializer.parse('/'); + const t = createRoot(p, [{segmentPath: '/one'}, 'two/three']); + expect(serializer.serialize(t)).toEqual('/%2Fone/two%2Fthree'); + }); + it('should preserve secondary segments', () => { const p = serializer.parse('/a/11/b(right:c)'); const t = createRoot(p, ['/a', 11, 'd']); @@ -98,7 +104,7 @@ describe('createUrlTree', () => { it('should create matrix parameters together with other segments', () => { const p = serializer.parse('/a'); - const t = createRoot(p, ['/a', '/b', {aa: 22, bb: 33}]); + const t = createRoot(p, ['/a', 'b', {aa: 22, bb: 33}]); expect(serializer.serialize(t)).toEqual('/a/b;aa=22;bb=33'); }); diff --git a/modules/@angular/router/test/url_serializer.spec.ts b/modules/@angular/router/test/url_serializer.spec.ts index 65a0def53c..2ac5411554 100644 --- a/modules/@angular/router/test/url_serializer.spec.ts +++ b/modules/@angular/router/test/url_serializer.spec.ts @@ -7,7 +7,7 @@ */ import {PRIMARY_OUTLET} from '../src/shared'; -import {DefaultUrlSerializer, UrlSegmentGroup, serializePath} from '../src/url_tree'; +import {DefaultUrlSerializer, UrlSegmentGroup, decode, encode, serializePath} from '../src/url_tree'; describe('url serializer', () => { const url = new DefaultUrlSerializer(); @@ -181,7 +181,7 @@ describe('url serializer', () => { describe('encoding/decoding', () => { it('should encode/decode path segments and parameters', () => { const u = - `/${encodeURIComponent("one two")};${encodeURIComponent("p 1")}=${encodeURIComponent("v 1")};${encodeURIComponent("p 2")}=${encodeURIComponent("v 2")}`; + `/${encode("one two")};${encode("p 1")}=${encode("v 1")};${encode("p 2")}=${encode("v 2")}`; const tree = url.parse(u); expect(tree.root.children[PRIMARY_OUTLET].segments[0].path).toEqual('one two'); @@ -190,9 +190,16 @@ describe('url serializer', () => { expect(url.serialize(tree)).toEqual(u); }); + it('should encode/decode "slash" in path segments and parameters', () => { + const u = `/${encode("one/two")};${encode("p/1")}=${encode("v/1")}/three`; + const tree = url.parse(u); + expect(tree.root.children[PRIMARY_OUTLET].segments[0].path).toEqual('one/two'); + expect(tree.root.children[PRIMARY_OUTLET].segments[0].parameters).toEqual({['p/1']: 'v/1'}); + expect(url.serialize(tree)).toEqual(u); + }); + it('should encode/decode query params', () => { - const u = - `/one?${encodeURIComponent("p 1")}=${encodeURIComponent("v 1")}&${encodeURIComponent("p 2")}=${encodeURIComponent("v 2")}`; + const u = `/one?${encode("p 1")}=${encode("v 1")}&${encode("p 2")}=${encode("v 2")}`; const tree = url.parse(u); expect(tree.queryParams).toEqual({['p 1']: 'v 1', ['p 2']: 'v 2'}); @@ -200,7 +207,7 @@ describe('url serializer', () => { }); it('should encode/decode fragment', () => { - const u = `/one#${encodeURIComponent("one two")}`; + const u = `/one#${encode("one two")}`; const tree = url.parse(u); expect(tree.fragment).toEqual('one two');