From 89e7130c2840bfabf6e4fe8b6ead25bbdb912c4a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matias=20Niemel=C3=A4?= Date: Mon, 24 Feb 2014 14:47:12 -0500 Subject: [PATCH 1/2] fix($animate): ensure all animated elements are taken care of during the closing timeout Closes #6395 --- src/ngAnimate/animate.js | 13 +++++++---- test/ngAnimate/animateSpec.js | 43 +++++++++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+), 4 deletions(-) diff --git a/src/ngAnimate/animate.js b/src/ngAnimate/animate.js index 6b7fbcce0bfc..c09e714e67bc 100644 --- a/src/ngAnimate/animate.js +++ b/src/ngAnimate/animate.js @@ -1063,6 +1063,15 @@ angular.module('ngAnimate', ['ng']) var closingTimestamp = 0; var animationElementQueue = []; function animationCloseHandler(element, totalTime) { + var node = extractElementNode(element); + element = angular.element(node); + + //this item will be garbage collected by the closing + //animation timeout + animationElementQueue.push(element); + + //but it may not need to cancel out the existing timeout + //if the timestamp is less than the previous one var futureTimestamp = Date.now() + (totalTime * 1000); if(futureTimestamp <= closingTimestamp) { return; @@ -1070,10 +1079,6 @@ angular.module('ngAnimate', ['ng']) $timeout.cancel(closingTimer); - var node = extractElementNode(element); - element = angular.element(node); - animationElementQueue.push(element); - closingTimestamp = futureTimestamp; closingTimer = $timeout(function() { closeAllAnimations(animationElementQueue); diff --git a/test/ngAnimate/animateSpec.js b/test/ngAnimate/animateSpec.js index 47e7afffb83e..27eeb1129ee3 100644 --- a/test/ngAnimate/animateSpec.js +++ b/test/ngAnimate/animateSpec.js @@ -1181,6 +1181,49 @@ describe("ngAnimate", function() { expect(element.hasClass('some-class-add-active')).toBe(false); })); + it("should intelligently cancel former timeouts and close off a series of elements a final timeout", function() { + var cancellations = 0; + module(function($provide) { + $provide.decorator('$timeout', function($delegate) { + var _cancel = $delegate.cancel; + $delegate.cancel = function() { + cancellations++; + return _cancel.apply($delegate, arguments); + }; + return $delegate; + }); + }) + inject(function($animate, $rootScope, $compile, $sniffer, $timeout) { + if (!$sniffer.transitions) return; + + ss.addRule('.animate-me', '-webkit-transition:1s linear all;' + + 'transition:1s linear all;'); + + element = $compile(html('
'))($rootScope); + + $rootScope.items = [1,2,3,4,5,6,7,8,9,10]; + var totalOperations = $rootScope.items.length; + + $rootScope.$digest(); + + $rootScope.items = [0]; + $animate.triggerReflow(); + $timeout.flush(1500); + + expect(cancellations).toBeLessThan(totalOperations); + expect(element.children().length).toBe(10); + cancellations = 0; + + $rootScope.items = [1]; + $rootScope.$digest(); + + $animate.triggerReflow(); + $timeout.flush(1500); + expect(element.children().length).toBe(1); + expect(cancellations).toBeLessThan(totalOperations); + }); + }); + it("apply a closing timeout with respect to a staggering animation", inject(function($animate, $rootScope, $compile, $sniffer, $timeout) { From 7b230e91cd192d23b4afe37dd615f570ab22e6b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matias=20Niemel=C3=A4?= Date: Mon, 24 Feb 2014 15:12:38 -0500 Subject: [PATCH 2/2] test($animate): ensure staggering timeout tests are secure --- test/ngAnimate/animateSpec.js | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/test/ngAnimate/animateSpec.js b/test/ngAnimate/animateSpec.js index 27eeb1129ee3..55ec4ae8a22f 100644 --- a/test/ngAnimate/animateSpec.js +++ b/test/ngAnimate/animateSpec.js @@ -1259,7 +1259,15 @@ describe("ngAnimate", function() { } //(stagger * index) + (duration + delay) * 150% - $timeout.flush(9500); //0.5 * 4 + 5 * 1.5 = 9500; + //0.5 * 4 + 5 * 1.5 = 9500; + //9500 - 7500 = 2000 + $timeout.flush(1999); //remove 1999 more + + for(var i = 0; i < 5; i++) { + expect(kids[i].hasClass('ng-enter-active')).toBe(true); + } + + $timeout.flush(1); //up to 2000ms for(var i = 0; i < 5; i++) { expect(kids[i].hasClass('ng-enter-active')).toBe(false);