PageSourceSearch

https://www.cispar.pr.gov.br/bower_components/angular-animate/angular-animate.js

js cispar.pr.gov.br collected 2026-10-09 21:55:05 UTC 74,520 bytes, 1,616 lines download raw bytes

1/**
2 * @license AngularJS v1.2.16
3 * (c) 2010-2014 Google, Inc. http://angularjs.org
4 * License: MIT
5 */
6(function(window, angular, undefined) {'use strict';
7
8/* jshint maxlen: false */
9
10/**
11 * @ngdoc module
12 * @name ngAnimate
13 * @description
14 *
15 * # ngAnimate
16 *
17 * The `ngAnimate` module provides support for JavaScript, CSS3 transition and CSS3 keyframe animation hooks within existing core and custom directives.
18 *
19 *
20 * <div doc-module-components="ngAnimate"></div>
21 *
22 * # Usage
23 *
24 * To see animations in action, all that is required is to define the appropriate CSS classes
25 * or to register a JavaScript animation via the myModule.animation() function. The directives that support animation automatically are:
26 * `ngRepeat`, `ngInclude`, `ngIf`, `ngSwitch`, `ngShow`, `ngHide`, `ngView` and `ngClass`. Custom directives can take advantage of animation
27 * by using the `$animate` service.
28 *
29 * Below is a more detailed breakdown of the supported animation events provided by pre-existing ng directives:
30 *
31 * | Directive                                                 | Supported Animations                               |
32 * |---------------------------------------------------------- |----------------------------------------------------|
33 * | {@link ng.directive:ngRepeat#usage_animations ngRepeat}         | enter, leave and move                              |
34 * | {@link ngRoute.directive:ngView#usage_animations ngView}        | enter and leave                                    |
35 * | {@link ng.directive:ngInclude#usage_animations ngInclude}       | enter and leave                                    |
36 * | {@link ng.directive:ngSwitch#usage_animations ngSwitch}         | enter and leave                                    |
37 * | {@link ng.directive:ngIf#usage_animations ngIf}                 | enter and leave                                    |
38 * | {@link ng.directive:ngClass#usage_animations ngClass}           | add and remove                                     |
39 * | {@link ng.directive:ngShow#usage_animations ngShow & ngHide}    | add and remove (the ng-hide class value)           |
40 * | {@link ng.directive:form#usage_animations form}                 | add and remove (dirty, pristine, valid, invalid & all other validations)                |
41 * | {@link ng.directive:ngModel#usage_animations ngModel}           | add and remove (dirty, pristine, valid, invalid & all other validations)                |
42 *
43 * You can find out more information about animations upon visiting each directive page.
44 *
45 * Below is an example of how to apply animations to a directive that supports animation hooks:
46 *
47 * ```html
48 * <style type="text/css">
49 * .slide.ng-enter, .slide.ng-leave {
50 *   -webkit-transition:0.5s linear all;
51 *   transition:0.5s linear all;
52 * }
53 *
54 * .slide.ng-enter { }        /&#42; starting animations for enter &#42;/
55 * .slide.ng-enter-active { } /&#42; terminal animations for enter &#42;/
56 * .slide.ng-leave { }        /&#42; starting animations for leave &#42;/
57 * .slide.ng-leave-active { } /&#42; terminal animations for leave &#42;/
58 * </style>
59 *
60 * <!--
61 * the animate service will automatically add .ng-enter and .ng-leave to the element
62 * to trigger the CSS transition/animations
63 * -->
64 * <ANY class="slide" ng-include="..."></ANY>
65 * ```
66 *
67 * Keep in mind that if an animation is running, any child elements cannot be animated until the parent element's
68 * animation has completed.
69 *
70 * <h2>CSS-defined Animations</h2>
71 * The animate service will automatically apply two CSS classes to the animated element and these two CSS classes
72 * are designed to contain the start and end CSS styling. Both CSS transitions and keyframe animations are supported
73 * and can be used to play along with this naming structure.
74 *
75 * The following code below demonstrates how to perform animations using **CSS transitions** with Angular:
76 *
77 * ```html
78 * <style type="text/css">
79 * /&#42;
80 *  The animate class is apart of the element and the ng-enter class
81 *  is attached to the element once the enter animation event is triggered
82 * &#42;/
83 * .reveal-animation.ng-enter {
84 *  -webkit-transition: 1s linear all; /&#42; Safari/Chrome &#42;/
85 *  transition: 1s linear all; /&#42; All other modern browsers and IE10+ &#42;/
86 *
87 *  /&#42; The animation preparation code &#42;/
88 *  opacity: 0;
89 * }
90 *
91 * /&#42;
92 *  Keep in mind that you want to combine both CSS
93 *  classes together to avoid any CSS-specificity
94 *  conflicts
95 * &#42;/
96 * .reveal-animation.ng-enter.ng-enter-active {
97 *  /&#42; The animation code itself &#42;/
98 *  opacity: 1;
99 * }
100 * </style>
101 *
102 * <div class="view-container">
103 *   <div ng-view class="reveal-animation"></div>
104 * </div>
105 * ```
106 *
107 * The following code below demonstrates how to perform animations using **CSS animations** with Angular:
108 *
109 * ```html
110 * <style type="text/css">
111 * .reveal-animation.ng-enter {
112 *   -webkit-animation: enter_sequence 1s linear; /&#42; Safari/Chrome &#42;/
113 *   animation: enter_sequence 1s linear; /&#42; IE10+ and Future Browsers &#42;/
114 * }
115 * @-webkit-keyframes enter_sequence {
116 *   from { opacity:0; }
117 *   to { opacity:1; }
118 * }
119 * @keyframes enter_sequence {
120 *   from { opacity:0; }
121 *   to { opacity:1; }
122 * }
123 * </style>
124 *
125 * <div class="view-container">
126 *   <div ng-view class="reveal-animation"></div>
127 * </div>
128 * ```
129 *
130 * Both CSS3 animations and transitions can be used together and the animate service will figure out the correct duration and delay timing.
131 *
132 * Upon DOM mutation, the event class is added first (something like `ng-enter`), then the browser prepares itself to add
133 * the active class (in this case `ng-enter-active`) which then triggers the animation. The animation module will automatically
134 * detect the CSS code to determine when the animation ends. Once the animation is over then both CSS classes will be
135 * removed from the DOM. If a browser does not support CSS transitions or CSS animations then the animation will start and end
136 * immediately resulting in a DOM element that is at its final state. This final state is when the DOM element
137 * has no CSS transition/animation classes applied to it.
138 *
139 * <h3>CSS Staggering Animations</h3>
140 * A Staggering animation is a collection of animations that are issued with a slight delay in between each successive operation resulting in a
141 * curtain-like effect. The ngAnimate module, as of 1.2.0, supports staggering animations and the stagger effect can be
142 * performed by creating a **ng-EVENT-stagger** CSS class and attaching that class to the base CSS class used for
143 * the animation. The style property expected within the stagger class can either be a **transition-delay** or an
144 * **animation-delay** property (or both if your animation contains both transitions and keyframe animations).
145 *
146 * ```css
147 * .my-animation.ng-enter {
148 *   /&#42; standard transition code &#42;/
149 *   -webkit-transition: 1s linear all;
150 *   transition: 1s linear all;
151 *   opacity:0;
152 * }
153 * .my-animation.ng-enter-stagger {
154 *   /&#42; this will have a 100ms delay between each successive leave animation &#42;/
155 *   -webkit-transition-delay: 0.1s;
156 *   transition-delay: 0.1s;
157 *
158 *   /&#42; in case the stagger doesn't work then these two values
159 *    must be set to 0 to avoid an accidental CSS inheritance &#42;/
160 *   -webkit-transition-duration: 0s;
161 *   transition-duration: 0s;
162 * }
163 * .my-animation.ng-enter.ng-enter-active {
164 *   /&#42; standard transition styles &#42;/
165 *   opacity:1;
166 * }
167 * ```
168 *
169 * Staggering animations work by default in ngRepeat (so long as the CSS class is defined). Outside of ngRepeat, to use staggering animations
170 * on your own, they can be triggered by firing multiple calls to the same event on $animate. However, the restrictions surrounding this
171 * are that each of the elements must have the same CSS className value as well as the same parent element. A stagger operation
172 * will also be reset if more than 10ms has passed after the last animation has been fired.
173 *
174 * The following code will issue the **ng-leave-stagger** event on the element provided:
175 *
176 * ```js
177 * var kids = parent.children();
178 *
179 * $animate.leave(kids[0]); //stagger index=0
180 * $animate.leave(kids[1]); //stagger index=1
181 * $animate.leave(kids[2]); //stagger index=2
182 * $animate.leave(kids[3]); //stagger index=3
183 * $animate.leave(kids[4]); //stagger index=4
184 *
185 * $timeout(function() {
186 *   //stagger has reset itself
187 *   $animate.leave(kids[5]); //stagger index=0
188 *   $animate.leave(kids[6]); //stagger index=1
189 * }, 100, false);
190 * ```
191 *
192 * Stagger animations are currently only supported within CSS-defined animations.
193 *
194 * <h2>JavaScript-defined Animations</h2>
195 * In the event that you do not want to use CSS3 transitions or CSS3 animations or if you wish to offer animations on browsers that do not
196 * yet support CSS transitions/animations, then you can make use of JavaScript animations defined inside of your AngularJS module.
197 *
198 * ```js
199 * //!annotate="YourApp" Your AngularJS Module|Replace this or ngModule with the module that you used to define your application.
200 * var ngModule = angular.module('YourApp', ['ngAnimate']);
201 * ngModule.animation('.my-crazy-animation', function() {
202 *   return {
203 *     enter: function(element, done) {
204 *       //run the animation here and call done when the animation is complete
205 *       return function(cancelled) {
206 *         //this (optional) function will be called when the animation
207 *         //completes or when the animation is cancelled (the cancelled
208 *         //flag will be set to true if cancelled).
209 *       };
210 *     },
211 *     leave: function(element, done) { },
212 *     move: function(element, done) { },
213 *
214 *     //animation that can be triggered before the class is added
215 *     beforeAddClass: function(element, className, done) { },
216 *
217 *     //animation that can be triggered after the class is added
218 *     addClass: function(element, className, done) { },
219 *
220 *     //animation that can be triggered before the class is removed
221 *     beforeRemoveClass: function(element, className, done) { },
222 *
223 *     //animation that can be triggered after the class is removed
224 *     removeClass: function(element, className, done) { }
225 *   };
226 * });
227 * ```
228 *
229 * JavaScript-defined animations are created with a CSS-like class selector and a collection of events which are set to run
230 * a javascript callback function. When an animation is triggered, $animate will look for a matching animation which fits
231 * the element's CSS class attribute value and then run the matching animation event function (if found).
232 * In other words, if the CSS classes present on the animated element match any of the JavaScript animations then the callback function will
233 * be executed. It should be also noted that only simple, single class selectors are allowed (compound class selectors are not supported).
234 *
235 * Within a JavaScript animation, an object containing various event callback animation functions is expected to be returned.
236 * As explained above, these callbacks are triggered based on the animation event. Therefore if an enter animation is run,
237 * and the JavaScript animation is found, then the enter callback will handle that animation (in addition to the CSS keyframe animation
238 * or transition code that is defined via a stylesheet).
239 *
240 */
241
242angular.module('ngAnimate', ['ng'])
243
244  /**
245   * @ngdoc provider
246   * @name $animateProvider
247   * @description
248   *
249   * The `$animateProvider` allows developers to register JavaScript animation event handlers directly inside of a module.
250   * When an animation is triggered, the $animate service will query the $animate service to find any animations that match
251   * the provided name value.
252   *
253   * Requires the {@link ngAnimate `ngAnimate`} module to be installed.
254   *
255   * Please visit the {@link ngAnimate `ngAnimate`} module overview page learn more about how to use animations in your application.
256   *
257   */
258
259  //this private service is only used within CSS-enabled animations
260  //IE8 + IE9 do not support rAF natively, but that is fine since they
261  //also don't support transitions and keyframes which means that the code
262  //below will never be used by the two browsers.
263  .factory('$$animateReflow', ['$$rAF', '$document', function($$rAF, $document) {
264    var bod = $document[0].body;
265    return function(fn) {
266      //the returned function acts as the cancellation function
267      return $$rAF(function() {
268        //the line below will force the browser to perform a repaint
269        //so that all the animated elements within the animation frame
270        //will be properly updated and drawn on screen. This is
271        //required to perform multi-class CSS based animations with
272        //Firefox. DO NOT REMOVE THIS LINE.
273        var a = bod.offsetWidth + 1;
274        fn();
275      });
276    };
277  }])
278
279  .config(['$provide', '$animateProvider', function($provide, $animateProvider) {
280    var noop = angular.noop;
281    var forEach = angular.forEach;
282    var selectors = $animateProvider.$$selectors;
283
284    var ELEMENT_NODE = 1;
285    var NG_ANIMATE_STATE = '$$ngAnimateState';
286    var NG_ANIMATE_CLASS_NAME = 'ng-animate';
287    var rootAnimateState = {running: true};
288
289    function extractElementNode(element) {
290      for(var i = 0; i < element.length; i++) {
291        var elm = element[i];
292        if(elm.nodeType == ELEMENT_NODE) {
293          return elm;
294        }
295      }
296    }
297
298    function stripCommentsFromElement(element) {
299      return angular.element(extractElementNode(element));
300    }
301
302    function isMatchingElement(elm1, elm2) {
303      return extractElementNode(elm1) == extractElementNode(elm2);
304    }
305
306    $provide.decorator('$animate', ['$delegate', '$injector', '$sniffer', '$rootElement', '$$asyncCallback', '$rootScope', '$document',
307                            function($delegate,   $injector,   $sniffer,   $rootElement,   $$asyncCallback,    $rootScope,   $document) {
308
309      var globalAnimationCounter = 0;
310      $rootElement.data(NG_ANIMATE_STATE, rootAnimateState);
311
312      // disable animations during bootstrap, but once we bootstrapped, wait again
313      // for another digest until enabling animations. The reason why we digest twice
314      // is because all structural animations (enter, leave and move) all perform a
315      // post digest operation before animating. If we only wait for a single digest
316      // to pass then the structural animation would render its animation on page load.
317      // (which is what we're trying to avoid when the application first boots up.)
318      $rootScope.$$postDigest(function() {
319        $rootScope.$$postDigest(function() {
320          rootAnimateState.running = false;
321        });
322      });
323
324      var classNameFilter = $animateProvider.classNameFilter();
325      var isAnimatableClassName = !classNameFilter
326              ? function() { return true; }
327              : function(className) {
328                return classNameFilter.test(className);
329              };
330
331      function lookup(name) {
332        if (name) {
333          var matches = [],
334              flagMap = {},
335              classes = name.substr(1).split('.');
336
337          //the empty string value is the default animation
338          //operation which performs CSS transition and keyframe
339          //animations sniffing. This is always included for each
340          //element animation procedure if the browser supports
341          //transitions and/or keyframe animations. The default
342          //animation is added to the top of the list to prevent
343          //any previous animations from affecting the element styling
344          //prior to the element being animated.
345          if ($sniffer.transitions || $sniffer.animations) {
346            matches.push($injector.get(selectors['']));
347          }
348
349          for(var i=0; i < classes.length; i++) {
350            var klass = classes[i],
351                selectorFactoryName = selectors[klass];
352            if(selectorFactoryName && !flagMap[klass]) {
353              matches.push($injector.get(selectorFactoryName));
354              flagMap[klass] = true;
355            }
356          }
357          return matches;
358        }
359      }
360
361      function animationRunner(element, animationEvent, className) {
362        //transcluded directives may sometimes fire an animation using only comment nodes
363        //best to catch this early on to prevent any animation operations from occurring
364        var node = element[0];
365        if(!node) {
366          return;
367        }
368
369        var isSetClassOperation = animationEvent == 'setClass';
370        var isClassBased = isSetClassOperation ||
371                           animationEvent == 'addClass' ||
372                           animationEvent == 'removeClass';
373
374        var classNameAdd, classNameRemove;
375        if(angular.isArray(className)) {
376          classNameAdd = className[0];
377          classNameRemove = className[1];
378          className = classNameAdd + ' ' + classNameRemove;
379        }
380
381        var currentClassName = element.attr('class');
382        var classes = currentClassName + ' ' + className;
383        if(!isAnimatableClassName(classes)) {
384          return;
385        }
386
387        var beforeComplete = noop,
388            beforeCancel = [],
389            before = [],
390            afterComplete = noop,
391            afterCancel = [],
392            after = [];
393
394        var animationLookup = (' ' + classes).replace(/\s+/g,'.');
395        forEach(lookup(animationLookup), function(animationFactory) {
396          var created = registerAnimation(animationFactory, animationEvent);
397          if(!created && isSetClassOperation) {
398            registerAnimation(animationFactory, 'addClass');
399            registerAnimation(animationFactory, 'removeClass');
400          }
401        });
402
403        function registerAnimation(animationFactory, event) {
404          var afterFn = animationFactory[event];
405          var beforeFn = animationFactory['before' + event.charAt(0).toUpperCase() + event.substr(1)];
406          if(afterFn || beforeFn) {
407            if(event == 'leave') {
408              beforeFn = afterFn;
409              //when set as null then animation knows to skip this phase
410              afterFn = null;
411            }
412            after.push({
413              event : event, fn : afterFn
414            });
415            before.push({
416              event : event, fn : beforeFn
417            });
418            return true;
419          }
420        }
421
422        function run(fns, cancellations, allCompleteFn) {
423          var animations = [];
424          forEach(fns, function(animation) {
425            animation.fn && animations.push(animation);
426          });
427
428          var count = 0;
429          function afterAnimationComplete(index) {
430            if(cancellations) {
431              (cancellations[index] || noop)();
432              if(++count < animations.length) return;
433              cancellations = null;
434            }
435            allCompleteFn();
436          }
437
438          //The code below adds directly to the array in order to work with
439          //both sync and async animations. Sync animations are when the done()
440          //operation is called right away. DO NOT REFACTOR!
441          forEach(animations, function(animation, index) {
442            var progress = function() {
443              afterAnimationComplete(index);
444            };
445            switch(animation.event) {
446              case 'setClass':
447                cancellations.push(animation.fn(element, classNameAdd, classNameRemove, progress));
448                break;
449              case 'addClass':
450                cancellations.push(animation.fn(element, classNameAdd || className,     progress));
451                break;
452              case 'removeClass':
453                cancellations.push(animation.fn(element, classNameRemove || className,  progress));
454                break;
455              default:
456                cancellations.push(animation.fn(element, progress));
457                break;
458            }
459          });
460
461          if(cancellations && cancellations.length === 0) {
462            allCompleteFn();
463          }
464        }
465
466        return {
467          node : node,
468          event : animationEvent,
469          className : className,
470          isClassBased : isClassBased,
471          isSetClassOperation : isSetClassOperation,
472          before : function(allCompleteFn) {
473            beforeComplete = allCompleteFn;
474            run(before, beforeCancel, function() {
475              beforeComplete = noop;
476              allCompleteFn();
477            });
478          },
479          after : function(allCompleteFn) {
480            afterComplete = allCompleteFn;
481            run(after, afterCancel, function() {
482              afterComplete = noop;
483              allCompleteFn();
484            });
485          },
486          cancel : function() {
487            if(beforeCancel) {
488              forEach(beforeCancel, function(cancelFn) {
489                (cancelFn || noop)(true);
490              });
491              beforeComplete(true);
492            }
493            if(afterCancel) {
494              forEach(afterCancel, function(cancelFn) {
495                (cancelFn || noop)(true);
496              });
497              afterComplete(true);
498            }
499          }
500        };
501      }
502
503      /**
504       * @ngdoc service
505       * @name $animate
506       * @function
507       *
508       * @description
509       * The `$animate` service provides animation detection support while performing DOM operations (enter, leave and move) as well as during addClass and removeClass operations.
510       * When any of these operations are run, the $animate service
511       * will examine any JavaScript-defined animations (which are defined by using the $animateProvider provider object)
512       * as well as any CSS-defined animations against the CSS classes present on the element once the DOM operation is run.
513       *
514       * The `$animate` service is used behind the scenes with pre-existing directives and animation with these directives
515       * will work out of the box without any extra configuration.
516       *
517       * Requires the {@link ngAnimate `ngAnimate`} module to be installed.
518       *
519       * Please visit the {@link ngAnimate `ngAnimate`} module overview page learn more about how to use animations in your application.
520       *
521       */
522      return {
523        /**
524         * @ngdoc method
525         * @name $animate#enter
526         * @function
527         *
528         * @description
529         * Appends the element to the parentElement element that resides in the document and then runs the enter animation. Once
530         * the animation is started, the following CSS classes will be present on the element for the duration of the animation:
531         *
532         * Below is a breakdown of each step that occurs during enter animation:
533         *
534         * | Animation Step                                                                               | What the element class attribute looks like |
535         * |----------------------------------------------------------------------------------------------|---------------------------------------------|
536         * | 1. $animate.enter(...) is called                                                             | class="my-animation"                        |
537         * | 2. element is inserted into the parentElement element or beside the afterElement element     | class="my-animation"                        |
538         * | 3. $animate runs any JavaScript-defined animations on the element                            | class="my-animation ng-animate"             |
539         * | 4. the .ng-enter class is added to the element                                               | class="my-animation ng-animate ng-enter"    |
540         * | 5. $animate scans the element styles to get the CSS transition/animation duration and delay  | class="my-animation ng-animate ng-enter"    |
541         * | 6. $animate waits for 10ms (this performs a reflow)                                          | class="my-animation ng-animate ng-enter"    |
542         * | 7. the .ng-enter-active and .ng-animate-active classes are added (this triggers the CSS transition/animation) | class="my-animation ng-animate ng-animate-active ng-enter ng-enter-active" |
543         * | 8. $animate waits for X milliseconds for the animation to complete                           | class="my-animation ng-animate ng-animate-active ng-enter ng-enter-active" |
544         * | 9. The animation ends and all generated CSS classes are removed from the element             | class="my-animation"                        |
545         * | 10. The doneCallback() callback is fired (if provided)                                       | class="my-animation"                        |
546         *
547         * @param {DOMElement} element the element that will be the focus of the enter animation
548         * @param {DOMElement} parentElement the parent element of the element that will be the focus of the enter animation
549         * @param {DOMElement} afterElement the sibling element (which is the previous element) of the element that will be the focus of the enter animation
550         * @param {function()=} doneCallback the callback function that will be called once the animation is complete
551        */
552        enter : function(element, parentElement, afterElement, doneCallback) {
553          this.enabled(false, element);
554          $delegate.enter(element, parentElement, afterElement);
555          $rootScope.$$postDigest(function() {
556            element = stripCommentsFromElement(element);
557            performAnimation('enter', 'ng-enter', element, parentElement, afterElement, noop, doneCallback);
558          });
559        },
560
561        /**
562         * @ngdoc method
563         * @name $animate#leave
564         * @function
565         *
566         * @description
567         * Runs the leave animation operation and, upon completion, removes the element from the DOM. Once
568         * the animation is started, the following CSS classes will be added for the duration of the animation:
569         *
570         * Below is a breakdown of each step that occurs during leave animation:
571         *
572         * | Animation Step                                                                               | What the element class attribute looks like |
573         * |----------------------------------------------------------------------------------------------|---------------------------------------------|
574         * | 1. $animate.leave(...) is called                                                             | class="my-animation"                        |
575         * | 2. $animate runs any JavaScript-defined animations on the element                            | class="my-animation ng-animate"             |
576         * | 3. the .ng-leave class is added to the element                                               | class="my-animation ng-animate ng-leave"    |
577         * | 4. $animate scans the element styles to get the CSS transition/animation duration and delay  | class="my-animation ng-animate ng-leave"    |
578         * | 5. $animate waits for 10ms (this performs a reflow)                                          | class="my-animation ng-animate ng-leave"    |
579         * | 6. the .ng-leave-active and .ng-animate-active classes is added (this triggers the CSS transition/animation) | class="my-animation ng-animate ng-animate-active ng-leave ng-leave-active" |
580         * | 7. $animate waits for X milliseconds for the animation to complete                           | class="my-animation ng-animate ng-animate-active ng-leave ng-leave-active" |
581         * | 8. The animation ends and all generated CSS classes are removed from the element             | class="my-animation"                        |
582         * | 9. The element is removed from the DOM                                                       | ...                                         |
583         * | 10. The doneCallback() callback is fired (if provided)                                       | ...                                         |
584         *
585         * @param {DOMElement} element the element that will be the focus of the leave animation
586         * @param {function()=} doneCallback the callback function that will be called once the animation is complete
587        */
588        leave : function(element, doneCallback) {
589          cancelChildAnimations(element);
590          this.enabled(false, element);
591          $rootScope.$$postDigest(function() {
592            performAnimation('leave', 'ng-leave', stripCommentsFromElement(element), null, null, function() {
593              $delegate.leave(element);
594            }, doneCallback);
595          });
596        },
597
598        /**
599         * @ngdoc method
600         * @name $animate#move
601         * @function
602         *
603         * @description
604         * Fires the move DOM operation. Just before the animation starts, the animate service will either append it into the parentElement container or
605         * add the element directly after the afterElement element if present. Then the move animation will be run. Once
606         * the animation is started, the following CSS classes will be added for the duration of the animation:
607         *
608         * Below is a breakdown of each step that occurs during move animation:
609         *
610         * | Animation Step                                                                               | What the element class attribute looks like |
611         * |----------------------------------------------------------------------------------------------|---------------------------------------------|
612         * | 1. $animate.move(...) is called                                                              | class="my-animation"                        |
613         * | 2. element is moved into the parentElement element or beside the afterElement element        | class="my-animation"                        |
614         * | 3. $animate runs any JavaScript-defined animations on the element                            | class="my-animation ng-animate"             |
615         * | 4. the .ng-move class is added to the element                                                | class="my-animation ng-animate ng-move"     |
616         * | 5. $animate scans the element styles to get the CSS transition/animation duration and delay  | class="my-animation ng-animate ng-move"     |
617         * | 6. $animate waits for 10ms (this performs a reflow)                                          | class="my-animation ng-animate ng-move"     |
618         * | 7. the .ng-move-active and .ng-animate-active classes is added (this triggers the CSS transition/animation) | class="my-animation ng-animate ng-animate-active ng-move ng-move-active" |
619         * | 8. $animate waits for X milliseconds for the animation to complete                           | class="my-animation ng-animate ng-animate-active ng-move ng-move-active" |
620         * | 9. The animation ends and all generated CSS classes are removed from the element             | class="my-animation"                        |
621         * | 10. The doneCallback() callback is fired (if provided)                                       | class="my-animation"                        |
622         *
623         * @param {DOMElement} element the element that will be the focus of the move animation
624         * @param {DOMElement} parentElement the parentElement element of the element that will be the focus of the move animation
625         * @param {DOMElement} afterElement the sibling element (which is the previous element) of the element that will be the focus of the move animation
626         * @param {function()=} doneCallback the callback function that will be called once the animation is complete
627        */
628        move : function(element, parentElement, afterElement, doneCallback) {
629          cancelChildAnimations(element);
630          this.enabled(false, element);
631          $delegate.move(element, parentElement, afterElement);
632          $rootScope.$$postDigest(function() {
633            element = stripCommentsFromElement(element);
634            performAnimation('move', 'ng-move', element, parentElement, afterElement, noop, doneCallback);
635          });
636        },
637
638        /**
639         * @ngdoc method
640         * @name $animate#addClass
641         *
642         * @description
643         * Triggers a custom animation event based off the className variable and then attaches the className value to the element as a CSS class.
644         * Unlike the other animation methods, the animate service will suffix the className value with {@type -add} in order to provide
645         * the animate service the setup and active CSS classes in order to trigger the animation (this will be skipped if no CSS transitions
646         * or keyframes are defined on the -add or base CSS class).
647         *
648         * Below is a breakdown of each step that occurs during addClass animation:
649         *
650         * | Animation Step                                                                                 | What the element class attribute looks like |
651         * |------------------------------------------------------------------------------------------------|---------------------------------------------|
652         * | 1. $animate.addClass(element, 'super') is called                                               | class="my-animation"                        |
653         * | 2. $animate runs any JavaScript-defined animations on the element                              | class="my-animation ng-animate"             |
654         * | 3. the .super-add class are added to the element                                               | class="my-animation ng-animate super-add"   |
655         * | 4. $animate scans the element styles to get the CSS transition/animation duration and delay    | class="my-animation ng-animate super-add"   |
656         * | 5. $animate waits for 10ms (this performs a reflow)                                            | class="my-animation ng-animate super-add"   |
657         * | 6. the .super, .super-add-active and .ng-animate-active classes are added (this triggers the CSS transition/animation) | class="my-animation ng-animate ng-animate-active super super-add super-add-active"          |
658         * | 7. $animate waits for X milliseconds for the animation to complete                             | class="my-animation super super-add super-add-active"  |
659         * | 8. The animation ends and all generated CSS classes are removed from the element               | class="my-animation super"                  |
660         * | 9. The super class is kept on the element                                                      | class="my-animation super"                  |
661         * | 10. The doneCallback() callback is fired (if provided)                                         | class="my-animation super"                  |
662         *
663         * @param {DOMElement} element the element that will be animated
664         * @param {string} className the CSS class that will be added to the element and then animated
665         * @param {function()=} doneCallback the callback function that will be called once the animation is complete
666        */
667        addClass : function(element, className, doneCallback) {
668          element = stripCommentsFromElement(element);
669          performAnimation('addClass', className, element, null, null, function() {
670            $delegate.addClass(element, className);
671          }, doneCallback);
672        },
673
674        /**
675         * @ngdoc method
676         * @name $animate#removeClass
677         *
678         * @description
679         * Triggers a custom animation event based off the className variable and then removes the CSS class provided by the className value
680         * from the element. Unlike the other animation methods, the animate service will suffix the className value with {@type -remove} in
681         * order to provide the animate service the setup and active CSS classes in order to trigger the animation (this will be skipped if
682         * no CSS transitions or keyframes are defined on the -remove or base CSS classes).
683         *
684         * Below is a breakdown of each step that occurs during removeClass animation:
685         *
686         * | Animation Step                                                                                | What the element class attribute looks like     |
687         * |-----------------------------------------------------------------------------------------------|---------------------------------------------|
688         * | 1. $animate.removeClass(element, 'super') is called                                           | class="my-animation super"                  |
689         * | 2. $animate runs any JavaScript-defined animations on the element                             | class="my-animation super ng-animate"       |
690         * | 3. the .super-remove class are added to the element                                           | class="my-animation super ng-animate super-remove"|
691         * | 4. $animate scans the element styles to get the CSS transition/animation duration and delay   | class="my-animation super ng-animate super-remove"   |
692         * | 5. $animate waits for 10ms (this performs a reflow)                                           | class="my-animation super ng-animate super-remove"   |
693         * | 6. the .super-remove-active and .ng-animate-active classes are added and .super is removed (this triggers the CSS transition/animation) | class="my-animation ng-animate ng-animate-active super-remove super-remove-active"          |
694         * | 7. $animate waits for X milliseconds for the animation to complete                            | class="my-animation ng-animate ng-animate-active super-remove super-remove-active"   |
695         * | 8. The animation ends and all generated CSS classes are removed from the element              | class="my-animation"                        |
696         * | 9. The doneCallback() callback is fired (if provided)                                         | class="my-animation"                        |
697         *
698         *
699         * @param {DOMElement} element the element that will be animated
700         * @param {string} className the CSS class that will be animated and then removed from the element
701         * @param {function()=} doneCallback the callback function that will be called once the animation is complete
702        */
703        removeClass : function(element, className, doneCallback) {
704          element = stripCommentsFromElement(element);
705          performAnimation('removeClass', className, element, null, null, function() {
706            $delegate.removeClass(element, className);
707          }, doneCallback);
708        },
709
710          /**
711           *
712           * @ngdoc function
713           * @name $animate#setClass
714           * @function
715           * @description Adds and/or removes the given CSS classes to and from the element.
716           * Once complete, the done() callback will be fired (if provided).
717           * @param {DOMElement} element the element which will it's CSS classes changed
718           *   removed from it
719           * @param {string} add the CSS classes which will be added to the element
720           * @param {string} remove the CSS class which will be removed from the element
721           * @param {Function=} done the callback function (if provided) that will be fired after the
722           *   CSS classes have been set on the element
723           */
724        setClass : function(element, add, remove, doneCallback) {
725          element = stripCommentsFromElement(element);
726          performAnimation('setClass', [add, remove], element, null, null, function() {
727            $delegate.setClass(element, add, remove);
728          }, doneCallback);
729        },
730
731        /**
732         * @ngdoc method
733         * @name $animate#enabled
734         * @function
735         *
736         * @param {boolean=} value If provided then set the animation on or off.
737         * @param {DOMElement=} element If provided then the element will be used to represent the enable/disable operation
738         * @return {boolean} Current animation state.
739         *
740         * @description
741         * Globally enables/disables animations.
742         *
743        */
744        enabled : function(value, element) {
745          switch(arguments.length) {
746            case 2:
747              if(value) {
748                cleanup(element);
749              } else {
750                var data = element.data(NG_ANIMATE_STATE) || {};
751                data.disabled = true;
752                element.data(NG_ANIMATE_STATE, data);
753              }
754            break;
755
756            case 1:
757              rootAnimateState.disabled = !value;
758            break;
759
760            default:
761              value = !rootAnimateState.disabled;
762            break;
763          }
764          return !!value;
765         }
766      };
767
768      /*
769        all animations call this shared animation triggering function internally.
770        The animationEvent variable refers to the JavaScript animation event that will be triggered
771        and the className value is the name of the animation that will be applied within the
772        CSS code. Element, parentElement and afterElement are provided DOM elements for the animation
773        and the onComplete callback will be fired once the animation is fully complete.
774      */
775      function performAnimation(animationEvent, className, element, parentElement, afterElement, domOperation, doneCallback) {
776
777        var runner = animationRunner(element, animationEvent, className);
778        if(!runner) {
779          fireDOMOperation();
780          fireBeforeCallbackAsync();
781          fireAfterCallbackAsync();
782          closeAnimation();
783          return;
784        }
785
786        className = runner.className;
787        var elementEvents = angular.element._data(runner.node);
788        elementEvents = elementEvents && elementEvents.events;
789
790        if (!parentElement) {
791          parentElement = afterElement ? afterElement.parent() : element.parent();
792        }
793
794        var ngAnimateState  = element.data(NG_ANIMATE_STATE) || {};
795        var runningAnimations     = ngAnimateState.active || {};
796        var totalActiveAnimations = ngAnimateState.totalActive || 0;
797        var lastAnimation         = ngAnimateState.last;
798
799        //only allow animations if the currently running animation is not structural
800        //or if there is no animation running at all
801        var skipAnimations = runner.isClassBased ?
802          ngAnimateState.disabled || (lastAnimation && !lastAnimation.isClassBased) :
803          false;
804
805        //skip the animation if animations are disabled, a parent is already being animated,
806        //the element is not currently attached to the document body or then completely close
807        //the animation if any matching animations are not found at all.
808        //NOTE: IE8 + IE9 should close properly (run closeAnimation()) in case an animation was found.
809        if (skipAnimations || animationsDisabled(element, parentElement)) {
810          fireDOMOperation();
811          fireBeforeCallbackAsync();
812          fireAfterCallbackAsync();
813          closeAnimation();
814          return;
815        }
816
817        var skipAnimation = false;
818        if(totalActiveAnimations > 0) {
819          var animationsToCancel = [];
820          if(!runner.isClassBased) {
821            if(animationEvent == 'leave' && runningAnimations['ng-leave']) {
822              skipAnimation = true;
823            } else {
824              //cancel all animations when a structural animation takes place
825              for(var klass in runningAnimations) {
826                animationsToCancel.push(runningAnimations[klass]);
827                cleanup(element, klass);
828              }
829              runningAnimations = {};
830              totalActiveAnimations = 0;
831            }
832          } else if(lastAnimation.event == 'setClass') {
833            animationsToCancel.push(lastAnimation);
834            cleanup(element, className);
835          }
836          else if(runningAnimations[className]) {
837            var current = runningAnimations[className];
838            if(current.event == animationEvent) {
839              skipAnimation = true;
840            } else {
841              animationsToCancel.push(current);
842              cleanup(element, className);
843            }
844          }
845
846          if(animationsToCancel.length > 0) {
847            forEach(animationsToCancel, function(operation) {
848              operation.cancel();
849            });
850          }
851        }
852
853        if(runner.isClassBased && !runner.isSetClassOperation && !skipAnimation) {
854          skipAnimation = (animationEvent == 'addClass') == element.hasClass(className); //opposite of XOR
855        }
856
857        if(skipAnimation) {
858          fireBeforeCallbackAsync();
859          fireAfterCallbackAsync();
860          fireDoneCallbackAsync();
861          return;
862        }
863
864        if(animationEvent == 'leave') {
865          //there's no need to ever remove the listener since the element
866          //will be removed (destroyed) after the leave animation ends or
867          //is cancelled midway
868          element.one('$destroy', function(e) {
869            var element = angular.element(this);
870            var state = element.data(NG_ANIMATE_STATE);
871            if(state) {
872              var activeLeaveAnimation = state.active['ng-leave'];
873              if(activeLeaveAnimation) {
874                activeLeaveAnimation.cancel();
875                cleanup(element, 'ng-leave');
876              }
877            }
878          });
879        }
880
881        //the ng-animate class does nothing, but it's here to allow for
882        //parent animations to find and cancel child animations when needed
883        element.addClass(NG_ANIMATE_CLASS_NAME);
884
885        var localAnimationCount = globalAnimationCounter++;
886        totalActiveAnimations++;
887        runningAnimations[className] = runner;
888
889        element.data(NG_ANIMATE_STATE, {
890          last : runner,
891          active : runningAnimations,
892          index : localAnimationCount,
893          totalActive : totalActiveAnimations
894        });
895
896        //first we run the before animations and when all of those are complete
897        //then we perform the DOM operation and run the next set of animations
898        fireBeforeCallbackAsync();
899        runner.before(function(cancelled) {
900          var data = element.data(NG_ANIMATE_STATE);
901          cancelled = cancelled ||
902                        !data || !data.active[className] ||
903                        (runner.isClassBased && data.active[className].event != animationEvent);
904
905          fireDOMOperation();
906          if(cancelled === true) {
907            closeAnimation();
908          } else {
909            fireAfterCallbackAsync();
910            runner.after(closeAnimation);
911          }
912        });
913
914        function fireDOMCallback(animationPhase) {
915          var eventName = '$animate:' + animationPhase;
916          if(elementEvents && elementEvents[eventName] && elementEvents[eventName].length > 0) {
917            $$asyncCallback(function() {
918              element.triggerHandler(eventName, {
919                event : animationEvent,
920                className : className
921              });
922            });
923          }
924        }
925
926        function fireBeforeCallbackAsync() {
927          fireDOMCallback('before');
928        }
929
930        function fireAfterCallbackAsync() {
931          fireDOMCallback('after');
932        }
933
934        function fireDoneCallbackAsync() {
935          fireDOMCallback('close');
936          if(doneCallback) {
937            $$asyncCallback(function() {
938              doneCallback();
939            });
940          }
941        }
942
943        //it is less complicated to use a flag than managing and canceling
944        //timeouts containing multiple callbacks.
945        function fireDOMOperation() {
946          if(!fireDOMOperation.hasBeenRun) {
947            fireDOMOperation.hasBeenRun = true;
948            domOperation();
949          }
950        }
951
952        function closeAnimation() {
953          if(!closeAnimation.hasBeenRun) {
954            closeAnimation.hasBeenRun = true;
955            var data = element.data(NG_ANIMATE_STATE);
956            if(data) {
957              /* only structural animations wait for reflow before removing an
958                 animation, but class-based animations don't. An example of this
959                 failing would be when a parent HTML tag has a ng-class attribute
960                 causing ALL directives below to skip animations during the digest */
961              if(runner && runner.isClassBased) {
962                cleanup(element, className);
963              } else {
964                $$asyncCallback(function() {
965                  var data = element.data(NG_ANIMATE_STATE) || {};
966                  if(localAnimationCount == data.index) {
967                    cleanup(element, className, animationEvent);
968                  }
969                });
970                element.data(NG_ANIMATE_STATE, data);
971              }
972            }
973            fireDoneCallbackAsync();
974          }
975        }
976      }
977
978      function cancelChildAnimations(element) {
979        var node = extractElementNode(element);
980        if (node) {
981          var nodes = angular.isFunction(node.getElementsByClassName) ?
982            node.getElementsByClassName(NG_ANIMATE_CLASS_NAME) :
983            node.querySelectorAll('.' + NG_ANIMATE_CLASS_NAME);
984          forEach(nodes, function(element) {
985            element = angular.element(element);
986            var data = element.data(NG_ANIMATE_STATE);
987            if(data && data.active) {
988              forEach(data.active, function(runner) {
989                runner.cancel();
990              });
991            }
992          });
993        }
994      }
995
996      function cleanup(element, className) {
997        if(isMatchingElement(element, $rootElement)) {
998          if(!rootAnimateState.disabled) {
999            rootAnimateState.running = false;
1000            rootAnimateState.structural = false;
1001          }
1002        } else if(className) {
1003          var data = element.data(NG_ANIMATE_STATE) || {};
1004
1005          var removeAnimations = className === true;
1006          if(!removeAnimations && data.active && data.active[className]) {
1007            data.totalActive--;
1008            delete data.active[className];
1009          }
1010
1011          if(removeAnimations || !data.totalActive) {
1012            element.removeClass(NG_ANIMATE_CLASS_NAME);
1013            element.removeData(NG_ANIMATE_STATE);
1014          }
1015        }
1016      }
1017
1018      function animationsDisabled(element, parentElement) {
1019        if (rootAnimateState.disabled) return true;
1020
1021        if(isMatchingElement(element, $rootElement)) {
1022          return rootAnimateState.disabled || rootAnimateState.running;
1023        }
1024
1025        do {
1026          //the element did not reach the root element which means that it
1027          //is not apart of the DOM. Therefore there is no reason to do
1028          //any animations on it
1029          if(parentElement.length === 0) break;
1030
1031          var isRoot = isMatchingElement(parentElement, $rootElement);
1032          var state = isRoot ? rootAnimateState : parentElement.data(NG_ANIMATE_STATE);
1033          var result = state && (!!state.disabled || state.running || state.totalActive > 0);
1034          if(isRoot || result) {
1035            return result;
1036          }
1037
1038          if(isRoot) return true;
1039        }
1040        while(parentElement = parentElement.parent());
1041
1042        return true;
1043      }
1044    }]);
1045
1046    $animateProvider.register('', ['$window', '$sniffer', '$timeout', '$$animateReflow',
1047                           function($window,   $sniffer,   $timeout,   $$animateReflow) {
1048      // Detect proper transitionend/animationend event names.
1049      var CSS_PREFIX = '', TRANSITION_PROP, TRANSITIONEND_EVENT, ANIMATION_PROP, ANIMATIONEND_EVENT;
1050
1051      // If unprefixed events are not supported but webkit-prefixed are, use the latter.
1052      // Otherwise, just use W3C names, browsers not supporting them at all will just ignore them.
1053      // Note: Chrome implements `window.onwebkitanimationend` and doesn't implement `window.onanimationend`
1054      // but at the same time dispatches the `animationend` event and not `webkitAnimationEnd`.
1055      // Register both events in case `window.onanimationend` is not supported because of that,
1056      // do the same for `transitionend` as Safari is likely to exhibit similar behavior.
1057      // Also, the only modern browser that uses vendor prefixes for transitions/keyframes is webkit
1058      // therefore there is no reason to test anymore for other vendor prefixes: http://caniuse.com/#search=transition
1059      if (window.ontransitionend === undefined && window.onwebkittransitionend !== undefined) {
1060        CSS_PREFIX = '-webkit-';
1061        TRANSITION_PROP = 'WebkitTransition';
1062        TRANSITIONEND_EVENT = 'webkitTransitionEnd transitionend';
1063      } else {
1064        TRANSITION_PROP = 'transition';
1065        TRANSITIONEND_EVENT = 'transitionend';
1066      }
1067
1068      if (window.onanimationend === undefined && window.onwebkitanimationend !== undefined) {
1069        CSS_PREFIX = '-webkit-';
1070        ANIMATION_PROP = 'WebkitAnimation';
1071        ANIMATIONEND_EVENT = 'webkitAnimationEnd animationend';
1072      } else {
1073        ANIMATION_PROP = 'animation';
1074        ANIMATIONEND_EVENT = 'animationend';
1075      }
1076
1077      var DURATION_KEY = 'Duration';
1078      var PROPERTY_KEY = 'Property';
1079      var DELAY_KEY = 'Delay';
1080      var ANIMATION_ITERATION_COUNT_KEY = 'IterationCount';
1081      var NG_ANIMATE_PARENT_KEY = '$$ngAnimateKey';
1082      var NG_ANIMATE_CSS_DATA_KEY = '$$ngAnimateCSS3Data';
1083      var NG_ANIMATE_BLOCK_CLASS_NAME = 'ng-animate-block-transitions';
1084      var ELAPSED_TIME_MAX_DECIMAL_PLACES = 3;
1085      var CLOSING_TIME_BUFFER = 1.5;
1086      var ONE_SECOND = 1000;
1087
1088      var lookupCache = {};
1089      var parentCounter = 0;
1090      var animationReflowQueue = [];
1091      var cancelAnimationReflow;
1092      function afterReflow(element, callback) {
1093        if(cancelAnimationReflow) {
1094          cancelAnimationReflow();
1095        }
1096        animationReflowQueue.push(callback);
1097        cancelAnimationReflow = $$animateReflow(function() {
1098          forEach(animationReflowQueue, function(fn) {
1099            fn();
1100          });
1101
1102          animationReflowQueue = [];
1103          cancelAnimationReflow = null;
1104          lookupCache = {};
1105        });
1106      }
1107
1108      var closingTimer = null;
1109      var closingTimestamp = 0;
1110      var animationElementQueue = [];
1111      function animationCloseHandler(element, totalTime) {
1112        var node = extractElementNode(element);
1113        element = angular.element(node);
1114
1115        //this item will be garbage collected by the closing
1116        //animation timeout
1117        animationElementQueue.push(element);
1118
1119        //but it may not need to cancel out the existing timeout
1120        //if the timestamp is less than the previous one
1121        var futureTimestamp = Date.now() + totalTime;
1122        if(futureTimestamp <= closingTimestamp) {
1123          return;
1124        }
1125
1126        $timeout.cancel(closingTimer);
1127
1128        closingTimestamp = futureTimestamp;
1129        closingTimer = $timeout(function() {
1130          closeAllAnimations(animationElementQueue);
1131          animationElementQueue = [];
1132        }, totalTime, false);
1133      }
1134
1135      function closeAllAnimations(elements) {
1136        forEach(elements, function(element) {
1137          var elementData = element.data(NG_ANIMATE_CSS_DATA_KEY);
1138          if(elementData) {
1139            (elementData.closeAnimationFn || noop)();
1140          }
1141        });
1142      }
1143
1144      function getElementAnimationDetails(element, cacheKey) {
1145        var data = cacheKey ? lookupCache[cacheKey] : null;
1146        if(!data) {
1147          var transitionDuration = 0;
1148          var transitionDelay = 0;
1149          var animationDuration = 0;
1150          var animationDelay = 0;
1151          var transitionDelayStyle;
1152          var animationDelayStyle;
1153          var transitionDurationStyle;
1154          var transitionPropertyStyle;
1155
1156          //we want all the styles defined before and after
1157          forEach(element, function(element) {
1158            if (element.nodeType == ELEMENT_NODE) {
1159              var elementStyles = $window.getComputedStyle(element) || {};
1160
1161              transitionDurationStyle = elementStyles[TRANSITION_PROP + DURATION_KEY];
1162
1163              transitionDuration = Math.max(parseMaxTime(transitionDurationStyle), transitionDuration);
1164
1165              transitionPropertyStyle = elementStyles[TRANSITION_PROP + PROPERTY_KEY];
1166
1167              transitionDelayStyle = elementStyles[TRANSITION_PROP + DELAY_KEY];
1168
1169              transitionDelay  = Math.max(parseMaxTime(transitionDelayStyle), transitionDelay);
1170
1171              animationDelayStyle = elementStyles[ANIMATION_PROP + DELAY_KEY];
1172
1173              animationDelay   = Math.max(parseMaxTime(animationDelayStyle), animationDelay);
1174
1175              var aDuration  = parseMaxTime(elementStyles[ANIMATION_PROP + DURATION_KEY]);
1176
1177              if(aDuration > 0) {
1178                aDuration *= parseInt(elementStyles[ANIMATION_PROP + ANIMATION_ITERATION_COUNT_KEY], 10) || 1;
1179              }
1180
1181              animationDuration = Math.max(aDuration, animationDuration);
1182            }
1183          });
1184          data = {
1185            total : 0,
1186            transitionPropertyStyle: transitionPropertyStyle,
1187            transitionDurationStyle: transitionDurationStyle,
1188            transitionDelayStyle: transitionDelayStyle,
1189            transitionDelay: transitionDelay,
1190            transitionDuration: transitionDuration,
1191            animationDelayStyle: animationDelayStyle,
1192            animationDelay: animationDelay,
1193            animationDuration: animationDuration
1194          };
1195          if(cacheKey) {
1196            lookupCache[cacheKey] = data;
1197          }
1198        }
1199        return data;
1200      }
1201
1202      function parseMaxTime(str) {
1203        var maxValue = 0;
1204        var values = angular.isString(str) ?
1205          str.split(/\s*,\s*/) :
1206          [];
1207        forEach(values, function(value) {
1208          maxValue = Math.max(parseFloat(value) || 0, maxValue);
1209        });
1210        return maxValue;
1211      }
1212
1213      function getCacheKey(element) {
1214        var parentElement = element.parent();
1215        var parentID = parentElement.data(NG_ANIMATE_PARENT_KEY);
1216        if(!parentID) {
1217          parentElement.data(NG_ANIMATE_PARENT_KEY, ++parentCounter);
1218          parentID = parentCounter;
1219        }
1220        return parentID + '-' + extractElementNode(element).getAttribute('class');
1221      }
1222
1223      function animateSetup(animationEvent, element, className, calculationDecorator) {
1224        var cacheKey = getCacheKey(element);
1225        var eventCacheKey = cacheKey + ' ' + className;
1226        var itemIndex = lookupCache[eventCacheKey] ? ++lookupCache[eventCacheKey].total : 0;
1227
1228        var stagger = {};
1229        if(itemIndex > 0) {
1230          var staggerClassName = className + '-stagger';
1231          var staggerCacheKey = cacheKey + ' ' + staggerClassName;
1232          var applyClasses = !lookupCache[staggerCacheKey];
1233
1234          applyClasses && element.addClass(staggerClassName);
1235
1236          stagger = getElementAnimationDetails(element, staggerCacheKey);
1237
1238          applyClasses && element.removeClass(staggerClassName);
1239        }
1240
1241        /* the animation itself may need to add/remove special CSS classes
1242         * before calculating the anmation styles */
1243        calculationDecorator = calculationDecorator ||
1244                               function(fn) { return fn(); };
1245
1246        element.addClass(className);
1247
1248        var formerData = element.data(NG_ANIMATE_CSS_DATA_KEY) || {};
1249
1250        var timings = calculationDecorator(function() {
1251          return getElementAnimationDetails(element, eventCacheKey);
1252        });
1253
1254        var transitionDuration = timings.transitionDuration;
1255        var animationDuration = timings.animationDuration;
1256        if(transitionDuration === 0 && animationDuration === 0) {
1257          element.removeClass(className);
1258          return false;
1259        }
1260
1261        element.data(NG_ANIMATE_CSS_DATA_KEY, {
1262          running : formerData.running || 0,
1263          itemIndex : itemIndex,
1264          stagger : stagger,
1265          timings : timings,
1266          closeAnimationFn : noop
1267        });
1268
1269        //temporarily disable the transition so that the enter styles
1270        //don't animate twice (this is here to avoid a bug in Chrome/FF).
1271        var isCurrentlyAnimating = formerData.running > 0 || animationEvent == 'setClass';
1272        if(transitionDuration > 0) {
1273          blockTransitions(element, className, isCurrentlyAnimating);
1274        }
1275
1276        //staggering keyframe animations work by adjusting the `animation-delay` CSS property
1277        //on the given element, however, the delay value can only calculated after the reflow
1278        //since by that time $animate knows how many elements are being animated. Therefore,
1279        //until the reflow occurs the element needs to be blocked (where the keyframe animation
1280        //is set to `none 0s`). This blocking mechanism should only be set for when a stagger
1281        //animation is detected and when the element item index is greater than 0.
1282        if(animationDuration > 0 && stagger.animationDelay > 0 && stagger.animationDuration === 0) {
1283          blockKeyframeAnimations(element);
1284        }
1285
1286        return true;
1287      }
1288
1289      function isStructuralAnimation(className) {
1290        return className == 'ng-enter' || className == 'ng-move' || className == 'ng-leave';
1291      }
1292
1293      function blockTransitions(element, className, isAnimating) {
1294        if(isStructuralAnimation(className) || !isAnimating) {
1295          extractElementNode(element).style[TRANSITION_PROP + PROPERTY_KEY] = 'none';
1296        } else {
1297          element.addClass(NG_ANIMATE_BLOCK_CLASS_NAME);
1298        }
1299      }
1300
1301      function blockKeyframeAnimations(element) {
1302        extractElementNode(element).style[ANIMATION_PROP] = 'none 0s';
1303      }
1304
1305      function unblockTransitions(element, className) {
1306        var prop = TRANSITION_PROP + PROPERTY_KEY;
1307        var node = extractElementNode(element);
1308        if(node.style[prop] && node.style[prop].length > 0) {
1309          node.style[prop] = '';
1310        }
1311        element.removeClass(NG_ANIMATE_BLOCK_CLASS_NAME);
1312      }
1313
1314      function unblockKeyframeAnimations(element) {
1315        var prop = ANIMATION_PROP;
1316        var node = extractElementNode(element);
1317        if(node.style[prop] && node.style[prop].length > 0) {
1318          node.style[prop] = '';
1319        }
1320      }
1321
1322      function animateRun(animationEvent, element, className, activeAnimationComplete) {
1323        var node = extractElementNode(element);
1324        var elementData = element.data(NG_ANIMATE_CSS_DATA_KEY);
1325        if(node.getAttribute('class').indexOf(className) == -1 || !elementData) {
1326          activeAnimationComplete();
1327          return;
1328        }
1329
1330        var activeClassName = '';
1331        forEach(className.split(' '), function(klass, i) {
1332          activeClassName += (i > 0 ? ' ' : '') + klass + '-active';
1333        });
1334
1335        var stagger = elementData.stagger;
1336        var timings = elementData.timings;
1337        var itemIndex = elementData.itemIndex;
1338        var maxDuration = Math.max(timings.transitionDuration, timings.animationDuration);
1339        var maxDelay = Math.max(timings.transitionDelay, timings.animationDelay);
1340        var maxDelayTime = maxDelay * ONE_SECOND;
1341
1342        var startTime = Date.now();
1343        var css3AnimationEvents = ANIMATIONEND_EVENT + ' ' + TRANSITIONEND_EVENT;
1344
1345        var style = '', appliedStyles = [];
1346        if(timings.transitionDuration > 0) {
1347          var propertyStyle = timings.transitionPropertyStyle;
1348          if(propertyStyle.indexOf('all') == -1) {
1349            style += CSS_PREFIX + 'transition-property: ' + propertyStyle + ';';
1350            style += CSS_PREFIX + 'transition-duration: ' + timings.transitionDurationStyle + ';';
1351            appliedStyles.push(CSS_PREFIX + 'transition-property');
1352            appliedStyles.push(CSS_PREFIX + 'transition-duration');
1353          }
1354        }
1355
1356        if(itemIndex > 0) {
1357          if(stagger.transitionDelay > 0 && stagger.transitionDuration === 0) {
1358            var delayStyle = timings.transitionDelayStyle;
1359            style += CSS_PREFIX + 'transition-delay: ' +
1360                     prepareStaggerDelay(delayStyle, stagger.transitionDelay, itemIndex) + '; ';
1361            appliedStyles.push(CSS_PREFIX + 'transition-delay');
1362          }
1363
1364          if(stagger.animationDelay > 0 && stagger.animationDuration === 0) {
1365            style += CSS_PREFIX + 'animation-delay: ' +
1366                     prepareStaggerDelay(timings.animationDelayStyle, stagger.animationDelay, itemIndex) + '; ';
1367            appliedStyles.push(CSS_PREFIX + 'animation-delay');
1368          }
1369        }
1370
1371        if(appliedStyles.length > 0) {
1372          //the element being animated may sometimes contain comment nodes in
1373          //the jqLite object, so we're safe to use a single variable to house
1374          //the styles since there is always only one element being animated
1375          var oldStyle = node.getAttribute('style') || '';
1376          node.setAttribute('style', oldStyle + ' ' + style);
1377        }
1378
1379        element.on(css3AnimationEvents, onAnimationProgress);
1380        element.addClass(activeClassName);
1381        elementData.closeAnimationFn = function() {
1382          onEnd();
1383          activeAnimationComplete();
1384        };
1385
1386        var staggerTime       = itemIndex * (Math.max(stagger.animationDelay, stagger.transitionDelay) || 0);
1387        var animationTime     = (maxDelay + maxDuration) * CLOSING_TIME_BUFFER;
1388        var totalTime         = (staggerTime + animationTime) * ONE_SECOND;
1389
1390        elementData.running++;
1391        animationCloseHandler(element, totalTime);
1392        return onEnd;
1393
1394        // This will automatically be called by $animate so
1395        // there is no need to attach this internally to the
1396        // timeout done method.
1397        function onEnd(cancelled) {
1398          element.off(css3AnimationEvents, onAnimationProgress);
1399          element.removeClass(activeClassName);
1400          animateClose(element, className);
1401          var node = extractElementNode(element);
1402          for (var i in appliedStyles) {
1403            node.style.removeProperty(appliedStyles[i]);
1404          }
1405        }
1406
1407        function onAnimationProgress(event) {
1408          event.stopPropagation();
1409          var ev = event.originalEvent || event;
1410          var timeStamp = ev.$manualTimeStamp || ev.timeStamp || Date.now();
1411
1412          /* Firefox (or possibly just Gecko) likes to not round values up
1413           * when a ms measurement is used for the animation */
1414          var elapsedTime = parseFloat(ev.elapsedTime.toFixed(ELAPSED_TIME_MAX_DECIMAL_PLACES));
1415
1416          /* $manualTimeStamp is a mocked timeStamp value which is set
1417           * within browserTrigger(). This is only here so that tests can
1418           * mock animations properly. Real events fallback to event.timeStamp,
1419           * or, if they don't, then a timeStamp is automatically created for them.
1420           * We're checking to see if the timeStamp surpasses the expected delay,
1421           * but we're using elapsedTime instead of the timeStamp on the 2nd
1422           * pre-condition since animations sometimes close off early */
1423          if(Math.max(timeStamp - startTime, 0) >= maxDelayTime && elapsedTime >= maxDuration) {
1424            activeAnimationComplete();
1425          }
1426        }
1427      }
1428
1429      function prepareStaggerDelay(delayStyle, staggerDelay, index) {
1430        var style = '';
1431        forEach(delayStyle.split(','), function(val, i) {
1432          style += (i > 0 ? ',' : '') +
1433                   (index * staggerDelay + parseInt(val, 10)) + 's';
1434        });
1435        return style;
1436      }
1437
1438      function animateBefore(animationEvent, element, className, calculationDecorator) {
1439        if(animateSetup(animationEvent, element, className, calculationDecorator)) {
1440          return function(cancelled) {
1441            cancelled && animateClose(element, className);
1442          };
1443        }
1444      }
1445
1446      function animateAfter(animationEvent, element, className, afterAnimationComplete) {
1447        if(element.data(NG_ANIMATE_CSS_DATA_KEY)) {
1448          return animateRun(animationEvent, element, className, afterAnimationComplete);
1449        } else {
1450          animateClose(element, className);
1451          afterAnimationComplete();
1452        }
1453      }
1454
1455      function animate(animationEvent, element, className, animationComplete) {
1456        //If the animateSetup function doesn't bother returning a
1457        //cancellation function then it means that there is no animation
1458        //to perform at all
1459        var preReflowCancellation = animateBefore(animationEvent, element, className);
1460        if(!preReflowCancellation) {
1461          animationComplete();
1462          return;
1463        }
1464
1465        //There are two cancellation functions: one is before the first
1466        //reflow animation and the second is during the active state
1467        //animation. The first function will take care of removing the
1468        //data from the element which will not make the 2nd animation
1469        //happen in the first place
1470        var cancel = preReflowCancellation;
1471        afterReflow(element, function() {
1472          unblockTransitions(element, className);
1473          unblockKeyframeAnimations(element);
1474          //once the reflow is complete then we point cancel to
1475          //the new cancellation function which will remove all of the
1476          //animation properties from the active animation
1477          cancel = animateAfter(animationEvent, element, className, animationComplete);
1478        });
1479
1480        return function(cancelled) {
1481          (cancel || noop)(cancelled);
1482        };
1483      }
1484
1485      function animateClose(element, className) {
1486        element.removeClass(className);
1487        var data = element.data(NG_ANIMATE_CSS_DATA_KEY);
1488        if(data) {
1489          if(data.running) {
1490            data.running--;
1491          }
1492          if(!data.running || data.running === 0) {
1493            element.removeData(NG_ANIMATE_CSS_DATA_KEY);
1494          }
1495        }
1496      }
1497
1498      return {
1499        enter : function(element, animationCompleted) {
1500          return animate('enter', element, 'ng-enter', animationCompleted);
1501        },
1502
1503        leave : function(element, animationCompleted) {
1504          return animate('leave', element, 'ng-leave', animationCompleted);
1505        },
1506
1507        move : function(element, animationCompleted) {
1508          return animate('move', element, 'ng-move', animationCompleted);
1509        },
1510
1511        beforeSetClass : function(element, add, remove, animationCompleted) {
1512          var className = suffixClasses(remove, '-remove') + ' ' +
1513                          suffixClasses(add, '-add');
1514          var cancellationMethod = animateBefore('setClass', element, className, function(fn) {
1515            /* when classes are removed from an element then the transition style
1516             * that is applied is the transition defined on the element without the
1517             * CSS class being there. This is how CSS3 functions outside of ngAnimate.
1518             * http://plnkr.co/edit/j8OzgTNxHTb4n3zLyjGW?p=preview */
1519            var klass = element.attr('class');
1520            element.removeClass(remove);
1521            element.addClass(add);
1522            var timings = fn();
1523            element.attr('class', klass);
1524            return timings;
1525          });
1526
1527          if(cancellationMethod) {
1528            afterReflow(element, function() {
1529              unblockTransitions(element, className);
1530              unblockKeyframeAnimations(element);
1531              animationCompleted();
1532            });
1533            return cancellationMethod;
1534          }
1535          animationCompleted();
1536        },
1537
1538        beforeAddClass : function(element, className, animationCompleted) {
1539          var cancellationMethod = animateBefore('addClass', element, suffixClasses(className, '-add'), function(fn) {
1540
1541            /* when a CSS class is added to an element then the transition style that
1542             * is applied is the transition defined on the element when the CSS class
1543             * is added at the time of the animation. This is how CSS3 functions
1544             * outside of ngAnimate. */
1545            element.addClass(className);
1546            var timings = fn();
1547            element.removeClass(className);
1548            return timings;
1549          });
1550
1551          if(cancellationMethod) {
1552            afterReflow(element, function() {
1553              unblockTransitions(element, className);
1554              unblockKeyframeAnimations(element);
1555              animationCompleted();
1556            });
1557            return cancellationMethod;
1558          }
1559          animationCompleted();
1560        },
1561
1562        setClass : function(element, add, remove, animationCompleted) {
1563          remove = suffixClasses(remove, '-remove');
1564          add = suffixClasses(add, '-add');
1565          var className = remove + ' ' + add;
1566          return animateAfter('setClass', element, className, animationCompleted);
1567        },
1568
1569        addClass : function(element, className, animationCompleted) {
1570          return animateAfter('addClass', element, suffixClasses(className, '-add'), animationCompleted);
1571        },
1572
1573        beforeRemoveClass : function(element, className, animationCompleted) {
1574          var cancellationMethod = animateBefore('removeClass', element, suffixClasses(className, '-remove'), function(fn) {
1575            /* when classes are removed from an element then the transition style
1576             * that is applied is the transition defined on the element without the
1577             * CSS class being there. This is how CSS3 functions outside of ngAnimate.
1578             * http://plnkr.co/edit/j8OzgTNxHTb4n3zLyjGW?p=preview */
1579            var klass = element.attr('class');
1580            element.removeClass(className);
1581            var timings = fn();
1582            element.attr('class', klass);
1583            return timings;
1584          });
1585
1586          if(cancellationMethod) {
1587            afterReflow(element, function() {
1588              unblockTransitions(element, className);
1589              unblockKeyframeAnimations(element);
1590              animationCompleted();
1591            });
1592            return cancellationMethod;
1593          }
1594          animationCompleted();
1595        },
1596
1597        removeClass : function(element, className, animationCompleted) {
1598          return animateAfter('removeClass', element, suffixClasses(className, '-remove'), animationCompleted);
1599        }
1600      };
1601
1602      function suffixClasses(classes, suffix) {
1603        var className = '';
1604        classes = angular.isArray(classes) ? classes : classes.split(/\s+/);
1605        forEach(classes, function(klass, i) {
1606          if(klass && klass.length > 0) {
1607            className += (i > 0 ? ' ' : '') + klass + suffix;
1608          }
1609        });
1610        return className;
1611      }
1612    }]);
1613  }]);
1614
1615
1616})(window, window.angular);

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.