Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(333)

Side by Side Diff: pkg/mdv/lib/src/template_iterator.dart

Issue 19492018: [mdv] Avoid observing placeholder arrays in TemplateIterator (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 7 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « pkg/mdv/lib/src/list_diff.dart ('k') | pkg/mdv/test/template_element_test.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 part of mdv; 5 part of mdv;
6 6
7 // This code is a port of Model-Driven-Views: 7 // This code is a port of Model-Driven-Views:
8 // https://github.com/polymer-project/mdv 8 // https://github.com/polymer-project/mdv
9 // The code mostly comes from src/template_element.js 9 // The code mostly comes from src/template_element.js
10 10
(...skipping 172 matching lines...) Expand 10 before | Expand all | Expand 10 after
183 final bool isBinding; 183 final bool isBinding;
184 184
185 _BindingToken(this.value, {this.isBinding: false}); 185 _BindingToken(this.value, {this.isBinding: false});
186 186
187 bool get isText => !isBinding; 187 bool get isText => !isBinding;
188 } 188 }
189 189
190 class _TemplateIterator { 190 class _TemplateIterator {
191 final Element _templateElement; 191 final Element _templateElement;
192 final List<Node> terminators = []; 192 final List<Node> terminators = [];
193 final CompoundBinding inputs; 193 CompoundBinding inputs;
194 List iteratedValue; 194 List iteratedValue;
195 Object _lastValue; 195 bool closed = false;
196 196
197 StreamSubscription _sub; 197 StreamSubscription _sub;
198 StreamSubscription _valueBinding;
199 198
200 _TemplateIterator(this._templateElement) 199 _TemplateIterator(this._templateElement) {
201 : inputs = new CompoundBinding(resolveInputs) { 200 inputs = new CompoundBinding(resolveInputs);
202
203 _valueBinding = new PathObserver(inputs, 'value').bindSync(valueChanged);
204 } 201 }
205 202
206 static Object resolveInputs(Map values) { 203 void resolveInputs(Map values) {
204 if (closed) return;
205
207 if (values.containsKey('if') && !_toBoolean(values['if'])) { 206 if (values.containsKey('if') && !_toBoolean(values['if'])) {
208 return null; 207 valueChanged(null);
208 } else if (values.containsKey('repeat')) {
209 valueChanged(values['repeat']);
210 } else if (values.containsKey('bind') || values.containsKey('if')) {
211 valueChanged([values['bind']]);
212 } else {
213 valueChanged(null);
209 } 214 }
210
211 if (values.containsKey('repeat')) {
212 return values['repeat'];
213 }
214
215 if (values.containsKey('bind') || values.containsKey('if')) {
216 return [values['bind']];
217 }
218
219 return null;
220 } 215 }
221 216
222 void valueChanged(value) { 217 void valueChanged(value) {
223 // TODO(jmesserly): should PathObserver do this for us? 218 if (value is! List) value = null;
224 var oldValue = _lastValue;
225 _lastValue = value;
226 219
227 if (value is! List) { 220 var oldValue = iteratedValue;
228 value = [];
229 }
230
231 unobserve(); 221 unobserve();
232 iteratedValue = value; 222 iteratedValue = value;
233 223
234 if (value is Observable) { 224 if (iteratedValue is Observable) {
235 _sub = value.changes.listen(_handleChanges); 225 _sub = iteratedValue.changes.listen(_handleChanges);
236 } 226 }
237 227
238 int addedCount = iteratedValue.length; 228 var splices = calculateSplices(
239 var removedCount = oldValue is List ? (oldValue as List).length : 0; 229 iteratedValue != null ? iteratedValue : [],
240 if (addedCount == 0 && removedCount == 0) return; // nothing to do. 230 oldValue != null ? oldValue : []);
241 231
242 _handleChanges([new ListChangeRecord(0, addedCount: addedCount, 232 if (splices.length > 0) _handleChanges(splices);
243 removedCount: removedCount)]); 233
234 if (inputs.length == 0) {
235 close();
236 _mdv(_templateElement)._templateIterator = null;
237 }
244 } 238 }
245 239
246 Node getTerminatorAt(int index) { 240 Node getTerminatorAt(int index) {
247 if (index == -1) return _templateElement; 241 if (index == -1) return _templateElement;
248 var terminator = terminators[index]; 242 var terminator = terminators[index];
249 if (terminator is Element && (terminator as Element).isTemplate && 243 if (terminator is Element && (terminator as Element).isTemplate &&
250 !identical(terminator, _templateElement)) { 244 !identical(terminator, _templateElement)) {
251 var subIterator = _mdv(terminator)._templateIterator; 245 var subIterator = _mdv(terminator)._templateIterator;
252 if (subIterator != null) { 246 if (subIterator != null) {
253 return subIterator.getTerminatorAt(subIterator.terminators.length - 1); 247 return subIterator.getTerminatorAt(subIterator.terminators.length - 1);
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after
305 return delegate.getInstanceModel(_templateElement, model); 299 return delegate.getInstanceModel(_templateElement, model);
306 } 300 }
307 return model; 301 return model;
308 } 302 }
309 303
310 DocumentFragment getInstanceFragment(model, BindingDelegate delegate) { 304 DocumentFragment getInstanceFragment(model, BindingDelegate delegate) {
311 return _templateElement.createInstance(model, delegate); 305 return _templateElement.createInstance(model, delegate);
312 } 306 }
313 307
314 void _handleChanges(Iterable<ChangeRecord> splices) { 308 void _handleChanges(Iterable<ChangeRecord> splices) {
309 if (closed) return;
310
315 splices = splices.where((s) => s is ListChangeRecord); 311 splices = splices.where((s) => s is ListChangeRecord);
316 312
317 var template = _templateElement; 313 var template = _templateElement;
318 var delegate = template.bindingDelegate; 314 var delegate = template.bindingDelegate;
319 315
320 if (template.parentNode == null || template.document.window == null) { 316 if (template.parentNode == null || template.document.window == null) {
321 abandon(); 317 close();
322 // TODO(jmesserly): MDV calls templateIteratorTable.delete(this) here, 318 // TODO(jmesserly): MDV calls templateIteratorTable.delete(this) here,
323 // but I think that's a no-op because only nodes are used as keys. 319 // but I think that's a no-op because only nodes are used as keys.
324 // See https://github.com/Polymer/mdv/pull/114. 320 // See https://github.com/Polymer/mdv/pull/114.
325 return; 321 return;
326 } 322 }
327 323
328 // TODO(jmesserly): IdentityMap matches JS semantics, but it's O(N) right 324 // TODO(jmesserly): IdentityMap matches JS semantics, but it's O(N) right
329 // now. See http://dartbug.com/4161. 325 // now. See http://dartbug.com/4161.
330 var instanceCache = new IdentityMap(); 326 var instanceCache = new IdentityMap();
331 var removeDelta = 0; 327 var removeDelta = 0;
(...skipping 29 matching lines...) Expand all
361 instanceNodes.forEach(_unbindAllRecursively); 357 instanceNodes.forEach(_unbindAllRecursively);
362 } 358 }
363 } 359 }
364 360
365 void unobserve() { 361 void unobserve() {
366 if (_sub == null) return; 362 if (_sub == null) return;
367 _sub.cancel(); 363 _sub.cancel();
368 _sub = null; 364 _sub = null;
369 } 365 }
370 366
371 void abandon() { 367 void close() {
368 if (closed) return;
369
372 unobserve(); 370 unobserve();
373 _valueBinding.cancel();
374 terminators.clear(); 371 terminators.clear();
375 inputs.dispose(); 372 inputs.dispose();
373 closed = true;
376 } 374 }
377 375
378 static void _unbindAllRecursively(Node node) { 376 static void _unbindAllRecursively(Node node) {
379 var nodeExt = _mdv(node); 377 var nodeExt = _mdv(node);
380 nodeExt._templateInstance = null; 378 nodeExt._templateInstance = null;
381 if (node is Element && (node as Element).isTemplate) { 379 if (node is Element && (node as Element).isTemplate) {
382 // Make sure we stop observing when we remove an element. 380 // Make sure we stop observing when we remove an element.
383 var templateIterator = nodeExt._templateIterator; 381 var templateIterator = nodeExt._templateIterator;
384 if (templateIterator != null) { 382 if (templateIterator != null) {
385 templateIterator.abandon(); 383 templateIterator.close();
386 nodeExt._templateIterator = null; 384 nodeExt._templateIterator = null;
387 } 385 }
388 } 386 }
389 387
390 _nodeOrCustom(node).unbindAll(); 388 _nodeOrCustom(node).unbindAll();
391 for (var c = node.firstChild; c != null; c = c.nextNode) { 389 for (var c = node.firstChild; c != null; c = c.nextNode) {
392 _unbindAllRecursively(c); 390 _unbindAllRecursively(c);
393 } 391 }
394 } 392 }
395 } 393 }
OLDNEW
« no previous file with comments | « pkg/mdv/lib/src/list_diff.dart ('k') | pkg/mdv/test/template_element_test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698