aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatias Niemelä2013-11-19 00:21:48 -0500
committerMatias Niemelä2013-11-21 20:48:15 -0500
commit6760d7a315d7ea5cbd4f8ab74b200f754a2041f4 (patch)
tree8e94b7e2e82f0b51ff4c436399e9bcf8adb73b86
parent062fbed8fc3f7bc55433f8c6915c27520e6f63c5 (diff)
downloadangular.js-6760d7a315d7ea5cbd4f8ab74b200f754a2041f4.tar.bz2
fix($animate): ensure keyframe animations are blocked around the reflow
Keyframe animations trigger on the first CSS class and not the second. This may cause a slight flicker during a stagger animation since the animation has already started before the stagger delay is considered. This fix ensures that the animation is blocked until the active animation starts which allows for staggering animations to take over properly. Closes #5018
-rw-r--r--src/ngAnimate/animate.js12
-rw-r--r--test/ngAnimate/animateSpec.js25
2 files changed, 37 insertions, 0 deletions
diff --git a/src/ngAnimate/animate.js b/src/ngAnimate/animate.js
index 1956d54c..4d3a5878 100644
--- a/src/ngAnimate/animate.js
+++ b/src/ngAnimate/animate.js
@@ -1002,6 +1002,8 @@ angular.module('ngAnimate', ['ng'])
element.addClass(NG_ANIMATE_FALLBACK_CLASS_NAME);
activeClassName += NG_ANIMATE_FALLBACK_ACTIVE_CLASS_NAME + ' ';
blockTransitions(element);
+ } else {
+ blockKeyframeAnimations(element);
}
forEach(className.split(' '), function(klass, i) {
@@ -1025,6 +1027,10 @@ angular.module('ngAnimate', ['ng'])
element[0].style[TRANSITION_PROP + PROPERTY_KEY] = 'none';
}
+ function blockKeyframeAnimations(element) {
+ element[0].style[ANIMATION_PROP] = 'none 0s';
+ }
+
function unblockTransitions(element) {
var node = element[0], prop = TRANSITION_PROP + PROPERTY_KEY;
if(node.style[prop] && node.style[prop].length > 0) {
@@ -1032,6 +1038,10 @@ angular.module('ngAnimate', ['ng'])
}
}
+ function unblockKeyframeAnimations(element) {
+ element[0].style[ANIMATION_PROP] = '';
+ }
+
function animateRun(element, className, activeAnimationComplete) {
var data = element.data(NG_ANIMATE_CSS_DATA_KEY);
if(!element.hasClass(className) || !data) {
@@ -1059,6 +1069,8 @@ angular.module('ngAnimate', ['ng'])
style += CSS_PREFIX + 'transition-property: ' + propertyStyle + ', ' + fallbackProperty + '; ';
style += CSS_PREFIX + 'transition-duration: ' + timings.transitionDurationStyle + ', ' + timings.transitionDuration + 's; ';
}
+ } else {
+ unblockKeyframeAnimations(element);
}
if(ii > 0) {
diff --git a/test/ngAnimate/animateSpec.js b/test/ngAnimate/animateSpec.js
index 2362576a..cbf9de63 100644
--- a/test/ngAnimate/animateSpec.js
+++ b/test/ngAnimate/animateSpec.js
@@ -2696,4 +2696,29 @@ describe("ngAnimate", function() {
expect(capturedProperty).not.toBe('none');
}));
+ it('should block and unblock keyframe animations around the reflow operation',
+ inject(function($rootScope, $compile, $rootElement, $document, $animate, $sniffer, $timeout) {
+
+ if (!$sniffer.animations) return;
+
+ $animate.enabled(true);
+
+ ss.addRule('.cross-animation', '-webkit-animation:1s my_animation;' +
+ 'animation:1s my_animation;');
+
+ var element = $compile('<div class="cross-animation"></div>')($rootScope);
+ $rootElement.append(element);
+ jqLite($document[0].body).append($rootElement);
+
+ var node = element[0];
+ var animationKey = $sniffer.vendorPrefix == 'Webkit' ? 'WebkitAnimation' : 'animation';
+
+ $animate.addClass(element, 'trigger-class');
+
+ expect(node.style[animationKey]).toContain('none');
+
+ $timeout.flush();
+
+ expect(node.style[animationKey]).not.toContain('none');
+ }));
});