Skip to content

Commit

Permalink
refactor($animate): use CSS3 transition/animation events instead of $…
Browse files Browse the repository at this point in the history
…timeouts to track ongoing animations

Closes angular#3629
Closes angular#3874
  • Loading branch information
matsko authored and jamesdaily committed Sep 25, 2013
1 parent d66e957 commit 0a61560
Show file tree
Hide file tree
Showing 2 changed files with 80 additions and 68 deletions.
31 changes: 18 additions & 13 deletions src/ngAnimate/animate.js
Original file line number Diff line number Diff line change
Expand Up @@ -549,13 +549,16 @@ angular.module('ngAnimate', ['ng'])
//one day all browsers will have these properties
var w3cAnimationProp = 'animation';
var w3cTransitionProp = 'transition';
var w3cAnimationEvent = 'animationend';
var w3cTransitionEvent = 'transitionend';

//but some still use vendor-prefixed styles
var vendorAnimationProp = $sniffer.vendorPrefix + 'Animation';
var vendorTransitionProp = $sniffer.vendorPrefix + 'Transition';
var vendorAnimationEvent = $sniffer.vendorPrefix.toLowerCase() + 'AnimationEnd';
var vendorTransitionEvent = $sniffer.vendorPrefix.toLowerCase() + 'TransitionEnd';

var durationKey = 'Duration',
delayKey = 'Delay',
propertyKey = 'Property',
animationIterationCountKey = 'IterationCount',
ELEMENT_NODE = 1;
Expand Down Expand Up @@ -584,17 +587,12 @@ angular.module('ngAnimate', ['ng'])
element.addClass(className);

//we want all the styles defined before and after
var duration = 0;
var transitionTime = 0,
animationTime = 0;
forEach(element, function(element) {
if (element.nodeType == ELEMENT_NODE) {
var elementStyles = $window.getComputedStyle(element) || {};

var transitionDelay = Math.max(parseMaxTime(elementStyles[w3cTransitionProp + delayKey]),
parseMaxTime(elementStyles[vendorTransitionProp + delayKey]));

var animationDelay = Math.max(parseMaxTime(elementStyles[w3cAnimationProp + delayKey]),
parseMaxTime(elementStyles[vendorAnimationProp + delayKey]));

var transitionDuration = Math.max(parseMaxTime(elementStyles[w3cTransitionProp + durationKey]),
parseMaxTime(elementStyles[vendorTransitionProp + durationKey]));

Expand All @@ -607,16 +605,16 @@ angular.module('ngAnimate', ['ng'])
1);
}

duration = Math.max(animationDelay + animationDuration,
transitionDelay + transitionDuration,
duration);
transitionTime = Math.max(transitionDuration, transitionTime);
animationTime = Math.max(animationDuration, animationTime);
}
});

/* there is no point in performing a reflow if the animation
timeout is empty (this would cause a flicker bug normally
in the page */
if(duration > 0) {
var totalTime = Math.max(transitionTime,animationTime);
if(totalTime > 0) {
var node = element[0];

//temporarily disable the transition so that the enter styles
Expand All @@ -635,12 +633,15 @@ angular.module('ngAnimate', ['ng'])
node.style[vendorTransitionProp + propertyKey] = '';
element.addClass(activeClassName);

$timeout(done, duration * 1000, false);
var css3AnimationEvents = [w3cAnimationEvent, vendorAnimationEvent,
w3cTransitionEvent, vendorTransitionEvent].join(' ');
element.on(css3AnimationEvents, onAnimationProgress);

//this will automatically be called by $animate so
//there is no need to attach this internally to the
//timeout done method
return function onEnd(cancelled) {
element.off(css3AnimationEvents, onAnimationProgress);
element.removeClass(className);
element.removeClass(activeClassName);

Expand All @@ -657,6 +658,10 @@ angular.module('ngAnimate', ['ng'])
done();
}

function onAnimationProgress(event) {
event.originalEvent.elapsedTime >= totalTime && done();
}

function parseMaxTime(str) {
var total = 0, values = angular.isString(str) ? str.split(/\s*,\s*/) : [];
forEach(values, function(value) {
Expand Down
Loading

0 comments on commit 0a61560

Please sign in to comment.