;(function () {
'use strict';
/**
* Layzyload images
* @namespace
*/
db.libs.imageDefer = (function($){
var name = 'imageDefer';
/**
* Ranges for targeting sizes in srcset
* @private
* @memberof db.libs.imageDefer
* @constant {object}
*/
var range = {
small: "(?:[0-9]|[0-9][0-9]|[0-6][0-3][0-9])", //Target 0-639
medium: "(?:6[4-9][0-9]|[7-9][0-9][0-9]|10[0-2][0-3])", //Target 640-1023
large: "(?:10[2-9][4-9]|[1-9][1-9][0-9][0-9])" //Target 1024 +
};
/**
* The threshold for when images in view should be loaded
* @private
* @memberof db.libs.imageDefer
* @constant {number}
*/
var threshold = 400;
/**
* The array for all the images to be lazy loaded
* @private
* @memberof db.libs.imageDefer
* @type {array}
*/
var images = [];
/**
* Loads all images with <code>data-defer="load"</code> attribute
* @private
* @memberof db.libs.imageDefer
* @return {external:jQuery} jQuery elements targeted
*/
function loadImagesOnLoad(){
var $images = $('[data-defer="load"]');
$images.each(function(i, img){
setImageSrc(img);
});
return $images;
}
/**
* Loads all images with <code>data-defer="view"</code> attribute if they are within the viewport threshold
* @private
* @memberof db.libs.imageDefer
*/
function loadImagesInView(){
var offset = $(document).scrollTop() + $(window).height() + threshold;
images.each(function(i, img){
if (img !== null) {
if( $(img).offset().top < offset ){
setImageSrc(img);
images[i] = null;
}
}
});
}
/**
* Loads a given image
* @public
* @memberof db.libs.imageDefer
* @param {external:jQuery|string} id jQuery element or selector
* @return {external:jQuery} jQuery elements targeted
*/
function load(id){
$img = $(id);
setImageSrc($img);
return $img;
}
/**
* Set the image src based on width of page and what is in data-srcset or data-src
* @private
* @memberof db.libs.imageDefer
* @param {external:jQuery|string} id jQuery element or selector
* @return {external:jQuery} jQuery element
*/
function setImageSrc(id){
var $img = $(id);
var size;
var src;
if($img.attr('data-src')){
src = $img.attr('data-src');
} else {
if(window.innerWidth <= 640){
size = range.small;
} else if(window.innerWidth > 1024){
size = range.large;
} else {
size = range.medium;
}
src = parseSrcset($img.attr('data-srcset'), size);
}
if( $img.prop('tagName') == 'IMG' ){
$img.attr('src', src);
} else {
$img.css('background-image', 'url('+src+')');
}
$img.removeAttr('data-defer');
return $img;
}
/**
* Parse the data-srcset and return the url that matches given size
* @private
* @memberof db.libs.imageDefer
* @param {string} srcset A srcset formatted string
* @param {string} size A string used in the regex to match a spesific size
* @return {string} the url matching size
*/
function parseSrcset(srcset, size){
var re = new RegExp("([^\\s|\\d|w|,]\\S+)\\s"+size+"w", "i");
var src = srcset.match(re);
return src[1].trim();
}
/**
* Initialize the component
* @public
* @memberof db.libs.imageDefer
*/
function init(){
if( !db.utils.isInitialized($('body'), name) ){
//FIXME: Not really sure we need to wait for document load here
if (document.readyState === 'complete') {
loadImagesOnLoad();
loadImagesInView();
} else {
window.addEventListener('load', function(){
setTimeout(function(){
loadImagesOnLoad();
loadImagesInView();
}, 0);
});
}
images = $('[data-defer="view"]');
$(window).on('scroll', function(){
window.requestAnimationFrame(loadImagesInView);
});
db.utils.initialized($('body'), name);
}
}
/**
* Load all images that can be loaded
* @public
* @memberof db.libs.imageDefer
*/
function reflow(){
loadImagesOnLoad();
loadImagesInView();
}
return {
init: init,
reflow: reflow,
load: load
};
})(jQuery);
})();