| 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 123 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 134 | 134 |
| 135 /** | 135 /** |
| 136 * Constructs a new JavaScript object from [constructor] and returns a proxy | 136 * Constructs a new JavaScript object from [constructor] and returns a proxy |
| 137 * to it. | 137 * to it. |
| 138 */ | 138 */ |
| 139 factory JsObject(JsFunction constructor, [List arguments]) { | 139 factory JsObject(JsFunction constructor, [List arguments]) { |
| 140 var constr = _convertToJS(constructor); | 140 var constr = _convertToJS(constructor); |
| 141 if (arguments == null) { | 141 if (arguments == null) { |
| 142 return _wrapToDart(JS('', 'new #()', constr)); | 142 return _wrapToDart(JS('', 'new #()', constr)); |
| 143 } | 143 } |
| 144 |
| 145 if (JS('bool', '# instanceof Array', arguments)) { |
| 146 int argumentCount = JS('int', '#.length', arguments); |
| 147 switch (argumentCount) { |
| 148 case 0: |
| 149 return _wrapToDart(JS('', 'new #()', constr)); |
| 150 |
| 151 case 1: |
| 152 var arg0 = _convertToJS(JS('', '#[0]', arguments)); |
| 153 return _wrapToDart(JS('', 'new #(#)', constr, arg0)); |
| 154 |
| 155 case 2: |
| 156 var arg0 = _convertToJS(JS('', '#[0]', arguments)); |
| 157 var arg1 = _convertToJS(JS('', '#[1]', arguments)); |
| 158 return _wrapToDart(JS('', 'new #(#, #)', constr, arg0, arg1)); |
| 159 |
| 160 case 3: |
| 161 var arg0 = _convertToJS(JS('', '#[0]', arguments)); |
| 162 var arg1 = _convertToJS(JS('', '#[1]', arguments)); |
| 163 var arg2 = _convertToJS(JS('', '#[2]', arguments)); |
| 164 return _wrapToDart( |
| 165 JS('', 'new #(#, #, #)', constr, arg0, arg1, arg2)); |
| 166 |
| 167 case 4: |
| 168 var arg0 = _convertToJS(JS('', '#[0]', arguments)); |
| 169 var arg1 = _convertToJS(JS('', '#[1]', arguments)); |
| 170 var arg2 = _convertToJS(JS('', '#[2]', arguments)); |
| 171 var arg3 = _convertToJS(JS('', '#[3]', arguments)); |
| 172 return _wrapToDart( |
| 173 JS('', 'new #(#, #, #, #)', constr, arg0, arg1, arg2, arg3)); |
| 174 } |
| 175 } |
| 176 |
| 144 // The following code solves the problem of invoking a JavaScript | 177 // The following code solves the problem of invoking a JavaScript |
| 145 // constructor with an unknown number arguments. | 178 // constructor with an unknown number arguments. |
| 146 // First bind the constructor to the argument list using bind.apply(). | 179 // First bind the constructor to the argument list using bind.apply(). |
| 147 // The first argument to bind() is the binding of 'this', so add 'null' to | 180 // The first argument to bind() is the binding of 'this', so add 'null' to |
| 148 // the arguments list passed to apply(). | 181 // the arguments list passed to apply(). |
| 149 // After that, use the JavaScript 'new' operator which overrides any binding | 182 // After that, use the JavaScript 'new' operator which overrides any binding |
| 150 // of 'this' with the new instance. | 183 // of 'this' with the new instance. |
| 151 var args = [null]..addAll(arguments.map(_convertToJS)); | 184 var args = [null]..addAll(arguments.map(_convertToJS)); |
| 152 var factoryFunction = JS('', '#.bind.apply(#, #)', constr, constr, args); | 185 var factoryFunction = JS('', '#.bind.apply(#, #)', constr, constr, args); |
| 153 // Without this line, calling factoryFunction as a constructor throws | 186 // Without this line, calling factoryFunction as a constructor throws |
| 154 JS('String', 'String(#)', factoryFunction); | 187 JS('String', 'String(#)', factoryFunction); |
| 155 // This could return an UnknownJavaScriptObject, or a native | 188 // This could return an UnknownJavaScriptObject, or a native |
| 156 // object for which there is an interceptor | 189 // object for which there is an interceptor |
| 157 var jsObj = JS('JavaScriptObject', 'new #()', factoryFunction); | 190 var jsObj = JS('', 'new #()', factoryFunction); |
| 158 | 191 |
| 159 return _wrapToDart(jsObj); | 192 return _wrapToDart(jsObj); |
| 193 |
| 194 // TODO(sra): Investigate: |
| 195 // |
| 196 // var jsObj = JS('', 'Object.create(#.prototype)', constr); |
| 197 // JS('', '#.apply(#, #)', constr, jsObj, |
| 198 // []..addAll(arguments.map(_convertToJS))); |
| 199 // return _wrapToDart(jsObj); |
| 160 } | 200 } |
| 161 | 201 |
| 162 /** | 202 /** |
| 163 * Constructs a [JsObject] that proxies a native Dart object; _for expert use | 203 * Constructs a [JsObject] that proxies a native Dart object; _for expert use |
| 164 * only_. | 204 * only_. |
| 165 * | 205 * |
| 166 * Use this constructor only if you wish to get access to JavaScript | 206 * Use this constructor only if you wish to get access to JavaScript |
| 167 * properties attached to a browser host object, such as a Node or Blob, that | 207 * properties attached to a browser host object, such as a Node or Blob, that |
| 168 * is normally automatically converted into a native Dart object. | 208 * is normally automatically converted into a native Dart object. |
| 169 * | 209 * |
| (...skipping 333 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 503 | 543 |
| 504 // The shared constructor function for proxies to Dart objects in JavaScript. | 544 // The shared constructor function for proxies to Dart objects in JavaScript. |
| 505 final _dartProxyCtor = JS('', 'function DartObject(o) { this.o = o; }'); | 545 final _dartProxyCtor = JS('', 'function DartObject(o) { this.o = o; }'); |
| 506 | 546 |
| 507 dynamic _convertToJS(dynamic o) { | 547 dynamic _convertToJS(dynamic o) { |
| 508 // Note: we don't write `if (o == null) return null;` to make sure dart2js | 548 // Note: we don't write `if (o == null) return null;` to make sure dart2js |
| 509 // doesn't convert `return null;` into `return;` (which would make `null` be | 549 // doesn't convert `return null;` into `return;` (which would make `null` be |
| 510 // `undefined` in Javascprit). See dartbug.com/20305 for details. | 550 // `undefined` in Javascprit). See dartbug.com/20305 for details. |
| 511 if (o == null || o is String || o is num || o is bool) { | 551 if (o == null || o is String || o is num || o is bool) { |
| 512 return o; | 552 return o; |
| 513 } else if (o is Blob || o is Event || o is KeyRange || o is ImageData | 553 } |
| 514 || o is Node || o is TypedData || o is Window) { | 554 if (o is JsObject) { |
| 555 return o._jsObject; |
| 556 } |
| 557 if (o is Blob || o is Event || o is KeyRange || o is ImageData || o is Node || |
| 558 o is TypedData || o is Window) { |
| 515 return o; | 559 return o; |
| 516 } else if (o is DateTime) { | 560 } |
| 561 if (o is DateTime) { |
| 517 return Primitives.lazyAsJsDate(o); | 562 return Primitives.lazyAsJsDate(o); |
| 518 } else if (o is JsObject) { | 563 } |
| 519 return o._jsObject; | 564 if (o is Function) { |
| 520 } else if (o is Function) { | |
| 521 return _getJsProxy(o, _JS_FUNCTION_PROPERTY_NAME, (o) { | 565 return _getJsProxy(o, _JS_FUNCTION_PROPERTY_NAME, (o) { |
| 522 var jsFunction = _convertDartFunction(o); | 566 var jsFunction = _convertDartFunction(o); |
| 523 // set a property on the JS closure referencing the Dart closure | 567 // set a property on the JS closure referencing the Dart closure |
| 524 _defineProperty(jsFunction, _DART_CLOSURE_PROPERTY_NAME, o); | 568 _defineProperty(jsFunction, _DART_CLOSURE_PROPERTY_NAME, o); |
| 525 return jsFunction; | 569 return jsFunction; |
| 526 }); | 570 }); |
| 527 } else { | |
| 528 var ctor = _dartProxyCtor; | |
| 529 return _getJsProxy(o, _JS_OBJECT_PROPERTY_NAME, | |
| 530 (o) => JS('', 'new #(#)', ctor, o)); | |
| 531 } | 571 } |
| 572 var ctor = _dartProxyCtor; |
| 573 return _getJsProxy(o, _JS_OBJECT_PROPERTY_NAME, |
| 574 (o) => JS('', 'new #(#)', ctor, o)); |
| 532 } | 575 } |
| 533 | 576 |
| 534 Object _getJsProxy(o, String propertyName, createProxy(o)) { | 577 Object _getJsProxy(o, String propertyName, createProxy(o)) { |
| 535 var jsProxy = _getOwnProperty(o, propertyName); | 578 var jsProxy = _getOwnProperty(o, propertyName); |
| 536 if (jsProxy == null) { | 579 if (jsProxy == null) { |
| 537 jsProxy = createProxy(o); | 580 jsProxy = createProxy(o); |
| 538 _defineProperty(o, propertyName, jsProxy); | 581 _defineProperty(o, propertyName, jsProxy); |
| 539 } | 582 } |
| 540 return jsProxy; | 583 return jsProxy; |
| 541 } | 584 } |
| (...skipping 18 matching lines...) Expand all Loading... |
| 560 return JS('', '#.o', o); | 603 return JS('', '#.o', o); |
| 561 } else { | 604 } else { |
| 562 return _wrapToDart(o); | 605 return _wrapToDart(o); |
| 563 } | 606 } |
| 564 } | 607 } |
| 565 | 608 |
| 566 JsObject _wrapToDart(o) { | 609 JsObject _wrapToDart(o) { |
| 567 if (JS('bool', 'typeof # == "function"', o)) { | 610 if (JS('bool', 'typeof # == "function"', o)) { |
| 568 return _getDartProxy(o, _DART_CLOSURE_PROPERTY_NAME, | 611 return _getDartProxy(o, _DART_CLOSURE_PROPERTY_NAME, |
| 569 (o) => new JsFunction._fromJs(o)); | 612 (o) => new JsFunction._fromJs(o)); |
| 570 } else if (JS('bool', '# instanceof Array', o)) { | 613 } |
| 614 if (JS('bool', '# instanceof Array', o)) { |
| 571 return _getDartProxy(o, _DART_OBJECT_PROPERTY_NAME, | 615 return _getDartProxy(o, _DART_OBJECT_PROPERTY_NAME, |
| 572 (o) => new JsArray._fromJs(o)); | 616 (o) => new JsArray._fromJs(o)); |
| 573 } else { | |
| 574 return _getDartProxy(o, _DART_OBJECT_PROPERTY_NAME, | |
| 575 (o) => new JsObject._fromJs(o)); | |
| 576 } | 617 } |
| 618 return _getDartProxy(o, _DART_OBJECT_PROPERTY_NAME, |
| 619 (o) => new JsObject._fromJs(o)); |
| 577 } | 620 } |
| 578 | 621 |
| 579 Object _getDartProxy(o, String propertyName, createProxy(o)) { | 622 Object _getDartProxy(o, String propertyName, createProxy(o)) { |
| 580 var dartProxy = _getOwnProperty(o, propertyName); | 623 var dartProxy = _getOwnProperty(o, propertyName); |
| 581 // Temporary fix for dartbug.com/15193 | 624 // Temporary fix for dartbug.com/15193 |
| 582 // In some cases it's possible to see a JavaScript object that | 625 // In some cases it's possible to see a JavaScript object that |
| 583 // came from a different context and was previously proxied to | 626 // came from a different context and was previously proxied to |
| 584 // Dart in that context. The JS object will have a cached proxy | 627 // Dart in that context. The JS object will have a cached proxy |
| 585 // but it won't be a valid Dart object in this context. | 628 // but it won't be a valid Dart object in this context. |
| 586 // For now we throw away the cached proxy, but we should be able | 629 // For now we throw away the cached proxy, but we should be able |
| 587 // to cache proxies from multiple JS contexts and Dart isolates. | 630 // to cache proxies from multiple JS contexts and Dart isolates. |
| 588 if (dartProxy == null || !_isLocalObject(o)) { | 631 if (dartProxy == null || !_isLocalObject(o)) { |
| 589 dartProxy = createProxy(o); | 632 dartProxy = createProxy(o); |
| 590 _defineProperty(o, propertyName, dartProxy); | 633 _defineProperty(o, propertyName, dartProxy); |
| 591 } | 634 } |
| 592 return dartProxy; | 635 return dartProxy; |
| 593 } | 636 } |
| OLD | NEW |