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 708 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 719 Function allowInteropCaptureThis(Function f) { | 719 Function allowInteropCaptureThis(Function f) { |
| 720 if (JS('bool', 'typeof(#) == "function"', f)) { | 720 if (JS('bool', 'typeof(#) == "function"', f)) { |
| 721 // Behavior when the function is already a JS function is unspecified. | 721 // Behavior when the function is already a JS function is unspecified. |
| 722 throw new ArgumentError( | 722 throw new ArgumentError( |
| 723 "Function is already a JS function so cannot capture this."); | 723 "Function is already a JS function so cannot capture this."); |
| 724 return f; | 724 return f; |
| 725 } else { | 725 } else { |
| 726 return _convertDartFunctionFastCaptureThis(f); | 726 return _convertDartFunctionFastCaptureThis(f); |
| 727 } | 727 } |
| 728 } | 728 } |
| 729 | |
| 730 /// Utility methods to efficiently manipulate typed JSInterop objects in cases | |
| 731 /// where the name to call is not known at runtime. You should only use these | |
| 732 /// methods when the same effect cannot be achieved with @JS annotations. | |
| 733 /// These methods would be extension methods on JSObject if Dart supported | |
| 734 /// extension methods. | |
| 735 class JSNative { | |
| 736 /** | |
| 737 * WARNING: performance of this method is much worse than other methods | |
| 738 * in JSNative. Only use this method as a last resort. | |
| 739 * | |
| 740 * Recursively converts a JSON-like collection of Dart objects to a | |
| 741 * collection of JavaScript objects and returns a [JsObject] proxy to it. | |
| 742 * | |
| 743 * [object] must be a [Map] or [Iterable], the contents of which are also | |
| 744 * converted. Maps and Iterables are copied to a new JavaScript object. | |
| 745 * Primitives and other transferrable values are directly converted to their | |
| 746 * JavaScript type, and all other objects are proxied. | |
| 747 */ | |
| 748 static jsify(object) { | |
| 749 if ((object is! Map) && (object is! Iterable)) { | |
| 750 throw new ArgumentError("object must be a Map or Iterable"); | |
| 751 } | |
| 752 return _convertDataTree(object); | |
| 753 } | |
| 754 | |
| 755 static _convertDataTree(data) { | |
| 756 var _convertedObjects = new HashMap.identity(); | |
| 757 | |
| 758 _convert(o) { | |
| 759 if (_convertedObjects.containsKey(o)) { | |
| 760 return _convertedObjects[o]; | |
| 761 } | |
| 762 if (o is Map) { | |
| 763 final convertedMap = JS('=Object', '{}'); | |
| 764 _convertedObjects[o] = convertedMap; | |
| 765 for (var key in o.keys) { | |
| 766 JS('=Object', '#[#]=#', convertedMap, key, _convert(o[key])); | |
| 767 } | |
| 768 return convertedMap; | |
| 769 } else if (o is Iterable) { | |
| 770 var convertedList = []; | |
| 771 _convertedObjects[o] = convertedList; | |
| 772 convertedList.addAll(o.map(_convert)); | |
| 773 return convertedList; | |
| 774 } else { | |
| 775 return o; | |
| 776 } | |
| 777 } | |
| 778 | |
| 779 return _convert(data); | |
| 780 } | |
| 781 | |
| 782 static JSObject newObject() => JS('=Object', '{}'); | |
| 783 | |
| 784 static hasProperty(o, name) => JS('bool', '# in #', name, o); | |
| 785 static getProperty(o, name) => JS('Object', '#[#]', o, name); | |
| 786 static setProperty(o, name, value) => JS('', '#[#]=#', o, name, value); | |
| 787 | |
| 788 static callMethod(o, String method, List args) => JS('Object', '#[#].apply(#, #)', o, method, o, args); | |
|
Alan Knight
2016/07/19 16:56:04
nit: line length
Jacob
2016/07/19 17:42:19
Done. Ran dartfmt.
| |
| 789 | |
| 790 static instanceof(o, Function type) => JS('bool', '# instanceof #', o, type); | |
| 791 static callConstructor(Function constr, List arguments) { | |
| 792 if (arguments == null) { | |
| 793 return JS('Object', 'new #()', constr); | |
| 794 } | |
| 795 | |
| 796 if (JS('bool', '# instanceof Array', arguments)) { | |
| 797 int argumentCount = JS('int', '#.length', arguments); | |
| 798 switch (argumentCount) { | |
| 799 case 0: | |
| 800 return JS('Object', 'new #()', constr); | |
| 801 | |
| 802 case 1: | |
| 803 var arg0 = JS('', '#[0]', arguments); | |
| 804 return JS('Object', 'new #(#)', constr, arg0); | |
| 805 | |
| 806 case 2: | |
| 807 var arg0 = JS('', '#[0]', arguments); | |
| 808 var arg1 = JS('', '#[1]', arguments); | |
| 809 return JS('Object', 'new #(#, #)', constr, arg0, arg1); | |
| 810 | |
| 811 case 3: | |
| 812 var arg0 = JS('', '#[0]', arguments); | |
| 813 var arg1 = JS('', '#[1]', arguments); | |
| 814 var arg2 = JS('', '#[2]', arguments); | |
| 815 return JS('Object', 'new #(#, #, #)', constr, arg0, arg1, arg2); | |
| 816 | |
| 817 case 4: | |
| 818 var arg0 = JS('', '#[0]', arguments); | |
| 819 var arg1 = JS('', '#[1]', arguments); | |
| 820 var arg2 = JS('', '#[2]', arguments); | |
| 821 var arg3 = JS('', '#[3]', arguments); | |
| 822 return JS('Object', 'new #(#, #, #, #)', constr, arg0, arg1, arg2, arg 3); | |
|
Alan Knight
2016/07/19 16:56:04
Also line length
Jacob
2016/07/19 17:42:19
Done.
| |
| 823 } | |
| 824 } | |
| 825 | |
| 826 // The following code solves the problem of invoking a JavaScript | |
| 827 // constructor with an unknown number arguments. | |
| 828 // First bind the constructor to the argument list using bind.apply(). | |
| 829 // The first argument to bind() is the binding of 'this', so add 'null' to | |
| 830 // the arguments list passed to apply(). | |
| 831 // After that, use the JavaScript 'new' operator which overrides any binding | |
| 832 // of 'this' with the new instance. | |
| 833 var args = [null]..addAll(arguments); | |
| 834 var factoryFunction = JS('', '#.bind.apply(#, #)', constr, constr, args); | |
| 835 // Without this line, calling factoryFunction as a constructor throws | |
| 836 JS('String', 'String(#)', factoryFunction); | |
| 837 // This could return an UnknownJavaScriptObject, or a native | |
| 838 // object for which there is an interceptor | |
| 839 return JS('Object', 'new #()', factoryFunction); | |
| 840 | |
| 841 // TODO(sra): Investigate: | |
| 842 // | |
| 843 // var jsObj = JS('', 'Object.create(#.prototype)', constr); | |
| 844 // JS('', '#.apply(#, #)', constr, jsObj, | |
| 845 // []..addAll(arguments.map(_convertToJS))); | |
| 846 // return _wrapToDart(jsObj); | |
| 847 } | |
| 848 } | |
| OLD | NEW |