﻿/**
* 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: <span>' + imgUrls[loaded].split('/')[imgUrls[loaded].split('/').length - 1] :
					'Loading complete'; // wrong status-text bug fixed
                jQuery(settings.statusTextEl).html('<span class="numLoaded">' + loaded + '</span> of <span class="numTotal">' + imgUrls.length + '</span> loaded (<span class="percentLoaded">' + (loaded / imgUrls.length * 100).toFixed(0) + '%</span>) <span class="currentImg">' + nowloading + '</span></span>');
            }
            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)
    {
        try{
            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);
            }
        }
        catch(err){}
    }
    parseCSS(document.styleSheets);
    return imgUrls;
};
