From 4533fe36e0ab2f0143edd854a4145deaa013915a Mon Sep 17 00:00:00 2001 From: christopherthielen Date: Tue, 21 Oct 2014 08:55:13 -0500 Subject: [PATCH] fix($state): register states at config-time fix($urlMatcherFactory): register types at config-time - allows Types to be referenced before runtime - reverts 97f8d9034bddffc4da3240b2cf004a6f8b2f5631 - partial revert 838b747664a6687360ea588b1d77faa32e4a7650 fix($state): handle parent.name when parent is obj - during state registration, properly grab parent.name and queue state definition, if parent is an object reference - Adding comment for commit 838b747664a6687360ea588b1d77faa32e4a7650 --- src/state.js | 7 ++--- src/urlMatcherFactory.js | 50 +++++++++++++++++++---------------- test/urlMatcherFactorySpec.js | 4 +-- 3 files changed, 31 insertions(+), 30 deletions(-) diff --git a/src/state.js b/src/state.js index 35f3ed7ee..5608caacd 100644 --- a/src/state.js +++ b/src/state.js @@ -22,7 +22,7 @@ $StateProvider.$inject = ['$urlRouterProvider', '$urlMatcherFactoryProvider']; function $StateProvider( $urlRouterProvider, $urlMatcherFactory) { - var root, states = {}, $state, queue = {}, abstractKey = 'abstract', isRuntime = false; + var root, states = {}, $state, queue = {}, abstractKey = 'abstract'; // Builds state properties from definition passed to registerState() var stateBuilder = { @@ -182,7 +182,7 @@ function $StateProvider( $urlRouterProvider, $urlMatcherFactory) { : ''; // If parent is not registered yet, add state to queue and register later - if (name !== "" && (!isRuntime || !states[parentName])) { + if (parentName && !states[parentName]) { return queueState(parentName, state.self); } @@ -1195,9 +1195,6 @@ function $StateProvider( $urlRouterProvider, $urlMatcherFactory) { }); } - isRuntime = true; - flushQueuedChildren(""); - return $state; } diff --git a/src/urlMatcherFactory.js b/src/urlMatcherFactory.js index 53d778f47..2882e65cc 100644 --- a/src/urlMatcherFactory.js +++ b/src/urlMatcherFactory.js @@ -454,7 +454,7 @@ function $UrlMatcherFactory() { } } - var $types, enqueue = true, typeQueue = [], injector, defaultTypes = { + var $types = {}, enqueue = true, typeQueue = [], injector, defaultTypes = { "searchParam": { encode: normalizeStringOrArray, decode: normalizeStringOrArray, @@ -610,8 +610,11 @@ function $UrlMatcherFactory() { * generate URLs with typed parameters. * * @param {string} name The type name. - * @param {Object|Function} def The type definition. See + * @param {Object|Function} definition The type definition. See * {@link ui.router.util.type:Type `Type`} for information on the values accepted. + * @param {Object|Function} definitionFn (optional) A function that is injected before the app + * runtime starts. The result of this function is merged into the existing `definition`. + * See {@link ui.router.util.type:Type `Type`} for information on the values accepted. * * @returns {Object} Returns `$urlMatcherFactoryProvider`. * @@ -659,7 +662,7 @@ function $UrlMatcherFactory() { * // Defines a custom type that gets a value from a service, * // where each service gets different types of values from * // a backend API: - * $urlMatcherFactoryProvider.type('dbObject', function(Users, Posts) { + * $urlMatcherFactoryProvider.type('dbObject', {}, function(Users, Posts) { * * // Matches up services to URL parameter names * var services = { @@ -704,21 +707,35 @@ function $UrlMatcherFactory() { * }); * */ - this.type = function (name, def) { - if (!isDefined(def)) { - if (!isDefined($types)) throw new Error("Please wait until runtime to retrieve types."); - return $types[name]; + this.type = function (name, definition, definitionFn) { + if (!isDefined(definition)) return $types[name]; + if ($types.hasOwnProperty(name)) throw new Error("A type named '" + name + "' has already been defined."); + + $types[name] = new Type(definition); + if (definitionFn) { + typeQueue.push({ name: name, def: definitionFn }); + if (!enqueue) flushTypeQueue(); } - typeQueue.push({ name: name, def: def }); - if (!enqueue) flushTypeQueue(); return this; }; + // `flushTypeQueue()` waits until `$urlMatcherFactory` is injected before invoking the queued `definitionFn`s + function flushTypeQueue() { + while(typeQueue.length) { + var type = typeQueue.shift(); + if (type.pattern) throw new Error("You cannot override a type's .pattern at runtime."); + angular.extend($types[type.name], injector.invoke(type.def)); + } + } + + // Register default types. Store them in the prototype of $types. + forEach(defaultTypes, function(type, name) { $types[name] = new Type(type); }); + $types = inherit($types, {}); + /* No need to document $get, since it returns this */ this.$get = ['$injector', function ($injector) { injector = $injector; enqueue = false; - $types = {}; flushTypeQueue(); forEach(defaultTypes, function(type, name) { @@ -727,19 +744,6 @@ function $UrlMatcherFactory() { return this; }]; - // To ensure proper order of operations in object configuration, and to allow internal - // types to be overridden, `flushTypeQueue()` waits until `$urlMatcherFactory` is injected - // before actually wiring up and assigning type definitions - function flushTypeQueue() { - forEach(typeQueue, function(type) { - if ($types[type.name]) { - throw new Error("A type named '" + type.name + "' has already been defined."); - } - var def = new Type(isInjectable(type.def) ? injector.invoke(type.def) : type.def); - $types[type.name] = def; - }); - } - this.Param = function Param(id, type, config) { var self = this; var defaultValueConfig = getDefaultValueConfig(config); diff --git a/test/urlMatcherFactorySpec.js b/test/urlMatcherFactorySpec.js index a652a6400..41f037cef 100644 --- a/test/urlMatcherFactorySpec.js +++ b/test/urlMatcherFactorySpec.js @@ -230,7 +230,7 @@ describe("urlMatcherFactory", function () { }); it("should accept injected function definitions", inject(function ($stateParams) { - $umf.type("myType", function($stateParams) { + $umf.type("myType", {}, function($stateParams) { return { decode: function() { return $stateParams; @@ -241,7 +241,7 @@ describe("urlMatcherFactory", function () { })); it("should accept annotated function definitions", inject(function ($stateParams) { - $umf.type("myAnnotatedType", ['$stateParams', function(s) { + $umf.type("myAnnotatedType", {},['$stateParams', function(s) { return { decode: function() { return s;