@@ -67,9 +67,8 @@ part of angular.directive;
67
67
map: const {'ng-class' : '@valueExpression' },
68
68
exportExpressionAttrs: const ['ng-class' ])
69
69
class NgClassDirective extends _NgClassBase {
70
- NgClassDirective (dom.Element element, Scope scope, NodeAttrs attrs,
71
- NgAnimate animate)
72
- : super (element, scope, null , attrs, animate);
70
+ NgClassDirective (NgElement ngElement, Scope scope)
71
+ : super (ngElement, scope);
73
72
}
74
73
75
74
/**
@@ -103,9 +102,8 @@ class NgClassDirective extends _NgClassBase {
103
102
map: const {'ng-class-odd' : '@valueExpression' },
104
103
exportExpressionAttrs: const ['ng-class-odd' ])
105
104
class NgClassOddDirective extends _NgClassBase {
106
- NgClassOddDirective (dom.Element element, Scope scope, NodeAttrs attrs,
107
- NgAnimate animate)
108
- : super (element, scope, 0 , attrs, animate);
105
+ NgClassOddDirective (NgElement ngElement, Scope scope)
106
+ : super (ngElement, scope, 0 );
109
107
}
110
108
111
109
/**
@@ -139,95 +137,125 @@ class NgClassOddDirective extends _NgClassBase {
139
137
map: const {'ng-class-even' : '@valueExpression' },
140
138
exportExpressionAttrs: const ['ng-class-even' ])
141
139
class NgClassEvenDirective extends _NgClassBase {
142
- NgClassEvenDirective (dom.Element element, Scope scope, NodeAttrs attrs,
143
- NgAnimate animate)
144
- : super (element, scope, 1 , attrs, animate);
140
+ NgClassEvenDirective (NgElement ngElement, Scope scope)
141
+ : super (ngElement, scope, 1 );
145
142
}
146
143
147
144
abstract class _NgClassBase {
148
- final dom. Element element ;
149
- final Scope scope ;
150
- final int mode ;
151
- final NodeAttrs nodeAttrs ;
152
- final NgAnimate _animate ;
153
- var previousSet = [] ;
154
- var currentSet = [] ;
155
- Watch _watch ;
145
+ final NgElement _ngElement ;
146
+ final Scope _scope ;
147
+ final int _mode ;
148
+ Watch _watchExpression ;
149
+ Watch _watchPosition ;
150
+ Set < String > _previousSet ;
151
+ var _currentSet = new Set < String >() ;
152
+ bool _first = true ;
156
153
157
- _NgClassBase (this .element, this .scope, this .mode, this .nodeAttrs,
158
- this ._animate)
159
- {
160
- var prevClass;
161
-
162
- nodeAttrs.observe ('class' , (String newValue) {
163
- if (prevClass != newValue) {
164
- prevClass = newValue;
165
- _handleChange (scope.context[r'$index' ]);
166
- }
167
- });
168
- }
154
+ _NgClassBase (this ._ngElement, this ._scope, [this ._mode = null ]);
169
155
170
156
set valueExpression (expression) {
171
- if (_watch != null ) _watch .remove ();
172
- _watch = scope .watch (expression, (current , _) {
173
- currentSet = _flatten (current );
174
- _handleChange (scope .context[r'$index' ]);
175
- },
176
- canChangeModel: false ,
177
- collection: true );
157
+ if (_watchExpression != null ) _watchExpression .remove ();
158
+ _watchExpression = _scope .watch (expression, (v , _) {
159
+ _computeChanges (v );
160
+ _applyChanges (_scope .context[r'$index' ]);
161
+ },
162
+ canChangeModel: false ,
163
+ collection: true );
178
164
179
- if (mode != null ) {
180
- scope.watch (r'$index' , (index, oldIndex) {
181
- var mod = index % 2 ;
182
- if (oldIndex == null || mod != oldIndex % 2 ) {
183
- if (mod == mode) {
184
- currentSet.forEach ((css) => _animate.addClass (element, css));
165
+ if (_mode != null ) {
166
+ if (_watchPosition != null ) _watchPosition.remove ();
167
+ _watchPosition = _scope.watch (r'$index' , (idx, previousIdx) {
168
+ var mod = idx % 2 ;
169
+ if (previousIdx == null || mod != previousIdx % 2 ) {
170
+ if (mod == _mode) {
171
+ _currentSet.forEach ((cls) => _ngElement.addClass (cls));
185
172
} else {
186
- previousSet .forEach ((css ) => _animate .removeClass (element, css ));
173
+ _previousSet .forEach ((cls ) => _ngElement .removeClass (cls ));
187
174
}
188
175
}
189
176
}, canChangeModel: false );
190
177
}
191
178
}
192
179
193
- _handleChange (index) {
194
- if (mode == null || (index != null && index % 2 == mode)) {
195
- previousSet.forEach ((css) {
196
- if (! currentSet.contains (css)) {
197
- _animate.removeClass (element, css);
198
- } else {
199
- element.classes.remove (css);
200
- }
201
- });
180
+ void _computeChanges (value) {
181
+ _previousSet = _currentSet.toSet ();
202
182
203
- currentSet.forEach ((css) {
204
- if (! previousSet.contains (css)) {
205
- _animate.addClass (element, css);
206
- } else {
207
- element.classes.add (css);
208
- }
209
- });
183
+ if (value is CollectionChangeRecord ) {
184
+ _computeCollectionChanges (value, _first);
185
+ } else if (value is MapChangeRecord ) {
186
+ _computeMapChanges (value, _first);
187
+ } else {
188
+ if (value is String ) {
189
+ _currentSet..clear ()..addAll (value.split (' ' ));
190
+ } else if (value == null ) {
191
+ _currentSet.clear ();
192
+ } else {
193
+ throw 'ng-class expects expression value to be List, Map or String, '
194
+ 'got $value ' ;
195
+ }
210
196
}
211
197
212
- previousSet = currentSet ;
198
+ _first = false ;
213
199
}
214
200
215
- static List <String > _flatten (classes) {
216
- if (classes == null ) return [];
217
- if (classes is CollectionChangeRecord ) {
218
- classes = (classes as CollectionChangeRecord ).iterable.toList ();
219
- }
220
- if (classes is List ) {
221
- return classes
222
- .where ((String e) => e != null && e.isNotEmpty)
223
- .toList (growable: false );
201
+ // todo(vicb) refactor once GH-774 gets fixed
202
+ void _computeCollectionChanges (CollectionChangeRecord changes, bool first) {
203
+ if (first) {
204
+ changes.iterable.forEach ((cls) {
205
+ _currentSet.add (cls);
206
+ });
207
+ } else {
208
+ changes.forEachAddition ((AddedItem a) {
209
+ _currentSet.add (a.item);
210
+ });
211
+ changes.forEachRemoval ((RemovedItem r) {
212
+ _currentSet.remove (r.item);
213
+ });
224
214
}
225
- if (classes is MapChangeRecord ) classes = (classes as MapChangeRecord ).map;
226
- if (classes is Map ) {
227
- return classes.keys.where ((key) => toBool (classes[key])).toList ();
215
+ }
216
+
217
+ // todo(vicb) refactor once GH-774 gets fixed
218
+ _computeMapChanges (MapChangeRecord changes, first) {
219
+ if (first) {
220
+ changes.map.forEach ((cls, active) {
221
+ if (toBool (active)) {
222
+ _currentSet.add (cls);
223
+ }
224
+ });
225
+ } else {
226
+ changes.forEachChange ((ChangedKeyValue kv) {
227
+ var cls = kv.key;
228
+ var active = toBool (kv.currentValue);
229
+ var wasActive = toBool (kv.previousValue);
230
+ if (active != wasActive) {
231
+ if (active) {
232
+ _currentSet.add (cls);
233
+ } else {
234
+ _currentSet.remove (cls);
235
+ }
236
+ }
237
+ });
238
+ changes.forEachAddition ((AddedKeyValue kv) {
239
+ if (toBool (kv.currentValue)) {
240
+ _currentSet.add (kv.key);
241
+ }
242
+ });
243
+ changes.forEachRemoval ((RemovedKeyValue kv) {
244
+ if (toBool (kv.previousValue)) {
245
+ _currentSet.remove (kv.key);
246
+ }
247
+ });
228
248
}
229
- if (classes is String ) return classes.split (' ' );
230
- throw 'ng-class expects expression value to be List, Map or String, '
231
- 'got $classes ' ;
232
249
}
233
- }
250
+
251
+ _applyChanges (index) {
252
+ if (_mode == null || (index != null && index % 2 == _mode)) {
253
+ _previousSet
254
+ .where ((cls) => cls != null )
255
+ .forEach ((cls) => _ngElement.removeClass (cls));
256
+ _currentSet
257
+ .where ((cls) => cls != null )
258
+ .forEach ((cls) => _ngElement.addClass (cls));
259
+ }
260
+ }
261
+ }
0 commit comments