11import { Promise , PromiseWrapper , EventEmitter , ObservableWrapper } from 'angular2/src/facade/async' ;
22import { Map , MapWrapper , List , ListWrapper } from 'angular2/src/facade/collection' ;
3- import { isBlank , isPresent , Type , isArray } from 'angular2/src/facade/lang' ;
3+ import {
4+ isBlank ,
5+ isString ,
6+ StringWrapper ,
7+ isPresent ,
8+ Type ,
9+ isArray ,
10+ BaseException
11+ } from 'angular2/src/facade/lang' ;
412
513import { RouteRegistry } from './route_registry' ;
614import { Pipeline } from './pipeline' ;
@@ -42,7 +50,7 @@ export class Router {
4250
4351 // todo(jeffbcross): rename _registry to registry since it is accessed from subclasses
4452 // todo(jeffbcross): rename _pipeline to pipeline since it is accessed from subclasses
45- constructor ( public _registry : RouteRegistry , public _pipeline : Pipeline , public parent : Router ,
53+ constructor ( public registry : RouteRegistry , public _pipeline : Pipeline , public parent : Router ,
4654 public hostComponent : any ) { }
4755
4856
@@ -88,9 +96,9 @@ export class Router {
8896 config ( config : StringMap < string , any > | List < StringMap < string , any > > ) : Promise < any > {
8997 if ( isArray ( config ) ) {
9098 ( < List < any > > config )
91- . forEach ( ( configObject ) => { this . _registry . config ( this . hostComponent , configObject ) ; } ) ;
99+ . forEach ( ( configObject ) => { this . registry . config ( this . hostComponent , configObject ) ; } ) ;
92100 } else {
93- this . _registry . config ( this . hostComponent , config ) ;
101+ this . registry . config ( this . hostComponent , config ) ;
94102 }
95103 return this . renavigate ( ) ;
96104 }
@@ -170,7 +178,7 @@ export class Router {
170178 * Given a URL, returns an instruction representing the component graph
171179 */
172180 recognize ( url : string ) : Promise < Instruction > {
173- return this . _registry . recognize ( url , this . hostComponent ) ;
181+ return this . registry . recognize ( url , this . hostComponent ) ;
174182 }
175183
176184
@@ -192,7 +200,48 @@ export class Router {
192200 * app's base href.
193201 */
194202 generate ( linkParams : List < any > ) : string {
195- return this . _registry . generate ( linkParams , this . hostComponent ) ;
203+ let normalizedLinkParams = splitAndFlattenLinkParams ( linkParams ) ;
204+
205+ var first = ListWrapper . first ( normalizedLinkParams ) ;
206+ var rest = ListWrapper . slice ( normalizedLinkParams , 1 ) ;
207+
208+ var router = this ;
209+
210+ // The first segment should be either '.' (generate from parent) or '' (generate from root).
211+ // When we normalize above, we strip all the slashes, './' becomes '.' and '/' becomes ''.
212+ if ( first == '' ) {
213+ while ( isPresent ( router . parent ) ) {
214+ router = router . parent ;
215+ }
216+ } else if ( first == '..' ) {
217+ router = router . parent ;
218+ while ( ListWrapper . first ( rest ) == '..' ) {
219+ rest = ListWrapper . slice ( rest , 1 ) ;
220+ router = router . parent ;
221+ if ( isBlank ( router ) ) {
222+ throw new BaseException (
223+ `Link "${ ListWrapper . toJSON ( linkParams ) } " has too many "../" segments.` ) ;
224+ }
225+ }
226+ } else if ( first != '.' ) {
227+ throw new BaseException (
228+ `Link "${ ListWrapper . toJSON ( linkParams ) } " must start with "/", "./", or "../"` ) ;
229+ }
230+
231+ if ( rest [ rest . length - 1 ] == '' ) {
232+ ListWrapper . removeLast ( rest ) ;
233+ }
234+
235+ if ( rest . length < 1 ) {
236+ let msg = `Link "${ ListWrapper . toJSON ( linkParams ) } " must include a route name.` ;
237+ throw new BaseException ( msg ) ;
238+ }
239+
240+ let url = '' ;
241+ if ( isPresent ( router . parent ) && isPresent ( router . parent . _currentInstruction ) ) {
242+ url = router . parent . _currentInstruction . capturedUrl ;
243+ }
244+ return url + '/' + this . registry . generate ( rest , router . hostComponent ) ;
196245 }
197246}
198247
@@ -204,7 +253,7 @@ export class RootRouter extends Router {
204253 super ( registry , pipeline , null , hostComponent ) ;
205254 this . _location = location ;
206255 this . _location . subscribe ( ( change ) => this . navigate ( change [ 'url' ] ) ) ;
207- this . _registry . configFromComponent ( hostComponent ) ;
256+ this . registry . configFromComponent ( hostComponent ) ;
208257 this . navigate ( location . path ( ) ) ;
209258 }
210259
@@ -216,7 +265,7 @@ export class RootRouter extends Router {
216265
217266class ChildRouter extends Router {
218267 constructor ( parent : Router , hostComponent ) {
219- super ( parent . _registry , parent . _pipeline , parent , hostComponent ) ;
268+ super ( parent . registry , parent . _pipeline , parent , hostComponent ) ;
220269 this . parent = parent ;
221270 }
222271
@@ -226,3 +275,18 @@ class ChildRouter extends Router {
226275 return this . parent . navigate ( url ) ;
227276 }
228277}
278+
279+ /*
280+ * Given: ['/a/b', {c: 2}]
281+ * Returns: ['', 'a', 'b', {c: 2}]
282+ */
283+ var SLASH = new RegExp ( '/' ) ;
284+ function splitAndFlattenLinkParams ( linkParams : List < any > ) : List < any > {
285+ return ListWrapper . reduce ( linkParams , ( accumulation , item ) => {
286+ if ( isString ( item ) ) {
287+ return ListWrapper . concat ( accumulation , StringWrapper . split ( item , SLASH ) ) ;
288+ }
289+ accumulation . push ( item ) ;
290+ return accumulation ;
291+ } , [ ] ) ;
292+ }
0 commit comments