diff options
| author | Matias Niemelä | 2013-05-07 10:33:08 -0400 | 
|---|---|---|
| committer | Misko Hevery | 2013-05-08 15:56:53 -0700 | 
| commit | 14757874a7cea7961f31211b245c417bd4b20512 (patch) | |
| tree | ce626824368e2a5dd3849335b01eb36705e524b6 /src | |
| parent | 88c3480aff79e1ff5b1ed8bd7f1e05df8ea1e068 (diff) | |
| download | angular.js-14757874a7cea7961f31211b245c417bd4b20512.tar.bz2 | |
feat(ngAnimate): Add support for CSS3 Animations with working delays and multiple durations
Diffstat (limited to 'src')
| -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);  | 
