Index: sdk/lib/js/dart2js/js_dart2js.dart |
diff --git a/sdk/lib/js/dart2js/js_dart2js.dart b/sdk/lib/js/dart2js/js_dart2js.dart |
index 3fb3756565b34dfb2a1e6c5adac3e58bf0f53d6a..c2325be41ee3113ead3bffbc44567e21a2f474ad 100644 |
--- a/sdk/lib/js/dart2js/js_dart2js.dart |
+++ b/sdk/lib/js/dart2js/js_dart2js.dart |
@@ -4,50 +4,13 @@ |
library dart.js; |
+import 'dart:collection' show HashMap; |
import 'dart:_foreign_helper' show JS, DART_CLOSURE_TO_JS; |
+import 'dart:_interceptors' show JavaScriptObject, UnknownJavaScriptObject; |
import 'dart:_js_helper' show Primitives, convertDartClosureToJS; |
final JsObject context = new JsObject._fromJs(Primitives.computeGlobalThis()); |
-JsObject jsify(dynamic data) => data == null ? null : new JsObject._json(data); |
- |
-class Callback implements Serializable<JsFunction> { |
- final Function _f; // here to allow capture in closure |
- final bool _withThis; // here to allow capture in closure |
- dynamic _jsFunction; |
- |
- Callback._(this._f, this._withThis) { |
- _jsFunction = JS('', r''' |
-(function(){ |
- var f = #; |
- return function(){ |
- return f(this, Array.prototype.slice.apply(arguments)); |
- }; |
-}).apply(this)''', convertDartClosureToJS(_call, 2)); |
- } |
- |
- factory Callback(Function f) => new Callback._(f, false); |
- factory Callback.withThis(Function f) => new Callback._(f, true); |
- |
- _call(thisArg, List args) { |
- final arguments = new List.from(args); |
- if (_withThis) arguments.insert(0, thisArg); |
- final dartArgs = arguments.map(_convertToDart).toList(); |
- return _convertToJS(Function.apply(_f, dartArgs)); |
- } |
- |
- JsFunction toJs() => new JsFunction._fromJs(_jsFunction); |
-} |
- |
-/* |
- * TODO(justinfagnani): add tests and make public when we remove Callback. |
- * |
- * Returns a [JsFunction] that captures its 'this' binding and calls [f] |
- * with the value of this passed as the first argument. |
- */ |
-JsFunction _captureThis(Function f) => |
- new JsFunction._fromJs(_convertDartFunction(f, captureThis: true)); |
- |
_convertDartFunction(Function f, {bool captureThis: false}) { |
return JS('', |
'function(_call, f, captureThis) {' |
@@ -72,10 +35,37 @@ class JsObject implements Serializable<JsObject> { |
final dynamic _jsObject; |
JsObject._fromJs(this._jsObject) { |
+ assert(_jsObject != null); |
// Remember this proxy for the JS object |
_getDartProxy(_jsObject, _DART_OBJECT_PROPERTY_NAME, (o) => this); |
} |
+ /** |
+ * Expert users only: |
+ * Use this constructor only if you wish to get access to JS expandos |
+ * attached to a WebKit native object such as a Node. |
+ * An exception will be thrown if a primitive type is passed in passing one |
+ * of these types to this method indicates an error. |
+ */ |
+ factory JsObject.fromDartObject(Object object) { |
alexandre.ardhuin
2013/10/16 19:32:11
Rename to `fromBrowserObject`.
justinfagnani
2013/10/18 03:19:08
Done.
|
+ if (object is num || object is String || object is bool || object == null) { |
+ throw new IllegalArgumentException( |
+ "object cannot be a num, string, bool, or null"); |
+ } |
+ return new JsObject._fromJs(_convertToJS(object)); |
+ } |
+ |
+ /** |
+ * Converts a json-like [data] to a JavaScript map or array and return a |
+ * [JsObject] to it. |
+ */ |
+ factory JsObject.jsify(Object object) { |
+ if ((object is! Map) && (object is! Iterable)) { |
+ throw new IllegalArgumentException("object must be a Map or Iterable"); |
+ } |
+ return new JsObject._fromJs(_convertDataTree(object)); |
+ } |
+ |
// TODO(vsm): Type constructor as Serializable<JsFunction> when |
// dartbug.com/11854 is fixed. |
factory JsObject(constructor, [List arguments]) { |
@@ -94,24 +84,41 @@ class JsObject implements Serializable<JsObject> { |
var factoryFunction = JS('', '#.bind.apply(#, #)', constr, constr, args); |
// Without this line, calling factoryFunction as a constructor throws |
JS('String', 'String(#)', factoryFunction); |
- return new JsObject._fromJs(JS('', 'new #()', factoryFunction)); |
+ // This could return an UnknownJavaScriptObject, or a native |
+ // object for which there is an interceptor |
+ var jsObj = JS('JavaScriptObject', 'new #()', factoryFunction); |
+ // print("UnknownJavaScriptObject: ${jsObj is UnknownJavaScriptObject}"); |
alexandre.ardhuin
2013/10/16 19:32:11
Remove these comments ?
justinfagnani
2013/10/18 03:19:08
Done.
|
+ // print("JavaScriptObject: ${jsObj is JavaScriptObject}"); |
+ // JS('void', 'console.log("jsObj: " + #)', jsObj); |
+ return new JsObject._fromJs(jsObj); |
} |
- factory JsObject._json(data) => new JsObject._fromJs(_convertDataTree(data)); |
- |
+ // TODO: handle cycles |
static _convertDataTree(data) { |
- if (data is Map) { |
- final convertedData = JS('=Object', '{}'); |
- for (var key in data.keys) { |
- JS('=Object', '#[#]=#', convertedData, key, |
- _convertDataTree(data[key])); |
+ 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 _convertToJS(o); |
} |
- return convertedData; |
- } else if (data is Iterable) { |
- return data.map(_convertDataTree).toList(); |
- } else { |
- return _convertToJS(data); |
} |
+ |
+ return _convert(data); |
} |
JsObject toJs() => this; |
@@ -188,6 +195,15 @@ class JsObject implements Serializable<JsObject> { |
class JsFunction extends JsObject implements Serializable<JsFunction> { |
+ /* |
+ * Returns a [JsFunction] that captures its 'this' binding and calls [f] |
+ * with the value of this passed as the first argument. |
+ */ |
+ factory JsFunction.withThis(Function f) { |
+ var jsFunc = _convertDartFunction(f, captureThis: true); |
+ return new JsFunction._fromJs(jsFunc); |
+ } |
+ |
JsFunction._fromJs(jsObject) : super._fromJs(jsObject); |
dynamic apply(thisArg, [List args]) => |