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

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

Issue 355133002: switch Node.bind to interop (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 6 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 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 final JsObject _js;
11
12 NodeBindExtension._(node)
13 : _node = node,
14 _js = new JsObject.fromBrowserObject(node);
10 15
11 /** 16 /**
12 * Gets the data bindings that are associated with this node, if any. 17 * Gets the data bindings that are associated with this node, if any.
13 * 18 *
14 * This starts out null, and if [enableBindingsReflection] is enabled, calls 19 * This starts out null, and if [enableBindingsReflection] is enabled, calls
15 * to [bind] will initialize this field and the binding. 20 * to [bind] will initialize this field and the binding.
16 */ 21 */
17 // Dart note: in JS this has a trailing underscore, meaning "private". 22 // Dart note: in JS this has a trailing underscore, meaning "private".
18 // But in dart if we made it _bindings, it wouldn't be accessible at all. 23 // But in dart if we made it _bindings, it wouldn't be accessible at all.
19 // It is unfortunately needed to implement Node.bind correctly. 24 // It is unfortunately needed to implement Node.bind correctly.
20 Map<String, Bindable> bindings; 25 Map<String, Bindable> get bindings {
21 26 var b = _js['bindings_'];
22 NodeBindExtension._(this._node); 27 if (b == null) return null;
28 // TODO(jmesserly): should cache this for identity.
29 return new _NodeBindingsMap(b);
30 }
31 set bindings(Map<String, Bindable> value) {
Siggi Cherem (dart-lang) 2014/06/27 18:40:52 nit: +empty line above
Jennifer Messerly 2014/06/27 19:10:03 Done.
32 if (value == null) {
33 _js.deleteProperty('bindings_');
34 return;
35 }
36 var b = bindings;
37 if (b == null) {
38 _js['bindings_'] = new JsObject.jsify({});
39 b = bindings;
40 }
41 b.addAll(value);
42 }
23 43
24 /** 44 /**
25 * Binds the attribute [name] to the [path] of the [model]. 45 * Binds the attribute [name] to the [path] of the [model].
Siggi Cherem (dart-lang) 2014/06/27 18:40:53 I independently sent you a CL to update this outda
Jennifer Messerly 2014/06/27 19:10:03 lgtm!
26 * Path is a String of accessors such as `foo.bar.baz`. 46 * Path is a String of accessors such as `foo.bar.baz`.
27 * Returns the [Bindable] instance. 47 * Returns the [Bindable] instance.
28 */ 48 */
29 Bindable bind(String name, value, {bool oneTime: false}) { 49 Bindable bind(String name, value, {bool oneTime: false}) {
30 // TODO(jmesserly): in Dart we could deliver an async error, which would 50 name = _dartToJsName(name);
31 // have a similar affect but be reported as a test failure. Should we? 51
32 window.console.error('Unhandled binding to Node: ' 52 if (!oneTime && value is Bindable) {
33 '$this $name $value $oneTime'); 53 value = bindableToJsObject(value);
34 return null; 54 }
55 return jsObjectToBindable(_js.callMethod('bind', [name, value, oneTime]));
35 } 56 }
36 57
37 /** 58 /**
38 * Called when all [bind] calls are finished for a given template expansion. 59 * Called when all [bind] calls are finished for a given template expansion.
39 */ 60 */
40 void bindFinished() {} 61 bindFinished() => _js.callMethod('bindFinished');
41 62
42 /** 63 // Note: confusingly this is on NodeBindExtension because it can be on any
43 * Dispatch support so custom HtmlElement's can override these methods. 64 // Node. It's really an API added by TemplateBinding. Therefore it stays
44 * 65 // implemented in Dart because TemplateBinding still is.
45 * A public method like [this.bind] should not call another public method.
46 *
47 * Instead it should dispatch through [_self] to give the "overridden" method
48 * a chance to intercept.
49 */
50 NodeBindExtension get _self => _node is NodeBindExtension ? _node : this;
51
52 TemplateInstance _templateInstance; 66 TemplateInstance _templateInstance;
53 67
54 /** Gets the template instance that instantiated this node, if any. */ 68 /** Gets the template instance that instantiated this node, if any. */
55 TemplateInstance get templateInstance => 69 TemplateInstance get templateInstance =>
56 _templateInstance != null ? _templateInstance : 70 _templateInstance != null ? _templateInstance :
57 (_node.parent != null ? nodeBind(_node.parent).templateInstance : null); 71 (_node.parent != null ? nodeBind(_node.parent).templateInstance : null);
72 }
58 73
59 _open(Bindable bindable, callback(value)) => 74 class _NodeBindingsMap extends MapBase<String, Bindable> {
60 callback(bindable.open(callback)); 75 final JsObject _bindings;
61 76
62 Bindable _maybeUpdateBindings(String name, Bindable binding) { 77 _NodeBindingsMap(this._bindings);
63 return enableBindingsReflection ? _updateBindings(name, binding) : binding; 78
79 // TODO(jmesserly): this should be lazy
80 Iterable<String> get keys =>
81 js.context['Object'].callMethod('keys', [_bindings]).map(_jsToDartName);
82
83 Bindable operator[](String name) =>
84 jsObjectToBindable(_bindings[_dartToJsName(name)]);
85
86 operator[]=(String name, Bindable value) {
87 _bindings[_dartToJsName(name)] = bindableToJsObject(value);
64 } 88 }
65 89
66 Bindable _updateBindings(String name, Bindable binding) { 90 @override Bindable remove(String name) {
67 if (bindings == null) bindings = {}; 91 name = _dartToJsName(name);
68 var old = bindings[name]; 92 var old = this[name];
69 if (old != null) old.close(); 93 _bindings.deleteProperty(name);
70 return bindings[name] = binding; 94 return old;
95 }
96
97 @override void clear() {
98 keys.forEach(remove);
Siggi Cherem (dart-lang) 2014/06/27 18:40:52 since this is pretty much private, could we instea
Jennifer Messerly 2014/06/27 19:10:04 that's an interesting idea. Certainly in practice,
Siggi Cherem (dart-lang) 2014/06/27 19:22:45 sgtm - let's just add a comment to not forget that
71 } 99 }
72 } 100 }
73 101
102 // TODO(jmesserly): perhaps we should switch Dart back to 'textContent' for
103 // consistency? This only affects the raw Node.bind API. Seems like a lot of
104 // magic to support it.
Siggi Cherem (dart-lang) 2014/06/27 18:40:53 not sure if it's worth to have this TODO here. May
Jennifer Messerly 2014/06/27 21:03:37 Oh -- definitely did *not* mean to suggest a chang
105 String _dartToJsName(String name) {
Siggi Cherem (dart-lang) 2014/06/27 18:40:53 nit: how about just a 1 liner: String _dartToJsNam
Jennifer Messerly 2014/06/27 21:03:36 Done.
106 if (name == 'text') name = 'textContent';
107 return name;
108 }
109
110
111 String _jsToDartName(String name) {
112 if (name == 'textContent') name = 'text';
113 return name;
114 }
115
116
117 /// Given a bindable [JsObject], wraps it in a Dart [Bindable].
118 /// See [bindableToJsObject] to go in the other direction.
119 Bindable jsObjectToBindable(JsObject obj) {
120 if (obj == null) return null;
121 var b = obj['__dartBindable'];
122 return b is Bindable ? b : new _JsBindable(obj);
Siggi Cherem (dart-lang) 2014/06/27 18:40:53 could 'b' ever be non-null & not Bindable? How abo
Jennifer Messerly 2014/06/27 19:10:04 yeah. I think that's essentially: return b !=
Siggi Cherem (dart-lang) 2014/06/27 19:22:45 makes sense. let's keep it as it is, maybe mention
Jennifer Messerly 2014/06/27 21:03:36 Done.
123 }
124
125 class _JsBindable extends Bindable {
126 final JsObject _js;
127 _JsBindable(JsObject obj) : _js = obj;
128
129 open(callback) => _js.callMethod('open', [callback]);
130
131 close() => _js.callMethod('close');
132
133 get value => _js.callMethod('discardChanges');
134
135 set value(newValue) {
136 _js.callMethod('discardChanges');
137 _js.callMethod('setValue', [newValue]);
138 }
139
140 deliver() => _js.callMethod('deliver');
141 }
142
143 /// Given a [bindable], create a JS object proxy for it.
144 /// This is the inverse of [jsObjectToBindable].
145 JsObject bindableToJsObject(Bindable bindable) {
146 if (bindable is _JsBindable) return bindable._js;
147
148 return new JsObject.jsify({
149 'open': (callback) => bindable.open((x) => callback.apply([x])),
150 'close': () => bindable.close(),
151 'discardChanges': () => bindable.value,
152 'setValue': (x) => bindable.value = x,
153 // NOTE: this is not used by Node.bind, but it's used by Polymer:
154 // https://github.com/Polymer/polymer-dev/blob/ba2b68fe5a5721f60b5994135f327 0e63588809a/src/declaration/properties.js#L130
Siggi Cherem (dart-lang) 2014/06/27 18:40:53 would this be an issue anymore if we had the js-ex
Jennifer Messerly 2014/06/27 21:03:36 That's a really good point. We could actually remo
155 'deliver': () => bindable.deliver(),
156 // Save this so we can return it from [jsObjectToBindable]
157 '__dartBindable': bindable
158 });
159 }
74 160
75 /** Information about the instantiated template. */ 161 /** Information about the instantiated template. */
76 class TemplateInstance { 162 class TemplateInstance {
77 // TODO(rafaelw): firstNode & lastNode should be read-synchronous 163 // TODO(rafaelw): firstNode & lastNode should be read-synchronous
78 // in cases where script has modified the template instance boundary. 164 // in cases where script has modified the template instance boundary.
79 165
80 /** The first node of this template instantiation. */ 166 /** The first node of this template instantiation. */
81 Node get firstNode => _firstNode; 167 Node get firstNode => _firstNode;
82 168
83 /** 169 /**
84 * The last node of this template instantiation. 170 * The last node of this template instantiation.
85 * This could be identical to [firstNode] if the template only expanded to a 171 * This could be identical to [firstNode] if the template only expanded to a
86 * single node. 172 * single node.
87 */ 173 */
88 Node get lastNode => _lastNode; 174 Node get lastNode => _lastNode;
89 175
90 /** The model used to instantiate the template. */ 176 /** The model used to instantiate the template. */
91 final model; 177 final model;
92 178
93 Node _firstNode, _lastNode; 179 Node _firstNode, _lastNode;
94 180
95 TemplateInstance(this.model); 181 TemplateInstance(this.model);
96 } 182 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698