489 lines
15 KiB
JavaScript
489 lines
15 KiB
JavaScript
/*! 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); |