Skip to content

Commit 029fb00

Browse files
BREAKING CHANGE: (CoreServices) Move location and locationConfig from services to UIRouter.locationService and UIRouter.locationConfig.
The core `services` object is a mutable object which each framework was monkey patching. This change removes the requirement to monkey patch a global mutable object. Instead, framework implementors should pass the `LocationServices` and `LocationConfig` implementations into the `UIRouter` constructor. ### End Users End users who were accessing `services.location` or `services.locationConfig` should access these off the `UIRouter` instance instead.
1 parent 9d316a7 commit 029fb00

9 files changed

+34
-36
lines changed

src/router.ts

+10-11
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,7 @@
33
* @module core
44
*/ /** */
55
import { UrlMatcherFactory } from "./url/urlMatcherFactory";
6-
import { UrlRouterProvider } from "./url/urlRouter";
7-
import { UrlRouter } from "./url/urlRouter";
6+
import { UrlRouterProvider, UrlRouter } from "./url/urlRouter";
87
import { TransitionService } from "./transition/transitionService";
98
import { ViewService } from "./view/view";
109
import { StateRegistry } from "./state/stateRegistry";
@@ -14,7 +13,7 @@ import { UIRouterPlugin, Disposable } from "./interface";
1413
import { values, removeFrom } from "./common/common";
1514
import { isFunction } from "./common/predicates";
1615
import { UrlService } from "./url/urlService";
17-
import { services, LocationServices, LocationConfig } from "./common/coreservices";
16+
import { LocationServices, LocationConfig } from "./common/coreservices";
1817

1918
/** @hidden */
2019
let _routerInstance = 0;
@@ -50,13 +49,7 @@ export class UIRouter {
5049

5150
stateService = new StateService(this);
5251

53-
get urlService(): LocationServices {
54-
return services.location;
55-
}
56-
57-
get urlConfig(): LocationConfig {
58-
return services.locationConfig;
59-
}
52+
urlService: UrlService = new UrlService(this);
6053

6154
private _disposables: Disposable[] = [];
6255

@@ -89,7 +82,11 @@ export class UIRouter {
8982
});
9083
}
9184

