UNPKG

24.9 kBJavaScriptView Raw
1(function (global, factory) {
2 typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
3 typeof define === 'function' && define.amd ? define(factory) :
4 (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.LazyLoad = factory());
5})(this, (function () { 'use strict';
6
7 const runningOnBrowser = typeof window !== "undefined";
8 const isBot = runningOnBrowser && !("onscroll" in window) || typeof navigator !== "undefined" && /(gle|ing|ro)bot|crawl|spider/i.test(navigator.userAgent);
9 const isHiDpi = runningOnBrowser && window.devicePixelRatio > 1;
10
11 const defaultSettings = {
12 elements_selector: ".lazy",
13 container: isBot || runningOnBrowser ? document : null,
14 threshold: 300,
15 thresholds: null,
16 data_src: "src",
17 data_srcset: "srcset",
18 data_sizes: "sizes",
19 data_bg: "bg",
20 data_bg_hidpi: "bg-hidpi",
21 data_bg_multi: "bg-multi",
22 data_bg_multi_hidpi: "bg-multi-hidpi",
23 data_bg_set: "bg-set",
24 data_poster: "poster",
25 class_applied: "applied",
26 class_loading: "loading",
27 class_loaded: "loaded",
28 class_error: "error",
29 class_entered: "entered",
30 class_exited: "exited",
31 unobserve_completed: true,
32 unobserve_entered: false,
33 cancel_on_exit: true,
34 callback_enter: null,
35 callback_exit: null,
36 callback_applied: null,
37 callback_loading: null,
38 callback_loaded: null,
39 callback_error: null,
40 callback_finish: null,
41 callback_cancel: null,
42 use_native: false,
43 restore_on_error: false
44 };
45 const getExtendedSettings = customSettings => {
46 return Object.assign({}, defaultSettings, customSettings);
47 };
48
49 /* Creates instance and notifies it through the window element */
50 const createInstance = function (classObj, options) {
51 let event;
52 const eventString = "LazyLoad::Initialized";
53 const instance = new classObj(options);
54 try {
55 // Works in modern browsers
56 event = new CustomEvent(eventString, {
57 detail: {
58 instance
59 }
60 });
61 } catch (err) {
62 // Works in Internet Explorer (all versions)
63 event = document.createEvent("CustomEvent");
64 event.initCustomEvent(eventString, false, false, {
65 instance
66 });
67 }
68 window.dispatchEvent(event);
69 };
70
71 /* Auto initialization of one or more instances of LazyLoad, depending on the
72 options passed in (plain object or an array) */
73 const autoInitialize = (classObj, options) => {
74 if (!options) {
75 return;
76 }
77 if (!options.length) {
78 // Plain object
79 createInstance(classObj, options);
80 } else {
81 // Array of objects
82 for (let i = 0, optionsItem; optionsItem = options[i]; i += 1) {
83 createInstance(classObj, optionsItem);
84 }
85 }
86 };
87
88 const SRC = "src";
89 const SRCSET = "srcset";
90 const SIZES = "sizes";
91 const POSTER = "poster";
92 const ORIGINALS = "llOriginalAttrs";
93 const DATA = "data";
94
95 const statusLoading = "loading";
96 const statusLoaded = "loaded";
97 const statusApplied = "applied";
98 const statusEntered = "entered";
99 const statusError = "error";
100 const statusNative = "native";
101
102 const dataPrefix = "data-";
103 const statusDataName = "ll-status";
104 const getData = (element, attribute) => {
105 return element.getAttribute(dataPrefix + attribute);
106 };
107 const setData = (element, attribute, value) => {
108 const attrName = dataPrefix + attribute;
109 if (value === null) {
110 element.removeAttribute(attrName);
111 return;
112 }
113 element.setAttribute(attrName, value);
114 };
115 const getStatus = element => getData(element, statusDataName);
116 const setStatus = (element, status) => setData(element, statusDataName, status);
117 const resetStatus = element => setStatus(element, null);
118 const hasEmptyStatus = element => getStatus(element) === null;
119 const hasStatusLoading = element => getStatus(element) === statusLoading;
120 const hasStatusError = element => getStatus(element) === statusError;
121 const hasStatusNative = element => getStatus(element) === statusNative;
122 const statusesAfterLoading = [statusLoading, statusLoaded, statusApplied, statusError];
123 const hadStartedLoading = element => statusesAfterLoading.indexOf(getStatus(element)) >= 0;
124
125 const safeCallback = (callback, arg1, arg2, arg3) => {
126 if (!callback || typeof callback !== 'function') {
127 return;
128 }
129 if (arg3 !== undefined) {
130 callback(arg1, arg2, arg3);
131 return;
132 }
133 if (arg2 !== undefined) {
134 callback(arg1, arg2);
135 return;
136 }
137 callback(arg1);
138 };
139
140 const addClass = (element, className) => {
141 if (!runningOnBrowser) {
142 return;
143 }
144 if (className === "") {
145 return;
146 }
147 element.classList.add(className);
148 };
149 const removeClass = (element, className) => {
150 if (!runningOnBrowser) {
151 return;
152 }
153 if (className === "") {
154 return;
155 }
156 element.classList.remove(className);
157 };
158
159 const addTempImage = element => {
160 element.llTempImage = document.createElement("IMG");
161 };
162 const deleteTempImage = element => {
163 delete element.llTempImage;
164 };
165 const getTempImage = element => element.llTempImage;
166
167 const unobserve = (element, instance) => {
168 if (!instance) return;
169 const observer = instance._observer;
170 if (!observer) return;
171 observer.unobserve(element);
172 };
173 const resetObserver = observer => {
174 observer.disconnect();
175 };
176 const unobserveEntered = (element, settings, instance) => {
177 if (settings.unobserve_entered) unobserve(element, instance);
178 };
179
180 const updateLoadingCount = (instance, delta) => {
181 if (!instance) return;
182 instance.loadingCount += delta;
183 };
184 const decreaseToLoadCount = instance => {
185 if (!instance) return;
186 instance.toLoadCount -= 1;
187 };
188 const setToLoadCount = (instance, value) => {
189 if (!instance) return;
190 instance.toLoadCount = value;
191 };
192 const isSomethingLoading = instance => instance.loadingCount > 0;
193 const haveElementsToLoad = instance => instance.toLoadCount > 0;
194
195 const getSourceTags = parentTag => {
196 let sourceTags = [];
197 for (let i = 0, childTag; childTag = parentTag.children[i]; i += 1) {
198 if (childTag.tagName === "SOURCE") {
199 sourceTags.push(childTag);
200 }
201 }
202 return sourceTags;
203 };
204 const forEachPictureSource = (element, fn) => {
205 const parent = element.parentNode;
206 if (!parent || parent.tagName !== "PICTURE") {
207 return;
208 }
209 let sourceTags = getSourceTags(parent);
210 sourceTags.forEach(fn);
211 };
212 const forEachVideoSource = (element, fn) => {
213 let sourceTags = getSourceTags(element);
214 sourceTags.forEach(fn);
215 };
216
217 const attrsSrc = [SRC];
218 const attrsSrcPoster = [SRC, POSTER];
219 const attrsSrcSrcsetSizes = [SRC, SRCSET, SIZES];
220 const attrsData = [DATA];
221 const hasOriginalAttrs = element => !!element[ORIGINALS];
222 const getOriginalAttrs = element => element[ORIGINALS];
223 const deleteOriginalAttrs = element => delete element[ORIGINALS];
224
225 // ## SAVE ##
226
227 const setOriginalsObject = (element, attributes) => {
228 if (hasOriginalAttrs(element)) {
229 return;
230 }
231 const originals = {};
232 attributes.forEach(attribute => {
233 originals[attribute] = element.getAttribute(attribute);
234 });
235 element[ORIGINALS] = originals;
236 };
237 const saveOriginalBackgroundStyle = element => {
238 if (hasOriginalAttrs(element)) {
239 return;
240 }
241 element[ORIGINALS] = {
242 backgroundImage: element.style.backgroundImage
243 };
244 };
245
246 // ## RESTORE ##
247
248 const setOrResetAttribute = (element, attrName, value) => {
249 if (!value) {
250 element.removeAttribute(attrName);
251 return;
252 }
253 element.setAttribute(attrName, value);
254 };
255 const restoreOriginalAttrs = (element, attributes) => {
256 if (!hasOriginalAttrs(element)) {
257 return;
258 }
259 const originals = getOriginalAttrs(element);
260 attributes.forEach(attribute => {
261 setOrResetAttribute(element, attribute, originals[attribute]);
262 });
263 };
264 const restoreOriginalBgImage = element => {
265 if (!hasOriginalAttrs(element)) {
266 return;
267 }
268 const originals = getOriginalAttrs(element);
269 element.style.backgroundImage = originals.backgroundImage;
270 };
271
272 const manageApplied = (element, settings, instance) => {
273 addClass(element, settings.class_applied);
274 setStatus(element, statusApplied);
275 // Instance is not provided when loading is called from static class
276 if (!instance) return;
277 if (settings.unobserve_completed) {
278 // Unobserve now because we can't do it on load
279 unobserve(element, settings);
280 }
281 safeCallback(settings.callback_applied, element, instance);
282 };
283 const manageLoading = (element, settings, instance) => {
284 addClass(element, settings.class_loading);
285 setStatus(element, statusLoading);
286 // Instance is not provided when loading is called from static class
287 if (!instance) return;
288 updateLoadingCount(instance, +1);
289 safeCallback(settings.callback_loading, element, instance);
290 };
291 const setAttributeIfValue = (element, attrName, value) => {
292 if (!value) {
293 return;
294 }
295 element.setAttribute(attrName, value);
296 };
297 const setImageAttributes = (element, settings) => {
298 setAttributeIfValue(element, SIZES, getData(element, settings.data_sizes));
299 setAttributeIfValue(element, SRCSET, getData(element, settings.data_srcset));
300 setAttributeIfValue(element, SRC, getData(element, settings.data_src));
301 };
302 const setSourcesImg = (imgEl, settings) => {
303 forEachPictureSource(imgEl, sourceTag => {
304 setOriginalsObject(sourceTag, attrsSrcSrcsetSizes);
305 setImageAttributes(sourceTag, settings);
306 });
307 setOriginalsObject(imgEl, attrsSrcSrcsetSizes);
308 setImageAttributes(imgEl, settings);
309 };
310 const setSourcesIframe = (iframe, settings) => {
311 setOriginalsObject(iframe, attrsSrc);
312 setAttributeIfValue(iframe, SRC, getData(iframe, settings.data_src));
313 };
314 const setSourcesVideo = (videoEl, settings) => {
315 forEachVideoSource(videoEl, sourceEl => {
316 setOriginalsObject(sourceEl, attrsSrc);
317 setAttributeIfValue(sourceEl, SRC, getData(sourceEl, settings.data_src));
318 });
319 setOriginalsObject(videoEl, attrsSrcPoster);
320 setAttributeIfValue(videoEl, POSTER, getData(videoEl, settings.data_poster));
321 setAttributeIfValue(videoEl, SRC, getData(videoEl, settings.data_src));
322 videoEl.load();
323 };
324 const setSourcesObject = (object, settings) => {
325 setOriginalsObject(object, attrsData);
326 setAttributeIfValue(object, DATA, getData(object, settings.data_src));
327 };
328 const setBackground = (element, settings, instance) => {
329 const bg1xValue = getData(element, settings.data_bg);
330 const bgHiDpiValue = getData(element, settings.data_bg_hidpi);
331 const bgDataValue = isHiDpi && bgHiDpiValue ? bgHiDpiValue : bg1xValue;
332 if (!bgDataValue) return;
333 element.style.backgroundImage = `url("${bgDataValue}")`;
334 getTempImage(element).setAttribute(SRC, bgDataValue);
335 manageLoading(element, settings, instance);
336 };
337
338 // NOTE: THE TEMP IMAGE TRICK CANNOT BE DONE WITH data-multi-bg
339 // BECAUSE INSIDE ITS VALUES MUST BE WRAPPED WITH URL() AND ONE OF THEM
340 // COULD BE A GRADIENT BACKGROUND IMAGE
341 const setMultiBackground = (element, settings, instance) => {
342 const bg1xValue = getData(element, settings.data_bg_multi);
343 const bgHiDpiValue = getData(element, settings.data_bg_multi_hidpi);
344 const bgDataValue = isHiDpi && bgHiDpiValue ? bgHiDpiValue : bg1xValue;
345 if (!bgDataValue) {
346 return;
347 }
348 element.style.backgroundImage = bgDataValue;
349 manageApplied(element, settings, instance);
350 };
351 const setImgsetBackground = (element, settings, instance) => {
352 const bgImgSetDataValue = getData(element, settings.data_bg_set);
353 if (!bgImgSetDataValue) {
354 return;
355 }
356 const imgSetValues = bgImgSetDataValue.split("|");
357 let bgImageValues = imgSetValues.map(value => `image-set(${value})`);
358 element.style.backgroundImage = bgImageValues.join();
359 manageApplied(element, settings, instance);
360 };
361 const setSourcesFunctions = {
362 IMG: setSourcesImg,
363 IFRAME: setSourcesIframe,
364 VIDEO: setSourcesVideo,
365 OBJECT: setSourcesObject
366 };
367 const setSourcesNative = (element, settings) => {
368 const setSourcesFunction = setSourcesFunctions[element.tagName];
369 if (!setSourcesFunction) {
370 return;
371 }
372 setSourcesFunction(element, settings);
373 };
374 const setSources = (element, settings, instance) => {
375 const setSourcesFunction = setSourcesFunctions[element.tagName];
376 if (!setSourcesFunction) {
377 return;
378 }
379 setSourcesFunction(element, settings);
380 manageLoading(element, settings, instance);
381 };
382
383 const elementsWithLoadEvent = ["IMG", "IFRAME", "VIDEO", "OBJECT"];
384 const hasLoadEvent = element => elementsWithLoadEvent.indexOf(element.tagName) > -1;
385 const checkFinish = (settings, instance) => {
386 if (instance && !isSomethingLoading(instance) && !haveElementsToLoad(instance)) {
387 safeCallback(settings.callback_finish, instance);
388 }
389 };
390 const addEventListener = (element, eventName, handler) => {
391 element.addEventListener(eventName, handler);
392 element.llEvLisnrs[eventName] = handler;
393 };
394 const removeEventListener = (element, eventName, handler) => {
395 element.removeEventListener(eventName, handler);
396 };
397 const hasEventListeners = element => {
398 return !!element.llEvLisnrs;
399 };
400 const addEventListeners = (element, loadHandler, errorHandler) => {
401 if (!hasEventListeners(element)) element.llEvLisnrs = {};
402 const loadEventName = element.tagName === "VIDEO" ? "loadeddata" : "load";
403 addEventListener(element, loadEventName, loadHandler);
404 addEventListener(element, "error", errorHandler);
405 };
406 const removeEventListeners = element => {
407 if (!hasEventListeners(element)) {
408 return;
409 }
410 const eventListeners = element.llEvLisnrs;
411 for (let eventName in eventListeners) {
412 const handler = eventListeners[eventName];
413 removeEventListener(element, eventName, handler);
414 }
415 delete element.llEvLisnrs;
416 };
417 const doneHandler = (element, settings, instance) => {
418 deleteTempImage(element);
419 updateLoadingCount(instance, -1);
420 decreaseToLoadCount(instance);
421 removeClass(element, settings.class_loading);
422 if (settings.unobserve_completed) {
423 unobserve(element, instance);
424 }
425 };
426 const loadHandler = (event, element, settings, instance) => {
427 const goingNative = hasStatusNative(element);
428 doneHandler(element, settings, instance);
429 addClass(element, settings.class_loaded);
430 setStatus(element, statusLoaded);
431 safeCallback(settings.callback_loaded, element, instance);
432 if (!goingNative) checkFinish(settings, instance);
433 };
434 const errorHandler = (event, element, settings, instance) => {
435 const goingNative = hasStatusNative(element);
436 doneHandler(element, settings, instance);
437 addClass(element, settings.class_error);
438 setStatus(element, statusError);
439 safeCallback(settings.callback_error, element, instance);
440 if (settings.restore_on_error) restoreOriginalAttrs(element, attrsSrcSrcsetSizes);
441 if (!goingNative) checkFinish(settings, instance);
442 };
443 const addOneShotEventListeners = (element, settings, instance) => {
444 const elementToListenTo = getTempImage(element) || element;
445 if (hasEventListeners(elementToListenTo)) {
446 // This happens when loading is retried twice
447 return;
448 }
449 const _loadHandler = event => {
450 loadHandler(event, element, settings, instance);
451 removeEventListeners(elementToListenTo);
452 };
453 const _errorHandler = event => {
454 errorHandler(event, element, settings, instance);
455 removeEventListeners(elementToListenTo);
456 };
457 addEventListeners(elementToListenTo, _loadHandler, _errorHandler);
458 };
459
460 const loadBackground = (element, settings, instance) => {
461 addTempImage(element);
462 addOneShotEventListeners(element, settings, instance);
463 saveOriginalBackgroundStyle(element);
464 setBackground(element, settings, instance);
465 setMultiBackground(element, settings, instance);
466 setImgsetBackground(element, settings, instance);
467 };
468 const loadRegular = (element, settings, instance) => {
469 addOneShotEventListeners(element, settings, instance);
470 setSources(element, settings, instance);
471 };
472 const load = (element, settings, instance) => {
473 if (hasLoadEvent(element)) {
474 loadRegular(element, settings, instance);
475 } else {
476 loadBackground(element, settings, instance);
477 }
478 };
479 const loadNative = (element, settings, instance) => {
480 element.setAttribute("loading", "lazy");
481 addOneShotEventListeners(element, settings, instance);
482 setSourcesNative(element, settings);
483 setStatus(element, statusNative);
484 };
485
486 const removeImageAttributes = element => {
487 element.removeAttribute(SRC);
488 element.removeAttribute(SRCSET);
489 element.removeAttribute(SIZES);
490 };
491 const resetSourcesImg = element => {
492 forEachPictureSource(element, sourceTag => {
493 removeImageAttributes(sourceTag);
494 });
495 removeImageAttributes(element);
496 };
497
498 const restoreImg = imgEl => {
499 forEachPictureSource(imgEl, sourceEl => {
500 restoreOriginalAttrs(sourceEl, attrsSrcSrcsetSizes);
501 });
502 restoreOriginalAttrs(imgEl, attrsSrcSrcsetSizes);
503 };
504 const restoreVideo = videoEl => {
505 forEachVideoSource(videoEl, sourceEl => {
506 restoreOriginalAttrs(sourceEl, attrsSrc);
507 });
508 restoreOriginalAttrs(videoEl, attrsSrcPoster);
509 videoEl.load();
510 };
511 const restoreIframe = iframeEl => {
512 restoreOriginalAttrs(iframeEl, attrsSrc);
513 };
514 const restoreObject = objectEl => {
515 restoreOriginalAttrs(objectEl, attrsData);
516 };
517 const restoreFunctions = {
518 IMG: restoreImg,
519 IFRAME: restoreIframe,
520 VIDEO: restoreVideo,
521 OBJECT: restoreObject
522 };
523 const restoreAttributes = element => {
524 const restoreFunction = restoreFunctions[element.tagName];
525 if (!restoreFunction) {
526 restoreOriginalBgImage(element);
527 return;
528 }
529 restoreFunction(element);
530 };
531 const resetClasses = (element, settings) => {
532 if (hasEmptyStatus(element) || hasStatusNative(element)) {
533 return;
534 }
535 removeClass(element, settings.class_entered);
536 removeClass(element, settings.class_exited);
537 removeClass(element, settings.class_applied);
538 removeClass(element, settings.class_loading);
539 removeClass(element, settings.class_loaded);
540 removeClass(element, settings.class_error);
541 };
542 const restore = (element, settings) => {
543 restoreAttributes(element);
544 resetClasses(element, settings);
545 resetStatus(element);
546 deleteOriginalAttrs(element);
547 };
548
549 const cancelLoading = (element, entry, settings, instance) => {
550 if (!settings.cancel_on_exit) return;
551 if (!hasStatusLoading(element)) return;
552 if (element.tagName !== "IMG") return; //Works only on images
553 removeEventListeners(element);
554 resetSourcesImg(element);
555 restoreImg(element);
556 removeClass(element, settings.class_loading);
557 updateLoadingCount(instance, -1);
558 resetStatus(element);
559 safeCallback(settings.callback_cancel, element, entry, instance);
560 };
561
562 const onEnter = (element, entry, settings, instance) => {
563 const dontLoad = hadStartedLoading(element); /* Save status
564 before setting it, to prevent loading it again. Fixes #526. */
565 setStatus(element, statusEntered);
566 addClass(element, settings.class_entered);
567 removeClass(element, settings.class_exited);
568 unobserveEntered(element, settings, instance);
569 safeCallback(settings.callback_enter, element, entry, instance);
570 if (dontLoad) return;
571 load(element, settings, instance);
572 };
573 const onExit = (element, entry, settings, instance) => {
574 if (hasEmptyStatus(element)) return; //Ignore the first pass, at landing
575 addClass(element, settings.class_exited);
576 cancelLoading(element, entry, settings, instance);
577 safeCallback(settings.callback_exit, element, entry, instance);
578 };
579
580 const tagsWithNativeLazy = ["IMG", "IFRAME", "VIDEO"];
581 const shouldUseNative = settings => settings.use_native && "loading" in HTMLImageElement.prototype;
582 const loadAllNative = (elements, settings, instance) => {
583 elements.forEach(element => {
584 if (tagsWithNativeLazy.indexOf(element.tagName) === -1) {
585 return;
586 }
587 loadNative(element, settings, instance);
588 });
589 setToLoadCount(instance, 0);
590 };
591
592 const isIntersecting = entry => entry.isIntersecting || entry.intersectionRatio > 0;
593 const getObserverSettings = settings => ({
594 root: settings.container === document ? null : settings.container,
595 rootMargin: settings.thresholds || settings.threshold + "px"
596 });
597 const intersectionHandler = (entries, settings, instance) => {
598 entries.forEach(entry => isIntersecting(entry) ? onEnter(entry.target, entry, settings, instance) : onExit(entry.target, entry, settings, instance));
599 };
600 const observeElements = (observer, elements) => {
601 elements.forEach(element => {
602 observer.observe(element);
603 });
604 };
605 const updateObserver = (observer, elementsToObserve) => {
606 resetObserver(observer);
607 observeElements(observer, elementsToObserve);
608 };
609 const setObserver = (settings, instance) => {
610 if (shouldUseNative(settings)) {
611 return;
612 }
613 instance._observer = new IntersectionObserver(entries => {
614 intersectionHandler(entries, settings, instance);
615 }, getObserverSettings(settings));
616 };
617
618 const toArray = nodeSet => Array.prototype.slice.call(nodeSet);
619 const queryElements = settings => settings.container.querySelectorAll(settings.elements_selector);
620 const excludeManagedElements = elements => toArray(elements).filter(hasEmptyStatus);
621 const hasError = element => hasStatusError(element);
622 const filterErrorElements = elements => toArray(elements).filter(hasError);
623 const getElementsToLoad = (elements, settings) => excludeManagedElements(elements || queryElements(settings));
624
625 const retryLazyLoad = (settings, instance) => {
626 const errorElements = filterErrorElements(queryElements(settings));
627 errorElements.forEach(element => {
628 removeClass(element, settings.class_error);
629 resetStatus(element);
630 });
631 instance.update();
632 };
633 const setOnlineCheck = (settings, instance) => {
634 if (!runningOnBrowser) {
635 return;
636 }
637 instance._onlineHandler = () => {
638 retryLazyLoad(settings, instance);
639 };
640 window.addEventListener("online", instance._onlineHandler);
641 };
642 const resetOnlineCheck = instance => {
643 if (!runningOnBrowser) {
644 return;
645 }
646 window.removeEventListener("online", instance._onlineHandler);
647 };
648
649 const LazyLoad = function (customSettings, elements) {
650 const settings = getExtendedSettings(customSettings);
651 this._settings = settings;
652 this.loadingCount = 0;
653 setObserver(settings, this);
654 setOnlineCheck(settings, this);
655 this.update(elements);
656 };
657 LazyLoad.prototype = {
658 update: function (givenNodeset) {
659 const settings = this._settings;
660 const elementsToLoad = getElementsToLoad(givenNodeset, settings);
661 setToLoadCount(this, elementsToLoad.length);
662 if (isBot) {
663 this.loadAll(elementsToLoad);
664 return;
665 }
666 if (shouldUseNative(settings)) {
667 loadAllNative(elementsToLoad, settings, this);
668 return;
669 }
670 updateObserver(this._observer, elementsToLoad);
671 },
672 destroy: function () {
673 // Observer
674 if (this._observer) {
675 this._observer.disconnect();
676 }
677 // Clean handlers
678 resetOnlineCheck(this);
679 // Clean custom attributes on elements
680 queryElements(this._settings).forEach(element => {
681 deleteOriginalAttrs(element);
682 });
683 // Delete all internal props
684 delete this._observer;
685 delete this._settings;
686 delete this._onlineHandler;
687 delete this.loadingCount;
688 delete this.toLoadCount;
689 },
690 loadAll: function (elements) {
691 const settings = this._settings;
692 const elementsToLoad = getElementsToLoad(elements, settings);
693 elementsToLoad.forEach(element => {
694 unobserve(element, this);
695 load(element, settings, this);
696 });
697 },
698 restoreAll: function () {
699 const settings = this._settings;
700 queryElements(settings).forEach(element => {
701 restore(element, settings);
702 });
703 }
704 };
705 LazyLoad.load = (element, customSettings) => {
706 const settings = getExtendedSettings(customSettings);
707 load(element, settings);
708 };
709 LazyLoad.resetStatus = element => {
710 resetStatus(element);
711 };
712
713 // Automatic instances creation if required (useful for async script loading)
714 if (runningOnBrowser) {
715 autoInitialize(LazyLoad, window.lazyLoadOptions);
716 }
717
718 return LazyLoad;
719
720}));