| Current Path : /var/www/element/data/www/revenuestory.ru/bitrix/js/ui/vue/directives/lazyload/src/ |
| Current File : /var/www/element/data/www/revenuestory.ru/bitrix/js/ui/vue/directives/lazyload/src/lazyload.js |
/**
* Image Lazy Load Vue directive
*
* @package bitrix
* @subpackage ui
* @copyright 2001-2019 Bitrix
*/
/*
Attention: intersection observer work with errors if image has border-radius
Example of usage:
<img v-bx-lazyload
class="bx-module-element"
src="https://.../placeholder.png"
data-lazyload-src="https://.../targetImage.png"
data-lazyload-error-src="https://.../errorImage.png"
/>
<img v-bx-lazyload
class="bx-module-element"
src="https://.../placeholder.png"
data-lazyload-dont-hide
data-lazyload-src="https://.../targetImage.png"
data-lazyload-error-src="https://.../errorImage.png"
/>
<img v-bx-lazyload
class="bx-module-element"
data-lazyload-src="https://.../targetImage.png"
/>
<img v-bx-lazyload
class="bx-module-element"
data-lazyload-src="https://.../targetImage.png"
data-lazyload-error-class="bx-module-element-error"
data-lazyload-success-class="bx-module-element-success"
/>
*/
import {BitrixVue} from "ui.vue";
import 'main.polyfill.intersectionobserver';
const WATCH = 'bx-lazyload-watch';
const LOADING = 'bx-lazyload-loading';
const SUCCESS = 'bx-lazyload-success';
const ERROR = 'bx-lazyload-error';
const HIDDEN = 'bx-lazyload-hidden';
const BLANK_IMAGE = "data:image/svg+xml,%3Csvg width='1px' height='1px' xmlns='http://www.w3.org/2000/svg'%3E%3C/svg%3E";
let lazyloadObserver = null;
let lazyloadLoadImage = function(currentImage, callback)
{
let SUCCESS_CLASS = currentImage.dataset.lazyloadSuccessClass? currentImage.dataset.lazyloadSuccessClass.split(" "): [];
delete currentImage.dataset.lazyloadSuccessClass;
SUCCESS_CLASS = [SUCCESS, ...SUCCESS_CLASS];
let ERROR_CLASS = currentImage.dataset.lazyloadErrorClass? currentImage.dataset.lazyloadErrorClass.split(" "): [];
delete currentImage.dataset.lazyloadErrorClass;
ERROR_CLASS = [ERROR, ...ERROR_CLASS];
currentImage.classList.add(LOADING);
const newImage = new Image();
newImage.src = currentImage.dataset.lazyloadSrc;
if (!currentImage.dataset.lazyloadHiddenSrc)
{
currentImage.dataset.lazyloadHiddenSrc = currentImage.src;
}
newImage.onload = function()
{
if (currentImage.classList.contains(HIDDEN))
{
return false;
}
if (currentImage.dataset.lazyloadSrc)
{
currentImage.src = currentImage.dataset.lazyloadSrc;
}
currentImage.classList.remove(LOADING);
currentImage.classList.add(...SUCCESS_CLASS);
if (typeof currentImage.lazyloadCallback === 'function')
{
currentImage.lazyloadCallback({element: currentImage, state: 'success'});
delete currentImage.lazyloadCallback;
}
};
newImage.onerror = function()
{
if (currentImage.classList.contains(HIDDEN))
{
return false;
}
currentImage.classList.remove(LOADING);
currentImage.classList.add(...ERROR_CLASS);
currentImage.title = '';
currentImage.alt = '';
if (typeof currentImage.lazyloadCallback === 'function')
{
currentImage.lazyloadCallback({element: currentImage, state: 'error'});
delete currentImage.lazyloadCallback;
}
else
{
currentImage.src = BLANK_IMAGE;
}
};
if (typeof currentImage.dataset.lazyloadDontHide !== 'undefined')
{
currentImage.classList.remove(WATCH);
delete currentImage.dataset.lazyloadDontHide;
if (lazyloadObserver)
{
lazyloadObserver.unobserve(currentImage);
}
}
};
if (typeof window.IntersectionObserver !== 'undefined')
{
lazyloadObserver = new IntersectionObserver(function (entries, observer)
{
entries.forEach(function(entry)
{
const currentImage = entry.target;
if (currentImage.classList.contains(ERROR))
{
return true;
}
if (entry.isIntersecting)
{
if (currentImage.classList.contains(HIDDEN))
{
if (currentImage.dataset.lazyloadSrc)
{
currentImage.src = currentImage.dataset.lazyloadSrc;
}
currentImage.classList.remove(HIDDEN);
}
else if (currentImage.classList.contains(WATCH))
{
return true;
}
else
{
currentImage.classList.add(WATCH);
lazyloadLoadImage(currentImage);
}
}
else
{
if (
currentImage.classList.contains(HIDDEN)
|| !currentImage.classList.contains(WATCH)
)
{
return true;
}
if (currentImage.dataset.lazyloadHiddenSrc)
{
currentImage.src = currentImage.dataset.lazyloadHiddenSrc;
}
currentImage.classList.remove(LOADING);
currentImage.classList.add(HIDDEN);
}
});
}, {
threshold: [0, 1]
});
}
BitrixVue.directive('bx-lazyload',
{
bind(element, bindings)
{
if (typeof bindings.value === 'object' && typeof bindings.value.callback === 'function')
{
element.lazyloadCallback = bindings.value.callback;
}
if (!element.src || element.src === location.href.replace(location.hash, ''))
{
element.src = BLANK_IMAGE;
}
if (lazyloadObserver)
{
lazyloadObserver.observe(element);
}
else
{
lazyloadLoadImage(element);
}
},
componentUpdated(element)
{
if (
!element.classList.contains(SUCCESS)
&& !element.classList.contains(ERROR)
&& !element.classList.contains(WATCH)
&& !element.classList.contains(LOADING)
)
{
element.classList.add(LOADING);
}
else if (
(element.classList.contains(SUCCESS) || element.classList.contains(ERROR))
&& element.dataset.lazyloadSrc
&& element.dataset.lazyloadSrc !== element.src
)
{
if (!element.dataset.lazyloadSrc.startsWith('http'))
{
const url = document.createElement('a');
url.href = element.dataset.lazyloadSrc;
if (url.href === element.src)
{
return;
}
}
lazyloadLoadImage(element);
}
},
unbind(element)
{
if (lazyloadObserver)
{
lazyloadObserver.unobserve(element);
}
}
});