diff options
author | Bernhard Posselt <dev@bernhard-posselt.com> | 2015-05-28 17:25:33 +0200 |
---|---|---|
committer | Bernhard Posselt <dev@bernhard-posselt.com> | 2015-05-28 17:25:33 +0200 |
commit | 67f1bab200637ce78f5baefb9e42ef6ef59a542f (patch) | |
tree | 350d7742c891f0ad54fb354f0765e66629b51a5f /js/vendor/angular-animate/angular-animate.js | |
parent | ddb0d5020f4deccc2aec9d959ea434828e60a699 (diff) |
downgrade angular because of regressions
Diffstat (limited to 'js/vendor/angular-animate/angular-animate.js')
-rw-r--r-- | js/vendor/angular-animate/angular-animate.js | 5245 |
1 files changed, 1837 insertions, 3408 deletions
diff --git a/js/vendor/angular-animate/angular-animate.js b/js/vendor/angular-animate/angular-animate.js index 42b03e0b5..7bd0d7a3a 100644 --- a/js/vendor/angular-animate/angular-animate.js +++ b/js/vendor/angular-animate/angular-animate.js @@ -1,3708 +1,2137 @@ /** - * @license AngularJS v1.4.0 - * (c) 2010-2015 Google, Inc. http://angularjs.org + * @license AngularJS v1.3.15 + * (c) 2010-2014 Google, Inc. http://angularjs.org * License: MIT */ (function(window, angular, undefined) {'use strict'; -/* jshint ignore:start */ -var noop = angular.noop; -var extend = angular.extend; -var jqLite = angular.element; -var forEach = angular.forEach; -var isArray = angular.isArray; -var isString = angular.isString; -var isObject = angular.isObject; -var isUndefined = angular.isUndefined; -var isDefined = angular.isDefined; -var isFunction = angular.isFunction; -var isElement = angular.isElement; - -var ELEMENT_NODE = 1; -var COMMENT_NODE = 8; - -var NG_ANIMATE_CLASSNAME = 'ng-animate'; -var NG_ANIMATE_CHILDREN_DATA = '$$ngAnimateChildren'; - -var isPromiseLike = function(p) { - return p && p.then ? true : false; -} - -function assertArg(arg, name, reason) { - if (!arg) { - throw ngMinErr('areq', "Argument '{0}' is {1}", (name || '?'), (reason || "required")); - } - return arg; -} - -function mergeClasses(a,b) { - if (!a && !b) return ''; - if (!a) return b; - if (!b) return a; - if (isArray(a)) a = a.join(' '); - if (isArray(b)) b = b.join(' '); - return a + ' ' + b; -} - -function packageStyles(options) { - var styles = {}; - if (options && (options.to || options.from)) { - styles.to = options.to; - styles.from = options.from; - } - return styles; -} - -function pendClasses(classes, fix, isPrefix) { - var className = ''; - classes = isArray(classes) - ? classes - : classes && isString(classes) && classes.length - ? classes.split(/\s+/) - : []; - forEach(classes, function(klass, i) { - if (klass && klass.length > 0) { - className += (i > 0) ? ' ' : ''; - className += isPrefix ? fix + klass - : klass + fix; - } - }); - return className; -} - -function removeFromArray(arr, val) { - var index = arr.indexOf(val); - if (val >= 0) { - arr.splice(index, 1); - } -} - -function stripCommentsFromElement(element) { - if (element instanceof jqLite) { - switch (element.length) { - case 0: - return []; - break; - - case 1: - // there is no point of stripping anything if the element - // is the only element within the jqLite wrapper. - // (it's important that we retain the element instance.) - if (element[0].nodeType === ELEMENT_NODE) { - return element; - } - break; - - default: - return jqLite(extractElementNode(element)); - break; - } - } - - if (element.nodeType === ELEMENT_NODE) { - return jqLite(element); - } -} - -function extractElementNode(element) { - if (!element[0]) return element; - for (var i = 0; i < element.length; i++) { - var elm = element[i]; - if (elm.nodeType == ELEMENT_NODE) { - return elm; - } - } -} - -function $$addClass($$jqLite, element, className) { - forEach(element, function(elm) { - $$jqLite.addClass(elm, className); - }); -} - -function $$removeClass($$jqLite, element, className) { - forEach(element, function(elm) { - $$jqLite.removeClass(elm, className); - }); -} - -function applyAnimationClassesFactory($$jqLite) { - return function(element, options) { - if (options.addClass) { - $$addClass($$jqLite, element, options.addClass); - options.addClass = null; - } - if (options.removeClass) { - $$removeClass($$jqLite, element, options.removeClass); - options.removeClass = null; - } - } -} - -function prepareAnimationOptions(options) { - options = options || {}; - if (!options.$$prepared) { - var domOperation = options.domOperation || noop; - options.domOperation = function() { - options.$$domOperationFired = true; - domOperation(); - domOperation = noop; - }; - options.$$prepared = true; - } - return options; -} - -function applyAnimationStyles(element, options) { - applyAnimationFromStyles(element, options); - applyAnimationToStyles(element, options); -} - -function applyAnimationFromStyles(element, options) { - if (options.from) { - element.css(options.from); - options.from = null; - } -} - -function applyAnimationToStyles(element, options) { - if (options.to) { - element.css(options.to); - options.to = null; - } -} - -function mergeAnimationOptions(element, target, newOptions) { - var toAdd = (target.addClass || '') + ' ' + (newOptions.addClass || ''); - var toRemove = (target.removeClass || '') + ' ' + (newOptions.removeClass || ''); - var classes = resolveElementClasses(element.attr('class'), toAdd, toRemove); - - extend(target, newOptions); - - if (classes.addClass) { - target.addClass = classes.addClass; - } else { - target.addClass = null; - } - - if (classes.removeClass) { - target.removeClass = classes.removeClass; - } else { - target.removeClass = null; - } - - return target; -} - -function resolveElementClasses(existing, toAdd, toRemove) { - var ADD_CLASS = 1; - var REMOVE_CLASS = -1; - - var flags = {}; - existing = splitClassesToLookup(existing); - - toAdd = splitClassesToLookup(toAdd); - forEach(toAdd, function(value, key) { - flags[key] = ADD_CLASS; - }); - - toRemove = splitClassesToLookup(toRemove); - forEach(toRemove, function(value, key) { - flags[key] = flags[key] === ADD_CLASS ? null : REMOVE_CLASS; - }); - - var classes = { - addClass: '', - removeClass: '' - }; - - forEach(flags, function(val, klass) { - var prop, allow; - if (val === ADD_CLASS) { - prop = 'addClass'; - allow = !existing[klass]; - } else if (val === REMOVE_CLASS) { - prop = 'removeClass'; - allow = existing[klass]; - } - if (allow) { - if (classes[prop].length) { - classes[prop] += ' '; - } - classes[prop] += klass; - } - }); - - function splitClassesToLookup(classes) { - if (isString(classes)) { - classes = classes.split(' '); - } - - var obj = {}; - forEach(classes, function(klass) { - // sometimes the split leaves empty string values - // incase extra spaces were applied to the options - if (klass.length) { - obj[klass] = true; - } - }); - return obj; - } - - return classes; -} - -function getDomNode(element) { - return (element instanceof angular.element) ? element[0] : element; -} - -var $$rAFSchedulerFactory = ['$$rAF', function($$rAF) { - var tickQueue = []; - var cancelFn; - - function scheduler(tasks) { - // we make a copy since RAFScheduler mutates the state - // of the passed in array variable and this would be difficult - // to track down on the outside code - tickQueue.push([].concat(tasks)); - nextTick(); - } - - /* waitUntilQuiet does two things: - * 1. It will run the FINAL `fn` value only when an uncancelled RAF has passed through - * 2. It will delay the next wave of tasks from running until the quiet `fn` has run. - * - * The motivation here is that animation code can request more time from the scheduler - * before the next wave runs. This allows for certain DOM properties such as classes to - * be resolved in time for the next animation to run. - */ - scheduler.waitUntilQuiet = function(fn) { - if (cancelFn) cancelFn(); - - cancelFn = $$rAF(function() { - cancelFn = null; - fn(); - nextTick(); - }); - }; - - return scheduler; - - function nextTick() { - if (!tickQueue.length) return; - - var updatedQueue = []; - for (var i = 0; i < tickQueue.length; i++) { - var innerQueue = tickQueue[i]; - runNextTask(innerQueue); - if (innerQueue.length) { - updatedQueue.push(innerQueue); - } - } - tickQueue = updatedQueue; - - if (!cancelFn) { - $$rAF(function() { - if (!cancelFn) nextTick(); - }); - } - } - - function runNextTask(tasks) { - var nextTask = tasks.shift(); - nextTask(); - } -}]; - -var $$AnimateChildrenDirective = [function() { - return function(scope, element, attrs) { - var val = attrs.ngAnimateChildren; - if (angular.isString(val) && val.length === 0) { //empty attribute - element.data(NG_ANIMATE_CHILDREN_DATA, true); - } else { - attrs.$observe('ngAnimateChildren', function(value) { - value = value === 'on' || value === 'true'; - element.data(NG_ANIMATE_CHILDREN_DATA, value); - }); - } - }; -}]; +/* jshint maxlen: false */ /** - * @ngdoc service - * @name $animateCss - * @kind object - * + * @ngdoc module + * @name ngAnimate * @description - * The `$animateCss` service is a useful utility to trigger customized CSS-based transitions/keyframes - * from a JavaScript-based animation or directly from a directive. The purpose of `$animateCss` is NOT - * to side-step how `$animate` and ngAnimate work, but the goal is to allow pre-existing animations or - * directives to create more complex animations that can be purely driven using CSS code. * - * Note that only browsers that support CSS transitions and/or keyframe animations are capable of - * rendering animations triggered via `$animateCss` (bad news for IE9 and lower). + * 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 + * or to register a JavaScript animation via the `myModule.animation()` function. The directives that support animation automatically are: + * `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#animations ngRepeat} | enter, leave and move | + * | {@link ngRoute.directive:ngView#animations ngView} | enter and leave | + * | {@link ng.directive:ngInclude#animations ngInclude} | enter and leave | + * | {@link ng.directive:ngSwitch#animations ngSwitch} | enter and leave | + * | {@link ng.directive:ngIf#animations ngIf} | enter and leave | + * | {@link ng.directive:ngClass#animations ngClass} | add and remove (the CSS class(es) present) | + * | {@link ng.directive:ngShow#animations ngShow} & {@link ng.directive:ngHide#animations ngHide} | add and remove (the ng-hide class value) | + * | {@link ng.directive:form#animation-hooks form} & {@link ng.directive:ngModel#animation-hooks ngModel} | add and remove (dirty, pristine, valid, invalid & all other validations) | + * | {@link module:ngMessages#animations ngMessages} | add and remove (ng-active & ng-inactive) | + * | {@link module:ngMessages#animations ngMessage} | enter and leave | + * + * You can find out more information about animations upon visiting each directive page. * - * ## Usage - * Once again, `$animateCss` is designed to be used inside of a registered JavaScript animation that - * is powered by ngAnimate. It is possible to use `$animateCss` directly inside of a directive, however, - * any automatic control over cancelling animations and/or preventing animations from being run on - * child elements will not be handled by Angular. For this to work as expected, please use `$animate` to - * trigger the animation and then setup a JavaScript animation that injects `$animateCss` to trigger - * the CSS animation. + * Below is an example of how to apply animations to a directive that supports animation hooks: * - * The example below shows how we can create a folding animation on an element using `ng-if`: + * ```html + * <style type="text/css"> + * .slide.ng-enter, .slide.ng-leave { + * -webkit-transition:0.5s linear all; + * transition:0.5s linear all; + * } + * + * .slide.ng-enter { } /* starting animations for enter */ + * .slide.ng-enter.ng-enter-active { } /* terminal animations for enter */ + * .slide.ng-leave { } /* starting animations for leave */ + * .slide.ng-leave.ng-leave-active { } /* terminal animations for leave */ + * </style> + * + * <!-- + * the animate service will automatically add .ng-enter and .ng-leave to the element + * to trigger the CSS transition/animations + * --> + * <ANY class="slide" ng-include="..."></ANY> + * ``` + * + * Keep in mind that, by default, if an animation is running, any child elements cannot be animated + * until the parent element's animation has completed. This blocking feature can be overridden by + * placing the `ng-animate-children` attribute on a parent container tag. * * ```html - * <!-- notice the `fold-animation` CSS class --> - * <div ng-if="onOff" class="fold-animation"> - * This element will go BOOM + * <div class="slide-animation" ng-if="on" ng-animate-children> + * <div class="fade-animation" ng-if="on"> + * <div class="explode-animation" ng-if="on"> + * ... + * </div> + * </div> * </div> - * <button ng-click="onOff=true">Fold In</button> * ``` * - * Now we create the **JavaScript animation** that will trigger the CSS transition: + * When the `on` expression value changes and an animation is triggered then each of the elements within + * will all animate without the block being applied to child elements. * - * ```js - * ngModule.animation('.fold-animation', ['$animateCss', function($animateCss) { - * return { - * enter: function(element, doneFn) { - * var height = element[0].offsetHeight; - * return $animateCss(element, { - * from: { height:'0px' }, - * to: { height:height + 'px' }, - * duration: 1 // one second - * }); - * } - * } - * }]); - * ``` + * ## Are animations run when the application starts? + * No they are not. When an application is bootstrapped Angular will disable animations from running to avoid + * a frenzy of animations from being triggered as soon as the browser has rendered the screen. For this to work, + * Angular will wait for two digest cycles until enabling animations. From there on, any animation-triggering + * layout changes in the application will trigger animations as normal. * - * ## More Advanced Uses + * In addition, upon bootstrap, if the routing system or any directives or load remote data (via $http) then Angular + * will automatically extend the wait time to enable animations once **all** of the outbound HTTP requests + * are complete. * - * `$animateCss` is the underlying code that ngAnimate uses to power **CSS-based animations** behind the scenes. Therefore CSS hooks - * like `.ng-EVENT`, `.ng-EVENT-active`, `.ng-EVENT-stagger` are all features that can be triggered using `$animateCss` via JavaScript code. + * ## CSS-defined Animations + * The animate service will automatically apply two CSS classes to the animated element and these two CSS classes + * are designed to contain the start and end CSS styling. Both CSS transitions and keyframe animations are supported + * and can be used to play along with this naming structure. * - * This also means that just about any combination of adding classes, removing classes, setting styles, dynamically setting a keyframe animation, - * applying a hardcoded duration or delay value, changing the animation easing or applying a stagger animation are all options that work with - * `$animateCss`. The service itself is smart enough to figure out the combination of options and examine the element styling properties in order - * to provide a working animation that will run in CSS. + * The following code below demonstrates how to perform animations using **CSS transitions** with Angular: * - * The example below showcases a more advanced version of the `.fold-animation` from the example above: + * ```html + * <style type="text/css"> + * /* + * The animate class is apart of the element and the ng-enter class + * is attached to the element once the enter animation event is triggered + * */ + * .reveal-animation.ng-enter { + * -webkit-transition: 1s linear all; /* Safari/Chrome */ + * transition: 1s linear all; /* All other modern browsers and IE10+ */ + * + * /* The animation preparation code */ + * opacity: 0; + * } * - * ```js - * ngModule.animation('.fold-animation', ['$animateCss', function($animateCss) { - * return { - * enter: function(element, doneFn) { - * var height = element[0].offsetHeight; - * return $animateCss(element, { - * addClass: 'red large-text pulse-twice', - * easing: 'ease-out', - * from: { height:'0px' }, - * to: { height:height + 'px' }, - * duration: 1 // one second - * }); - * } - * } - * }]); + * /* + * Keep in mind that you want to combine both CSS + * classes together to avoid any CSS-specificity + * conflicts + * */ + * .reveal-animation.ng-enter.ng-enter-active { + * /* The animation code itself */ + * opacity: 1; + * } + * </style> + * + * <div class="view-container"> + * <div ng-view class="reveal-animation"></div> + * </div> * ``` * - * Since we're adding/removing CSS classes then the CSS transition will also pick those up: + * The following code below demonstrates how to perform animations using **CSS animations** with Angular: * - * ```css - * /* since a hardcoded duration value of 1 was provided in the JavaScript animation code, - * the CSS classes below will be transitioned despite them being defined as regular CSS classes */ - * .red { background:red; } - * .large-text { font-size:20px; } - * - * /* we can also use a keyframe animation and $animateCss will make it work alongside the transition */ - * .pulse-twice { - * animation: 0.5s pulse linear 2; - * -webkit-animation: 0.5s pulse linear 2; + * ```html + * <style type="text/css"> + * .reveal-animation.ng-enter { + * -webkit-animation: enter_sequence 1s linear; /* Safari/Chrome */ + * animation: enter_sequence 1s linear; /* IE10+ and Future Browsers */ * } + * @-webkit-keyframes enter_sequence { + * from { opacity:0; } + * to { opacity:1; } + * } + * @keyframes enter_sequence { + * from { opacity:0; } + * to { opacity:1; } + * } + * </style> + * + * <div class="view-container"> + * <div ng-view class="reveal-animation"></div> + * </div> + * ``` + * + * Both CSS3 animations and transitions can be used together and the animate service will figure out the correct duration and delay timing. + * + * Upon DOM mutation, the event class is added first (something like `ng-enter`), then the browser prepares itself to add + * the active class (in this case `ng-enter-active`) which then triggers the animation. The animation module will automatically + * 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. + * + * ### 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 { + * /* remember to place a 0s transition here + * to ensure that the styles are applied instantly + * even if the element already has a transition style */ + * transition:0s linear all; * - * @keyframes pulse { - * from { transform: scale(0.5); } - * to { transform: scale(1.5); } + * /* starting CSS styles */ + * opacity:1; * } + * .fade-add.fade-add-active { + * /* this will be the length of the animation */ + * transition:1s linear all; + * opacity:0; + * } + * ``` * - * @-webkit-keyframes pulse { - * from { -webkit-transform: scale(0.5); } - * to { -webkit-transform: scale(1.5); } + * 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 + * /* this works as expected */ + * .fade { + * transition:1s linear all; + * opacity:0; * } * ``` * - * Given this complex combination of CSS classes, styles and options, `$animateCss` will figure everything out and make the animation happen. + * 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. + * * - * ## How the Options are handled + * ### Preventing Collisions With Third Party Libraries + * + * Some third-party frameworks place animation duration defaults across many element or className + * selectors in order to make their code small and reuseable. This can lead to issues with ngAnimate, which + * is expecting actual animations on these elements and has to wait for their completion. + * + * You can prevent this unwanted behavior by using a prefix on all your animation classes: + * + * ```css + * /* prefixed with animate- */ + * .animate-fade-add.animate-fade-add-active { + * transition:1s linear all; + * opacity:0; + * } + * ``` * - * `$animateCss` is very versatile and intelligent when it comes to figuring out what configurations to apply to the element to ensure the animation - * works with the options provided. Say for example we were adding a class that contained a keyframe value and we wanted to also animate some inline - * styles using the `from` and `to` properties. + * You then configure `$animate` to enforce this prefix: * * ```js - * var animator = $animateCss(element, { - * from: { background:'red' }, - * to: { background:'blue' } - * }); - * animator.start(); + * $animateProvider.classNameFilter(/animate-/); * ``` + * </div> + * + * ### 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 (versions >=1.2) 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). * * ```css - * .rotating-animation { - * animation:0.5s rotate linear; - * -webkit-animation:0.5s rotate linear; + * .my-animation.ng-enter { + * /* standard transition code */ + * -webkit-transition: 1s linear all; + * transition: 1s linear all; + * opacity:0; * } + * .my-animation.ng-enter-stagger { + * /* this will have a 100ms delay between each successive leave animation */ + * -webkit-transition-delay: 0.1s; + * transition-delay: 0.1s; * - * @keyframes rotate { - * from { transform: rotate(0deg); } - * to { transform: rotate(360deg); } + * /* in case the stagger doesn't work then these two values + * must be set to 0 to avoid an accidental CSS inheritance */ + * -webkit-transition-duration: 0s; + * transition-duration: 0s; * } - * - * @-webkit-keyframes rotate { - * from { -webkit-transform: rotate(0deg); } - * to { -webkit-transform: rotate(360deg); } + * .my-animation.ng-enter.ng-enter-active { + * /* standard transition styles */ + * opacity:1; * } * ``` * - * The missing pieces here are that we do not have a transition set (within the CSS code nor within the `$animateCss` options) and the duration of the animation is - * going to be detected from what the keyframe styles on the CSS class are. In this event, `$animateCss` will automatically create an inline transition - * style matching the duration detected from the keyframe style (which is present in the CSS class that is being added) and then prepare both the transition - * and keyframe animations to run in parallel on the element. Then when the animation is underway the provided `from` and `to` CSS styles will be applied - * and spread across the transition and keyframe animation. + * Staggering animations work by default in ngRepeat (so long as the CSS class is defined). Outside of ngRepeat, to use staggering animations + * on your own, they can be triggered by firing multiple calls to the same event on $animate. However, the restrictions surrounding this + * are that each of the elements must have the same CSS className value as well as the same parent element. A stagger operation + * will also be reset if more than 10ms has passed after the last animation has been fired. * - * ## What is returned + * The following code will issue the **ng-leave-stagger** event on the element provided: * - * `$animateCss` works in two stages: a preparation phase and an animation phase. Therefore when `$animateCss` is first called it will NOT actually - * start the animation. All that is going on here is that the element is being prepared for the animation (which means that the generated CSS classes are - * added and removed on the element). Once `$animateCss` is called it will return an object with the following properties: + * ```js + * var kids = parent.children(); + * + * $animate.leave(kids[0]); //stagger index=0 + * $animate.leave(kids[1]); //stagger index=1 + * $animate.leave(kids[2]); //stagger index=2 + * $animate.leave(kids[3]); //stagger index=3 + * $animate.leave(kids[4]); //stagger index=4 + * + * $timeout(function() { + * //stagger has reset itself + * $animate.leave(kids[5]); //stagger index=0 + * $animate.leave(kids[6]); //stagger index=1 + * }, 100, false); + * ``` + * + * Stagger animations are currently only supported within CSS-defined animations. + * + * ## JavaScript-defined Animations + * 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 + * yet support CSS transitions/animations, then you can make use of JavaScript animations defined inside of your AngularJS module. * * ```js - * var animator = $animateCss(element, { ... }); + * //!annotate="YourApp" Your AngularJS Module|Replace this or ngModule with the module that you used to define your application. + * var ngModule = angular.module('YourApp', ['ngAnimate']); + * ngModule.animation('.my-crazy-animation', function() { + * return { + * enter: function(element, done) { + * //run the animation here and call done when the animation is complete + * return function(cancelled) { + * //this (optional) function will be called when the animation + * //completes or when the animation is cancelled (the cancelled + * //flag will be set to true if cancelled). + * }; + * }, + * leave: function(element, done) { }, + * move: function(element, done) { }, + * + * //animation that can be triggered before the class is added + * beforeAddClass: function(element, className, done) { }, + * + * //animation that can be triggered after the class is added + * addClass: function(element, className, done) { }, + * + * //animation that can be triggered before the class is removed + * beforeRemoveClass: function(element, className, done) { }, + * + * //animation that can be triggered after the class is removed + * removeClass: function(element, className, done) { } + * }; + * }); * ``` * - * Now what do the contents of our `animator` variable look like: + * JavaScript-defined animations are created with a CSS-like class selector and a collection of events which are set to run + * a javascript callback function. When an animation is triggered, $animate will look for a matching animation which fits + * the element's CSS class attribute value and then run the matching animation event function (if found). + * In other words, if the CSS classes present on the animated element match any of the JavaScript animations then the callback function will + * be executed. It should be also noted that only simple, single class selectors are allowed (compound class selectors are not supported). + * + * Within a JavaScript animation, an object containing various event callback animation functions is expected to be returned. + * As explained above, these callbacks are triggered based on the animation event. Therefore if an enter animation is run, + * and the JavaScript animation is found, then the enter callback will handle that animation (in addition to the CSS keyframe animation + * or transition code that is defined via a stylesheet). + * + * + * ### Applying Directive-specific Styles to an Animation + * In some cases a directive or service may want to provide `$animate` with extra details that the animation will + * include into its animation. Let's say for example we wanted to render an animation that animates an element + * towards the mouse coordinates as to where the user clicked last. By collecting the X/Y coordinates of the click + * (via the event parameter) we can set the `top` and `left` styles into an object and pass that into our function + * call to `$animate.addClass`. * * ```js - * { - * // starts the animation - * start: Function, + * canvas.on('click', function(e) { + * $animate.addClass(element, 'on', { |