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

Unified 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, 6 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 side-by-side diff with in-line comments
Download patch
Index: pkg/template_binding/lib/src/node.dart
diff --git a/pkg/template_binding/lib/src/node.dart b/pkg/template_binding/lib/src/node.dart
index fe6f9e6c611db4ba0ba485d9572a4521ab3e83c3..297f9587ec98941b0b728ba87307db92d4c92fc5 100644
--- a/pkg/template_binding/lib/src/node.dart
+++ b/pkg/template_binding/lib/src/node.dart
@@ -7,6 +7,11 @@ part of template_binding;
/** Extensions to the [Node] API. */
class NodeBindExtension {
final Node _node;
+ final JsObject _js;
+
+ NodeBindExtension._(node)
+ : _node = node,
+ _js = new JsObject.fromBrowserObject(node);
/**
* Gets the data bindings that are associated with this node, if any.
@@ -17,9 +22,24 @@ class NodeBindExtension {
// Dart note: in JS this has a trailing underscore, meaning "private".
// But in dart if we made it _bindings, it wouldn't be accessible at all.
// It is unfortunately needed to implement Node.bind correctly.
- Map<String, Bindable> bindings;
-
- NodeBindExtension._(this._node);
+ Map<String, Bindable> get bindings {
+ var b = _js['bindings_'];
+ if (b == null) return null;
+ // TODO(jmesserly): should cache this for identity.
+ return new _NodeBindingsMap(b);
+ }
+ 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.
+ if (value == null) {
+ _js.deleteProperty('bindings_');
+ return;
+ }
+ var b = bindings;
+ if (b == null) {
+ _js['bindings_'] = new JsObject.jsify({});
+ b = bindings;
+ }
+ b.addAll(value);
+ }
/**
* 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!
@@ -27,50 +47,116 @@ class NodeBindExtension {
* Returns the [Bindable] instance.
*/
Bindable bind(String name, value, {bool oneTime: false}) {
- // TODO(jmesserly): in Dart we could deliver an async error, which would
- // have a similar affect but be reported as a test failure. Should we?
- window.console.error('Unhandled binding to Node: '
- '$this $name $value $oneTime');
- return null;
+ name = _dartToJsName(name);
+
+ if (!oneTime && value is Bindable) {
+ value = bindableToJsObject(value);
+ }
+ return jsObjectToBindable(_js.callMethod('bind', [name, value, oneTime]));
}
/**
* Called when all [bind] calls are finished for a given template expansion.
*/
- void bindFinished() {}
-
- /**
- * Dispatch support so custom HtmlElement's can override these methods.
- *
- * A public method like [this.bind] should not call another public method.
- *
- * Instead it should dispatch through [_self] to give the "overridden" method
- * a chance to intercept.
- */
- NodeBindExtension get _self => _node is NodeBindExtension ? _node : this;
+ bindFinished() => _js.callMethod('bindFinished');
+ // Note: confusingly this is on NodeBindExtension because it can be on any
+ // Node. It's really an API added by TemplateBinding. Therefore it stays
+ // implemented in Dart because TemplateBinding still is.
TemplateInstance _templateInstance;
/** Gets the template instance that instantiated this node, if any. */
TemplateInstance get templateInstance =>
_templateInstance != null ? _templateInstance :
(_node.parent != null ? nodeBind(_node.parent).templateInstance : null);
+}
+
+class _NodeBindingsMap extends MapBase<String, Bindable> {
+ final JsObject _bindings;
+
+ _NodeBindingsMap(this._bindings);
+
+ // TODO(jmesserly): this should be lazy
+ Iterable<String> get keys =>
+ js.context['Object'].callMethod('keys', [_bindings]).map(_jsToDartName);
+
+ Bindable operator[](String name) =>
+ jsObjectToBindable(_bindings[_dartToJsName(name)]);
+
+ operator[]=(String name, Bindable value) {
+ _bindings[_dartToJsName(name)] = bindableToJsObject(value);
+ }
- _open(Bindable bindable, callback(value)) =>
- callback(bindable.open(callback));
+ @override Bindable remove(String name) {
+ name = _dartToJsName(name);
+ var old = this[name];
+ _bindings.deleteProperty(name);
+ return old;
+ }
- Bindable _maybeUpdateBindings(String name, Bindable binding) {
- return enableBindingsReflection ? _updateBindings(name, binding) : binding;
+ @override void clear() {
+ 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
}
+}
+
+// TODO(jmesserly): perhaps we should switch Dart back to 'textContent' for
+// consistency? This only affects the raw Node.bind API. Seems like a lot of
+// 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
+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.
+ if (name == 'text') name = 'textContent';
+ return name;
+}
+
+
+String _jsToDartName(String name) {
+ if (name == 'textContent') name = 'text';
+ return name;
+}
- Bindable _updateBindings(String name, Bindable binding) {
- if (bindings == null) bindings = {};
- var old = bindings[name];
- if (old != null) old.close();
- return bindings[name] = binding;
+
+/// Given a bindable [JsObject], wraps it in a Dart [Bindable].
+/// See [bindableToJsObject] to go in the other direction.
+Bindable jsObjectToBindable(JsObject obj) {
+ if (obj == null) return null;
+ var b = obj['__dartBindable'];
+ 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.
+}
+
+class _JsBindable extends Bindable {
+ final JsObject _js;
+ _JsBindable(JsObject obj) : _js = obj;
+
+ open(callback) => _js.callMethod('open', [callback]);
+
+ close() => _js.callMethod('close');
+
+ get value => _js.callMethod('discardChanges');
+
+ set value(newValue) {
+ _js.callMethod('discardChanges');
+ _js.callMethod('setValue', [newValue]);
}
+
+ deliver() => _js.callMethod('deliver');
}
+/// Given a [bindable], create a JS object proxy for it.
+/// This is the inverse of [jsObjectToBindable].
+JsObject bindableToJsObject(Bindable bindable) {
+ if (bindable is _JsBindable) return bindable._js;
+
+ return new JsObject.jsify({
+ 'open': (callback) => bindable.open((x) => callback.apply([x])),
+ 'close': () => bindable.close(),
+ 'discardChanges': () => bindable.value,
+ 'setValue': (x) => bindable.value = x,
+ // NOTE: this is not used by Node.bind, but it's used by Polymer:
+ // https://github.com/Polymer/polymer-dev/blob/ba2b68fe5a5721f60b5994135f3270e63588809a/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
+ 'deliver': () => bindable.deliver(),
+ // Save this so we can return it from [jsObjectToBindable]
+ '__dartBindable': bindable
+ });
+}
/** Information about the instantiated template. */
class TemplateInstance {

Powered by Google App Engine
This is Rietveld 408576698