From 13729f0d9a8dea0d839b3479e0caca7adba9759f Mon Sep 17 00:00:00 2001 From: Jake Date: Fri, 1 Nov 2013 16:18:04 +0100 Subject: [PATCH] 0.2.0 + #492 --- release/angular-ui-router.js | 204 ++++++----------------------------- 1 file changed, 30 insertions(+), 174 deletions(-) diff --git a/release/angular-ui-router.js b/release/angular-ui-router.js index 9e4ee976d..6c09379aa 100644 --- a/release/angular-ui-router.js +++ b/release/angular-ui-router.js @@ -1,15 +1,9 @@ /** * State-based routing for AngularJS - * @version v0.2.0-dev-2013-10-28 + * @version v0.2.0-dev-2013-11-01 * @link http://angular-ui.github.com/ * @license MIT License, http://www.opensource.org/licenses/MIT */ - -/* commonjs package manager support (eg componentjs) */ -if (typeof module !== "undefined" && typeof exports !== "undefined" && module.exports === exports){ - module.exports = 'ui.router'; -} - (function (window, angular, undefined) { /*jshint globalstrict:true*/ /*global angular:false*/ @@ -133,7 +127,7 @@ function $Resolve( $q, $injector) { visited[key] = VISIT_IN_PROGRESS; if (isString(value)) { - plan.push(key, [ function() { return $injector.get(value); }], NO_DEPENDENCIES); + plan.push(key, [ function() { return $injector.get(key); }], NO_DEPENDENCIES); } else { var params = $injector.annotate(value); forEach(params, function (param) { @@ -220,7 +214,7 @@ function $Resolve( $q, $injector) { } // Wait for any parameter that we have a promise for (either from parent or from this // resolve; in that case study() will have made sure it's ordered before us in the plan). - forEach(params, function (dep) { + params.forEach(function (dep) { if (promises.hasOwnProperty(dep) && !locals.hasOwnProperty(dep)) { waitParams++; promises[dep].then(function (result) { @@ -790,7 +784,7 @@ function $StateProvider( $urlRouterProvider, $urlMatcherFactory, $ // inherit 'data' from parent and override by own values (if any) data: function(state) { if (state.parent && state.parent.data) { - state.data = state.self.data = extend({}, state.parent.data, state.data); + state.data = state.self.data = angular.extend({}, state.parent.data, state.data); } return state.data; }, @@ -872,19 +866,14 @@ function $StateProvider( $urlRouterProvider, $urlMatcherFactory, $ var includes = state.parent ? extend({}, state.parent.includes) : {}; includes[state.name] = true; return includes; - }, - - $delegates: {} + } }; - function isRelative(stateName) { - return stateName.indexOf(".") === 0 || stateName.indexOf("^") === 0; - } function findState(stateOrName, base) { var isStr = isString(stateOrName), name = isStr ? stateOrName : stateOrName.name, - path = isRelative(name); + path = name.indexOf(".") === 0 || name.indexOf("^") === 0; if (path) { if (!base) throw new Error("No reference point given for path '" + name + "'"); @@ -931,7 +920,7 @@ function $StateProvider( $urlRouterProvider, $urlMatcherFactory, $ var name = state.name; if (!isString(name) || name.indexOf('@') >= 0) throw new Error("State must have a valid name"); - if (states.hasOwnProperty(name)) throw new Error("State '" + name + "'' is already defined"); + if (states[name]) throw new Error("State '" + name + "'' is already defined"); // Get parent name var parentName = @@ -945,7 +934,7 @@ function $StateProvider( $urlRouterProvider, $urlMatcherFactory, $ } for (var key in stateBuilder) { - if (isFunction(stateBuilder[key])) state[key] = stateBuilder[key](state, stateBuilder.$delegates[key]); + state[key] = stateBuilder[key](state); } states[name] = state; @@ -979,25 +968,6 @@ function $StateProvider( $urlRouterProvider, $urlMatcherFactory, $ root.navigable = null; - // .decorator() - // .decorator(name) - // .decorator(name, function) - this.decorator = decorator; - function decorator(name, func) { - /*jshint validthis: true */ - if (isString(name) && !isDefined(func)) { - return stateBuilder[name]; - } - if (!isFunction(func) || !isString(name)) { - return this; - } - if (stateBuilder[name] && !stateBuilder.$delegates[name]) { - stateBuilder.$delegates[name] = stateBuilder[name]; - } - stateBuilder[name] = func; - return this; - } - // .state(state) // .state(name, state) this.state = state; @@ -1016,16 +986,6 @@ function $StateProvider( $urlRouterProvider, $urlMatcherFactory, $ var TransitionSuperseded = $q.reject(new Error('transition superseded')); var TransitionPrevented = $q.reject(new Error('transition prevented')); - var TransitionAborted = $q.reject(new Error('transition aborted')); - var TransitionFailed = $q.reject(new Error('transition failed')); - var currentLocation = $location.url(); - - function syncUrl() { - if ($location.url() !== currentLocation) { - $location.url(currentLocation); - $location.replace(); - } - } root.locals = { resolve: null, globals: { $stateParams: {} } }; $state = { @@ -1042,55 +1002,16 @@ function $StateProvider( $urlRouterProvider, $urlMatcherFactory, $ $state.transitionTo = function transitionTo(to, toParams, options) { if (!isDefined(options)) options = (options === true || options === false) ? { location: options } : {}; toParams = toParams || {}; - options = extend({ location: true, inherit: false, relative: null, notify: true, $retry: false }, options); - - var from = $state.$current, fromParams = $state.params, fromPath = from.path; - var evt, toState = findState(to, options.relative); - - if (!isDefined(toState)) { - // Broadcast not found event and abort the transition if prevented - var redirect = { to: to, toParams: toParams, options: options }; - evt = $rootScope.$broadcast('$stateNotFound', redirect, from.self, fromParams); - if (evt.defaultPrevented) { - syncUrl(); - return TransitionAborted; - } + options = extend({ location: true, inherit: false, relative: null }, options); - // Allow the handler to return a promise to defer state lookup retry - if (evt.retry) { - if (options.$retry) { - syncUrl(); - return TransitionFailed; - } - var retryTransition = $state.transition = $q.when(evt.retry); - retryTransition.then(function() { - if (retryTransition !== $state.transition) return TransitionSuperseded; - redirect.options.$retry = true; - return $state.transitionTo(redirect.to, redirect.toParams, redirect.options); - }, - function() { - return TransitionAborted; - }); - syncUrl(); - return retryTransition; - } - - // Always retry once if the $stateNotFound was not prevented - // (handles either redirect changed or state lazy-definition) - to = redirect.to; - toParams = redirect.toParams; - options = redirect.options; - toState = findState(to, options.relative); - if (!isDefined(toState)) { - if (options.relative) throw new Error("Could not resolve '" + to + "' from state '" + options.relative + "'"); - throw new Error("No such state '" + to + "'"); - } - } + var toState = findState(to, options.relative); + if (!isDefined(toState)) throw new Error("No such state " + toState); if (toState['abstract']) throw new Error("Cannot transition to abstract state '" + to + "'"); if (options.inherit) toParams = inheritParams($stateParams, toParams || {}, $state.$current, toState); to = toState; - var toPath = to.path; + var toPath = to.path, + from = $state.$current, fromParams = $state.params, fromPath = from.path; // Starting from the root of the path, keep all levels that haven't changed var keep, state, locals = root.locals, toLocals = []; @@ -1105,7 +1026,6 @@ function $StateProvider( $urlRouterProvider, $urlMatcherFactory, $ // TODO: We may not want to bump 'transition' if we're called from a location change that we've initiated ourselves, // because we might accidentally abort a legitimate transition initiated from code? if (to === from && locals === from.locals) { - syncUrl(); $state.transition = null; return $q.when($state.current); } @@ -1114,13 +1034,8 @@ function $StateProvider( $urlRouterProvider, $urlMatcherFactory, $ toParams = normalize(to.params, toParams || {}); // Broadcast start event and cancel the transition if requested - if (options.notify) { - evt = $rootScope.$broadcast('$stateChangeStart', to.self, toParams, from.self, fromParams); - if (evt.defaultPrevented) { - syncUrl(); - return TransitionPrevented; - } - } + var evt = $rootScope.$broadcast('$stateChangeStart', to.self, toParams, from.self, fromParams); + if (evt.defaultPrevented) return TransitionPrevented; // Resolve locals for the remaining states, but don't update any global state just // yet -- if anything fails to resolve the current state needs to remain untouched. @@ -1135,7 +1050,7 @@ function $StateProvider( $urlRouterProvider, $urlMatcherFactory, $ resolved = resolveState(state, toParams, state===to, resolved, locals); } - // Once everything is resolved, we are ready to perform the actual transition + // Once everything is resolved, wer are ready to perform the actual transition // and return a promise for the new state. We also keep track of what the // current promise is, so that we can detect overlapping transitions and // keep only the outcome of the last transition. @@ -1162,9 +1077,6 @@ function $StateProvider( $urlRouterProvider, $urlMatcherFactory, $ } } - // Run it again, to catch any transitions in callbacks - if ($state.transition !== transition) return TransitionSuperseded; - // Update globals in $state $state.$current = to; $state.current = to.self; @@ -1176,16 +1088,9 @@ function $StateProvider( $urlRouterProvider, $urlMatcherFactory, $ var toNav = to.navigable; if (options.location && toNav) { $location.url(toNav.url.format(toNav.locals.globals.$stateParams)); - - if (options.location === 'replace') { - $location.replace(); - } } - if (options.notify) { - $rootScope.$broadcast('$stateChangeSuccess', to.self, toParams, from.self, fromParams); - } - currentLocation = $location.url(); + $rootScope.$broadcast('$stateChangeSuccess', to.self, toParams, from.self, fromParams); return $state.current; }, function (error) { @@ -1193,7 +1098,6 @@ function $StateProvider( $urlRouterProvider, $urlMatcherFactory, $ $state.transition = null; $rootScope.$broadcast('$stateChangeError', to.self, toParams, from.self, fromParams, error); - syncUrl(); return $q.reject(error); }); @@ -1201,66 +1105,28 @@ function $StateProvider( $urlRouterProvider, $urlMatcherFactory, $ return transition; }; - $state.is = function is(stateOrName, params) { + $state.is = function is(stateOrName) { var state = findState(stateOrName); - - if (!isDefined(state)) { - return undefined; - } - - if ($state.$current !== state) { - return false; - } - - return isDefined(params) ? angular.equals($stateParams, params) : true; + return (isDefined(state)) ? $state.$current === state : undefined; }; - $state.includes = function includes(stateOrName, params) { + $state.includes = function includes(stateOrName) { var state = findState(stateOrName); - if (!isDefined(state)) { - return undefined; - } - - if (!isDefined($state.$current.includes[state.name])) { - return false; - } - - var validParams = true; - angular.forEach(params, function(value, key) { - if (!isDefined($stateParams[key]) || $stateParams[key] !== value) { - validParams = false; - } - }); - return validParams; + return (isDefined(state)) ? isDefined($state.$current.includes[state.name]) : undefined; }; $state.href = function href(stateOrName, params, options) { - options = extend({ lossy: true, inherit: false, absolute: false, relative: $state.$current }, options || {}); + options = extend({ lossy: true, inherit: false, relative: $state.$current }, options || {}); var state = findState(stateOrName, options.relative); if (!isDefined(state)) return null; params = inheritParams($stateParams, params || {}, $state.$current, state); var nav = (state && options.lossy) ? state.navigable : state; var url = (nav && nav.url) ? nav.url.format(normalize(state.params, params || {})) : null; - if (!$locationProvider.html5Mode() && url) { - url = "#" + url; - } - if (options.absolute && url) { - url = $location.protocol() + '://' + - $location.host() + - ($location.port() == 80 || $location.port() == 443 ? '' : ':' + $location.port()) + - (!$locationProvider.html5Mode() && url ? '/' : '') + - url; - } - return url; + return !$locationProvider.html5Mode() && url ? "#" + url : url; }; $state.get = function (stateOrName) { - if (!isDefined(stateOrName)) { - var list = []; - forEach(states, function(state) { list.push(state.self); }); - return list; - } var state = findState(stateOrName); return (state && state.self) ? state.self : null; }; @@ -1292,13 +1158,7 @@ function $StateProvider( $urlRouterProvider, $urlMatcherFactory, $ promises.push($resolve.resolve(injectables, locals, dst.resolve, state).then(function (result) { // References to the controller (only instantiated at link time) - if (isFunction(view.controllerProvider)) { - result.$$controller = $injector.invoke( - view.controllerProvider, null, angular.extend({}, injectables, locals) - ); - } else { - result.$$controller = view.controller; - } + result.$$controller = view.controller; // Provide access to the state itself for internal use result.$$state = state; dst[name] = result; @@ -1392,15 +1252,13 @@ function $ViewDirective( $state, $compile, $controller, $injector, $an var directive = { restrict: 'ECA', terminal: true, - priority: 1000, transclude: true, compile: function (element, attr, transclude) { return function(scope, element, attr) { var viewScope, viewLocals, name = attr[directive.name] || attr.name || '', onloadExp = attr.onload || '', - animate = isDefined($animator) && $animator(scope, attr), - initialView = transclude(scope); + animate = isDefined($animator) && $animator(scope, attr); // Returns a set of DOM manipulation functions based on whether animation // should be performed @@ -1427,7 +1285,7 @@ function $ViewDirective( $state, $compile, $controller, $injector, $an }; // Put back the compiled initial view - element.append(initialView); + element.append(transclude(scope)); // Find the details of the parent view directive (if any) and use it // to derive our own qualified view name, then hang our own details @@ -1471,7 +1329,7 @@ function $ViewDirective( $state, $compile, $controller, $injector, $an view.state = null; // Restore the initial view - return render.restore(initialView, element); + return render.restore(transclude(scope), element); } viewLocals = locals; @@ -1502,7 +1360,7 @@ function $ViewDirective( $state, $compile, $controller, $injector, $an angular.module('ui.router.state').directive('uiView', $ViewDirective); function parseStateRef(ref) { - var parsed = ref.replace(/\n/g, " ").match(/^([^(]+?)\s*(\((.*)\))?$/); + var parsed = ref.match(/^([^(]+?)\s*(\((.*)\))?$/); if (!parsed || parsed.length !== 4) throw new Error("Invalid state ref '" + ref + "'"); return { state: parsed[1], paramExpr: parsed[3] || null }; } @@ -1538,7 +1396,7 @@ function $StateRefDirective($state) { if (ref.paramExpr) { scope.$watch(ref.paramExpr, function(newVal, oldVal) { - if (newVal !== params) update(newVal); + if (newVal !== oldVal) update(newVal); }, true); params = scope.$eval(ref.paramExpr); } @@ -1547,9 +1405,7 @@ function $StateRefDirective($state) { if (isForm) return; element.bind("click", function(e) { - var button = e.which || e.button; - - if ((button == 1) && !e.ctrlKey && !e.metaKey && !e.shiftKey) { + if ((e.which == 1) && !e.ctrlKey && !e.metaKey && !e.shiftKey) { $state.go(ref.state, params, { relative: base }); scope.$apply(); e.preventDefault();