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

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

Powered by Google App Engine
This is Rietveld 408576698