Skip to content

Commit 3932f61

Browse files
feat(ng2.location): Add initial HTML5 pushState support
`provide(UrlStrategy, { useClass: HTML5UrlStrategy })` Closes #2688
1 parent 961c742 commit 3932f61

File tree

3 files changed

+81
-17
lines changed

3 files changed

+81
-17
lines changed

src/ng2.ts

+1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import "./justjs";
99

1010
export * from "./ng2/interface";
1111
export * from "./ng2/providers";
12+
export * from "./ng2/services";
1213
export * from "./ng2/directives";
1314
export * from "./ng2/viewsBuilder";
1415
export * from "./ng2/uiRouterConfig";

src/ng2/providers.ts

+7-4
Original file line numberDiff line numberDiff line change
@@ -60,10 +60,13 @@ import {ng2ViewsBuilder, Ng2ViewConfig} from "./viewsBuilder";
6060
import {Ng2ViewDeclaration} from "./interface";
6161
import {UIRouterConfig} from "./uiRouterConfig";
6262
import {UIRouterGlobals} from "../globals";
63+
import {UrlStrategy, HashUrlStrategy} from "./services";
6364

64-
let uiRouterFactory = (routerConfig: UIRouterConfig) => {
65+
let uiRouterFactory = (routerConfig: UIRouterConfig, urlStrategy: UrlStrategy) => {
6566
let router = new UIRouter();
6667

68+
urlStrategy.init();
69+
6770
router.viewService.viewConfigFactory("ng2", (node: Node, config: Ng2ViewDeclaration) => new Ng2ViewConfig(node, config));
6871
router.stateRegistry.decorator('views', ng2ViewsBuilder);
6972

@@ -93,8 +96,7 @@ let uiRouterFactory = (routerConfig: UIRouterConfig) => {
9396
* ```
9497
*/
9598
export const UIROUTER_PROVIDERS: Provider[] = [
96-
97-
provide(UIRouter, { useFactory: uiRouterFactory, deps: [UIRouterConfig] }),
99+
provide(UIRouter, { useFactory: uiRouterFactory, deps: [UIRouterConfig, UrlStrategy] }),
98100

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

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

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

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

117+
provide(UrlStrategy, { useClass: HashUrlStrategy })
115118
];
116119

src/ng2/services.ts

+73-13
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,50 @@
1+
import {DOM} from "angular2/src/platform/dom/dom_adapter";
12
import {Injectable} from "angular2/core";
2-
import {PlatformLocation, LocationStrategy, PathLocationStrategy} from "angular2/router";
33
import {services} from "../common/coreservices";
44
import {isDefined} from "../common/predicates";
55

6+
const beforeAfterSubstr = char => str => {
7+
if (!str) return ["", ""];
8+
let idx = str.indexOf(char);
9+
if (idx === -1) return [str, ""];
10+
return [str.substr(0, idx), str.substr(idx + 1)];
11+
};
12+
13+
const splitHash = beforeAfterSubstr("#");
14+
const trimHashVal = (str) => str ? str.replace(/^#/, "") : "";
15+
16+
17+
export abstract class UrlStrategy {
18+
abstract init();
19+
}
20+
621
@Injectable()
7-
export class UiLocationStrategy {
22+
export class HashUrlStrategy extends UrlStrategy {
823
private hashPrefix: string = '!';
924

10-
constructor(private locationStrategy: LocationStrategy, private _platformLocation: PlatformLocation) {
11-
}
12-
1325
init() {
1426
let loc = <any> services.location;
27+
let location: Location = DOM.getLocation();
1528

16-
loc.hash = () => this._platformLocation.hash;
17-
loc.path = this.locationStrategy.path;
29+
loc.hash = () => splitHash(trimHashVal(location.hash))[1];
30+
loc.path = () => splitHash(trimHashVal(location.hash))[0];
1831
loc.search = () => location.search;
1932
loc.url = (url) => {
20-
if(url) {
33+
if(isDefined(url)) {
2134
location.hash = url;
2235
}
2336
return loc.path();
2437
};
25-
loc.replace = this.locationStrategy.replaceState;
26-
// should we use location.onPopState instead ? https://github.com/angular/angular/blob/d272f96e23f379e1b565435b3af010138e710ab9/modules/angular2/src/router/location/hash_location_strategy.ts#L61
27-
loc.onChange = this._platformLocation.onHashChange;
38+
loc.replace = () => { console.log(new Error('$location.replace() not impl'))};
39+
loc.onChange = cb => window.addEventListener("hashchange", cb, false);
2840

2941
let locCfg = <any> services.locationConfig;
3042

3143
locCfg.port = () => location.port;
3244
locCfg.protocol = () => location.protocol;
3345
locCfg.host = () => location.host;
34-
locCfg.baseHref = this.locationStrategy.getBaseHref;
35-
locCfg.html5Mode = () => this.locationStrategy instanceof PathLocationStrategy; // does it work ?
46+
locCfg.baseHref = () => null;
47+
locCfg.html5Mode = () => false;
3648
locCfg.hashPrefix = (newprefix: string): string => {
3749
if(isDefined(newprefix)) {
3850
this.hashPrefix = newprefix;
@@ -41,3 +53,51 @@ export class UiLocationStrategy {
4153
};
4254
}
4355
}
56+
57+
58+
@Injectable()
59+
export class HTML5UrlStrategy extends UrlStrategy {
60+
baseHref: string;
61+
62+
init() {
63+
let loc = <any> services.location;
64+
let location: Location = DOM.getLocation();
65+
let history: History = DOM.getHistory();
66+
this.baseHref = DOM.getBaseHref() || "";
67+
68+
loc.hash = () =>
69+
trimHashVal(location.hash);
70+
loc.path = () => {
71+
let path = location.pathname;
72+
let idx = path.indexOf(this.baseHref);
73+
if (idx !== 0) throw new Error(`current url: ${path} does not start with <base> tag ${this.baseHref}`);
74+
return path.substr(this.baseHref.length);
75+
};
76+
77+
loc.search = () =>
78+
location.search;
79+
loc.url = (url) => {
80+
if(isDefined(url) && url !== loc.url()) {
81+
history.pushState(null, null, this.baseHref + url);
82+
}
83+
let hash = loc.hash();
84+
return loc.path() + (hash ? "#" + hash : "");
85+
};
86+
loc.replace = () => { console.log(new Error('$location.replace() not impl'))};
87+
loc.onChange = cb => window.addEventListener("popstate", cb, false);
88+
89+
let locCfg = <any> services.locationConfig;
90+
91+
locCfg.port = () => location.port;
92+
locCfg.protocol = () => location.protocol;
93+
locCfg.host = () => location.host;
94+
locCfg.baseHref = (baseHref?) => {
95+
if (isDefined(baseHref)) {
96+
this.baseHref = baseHref;
97+
}
98+
return this.baseHref
99+
};
100+
locCfg.html5Mode = () => true;
101+
locCfg.hashPrefix = () => null;
102+
}
103+
}

0 commit comments

Comments
 (0)