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

Side by Side Diff: pkg/polymer/lib/src/declaration.dart

Issue 26051002: Updating Polymer to derive from custom elements. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 7 years, 2 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 | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 part of polymer; 5 part of polymer;
6 6
7 /** 7 /**
8 * **Deprecated**: use [Polymer.register] instead. 8 * **Deprecated**: use [Polymer.register] instead.
9 *
10 * Registers a [PolymerElement]. This is similar to [registerCustomElement]
11 * but it is designed to work with the `<element>` element and adds additional
12 * features.
13 */ 9 */
14 @deprecated 10 @deprecated
15 void registerPolymerElement(String localName, PolymerElement create()) { 11 void registerPolymerElement(String localName, PolymerElement create()) {
16 Polymer._registerClassMirror(localName, reflect(create()).type); 12 window.console.error('registerPolymerElement is not supported.');
17 } 13 }
18 14
19 /** 15 /**
20 * **Warning**: this class is experiental and subject to change. 16 * **Warning**: this class is experiental and subject to change.
21 * 17 *
22 * The implementation for the `polymer-element` element. 18 * The implementation for the `polymer-element` element.
23 * 19 *
24 * Normally you do not need to use this class directly, see [PolymerElement]. 20 * Normally you do not need to use this class directly, see [PolymerElement].
25 */ 21 */
26 class PolymerDeclaration extends CustomElement { 22 class PolymerDeclaration extends HtmlElement {
23 static const _TAG = 'polymer-element';
24
25 factory PolymerDeclaration() => new Element.tag(_TAG);
27 // Fully ported from revision: 26 // Fully ported from revision:
28 // https://github.com/Polymer/polymer/blob/4dc481c11505991a7c43228d3797d28f212 67779 27 // https://github.com/Polymer/polymer/blob/4dc481c11505991a7c43228d3797d28f212 67779
29 // 28 //
30 // src/declaration/attributes.js 29 // src/declaration/attributes.js
31 // src/declaration/events.js 30 // src/declaration/events.js
32 // src/declaration/polymer-element.js 31 // src/declaration/polymer-element.js
33 // src/declaration/properties.js 32 // src/declaration/properties.js
34 // src/declaration/prototype.js (note: most code not needed in Dart) 33 // src/declaration/prototype.js (note: most code not needed in Dart)
35 // src/declaration/styles.js 34 // src/declaration/styles.js
36 // 35 //
37 // Not yet ported: 36 // Not yet ported:
38 // src/declaration/path.js - blocked on HTMLImports.getDocumentUrl 37 // src/declaration/path.js - blocked on HTMLImports.getDocumentUrl
39 38
40 // TODO(jmesserly): these should be Type not ClassMirror. But we can't get 39 Type _type;
41 // from ClassMirror to Type yet in dart2js, so we use ClassMirror for now. 40 Type get type => _type;
42 // See https://code.google.com/p/dart/issues/detail?id=12607
43 ClassMirror _type;
44 ClassMirror get type => _type;
45 41
46 // TODO(jmesserly): this is a cache, because it's tricky in Dart to get from 42 // TODO(jmesserly): this is a cache, because it's tricky in Dart to get from
47 // ClassMirror -> Supertype. 43 // Type -> Supertype.
48 ClassMirror _supertype; 44 Type _supertype;
49 ClassMirror get supertype => _supertype; 45 Type get supertype => _supertype;
50 46
51 // TODO(jmesserly): this is also a cache, since we can't store .element on 47 // TODO(jmesserly): this is also a cache, since we can't store .element on
52 // each level of the __proto__ like JS does. 48 // each level of the __proto__ like JS does.
53 PolymerDeclaration _super; 49 PolymerDeclaration _super;
54 PolymerDeclaration get superDeclaration => _super; 50 PolymerDeclaration get superDeclaration => _super;
55 51
56 String _name; 52 String _name;
57 String get name => _name; 53 String get name => _name;
58 54
59 /** 55 /**
(...skipping 13 matching lines...) Expand all
73 69
74 Map<String, Object> _instanceAttributes; 70 Map<String, Object> _instanceAttributes;
75 71
76 List<Element> _sheets; 72 List<Element> _sheets;
77 List<Element> get sheets => _sheets; 73 List<Element> get sheets => _sheets;
78 74
79 List<Element> _styles; 75 List<Element> _styles;
80 List<Element> get styles => _styles; 76 List<Element> get styles => _styles;
81 77
82 DocumentFragment get templateContent { 78 DocumentFragment get templateContent {
83 final template = query('template'); 79 final template = this.query('template');
84 return template != null ? template.content : null; 80 return template != null ? template.content : null;
85 } 81 }
86 82
87 /** Maps event names and their associated method in the element class. */ 83 /** Maps event names and their associated method in the element class. */
88 final Map<String, String> _eventDelegates = {}; 84 final Map<String, String> _eventDelegates = {};
89 85
90 /** Expected events per element node. */ 86 /** Expected events per element node. */
91 // TODO(sigmund): investigate whether we need more than 1 set of local events 87 // TODO(sigmund): investigate whether we need more than 1 set of local events
92 // per element (why does the js implementation stores 1 per template node?) 88 // per element (why does the js implementation stores 1 per template node?)
93 Expando<Set<String>> _templateDelegates; 89 Expando<Set<String>> _templateDelegates;
94 90
95 void created() { 91 PolymerDeclaration.created() : super.created() {
96 super.created();
97
98 // fetch the element name 92 // fetch the element name
99 _name = attributes['name']; 93 _name = attributes['name'];
100 // install element definition, if ready 94 // install element definition, if ready
101 registerWhenReady(); 95 registerWhenReady();
102 } 96 }
103 97
104 void registerWhenReady() { 98 void registerWhenReady() {
105 // if we have no prototype, wait 99 // if we have no prototype, wait
106 if (waitingForType(name)) { 100 if (waitingForType(name)) {
107 return; 101 return;
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after
179 // setting resource paths. e.g. 173 // setting resource paths. e.g.
180 // this.$.image.src = this.resolvePath('images/foo.png') 174 // this.$.image.src = this.resolvePath('images/foo.png')
181 // Potentially remove when spec bug is addressed. 175 // Potentially remove when spec bug is addressed.
182 // https://www.w3.org/Bugs/Public/show_bug.cgi?id=21407 176 // https://www.w3.org/Bugs/Public/show_bug.cgi?id=21407
183 // TODO(jmesserly): resolvePath not ported, see first comment in this class. 177 // TODO(jmesserly): resolvePath not ported, see first comment in this class.
184 178
185 // under ShadowDOMPolyfill, transforms to approximate missing CSS features 179 // under ShadowDOMPolyfill, transforms to approximate missing CSS features
186 _shimShadowDomStyling(templateContent, name); 180 _shimShadowDomStyling(templateContent, name);
187 181
188 // register our custom element 182 // register our custom element
189 registerType(name); 183 registerType(name, extendsTag: extendee);
190 184
191 // NOTE: skip in Dart because we don't have mutable global scope. 185 // NOTE: skip in Dart because we don't have mutable global scope.
192 // reference constructor in a global named by 'constructor' attribute 186 // reference constructor in a global named by 'constructor' attribute
193 // publishConstructor(); 187 // publishConstructor();
194 } 188 }
195 189
196 /** 190 /**
197 * Gets the Dart type registered for this name, and sets up declarative 191 * Gets the Dart type registered for this name, and sets up declarative
198 * features. Fills in the [type] and [supertype] fields. 192 * features. Fills in the [type] and [supertype] fields.
199 * 193 *
200 * *Note*: unlike the JavaScript version, we do not have to metaprogram the 194 * *Note*: unlike the JavaScript version, we do not have to metaprogram the
201 * prototype, which simplifies this method. 195 * prototype, which simplifies this method.
202 */ 196 */
203 void buildType(String name, String extendee) { 197 void buildType(String name, String extendee) {
204 // get our custom type 198 // get our custom type
205 _type = _getRegisteredType(name); 199 _type = _getRegisteredType(name);
206 200
207 // get basal prototype 201 // get basal prototype
208 _supertype = _getRegisteredType(extendee); 202 _supertype = _getRegisteredType(extendee);
209 if (supertype != null) _super = _getDeclaration(supertype); 203 if (supertype != null) _super = _getDeclaration(supertype);
210 204
205 var cls = reflectClass(_type);
206
211 // transcribe `attributes` declarations onto own prototype's `publish` 207 // transcribe `attributes` declarations onto own prototype's `publish`
212 publishAttributes(type, _super); 208 publishAttributes(cls, _super);
213 209
214 publishProperties(type); 210 publishProperties(type);
215 211
216 inferObservers(type); 212 inferObservers(cls);
217 213
218 // Skip the rest in Dart: 214 // Skip the rest in Dart:
219 // chain various meta-data objects to inherited versions 215 // chain various meta-data objects to inherited versions
220 // chain custom api to inherited 216 // chain custom api to inherited
221 // build side-chained lists to optimize iterations 217 // build side-chained lists to optimize iterations
222 // inherit publishing meta-data 218 // inherit publishing meta-data
223 //this.inheritAttributesObjects(prototype); 219 //this.inheritAttributesObjects(prototype);
224 //this.inheritDelegates(prototype); 220 //this.inheritDelegates(prototype);
225 // x-platform fixups 221 // x-platform fixups
226 } 222 }
227 223
228 /** Implement various declarative features. */ 224 /** Implement various declarative features. */
229 void desugar() { 225 void desugar() {
230 // compile list of attributes to copy to instances 226 // compile list of attributes to copy to instances
231 accumulateInstanceAttributes(); 227 accumulateInstanceAttributes();
232 // parse on-* delegates declared on `this` element 228 // parse on-* delegates declared on `this` element
233 parseHostEvents(); 229 parseHostEvents();
234 // parse on-* delegates declared in templates 230 // parse on-* delegates declared in templates
235 parseLocalEvents(); 231 parseLocalEvents();
236 // install external stylesheets as if they are inline 232 // install external stylesheets as if they are inline
237 installSheets(); 233 installSheets();
234 var cls = reflectClass(type);
238 // TODO(jmesserly): this feels unnatrual in Dart. Since we have convenient 235 // TODO(jmesserly): this feels unnatrual in Dart. Since we have convenient
239 // lazy static initialization, can we get by without it? 236 // lazy static initialization, can we get by without it?
240 var registered = type.methods[#registerCallback]; 237 var registered = cls.methods[#registerCallback];
241 if (registered != null && registered.isStatic && 238 if (registered != null && registered.isStatic &&
242 registered.isRegularMethod) { 239 registered.isRegularMethod) {
243 type.invoke(#registerCallback, [this]); 240 cls.invoke(#registerCallback, [this]);
244 } 241 }
245 242
246 } 243 }
247 244
248 void registerType(String name) { 245 void registerType(String name, {String extendsTag}) {
249 // TODO(jmesserly): document.register 246 // native element must be specified in extends
250 registerCustomElement(name, () => 247 var nativeExtends = (extendsTag != null && !extendsTag.contains('-')) ?
251 type.newInstance(const Symbol(''), const []).reflectee); 248 extendsTag : null;
249 document.register(name, type, extendsTag: nativeExtends);
252 } 250 }
253 251
254 void publishAttributes(ClassMirror type, PolymerDeclaration superDecl) { 252 void publishAttributes(ClassMirror cls, PolymerDeclaration superDecl) {
255 // get properties to publish 253 // get properties to publish
256 if (superDecl != null && superDecl._publish != null) { 254 if (superDecl != null && superDecl._publish != null) {
257 _publish = new Map.from(superDecl._publish); 255 _publish = new Map.from(superDecl._publish);
258 } 256 }
259 _publish = _getProperties(type, _publish, (x) => x is PublishedProperty); 257 _publish = _getProperties(cls, _publish, (x) => x is PublishedProperty);
260 258
261 // merge names from 'attributes' attribute 259 // merge names from 'attributes' attribute
262 var attrs = attributes['attributes']; 260 var attrs = attributes['attributes'];
263 if (attrs != null) { 261 if (attrs != null) {
264 // names='a b c' or names='a,b,c' 262 // names='a b c' or names='a,b,c'
265 // record each name for publishing 263 // record each name for publishing
266 for (var attr in attrs.split(attrs.contains(',') ? ',' : ' ')) { 264 for (var attr in attrs.split(attrs.contains(',') ? ',' : ' ')) {
267 // remove excess ws 265 // remove excess ws
268 attr = attr.trim(); 266 attr = attr.trim();
269 267
270 // do not override explicit entries 268 // do not override explicit entries
271 if (_publish != null && _publish.containsKey(attr)) continue; 269 if (_publish != null && _publish.containsKey(attr)) continue;
272 270
273 var property = new Symbol(attr); 271 var property = new Symbol(attr);
274 var mirror = type.variables[property]; 272 var mirror = cls.variables[property];
275 if (mirror == null) { 273 if (mirror == null) {
276 mirror = type.getters[property]; 274 mirror = cls.getters[property];
277 if (mirror != null && !_hasSetter(type, mirror)) mirror = null; 275 if (mirror != null && !_hasSetter(cls, mirror)) mirror = null;
278 } 276 }
279 if (mirror == null) { 277 if (mirror == null) {
280 window.console.warn('property for attribute $attr of polymer-element ' 278 window.console.warn('property for attribute $attr of polymer-element '
281 'name=$name not found.'); 279 'name=$name not found.');
282 continue; 280 continue;
283 } 281 }
284 if (_publish == null) _publish = {}; 282 if (_publish == null) _publish = {};
285 _publish[attr] = mirror; 283 _publish[attr] = mirror;
286 } 284 }
287 } 285 }
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
321 void addAttributeDelegates(Map<String, String> delegates) { 319 void addAttributeDelegates(Map<String, String> delegates) {
322 attributes.forEach((name, value) { 320 attributes.forEach((name, value) {
323 if (_hasEventPrefix(name)) { 321 if (_hasEventPrefix(name)) {
324 delegates[_removeEventPrefix(name)] = value; 322 delegates[_removeEventPrefix(name)] = value;
325 } 323 }
326 }); 324 });
327 } 325 }
328 326
329 /** Extracts events under the element's <template>. */ 327 /** Extracts events under the element's <template>. */
330 void parseLocalEvents() { 328 void parseLocalEvents() {
331 for (var t in queryAll('template')) { 329 for (var t in this.queryAll('template')) {
332 final events = new Set<String>(); 330 final events = new Set<String>();
333 // acquire delegates from entire subtree at t 331 // acquire delegates from entire subtree at t
334 accumulateTemplatedEvents(t, events); 332 accumulateTemplatedEvents(t, events);
335 if (events.isNotEmpty) { 333 if (events.isNotEmpty) {
336 // store delegate information directly on template 334 // store delegate information directly on template
337 if (_templateDelegates == null) { 335 if (_templateDelegates == null) {
338 _templateDelegates = new Expando<Set<String>>(); 336 _templateDelegates = new Expando<Set<String>>();
339 } 337 }
340 _templateDelegates[t] = events; 338 _templateDelegates[t] = events;
341 } 339 }
(...skipping 135 matching lines...) Expand 10 before | Expand all | Expand 10 after
477 ..attributes[_STYLE_SCOPE_ATTRIBUTE] = '$name-$scopeDescriptor'; 475 ..attributes[_STYLE_SCOPE_ATTRIBUTE] = '$name-$scopeDescriptor';
478 } 476 }
479 477
480 /** 478 /**
481 * fetch a list of all observable properties names in our inheritance chain 479 * fetch a list of all observable properties names in our inheritance chain
482 * above Polymer. 480 * above Polymer.
483 */ 481 */
484 // TODO(sjmiles): perf: reflection is slow, relatively speaking 482 // TODO(sjmiles): perf: reflection is slow, relatively speaking
485 // If an element may take 6us to create, getCustomPropertyNames might 483 // If an element may take 6us to create, getCustomPropertyNames might
486 // cost 1.6us more. 484 // cost 1.6us more.
487 void inferObservers(ClassMirror type) { 485 void inferObservers(ClassMirror cls) {
488 for (var method in type.methods.values) { 486 for (var method in cls.methods.values) {
489 if (method.isStatic || !method.isRegularMethod) continue; 487 if (method.isStatic || !method.isRegularMethod) continue;
490 488
491 String name = MirrorSystem.getName(method.simpleName); 489 String name = MirrorSystem.getName(method.simpleName);
492 if (name.endsWith('Changed')) { 490 if (name.endsWith('Changed')) {
493 if (_observe == null) _observe = {}; 491 if (_observe == null) _observe = {};
494 name = name.substring(0, name.length - 7); 492 name = name.substring(0, name.length - 7);
495 _observe[name] = method.simpleName; 493 _observe[name] = method.simpleName;
496 } 494 }
497 } 495 }
498 } 496 }
499 497
500 void publishProperties(ClassMirror type) { 498 void publishProperties(Type type) {
501 // Dart note: _publish was already populated by publishAttributes 499 // Dart note: _publish was already populated by publishAttributes
502 if (_publish != null) _publishLC = _lowerCaseMap(_publish); 500 if (_publish != null) _publishLC = _lowerCaseMap(_publish);
503 } 501 }
504 502
505 Map<String, dynamic> _lowerCaseMap(Map<String, dynamic> properties) { 503 Map<String, dynamic> _lowerCaseMap(Map<String, dynamic> properties) {
506 final map = new Map<String, dynamic>(); 504 final map = new Map<String, dynamic>();
507 properties.forEach((name, value) { 505 properties.forEach((name, value) {
508 map[name.toLowerCase()] = value; 506 map[name.toLowerCase()] = value;
509 }); 507 });
510 return map; 508 return map;
511 } 509 }
512 } 510 }
513 511
514 /// maps tag names to prototypes 512 /// maps tag names to prototypes
515 final Map _typesByName = new Map<String, ClassMirror>(); 513 final Map _typesByName = new Map<String, Type>();
516 514
517 ClassMirror _getRegisteredType(String name) => _typesByName[name]; 515 Type _getRegisteredType(String name) => _typesByName[name];
518 516
519 /// elements waiting for prototype, by name 517 /// elements waiting for prototype, by name
520 final Map _waitType = new Map<String, PolymerDeclaration>(); 518 final Map _waitType = new Map<String, PolymerDeclaration>();
521 519
522 void _notifyType(String name) { 520 void _notifyType(String name) {
523 var waiting = _waitType.remove(name); 521 var waiting = _waitType.remove(name);
524 if (waiting != null) waiting.registerWhenReady(); 522 if (waiting != null) waiting.registerWhenReady();
525 } 523 }
526 524
527 /// elements waiting for super, by name 525 /// elements waiting for super, by name
528 final Map _waitSuper = new Map<String, List<PolymerDeclaration>>(); 526 final Map _waitSuper = new Map<String, List<PolymerDeclaration>>();
529 527
530 void _notifySuper(String name) { 528 void _notifySuper(String name) {
531 _registered.add(name); 529 _registered.add(name);
532 var waiting = _waitSuper.remove(name); 530 var waiting = _waitSuper.remove(name);
533 if (waiting != null) { 531 if (waiting != null) {
534 for (var w in waiting) { 532 for (var w in waiting) {
535 w.registerWhenReady(); 533 w.registerWhenReady();
536 } 534 }
537 } 535 }
538 } 536 }
539 537
540 /// track document.register'ed tag names 538 /// track document.register'ed tag names
541 final Set _registered = new Set<String>(); 539 final Set _registered = new Set<String>();
542 540
543 bool _isRegistered(name) => _registered.contains(name); 541 bool _isRegistered(name) => _registered.contains(name);
544 542
545 final Map _declarations = new Map<ClassMirror, PolymerDeclaration>(); 543 final Map _declarations = new Map<Type, PolymerDeclaration>();
546 544
547 PolymerDeclaration _getDeclaration(ClassMirror type) => _declarations[type]; 545 PolymerDeclaration _getDeclaration(Type type) => _declarations[type];
548 546
549 final _objectType = reflectClass(Object); 547 final _objectType = reflectClass(Object);
550 548
551 Map _getProperties(ClassMirror type, Map props, bool matches(metadata)) { 549 Map _getProperties(ClassMirror cls, Map props, bool matches(metadata)) {
552 for (var field in type.variables.values) { 550 for (var field in cls.variables.values) {
553 if (field.isFinal || field.isStatic || field.isPrivate) continue; 551 if (field.isFinal || field.isStatic || field.isPrivate) continue;
554 552
555 for (var meta in field.metadata) { 553 for (var meta in field.metadata) {
556 if (matches(meta.reflectee)) { 554 if (matches(meta.reflectee)) {
557 if (props == null) props = {}; 555 if (props == null) props = {};
558 props[MirrorSystem.getName(field.simpleName)] = field; 556 props[MirrorSystem.getName(field.simpleName)] = field;
559 break; 557 break;
560 } 558 }
561 } 559 }
562 } 560 }
563 561
564 for (var getter in type.getters.values) { 562 for (var getter in cls.getters.values) {
565 if (getter.isStatic || getter.isPrivate) continue; 563 if (getter.isStatic || getter.isPrivate) continue;
566 564
567 for (var meta in getter.metadata) { 565 for (var meta in getter.metadata) {
568 if (matches(meta.reflectee)) { 566 if (matches(meta.reflectee)) {
569 if (_hasSetter(type, getter)) { 567 if (_hasSetter(cls, getter)) {
570 if (props == null) props = {}; 568 if (props == null) props = {};
571 props[MirrorSystem.getName(getter.simpleName)] = getter; 569 props[MirrorSystem.getName(getter.simpleName)] = getter;
572 } 570 }
573 break; 571 break;
574 } 572 }
575 } 573 }
576 } 574 }
577 575
578 return props; 576 return props;
579 } 577 }
580 578
581 bool _hasSetter(ClassMirror type, MethodMirror getter) { 579 bool _hasSetter(ClassMirror cls, MethodMirror getter) {
582 var setterName = new Symbol('${MirrorSystem.getName(getter.simpleName)}='); 580 var setterName = new Symbol('${MirrorSystem.getName(getter.simpleName)}=');
583 return type.setters.containsKey(setterName); 581 return cls.setters.containsKey(setterName);
584 } 582 }
585 583
586 bool _inDartHtml(ClassMirror type) => type.owner.simpleName == #dart.dom.html;
587
588 584
589 /** Attribute prefix used for declarative event handlers. */ 585 /** Attribute prefix used for declarative event handlers. */
590 const _EVENT_PREFIX = 'on-'; 586 const _EVENT_PREFIX = 'on-';
591 587
592 /** Whether an attribute declares an event. */ 588 /** Whether an attribute declares an event. */
593 bool _hasEventPrefix(String attr) => attr.startsWith(_EVENT_PREFIX); 589 bool _hasEventPrefix(String attr) => attr.startsWith(_EVENT_PREFIX);
594 590
595 String _removeEventPrefix(String name) => name.substring(_EVENT_PREFIX.length); 591 String _removeEventPrefix(String name) => name.substring(_EVENT_PREFIX.length);
596 592
597 /** 593 /**
(...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after
703 return map; 699 return map;
704 }(); 700 }();
705 701
706 // Dart note: we need this function because we have additional renames JS does 702 // Dart note: we need this function because we have additional renames JS does
707 // not have. The JS renames are simply case differences, whereas we have ones 703 // not have. The JS renames are simply case differences, whereas we have ones
708 // like doubleclick -> dblclick and stripping the webkit prefix. 704 // like doubleclick -> dblclick and stripping the webkit prefix.
709 String _eventNameFromType(String eventType) { 705 String _eventNameFromType(String eventType) {
710 final result = _reverseEventTranslations[eventType]; 706 final result = _reverseEventTranslations[eventType];
711 return result != null ? result : eventType; 707 return result != null ? result : eventType;
712 } 708 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698