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 |