123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579 |
- if (!dojo._hasResource["dojox.off._common"]) { // _hasResource checks added by
- // build. Do not use
- // _hasResource directly in your
- // code.
- dojo._hasResource["dojox.off._common"] = true;
- dojo.provide("dojox.off._common");
- dojo.require("dojox.storage");
- dojo.require("dojox.sql");
- dojo.require("dojox.off.sync");
- // Author: Brad Neuberg, bkn3@columbia.edu, http://codinginparadise.org
- // summary:
- // dojox.off is the main object for offline applications.
- dojo.mixin(dojox.off, {
- // isOnline: boolean
- // true if we are online, false if not
- isOnline : false,
- // NET_CHECK: int
- // For advanced usage; most developers can ignore this.
- // Time in seconds on how often we should check the status of the
- // network with an automatic background timer. The current default
- // is 5 seconds.
- NET_CHECK : 5,
- // STORAGE_NAMESPACE: String
- // For advanced usage; most developers can ignore this.
- // The namespace we use to save core data into Dojo Storage.
- STORAGE_NAMESPACE : "_dot",
- // enabled: boolean
- // For advanced usage; most developers can ignore this.
- // Whether offline ability is enabled or not. Defaults to true.
- enabled : true,
- // availabilityURL: String
- // For advanced usage; most developers can ignore this.
- // The URL to check for site availability. We do a GET request on
- // this URL to check for site availability. By default we check for a
- // simple text file in src/off/network_check.txt that has one value
- // it, the value '1'.
- availabilityURL : dojo.moduleUrl("dojox", "off/network_check.txt"),
- // goingOnline: boolean
- // For advanced usage; most developers can ignore this.
- // True if we are attempting to go online, false otherwise
- goingOnline : false,
- // coreOpFailed: boolean
- // For advanced usage; most developers can ignore this.
- // A flag set by the Dojo Offline framework that indicates that the
- // user denied some operation that required the offline cache or an
- // operation failed in some critical way that was unrecoverable. For
- // example, if the offline cache is Google Gears and we try to get a
- // Gears database, a popup window appears asking the user whether they
- // will approve or deny this request. If the user denies the request,
- // and we are doing some operation that is core to Dojo Offline, then
- // we set this flag to 'true'. This flag causes a 'fail fast'
- // condition, turning off offline ability.
- coreOpFailed : false,
- // doNetChecking: boolean
- // For advanced usage; most developers can ignore this.
- // Whether to have a timing interval in the background doing automatic
- // network checks at regular intervals; the length of time between
- // checks is controlled by dojox.off.NET_CHECK. Defaults to true.
- doNetChecking : true,
- // hasOfflineCache: boolean
- // For advanced usage; most developers can ignore this.
- // Determines if an offline cache is available or installed; an
- // offline cache is a facility that can truely cache offline
- // resources, such as JavaScript, HTML, etc. in such a way that they
- // won't be removed from the cache inappropriately like a browser
- // cache would. If this is false then an offline cache will be
- // installed. Only Google Gears is currently supported as an offline
- // cache. Future possible offline caches include Firefox 3.
- hasOfflineCache : null,
- // browserRestart: boolean
- // For advanced usage; most developers can ignore this.
- // If true, the browser must be restarted to register the existence of
- // a new host added offline (from a call to addHostOffline); if false,
- // then nothing is needed.
- browserRestart : false,
- _STORAGE_APP_NAME : window.location.href.replace(/[^0-9A-Za-z_]/g, "_"),
- _initializeCalled : false,
- _storageLoaded : false,
- _pageLoaded : false,
- onLoad : function() {
- // summary:
- // Called when Dojo Offline can be used.
- // description:
- // Do a dojo.connect to this to know when you can
- // start using Dojo Offline:
- // dojo.connect(dojox.off, "onLoad", myFunc);
- },
- onNetwork : function(type) {
- // summary:
- // Called when our on- or offline- status changes.
- // description:
- // If we move online, then this method is called with the
- // value "online". If we move offline, then this method is
- // called with the value "offline". You can connect to this
- // method to do add your own behavior:
- //
- // dojo.connect(dojox.off, "onNetwork", someFunc)
- //
- // Note that if you are using the default Dojo Offline UI
- // widget that most of the on- and off-line notification
- // and syncing is automatically handled and provided to the
- // user.
- // type: String
- // Either "online" or "offline".
- },
- initialize : function() { /* void */
- // summary:
- // Called when a Dojo Offline-enabled application is finished
- // configuring Dojo Offline, and is ready for Dojo Offline to
- // initialize itself.
- // description:
- // When an application has finished filling out the variables Dojo
- // Offline needs to work, such as dojox.off.ui.appName, it must
- // this method to tell Dojo Offline to initialize itself.
- // Note:
- // This method is needed for a rare edge case. In some conditions,
- // especially if we are dealing with a compressed Dojo build, the
- // entire Dojo Offline subsystem might initialize itself and be
- // running even before the JavaScript for an application has had a
- // chance to run and configure Dojo Offline, causing Dojo Offline
- // to have incorrect initialization parameters for a given app,
- // such as no value for dojox.off.ui.appName. This method is
- // provided to prevent this scenario, to slightly 'slow down' Dojo
- // Offline so it can be configured before running off and doing
- // its thing.
- // console.debug("dojox.off.initialize");
- this._initializeCalled = true;
- if (this._storageLoaded && this._pageLoaded) {
- this._onLoad();
- }
- },
- goOffline : function() { /* void */
- // summary:
- // For advanced usage; most developers can ignore this.
- // Manually goes offline, away from the network.
- if ((dojox.off.sync.isSyncing) || (this.goingOnline)) {
- return;
- }
- this.goingOnline = false;
- this.isOnline = false;
- },
- goOnline : function(callback) { /* void */
- // summary:
- // For advanced usage; most developers can ignore this.
- // Attempts to go online.
- // description:
- // Attempts to go online, making sure this web application's web
- // site is available. 'callback' is called asychronously with the
- // result of whether we were able to go online or not.
- // callback: Function
- // An optional callback function that will receive one argument:
- // whether the site is available or not and is boolean. If this
- // function is not present we call dojo.xoff.onOnline instead if
- // we are able to go online.
- // console.debug("goOnline");
- if (dojox.off.sync.isSyncing || dojox.off.goingOnline) {
- return;
- }
- this.goingOnline = true;
- this.isOnline = false;
- // see if can reach our web application's web site
- this._isSiteAvailable(callback);
- },
- onFrameworkEvent : function(type /* String */, saveData /* Object? */) {
- // summary:
- // For advanced usage; most developers can ignore this.
- // A standard event handler that can be attached to to find out
- // about low-level framework events. Most developers will not need
- // to
- // attach to this method; it is meant for low-level information
- // that can be useful for updating offline user-interfaces in
- // exceptional circumstances. The default Dojo Offline UI
- // widget takes care of most of these situations.
- // type: String
- // The type of the event:
- //
- // * "offlineCacheInstalled"
- // An event that is fired when a user
- // has installed an offline cache after the page has been loaded.
- // If a user didn't have an offline cache when the page loaded, a
- // UI of some kind might have prompted them to download one. This
- // method is called if they have downloaded and installed an
- // offline cache so a UI can reinitialize itself to begin using
- // this offline cache.
- // * "coreOperationFailed"
- // Fired when a core operation during interaction with the
- // offline cache is denied by the user. Some offline caches, such
- // as Google Gears, prompts the user to approve or deny caching
- // files, using the database, and more. If the user denies a
- // request that is core to Dojo Offline's operation, we set
- // dojox.off.coreOpFailed to true and call this method for
- // listeners that would like to respond some how to Dojo Offline
- // 'failing fast'.
- // * "save"
- // Called whenever the framework saves data into persistent
- // storage. This could be useful for providing save feedback
- // or providing appropriate error feedback if saving fails
- // due to a user not allowing the save to occur
- // saveData: Object?
- // If the type was 'save', then a saveData object is provided with
- // further save information. This object has the following
- // properties:
- //
- // * status - dojox.storage.SUCCESS, dojox.storage.PENDING,
- // dojox.storage.FAILED
- // Whether the save succeeded, whether it is pending based on a UI
- // dialog asking the user for permission, or whether it failed.
- //
- // * isCoreSave - boolean
- // If true, then this save was for a core piece of data necessary
- // for the functioning of Dojo Offline. If false, then it is a
- // piece of normal data being saved for offline access. Dojo
- // Offline will 'fail fast' if some core piece of data could not
- // be saved, automatically setting dojox.off.coreOpFailed to
- // 'true' and dojox.off.enabled to 'false'.
- //
- // * key - String
- // The key that we are attempting to persist
- //
- // * value - Object
- // The object we are trying to persist
- //
- // * namespace - String
- // The Dojo Storage namespace we are saving this key/value pair
- // into, such as "default", "Documents", "Contacts", etc.
- // Optional.
- if (type == "save") {
- if (saveData.isCoreSave
- && (saveData.status == dojox.storage.FAILED)) {
- dojox.off.coreOpFailed = true;
- dojox.off.enabled = false;
- // FIXME: Stop the background network thread
- dojox.off.onFrameworkEvent("coreOperationFailed");
- }
- } else if (type == "coreOperationFailed") {
- dojox.off.coreOpFailed = true;
- dojox.off.enabled = false;
- // FIXME: Stop the background network thread
- }
- },
- _checkOfflineCacheAvailable : function(callback) {
- // is a true, offline cache running on this machine?
- this.hasOfflineCache = dojo.isGears;
- callback();
- },
- _onLoad : function() {
- // console.debug("dojox.off._onLoad");
- // both local storage and the page are finished loading
- // cache the Dojo JavaScript -- just use the default dojo.js
- // name for the most common scenario
- // FIXME: TEST: Make sure syncing doesn't break if dojo.js
- // can't be found, or report an error to developer
- dojox.off.files.cache(dojo.moduleUrl("dojo", "dojo.js"));
- // pull in the files needed by Dojo
- this._cacheDojoResources();
- // FIXME: need to pull in the firebug lite files here!
- // workaround or else we will get an error on page load
- // from Dojo that it can't find 'console.debug' for optimized builds
- // dojox.off.files.cache(djConfig.baseRelativePath +
- // "src/debug.js");
- // make sure that resources needed by all of our underlying
- // Dojo Storage storage providers will be available
- // offline
- dojox.off.files.cache(dojox.storage.manager.getResourceList());
- // slurp the page if the end-developer wants that
- dojox.off.files._slurp();
- // see if we have an offline cache; when done, move
- // on to the rest of our startup tasks
- this._checkOfflineCacheAvailable(dojo.hitch(this,
- "_onOfflineCacheChecked"));
- },
- _onOfflineCacheChecked : function() {
- // this method is part of our _onLoad series of startup tasks
- // if we have an offline cache, see if we have been added to the
- // list of available offline web apps yet
- if (this.hasOfflineCache && this.enabled) {
- // load framework data; when we are finished, continue
- // initializing ourselves
- this._load(dojo.hitch(this, "_finishStartingUp"));
- } else if (this.hasOfflineCache && !this.enabled) {
- // we have an offline cache, but it is disabled for some reason
- // perhaps due to the user denying a core operation
- this._finishStartingUp();
- } else {
- this._keepCheckingUntilInstalled();
- }
- },
- _keepCheckingUntilInstalled : function() {
- // this method is part of our _onLoad series of startup tasks
- // kick off a background interval that keeps
- // checking to see if an offline cache has been
- // installed since this page loaded
- // FIXME: Gears: See if we are installed somehow after the
- // page has been loaded
- // now continue starting up
- this._finishStartingUp();
- },
- _finishStartingUp : function() {
- // console.debug("dojox.off._finishStartingUp");
- // this method is part of our _onLoad series of startup tasks
- if (!this.hasOfflineCache) {
- this.onLoad();
- } else if (this.enabled) {
- // kick off a thread to check network status on
- // a regular basis
- this._startNetworkThread();
- // try to go online
- this.goOnline(dojo.hitch(this, function() {
- // console.debug("Finished trying to go online");
- // indicate we are ready to be used
- dojox.off.onLoad();
- }));
- } else { // we are disabled or a core operation failed
- if (this.coreOpFailed) {
- this.onFrameworkEvent("coreOperationFailed");
- } else {
- this.onLoad();
- }
- }
- },
- _onPageLoad : function() {
- // console.debug("dojox.off._onPageLoad");
- this._pageLoaded = true;
- if (this._storageLoaded && this._initializeCalled) {
- this._onLoad();
- }
- },
- _onStorageLoad : function() {
- // console.debug("dojox.off._onStorageLoad");
- this._storageLoaded = true;
- // were we able to initialize storage? if
- // not, then this is a core operation, and
- // let's indicate we will need to fail fast
- if (!dojox.storage.manager.isAvailable()
- && dojox.storage.manager.isInitialized()) {
- this.coreOpFailed = true;
- this.enabled = false;
- }
- if (this._pageLoaded && this._initializeCalled) {
- this._onLoad();
- }
- },
- _isSiteAvailable : function(callback) {
- // summary:
- // Determines if our web application's website is available.
- // description:
- // This method will asychronously determine if our web
- // application's web site is available, which is a good proxy for
- // network availability. The URL dojox.off.availabilityURL is
- // used, which defaults to this site's domain name (ex:
- // foobar.com). We check for dojox.off.AVAILABILITY_TIMEOUT (in
- // seconds) and abort after that
- // callback: Function
- // An optional callback function that will receive one argument:
- // whether the site is available or not and is boolean. If this
- // function is not present we call dojox.off.onNetwork instead if we
- // are able to go online.
- dojo.xhrGet({
- url : this._getAvailabilityURL(),
- handleAs : "text",
- timeout : this.NET_CHECK * 1000,
- error : dojo.hitch(this, function(err) {
- // console.debug("dojox.off._isSiteAvailable.error:
- // " + err);
- this.goingOnline = false;
- this.isOnline = false;
- if (callback) {
- callback(false);
- }
- }),
- load : dojo.hitch(this, function(data) {
- // console.debug("dojox.off._isSiteAvailable.load,
- // data="+data);
- this.goingOnline = false;
- this.isOnline = true;
- if (callback) {
- callback(true);
- } else {
- this.onNetwork("online");
- }
- })
- });
- },
- _startNetworkThread : function() {
- // console.debug("startNetworkThread");
- // kick off a thread that does periodic
- // checks on the status of the network
- if (!this.doNetChecking) {
- return;
- }
- window.setInterval(dojo.hitch(this, function() {
- var d = dojo.xhrGet({
- url : this._getAvailabilityURL(),
- handleAs : "text",
- timeout : this.NET_CHECK * 1000,
- error : dojo.hitch(this, function(err) {
- if (this.isOnline) {
- this.isOnline = false;
- // FIXME: xhrGet() is not
- // correctly calling abort
- // on the XHR object when
- // it times out; fix inside
- // there instead of externally
- // here
- try {
- if (typeof d.ioArgs.xhr.abort == "function") {
- d.ioArgs.xhr.abort();
- }
- } catch (e) {
- }
- // if things fell in the middle of syncing,
- // stop syncing
- dojox.off.sync.isSyncing = false;
- this.onNetwork("offline");
- }
- }),
- load : dojo.hitch(this, function(data) {
- if (!this.isOnline) {
- this.isOnline = true;
- this.onNetwork("online");
- }
- })
- });
- }), this.NET_CHECK * 1000);
- },
- _getAvailabilityURL : function() {
- var url = this.availabilityURL.toString();
- // bust the browser's cache to make sure we are really talking to
- // the server
- if (url.indexOf("?") == -1) {
- url += "?";
- } else {
- url += "&";
- }
- url += "browserbust=" + allGetServerTime().getTime();
- return url;
- },
- _onOfflineCacheInstalled : function() {
- this.onFrameworkEvent("offlineCacheInstalled");
- },
- _cacheDojoResources : function() {
- // if we are a non-optimized build, then the core Dojo bootstrap
- // system was loaded as separate JavaScript files;
- // add these to our offline cache list. these are
- // loaded before the dojo.require() system exists
- // FIXME: create a better mechanism in the Dojo core to
- // expose whether you are dealing with an optimized build;
- // right now we just scan the SCRIPT tags attached to this
- // page and see if there is one for _base/_loader/bootstrap.js
- var isOptimizedBuild = true;
- dojo.forEach(dojo.query("script"), function(i) {
- var src = i.getAttribute("src");
- if (!src) {
- return;
- }
- if (src.indexOf("_base/_loader/bootstrap.js") != -1) {
- isOptimizedBuild = false;
- }
- });
- if (!isOptimizedBuild) {
- dojox.off.files.cache(dojo.moduleUrl("dojo", "_base.js").uri);
- dojox.off.files.cache(dojo.moduleUrl("dojo",
- "_base/_loader/loader.js").uri);
- dojox.off.files.cache(dojo.moduleUrl("dojo",
- "_base/_loader/bootstrap.js").uri);
- // FIXME: pull in the host environment file in a more generic
- // way
- // for other host environments
- dojox.off.files.cache(dojo.moduleUrl("dojo",
- "_base/_loader/hostenv_browser.js").uri);
- }
- // add anything that was brought in with a
- // dojo.require() that resulted in a JavaScript
- // URL being fetched
- // FIXME: modify dojo/_base/_loader/loader.js to
- // expose a public API to get this information
- for (var i = 0; i < dojo._loadedUrls.length; i++) {
- dojox.off.files.cache(dojo._loadedUrls[i]);
- }
- // FIXME: add the standard Dojo CSS file
- },
- _save : function() {
- // summary:
- // Causes the Dojo Offline framework to save its configuration
- // data into local storage.
- },
- _load : function(callback) {
- // summary:
- // Causes the Dojo Offline framework to load its configuration
- // data from local storage
- dojox.off.sync._load(callback);
- }
- });
- // wait until the storage system is finished loading
- dojox.storage.manager.addOnLoad(dojo.hitch(dojox.off, "_onStorageLoad"));
- // wait until the page is finished loading
- dojo.addOnLoad(dojox.off, "_onPageLoad");
- }
|