blob: b03e81436ff8bda786369d10068260f27fe85294 [file] [log] [blame]
// 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;
}
}
}