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

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

Issue 1400473008: Roll Observatory packages and add a roll script (Closed) Base URL: git@github.com:dart-lang/observatory_pub_packages.git@master
Patch Set: Created 5 years, 2 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
« no previous file with comments | « template_binding/lib/src/mustache_tokens.dart ('k') | template_binding/lib/src/template.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 part of template_binding;
6
7 /** Extensions to the [Node] API. */
8 class NodeBindExtension {
9 final Node _node;
10 final JsObject _js;
11
12 NodeBindExtension._(node)
13 : _node = node,
14 _js = new JsObject.fromBrowserObject(node);
15
16 /**
17 * Gets the data bindings that are associated with this node, if any.
18 *
19 * This starts out null, and if [enableBindingsReflection] is enabled, calls
20 * to [bind] will initialize this field and the binding.
21 */
22 // Dart note: in JS this has a trailing underscore, meaning "private".
23 // But in dart if we made it _bindings, it wouldn't be accessible at all.
24 // It is unfortunately needed to implement Node.bind correctly.
25 Map<String, Bindable> get bindings {
26 var b = _js['bindings_'];
27 if (b == null) return null;
28 // TODO(jmesserly): should cache this for identity.
29 return new _NodeBindingsMap(_node, b);
30 }
31
32 set bindings(Map<String, Bindable> value) {
33 if (value == null) {
34 _js.deleteProperty('bindings_');
35 return;
36 }
37 var b = bindings;
38 if (b == null) {
39 _js['bindings_'] = new JsObject.jsify({});
40 b = bindings;
41 }
42 b.addAll(value);
43 }
44
45 /**
46 * Binds the attribute [name] to [value]. [value] can be a simple value when
47 * [oneTime] is true, or a [Bindable] like [PathObserver].
48 * Returns the [Bindable] instance.
49 */
50 Bindable bind(String name, value, {bool oneTime: false}) {
51 name = _dartToJsName(_node, name);
52
53 if (!oneTime && value is Bindable) {
54 value = bindableToJsObject(value);
55 }
56 return jsObjectToBindable(_js.callMethod('bind', [name, value, oneTime]));
57 }
58
59 /**
60 * Called when all [bind] calls are finished for a given template expansion.
61 */
62 bindFinished() => _js.callMethod('bindFinished');
63
64 // Note: confusingly this is on NodeBindExtension because it can be on any
65 // Node. It's really an API added by TemplateBinding. Therefore it stays
66 // implemented in Dart because TemplateBinding still is.
67 TemplateInstance _templateInstance;
68
69 /** Gets the template instance that instantiated this node, if any. */
70 TemplateInstance get templateInstance =>
71 _templateInstance != null ? _templateInstance :
72 (_node.parent != null ? nodeBind(_node.parent).templateInstance : null);
73 }
74
75 class _NodeBindingsMap extends MapBase<String, Bindable> {
76 final Node _node;
77 final JsObject _bindings;
78
79 _NodeBindingsMap(this._node, this._bindings);
80
81 // TODO(jmesserly): this should be lazy
82 Iterable<String> get keys =>
83 js.context['Object'].callMethod('keys', [_bindings]).map(
84 (name) => _jsToDartName(_node, name));
85
86 Bindable operator[](String name) =>
87 jsObjectToBindable(_bindings[_dartToJsName(_node, name)]);
88
89 operator[]=(String name, Bindable value) {
90 _bindings[_dartToJsName(_node, name)] = bindableToJsObject(value);
91 }
92
93 @override Bindable remove(String name) {
94 name = _dartToJsName(_node, name);
95 var old = this[name];
96 _bindings.deleteProperty(name);
97 return old;
98 }
99
100 @override void clear() {
101 // Notes: this implementation only works because our "keys" returns a copy.
102 // We could also make it O(1) by assigning a new JS object to the bindings_
103 // property, if performance is an issue.
104 keys.forEach(remove);
105 }
106 }
107
108 // TODO(jmesserly): perhaps we should switch Dart's Node.bind API back to
109 // 'textContent' for consistency? This only affects the raw Node.bind API when
110 // called on Text nodes, which is unlikely to be used except by TemplateBinding.
111 // Seems like a lot of magic to support it. I don't think Node.bind promises any
112 // strong relationship between properties and [name], so textContent seems fine.
113 String _dartToJsName(Node node, String name) {
114 if (node is Text && name == 'text') name = 'textContent';
115 return name;
116 }
117
118
119 String _jsToDartName(Node node, String name) {
120 if (node is Text && name == 'textContent') name = 'text';
121 return name;
122 }
123
124
125 /// Given a bindable [JsObject], wraps it in a Dart [Bindable].
126 /// See [bindableToJsObject] to go in the other direction.
127 Bindable jsObjectToBindable(JsObject obj) {
128 if (obj == null) return null;
129 var b = obj['__dartBindable'];
130 // For performance, unwrap the Dart bindable if we find one.
131 // Note: in the unlikely event some code messes with our __dartBindable
132 // property we can simply fallback to a _JsBindable wrapper.
133 return b is Bindable ? b : new _JsBindable(obj);
134 }
135
136 class _JsBindable extends Bindable {
137 final JsObject _js;
138 _JsBindable(JsObject obj) : _js = obj;
139
140 open(callback) => _js.callMethod('open',
141 [Zone.current.bindUnaryCallback(callback)]);
142
143 close() => _js.callMethod('close');
144
145 get value => _js.callMethod('discardChanges');
146
147 set value(newValue) {
148 _js.callMethod('setValue', [newValue]);
149 }
150
151 deliver() => _js.callMethod('deliver');
152 }
153
154 /// Given a [bindable], create a JS object proxy for it.
155 /// This is the inverse of [jsObjectToBindable].
156 JsObject bindableToJsObject(Bindable bindable) {
157 if (bindable is _JsBindable) return bindable._js;
158
159 var zone = Zone.current;
160 inZone(f) => zone.bindCallback(f, runGuarded: false);
161 inZoneUnary(f) => zone.bindUnaryCallback(f, runGuarded: false);
162
163 return new JsObject.jsify({
164 'open': inZoneUnary(
165 (callback) => bindable.open((x) => callback.apply([x]))),
166 'close': inZone(() => bindable.close()),
167 'discardChanges': inZone(() => bindable.value),
168 'setValue': inZoneUnary((x) => bindable.value = x),
169 // NOTE: this is not used by Node.bind, but it's used by Polymer:
170 // https://github.com/Polymer/polymer-dev/blob/ba2b68fe5a5721f60b5994135f327 0e63588809a/src/declaration/properties.js#L130
171 // Technically this works because 'deliver' is on PathObserver and
172 // CompoundObserver. But ideally Polymer-JS would not assume that.
173 'deliver': inZone(() => bindable.deliver()),
174 // Save this so we can return it from [jsObjectToBindable]
175 '__dartBindable': bindable
176 });
177 }
178
179 /** Information about the instantiated template. */
180 class TemplateInstance {
181 // TODO(rafaelw): firstNode & lastNode should be read-synchronous
182 // in cases where script has modified the template instance boundary.
183
184 /** The first node of this template instantiation. */
185 Node get firstNode => _firstNode;
186
187 /**
188 * The last node of this template instantiation.
189 * This could be identical to [firstNode] if the template only expanded to a
190 * single node.
191 */
192 Node get lastNode => _lastNode;
193
194 /** The model used to instantiate the template. */
195 final model;
196
197 Node _firstNode, _lastNode;
198
199 TemplateInstance(this.model);
200 }
OLDNEW
« no previous file with comments | « template_binding/lib/src/mustache_tokens.dart ('k') | template_binding/lib/src/template.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698