/* * waitForImages 1.4 * ----------------- * Provides a callback when all images have loaded in your given selector. * https://www.alexanderdickson.com/ * * * Copyright (c) 2011 Alex Dickson * Licensed under the MIT licenses. * See website for more info. * */ ;(function($) { // Namespace all events. var eventNamespace = 'waitForImages'; // CSS properties which contain references to images. $.waitForImages = { hasImageProperties: [ 'backgroundImage', 'listStyleImage', 'borderImage', 'borderCornerImage' ] }; // Custom selector to find `img` elements that have a valid `src` attribute and have not already loaded. $.expr[':'].uncached = function(obj) { // Ensure we are dealing with an `img` element with a valid `src` attribute. if ( ! $(obj).is('img[src!=""]')) { return false; } // Firefox's `complete` property will always be`true` even if the image has not been downloaded. // Doing it this way works in Firefox. var img = document.createElement('img'); img.src = obj.src; return ! img.complete; }; $.fn.waitForImages = function(finishedCallback, eachCallback, waitForAll) { // Handle options object. if ($.isPlainObject(arguments[0])) { eachCallback = finishedCallback.each; waitForAll = finishedCallback.waitForAll; finishedCallback = finishedCallback.finished; } // Handle missing callbacks. finishedCallback = finishedCallback || $.noop; eachCallback = eachCallback || $.noop; // Convert waitForAll to Boolean waitForAll = !! waitForAll; // Ensure callbacks are functions. if (!$.isFunction(finishedCallback) || !$.isFunction(eachCallback)) { throw new TypeError('An invalid callback was supplied.'); }; return this.each(function() { // Build a list of all imgs, dependent on what images will be considered. var obj = $(this), allImgs = []; if (waitForAll) { // CSS properties which may contain an image. var hasImgProperties = $.waitForImages.hasImageProperties || [], matchUrl = /url\((['"]?)(.*?)\1\)/g; // Get all elements, as any one of them could have a background image. obj.find('*').each(function() { var element = $(this); // If an `img` element, add it. But keep iterating in case it has a background image too. if (element.is('img:uncached')) { allImgs.push({ src: element.attr('src'), element: element[0] }); } $.each(hasImgProperties, function(i, property) { var propertyValue = element.css(property); // If it doesn't contain this property, skip. if ( ! propertyValue) { return true; } // Get all url() of this element. var match; while (match = matchUrl.exec(propertyValue)) { allImgs.push({ src: match[2], element: element[0] }); }; }); }); } else { // For images only, the task is simpler. obj .find('img:uncached') .each(function() { allImgs.push({ src: this.src, element: this }); }); }; var allImgsLength = allImgs.length, allImgsLoaded = 0; // If no images found, don't bother. if (allImgsLength == 0) { finishedCallback.call(obj[0]); }; $.each(allImgs, function(i, img) { var image = new Image; // Handle the image loading and error with the same callback. $(image).bind('load.' + eventNamespace + ' error.' + eventNamespace, function(event) { allImgsLoaded++; // If an error occurred with loading the image, set the third argument accordingly. eachCallback.call(img.element, allImgsLoaded, allImgsLength, event.type == 'load'); if (allImgsLoaded == allImgsLength) { finishedCallback.call(obj[0]); return false; }; }); image.src = img.src; }); }); }; })(jQuery);