vendor: 14,399 bytes, lines 1-370
1/*! 2 hey, [be]Lazy.js - v1.8.2 - 2016.10.25 3 A fast, small and dependency free lazy load script (https://github.com/dinbror/blazy) 4 (c) Bjoern Klinggaard - @bklinggaard - http://dinbror.dk/blazy 5*/ 6; 7(function(root, blazy) { 8 if (typeof define === 'function' && define.amd) { 9 // AMD. Register bLazy as an anonymous module 10 define(blazy); 11 } else if (typeof exports === 'object') { 12 // Node. Does not work with strict CommonJS, but 13 // only CommonJS-like environments that support module.exports, 14 // like Node. 15 module.exports = blazy(); 16 } else { 17 // Browser globals. Register bLazy on window 18 root.Blazy = blazy(); 19 } 20})(this, function() { 21 'use strict'; 22 23 //private vars 24 var _source, _viewport, _isRetina, _supportClosest, _attrSrc = 'src', _attrSrcset = 'srcset'; 25 26 // constructor 27 return function Blazy(options) { 28 //IE7- fallback for missing querySelectorAll support 29 if (!document.querySelectorAll) { 30 var s = document.createStyleSheet(); 31 document.querySelectorAll = function(r, c, i, j, a) { 32 a = document.all, c = [], r = r.replace(/\[for\b/gi, '[htmlFor').split(','); 33 for (i = r.length; i--;) { 34 s.addRule(r[i], 'k:v'); 35 for (j = a.length; j--;) a[j].currentStyle.k && c.push(a[j]); 36 s.removeRule(0); 37 } 38 return c; 39 }; 40 } 41 42 //options and helper vars 43 var scope = this; 44 var util = scope._util = {}; 45 util.elements = []; 46 util.destroyed = true; 47 scope.options = options || {}; 48 scope.options.error = scope.options.error || false; 49 scope.options.offset = scope.options.offset || 100; 50 scope.options.root = scope.options.root || document; 51 scope.options.success = scope.options.success || false; 52 scope.options.selector = scope.options.selector || '.b-lazy'; 53 scope.options.separator = scope.options.separator || '|'; 54 scope.options.containerClass = scope.options.container; 55 scope.options.container = scope.options.containerClass ? document.querySelectorAll(scope.options.containerClass) : false; 56 scope.options.errorClass = scope.options.errorClass || 'b-error'; 57 scope.options.breakpoints = scope.options.breakpoints || false; 58 scope.options.loadInvisible = scope.options.loadInvisible || false; 59 scope.options.successClass = scope.options.successClass || 'b-loaded'; 60 scope.options.validateDelay = scope.options.validateDelay || 25; 61 scope.options.saveViewportOffsetDelay = scope.options.saveViewportOffsetDelay || 50; 62 scope.options.srcset = scope.options.srcset || 'data-srcset'; 63 scope.options.src = _source = scope.options.src || 'data-src'; 64 _supportClosest = Element.prototype.closest; 65 _isRetina = window.devicePixelRatio > 1; 66 _viewport = {}; 67 _viewport.top = 0 - scope.options.offset; 68 _viewport.left = 0 - scope.options.offset; 69 70 71 /* public functions 72 ************************************/ 73 scope.revalidate = function() { 74 initialize(scope); 75 }; 76 scope.load = function(elements, force) { 77 var opt = this.options; 78 if (elements && elements.length === undefined) { 79 loadElement(elements, force, opt); 80 } else { 81 each(elements, function(element) { 82 loadElement(element, force, opt); 83 }); 84 } 85 }; 86 scope.destroy = function() { 87 var util = scope._util; 88 if (scope.options.container) { 89 each(scope.options.container, function(object) { 90 unbindEvent(object, 'scroll', util.validateT); 91 }); 92 } 93 unbindEvent(window, 'scroll', util.validateT); 94 unbindEvent(window, 'resize', util.validateT); 95 unbindEvent(window, 'resize', util.saveViewportOffsetT); 96 util.count = 0; 97 util.elements.length = 0; 98 util.destroyed = true; 99 }; 100 101 //throttle, ensures that we don't call the functions too often 102 util.validateT = throttle(function() { 103 validate(scope); 104 }, scope.options.validateDelay, scope); 105 util.saveViewportOffsetT = throttle(function() { 106 saveViewportOffset(scope.options.offset); 107 }, scope.options.saveViewportOffsetDelay, scope); 108 saveViewportOffset(scope.options.offset); 109 110 //handle multi-served image src (obsolete) 111 each(scope.options.breakpoints, function(object) { 112 if (object.width >= window.screen.width) { 113 _source = object.src; 114 return false; 115 } 116 }); 117 118 // start lazy load 119 setTimeout(function() { 120 initialize(scope); 121 }); // "dom ready" fix 122 123 }; 124 125 126 /* Private helper functions 127 ************************************/ 128 function initialize(self) { 129 var util = self._util; 130 // First we create an array of elements to lazy load 131 util.elements = toArray(self.options); 132 util.count = util.elements.length; 133 // Then we bind resize and scroll events if not already binded 134 if (util.destroyed) { 135 util.destroyed = false; 136 if (self.options.container) { 137 each(self.options.container, function(object) { 138 bindEvent(object, 'scroll', util.validateT); 139 }); 140 } 141 bindEvent(window, 'resize', util.saveViewportOffsetT); 142 bindEvent(window, 'resize', util.validateT); 143 bindEvent(window, 'scroll', util.validateT); 144 } 145 // And finally, we start to lazy load. 146 validate(self); 147 } 148 149 function validate(self) { 150 var util = self._util; 151 for (var i = 0; i < util.count; i++) { 152 var element = util.elements[i]; 153 if (elementInView(element, self.options) || hasClass(element, self.options.successClass)) { 154 self.load(element); 155 util.elements.splice(i, 1); 156 util.count--; 157 i--; 158 } 159 } 160 if (util.count === 0) { 161 self.destroy(); 162 } 163 } 164 165 function elementInView(ele, options) { 166 var rect = ele.getBoundingClientRect(); 167 168 if(options.container && _supportClosest){ 169 // Is element inside a container? 170 var elementContainer = ele.closest(options.containerClass); 171 if(elementContainer){ 172 var containerRect = elementContainer.getBoundingClientRect(); 173 // Is container in view? 174 if(inView(containerRect, _viewport)){ 175 var top = containerRect.top - options.offset; 176 var right = containerRect.right + options.offset; 177 var bottom = containerRect.bottom + options.offset; 178 var left = containerRect.left - options.offset; 179 var containerRectWithOffset = { 180 top: top > _viewport.top ? top : _viewport.top, 181 right: right < _viewport.right ? right : _viewport.right, 182 bottom: bottom < _viewport.bottom ? bottom : _viewport.bottom, 183 left: left > _viewport.left ? left : _viewport.left 184 }; 185 // Is element in view of container? 186 return inView(rect, containerRectWithOffset); 187 } else { 188 return false; 189 } 190 } 191 } 192 return inView(rect, _viewport); 193 } 194 195 function inView(rect, viewport){ 196 // Intersection 197 return rect.right >= viewport.left && 198 rect.bottom >= viewport.top && 199 rect.left <= viewport.right && 200 rect.top <= viewport.bottom; 201 } 202 203 function loadElement(ele, force, options) { 204 // if element is visible, not loaded or forced 205 if (!hasClass(ele, options.successClass) && (force || options.loadInvisible || (ele.offsetWidth > 0 && ele.offsetHeight > 0))) { 206 var dataSrc = getAttr(ele, _source) || getAttr(ele, options.src); // fallback to default 'data-src' 207 if (dataSrc) { 208 var dataSrcSplitted = dataSrc.split(options.separator); 209 var src = dataSrcSplitted[_isRetina && dataSrcSplitted.length > 1 ? 1 : 0]; 210 var srcset = getAttr(ele, options.srcset); 211 var isImage = equal(ele, 'img'); 212 var parent = ele.parentNode; 213 var isPicture = parent && equal(parent, 'picture'); 214 // Image or background image 215 if (isImage || ele.src === undefined) { 216 var img = new Image(); 217 // using EventListener instead of onerror and onload 218 // due to bug introduced in chrome v50 219 // (https://productforums.google.com/forum/#!topic/chrome/p51Lk7vnP2o) 220 var onErrorHandler = function() { 221 if (options.error) options.error(ele, "invalid"); 222 addClass(ele, options.errorClass); 223 unbindEvent(img, 'error', onErrorHandler); 224 unbindEvent(img, 'load', onLoadHandler); 225 }; 226 var onLoadHandler = function() { 227 // Is element an image 228 if (isImage) { 229 if(!isPicture) { 230 handleSources(ele, src, srcset); 231 } 232 // or background-image 233 } else { 234 ele.style.backgroundImage = 'url("' + src + '")'; 235 } 236 itemLoaded(ele, options); 237 unbindEvent(img, 'load', onLoadHandler); 238 unbindEvent(img, 'error', onErrorHandler); 239 }; 240 241 // Picture element 242 if (isPicture) { 243 img = ele; // Image tag inside picture element wont get preloaded 244 each(parent.getElementsByTagName('source'), function(source) { 245 handleSource(source, _attrSrcset, options.srcset); 246 }); 247 } 248 bindEvent(img, 'error', onErrorHandler); 249 bindEvent(img, 'load', onLoadHandler); 250 handleSources(img, src, srcset); // Preload 251 252 } else { // An item with src like iframe, unity games, simpel video etc 253 ele.src = src; 254 itemLoaded(ele, options); 255 } 256 } else { 257 // video with child source 258 if (equal(ele, 'video')) { 259 each(ele.getElementsByTagName('source'), function(source) { 260 handleSource(source, _attrSrc, options.src); 261 }); 262 ele.load(); 263 itemLoaded(ele, options); 264 } else { 265 if (options.error) options.error(ele, "missing"); 266 addClass(ele, options.errorClass); 267 } 268 } 269 } 270 } 271 272 function itemLoaded(ele, options) { 273 addClass(ele, options.successClass); 274 if (options.success) options.success(ele); 275 // cleanup markup, remove data source attributes 276 removeAttr(ele, options.src); 277 removeAttr(ele, options.srcset); 278 each(options.breakpoints, function(object) { 279 removeAttr(ele, object.src); 280 }); 281 } 282 283 function handleSource(ele, attr, dataAttr) { 284 var dataSrc = getAttr(ele, dataAttr); 285 if (dataSrc) { 286 setAttr(ele, attr, dataSrc); 287 removeAttr(ele, dataAttr); 288 } 289 } 290 291 function handleSources(ele, src, srcset){ 292 if(srcset) { 293 setAttr(ele, _attrSrcset, srcset); //srcset 294 } 295 ele.src = src; //src 296 } 297 298 function setAttr(ele, attr, value){ 299 ele.setAttribute(attr, value); 300 } 301 302 function getAttr(ele, attr) { 303 return ele.getAttribute(attr); 304 } 305 306 function removeAttr(ele, attr){ 307 ele.removeAttribute(attr); 308 } 309 310 function equal(ele, str) { 311 return ele.nodeName.toLowerCase() === str; 312 } 313 314 function hasClass(ele, className) { 315 return (' ' + ele.className + ' ').indexOf(' ' + className + ' ') !== -1; 316 } 317 318 function addClass(ele, className) { 319 if (!hasClass(ele, className)) { 320 ele.className += ' ' + className; 321 } 322 } 323 324 function toArray(options) { 325 var array = []; 326 var nodelist = (options.root).querySelectorAll(options.selector); 327 for (var i = nodelist.length; i--; array.unshift(nodelist[i])) {} 328 return array; 329 } 330 331 function saveViewportOffset(offset) { 332 _viewport.bottom = (window.innerHeight || document.documentElement.clientHeight) + offset; 333 _viewport.right = (window.innerWidth || document.documentElement.clientWidth) + offset; 334 } 335 336 function bindEvent(ele, type, fn) { 337 if (ele.attachEvent) { 338 ele.attachEvent && ele.attachEvent('on' + type, fn); 339 } else { 340 ele.addEventListener(type, fn, { capture: false, passive: true }); 341 } 342 } 343 344 function unbindEvent(ele, type, fn) { 345 if (ele.detachEvent) { 346 ele.detachEvent && ele.detachEvent('on' + type, fn); 347 } else { 348 ele.removeEventListener(type, fn, { capture: false, passive: true }); 349 } 350 } 351 352 function each(object, fn) { 353 if (object && fn) { 354 var l = object.length; 355 for (var i = 0; i < l && fn(object[i], i) !== false; i++) {} 356 } 357 } 358 359 function throttle(fn, minDelay, scope) { 360 var lastCall = 0; 361 return function() { 362 var now = +new Date(); 363 if (now - lastCall < minDelay) { 364 return; 365 } 366 lastCall = now; 367 fn.apply(scope, arguments); 368 }; 369 } 370});
371;
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.