Index: sdk/lib/js/dartium/js_dartium.dart |
diff --git a/sdk/lib/js/dartium/js_dartium.dart b/sdk/lib/js/dartium/js_dartium.dart |
index 393320f91ffd8f70fe532342e4164d54a8e452d1..abe02043490e9d4a471fa6d30e97a7a99f8eb524 100644 |
--- a/sdk/lib/js/dartium/js_dartium.dart |
+++ b/sdk/lib/js/dartium/js_dartium.dart |
@@ -66,6 +66,7 @@ |
library dart.js; |
+import 'dart:collection' show ListMixin, Maps; |
import 'dart:html'; |
import 'dart:isolate'; |
@@ -198,6 +199,8 @@ class JsObject implements Serializable<JsObject> { |
return _forward(this, name, 'method', args != null ? args : []); |
} |
+ Map<String, dynamic> asDartMap() => new _JsObjectAsMap(this); |
+ |
// Forward member accesses to the backing JavaScript object. |
static _forward(JsObject receiver, String member, String kind, List args) { |
var result = receiver._port.callSync([receiver._id, member, kind, |
@@ -222,6 +225,90 @@ class JsFunction extends JsObject implements Serializable<JsFunction> { |
} |
} |
+/// A [JsObject] subtype for JavaScript arrays. |
+class JsArray extends JsObject with ListMixin { |
+ JsArray._internal(SendPortSync port, String id) : super._internal(port, id); |
+ |
+ // Iterable |
+ /*@override*/ int get length => super['length']; |
+ |
+ // Collection |
+ /*@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.
|
+ |
+ // List |
+ /*@override*/ operator [](index) { |
+ if (index is int && (index < 0 || index >= this.length)) { |
+ throw new RangeError.value(index); |
+ } |
+ return super[index]; |
+ } |
+ /*@override*/ void operator []=(index, value) { |
+ if (index is int && (index < 0 || index >= this.length)) { |
+ throw new RangeError.value(index); |
+ } |
+ super[index] = value; |
+ } |
+ /*@override*/ void set length(int length) { super['length'] = length; } |
+ /*@override*/ void sort([int compare(a, b)]) { |
+ final sortedList = toList()..sort(compare); |
+ setRange(0, sortedList.length, sortedList); |
+ } |
+ /*@override*/ void insert(int index, element) { |
+ callMethod('splice', [index, 0, element]); |
+ } |
+ /*@override*/ removeAt(int index) { |
+ if (index < 0 || index >= this.length) throw new RangeError.value(index); |
+ return callMethod('splice', [index, 1])[0]; |
+ } |
+ /*@override*/ removeLast() => callMethod('pop'); |
+ /*@override*/ void setRange(int start, int length, List from, |
+ [int startFrom = 0]) { |
+ final args = [start, length]; |
+ for(int i = startFrom; i < startFrom + length; i++) { |
+ args.add(from[i]); |
+ } |
+ callMethod('splice', args); |
+ } |
+ /*@override*/ void removeRange(int start, int end) { |
+ callMethod('splice', [start, end - start]); |
+ } |
+} |
+ |
+class _JsObjectAsMap implements Map<String, dynamic> { |
+ JsObject _jsObject; |
+ |
+ _JsObjectAsMap(this._jsObject); |
+ |
+ /*@override*/ operator [](String key) => _jsObject[key]; |
+ /*@override*/ void operator []=(String key, value) { |
+ _jsObject[key] = value; |
+ } |
+ /*@override*/ remove(String key) { |
+ final value = this[key]; |
+ _jsObject.deleteProperty(key); |
+ return value; |
+ } |
+ /*@override*/ Iterable<String> get keys => |
+ context['Object'].callMethod('keys', [_jsObject]); |
+ |
+ // use Maps to implement functions |
+ /*@override*/ bool containsValue(value) => Maps.containsValue(this, value); |
justinfagnani
2013/08/22 18:29:36
I think containsValue should be implemented in JS
|
+ /*@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
|
+ /*@override*/ putIfAbsent(String key, ifAbsent()) => |
+ Maps.putIfAbsent(this, key, ifAbsent); |
+ /*@override*/ void addAll(Map<String, dynamic> other) { |
justinfagnani
2013/08/22 18:29:36
same here, but more important so that conversion /
|
+ if (other != null) { |
+ other.forEach((k,v) => this[k] = v); |
+ } |
+ } |
+ /*@override*/ void clear() => Maps.clear(this); |
+ /*@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.
|
+ /*@override*/ Iterable get values => Maps.getValues(this); |
justinfagnani
2013/08/22 18:29:36
also implement in JS
|
+ /*@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
|
+ /*@override*/ bool get isEmpty => Maps.isEmpty(this); |
+ /*@override*/ bool get isNotEmpty => Maps.isNotEmpty(this); |
+} |
+ |
/// Marker class used to indicate it is serializable to js. If a class is a |
/// [Serializable] the "toJs" method will be called and the result will be used |
/// as value. |
@@ -318,6 +405,10 @@ _serialize(var message) { |
return _serialize(message.toJs()); |
} else if (message is Function) { |
return _serialize(new Callback(message)); |
+ } else if (message is Map) { |
+ return _serialize(jsify(message)); |
+ } else if (message is Iterable) { |
+ return _serialize(jsify(message)); |
} else { |
// Local object proxy. |
return [ 'objref', |
@@ -351,6 +442,12 @@ _deserialize(var message) { |
} |
} |
+ deserializeArray(message) { |
+ var id = message[1]; |
+ var port = message[2]; |
+ return new JsArray._internal(port, id); |
+ } |
+ |
if (message == null) { |
return null; // Convert undefined to null. |
} else if (message is String || |
@@ -366,6 +463,7 @@ _deserialize(var message) { |
switch (tag) { |
case 'funcref': return deserializeFunction(message); |
case 'objref': return deserializeObject(message); |
+ case 'arrayref': return deserializeArray(message); |
} |
throw 'Unsupported serialized data: $message'; |
} |