@@ -86,6 +86,19 @@ var $AnimateProvider = ['$provide', function($provide) {
86
86
var currentDefer ;
87
87
var ELEMENT_NODE = 1 ;
88
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
+
89
102
function runAnimationPostDigest ( fn ) {
90
103
var cancelFn , defer = $$q . defer ( ) ;
91
104
defer . promise . $$cancelFn = function ngAnimateMaybeCancel ( ) {
@@ -102,33 +115,31 @@ var $AnimateProvider = ['$provide', function($provide) {
102
115
}
103
116
104
117
function resolveElementClasses ( element , cache ) {
105
- var map = { } ;
106
-
107
- forEach ( cache . add , function ( className ) {
108
- if ( className && className . length ) {
109
- map [ className ] = map [ className ] || 0 ;
110
- map [ className ] ++ ;
111
- }
112
- } ) ;
113
-
114
- forEach ( cache . remove , function ( className ) {
115
- if ( className && className . length ) {
116
- map [ className ] = map [ className ] || 0 ;
117
- map [ className ] -- ;
118
- }
119
- } ) ;
120
-
121
118
var toAdd = [ ] , toRemove = [ ] ;
122
- forEach ( map , function ( status , className ) {
119
+ forEach ( cache . classes , function ( status , className ) {
123
120
var hasClass = jqLiteHasClass ( element [ 0 ] , className ) ;
124
121
125
- if ( status < 0 && hasClass ) toRemove . push ( className ) ;
126
- else if ( status > 0 && ! hasClass ) toAdd . push ( className ) ;
122
+ // If the most recent class manipulation (via $animate) was to remove the class, and the
123
+ // element currently has the class, the class is scheduled for removal. Otherwise, if
124
+ // the most recent class manipulation (via $animate) was to add the class, and the
125
+ // element does not currently have the class, the class is scheduled to be added.
126
+ if ( status === false && hasClass ) {
127
+ toRemove . push ( className ) ;
128
+ } else if ( status === true && ! hasClass ) {
129
+ toAdd . push ( className ) ;
130
+ }
127
131
} ) ;
128
132
129
133
return ( toAdd . length + toRemove . length ) > 0 && [ toAdd . join ( ' ' ) , toRemove . join ( ' ' ) ] ;
130
134
}
131
135
136
+ function cachedClassManipulation ( cache , classes , op ) {
137
+ for ( var i = 0 , ii = classes . length ; i < ii ; ++ i ) {
138
+ var className = classes [ i ] ;
139
+ cache [ className ] = op ;
140
+ }
141
+ }
142
+
132
143
function asyncPromise ( ) {
133
144
// only serve one instance of a promise in order to save CPU cycles
134
145
if ( ! currentDefer ) {
@@ -285,40 +296,50 @@ var $AnimateProvider = ['$provide', function($provide) {
285
296
* @param {string } remove the CSS class which will be removed from the element
286
297
* @return {Promise } the animation callback promise
287
298
*/
288
- setClass : function ( element , add , remove ) {
299
+ setClass : function ( element , add , remove , runSynchronously ) {
289
300
var self = this ;
290
301
var STORAGE_KEY = '$$animateClasses' ;
291
- element = jqLite ( element ) ;
302
+ element = extractElementNodes ( jqLite ( element ) ) ;
292
303
293
- add = isArray ( add ) ? add : add . split ( ' ' ) ;
294
- remove = isArray ( remove ) ? remove : remove . split ( ' ' ) ;
304
+ if ( runSynchronously ) {
305
+ self . $$addClassImmediately ( element , add ) ;
306
+ self . $$removeClassImmediately ( element , remove ) ;
307
+ return asyncPromise ( ) ;
308
+ }
295
309
296
310
var cache = element . data ( STORAGE_KEY ) ;
297
- if ( cache ) {
298
- cache . add = cache . add . concat ( add ) ;
299
- cache . remove = cache . remove . concat ( remove ) ;
300
- //the digest cycle will combine all the animations into one function
301
- return cache . promise ;
302
- } else {
303
- element . data ( STORAGE_KEY , cache = {
304
- add : add ,
305
- remove : remove
306
- } ) ;
311
+ if ( ! cache ) {
312
+ cache = {
313
+ classes : { }
314
+ } ;
315
+ var createdCache = true ;
307
316
}
308
317
309
- return cache . promise = runAnimationPostDigest ( function ( done ) {
310
- var cache = element . data ( STORAGE_KEY ) ;
311
- element . removeData ( STORAGE_KEY ) ;
318
+ var classes = cache . classes ;
319
+
320
+ add = isArray ( add ) ? add : add . split ( ' ' ) ;
321
+ remove = isArray ( remove ) ? remove : remove . split ( ' ' ) ;
322
+ cachedClassManipulation ( classes , add , true ) ;
323
+ cachedClassManipulation ( classes , remove , false ) ;
312
324
313
- var classes = cache && resolveElementClasses ( element , cache ) ;
325
+ if ( createdCache ) {
326
+ cache . promise = runAnimationPostDigest ( function ( done ) {
327
+ var cache = element . data ( STORAGE_KEY ) ;
328
+ element . removeData ( STORAGE_KEY ) ;
314
329
315
- if ( classes ) {
316
- if ( classes [ 0 ] ) self . $$addClassImmediately ( element , classes [ 0 ] ) ;
317
- if ( classes [ 1 ] ) self . $$removeClassImmediately ( element , classes [ 1 ] ) ;
318
- }
330
+ var classes = cache && resolveElementClasses ( element , cache ) ;
319
331
320
- done ( ) ;
321
- } ) ;
332
+ if ( classes ) {
333
+ if ( classes [ 0 ] ) self . $$addClassImmediately ( element , classes [ 0 ] ) ;
334
+ if ( classes [ 1 ] ) self . $$removeClassImmediately ( element , classes [ 1 ] ) ;
335
+ }
336
+
337
+ done ( ) ;
338
+ } ) ;
339
+ element . data ( STORAGE_KEY , cache ) ;
340
+ }
341
+
342
+ return cache . promise ;
322
343
} ,
323
344
324
345
enabled : noop ,
0 commit comments