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

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

Issue 50203004: port TemplateBinding to ed3266266e751b5ab1f75f8e0509d0d5f0ef35d8 (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
(Empty)
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
3 // BSD-style license that can be found in the LICENSE file.
4
5 part of observe;
6
7 /** The callback used in the [CompoundBinding.combinator] field. */
8 typedef Object CompoundBindingCombinator(Map objects);
9
10 /**
11 * CompoundBinding is an object which knows how to listen to multiple path
12 * values (registered via [bind]) and invoke its [combinator] when one or more
13 * of the values have changed and set its [value] property to the return value
14 * of the function. When any value has changed, all current values are provided
15 * to the [combinator] in the single `values` argument.
16 *
17 * For example:
18 *
19 * var binding = new CompoundBinding((values) {
20 * var combinedValue;
21 * // compute combinedValue based on the current values which are provided
22 * return combinedValue;
23 * });
24 * binding.bind('name1', obj1, path1);
25 * binding.bind('name2', obj2, path2);
26 * //...
27 * binding.bind('nameN', objN, pathN);
28 */
29 // TODO(jmesserly): rename to something that indicates it's a computed value?
30 class CompoundBinding extends ChangeNotifier {
31 CompoundBindingCombinator _combinator;
32
33 // TODO(jmesserly): ideally these would be String keys, but sometimes we
34 // use integers.
35 Map<dynamic, StreamSubscription> _observers = new Map();
36 Map _values = new Map();
37 Object _value;
38
39 /**
40 * True if [resolve] is scheduled. You can set this to true if you plan to
41 * call [resolve] manually, avoiding the need for scheduling an asynchronous
42 * resolve.
43 */
44 // TODO(jmesserly): I don't like having this public, is the optimization
45 // really needed? "scheduleMicrotask" in Dart should be pretty cheap.
46 bool scheduled = false;
47
48 /**
49 * Creates a new CompoundBinding, optionally proving the [combinator] function
50 * for computing the value. You can also set [schedule] to true if you plan
51 * to invoke [resolve] manually after initial construction of the binding.
52 */
53 CompoundBinding([CompoundBindingCombinator combinator]) {
54 // TODO(jmesserly): this is a tweak to the original code, it seemed to me
55 // that passing the combinator to the constructor should be equivalent to
56 // setting it via the property.
57 // I also added a null check to the combinator setter.
58 this.combinator = combinator;
59 }
60
61 CompoundBindingCombinator get combinator => _combinator;
62
63 set combinator(CompoundBindingCombinator combinator) {
64 _combinator = combinator;
65 if (combinator != null) _scheduleResolve();
66 }
67
68 int get length => _observers.length;
69
70 @reflectable get value => _value;
71
72 @reflectable void set value(newValue) {
73 _value = notifyPropertyChange(#value, _value, newValue);
74 }
75
76 void bind(name, model, String path) {
77 unbind(name);
78
79 // TODO(jmesserly): should we delay observing until we are observed,
80 // similar to PathObserver?
81 _observers[name] = new PathObserver(model, path).bindSync((value) {
82 _values[name] = value;
83 _scheduleResolve();
84 });
85 }
86
87 void unbind(name, {bool suppressResolve: false}) {
88 var binding = _observers.remove(name);
89 if (binding == null) return;
90
91 binding.cancel();
92 _values.remove(name);
93 if (!suppressResolve) _scheduleResolve();
94 }
95
96 // TODO(rafaelw): Is this the right processing model?
97 // TODO(rafaelw): Consider having a seperate ChangeSummary for
98 // CompoundBindings so to excess dirtyChecks.
99 void _scheduleResolve() {
100 if (scheduled) return;
101 scheduled = true;
102 scheduleMicrotask(resolve);
103 }
104
105 void resolve() {
106 if (_observers.isEmpty) return;
107 scheduled = false;
108
109 if (_combinator == null) {
110 throw new StateError(
111 'CompoundBinding attempted to resolve without a combinator');
112 }
113
114 value = _combinator(_values);
115 }
116
117 /**
118 * Closes the observer.
119 *
120 * This happens automatically if the [value] property is no longer observed,
121 * but this can also be called explicitly.
122 */
123 void close() {
124 for (var binding in _observers.values) {
125 binding.cancel();
126 }
127 _observers.clear();
128 _values.clear();
129 value = null;
130 }
131
132 _unobserved() => close();
133 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698