Skip to content

Commit

Permalink
feat(ng2.location): Add initial HTML5 pushState support
Browse files Browse the repository at this point in the history
`provide(UrlStrategy, { useClass: HTML5UrlStrategy })`
Closes #2688
  • Loading branch information
christopherthielen committed May 9, 2016
1 parent ad93755 commit 6d7257b
Show file tree
Hide file tree
Showing 3 changed files with 81 additions and 17 deletions.
1 change: 1 addition & 0 deletions src/ng2.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import "./justjs";

export * from "./ng2/interface";
export * from "./ng2/providers";
export * from "./ng2/services";
export * from "./ng2/directives";
export * from "./ng2/viewsBuilder";
export * from "./ng2/uiRouterConfig";
Expand Down
11 changes: 7 additions & 4 deletions src/ng2/providers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,10 +60,13 @@ import {ng2ViewsBuilder, Ng2ViewConfig} from "./viewsBuilder";
import {Ng2ViewDeclaration} from "./interface";
import {UIRouterConfig} from "./uiRouterConfig";
import {UIRouterGlobals} from "../globals";
import {UrlStrategy, HashUrlStrategy} from "./services";

let uiRouterFactory = (routerConfig: UIRouterConfig) => {
let uiRouterFactory = (routerConfig: UIRouterConfig, urlStrategy: UrlStrategy) => {
let router = new UIRouter();

urlStrategy.init();

router.viewService.viewConfigFactory("ng2", (node: Node, config: Ng2ViewDeclaration) => new Ng2ViewConfig(node, config));
router.stateRegistry.decorator('views', ng2ViewsBuilder);

Expand Down Expand Up @@ -93,8 +96,7 @@ let uiRouterFactory = (routerConfig: UIRouterConfig) => {
* ```
*/
export const UIROUTER_PROVIDERS: Provider[] = [

provide(UIRouter, { useFactory: uiRouterFactory, deps: [UIRouterConfig] }),
provide(UIRouter, { useFactory: uiRouterFactory, deps: [UIRouterConfig, UrlStrategy] }),

provide(StateService, { useFactory: (r: UIRouter) => { return r.stateService; }, deps: [UIRouter]}),

Expand All @@ -110,7 +112,8 @@ export const UIROUTER_PROVIDERS: Provider[] = [

provide(UIRouterGlobals, { useFactory: (r: UIRouter) => { return r.globals; }, deps: [UIRouter]}),

provide(UiView.PARENT_INJECT, { useFactory: (r: StateRegistry) => { return { fqn: null, context: r.root() } }, deps: [StateRegistry]} )
provide(UiView.PARENT_INJECT, { useFactory: (r: StateRegistry) => { return { fqn: null, context: r.root() } }, deps: [StateRegistry]} ),

provide(UrlStrategy, { useClass: HashUrlStrategy })
];

86 changes: 73 additions & 13 deletions src/ng2/services.ts
Original file line number Diff line number Diff line change
@@ -1,38 +1,50 @@
import {DOM} from "angular2/src/platform/dom/dom_adapter";
import {Injectable} from "angular2/core";
import {PlatformLocation, LocationStrategy, PathLocationStrategy} from "angular2/router";
import {services} from "../common/coreservices";
import {isDefined} from "../common/predicates";

const beforeAfterSubstr = char => str => {
if (!str) return ["", ""];
let idx = str.indexOf(char);
if (idx === -1) return [str, ""];
return [str.substr(0, idx), str.substr(idx + 1)];
};

const splitHash = beforeAfterSubstr("#");
const trimHashVal = (str) => str ? str.replace(/^#/, "") : "";


export abstract class UrlStrategy {
abstract init();
}

@Injectable()
export class UiLocationStrategy {
export class HashUrlStrategy extends UrlStrategy {
private hashPrefix: string = '!';

constructor(private locationStrategy: LocationStrategy, private _platformLocation: PlatformLocation) {
}

init() {
let loc = <any> services.location;
let location: Location = DOM.getLocation();

loc.hash = () => this._platformLocation.hash;
loc.path = this.locationStrategy.path;
loc.hash = () => splitHash(trimHashVal(location.hash))[1];
loc.path = () => splitHash(trimHashVal(location.hash))[0];
loc.search = () => location.search;
loc.url = (url) => {
if(url) {
if(isDefined(url)) {
location.hash = url;
}
return loc.path();
};
loc.replace = this.locationStrategy.replaceState;
// should we use location.onPopState instead ? https://github.com/angular/angular/blob/d272f96e23f379e1b565435b3af010138e710ab9/modules/angular2/src/router/location/hash_location_strategy.ts#L61
loc.onChange = this._platformLocation.onHashChange;
loc.replace = () => { console.log(new Error('$location.replace() not impl'))};
loc.onChange = cb => window.addEventListener("hashchange", cb, false);

let locCfg = <any> services.locationConfig;

locCfg.port = () => location.port;
locCfg.protocol = () => location.protocol;
locCfg.host = () => location.host;
locCfg.baseHref = this.locationStrategy.getBaseHref;
locCfg.html5Mode = () => this.locationStrategy instanceof PathLocationStrategy; // does it work ?
locCfg.baseHref = () => null;
locCfg.html5Mode = () => false;
locCfg.hashPrefix = (newprefix: string): string => {
if(isDefined(newprefix)) {
this.hashPrefix = newprefix;
Expand All @@ -41,3 +53,51 @@ export class UiLocationStrategy {
};
}
}


@Injectable()
export class HTML5UrlStrategy extends UrlStrategy {
baseHref: string;

init() {
let loc = <any> services.location;
let location: Location = DOM.getLocation();
let history: History = DOM.getHistory();
this.baseHref = DOM.getBaseHref() || "";

loc.hash = () =>
trimHashVal(location.hash);
loc.path = () => {
let path = location.pathname;
let idx = path.indexOf(this.baseHref);
if (idx !== 0) throw new Error(`current url: ${path} does not start with <base> tag ${this.baseHref}`);
return path.substr(this.baseHref.length);
};

loc.search = () =>
location.search;
loc.url = (url) => {
if(isDefined(url) && url !== loc.url()) {
history.pushState(null, null, this.baseHref + url);
}
let hash = loc.hash();
return loc.path() + (hash ? "#" + hash : "");
};
loc.replace = () => { console.log(new Error('$location.replace() not impl'))};
loc.onChange = cb => window.addEventListener("popstate", cb, false);

let locCfg = <any> services.locationConfig;

locCfg.port = () => location.port;
locCfg.protocol = () => location.protocol;
locCfg.host = () => location.host;
locCfg.baseHref = (baseHref?) => {
if (isDefined(baseHref)) {
this.baseHref = baseHref;
}
return this.baseHref
};
locCfg.html5Mode = () => true;
locCfg.hashPrefix = () => null;
}
}

0 comments on commit 6d7257b

Please sign in to comment.