@@ -274,9 +274,9 @@ function $CompileProvider($provide) {
274
274
275
275
this . $get = [
276
276
'$injector' , '$interpolate' , '$exceptionHandler' , '$http' , '$templateCache' , '$parse' ,
277
- '$controller' , '$rootScope' , '$document' , '$sce' , '$$urlUtils' ,
277
+ '$controller' , '$rootScope' , '$document' , '$sce' , '$$urlUtils' , '$animate' ,
278
278
function ( $injector , $interpolate , $exceptionHandler , $http , $templateCache , $parse ,
279
- $controller , $rootScope , $document , $sce , $$urlUtils ) {
279
+ $controller , $rootScope , $document , $sce , $$urlUtils , $animate ) {
280
280
281
281
var Attributes = function ( element , attr ) {
282
282
this . $$element = element ;
@@ -287,6 +287,42 @@ function $CompileProvider($provide) {
287
287
$normalize : directiveNormalize ,
288
288
289
289
290
+ /**
291
+ * @ngdoc function
292
+ * @name ng.$compile.directive.Attributes#$addClass
293
+ * @methodOf ng.$compile.directive.Attributes
294
+ * @function
295
+ *
296
+ * @description
297
+ * Adds the CSS class value specified by the classVal parameter to the element. If animations
298
+ * are enabled then an animation will be triggered for the class addition.
299
+ *
300
+ * @param {string } classVal The className value that will be added to the element
301
+ */
302
+ $addClass : function ( classVal ) {
303
+ if ( classVal && classVal . length > 0 ) {
304
+ $animate . addClass ( this . $$element , classVal ) ;
305
+ }
306
+ } ,
307
+
308
+ /**
309
+ * @ngdoc function
310
+ * @name ng.$compile.directive.Attributes#$removeClass
311
+ * @methodOf ng.$compile.directive.Attributes
312
+ * @function
313
+ *
314
+ * @description
315
+ * Removes the CSS class value specified by the classVal parameter from the element. If animations
316
+ * are enabled then an animation will be triggered for the class removal.
317
+ *
318
+ * @param {string } classVal The className value that will be removed from the element
319
+ */
320
+ $removeClass : function ( classVal ) {
321
+ if ( classVal && classVal . length > 0 ) {
322
+ $animate . removeClass ( this . $$element , classVal ) ;
323
+ }
324
+ } ,
325
+
290
326
/**
291
327
* Set a normalized attribute on the element in a way such that all directives
292
328
* can share the attribute. This function properly handles boolean attributes.
@@ -297,61 +333,87 @@ function $CompileProvider($provide) {
297
333
* @param {string= } attrName Optional none normalized name. Defaults to key.
298
334
*/
299
335
$set : function ( key , value , writeAttr , attrName ) {
300
- var booleanKey = getBooleanAttrName ( this . $$element [ 0 ] , key ) ,
301
- $$observers = this . $$observers ,
302
- normalizedVal ,
303
- nodeName ;
304
-
305
- if ( booleanKey ) {
306
- this . $$element . prop ( key , value ) ;
307
- attrName = booleanKey ;
308
- }
336
+ //special case for class attribute addition + removal
337
+ //so that class changes can tap into the animation
338
+ //hooks provided by the $animate service
339
+ if ( key == 'class' ) {
340
+ value = value || '' ;
341
+ var current = this . $$element . attr ( 'class' ) || '' ;
342
+ this . $removeClass ( tokenDifference ( current , value ) . join ( ' ' ) ) ;
343
+ this . $addClass ( tokenDifference ( value , current ) . join ( ' ' ) ) ;
344
+ } else {
345
+ var booleanKey = getBooleanAttrName ( this . $$element [ 0 ] , key ) ,
346
+ normalizedVal ,
347
+ nodeName ;
309
348
310
- this [ key ] = value ;
349
+ if ( booleanKey ) {
350
+ this . $$element . prop ( key , value ) ;
351
+ attrName = booleanKey ;
352
+ }
311
353
312
- // translate normalized key to actual key
313
- if ( attrName ) {
314
- this . $attr [ key ] = attrName ;
315
- } else {
316
- attrName = this . $attr [ key ] ;
317
- if ( ! attrName ) {
318
- this . $attr [ key ] = attrName = snake_case ( key , '-' ) ;
354
+ this [ key ] = value ;
355
+
356
+ // translate normalized key to actual key
357
+ if ( attrName ) {
358
+ this . $attr [ key ] = attrName ;
359
+ } else {
360
+ attrName = this . $attr [ key ] ;
361
+ if ( ! attrName ) {
362
+ this . $attr [ key ] = attrName = snake_case ( key , '-' ) ;
363
+ }
319
364
}
320
- }
321
365
322
- nodeName = nodeName_ ( this . $$element ) ;
323
-
324
- // sanitize a[href] and img[src] values
325
- if ( ( nodeName === 'A' && key === 'href' ) ||
326
- ( nodeName === 'IMG' && key === 'src' ) ) {
327
- // NOTE: $$urlUtils.resolve() doesn't support IE < 8 so we don't sanitize for that case.
328
- if ( ! msie || msie >= 8 ) {
329
- normalizedVal = $$urlUtils . resolve ( value ) ;
330
- if ( normalizedVal !== '' ) {
331
- if ( ( key === 'href' && ! normalizedVal . match ( aHrefSanitizationWhitelist ) ) ||
332
- ( key === 'src' && ! normalizedVal . match ( imgSrcSanitizationWhitelist ) ) ) {
333
- this [ key ] = value = 'unsafe:' + normalizedVal ;
366
+ nodeName = nodeName_ ( this . $$element ) ;
367
+
368
+ // sanitize a[href] and img[src] values
369
+ if ( ( nodeName === 'A' && key === 'href' ) ||
370
+ ( nodeName === 'IMG' && key === 'src' ) ) {
371
+ // NOTE: $$urlUtils.resolve() doesn't support IE < 8 so we don't sanitize for that case.
372
+ if ( ! msie || msie >= 8 ) {
373
+ normalizedVal = $$urlUtils . resolve ( value ) ;
374
+ if ( normalizedVal !== '' ) {
375
+ if ( ( key === 'href' && ! normalizedVal . match ( aHrefSanitizationWhitelist ) ) ||
376
+ ( key === 'src' && ! normalizedVal . match ( imgSrcSanitizationWhitelist ) ) ) {
377
+ this [ key ] = value = 'unsafe:' + normalizedVal ;
378
+ }
334
379
}
335
380
}
336
381
}
337
- }
338
382
339
- if ( writeAttr !== false ) {
340
- if ( value === null || value === undefined ) {
341
- this . $$element . removeAttr ( attrName ) ;
342
- } else {
343
- this . $$element . attr ( attrName , value ) ;
383
+ if ( writeAttr !== false ) {
384
+ if ( value === null || value === undefined ) {
385
+ this . $$element . removeAttr ( attrName ) ;
386
+ } else {
387
+ this . $$element . attr ( attrName , value ) ;
388
+ }
344
389
}
345
390
}
346
391
347
392
// fire observers
393
+ var $$observers = this . $$observers ;
348
394
$$observers && forEach ( $$observers [ key ] , function ( fn ) {
349
395
try {
350
396
fn ( value ) ;
351
397
} catch ( e ) {
352
398
$exceptionHandler ( e ) ;
353
399
}
354
400
} ) ;
401
+
402
+ function tokenDifference ( str1 , str2 ) {
403
+ var values = [ ] ,
404
+ tokens1 = str1 . split ( / \s + / ) ,
405
+ tokens2 = str2 . split ( / \s + / ) ;
406
+
407
+ outer:
408
+ for ( var i = 0 ; i < tokens1 . length ; i ++ ) {
409
+ var token = tokens1 [ i ] ;
410
+ for ( var j = 0 ; j < tokens2 . length ; j ++ ) {
411
+ if ( token == tokens2 [ j ] ) continue outer;
412
+ }
413
+ values . push ( token ) ;
414
+ }
415
+ return values ;
416
+ } ;
355
417
} ,
356
418
357
419
0 commit comments