| 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="sky-binder.sky" as="binder" /> | 6 <import src="sky-binder.sky" as="binder" /> |
| 7 <script> | 7 <script> |
| 8 var templates = new Map(); | 8 var templates = new Map(); |
| 9 | 9 |
| 10 var attributeConverters = { |
| 11 boolean: function(value) { |
| 12 if (typeof value == 'string') |
| 13 return value == 'true'; |
| 14 return !!value; |
| 15 }, |
| 16 number: function(value) { |
| 17 return Number(value); |
| 18 }, |
| 19 string: function(value) { |
| 20 if (value === null) |
| 21 return ''; |
| 22 return String(value); |
| 23 }, |
| 24 }; |
| 25 |
| 26 function defineReflectedAttribute(prototype, converter, name) { |
| 27 Object.defineProperty(prototype, name, { |
| 28 get: function() { |
| 29 return converter(this.getAttribute(name)); |
| 30 }, |
| 31 set: function(newValue) { |
| 32 this.setAttribute(name, converter(newValue)); |
| 33 }, |
| 34 enumerable: true, |
| 35 configurable: true, |
| 36 }); |
| 37 |
| 38 prototype[name + 'AttributeChanged'] = function(oldValue, newValue) { |
| 39 this.notifyPropertyChanged(name, converter(oldValue), converter(newValue)); |
| 40 }; |
| 41 } |
| 42 |
| 43 function defineReflectedAttributes(elementClass, list) { |
| 44 var attributeNames = (list || '').split(','); |
| 45 var prototype = elementClass.prototype; |
| 46 |
| 47 for (var i = 0; i < attributeNames.length; ++i) { |
| 48 var parts = attributeNames[i].split(':'); |
| 49 var name = parts[0].trim(); |
| 50 var type = (parts[1] || '').trim(); |
| 51 var converter = attributeConverters[type] || attributeConverters.string; |
| 52 |
| 53 defineReflectedAttribute(prototype, converter, name); |
| 54 } |
| 55 } |
| 56 |
| 10 class SkyElement extends HTMLElement { | 57 class SkyElement extends HTMLElement { |
| 11 | 58 |
| 12 static register() { | 59 static register() { |
| 13 var wrapper = document.currentScript.parentNode; | 60 var wrapper = document.currentScript.parentNode; |
| 14 | 61 |
| 15 if (wrapper.localName !== 'sky-element') | 62 if (wrapper.localName !== 'sky-element') |
| 16 throw new Error('No <sky-element>.'); | 63 throw new Error('No <sky-element>.'); |
| 17 | 64 |
| 18 var tagName = wrapper.getAttribute("name"); | 65 var tagName = wrapper.getAttribute('name'); |
| 19 if (!tagName) | 66 if (!tagName) |
| 20 throw new Error('<sky-element> must have a name.'); | 67 throw new Error('<sky-element> must have a name.'); |
| 21 | 68 |
| 22 var template = wrapper.querySelector('template'); | 69 var template = wrapper.querySelector('template'); |
| 23 if (template) | 70 if (template) |
| 24 templates.set(tagName, template); | 71 templates.set(tagName, template); |
| 25 | 72 |
| 73 defineReflectedAttributes(this, wrapper.getAttribute('attributes')); |
| 74 |
| 26 return document.registerElement(tagName, { | 75 return document.registerElement(tagName, { |
| 27 prototype: this.prototype, | 76 prototype: this.prototype, |
| 28 }); | 77 }); |
| 29 } | 78 } |
| 30 | 79 |
| 31 created() { | 80 created() { |
| 32 // override | 81 // override |
| 33 } | 82 } |
| 34 | 83 |
| 35 attached() { | 84 attached() { |
| 36 // override | 85 // override |
| 37 } | 86 } |
| 38 | 87 |
| 39 detached() { | 88 detached() { |
| 40 // override | 89 // override |
| 41 } | 90 } |
| 42 | 91 |
| 43 attributeChanged(attrName, oldValue, newValue) { | 92 attributeChanged(attrName, oldValue, newValue) { |
| 44 // override | 93 // override |
| 45 } | 94 } |
| 46 | 95 |
| 47 shadowRootReady() { | 96 shadowRootReady() { |
| 48 // override | 97 // override |
| 49 } | 98 } |
| 50 | 99 |
| 51 createdCallback() { | 100 createdCallback() { |
| 52 this.isAttached = false; | 101 this.isAttached = false; |
| 53 this.created(); | 102 this.created(); |
| 103 |
| 104 // Invoke attributeChanged callback when element is first created too. |
| 105 var attributes = this.getAttributes(); |
| 106 for (var i = 0; i < attributes.length; ++i) { |
| 107 var attribute = attributes[i]; |
| 108 this.attributeChangedCallback(attribute.name, null, attribute.value); |
| 109 } |
| 54 } | 110 } |
| 55 | 111 |
| 56 attachedCallback() { | 112 attachedCallback() { |
| 57 if (!this.shadowRoot) { | 113 if (!this.shadowRoot) { |
| 58 var template = templates.get(this.localName); | 114 var template = templates.get(this.localName); |
| 59 if (template) { | 115 if (template) { |
| 60 var shadow = this.ensureShadowRoot(); | 116 var shadow = this.ensureShadowRoot(); |
| 61 var instance = binder.createInstance(template, this); | 117 var instance = binder.createInstance(template, this); |
| 62 shadow.appendChild(instance.fragment); | 118 shadow.appendChild(instance.fragment); |
| 63 this.shadowRootReady(); | 119 this.shadowRootReady(); |
| 64 } | 120 } |
| 65 } | 121 } |
| 66 this.attached(); | 122 this.attached(); |
| 67 this.isAttached = true; | 123 this.isAttached = true; |
| 68 } | 124 } |
| 69 | 125 |
| 70 detachedCallback() { | 126 detachedCallback() { |
| 71 this.detached(); | 127 this.detached(); |
| 72 this.isAttached = false; | 128 this.isAttached = false; |
| 73 } | 129 } |
| 74 | 130 |
| 75 attributeChangedCallback(attrName, oldValue, newValue) { | 131 attributeChangedCallback(name, oldValue, newValue) { |
| 76 // reserved for canonical behavior | 132 this.attributeChanged(name, oldValue, newValue); |
| 77 this.attributeChanged(attrName, oldValue, newValue); | 133 var handler = this[name + 'AttributeChanged']; |
| 134 if (typeof handler == 'function') |
| 135 handler.call(this, oldValue, newValue); |
| 136 } |
| 137 |
| 138 notifyPropertyChanged(name, oldValue, newValue) { |
| 139 var notifier = Object.getNotifier(this); |
| 140 notifier.notify({ |
| 141 type: 'update', |
| 142 name: name, |
| 143 oldValue: oldValue, |
| 144 }); |
| 145 var handler = this[name + 'Changed']; |
| 146 if (typeof handler == 'function') |
| 147 handler.call(this, oldValue, newValue); |
| 78 } | 148 } |
| 79 }; | 149 }; |
| 80 | 150 |
| 81 module.exports = SkyElement; | 151 module.exports = SkyElement; |
| 82 </script> | 152 </script> |
| OLD | NEW |