OLD | NEW |
---|---|
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 * **Warning**: this class is experiental and subject to change. | 8 * **Warning**: this class is experiental and subject to change. |
9 * | 9 * |
10 * The implementation for the `polymer-element` element. | 10 * The implementation for the `polymer-element` element. |
(...skipping 23 matching lines...) Expand all Loading... | |
34 // TODO(jmesserly): this is a cache, because it's tricky in Dart to get from | 34 // TODO(jmesserly): this is a cache, because it's tricky in Dart to get from |
35 // Type -> Supertype. | 35 // Type -> Supertype. |
36 Type _supertype; | 36 Type _supertype; |
37 Type get supertype => _supertype; | 37 Type get supertype => _supertype; |
38 | 38 |
39 // TODO(jmesserly): this is also a cache, since we can't store .element on | 39 // TODO(jmesserly): this is also a cache, since we can't store .element on |
40 // each level of the __proto__ like JS does. | 40 // each level of the __proto__ like JS does. |
41 PolymerDeclaration _super; | 41 PolymerDeclaration _super; |
42 PolymerDeclaration get superDeclaration => _super; | 42 PolymerDeclaration get superDeclaration => _super; |
43 | 43 |
44 String _extendsName; | |
45 | |
44 String _name; | 46 String _name; |
45 String get name => _name; | 47 String get name => _name; |
46 | 48 |
47 /** | 49 /** |
48 * Map of publish properties. Can be a [VariableMirror] or a [MethodMirror] | 50 * Map of publish properties. Can be a [VariableMirror] or a [MethodMirror] |
49 * representing a getter. If it is a getter, there will also be a setter. | 51 * representing a getter. If it is a getter, there will also be a setter. |
52 * | |
53 * Note: technically these are always single properties, so we could use | |
54 * a Symbol instead of a PropertyPath. However there are lookups between | |
55 * this map and [_observe] so it is easier to just track paths. | |
50 */ | 56 */ |
51 Map<Symbol, DeclarationMirror> _publish; | 57 Map<PropertyPath, DeclarationMirror> _publish; |
52 | 58 |
53 /** The names of published properties for this polymer-element. */ | 59 /** The names of published properties for this polymer-element. */ |
54 Iterable<Symbol> get publishedProperties => | 60 Iterable<String> get publishedProperties => |
55 _publish != null ? _publish.keys : const []; | 61 _publish != null ? _publish.keys.map((p) => '$p') : const []; |
56 | 62 |
57 /** Same as [_publish] but with lower case names. */ | 63 /** Same as [_publish] but with lower case names. */ |
58 Map<String, DeclarationMirror> _publishLC; | 64 Map<String, DeclarationMirror> _publishLC; |
59 | 65 |
60 Map<Symbol, Symbol> _observe; | 66 Map<PropertyPath, Symbol> _observe; |
61 | 67 |
62 Map<String, Object> _instanceAttributes; | 68 Map<String, Object> _instanceAttributes; |
63 | 69 |
64 List<Element> _sheets; | 70 List<Element> _sheets; |
65 List<Element> get sheets => _sheets; | 71 List<Element> get sheets => _sheets; |
66 | 72 |
67 List<Element> _styles; | 73 List<Element> _styles; |
68 List<Element> get styles => _styles; | 74 List<Element> get styles => _styles; |
69 | 75 |
70 DocumentFragment get templateContent { | 76 DocumentFragment get templateContent { |
71 final template = this.querySelector('template'); | 77 final template = this.querySelector('template'); |
72 return template != null ? templateBind(template).content : null; | 78 return template != null ? templateBind(template).content : null; |
73 } | 79 } |
74 | 80 |
75 /** Maps event names and their associated method in the element class. */ | 81 /** Maps event names and their associated method in the element class. */ |
76 final Map<String, String> _eventDelegates = {}; | 82 final Map<String, String> _eventDelegates = {}; |
77 | 83 |
78 /** Expected events per element node. */ | 84 /** Expected events per element node. */ |
79 // TODO(sigmund): investigate whether we need more than 1 set of local events | 85 // TODO(sigmund): investigate whether we need more than 1 set of local events |
80 // per element (why does the js implementation stores 1 per template node?) | 86 // per element (why does the js implementation stores 1 per template node?) |
81 Expando<Set<String>> _templateDelegates; | 87 Expando<Set<String>> _templateDelegates; |
82 | 88 |
83 PolymerDeclaration.created() : super.created() { | 89 PolymerDeclaration.created() : super.created() { |
84 // fetch the element name | 90 // fetch the element name |
85 _name = attributes['name']; | 91 _name = attributes['name']; |
92 // fetch our extendee name | |
93 _extendsName = attributes['extends']; | |
86 // install element definition, if ready | 94 // install element definition, if ready |
87 registerWhenReady(); | 95 registerWhenReady(); |
88 } | 96 } |
89 | 97 |
90 void registerWhenReady() { | 98 void registerWhenReady() { |
91 // if we have no prototype, wait | 99 // if we have no prototype, wait |
92 if (waitingForType(name)) { | 100 if (waitingForType(name)) { |
93 return; | 101 return; |
94 } | 102 } |
95 // fetch our extendee name | 103 if (waitingForExtendee(_extendsName)) { |
96 var extendee = attributes['extends']; | |
97 if (waitingForExtendee(extendee)) { | |
98 //console.warn(name + ': waitingForExtendee:' + extendee); | 104 //console.warn(name + ': waitingForExtendee:' + extendee); |
99 return; | 105 return; |
100 } | 106 } |
101 // TODO(sjmiles): HTMLImports polyfill awareness: | 107 // TODO(sjmiles): HTMLImports polyfill awareness: |
102 // elements in the main document are likely to parse | 108 // elements in the main document are likely to parse |
103 // in advance of elements in imports because the | 109 // in advance of elements in imports because the |
104 // polyfill parser is simulated | 110 // polyfill parser is simulated |
105 // therefore, wait for imports loaded before | 111 // therefore, wait for imports loaded before |
106 // finalizing elements in the main document | 112 // finalizing elements in the main document |
107 // TODO(jmesserly): Polymer.dart waits for HTMLImportsLoaded, so I've | 113 // TODO(jmesserly): Polymer.dart waits for HTMLImportsLoaded, so I've |
108 // removed "whenImportsLoaded" for now. Restore the workaround if needed. | 114 // removed "whenImportsLoaded" for now. Restore the workaround if needed. |
109 _register(extendee); | 115 _register(_extendsName); |
110 } | 116 } |
111 | 117 |
112 void _register(extendee) { | 118 void _register(extendee) { |
113 //console.group('registering', name); | 119 //console.group('registering', name); |
114 register(name, extendee); | 120 register(name, extendee); |
115 //console.groupEnd(); | 121 //console.groupEnd(); |
116 // subclasses may now register themselves | 122 // subclasses may now register themselves |
117 _notifySuper(name); | 123 _notifySuper(name); |
118 } | 124 } |
119 | 125 |
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
181 | 187 |
182 // get basal prototype | 188 // get basal prototype |
183 _supertype = _getRegisteredType(extendee); | 189 _supertype = _getRegisteredType(extendee); |
184 if (_supertype != null) _super = _getDeclaration(extendee); | 190 if (_supertype != null) _super = _getDeclaration(extendee); |
185 | 191 |
186 var cls = reflectClass(_type); | 192 var cls = reflectClass(_type); |
187 | 193 |
188 // transcribe `attributes` declarations onto own prototype's `publish` | 194 // transcribe `attributes` declarations onto own prototype's `publish` |
189 publishAttributes(cls, _super); | 195 publishAttributes(cls, _super); |
190 | 196 |
191 publishProperties(type); | 197 publishProperties(_type); |
192 | 198 |
193 inferObservers(cls); | 199 inferObservers(cls); |
194 | 200 |
201 // desugar compound observer syntax, e.g. @ObserveProperty('a b c') | |
202 explodeObservers(cls); | |
203 | |
195 // Skip the rest in Dart: | 204 // Skip the rest in Dart: |
196 // chain various meta-data objects to inherited versions | 205 // chain various meta-data objects to inherited versions |
197 // chain custom api to inherited | 206 // chain custom api to inherited |
198 // build side-chained lists to optimize iterations | 207 // build side-chained lists to optimize iterations |
199 // inherit publishing meta-data | 208 // inherit publishing meta-data |
200 // x-platform fixup | 209 // x-platform fixup |
201 } | 210 } |
202 | 211 |
203 /** Implement various declarative features. */ | 212 /** Implement various declarative features. */ |
204 void desugar(name, extendee) { | 213 void desugar(name, extendee) { |
205 // compile list of attributes to copy to instances | 214 // compile list of attributes to copy to instances |
206 accumulateInstanceAttributes(); | 215 accumulateInstanceAttributes(); |
207 // parse on-* delegates declared on `this` element | 216 // parse on-* delegates declared on `this` element |
208 parseHostEvents(); | 217 parseHostEvents(); |
209 // install external stylesheets as if they are inline | 218 // install external stylesheets as if they are inline |
210 installSheets(); | 219 installSheets(); |
211 | 220 |
221 adjustShadowElement(); | |
222 | |
212 // TODO(sorvell): install a helper method this.resolvePath to aid in | 223 // TODO(sorvell): install a helper method this.resolvePath to aid in |
213 // setting resource paths. e.g. | 224 // setting resource paths. e.g. |
214 // this.$.image.src = this.resolvePath('images/foo.png') | 225 // this.$.image.src = this.resolvePath('images/foo.png') |
215 // Potentially remove when spec bug is addressed. | 226 // Potentially remove when spec bug is addressed. |
216 // https://www.w3.org/Bugs/Public/show_bug.cgi?id=21407 | 227 // https://www.w3.org/Bugs/Public/show_bug.cgi?id=21407 |
217 // TODO(jmesserly): resolvePath not ported, see first comment in this class. | 228 // TODO(jmesserly): resolvePath not ported, see first comment in this class. |
218 | 229 |
219 // under ShadowDOMPolyfill, transforms to approximate missing CSS features | 230 // under ShadowDOMPolyfill, transforms to approximate missing CSS features |
220 _shimShadowDomStyling(templateContent, name, extendee); | 231 _shimShadowDomStyling(templateContent, name, extendee); |
221 | 232 |
222 var cls = reflectClass(type); | 233 var cls = reflectClass(type); |
223 // TODO(jmesserly): this feels unnatrual in Dart. Since we have convenient | 234 // TODO(jmesserly): this feels unnatrual in Dart. Since we have convenient |
224 // lazy static initialization, can we get by without it? | 235 // lazy static initialization, can we get by without it? |
225 var registered = cls.declarations[#registerCallback]; | 236 var registered = cls.declarations[#registerCallback]; |
226 if (registered != null && | 237 if (registered != null && |
227 registered is MethodMirror && | 238 registered is MethodMirror && |
228 registered.isStatic && | 239 registered.isStatic && |
229 registered.isRegularMethod) { | 240 registered.isRegularMethod) { |
230 cls.invoke(#registerCallback, [this]); | 241 cls.invoke(#registerCallback, [this]); |
231 } | 242 } |
232 } | 243 } |
233 | 244 |
245 // TODO(sorvell): remove when spec addressed: | |
246 // https://www.w3.org/Bugs/Public/show_bug.cgi?id=22460 | |
247 // make <shadow></shadow> be <shadow><content></content></shadow> | |
248 void adjustShadowElement() { | |
249 // TODO(sorvell): avoid under SD polyfill until this bug is addressed: | |
250 // https://github.com/Polymer/ShadowDOM/issues/297 | |
251 if (!_hasShadowDomPolyfill) { | |
252 final content = templateContent; | |
253 if (content == null) return; | |
254 | |
255 for (var s in content.querySelectorAll('shadow')) { | |
256 if (s.nodes.isEmpty) s.append(new ContentElement()); | |
257 } | |
258 } | |
259 } | |
260 | |
234 void registerType(String name) { | 261 void registerType(String name) { |
235 var baseTag; | 262 var baseTag; |
236 var decl = this; | 263 var decl = this; |
237 while (decl != null) { | 264 while (decl != null) { |
238 baseTag = decl.attributes['extends']; | 265 baseTag = decl.attributes['extends']; |
239 decl = decl.superDeclaration; | 266 decl = decl.superDeclaration; |
240 } | 267 } |
241 document.register(name, type, extendsTag: baseTag); | 268 document.register(name, type, extendsTag: baseTag); |
242 } | 269 } |
243 | 270 |
244 void publishAttributes(ClassMirror cls, PolymerDeclaration superDecl) { | 271 void publishAttributes(ClassMirror cls, PolymerDeclaration superDecl) { |
245 // get properties to publish | 272 // get properties to publish |
246 if (superDecl != null && superDecl._publish != null) { | 273 if (superDecl != null && superDecl._publish != null) { |
247 // Dart note: even though we walk the type hierarchy in | 274 // Dart note: even though we walk the type hierarchy in |
248 // _getPublishedProperties, this will additionally include any names | 275 // _getPublishedProperties, this will additionally include any names |
249 // published via the `attributes` attribute. | 276 // published via the `attributes` attribute. |
250 _publish = new Map.from(superDecl._publish); | 277 _publish = new Map.from(superDecl._publish); |
251 } | 278 } |
252 | 279 |
253 _publish = _getPublishedProperties(cls, _publish); | 280 _publish = _getPublishedProperties(cls, _publish); |
254 | 281 |
255 // merge names from 'attributes' attribute | 282 // merge names from 'attributes' attribute |
256 var attrs = attributes['attributes']; | 283 var attrs = attributes['attributes']; |
257 if (attrs != null) { | 284 if (attrs != null) { |
258 // names='a b c' or names='a,b,c' | 285 // names='a b c' or names='a,b,c' |
259 // record each name for publishing | 286 // record each name for publishing |
260 for (var attr in attrs.split(attrs.contains(',') ? ',' : ' ')) { | 287 for (var attr in attrs.split(_ATTRIBUTES_REGEX)) { |
261 // remove excess ws | 288 // remove excess ws |
262 attr = attr.trim(); | 289 attr = attr.trim(); |
263 | 290 |
264 // do not override explicit entries | 291 // do not override explicit entries |
265 if (attr != '' && _publish != null && _publish.containsKey(attr)) { | 292 if (attr == '') continue; |
293 | |
294 var property = new Symbol(attr); | |
295 var path = new PropertyPath([property]); | |
296 if (_publish != null && _publish.containsKey(path)) { | |
266 continue; | 297 continue; |
267 } | 298 } |
268 | 299 |
269 var property = new Symbol(attr); | |
270 var mirror = _getProperty(cls, property); | 300 var mirror = _getProperty(cls, property); |
271 if (mirror == null) { | 301 if (mirror == null) { |
272 window.console.warn('property for attribute $attr of polymer-element ' | 302 window.console.warn('property for attribute $attr of polymer-element ' |
273 'name=$name not found.'); | 303 'name=$name not found.'); |
274 continue; | 304 continue; |
275 } | 305 } |
276 if (_publish == null) _publish = {}; | 306 if (_publish == null) _publish = {}; |
277 _publish[property] = mirror; | 307 _publish[path] = mirror; |
278 } | 308 } |
279 } | 309 } |
280 | 310 |
281 // NOTE: the following is not possible in Dart; fields must be declared. | 311 // NOTE: the following is not possible in Dart; fields must be declared. |
282 // install 'attributes' as properties on the prototype, | 312 // install 'attributes' as properties on the prototype, |
283 // but don't override | 313 // but don't override |
284 } | 314 } |
285 | 315 |
286 void accumulateInstanceAttributes() { | 316 void accumulateInstanceAttributes() { |
287 // inherit instance attributes | 317 // inherit instance attributes |
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
371 new StyleElement()..text = '$cssText', | 401 new StyleElement()..text = '$cssText', |
372 content.firstChild); | 402 content.firstChild); |
373 } | 403 } |
374 } | 404 } |
375 } | 405 } |
376 | 406 |
377 List<Element> findNodes(String selector, [bool matcher(Element e)]) { | 407 List<Element> findNodes(String selector, [bool matcher(Element e)]) { |
378 var nodes = this.querySelectorAll(selector).toList(); | 408 var nodes = this.querySelectorAll(selector).toList(); |
379 var content = templateContent; | 409 var content = templateContent; |
380 if (content != null) { | 410 if (content != null) { |
381 nodes = nodes..addAll(content.queryAll(selector)); | 411 nodes = nodes..addAll(content.querySelectorAll(selector)); |
382 } | 412 } |
383 if (matcher != null) return nodes.where(matcher).toList(); | 413 if (matcher != null) return nodes.where(matcher).toList(); |
384 return nodes; | 414 return nodes; |
385 } | 415 } |
386 | 416 |
387 /** | 417 /** |
388 * Promotes external stylesheets and style elements with the attribute | 418 * Promotes external stylesheets and style elements with the attribute |
389 * polymer-scope='global' into global scope. | 419 * polymer-scope='global' into global scope. |
390 * This is particularly useful for defining @keyframe rules which | 420 * This is particularly useful for defining @keyframe rules which |
391 * currently do not function in scoped or shadow style elements. | 421 * currently do not function in scoped or shadow style elements. |
392 * (See wkb.ug/72462) | 422 * (See wkb.ug/72462) |
393 */ | 423 */ |
394 // TODO(sorvell): remove when wkb.ug/72462 is addressed. | 424 // TODO(sorvell): remove when wkb.ug/72462 is addressed. |
395 void installGlobalStyles() { | 425 void installGlobalStyles() { |
396 var style = styleForScope(_STYLE_GLOBAL_SCOPE); | 426 var style = styleForScope(_STYLE_GLOBAL_SCOPE); |
397 Polymer.applyStyleToScope(style, document.head); | 427 Polymer.applyStyleToScope(style, document.head); |
398 } | 428 } |
399 | 429 |
400 String cssTextForScope(String scopeDescriptor) { | 430 String cssTextForScope(String scopeDescriptor) { |
401 var cssText = new StringBuffer(); | 431 var cssText = new StringBuffer(); |
402 // handle stylesheets | 432 // handle stylesheets |
403 var selector = '[$_SCOPE_ATTR=$scopeDescriptor]'; | 433 var selector = '[$_SCOPE_ATTR=$scopeDescriptor]'; |
404 matcher(s) => s.matches(selector); | 434 matcher(s) => s.matches(selector); |
405 | 435 |
406 for (var sheet in sheets.where(matcher)) { | 436 for (var sheet in sheets.where(matcher)) { |
407 cssText..write(_cssTextFromSheet(sheet))..write('\n\n'); | 437 cssText..write(_cssTextFromSheet(sheet))..write('\n\n'); |
408 } | 438 } |
409 // handle cached style elements | 439 // handle cached style elements |
410 for (var style in styles.where(matcher)) { | 440 for (var style in styles.where(matcher)) { |
411 cssText..write(style.textContent)..write('\n\n'); | 441 cssText..write(style.text)..write('\n\n'); |
Siggi Cherem (dart-lang)
2014/02/03 22:52:48
was this just broken before :/?
Jennifer Messerly
2014/02/04 00:33:06
apparently, yes :)
| |
412 } | 442 } |
413 return cssText.toString(); | 443 return cssText.toString(); |
414 } | 444 } |
415 | 445 |
416 StyleElement styleForScope(String scopeDescriptor) { | 446 StyleElement styleForScope(String scopeDescriptor) { |
417 var cssText = cssTextForScope(scopeDescriptor); | 447 var cssText = cssTextForScope(scopeDescriptor); |
418 return cssTextToScopeStyle(cssText, scopeDescriptor); | 448 return cssTextToScopeStyle(cssText, scopeDescriptor); |
419 } | 449 } |
420 | 450 |
421 StyleElement cssTextToScopeStyle(String cssText, String scopeDescriptor) { | 451 StyleElement cssTextToScopeStyle(String cssText, String scopeDescriptor) { |
422 if (cssText == '') return null; | 452 if (cssText == '') return null; |
423 | 453 |
424 return new StyleElement() | 454 return new StyleElement() |
425 ..text = cssText | 455 ..text = cssText |
426 ..attributes[_STYLE_SCOPE_ATTRIBUTE] = '$name-$scopeDescriptor'; | 456 ..attributes[_STYLE_SCOPE_ATTRIBUTE] = '$name-$scopeDescriptor'; |
427 } | 457 } |
428 | 458 |
429 /** | 459 /** |
430 * fetch a list of all observable properties names in our inheritance chain | 460 * fetch a list of all observable properties names in our inheritance chain |
431 * above Polymer. | 461 * above Polymer. |
432 */ | 462 */ |
433 // TODO(sjmiles): perf: reflection is slow, relatively speaking | |
434 // If an element may take 6us to create, getCustomPropertyNames might | |
435 // cost 1.6us more. | |
436 void inferObservers(ClassMirror cls) { | 463 void inferObservers(ClassMirror cls) { |
437 if (cls == _objectType) return; | 464 if (cls == _htmlElementType) return; |
438 inferObservers(cls.superclass); | 465 inferObservers(cls.superclass); |
439 for (var method in cls.declarations.values) { | 466 for (var method in cls.declarations.values) { |
440 if (method is! MethodMirror || method.isStatic | 467 if (method is! MethodMirror || method.isStatic |
441 || !method.isRegularMethod) continue; | 468 || !method.isRegularMethod) continue; |
442 | 469 |
443 String name = MirrorSystem.getName(method.simpleName); | 470 String name = MirrorSystem.getName(method.simpleName); |
444 if (name.endsWith(_OBSERVE_SUFFIX) && name != 'attributeChanged') { | 471 if (name.endsWith(_OBSERVE_SUFFIX) && name != 'attributeChanged') { |
445 if (_observe == null) _observe = new Map(); | 472 // TODO(jmesserly): now that we have a better system, should we |
473 // deprecate *Changed methods? | |
474 if (_observe == null) _observe = new HashMap(); | |
446 name = name.substring(0, name.length - 7); | 475 name = name.substring(0, name.length - 7); |
447 _observe[new Symbol(name)] = method.simpleName; | 476 _observe[new PropertyPath(name)] = method.simpleName; |
448 } | 477 } |
449 } | 478 } |
450 } | 479 } |
451 | 480 |
481 void explodeObservers(ClassMirror cls) { | |
Siggi Cherem (dart-lang)
2014/02/03 22:52:48
nit: consider adding a short doc here to point to
Jennifer Messerly
2014/02/04 00:33:06
sure. wish polymer-js would doc these :|
| |
482 if (cls == _htmlElementType) return; | |
483 | |
484 explodeObservers(cls.superclass); | |
485 for (var method in cls.declarations.values) { | |
486 if (method is! MethodMirror || method.isStatic | |
487 || !method.isRegularMethod) continue; | |
488 | |
489 for (var meta in _safeGetMetadata(method)) { | |
490 if (meta.reflectee is! ObserveProperty) continue; | |
491 | |
492 if (_observe == null) _observe = new HashMap(); | |
493 | |
494 for (String name in meta.reflectee.names) { | |
495 _observe[new PropertyPath(name)] = method.simpleName; | |
Siggi Cherem (dart-lang)
2014/02/03 22:52:48
what if 2 methods react on the same path?
@Observ
Jennifer Messerly
2014/02/04 00:33:06
good catch. JS doesn't support this. Added support
| |
496 } | |
497 } | |
498 } | |
499 } | |
452 void publishProperties(Type type) { | 500 void publishProperties(Type type) { |
Siggi Cherem (dart-lang)
2014/02/03 22:52:48
nit: + empty line above
Jennifer Messerly
2014/02/04 00:33:06
Done.
| |
453 // Dart note: _publish was already populated by publishAttributes | 501 // Dart note: _publish was already populated by publishAttributes |
454 if (_publish != null) _publishLC = _lowerCaseMap(_publish); | 502 if (_publish != null) _publishLC = _lowerCaseMap(_publish); |
455 } | 503 } |
456 | 504 |
457 Map<String, dynamic> _lowerCaseMap(Map<Symbol, dynamic> properties) { | 505 Map<String, dynamic> _lowerCaseMap(Map<PropertyPath, dynamic> properties) { |
458 final map = new Map<String, dynamic>(); | 506 final map = new Map<String, dynamic>(); |
459 properties.forEach((name, value) { | 507 properties.forEach((name, value) { |
460 map[MirrorSystem.getName(name).toLowerCase()] = value; | 508 map['$name'.toLowerCase()] = value; |
Siggi Cherem (dart-lang)
2014/02/03 22:52:48
'$name' -> name ? or is this to protect from key b
Jennifer Messerly
2014/02/04 00:33:06
name is a PropertyPath, not a String. Clarified.
| |
461 }); | 509 }); |
462 return map; | 510 return map; |
463 } | 511 } |
464 } | 512 } |
465 | 513 |
466 /// maps tag names to prototypes | 514 /// maps tag names to prototypes |
467 final Map _typesByName = new Map<String, Type>(); | 515 final Map _typesByName = new Map<String, Type>(); |
468 | 516 |
469 Type _getRegisteredType(String name) => _typesByName[name]; | 517 Type _getRegisteredType(String name) => _typesByName[name]; |
470 | 518 |
(...skipping 17 matching lines...) Expand all Loading... | |
488 } | 536 } |
489 } | 537 } |
490 | 538 |
491 /// track document.register'ed tag names and their declarations | 539 /// track document.register'ed tag names and their declarations |
492 final Map _declarations = new Map<String, PolymerDeclaration>(); | 540 final Map _declarations = new Map<String, PolymerDeclaration>(); |
493 | 541 |
494 bool _isRegistered(String name) => _declarations.containsKey(name); | 542 bool _isRegistered(String name) => _declarations.containsKey(name); |
495 PolymerDeclaration _getDeclaration(String name) => _declarations[name]; | 543 PolymerDeclaration _getDeclaration(String name) => _declarations[name]; |
496 | 544 |
497 final _objectType = reflectClass(Object); | 545 final _objectType = reflectClass(Object); |
498 | 546 final _htmlElementType = reflectClass(HtmlElement); |
499 | 547 |
500 Map _getPublishedProperties(ClassMirror cls, Map props) { | 548 Map _getPublishedProperties(ClassMirror cls, Map props) { |
501 if (cls == _objectType) return props; | 549 if (cls == _htmlElementType) return props; |
502 props = _getPublishedProperties(cls.superclass, props); | 550 props = _getPublishedProperties(cls.superclass, props); |
503 for (var member in cls.declarations.values) { | 551 for (var member in cls.declarations.values) { |
504 if (member.isStatic || member.isPrivate) continue; | 552 if (member.isStatic || member.isPrivate) continue; |
505 | 553 |
506 if (member is VariableMirror && !member.isFinal | 554 if (member is VariableMirror && !member.isFinal |
507 || member is MethodMirror && member.isGetter) { | 555 || member is MethodMirror && member.isGetter) { |
508 | 556 |
509 for (var meta in member.metadata) { | 557 for (var meta in member.metadata) { |
510 if (meta.reflectee is PublishedProperty) { | 558 if (meta.reflectee is PublishedProperty) { |
511 // Note: we delay the setter check until we find @published because | 559 // Note: we delay the setter check until we find @published because |
512 // it's a tad expensive. | 560 // it's a tad expensive. |
513 if (member is! MethodMirror || _hasSetter(cls, member)) { | 561 if (member is! MethodMirror || _hasSetter(cls, member)) { |
514 if (props == null) props = {}; | 562 if (props == null) props = {}; |
515 props[member.simpleName] = member; | 563 props[new PropertyPath([member.simpleName])] = member; |
516 } | 564 } |
517 break; | 565 break; |
518 } | 566 } |
519 } | 567 } |
520 } | 568 } |
521 } | 569 } |
522 | 570 |
523 return props; | 571 return props; |
524 } | 572 } |
525 | 573 |
(...skipping 12 matching lines...) Expand all Loading... | |
538 // bug introduced between Chrome 31 and 32. After 32 | 586 // bug introduced between Chrome 31 and 32. After 32 |
539 // JsClassMirror.declarations on Object calls | 587 // JsClassMirror.declarations on Object calls |
540 // JsClassMirror.typeVariables, which tries to get the _jsConstructor's | 588 // JsClassMirror.typeVariables, which tries to get the _jsConstructor's |
541 // .prototype["<>"]. This ends up getting the "" property instead, maybe | 589 // .prototype["<>"]. This ends up getting the "" property instead, maybe |
542 // because "<>" doesn't exist, and gets ";" which then blows up because | 590 // because "<>" doesn't exist, and gets ";" which then blows up because |
543 // the code later on expects a List of ints. | 591 // the code later on expects a List of ints. |
544 } while (cls != _objectType); | 592 } while (cls != _objectType); |
545 return null; | 593 return null; |
546 } | 594 } |
547 | 595 |
596 List _safeGetMetadata(MethodMirror method) { | |
597 // TODO(jmesserly): dart2js blows up getting metadata from methods in some | |
598 // cases. Why does this happen? It seems like the culprit might be named | |
599 // arguments. Unfortunately even calling method.parameters also | |
600 // triggers the bug in computeFunctionRti. For now we guard against it | |
601 // with this check. | |
602 try { | |
603 return method.metadata; | |
604 } catch (e) { | |
605 return []; | |
606 } | |
607 } | |
608 | |
548 bool _hasSetter(ClassMirror cls, MethodMirror getter) { | 609 bool _hasSetter(ClassMirror cls, MethodMirror getter) { |
549 var setterName = new Symbol('${MirrorSystem.getName(getter.simpleName)}='); | 610 var setterName = new Symbol('${MirrorSystem.getName(getter.simpleName)}='); |
550 var mirror = cls.declarations[setterName]; | 611 var mirror = cls.declarations[setterName]; |
551 return mirror is MethodMirror && mirror.isSetter; | 612 return mirror is MethodMirror && mirror.isSetter; |
552 } | 613 } |
553 | 614 |
554 | 615 |
555 /** Attribute prefix used for declarative event handlers. */ | 616 /** Attribute prefix used for declarative event handlers. */ |
556 const _EVENT_PREFIX = 'on-'; | 617 const _EVENT_PREFIX = 'on-'; |
557 | 618 |
558 /** Whether an attribute declares an event. */ | 619 /** Whether an attribute declares an event. */ |
559 bool _hasEventPrefix(String attr) => attr.startsWith(_EVENT_PREFIX); | 620 bool _hasEventPrefix(String attr) => attr.startsWith(_EVENT_PREFIX); |
560 | 621 |
561 String _removeEventPrefix(String name) => name.substring(_EVENT_PREFIX.length); | 622 String _removeEventPrefix(String name) => name.substring(_EVENT_PREFIX.length); |
562 | 623 |
563 /** | 624 /** |
564 * Using Polymer's platform/src/ShadowCSS.js passing the style tag's content. | 625 * Using Polymer's platform/src/ShadowCSS.js passing the style tag's content. |
565 */ | 626 */ |
566 void _shimShadowDomStyling(DocumentFragment template, String name, | 627 void _shimShadowDomStyling(DocumentFragment template, String name, |
567 String extendee) { | 628 String extendee) { |
568 if (js.context == null || template == null) return; | 629 if (template == null || !_hasShadowDomPolyfill) return; |
569 if (!js.context.hasProperty('ShadowDOMPolyfill')) return; | |
570 | 630 |
571 var platform = js.context['Platform']; | 631 var platform = js.context['Platform']; |
572 if (platform == null) return; | 632 if (platform == null) return; |
573 var shadowCss = platform['ShadowCSS']; | 633 var shadowCss = platform['ShadowCSS']; |
574 if (shadowCss == null) return; | 634 if (shadowCss == null) return; |
575 shadowCss.callMethod('shimStyling', [template, name, extendee]); | 635 shadowCss.callMethod('shimStyling', [template, name, extendee]); |
576 } | 636 } |
577 | 637 |
638 final bool _hasShadowDomPolyfill = js.context != null && | |
639 js.context.hasProperty('ShadowDOMPolyfill'); | |
640 | |
578 const _STYLE_SELECTOR = 'style'; | 641 const _STYLE_SELECTOR = 'style'; |
579 const _SHEET_SELECTOR = '[rel=stylesheet]'; | 642 const _SHEET_SELECTOR = '[rel=stylesheet]'; |
580 const _STYLE_GLOBAL_SCOPE = 'global'; | 643 const _STYLE_GLOBAL_SCOPE = 'global'; |
581 const _SCOPE_ATTR = 'polymer-scope'; | 644 const _SCOPE_ATTR = 'polymer-scope'; |
582 const _STYLE_SCOPE_ATTRIBUTE = 'element'; | 645 const _STYLE_SCOPE_ATTRIBUTE = 'element'; |
583 const _STYLE_CONTROLLER_SCOPE = 'controller'; | 646 const _STYLE_CONTROLLER_SCOPE = 'controller'; |
584 | 647 |
585 String _cssTextFromSheet(LinkElement sheet) { | 648 String _cssTextFromSheet(LinkElement sheet) { |
586 if (sheet == null) return ''; | 649 if (sheet == null) return ''; |
587 | 650 |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
620 // TODO(jmesserly): is this list complete? | 683 // TODO(jmesserly): is this list complete? |
621 final _eventTranslations = const { | 684 final _eventTranslations = const { |
622 // TODO(jmesserly): these three Polymer.js translations won't work in Dart, | 685 // TODO(jmesserly): these three Polymer.js translations won't work in Dart, |
623 // because we strip the webkit prefix (below). Reconcile. | 686 // because we strip the webkit prefix (below). Reconcile. |
624 'webkitanimationstart': 'webkitAnimationStart', | 687 'webkitanimationstart': 'webkitAnimationStart', |
625 'webkitanimationend': 'webkitAnimationEnd', | 688 'webkitanimationend': 'webkitAnimationEnd', |
626 'webkittransitionend': 'webkitTransitionEnd', | 689 'webkittransitionend': 'webkitTransitionEnd', |
627 | 690 |
628 'domfocusout': 'DOMFocusOut', | 691 'domfocusout': 'DOMFocusOut', |
629 'domfocusin': 'DOMFocusIn', | 692 'domfocusin': 'DOMFocusIn', |
693 'dommousescroll': 'DOMMouseScroll', | |
630 | 694 |
631 // TODO(jmesserly): Dart specific renames. Reconcile with Polymer.js | 695 // TODO(jmesserly): Dart specific renames. Reconcile with Polymer.js |
632 'animationend': 'webkitAnimationEnd', | 696 'animationend': 'webkitAnimationEnd', |
633 'animationiteration': 'webkitAnimationIteration', | 697 'animationiteration': 'webkitAnimationIteration', |
634 'animationstart': 'webkitAnimationStart', | 698 'animationstart': 'webkitAnimationStart', |
635 'doubleclick': 'dblclick', | 699 'doubleclick': 'dblclick', |
636 'fullscreenchange': 'webkitfullscreenchange', | 700 'fullscreenchange': 'webkitfullscreenchange', |
637 'fullscreenerror': 'webkitfullscreenerror', | 701 'fullscreenerror': 'webkitfullscreenerror', |
638 'keyadded': 'webkitkeyadded', | 702 'keyadded': 'webkitkeyadded', |
639 'keyerror': 'webkitkeyerror', | 703 'keyerror': 'webkitkeyerror', |
(...skipping 10 matching lines...) Expand all Loading... | |
650 return map; | 714 return map; |
651 }(); | 715 }(); |
652 | 716 |
653 // Dart note: we need this function because we have additional renames JS does | 717 // Dart note: we need this function because we have additional renames JS does |
654 // not have. The JS renames are simply case differences, whereas we have ones | 718 // not have. The JS renames are simply case differences, whereas we have ones |
655 // like doubleclick -> dblclick and stripping the webkit prefix. | 719 // like doubleclick -> dblclick and stripping the webkit prefix. |
656 String _eventNameFromType(String eventType) { | 720 String _eventNameFromType(String eventType) { |
657 final result = _reverseEventTranslations[eventType]; | 721 final result = _reverseEventTranslations[eventType]; |
658 return result != null ? result : eventType; | 722 return result != null ? result : eventType; |
659 } | 723 } |
724 | |
725 final _ATTRIBUTES_REGEX = new RegExp(r'\s|,'); | |
OLD | NEW |