Chromium Code Reviews| Index: sky/framework/sky-element/sky-element.sky |
| diff --git a/sky/framework/sky-element/sky-element.sky b/sky/framework/sky-element/sky-element.sky |
| index a6202df2763e4ac3f4e2fb2586f92bd05f068865..f3e928a7ff099b0d5d5fa0a06b41e23347689d5a 100644 |
| --- a/sky/framework/sky-element/sky-element.sky |
| +++ b/sky/framework/sky-element/sky-element.sky |
| @@ -7,6 +7,63 @@ |
| <script> |
| var templates = new Map(); |
| +var attributeDescriptors = { |
| + boolean: { |
| + type: 'boolean', |
| + convert: function(value) { |
| + if (typeof value == 'string') |
| + return value == 'true'; |
| + return !!value; |
| + }, |
| + }, |
| + number: { |
| + type: 'number', |
| + convert: function(value) { |
| + return Number(value); |
| + }, |
| + }, |
| + string: { |
| + type: 'string', |
| + convert: function(value) { |
| + if (value == null) |
|
abarth-chromium
2015/01/06 04:02:38
Why handle |null| special but not |undefined|?
esprehn
2015/01/06 04:10:24
undefined is itself a string, if I special case th
|
| + return ""; |
| + return String(value); |
| + }, |
| + }, |
| +}; |
| + |
| +function defineReflectedAttribute(prototype, descriptor, name) { |
|
abarth-chromium
2015/01/06 04:02:38
Why not just pass in the convert function instead
esprehn
2015/01/06 04:10:24
Done, originally I had a more complex idea for how
|
| + Object.defineProperty(prototype, name, { |
| + get: function() { |
| + return descriptor.convert(this.getAttribute(name)); |
| + }, |
| + set: function(newValue) { |
| + this.setAttribute(name, descriptor.convert(newValue)); |
| + }, |
| + enumerable: true, |
| + configurable: true, |
| + }); |
| + |
| + prototype[name + 'AttributeChanged'] = function(oldValue, newValue) { |
| + this.notifyPropertyChanged(name, descriptor.convert(oldValue), |
| + descriptor.convert(newValue)); |
| + }; |
| +} |
| + |
| +function defineReflectedAttributes(elementClass, list) { |
| + var attributeNames = (list || '').split(','); |
| + var prototype = elementClass.prototype; |
| + |
| + for (var i = 0; i < attributeNames.length; ++i) { |
| + var parts = attributeNames[i].split(':'); |
| + var name = parts[0].trim(); |
| + var type = (parts[1] || "").trim(); |
|
abarth-chromium
2015/01/06 04:02:38
s/""/''/ for consistency
esprehn
2015/01/06 04:10:24
done.
|
| + var descriptor = attributeDescriptors[type] || attributeDescriptors.string; |
| + |
| + defineReflectedAttribute(prototype, descriptor, name); |
| + } |
| +} |
| + |
| class SkyElement extends HTMLElement { |
| static register() { |
| @@ -23,6 +80,8 @@ class SkyElement extends HTMLElement { |
| if (template) |
| templates.set(tagName, template); |
| + defineReflectedAttributes(this, wrapper.getAttribute("attributes")); |
| + |
| return document.registerElement(tagName, { |
| prototype: this.prototype, |
| }); |
| @@ -51,6 +110,13 @@ class SkyElement extends HTMLElement { |
| createdCallback() { |
| this.isAttached = false; |
| this.created(); |
| + |
| + // Invoke attributeChanged callback when element is first created too. |
| + var attributes = this.getAttributes(); |
| + for (var i = 0; i < attributes.length; ++i) { |
| + var attribute = attributes[i]; |
| + this.attributeChangedCallback(attribute.name, null, attribute.value); |
| + } |
| } |
| attachedCallback() { |
| @@ -72,9 +138,23 @@ class SkyElement extends HTMLElement { |
| this.isAttached = false; |
| } |
| - attributeChangedCallback(attrName, oldValue, newValue) { |
| - // reserved for canonical behavior |
| - this.attributeChanged(attrName, oldValue, newValue); |
| + attributeChangedCallback(name, oldValue, newValue) { |
| + this.attributeChanged(name, oldValue, newValue); |
| + var handler = this[name + 'AttributeChanged']; |
| + if (typeof handler == 'function') |
| + handler.call(this, oldValue, newValue); |
| + } |
| + |
| + notifyPropertyChanged(name, oldValue, newValue) { |
| + var notifier = Object.getNotifier(this); |
| + notifier.notify({ |
| + type: 'update', |
| + name: name, |
| + oldValue: oldValue, |
| + }); |
| + var handler = this[name + 'Changed']; |
| + if (typeof handler == 'function') |
| + handler.call(this, oldValue, newValue); |
| } |
| }; |