vendor/assets/javascripts/angular-animate.js in angular-gem-1.2.19 vs vendor/assets/javascripts/angular-animate.js in angular-gem-1.2.20

- old
+ new

@@ -1,7 +1,7 @@ /** - * @license AngularJS v1.2.19 + * @license AngularJS v1.2.20 * (c) 2010-2014 Google, Inc. http://angularjs.org * License: MIT */ (function(window, angular, undefined) {'use strict'; @@ -62,13 +62,27 @@ * to trigger the CSS transition/animations * --> * <ANY class="slide" ng-include="..."></ANY> * ``` * - * Keep in mind that if an animation is running, any child elements cannot be animated until the parent element's - * animation has completed. + * Keep in mind that, by default, if an animation is running, any child elements cannot be animated + * until the parent element's animation has completed. This blocking feature can be overridden by + * placing the `ng-animate-children` attribute on a parent container tag. * + * ```html + * <div class="slide-animation" ng-if="on" ng-animate-children> + * <div class="fade-animation" ng-if="on"> + * <div class="explode-animation" ng-if="on"> + * ... + * </div> + * </div> + * </div> + * ``` + * + * When the `on` expression value changes and an animation is triggered then each of the elements within + * will all animate without the block being applied to child elements. + * * <h2>CSS-defined Animations</h2> * The animate service will automatically apply two CSS classes to the animated element and these two CSS classes * are designed to contain the start and end CSS styling. Both CSS transitions and keyframe animations are supported * and can be used to play along with this naming structure. * @@ -253,10 +267,23 @@ * Requires the {@link ngAnimate `ngAnimate`} module to be installed. * * Please visit the {@link ngAnimate `ngAnimate`} module overview page learn more about how to use animations in your application. * */ + .directive('ngAnimateChildren', function() { + var NG_ANIMATE_CHILDREN = '$$ngAnimateChildren'; + return function(scope, element, attrs) { + var val = attrs.ngAnimateChildren; + if(angular.isString(val) && val.length === 0) { //empty attribute + element.data(NG_ANIMATE_CHILDREN, true); + } else { + scope.$watch(val, function(value) { + element.data(NG_ANIMATE_CHILDREN, !!value); + }); + } + }; + }) //this private service is only used within CSS-enabled animations //IE8 + IE9 do not support rAF natively, but that is fine since they //also don't support transitions and keyframes which means that the code //below will never be used by the two browsers. @@ -281,10 +308,11 @@ var forEach = angular.forEach; var selectors = $animateProvider.$$selectors; var ELEMENT_NODE = 1; var NG_ANIMATE_STATE = '$$ngAnimateState'; + var NG_ANIMATE_CHILDREN = '$$ngAnimateChildren'; var NG_ANIMATE_CLASS_NAME = 'ng-animate'; var rootAnimateState = {running: true}; function extractElementNode(element) { for(var i = 0; i < element.length; i++) { @@ -330,10 +358,16 @@ ? function() { return true; } : function(className) { return classNameFilter.test(className); }; + function blockElementAnimations(element) { + var data = element.data(NG_ANIMATE_STATE) || {}; + data.running = true; + element.data(NG_ANIMATE_STATE, data); + } + function lookup(name) { if (name) { var matches = [], flagMap = {}, classes = name.substr(1).split('.'); @@ -556,11 +590,11 @@ enter : function(element, parentElement, afterElement, doneCallback) { element = angular.element(element); parentElement = prepareElement(parentElement); afterElement = prepareElement(afterElement); - this.enabled(false, element); + blockElementAnimations(element); $delegate.enter(element, parentElement, afterElement); $rootScope.$$postDigest(function() { element = stripCommentsFromElement(element); performAnimation('enter', 'ng-enter', element, parentElement, afterElement, noop, doneCallback); }); @@ -594,11 +628,11 @@ * @param {function()=} doneCallback the callback function that will be called once the animation is complete */ leave : function(element, doneCallback) { element = angular.element(element); cancelChildAnimations(element); - this.enabled(false, element); + blockElementAnimations(element); $rootScope.$$postDigest(function() { performAnimation('leave', 'ng-leave', stripCommentsFromElement(element), null, null, function() { $delegate.leave(element); }, doneCallback); }); @@ -638,11 +672,11 @@ element = angular.element(element); parentElement = prepareElement(parentElement); afterElement = prepareElement(afterElement); cancelChildAnimations(element); - this.enabled(false, element); + blockElementAnimations(element); $delegate.move(element, parentElement, afterElement); $rootScope.$$postDigest(function() { element = stripCommentsFromElement(element); performAnimation('move', 'ng-move', element, parentElement, afterElement, noop, doneCallback); }); @@ -812,13 +846,16 @@ var totalActiveAnimations = ngAnimateState.totalActive || 0; var lastAnimation = ngAnimateState.last; //only allow animations if the currently running animation is not structural //or if there is no animation running at all - var skipAnimations = runner.isClassBased ? - ngAnimateState.disabled || (lastAnimation && !lastAnimation.isClassBased) : - false; + var skipAnimations; + if (runner.isClassBased) { + skipAnimations = ngAnimateState.running || + ngAnimateState.disabled || + (lastAnimation && !lastAnimation.isClassBased); + } //skip the animation if animations are disabled, a parent is already being animated, //the element is not currently attached to the document body or then completely close //the animation if any matching animations are not found at all. //NOTE: IE8 + IE9 should close properly (run closeAnimation()) in case an animation was found. @@ -1031,33 +1068,52 @@ } } } function animationsDisabled(element, parentElement) { - if (rootAnimateState.disabled) return true; + if (rootAnimateState.disabled) { + return true; + } - if(isMatchingElement(element, $rootElement)) { - return rootAnimateState.disabled || rootAnimateState.running; + if (isMatchingElement(element, $rootElement)) { + return rootAnimateState.running; } + var allowChildAnimations, parentRunningAnimation, hasParent; do { //the element did not reach the root element which means that it //is not apart of the DOM. Therefore there is no reason to do //any animations on it - if(parentElement.length === 0) break; + if (parentElement.length === 0) break; var isRoot = isMatchingElement(parentElement, $rootElement); - var state = isRoot ? rootAnimateState : parentElement.data(NG_ANIMATE_STATE); - var result = state && (!!state.disabled || state.running || state.totalActive > 0); - if(isRoot || result) { - return result; + var state = isRoot ? rootAnimateState : (parentElement.data(NG_ANIMATE_STATE) || {}); + if (state.disabled) { + return true; } - if(isRoot) return true; + //no matter what, for an animation to work it must reach the root element + //this implies that the element is attached to the DOM when the animation is run + if (isRoot) { + hasParent = true; + } + + //once a flag is found that is strictly false then everything before + //it will be discarded and all child animations will be restricted + if (allowChildAnimations !== false) { + var animateChildrenFlag = parentElement.data(NG_ANIMATE_CHILDREN); + if(angular.isDefined(animateChildrenFlag)) { + allowChildAnimations = animateChildrenFlag; + } + } + + parentRunningAnimation = parentRunningAnimation || + state.running || + (state.last && !state.last.isClassBased); } while(parentElement = parentElement.parent()); - return true; + return !hasParent || (!allowChildAnimations && parentRunningAnimation); } }]); $animateProvider.register('', ['$window', '$sniffer', '$timeout', '$$animateReflow', function($window, $sniffer, $timeout, $$animateReflow) {