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 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 80 * `a` and `b` defined: | 80 * `a` and `b` defined: |
| 81 * | 81 * |
| 82 * var jsMap = new JsObject.jsify({'a': 1, 'b': 2}); | 82 * var jsMap = new JsObject.jsify({'a': 1, 'b': 2}); |
| 83 * | 83 * |
| 84 * This expression creates a JavaScript array: | 84 * This expression creates a JavaScript array: |
| 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:async' show Zone; | |
| 90 import 'dart:collection' show ListMixin; | 91 import 'dart:collection' show ListMixin; |
| 91 import 'dart:nativewrappers'; | 92 import 'dart:nativewrappers'; |
| 92 | 93 |
| 93 JsObject _cachedContext; | 94 JsObject _cachedContext; |
| 94 | 95 |
| 95 JsObject get _context native "Js_context_Callback"; | 96 JsObject get _context native "Js_context_Callback"; |
| 96 | 97 |
| 97 JsObject get context { | 98 JsObject get context { |
| 98 if (_cachedContext == null) { | 99 if (_cachedContext == null) { |
| 99 _cachedContext = _context; | 100 _cachedContext = _context; |
| (...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 164 * The type of [property] must be either [String] or [num]. | 165 * The type of [property] must be either [String] or [num]. |
| 165 */ | 166 */ |
| 166 operator[](property) native "JsObject_[]"; | 167 operator[](property) native "JsObject_[]"; |
| 167 | 168 |
| 168 /** | 169 /** |
| 169 * Sets the value associated with [property] on the proxied JavaScript | 170 * Sets the value associated with [property] on the proxied JavaScript |
| 170 * object. | 171 * object. |
| 171 * | 172 * |
| 172 * The type of [property] must be either [String] or [num]. | 173 * The type of [property] must be either [String] or [num]. |
| 173 */ | 174 */ |
| 174 operator[]=(property, value) native "JsObject_[]="; | 175 operator[]=(property, value) { |
| 176 return _setIndex(property, _maybeWrapFunction(value)); | |
| 177 } | |
| 178 | |
| 179 Object _setIndex(property, value) native "JsObject_[]="; | |
| 175 | 180 |
| 176 int get hashCode native "JsObject_hashCode"; | 181 int get hashCode native "JsObject_hashCode"; |
| 177 | 182 |
| 178 operator==(other) => other is JsObject && _identityEquality(this, other); | 183 operator==(other) => other is JsObject && _identityEquality(this, other); |
| 179 | 184 |
| 180 static bool _identityEquality(JsObject a, JsObject b) native "JsObject_identit yEquality"; | 185 static bool _identityEquality(JsObject a, JsObject b) native "JsObject_identit yEquality"; |
| 181 | 186 |
| 182 /** | 187 /** |
| 183 * Returns `true` if the JavaScript object contains the specified property | 188 * Returns `true` if the JavaScript object contains the specified property |
| 184 * either directly or though its prototype chain. | 189 * either directly or though its prototype chain. |
| (...skipping 30 matching lines...) Expand all Loading... | |
| 215 String _toString() native "JsObject_toString"; | 220 String _toString() native "JsObject_toString"; |
| 216 | 221 |
| 217 /** | 222 /** |
| 218 * Calls [method] on the JavaScript object with the arguments [args] and | 223 * Calls [method] on the JavaScript object with the arguments [args] and |
| 219 * returns the result. | 224 * returns the result. |
| 220 * | 225 * |
| 221 * The type of [method] must be either [String] or [num]. | 226 * The type of [method] must be either [String] or [num]. |
| 222 */ | 227 */ |
| 223 callMethod(String method, [List args]) { | 228 callMethod(String method, [List args]) { |
| 224 try { | 229 try { |
| 230 args = args == null ? null : args.map(_maybeWrapFunction).toList(); | |
| 225 return _callMethod(method, args); | 231 return _callMethod(method, args); |
| 226 } catch(e) { | 232 } catch(e) { |
| 227 if (hasProperty(method)) { | 233 if (hasProperty(method)) { |
| 228 rethrow; | 234 rethrow; |
| 229 } else { | 235 } else { |
| 230 throw new NoSuchMethodError(this, new Symbol(method), args, null); | 236 throw new NoSuchMethodError(this, new Symbol(method), args, null); |
| 231 } | 237 } |
| 232 } | 238 } |
| 233 } | 239 } |
| 234 | 240 |
| 235 _callMethod(String name, List args) native "JsObject_callMethod"; | 241 _callMethod(String name, List args) native "JsObject_callMethod"; |
| 236 } | 242 } |
| 237 | 243 |
| 238 /** | 244 /** |
| 239 * Proxies a JavaScript Function object. | 245 * Proxies a JavaScript Function object. |
| 240 */ | 246 */ |
| 241 class JsFunction extends JsObject { | 247 class JsFunction extends JsObject { |
| 242 JsFunction.internal() : super.internal(); | 248 JsFunction.internal() : super.internal(); |
| 243 | 249 |
| 244 /** | 250 /** |
| 245 * Returns a [JsFunction] that captures its 'this' binding and calls [f] | 251 * Returns a [JsFunction] that captures its 'this' binding and calls [f] |
| 246 * with the value of this passed as the first argument. | 252 * with the value of this passed as the first argument. |
| 247 */ | 253 */ |
| 248 factory JsFunction.withThis(Function f) => _withThis(f); | 254 factory JsFunction.withThis(Function f) => _withThis(_maybeWrapFunction(f)); |
| 249 | 255 |
| 250 /** | 256 /** |
| 251 * Invokes the JavaScript function with arguments [args]. If [thisArg] is | 257 * Invokes the JavaScript function with arguments [args]. If [thisArg] is |
| 252 * supplied it is the value of `this` for the invocation. | 258 * supplied it is the value of `this` for the invocation. |
| 253 */ | 259 */ |
| 254 dynamic apply(List args, {thisArg}) native "JsFunction_apply"; | 260 dynamic apply(List args, {thisArg}) native "JsFunction_apply"; |
| 255 | 261 |
| 256 /** | 262 /** |
| 257 * Internal only version of apply which uses debugger proxies of Dart objects | 263 * Internal only version of apply which uses debugger proxies of Dart objects |
| 258 * rather than opaque handles. This method is private because it cannot be | 264 * rather than opaque handles. This method is private because it cannot be |
| (...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 352 if (skipCount < 0) throw new ArgumentError(skipCount); | 358 if (skipCount < 0) throw new ArgumentError(skipCount); |
| 353 var args = [start, length]..addAll(iterable.skip(skipCount).take(length)); | 359 var args = [start, length]..addAll(iterable.skip(skipCount).take(length)); |
| 354 callMethod('splice', args); | 360 callMethod('splice', args); |
| 355 } | 361 } |
| 356 | 362 |
| 357 void sort([int compare(E a, E b)]) { | 363 void sort([int compare(E a, E b)]) { |
| 358 callMethod('sort', [compare]); | 364 callMethod('sort', [compare]); |
| 359 } | 365 } |
| 360 } | 366 } |
| 361 | 367 |
| 368 _maybeWrapFunction(value) { | |
| 369 if (value is Function) return _applyZoned(value); | |
|
Jacob
2014/04/10 00:51:53
nit: the following is cleaner.
_maybeWrapFunction(
justinfagnani
2014/04/10 03:55:05
Done.
| |
| 370 return value; | |
| 371 } | |
| 372 | |
| 373 _applyZoned(f) { | |
| 374 var call = (List arguments) => Function.apply(f, arguments); | |
| 375 if (Zone.current == Zone.ROOT) return call; | |
| 376 return Zone.current.bindUnaryCallback(call); | |
| 377 } | |
| 378 | |
| 362 /** | 379 /** |
| 363 * Placeholder object for cases where we need to determine exactly how many | 380 * Placeholder object for cases where we need to determine exactly how many |
| 364 * args were passed to a function. | 381 * args were passed to a function. |
| 365 */ | 382 */ |
| 366 const _UNDEFINED = const Object(); | 383 const _UNDEFINED = const Object(); |
| 367 | 384 |
| 368 // FIXME(jacobr): this method is a hack to work around the lack of proper dart | 385 // FIXME(jacobr): this method is a hack to work around the lack of proper dart |
| 369 // support for varargs methods. | 386 // support for varargs methods. |
| 370 List _stripUndefinedArgs(List args) => | 387 List _stripUndefinedArgs(List args) => |
| 371 args.takeWhile((i) => i != _UNDEFINED).toList(); | 388 args.takeWhile((i) => i != _UNDEFINED).toList(); |
| 372 | 389 |
| 373 /** | 390 /** |
| 374 * Returns a method that can be called with an arbitrary number (for n less | 391 * Returns a method that can be called with an arbitrary number (for n less |
| 375 * than 11) of arguments without violating Dart type checks. | 392 * than 11) of arguments without violating Dart type checks. |
| 376 */ | 393 */ |
| 377 Function _wrapAsDebuggerVarArgsFunction(JsFunction jsFunction) => | 394 Function _wrapAsDebuggerVarArgsFunction(JsFunction jsFunction) => |
| 378 ([a1=_UNDEFINED, a2=_UNDEFINED, a3=_UNDEFINED, a4=_UNDEFINED, | 395 ([a1=_UNDEFINED, a2=_UNDEFINED, a3=_UNDEFINED, a4=_UNDEFINED, |
| 379 a5=_UNDEFINED, a6=_UNDEFINED, a7=_UNDEFINED, a8=_UNDEFINED, | 396 a5=_UNDEFINED, a6=_UNDEFINED, a7=_UNDEFINED, a8=_UNDEFINED, |
| 380 a9=_UNDEFINED, a10=_UNDEFINED]) => | 397 a9=_UNDEFINED, a10=_UNDEFINED]) => |
| 381 jsFunction._applyDebuggerOnly(_stripUndefinedArgs( | 398 jsFunction._applyDebuggerOnly(_stripUndefinedArgs( |
| 382 [a1,a2,a3,a4,a5,a6,a7,a8,a9,a10])); | 399 [a1,a2,a3,a4,a5,a6,a7,a8,a9,a10])); |
| OLD | NEW |