summaryrefslogtreecommitdiff
path: root/static/js/src/imgcache.js
diff options
context:
space:
mode:
Diffstat (limited to 'static/js/src/imgcache.js')
-rw-r--r--static/js/src/imgcache.js141
1 files changed, 141 insertions, 0 deletions
diff --git a/static/js/src/imgcache.js b/static/js/src/imgcache.js
new file mode 100644
index 0000000..9cffb1d
--- /dev/null
+++ b/static/js/src/imgcache.js
@@ -0,0 +1,141 @@
+
+/*
+ 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": {}, // <img> 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 <stevenlevithan.com>, 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