dojo.provide("dojox.off.ui"); dojo.require("dojox.storage.Provider"); dojo.require("dojox.storage.manager"); dojo.require("dojox.storage.GearsStorageProvider"); // Author: Brad Neuberg, bkn3@columbia.edu, http://codinginparadise.org // summary: // dojox.off.ui provides a standard, // default user-interface for a // Dojo Offline Widget that can easily // be dropped into applications that would // like to work offline. dojo.mixin(dojox.off.ui, { // appName: String // This application's name, such as "Foobar". Note that // this is a string, not HTML, so embedded markup will // not work, including entities. Only the following // characters are allowed: numbers, letters, and spaces. // You must set this property. appName: "setme", // autoEmbed: boolean // For advanced usage; most developers can ignore this. // Whether to automatically auto-embed the default Dojo Offline // widget into this page; default is true. autoEmbed: true, // autoEmbedID: String // For advanced usage; most developers can ignore this. // The ID of the DOM element that will contain our // Dojo Offline widget; defaults to the ID 'dot-widget'. autoEmbedID: "dot-widget", // runLink: String // For advanced usage; most developers can ignore this. // The URL that should be navigated to to run this // application offline; this will be placed inside of a // link that the user can drag to their desktop and double // click. Note that this URL must exactly match the URL // of the main page of our resource that is offline for // it to be retrieved from the offline cache correctly. // For example, if you have cached your main page as // http://foobar.com/index.html, and you set this to // http://www.foobar.com/index.html, the run link will // not work. By default this value is automatically set to // the URL of this page, so it does not need to be set // manually unless you have unusual needs. runLink: window.location.href, // runLinkTitle: String // For advanced usage; most developers can ignore this. // The text that will be inside of the link that a user // can drag to their desktop to run this application offline. // By default this is automatically set to "Run " plus your // application's name. runLinkTitle: "Run Application", // learnHowPath: String // For advanced usage; most developers can ignore this. // The path to a web page that has information on // how to use this web app offline; defaults to // src/off/ui-template/learnhow.html, relative to // your Dojo installation. Make sure to set // dojo.to.ui.customLearnHowPath to true if you want // a custom Learn How page. learnHowPath: dojo.moduleUrl("dojox", "off/resources/learnhow.html"), // customLearnHowPath: boolean // For advanced usage; most developers can ignore this. // Whether the developer is using their own custom page // for the Learn How instructional page; defaults to false. // Use in conjunction with dojox.off.ui.learnHowPath. customLearnHowPath: false, htmlTemplatePath: dojo.moduleUrl("dojox", "off/resources/offline-widget.html").uri, cssTemplatePath: dojo.moduleUrl("dojox", "off/resources/offline-widget.css").uri, onlineImagePath: dojo.moduleUrl("dojox", "off/resources/greenball.png").uri, offlineImagePath: dojo.moduleUrl("dojox", "off/resources/redball.png").uri, rollerImagePath: dojo.moduleUrl("dojox", "off/resources/roller.gif").uri, checkmarkImagePath: dojo.moduleUrl("dojox", "off/resources/checkmark.png").uri, learnHowJSPath: dojo.moduleUrl("dojox", "off/resources/learnhow.js").uri, _initialized: false, onLoad: function(){ // summary: // A function that should be connected to allow your // application to know when Dojo Offline, the page, and // the Offline Widget are all initialized and ready to be // used: // // dojo.connect(dojox.off.ui, "onLoad", someFunc) }, _initialize: function(){ //console.debug("dojox.off.ui._initialize"); // make sure our app name is correct if(this._validateAppName(this.appName) == false){ alert("You must set dojox.off.ui.appName; it can only contain " + "letters, numbers, and spaces; right now it " + "is incorrectly set to '" + dojox.off.ui.appName + "'"); dojox.off.enabled = false; return; } // set our run link text to its default this.runLinkText = "Run " + this.appName; // setup our event listeners for Dojo Offline events // to update our UI dojo.connect(dojox.off, "onNetwork", this, "_onNetwork"); dojo.connect(dojox.off.sync, "onSync", this, "_onSync"); // cache our default UI resources dojox.off.files.cache([ this.htmlTemplatePath, this.cssTemplatePath, this.onlineImagePath, this.offlineImagePath, this.rollerImagePath, this.checkmarkImagePath ]); // embed the offline widget UI if(this.autoEmbed){ this._doAutoEmbed(); } }, _doAutoEmbed: function(){ // fetch our HTML for the offline widget // dispatch the request dojo.xhrGet({ url: this.htmlTemplatePath, handleAs: "text", error: function(err){ dojox.off.enabled = false; err = err.message||err; alert("Error loading the Dojo Offline Widget from " + this.htmlTemplatePath + ": " + err); }, load: dojo.hitch(this, this._templateLoaded) }); }, _templateLoaded: function(data){ //console.debug("dojox.off.ui._templateLoaded"); // inline our HTML var container = dojo.byId(this.autoEmbedID); if(container){ container.innerHTML = data; } // fill out our image paths this._initImages(); // update our network indicator status ball this._updateNetIndicator(); // update our 'Learn How' text this._initLearnHow(); this._initialized = true; // check offline cache settings if(!dojox.off.hasOfflineCache){ this._showNeedsOfflineCache(); return; } // check to see if we need a browser restart // to be able to use this web app offline if(dojox.off.hasOfflineCache && dojox.off.browserRestart){ this._needsBrowserRestart(); return; }else{ var browserRestart = dojo.byId("dot-widget-browser-restart"); if(browserRestart){ browserRestart.style.display = "none"; } } // update our sync UI this._updateSyncUI(); // register our event listeners for our main buttons this._initMainEvtHandlers(); // if offline functionality is disabled, disable everything this._setOfflineEnabled(dojox.off.enabled); // update our UI based on the state of the network this._onNetwork(dojox.off.isOnline ? "online" : "offline"); // try to go online this._testNet(); }, _testNet: function(){ dojox.off.goOnline(dojo.hitch(this, function(isOnline){ //console.debug("testNet callback, isOnline="+isOnline); // display our online/offline results this._onNetwork(isOnline ? "online" : "offline"); // indicate that our default UI // and Dojo Offline are now ready to // be used this.onLoad(); })); }, _updateNetIndicator: function(){ var onlineImg = dojo.byId("dot-widget-network-indicator-online"); var offlineImg = dojo.byId("dot-widget-network-indicator-offline"); var titleText = dojo.byId("dot-widget-title-text"); if(onlineImg && offlineImg){ if(dojox.off.isOnline == true){ onlineImg.style.display = "inline"; offlineImg.style.display = "none"; }else{ onlineImg.style.display = "none"; offlineImg.style.display = "inline"; } } if(titleText){ if(dojox.off.isOnline){ titleText.innerHTML = "Online"; }else{ titleText.innerHTML = "Offline"; } } }, _initLearnHow: function(){ var learnHow = dojo.byId("dot-widget-learn-how-link"); if(!learnHow){ return; } if(!this.customLearnHowPath){ // add parameters to URL so the Learn How page // can customize itself and display itself // correctly based on framework settings var dojoPath = dojo.config.baseRelativePath; this.learnHowPath += "?appName=" + encodeURIComponent(this.appName) + "&hasOfflineCache=" + dojox.off.hasOfflineCache + "&runLink=" + encodeURIComponent(this.runLink) + "&runLinkText=" + encodeURIComponent(this.runLinkText) + "&baseRelativePath=" + encodeURIComponent(dojoPath); // cache our Learn How JavaScript page and // the HTML version with full query parameters // so it is available offline without a cache miss dojox.off.files.cache(this.learnHowJSPath); dojox.off.files.cache(this.learnHowPath); } learnHow.setAttribute("href", this.learnHowPath); var appName = dojo.byId("dot-widget-learn-how-app-name"); if(!appName){ return; } appName.innerHTML = ""; appName.appendChild(document.createTextNode(this.appName)); }, _validateAppName: function(appName){ if(!appName){ return false; } return (/^[a-z0-9 ]*$/i.test(appName)); }, _updateSyncUI: function(){ var roller = dojo.byId("dot-roller"); var checkmark = dojo.byId("dot-success-checkmark"); var syncMessages = dojo.byId("dot-sync-messages"); var details = dojo.byId("dot-sync-details"); var cancel = dojo.byId("dot-sync-cancel"); if(dojox.off.sync.isSyncing){ this._clearSyncMessage(); if(roller){ roller.style.display = "inline"; } if(checkmark){ checkmark.style.display = "none"; } if(syncMessages){ dojo.removeClass(syncMessages, "dot-sync-error"); } if(details){ details.style.display = "none"; } if(cancel){ cancel.style.display = "inline"; } }else{ if(roller){ roller.style.display = "none"; } if(cancel){ cancel.style.display = "none"; } if(syncMessages){ dojo.removeClass(syncMessages, "dot-sync-error"); } } }, _setSyncMessage: function(message){ var syncMessage = dojo.byId("dot-sync-messages"); if(syncMessage){ // when used with Google Gears pre-release in Firefox/Mac OS X, // the browser would crash when testing in Moxie // if we set the message this way for some reason. // Brad Neuberg, bkn3@columbia.edu //syncMessage.innerHTML = message; while(syncMessage.firstChild){ syncMessage.removeChild(syncMessage.firstChild); } syncMessage.appendChild(document.createTextNode(message)); } }, _clearSyncMessage: function(){ this._setSyncMessage(""); }, _initImages: function(){ var onlineImg = dojo.byId("dot-widget-network-indicator-online"); if(onlineImg){ onlineImg.setAttribute("src", this.onlineImagePath); } var offlineImg = dojo.byId("dot-widget-network-indicator-offline"); if(offlineImg){ offlineImg.setAttribute("src", this.offlineImagePath); } var roller = dojo.byId("dot-roller"); if(roller){ roller.setAttribute("src", this.rollerImagePath); } var checkmark = dojo.byId("dot-success-checkmark"); if(checkmark){ checkmark.setAttribute("src", this.checkmarkImagePath); } }, _showDetails: function(evt){ // cancel the button's default behavior evt.preventDefault(); evt.stopPropagation(); if(!dojox.off.sync.details.length){ return; } // determine our HTML message to display var html = ""; html += "