| part of html_common; |
| |
| /// Converts native values to their Dart equivalent |
| /// |
| /// This includes other maps, lists, or values that don't need a conversion e.g. |
| /// bool, String. |
| _convertNativeToDart_Value(value) { |
| if (value == null) return value; |
| if (value is String || value is num || value is bool) return value; |
| if (isJavaScriptSimpleObject(value)) { |
| return convertNativeToDart_Dictionary(value); |
| } |
| if (JS('bool', 'Array.isArray(#)', value)) { |
| List values = []; |
| for (var i = 0; i < JS<int>('int', '#.length', value); i++) { |
| values.add(_convertNativeToDart_Value(JS('var', '#[#]', value, i))); |
| } |
| |
| return values; |
| } |
| return value; |
| } |
| |
| /// Recursively converts a JavaScript object with properties into a Dart Map. |
| /// This includes maps, lists, and other values that don't need a conversion. |
| Map<String, dynamic>? convertNativeToDart_Dictionary(object) { |
| if (object == null) return null; |
| var dict = <String, dynamic>{}; |
| var keys = JS<JSExtendableArray>( |
| 'JSExtendableArray', 'Object.getOwnPropertyNames(#)', object); |
| for (final key in keys) { |
| dict[JS('String', '#', key)] = |
| _convertNativeToDart_Value(JS('var', '#[#]', object, key)); |
| } |
| return dict; |
| } |
| |
| /// Converts values that occur within a Dart map for map conversion. |
| /// |
| /// This includes other maps, lists, or values that don't need a conversion e.g. |
| /// bool, String. |
| _convertDartToNative_Value(Object? value) { |
| if (value == null) return value; |
| if (value is String || value is num || value is bool) return value; |
| if (value is Map) return convertDartToNative_Dictionary(value); |
| if (value is List) { |
| var array = JS('var', '[]'); |
| value.forEach((element) { |
| JS('void', '#.push(#)', array, _convertDartToNative_Value(element)); |
| }); |
| value = array; |
| } |
| return value; |
| } |
| |
| /// Converts a potentially nested Dart map to a JavaScript object with |
| /// properties. |
| /// |
| /// This method requires that the values within the map are either maps |
| /// themselves, lists, or do not need a conversion. |
| convertDartToNative_Dictionary(Map? dict, [void postCreate(Object? f)?]) { |
| if (dict == null) return null; |
| var object = JS('var', '{}'); |
| if (postCreate != null) { |
| postCreate(object); |
| } |
| dict.forEach((key, value) { |
| JS('void', '#[#] = #', object, key, _convertDartToNative_Value(value)); |
| }); |
| return object; |
| } |
| |
| /** |
| * Ensures that the input is a JavaScript Array. |
| * |
| * Creates a new JavaScript array if necessary, otherwise returns the original. |
| */ |
| List convertDartToNative_StringArray(List<String> input) { |
| // TODO(sra). Implement this. |
| return input; |
| } |
| |
| DateTime convertNativeToDart_DateTime(date) { |
| int millisSinceEpoch = JS('int', '#.getTime()', date); |
| return new DateTime.fromMillisecondsSinceEpoch(millisSinceEpoch, isUtc: true); |
| } |
| |
| convertDartToNative_DateTime(DateTime date) { |
| return JS('', 'new Date(#)', date.millisecondsSinceEpoch); |
| } |
| |
| convertDartToNative_PrepareForStructuredClone(value) => |
| new _StructuredCloneDart2Js() |
| .convertDartToNative_PrepareForStructuredClone(value); |
| |
| convertNativeToDart_AcceptStructuredClone(object, {mustCopy: false}) => |
| new _AcceptStructuredCloneDart2Js() |
| .convertNativeToDart_AcceptStructuredClone(object, mustCopy: mustCopy); |
| |
| class _StructuredCloneDart2Js extends _StructuredClone { |
| JSObject newJsObject() => JS('JSObject', '{}'); |
| |
| void forEachObjectKey(object, action(key, value)) { |
| for (final key |
| in JS('returns:JSExtendableArray;new:true', 'Object.keys(#)', object)) { |
| action(key, JS('var', '#[#]', object, key)); |
| } |
| } |
| |
| void putIntoObject(object, key, value) => |
| JS('void', '#[#] = #', object, key, value); |
| |
| newJsMap() => JS('var', '{}'); |
| putIntoMap(map, key, value) => JS('void', '#[#] = #', map, key, value); |
| newJsList(length) => JS('JSExtendableArray', 'new Array(#)', length); |
| cloneNotRequired(e) => |
| (e is NativeByteBuffer || e is NativeTypedData || e is MessagePort); |
| } |
| |
| class _AcceptStructuredCloneDart2Js extends _AcceptStructuredClone { |
| List newJsList(length) => JS('JSExtendableArray', 'new Array(#)', length); |
| List newDartList(length) => newJsList(length); |
| bool identicalInJs(a, b) => identical(a, b); |
| |
| void forEachJsField(object, action(key, value)) { |
| for (final key in JS('JSExtendableArray', 'Object.keys(#)', object)) { |
| action(key, JS('var', '#[#]', object, key)); |
| } |
| } |
| } |
| |
| bool isJavaScriptDate(value) => JS('bool', '# instanceof Date', value); |
| bool isJavaScriptRegExp(value) => JS('bool', '# instanceof RegExp', value); |
| bool isJavaScriptArray(value) => JS('bool', '# instanceof Array', value); |
| bool isJavaScriptSimpleObject(value) { |
| var proto = JS('', 'Object.getPrototypeOf(#)', value); |
| return JS('bool', '# === Object.prototype', proto) || |
| JS('bool', '# === null', proto); |
| } |
| |
| bool isImmutableJavaScriptArray(value) => |
| JS('bool', r'!!(#.immutable$list)', value); |
| bool isJavaScriptPromise(value) => |
| JS('bool', r'typeof Promise != "undefined" && # instanceof Promise', value); |
| |
| const String _serializedScriptValue = 'num|String|bool|' |
| 'JSExtendableArray|=Object|' |
| 'Blob|File|NativeByteBuffer|NativeTypedData|MessagePort' |
| // TODO(sra): Add Date, RegExp. |
| ; |
| const annotation_Creates_SerializedScriptValue = |
| const Creates(_serializedScriptValue); |
| const annotation_Returns_SerializedScriptValue = |
| const Returns(_serializedScriptValue); |