diff options
Diffstat (limited to 'src/ng/animator.js')
| -rw-r--r-- | src/ng/animator.js | 109 |
1 files changed, 88 insertions, 21 deletions
diff --git a/src/ng/animator.js b/src/ng/animator.js index a8064f5e..97c9e0ed 100644 --- a/src/ng/animator.js +++ b/src/ng/animator.js @@ -46,14 +46,16 @@ * Keep in mind that if an animation is running, no child element of such animation can also be animated. * * <h2>CSS-defined Animations</h2> - * By default, ngAnimate attaches two CSS3 classes per animation event to the DOM element to achieve the animation. - * It is up to you, the developer, to ensure that the animations take place using cross-browser CSS3 transitions. - * All that is required is the following CSS code: + * By default, ngAnimate attaches two CSS classes per animation event to the DOM element to achieve the animation. + * It is up to you, the developer, to ensure that the animations take place using cross-browser CSS3 transitions as + * well as CSS animations. + * + * The following code below demonstrates how to perform animations using **CSS transitions** with ngAnimate: * * <pre> * <style type="text/css"> * /* - * The animate-enter prefix is the event name that you + * The animate-enter CSS class is the event name that you * have provided within the ngAnimate attribute. * */ * .animate-enter-setup { @@ -81,16 +83,49 @@ * <div ng-directive ng-animate="{enter: 'animate-enter'}"></div> * </pre> * + * The following code below demonstrates how to perform animations using **CSS animations** with ngAnimate: + * + * <pre> + * <style type="text/css"> + * .animate-enter-setup { + * -webkit-animation: enter_sequence 1s linear; + * -moz-animation: enter_sequence 1s linear; + * -o-animation: enter_sequence 1s linear; + * animation: enter_sequence 1s linear; + * } + * @-webkit-keyframes enter_sequence { + * from { opacity:0; } + * to { opacity:1; } + * } + * @-moz-keyframes enter_sequence { + * from { opacity:0; } + * to { opacity:1; } + * } + * @-o-keyframes enter_sequence { + * from { opacity:0; } + * to { opacity:1; } + * } + * @keyframes enter_sequence { + * from { opacity:0; } + * to { opacity:1; } + * } + * </style> + * + * <div ng-directive ng-animate="{enter: 'animate-enter'}"></div> + * </pre> + * + * ngAnimate will first examine any CSS animation code and then fallback to using CSS transitions. + * * Upon DOM mutation, the setup class is added first, then the browser is allowed to reflow the content and then, * the start class is added to trigger the animation. The ngAnimate directive will automatically extract the duration * of the animation to determine when the animation ends. Once the animation is over then both CSS classes will be - * removed from the DOM. If a browser does not support CSS transitions then the animation will start and end + * removed from the DOM. If a browser does not support CSS transitions or CSS animations then the animation will start and end * immediately resulting in a DOM element that is at it's final state. This final state is when the DOM element - * has no CSS animation classes surrounding it. + * has no CSS transition/animation classes surrounding it. * * <h2>JavaScript-defined Animations</h2> - * In the event that you do not want to use CSS3 animations or if you wish to offer animations to browsers that do not - * yet support them, then you can make use of JavaScript animations defined inside ngModule. + * In the event that you do not want to use CSS3 transitions or CSS3 animations or if you wish to offer animations to browsers that do not + * yet support them, then you can make use of JavaScript animations defined inside of your AngularJS module. * * <pre> * var ngModule = angular.module('YourApp', []); @@ -117,8 +152,8 @@ * * As you can see, the JavaScript code follows a similar template to the CSS3 animations. Once defined, the animation * can be used in the same way with the ngAnimate attribute. Keep in mind that, when using JavaScript-enabled - * animations, ngAnimate will also add in the same CSS classes that CSS-enabled animations do (even if you're using - * JavaScript animations) to animated the element, but it will not attempt to find any CSS3 transition duration value. + * animations, ngAnimate will also add in the same CSS classes that CSS-enabled animations do (even if you're not using + * CSS animations) to animated the element, but it will not attempt to find any CSS3 transition or animation duration/delay values. * It will instead close off the animation once the provided done function is executed. So it's important that you * make sure your animations remember to fire off the done function once the animations are complete. * @@ -258,6 +293,14 @@ var $AnimatorProvider = function() { // $window.setTimeout(beginAnimation, 0); this was causing the element not to animate // keep at 1 for animation dom rerender $window.setTimeout(beginAnimation, 1); + } + + function parseMaxTime(str) { + var total = 0, values = isString(str) ? str.split(/\s*,\s*/) : []; + forEach(values, function(value) { + total = Math.max(parseFloat(value) || 0, total); + }); + return total; }; function beginAnimation() { @@ -265,21 +308,45 @@ var $AnimatorProvider = function() { if (polyfillStart) { polyfillStart(element, done, memento); } else if (isFunction($window.getComputedStyle)) { - var vendorTransitionProp = $sniffer.vendorPrefix + 'Transition'; - var w3cTransitionProp = 'transition'; //one day all browsers will have this + //one day all browsers will have these properties + var w3cAnimationProp = 'animation'; + var w3cTransitionProp = 'transition'; - var durationKey = 'Duration'; - var duration = 0; + //but some still use vendor-prefixed styles + var vendorAnimationProp = $sniffer.vendorPrefix + 'Animation'; + var vendorTransitionProp = $sniffer.vendorPrefix + 'Transition'; + var durationKey = 'Duration', + delayKey = 'Delay', + animationIterationCountKey = 'IterationCount', + duration = 0; + //we want all the styles defined before and after + var ELEMENT_NODE = 1; forEach(element, function(element) { - if (element.nodeType == 1) { - var globalStyles = $window.getComputedStyle(element) || {}; - duration = Math.max( - parseFloat(globalStyles[w3cTransitionProp + durationKey]) || - parseFloat(globalStyles[vendorTransitionProp + durationKey]) || - 0, - duration); + if (element.nodeType == ELEMENT_NODE) { + var w3cProp = w3cTransitionProp, + vendorProp = vendorTransitionProp, + iterations = 1, + elementStyles = $window.getComputedStyle(element) || {}; + + //use CSS Animations over CSS Transitions + if(parseFloat(elementStyles[w3cAnimationProp + durationKey]) > 0 || + parseFloat(elementStyles[vendorAnimationProp + durationKey]) > 0) { + w3cProp = w3cAnimationProp; + vendorProp = vendorAnimationProp; + iterations = Math.max(parseInt(elementStyles[w3cProp + animationIterationCountKey]) || 0, + parseInt(elementStyles[vendorProp + animationIterationCountKey]) || 0, + iterations); + } + + var parsedDelay = Math.max(parseMaxTime(elementStyles[w3cProp + delayKey]), + parseMaxTime(elementStyles[vendorProp + delayKey])); + + var parsedDuration = Math.max(parseMaxTime(elementStyles[w3cProp + durationKey]), + parseMaxTime(elementStyles[vendorProp + durationKey])); + + duration = Math.max(parsedDelay + (iterations * parsedDuration), duration); } }); $window.setTimeout(done, duration * 1000); |
