fix(router): strip base href from URLs when navigating
This commit is contained in:
		
							parent
							
								
									84dc6ae76b
								
							
						
					
					
						commit
						853d1de6ec
					
				
							
								
								
									
										2
									
								
								modules/angular2/router.js
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								modules/angular2/router.js
									
									
									
									
										vendored
									
									
								
							| @ -13,6 +13,7 @@ export {RouteParams} from './src/router/instruction'; | |||||||
| export * from './src/router/route_config_annotation'; | export * from './src/router/route_config_annotation'; | ||||||
| export * from './src/router/route_config_decorator'; | export * from './src/router/route_config_decorator'; | ||||||
| 
 | 
 | ||||||
|  | import {BrowserLocation} from './src/router/browser_location'; | ||||||
| import {Router, RootRouter} from './src/router/router'; | import {Router, RootRouter} from './src/router/router'; | ||||||
| import {RouteRegistry} from './src/router/route_registry'; | import {RouteRegistry} from './src/router/route_registry'; | ||||||
| import {Pipeline} from './src/router/pipeline'; | import {Pipeline} from './src/router/pipeline'; | ||||||
| @ -23,6 +24,7 @@ import {bind} from './di'; | |||||||
| export var routerInjectables:List = [ | export var routerInjectables:List = [ | ||||||
|   RouteRegistry, |   RouteRegistry, | ||||||
|   Pipeline, |   Pipeline, | ||||||
|  |   BrowserLocation, | ||||||
|   Location, |   Location, | ||||||
|   bind(Router).toFactory((registry, pipeline, location, meta) => { |   bind(Router).toFactory((registry, pipeline, location, meta) => { | ||||||
|     return new RootRouter(registry, pipeline, location, meta.type); |     return new RootRouter(registry, pipeline, location, meta.type); | ||||||
|  | |||||||
							
								
								
									
										36
									
								
								modules/angular2/src/router/browser_location.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								modules/angular2/src/router/browser_location.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,36 @@ | |||||||
|  | import {DOM} from 'angular2/src/dom/dom_adapter'; | ||||||
|  | 
 | ||||||
|  | export class BrowserLocation { | ||||||
|  |   _location; | ||||||
|  |   _history; | ||||||
|  |   _baseHref:string; | ||||||
|  |   constructor() { | ||||||
|  |     this._location = DOM.getLocation(); | ||||||
|  |     this._history = DOM.getHistory(); | ||||||
|  |     this._baseHref = DOM.getBaseHref(); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   onPopState(fn) { | ||||||
|  |     DOM.getGlobalEventTarget('window').addEventListener('popstate', fn, false); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   getBaseHref() { | ||||||
|  |     return this._baseHref; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   path() { | ||||||
|  |     return this._location.pathname; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   pushState(state:any, title:string, url:string) { | ||||||
|  |     this._history.pushState(state, title, url); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   forward() { | ||||||
|  |     this._history.forward(); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   back() { | ||||||
|  |     this._history.back(); | ||||||
|  |   } | ||||||
|  | } | ||||||
							
								
								
									
										47
									
								
								modules/angular2/src/router/location.js
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										47
									
								
								modules/angular2/src/router/location.js
									
									
									
									
										vendored
									
									
								
							| @ -1,40 +1,63 @@ | |||||||
| import {DOM} from 'angular2/src/dom/dom_adapter'; | import {BrowserLocation} from './browser_location'; | ||||||
|  | import {StringWrapper} from 'angular2/src/facade/lang'; | ||||||
| import {EventEmitter, ObservableWrapper} from 'angular2/src/facade/async'; | import {EventEmitter, ObservableWrapper} from 'angular2/src/facade/async'; | ||||||
| 
 | 
 | ||||||
| export class Location { | export class Location { | ||||||
|   _location; |  | ||||||
|   _subject:EventEmitter; |   _subject:EventEmitter; | ||||||
|   _history; |   _browserLocation:BrowserLocation; | ||||||
|   constructor() { |   _baseHref:string; | ||||||
|  |   constructor(browserLocation:BrowserLocation) { | ||||||
|     this._subject = new EventEmitter(); |     this._subject = new EventEmitter(); | ||||||
|     this._location = DOM.getLocation(); |     this._browserLocation = browserLocation; | ||||||
|     this._history = DOM.getHistory(); |     this._baseHref = stripIndexHtml(this._browserLocation.getBaseHref()); | ||||||
|     DOM.getGlobalEventTarget('window').addEventListener('popstate', (_) => this._onPopState(_), false); |     this._browserLocation.onPopState((_) => this._onPopState(_)); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   _onPopState(_) { |   _onPopState(_) { | ||||||
|     ObservableWrapper.callNext(this._subject, { |     ObservableWrapper.callNext(this._subject, { | ||||||
|       'url': this._location.pathname |       'url': this.path() | ||||||
|     }); |     }); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   path() { |   path() { | ||||||
|     return this._location.pathname; |     return this.normalize(this._browserLocation.path()); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   normalize(url) { | ||||||
|  |     return this._stripBaseHref(stripIndexHtml(url)); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   _stripBaseHref(url) { | ||||||
|  |     if (this._baseHref.length > 0 && StringWrapper.startsWith(url, this._baseHref)) { | ||||||
|  |       return StringWrapper.substring(url, this._baseHref.length); | ||||||
|  |     } | ||||||
|  |     return url; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   go(url:string) { |   go(url:string) { | ||||||
|     this._history.pushState(null, null, url); |     url = this._stripBaseHref(url); | ||||||
|  |     this._browserLocation.pushState(null, null, url); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   forward() { |   forward() { | ||||||
|     this._history.forward(); |     this._browserLocation.forward(); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   back() { |   back() { | ||||||
|     this._history.back() |     this._browserLocation.back(); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   subscribe(onNext, onThrow = null, onReturn = null) { |   subscribe(onNext, onThrow = null, onReturn = null) { | ||||||
|     ObservableWrapper.subscribe(this._subject, onNext, onThrow, onReturn); |     ObservableWrapper.subscribe(this._subject, onNext, onThrow, onReturn); | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | function stripIndexHtml(url) { | ||||||
|  |   // '/index.html'.length == 11
 | ||||||
|  |   if (url.length > 10 && StringWrapper.substring(url, url.length - 11) == '/index.html') { | ||||||
|  |     return StringWrapper.substring(url, 0, url.length - 11); | ||||||
|  |   } | ||||||
|  |   return url; | ||||||
|  | } | ||||||
|  | |||||||
							
								
								
									
										85
									
								
								modules/angular2/test/router/location_spec.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										85
									
								
								modules/angular2/test/router/location_spec.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,85 @@ | |||||||
|  | import { | ||||||
|  |   AsyncTestCompleter, | ||||||
|  |   describe, | ||||||
|  |   proxy, | ||||||
|  |   it, iit, | ||||||
|  |   ddescribe, expect, | ||||||
|  |   inject, beforeEach, beforeEachBindings, | ||||||
|  |   SpyObject} from 'angular2/test_lib'; | ||||||
|  | import {IMPLEMENTS} from 'angular2/src/facade/lang'; | ||||||
|  | import {EventEmitter, ObservableWrapper} from 'angular2/src/facade/async'; | ||||||
|  | 
 | ||||||
|  | import {BrowserLocation} from 'angular2/src/router/browser_location'; | ||||||
|  | import {Location} from 'angular2/src/router/location'; | ||||||
|  | 
 | ||||||
|  | export function main() { | ||||||
|  | 
 | ||||||
|  |   describe('Location', () => { | ||||||
|  | 
 | ||||||
|  |     var browserLocation, location; | ||||||
|  | 
 | ||||||
|  |     beforeEach(() => { | ||||||
|  |       browserLocation = new DummyBrowserLocation(); | ||||||
|  |       browserLocation.spy('pushState'); | ||||||
|  |       browserLocation.baseHref = '/my/app'; | ||||||
|  |       location = new Location(browserLocation); | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     it('should normalize urls on navigate', () => { | ||||||
|  |       location.go('/my/app/user/btford'); | ||||||
|  |       expect(browserLocation.spy('pushState')).toHaveBeenCalledWith(null, null, '/user/btford'); | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     it('should remove index.html from base href', () => { | ||||||
|  |       browserLocation.baseHref = '/my/app/index.html'; | ||||||
|  |       location = new Location(browserLocation); | ||||||
|  |       location.go('/my/app/user/btford'); | ||||||
|  |       expect(browserLocation.spy('pushState')).toHaveBeenCalledWith(null, null, '/user/btford'); | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     it('should normalize urls on popstate', inject([AsyncTestCompleter], (async) => { | ||||||
|  |       browserLocation.simulatePopState('/my/app/user/btford'); | ||||||
|  |       location.subscribe((ev) => { | ||||||
|  |         expect(ev['url']).toEqual('/user/btford'); | ||||||
|  |         async.done(); | ||||||
|  |       }) | ||||||
|  |     })); | ||||||
|  | 
 | ||||||
|  |     it('should normalize location path', () => { | ||||||
|  |       browserLocation.internalPath = '/my/app/user/btford'; | ||||||
|  |       expect(location.path()).toEqual('/user/btford'); | ||||||
|  |     }); | ||||||
|  |   }); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | @proxy | ||||||
|  | @IMPLEMENTS(BrowserLocation) | ||||||
|  | class DummyBrowserLocation extends SpyObject { | ||||||
|  |   baseHref; | ||||||
|  |   internalPath; | ||||||
|  |   _subject:EventEmitter; | ||||||
|  |   constructor() { | ||||||
|  |     super(); | ||||||
|  |     this.internalPath = '/'; | ||||||
|  |     this._subject = new EventEmitter(); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   simulatePopState(url) { | ||||||
|  |     this.internalPath = url; | ||||||
|  |     ObservableWrapper.callNext(this._subject, null); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   path() { | ||||||
|  |     return this.internalPath; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   onPopState(fn) { | ||||||
|  |     ObservableWrapper.subscribe(this._subject, fn); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   getBaseHref() { | ||||||
|  |     return this.baseHref; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   noSuchMethod(m){return super.noSuchMethod(m);} | ||||||
|  | } | ||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user