]> git.pond.sub.org Git - eow/blobdiff - static/dojo-release-1.1.1/dojox/off/_common.js
add Dojo 1.1.1
[eow] / static / dojo-release-1.1.1 / dojox / off / _common.js
diff --git a/static/dojo-release-1.1.1/dojox/off/_common.js b/static/dojo-release-1.1.1/dojox/off/_common.js
new file mode 100644 (file)
index 0000000..005cd31
--- /dev/null
@@ -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");
+
+}