diff --git a/docs/components/angular-bootstrap/bootstrap-prettify.js b/docs/components/angular-bootstrap/bootstrap-prettify.js index 169d232b6075..c0496c2c4d30 100644 --- a/docs/components/angular-bootstrap/bootstrap-prettify.js +++ b/docs/components/angular-bootstrap/bootstrap-prettify.js @@ -199,7 +199,6 @@ directive.ngEmbedApp = ['$templateCache', '$browser', '$rootScope', '$location', deregisterEmbedRootScope; modules.push(['$provide', function($provide) { - $provide.value('$animate', $animate); $provide.value('$templateCache', $templateCache); $provide.value('$anchorScroll', angular.noop); $provide.value('$browser', $browser); diff --git a/src/ng/animate.js b/src/ng/animate.js index 22675a13363b..fbd17848eba8 100644 --- a/src/ng/animate.js +++ b/src/ng/animate.js @@ -98,7 +98,7 @@ var $AnimateProvider = ['$provide', function($provide) { forEach(element, function(node) { parentNode.insertBefore(node, afterNextSibling); }); - $timeout(done || noop, 0, false); + done && $timeout(done, 0, false); }, /** @@ -115,7 +115,7 @@ var $AnimateProvider = ['$provide', function($provide) { */ leave : function(element, done) { element.remove(); - $timeout(done || noop, 0, false); + done && $timeout(done, 0, false); }, /** @@ -157,7 +157,7 @@ var $AnimateProvider = ['$provide', function($provide) { className : isArray(className) ? className.join(' ') : ''; element.addClass(className); - $timeout(done || noop, 0, false); + done && $timeout(done, 0, false); }, /** @@ -178,7 +178,7 @@ var $AnimateProvider = ['$provide', function($provide) { className : isArray(className) ? className.join(' ') : ''; element.removeClass(className); - $timeout(done || noop, 0, false); + done && $timeout(done, 0, false); }, enabled : noop diff --git a/src/ng/rootScope.js b/src/ng/rootScope.js index 18c544340c44..d3b2762d8c01 100644 --- a/src/ng/rootScope.js +++ b/src/ng/rootScope.js @@ -119,6 +119,7 @@ function $RootScopeProvider(){ this['this'] = this.$root = this; this.$$destroyed = false; this.$$asyncQueue = []; + this.$$postDigestQueue = []; this.$$listeners = {}; this.$$isolateBindings = {}; } @@ -133,6 +134,7 @@ function $RootScopeProvider(){ Scope.prototype = { + constructor: Scope, /** * @ngdoc function * @name ng.$rootScope.Scope#$new @@ -167,6 +169,7 @@ function $RootScopeProvider(){ child.$root = this.$root; // ensure that there is just one async queue per $rootScope and it's children child.$$asyncQueue = this.$$asyncQueue; + child.$$postDigestQueue = this.$$postDigestQueue; } else { Child = function() {}; // should be anonymous; This is so that when the minifier munges // the name it does not become random set of chars. These will then show up as class @@ -494,6 +497,7 @@ function $RootScopeProvider(){ var watch, value, last, watchers, asyncQueue = this.$$asyncQueue, + postDigestQueue = this.$$postDigestQueue, length, dirty, ttl = TTL, next, current, target = this, @@ -566,6 +570,14 @@ function $RootScopeProvider(){ } while (dirty || asyncQueue.length); clearPhase(); + + while(postDigestQueue.length) { + try { + postDigestQueue.shift()(); + } catch (e) { + $exceptionHandler(e); + } + } }, @@ -696,6 +708,10 @@ function $RootScopeProvider(){ this.$$asyncQueue.push(expr); }, + $$postDigest : function(expr) { + this.$$postDigestQueue.push(expr); + }, + /** * @ngdoc function * @name ng.$rootScope.Scope#$apply diff --git a/src/ngAnimate/animate.js b/src/ngAnimate/animate.js index 32bbd6d50f85..ca136a504942 100644 --- a/src/ngAnimate/animate.js +++ b/src/ngAnimate/animate.js @@ -201,9 +201,9 @@ angular.module('ngAnimate', ['ng']) var NG_ANIMATE_STATE = '$$ngAnimateState'; var rootAnimateState = {running:true}; - $provide.decorator('$animate', ['$delegate', '$injector', '$sniffer', '$rootElement', '$timeout', - function($delegate, $injector, $sniffer, $rootElement, $timeout) { - + $provide.decorator('$animate', ['$delegate', '$injector', '$sniffer', '$rootElement', '$timeout', '$rootScope', + function($delegate, $injector, $sniffer, $rootElement, $timeout, $rootScope) { + $rootElement.data(NG_ANIMATE_STATE, rootAnimateState); function lookup(name) { @@ -282,8 +282,10 @@ angular.module('ngAnimate', ['ng']) */ enter : function(element, parent, after, done) { $delegate.enter(element, parent, after); - performAnimation('enter', 'ng-enter', element, parent, after, function() { - $timeout(done || noop, 0, false); + $rootScope.$$postDigest(function() { + performAnimation('enter', 'ng-enter', element, parent, after, function() { + done && $timeout(done, 0, false); + }); }); }, @@ -315,8 +317,10 @@ angular.module('ngAnimate', ['ng']) * @param {function()=} done callback function that will be called once the animation is complete */ leave : function(element, done) { - performAnimation('leave', 'ng-leave', element, null, null, function() { - $delegate.leave(element, done); + $rootScope.$$postDigest(function() { + performAnimation('leave', 'ng-leave', element, null, null, function() { + $delegate.leave(element, done); + }); }); }, @@ -352,8 +356,10 @@ angular.module('ngAnimate', ['ng']) */ move : function(element, parent, after, done) { $delegate.move(element, parent, after); - performAnimation('move', 'ng-move', element, null, null, function() { - $timeout(done || noop, 0, false); + $rootScope.$$postDigest(function() { + performAnimation('move', 'ng-move', element, null, null, function() { + done && $timeout(done, 0, false); + }); }); }, @@ -550,6 +556,7 @@ angular.module('ngAnimate', ['ng']) var durationKey = 'Duration', delayKey = 'Delay', + propertyKey = 'Property', animationIterationCountKey = 'IterationCount', ELEMENT_NODE = 1; @@ -610,15 +617,25 @@ angular.module('ngAnimate', ['ng']) timeout is empty (this would cause a flicker bug normally in the page */ if(duration > 0) { + var node = element[0]; + + //temporarily disable the transition so that the enter styles + //don't animate twice (this is here to avoid a bug in Chrome/FF). + node.style[w3cTransitionProp + propertyKey] = 'none'; + node.style[vendorTransitionProp + propertyKey] = 'none'; + var activeClassName = ''; forEach(className.split(' '), function(klass, i) { activeClassName += (i > 0 ? ' ' : '') + klass + '-active'; }); - $timeout(function() { - element.addClass(activeClassName); - $timeout(done, duration * 1000, false); - },0,false); + //this triggers a reflow which allows for the transition animation to kick in + element.prop('clientWidth'); + node.style[w3cTransitionProp + propertyKey] = ''; + node.style[vendorTransitionProp + propertyKey] = ''; + element.addClass(activeClassName); + + $timeout(done, duration * 1000, false); //this will automatically be called by $animate so //there is no need to attach this internally to the diff --git a/src/ngRoute/directive/ngView.js b/src/ngRoute/directive/ngView.js index 3b97367c1bae..d67d8a76d53e 100644 --- a/src/ngRoute/directive/ngView.js +++ b/src/ngRoute/directive/ngView.js @@ -176,6 +176,7 @@ function ngViewFactory( $route, $anchorScroll, $compile, $controller, return { restrict: 'ECA', terminal: true, + priority: 1000, transclude: 'element', compile: function(element, attr, linker) { return function(scope, $element, attr) { diff --git a/test/ng/directive/ngClassSpec.js b/test/ng/directive/ngClassSpec.js index 54dee1420744..f0989f4a9531 100644 --- a/test/ng/directive/ngClassSpec.js +++ b/test/ng/directive/ngClassSpec.js @@ -308,42 +308,107 @@ describe('ngClass', function() { describe('ngClass animations', function() { var body, element, $rootElement; - beforeEach(module('mock.animate')); - - it("should avoid calling addClass accidentally when removeClass is going on", + it("should avoid calling addClass accidentally when removeClass is going on", function() { + module('mock.animate'); inject(function($compile, $rootScope, $animate, $timeout) { + var element = angular.element('
'); + var body = jqLite(document.body); + body.append(element); + $compile(element)($rootScope); - var element = angular.element(''); - var body = jqLite(document.body); - body.append(element); - $compile(element)($rootScope); + expect($animate.queue.length).toBe(0); - expect($animate.queue.length).toBe(0); + $rootScope.val = 'one'; + $rootScope.$digest(); + $animate.flushNext('addClass'); + $animate.flushNext('addClass'); + expect($animate.queue.length).toBe(0); - $rootScope.val = 'one'; - $rootScope.$digest(); - $animate.flushNext('addClass'); - $animate.flushNext('addClass'); - $timeout.flush(); - expect($animate.queue.length).toBe(0); + $rootScope.val = ''; + $rootScope.$digest(); + $animate.flushNext('removeClass'); //only removeClass is called + expect($animate.queue.length).toBe(0); - $rootScope.val = ''; - $rootScope.$digest(); - $animate.flushNext('removeClass'); //only removeClass is called - expect($animate.queue.length).toBe(0); - $timeout.flush(); + $rootScope.val = 'one'; + $rootScope.$digest(); + $animate.flushNext('addClass'); + expect($animate.queue.length).toBe(0); - $rootScope.val = 'one'; - $rootScope.$digest(); - $animate.flushNext('addClass'); - $timeout.flush(); - expect($animate.queue.length).toBe(0); + $rootScope.val = 'two'; + $rootScope.$digest(); + $animate.flushNext('removeClass'); + $animate.flushNext('addClass'); + expect($animate.queue.length).toBe(0); + }); + }); - $rootScope.val = 'two'; - $rootScope.$digest(); - $animate.flushNext('removeClass'); - $animate.flushNext('addClass'); - $timeout.flush(); - expect($animate.queue.length).toBe(0); - })); + it("should consider the ngClass expression evaluation before performing an animation", function() { + + //mocks are not used since the enter delegation method is called before addClass and + //it makes it impossible to test to see that addClass is called first + module('ngAnimate'); + + var digestQueue = []; + module(function($animateProvider) { + $animateProvider.register('.crazy', function() { + return { + enter : function(element, done) { + element.data('state', 'crazy-enter'); + done(); + } + }; + }); + + return function($rootScope) { + var before = $rootScope.$$postDigest; + $rootScope.$$postDigest = function() { + var args = arguments; + digestQueue.push(function() { + before.apply($rootScope, args); + }); + }; + }; + }); + inject(function($compile, $rootScope, $rootElement, $animate, $timeout, $document) { + + //since we skip animations upon first digest, this needs to be set to true + $animate.enabled(true); + + $rootScope.val = 'crazy'; + var element = angular.element(''); + jqLite($document[0].body).append($rootElement); + + $compile(element)($rootScope); + + var enterComplete = false; + $animate.enter(element, $rootElement, null, function() { + enterComplete = true; + }); + + //jquery doesn't compare both elements properly so let's use the nodes + expect(element.parent()[0]).toEqual($rootElement[0]); + expect(element.hasClass('crazy')).toBe(false); + expect(enterComplete).toBe(false); + + expect(digestQueue.length).toBe(1); + $rootScope.$digest(); + + $timeout.flush(); + + expect(element.hasClass('crazy')).toBe(true); + expect(enterComplete).toBe(false); + + digestQueue.shift()(); //enter + expect(digestQueue.length).toBe(0); + + //we don't normally need this, but since the timing between digests + //is spaced-out then it is required so that the original digestion + //is kicked into gear + $rootScope.$digest(); + $timeout.flush(); + + expect(element.data('state')).toBe('crazy-enter'); + expect(enterComplete).toBe(true); + }); + }); }); diff --git a/test/ng/rootScopeSpec.js b/test/ng/rootScopeSpec.js index d6a684a79a3d..656385e9681c 100644 --- a/test/ng/rootScopeSpec.js +++ b/test/ng/rootScopeSpec.js @@ -12,6 +12,12 @@ describe('Scope', function() { })); + it('should expose the constructor', inject(function($rootScope) { + if (msie) return; + expect($rootScope.__proto__).toBe($rootScope.constructor.prototype); + })); + + it('should not have $root on children, but should inherit', inject(function($rootScope) { var child = $rootScope.$new(); expect(child.$root).toEqual($rootScope); @@ -672,6 +678,74 @@ describe('Scope', function() { expect(log).toEqual('parent.async;child.async;parent.$digest;child.$digest;'); })); + it('should not run another digest for an $$postDigest call', inject(function($rootScope) { + var internalWatchCount = 0; + var externalWatchCount = 0; + + $rootScope.internalCount = 0; + $rootScope.externalCount = 0; + + $rootScope.$evalAsync(function(scope) { + $rootScope.internalCount++; + }); + + $rootScope.$$postDigest(function(scope) { + $rootScope.externalCount++; + }); + + $rootScope.$watch('internalCount', function(value) { + internalWatchCount = value; + }); + $rootScope.$watch('externalCount', function(value) { + externalWatchCount = value; + }); + + $rootScope.$digest(); + + expect(internalWatchCount).toEqual(1); + expect(externalWatchCount).toEqual(0); + })); + + it('should run a $$postDigest call on all child scopes when a parent scope is digested', inject(function($rootScope) { + var parent = $rootScope.$new(), + child = parent.$new(), + count = 0; + + $rootScope.$$postDigest(function() { + count++; + }); + + parent.$$postDigest(function() { + count++; + }); + + child.$$postDigest(function() { + count++; + }); + + expect(count).toBe(0); + $rootScope.$digest(); + expect(count).toBe(3); + })); + + it('should run a $$postDigest call even if the child scope is isolated', inject(function($rootScope) { + var parent = $rootScope.$new(), + child = parent.$new(true), + signature = ''; + + parent.$$postDigest(function() { + signature += 'A'; + }); + + child.$$postDigest(function() { + signature += 'B'; + }); + + expect(signature).toBe(''); + $rootScope.$digest(); + expect(signature).toBe('AB'); + })); + it('should cause a $digest rerun', inject(function($rootScope) { $rootScope.log = ''; $rootScope.value = 0; diff --git a/test/ngAnimate/animateSpec.js b/test/ngAnimate/animateSpec.js index 7c5848e2e0ee..661cc91e87a6 100644 --- a/test/ngAnimate/animateSpec.js +++ b/test/ngAnimate/animateSpec.js @@ -133,15 +133,13 @@ describe("ngAnimate", function() { expect(element.contents().length).toBe(0); $animate.enter(child, element); - $timeout.flushNext(0); + $rootScope.$digest(); if($sniffer.transitions) { expect(child.hasClass('ng-enter')).toBe(true); - $timeout.flushNext(0); expect(child.hasClass('ng-enter-active')).toBe(true); - $timeout.flushNext(1000); + $timeout.flush(); } - $timeout.flush(); expect(element.contents().length).toBe(1); })); @@ -151,13 +149,13 @@ describe("ngAnimate", function() { expect(element.contents().length).toBe(1); $animate.leave(child); + $rootScope.$digest(); + if($sniffer.transitions) { expect(child.hasClass('ng-leave')).toBe(true); - $timeout.flushNext(0); expect(child.hasClass('ng-leave-active')).toBe(true); - $timeout.flushNext(1000); + $timeout.flush(); } - $timeout.flush(); expect(element.contents().length).toBe(0); })); @@ -174,6 +172,7 @@ describe("ngAnimate", function() { element.append(child2); expect(element.text()).toBe('12'); $animate.move(child1, element, child2); + $rootScope.$digest(); expect(element.text()).toBe('21'); })); @@ -186,9 +185,8 @@ describe("ngAnimate", function() { $animate.removeClass(child, 'ng-hide'); if($sniffer.transitions) { expect(child.hasClass('ng-hide-remove')).toBe(true); - $timeout.flushNext(0); expect(child.hasClass('ng-hide-remove-active')).toBe(true); - $timeout.flushNext(1000); + $timeout.flush(); } expect(child.hasClass('ng-hide-remove')).toBe(false); expect(child.hasClass('ng-hide-remove-active')).toBe(false); @@ -203,11 +201,9 @@ describe("ngAnimate", function() { $animate.addClass(child, 'ng-hide'); if($sniffer.transitions) { expect(child.hasClass('ng-hide-add')).toBe(true); - $timeout.flushNext(0); expect(child.hasClass('ng-hide-add-active')).toBe(true); - $timeout.flushNext(1000); + $timeout.flush(); } - $timeout.flush(); expect(child).toBeHidden(); })); @@ -221,46 +217,39 @@ describe("ngAnimate", function() { //enter $animate.enter(child, element); - $timeout.flushNext(0); + $rootScope.$digest(); + expect(child.attr('class')).toContain('ng-enter'); - $timeout.flushNext(0); expect(child.attr('class')).toContain('ng-enter-active'); $timeout.flushNext(1000); - $timeout.flushNext(0); //move element.append(after); $animate.move(child, element, after); - $timeout.flushNext(0); + $rootScope.$digest(); + expect(child.attr('class')).toContain('ng-move'); - $timeout.flushNext(0); expect(child.attr('class')).toContain('ng-move-active'); $timeout.flushNext(1000); - $timeout.flushNext(0); //hide $animate.addClass(child, 'ng-hide'); expect(child.attr('class')).toContain('ng-hide-add'); - $timeout.flushNext(0); expect(child.attr('class')).toContain('ng-hide-add-active'); $timeout.flushNext(1000); - $timeout.flushNext(0); //show $animate.removeClass(child, 'ng-hide'); expect(child.attr('class')).toContain('ng-hide-remove'); - $timeout.flushNext(0); expect(child.attr('class')).toContain('ng-hide-remove-active'); $timeout.flushNext(1000); - $timeout.flushNext(0); //leave $animate.leave(child); + $rootScope.$digest(); expect(child.attr('class')).toContain('ng-leave'); - $timeout.flushNext(0); expect(child.attr('class')).toContain('ng-leave-active'); $timeout.flushNext(1000); - $timeout.flushNext(0); })); it("should not run if animations are disabled", @@ -276,12 +265,10 @@ describe("ngAnimate", function() { expect(element.text()).toBe('123'); $animate.removeClass(element, 'ng-hide'); expect(element.text()).toBe('123'); - $timeout.flushNext(0); //fires the addClass callback $animate.enabled(true); $animate.removeClass(element, 'ng-hide'); - $timeout.flushNext(0); expect(element.text()).toBe('memento'); })); @@ -296,23 +283,20 @@ describe("ngAnimate", function() { expect(child).toBeShown(); $animate.leave(child); + $rootScope.$digest(); expect(child).toBeHidden(); //hides instantly //lets change this to prove that done doesn't fire anymore for the previous hide() operation child.css('display','block'); child.removeClass('ng-hide'); - $timeout.flushNext(0); if($sniffer.transitions) { - $timeout.flushNext(0); - $timeout.flushNext(0); expect(element.children().length).toBe(1); //still animating $timeout.flushNext(1000); $timeout.flushNext(1000); } $timeout.flushNext(2000); $timeout.flushNext(2000); - $timeout.flushNext(0); expect(child).toBeShown(); expect(element.children().length).toBe(0); @@ -326,7 +310,6 @@ describe("ngAnimate", function() { child.addClass('custom-delay ng-hide'); $animate.removeClass(child, 'ng-hide'); if($sniffer.transitions) { - $timeout.flushNext(0); $timeout.flushNext(1000); } $timeout.flushNext(2000); @@ -371,7 +354,6 @@ describe("ngAnimate", function() { $animate.addClass(element, 'custom-delay custom-long-delay'); $timeout.flushNext(2000); $timeout.flushNext(20000); - $timeout.flushNext(0); expect(element.hasClass('custom-delay')).toBe(true); expect(element.hasClass('custom-long-delay')).toBe(true); })); @@ -392,12 +374,10 @@ describe("ngAnimate", function() { $animate.removeClass(element, 'ng-hide'); if($sniffer.transitions) { - $timeout.flushNext(0); $timeout.flushNext(1000); } $timeout.flushNext(2000); $timeout.flushNext(20000); - $timeout.flushNext(0); expect(element.hasClass('custom-delay')).toBe(true); expect(element.hasClass('custom-delay-add')).toBe(false); @@ -437,7 +417,6 @@ describe("ngAnimate", function() { $animate.removeClass(element, 'ng-hide'); if ($sniffer.animations) { - $timeout.flushNext(0); $timeout.flushNext(4000); } expect(element).toBeShown(); @@ -461,7 +440,6 @@ describe("ngAnimate", function() { $animate.removeClass(element, 'ng-hide'); if ($sniffer.animations) { - $timeout.flushNext(0); $timeout.flushNext(6000); } expect(element).toBeShown(); @@ -485,7 +463,6 @@ describe("ngAnimate", function() { $animate.removeClass(element, 'ng-hide'); if ($sniffer.animations) { - $timeout.flushNext(0); $timeout.flushNext(2000); } expect(element).toBeShown(); @@ -511,7 +488,6 @@ describe("ngAnimate", function() { $animate.removeClass(element, 'ng-hide'); if ($sniffer.transitions) { - $timeout.flushNext(0); $timeout.flushNext(20000); } expect(element).toBeShown(); @@ -548,18 +524,15 @@ describe("ngAnimate", function() { $animate.removeClass(element, 'ng-hide'); if($sniffer.animations) { expect(element.hasClass('ng-hide-remove')).toBe(true); - $timeout.flushNext(0); expect(element.hasClass('ng-hide-remove-active')).toBe(true); } $animate.addClass(element, 'ng-hide'); expect(element.hasClass('ng-hide-remove')).toBe(false); //added right away - $timeout.flushNext(0); if($sniffer.animations) { //cleanup some pending animations expect(element.hasClass('ng-hide-add')).toBe(true); - $timeout.flushNext(0); expect(element.hasClass('ng-hide-add-active')).toBe(true); $timeout.flushNext(2000); } @@ -584,8 +557,7 @@ describe("ngAnimate", function() { element.addClass('ng-hide'); expect(element).toBeHidden(); $animate.removeClass(element, 'ng-hide'); - $timeout.flushNext(0); - $timeout.flushNext(0); + $timeout.flush(); expect(element).toBeShown(); $animate.enabled(true); @@ -595,10 +567,8 @@ describe("ngAnimate", function() { $animate.removeClass(element, 'ng-hide'); if ($sniffer.transitions) { - $timeout.flushNext(0); $timeout.flushNext(1000); } - $timeout.flushNext(0); expect(element).toBeShown(); })); @@ -618,10 +588,8 @@ describe("ngAnimate", function() { $animate.removeClass(element, 'ng-hide'); if ($sniffer.transitions) { expect(element).toBeHidden(); - $timeout.flushNext(0); $timeout.flushNext(2000); } - $timeout.flush(); expect(element).toBeShown(); })); @@ -643,9 +611,7 @@ describe("ngAnimate", function() { element.addClass('ng-hide'); $animate.removeClass(element, 'ng-hide'); $timeout.flushNext(0); - $timeout.flushNext(0); expect(element).toBeShown(); - $animate.enabled(true); element.addClass('ng-hide'); @@ -653,10 +619,8 @@ describe("ngAnimate", function() { $animate.removeClass(element, 'ng-hide'); if ($sniffer.transitions) { - $timeout.flushNext(0); $timeout.flushNext(3000); } - $timeout.flush(); expect(element).toBeShown(); })); @@ -677,7 +641,6 @@ describe("ngAnimate", function() { $animate.removeClass(element, 'ng-hide'); if ($sniffer.transitions) { - $timeout.flushNext(0); $timeout.flushNext(11000); } expect(element).toBeShown(); @@ -697,11 +660,9 @@ describe("ngAnimate", function() { $animate.removeClass(element, 'ng-hide'); if($sniffer.transitions) { expect(element.hasClass('ng-hide-remove')).toBe(true); - $timeout.flushNext(0); expect(element.hasClass('ng-hide-remove-active')).toBe(true); $timeout.flushNext(1000); } - $timeout.flushNext(0); expect(element.hasClass('ng-hide-remove')).toBe(false); expect(element.hasClass('ng-hide-remove-active')).toBe(false); expect(element).toBeShown(); @@ -709,7 +670,6 @@ describe("ngAnimate", function() { $animate.addClass(element, 'ng-hide'); if($sniffer.transitions) { expect(element.hasClass('ng-hide-add')).toBe(true); - $timeout.flushNext(0); expect(element.hasClass('ng-hide-add-active')).toBe(true); } })); @@ -732,28 +692,24 @@ describe("ngAnimate", function() { element[0].className = 'abc'; $animate.enter(element, parent); - $timeout.flushNext(0); + $rootScope.$digest(); if ($sniffer.transitions) { expect(element.hasClass('abc ng-enter')).toBe(true); - $timeout.flushNext(0); expect(element.hasClass('abc ng-enter ng-enter-active')).toBe(true); $timeout.flushNext(22000); } - $timeout.flushNext(0); expect(element.hasClass('abc')).toBe(true); element[0].className = 'xyz'; $animate.enter(element, parent); - $timeout.flushNext(0); + $rootScope.$digest(); if ($sniffer.transitions) { expect(element.hasClass('xyz')).toBe(true); - $timeout.flushNext(0); expect(element.hasClass('xyz ng-enter ng-enter-active')).toBe(true); $timeout.flushNext(22000); } - $timeout.flushNext(0); expect(element.hasClass('xyz')).toBe(true); })); @@ -773,10 +729,9 @@ describe("ngAnimate", function() { element.attr('class','one two'); $animate.enter(element, parent); - $timeout.flushNext(0); + $rootScope.$digest(); if($sniffer.transitions) { expect(element.hasClass('one two ng-enter')).toBe(true); - $timeout.flushNext(0); expect(element.hasClass('one two ng-enter ng-enter-active')).toBe(true); expect(element.hasClass('one-active')).toBe(false); expect(element.hasClass('two-active')).toBe(false); @@ -824,9 +779,9 @@ describe("ngAnimate", function() { $animate.enter(element, parent, null, function() { flag = true; }); + $rootScope.$digest(); - $timeout.flushNext(0); //move operation callback - $timeout.flushNext(0); //ngAnimate callback + $timeout.flush(); expect(flag).toBe(true); })); @@ -843,8 +798,10 @@ describe("ngAnimate", function() { $animate.leave(element, function() { flag = true; }); + $rootScope.$digest(); + + $timeout.flush(); - $timeout.flushNext(0); expect(flag).toBe(true); })); @@ -861,9 +818,9 @@ describe("ngAnimate", function() { $animate.move(element, parent, parent2, function() { flag = true; }); + $rootScope.$digest(); - $timeout.flushNext(0); //move operation callback - $timeout.flushNext(0); //ngAnimate callback + $timeout.flush(); expect(flag).toBe(true); expect(element.parent().id).toBe(parent2.id); @@ -881,13 +838,13 @@ describe("ngAnimate", function() { $animate.addClass(element, 'on', function() { signature += 'A'; }); - $timeout.flushNext(0); $animate.removeClass(element, 'on', function() { signature += 'B'; }); - $timeout.flushNext(0); + $timeout.flush(); + expect(signature).toBe('AB'); })); @@ -904,8 +861,7 @@ describe("ngAnimate", function() { flag = true; }); - var timeoutDelay = $sniffer.transitions ? 1 : 0; - $timeout.flush(timeoutDelay); + $timeout.flush(); expect(flag).toBe(true); })); @@ -927,11 +883,7 @@ describe("ngAnimate", function() { flag = true; }); - if($sniffer.transitions) { - $timeout.flushNext(0); - $timeout.flushNext(1000); - } - $timeout.flushNext(0); + $timeout.flush(); expect(flag).toBe(true); })); @@ -949,8 +901,7 @@ describe("ngAnimate", function() { flag = true; }); - $timeout.flushNext(2000); - $timeout.flushNext(0); + $timeout.flush(); expect(flag).toBe(true); })); @@ -975,19 +926,7 @@ describe("ngAnimate", function() { signature += 'B'; }); - if($sniffer.transitions) { - $timeout.flushNext(0); //callback for removeClass - $timeout.flushNext(0); - $timeout.flushNext(0); - $timeout.flushNext(9000); - $timeout.flushNext(9000); - $timeout.flushNext(0); - } $animate.addClass(element, 'ng-hide'); //earlier animation cancelled - if($sniffer.transitions) { - $timeout.flushNext(0); - $timeout.flushNext(9000); - } $timeout.flush(); expect(signature).toBe('AB'); })); @@ -1023,12 +962,10 @@ describe("ngAnimate", function() { var element = jqLite(parent.find('span')); $animate.addClass(element,'klass'); - $timeout.flushNext(0); expect(element.hasClass('klass')).toBe(true); $animate.removeClass(element,'klass'); - $timeout.flushNext(0); expect(element.hasClass('klass')).toBe(false); expect(element.hasClass('klass-remove')).toBe(false); @@ -1049,16 +986,14 @@ describe("ngAnimate", function() { signature += 'A'; }); - $timeout.flushNext(0); expect(element.hasClass('klass')).toBe(true); $animate.removeClass(element,'klass', function() { signature += 'B'; }); - $timeout.flushNext(0); + $timeout.flush(); expect(element.hasClass('klass')).toBe(false); - expect(signature).toBe('AB'); })); @@ -1083,11 +1018,9 @@ describe("ngAnimate", function() { if($sniffer.transitions) { expect(element.hasClass('klass')).toBe(false); expect(element.hasClass('klass-add')).toBe(true); - $timeout.flushNext(0); expect(element.hasClass('klass-add-active')).toBe(true); $timeout.flushNext(3000); } - $timeout.flushNext(0); //this cancels out the older animation $animate.removeClass(element,'klass', function() { @@ -1099,7 +1032,6 @@ describe("ngAnimate", function() { expect(element.hasClass('klass-add')).toBe(false); expect(element.hasClass('klass-add-active')).toBe(false); - $timeout.flushNext(0); expect(element.hasClass('klass-remove')).toBe(true); } $timeout.flush(); @@ -1122,8 +1054,7 @@ describe("ngAnimate", function() { signature += 'X'; }); - $timeout.flushNext(500); - $timeout.flushNext(0); + $timeout.flush(500); expect(element.hasClass('klassy')).toBe(true); @@ -1131,8 +1062,7 @@ describe("ngAnimate", function() { signature += 'Y'; }); - $timeout.flushNext(3000); - $timeout.flushNext(0); + $timeout.flush(3000); expect(element.hasClass('klassy')).toBe(false); @@ -1159,14 +1089,13 @@ describe("ngAnimate", function() { }); if($sniffer.transitions) { expect(element.hasClass('klass-add')).toBe(true); - $timeout.flushNext(0); expect(element.hasClass('klass-add-active')).toBe(true); $timeout.flushNext(11000); expect(element.hasClass('klass-add')).toBe(false); expect(element.hasClass('klass-add-active')).toBe(false); } - $timeout.flushNext(0); + $timeout.flush(); expect(element.hasClass('klass')).toBe(true); $animate.removeClass(element,'klass', function() { @@ -1174,14 +1103,13 @@ describe("ngAnimate", function() { }); if($sniffer.transitions) { expect(element.hasClass('klass-remove')).toBe(true); - $timeout.flushNext(0); expect(element.hasClass('klass-remove-active')).toBe(true); $timeout.flushNext(11000); expect(element.hasClass('klass-remove')).toBe(false); expect(element.hasClass('klass-remove-active')).toBe(false); } - $timeout.flushNext(0); + $timeout.flush(); expect(element.hasClass('klass')).toBe(false); expect(signature).toBe('db'); @@ -1208,7 +1136,6 @@ describe("ngAnimate", function() { if($sniffer.transitions) { expect(element.hasClass('one-add')).toBe(true); expect(element.hasClass('two-add')).toBe(true); - $timeout.flushNext(0); expect(element.hasClass('one-add-active')).toBe(true); expect(element.hasClass('two-add-active')).toBe(true); @@ -1219,7 +1146,8 @@ describe("ngAnimate", function() { expect(element.hasClass('two-add')).toBe(false); expect(element.hasClass('two-add-active')).toBe(false); } - $timeout.flushNext(0); + + $timeout.flush(); expect(element.hasClass('one')).toBe(true); expect(element.hasClass('two')).toBe(true); @@ -1228,7 +1156,7 @@ describe("ngAnimate", function() { })); it("should allow for multiple css classes to be animated plus a callback when removed", - inject(function($animate, $rootScope, $sniffer, $rootElement, $timeout) { + inject(function($animate, $rootScope, $sniffer, $rootElement, $timeout, filterFilter) { ss.addRule('.one-remove', 'transition:9s linear all;' + vendorPrefix + 'transition:9s linear all'); @@ -1252,7 +1180,6 @@ describe("ngAnimate", function() { if($sniffer.transitions) { expect(element.hasClass('one-remove')).toBe(true); expect(element.hasClass('two-remove')).toBe(true); - $timeout.flushNext(0); expect(element.hasClass('one-remove-active')).toBe(true); expect(element.hasClass('two-remove-active')).toBe(true); @@ -1263,7 +1190,8 @@ describe("ngAnimate", function() { expect(element.hasClass('two-remove')).toBe(false); expect(element.hasClass('two-remove-active')).toBe(false); } - $timeout.flushNext(0); + + $timeout.flush(); expect(element.hasClass('one')).toBe(false); expect(element.hasClass('two')).toBe(false); @@ -1300,11 +1228,10 @@ describe("ngAnimate", function() { var child = $compile('