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 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
68 } | 68 } |
69 | 69 |
70 /// Creates a Dart Rectangle from a Javascript object with properties | 70 /// Creates a Dart Rectangle from a Javascript object with properties |
71 /// left, top, width and height. Used internally in Dartium. | 71 /// left, top, width and height. Used internally in Dartium. |
72 Rectangle make_dart_rectangle(r) => | 72 Rectangle make_dart_rectangle(r) => |
73 r == null ? null : new Rectangle( | 73 r == null ? null : new Rectangle( |
74 js.JsNative.getProperty(r, 'left'), | 74 js.JsNative.getProperty(r, 'left'), |
75 js.JsNative.getProperty(r, 'top'), | 75 js.JsNative.getProperty(r, 'top'), |
76 js.JsNative.getProperty(r, 'width'), | 76 js.JsNative.getProperty(r, 'width'), |
77 js.JsNative.getProperty(r, 'height')); | 77 js.JsNative.getProperty(r, 'height')); |
| 78 |
| 79 // Converts a flat Dart map into a JavaScript object with properties this is |
| 80 // is the Dartium only version it uses dart:js. |
| 81 // TODO(alanknight): This could probably be unified with the dart2js conversions |
| 82 // code in html_common and be more general. |
| 83 convertDartToNative_Dictionary(Map dict) { |
| 84 if (dict == null) return null; |
| 85 var jsObject = new js.JsObject(js.JsNative.getProperty(js.context, 'Object')); |
| 86 dict.forEach((String key, value) { |
| 87 if (value is List) { |
| 88 var jsArray = new js.JsArray(); |
| 89 value.forEach((elem) { |
| 90 jsArray.add(elem is Map ? convertDartToNative_Dictionary(elem): elem); |
| 91 }); |
| 92 jsObject[key] = jsArray; |
| 93 } else { |
| 94 jsObject[key] = value; |
| 95 } |
| 96 }); |
| 97 return jsObject; |
| 98 } |
| 99 |
| 100 // Conversion function place holder (currently not used in dart2js or dartium). |
| 101 List convertDartToNative_StringArray(List<String> input) => input; |
| 102 |
| 103 // Converts a Dart list into a JsArray. For the Dartium version only. |
| 104 convertDartToNative_List(List input) => new js.JsArray()..addAll(input); |
| 105 |
| 106 /// Find the underlying JS object for a dart:html Dart object. |
| 107 unwrap_jso(dartClass_instance) => js.unwrap_jso(dartClass_instance); |
| 108 |
| 109 // Flag to disable JS interop asserts. Setting to false will speed up the |
| 110 // wrap_jso calls. |
| 111 bool interop_checks = false; |
| 112 |
| 113 /// Wrap a JS object with an instance of the matching dart:html class. Used only
in Dartium. |
| 114 wrap_jso(jsObject) { |
| 115 try { |
| 116 if (jsObject is! js.JsObject || jsObject == null) { |
| 117 // JS Interop converted the object to a Dart class e.g., Uint8ClampedList. |
| 118 // or it's a simple type. |
| 119 return jsObject; |
| 120 } |
| 121 |
| 122 var wrapper = js.getDartHtmlWrapperFor(jsObject); |
| 123 // if we have a wrapper return the Dart instance. |
| 124 if (wrapper != null) { |
| 125 var customElementClass = getCustomElementType(wrapper.blink_jsObject); |
| 126 if (wrapper.runtimeType != customElementClass && customElementClass != nul
l) { |
| 127 if (wrapper.runtimeType == HtmlElement && !wrapper.isBadUpgrade) { |
| 128 // We're a Dart instance if it's HtmlElement and we have a customEleme
nt |
| 129 // class then we need to upgrade. |
| 130 if (customElementClass != null) { |
| 131 var dartClass_instance; |
| 132 try { |
| 133 dartClass_instance = _blink.Blink_Utils.constructElement(customEle
mentClass, jsObject); |
| 134 } finally { |
| 135 dartClass_instance.blink_jsObject = jsObject; |
| 136 return dartClass_instance; |
| 137 } |
| 138 } |
| 139 } |
| 140 } |
| 141 |
| 142 return wrapper; |
| 143 } |
| 144 |
| 145 if (jsObject is js.JsArray) { |
| 146 var wrappingList = new DartHtmlWrappingList(jsObject); |
| 147 js.setDartHtmlWrapperFor(jsObject, wrappingList); |
| 148 return wrappingList; |
| 149 } |
| 150 |
| 151 // Try the most general type conversions on it. |
| 152 // TODO(alanknight): We may be able to do better. This maintains identity, |
| 153 // which is useful, but expensive. And if we nest something that only |
| 154 // this conversion handles, how does that work? e.g. a list of maps of eleme
nts. |
| 155 var converted = convertNativeToDart_SerializedScriptValue(jsObject); |
| 156 if (!identical(converted, jsObject)) { |
| 157 return converted; |
| 158 } |
| 159 |
| 160 var constructor = js.JsNative.getProperty(jsObject, 'constructor'); |
| 161 if (constructor == null) { |
| 162 // Perfectly valid case for JavaScript objects where __proto__ has |
| 163 // intentionally been set to null. |
| 164 js.setDartHtmlWrapperFor(jsObject, jsObject); |
| 165 return jsObject; |
| 166 } |
| 167 var jsTypeName = js.JsNative.getProperty(constructor, 'name'); |
| 168 if (jsTypeName is! String || jsTypeName.length == 0) { |
| 169 // Not an html type. |
| 170 js.setDartHtmlWrapperFor(jsObject, jsObject); |
| 171 return jsObject; |
| 172 } |
| 173 |
| 174 var dartClass_instance; |
| 175 var customElementClass = null; |
| 176 var extendsTag = ""; |
| 177 var custom = getCustomElementEntry(jsObject); |
| 178 if (custom != null) { |
| 179 customElementClass = custom['type']; |
| 180 extendsTag = custom['extends']; |
| 181 } |
| 182 |
| 183 // Custom Element to upgrade. |
| 184 // Only allow custome elements to be created in the html or svg default |
| 185 // namespace. |
| 186 var defaultNS = jsObject['namespaceURI'] == 'http://www.w3.org/1999/xhtml' |
| |
| 187 jsObject['namespaceURI'] == 'http://www.w3.org/2000/svg'; |
| 188 if (customElementClass != null && extendsTag == "" && defaultNS) { |
| 189 try { |
| 190 dartClass_instance = _blink.Blink_Utils.constructElement(customElementCl
ass, jsObject); |
| 191 } finally { |
| 192 dartClass_instance.blink_jsObject = jsObject; |
| 193 js.setDartHtmlWrapperFor(jsObject, dartClass_instance); |
| 194 } |
| 195 } else { |
| 196 var func = getHtmlCreateFunction(jsTypeName); |
| 197 if (func == null) { |
| 198 if (jsTypeName == 'auto-binding') { |
| 199 func = getHtmlCreateFunction("HTMLTemplateElement"); |
| 200 } else if (jsObject.toString() == "[object HTMLElement]") { |
| 201 // One last ditch effort could be a JS custom element. |
| 202 func = getHtmlCreateFunction("HTMLElement"); |
| 203 } |
| 204 } |
| 205 if (func != null) { |
| 206 dartClass_instance = func(); |
| 207 dartClass_instance.blink_jsObject = jsObject; |
| 208 js.setDartHtmlWrapperFor(jsObject, dartClass_instance); |
| 209 } |
| 210 } |
| 211 |
| 212 // TODO(jacobr): cache that this is not a dart:html JS class. |
| 213 return dartClass_instance; |
| 214 } catch(e, stacktrace){ |
| 215 if (interop_checks) { |
| 216 if (e is DebugAssertException) |
| 217 window.console.log("${e.message}\n ${stacktrace}"); |
| 218 else |
| 219 window.console.log("${stacktrace}"); |
| 220 } |
| 221 } |
| 222 |
| 223 return null; |
| 224 } |
| 225 |
| 226 /** |
| 227 * Create Dart class that maps to the JS Type, add the JsObject as an expando |
| 228 * on the Dart class and return the created Dart class. |
| 229 */ |
| 230 wrap_jso_no_SerializedScriptvalue(jsObject) { |
| 231 try { |
| 232 if (jsObject is! js.JsObject || jsObject == null) { |
| 233 // JS Interop converted the object to a Dart class e.g., Uint8ClampedList. |
| 234 // or it's a simple type. |
| 235 return jsObject; |
| 236 } |
| 237 |
| 238 // TODO(alanknight): With upgraded custom elements this causes a failure bec
ause |
| 239 // we need a new wrapper after the type changes. We could possibly invalidat
e this |
| 240 // if the constructor name didn't match? |
| 241 var wrapper = js.getDartHtmlWrapperFor(jsObject); |
| 242 if (wrapper != null) { |
| 243 return wrapper; |
| 244 } |
| 245 |
| 246 if (jsObject is js.JsArray) { |
| 247 var wrappingList = new DartHtmlWrappingList(jsObject); |
| 248 js.setDartHtmlWrapperFor(jsObject, wrappingList); |
| 249 return wrappingList; |
| 250 } |
| 251 |
| 252 var constructor = js.JsNative.getProperty(jsObject, 'constructor'); |
| 253 if (constructor == null) { |
| 254 // Perfectly valid case for JavaScript objects where __proto__ has |
| 255 // intentionally been set to null. |
| 256 js.setDartHtmlWrapperFor(jsObject, jsObject); |
| 257 return jsObject; |
| 258 } |
| 259 var jsTypeName = js.JsNative.getProperty(constructor, 'name'); |
| 260 if (jsTypeName is! String || jsTypeName.length == 0) { |
| 261 // Not an html type. |
| 262 js.setDartHtmlWrapperFor(jsObject, jsObject); |
| 263 return jsObject; |
| 264 } |
| 265 |
| 266 var func = getHtmlCreateFunction(jsTypeName); |
| 267 if (func != null) { |
| 268 var dartClass_instance = func(); |
| 269 dartClass_instance.blink_jsObject = jsObject; |
| 270 js.setDartHtmlWrapperFor(jsObject, dartClass_instance); |
| 271 return dartClass_instance; |
| 272 } |
| 273 return jsObject; |
| 274 } catch(e, stacktrace){ |
| 275 if (interop_checks) { |
| 276 if (e is DebugAssertException) |
| 277 window.console.log("${e.message}\n ${stacktrace}"); |
| 278 else |
| 279 window.console.log("${stacktrace}"); |
| 280 } |
| 281 } |
| 282 |
| 283 return null; |
| 284 } |
| 285 |
| 286 /** |
| 287 * Create Dart class that maps to the JS Type that is the JS type being |
| 288 * extended using JS interop createCallback (we need the base type of the |
| 289 * custom element) not the Dart created constructor. |
| 290 */ |
| 291 wrap_jso_custom_element(jsObject) { |
| 292 try { |
| 293 if (jsObject is! js.JsObject) { |
| 294 // JS Interop converted the object to a Dart class e.g., Uint8ClampedList. |
| 295 return jsObject; |
| 296 } |
| 297 |
| 298 // Find out what object we're extending. |
| 299 var objectName = jsObject.toString(); |
| 300 // Expect to see something like '[object HTMLElement]'. |
| 301 if (!objectName.startsWith('[object ')) { |
| 302 return jsObject; |
| 303 } |
| 304 |
| 305 var extendsClass = objectName.substring(8, objectName.length - 1); |
| 306 var func = getHtmlCreateFunction(extendsClass); |
| 307 if (interop_checks) |
| 308 debug_or_assert("func != null name = ${extendsClass}", func != null); |
| 309 var dartClass_instance = func(); |
| 310 dartClass_instance.blink_jsObject = jsObject; |
| 311 return dartClass_instance; |
| 312 } catch(e, stacktrace){ |
| 313 if (interop_checks) { |
| 314 if (e is DebugAssertException) |
| 315 window.console.log("${e.message}\n ${stacktrace}"); |
| 316 else |
| 317 window.console.log("${stacktrace}"); |
| 318 } |
| 319 |
| 320 // Problem? |
| 321 return null; |
| 322 } |
| 323 } |
| 324 |
| 325 getCustomElementEntry(element) { |
| 326 var hasAttribute = false; |
| 327 |
| 328 var jsObject; |
| 329 var tag = ""; |
| 330 var runtimeType = element.runtimeType; |
| 331 if (runtimeType == HtmlElement) { |
| 332 tag = element.localName; |
| 333 } else if (runtimeType == TemplateElement) { |
| 334 // Data binding with a Dart class. |
| 335 tag = element.attributes['is']; |
| 336 } else if (runtimeType == js.JsObjectImpl) { |
| 337 // It's a Polymer core element (written in JS). |
| 338 // Make sure it's an element anything else we can ignore. |
| 339 if (element.hasProperty('nodeType') && element['nodeType'] == 1) { |
| 340 if (js.JsNative.callMethod(element, 'hasAttribute', ['is'])) { |
| 341 hasAttribute = true; |
| 342 // It's data binding use the is attribute. |
| 343 tag = js.JsNative.callMethod(element, 'getAttribute', ['is']); |
| 344 } else { |
| 345 // It's a custom element we want the local name. |
| 346 tag = element['localName']; |
| 347 } |
| 348 } |
| 349 } else { |
| 350 throw new UnsupportedError('Element is incorrect type. Got ${runtimeType}, e
xpected HtmlElement/HtmlTemplate/JsObjectImpl.'); |
| 351 } |
| 352 |
| 353 var entry = _knownCustomElements[tag]; |
| 354 if (entry != null) { |
| 355 // If there's an 'is' attribute then check if the extends tag registered |
| 356 // matches the tag if so then return the entry that's registered for this |
| 357 // extendsTag or if there's no 'is' tag then return the entry found. |
| 358 if ((hasAttribute && entry['extends'] == tag) || !hasAttribute) { |
| 359 return entry; |
| 360 } |
| 361 } |
| 362 |
| 363 return null; |
| 364 } |
| 365 |
| 366 // List of known tagName to DartClass for custom elements, used for upgrade. |
| 367 var _knownCustomElements = new Map<String, Map<Type, String>>(); |
| 368 |
| 369 void addCustomElementType(String tagName, Type dartClass, [String extendTag]) { |
| 370 _knownCustomElements[tagName] = |
| 371 {'type': dartClass, 'extends': extendTag != null ? extendTag : "" }; |
| 372 } |
| 373 |
| 374 Type getCustomElementType(object) { |
| 375 var entry = getCustomElementEntry(object); |
| 376 if (entry != null) { |
| 377 return entry['type']; |
| 378 } |
| 379 return null; |
| 380 } |
| 381 |
| 382 /** |
| 383 * Wraps a JsArray and will call wrap_jso on its entries. |
| 384 */ |
| 385 class DartHtmlWrappingList extends ListBase implements NativeFieldWrapperClass2
{ |
| 386 DartHtmlWrappingList(this.blink_jsObject); |
| 387 |
| 388 final js.JsArray blink_jsObject; |
| 389 |
| 390 operator [](int index) => wrap_jso(js.JsNative.getArrayIndex(blink_jsObject, i
ndex)); |
| 391 |
| 392 operator []=(int index, value) => blink_jsObject[index] = value; |
| 393 |
| 394 int get length => blink_jsObject.length; |
| 395 int set length(int newLength) => blink_jsObject.length = newLength; |
| 396 } |
OLD | NEW |