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

Side by Side Diff: pkg/observe/lib/src/compound_binding.dart

Issue 19996008: automatically clean up CompoundBinding (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: merged 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/template_iterator.dart ('k') | no next file » | 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 observe; 5 part of observe;
6 6
7 /** The callback used in the [CompoundBinding.combinator] field. */ 7 /** The callback used in the [CompoundBinding.combinator] field. */
8 typedef Object CompoundBindingCombinator(Map objects); 8 typedef Object CompoundBindingCombinator(Map objects);
9 9
10 /** 10 /**
(...skipping 14 matching lines...) Expand all
25 * binding.bind('name2', obj2, path2); 25 * binding.bind('name2', obj2, path2);
26 * //... 26 * //...
27 * binding.bind('nameN', objN, pathN); 27 * binding.bind('nameN', objN, pathN);
28 */ 28 */
29 // TODO(jmesserly): rename to something that indicates it's a computed value? 29 // TODO(jmesserly): rename to something that indicates it's a computed value?
30 class CompoundBinding extends ChangeNotifierBase { 30 class CompoundBinding extends ChangeNotifierBase {
31 CompoundBindingCombinator _combinator; 31 CompoundBindingCombinator _combinator;
32 32
33 // TODO(jmesserly): ideally these would be String keys, but sometimes we 33 // TODO(jmesserly): ideally these would be String keys, but sometimes we
34 // use integers. 34 // use integers.
35 Map<dynamic, StreamSubscription> _bindings = new Map(); 35 Map<dynamic, StreamSubscription> _observers = new Map();
36 Map _values = new Map(); 36 Map _values = new Map();
37 bool _scheduled = false; 37 bool _scheduled = false;
38 bool _disposed = false;
39 Object _value; 38 Object _value;
40 39
41 CompoundBinding([CompoundBindingCombinator combinator]) { 40 CompoundBinding([CompoundBindingCombinator combinator]) {
42 // TODO(jmesserly): this is a tweak to the original code, it seemed to me 41 // TODO(jmesserly): this is a tweak to the original code, it seemed to me
43 // that passing the combinator to the constructor should be equivalent to 42 // that passing the combinator to the constructor should be equivalent to
44 // setting it via the property. 43 // setting it via the property.
45 // I also added a null check to the combinator setter. 44 // I also added a null check to the combinator setter.
46 this.combinator = combinator; 45 this.combinator = combinator;
47 } 46 }
48 47
49 CompoundBindingCombinator get combinator => _combinator; 48 CompoundBindingCombinator get combinator => _combinator;
50 49
51 set combinator(CompoundBindingCombinator combinator) { 50 set combinator(CompoundBindingCombinator combinator) {
52 _combinator = combinator; 51 _combinator = combinator;
53 if (combinator != null) _scheduleResolve(); 52 if (combinator != null) _scheduleResolve();
54 } 53 }
55 54
56 static const _VALUE = const Symbol('value'); 55 static const _VALUE = const Symbol('value');
57 56
58 get value => _value; 57 get value => _value;
59 58
60 int get length => _bindings.length; 59 int get length => _observers.length;
61 60
62 void set value(newValue) { 61 void set value(newValue) {
63 _value = notifyPropertyChange(_VALUE, _value, newValue); 62 _value = notifyPropertyChange(_VALUE, _value, newValue);
64 } 63 }
65 64
66 void bind(name, model, String path) { 65 void bind(name, model, String path) {
67 unbind(name); 66 unbind(name);
68 67
69 // TODO(jmesserly): should we avoid observing until we are observed, 68 // TODO(jmesserly): should we delay observing until we are observed,
70 // similar to PathObserver? Similar for unobserving? 69 // similar to PathObserver?
71 _bindings[name] = new PathObserver(model, path).bindSync((value) { 70 _observers[name] = new PathObserver(model, path).bindSync((value) {
72 _values[name] = value; 71 _values[name] = value;
73 _scheduleResolve(); 72 _scheduleResolve();
74 }); 73 });
75 } 74 }
76 75
77 void unbind(name, {bool suppressResolve: false}) { 76 void unbind(name, {bool suppressResolve: false}) {
78 var binding = _bindings.remove(name); 77 var binding = _observers.remove(name);
79 if (binding == null) return; 78 if (binding == null) return;
80 79
81 binding.cancel(); 80 binding.cancel();
82 _values.remove(name); 81 _values.remove(name);
83 if (!suppressResolve) _scheduleResolve(); 82 if (!suppressResolve) _scheduleResolve();
84 } 83 }
85 84
86 // TODO(rafaelw): Is this the right processing model? 85 // TODO(rafaelw): Is this the right processing model?
87 // TODO(rafaelw): Consider having a seperate ChangeSummary for 86 // TODO(rafaelw): Consider having a seperate ChangeSummary for
88 // CompoundBindings so to excess dirtyChecks. 87 // CompoundBindings so to excess dirtyChecks.
89 void _scheduleResolve() { 88 void _scheduleResolve() {
90 if (_scheduled) return; 89 if (_scheduled) return;
91 _scheduled = true; 90 _scheduled = true;
92 runAsync(resolve); 91 runAsync(resolve);
93 } 92 }
94 93
95 void resolve() { 94 void resolve() {
96 if (_disposed) return; 95 if (_observers.isEmpty) return;
97 _scheduled = false; 96 _scheduled = false;
98 97
99 if (_combinator == null) { 98 if (_combinator == null) {
100 throw new StateError( 99 throw new StateError(
101 'CompoundBinding attempted to resolve without a combinator'); 100 'CompoundBinding attempted to resolve without a combinator');
102 } 101 }
103 102
104 value = _combinator(_values); 103 value = _combinator(_values);
105 } 104 }
106 105
107 void dispose() { 106 /**
108 for (var binding in _bindings.values) { 107 * Closes the observer.
108 *
109 * This happens automatically if the [value] property is no longer observed,
110 * but this can also be called explicitly.
111 */
112 void close() {
113 for (var binding in _observers.values) {
109 binding.cancel(); 114 binding.cancel();
110 } 115 }
111 _bindings.clear(); 116 _observers.clear();
112 _values.clear(); 117 _values.clear();
113
114 _disposed = true;
115 value = null; 118 value = null;
116 } 119 }
120
121 _unobserved() => close();
117 } 122 }
OLDNEW
« no previous file with comments | « pkg/mdv/lib/src/template_iterator.dart ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698