@@ -347,6 +347,120 @@ angular.module('ngAnimate', ['ng'])
347
347
}
348
348
}
349
349
350
+ function animationRunner ( element , animationEvent , className ) {
351
+ var node = element [ 0 ] ;
352
+ if ( ! node ) {
353
+ throw new Error ;
354
+ }
355
+
356
+ var setClassOperation = animationEvent == 'setClass' ;
357
+ var isClassBased = setClassOperation ||
358
+ animationEvent == 'addClass' ||
359
+ animationEvent == 'removeClass' ;
360
+
361
+ var classNameAdd , classNameRemove ;
362
+ if ( angular . isArray ( className ) ) {
363
+ classNameAdd = className [ 0 ] ;
364
+ classNameRemove = className [ 1 ] ;
365
+ className = classNameAdd + ' ' + classNameRemove ;
366
+ }
367
+
368
+ var currentClassName = element . attr ( 'class' ) ;
369
+ var classes = currentClassName + ' ' + className ;
370
+ if ( isAnimatableClassName ( classes ) ) {
371
+ throw new Error ;
372
+ }
373
+
374
+ var detectedAnimations = lookup ( classes ) ;
375
+
376
+ var cancellations ,
377
+ before = [ ] ,
378
+ after = [ ] ;
379
+
380
+ var animationLookup = ( ' ' + classes ) . replace ( / \s + / g, '.' ) ;
381
+ var matches = lookup ( animationLookup ) ;
382
+ for ( var i = 0 ; i < matches . length ; i ++ ) {
383
+ var animationFactory = matches [ i ] ;
384
+ var created = registerAnimation ( animationFactory , animationEvent ) ;
385
+ if ( ! created && setClassOperation ) {
386
+ registerAnimation ( animationFactory , 'addClass' ) ;
387
+ registerAnimation ( animationFactory , 'removeClass' ) ;
388
+ }
389
+ } ) ;
390
+
391
+ function registerAnimation ( animationFactory , event ) {
392
+ var afterFn = animationFactory [ event ] ;
393
+ var beforeFn = animationFactory [
394
+ 'before' + animationEvent . charAt ( 0 ) . toUpperCase ( ) + animationEvent . substr ( 1 ) ] ;
395
+ if ( afterFn || beforeFn ) {
396
+ if ( event == 'leave' ) {
397
+ beforeFn = afterFn ;
398
+ afterFn = angular . noop ;
399
+ }
400
+ after . push ( {
401
+ event : event ,
402
+ fn : afterFn || angular . noop
403
+ } ) ;
404
+ before . push ( {
405
+ event : event ,
406
+ fn : beforeFn || angular . noop
407
+ } ) ;
408
+ return true ;
409
+ }
410
+ } ;
411
+
412
+ function run ( animations , onAllComplete ) {
413
+ cancellations = [ ] ;
414
+ var count = 0 , total = animations . length ;
415
+
416
+ function onComplete ( ) {
417
+ if ( ! cancellations ) return ;
418
+
419
+ cancellations [ i ] ( ) ;
420
+ if ( ++ count < total ) return ;
421
+
422
+ cancellations = null ;
423
+ onAllComplete ( ) ;
424
+ } ;
425
+
426
+ angular . forEach ( animations , function ( animation ) {
427
+ var cancelFn ;
428
+ switch ( animation . event ) {
429
+ case 'setClass' :
430
+ cancelFn = animation . fn ( element , classNameAdd , classNameRemove , done ) ;
431
+ break ;
432
+ case 'addClass' :
433
+ case 'removeClass' :
434
+ cancelFn = animation . fn ( element , className , done ) ;
435
+ break ;
436
+ default :
437
+ cancelFn = animation . fn ( element , done ) ;
438
+ break ;
439
+ }
440
+ cancellations . push ( cancelFn || angular . noop ) ;
441
+ } ) ;
442
+ }
443
+
444
+ return {
445
+ isClassBased :
446
+ allowAnimations : function ( ) {
447
+ return true ;
448
+ } ,
449
+ before : function ( allCompleteFn ) {
450
+ run ( before , allCompleteFn ) ;
451
+ } ,
452
+ after : function ( allCompleteFn ) {
453
+ run ( before , allCompleteFn ) ;
454
+ } ,
455
+ cancelAnmations : function ( ) {
456
+ angular . forEach ( cancellation , function ( cancelFn ) {
457
+ cancelFn ( true ) ;
458
+ } ) ;
459
+ cancellations = null ;
460
+ }
461
+ } ;
462
+ }
463
+
350
464
/**
351
465
* @ngdoc service
352
466
* @name $animate
@@ -622,22 +736,12 @@ angular.module('ngAnimate', ['ng'])
622
736
*/
623
737
function performAnimation ( animationEvent , className , element , parentElement , afterElement , domOperation , doneCallback ) {
624
738
625
- var classNameAdd , classNameRemove , setClassOperation = animationEvent == 'setClass' ;
626
- if ( setClassOperation ) {
627
- classNameAdd = className [ 0 ] ;
628
- classNameRemove = className [ 1 ] ;
629
- className = classNameAdd + ' ' + classNameRemove ;
630
- }
631
-
632
- var currentClassName , classes , node = element [ 0 ] ;
633
- if ( node ) {
634
- currentClassName = node . className ;
635
- classes = currentClassName + ' ' + className ;
636
- }
637
-
638
739
//transcluded directives may sometimes fire an animation using only comment nodes
639
740
//best to catch this early on to prevent any animation operations from occurring
640
- if ( ! node || ! isAnimatableClassName ( classes ) ) {
741
+ var runner ;
742
+ try {
743
+ runner = animationRunner ( element , animationEvent , className ) ;
744
+ } catch ( e ) {
641
745
fireDOMOperation ( ) ;
642
746
fireBeforeCallbackAsync ( ) ;
643
747
fireAfterCallbackAsync ( ) ;
@@ -648,73 +752,36 @@ angular.module('ngAnimate', ['ng'])
648
752
var elementEvents = angular . element . _data ( node ) ;
649
753
elementEvents = elementEvents && elementEvents . events ;
650
754
651
- var animationLookup = ( ' ' + classes ) . replace ( / \s + / g, '.' ) ;
652
755
if ( ! parentElement ) {
653
756
parentElement = afterElement ? afterElement . parent ( ) : element . parent ( ) ;
654
757
}
655
758
656
- var matches = lookup ( animationLookup ) ;
657
- var isClassBased = animationEvent == 'addClass' ||
658
- animationEvent == 'removeClass' ||
659
- setClassOperation ;
660
759
var ngAnimateState = element . data ( NG_ANIMATE_STATE ) || { } ;
661
760
662
761
var runningAnimations = ngAnimateState . active || { } ;
663
762
var totalActiveAnimations = ngAnimateState . totalActive || 0 ;
664
763
var lastAnimation = ngAnimateState . last ;
665
764
765
+ //only allow animations if the currently running animation is not structural
766
+ //or if there is no animation running at all
767
+ var skipAnimations = runner . isClassBased ?
768
+ ! ngAnimateState . disabled && ( ! lastAnimation || lastAnimation . classBased ) :
769
+ true ;
770
+
666
771
//skip the animation if animations are disabled, a parent is already being animated,
667
772
//the element is not currently attached to the document body or then completely close
668
773
//the animation if any matching animations are not found at all.
669
774
//NOTE: IE8 + IE9 should close properly (run closeAnimation()) in case a NO animation is not found.
670
- if ( animationsDisabled ( element , parentElement ) || matches . length === 0 ) {
775
+ if ( skipAnimations ||
776
+ ! runner . allowAnimations ( ) ||
777
+ animationsDisabled ( element , parentElement ) ) {
671
778
fireDOMOperation ( ) ;
672
779
fireBeforeCallbackAsync ( ) ;
673
780
fireAfterCallbackAsync ( ) ;
674
781
closeAnimation ( ) ;
675
782
return ;
676
783
}
677
784
678
- var animations = [ ] ;
679
-
680
- //only add animations if the currently running animation is not structural
681
- //or if there is no animation running at all
682
- var allowAnimations = isClassBased ?
683
- ! ngAnimateState . disabled && ( ! lastAnimation || lastAnimation . classBased ) :
684
- true ;
685
-
686
- if ( allowAnimations ) {
687
- forEach ( matches , function ( animation ) {
688
- //add the animation to the queue to if it is allowed to be cancelled
689
- if ( ! animation . allowCancel || animation . allowCancel ( element , animationEvent , className ) ) {
690
- var beforeFn , afterFn = animation [ animationEvent ] ;
691
-
692
- //Special case for a leave animation since there is no point in performing an
693
- //animation on a element node that has already been removed from the DOM
694
- if ( animationEvent == 'leave' ) {
695
- beforeFn = afterFn ;
696
- afterFn = null ; //this must be falsy so that the animation is skipped for leave
697
- } else {
698
- beforeFn = animation [ 'before' + animationEvent . charAt ( 0 ) . toUpperCase ( ) + animationEvent . substr ( 1 ) ] ;
699
- }
700
- animations . push ( {
701
- before : beforeFn ,
702
- after : afterFn
703
- } ) ;
704
- }
705
- } ) ;
706
- }
707
-
708
- //this would mean that an animation was not allowed so let the existing
709
- //animation do it's thing and close this one early
710
- if ( animations . length === 0 ) {
711
- fireDOMOperation ( ) ;
712
- fireBeforeCallbackAsync ( ) ;
713
- fireAfterCallbackAsync ( ) ;
714
- fireDoneCallbackAsync ( ) ;
715
- return ;
716
- }
717
-
718
785
var skipAnimation = false ;
719
786
if ( totalActiveAnimations > 0 ) {
720
787
var animationsToCancel = [ ] ;
0 commit comments