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> asDartMap() => 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']; | |
justinfagnani
2013/08/22 18:29:36
The /*@override*/ part is visually noisy. Can you
alexandre.ardhuin
2013/08/23 21:08:33
Unfortunately there's no library 'dart:meta' there
| |
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)) { | |
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; | |
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) ; | |
justinfagnani
2013/08/22 18:29:36
long line
alexandre.ardhuin
2013/08/23 21:08:33
Done.
| |
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('var', '#', o)); |
287 } else if (JS('bool', '# instanceof Array', o)) { | |
288 return new JsArray._fromJs(JS('var', '#', o)); | |
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('var', '#', o)); |
200 } | 293 } |
201 } | 294 } |
OLD | NEW |