@@ -19,12 +19,16 @@ var $$AnimationProvider = ['$animateProvider', function($animateProvider) {
19
19
return element . data ( RUNNER_STORAGE_KEY ) ;
20
20
}
21
21
22
- this . $get = [ '$$jqLite' , '$rootScope' , '$injector' , '$$AnimateRunner' ,
23
- function ( $$jqLite , $rootScope , $injector , $$AnimateRunner ) {
22
+ this . $get = [ '$$jqLite' , '$rootScope' , '$injector' , '$$AnimateRunner' , '$$rAFScheduler' ,
23
+ function ( $$jqLite , $rootScope , $injector , $$AnimateRunner , $$rAFScheduler ) {
24
24
25
25
var animationQueue = [ ] ;
26
26
var applyAnimationClasses = applyAnimationClassesFactory ( $$jqLite ) ;
27
27
28
+ var totalPendingClassBasedAnimations = 0 ;
29
+ var totalActiveClassBasedAnimations = 0 ;
30
+ var classBasedAnimationsQueue = [ ] ;
31
+
28
32
// TODO(matsko): document the signature in a better way
29
33
return function ( element , event , options ) {
30
34
options = prepareAnimationOptions ( options ) ;
@@ -53,12 +57,18 @@ var $$AnimationProvider = ['$animateProvider', function($animateProvider) {
53
57
options . tempClasses = null ;
54
58
}
55
59
60
+ var classBasedIndex ;
61
+ if ( ! isStructural ) {
62
+ classBasedIndex = totalPendingClassBasedAnimations ++ ;
63
+ }
64
+
56
65
animationQueue . push ( {
57
66
// this data is used by the postDigest code and passed into
58
67
// the driver step function
59
68
element : element ,
60
69
classes : classes ,
61
70
event : event ,
71
+ classBasedIndex : classBasedIndex ,
62
72
structural : isStructural ,
63
73
options : options ,
64
74
beforeStart : beforeStart ,
@@ -73,6 +83,10 @@ var $$AnimationProvider = ['$animateProvider', function($animateProvider) {
73
83
if ( animationQueue . length > 1 ) return runner ;
74
84
75
85
$rootScope . $$postDigest ( function ( ) {
86
+ totalActiveClassBasedAnimations = totalPendingClassBasedAnimations ;
87
+ totalPendingClassBasedAnimations = 0 ;
88
+ classBasedAnimationsQueue . length = 0 ;
89
+
76
90
var animations = [ ] ;
77
91
forEach ( animationQueue , function ( entry ) {
78
92
// the element was destroyed early on which removed the runner
@@ -87,23 +101,58 @@ var $$AnimationProvider = ['$animateProvider', function($animateProvider) {
87
101
animationQueue . length = 0 ;
88
102
89
103
forEach ( groupAnimations ( animations ) , function ( animationEntry ) {
90
- // it's important that we apply the `ng-animate` CSS class and the
91
- // temporary classes before we do any driver invoking since these
92
- // CSS classes may be required for proper CSS detection.
93
- animationEntry . beforeStart ( ) ;
94
-
95
- var operation = invokeFirstDriver ( animationEntry ) ;
96
- var triggerAnimationStart = operation && operation . start ; /// TODO(matsko): only recognize operation.start()
97
-
98
- var closeFn = animationEntry . close ;
99
- if ( ! triggerAnimationStart ) {
100
- closeFn ( ) ;
104
+ if ( animationEntry . structural || animationEntry . anchors ) {
105
+ triggerAnimationStart ( ) ;
101
106
} else {
102
- var animationRunner = triggerAnimationStart ( ) ;
103
- animationRunner . done ( function ( status ) {
104
- closeFn ( ! status ) ;
107
+ classBasedAnimationsQueue . push ( {
108
+ node : getDomNode ( animationEntry . element ) ,
109
+ fn : triggerAnimationStart
105
110
} ) ;
106
- updateAnimationRunners ( animationEntry , animationRunner ) ;
111
+
112
+ if ( animationEntry . classBasedIndex === totalActiveClassBasedAnimations - 1 ) {
113
+ // we need to sort each of the animations in order of parent to child
114
+ // relationships. This ensures that the child classes are applied at the
115
+ // right time.
116
+ classBasedAnimationsQueue = classBasedAnimationsQueue . sort ( function ( a , b ) {
117
+ return b . node . contains ( a . node ) ;
118
+ } ) . map ( function ( entry ) {
119
+ return entry . fn ;
120
+ } ) ;
121
+
122
+ $$rAFScheduler ( classBasedAnimationsQueue ) ;
123
+ }
124
+ }
125
+
126
+ function triggerAnimationStart ( ) {
127
+ // it's important that we apply the `ng-animate` CSS class and the
128
+ // temporary classes before we do any driver invoking since these
129
+ // CSS classes may be required for proper CSS detection.
130
+ animationEntry . beforeStart ( ) ;
131
+
132
+ var startAnimationFn , closeFn = animationEntry . close ;
133
+
134
+ // in the event that the element was removed before the digest runs or
135
+ // during the RAF sequencing then we should not trigger the animation.
136
+ var targetElement = animationEntry . anchors
137
+ ? ( animationEntry . from . element || animationEntry . to . element )
138
+ : animationEntry . element ;
139
+
140
+ if ( getRunner ( targetElement ) ) {
141
+ var operation = invokeFirstDriver ( animationEntry ) ;
142
+ if ( operation ) {
143
+ startAnimationFn = operation . start ;
144
+ }
145
+ }
146
+
147
+ if ( ! startAnimationFn ) {
148
+ closeFn ( ) ;
149
+ } else {
150
+ var animationRunner = startAnimationFn ( ) ;
151
+ animationRunner . done ( function ( status ) {
152
+ closeFn ( ! status ) ;
153
+ } ) ;
154
+ updateAnimationRunners ( animationEntry , animationRunner ) ;
155
+ }
107
156
}
108
157
} ) ;
109
158
} ) ;
@@ -175,7 +224,7 @@ var $$AnimationProvider = ['$animateProvider', function($animateProvider) {
175
224
var lookupKey = from . animationID . toString ( ) ;
176
225
if ( ! anchorGroups [ lookupKey ] ) {
177
226
var group = anchorGroups [ lookupKey ] = {
178
- // TODO(matsko): double-check this code
227
+ structural : true ,
179
228
beforeStart : function ( ) {
180
229
fromAnimation . beforeStart ( ) ;
181
230
toAnimation . beforeStart ( ) ;
0 commit comments