indexzero
3/28/2011 - 6:40 PM

preloader.js

// spew out some info
function load(src,preloader) {
    console.log("loaded:",preloader._loaded.length ,"still queued:",preloader._queue.length);
}
var arr = []
for(var i = 0; i < 100; i++) {
    arr.push("localhost?v="+i);
}
preload.queue(arr,load);
//
// Set up a default preloader for websites
//
var preload = new PreLoader();
preload.addFileType("js","text/javascript");
preload.addFileType("jpg","image/jpeg");
preload.addFileType("jpeg","image/jpeg");
preload.addFileType("gif","image/gif");
preload.addFileType("png","image/png");
preload.addFileType("css","text/css");

preload.addMimeHandler("text/javascript",function(src,next){
    var elem = document.createElement("script");
    elem.type = "text/javascript";
    elem.src = src;
    var done = false;
    function finish(err) {
        if(done) return;
        done = true;
        elem.parentNode.removeChild(elem);
        next(err,elem);
    }
    elem.onload = function onLoad(){finish();};
    elem.onreadystatechange = function onReadyState() {
        var state = String(elem.readyState).toLowerCase();
        if(state === "completed") finish();
    };
    elem.onerror = function onError(){finish(arguments);};
    document.body.appendChild(elem);
});

preload.addMimeHandler("image/*",function(src,next){
    var elem = document.createElement("img");
    elem.src = src;
    var done = false;
    function finish(err) {
        if(done) return;
        done = true;
        elem.parentNode.removeChild(elem);
        next(err,elem);
    }
    elem.onload = finish;
    elem.onreadystatechange = function onReadyState() {
        var state = String(elem.readyState).toLowerCase();
        if(state === "completed") finish(false);
    };
    elem.onerror = function onError(){finish(arguments);};
    document.body.appendChild(elem);
});

preload.addMimeHandler("text/css",function(src,next){
    var elem = document.createElement("link");
    elem.type = "text/css";
    elem.rel = "stylesheet";
    elem.src = src;
    var done = false;
    function finish(err) {
        if(done) return;
        done = true;
        elem.parentNode.removeChild(elem);
        next(err,elem);
    }
    elem.onload = finish;
    elem.onreadystatechange = function onReadyState() {
        var state = String(elem.readyState).toLowerCase();
        if(state === "completed") finish();
    };
    elem.onerror = function onError(){finish(arguments);};
    document.body.appendChild(elem);
});
//
//  Create our type
//
function PreLoader() {
    this._queue = [];
    this._mime = {};
    this._handlers = {};
    this._loaded = [];
};
PreLoader.prototype.addFileType = function addFileType(extension,mime) {
    var ext = "." + extension.toLowerCase().replace(/^[.]/,"");
    this._mime[ ext ] = mime;
    return this;
};
//cb(next(err,?))
PreLoader.prototype.addMimeHandler = function addMimeHandler(mime,cb) {
    ;(this._handlers[ mime ] || (this._handlers[ mime ] = [])).push(cb);
    return this;
};  
//mime will be inferred if missing
//callback and mime are optional
PreLoader.prototype.queue = function queue(src,mime,callback) {
    var self = this;
    if(src instanceof Array || (typeof src === "object" && src.length)) {
        if(typeof mime === "function") {
            callback = mime;
        }
        var done = 0;
        var l = src.length;
        function finish() {
            done++;
            if(done === l) {
              if(callback) callback(src,self);
            }
        };
        for(var i = 0; i < l; i++) {
            queue.call(this,src[i],finish);
        }
        return;
    }
    if(arguments.length === 2 && typeof mime === "function") {
        callback = mime;
        mime = this._mime[ src.match(/[.]\w+(?=[?]|$)/)[0].toLowerCase() ];;
    }
    else {
        mime = mime || this._mime[ src.match(/[.]\w+(?=[?]|$)/)[0].toLowerCase() ];
    }
    var handlers = this._handlers[ mime ];
    if(!handlers) {
        var parts = mime.split("/");
        while(!handlers) {
            parts.pop();
            handlers = this._handlers[ parts.join("/") + "/*" ]
        }
    }
    var l = handlers.length;
    var finished = 0;
    function next() {
        finished++;
        if(finished === l) {
            finished++;
            var queue = self.queue;
            for(var i = 0; i < queue.length; i++) {
                if(queue[i] === src) {
                    queue.splice(i,1);
                }
            }
            self._loaded.push(src);
            if(callback) callback(src,self);
        }
    }
    for(var i = 0; i < l; i++) {
        handlers[ i ](src,next);
    }
    return this;
};