Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(350)

Side by Side Diff: sdk/lib/js/dartium/js_dartium.dart

Issue 1391353002: Dartium typed js interop work dart repo side of the change. Also tries to get (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Created 5 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « sdk/lib/html/dartium/html_dartium.dart ('k') | tests/html/js_test.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 74 matching lines...) Expand 10 before | Expand all | Expand 10 after
85 * 85 *
86 * var jsArray = new JsObject.jsify([1, 2, 3]); 86 * var jsArray = new JsObject.jsify([1, 2, 3]);
87 */ 87 */
88 library dart.js; 88 library dart.js;
89 89
90 import 'dart:collection' show ListMixin; 90 import 'dart:collection' show ListMixin;
91 import 'dart:nativewrappers'; 91 import 'dart:nativewrappers';
92 import 'dart:math' as math; 92 import 'dart:math' as math;
93 import 'dart:mirrors' as mirrors; 93 import 'dart:mirrors' as mirrors;
94 import 'dart:html' as html; 94 import 'dart:html' as html;
95 import 'dart:indexed_db' as indexed_db;
96 import 'dart:typed_data';
95 97
96 // Pretend we are always in checked mode as we aren't interested in users 98 // Pretend we are always in checked mode as we aren't interested in users
97 // running Dartium code outside of checked mode. 99 // running Dartium code outside of checked mode.
98 final bool CHECK_JS_INVOCATIONS = true; 100 final bool CHECK_JS_INVOCATIONS = true;
99 101
100 final _allowedMethods = new Map<Symbol, _DeclarationSet>(); 102 final _allowedMethods = new Map<Symbol, _DeclarationSet>();
101 final _allowedGetters = new Map<Symbol, _DeclarationSet>(); 103 final _allowedGetters = new Map<Symbol, _DeclarationSet>();
102 final _allowedSetters = new Map<Symbol, _DeclarationSet>(); 104 final _allowedSetters = new Map<Symbol, _DeclarationSet>();
103 105
104 final _jsInterfaceTypes = new Set<Type>(); 106 final _jsInterfaceTypes = new Set<Type>();
(...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after
197 _members.add(mirror); 199 _members.add(mirror);
198 } 200 }
199 201
200 final List<mirrors.DeclarationMirror> _members; 202 final List<mirrors.DeclarationMirror> _members;
201 } 203 }
202 204
203 /** 205 /**
204 * Temporary method that we hope to remove at some point. This method should 206 * Temporary method that we hope to remove at some point. This method should
205 * generally only be called by machine generated code. 207 * generally only be called by machine generated code.
206 */ 208 */
207 void registerJsInterfaces(List<Type> classes) { 209
208 if (_finalized == true) { 210 void registerJsInterfaces([List<Type> classes]) {
209 throw 'JSInterop class registration already finalized'; 211 // This method is now obsolete in Dartium.
210 } 212 }
213
214 void _registerJsInterfaces(List<Type> classes) {
211 for (Type type in classes) { 215 for (Type type in classes) {
212 if (!_jsInterfaceTypes.add(type)) continue; // Already registered. 216 if (!_jsInterfaceTypes.add(type)) continue; // Already registered.
213 mirrors.ClassMirror typeMirror = mirrors.reflectType(type); 217 mirrors.ClassMirror typeMirror = mirrors.reflectType(type);
214 typeMirror.declarations.forEach((symbol, declaration) { 218 typeMirror.declarations.forEach((symbol, declaration) {
215 if (declaration is mirrors.MethodMirror || 219 if (declaration is mirrors.MethodMirror ||
216 declaration is mirrors.VariableMirror && !declaration.isStatic) { 220 declaration is mirrors.VariableMirror && !declaration.isStatic) {
217 bool treatAsGetter = false; 221 bool treatAsGetter = false;
218 bool treatAsSetter = false; 222 bool treatAsSetter = false;
219 if (declaration is mirrors.VariableMirror) { 223 if (declaration is mirrors.VariableMirror) {
220 treatAsGetter = true; 224 treatAsGetter = true;
(...skipping 24 matching lines...) Expand all
245 .putIfAbsent(symbol, () => new _DeclarationSet()) 249 .putIfAbsent(symbol, () => new _DeclarationSet())
246 .add(declaration); 250 .add(declaration);
247 } 251 }
248 } 252 }
249 }); 253 });
250 } 254 }
251 } 255 }
252 256
253 _finalizeJsInterfaces() native "Js_finalizeJsInterfaces"; 257 _finalizeJsInterfaces() native "Js_finalizeJsInterfaces";
254 258
259 String _getJsName(mirrors.DeclarationMirror mirror) {
260 for (var annotation in mirror.metadata) {
261 if (mirrors.MirrorSystem.getName(annotation.type.simpleName) == "Js") {
262 mirrors.LibraryMirror library = annotation.type.owner;
263 var uri = library.uri;
264 // make sure the annotation is from package://js
265 if (uri.scheme == 'package' && uri.path == 'js/js.dart') {
266 try {
267 var name = annotation.reflectee.name;
268 return name != null ? name : "";
269 } catch (e) {
270 }
271 }
272 }
273 }
274 return null;
275 }
276
277 bool _hasJsName(mirrors.DeclarationMirror mirror) =>
278 _getJsName(mirror) != null;
279
280
281 _getJsMemberName(mirrors.DeclarationMirror mirror) {
282 var name = _getJsName(mirror);
283 return name == null || name.isEmpty ? _getDeclarationName(mirror) :
284 name;
285 }
286
287 // TODO(jacobr): handle setters correctyl.
288 String _getDeclarationName(mirrors.DeclarationMirror declaration) {
289 var name = mirrors.MirrorSystem.getName(declaration.simpleName);
290 if (declaration is mirrors.MethodMirror && declaration.isSetter) {
291 assert(name.endsWith("="));
292 name = name.substring(0, name.length - 1);
293 }
294 return name;
295 }
296
297 final _JS_LIBRARY_PREFIX = "js_library";
298 final _UNDEFINED_VAR = "_UNDEFINED_JS_CONST";
299
300 String _accessJsPath(String path) =>
301 "${_JS_LIBRARY_PREFIX}.context${path.split(".").map((p) => "['$p']").join('' )}";
302
303 void addMemberHelper(mirrors.MethodMirror declaration, String path, StringBuffer sb, {bool isStatic: false, String memberName}) {
304 var jsName = _getJsMemberName(declaration);
305 path = (path != null && path.isNotEmpty) ? "${path}.${jsName}" : jsName;
306 var name = memberName != null ? memberName : _getDeclarationName(declaration);
307 if (declaration.isConstructor) {
308 sb.write("factory");
309 } else if (isStatic) {
310 sb.write("static");
311 } else {
312 sb.write("patch");
313 }
314 sb.write(" ");
315 if (declaration.isGetter) {
316 sb.write("get $name => ${_accessJsPath(path)};");
317 } else if (declaration.isSetter) {
318 sb.write("set $name(v) => ${_accessJsPath(path)} = v;");
319 } else {
320 sb.write("$name(");
321 bool hasOptional = false;
322 int i = 0;
323 var args = <String>[];
324 for (var p in declaration.parameters) {
325 assert(!p.isNamed); // XXX throw
326 assert(!p.hasDefaultValue);
327 if (i > 0) {
328 sb.write(", ");
329 }
330 if (p.isOptional && !hasOptional) {
331 sb.write("[");
332 hasOptional = true;
333 }
334 var arg = "p$i";
335 args.add(arg);
336 sb.write(arg);
337 if (p.isOptional) {
338 sb.write("=${_UNDEFINED_VAR}");
339 }
340 i++;
341 }
342 if (hasOptional) {
343 sb.write("]");
344 }
345 // TODO(jacobr):
346 sb.write(") => ");
347 if (declaration.isConstructor) {
348 sb.write("new ${_JS_LIBRARY_PREFIX}.JsObject(");
349 }
350 sb
351 ..write(_accessJsPath(path))
352 ..write(declaration.isConstructor ? "," : ".apply(")
353 ..write("[${args.join(",")}]");
354
355 if (hasOptional) {
356 sb.write(".takeWhile((i) => i != ${_UNDEFINED_VAR}).toList()");
357 }
358 sb.write(");");
359 }
360 sb.write("\n");
361 }
362
363 // TODO(jacobr): make this check more robust.
364 bool _isExternal(mirrors.MethodMirror mirror) =>
365 mirror.source != null && mirror.source.startsWith("external ");
366
367 List<String> _generateExternalMethods() {
368 var staticCodegen = <String>[];
369 mirrors.currentMirrorSystem().libraries.forEach((uri, library) {
370 var sb = new StringBuffer();
371 String jsLibraryName = _getJsName(library);
372 library.declarations.forEach((name, declaration) {
373 if (declaration is mirrors.MethodMirror) {
374 if (_isExternal(declaration) && (_hasJsName(declaration) || jsLibraryNam e != null)) {
375 addMemberHelper(declaration, jsLibraryName, sb);
376 }
377 } else if (declaration is mirrors.ClassMirror) {
378 mirrors.ClassMirror clazz = declaration;
379 if (_hasJsName(clazz)) {
380 // TODO(jacobr): verify class implements JavaScriptObject.
381 assert(clazz.hasReflectedType);
382 jsInterfaceTypes.add(clazz.reflectedType);
383 String jsClassName = _getJsMemberName(clazz);
384 var className = mirrors.MirrorSystem.getName(clazz.simpleName);
385 var sbPatch = new StringBuffer();
386 clazz.declarations.forEach((name, declaration) {
387 if (declaration is! mirrors.MethodMirror || !_isExternal(declaration )) return;
388 if (declaration.isFactoryConstructor) {
389 sbPatch.write(" factory ${className}({");
390 int i = 0;
391 var args = <String>[];
392 for (var p in declaration.parameters) {
393 assert(p.isNamed); // XXX throw
394 args.add(mirrors.MirrorSystem.getName(p.simpleName));
395 i++;
396 }
397 sbPatch
398 ..write(args.map((name) => '$name:${_UNDEFINED_VAR}').join(", ") )
399 ..write("}) {\n"
400 " var ret = new ${_JS_LIBRARY_PREFIX}.JsObject.jsify( {});\n");
401 i = 0;
402 for (var p in declaration.parameters) {
403 assert(p.isNamed); // XXX throw
404 var name = args[i];
405 var jsName = mirrors.MirrorSystem.getName(p.simpleName);
406 // XXX apply name conversion rules.
407 sbPatch.write(" if($name != ${_UNDEFINED_VAR}) ret['$jsName'] = $name;\n");
408 i++;
409 }
410
411 sbPatch.write(" return ret;\n"
412 " }\n");
413 } else if (declaration.isConstructor) {
414 sbPatch.write(" ");
415 addMemberHelper(declaration,
416 (jsLibraryName != null && jsLibraryName.isNotEmpty) ? "${jsLib raryName}" : "",
417 sbPatch,
418 isStatic: true,
419 memberName: className);
420 }
421 });
422
423 clazz.staticMembers.forEach((memberName, member) {
424 if (_isExternal(member)) {
425 sbPatch.write(" ");
426 addMemberHelper(member,
427 (jsLibraryName != null && jsLibraryName.isNotEmpty) ? "${jsLib raryName}.${jsClassName}" : jsClassName,
428 sbPatch,
429 isStatic: true);
430 }
431 });
432 if (sbPatch.isNotEmpty) {
433 sb.write("""
434 patch class $className {
435 $sbPatch
436 }
437 """);
438 }
439 }
440 }
441 });
442 if (sb.isNotEmpty) {
443 staticCodegen
444 ..add(uri.toString())
445 ..add("${uri}_js_interop_patch.dart")
446 ..add("""
447 import 'dart:js' as ${_JS_LIBRARY_PREFIX};
448
449 /**
450 * Placeholder object for cases where we need to determine exactly how many
451 * args were passed to a function.
452 */
453 const ${_UNDEFINED_VAR} = const Object();
454
455 ${sb}
456 """);
457 }
458 });
459
460 return staticCodegen;
461 }
462
255 /** 463 /**
256 * Generates a part file defining source code for JsObjectImpl and related 464 * Generates a part file defining source code for JsObjectImpl and related
257 * classes. This calass is needed so that type checks for all registered JavaScr ipt 465 * classes. This calass is needed so that type checks for all registered JavaScr ipt
258 * interop classes pass. 466 * interop classes pass.
259 */ 467 */
260 String _generateJsObjectImplPart() { 468 List<String> _generateInteropPatchFiles() {
261 Iterable<Type> types = jsInterfaceTypes; 469 var ret = _generateExternalMethods();
262 var libraryPrefixes = new Map<mirrors.LibraryMirror, String>(); 470 var libraryPrefixes = new Map<mirrors.LibraryMirror, String>();
263 var prefixNames = new Set<String>(); 471 var prefixNames = new Set<String>();
264 var sb = new StringBuffer(); 472 var sb = new StringBuffer();
265 473
266 var implements = <String>[]; 474 var implements = <String>[];
267 for (var type in types) { 475 var implementsArray = <String>[];
476 var listMirror = mirrors.reflectType(List);
477
478 for (var type in jsInterfaceTypes) {
268 mirrors.ClassMirror typeMirror = mirrors.reflectType(type); 479 mirrors.ClassMirror typeMirror = mirrors.reflectType(type);
269 mirrors.LibraryMirror libraryMirror = typeMirror.owner; 480 mirrors.LibraryMirror libraryMirror = typeMirror.owner;
270 var prefixName; 481 var prefixName;
271 if (libraryPrefixes.containsKey(libraryMirror)) { 482 if (libraryPrefixes.containsKey(libraryMirror)) {
272 prefixName = libraryPrefixes[libraryMirror]; 483 prefixName = libraryPrefixes[libraryMirror];
273 } else { 484 } else {
274 var basePrefixName = 485 var basePrefixName =
275 mirrors.MirrorSystem.getName(libraryMirror.simpleName); 486 mirrors.MirrorSystem.getName(libraryMirror.simpleName);
276 basePrefixName = basePrefixName.replaceAll('.', '_'); 487 basePrefixName = basePrefixName.replaceAll('.', '_');
277 if (basePrefixName.isEmpty) basePrefixName = "lib"; 488 if (basePrefixName.isEmpty) basePrefixName = "lib";
278 prefixName = basePrefixName; 489 prefixName = basePrefixName;
279 var i = 1; 490 var i = 1;
280 while (prefixNames.contains(prefixName)) { 491 while (prefixNames.contains(prefixName)) {
281 prefixName = '$basePrefixName$i'; 492 prefixName = '$basePrefixName$i';
282 i++; 493 i++;
283 } 494 }
284 prefixNames.add(prefixName); 495 prefixNames.add(prefixName);
285 libraryPrefixes[libraryMirror] = prefixName; 496 libraryPrefixes[libraryMirror] = prefixName;
286 } 497 }
287 implements.add( 498 var isArray = typeMirror.isSubtypeOf(listMirror);
499 (isArray ? implementsArray : implements).add(
288 '${prefixName}.${mirrors.MirrorSystem.getName(typeMirror.simpleName)}'); 500 '${prefixName}.${mirrors.MirrorSystem.getName(typeMirror.simpleName)}');
289 } 501 }
290 libraryPrefixes.forEach((libraryMirror, prefix) { 502 libraryPrefixes.forEach((libraryMirror, prefix) {
291 sb.writeln('import "${libraryMirror.uri}" as $prefix;'); 503 sb.writeln('import "${libraryMirror.uri}" as $prefix;');
292 }); 504 });
293 var implementsClause = 505 buildImplementsClause(classes) =>
294 implements.isEmpty ? "" : "implements ${implements.join(', ')}"; 506 classes.isEmpty ? "" : "implements ${classes.join(', ')}"
507 var implementsClause = buildImplementsClause(implements);
295 // TODO(jacobr): only certain classes need to be implemented by 508 // TODO(jacobr): only certain classes need to be implemented by
296 // Function and Array. 509 // JsFunctionImpl.
510 var allTypes = []..addAll(implements)..addAll(implementsArray);
297 sb.write(''' 511 sb.write('''
298 class JsObjectImpl extends JsObject $implementsClause { 512 class JsObjectImpl extends JsObject $implementsClause {
299 JsObjectImpl.internal() : super.internal(); 513 JsObjectImpl.internal() : super.internal();
300 } 514 }
301 515
302 class JsFunctionImpl extends JsFunction $implementsClause { 516 class JsFunctionImpl extends JsFunction $implementsClause {
303 JsFunctionImpl.internal() : super.internal(); 517 JsFunctionImpl.internal() : super.internal();
304 } 518 }
305 519
306 class JsArrayImpl<E> extends JsArray<E> $implementsClause { 520 class JsArrayImpl<E> extends JsArray<E> ${buildImplementsClause(implementsArray) } {
307 JsArrayImpl.internal() : super.internal(); 521 JsArrayImpl.internal() : super.internal();
308 } 522 }
523
524 _registerAllJsInterfaces() {
525 _registerJsInterfaces([${allTypes.join(", ")}]);
526 }
527
309 '''); 528 ''');
310 return sb.toString(); 529 ret..addAll(["dart:js", "JsInteropImpl.dart", sb.toString()]);
530 return ret;
311 } 531 }
312 532
313 // Start of block of helper methods facilitating emulating JavaScript Array 533 // Start of block of helper methods facilitating emulating JavaScript Array
314 // methods on Dart List objects passed to JavaScript via JS interop. 534 // methods on Dart List objects passed to JavaScript via JS interop.
315 // TODO(jacobr): match JS more closely. 535 // TODO(jacobr): match JS more closely.
316 String _toStringJs(obj) => '$obj'; 536 String _toStringJs(obj) => '$obj';
317 537
318 // TODO(jacobr): this might not exactly match JS semantics but should be 538 // TODO(jacobr): this might not exactly match JS semantics but should be
319 // adequate for now. 539 // adequate for now.
320 int _toIntJs(obj) { 540 int _toIntJs(obj) {
(...skipping 151 matching lines...) Expand 10 before | Expand all | Expand 10 after
472 692
473 bool get _finalized native "Js_interfacesFinalized_Callback"; 693 bool get _finalized native "Js_interfacesFinalized_Callback";
474 694
475 JsObject get context { 695 JsObject get context {
476 if (_cachedContext == null) { 696 if (_cachedContext == null) {
477 _cachedContext = _context; 697 _cachedContext = _context;
478 } 698 }
479 return _cachedContext; 699 return _cachedContext;
480 } 700 }
481 701
702 _maybeWrap(o) {
703 var wrapped = html.wrap_jso_no_SerializedScriptvalue(o);
704 if (identical(wrapped, o)) return o;
705 return (wrapped is html.Blob
706 || wrapped is html.Event
707 || wrapped is indexed_db.KeyRange
708 || wrapped is html.ImageData
709 || wrapped is html.Node
710 || wrapped is TypedData
711 || wrapped is html.Window) ? wrapped : o;
712 }
713
482 /** 714 /**
483 * Get the dart wrapper object for object. Top-level so we 715 * Get the dart wrapper object for object. Top-level so we
484 * we can access it from other libraries without it being 716 * we can access it from other libraries without it being
485 * a public instance field on JsObject. 717 * a public instance field on JsObject.
486 */ 718 */
487 getDartHtmlWrapperFor(JsObject object) => object._dartHtmlWrapper; 719 getDartHtmlWrapperFor(JsObject object) => object._dartHtmlWrapper;
488 720
489 /** 721 /**
490 * Set the dart wrapper object for object. Top-level so we 722 * Set the dart wrapper object for object. Top-level so we
491 * we can access it from other libraries without it being 723 * we can access it from other libraries without it being
492 * a public instance field on JsObject. 724 * a public instance field on JsObject.
493 */ 725 */
494 void setDartHtmlWrapperFor(JsObject object, wrapper) { 726 void setDartHtmlWrapperFor(JsObject object, wrapper) {
495 object._dartHtmlWrapper = wrapper; 727 object._dartHtmlWrapper = wrapper;
496 } 728 }
497 729
498 /** 730 /**
499 * Used by callMethod to get the JS object for each argument passed if the 731 * Used by callMethod to get the JS object for each argument passed if the
500 * argument is a Dart class instance that delegates to a DOM object. See 732 * argument is a Dart class instance that delegates to a DOM object. See
501 * wrap_jso defined in dart:html. 733 * wrap_jso defined in dart:html.
502 */ 734 */
503 unwrap_jso(dartClass_instance) { 735 unwrap_jso(dartClass_instance) {
504 try { 736 if (dartClass_instance is NativeFieldWrapperClass2 && dartClass_instance is! J sObject)
505 if (dartClass_instance != null) 737 return dartClass_instance.blink_jsObject;
506 return dartClass_instance is NativeFieldWrapperClass2 ? 738 else
507 dartClass_instance.blink_jsObject : dartClass_instance;
508 else
509 return null;
510 } catch(NoSuchMethodException) {
511 // No blink_jsObject then return the dartClass_instance is probably an
512 // array that was already converted to a Dart class e.g., Uint8ClampedList.
513 return dartClass_instance; 739 return dartClass_instance;
514 }
515 } 740 }
516 741
517 /** 742 /**
518 * Proxies a JavaScript object to Dart. 743 * Proxies a JavaScript object to Dart.
519 * 744 *
520 * The properties of the JavaScript object are accessible via the `[]` and 745 * The properties of the JavaScript object are accessible via the `[]` and
521 * `[]=` operators. Methods are callable via [callMethod]. 746 * `[]=` operators. Methods are callable via [callMethod].
522 */ 747 */
523 class JsObject extends NativeFieldWrapperClass2 { 748 class JsObject extends NativeFieldWrapperClass2 {
524 JsObject.internal(); 749 JsObject.internal();
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after
597 static JsObject _fromBrowserObject(object) => html.unwrap_jso(object); 822 static JsObject _fromBrowserObject(object) => html.unwrap_jso(object);
598 823
599 /** 824 /**
600 * Returns the value associated with [property] from the proxied JavaScript 825 * Returns the value associated with [property] from the proxied JavaScript
601 * object. 826 * object.
602 * 827 *
603 * The type of [property] must be either [String] or [num]. 828 * The type of [property] must be either [String] or [num].
604 */ 829 */
605 operator [](property) { 830 operator [](property) {
606 try { 831 try {
607 return _operator_getter(property); 832 return _maybeWrap(_operator_getter(property));
608 } catch (e) { 833 } catch (e) {
609 // Re-throw any errors (returned as a string) as a DomException. 834 // Re-throw any errors (returned as a string) as a DomException.
610 throw new html.DomException.jsInterop(e); 835 throw new html.DomException.jsInterop(e);
611 } 836 }
612 } 837 }
613 _operator_getter(property) native "JsObject_[]"; 838 _operator_getter(property) native "JsObject_[]";
614 839
615 /** 840 /**
616 * Sets the value associated with [property] on the proxied JavaScript 841 * Sets the value associated with [property] on the proxied JavaScript
617 * object. 842 * object.
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after
678 String _toString() native "JsObject_toString"; 903 String _toString() native "JsObject_toString";
679 904
680 /** 905 /**
681 * Calls [method] on the JavaScript object with the arguments [args] and 906 * Calls [method] on the JavaScript object with the arguments [args] and
682 * returns the result. 907 * returns the result.
683 * 908 *
684 * The type of [method] must be either [String] or [num]. 909 * The type of [method] must be either [String] or [num].
685 */ 910 */
686 callMethod(String method, [List args]) { 911 callMethod(String method, [List args]) {
687 try { 912 try {
688 if (args != null) { 913 return _maybeWrap(_callMethod(method, args));
689 for (var i = 0; i < args.length; i++)
690 args[i] = unwrap_jso(args[i]);
691 }
692 return _callMethod(method, args);
693 } catch (e) { 914 } catch (e) {
694 if (hasProperty(method)) { 915 if (hasProperty(method)) {
695 // Return a DomException if DOM call returned an error. 916 // Return a DomException if DOM call returned an error.
696 throw new html.DomException.jsInterop(e); 917 throw new html.DomException.jsInterop(e);
697 } else { 918 } else {
698 throw new NoSuchMethodError(this, new Symbol(method), args, null); 919 throw new NoSuchMethodError(this, new Symbol(method), args, null);
699 } 920 }
700 } 921 }
701 } 922 }
702 923
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
746 if (CHECK_JS_INVOCATIONS) { 967 if (CHECK_JS_INVOCATIONS) {
747 if (!matches._checkReturnType(ret)) throwError(); 968 if (!matches._checkReturnType(ret)) throwError();
748 } 969 }
749 return ret; 970 return ret;
750 } 971 }
751 } 972 }
752 973
753 _callMethod(String name, List args) native "JsObject_callMethod"; 974 _callMethod(String name, List args) native "JsObject_callMethod";
754 } 975 }
755 976
977 // JavaScript interop methods that do not automatically wrap to dart:html types.
978 // Warning: this API is not exposed to dart:js.
979 class JsNative {
980 static getProperty(JsObject o, name) {
981 return o._operator_getter(name);
982 }
983
984 static callMethod(JsObject o, String method, List args) {
985 return o._callMethod(method, args);
986 }
987
988 static getArrayIndex(JsArray array, int index) {
989 array._checkIndex(index);
990 return getProperty(array, index);
991 }
992
993 /**
994 * Same behavior as new JsFunction.withThis except that JavaScript "this" is n ot
995 * wrapped.
996 */
997 static JsFunction withThis(Function f) native "JsFunction_withThisNoWrap";
998 }
999
756 /** 1000 /**
757 * Proxies a JavaScript Function object. 1001 * Proxies a JavaScript Function object.
758 */ 1002 */
759 class JsFunction extends JsObject implements Function { 1003 class JsFunction extends JsObject implements Function {
760 JsFunction.internal() : super.internal(); 1004 JsFunction.internal() : super.internal();
761 1005
762 /** 1006 /**
763 * Returns a [JsFunction] that captures its 'this' binding and calls [f] 1007 * Returns a [JsFunction] that captures its 'this' binding and calls [f]
764 * with the value of this passed as the first argument. 1008 * with the value of this passed as the first argument.
765 */ 1009 */
766 factory JsFunction.withThis(Function f) => _withThis(f); 1010 factory JsFunction.withThis(Function f) => _withThis(f);
767 1011
768 /** 1012 /**
769 * Invokes the JavaScript function with arguments [args]. If [thisArg] is 1013 * Invokes the JavaScript function with arguments [args]. If [thisArg] is
770 * supplied it is the value of `this` for the invocation. 1014 * supplied it is the value of `this` for the invocation.
771 */ 1015 */
772 dynamic apply(List args, {thisArg}) native "JsFunction_apply"; 1016 dynamic apply(List args, {thisArg}) =>
1017 _maybeWrap(_apply(args, thisArg: thisArg));
1018
1019 dynamic _apply(List args, {thisArg}) native "JsFunction_apply";
773 1020
774 noSuchMethod(Invocation invocation) { 1021 noSuchMethod(Invocation invocation) {
775 if (invocation.isMethod && invocation.memberName == #call) { 1022 if (invocation.isMethod && invocation.memberName == #call) {
776 return apply(_buildArgs(invocation)); 1023 return apply(_buildArgs(invocation));
777 } 1024 }
778 return super.noSuchMethod(invocation); 1025 return super.noSuchMethod(invocation);
779 } 1026 }
780 1027
781 /** 1028 /**
782 * Internal only version of apply which uses debugger proxies of Dart objects 1029 * Internal only version of apply which uses debugger proxies of Dart objects
(...skipping 121 matching lines...) Expand 10 before | Expand all | Expand 10 after
904 1151
905 /** 1152 /**
906 * Returns a method that can be called with an arbitrary number (for n less 1153 * Returns a method that can be called with an arbitrary number (for n less
907 * than 11) of arguments without violating Dart type checks. 1154 * than 11) of arguments without violating Dart type checks.
908 */ 1155 */
909 Function _wrapAsDebuggerVarArgsFunction(JsFunction jsFunction) => 1156 Function _wrapAsDebuggerVarArgsFunction(JsFunction jsFunction) =>
910 ([a1 = _UNDEFINED, a2 = _UNDEFINED, a3 = _UNDEFINED, a4 = _UNDEFINED, 1157 ([a1 = _UNDEFINED, a2 = _UNDEFINED, a3 = _UNDEFINED, a4 = _UNDEFINED,
911 a5 = _UNDEFINED, a6 = _UNDEFINED, a7 = _UNDEFINED, a8 = _UNDEFINED, 1158 a5 = _UNDEFINED, a6 = _UNDEFINED, a7 = _UNDEFINED, a8 = _UNDEFINED,
912 a9 = _UNDEFINED, a10 = _UNDEFINED]) => jsFunction._applyDebuggerOnly( 1159 a9 = _UNDEFINED, a10 = _UNDEFINED]) => jsFunction._applyDebuggerOnly(
913 _stripUndefinedArgs([a1, a2, a3, a4, a5, a6, a7, a8, a9, a10])); 1160 _stripUndefinedArgs([a1, a2, a3, a4, a5, a6, a7, a8, a9, a10]));
1161
1162 // This method is a no-op in Dartium.
1163 // TODO(jacobr): tag methods so we can throw if a Dart method is passed to
1164 // JavaScript using the new interop without calling allowInterop.
1165 Function allowInterop(Function f) => f;
1166
1167 Expando<JsFunction> _interopCaptureThisExpando = new Expando<JsFunction>();
1168
1169 Function allowInteropCaptureThis(Function f) {
1170 if (f is JsFunction) {
1171 // Behavior when the function is already a JS function is unspecified.
1172 throw new ArgumentError(
1173 "Function is already a JS function so cannot capture this.");
1174 return f;
1175 } else {
1176 var ret = _interopCaptureThisExpando[f];
1177 if (ret == null) {
1178 ret = new JsFunction.withThis(f);
1179 _interopCaptureThisExpando[f] = ret;
1180 }
1181 return ret;
1182 }
1183 }
OLDNEW
« no previous file with comments | « sdk/lib/html/dartium/html_dartium.dart ('k') | tests/html/js_test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698