| OLD | NEW |
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 /** | 5 /** |
| 6 * Support for interoperating with JavaScript. | 6 * Support for interoperating with JavaScript. |
| 7 * | 7 * |
| 8 * This library provides access to JavaScript objects from Dart, allowing | 8 * This library provides access to JavaScript objects from Dart, allowing |
| 9 * Dart code to get and set properties, and call methods of JavaScript objects | 9 * Dart code to get and set properties, and call methods of JavaScript objects |
| 10 * and invoke JavaScript functions. The library takes care of converting | 10 * and invoke JavaScript functions. The library takes care of converting |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 77 * | 77 * |
| 78 * var jsMap = new JsObject.jsify({'a': 1, 'b': 2}); | 78 * var jsMap = new JsObject.jsify({'a': 1, 'b': 2}); |
| 79 * | 79 * |
| 80 * This expression creates a JavaScript array: | 80 * This expression creates a JavaScript array: |
| 81 * | 81 * |
| 82 * var jsArray = new JsObject.jsify([1, 2, 3]); | 82 * var jsArray = new JsObject.jsify([1, 2, 3]); |
| 83 */ | 83 */ |
| 84 library dart.js; | 84 library dart.js; |
| 85 | 85 |
| 86 import 'dart:html' show Blob, ImageData, Node; | 86 import 'dart:html' show Blob, ImageData, Node; |
| 87 import 'dart:collection' show HashMap; | 87 import 'dart:collection' show HashMap, ListMixin; |
| 88 import 'dart:indexed_db' show KeyRange; | 88 import 'dart:indexed_db' show KeyRange; |
| 89 import 'dart:typed_data' show TypedData; | 89 import 'dart:typed_data' show TypedData; |
| 90 | 90 |
| 91 import 'dart:_foreign_helper' show JS, DART_CLOSURE_TO_JS; | 91 import 'dart:_foreign_helper' show JS, DART_CLOSURE_TO_JS; |
| 92 import 'dart:_interceptors' show JavaScriptObject, UnknownJavaScriptObject; | 92 import 'dart:_interceptors' show JavaScriptObject, UnknownJavaScriptObject; |
| 93 import 'dart:_js_helper' show Primitives, convertDartClosureToJS; | 93 import 'dart:_js_helper' show Primitives, convertDartClosureToJS; |
| 94 | 94 |
| 95 final JsObject context = new JsObject._fromJs(Primitives.computeGlobalThis()); | 95 final JsObject context = _wrapToDart(Primitives.computeGlobalThis()); |
| 96 | 96 |
| 97 _convertDartFunction(Function f, {bool captureThis: false}) { | 97 _convertDartFunction(Function f, {bool captureThis: false}) { |
| 98 return JS('', | 98 return JS('', |
| 99 'function(_call, f, captureThis) {' | 99 'function(_call, f, captureThis) {' |
| 100 'return function() {' | 100 'return function() {' |
| 101 'return _call(f, captureThis, this, ' | 101 'return _call(f, captureThis, this, ' |
| 102 'Array.prototype.slice.apply(arguments));' | 102 'Array.prototype.slice.apply(arguments));' |
| 103 '}' | 103 '}' |
| 104 '}(#, #, #)', DART_CLOSURE_TO_JS(_callDartFunction), f, captureThis); | 104 '}(#, #, #)', DART_CLOSURE_TO_JS(_callDartFunction), f, captureThis); |
| 105 } | 105 } |
| 106 | 106 |
| 107 _callDartFunction(callback, bool captureThis, self, List arguments) { | 107 _callDartFunction(callback, bool captureThis, self, List arguments) { |
| 108 if (captureThis) { | 108 if (captureThis) { |
| 109 arguments = [self]..addAll(arguments); | 109 arguments = [self]..addAll(arguments); |
| 110 } | 110 } |
| 111 var dartArgs = arguments.map(_convertToDart).toList(); | 111 var dartArgs = new List.from(arguments.map(_convertToDart)); |
| 112 return _convertToJS(Function.apply(callback, dartArgs)); | 112 return _convertToJS(Function.apply(callback, dartArgs)); |
| 113 } | 113 } |
| 114 | 114 |
| 115 /** | 115 /** |
| 116 * Proxies a JavaScript object to Dart. | 116 * Proxies a JavaScript object to Dart. |
| 117 * | 117 * |
| 118 * The properties of the JavaScript object are accessible via the `[]` and | 118 * The properties of the JavaScript object are accessible via the `[]` and |
| 119 * `[]=` operators. Methods are callable via [callMethod]. | 119 * `[]=` operators. Methods are callable via [callMethod]. |
| 120 */ | 120 */ |
| 121 class JsObject { | 121 class JsObject { |
| 122 // The wrapped JS object. | 122 // The wrapped JS object. |
| 123 final dynamic _jsObject; | 123 final dynamic _jsObject; |
| 124 | 124 |
| 125 // This shoud only be called from _wrapToDart |
| 125 JsObject._fromJs(this._jsObject) { | 126 JsObject._fromJs(this._jsObject) { |
| 126 assert(_jsObject != null); | 127 assert(_jsObject != null); |
| 127 // Remember this proxy for the JS object | |
| 128 _getDartProxy(_jsObject, _DART_OBJECT_PROPERTY_NAME, (o) => this); | |
| 129 } | 128 } |
| 130 | 129 |
| 131 /** | 130 /** |
| 132 * Constructs a new JavaScript object from [constructor] and returns a proxy | 131 * Constructs a new JavaScript object from [constructor] and returns a proxy |
| 133 * to it. | 132 * to it. |
| 134 */ | 133 */ |
| 135 factory JsObject(JsFunction constructor, [List arguments]) { | 134 factory JsObject(JsFunction constructor, [List arguments]) { |
| 136 var constr = _convertToJS(constructor); | 135 var constr = _convertToJS(constructor); |
| 137 if (arguments == null) { | 136 if (arguments == null) { |
| 138 return new JsObject._fromJs(JS('', 'new #()', constr)); | 137 return _wrapToDart(JS('', 'new #()', constr)); |
| 139 } | 138 } |
| 140 // The following code solves the problem of invoking a JavaScript | 139 // The following code solves the problem of invoking a JavaScript |
| 141 // constructor with an unknown number arguments. | 140 // constructor with an unknown number arguments. |
| 142 // First bind the constructor to the argument list using bind.apply(). | 141 // First bind the constructor to the argument list using bind.apply(). |
| 143 // The first argument to bind() is the binding of 'this', so add 'null' to | 142 // The first argument to bind() is the binding of 'this', so add 'null' to |
| 144 // the arguments list passed to apply(). | 143 // the arguments list passed to apply(). |
| 145 // After that, use the JavaScript 'new' operator which overrides any binding | 144 // After that, use the JavaScript 'new' operator which overrides any binding |
| 146 // of 'this' with the new instance. | 145 // of 'this' with the new instance. |
| 147 var args = [null]..addAll(arguments.map(_convertToJS)); | 146 var args = [null]..addAll(arguments.map(_convertToJS)); |
| 148 var factoryFunction = JS('', '#.bind.apply(#, #)', constr, constr, args); | 147 var factoryFunction = JS('', '#.bind.apply(#, #)', constr, constr, args); |
| 149 // Without this line, calling factoryFunction as a constructor throws | 148 // Without this line, calling factoryFunction as a constructor throws |
| 150 JS('String', 'String(#)', factoryFunction); | 149 JS('String', 'String(#)', factoryFunction); |
| 151 // This could return an UnknownJavaScriptObject, or a native | 150 // This could return an UnknownJavaScriptObject, or a native |
| 152 // object for which there is an interceptor | 151 // object for which there is an interceptor |
| 153 var jsObj = JS('JavaScriptObject', 'new #()', factoryFunction); | 152 var jsObj = JS('JavaScriptObject', 'new #()', factoryFunction); |
| 154 return new JsObject._fromJs(jsObj); | 153 |
| 154 return _wrapToDart(jsObj); |
| 155 } | 155 } |
| 156 | 156 |
| 157 /** | 157 /** |
| 158 * Constructs a [JsObject] that proxies a native Dart object; _for expert use | 158 * Constructs a [JsObject] that proxies a native Dart object; _for expert use |
| 159 * only_. | 159 * only_. |
| 160 * | 160 * |
| 161 * Use this constructor only if you wish to get access to JavaScript | 161 * Use this constructor only if you wish to get access to JavaScript |
| 162 * properties attached to a browser host object, such as a Node or Blob, that | 162 * properties attached to a browser host object, such as a Node or Blob, that |
| 163 * is normally automatically converted into a native Dart object. | 163 * is normally automatically converted into a native Dart object. |
| 164 * | 164 * |
| 165 * An exception will be thrown if [object] either is `null` or has the type | 165 * An exception will be thrown if [object] either is `null` or has the type |
| 166 * `bool`, `num`, or `String`. | 166 * `bool`, `num`, or `String`. |
| 167 */ | 167 */ |
| 168 factory JsObject.fromBrowserObject(object) { | 168 factory JsObject.fromBrowserObject(object) { |
| 169 if (object is num || object is String || object is bool || object == null) { | 169 if (object is num || object is String || object is bool || object == null) { |
| 170 throw new ArgumentError( | 170 throw new ArgumentError( |
| 171 "object cannot be a num, string, bool, or null"); | 171 "object cannot be a num, string, bool, or null"); |
| 172 } | 172 } |
| 173 return new JsObject._fromJs(_convertToJS(object)); | 173 return _wrapToDart(_convertToJS(object)); |
| 174 } | 174 } |
| 175 | 175 |
| 176 /** | 176 /** |
| 177 * Recursively converts a JSON-like collection of Dart objects to a | 177 * Recursively converts a JSON-like collection of Dart objects to a |
| 178 * collection of JavaScript objects and returns a [JsObject] proxy to it. | 178 * collection of JavaScript objects and returns a [JsObject] proxy to it. |
| 179 * | 179 * |
| 180 * [object] must be a [Map] or [Iterable], the contents of which are also | 180 * [object] must be a [Map] or [Iterable], the contents of which are also |
| 181 * converted. Maps and Iterables are copied to a new JavaScript object. | 181 * converted. Maps and Iterables are copied to a new JavaScript object. |
| 182 * Primitives and other transferrable values are directly converted to their | 182 * Primitives and other transferrable values are directly converted to their |
| 183 * JavaScript type, and all other objects are proxied. | 183 * JavaScript type, and all other objects are proxied. |
| 184 */ | 184 */ |
| 185 factory JsObject.jsify(object) { | 185 factory JsObject.jsify(object) { |
| 186 if ((object is! Map) && (object is! Iterable)) { | 186 if ((object is! Map) && (object is! Iterable)) { |
| 187 throw new ArgumentError("object must be a Map or Iterable"); | 187 throw new ArgumentError("object must be a Map or Iterable"); |
| 188 } | 188 } |
| 189 return new JsObject._fromJs(_convertDataTree(object)); | 189 return _wrapToDart(_convertDataTree(object)); |
| 190 } | 190 } |
| 191 | 191 |
| 192 static _convertDataTree(data) { | 192 static _convertDataTree(data) { |
| 193 var _convertedObjects = new HashMap.identity(); | 193 var _convertedObjects = new HashMap.identity(); |
| 194 | 194 |
| 195 _convert(o) { | 195 _convert(o) { |
| 196 if (_convertedObjects.containsKey(o)) { | 196 if (_convertedObjects.containsKey(o)) { |
| 197 return _convertedObjects[o]; | 197 return _convertedObjects[o]; |
| 198 } | 198 } |
| 199 if (o is Map) { | 199 if (o is Map) { |
| (...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 297 * returns the result. | 297 * returns the result. |
| 298 * | 298 * |
| 299 * The type of [method] must be either [String] or [num]. | 299 * The type of [method] must be either [String] or [num]. |
| 300 */ | 300 */ |
| 301 dynamic callMethod(method, [List args]) { | 301 dynamic callMethod(method, [List args]) { |
| 302 if (method is! String && method is! num) { | 302 if (method is! String && method is! num) { |
| 303 throw new ArgumentError("method is not a String or num"); | 303 throw new ArgumentError("method is not a String or num"); |
| 304 } | 304 } |
| 305 return _convertToDart(JS('', '#[#].apply(#, #)', _jsObject, method, | 305 return _convertToDart(JS('', '#[#].apply(#, #)', _jsObject, method, |
| 306 _jsObject, | 306 _jsObject, |
| 307 args == null ? null : args.map(_convertToJS).toList())); | 307 args == null ? null : new List.from(args.map(_convertToJS)))); |
| 308 } | 308 } |
| 309 } | 309 } |
| 310 | 310 |
| 311 /** | 311 /** |
| 312 * Proxies a JavaScript Function object. | 312 * Proxies a JavaScript Function object. |
| 313 */ | 313 */ |
| 314 class JsFunction extends JsObject { | 314 class JsFunction extends JsObject { |
| 315 | 315 |
| 316 /** | 316 /** |
| 317 * Returns a [JsFunction] that captures its 'this' binding and calls [f] | 317 * Returns a [JsFunction] that captures its 'this' binding and calls [f] |
| 318 * with the value of this passed as the first argument. | 318 * with the value of this passed as the first argument. |
| 319 */ | 319 */ |
| 320 factory JsFunction.withThis(Function f) { | 320 factory JsFunction.withThis(Function f) { |
| 321 var jsFunc = _convertDartFunction(f, captureThis: true); | 321 var jsFunc = _convertDartFunction(f, captureThis: true); |
| 322 return new JsFunction._fromJs(jsFunc); | 322 return new JsFunction._fromJs(jsFunc); |
| 323 } | 323 } |
| 324 | 324 |
| 325 JsFunction._fromJs(jsObject) : super._fromJs(jsObject); | 325 JsFunction._fromJs(jsObject) : super._fromJs(jsObject); |
| 326 | 326 |
| 327 /** | 327 /** |
| 328 * Invokes the JavaScript function with arguments [args]. If [thisArg] is | 328 * Invokes the JavaScript function with arguments [args]. If [thisArg] is |
| 329 * supplied it is the value of `this` for the invocation. | 329 * supplied it is the value of `this` for the invocation. |
| 330 */ | 330 */ |
| 331 dynamic apply(List args, { thisArg }) => | 331 dynamic apply(List args, { thisArg }) => |
| 332 _convertToDart(JS('', '#.apply(#, #)', _jsObject, | 332 _convertToDart(JS('', '#.apply(#, #)', _jsObject, |
| 333 _convertToJS(thisArg), | 333 _convertToJS(thisArg), |
| 334 args == null ? null : args.map(_convertToJS).toList())); | 334 args == null ? null : new List.from(args.map(_convertToJS)))); |
| 335 } |
| 336 |
| 337 /** |
| 338 * A [List] that proxies a JavaScript array. |
| 339 */ |
| 340 class JsArray<E> extends JsObject with ListMixin<E> { |
| 341 |
| 342 /** |
| 343 * Creates a new JavaScript array. |
| 344 */ |
| 345 JsArray() : super._fromJs([]); |
| 346 |
| 347 /** |
| 348 * Creates a new JavaScript array and initializes it to the contents of |
| 349 * [other]. |
| 350 */ |
| 351 JsArray.from(Iterable<E> other) |
| 352 : super._fromJs([]..addAll(other.map(_convertToJS))); |
| 353 |
| 354 JsArray._fromJs(jsObject) : super._fromJs(jsObject); |
| 355 |
| 356 _checkIndex(int index) { |
| 357 if (index is int && (index < 0 || index >= length)) { |
| 358 throw new RangeError.range(index, 0, length); |
| 359 } |
| 360 } |
| 361 |
| 362 _checkInsertIndex(int index) { |
| 363 if (index is int && (index < 0 || index >= length + 1)) { |
| 364 throw new RangeError.range(index, 0, length); |
| 365 } |
| 366 } |
| 367 |
| 368 _checkRange(int start, int end) { |
| 369 if (start < 0 || start > this.length) { |
| 370 throw new RangeError.range(start, 0, this.length); |
| 371 } |
| 372 if (end < start || end > this.length) { |
| 373 throw new RangeError.range(end, start, this.length); |
| 374 } |
| 375 } |
| 376 |
| 377 // Methods required by ListMixin |
| 378 |
| 379 E operator [](int index) { |
| 380 _checkIndex(index); |
| 381 return super[index]; |
| 382 } |
| 383 |
| 384 void operator []=(int index, E value) { |
| 385 _checkIndex(index); |
| 386 super[index] = value; |
| 387 } |
| 388 |
| 389 int get length => super['length']; |
| 390 |
| 391 void set length(int length) { super['length'] = length; } |
| 392 |
| 393 |
| 394 // Methods overriden for better performance |
| 395 |
| 396 void add(E value) { |
| 397 callMethod('push', [value]); |
| 398 } |
| 399 |
| 400 void addAll(Iterable<E> iterable) { |
| 401 var list = (JS('bool', '# instanceof Array', iterable)) |
| 402 ? iterable |
| 403 : new List.from(iterable); |
| 404 callMethod('push', list); |
| 405 } |
| 406 |
| 407 void insert(int index, E element) { |
| 408 _checkInsertIndex(index); |
| 409 callMethod('splice', [index, 0, element]); |
| 410 } |
| 411 |
| 412 E removeAt(int index) { |
| 413 _checkIndex(index); |
| 414 return callMethod('splice', [index, 1])[0]; |
| 415 } |
| 416 |
| 417 E removeLast() { |
| 418 if (length == 0) throw new RangeError(-1); |
| 419 return callMethod('pop'); |
| 420 } |
| 421 |
| 422 void removeRange(int start, int end) { |
| 423 _checkRange(start, end); |
| 424 callMethod('splice', [start, end - start]); |
| 425 } |
| 426 |
| 427 void setRange(int start, int end, Iterable<E> iterable, [int skipCount = 0]) { |
| 428 _checkRange(start, end); |
| 429 int length = end - start; |
| 430 if (length == 0) return; |
| 431 if (skipCount < 0) throw new ArgumentError(skipCount); |
| 432 var args = [start, length]..addAll(iterable.skip(skipCount).take(length)); |
| 433 callMethod('splice', args); |
| 434 } |
| 435 |
| 436 void sort([int compare(E a, E b)]) { |
| 437 callMethod('sort', [compare]); |
| 438 } |
| 335 } | 439 } |
| 336 | 440 |
| 337 // property added to a Dart object referencing its JS-side DartObject proxy | 441 // property added to a Dart object referencing its JS-side DartObject proxy |
| 338 const _DART_OBJECT_PROPERTY_NAME = r'_$dart_dartObject'; | 442 const _DART_OBJECT_PROPERTY_NAME = r'_$dart_dartObject'; |
| 339 const _DART_CLOSURE_PROPERTY_NAME = r'_$dart_dartClosure'; | 443 const _DART_CLOSURE_PROPERTY_NAME = r'_$dart_dartClosure'; |
| 340 | 444 |
| 341 // property added to a JS object referencing its Dart-side JsObject proxy | 445 // property added to a JS object referencing its Dart-side JsObject proxy |
| 342 const _JS_OBJECT_PROPERTY_NAME = r'_$dart_jsObject'; | 446 const _JS_OBJECT_PROPERTY_NAME = r'_$dart_jsObject'; |
| 343 const _JS_FUNCTION_PROPERTY_NAME = r'$dart_jsFunction'; | 447 const _JS_FUNCTION_PROPERTY_NAME = r'$dart_jsFunction'; |
| 344 | 448 |
| 345 bool _defineProperty(o, String name, value) { | 449 bool _defineProperty(o, String name, value) { |
| 346 if (JS('bool', 'Object.isExtensible(#)', o)) { | 450 if (JS('bool', 'Object.isExtensible(#)', o)) { |
| 347 try { | 451 try { |
| 348 JS('void', 'Object.defineProperty(#, #, { value: #})', o, name, value); | 452 JS('void', 'Object.defineProperty(#, #, { value: #})', o, name, value); |
| 349 return true; | 453 return true; |
| 350 } catch(e) { | 454 } catch(e) { |
| 351 // object is native and lies about being extensible | 455 // object is native and lies about being extensible |
| 352 // see https://bugzilla.mozilla.org/show_bug.cgi?id=775185 | 456 // see https://bugzilla.mozilla.org/show_bug.cgi?id=775185 |
| 353 } | 457 } |
| 354 } | 458 } |
| 355 return false; | 459 return false; |
| 356 } | 460 } |
| 357 | 461 |
| 358 dynamic _convertToJS(dynamic o) { | 462 dynamic _convertToJS(dynamic o) { |
| 359 if (o == null) { | 463 if (o == null) { |
| 360 return null; | 464 return null; |
| 361 } else if (o is String || o is num || o is bool | 465 } else if (o is String || o is num || o is bool |
| 362 || o is Blob || o is KeyRange || o is ImageData || o is Node | 466 || o is Blob || o is KeyRange || o is ImageData || o is Node |
| 363 || o is TypedData) { | 467 || o is TypedData) { |
| 364 return o; | 468 return o; |
| 365 } else if (o is DateTime) { | 469 } else if (o is DateTime) { |
| 366 return Primitives.lazyAsJsDate(o); | 470 return Primitives.lazyAsJsDate(o); |
| 367 } else if (o is JsObject) { | 471 } else if (o is JsObject) { |
| 368 return o._jsObject; | 472 return o._jsObject; |
| 369 } else if (o is Function) { | 473 } else if (o is Function) { |
| 370 return _getJsProxy(o, _JS_FUNCTION_PROPERTY_NAME, (o) { | 474 return _getJsProxy(o, _JS_FUNCTION_PROPERTY_NAME, (o) { |
| 371 var jsFunction = _convertDartFunction(o); | 475 var jsFunction = _convertDartFunction(o); |
| 372 // set a property on the JS closure referencing the Dart closure | 476 // set a property on the JS closure referencing the Dart closure |
| 373 _defineProperty(jsFunction, _DART_CLOSURE_PROPERTY_NAME, o); | 477 _defineProperty(jsFunction, _DART_CLOSURE_PROPERTY_NAME, o); |
| (...skipping 10 matching lines...) Expand all Loading... |
| 384 if (jsProxy == null) { | 488 if (jsProxy == null) { |
| 385 jsProxy = createProxy(o); | 489 jsProxy = createProxy(o); |
| 386 _defineProperty(o, propertyName, jsProxy); | 490 _defineProperty(o, propertyName, jsProxy); |
| 387 } | 491 } |
| 388 return jsProxy; | 492 return jsProxy; |
| 389 } | 493 } |
| 390 | 494 |
| 391 // converts a Dart object to a reference to a native JS object | 495 // converts a Dart object to a reference to a native JS object |
| 392 // which might be a DartObject JS->Dart proxy | 496 // which might be a DartObject JS->Dart proxy |
| 393 Object _convertToDart(o) { | 497 Object _convertToDart(o) { |
| 498 var isArray = JS('bool', '# instanceof Array', o); |
| 394 if (JS('bool', '# == null', o) || | 499 if (JS('bool', '# == null', o) || |
| 395 JS('bool', 'typeof # == "string"', o) || | 500 JS('bool', 'typeof # == "string"', o) || |
| 396 JS('bool', 'typeof # == "number"', o) || | 501 JS('bool', 'typeof # == "number"', o) || |
| 397 JS('bool', 'typeof # == "boolean"', o)) { | 502 JS('bool', 'typeof # == "boolean"', o)) { |
| 398 return o; | 503 return o; |
| 399 } else if (o is Blob || o is KeyRange || o is ImageData || o is Node | 504 } else if (o is Blob || o is KeyRange || o is ImageData || o is Node |
| 400 || o is TypedData) { | 505 || o is TypedData) { |
| 401 return JS('Blob|KeyRange|ImageData|Node|TypedData', '#', o); | 506 return JS('Blob|KeyRange|ImageData|Node|TypedData', '#', o); |
| 402 } else if (JS('bool', '# instanceof Date', o)) { | 507 } else if (JS('bool', '# instanceof Date', o)) { |
| 403 var ms = JS('num', '#.getMilliseconds()', o); | 508 var ms = JS('num', '#.getMilliseconds()', o); |
| 404 return new DateTime.fromMillisecondsSinceEpoch(ms); | 509 return new DateTime.fromMillisecondsSinceEpoch(ms); |
| 405 } else if (JS('bool', 'typeof # == "function"', o)) { | 510 } else { |
| 511 return _wrapToDart(o); |
| 512 } |
| 513 } |
| 514 |
| 515 JsObject _wrapToDart(o) { |
| 516 if (JS('bool', 'typeof # == "function"', o)) { |
| 406 return _getDartProxy(o, _DART_CLOSURE_PROPERTY_NAME, | 517 return _getDartProxy(o, _DART_CLOSURE_PROPERTY_NAME, |
| 407 (o) => new JsFunction._fromJs(o)); | 518 (o) => new JsFunction._fromJs(o)); |
| 519 } else if (JS('bool', '# instanceof Array', o)) { |
| 520 return _getDartProxy(o, _DART_OBJECT_PROPERTY_NAME, |
| 521 (o) => new JsArray._fromJs(o)); |
| 408 } else if (JS('bool', '#.constructor === DartObject', o)) { | 522 } else if (JS('bool', '#.constructor === DartObject', o)) { |
| 409 return JS('', '#.o', o); | 523 return JS('', '#.o', o); |
| 410 } else { | 524 } else { |
| 411 return _getDartProxy(o, _DART_OBJECT_PROPERTY_NAME, | 525 return _getDartProxy(o, _DART_OBJECT_PROPERTY_NAME, |
| 412 (o) => new JsObject._fromJs(o)); | 526 (o) => new JsObject._fromJs(o)); |
| 413 } | 527 } |
| 414 } | 528 } |
| 415 | 529 |
| 416 Object _getDartProxy(o, String propertyName, createProxy(o)) { | 530 Object _getDartProxy(o, String propertyName, createProxy(o)) { |
| 417 var dartProxy = JS('', '#[#]', o, propertyName); | 531 var dartProxy = JS('', '#[#]', o, propertyName); |
| 418 if (dartProxy == null) { | 532 if (dartProxy == null) { |
| 419 dartProxy = createProxy(o); | 533 dartProxy = createProxy(o); |
| 420 _defineProperty(o, propertyName, dartProxy); | 534 _defineProperty(o, propertyName, dartProxy); |
| 421 } | 535 } |
| 422 return dartProxy; | 536 return dartProxy; |
| 423 } | 537 } |
| OLD | NEW |