| 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 _js_helper; | 5 library _js_helper; |
| 6 | 6 |
| 7 import 'dart:collection'; | 7 import 'dart:collection'; |
| 8 import 'dart:_isolate_helper' show | 8 import 'dart:_isolate_helper' show |
| 9 IsolateNatives, | 9 IsolateNatives, |
| 10 leaveJsAsync, | 10 leaveJsAsync, |
| (...skipping 3205 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3216 * DOM isolates. This happens when multiple programs are loaded in the same | 3216 * DOM isolates. This happens when multiple programs are loaded in the same |
| 3217 * JavaScript context (i.e. page). The name is based on [name] but with an | 3217 * JavaScript context (i.e. page). The name is based on [name] but with an |
| 3218 * additional part that is unique for each isolate. | 3218 * additional part that is unique for each isolate. |
| 3219 * | 3219 * |
| 3220 * The form of the name is '___dart_$name_$id'. | 3220 * The form of the name is '___dart_$name_$id'. |
| 3221 */ | 3221 */ |
| 3222 String getIsolateAffinityTag(String name) { | 3222 String getIsolateAffinityTag(String name) { |
| 3223 return JS('String', 'init.getIsolateTag(#)', name); | 3223 return JS('String', 'init.getIsolateTag(#)', name); |
| 3224 } | 3224 } |
| 3225 | 3225 |
| 3226 typedef Future<bool> LoadLibraryFunctionType(); | 3226 typedef Future<Null> LoadLibraryFunctionType(); |
| 3227 | 3227 |
| 3228 LoadLibraryFunctionType _loadLibraryWrapper(String loadId) { | 3228 LoadLibraryFunctionType _loadLibraryWrapper(String loadId) { |
| 3229 return () => loadDeferredLibrary(loadId); | 3229 return () => loadDeferredLibrary(loadId); |
| 3230 } | 3230 } |
| 3231 | 3231 |
| 3232 final Map<String, Future<bool>> _loadedLibraries = <String, Future<bool>>{}; | 3232 final Map<String, Future<Null>> _loadedLibraries = <String, Future<Null>>{}; |
| 3233 | 3233 |
| 3234 Future<bool> loadDeferredLibrary(String loadId, [String uri]) { | 3234 Future<bool> loadDeferredLibrary(String loadId, [String uri]) { |
| 3235 List hunkNames = new List(); | 3235 |
| 3236 if (JS('bool', '\$.libraries_to_load[#] === undefined', loadId)) { | 3236 List<List<String>> hunkLists = JS('JSExtendableArray|Null', |
| 3237 return new Future(() => false); | 3237 '\$.libraries_to_load[#]', loadId); |
| 3238 } | 3238 if (hunkLists == null) return new Future.value(null); |
| 3239 for (int index = 0; | 3239 |
| 3240 index < JS('int', '\$.libraries_to_load[#].length', loadId); | 3240 return Future.forEach(hunkLists, (hunkNames) { |
| 3241 ++index) { | 3241 Iterable<Future<Null>> allLoads = |
| 3242 hunkNames.add(JS('String', '\$.libraries_to_load[#][#]', | 3242 hunkNames.map((hunkName) => _loadHunk(hunkName, uri)); |
| 3243 loadId, index)); | 3243 return Future.wait(allLoads).then((_) => null); |
| 3244 } | |
| 3245 Iterable<Future<bool>> allLoads = | |
| 3246 hunkNames.map((hunkName) => _loadHunk(hunkName, uri)); | |
| 3247 return Future.wait(allLoads).then((results) { | |
| 3248 return results.any((x) => x); | |
| 3249 }); | 3244 }); |
| 3250 } | 3245 } |
| 3251 | 3246 |
| 3252 Future<bool> _loadHunk(String hunkName, String uri) { | 3247 Future<Null> _loadHunk(String hunkName, String uri) { |
| 3253 // TODO(ahe): Validate libraryName. Kasper points out that you want | 3248 // TODO(ahe): Validate libraryName. Kasper points out that you want |
| 3254 // to be able to experiment with the effect of toggling @DeferLoad, | 3249 // to be able to experiment with the effect of toggling @DeferLoad, |
| 3255 // so perhaps we should silently ignore "bad" library names. | 3250 // so perhaps we should silently ignore "bad" library names. |
| 3256 Future<bool> future = _loadedLibraries[hunkName]; | 3251 Future<Null> future = _loadedLibraries[hunkName]; |
| 3257 if (future != null) { | 3252 if (future != null) { |
| 3258 return future.then((_) => false); | 3253 return future.then((_) => null); |
| 3259 } | 3254 } |
| 3260 | 3255 |
| 3261 if (uri == null) { | 3256 if (uri == null) { |
| 3262 uri = IsolateNatives.thisScript; | 3257 uri = IsolateNatives.thisScript; |
| 3263 } | 3258 } |
| 3264 int index = uri.lastIndexOf('/'); | 3259 int index = uri.lastIndexOf('/'); |
| 3265 uri = '${uri.substring(0, index + 1)}$hunkName'; | 3260 uri = '${uri.substring(0, index + 1)}$hunkName'; |
| 3266 | 3261 |
| 3267 if (Primitives.isJsshell || Primitives.isD8) { | 3262 if (Primitives.isJsshell || Primitives.isD8) { |
| 3268 // TODO(ahe): Move this code to a JavaScript command helper script that is | 3263 // TODO(ahe): Move this code to a JavaScript command helper script that is |
| 3269 // not included in generated output. | 3264 // not included in generated output. |
| 3270 return _loadedLibraries[hunkName] = new Future<bool>(() { | 3265 return _loadedLibraries[hunkName] = new Future<Null>(() { |
| 3271 try { | 3266 try { |
| 3272 // Create a new function to avoid getting access to current function | 3267 // Create a new function to avoid getting access to current function |
| 3273 // context. | 3268 // context. |
| 3274 JS('void', '(new Function(#))()', 'load("$uri")'); | 3269 JS('void', '(new Function(#))()', 'load("$uri")'); |
| 3275 } catch (error, stackTrace) { | 3270 } catch (error, stackTrace) { |
| 3276 throw new DeferredLoadException("Loading $uri failed."); | 3271 throw new DeferredLoadException("Loading $uri failed."); |
| 3277 } | 3272 } |
| 3278 return true; | 3273 return null; |
| 3279 }); | 3274 }); |
| 3280 } else if (isWorker()) { | 3275 } else if (isWorker()) { |
| 3281 // We are in a web worker. Load the code with an XMLHttpRequest. | 3276 // We are in a web worker. Load the code with an XMLHttpRequest. |
| 3282 return _loadedLibraries[hunkName] = new Future<bool>(() { | 3277 return _loadedLibraries[hunkName] = new Future<Null>(() { |
| 3283 Completer completer = new Completer<bool>(); | 3278 Completer completer = new Completer<Null>(); |
| 3284 enterJsAsync(); | 3279 enterJsAsync(); |
| 3285 Future<bool> leavingFuture = completer.future.whenComplete(() { | 3280 Future<Null> leavingFuture = completer.future.whenComplete(() { |
| 3286 leaveJsAsync(); | 3281 leaveJsAsync(); |
| 3287 }); | 3282 }); |
| 3288 | 3283 |
| 3289 int index = uri.lastIndexOf('/'); | 3284 int index = uri.lastIndexOf('/'); |
| 3290 uri = '${uri.substring(0, index + 1)}$hunkName'; | 3285 uri = '${uri.substring(0, index + 1)}$hunkName'; |
| 3291 var xhr = JS('dynamic', 'new XMLHttpRequest()'); | 3286 var xhr = JS('dynamic', 'new XMLHttpRequest()'); |
| 3292 JS('void', '#.open("GET", #)', xhr, uri); | 3287 JS('void', '#.open("GET", #)', xhr, uri); |
| 3293 JS('void', '#.addEventListener("load", #, false)', | 3288 JS('void', '#.addEventListener("load", #, false)', |
| 3294 xhr, convertDartClosureToJS((event) { | 3289 xhr, convertDartClosureToJS((event) { |
| 3295 if (JS('int', '#.status', xhr) != 200) { | 3290 if (JS('int', '#.status', xhr) != 200) { |
| 3296 completer.completeError( | 3291 completer.completeError( |
| 3297 new DeferredLoadException("Loading $uri failed.")); | 3292 new DeferredLoadException("Loading $uri failed.")); |
| 3298 return; | 3293 return; |
| 3299 } | 3294 } |
| 3300 String code = JS('String', '#.responseText', xhr); | 3295 String code = JS('String', '#.responseText', xhr); |
| 3301 try { | 3296 try { |
| 3302 // Create a new function to avoid getting access to current function | 3297 // Create a new function to avoid getting access to current function |
| 3303 // context. | 3298 // context. |
| 3304 JS('void', '(new Function(#))()', code); | 3299 JS('void', '(new Function(#))()', code); |
| 3305 } catch (error, stackTrace) { | 3300 } catch (error, stackTrace) { |
| 3306 completer.completeError( | 3301 completer.completeError( |
| 3307 new DeferredLoadException("Evaluating $uri failed.")); | 3302 new DeferredLoadException("Evaluating $uri failed.")); |
| 3308 return; | 3303 return; |
| 3309 } | 3304 } |
| 3310 completer.complete(true); | 3305 completer.complete(null); |
| 3311 }, 1)); | 3306 }, 1)); |
| 3312 | 3307 |
| 3313 var fail = convertDartClosureToJS((event) { | 3308 var fail = convertDartClosureToJS((event) { |
| 3314 new DeferredLoadException("Loading $uri failed."); | 3309 new DeferredLoadException("Loading $uri failed."); |
| 3315 }, 1); | 3310 }, 1); |
| 3316 JS('void', '#.addEventListener("error", #, false)', xhr, fail); | 3311 JS('void', '#.addEventListener("error", #, false)', xhr, fail); |
| 3317 JS('void', '#.addEventListener("abort", #, false)', xhr, fail); | 3312 JS('void', '#.addEventListener("abort", #, false)', xhr, fail); |
| 3318 | 3313 |
| 3319 JS('void', '#.send()', xhr); | 3314 JS('void', '#.send()', xhr); |
| 3320 return leavingFuture; | 3315 return leavingFuture; |
| 3321 }); | 3316 }); |
| 3322 } | 3317 } |
| 3323 // We are in a dom-context. | 3318 // We are in a dom-context. |
| 3324 return _loadedLibraries[hunkName] = new Future<bool>(() { | 3319 return _loadedLibraries[hunkName] = new Future<Null>(() { |
| 3325 Completer completer = new Completer<bool>(); | 3320 Completer completer = new Completer<Null>(); |
| 3326 // Inject a script tag. | 3321 // Inject a script tag. |
| 3327 var script = JS('', 'document.createElement("script")'); | 3322 var script = JS('', 'document.createElement("script")'); |
| 3328 JS('', '#.type = "text/javascript"', script); | 3323 JS('', '#.type = "text/javascript"', script); |
| 3329 JS('', '#.src = #', script, uri); | 3324 JS('', '#.src = #', script, uri); |
| 3330 JS('', '#.addEventListener("load", #, false)', | 3325 JS('', '#.addEventListener("load", #, false)', |
| 3331 script, convertDartClosureToJS((event) { | 3326 script, convertDartClosureToJS((event) { |
| 3332 completer.complete(true); | 3327 completer.complete(null); |
| 3333 }, 1)); | 3328 }, 1)); |
| 3334 JS('', '#.addEventListener("error", #, false)', | 3329 JS('', '#.addEventListener("error", #, false)', |
| 3335 script, convertDartClosureToJS((event) { | 3330 script, convertDartClosureToJS((event) { |
| 3336 completer.completeError( | 3331 completer.completeError( |
| 3337 new DeferredLoadException("Loading $uri failed.")); | 3332 new DeferredLoadException("Loading $uri failed.")); |
| 3338 }, 1)); | 3333 }, 1)); |
| 3339 JS('', 'document.body.appendChild(#)', script); | 3334 JS('', 'document.body.appendChild(#)', script); |
| 3340 | 3335 |
| 3341 return completer.future; | 3336 return completer.future; |
| 3342 }); | 3337 }); |
| 3343 } | 3338 } |
| OLD | NEW |