aboutsummaryrefslogtreecommitdiffstats
path: root/src/ngAnimate
diff options
context:
space:
mode:
authorMatias Niemelä2013-10-08 23:40:46 -0400
committerMisko Hevery2013-10-10 17:35:36 -0700
commitcc5846073e57ef190182026d7e5a8e2770d9b770 (patch)
treee9df55f6845a2b83e8139fde38dab390016cebea /src/ngAnimate
parent23c698821f41e7c7e46a5898e29ac0515041bedc (diff)
downloadangular.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.js75
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)();
}
}