OLD | NEW |
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, 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 // Patch file for the dart:async library. | 5 // Patch file for the dart:async library. |
6 | 6 |
7 import 'dart:_isolate_helper' show TimerImpl; | 7 import 'dart:_isolate_helper' show TimerImpl; |
| 8 import 'dart:_foreign_helper' show JS; |
8 | 9 |
9 patch class Timer { | 10 patch class Timer { |
10 patch factory Timer(int milliseconds, void callback(Timer timer)) { | 11 patch factory Timer(int milliseconds, void callback(Timer timer)) { |
11 return new TimerImpl(milliseconds, callback); | 12 return new TimerImpl(milliseconds, callback); |
12 } | 13 } |
13 | 14 |
14 /** | 15 /** |
15 * Creates a new repeating timer. The [callback] is invoked every | 16 * Creates a new repeating timer. The [callback] is invoked every |
16 * [milliseconds] millisecond until cancelled. | 17 * [milliseconds] millisecond until cancelled. |
17 */ | 18 */ |
18 patch factory Timer.repeating(int milliseconds, void callback(Timer timer)) { | 19 patch factory Timer.repeating(int milliseconds, void callback(Timer timer)) { |
19 return new TimerImpl.repeating(milliseconds, callback); | 20 return new TimerImpl.repeating(milliseconds, callback); |
20 } | 21 } |
21 } | 22 } |
| 23 |
| 24 // TODO(ahe): This should not only apply to this isolate. |
| 25 final _loadedLibraries = <String, Completer<bool>>{}; |
| 26 |
| 27 patch Future<bool> load(String libraryName, {String uri}) { |
| 28 // TODO(ahe): Validate libraryName. Kasper points out that you want |
| 29 // to be able to experiment with the effect of toggling @DeferLoad, |
| 30 // so perhaps we should silently ignore "bad" library names. |
| 31 Completer completer = new Completer<bool>(); |
| 32 Future<bool> future = _loadedLibraries[libraryName]; |
| 33 if (future != null) { |
| 34 future.then((_) { completer.complete(false); }); |
| 35 return completer.future; |
| 36 } |
| 37 _loadedLibraries[libraryName] = completer.future; |
| 38 |
| 39 if (uri == null) { |
| 40 uri = _currentScriptUri; |
| 41 int index = JS('int', '#.lastIndexOf("/")', uri); |
| 42 uri = JS('String', '#.substring(0, # + 1) + #', uri, index, "part.js"); |
| 43 } |
| 44 |
| 45 if (_hasDocument) { |
| 46 // Inject a script tag. |
| 47 var script = JS('', 'document.createElement("script")'); |
| 48 JS('', '#.type = "text/javascript"', script); |
| 49 JS('', '#.async = "async"', script); |
| 50 JS('', '#.src = #', script, uri); |
| 51 var onLoad = JS('', '#.bind(null, #)', |
| 52 DART_CLOSURE_TO_JS(_onDeferredLibraryLoad), completer); |
| 53 JS('', '#.addEventListener("load", #, false)', script, onLoad); |
| 54 JS('', 'document.body.appendChild(#)', script); |
| 55 } else if (JS('String', 'typeof load') == 'function') { |
| 56 new Timer(0, (_) { |
| 57 JS('void', 'load(#)', uri); |
| 58 completer.complete(true); |
| 59 }); |
| 60 } else { |
| 61 throw new UnsupportedError('load not supported'); |
| 62 } |
| 63 return completer.future; |
| 64 } |
| 65 |
| 66 /// Used to implement deferred loading. Used as callback on "load" |
| 67 /// event above in [load]. |
| 68 _onDeferredLibraryLoad(Completer<bool> completer, event) { |
| 69 completer.complete(true); |
| 70 } |
| 71 |
| 72 bool get _hasDocument => JS('String', 'typeof document') == 'object'; |
| 73 |
| 74 /// Returns the URI of the current script (as a string). |
| 75 // TODO(ahe): Share with IsolateNatives.computeThisScript. |
| 76 String get _currentScriptUri() { |
| 77 // TODO(ahe): The following works in Firefox during loading of the |
| 78 // script, and is being considered for the standard. |
| 79 // if (_hasDocument) { |
| 80 // var currentScript = JS('', 'document.currentScript'); |
| 81 // if (JS('String', 'typeof #', currentScript) == 'object') { |
| 82 // return JS('String', '#.src', currentScript); |
| 83 // } |
| 84 // } |
| 85 |
| 86 var stack = JS('String|Null', 'new Error().stack'); |
| 87 if (stack == null) { |
| 88 // According to Internet Explorer documentation, the stack |
| 89 // property is not set until the exception is thrown. |
| 90 stack = JS('String', |
| 91 'function() {try{throw new Error()}catch(e){return e.stack}}'); |
| 92 } |
| 93 var pattern, matches; |
| 94 |
| 95 // This pattern matches V8, Chrome, and Internet Explorer stack |
| 96 // traces that look like this: |
| 97 // Error |
| 98 // at methodName (URI:LINE:COLUMN) |
| 99 pattern = JS('', r'new RegExp("^ *at (.*):[0-9]*:[0-9]*$", "m")'); |
| 100 |
| 101 matches = JS('', '#.match(#)', stack, pattern); |
| 102 if (matches != null) return matches[1]; |
| 103 |
| 104 // This pattern matches Firefox stack traces that look like this: |
| 105 // methodName@URI:LINE |
| 106 pattern = JS('', r'new RegExp("^[^@]*@(.*):[0-9]*$", "m")'); |
| 107 |
| 108 matches = JS('', '#.match(#)', stack, pattern); |
| 109 if (matches != null) return matches[1]; |
| 110 |
| 111 throw new UnsupportedError('Cannot extract URI from "$stack"'); |
| 112 } |
OLD | NEW |