/ Published in: JavaScript
                    
                                        
                            
                                Expand |
                                Embed | Plain Text
                            
                        
                        Copy this code and paste it in your HTML
/**
* HTML5 offline manifest preloader.
*
* Load all manifest cached entries, so that they are immediately available during the web app execution.
* Display some nice JQuery progress while loading.
*
* @copyright 2010 mFabrik Research
*
* @author Mikko Ohtamaa <[email protected]>
*/
/**
* Preloader class constructor.
*
* Manifest is retrieved via HTTP GET and parsed.
* All cache entries are loaded using HTTP GET.
*
* Local storage attribute "preloaded" is used to check whether loading needs to be performed,
* as it is quite taxing operation.
*
* To debug this code and force retrieving of all manifest URLs, add reloaded=true HTTP GET query parameter:
*
*
*
* @param {Function} endCallback will be called when all offline entries are loaded
*
* @param {Object} progressMonitor ProgressMonitor object for which the status of the loading is reported.
*/
function ApplicationCachePreloader(endCallback, progressMonitor, debug) {
if(!progressMonitor) {
throw "progressMonitor must be defined";
}
this.endCallback = endCallback;
this.progressMonitor = progressMonitor;
this.logging = debug; // Flag to control console.log() output
this.eventCount = 0;
}
ApplicationCachePreloader.prototype = {
translateEventCode : function(eventCode) {
var cacheStatusValues = [];
cacheStatusValues[0] = 'uncached';
cacheStatusValues[1] = 'idle';
cacheStatusValues[2] = 'checking';
cacheStatusValues[3] = 'downloading';
cacheStatusValues[4] = 'updateready';
cacheStatusValues[5] = 'obsolete';
return cacheStatusValues[eventCode];
},
trapEvents : function(cache, handler) {
cache.addEventListener('progress', handler, false);
try {
cache.addEventListener('cached', handler, false);
} catch(e) {
// FF 3.5 won't allow
}
cache.addEventListener('checking', handler, false);
cache.addEventListener('downloading', handler, false);
cache.addEventListener('error', handler, false);
cache.addEventListener('noupdate', handler, false);
cache.addEventListener('obsolete', handler, false);
cache.addEventListener('updateready', handler, false);
},
waitUntilAllowed : function() {
try {
cache.addEventListener('cached', handler, false);
} catch(e) {
// FF 3.5 needs user permission "Allow" in pop-up dialog
this.debug("Not allowed yet");
setTimeout(jQuery.proxy(this.waitUntilAllowed, this), 1000);
}
this.start();
},
deferEndCallback : function(success) {
function timemout() {
this.endCallback(success);
}
setTimeout(jQuery.proxy(timemout, this), 100);
},
/**
* Do everything necessary to set-up offline application
*
* @return true if applicationCache loading performed succesfully
*/
load : function() {
//alert("load");
if (window.applicationCache) {
this.debug("ApplicationCache status " + window.applicationCache.status);
this.debug("Please see http://www.w3.org/TR/html5/offline.html#applicationcache");
} else {
// This could be probably worked around on Google Chrome using Gears extension somehow
this.silentError("applicationCache object not supported");
this.deferEndCallback(true);
return true;
}
// Can't update
if(!navigator.onLine) {
this.debug("Not online");
this.deferEndCallback(true);
return true;
}
if(jQuery.browser.mozilla) {
// Mozilla won't work until user answers "Allow" to pop-up dialog,
// put dialog seems to be broken
this.deferEndCallback(true);
return false;
//this.waitUntilAllowed();
} else {
this.start();
}
return true;
},
start : function() {
//alert("Started");
this.debug("Preloading starting - xxxx");
this.progressMonitor.start();
this.trapEvents(window.applicationCache, jQuery.proxy(this.handleEvent, this));
var cache = window.applicationCache;
if(cache.status == 4) {
this.debug("Update complete");
this.end(true);
}
if (cache.status == 1) {
this.debug("Idle - manifest not changed");
this.end(true);
}
if (cache.status == 0) {
this.debug("Uncached - offline mode not enabled (prolly not saved on desktop/mainscreen and running straight from the browser)");
this.end(true);
}
//alert("Trapping");
this.debug("Trapping and waiting events, status:"+ cache.status);
},
end : function(success) {
//alert("Ended:" + success);
// Trigger activation of new cache if available
if(status) {
if(!window.applicationCache) {
// blaa... not supported
} else {
window.applicationCache.swapCache();
}
}
this.debug("Preloading ending to " + success);
this.progressMonitor.end(success);
this.endCallback(success);
},
handleEvent : function(e) {
var online, status, type, message;
var cache = window.applicationCache;
online = (navigator.onLine) ? 'yes' : 'no';
status = this.translateEventCode(cache.status);
type = e.type;
message = 'online: ' + online;
message+= ', event: ' + type;
message+= ', status: ' + status;
if (type == 'error' && navigator.onLine) {
message+= ' (prolly a syntax error in manifest)';
}
// this.debug(message);
// $("body").append("<p>" + message + "</p>");
this.eventCount++;
if(status == "downloading" || status == "checking") {
this.progressMonitor.update(type, this.eventCount, this.eventCount);
} else {
console.log("Got event " + this.eventCount + " " + status);
//alert("event:" + status);
}
if(status == "error") {
this.end(false);
}
// Google Chrome reports "uncached" when the application offline
// mode is not enabled - allow still to run in the browser
// without doing resource caching
if(status == "cached" || status == "updateready" || status == "idle" || status == "uncached") {
this.end(true);
}
},
/**
* Write to debug console
*
* @param {String} msg
*/
debug : function(msg) {
if(this.logging) {
console.log(msg);
}
},
/**
* Non-end user visible error message
*
* @param {Object} msg
*/
silentError : function(msg) {
console.log(msg);
}
};
function ProgressMonitor() {
};
ProgressMonitor.prototype = {
/**
* Start progress bar... initialize as 0 / 0
*/
start : function(status, coldVirgin) {
$("#web-app-updating").show();
if(window.navigator.standlone) {
$("#web-app-updating .standalone").show();
}
},
end: function(status) {
$("#web-app-updating").hide();
},
update : function(status, currentEntry, maxEntries) {
$("#web-app-updating .event-count").text(currentEntry);
},
/**
* Called when application has not been saved on the desktop.
*
* ...problems with Mobile Safari cache size.
*/
needWebAppMode : function() {
$("#web-app-no-browser").show();
}
};
Comments
 Subscribe to comments
                    Subscribe to comments
                
                