| Index: sdk/lib/js_util/dart2js/js_util_dart2js.dart
|
| diff --git a/sdk/lib/js_util/dart2js/js_util_dart2js.dart b/sdk/lib/js_util/dart2js/js_util_dart2js.dart
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..da9b3677956241e292fa4ba03b404fb4b2f93159
|
| --- /dev/null
|
| +++ b/sdk/lib/js_util/dart2js/js_util_dart2js.dart
|
| @@ -0,0 +1,126 @@
|
| +// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
|
| +// for details. All rights reserved. Use of this source code is governed by a
|
| +// BSD-style license that can be found in the LICENSE file.
|
| +
|
| +/// Utility methods to efficiently manipulate typed JSInterop objects in cases
|
| +/// where the name to call is not known at runtime. You should only use these
|
| +/// methods when the same effect cannot be achieved with @JS annotations.
|
| +/// These methods would be extension methods on JSObject if Dart supported
|
| +/// extension methods.
|
| +library dart.js_util;
|
| +
|
| +import 'dart:_foreign_helper' show JS;
|
| +import 'dart:collection' show HashMap;
|
| +
|
| +/// WARNING: performance of this method is much worse than other uitil
|
| +/// methods in this library. Only use this method as a last resort.
|
| +///
|
| +/// Recursively converts a JSON-like collection of Dart objects to a
|
| +/// collection of JavaScript objects and returns a [JsObject] proxy to it.
|
| +///
|
| +/// [object] must be a [Map] or [Iterable], the contents of which are also
|
| +/// converted. Maps and Iterables are copied to a new JavaScript object.
|
| +/// Primitives and other transferrable values are directly converted to their
|
| +/// JavaScript type, and all other objects are proxied.
|
| +jsify(object) {
|
| + if ((object is! Map) && (object is! Iterable)) {
|
| + throw new ArgumentError("object must be a Map or Iterable");
|
| + }
|
| + return _convertDataTree(object);
|
| +}
|
| +
|
| +_convertDataTree(data) {
|
| + var _convertedObjects = new HashMap.identity();
|
| +
|
| + _convert(o) {
|
| + if (_convertedObjects.containsKey(o)) {
|
| + return _convertedObjects[o];
|
| + }
|
| + if (o is Map) {
|
| + final convertedMap = JS('=Object', '{}');
|
| + _convertedObjects[o] = convertedMap;
|
| + for (var key in o.keys) {
|
| + JS('=Object', '#[#]=#', convertedMap, key, _convert(o[key]));
|
| + }
|
| + return convertedMap;
|
| + } else if (o is Iterable) {
|
| + var convertedList = [];
|
| + _convertedObjects[o] = convertedList;
|
| + convertedList.addAll(o.map(_convert));
|
| + return convertedList;
|
| + } else {
|
| + return o;
|
| + }
|
| + }
|
| +
|
| + return _convert(data);
|
| +}
|
| +
|
| +JSObject newObject() => JS('=Object', '{}');
|
| +
|
| +hasProperty(o, name) => JS('bool', '# in #', name, o);
|
| +getProperty(o, name) => JS('Object', '#[#]', o, name);
|
| +setProperty(o, name, value) => JS('', '#[#]=#', o, name, value);
|
| +
|
| +callMethod(o, String method, List args) =>
|
| + JS('Object', '#[#].apply(#, #)', o, method, o, args);
|
| +
|
| +instanceof(o, Function type) => JS('bool', '# instanceof #', o, type);
|
| +callConstructor(Function constr, List arguments) {
|
| + if (arguments == null) {
|
| + return JS('Object', 'new #()', constr);
|
| + }
|
| +
|
| + if (JS('bool', '# instanceof Array', arguments)) {
|
| + int argumentCount = JS('int', '#.length', arguments);
|
| + switch (argumentCount) {
|
| + case 0:
|
| + return JS('Object', 'new #()', constr);
|
| +
|
| + case 1:
|
| + var arg0 = JS('', '#[0]', arguments);
|
| + return JS('Object', 'new #(#)', constr, arg0);
|
| +
|
| + case 2:
|
| + var arg0 = JS('', '#[0]', arguments);
|
| + var arg1 = JS('', '#[1]', arguments);
|
| + return JS('Object', 'new #(#, #)', constr, arg0, arg1);
|
| +
|
| + case 3:
|
| + var arg0 = JS('', '#[0]', arguments);
|
| + var arg1 = JS('', '#[1]', arguments);
|
| + var arg2 = JS('', '#[2]', arguments);
|
| + return JS('Object', 'new #(#, #, #)', constr, arg0, arg1, arg2);
|
| +
|
| + case 4:
|
| + var arg0 = JS('', '#[0]', arguments);
|
| + var arg1 = JS('', '#[1]', arguments);
|
| + var arg2 = JS('', '#[2]', arguments);
|
| + var arg3 = JS('', '#[3]', arguments);
|
| + return JS(
|
| + 'Object', 'new #(#, #, #, #)', constr, arg0, arg1, arg2, arg3);
|
| + }
|
| + }
|
| +
|
| + // The following code solves the problem of invoking a JavaScript
|
| + // constructor with an unknown number arguments.
|
| + // First bind the constructor to the argument list using bind.apply().
|
| + // The first argument to bind() is the binding of 't', so add 'null' to
|
| + // the arguments list passed to apply().
|
| + // After that, use the JavaScript 'new' operator which overrides any binding
|
| + // of 'this' with the new instance.
|
| + var args = [null]..addAll(arguments);
|
| + var factoryFunction = JS('', '#.bind.apply(#, #)', constr, constr, args);
|
| + // Without this line, calling factoryFunction as a constructor throws
|
| + JS('String', 'String(#)', factoryFunction);
|
| + // This could return an UnknownJavaScriptObject, or a native
|
| + // object for which there is an interceptor
|
| + return JS('Object', 'new #()', factoryFunction);
|
| +
|
| + // TODO(sra): Investigate:
|
| + //
|
| + // var jsObj = JS('', 'Object.create(#.prototype)', constr);
|
| + // JS('', '#.apply(#, #)', constr, jsObj,
|
| + // []..addAll(arguments.map(_convertToJS)));
|
| + // return _wrapToDart(jsObj);
|
| +}
|
|
|