@@ -81,9 +81,69 @@ var $AnimateProvider = ['$provide', function($provide) {
81
81
return this . $$classNameFilter ;
82
82
} ;
83
83
84
- this . $get = [ '$$q' , '$$asyncCallback' , function ( $$q , $$asyncCallback ) {
84
+ this . $get = [ '$$q' , '$$asyncCallback' , '$rootScope' , function ( $$q , $$asyncCallback , $rootScope ) {
85
85
86
86
var currentDefer ;
87
+ var ELEMENT_NODE = 1 ;
88
+
89
+ function extractElementNodes ( element ) {
90
+ var elements = new Array ( element . length ) ;
91
+ var count = 0 ;
92
+ for ( var i = 0 ; i < element . length ; i ++ ) {
93
+ var elm = element [ i ] ;
94
+ if ( elm . nodeType == ELEMENT_NODE ) {
95
+ elements [ count ++ ] = elm ;
96
+ }
97
+ }
98
+ elements . length = count ;
99
+ return jqLite ( elements ) ;
100
+ }
101
+
102
+ function runAnimationPostDigest ( fn ) {
103
+ var cancelFn , defer = $$q . defer ( ) ;
104
+ if ( ! $rootScope . $$phase ) {
105
+ fn ( noop ) ;
106
+ defer . resolve ( ) ;
107
+ }
108
+ defer . promise . $$cancelFn = function ngAnimateMaybeCancel ( ) {
109
+ cancelFn && cancelFn ( ) ;
110
+ } ;
111
+ $rootScope . $$postDigest ( function ngAnimatePostDigest ( ) {
112
+ cancelFn = fn ( function ngAnimateNotifyComplete ( ) {
113
+ defer . resolve ( ) ;
114
+ } ) ;
115
+ } ) ;
116
+ return defer . promise ;
117
+ }
118
+
119
+ function resolveElementClasses ( element , cache ) {
120
+ var map = { } ;
121
+
122
+ forEach ( cache . add , function ( className ) {
123
+ if ( className && className . length ) {
124
+ map [ className ] = map [ className ] || 0 ;
125
+ map [ className ] ++ ;
126
+ }
127
+ } ) ;
128
+
129
+ forEach ( cache . remove , function ( className ) {
130
+ if ( className && className . length ) {
131
+ map [ className ] = map [ className ] || 0 ;
132
+ map [ className ] -- ;
133
+ }
134
+ } ) ;
135
+
136
+ var toAdd = [ ] , toRemove = [ ] ;
137
+ forEach ( map , function ( status , className ) {
138
+ var hasClass = jqLiteHasClass ( element [ 0 ] , className ) ;
139
+
140
+ if ( status < 0 && hasClass ) toRemove . push ( className ) ;
141
+ else if ( status > 0 && ! hasClass ) toAdd . push ( className ) ;
142
+ } ) ;
143
+
144
+ return ( toAdd . length + toRemove . length ) > 0 && [ toAdd . join ( ' ' ) , toRemove . join ( ' ' ) ] ;
145
+ }
146
+
87
147
function asyncPromise ( ) {
88
148
// only serve one instance of a promise in order to save CPU cycles
89
149
if ( ! currentDefer ) {
@@ -187,6 +247,11 @@ var $AnimateProvider = ['$provide', function($provide) {
187
247
* @return {Promise } the animation callback promise
188
248
*/
189
249
addClass : function ( element , className ) {
250
+ return this . setClass ( element , className , [ ] ) ;
251
+ } ,
252
+
253
+ $$addClassImmediately : function addClassImmediately ( element , className ) {
254
+ element = jqLite ( element ) ;
190
255
className = ! isString ( className )
191
256
? ( isArray ( className ) ? className . join ( ' ' ) : '' )
192
257
: className ;
@@ -209,6 +274,11 @@ var $AnimateProvider = ['$provide', function($provide) {
209
274
* @return {Promise } the animation callback promise
210
275
*/
211
276
removeClass : function ( element , className ) {
277
+ return this . setClass ( element , [ ] , className ) ;
278
+ } ,
279
+
280
+ $$removeClassImmediately : function removeClassImmediately ( element , className ) {
281
+ element = jqLite ( element ) ;
212
282
className = ! isString ( className )
213
283
? ( isArray ( className ) ? className . join ( ' ' ) : '' )
214
284
: className ;
@@ -232,9 +302,39 @@ var $AnimateProvider = ['$provide', function($provide) {
232
302
* @return {Promise } the animation callback promise
233
303
*/
234
304
setClass : function ( element , add , remove ) {
235
- this . addClass ( element , add ) ;
236
- this . removeClass ( element , remove ) ;
237
- return asyncPromise ( ) ;
305
+ var self = this ;
306
+ var STORAGE_KEY = '$$animateClasses' ;
307
+ element = extractElementNodes ( jqLite ( element ) ) ;
308
+
309
+ add = isArray ( add ) ? add : add . split ( ' ' ) ;
310
+ remove = isArray ( remove ) ? remove : remove . split ( ' ' ) ;
311
+
312
+ var cache = element . data ( STORAGE_KEY ) ;
313
+ if ( cache ) {
314
+ cache . add = cache . add . concat ( add ) ;
315
+ cache . remove = cache . remove . concat ( remove ) ;
316
+ //the digest cycle will combine all the animations into one function
317
+ return cache . promise ;
318
+ } else {
319
+ element . data ( STORAGE_KEY , cache = {
320
+ add : add ,
321
+ remove : remove
322
+ } ) ;
323
+ }
324
+
325
+ return cache . promise = runAnimationPostDigest ( function ( done ) {
326
+ var cache = element . data ( STORAGE_KEY ) ;
327
+ element . removeData ( STORAGE_KEY ) ;
328
+
329
+ var classes = cache && resolveElementClasses ( element , cache ) ;
330
+
331
+ if ( classes ) {
332
+ if ( classes [ 0 ] . length ) self . $$addClassImmediately ( element , classes [ 0 ] ) ;
333
+ if ( classes [ 1 ] . length ) self . $$removeClassImmediately ( element , classes [ 1 ] ) ;
334
+ }
335
+
336
+ done ( ) ;
337
+ } ) ;
238
338
} ,
239
339
240
340
enabled : noop ,
0 commit comments