|
1 | 1 | /** |
2 | | - * @license AngularJS v1.2.17 |
| 2 | + * @license AngularJS v1.2.25 |
3 | 3 | * (c) 2010-2014 Google, Inc. http://angularjs.org |
4 | 4 | * License: MIT |
5 | 5 | */ |
|
52 | 52 | * } |
53 | 53 | * |
54 | 54 | * .slide.ng-enter { } /* starting animations for enter */ |
55 | | - * .slide.ng-enter-active { } /* terminal animations for enter */ |
| 55 | + * .slide.ng-enter.ng-enter-active { } /* terminal animations for enter */ |
56 | 56 | * .slide.ng-leave { } /* starting animations for leave */ |
57 | | - * .slide.ng-leave-active { } /* terminal animations for leave */ |
| 57 | + * .slide.ng-leave.ng-leave-active { } /* terminal animations for leave */ |
58 | 58 | * </style> |
59 | 59 | * |
60 | 60 | * <!-- |
|
64 | 64 | * <ANY class="slide" ng-include="..."></ANY> |
65 | 65 | * ``` |
66 | 66 | * |
67 | | - * Keep in mind that if an animation is running, any child elements cannot be animated until the parent element's |
68 | | - * animation has completed. |
| 67 | + * Keep in mind that, by default, if an animation is running, any child elements cannot be animated |
| 68 | + * until the parent element's animation has completed. This blocking feature can be overridden by |
| 69 | + * placing the `ng-animate-children` attribute on a parent container tag. |
| 70 | + * |
| 71 | + * ```html |
| 72 | + * <div class="slide-animation" ng-if="on" ng-animate-children> |
| 73 | + * <div class="fade-animation" ng-if="on"> |
| 74 | + * <div class="explode-animation" ng-if="on"> |
| 75 | + * ... |
| 76 | + * </div> |
| 77 | + * </div> |
| 78 | + * </div> |
| 79 | + * ``` |
| 80 | + * |
| 81 | + * When the `on` expression value changes and an animation is triggered then each of the elements within |
| 82 | + * will all animate without the block being applied to child elements. |
69 | 83 | * |
70 | 84 | * <h2>CSS-defined Animations</h2> |
71 | 85 | * The animate service will automatically apply two CSS classes to the animated element and these two CSS classes |
@@ -255,6 +269,19 @@ angular.module('ngAnimate', ['ng']) |
255 | 269 | * Please visit the {@link ngAnimate `ngAnimate`} module overview page learn more about how to use animations in your application. |
256 | 270 | * |
257 | 271 | */ |
| 272 | + .directive('ngAnimateChildren', function() { |
| 273 | + var NG_ANIMATE_CHILDREN = '$$ngAnimateChildren'; |
| 274 | + return function(scope, element, attrs) { |
| 275 | + var val = attrs.ngAnimateChildren; |
| 276 | + if(angular.isString(val) && val.length === 0) { //empty attribute |
| 277 | + element.data(NG_ANIMATE_CHILDREN, true); |
| 278 | + } else { |
| 279 | + scope.$watch(val, function(value) { |
| 280 | + element.data(NG_ANIMATE_CHILDREN, !!value); |
| 281 | + }); |
| 282 | + } |
| 283 | + }; |
| 284 | + }) |
258 | 285 |
|
259 | 286 | //this private service is only used within CSS-enabled animations |
260 | 287 | //IE8 + IE9 do not support rAF natively, but that is fine since they |
@@ -283,6 +310,7 @@ angular.module('ngAnimate', ['ng']) |
283 | 310 |
|
284 | 311 | var ELEMENT_NODE = 1; |
285 | 312 | var NG_ANIMATE_STATE = '$$ngAnimateState'; |
| 313 | + var NG_ANIMATE_CHILDREN = '$$ngAnimateChildren'; |
286 | 314 | var NG_ANIMATE_CLASS_NAME = 'ng-animate'; |
287 | 315 | var rootAnimateState = {running: true}; |
288 | 316 |
|
@@ -332,6 +360,12 @@ angular.module('ngAnimate', ['ng']) |
332 | 360 | return classNameFilter.test(className); |
333 | 361 | }; |
334 | 362 |
|
| 363 | + function blockElementAnimations(element) { |
| 364 | + var data = element.data(NG_ANIMATE_STATE) || {}; |
| 365 | + data.running = true; |
| 366 | + element.data(NG_ANIMATE_STATE, data); |
| 367 | + } |
| 368 | + |
335 | 369 | function lookup(name) { |
336 | 370 | if (name) { |
337 | 371 | var matches = [], |
@@ -558,7 +592,7 @@ angular.module('ngAnimate', ['ng']) |
558 | 592 | parentElement = prepareElement(parentElement); |
559 | 593 | afterElement = prepareElement(afterElement); |
560 | 594 |
|
561 | | - this.enabled(false, element); |
| 595 | + blockElementAnimations(element); |
562 | 596 | $delegate.enter(element, parentElement, afterElement); |
563 | 597 | $rootScope.$$postDigest(function() { |
564 | 598 | element = stripCommentsFromElement(element); |
@@ -596,7 +630,7 @@ angular.module('ngAnimate', ['ng']) |
596 | 630 | leave : function(element, doneCallback) { |
597 | 631 | element = angular.element(element); |
598 | 632 | cancelChildAnimations(element); |
599 | | - this.enabled(false, element); |
| 633 | + blockElementAnimations(element); |
600 | 634 | $rootScope.$$postDigest(function() { |
601 | 635 | performAnimation('leave', 'ng-leave', stripCommentsFromElement(element), null, null, function() { |
602 | 636 | $delegate.leave(element); |
@@ -640,7 +674,7 @@ angular.module('ngAnimate', ['ng']) |
640 | 674 | afterElement = prepareElement(afterElement); |
641 | 675 |
|
642 | 676 | cancelChildAnimations(element); |
643 | | - this.enabled(false, element); |
| 677 | + blockElementAnimations(element); |
644 | 678 | $delegate.move(element, parentElement, afterElement); |
645 | 679 | $rootScope.$$postDigest(function() { |
646 | 680 | element = stripCommentsFromElement(element); |
@@ -750,7 +784,7 @@ angular.module('ngAnimate', ['ng']) |
750 | 784 | * @kind function |
751 | 785 | * |
752 | 786 | * @param {boolean=} value If provided then set the animation on or off. |
753 | | - * @param {DOMElement} element If provided then the element will be used to represent the enable/disable operation |
| 787 | + * @param {DOMElement=} element If provided then the element will be used to represent the enable/disable operation |
754 | 788 | * @return {boolean} Current animation state. |
755 | 789 | * |
756 | 790 | * @description |
@@ -814,9 +848,12 @@ angular.module('ngAnimate', ['ng']) |
814 | 848 |
|
815 | 849 | //only allow animations if the currently running animation is not structural |
816 | 850 | //or if there is no animation running at all |
817 | | - var skipAnimations = runner.isClassBased ? |
818 | | - ngAnimateState.disabled || (lastAnimation && !lastAnimation.isClassBased) : |
819 | | - false; |
| 851 | + var skipAnimations; |
| 852 | + if (runner.isClassBased) { |
| 853 | + skipAnimations = ngAnimateState.running || |
| 854 | + ngAnimateState.disabled || |
| 855 | + (lastAnimation && !lastAnimation.isClassBased); |
| 856 | + } |
820 | 857 |
|
821 | 858 | //skip the animation if animations are disabled, a parent is already being animated, |
822 | 859 | //the element is not currently attached to the document body or then completely close |
@@ -1033,30 +1070,49 @@ angular.module('ngAnimate', ['ng']) |
1033 | 1070 | } |
1034 | 1071 |
|
1035 | 1072 | function animationsDisabled(element, parentElement) { |
1036 | | - if (rootAnimateState.disabled) return true; |
| 1073 | + if (rootAnimateState.disabled) { |
| 1074 | + return true; |
| 1075 | + } |
1037 | 1076 |
|
1038 | | - if(isMatchingElement(element, $rootElement)) { |
1039 | | - return rootAnimateState.disabled || rootAnimateState.running; |
| 1077 | + if (isMatchingElement(element, $rootElement)) { |
| 1078 | + return rootAnimateState.running; |
1040 | 1079 | } |
1041 | 1080 |
|
| 1081 | + var allowChildAnimations, parentRunningAnimation, hasParent; |
1042 | 1082 | do { |
1043 | 1083 | //the element did not reach the root element which means that it |
1044 | 1084 | //is not apart of the DOM. Therefore there is no reason to do |
1045 | 1085 | //any animations on it |
1046 | | - if(parentElement.length === 0) break; |
| 1086 | + if (parentElement.length === 0) break; |
1047 | 1087 |
|
1048 | 1088 | var isRoot = isMatchingElement(parentElement, $rootElement); |
1049 | | - var state = isRoot ? rootAnimateState : parentElement.data(NG_ANIMATE_STATE); |
1050 | | - var result = state && (!!state.disabled || state.running || state.totalActive > 0); |
1051 | | - if(isRoot || result) { |
1052 | | - return result; |
| 1089 | + var state = isRoot ? rootAnimateState : (parentElement.data(NG_ANIMATE_STATE) || {}); |
| 1090 | + if (state.disabled) { |
| 1091 | + return true; |
| 1092 | + } |
| 1093 | + |
| 1094 | + //no matter what, for an animation to work it must reach the root element |
| 1095 | + //this implies that the element is attached to the DOM when the animation is run |
| 1096 | + if (isRoot) { |
| 1097 | + hasParent = true; |
1053 | 1098 | } |
1054 | 1099 |
|
1055 | | - if(isRoot) return true; |
| 1100 | + //once a flag is found that is strictly false then everything before |
| 1101 | + //it will be discarded and all child animations will be restricted |
| 1102 | + if (allowChildAnimations !== false) { |
| 1103 | + var animateChildrenFlag = parentElement.data(NG_ANIMATE_CHILDREN); |
| 1104 | + if(angular.isDefined(animateChildrenFlag)) { |
| 1105 | + allowChildAnimations = animateChildrenFlag; |
| 1106 | + } |
| 1107 | + } |
| 1108 | + |
| 1109 | + parentRunningAnimation = parentRunningAnimation || |
| 1110 | + state.running || |
| 1111 | + (state.last && !state.last.isClassBased); |
1056 | 1112 | } |
1057 | 1113 | while(parentElement = parentElement.parent()); |
1058 | 1114 |
|
1059 | | - return true; |
| 1115 | + return !hasParent || (!allowChildAnimations && parentRunningAnimation); |
1060 | 1116 | } |
1061 | 1117 | }]); |
1062 | 1118 |
|
|
0 commit comments