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

Unified 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 side-by-side diff with in-line comments
Download patch
Index: pkg/mdv/lib/src/node.dart
diff --git a/pkg/mdv/lib/src/node.dart b/pkg/mdv/lib/src/node.dart
index 0379838f5aca8f4cf96f49b76c09eabcc878281c..d2fa6d40c7b239734dfae4d7c33a9ed5a73f3fc1 100644
--- a/pkg/mdv/lib/src/node.dart
+++ b/pkg/mdv/lib/src/node.dart
@@ -7,23 +7,50 @@ part of mdv;
/** Extensions to the [Node] API. */
class _NodeExtension {
final Node node;
+ Map<String, NodeBinding> _bindings;
_NodeExtension(this.node);
+ NodeBinding createBinding(String name, model, String path) => null;
+
/**
* Binds the attribute [name] to the [path] of the [model].
* Path is a String of accessors such as `foo.bar.baz`.
*/
- void bind(String name, model, String path) {
- window.console.error('Unhandled binding to Node: '
- '$this $name $model $path');
+ NodeBinding bind(String name, model, String path) {
+ var binding = bindings[name];
+ if (binding != null) binding.close();
+
+ binding = createBinding(name, model, path);
+ bindings[name] = binding;
+ if (binding == null) {
+ window.console.error('Unhandled binding to Node: '
+ '$this $name $model $path');
+ }
+ return binding;
}
/** Unbinds the attribute [name]. */
- void unbind(String name) {}
+ void unbind(String name) {
+ if (_bindings == null) return;
+ var binding = bindings.remove(name);
+ if (binding != null) binding.close();
+ }
/** Unbinds all bound attributes. */
- void unbindAll() {}
+ void unbindAll() {
+ if (_bindings == null) return;
+ for (var binding in bindings.values) {
+ if (binding != null) binding.close();
+ }
+ _bindings = null;
+ }
+
+ // TODO(jmesserly): we should return a read-only wrapper here.
+ Map<String, NodeBinding> get bindings {
+ if (_bindings == null) _bindings = new LinkedHashMap<String, NodeBinding>();
+ return _bindings;
+ }
TemplateInstance _templateInstance;
@@ -32,3 +59,71 @@ class _NodeExtension {
_templateInstance != null ? _templateInstance :
(node.parent != null ? node.parent.templateInstance : null);
}
+
+/** A data binding on a [Node]. See [Node.bindings] and [Node.bind]. */
+abstract class NodeBinding {
+ Node _node;
+ var _model;
+ PathObserver _observer;
+ StreamSubscription _pathSub;
+
+ /** The property of [node] which will be data bound. */
+ final String property;
+
+ /** The property of [node] which will be data bound. */
+ final String path;
+
+ /** The node that has [property] which will be data bound. */
+ Node get node => _node;
+
+ /**
+ * The bound data model.
Siggi Cherem (dart-lang) 2013/07/25 16:24:12 silly nit: this fits in 1 line (/** ... */)
+ */
+ get model => _model;
+
+ /** True if this binding has been [closed]. */
+ bool get closed => _observer == null;
+
+ /** The value at the [path] on [model]. */
+ get value => _observer.value;
+
+ set value(newValue) {
+ _observer.value = newValue;
+ }
+
+ NodeBinding(this._node, this.property, this._model, this.path) {
+ // Create the path observer
+ _observer = new PathObserver(model, path);
+ _observePath();
+ }
+
+ void _observePath() {
+ _pathSub = _observer.bindSync(boundValueChanged);
+ }
+
+ /** Called when [value] changes to update the [node]. */
+ // TODO(jmesserly): the impl in MDV uses mirrors to set the property,
+ // but that isn't used except for specific known fields like "textContent",
+ // so I'm overridding this in the subclasses instead.
+ void boundValueChanged(newValue);
+
+ /** Called to sanitize the value before it is assigned into the property. */
+ sanitizeBoundValue(value) => value == null ? '' : '$value';
+
+ /**
+ * Called by [Node.unbind] to close this binding and unobserve the [path].
+ *
+ * This can be overridden in subclasses, but they must call `super.close()`
+ * to free associated resources. They must also check [closed] and return
+ * immediately if already closed.
+ */
+ void close() {
+ if (closed) return;
+
+ if (_pathSub != null) _pathSub.cancel();
+ _pathSub = null;
+ _observer = null;
+ _node = null;
+ _model = null;
+ }
+}

Powered by Google App Engine
This is Rietveld 408576698