| 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() => js.JsNative.newObject(); |
| 11 putIntoMap(map, key, value) => map[key] = value; | 11 putIntoMap(map, key, value) => js.JsNative.setProperty(map, key, value); |
| 12 // TODO(alanknight): Don't create two extra lists to get a fixed-length JS lis
t. | 12 newJsList(length) => js.JsNative.newArray()..length = length; |
| 13 newJsList(length) => new js.JsArray.from(new List(length)); | 13 cloneNotRequired(e) => |
| 14 cloneNotRequired(e) => e is js.JsObject; | 14 e is js.JSObject || e is TypedData || e is ByteBuffer; |
| 15 } | 15 } |
| 16 | 16 |
| 17 /// A version of _AcceptStructuredClone, but using a different algorithm | 17 /// A version of _AcceptStructuredClone, but using a different algorithm |
| 18 /// so we can take advantage of an identity HashMap on Dartium without | 18 /// so we can take advantage of an identity HashMap on Dartium without |
| 19 /// the bad side-effect of modifying the JS source objects if we do the same in | 19 /// the bad side-effect of modifying the JS source objects if we do the same in |
| 20 /// dart2js. | 20 /// dart2js. |
| 21 /// | 21 /// |
| 22 /// This no longer inherits anything from _AcceptStructuredClone | 22 /// This no longer inherits anything from _AcceptStructuredClone |
| 23 /// and is never used polymorphically with it, so it doesn't inherit. | 23 /// and is never used polymorphically with it, so it doesn't inherit. |
| 24 class _AcceptStructuredCloneDartium { | 24 class _AcceptStructuredCloneDartium { |
| 25 newDartList(length) => new List(length); | 25 newDartList(length) => new List(length); |
| 26 | 26 |
| 27 // JsObjects won't be identical, but will be equal only if the underlying | 27 // As long as we stick to JSObject instead of intermingling legacy JsObject, |
| 28 // Js entities are identical. | 28 // we can simply use identical. |
| 29 bool identicalInJs(a, b) => | 29 bool identicalInJs(a, b) => identical(a, b); |
| 30 (a is js.JsObject) ? a == b : identical(a, b); | |
| 31 | 30 |
| 32 void forEachJsField(jsObject, action) { | 31 void forEachJsField(jsObject, action) { |
| 33 var keys = js.context["Object"].callMethod("keys", [jsObject]); | 32 var keys = js.JsNative.callMethod(_object, "keys", [jsObject]); |
| 34 for (var key in keys) { | 33 for (var key in keys) { |
| 35 action(key, jsObject[key]); | 34 action(key, js.JsNative.getProperty(jsObject, key)); |
| 36 } | 35 } |
| 37 } | 36 } |
| 38 | 37 |
| 39 // Keep track of the clones, keyed by the original object. If we're | 38 // Keep track of the clones, keyed by the original object. If we're |
| 40 // not copying, these may be the same. | 39 // not copying, these may be the same. |
| 41 var clones = new HashMap.identity(); | 40 var clones = new HashMap.identity(); |
| 42 bool mustCopy = false; | 41 bool mustCopy = false; |
| 43 | 42 |
| 44 Object findSlot(value) { | 43 Object findSlot(value) { |
| 45 return clones.putIfAbsent(value, () => null); | 44 return clones.putIfAbsent(value, () => null); |
| 46 } | 45 } |
| 47 | 46 |
| 48 writeSlot(original, x) { clones[original] = x; } | 47 writeSlot(original, x) { clones[original] = x; } |
| 49 | 48 |
| 50 walk(e) { | 49 walk(e) { |
| 51 if (e == null) return e; | 50 if (e == null) return e; |
| 52 if (e is bool) return e; | 51 if (e is bool) return e; |
| 53 if (e is num) return e; | 52 if (e is num) return e; |
| 54 if (e is String) return e; | 53 if (e is String) return e; |
| 55 | 54 if (e is DateTime) return e; |
| 56 if (isJavaScriptDate(e)) { | |
| 57 return convertNativeToDart_DateTime(e); | |
| 58 } | |
| 59 | 55 |
| 60 if (isJavaScriptRegExp(e)) { | 56 if (isJavaScriptRegExp(e)) { |
| 61 // TODO(sra). | 57 // TODO(sra). |
| 62 throw new UnimplementedError('structured clone of RegExp'); | 58 throw new UnimplementedError('structured clone of RegExp'); |
| 63 } | 59 } |
| 64 | 60 |
| 65 if (isJavaScriptPromise(e)) { | 61 if (isJavaScriptPromise(e)) { |
| 66 return convertNativePromiseToDartFuture(e); | 62 return convertNativePromiseToDartFuture(e); |
| 67 } | 63 } |
| 68 | 64 |
| (...skipping 30 matching lines...) Expand all Loading... |
| 99 return e; | 95 return e; |
| 100 } | 96 } |
| 101 | 97 |
| 102 convertNativeToDart_AcceptStructuredClone(object, {mustCopy: false}) { | 98 convertNativeToDart_AcceptStructuredClone(object, {mustCopy: false}) { |
| 103 this.mustCopy = mustCopy; | 99 this.mustCopy = mustCopy; |
| 104 var copy = walk(object); | 100 var copy = walk(object); |
| 105 return copy; | 101 return copy; |
| 106 } | 102 } |
| 107 } | 103 } |
| 108 | 104 |
| 109 final _dateConstructor = js.context["Date"]; | 105 final _dateConstructor = js.JsNative.getProperty(window, "Date"); |
| 110 final _regexConstructor = js.context["RegExp"]; | 106 final _regexConstructor = js.JsNative.getProperty(window, "RegExp"); |
| 111 | 107 |
| 112 bool isJavaScriptDate(value) => value is js.JsObject && value.instanceof(_dateCo
nstructor); | 108 bool isJavaScriptDate(value) => value is js.JSObject && js.JsNative.instanceof(v
alue, _dateConstructor); |
| 113 bool isJavaScriptRegExp(value) => value is js.JsObject && value.instanceof(_rege
xConstructor); | 109 bool isJavaScriptRegExp(value) => value is js.JSObject && js.JsNative.instanceof
(value, _regexConstructor); |
| 114 bool isJavaScriptArray(value) => value is js.JsArray; | 110 bool isJavaScriptArray(value) => value is js.JSArray; |
| 115 | 111 |
| 116 final _object = js.context["Object"]; | 112 final _object = js.JsNative.getProperty(window, "Object"); |
| 117 final _getPrototypeOf = _object["getPrototypeOf"]; | 113 final _getPrototypeOf = js.JsNative.getProperty(_object, "getPrototypeOf"); |
| 118 _getProto(object) { | 114 _getProto(object) { |
| 119 return _getPrototypeOf.apply([object]); | 115 return _getPrototypeOf(object); |
| 120 } | 116 } |
| 121 final _objectProto = js.context["Object"]["prototype"]; | 117 final _objectProto = js.JsNative.getProperty(_object, "prototype"); |
| 122 | 118 |
| 123 bool isJavaScriptSimpleObject(value) { | 119 bool isJavaScriptSimpleObject(value) { |
| 124 if (value is! js.JsObject) return false; | 120 if (value is! js.JSObject) return false; |
| 125 var proto = _getProto(value); | 121 var proto = _getProto(value); |
| 126 return proto == _objectProto || proto == null; | 122 return proto == _objectProto || proto == null; |
| 127 } | 123 } |
| 124 |
| 125 // TODO(jacobr): this makes little sense unless we are doing something |
| 126 // ambitious to make Dartium and Dart2Js interop well with each other. |
| 128 bool isImmutableJavaScriptArray(value) => | 127 bool isImmutableJavaScriptArray(value) => |
| 129 isJavaScriptArray(value) && value["immutable$list"] != null; | 128 isJavaScriptArray(value) && js.JsNative.getProperty(value, "immutable$list")
!= null; |
| 130 | 129 |
| 131 final _promiseConstructor = js.context['Promise']; | 130 final _promiseConstructor = js.JsNative.getProperty(window, 'Promise'); |
| 132 bool isJavaScriptPromise(value) => value is js.JsObject && value['constructor']
== _promiseConstructor; | 131 bool isJavaScriptPromise(value) => value is js.JSObject && identical(js.JsNative
.getProperty(value, 'constructor'), _promiseConstructor); |
| 133 | 132 |
| 134 Future convertNativePromiseToDartFuture(js.JsObject promise) { | 133 Future convertNativePromiseToDartFuture(js.JSObject promise) { |
| 135 var completer = new Completer(); | 134 var completer = new Completer(); |
| 136 var newPromise = promise | 135 var newPromise = js.JsNative.callMethod(js.JsNative.callMethod(promise, |
| 137 .callMethod("then", [(result) => completer.complete(result)]) | 136 "then", [js.allowInterop((result) => completer.complete(result))]), |
| 138 .callMethod("catch", [(result) => completer.completeError(result)]); | 137 "catch", [js.allowInterop((result) => completer.completeError(result))]); |
| 139 return completer.future; | 138 return completer.future; |
| 140 } | 139 } |
| 141 | 140 |
| 142 convertDartToNative_DateTime(DateTime date) { | 141 convertDartToNative_DateTime(DateTime date) { |
| 143 return new js.JsObject(js.context["Date"], [date.millisecondsSinceEpoch]); | 142 return date; |
| 144 } | 143 } |
| 145 | 144 |
| 146 /// Creates a Dart Rectangle from a Javascript object with properties | 145 /// Creates a Dart Rectangle from a Javascript object with properties |
| 147 /// left, top, width and height. Used internally in Dartium. | 146 /// left, top, width and height or a 4 element array of integers. Used internall
y in Dartium. |
| 148 Rectangle make_dart_rectangle(r) => | 147 Rectangle make_dart_rectangle(r) { |
| 149 r == null ? null : new Rectangle( | 148 if (r == null) return null; |
| 150 js.JsNative.getProperty(r, 'left'), | 149 if (r is List) { |
| 151 js.JsNative.getProperty(r, 'top'), | 150 return new Rectangle(r[0], r[1], r[2], r[3]); |
| 152 js.JsNative.getProperty(r, 'width'), | 151 } |
| 153 js.JsNative.getProperty(r, 'height')); | 152 |
| 153 return new Rectangle( |
| 154 js.JsNative.getProperty(r, 'left'), |
| 155 js.JsNative.getProperty(r, 'top'), |
| 156 js.JsNative.getProperty(r, 'width'), |
| 157 js.JsNative.getProperty(r, 'height')); |
| 158 } |
| 154 | 159 |
| 155 // Converts a flat Dart map into a JavaScript object with properties this is | 160 // Converts a flat Dart map into a JavaScript object with properties this is |
| 156 // is the Dartium only version it uses dart:js. | 161 // is the Dartium only version it uses dart:js. |
| 157 // TODO(alanknight): This could probably be unified with the dart2js conversions | 162 // TODO(alanknight): This could probably be unified with the dart2js conversions |
| 158 // code in html_common and be more general. | 163 // code in html_common and be more general. |
| 159 convertDartToNative_Dictionary(Map dict) { | 164 convertDartToNative_Dictionary(Map dict) { |
| 160 if (dict == null) return null; | 165 if (dict == null) return null; |
| 161 var jsObject = new js.JsObject(js.JsNative.getProperty(js.context, 'Object')); | 166 var jsObject = js.JsNative.newObject(); |
| 162 dict.forEach((String key, value) { | 167 dict.forEach((String key, value) { |
| 163 if (value is List) { | 168 if (value is List) { |
| 164 var jsArray = new js.JsArray(); | 169 var jsArray = js.JsNative.newArray(); |
| 165 value.forEach((elem) { | 170 value.forEach((elem) { |
| 166 jsArray.add(elem is Map ? convertDartToNative_Dictionary(elem): elem); | 171 jsArray.add(elem is Map ? convertDartToNative_Dictionary(elem): elem); |
| 167 }); | 172 }); |
| 168 jsObject[key] = jsArray; | 173 js.JsNative.setProperty(jsObject, key, jsArray); |
| 169 } else { | 174 } else { |
| 170 jsObject[key] = value; | 175 js.JsNative.setProperty(jsObject, key, value); |
| 171 } | 176 } |
| 172 }); | 177 }); |
| 173 return jsObject; | 178 return jsObject; |
| 174 } | 179 } |
| 175 | 180 |
| 176 // Creates a Dart class to allow members of the Map to be fetched (as if getters
exist). | 181 // Creates a Dart class to allow members of the Map to be fetched (as if getters
exist). |
| 177 // TODO(terry): Need to use package:js but that's a problem in dart:html. Talk t
o | 182 // TODO(terry): Need to use package:js but that's a problem in dart:html. Talk t
o |
| 178 // Jacob about how to do this properly using dart:js. | 183 // Jacob about how to do this properly using dart:js. |
| 179 class _ReturnedDictionary { | 184 class _ReturnedDictionary { |
| 180 Map _values; | 185 Map _values; |
| 181 | 186 |
| 182 noSuchMethod(Invocation invocation) { | 187 noSuchMethod(Invocation invocation) { |
| 183 var key = MirrorSystem.getName(invocation.memberName); | 188 var key = MirrorSystem.getName(invocation.memberName); |
| 184 if (invocation.isGetter) { | 189 if (invocation.isGetter) { |
| 185 return _values[key]; | 190 return _values[key]; |
| 186 } else if (invocation.isSetter && key.endsWith('=')) { | 191 } else if (invocation.isSetter && key.endsWith('=')) { |
| 187 key = key.substring(0, key.length-1); | 192 key = key.substring(0, key.length-1); |
| 188 _values[key] = invocation.positionalArguments[0]; | 193 _values[key] = invocation.positionalArguments[0]; |
| 189 } | 194 } |
| 190 } | 195 } |
| 191 | 196 |
| 192 Map get toMap => _values; | 197 Map get toMap => _values; |
| 193 | 198 |
| 194 _ReturnedDictionary(Map value): _values = value != null ? value : {}; | 199 _ReturnedDictionary(Map value): _values = value != null ? value : {}; |
| 195 } | 200 } |
| 196 | 201 |
| 197 // Helper function to wrapped a returned dictionary from blink to a Dart looking | 202 // Helper function to wrapped a returned dictionary from blink to a Dart looking |
| 198 // class. | 203 // class. |
| 199 convertNativeDictionaryToDartDictionary(Map values) => | 204 convertNativeDictionaryToDartDictionary(values) { |
| 200 values != null ? new _ReturnedDictionary(values) : null; | 205 if (values is! Map) { |
| 206 // TODO(jacobr): wish wwe didn't have to do this. |
| 207 values = convertNativeToDart_SerializedScriptValue(values); |
| 208 } |
| 209 return values != null ? new _ReturnedDictionary(values) : null; |
| 210 } |
| 211 |
| 212 convertNativeToDart_Dictionary(values) => convertNativeToDart_SerializedScriptVa
lue(values); |
| 201 | 213 |
| 202 // Conversion function place holder (currently not used in dart2js or dartium). | 214 // Conversion function place holder (currently not used in dart2js or dartium). |
| 203 List convertDartToNative_StringArray(List<String> input) => input; | 215 List convertDartToNative_StringArray(List<String> input) => input; |
| 204 | 216 |
| 205 // Converts a Dart list into a JsArray. For the Dartium version only. | 217 // Converts a Dart list into a JsArray. For the Dartium version only. |
| 206 convertDartToNative_List(List input) => new js.JsArray()..addAll(input); | 218 convertDartToNative_List(List input) => new js.JsArray()..addAll(input); |
| 207 | 219 |
| 208 /// Find the underlying JS object for a dart:html Dart object. | 220 // Incredibly slow implementation to lookup the runtime type for an object. |
| 209 unwrap_jso(dartClass_instance) => js.unwrap_jso(dartClass_instance); | 221 // Fortunately, performance doesn't matter much as the results are cached |
| 210 | 222 // 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 | 223 // TODO(jacobr): we should track the # of lookups to ensure that things aren't |
| 212 // wrap_jso calls. | 224 // going off the rails due to objects with null prototypes, etc. |
| 213 bool interop_checks = false; | 225 // Note: unlike all other methods in this class, here we intentionally use |
| 214 | 226 // the old JsObject types to bootstrap the new typed bindings. |
| 215 /// Wrap a JS object with an instance of the matching dart:html class. Used only
in Dartium. | 227 Type lookupType(js.JsObject jsObject, bool isElement) { |
| 216 wrap_jso(jsObject) { | |
| 217 try { | 228 try { |
| 218 if (jsObject is! js.JsObject || jsObject == null) { | 229 // 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. | 230 // class so that this code works as expected. |
| 220 // or it's a simple type. | 231 if (jsObject is js.JsArray) { |
| 221 return jsObject; | 232 return js.JSArray.instanceRuntimeType; |
| 222 } | 233 } |
| 223 | 234 if (jsObject is js.JsFunction) { |
| 224 var wrapper = js.getDartHtmlWrapperFor(jsObject); | 235 return js.JSFunction.instanceRuntimeType; |
| 225 // if we have a wrapper return the Dart instance. | 236 } |
| 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 | 237 |
| 250 var constructor = js.JsNative.getProperty(jsObject, 'constructor'); | 238 var constructor = js.JsNative.getProperty(jsObject, 'constructor'); |
| 251 if (constructor == null) { | 239 if (constructor == null) { |
| 252 // Perfectly valid case for JavaScript objects where __proto__ has | 240 // Perfectly valid case for JavaScript objects where __proto__ has |
| 253 // intentionally been set to null. | 241 // intentionally been set to null. |
| 254 js.setDartHtmlWrapperFor(jsObject, new js.JSObject.create(jsObject)); | 242 // We should track and warn about this case as peformance will be poor. |
| 255 return jsObject; | 243 return js.JSObject.instanceRuntimeType; |
| 256 } | 244 } |
| 257 var jsTypeName = js.JsNative.getProperty(constructor, 'name'); | 245 var jsTypeName = js.JsNative.getProperty(constructor, 'name'); |
| 258 if (jsTypeName is! String || jsTypeName.length == 0) { | 246 if (jsTypeName is! String || jsTypeName.length == 0) { |
| 259 // Not an html type. | 247 // Not an html type. |
| 260 wrapper = new js.JSObject.create(jsObject); | 248 return js.JSObject.instanceRuntimeType; |
| 261 js.setDartHtmlWrapperFor(jsObject, wrapper); | |
| 262 return wrapper; | |
| 263 } | 249 } |
| 264 | 250 |
| 265 var dartClass_instance; | 251 var dartClass_instance; |
| 266 var customElementClass = null; | 252 var customElementClass = null; |
| 267 var extendsTag = ""; | 253 var extendsTag = ""; |
| 268 var custom = getCustomElementEntry(jsObject); | 254 |
| 269 if (custom != null) { | 255 Type type = getHtmlCreateType(jsTypeName); |
| 270 customElementClass = custom['type']; | 256 if (type != null) return type; |
| 271 extendsTag = custom['extends']; | 257 |
| 258 // Start walking the prototype chain looking for a JS class. |
| 259 var prototype = js.JsNative.getProperty(jsObject, '__proto__'); |
| 260 while (prototype != null) { |
| 261 // We're a Dart class that's pointing to a JS class. |
| 262 var constructor = js.JsNative.getProperty(prototype, 'constructor'); |
| 263 if (constructor != null) { |
| 264 jsTypeName = js.JsNative.getProperty(constructor, 'name'); |
| 265 type = getHtmlCreateType(jsTypeName); |
| 266 if (type != null) return type; |
| 267 } |
| 268 prototype = js.JsNative.getProperty(prototype, '__proto__'); |
| 272 } | 269 } |
| 273 | |
| 274 // Only allow custom elements to be created in the html or svg default | |
| 275 // namespace. | |
| 276 var func; | |
| 277 var defaultNS = jsObject['namespaceURI'] == 'http://www.w3.org/1999/xhtml' |
| | |
| 278 jsObject['namespaceURI'] == 'http://www.w3.org/2000/svg'; | |
| 279 if (customElementClass != null && extendsTag == "" && defaultNS) { | |
| 280 // 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 | |
| 282 // createdCallback is called. | |
| 283 func = getHtmlCreateFunction('HTMLElement'); | |
| 284 } else { | |
| 285 func = getHtmlCreateFunction(jsTypeName); | |
| 286 if (func == null) { | |
| 287 // Start walking the prototype chain looking for a JS class. | |
| 288 var prototype = jsObject['__proto__']; | |
| 289 var keepWalking = true; | |
| 290 while (keepWalking && prototype.hasProperty('__proto__')) { | |
| 291 prototype = prototype['__proto__']; | |
| 292 if (prototype != null && prototype is Element && | |
| 293 prototype.blink_jsObject != null) { | |
| 294 // We're a Dart class that's pointing to a JS class. | |
| 295 var blinkJso = prototype.blink_jsObject; | |
| 296 jsTypeName = blinkJso['constructor']['name']; | |
| 297 func = getHtmlCreateFunction(jsTypeName); | |
| 298 keepWalking = func == null; | |
| 299 } | |
| 300 } | |
| 301 } | |
| 302 } | |
| 303 | |
| 304 // Can we construct a Dart class? | |
| 305 if (func != null) { | |
| 306 dartClass_instance = func(); | |
| 307 | |
| 308 // Wrap our Dart instance in both directions. | |
| 309 dartClass_instance.blink_jsObject = jsObject; | |
| 310 js.setDartHtmlWrapperFor(jsObject, dartClass_instance); | |
| 311 } | |
| 312 | |
| 313 // TODO(jacobr): cache that this is not a dart:html JS class. | |
| 314 return dartClass_instance; | |
| 315 } catch (e, stacktrace) { | 270 } catch (e, stacktrace) { |
| 316 if (interop_checks) { | 271 if (e is DebugAssertException) print("${e.message}\n ${stacktrace}"); |
| 317 if (e is DebugAssertException) window.console | 272 else print("${stacktrace}"); |
| 318 .log("${e.message}\n ${stacktrace}"); | |
| 319 else window.console.log("${stacktrace}"); | |
| 320 } | |
| 321 } | 273 } |
| 322 | 274 return js.JSObject.instanceRuntimeType; |
| 323 return null; | |
| 324 } | 275 } |
| 325 | |
| 326 /** | |
| 327 * Create Dart class that maps to the JS Type, add the JsObject as an expando | |
| 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 | |
| 338 // TODO(alanknight): With upgraded custom elements this causes a failure bec
ause | |
| 339 // we need a new wrapper after the type changes. We could possibly invalidat
e this | |
| 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 } | |
| 473 | |
| 474 // List of known tagName to DartClass for custom elements, used for upgrade. | |
| 475 var _knownCustomElements = new Map<String, Map<Type, String>>(); | |
| 476 | |
| 477 void addCustomElementType(String tagName, Type dartClass, [String extendTag]) { | |
| 478 _knownCustomElements[tagName] = | |
| 479 {'type': dartClass, 'extends': extendTag != null ? extendTag : "" }; | |
| 480 } | |
| 481 | |
| 482 Type getCustomElementType(object) { | |
| 483 var entry = getCustomElementEntry(object); | |
| 484 if (entry != null) { | |
| 485 return entry['type']; | |
| 486 } | |
| 487 return null; | |
| 488 } | |
| OLD | NEW |