@@ -493,35 +493,47 @@ angular.module('ngAnimate', ['ng'])
493
493
*/
494
494
function performAnimation ( event , className , element , parent , after , onComplete ) {
495
495
var classes = ( element . attr ( 'class' ) || '' ) + ' ' + className ;
496
- var animationLookup = ( ' ' + classes ) . replace ( / \s + / g, '.' ) ,
497
- animations = [ ] ;
498
- forEach ( lookup ( animationLookup ) , function ( animation , index ) {
499
- animations . push ( {
500
- start : animation [ event ]
501
- } ) ;
502
- } ) ;
503
-
496
+ var animationLookup = ( ' ' + classes ) . replace ( / \s + / g, '.' ) ;
504
497
if ( ! parent ) {
505
498
parent = after ? after . parent ( ) : element . parent ( ) ;
506
499
}
500
+
507
501
var disabledAnimation = { running : true } ;
502
+ var matches = lookup ( animationLookup ) ;
503
+ var isClassBased = event == 'addClass' || event == 'removeClass' ;
504
+ var ngAnimateState = element . data ( NG_ANIMATE_STATE ) || { } ;
508
505
509
- //skip the animation if animations are disabled, a parent is already being animated
510
- //or the element is not currently attached to the document body.
511
- if ( ( parent . inheritedData ( NG_ANIMATE_STATE ) || disabledAnimation ) . running || animations . length === 0 ) {
506
+ //skip the animation if animations are disabled, a parent is already being animated,
507
+ //the element is not currently attached to the document body or then completely close
508
+ //the animation if any matching animations are not found at all.
509
+ //NOTE: IE8 + IE9 should close properly (run done()) in case a NO animation is not found.
510
+ if ( ( parent . inheritedData ( NG_ANIMATE_STATE ) || disabledAnimation ) . running || matches . length == 0 ) {
512
511
done ( ) ;
513
512
return ;
514
513
}
515
514
516
- var ngAnimateState = element . data ( NG_ANIMATE_STATE ) || { } ;
515
+ var animations = [ ] ;
516
+ //only add animations if the currently running animation is not structural
517
+ //or if there is no animation running at all
518
+ if ( ! ngAnimateState . running || ! ( isClassBased && ngAnimateState . structural ) ) {
519
+ forEach ( matches , function ( animation ) {
520
+ //add the animation to the queue to if it is allowed to be cancelled
521
+ if ( ! animation . allowCancel || animation . allowCancel ( element , event , className ) ) {
522
+ animations . push ( {
523
+ start : animation [ event ]
524
+ } ) ;
525
+ }
526
+ } ) ;
527
+ }
517
528
518
- var isClassBased = event == 'addClass' || event == 'removeClass' ;
519
- if ( ngAnimateState . running ) {
520
- if ( isClassBased && ngAnimateState . structural ) {
521
- onComplete && onComplete ( ) ;
522
- return ;
523
- }
529
+ //this would mean that an animation was not allowed so let the existing
530
+ //animation do it's thing and close this one early
531
+ if ( animations . length == 0 ) {
532
+ onComplete && onComplete ( ) ;
533
+ return ;
534
+ }
524
535
536
+ if ( ngAnimateState . running ) {
525
537
//if an animation is currently running on the element then lets take the steps
526
538
//to cancel that animation and fire any required callbacks
527
539
$timeout . cancel ( ngAnimateState . flagTimer ) ;
@@ -651,6 +663,7 @@ angular.module('ngAnimate', ['ng'])
651
663
animationIterationCountKey = 'IterationCount' ;
652
664
653
665
var NG_ANIMATE_PARENT_KEY = '$ngAnimateKey' ;
666
+ var NG_ANIMATE_CLASS_KEY = '$$ngAnimateClasses' ;
654
667
var lookupCache = { } ;
655
668
var parentCounter = 0 ;
656
669
@@ -669,7 +682,7 @@ angular.module('ngAnimate', ['ng'])
669
682
}
670
683
671
684
function getElementAnimationDetails ( element , cacheKey , onlyCheckTransition ) {
672
- var data = lookupCache [ cacheKey ] ;
685
+ var data = cacheKey ? lookupCache [ cacheKey ] : null ;
673
686
if ( ! data ) {
674
687
var transitionDuration = 0 , transitionDelay = 0 ,
675
688
animationDuration = 0 , animationDelay = 0 ;
@@ -702,7 +715,9 @@ angular.module('ngAnimate', ['ng'])
702
715
transitionDuration : transitionDuration ,
703
716
animationDuration : animationDuration
704
717
} ;
705
- lookupCache [ cacheKey ] = data ;
718
+ if ( cacheKey ) {
719
+ lookupCache [ cacheKey ] = data ;
720
+ }
706
721
}
707
722
return data ;
708
723
}
@@ -769,6 +784,7 @@ angular.module('ngAnimate', ['ng'])
769
784
element . addClass ( activeClassName ) ;
770
785
} ) ;
771
786
787
+ element . data ( NG_ANIMATE_CLASS_KEY , className + ' ' + activeClassName ) ;
772
788
element . on ( css3AnimationEvents , onAnimationProgress ) ;
773
789
774
790
// This will automatically be called by $animate so
@@ -778,6 +794,7 @@ angular.module('ngAnimate', ['ng'])
778
794
element . off ( css3AnimationEvents , onAnimationProgress ) ;
779
795
element . removeClass ( className ) ;
780
796
element . removeClass ( activeClassName ) ;
797
+ element . removeData ( NG_ANIMATE_CLASS_KEY ) ;
781
798
782
799
// Only when the animation is cancelled is the done()
783
800
// function not called for this animation therefore
@@ -811,6 +828,35 @@ angular.module('ngAnimate', ['ng'])
811
828
}
812
829
813
830
return {
831
+ allowCancel : function ( element , event , className ) {
832
+ //always cancel the current animation if it is a
833
+ //structural animation
834
+ var oldClasses = element . data ( NG_ANIMATE_CLASS_KEY ) ;
835
+ if ( ! oldClasses || [ 'enter' , 'leave' , 'move' ] . indexOf ( event ) >= 0 ) {
836
+ return true ;
837
+ }
838
+
839
+ var parent = element . parent ( ) ;
840
+ var clone = angular . element ( element [ 0 ] . cloneNode ( ) ) ;
841
+
842
+ //make the element super hidden and override any CSS style values
843
+ clone . attr ( 'style' , 'position:absolute; top:-9999px; left:-9999px' ) ;
844
+ clone . removeAttr ( 'id' ) ;
845
+ clone . html ( '' ) ;
846
+
847
+ angular . forEach ( oldClasses . split ( ' ' ) , function ( klass ) {
848
+ clone . removeClass ( klass ) ;
849
+ } ) ;
850
+
851
+ var suffix = event == 'addClass' ? '-add' : '-remove' ;
852
+ clone . addClass ( suffixClasses ( className , suffix ) ) ;
853
+ parent . append ( clone ) ;
854
+
855
+ var timings = getElementAnimationDetails ( clone ) ;
856
+ clone . remove ( ) ;
857
+
858
+ return Math . max ( timings . transitionDuration , timings . animationDuration ) > 0 ;
859
+ } ,
814
860
enter : function ( element , done ) {
815
861
return animate ( element , 'ng-enter' , done ) ;
816
862
} ,
0 commit comments