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

Unified Diff: observatory_pub_packages/template_binding/src/node.dart

Issue 816693004: Add observatory_pub_packages snapshot to third_party (Closed) Base URL: http://dart.googlecode.com/svn/third_party/
Patch Set: Created 6 years 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: observatory_pub_packages/template_binding/src/node.dart
===================================================================
--- observatory_pub_packages/template_binding/src/node.dart (revision 0)
+++ observatory_pub_packages/template_binding/src/node.dart (working copy)
@@ -0,0 +1,200 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+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.
+ *
+ * This starts out null, and if [enableBindingsReflection] is enabled, calls
+ * to [bind] will initialize this field and the binding.
+ */
+ // 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> get bindings {
+ var b = _js['bindings_'];
+ if (b == null) return null;
+ // TODO(jmesserly): should cache this for identity.
+ return new _NodeBindingsMap(_node, b);
+ }
+
+ set bindings(Map<String, Bindable> value) {
+ 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 [value]. [value] can be a simple value when
+ * [oneTime] is true, or a [Bindable] like [PathObserver].
+ * Returns the [Bindable] instance.
+ */
+ Bindable bind(String name, value, {bool oneTime: false}) {
+ name = _dartToJsName(_node, 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.
+ */
+ 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 Node _node;
+ final JsObject _bindings;
+
+ _NodeBindingsMap(this._node, this._bindings);
+
+ // TODO(jmesserly): this should be lazy
+ Iterable<String> get keys =>
+ js.context['Object'].callMethod('keys', [_bindings]).map(
+ (name) => _jsToDartName(_node, name));
+
+ Bindable operator[](String name) =>
+ jsObjectToBindable(_bindings[_dartToJsName(_node, name)]);
+
+ operator[]=(String name, Bindable value) {
+ _bindings[_dartToJsName(_node, name)] = bindableToJsObject(value);
+ }
+
+ @override Bindable remove(String name) {
+ name = _dartToJsName(_node, name);
+ var old = this[name];
+ _bindings.deleteProperty(name);
+ return old;
+ }
+
+ @override void clear() {
+ // Notes: this implementation only works because our "keys" returns a copy.
+ // We could also make it O(1) by assigning a new JS object to the bindings_
+ // property, if performance is an issue.
+ keys.forEach(remove);
+ }
+}
+
+// TODO(jmesserly): perhaps we should switch Dart's Node.bind API back to
+// 'textContent' for consistency? This only affects the raw Node.bind API when
+// called on Text nodes, which is unlikely to be used except by TemplateBinding.
+// Seems like a lot of magic to support it. I don't think Node.bind promises any
+// strong relationship between properties and [name], so textContent seems fine.
+String _dartToJsName(Node node, String name) {
+ if (node is Text && name == 'text') name = 'textContent';
+ return name;
+}
+
+
+String _jsToDartName(Node node, String name) {
+ if (node is Text && name == 'textContent') name = 'text';
+ return name;
+}
+
+
+/// 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'];
+ // For performance, unwrap the Dart bindable if we find one.
+ // Note: in the unlikely event some code messes with our __dartBindable
+ // property we can simply fallback to a _JsBindable wrapper.
+ return b is Bindable ? b : new _JsBindable(obj);
+}
+
+class _JsBindable extends Bindable {
+ final JsObject _js;
+ _JsBindable(JsObject obj) : _js = obj;
+
+ open(callback) => _js.callMethod('open',
+ [Zone.current.bindUnaryCallback(callback)]);
+
+ close() => _js.callMethod('close');
+
+ get value => _js.callMethod('discardChanges');
+
+ set value(newValue) {
+ _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;
+
+ var zone = Zone.current;
+ inZone(f) => zone.bindCallback(f, runGuarded: false);
+ inZoneUnary(f) => zone.bindUnaryCallback(f, runGuarded: false);
+
+ return new JsObject.jsify({
+ 'open': inZoneUnary(
+ (callback) => bindable.open((x) => callback.apply([x]))),
+ 'close': inZone(() => bindable.close()),
+ 'discardChanges': inZone(() => bindable.value),
+ 'setValue': inZoneUnary((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
+ // Technically this works because 'deliver' is on PathObserver and
+ // CompoundObserver. But ideally Polymer-JS would not assume that.
+ 'deliver': inZone(() => bindable.deliver()),
+ // Save this so we can return it from [jsObjectToBindable]
+ '__dartBindable': bindable
+ });
+}
+
+/** Information about the instantiated template. */
+class TemplateInstance {
+ // TODO(rafaelw): firstNode & lastNode should be read-synchronous
+ // in cases where script has modified the template instance boundary.
+
+ /** The first node of this template instantiation. */
+ Node get firstNode => _firstNode;
+
+ /**
+ * The last node of this template instantiation.
+ * This could be identical to [firstNode] if the template only expanded to a
+ * single node.
+ */
+ Node get lastNode => _lastNode;
+
+ /** The model used to instantiate the template. */
+ final model;
+
+ Node _firstNode, _lastNode;
+
+ TemplateInstance(this.model);
+}

Powered by Google App Engine
This is Rietveld 408576698