| 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 <import src="element-registry.sky" as="registry" /> |
| 7 | 8 |
| 8 <script> | 9 <script> |
| 9 var stagingDocument = new Document(); | 10 var stagingDocument = new Document(); |
| 10 | 11 |
| 11 class TemplateInstance { | 12 class TemplateInstance { |
| 12 constructor() { | 13 constructor() { |
| 13 this.bindings = []; | 14 this.bindings = []; |
| 14 this.terminator = null; | 15 this.terminator = null; |
| 15 this.fragment = stagingDocument.createDocumentFragment(); | 16 this.fragment = stagingDocument.createDocumentFragment(); |
| 16 Object.preventExtensions(this); | 17 Object.preventExtensions(this); |
| 17 } | 18 } |
| 18 close() { | 19 close() { |
| 19 var bindings = this.bindings; | 20 var bindings = this.bindings; |
| 20 for (var i = 0; i < bindings.length; i++) { | 21 for (var i = 0; i < bindings.length; i++) { |
| 21 bindings[i].close(); | 22 bindings[i].close(); |
| 22 } | 23 } |
| 23 } | 24 } |
| 24 } | 25 } |
| 25 | 26 |
| 26 var emptyInstance = new TemplateInstance(); | 27 var emptyInstance = new TemplateInstance(); |
| 27 var directiveCache = new WeakMap(); | 28 var directiveCache = new WeakMap(); |
| 28 | 29 |
| 29 // TODO(esprehn): It would be nice if these were exposed by the platform so | 30 (function() { |
| 30 // the framework didn't need to hard code a list. | 31 var templateRegistration = registry.registerElement('template'); |
| 31 var defaultAttributesNames = new Set([ | 32 templateRegistration.defineAttribute('if', 'string'); |
| 32 'accesskey', | 33 templateRegistration.defineAttribute('repeat', 'string'); |
| 33 'alt', | 34 })(); |
| 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 | 35 |
| 69 function createInstance(template, model) { | 36 function createInstance(template, model) { |
| 70 var content = template.content; | 37 var content = template.content; |
| 71 if (!content.firstChild) | 38 if (!content.firstChild) |
| 72 return emptyInstance; | 39 return emptyInstance; |
| 73 | 40 |
| 74 var directives = directiveCache.get(content); | 41 var directives = directiveCache.get(content); |
| 75 if (!directives) { | 42 if (!directives) { |
| 76 directives = new NodeDirectives(content); | 43 directives = new NodeDirectives(content); |
| 77 directiveCache.set(content, directives); | 44 directiveCache.set(content, directives); |
| (...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 189 result = new PropertyDirective(property); | 156 result = new PropertyDirective(property); |
| 190 result.expressions.push(new BindingExpression(prefix, path)); | 157 result.expressions.push(new BindingExpression(prefix, path)); |
| 191 } | 158 } |
| 192 | 159 |
| 193 if (result && offset < value.length) | 160 if (result && offset < value.length) |
| 194 result.suffix = value.substring(offset); | 161 result.suffix = value.substring(offset); |
| 195 | 162 |
| 196 return result; | 163 return result; |
| 197 } | 164 } |
| 198 | 165 |
| 199 function checkAttribute(name, allowedAttributeNames) { | |
| 200 if (name.startsWith('data-')) | |
| 201 return true; | |
| 202 if (defaultAttributesNames.has(name)) | |
| 203 return true; | |
| 204 if (allowedAttributeNames && allowedAttributeNames.has(name)) | |
| 205 return true; | |
| 206 return false; | |
| 207 } | |
| 208 | |
| 209 function parseAttributeDirectives(element, directives) { | 166 function parseAttributeDirectives(element, directives) { |
| 210 var attributes = element.getAttributes(); | 167 var attributes = element.getAttributes(); |
| 211 | 168 var tagName = element.tagName; |
| 212 var allowedAttributeNames = elementAttributeNames.get(element.tagName); | |
| 213 | 169 |
| 214 for (var i = 0; i < attributes.length; i++) { | 170 for (var i = 0; i < attributes.length; i++) { |
| 215 var attr = attributes[i]; | 171 var attr = attributes[i]; |
| 216 var name = attr.name; | 172 var name = attr.name; |
| 217 var value = attr.value; | 173 var value = attr.value; |
| 218 | 174 |
| 219 if (name.startsWith('on-')) { | 175 if (name.startsWith('on-')) { |
| 220 directives.eventHandlers.push(name.substring(3)); | 176 directives.eventHandlers.push(name.substring(3)); |
| 221 continue; | 177 continue; |
| 222 } | 178 } |
| 223 | 179 |
| 224 if (!checkAttribute(name, allowedAttributeNames)) { | 180 if (!registry.checkAttribute(tagName, name)) { |
| 225 console.error('Element "'+ element.tagName + | 181 console.error('Element "'+ tagName + |
| 226 '" has unknown attribute "' + name + '".'); | 182 '" has unknown attribute "' + name + '".'); |
| 227 } | 183 } |
| 228 | 184 |
| 229 var property = parsePropertyDirective(value, name); | 185 var property = parsePropertyDirective(value, name); |
| 230 if (!property) | 186 if (!property) |
| 231 continue; | 187 continue; |
| 232 | 188 |
| 233 directives.properties.push(property); | 189 directives.properties.push(property); |
| 234 } | 190 } |
| 235 } | 191 } |
| (...skipping 283 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 519 if (this.valueObserver) | 475 if (this.valueObserver) |
| 520 this.valueObserver.close(); | 476 this.valueObserver.close(); |
| 521 | 477 |
| 522 iterators.delete(this.template); | 478 iterators.delete(this.template); |
| 523 this.closed = true; | 479 this.closed = true; |
| 524 } | 480 } |
| 525 } | 481 } |
| 526 | 482 |
| 527 module.exports = { | 483 module.exports = { |
| 528 createInstance: createInstance, | 484 createInstance: createInstance, |
| 529 registerElement: registerElement, | |
| 530 }; | 485 }; |
| 531 </script> | 486 </script> |
| OLD | NEW |