fix($animate): ensure transition animations are unblocked before the dom operation occurs

Transitions are blocked when the base CSS class is added at the start of the animation. This
causes an issue if the followup CSS class contains animatable-styles. Now, once the animation
active state is triggered (when the animation CSS dom operation occurs) the animation itself
will always trigger an animate without a quick jump.

Closes #5014
Closes #4265
This commit is contained in:
Matias Niemelä 2013-11-18 16:20:22 -05:00
parent 76e4db6f3d
commit 062fbed8fc
2 changed files with 54 additions and 5 deletions

View file

@ -1001,7 +1001,7 @@ angular.module('ngAnimate', ['ng'])
if(timings.transitionDuration > 0) {
element.addClass(NG_ANIMATE_FALLBACK_CLASS_NAME);
activeClassName += NG_ANIMATE_FALLBACK_ACTIVE_CLASS_NAME + ' ';
node.style[TRANSITION_PROP + PROPERTY_KEY] = 'none';
blockTransitions(element);
}
forEach(className.split(' '), function(klass, i) {
@ -1021,6 +1021,17 @@ angular.module('ngAnimate', ['ng'])
return true;
}
function blockTransitions(element) {
element[0].style[TRANSITION_PROP + PROPERTY_KEY] = 'none';
}
function unblockTransitions(element) {
var node = element[0], prop = TRANSITION_PROP + PROPERTY_KEY;
if(node.style[prop] && node.style[prop].length > 0) {
node.style[prop] = '';
}
}
function animateRun(element, className, activeAnimationComplete) {
var data = element.data(NG_ANIMATE_CSS_DATA_KEY);
if(!element.hasClass(className) || !data) {
@ -1041,8 +1052,6 @@ angular.module('ngAnimate', ['ng'])
var applyFallbackStyle, style = '';
if(timings.transitionDuration > 0) {
node.style[TRANSITION_PROP + PROPERTY_KEY] = '';
var propertyStyle = timings.transitionPropertyStyle;
if(propertyStyle.indexOf('all') == -1) {
applyFallbackStyle = true;
@ -1150,6 +1159,7 @@ angular.module('ngAnimate', ['ng'])
//happen in the first place
var cancel = preReflowCancellation;
afterReflow(function() {
unblockTransitions(element);
//once the reflow is complete then we point cancel to
//the new cancellation function which will remove all of the
//animation properties from the active animation
@ -1213,7 +1223,10 @@ angular.module('ngAnimate', ['ng'])
beforeAddClass : function(element, className, animationCompleted) {
var cancellationMethod = animateBefore(element, suffixClasses(className, '-add'));
if(cancellationMethod) {
afterReflow(animationCompleted);
afterReflow(function() {
unblockTransitions(element);
animationCompleted();
});
return cancellationMethod;
}
animationCompleted();
@ -1226,7 +1239,10 @@ angular.module('ngAnimate', ['ng'])
beforeRemoveClass : function(element, className, animationCompleted) {
var cancellationMethod = animateBefore(element, suffixClasses(className, '-remove'));
if(cancellationMethod) {
afterReflow(animationCompleted);
afterReflow(function() {
unblockTransitions(element);
animationCompleted();
});
return cancellationMethod;
}
animationCompleted();

View file

@ -2663,4 +2663,37 @@ describe("ngAnimate", function() {
expect(element.hasClass('base-class')).toBe(true);
}));
it('should block and unblock transitions before the dom operation occurs',
inject(function($rootScope, $compile, $rootElement, $document, $animate, $sniffer, $timeout) {
if (!$sniffer.transitions) return;
$animate.enabled(true);
ss.addRule('.cross-animation', '-webkit-transition:1s linear all;' +
'transition:1s linear all;');
var capturedProperty = 'none';
var element = $compile('<div class="cross-animation"></div>')($rootScope);
$rootElement.append(element);
jqLite($document[0].body).append($rootElement);
var node = element[0];
node._setAttribute = node.setAttribute;
node.setAttribute = function(prop, val) {
if(prop == 'class' && val.indexOf('trigger-class') >= 0) {
var propertyKey = ($sniffer.vendorPrefix == 'Webkit' ? '-webkit-' : '') + 'transition-property';
capturedProperty = element.css(propertyKey);
}
node._setAttribute(prop, val);
};
$animate.addClass(element, 'trigger-class');
$timeout.flush();
expect(capturedProperty).not.toBe('none');
}));
});