/** * jQuery-Plugin "preloadCssImages" * by Scott Jehl, scott@filamentgroup.com * http://www.filamentgroup.com * reference article: http://www.filamentgroup.com/lab/update_automatically_preload_images_from_css_with_jquery/ * demo page: http://www.filamentgroup.com/examples/preloadImages/index_v2.php * * Copyright (c) 2008 Filament Group, Inc * Dual licensed under the MIT (filamentgroup.com/examples/mit-license.txt) and GPL (filamentgroup.com/examples/gpl-license.txt) licenses. * * Version: 5.0, 10.31.2008 * Changelog: * 02.20.2008 initial Version 1.0 * 06.04.2008 Version 2.0 : removed need for any passed arguments. Images load from any and all directories. * 06.21.2008 Version 3.0 : Added options for loading status. Fixed IE abs image path bug (thanks Sam Pohlenz). * 07.24.2008 Version 4.0 : Added support for @imported CSS (credit: http://marcarea.com/). Fixed support in Opera as well. * 10.31.2008 Version: 5.0 : Many feature and performance enhancements from trixta * -------------------------------------------------------------------- */ ;jQuery.preloadCssImages = function(settings){ settings = jQuery.extend({ statusTextEl: null, statusBarEl: null, errorDelay: 999, // handles 404-Errors in IE simultaneousCacheLoading: 2 }, settings); var allImgs = [], loaded = 0, imgUrls = [], thisSheetRules, errorTimer; function onImgComplete(){ clearTimeout(errorTimer); if (imgUrls && imgUrls.length && imgUrls[loaded]) { loaded++; if (settings.statusTextEl) { var nowloading = (imgUrls[loaded]) ? 'Now Loading: ' + imgUrls[loaded].split('/')[imgUrls[loaded].split('/').length - 1] : 'Loading complete'; // wrong status-text bug fixed jQuery(settings.statusTextEl).html('' + loaded + ' of ' + imgUrls.length + ' loaded (' + (loaded / imgUrls.length * 100).toFixed(0) + '%) ' + nowloading + ''); } if (settings.statusBarEl) { var barWidth = jQuery(settings.statusBarEl).width(); jQuery(settings.statusBarEl).css('background-position', -(barWidth - (barWidth * loaded / imgUrls.length).toFixed(0)) + 'px 50%'); } loadImgs(); } } function loadImgs(){ //only load 1 image at the same time / most browsers can only handle 2 http requests, 1 should remain for user-interaction (Ajax, other images, normal page requests...) // otherwise set simultaneousCacheLoading to a higher number for simultaneous downloads if(imgUrls && imgUrls.length && imgUrls[loaded]){ var img = new Image(); //new img obj img.src = imgUrls[loaded]; //set src either absolute or rel to css dir if(!img.complete){ jQuery(img).bind('error load onreadystatechange', onImgComplete); } else { onImgComplete(); } errorTimer = setTimeout(onImgComplete, settings.errorDelay); // handles 404-Errors in IE } } function parseCSS(sheets, urls) { var w3cImport = false, imported = [], importedSrc = [], baseURL; var sheetIndex = sheets.length; while(sheetIndex--){//loop through each stylesheet var cssPile = '';//create large string of all css rules in sheet if(urls && urls[sheetIndex]){ baseURL = urls[sheetIndex]; } else { var csshref = (sheets[sheetIndex].href) ? sheets[sheetIndex].href : 'window.location.href'; var baseURLarr = csshref.split('/');//split href at / to make array baseURLarr.pop();//remove file path from baseURL array baseURL = baseURLarr.join('/');//create base url for the images in this sheet (css file's dir) if (baseURL) { baseURL += '/'; //tack on a / if needed } } if(sheets[sheetIndex].cssRules || sheets[sheetIndex].rules){ thisSheetRules = (sheets[sheetIndex].cssRules) ? //->>> http://www.quirksmode.org/dom/w3c_css.html sheets[sheetIndex].cssRules : //w3 sheets[sheetIndex].rules; //ie var ruleIndex = thisSheetRules.length; while(ruleIndex--){ if(thisSheetRules[ruleIndex].style && thisSheetRules[ruleIndex].style.cssText){ var text = thisSheetRules[ruleIndex].style.cssText; if(text.toLowerCase().indexOf('url') != -1){ // only add rules to the string if you can assume, to find an image, speed improvement cssPile += text; // thisSheetRules[ruleIndex].style.cssText instead of thisSheetRules[ruleIndex].cssText is a huge speed improvement } } else if(thisSheetRules[ruleIndex].styleSheet) { imported.push(thisSheetRules[ruleIndex].styleSheet); w3cImport = true; } } } //parse cssPile for image urls var tmpImage = cssPile.match(/[^\("]+\.(gif|jpg|jpeg|png)/g);//reg ex to get a string of between a "(" and a ".filename" / '"' for opera-bugfix if(tmpImage){ var i = tmpImage.length; while(i--){ // handle baseUrl here for multiple stylesheets in different folders bug var imgSrc = (tmpImage[i].charAt(0) == '/' || tmpImage[i].match('://')) ? // protocol-bug fixed tmpImage[i] : baseURL + tmpImage[i]; if(jQuery.inArray(imgSrc, imgUrls) == -1){ imgUrls.push(imgSrc); } } } if(!w3cImport && sheets[sheetIndex].imports && sheets[sheetIndex].imports.length) { for(var iImport = 0, importLen = sheets[sheetIndex].imports.length; iImport < importLen; iImport++){ var iHref = sheets[sheetIndex].imports[iImport].href; iHref = iHref.split('/'); iHref.pop(); iHref = iHref.join('/'); if (iHref) { iHref += '/'; //tack on a / if needed } var iSrc = (iHref.charAt(0) == '/' || iHref.match('://')) ? // protocol-bug fixed iHref : baseURL + iHref; importedSrc.push(iSrc); imported.push(sheets[sheetIndex].imports[iImport]); } } }//loop if(imported.length){ parseCSS(imported, importedSrc); return false; } var downloads = settings.simultaneousCacheLoading; while( downloads--){ setTimeout(loadImgs, downloads); } } parseCSS(document.styleSheets); return imgUrls; }; $(document).ready(function(){ $.preloadCssImages(); });