/*! Lazy Load XT v1.1.0 2016-01-12 * http://ressio.github.io/lazy-load-xt * (C) 2016 RESS.io * Licensed under MIT */ (function ($, window, document, undefined) { // options var lazyLoadXT = 'lazyLoadXT', dataLazied = 'lazied', load_error = 'load error', classLazyHidden = 'lazy-hidden', docElement = document.documentElement || document.body, // force load all images in Opera Mini and some mobile browsers without scroll event or getBoundingClientRect() forceLoad = (window.onscroll === undefined || !!window.operamini || !docElement.getBoundingClientRect), options = { autoInit: true, // auto initialize in $.ready selector: 'img[data-src]', // selector for lazyloading elements blankImage: 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7', /* blankImage: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAACmklEQVR4Xu2bS0/EMAyEvRx4CCG4IPH/fx0SpxUvcQGUpUFR1cZ2ZpxSlJU4sYk9X8Zum2YP0v/zpYQ89Eypa7BJ2AAwHFAn0NWVXYONEvghsPsekFyjiaiZXBuLuNKdmzfYjYhcicgTACEKQNJyLyLvIvJsvZR6ACTx19PEnwCECABZ/NmU36sVghVAKT7DbYXABjAXn/MzQbAAWBKPQGACWBNvhqABqIlvhcACoIk3QagBsAZIgTzlwABAy01zAC1Q0ZVRANScNAApb2pAw+WzqystANgQWh3AXoiTKa0A2BCs9yn5eyHivQC2ghAmvgWAB0K6JT16l3rl+7fTLXhtOs+V6HceTwmUwbVVYYrPcWsQmsS3OkCrywjxNQjN4lEAS+UQKX4JAiSeAaCE8EGsea11pHK4AJ5I4R4wT9C9EaEpNPyfErO1CRry28dXBoB9rFNclsMBIvIA8n0Ex6PDofyTA6AJRGQAQJcQHA8t4HDAKIHRA0YThJrIf7gKgE1438PHneC+1w/PfjgAZ3iagbI54cyFEpPhgLxD3HNL7E5Ezv/Clth8e7zHpmgSfzm5ZdNN0bV3A5EQSvG5YiAIrSWwxYuRJfEwhBYAmvicFNMJNfEQBC8Aq/iUFGTN4ooQGtMDIDQR5RIYFtsKgJmA9vC1tsXGzMH1ZogduBVA+RouH4isGcdUgpoD2OJTwggAOoQagAjxDABUCJoDIg5Kog7Itrcu0IuIpL/FjwYgDWIflWUBsDihKj5PYHkIYx6WZgKoQVDFewDMnWDqsCtk2QCWIJjEewFkCOgPJiIAlBDeajU/XxRLD1gao532rJVVFIAMwZVbCwBLz9gKgDu3AcCNDB8QWQLu7IYD3MjwAcMBCsOuJ06+ASU92QGOit9YAAAAAElFTkSuQmCC',*/ throttle: 99, // interval (ms) for changes check forceLoad: forceLoad, // force auto load all images loadEvent: 'pageshow', // check AJAX-loaded content in jQueryMobile updateEvent: 'load orientationchange resize scroll touchmove focus', // page-modified events forceEvent: 'lazyloadall', // force loading of all elements //onstart: null, oninit: {removeClass: 'lazy'}, // init handler onshow: {addClass: classLazyHidden}, // start loading handler onload: {removeClass: classLazyHidden, addClass: 'lazy-loaded'}, // load success handler onerror: {removeClass: classLazyHidden}, // error handler //oncomplete: null, // complete handler //scrollContainer: undefined, checkDuplicates: true }, elementOptions = { srcAttr: 'data-src', edgeX: 200, edgeY: 500, visibleOnly: true }, $window = $(window), $isFunction = $.isFunction, $extend = $.extend, $data = $.data || function (el, name) { return $(el).data(name); }, elements = [], topLazy = 0, /* waitingMode=0 : no setTimeout waitingMode=1 : setTimeout, no deferred events waitingMode=2 : setTimeout, deferred events */ waitingMode = 0; $[lazyLoadXT] = $extend(options, elementOptions, $[lazyLoadXT]); /** * Return options.prop if obj.prop is undefined, otherwise return obj.prop * @param {*} obj * @param {*} prop * @returns * */ function getOrDef(obj, prop) { return obj[prop] === undefined ? options[prop] : obj[prop]; } /** * @returns {number} */ function scrollTop() { var scroll = window.pageYOffset; return (scroll === undefined) ? docElement.scrollTop : scroll; } /** * Add new elements to lazy-load list: * $(elements).lazyLoadXT() or $(window).lazyLoadXT() * * @param {object} [overrides] override global options */ $.fn[lazyLoadXT] = function (overrides) { overrides = overrides || {}; var blankImage = getOrDef(overrides, 'blankImage'), checkDuplicates = getOrDef(overrides, 'checkDuplicates'), scrollContainer = getOrDef(overrides, 'scrollContainer'), forceShow = getOrDef(overrides, 'show'), elementOptionsOverrides = {}, prop; // empty overrides.scrollContainer is supported by both jQuery and Zepto $(scrollContainer).on('scroll', queueCheckLazyElements); for (prop in elementOptions) { elementOptionsOverrides[prop] = getOrDef(overrides, prop); } return this.each(function (index, el) { if (el === window) { $(options.selector).lazyLoadXT(overrides); } else { var duplicate = checkDuplicates && $data(el, dataLazied), $el = $(el).data(dataLazied, forceShow ? -1 : 1); // prevent duplicates if (duplicate) { queueCheckLazyElements(); return; } if (blankImage && el.tagName === 'IMG' && !el.src) { el.src = blankImage; } // clone elementOptionsOverrides object $el[lazyLoadXT] = $extend({}, elementOptionsOverrides); triggerEvent('init', $el); elements.push($el); queueCheckLazyElements(); } }); }; /** * Process function/object event handler * @param {string} event suffix * @param {jQuery} $el */ function triggerEvent(event, $el) { var handler = options['on' + event]; if (handler) { if ($isFunction(handler)) { handler.call($el[0]); } else { if (handler.addClass) { $el.addClass(handler.addClass); } if (handler.removeClass) { $el.removeClass(handler.removeClass); } } } $el.trigger('lazy' + event, [$el]); // queue next check as images may be resized after loading of actual file queueCheckLazyElements(); } /** * Trigger onload/onerror handler * @param {Event} e */ function triggerLoadOrError(e) { triggerEvent(e.type, $(this).off(load_error, triggerLoadOrError)); } /** * Load visible elements * @param {bool} [force] loading of all elements */ function checkLazyElements(force) { if (!elements.length) { return; } force = force || options.forceLoad; topLazy = Infinity; var viewportTop = scrollTop(), viewportHeight = window.innerHeight || docElement.clientHeight, viewportWidth = window.innerWidth || docElement.clientWidth, i, length; for (i = 0, length = elements.length; i < length; i++) { var $el = elements[i], el = $el[0], objData = $el[lazyLoadXT], removeNode = false, visible = force || $data(el, dataLazied) < 0, topEdge; // remove items that are not in DOM if (!$.contains(docElement, el)) { removeNode = true; } else if (force || !objData.visibleOnly || el.offsetWidth || el.offsetHeight) { if (!visible) { var elPos = el.getBoundingClientRect(), edgeX = objData.edgeX, edgeY = objData.edgeY; topEdge = (elPos.top + viewportTop - edgeY) - viewportHeight; visible = (topEdge <= viewportTop && elPos.bottom > -edgeY && elPos.left <= viewportWidth + edgeX && elPos.right > -edgeX); } if (visible) { $el.on(load_error, triggerLoadOrError); triggerEvent('show', $el); var srcAttr = objData.srcAttr, src = $isFunction(srcAttr) ? srcAttr($el) : el.getAttribute(srcAttr); if (src) { el.src = src; } removeNode = true; } else { if (topEdge < topLazy) { topLazy = topEdge; } } } if (removeNode) { $data(el, dataLazied, 0); elements.splice(i--, 1); length--; } } if (!length) { triggerEvent('complete', $(docElement)); } } /** * Run check of lazy elements after timeout */ function timeoutLazyElements() { if (waitingMode > 1) { waitingMode = 1; checkLazyElements(); setTimeout(timeoutLazyElements, options.throttle); } else { waitingMode = 0; } } /** * Queue check of lazy elements because of event e * @param {Event} [e] */ function queueCheckLazyElements(e) { if (!elements.length) { return; } // fast check for scroll event without new visible elements if (e && e.type === 'scroll' && e.currentTarget === window) { if (topLazy >= scrollTop()) { return; } } if (!waitingMode) { setTimeout(timeoutLazyElements, 0); } waitingMode = 2; } /** * Initialize list of hidden elements */ function initLazyElements() { $window.lazyLoadXT(); } /** * Loading of all elements */ function forceLoadAll() { checkLazyElements(true); } /** * Initialization */ $(document).ready(function () { triggerEvent('start', $window); $window .on(options.updateEvent, queueCheckLazyElements) .on(options.forceEvent, forceLoadAll); $('.mobile-nowrap-carousel').on('scroll touchmove', queueCheckLazyElements); $(document).on(options.updateEvent, queueCheckLazyElements); if (options.autoInit) { $window.on(options.loadEvent, initLazyElements); initLazyElements(); // standard initialization } }); })(window.jQuery || window.Zepto || window.$, window, document); (function ($) { var options = $.lazyLoadXT; options.selector += ',video,iframe[data-src]'; options.videoPoster = 'data-poster'; $(document).on('lazyshow', 'video', function (e, $el) { var srcAttr = $el.lazyLoadXT.srcAttr, isFuncSrcAttr = $.isFunction(srcAttr), changed = false; $el.attr('poster', $el.attr(options.videoPoster)); $el.children('source,track') .each(function (index, el) { var $child = $(el), src = isFuncSrcAttr ? srcAttr($child) : $child.attr(srcAttr); if (src) { $child.attr('src', src); changed = true; } }); // reload video if (changed) { this.load(); } }); })(window.jQuery || window.Zepto || window.$); /* Load html plugin */ (function ($) { 'use strict'; var options = $.lazyLoadXT, lazyAttr = options.lazyAttr || 'data-lazy-src'; options.selector += ',[' + lazyAttr + ']'; $(document).on('lazyshow', '[' + lazyAttr + ']', function () { var $this = $(this); $this.load($this.attr(lazyAttr), function () { $this.removeAttr(lazyAttr); $this.triggerHandler('load'); setTimeout(function() { $(window).lazyLoadXT(); }, 50); }); }); })(window.jQuery || window.Zepto || window.$); /*! Lazy Load XT v1.1.0 2016-01-12 * http://ressio.github.io/lazy-load-xt * (C) 2016 RESS.io * Licensed under MIT */ (function ($, window, document, undefined) { var options = $.lazyLoadXT, srcsetSupport = (function () { return 'srcset' in (new Image()); })(), reUrl = /^\s*(\S*)/, reWidth = /\S\s+(\d+)w/, reHeight = /\S\s+(\d+)h/, reDpr = /\S\s+([\d\.]+)x/, infty = [0, Infinity], one = [0, 1], srcsetOptions = { srcsetAttr: 'data-srcset', srcsetExtended: false, srcsetBaseAttr: 'data-srcset-base', srcsetExtAttr: 'data-srcset-ext' }, viewport = { w: 0, h: 0, x: 0 }, property, limit; for (property in srcsetOptions) { if (options[property] === undefined) { options[property] = srcsetOptions[property]; } } options.selector += ',img[' + options.srcsetAttr + ']'; function mathFilter(array, action) { return Math[action].apply(null, $.map(array, function (item) { return item[property]; })); } function compareMax(item) { return item[property] >= viewport[property] || item[property] === limit; } function compareMin(item) { return item[property] === limit; } function parseSrcset($el) { var srcset = $el.attr(options.srcsetAttr); if (!srcset) { return false; } var list = $.map(srcset.replace(/(\s[\d.]+[whx]),/g, '$1 @,@ ').split(' @,@ '), function (item) { return { url: reUrl.exec(item)[1], w: parseFloat((reWidth.exec(item) || infty)[1]), h: parseFloat((reHeight.exec(item) || infty)[1]), x: parseFloat((reDpr.exec(item) || one)[1]) }; }); if (!list.length) { return false; } var documentElement = document.documentElement, whx, src; viewport = { w: window.innerWidth || documentElement.clientWidth, h: window.innerHeight || documentElement.clientHeight, x: window.devicePixelRatio || 1 }; // Notice for DOMtastic users: currently $.grep method is not implemented in DOMtastic for (whx in viewport) { property = whx; limit = mathFilter(list, 'max'); list = $.grep(list, compareMax); } for (whx in viewport) { property = whx; limit = mathFilter(list, 'min'); list = $.grep(list, compareMin); } src = list[0].url; if (options.srcsetExtended) { src = ($el.attr(options.srcsetBaseAttr) || '') + src + ($el.attr(options.srcsetExtAttr) || ''); } return src; } $(document).on('lazyshow', 'img', function (e, $el) { var srcset = $el.attr(options.srcsetAttr); if (srcset) { if (!options.srcsetExtended && srcsetSupport) { $el.attr('srcset', srcset); } else { $el.lazyLoadXT.srcAttr = parseSrcset; } } }); })(window.jQuery || window.Zepto || window.$, window, document);