OLD | NEW |
(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 library template_binding.src.node_binding; |
| 6 |
| 7 import 'dart:async' show StreamSubscription; |
| 8 import 'dart:html' show Node; |
| 9 import 'package:observe/observe.dart' show PathObserver, CompoundPathObserver; |
| 10 |
| 11 /** Test only method. Not re-exported. */ |
| 12 getObserverForTest(NodeBinding binding) => binding._observer; |
| 13 |
| 14 /** |
| 15 * A data binding on a [Node]. |
| 16 * See [NodeBindExtension.bindings] and [NodeBindExtension.bind]. |
| 17 */ |
| 18 abstract class NodeBinding { |
| 19 Node _node; |
| 20 var _model; |
| 21 |
| 22 // TODO(jmesserly): need common interface for PathObserver, |
| 23 // CompoundPathObserver. |
| 24 var _observer; |
| 25 StreamSubscription _pathSub; |
| 26 |
| 27 /** The property of [node] which will be data bound. */ |
| 28 final String property; |
| 29 |
| 30 /** The property of [node] which will be data bound. */ |
| 31 final String path; |
| 32 |
| 33 /** The node that has [property] which will be data bound. */ |
| 34 Node get node => _node; |
| 35 |
| 36 /** The bound data model. */ |
| 37 get model => _model; |
| 38 |
| 39 /** True if this binding has been [closed]. */ |
| 40 bool get closed => _node == null; |
| 41 |
| 42 /** The value at the [path] on [model]. */ |
| 43 get value => _observer.value; |
| 44 |
| 45 set value(newValue) { |
| 46 _observer.value = newValue; |
| 47 } |
| 48 |
| 49 NodeBinding(this._node, this.property, this._model, [String path]) |
| 50 : path = path != null ? path : '' { |
| 51 |
| 52 // Fast path if we're observing "value" |
| 53 if ((model is PathObserver || model is CompoundPathObserver) && |
| 54 path == 'value') { |
| 55 |
| 56 _observer = model; |
| 57 } else { |
| 58 // Create the path observer |
| 59 _observer = new PathObserver(model, this.path); |
| 60 } |
| 61 |
| 62 _pathSub = _observer.changes.listen((r) => valueChanged(value)); |
| 63 valueChanged(value); |
| 64 } |
| 65 |
| 66 /** Called when [value] changes to update the [node]. */ |
| 67 // TODO(jmesserly): the impl in template_binding uses reflection to set the |
| 68 // property, but that isn't used except for specific known fields like |
| 69 // "textContent", so I'm overridding this in the subclasses instead. |
| 70 void valueChanged(newValue); |
| 71 |
| 72 /** Called to sanitize the value before it is assigned into the property. */ |
| 73 sanitizeBoundValue(value) => value == null ? '' : '$value'; |
| 74 |
| 75 /** |
| 76 * Called by [NodeBindExtension.unbind] to close this binding and unobserve |
| 77 * the [path]. |
| 78 * |
| 79 * This can be overridden in subclasses, but they must call `super.close()` |
| 80 * to free associated resources. They must also check [closed] and return |
| 81 * immediately if already closed. |
| 82 */ |
| 83 void close() { |
| 84 if (closed) return; |
| 85 |
| 86 if (_pathSub != null) _pathSub.cancel(); |
| 87 _pathSub = null; |
| 88 _observer = null; |
| 89 _node = null; |
| 90 _model = null; |
| 91 } |
| 92 } |
OLD | NEW |