/* timb: the ImgCache manages loading images and keeping track of image sizes... it can be passed a bunch of urls to load and a callback that gets called when more images are ready image loading can also be paused and started again. there can be separate ImageCaches, eg, one for search result images, one for chat images (but they all share the actual image cache) In theory it should also avoid a few http requests bc we can just dup DOM nodes for images that are already loaded that don't have cache headers (not sure tho, browsers probably pretty aggressive with that already) */ var ImgCache = { "imgs": {}, // nodes indexed by url "caches": {}, "init": function(name){ // don't clear callback var callback = emptyFunc if (name in ImgCache.caches) callback = ImgCache.caches[name].onImgsLoaded delete ImgCache.caches[name] ImgCache.caches[name] = { "loadAtATime": 10, "urlsToLoad": [], "imgsLoading": {}, "imgsLoadingCounter" : 0, // a hack so i don't have to iterate over the object to always get its size... "imgsLoaded": {}, "onImgsLoaded": callback, "paused": false } }, "add": function(name, urls){ if (!(name in ImgCache.caches)) ImgCache.init(name) if (!$.isArray(urls)) urls = [urls]; var cache = ImgCache.caches[name] urls.forEach(function(url){ cache.urlsToLoad.push(url) }) }, "config": function(name, cfg){ if (!(name in ImgCache.caches)) ImgCache.init(name) var cache = ImgCache.caches[name] for(var key in cfg) cache[key] = cfg[key] }, "clear": function(name){ ImgCache.init(name) }, "pause": function(name){ ImgCache.caches[name].paused = true }, "unpause": function(name){ ImgCache.caches[name].paused = false }, "loadImages": function(cache){ if (cache.paused) return; while(cache.urlsToLoad.length && cache.imgsLoadingCounter < cache.loadAtATime) { var url = cache.urlsToLoad.shift() if (url in ImgCache.imgs) { // already loading this image var img = ImgCache.imgs[url] if (img.complete) { cache.imgsLoaded[url] = ImgCache.imgs[url] } else if (!(url in cache.imgsLoading)) { cache.imgsLoading[url] = ImgCache.imgs[url] cache.imgsLoadingCounter += 1 } } else { var img = new Image() img.src = url img.animated = (parseUri(url)["file"].toLowerCase().substr(-3) == "gif") ? true : false; ImgCache.imgs[url] = img cache.imgsLoading[url] = img cache.imgsLoadingCounter += 1 } } }, "processLoadingImages": function(cache){ for (var url in cache.imgsLoading) { var img = cache.imgsLoading[url] if (img.complete) { cache.imgsLoaded[url] = img delete cache.imgsLoading[url] cache.imgsLoadingCounter -= 1 } } }, "loader": function(){ for (name in ImgCache.caches){ var cache = ImgCache.caches[name] ImgCache.processLoadingImages(cache) // move images from imgsLoading into imgsLoaded ImgCache.loadImages(cache) // put new images in imgsLoading/imgsLoaded from urlsToLoad for (var url in cache.imgsLoaded) { cache.onImgsLoaded(cache.imgsLoaded) // only call if new images actually loaded delete cache.imgsLoaded cache.imgsLoaded = {} break; } } setTimeout(ImgCache.loader, 500) } } ImgCache.loader() // parseUri 1.2.2 from http://blog.stevenlevithan.com/archives/parseuri // (c) Steven Levithan , MIT License // timb: todo: this can't deal with @s in urls correctly. ex: http://www.classicbattletech.com/images/gallery/Combat_Operations_Cover@1280x960.jpg function parseUri (str) { var o = parseUri.options, m = o.parser[o.strictMode ? "strict" : "loose"].exec(str), uri = {}, i = 14; while (i--) uri[o.key[i]] = m[i] || ""; uri[o.q.name] = {}; uri[o.key[12]].replace(o.q.parser, function ($0, $1, $2) { if ($1) uri[o.q.name][$1] = $2; }); return uri; }; parseUri.options = { strictMode: false, key: ["source","protocol","authority","userInfo","user","password","host","port","relative","path","directory","file","query","anchor"], q: { name: "queryKey", parser: /(?:^|&)([^&=]*)=?([^&]*)/g }, parser: { strict: /^(?:([^:\/?#]+):)?(?:\/\/((?:(([^:@]*)(?::([^:@]*))?)?@)?([^:\/?#]*)(?::(\d*))?))?((((?:[^?#\/]*\/)*)([^?#]*))(?:\?([^#]*))?(?:#(.*))?)/, loose: /^(?:(?![^:@]+:[^:@\/]*@)([^:\/?#.]+):)?(?:\/\/)?((?:(([^:@]*)(?::([^:@]*))?)?@)?([^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/ } }; // end parseUri