/**
- * @license AngularJS v1.2.16
+ * @license AngularJS v1.2.32
* (c) 2010-2014 Google, Inc. http://angularjs.org
* License: MIT
*/
* }
*
* .slide.ng-enter { } /* starting animations for enter */
- * .slide.ng-enter-active { } /* terminal animations for enter */
+ * .slide.ng-enter.ng-enter-active { } /* terminal animations for enter */
* .slide.ng-leave { } /* starting animations for leave */
- * .slide.ng-leave-active { } /* terminal animations for leave */
+ * .slide.ng-leave.ng-leave-active { } /* terminal animations for leave */
* </style>
*
* <!--
* <ANY class="slide" ng-include="..."></ANY>
* ```
*
- * Keep in mind that if an animation is running, any child elements cannot be animated until the parent element's
- * animation has completed.
+ * Keep in mind that, by default, if an animation is running, any child elements cannot be animated
+ * until the parent element's animation has completed. This blocking feature can be overridden by
+ * placing the `ng-animate-children` attribute on a parent container tag.
+ *
+ * ```html
+ * <div class="slide-animation" ng-if="on" ng-animate-children>
+ * <div class="fade-animation" ng-if="on">
+ * <div class="explode-animation" ng-if="on">
+ * ...
+ * </div>
+ * </div>
+ * </div>
+ * ```
+ *
+ * When the `on` expression value changes and an animation is triggered then each of the elements within
+ * will all animate without the block being applied to child elements.
*
* <h2>CSS-defined Animations</h2>
* The animate service will automatically apply two CSS classes to the animated element and these two CSS classes
* Please visit the {@link ngAnimate `ngAnimate`} module overview page learn more about how to use animations in your application.
*
*/
+ .directive('ngAnimateChildren', function() {
+ var NG_ANIMATE_CHILDREN = '$$ngAnimateChildren';
+ return function(scope, element, attrs) {
+ var val = attrs.ngAnimateChildren;
+ if(angular.isString(val) && val.length === 0) { //empty attribute
+ element.data(NG_ANIMATE_CHILDREN, true);
+ } else {
+ scope.$watch(val, function(value) {
+ element.data(NG_ANIMATE_CHILDREN, !!value);
+ });
+ }
+ };
+ })
//this private service is only used within CSS-enabled animations
//IE8 + IE9 do not support rAF natively, but that is fine since they
//so that all the animated elements within the animation frame
//will be properly updated and drawn on screen. This is
//required to perform multi-class CSS based animations with
- //Firefox. DO NOT REMOVE THIS LINE.
- var a = bod.offsetWidth + 1;
- fn();
+ //Firefox. DO NOT REMOVE THIS LINE. DO NOT OPTIMIZE THIS LINE.
+ //THE MINIFIER WILL REMOVE IT OTHERWISE WHICH WILL RESULT IN AN
+ //UNPREDICTABLE BUG THAT IS VERY HARD TO TRACK DOWN AND WILL
+ //TAKE YEARS AWAY FROM YOUR LIFE!
+ fn(bod.offsetWidth);
});
};
}])
var ELEMENT_NODE = 1;
var NG_ANIMATE_STATE = '$$ngAnimateState';
+ var NG_ANIMATE_CHILDREN = '$$ngAnimateChildren';
var NG_ANIMATE_CLASS_NAME = 'ng-animate';
var rootAnimateState = {running: true};
}
}
+ function prepareElement(element) {
+ return element && angular.element(element);
+ }
+
function stripCommentsFromElement(element) {
return angular.element(extractElementNode(element));
}
return classNameFilter.test(className);
};
+ function blockElementAnimations(element) {
+ var data = element.data(NG_ANIMATE_STATE) || {};
+ data.running = true;
+ element.data(NG_ANIMATE_STATE, data);
+ }
+
function lookup(name) {
if (name) {
var matches = [],
/**
* @ngdoc service
* @name $animate
- * @function
+ * @kind function
*
* @description
* The `$animate` service provides animation detection support while performing DOM operations (enter, leave and move) as well as during addClass and removeClass operations.
/**
* @ngdoc method
* @name $animate#enter
- * @function
+ * @kind function
*
* @description
* Appends the element to the parentElement element that resides in the document and then runs the enter animation. Once
* @param {function()=} doneCallback the callback function that will be called once the animation is complete
*/
enter : function(element, parentElement, afterElement, doneCallback) {
- this.enabled(false, element);
+ element = angular.element(element);
+ parentElement = prepareElement(parentElement);
+ afterElement = prepareElement(afterElement);
+
+ blockElementAnimations(element);
$delegate.enter(element, parentElement, afterElement);
$rootScope.$$postDigest(function() {
element = stripCommentsFromElement(element);
/**
* @ngdoc method
* @name $animate#leave
- * @function
+ * @kind function
*
* @description
* Runs the leave animation operation and, upon completion, removes the element from the DOM. Once
* @param {function()=} doneCallback the callback function that will be called once the animation is complete
*/
leave : function(element, doneCallback) {
+ element = angular.element(element);
cancelChildAnimations(element);
- this.enabled(false, element);
+ blockElementAnimations(element);
$rootScope.$$postDigest(function() {
performAnimation('leave', 'ng-leave', stripCommentsFromElement(element), null, null, function() {
$delegate.leave(element);
/**
* @ngdoc method
* @name $animate#move
- * @function
+ * @kind function
*
* @description
* Fires the move DOM operation. Just before the animation starts, the animate service will either append it into the parentElement container or
* @param {function()=} doneCallback the callback function that will be called once the animation is complete
*/
move : function(element, parentElement, afterElement, doneCallback) {
+ element = angular.element(element);
+ parentElement = prepareElement(parentElement);
+ afterElement = prepareElement(afterElement);
+
cancelChildAnimations(element);
- this.enabled(false, element);
+ blockElementAnimations(element);
$delegate.move(element, parentElement, afterElement);
$rootScope.$$postDigest(function() {
element = stripCommentsFromElement(element);
* @param {function()=} doneCallback the callback function that will be called once the animation is complete
*/
addClass : function(element, className, doneCallback) {
+ element = angular.element(element);
element = stripCommentsFromElement(element);
performAnimation('addClass', className, element, null, null, function() {
$delegate.addClass(element, className);
* @param {function()=} doneCallback the callback function that will be called once the animation is complete
*/
removeClass : function(element, className, doneCallback) {
+ element = angular.element(element);
element = stripCommentsFromElement(element);
performAnimation('removeClass', className, element, null, null, function() {
$delegate.removeClass(element, className);
* @function
* @description Adds and/or removes the given CSS classes to and from the element.
* Once complete, the done() callback will be fired (if provided).
- * @param {DOMElement} element the element which will it's CSS classes changed
+ * @param {DOMElement} element the element which will its CSS classes changed
* removed from it
* @param {string} add the CSS classes which will be added to the element
* @param {string} remove the CSS class which will be removed from the element
* CSS classes have been set on the element
*/
setClass : function(element, add, remove, doneCallback) {
+ element = angular.element(element);
element = stripCommentsFromElement(element);
performAnimation('setClass', [add, remove], element, null, null, function() {
$delegate.setClass(element, add, remove);
/**
* @ngdoc method
* @name $animate#enabled
- * @function
+ * @kind function
*
* @param {boolean=} value If provided then set the animation on or off.
* @param {DOMElement=} element If provided then the element will be used to represent the enable/disable operation
//only allow animations if the currently running animation is not structural
//or if there is no animation running at all
- var skipAnimations = runner.isClassBased ?
- ngAnimateState.disabled || (lastAnimation && !lastAnimation.isClassBased) :
- false;
+ var skipAnimations;
+ if (runner.isClassBased) {
+ skipAnimations = ngAnimateState.running ||
+ ngAnimateState.disabled ||
+ (lastAnimation && !lastAnimation.isClassBased);
+ }
//skip the animation if animations are disabled, a parent is already being animated,
//the element is not currently attached to the document body or then completely close
}
if(skipAnimation) {
+ fireDOMOperation();
fireBeforeCallbackAsync();
fireAfterCallbackAsync();
fireDoneCallbackAsync();
}
function animationsDisabled(element, parentElement) {
- if (rootAnimateState.disabled) return true;
+ if (rootAnimateState.disabled) {
+ return true;
+ }
- if(isMatchingElement(element, $rootElement)) {
- return rootAnimateState.disabled || rootAnimateState.running;
+ if (isMatchingElement(element, $rootElement)) {
+ return rootAnimateState.running;
}
+ var allowChildAnimations, parentRunningAnimation, hasParent;
do {
//the element did not reach the root element which means that it
//is not apart of the DOM. Therefore there is no reason to do
//any animations on it
- if(parentElement.length === 0) break;
+ if (parentElement.length === 0) break;
var isRoot = isMatchingElement(parentElement, $rootElement);
- var state = isRoot ? rootAnimateState : parentElement.data(NG_ANIMATE_STATE);
- var result = state && (!!state.disabled || state.running || state.totalActive > 0);
- if(isRoot || result) {
- return result;
+ var state = isRoot ? rootAnimateState : (parentElement.data(NG_ANIMATE_STATE) || {});
+ if (state.disabled) {
+ return true;
+ }
+
+ //no matter what, for an animation to work it must reach the root element
+ //this implies that the element is attached to the DOM when the animation is run
+ if (isRoot) {
+ hasParent = true;
}
- if(isRoot) return true;
+ //once a flag is found that is strictly false then everything before
+ //it will be discarded and all child animations will be restricted
+ if (allowChildAnimations !== false) {
+ var animateChildrenFlag = parentElement.data(NG_ANIMATE_CHILDREN);
+ if(angular.isDefined(animateChildrenFlag)) {
+ allowChildAnimations = animateChildrenFlag;
+ }
+ }
+
+ parentRunningAnimation = parentRunningAnimation ||
+ state.running ||
+ (state.last && !state.last.isClassBased);
}
while(parentElement = parentElement.parent());
- return true;
+ return !hasParent || (!allowChildAnimations && parentRunningAnimation);
}
}]);
var parentCounter = 0;
var animationReflowQueue = [];
var cancelAnimationReflow;
+ function clearCacheAfterReflow() {
+ if (!cancelAnimationReflow) {
+ cancelAnimationReflow = $$animateReflow(function() {
+ animationReflowQueue = [];
+ cancelAnimationReflow = null;
+ lookupCache = {};
+ });
+ }
+ }
+
function afterReflow(element, callback) {
if(cancelAnimationReflow) {
cancelAnimationReflow();
//the jqLite object, so we're safe to use a single variable to house
//the styles since there is always only one element being animated
var oldStyle = node.getAttribute('style') || '';
- node.setAttribute('style', oldStyle + ' ' + style);
+ node.setAttribute('style', oldStyle + '; ' + style);
}
element.on(css3AnimationEvents, onAnimationProgress);
function onAnimationProgress(event) {
event.stopPropagation();
var ev = event.originalEvent || event;
- var timeStamp = ev.$manualTimeStamp || ev.timeStamp || Date.now();
+ 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 */
/* $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,
+ * mock animations properly. Real events fallback to Date.now(),
* 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
//cancellation function then it means that there is no animation
//to perform at all
var preReflowCancellation = animateBefore(animationEvent, element, className);
- if(!preReflowCancellation) {
+ if (!preReflowCancellation) {
+ clearCacheAfterReflow();
animationComplete();
return;
}
});
return cancellationMethod;
}
+ clearCacheAfterReflow();
animationCompleted();
},
});
return cancellationMethod;
}
+ clearCacheAfterReflow();
animationCompleted();
},
}]);
-})(window, window.angular);
\ No newline at end of file
+})(window, window.angular);