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

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

Issue 20149004: [mdv] implement Node.createBinding and Node.createBindings (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: 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
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 mdv; 5 part of mdv;
6 6
7 /** Extensions to the [Node] API. */ 7 /** Extensions to the [Node] API. */
8 class _NodeExtension { 8 class _NodeExtension {
9 final Node node; 9 final Node node;
10 Map<String, NodeBinding> _bindings;
10 11
11 _NodeExtension(this.node); 12 _NodeExtension(this.node);
12 13
14 NodeBinding createBinding(String name, model, String path) => null;
15
13 /** 16 /**
14 * Binds the attribute [name] to the [path] of the [model]. 17 * Binds the attribute [name] to the [path] of the [model].
15 * Path is a String of accessors such as `foo.bar.baz`. 18 * Path is a String of accessors such as `foo.bar.baz`.
16 */ 19 */
17 void bind(String name, model, String path) { 20 NodeBinding bind(String name, model, String path) {
18 window.console.error('Unhandled binding to Node: ' 21 var binding = bindings[name];
19 '$this $name $model $path'); 22 if (binding != null) binding.close();
23
24 binding = createBinding(name, model, path);
25 bindings[name] = binding;
26 if (binding == null) {
27 window.console.error('Unhandled binding to Node: '
28 '$this $name $model $path');
29 }
30 return binding;
20 } 31 }
21 32
22 /** Unbinds the attribute [name]. */ 33 /** Unbinds the attribute [name]. */
23 void unbind(String name) {} 34 void unbind(String name) {
35 if (_bindings == null) return;
36 var binding = bindings.remove(name);
37 if (binding != null) binding.close();
38 }
24 39
25 /** Unbinds all bound attributes. */ 40 /** Unbinds all bound attributes. */
26 void unbindAll() {} 41 void unbindAll() {
42 if (_bindings == null) return;
43 for (var binding in bindings.values) {
44 if (binding != null) binding.close();
45 }
46 _bindings = null;
47 }
48
49 // TODO(jmesserly): we should return a read-only wrapper here.
50 Map<String, NodeBinding> get bindings {
51 if (_bindings == null) _bindings = new LinkedHashMap<String, NodeBinding>();
52 return _bindings;
53 }
27 54
28 TemplateInstance _templateInstance; 55 TemplateInstance _templateInstance;
29 56
30 /** Gets the template instance that instantiated this node, if any. */ 57 /** Gets the template instance that instantiated this node, if any. */
31 TemplateInstance get templateInstance => 58 TemplateInstance get templateInstance =>
32 _templateInstance != null ? _templateInstance : 59 _templateInstance != null ? _templateInstance :
33 (node.parent != null ? node.parent.templateInstance : null); 60 (node.parent != null ? node.parent.templateInstance : null);
34 } 61 }
62
63 /** A data binding on a [Node]. See [Node.bindings] and [Node.bind]. */
64 abstract class NodeBinding {
65 Node _node;
66 var _model;
67 PathObserver _observer;
68 StreamSubscription _pathSub;
69
70 /** The property of [node] which will be data bound. */
71 final String property;
72
73 /** The property of [node] which will be data bound. */
74 final String path;
75
76 /** The node that has [property] which will be data bound. */
77 Node get node => _node;
78
79 /**
80 * The bound data model.
Siggi Cherem (dart-lang) 2013/07/25 16:24:12 silly nit: this fits in 1 line (/** ... */)
81 */
82 get model => _model;
83
84 /** True if this binding has been [closed]. */
85 bool get closed => _observer == null;
86
87 /** The value at the [path] on [model]. */
88 get value => _observer.value;
89
90 set value(newValue) {
91 _observer.value = newValue;
92 }
93
94 NodeBinding(this._node, this.property, this._model, this.path) {
95 // Create the path observer
96 _observer = new PathObserver(model, path);
97 _observePath();
98 }
99
100 void _observePath() {
101 _pathSub = _observer.bindSync(boundValueChanged);
102 }
103
104 /** Called when [value] changes to update the [node]. */
105 // TODO(jmesserly): the impl in MDV uses mirrors to set the property,
106 // but that isn't used except for specific known fields like "textContent",
107 // so I'm overridding this in the subclasses instead.
108 void boundValueChanged(newValue);
109
110 /** Called to sanitize the value before it is assigned into the property. */
111 sanitizeBoundValue(value) => value == null ? '' : '$value';
112
113 /**
114 * Called by [Node.unbind] to close this binding and unobserve the [path].
115 *
116 * This can be overridden in subclasses, but they must call `super.close()`
117 * to free associated resources. They must also check [closed] and return
118 * immediately if already closed.
119 */
120 void close() {
121 if (closed) return;
122
123 if (_pathSub != null) _pathSub.cancel();
124 _pathSub = null;
125 _observer = null;
126 _node = null;
127 _model = null;
128 }
129 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698