92-
constructor() {
85+
constructor(
86+
public locationService: LocationServices = UrlService.locationServiceStub,
87+
public locationConfig: LocationConfig = UrlService.locationConfigStub
88+
) {
89+
9390
this.viewService._pluginapi._rootViewContext(this.stateRegistry.root());
9491
this.globals.$current = this.stateRegistry.root();
9592
this.globals.current = this.globals.$current.self;
@@ -98,6 +95,8 @@ export class UIRouter {
9895
this.disposable(this.urlRouterProvider);
9996
this.disposable(this.urlRouter);
10097
this.disposable(this.stateRegistry);
98+
this.disposable(locationService);
99+
this.disposable(locationConfig);
101100
}
102101

103102
/** @hidden */

src/state/stateService.ts

+4-3
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@
22
* @coreapi
33
* @module state
44
*/ /** */
5-
import { extend, defaults, silentRejection, silenceUncaughtInPromise, removeFrom, noop } from "../common/common";
5+
import {
6+
extend, defaults, silentRejection, silenceUncaughtInPromise, removeFrom, noop, createProxyFunctions
7+
} from "../common/common";
68
import {isDefined, isObject, isString} from "../common/predicates";
79
import {Queue} from "../common/queue";
810
import {services} from "../common/coreservices";
@@ -24,7 +26,6 @@ import {ParamsOrArray} from "../params/interface";
2426
import {Param} from "../params/param";
2527
import {Glob} from "../common/glob";
2628
import {HrefOptions} from "./interface";
27-
import {bindFunctions} from "../common/common";
2829
import {Globals} from "../globals";
2930
import {UIRouter} from "../router";
3031
import {UIInjector} from "../interface";
@@ -74,7 +75,7 @@ export class StateService {
7475
constructor(private router: UIRouter) {
7576
let getters = ['current', '$current', 'params', 'transition'];
7677
let boundFns = Object.keys(StateService.prototype).filter(key => getters.indexOf(key) === -1);
77-
bindFunctions(StateService.prototype, this, this, boundFns);
78+
createProxyFunctions(StateService.prototype, this, this, boundFns);
7879
}
7980

8081
/** @internalapi */

src/transition/transitionService.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ import { registerLazyLoadHook } from "../hooks/lazyLoad";
2222
import { TransitionEventType } from "./transitionEventType";
2323
import { TransitionHook, GetResultHandler, GetErrorHandler } from "./transitionHook";
2424
import { isDefined } from "../common/predicates";
25-
import { removeFrom, values, bindFunctions } from "../common/common";
25+
import { removeFrom, values, createProxyFunctions } from "../common/common";
2626
import { Disposable } from "../interface"; // has or is using
2727

2828
/**
@@ -149,7 +149,7 @@ export class TransitionService implements IHookRegistry, Disposable {
149149
constructor(private _router: UIRouter) {
150150
this.$view = _router.viewService;
151151
this._deregisterHookFns = <any> {};
152-
this._pluginapi = <TransitionServicePluginAPI> bindFunctions(this, {}, this, [
152+
this._pluginapi = <TransitionServicePluginAPI> createProxyFunctions(this, {}, this, [
153153
'_definePathType',
154154
'_defineEvent',
155155
'_getPathTypes',

src/url/urlRouter.ts

+8-9
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
* @coreapi
33
* @module url
44
*/ /** for typedoc */
5-
import { extend, bindFunctions, IInjectable, removeFrom } from "../common/common";
5+
import { extend, IInjectable, removeFrom, createProxyFunctions } from "../common/common";
66
import { isFunction, isString, isDefined, isArray } from "../common/predicates";
77
import { UrlMatcher } from "./urlMatcher";
88
import { services, $InjectorLike, LocationServices } from "../common/coreservices";
@@ -260,10 +260,10 @@ export class UrlRouterProvider implements Disposable {
260260
* });
261261
* ```
262262
*
263-
* @param defer Indicates whether to defer location change interception. Passing
264-
* no parameter is equivalent to `true`.
263+
* @param defer Indicates whether to defer location change interception.
264+
* Passing no parameter is equivalent to `true`.
265265
*/
266-
deferIntercept(defer) {
266+
deferIntercept(defer?: boolean) {
267267
if (defer === undefined) defer = true;
268268
this.interceptDeferred = defer;
269269
};
@@ -277,7 +277,7 @@ export class UrlRouter implements Disposable {
277277

278278
/** @hidden */
279279
constructor(public router: UIRouter) {
280-
bindFunctions(UrlRouter.prototype, this, this);
280+
createProxyFunctions(UrlRouter.prototype, this, this);
281281
}
282282

283283
/** @internalapi */
@@ -398,11 +398,10 @@ export class UrlRouter implements Disposable {
398398
let url = urlMatcher.format(params);
399399
options = options || { absolute: false };
400400

401-
let cfg = this.router.urlConfig;
402-
let loc = this.router.urlService;
403-
let isHtml5 = loc.html5Mode();
401+
let cfg = this.router.urlService.config;
402+
let isHtml5 = cfg.html5Mode();
404403
if (!isHtml5 && url !== null) {
405-
url = "#" + loc.hashPrefix() + url;
404+
url = "#" + cfg.hashPrefix() + url;
406405
}
407406
url = appendBasePath(url, isHtml5, options.absolute, cfg.baseHref());
408407

src/vanilla/utils.ts

+4-7
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
import {isArray} from "../common/index";
66
import { LocationServices, LocationConfig, services } from "../common/coreservices";
77
import { UIRouter } from "../router";
8-
import { extend, bindFunctions } from "../common/common";
98

109
const beforeAfterSubstr = (char: string) => (str: string): string[] => {
1110
if (!str) return ["", ""];
@@ -35,21 +34,19 @@ export const getParams = (queryString: string): any =>
3534

3635
export function locationPluginFactory(
3736
name: string,
37+
isHtml5: boolean,
3838
serviceClass: { new(router?: UIRouter): LocationServices },
39-
configurationClass: { new(router?: UIRouter): LocationConfig }
39+
configurationClass: { new(router?: UIRouter, isHtml5?: boolean): LocationConfig }
4040
) {
4141
return function(router: UIRouter) {
42-
let service = new serviceClass(router);
43-
let configuration = new configurationClass(router);
42+
let service = router.locationService = new serviceClass(router);
43+
let configuration = router.locationConfig = new configurationClass(router, isHtml5);
4444

4545
function dispose(router: UIRouter) {
4646
router.dispose(service);
4747
router.dispose(configuration);
4848
}
4949

50-
bindFunctions(serviceClass.prototype, services.location, service);
51-
bindFunctions(configurationClass.prototype, services.locationConfig, configuration);
52-
5350
return { name, service, configuration, dispose };
5451
};
5552
}

test/stateRegistrySpec.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { UIRouter } from "../src/router";
22
import { tree2Array } from "./_testUtils";
33
import { StateRegistry } from "../src/state/stateRegistry";
4-
import { services } from "../src/common/coreservices";
4+
import { TestingPlugin } from "./_testingPlugin";
55

66
let router: UIRouter = null;
77
let registry: StateRegistry = null;
@@ -20,6 +20,7 @@ let statetree = {
2020
describe("StateRegistry", () => {
2121
beforeEach(() => {
2222
router = new UIRouter();
23+
router.plugin(TestingPlugin);
2324
registry = router.stateRegistry;
2425
tree2Array(statetree, true).forEach(state => registry.register(state));
2526
registry.stateQueue.autoFlush(router.stateService);

test/stateServiceSpec.ts

+1
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ describe('stateService', function () {
2929
afterEach(() => router.dispose());
3030

3131
beforeEach(() => {
32+
jasmine.DEFAULT_TIMEOUT_INTERVAL = 1000;
3233
router = new UIRouter();
3334
router.plugin(TestingPlugin);
3435

test/vanilla.browserHistorySpec.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ describe('browserHistory implementation', () => {
3939

4040
it('uses history.pushState when setting a url', () => {
4141
let service = mockHistoryObject();
42-
expect(router.urlService.html5Mode()).toBe(true);
42+
expect(router.urlService.config.html5Mode()).toBe(true);
4343
let stub = spyOn(service._history, 'pushState');
4444
router.urlRouter.push(makeMatcher('/hello/:name'), { name: 'world' }, {});
4545
expect(stub.calls.first().args[2]).toBe('/hello/world');
@@ -53,7 +53,7 @@ describe('browserHistory implementation', () => {
5353
});
5454

5555
it('returns the correct url query', () => {
56-
expect(router.urlService.html5Mode()).toBe(true);
56+
expect(router.urlService.config.html5Mode()).toBe(true);
5757
return router.stateService.go('path', {urlParam: 'bar'}).then(() => {
5858
expect(window.location.toString().includes('/path/bar')).toBe(true);
5959
expect(window.location.toString().includes('/#/path/bar')).toBe(false);

test/vanilla.hashHistorySpec.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ describe('hashHistory implementation', () => {
2727
});
2828

2929
it('reports html5Mode to be false', () => {
30-
expect(router.urlService.html5Mode()).toBe(false);
30+
expect(router.urlService.config.html5Mode()).toBe(false);
3131
});
3232

3333
it('returns the correct url query', (done) => {

0 commit comments

Comments
 (0)