OLD | NEW |
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 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 | 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. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 part of template_binding; | 5 part of template_binding; |
6 | 6 |
7 /** Extensions to the [Node] API. */ | 7 /** Extensions to the [Node] API. */ |
8 class NodeBindExtension { | 8 class NodeBindExtension { |
9 final Node _node; | 9 final Node _node; |
10 Map<String, Bindable> _bindings; | 10 |
| 11 /** |
| 12 * Gets the data bindings that are associated with this node, if any. |
| 13 * |
| 14 * This starts out null, and if [enableBindingsReflection] is enabled, calls |
| 15 * to [bind] will initialize this field and the binding. |
| 16 */ |
| 17 // Dart note: in JS this has a trailing underscore, meaning "private". |
| 18 // But in dart if we made it _bindings, it wouldn't be accessible at all. |
| 19 // It is unfortunately needed to implement Node.bind correctly. |
| 20 Map<String, Bindable> bindings; |
11 | 21 |
12 NodeBindExtension._(this._node); | 22 NodeBindExtension._(this._node); |
13 | 23 |
14 /** | 24 /** |
15 * Binds the attribute [name] to the [path] of the [model]. | 25 * Binds the attribute [name] to the [path] of the [model]. |
16 * Path is a String of accessors such as `foo.bar.baz`. | 26 * Path is a String of accessors such as `foo.bar.baz`. |
17 * Returns the `Bindable` instance. | 27 * Returns the [Bindable] instance. |
18 */ | 28 */ |
19 Bindable bind(String name, value, {bool oneTime: false}) { | 29 Bindable bind(String name, value, {bool oneTime: false}) { |
20 // TODO(jmesserly): in Dart we could deliver an async error, which would | 30 // TODO(jmesserly): in Dart we could deliver an async error, which would |
21 // have a similar affect but be reported as a test failure. Should we? | 31 // have a similar affect but be reported as a test failure. Should we? |
22 window.console.error('Unhandled binding to Node: ' | 32 window.console.error('Unhandled binding to Node: ' |
23 '$this $name $value $oneTime'); | 33 '$this $name $value $oneTime'); |
24 return null; | 34 return null; |
25 } | 35 } |
26 | 36 |
27 /** Unbinds the attribute [name]. */ | 37 /** |
28 void unbind(String name) { | 38 * Called when all [bind] calls are finished for a given template expansion. |
29 if (_bindings == null) return; | 39 */ |
30 var binding = bindings.remove(name); | 40 void bindFinished() {} |
31 if (binding != null) binding.close(); | |
32 } | |
33 | |
34 /** Unbinds all bound attributes. */ | |
35 void unbindAll() { | |
36 if (_bindings == null) return; | |
37 for (var binding in bindings.values.toList()) { | |
38 if (binding != null) binding.close(); | |
39 } | |
40 _bindings = null; | |
41 } | |
42 | |
43 // TODO(jmesserly): we should return a read-only wrapper here. | |
44 /** Gets the data bindings that are associated with this node. */ | |
45 Map<String, Bindable> get bindings { | |
46 if (_bindings == null) _bindings = new LinkedHashMap<String, Bindable>(); | |
47 return _bindings; | |
48 } | |
49 | 41 |
50 /** | 42 /** |
51 * Dispatch support so custom HtmlElement's can override these methods. | 43 * Dispatch support so custom HtmlElement's can override these methods. |
52 * A public method like [this.bind] should not call another public method such | 44 * |
53 * as [this.unbind]. Instead it should dispatch through [_self.unbind]. | 45 * A public method like [this.bind] should not call another public method. |
| 46 * |
| 47 * Instead it should dispatch through [_self] to give the "overridden" method |
| 48 * a chance to intercept. |
54 */ | 49 */ |
55 NodeBindExtension get _self => _node is NodeBindExtension ? _node : this; | 50 NodeBindExtension get _self => _node is NodeBindExtension ? _node : this; |
56 | 51 |
57 TemplateInstance _templateInstance; | 52 TemplateInstance _templateInstance; |
58 | 53 |
59 /** Gets the template instance that instantiated this node, if any. */ | 54 /** Gets the template instance that instantiated this node, if any. */ |
60 TemplateInstance get templateInstance => | 55 TemplateInstance get templateInstance => |
61 _templateInstance != null ? _templateInstance : | 56 _templateInstance != null ? _templateInstance : |
62 (_node.parent != null ? nodeBind(_node.parent).templateInstance : null); | 57 (_node.parent != null ? nodeBind(_node.parent).templateInstance : null); |
63 | 58 |
64 _open(Bindable bindable, callback(value)) => | 59 _open(Bindable bindable, callback(value)) => |
65 callback(bindable.open(callback)); | 60 callback(bindable.open(callback)); |
| 61 |
| 62 Bindable _maybeUpdateBindings(String name, Bindable binding) { |
| 63 return enableBindingsReflection ? _updateBindings(name, binding) : binding; |
| 64 } |
| 65 |
| 66 Bindable _updateBindings(String name, Bindable binding) { |
| 67 if (bindings == null) bindings = {}; |
| 68 var old = bindings[name]; |
| 69 if (old != null) old.close(); |
| 70 return bindings[name] = binding; |
| 71 } |
66 } | 72 } |
67 | 73 |
68 | 74 |
69 /** Information about the instantiated template. */ | 75 /** Information about the instantiated template. */ |
70 class TemplateInstance { | 76 class TemplateInstance { |
71 // TODO(rafaelw): firstNode & lastNode should be read-synchronous | 77 // TODO(rafaelw): firstNode & lastNode should be read-synchronous |
72 // in cases where script has modified the template instance boundary. | 78 // in cases where script has modified the template instance boundary. |
73 | 79 |
74 /** The first node of this template instantiation. */ | 80 /** The first node of this template instantiation. */ |
75 Node get firstNode => _firstNode; | 81 Node get firstNode => _firstNode; |
76 | 82 |
77 /** | 83 /** |
78 * The last node of this template instantiation. | 84 * The last node of this template instantiation. |
79 * This could be identical to [firstNode] if the template only expanded to a | 85 * This could be identical to [firstNode] if the template only expanded to a |
80 * single node. | 86 * single node. |
81 */ | 87 */ |
82 Node get lastNode => _lastNode; | 88 Node get lastNode => _lastNode; |
83 | 89 |
84 /** The model used to instantiate the template. */ | 90 /** The model used to instantiate the template. */ |
85 final model; | 91 final model; |
86 | 92 |
87 Node _firstNode, _lastNode; | 93 Node _firstNode, _lastNode; |
88 | 94 |
89 TemplateInstance(this.model); | 95 TemplateInstance(this.model); |
90 } | 96 } |
OLD | NEW |