From 029fb00ee9cea9084fa43416b64199fbe51a71e7 Mon Sep 17 00:00:00 2001 From: Chris Thielen Date: Sat, 17 Dec 2016 17:25:30 -0600 Subject: [PATCH] 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. --- src/router.ts | 21 ++++++++++----------- src/state/stateService.ts | 7 ++++--- src/transition/transitionService.ts | 4 ++-- src/url/urlRouter.ts | 17 ++++++++--------- src/vanilla/utils.ts | 11 ++++------- test/stateRegistrySpec.ts | 3 ++- test/stateServiceSpec.ts | 1 + test/vanilla.browserHistorySpec.ts | 4 ++-- test/vanilla.hashHistorySpec.ts | 2 +- 9 files changed, 34 insertions(+), 36 deletions(-) diff --git a/src/router.ts b/src/router.ts index 9cdd3c55..3f392bd1 100644 --- a/src/router.ts +++ b/src/router.ts @@ -3,8 +3,7 @@ * @module core */ /** */ import { UrlMatcherFactory } from "./url/urlMatcherFactory"; -import { UrlRouterProvider } from "./url/urlRouter"; -import { UrlRouter } from "./url/urlRouter"; +import { UrlRouterProvider, UrlRouter } from "./url/urlRouter"; import { TransitionService } from "./transition/transitionService"; import { ViewService } from "./view/view"; import { StateRegistry } from "./state/stateRegistry"; @@ -14,7 +13,7 @@ import { UIRouterPlugin, Disposable } from "./interface"; import { values, removeFrom } from "./common/common"; import { isFunction } from "./common/predicates"; import { UrlService } from "./url/urlService"; -import { services, LocationServices, LocationConfig } from "./common/coreservices"; +import { LocationServices, LocationConfig } from "./common/coreservices"; /** @hidden */ let _routerInstance = 0; @@ -50,13 +49,7 @@ export class UIRouter { stateService = new StateService(this); - get urlService(): LocationServices { - return services.location; - } - - get urlConfig(): LocationConfig { - return services.locationConfig; - } + urlService: UrlService = new UrlService(this); private _disposables: Disposable[] = []; @@ -89,7 +82,11 @@ export class UIRouter { }); } - constructor() { + constructor( + public locationService: LocationServices = UrlService.locationServiceStub, + public locationConfig: LocationConfig = UrlService.locationConfigStub + ) { + this.viewService._pluginapi._rootViewContext(this.stateRegistry.root()); this.globals.$current = this.stateRegistry.root(); this.globals.current = this.globals.$current.self; @@ -98,6 +95,8 @@ export class UIRouter { this.disposable(this.urlRouterProvider); this.disposable(this.urlRouter); this.disposable(this.stateRegistry); + this.disposable(locationService); + this.disposable(locationConfig); } /** @hidden */ diff --git a/src/state/stateService.ts b/src/state/stateService.ts index d5978192..ac886f19 100644 --- a/src/state/stateService.ts +++ b/src/state/stateService.ts @@ -2,7 +2,9 @@ * @coreapi * @module state */ /** */ -import { extend, defaults, silentRejection, silenceUncaughtInPromise, removeFrom, noop } from "../common/common"; +import { + extend, defaults, silentRejection, silenceUncaughtInPromise, removeFrom, noop, createProxyFunctions +} from "../common/common"; import {isDefined, isObject, isString} from "../common/predicates"; import {Queue} from "../common/queue"; import {services} from "../common/coreservices"; @@ -24,7 +26,6 @@ import {ParamsOrArray} from "../params/interface"; import {Param} from "../params/param"; import {Glob} from "../common/glob"; import {HrefOptions} from "./interface"; -import {bindFunctions} from "../common/common"; import {Globals} from "../globals"; import {UIRouter} from "../router"; import {UIInjector} from "../interface"; @@ -74,7 +75,7 @@ export class StateService { constructor(private router: UIRouter) { let getters = ['current', '$current', 'params', 'transition']; let boundFns = Object.keys(StateService.prototype).filter(key => getters.indexOf(key) === -1); - bindFunctions(StateService.prototype, this, this, boundFns); + createProxyFunctions(StateService.prototype, this, this, boundFns); } /** @internalapi */ diff --git a/src/transition/transitionService.ts b/src/transition/transitionService.ts index ac772258..ebd4a926 100644 --- a/src/transition/transitionService.ts +++ b/src/transition/transitionService.ts @@ -22,7 +22,7 @@ import { registerLazyLoadHook } from "../hooks/lazyLoad"; import { TransitionEventType } from "./transitionEventType"; import { TransitionHook, GetResultHandler, GetErrorHandler } from "./transitionHook"; import { isDefined } from "../common/predicates"; -import { removeFrom, values, bindFunctions } from "../common/common"; +import { removeFrom, values, createProxyFunctions } from "../common/common"; import { Disposable } from "../interface"; // has or is using /** @@ -149,7 +149,7 @@ export class TransitionService implements IHookRegistry, Disposable { constructor(private _router: UIRouter) { this.$view = _router.viewService; this._deregisterHookFns = {}; - this._pluginapi = bindFunctions(this, {}, this, [ + this._pluginapi = createProxyFunctions(this, {}, this, [ '_definePathType', '_defineEvent', '_getPathTypes', diff --git a/src/url/urlRouter.ts b/src/url/urlRouter.ts index 54eaac34..d5cf0d57 100644 --- a/src/url/urlRouter.ts +++ b/src/url/urlRouter.ts @@ -2,7 +2,7 @@ * @coreapi * @module url */ /** for typedoc */ -import { extend, bindFunctions, IInjectable, removeFrom } from "../common/common"; +import { extend, IInjectable, removeFrom, createProxyFunctions } from "../common/common"; import { isFunction, isString, isDefined, isArray } from "../common/predicates"; import { UrlMatcher } from "./urlMatcher"; import { services, $InjectorLike, LocationServices } from "../common/coreservices"; @@ -260,10 +260,10 @@ export class UrlRouterProvider implements Disposable { * }); * ``` * - * @param defer Indicates whether to defer location change interception. Passing - * no parameter is equivalent to `true`. + * @param defer Indicates whether to defer location change interception. + * Passing no parameter is equivalent to `true`. */ - deferIntercept(defer) { + deferIntercept(defer?: boolean) { if (defer === undefined) defer = true; this.interceptDeferred = defer; }; @@ -277,7 +277,7 @@ export class UrlRouter implements Disposable { /** @hidden */ constructor(public router: UIRouter) { - bindFunctions(UrlRouter.prototype, this, this); + createProxyFunctions(UrlRouter.prototype, this, this); } /** @internalapi */ @@ -398,11 +398,10 @@ export class UrlRouter implements Disposable { let url = urlMatcher.format(params); options = options || { absolute: false }; - let cfg = this.router.urlConfig; - let loc = this.router.urlService; - let isHtml5 = loc.html5Mode(); + let cfg = this.router.urlService.config; + let isHtml5 = cfg.html5Mode(); if (!isHtml5 && url !== null) { - url = "#" + loc.hashPrefix() + url; + url = "#" + cfg.hashPrefix() + url; } url = appendBasePath(url, isHtml5, options.absolute, cfg.baseHref()); diff --git a/src/vanilla/utils.ts b/src/vanilla/utils.ts index 53df30a7..11aa2a1d 100644 --- a/src/vanilla/utils.ts +++ b/src/vanilla/utils.ts @@ -5,7 +5,6 @@ import {isArray} from "../common/index"; import { LocationServices, LocationConfig, services } from "../common/coreservices"; import { UIRouter } from "../router"; -import { extend, bindFunctions } from "../common/common"; const beforeAfterSubstr = (char: string) => (str: string): string[] => { if (!str) return ["", ""]; @@ -35,21 +34,19 @@ export const getParams = (queryString: string): any => export function locationPluginFactory( name: string, + isHtml5: boolean, serviceClass: { new(router?: UIRouter): LocationServices }, - configurationClass: { new(router?: UIRouter): LocationConfig } + configurationClass: { new(router?: UIRouter, isHtml5?: boolean): LocationConfig } ) { return function(router: UIRouter) { - let service = new serviceClass(router); - let configuration = new configurationClass(router); + let service = router.locationService = new serviceClass(router); + let configuration = router.locationConfig = new configurationClass(router, isHtml5); function dispose(router: UIRouter) { router.dispose(service); router.dispose(configuration); } - bindFunctions(serviceClass.prototype, services.location, service); - bindFunctions(configurationClass.prototype, services.locationConfig, configuration); - return { name, service, configuration, dispose }; }; } diff --git a/test/stateRegistrySpec.ts b/test/stateRegistrySpec.ts index 10f3227d..f067dc69 100644 --- a/test/stateRegistrySpec.ts +++ b/test/stateRegistrySpec.ts @@ -1,7 +1,7 @@ import { UIRouter } from "../src/router"; import { tree2Array } from "./_testUtils"; import { StateRegistry } from "../src/state/stateRegistry"; -import { services } from "../src/common/coreservices"; +import { TestingPlugin } from "./_testingPlugin"; let router: UIRouter = null; let registry: StateRegistry = null; @@ -20,6 +20,7 @@ let statetree = { describe("StateRegistry", () => { beforeEach(() => { router = new UIRouter(); + router.plugin(TestingPlugin); registry = router.stateRegistry; tree2Array(statetree, true).forEach(state => registry.register(state)); registry.stateQueue.autoFlush(router.stateService); diff --git a/test/stateServiceSpec.ts b/test/stateServiceSpec.ts index 7c958666..b84b2c94 100644 --- a/test/stateServiceSpec.ts +++ b/test/stateServiceSpec.ts @@ -29,6 +29,7 @@ describe('stateService', function () { afterEach(() => router.dispose()); beforeEach(() => { + jasmine.DEFAULT_TIMEOUT_INTERVAL = 1000; router = new UIRouter(); router.plugin(TestingPlugin); diff --git a/test/vanilla.browserHistorySpec.ts b/test/vanilla.browserHistorySpec.ts index 0def93f7..35d11d7d 100644 --- a/test/vanilla.browserHistorySpec.ts +++ b/test/vanilla.browserHistorySpec.ts @@ -39,7 +39,7 @@ describe('browserHistory implementation', () => { it('uses history.pushState when setting a url', () => { let service = mockHistoryObject(); - expect(router.urlService.html5Mode()).toBe(true); + expect(router.urlService.config.html5Mode()).toBe(true); let stub = spyOn(service._history, 'pushState'); router.urlRouter.push(makeMatcher('/hello/:name'), { name: 'world' }, {}); expect(stub.calls.first().args[2]).toBe('/hello/world'); @@ -53,7 +53,7 @@ describe('browserHistory implementation', () => { }); it('returns the correct url query', () => { - expect(router.urlService.html5Mode()).toBe(true); + expect(router.urlService.config.html5Mode()).toBe(true); return router.stateService.go('path', {urlParam: 'bar'}).then(() => { expect(window.location.toString().includes('/path/bar')).toBe(true); expect(window.location.toString().includes('/#/path/bar')).toBe(false); diff --git a/test/vanilla.hashHistorySpec.ts b/test/vanilla.hashHistorySpec.ts index a80d199f..a30f1b2d 100644 --- a/test/vanilla.hashHistorySpec.ts +++ b/test/vanilla.hashHistorySpec.ts @@ -27,7 +27,7 @@ describe('hashHistory implementation', () => { }); it('reports html5Mode to be false', () => { - expect(router.urlService.html5Mode()).toBe(false); + expect(router.urlService.config.html5Mode()).toBe(false); }); it('returns the correct url query', (done) => {