Skip to content

Commit

Permalink
feat(ng2.urlRouter): HTML5 PushState support
Browse files Browse the repository at this point in the history
- Wire up HTML5 PushState and HashBang modes using Hash and PathLocationStrategy from angular2 rc.0+
Closes #2688
  • Loading branch information
ocombe authored and christopherthielen committed May 12, 2016
1 parent 79d4fd7 commit 9842fb7
Show file tree
Hide file tree
Showing 5 changed files with 90 additions and 4 deletions.
3 changes: 2 additions & 1 deletion packages/ng2/webpack.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ module.exports = {
},

externals: {
"@angular/core": { root: '@angular/core', amd: '@angular/core', commonjs2: '@angular/core', commonjs: '@angular/core' }
"@angular/core": { root: '@angular/core', amd: '@angular/core', commonjs2: '@angular/core', commonjs: '@angular/core' },
"@angular/common": { root: '@angular/common', amd: '@angular/common', commonjs2: '@angular/common', commonjs: '@angular/common' }
}
};
7 changes: 7 additions & 0 deletions src/common/strings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,3 +89,10 @@ export function stringify(o) {
return JSON.stringify(o, (key, val) => format(val)).replace(/\\"/g, '"');
}

/** Returns a function that splits a string on a character or substring */
export 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)];
};
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/location";
export * from "./ng2/directives";
export * from "./ng2/viewsBuilder";
export * from "./ng2/uiRouterConfig";
Expand Down
74 changes: 74 additions & 0 deletions src/ng2/location.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import {HashLocationStrategy, PlatformLocation, LocationStrategy} from "@angular/common";
import {Injectable} from "@angular/core";

import {services} from "../common/coreservices";
import {isDefined} from "../common/predicates";
import {applyPairs} from "../common/common";
import {beforeAfterSubstr} from "../common/strings";

const splitOnHash = beforeAfterSubstr("#");
const splitOnEquals = beforeAfterSubstr("=");
const splitOnQuestionMark = beforeAfterSubstr("?");

@Injectable()
export class UIRouterLocation {
isHashBang: boolean;
hashPrefix: string = "";

constructor(
public locationStrategy: LocationStrategy,
public platformLocation: PlatformLocation
) {
this.isHashBang = locationStrategy instanceof HashLocationStrategy;
}

init() {
let loc = <any> services.location;
let locSt = this.locationStrategy;

if (this.isHashBang) {
loc.hash = () =>
splitOnHash(splitOnHash(this.platformLocation.hash)[1])[1];
} else {
loc.hash = () =>
splitOnHash(this.platformLocation.hash)[1];
}

loc.path = () =>
splitOnHash(splitOnQuestionMark(locSt.path())[0])[0];

loc.search = () => {
let queryString = splitOnHash(splitOnQuestionMark(locSt.path())[1])[0];
return queryString.split("&").map(kv => splitOnEquals(kv)).reduce(applyPairs, {});
};

loc.url = (url) => {
if(isDefined(url)) {
let split = splitOnQuestionMark(url);
locSt.pushState(null, null, split[0], split[1]);
}
return locSt.path()
};

loc.replace = () => {
console.log(new Error('$location.replace() not impl'))
};

loc.onChange = cb => locSt.onPopState(cb);

let locCfg = <any> services.locationConfig;

locCfg.port = () => null;
locCfg.protocol = () => null;
locCfg.host = () => null;
locCfg.baseHref = () => locSt.getBaseHref();
locCfg.html5Mode = () => !this.isHashBang;
locCfg.hashPrefix = (newprefix: string): string => {
if(isDefined(newprefix)) {
this.hashPrefix = newprefix;
}
return this.hashPrefix;
};
}
}

9 changes: 6 additions & 3 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 {UIRouterLocation} from "./location";

let uiRouterFactory = (routerConfig: UIRouterConfig) => {
let uiRouterFactory = (routerConfig: UIRouterConfig, location: UIRouterLocation) => {
let router = new UIRouter();

location.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,9 @@ let uiRouterFactory = (routerConfig: UIRouterConfig) => {
* ```
*/
export const UIROUTER_PROVIDERS: Provider[] = [
provide(UIRouter, { useFactory: uiRouterFactory, deps: [UIRouterConfig, UIRouterLocation] }),

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

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

Expand All @@ -111,6 +115,5 @@ 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]} )

];

0 comments on commit 9842fb7

Please sign in to comment.