lazysizes
Version:
High performance (jankfree) lazy loader for images (including responsive images), iframes and scripts (widgets).
177 lines (144 loc) • 4.4 kB
JavaScript
(function(window, factory) {
if (!window) {return;}
var globalInstall = function(){
factory(window.lazySizes);
window.removeEventListener('lazyunveilread', globalInstall, true);
};
factory = factory.bind(null, window, window.document);
if(typeof module == 'object' && module.exports){
factory(require('lazysizes'));
} else if (typeof define == 'function' && define.amd) {
define(['lazysizes'], factory);
} else if(window.lazySizes) {
globalInstall();
} else {
window.addEventListener('lazyunveilread', globalInstall, true);
}
}(typeof window != 'undefined' ?
window : 0, function(window, document, lazySizes) {
'use strict';
if(!window.addEventListener){return;}
var lazySizesConfig = lazySizes.cfg;
var ElementPrototype = (window.Element || Node || window.HTMLElement).prototype;
var regArtDirect = /artdirect/;
var regDescriptors = /\s+(\d+)(w|h)\s+(\d+)(w|h)/;
var regArtDirectTags = /artdirect["']*\s*:\s*["']*(.+?)(?=($|'|"|;))/;
var regPicture = /^picture$/i;
var regSplit = /[\s,]+/g;
var slice = [].slice;
function getCandidatesAspectRatio(element){
var match, width, height;
var ratio = parseFloat(element.getAttribute('data-aspectratio'));
var srcset = element.getAttribute(lazySizesConfig.srcsetAttr) || element.getAttribute('srcset');
if(!ratio){
match = srcset.match(regDescriptors);
if (match) {
if(match[2] == 'w'){
width = match[1];
height = match[3];
} else {
width = match[3];
height = match[1];
}
} else {
width = element.getAttribute('width');
height = element.getAttribute('height');
}
ratio = width / height;
}
return ratio;
}
function getLayoutAspectRatio(element){
return element.offsetWidth / element.offsetHeight;
}
function toTagSelector(tag){
return 'source[data-tag~="' + tag + '"]';
}
function getArtDirectConfig(img){
var picture = img.parentNode;
var isPicture = regPicture.test(picture.nodeName || '');
var content = (window.getComputedStyle(img) || {}).fontFamily;
var config = null;
if(isPicture && (lazySizesConfig.autoArtDirect || regArtDirect.test(content || ''))){
config = {
picture: picture,
img: img,
tags: content.match(regArtDirectTags)
};
if(config.tags){
config.selector = config.tags[1].split(regSplit).map(toTagSelector).join(',');
}
}
return config;
}
function toSourceObj(source){
var media = source.getAttribute('media');
return {
source: source,
aspectRatio: getCandidatesAspectRatio(source),
isSelected: !media || window.matchMedia(media).matches,
};
}
function sortAspectRatio(source1, source2){
return source1.aspectRatio < source2.aspectRatio;
}
function getClosestSource(sources, aspecRatio){
var i, len;
var closest = sources[0];
for(i = 1, len = sources.length; i < len; i++){
if(Math.abs(closest.aspectRatio - aspecRatio) > Math.abs(sources[i].aspectRatio - aspecRatio)){
closest = sources[i];
}
}
return closest;
}
function setMedia(source, media){
source._lsMedia = media;
lazySizes.rAF(function(){
if(source._lsMedia){
delete source._lsMedia;
}
source.setAttribute('media', media);
});
}
function selectSource(imgCfg){
var imgAspectRatio = getLayoutAspectRatio(imgCfg.img);
var sources = slice.call(imgCfg.picture.getElementsByTagName('source'))
.map(toSourceObj)
.sort(sortAspectRatio)
;
var matchedSources = imgCfg.selector ?
sources.filter(function(source){
return source.source.matches(imgCfg.selector);
}) :
sources
;
var closestSource = getClosestSource(matchedSources, imgAspectRatio);
if(!closestSource.isSelected){
setMedia(closestSource.source, '(min-width: 1px)');
}
sources
.filter(function(source){
return (source != closestSource && source.isSelected);
})
.forEach(function (source) {
setMedia(source.source, '(x)');
})
;
}
function addAutoArtDirection(e){
if(e.detail.instance != lazySizes){return;}
var img = e.target;
var imgCfg = getArtDirectConfig(img);
if(imgCfg){
selectSource(imgCfg);
}
}
if(!ElementPrototype.matches){
ElementPrototype.matches = ElementPrototype.matchesSelector ||
ElementPrototype.webkitMatchesSelector ||
ElementPrototype.msMatchesSelector ||
ElementPrototype.oMatchesSelector;
}
window.addEventListener('lazybeforesizes', addAutoArtDirection, true);
}));