Skip to content

Instantly share code, notes, and snippets.

@benbrandt
Created August 23, 2017 23:51
Show Gist options
  • Save benbrandt/34561643335f1d7442d53272a9080512 to your computer and use it in GitHub Desktop.
Save benbrandt/34561643335f1d7442d53272a9080512 to your computer and use it in GitHub Desktop.
Angular Animate through babel-minify
/**
* @license AngularJS v1.6.5
* (c) 2010-2017 Google, Inc. http://angularjs.org
* License: MIT
*/
(function(window, angular) {'use strict';
var ELEMENT_NODE = 1;
var COMMENT_NODE = 8;
var ADD_CLASS_SUFFIX = '-add';
var REMOVE_CLASS_SUFFIX = '-remove';
var EVENT_CLASS_PREFIX = 'ng-';
var ACTIVE_CLASS_SUFFIX = '-active';
var PREPARE_CLASS_SUFFIX = '-prepare';
var NG_ANIMATE_CLASSNAME = 'ng-animate';
var NG_ANIMATE_CHILDREN_DATA = '$$ngAnimateChildren';
// Detect proper transitionend/animationend event names.
var CSS_PREFIX = '', TRANSITION_PROP, TRANSITIONEND_EVENT, ANIMATION_PROP, ANIMATIONEND_EVENT;
// If unprefixed events are not supported but webkit-prefixed are, use the latter.
// Otherwise, just use W3C names, browsers not supporting them at all will just ignore them.
// Note: Chrome implements `window.onwebkitanimationend` and doesn't implement `window.onanimationend`
// but at the same time dispatches the `animationend` event and not `webkitAnimationEnd`.
// Register both events in case `window.onanimationend` is not supported because of that,
// do the same for `transitionend` as Safari is likely to exhibit similar behavior.
// Also, the only modern browser that uses vendor prefixes for transitions/keyframes is webkit
// therefore there is no reason to test anymore for other vendor prefixes:
// http://caniuse.com/#search=transition
if ((window.ontransitionend === undefined) && (window.onwebkittransitionend !== undefined)) {
CSS_PREFIX = '-webkit-';
TRANSITION_PROP = 'WebkitTransition';
TRANSITIONEND_EVENT = 'webkitTransitionEnd transitionend';
} else {
TRANSITION_PROP = 'transition';
TRANSITIONEND_EVENT = 'transitionend';
}
if ((window.onanimationend === undefined) && (window.onwebkitanimationend !== undefined)) {
CSS_PREFIX = '-webkit-';
ANIMATION_PROP = 'WebkitAnimation';
ANIMATIONEND_EVENT = 'webkitAnimationEnd animationend';
} else {
ANIMATION_PROP = 'animation';
ANIMATIONEND_EVENT = 'animationend';
}
var DURATION_KEY = 'Duration';
var PROPERTY_KEY = 'Property';
var DELAY_KEY = 'Delay';
var TIMING_KEY = 'TimingFunction';
var ANIMATION_ITERATION_COUNT_KEY = 'IterationCount';
var ANIMATION_PLAYSTATE_KEY = 'PlayState';
var SAFE_FAST_FORWARD_DURATION_VALUE = 9999;
var ANIMATION_DELAY_PROP = ANIMATION_PROP + DELAY_KEY;
var ANIMATION_DURATION_PROP = ANIMATION_PROP + DURATION_KEY;
var TRANSITION_DELAY_PROP = TRANSITION_PROP + DELAY_KEY;
var TRANSITION_DURATION_PROP = TRANSITION_PROP + DURATION_KEY;
var ngMinErr = angular.$$minErr('ng');
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 element;
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));
}
}
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 mergeAnimationDetails(element, oldAnimation, newAnimation) {
var target = oldAnimation.options || {};
var newOptions = newAnimation.options || {};
var toAdd = (target.addClass || '') + ' ' + (newOptions.addClass || '');
var toRemove = (target.removeClass || '') + ' ' + (newOptions.removeClass || '');
var classes = resolveElementClasses(element.attr('class'), toAdd, toRemove);
if (newOptions.preparationClasses) {
target.preparationClasses = concatWithSpace(newOptions.preparationClasses, target.preparationClasses);
delete newOptions.preparationClasses;
}
// noop is basically when there is no callback; otherwise something has been set
var realDomOperation = target.domOperation !== noop ? target.domOperation : null;
extend(target, newOptions);
// TODO(matsko or sreeramu): proper fix is to maintain all animation callback in array and call at last,but now only leave has the callback so no issue with this.
if (realDomOperation) {
target.domOperation = realDomOperation;
}
if (classes.addClass) {
target.addClass = classes.addClass;
} else {
target.addClass = null;
}
if (classes.removeClass) {
target.removeClass = classes.removeClass;
} else {
target.removeClass = null;
}
oldAnimation.addClass = target.addClass;
oldAnimation.removeClass = target.removeClass;
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] || existing[klass + REMOVE_CLASS_SUFFIX];
} else if (val === REMOVE_CLASS) {
prop = 'removeClass';
allow = existing[klass] || existing[klass + ADD_CLASS_SUFFIX];
}
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 jqLite) ? element[0] : element;
}
function applyGeneratedPreparationClasses(element, event, options) {
var classes = '';
if (event) {
classes = pendClasses(event, EVENT_CLASS_PREFIX, true);
}
if (options.addClass) {
classes = concatWithSpace(classes, pendClasses(options.addClass, ADD_CLASS_SUFFIX));
}
if (options.removeClass) {
classes = concatWithSpace(classes, pendClasses(options.removeClass, REMOVE_CLASS_SUFFIX));
}
if (classes.length) {
options.preparationClasses = classes;
element.addClass(classes);
}
}
function clearGeneratedClasses(element, options) {
if (options.preparationClasses) {
element.removeClass(options.preparationClasses);
options.preparationClasses = null;
}
if (options.activeClasses) {
element.removeClass(options.activeClasses);
options.activeClasses = null;
}
}
function blockTransitions(node, duration) {
// we use a negative delay value since it performs blocking
// yet it doesn't kill any existing transitions running on the
// same element which makes this safe for class-based animations
var value = duration ? '-' + duration + 's' : '';
applyInlineStyle(node, [TRANSITION_DELAY_PROP, value]);
return [TRANSITION_DELAY_PROP, value];
}
function blockKeyframeAnimations(node, applyBlock) {
var value = applyBlock ? 'paused' : '';
var key = ANIMATION_PROP + ANIMATION_PLAYSTATE_KEY;
applyInlineStyle(node, [key, value]);
return [key, value];
}
function applyInlineStyle(node, styleTuple) {
var prop = styleTuple[0];
var value = styleTuple[1];
node.style[prop] = value;
}
function concatWithSpace(a,b) {
if (!a) return b;
if (!b) return a;
return a + ' ' + b;
}
var $$rAFSchedulerFactory = ['$$rAF', function($$rAF) {
var queue, 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
queue = queue.concat(tasks);
nextTick();
}
queue = scheduler.queue = [];
/* waitUntilQuiet does two things:
* 1. It will run the FINAL `fn` value only when an uncanceled 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 (!queue.length) return;
var items = queue.shift();
for (var i = 0; i < items.length; i++) {
items[i]();
}
if (!cancelFn) {
$$rAF(function() {
if (!cancelFn) nextTick();
});
}
}
}];
/**
* @ngdoc directive
* @name ngAnimateChildren
* @restrict AE
* @element ANY
*
* @description
*
* ngAnimateChildren allows you to specify that children of this element should animate even if any
* of the children's parents are currently animating. By default, when an element has an active `enter`, `leave`, or `move`
* (structural) animation, child elements that also have an active structural animation are not animated.
*
* Note that even if `ngAnimateChildren` is set, no child animations will run when the parent element is removed from the DOM (`leave` animation).
*
*
* @param {string} ngAnimateChildren If the value is empty, `true` or `on`,
* then child animations are allowed. If the value is `false`, child animations are not allowed.
*
* @example
* <example module="ngAnimateChildren" name="ngAnimateChildren" deps="angular-animate.js" animations="true">
<file name="index.html">
<div ng-controller="MainController as main">
<label>Show container? <input type="checkbox" ng-model="main.enterElement" /></label>
<label>Animate children? <input type="checkbox" ng-model="main.animateChildren" /></label>
<hr>
<div ng-animate-children="{{main.animateChildren}}">
<div ng-if="main.enterElement" class="container">
List of items:
<div ng-repeat="item in [0, 1, 2, 3]" class="item">Item {{item}}</div>
</div>
</div>
</div>
</file>
<file name="animations.css">
.container.ng-enter,
.container.ng-leave {
transition: all ease 1.5s;
}
.container.ng-enter,
.container.ng-leave-active {
opacity: 0;
}
.container.ng-leave,
.container.ng-enter-active {
opacity: 1;
}
.item {
background: firebrick;
color: #FFF;
margin-bottom: 10px;
}
.item.ng-enter,
.item.ng-leave {
transition: transform 1.5s ease;
}
.item.ng-enter {
transform: translateX(50px);
}
.item.ng-enter-active {
transform: translateX(0);
}
</file>
<file name="script.js">
angular.module('ngAnimateChildren', ['ngAnimate'])
.controller('MainController', function MainController() {
this.animateChildren = false;
this.enterElement = false;
});
</file>
</example>
*/
var $$AnimateChildrenDirective = ['$interpolate', function($interpolate) {
return {
link: function(scope, element, attrs) {
var val = attrs.ngAnimateChildren;
if (isString(val) && val.length === 0) { //empty attribute
element.data(NG_ANIMATE_CHILDREN_DATA, true);
} else {
// Interpolate and set the value, so that it is available to
// animations that run right after compilation
setData($interpolate(val)(scope));
attrs.$observe('ngAnimateChildren', setData);
}
function setData(value) {
value = value === 'on' || value === 'true';
element.data(NG_ANIMATE_CHILDREN_DATA, value);
}
}
};
}];
/* exported $AnimateCssProvider */
var ANIMATE_TIMER_KEY = '$$animateCss';
/**
* @ngdoc service
* @name $animateCss
* @kind object
*
* @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).
*
* ## 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.
*
* The example below shows how we can create a folding animation on an element using `ng-if`:
*
* ```html
* <!-- notice the `fold-animation` CSS class -->
* <div ng-if="onOff" class="fold-animation">
* This element will go BOOM
* </div>
* <button ng-click="onOff=true">Fold In</button>
* ```
*
* Now we create the **JavaScript animation** that will trigger the CSS transition:
*
* ```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
* });
* }
* }
* }]);
* ```
*
* ## More Advanced Uses
*
* `$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.
*
* 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 example below showcases a more advanced version of the `.fold-animation` from the example above:
*
* ```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
* });
* }
* }
* }]);
* ```
*
* Since we're adding/removing CSS classes then the CSS transition will also pick those up:
*
* ```css
* /&#42; 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 &#42;/
* .red { background:red; }
* .large-text { font-size:20px; }
*
* /&#42; we can also use a keyframe animation and $animateCss will make it work alongside the transition &#42;/
* .pulse-twice {
* animation: 0.5s pulse linear 2;
* -webkit-animation: 0.5s pulse linear 2;
* }
*
* @keyframes pulse {
* from { transform: scale(0.5); }
* to { transform: scale(1.5); }
* }
*
* @-webkit-keyframes pulse {
* from { -webkit-transform: scale(0.5); }
* to { -webkit-transform: scale(1.5); }
* }
* ```
*
* Given this complex combination of CSS classes, styles and options, `$animateCss` will figure everything out and make the animation happen.
*
* ## How the Options are handled
*
* `$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.
*
* ```js
* var animator = $animateCss(element, {
* from: { background:'red' },
* to: { background:'blue' }
* });
* animator.start();
* ```
*
* ```css
* .rotating-animation {
* animation:0.5s rotate linear;
* -webkit-animation:0.5s rotate linear;
* }
*
* @keyframes rotate {
* from { transform: rotate(0deg); }
* to { transform: rotate(360deg); }
* }
*
* @-webkit-keyframes rotate {
* from { -webkit-transform: rotate(0deg); }
* to { -webkit-transform: rotate(360deg); }
* }
* ```
*
* 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.
*
* ## What is returned
*
* `$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 animator = $animateCss(element, { ... });
* ```
*
* Now what do the contents of our `animator` variable look like:
*
* ```js
* {
* // starts the animation
* start: Function,
*
* // ends (aborts) the animation
* end: Function
* }
* ```
*
* To actually start the animation we need to run `animation.start()` which will then return a promise that we can hook into to detect when the animation ends.
* If we choose not to run the animation then we MUST run `animation.end()` to perform a cleanup on the element (since some CSS classes and styles may have been
* applied to the element during the preparation phase). Note that all other properties such as duration, delay, transitions and keyframes are just properties
* and that changing them will not reconfigure the parameters of the animation.
*
* ### runner.done() vs runner.then()
* It is documented that `animation.start()` will return a promise object and this is true, however, there is also an additional method available on the
* runner called `.done(callbackFn)`. The done method works the same as `.finally(callbackFn)`, however, it does **not trigger a digest to occur**.
* Therefore, for performance reasons, it's always best to use `runner.done(callback)` instead of `runner.then()`, `runner.catch()` or `runner.finally()`
* unless you really need a digest to kick off afterwards.
*
* Keep in mind that, to make this easier, ngAnimate has tweaked the JS animations API to recognize when a runner instance is returned from $animateCss
* (so there is no need to call `runner.done(doneFn)` inside of your JavaScript animation code).
* Check the {@link ngAnimate.$animateCss#usage animation code above} to see how this works.
*
* @param {DOMElement} element the element that will be animated
* @param {object} options the animation-related options that will be applied during the animation
*
* * `event` - The DOM event (e.g. enter, leave, move). When used, a generated CSS class of `ng-EVENT` and `ng-EVENT-active` will be applied
* to the element during the animation. Multiple events can be provided when spaces are used as a separator. (Note that this will not perform any DOM operation.)
* * `structural` - Indicates that the `ng-` prefix will be added to the event class. Setting to `false` or omitting will turn `ng-EVENT` and
* `ng-EVENT-active` in `EVENT` and `EVENT-active`. Unused if `event` is omitted.
* * `easing` - The CSS easing value that will be applied to the transition or keyframe animation (or both).
* * `transitionStyle` - The raw CSS transition style that will be used (e.g. `1s linear all`).
* * `keyframeStyle` - The raw CSS keyframe animation style that will be used (e.g. `1s my_animation linear`).
* * `from` - The starting CSS styles (a key/value object) that will be applied at the start of the animation.
* * `to` - The ending CSS styles (a key/value object) that will be applied across the animation via a CSS transition.
* * `addClass` - A space separated list of CSS classes that will be added to the element and spread across the animation.
* * `removeClass` - A space separated list of CSS classes that will be removed from the element and spread across the animation.
* * `duration` - A number value representing the total duration of the transition and/or keyframe (note that a value of 1 is 1000ms). If a value of `0`
* is provided then the animation will be skipped entirely.
* * `delay` - A number value representing the total delay of the transition and/or keyframe (note that a value of 1 is 1000ms). If a value of `true` is
* used then whatever delay value is detected from the CSS classes will be mirrored on the elements styles (e.g. by setting delay true then the style value
* of the element will be `transition-delay: DETECTED_VALUE`). Using `true` is useful when you want the CSS classes and inline styles to all share the same
* CSS delay value.
* * `stagger` - A numeric time value representing the delay between successively animated elements
* ({@link ngAnimate#css-staggering-animations Click here to learn how CSS-based staggering works in ngAnimate.})
* * `staggerIndex` - The numeric index representing the stagger item (e.g. a value of 5 is equal to the sixth item in the stagger; therefore when a
* `stagger` option value of `0.1` is used then there will be a stagger delay of `600ms`)
* * `applyClassesEarly` - Whether or not the classes being added or removed will be used when detecting the animation. This is set by `$animate` when enter/leave/move animations are fired to ensure that the CSS classes are resolved in time. (Note that this will prevent any transitions from occurring on the classes being added and removed.)
* * `cleanupStyles` - Whether or not the provided `from` and `to` styles will be removed once
* the animation is closed. This is useful for when the styles are used purely for the sake of
* the animation and do not have a lasting visual effect on the element (e.g. a collapse and open animation).
* By default this value is set to `false`.
*
* @return {object} an object with start and end methods and details about the animation.
*
* * `start` - The method to start the animation. This will return a `Promise` when called.
* * `end` - This method will cancel the animation and remove all applied CSS classes and styles.
*/
var ONE_SECOND = 1000;
var ELAPSED_TIME_MAX_DECIMAL_PLACES = 3;
var CLOSING_TIME_BUFFER = 1.5;
var DETECT_CSS_PROPERTIES = {
transitionDuration: TRANSITION_DURATION_PROP,
transitionDelay: TRANSITION_DELAY_PROP,
transitionProperty: TRANSITION_PROP + PROPERTY_KEY,
animationDuration: ANIMATION_DURATION_PROP,
animationDelay: ANIMATION_DELAY_PROP,
animationIterationCount: ANIMATION_PROP + ANIMATION_ITERATION_COUNT_KEY
};
var DETECT_STAGGER_CSS_PROPERTIES = {
transitionDuration: TRANSITION_DURATION_PROP,
transitionDelay: TRANSITION_DELAY_PROP,
animationDuration: ANIMATION_DURATION_PROP,
animationDelay: ANIMATION_DELAY_PROP
};
function getCssKeyframeDurationStyle(duration) {
return [ANIMATION_DURATION_PROP, duration + 's'];
}
function getCssDelayStyle(delay, isKeyframeAnimation) {
var prop = isKeyframeAnimation ? ANIMATION_DELAY_PROP : TRANSITION_DELAY_PROP;
return [prop, delay + 's'];
}
function computeCssStyles($window, element, properties) {
var styles = Object.create(null);
var detectedStyles = $window.getComputedStyle(element) || {};
forEach(properties, function(formalStyleName, actualStyleName) {
var val = detectedStyles[formalStyleName];
if (val) {
var c = val.charAt(0);
// only numerical-based values have a negative sign or digit as the first value
if (c === '-' || c === '+' || c >= 0) {
val = parseMaxTime(val);
}
// by setting this to null in the event that the delay is not set or is set directly as 0
// then we can still allow for negative values to be used later on and not mistake this
// value for being greater than any other negative value.
if (val === 0) {
val = null;
}
styles[actualStyleName] = val;
}
});
return styles;
}
function parseMaxTime(str) {
var maxValue = 0;
var values = str.split(/\s*,\s*/);
forEach(values, function(value) {
// it's always safe to consider only second values and omit `ms` values since
// getComputedStyle will always handle the conversion for us
if (value.charAt(value.length - 1) === 's') {
value = value.substring(0, value.length - 1);
}
value = parseFloat(value) || 0;
maxValue = maxValue ? Math.max(value, maxValue) : value;
});
return maxValue;
}
function truthyTimingValue(val) {
return val === 0 || val != null;
}
function getCssTransitionDurationStyle(duration, applyOnlyDuration) {
var style = TRANSITION_PROP;
var value = duration + 's';
if (applyOnlyDuration) {
style += DURATION_KEY;
} else {
value += ' linear all';
}
return [style, value];
}
function createLocalCacheLookup() {
var cache = Object.create(null);
return {
flush: function() {
cache = Object.create(null);
},
count: function(key) {
var entry = cache[key];
return entry ? entry.total : 0;
},
get: function(key) {
var entry = cache[key];
return entry && entry.value;
},
put: function(key, value) {
if (!cache[key]) {
cache[key] = { total: 1, value: value };
} else {
cache[key].total++;
}
}
};
}
// we do not reassign an already present style value since
// if we detect the style property value again we may be
// detecting styles that were added via the `from` styles.
// We make use of `isDefined` here since an empty string
// or null value (which is what getPropertyValue will return
// for a non-existing style) will still be marked as a valid
// value for the style (a falsy value implies that the style
// is to be removed at the end of the animation). If we had a simple
// "OR" statement then it would not be enough to catch that.
function registerRestorableStyles(backup, node, properties) {
forEach(properties, function(prop) {
backup[prop] = isDefined(backup[prop])
? backup[prop]
: node.style.getPropertyValue(prop);
});
}
var $AnimateCssProvider = ['$animateProvider', /** @this */ function($animateProvider) {
var gcsLookup = createLocalCacheLookup();
var gcsStaggerLookup = createLocalCacheLookup();
this.$get = ['$window', '$$jqLite', '$$AnimateRunner', '$timeout',
'$$forceReflow', '$sniffer', '$$rAFScheduler', '$$animateQueue',
function($window, $$jqLite, $$AnimateRunner, $timeout,
$$forceReflow, $sniffer, $$rAFScheduler, $$animateQueue) {
var applyAnimationClasses = applyAnimationClassesFactory($$jqLite);
var parentCounter = 0;
function gcsHashFn(node, extraClasses) {
var KEY = '$$ngAnimateParentKey';
var parentNode = node.parentNode;
var parentID = parentNode[KEY] || (parentNode[KEY] = ++parentCounter);
return parentID + '-' + node.getAttribute('class') + '-' + extraClasses;
}
function computeCachedCssStyles(node, className, cacheKey, properties) {
var timings = gcsLookup.get(cacheKey);
if (!timings) {
timings = computeCssStyles($window, node, properties);
if (timings.animationIterationCount === 'infinite') {
timings.animationIterationCount = 1;
}
}
// we keep putting this in multiple times even though the value and the cacheKey are the same
// because we're keeping an internal tally of how many duplicate animations are detected.
gcsLookup.put(cacheKey, timings);
return timings;
}
function computeCachedCssStaggerStyles(node, className, cacheKey, properties) {
var stagger;
// if we have one or more existing matches of matching elements
// containing the same parent + CSS styles (which is how cacheKey works)
// then staggering is possible
if (gcsLookup.count(cacheKey) > 0) {
stagger = gcsStaggerLookup.get(cacheKey);
if (!stagger) {
var staggerClassName = pendClasses(className, '-stagger');
$$jqLite.addClass(node, staggerClassName);
stagger = computeCssStyles($window, node, properties);
// force the conversion of a null value to zero incase not set
stagger.animationDuration = Math.max(stagger.animationDuration, 0);
stagger.transitionDuration = Math.max(stagger.transitionDuration, 0);
$$jqLite.removeClass(node, staggerClassName);
gcsStaggerLookup.put(cacheKey, stagger);
}
}
return stagger || {};
}
var rafWaitQueue = [];
function waitUntilQuiet(callback) {
rafWaitQueue.push(callback);
$$rAFScheduler.waitUntilQuiet(function() {
gcsLookup.flush();
gcsStaggerLookup.flush();
// DO NOT REMOVE THIS LINE OR REFACTOR OUT THE `pageWidth` variable.
// PLEASE EXAMINE THE `$$forceReflow` service to understand why.
var pageWidth = $$forceReflow();
// we use a for loop to ensure that if the queue is changed
// during this looping then it will consider new requests
for (var i = 0; i < rafWaitQueue.length; i++) {
rafWaitQueue[i](pageWidth);
}
rafWaitQueue.length = 0;
});
}
function computeTimings(node, className, cacheKey) {
var timings = computeCachedCssStyles(node, className, cacheKey, DETECT_CSS_PROPERTIES);
var aD = timings.animationDelay;
var tD = timings.transitionDelay;
timings.maxDelay = aD && tD
? Math.max(aD, tD)
: (aD || tD);
timings.maxDuration = Math.max(
timings.animationDuration * timings.animationIterationCount,
timings.transitionDuration);
return timings;
}
return function init(element, initialOptions) {
// all of the animation functions should create
// a copy of the options data, however, if a
// parent service has already created a copy then
// we should stick to using that
var options = initialOptions || {};
if (!options.$$prepared) {
options = prepareAnimationOptions(copy(options));
}
var restoreStyles = {};
var node = getDomNode(element);
if (!node
|| !node.parentNode
|| !$$animateQueue.enabled()) {
return closeAndReturnNoopAnimator();
}
var temporaryStyles = [];
var classes = element.attr('class');
var styles = packageStyles(options);
var animationClosed;
var animationPaused;
var animationCompleted;
var runner;
var runnerHost;
var maxDelay;
var maxDelayTime;
var maxDuration;
var maxDurationTime;
var startTime;
var events = [];
if (options.duration === 0 || (!$sniffer.animations && !$sniffer.transitions)) {
return closeAndReturnNoopAnimator();
}
var method = options.event && isArray(options.event)
? options.event.join(' ')
: options.event;
var isStructural = method && options.structural;
var structuralClassName = '';
var addRemoveClassName = '';
if (isStructural) {
structuralClassName = pendClasses(method, EVENT_CLASS_PREFIX, true);
} else if (method) {
structuralClassName = method;
}
if (options.addClass) {
addRemoveClassName += pendClasses(options.addClass, ADD_CLASS_SUFFIX);
}
if (options.removeClass) {
if (addRemoveClassName.length) {
addRemoveClassName += ' ';
}
addRemoveClassName += pendClasses(options.removeClass, REMOVE_CLASS_SUFFIX);
}
// there may be a situation where a structural animation is combined together
// with CSS classes that need to resolve before the animation is computed.
// However this means that there is no explicit CSS code to block the animation
// from happening (by setting 0s none in the class name). If this is the case
// we need to apply the classes before the first rAF so we know to continue if
// there actually is a detected transition or keyframe animation
if (options.applyClassesEarly && addRemoveClassName.length) {
applyAnimationClasses(element, options);
}
var preparationClasses = [structuralClassName, addRemoveClassName].join(' ').trim();
var fullClassName = classes + ' ' + preparationClasses;
var activeClasses = pendClasses(preparationClasses, ACTIVE_CLASS_SUFFIX);
var hasToStyles = styles.to && Object.keys(styles.to).length > 0;
var containsKeyframeAnimation = (options.keyframeStyle || '').length > 0;
// there is no way we can trigger an animation if no styles and
// no classes are being applied which would then trigger a transition,
// unless there a is raw keyframe value that is applied to the element.
if (!containsKeyframeAnimation
&& !hasToStyles
&& !preparationClasses) {
return closeAndReturnNoopAnimator();
}
var cacheKey, stagger;
if (options.stagger > 0) {
var staggerVal = parseFloat(options.stagger);
stagger = {
transitionDelay: staggerVal,
animationDelay: staggerVal,
transitionDuration: 0,
animationDuration: 0
};
} else {
cacheKey = gcsHashFn(node, fullClassName);
stagger = computeCachedCssStaggerStyles(node, preparationClasses, cacheKey, DETECT_STAGGER_CSS_PROPERTIES);
}
if (!options.$$skipPreparationClasses) {
$$jqLite.addClass(element, preparationClasses);
}
var applyOnlyDuration;
if (options.transitionStyle) {
var transitionStyle = [TRANSITION_PROP, options.transitionStyle];
applyInlineStyle(node, transitionStyle);
temporaryStyles.push(transitionStyle);
}
if (options.duration >= 0) {
applyOnlyDuration = node.style[TRANSITION_PROP].length > 0;
var durationStyle = getCssTransitionDurationStyle(options.duration, applyOnlyDuration);
// we set the duration so that it will be picked up by getComputedStyle later
applyInlineStyle(node, durationStyle);
temporaryStyles.push(durationStyle);
}
if (options.keyframeStyle) {
var keyframeStyle = [ANIMATION_PROP, options.keyframeStyle];
applyInlineStyle(node, keyframeStyle);
temporaryStyles.push(keyframeStyle);
}
var itemIndex = stagger
? options.staggerIndex >= 0
? options.staggerIndex
: gcsLookup.count(cacheKey)
: 0;
var isFirst = itemIndex === 0;
// this is a pre-emptive way of forcing the setup classes to be added and applied INSTANTLY
// without causing any combination of transitions to kick in. By adding a negative delay value
// it forces the setup class' transition to end immediately. We later then remove the negative
// transition delay to allow for the transition to naturally do it's thing. The beauty here is
// that if there is no transition defined then nothing will happen and this will also allow
// other transitions to be stacked on top of each other without any chopping them out.
if (isFirst && !options.skipBlocking) {
blockTransitions(node, SAFE_FAST_FORWARD_DURATION_VALUE);
}
var timings = computeTimings(node, fullClassName, cacheKey);
var relativeDelay = timings.maxDelay;
maxDelay = Math.max(relativeDelay, 0);
maxDuration = timings.maxDuration;
var flags = {};
flags.hasTransitions = timings.transitionDuration > 0;
flags.hasAnimations = timings.animationDuration > 0;
flags.hasTransitionAll = flags.hasTransitions && timings.transitionProperty === 'all';
flags.applyTransitionDuration = hasToStyles && (
(flags.hasTransitions && !flags.hasTransitionAll)
|| (flags.hasAnimations && !flags.hasTransitions));
flags.applyAnimationDuration = options.duration && flags.hasAnimations;
flags.applyTransitionDelay = truthyTimingValue(options.delay) && (flags.applyTransitionDuration || flags.hasTransitions);
flags.applyAnimationDelay = truthyTimingValue(options.delay) && flags.hasAnimations;
flags.recalculateTimingStyles = addRemoveClassName.length > 0;
if (flags.applyTransitionDuration || flags.applyAnimationDuration) {
maxDuration = options.duration ? parseFloat(options.duration) : maxDuration;
if (flags.applyTransitionDuration) {
flags.hasTransitions = true;
timings.transitionDuration = maxDuration;
applyOnlyDuration = node.style[TRANSITION_PROP + PROPERTY_KEY].length > 0;
temporaryStyles.push(getCssTransitionDurationStyle(maxDuration, applyOnlyDuration));
}
if (flags.applyAnimationDuration) {
flags.hasAnimations = true;
timings.animationDuration = maxDuration;
temporaryStyles.push(getCssKeyframeDurationStyle(maxDuration));
}
}
if (maxDuration === 0 && !flags.recalculateTimingStyles) {
return closeAndReturnNoopAnimator();
}
if (options.delay != null) {
var delayStyle;
if (typeof options.delay !== 'boolean') {
delayStyle = parseFloat(options.delay);
// number in options.delay means we have to recalculate the delay for the closing timeout
maxDelay = Math.max(delayStyle, 0);
}
if (flags.applyTransitionDelay) {
temporaryStyles.push(getCssDelayStyle(delayStyle));
}
if (flags.applyAnimationDelay) {
temporaryStyles.push(getCssDelayStyle(delayStyle, true));
}
}
// we need to recalculate the delay value since we used a pre-emptive negative
// delay value and the delay value is required for the final event checking. This
// property will ensure that this will happen after the RAF phase has passed.
if (options.duration == null && timings.transitionDuration > 0) {
flags.recalculateTimingStyles = flags.recalculateTimingStyles || isFirst;
}
maxDelayTime = maxDelay * ONE_SECOND;
maxDurationTime = maxDuration * ONE_SECOND;
if (!options.skipBlocking) {
flags.blockTransition = timings.transitionDuration > 0;
flags.blockKeyframeAnimation = timings.animationDuration > 0 &&
stagger.animationDelay > 0 &&
stagger.animationDuration === 0;
}
if (options.from) {
if (options.cleanupStyles) {
registerRestorableStyles(restoreStyles, node, Object.keys(options.from));
}
applyAnimationFromStyles(element, options);
}
if (flags.blockTransition || flags.blockKeyframeAnimation) {
applyBlocking(maxDuration);
} else if (!options.skipBlocking) {
blockTransitions(node, false);
}
// TODO(matsko): for 1.5 change this code to have an animator object for better debugging
return {
$$willAnimate: true,
end: endFn,
start: function() {
if (animationClosed) return;
runnerHost = {
end: endFn,
cancel: cancelFn,
resume: null, //this will be set during the start() phase
pause: null
};
runner = new $$AnimateRunner(runnerHost);
waitUntilQuiet(start);
// we don't have access to pause/resume the animation
// since it hasn't run yet. AnimateRunner will therefore
// set noop functions for resume and pause and they will
// later be overridden once the animation is triggered
return runner;
}
};
function endFn() {
close();
}
function cancelFn() {
close(true);
}
function close(rejected) {
// if the promise has been called already then we shouldn't close
// the animation again
if (animationClosed || (animationCompleted && animationPaused)) return;
animationClosed = true;
animationPaused = false;
if (!options.$$skipPreparationClasses) {
$$jqLite.removeClass(element, preparationClasses);
}
$$jqLite.removeClass(element, activeClasses);
blockKeyframeAnimations(node, false);
blockTransitions(node, false);
forEach(temporaryStyles, function(entry) {
// There is only one way to remove inline style properties entirely from elements.
// By using `removeProperty` this works, but we need to convert camel-cased CSS
// styles down to hyphenated values.
node.style[entry[0]] = '';
});
applyAnimationClasses(element, options);
applyAnimationStyles(element, options);
if (Object.keys(restoreStyles).length) {
forEach(restoreStyles, function(value, prop) {
if (value) {
node.style.setProperty(prop, value);
} else {
node.style.removeProperty(prop);
}
});
}
// the reason why we have this option is to allow a synchronous closing callback
// that is fired as SOON as the animation ends (when the CSS is removed) or if
// the animation never takes off at all. A good example is a leave animation since
// the element must be removed just after the animation is over or else the element
// will appear on screen for one animation frame causing an overbearing flicker.
if (options.onDone) {
options.onDone();
}
if (events && events.length) {
// Remove the transitionend / animationend listener(s)
element.off(events.join(' '), onAnimationProgress);
}
//Cancel the fallback closing timeout and remove the timer data
var animationTimerData = element.data(ANIMATE_TIMER_KEY);
if (animationTimerData) {
$timeout.cancel(animationTimerData[0].timer);
element.removeData(ANIMATE_TIMER_KEY);
}
// if the preparation function fails then the promise is not setup
if (runner) {
runner.complete(!rejected);
}
}
function applyBlocking(duration) {
if (flags.blockTransition) {
blockTransitions(node, duration);
}
if (flags.blockKeyframeAnimation) {
blockKeyframeAnimations(node, !!duration);
}
}
function closeAndReturnNoopAnimator() {
runner = new $$AnimateRunner({
end: endFn,
cancel: cancelFn
});
// should flush the cache animation
waitUntilQuiet(noop);
close();
return {
$$willAnimate: false,
start: function() {
return runner;
},
end: endFn
};
}
function onAnimationProgress(event) {
event.stopPropagation();
var ev = event.originalEvent || event;
// we now always use `Date.now()` due to the recent changes with
// event.timeStamp in Firefox, Webkit and Chrome (see #13494 for more info)
var timeStamp = ev.$manualTimeStamp || Date.now();
/* Firefox (or possibly just Gecko) likes to not round values up
* when a ms measurement is used for the animation */
var elapsedTime = parseFloat(ev.elapsedTime.toFixed(ELAPSED_TIME_MAX_DECIMAL_PLACES));
/* $manualTimeStamp is a mocked timeStamp value which is set
* within browserTrigger(). This is only here so that tests can
* mock animations properly. Real events fallback to event.timeStamp,
* or, if they don't, then a timeStamp is automatically created for them.
* We're checking to see if the timeStamp surpasses the expected delay,
* but we're using elapsedTime instead of the timeStamp on the 2nd
* pre-condition since animationPauseds sometimes close off early */
if (Math.max(timeStamp - startTime, 0) >= maxDelayTime && elapsedTime >= maxDuration) {
// we set this flag to ensure that if the transition is paused then, when resumed,
// the animation will automatically close itself since transitions cannot be paused.
animationCompleted = true;
close();
}
}
function start() {
if (animationClosed) return;
if (!node.parentNode) {
close();
return;
}
// even though we only pause keyframe animations here the pause flag
// will still happen when transitions are used. Only the transition will
// not be paused since that is not possible. If the animation ends when
// paused then it will not complete until unpaused or cancelled.
var playPause = function(playAnimation) {
if (!animationCompleted) {
animationPaused = !playAnimation;
if (timings.animationDuration) {
var value = blockKeyframeAnimations(node, animationPaused);
if (animationPaused) {
temporaryStyles.push(value);
} else {
removeFromArray(temporaryStyles, value);
}
}
} else if (animationPaused && playAnimation) {
animationPaused = false;
close();
}
};
// checking the stagger duration prevents an accidentally cascade of the CSS delay style
// being inherited from the parent. If the transition duration is zero then we can safely
// rely that the delay value is an intentional stagger delay style.
var maxStagger = itemIndex > 0
&& ((timings.transitionDuration && stagger.transitionDuration === 0) ||
(timings.animationDuration && stagger.animationDuration === 0))
&& Math.max(stagger.animationDelay, stagger.transitionDelay);
if (maxStagger) {
$timeout(triggerAnimationStart,
Math.floor(maxStagger * itemIndex * ONE_SECOND),
false);
} else {
triggerAnimationStart();
}
// this will decorate the existing promise runner with pause/resume methods
runnerHost.resume = function() {
playPause(true);
};
runnerHost.pause = function() {
playPause(false);
};
function triggerAnimationStart() {
// just incase a stagger animation kicks in when the animation
// itself was cancelled entirely
if (animationClosed) return;
applyBlocking(false);
forEach(temporaryStyles, function(entry) {
var key = entry[0];
var value = entry[1];
node.style[key] = value;
});
applyAnimationClasses(element, options);
$$jqLite.addClass(element, activeClasses);
if (flags.recalculateTimingStyles) {
fullClassName = node.getAttribute('class') + ' ' + preparationClasses;
cacheKey = gcsHashFn(node, fullClassName);
timings = computeTimings(node, fullClassName, cacheKey);
relativeDelay = timings.maxDelay;
maxDelay = Math.max(relativeDelay, 0);
maxDuration = timings.maxDuration;
if (maxDuration === 0) {
close();
return;
}
flags.hasTransitions = timings.transitionDuration > 0;
flags.hasAnimations = timings.animationDuration > 0;
}
if (flags.applyAnimationDelay) {
relativeDelay = typeof options.delay !== 'boolean' && truthyTimingValue(options.delay)
? parseFloat(options.delay)
: relativeDelay;
maxDelay = Math.max(relativeDelay, 0);
timings.animationDelay = relativeDelay;
delayStyle = getCssDelayStyle(relativeDelay, true);
temporaryStyles.push(delayStyle);
node.style[delayStyle[0]] = delayStyle[1];
}
maxDelayTime = maxDelay * ONE_SECOND;
maxDurationTime = maxDuration * ONE_SECOND;
if (options.easing) {
var easeProp, easeVal = options.easing;
if (flags.hasTransitions) {
easeProp = TRANSITION_PROP + TIMING_KEY;
temporaryStyles.push([easeProp, easeVal]);
node.style[easeProp] = easeVal;
}
if (flags.hasAnimations) {
easeProp = ANIMATION_PROP + TIMING_KEY;
temporaryStyles.push([easeProp, easeVal]);
node.style[easeProp] = easeVal;
}
}
if (timings.transitionDuration) {
events.push(TRANSITIONEND_EVENT);
}
if (timings.animationDuration) {
events.push(ANIMATIONEND_EVENT);
}
startTime = Date.now();
var timerTime = maxDelayTime + CLOSING_TIME_BUFFER * maxDurationTime;
var endTime = startTime + timerTime;
var animationsData = element.data(ANIMATE_TIMER_KEY) || [];
var setupFallbackTimer = true;
if (animationsData.length) {
var currentTimerData = animationsData[0];
setupFallbackTimer = endTime > currentTimerData.expectedEndTime;
if (setupFallbackTimer) {
$timeout.cancel(currentTimerData.timer);
} else {
animationsData.push(close);
}
}
if (setupFallbackTimer) {
var timer = $timeout(onAnimationExpired, timerTime, false);
animationsData[0] = {
timer: timer,
expectedEndTime: endTime
};
animationsData.push(close);
element.data(ANIMATE_TIMER_KEY, animationsData);
}
if (events.length) {
element.on(events.join(' '), onAnimationProgress);
}
if (options.to) {
if (options.cleanupStyles) {
registerRestorableStyles(restoreStyles, node, Object.keys(options.to));
}
applyAnimationToStyles(element, options);
}
}
function onAnimationExpired() {
var animationsData = element.data(ANIMATE_TIMER_KEY);
// this will be false in the event that the element was
// removed from the DOM (via a leave animation or something
// similar)
if (animationsData) {
for (var i = 1; i < animationsData.length; i++) {
animationsData[i]();
}
element.removeData(ANIMATE_TIMER_KEY);
}
}
}
};
}];
}];
var $$AnimateCssDriverProvider = ['$$animationProvider', /** @this */ function($$animationProvider) {
$$animationProvider.drivers.push('$$animateCssDriver');
var NG_ANIMATE_SHIM_CLASS_NAME = 'ng-animate-shim';
var NG_ANIMATE_ANCHOR_CLASS_NAME = 'ng-anchor';
var NG_OUT_ANCHOR_CLASS_NAME = 'ng-anchor-out';
var NG_IN_ANCHOR_CLASS_NAME = 'ng-anchor-in';
function isDocumentFragment(node) {
return node.parentNode && node.parentNode.nodeType === 11;
}
this.$get = ['$animateCss', '$rootScope', '$$AnimateRunner', '$rootElement', '$sniffer', '$$jqLite', '$document',
function($animateCss, $rootScope, $$AnimateRunner, $rootElement, $sniffer, $$jqLite, $document) {
// only browsers that support these properties can render animations
if (!$sniffer.animations && !$sniffer.transitions) return noop;
var bodyNode = $document[0].body;
var rootNode = getDomNode($rootElement);
var rootBodyElement = jqLite(
// this is to avoid using something that exists outside of the body
// we also special case the doc fragment case because our unit test code
// appends the $rootElement to the body after the app has been bootstrapped
isDocumentFragment(rootNode) || bodyNode.contains(rootNode) ? rootNode : bodyNode
);
return function initDriverFn(animationDetails) {
return animationDetails.from && animationDetails.to
? prepareFromToAnchorAnimation(animationDetails.from,
animationDetails.to,
animationDetails.classes,
animationDetails.anchors)
: prepareRegularAnimation(animationDetails);
};
function filterCssClasses(classes) {
//remove all the `ng-` stuff
return classes.replace(/\bng-\S+\b/g, '');
}
function getUniqueValues(a, b) {
if (isString(a)) a = a.split(' ');
if (isString(b)) b = b.split(' ');
return a.filter(function(val) {
return b.indexOf(val) === -1;
}).join(' ');
}
function prepareAnchoredAnimation(classes, outAnchor, inAnchor) {
var clone = jqLite(getDomNode(outAnchor).cloneNode(true));
var startingClasses = filterCssClasses(getClassVal(clone));
outAnchor.addClass(NG_ANIMATE_SHIM_CLASS_NAME);
inAnchor.addClass(NG_ANIMATE_SHIM_CLASS_NAME);
clone.addClass(NG_ANIMATE_ANCHOR_CLASS_NAME);
rootBodyElement.append(clone);
var animatorIn, animatorOut = prepareOutAnimation();
// the user may not end up using the `out` animation and
// only making use of the `in` animation or vice-versa.
// In either case we should allow this and not assume the
// animation is over unless both animations are not used.
if (!animatorOut) {
animatorIn = prepareInAnimation();
if (!animatorIn) {
return end();
}
}
var startingAnimator = animatorOut || animatorIn;
return {
start: function() {
var runner;
var currentAnimation = startingAnimator.start();
currentAnimation.done(function() {
currentAnimation = null;
if (!animatorIn) {
animatorIn = prepareInAnimation();
if (animatorIn) {
currentAnimation = animatorIn.start();
currentAnimation.done(function() {
currentAnimation = null;
end();
runner.complete();
});
return currentAnimation;
}
}
// in the event that there is no `in` animation
end();
runner.complete();
});
runner = new $$AnimateRunner({
end: endFn,
cancel: endFn
});
return runner;
function endFn() {
if (currentAnimation) {
currentAnimation.end();
}
}
}
};
function calculateAnchorStyles(anchor) {
var styles = {};
var coords = getDomNode(anchor).getBoundingClientRect();
// we iterate directly since safari messes up and doesn't return
// all the keys for the coords object when iterated
forEach(['width','height','top','left'], function(key) {
var value = coords[key];
switch (key) {
case 'top':
value += bodyNode.scrollTop;
break;
case 'left':
value += bodyNode.scrollLeft;
break;
}
styles[key] = Math.floor(value) + 'px';
});
return styles;
}
function prepareOutAnimation() {
var animator = $animateCss(clone, {
addClass: NG_OUT_ANCHOR_CLASS_NAME,
delay: true,
from: calculateAnchorStyles(outAnchor)
});
// read the comment within `prepareRegularAnimation` to understand
// why this check is necessary
return animator.$$willAnimate ? animator : null;
}
function getClassVal(element) {
return element.attr('class') || '';
}
function prepareInAnimation() {
var endingClasses = filterCssClasses(getClassVal(inAnchor));
var toAdd = getUniqueValues(endingClasses, startingClasses);
var toRemove = getUniqueValues(startingClasses, endingClasses);
var animator = $animateCss(clone, {
to: calculateAnchorStyles(inAnchor),
addClass: NG_IN_ANCHOR_CLASS_NAME + ' ' + toAdd,
removeClass: NG_OUT_ANCHOR_CLASS_NAME + ' ' + toRemove,
delay: true
});
// read the comment within `prepareRegularAnimation` to understand
// why this check is necessary
return animator.$$willAnimate ? animator : null;
}
function end() {
clone.remove();
outAnchor.removeClass(NG_ANIMATE_SHIM_CLASS_NAME);
inAnchor.removeClass(NG_ANIMATE_SHIM_CLASS_NAME);
}
}
function prepareFromToAnchorAnimation(from, to, classes, anchors) {
var fromAnimation = prepareRegularAnimation(from, noop);
var toAnimation = prepareRegularAnimation(to, noop);
var anchorAnimations = [];
forEach(anchors, function(anchor) {
var outElement = anchor['out'];
var inElement = anchor['in'];
var animator = prepareAnchoredAnimation(classes, outElement, inElement);
if (animator) {
anchorAnimations.push(animator);
}
});
// no point in doing anything when there are no elements to animate
if (!fromAnimation && !toAnimation && anchorAnimations.length === 0) return;
return {
start: function() {
var animationRunners = [];
if (fromAnimation) {
animationRunners.push(fromAnimation.start());
}
if (toAnimation) {
animationRunners.push(toAnimation.start());
}
forEach(anchorAnimations, function(animation) {
animationRunners.push(animation.start());
});
var runner = new $$AnimateRunner({
end: endFn,
cancel: endFn // CSS-driven animations cannot be cancelled, only ended
});
$$AnimateRunner.all(animationRunners, function(status) {
runner.complete(status);
});
return runner;
function endFn() {
forEach(animationRunners, function(runner) {
runner.end();
});
}
}
};
}
function prepareRegularAnimation(animationDetails) {
var element = animationDetails.element;
var options = animationDetails.options || {};
if (animationDetails.structural) {
options.event = animationDetails.event;
options.structural = true;
options.applyClassesEarly = true;
// we special case the leave animation since we want to ensure that
// the element is removed as soon as the animation is over. Otherwise
// a flicker might appear or the element may not be removed at all
if (animationDetails.event === 'leave') {
options.onDone = options.domOperation;
}
}
// We assign the preparationClasses as the actual animation event since
// the internals of $animateCss will just suffix the event token values
// with `-active` to trigger the animation.
if (options.preparationClasses) {
options.event = concatWithSpace(options.event, options.preparationClasses);
}
var animator = $animateCss(element, options);
// the driver lookup code inside of $$animation attempts to spawn a
// driver one by one until a driver returns a.$$willAnimate animator object.
// $animateCss will always return an object, however, it will pass in
// a flag as a hint as to whether an animation was detected or not
return animator.$$willAnimate ? animator : null;
}
}];
}];
// TODO(matsko): use caching here to speed things up for detection
// TODO(matsko): add documentation
// by the time...
var $$AnimateJsProvider = ['$animateProvider', /** @this */ function($animateProvider) {
this.$get = ['$injector', '$$AnimateRunner', '$$jqLite',
function($injector, $$AnimateRunner, $$jqLite) {
var applyAnimationClasses = applyAnimationClassesFactory($$jqLite);
// $animateJs(element, 'enter');
return function(element, event, classes, options) {
var animationClosed = false;
// the `classes` argument is optional and if it is not used
// then the classes will be resolved from the element's className
// property as well as options.addClass/options.removeClass.
if (arguments.length === 3 && isObject(classes)) {
options = classes;
classes = null;
}
options = prepareAnimationOptions(options);
if (!classes) {
classes = element.attr('class') || '';
if (options.addClass) {
classes += ' ' + options.addClass;
}
if (options.removeClass) {
classes += ' ' + options.removeClass;
}
}
var classesToAdd = options.addClass;
var classesToRemove = options.removeClass;
// the lookupAnimations function returns a series of animation objects that are
// matched up with one or more of the CSS classes. These animation objects are
// defined via the module.animation factory function. If nothing is detected then
// we don't return anything which then makes $animation query the next driver.
var animations = lookupAnimations(classes);
var before, after;
if (animations.length) {
var afterFn, beforeFn;
if (event === 'leave') {
beforeFn = 'leave';
afterFn = 'afterLeave'; // TODO(matsko): get rid of this
} else {
beforeFn = 'before' + event.charAt(0).toUpperCase() + event.substr(1);
afterFn = event;
}
if (event !== 'enter' && event !== 'move') {
before = packageAnimations(element, event, options, animations, beforeFn);
}
after = packageAnimations(element, event, options, animations, afterFn);
}
// no matching animations
if (!before && !after) return;
function applyOptions() {
options.domOperation();
applyAnimationClasses(element, options);
}
function close() {
animationClosed = true;
applyOptions();
applyAnimationStyles(element, options);
}
var runner;
return {
$$willAnimate: true,
end: function() {
if (runner) {
runner.end();
} else {
close();
runner = new $$AnimateRunner();
runner.complete(true);
}
return runner;
},
start: function() {
if (runner) {
return runner;
}
runner = new $$AnimateRunner();
var closeActiveAnimations;
var chain = [];
if (before) {
chain.push(function(fn) {
closeActiveAnimations = before(fn);
});
}
if (chain.length) {
chain.push(function(fn) {
applyOptions();
fn(true);
});
} else {
applyOptions();
}
if (after) {
chain.push(function(fn) {
closeActiveAnimations = after(fn);
});
}
runner.setHost({
end: function() {
endAnimations();
},
cancel: function() {
endAnimations(true);
}
});
$$AnimateRunner.chain(chain, onComplete);
return runner;
function onComplete(success) {
close(success);
runner.complete(success);
}
function endAnimations(cancelled) {
if (!animationClosed) {
(closeActiveAnimations || noop)(cancelled);
onComplete(cancelled);
}
}
}
};
function executeAnimationFn(fn, element, event, options, onDone) {
var args;
switch (event) {
case 'animate':
args = [element, options.from, options.to, onDone];
break;
case 'setClass':
args = [element, classesToAdd, classesToRemove, onDone];
break;
case 'addClass':
args = [element, classesToAdd, onDone];
break;
case 'removeClass':
args = [element, classesToRemove, onDone];
break;
default:
args = [element, onDone];
break;
}
args.push(options);
var value = fn.apply(fn, args);
if (value) {
if (isFunction(value.start)) {
value = value.start();
}
if (value instanceof $$AnimateRunner) {
value.done(onDone);
} else if (isFunction(value)) {
// optional onEnd / onCancel callback
return value;
}
}
return noop;
}
function groupEventedAnimations(element, event, options, animations, fnName) {
var operations = [];
forEach(animations, function(ani) {
var animation = ani[fnName];
if (!animation) return;
// note that all of these animations will run in parallel
operations.push(function() {
var runner;
var endProgressCb;
var resolved = false;
var onAnimationComplete = function(rejected) {
if (!resolved) {
resolved = true;
(endProgressCb || noop)(rejected);
runner.complete(!rejected);
}
};
runner = new $$AnimateRunner({
end: function() {
onAnimationComplete();
},
cancel: function() {
onAnimationComplete(true);
}
});
endProgressCb = executeAnimationFn(animation, element, event, options, function(result) {
var cancelled = result === false;
onAnimationComplete(cancelled);
});
return runner;
});
});
return operations;
}
function packageAnimations(element, event, options, animations, fnName) {
var operations = groupEventedAnimations(element, event, options, animations, fnName);
if (operations.length === 0) {
var a, b;
if (fnName === 'beforeSetClass') {
a = groupEventedAnimations(element, 'removeClass', options, animations, 'beforeRemoveClass');
b = groupEventedAnimations(element, 'addClass', options, animations, 'beforeAddClass');
} else if (fnName === 'setClass') {
a = groupEventedAnimations(element, 'removeClass', options, animations, 'removeClass');
b = groupEventedAnimations(element, 'addClass', options, animations, 'addClass');
}
if (a) {
operations = operations.concat(a);
}
if (b) {
operations = operations.concat(b);
}
}
if (operations.length === 0) return;
// TODO(matsko): add documentation
return function startAnimation(callback) {
var runners = [];
if (operations.length) {
forEach(operations, function(animateFn) {
runners.push(animateFn());
});
}
if (runners.length) {
$$AnimateRunner.all(runners, callback);
} else {
callback();
}
return function endFn(reject) {
forEach(runners, function(runner) {
if (reject) {
runner.cancel();
} else {
runner.end();
}
});
};
};
}
};
function lookupAnimations(classes) {
classes = isArray(classes) ? classes : classes.split(' ');
var matches = [], flagMap = {};
for (var i = 0; i < classes.length; i++) {
var klass = classes[i],
animationFactory = $animateProvider.$$registeredAnimations[klass];
if (animationFactory && !flagMap[klass]) {
matches.push($injector.get(animationFactory));
flagMap[klass] = true;
}
}
return matches;
}
}];
}];
var $$AnimateJsDriverProvider = ['$$animationProvider', /** @this */ function($$animationProvider) {
$$animationProvider.drivers.push('$$animateJsDriver');
this.$get = ['$$animateJs', '$$AnimateRunner', function($$animateJs, $$AnimateRunner) {
return function initDriverFn(animationDetails) {
if (animationDetails.from && animationDetails.to) {
var fromAnimation = prepareAnimation(animationDetails.from);
var toAnimation = prepareAnimation(animationDetails.to);
if (!fromAnimation && !toAnimation) return;
return {
start: function() {
var animationRunners = [];
if (fromAnimation) {
animationRunners.push(fromAnimation.start());
}
if (toAnimation) {
animationRunners.push(toAnimation.start());
}
$$AnimateRunner.all(animationRunners, done);
var runner = new $$AnimateRunner({
end: endFnFactory(),
cancel: endFnFactory()
});
return runner;
function endFnFactory() {
return function() {
forEach(animationRunners, function(runner) {
// at this point we cannot cancel animations for groups just yet. 1.5+
runner.end();
});
};
}
function done(status) {
runner.complete(status);
}
}
};
} else {
return prepareAnimation(animationDetails);
}
};
function prepareAnimation(animationDetails) {
// TODO(matsko): make sure to check for grouped animations and delegate down to normal animations
var element = animationDetails.element;
var event = animationDetails.event;
var options = animationDetails.options;
var classes = animationDetails.classes;
return $$animateJs(element, event, classes, options);
}
}];
}];
var NG_ANIMATE_ATTR_NAME = 'data-ng-animate';
var NG_ANIMATE_PIN_DATA = '$ngAnimatePin';
var $$AnimateQueueProvider = ['$animateProvider', /** @this */ function($animateProvider) {
var PRE_DIGEST_STATE = 1;
var RUNNING_STATE = 2;
var ONE_SPACE = ' ';
var rules = this.rules = {
skip: [],
cancel: [],
join: []
};
function makeTruthyCssClassMap(classString) {
if (!classString) {
return null;
}
var keys = classString.split(ONE_SPACE);
var map = Object.create(null);
forEach(keys, function(key) {
map[key] = true;
});
return map;
}
function hasMatchingClasses(newClassString, currentClassString) {
if (newClassString && currentClassString) {
var currentClassMap = makeTruthyCssClassMap(currentClassString);
return newClassString.split(ONE_SPACE).some(function(className) {
return currentClassMap[className];
});
}
}
function isAllowed(ruleType, currentAnimation, previousAnimation) {
return rules[ruleType].some(function(fn) {
return fn(currentAnimation, previousAnimation);
});
}
function hasAnimationClasses(animation, and) {
var a = (animation.addClass || '').length > 0;
var b = (animation.removeClass || '').length > 0;
return and ? a && b : a || b;
}
rules.join.push(function(newAnimation, currentAnimation) {
// if the new animation is class-based then we can just tack that on
return !newAnimation.structural && hasAnimationClasses(newAnimation);
});
rules.skip.push(function(newAnimation, currentAnimation) {
// there is no need to animate anything if no classes are being added and
// there is no structural animation that will be triggered
return !newAnimation.structural && !hasAnimationClasses(newAnimation);
});
rules.skip.push(function(newAnimation, currentAnimation) {
// why should we trigger a new structural animation if the element will
// be removed from the DOM anyway?
return currentAnimation.event === 'leave' && newAnimation.structural;
});
rules.skip.push(function(newAnimation, currentAnimation) {
// if there is an ongoing current animation then don't even bother running the class-based animation
return currentAnimation.structural && currentAnimation.state === RUNNING_STATE && !newAnimation.structural;
});
rules.cancel.push(function(newAnimation, currentAnimation) {
// there can never be two structural animations running at the same time
return currentAnimation.structural && newAnimation.structural;
});
rules.cancel.push(function(newAnimation, currentAnimation) {
// if the previous animation is already running, but the new animation will
// be triggered, but the new animation is structural
return currentAnimation.state === RUNNING_STATE && newAnimation.structural;
});
rules.cancel.push(function(newAnimation, currentAnimation) {
// cancel the animation if classes added / removed in both animation cancel each other out,
// but only if the current animation isn't structural
if (currentAnimation.structural) return false;
var nA = newAnimation.addClass;
var nR = newAnimation.removeClass;
var cA = currentAnimation.addClass;
var cR = currentAnimation.removeClass;
// early detection to save the global CPU shortage :)
if ((isUndefined(nA) && isUndefined(nR)) || (isUndefined(cA) && isUndefined(cR))) {
return false;
}
return hasMatchingClasses(nA, cR) || hasMatchingClasses(nR, cA);
});
this.$get = ['$$rAF', '$rootScope', '$rootElement', '$document', '$$Map',
'$$animation', '$$AnimateRunner', '$templateRequest', '$$jqLite', '$$forceReflow',
'$$isDocumentHidden',
function($$rAF, $rootScope, $rootElement, $document, $$Map,
$$animation, $$AnimateRunner, $templateRequest, $$jqLite, $$forceReflow,
$$isDocumentHidden) {
var activeAnimationsLookup = new $$Map();
var disabledElementsLookup = new $$Map();
var animationsEnabled = null;
function postDigestTaskFactory() {
var postDigestCalled = false;
return function(fn) {
// we only issue a call to postDigest before
// it has first passed. This prevents any callbacks
// from not firing once the animation has completed
// since it will be out of the digest cycle.
if (postDigestCalled) {
fn();
} else {
$rootScope.$$postDigest(function() {
postDigestCalled = true;
fn();
});
}
};
}
// Wait until all directive and route-related templates are downloaded and
// compiled. The $templateRequest.totalPendingRequests variable keeps track of
// all of the remote templates being currently downloaded. If there are no
// templates currently downloading then the watcher will still fire anyway.
var deregisterWatch = $rootScope.$watch(
function() { return $templateRequest.totalPendingRequests === 0; },
function(isEmpty) {
if (!isEmpty) return;
deregisterWatch();
// Now that all templates have been downloaded, $animate will wait until
// the post digest queue is empty before enabling animations. By having two
// calls to $postDigest calls we can ensure that the flag is enabled at the
// very end of the post digest queue. Since all of the animations in $animate
// use $postDigest, it's important that the code below executes at the end.
// This basically means that the page is fully downloaded and compiled before
// any animations are triggered.
$rootScope.$$postDigest(function() {
$rootScope.$$postDigest(function() {
// we check for null directly in the event that the application already called
// .enabled() with whatever arguments that it provided it with
if (animationsEnabled === null) {
animationsEnabled = true;
}
});
});
}
);
var callbackRegistry = Object.create(null);
// remember that the `customFilter`/`classNameFilter` are set during the
// provider/config stage therefore we can optimize here and setup helper functions
var customFilter = $animateProvider.customFilter();
var classNameFilter = $animateProvider.classNameFilter();
var returnTrue = function() { return true; };
var isAnimatableByFilter = customFilter || returnTrue;
var isAnimatableClassName = !classNameFilter ? returnTrue : function(node, options) {
var className = [node.getAttribute('class'), options.addClass, options.removeClass].join(' ');
return classNameFilter.test(className);
};
var applyAnimationClasses = applyAnimationClassesFactory($$jqLite);
function normalizeAnimationDetails(element, animation) {
return mergeAnimationDetails(element, animation, {});
}
// IE9-11 has no method "contains" in SVG element and in Node.prototype. Bug #10259.
var contains = window.Node.prototype.contains || /** @this */ function(arg) {
// eslint-disable-next-line no-bitwise
return this === arg || !!(this.compareDocumentPosition(arg) & 16);
};
function findCallbacks(targetParentNode, targetNode, event) {
var matches = [];
var entries = callbackRegistry[event];
if (entries) {
forEach(entries, function(entry) {
if (contains.call(entry.node, targetNode)) {
matches.push(entry.callback);
} else if (event === 'leave' && contains.call(entry.node, targetParentNode)) {
matches.push(entry.callback);
}
});
}
return matches;
}
function filterFromRegistry(list, matchContainer, matchCallback) {
var containerNode = extractElementNode(matchContainer);
return list.filter(function(entry) {
var isMatch = entry.node === containerNode &&
(!matchCallback || entry.callback === matchCallback);
return !isMatch;
});
}
function cleanupEventListeners(phase, node) {
if (phase === 'close' && !node.parentNode) {
// If the element is not attached to a parentNode, it has been removed by
// the domOperation, and we can safely remove the event callbacks
$animate.off(node);
}
}
var $animate = {
on: function(event, container, callback) {
var node = extractElementNode(container);
callbackRegistry[event] = callbackRegistry[event] || [];
callbackRegistry[event].push({
node: node,
callback: callback
});
// Remove the callback when the element is removed from the DOM
jqLite(container).on('$destroy', function() {
var animationDetails = activeAnimationsLookup.get(node);
if (!animationDetails) {
// If there's an animation ongoing, the callback calling code will remove
// the event listeners. If we'd remove here, the callbacks would be removed
// before the animation ends
$animate.off(event, container, callback);
}
});
},
off: function(event, container, callback) {
if (arguments.length === 1 && !isString(arguments[0])) {
container = arguments[0];
for (var eventType in callbackRegistry) {
callbackRegistry[eventType] = filterFromRegistry(callbackRegistry[eventType], container);
}
return;
}
var entries = callbackRegistry[event];
if (!entries) return;
callbackRegistry[event] = arguments.length === 1
? null
: filterFromRegistry(entries, container, callback);
},
pin: function(element, parentElement) {
assertArg(isElement(element), 'element', 'not an element');
assertArg(isElement(parentElement), 'parentElement', 'not an element');
element.data(NG_ANIMATE_PIN_DATA, parentElement);
},
push: function(element, event, options, domOperation) {
options = options || {};
options.domOperation = domOperation;
return queueAnimation(element, event, options);
},
// this method has four signatures:
// () - global getter
// (bool) - global setter
// (element) - element getter
// (element, bool) - element setter<F37>
enabled: function(element, bool) {
var argCount = arguments.length;
if (argCount === 0) {
// () - Global getter
bool = !!animationsEnabled;
} else {
var hasElement = isElement(element);
if (!hasElement) {
// (bool) - Global setter
bool = animationsEnabled = !!element;
} else {
var node = getDomNode(element);
if (argCount === 1) {
// (element) - Element getter
bool = !disabledElementsLookup.get(node);
} else {
// (element, bool) - Element setter
disabledElementsLookup.set(node, !bool);
}
}
}
return bool;
}
};
return $animate;
function queueAnimation(originalElement, event, initialOptions) {
// we always make a copy of the options since
// there should never be any side effects on
// the input data when running `$animateCss`.
var options = copy(initialOptions);
var element = stripCommentsFromElement(originalElement);
var node = getDomNode(element);
var parentNode = node && node.parentNode;
options = prepareAnimationOptions(options);
// we create a fake runner with a working promise.
// These methods will become available after the digest has passed
var runner = new $$AnimateRunner();
// this is used to trigger callbacks in postDigest mode
var runInNextPostDigestOrNow = postDigestTaskFactory();
if (isArray(options.addClass)) {
options.addClass = options.addClass.join(' ');
}
if (options.addClass && !isString(options.addClass)) {
options.addClass = null;
}
if (isArray(options.removeClass)) {
options.removeClass = options.removeClass.join(' ');
}
if (options.removeClass && !isString(options.removeClass)) {
options.removeClass = null;
}
if (options.from && !isObject(options.from)) {
options.from = null;
}
if (options.to && !isObject(options.to)) {
options.to = null;
}
// If animations are hard-disabled for the whole application there is no need to continue.
// There are also situations where a directive issues an animation for a jqLite wrapper that
// contains only comment nodes. In this case, there is no way we can perform an animation.
if (!animationsEnabled ||
!node ||
!isAnimatableByFilter(node, event, initialOptions) ||
!isAnimatableClassName(node, options)) {
close();
return runner;
}
var isStructural = ['enter', 'move', 'leave'].indexOf(event) >= 0;
var documentHidden = $$isDocumentHidden();
// This is a hard disable of all animations the element itself, therefore there is no need to
// continue further past this point if not enabled
// Animations are also disabled if the document is currently hidden (page is not visible
// to the user), because browsers slow down or do not flush calls to requestAnimationFrame
var skipAnimations = documentHidden || disabledElementsLookup.get(node);
var existingAnimation = (!skipAnimations && activeAnimationsLookup.get(node)) || {};
var hasExistingAnimation = !!existingAnimation.state;
// there is no point in traversing the same collection of parent ancestors if a followup
// animation will be run on the same element that already did all that checking work
if (!skipAnimations && (!hasExistingAnimation || existingAnimation.state !== PRE_DIGEST_STATE)) {
skipAnimations = !areAnimationsAllowed(node, parentNode, event);
}
if (skipAnimations) {
// Callbacks should fire even if the document is hidden (regression fix for issue #14120)
if (documentHidden) notifyProgress(runner, event, 'start');
close();
if (documentHidden) notifyProgress(runner, event, 'close');
return runner;
}
if (isStructural) {
closeChildAnimations(node);
}
var newAnimation = {
structural: isStructural,
element: element,
event: event,
addClass: options.addClass,
removeClass: options.removeClass,
close: close,
options: options,
runner: runner
};
if (hasExistingAnimation) {
var skipAnimationFlag = isAllowed('skip', newAnimation, existingAnimation);
if (skipAnimationFlag) {
if (existingAnimation.state === RUNNING_STATE) {
close();
return runner;
} else {
mergeAnimationDetails(element, existingAnimation, newAnimation);
return existingAnimation.runner;
}
}
var cancelAnimationFlag = isAllowed('cancel', newAnimation, existingAnimation);
if (cancelAnimationFlag) {
if (existingAnimation.state === RUNNING_STATE) {
// this will end the animation right away and it is safe
// to do so since the animation is already running and the
// runner callback code will run in async
existingAnimation.runner.end();
} else if (existingAnimation.structural) {
// this means that the animation is queued into a digest, but
// hasn't started yet. Therefore it is safe to run the close
// method which will call the runner methods in async.
existingAnimation.close();
} else {
// this will merge the new animation options into existing animation options
mergeAnimationDetails(element, existingAnimation, newAnimation);
return existingAnimation.runner;
}
} else {
// a joined animation means that this animation will take over the existing one
// so an example would involve a leave animation taking over an enter. Then when
// the postDigest kicks in the enter will be ignored.
var joinAnimationFlag = isAllowed('join', newAnimation, existingAnimation);
if (joinAnimationFlag) {
if (existingAnimation.state === RUNNING_STATE) {
normalizeAnimationDetails(element, newAnimation);
} else {
applyGeneratedPreparationClasses(element, isStructural ? event : null, options);
event = newAnimation.event = existingAnimation.event;
options = mergeAnimationDetails(element, existingAnimation, newAnimation);
//we return the same runner since only the option values of this animation will
//be fed into the `existingAnimation`.
return existingAnimation.runner;
}
}
}
} else {
// normalization in this case means that it removes redundant CSS classes that
// already exist (addClass) or do not exist (removeClass) on the element
normalizeAnimationDetails(element, newAnimation);
}
// when the options are merged and cleaned up we may end up not having to do
// an animation at all, therefore we should check this before issuing a post
// digest callback. Structural animations will always run no matter what.
var isValidAnimation = newAnimation.structural;
if (!isValidAnimation) {
// animate (from/to) can be quickly checked first, otherwise we check if any classes are present
isValidAnimation = (newAnimation.event === 'animate' && Object.keys(newAnimation.options.to || {}).length > 0)
|| hasAnimationClasses(newAnimation);
}
if (!isValidAnimation) {
close();
clearElementAnimationState(node);
return runner;
}
// the counter keeps track of cancelled animations
var counter = (existingAnimation.counter || 0) + 1;
newAnimation.counter = counter;
markElementAnimationState(node, PRE_DIGEST_STATE, newAnimation);
$rootScope.$$postDigest(function() {
// It is possible that the DOM nodes inside `originalElement` have been replaced. This can
// happen if the animated element is a transcluded clone and also has a `templateUrl`
// directive on it. Therefore, we must recreate `element` in order to interact with the
// actual DOM nodes.
// Note: We still need to use the old `node` for certain things, such as looking up in
// HashMaps where it was used as the key.
element = stripCommentsFromElement(originalElement);
var animationDetails = activeAnimationsLookup.get(node);
var animationCancelled = !animationDetails;
animationDetails = animationDetails || {};
// if addClass/removeClass is called before something like enter then the
// registered parent element may not be present. The code below will ensure
// that a final value for parent element is obtained
var parentElement = element.parent() || [];
// animate/structural/class-based animations all have requirements. Otherwise there
// is no point in performing an animation. The parent node must also be set.
var isValidAnimation = parentElement.length > 0
&& (animationDetails.event === 'animate'
|| animationDetails.structural
|| hasAnimationClasses(animationDetails));
// this means that the previous animation was cancelled
// even if the follow-up animation is the same event
if (animationCancelled || animationDetails.counter !== counter || !isValidAnimation) {
// if another animation did not take over then we need
// to make sure that the domOperation and options are
// handled accordingly
if (animationCancelled) {
applyAnimationClasses(element, options);
applyAnimationStyles(element, options);
}
// if the event changed from something like enter to leave then we do
// it, otherwise if it's the same then the end result will be the same too
if (animationCancelled || (isStructural && animationDetails.event !== event)) {
options.domOperation();
runner.end();
}
// in the event that the element animation was not cancelled or a follow-up animation
// isn't allowed to animate from here then we need to clear the state of the element
// so that any future animations won't read the expired animation data.
if (!isValidAnimation) {
clearElementAnimationState(node);
}
return;
}
// this combined multiple class to addClass / removeClass into a setClass event
// so long as a structural event did not take over the animation
event = !animationDetails.structural && hasAnimationClasses(animationDetails, true)
? 'setClass'
: animationDetails.event;
markElementAnimationState(node, RUNNING_STATE);
var realRunner = $$animation(element, event, animationDetails.options);
// this will update the runner's flow-control events based on
// the `realRunner` object.
runner.setHost(realRunner);
notifyProgress(runner, event, 'start', {});
realRunner.done(function(status) {
close(!status);
var animationDetails = activeAnimationsLookup.get(node);
if (animationDetails && animationDetails.counter === counter) {
clearElementAnimationState(node);
}
notifyProgress(runner, event, 'close', {});
});
});
return runner;
function notifyProgress(runner, event, phase, data) {
runInNextPostDigestOrNow(function() {
var callbacks = findCallbacks(parentNode, node, event);
if (callbacks.length) {
// do not optimize this call here to RAF because
// we don't know how heavy the callback code here will
// be and if this code is buffered then this can
// lead to a performance regression.
$$rAF(function() {
forEach(callbacks, function(callback) {
callback(element, phase, data);
});
cleanupEventListeners(phase, node);
});
} else {
cleanupEventListeners(phase, node);
}
});
runner.progress(event, phase, data);
}
function close(reject) {
clearGeneratedClasses(element, options);
applyAnimationClasses(element, options);
applyAnimationStyles(element, options);
options.domOperation();
runner.complete(!reject);
}
}
function closeChildAnimations(node) {
var children = node.querySelectorAll('[' + NG_ANIMATE_ATTR_NAME + ']');
forEach(children, function(child) {
var state = parseInt(child.getAttribute(NG_ANIMATE_ATTR_NAME), 10);
var animationDetails = activeAnimationsLookup.get(child);
if (animationDetails) {
switch (state) {
case RUNNING_STATE:
animationDetails.runner.end();
/* falls through */
case PRE_DIGEST_STATE:
activeAnimationsLookup.delete(child);
break;
}
}
});
}
function clearElementAnimationState(node) {
node.removeAttribute(NG_ANIMATE_ATTR_NAME);
activeAnimationsLookup.delete(node);
}
/**
* This fn returns false if any of the following is true:
* a) animations on any parent element are disabled, and animations on the element aren't explicitly allowed
* b) a parent element has an ongoing structural animation, and animateChildren is false
* c) the element is not a child of the body
* d) the element is not a child of the $rootElement
*/
function areAnimationsAllowed(node, parentNode, event) {
var bodyNode = $document[0].body;
var rootNode = getDomNode($rootElement);
var bodyNodeDetected = (node === bodyNode) || node.nodeName === 'HTML';
var rootNodeDetected = (node === rootNode);
var parentAnimationDetected = false;
var elementDisabled = disabledElementsLookup.get(node);
var animateChildren;
var parentHost = jqLite.data(node, NG_ANIMATE_PIN_DATA);
if (parentHost) {
parentNode = getDomNode(parentHost);
}
while (parentNode) {
if (!rootNodeDetected) {
// angular doesn't want to attempt to animate elements outside of the application
// therefore we need to ensure that the rootElement is an ancestor of the current element
rootNodeDetected = (parentNode === rootNode);
}
if (parentNode.nodeType !== ELEMENT_NODE) {
// no point in inspecting the #document element
break;
}
var details = activeAnimationsLookup.get(parentNode) || {};
// either an enter, leave or move animation will commence
// therefore we can't allow any animations to take place
// but if a parent animation is class-based then that's ok
if (!parentAnimationDetected) {
var parentNodeDisabled = disabledElementsLookup.get(parentNode);
if (parentNodeDisabled === true && elementDisabled !== false) {
// disable animations if the user hasn't explicitly enabled animations on the
// current element
elementDisabled = true;
// element is disabled via parent element, no need to check anything else
break;
} else if (parentNodeDisabled === false) {
elementDisabled = false;
}
parentAnimationDetected = details.structural;
}
if (isUndefined(animateChildren) || animateChildren === true) {
var value = jqLite.data(parentNode, NG_ANIMATE_CHILDREN_DATA);
if (isDefined(value)) {
animateChildren = value;
}
}
// there is no need to continue traversing at this point
if (parentAnimationDetected && animateChildren === false) break;
if (!bodyNodeDetected) {
// we also need to ensure that the element is or will be a part of the body element
// otherwise it is pointless to even issue an animation to be rendered
bodyNodeDetected = (parentNode === bodyNode);
}
if (bodyNodeDetected && rootNodeDetected) {
// If both body and root have been found, any other checks are pointless,
// as no animation data should live outside the application
break;
}
if (!rootNodeDetected) {
// If `rootNode` is not detected, check if `parentNode` is pinned to another element
parentHost = jqLite.data(parentNode, NG_ANIMATE_PIN_DATA);
if (parentHost) {
// The pin target element becomes the next parent element
parentNode = getDomNode(parentHost);
continue;
}
}
parentNode = parentNode.parentNode;
}
var allowAnimation = (!parentAnimationDetected || animateChildren) && elementDisabled !== true;
return allowAnimation && rootNodeDetected && bodyNodeDetected;
}
function markElementAnimationState(node, state, details) {
details = details || {};
details.state = state;
node.setAttribute(NG_ANIMATE_ATTR_NAME, state);
var oldValue = activeAnimationsLookup.get(node);
var newValue = oldValue
? extend(oldValue, details)
: details;
activeAnimationsLookup.set(node, newValue);
}
}];
}];
/* exported $$AnimationProvider */
var $$AnimationProvider = ['$animateProvider', /** @this */ function($animateProvider) {
var NG_ANIMATE_REF_ATTR = 'ng-animate-ref';
var drivers = this.drivers = [];
var RUNNER_STORAGE_KEY = '$$animationRunner';
function setRunner(element, runner) {
element.data(RUNNER_STORAGE_KEY, runner);
}
function removeRunner(element) {
element.removeData(RUNNER_STORAGE_KEY);
}
function getRunner(element) {
return element.data(RUNNER_STORAGE_KEY);
}
this.$get = ['$$jqLite', '$rootScope', '$injector', '$$AnimateRunner', '$$Map', '$$rAFScheduler',
function($$jqLite, $rootScope, $injector, $$AnimateRunner, $$Map, $$rAFScheduler) {
var animationQueue = [];
var applyAnimationClasses = applyAnimationClassesFactory($$jqLite);
function sortAnimations(animations) {
var tree = { children: [] };
var i, lookup = new $$Map();
// this is done first beforehand so that the map
// is filled with a list of the elements that will be animated
for (i = 0; i < animations.length; i++) {
var animation = animations[i];
lookup.set(animation.domNode, animations[i] = {
domNode: animation.domNode,
fn: animation.fn,
children: []
});
}
for (i = 0; i < animations.length; i++) {
processNode(animations[i]);
}
return flatten(tree);
function processNode(entry) {
if (entry.processed) return entry;
entry.processed = true;
var elementNode = entry.domNode;
var parentNode = elementNode.parentNode;
lookup.set(elementNode, entry);
var parentEntry;
while (parentNode) {
parentEntry = lookup.get(parentNode);
if (parentEntry) {
if (!parentEntry.processed) {
parentEntry = processNode(parentEntry);
}
break;
}
parentNode = parentNode.parentNode;
}
(parentEntry || tree).children.push(entry);
return entry;
}
function flatten(tree) {
var result = [];
var queue = [];
var i;
for (i = 0; i < tree.children.length; i++) {
queue.push(tree.children[i]);
}
var remainingLevelEntries = queue.length;
var nextLevelEntries = 0;
var row = [];
for (i = 0; i < queue.length; i++) {
var entry = queue[i];
if (remainingLevelEntries <= 0) {
remainingLevelEntries = nextLevelEntries;
nextLevelEntries = 0;
result.push(row);
row = [];
}
row.push(entry.fn);
entry.children.forEach(function(childEntry) {
nextLevelEntries++;
queue.push(childEntry);
});
remainingLevelEntries--;
}
if (row.length) {
result.push(row);
}
return result;
}
}
// TODO(matsko): document the signature in a better way
return function(element, event, options) {
options = prepareAnimationOptions(options);
var isStructural = ['enter', 'move', 'leave'].indexOf(event) >= 0;
// there is no animation at the current moment, however
// these runner methods will get later updated with the
// methods leading into the driver's end/cancel methods
// for now they just stop the animation from starting
var runner = new $$AnimateRunner({
end: function() { close(); },
cancel: function() { close(true); }
});
if (!drivers.length) {
close();
return runner;
}
setRunner(element, runner);
var classes = mergeClasses(element.attr('class'), mergeClasses(options.addClass, options.removeClass));
var tempClasses = options.tempClasses;
if (tempClasses) {
classes += ' ' + tempClasses;
options.tempClasses = null;
}
var prepareClassName;
if (isStructural) {
prepareClassName = 'ng-' + event + PREPARE_CLASS_SUFFIX;
$$jqLite.addClass(element, prepareClassName);
}
animationQueue.push({
// this data is used by the postDigest code and passed into
// the driver step function
element: element,
classes: classes,
event: event,
structural: isStructural,
options: options,
beforeStart: beforeStart,
close: close
});
element.on('$destroy', handleDestroyedElement);
// we only want there to be one function called within the post digest
// block. This way we can group animations for all the animations that
// were apart of the same postDigest flush call.
if (animationQueue.length > 1) return runner;
$rootScope.$$postDigest(function() {
var animations = [];
forEach(animationQueue, function(entry) {
// the element was destroyed early on which removed the runner
// form its storage. This means we can't animate this element
// at all and it already has been closed due to destruction.
if (getRunner(entry.element)) {
animations.push(entry);
} else {
entry.close();
}
});
// now any future animations will be in another postDigest
animationQueue.length = 0;
var groupedAnimations = groupAnimations(animations);
var toBeSortedAnimations = [];
forEach(groupedAnimations, function(animationEntry) {
toBeSortedAnimations.push({
domNode: getDomNode(animationEntry.from ? animationEntry.from.element : animationEntry.element),
fn: function triggerAnimationStart() {
// it's important that we apply the `ng-animate` CSS class and the
// temporary classes before we do any driver invoking since these
// CSS classes may be required for proper CSS detection.
animationEntry.beforeStart();
var startAnimationFn, closeFn = animationEntry.close;
// in the event that the element was removed before the digest runs or
// during the RAF sequencing then we should not trigger the animation.
var targetElement = animationEntry.anchors
? (animationEntry.from.element || animationEntry.to.element)
: animationEntry.element;
if (getRunner(targetElement)) {
var operation = invokeFirstDriver(animationEntry);
if (operation) {
startAnimationFn = operation.start;
}
}
if (!startAnimationFn) {
closeFn();
} else {
var animationRunner = startAnimationFn();
animationRunner.done(function(status) {
closeFn(!status);
});
updateAnimationRunners(animationEntry, animationRunner);
}
}
});
});
// we need to sort each of the animations in order of parent to child
// relationships. This ensures that the child classes are applied at the
// right time.
$$rAFScheduler(sortAnimations(toBeSortedAnimations));
});
return runner;
// TODO(matsko): change to reference nodes
function getAnchorNodes(node) {
var SELECTOR = '[' + NG_ANIMATE_REF_ATTR + ']';
var items = node.hasAttribute(NG_ANIMATE_REF_ATTR)
? [node]
: node.querySelectorAll(SELECTOR);
var anchors = [];
forEach(items, function(node) {
var attr = node.getAttribute(NG_ANIMATE_REF_ATTR);
if (attr && attr.length) {
anchors.push(node);
}
});
return anchors;
}
function groupAnimations(animations) {
var preparedAnimations = [];
var refLookup = {};
forEach(animations, function(animation, index) {
var element = animation.element;
var node = getDomNode(element);
var event = animation.event;
var enterOrMove = ['enter', 'move'].indexOf(event) >= 0;
var anchorNodes = animation.structural ? getAnchorNodes(node) : [];
if (anchorNodes.length) {
var direction = enterOrMove ? 'to' : 'from';
forEach(anchorNodes, function(anchor) {
var key = anchor.getAttribute(NG_ANIMATE_REF_ATTR);
refLookup[key] = refLookup[key] || {};
refLookup[key][direction] = {
animationID: index,
element: jqLite(anchor)
};
});
} else {
preparedAnimations.push(animation);
}
});
var usedIndicesLookup = {};
var anchorGroups = {};
forEach(refLookup, function(operations, key) {
var from = operations.from;
var to = operations.to;
if (!from || !to) {
// only one of these is set therefore we can't have an
// anchor animation since all three pieces are required
var index = from ? from.animationID : to.animationID;
var indexKey = index.toString();
if (!usedIndicesLookup[indexKey]) {
usedIndicesLookup[indexKey] = true;
preparedAnimations.push(animations[index]);
}
return;
}
var fromAnimation = animations[from.animationID];
var toAnimation = animations[to.animationID];
var lookupKey = from.animationID.toString();
if (!anchorGroups[lookupKey]) {
var group = anchorGroups[lookupKey] = {
structural: true,
beforeStart: function() {
fromAnimation.beforeStart();
toAnimation.beforeStart();
},
close: function() {
fromAnimation.close();
toAnimation.close();
},
classes: cssClassesIntersection(fromAnimation.classes, toAnimation.classes),
from: fromAnimation,
to: toAnimation,
anchors: [] // TODO(matsko): change to reference nodes
};
// the anchor animations require that the from and to elements both have at least
// one shared CSS class which effectively marries the two elements together to use
// the same animation driver and to properly sequence the anchor animation.
if (group.classes.length) {
preparedAnimations.push(group);
} else {
preparedAnimations.push(fromAnimation);
preparedAnimations.push(toAnimation);
}
}
anchorGroups[lookupKey].anchors.push({
'out': from.element, 'in': to.element
});
});
return preparedAnimations;
}
function cssClassesIntersection(a,b) {
a = a.split(' ');
b = b.split(' ');
var matches = [];
for (var i = 0; i < a.length; i++) {
var aa = a[i];
if (aa.substring(0,3) === 'ng-') continue;
for (var j = 0; j < b.length; j++) {
if (aa === b[j]) {
matches.push(aa);
break;
}
}
}
return matches.join(' ');
}
function invokeFirstDriver(animationDetails) {
// we loop in reverse order since the more general drivers (like CSS and JS)
// may attempt more elements, but custom drivers are more particular
for (var i = drivers.length - 1; i >= 0; i--) {
var driverName = drivers[i];
var factory = $injector.get(driverName);
var driver = factory(animationDetails);
if (driver) {
return driver;
}
}
}
function beforeStart() {
element.addClass(NG_ANIMATE_CLASSNAME);
if (tempClasses) {
$$jqLite.addClass(element, tempClasses);
}
if (prepareClassName) {
$$jqLite.removeClass(element, prepareClassName);
prepareClassName = null;
}
}
function updateAnimationRunners(animation, newRunner) {
if (animation.from && animation.to) {
update(animation.from.element);
update(animation.to.element);
} else {
update(animation.element);
}
function update(element) {
var runner = getRunner(element);
if (runner) runner.setHost(newRunner);
}
}
function handleDestroyedElement() {
var runner = getRunner(element);
if (runner && (event !== 'leave' || !options.$$domOperationFired)) {
runner.end();
}
}
function close(rejected) {
element.off('$destroy', handleDestroyedElement);
removeRunner(element);
applyAnimationClasses(element, options);
applyAnimationStyles(element, options);
options.domOperation();
if (tempClasses) {
$$jqLite.removeClass(element, tempClasses);
}
element.removeClass(NG_ANIMATE_CLASSNAME);
runner.complete(!rejected);
}
};
}];
}];
/**
* @ngdoc directive
* @name ngAnimateSwap
* @restrict A
* @scope
*
* @description
*
* ngAnimateSwap is a animation-oriented directive that allows for the container to
* be removed and entered in whenever the associated expression changes. A
* common usecase for this directive is a rotating banner or slider component which
* contains one image being present at a time. When the active image changes
* then the old image will perform a `leave` animation and the new element
* will be inserted via an `enter` animation.
*
* @animations
* | Animation | Occurs |
* |----------------------------------|--------------------------------------|
* | {@link ng.$animate#enter enter} | when the new element is inserted to the DOM |
* | {@link ng.$animate#leave leave} | when the old element is removed from the DOM |
*
* @example
* <example name="ngAnimateSwap-directive" module="ngAnimateSwapExample"
* deps="angular-animate.js"
* animations="true" fixBase="true">
* <file name="index.html">
* <div class="container" ng-controller="AppCtrl">
* <div ng-animate-swap="number" class="cell swap-animation" ng-class="colorClass(number)">
* {{ number }}
* </div>
* </div>
* </file>
* <file name="script.js">
* angular.module('ngAnimateSwapExample', ['ngAnimate'])
* .controller('AppCtrl', ['$scope', '$interval', function($scope, $interval) {
* $scope.number = 0;
* $interval(function() {
* $scope.number++;
* }, 1000);
*
* var colors = ['red','blue','green','yellow','orange'];
* $scope.colorClass = function(number) {
* return colors[number % colors.length];
* };
* }]);
* </file>
* <file name="animations.css">
* .container {
* height:250px;
* width:250px;
* position:relative;
* overflow:hidden;
* border:2px solid black;
* }
* .container .cell {
* font-size:150px;
* text-align:center;
* line-height:250px;
* position:absolute;
* top:0;
* left:0;
* right:0;
* border-bottom:2px solid black;
* }
* .swap-animation.ng-enter, .swap-animation.ng-leave {
* transition:0.5s linear all;
* }
* .swap-animation.ng-enter {
* top:-250px;
* }
* .swap-animation.ng-enter-active {
* top:0px;
* }
* .swap-animation.ng-leave {
* top:0px;
* }
* .swap-animation.ng-leave-active {
* top:250px;
* }
* .red { background:red; }
* .green { background:green; }
* .blue { background:blue; }
* .yellow { background:yellow; }
* .orange { background:orange; }
* </file>
* </example>
*/
var ngAnimateSwapDirective = ['$animate', '$rootScope', function($animate, $rootScope) {
return {
restrict: 'A',
transclude: 'element',
terminal: true,
priority: 600, // we use 600 here to ensure that the directive is caught before others
link: function(scope, $element, attrs, ctrl, $transclude) {
var previousElement, previousScope;
scope.$watchCollection(attrs.ngAnimateSwap || attrs['for'], function(value) {
if (previousElement) {
$animate.leave(previousElement);
}
if (previousScope) {
previousScope.$destroy();
previousScope = null;
}
if (value || value === 0) {
previousScope = scope.$new();
$transclude(previousScope, function(element) {
previousElement = element;
$animate.enter(element, null, $element);
});
}
});
}
};
}];
/**
* @ngdoc module
* @name ngAnimate
* @description
*
* The `ngAnimate` module provides support for CSS-based animations (keyframes and transitions) as well as JavaScript-based animations via
* callback hooks. Animations are not enabled by default, however, by including `ngAnimate` the animation hooks are enabled for an Angular app.
*
* <div doc-module-components="ngAnimate"></div>
*
* # Usage
* Simply put, there are two ways to make use of animations when ngAnimate is used: by using **CSS** and **JavaScript**. The former works purely based
* using CSS (by using matching CSS selectors/styles) and the latter triggers animations that are registered via `module.animation()`. For
* both CSS and JS animations the sole requirement is to have a matching `CSS class` that exists both in the registered animation and within
* the HTML element that the animation will be triggered on.
*
* ## Directive Support
* The following directives are "animation aware":
*
* | 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 |
*
* (More information can be found by visiting each the documentation associated with each directive.)
*
* ## CSS-based Animations
*
* CSS-based animations with ngAnimate are unique since they require no JavaScript code at all. By using a CSS class that we reference between our HTML
* and CSS code we can create an animation that will be picked up by Angular when an underlying directive performs an operation.
*
* The example below shows how an `enter` animation can be made possible on an element using `ng-if`:
*
* ```html
* <div ng-if="bool" class="fade">
* Fade me in out
* </div>
* <button ng-click="bool=true">Fade In!</button>
* <button ng-click="bool=false">Fade Out!</button>
* ```
*
* Notice the CSS class **fade**? We can now create the CSS transition code that references this class:
*
* ```css
* /&#42; The starting CSS styles for the enter animation &#42;/
* .fade.ng-enter {
* transition:0.5s linear all;
* opacity:0;
* }
*
* /&#42; The finishing CSS styles for the enter animation &#42;/
* .fade.ng-enter.ng-enter-active {
* opacity:1;
* }
* ```
*
* The key thing to remember here is that, depending on the animation event (which each of the directives above trigger depending on what's going on) two
* generated CSS classes will be applied to the element; in the example above we have `.ng-enter` and `.ng-enter-active`. For CSS transitions, the transition
* code **must** be defined within the starting CSS class (in this case `.ng-enter`). The destination class is what the transition will animate towards.
*
* If for example we wanted to create animations for `leave` and `move` (ngRepeat triggers move) then we can do so using the same CSS naming conventions:
*
* ```css
* /&#42; now the element will fade out before it is removed from the DOM &#42;/
* .fade.ng-leave {
* transition:0.5s linear all;
* opacity:1;
* }
* .fade.ng-leave.ng-leave-active {
* opacity:0;
* }
* ```
*
* We can also make use of **CSS Keyframes** by referencing the keyframe animation within the starting CSS class:
*
* ```css
* /&#42; there is no need to define anything inside of the destination
* CSS class since the keyframe will take charge of the animation &#42;/
* .fade.ng-leave {
* animation: my_fade_animation 0.5s linear;
* -webkit-animation: my_fade_animation 0.5s linear;
* }
*
* @keyframes my_fade_animation {
* from { opacity:1; }
* to { opacity:0; }
* }
*
* @-webkit-keyframes my_fade_animation {
* from { opacity:1; }
* to { opacity:0; }
* }
* ```
*
* Feel free also mix transitions and keyframes together as well as any other CSS classes on the same element.
*
* ### CSS Class-based Animations
*
* Class-based animations (animations that are triggered via `ngClass`, `ngShow`, `ngHide` and some other directives) have a slightly different
* naming convention. Class-based animations are basic enough that a standard transition or keyframe can be referenced on the class being added
* and removed.
*
* For example if we wanted to do a CSS animation for `ngHide` then we place an animation on the `.ng-hide` CSS class:
*
* ```html
* <div ng-show="bool" class="fade">
* Show and hide me
* </div>
* <button ng-click="bool=!bool">Toggle</button>
*
* <style>
* .fade.ng-hide {
* transition:0.5s linear all;
* opacity:0;
* }
* </style>
* ```
*
* All that is going on here with ngShow/ngHide behind the scenes is the `.ng-hide` class is added/removed (when the hidden state is valid). Since
* ngShow and ngHide are animation aware then we can match up a transition and ngAnimate handles the rest.
*
* In addition the addition and removal of the CSS class, ngAnimate also provides two helper methods that we can use to further decorate the animation
* with CSS styles.
*
* ```html
* <div ng-class="{on:onOff}" class="highlight">
* Highlight this box
* </div>
* <button ng-click="onOff=!onOff">Toggle</button>
*
* <style>
* .highlight {
* transition:0.5s linear all;
* }
* .highlight.on-add {
* background:white;
* }
* .highlight.on {
* background:yellow;
* }
* .highlight.on-remove {
* background:black;
* }
* </style>
* ```
*
* We can also make use of CSS keyframes by placing them within the CSS classes.
*
*
* ### 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
* .my-animation.ng-enter {
* /&#42; standard transition code &#42;/
* transition: 1s linear all;
* opacity:0;
* }
* .my-animation.ng-enter-stagger {
* /&#42; this will have a 100ms delay between each successive leave animation &#42;/
* transition-delay: 0.1s;
*
* /&#42; As of 1.4.4, this must always be set: it signals ngAnimate
* to not accidentally inherit a delay property from another CSS class &#42;/
* transition-duration: 0s;
*
* /&#42; if you are using animations instead of transitions you should configure as follows:
* animation-delay: 0.1s;
* animation-duration: 0s; &#42;/
* }
* .my-animation.ng-enter.ng-enter-active {
* /&#42; standard transition styles &#42;/
* opacity:1;
* }
* ```
*
* 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 one or more animation frames have passed since the multiple calls to `$animate` were fired.
*
* The following code will issue the **ng-leave-stagger** event on the element provided:
*
* ```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
*
* window.requestAnimationFrame(function() {
* //stagger has reset itself
* $animate.leave(kids[5]); //stagger index=0
* $animate.leave(kids[6]); //stagger index=1
*
* $scope.$digest();
* });
* ```
*
* Stagger animations are currently only supported within CSS-defined animations.
*
* ### The `ng-animate` CSS class
*
* When ngAnimate is animating an element it will apply the `ng-animate` CSS class to the element for the duration of the animation.
* This is a temporary CSS class and it will be removed once the animation is over (for both JavaScript and CSS-based animations).
*
* Therefore, animations can be applied to an element using this temporary class directly via CSS.
*
* ```css
* .zipper.ng-animate {
* transition:0.5s linear all;
* }
* .zipper.ng-enter {
* opacity:0;
* }
* .zipper.ng-enter.ng-enter-active {
* opacity:1;
* }
* .zipper.ng-leave {
* opacity:1;
* }
* .zipper.ng-leave.ng-leave-active {
* opacity:0;
* }
* ```
*
* (Note that the `ng-animate` CSS class is reserved and it cannot be applied on an element directly since ngAnimate will always remove
* the CSS class once an animation has completed.)
*
*
* ### The `ng-[event]-prepare` class
*
* This is a special class that can be used to prevent unwanted flickering / flash of content before
* the actual animation starts. The class is added as soon as an animation is initialized, but removed
* before the actual animation starts (after waiting for a $digest).
* It is also only added for *structural* animations (`enter`, `move`, and `leave`).
*
* In practice, flickering can appear when nesting elements with structural animations such as `ngIf`
* into elements that have class-based animations such as `ngClass`.
*
* ```html
* <div ng-class="{red: myProp}">
* <div ng-class="{blue: myProp}">
* <div class="message" ng-if="myProp"></div>
* </div>
* </div>
* ```
*
* It is possible that during the `enter` animation, the `.message` div will be briefly visible before it starts animating.
* In that case, you can add styles to the CSS that make sure the element stays hidden before the animation starts:
*
* ```css
* .message.ng-enter-prepare {
* opacity: 0;
* }
*
* ```
*
* ## JavaScript-based Animations
*
* ngAnimate also allows for animations to be consumed by JavaScript code. The approach is similar to CSS-based animations (where there is a shared
* CSS class that is referenced in our HTML code) but in addition we need to register the JavaScript animation on the module. By making use of the
* `module.animation()` module function we can register the animation.
*
* Let's see an example of a enter/leave animation using `ngRepeat`:
*
* ```html
* <div ng-repeat="item in items" class="slide">
* {{ item }}
* </div>
* ```
*
* See the **slide** CSS class? Let's use that class to define an animation that we'll structure in our module code by using `module.animation`:
*
* ```js
* myModule.animation('.slide', [function() {
* return {
* // make note that other events (like addClass/removeClass)
* // have different function input parameters
* enter: function(element, doneFn) {
* jQuery(element).fadeIn(1000, doneFn);
*
* // remember to call doneFn so that angular
* // knows that the animation has concluded
* },
*
* move: function(element, doneFn) {
* jQuery(element).fadeIn(1000, doneFn);
* },
*
* leave: function(element, doneFn) {
* jQuery(element).fadeOut(1000, doneFn);
* }
* }
* }]);
* ```
*
* The nice thing about JS-based animations is that we can inject other services and make use of advanced animation libraries such as
* greensock.js and velocity.js.
*
* If our animation code class-based (meaning that something like `ngClass`, `ngHide` and `ngShow` triggers it) then we can still define
* our animations inside of the same registered animation, however, the function input arguments are a bit different:
*
* ```html
* <div ng-class="color" class="colorful">
* this box is moody
* </div>
* <button ng-click="color='red'">Change to red</button>
* <button ng-click="color='blue'">Change to blue</button>
* <button ng-click="color='green'">Change to green</button>
* ```
*
* ```js
* myModule.animation('.colorful', [function() {
* return {
* addClass: function(element, className, doneFn) {
* // do some cool animation and call the doneFn
* },
* removeClass: function(element, className, doneFn) {
* // do some cool animation and call the doneFn
* },
* setClass: function(element, addedClass, removedClass, doneFn) {
* // do some cool animation and call the doneFn
* }
* }
* }]);
* ```
*
* ## CSS + JS Animations Together
*
* AngularJS 1.4 and higher has taken steps to make the amalgamation of CSS and JS animations more flexible. However, unlike earlier versions of Angular,
* defining CSS and JS animations to work off of the same CSS class will not work anymore. Therefore the example below will only result in **JS animations taking
* charge of the animation**:
*
* ```html
* <div ng-if="bool" class="slide">
* Slide in and out
* </div>
* ```
*
* ```js
* myModule.animation('.slide', [function() {
* return {
* enter: function(element, doneFn) {
* jQuery(element).slideIn(1000, doneFn);
* }
* }
* }]);
* ```
*
* ```css
* .slide.ng-enter {
* transition:0.5s linear all;
* transform:translateY(-100px);
* }
* .slide.ng-enter.ng-enter-active {
* transform:translateY(0);
* }
* ```
*
* Does this mean that CSS and JS animations cannot be used together? Do JS-based animations always have higher priority? We can make up for the
* lack of CSS animations by using the `$animateCss` service to trigger our own tweaked-out, CSS-based animations directly from
* our own JS-based animation code:
*
* ```js
* myModule.animation('.slide', ['$animateCss', function($animateCss) {
* return {
* enter: function(element) {
* // this will trigger `.slide.ng-enter` and `.slide.ng-enter-active`.
* return $animateCss(element, {
* event: 'enter',
* structural: true
* });
* }
* }
* }]);
* ```
*
* The nice thing here is that we can save bandwidth by sticking to our CSS-based animation code and we don't need to rely on a 3rd-party animation framework.
*
* The `$animateCss` service is very powerful since we can feed in all kinds of extra properties that will be evaluated and fed into a CSS transition or
* keyframe animation. For example if we wanted to animate the height of an element while adding and removing classes then we can do so by providing that
* data into `$animateCss` directly:
*
* ```js
* myModule.animation('.slide', ['$animateCss', function($animateCss) {
* return {
* enter: function(element) {
* return $animateCss(element, {
* event: 'enter',
* structural: true,
* addClass: 'maroon-setting',
* from: { height:0 },
* to: { height: 200 }
* });
* }
* }
* }]);
* ```
*
* Now we can fill in the rest via our transition CSS code:
*
* ```css
* /&#42; the transition tells ngAnimate to make the animation happen &#42;/
* .slide.ng-enter { transition:0.5s linear all; }
*
* /&#42; this extra CSS class will be absorbed into the transition
* since the $animateCss code is adding the class &#42;/
* .maroon-setting { background:red; }
* ```
*
* And `$animateCss` will figure out the rest. Just make sure to have the `done()` callback fire the `doneFn` function to signal when the animation is over.
*
* To learn more about what's possible be sure to visit the {@link ngAnimate.$animateCss $animateCss service}.
*
* ## Animation Anchoring (via `ng-animate-ref`)
*
* ngAnimate in AngularJS 1.4 comes packed with the ability to cross-animate elements between
* structural areas of an application (like views) by pairing up elements using an attribute
* called `ng-animate-ref`.
*
* Let's say for example we have two views that are managed by `ng-view` and we want to show
* that there is a relationship between two components situated in within these views. By using the
* `ng-animate-ref` attribute we can identify that the two components are paired together and we
* can then attach an animation, which is triggered when the view changes.
*
* Say for example we have the following template code:
*
* ```html
* <!-- index.html -->
* <div ng-view class="view-animation">
* </div>
*
* <!-- home.html -->
* <a href="#/banner-page">
* <img src="./banner.jpg" class="banner" ng-animate-ref="banner">
* </a>
*
* <!-- banner-page.html -->
* <img src="./banner.jpg" class="banner" ng-animate-ref="banner">
* ```
*
* Now, when the view changes (once the link is clicked), ngAnimate will examine the
* HTML contents to see if there is a match reference between any components in the view
* that is leaving and the view that is entering. It will scan both the view which is being
* removed (leave) and inserted (enter) to see if there are any paired DOM elements that
* contain a matching ref value.
*
* The two images match since they share the same ref value. ngAnimate will now create a
* transport element (which is a clone of the first image element) and it will then attempt
* to animate to the position of the second image element in the next view. For the animation to
* work a special CSS class called `ng-anchor` will be added to the transported element.
*
* We can now attach a transition onto the `.banner.ng-anchor` CSS class and then
* ngAnimate will handle the entire transition for us as well as the addition and removal of
* any changes of CSS classes between the elements:
*
* ```css
* .banner.ng-anchor {
* /&#42; this animation will last for 1 second since there are
* two phases to the animation (an `in` and an `out` phase) &#42;/
* transition:0.5s linear all;
* }
* ```
*
* We also **must** include animations for the views that are being entered and removed
* (otherwise anchoring wouldn't be possible since the new view would be inserted right away).
*
* ```css
* .view-animation.ng-enter, .view-animation.ng-leave {
* transition:0.5s linear all;
* position:fixed;
* left:0;
* top:0;
* width:100%;
* }
* .view-animation.ng-enter {
* transform:translateX(100%);
* }
* .view-animation.ng-leave,
* .view-animation.ng-enter.ng-enter-active {
* transform:translateX(0%);
* }
* .view-animation.ng-leave.ng-leave-active {
* transform:translateX(-100%);
* }
* ```
*
* Now we can jump back to the anchor animation. When the animation happens, there are two stages that occur:
* an `out` and an `in` stage. The `out` stage happens first and that is when the element is animated away
* from its origin. Once that animation is over then the `in` stage occurs which animates the
* element to its destination. The reason why there are two animations is to give enough time
* for the enter animation on the new element to be ready.
*
* The example above sets up a transition for both the in and out phases, but we can also target the out or
* in phases directly via `ng-anchor-out` and `ng-anchor-in`.
*
* ```css
* .banner.ng-anchor-out {
* transition: 0.5s linear all;
*
* /&#42; the scale will be applied during the out animation,
* but will be animated away when the in animation runs &#42;/
* transform: scale(1.2);
* }
*
* .banner.ng-anchor-in {
* transition: 1s linear all;
* }
* ```
*
*
*
*
* ### Anchoring Demo
*
<example module="anchoringExample"
name="anchoringExample"
id="anchoringExample"
deps="angular-animate.js;angular-route.js"
animations="true">
<file name="index.html">
<a href="#!/">Home</a>
<hr />
<div class="view-container">
<div ng-view class="view"></div>
</div>
</file>
<file name="script.js">
angular.module('anchoringExample', ['ngAnimate', 'ngRoute'])
.config(['$routeProvider', function($routeProvider) {
$routeProvider.when('/', {
templateUrl: 'home.html',
controller: 'HomeController as home'
});
$routeProvider.when('/profile/:id', {
templateUrl: 'profile.html',
controller: 'ProfileController as profile'
});
}])
.run(['$rootScope', function($rootScope) {
$rootScope.records = [
{ id: 1, title: 'Miss Beulah Roob' },
{ id: 2, title: 'Trent Morissette' },
{ id: 3, title: 'Miss Ava Pouros' },
{ id: 4, title: 'Rod Pouros' },
{ id: 5, title: 'Abdul Rice' },
{ id: 6, title: 'Laurie Rutherford Sr.' },
{ id: 7, title: 'Nakia McLaughlin' },
{ id: 8, title: 'Jordon Blanda DVM' },
{ id: 9, title: 'Rhoda Hand' },
{ id: 10, title: 'Alexandrea Sauer' }
];
}])
.controller('HomeController', [function() {
//empty
}])
.controller('ProfileController', ['$rootScope', '$routeParams',
function ProfileController($rootScope, $routeParams) {
var index = parseInt($routeParams.id, 10);
var record = $rootScope.records[index - 1];
this.title = record.title;
this.id = record.id;
}]);
</file>
<file name="home.html">
<h2>Welcome to the home page</h1>
<p>Please click on an element</p>
<a class="record"
ng-href="#!/profile/{{ record.id }}"
ng-animate-ref="{{ record.id }}"
ng-repeat="record in records">
{{ record.title }}
</a>
</file>
<file name="profile.html">
<div class="profile record" ng-animate-ref="{{ profile.id }}">
{{ profile.title }}
</div>
</file>
<file name="animations.css">
.record {
display:block;
font-size:20px;
}
.profile {
background:black;
color:white;
font-size:100px;
}
.view-container {
position:relative;
}
.view-container > .view.ng-animate {
position:absolute;
top:0;
left:0;
width:100%;
min-height:500px;
}
.view.ng-enter, .view.ng-leave,
.record.ng-anchor {
transition:0.5s linear all;
}
.view.ng-enter {
transform:translateX(100%);
}
.view.ng-enter.ng-enter-active, .view.ng-leave {
transform:translateX(0%);
}
.view.ng-leave.ng-leave-active {
transform:translateX(-100%);
}
.record.ng-anchor-out {
background:red;
}
</file>
</example>
*
* ### How is the element transported?
*
* When an anchor animation occurs, ngAnimate will clone the starting element and position it exactly where the starting
* element is located on screen via absolute positioning. The cloned element will be placed inside of the root element
* of the application (where ng-app was defined) and all of the CSS classes of the starting element will be applied. The
* element will then animate into the `out` and `in` animations and will eventually reach the coordinates and match
* the dimensions of the destination element. During the entire animation a CSS class of `.ng-animate-shim` will be applied
* to both the starting and destination elements in order to hide them from being visible (the CSS styling for the class
* is: `visibility:hidden`). Once the anchor reaches its destination then it will be removed and the destination element
* will become visible since the shim class will be removed.
*
* ### How is the morphing handled?
*
* CSS Anchoring relies on transitions and keyframes and the internal code is intelligent enough to figure out
* what CSS classes differ between the starting element and the destination element. These different CSS classes
* will be added/removed on the anchor element and a transition will be applied (the transition that is provided
* in the anchor class). Long story short, ngAnimate will figure out what classes to add and remove which will
* make the transition of the element as smooth and automatic as possible. Be sure to use simple CSS classes that
* do not rely on DOM nesting structure so that the anchor element appears the same as the starting element (since
* the cloned element is placed inside of root element which is likely close to the body element).
*
* Note that if the root element is on the `<html>` element then the cloned node will be placed inside of body.
*
*
* ## Using $animate in your directive code
*
* So far we've explored how to feed in animations into an Angular application, but how do we trigger animations within our own directives in our application?
* By injecting the `$animate` service into our directive code, we can trigger structural and class-based hooks which can then be consumed by animations. Let's
* imagine we have a greeting box that shows and hides itself when the data changes
*
* ```html
* <greeting-box active="onOrOff">Hi there</greeting-box>
* ```
*
* ```js
* ngModule.directive('greetingBox', ['$animate', function($animate) {
* return function(scope, element, attrs) {
* attrs.$observe('active', function(value) {
* value ? $animate.addClass(element, 'on') : $animate.removeClass(element, 'on');
* });
* });
* }]);
* ```
*
* Now the `on` CSS class is added and removed on the greeting box component. Now if we add a CSS class on top of the greeting box element
* in our HTML code then we can trigger a CSS or JS animation to happen.
*
* ```css
* /&#42; normally we would create a CSS class to reference on the element &#42;/
* greeting-box.on { transition:0.5s linear all; background:green; color:white; }
* ```
*
* The `$animate` service contains a variety of other methods like `enter`, `leave`, `animate` and `setClass`. To learn more about what's
* possible be sure to visit the {@link ng.$animate $animate service API page}.
*
*
* ## Callbacks and Promises
*
* When `$animate` is called it returns a promise that can be used to capture when the animation has ended. Therefore if we were to trigger
* an animation (within our directive code) then we can continue performing directive and scope related activities after the animation has
* ended by chaining onto the returned promise that animation method returns.
*
* ```js
* // somewhere within the depths of the directive
* $animate.enter(element, parent).then(function() {
* //the animation has completed
* });
* ```
*
* (Note that earlier versions of Angular prior to v1.4 required the promise code to be wrapped using `$scope.$apply(...)`. This is not the case
* anymore.)
*
* In addition to the animation promise, we can also make use of animation-related callbacks within our directives and controller code by registering
* an event listener using the `$animate` service. Let's say for example that an animation was triggered on our view
* routing controller to hook into that:
*
* ```js
* ngModule.controller('HomePageController', ['$animate', function($animate) {
* $animate.on('enter', ngViewElement, function(element) {
* // the animation for this route has completed
* }]);
* }])
* ```
*
* (Note that you will need to trigger a digest within the callback to get angular to notice any scope-related changes.)
*/
var copy;
var extend;
var forEach;
var isArray;
var isDefined;
var isElement;
var isFunction;
var isObject;
var isString;
var isUndefined;
var jqLite;
var noop;
/**
* @ngdoc service
* @name $animate
* @kind object
*
* @description
* The ngAnimate `$animate` service documentation is the same for the core `$animate` service.
*
* Click here {@link ng.$animate to learn more about animations with `$animate`}.
*/
angular.module('ngAnimate', [], function initAngularHelpers() {
// Access helpers from angular core.
// Do it inside a `config` block to ensure `window.angular` is available.
noop = angular.noop;
copy = angular.copy;
extend = angular.extend;
jqLite = angular.element;
forEach = angular.forEach;
isArray = angular.isArray;
isString = angular.isString;
isObject = angular.isObject;
isUndefined = angular.isUndefined;
isDefined = angular.isDefined;
isFunction = angular.isFunction;
isElement = angular.isElement;
})
.info({ angularVersion: '1.6.5' })
.directive('ngAnimateSwap', ngAnimateSwapDirective)
.directive('ngAnimateChildren', $$AnimateChildrenDirective)
.factory('$$rAFScheduler', $$rAFSchedulerFactory)
.provider('$$animateQueue', $$AnimateQueueProvider)
.provider('$$animation', $$AnimationProvider)
.provider('$animateCss', $AnimateCssProvider)
.provider('$$animateCssDriver', $$AnimateCssDriverProvider)
.provider('$$animateJs', $$AnimateJsProvider)
.provider('$$animateJsDriver', $$AnimateJsDriverProvider);
})(window, window.angular);
"use strict";
(function(e, t) {
"use strict";
function n(Le, He, Je) {
if (!Le) throw de("areq", "Argument '{0}' is {1}", He || "?", Je || "required");
return Le;
}
function s(Le, He) {
return Le || He
? Le
? He ? (Pe(Le) && (Le = Le.join(" ")), Pe(He) && (He = He.join(" ")), Le + " " + He) : Le
: He
: "";
}
function o(Le) {
var He = {};
return Le && (Le.to || Le.from) && ((He.to = Le.to), (He.from = Le.from)), He;
}
function r(Le, He, Je) {
var Qe = "";
return (Le = Pe(Le) ? Le : Le && Re(Le) && Le.length ? Le.split(/\s+/) : []), Ne(Le, function(
Be,
Ue
) {
Be && 0 < Be.length && ((Qe += 0 < Ue ? " " : ""), (Qe += Je ? He + Be : Be + He));
}), Qe;
}
function l(Le, He) {
var Je = Le.indexOf(He);
0 <= He && Le.splice(Je, 1);
}
function d(Le) {
if (Le instanceof Fe)
switch (Le.length) {
case 0:
return Le;
case 1:
if (Le[0].nodeType === K) return Le;
break;
default:
return Fe(u(Le));
}
return Le.nodeType === K ? Fe(Le) : void 0;
}
function u(Le) {
if (!Le[0]) return Le;
for (var Je, He = 0; He < Le.length; He++) if (((Je = Le[He]), Je.nodeType === K)) return Je;
}
function m(Le, He, Je) {
Ne(He, function(Qe) {
Le.addClass(Qe, Je);
});
}
function p(Le, He, Je) {
Ne(He, function(Qe) {
Le.removeClass(Qe, Je);
});
}
function h(Le) {
return function(He, Je) {
Je.addClass && (m(Le, He, Je.addClass), (Je.addClass = null)), Je.removeClass &&
(p(Le, He, Je.removeClass), (Je.removeClass = null));
};
}
function f(Le) {
if (((Le = Le || {}), !Le.$$prepared)) {
var He = Le.domOperation || Ke;
(Le.domOperation = function() {
(Le.$$domOperationFired = !0), He(), (He = Ke);
}), (Le.$$prepared = !0);
}
return Le;
}
function $(Le, He) {
g(Le, He), C(Le, He);
}
function g(Le, He) {
He.from && (Le.css(He.from), (He.from = null));
}
function C(Le, He) {
He.to && (Le.css(He.to), (He.to = null));
}
function y(Le, He, Je) {
var Qe = He.options || {},
Be = Je.options || {},
Ue = (Qe.addClass || "") + " " + (Be.addClass || ""),
Me = (Qe.removeClass || "") + " " + (Be.removeClass || ""),
Ve = v(Le.attr("class"), Ue, Me);
Be.preparationClasses &&
(
(Qe.preparationClasses = w(Be.preparationClasses, Qe.preparationClasses)),
delete Be.preparationClasses
);
var We = Qe.domOperation === Ke ? null : Qe.domOperation;
return we(Qe, Be), We && (Qe.domOperation = We), (Qe.addClass = Ve.addClass
? Ve.addClass
: null), (Qe.removeClass = Ve.removeClass ? Ve.removeClass : null), (He.addClass =
Qe.addClass), (He.removeClass = Qe.removeClass), Qe;
}
function v(Le, He, Je) {
function Qe(We) {
Re(We) && (We = We.split(" "));
var Ye = {};
return Ne(We, function(_e) {
_e.length && (Ye[_e] = !0);
}), Ye;
}
var Be = 1,
Ue = -1,
Me = {};
(Le = Qe(Le)), (He = Qe(He)), Ne(He, function(We, Ye) {
Me[Ye] = Be;
}), (Je = Qe(Je)), Ne(Je, function(We, Ye) {
Me[Ye] = Me[Ye] === Be ? null : Ue;
});
var Ve = { addClass: "", removeClass: "" };
return Ne(Me, function(We, Ye) {
var _e, Ge;
We === Be
? ((_e = "addClass"), (Ge = !Le[Ye] || Le[Ye + J]))
: We == Ue &&
(
(_e = "removeClass"),
(Ge = Le[Ye] || Le[Ye + H])
), Ge && (Ve[_e].length && (Ve[_e] += " "), (Ve[_e] += Ye));
}), Ve;
}
function D(Le) {
return Le instanceof Fe ? Le[0] : Le;
}
function A(Le, He, Je) {
var Qe = "";
He && (Qe = r(He, Q, !0)), Je.addClass && (Qe = w(Qe, r(Je.addClass, H))), Je.removeClass &&
(Qe = w(Qe, r(Je.removeClass, J))), Qe.length &&
((Je.preparationClasses = Qe), Le.addClass(Qe));
}
function k(Le, He) {
He.preparationClasses &&
(Le.removeClass(He.preparationClasses), (He.preparationClasses = null)), He.activeClasses &&
(Le.removeClass(He.activeClasses), (He.activeClasses = null));
}
function T(Le, He) {
var Je = He ? "-" + He + "s" : "";
return x(Le, [re, Je]), [re, Je];
}
function S(Le, He) {
var Je = He ? "paused" : "",
Qe = G + "PlayState";
return x(Le, [Qe, Je]), [Qe, Je];
}
function x(Le, He) {
var Je = He[0],
Qe = He[1];
Le.style[Je] = Qe;
}
function w(Le, He) {
return Le ? (He ? Le + " " + He : Le) : He;
}
function N(Le) {
return [oe, Le + "s"];
}
function P(Le, He) {
var Je = He ? ie : re;
return [Je, Le + "s"];
}
function O(Le, He, Je) {
var Qe = Object.create(null),
Be = Le.getComputedStyle(He) || {};
return Ne(Je, function(Ue, Me) {
var Ve = Be[Ue];
if (Ve) {
var We = Ve.charAt(0);
("-" === We || "+" === We || 0 <= We) && (Ve = E(Ve)), 0 === Ve && (Ve = null), (Qe[
Me
] = Ve);
}
}), Qe;
}
function E(Le) {
var He = 0,
Je = Le.split(/\s*,\s*/);
return Ne(Je, function(Qe) {
"s" === Qe.charAt(Qe.length - 1) &&
(Qe = Qe.substring(
0,
Qe.length - 1
)), (Qe = parseFloat(Qe) || 0), (He = He ? Math.max(Qe, He) : Qe);
}), He;
}
function I(Le) {
return 0 === Le || null != Le;
}
function R(Le, He) {
var Je = Y,
Qe = Le + "s";
return He ? (Je += Z) : (Qe += " linear all"), [Je, Qe];
}
function q() {
var Le = Object.create(null);
return {
flush: function flush() {
Le = Object.create(null);
},
count: function count(He) {
var Je = Le[He];
return Je ? Je.total : 0;
},
get: function get(He) {
var Je = Le[He];
return Je && Je.value;
},
put: function put(He, Je) {
Le[He] ? Le[He].total++ : (Le[He] = { total: 1, value: Je });
}
};
}
function F(Le, He, Je) {
Ne(Je, function(Qe) {
Le[Qe] = je(Le[Qe]) ? Le[Qe] : He.style.getPropertyValue(Qe);
});
}
var K = 1,
H = "-add",
J = "-remove",
Q = "ng-",
M = "ng-animate",
V = "$$ngAnimateChildren",
W = "",
Y,
_,
G,
X;
e.ontransitionend === void 0 && e.onwebkittransitionend !== void 0
? ((W = "-webkit-"), (Y = "WebkitTransition"), (_ = "webkitTransitionEnd transitionend"))
: ((Y = "transition"), (_ = "transitionend")), e.onanimationend === void 0 &&
e.onwebkitanimationend !== void 0
? ((W = "-webkit-"), (G = "WebkitAnimation"), (X = "webkitAnimationEnd animationend"))
: ((G = "animation"), (X = "animationend"));
var Z = "Duration",
z = "Property",
ee = "Delay",
te = "TimingFunction",
ie = G + ee,
oe = G + Z,
re = Y + ee,
le = Y + Z,
de = t.$$minErr("ng"),
pe = "$$animateCss",
ce = 1e3,
$e = {
transitionDuration: le,
transitionDelay: re,
transitionProperty: Y + z,
animationDuration: oe,
animationDelay: ie,
animationIterationCount: G + "IterationCount"
},
ge = { transitionDuration: le, transitionDelay: re, animationDuration: oe, animationDelay: ie },
Ae = "data-ng-animate",
ke = "$ngAnimatePin",
xe,
we,
Ne,
Pe,
je,
Oe,
Ee,
Ie,
Re,
qe,
Fe,
Ke;
t
.module("ngAnimate", [], function() {
(Ke =
t.noop), (xe = t.copy), (we = t.extend), (Fe = t.element), (Ne = t.forEach), (Pe = t.isArray), (Re = t.isString), (Ie = t.isObject), (qe = t.isUndefined), (je = t.isDefined), (Ee = t.isFunction), (Oe = t.isElement);
})
.info({ angularVersion: "1.6.5" })
.directive("ngAnimateSwap", [
"$animate",
"$rootScope",
function(Le) {
return {
restrict: "A",
transclude: "element",
terminal: !0,
priority: 600,
link: function link(Je, Qe, Be, Ue, Me) {
var Ve, We;
Je.$watchCollection(Be.ngAnimateSwap || Be["for"], function(Ye) {
Ve && Le.leave(Ve), We && (We.$destroy(), (We = null)), (Ye || 0 === Ye) &&
(
(We = Je.$new()),
Me(We, function(_e) {
(Ve = _e), Le.enter(_e, null, Qe);
})
);
});
}
};
}
])
.directive("ngAnimateChildren", [
"$interpolate",
function(Le) {
return {
link: function link(He, Je, Qe) {
function Be(Me) {
(Me = "on" === Me || "true" === Me), Je.data(V, Me);
}
var Ue = Qe.ngAnimateChildren;
Re(Ue) && 0 === Ue.length
? Je.data(V, !0)
: (Be(Le(Ue)(He)), Qe.$observe("ngAnimateChildren", Be));
}
};
}
])
.factory("$$rAFScheduler", [
"$$rAF",
function(Le) {
function He(Ue) {
(Qe = Qe.concat(Ue)), Je();
}
function Je() {
if (Qe.length) {
for (var Ue = Qe.shift(), Me = 0; Me < Ue.length; Me++) Ue[Me]();
Be ||
Le(function() {
Be || Je();
});
}
}
var Qe, Be;
return (Qe = He.queue = []), (He.waitUntilQuiet = function(Ue) {
Be && Be(), (Be = Le(function() {
(Be = null), Ue(), Je();
}));
}), He;
}
])
.provider("$$animateQueue", [
"$animateProvider",
function(Le) {
function He(Ye) {
if (!Ye) return null;
var _e = Ye.split(Ve),
Ge = Object.create(null);
return Ne(_e, function(Xe) {
Ge[Xe] = !0;
}), Ge;
}
function Je(Ye, _e) {
if (Ye && _e) {
var Ge = He(_e);
return Ye.split(Ve).some(function(Xe) {
return Ge[Xe];
});
}
}
function Qe(Ye, _e, Ge) {
return We[Ye].some(function(Xe) {
return Xe(_e, Ge);
});
}
function Be(Ye, _e) {
var Ge = 0 < (Ye.addClass || "").length,
Xe = 0 < (Ye.removeClass || "").length;
return _e ? Ge && Xe : Ge || Xe;
}
var Ue = 1,
Me = 2,
Ve = " ",
We = (this.rules = { skip: [], cancel: [], join: [] });
We.join.push(function(Ye) {
return !Ye.structural && Be(Ye);
}), We.skip.push(function(Ye) {
return !Ye.structural && !Be(Ye);
}), We.skip.push(function(Ye, _e) {
return "leave" === _e.event && Ye.structural;
}), We.skip.push(function(Ye, _e) {
return _e.structural && _e.state === Me && !Ye.structural;
}), We.cancel.push(function(Ye, _e) {
return _e.structural && Ye.structural;
}), We.cancel.push(function(Ye, _e) {
return _e.state === Me && Ye.structural;
}), We.cancel.push(function(Ye, _e) {
if (_e.structural) return !1;
var Ge = Ye.addClass,
Xe = Ye.removeClass,
Ze = _e.addClass,
ze = _e.removeClass;
return (qe(Ge) && qe(Xe)) || (qe(Ze) && qe(ze)) ? !1 : Je(Ge, ze) || Je(Xe, Ze);
}), (this.$get = [
"$$rAF",
"$rootScope",
"$rootElement",
"$document",
"$$Map",
"$$animation",
"$$AnimateRunner",
"$templateRequest",
"$$jqLite",
"$$forceReflow",
"$$isDocumentHidden",
function(Ye, _e, Ge, Xe, Ze, ze, et, tt, at, nt, st) {
function it() {
var wt = !1;
return function(Nt) {
wt
? Nt()
: _e.$$postDigest(function() {
(wt = !0), Nt();
});
};
}
function ot(wt, Nt) {
return y(wt, Nt, {});
}
function rt(wt, Nt, Pt) {
var jt = [],
Ot = yt[Pt];
return Ot &&
Ne(Ot, function(Et) {
St.call(Et.node, Nt)
? jt.push(Et.callback)
: "leave" === Pt && St.call(Et.node, wt) && jt.push(Et.callback);
}), jt;
}
function lt(wt, Nt, Pt) {
var jt = u(Nt);
return wt.filter(function(Ot) {
var Et = Ot.node === jt && (!Pt || Ot.callback === Pt);
return !Et;
});
}
function dt(wt, Nt) {
"close" !== wt || Nt.parentNode || xt.off(Nt);
}
function ut(wt, Nt, Pt) {
function jt(Gt, Xt, Zt, zt) {
Kt(function() {
var ea = rt(qt, Rt, Xt);
ea.length
? Ye(function() {
Ne(ea, function(ta) {
ta(It, Zt, zt);
}), dt(Zt, Rt);
})
: dt(Zt, Rt);
}), Gt.progress(Xt, Zt, zt);
}
function Ot(Gt) {
k(It, Et), Tt(It, Et), $(It, Et), Et.domOperation(), Ft.complete(!Gt);
}
var Et = xe(Pt),
It = d(wt),
Rt = D(It),
qt = Rt && Rt.parentNode;
Et = f(Et);
var Ft = new et(),
Kt = it();
if (
(
Pe(Et.addClass) && (Et.addClass = Et.addClass.join(" ")),
Et.addClass && !Re(Et.addClass) && (Et.addClass = null),
Pe(Et.removeClass) && (Et.removeClass = Et.removeClass.join(" ")),
Et.removeClass && !Re(Et.removeClass) && (Et.removeClass = null),
Et.from && !Ie(Et.from) && (Et.from = null),
Et.to && !Ie(Et.to) && (Et.to = null),
!gt || !Rt || !(vt || At)(Rt, Nt, Pt) || !bt(Rt, Et)
)
)
return Ot(), Ft;
var Lt = 0 <= ["enter", "move", "leave"].indexOf(Nt),
Ht = st(),
Jt = Ht || $t.get(Rt),
Qt = (!Jt && ft.get(Rt)) || {},
Bt = !!Qt.state;
if ((Jt || (Bt && Qt.state === Ue) || (Jt = !ct(Rt, qt, Nt)), Jt))
return Ht && jt(Ft, Nt, "start"), Ot(), Ht && jt(Ft, Nt, "close"), Ft;
Lt && mt(Rt);
var Ut = {
structural: Lt,
element: It,
event: Nt,
addClass: Et.addClass,
removeClass: Et.removeClass,
close: Ot,
options: Et,
runner: Ft
};
if (Bt) {
var Mt = Qe("skip", Ut, Qt);
if (Mt) return Qt.state === Me ? (Ot(), Ft) : (y(It, Qt, Ut), Qt.runner);
var Vt = Qe("cancel", Ut, Qt);
if (!Vt) {
var Wt = Qe("join", Ut, Qt);
if (Wt)
if (Qt.state === Me) ot(It, Ut);
else
return A(It, Lt ? Nt : null, Et), (Nt = Ut.event = Qt.event), (Et = y(
It,
Qt,
Ut
)), Qt.runner;
} else if (Qt.state === Me) Qt.runner.end();
else if (Qt.structural) Qt.close();
else return y(It, Qt, Ut), Qt.runner;
} else ot(It, Ut);
var Yt = Ut.structural;
if (
(
Yt ||
(Yt =
("animate" === Ut.event && 0 < Object.keys(Ut.options.to || {}).length) ||
Be(Ut)),
!Yt
)
)
return Ot(), pt(Rt), Ft;
var _t = (Qt.counter || 0) + 1;
return (Ut.counter = _t), ht(Rt, Ue, Ut), _e.$$postDigest(function() {
It = d(wt);
var Gt = ft.get(Rt),
Xt = !Gt;
Gt = Gt || {};
var Zt = It.parent() || [],
zt = 0 < Zt.length && ("animate" === Gt.event || Gt.structural || Be(Gt));
if (Xt || Gt.counter !== _t || !zt)
return Xt && (Tt(It, Et), $(It, Et)), (Xt || (Lt && Gt.event !== Nt)) &&
(Et.domOperation(), Ft.end()), void (zt || pt(Rt));
(Nt = !Gt.structural && Be(Gt, !0) ? "setClass" : Gt.event), ht(Rt, Me);
var ea = ze(It, Nt, Gt.options);
Ft.setHost(ea), jt(Ft, Nt, "start", {}), ea.done(function(ta) {
Ot(!ta);
var na = ft.get(Rt);
na && na.counter === _t && pt(Rt), jt(Ft, Nt, "close", {});
});
}), Ft;
}
function mt(wt) {
var Nt = wt.querySelectorAll("[" + Ae + "]");
Ne(Nt, function(Pt) {
var jt = parseInt(Pt.getAttribute(Ae), 10),
Ot = ft.get(Pt);
if (Ot)
switch (jt) {
case Me:
Ot.runner.end();
case Ue:
ft.delete(Pt);
}
});
}
function pt(wt) {
wt.removeAttribute(Ae), ft.delete(wt);
}
function ct(wt, Nt) {
var jt = Xe[0].body,
Ot = D(Ge),
Et = wt === jt || "HTML" === wt.nodeName,
It = wt === Ot,
Rt = !1,
qt = $t.get(wt),
Ft,
Kt = Fe.data(wt, ke);
for (Kt && (Nt = D(Kt)); Nt && (It || (It = Nt === Ot), Nt.nodeType === K); ) {
var Lt = ft.get(Nt) || {};
if (!Rt) {
var Ht = $t.get(Nt);
if (!0 === Ht && !1 !== qt) {
qt = !0;
break;
} else !1 === Ht && (qt = !1);
Rt = Lt.structural;
}
if (qe(Ft) || !0 === Ft) {
var Jt = Fe.data(Nt, V);
je(Jt) && (Ft = Jt);
}
if (Rt && !1 === Ft) break;
if ((Et || (Et = Nt === jt), Et && It)) break;
if (!It && ((Kt = Fe.data(Nt, ke)), Kt)) {
Nt = D(Kt);
continue;
}
Nt = Nt.parentNode;
}
var Qt = (!Rt || Ft) && !0 !== qt;
return Qt && It && Et;
}
function ht(wt, Nt, Pt) {
(Pt = Pt || {}), (Pt.state = Nt), wt.setAttribute(Ae, Nt);
var jt = ft.get(wt),
Ot = jt ? we(jt, Pt) : Pt;
ft.set(wt, Ot);
}
var ft = new Ze(),
$t = new Ze(),
gt = null,
Ct = _e.$watch(
function() {
return 0 === tt.totalPendingRequests;
},
function(wt) {
wt &&
(
Ct(),
_e.$$postDigest(function() {
_e.$$postDigest(function() {
null === gt && (gt = !0);
});
})
);
}
),
yt = Object.create(null),
vt = Le.customFilter(),
Dt = Le.classNameFilter(),
At = function() {
return !0;
},
bt = Dt
? function(wt, Nt) {
var Pt = [wt.getAttribute("class"), Nt.addClass, Nt.removeClass].join(" ");
return Dt.test(Pt);
}
: At,
Tt = h(at),
St =
e.Node.prototype.contains ||
function(wt) {
return this === wt || !!(16 & this.compareDocumentPosition(wt));
},
xt = {
on: function on(wt, Nt, Pt) {
var jt = u(Nt);
(yt[wt] = yt[wt] || []), yt[wt].push({ node: jt, callback: Pt }), Fe(
Nt
).on("$destroy", function() {
var Ot = ft.get(jt);
Ot || xt.off(wt, Nt, Pt);
});
},
off: function off(wt, Nt, Pt) {
if (1 === arguments.length && !Re(arguments[0])) {
for (var jt in ((Nt = arguments[0]), yt)) yt[jt] = lt(yt[jt], Nt);
return;
}
var Ot = yt[wt];
Ot && (yt[wt] = 1 === arguments.length ? null : lt(Ot, Nt, Pt));
},
pin: function pin(wt, Nt) {
n(Oe(wt), "element", "not an element"), n(
Oe(Nt),
"parentElement",
"not an element"
), wt.data(ke, Nt);
},
push: function push(wt, Nt, Pt, jt) {
return (Pt = Pt || {}), (Pt.domOperation = jt), ut(wt, Nt, Pt);
},
enabled: function enabled(wt, Nt) {
var Pt = arguments.length;
if (0 === Pt) Nt = !!gt;
else {
var jt = Oe(wt);
if (!jt) Nt = gt = !!wt;
else {
var Ot = D(wt);
1 === Pt ? (Nt = !$t.get(Ot)) : $t.set(Ot, !Nt);
}
}
return Nt;
}
};
return xt;
}
]);
}
])
.provider("$$animation", [
"$animateProvider",
function() {
function He(Ve, We) {
Ve.data(Me, We);
}
function Je(Ve) {
Ve.removeData(Me);
}
function Qe(Ve) {
return Ve.data(Me);
}
var Be = "ng-animate-ref",
Ue = (this.drivers = []),
Me = "$$animationRunner";
this.$get = [
"$$jqLite",
"$rootScope",
"$injector",
"$$AnimateRunner",
"$$Map",
"$$rAFScheduler",
function(Ve, We, Ye, _e, Ge, Xe) {
function Ze(tt) {
function at(lt) {
if (lt.processed) return lt;
lt.processed = !0;
var dt = lt.domNode,
ut = dt.parentNode;
ot.set(dt, lt);
for (var mt; ut; ) {
if (((mt = ot.get(ut)), mt)) {
mt.processed || (mt = at(mt));
break;
}
ut = ut.parentNode;
}
return (mt || st).children.push(lt), lt;
}
var st = { children: [] },
it,
ot = new Ge();
for (it = 0; it < tt.length; it++) {
var rt = tt[it];
ot.set(rt.domNode, (tt[it] = { domNode: rt.domNode, fn: rt.fn, children: [] }));
}
for (it = 0; it < tt.length; it++) at(tt[it]);
return (function(lt) {
var mt,
dt = [],
ut = [];
for (mt = 0; mt < lt.children.length; mt++) ut.push(lt.children[mt]);
var pt = ut.length,
ct = 0,
ht = [];
for (mt = 0; mt < ut.length; mt++) {
var ft = ut[mt];
0 >= pt && ((pt = ct), (ct = 0), dt.push(ht), (ht = [])), ht.push(
ft.fn
), ft.children.forEach(function($t) {
ct++, ut.push($t);
}), pt--;
}
return ht.length && dt.push(ht), dt;
})(st);
}
var ze = [],
et = h(Ve);
return function(tt, at, nt) {
function st(gt) {
var yt = gt.hasAttribute(Be) ? [gt] : gt.querySelectorAll("[" + Be + "]"),
vt = [];
return Ne(yt, function(Dt) {
var At = Dt.getAttribute(Be);
At && At.length && vt.push(Dt);
}), vt;
}
function it(gt) {
var Ct = [],
yt = {};
Ne(gt, function(At, kt) {
var bt = At.element,
Tt = D(bt),
St = At.event,
xt = 0 <= ["enter", "move"].indexOf(St),
wt = At.structural ? st(Tt) : [];
if (wt.length) {
var Nt = xt ? "to" : "from";
Ne(wt, function(Pt) {
var jt = Pt.getAttribute(Be);
(yt[jt] = yt[jt] || {}), (yt[jt][Nt] = { animationID: kt, element: Fe(Pt) });
});
} else Ct.push(At);
});
var vt = {},
Dt = {};
return Ne(yt, function(At) {
var bt = At.from,
Tt = At.to;
if (!bt || !Tt) {
var St = bt ? bt.animationID : Tt.animationID,
xt = St.toString();
return void (vt[xt] || ((vt[xt] = !0), Ct.push(gt[St])));
}
var wt = gt[bt.animationID],
Nt = gt[Tt.animationID],
Pt = bt.animationID.toString();
if (!Dt[Pt]) {
var jt = (Dt[Pt] = {
structural: !0,
beforeStart: function beforeStart() {
wt.beforeStart(), Nt.beforeStart();
},
close: function close() {
wt.close(), Nt.close();
},
classes: ot(wt.classes, Nt.classes),
from: wt,
to: Nt,
anchors: []
});
jt.classes.length ? Ct.push(jt) : (Ct.push(wt), Ct.push(Nt));
}
Dt[Pt].anchors.push({ out: bt.element, in: Tt.element });
}), Ct;
}
function ot(gt, Ct) {
(gt = gt.split(" ")), (Ct = Ct.split(" "));
for (var Dt, yt = [], vt = 0; vt < gt.length; vt++)
if (((Dt = gt[vt]), "ng-" !== Dt.substring(0, 3)))
for (var At = 0; At < Ct.length; At++)
if (Dt === Ct[At]) {
yt.push(Dt);
break;
}
return yt.join(" ");
}
function rt(gt) {
for (var Ct = Ue.length - 1; 0 <= Ct; Ct--) {
var yt = Ue[Ct],
vt = Ye.get(yt),
Dt = vt(gt);
if (Dt) return Dt;
}
}
function dt(gt, Ct) {
function yt(vt) {
var Dt = Qe(vt);
Dt && Dt.setHost(Ct);
}
gt.from && gt.to ? (yt(gt.from.element), yt(gt.to.element)) : yt(gt.element);
}
function ut() {
var gt = Qe(tt);
gt && ("leave" !== at || !nt.$$domOperationFired) && gt.end();
}
function mt(gt) {
tt.off("$destroy", ut), Je(tt), et(tt, nt), $(tt, nt), nt.domOperation(), ft &&
Ve.removeClass(tt, ft), tt.removeClass(M), ct.complete(!gt);
}
nt = f(nt);
var pt = 0 <= ["enter", "move", "leave"].indexOf(at),
ct = new _e({
end: function end() {
mt();
},
cancel: function cancel() {
mt(!0);
}
});
if (!Ue.length) return mt(), ct;
He(tt, ct);
var ht = s(tt.attr("class"), s(nt.addClass, nt.removeClass)),
ft = nt.tempClasses;
ft && ((ht += " " + ft), (nt.tempClasses = null));
var $t;
return (
pt && (($t = "ng-" + at + "-prepare"), Ve.addClass(tt, $t)),
ze.push({
element: tt,
classes: ht,
event: at,
structural: pt,
options: nt,
beforeStart: function() {
tt.addClass(M), ft && Ve.addClass(tt, ft), $t &&
(Ve.removeClass(tt, $t), ($t = null));
},
close: mt
}),
tt.on("$destroy", ut),
1 < ze.length
)
? ct
: (
We.$$postDigest(function() {
var gt = [];
Ne(ze, function(vt) {
Qe(vt.element) ? gt.push(vt) : vt.close();
}), (ze.length = 0);
var Ct = it(gt),
yt = [];
Ne(Ct, function(vt) {
yt.push({
domNode: D(vt.from ? vt.from.element : vt.element),
fn: function() {
vt.beforeStart();
var At,
kt = vt.close,
bt = vt.anchors ? vt.from.element || vt.to.element : vt.element;
if (Qe(bt)) {
var Tt = rt(vt);
Tt && (At = Tt.start);
}
if (!At) kt();
else {
var St = At();
St.done(function(xt) {
kt(!xt);
}), dt(vt, St);
}
}
});
}), Xe(Ze(yt));
}),
ct
);
};
}
];
}
])
.provider("$animateCss", [
"$animateProvider",
function() {
var He = q(),
Je = q();
this.$get = [
"$window",
"$$jqLite",
"$$AnimateRunner",
"$timeout",
"$$forceReflow",
"$sniffer",
"$$rAFScheduler",
"$$animateQueue",
function(Qe, Be, Ue, Me, Ve, We, Ye, _e) {
function Ge(st, it) {
var ot = "$$ngAnimateParentKey",
rt = st.parentNode,
lt = rt[ot] || (rt[ot] = ++at);
return lt + "-" + st.getAttribute("class") + "-" + it;
}
function Xe(st, it, ot, rt) {
var lt = He.get(ot);
return lt ||
(
(lt = O(Qe, st, rt)),
"infinite" === lt.animationIterationCount && (lt.animationIterationCount = 1)
), He.put(ot, lt), lt;
}
function Ze(st, it, ot, rt) {
var lt;
if (0 < He.count(ot) && ((lt = Je.get(ot)), !lt)) {
var dt = r(it, "-stagger");
Be.addClass(st, dt), (lt = O(Qe, st, rt)), (lt.animationDuration = Math.max(
lt.animationDuration,
0
)), (lt.transitionDuration = Math.max(lt.transitionDuration, 0)), Be.removeClass(
st,
dt
), Je.put(ot, lt);
}
return lt || {};
}
function ze(st) {
nt.push(st), Ye.waitUntilQuiet(function() {
He.flush(), Je.flush();
for (var it = Ve(), ot = 0; ot < nt.length; ot++) nt[ot](it);
nt.length = 0;
});
}
function et(st, it, ot) {
var rt = Xe(st, it, ot, $e),
lt = rt.animationDelay,
dt = rt.transitionDelay;
return (rt.maxDelay =
lt && dt ? Math.max(lt, dt) : lt || dt), (rt.maxDuration = Math.max(
rt.animationDuration * rt.animationIterationCount,
rt.transitionDuration
)), rt;
}
var tt = h(Be),
at = 0,
nt = [];
return function(it, ot) {
function rt() {
dt();
}
function lt() {
dt(!0);
}
function dt(zt) {
if (!(yt || (Dt && vt))) {
(yt = !0), (vt = !1), ct.$$skipPreparationClasses ||
Be.removeClass(it, It), Be.removeClass(it, qt), S(ft, !1), T(
ft,
!1
), Ne($t, function(ta) {
ft.style[ta[0]] = "";
}), tt(it, ct), $(it, ct), Object.keys(ht).length &&
Ne(ht, function(ta, na) {
ta ? ft.style.setProperty(na, ta) : ft.style.removeProperty(na);
}), ct.onDone && ct.onDone(), Nt.length && it.off(Nt.join(" "), pt);
var ea = it.data(pe);
ea && (Me.cancel(ea[0].timer), it.removeData(pe)), At && At.complete(!zt);
}
}
function ut(zt) {
Gt.blockTransition && T(ft, zt), Gt.blockKeyframeAnimation && S(ft, !!zt);
}
function mt() {
return (At = new Ue({ end: rt, cancel: lt })), ze(Ke), dt(), {
$$willAnimate: !1,
start: function start() {
return At;
},
end: rt
};
}
function pt(zt) {
zt.stopPropagation();
var ea = zt.originalEvent || zt,
ta = ea.$manualTimeStamp || Date.now(),
na = parseFloat(ea.elapsedTime.toFixed(3));
Math.max(ta - wt, 0) >= Tt && na >= St && ((Dt = !0), dt());
}
function Zt() {
function zt() {
if (!yt) {
if (
(
ut(!1),
Ne($t, function(pa) {
var ca = pa[0],
ha = pa[1];
ft.style[ca] = ha;
}),
tt(it, ct),
Be.addClass(it, qt),
Gt.recalculateTimingStyles
)
) {
if (
(
(Rt = ft.getAttribute("class") + " " + It),
(Lt = Ge(ft, Rt)),
(Yt = et(ft, Rt, Lt)),
(_t = Yt.maxDelay),
(bt = Math.max(_t, 0)),
(St = Yt.maxDuration),
0 === St
)
)
return void dt();
(Gt.hasTransitions = 0 < Yt.transitionDuration), (Gt.hasAnimations =
0 < Yt.animationDuration);
}
if (
(
Gt.applyAnimationDelay &&
(
(_t =
"boolean" != typeof ct.delay && I(ct.delay)
? parseFloat(ct.delay)
: _t),
(bt = Math.max(_t, 0)),
(Yt.animationDelay = _t),
(Xt = P(_t, !0)),
$t.push(Xt),
(ft.style[Xt[0]] = Xt[1])
),
(Tt = bt * ce),
(xt = St * ce),
ct.easing
)
) {
var sa,
ia = ct.easing;
Gt.hasTransitions &&
((sa = Y + te), $t.push([sa, ia]), (ft.style[sa] = ia)), Gt.hasAnimations &&
((sa = G + te), $t.push([sa, ia]), (ft.style[sa] = ia));
}
Yt.transitionDuration && Nt.push(_), Yt.animationDuration &&
Nt.push(X), (wt = Date.now());
var oa = Tt + 1.5 * xt,
ra = wt + oa,
la = it.data(pe) || [],
da = !0;
if (la.length) {
var ua = la[0];
(da = ra > ua.expectedEndTime), da ? Me.cancel(ua.timer) : la.push(dt);
}
if (da) {
var ma = Me(ea, oa, !1);
(la[0] = { timer: ma, expectedEndTime: ra }), la.push(dt), it.data(pe, la);
}
Nt.length && it.on(Nt.join(" "), pt), ct.to &&
(ct.cleanupStyles && F(ht, ft, Object.keys(ct.to)), C(it, ct));
}
}
function ea() {
var sa = it.data(pe);
if (sa) {
for (var ia = 1; ia < sa.length; ia++) sa[ia]();
it.removeData(pe);
}
}
if (!yt) {
if (!ft.parentNode) return void dt();
var ta = function(sa) {
if (!!Dt) vt && sa && ((vt = !1), dt());
else if (((vt = !sa), Yt.animationDuration)) {
var ia = S(ft, vt);
vt ? $t.push(ia) : l($t, ia);
}
},
na =
0 < Vt &&
((Yt.transitionDuration && 0 === Ht.transitionDuration) ||
(Yt.animationDuration && 0 === Ht.animationDuration)) &&
Math.max(Ht.animationDelay, Ht.transitionDelay);
na ? Me(zt, Math.floor(na * Vt * ce), !1) : zt(), (kt.resume = function() {
ta(!0);
}), (kt.pause = function() {
ta(!1);
});
}
}
var ct = ot || {};
ct.$$prepared || (ct = f(xe(ct)));
var ht = {},
ft = D(it);
if (!ft || !ft.parentNode || !_e.enabled()) return mt();
var yt,
vt,
Dt,
At,
kt,
bt,
Tt,
St,
xt,
wt,
$t = [],
gt = it.attr("class"),
Ct = o(ct),
Nt = [];
if (0 === ct.duration || (!We.animations && !We.transitions)) return mt();
var Pt = ct.event && Pe(ct.event) ? ct.event.join(" ") : ct.event,
jt = Pt && ct.structural,
Ot = "",
Et = "";
jt ? (Ot = r(Pt, Q, !0)) : Pt && (Ot = Pt), ct.addClass &&
(Et += r(ct.addClass, H)), ct.removeClass &&
(Et.length && (Et += " "), (Et += r(ct.removeClass, J))), ct.applyClassesEarly &&
Et.length &&
tt(it, ct);
var It = [Ot, Et].join(" ").trim(),
Rt = gt + " " + It,
qt = r(It, "-active"),
Ft = Ct.to && 0 < Object.keys(Ct.to).length,
Kt = 0 < (ct.keyframeStyle || "").length;
if (!Kt && !Ft && !It) return mt();
var Lt, Ht;
if (0 < ct.stagger) {
var Jt = parseFloat(ct.stagger);
Ht = {
transitionDelay: Jt,
animationDelay: Jt,
transitionDuration: 0,
animationDuration: 0
};
} else (Lt = Ge(ft, Rt)), (Ht = Ze(ft, It, Lt, ge));
ct.$$skipPreparationClasses || Be.addClass(it, It);
var Qt;
if (ct.transitionStyle) {
var Bt = [Y, ct.transitionStyle];
x(ft, Bt), $t.push(Bt);
}
if (0 <= ct.duration) {
Qt = 0 < ft.style[Y].length;
var Ut = R(ct.duration, Qt);
x(ft, Ut), $t.push(Ut);
}
if (ct.keyframeStyle) {
var Mt = [G, ct.keyframeStyle];
x(ft, Mt), $t.push(Mt);
}
var Vt = Ht ? (0 <= ct.staggerIndex ? ct.staggerIndex : He.count(Lt)) : 0,
Wt = 0 === Vt;
Wt && !ct.skipBlocking && T(ft, 9999);
var Yt = et(ft, Rt, Lt),
_t = Yt.maxDelay;
(bt = Math.max(_t, 0)), (St = Yt.maxDuration);
var Gt = {};
if (
(
(Gt.hasTransitions = 0 < Yt.transitionDuration),
(Gt.hasAnimations = 0 < Yt.animationDuration),
(Gt.hasTransitionAll = Gt.hasTransitions && "all" === Yt.transitionProperty),
(Gt.applyTransitionDuration =
Ft &&
((Gt.hasTransitions && !Gt.hasTransitionAll) ||
(Gt.hasAnimations && !Gt.hasTransitions))),
(Gt.applyAnimationDuration = ct.duration && Gt.hasAnimations),
(Gt.applyTransitionDelay =
I(ct.delay) && (Gt.applyTransitionDuration || Gt.hasTransitions)),
(Gt.applyAnimationDelay = I(ct.delay) && Gt.hasAnimations),
(Gt.recalculateTimingStyles = 0 < Et.length),
(Gt.applyTransitionDuration || Gt.applyAnimationDuration) &&
(
(St = ct.duration ? parseFloat(ct.duration) : St),
Gt.applyTransitionDuration &&
(
(Gt.hasTransitions = !0),
(Yt.transitionDuration = St),
(Qt = 0 < ft.style[Y + z].length),
$t.push(R(St, Qt))
),
Gt.applyAnimationDuration &&
((Gt.hasAnimations = !0), (Yt.animationDuration = St), $t.push(N(St)))
),
0 === St && !Gt.recalculateTimingStyles
)
)
return mt();
if (null != ct.delay) {
var Xt;
"boolean" != typeof ct.delay &&
((Xt = parseFloat(ct.delay)), (bt = Math.max(Xt, 0))), Gt.applyTransitionDelay &&
$t.push(P(Xt)), Gt.applyAnimationDelay && $t.push(P(Xt, !0));
}
return null == ct.duration &&
0 < Yt.transitionDuration &&
(Gt.recalculateTimingStyles = Gt.recalculateTimingStyles || Wt), (Tt =
bt * ce), (xt = St * ce), ct.skipBlocking ||
(
(Gt.blockTransition = 0 < Yt.transitionDuration),
(Gt.blockKeyframeAnimation =
0 < Yt.animationDuration && 0 < Ht.animationDelay && 0 === Ht.animationDuration)
), ct.from &&
(
ct.cleanupStyles && F(ht, ft, Object.keys(ct.from)),
g(it, ct)
), Gt.blockTransition || Gt.blockKeyframeAnimation
? ut(St)
: !ct.skipBlocking && T(ft, !1), {
$$willAnimate: !0,
end: rt,
start: function start() {
if (!yt)
return (kt = { end: rt, cancel: lt, resume: null, pause: null }), (At = new Ue(
kt
)), ze(Zt), At;
}
};
};
}
];
}
])
.provider("$$animateCssDriver", [
"$$animationProvider",
function(Le) {
function He(Me) {
return Me.parentNode && 11 === Me.parentNode.nodeType;
}
Le.drivers.push("$$animateCssDriver");
var Je = "ng-animate-shim",
Be = "ng-anchor-out";
this.$get = [
"$animateCss",
"$rootScope",
"$$AnimateRunner",
"$rootElement",
"$sniffer",
"$$jqLite",
"$document",
function(Me, Ve, We, Ye, _e, Ge, Xe) {
function Ze(ot) {
return ot.replace(/\bng-\S+\b/g, "");
}
function ze(ot, rt) {
return Re(ot) && (ot = ot.split(" ")), Re(rt) && (rt = rt.split(" ")), ot
.filter(function(lt) {
return -1 === rt.indexOf(lt);
})
.join(" ");
}
function et(ot, rt, lt) {
function dt(yt) {
var vt = {},
Dt = D(yt).getBoundingClientRect();
return Ne(["width", "height", "top", "left"], function(At) {
var kt = Dt[At];
"top" === At
? (kt += nt.scrollTop)
: "left" === At
? (kt += nt.scrollLeft)
: void 0, (vt[At] = Math.floor(kt) + "px");
}), vt;
}
function mt(yt) {
return yt.attr("class") || "";
}
function pt() {
var yt = Ze(mt(lt)),
vt = ze(yt, ft),
Dt = ze(ft, yt),
At = Me(ht, {
to: dt(lt),
addClass: "ng-anchor-in" + " " + vt,
removeClass: Be + " " + Dt,
delay: !0
});
return At.$$willAnimate ? At : null;
}
function ct() {
ht.remove(), rt.removeClass(Je), lt.removeClass(Je);
}
var ht = Fe(D(rt).cloneNode(!0)),
ft = Ze(mt(ht));
rt.addClass(Je), lt.addClass(Je), ht.addClass("ng-anchor"), it.append(ht);
var $t,
gt = (function() {
var yt = Me(ht, { addClass: Be, delay: !0, from: dt(rt) });
return yt.$$willAnimate ? yt : null;
})();
if (!gt && (($t = pt()), !$t)) return ct();
var Ct = gt || $t;
return {
start: function start() {
function yt() {
Dt && Dt.end();
}
var vt,
Dt = Ct.start();
return Dt.done(function() {
return (Dt = null), !$t && (($t = pt()), $t)
? (
(Dt = $t.start()),
Dt.done(function() {
(Dt = null), ct(), vt.complete();
}),
Dt
)
: void (ct(), vt.complete());
}), (vt = new We({ end: yt, cancel: yt })), vt;
}
};
}
function tt(ot, rt, lt, dt) {
var ut = at(ot, Ke),
mt = at(rt, Ke),
pt = [];
return Ne(dt, function(ct) {
var ht = ct.out,
ft = ct["in"],
$t = et(lt, ht, ft);
$t && pt.push($t);
}), ut || mt || 0 !== pt.length
? {
start: function start() {
function ct() {
Ne(ht, function($t) {
$t.end();
});
}
var ht = [];
ut && ht.push(ut.start()), mt && ht.push(mt.start()), Ne(pt, function($t) {
ht.push($t.start());
});
var ft = new We({ end: ct, cancel: ct });
return We.all(ht, function($t) {
ft.complete($t);
}), ft;
}
}
: void 0;
}
function at(ot) {
var rt = ot.element,
lt = ot.options || {};
ot.structural &&
(
(lt.event = ot.event),
(lt.structural = !0),
(lt.applyClassesEarly = !0),
"leave" === ot.event && (lt.onDone = lt.domOperation)
), lt.preparationClasses && (lt.event = w(lt.event, lt.preparationClasses));
var dt = Me(rt, lt);
return dt.$$willAnimate ? dt : null;
}
if (!_e.animations && !_e.transitions) return Ke;
var nt = Xe[0].body,
st = D(Ye),
it = Fe(He(st) || nt.contains(st) ? st : nt);
return function(rt) {
return rt.from && rt.to ? tt(rt.from, rt.to, rt.classes, rt.anchors) : at(rt);
};
}
];
}
])
.provider("$$animateJs", [
"$animateProvider",
function(Le) {
this.$get = [
"$injector",
"$$AnimateRunner",
"$$jqLite",
function(He, Je, Qe) {
function Be(Me) {
Me = Pe(Me) ? Me : Me.split(" ");
for (var Ve = [], We = {}, Ye = 0; Ye < Me.length; Ye++) {
var _e = Me[Ye],
Ge = Le.$$registeredAnimations[_e];
Ge && !We[_e] && (Ve.push(He.get(Ge)), (We[_e] = !0));
}
return Ve;
}
var Ue = h(Qe);
return function(Me, Ve, We, Ye) {
function _e() {
Ye.domOperation(), Ue(Me, Ye);
}
function Ge() {
(et = !0), _e(), $(Me, Ye);
}
function Xe(dt, ut, mt, pt, ct) {
var ht;
switch (mt) {
case "animate":
ht = [ut, pt.from, pt.to, ct];
break;
case "setClass":
ht = [ut, tt, at, ct];
break;
case "addClass":
ht = [ut, tt, ct];
break;
case "removeClass":
ht = [ut, at, ct];
break;
default:
ht = [ut, ct];
}
ht.push(pt);
var ft = dt.apply(dt, ht);
if (ft)
if ((Ee(ft.start) && (ft = ft.start()), ft instanceof Je)) ft.done(ct);
else if (Ee(ft)) return ft;
return Ke;
}
function Ze(dt, ut, mt, pt, ct) {
var ht = [];
return Ne(pt, function(ft) {
var $t = ft[ct];
$t &&
ht.push(function() {
var gt,
Ct,
yt = !1,
vt = function(Dt) {
yt || ((yt = !0), (Ct || Ke)(Dt), gt.complete(!Dt));
};
return (gt = new Je({
end: function end() {
vt();
},
cancel: function cancel() {
vt(!0);
}
})), (Ct = Xe($t, dt, ut, mt, function(Dt) {
vt(!1 === Dt);
})), gt;
});
}), ht;
}
function ze(dt, ut, mt, pt, ct) {
var ht = Ze(dt, ut, mt, pt, ct);
if (0 === ht.length) {
var ft, $t;
"beforeSetClass" === ct
? (
(ft = Ze(dt, "removeClass", mt, pt, "beforeRemoveClass")),
($t = Ze(dt, "addClass", mt, pt, "beforeAddClass"))
)
: "setClass" == ct &&
(
(ft = Ze(dt, "removeClass", mt, pt, "removeClass")),
($t = Ze(dt, "addClass", mt, pt, "addClass"))
), ft && (ht = ht.concat(ft)), $t && (ht = ht.concat($t));
}
return 0 === ht.length
? void 0
: function(Ct) {
var yt = [];
return ht.length &&
Ne(ht, function(vt) {
yt.push(vt());
}), yt.length ? Je.all(yt, Ct) : Ct(), function(Dt) {
Ne(yt, function(At) {
Dt ? At.cancel() : At.end();
});
};
};
}
var et = !1;
3 === arguments.length && Ie(We) && ((Ye = We), (We = null)), (Ye = f(Ye)), We ||
(
(We = Me.attr("class") || ""),
Ye.addClass && (We += " " + Ye.addClass),
Ye.removeClass && (We += " " + Ye.removeClass)
);
var tt = Ye.addClass,
at = Ye.removeClass,
nt = Be(We),
st,
it;
if (nt.length) {
var ot, rt;
"leave" === Ve
? ((rt = "leave"), (ot = "afterLeave"))
: (
(rt = "before" + Ve.charAt(0).toUpperCase() + Ve.substr(1)),
(ot = Ve)
), "enter" !== Ve && "move" !== Ve && (st = ze(Me, Ve, Ye, nt, rt)), (it = ze(
Me,
Ve,
Ye,
nt,
ot
));
}
if (st || it) {
var lt;
return {
$$willAnimate: !0,
end: function end() {
return lt ? lt.end() : (Ge(), (lt = new Je()), lt.complete(!0)), lt;
},
start: function start() {
function dt(ct) {
Ge(ct), lt.complete(ct);
}
function ut(ct) {
et || ((mt || Ke)(ct), dt(ct));
}
if (lt) return lt;
lt = new Je();
var mt,
pt = [];
return st &&
pt.push(function(ct) {
mt = st(ct);
}), pt.length
? pt.push(function(ct) {
_e(), ct(!0);
})
: _e(), it &&
pt.push(function(ct) {
mt = it(ct);
}), lt.setHost({
end: function end() {
ut();
},
cancel: function cancel() {
ut(!0);
}
}), Je.chain(pt, dt), lt;
}
};
}
};
}
];
}
])
.provider("$$animateJsDriver", [
"$$animationProvider",
function(Le) {
Le.drivers.push("$$animateJsDriver"), (this.$get = [
"$$animateJs",
"$$AnimateRunner",
function(He, Je) {
function Qe(Be) {
var Ue = Be.element,
Me = Be.event,
Ve = Be.options,
We = Be.classes;
return He(Ue, Me, We, Ve);
}
return function(Ue) {
if (Ue.from && Ue.to) {
var Me = Qe(Ue.from),
Ve = Qe(Ue.to);
return Me || Ve
? {
start: function start() {
function We() {
return function() {
Ne(_e, function(Xe) {
Xe.end();
});
};
}
var _e = [];
Me && _e.push(Me.start()), Ve && _e.push(Ve.start()), Je.all(_e, function(
Xe
) {
Ge.complete(Xe);
});
var Ge = new Je({ end: We(), cancel: We() });
return Ge;
}
}
: void 0;
}
return Qe(Ue);
};
}
]);
}
]);
})(window, window.angular);
'use strict';(function(e,t){'use strict';function n(Le,He,Je){if(!Le)throw de('areq','Argument \'{0}\' is {1}',He||'?',Je||'required');return Le}function s(Le,He){return Le||He?Le?He?(Pe(Le)&&(Le=Le.join(' ')),Pe(He)&&(He=He.join(' ')),Le+' '+He):Le:He:''}function o(Le){var He={};return Le&&(Le.to||Le.from)&&(He.to=Le.to,He.from=Le.from),He}function r(Le,He,Je){var Qe='';return Le=Pe(Le)?Le:Le&&Re(Le)&&Le.length?Le.split(/\s+/):[],Ne(Le,function(Be,Ue){Be&&0<Be.length&&(Qe+=0<Ue?' ':'',Qe+=Je?He+Be:Be+He)}),Qe}function l(Le,He){var Je=Le.indexOf(He);0<=He&&Le.splice(Je,1)}function d(Le){if(Le instanceof Fe)switch(Le.length){case 0:return Le;case 1:if(Le[0].nodeType===K)return Le;break;default:return Fe(u(Le));}return Le.nodeType===K?Fe(Le):void 0}function u(Le){if(!Le[0])return Le;for(var Je,He=0;He<Le.length;He++)if(Je=Le[He],Je.nodeType===K)return Je}function m(Le,He,Je){Ne(He,function(Qe){Le.addClass(Qe,Je)})}function p(Le,He,Je){Ne(He,function(Qe){Le.removeClass(Qe,Je)})}function h(Le){return function(He,Je){Je.addClass&&(m(Le,He,Je.addClass),Je.addClass=null),Je.removeClass&&(p(Le,He,Je.removeClass),Je.removeClass=null)}}function f(Le){if(Le=Le||{},!Le.$$prepared){var He=Le.domOperation||Ke;Le.domOperation=function(){Le.$$domOperationFired=!0,He(),He=Ke},Le.$$prepared=!0}return Le}function $(Le,He){g(Le,He),C(Le,He)}function g(Le,He){He.from&&(Le.css(He.from),He.from=null)}function C(Le,He){He.to&&(Le.css(He.to),He.to=null)}function y(Le,He,Je){var Qe=He.options||{},Be=Je.options||{},Ue=(Qe.addClass||'')+' '+(Be.addClass||''),Me=(Qe.removeClass||'')+' '+(Be.removeClass||''),Ve=v(Le.attr('class'),Ue,Me);Be.preparationClasses&&(Qe.preparationClasses=w(Be.preparationClasses,Qe.preparationClasses),delete Be.preparationClasses);var We=Qe.domOperation===Ke?null:Qe.domOperation;return we(Qe,Be),We&&(Qe.domOperation=We),Qe.addClass=Ve.addClass?Ve.addClass:null,Qe.removeClass=Ve.removeClass?Ve.removeClass:null,He.addClass=Qe.addClass,He.removeClass=Qe.removeClass,Qe}function v(Le,He,Je){function Qe(We){Re(We)&&(We=We.split(' '));var Ye={};return Ne(We,function(_e){_e.length&&(Ye[_e]=!0)}),Ye}var Be=1,Ue=-1,Me={};Le=Qe(Le),He=Qe(He),Ne(He,function(We,Ye){Me[Ye]=Be}),Je=Qe(Je),Ne(Je,function(We,Ye){Me[Ye]=Me[Ye]===Be?null:Ue});var Ve={addClass:'',removeClass:''};return Ne(Me,function(We,Ye){var _e,Ge;We===Be?(_e='addClass',Ge=!Le[Ye]||Le[Ye+J]):We==Ue&&(_e='removeClass',Ge=Le[Ye]||Le[Ye+H]),Ge&&(Ve[_e].length&&(Ve[_e]+=' '),Ve[_e]+=Ye)}),Ve}function D(Le){return Le instanceof Fe?Le[0]:Le}function A(Le,He,Je){var Qe='';He&&(Qe=r(He,Q,!0)),Je.addClass&&(Qe=w(Qe,r(Je.addClass,H))),Je.removeClass&&(Qe=w(Qe,r(Je.removeClass,J))),Qe.length&&(Je.preparationClasses=Qe,Le.addClass(Qe))}function k(Le,He){He.preparationClasses&&(Le.removeClass(He.preparationClasses),He.preparationClasses=null),He.activeClasses&&(Le.removeClass(He.activeClasses),He.activeClasses=null)}function T(Le,He){var Je=He?'-'+He+'s':'';return x(Le,[re,Je]),[re,Je]}function S(Le,He){var Je=He?'paused':'',Qe=G+'PlayState';return x(Le,[Qe,Je]),[Qe,Je]}function x(Le,He){var Je=He[0],Qe=He[1];Le.style[Je]=Qe}function w(Le,He){return Le?He?Le+' '+He:Le:He}function N(Le){return[oe,Le+'s']}function P(Le,He){var Je=He?ie:re;return[Je,Le+'s']}function O(Le,He,Je){var Qe=Object.create(null),Be=Le.getComputedStyle(He)||{};return Ne(Je,function(Ue,Me){var Ve=Be[Ue];if(Ve){var We=Ve.charAt(0);('-'===We||'+'===We||0<=We)&&(Ve=E(Ve)),0===Ve&&(Ve=null),Qe[Me]=Ve}}),Qe}function E(Le){var He=0,Je=Le.split(/\s*,\s*/);return Ne(Je,function(Qe){'s'===Qe.charAt(Qe.length-1)&&(Qe=Qe.substring(0,Qe.length-1)),Qe=parseFloat(Qe)||0,He=He?Math.max(Qe,He):Qe}),He}function I(Le){return 0===Le||null!=Le}function R(Le,He){var Je=Y,Qe=Le+'s';return He?Je+=Z:Qe+=' linear all',[Je,Qe]}function q(){var Le=Object.create(null);return{flush:function flush(){Le=Object.create(null)},count:function count(He){var Je=Le[He];return Je?Je.total:0},get:function get(He){var Je=Le[He];return Je&&Je.value},put:function put(He,Je){Le[He]?Le[He].total++:Le[He]={total:1,value:Je}}}}function F(Le,He,Je){Ne(Je,function(Qe){Le[Qe]=je(Le[Qe])?Le[Qe]:He.style.getPropertyValue(Qe)})}var K=1,H='-add',J='-remove',Q='ng-',M='ng-animate',V='$$ngAnimateChildren',W='',Y,_,G,X;e.ontransitionend===void 0&&e.onwebkittransitionend!==void 0?(W='-webkit-',Y='WebkitTransition',_='webkitTransitionEnd transitionend'):(Y='transition',_='transitionend'),e.onanimationend===void 0&&e.onwebkitanimationend!==void 0?(W='-webkit-',G='WebkitAnimation',X='webkitAnimationEnd animationend'):(G='animation',X='animationend');var Z='Duration',z='Property',ee='Delay',te='TimingFunction',ie=G+ee,oe=G+Z,re=Y+ee,le=Y+Z,de=t.$$minErr('ng'),pe='$$animateCss',ce=1e3,$e={transitionDuration:le,transitionDelay:re,transitionProperty:Y+z,animationDuration:oe,animationDelay:ie,animationIterationCount:G+'IterationCount'},ge={transitionDuration:le,transitionDelay:re,animationDuration:oe,animationDelay:ie},Ae='data-ng-animate',ke='$ngAnimatePin',xe,we,Ne,Pe,je,Oe,Ee,Ie,Re,qe,Fe,Ke;t.module('ngAnimate',[],function(){Ke=t.noop,xe=t.copy,we=t.extend,Fe=t.element,Ne=t.forEach,Pe=t.isArray,Re=t.isString,Ie=t.isObject,qe=t.isUndefined,je=t.isDefined,Ee=t.isFunction,Oe=t.isElement}).info({angularVersion:'1.6.5'}).directive('ngAnimateSwap',['$animate','$rootScope',function(Le){return{restrict:'A',transclude:'element',terminal:!0,priority:600,link:function link(Je,Qe,Be,Ue,Me){var Ve,We;Je.$watchCollection(Be.ngAnimateSwap||Be['for'],function(Ye){Ve&&Le.leave(Ve),We&&(We.$destroy(),We=null),(Ye||0===Ye)&&(We=Je.$new(),Me(We,function(_e){Ve=_e,Le.enter(_e,null,Qe)}))})}}}]).directive('ngAnimateChildren',['$interpolate',function(Le){return{link:function link(He,Je,Qe){function Be(Me){Me='on'===Me||'true'===Me,Je.data(V,Me)}var Ue=Qe.ngAnimateChildren;Re(Ue)&&0===Ue.length?Je.data(V,!0):(Be(Le(Ue)(He)),Qe.$observe('ngAnimateChildren',Be))}}}]).factory('$$rAFScheduler',['$$rAF',function(Le){function He(Ue){Qe=Qe.concat(Ue),Je()}function Je(){if(Qe.length){for(var Ue=Qe.shift(),Me=0;Me<Ue.length;Me++)Ue[Me]();Be||Le(function(){Be||Je()})}}var Qe,Be;return Qe=He.queue=[],He.waitUntilQuiet=function(Ue){Be&&Be(),Be=Le(function(){Be=null,Ue(),Je()})},He}]).provider('$$animateQueue',['$animateProvider',function(Le){function He(Ye){if(!Ye)return null;var _e=Ye.split(Ve),Ge=Object.create(null);return Ne(_e,function(Xe){Ge[Xe]=!0}),Ge}function Je(Ye,_e){if(Ye&&_e){var Ge=He(_e);return Ye.split(Ve).some(function(Xe){return Ge[Xe]})}}function Qe(Ye,_e,Ge){return We[Ye].some(function(Xe){return Xe(_e,Ge)})}function Be(Ye,_e){var Ge=0<(Ye.addClass||'').length,Xe=0<(Ye.removeClass||'').length;return _e?Ge&&Xe:Ge||Xe}var Ue=1,Me=2,Ve=' ',We=this.rules={skip:[],cancel:[],join:[]};We.join.push(function(Ye){return!Ye.structural&&Be(Ye)}),We.skip.push(function(Ye){return!Ye.structural&&!Be(Ye)}),We.skip.push(function(Ye,_e){return'leave'===_e.event&&Ye.structural}),We.skip.push(function(Ye,_e){return _e.structural&&_e.state===Me&&!Ye.structural}),We.cancel.push(function(Ye,_e){return _e.structural&&Ye.structural}),We.cancel.push(function(Ye,_e){return _e.state===Me&&Ye.structural}),We.cancel.push(function(Ye,_e){if(_e.structural)return!1;var Ge=Ye.addClass,Xe=Ye.removeClass,Ze=_e.addClass,ze=_e.removeClass;return qe(Ge)&&qe(Xe)||qe(Ze)&&qe(ze)?!1:Je(Ge,ze)||Je(Xe,Ze)}),this.$get=['$$rAF','$rootScope','$rootElement','$document','$$Map','$$animation','$$AnimateRunner','$templateRequest','$$jqLite','$$forceReflow','$$isDocumentHidden',function(Ye,_e,Ge,Xe,Ze,ze,et,tt,at,nt,st){function it(){var wt=!1;return function(Nt){wt?Nt():_e.$$postDigest(function(){wt=!0,Nt()})}}function ot(wt,Nt){return y(wt,Nt,{})}function rt(wt,Nt,Pt){var jt=[],Ot=yt[Pt];return Ot&&Ne(Ot,function(Et){St.call(Et.node,Nt)?jt.push(Et.callback):'leave'===Pt&&St.call(Et.node,wt)&&jt.push(Et.callback)}),jt}function lt(wt,Nt,Pt){var jt=u(Nt);return wt.filter(function(Ot){var Et=Ot.node===jt&&(!Pt||Ot.callback===Pt);return!Et})}function dt(wt,Nt){'close'!==wt||Nt.parentNode||xt.off(Nt)}function ut(wt,Nt,Pt){function jt(Gt,Xt,Zt,zt){Kt(function(){var ea=rt(qt,Rt,Xt);ea.length?Ye(function(){Ne(ea,function(ta){ta(It,Zt,zt)}),dt(Zt,Rt)}):dt(Zt,Rt)}),Gt.progress(Xt,Zt,zt)}function Ot(Gt){k(It,Et),Tt(It,Et),$(It,Et),Et.domOperation(),Ft.complete(!Gt)}var Et=xe(Pt),It=d(wt),Rt=D(It),qt=Rt&&Rt.parentNode;Et=f(Et);var Ft=new et,Kt=it();if(Pe(Et.addClass)&&(Et.addClass=Et.addClass.join(' ')),Et.addClass&&!Re(Et.addClass)&&(Et.addClass=null),Pe(Et.removeClass)&&(Et.removeClass=Et.removeClass.join(' ')),Et.removeClass&&!Re(Et.removeClass)&&(Et.removeClass=null),Et.from&&!Ie(Et.from)&&(Et.from=null),Et.to&&!Ie(Et.to)&&(Et.to=null),!gt||!Rt||!(vt||At)(Rt,Nt,Pt)||!bt(Rt,Et))return Ot(),Ft;var Lt=0<=['enter','move','leave'].indexOf(Nt),Ht=st(),Jt=Ht||$t.get(Rt),Qt=!Jt&&ft.get(Rt)||{},Bt=!!Qt.state;if(Jt||Bt&&Qt.state===Ue||(Jt=!ct(Rt,qt,Nt)),Jt)return Ht&&jt(Ft,Nt,'start'),Ot(),Ht&&jt(Ft,Nt,'close'),Ft;Lt&&mt(Rt);var Ut={structural:Lt,element:It,event:Nt,addClass:Et.addClass,removeClass:Et.removeClass,close:Ot,options:Et,runner:Ft};if(Bt){var Mt=Qe('skip',Ut,Qt);if(Mt)return Qt.state===Me?(Ot(),Ft):(y(It,Qt,Ut),Qt.runner);var Vt=Qe('cancel',Ut,Qt);if(!Vt){var Wt=Qe('join',Ut,Qt);if(Wt)if(Qt.state===Me)ot(It,Ut);else return A(It,Lt?Nt:null,Et),Nt=Ut.event=Qt.event,Et=y(It,Qt,Ut),Qt.runner}else if(Qt.state===Me)Qt.runner.end();else if(Qt.structural)Qt.close();else return y(It,Qt,Ut),Qt.runner}else ot(It,Ut);var Yt=Ut.structural;if(Yt||(Yt='animate'===Ut.event&&0<Object.keys(Ut.options.to||{}).length||Be(Ut)),!Yt)return Ot(),pt(Rt),Ft;var _t=(Qt.counter||0)+1;return Ut.counter=_t,ht(Rt,Ue,Ut),_e.$$postDigest(function(){It=d(wt);var Gt=ft.get(Rt),Xt=!Gt;Gt=Gt||{};var Zt=It.parent()||[],zt=0<Zt.length&&('animate'===Gt.event||Gt.structural||Be(Gt));if(Xt||Gt.counter!==_t||!zt)return Xt&&(Tt(It,Et),$(It,Et)),(Xt||Lt&&Gt.event!==Nt)&&(Et.domOperation(),Ft.end()),void(zt||pt(Rt));Nt=!Gt.structural&&Be(Gt,!0)?'setClass':Gt.event,ht(Rt,Me);var ea=ze(It,Nt,Gt.options);Ft.setHost(ea),jt(Ft,Nt,'start',{}),ea.done(function(ta){Ot(!ta);var na=ft.get(Rt);na&&na.counter===_t&&pt(Rt),jt(Ft,Nt,'close',{})})}),Ft}function mt(wt){var Nt=wt.querySelectorAll('['+Ae+']');Ne(Nt,function(Pt){var jt=parseInt(Pt.getAttribute(Ae),10),Ot=ft.get(Pt);if(Ot)switch(jt){case Me:Ot.runner.end();case Ue:ft.delete(Pt);}})}function pt(wt){wt.removeAttribute(Ae),ft.delete(wt)}function ct(wt,Nt){var jt=Xe[0].body,Ot=D(Ge),Et=wt===jt||'HTML'===wt.nodeName,It=wt===Ot,Rt=!1,qt=$t.get(wt),Ft,Kt=Fe.data(wt,ke);for(Kt&&(Nt=D(Kt));Nt&&(It||(It=Nt===Ot),Nt.nodeType===K);){var Lt=ft.get(Nt)||{};if(!Rt){var Ht=$t.get(Nt);if(!0===Ht&&!1!==qt){qt=!0;break}else!1===Ht&&(qt=!1);Rt=Lt.structural}if(qe(Ft)||!0===Ft){var Jt=Fe.data(Nt,V);je(Jt)&&(Ft=Jt)}if(Rt&&!1===Ft)break;if(Et||(Et=Nt===jt),Et&&It)break;if(!It&&(Kt=Fe.data(Nt,ke),Kt)){Nt=D(Kt);continue}Nt=Nt.parentNode}var Qt=(!Rt||Ft)&&!0!==qt;return Qt&&It&&Et}function ht(wt,Nt,Pt){Pt=Pt||{},Pt.state=Nt,wt.setAttribute(Ae,Nt);var jt=ft.get(wt),Ot=jt?we(jt,Pt):Pt;ft.set(wt,Ot)}var ft=new Ze,$t=new Ze,gt=null,Ct=_e.$watch(function(){return 0===tt.totalPendingRequests},function(wt){wt&&(Ct(),_e.$$postDigest(function(){_e.$$postDigest(function(){null===gt&&(gt=!0)})}))}),yt=Object.create(null),vt=Le.customFilter(),Dt=Le.classNameFilter(),At=function(){return!0},bt=Dt?function(wt,Nt){var Pt=[wt.getAttribute('class'),Nt.addClass,Nt.removeClass].join(' ');return Dt.test(Pt)}:At,Tt=h(at),St=e.Node.prototype.contains||function(wt){return this===wt||!!(16&this.compareDocumentPosition(wt))},xt={on:function on(wt,Nt,Pt){var jt=u(Nt);yt[wt]=yt[wt]||[],yt[wt].push({node:jt,callback:Pt}),Fe(Nt).on('$destroy',function(){var Ot=ft.get(jt);Ot||xt.off(wt,Nt,Pt)})},off:function off(wt,Nt,Pt){if(1===arguments.length&&!Re(arguments[0])){for(var jt in Nt=arguments[0],yt)yt[jt]=lt(yt[jt],Nt);return}var Ot=yt[wt];Ot&&(yt[wt]=1===arguments.length?null:lt(Ot,Nt,Pt))},pin:function pin(wt,Nt){n(Oe(wt),'element','not an element'),n(Oe(Nt),'parentElement','not an element'),wt.data(ke,Nt)},push:function push(wt,Nt,Pt,jt){return Pt=Pt||{},Pt.domOperation=jt,ut(wt,Nt,Pt)},enabled:function enabled(wt,Nt){var Pt=arguments.length;if(0===Pt)Nt=!!gt;else{var jt=Oe(wt);if(!jt)Nt=gt=!!wt;else{var Ot=D(wt);1===Pt?Nt=!$t.get(Ot):$t.set(Ot,!Nt)}}return Nt}};return xt}]}]).provider('$$animation',['$animateProvider',function(){function He(Ve,We){Ve.data(Me,We)}function Je(Ve){Ve.removeData(Me)}function Qe(Ve){return Ve.data(Me)}var Be='ng-animate-ref',Ue=this.drivers=[],Me='$$animationRunner';this.$get=['$$jqLite','$rootScope','$injector','$$AnimateRunner','$$Map','$$rAFScheduler',function(Ve,We,Ye,_e,Ge,Xe){function Ze(tt){function at(lt){if(lt.processed)return lt;lt.processed=!0;var dt=lt.domNode,ut=dt.parentNode;ot.set(dt,lt);for(var mt;ut;){if(mt=ot.get(ut),mt){mt.processed||(mt=at(mt));break}ut=ut.parentNode}return(mt||st).children.push(lt),lt}var st={children:[]},it,ot=new Ge;for(it=0;it<tt.length;it++){var rt=tt[it];ot.set(rt.domNode,tt[it]={domNode:rt.domNode,fn:rt.fn,children:[]})}for(it=0;it<tt.length;it++)at(tt[it]);return function(lt){var mt,dt=[],ut=[];for(mt=0;mt<lt.children.length;mt++)ut.push(lt.children[mt]);var pt=ut.length,ct=0,ht=[];for(mt=0;mt<ut.length;mt++){var ft=ut[mt];0>=pt&&(pt=ct,ct=0,dt.push(ht),ht=[]),ht.push(ft.fn),ft.children.forEach(function($t){ct++,ut.push($t)}),pt--}return ht.length&&dt.push(ht),dt}(st)}var ze=[],et=h(Ve);return function(tt,at,nt){function st(gt){var yt=gt.hasAttribute(Be)?[gt]:gt.querySelectorAll('['+Be+']'),vt=[];return Ne(yt,function(Dt){var At=Dt.getAttribute(Be);At&&At.length&&vt.push(Dt)}),vt}function it(gt){var Ct=[],yt={};Ne(gt,function(At,kt){var bt=At.element,Tt=D(bt),St=At.event,xt=0<=['enter','move'].indexOf(St),wt=At.structural?st(Tt):[];if(wt.length){var Nt=xt?'to':'from';Ne(wt,function(Pt){var jt=Pt.getAttribute(Be);yt[jt]=yt[jt]||{},yt[jt][Nt]={animationID:kt,element:Fe(Pt)}})}else Ct.push(At)});var vt={},Dt={};return Ne(yt,function(At){var bt=At.from,Tt=At.to;if(!bt||!Tt){var St=bt?bt.animationID:Tt.animationID,xt=St.toString();return void(vt[xt]||(vt[xt]=!0,Ct.push(gt[St])))}var wt=gt[bt.animationID],Nt=gt[Tt.animationID],Pt=bt.animationID.toString();if(!Dt[Pt]){var jt=Dt[Pt]={structural:!0,beforeStart:function beforeStart(){wt.beforeStart(),Nt.beforeStart()},close:function close(){wt.close(),Nt.close()},classes:ot(wt.classes,Nt.classes),from:wt,to:Nt,anchors:[]};jt.classes.length?Ct.push(jt):(Ct.push(wt),Ct.push(Nt))}Dt[Pt].anchors.push({out:bt.element,'in':Tt.element})}),Ct}function ot(gt,Ct){gt=gt.split(' '),Ct=Ct.split(' ');for(var Dt,yt=[],vt=0;vt<gt.length;vt++)if(Dt=gt[vt],'ng-'!==Dt.substring(0,3))for(var At=0;At<Ct.length;At++)if(Dt===Ct[At]){yt.push(Dt);break}return yt.join(' ')}function rt(gt){for(var Ct=Ue.length-1;0<=Ct;Ct--){var yt=Ue[Ct],vt=Ye.get(yt),Dt=vt(gt);if(Dt)return Dt}}function dt(gt,Ct){function yt(vt){var Dt=Qe(vt);Dt&&Dt.setHost(Ct)}gt.from&&gt.to?(yt(gt.from.element),yt(gt.to.element)):yt(gt.element)}function ut(){var gt=Qe(tt);gt&&('leave'!==at||!nt.$$domOperationFired)&&gt.end()}function mt(gt){tt.off('$destroy',ut),Je(tt),et(tt,nt),$(tt,nt),nt.domOperation(),ft&&Ve.removeClass(tt,ft),tt.removeClass(M),ct.complete(!gt)}nt=f(nt);var pt=0<=['enter','move','leave'].indexOf(at),ct=new _e({end:function end(){mt()},cancel:function cancel(){mt(!0)}});if(!Ue.length)return mt(),ct;He(tt,ct);var ht=s(tt.attr('class'),s(nt.addClass,nt.removeClass)),ft=nt.tempClasses;ft&&(ht+=' '+ft,nt.tempClasses=null);var $t;return(pt&&($t='ng-'+at+'-prepare',Ve.addClass(tt,$t)),ze.push({element:tt,classes:ht,event:at,structural:pt,options:nt,beforeStart:function(){tt.addClass(M),ft&&Ve.addClass(tt,ft),$t&&(Ve.removeClass(tt,$t),$t=null)},close:mt}),tt.on('$destroy',ut),1<ze.length)?ct:(We.$$postDigest(function(){var gt=[];Ne(ze,function(vt){Qe(vt.element)?gt.push(vt):vt.close()}),ze.length=0;var Ct=it(gt),yt=[];Ne(Ct,function(vt){yt.push({domNode:D(vt.from?vt.from.element:vt.element),fn:function(){vt.beforeStart();var At,kt=vt.close,bt=vt.anchors?vt.from.element||vt.to.element:vt.element;if(Qe(bt)){var Tt=rt(vt);Tt&&(At=Tt.start)}if(!At)kt();else{var St=At();St.done(function(xt){kt(!xt)}),dt(vt,St)}}})}),Xe(Ze(yt))}),ct)}}]}]).provider('$animateCss',['$animateProvider',function(){var He=q(),Je=q();this.$get=['$window','$$jqLite','$$AnimateRunner','$timeout','$$forceReflow','$sniffer','$$rAFScheduler','$$animateQueue',function(Qe,Be,Ue,Me,Ve,We,Ye,_e){function Ge(st,it){var ot='$$ngAnimateParentKey',rt=st.parentNode,lt=rt[ot]||(rt[ot]=++at);return lt+'-'+st.getAttribute('class')+'-'+it}function Xe(st,it,ot,rt){var lt=He.get(ot);return lt||(lt=O(Qe,st,rt),'infinite'===lt.animationIterationCount&&(lt.animationIterationCount=1)),He.put(ot,lt),lt}function Ze(st,it,ot,rt){var lt;if(0<He.count(ot)&&(lt=Je.get(ot),!lt)){var dt=r(it,'-stagger');Be.addClass(st,dt),lt=O(Qe,st,rt),lt.animationDuration=Math.max(lt.animationDuration,0),lt.transitionDuration=Math.max(lt.transitionDuration,0),Be.removeClass(st,dt),Je.put(ot,lt)}return lt||{}}function ze(st){nt.push(st),Ye.waitUntilQuiet(function(){He.flush(),Je.flush();for(var it=Ve(),ot=0;ot<nt.length;ot++)nt[ot](it);nt.length=0})}function et(st,it,ot){var rt=Xe(st,it,ot,$e),lt=rt.animationDelay,dt=rt.transitionDelay;return rt.maxDelay=lt&&dt?Math.max(lt,dt):lt||dt,rt.maxDuration=Math.max(rt.animationDuration*rt.animationIterationCount,rt.transitionDuration),rt}var tt=h(Be),at=0,nt=[];return function(it,ot){function rt(){dt()}function lt(){dt(!0)}function dt(zt){if(!(yt||Dt&&vt)){yt=!0,vt=!1,ct.$$skipPreparationClasses||Be.removeClass(it,It),Be.removeClass(it,qt),S(ft,!1),T(ft,!1),Ne($t,function(ta){ft.style[ta[0]]=''}),tt(it,ct),$(it,ct),Object.keys(ht).length&&Ne(ht,function(ta,na){ta?ft.style.setProperty(na,ta):ft.style.removeProperty(na)}),ct.onDone&&ct.onDone(),Nt.length&&it.off(Nt.join(' '),pt);var ea=it.data(pe);ea&&(Me.cancel(ea[0].timer),it.removeData(pe)),At&&At.complete(!zt)}}function ut(zt){Gt.blockTransition&&T(ft,zt),Gt.blockKeyframeAnimation&&S(ft,!!zt)}function mt(){return At=new Ue({end:rt,cancel:lt}),ze(Ke),dt(),{$$willAnimate:!1,start:function start(){return At},end:rt}}function pt(zt){zt.stopPropagation();var ea=zt.originalEvent||zt,ta=ea.$manualTimeStamp||Date.now(),na=parseFloat(ea.elapsedTime.toFixed(3));Math.max(ta-wt,0)>=Tt&&na>=St&&(Dt=!0,dt())}function Zt(){function zt(){if(!yt){if(ut(!1),Ne($t,function(pa){var ca=pa[0],ha=pa[1];ft.style[ca]=ha}),tt(it,ct),Be.addClass(it,qt),Gt.recalculateTimingStyles){if(Rt=ft.getAttribute('class')+' '+It,Lt=Ge(ft,Rt),Yt=et(ft,Rt,Lt),_t=Yt.maxDelay,bt=Math.max(_t,0),St=Yt.maxDuration,0===St)return void dt();Gt.hasTransitions=0<Yt.transitionDuration,Gt.hasAnimations=0<Yt.animationDuration}if(Gt.applyAnimationDelay&&(_t='boolean'!=typeof ct.delay&&I(ct.delay)?parseFloat(ct.delay):_t,bt=Math.max(_t,0),Yt.animationDelay=_t,Xt=P(_t,!0),$t.push(Xt),ft.style[Xt[0]]=Xt[1]),Tt=bt*ce,xt=St*ce,ct.easing){var sa,ia=ct.easing;Gt.hasTransitions&&(sa=Y+te,$t.push([sa,ia]),ft.style[sa]=ia),Gt.hasAnimations&&(sa=G+te,$t.push([sa,ia]),ft.style[sa]=ia)}Yt.transitionDuration&&Nt.push(_),Yt.animationDuration&&Nt.push(X),wt=Date.now();var oa=Tt+1.5*xt,ra=wt+oa,la=it.data(pe)||[],da=!0;if(la.length){var ua=la[0];da=ra>ua.expectedEndTime,da?Me.cancel(ua.timer):la.push(dt)}if(da){var ma=Me(ea,oa,!1);la[0]={timer:ma,expectedEndTime:ra},la.push(dt),it.data(pe,la)}Nt.length&&it.on(Nt.join(' '),pt),ct.to&&(ct.cleanupStyles&&F(ht,ft,Object.keys(ct.to)),C(it,ct))}}function ea(){var sa=it.data(pe);if(sa){for(var ia=1;ia<sa.length;ia++)sa[ia]();it.removeData(pe)}}if(!yt){if(!ft.parentNode)return void dt();var ta=function(sa){if(!!Dt)vt&&sa&&(vt=!1,dt());else if(vt=!sa,Yt.animationDuration){var ia=S(ft,vt);vt?$t.push(ia):l($t,ia)}},na=0<Vt&&(Yt.transitionDuration&&0===Ht.transitionDuration||Yt.animationDuration&&0===Ht.animationDuration)&&Math.max(Ht.animationDelay,Ht.transitionDelay);na?Me(zt,Math.floor(na*Vt*ce),!1):zt(),kt.resume=function(){ta(!0)},kt.pause=function(){ta(!1)}}}var ct=ot||{};ct.$$prepared||(ct=f(xe(ct)));var ht={},ft=D(it);if(!ft||!ft.parentNode||!_e.enabled())return mt();var yt,vt,Dt,At,kt,bt,Tt,St,xt,wt,$t=[],gt=it.attr('class'),Ct=o(ct),Nt=[];if(0===ct.duration||!We.animations&&!We.transitions)return mt();var Pt=ct.event&&Pe(ct.event)?ct.event.join(' '):ct.event,jt=Pt&&ct.structural,Ot='',Et='';jt?Ot=r(Pt,Q,!0):Pt&&(Ot=Pt),ct.addClass&&(Et+=r(ct.addClass,H)),ct.removeClass&&(Et.length&&(Et+=' '),Et+=r(ct.removeClass,J)),ct.applyClassesEarly&&Et.length&&tt(it,ct);var It=[Ot,Et].join(' ').trim(),Rt=gt+' '+It,qt=r(It,'-active'),Ft=Ct.to&&0<Object.keys(Ct.to).length,Kt=0<(ct.keyframeStyle||'').length;if(!Kt&&!Ft&&!It)return mt();var Lt,Ht;if(0<ct.stagger){var Jt=parseFloat(ct.stagger);Ht={transitionDelay:Jt,animationDelay:Jt,transitionDuration:0,animationDuration:0}}else Lt=Ge(ft,Rt),Ht=Ze(ft,It,Lt,ge);ct.$$skipPreparationClasses||Be.addClass(it,It);var Qt;if(ct.transitionStyle){var Bt=[Y,ct.transitionStyle];x(ft,Bt),$t.push(Bt)}if(0<=ct.duration){Qt=0<ft.style[Y].length;var Ut=R(ct.duration,Qt);x(ft,Ut),$t.push(Ut)}if(ct.keyframeStyle){var Mt=[G,ct.keyframeStyle];x(ft,Mt),$t.push(Mt)}var Vt=Ht?0<=ct.staggerIndex?ct.staggerIndex:He.count(Lt):0,Wt=0===Vt;Wt&&!ct.skipBlocking&&T(ft,9999);var Yt=et(ft,Rt,Lt),_t=Yt.maxDelay;bt=Math.max(_t,0),St=Yt.maxDuration;var Gt={};if(Gt.hasTransitions=0<Yt.transitionDuration,Gt.hasAnimations=0<Yt.animationDuration,Gt.hasTransitionAll=Gt.hasTransitions&&'all'===Yt.transitionProperty,Gt.applyTransitionDuration=Ft&&(Gt.hasTransitions&&!Gt.hasTransitionAll||Gt.hasAnimations&&!Gt.hasTransitions),Gt.applyAnimationDuration=ct.duration&&Gt.hasAnimations,Gt.applyTransitionDelay=I(ct.delay)&&(Gt.applyTransitionDuration||Gt.hasTransitions),Gt.applyAnimationDelay=I(ct.delay)&&Gt.hasAnimations,Gt.recalculateTimingStyles=0<Et.length,(Gt.applyTransitionDuration||Gt.applyAnimationDuration)&&(St=ct.duration?parseFloat(ct.duration):St,Gt.applyTransitionDuration&&(Gt.hasTransitions=!0,Yt.transitionDuration=St,Qt=0<ft.style[Y+z].length,$t.push(R(St,Qt))),Gt.applyAnimationDuration&&(Gt.hasAnimations=!0,Yt.animationDuration=St,$t.push(N(St)))),0===St&&!Gt.recalculateTimingStyles)return mt();if(null!=ct.delay){var Xt;'boolean'!=typeof ct.delay&&(Xt=parseFloat(ct.delay),bt=Math.max(Xt,0)),Gt.applyTransitionDelay&&$t.push(P(Xt)),Gt.applyAnimationDelay&&$t.push(P(Xt,!0))}return null==ct.duration&&0<Yt.transitionDuration&&(Gt.recalculateTimingStyles=Gt.recalculateTimingStyles||Wt),Tt=bt*ce,xt=St*ce,ct.skipBlocking||(Gt.blockTransition=0<Yt.transitionDuration,Gt.blockKeyframeAnimation=0<Yt.animationDuration&&0<Ht.animationDelay&&0===Ht.animationDuration),ct.from&&(ct.cleanupStyles&&F(ht,ft,Object.keys(ct.from)),g(it,ct)),Gt.blockTransition||Gt.blockKeyframeAnimation?ut(St):!ct.skipBlocking&&T(ft,!1),{$$willAnimate:!0,end:rt,start:function start(){if(!yt)return kt={end:rt,cancel:lt,resume:null,pause:null},At=new Ue(kt),ze(Zt),At}}}}]}]).provider('$$animateCssDriver',['$$animationProvider',function(Le){function He(Me){return Me.parentNode&&11===Me.parentNode.nodeType}Le.drivers.push('$$animateCssDriver');var Je='ng-animate-shim',Be='ng-anchor-out';this.$get=['$animateCss','$rootScope','$$AnimateRunner','$rootElement','$sniffer','$$jqLite','$document',function(Me,Ve,We,Ye,_e,Ge,Xe){function Ze(ot){return ot.replace(/\bng-\S+\b/g,'')}function ze(ot,rt){return Re(ot)&&(ot=ot.split(' ')),Re(rt)&&(rt=rt.split(' ')),ot.filter(function(lt){return-1===rt.indexOf(lt)}).join(' ')}function et(ot,rt,lt){function dt(yt){var vt={},Dt=D(yt).getBoundingClientRect();return Ne(['width','height','top','left'],function(At){var kt=Dt[At];'top'===At?kt+=nt.scrollTop:'left'===At?kt+=nt.scrollLeft:void 0,vt[At]=Math.floor(kt)+'px'}),vt}function mt(yt){return yt.attr('class')||''}function pt(){var yt=Ze(mt(lt)),vt=ze(yt,ft),Dt=ze(ft,yt),At=Me(ht,{to:dt(lt),addClass:'ng-anchor-in'+' '+vt,removeClass:Be+' '+Dt,delay:!0});return At.$$willAnimate?At:null}function ct(){ht.remove(),rt.removeClass(Je),lt.removeClass(Je)}var ht=Fe(D(rt).cloneNode(!0)),ft=Ze(mt(ht));rt.addClass(Je),lt.addClass(Je),ht.addClass('ng-anchor'),it.append(ht);var $t,gt=function(){var yt=Me(ht,{addClass:Be,delay:!0,from:dt(rt)});return yt.$$willAnimate?yt:null}();if(!gt&&($t=pt(),!$t))return ct();var Ct=gt||$t;return{start:function start(){function yt(){Dt&&Dt.end()}var vt,Dt=Ct.start();return Dt.done(function(){return Dt=null,!$t&&($t=pt(),$t)?(Dt=$t.start(),Dt.done(function(){Dt=null,ct(),vt.complete()}),Dt):void(ct(),vt.complete())}),vt=new We({end:yt,cancel:yt}),vt}}}function tt(ot,rt,lt,dt){var ut=at(ot,Ke),mt=at(rt,Ke),pt=[];return Ne(dt,function(ct){var ht=ct.out,ft=ct['in'],$t=et(lt,ht,ft);$t&&pt.push($t)}),ut||mt||0!==pt.length?{start:function start(){function ct(){Ne(ht,function($t){$t.end()})}var ht=[];ut&&ht.push(ut.start()),mt&&ht.push(mt.start()),Ne(pt,function($t){ht.push($t.start())});var ft=new We({end:ct,cancel:ct});return We.all(ht,function($t){ft.complete($t)}),ft}}:void 0}function at(ot){var rt=ot.element,lt=ot.options||{};ot.structural&&(lt.event=ot.event,lt.structural=!0,lt.applyClassesEarly=!0,'leave'===ot.event&&(lt.onDone=lt.domOperation)),lt.preparationClasses&&(lt.event=w(lt.event,lt.preparationClasses));var dt=Me(rt,lt);return dt.$$willAnimate?dt:null}if(!_e.animations&&!_e.transitions)return Ke;var nt=Xe[0].body,st=D(Ye),it=Fe(He(st)||nt.contains(st)?st:nt);return function(rt){return rt.from&&rt.to?tt(rt.from,rt.to,rt.classes,rt.anchors):at(rt)}}]}]).provider('$$animateJs',['$animateProvider',function(Le){this.$get=['$injector','$$AnimateRunner','$$jqLite',function(He,Je,Qe){function Be(Me){Me=Pe(Me)?Me:Me.split(' ');for(var Ve=[],We={},Ye=0;Ye<Me.length;Ye++){var _e=Me[Ye],Ge=Le.$$registeredAnimations[_e];Ge&&!We[_e]&&(Ve.push(He.get(Ge)),We[_e]=!0)}return Ve}var Ue=h(Qe);return function(Me,Ve,We,Ye){function _e(){Ye.domOperation(),Ue(Me,Ye)}function Ge(){et=!0,_e(),$(Me,Ye)}function Xe(dt,ut,mt,pt,ct){var ht;switch(mt){case'animate':ht=[ut,pt.from,pt.to,ct];break;case'setClass':ht=[ut,tt,at,ct];break;case'addClass':ht=[ut,tt,ct];break;case'removeClass':ht=[ut,at,ct];break;default:ht=[ut,ct];}ht.push(pt);var ft=dt.apply(dt,ht);if(ft)if(Ee(ft.start)&&(ft=ft.start()),ft instanceof Je)ft.done(ct);else if(Ee(ft))return ft;return Ke}function Ze(dt,ut,mt,pt,ct){var ht=[];return Ne(pt,function(ft){var $t=ft[ct];$t&&ht.push(function(){var gt,Ct,yt=!1,vt=function(Dt){yt||(yt=!0,(Ct||Ke)(Dt),gt.complete(!Dt))};return gt=new Je({end:function end(){vt()},cancel:function cancel(){vt(!0)}}),Ct=Xe($t,dt,ut,mt,function(Dt){vt(!1===Dt)}),gt})}),ht}function ze(dt,ut,mt,pt,ct){var ht=Ze(dt,ut,mt,pt,ct);if(0===ht.length){var ft,$t;'beforeSetClass'===ct?(ft=Ze(dt,'removeClass',mt,pt,'beforeRemoveClass'),$t=Ze(dt,'addClass',mt,pt,'beforeAddClass')):'setClass'==ct&&(ft=Ze(dt,'removeClass',mt,pt,'removeClass'),$t=Ze(dt,'addClass',mt,pt,'addClass')),ft&&(ht=ht.concat(ft)),$t&&(ht=ht.concat($t))}return 0===ht.length?void 0:function(Ct){var yt=[];return ht.length&&Ne(ht,function(vt){yt.push(vt())}),yt.length?Je.all(yt,Ct):Ct(),function(Dt){Ne(yt,function(At){Dt?At.cancel():At.end()})}}}var et=!1;3===arguments.length&&Ie(We)&&(Ye=We,We=null),Ye=f(Ye),We||(We=Me.attr('class')||'',Ye.addClass&&(We+=' '+Ye.addClass),Ye.removeClass&&(We+=' '+Ye.removeClass));var tt=Ye.addClass,at=Ye.removeClass,nt=Be(We),st,it;if(nt.length){var ot,rt;'leave'===Ve?(rt='leave',ot='afterLeave'):(rt='before'+Ve.charAt(0).toUpperCase()+Ve.substr(1),ot=Ve),'enter'!==Ve&&'move'!==Ve&&(st=ze(Me,Ve,Ye,nt,rt)),it=ze(Me,Ve,Ye,nt,ot)}if(st||it){var lt;return{$$willAnimate:!0,end:function end(){return lt?lt.end():(Ge(),lt=new Je,lt.complete(!0)),lt},start:function start(){function dt(ct){Ge(ct),lt.complete(ct)}function ut(ct){et||((mt||Ke)(ct),dt(ct))}if(lt)return lt;lt=new Je;var mt,pt=[];return st&&pt.push(function(ct){mt=st(ct)}),pt.length?pt.push(function(ct){_e(),ct(!0)}):_e(),it&&pt.push(function(ct){mt=it(ct)}),lt.setHost({end:function end(){ut()},cancel:function cancel(){ut(!0)}}),Je.chain(pt,dt),lt}}}}}]}]).provider('$$animateJsDriver',['$$animationProvider',function(Le){Le.drivers.push('$$animateJsDriver'),this.$get=['$$animateJs','$$AnimateRunner',function(He,Je){function Qe(Be){var Ue=Be.element,Me=Be.event,Ve=Be.options,We=Be.classes;return He(Ue,Me,We,Ve)}return function(Ue){if(Ue.from&&Ue.to){var Me=Qe(Ue.from),Ve=Qe(Ue.to);return Me||Ve?{start:function start(){function We(){return function(){Ne(_e,function(Xe){Xe.end()})}}var _e=[];Me&&_e.push(Me.start()),Ve&&_e.push(Ve.start()),Je.all(_e,function(Xe){Ge.complete(Xe)});var Ge=new Je({end:We(),cancel:We()});return Ge}}:void 0}return Qe(Ue)}}]}])})(window,window.angular);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment