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

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

Issue 23291005: add JsArray and JsObject.asJsMap() Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: rename asJsMap -> asDartMap + change JS type to var Created 7 years, 4 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 | Annotate | Revision Log
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 * The js.dart library provides simple JavaScript invocation from Dart that 6 * The js.dart library provides simple JavaScript invocation from Dart that
7 * works on both Dartium and on other modern browsers via Dart2JS. 7 * works on both Dartium and on other modern browsers via Dart2JS.
8 * 8 *
9 * It provides a model based on scoped [JsObject] objects. Proxies give Dart 9 * It provides a model based on scoped [JsObject] objects. Proxies give Dart
10 * code access to JavaScript objects, fields, and functions as well as the 10 * code access to JavaScript objects, fields, and functions as well as the
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
59 * var foo = new JsObject(context['Foo'], [42]); 59 * var foo = new JsObject(context['Foo'], [42]);
60 * var foo2 = foo.callMethod('add', [foo]); 60 * var foo2 = foo.callMethod('add', [foo]);
61 * print(foo2['x']); 61 * print(foo2['x']);
62 * 62 *
63 * will construct a JavaScript Foo object with the parameter 42, invoke its 63 * will construct a JavaScript Foo object with the parameter 42, invoke its
64 * add method, and return a [JsObject] to a new Foo object whose x field is 84. 64 * add method, and return a [JsObject] to a new Foo object whose x field is 84.
65 */ 65 */
66 66
67 library dart.js; 67 library dart.js;
68 68
69 import 'dart:collection' show ListMixin, Maps;
69 import 'dart:html'; 70 import 'dart:html';
70 import 'dart:isolate'; 71 import 'dart:isolate';
71 72
72 // Global ports to manage communication from Dart to JS. 73 // Global ports to manage communication from Dart to JS.
73 SendPortSync _jsPortSync = window.lookupPort('dart-js-context'); 74 SendPortSync _jsPortSync = window.lookupPort('dart-js-context');
74 SendPortSync _jsPortCreate = window.lookupPort('dart-js-create'); 75 SendPortSync _jsPortCreate = window.lookupPort('dart-js-create');
75 SendPortSync _jsPortInstanceof = window.lookupPort('dart-js-instanceof'); 76 SendPortSync _jsPortInstanceof = window.lookupPort('dart-js-instanceof');
76 SendPortSync _jsPortDeleteProperty = window.lookupPort('dart-js-delete-property' ); 77 SendPortSync _jsPortDeleteProperty = window.lookupPort('dart-js-delete-property' );
77 SendPortSync _jsPortConvert = window.lookupPort('dart-js-convert'); 78 SendPortSync _jsPortConvert = window.lookupPort('dart-js-convert');
78 79
(...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after
191 return _forward(this, 'toString', 'method', []); 192 return _forward(this, 'toString', 'method', []);
192 } catch(e) { 193 } catch(e) {
193 return super.toString(); 194 return super.toString();
194 } 195 }
195 } 196 }
196 197
197 callMethod(String name, [List args]) { 198 callMethod(String name, [List args]) {
198 return _forward(this, name, 'method', args != null ? args : []); 199 return _forward(this, name, 'method', args != null ? args : []);
199 } 200 }
200 201
202 Map<String, dynamic> asDartMap() => new _JsObjectAsMap(this);
203
201 // Forward member accesses to the backing JavaScript object. 204 // Forward member accesses to the backing JavaScript object.
202 static _forward(JsObject receiver, String member, String kind, List args) { 205 static _forward(JsObject receiver, String member, String kind, List args) {
203 var result = receiver._port.callSync([receiver._id, member, kind, 206 var result = receiver._port.callSync([receiver._id, member, kind,
204 args.map(_serialize).toList()]); 207 args.map(_serialize).toList()]);
205 switch (result[0]) { 208 switch (result[0]) {
206 case 'return': return _deserialize(result[1]); 209 case 'return': return _deserialize(result[1]);
207 case 'throws': throw _deserialize(result[1]); 210 case 'throws': throw _deserialize(result[1]);
208 case 'none': throw new NoSuchMethodError(receiver, member, args, {}); 211 case 'none': throw new NoSuchMethodError(receiver, member, args, {});
209 default: throw 'Invalid return value'; 212 default: throw 'Invalid return value';
210 } 213 }
211 } 214 }
212 } 215 }
213 216
214 /// A [JsObject] subtype to JavaScript functions. 217 /// A [JsObject] subtype to JavaScript functions.
215 class JsFunction extends JsObject implements Serializable<JsFunction> { 218 class JsFunction extends JsObject implements Serializable<JsFunction> {
216 JsFunction._internal(SendPortSync port, String id) 219 JsFunction._internal(SendPortSync port, String id)
217 : super._internal(port, id); 220 : super._internal(port, id);
218 221
219 apply(thisArg, [List args]) { 222 apply(thisArg, [List args]) {
220 return JsObject._forward(this, '', 'apply', 223 return JsObject._forward(this, '', 'apply',
221 [thisArg]..addAll(args == null ? [] : args)); 224 [thisArg]..addAll(args == null ? [] : args));
222 } 225 }
223 } 226 }
224 227
228 /// A [JsObject] subtype for JavaScript arrays.
229 class JsArray extends JsObject with ListMixin {
230 JsArray._internal(SendPortSync port, String id) : super._internal(port, id);
231
232 // Iterable
233 /*@override*/ int get length => super['length'];
234
235 // Collection
236 /*@override*/ void add(value) { callMethod('push', [value]); }
justinfagnani 2013/08/22 18:29:36 I think you should override addAll() also. The def
alexandre.ardhuin 2013/08/23 21:08:33 Done.
237
238 // List
239 /*@override*/ operator [](index) {
240 if (index is int && (index < 0 || index >= this.length)) {
241 throw new RangeError.value(index);
242 }
243 return super[index];
244 }
245 /*@override*/ void operator []=(index, value) {
246 if (index is int && (index < 0 || index >= this.length)) {
247 throw new RangeError.value(index);
248 }
249 super[index] = value;
250 }
251 /*@override*/ void set length(int length) { super['length'] = length; }
252 /*@override*/ void sort([int compare(a, b)]) {
253 final sortedList = toList()..sort(compare);
254 setRange(0, sortedList.length, sortedList);
255 }
256 /*@override*/ void insert(int index, element) {
257 callMethod('splice', [index, 0, element]);
258 }
259 /*@override*/ removeAt(int index) {
260 if (index < 0 || index >= this.length) throw new RangeError.value(index);
261 return callMethod('splice', [index, 1])[0];
262 }
263 /*@override*/ removeLast() => callMethod('pop');
264 /*@override*/ void setRange(int start, int length, List from,
265 [int startFrom = 0]) {
266 final args = [start, length];
267 for(int i = startFrom; i < startFrom + length; i++) {
268 args.add(from[i]);
269 }
270 callMethod('splice', args);
271 }
272 /*@override*/ void removeRange(int start, int end) {
273 callMethod('splice', [start, end - start]);
274 }
275 }
276
277 class _JsObjectAsMap implements Map<String, dynamic> {
278 JsObject _jsObject;
279
280 _JsObjectAsMap(this._jsObject);
281
282 /*@override*/ operator [](String key) => _jsObject[key];
283 /*@override*/ void operator []=(String key, value) {
284 _jsObject[key] = value;
285 }
286 /*@override*/ remove(String key) {
287 final value = this[key];
288 _jsObject.deleteProperty(key);
289 return value;
290 }
291 /*@override*/ Iterable<String> get keys =>
292 context['Object'].callMethod('keys', [_jsObject]);
293
294 // use Maps to implement functions
295 /*@override*/ bool containsValue(value) => Maps.containsValue(this, value);
justinfagnani 2013/08/22 18:29:36 I think containsValue should be implemented in JS
296 /*@override*/ bool containsKey(String key) => Maps.containsKey(this, key);
justinfagnani 2013/08/22 18:29:36 same here, but much less important. rather than tr
297 /*@override*/ putIfAbsent(String key, ifAbsent()) =>
298 Maps.putIfAbsent(this, key, ifAbsent);
299 /*@override*/ void addAll(Map<String, dynamic> other) {
justinfagnani 2013/08/22 18:29:36 same here, but more important so that conversion /
300 if (other != null) {
301 other.forEach((k,v) => this[k] = v);
302 }
303 }
304 /*@override*/ void clear() => Maps.clear(this);
305 /*@override*/ void forEach(void f(String key, value)) => Maps.forEach(this, f) ;
justinfagnani 2013/08/22 18:29:36 long line
alexandre.ardhuin 2013/08/23 21:08:33 Done.
306 /*@override*/ Iterable get values => Maps.getValues(this);
justinfagnani 2013/08/22 18:29:36 also implement in JS
307 /*@override*/ int get length => Maps.length(this);
justinfagnani 2013/08/22 18:29:36 these are especially important to implement in JS
alexandre.ardhuin 2013/08/23 21:08:33 The result of "get keys" is not the entire key lis
308 /*@override*/ bool get isEmpty => Maps.isEmpty(this);
309 /*@override*/ bool get isNotEmpty => Maps.isNotEmpty(this);
310 }
311
225 /// Marker class used to indicate it is serializable to js. If a class is a 312 /// Marker class used to indicate it is serializable to js. If a class is a
226 /// [Serializable] the "toJs" method will be called and the result will be used 313 /// [Serializable] the "toJs" method will be called and the result will be used
227 /// as value. 314 /// as value.
228 abstract class Serializable<T> { 315 abstract class Serializable<T> {
229 T toJs(); 316 T toJs();
230 } 317 }
231 318
232 // A table to managed local Dart objects that are proxied in JavaScript. 319 // A table to managed local Dart objects that are proxied in JavaScript.
233 class _ProxiedObjectTable { 320 class _ProxiedObjectTable {
234 // Debugging name. 321 // Debugging name.
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after
311 // Remote function proxy. 398 // Remote function proxy.
312 return [ 'funcref', message._id, message._port ]; 399 return [ 'funcref', message._id, message._port ];
313 } else if (message is JsObject) { 400 } else if (message is JsObject) {
314 // Remote object proxy. 401 // Remote object proxy.
315 return [ 'objref', message._id, message._port ]; 402 return [ 'objref', message._id, message._port ];
316 } else if (message is Serializable) { 403 } else if (message is Serializable) {
317 // use of result of toJs() 404 // use of result of toJs()
318 return _serialize(message.toJs()); 405 return _serialize(message.toJs());
319 } else if (message is Function) { 406 } else if (message is Function) {
320 return _serialize(new Callback(message)); 407 return _serialize(new Callback(message));
408 } else if (message is Map) {
409 return _serialize(jsify(message));
410 } else if (message is Iterable) {
411 return _serialize(jsify(message));
321 } else { 412 } else {
322 // Local object proxy. 413 // Local object proxy.
323 return [ 'objref', 414 return [ 'objref',
324 _proxiedObjectTable.add(message), 415 _proxiedObjectTable.add(message),
325 _proxiedObjectTable.sendPort ]; 416 _proxiedObjectTable.sendPort ];
326 } 417 }
327 } 418 }
328 419
329 _deserialize(var message) { 420 _deserialize(var message) {
330 deserializeFunction(message) { 421 deserializeFunction(message) {
(...skipping 13 matching lines...) Expand all
344 var port = message[2]; 435 var port = message[2];
345 if (port == _proxiedObjectTable.sendPort) { 436 if (port == _proxiedObjectTable.sendPort) {
346 // Local object. 437 // Local object.
347 return _proxiedObjectTable.get(id); 438 return _proxiedObjectTable.get(id);
348 } else { 439 } else {
349 // Remote object. 440 // Remote object.
350 return new JsObject._internal(port, id); 441 return new JsObject._internal(port, id);
351 } 442 }
352 } 443 }
353 444
445 deserializeArray(message) {
446 var id = message[1];
447 var port = message[2];
448 return new JsArray._internal(port, id);
449 }
450
354 if (message == null) { 451 if (message == null) {
355 return null; // Convert undefined to null. 452 return null; // Convert undefined to null.
356 } else if (message is String || 453 } else if (message is String ||
357 message is num || 454 message is num ||
358 message is bool) { 455 message is bool) {
359 // Primitives are passed directly through. 456 // Primitives are passed directly through.
360 return message; 457 return message;
361 } else if (message is SendPortSync) { 458 } else if (message is SendPortSync) {
362 // Serialized type. 459 // Serialized type.
363 return message; 460 return message;
364 } 461 }
365 var tag = message[0]; 462 var tag = message[0];
366 switch (tag) { 463 switch (tag) {
367 case 'funcref': return deserializeFunction(message); 464 case 'funcref': return deserializeFunction(message);
368 case 'objref': return deserializeObject(message); 465 case 'objref': return deserializeObject(message);
466 case 'arrayref': return deserializeArray(message);
369 } 467 }
370 throw 'Unsupported serialized data: $message'; 468 throw 'Unsupported serialized data: $message';
371 } 469 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698