1/*! Lazy Load XT v1.0.1 2014-02-17 2 * http://ressio.github.io/lazy-load-xt 3 * (C) 2014 RESS.io 4 * Licensed under MIT */ 5 6(function ($, window, document, undefined) { 7 // options 8 var lazyLoadXT = 'lazyLoadXT', 9 dataLazied = 'lazied', 10 load_error = 'load error', 11 classLazyHidden = 'lazy-hidden', 12 docElement = document.documentElement || document.body, 13 // force load all images in Opera Mini and some mobile browsers without scroll event or getBoundingClientRect() 14 forceLoad = (window.onscroll === undefined || !!window.operamini || !docElement.getBoundingClientRect), 15 options = { 16 autoInit: true, // auto initialize in $.ready 17 selector: 'img[data-src]', // selector for lazyloading elements 18 blankImage: 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP/yH5BAEAAAAALAAAAAABAAEAAAIBRAA7', 19 throttle: 99, // interval (ms) for changes check 20 forceLoad: forceLoad, // force auto load all images 21 22 loadEvent: 'pageshow', // check AJAX-loaded content in jQueryMobile 23 updateEvent: 'load orientationchange resize scroll touchmove', // page-modified events 24 forceEvent: '', // force loading of all elements 25 26 //onstart: null, 27 oninit: {removeClass: 'lazy'}, // init handler 28 onshow: {addClass: classLazyHidden}, // start loading handler 29 onload: {removeClass: classLazyHidden, addClass: 'lazy-loaded'}, // load success handler 30 onerror: {removeClass: classLazyHidden}, // error handler 31 //oncomplete: null, // complete handler 32 33 //scrollContainer: undefined, 34 checkDuplicates: true 35 }, 36 elementOptions = { 37 srcAttr: 'data-src', 38 edgeX: 0, 39 edgeY: 0, 40 visibleOnly: true 41 }, 42 $window = $(window), 43 $isFunction = $.isFunction, 44 $extend = $.extend, 45 $data = $.data || function (el, name) { 46 return $(el).data(name); 47 }, 48 elements = [], 49 topLazy = 0, 50 /* 51 waitingMode=0 : no setTimeout 52 waitingMode=1 : setTimeout, no deferred events 53 waitingMode=2 : setTimeout, deferred events 54 */ 55 waitingMode = 0; 56 57 $[lazyLoadXT] = $extend(options, elementOptions, $[lazyLoadXT]); 58 59 /** 60 * Return options.prop if obj.prop is undefined, otherwise return obj.prop 61 * @param {*} obj 62 * @param {*} prop 63 * @returns * 64 */ 65 function getOrDef(obj, prop) { 66 return obj[prop] === undefined ? options[prop] : obj[prop]; 67 } 68 69 70 /** 71 * Add new elements to lazy-load list: 72 * $(elements).lazyLoadXT() or $(window).lazyLoadXT() 73 * 74 * @param {object} [overrides] override global options 75 */ 76 $.fn[lazyLoadXT] = function (overrides) { 77 overrides = overrides || {}; 78 79 var blankImage = getOrDef(overrides, 'blankImage'), 80 checkDuplicates = getOrDef(overrides, 'checkDuplicates'), 81 scrollContainer = getOrDef(overrides, 'scrollContainer'), 82 elementOptionsOverrides = {}, 83 prop; 84 85 // empty overrides.scrollContainer is supported by both jQuery and Zepto 86 $(scrollContainer).on('scroll', queueCheckLazyElements); 87 88 for (prop in elementOptions) { 89 elementOptionsOverrides[prop] = getOrDef(overrides, prop); 90 } 91 92 return this.each(function () { 93 if (this === window) { 94 $(options.selector).lazyLoadXT(overrides); 95 } else { 96 // prevent duplicates 97 if (checkDuplicates && $data(this, dataLazied)) { 98 return; 99 } 100 101 var $el = $(this).data(dataLazied, 1); 102 103 if (blankImage && $el[0].tagName === 'IMG' && !this.src) { 104 this.src = blankImage; 105 } 106 107 // clone elementOptionsOverrides object 108 $el[lazyLoadXT] = $extend({}, elementOptionsOverrides); 109 110 triggerEvent('init', $el); 111 112 elements.push($el); 113 } 114 }); 115 }; 116 117 118 /** 119 * Process function/object event handler 120 * @param {string} event suffix 121 * @param {jQuery} $el 122 */ 123 function triggerEvent(event, $el) { 124 var handler = options['on' + event]; 125 if (handler) { 126 if ($isFunction(handler)) { 127 handler.call($el[0]); 128 } else { 129 $el 130 .addClass(handler.addClass || '') 131 .removeClass(handler.removeClass || ''); 132 } 133 } 134 135 $el.trigger('lazy' + event, [$el]); 136 137 // queue next check as images may be resized after loading of actual file 138 queueCheckLazyElements(); 139 } 140 141 142 /** 143 * Trigger onload/onerror handler 144 * @param {Event} e 145 */ 146 function triggerLoadOrError(e) { 147 triggerEvent(e.type, $(this).off(load_error, triggerLoadOrError)); 148 } 149 150 151 /** 152 * Load visible elements 153 * @param {bool} [force] loading of all elements 154 */ 155 function checkLazyElements(force) { 156 if (!elements.length) { 157 return; 158 } 159 160 force = force || options.forceLoad; 161 162 topLazy = Infinity; 163 164 var viewportTop = $window.scrollTop(),
165 viewportHeight = window.innerHeight || $window.height(), 166 viewportWidth = window.innerWidth || $window.width(), 167 i, 168 length; 169 170 for (i = 0, length = elements.length; i < length; i++) { 171 var $el = elements[i], 172 el = $el[0], 173 objData = $el[lazyLoadXT], 174 removeNode = false, 175 visible = force, 176 topEdge; 177 178 // remove items that are not in DOM 179 if (!$.contains(docElement, el)) { 180 removeNode = true; 181 } else if (force || !objData.visibleOnly || el.offsetWidth || el.offsetHeight) { 182 183 if (!visible) { 184 var elPos = el.getBoundingClientRect(), 185 edgeX = objData.edgeX, 186 edgeY = objData.edgeY; 187 188 topEdge = (elPos.top + viewportTop - edgeY) - viewportHeight; 189 190 visible = (topEdge <= viewportTop && elPos.bottom > -edgeY && 191 elPos.left <= viewportWidth + edgeX && elPos.right > -edgeX); 192 } 193 194 if (visible) { 195 triggerEvent('show', $el); 196 197 var srcAttr = objData.srcAttr, 198 src = $isFunction(srcAttr) ? srcAttr($el) : el.getAttribute(srcAttr); 199 if (src) { 200 $el.on(load_error, triggerLoadOrError); 201 el.src = src; 202 } 203 204 removeNode = true; 205 } else { 206 if (topEdge < topLazy) { 207 topLazy = topEdge; 208 } 209 } 210 } 211 212 if (removeNode) { 213 elements.splice(i--, 1); 214 length--; 215 } 216 } 217 218 if (!length) { 219 triggerEvent('complete', $(docElement)); 220 } 221 } 222 223 224 /** 225 * Run check of lazy elements after timeout 226 */ 227 function timeoutLazyElements() { 228 if (waitingMode > 1) { 229 waitingMode = 1; 230 checkLazyElements(); 231 setTimeout(timeoutLazyElements, options.throttle); 232 } else { 233 waitingMode = 0; 234 } 235 } 236 237 238 /** 239 * Queue check of lazy elements because of event e 240 * @param {Event} [e] 241 */ 242 function queueCheckLazyElements(e) { 243 if (!elements.length) { 244 return; 245 } 246 247 // fast check for scroll event without new visible elements 248 if (e && e.type === 'scroll' && e.currentTarget === window) { 249 if (topLazy >= $window.scrollTop()) { 250 return; 251 } 252 } 253 254 if (!waitingMode) { 255 setTimeout(timeoutLazyElements, 0); 256 } 257 waitingMode = 2; 258 } 259 260 261 /** 262 * Initialize list of hidden elements 263 */ 264 function initLazyElements() { 265 $window.lazyLoadXT(); 266 queueCheckLazyElements(); 267 } 268 269 270 /** 271 * Loading of all elements 272 */ 273 function forceLoadAll() { 274 checkLazyElements(true); 275 } 276 277 278 /** 279 * Initialization 280 */ 281 $(document).ready(function () { 282 triggerEvent('start', $window); 283 284 $window 285 .on(options.loadEvent, initLazyElements) 286 .on(options.updateEvent, queueCheckLazyElements) 287 .on(options.forceEvent, forceLoadAll); 288 289 if (options.autoInit) { 290 initLazyElements(); // standard initialization 291 } 292 }); 293 294})(window.jQuery || window.Zepto, window, document);
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.