From 6ba667ba5eb1282b88f82315cee9610e4fa42061 Mon Sep 17 00:00:00 2001 From: Andrea Verlicchi Date: Fri, 3 Aug 2018 16:29:32 +0200 Subject: [PATCH] "dist" folder now featuring new amd and iife versions --- dist/lazyload.amd.js | 384 ++++++++++++++++++++++++++++++++++ dist/lazyload.amd.min.js | 2 + dist/lazyload.amd.min.js.map | 1 + dist/lazyload.es2015.js | 17 +- dist/lazyload.iife.js | 384 ++++++++++++++++++++++++++++++++++ dist/lazyload.iife.min.js | 2 + dist/lazyload.iife.min.js.map | 1 + dist/lazyload.js | 3 +- dist/lazyload.min.js | 3 +- dist/lazyload.min.js.map | 1 + 10 files changed, 782 insertions(+), 16 deletions(-) create mode 100644 dist/lazyload.amd.js create mode 100644 dist/lazyload.amd.min.js create mode 100644 dist/lazyload.amd.min.js.map create mode 100644 dist/lazyload.iife.js create mode 100644 dist/lazyload.iife.min.js create mode 100644 dist/lazyload.iife.min.js.map create mode 100644 dist/lazyload.min.js.map diff --git a/dist/lazyload.amd.js b/dist/lazyload.amd.js new file mode 100644 index 00000000..58520cb0 --- /dev/null +++ b/dist/lazyload.amd.js @@ -0,0 +1,384 @@ +var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; + +define(function () { + 'use strict'; + + var getDefaultSettings = function getDefaultSettings() { + return { + elements_selector: "img", + container: window, + threshold: 300, + throttle: 150, + data_src: "src", + data_srcset: "srcset", + data_sizes: "sizes", + class_loading: "loading", + class_loaded: "loaded", + class_error: "error", + class_initial: "initial", + skip_invisible: true, + callback_load: null, + callback_error: null, + callback_set: null, + callback_processed: null, + callback_enter: null + }; + }; + + var callCallback = function callCallback(callback, argument) { + if (callback) { + callback(argument); + } + }; + + var getTopOffset = function getTopOffset(element) { + return element.getBoundingClientRect().top + window.pageYOffset - element.ownerDocument.documentElement.clientTop; + }; + + var isBelowViewport = function isBelowViewport(element, container, threshold) { + var fold = container === window ? window.innerHeight + window.pageYOffset : getTopOffset(container) + container.offsetHeight; + return fold <= getTopOffset(element) - threshold; + }; + + var getLeftOffset = function getLeftOffset(element) { + return element.getBoundingClientRect().left + window.pageXOffset - element.ownerDocument.documentElement.clientLeft; + }; + + var isAtRightOfViewport = function isAtRightOfViewport(element, container, threshold) { + var documentWidth = window.innerWidth; + var fold = container === window ? documentWidth + window.pageXOffset : getLeftOffset(container) + documentWidth; + return fold <= getLeftOffset(element) - threshold; + }; + + var isAboveViewport = function isAboveViewport(element, container, threshold) { + var fold = container === window ? window.pageYOffset : getTopOffset(container); + return fold >= getTopOffset(element) + threshold + element.offsetHeight; + }; + + var isAtLeftOfViewport = function isAtLeftOfViewport(element, container, threshold) { + var fold = container === window ? window.pageXOffset : getLeftOffset(container); + return fold >= getLeftOffset(element) + threshold + element.offsetWidth; + }; + + function isInsideViewport(element, container, threshold) { + return !isBelowViewport(element, container, threshold) && !isAboveViewport(element, container, threshold) && !isAtRightOfViewport(element, container, threshold) && !isAtLeftOfViewport(element, container, threshold); + } + + /* Creates instance and notifies it through the window element */ + var createInstance = function createInstance(classObj, options) { + var event; + var eventString = "LazyLoad::Initialized"; + var instance = new classObj(options); + try { + // Works in modern browsers + event = new CustomEvent(eventString, { detail: { instance: instance } }); + } catch (err) { + // Works in Internet Explorer (all versions) + event = document.createEvent("CustomEvent"); + event.initCustomEvent(eventString, false, false, { instance: instance }); + } + window.dispatchEvent(event); + }; + + /* Auto initialization of one or more instances of lazyload, depending on the + options passed in (plain object or an array) */ + function autoInitialize(classObj, options) { + var optsLength = options.length; + if (!optsLength) { + // Plain object + createInstance(classObj, options); + } else { + // Array of objects + for (var i = 0; i < optsLength; i++) { + createInstance(classObj, options[i]); + } + } + } + + var dataPrefix = "data-"; + var processedDataName = "was-processed"; + var processedDataValue = "true"; + + var getData = function getData(element, attribute) { + return element.getAttribute(dataPrefix + attribute); + }; + + var setData = function setData(element, attribute, value) { + return element.setAttribute(dataPrefix + attribute, value); + }; + + var setWasProcessed = function setWasProcessed(element) { + return setData(element, processedDataName, processedDataValue); + }; + + var getWasProcessed = function getWasProcessed(element) { + return getData(element, processedDataName) === processedDataValue; + }; + + var setSourcesInChildren = function setSourcesInChildren(parentTag, attrName, dataAttrName) { + for (var i = 0, childTag; childTag = parentTag.children[i]; i += 1) { + if (childTag.tagName === "SOURCE") { + var attributeValue = getData(childTag, dataAttrName); + if (attributeValue) { + childTag.setAttribute(attrName, attributeValue); + } + } + } + }; + + var setAttributeIfNotNullOrEmpty = function setAttributeIfNotNullOrEmpty(element, attrName, value) { + if (!value) { + return; + } + element.setAttribute(attrName, value); + }; + + function setSources(element, settings) { + var sizesDataName = settings.data_sizes, + srcsetDataName = settings.data_srcset, + srcDataName = settings.data_src; + + var srcDataValue = getData(element, srcDataName); + var tagName = element.tagName; + if (tagName === "IMG") { + var parent = element.parentNode; + if (parent && parent.tagName === "PICTURE") { + setSourcesInChildren(parent, "srcset", srcsetDataName); + } + var sizesDataValue = getData(element, sizesDataName); + setAttributeIfNotNullOrEmpty(element, "sizes", sizesDataValue); + var srcsetDataValue = getData(element, srcsetDataName); + setAttributeIfNotNullOrEmpty(element, "srcset", srcsetDataValue); + setAttributeIfNotNullOrEmpty(element, "src", srcDataValue); + return; + } + if (tagName === "IFRAME") { + setAttributeIfNotNullOrEmpty(element, "src", srcDataValue); + return; + } + if (tagName === "VIDEO") { + setSourcesInChildren(element, "src", srcDataName); + setAttributeIfNotNullOrEmpty(element, "src", srcDataValue); + return; + } + if (srcDataValue) { + element.style.backgroundImage = "url(\"" + srcDataValue + "\")"; + } + } + + var runningOnBrowser = typeof window !== "undefined"; + + var isBot = runningOnBrowser && !("onscroll" in window) || /(gle|ing|ro)bot|crawl|spider/i.test(navigator.userAgent); + var supportsClassList = runningOnBrowser && "classList" in document.createElement("p"); + + var addClass = function addClass(element, className) { + if (supportsClassList) { + element.classList.add(className); + return; + } + element.className += (element.className ? " " : "") + className; + }; + + var removeClass = function removeClass(element, className) { + if (supportsClassList) { + element.classList.remove(className); + return; + } + element.className = element.className.replace(new RegExp("(^|\\s+)" + className + "(\\s+|$)"), " ").replace(/^\s+/, "").replace(/\s+$/, ""); + }; + + /* + * Constructor + */ + + var LazyLoad = function LazyLoad(instanceSettings) { + this._settings = _extends({}, getDefaultSettings(), instanceSettings); + this._queryOriginNode = this._settings.container === window ? document : this._settings.container; + + this._previousLoopTime = 0; + this._loopTimeout = null; + this._boundHandleScroll = this.handleScroll.bind(this); + + this._isFirstLoop = true; + window.addEventListener("resize", this._boundHandleScroll); + this.update(); + }; + + LazyLoad.prototype = { + _reveal: function _reveal(element, force) { + if (!force && getWasProcessed(element)) { + return; // element has already been processed and force wasn't true + } + + var settings = this._settings; + + var errorCallback = function errorCallback() { + /* As this method is asynchronous, it must be protected against external destroy() calls */ + if (!settings) { + return; + } + element.removeEventListener("load", loadCallback); + element.removeEventListener("error", errorCallback); + removeClass(element, settings.class_loading); + addClass(element, settings.class_error); + callCallback(settings.callback_error, element); + }; + + var loadCallback = function loadCallback() { + /* As this method is asynchronous, it must be protected against external destroy() calls */ + if (!settings) { + return; + } + removeClass(element, settings.class_loading); + addClass(element, settings.class_loaded); + element.removeEventListener("load", loadCallback); + element.removeEventListener("error", errorCallback); + callCallback(settings.callback_load, element); + }; + + callCallback(settings.callback_enter, element); + if (["IMG", "IFRAME", "VIDEO"].indexOf(element.tagName) > -1) { + element.addEventListener("load", loadCallback); + element.addEventListener("error", errorCallback); + addClass(element, settings.class_loading); + } + setSources(element, settings); + callCallback(settings.callback_set, element); + }, + + _loopThroughElements: function _loopThroughElements(forceDownload) { + var settings = this._settings, + elements = this._elements, + elementsLength = !elements ? 0 : elements.length; + var i = void 0, + processedIndexes = [], + firstLoop = this._isFirstLoop; + + for (i = 0; i < elementsLength; i++) { + var element = elements[i]; + /* If must skip_invisible and element is invisible, skip it */ + if (settings.skip_invisible && element.offsetParent === null) { + continue; + } + + if (isBot || forceDownload || isInsideViewport(element, settings.container, settings.threshold)) { + if (firstLoop) { + addClass(element, settings.class_initial); + } + /* Start loading the image */ + this.load(element); + /* Marking the element as processed. */ + processedIndexes.push(i); + setWasProcessed(element); + } + } + /* Removing processed elements from this._elements. */ + while (processedIndexes.length) { + elements.splice(processedIndexes.pop(), 1); + callCallback(settings.callback_processed, elements.length); + } + /* Stop listening to scroll event when 0 elements remains */ + if (elementsLength === 0) { + this._stopScrollHandler(); + } + /* Sets isFirstLoop to false */ + if (firstLoop) { + this._isFirstLoop = false; + } + }, + + _purgeElements: function _purgeElements() { + var elements = this._elements, + elementsLength = elements.length; + var i = void 0, + elementsToPurge = []; + + for (i = 0; i < elementsLength; i++) { + var element = elements[i]; + /* If the element has already been processed, skip it */ + if (getWasProcessed(element)) { + elementsToPurge.push(i); + } + } + /* Removing elements to purge from this._elements. */ + while (elementsToPurge.length > 0) { + elements.splice(elementsToPurge.pop(), 1); + } + }, + + _startScrollHandler: function _startScrollHandler() { + if (!this._isHandlingScroll) { + this._isHandlingScroll = true; + this._settings.container.addEventListener("scroll", this._boundHandleScroll); + } + }, + + _stopScrollHandler: function _stopScrollHandler() { + if (this._isHandlingScroll) { + this._isHandlingScroll = false; + this._settings.container.removeEventListener("scroll", this._boundHandleScroll); + } + }, + + handleScroll: function handleScroll() { + var throttle = this._settings.throttle; + + if (throttle !== 0) { + var now = Date.now(); + var remainingTime = throttle - (now - this._previousLoopTime); + if (remainingTime <= 0 || remainingTime > throttle) { + if (this._loopTimeout) { + clearTimeout(this._loopTimeout); + this._loopTimeout = null; + } + this._previousLoopTime = now; + this._loopThroughElements(); + } else if (!this._loopTimeout) { + this._loopTimeout = setTimeout(function () { + this._previousLoopTime = Date.now(); + this._loopTimeout = null; + this._loopThroughElements(); + }.bind(this), remainingTime); + } + } else { + this._loopThroughElements(); + } + }, + + loadAll: function loadAll() { + this._loopThroughElements(true); + }, + + update: function update() { + // Converts to array the nodeset obtained querying the DOM from _queryOriginNode with elements_selector + this._elements = Array.prototype.slice.call(this._queryOriginNode.querySelectorAll(this._settings.elements_selector)); + this._purgeElements(); + this._loopThroughElements(); + this._startScrollHandler(); + }, + + destroy: function destroy() { + window.removeEventListener("resize", this._boundHandleScroll); + if (this._loopTimeout) { + clearTimeout(this._loopTimeout); + this._loopTimeout = null; + } + this._stopScrollHandler(); + this._elements = null; + this._queryOriginNode = null; + this._settings = null; + }, + + load: function load(element, force) { + this._reveal(element, force); + } + }; + + /* Automatic instances creation if required (useful for async script loading!) */ + var autoInitOptions = window.lazyLoadOptions; + if (runningOnBrowser && autoInitOptions) { + autoInitialize(LazyLoad, autoInitOptions); + } + + return LazyLoad; +}); \ No newline at end of file diff --git a/dist/lazyload.amd.min.js b/dist/lazyload.amd.min.js new file mode 100644 index 00000000..1140922c --- /dev/null +++ b/dist/lazyload.amd.min.js @@ -0,0 +1,2 @@ +var _extends=Object.assign||function(e){for(var t=1;t=o(e)+n+e.offsetHeight},c=function(e,t,n){return(t===window?window.pageXOffset:r(t))>=r(e)+n+e.offsetWidth},u=function(e,t){var n,i=new e(t);try{n=new CustomEvent("LazyLoad::Initialized",{detail:{instance:i}})}catch(e){(n=document.createEvent("CustomEvent")).initCustomEvent("LazyLoad::Initialized",!1,!1,{instance:i})}window.dispatchEvent(n)},d=function(e,t){return e.getAttribute("data-"+t)},h=function(e,t,n){return e.setAttribute("data-"+t,n)},_=function(e){return h(e,"was-processed","true")},f=function(e){return"true"===d(e,"was-processed")},p=function(e,t,n){for(var i,o=0;i=e.children[o];o+=1)if("SOURCE"===i.tagName){var s=d(i,n);s&&i.setAttribute(t,s)}},g=function(e,t,n){n&&e.setAttribute(t,n)},m="undefined"!=typeof window,v=m&&!("onscroll"in window)||/(gle|ing|ro)bot|crawl|spider/i.test(navigator.userAgent),w=m&&"classList"in document.createElement("p"),E=function(e,t){w?e.classList.add(t):e.className+=(e.className?" ":"")+t},b=function(e,t){w?e.classList.remove(t):e.className=e.className.replace(new RegExp("(^|\\s+)"+t+"(\\s+|$)")," ").replace(/^\s+/,"").replace(/\s+$/,"")},L=function(e){this._settings=_extends({},n(),e),this._queryOriginNode=this._settings.container===window?document:this._settings.container,this._previousLoopTime=0,this._loopTimeout=null,this._boundHandleScroll=this.handleScroll.bind(this),this._isFirstLoop=!0,window.addEventListener("resize",this._boundHandleScroll),this.update()};L.prototype={_reveal:function(e,n){if(n||!f(e)){var o=this._settings,s=function t(){o&&(e.removeEventListener("load",r),e.removeEventListener("error",t),b(e,o.class_loading),E(e,o.class_error),i(o.callback_error,e))},r=function t(){o&&(b(e,o.class_loading),E(e,o.class_loaded),e.removeEventListener("load",t),e.removeEventListener("error",s),i(o.callback_load,e))};i(o.callback_enter,e),["IMG","IFRAME","VIDEO"].indexOf(e.tagName)>-1&&(e.addEventListener("load",r),e.addEventListener("error",s),E(e,o.class_loading)),t(e,o),i(o.callback_set,e)}},_loopThroughElements:function(t){var n=this._settings,o=this._elements,s=o?o.length:0,r=void 0,l=[],a=this._isFirstLoop;for(r=0;r0;)e.splice(i.pop(),1)},_startScrollHandler:function(){this._isHandlingScroll||(this._isHandlingScroll=!0,this._settings.container.addEventListener("scroll",this._boundHandleScroll))},_stopScrollHandler:function(){this._isHandlingScroll&&(this._isHandlingScroll=!1,this._settings.container.removeEventListener("scroll",this._boundHandleScroll))},handleScroll:function(){var e=this._settings.throttle;if(0!==e){var t=Date.now(),n=e-(t-this._previousLoopTime);n<=0||n>e?(this._loopTimeout&&(clearTimeout(this._loopTimeout),this._loopTimeout=null),this._previousLoopTime=t,this._loopThroughElements()):this._loopTimeout||(this._loopTimeout=setTimeout(function(){this._previousLoopTime=Date.now(),this._loopTimeout=null,this._loopThroughElements()}.bind(this),n))}else this._loopThroughElements()},loadAll:function(){this._loopThroughElements(!0)},update:function(){this._elements=Array.prototype.slice.call(this._queryOriginNode.querySelectorAll(this._settings.elements_selector)),this._purgeElements(),this._loopThroughElements(),this._startScrollHandler()},destroy:function(){window.removeEventListener("resize",this._boundHandleScroll),this._loopTimeout&&(clearTimeout(this._loopTimeout),this._loopTimeout=null),this._stopScrollHandler(),this._elements=null,this._queryOriginNode=null,this._settings=null},load:function(e,t){this._reveal(e,t)}};var T=window.lazyLoadOptions;return m&&T&&function(e,t){var n=t.length;if(n)for(var i=0;i ({\r\n\telements_selector: \"img\",\r\n\tcontainer: window,\r\n\tthreshold: 300,\r\n\tthrottle: 150,\r\n\tdata_src: \"src\",\r\n\tdata_srcset: \"srcset\",\r\n\tdata_sizes: \"sizes\",\r\n\tclass_loading: \"loading\",\r\n\tclass_loaded: \"loaded\",\r\n\tclass_error: \"error\",\r\n\tclass_initial: \"initial\",\r\n\tskip_invisible: true,\r\n\tcallback_load: null,\r\n\tcallback_error: null,\r\n\tcallback_set: null,\r\n\tcallback_processed: null,\r\n\tcallback_enter: null\r\n});\n\nconst callCallback = function(callback, argument) {\r\n\tif (callback) {\r\n\t\tcallback(argument);\r\n\t}\r\n};\n\nconst getTopOffset = function(element) {\r\n\treturn (\r\n\t\telement.getBoundingClientRect().top +\r\n\t\twindow.pageYOffset -\r\n\t\telement.ownerDocument.documentElement.clientTop\r\n\t);\r\n};\r\n\r\nconst isBelowViewport = function(element, container, threshold) {\r\n\tconst fold =\r\n\t\tcontainer === window\r\n\t\t\t? window.innerHeight + window.pageYOffset\r\n\t\t\t: getTopOffset(container) + container.offsetHeight;\r\n\treturn fold <= getTopOffset(element) - threshold;\r\n};\r\n\r\nconst getLeftOffset = function(element) {\r\n\treturn (\r\n\t\telement.getBoundingClientRect().left +\r\n\t\twindow.pageXOffset -\r\n\t\telement.ownerDocument.documentElement.clientLeft\r\n\t);\r\n};\r\n\r\nconst isAtRightOfViewport = function(element, container, threshold) {\r\n\tconst documentWidth = window.innerWidth;\r\n\tconst fold =\r\n\t\tcontainer === window\r\n\t\t\t? documentWidth + window.pageXOffset\r\n\t\t\t: getLeftOffset(container) + documentWidth;\r\n\treturn fold <= getLeftOffset(element) - threshold;\r\n};\r\n\r\nconst isAboveViewport = function(element, container, threshold) {\r\n\tconst fold =\r\n\t\tcontainer === window ? window.pageYOffset : getTopOffset(container);\r\n\treturn fold >= getTopOffset(element) + threshold + element.offsetHeight;\r\n};\r\n\r\nconst isAtLeftOfViewport = function(element, container, threshold) {\r\n\tconst fold =\r\n\t\tcontainer === window ? window.pageXOffset : getLeftOffset(container);\r\n\treturn fold >= getLeftOffset(element) + threshold + element.offsetWidth;\r\n};\r\n\r\nfunction isInsideViewport(element, container, threshold) {\r\n\treturn (\r\n\t\t!isBelowViewport(element, container, threshold) &&\r\n\t\t!isAboveViewport(element, container, threshold) &&\r\n\t\t!isAtRightOfViewport(element, container, threshold) &&\r\n\t\t!isAtLeftOfViewport(element, container, threshold)\r\n\t);\r\n}\n\n/* Creates instance and notifies it through the window element */\r\nconst createInstance = function (classObj, options) { \r\n var event;\r\n let eventString = \"LazyLoad::Initialized\";\r\n let instance = new classObj(options);\r\n try {\r\n // Works in modern browsers\r\n event = new CustomEvent(eventString, { detail: { instance } });\r\n } \r\n catch(err) {\r\n // Works in Internet Explorer (all versions)\r\n event = document.createEvent(\"CustomEvent\");\r\n event.initCustomEvent(eventString, false, false, { instance });\r\n }\r\n window.dispatchEvent(event);\r\n};\r\n\r\n/* Auto initialization of one or more instances of lazyload, depending on the \r\n options passed in (plain object or an array) */\r\nfunction autoInitialize (classObj, options) { \r\n let optsLength = options.length;\r\n if (!optsLength) {\r\n // Plain object\r\n createInstance(classObj, options);\r\n }\r\n else {\r\n // Array of objects\r\n for (let i = 0; i < optsLength; i++) {\r\n createInstance(classObj, options[i]);\r\n }\r\n }\r\n}\n\nconst dataPrefix = \"data-\";\r\nconst processedDataName = \"was-processed\";\r\nconst processedDataValue = \"true\";\r\n\r\nconst getData = (element, attribute) => {\r\n\treturn element.getAttribute(dataPrefix + attribute);\r\n};\r\n\r\nconst setData = (element, attribute, value) => {\r\n\treturn element.setAttribute(dataPrefix + attribute, value);\r\n};\r\n\r\nconst setWasProcessed = element =>\r\n\tsetData(element, processedDataName, processedDataValue);\r\n\r\nconst getWasProcessed = element =>\r\n\tgetData(element, processedDataName) === processedDataValue;\n\nconst setSourcesInChildren = function(parentTag, attrName, dataAttrName) {\r\n\tfor (let i = 0, childTag; (childTag = parentTag.children[i]); i += 1) {\r\n\t\tif (childTag.tagName === \"SOURCE\") {\r\n\t\t\tlet attributeValue = getData(childTag, dataAttrName);\r\n\t\t\tif (attributeValue) {\r\n\t\t\t\tchildTag.setAttribute(attrName, attributeValue);\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n};\r\n\r\nconst setAttributeIfNotNullOrEmpty = function(element, attrName, value) {\r\n\tif (!value) {\r\n\t\treturn;\r\n\t}\r\n\telement.setAttribute(attrName, value);\r\n};\r\n\r\nfunction setSources(element, settings) {\r\n\tconst {\r\n\t\tdata_sizes: sizesDataName,\r\n\t\tdata_srcset: srcsetDataName,\r\n\t\tdata_src: srcDataName\r\n\t} = settings;\r\n\tconst srcDataValue = getData(element, srcDataName);\r\n\tconst tagName = element.tagName;\r\n\tif (tagName === \"IMG\") {\r\n\t\tconst parent = element.parentNode;\r\n\t\tif (parent && parent.tagName === \"PICTURE\") {\r\n\t\t\tsetSourcesInChildren(parent, \"srcset\", srcsetDataName);\r\n\t\t}\r\n\t\tconst sizesDataValue = getData(element, sizesDataName);\r\n\t\tsetAttributeIfNotNullOrEmpty(element, \"sizes\", sizesDataValue);\r\n\t\tconst srcsetDataValue = getData(element, srcsetDataName);\r\n\t\tsetAttributeIfNotNullOrEmpty(element, \"srcset\", srcsetDataValue);\r\n\t\tsetAttributeIfNotNullOrEmpty(element, \"src\", srcDataValue);\r\n\t\treturn;\r\n\t}\r\n\tif (tagName === \"IFRAME\") {\r\n\t\tsetAttributeIfNotNullOrEmpty(element, \"src\", srcDataValue);\r\n\t\treturn;\r\n\t}\r\n\tif (tagName === \"VIDEO\") {\r\n\t\tsetSourcesInChildren(element, \"src\", srcDataName);\r\n\t\tsetAttributeIfNotNullOrEmpty(element, \"src\", srcDataValue);\r\n\t\treturn;\r\n\t}\r\n\tif (srcDataValue) {\r\n\t\telement.style.backgroundImage = `url(\"${srcDataValue}\")`;\r\n\t}\r\n}\n\nconst runningOnBrowser = typeof window !== \"undefined\";\r\n\r\nconst isBot =\r\n\t(runningOnBrowser && !(\"onscroll\" in window)) ||\r\n\t/(gle|ing|ro)bot|crawl|spider/i.test(navigator.userAgent);\r\nconst supportsClassList =\r\n\trunningOnBrowser && \"classList\" in document.createElement(\"p\");\n\nconst addClass = (element, className) => {\r\n if (supportsClassList) {\r\n element.classList.add(className);\r\n return;\r\n }\r\n element.className += (element.className ? \" \" : \"\") + className;\r\n};\r\n\r\nconst removeClass = (element, className) => {\r\n if (supportsClassList) {\r\n element.classList.remove(className);\r\n return;\r\n }\r\n element.className = element.className.replace(new RegExp(\"(^|\\\\s+)\" + className + \"(\\\\s+|$)\"), \" \").replace(/^\\s+/, \"\").replace(/\\s+$/, \"\");\r\n};\n\n/*\r\n * Constructor\r\n */\r\n\r\nconst LazyLoad = function(instanceSettings) {\r\n\tthis._settings = Object.assign({}, getDefaultSettings(), instanceSettings);\r\n\tthis._queryOriginNode =\r\n\t\tthis._settings.container === window\r\n\t\t\t? document\r\n\t\t\t: this._settings.container;\r\n\r\n\tthis._previousLoopTime = 0;\r\n\tthis._loopTimeout = null;\r\n\tthis._boundHandleScroll = this.handleScroll.bind(this);\r\n\r\n\tthis._isFirstLoop = true;\r\n\twindow.addEventListener(\"resize\", this._boundHandleScroll);\r\n\tthis.update();\r\n};\r\n\r\nLazyLoad.prototype = {\r\n\t_reveal: function(element, force) {\r\n\t\tif (!force && getWasProcessed(element)) {\r\n\t\t\treturn; // element has already been processed and force wasn't true\r\n\t\t}\r\n\r\n\t\tconst settings = this._settings;\r\n\r\n\t\tconst errorCallback = function() {\r\n\t\t\t/* As this method is asynchronous, it must be protected against external destroy() calls */\r\n\t\t\tif (!settings) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\telement.removeEventListener(\"load\", loadCallback);\r\n\t\t\telement.removeEventListener(\"error\", errorCallback);\r\n\t\t\tremoveClass(element, settings.class_loading);\r\n\t\t\taddClass(element, settings.class_error);\r\n\t\t\tcallCallback(settings.callback_error, element);\r\n\t\t};\r\n\r\n\t\tconst loadCallback = function() {\r\n\t\t\t/* As this method is asynchronous, it must be protected against external destroy() calls */\r\n\t\t\tif (!settings) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\tremoveClass(element, settings.class_loading);\r\n\t\t\taddClass(element, settings.class_loaded);\r\n\t\t\telement.removeEventListener(\"load\", loadCallback);\r\n\t\t\telement.removeEventListener(\"error\", errorCallback);\r\n\t\t\tcallCallback(settings.callback_load, element);\r\n\t\t};\r\n\r\n\t\tcallCallback(settings.callback_enter, element);\r\n\t\tif ([\"IMG\", \"IFRAME\", \"VIDEO\"].indexOf(element.tagName) > -1) {\r\n\t\t\telement.addEventListener(\"load\", loadCallback);\r\n\t\t\telement.addEventListener(\"error\", errorCallback);\r\n\t\t\taddClass(element, settings.class_loading);\r\n\t\t}\r\n\t\tsetSources(element, settings);\r\n\t\tcallCallback(settings.callback_set, element);\r\n\t},\r\n\r\n\t_loopThroughElements: function(forceDownload) {\r\n\t\tconst settings = this._settings,\r\n\t\t\telements = this._elements,\r\n\t\t\telementsLength = !elements ? 0 : elements.length;\r\n\t\tlet i,\r\n\t\t\tprocessedIndexes = [],\r\n\t\t\tfirstLoop = this._isFirstLoop;\r\n\r\n\t\tfor (i = 0; i < elementsLength; i++) {\r\n\t\t\tlet element = elements[i];\r\n\t\t\t/* If must skip_invisible and element is invisible, skip it */\r\n\t\t\tif (settings.skip_invisible && element.offsetParent === null) {\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\r\n\t\t\tif (\r\n\t\t\t\tisBot ||\r\n\t\t\t\tforceDownload ||\r\n\t\t\t\tisInsideViewport(\r\n\t\t\t\t\telement,\r\n\t\t\t\t\tsettings.container,\r\n\t\t\t\t\tsettings.threshold\r\n\t\t\t\t)\r\n\t\t\t) {\r\n\t\t\t\tif (firstLoop) {\r\n\t\t\t\t\taddClass(element, settings.class_initial);\r\n\t\t\t\t}\r\n\t\t\t\t/* Start loading the image */\r\n\t\t\t\tthis.load(element);\r\n\t\t\t\t/* Marking the element as processed. */\r\n\t\t\t\tprocessedIndexes.push(i);\r\n\t\t\t\tsetWasProcessed(element);\r\n\t\t\t}\r\n\t\t}\r\n\t\t/* Removing processed elements from this._elements. */\r\n\t\twhile (processedIndexes.length) {\r\n\t\t\telements.splice(processedIndexes.pop(), 1);\r\n\t\t\tcallCallback(settings.callback_processed, elements.length);\r\n\t\t}\r\n\t\t/* Stop listening to scroll event when 0 elements remains */\r\n\t\tif (elementsLength === 0) {\r\n\t\t\tthis._stopScrollHandler();\r\n\t\t}\r\n\t\t/* Sets isFirstLoop to false */\r\n\t\tif (firstLoop) {\r\n\t\t\tthis._isFirstLoop = false;\r\n\t\t}\r\n\t},\r\n\r\n\t_purgeElements: function() {\r\n\t\tconst elements = this._elements,\r\n\t\t\telementsLength = elements.length;\r\n\t\tlet i,\r\n\t\t\telementsToPurge = [];\r\n\r\n\t\tfor (i = 0; i < elementsLength; i++) {\r\n\t\t\tlet element = elements[i];\r\n\t\t\t/* If the element has already been processed, skip it */\r\n\t\t\tif (getWasProcessed(element)) {\r\n\t\t\t\telementsToPurge.push(i);\r\n\t\t\t}\r\n\t\t}\r\n\t\t/* Removing elements to purge from this._elements. */\r\n\t\twhile (elementsToPurge.length > 0) {\r\n\t\t\telements.splice(elementsToPurge.pop(), 1);\r\n\t\t}\r\n\t},\r\n\r\n\t_startScrollHandler: function() {\r\n\t\tif (!this._isHandlingScroll) {\r\n\t\t\tthis._isHandlingScroll = true;\r\n\t\t\tthis._settings.container.addEventListener(\r\n\t\t\t\t\"scroll\",\r\n\t\t\t\tthis._boundHandleScroll\r\n\t\t\t);\r\n\t\t}\r\n\t},\r\n\r\n\t_stopScrollHandler: function() {\r\n\t\tif (this._isHandlingScroll) {\r\n\t\t\tthis._isHandlingScroll = false;\r\n\t\t\tthis._settings.container.removeEventListener(\r\n\t\t\t\t\"scroll\",\r\n\t\t\t\tthis._boundHandleScroll\r\n\t\t\t);\r\n\t\t}\r\n\t},\r\n\r\n\thandleScroll: function() {\r\n\t\tconst throttle = this._settings.throttle;\r\n\r\n\t\tif (throttle !== 0) {\r\n\t\t\tlet now = Date.now();\r\n\t\t\tlet remainingTime = throttle - (now - this._previousLoopTime);\r\n\t\t\tif (remainingTime <= 0 || remainingTime > throttle) {\r\n\t\t\t\tif (this._loopTimeout) {\r\n\t\t\t\t\tclearTimeout(this._loopTimeout);\r\n\t\t\t\t\tthis._loopTimeout = null;\r\n\t\t\t\t}\r\n\t\t\t\tthis._previousLoopTime = now;\r\n\t\t\t\tthis._loopThroughElements();\r\n\t\t\t} else if (!this._loopTimeout) {\r\n\t\t\t\tthis._loopTimeout = setTimeout(\r\n\t\t\t\t\tfunction() {\r\n\t\t\t\t\t\tthis._previousLoopTime = Date.now();\r\n\t\t\t\t\t\tthis._loopTimeout = null;\r\n\t\t\t\t\t\tthis._loopThroughElements();\r\n\t\t\t\t\t}.bind(this),\r\n\t\t\t\t\tremainingTime\r\n\t\t\t\t);\r\n\t\t\t}\r\n\t\t} else {\r\n\t\t\tthis._loopThroughElements();\r\n\t\t}\r\n\t},\r\n\r\n\tloadAll: function() {\r\n\t\tthis._loopThroughElements(true);\r\n\t},\r\n\r\n\tupdate: function() {\r\n\t\t// Converts to array the nodeset obtained querying the DOM from _queryOriginNode with elements_selector\r\n\t\tthis._elements = Array.prototype.slice.call(\r\n\t\t\tthis._queryOriginNode.querySelectorAll(\r\n\t\t\t\tthis._settings.elements_selector\r\n\t\t\t)\r\n\t\t);\r\n\t\tthis._purgeElements();\r\n\t\tthis._loopThroughElements();\r\n\t\tthis._startScrollHandler();\r\n\t},\r\n\r\n\tdestroy: function() {\r\n\t\twindow.removeEventListener(\"resize\", this._boundHandleScroll);\r\n\t\tif (this._loopTimeout) {\r\n\t\t\tclearTimeout(this._loopTimeout);\r\n\t\t\tthis._loopTimeout = null;\r\n\t\t}\r\n\t\tthis._stopScrollHandler();\r\n\t\tthis._elements = null;\r\n\t\tthis._queryOriginNode = null;\r\n\t\tthis._settings = null;\r\n\t},\r\n\r\n\tload: function(element, force) {\r\n\t\tthis._reveal(element, force);\r\n\t}\r\n};\r\n\r\n/* Automatic instances creation if required (useful for async script loading!) */\r\nlet autoInitOptions = window.lazyLoadOptions;\r\nif (runningOnBrowser && autoInitOptions) {\r\n\tautoInitialize(LazyLoad, autoInitOptions);\r\n}\n\nreturn LazyLoad;\n\n});\n"]} \ No newline at end of file diff --git a/dist/lazyload.es2015.js b/dist/lazyload.es2015.js index 9b1db983..6bfc2778 100644 --- a/dist/lazyload.es2015.js +++ b/dist/lazyload.es2015.js @@ -1,9 +1,3 @@ -(function (global, factory) { - typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : - typeof define === 'function' && define.amd ? define(factory) : - (global.LazyLoad = factory()); -}(this, (function () { 'use strict'; - var getDefaultSettings = () => ({ elements_selector: "img", container: window, @@ -189,12 +183,11 @@ function setSources(element, settings) { const runningOnBrowser = typeof window !== "undefined"; -const supportsClassList = - runningOnBrowser && "classList" in document.createElement("p"); - const isBot = (runningOnBrowser && !("onscroll" in window)) || - /glebot|bingbot|crawler|spider|robot|crawling/i.test(navigator.userAgent); + /(gle|ing|ro)bot|crawl|spider/i.test(navigator.userAgent); +const supportsClassList = + runningOnBrowser && "classList" in document.createElement("p"); const addClass = (element, className) => { if (supportsClassList) { @@ -429,6 +422,4 @@ if (runningOnBrowser && autoInitOptions) { autoInitialize(LazyLoad, autoInitOptions); } -return LazyLoad; - -}))); +export default LazyLoad; diff --git a/dist/lazyload.iife.js b/dist/lazyload.iife.js new file mode 100644 index 00000000..803b13eb --- /dev/null +++ b/dist/lazyload.iife.js @@ -0,0 +1,384 @@ +var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; + +var LazyLoad = function () { + 'use strict'; + + var getDefaultSettings = function getDefaultSettings() { + return { + elements_selector: "img", + container: window, + threshold: 300, + throttle: 150, + data_src: "src", + data_srcset: "srcset", + data_sizes: "sizes", + class_loading: "loading", + class_loaded: "loaded", + class_error: "error", + class_initial: "initial", + skip_invisible: true, + callback_load: null, + callback_error: null, + callback_set: null, + callback_processed: null, + callback_enter: null + }; + }; + + var callCallback = function callCallback(callback, argument) { + if (callback) { + callback(argument); + } + }; + + var getTopOffset = function getTopOffset(element) { + return element.getBoundingClientRect().top + window.pageYOffset - element.ownerDocument.documentElement.clientTop; + }; + + var isBelowViewport = function isBelowViewport(element, container, threshold) { + var fold = container === window ? window.innerHeight + window.pageYOffset : getTopOffset(container) + container.offsetHeight; + return fold <= getTopOffset(element) - threshold; + }; + + var getLeftOffset = function getLeftOffset(element) { + return element.getBoundingClientRect().left + window.pageXOffset - element.ownerDocument.documentElement.clientLeft; + }; + + var isAtRightOfViewport = function isAtRightOfViewport(element, container, threshold) { + var documentWidth = window.innerWidth; + var fold = container === window ? documentWidth + window.pageXOffset : getLeftOffset(container) + documentWidth; + return fold <= getLeftOffset(element) - threshold; + }; + + var isAboveViewport = function isAboveViewport(element, container, threshold) { + var fold = container === window ? window.pageYOffset : getTopOffset(container); + return fold >= getTopOffset(element) + threshold + element.offsetHeight; + }; + + var isAtLeftOfViewport = function isAtLeftOfViewport(element, container, threshold) { + var fold = container === window ? window.pageXOffset : getLeftOffset(container); + return fold >= getLeftOffset(element) + threshold + element.offsetWidth; + }; + + function isInsideViewport(element, container, threshold) { + return !isBelowViewport(element, container, threshold) && !isAboveViewport(element, container, threshold) && !isAtRightOfViewport(element, container, threshold) && !isAtLeftOfViewport(element, container, threshold); + } + + /* Creates instance and notifies it through the window element */ + var createInstance = function createInstance(classObj, options) { + var event; + var eventString = "LazyLoad::Initialized"; + var instance = new classObj(options); + try { + // Works in modern browsers + event = new CustomEvent(eventString, { detail: { instance: instance } }); + } catch (err) { + // Works in Internet Explorer (all versions) + event = document.createEvent("CustomEvent"); + event.initCustomEvent(eventString, false, false, { instance: instance }); + } + window.dispatchEvent(event); + }; + + /* Auto initialization of one or more instances of lazyload, depending on the + options passed in (plain object or an array) */ + function autoInitialize(classObj, options) { + var optsLength = options.length; + if (!optsLength) { + // Plain object + createInstance(classObj, options); + } else { + // Array of objects + for (var i = 0; i < optsLength; i++) { + createInstance(classObj, options[i]); + } + } + } + + var dataPrefix = "data-"; + var processedDataName = "was-processed"; + var processedDataValue = "true"; + + var getData = function getData(element, attribute) { + return element.getAttribute(dataPrefix + attribute); + }; + + var setData = function setData(element, attribute, value) { + return element.setAttribute(dataPrefix + attribute, value); + }; + + var setWasProcessed = function setWasProcessed(element) { + return setData(element, processedDataName, processedDataValue); + }; + + var getWasProcessed = function getWasProcessed(element) { + return getData(element, processedDataName) === processedDataValue; + }; + + var setSourcesInChildren = function setSourcesInChildren(parentTag, attrName, dataAttrName) { + for (var i = 0, childTag; childTag = parentTag.children[i]; i += 1) { + if (childTag.tagName === "SOURCE") { + var attributeValue = getData(childTag, dataAttrName); + if (attributeValue) { + childTag.setAttribute(attrName, attributeValue); + } + } + } + }; + + var setAttributeIfNotNullOrEmpty = function setAttributeIfNotNullOrEmpty(element, attrName, value) { + if (!value) { + return; + } + element.setAttribute(attrName, value); + }; + + function setSources(element, settings) { + var sizesDataName = settings.data_sizes, + srcsetDataName = settings.data_srcset, + srcDataName = settings.data_src; + + var srcDataValue = getData(element, srcDataName); + var tagName = element.tagName; + if (tagName === "IMG") { + var parent = element.parentNode; + if (parent && parent.tagName === "PICTURE") { + setSourcesInChildren(parent, "srcset", srcsetDataName); + } + var sizesDataValue = getData(element, sizesDataName); + setAttributeIfNotNullOrEmpty(element, "sizes", sizesDataValue); + var srcsetDataValue = getData(element, srcsetDataName); + setAttributeIfNotNullOrEmpty(element, "srcset", srcsetDataValue); + setAttributeIfNotNullOrEmpty(element, "src", srcDataValue); + return; + } + if (tagName === "IFRAME") { + setAttributeIfNotNullOrEmpty(element, "src", srcDataValue); + return; + } + if (tagName === "VIDEO") { + setSourcesInChildren(element, "src", srcDataName); + setAttributeIfNotNullOrEmpty(element, "src", srcDataValue); + return; + } + if (srcDataValue) { + element.style.backgroundImage = "url(\"" + srcDataValue + "\")"; + } + } + + var runningOnBrowser = typeof window !== "undefined"; + + var isBot = runningOnBrowser && !("onscroll" in window) || /(gle|ing|ro)bot|crawl|spider/i.test(navigator.userAgent); + var supportsClassList = runningOnBrowser && "classList" in document.createElement("p"); + + var addClass = function addClass(element, className) { + if (supportsClassList) { + element.classList.add(className); + return; + } + element.className += (element.className ? " " : "") + className; + }; + + var removeClass = function removeClass(element, className) { + if (supportsClassList) { + element.classList.remove(className); + return; + } + element.className = element.className.replace(new RegExp("(^|\\s+)" + className + "(\\s+|$)"), " ").replace(/^\s+/, "").replace(/\s+$/, ""); + }; + + /* + * Constructor + */ + + var LazyLoad = function LazyLoad(instanceSettings) { + this._settings = _extends({}, getDefaultSettings(), instanceSettings); + this._queryOriginNode = this._settings.container === window ? document : this._settings.container; + + this._previousLoopTime = 0; + this._loopTimeout = null; + this._boundHandleScroll = this.handleScroll.bind(this); + + this._isFirstLoop = true; + window.addEventListener("resize", this._boundHandleScroll); + this.update(); + }; + + LazyLoad.prototype = { + _reveal: function _reveal(element, force) { + if (!force && getWasProcessed(element)) { + return; // element has already been processed and force wasn't true + } + + var settings = this._settings; + + var errorCallback = function errorCallback() { + /* As this method is asynchronous, it must be protected against external destroy() calls */ + if (!settings) { + return; + } + element.removeEventListener("load", loadCallback); + element.removeEventListener("error", errorCallback); + removeClass(element, settings.class_loading); + addClass(element, settings.class_error); + callCallback(settings.callback_error, element); + }; + + var loadCallback = function loadCallback() { + /* As this method is asynchronous, it must be protected against external destroy() calls */ + if (!settings) { + return; + } + removeClass(element, settings.class_loading); + addClass(element, settings.class_loaded); + element.removeEventListener("load", loadCallback); + element.removeEventListener("error", errorCallback); + callCallback(settings.callback_load, element); + }; + + callCallback(settings.callback_enter, element); + if (["IMG", "IFRAME", "VIDEO"].indexOf(element.tagName) > -1) { + element.addEventListener("load", loadCallback); + element.addEventListener("error", errorCallback); + addClass(element, settings.class_loading); + } + setSources(element, settings); + callCallback(settings.callback_set, element); + }, + + _loopThroughElements: function _loopThroughElements(forceDownload) { + var settings = this._settings, + elements = this._elements, + elementsLength = !elements ? 0 : elements.length; + var i = void 0, + processedIndexes = [], + firstLoop = this._isFirstLoop; + + for (i = 0; i < elementsLength; i++) { + var element = elements[i]; + /* If must skip_invisible and element is invisible, skip it */ + if (settings.skip_invisible && element.offsetParent === null) { + continue; + } + + if (isBot || forceDownload || isInsideViewport(element, settings.container, settings.threshold)) { + if (firstLoop) { + addClass(element, settings.class_initial); + } + /* Start loading the image */ + this.load(element); + /* Marking the element as processed. */ + processedIndexes.push(i); + setWasProcessed(element); + } + } + /* Removing processed elements from this._elements. */ + while (processedIndexes.length) { + elements.splice(processedIndexes.pop(), 1); + callCallback(settings.callback_processed, elements.length); + } + /* Stop listening to scroll event when 0 elements remains */ + if (elementsLength === 0) { + this._stopScrollHandler(); + } + /* Sets isFirstLoop to false */ + if (firstLoop) { + this._isFirstLoop = false; + } + }, + + _purgeElements: function _purgeElements() { + var elements = this._elements, + elementsLength = elements.length; + var i = void 0, + elementsToPurge = []; + + for (i = 0; i < elementsLength; i++) { + var element = elements[i]; + /* If the element has already been processed, skip it */ + if (getWasProcessed(element)) { + elementsToPurge.push(i); + } + } + /* Removing elements to purge from this._elements. */ + while (elementsToPurge.length > 0) { + elements.splice(elementsToPurge.pop(), 1); + } + }, + + _startScrollHandler: function _startScrollHandler() { + if (!this._isHandlingScroll) { + this._isHandlingScroll = true; + this._settings.container.addEventListener("scroll", this._boundHandleScroll); + } + }, + + _stopScrollHandler: function _stopScrollHandler() { + if (this._isHandlingScroll) { + this._isHandlingScroll = false; + this._settings.container.removeEventListener("scroll", this._boundHandleScroll); + } + }, + + handleScroll: function handleScroll() { + var throttle = this._settings.throttle; + + if (throttle !== 0) { + var now = Date.now(); + var remainingTime = throttle - (now - this._previousLoopTime); + if (remainingTime <= 0 || remainingTime > throttle) { + if (this._loopTimeout) { + clearTimeout(this._loopTimeout); + this._loopTimeout = null; + } + this._previousLoopTime = now; + this._loopThroughElements(); + } else if (!this._loopTimeout) { + this._loopTimeout = setTimeout(function () { + this._previousLoopTime = Date.now(); + this._loopTimeout = null; + this._loopThroughElements(); + }.bind(this), remainingTime); + } + } else { + this._loopThroughElements(); + } + }, + + loadAll: function loadAll() { + this._loopThroughElements(true); + }, + + update: function update() { + // Converts to array the nodeset obtained querying the DOM from _queryOriginNode with elements_selector + this._elements = Array.prototype.slice.call(this._queryOriginNode.querySelectorAll(this._settings.elements_selector)); + this._purgeElements(); + this._loopThroughElements(); + this._startScrollHandler(); + }, + + destroy: function destroy() { + window.removeEventListener("resize", this._boundHandleScroll); + if (this._loopTimeout) { + clearTimeout(this._loopTimeout); + this._loopTimeout = null; + } + this._stopScrollHandler(); + this._elements = null; + this._queryOriginNode = null; + this._settings = null; + }, + + load: function load(element, force) { + this._reveal(element, force); + } + }; + + /* Automatic instances creation if required (useful for async script loading!) */ + var autoInitOptions = window.lazyLoadOptions; + if (runningOnBrowser && autoInitOptions) { + autoInitialize(LazyLoad, autoInitOptions); + } + + return LazyLoad; +}(); \ No newline at end of file diff --git a/dist/lazyload.iife.min.js b/dist/lazyload.iife.min.js new file mode 100644 index 00000000..0850b1de --- /dev/null +++ b/dist/lazyload.iife.min.js @@ -0,0 +1,2 @@ +var _extends=Object.assign||function(e){for(var t=1;t=o(e)+n+e.offsetHeight},c=function(e,t,n){return(t===window?window.pageXOffset:r(t))>=r(e)+n+e.offsetWidth},u=function(e,t){var n,i=new e(t);try{n=new CustomEvent("LazyLoad::Initialized",{detail:{instance:i}})}catch(e){(n=document.createEvent("CustomEvent")).initCustomEvent("LazyLoad::Initialized",!1,!1,{instance:i})}window.dispatchEvent(n)},d=function(e,t){return e.getAttribute("data-"+t)},h=function(e,t,n){return e.setAttribute("data-"+t,n)},_=function(e){return h(e,"was-processed","true")},f=function(e){return"true"===d(e,"was-processed")},p=function(e,t,n){for(var i,o=0;i=e.children[o];o+=1)if("SOURCE"===i.tagName){var s=d(i,n);s&&i.setAttribute(t,s)}},g=function(e,t,n){n&&e.setAttribute(t,n)},m="undefined"!=typeof window,v=m&&!("onscroll"in window)||/(gle|ing|ro)bot|crawl|spider/i.test(navigator.userAgent),w=m&&"classList"in document.createElement("p"),E=function(e,t){w?e.classList.add(t):e.className+=(e.className?" ":"")+t},L=function(e,t){w?e.classList.remove(t):e.className=e.className.replace(new RegExp("(^|\\s+)"+t+"(\\s+|$)")," ").replace(/^\s+/,"").replace(/\s+$/,"")},b=function(e){this._settings=_extends({},n(),e),this._queryOriginNode=this._settings.container===window?document:this._settings.container,this._previousLoopTime=0,this._loopTimeout=null,this._boundHandleScroll=this.handleScroll.bind(this),this._isFirstLoop=!0,window.addEventListener("resize",this._boundHandleScroll),this.update()};b.prototype={_reveal:function(e,n){if(n||!f(e)){var o=this._settings,s=function t(){o&&(e.removeEventListener("load",r),e.removeEventListener("error",t),L(e,o.class_loading),E(e,o.class_error),i(o.callback_error,e))},r=function t(){o&&(L(e,o.class_loading),E(e,o.class_loaded),e.removeEventListener("load",t),e.removeEventListener("error",s),i(o.callback_load,e))};i(o.callback_enter,e),["IMG","IFRAME","VIDEO"].indexOf(e.tagName)>-1&&(e.addEventListener("load",r),e.addEventListener("error",s),E(e,o.class_loading)),t(e,o),i(o.callback_set,e)}},_loopThroughElements:function(t){var n=this._settings,o=this._elements,s=o?o.length:0,r=void 0,l=[],a=this._isFirstLoop;for(r=0;r0;)e.splice(i.pop(),1)},_startScrollHandler:function(){this._isHandlingScroll||(this._isHandlingScroll=!0,this._settings.container.addEventListener("scroll",this._boundHandleScroll))},_stopScrollHandler:function(){this._isHandlingScroll&&(this._isHandlingScroll=!1,this._settings.container.removeEventListener("scroll",this._boundHandleScroll))},handleScroll:function(){var e=this._settings.throttle;if(0!==e){var t=Date.now(),n=e-(t-this._previousLoopTime);n<=0||n>e?(this._loopTimeout&&(clearTimeout(this._loopTimeout),this._loopTimeout=null),this._previousLoopTime=t,this._loopThroughElements()):this._loopTimeout||(this._loopTimeout=setTimeout(function(){this._previousLoopTime=Date.now(),this._loopTimeout=null,this._loopThroughElements()}.bind(this),n))}else this._loopThroughElements()},loadAll:function(){this._loopThroughElements(!0)},update:function(){this._elements=Array.prototype.slice.call(this._queryOriginNode.querySelectorAll(this._settings.elements_selector)),this._purgeElements(),this._loopThroughElements(),this._startScrollHandler()},destroy:function(){window.removeEventListener("resize",this._boundHandleScroll),this._loopTimeout&&(clearTimeout(this._loopTimeout),this._loopTimeout=null),this._stopScrollHandler(),this._elements=null,this._queryOriginNode=null,this._settings=null},load:function(e,t){this._reveal(e,t)}};var T=window.lazyLoadOptions;return m&&T&&function(e,t){var n=t.length;if(n)for(var i=0;i ({\r\n\telements_selector: \"img\",\r\n\tcontainer: window,\r\n\tthreshold: 300,\r\n\tthrottle: 150,\r\n\tdata_src: \"src\",\r\n\tdata_srcset: \"srcset\",\r\n\tdata_sizes: \"sizes\",\r\n\tclass_loading: \"loading\",\r\n\tclass_loaded: \"loaded\",\r\n\tclass_error: \"error\",\r\n\tclass_initial: \"initial\",\r\n\tskip_invisible: true,\r\n\tcallback_load: null,\r\n\tcallback_error: null,\r\n\tcallback_set: null,\r\n\tcallback_processed: null,\r\n\tcallback_enter: null\r\n});\n\nconst callCallback = function(callback, argument) {\r\n\tif (callback) {\r\n\t\tcallback(argument);\r\n\t}\r\n};\n\nconst getTopOffset = function(element) {\r\n\treturn (\r\n\t\telement.getBoundingClientRect().top +\r\n\t\twindow.pageYOffset -\r\n\t\telement.ownerDocument.documentElement.clientTop\r\n\t);\r\n};\r\n\r\nconst isBelowViewport = function(element, container, threshold) {\r\n\tconst fold =\r\n\t\tcontainer === window\r\n\t\t\t? window.innerHeight + window.pageYOffset\r\n\t\t\t: getTopOffset(container) + container.offsetHeight;\r\n\treturn fold <= getTopOffset(element) - threshold;\r\n};\r\n\r\nconst getLeftOffset = function(element) {\r\n\treturn (\r\n\t\telement.getBoundingClientRect().left +\r\n\t\twindow.pageXOffset -\r\n\t\telement.ownerDocument.documentElement.clientLeft\r\n\t);\r\n};\r\n\r\nconst isAtRightOfViewport = function(element, container, threshold) {\r\n\tconst documentWidth = window.innerWidth;\r\n\tconst fold =\r\n\t\tcontainer === window\r\n\t\t\t? documentWidth + window.pageXOffset\r\n\t\t\t: getLeftOffset(container) + documentWidth;\r\n\treturn fold <= getLeftOffset(element) - threshold;\r\n};\r\n\r\nconst isAboveViewport = function(element, container, threshold) {\r\n\tconst fold =\r\n\t\tcontainer === window ? window.pageYOffset : getTopOffset(container);\r\n\treturn fold >= getTopOffset(element) + threshold + element.offsetHeight;\r\n};\r\n\r\nconst isAtLeftOfViewport = function(element, container, threshold) {\r\n\tconst fold =\r\n\t\tcontainer === window ? window.pageXOffset : getLeftOffset(container);\r\n\treturn fold >= getLeftOffset(element) + threshold + element.offsetWidth;\r\n};\r\n\r\nfunction isInsideViewport(element, container, threshold) {\r\n\treturn (\r\n\t\t!isBelowViewport(element, container, threshold) &&\r\n\t\t!isAboveViewport(element, container, threshold) &&\r\n\t\t!isAtRightOfViewport(element, container, threshold) &&\r\n\t\t!isAtLeftOfViewport(element, container, threshold)\r\n\t);\r\n}\n\n/* Creates instance and notifies it through the window element */\r\nconst createInstance = function (classObj, options) { \r\n var event;\r\n let eventString = \"LazyLoad::Initialized\";\r\n let instance = new classObj(options);\r\n try {\r\n // Works in modern browsers\r\n event = new CustomEvent(eventString, { detail: { instance } });\r\n } \r\n catch(err) {\r\n // Works in Internet Explorer (all versions)\r\n event = document.createEvent(\"CustomEvent\");\r\n event.initCustomEvent(eventString, false, false, { instance });\r\n }\r\n window.dispatchEvent(event);\r\n};\r\n\r\n/* Auto initialization of one or more instances of lazyload, depending on the \r\n options passed in (plain object or an array) */\r\nfunction autoInitialize (classObj, options) { \r\n let optsLength = options.length;\r\n if (!optsLength) {\r\n // Plain object\r\n createInstance(classObj, options);\r\n }\r\n else {\r\n // Array of objects\r\n for (let i = 0; i < optsLength; i++) {\r\n createInstance(classObj, options[i]);\r\n }\r\n }\r\n}\n\nconst dataPrefix = \"data-\";\r\nconst processedDataName = \"was-processed\";\r\nconst processedDataValue = \"true\";\r\n\r\nconst getData = (element, attribute) => {\r\n\treturn element.getAttribute(dataPrefix + attribute);\r\n};\r\n\r\nconst setData = (element, attribute, value) => {\r\n\treturn element.setAttribute(dataPrefix + attribute, value);\r\n};\r\n\r\nconst setWasProcessed = element =>\r\n\tsetData(element, processedDataName, processedDataValue);\r\n\r\nconst getWasProcessed = element =>\r\n\tgetData(element, processedDataName) === processedDataValue;\n\nconst setSourcesInChildren = function(parentTag, attrName, dataAttrName) {\r\n\tfor (let i = 0, childTag; (childTag = parentTag.children[i]); i += 1) {\r\n\t\tif (childTag.tagName === \"SOURCE\") {\r\n\t\t\tlet attributeValue = getData(childTag, dataAttrName);\r\n\t\t\tif (attributeValue) {\r\n\t\t\t\tchildTag.setAttribute(attrName, attributeValue);\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n};\r\n\r\nconst setAttributeIfNotNullOrEmpty = function(element, attrName, value) {\r\n\tif (!value) {\r\n\t\treturn;\r\n\t}\r\n\telement.setAttribute(attrName, value);\r\n};\r\n\r\nfunction setSources(element, settings) {\r\n\tconst {\r\n\t\tdata_sizes: sizesDataName,\r\n\t\tdata_srcset: srcsetDataName,\r\n\t\tdata_src: srcDataName\r\n\t} = settings;\r\n\tconst srcDataValue = getData(element, srcDataName);\r\n\tconst tagName = element.tagName;\r\n\tif (tagName === \"IMG\") {\r\n\t\tconst parent = element.parentNode;\r\n\t\tif (parent && parent.tagName === \"PICTURE\") {\r\n\t\t\tsetSourcesInChildren(parent, \"srcset\", srcsetDataName);\r\n\t\t}\r\n\t\tconst sizesDataValue = getData(element, sizesDataName);\r\n\t\tsetAttributeIfNotNullOrEmpty(element, \"sizes\", sizesDataValue);\r\n\t\tconst srcsetDataValue = getData(element, srcsetDataName);\r\n\t\tsetAttributeIfNotNullOrEmpty(element, \"srcset\", srcsetDataValue);\r\n\t\tsetAttributeIfNotNullOrEmpty(element, \"src\", srcDataValue);\r\n\t\treturn;\r\n\t}\r\n\tif (tagName === \"IFRAME\") {\r\n\t\tsetAttributeIfNotNullOrEmpty(element, \"src\", srcDataValue);\r\n\t\treturn;\r\n\t}\r\n\tif (tagName === \"VIDEO\") {\r\n\t\tsetSourcesInChildren(element, \"src\", srcDataName);\r\n\t\tsetAttributeIfNotNullOrEmpty(element, \"src\", srcDataValue);\r\n\t\treturn;\r\n\t}\r\n\tif (srcDataValue) {\r\n\t\telement.style.backgroundImage = `url(\"${srcDataValue}\")`;\r\n\t}\r\n}\n\nconst runningOnBrowser = typeof window !== \"undefined\";\r\n\r\nconst isBot =\r\n\t(runningOnBrowser && !(\"onscroll\" in window)) ||\r\n\t/(gle|ing|ro)bot|crawl|spider/i.test(navigator.userAgent);\r\nconst supportsClassList =\r\n\trunningOnBrowser && \"classList\" in document.createElement(\"p\");\n\nconst addClass = (element, className) => {\r\n if (supportsClassList) {\r\n element.classList.add(className);\r\n return;\r\n }\r\n element.className += (element.className ? \" \" : \"\") + className;\r\n};\r\n\r\nconst removeClass = (element, className) => {\r\n if (supportsClassList) {\r\n element.classList.remove(className);\r\n return;\r\n }\r\n element.className = element.className.replace(new RegExp(\"(^|\\\\s+)\" + className + \"(\\\\s+|$)\"), \" \").replace(/^\\s+/, \"\").replace(/\\s+$/, \"\");\r\n};\n\n/*\r\n * Constructor\r\n */\r\n\r\nconst LazyLoad = function(instanceSettings) {\r\n\tthis._settings = Object.assign({}, getDefaultSettings(), instanceSettings);\r\n\tthis._queryOriginNode =\r\n\t\tthis._settings.container === window\r\n\t\t\t? document\r\n\t\t\t: this._settings.container;\r\n\r\n\tthis._previousLoopTime = 0;\r\n\tthis._loopTimeout = null;\r\n\tthis._boundHandleScroll = this.handleScroll.bind(this);\r\n\r\n\tthis._isFirstLoop = true;\r\n\twindow.addEventListener(\"resize\", this._boundHandleScroll);\r\n\tthis.update();\r\n};\r\n\r\nLazyLoad.prototype = {\r\n\t_reveal: function(element, force) {\r\n\t\tif (!force && getWasProcessed(element)) {\r\n\t\t\treturn; // element has already been processed and force wasn't true\r\n\t\t}\r\n\r\n\t\tconst settings = this._settings;\r\n\r\n\t\tconst errorCallback = function() {\r\n\t\t\t/* As this method is asynchronous, it must be protected against external destroy() calls */\r\n\t\t\tif (!settings) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\telement.removeEventListener(\"load\", loadCallback);\r\n\t\t\telement.removeEventListener(\"error\", errorCallback);\r\n\t\t\tremoveClass(element, settings.class_loading);\r\n\t\t\taddClass(element, settings.class_error);\r\n\t\t\tcallCallback(settings.callback_error, element);\r\n\t\t};\r\n\r\n\t\tconst loadCallback = function() {\r\n\t\t\t/* As this method is asynchronous, it must be protected against external destroy() calls */\r\n\t\t\tif (!settings) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\tremoveClass(element, settings.class_loading);\r\n\t\t\taddClass(element, settings.class_loaded);\r\n\t\t\telement.removeEventListener(\"load\", loadCallback);\r\n\t\t\telement.removeEventListener(\"error\", errorCallback);\r\n\t\t\tcallCallback(settings.callback_load, element);\r\n\t\t};\r\n\r\n\t\tcallCallback(settings.callback_enter, element);\r\n\t\tif ([\"IMG\", \"IFRAME\", \"VIDEO\"].indexOf(element.tagName) > -1) {\r\n\t\t\telement.addEventListener(\"load\", loadCallback);\r\n\t\t\telement.addEventListener(\"error\", errorCallback);\r\n\t\t\taddClass(element, settings.class_loading);\r\n\t\t}\r\n\t\tsetSources(element, settings);\r\n\t\tcallCallback(settings.callback_set, element);\r\n\t},\r\n\r\n\t_loopThroughElements: function(forceDownload) {\r\n\t\tconst settings = this._settings,\r\n\t\t\telements = this._elements,\r\n\t\t\telementsLength = !elements ? 0 : elements.length;\r\n\t\tlet i,\r\n\t\t\tprocessedIndexes = [],\r\n\t\t\tfirstLoop = this._isFirstLoop;\r\n\r\n\t\tfor (i = 0; i < elementsLength; i++) {\r\n\t\t\tlet element = elements[i];\r\n\t\t\t/* If must skip_invisible and element is invisible, skip it */\r\n\t\t\tif (settings.skip_invisible && element.offsetParent === null) {\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\r\n\t\t\tif (\r\n\t\t\t\tisBot ||\r\n\t\t\t\tforceDownload ||\r\n\t\t\t\tisInsideViewport(\r\n\t\t\t\t\telement,\r\n\t\t\t\t\tsettings.container,\r\n\t\t\t\t\tsettings.threshold\r\n\t\t\t\t)\r\n\t\t\t) {\r\n\t\t\t\tif (firstLoop) {\r\n\t\t\t\t\taddClass(element, settings.class_initial);\r\n\t\t\t\t}\r\n\t\t\t\t/* Start loading the image */\r\n\t\t\t\tthis.load(element);\r\n\t\t\t\t/* Marking the element as processed. */\r\n\t\t\t\tprocessedIndexes.push(i);\r\n\t\t\t\tsetWasProcessed(element);\r\n\t\t\t}\r\n\t\t}\r\n\t\t/* Removing processed elements from this._elements. */\r\n\t\twhile (processedIndexes.length) {\r\n\t\t\telements.splice(processedIndexes.pop(), 1);\r\n\t\t\tcallCallback(settings.callback_processed, elements.length);\r\n\t\t}\r\n\t\t/* Stop listening to scroll event when 0 elements remains */\r\n\t\tif (elementsLength === 0) {\r\n\t\t\tthis._stopScrollHandler();\r\n\t\t}\r\n\t\t/* Sets isFirstLoop to false */\r\n\t\tif (firstLoop) {\r\n\t\t\tthis._isFirstLoop = false;\r\n\t\t}\r\n\t},\r\n\r\n\t_purgeElements: function() {\r\n\t\tconst elements = this._elements,\r\n\t\t\telementsLength = elements.length;\r\n\t\tlet i,\r\n\t\t\telementsToPurge = [];\r\n\r\n\t\tfor (i = 0; i < elementsLength; i++) {\r\n\t\t\tlet element = elements[i];\r\n\t\t\t/* If the element has already been processed, skip it */\r\n\t\t\tif (getWasProcessed(element)) {\r\n\t\t\t\telementsToPurge.push(i);\r\n\t\t\t}\r\n\t\t}\r\n\t\t/* Removing elements to purge from this._elements. */\r\n\t\twhile (elementsToPurge.length > 0) {\r\n\t\t\telements.splice(elementsToPurge.pop(), 1);\r\n\t\t}\r\n\t},\r\n\r\n\t_startScrollHandler: function() {\r\n\t\tif (!this._isHandlingScroll) {\r\n\t\t\tthis._isHandlingScroll = true;\r\n\t\t\tthis._settings.container.addEventListener(\r\n\t\t\t\t\"scroll\",\r\n\t\t\t\tthis._boundHandleScroll\r\n\t\t\t);\r\n\t\t}\r\n\t},\r\n\r\n\t_stopScrollHandler: function() {\r\n\t\tif (this._isHandlingScroll) {\r\n\t\t\tthis._isHandlingScroll = false;\r\n\t\t\tthis._settings.container.removeEventListener(\r\n\t\t\t\t\"scroll\",\r\n\t\t\t\tthis._boundHandleScroll\r\n\t\t\t);\r\n\t\t}\r\n\t},\r\n\r\n\thandleScroll: function() {\r\n\t\tconst throttle = this._settings.throttle;\r\n\r\n\t\tif (throttle !== 0) {\r\n\t\t\tlet now = Date.now();\r\n\t\t\tlet remainingTime = throttle - (now - this._previousLoopTime);\r\n\t\t\tif (remainingTime <= 0 || remainingTime > throttle) {\r\n\t\t\t\tif (this._loopTimeout) {\r\n\t\t\t\t\tclearTimeout(this._loopTimeout);\r\n\t\t\t\t\tthis._loopTimeout = null;\r\n\t\t\t\t}\r\n\t\t\t\tthis._previousLoopTime = now;\r\n\t\t\t\tthis._loopThroughElements();\r\n\t\t\t} else if (!this._loopTimeout) {\r\n\t\t\t\tthis._loopTimeout = setTimeout(\r\n\t\t\t\t\tfunction() {\r\n\t\t\t\t\t\tthis._previousLoopTime = Date.now();\r\n\t\t\t\t\t\tthis._loopTimeout = null;\r\n\t\t\t\t\t\tthis._loopThroughElements();\r\n\t\t\t\t\t}.bind(this),\r\n\t\t\t\t\tremainingTime\r\n\t\t\t\t);\r\n\t\t\t}\r\n\t\t} else {\r\n\t\t\tthis._loopThroughElements();\r\n\t\t}\r\n\t},\r\n\r\n\tloadAll: function() {\r\n\t\tthis._loopThroughElements(true);\r\n\t},\r\n\r\n\tupdate: function() {\r\n\t\t// Converts to array the nodeset obtained querying the DOM from _queryOriginNode with elements_selector\r\n\t\tthis._elements = Array.prototype.slice.call(\r\n\t\t\tthis._queryOriginNode.querySelectorAll(\r\n\t\t\t\tthis._settings.elements_selector\r\n\t\t\t)\r\n\t\t);\r\n\t\tthis._purgeElements();\r\n\t\tthis._loopThroughElements();\r\n\t\tthis._startScrollHandler();\r\n\t},\r\n\r\n\tdestroy: function() {\r\n\t\twindow.removeEventListener(\"resize\", this._boundHandleScroll);\r\n\t\tif (this._loopTimeout) {\r\n\t\t\tclearTimeout(this._loopTimeout);\r\n\t\t\tthis._loopTimeout = null;\r\n\t\t}\r\n\t\tthis._stopScrollHandler();\r\n\t\tthis._elements = null;\r\n\t\tthis._queryOriginNode = null;\r\n\t\tthis._settings = null;\r\n\t},\r\n\r\n\tload: function(element, force) {\r\n\t\tthis._reveal(element, force);\r\n\t}\r\n};\r\n\r\n/* Automatic instances creation if required (useful for async script loading!) */\r\nlet autoInitOptions = window.lazyLoadOptions;\r\nif (runningOnBrowser && autoInitOptions) {\r\n\tautoInitialize(LazyLoad, autoInitOptions);\r\n}\n\nreturn LazyLoad;\n\n}());\n"]} \ No newline at end of file diff --git a/dist/lazyload.js b/dist/lazyload.js index e49fc428..9069ea48 100644 --- a/dist/lazyload.js +++ b/dist/lazyload.js @@ -172,10 +172,9 @@ var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol var runningOnBrowser = typeof window !== "undefined"; + var isBot = runningOnBrowser && !("onscroll" in window) || /(gle|ing|ro)bot|crawl|spider/i.test(navigator.userAgent); var supportsClassList = runningOnBrowser && "classList" in document.createElement("p"); - var isBot = runningOnBrowser && !("onscroll" in window) || /glebot|bingbot|crawler|spider|robot|crawling/i.test(navigator.userAgent); - var addClass = function addClass(element, className) { if (supportsClassList) { element.classList.add(className); diff --git a/dist/lazyload.min.js b/dist/lazyload.min.js index 576fa71a..4029f1b3 100644 --- a/dist/lazyload.min.js +++ b/dist/lazyload.min.js @@ -1 +1,2 @@ -var _extends=Object.assign||function(e){for(var t=1;t=o(e)+n+e.offsetHeight},p=function(e,t,n){return(t===window?window.pageXOffset:i(t))>=i(e)+n+e.offsetWidth};var s=function(e,t){var n,o="LazyLoad::Initialized",i=new e(t);try{n=new CustomEvent(o,{detail:{instance:i}})}catch(e){(n=document.createEvent("CustomEvent")).initCustomEvent(o,!1,!1,{instance:i})}window.dispatchEvent(n)};var r="data-",l="was-processed",a="true",u=function(e,t){return e.getAttribute(r+t)},m=function(e){return t=l,n=a,e.setAttribute(r+t,n);var t,n},c=function(e){return u(e,l)===a},g=function(e,t,n){for(var o,i=0;o=e.children[i];i+=1)if("SOURCE"===o.tagName){var s=u(o,n);s&&o.setAttribute(t,s)}},v=function(e,t,n){n&&e.setAttribute(t,n)};var e="undefined"!=typeof window,n=e&&"classList"in document.createElement("p"),w=e&&!("onscroll"in window)||/glebot|bingbot|crawler|spider|robot|crawling/i.test(navigator.userAgent),b=function(e,t){n?e.classList.add(t):e.className+=(e.className?" ":"")+t},y=function(e,t){n?e.classList.remove(t):e.className=e.className.replace(new RegExp("(^|\\s+)"+t+"(\\s+|$)")," ").replace(/^\s+/,"").replace(/\s+$/,"")},t=function(e){this._settings=_extends({},{elements_selector:"img",container:window,threshold:300,throttle:150,data_src:"src",data_srcset:"srcset",data_sizes:"sizes",class_loading:"loading",class_loaded:"loaded",class_error:"error",class_initial:"initial",skip_invisible:!0,callback_load:null,callback_error:null,callback_set:null,callback_processed:null,callback_enter:null},e),this._queryOriginNode=this._settings.container===window?document:this._settings.container,this._previousLoopTime=0,this._loopTimeout=null,this._boundHandleScroll=this.handleScroll.bind(this),this._isFirstLoop=!0,window.addEventListener("resize",this._boundHandleScroll),this.update()};t.prototype={_reveal:function(t,e){if(e||!c(t)){var n=this._settings,o=function e(){n&&(t.removeEventListener("load",i),t.removeEventListener("error",e),y(t,n.class_loading),b(t,n.class_error),d(n.callback_error,t))},i=function e(){n&&(y(t,n.class_loading),b(t,n.class_loaded),t.removeEventListener("load",e),t.removeEventListener("error",o),d(n.callback_load,t))};d(n.callback_enter,t),-1<["IMG","IFRAME","VIDEO"].indexOf(t.tagName)&&(t.addEventListener("load",i),t.addEventListener("error",o),b(t,n.class_loading)),function(e,t){var n=t.data_sizes,o=t.data_srcset,i=t.data_src,s=u(e,i),r=e.tagName;if("IMG"===r){var l=e.parentNode;l&&"PICTURE"===l.tagName&&g(l,"srcset",o);var a=u(e,n);v(e,"sizes",a);var c=u(e,o);return v(e,"srcset",c),v(e,"src",s)}if("IFRAME"!==r)return"VIDEO"===r?(g(e,"src",i),v(e,"src",s)):s&&(e.style.backgroundImage='url("'+s+'")');v(e,"src",s)}(t,n),d(n.callback_set,t)}},_loopThroughElements:function(e){var t,n,o,i=this._settings,s=this._elements,r=s?s.length:0,l=void 0,a=[],c=this._isFirstLoop;for(l=0;l=i(e)+n+e.offsetHeight},c=function(e,t,n){return(t===window?window.pageXOffset:r(t))>=r(e)+n+e.offsetWidth},u=function(e,t){var n,o=new e(t);try{n=new CustomEvent("LazyLoad::Initialized",{detail:{instance:o}})}catch(e){(n=document.createEvent("CustomEvent")).initCustomEvent("LazyLoad::Initialized",!1,!1,{instance:o})}window.dispatchEvent(n)},d=function(e,t){return e.getAttribute("data-"+t)},f=function(e,t,n){return e.setAttribute("data-"+t,n)},h=function(e){return f(e,"was-processed","true")},_=function(e){return"true"===d(e,"was-processed")},p=function(e,t,n){for(var o,i=0;o=e.children[i];i+=1)if("SOURCE"===o.tagName){var s=d(o,n);s&&o.setAttribute(t,s)}},m=function(e,t,n){n&&e.setAttribute(t,n)},g="undefined"!=typeof window,v=g&&!("onscroll"in window)||/(gle|ing|ro)bot|crawl|spider/i.test(navigator.userAgent),w=g&&"classList"in document.createElement("p"),b=function(e,t){w?e.classList.add(t):e.className+=(e.className?" ":"")+t},y=function(e,t){w?e.classList.remove(t):e.className=e.className.replace(new RegExp("(^|\\s+)"+t+"(\\s+|$)")," ").replace(/^\s+/,"").replace(/\s+$/,"")},E=function(e){this._settings=_extends({},n(),e),this._queryOriginNode=this._settings.container===window?document:this._settings.container,this._previousLoopTime=0,this._loopTimeout=null,this._boundHandleScroll=this.handleScroll.bind(this),this._isFirstLoop=!0,window.addEventListener("resize",this._boundHandleScroll),this.update()};E.prototype={_reveal:function(e,n){if(n||!_(e)){var i=this._settings,s=function t(){i&&(e.removeEventListener("load",r),e.removeEventListener("error",t),y(e,i.class_loading),b(e,i.class_error),o(i.callback_error,e))},r=function t(){i&&(y(e,i.class_loading),b(e,i.class_loaded),e.removeEventListener("load",t),e.removeEventListener("error",s),o(i.callback_load,e))};o(i.callback_enter,e),["IMG","IFRAME","VIDEO"].indexOf(e.tagName)>-1&&(e.addEventListener("load",r),e.addEventListener("error",s),b(e,i.class_loading)),t(e,i),o(i.callback_set,e)}},_loopThroughElements:function(t){var n=this._settings,i=this._elements,s=i?i.length:0,r=void 0,l=[],a=this._isFirstLoop;for(r=0;r0;)e.splice(o.pop(),1)},_startScrollHandler:function(){this._isHandlingScroll||(this._isHandlingScroll=!0,this._settings.container.addEventListener("scroll",this._boundHandleScroll))},_stopScrollHandler:function(){this._isHandlingScroll&&(this._isHandlingScroll=!1,this._settings.container.removeEventListener("scroll",this._boundHandleScroll))},handleScroll:function(){var e=this._settings.throttle;if(0!==e){var t=Date.now(),n=e-(t-this._previousLoopTime);n<=0||n>e?(this._loopTimeout&&(clearTimeout(this._loopTimeout),this._loopTimeout=null),this._previousLoopTime=t,this._loopThroughElements()):this._loopTimeout||(this._loopTimeout=setTimeout(function(){this._previousLoopTime=Date.now(),this._loopTimeout=null,this._loopThroughElements()}.bind(this),n))}else this._loopThroughElements()},loadAll:function(){this._loopThroughElements(!0)},update:function(){this._elements=Array.prototype.slice.call(this._queryOriginNode.querySelectorAll(this._settings.elements_selector)),this._purgeElements(),this._loopThroughElements(),this._startScrollHandler()},destroy:function(){window.removeEventListener("resize",this._boundHandleScroll),this._loopTimeout&&(clearTimeout(this._loopTimeout),this._loopTimeout=null),this._stopScrollHandler(),this._elements=null,this._queryOriginNode=null,this._settings=null},load:function(e,t){this._reveal(e,t)}};var L=window.lazyLoadOptions;return g&&L&&function(e,t){var n=t.length;if(n)for(var o=0;o ({\r\n\telements_selector: \"img\",\r\n\tcontainer: window,\r\n\tthreshold: 300,\r\n\tthrottle: 150,\r\n\tdata_src: \"src\",\r\n\tdata_srcset: \"srcset\",\r\n\tdata_sizes: \"sizes\",\r\n\tclass_loading: \"loading\",\r\n\tclass_loaded: \"loaded\",\r\n\tclass_error: \"error\",\r\n\tclass_initial: \"initial\",\r\n\tskip_invisible: true,\r\n\tcallback_load: null,\r\n\tcallback_error: null,\r\n\tcallback_set: null,\r\n\tcallback_processed: null,\r\n\tcallback_enter: null\r\n});\n\nconst callCallback = function(callback, argument) {\r\n\tif (callback) {\r\n\t\tcallback(argument);\r\n\t}\r\n};\n\nconst getTopOffset = function(element) {\r\n\treturn (\r\n\t\telement.getBoundingClientRect().top +\r\n\t\twindow.pageYOffset -\r\n\t\telement.ownerDocument.documentElement.clientTop\r\n\t);\r\n};\r\n\r\nconst isBelowViewport = function(element, container, threshold) {\r\n\tconst fold =\r\n\t\tcontainer === window\r\n\t\t\t? window.innerHeight + window.pageYOffset\r\n\t\t\t: getTopOffset(container) + container.offsetHeight;\r\n\treturn fold <= getTopOffset(element) - threshold;\r\n};\r\n\r\nconst getLeftOffset = function(element) {\r\n\treturn (\r\n\t\telement.getBoundingClientRect().left +\r\n\t\twindow.pageXOffset -\r\n\t\telement.ownerDocument.documentElement.clientLeft\r\n\t);\r\n};\r\n\r\nconst isAtRightOfViewport = function(element, container, threshold) {\r\n\tconst documentWidth = window.innerWidth;\r\n\tconst fold =\r\n\t\tcontainer === window\r\n\t\t\t? documentWidth + window.pageXOffset\r\n\t\t\t: getLeftOffset(container) + documentWidth;\r\n\treturn fold <= getLeftOffset(element) - threshold;\r\n};\r\n\r\nconst isAboveViewport = function(element, container, threshold) {\r\n\tconst fold =\r\n\t\tcontainer === window ? window.pageYOffset : getTopOffset(container);\r\n\treturn fold >= getTopOffset(element) + threshold + element.offsetHeight;\r\n};\r\n\r\nconst isAtLeftOfViewport = function(element, container, threshold) {\r\n\tconst fold =\r\n\t\tcontainer === window ? window.pageXOffset : getLeftOffset(container);\r\n\treturn fold >= getLeftOffset(element) + threshold + element.offsetWidth;\r\n};\r\n\r\nfunction isInsideViewport(element, container, threshold) {\r\n\treturn (\r\n\t\t!isBelowViewport(element, container, threshold) &&\r\n\t\t!isAboveViewport(element, container, threshold) &&\r\n\t\t!isAtRightOfViewport(element, container, threshold) &&\r\n\t\t!isAtLeftOfViewport(element, container, threshold)\r\n\t);\r\n}\n\n/* Creates instance and notifies it through the window element */\r\nconst createInstance = function (classObj, options) { \r\n var event;\r\n let eventString = \"LazyLoad::Initialized\";\r\n let instance = new classObj(options);\r\n try {\r\n // Works in modern browsers\r\n event = new CustomEvent(eventString, { detail: { instance } });\r\n } \r\n catch(err) {\r\n // Works in Internet Explorer (all versions)\r\n event = document.createEvent(\"CustomEvent\");\r\n event.initCustomEvent(eventString, false, false, { instance });\r\n }\r\n window.dispatchEvent(event);\r\n};\r\n\r\n/* Auto initialization of one or more instances of lazyload, depending on the \r\n options passed in (plain object or an array) */\r\nfunction autoInitialize (classObj, options) { \r\n let optsLength = options.length;\r\n if (!optsLength) {\r\n // Plain object\r\n createInstance(classObj, options);\r\n }\r\n else {\r\n // Array of objects\r\n for (let i = 0; i < optsLength; i++) {\r\n createInstance(classObj, options[i]);\r\n }\r\n }\r\n}\n\nconst dataPrefix = \"data-\";\r\nconst processedDataName = \"was-processed\";\r\nconst processedDataValue = \"true\";\r\n\r\nconst getData = (element, attribute) => {\r\n\treturn element.getAttribute(dataPrefix + attribute);\r\n};\r\n\r\nconst setData = (element, attribute, value) => {\r\n\treturn element.setAttribute(dataPrefix + attribute, value);\r\n};\r\n\r\nconst setWasProcessed = element =>\r\n\tsetData(element, processedDataName, processedDataValue);\r\n\r\nconst getWasProcessed = element =>\r\n\tgetData(element, processedDataName) === processedDataValue;\n\nconst setSourcesInChildren = function(parentTag, attrName, dataAttrName) {\r\n\tfor (let i = 0, childTag; (childTag = parentTag.children[i]); i += 1) {\r\n\t\tif (childTag.tagName === \"SOURCE\") {\r\n\t\t\tlet attributeValue = getData(childTag, dataAttrName);\r\n\t\t\tif (attributeValue) {\r\n\t\t\t\tchildTag.setAttribute(attrName, attributeValue);\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n};\r\n\r\nconst setAttributeIfNotNullOrEmpty = function(element, attrName, value) {\r\n\tif (!value) {\r\n\t\treturn;\r\n\t}\r\n\telement.setAttribute(attrName, value);\r\n};\r\n\r\nfunction setSources(element, settings) {\r\n\tconst {\r\n\t\tdata_sizes: sizesDataName,\r\n\t\tdata_srcset: srcsetDataName,\r\n\t\tdata_src: srcDataName\r\n\t} = settings;\r\n\tconst srcDataValue = getData(element, srcDataName);\r\n\tconst tagName = element.tagName;\r\n\tif (tagName === \"IMG\") {\r\n\t\tconst parent = element.parentNode;\r\n\t\tif (parent && parent.tagName === \"PICTURE\") {\r\n\t\t\tsetSourcesInChildren(parent, \"srcset\", srcsetDataName);\r\n\t\t}\r\n\t\tconst sizesDataValue = getData(element, sizesDataName);\r\n\t\tsetAttributeIfNotNullOrEmpty(element, \"sizes\", sizesDataValue);\r\n\t\tconst srcsetDataValue = getData(element, srcsetDataName);\r\n\t\tsetAttributeIfNotNullOrEmpty(element, \"srcset\", srcsetDataValue);\r\n\t\tsetAttributeIfNotNullOrEmpty(element, \"src\", srcDataValue);\r\n\t\treturn;\r\n\t}\r\n\tif (tagName === \"IFRAME\") {\r\n\t\tsetAttributeIfNotNullOrEmpty(element, \"src\", srcDataValue);\r\n\t\treturn;\r\n\t}\r\n\tif (tagName === \"VIDEO\") {\r\n\t\tsetSourcesInChildren(element, \"src\", srcDataName);\r\n\t\tsetAttributeIfNotNullOrEmpty(element, \"src\", srcDataValue);\r\n\t\treturn;\r\n\t}\r\n\tif (srcDataValue) {\r\n\t\telement.style.backgroundImage = `url(\"${srcDataValue}\")`;\r\n\t}\r\n}\n\nconst runningOnBrowser = typeof window !== \"undefined\";\r\n\r\nconst isBot =\r\n\t(runningOnBrowser && !(\"onscroll\" in window)) ||\r\n\t/(gle|ing|ro)bot|crawl|spider/i.test(navigator.userAgent);\r\nconst supportsClassList =\r\n\trunningOnBrowser && \"classList\" in document.createElement(\"p\");\n\nconst addClass = (element, className) => {\r\n if (supportsClassList) {\r\n element.classList.add(className);\r\n return;\r\n }\r\n element.className += (element.className ? \" \" : \"\") + className;\r\n};\r\n\r\nconst removeClass = (element, className) => {\r\n if (supportsClassList) {\r\n element.classList.remove(className);\r\n return;\r\n }\r\n element.className = element.className.replace(new RegExp(\"(^|\\\\s+)\" + className + \"(\\\\s+|$)\"), \" \").replace(/^\\s+/, \"\").replace(/\\s+$/, \"\");\r\n};\n\n/*\r\n * Constructor\r\n */\r\n\r\nconst LazyLoad = function(instanceSettings) {\r\n\tthis._settings = Object.assign({}, getDefaultSettings(), instanceSettings);\r\n\tthis._queryOriginNode =\r\n\t\tthis._settings.container === window\r\n\t\t\t? document\r\n\t\t\t: this._settings.container;\r\n\r\n\tthis._previousLoopTime = 0;\r\n\tthis._loopTimeout = null;\r\n\tthis._boundHandleScroll = this.handleScroll.bind(this);\r\n\r\n\tthis._isFirstLoop = true;\r\n\twindow.addEventListener(\"resize\", this._boundHandleScroll);\r\n\tthis.update();\r\n};\r\n\r\nLazyLoad.prototype = {\r\n\t_reveal: function(element, force) {\r\n\t\tif (!force && getWasProcessed(element)) {\r\n\t\t\treturn; // element has already been processed and force wasn't true\r\n\t\t}\r\n\r\n\t\tconst settings = this._settings;\r\n\r\n\t\tconst errorCallback = function() {\r\n\t\t\t/* As this method is asynchronous, it must be protected against external destroy() calls */\r\n\t\t\tif (!settings) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\telement.removeEventListener(\"load\", loadCallback);\r\n\t\t\telement.removeEventListener(\"error\", errorCallback);\r\n\t\t\tremoveClass(element, settings.class_loading);\r\n\t\t\taddClass(element, settings.class_error);\r\n\t\t\tcallCallback(settings.callback_error, element);\r\n\t\t};\r\n\r\n\t\tconst loadCallback = function() {\r\n\t\t\t/* As this method is asynchronous, it must be protected against external destroy() calls */\r\n\t\t\tif (!settings) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\tremoveClass(element, settings.class_loading);\r\n\t\t\taddClass(element, settings.class_loaded);\r\n\t\t\telement.removeEventListener(\"load\", loadCallback);\r\n\t\t\telement.removeEventListener(\"error\", errorCallback);\r\n\t\t\tcallCallback(settings.callback_load, element);\r\n\t\t};\r\n\r\n\t\tcallCallback(settings.callback_enter, element);\r\n\t\tif ([\"IMG\", \"IFRAME\", \"VIDEO\"].indexOf(element.tagName) > -1) {\r\n\t\t\telement.addEventListener(\"load\", loadCallback);\r\n\t\t\telement.addEventListener(\"error\", errorCallback);\r\n\t\t\taddClass(element, settings.class_loading);\r\n\t\t}\r\n\t\tsetSources(element, settings);\r\n\t\tcallCallback(settings.callback_set, element);\r\n\t},\r\n\r\n\t_loopThroughElements: function(forceDownload) {\r\n\t\tconst settings = this._settings,\r\n\t\t\telements = this._elements,\r\n\t\t\telementsLength = !elements ? 0 : elements.length;\r\n\t\tlet i,\r\n\t\t\tprocessedIndexes = [],\r\n\t\t\tfirstLoop = this._isFirstLoop;\r\n\r\n\t\tfor (i = 0; i < elementsLength; i++) {\r\n\t\t\tlet element = elements[i];\r\n\t\t\t/* If must skip_invisible and element is invisible, skip it */\r\n\t\t\tif (settings.skip_invisible && element.offsetParent === null) {\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\r\n\t\t\tif (\r\n\t\t\t\tisBot ||\r\n\t\t\t\tforceDownload ||\r\n\t\t\t\tisInsideViewport(\r\n\t\t\t\t\telement,\r\n\t\t\t\t\tsettings.container,\r\n\t\t\t\t\tsettings.threshold\r\n\t\t\t\t)\r\n\t\t\t) {\r\n\t\t\t\tif (firstLoop) {\r\n\t\t\t\t\taddClass(element, settings.class_initial);\r\n\t\t\t\t}\r\n\t\t\t\t/* Start loading the image */\r\n\t\t\t\tthis.load(element);\r\n\t\t\t\t/* Marking the element as processed. */\r\n\t\t\t\tprocessedIndexes.push(i);\r\n\t\t\t\tsetWasProcessed(element);\r\n\t\t\t}\r\n\t\t}\r\n\t\t/* Removing processed elements from this._elements. */\r\n\t\twhile (processedIndexes.length) {\r\n\t\t\telements.splice(processedIndexes.pop(), 1);\r\n\t\t\tcallCallback(settings.callback_processed, elements.length);\r\n\t\t}\r\n\t\t/* Stop listening to scroll event when 0 elements remains */\r\n\t\tif (elementsLength === 0) {\r\n\t\t\tthis._stopScrollHandler();\r\n\t\t}\r\n\t\t/* Sets isFirstLoop to false */\r\n\t\tif (firstLoop) {\r\n\t\t\tthis._isFirstLoop = false;\r\n\t\t}\r\n\t},\r\n\r\n\t_purgeElements: function() {\r\n\t\tconst elements = this._elements,\r\n\t\t\telementsLength = elements.length;\r\n\t\tlet i,\r\n\t\t\telementsToPurge = [];\r\n\r\n\t\tfor (i = 0; i < elementsLength; i++) {\r\n\t\t\tlet element = elements[i];\r\n\t\t\t/* If the element has already been processed, skip it */\r\n\t\t\tif (getWasProcessed(element)) {\r\n\t\t\t\telementsToPurge.push(i);\r\n\t\t\t}\r\n\t\t}\r\n\t\t/* Removing elements to purge from this._elements. */\r\n\t\twhile (elementsToPurge.length > 0) {\r\n\t\t\telements.splice(elementsToPurge.pop(), 1);\r\n\t\t}\r\n\t},\r\n\r\n\t_startScrollHandler: function() {\r\n\t\tif (!this._isHandlingScroll) {\r\n\t\t\tthis._isHandlingScroll = true;\r\n\t\t\tthis._settings.container.addEventListener(\r\n\t\t\t\t\"scroll\",\r\n\t\t\t\tthis._boundHandleScroll\r\n\t\t\t);\r\n\t\t}\r\n\t},\r\n\r\n\t_stopScrollHandler: function() {\r\n\t\tif (this._isHandlingScroll) {\r\n\t\t\tthis._isHandlingScroll = false;\r\n\t\t\tthis._settings.container.removeEventListener(\r\n\t\t\t\t\"scroll\",\r\n\t\t\t\tthis._boundHandleScroll\r\n\t\t\t);\r\n\t\t}\r\n\t},\r\n\r\n\thandleScroll: function() {\r\n\t\tconst throttle = this._settings.throttle;\r\n\r\n\t\tif (throttle !== 0) {\r\n\t\t\tlet now = Date.now();\r\n\t\t\tlet remainingTime = throttle - (now - this._previousLoopTime);\r\n\t\t\tif (remainingTime <= 0 || remainingTime > throttle) {\r\n\t\t\t\tif (this._loopTimeout) {\r\n\t\t\t\t\tclearTimeout(this._loopTimeout);\r\n\t\t\t\t\tthis._loopTimeout = null;\r\n\t\t\t\t}\r\n\t\t\t\tthis._previousLoopTime = now;\r\n\t\t\t\tthis._loopThroughElements();\r\n\t\t\t} else if (!this._loopTimeout) {\r\n\t\t\t\tthis._loopTimeout = setTimeout(\r\n\t\t\t\t\tfunction() {\r\n\t\t\t\t\t\tthis._previousLoopTime = Date.now();\r\n\t\t\t\t\t\tthis._loopTimeout = null;\r\n\t\t\t\t\t\tthis._loopThroughElements();\r\n\t\t\t\t\t}.bind(this),\r\n\t\t\t\t\tremainingTime\r\n\t\t\t\t);\r\n\t\t\t}\r\n\t\t} else {\r\n\t\t\tthis._loopThroughElements();\r\n\t\t}\r\n\t},\r\n\r\n\tloadAll: function() {\r\n\t\tthis._loopThroughElements(true);\r\n\t},\r\n\r\n\tupdate: function() {\r\n\t\t// Converts to array the nodeset obtained querying the DOM from _queryOriginNode with elements_selector\r\n\t\tthis._elements = Array.prototype.slice.call(\r\n\t\t\tthis._queryOriginNode.querySelectorAll(\r\n\t\t\t\tthis._settings.elements_selector\r\n\t\t\t)\r\n\t\t);\r\n\t\tthis._purgeElements();\r\n\t\tthis._loopThroughElements();\r\n\t\tthis._startScrollHandler();\r\n\t},\r\n\r\n\tdestroy: function() {\r\n\t\twindow.removeEventListener(\"resize\", this._boundHandleScroll);\r\n\t\tif (this._loopTimeout) {\r\n\t\t\tclearTimeout(this._loopTimeout);\r\n\t\t\tthis._loopTimeout = null;\r\n\t\t}\r\n\t\tthis._stopScrollHandler();\r\n\t\tthis._elements = null;\r\n\t\tthis._queryOriginNode = null;\r\n\t\tthis._settings = null;\r\n\t},\r\n\r\n\tload: function(element, force) {\r\n\t\tthis._reveal(element, force);\r\n\t}\r\n};\r\n\r\n/* Automatic instances creation if required (useful for async script loading!) */\r\nlet autoInitOptions = window.lazyLoadOptions;\r\nif (runningOnBrowser && autoInitOptions) {\r\n\tautoInitialize(LazyLoad, autoInitOptions);\r\n}\n\nreturn LazyLoad;\n\n})));\n"]} \ No newline at end of file