You may recall, in this previous post I showed you how to use a bookmarklet (typically a small piece of JavaScript you can save as a bookmark and run against a page) to get the latest versions of CSS files and images, and not use the cached files. The previous version had some limitations. Namely:
- Background images set in CSS would not be refreshed
- Frame and iframe contents would not be refreshed
- In some instances it was one-hit only – i.e. you could only run it once, without having to manually refresh the page anyway
So, I would like to present to you – CacheBuster version 2. Or CacheBusterizer the second. Or MegaCacheKiller 2. You get the idea.
This time, I will step through the code and how it works.
Getting the current values of styles set via CSS can be a pain. Unless they were explicitly set via JavaScript, we can only fetch them using currentStyle
or getComputedStyle
, complete of course with their own browser idiosyncrasies. Therefore, the first thing we need is a function to do this for us in a cross-browser fashion. I have amended a version I found on Incoherent Babble.
function gcs(e,s) { if (typeof e.currentStyle != 'undefined') { return e.currentStyle[s]; } else { return document.defaultView.getComputedStyle(e, null)[s]; } }
In this instance, e
represents the element, and s
is a string representing the style we are looking for. Remember that we are looking JavaScript termed styles, not CSS – so backgroundImage
, rather than background-image
.
Since I am going to loop through all of the frames in the page, as well as the main window itself, I have decided to join these together in a single array, rather than writing the code out twice.
var z =[]; z.push(self); z.concat(self.frames);
To get the latest version of the files, I will just amend a querystring with the current time on the end of the filename.
var y = new Date().getTime();
And finally, we do the work:
for (k=0,l=z.length;k<l;k++) { x=z[k].document.getElementsByTagName('*'); for (i=0,j=x.length;i<j;i++){ bi = gcs(x[i],'backgroundImage'); if (bi.indexOf(')') > -1){ bi = bi.replace(/'/gi,'').replace(/"/gi,''); x[i].style.backgroundImage=bi.replace(')',(bi.indexOf('?')==-1?'?':'')+y+')'); } } x=z[k].document.getElementsByTagName('link'); for(i=0,j=x.length;i<j;i++){ x[i].href+=(x[i].href.indexOf('?')==-1?'?':'')+y; } x=z[k].document.getElementsByTagName('img'); for(i=0,j=x.length;i<j;i++){ x[i].src+=(x[i].src.indexOf('?')==-1?'?':'')+y; } }
This code:
- Loops through all elements on the page, checks to see if they have a background image set and appends the time on the end of the URI if they do
- Loops through all the
link
tags on a page for stylesheets, and appends the time on the end of thehref
of any it finds - Loops through all the
img
tags on a page, and appends the time on the end of thesrc
of any it finds
Finally, we wrap the whole lot in a closure to make sure we don’t mess with the main window
namespace, tidy up, and we get:
(function(){ var gcs = function(e,s) { if (typeof e.currentStyle != 'undefined') { return e.currentStyle[s]; } else { return document.defaultView.getComputedStyle(e, null)[s]; } }; var i,j,k,l,x,y,z,bi; z =[]; z.push(self); z.concat(self.frames); y = new Date().getTime(); for (k=0,l=z.length;k<l;k++) { x=z[k].document.getElementsByTagName('*'); for (i=0,j=x.length;i<j;i++){ bi = gcs(x[i],'backgroundImage'); if (bi.indexOf(')') > -1){ bi = bi.replace(/'/gi,'').replace(/"/gi,''); x[i].style.backgroundImage=bi.replace(')',(bi.indexOf('?')==-1?'?':'')+y+')'); }; }; x=z[k].document.getElementsByTagName('link'); for(i=0,j=x.length;i<j;i++){ x[i].href+=(x[i].href.indexOf('?')==-1?'?':'')+y; }; x=z[k].document.getElementsByTagName('img'); for(i=0,j=x.length;i<j;i++){ x[i].src+=(x[i].src.indexOf('?')==-1?'?':'')+y; }; }; })();
The last thing to do, is stick it all on one line, and prefix javascript:
and we’re done.
javascript:(function(){var gcs=function(e,s){if(typeof e.currentStyle!='undefined'){return e.currentStyle[s];}else{return document.defaultView.getComputedStyle(e,null)[s];}};var i,j,k,l,x,y,z,bi;z=[];z.push(self);z.concat(self.frames);y=new Date().getTime();for(k=0,l=z.length;k<l;k++){x=z[k].document.getElementsByTagName('*');for(i=0,j=x.length;i<j;i++){bi=gcs(x[i],'backgroundImage');if(bi.indexOf(')')>-1){bi=bi.replace(/'/gi,'').replace(/"/gi,'');x[i].style.backgroundImage=bi.replace(')',(bi.indexOf('?')==-1?'?':'')+y+')');}};x=z[k].document.getElementsByTagName('link');for(i=0,j=x.length;i<j;i++){x[i].href+=(x[i].href.indexOf('?')==-1?'?':'')+y;};x=z[k].document.getElementsByTagName('img');for(i=0,j=x.length;i<j;i++){x[i].src+=(x[i].src.indexOf('?')==-1?'?':'')+y;};};})();
Save this result as a bookmark, and any page you run the bookmark against will load all images and CSS anew, bypassing the cache! Phew.
The only remaining caveat I can think of: this won’t work for CSS included with the @import
directive. Any ideas?
Comments, as always, are welcome.