aboutsummaryrefslogtreecommitdiff
path: root/includes/js/dojox/off/_common.js
diff options
context:
space:
mode:
Diffstat (limited to 'includes/js/dojox/off/_common.js')
-rw-r--r--includes/js/dojox/off/_common.js559
1 files changed, 559 insertions, 0 deletions
diff --git a/includes/js/dojox/off/_common.js b/includes/js/dojox/off/_common.js
new file mode 100644
index 0000000..005cd31
--- /dev/null
+++ b/includes/js/dojox/off/_common.js
@@ -0,0 +1,559 @@
+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(dojo.config.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=" + 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.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");
+
+}