Hi all, After comments on the previous version by Roberto, I looked into creating callbacks within the code so that it can be used in the way that Roberto had outlined, also I used it as a way to improve my knowledge a little.
After a while I got stuck and figured out a potential method thanks to ai-a in #Javascript on UnderNet, then I spoke to Remy Sharp on Twitter and always being impressed with the work he does on his site (http://www.jqueryfordesigners.com) I asked politely if he would give my code a quick look over. He did so, and so much more besides.
So I present to you now v0.95 of the Image Pre-loader which is now Split into 3 functions (rather than the 2 from before)
So the main functionality is the same as the one from http://binarykitten.jkrswebsolutions.co.uk/2009/01/06/jquery-image-preloader/ but now has the following functions
- $.preLoadImages – Preload the passed list of images, calling the passed call back function when all images are preloaded
- $.preLoadCSSImages – Preload all images found within the stylesheets of the document, then call the passed call back function when all the images are preloaded
- $.preLoadAllImages – Processes the stylesheet images and then if passed additional images, will process them too. When all are complete will call the passed callback function.
Here’s the actual code now for the plugin:
/* jQuery.preloader - v0.95 - K Reeve aka BinaryKitten
*
* v0.95
* # Note - keeping below v1 as really not sure that I consider it public usable.
* # But it saying that it does the job it was intended to do.
* Added Completion of loading callback.
* Main Reworking With Thanks to Remy Sharp of jQuery for Designers
*
*
* v0.9
* Fixed .toString being .toSteing
*
* v0.8
* Fixed sheet.href being null error (was causing issues in FF3RC1)
*
* v0.7
* Remade the preLoadImages from jQuery to DOM
*
* v0.6
* Fixed IE6 Compatability!
* Moved from jQuery to DOM
*
* v0.5
* Shifted the additionalimages loader in the preLoadAllImages so it wasn't called multiple times
* Created secondary .preLoadImages to handle additionalimages and so it can be called on itself
*/
(function ($) {
$.preLoadImages = function(imageList,callback) {
var pic = [], i, total, loaded = 0;
if (typeof imageList != 'undefined') {
if ($.isArray(imageList)) {
total = imageList.length; // used later
for (i=0; i < total; i++) {
pic[i] = new Image();
pic[i].onload = function() {
loaded++; // should never hit a race condition due to JS's non-threaded nature
if (loaded == total) {
if ($.isFunction(callback)) {
callback();
}
}
};
pic[i].src = imageList[i];
}
}
else {
pic[0] = new Image();
pic[0].onload = function() {
if ($.isFunction(callback)) {
callback();
}
}
pic[0].src = imageList;
}
}
pic = undefined;
};
$.preLoadCSSImages = function(callback) {
var pic = [], i, imageList = [], loaded = 0, total, regex = new RegExp("url\((.*)\)",'i'),spl;
var cssSheets = document.styleSheets, path,myRules,Rule,match,txt,img,sheetIdx,ruleIdx;
for (sheetIdx=0;sheetIdx < cssSheets.length;sheetIdx++){
var sheet = cssSheets[sheetIdx];
if (typeof sheet.href == 'string' && sheet.href.length > 0) {
spl = sheet.href.split('/');spl.pop();path = spl.join('/')+'/';
}
else {
path = './';
}
myRules = sheet.cssRules ? sheet.cssRules : sheet.rules;
for (ruleIdx=0;ruleIdx < myRules.length;ruleIdx++) {
Rule = myRules[ruleIdx];
txt = Rule.cssText ? Rule.cssText : Rule.style.cssText;
match = regex.exec(txt);
if (match != null) {
img = match[1].substring(1,match[1].indexOf(')',1));
if (img.substring(0,4) == 'http') {
imageList[imageList.length] = img;
}
else if ( match[1].substring(1,2) == '/') {
var p2 = path.split('/');p2.pop();p2.pop();p2x = p2.join("/");
imageList[imageList.length] = p2x+img;
}
else {
imageList[imageList.length] = path+img;
}
}
};
};
total = imageList.length; // used later
for (i=0; i < total; i++) {
pic[i] = new Image();
pic[i].onload = function() {
loaded++; // should never hit a race condition due to JS's non-threaded nature
if (loaded == total) {
if ($.isFunction(callback)) {
callback();
}
}
};
pic[i].src = imageList[i];
}
};
$.preLoadAllImages = function(imageList,callback) {
if (typeof imageList != 'undefined') {
if ($.isFunction(imageList)) {
callback = imageList;
}
else if (!$.isArray(imageList)) {
imageList = [imageList];
}
}
$.preLoadCSSImages(function(){
if (imageList.length > 0) {
$.preLoadImages(imageList,function(){
callback();
});
}
else {
callback();
}
});
}
})(jQuery);
So now with these in place we can call them as so:
$.preLoadImages(
[
'http://www.google.co.uk/intl/en_uk/images/logo.gif',
'http://l.yimg.com/eur.yimg.com/i/uk/hp/yahoo1.png',
'http://tk2.stc.s-msn.com/br/hp/11/en-us/css/i/msn_b2.gif'
],function(){
alert('All Passed Images Loaded');
}
);
$.preLoadCSSImages(function(){
alert('All CSS Images Loaded');
});
$.preLoadAllImages(
[
'http://www.google.co.uk/intl/en_uk/images/logo.gif',
'http://l.yimg.com/eur.yimg.com/i/uk/hp/yahoo1.png',
'http://tk2.stc.s-msn.com/br/hp/11/en-us/css/i/msn_b2.gif'
],function(){
alert('All Passed Images and All CSS Images Loaded');
}
);
To match up with Robert’s request for a loader image…
$.preLoadImages('/images/loader.gif',function() {
/* Pre Load the loader gif first */
$('<img />').attr({
src:'/images/loader.gif',
id:'loader'
}).appendTo('#position');
/* now preload stuff */
$.preLoadCSSImages(function() {
$('#loader').remove();
})
});
Hopefully you have found this useful, as usual.. comments gratefully received.
[edit]
Thanks to Roberto for pointing out that the source had become corrupted in the post
That’s great, Kat! Thank you so much for giving attention to my requests. I’ll give it a try and post some feedback.
Great work! So easy to use..
Thanks
will check this out… it will be great if it will work in ie678 opera 8+ safari 2+ chrome 3.0 and ff 2+
Very nice, any chance you will compile using google closure.
not looked at google closure yet for compiling.. but will do.
Should work in all browsers.. if it doesn’t please do let me know
I keep getting this error while trying to preload CSS images. Kind of a noob… Is there something I’m supposed to customize within the plugin?
Error: missing ) after condition
Column: 41
Source Code:
if (typeof sheet.href == ‘string’ && sheet.href.length > 0) {
those ampersands and that greater than symbol were supposed to stay in html. arg
There is a problem concerning css preload, firebug spits out the following url:
http://somehost.com/css/%22../images/some_image.png%22
which should look like this:
http://somehost.com/css/images/some_image.png
are we supposed to use absolute paths in our css stylesheets?
got it, just append a substring to get rid of the quotation marks..
thanks for pointing this out, Will update for the next version.. (coming soon)
excellent script, but there’s another thing. i get a 403 error while trying to get attached css documents when testing it online.. no problem locally though..
Hey, when using @font-face and loading a font file in the attached CSS-Stylesheet, your script never fires a callback, since this if (loaded == total) is never reached, not sure why, but I dig into it.
Hey franton, what code did you add to fix your css image path problem? I’m getting the same thing.
has problems with ie6 and 7. it seems to have problems with the loaded. i don’t know what specifically.
It’s because it’s trying to load the font-face url into an image. Will need to add extra validation for those specific cases where the url keyword is not used for images and filter them out. Will think how to best achieve this for the next vesion. Due soon I hope.
@Ambrosia
Put following code in Line 77
img = match[1].substring(2,(match[1].indexOf(‘)’,1)-1));
In Firefox the preLoadAllImages function works… but when I open the same page in chrome it simply doesn’t.
Stil looking what the prob is.
Seems great. I will test this
This is what Firebug tells me, and also the IE8 javascript error alert.
Security error” code: “1000
[Break on this error] myRules = sheet.cssRules ? sheet.cssRules : sheet.rules;
preloadimages.js (rad 50)
Would processing be any quicker if I did not need to preload stylesheet images?
@Riball I’m having the same issue. I don’t suppose you ever found a fix?
I doen’t get the Alert from the callback of preLoadAllImages (others are untested at the momen).
@Kryptic: thx, your solution worked!
thx for this good script!