@@ -81,9 +81,69 @@ var $AnimateProvider = ['$provide', function($provide) {
8181 return this . $$classNameFilter ;
8282 } ;
8383
84- this . $get = [ '$$q' , '$$asyncCallback' , function ( $$q , $$asyncCallback ) {
84+ this . $get = [ '$$q' , '$$asyncCallback' , '$rootScope' , function ( $$q , $$asyncCallback , $rootScope ) {
8585
8686 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+
87147 function asyncPromise ( ) {
88148 // only serve one instance of a promise in order to save CPU cycles
89149 if ( ! currentDefer ) {
@@ -187,6 +247,11 @@ var $AnimateProvider = ['$provide', function($provide) {
187247 * @return {Promise } the animation callback promise
188248 */
189249 addClass : function ( element , className ) {
250+ return this . setClass ( element , className , [ ] ) ;
251+ } ,
252+
253+ $$addClassImmediately : function addClassImmediately ( element , className ) {
254+ element = jqLite ( element ) ;
190255 className = ! isString ( className )
191256 ? ( isArray ( className ) ? className . join ( ' ' ) : '' )
192257 : className ;
@@ -209,6 +274,11 @@ var $AnimateProvider = ['$provide', function($provide) {
209274 * @return {Promise } the animation callback promise
210275 */
211276 removeClass : function ( element , className ) {
277+ return this . setClass ( element , [ ] , className ) ;
278+ } ,
279+
280+ $$removeClassImmediately : function removeClassImmediately ( element , className ) {
281+ element = jqLite ( element ) ;
212282 className = ! isString ( className )
213283 ? ( isArray ( className ) ? className . join ( ' ' ) : '' )
214284 : className ;
@@ -232,9 +302,39 @@ var $AnimateProvider = ['$provide', function($provide) {
232302 * @return {Promise } the animation callback promise
233303 */
234304 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+ } ) ;
238338 } ,
239339
240340 enabled : noop ,
0 commit comments