2
2
3
3
function classDirective ( name , selector ) {
4
4
name = 'ngClass' + name ;
5
- return [ '$animate' , function ( $animate ) {
5
+ return [ '$animate' , '$parse' , function ( $animate , $parse ) {
6
6
return {
7
7
restrict : 'AC' ,
8
- link : function ( scope , element , attr ) {
9
- var oldVal ;
10
-
11
- scope . $watch ( attr [ name ] , ngClassWatchAction , true ) ;
12
-
13
- attr . $observe ( 'class' , function ( value ) {
14
- ngClassWatchAction ( scope . $eval ( attr [ name ] ) ) ;
8
+ compile : function ( tElement , tAttr ) {
9
+ var classFn = $parse ( tAttr [ name ] , function ( value ) {
10
+ return arrayClassesL1 ( value ) ;
15
11
} ) ;
12
+ return function ( scope , element , attr ) {
13
+ var oldClasses ;
16
14
17
15
18
- if ( name !== 'ngClass' ) {
19
- scope . $watch ( '$index' , function ( $index , old$index ) {
20
- // jshint bitwise: false
21
- var mod = $index & 1 ;
22
- if ( mod !== ( old$index & 1 ) ) {
23
- var classes = arrayClasses ( scope . $eval ( attr [ name ] ) ) ;
24
- mod === selector ?
25
- addClasses ( classes ) :
26
- removeClasses ( classes ) ;
27
- }
28
- } ) ;
29
- }
16
+ var unwatch = scope . $watch ( classFn , ngClassWatchAction , classArrayEquals ) ;
30
17
31
- function addClasses ( classes ) {
32
- var newClasses = digestClassCounts ( classes , 1 ) ;
33
- attr . $addClass ( newClasses ) ;
34
- }
18
+ attr . $observe ( 'class' , function ( value ) {
19
+ ngClassWatchAction ( classFn ( scope ) ) ;
20
+ } ) ;
35
21
36
- function removeClasses ( classes ) {
37
- var newClasses = digestClassCounts ( classes , - 1 ) ;
38
- attr . $removeClass ( newClasses ) ;
39
- }
40
22
41
- function digestClassCounts ( classes , count ) {
42
- // Use createMap() to prevent class assumptions involving property
43
- // names in Object.prototype
44
- var classCounts = element . data ( '$classCounts' ) || createMap ( ) ;
45
- var classesToUpdate = [ ] ;
46
- forEach ( classes , function ( className ) {
47
- if ( count > 0 || classCounts [ className ] ) {
48
- classCounts [ className ] = ( classCounts [ className ] || 0 ) + count ;
49
- if ( classCounts [ className ] === + ( count > 0 ) ) {
50
- classesToUpdate . push ( className ) ;
23
+ if ( name !== 'ngClass' ) {
24
+ scope . $watch ( '$index' , function ( $index , old$index ) {
25
+ // jshint bitwise: false
26
+ var mod = $index & 1 ;
27
+ if ( mod !== ( old$index & 1 ) ) {
28
+ var classes = classFn ( scope ) . join ( ' ' ) . split ( ' ' ) ;
29
+ mod === selector ?
30
+ addClasses ( classes ) :
31
+ removeClasses ( classes ) ;
51
32
}
52
- }
53
- } ) ;
54
- element . data ( '$classCounts' , classCounts ) ;
55
- return classesToUpdate . join ( ' ' ) ;
56
- }
33
+ } ) ;
34
+ }
57
35
58
- function updateClasses ( oldClasses , newClasses ) {
59
- var toAdd = arrayDifference ( newClasses , oldClasses ) ;
60
- var toRemove = arrayDifference ( oldClasses , newClasses ) ;
61
- toAdd = digestClassCounts ( toAdd , 1 ) ;
62
- toRemove = digestClassCounts ( toRemove , - 1 ) ;
63
- if ( toAdd && toAdd . length ) {
64
- $animate . addClass ( element , toAdd ) ;
36
+ function addClasses ( classes ) {
37
+ var newClasses = digestClassCounts ( classes , 1 ) ;
38
+ attr . $addClass ( newClasses ) ;
65
39
}
66
- if ( toRemove && toRemove . length ) {
67
- $animate . removeClass ( element , toRemove ) ;
40
+
41
+ function removeClasses ( classes ) {
42
+ var newClasses = digestClassCounts ( classes , - 1 ) ;
43
+ attr . $removeClass ( newClasses ) ;
44
+ }
45
+
46
+ function digestClassCounts ( classes , count ) {
47
+ // Use createMap() to prevent class assumptions involving property
48
+ // names in Object.prototype
49
+ var classCounts = element . data ( '$classCounts' ) || createMap ( ) ;
50
+ var classesToUpdate = [ ] ;
51
+ forEach ( classes , function ( className ) {
52
+ if ( count > 0 || classCounts [ className ] ) {
53
+ classCounts [ className ] = ( classCounts [ className ] || 0 ) + count ;
54
+ if ( classCounts [ className ] === + ( count > 0 ) ) {
55
+ classesToUpdate . push ( className ) ;
56
+ }
57
+ }
58
+ } ) ;
59
+ element . data ( '$classCounts' , classCounts ) ;
60
+ return classesToUpdate . join ( ' ' ) ;
68
61
}
69
- }
70
62
71
- function ngClassWatchAction ( newVal ) {
72
- // jshint bitwise: false
73
- if ( selector === true || ( scope . $index & 1 ) === selector ) {
74
- // jshint bitwise: true
75
- var newClasses = arrayClasses ( newVal || [ ] ) ;
76
- if ( ! oldVal ) {
77
- addClasses ( newClasses ) ;
78
- } else if ( ! equals ( newVal , oldVal ) ) {
79
- var oldClasses = arrayClasses ( oldVal ) ;
80
- updateClasses ( oldClasses , newClasses ) ;
63
+ function updateClasses ( oldClasses , newClasses ) {
64
+ var toAdd = arrayDifference ( newClasses , oldClasses ) ;
65
+ var toRemove = arrayDifference ( oldClasses , newClasses ) ;
66
+ toAdd = digestClassCounts ( toAdd , 1 ) ;
67
+ toRemove = digestClassCounts ( toRemove , - 1 ) ;
68
+ if ( toAdd && toAdd . length ) {
69
+ $animate . addClass ( element , toAdd ) ;
70
+ }
71
+ if ( toRemove && toRemove . length ) {
72
+ $animate . removeClass ( element , toRemove ) ;
81
73
}
82
74
}
83
- if ( isArray ( newVal ) ) {
84
- oldVal = newVal . map ( function ( v ) { return shallowCopy ( v ) ; } ) ;
85
- } else {
86
- oldVal = shallowCopy ( newVal ) ;
75
+
76
+ function ngClassWatchAction ( newVal ) {
77
+ // jshint bitwise: false
78
+ if ( selector === true || ( scope . $index & 1 ) === selector ) {
79
+ // jshint bitwise: true
80
+ var newClasses = ( newVal || [ ] ) . join ( ' ' ) . split ( ' ' ) ;
81
+ if ( ! oldClasses ) {
82
+ addClasses ( newClasses ) ;
83
+ } else if ( ! classArrayEquals ( oldClasses , newClasses ) ) {
84
+ updateClasses ( oldClasses , newClasses ) ;
85
+ }
86
+ oldClasses = shallowCopy ( newClasses ) ;
87
+ }
87
88
}
88
- }
89
+ } ;
89
90
}
90
91
} ;
91
92
@@ -103,25 +104,43 @@ function classDirective(name, selector) {
103
104
return values ;
104
105
}
105
106
106
- function arrayClasses ( classVal ) {
107
- var classes = [ ] ;
107
+ function arrayClassesL1 ( classVal ) {
108
+ var classes ;
108
109
if ( isArray ( classVal ) ) {
109
- forEach ( classVal , function ( v ) {
110
- classes = classes . concat ( arrayClasses ( v ) ) ;
111
- } ) ;
112
- return classes ;
113
- } else if ( isString ( classVal ) ) {
114
- return classVal . split ( ' ' ) ;
110
+ classes = classVal . map ( arrayClassesL2 ) ;
115
111
} else if ( isObject ( classVal ) ) {
116
- forEach ( classVal , function ( v , k ) {
117
- if ( v ) {
118
- classes = classes . concat ( k . split ( ' ' ) ) ;
112
+ classes = [ ] ;
113
+ forEach ( classVal , function ( val , key ) {
114
+ if ( val ) {
115
+ classes . push ( key ) ;
116
+ } else if ( isUndefined ( val ) ) {
117
+ classes . push ( val ) ;
119
118
}
120
119
} ) ;
121
- return classes ;
120
+ } else if ( isString ( classVal ) ) {
121
+ classes = [ classVal ] ;
122
+ } else {
123
+ classes = classVal ;
124
+ }
125
+
126
+ return classes ;
127
+ }
128
+
129
+ function arrayClassesL2 ( values ) {
130
+ if ( isObject ( values ) ) {
131
+ return Object . keys ( values ) . filter ( function ( k ) {
132
+ return values [ k ] ;
133
+ } ) . join ( ' ' ) ;
134
+ } else {
135
+ return values ;
122
136
}
123
- return classVal ;
124
137
}
138
+
139
+ function classArrayEquals ( a1 , a2 ) {
140
+ return a1 === a2 ||
141
+ isArray ( a1 ) && isArray ( a2 ) && a1 . join ( ' ' ) === a2 . join ( ' ' ) ;
142
+ }
143
+
125
144
} ] ;
126
145
}
127
146
0 commit comments