diff options
| author | Matias Niemelä | 2013-10-08 23:40:46 -0400 |
|---|---|---|
| committer | Misko Hevery | 2013-10-10 17:35:36 -0700 |
| commit | cc5846073e57ef190182026d7e5a8e2770d9b770 (patch) | |
| tree | e9df55f6845a2b83e8139fde38dab390016cebea /src/ngAnimate | |
| parent | 23c698821f41e7c7e46a5898e29ac0515041bedc (diff) | |
| download | angular.js-cc5846073e57ef190182026d7e5a8e2770d9b770.tar.bz2 | |
fix($animate): ensure structural animations skip all child animations even if no animation is present during compile
Closes #3215
Diffstat (limited to 'src/ngAnimate')
| -rw-r--r-- | src/ngAnimate/animate.js | 75 |
1 files changed, 56 insertions, 19 deletions
diff --git a/src/ngAnimate/animate.js b/src/ngAnimate/animate.js index fc865a65..4bd7b886 100644 --- a/src/ngAnimate/animate.js +++ b/src/ngAnimate/animate.js @@ -285,6 +285,7 @@ angular.module('ngAnimate', ['ng']) * @param {function()=} done callback function that will be called once the animation is complete */ enter : function(element, parent, after, done) { + this.enabled(false, element); $delegate.enter(element, parent, after); $rootScope.$$postDigest(function() { performAnimation('enter', 'ng-enter', element, parent, after, function() { @@ -322,6 +323,7 @@ angular.module('ngAnimate', ['ng']) */ leave : function(element, done) { cancelChildAnimations(element); + this.enabled(false, element); $rootScope.$$postDigest(function() { performAnimation('leave', 'ng-leave', element, null, null, function() { $delegate.leave(element, done); @@ -361,6 +363,7 @@ angular.module('ngAnimate', ['ng']) */ move : function(element, parent, after, done) { cancelChildAnimations(element); + this.enabled(false, element); $delegate.move(element, parent, after); $rootScope.$$postDigest(function() { performAnimation('move', 'ng-move', element, null, null, function() { @@ -451,12 +454,30 @@ angular.module('ngAnimate', ['ng']) * Globally enables/disables animations. * */ - enabled : function(value) { - if (arguments.length) { - rootAnimateState.running = !value; + enabled : function(value, element) { + switch(arguments.length) { + case 2: + if(value) { + cleanup(element); + } + else { + var data = element.data(NG_ANIMATE_STATE) || {}; + data.structural = true; + data.running = true; + element.data(NG_ANIMATE_STATE, data); + } + break; + + case 1: + rootAnimateState.running = !value; + break; + + default: + value = !rootAnimateState.running + break; } - return !rootAnimateState.running; - } + return !!value; + } }; /* @@ -484,24 +505,29 @@ angular.module('ngAnimate', ['ng']) //skip the animation if animations are disabled, a parent is already being animated //or the element is not currently attached to the document body. if ((parent.inheritedData(NG_ANIMATE_STATE) || disabledAnimation).running || animations.length == 0) { - //avoid calling done() since there is no need to remove any - //data or className values since this happens earlier than that - //and also use a timeout so that it won't be asynchronous - onComplete && onComplete(); + done(); return; } var ngAnimateState = element.data(NG_ANIMATE_STATE) || {}; - //if an animation is currently running on the element then lets take the steps - //to cancel that animation and fire any required callbacks + var isClassBased = event == 'addClass' || event == 'removeClass'; if(ngAnimateState.running) { + if(isClassBased && ngAnimateState.structural) { + onComplete && onComplete(); + return; + } + + //if an animation is currently running on the element then lets take the steps + //to cancel that animation and fire any required callbacks + $timeout.cancel(ngAnimateState.flagTimer); cancelAnimations(ngAnimateState.animations); - ngAnimateState.done(); + (ngAnimateState.done || noop)(); } element.data(NG_ANIMATE_STATE, { running:true, + structural:!isClassBased, animations:animations, done:done }); @@ -516,17 +542,14 @@ angular.module('ngAnimate', ['ng']) }; if(animation.start) { - if(event == 'addClass' || event == 'removeClass') { - animation.endFn = animation.start(element, className, fn); - } else { - animation.endFn = animation.start(element, fn); - } + animation.endFn = isClassBased ? + animation.start(element, className, fn) : + animation.start(element, fn); } else { fn(); } }); - function progress(index) { animations[index].done = true; (animations[index].endFn || noop)(); @@ -539,7 +562,21 @@ angular.module('ngAnimate', ['ng']) function done() { if(!done.hasBeenRun) { done.hasBeenRun = true; - cleanup(element); + var data = element.data(NG_ANIMATE_STATE); + if(data) { + /* only structural animations wait for reflow before removing an + animation, but class-based animations don't. An example of this + failing would be when a parent HTML tag has a ng-class attribute + causing ALL directives below to skip animations during the digest */ + if(isClassBased) { + cleanup(element); + } else { + data.flagTimer = $timeout(function() { + cleanup(element); + }, 0, false); + element.data(NG_ANIMATE_STATE, data); + } + } (onComplete || noop)(); } } |
