| 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 /// *Warning* this class is experimental and subject to change. | 7 /// *Warning* this class is experimental and subject to change. |
| 8 /// | 8 /// |
| 9 /// The data associated with a polymer-element declaration, if it is backed | 9 /// The data associated with a polymer-element declaration, if it is backed |
| 10 /// by a Dart class instead of a JavaScript prototype. | 10 /// by a Dart class instead of a JavaScript prototype. |
| 11 class PolymerDeclaration { | 11 class PolymerDeclaration { |
| 12 /// The one syntax to rule them all. |
| 13 static final BindingDelegate _polymerSyntax = new PolymerExpressions(); |
| 14 |
| 12 /// The polymer-element for this declaration. | 15 /// The polymer-element for this declaration. |
| 13 final HtmlElement element; | 16 final HtmlElement element; |
| 14 | 17 |
| 15 /// The Dart type corresponding to this custom element declaration. | 18 /// The Dart type corresponding to this custom element declaration. |
| 16 final Type type; | 19 final Type type; |
| 17 | 20 |
| 18 /// If we extend another custom element, this points to the super declaration. | 21 /// If we extend another custom element, this points to the super declaration. |
| 19 final PolymerDeclaration superDeclaration; | 22 final PolymerDeclaration superDeclaration; |
| 20 | 23 |
| 21 /// The name of the custom element. | 24 /// The name of the custom element. |
| (...skipping 11 matching lines...) Expand all Loading... |
| 33 Iterable<String> get publishedProperties => | 36 Iterable<String> get publishedProperties => |
| 34 _publish != null ? _publish.keys.map((p) => '$p') : const []; | 37 _publish != null ? _publish.keys.map((p) => '$p') : const []; |
| 35 | 38 |
| 36 /// Same as [_publish] but with lower case names. | 39 /// Same as [_publish] but with lower case names. |
| 37 Map<String, smoke.Declaration> _publishLC; | 40 Map<String, smoke.Declaration> _publishLC; |
| 38 | 41 |
| 39 Map<PropertyPath, List<Symbol>> _observe; | 42 Map<PropertyPath, List<Symbol>> _observe; |
| 40 | 43 |
| 41 Map<String, Object> _instanceAttributes; | 44 Map<String, Object> _instanceAttributes; |
| 42 | 45 |
| 46 /// A set of properties that should be automatically reflected to attributes. |
| 47 /// Typically this is used for CSS styling. If none, this variable will be |
| 48 /// left as null. |
| 49 Set<String> _reflect; |
| 50 |
| 43 List<Element> _sheets; | 51 List<Element> _sheets; |
| 44 List<Element> get sheets => _sheets; | 52 List<Element> get sheets => _sheets; |
| 45 | 53 |
| 46 List<Element> _styles; | 54 List<Element> _styles; |
| 47 List<Element> get styles => _styles; | 55 List<Element> get styles => _styles; |
| 48 | 56 |
| 57 // The default syntax for polymer-elements. |
| 58 PolymerExpressions syntax = _polymerSyntax; |
| 59 |
| 49 DocumentFragment get templateContent { | 60 DocumentFragment get templateContent { |
| 50 final template = element.querySelector('template'); | 61 final template = fetchTemplate(); |
| 51 return template != null ? templateBind(template).content : null; | 62 return template != null ? templateBind(template).content : null; |
| 52 } | 63 } |
| 53 | 64 |
| 54 /// Maps event names and their associated method in the element class. | 65 /// Maps event names and their associated method in the element class. |
| 55 final Map<String, String> _eventDelegates = {}; | 66 final Map<String, String> _eventDelegates = {}; |
| 56 | 67 |
| 57 /// Expected events per element node. | 68 /// Expected events per element node. |
| 58 // TODO(sigmund): investigate whether we need more than 1 set of local events | 69 // TODO(sigmund): investigate whether we need more than 1 set of local events |
| 59 // per element (why does the js implementation stores 1 per template node?) | 70 // per element (why does the js implementation stores 1 per template node?) |
| 60 Expando<Set<String>> _templateDelegates; | 71 Expando<Set<String>> _templateDelegates; |
| 61 | 72 |
| 62 String get extendee => superDeclaration != null ? | 73 String get extendee => superDeclaration != null ? |
| 63 superDeclaration.name : null; | 74 superDeclaration.name : null; |
| 64 | 75 |
| 76 /// The root URI for assets. |
| 77 Uri _rootUri; |
| 78 |
| 65 // Dart note: since polymer-element is handled in JS now, we have a simplified | 79 // Dart note: since polymer-element is handled in JS now, we have a simplified |
| 66 // flow for registering. We don't need to wait for the supertype or the code | 80 // flow for registering. We don't need to wait for the supertype or the code |
| 67 // to be noticed. | 81 // to be noticed. |
| 68 PolymerDeclaration(this.element, this.name, this.type, this.superDeclaration); | 82 PolymerDeclaration(this.element, this.name, this.type, this.superDeclaration); |
| 69 | 83 |
| 70 void register() { | 84 void register() { |
| 71 // build prototype combining extendee, Polymer base, and named api | |
| 72 buildType(); | |
| 73 | |
| 74 // back reference declaration element | |
| 75 // TODO(sjmiles): replace `element` with `elementElement` or `declaration` | |
| 76 _declarations[name] = this; | |
| 77 | |
| 78 // more declarative features | 85 // more declarative features |
| 79 desugar(); | 86 desugar(); |
| 80 // register our custom element | 87 // register our custom element |
| 81 registerType(name); | 88 registerType(name); |
| 82 | 89 |
| 83 // NOTE: skip in Dart because we don't have mutable global scope. | 90 // NOTE: skip in Dart because we don't have mutable global scope. |
| 84 // reference constructor in a global named by 'constructor' attribute | 91 // reference constructor in a global named by 'constructor' attribute |
| 85 // publishConstructor(); | 92 // publishConstructor(); |
| 86 } | 93 } |
| 87 | 94 |
| 88 /// Gets the Dart type registered for this name, and sets up declarative | 95 /// Implement various declarative features. |
| 89 /// features. Fills in the [type] and [supertype] fields. | 96 // Dart note: this merges "buildPrototype" "desugarBeforeChaining" and |
| 90 /// | 97 // "desugarAfterChaining", because we don't have prototypes. |
| 91 /// *Note*: unlike the JavaScript version, we do not have to metaprogram the | 98 void desugar() { |
| 92 /// prototype, which simplifies this method. | 99 |
| 93 void buildType() { | 100 // back reference declaration element |
| 101 _declarations[name] = this; |
| 102 |
| 94 // transcribe `attributes` declarations onto own prototype's `publish` | 103 // transcribe `attributes` declarations onto own prototype's `publish` |
| 95 publishAttributes(superDeclaration); | 104 publishAttributes(superDeclaration); |
| 96 | 105 |
| 97 publishProperties(); | 106 publishProperties(); |
| 98 | 107 |
| 99 inferObservers(); | 108 inferObservers(); |
| 100 | 109 |
| 101 // desugar compound observer syntax, e.g. @ObserveProperty('a b c') | 110 // desugar compound observer syntax, e.g. @ObserveProperty('a b c') |
| 102 explodeObservers(); | 111 explodeObservers(); |
| 103 | 112 |
| 104 // Skip the rest in Dart: | 113 // install mdv delegate on template |
| 105 // chain various meta-data objects to inherited versions | 114 installBindingDelegate(fetchTemplate()); |
| 106 // chain custom api to inherited | 115 // install external stylesheets as if they are inline |
| 107 // build side-chained lists to optimize iterations | 116 installSheets(); |
| 108 // inherit publishing meta-data | 117 // adjust any paths in dom from imports |
| 109 // x-platform fixup | 118 resolveElementPaths(element); |
| 110 } | |
| 111 | |
| 112 /// Implement various declarative features. | |
| 113 void desugar() { | |
| 114 // compile list of attributes to copy to instances | 119 // compile list of attributes to copy to instances |
| 115 accumulateInstanceAttributes(); | 120 accumulateInstanceAttributes(); |
| 116 // parse on-* delegates declared on `this` element | 121 // parse on-* delegates declared on `this` element |
| 117 parseHostEvents(); | 122 parseHostEvents(); |
| 118 // install external stylesheets as if they are inline | 123 // install a helper method this.resolvePath to aid in |
| 119 installSheets(); | 124 // setting resource urls. e.g. |
| 120 | |
| 121 adjustShadowElement(); | |
| 122 | |
| 123 // TODO(sorvell): install a helper method this.resolvePath to aid in | |
| 124 // setting resource paths. e.g. | |
| 125 // this.$.image.src = this.resolvePath('images/foo.png') | 125 // this.$.image.src = this.resolvePath('images/foo.png') |
| 126 // Potentially remove when spec bug is addressed. | 126 initResolvePath(); |
| 127 // https://www.w3.org/Bugs/Public/show_bug.cgi?id=21407 | |
| 128 // TODO(jmesserly): resolvePath not ported, see first comment in this class. | |
| 129 | |
| 130 // under ShadowDOMPolyfill, transforms to approximate missing CSS features | 127 // under ShadowDOMPolyfill, transforms to approximate missing CSS features |
| 131 _shimShadowDomStyling(templateContent, name, extendee); | 128 _shimShadowDomStyling(templateContent, name, extendee); |
| 132 | 129 |
| 133 // TODO(jmesserly): this feels unnatrual in Dart. Since we have convenient | 130 // TODO(jmesserly): this feels unnatrual in Dart. Since we have convenient |
| 134 // lazy static initialization, can we get by without it? | 131 // lazy static initialization, can we get by without it? |
| 135 if (smoke.hasStaticMethod(type, #registerCallback)) { | 132 if (smoke.hasStaticMethod(type, #registerCallback)) { |
| 136 smoke.invoke(type, #registerCallback, [this]); | 133 smoke.invoke(type, #registerCallback, [this]); |
| 137 } | 134 } |
| 138 } | 135 } |
| 139 | 136 |
| 140 // TODO(sorvell): remove when spec addressed: | |
| 141 // https://www.w3.org/Bugs/Public/show_bug.cgi?id=22460 | |
| 142 // make <shadow></shadow> be <shadow><content></content></shadow> | |
| 143 void adjustShadowElement() { | |
| 144 // TODO(sorvell): avoid under SD polyfill until this bug is addressed: | |
| 145 // https://github.com/Polymer/ShadowDOM/issues/297 | |
| 146 if (!_hasShadowDomPolyfill) { | |
| 147 final content = templateContent; | |
| 148 if (content == null) return; | |
| 149 | |
| 150 for (var s in content.querySelectorAll('shadow')) { | |
| 151 if (s.nodes.isEmpty) s.append(new ContentElement()); | |
| 152 } | |
| 153 } | |
| 154 } | |
| 155 | |
| 156 void registerType(String name) { | 137 void registerType(String name) { |
| 157 var baseTag; | 138 var baseTag; |
| 158 var decl = this; | 139 var decl = this; |
| 159 while (decl != null) { | 140 while (decl != null) { |
| 160 baseTag = decl.element.attributes['extends']; | 141 baseTag = decl.element.attributes['extends']; |
| 161 decl = decl.superDeclaration; | 142 decl = decl.superDeclaration; |
| 162 } | 143 } |
| 163 document.register(name, type, extendsTag: baseTag); | 144 document.registerElement(name, type, extendsTag: baseTag); |
| 145 } |
| 146 |
| 147 // from declaration/mdv.js |
| 148 Element fetchTemplate() => element.querySelector('template'); |
| 149 |
| 150 void installBindingDelegate(Element template) { |
| 151 if (template != null) { |
| 152 templateBind(template).bindingDelegate = this.syntax; |
| 153 } |
| 154 } |
| 155 |
| 156 // from declaration/path.js |
| 157 void resolveElementPaths(Node node) { |
| 158 if (_Platform == null) return; |
| 159 _Platform['urlResolver'].callMethod('resolveDom', [node]); |
| 160 } |
| 161 |
| 162 // Dart note: renamed from "addResolvePathApi". |
| 163 void initResolvePath() { |
| 164 // let assetpath attribute modify the resolve path |
| 165 var assetPath = element.attributes['assetpath']; |
| 166 if (assetPath == null) assetPath = ''; |
| 167 var base = Uri.parse(element.ownerDocument.baseUri); |
| 168 _rootUri = base.resolve(assetPath); |
| 169 } |
| 170 |
| 171 String resolvePath(String urlPath, [baseUrlOrString]) { |
| 172 Uri base; |
| 173 if (baseUrlOrString == null) { |
| 174 // Dart note: this enforces the same invariant as JS, where you need to |
| 175 // call addResolvePathApi first. |
| 176 if (_rootUri == null) { |
| 177 throw new StateError('call initResolvePath before calling resolvePath'); |
| 178 } |
| 179 base = _rootUri; |
| 180 } else if (baseUrlOrString is Uri) { |
| 181 base = baseUrlOrString; |
| 182 } else { |
| 183 base = Uri.parse(baseUrlOrString); |
| 184 } |
| 185 return base.resolve(urlPath).toString(); |
| 164 } | 186 } |
| 165 | 187 |
| 166 void publishAttributes(PolymerDeclaration superDecl) { | 188 void publishAttributes(PolymerDeclaration superDecl) { |
| 167 // get properties to publish | 189 // get properties to publish |
| 168 if (superDecl != null && superDecl._publish != null) { | 190 if (superDecl != null) { |
| 169 // Dart note: even though we walk the type hierarchy in | 191 // Dart note: even though we walk the type hierarchy in |
| 170 // _getPublishedProperties, this will additionally include any names | 192 // _getPublishedProperties, this will additionally include any names |
| 171 // published via the `attributes` attribute. | 193 // published via the `attributes` attribute. |
| 172 _publish = new Map.from(superDecl._publish); | 194 if (superDecl._publish != null) { |
| 195 _publish = new Map.from(superDecl._publish); |
| 196 } |
| 197 if (superDecl._reflect != null) { |
| 198 _reflect = new Set.from(superDecl._reflect); |
| 199 } |
| 173 } | 200 } |
| 174 | 201 |
| 175 _publish = _getPublishedProperties(type, _publish); | 202 _getPublishedProperties(type); |
| 176 | 203 |
| 177 // merge names from 'attributes' attribute | 204 // merge names from 'attributes' attribute |
| 178 var attrs = element.attributes['attributes']; | 205 var attrs = element.attributes['attributes']; |
| 179 if (attrs != null) { | 206 if (attrs != null) { |
| 180 // names='a b c' or names='a,b,c' | 207 // names='a b c' or names='a,b,c' |
| 181 // record each name for publishing | 208 // record each name for publishing |
| 182 for (var attr in attrs.split(_ATTRIBUTES_REGEX)) { | 209 for (var attr in attrs.split(_ATTRIBUTES_REGEX)) { |
| 183 // remove excess ws | 210 // remove excess ws |
| 184 attr = attr.trim(); | 211 attr = attr.trim(); |
| 185 | 212 |
| (...skipping 15 matching lines...) Expand all Loading... |
| 201 if (_publish == null) _publish = {}; | 228 if (_publish == null) _publish = {}; |
| 202 _publish[path] = decl; | 229 _publish[path] = decl; |
| 203 } | 230 } |
| 204 } | 231 } |
| 205 | 232 |
| 206 // NOTE: the following is not possible in Dart; fields must be declared. | 233 // NOTE: the following is not possible in Dart; fields must be declared. |
| 207 // install 'attributes' as properties on the prototype, | 234 // install 'attributes' as properties on the prototype, |
| 208 // but don't override | 235 // but don't override |
| 209 } | 236 } |
| 210 | 237 |
| 238 void _getPublishedProperties(Type type) { |
| 239 var options = const smoke.QueryOptions(includeInherited: true, |
| 240 includeUpTo: HtmlElement, withAnnotations: const [PublishedProperty]); |
| 241 for (var decl in smoke.query(type, options)) { |
| 242 if (decl.isFinal) continue; |
| 243 if (_publish == null) _publish = {}; |
| 244 _publish[new PropertyPath([decl.name])] = decl; |
| 245 |
| 246 // Should we reflect the property value to the attribute automatically? |
| 247 if (decl.annotations |
| 248 .where((a) => a is PublishedProperty) |
| 249 .any((a) => a.reflect)) { |
| 250 |
| 251 if (_reflect == null) _reflect = new Set(); |
| 252 _reflect.add(smoke.symbolToName(decl.name)); |
| 253 } |
| 254 } |
| 255 } |
| 256 |
| 257 |
| 211 void accumulateInstanceAttributes() { | 258 void accumulateInstanceAttributes() { |
| 212 // inherit instance attributes | 259 // inherit instance attributes |
| 213 _instanceAttributes = new Map<String, Object>(); | 260 _instanceAttributes = new Map<String, Object>(); |
| 214 if (superDeclaration != null) { | 261 if (superDeclaration != null) { |
| 215 _instanceAttributes.addAll(superDeclaration._instanceAttributes); | 262 _instanceAttributes.addAll(superDeclaration._instanceAttributes); |
| 216 } | 263 } |
| 217 | 264 |
| 218 // merge attributes from element | 265 // merge attributes from element |
| 219 element.attributes.forEach((name, value) { | 266 element.attributes.forEach((name, value) { |
| 220 if (isInstanceAttribute(name)) { | 267 if (isInstanceAttribute(name)) { |
| 221 _instanceAttributes[name] = value; | 268 _instanceAttributes[name] = value; |
| 222 } | 269 } |
| 223 }); | 270 }); |
| 224 } | 271 } |
| 225 | 272 |
| 226 static bool isInstanceAttribute(name) { | 273 static bool isInstanceAttribute(name) { |
| 227 // do not clone these attributes onto instances | 274 // do not clone these attributes onto instances |
| 228 final blackList = const { | 275 final blackList = const { |
| 229 'name': 1, 'extends': 1, 'constructor': 1, 'noscript': 1, | 276 'name': 1, |
| 230 'attributes': 1}; | 277 'extends': 1, |
| 278 'constructor': 1, |
| 279 'noscript': 1, |
| 280 'assetpath': 1, |
| 281 'cache-csstext': 1, |
| 282 // add ATTRIBUTES_ATTRIBUTE to the blacklist |
| 283 'attributes': 1, |
| 284 }; |
| 231 | 285 |
| 232 return !blackList.containsKey(name) && !name.startsWith('on-'); | 286 return !blackList.containsKey(name) && !name.startsWith('on-'); |
| 233 } | 287 } |
| 234 | 288 |
| 235 /// Extracts events from the element tag attributes. | 289 /// Extracts events from the element tag attributes. |
| 236 void parseHostEvents() { | 290 void parseHostEvents() { |
| 237 addAttributeDelegates(_eventDelegates); | 291 addAttributeDelegates(_eventDelegates); |
| 238 } | 292 } |
| 239 | 293 |
| 240 void addAttributeDelegates(Map<String, String> delegates) { | 294 void addAttributeDelegates(Map<String, String> delegates) { |
| 241 element.attributes.forEach((name, value) { | 295 element.attributes.forEach((name, value) { |
| 242 if (_hasEventPrefix(name)) { | 296 if (_hasEventPrefix(name)) { |
| 243 var start = value.indexOf('{{'); | 297 var start = value.indexOf('{{'); |
| 244 var end = value.lastIndexOf('}}'); | 298 var end = value.lastIndexOf('}}'); |
| 245 if (start >= 0 && end >= 0) { | 299 if (start >= 0 && end >= 0) { |
| 246 delegates[_removeEventPrefix(name)] = | 300 delegates[_removeEventPrefix(name)] = |
| 247 value.substring(start + 2, end).trim(); | 301 value.substring(start + 2, end).trim(); |
| 248 } | 302 } |
| 249 } | 303 } |
| 250 }); | 304 }); |
| 251 } | 305 } |
| 252 | 306 |
| 253 String urlToPath(String url) { | 307 String urlToPath(String url) { |
| 254 if (url == null) return ''; | 308 if (url == null) return ''; |
| 255 return (url.split('/')..removeLast()..add('')).join('/'); | 309 return (url.split('/')..removeLast()..add('')).join('/'); |
| 256 } | 310 } |
| 257 | 311 |
| 312 // Dart note: loadStyles, convertSheetsToStyles, copySheetAttribute and |
| 313 // findLoadableStyles are not ported because they're handled by Polymer JS |
| 314 // before we get into [register]. |
| 315 |
| 258 /// Install external stylesheets loaded in <element> elements into the | 316 /// Install external stylesheets loaded in <element> elements into the |
| 259 /// element's template. | 317 /// element's template. |
| 260 void installSheets() { | 318 void installSheets() { |
| 261 cacheSheets(); | 319 cacheSheets(); |
| 262 cacheStyles(); | 320 cacheStyles(); |
| 263 installLocalSheets(); | 321 installLocalSheets(); |
| 264 installGlobalStyles(); | 322 installGlobalStyles(); |
| 265 } | 323 } |
| 266 | 324 |
| 267 void cacheSheets() { | 325 void cacheSheets() { |
| (...skipping 15 matching lines...) Expand all Loading... |
| 283 void installLocalSheets() { | 341 void installLocalSheets() { |
| 284 var sheets = this.sheets.where( | 342 var sheets = this.sheets.where( |
| 285 (s) => !s.attributes.containsKey(_SCOPE_ATTR)); | 343 (s) => !s.attributes.containsKey(_SCOPE_ATTR)); |
| 286 var content = templateContent; | 344 var content = templateContent; |
| 287 if (content != null) { | 345 if (content != null) { |
| 288 var cssText = new StringBuffer(); | 346 var cssText = new StringBuffer(); |
| 289 for (var sheet in sheets) { | 347 for (var sheet in sheets) { |
| 290 cssText..write(_cssTextFromSheet(sheet))..write('\n'); | 348 cssText..write(_cssTextFromSheet(sheet))..write('\n'); |
| 291 } | 349 } |
| 292 if (cssText.length > 0) { | 350 if (cssText.length > 0) { |
| 293 content.insertBefore( | 351 var style = element.ownerDocument.createElement('style') |
| 294 new StyleElement()..text = '$cssText', | 352 ..text = '$cssText'; |
| 295 content.firstChild); | 353 |
| 354 content.insertBefore(style, content.firstChild); |
| 296 } | 355 } |
| 297 } | 356 } |
| 298 } | 357 } |
| 299 | 358 |
| 300 List<Element> findNodes(String selector, [bool matcher(Element e)]) { | 359 List<Element> findNodes(String selector, [bool matcher(Element e)]) { |
| 301 var nodes = element.querySelectorAll(selector).toList(); | 360 var nodes = element.querySelectorAll(selector).toList(); |
| 302 var content = templateContent; | 361 var content = templateContent; |
| 303 if (content != null) { | 362 if (content != null) { |
| 304 nodes = nodes..addAll(content.querySelectorAll(selector)); | 363 nodes = nodes..addAll(content.querySelectorAll(selector)); |
| 305 } | 364 } |
| (...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 395 final Map _typesByName = new Map<String, Type>(); | 454 final Map _typesByName = new Map<String, Type>(); |
| 396 | 455 |
| 397 Type _getRegisteredType(String name) => _typesByName[name]; | 456 Type _getRegisteredType(String name) => _typesByName[name]; |
| 398 | 457 |
| 399 /// track document.register'ed tag names and their declarations | 458 /// track document.register'ed tag names and their declarations |
| 400 final Map _declarations = new Map<String, PolymerDeclaration>(); | 459 final Map _declarations = new Map<String, PolymerDeclaration>(); |
| 401 | 460 |
| 402 bool _isRegistered(String name) => _declarations.containsKey(name); | 461 bool _isRegistered(String name) => _declarations.containsKey(name); |
| 403 PolymerDeclaration _getDeclaration(String name) => _declarations[name]; | 462 PolymerDeclaration _getDeclaration(String name) => _declarations[name]; |
| 404 | 463 |
| 405 Map<PropertyPath, smoke.Declaration> _getPublishedProperties( | |
| 406 Type type, Map<PropertyPath, smoke.Declaration> props) { | |
| 407 var options = const smoke.QueryOptions(includeInherited: true, | |
| 408 includeUpTo: HtmlElement, withAnnotations: const [PublishedProperty]); | |
| 409 for (var decl in smoke.query(type, options)) { | |
| 410 if (decl.isFinal) continue; | |
| 411 if (props == null) props = {}; | |
| 412 props[new PropertyPath([decl.name])] = decl; | |
| 413 } | |
| 414 return props; | |
| 415 } | |
| 416 | |
| 417 /// Attribute prefix used for declarative event handlers. | |
| 418 const _EVENT_PREFIX = 'on-'; | |
| 419 | |
| 420 /// Whether an attribute declares an event. | |
| 421 bool _hasEventPrefix(String attr) => attr.startsWith(_EVENT_PREFIX); | |
| 422 | |
| 423 String _removeEventPrefix(String name) => name.substring(_EVENT_PREFIX.length); | |
| 424 | |
| 425 /// Using Polymer's platform/src/ShadowCSS.js passing the style tag's content. | 464 /// Using Polymer's platform/src/ShadowCSS.js passing the style tag's content. |
| 426 void _shimShadowDomStyling(DocumentFragment template, String name, | 465 void _shimShadowDomStyling(DocumentFragment template, String name, |
| 427 String extendee) { | 466 String extendee) { |
| 428 if (template == null || !_hasShadowDomPolyfill) return; | 467 if (template == null || _ShadowCss == null) return; |
| 429 | 468 |
| 430 var platform = js.context['Platform']; | 469 _ShadowCss.callMethod('shimStyling', [template, name, extendee]); |
| 431 if (platform == null) return; | |
| 432 var shadowCss = platform['ShadowCSS']; | |
| 433 if (shadowCss == null) return; | |
| 434 shadowCss.callMethod('shimStyling', [template, name, extendee]); | |
| 435 } | 470 } |
| 436 | 471 |
| 437 final bool _hasShadowDomPolyfill = js.context.hasProperty('ShadowDOMPolyfill'); | 472 final bool _hasShadowDomPolyfill = js.context.hasProperty('ShadowDOMPolyfill'); |
| 473 final JsObject _ShadowCss = _Platform != null ? _Platform['ShadowCSS'] : null; |
| 438 | 474 |
| 439 const _STYLE_SELECTOR = 'style'; | 475 const _STYLE_SELECTOR = 'style'; |
| 440 const _SHEET_SELECTOR = '[rel=stylesheet]'; | 476 const _SHEET_SELECTOR = 'link[rel=stylesheet]'; |
| 441 const _STYLE_GLOBAL_SCOPE = 'global'; | 477 const _STYLE_GLOBAL_SCOPE = 'global'; |
| 442 const _SCOPE_ATTR = 'polymer-scope'; | 478 const _SCOPE_ATTR = 'polymer-scope'; |
| 443 const _STYLE_SCOPE_ATTRIBUTE = 'element'; | 479 const _STYLE_SCOPE_ATTRIBUTE = 'element'; |
| 444 const _STYLE_CONTROLLER_SCOPE = 'controller'; | 480 const _STYLE_CONTROLLER_SCOPE = 'controller'; |
| 445 | 481 |
| 446 String _cssTextFromSheet(LinkElement sheet) { | 482 String _cssTextFromSheet(LinkElement sheet) { |
| 447 if (sheet == null) return ''; | 483 if (sheet == null) return ''; |
| 448 | 484 |
| 449 // In deploy mode we should never do a sync XHR; link rel=stylesheet will | 485 // In deploy mode we should never do a sync XHR; link rel=stylesheet will |
| 450 // be inlined into a <style> tag by ImportInliner. | 486 // be inlined into a <style> tag by ImportInliner. |
| (...skipping 27 matching lines...) Expand all Loading... |
| 478 includeFields: false, includeProperties: false, includeMethods: true, | 514 includeFields: false, includeProperties: false, includeMethods: true, |
| 479 includeInherited: true, includeUpTo: HtmlElement, | 515 includeInherited: true, includeUpTo: HtmlElement, |
| 480 matches: _isObserverMethod); | 516 matches: _isObserverMethod); |
| 481 | 517 |
| 482 bool _isObserverMethod(Symbol symbol) { | 518 bool _isObserverMethod(Symbol symbol) { |
| 483 String name = smoke.symbolToName(symbol); | 519 String name = smoke.symbolToName(symbol); |
| 484 if (name == null) return false; | 520 if (name == null) return false; |
| 485 return name.endsWith('Changed') && name != 'attributeChanged'; | 521 return name.endsWith('Changed') && name != 'attributeChanged'; |
| 486 } | 522 } |
| 487 | 523 |
| 488 // TODO(jmesserly): is this list complete? | |
| 489 final _eventTranslations = const { | |
| 490 // TODO(jmesserly): these three Polymer.js translations won't work in Dart, | |
| 491 // because we strip the webkit prefix (below). Reconcile. | |
| 492 'webkitanimationstart': 'webkitAnimationStart', | |
| 493 'webkitanimationend': 'webkitAnimationEnd', | |
| 494 'webkittransitionend': 'webkitTransitionEnd', | |
| 495 | |
| 496 'domfocusout': 'DOMFocusOut', | |
| 497 'domfocusin': 'DOMFocusIn', | |
| 498 'dommousescroll': 'DOMMouseScroll', | |
| 499 | |
| 500 // TODO(jmesserly): Dart specific renames. Reconcile with Polymer.js | |
| 501 'animationend': 'webkitAnimationEnd', | |
| 502 'animationiteration': 'webkitAnimationIteration', | |
| 503 'animationstart': 'webkitAnimationStart', | |
| 504 'doubleclick': 'dblclick', | |
| 505 'fullscreenchange': 'webkitfullscreenchange', | |
| 506 'fullscreenerror': 'webkitfullscreenerror', | |
| 507 'keyadded': 'webkitkeyadded', | |
| 508 'keyerror': 'webkitkeyerror', | |
| 509 'keymessage': 'webkitkeymessage', | |
| 510 'needkey': 'webkitneedkey', | |
| 511 'speechchange': 'webkitSpeechChange', | |
| 512 }; | |
| 513 | |
| 514 final _reverseEventTranslations = () { | |
| 515 final map = new Map<String, String>(); | |
| 516 _eventTranslations.forEach((onName, eventType) { | |
| 517 map[eventType] = onName; | |
| 518 }); | |
| 519 return map; | |
| 520 }(); | |
| 521 | |
| 522 // Dart note: we need this function because we have additional renames JS does | |
| 523 // not have. The JS renames are simply case differences, whereas we have ones | |
| 524 // like doubleclick -> dblclick and stripping the webkit prefix. | |
| 525 String _eventNameFromType(String eventType) { | |
| 526 final result = _reverseEventTranslations[eventType]; | |
| 527 return result != null ? result : eventType; | |
| 528 } | |
| 529 | 524 |
| 530 final _ATTRIBUTES_REGEX = new RegExp(r'\s|,'); | 525 final _ATTRIBUTES_REGEX = new RegExp(r'\s|,'); |
| 526 |
| 527 final JsObject _Platform = js.context['Platform']; |
| OLD | NEW |