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 |