aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/ngAnimate/animate.js40
-rw-r--r--test/ngAnimate/animateSpec.js39
2 files changed, 59 insertions, 20 deletions
diff --git a/src/ngAnimate/animate.js b/src/ngAnimate/animate.js
index b1ea7d3d..99b42f38 100644
--- a/src/ngAnimate/animate.js
+++ b/src/ngAnimate/animate.js
@@ -268,6 +268,20 @@ angular.module('ngAnimate', ['ng'])
};
}])
+ .factory('$$asyncQueueBuffer', ['$timeout', function($timeout) {
+ var timer, queue = [];
+ return function(fn) {
+ $timeout.cancel(timer);
+ queue.push(fn);
+ timer = $timeout(function() {
+ for(var i = 0; i < queue.length; i++) {
+ queue[i]();
+ }
+ queue = [];
+ }, 0, false);
+ };
+ }])
+
.config(['$provide', '$animateProvider', function($provide, $animateProvider) {
var noop = angular.noop;
var forEach = angular.forEach;
@@ -291,9 +305,10 @@ angular.module('ngAnimate', ['ng'])
return extractElementNode(elm1) == extractElementNode(elm2);
}
- $provide.decorator('$animate', ['$delegate', '$injector', '$sniffer', '$rootElement', '$timeout', '$rootScope', '$document',
- function($delegate, $injector, $sniffer, $rootElement, $timeout, $rootScope, $document) {
+ $provide.decorator('$animate', ['$delegate', '$injector', '$sniffer', '$rootElement', '$$asyncQueueBuffer', '$rootScope', '$document',
+ function($delegate, $injector, $sniffer, $rootElement, $$asyncQueueBuffer, $rootScope, $document) {
+ var globalAnimationCounter = 0;
$rootElement.data(NG_ANIMATE_STATE, rootAnimateState);
// disable animations during bootstrap, but once we bootstrapped, wait again
@@ -315,10 +330,6 @@ angular.module('ngAnimate', ['ng'])
return classNameFilter.test(className);
};
- function async(fn) {
- return $timeout(fn, 0, false);
- }
-
function lookup(name) {
if (name) {
var matches = [],
@@ -685,7 +696,6 @@ angular.module('ngAnimate', ['ng'])
if(ngAnimateState.running) {
//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.closeAnimationTimeout);
cleanup(element);
cancelAnimations(ngAnimateState.animations);
@@ -736,12 +746,15 @@ angular.module('ngAnimate', ['ng'])
//parent animations to find and cancel child animations when needed
element.addClass(NG_ANIMATE_CLASS_NAME);
+ var localAnimationCount = globalAnimationCounter++;
+
element.data(NG_ANIMATE_STATE, {
running:true,
event:animationEvent,
className:className,
structural:!isClassBased,
animations:animations,
+ index:localAnimationCount,
done:onBeforeAnimationsComplete
});
@@ -816,19 +829,19 @@ angular.module('ngAnimate', ['ng'])
}
function fireBeforeCallbackAsync() {
- async(function() {
+ $$asyncQueueBuffer(function() {
fireDOMCallback('before');
});
}
function fireAfterCallbackAsync() {
- async(function() {
+ $$asyncQueueBuffer(function() {
fireDOMCallback('after');
});
}
function fireDoneCallbackAsync() {
- async(function() {
+ $$asyncQueueBuffer(function() {
fireDOMCallback('close');
doneCallback && doneCallback();
});
@@ -855,8 +868,11 @@ angular.module('ngAnimate', ['ng'])
if(isClassBased) {
cleanup(element);
} else {
- data.closeAnimationTimeout = async(function() {
- cleanup(element);
+ $$asyncQueueBuffer(function() {
+ var data = element.data(NG_ANIMATE_STATE) || {};
+ if(localAnimationCount == data.index) {
+ cleanup(element);
+ }
});
element.data(NG_ANIMATE_STATE, data);
}
diff --git a/test/ngAnimate/animateSpec.js b/test/ngAnimate/animateSpec.js
index d626d60e..41115e42 100644
--- a/test/ngAnimate/animateSpec.js
+++ b/test/ngAnimate/animateSpec.js
@@ -2563,8 +2563,9 @@ describe("ngAnimate", function() {
});
- it("should disable all child animations on structural animations until the post animation timeout has passed", function() {
- var intercepted;
+ it("should disable all child animations on structural animations until the post animation" +
+ "timeout has passed as well as all structural animations", function() {
+ var intercepted, continueAnimation;
module(function($animateProvider) {
$animateProvider.register('.animated', function() {
return {
@@ -2578,7 +2579,10 @@ describe("ngAnimate", function() {
function ani(type) {
return function(element, className, done) {
intercepted = type;
- (done || className)();
+ continueAnimation = function() {
+ continueAnimation = angular.noop;
+ (done || className)();
+ }
}
}
});
@@ -2595,26 +2599,45 @@ describe("ngAnimate", function() {
var child2 = $compile('<div class="child2 animated">...</div>')($rootScope);
var container = $compile('<div class="container">...</div>')($rootScope);
- jqLite($document[0].body).append($rootElement);
+ var body = angular.element($document[0].body);
+ body.append($rootElement);
$rootElement.append(container);
element.append(child1);
element.append(child2);
- $animate.move(element, null, container);
+ $animate.enter(element, container);
$rootScope.$digest();
- expect(intercepted).toBe('move');
+ expect(intercepted).toBe('enter');
+ continueAnimation();
$animate.addClass(child1, 'test');
expect(child1.hasClass('test')).toBe(true);
- expect(intercepted).toBe('move');
+ expect(element.children().length).toBe(2);
+
+ expect(intercepted).toBe('enter');
$animate.leave(child1);
$rootScope.$digest();
+ expect(element.children().length).toBe(1);
+
+ expect(intercepted).toBe('enter');
+
+ $animate.move(element, null, container);
+ $rootScope.$digest();
+
expect(intercepted).toBe('move');
- //reflow has passed
+ //flush the enter reflow
+ $timeout.flush();
+
+ $animate.addClass(child2, 'testing');
+ expect(intercepted).toBe('move');
+
+ continueAnimation();
+
+ //flush the move reflow
$timeout.flush();
$animate.leave(child2);