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