@@ -489,35 +489,47 @@ angular.module('ngAnimate', ['ng'])
489
489
*/
490
490
function performAnimation ( event , className , element , parent , after , onComplete ) {
491
491
var classes = ( element . attr ( 'class' ) || '' ) + ' ' + className ;
492
- var animationLookup = ( ' ' + classes ) . replace ( / \s + / g, '.' ) ,
493
- animations = [ ] ;
494
- forEach ( lookup ( animationLookup ) , function ( animation , index ) {
495
- animations . push ( {
496
- start : animation [ event ]
497
- } ) ;
498
- } ) ;
499
-
492
+ var animationLookup = ( ' ' + classes ) . replace ( / \s + / g, '.' ) ;
500
493
if ( ! parent ) {
501
494
parent = after ? after . parent ( ) : element . parent ( ) ;
502
495
}
496
+
503
497
var disabledAnimation = { running : true } ;
498
+ var matches = lookup ( animationLookup ) ;
499
+ var isClassBased = event == 'addClass' || event == 'removeClass' ;
500
+ var ngAnimateState = element . data ( NG_ANIMATE_STATE ) || { } ;
504
501
505
- //skip the animation if animations are disabled, a parent is already being animated
506
- //or the element is not currently attached to the document body.
507
- if ( ( parent . inheritedData ( NG_ANIMATE_STATE ) || disabledAnimation ) . running || animations . length == 0 ) {
502
+ //skip the animation if animations are disabled, a parent is already being animated,
503
+ //the element is not currently attached to the document body or then completely close
504
+ //the animation if any matching animations are not found at all.
505
+ //NOTE: IE8 + IE9 should close properly (run done()) in case a NO animation is not found.
506
+ if ( ( parent . inheritedData ( NG_ANIMATE_STATE ) || disabledAnimation ) . running || matches . length == 0 ) {
508
507
done ( ) ;
509
508
return ;
510
509
}
511
510
512
- var ngAnimateState = element . data ( NG_ANIMATE_STATE ) || { } ;
511
+ var animations = [ ] ;
512
+ //only add animations if the currently running animation is not structural
513
+ //or if there is no animation running at all
514
+ if ( ! ngAnimateState . running || ! ( isClassBased && ngAnimateState . structural ) ) {
515
+ forEach ( matches , function ( animation ) {
516
+ //add the animation to the queue to if it is allowed to be cancelled
517
+ if ( ! animation . allowCancel || animation . allowCancel ( element , event , className ) ) {
518
+ animations . push ( {
519
+ start : animation [ event ]
520
+ } ) ;
521
+ }
522
+ } ) ;
523
+ }
513
524
514
- var isClassBased = event == 'addClass' || event == 'removeClass' ;
515
- if ( ngAnimateState . running ) {
516
- if ( isClassBased && ngAnimateState . structural ) {
517
- onComplete && onComplete ( ) ;
518
- return ;
519
- }
525
+ //this would mean that an animation was not allowed so let the existing
526
+ //animation do it's thing and close this one early
527
+ if ( animations . length == 0 ) {
528
+ onComplete && onComplete ( ) ;
529
+ return ;
530
+ }
520
531
532
+ if ( ngAnimateState . running ) {
521
533
//if an animation is currently running on the element then lets take the steps
522
534
//to cancel that animation and fire any required callbacks
523
535
$timeout . cancel ( ngAnimateState . flagTimer ) ;
@@ -643,6 +655,7 @@ angular.module('ngAnimate', ['ng'])
643
655
ELEMENT_NODE = 1 ;
644
656
645
657
var NG_ANIMATE_PARENT_KEY = '$ngAnimateKey' ;
658
+ var NG_ANIMATE_CLASS_KEY = '$$ngAnimateClasses' ;
646
659
var lookupCache = { } ;
647
660
var parentCounter = 0 ;
648
661
@@ -661,7 +674,7 @@ angular.module('ngAnimate', ['ng'])
661
674
}
662
675
663
676
function getElementAnimationDetails ( element , cacheKey , onlyCheckTransition ) {
664
- var data = lookupCache [ cacheKey ] ;
677
+ var data = cacheKey ? lookupCache [ cacheKey ] : null ;
665
678
if ( ! data ) {
666
679
var transitionDuration = 0 , transitionDelay = 0 ,
667
680
animationDuration = 0 , animationDelay = 0 ;
@@ -694,7 +707,9 @@ angular.module('ngAnimate', ['ng'])
694
707
transitionDuration : transitionDuration ,
695
708
animationDuration : animationDuration
696
709
} ;
697
- lookupCache [ cacheKey ] = data ;
710
+ if ( cacheKey ) {
711
+ lookupCache [ cacheKey ] = data ;
712
+ }
698
713
}
699
714
return data ;
700
715
}
@@ -761,6 +776,7 @@ angular.module('ngAnimate', ['ng'])
761
776
element . addClass ( activeClassName ) ;
762
777
} ) ;
763
778
779
+ element . data ( NG_ANIMATE_CLASS_KEY , className + ' ' + activeClassName ) ;
764
780
element . on ( css3AnimationEvents , onAnimationProgress ) ;
765
781
766
782
// This will automatically be called by $animate so
@@ -770,6 +786,7 @@ angular.module('ngAnimate', ['ng'])
770
786
element . off ( css3AnimationEvents , onAnimationProgress ) ;
771
787
element . removeClass ( className ) ;
772
788
element . removeClass ( activeClassName ) ;
789
+ element . removeData ( NG_ANIMATE_CLASS_KEY ) ;
773
790
774
791
// Only when the animation is cancelled is the done()
775
792
// function not called for this animation therefore
@@ -803,6 +820,35 @@ angular.module('ngAnimate', ['ng'])
803
820
}
804
821
805
822
return {
823
+ allowCancel : function ( element , event , className ) {
824
+ //always cancel the current animation if it is a
825
+ //structural animation
826
+ var oldClasses = element . data ( NG_ANIMATE_CLASS_KEY ) ;
827
+ if ( ! oldClasses || [ 'enter' , 'leave' , 'move' ] . indexOf ( event ) >= 0 ) {
828
+ return true ;
829
+ }
830
+
831
+ var parent = element . parent ( ) ;
832
+ var clone = angular . element ( element [ 0 ] . cloneNode ( ) ) ;
833
+
834
+ //make the element super hidden and override any CSS style values
835
+ clone . attr ( 'style' , 'position:absolute; top:-9999px; left:-9999px' ) ;
836
+ clone . removeAttr ( 'id' ) ;
837
+ clone . html ( '' ) ;
838
+
839
+ angular . forEach ( oldClasses . split ( ' ' ) , function ( klass ) {
840
+ clone . removeClass ( klass ) ;
841
+ } ) ;
842
+
843
+ var suffix = event == 'addClass' ? '-add' : '-remove' ;
844
+ clone . addClass ( suffixClasses ( className , suffix ) ) ;
845
+ parent . append ( clone ) ;
846
+
847
+ var timings = getElementAnimationDetails ( clone ) ;
848
+ clone . remove ( ) ;
849
+
850
+ return Math . max ( timings . transitionDuration , timings . animationDuration ) > 0 ;
851
+ } ,
806
852
enter : function ( element , done ) {
807
853
return animate ( element , 'ng-enter' , done ) ;
808
854
} ,
0 commit comments