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
This commit is contained in:
Matias Niemelä
2014-03-21 19:07:58 -04:00
parent 3bf8d6c612
commit 2317af6851
2 changed files with 36 additions and 2 deletions

View File

@@ -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++) {

View File

@@ -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('<div class="js-animation"></div>'))($rootScope);
$animate.leave(element);
$rootScope.$digest();
expect(log).toEqual(['css','js']);
});
});
describe("Animations", function() {