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 |