vendor/assets/javascripts/unstable/angular-animate.js in angularjs-rails-1.2.15 vs vendor/assets/javascripts/unstable/angular-animate.js in angularjs-rails-1.2.16

- old
+ new

@@ -1,7 +1,7 @@ /** - * @license AngularJS v1.3.0-beta.3 + * @license AngularJS v1.3.0-beta.5 * (c) 2010-2014 Google, Inc. http://angularjs.org * License: MIT */ (function(window, angular, undefined) {'use strict'; @@ -10,15 +10,12 @@ /** * @ngdoc module * @name ngAnimate * @description * - * # ngAnimate - * * The `ngAnimate` module provides support for JavaScript, CSS3 transition and CSS3 keyframe animation hooks within existing core and custom directives. * - * * <div doc-module-components="ngAnimate"></div> * * # Usage * * To see animations in action, all that is required is to define the appropriate CSS classes @@ -26,21 +23,20 @@ * `ngRepeat`, `ngInclude`, `ngIf`, `ngSwitch`, `ngShow`, `ngHide`, `ngView` and `ngClass`. Custom directives can take advantage of animation * by using the `$animate` service. * * Below is a more detailed breakdown of the supported animation events provided by pre-existing ng directives: * - * | Directive | Supported Animations | - * |---------------------------------------------------------- |----------------------------------------------------| - * | {@link ng.directive:ngRepeat#usage_animations ngRepeat} | enter, leave and move | - * | {@link ngRoute.directive:ngView#usage_animations ngView} | enter and leave | - * | {@link ng.directive:ngInclude#usage_animations ngInclude} | enter and leave | - * | {@link ng.directive:ngSwitch#usage_animations ngSwitch} | enter and leave | - * | {@link ng.directive:ngIf#usage_animations ngIf} | enter and leave | - * | {@link ng.directive:ngClass#usage_animations ngClass} | add and remove | - * | {@link ng.directive:ngShow#usage_animations ngShow & ngHide} | add and remove (the ng-hide class value) | - * | {@link ng.directive:form#usage_animations form} | add and remove (dirty, pristine, valid, invalid & all other validations) | - * | {@link ng.directive:ngModel#usage_animations ngModel} | add and remove (dirty, pristine, valid, invalid & all other validations) | + * | Directive | Supported Animations | + * |-----------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------| + * | {@link ng.directive:ngRepeat#usage_animations ngRepeat} | enter, leave and move | + * | {@link ngRoute.directive:ngView#usage_animations ngView} | enter and leave | + * | {@link ng.directive:ngInclude#usage_animations ngInclude} | enter and leave | + * | {@link ng.directive:ngSwitch#usage_animations ngSwitch} | enter and leave | + * | {@link ng.directive:ngIf#usage_animations ngIf} | enter and leave | + * | {@link ng.directive:ngClass#usage_animations ngClass} | add and remove (the CSS class(es) present) | + * | {@link ng.directive:ngShow#usage_animations ngShow} & {@link ng.directive:ngHide#usage_animations ngHide} | add and remove (the ng-hide class value) | + * | {@link ng.directive:form#usage_animations form} & {@link ng.directive:ngModel#usage_animations ngModel} | add and remove (dirty, pristine, valid, invalid & all other validations) | * * You can find out more information about animations upon visiting each directive page. * * Below is an example of how to apply animations to a directive that supports animation hooks: * @@ -110,15 +106,15 @@ * <style type="text/css"> * .reveal-animation.ng-enter { * -webkit-animation: enter_sequence 1s linear; /&#42; Safari/Chrome &#42;/ * animation: enter_sequence 1s linear; /&#42; IE10+ and Future Browsers &#42;/ * } - * &#64-webkit-keyframes enter_sequence { + * @-webkit-keyframes enter_sequence { * from { opacity:0; } * to { opacity:1; } * } - * &#64keyframes enter_sequence { + * @keyframes enter_sequence { * from { opacity:0; } * to { opacity:1; } * } * </style> * @@ -134,11 +130,78 @@ * detect the CSS code 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 or CSS animations then the animation will start and end * immediately resulting in a DOM element that is at its final state. This final state is when the DOM element * has no CSS transition/animation classes applied to it. * - * <h3>CSS Staggering Animations</h3> + * ### Structural transition animations + * + * Structural transitions (such as enter, leave and move) will always apply a `0s none` transition + * value to force the browser into rendering the styles defined in the setup (.ng-enter, .ng-leave + * or .ng-move) class. This means that any active transition animations operating on the element + * will be cut off to make way for the enter, leave or move animation. + * + * ### Class-based transition animations + * + * Class-based transitions refer to transition animations that are triggered when a CSS class is + * added to or removed from the element (via `$animate.addClass`, `$animate.removeClass`, + * `$animate.setClass`, or by directives such as `ngClass`, `ngModel` and `form`). + * They are different when compared to structural animations since they **do not cancel existing + * animations** nor do they **block successive transitions** from rendering on the same element. + * This distinction allows for **multiple class-based transitions** to be performed on the same element. + * + * In addition to ngAnimate supporting the default (natural) functionality of class-based transition + * animations, ngAnimate also decorates the element with starting and ending CSS classes to aid the + * developer in further styling the element throughout the transition animation. Earlier versions + * of ngAnimate may have caused natural CSS transitions to break and not render properly due to + * $animate temporarily blocking transitions using `0s none` in order to allow the setup CSS class + * (the `-add` or `-remove` class) to be applied without triggering an animation. However, as of + * **version 1.3**, this workaround has been removed with ngAnimate and all non-ngAnimate CSS + * class transitions are compatible with ngAnimate. + * + * There is, however, one special case when dealing with class-based transitions in ngAnimate. + * When rendering class-based transitions that make use of the setup and active CSS classes + * (e.g. `.fade-add` and `.fade-add-active` for when `.fade` is added) be sure to define + * the transition value **on the active CSS class** and not the setup class. + * + * ```css + * .fade-add { + * /&#42; remember to place a 0s transition here + * to ensure that the styles are applied instantly + * even if the element already has a transition style &#42;/ + * transition:0s linear all; + * + * /&#42; starting CSS styles &#42;/ + * opacity:1; + * } + * .fade-add.fade-add-active { + * /&#42; this will be the length of the animation &#42;/ + * transition:1s linear all; + * opacity:0; + * } + * ``` + * + * The setup CSS class (in this case `.fade-add`) also has a transition style property, however, it + * has a duration of zero. This may not be required, however, incase the browser is unable to render + * the styling present in this CSS class instantly then it could be that the browser is attempting + * to perform an unnecessary transition. + * + * This workaround, however, does not apply to standard class-based transitions that are rendered + * when a CSS class containing a transition is applied to an element: + * + * ```css + * .fade { + * /&#42; this works as expected &#42;/ + * transition:1s linear all; + * opacity:0; + * } + * ``` + * + * Please keep this in mind when coding the CSS markup that will be used within class-based transitions. + * Also, try not to mix the two class-based animation flavors together since the CSS code may become + * overly complex. + * + * ### CSS Staggering Animations * A Staggering animation is a collection of animations that are issued with a slight delay in between each successive operation resulting in a * curtain-like effect. The ngAnimate module, as of 1.2.0, supports staggering animations and the stagger effect can be * performed by creating a **ng-EVENT-stagger** CSS class and attaching that class to the base CSS class used for * the animation. The style property expected within the stagger class can either be a **transition-delay** or an * **animation-delay** property (or both if your animation contains both transitions and keyframe animations). @@ -336,13 +399,16 @@ //the empty string value is the default animation //operation which performs CSS transition and keyframe //animations sniffing. This is always included for each //element animation procedure if the browser supports - //transitions and/or keyframe animations + //transitions and/or keyframe animations. The default + //animation is added to the top of the list to prevent + //any previous animations from affecting the element styling + //prior to the element being animated. if ($sniffer.transitions || $sniffer.animations) { - classes.push(''); + matches.push($injector.get(selectors[''])); } for(var i=0; i < classes.length; i++) { var klass = classes[i], selectorFactoryName = selectors[klass]; @@ -526,22 +592,25 @@ * Appends the element to the parentElement element that resides in the document and then runs the enter animation. Once * the animation is started, the following CSS classes will be present on the element for the duration of the animation: * * Below is a breakdown of each step that occurs during enter animation: * - * | Animation Step | What the element class attribute looks like | - * |----------------------------------------------------------------------------------------------|---------------------------------------------| - * | 1. $animate.enter(...) is called | class="my-animation" | - * | 2. element is inserted into the parentElement element or beside the afterElement element | class="my-animation" | - * | 3. $animate runs any JavaScript-defined animations on the element | class="my-animation ng-animate" | - * | 4. the .ng-enter class is added to the element | class="my-animation ng-animate ng-enter" | - * | 5. $animate scans the element styles to get the CSS transition/animation duration and delay | class="my-animation ng-animate ng-enter" | - * | 6. $animate waits for 10ms (this performs a reflow) | class="my-animation ng-animate ng-enter" | - * | 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" | - * | 8. $animate waits for X milliseconds for the animation to complete | class="my-animation ng-animate ng-animate-active ng-enter ng-enter-active" | - * | 9. The animation ends and all generated CSS classes are removed from the element | class="my-animation" | - * | 10. The doneCallback() callback is fired (if provided) | class="my-animation" | + * | Animation Step | What the element class attribute looks like | + * |-------------------------------------------------------------------------------------------------------------------|----------------------------------------------------------| + * | 1. $animate.enter(...) is called | class="my-animation" | + * | 2. element is inserted into the parentElement element or beside the afterElement element | class="my-animation" | + * | 3. $animate waits for the next digest to start the animation | class="my-animation ng-animate" | + * | 4. $animate runs the JavaScript-defined animations detected on the element | class="my-animation ng-animate" | + * | 5. the .ng-enter class is added to the element | class="my-animation ng-animate ng-enter" | + * | 6. $animate scans the element styles to get the CSS transition/animation duration and delay | class="my-animation ng-animate ng-enter" | + * | 7. $animate blocks all CSS transitions on the element to ensure the .ng-enter class styling is applied right away | class="my-animation ng-animate ng-enter" | + * | 8. $animate waits for a single animation frame (this performs a reflow) | class="my-animation ng-animate ng-enter" | + * | 9. $animate removes the CSS transition block placed on the element | class="my-animation ng-animate ng-enter" | + * | 10. the .ng-enter-active class is added (this triggers the CSS transition/animation) | class="my-animation ng-animate ng-enter ng-enter-active" | + * | 11. $animate waits for the animation to complete (via events and timeout) | class="my-animation ng-animate ng-enter ng-enter-active" | + * | 12. The animation ends and all generated CSS classes are removed from the element | class="my-animation" | + * | 13. The doneCallback() callback is fired (if provided) | class="my-animation" | * * @param {DOMElement} element the element that will be the focus of the enter animation * @param {DOMElement} parentElement the parent element of the element that will be the focus of the enter animation * @param {DOMElement} afterElement the sibling element (which is the previous element) of the element that will be the focus of the enter animation * @param {function()=} doneCallback the callback function that will be called once the animation is complete @@ -564,22 +633,25 @@ * Runs the leave animation operation and, upon completion, removes the element from the DOM. Once * the animation is started, the following CSS classes will be added for the duration of the animation: * * Below is a breakdown of each step that occurs during leave animation: * - * | Animation Step | What the element class attribute looks like | - * |----------------------------------------------------------------------------------------------|---------------------------------------------| - * | 1. $animate.leave(...) is called | class="my-animation" | - * | 2. $animate runs any JavaScript-defined animations on the element | class="my-animation ng-animate" | - * | 3. the .ng-leave class is added to the element | class="my-animation ng-animate ng-leave" | - * | 4. $animate scans the element styles to get the CSS transition/animation duration and delay | class="my-animation ng-animate ng-leave" | - * | 5. $animate waits for 10ms (this performs a reflow) | class="my-animation ng-animate ng-leave" | - * | 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" | - * | 7. $animate waits for X milliseconds for the animation to complete | class="my-animation ng-animate ng-animate-active ng-leave ng-leave-active" | - * | 8. The animation ends and all generated CSS classes are removed from the element | class="my-animation" | - * | 9. The element is removed from the DOM | ... | - * | 10. The doneCallback() callback is fired (if provided) | ... | + * | Animation Step | What the element class attribute looks like | + * |-------------------------------------------------------------------------------------------------------------------|----------------------------------------------------------| + * | 1. $animate.leave(...) is called | class="my-animation" | + * | 2. $animate runs the JavaScript-defined animations detected on the element | class="my-animation ng-animate" | + * | 3. $animate waits for the next digest to start the animation | class="my-animation ng-animate" | + * | 4. the .ng-leave class is added to the element | class="my-animation ng-animate ng-leave" | + * | 5. $animate scans the element styles to get the CSS transition/animation duration and delay | class="my-animation ng-animate ng-leave" | + * | 6. $animate blocks all CSS transitions on the element to ensure the .ng-leave class styling is applied right away | class="my-animation ng-animate ng-leave” | + * | 7. $animate waits for a single animation frame (this performs a reflow) | class="my-animation ng-animate ng-leave" | + * | 8. $animate removes the CSS transition block placed on the element | class="my-animation ng-animate ng-leave” | + * | 9. the .ng-leave-active class is added (this triggers the CSS transition/animation) | class="my-animation ng-animate ng-leave ng-leave-active" | + * | 10. $animate waits for the animation to complete (via events and timeout) | class="my-animation ng-animate ng-leave ng-leave-active" | + * | 11. The animation ends and all generated CSS classes are removed from the element | class="my-animation" | + * | 12. The element is removed from the DOM | ... | + * | 13. The doneCallback() callback is fired (if provided) | ... | * * @param {DOMElement} element the element that will be the focus of the leave animation * @param {function()=} doneCallback the callback function that will be called once the animation is complete */ leave : function(element, doneCallback) { @@ -602,22 +674,25 @@ * add the element directly after the afterElement element if present. Then the move animation will be run. Once * the animation is started, the following CSS classes will be added for the duration of the animation: * * Below is a breakdown of each step that occurs during move animation: * - * | Animation Step | What the element class attribute looks like | - * |----------------------------------------------------------------------------------------------|---------------------------------------------| - * | 1. $animate.move(...) is called | class="my-animation" | - * | 2. element is moved into the parentElement element or beside the afterElement element | class="my-animation" | - * | 3. $animate runs any JavaScript-defined animations on the element | class="my-animation ng-animate" | - * | 4. the .ng-move class is added to the element | class="my-animation ng-animate ng-move" | - * | 5. $animate scans the element styles to get the CSS transition/animation duration and delay | class="my-animation ng-animate ng-move" | - * | 6. $animate waits for 10ms (this performs a reflow) | class="my-animation ng-animate ng-move" | - * | 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" | - * | 8. $animate waits for X milliseconds for the animation to complete | class="my-animation ng-animate ng-animate-active ng-move ng-move-active" | - * | 9. The animation ends and all generated CSS classes are removed from the element | class="my-animation" | - * | 10. The doneCallback() callback is fired (if provided) | class="my-animation" | + * | Animation Step | What the element class attribute looks like | + * |------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------| + * | 1. $animate.move(...) is called | class="my-animation" | + * | 2. element is moved into the parentElement element or beside the afterElement element | class="my-animation" | + * | 3. $animate waits for the next digest to start the animation | class="my-animation ng-animate" | + * | 4. $animate runs the JavaScript-defined animations detected on the element | class="my-animation ng-animate" | + * | 5. the .ng-move class is added to the element | class="my-animation ng-animate ng-move" | + * | 6. $animate scans the element styles to get the CSS transition/animation duration and delay | class="my-animation ng-animate ng-move" | + * | 7. $animate blocks all CSS transitions on the element to ensure the .ng-move class styling is applied right away | class="my-animation ng-animate ng-move” | + * | 8. $animate waits for a single animation frame (this performs a reflow) | class="my-animation ng-animate ng-move" | + * | 9. $animate removes the CSS transition block placed on the element | class="my-animation ng-animate ng-move” | + * | 10. the .ng-move-active class is added (this triggers the CSS transition/animation) | class="my-animation ng-animate ng-move ng-move-active" | + * | 11. $animate waits for the animation to complete (via events and timeout) | class="my-animation ng-animate ng-move ng-move-active" | + * | 12. The animation ends and all generated CSS classes are removed from the element | class="my-animation" | + * | 13. The doneCallback() callback is fired (if provided) | class="my-animation" | * * @param {DOMElement} element the element that will be the focus of the move animation * @param {DOMElement} parentElement the parentElement element of the element that will be the focus of the move animation * @param {DOMElement} afterElement the sibling element (which is the previous element) of the element that will be the focus of the move animation * @param {function()=} doneCallback the callback function that will be called once the animation is complete @@ -638,26 +713,26 @@ * * @description * Triggers a custom animation event based off the className variable and then attaches the className value to the element as a CSS class. * Unlike the other animation methods, the animate service will suffix the className value with {@type -add} in order to provide * the animate service the setup and active CSS classes in order to trigger the animation (this will be skipped if no CSS transitions - * or keyframes are defined on the -add or base CSS class). + * or keyframes are defined on the -add-active or base CSS class). * * Below is a breakdown of each step that occurs during addClass animation: * - * | Animation Step | What the element class attribute looks like | - * |------------------------------------------------------------------------------------------------|---------------------------------------------| - * | 1. $animate.addClass(element, 'super') is called | class="my-animation" | - * | 2. $animate runs any JavaScript-defined animations on the element | class="my-animation ng-animate" | - * | 3. the .super-add class are added to the element | class="my-animation ng-animate super-add" | - * | 4. $animate scans the element styles to get the CSS transition/animation duration and delay | class="my-animation ng-animate super-add" | - * | 5. $animate waits for 10ms (this performs a reflow) | class="my-animation ng-animate super-add" | - * | 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" | - * | 7. $animate waits for X milliseconds for the animation to complete | class="my-animation super super-add super-add-active" | - * | 8. The animation ends and all generated CSS classes are removed from the element | class="my-animation super" | - * | 9. The super class is kept on the element | class="my-animation super" | - * | 10. The doneCallback() callback is fired (if provided) | class="my-animation super" | + * | Animation Step | What the element class attribute looks like | + * |----------------------------------------------------------------------------------------------------|------------------------------------------------------------------| + * | 1. $animate.addClass(element, 'super') is called | class="my-animation" | + * | 2. $animate runs the JavaScript-defined animations detected on the element | class="my-animation ng-animate" | + * | 3. the .super-add class is added to the element | class="my-animation ng-animate super-add" | + * | 4. $animate waits for a single animation frame (this performs a reflow) | class="my-animation ng-animate super-add" | + * | 5. the .super and .super-add-active classes are added (this triggers the CSS transition/animation) | class="my-animation ng-animate super super-add super-add-active" | + * | 6. $animate scans the element styles to get the CSS transition/animation duration and delay | class="my-animation ng-animate super-add" | + * | 7. $animate waits for the animation to complete (via events and timeout) | class="my-animation super super-add super-add-active" | + * | 8. The animation ends and all generated CSS classes are removed from the element | class="my-animation super" | + * | 9. The super class is kept on the element | class="my-animation super" | + * | 10. The doneCallback() callback is fired (if provided) | class="my-animation super" | * * @param {DOMElement} element the element that will be animated * @param {string} className the CSS class that will be added to the element and then animated * @param {function()=} doneCallback the callback function that will be called once the animation is complete */ @@ -678,21 +753,21 @@ * order to provide the animate service the setup and active CSS classes in order to trigger the animation (this will be skipped if * no CSS transitions or keyframes are defined on the -remove or base CSS classes). * * Below is a breakdown of each step that occurs during removeClass animation: * - * | Animation Step | What the element class attribute looks like | - * |-----------------------------------------------------------------------------------------------|---------------------------------------------| - * | 1. $animate.removeClass(element, 'super') is called | class="my-animation super" | - * | 2. $animate runs any JavaScript-defined animations on the element | class="my-animation super ng-animate" | - * | 3. the .super-remove class are added to the element | class="my-animation super ng-animate super-remove"| - * | 4. $animate scans the element styles to get the CSS transition/animation duration and delay | class="my-animation super ng-animate super-remove" | - * | 5. $animate waits for 10ms (this performs a reflow) | class="my-animation super ng-animate super-remove" | - * | 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" | - * | 7. $animate waits for X milliseconds for the animation to complete | class="my-animation ng-animate ng-animate-active super-remove super-remove-active" | - * | 8. The animation ends and all generated CSS classes are removed from the element | class="my-animation" | - * | 9. The doneCallback() callback is fired (if provided) | class="my-animation" | + * | Animation Step | What the element class attribute looks like | + * |------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------| + * | 1. $animate.removeClass(element, 'super') is called | class="my-animation super" | + * | 2. $animate runs the JavaScript-defined animations detected on the element | class="my-animation super ng-animate" | + * | 3. the .super-remove class is added to the element | class="my-animation super ng-animate super-remove" | + * | 4. $animate waits for a single animation frame (this performs a reflow) | class="my-animation super ng-animate super-remove" | + * | 5. the .super-remove-active classes are added and .super is removed (this triggers the CSS transition/animation) | class="my-animation ng-animate super-remove super-remove-active" | + * | 6. $animate scans the element styles to get the CSS transition/animation duration and delay | class="my-animation super ng-animate super-remove" | + * | 7. $animate waits for the animation to complete (via events and timeout) | class="my-animation ng-animate super-remove super-remove-active" | + * | 8. The animation ends and all generated CSS classes are removed from the element | class="my-animation" | + * | 9. The doneCallback() callback is fired (if provided) | class="my-animation" | * * * @param {DOMElement} element the element that will be animated * @param {string} className the CSS class that will be animated and then removed from the element * @param {function()=} doneCallback the callback function that will be called once the animation is complete @@ -702,24 +777,37 @@ performAnimation('removeClass', className, element, null, null, function() { $delegate.removeClass(element, className); }, doneCallback); }, - /** - * - * @ngdoc function - * @name $animate#setClass - * @function - * @description Adds and/or removes the given CSS classes to and from the element. - * Once complete, the done() callback will be fired (if provided). - * @param {DOMElement} element the element which will it's CSS classes changed - * removed from it - * @param {string} add the CSS classes which will be added to the element - * @param {string} remove the CSS class which will be removed from the element - * @param {Function=} done the callback function (if provided) that will be fired after the - * CSS classes have been set on the element - */ + /** + * + * @ngdoc method + * @name $animate#setClass + * + * @description Adds and/or removes the given CSS classes to and from the element. + * Once complete, the done() callback will be fired (if provided). + * + * | Animation Step | What the element class attribute looks like | + * |--------------------------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------| + * | 1. $animate.removeClass(element, ‘on’, ‘off’) is called | class="my-animation super off” | + * | 2. $animate runs the JavaScript-defined animations detected on the element | class="my-animation super ng-animate off” | + * | 3. the .on-add and .off-remove classes are added to the element | class="my-animation ng-animate on-add off-remove off” | + * | 4. $animate waits for a single animation frame (this performs a reflow) | class="my-animation ng-animate on-add off-remove off” | + * | 5. the .on, .on-add-active and .off-remove-active classes are added and .off is removed (this triggers the CSS transition/animation) | class="my-animation ng-animate on on-add on-add-active off-remove off-remove-active” | + * | 6. $animate scans the element styles to get the CSS transition/animation duration and delay | class="my-animation ng-animate on on-add on-add-active off-remove off-remove-active" | + * | 7. $animate waits for the animation to complete (via events and timeout) | class="my-animation ng-animate on on-add on-add-active off-remove off-remove-active" | + * | 8. The animation ends and all generated CSS classes are removed from the element | class="my-animation" | + * | 9. The doneCallback() callback is fired (if provided) | class="my-animation" | + * + * @param {DOMElement} element the element which will it's CSS classes changed + * removed from it + * @param {string} add the CSS classes which will be added to the element + * @param {string} remove the CSS class which will be removed from the element + * @param {Function=} done the callback function (if provided) that will be fired after the + * CSS classes have been set on the element + */ setClass : function(element, add, remove, doneCallback) { element = stripCommentsFromElement(element); performAnimation('setClass', [add, remove], element, null, null, function() { $delegate.setClass(element, add, remove); }, doneCallback); @@ -793,13 +881,13 @@ var totalActiveAnimations = ngAnimateState.totalActive || 0; var lastAnimation = ngAnimateState.last; //only allow animations if the currently running animation is not structural //or if there is no animation running at all - var skipAnimations = runner.isClassBased ? - ngAnimateState.disabled || (lastAnimation && !lastAnimation.isClassBased) : - false; + var skipAnimations = runner.isClassBased + ? ngAnimateState.disabled || (lastAnimation && !lastAnimation.isClassBased) + : false; //skip the animation if animations are disabled, a parent is already being animated, //the element is not currently attached to the document body or then completely close //the animation if any matching animations are not found at all. //NOTE: IE8 + IE9 should close properly (run closeAnimation()) in case an animation was found. @@ -1024,12 +1112,15 @@ //is not apart of the DOM. Therefore there is no reason to do //any animations on it if(parentElement.length === 0) break; var isRoot = isMatchingElement(parentElement, $rootElement); - var state = isRoot ? rootAnimateState : parentElement.data(NG_ANIMATE_STATE); - var result = state && (!!state.disabled || state.running || state.totalActive > 0); + var state = isRoot ? rootAnimateState : (parentElement.data(NG_ANIMATE_STATE) || {}); + var result = state.disabled || state.running + ? true + : state.last && !state.last.isClassBased; + if(isRoot || result) { return result; } if(isRoot) return true; @@ -1075,11 +1166,10 @@ var PROPERTY_KEY = 'Property'; var DELAY_KEY = 'Delay'; var ANIMATION_ITERATION_COUNT_KEY = 'IterationCount'; var NG_ANIMATE_PARENT_KEY = '$$ngAnimateKey'; var NG_ANIMATE_CSS_DATA_KEY = '$$ngAnimateCSS3Data'; - var NG_ANIMATE_BLOCK_CLASS_NAME = 'ng-animate-block-transitions'; var ELAPSED_TIME_MAX_DECIMAL_PLACES = 3; var CLOSING_TIME_BUFFER = 1.5; var ONE_SECOND = 1000; var lookupCache = {}; @@ -1113,11 +1203,11 @@ //animation timeout animationElementQueue.push(element); //but it may not need to cancel out the existing timeout //if the timestamp is less than the previous one - var futureTimestamp = Date.now() + (totalTime * 1000); + var futureTimestamp = Date.now() + totalTime; if(futureTimestamp <= closingTimestamp) { return; } $timeout.cancel(closingTimer); @@ -1212,14 +1302,16 @@ var parentID = parentElement.data(NG_ANIMATE_PARENT_KEY); if(!parentID) { parentElement.data(NG_ANIMATE_PARENT_KEY, ++parentCounter); parentID = parentCounter; } - return parentID + '-' + extractElementNode(element).className; + return parentID + '-' + extractElementNode(element).getAttribute('class'); } - function animateSetup(animationEvent, element, className, calculationDecorator) { + function animateSetup(animationEvent, element, className) { + var structural = ['ng-enter','ng-leave','ng-move'].indexOf(className) >= 0; + var cacheKey = getCacheKey(element); var eventCacheKey = cacheKey + ' ' + className; var itemIndex = lookupCache[eventCacheKey] ? ++lookupCache[eventCacheKey].total : 0; var stagger = {}; @@ -1233,114 +1325,88 @@ stagger = getElementAnimationDetails(element, staggerCacheKey); applyClasses && element.removeClass(staggerClassName); } - /* the animation itself may need to add/remove special CSS classes - * before calculating the anmation styles */ - calculationDecorator = calculationDecorator || - function(fn) { return fn(); }; - element.addClass(className); var formerData = element.data(NG_ANIMATE_CSS_DATA_KEY) || {}; - - var timings = calculationDecorator(function() { - return getElementAnimationDetails(element, eventCacheKey); - }); - + var timings = getElementAnimationDetails(element, eventCacheKey); var transitionDuration = timings.transitionDuration; var animationDuration = timings.animationDuration; - if(transitionDuration === 0 && animationDuration === 0) { + + if(structural && transitionDuration === 0 && animationDuration === 0) { element.removeClass(className); return false; } + var blockTransition = structural && transitionDuration > 0; + var blockAnimation = animationDuration > 0 && + stagger.animationDelay > 0 && + stagger.animationDuration === 0; + element.data(NG_ANIMATE_CSS_DATA_KEY, { + stagger : stagger, + cacheKey : eventCacheKey, running : formerData.running || 0, itemIndex : itemIndex, - stagger : stagger, - timings : timings, + blockTransition : blockTransition, + blockAnimation : blockAnimation, closeAnimationFn : noop }); - //temporarily disable the transition so that the enter styles - //don't animate twice (this is here to avoid a bug in Chrome/FF). - var isCurrentlyAnimating = formerData.running > 0 || animationEvent == 'setClass'; - if(transitionDuration > 0) { - blockTransitions(element, className, isCurrentlyAnimating); + var node = extractElementNode(element); + + if(blockTransition) { + node.style[TRANSITION_PROP + PROPERTY_KEY] = 'none'; } - //staggering keyframe animations work by adjusting the `animation-delay` CSS property - //on the given element, however, the delay value can only calculated after the reflow - //since by that time $animate knows how many elements are being animated. Therefore, - //until the reflow occurs the element needs to be blocked (where the keyframe animation - //is set to `none 0s`). This blocking mechanism should only be set for when a stagger - //animation is detected and when the element item index is greater than 0. - if(animationDuration > 0 && stagger.animationDelay > 0 && stagger.animationDuration === 0) { - blockKeyframeAnimations(element); + if(blockAnimation) { + node.style[ANIMATION_PROP] = 'none 0s'; } return true; } - function isStructuralAnimation(className) { - return className == 'ng-enter' || className == 'ng-move' || className == 'ng-leave'; - } - - function blockTransitions(element, className, isAnimating) { - if(isStructuralAnimation(className) || !isAnimating) { - extractElementNode(element).style[TRANSITION_PROP + PROPERTY_KEY] = 'none'; - } else { - element.addClass(NG_ANIMATE_BLOCK_CLASS_NAME); - } - } - - function blockKeyframeAnimations(element) { - extractElementNode(element).style[ANIMATION_PROP] = 'none 0s'; - } - - function unblockTransitions(element, className) { - var prop = TRANSITION_PROP + PROPERTY_KEY; - var node = extractElementNode(element); - if(node.style[prop] && node.style[prop].length > 0) { - node.style[prop] = ''; - } - element.removeClass(NG_ANIMATE_BLOCK_CLASS_NAME); - } - - function unblockKeyframeAnimations(element) { - var prop = ANIMATION_PROP; - var node = extractElementNode(element); - if(node.style[prop] && node.style[prop].length > 0) { - node.style[prop] = ''; - } - } - function animateRun(animationEvent, element, className, activeAnimationComplete) { var node = extractElementNode(element); var elementData = element.data(NG_ANIMATE_CSS_DATA_KEY); - if(node.className.indexOf(className) == -1 || !elementData) { + if(node.getAttribute('class').indexOf(className) == -1 || !elementData) { activeAnimationComplete(); return; } + if(elementData.blockTransition) { + node.style[TRANSITION_PROP + PROPERTY_KEY] = ''; + } + + if(elementData.blockAnimation) { + node.style[ANIMATION_PROP] = ''; + } + var activeClassName = ''; forEach(className.split(' '), function(klass, i) { activeClassName += (i > 0 ? ' ' : '') + klass + '-active'; }); - var stagger = elementData.stagger; - var timings = elementData.timings; - var itemIndex = elementData.itemIndex; + element.addClass(activeClassName); + var eventCacheKey = elementData.eventCacheKey + ' ' + activeClassName; + var timings = getElementAnimationDetails(element, eventCacheKey); + var maxDuration = Math.max(timings.transitionDuration, timings.animationDuration); + if(maxDuration === 0) { + element.removeClass(activeClassName); + animateClose(element, className); + activeAnimationComplete(); + return; + } + var maxDelay = Math.max(timings.transitionDelay, timings.animationDelay); + var stagger = elementData.stagger; + var itemIndex = elementData.itemIndex; var maxDelayTime = maxDelay * ONE_SECOND; - var startTime = Date.now(); - var css3AnimationEvents = ANIMATIONEND_EVENT + ' ' + TRANSITIONEND_EVENT; - var style = '', appliedStyles = []; if(timings.transitionDuration > 0) { var propertyStyle = timings.transitionPropertyStyle; if(propertyStyle.indexOf('all') == -1) { style += CSS_PREFIX + 'transition-property: ' + propertyStyle + ';'; @@ -1371,12 +1437,14 @@ //the styles since there is always only one element being animated var oldStyle = node.getAttribute('style') || ''; node.setAttribute('style', oldStyle + ' ' + style); } + var startTime = Date.now(); + var css3AnimationEvents = ANIMATIONEND_EVENT + ' ' + TRANSITIONEND_EVENT; + element.on(css3AnimationEvents, onAnimationProgress); - element.addClass(activeClassName); elementData.closeAnimationFn = function() { onEnd(); activeAnimationComplete(); }; @@ -1464,12 +1532,10 @@ //animation. The first function will take care of removing the //data from the element which will not make the 2nd animation //happen in the first place var cancel = preReflowCancellation; afterReflow(element, function() { - unblockTransitions(element, className); - unblockKeyframeAnimations(element); //once the reflow is complete then we point cancel to //the new cancellation function which will remove all of the //animation properties from the active animation cancel = animateAfter(animationEvent, element, className, animationComplete); }); @@ -1506,53 +1572,31 @@ }, beforeSetClass : function(element, add, remove, animationCompleted) { var className = suffixClasses(remove, '-remove') + ' ' + suffixClasses(add, '-add'); - var cancellationMethod = animateBefore('setClass', element, className, function(fn) { - /* when classes are removed from an element then the transition style - * that is applied is the transition defined on the element without the - * CSS class being there. This is how CSS3 functions outside of ngAnimate. - * http://plnkr.co/edit/j8OzgTNxHTb4n3zLyjGW?p=preview */ - var klass = element.attr('class'); - element.removeClass(remove); - element.addClass(add); - var timings = fn(); - element.attr('class', klass); - return timings; - }); - + var cancellationMethod = animateBefore('setClass', element, className); if(cancellationMethod) { - afterReflow(element, function() { - unblockTransitions(element, className); - unblockKeyframeAnimations(element); - animationCompleted(); - }); + afterReflow(element, animationCompleted); return cancellationMethod; } animationCompleted(); }, beforeAddClass : function(element, className, animationCompleted) { - var cancellationMethod = animateBefore('addClass', element, suffixClasses(className, '-add'), function(fn) { + var cancellationMethod = animateBefore('addClass', element, suffixClasses(className, '-add')); + if(cancellationMethod) { + afterReflow(element, animationCompleted); + return cancellationMethod; + } + animationCompleted(); + }, - /* when a CSS class is added to an element then the transition style that - * is applied is the transition defined on the element when the CSS class - * is added at the time of the animation. This is how CSS3 functions - * outside of ngAnimate. */ - element.addClass(className); - var timings = fn(); - element.removeClass(className); - return timings; - }); - + beforeRemoveClass : function(element, className, animationCompleted) { + var cancellationMethod = animateBefore('removeClass', element, suffixClasses(className, '-remove')); if(cancellationMethod) { - afterReflow(element, function() { - unblockTransitions(element, className); - unblockKeyframeAnimations(element); - animationCompleted(); - }); + afterReflow(element, animationCompleted); return cancellationMethod; } animationCompleted(); }, @@ -1563,33 +1607,9 @@ return animateAfter('setClass', element, className, animationCompleted); }, addClass : function(element, className, animationCompleted) { return animateAfter('addClass', element, suffixClasses(className, '-add'), animationCompleted); - }, - - beforeRemoveClass : function(element, className, animationCompleted) { - var cancellationMethod = animateBefore('removeClass', element, suffixClasses(className, '-remove'), function(fn) { - /* when classes are removed from an element then the transition style - * that is applied is the transition defined on the element without the - * CSS class being there. This is how CSS3 functions outside of ngAnimate. - * http://plnkr.co/edit/j8OzgTNxHTb4n3zLyjGW?p=preview */ - var klass = element.attr('class'); - element.removeClass(className); - var timings = fn(); - element.attr('class', klass); - return timings; - }); - - if(cancellationMethod) { - afterReflow(element, function() { - unblockTransitions(element, className); - unblockKeyframeAnimations(element); - animationCompleted(); - }); - return cancellationMethod; - } - animationCompleted(); }, removeClass : function(element, className, animationCompleted) { return animateAfter('removeClass', element, suffixClasses(className, '-remove'), animationCompleted); }