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:html' show Blob, ImageData, Node; | 7 import 'dart:html' show Blob, ImageData, Node; |
| 8 import 'dart:collection' show HashMap; | 8 import 'dart:collection' show HashMap, ListMixin; |
| 9 import 'dart:indexed_db' show KeyRange; | 9 import 'dart:indexed_db' show KeyRange; |
| 10 import 'dart:typed_data' show TypedData; | 10 import 'dart:typed_data' show TypedData; |
| 11 | 11 |
| 12 import 'dart:_foreign_helper' show JS, DART_CLOSURE_TO_JS; | 12 import 'dart:_foreign_helper' show JS, DART_CLOSURE_TO_JS; |
| 13 import 'dart:_interceptors' show JavaScriptObject, UnknownJavaScriptObject; | 13 import 'dart:_interceptors' show JavaScriptObject, UnknownJavaScriptObject; |
| 14 import 'dart:_js_helper' show Primitives, convertDartClosureToJS; | 14 import 'dart:_js_helper' show Primitives, convertDartClosureToJS; |
| 15 | 15 |
| 16 final JsObject context = new JsObject._fromJs(Primitives.computeGlobalThis()); | 16 final JsObject context = new JsObject._fromJs(Primitives.computeGlobalThis()); |
| 17 | 17 |
| 18 _convertDartFunction(Function f, {bool captureThis: false}) { | 18 _convertDartFunction(Function f, {bool captureThis: false}) { |
| 19 return JS('', | 19 return JS('', |
| 20 'function(_call, f, captureThis) {' | 20 'function(_call, f, captureThis) {' |
| 21 'return function() {' | 21 'return function() {' |
| 22 'return _call(f, captureThis, this, ' | 22 'return _call(f, captureThis, this, ' |
| 23 'Array.prototype.slice.apply(arguments));' | 23 'Array.prototype.slice.apply(arguments));' |
| 24 '}' | 24 '}' |
| 25 '}(#, #, #)', DART_CLOSURE_TO_JS(_callDartFunction), f, captureThis); | 25 '}(#, #, #)', DART_CLOSURE_TO_JS(_callDartFunction), f, captureThis); |
| 26 } | 26 } |
| 27 | 27 |
| 28 _callDartFunction(callback, bool captureThis, self, List arguments) { | 28 _callDartFunction(callback, bool captureThis, self, List arguments) { |
| 29 if (captureThis) { | 29 if (captureThis) { |
| 30 arguments = [self]..addAll(arguments); | 30 arguments = [self]..addAll(arguments); |
| 31 } | 31 } |
| 32 var dartArgs = arguments.map(_convertToDart).toList(); | 32 var dartArgs = new List.from(arguments.map(_convertToDart)); |
| 33 return _convertToJS(Function.apply(callback, dartArgs)); | 33 return _convertToJS(Function.apply(callback, dartArgs)); |
| 34 } | 34 } |
| 35 | 35 |
| 36 | 36 |
| 37 class JsObject { | 37 class JsObject { |
| 38 // The wrapped JS object. | 38 // The wrapped JS object. |
| 39 final dynamic _jsObject; | 39 final dynamic _jsObject; |
| 40 | 40 |
| 41 JsObject._fromJs(this._jsObject) { | 41 JsObject._fromJs(this._jsObject) { |
| 42 assert(_jsObject != null); | 42 assert(_jsObject != null); |
| (...skipping 137 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 180 return super.toString(); | 180 return super.toString(); |
| 181 } | 181 } |
| 182 } | 182 } |
| 183 | 183 |
| 184 dynamic callMethod(name, [List args]) { | 184 dynamic callMethod(name, [List args]) { |
| 185 if (name is! String && name is! num) { | 185 if (name is! String && name is! num) { |
| 186 throw new ArgumentError("name is not a String or num"); | 186 throw new ArgumentError("name is not a String or num"); |
| 187 } | 187 } |
| 188 return _convertToDart(JS('', '#[#].apply(#, #)', _jsObject, name, | 188 return _convertToDart(JS('', '#[#].apply(#, #)', _jsObject, name, |
| 189 _jsObject, | 189 _jsObject, |
| 190 args == null ? null : args.map(_convertToJS).toList())); | 190 args == null ? null : new List.from(args.map(_convertToJS)))); |
| 191 } | 191 } |
| 192 } | 192 } |
| 193 | 193 |
| 194 class JsFunction extends JsObject { | 194 class JsFunction extends JsObject { |
| 195 | 195 |
| 196 /** | 196 /** |
| 197 * Returns a [JsFunction] that captures its 'this' binding and calls [f] | 197 * Returns a [JsFunction] that captures its 'this' binding and calls [f] |
| 198 * with the value of this passed as the first argument. | 198 * with the value of this passed as the first argument. |
| 199 */ | 199 */ |
| 200 factory JsFunction.withThis(Function f) { | 200 factory JsFunction.withThis(Function f) { |
| 201 var jsFunc = _convertDartFunction(f, captureThis: true); | 201 var jsFunc = _convertDartFunction(f, captureThis: true); |
| 202 return new JsFunction._fromJs(jsFunc); | 202 return new JsFunction._fromJs(jsFunc); |
| 203 } | 203 } |
| 204 | 204 |
| 205 JsFunction._fromJs(jsObject) : super._fromJs(jsObject); | 205 JsFunction._fromJs(jsObject) : super._fromJs(jsObject); |
| 206 | 206 |
| 207 dynamic apply(List args, { thisArg }) => | 207 dynamic apply(List args, { thisArg }) => |
| 208 _convertToDart(JS('', '#.apply(#, #)', _jsObject, | 208 _convertToDart(JS('', '#.apply(#, #)', _jsObject, |
| 209 _convertToJS(thisArg), | 209 _convertToJS(thisArg), |
| 210 args == null ? null : args.map(_convertToJS).toList())); | 210 args == null ? null : new List.from(args.map(_convertToJS)))); |
| 211 } | |
| 212 | |
| 213 /** | |
| 214 * A [List] that is stored in a JavaScript array. | |
| 215 */ | |
| 216 class JsArray<E> extends JsObject with ListMixin<E> { | |
| 217 | |
| 218 JsArray() : super._fromJs([]); | |
| 219 | |
| 220 JsArray.from(Iterable<E> other) | |
| 221 : super._fromJs([]..addAll(other.map(_convertToJS))); | |
| 222 | |
| 223 JsArray._fromJs(jsObject) : super._fromJs(jsObject); | |
| 224 | |
| 225 _checkIndex(int index, {bool insert: false}) { | |
|
Jacob
2013/10/24 21:02:09
why not have two check index methods? one for inse
justinfagnani
2013/10/26 03:26:52
Done.
| |
| 226 int length = insert ? this.length + 1 : this.length; | |
| 227 if (index is int && (index < 0 || index >= length)) { | |
| 228 throw new RangeError.range(index, 0, length); | |
| 229 } | |
| 230 } | |
| 231 | |
| 232 _checkRange(int start, int end) { | |
| 233 if (start < 0 || start > this.length) { | |
| 234 throw new RangeError.range(start, 0, this.length); | |
| 235 } | |
| 236 if (end < start || end > this.length) { | |
| 237 throw new RangeError.range(end, start, this.length); | |
| 238 } | |
| 239 } | |
| 240 | |
| 241 // Methods required by ListMixin | |
| 242 | |
| 243 E operator [](int index) { | |
| 244 _checkIndex(index); | |
| 245 return super[index]; | |
| 246 } | |
| 247 | |
| 248 void operator []=(int index, E value) { | |
| 249 _checkIndex(index); | |
| 250 super[index] = value; | |
| 251 } | |
| 252 | |
| 253 int get length => super['length']; | |
| 254 | |
| 255 void set length(int length) { super['length'] = length; } | |
| 256 | |
| 257 | |
| 258 // Methods overriden for better performance | |
| 259 | |
| 260 void add(E value) { | |
| 261 callMethod('push', [value]); | |
| 262 } | |
| 263 | |
| 264 void addAll(Iterable<E> iterable) { | |
| 265 var list = (JS('bool', '# instanceof Array', iterable)) | |
| 266 ? iterable | |
| 267 : new List.from(iterable); | |
| 268 callMethod('push', list); | |
| 269 } | |
| 270 | |
| 271 void insert(int index, E element) { | |
| 272 _checkIndex(index, insert:true); | |
| 273 callMethod('splice', [index, 0, element]); | |
| 274 } | |
| 275 | |
| 276 E removeAt(int index) { | |
| 277 _checkIndex(index); | |
| 278 return callMethod('splice', [index, 1])[0]; | |
| 279 } | |
| 280 | |
| 281 E removeLast() { | |
| 282 if (length == 0) throw new RangeError(-1); | |
| 283 return callMethod('pop'); | |
| 284 } | |
| 285 | |
| 286 void removeRange(int start, int end) { | |
| 287 _checkRange(start, end); | |
| 288 callMethod('splice', [start, end - start]); | |
| 289 } | |
| 290 | |
| 291 void setRange(int start, int end, Iterable<E> iterable, [int skipCount = 0]) { | |
| 292 _checkRange(start, end); | |
| 293 int length = end - start; | |
| 294 if (length == 0) return; | |
| 295 if (skipCount < 0) throw new ArgumentError(skipCount); | |
| 296 var args = [start, length]..addAll(iterable.skip(skipCount).take(length)); | |
| 297 callMethod('splice', args); | |
| 298 } | |
| 299 | |
| 300 void sort([int compare(E a, E b)]) { | |
| 301 callMethod('sort', [compare]); | |
| 302 } | |
| 211 } | 303 } |
| 212 | 304 |
| 213 // property added to a Dart object referencing its JS-side DartObject proxy | 305 // property added to a Dart object referencing its JS-side DartObject proxy |
| 214 const _DART_OBJECT_PROPERTY_NAME = r'_$dart_dartObject'; | 306 const _DART_OBJECT_PROPERTY_NAME = r'_$dart_dartObject'; |
| 215 const _DART_CLOSURE_PROPERTY_NAME = r'_$dart_dartClosure'; | 307 const _DART_CLOSURE_PROPERTY_NAME = r'_$dart_dartClosure'; |
| 216 | 308 |
| 217 // property added to a JS object referencing its Dart-side JsObject proxy | 309 // property added to a JS object referencing its Dart-side JsObject proxy |
| 218 const _JS_OBJECT_PROPERTY_NAME = r'_$dart_jsObject'; | 310 const _JS_OBJECT_PROPERTY_NAME = r'_$dart_jsObject'; |
| 219 const _JS_FUNCTION_PROPERTY_NAME = r'$dart_jsFunction'; | 311 const _JS_FUNCTION_PROPERTY_NAME = r'$dart_jsFunction'; |
| 220 | 312 |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 274 return o; | 366 return o; |
| 275 } else if (o is Blob || o is KeyRange || o is ImageData || o is Node | 367 } else if (o is Blob || o is KeyRange || o is ImageData || o is Node |
| 276 || o is TypedData) { | 368 || o is TypedData) { |
| 277 return JS('Blob|KeyRange|ImageData|Node|TypedData', '#', o); | 369 return JS('Blob|KeyRange|ImageData|Node|TypedData', '#', o); |
| 278 } else if (JS('bool', '# instanceof Date', o)) { | 370 } else if (JS('bool', '# instanceof Date', o)) { |
| 279 var ms = JS('num', '#.getMilliseconds()', o); | 371 var ms = JS('num', '#.getMilliseconds()', o); |
| 280 return new DateTime.fromMillisecondsSinceEpoch(ms); | 372 return new DateTime.fromMillisecondsSinceEpoch(ms); |
| 281 } else if (JS('bool', 'typeof # == "function"', o)) { | 373 } else if (JS('bool', 'typeof # == "function"', o)) { |
| 282 return _getDartProxy(o, _DART_CLOSURE_PROPERTY_NAME, | 374 return _getDartProxy(o, _DART_CLOSURE_PROPERTY_NAME, |
| 283 (o) => new JsFunction._fromJs(o)); | 375 (o) => new JsFunction._fromJs(o)); |
| 376 } else if (JS('bool', '# instanceof Array', o)) { | |
| 377 return _getDartProxy(o, _DART_OBJECT_PROPERTY_NAME, | |
| 378 (o) => new JsArray._fromJs(o)); | |
| 284 } else if (JS('bool', '#.constructor === DartObject', o)) { | 379 } else if (JS('bool', '#.constructor === DartObject', o)) { |
| 285 return JS('', '#.o', o); | 380 return JS('', '#.o', o); |
| 286 } else { | 381 } else { |
| 287 return _getDartProxy(o, _DART_OBJECT_PROPERTY_NAME, | 382 return _getDartProxy(o, _DART_OBJECT_PROPERTY_NAME, |
| 288 (o) => new JsObject._fromJs(o)); | 383 (o) => new JsObject._fromJs(o)); |
| 289 } | 384 } |
| 290 } | 385 } |
| 291 | 386 |
| 292 Object _getDartProxy(o, String propertyName, createProxy(o)) { | 387 Object _getDartProxy(o, String propertyName, createProxy(o)) { |
| 293 var dartProxy = JS('', '#[#]', o, propertyName); | 388 var dartProxy = JS('', '#[#]', o, propertyName); |
| 294 if (dartProxy == null) { | 389 if (dartProxy == null) { |
| 295 dartProxy = createProxy(o); | 390 dartProxy = createProxy(o); |
| 296 _defineProperty(o, propertyName, dartProxy); | 391 _defineProperty(o, propertyName, dartProxy); |
| 297 } | 392 } |
| 298 return dartProxy; | 393 return dartProxy; |
| 299 } | 394 } |
| OLD | NEW |