]> git.pond.sub.org Git - eow/blobdiff - static/dojo-release-1.1.1/dojox/off/files.js
add Dojo 1.1.1
[eow] / static / dojo-release-1.1.1 / dojox / off / files.js
diff --git a/static/dojo-release-1.1.1/dojox/off/files.js b/static/dojo-release-1.1.1/dojox/off/files.js
new file mode 100644 (file)
index 0000000..6c19ea0
--- /dev/null
@@ -0,0 +1,454 @@
+if(!dojo._hasResource["dojox.off.files"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojox.off.files"] = true;
+dojo.provide("dojox.off.files");
+
+// Author: Brad Neuberg, bkn3@columbia.edu, http://codinginparadise.org
+
+// summary:
+//     Helps maintain resources that should be
+//     available offline, such as CSS files.
+// description:
+//     dojox.off.files makes it easy to indicate
+//     what resources should be available offline,
+//     such as CSS files, JavaScript, HTML, etc.
+dojox.off.files = {
+       // versionURL: String
+       //      An optional file, that if present, records the version
+       //      of our bundle of files to make available offline. If this
+       //      file is present, and we are not currently debugging,
+       //      then we only refresh our offline files if the version has
+       //      changed. 
+       versionURL: "version.js",
+       
+       // listOfURLs: Array
+       //      For advanced usage; most developers can ignore this.
+       //      Our list of URLs that will be cached and made available
+       //      offline.
+       listOfURLs: [],
+       
+       // refreshing: boolean
+       //      For advanced usage; most developers can ignore this.
+       //      Whether we are currently in the middle
+       //      of refreshing our list of offline files.
+       refreshing: false,
+
+       _cancelID: null,
+       
+       _error: false,
+       _errorMessages: [],
+       _currentFileIndex: 0,
+       _store: null,
+       _doSlurp: false,
+       
+       slurp: function(){
+               // summary:
+               //      Autoscans the page to find all resources to
+               //      cache. This includes scripts, images, CSS, and hyperlinks
+               //      to pages that are in the same scheme/port/host as this
+               //      page. We also scan the embedded CSS of any stylesheets
+               //      to find @import statements and url()'s.
+               //  You should call this method from the top-level, outside of
+               //      any functions and before the page loads:
+               //
+               //      <script>
+               //              dojo.require("dojox.sql");
+               //              dojo.require("dojox.off");
+               //              dojo.require("dojox.off.ui");
+               //              dojo.require("dojox.off.sync");
+               //
+               //              // configure how we should work offline
+               //
+               //              // set our application name
+               //              dojox.off.ui.appName = "Moxie";
+               //
+               //              // automatically "slurp" the page and
+               //              // capture the resources we need offline
+               //              dojox.off.files.slurp();
+               //
+               //              // tell Dojo Offline we are ready for it to initialize itself now
+               //              // that we have finished configuring it for our application
+               //              dojox.off.initialize();
+               //      </script>
+               //
+               //      Note that inline styles on elements are not handled (i.e.
+               //      if you somehow have an inline style that uses a URL);
+               //      object and embed tags are not scanned since their format
+               //      differs based on type; and elements created by JavaScript
+               //      after page load are not found. For these you must manually
+               //      add them with a dojox.off.files.cache() method call.
+               
+               // just schedule the slurp once the page is loaded and
+               // Dojo Offline is ready to slurp; dojox.off will call
+               // our _slurp() method before indicating it is finished
+               // loading
+               this._doSlurp = true;
+       },
+       
+       cache: function(urlOrList){ /* void */
+               // summary:
+               //              Caches a file or list of files to be available offline. This
+               //              can either be a full URL, such as http://foobar.com/index.html,
+               //              or a relative URL, such as ../index.html. This URL is not
+               //              actually cached until dojox.off.sync.synchronize() is called.
+               // urlOrList: String or Array[]
+               //              A URL of a file to cache or an Array of Strings of files to
+               //              cache
+               
+               //console.debug("dojox.off.files.cache, urlOrList="+urlOrList);
+               
+               if(dojo.isString(urlOrList)){
+                       var url = this._trimAnchor(urlOrList+"");
+                       if(!this.isAvailable(url)){ 
+                               this.listOfURLs.push(url); 
+                       }
+               }else if(urlOrList instanceof dojo._Url){
+                       var url = this._trimAnchor(urlOrList.uri);
+                       if(!this.isAvailable(url)){ 
+                               this.listOfURLs.push(url); 
+                       }
+               }else{
+                       dojo.forEach(urlOrList, function(url){
+                               url = this._trimAnchor(url);
+                               if(!this.isAvailable(url)){ 
+                                       this.listOfURLs.push(url); 
+                               }
+                       }, this);
+               }
+       },
+       
+       printURLs: function(){
+               // summary:
+               //      A helper function that will dump and print out
+               //      all of the URLs that are cached for offline
+               //      availability. This can help with debugging if you
+               //      are trying to make sure that all of your URLs are
+               //      available offline
+               console.debug("The following URLs are cached for offline use:");
+               dojo.forEach(this.listOfURLs, function(i){
+                       console.debug(i);
+               });     
+       },
+       
+       remove: function(url){ /* void */
+               // summary:
+               //              Removes a URL from the list of files to cache.
+               // description:
+               //              Removes a URL from the list of URLs to cache. Note that this
+               //              does not actually remove the file from the offline cache;
+               //              instead, it just prevents us from refreshing this file at a
+               //              later time, so that it will naturally time out and be removed
+               //              from the offline cache
+               // url: String
+               //              The URL to remove
+               for(var i = 0; i < this.listOfURLs.length; i++){
+                       if(this.listOfURLs[i] == url){
+                               this.listOfURLs = this.listOfURLs.splice(i, 1);
+                               break;
+                       }
+               }
+       },
+       
+       isAvailable: function(url){ /* boolean */
+               // summary:
+               //              Determines whether the given resource is available offline.
+               // url: String
+               //      The URL to check
+               for(var i = 0; i < this.listOfURLs.length; i++){
+                       if(this.listOfURLs[i] == url){
+                               return true;
+                       }
+               }
+               
+               return false;
+       },
+       
+       refresh: function(callback){ /* void */
+               //console.debug("dojox.off.files.refresh");
+               // summary:
+               //      For advanced usage; most developers can ignore this.
+               //      Refreshes our list of offline resources,
+               //      making them available offline.
+               // callback: Function
+               //      A callback that receives two arguments: whether an error
+               //      occurred, which is a boolean; and an array of error message strings
+               //      with details on errors encountered. If no error occured then message is
+               //      empty array with length 0.
+               try{
+                       if(dojo.config.isDebug){
+                               this.printURLs();
+                       }
+                       
+                       this.refreshing = true;
+                       
+                       if(this.versionURL){
+                               this._getVersionInfo(function(oldVersion, newVersion, justDebugged){
+                                       //console.warn("getVersionInfo, oldVersion="+oldVersion+", newVersion="+newVersion
+                                       //                              + ", justDebugged="+justDebugged+", isDebug="+dojo.config.isDebug);
+                                       if(dojo.config.isDebug || !newVersion || justDebugged 
+                                                       || !oldVersion || oldVersion != newVersion){
+                                               console.warn("Refreshing offline file list");
+                                               this._doRefresh(callback, newVersion);
+                                       }else{
+                                               console.warn("No need to refresh offline file list");
+                                               callback(false, []);
+                                       }
+                               });
+                       }else{
+                               console.warn("Refreshing offline file list");
+                               this._doRefresh(callback);
+                       }
+               }catch(e){
+                       this.refreshing = false;
+                       
+                       // can't refresh files -- core operation --
+                       // fail fast
+                       dojox.off.coreOpFailed = true;
+                       dojox.off.enabled = false;
+                       dojox.off.onFrameworkEvent("coreOperationFailed");
+               }
+       },
+       
+       abortRefresh: function(){
+               // summary:
+               //      For advanced usage; most developers can ignore this.
+               //      Aborts and cancels a refresh.
+               if(!this.refreshing){
+                       return;
+               }
+               
+               this._store.abortCapture(this._cancelID);
+               this.refreshing = false;
+       },
+       
+       _slurp: function(){
+               if(!this._doSlurp){
+                       return;
+               }
+               
+               var handleUrl = dojo.hitch(this, function(url){
+                       if(this._sameLocation(url)){
+                               this.cache(url);
+                       }
+               });
+               
+               handleUrl(window.location.href);
+               
+               dojo.query("script").forEach(function(i){
+                       try{
+                               handleUrl(i.getAttribute("src"));
+                       }catch(exp){
+                               //console.debug("dojox.off.files.slurp 'script' error: " 
+                               //                              + exp.message||exp);
+                       }
+               });
+               
+               dojo.query("link").forEach(function(i){
+                       try{
+                               if(!i.getAttribute("rel")
+                                       || i.getAttribute("rel").toLowerCase() != "stylesheet"){
+                                       return;
+                               }
+                       
+                               handleUrl(i.getAttribute("href"));
+                       }catch(exp){
+                               //console.debug("dojox.off.files.slurp 'link' error: " 
+                               //                              + exp.message||exp);
+                       }
+               });
+               
+               dojo.query("img").forEach(function(i){
+                       try{
+                               handleUrl(i.getAttribute("src"));
+                       }catch(exp){
+                               //console.debug("dojox.off.files.slurp 'img' error: " 
+                               //                              + exp.message||exp);
+                       }
+               });
+               
+               dojo.query("a").forEach(function(i){
+                       try{
+                               handleUrl(i.getAttribute("href"));
+                       }catch(exp){
+                               //console.debug("dojox.off.files.slurp 'a' error: " 
+                               //                              + exp.message||exp);
+                       }
+               });
+               
+               // FIXME: handle 'object' and 'embed' tag
+               
+               // parse our style sheets for inline URLs and imports
+               dojo.forEach(document.styleSheets, function(sheet){
+                       try{
+                               if(sheet.cssRules){ // Firefox
+                                       dojo.forEach(sheet.cssRules, function(rule){
+                                               var text = rule.cssText;
+                                               if(text){
+                                                       var matches = text.match(/url\(\s*([^\) ]*)\s*\)/i);
+                                                       if(!matches){
+                                                               return;
+                                                       }
+                                                       
+                                                       for(var i = 1; i < matches.length; i++){
+                                                               handleUrl(matches[i])
+                                                       }
+                                               }
+                                       });
+                               }else if(sheet.cssText){ // IE
+                                       var matches;
+                                       var text = sheet.cssText.toString();
+                                       // unfortunately, using RegExp.exec seems to be flakey
+                                       // for looping across multiple lines on IE using the
+                                       // global flag, so we have to simulate it
+                                       var lines = text.split(/\f|\r|\n/);
+                                       for(var i = 0; i < lines.length; i++){
+                                               matches = lines[i].match(/url\(\s*([^\) ]*)\s*\)/i);
+                                               if(matches && matches.length){
+                                                       handleUrl(matches[1]);
+                                               }
+                                       }
+                               }
+                       }catch(exp){
+                               //console.debug("dojox.off.files.slurp stylesheet parse error: " 
+                               //                              + exp.message||exp);
+                       }
+               });
+               
+               //this.printURLs();
+       },
+       
+       _sameLocation: function(url){
+               if(!url){ return false; }
+               
+               // filter out anchors
+               if(url.length && url.charAt(0) == "#"){
+                       return false;
+               }
+               
+               // FIXME: dojo._Url should be made public;
+               // it's functionality is very useful for
+               // parsing URLs correctly, which is hard to
+               // do right
+               url = new dojo._Url(url);
+               
+               // totally relative -- ../../someFile.html
+               if(!url.scheme && !url.port && !url.host){ 
+                       return true;
+               }
+               
+               // scheme relative with port specified -- brad.com:8080
+               if(!url.scheme && url.host && url.port
+                               && window.location.hostname == url.host
+                               && window.location.port == url.port){
+                       return true;
+               }
+               
+               // scheme relative with no-port specified -- brad.com
+               if(!url.scheme && url.host && !url.port
+                       && window.location.hostname == url.host
+                       && window.location.port == 80){
+                       return true;
+               }
+               
+               // else we have everything
+               return  window.location.protocol == (url.scheme + ":")
+                               && window.location.hostname == url.host
+                               && (window.location.port == url.port || !window.location.port && !url.port);
+       },
+       
+       _trimAnchor: function(url){
+               return url.replace(/\#.*$/, "");
+       },
+       
+       _doRefresh: function(callback, newVersion){
+               // get our local server
+               var localServer;
+               try{
+                       localServer = google.gears.factory.create("beta.localserver", "1.0");
+               }catch(exp){
+                       dojo.setObject("google.gears.denied", true);
+                       dojox.off.onFrameworkEvent("coreOperationFailed");
+                       throw "Google Gears must be allowed to run";
+               }
+               
+               var storeName = "dot_store_" 
+                                                       + window.location.href.replace(/[^0-9A-Za-z_]/g, "_");
+                                                       
+               // clip at 64 characters, the max length of a resource store name
+               if(storeName.length >= 64){
+                 storeName = storeName.substring(0, 63);
+               }
+                       
+               // refresh everything by simply removing
+               // any older stores
+               localServer.removeStore(storeName);
+               
+               // open/create the resource store
+               localServer.openStore(storeName);
+               var store = localServer.createStore(storeName);
+               this._store = store;
+
+               // add our list of files to capture
+               var self = this;
+               this._currentFileIndex = 0;
+               this._cancelID = store.capture(this.listOfURLs, function(url, success, captureId){
+                       //console.debug("store.capture, url="+url+", success="+success);
+                       if(!success && self.refreshing){
+                               self._cancelID = null;
+                               self.refreshing = false;
+                               var errorMsgs = [];
+                               errorMsgs.push("Unable to capture: " + url);
+                               callback(true, errorMsgs);
+                               return;
+                       }else if(success){
+                               self._currentFileIndex++;
+                       }
+                       
+                       if(success && self._currentFileIndex >= self.listOfURLs.length){
+                               self._cancelID = null;
+                               self.refreshing = false;
+                               if(newVersion){
+                                       dojox.storage.put("oldVersion", newVersion, null,
+                                                                       dojox.off.STORAGE_NAMESPACE);
+                               }
+                               dojox.storage.put("justDebugged", dojo.config.isDebug, null,
+                                                                       dojox.off.STORAGE_NAMESPACE);
+                               callback(false, []);
+                       }
+               });
+       },
+       
+       _getVersionInfo: function(callback){
+               var justDebugged = dojox.storage.get("justDebugged", 
+                                                                       dojox.off.STORAGE_NAMESPACE);
+               var oldVersion = dojox.storage.get("oldVersion",
+                                                                       dojox.off.STORAGE_NAMESPACE);
+               var newVersion = null;
+               
+               callback = dojo.hitch(this, callback);
+               
+               dojo.xhrGet({
+                               url: this.versionURL + "?browserbust=" + new Date().getTime(),
+                               timeout: 5 * 1000,
+                               handleAs: "javascript",
+                               error: function(err){
+                                       //console.warn("dojox.off.files._getVersionInfo, err=",err);
+                                       dojox.storage.remove("oldVersion", dojox.off.STORAGE_NAMESPACE);
+                                       dojox.storage.remove("justDebugged", dojox.off.STORAGE_NAMESPACE);
+                                       callback(oldVersion, newVersion, justDebugged);
+                               },
+                               load: function(data){
+                                       //console.warn("dojox.off.files._getVersionInfo, load=",data);
+                                       
+                                       // some servers incorrectly return 404's
+                                       // as a real page
+                                       if(data){
+                                               newVersion = data;
+                                       }
+                                       
+                                       callback(oldVersion, newVersion, justDebugged);
+                               }
+               });
+       }
+}
+
+}