Chromium Code Reviews| 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 |