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 // methods to implement for ListMixin |
| 175 |
| 176 int get length => super['length']; |
| 177 void set length(int length) { super['length'] = length; } |
| 178 operator [](index) { |
| 179 if (index is int && (index < 0 || index >= this.length)) { |
| 180 throw new RangeError.value(index); |
| 181 } |
| 182 return super[index]; |
| 183 } |
| 184 void operator []=(index, value) { |
| 185 if (index is int && (index < 0 || index >= this.length)) { |
| 186 throw new RangeError.value(index); |
| 187 } |
| 188 super[index] = value; |
| 189 } |
| 190 |
| 191 // overriden methods for better performance |
| 192 |
| 193 void add(value) { callMethod('push', [value]); } |
| 194 void addAll(Iterable iterable) { callMethod('push', iterable.toList()); } |
| 195 void sort([int compare(a, b)]) { |
| 196 final sortedList = toList()..sort(compare); |
| 197 setRange(0, sortedList.length, sortedList); |
| 198 } |
| 199 void insert(int index, element) { |
| 200 callMethod('splice', [index, 0, element]); |
| 201 } |
| 202 removeAt(int index) { |
| 203 if (index < 0 || index >= this.length) throw new RangeError.value(index); |
| 204 return callMethod('splice', [index, 1])[0]; |
| 205 } |
| 206 removeLast() => callMethod('pop'); |
| 207 void setRange(int start, int length, List from, |
| 208 [int startFrom = 0]) { |
| 209 final args = [start, length]; |
| 210 for(int i = startFrom; i < startFrom + length; i++) { |
| 211 args.add(from[i]); |
| 212 } |
| 213 callMethod('splice', args); |
| 214 } |
| 215 void removeRange(int start, int end) { |
| 216 callMethod('splice', [start, end - start]); |
| 217 } |
| 218 } |
| 219 |
| 220 class _JsObjectAsMap implements Map<String, dynamic> { |
| 221 JsObject _jsObject; |
| 222 |
| 223 _JsObjectAsMap(this._jsObject); |
| 224 |
| 225 operator [](String key) => _jsObject[key]; |
| 226 void operator []=(String key, value) { |
| 227 _jsObject[key] = value; |
| 228 } |
| 229 remove(String key) { |
| 230 final value = this[key]; |
| 231 _jsObject.deleteProperty(key); |
| 232 return value; |
| 233 } |
| 234 Iterable<String> get keys => |
| 235 context['Object'].callMethod('keys', [_jsObject]); |
| 236 |
| 237 // use Maps to implement functions |
| 238 bool containsValue(value) => Maps.containsValue(this, value); |
| 239 bool containsKey(String key) => Maps.containsKey(this, key); |
| 240 putIfAbsent(String key, ifAbsent()) => Maps.putIfAbsent(this, key, ifAbsent); |
| 241 void addAll(Map<String, dynamic> other) { |
| 242 if (other != null) { |
| 243 other.forEach((k,v) => this[k] = v); |
| 244 } |
| 245 } |
| 246 void clear() => Maps.clear(this); |
| 247 void forEach(void f(String key, value)) => Maps.forEach(this, f); |
| 248 Iterable get values => Maps.getValues(this); |
| 249 int get length => Maps.length(this); |
| 250 bool get isEmpty => Maps.isEmpty(this); |
| 251 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 |