From 0e5106ec2ccc8596c589b89074d3b27d27bf395a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matias=20Niemel=C3=A4?= Date: Fri, 21 Mar 2014 19:07:58 -0400 Subject: [PATCH] fix($animate): run CSS animations before JS animations to avoid style inheritance If a JS animation is run before a CSS animation then the JS animation may end up writing style data to the element. If any transition or animation style data is written then it may end up being accidentally inherited into the CSS animation hanlder that ngAnimate uses. This may result in an unexpected outcome due to the tweaks and hacks that the CSS handler places on the element. If the CSS animation is run before the JS animation then, if there are no transitions on the style attribute nor within the global CSS on the page then nothing will happen and the JS animation can work as expected. Closes #6675 --- src/ngAnimate/animate.js | 7 +++++-- test/ngAnimate/animateSpec.js | 31 +++++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+), 2 deletions(-) diff --git a/src/ngAnimate/animate.js b/src/ngAnimate/animate.js index 0466cecb1715..269db9227a3b 100644 --- a/src/ngAnimate/animate.js +++ b/src/ngAnimate/animate.js @@ -332,9 +332,12 @@ angular.module('ngAnimate', ['ng']) //operation which performs CSS transition and keyframe //animations sniffing. This is always included for each //element animation procedure if the browser supports - //transitions and/or keyframe animations + //transitions and/or keyframe animations. The default + //animation is added to the top of the list to prevent + //any previous animations from affecting the element styling + //prior to the element being animated. if ($sniffer.transitions || $sniffer.animations) { - classes.push(''); + matches.push($injector.get(selectors[''])); } for(var i=0; i < classes.length; i++) { diff --git a/test/ngAnimate/animateSpec.js b/test/ngAnimate/animateSpec.js index 204ca9c32114..69cb657336fb 100644 --- a/test/ngAnimate/animateSpec.js +++ b/test/ngAnimate/animateSpec.js @@ -721,6 +721,37 @@ describe("ngAnimate", function() { }) }); + /* The CSS animation handler must always be rendered before the other JS animation + handlers. This is important since the CSS animation handler may place temporary + styling on the HTML element before the reflow commences which in turn may override + other transition or keyframe styles that any former JS animations may have placed + on the element: https://github.com/angular/angular.js/issues/6675 */ + it("should always perform the CSS animation before the JS animation", function() { + var log = []; + module(function($animateProvider) { + //CSS animation handler + $animateProvider.register('', function() { + return { + leave : function() { log.push('css'); } + } + }); + //custom JS animation handler + $animateProvider.register('.js-animation', function() { + return { + leave : function() { log.push('js'); } + } + }); + }); + inject(function($animate, $rootScope, $compile, $sniffer) { + if(!$sniffer.transitions) return; + + element = $compile(html('
'))($rootScope); + $animate.leave(element); + $rootScope.$digest(); + expect(log).toEqual(['css','js']); + }); + }); + describe("Animations", function() {