1;(function (factory) { 2 if (typeof define === 'function' && define.amd) { 3 // AMD. Register as an anonymous module. 4 define(['jquery'], factory); 5 } else if (typeof exports === 'object') { 6 // CommonJS / nodejs module 7 module.exports = factory(require('jquery')); 8 } else { 9 // Browser globals 10 factory(jQuery); 11 } 12}(function ($) { 13 // Namespace all events. 14 var eventNamespace = 'waitForImages'; 15 16 // CSS properties which contain references to images. 17 $.waitForImages = { 18 hasImageProperties: [ 19 'backgroundImage', 20 'listStyleImage', 21 'borderImage', 22 'borderCornerImage', 23 'cursor' 24 ], 25 hasImageAttributes: ['srcset'] 26 }; 27 28 // Custom selector to find all `img` elements with a valid `src` attribute. 29 $.expr[':']['has-src'] = function (obj) { 30 // Ensure we are dealing with an `img` element with a valid 31 // `src` attribute. 32 return $(obj).is('img[src][src!=""]'); 33 }; 34 35 // Custom selector to find images which are not already cached by the 36 // browser. 37 $.expr[':'].uncached = function (obj) { 38 // Ensure we are dealing with an `img` element with a valid 39 // `src` attribute. 40 if (!$(obj).is(':has-src')) { 41 return false; 42 } 43 44 return !obj.complete; 45 }; 46 47 $.fn.waitForImages = function () { 48 49 var allImgsLength = 0; 50 var allImgsLoaded = 0; 51 var deferred = $.Deferred(); 52 53 var finishedCallback; 54 var eachCallback; 55 var waitForAll; 56 57 // Handle options object (if passed). 58 if ($.isPlainObject(arguments[0])) { 59 60 waitForAll = arguments[0].waitForAll; 61 eachCallback = arguments[0].each; 62 finishedCallback = arguments[0].finished; 63 64 } else { 65 66 // Handle if using deferred object and only one param was passed in. 67 if (arguments.length === 1 && $.type(arguments[0]) === 'boolean') { 68 waitForAll = arguments[0]; 69 } else { 70 finishedCallback = arguments[0]; 71 eachCallback = arguments[1]; 72 waitForAll = arguments[2]; 73 } 74 75 } 76 77 // Handle missing callbacks. 78 finishedCallback = finishedCallback || $.noop; 79 eachCallback = eachCallback || $.noop; 80 81 // Convert waitForAll to Boolean 82 waitForAll = !! waitForAll; 83 84 // Ensure callbacks are functions. 85 if (!$.isFunction(finishedCallback) || !$.isFunction(eachCallback)) { 86 throw new TypeError('An invalid callback was supplied.'); 87 } 88 89 this.each(function () { 90 // Build a list of all imgs, dependent on what images will 91 // be considered. 92 var obj = $(this); 93 var allImgs = []; 94 // CSS properties which may contain an image. 95 var hasImgProperties = $.waitForImages.hasImageProperties || []; 96 // Element attributes which may contain an image. 97 var hasImageAttributes = $.waitForImages.hasImageAttributes || []; 98 // To match `url()` references. 99 // Spec: http://www.w3.org/TR/CSS2/syndata.html#value-def-uri 100 var matchUrl = /url\(\s*(['"]?)(.*?)\1\s*\)/g; 101 102 if (waitForAll) { 103 104 // Get all elements (including the original), as any one of 105 // them could have a background image. 106 obj.find('*').addBack().each(function () { 107 var element = $(this); 108 109 // If an `img` element, add it. But keep iterating in 110 // case it has a background image too. 111 if (element.is('img:has-src')) { 112 allImgs.push({ 113 src: element.attr('src'), 114 element: element[0] 115 }); 116 } 117 118 $.each(hasImgProperties, function (i, property) { 119 var propertyValue = element.css(property); 120 var match; 121 122 // If it doesn't contain this property, skip. 123 if (!propertyValue) { 124 return true; 125 } 126 127 // Get all url() of this element. 128 while (match = matchUrl.exec(propertyValue)) { 129 allImgs.push({ 130 src: match[2], 131 element: element[0] 132 }); 133 } 134 }); 135 136 $.each(hasImageAttributes, function (i, attribute) { 137 var attributeValue = element.attr(attribute); 138 var attributeValues; 139 140 // If it doesn't contain this property, skip. 141 if (!attributeValue) { 142 return true; 143 } 144 145 // Check for multiple comma separated images 146 attributeValues = attributeValue.split(','); 147 148 $.each(attributeValues, function(i, value) { 149 // Trim value and get string before first 150 // whitespace (for use with srcset). 151 value = $.trim(value).split(' ')[0]; 152 allImgs.push({ 153 src: value, 154 element: element[0] 155 }); 156 }); 157 }); 158 }); 159 } else { 160 // For images only, the task is simpler. 161 obj.find('img:has-src') 162 .each(function () { 163 allImgs.push({ 164 src: this.src, 165 element: this 166 }); 167 }); 168 } 169 170 allImgsLength = allImgs.length; 171 allImgsLoaded = 0; 172 173 // If no images found, don't bother. 174 if (allImgsLength === 0) { 175 finishedCallback.call(obj[0]); 176 deferred.resolveWith(obj[0]); 177 } 178 179 $.each(allImgs, function (i, img) { 180 181 var image = new Image(); 182 var events = 183 'load.' + eventNamespace + ' error.' + eventNamespace; 184 185 // Handle the image loading and error with the same callback. 186 $(image).one(events, function me (event) { 187 // If an error occurred with loading the image, set the 188 // third argument accordingly. 189 var eachArguments = [ 190 allImgsLoaded, 191 allImgsLength, 192 event.type == 'load' 193 ]; 194 allImgsLoaded++; 195 196 eachCallback.apply(img.element, eachArguments); 197 deferred.notifyWith(img.element, eachArguments); 198 199 // Unbind the event listeners. I use this in addition to 200 // `one` as one of those events won't be called (either 201 // 'load' or 'error' will be called). 202 $(this).off(events, me); 203 204 if (allImgsLoaded == allImgsLength) { 205 finishedCallback.call(obj[0]); 206 deferred.resolveWith(obj[0]); 207 return false; 208 } 209 210 }); 211 212 image.src = img.src; 213 }); 214 }); 215 216 return deferred.promise(); 217 218 }; 219}));
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.