fix(router): strip base href from URLs when navigating
This commit is contained in:
parent
84dc6ae76b
commit
853d1de6ec
|
@ -13,6 +13,7 @@ export {RouteParams} from './src/router/instruction';
|
|||
export * from './src/router/route_config_annotation';
|
||||
export * from './src/router/route_config_decorator';
|
||||
|
||||
import {BrowserLocation} from './src/router/browser_location';
|
||||
import {Router, RootRouter} from './src/router/router';
|
||||
import {RouteRegistry} from './src/router/route_registry';
|
||||
import {Pipeline} from './src/router/pipeline';
|
||||
|
@ -23,6 +24,7 @@ import {bind} from './di';
|
|||
export var routerInjectables:List = [
|
||||
RouteRegistry,
|
||||
Pipeline,
|
||||
BrowserLocation,
|
||||
Location,
|
||||
bind(Router).toFactory((registry, pipeline, location, meta) => {
|
||||
return new RootRouter(registry, pipeline, location, meta.type);
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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';
|
||||
|
||||
export class Location {
|
||||
_location;
|
||||
_subject:EventEmitter;
|
||||
_history;
|
||||
constructor() {
|
||||
_browserLocation:BrowserLocation;
|
||||
_baseHref:string;
|
||||
constructor(browserLocation:BrowserLocation) {
|
||||
this._subject = new EventEmitter();
|
||||
this._location = DOM.getLocation();
|
||||
this._history = DOM.getHistory();
|
||||
DOM.getGlobalEventTarget('window').addEventListener('popstate', (_) => this._onPopState(_), false);
|
||||
this._browserLocation = browserLocation;
|
||||
this._baseHref = stripIndexHtml(this._browserLocation.getBaseHref());
|
||||
this._browserLocation.onPopState((_) => this._onPopState(_));
|
||||
}
|
||||
|
||||
_onPopState(_) {
|
||||
ObservableWrapper.callNext(this._subject, {
|
||||
'url': this._location.pathname
|
||||
'url': this.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) {
|
||||
this._history.pushState(null, null, url);
|
||||
url = this._stripBaseHref(url);
|
||||
this._browserLocation.pushState(null, null, url);
|
||||
}
|
||||
|
||||
forward() {
|
||||
this._history.forward();
|
||||
this._browserLocation.forward();
|
||||
}
|
||||
|
||||
back() {
|
||||
this._history.back()
|
||||
this._browserLocation.back();
|
||||
}
|
||||
|
||||
subscribe(onNext, onThrow = null, onReturn = null) {
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -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…
Reference in New Issue