Blame | Last modification | View Log | RSS feed
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 notisOnline: 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 otherwisegoingOnline: 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 sitethis._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 threaddojox.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 developerdojox.off.files.cache(dojo.moduleUrl("dojo", "dojo.js"));// pull in the files needed by Dojothis._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// offlinedojox.off.files.cache(dojox.storage.manager.getResourceList());// slurp the page if the end-developer wants thatdojox.off.files._slurp();// see if we have an offline cache; when done, move// on to the rest of our startup tasksthis._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 yetif(this.hasOfflineCache && this.enabled){// load framework data; when we are finished, continue// initializing ourselvesthis._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 operationthis._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 upthis._finishStartingUp();},_finishStartingUp: function(){//console.debug("dojox.off._finishStartingUp");// this method is part of our _onLoad series of startup tasksif(!this.hasOfflineCache){this.onLoad();}else if(this.enabled){// kick off a thread to check network status on// a regular basisthis._startNetworkThread();// try to go onlinethis.goOnline(dojo.hitch(this, function(){//console.debug("Finished trying to go online");// indicate we are ready to be useddojox.off.onLoad();}));}else{ // we are disabled or a core operation failedif(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 fastif(!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 networkif(!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// heretry{if(typeof d.ioArgs.xhr.abort == "function"){d.ioArgs.xhr.abort();}}catch(e){}// if things fell in the middle of syncing,// stop syncingdojox.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 serverif(url.indexOf("?") == -1){url += "?";}else{url += "&";}url += "browserbust=" + new Date().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.jsvar 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 environmentsdojox.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 informationfor(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 storagedojox.off.sync._load(callback);}});// wait until the storage system is finished loadingdojox.storage.manager.addOnLoad(dojo.hitch(dojox.off, "_onStorageLoad"));// wait until the page is finished loadingdojo.addOnLoad(dojox.off, "_onPageLoad");}