OLD | NEW |
1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2014, 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 /** | 5 /** |
6 * This library provides access to the Polymer project's | 6 * This library provides access to the Polymer project's |
7 * [Data Binding](http://www.polymer-project.org/docs/polymer/databinding.html) | 7 * [Data Binding](http://www.polymer-project.org/docs/polymer/databinding.html) |
8 * Find more information at the | 8 * Find more information at the |
9 * [Polymer.dart homepage](https://www.dartlang.org/polymer-dart/). | 9 * [Polymer.dart homepage](https://www.dartlang.org/polymer-dart/). |
10 * | 10 * |
11 * Extends the capabilities of the HTML Template Element by enabling it to | 11 * Extends the capabilities of the HTML Template Element by enabling it to |
12 * create, manage, and remove instances of content bound to data defined in | 12 * create, manage, and remove instances of content bound to data defined in |
13 * Dart. | 13 * Dart. |
14 * | 14 * |
15 * Node.bind() is a new method added to all DOM nodes which instructs them to | 15 * Node.bind() is a new method added to all DOM nodes which instructs them to |
16 * bind the named property to the data provided. These allows applications to | 16 * bind the named property to the data provided. These allows applications to |
17 * create a data model in Dart or JavaScript that DOM reacts to. | 17 * create a data model in Dart or JavaScript that DOM reacts to. |
18 */ | 18 */ |
19 library template_binding; | 19 library template_binding; |
20 | 20 |
21 import 'dart:async'; | 21 import 'dart:async'; |
22 import 'dart:collection'; | 22 import 'dart:collection'; |
23 import 'dart:html'; | 23 import 'dart:html'; |
| 24 import 'dart:js' as js show context; |
| 25 import 'dart:js' show JsObject; |
24 import 'dart:svg' show SvgSvgElement; | 26 import 'dart:svg' show SvgSvgElement; |
25 import 'package:observe/observe.dart'; | 27 import 'package:observe/observe.dart'; |
26 | 28 |
27 import 'src/mustache_tokens.dart'; | 29 import 'src/mustache_tokens.dart'; |
28 | 30 |
29 part 'src/binding_delegate.dart'; | 31 part 'src/binding_delegate.dart'; |
30 part 'src/element.dart'; | |
31 part 'src/input_bindings.dart'; | |
32 part 'src/input_element.dart'; | |
33 part 'src/instance_binding_map.dart'; | 32 part 'src/instance_binding_map.dart'; |
34 part 'src/node.dart'; | 33 part 'src/node.dart'; |
35 part 'src/select_element.dart'; | |
36 part 'src/template.dart'; | 34 part 'src/template.dart'; |
37 part 'src/template_iterator.dart'; | 35 part 'src/template_iterator.dart'; |
38 part 'src/text.dart'; | |
39 part 'src/text_area_element.dart'; | |
40 | 36 |
41 // TODO(jmesserly): ideally we would split TemplateBinding and Node.bind into | 37 // TODO(jmesserly): ideally we would split TemplateBinding and Node.bind into |
42 // two packages, but this is not easy when we are faking extension methods. | 38 // two packages, but this is not easy when we are faking extension methods. |
43 // Since TemplateElement needs to override Node.bind, it seems like the | 39 // Since TemplateElement needs to override Node.bind, it seems like the |
44 // Node.bind layer must have some innate knowledge of TemplateBinding. | 40 // Node.bind layer must have some innate knowledge of TemplateBinding. |
45 // NOTE: I've heard NodeBind might become an internal API, which is all the more | 41 // NOTE: I've heard NodeBind might become an internal API, which is all the more |
46 // reason to have it in this package. | 42 // reason to have it in this package. |
47 | 43 |
48 /** | 44 /** |
49 * Provides access to the data binding APIs for the [node]. For example: | 45 * Provides access to the data binding APIs for the [node]. For example: |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
101 * // otherwise, fall back to superclass | 97 * // otherwise, fall back to superclass |
102 * return nodeBindFallback(this).bind(name, model, path); | 98 * return nodeBindFallback(this).bind(name, model, path); |
103 * } | 99 * } |
104 * ... | 100 * ... |
105 * } | 101 * } |
106 */ | 102 */ |
107 NodeBindExtension nodeBindFallback(Node node) { | 103 NodeBindExtension nodeBindFallback(Node node) { |
108 var extension = _expando[node]; | 104 var extension = _expando[node]; |
109 if (extension != null) return extension; | 105 if (extension != null) return extension; |
110 | 106 |
111 // TODO(jmesserly): switch on localName? | 107 if (isSemanticTemplate(node)) { |
112 if (node is InputElement) { | 108 extension = new TemplateBindExtension._(node); |
113 extension = new _InputElementExtension(node); | |
114 } else if (node is SelectElement) { | |
115 extension = new _SelectElementExtension(node); | |
116 } else if (node is TextAreaElement) { | |
117 extension = new _TextAreaElementExtension(node); | |
118 } else if (node is Element) { | |
119 if (isSemanticTemplate(node)) { | |
120 extension = new TemplateBindExtension._(node); | |
121 } else { | |
122 extension = new _ElementExtension(node); | |
123 } | |
124 } else if (node is Text) { | |
125 extension = new _TextExtension(node); | |
126 } else { | 109 } else { |
127 extension = new NodeBindExtension._(node); | 110 extension = new NodeBindExtension._(node); |
128 } | 111 } |
129 | |
130 _expando[node] = extension; | 112 _expando[node] = extension; |
131 return extension; | 113 return extension; |
132 } | 114 } |
133 | 115 |
134 | 116 |
135 bool _isAttributeTemplate(Element n) => n.attributes.containsKey('template') && | 117 bool _isAttributeTemplate(Element n) => n.attributes.containsKey('template') && |
136 _SEMANTIC_TEMPLATE_TAGS.containsKey(n.localName); | 118 _SEMANTIC_TEMPLATE_TAGS.containsKey(n.localName); |
137 | 119 |
138 bool _isSvgTemplate(Element el) => el.tagName == 'template' && | 120 bool _isSvgTemplate(Element el) => el.tagName == 'template' && |
139 el.namespaceUri == 'http://www.w3.org/2000/svg'; | 121 el.namespaceUri == 'http://www.w3.org/2000/svg'; |
140 | 122 |
141 bool _isHtmlTemplate(Element el) => el.tagName == 'TEMPLATE' && | 123 bool _isHtmlTemplate(Element el) => el.tagName == 'TEMPLATE' && |
142 el.namespaceUri == 'http://www.w3.org/1999/xhtml'; | 124 el.namespaceUri == 'http://www.w3.org/1999/xhtml'; |
143 | 125 |
144 /** | 126 /** |
145 * Returns true if this node is semantically a template. | 127 * Returns true if this node is semantically a template. |
146 * | 128 * |
147 * A node is a template if [tagName] is TEMPLATE, or the node has the | 129 * A node is a template if [tagName] is TEMPLATE, or the node has the |
148 * 'template' attribute and this tag supports attribute form for backwards | 130 * 'template' attribute and this tag supports attribute form for backwards |
149 * compatibility with existing HTML parsers. The nodes that can use attribute | 131 * compatibility with existing HTML parsers. The nodes that can use attribute |
150 * form are table elments (THEAD, TBODY, TFOOT, TH, TR, TD, CAPTION, COLGROUP | 132 * form are table elements (THEAD, TBODY, TFOOT, TH, TR, TD, CAPTION, COLGROUP |
151 * and COL), OPTION, and OPTGROUP. | 133 * and COL), OPTION, and OPTGROUP. |
152 */ | 134 */ |
153 bool isSemanticTemplate(Node n) => n is Element && | 135 bool isSemanticTemplate(Node n) => n is Element && |
154 (_isHtmlTemplate(n) || _isAttributeTemplate(n) || _isSvgTemplate(n)); | 136 (_isHtmlTemplate(n) || _isAttributeTemplate(n) || _isSvgTemplate(n)); |
155 | 137 |
156 /** Returns true if this is the staging document for a template. */ | 138 /** Returns true if this is the staging document for a template. */ |
157 bool isTemplateStagingDocument(Document d) => _isStagingDocument[d] == true; | 139 bool isTemplateStagingDocument(Document d) => _isStagingDocument[d] == true; |
158 | 140 |
159 | 141 |
160 /** | 142 /** |
161 * True to enable [NodeBindingExtension.bindings]. This can be used by tools | 143 * True to enable [NodeBindingExtension.bindings]. This can be used by tools |
162 * such as UI builders to easily inspect live bindings. Defaults to false for | 144 * such as UI builders to easily inspect live bindings. Defaults to false for |
163 * performance reasons. | 145 * performance reasons. |
164 */ | 146 */ |
165 bool enableBindingsReflection = false; | 147 bool get enableBindingsReflection => |
| 148 js.context['Platform']['enableBindingsReflection'] == true; |
| 149 |
| 150 set enableBindingsReflection(bool value) { |
| 151 js.context['Platform']['enableBindingsReflection'] = value; |
| 152 } |
166 | 153 |
167 // TODO(jmesserly): const set would be better | 154 // TODO(jmesserly): const set would be better |
168 const _SEMANTIC_TEMPLATE_TAGS = const { | 155 const _SEMANTIC_TEMPLATE_TAGS = const { |
169 'caption': null, | 156 'caption': null, |
170 'col': null, | 157 'col': null, |
171 'colgroup': null, | 158 'colgroup': null, |
172 'option': null, | 159 'option': null, |
173 'optgroup': null, | 160 'optgroup': null, |
174 'tbody': null, | 161 'tbody': null, |
175 'td': null, | 162 'td': null, |
176 'tfoot': null, | 163 'tfoot': null, |
177 'th': null, | 164 'th': null, |
178 'thead': null, | 165 'thead': null, |
179 'tr': null, | 166 'tr': null, |
180 }; | 167 }; |
181 | 168 |
182 | 169 |
183 // TODO(jmesserly): investigate if expandos give us enough performance. | 170 // TODO(jmesserly): investigate if expandos give us enough performance. |
184 | 171 |
185 // The expando for storing our MDV extensions. | 172 // The expando for storing our MDV extensions. |
186 // | 173 // |
187 // In general, we need state associated with the nodes. Rather than having a | 174 // In general, we need state associated with the nodes. Rather than having a |
188 // bunch of individual expandos, we keep one per node. | 175 // bunch of individual expandos, we keep one per node. |
189 // | 176 // |
190 // Aside from the potentially helping performance, it also keeps things simpler | 177 // Aside from the potentially helping performance, it also keeps things simpler |
191 // if we decide to integrate MDV into the DOM later, and means less code needs | 178 // if we decide to integrate MDV into the DOM later, and means less code needs |
192 // to worry about expandos. | 179 // to worry about expandos. |
193 final Expando _expando = new Expando('template_binding'); | 180 final Expando _expando = new Expando('template_binding'); |
OLD | NEW |