Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(457)

Side by Side Diff: sky/framework/sky-element/sky-element.sky

Issue 856693002: Combine element registries from sky-binder and sky-element. (Closed) Base URL: git@github.com:domokit/mojo.git@master
Patch Set: Created 5 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « sky/framework/sky-element/sky-binder.sky ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 <import src="element-registry.sky" as="registry" />
7 <script> 8 <script>
8 var attributeConverters = { 9 function parseAttributeSpec(registration, definition) {
9 boolean: function(value) { 10 var spec = definition.getAttribute('attributes');
10 if (typeof value == 'string')
11 return value == 'true';
12 return !!value;
13 },
14 number: function(value) {
15 return Number(value);
16 },
17 string: function(value) {
18 if (value === null)
19 return '';
20 return String(value);
21 },
22 };
23
24 function parseAttributeSpec(spec) {
25 var attributes = new Map();
26 11
27 if (!spec) 12 if (!spec)
28 return attributes; 13 return;
29 14
30 var attributeTokens = spec.split(','); 15 var attributeTokens = spec.split(',');
31 16
32 for (var i = 0; i < attributeTokens.length; ++i) { 17 for (var i = 0; i < attributeTokens.length; ++i) {
33 var parts = attributeTokens[i].split(':'); 18 var parts = attributeTokens[i].split(':');
34 19
35 if (parts.length != 2) { 20 if (parts.length != 2) {
36 console.error('Invalid attribute spec "' + spec + '", attributes must' + 21 console.error('Invalid attribute spec "' + spec + '", attributes must' +
37 ' be {name}:{type}, where type is one of boolean, number or' + 22 ' be {name}:{type}, where type is one of boolean, number or' +
38 ' string.'); 23 ' string.');
39 continue; 24 continue;
40 } 25 }
41 26
42 var name = parts[0].trim(); 27 var name = parts[0].trim();
43 var type = parts[1].trim(); 28 var type = parts[1].trim();
44 var converter = attributeConverters[type];
45 29
46 if (!converter) { 30 registration.defineAttribute(name, type);
47 console.error('Invalid attribute spec "' + spec + '", type must be one'
48 + ' of boolean, number or string.');
49 continue;
50 }
51
52 attributes.set(name, converter);
53 } 31 }
54
55 return attributes;
56 } 32 }
57 33
58 function collectEventHandlers(definition) { 34 function parseEventHandlers(registration, definition) {
59 var eventHandlers = []; 35 var eventHandlers = [];
60 var attributes = definition.getAttributes(); 36 var attributes = definition.getAttributes();
61 37
62 for (var i = 0; i < attributes.length; i++) { 38 for (var i = 0; i < attributes.length; i++) {
63 var attr = attributes[i]; 39 var attr = attributes[i];
64 var name = attr.name; 40 var name = attr.name;
65 var value = attr.value; 41 var value = attr.value;
66 42
67 if (name.startsWith('on-')) { 43 if (name.startsWith('on-')) {
68 eventHandlers.push(name.substring(3)); 44 registration.eventHandlers.set(name.substring(3), value);
69 } 45 }
70 } 46 }
71
72 return eventHandlers;
73 } 47 }
74 48
75 function eventHandlerCallback(event) {
76 var element = event.currentTarget;
77 var registration = registrations.get(element.localName);
78 var method = registration.getEventHandler(event.type);
79 var handler = element[method];
80 if (handler instanceof Function)
81 return handler.call(element, event);
82 }
83
84 class ElementRegistration {
85 constructor(definition) {
86 this.definition = definition;
87 this.tagName = definition.getAttribute('name');
88 this.attributes = parseAttributeSpec(definition.getAttribute('attributes'));
89 this.eventHandlers = collectEventHandlers(definition);
90 this.template = definition.querySelector('template');
91 Object.preventExtensions(this);
92 }
93
94 getEventHandler(eventName) {
95 return this.definition.getAttribute('on-' + eventName);
96 }
97
98 synthesizeAttributes(prototype) {
99 this.attributes.forEach(function(converter, name) {
100 Object.defineProperty(prototype, name, {
101 get: function() {
102 return converter(this.getAttribute(name));
103 },
104 set: function(newValue) {
105 this.setAttribute(name, converter(newValue));
106 },
107 enumerable: true,
108 configurable: true,
109 });
110 });
111 }
112 }
113
114 var registrations = new Map();
115
116 class SkyElement extends HTMLElement { 49 class SkyElement extends HTMLElement {
117 50
118 static register() { 51 static register() {
119 var definition = document.currentScript.parentNode; 52 var definition = document.currentScript.parentNode;
120 53
121 if (definition.localName !== 'sky-element') { 54 if (definition.localName !== 'sky-element') {
122 throw new Error('register() calls must be inside a <sky-element>.'); 55 throw new Error('register() calls must be inside a <sky-element>.');
123 } 56 }
124 57
125 var registration = new ElementRegistration(definition); 58 var tagName = definition.getAttribute('name');
126 59 if (!tagName) {
127 if (!registration.tagName) {
128 throw new Error('<sky-element> must have a name.'); 60 throw new Error('<sky-element> must have a name.');
129 } 61 }
130 62
131 if (registrations.has(registration.tagName)) { 63 var registration = registry.registerElement(tagName);
132 throw new Error('Duplicate registration for tag name: ' + 64
133 registration.tagName); 65 parseAttributeSpec(registration, definition);
134 } 66 parseEventHandlers(registration, definition);
67
68 registration.template = definition.querySelector('template');
135 69
136 registration.synthesizeAttributes(this.prototype); 70 registration.synthesizeAttributes(this.prototype);
137 71
138 // TODO(esprehn): Combine the two element registries here and in sky binder. 72 return document.registerElement(tagName, {
139 binder.registerElement(registration.tagName, {
140 attributeNames: Array.from(registration.attributes.keys()),
141 });
142
143 registrations.set(registration.tagName, registration);
144 return document.registerElement(registration.tagName, {
145 prototype: this.prototype, 73 prototype: this.prototype,
146 }); 74 });
147 } 75 }
148 76
149 created() { 77 created() {
150 // override 78 // override
151 } 79 }
152 80
153 attached() { 81 attached() {
154 // override 82 // override
(...skipping 19 matching lines...) Expand all
174 102
175 Object.preventExtensions(this); 103 Object.preventExtensions(this);
176 104
177 // Invoke attributeChanged callback when element is first created too. 105 // Invoke attributeChanged callback when element is first created too.
178 var attributes = this.getAttributes(); 106 var attributes = this.getAttributes();
179 for (var i = 0; i < attributes.length; ++i) { 107 for (var i = 0; i < attributes.length; ++i) {
180 var attribute = attributes[i]; 108 var attribute = attributes[i];
181 this.attributeChangedCallback(attribute.name, null, attribute.value); 109 this.attributeChangedCallback(attribute.name, null, attribute.value);
182 } 110 }
183 111
184 var registration = registrations.get(this.localName); 112 var registration = registry.getRegistration(this.localName);
185 for (var i = 0; i < registration.eventHandlers.length; ++i) { 113 registration.addInstanceEventListeners(this);
186 var eventName = registration.eventHandlers[i];
187 this.addEventListener(eventName, eventHandlerCallback);
188 }
189 } 114 }
190 115
191 attachedCallback() { 116 attachedCallback() {
192 if (!this.shadowRoot) { 117 if (!this.shadowRoot) {
193 var registration = registrations.get(this.localName); 118 var registration = registry.getRegistration(this.localName);
194 if (registration.template) { 119 if (registration.template) {
195 var shadow = this.ensureShadowRoot(); 120 var shadow = this.ensureShadowRoot();
196 var instance = binder.createInstance(registration.template, this); 121 var instance = binder.createInstance(registration.template, this);
197 shadow.appendChild(instance.fragment); 122 shadow.appendChild(instance.fragment);
198 this.shadowRootReady(); 123 this.shadowRootReady();
199 } 124 }
200 } 125 }
201 this.attached(); 126 this.attached();
202 this.isAttached = true; 127 this.isAttached = true;
203 } 128 }
204 129
205 detachedCallback() { 130 detachedCallback() {
206 this.detached(); 131 this.detached();
207 this.isAttached = false; 132 this.isAttached = false;
208 } 133 }
209 134
210 attributeChangedCallback(name, oldValue, newValue) { 135 attributeChangedCallback(name, oldValue, newValue) {
211 this.attributeChanged(name, oldValue, newValue); 136 this.attributeChanged(name, oldValue, newValue);
212 var registration = registrations.get(this.localName); 137 var registration = registry.getRegistration(this.localName);
213 var converter = registration.attributes.get(name); 138 var converter = registration.attributes.get(name);
214 if (converter) { 139 if (converter) {
215 this.notifyPropertyChanged(name, converter(oldValue), 140 this.notifyPropertyChanged(name, converter(oldValue),
216 converter(newValue)); 141 converter(newValue));
217 } 142 }
218 } 143 }
219 144
220 notifyPropertyChanged(name, oldValue, newValue) { 145 notifyPropertyChanged(name, oldValue, newValue) {
221 if (oldValue == newValue) 146 if (oldValue == newValue)
222 return; 147 return;
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
259 binding.setValue(this[name]); 184 binding.setValue(this[name]);
260 binding.discardChanges(); 185 binding.discardChanges();
261 } 186 }
262 } 187 }
263 this.dirtyPropertyBindings = null; 188 this.dirtyPropertyBindings = null;
264 } 189 }
265 }; 190 };
266 191
267 module.exports = SkyElement; 192 module.exports = SkyElement;
268 </script> 193 </script>
OLDNEW
« no previous file with comments | « sky/framework/sky-element/sky-binder.sky ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698