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

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

Issue 42433002: port Node.bind to bd0a0591920da9091b326627a46a104a92c7efe7 (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 /** Extensions to the [Node] API. */ 7 /** Extensions to the [Node] API. */
8 class NodeBindExtension { 8 class NodeBindExtension {
9 final Node _node; 9 final Node _node;
10 Map<String, NodeBinding> _bindings; 10 Map<String, NodeBinding> _bindings;
11 11
12 NodeBindExtension._(this._node); 12 NodeBindExtension._(this._node);
13 13
14 /** 14 /**
15 * Creates a binding to the attribute [name] to the [path] of the [model].
16 *
17 * This can be overridden by custom elements to provide the binding used in
18 * [bind]. This will only create the binding; it will not add
19 * it to [bindings].
20 *
21 * You should not need to call this directly except from [bind].
22 */
23 NodeBinding createBinding(String name, model, String path) => null;
24
25 /**
26 * Binds the attribute [name] to the [path] of the [model]. 15 * Binds the attribute [name] to the [path] of the [model].
27 * Path is a String of accessors such as `foo.bar.baz`. 16 * Path is a String of accessors such as `foo.bar.baz`.
28 * Returns the `NodeBinding` instance. 17 * Returns the `NodeBinding` instance.
29 */ 18 */
30 NodeBinding bind(String name, model, String path) { 19 NodeBinding bind(String name, model, [String path]) {
31 var binding = bindings[name]; 20 window.console.error('Unhandled binding to Node: '
32 if (binding != null) binding.close(); 21 '$this $name $model $path');
33
34 // Note: dispatch through the node so it can override this.
35 binding = nodeBind(_node).createBinding(name, model, path);
36
37 bindings[name] = binding;
38 if (binding == null) {
39 window.console.error('Unhandled binding to Node: '
40 '$this $name $model $path');
41 }
42 return binding;
43 } 22 }
44 23
45 /** Unbinds the attribute [name]. */ 24 /** Unbinds the attribute [name]. */
46 void unbind(String name) { 25 void unbind(String name) {
47 if (_bindings == null) return; 26 if (_bindings == null) return;
48 var binding = bindings.remove(name); 27 var binding = bindings.remove(name);
49 if (binding != null) binding.close(); 28 if (binding != null) binding.close();
50 } 29 }
51 30
52 /** Unbinds all bound attributes. */ 31 /** Unbinds all bound attributes. */
53 void unbindAll() { 32 void unbindAll() {
54 if (_bindings == null) return; 33 if (_bindings == null) return;
55 for (var binding in bindings.values) { 34 for (var binding in bindings.values) {
56 if (binding != null) binding.close(); 35 if (binding != null) binding.close();
57 } 36 }
58 _bindings = null; 37 _bindings = null;
59 } 38 }
60 39
61 // TODO(jmesserly): we should return a read-only wrapper here. 40 // TODO(jmesserly): we should return a read-only wrapper here.
62 /** Gets the data bindings that are associated with this node. */ 41 /** Gets the data bindings that are associated with this node. */
63 Map<String, NodeBinding> get bindings { 42 Map<String, NodeBinding> get bindings {
64 if (_bindings == null) _bindings = new LinkedHashMap<String, NodeBinding>(); 43 if (_bindings == null) _bindings = new LinkedHashMap<String, NodeBinding>();
65 return _bindings; 44 return _bindings;
66 } 45 }
67 46
47 /**
48 * Dispatch support so custom HtmlElement's can override these methods.
49 * A public method like [this.bind] should not call another public method such
50 * as [this.unbind]. Instead it should dispatch through [_self.unbind].
51 */
52 NodeBindExtension get _self => _node is NodeBindExtension ? _node : this;
53
68 TemplateInstance _templateInstance; 54 TemplateInstance _templateInstance;
69 55
70 /** Gets the template instance that instantiated this node, if any. */ 56 /** Gets the template instance that instantiated this node, if any. */
71 TemplateInstance get templateInstance => 57 TemplateInstance get templateInstance =>
72 _templateInstance != null ? _templateInstance : 58 _templateInstance != null ? _templateInstance :
73 (_node.parent != null ? _node.parent.templateInstance : null); 59 (_node.parent != null ? _node.parent.templateInstance : null);
74 } 60 }
75 61
76 62
77 /** Information about the instantiated template. */ 63 /** Information about the instantiated template. */
(...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after
192 178
193 /** The node that has [property] which will be data bound. */ 179 /** The node that has [property] which will be data bound. */
194 Node get node => _node; 180 Node get node => _node;
195 181
196 /** 182 /**
197 * The bound data model. 183 * The bound data model.
198 */ 184 */
199 get model => _model; 185 get model => _model;
200 186
201 /** True if this binding has been [closed]. */ 187 /** True if this binding has been [closed]. */
202 bool get closed => _observer == null; 188 bool get closed => _node == null;
203 189
204 /** The value at the [path] on [model]. */ 190 /** The value at the [path] on [model]. */
205 get value => _observer.value; 191 get value => _observer.value;
206 192
207 set value(newValue) { 193 set value(newValue) {
208 _observer.value = newValue; 194 _observer.value = newValue;
209 } 195 }
210 196
211 NodeBinding(this._node, this.property, this._model, this.path) { 197 NodeBinding(this._node, this.property, this._model, [String path])
212 // Create the path observer 198 : path = path != null ? path : '' {
213 _observer = new PathObserver(model, path);
214 _observePath(); 199 _observePath();
215 } 200 }
216 201
217 void _observePath() { 202 _observePath() {
218 _pathSub = _observer.bindSync(boundValueChanged); 203 // Fast path if we're observing PathObserver.value
204 if (model is PathObserver && path == 'value') {
205 _observer = model;
206 } else {
207 // Create the path observer
208 _observer = new PathObserver(model, path);
209 }
210 _pathSub = _observer.bindSync(valueChanged);
219 } 211 }
220 212
221 /** Called when [value] changes to update the [node]. */ 213 /** Called when [value] changes to update the [node]. */
222 // TODO(jmesserly): the impl in MDV uses mirrors to set the property, 214 // TODO(jmesserly): the impl in template_binding uses reflection to set the
223 // but that isn't used except for specific known fields like "textContent", 215 // property, but that isn't used except for specific known fields like
224 // so I'm overridding this in the subclasses instead. 216 // "textContent", so I'm overridding this in the subclasses instead.
225 void boundValueChanged(newValue); 217 void valueChanged(newValue);
226 218
227 /** Called to sanitize the value before it is assigned into the property. */ 219 /** Called to sanitize the value before it is assigned into the property. */
228 sanitizeBoundValue(value) => value == null ? '' : '$value'; 220 sanitizeBoundValue(value) => value == null ? '' : '$value';
229 221
230 /** 222 /**
231 * Called by [NodeBindExtension.unbind] to close this binding and unobserve 223 * Called by [NodeBindExtension.unbind] to close this binding and unobserve
232 * the [path]. 224 * the [path].
233 * 225 *
234 * This can be overridden in subclasses, but they must call `super.close()` 226 * This can be overridden in subclasses, but they must call `super.close()`
235 * to free associated resources. They must also check [closed] and return 227 * to free associated resources. They must also check [closed] and return
236 * immediately if already closed. 228 * immediately if already closed.
237 */ 229 */
238 void close() { 230 void close() {
239 if (closed) return; 231 if (closed) return;
240 232
241 if (_pathSub != null) _pathSub.cancel(); 233 if (_pathSub != null) _pathSub.cancel();
242 _pathSub = null; 234 _pathSub = null;
243 _observer = null; 235 _observer = null;
244 _node = null; 236 _node = null;
245 _model = null; 237 _model = null;
246 } 238 }
247 } 239 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698