1/* 2 * Responsively Lazy 3 * http://ivopetkov.com/b/lazy-load-responsive-images/ 4 * Copyright 2015-2017, Ivo Petkov 5 * Free to use under the MIT license. 6 */ 7 8var responsivelyLazy = typeof responsivelyLazy !== 'undefined' ? responsivelyLazy : (function () { 9 10 var hasWebPSupport = false; 11 var hasSrcSetSupport = false; 12 var windowWidth = null; 13 var windowHeight = null; 14 var hasIntersectionObserverSupport = typeof IntersectionObserver !== 'undefined'; 15 var mutationObserverIsDisabled = false; 16 var doneElements = []; // elements that should never be updated again 17 18 var isVisible = function (element) { 19 if (windowWidth === null) { 20 return false; 21 } 22 var rect = element.getBoundingClientRect(); 23 var elementTop = rect.top; 24 var elementLeft = rect.left; 25 var elementWidth = rect.width; 26 var elementHeight = rect.height; 27 return elementTop < windowHeight && elementTop + elementHeight > 0 && elementLeft < windowWidth && elementLeft + elementWidth > 0; 28 }; 29 30 var evalScripts = function (scripts, startIndex) { 31 var scriptsCount = scripts.length; 32 for (var i = startIndex; i < scriptsCount; i++) { 33 var breakAfterThisScript = false; 34 var script = scripts[i]; 35 var newScript = document.createElement('script'); 36 var type = script.getAttribute('type'); 37 if (type !== null) { 38 newScript.setAttribute("type", type); 39 } 40 var src = script.getAttribute('src'); 41 if (src !== null) { 42 newScript.setAttribute("src", src); 43 if ((typeof script.async === 'undefined' || script.async === false) && i + 1 < scriptsCount) { 44 breakAfterThisScript = true; 45 newScript.addEventListener('load', function () { 46 evalScripts(scripts, i + 1); 47 }); 48 } 49 } 50 newScript.innerHTML = script.innerHTML; 51 script.parentNode.insertBefore(newScript, script); 52 script.parentNode.removeChild(script); 53 if (breakAfterThisScript) { 54 break; 55 } 56 } 57 }; 58 59 var updateImage = function (container, element) { 60 var options = element.getAttribute('data-srcset'); 61 if (options !== null) { 62 options = options.trim(); 63 if (options.length > 0) { 64 options = options.split(','); 65 var temp = []; 66 var optionsCount = options.length; 67 for (var j = 0; j < optionsCount; j++) { 68 var option = options[j].trim(); 69 if (option.length === 0) { 70 continue; 71 } 72 var spaceIndex = option.lastIndexOf(' '); 73 if (spaceIndex === -1) { 74 var optionImage = option; 75 var optionWidth = 999998; 76 } else { 77 var optionImage = option.substr(0, spaceIndex); 78 var optionWidth = parseInt(option.substr(spaceIndex + 1, option.length - spaceIndex - 2), 10); 79 } 80 var add = false; 81 if (optionImage.indexOf('.webp', optionImage.length - 5) !== -1) { 82 if (hasWebPSupport) { 83 add = true; 84 } 85 } else { 86 add = true; 87 } 88 if (add) { 89 temp.push([optionImage, optionWidth]); 90 } 91 } 92 temp.sort(function (a, b) { 93 if (a[1] < b[1]) { 94 return -1; 95 } 96 if (a[1] > b[1]) { 97 return 1; 98 } 99 if (a[1] === b[1]) { 100 if (b[0].indexOf('.webp', b[0].length - 5) !== -1) { 101 return 1; 102 } 103 if (a[0].indexOf('.webp', a[0].length - 5) !== -1) { 104 return -1; 105 } 106 } 107 return 0; 108 }); 109 options = temp; 110 } else { 111 options = []; 112 } 113 } else { 114 options = []; 115 } 116 117 var containerWidth = container.offsetWidth * (typeof window.devicePixelRatio !== 'undefined' ? window.devicePixelRatio : 1); 118 119 var bestSelectedOption = null; 120 var optionsCount = options.length; 121 for (var j = 0; j < optionsCount; j++) { 122 var optionData = options[j]; 123 if (optionData[1] >= containerWidth) { 124 bestSelectedOption = optionData; 125 break; 126 } 127 } 128 129 if (bestSelectedOption === null) { 130 bestSelectedOption = [element.getAttribute('src'), 999999]; 131 } 132 133 if (typeof container.responsivelyLazyLastSetOption === 'undefined') { 134 container.responsivelyLazyLastSetOption = ['', 0]; 135 } 136 container.responsivelyLazyLastSetOption = ['', 0]; 137 138 if (container.responsivelyLazyLastSetOption[1] < bestSelectedOption[1]) { 139 container.responsivelyLazyLastSetOption = bestSelectedOption; 140 var url = bestSelectedOption[0]; 141 if (typeof container.responsivelyLazyEventsAttached === 'undefined') { 142 container.responsivelyLazyEventsAttached = true; 143 element.addEventListener('load', function () { 144 var handler = container.getAttribute('data-onlazyload'); 145 if (handler !== null) { 146 (new Function(handler).bind(container))(); 147 } 148 }, false); 149 element.addEventListener('error', function () { 150 container.responsivelyLazyLastSetOption = ['', 0]; 151 }, false); 152 } 153 if (url === element.getAttribute('src')) { 154 element.removeAttribute('srcset'); 155 } else { 156 element.setAttribute('srcset', url); 157 } 158 } 159 }; 160 161 var updateWindowSize = function () { 162 windowWidth = window.innerWidth; 163 windowHeight = window.innerHeight; 164 }; 165 166 var updateElement = function (element) { 167 if (false && doneElements.indexOf(element) !== -1) { 168 return; 169 } 170 171 if (!isVisible(element)) { 172 return; 173 } 174 175 var lazyContent = element.getAttribute('data-lazycontent'); 176 if (lazyContent !== null) { 177 doneElements.push(element); 178 mutationObserverIsDisabled = true; 179 element.innerHTML = lazyContent; 180 var scripts = element.querySelectorAll('script'); 181 if (scripts.length > 0) { 182 evalScripts(scripts, 0); 183 } 184 mutationObserverIsDisabled = false;
185 return; 186 } 187 188 if (hasSrcSetSupport) { 189 if (element.tagName.toLowerCase() === 'img') { // image with unknown height 190 updateImage(element, element); 191 return; 192 } 193 194 var imageElement = element.querySelector('img'); 195 if (imageElement !== null) { // image with parent container 196 updateImage(element, imageElement); 197 return; 198 } 199 } 200 201 }; 202 203 var run = function () { 204 var elements = document.querySelectorAll('.responsively-lazy'); 205 var elementsCount = elements.length; 206 for (var i = 0; i < elementsCount; i++) { 207 updateElement(elements[i]); 208 } 209 }; 210 211 if (typeof window.addEventListener !== 'undefined' && typeof document.querySelectorAll !== 'undefined') { 212 213 updateWindowSize(); 214 215 var image = new Image(); 216 image.src = 'data:image/webp;base64,UklGRiQAAABXRUJQVlA4IBgAAAAwAQCdASoCAAEADMDOJaQAA3AA/uuuAAA='; 217 image.onload = image.onerror = function () { 218 hasWebPSupport = image.width === 2; 219 hasSrcSetSupport = 'srcset' in document.createElement('img'); 220 221 var requestAnimationFrameFunction = window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || function (callback) { 222 window.setTimeout(callback, 1000 / 60); 223 }; 224 225 var hasChange = true; 226 var runIfHasChange = function () { 227 if (hasChange) { 228 hasChange = false; 229 run(); 230 } 231 requestAnimationFrameFunction.call(null, runIfHasChange); 232 }; 233 234 runIfHasChange(); 235 236 if (hasIntersectionObserverSupport) { 237 238 var updateIntersectionObservers = function () { 239 var elements = document.querySelectorAll('.responsively-lazy'); 240 var elementsCount = elements.length; 241 for (var i = 0; i < elementsCount; i++) { 242 var element = elements[i]; 243 if (typeof element.responsivelyLazyObserverAttached === 'undefined') { 244 element.responsivelyLazyObserverAttached = true; 245 intersectionObserver.observe(element); 246 } 247 } 248 }; 249 250 var intersectionObserver = new IntersectionObserver(function (entries) { 251 for (var i in entries) { 252 var entry = entries[i]; 253 if (entry.intersectionRatio > 0) { 254 updateElement(entry.target); 255 } 256 } 257 }); 258 259 var changeTimeout = null; 260 261 } 262 263 var setChanged = function () { 264 if (hasIntersectionObserverSupport) { 265 window.clearTimeout(changeTimeout); 266 changeTimeout = window.setTimeout(function () { 267 hasChange = true; 268 }, 300); 269 } else { 270 hasChange = true; 271 } 272 }; 273 274 var updateParentNodesScrollListeners = function () { 275 var elements = document.querySelectorAll('.responsively-lazy'); 276 var elementsCount = elements.length; 277 for (var i = 0; i < elementsCount; i++) { 278 var parentNode = elements[i].parentNode; 279 while (parentNode && parentNode.tagName.toLowerCase() !== 'html') { 280 if (typeof parentNode.responsivelyLazyScrollAttached === 'undefined') { 281 parentNode.responsivelyLazyScrollAttached = true; 282 parentNode.addEventListener('scroll', setChanged); 283 } 284 parentNode = parentNode.parentNode; 285 } 286 } 287 }; 288 289 var initialize = function () { 290 window.addEventListener('resize', function () { 291 updateWindowSize(); 292 setChanged(); 293 }); 294 window.addEventListener('scroll', setChanged); 295 window.addEventListener('load', setChanged); 296 if (hasIntersectionObserverSupport) { 297 updateIntersectionObservers(); 298 } 299 updateParentNodesScrollListeners(); 300 if (typeof MutationObserver !== 'undefined') { 301 var observer = new MutationObserver(function () { 302 if (!mutationObserverIsDisabled) { 303 if (hasIntersectionObserverSupport) { 304 updateIntersectionObservers(); 305 } 306 updateParentNodesScrollListeners(); 307 setChanged(); 308 } 309 }); 310 observer.observe(document.querySelector('body'), { childList: true, subtree: true }); 311 } 312 }; 313 if (document.readyState === 'loading') { 314 document.addEventListener('DOMContentLoaded', initialize); 315 } else { 316 initialize(); 317 } 318 }; 319 } 320 321 return { 322 'run': run, 323 'isVisible': isVisible 324 }; 325 326}());
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.