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

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

Issue 53743002: introduce ObservableList.listChanges to keep list changes separate from property changes (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 7 years, 1 month 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
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 template_binding; 5 part of template_binding;
6 6
7 // This code is a port of what was formerly known as Model-Driven-Views, now 7 // This code is a port of what was formerly known as Model-Driven-Views, now
8 // located at: 8 // located at:
9 // https://github.com/polymer/TemplateBinding 9 // https://github.com/polymer/TemplateBinding
10 // https://github.com/polymer/NodeBind 10 // https://github.com/polymer/NodeBind
(...skipping 226 matching lines...) Expand 10 before | Expand all | Expand 10 after
237 */ 237 */
238 final List terminators = []; 238 final List terminators = [];
239 List iteratedValue; 239 List iteratedValue;
240 bool closed = false; 240 bool closed = false;
241 bool depsChanging = false; 241 bool depsChanging = false;
242 242
243 bool hasRepeat = false, hasBind = false, hasIf = false; 243 bool hasRepeat = false, hasBind = false, hasIf = false;
244 Object repeatModel, bindModel, ifModel; 244 Object repeatModel, bindModel, ifModel;
245 String repeatPath, bindPath, ifPath; 245 String repeatPath, bindPath, ifPath;
246 246
247 StreamSubscription _valueSub, _arraySub; 247 StreamSubscription _valueSub, _listSub;
248 248
249 bool _initPrepareFunctions = false; 249 bool _initPrepareFunctions = false;
250 PrepareInstanceModelFunction _instanceModelFn; 250 PrepareInstanceModelFunction _instanceModelFn;
251 PrepareInstancePositionChangedFunction _instancePositionChangedFn; 251 PrepareInstancePositionChangedFunction _instancePositionChangedFn;
252 252
253 _TemplateIterator(this._templateExt); 253 _TemplateIterator(this._templateExt);
254 254
255 Element get _templateElement => _templateExt._node; 255 Element get _templateElement => _templateExt._node;
256 256
257 resolve() { 257 resolve() {
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
306 iteratedValue = newValue; 306 iteratedValue = newValue;
307 } else if (newValue is Iterable) { 307 } else if (newValue is Iterable) {
308 // Dart note: we support Iterable by calling toList. 308 // Dart note: we support Iterable by calling toList.
309 // But we need to be careful to observe the original iterator if it 309 // But we need to be careful to observe the original iterator if it
310 // supports that. 310 // supports that.
311 iteratedValue = (newValue as Iterable).toList(); 311 iteratedValue = (newValue as Iterable).toList();
312 } else { 312 } else {
313 iteratedValue = null; 313 iteratedValue = null;
314 } 314 }
315 315
316 if (iteratedValue != null && newValue is Observable) { 316 if (iteratedValue != null && newValue is ObservableList) {
317 _arraySub = (newValue as Observable).changes.listen( 317 _listSub = newValue.listChanges.listen(_handleSplices);
318 _handleSplices);
319 } 318 }
320 319
321 var splices = calculateSplices( 320 var splices = ObservableList.calculateChangeRecords(
322 iteratedValue != null ? iteratedValue : [], 321 oldValue != null ? oldValue : [],
323 oldValue != null ? oldValue : []); 322 iteratedValue != null ? iteratedValue : []);
324 323
325 if (splices.isNotEmpty) _handleSplices(splices); 324 if (splices.isNotEmpty) _handleSplices(splices);
326 } 325 }
327 326
328 Node getTerminatorAt(int index) { 327 Node getTerminatorAt(int index) {
329 if (index == -1) return _templateElement; 328 if (index == -1) return _templateElement;
330 var terminator = terminators[index * 2]; 329 var terminator = terminators[index * 2];
331 if (!isSemanticTemplate(terminator) || 330 if (!isSemanticTemplate(terminator) ||
332 identical(terminator, _templateElement)) { 331 identical(terminator, _templateElement)) {
333 return terminator; 332 return terminator;
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
376 var parent = _templateElement.parentNode; 375 var parent = _templateElement.parentNode;
377 while (terminator != previousTerminator) { 376 while (terminator != previousTerminator) {
378 var node = previousTerminator.nextNode; 377 var node = previousTerminator.nextNode;
379 if (node == terminator) terminator = previousTerminator; 378 if (node == terminator) terminator = previousTerminator;
380 node.remove(); 379 node.remove();
381 instanceNodes.add(node); 380 instanceNodes.add(node);
382 } 381 }
383 return new _BoundNodes(instanceNodes, bound); 382 return new _BoundNodes(instanceNodes, bound);
384 } 383 }
385 384
386 void _handleSplices(Iterable<ChangeRecord> splices) { 385 void _handleSplices(List<ListChangeRecord> splices) {
387 if (closed) return; 386 if (closed) return;
388 387
389 splices = splices.where((s) => s is ListChangeRecord);
390
391 final template = _templateElement; 388 final template = _templateElement;
392 final delegate = _templateExt._self.bindingDelegate; 389 final delegate = _templateExt._self.bindingDelegate;
393 390
394 if (template.parentNode == null || template.ownerDocument.window == null) { 391 if (template.parentNode == null || template.ownerDocument.window == null) {
395 close(); 392 close();
396 return; 393 return;
397 } 394 }
398 395
399 // Dart note: the JavaScript code relies on the distinction between null 396 // Dart note: the JavaScript code relies on the distinction between null
400 // and undefined to track whether the functions are prepared. We use a bool. 397 // and undefined to track whether the functions are prepared. We use a bool.
401 if (!_initPrepareFunctions) { 398 if (!_initPrepareFunctions) {
402 _initPrepareFunctions = true; 399 _initPrepareFunctions = true;
403 if (delegate != null) { 400 if (delegate != null) {
404 _instanceModelFn = delegate.prepareInstanceModel(template); 401 _instanceModelFn = delegate.prepareInstanceModel(template);
405 _instancePositionChangedFn = 402 _instancePositionChangedFn =
406 delegate.prepareInstancePositionChanged(template); 403 delegate.prepareInstancePositionChanged(template);
407 } 404 }
408 } 405 }
409 406
410 var instanceCache = new HashMap<Object, _BoundNodes>(equals: identical); 407 var instanceCache = new HashMap<Object, _BoundNodes>(equals: identical);
411 var removeDelta = 0; 408 var removeDelta = 0;
412 for (var splice in splices) { 409 for (var splice in splices) {
413 for (int i = 0; i < splice.removedCount; i++) { 410 for (var model in splice.removed) {
414 var instance = extractInstanceAt(splice.index + removeDelta); 411 instanceCache[model] = extractInstanceAt(splice.index + removeDelta);
415 if (instance.nodes.length == 0) continue;
416 var model = nodeBind(instance.nodes.first).templateInstance.model;
417 instanceCache[model] = instance;
418 } 412 }
419 413
420 removeDelta -= splice.addedCount; 414 removeDelta -= splice.addedCount;
421 } 415 }
422 416
423 for (var splice in splices) { 417 for (var splice in splices) {
424 for (var addIndex = splice.index; 418 for (var addIndex = splice.index;
425 addIndex < splice.index + splice.addedCount; 419 addIndex < splice.index + splice.addedCount;
426 addIndex++) { 420 addIndex++) {
427 421
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
462 } 456 }
463 457
464 // We must use the first node of the instance, because any subsequent 458 // We must use the first node of the instance, because any subsequent
465 // nodes may have been generated by sub-templates. 459 // nodes may have been generated by sub-templates.
466 // TODO(rafaelw): This is brittle WRT instance mutation -- e.g. if the 460 // TODO(rafaelw): This is brittle WRT instance mutation -- e.g. if the
467 // first node was removed by script. 461 // first node was removed by script.
468 var instance = nodeBind(previousTerminator.nextNode).templateInstance; 462 var instance = nodeBind(previousTerminator.nextNode).templateInstance;
469 _instancePositionChangedFn(instance, index); 463 _instancePositionChangedFn(instance, index);
470 } 464 }
471 465
472 void reportInstancesMoved(Iterable<ChangeRecord> splices) { 466 void reportInstancesMoved(List<ListChangeRecord> splices) {
473 var index = 0; 467 var index = 0;
474 var offset = 0; 468 var offset = 0;
475 for (ListChangeRecord splice in splices) { 469 for (var splice in splices) {
476 if (offset != 0) { 470 if (offset != 0) {
477 while (index < splice.index) { 471 while (index < splice.index) {
478 reportInstanceMoved(index); 472 reportInstanceMoved(index);
479 index++; 473 index++;
480 } 474 }
481 } else { 475 } else {
482 index = splice.index; 476 index = splice.index;
483 } 477 }
484 478
485 while (index < splice.index + splice.addedCount) { 479 while (index < splice.index + splice.addedCount) {
486 reportInstanceMoved(index); 480 reportInstanceMoved(index);
487 index++; 481 index++;
488 } 482 }
489 483
490 offset += splice.addedCount - splice.removedCount; 484 offset += splice.addedCount - splice.removed.length;
491 } 485 }
492 486
493 if (offset == 0) return; 487 if (offset == 0) return;
494 488
495 var length = terminators.length ~/ 2; 489 var length = terminators.length ~/ 2;
496 while (index < length) { 490 while (index < length) {
497 reportInstanceMoved(index); 491 reportInstanceMoved(index);
498 index++; 492 index++;
499 } 493 }
500 } 494 }
501 495
502 void closeInstanceBindings(List<NodeBinding> bound) { 496 void closeInstanceBindings(List<NodeBinding> bound) {
503 for (var binding in bound) binding.close(); 497 for (var binding in bound) binding.close();
504 } 498 }
505 499
506 void unobserve() { 500 void unobserve() {
507 if (_arraySub == null) return; 501 if (_listSub == null) return;
508 _arraySub.cancel(); 502 _listSub.cancel();
509 _arraySub = null; 503 _listSub = null;
510 } 504 }
511 505
512 void close() { 506 void close() {
513 if (closed) return; 507 if (closed) return;
514 508
515 unobserve(); 509 unobserve();
516 for (var i = 1; i < terminators.length; i += 2) { 510 for (var i = 1; i < terminators.length; i += 2) {
517 closeInstanceBindings(terminators[i]); 511 closeInstanceBindings(terminators[i]);
518 } 512 }
519 513
520 terminators.clear(); 514 terminators.clear();
521 if (_valueSub != null) { 515 if (_valueSub != null) {
522 _valueSub.cancel(); 516 _valueSub.cancel();
523 _valueSub = null; 517 _valueSub = null;
524 } 518 }
525 _templateExt._iterator = null; 519 _templateExt._iterator = null;
526 closed = true; 520 closed = true;
527 } 521 }
528 } 522 }
529 523
530 // Dart note: the JavaScript version just puts an expando on the array. 524 // Dart note: the JavaScript version just puts an expando on the array.
531 class _BoundNodes { 525 class _BoundNodes {
532 final List<Node> nodes; 526 final List<Node> nodes;
533 final List<NodeBinding> bound; 527 final List<NodeBinding> bound;
534 _BoundNodes(this.nodes, this.bound); 528 _BoundNodes(this.nodes, this.bound);
535 } 529 }
OLDNEW
« no previous file with comments | « pkg/template_binding/lib/src/list_diff.dart ('k') | pkg/template_binding/lib/template_binding.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698