@@ -282,7 +282,9 @@ angular.module('ngAnimate', ['ng'])
282
282
*/
283
283
enter : function ( element , parent , after , done ) {
284
284
$delegate . enter ( element , parent , after ) ;
285
- performAnimation ( 'enter' , 'ng-enter' , element , parent , after , done ) ;
285
+ performAnimation ( 'enter' , 'ng-enter' , element , parent , after , function ( ) {
286
+ $timeout ( done || noop , 0 , false ) ;
287
+ } ) ;
286
288
} ,
287
289
288
290
/**
@@ -350,7 +352,9 @@ angular.module('ngAnimate', ['ng'])
350
352
*/
351
353
move : function ( element , parent , after , done ) {
352
354
$delegate . move ( element , parent , after ) ;
353
- performAnimation ( 'move' , 'ng-move' , element , null , null , done ) ;
355
+ performAnimation ( 'move' , 'ng-move' , element , null , null , function ( ) {
356
+ $timeout ( done || noop , 0 , false ) ;
357
+ } ) ;
354
358
} ,
355
359
356
360
/**
@@ -361,7 +365,8 @@ angular.module('ngAnimate', ['ng'])
361
365
* @description
362
366
* Triggers a custom animation event based off the className variable and then attaches the className value to the element as a CSS class.
363
367
* Unlike the other animation methods, the animate service will suffix the className value with {@type -add} in order to provide
364
- * the animate service the setup and active CSS classes in order to trigger the animation.
368
+ * the animate service the setup and active CSS classes in order to trigger the animation (this will be skipped if no CSS transitions
369
+ * or keyframes are defined on the -add CSS class).
365
370
*
366
371
* Below is a breakdown of each step that occurs during addClass animation:
367
372
*
@@ -395,7 +400,8 @@ angular.module('ngAnimate', ['ng'])
395
400
* @description
396
401
* Triggers a custom animation event based off the className variable and then removes the CSS class provided by the className value
397
402
* from the element. Unlike the other animation methods, the animate service will suffix the className value with {@type -remove} in
398
- * order to provide the animate service the setup and active CSS classes in order to trigger the animation.
403
+ * order to provide the animate service the setup and active CSS classes in order to trigger the animation (this will be skipped if
404
+ * no CSS transitions or keyframes are defined on the -remove CSS class).
399
405
*
400
406
* Below is a breakdown of each step that occurs during removeClass animation:
401
407
*
@@ -546,90 +552,89 @@ angular.module('ngAnimate', ['ng'])
546
552
function animate ( element , className , done ) {
547
553
if ( ! ( $sniffer . transitions || $sniffer . animations ) ) {
548
554
done ( ) ;
549
- } else {
550
- var activeClassName = '' ;
551
- $timeout ( startAnimation , 1 , false ) ;
552
-
553
- //this acts as the cancellation function in case
554
- //a new animation is triggered while another animation
555
- //is still going on (otherwise the active className
556
- //would still hang around until the timer is complete).
557
- return onEnd ;
558
- }
559
-
560
- function parseMaxTime ( str ) {
561
- var total = 0 , values = angular . isString ( str ) ? str . split ( / \s * , \s * / ) : [ ] ;
562
- forEach ( values , function ( value ) {
563
- total = Math . max ( parseFloat ( value ) || 0 , total ) ;
564
- } ) ;
565
- return total ;
555
+ return ;
566
556
}
567
557
568
- function startAnimation ( ) {
569
- var duration = 0 ;
570
- forEach ( className . split ( ' ' ) , function ( klass , i ) {
571
- activeClassName += ( i > 0 ? ' ' : '' ) + klass + '-active' ;
572
- } ) ;
558
+ //one day all browsers will have these properties
559
+ var w3cAnimationProp = 'animation' ;
560
+ var w3cTransitionProp = 'transition' ;
573
561
574
- element . addClass ( activeClassName ) ;
562
+ //but some still use vendor-prefixed styles
563
+ var vendorAnimationProp = $sniffer . vendorPrefix + 'Animation' ;
564
+ var vendorTransitionProp = $sniffer . vendorPrefix + 'Transition' ;
575
565
576
- //one day all browsers will have these properties
577
- var w3cAnimationProp = 'animation' ;
578
- var w3cTransitionProp = 'transition ' ;
566
+ var durationKey = 'Duration' ,
567
+ delayKey = 'Delay' ,
568
+ animationIterationCountKey = 'IterationCount ' ;
579
569
580
- //but some still use vendor-prefixed styles
581
- var vendorAnimationProp = $sniffer . vendorPrefix + 'Animation' ;
582
- var vendorTransitionProp = $sniffer . vendorPrefix + 'Transition' ;
570
+ //we want all the styles defined before and after
571
+ var duration = 0 , ELEMENT_NODE = 1 ;
572
+ forEach ( element , function ( element ) {
573
+ if ( element . nodeType == ELEMENT_NODE ) {
574
+ var elementStyles = $window . getComputedStyle ( element ) || { } ;
583
575
584
- var durationKey = 'Duration' ,
585
- delayKey = 'Delay' ,
586
- animationIterationCountKey = 'IterationCount' ;
576
+ var transitionDelay = Math . max ( parseMaxTime ( elementStyles [ w3cTransitionProp + delayKey ] ) ,
577
+ parseMaxTime ( elementStyles [ vendorTransitionProp + delayKey ] ) ) ;
587
578
588
- //we want all the styles defined before and after
589
- var ELEMENT_NODE = 1 ;
590
- forEach ( element , function ( element ) {
591
- if ( element . nodeType == ELEMENT_NODE ) {
592
- var elementStyles = $window . getComputedStyle ( element ) || { } ;
579
+ var animationDelay = Math . max ( parseMaxTime ( elementStyles [ w3cAnimationProp + delayKey ] ) ,
580
+ parseMaxTime ( elementStyles [ vendorAnimationProp + delayKey ] ) ) ;
593
581
594
- var transitionDelay = Math . max ( parseMaxTime ( elementStyles [ w3cTransitionProp + delayKey ] ) ,
595
- parseMaxTime ( elementStyles [ vendorTransitionProp + delayKey ] ) ) ;
582
+ var transitionDuration = Math . max ( parseMaxTime ( elementStyles [ w3cTransitionProp + durationKey ] ) ,
583
+ parseMaxTime ( elementStyles [ vendorTransitionProp + durationKey ] ) ) ;
596
584
597
- var animationDelay = Math . max ( parseMaxTime ( elementStyles [ w3cAnimationProp + delayKey ] ) ,
598
- parseMaxTime ( elementStyles [ vendorAnimationProp + delayKey ] ) ) ;
585
+ var animationDuration = Math . max ( parseMaxTime ( elementStyles [ w3cAnimationProp + durationKey ] ) ,
586
+ parseMaxTime ( elementStyles [ vendorAnimationProp + durationKey ] ) ) ;
599
587
600
- var transitionDuration = Math . max ( parseMaxTime ( elementStyles [ w3cTransitionProp + durationKey ] ) ,
601
- parseMaxTime ( elementStyles [ vendorTransitionProp + durationKey ] ) ) ;
602
-
603
- var animationDuration = Math . max ( parseMaxTime ( elementStyles [ w3cAnimationProp + durationKey ] ) ,
604
- parseMaxTime ( elementStyles [ vendorAnimationProp + durationKey ] ) ) ;
588
+ if ( animationDuration > 0 ) {
589
+ animationDuration *= Math . max ( parseInt ( elementStyles [ w3cAnimationProp + animationIterationCountKey ] ) || 0 ,
590
+ parseInt ( elementStyles [ vendorAnimationProp + animationIterationCountKey ] ) || 0 ,
591
+ 1 ) ;
592
+ }
605
593
606
- if ( animationDuration > 0 ) {
607
- animationDuration *= Math . max ( parseInt ( elementStyles [ w3cAnimationProp + animationIterationCountKey ] ) || 0 ,
608
- parseInt ( elementStyles [ vendorAnimationProp + animationIterationCountKey ] ) || 0 ,
609
- 1 ) ;
610
- }
594
+ duration = Math . max ( animationDelay + animationDuration ,
595
+ transitionDelay + transitionDuration ,
596
+ duration ) ;
597
+ }
598
+ } ) ;
611
599
612
- duration = Math . max ( animationDelay + animationDuration ,
613
- transitionDelay + transitionDuration ,
614
- duration ) ;
615
- }
600
+ /* there is no point in performing a reflow if the animation
601
+ timeout is empty (this would cause a flicker bug normally
602
+ in the page */
603
+ if ( duration > 0 ) {
604
+ var activeClassName = '' ;
605
+ forEach ( className . split ( ' ' ) , function ( klass , i ) {
606
+ activeClassName += ( i > 0 ? ' ' : '' ) + klass + '-active' ;
616
607
} ) ;
617
608
618
- $timeout ( done , duration * 1000 , false ) ;
609
+ $timeout ( function ( ) {
610
+ element . addClass ( activeClassName ) ;
611
+ $timeout ( done , duration * 1000 , false ) ;
612
+ } , 0 , false ) ;
613
+
614
+ //this will automatically be called by $animate so
615
+ //there is no need to attach this internally to the
616
+ //timeout done method
617
+ return function onEnd ( cancelled ) {
618
+ element . removeClass ( activeClassName ) ;
619
+
620
+ //only when the animation is cancelled is the done()
621
+ //function not called for this animation therefore
622
+ //this must be also called
623
+ if ( cancelled ) {
624
+ done ( ) ;
625
+ }
626
+ }
627
+ }
628
+ else {
629
+ done ( ) ;
619
630
}
620
631
621
- //this will automatically be called by $animate so
622
- //there is no need to attach this internally to the
623
- //timeout done method
624
- function onEnd ( cancelled ) {
625
- element . removeClass ( activeClassName ) ;
626
-
627
- //only when the animation is cancelled is the done()
628
- //function not called for this animation therefore
629
- //this must be also called
630
- if ( cancelled ) {
631
- done ( ) ;
632
- }
632
+ function parseMaxTime ( str ) {
633
+ var total = 0 , values = angular . isString ( str ) ? str . split ( / \s * , \s * / ) : [ ] ;
634
+ forEach ( values , function ( value ) {
635
+ total = Math . max ( parseFloat ( value ) || 0 , total ) ;
636
+ } ) ;
637
+ return total ;
633
638
}
634
639
}
635
640
0 commit comments