feat(router): add support for APP_BASE_HREF to HashLocationStrategy
Closes #4935 Closes #5368 Closes #5451
This commit is contained in:
@ -1,7 +1,13 @@
|
||||
import {DOM} from 'angular2/src/platform/dom/dom_adapter';
|
||||
import {Injectable} from 'angular2/core';
|
||||
import {LocationStrategy, normalizeQueryParams} from './location_strategy';
|
||||
import {EventListener, History, Location} from 'angular2/src/facade/browser';
|
||||
import {Injectable, Inject, Optional} from 'angular2/core';
|
||||
import {
|
||||
LocationStrategy,
|
||||
joinWithSlash,
|
||||
APP_BASE_HREF,
|
||||
normalizeQueryParams
|
||||
} from './location_strategy';
|
||||
import {EventListener} from 'angular2/src/facade/browser';
|
||||
import {isPresent} from 'angular2/src/facade/lang';
|
||||
import {PlatformLocation} from './platform_location';
|
||||
|
||||
/**
|
||||
* `HashLocationStrategy` is a {@link LocationStrategy} used to configure the
|
||||
@ -43,48 +49,45 @@ import {EventListener, History, Location} from 'angular2/src/facade/browser';
|
||||
*/
|
||||
@Injectable()
|
||||
export class HashLocationStrategy extends LocationStrategy {
|
||||
private _location: Location;
|
||||
private _history: History;
|
||||
|
||||
constructor() {
|
||||
private _baseHref: string = '';
|
||||
constructor(private _platformLocation: PlatformLocation,
|
||||
@Optional() @Inject(APP_BASE_HREF) _baseHref?: string) {
|
||||
super();
|
||||
this._location = DOM.getLocation();
|
||||
this._history = DOM.getHistory();
|
||||
if (isPresent(_baseHref)) {
|
||||
this._baseHref = _baseHref;
|
||||
}
|
||||
}
|
||||
|
||||
onPopState(fn: EventListener): void {
|
||||
DOM.getGlobalEventTarget('window').addEventListener('popstate', fn, false);
|
||||
}
|
||||
onPopState(fn: EventListener): void { this._platformLocation.onPopState(fn); }
|
||||
|
||||
getBaseHref(): string { return ''; }
|
||||
getBaseHref(): string { return this._baseHref; }
|
||||
|
||||
path(): string {
|
||||
// the hash value is always prefixed with a `#`
|
||||
// and if it is empty then it will stay empty
|
||||
var path = this._location.hash;
|
||||
var path = this._platformLocation.hash;
|
||||
|
||||
// Dart will complain if a call to substring is
|
||||
// executed with a position value that extends the
|
||||
// length of string.
|
||||
return (path.length > 0 ? path.substring(1) : path) +
|
||||
normalizeQueryParams(this._location.search);
|
||||
normalizeQueryParams(this._platformLocation.search);
|
||||
}
|
||||
|
||||
prepareExternalUrl(internal: string): string {
|
||||
return internal.length > 0 ? ('#' + internal) : internal;
|
||||
var url = joinWithSlash(this._baseHref, internal);
|
||||
return url.length > 0 ? ('#' + url) : url;
|
||||
}
|
||||
|
||||
pushState(state: any, title: string, path: string, queryParams: string) {
|
||||
var url = path + normalizeQueryParams(queryParams);
|
||||
var url = this.prepareExternalUrl(path + normalizeQueryParams(queryParams));
|
||||
if (url.length == 0) {
|
||||
url = this._location.pathname;
|
||||
} else {
|
||||
url = this.prepareExternalUrl(url);
|
||||
url = this._platformLocation.pathname;
|
||||
}
|
||||
this._history.pushState(state, title, url);
|
||||
this._platformLocation.pushState(state, title, url);
|
||||
}
|
||||
|
||||
forward(): void { this._history.forward(); }
|
||||
forward(): void { this._platformLocation.forward(); }
|
||||
|
||||
back(): void { this._history.back(); }
|
||||
back(): void { this._platformLocation.back(); }
|
||||
}
|
||||
|
@ -62,3 +62,26 @@ export const APP_BASE_HREF: OpaqueToken = CONST_EXPR(new OpaqueToken('appBaseHre
|
||||
export function normalizeQueryParams(params: string): string {
|
||||
return (params.length > 0 && params.substring(0, 1) != '?') ? ('?' + params) : params;
|
||||
}
|
||||
|
||||
export function joinWithSlash(start: string, end: string): string {
|
||||
if (start.length == 0) {
|
||||
return end;
|
||||
}
|
||||
if (end.length == 0) {
|
||||
return start;
|
||||
}
|
||||
var slashes = 0;
|
||||
if (start.endsWith('/')) {
|
||||
slashes++;
|
||||
}
|
||||
if (end.startsWith('/')) {
|
||||
slashes++;
|
||||
}
|
||||
if (slashes == 2) {
|
||||
return start + end.substring(1);
|
||||
}
|
||||
if (slashes == 1) {
|
||||
return start + end;
|
||||
}
|
||||
return start + '/' + end;
|
||||
}
|
||||
|
@ -1,9 +1,14 @@
|
||||
import {DOM} from 'angular2/src/platform/dom/dom_adapter';
|
||||
import {Injectable, Inject} from 'angular2/core';
|
||||
import {Injectable, Inject, Optional} from 'angular2/core';
|
||||
import {EventListener, History, Location} from 'angular2/src/facade/browser';
|
||||
import {isBlank} from 'angular2/src/facade/lang';
|
||||
import {BaseException} from 'angular2/src/facade/exceptions';
|
||||
import {LocationStrategy, APP_BASE_HREF, normalizeQueryParams} from './location_strategy';
|
||||
import {
|
||||
LocationStrategy,
|
||||
APP_BASE_HREF,
|
||||
normalizeQueryParams,
|
||||
joinWithSlash
|
||||
} from './location_strategy';
|
||||
import {PlatformLocation} from './platform_location';
|
||||
|
||||
/**
|
||||
* `PathLocationStrategy` is a {@link LocationStrategy} used to configure the
|
||||
@ -52,15 +57,14 @@ import {LocationStrategy, APP_BASE_HREF, normalizeQueryParams} from './location_
|
||||
*/
|
||||
@Injectable()
|
||||
export class PathLocationStrategy extends LocationStrategy {
|
||||
private _location: Location;
|
||||
private _history: History;
|
||||
private _baseHref: string;
|
||||
|
||||
constructor(@Inject(APP_BASE_HREF) href?: string) {
|
||||
constructor(private _platformLocation: PlatformLocation,
|
||||
@Optional() @Inject(APP_BASE_HREF) href?: string) {
|
||||
super();
|
||||
|
||||
if (isBlank(href)) {
|
||||
href = DOM.getBaseHref();
|
||||
href = this._platformLocation.getBaseHrefFromDOM();
|
||||
}
|
||||
|
||||
if (isBlank(href)) {
|
||||
@ -68,33 +72,28 @@ export class PathLocationStrategy extends LocationStrategy {
|
||||
`No base href set. Please provide a value for the APP_BASE_HREF token or add a base element to the document.`);
|
||||
}
|
||||
|
||||
this._location = DOM.getLocation();
|
||||
this._history = DOM.getHistory();
|
||||
this._baseHref = href;
|
||||
}
|
||||
|
||||
onPopState(fn: EventListener): void {
|
||||
DOM.getGlobalEventTarget('window').addEventListener('popstate', fn, false);
|
||||
DOM.getGlobalEventTarget('window').addEventListener('hashchange', fn, false);
|
||||
this._platformLocation.onPopState(fn);
|
||||
this._platformLocation.onHashChange(fn);
|
||||
}
|
||||
|
||||
getBaseHref(): string { return this._baseHref; }
|
||||
|
||||
prepareExternalUrl(internal: string): string {
|
||||
if (internal.startsWith('/') && this._baseHref.endsWith('/')) {
|
||||
return this._baseHref + internal.substring(1);
|
||||
}
|
||||
return this._baseHref + internal;
|
||||
}
|
||||
prepareExternalUrl(internal: string): string { return joinWithSlash(this._baseHref, internal); }
|
||||
|
||||
path(): string { return this._location.pathname + normalizeQueryParams(this._location.search); }
|
||||
path(): string {
|
||||
return this._platformLocation.pathname + normalizeQueryParams(this._platformLocation.search);
|
||||
}
|
||||
|
||||
pushState(state: any, title: string, url: string, queryParams: string) {
|
||||
var externalUrl = this.prepareExternalUrl(url + normalizeQueryParams(queryParams));
|
||||
this._history.pushState(state, title, externalUrl);
|
||||
this._platformLocation.pushState(state, title, externalUrl);
|
||||
}
|
||||
|
||||
forward(): void { this._history.forward(); }
|
||||
forward(): void { this._platformLocation.forward(); }
|
||||
|
||||
back(): void { this._history.back(); }
|
||||
back(): void { this._platformLocation.back(); }
|
||||
}
|
||||
|
46
modules/angular2/src/router/platform_location.ts
Normal file
46
modules/angular2/src/router/platform_location.ts
Normal file
@ -0,0 +1,46 @@
|
||||
import {DOM} from 'angular2/src/platform/dom/dom_adapter';
|
||||
import {Injectable} from 'angular2/core';
|
||||
import {EventListener, History, Location} from 'angular2/src/facade/browser';
|
||||
|
||||
/**
|
||||
* `PlatformLocation` encapsulates all of the direct calls to platform APIs.
|
||||
* This class should not be used directly by an application developer. Instead, use
|
||||
* {@link Location}.
|
||||
*/
|
||||
@Injectable()
|
||||
export class PlatformLocation {
|
||||
private _location: Location;
|
||||
private _history: History;
|
||||
|
||||
constructor() { this._init(); }
|
||||
|
||||
// This is moved to its own method so that `MockPlatformLocationStrategy` can overwrite it
|
||||
/** @internal */
|
||||
_init() {
|
||||
this._location = DOM.getLocation();
|
||||
this._history = DOM.getHistory();
|
||||
}
|
||||
|
||||
getBaseHrefFromDOM(): string { return DOM.getBaseHref(); }
|
||||
|
||||
onPopState(fn: EventListener): void {
|
||||
DOM.getGlobalEventTarget('window').addEventListener('popstate', fn, false);
|
||||
}
|
||||
|
||||
onHashChange(fn: EventListener): void {
|
||||
DOM.getGlobalEventTarget('window').addEventListener('hashchange', fn, false);
|
||||
}
|
||||
|
||||
get pathname(): string { return this._location.pathname; }
|
||||
get search(): string { return this._location.search; }
|
||||
get hash(): string { return this._location.hash; }
|
||||
set pathname(newPath: string) { this._location.pathname = newPath; }
|
||||
|
||||
pushState(state: any, title: string, url: string): void {
|
||||
this._history.pushState(state, title, url);
|
||||
}
|
||||
|
||||
forward(): void { this._history.forward(); }
|
||||
|
||||
back(): void { this._history.back(); }
|
||||
}
|
Reference in New Issue
Block a user