From 291a70ead656b1fbf56d4b7a3ab0713643b8ee3a Mon Sep 17 00:00:00 2001 From: Joe Duchnowski Date: Mon, 14 Oct 2013 16:53:11 -0400 Subject: [PATCH] Added ability to queue child states and register them once their parent is registered. --- src/state.js | 27 ++++++++++++++++++++++++++- test/stateSpec.js | 38 ++++++++++++++++++++++++++++++++++++-- 2 files changed, 62 insertions(+), 3 deletions(-) diff --git a/src/state.js b/src/state.js index bf1e0eedc..3aeaec238 100644 --- a/src/state.js +++ b/src/state.js @@ -1,7 +1,7 @@ $StateProvider.$inject = ['$urlRouterProvider', '$urlMatcherFactoryProvider', '$locationProvider']; function $StateProvider( $urlRouterProvider, $urlMatcherFactory, $locationProvider) { - var root, states = {}, $state; + var root, states = {}, $state, queue = {}; // Builds state properties from definition passed to registerState() var stateBuilder = { @@ -143,6 +143,13 @@ function $StateProvider( $urlRouterProvider, $urlMatcherFactory, $ return undefined; } + function queueState(parentName, state) { + if (!queue[parentName]) { + queue[parentName] = []; + } + + queue[parentName].push(state); + } function registerState(state) { // Wrap a new object around the state so we can store our private details easily. @@ -156,6 +163,17 @@ function $StateProvider( $urlRouterProvider, $urlMatcherFactory, $ if (!isString(name) || name.indexOf('@') >= 0) throw new Error("State must have a valid name"); if (states[name]) throw new Error("State '" + name + "'' is already defined"); + // Get parent name + var parentName = + (name.indexOf('.') !== -1) ? name.substring(0, name.lastIndexOf('.')) + : (isString(state.parent)) ? state.parent + : ''; + + // If parent is not registered yet, add state to queue and register later + if (parentName && !states[parentName]) { + return queueState(parentName, state.self); + } + for (var key in stateBuilder) { if (isFunction(stateBuilder[key])) state[key] = stateBuilder[key](state, stateBuilder.$delegates[key]); } @@ -170,6 +188,13 @@ function $StateProvider( $urlRouterProvider, $urlMatcherFactory, $ }]); } + // Register any queued children + if (queue[name]) { + for (var i = 0; i < queue[name].length; i++) { + registerState(queue[name][i]); + } + } + return state; } diff --git a/test/stateSpec.js b/test/stateSpec.js index 6ca7f1d4c..555317b6d 100644 --- a/test/stateSpec.js +++ b/test/stateSpec.js @@ -25,7 +25,7 @@ describe('state', function () { E = { params: [ 'i' ] }, H = { data: {propA: 'propA', propB: 'propB'} }, HH = { parent: H }, - HHH = {parent: HH, data: {propA: 'overriddenA', propC: 'propC'} } + HHH = {parent: HH, data: {propA: 'overriddenA', propC: 'propC'} }, AppInjectable = {}; beforeEach(module(function ($stateProvider, $provide) { @@ -87,7 +87,6 @@ describe('state', function () { expect($state.current).toBe(state); } - describe('.transitionTo()', function () { it('returns a promise for the target state', inject(function ($state, $q) { var trans = $state.transitionTo(A, {}); @@ -716,3 +715,38 @@ describe('state', function () { }); }); + +describe('state queue', function(){ + angular.module('ui.router.queue.test', ['ui.router.queue.test.dependency']) + .config(function($stateProvider) { + $stateProvider + .state('queue-test-a', {}) + .state('queue-test-b-child', { parent: 'queue-test-b' }) + .state('queue-test-b', {}); + }); + angular.module('ui.router.queue.test.dependency', []) + .config(function($stateProvider) { + $stateProvider + .state('queue-test-a.child', {}) + }); + + var expectedStates = ['','queue-test-a', 'queue-test-a.child', 'queue-test-b', 'queue-test-b-child']; + + it('should work across modules', function() { + module('ui.router.queue.test', 'ui.router.queue.test.dependency'); + + inject(function ($state) { + var list = $state.get().sort(function(a, b) { return (a.name > b.name) - (b.name > a.name); }); + expect(list.map(function(state) { return state.name; })).toEqual(expectedStates); + }); + }); + + it('should work when parent is name string', function() { + module('ui.router.queue.test', 'ui.router.queue.test.dependency'); + + inject(function ($state) { + var list = $state.get().sort(function(a, b) { return (a.name > b.name) - (b.name > a.name); }); + expect(list.map(function(state) { return state.name; })).toEqual(expectedStates); + }); + }); +}); \ No newline at end of file