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 library dart.js; | 5 library dart.js; |
| 6 | 6 |
| 7 import 'dart:collection' show ListMixin, Maps; | |
| 7 import 'dart:_foreign_helper' show JS; | 8 import 'dart:_foreign_helper' show JS; |
| 8 import 'dart:_js_helper' show convertDartClosureToJS; | 9 import 'dart:_js_helper' show convertDartClosureToJS; |
| 9 | 10 |
| 10 JsObject get context { | 11 JsObject get context { |
| 11 return new JsObject._fromJs(JS('=Object', 'window')); | 12 return new JsObject._fromJs(JS('=Object', 'window')); |
| 12 } | 13 } |
| 13 | 14 |
| 14 JsObject jsify(dynamic data) => data == null ? null : new JsObject._json(data); | 15 JsObject jsify(dynamic data) => data == null ? null : new JsObject._json(data); |
| 15 | 16 |
| 16 class Callback implements Serializable<JsFunction> { | 17 class Callback implements Serializable<JsFunction> { |
| (...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 94 return new JsObject._fromJs(JS('=Object', r'''(function(){ | 95 return new JsObject._fromJs(JS('=Object', r'''(function(){ |
| 95 var Type = function(){}; | 96 var Type = function(){}; |
| 96 Type.prototype = #.prototype; | 97 Type.prototype = #.prototype; |
| 97 var instance = new Type(); | 98 var instance = new Type(); |
| 98 ret = #.apply(instance, #); | 99 ret = #.apply(instance, #); |
| 99 ret = Object(ret) === ret ? ret : instance; | 100 ret = Object(ret) === ret ? ret : instance; |
| 100 return ret; | 101 return ret; |
| 101 })()''', constr, constr, args)); | 102 })()''', constr, constr, args)); |
| 102 } | 103 } |
| 103 | 104 |
| 104 factory JsObject._json(data) => new JsObject._fromJs(_convertDataTree(data)); | 105 factory JsObject._json(data) => _convertToDart(_convertDataTree(data)); |
| 105 | 106 |
| 106 static _convertDataTree(data) { | 107 static _convertDataTree(data) { |
| 107 if (data is Map) { | 108 if (data is Map) { |
| 108 final convertedData = JS('=Object', '{}'); | 109 final convertedData = JS('=Object', '{}'); |
| 109 for (var key in data.keys) { | 110 for (var key in data.keys) { |
| 110 JS('=Object', '#[#]=#', convertedData, key, | 111 JS('=Object', '#[#]=#', convertedData, key, |
| 111 _convertDataTree(data[key])); | 112 _convertDataTree(data[key])); |
| 112 } | 113 } |
| 113 return convertedData; | 114 return convertedData; |
| 114 } else if (data is Iterable) { | 115 } else if (data is Iterable) { |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 147 return JS('String', '#.toString()', _convertToJS(this)); | 148 return JS('String', '#.toString()', _convertToJS(this)); |
| 148 } catch(e) { | 149 } catch(e) { |
| 149 return super.toString(); | 150 return super.toString(); |
| 150 } | 151 } |
| 151 } | 152 } |
| 152 | 153 |
| 153 callMethod(String name, [List args]) => | 154 callMethod(String name, [List args]) => |
| 154 _convertToDart(JS('=Object', '#[#].apply(#, #)', _convertToJS(this), name, | 155 _convertToDart(JS('=Object', '#[#].apply(#, #)', _convertToJS(this), name, |
| 155 _convertToJS(this), | 156 _convertToJS(this), |
| 156 args == null ? null : args.map(_convertToJS).toList())); | 157 args == null ? null : args.map(_convertToJS).toList())); |
| 158 | |
| 159 Map<String, dynamic> asJsMap() => new _JsObjectAsMap(this); | |
| 157 } | 160 } |
| 158 | 161 |
| 159 class JsFunction extends JsObject implements Serializable<JsFunction> { | 162 class JsFunction extends JsObject implements Serializable<JsFunction> { |
| 160 JsFunction._fromJs(jsObject) : super._fromJs(jsObject); | 163 JsFunction._fromJs(jsObject) : super._fromJs(jsObject); |
| 161 apply(thisArg, [List args]) => | 164 apply(thisArg, [List args]) => |
| 162 _convertToDart(JS('=Object', '#.apply(#, #)', _convertToJS(this), | 165 _convertToDart(JS('=Object', '#.apply(#, #)', _convertToJS(this), |
| 163 _convertToJS(thisArg), | 166 _convertToJS(thisArg), |
| 164 args == null ? null : args.map(_convertToJS).toList())); | 167 args == null ? null : args.map(_convertToJS).toList())); |
| 165 } | 168 } |
| 166 | 169 |
| 170 /// A [JsObject] subtype for JavaScript arrays. | |
| 171 class JsArray extends JsObject with ListMixin { | |
| 172 JsArray._fromJs(jsObject) : super._fromJs(jsObject); | |
| 173 | |
| 174 // Iterable | |
| 175 /*@override*/ int get length => super['length']; | |
| 176 | |
| 177 // Collection | |
| 178 /*@override*/ void add(value) { callMethod('push', [value]); } | |
| 179 | |
| 180 // List | |
| 181 /*@override*/ operator [](index) { | |
| 182 if (index is int && (index < 0 || index >= this.length)) { | |
|
vsm
2013/08/20 15:44:13
Should JsArray throw on non-int indices?
alexandre.ardhuin
2013/08/20 20:58:55
In Js an array is an object. So it's possible to s
| |
| 183 throw new RangeError.value(index); | |
| 184 } | |
| 185 return super[index]; | |
| 186 } | |
| 187 /*@override*/ void operator []=(index, value) { | |
| 188 if (index is int && (index < 0 || index >= this.length)) { | |
| 189 throw new RangeError.value(index); | |
| 190 } | |
| 191 super[index] = value; | |
| 192 } | |
| 193 /*@override*/ void set length(int length) { super['length'] = length; } | |
| 194 /*@override*/ void sort([int compare(a, b)]) { | |
| 195 final sortedList = toList()..sort(compare); | |
| 196 setRange(0, sortedList.length, sortedList); | |
| 197 } | |
| 198 /*@override*/ void insert(int index, element) { | |
| 199 callMethod('splice', [index, 0, element]); | |
| 200 } | |
| 201 /*@override*/ removeAt(int index) { | |
| 202 if (index < 0 || index >= this.length) throw new RangeError.value(index); | |
| 203 return callMethod('splice', [index, 1])[0]; | |
| 204 } | |
| 205 /*@override*/ removeLast() => callMethod('pop'); | |
| 206 /*@override*/ void setRange(int start, int length, List from, | |
| 207 [int startFrom = 0]) { | |
| 208 final args = [start, length]; | |
| 209 for(int i = startFrom; i < startFrom + length; i++) { | |
| 210 args.add(from[i]); | |
| 211 } | |
| 212 callMethod('splice', args); | |
| 213 } | |
| 214 /*@override*/ void removeRange(int start, int end) { | |
| 215 callMethod('splice', [start, end - start]); | |
| 216 } | |
| 217 } | |
| 218 | |
| 219 class _JsObjectAsMap implements Map<String, dynamic> { | |
| 220 JsObject _jsObject; | |
|
vsm
2013/08/20 15:44:13
It seems odd that Array extends JsObject while Map
alexandre.ardhuin
2013/08/20 20:58:55
Ideally I would have made JsObject implementing Ma
| |
| 221 | |
| 222 _JsObjectAsMap(this._jsObject); | |
| 223 | |
| 224 /*@override*/ operator [](String key) => _jsObject[key]; | |
| 225 /*@override*/ void operator []=(String key, value) { | |
| 226 _jsObject[key] = value; | |
| 227 } | |
| 228 /*@override*/ remove(String key) { | |
| 229 final value = this[key]; | |
| 230 _jsObject.deleteProperty(key); | |
| 231 return value; | |
| 232 } | |
| 233 /*@override*/ Iterable<String> get keys => | |
| 234 context['Object'].callMethod('keys', [_jsObject]); | |
| 235 | |
| 236 // use Maps to implement functions | |
| 237 /*@override*/ bool containsValue(value) => Maps.containsValue(this, value); | |
| 238 /*@override*/ bool containsKey(String key) => Maps.containsKey(this, key); | |
| 239 /*@override*/ putIfAbsent(String key, ifAbsent()) => | |
| 240 Maps.putIfAbsent(this, key, ifAbsent); | |
| 241 /*@override*/ void addAll(Map<String, dynamic> other) { | |
| 242 if (other != null) { | |
| 243 other.forEach((k,v) => this[k] = v); | |
| 244 } | |
| 245 } | |
| 246 /*@override*/ void clear() => Maps.clear(this); | |
| 247 /*@override*/ void forEach(void f(String key, value)) => Maps.forEach(this, f) ; | |
| 248 /*@override*/ Iterable get values => Maps.getValues(this); | |
| 249 /*@override*/ int get length => Maps.length(this); | |
| 250 /*@override*/ bool get isEmpty => Maps.isEmpty(this); | |
| 251 /*@override*/ bool get isNotEmpty => Maps.isNotEmpty(this); | |
| 252 } | |
| 253 | |
| 167 abstract class Serializable<T> { | 254 abstract class Serializable<T> { |
| 168 T toJs(); | 255 T toJs(); |
| 169 } | 256 } |
| 170 | 257 |
| 171 dynamic _convertToJS(dynamic o) { | 258 dynamic _convertToJS(dynamic o) { |
| 172 if (o == null) { | 259 if (o == null) { |
| 173 return null; | 260 return null; |
| 174 } else if (o is String || o is num || o is bool) { | 261 } else if (o is String || o is num || o is bool) { |
| 175 return o; | 262 return o; |
| 176 } else if (o is JsObject) { | 263 } else if (o is JsObject) { |
| 177 return o._jsObject; | 264 return o._jsObject; |
| 178 } else if (o is Serializable) { | 265 } else if (o is Serializable) { |
| 179 return _convertToJS(o.toJs()); | 266 return _convertToJS(o.toJs()); |
| 180 } else if (o is Function) { | 267 } else if (o is Function) { |
| 181 return _convertToJS(new Callback(o)); | 268 return _convertToJS(new Callback(o)); |
| 269 } else if (o is Map) { | |
| 270 return _convertToJS(jsify(o)); | |
| 271 } else if (o is Iterable) { | |
| 272 return _convertToJS(jsify(o)); | |
| 182 } else { | 273 } else { |
| 183 return JS('=Object', 'new DartProxy(#)', o); | 274 return JS('=Object', 'new DartProxy(#)', o); |
| 184 } | 275 } |
| 185 } | 276 } |
| 186 | 277 |
| 187 dynamic _convertToDart(dynamic o) { | 278 dynamic _convertToDart(dynamic o) { |
| 188 if (JS('bool', '# == null', o)) { | 279 if (JS('bool', '# == null', o)) { |
| 189 return null; | 280 return null; |
| 190 } else if (JS('bool', 'typeof # == "string" || # instanceof String', o, o) || | 281 } else if (JS('bool', 'typeof # == "string" || # instanceof String', o, o) || |
| 191 JS('bool', 'typeof # == "number" || # instanceof Number', o, o) || | 282 JS('bool', 'typeof # == "number" || # instanceof Number', o, o) || |
| 192 JS('bool', 'typeof # == "boolean" || # instanceof Boolean', o, o)) { | 283 JS('bool', 'typeof # == "boolean" || # instanceof Boolean', o, o)) { |
| 193 return o; | 284 return o; |
| 194 } else if (JS('bool', '# instanceof Function', o)) { | 285 } else if (JS('bool', '# instanceof Function', o)) { |
| 195 return new JsFunction._fromJs(JS('=Object', '#', o)); | 286 return new JsFunction._fromJs(JS('=Object', '#', o)); |
| 287 } else if (JS('bool', '# instanceof Array', o)) { | |
| 288 return new JsArray._fromJs(JS('=Object', '#', o)); | |
|
vsm
2013/08/20 15:44:13
After talking to sra, I think the right to put her
alexandre.ardhuin
2013/08/20 20:58:55
Done
| |
| 196 } else if (JS('bool', '# instanceof DartProxy', o)) { | 289 } else if (JS('bool', '# instanceof DartProxy', o)) { |
| 197 return JS('var', '#.o', o); | 290 return JS('var', '#.o', o); |
| 198 } else { | 291 } else { |
| 199 return new JsObject._fromJs(JS('=Object', '#', o)); | 292 return new JsObject._fromJs(JS('=Object', '#', o)); |
| 200 } | 293 } |
| 201 } | 294 } |
| OLD | NEW |