OLD | NEW |
1 <!-- | 1 <!-- |
2 // Copyright 2014 The Chromium Authors. All rights reserved. | 2 // Copyright 2014 The Chromium Authors. All rights reserved. |
3 // Use of this source code is governed by a BSD-style license that can be | 3 // Use of this source code is governed by a BSD-style license that can be |
4 // found in the LICENSE file. | 4 // found in the LICENSE file. |
5 --> | 5 --> |
6 <import src="observe.sky" as="observe" /> | 6 <import src="observe.sky" as="observe" /> |
7 | 7 |
8 <script> | 8 <script> |
9 var stagingDocument = new Document(); | 9 var stagingDocument = new Document(); |
10 | 10 |
11 class TemplateInstance { | 11 class TemplateInstance { |
12 constructor() { | 12 constructor() { |
13 this.bindings = []; | 13 this.bindings = []; |
14 this.terminator = null; | 14 this.terminator = null; |
15 this.fragment = stagingDocument.createDocumentFragment(); | 15 this.fragment = stagingDocument.createDocumentFragment(); |
16 Object.preventExtensions(this); | 16 Object.preventExtensions(this); |
17 } | 17 } |
18 close() { | 18 close() { |
19 var bindings = this.bindings; | 19 var bindings = this.bindings; |
20 for (var i = 0; i < bindings.length; i++) { | 20 for (var i = 0; i < bindings.length; i++) { |
21 bindings[i].close(); | 21 bindings[i].close(); |
22 } | 22 } |
23 } | 23 } |
24 } | 24 } |
25 | 25 |
26 var emptyInstance = new TemplateInstance(); | 26 var emptyInstance = new TemplateInstance(); |
27 var directiveCache = new WeakMap(); | 27 var directiveCache = new WeakMap(); |
28 | 28 |
| 29 // TODO(esprehn): It would be nice if these were exposed by the platform so |
| 30 // the framework didn't need to hard code a list. |
| 31 var defaultAttributesNames = new Set([ |
| 32 'accesskey', |
| 33 'alt', |
| 34 'as', |
| 35 'async', |
| 36 'class', |
| 37 'contenteditable', |
| 38 'crossorigin', |
| 39 'dir', |
| 40 'height', |
| 41 'href', |
| 42 'id', |
| 43 'is', |
| 44 'lang', |
| 45 'media', |
| 46 'name', |
| 47 'rel', |
| 48 'select', |
| 49 'sizes', |
| 50 'spellcheck', |
| 51 'src', |
| 52 'srcset', |
| 53 'style', |
| 54 'tabindex', |
| 55 'title', |
| 56 'type', |
| 57 'width', |
| 58 ]); |
| 59 var elementAttributeNames = new Map(); |
| 60 |
| 61 function registerElement(name, options) { |
| 62 elementAttributeNames.set(name, new Set(options.attributeNames)); |
| 63 } |
| 64 |
| 65 registerElement('template', { |
| 66 attributeNames: ['if', 'repeat'], |
| 67 }); |
| 68 |
29 function createInstance(template, model) { | 69 function createInstance(template, model) { |
30 var content = template.content; | 70 var content = template.content; |
31 if (!content.firstChild) | 71 if (!content.firstChild) |
32 return emptyInstance; | 72 return emptyInstance; |
33 | 73 |
34 var directives = directiveCache.get(content); | 74 var directives = directiveCache.get(content); |
35 if (!directives) { | 75 if (!directives) { |
36 directives = new NodeDirectives(content); | 76 directives = new NodeDirectives(content); |
37 directiveCache.set(content, directives); | 77 directiveCache.set(content, directives); |
38 } | 78 } |
(...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
147 result = new PropertyDirective(property); | 187 result = new PropertyDirective(property); |
148 result.expressions.push(new BindingExpression(prefix, path)); | 188 result.expressions.push(new BindingExpression(prefix, path)); |
149 } | 189 } |
150 | 190 |
151 if (result && offset < value.length) | 191 if (result && offset < value.length) |
152 result.suffix = value.substring(offset); | 192 result.suffix = value.substring(offset); |
153 | 193 |
154 return result; | 194 return result; |
155 } | 195 } |
156 | 196 |
| 197 function checkAttribute(name, allowedAttributeNames) { |
| 198 if (name.startsWith('data-')) |
| 199 return true; |
| 200 if (defaultAttributesNames.has(name)) |
| 201 return true; |
| 202 if (allowedAttributeNames && allowedAttributeNames.has(name)) |
| 203 return true; |
| 204 return false; |
| 205 } |
| 206 |
157 function parseAttributeDirectives(element, directives) { | 207 function parseAttributeDirectives(element, directives) { |
158 var attributes = element.getAttributes(); | 208 var attributes = element.getAttributes(); |
159 | 209 |
| 210 var allowedAttributeNames = elementAttributeNames.get(element.tagName); |
| 211 |
160 for (var i = 0; i < attributes.length; i++) { | 212 for (var i = 0; i < attributes.length; i++) { |
161 var attr = attributes[i]; | 213 var attr = attributes[i]; |
162 var name = attr.name; | 214 var name = attr.name; |
163 var value = attr.value; | 215 var value = attr.value; |
164 | 216 |
165 if (name.startsWith('on-')) { | 217 if (name.startsWith('on-')) { |
166 directives.eventHandlers.push(name.substring(3)); | 218 directives.eventHandlers.push(name.substring(3)); |
167 continue; | 219 continue; |
168 } | 220 } |
169 | 221 |
| 222 if (!checkAttribute(name, allowedAttributeNames)) { |
| 223 console.error('Element "'+ element.tagName + |
| 224 '" has unknown attribute "' + name + '".'); |
| 225 } |
| 226 |
170 var property = parsePropertyDirective(value, name); | 227 var property = parsePropertyDirective(value, name); |
171 if (!property) | 228 if (!property) |
172 continue; | 229 continue; |
173 | 230 |
174 directives.properties.push(property); | 231 directives.properties.push(property); |
175 } | 232 } |
176 } | 233 } |
177 | 234 |
178 function eventHandlerCallback(event) { | 235 function eventHandlerCallback(event) { |
179 var element = event.currentTarget; | 236 var element = event.currentTarget; |
(...skipping 280 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
460 if (this.valueObserver) | 517 if (this.valueObserver) |
461 this.valueObserver.close(); | 518 this.valueObserver.close(); |
462 | 519 |
463 iterators.delete(this.template); | 520 iterators.delete(this.template); |
464 this.closed = true; | 521 this.closed = true; |
465 } | 522 } |
466 } | 523 } |
467 | 524 |
468 module.exports = { | 525 module.exports = { |
469 createInstance: createInstance, | 526 createInstance: createInstance, |
| 527 registerElement: registerElement, |
470 }; | 528 }; |
471 </script> | 529 </script> |
OLD | NEW |