| Index: sky/framework/sky-element.sky
|
| diff --git a/sky/framework/sky-element.sky b/sky/framework/sky-element.sky
|
| index 2fdc62ad65dcf10e6f0301995ed6ca375e637f41..e1d0a0ea715da04f9ea53e51ecceeb5be2b74d6f 100644
|
| --- a/sky/framework/sky-element.sky
|
| +++ b/sky/framework/sky-element.sky
|
| @@ -7,9 +7,61 @@
|
| import "dart:mirrors";
|
| import "dart:sky";
|
|
|
| +typedef dynamic _Converter(String value);
|
| +
|
| +final Map<String, _Converter> _kAttributeConverters = {
|
| + 'boolean': (String value) {
|
| + return value == 'true';
|
| + },
|
| + 'number': (String value) {
|
| + return double.parse(value);
|
| + },
|
| + 'string': (String value) {
|
| + return value == null ? '' : value;
|
| + },
|
| +};
|
| +
|
| class _Registration {
|
| - Element template;
|
| + final Element template;
|
| + final Map<String, _Converter> attributes = new Map();
|
| +
|
| _Registration(this.template);
|
| +
|
| + void parseAttributeSpec(definition) {
|
| + String spec = definition.getAttribute('attributes');
|
| + if (spec == null)
|
| + return;
|
| +
|
| + for (String token in spec.split(',')) {
|
| + List<String> parts = token.split(':');
|
| +
|
| + if (parts.length != 2) {
|
| + window.console.error(
|
| + 'Invalid attribute spec "${spec}", attributes must'
|
| + ' be {name}:{type}, where type is one of boolean, number or'
|
| + ' string.');
|
| + continue;
|
| + }
|
| +
|
| + var name = parts[0].trim();
|
| + var type = parts[1].trim();
|
| +
|
| + defineAttribute(name, type);
|
| + }
|
| + }
|
| +
|
| + void defineAttribute(String name, String type) {
|
| + _Converter converter = _kAttributeConverters[type];
|
| +
|
| + if (converter == null) {
|
| + window.console.error(
|
| + 'Invalid attribute type "${type}", type must be one of boolean,'
|
| + ' number or string.');
|
| + return;
|
| + }
|
| +
|
| + attributes[name] = converter;
|
| + }
|
| }
|
|
|
| final Map<String, _Registration> _registery = new Map<String, _Registration>();
|
| @@ -33,21 +85,21 @@ abstract class SkyElement extends Element {
|
| void shadowRootReady() {}
|
|
|
| String get tagName => _getTagName(runtimeType);
|
| + _Registration _registration;
|
|
|
| SkyElement() {
|
| - created();
|
| -
|
| + _registration = _registery[tagName];
|
| // Invoke attributeChanged callback when element is first created too.
|
| + // TODO(abarth): Is this necessary? We shouldn't have any attribute yet...
|
| for (Attr attribute in getAttributes())
|
| attributeChangedCallback(attribute.name, null, attribute.value);
|
| }
|
|
|
| attachedCallback() {
|
| if (shadowRoot == null) {
|
| - var registration = _registery[tagName];
|
| - if (registration.template != null) {
|
| + if (_registration.template != null) {
|
| ShadowRoot shadow = ensureShadowRoot();
|
| - Node content = registration.template.content;
|
| + Node content = _registration.template.content;
|
| shadow.appendChild(document.importNode(content, deep: true));
|
| shadowRootReady();
|
| }
|
| @@ -61,6 +113,30 @@ abstract class SkyElement extends Element {
|
|
|
| attributeChangedCallback(name, oldValue, newValue) {
|
| attributeChanged(name, oldValue, newValue);
|
| +
|
| + _Converter converter = _registration.attributes[name];
|
| + if (converter == null)
|
| + return;
|
| + Symbol callback = new Symbol('${name}Changed');
|
| + InstanceMirror mirror = reflect(this);
|
| + if (mirror.type.instanceMembers.containsKey(callback))
|
| + mirror.invoke(callback, [converter(oldValue), converter(newValue)]);
|
| + }
|
| +
|
| + noSuchMethod(Invocation invocation) {
|
| + String name = MirrorSystem.getName(invocation.memberName);
|
| + if (name.endsWith('='))
|
| + name = name.substring(0, name.length - 1);
|
| + _Converter converter = _registration.attributes[name];
|
| + if (converter != null) {
|
| + if (invocation.isGetter) {
|
| + return converter(getAttribute(name));
|
| + } else if (invocation.isSetter) {
|
| + setAttribute(name, invocation.positionalArguments[0].toString());
|
| + return;
|
| + }
|
| + }
|
| + return super.noSuchMethod(invocation);
|
| }
|
| }
|
|
|
| @@ -78,6 +154,7 @@ void register(Element script, Type type) {
|
| Element template = definition.querySelector('template');
|
|
|
| document.registerElement(tagName, type);
|
| - _registery[tagName] = new _Registration(template);
|
| + _registery[tagName] = new _Registration(template)
|
| + ..parseAttributeSpec(definition);
|
| }
|
| </script>
|
|
|