// 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. 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; } } }