whitesource
Version:
whitesource node module
106 lines (94 loc) • 4.76 kB
JavaScript
/**
* UI-Router Extras: Sticky states, Future States, Deep State Redirect, Transition promise
* Module: transition
* @version 0.0.14
* @link http://christopherthielen.github.io/ui-router-extras/
* @license MIT License, http://www.opensource.org/licenses/MIT
*/
(function(angular, undefined){
"use strict";
angular.module("ct.ui.router.extras.transition", [ 'ct.ui.router.extras.core' ]).config( [ "$provide", function ($provide) {
// Decorate the $state service, so we can replace $state.transitionTo()
$provide.decorator("$state", ['$delegate', '$rootScope', '$q', '$injector',
function ($state, $rootScope, $q, $injector) {
// Keep an internal reference to the real $state.transitionTo function
var $state_transitionTo = $state.transitionTo;
// $state.transitionTo can be re-entered. Keep track of re-entrant stack
var transitionDepth = -1;
var tDataStack = [];
var restoreFnStack = [];
// This function decorates the $injector, adding { $transition$: tData } to invoke() and instantiate() locals.
// It returns a function that restores $injector to its previous state.
function decorateInjector(tData) {
var oldinvoke = $injector.invoke;
var oldinstantiate = $injector.instantiate;
$injector.invoke = function (fn, self, locals) {
return oldinvoke(fn, self, angular.extend({$transition$: tData}, locals));
};
$injector.instantiate = function (fn, locals) {
return oldinstantiate(fn, angular.extend({$transition$: tData}, locals));
};
return function restoreItems() {
$injector.invoke = oldinvoke;
$injector.instantiate = oldinstantiate;
};
}
function popStack() {
restoreFnStack.pop()();
tDataStack.pop();
transitionDepth--;
}
// This promise callback (for when the real transitionTo is successful) runs the restore function for the
// current stack level, then broadcasts the $transitionSuccess event.
function transitionSuccess(deferred, tSuccess) {
return function successFn(data) {
popStack();
$rootScope.$broadcast("$transitionSuccess", tSuccess);
deferred.resolve(data); // $transition$ deferred
return data;
};
}
// This promise callback (for when the real transitionTo fails) runs the restore function for the
// current stack level, then broadcasts the $transitionError event.
function transitionFailure(deferred, tFail) {
return function failureFn(error) {
popStack();
$rootScope.$broadcast("$transitionError", tFail, error);
deferred.reject(error); // $transition$ deferred
return $q.reject(error);
};
}
// Decorate $state.transitionTo.
$state.transitionTo = function (to, toParams, options) {
// Create a deferred/promise which can be used earlier than UI-Router's transition promise.
var deferred = $q.defer();
// Place the promise in a transition data, and place it on the stack to be used in $stateChangeStart
var tData = tDataStack[++transitionDepth] = {
promise: deferred.promise
};
// placeholder restoreFn in case transitionTo doesn't reach $stateChangeStart (state not found, etc)
restoreFnStack[transitionDepth] = function() { };
// Invoke the real $state.transitionTo
var tPromise = $state_transitionTo.apply($state, arguments);
// insert our promise callbacks into the chain.
return tPromise.then(transitionSuccess(deferred, tData), transitionFailure(deferred, tData));
};
// This event is handled synchronously in transitionTo call stack
$rootScope.$on("$stateChangeStart", function (evt, toState, toParams, fromState, fromParams) {
var depth = transitionDepth;
// To/From is now normalized by ui-router. Add this information to the transition data object.
var tData = angular.extend(tDataStack[depth], {
to: { state: toState, params: toParams },
from: { state: fromState, params: fromParams }
});
var restoreFn = decorateInjector(tData);
restoreFnStack[depth] = restoreFn;
$rootScope.$broadcast("$transitionStart", tData);
}
);
return $state;
}]);
}
]
);
})(angular);