| Index: sdk/lib/js/dart2js/js_dart2js.dart
|
| diff --git a/sdk/lib/js/dart2js/js_dart2js.dart b/sdk/lib/js/dart2js/js_dart2js.dart
|
| index 7f806b73f3744794eeca4b725e61093b6cf12008..7fd2726d9ac560f81cfe47ab72884fd48f261721 100644
|
| --- a/sdk/lib/js/dart2js/js_dart2js.dart
|
| +++ b/sdk/lib/js/dart2js/js_dart2js.dart
|
| @@ -4,6 +4,7 @@
|
|
|
| library dart.js;
|
|
|
| +import 'dart:collection' show ListMixin, Maps;
|
| import 'dart:_foreign_helper' show JS;
|
| import 'dart:_js_helper' show convertDartClosureToJS;
|
|
|
| @@ -101,7 +102,7 @@ return ret;
|
| })()''', constr, constr, args));
|
| }
|
|
|
| - factory JsObject._json(data) => new JsObject._fromJs(_convertDataTree(data));
|
| + factory JsObject._json(data) => _convertToDart(_convertDataTree(data));
|
|
|
| static _convertDataTree(data) {
|
| if (data is Map) {
|
| @@ -154,6 +155,8 @@ return ret;
|
| _convertToDart(JS('=Object', '#[#].apply(#, #)', _convertToJS(this), name,
|
| _convertToJS(this),
|
| args == null ? null : args.map(_convertToJS).toList()));
|
| +
|
| + Map<String, dynamic> asDartMap() => new _JsObjectAsMap(this);
|
| }
|
|
|
| class JsFunction extends JsObject implements Serializable<JsFunction> {
|
| @@ -164,6 +167,90 @@ class JsFunction extends JsObject implements Serializable<JsFunction> {
|
| args == null ? null : args.map(_convertToJS).toList()));
|
| }
|
|
|
| +/// A [JsObject] subtype for JavaScript arrays.
|
| +class JsArray extends JsObject with ListMixin {
|
| + JsArray._fromJs(jsObject) : super._fromJs(jsObject);
|
| +
|
| + // methods to implement for ListMixin
|
| +
|
| + int get length => super['length'];
|
| + void set length(int length) { super['length'] = length; }
|
| + operator [](index) {
|
| + if (index is int && (index < 0 || index >= this.length)) {
|
| + throw new RangeError.value(index);
|
| + }
|
| + return super[index];
|
| + }
|
| + void operator []=(index, value) {
|
| + if (index is int && (index < 0 || index >= this.length)) {
|
| + throw new RangeError.value(index);
|
| + }
|
| + super[index] = value;
|
| + }
|
| +
|
| + // overriden methods for better performance
|
| +
|
| + void add(value) { callMethod('push', [value]); }
|
| + void addAll(Iterable iterable) { callMethod('push', iterable.toList()); }
|
| + void sort([int compare(a, b)]) {
|
| + final sortedList = toList()..sort(compare);
|
| + setRange(0, sortedList.length, sortedList);
|
| + }
|
| + void insert(int index, element) {
|
| + callMethod('splice', [index, 0, element]);
|
| + }
|
| + removeAt(int index) {
|
| + if (index < 0 || index >= this.length) throw new RangeError.value(index);
|
| + return callMethod('splice', [index, 1])[0];
|
| + }
|
| + removeLast() => callMethod('pop');
|
| + 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);
|
| + }
|
| + void removeRange(int start, int end) {
|
| + callMethod('splice', [start, end - start]);
|
| + }
|
| +}
|
| +
|
| +class _JsObjectAsMap implements Map<String, dynamic> {
|
| + JsObject _jsObject;
|
| +
|
| + _JsObjectAsMap(this._jsObject);
|
| +
|
| + operator [](String key) => _jsObject[key];
|
| + void operator []=(String key, value) {
|
| + _jsObject[key] = value;
|
| + }
|
| + remove(String key) {
|
| + final value = this[key];
|
| + _jsObject.deleteProperty(key);
|
| + return value;
|
| + }
|
| + Iterable<String> get keys =>
|
| + context['Object'].callMethod('keys', [_jsObject]);
|
| +
|
| + // use Maps to implement functions
|
| + bool containsValue(value) => Maps.containsValue(this, value);
|
| + bool containsKey(String key) => Maps.containsKey(this, key);
|
| + putIfAbsent(String key, ifAbsent()) => Maps.putIfAbsent(this, key, ifAbsent);
|
| + void addAll(Map<String, dynamic> other) {
|
| + if (other != null) {
|
| + other.forEach((k,v) => this[k] = v);
|
| + }
|
| + }
|
| + void clear() => Maps.clear(this);
|
| + void forEach(void f(String key, value)) => Maps.forEach(this, f);
|
| + Iterable get values => Maps.getValues(this);
|
| + int get length => Maps.length(this);
|
| + bool get isEmpty => Maps.isEmpty(this);
|
| + bool get isNotEmpty => Maps.isNotEmpty(this);
|
| +}
|
| +
|
| abstract class Serializable<T> {
|
| T toJs();
|
| }
|
| @@ -179,6 +266,10 @@ dynamic _convertToJS(dynamic o) {
|
| return _convertToJS(o.toJs());
|
| } else if (o is Function) {
|
| return _convertToJS(new Callback(o));
|
| + } else if (o is Map) {
|
| + return _convertToJS(jsify(o));
|
| + } else if (o is Iterable) {
|
| + return _convertToJS(jsify(o));
|
| } else {
|
| return JS('=Object', 'new DartProxy(#)', o);
|
| }
|
| @@ -192,10 +283,12 @@ dynamic _convertToDart(dynamic o) {
|
| JS('bool', 'typeof # == "boolean" || # instanceof Boolean', o, o)) {
|
| return o;
|
| } else if (JS('bool', '# instanceof Function', o)) {
|
| - return new JsFunction._fromJs(JS('=Object', '#', o));
|
| + return new JsFunction._fromJs(JS('var', '#', o));
|
| + } else if (JS('bool', '# instanceof Array', o)) {
|
| + return new JsArray._fromJs(JS('var', '#', o));
|
| } else if (JS('bool', '# instanceof DartProxy', o)) {
|
| return JS('var', '#.o', o);
|
| } else {
|
| - return new JsObject._fromJs(JS('=Object', '#', o));
|
| + return new JsObject._fromJs(JS('var', '#', o));
|
| }
|
| }
|
|
|