diff options
Diffstat (limited to 'libs/bower_components/angular-animate/angular-animate.js')
-rw-r--r-- | libs/bower_components/angular-animate/angular-animate.js | 668 |
1 files changed, 406 insertions, 262 deletions
diff --git a/libs/bower_components/angular-animate/angular-animate.js b/libs/bower_components/angular-animate/angular-animate.js index 7c0677e261..eceab4f477 100644 --- a/libs/bower_components/angular-animate/angular-animate.js +++ b/libs/bower_components/angular-animate/angular-animate.js @@ -1,23 +1,9 @@ /** - * @license AngularJS v1.4.10 - * (c) 2010-2015 Google, Inc. http://angularjs.org + * @license AngularJS v1.6.5 + * (c) 2010-2017 Google, Inc. http://angularjs.org * License: MIT */ -(function(window, angular, undefined) {'use strict'; - -/* jshint ignore:start */ -var noop = angular.noop; -var copy = angular.copy; -var extend = angular.extend; -var jqLite = angular.element; -var forEach = angular.forEach; -var isArray = angular.isArray; -var isString = angular.isString; -var isObject = angular.isObject; -var isUndefined = angular.isUndefined; -var isDefined = angular.isDefined; -var isFunction = angular.isFunction; -var isElement = angular.isElement; +(function(window, angular) {'use strict'; var ELEMENT_NODE = 1; var COMMENT_NODE = 8; @@ -43,7 +29,7 @@ var CSS_PREFIX = '', TRANSITION_PROP, TRANSITIONEND_EVENT, ANIMATION_PROP, ANIMA // 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 (isUndefined(window.ontransitionend) && isDefined(window.onwebkittransitionend)) { +if ((window.ontransitionend === undefined) && (window.onwebkittransitionend !== undefined)) { CSS_PREFIX = '-webkit-'; TRANSITION_PROP = 'WebkitTransition'; TRANSITIONEND_EVENT = 'webkitTransitionEnd transitionend'; @@ -52,7 +38,7 @@ if (isUndefined(window.ontransitionend) && isDefined(window.onwebkittransitionen TRANSITIONEND_EVENT = 'transitionend'; } -if (isUndefined(window.onanimationend) && isDefined(window.onwebkitanimationend)) { +if ((window.onanimationend === undefined) && (window.onwebkitanimationend !== undefined)) { CSS_PREFIX = '-webkit-'; ANIMATION_PROP = 'WebkitAnimation'; ANIMATIONEND_EVENT = 'webkitAnimationEnd animationend'; @@ -74,14 +60,10 @@ 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 isPromiseLike = function(p) { - return p && p.then ? true : false; -}; - var ngMinErr = angular.$$minErr('ng'); function assertArg(arg, name, reason) { if (!arg) { - throw ngMinErr('areq', "Argument '{0}' is {1}", (name || '?'), (reason || "required")); + throw ngMinErr('areq', 'Argument \'{0}\' is {1}', (name || '?'), (reason || 'required')); } return arg; } @@ -132,8 +114,7 @@ function stripCommentsFromElement(element) { if (element instanceof jqLite) { switch (element.length) { case 0: - return []; - break; + return element; case 1: // there is no point of stripping anything if the element @@ -146,7 +127,6 @@ function stripCommentsFromElement(element) { default: return jqLite(extractElementNode(element)); - break; } } @@ -159,7 +139,7 @@ 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) { + if (elm.nodeType === ELEMENT_NODE) { return elm; } } @@ -187,7 +167,7 @@ function applyAnimationClassesFactory($$jqLite) { $$removeClass($$jqLite, element, options.removeClass); options.removeClass = null; } - } + }; } function prepareAnimationOptions(options) { @@ -290,10 +270,10 @@ function resolveElementClasses(existing, toAdd, toRemove) { var prop, allow; if (val === ADD_CLASS) { prop = 'addClass'; - allow = !existing[klass]; + allow = !existing[klass] || existing[klass + REMOVE_CLASS_SUFFIX]; } else if (val === REMOVE_CLASS) { prop = 'removeClass'; - allow = existing[klass]; + allow = existing[klass] || existing[klass + ADD_CLASS_SUFFIX]; } if (allow) { if (classes[prop].length) { @@ -323,7 +303,7 @@ function resolveElementClasses(existing, toAdd, toRemove) { } function getDomNode(element) { - return (element instanceof angular.element) ? element[0] : element; + return (element instanceof jqLite) ? element[0] : element; } function applyGeneratedPreparationClasses(element, event, options) { @@ -396,7 +376,7 @@ var $$rAFSchedulerFactory = ['$$rAF', function($$rAF) { queue = scheduler.queue = []; /* waitUntilQuiet does two things: - * 1. It will run the FINAL `fn` value only when an uncancelled RAF has passed through + * 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 @@ -443,7 +423,7 @@ var $$rAFSchedulerFactory = ['$$rAF', function($$rAF) { * 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 `ngAnimteChildren` is set, no child animations will run when the parent element is removed from the DOM (`leave` animation). + * 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`, @@ -452,7 +432,7 @@ var $$rAFSchedulerFactory = ['$$rAF', function($$rAF) { * @example * <example module="ngAnimateChildren" name="ngAnimateChildren" deps="angular-animate.js" animations="true"> <file name="index.html"> - <div ng-controller="mainController as main"> + <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> @@ -502,7 +482,7 @@ var $$rAFSchedulerFactory = ['$$rAF', function($$rAF) { </file> <file name="script.js"> angular.module('ngAnimateChildren', ['ngAnimate']) - .controller('mainController', function() { + .controller('MainController', function MainController() { this.animateChildren = false; this.enterElement = false; }); @@ -513,7 +493,7 @@ var $$AnimateChildrenDirective = ['$interpolate', function($interpolate) { return { link: function(scope, element, attrs) { var val = attrs.ngAnimateChildren; - if (angular.isString(val) && val.length === 0) { //empty attribute + 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 @@ -530,6 +510,8 @@ var $$AnimateChildrenDirective = ['$interpolate', function($interpolate) { }; }]; +/* exported $AnimateCssProvider */ + var ANIMATE_TIMER_KEY = '$$animateCss'; /** @@ -697,7 +679,7 @@ var ANIMATE_TIMER_KEY = '$$animateCss'; * ``` * * 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 stlyes may have been + * 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. * @@ -734,11 +716,11 @@ var ANIMATE_TIMER_KEY = '$$animateCss'; * * `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 occuring on the classes being added and removed.) + * `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 colapse and open animation). + * 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. @@ -747,7 +729,6 @@ var ANIMATE_TIMER_KEY = '$$animateCss'; * * `end` - This method will cancel the animation and remove all applied CSS classes and styles. */ var ONE_SECOND = 1000; -var BASE_TEN = 10; var ELAPSED_TIME_MAX_DECIMAL_PLACES = 3; var CLOSING_TIME_BUFFER = 1.5; @@ -791,7 +772,7 @@ function computeCssStyles($window, element, properties) { } // 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 zegative values to be used later on and not mistake this + // 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; @@ -809,7 +790,7 @@ function parseMaxTime(str) { 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') { + if (value.charAt(value.length - 1) === 's') { value = value.substring(0, value.length - 1); } value = parseFloat(value) || 0; @@ -877,7 +858,7 @@ function registerRestorableStyles(backup, node, properties) { }); } -var $AnimateCssProvider = ['$animateProvider', function($animateProvider) { +var $AnimateCssProvider = ['$animateProvider', /** @this */ function($animateProvider) { var gcsLookup = createLocalCacheLookup(); var gcsStaggerLookup = createLocalCacheLookup(); @@ -890,7 +871,7 @@ var $AnimateCssProvider = ['$animateProvider', function($animateProvider) { var parentCounter = 0; function gcsHashFn(node, extraClasses) { - var KEY = "$$ngAnimateParentKey"; + var KEY = '$$ngAnimateParentKey'; var parentNode = node.parentNode; var parentID = parentNode[KEY] || (parentNode[KEY] = ++parentCounter); return parentID + '-' + node.getAttribute('class') + '-' + extraClasses; @@ -907,7 +888,7 @@ var $AnimateCssProvider = ['$animateProvider', function($animateProvider) { } // we keep putting this in multiple times even though the value and the cacheKey are the same - // because we're keeping an interal tally of how many duplicate animations are detected. + // because we're keeping an internal tally of how many duplicate animations are detected. gcsLookup.put(cacheKey, timings); return timings; } @@ -941,7 +922,6 @@ var $AnimateCssProvider = ['$animateProvider', function($animateProvider) { return stagger || {}; } - var cancelLastRAFRequest; var rafWaitQueue = []; function waitUntilQuiet(callback) { rafWaitQueue.push(callback); @@ -1130,7 +1110,7 @@ var $AnimateCssProvider = ['$animateProvider', function($animateProvider) { var flags = {}; flags.hasTransitions = timings.transitionDuration > 0; flags.hasAnimations = timings.animationDuration > 0; - flags.hasTransitionAll = flags.hasTransitions && timings.transitionProperty == 'all'; + flags.hasTransitionAll = flags.hasTransitions && timings.transitionProperty === 'all'; flags.applyTransitionDuration = hasToStyles && ( (flags.hasTransitions && !flags.hasTransitionAll) || (flags.hasAnimations && !flags.hasTransitions)); @@ -1162,7 +1142,7 @@ var $AnimateCssProvider = ['$animateProvider', function($animateProvider) { if (options.delay != null) { var delayStyle; - if (typeof options.delay !== "boolean") { + 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); @@ -1240,7 +1220,7 @@ var $AnimateCssProvider = ['$animateProvider', function($animateProvider) { close(true); } - function close(rejected) { // jshint ignore:line + function close(rejected) { // if the promise has been called already then we shouldn't close // the animation again if (animationClosed || (animationCompleted && animationPaused)) return; @@ -1267,8 +1247,11 @@ var $AnimateCssProvider = ['$animateProvider', function($animateProvider) { if (Object.keys(restoreStyles).length) { forEach(restoreStyles, function(value, prop) { - value ? node.style.setProperty(prop, value) - : node.style.removeProperty(prop); + if (value) { + node.style.setProperty(prop, value); + } else { + node.style.removeProperty(prop); + } }); } @@ -1371,9 +1354,11 @@ var $AnimateCssProvider = ['$animateProvider', function($animateProvider) { animationPaused = !playAnimation; if (timings.animationDuration) { var value = blockKeyframeAnimations(node, animationPaused); - animationPaused - ? temporaryStyles.push(value) - : removeFromArray(temporaryStyles, value); + if (animationPaused) { + temporaryStyles.push(value); + } else { + removeFromArray(temporaryStyles, value); + } } } else if (animationPaused && playAnimation) { animationPaused = false; @@ -1381,9 +1366,9 @@ var $AnimateCssProvider = ['$animateProvider', function($animateProvider) { } }; - // checking the stagger duration prevents an accidently cascade of the CSS delay style + // 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 intential stagger delay style. + // 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)) @@ -1422,7 +1407,7 @@ var $AnimateCssProvider = ['$animateProvider', function($animateProvider) { $$jqLite.addClass(element, activeClasses); if (flags.recalculateTimingStyles) { - fullClassName = node.className + ' ' + preparationClasses; + fullClassName = node.getAttribute('class') + ' ' + preparationClasses; cacheKey = gcsHashFn(node, fullClassName); timings = computeTimings(node, fullClassName, cacheKey); @@ -1440,7 +1425,7 @@ var $AnimateCssProvider = ['$animateProvider', function($animateProvider) { } if (flags.applyAnimationDelay) { - relativeDelay = typeof options.delay !== "boolean" && truthyTimingValue(options.delay) + relativeDelay = typeof options.delay !== 'boolean' && truthyTimingValue(options.delay) ? parseFloat(options.delay) : relativeDelay; @@ -1532,7 +1517,7 @@ var $AnimateCssProvider = ['$animateProvider', function($animateProvider) { }]; }]; -var $$AnimateCssDriverProvider = ['$$animationProvider', function($$animationProvider) { +var $$AnimateCssDriverProvider = ['$$animationProvider', /** @this */ function($$animationProvider) { $$animationProvider.drivers.push('$$animateCssDriver'); var NG_ANIMATE_SHIM_CLASS_NAME = 'ng-animate-shim'; @@ -1556,13 +1541,11 @@ var $$AnimateCssDriverProvider = ['$$animationProvider', function($$animationPro var rootBodyElement = jqLite( // this is to avoid using something that exists outside of the body - // we also special case the doc fragement case because our unit test code + // 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 ); - var applyAnimationClasses = applyAnimationClassesFactory($$jqLite); - return function initDriverFn(animationDetails) { return animationDetails.from && animationDetails.to ? prepareFromToAnchorAnimation(animationDetails.from, @@ -1656,7 +1639,7 @@ var $$AnimateCssDriverProvider = ['$$animationProvider', function($$animationPro var coords = getDomNode(anchor).getBoundingClientRect(); // we iterate directly since safari messes up and doesn't return - // all the keys for the coods object when iterated + // all the keys for the coords object when iterated forEach(['width','height','top','left'], function(key) { var value = coords[key]; switch (key) { @@ -1804,7 +1787,7 @@ var $$AnimateCssDriverProvider = ['$$animationProvider', function($$animationPro // TODO(matsko): add documentation // by the time... -var $$AnimateJsProvider = ['$animateProvider', function($animateProvider) { +var $$AnimateJsProvider = ['$animateProvider', /** @this */ function($animateProvider) { this.$get = ['$injector', '$$AnimateRunner', '$$jqLite', function($injector, $$AnimateRunner, $$jqLite) { @@ -1843,7 +1826,7 @@ var $$AnimateJsProvider = ['$animateProvider', function($animateProvider) { var before, after; if (animations.length) { var afterFn, beforeFn; - if (event == 'leave') { + if (event === 'leave') { beforeFn = 'leave'; afterFn = 'afterLeave'; // TODO(matsko): get rid of this } else { @@ -2028,7 +2011,7 @@ var $$AnimateJsProvider = ['$animateProvider', function($animateProvider) { function packageAnimations(element, event, options, animations, fnName) { var operations = groupEventedAnimations(element, event, options, animations, fnName); if (operations.length === 0) { - var a,b; + var a, b; if (fnName === 'beforeSetClass') { a = groupEventedAnimations(element, 'removeClass', options, animations, 'beforeRemoveClass'); b = groupEventedAnimations(element, 'addClass', options, animations, 'beforeAddClass'); @@ -2056,11 +2039,19 @@ var $$AnimateJsProvider = ['$animateProvider', function($animateProvider) { }); } - runners.length ? $$AnimateRunner.all(runners, callback) : callback(); + if (runners.length) { + $$AnimateRunner.all(runners, callback); + } else { + callback(); + } return function endFn(reject) { forEach(runners, function(runner) { - reject ? runner.cancel() : runner.end(); + if (reject) { + runner.cancel(); + } else { + runner.end(); + } }); }; }; @@ -2070,7 +2061,7 @@ var $$AnimateJsProvider = ['$animateProvider', function($animateProvider) { function lookupAnimations(classes) { classes = isArray(classes) ? classes : classes.split(' '); var matches = [], flagMap = {}; - for (var i=0; i < classes.length; i++) { + for (var i = 0; i < classes.length; i++) { var klass = classes[i], animationFactory = $animateProvider.$$registeredAnimations[klass]; if (animationFactory && !flagMap[klass]) { @@ -2083,7 +2074,7 @@ var $$AnimateJsProvider = ['$animateProvider', function($animateProvider) { }]; }]; -var $$AnimateJsDriverProvider = ['$$animationProvider', function($$animationProvider) { +var $$AnimateJsDriverProvider = ['$$animationProvider', /** @this */ function($$animationProvider) { $$animationProvider.drivers.push('$$animateJsDriver'); this.$get = ['$$animateJs', '$$AnimateRunner', function($$animateJs, $$AnimateRunner) { return function initDriverFn(animationDetails) { @@ -2145,7 +2136,7 @@ var $$AnimateJsDriverProvider = ['$$animationProvider', function($$animationProv var NG_ANIMATE_ATTR_NAME = 'data-ng-animate'; var NG_ANIMATE_PIN_DATA = '$ngAnimatePin'; -var $$AnimateQueueProvider = ['$animateProvider', function($animateProvider) { +var $$AnimateQueueProvider = ['$animateProvider', /** @this */ function($animateProvider) { var PRE_DIGEST_STATE = 1; var RUNNING_STATE = 2; var ONE_SPACE = ' '; @@ -2179,9 +2170,9 @@ var $$AnimateQueueProvider = ['$animateProvider', function($animateProvider) { } } - function isAllowed(ruleType, element, currentAnimation, previousAnimation) { + function isAllowed(ruleType, currentAnimation, previousAnimation) { return rules[ruleType].some(function(fn) { - return fn(element, currentAnimation, previousAnimation); + return fn(currentAnimation, previousAnimation); }); } @@ -2191,40 +2182,45 @@ var $$AnimateQueueProvider = ['$animateProvider', function($animateProvider) { return and ? a && b : a || b; } - rules.join.push(function(element, newAnimation, currentAnimation) { + 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(element, newAnimation, currentAnimation) { + 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(element, newAnimation, currentAnimation) { + 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; + return currentAnimation.event === 'leave' && newAnimation.structural; }); - rules.skip.push(function(element, newAnimation, currentAnimation) { + 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(element, newAnimation, currentAnimation) { + 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(element, newAnimation, currentAnimation) { + 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(element, newAnimation, currentAnimation) { + 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; @@ -2238,13 +2234,15 @@ var $$AnimateQueueProvider = ['$animateProvider', function($animateProvider) { return hasMatchingClasses(nA, cR) || hasMatchingClasses(nR, cA); }); - this.$get = ['$$rAF', '$rootScope', '$rootElement', '$document', '$$HashMap', + this.$get = ['$$rAF', '$rootScope', '$rootElement', '$document', '$$Map', '$$animation', '$$AnimateRunner', '$templateRequest', '$$jqLite', '$$forceReflow', - function($$rAF, $rootScope, $rootElement, $document, $$HashMap, - $$animation, $$AnimateRunner, $templateRequest, $$jqLite, $$forceReflow) { + '$$isDocumentHidden', + function($$rAF, $rootScope, $rootElement, $document, $$Map, + $$animation, $$AnimateRunner, $templateRequest, $$jqLite, $$forceReflow, + $$isDocumentHidden) { - var activeAnimationsLookup = new $$HashMap(); - var disabledElementsLookup = new $$HashMap(); + var activeAnimationsLookup = new $$Map(); + var disabledElementsLookup = new $$Map(); var animationsEnabled = null; function postDigestTaskFactory() { @@ -2294,16 +2292,19 @@ var $$AnimateQueueProvider = ['$animateProvider', function($animateProvider) { } ); - var callbackRegistry = {}; + var callbackRegistry = Object.create(null); - // remember that the classNameFilter is set during the provider/config - // stage therefore we can optimize here and setup a helper function + // 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 isAnimatableClassName = !classNameFilter - ? function() { return true; } - : function(className) { - return classNameFilter.test(className); - }; + 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); @@ -2312,16 +2313,12 @@ var $$AnimateQueueProvider = ['$animateProvider', function($animateProvider) { } // IE9-11 has no method "contains" in SVG element and in Node.prototype. Bug #10259. - var contains = Node.prototype.contains || function(arg) { - // jshint bitwise: false + var contains = window.Node.prototype.contains || /** @this */ function(arg) { + // eslint-disable-next-line no-bitwise return this === arg || !!(this.compareDocumentPosition(arg) & 16); - // jshint bitwise: true }; - function findCallbacks(parent, element, event) { - var targetNode = getDomNode(element); - var targetParentNode = getDomNode(parent); - + function findCallbacks(targetParentNode, targetNode, event) { var matches = []; var entries = callbackRegistry[event]; if (entries) { @@ -2337,7 +2334,24 @@ var $$AnimateQueueProvider = ['$animateProvider', function($animateProvider) { return matches; } - return { + 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] || []; @@ -2345,24 +2359,36 @@ var $$AnimateQueueProvider = ['$animateProvider', function($animateProvider) { 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); - - 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; - }); - } }, pin: function(element, parentElement) { @@ -2396,14 +2422,13 @@ var $$AnimateQueueProvider = ['$animateProvider', function($animateProvider) { bool = animationsEnabled = !!element; } else { var node = getDomNode(element); - var recordExists = disabledElementsLookup.get(node); if (argCount === 1) { // (element) - Element getter - bool = !recordExists; + bool = !disabledElementsLookup.get(node); } else { // (element, bool) - Element setter - disabledElementsLookup.put(node, !bool); + disabledElementsLookup.set(node, !bool); } } } @@ -2412,18 +2437,17 @@ var $$AnimateQueueProvider = ['$animateProvider', function($animateProvider) { } }; - function queueAnimation(element, event, initialOptions) { + 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 node, parent; - element = stripCommentsFromElement(element); - if (element) { - node = getDomNode(element); - parent = element.parent(); - } + var element = stripCommentsFromElement(originalElement); + var node = getDomNode(element); + var parentNode = node && node.parentNode; options = prepareAnimationOptions(options); @@ -2458,44 +2482,45 @@ var $$AnimateQueueProvider = ['$animateProvider', function($animateProvider) { options.to = null; } - // there are situations where a directive issues an animation for - // a jqLite wrapper that contains only comment nodes... If this - // happens then there is no way we can perform an animation - if (!node) { - close(); - return runner; - } - - var className = [node.className, options.addClass, options.removeClass].join(' '); - if (!isAnimatableClassName(className)) { + // 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; - // this is a hard disable of all animations for the application or on - // the element itself, therefore there is no need to continue further - // past this point if not enabled + 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 = !animationsEnabled || $document[0].hidden || disabledElementsLookup.get(node); + 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(element, parent, event); + 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(element); + closeChildAnimations(node); } var newAnimation = { @@ -2510,7 +2535,7 @@ var $$AnimateQueueProvider = ['$animateProvider', function($animateProvider) { }; if (hasExistingAnimation) { - var skipAnimationFlag = isAllowed('skip', element, newAnimation, existingAnimation); + var skipAnimationFlag = isAllowed('skip', newAnimation, existingAnimation); if (skipAnimationFlag) { if (existingAnimation.state === RUNNING_STATE) { close(); @@ -2520,7 +2545,7 @@ var $$AnimateQueueProvider = ['$animateProvider', function($animateProvider) { return existingAnimation.runner; } } - var cancelAnimationFlag = isAllowed('cancel', element, newAnimation, existingAnimation); + var cancelAnimationFlag = isAllowed('cancel', newAnimation, existingAnimation); if (cancelAnimationFlag) { if (existingAnimation.state === RUNNING_STATE) { // this will end the animation right away and it is safe @@ -2542,7 +2567,7 @@ var $$AnimateQueueProvider = ['$animateProvider', function($animateProvider) { // 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', element, newAnimation, existingAnimation); + var joinAnimationFlag = isAllowed('join', newAnimation, existingAnimation); if (joinAnimationFlag) { if (existingAnimation.state === RUNNING_STATE) { normalizeAnimationDetails(element, newAnimation); @@ -2576,7 +2601,7 @@ var $$AnimateQueueProvider = ['$animateProvider', function($animateProvider) { if (!isValidAnimation) { close(); - clearElementAnimationState(element); + clearElementAnimationState(node); return runner; } @@ -2584,9 +2609,18 @@ var $$AnimateQueueProvider = ['$animateProvider', function($animateProvider) { var counter = (existingAnimation.counter || 0) + 1; newAnimation.counter = counter; - markElementAnimationState(element, PRE_DIGEST_STATE, newAnimation); + 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 || {}; @@ -2625,7 +2659,7 @@ var $$AnimateQueueProvider = ['$animateProvider', function($animateProvider) { // 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(element); + clearElementAnimationState(node); } return; @@ -2637,29 +2671,29 @@ var $$AnimateQueueProvider = ['$animateProvider', function($animateProvider) { ? 'setClass' : animationDetails.event; - markElementAnimationState(element, RUNNING_STATE); + 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(getDomNode(element)); + clearElementAnimationState(node); } notifyProgress(runner, event, 'close', {}); }); - - // this will update the runner's flow-control events based on - // the `realRunner` object. - runner.setHost(realRunner); - notifyProgress(runner, event, 'start', {}); }); return runner; function notifyProgress(runner, event, phase, data) { runInNextPostDigestOrNow(function() { - var callbacks = findCallbacks(parent, element, event); + 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 @@ -2669,13 +2703,16 @@ var $$AnimateQueueProvider = ['$animateProvider', function($animateProvider) { forEach(callbacks, function(callback) { callback(element, phase, data); }); + cleanupEventListeners(phase, node); }); + } else { + cleanupEventListeners(phase, node); } }); runner.progress(event, phase, data); } - function close(reject) { // jshint ignore:line + function close(reject) { clearGeneratedClasses(element, options); applyAnimationClasses(element, options); applyAnimationStyles(element, options); @@ -2684,11 +2721,10 @@ var $$AnimateQueueProvider = ['$animateProvider', function($animateProvider) { } } - function closeChildAnimations(element) { - var node = getDomNode(element); + function closeChildAnimations(node) { var children = node.querySelectorAll('[' + NG_ANIMATE_ATTR_NAME + ']'); forEach(children, function(child) { - var state = parseInt(child.getAttribute(NG_ANIMATE_ATTR_NAME)); + var state = parseInt(child.getAttribute(NG_ANIMATE_ATTR_NAME), 10); var animationDetails = activeAnimationsLookup.get(child); if (animationDetails) { switch (state) { @@ -2696,21 +2732,16 @@ var $$AnimateQueueProvider = ['$animateProvider', function($animateProvider) { animationDetails.runner.end(); /* falls through */ case PRE_DIGEST_STATE: - activeAnimationsLookup.remove(child); + activeAnimationsLookup.delete(child); break; } } }); } - function clearElementAnimationState(element) { - var node = getDomNode(element); + function clearElementAnimationState(node) { node.removeAttribute(NG_ANIMATE_ATTR_NAME); - activeAnimationsLookup.remove(node); - } - - function isMatchingElement(nodeOrElmA, nodeOrElmB) { - return getDomNode(nodeOrElmA) === getDomNode(nodeOrElmB); + activeAnimationsLookup.delete(node); } /** @@ -2720,54 +2751,54 @@ var $$AnimateQueueProvider = ['$animateProvider', function($animateProvider) { * c) the element is not a child of the body * d) the element is not a child of the $rootElement */ - function areAnimationsAllowed(element, parentElement, event) { - var bodyElement = jqLite($document[0].body); - var bodyElementDetected = isMatchingElement(element, bodyElement) || element[0].nodeName === 'HTML'; - var rootElementDetected = isMatchingElement(element, $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 elementDisabled = disabledElementsLookup.get(getDomNode(element)); - var parentHost = jqLite.data(element[0], NG_ANIMATE_PIN_DATA); + var parentHost = jqLite.data(node, NG_ANIMATE_PIN_DATA); if (parentHost) { - parentElement = parentHost; + parentNode = getDomNode(parentHost); } - parentElement = getDomNode(parentElement); - - while (parentElement) { - if (!rootElementDetected) { + 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 - rootElementDetected = isMatchingElement(parentElement, $rootElement); + rootNodeDetected = (parentNode === rootNode); } - if (parentElement.nodeType !== ELEMENT_NODE) { + if (parentNode.nodeType !== ELEMENT_NODE) { // no point in inspecting the #document element break; } - var details = activeAnimationsLookup.get(parentElement) || {}; + 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 parentElementDisabled = disabledElementsLookup.get(parentElement); + var parentNodeDisabled = disabledElementsLookup.get(parentNode); - if (parentElementDisabled === true && elementDisabled !== false) { + 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 (parentElementDisabled === false) { + } else if (parentNodeDisabled === false) { elementDisabled = false; } parentAnimationDetected = details.structural; } if (isUndefined(animateChildren) || animateChildren === true) { - var value = jqLite.data(parentElement, NG_ANIMATE_CHILDREN_DATA); + var value = jqLite.data(parentNode, NG_ANIMATE_CHILDREN_DATA); if (isDefined(value)) { animateChildren = value; } @@ -2776,52 +2807,53 @@ var $$AnimateQueueProvider = ['$animateProvider', function($animateProvider) { // there is no need to continue traversing at this point if (parentAnimationDetected && animateChildren === false) break; - if (!bodyElementDetected) { + 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 - bodyElementDetected = isMatchingElement(parentElement, bodyElement); + bodyNodeDetected = (parentNode === bodyNode); } - if (bodyElementDetected && rootElementDetected) { + 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 (!rootElementDetected) { - // If no rootElement is detected, check if the parentElement is pinned to another element - parentHost = jqLite.data(parentElement, NG_ANIMATE_PIN_DATA); + 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 - parentElement = getDomNode(parentHost); + parentNode = getDomNode(parentHost); continue; } } - parentElement = parentElement.parentNode; + parentNode = parentNode.parentNode; } var allowAnimation = (!parentAnimationDetected || animateChildren) && elementDisabled !== true; - return allowAnimation && rootElementDetected && bodyElementDetected; + return allowAnimation && rootNodeDetected && bodyNodeDetected; } - function markElementAnimationState(element, state, details) { + function markElementAnimationState(node, state, details) { details = details || {}; details.state = state; - var node = getDomNode(element); node.setAttribute(NG_ANIMATE_ATTR_NAME, state); var oldValue = activeAnimationsLookup.get(node); var newValue = oldValue ? extend(oldValue, details) : details; - activeAnimationsLookup.put(node, newValue); + activeAnimationsLookup.set(node, newValue); } }]; }]; -var $$AnimationProvider = ['$animateProvider', function($animateProvider) { +/* exported $$AnimationProvider */ + +var $$AnimationProvider = ['$animateProvider', /** @this */ function($animateProvider) { var NG_ANIMATE_REF_ATTR = 'ng-animate-ref'; var drivers = this.drivers = []; @@ -2840,21 +2872,21 @@ var $$AnimationProvider = ['$animateProvider', function($animateProvider) { return element.data(RUNNER_STORAGE_KEY); } - this.$get = ['$$jqLite', '$rootScope', '$injector', '$$AnimateRunner', '$$HashMap', '$$rAFScheduler', - function($$jqLite, $rootScope, $injector, $$AnimateRunner, $$HashMap, $$rAFScheduler) { + 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 $$HashMap(); + var i, lookup = new $$Map(); - // this is done first beforehand so that the hashmap + // 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.put(animation.domNode, animations[i] = { + lookup.set(animation.domNode, animations[i] = { domNode: animation.domNode, fn: animation.fn, children: [] @@ -2873,7 +2905,7 @@ var $$AnimationProvider = ['$animateProvider', function($animateProvider) { var elementNode = entry.domNode; var parentNode = elementNode.parentNode; - lookup.put(elementNode, entry); + lookup.set(elementNode, entry); var parentEntry; while (parentNode) { @@ -3126,7 +3158,7 @@ var $$AnimationProvider = ['$animateProvider', function($animateProvider) { }; // the anchor animations require that the from and to elements both have at least - // one shared CSS class which effictively marries the two elements together to use + // 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); @@ -3169,8 +3201,6 @@ var $$AnimationProvider = ['$animateProvider', function($animateProvider) { // may attempt more elements, but custom drivers are more particular for (var i = drivers.length - 1; i >= 0; i--) { var driverName = drivers[i]; - if (!$injector.has(driverName)) continue; // TODO(matsko): remove this check - var factory = $injector.get(driverName); var driver = factory(animationDetails); if (driver) { @@ -3199,7 +3229,8 @@ var $$AnimationProvider = ['$animateProvider', function($animateProvider) { } function update(element) { - getRunner(element).setHost(newRunner); + var runner = getRunner(element); + if (runner) runner.setHost(newRunner); } } @@ -3210,7 +3241,7 @@ var $$AnimationProvider = ['$animateProvider', function($animateProvider) { } } - function close(rejected) { // jshint ignore:line + function close(rejected) { element.off('$destroy', handleDestroyedElement); removeRunner(element); @@ -3229,18 +3260,120 @@ var $$AnimationProvider = ['$animateProvider', function($animateProvider) { }]; }]; -/* global angularAnimateModule: true, - - $$AnimateAsyncRunFactory, - $$rAFSchedulerFactory, - $$AnimateChildrenDirective, - $$AnimateQueueProvider, - $$AnimationProvider, - $AnimateCssProvider, - $$AnimateCssDriverProvider, - $$AnimateJsProvider, - $$AnimateJsDriverProvider, -*/ +/** + * @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 @@ -3279,7 +3412,7 @@ var $$AnimationProvider = ['$animateProvider', function($animateProvider) { * ## 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 the underlying directive performs an operation. + * 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`: * @@ -3358,7 +3491,7 @@ var $$AnimationProvider = ['$animateProvider', function($animateProvider) { * <div ng-show="bool" class="fade"> * Show and hide me * </div> - * <button ng-click="bool=true">Toggle</button> + * <button ng-click="bool=!bool">Toggle</button> * * <style> * .fade.ng-hide { @@ -3419,6 +3552,10 @@ var $$AnimationProvider = ['$animateProvider', function($animateProvider) { * /* As of 1.4.4, this must always be set: it signals ngAnimate * to not accidentally inherit a delay property from another CSS class */ * transition-duration: 0s; + * + * /* if you are using animations instead of transitions you should configure as follows: + * animation-delay: 0.1s; + * animation-duration: 0s; */ * } * .my-animation.ng-enter.ng-enter-active { * /* standard transition styles */ @@ -3514,7 +3651,7 @@ var $$AnimationProvider = ['$animateProvider', function($animateProvider) { * * 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 ainmation. + * `module.animation()` module function we can register the animation. * * Let's see an example of a enter/leave animation using `ngRepeat`: * @@ -3774,7 +3911,7 @@ var $$AnimationProvider = ['$animateProvider', function($animateProvider) { deps="angular-animate.js;angular-route.js" animations="true"> <file name="index.html"> - <a href="#/">Home</a> + <a href="#!/">Home</a> <hr /> <div class="view-container"> <div ng-view class="view"></div> @@ -3794,22 +3931,23 @@ var $$AnimationProvider = ['$animateProvider', function($animateProvider) { }]) .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" } + { 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($rootScope, $routeParams) { + .controller('ProfileController', ['$rootScope', '$routeParams', + function ProfileController($rootScope, $routeParams) { var index = parseInt($routeParams.id, 10); var record = $rootScope.records[index - 1]; @@ -3821,7 +3959,7 @@ var $$AnimationProvider = ['$animateProvider', function($animateProvider) { <h2>Welcome to the home page</h1> <p>Please click on an element</p> <a class="record" - ng-href="#/profile/{{ record.id }}" + ng-href="#!/profile/{{ record.id }}" ng-animate-ref="{{ record.id }}" ng-repeat="record in records"> {{ record.title }} @@ -3927,31 +4065,6 @@ var $$AnimationProvider = ['$animateProvider', function($animateProvider) { * possible be sure to visit the {@link ng.$animate $animate service API page}. * * - * ### Preventing Collisions With Third Party Libraries - * - * Some third-party frameworks place animation duration defaults across many element or className - * selectors in order to make their code small and reuseable. This can lead to issues with ngAnimate, which - * is expecting actual animations on these elements and has to wait for their completion. - * - * You can prevent this unwanted behavior by using a prefix on all your animation classes: - * - * ```css - * /* prefixed with animate- */ - * .animate-fade-add.animate-fade-add-active { - * transition:1s linear all; - * opacity:0; - * } - * ``` - * - * You then configure `$animate` to enforce this prefix: - * - * ```js - * $animateProvider.classNameFilter(/animate-/); - * ``` - * - * This also may provide your application with a speed boost since only specific elements containing CSS class prefix - * will be evaluated for animation when any DOM changes occur in the application. - * * ## 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 @@ -3983,6 +4096,19 @@ var $$AnimationProvider = ['$animateProvider', function($animateProvider) { * (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 @@ -3993,7 +4119,25 @@ var $$AnimationProvider = ['$animateProvider', function($animateProvider) { * * Click here {@link ng.$animate to learn more about animations with `$animate`}. */ -angular.module('ngAnimate', []) +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) |