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