OLD | NEW |
---|---|
1 part of html_common; | 1 part of html_common; |
2 | 2 |
3 convertDartToNative_PrepareForStructuredClone(value) => | 3 convertDartToNative_PrepareForStructuredClone(value) => |
4 new _StructuredCloneDartium().convertDartToNative_PrepareForStructuredClone( value); | 4 new _StructuredCloneDartium().convertDartToNative_PrepareForStructuredClone( value); |
5 | 5 |
6 convertNativeToDart_AcceptStructuredClone(object, {mustCopy: false}) => | 6 convertNativeToDart_AcceptStructuredClone(object, {mustCopy: false}) => |
7 new _AcceptStructuredCloneDartium().convertNativeToDart_AcceptStructuredClon e(object, mustCopy: mustCopy); | 7 new _AcceptStructuredCloneDartium().convertNativeToDart_AcceptStructuredClon e(object, mustCopy: mustCopy); |
8 | 8 |
9 class _StructuredCloneDartium extends _StructuredClone { | 9 class _StructuredCloneDartium extends _StructuredClone { |
10 newJsMap() => new js.JsObject(js.context["Object"]); | 10 newJsMap() => new js.JsObject(js.context["Object"]); |
(...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
133 | 133 |
134 Future convertNativePromiseToDartFuture(js.JsObject promise) { | 134 Future convertNativePromiseToDartFuture(js.JsObject promise) { |
135 var completer = new Completer(); | 135 var completer = new Completer(); |
136 var newPromise = promise | 136 var newPromise = promise |
137 .callMethod("then", [(result) => completer.complete(result)]) | 137 .callMethod("then", [(result) => completer.complete(result)]) |
138 .callMethod("catch", [(result) => completer.completeError(result)]); | 138 .callMethod("catch", [(result) => completer.completeError(result)]); |
139 return completer.future; | 139 return completer.future; |
140 } | 140 } |
141 | 141 |
142 convertDartToNative_DateTime(DateTime date) { | 142 convertDartToNative_DateTime(DateTime date) { |
143 return new js.JsObject(js.context["Date"], [date.millisecondsSinceEpoch]); | 143 return date; // TODO(jacobr): I don't get why this is needed. new js.JsObject( js.context["Date"], [date.millisecondsSinceEpoch]); |
Alan Knight
2016/03/25 21:39:09
There will be explicit calls to it from conversion
Jacob
2016/03/30 00:19:00
Removed. This is already done in Dartium C++
| |
144 } | 144 } |
145 | 145 |
146 /// Creates a Dart Rectangle from a Javascript object with properties | 146 /// Creates a Dart Rectangle from a Javascript object with properties |
147 /// left, top, width and height. Used internally in Dartium. | 147 /// left, top, width and height or a 4 element array of integers. Used internall y in Dartium. |
148 Rectangle make_dart_rectangle(r) => | 148 Rectangle make_dart_rectangle(r) { |
149 r == null ? null : new Rectangle( | 149 if (r == null) return null; |
150 js.JsNative.getProperty(r, 'left'), | 150 if (r is List) { |
151 js.JsNative.getProperty(r, 'top'), | 151 return new Rectangle(r[0], r[1], r[2], r[3]); |
152 js.JsNative.getProperty(r, 'width'), | 152 } |
153 js.JsNative.getProperty(r, 'height')); | 153 |
154 return new Rectangle( | |
155 js.JsNative.getProperty(r, 'left'), | |
156 js.JsNative.getProperty(r, 'top'), | |
157 js.JsNative.getProperty(r, 'width'), | |
158 js.JsNative.getProperty(r, 'height')); | |
159 } | |
154 | 160 |
155 // Converts a flat Dart map into a JavaScript object with properties this is | 161 // Converts a flat Dart map into a JavaScript object with properties this is |
156 // is the Dartium only version it uses dart:js. | 162 // is the Dartium only version it uses dart:js. |
157 // TODO(alanknight): This could probably be unified with the dart2js conversions | 163 // TODO(alanknight): This could probably be unified with the dart2js conversions |
158 // code in html_common and be more general. | 164 // code in html_common and be more general. |
159 convertDartToNative_Dictionary(Map dict) { | 165 convertDartToNative_Dictionary(Map dict) { |
160 if (dict == null) return null; | 166 if (dict == null) return null; |
161 var jsObject = new js.JsObject(js.JsNative.getProperty(js.context, 'Object')); | 167 var jsObject = new js.JsObject(js.context['Object']); |
162 dict.forEach((String key, value) { | 168 dict.forEach((String key, value) { |
163 if (value is List) { | 169 if (value is List) { |
164 var jsArray = new js.JsArray(); | 170 var jsArray = new js.JsArray(); |
165 value.forEach((elem) { | 171 value.forEach((elem) { |
166 jsArray.add(elem is Map ? convertDartToNative_Dictionary(elem): elem); | 172 jsArray.add(elem is Map ? convertDartToNative_Dictionary(elem): elem); |
167 }); | 173 }); |
168 jsObject[key] = jsArray; | 174 jsObject[key] = jsArray; |
169 } else { | 175 } else { |
170 jsObject[key] = value; | 176 jsObject[key] = value; |
171 } | 177 } |
(...skipping 26 matching lines...) Expand all Loading... | |
198 // class. | 204 // class. |
199 convertNativeDictionaryToDartDictionary(Map values) => | 205 convertNativeDictionaryToDartDictionary(Map values) => |
200 values != null ? new _ReturnedDictionary(values) : null; | 206 values != null ? new _ReturnedDictionary(values) : null; |
201 | 207 |
202 // Conversion function place holder (currently not used in dart2js or dartium). | 208 // Conversion function place holder (currently not used in dart2js or dartium). |
203 List convertDartToNative_StringArray(List<String> input) => input; | 209 List convertDartToNative_StringArray(List<String> input) => input; |
204 | 210 |
205 // Converts a Dart list into a JsArray. For the Dartium version only. | 211 // Converts a Dart list into a JsArray. For the Dartium version only. |
206 convertDartToNative_List(List input) => new js.JsArray()..addAll(input); | 212 convertDartToNative_List(List input) => new js.JsArray()..addAll(input); |
207 | 213 |
208 /// Find the underlying JS object for a dart:html Dart object. | 214 // Incredibly slow implementation to lookup the runtime type for an object. |
209 unwrap_jso(dartClass_instance) => js.unwrap_jso(dartClass_instance); | 215 // Fortunately, performance doesn't matter much as the results are cached |
210 | 216 // as long as the object being looked up has a valid prototype. |
211 // Flag to disable JS interop asserts. Setting to false will speed up the | 217 // TODO(jacobr): we should track the # of lookups to ensure that things aren't |
212 // wrap_jso calls. | 218 // going off the rails due to objects with null prototypes, etc. |
213 bool interop_checks = false; | 219 Type lookupType(js.JsObject jsObject) { |
Alan Knight
2016/03/25 21:39:09
Will probably break if we have JS objects that sha
Jacob
2016/03/30 00:19:00
Yep. But there is no cost of failing in the same p
| |
214 | |
215 /// Wrap a JS object with an instance of the matching dart:html class. Used only in Dartium. | |
216 wrap_jso(jsObject) { | |
217 try { | 220 try { |
218 if (jsObject is! js.JsObject || jsObject == null) { | 221 // TODO(jacobr): add static methods that return the runtime type of the patch |
219 // JS Interop converted the object to a Dart class e.g., Uint8ClampedList. | 222 // class so that this code works as expected. |
220 // or it's a simple type. | 223 if (jsObject is js.JsArray) { |
221 return jsObject; | 224 return js.JSArray.instanceRuntimeType; |
222 } | 225 } |
223 | 226 if (jsObject is js.JsFunction) { |
224 var wrapper = js.getDartHtmlWrapperFor(jsObject); | 227 return js.JSFunction.instanceRuntimeType; |
225 // if we have a wrapper return the Dart instance. | 228 } |
226 if (wrapper != null) { | |
227 return wrapper; | |
228 } | |
229 | |
230 if (jsObject is js.JsArray) { | |
231 wrapper = new js.JSArray.create(jsObject); | |
232 js.setDartHtmlWrapperFor(jsObject, wrapper); | |
233 return wrapper; | |
234 } | |
235 if (jsObject is js.JsFunction) { | |
236 wrapper = new js.JSFunction.create(jsObject); | |
237 js.setDartHtmlWrapperFor(jsObject, wrapper); | |
238 return wrapper; | |
239 } | |
240 | |
241 // Try the most general type conversions on it. | |
242 // TODO(alanknight): We may be able to do better. This maintains identity, | |
243 // which is useful, but expensive. And if we nest something that only | |
244 // this conversion handles, how does that work? e.g. a list of maps of eleme nts. | |
245 var converted = convertNativeToDart_SerializedScriptValue(jsObject); | |
246 if (!identical(converted, jsObject)) { | |
247 return converted; | |
248 } | |
249 | 229 |
250 var constructor = js.JsNative.getProperty(jsObject, 'constructor'); | 230 var constructor = js.JsNative.getProperty(jsObject, 'constructor'); |
251 if (constructor == null) { | 231 if (constructor == null) { |
252 // Perfectly valid case for JavaScript objects where __proto__ has | 232 // Perfectly valid case for JavaScript objects where __proto__ has |
253 // intentionally been set to null. | 233 // intentionally been set to null. |
254 js.setDartHtmlWrapperFor(jsObject, new js.JSObject.create(jsObject)); | 234 // We should track and warn about this case as peformance will be poor. |
255 return jsObject; | 235 return js.JSObject.instanceRuntimeType; |
256 } | 236 } |
257 var jsTypeName = js.JsNative.getProperty(constructor, 'name'); | 237 var jsTypeName = js.JsNative.getProperty(constructor, 'name'); |
258 if (jsTypeName is! String || jsTypeName.length == 0) { | 238 if (jsTypeName is! String || jsTypeName.length == 0) { |
259 // Not an html type. | 239 // Not an html type. |
260 wrapper = new js.JSObject.create(jsObject); | 240 return js.JSObject.instanceRuntimeType; |
261 js.setDartHtmlWrapperFor(jsObject, wrapper); | |
262 return wrapper; | |
263 } | 241 } |
264 | 242 |
265 var dartClass_instance; | 243 var dartClass_instance; |
266 var customElementClass = null; | 244 var customElementClass = null; |
267 var extendsTag = ""; | 245 var extendsTag = ""; |
268 var custom = getCustomElementEntry(jsObject); | 246 var custom = getCustomElementEntry(jsObject); |
269 if (custom != null) { | 247 if (custom != null) { |
270 customElementClass = custom['type']; | 248 customElementClass = custom['type']; |
271 extendsTag = custom['extends']; | 249 extendsTag = custom['extends']; |
272 } | 250 } |
273 | 251 |
274 // Only allow custom elements to be created in the html or svg default | 252 // Only allow custom elements to be created in the html or svg default |
275 // namespace. | 253 // namespace. |
276 var func; | 254 var func; |
277 var defaultNS = jsObject['namespaceURI'] == 'http://www.w3.org/1999/xhtml' | | | 255 var defaultNS = jsObject['namespaceURI'] == 'http://www.w3.org/1999/xhtml' | | |
278 jsObject['namespaceURI'] == 'http://www.w3.org/2000/svg'; | 256 jsObject['namespaceURI'] == 'http://www.w3.org/2000/svg'; |
279 if (customElementClass != null && extendsTag == "" && defaultNS) { | 257 if (customElementClass != null && extendsTag == "" && defaultNS) { |
280 // The customElementClass is known but we can't create the real class so | 258 // The customElementClass is known but we can't create the real class so |
281 // create the HtmlElement and it will get upgraded when registerElement's | 259 // create the HtmlElement and it will get upgraded when registerElement's |
282 // createdCallback is called. | 260 // createdCallback is called. |
283 func = getHtmlCreateFunction('HTMLElement'); | 261 func = getHtmlCreateFunction('HTMLElement'); |
284 } else { | 262 } else { |
285 func = getHtmlCreateFunction(jsTypeName); | 263 func = getHtmlCreateFunction(jsTypeName); |
286 if (func == null) { | 264 if (func == null) { |
287 // Start walking the prototype chain looking for a JS class. | 265 // Start walking the prototype chain looking for a JS class. |
288 var prototype = jsObject['__proto__']; | 266 var prototype = jsObject['__proto__']; |
289 var keepWalking = true; | 267 while (prototype != null && prototype.hasProperty('__proto__')) { |
290 while (keepWalking && prototype.hasProperty('__proto__')) { | |
291 prototype = prototype['__proto__']; | 268 prototype = prototype['__proto__']; |
292 if (prototype != null && prototype is Element && | 269 // XXX FIX this... we are hosed if we hit a not JS class |
293 prototype.blink_jsObject != null) { | 270 // so this makes little sense. |
294 // We're a Dart class that's pointing to a JS class. | 271 if (prototype is! js.JsObject) break; |
295 var blinkJso = prototype.blink_jsObject; | 272 |
296 jsTypeName = blinkJso['constructor']['name']; | 273 // We're a Dart class that's pointing to a JS class. |
274 var constructor = prototype['constructor']; | |
275 if (constructor is js.JsObject) { | |
276 jsTypeName = constructor['name']; | |
297 func = getHtmlCreateFunction(jsTypeName); | 277 func = getHtmlCreateFunction(jsTypeName); |
298 keepWalking = func == null; | 278 if (func != null) break; |
299 } | 279 } |
300 } | 280 } |
301 } | 281 } |
302 } | 282 } |
303 | 283 |
304 // Can we construct a Dart class? | 284 // Can we construct a Dart class? |
305 if (func != null) { | 285 if (func != null) { |
306 dartClass_instance = func(); | 286 var ret = func().runtimeType; |
287 return ret; | |
288 } | |
289 } catch (e, stacktrace) { | |
290 if (e is DebugAssertException) print("${e.message}\n ${stacktrace}"); | |
291 else print("${stacktrace}"); | |
292 } | |
293 return js.JSObject.instanceRuntimeType; | |
294 } | |
307 | 295 |
308 // Wrap our Dart instance in both directions. | 296 CustomElementEntry getCustomElementEntry(element) { |
309 dartClass_instance.blink_jsObject = jsObject; | 297 var hasAttribute = false; |
310 js.setDartHtmlWrapperFor(jsObject, dartClass_instance); | 298 |
299 var jsObject; | |
300 var tag; | |
301 | |
302 // It's a Polymer core element (written in JS). | |
303 // Make sure it's an element anything else we can ignore. | |
304 if (element.hasProperty('nodeType') && element['nodeType'] == 1) { | |
305 if (js.JsNative.callMethod(element, 'hasAttribute', ['is'])) { | |
306 hasAttribute = true; | |
307 // It's data binding use the is attribute. | |
308 tag = js.JsNative.callMethod(element, 'getAttribute', ['is']); | |
309 } else { | |
310 // It's a custom element we want the local name. | |
311 tag = js.JsNative.getProperty(element, 'localName'); | |
311 } | 312 } |
313 } | |
312 | 314 |
313 // TODO(jacobr): cache that this is not a dart:html JS class. | 315 // TODO: handle template element case? I think it is handled by is, etc. |
314 return dartClass_instance; | 316 if (tag != null) { |
315 } catch (e, stacktrace) { | 317 CustomElementEntry entry = _knownCustomElements[tag]; |
316 if (interop_checks) { | 318 if (entry != null) { |
317 if (e is DebugAssertException) window.console | 319 // If there's an 'is' attribute then check if the extends tag registered |
318 .log("${e.message}\n ${stacktrace}"); | 320 // matches the tag if so then return the entry that's registered for this |
319 else window.console.log("${stacktrace}"); | 321 // extendsTag or if there's no 'is' tag then return the entry found. |
322 if ((hasAttribute && entry.extendTag == tag) || !hasAttribute) { | |
323 return entry; | |
324 } | |
320 } | 325 } |
321 } | 326 } |
322 | 327 |
323 return null; | 328 return null; |
324 } | 329 } |
325 | 330 |
326 /** | 331 class CustomElementEntry { |
327 * Create Dart class that maps to the JS Type, add the JsObject as an expando | 332 CustomElementEntry({this.type, this.extendTag}); |
328 * on the Dart class and return the created Dart class. | |
329 */ | |
330 wrap_jso_no_SerializedScriptvalue(jsObject) { | |
331 try { | |
332 if (jsObject is! js.JsObject || jsObject == null) { | |
333 // JS Interop converted the object to a Dart class e.g., Uint8ClampedList. | |
334 // or it's a simple type. | |
335 return jsObject; | |
336 } | |
337 | 333 |
338 // TODO(alanknight): With upgraded custom elements this causes a failure bec ause | 334 final Type type; |
339 // we need a new wrapper after the type changes. We could possibly invalidat e this | 335 final String extendTag; |
340 // if the constructor name didn't match? | |
341 var wrapper = js.getDartHtmlWrapperFor(jsObject); | |
342 if (wrapper != null) { | |
343 return wrapper; | |
344 } | |
345 | |
346 if (jsObject is js.JsArray) { | |
347 wrapper = new js.JSArray.create(jsObject); | |
348 js.setDartHtmlWrapperFor(jsObject, wrapper); | |
349 return wrapper; | |
350 } | |
351 if (jsObject is js.JsFunction) { | |
352 wrapper = new js.JSFunction.create(jsObject); | |
353 js.setDartHtmlWrapperFor(jsObject, wrapper); | |
354 return wrapper; | |
355 } | |
356 | |
357 var constructor = js.JsNative.getProperty(jsObject, 'constructor'); | |
358 if (constructor == null) { | |
359 // Perfectly valid case for JavaScript objects where __proto__ has | |
360 // intentionally been set to null. | |
361 js.setDartHtmlWrapperFor(jsObject, new js.JSObject.create(jsObject)); | |
362 return jsObject; | |
363 } | |
364 var jsTypeName = js.JsNative.getProperty(constructor, 'name'); | |
365 if (jsTypeName is! String || jsTypeName.length == 0) { | |
366 // Not an html type. | |
367 wrapper = new js.JSObject.create(jsObject); | |
368 js.setDartHtmlWrapperFor(jsObject, wrapper); | |
369 return wrapper; | |
370 } | |
371 | |
372 var func = getHtmlCreateFunction(jsTypeName); | |
373 if (func != null) { | |
374 var dartClass_instance = func(); | |
375 dartClass_instance.blink_jsObject = jsObject; | |
376 js.setDartHtmlWrapperFor(jsObject, dartClass_instance); | |
377 return dartClass_instance; | |
378 } | |
379 wrapper = new js.JSObject.create(jsObject); | |
380 js.setDartHtmlWrapperFor(jsObject, wrapper); | |
381 return wrapper; | |
382 } catch (e, stacktrace) { | |
383 if (interop_checks) { | |
384 if (e is DebugAssertException) window.console | |
385 .log("${e.message}\n ${stacktrace}"); | |
386 else window.console.log("${stacktrace}"); | |
387 } | |
388 } | |
389 | |
390 return null; | |
391 } | |
392 | |
393 /** | |
394 * Create Dart class that maps to the JS Type that is the JS type being | |
395 * extended using JS interop createCallback (we need the base type of the | |
396 * custom element) not the Dart created constructor. | |
397 */ | |
398 wrap_jso_custom_element(jsObject) { | |
399 try { | |
400 if (jsObject is! js.JsObject) { | |
401 // JS Interop converted the object to a Dart class e.g., Uint8ClampedList. | |
402 return jsObject; | |
403 } | |
404 | |
405 // Find out what object we're extending. | |
406 var objectName = jsObject.toString(); | |
407 // Expect to see something like '[object HTMLElement]'. | |
408 if (!objectName.startsWith('[object ')) { | |
409 return jsObject; | |
410 } | |
411 | |
412 var extendsClass = objectName.substring(8, objectName.length - 1); | |
413 var func = getHtmlCreateFunction(extendsClass); | |
414 if (interop_checks) | |
415 debug_or_assert("func != null name = ${extendsClass}", func != null); | |
416 var dartClass_instance = func(); | |
417 dartClass_instance.blink_jsObject = jsObject; | |
418 return dartClass_instance; | |
419 } catch(e, stacktrace){ | |
420 if (interop_checks) { | |
421 if (e is DebugAssertException) | |
422 window.console.log("${e.message}\n ${stacktrace}"); | |
423 else | |
424 window.console.log("${stacktrace}"); | |
425 } | |
426 | |
427 // Problem? | |
428 return null; | |
429 } | |
430 } | |
431 | |
432 getCustomElementEntry(element) { | |
433 var hasAttribute = false; | |
434 | |
435 var jsObject; | |
436 var tag = ""; | |
437 var runtimeType = element.runtimeType; | |
438 if (runtimeType == HtmlElement) { | |
439 tag = element.localName; | |
440 } else if (runtimeType == TemplateElement) { | |
441 // Data binding with a Dart class. | |
442 tag = element.attributes['is']; | |
443 } else if (runtimeType == js.JsObject) { | |
444 // It's a Polymer core element (written in JS). | |
445 // Make sure it's an element anything else we can ignore. | |
446 if (element.hasProperty('nodeType') && element['nodeType'] == 1) { | |
447 if (js.JsNative.callMethod(element, 'hasAttribute', ['is'])) { | |
448 hasAttribute = true; | |
449 // It's data binding use the is attribute. | |
450 tag = js.JsNative.callMethod(element, 'getAttribute', ['is']); | |
451 } else { | |
452 // It's a custom element we want the local name. | |
453 tag = element['localName']; | |
454 } | |
455 } | |
456 } else { | |
457 throw new UnsupportedError( | |
458 'Element is incorrect type. Got ${runtimeType}, expected HtmlElement/Htm lTemplate/JsObject.'); | |
459 } | |
460 | |
461 var entry = _knownCustomElements[tag]; | |
462 if (entry != null) { | |
463 // If there's an 'is' attribute then check if the extends tag registered | |
464 // matches the tag if so then return the entry that's registered for this | |
465 // extendsTag or if there's no 'is' tag then return the entry found. | |
466 if ((hasAttribute && entry['extends'] == tag) || !hasAttribute) { | |
467 return entry; | |
468 } | |
469 } | |
470 | |
471 return null; | |
472 } | 336 } |
473 | 337 |
474 // List of known tagName to DartClass for custom elements, used for upgrade. | 338 // List of known tagName to DartClass for custom elements, used for upgrade. |
475 var _knownCustomElements = new Map<String, Map<Type, String>>(); | 339 var _knownCustomElements = new Map<String, CustomElementEntry>(); |
476 | 340 |
477 void addCustomElementType(String tagName, Type dartClass, [String extendTag]) { | 341 void addCustomElementType(String tagName, Type dartClass, [String extendTag]) { |
478 _knownCustomElements[tagName] = | 342 _knownCustomElements[tagName] = |
479 {'type': dartClass, 'extends': extendTag != null ? extendTag : "" }; | 343 new CustomElementEntry(type: dartClass, extendTag: extendTag != null ? ext endTag : ""); |
480 } | 344 } |
481 | 345 |
482 Type getCustomElementType(object) { | 346 Type getCustomElementType(object) { |
483 var entry = getCustomElementEntry(object); | 347 var entry = getCustomElementEntry(object); |
484 if (entry != null) { | 348 if (entry != null) { |
485 return entry['type']; | 349 return entry.type; |
486 } | 350 } |
487 return null; | 351 return null; |
488 } | 352 } |
OLD | NEW |