| // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file |
| // for details. All rights reserved. Use of this source code is governed by a |
| // BSD-style license that can be found in the LICENSE file. |
| |
| // @dart = 2.9 |
| |
| part of swarmlib; |
| |
| /** |
| * The base class that should be extended by all HTML applications. |
| * |
| * It should both be easy to use for users coming over from JavaScript, but |
| * also offer a clear notion of OO encapsulation. |
| * |
| * This class or something similar belongs in the standard DOM library. |
| */ |
| class App { |
| App() {} |
| |
| /** Begins executing code in this [App]. */ |
| void run() { |
| // If the script is async, by the time we get here the DOM content may |
| // already be loaded, so waiting on the DOMContentLoaded event is a no-op. |
| // Guard against this by checking whether the document readiness state has |
| // gotten as far as "interactive". (We believe the transition to |
| // "interactive" is when the DOMContentLoaded event fires, but haven't |
| // found that specified; if that's not true it leaves a race bug.) |
| if (document.readyState == "interactive" || |
| document.readyState == "complete" || |
| document.readyState == "loaded") { |
| // We use a timer to insure that onLoad is always called in an async |
| // manner even if the document is already loaded. |
| Timer.run(onLoad); |
| } else { |
| window.onContentLoaded.listen( |
| // TODO(sigmund): Consider eliminating the call to "wrap", for |
| // instance, modify event listeners to always wrap, or extend DOM code |
| // to intercept the beginning & end of each event loop |
| EventBatch.wrap((event) => onLoad())); |
| } |
| } |
| |
| /** |
| * Called when the DOM is fully loaded but potentially before resources. |
| * |
| * For most apps, any startup code should be in this method. Be sure to call |
| * the superclass implementation. |
| */ |
| void onLoad() { |
| // Prevent the default browser behavior of scrolling the window. |
| document.onTouchMove.listen((Event event) => event.preventDefault()); |
| |
| // Swap and reload the cache if ready |
| if (!swapAndReloadCache()) { |
| // Otherwise wait until an update to the cache is ready |
| window.applicationCache.onUpdateReady.listen((e) => swapAndReloadCache()); |
| } |
| } |
| |
| /** |
| * Erase the static splash screen. |
| * |
| * Assumption: if a splash screen exists, an element #appSplash contains it. |
| */ |
| void eraseSplashScreen() { |
| final splash = document.querySelector("#appSplash"); |
| // Delete it if found, but it's okay for it not to be -- maybe |
| // somebody just didn't want to use our splash mechanism. |
| if (splash != null) { |
| splash.remove(); |
| } |
| } |
| |
| /** |
| * Swaps and reloads the app cache if an update is ready. Returns false if |
| * an update is not ready. |
| */ |
| bool swapAndReloadCache() { |
| ApplicationCache appCache = window.applicationCache; |
| if (!identical(appCache.status, ApplicationCache.UPDATEREADY)) { |
| return false; |
| } |
| |
| print('App cache update ready, now swapping...'); |
| window.applicationCache.swapCache(); |
| print('App cache swapped, now reloading page...'); |
| window.location.reload(); |
| return true; |
| } |
| |
| /** Returns true if we are running as a packaged application. */ |
| static bool get isPackaged { |
| return window.location.protocol == 'chrome-extension:'; |
| } |
| |
| /** |
| * Gets the server URL. This is needed when we are loaded from a packaged |
| * Chrome app. |
| */ |
| static String serverUrl(String url) { |
| if (isPackaged) { |
| // TODO(jmesserly): Several problems with this: |
| // * How do we authenticate against the server? |
| // * How do we talk to a server other than thump? |
| assert(url.startsWith('/')); |
| return 'http://thump.googleplex.com$url'; |
| } else { |
| return url; |
| } |
| } |
| } |