UNPKG

lightgallery

Version:

lightGallery is a feature-rich, modular JavaScript gallery plugin for building beautiful image and video galleries for the web and the mobile

1,096 lines 83.9 kB
"use strict"; var __assign = (this && this.__assign) || function () { __assign = Object.assign || function(t) { for (var s, i = 1, n = arguments.length; i < n; i++) { s = arguments[i]; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; } return t; }; return __assign.apply(this, arguments); }; Object.defineProperty(exports, "__esModule", { value: true }); exports.LightGallery = void 0; var lg_events_1 = require("./lg-events"); var lg_settings_1 = require("./lg-settings"); var lg_utils_1 = require("./lg-utils"); var lgQuery_1 = require("./lgQuery"); // @ref - https://stackoverflow.com/questions/3971841/how-to-resize-images-proportionally-keeping-the-aspect-ratio // @ref - https://2ality.com/2017/04/setting-up-multi-platform-packages.html // Unique id for each gallery var lgId = 0; var LightGallery = /** @class */ (function () { function LightGallery(element, options) { this.lgOpened = false; this.index = 0; // lightGallery modules this.plugins = []; // false when lightGallery load first slide content; this.lGalleryOn = false; // True when a slide animation is in progress this.lgBusy = false; this.currentItemsInDom = []; // Scroll top value before lightGallery is opened this.prevScrollTop = 0; this.bodyPaddingRight = 0; this.isDummyImageRemoved = false; this.dragOrSwipeEnabled = false; this.mediaContainerPosition = { top: 0, bottom: 0, }; if (!element) { return this; } lgId++; this.lgId = lgId; this.el = element; this.LGel = lgQuery_1.$LG(element); this.generateSettings(options); this.buildModules(); // When using dynamic mode, ensure dynamicEl is an array if (this.settings.dynamic && this.settings.dynamicEl !== undefined && !Array.isArray(this.settings.dynamicEl)) { throw 'When using dynamic mode, you must also define dynamicEl as an Array.'; } this.galleryItems = this.getItems(); this.normalizeSettings(); // Gallery items this.init(); this.validateLicense(); return this; } LightGallery.prototype.generateSettings = function (options) { // lightGallery settings this.settings = __assign(__assign({}, lg_settings_1.lightGalleryCoreSettings), options); if (this.settings.isMobile && typeof this.settings.isMobile === 'function' ? this.settings.isMobile() : lg_utils_1.default.isMobile()) { var mobileSettings = __assign(__assign({}, this.settings.mobileSettings), this.settings.mobileSettings); this.settings = __assign(__assign({}, this.settings), mobileSettings); } }; LightGallery.prototype.normalizeSettings = function () { if (this.settings.slideEndAnimation) { this.settings.hideControlOnEnd = false; } if (!this.settings.closable) { this.settings.swipeToClose = false; } // And reset it on close to get the correct value next time this.zoomFromOrigin = this.settings.zoomFromOrigin; // At the moment, Zoom from image doesn't support dynamic options // @todo add zoomFromOrigin support for dynamic images if (this.settings.dynamic) { this.zoomFromOrigin = false; } if (!this.settings.container) { this.settings.container = document.body; } // settings.preload should not be grater than $item.length this.settings.preload = Math.min(this.settings.preload, this.galleryItems.length); }; LightGallery.prototype.init = function () { var _this = this; this.addSlideVideoInfo(this.galleryItems); this.buildStructure(); this.LGel.trigger(lg_events_1.lGEvents.init, { instance: this, }); if (this.settings.keyPress) { this.keyPress(); } setTimeout(function () { _this.enableDrag(); _this.enableSwipe(); _this.triggerPosterClick(); }, 50); this.arrow(); if (this.settings.mousewheel) { this.mousewheel(); } if (!this.settings.dynamic) { this.openGalleryOnItemClick(); } }; LightGallery.prototype.openGalleryOnItemClick = function () { var _this = this; var _loop_1 = function (index) { var element = this_1.items[index]; var $element = lgQuery_1.$LG(element); // Using different namespace for click because click event should not unbind if selector is same object('this') // @todo manage all event listners - should have namespace that represent element var uuid = lgQuery_1.lgQuery.generateUUID(); $element .attr('data-lg-id', uuid) .on("click.lgcustom-item-" + uuid, function (e) { e.preventDefault(); var currentItemIndex = _this.settings.index || index; _this.openGallery(currentItemIndex, element); }); }; var this_1 = this; // Using for loop instead of using bubbling as the items can be any html element. for (var index = 0; index < this.items.length; index++) { _loop_1(index); } }; /** * Module constructor * Modules are build incrementally. * Gallery should be opened only once all the modules are initialized. * use moduleBuildTimeout to make sure this */ LightGallery.prototype.buildModules = function () { var _this = this; this.settings.plugins.forEach(function (plugin) { _this.plugins.push(new plugin(_this, lgQuery_1.$LG)); }); }; LightGallery.prototype.validateLicense = function () { if (!this.settings.licenseKey) { console.error('Please provide a valid license key'); } else if (this.settings.licenseKey === '0000-0000-000-0000') { console.warn("lightGallery: " + this.settings.licenseKey + " license key is not valid for production use"); } }; LightGallery.prototype.getSlideItem = function (index) { return lgQuery_1.$LG(this.getSlideItemId(index)); }; LightGallery.prototype.getSlideItemId = function (index) { return "#lg-item-" + this.lgId + "-" + index; }; LightGallery.prototype.getIdName = function (id) { return id + "-" + this.lgId; }; LightGallery.prototype.getElementById = function (id) { return lgQuery_1.$LG("#" + this.getIdName(id)); }; LightGallery.prototype.manageSingleSlideClassName = function () { if (this.galleryItems.length < 2) { this.outer.addClass('lg-single-item'); } else { this.outer.removeClass('lg-single-item'); } }; LightGallery.prototype.buildStructure = function () { var _this = this; var container = this.$container && this.$container.get(); if (container) { return; } var controls = ''; var subHtmlCont = ''; // Create controls if (this.settings.controls) { controls = "<button type=\"button\" id=\"" + this.getIdName('lg-prev') + "\" aria-label=\"" + this.settings.strings['previousSlide'] + "\" class=\"lg-prev lg-icon\"> " + this.settings.prevHtml + " </button>\n <button type=\"button\" id=\"" + this.getIdName('lg-next') + "\" aria-label=\"" + this.settings.strings['nextSlide'] + "\" class=\"lg-next lg-icon\"> " + this.settings.nextHtml + " </button>"; } if (this.settings.appendSubHtmlTo !== '.lg-item') { subHtmlCont = '<div class="lg-sub-html" role="status" aria-live="polite"></div>'; } var addClasses = ''; if (this.settings.allowMediaOverlap) { // Do not remove space before last single quote addClasses += 'lg-media-overlap '; } var ariaLabelledby = this.settings.ariaLabelledby ? 'aria-labelledby="' + this.settings.ariaLabelledby + '"' : ''; var ariaDescribedby = this.settings.ariaDescribedby ? 'aria-describedby="' + this.settings.ariaDescribedby + '"' : ''; var containerClassName = "lg-container " + this.settings.addClass + " " + (document.body !== this.settings.container ? 'lg-inline' : ''); var closeIcon = this.settings.closable && this.settings.showCloseIcon ? "<button type=\"button\" aria-label=\"" + this.settings.strings['closeGallery'] + "\" id=\"" + this.getIdName('lg-close') + "\" class=\"lg-close lg-icon\"></button>" : ''; var maximizeIcon = this.settings.showMaximizeIcon ? "<button type=\"button\" aria-label=\"" + this.settings.strings['toggleMaximize'] + "\" id=\"" + this.getIdName('lg-maximize') + "\" class=\"lg-maximize lg-icon\"></button>" : ''; var template = "\n <div class=\"" + containerClassName + "\" id=\"" + this.getIdName('lg-container') + "\" tabindex=\"-1\" aria-modal=\"true\" " + ariaLabelledby + " " + ariaDescribedby + " role=\"dialog\"\n >\n <div id=\"" + this.getIdName('lg-backdrop') + "\" class=\"lg-backdrop\"></div>\n\n <div id=\"" + this.getIdName('lg-outer') + "\" class=\"lg-outer lg-use-css3 lg-css3 lg-hide-items " + addClasses + " \">\n\n <div id=\"" + this.getIdName('lg-content') + "\" class=\"lg-content\">\n <div id=\"" + this.getIdName('lg-inner') + "\" class=\"lg-inner\">\n </div>\n " + controls + "\n </div>\n <div id=\"" + this.getIdName('lg-toolbar') + "\" class=\"lg-toolbar lg-group\">\n " + maximizeIcon + "\n " + closeIcon + "\n </div>\n " + (this.settings.appendSubHtmlTo === '.lg-outer' ? subHtmlCont : '') + "\n <div id=\"" + this.getIdName('lg-components') + "\" class=\"lg-components\">\n " + (this.settings.appendSubHtmlTo === '.lg-sub-html' ? subHtmlCont : '') + "\n </div>\n </div>\n </div>\n "; lgQuery_1.$LG(this.settings.container).append(template); if (document.body !== this.settings.container) { lgQuery_1.$LG(this.settings.container).css('position', 'relative'); } this.outer = this.getElementById('lg-outer'); this.$lgComponents = this.getElementById('lg-components'); this.$backdrop = this.getElementById('lg-backdrop'); this.$container = this.getElementById('lg-container'); this.$inner = this.getElementById('lg-inner'); this.$content = this.getElementById('lg-content'); this.$toolbar = this.getElementById('lg-toolbar'); this.$backdrop.css('transition-duration', this.settings.backdropDuration + 'ms'); var outerClassNames = this.settings.mode + " "; this.manageSingleSlideClassName(); if (this.settings.enableDrag) { outerClassNames += 'lg-grab '; } this.outer.addClass(outerClassNames); this.$inner.css('transition-timing-function', this.settings.easing); this.$inner.css('transition-duration', this.settings.speed + 'ms'); if (this.settings.download) { this.$toolbar.append("<a id=\"" + this.getIdName('lg-download') + "\" target=\"_blank\" rel=\"noopener\" aria-label=\"" + this.settings.strings['download'] + "\" download class=\"lg-download lg-icon\"></a>"); } this.counter(); lgQuery_1.$LG(window).on("resize.lg.global" + this.lgId + " orientationchange.lg.global" + this.lgId, function () { _this.refreshOnResize(); }); this.hideBars(); this.manageCloseGallery(); this.toggleMaximize(); this.initModules(); }; LightGallery.prototype.refreshOnResize = function () { if (this.lgOpened) { var currentGalleryItem = this.galleryItems[this.index]; var __slideVideoInfo = currentGalleryItem.__slideVideoInfo; this.mediaContainerPosition = this.getMediaContainerPosition(); var _a = this.mediaContainerPosition, top_1 = _a.top, bottom = _a.bottom; this.currentImageSize = lg_utils_1.default.getSize(this.items[this.index], this.outer, top_1 + bottom, __slideVideoInfo && this.settings.videoMaxSize); if (__slideVideoInfo) { this.resizeVideoSlide(this.index, this.currentImageSize); } if (this.zoomFromOrigin && !this.isDummyImageRemoved) { var imgStyle = this.getDummyImgStyles(this.currentImageSize); this.outer .find('.lg-current .lg-dummy-img') .first() .attr('style', imgStyle); } this.LGel.trigger(lg_events_1.lGEvents.containerResize); } }; LightGallery.prototype.resizeVideoSlide = function (index, imageSize) { var lgVideoStyle = this.getVideoContStyle(imageSize); var currentSlide = this.getSlideItem(index); currentSlide.find('.lg-video-cont').attr('style', lgVideoStyle); }; /** * Update slides dynamically. * Add, edit or delete slides dynamically when lightGallery is opened. * Modify the current gallery items and pass it via updateSlides method * @note * - Do not mutate existing lightGallery items directly. * - Always pass new list of gallery items * - You need to take care of thumbnails outside the gallery if any * - user this method only if you want to update slides when the gallery is opened. Otherwise, use `refresh()` method. * @param items Gallery items * @param index After the update operation, which slide gallery should navigate to * @category lGPublicMethods * @example * const plugin = lightGallery(); * * // Adding slides dynamically * let galleryItems = [ * // Access existing lightGallery items * // galleryItems are automatically generated internally from the gallery HTML markup * // or directly from galleryItems when dynamic gallery is used * ...plugin.galleryItems, * ...[ * { * src: 'img/img-1.png', * thumb: 'img/thumb1.png', * }, * ], * ]; * plugin.updateSlides( * galleryItems, * plugin.index, * ); * * * // Remove slides dynamically * galleryItems = JSON.parse( * JSON.stringify(updateSlideInstance.galleryItems), * ); * galleryItems.shift(); * updateSlideInstance.updateSlides(galleryItems, 1); * @see <a href="/demos/update-slides/">Demo</a> */ LightGallery.prototype.updateSlides = function (items, index) { if (this.index > items.length - 1) { this.index = items.length - 1; } if (items.length === 1) { this.index = 0; } if (!items.length) { this.closeGallery(); return; } var currentSrc = this.galleryItems[index].src; this.galleryItems = items; this.updateControls(); this.$inner.empty(); this.currentItemsInDom = []; var _index = 0; // Find the current index based on source value of the slide this.galleryItems.some(function (galleryItem, itemIndex) { if (galleryItem.src === currentSrc) { _index = itemIndex; return true; } return false; }); this.currentItemsInDom = this.organizeSlideItems(_index, -1); this.loadContent(_index, true); this.getSlideItem(_index).addClass('lg-current'); this.index = _index; this.updateCurrentCounter(_index); this.LGel.trigger(lg_events_1.lGEvents.updateSlides); }; // Get gallery items based on multiple conditions LightGallery.prototype.getItems = function () { // Gallery items this.items = []; if (!this.settings.dynamic) { if (this.settings.selector === 'this') { this.items.push(this.el); } else if (this.settings.selector) { if (typeof this.settings.selector === 'string') { if (this.settings.selectWithin) { var selectWithin = lgQuery_1.$LG(this.settings.selectWithin); this.items = selectWithin .find(this.settings.selector) .get(); } else { this.items = this.el.querySelectorAll(this.settings.selector); } } else { this.items = this.settings.selector; } } else { this.items = this.el.children; } return lg_utils_1.default.getDynamicOptions(this.items, this.settings.extraProps, this.settings.getCaptionFromTitleOrAlt, this.settings.exThumbImage); } else { return this.settings.dynamicEl || []; } }; LightGallery.prototype.shouldHideScrollbar = function () { return (this.settings.hideScrollbar && document.body === this.settings.container); }; LightGallery.prototype.hideScrollbar = function () { if (!this.shouldHideScrollbar()) { return; } this.bodyPaddingRight = parseFloat(lgQuery_1.$LG('body').style().paddingRight); var bodyRect = document.documentElement.getBoundingClientRect(); var scrollbarWidth = window.innerWidth - bodyRect.width; lgQuery_1.$LG(document.body).css('padding-right', scrollbarWidth + this.bodyPaddingRight + 'px'); lgQuery_1.$LG(document.body).addClass('lg-overlay-open'); }; LightGallery.prototype.resetScrollBar = function () { if (!this.shouldHideScrollbar()) { return; } lgQuery_1.$LG(document.body).css('padding-right', this.bodyPaddingRight + 'px'); lgQuery_1.$LG(document.body).removeClass('lg-overlay-open'); }; /** * Open lightGallery. * Open gallery with specific slide by passing index of the slide as parameter. * @category lGPublicMethods * @param {Number} index - index of the slide * @param {HTMLElement} element - Which image lightGallery should zoom from * * @example * const $dynamicGallery = document.getElementById('dynamic-gallery-demo'); * const dynamicGallery = lightGallery($dynamicGallery, { * dynamic: true, * dynamicEl: [ * { * src: 'img/1.jpg', * thumb: 'img/thumb-1.jpg', * subHtml: '<h4>Image 1 title</h4><p>Image 1 descriptions.</p>', * }, * ... * ], * }); * $dynamicGallery.addEventListener('click', function () { * // Starts with third item.(Optional). * // This is useful if you want use dynamic mode with * // custom thumbnails (thumbnails outside gallery), * dynamicGallery.openGallery(2); * }); * */ LightGallery.prototype.openGallery = function (index, element) { var _this = this; if (index === void 0) { index = this.settings.index; } // prevent accidental double execution if (this.lgOpened) return; this.lgOpened = true; this.outer.removeClass('lg-hide-items'); this.hideScrollbar(); // Add display block, but still has opacity 0 this.$container.addClass('lg-show'); var itemsToBeInsertedToDom = this.getItemsToBeInsertedToDom(index, index); this.currentItemsInDom = itemsToBeInsertedToDom; var items = ''; itemsToBeInsertedToDom.forEach(function (item) { items = items + ("<div id=\"" + item + "\" class=\"lg-item\"></div>"); }); this.$inner.append(items); this.addHtml(index); var transform = ''; this.mediaContainerPosition = this.getMediaContainerPosition(); var _a = this.mediaContainerPosition, top = _a.top, bottom = _a.bottom; if (!this.settings.allowMediaOverlap) { this.setMediaContainerPosition(top, bottom); } var __slideVideoInfo = this.galleryItems[index].__slideVideoInfo; if (this.zoomFromOrigin && element) { this.currentImageSize = lg_utils_1.default.getSize(element, this.outer, top + bottom, __slideVideoInfo && this.settings.videoMaxSize); transform = lg_utils_1.default.getTransform(element, this.outer, top, bottom, this.currentImageSize); } if (!this.zoomFromOrigin || !transform) { this.outer.addClass(this.settings.startClass); this.getSlideItem(index).removeClass('lg-complete'); } var timeout = this.settings.zoomFromOrigin ? 100 : this.settings.backdropDuration; setTimeout(function () { _this.outer.addClass('lg-components-open'); }, timeout); this.index = index; this.LGel.trigger(lg_events_1.lGEvents.beforeOpen); // add class lg-current to remove initial transition this.getSlideItem(index).addClass('lg-current'); this.lGalleryOn = false; // Store the current scroll top value to scroll back after closing the gallery.. this.prevScrollTop = lgQuery_1.$LG(window).scrollTop(); setTimeout(function () { // Need to check both zoomFromOrigin and transform values as we need to set set the // default opening animation if user missed to add the lg-size attribute if (_this.zoomFromOrigin && transform) { var currentSlide_1 = _this.getSlideItem(index); currentSlide_1.css('transform', transform); setTimeout(function () { currentSlide_1 .addClass('lg-start-progress lg-start-end-progress') .css('transition-duration', _this.settings.startAnimationDuration + 'ms'); _this.outer.addClass('lg-zoom-from-image'); }); setTimeout(function () { currentSlide_1.css('transform', 'translate3d(0, 0, 0)'); }, 100); } setTimeout(function () { _this.$backdrop.addClass('in'); _this.$container.addClass('lg-show-in'); }, 10); setTimeout(function () { if (_this.settings.trapFocus && document.body === _this.settings.container) { _this.trapFocus(); } }, _this.settings.backdropDuration + 50); // lg-visible class resets gallery opacity to 1 if (!_this.zoomFromOrigin || !transform) { setTimeout(function () { _this.outer.addClass('lg-visible'); }, _this.settings.backdropDuration); } // initiate slide function _this.slide(index, false, false, false); _this.LGel.trigger(lg_events_1.lGEvents.afterOpen); }); if (document.body === this.settings.container) { lgQuery_1.$LG('html').addClass('lg-on'); } }; /** * Note - Changing the position of the media on every slide transition creates a flickering effect. * Therefore, The height of the caption is calculated dynamically, only once based on the first slide caption. * if you have dynamic captions for each media, * you can provide an appropriate height for the captions via allowMediaOverlap option */ LightGallery.prototype.getMediaContainerPosition = function () { if (this.settings.allowMediaOverlap) { return { top: 0, bottom: 0, }; } var top = this.$toolbar.get().clientHeight || 0; var subHtml = this.outer.find('.lg-components .lg-sub-html').get(); var captionHeight = this.settings.defaultCaptionHeight || (subHtml && subHtml.clientHeight) || 0; var thumbContainer = this.outer.find('.lg-thumb-outer').get(); var thumbHeight = thumbContainer ? thumbContainer.clientHeight : 0; var bottom = thumbHeight + captionHeight; return { top: top, bottom: bottom, }; }; LightGallery.prototype.setMediaContainerPosition = function (top, bottom) { if (top === void 0) { top = 0; } if (bottom === void 0) { bottom = 0; } this.$content.css('top', top + 'px').css('bottom', bottom + 'px'); }; LightGallery.prototype.hideBars = function () { var _this = this; // Hide controllers if mouse doesn't move for some period setTimeout(function () { _this.outer.removeClass('lg-hide-items'); if (_this.settings.hideBarsDelay > 0) { _this.outer.on('mousemove.lg click.lg touchstart.lg', function () { _this.outer.removeClass('lg-hide-items'); clearTimeout(_this.hideBarTimeout); // Timeout will be cleared on each slide movement also _this.hideBarTimeout = setTimeout(function () { _this.outer.addClass('lg-hide-items'); }, _this.settings.hideBarsDelay); }); _this.outer.trigger('mousemove.lg'); } }, this.settings.showBarsAfter); }; LightGallery.prototype.initPictureFill = function ($img) { if (this.settings.supportLegacyBrowser) { try { picturefill({ elements: [$img.get()], }); } catch (e) { console.warn('lightGallery :- If you want srcset or picture tag to be supported for older browser please include picturefil javascript library in your document.'); } } }; /** * @desc Create image counter * Ex: 1/10 */ LightGallery.prototype.counter = function () { if (this.settings.counter) { var counterHtml = "<div class=\"lg-counter\" role=\"status\" aria-live=\"polite\">\n <span id=\"" + this.getIdName('lg-counter-current') + "\" class=\"lg-counter-current\">" + (this.index + 1) + " </span> /\n <span id=\"" + this.getIdName('lg-counter-all') + "\" class=\"lg-counter-all\">" + this.galleryItems.length + " </span></div>"; this.outer.find(this.settings.appendCounterTo).append(counterHtml); } }; /** * @desc add sub-html into the slide * @param {Number} index - index of the slide */ LightGallery.prototype.addHtml = function (index) { var subHtml; var subHtmlUrl; if (this.galleryItems[index].subHtmlUrl) { subHtmlUrl = this.galleryItems[index].subHtmlUrl; } else { subHtml = this.galleryItems[index].subHtml; } if (!subHtmlUrl) { if (subHtml) { // get first letter of sub-html // if first letter starts with . or # get the html form the jQuery object var fL = subHtml.substring(0, 1); if (fL === '.' || fL === '#') { if (this.settings.subHtmlSelectorRelative && !this.settings.dynamic) { subHtml = lgQuery_1.$LG(this.items) .eq(index) .find(subHtml) .first() .html(); } else { subHtml = lgQuery_1.$LG(subHtml).first().html(); } } } else { subHtml = ''; } } if (this.settings.appendSubHtmlTo !== '.lg-item') { if (subHtmlUrl) { this.outer.find('.lg-sub-html').load(subHtmlUrl); } else { this.outer.find('.lg-sub-html').html(subHtml); } } else { var currentSlide = lgQuery_1.$LG(this.getSlideItemId(index)); if (subHtmlUrl) { currentSlide.load(subHtmlUrl); } else { currentSlide.append("<div class=\"lg-sub-html\">" + subHtml + "</div>"); } } // Add lg-empty-html class if title doesn't exist if (typeof subHtml !== 'undefined' && subHtml !== null) { if (subHtml === '') { this.outer .find(this.settings.appendSubHtmlTo) .addClass('lg-empty-html'); } else { this.outer .find(this.settings.appendSubHtmlTo) .removeClass('lg-empty-html'); } } this.LGel.trigger(lg_events_1.lGEvents.afterAppendSubHtml, { index: index, }); }; /** * @desc Preload slides * @param {Number} index - index of the slide * @todo preload not working for the first slide, Also, should work for the first and last slide as well */ LightGallery.prototype.preload = function (index) { for (var i = 1; i <= this.settings.preload; i++) { if (i >= this.galleryItems.length - index) { break; } this.loadContent(index + i, false); } for (var j = 1; j <= this.settings.preload; j++) { if (index - j < 0) { break; } this.loadContent(index - j, false); } }; LightGallery.prototype.getDummyImgStyles = function (imageSize) { if (!imageSize) return ''; return "width:" + imageSize.width + "px;\n margin-left: -" + imageSize.width / 2 + "px;\n margin-top: -" + imageSize.height / 2 + "px;\n height:" + imageSize.height + "px"; }; LightGallery.prototype.getVideoContStyle = function (imageSize) { if (!imageSize) return ''; return "width:" + imageSize.width + "px;\n height:" + imageSize.height + "px"; }; LightGallery.prototype.getDummyImageContent = function ($currentSlide, index, alt) { var $currentItem; if (!this.settings.dynamic) { $currentItem = lgQuery_1.$LG(this.items).eq(index); } if ($currentItem) { var _dummyImgSrc = void 0; if (!this.settings.exThumbImage) { _dummyImgSrc = $currentItem.find('img').first().attr('src'); } else { _dummyImgSrc = $currentItem.attr(this.settings.exThumbImage); } if (!_dummyImgSrc) return ''; var imgStyle = this.getDummyImgStyles(this.currentImageSize); var dummyImgContent = "<img " + alt + " style=\"" + imgStyle + "\" class=\"lg-dummy-img\" src=\"" + _dummyImgSrc + "\" />"; $currentSlide.addClass('lg-first-slide'); this.outer.addClass('lg-first-slide-loading'); return dummyImgContent; } return ''; }; LightGallery.prototype.setImgMarkup = function (src, $currentSlide, index) { var currentGalleryItem = this.galleryItems[index]; var alt = currentGalleryItem.alt, srcset = currentGalleryItem.srcset, sizes = currentGalleryItem.sizes, sources = currentGalleryItem.sources; // Use the thumbnail as dummy image which will be resized to actual image size and // displayed on top of actual image var imgContent = ''; var altAttr = alt ? 'alt="' + alt + '"' : ''; if (this.isFirstSlideWithZoomAnimation()) { imgContent = this.getDummyImageContent($currentSlide, index, altAttr); } else { imgContent = lg_utils_1.default.getImgMarkup(index, src, altAttr, srcset, sizes, sources); } var imgMarkup = "<picture class=\"lg-img-wrap\"> " + imgContent + "</picture>"; $currentSlide.prepend(imgMarkup); }; LightGallery.prototype.onSlideObjectLoad = function ($slide, isHTML5VideoWithoutPoster, onLoad, onError) { var mediaObject = $slide.find('.lg-object').first(); if (lg_utils_1.default.isImageLoaded(mediaObject.get()) || isHTML5VideoWithoutPoster) { onLoad(); } else { mediaObject.on('load.lg error.lg', function () { onLoad && onLoad(); }); mediaObject.on('error.lg', function () { onError && onError(); }); } }; /** * * @param $el Current slide item * @param index * @param delay Delay is 0 except first time * @param speed Speed is same as delay, except it is 0 if gallery is opened via hash plugin * @param isFirstSlide */ LightGallery.prototype.onLgObjectLoad = function (currentSlide, index, delay, speed, isFirstSlide, isHTML5VideoWithoutPoster) { var _this = this; this.onSlideObjectLoad(currentSlide, isHTML5VideoWithoutPoster, function () { _this.triggerSlideItemLoad(currentSlide, index, delay, speed, isFirstSlide); }, function () { currentSlide.addClass('lg-complete lg-complete_'); currentSlide.html('<span class="lg-error-msg">Oops... Failed to load content...</span>'); }); }; LightGallery.prototype.triggerSlideItemLoad = function ($currentSlide, index, delay, speed, isFirstSlide) { var _this = this; var currentGalleryItem = this.galleryItems[index]; // Adding delay for video slides without poster for better performance and user experience // Videos should start playing once once the gallery is completely loaded var _speed = isFirstSlide && this.getSlideType(currentGalleryItem) === 'video' && !currentGalleryItem.poster ? speed : 0; setTimeout(function () { $currentSlide.addClass('lg-complete lg-complete_'); _this.LGel.trigger(lg_events_1.lGEvents.slideItemLoad, { index: index, delay: delay || 0, isFirstSlide: isFirstSlide, }); }, _speed); }; LightGallery.prototype.isFirstSlideWithZoomAnimation = function () { return !!(!this.lGalleryOn && this.zoomFromOrigin && this.currentImageSize); }; // Add video slideInfo LightGallery.prototype.addSlideVideoInfo = function (items) { var _this = this; items.forEach(function (element, index) { element.__slideVideoInfo = lg_utils_1.default.isVideo(element.src, !!element.video, index); if (element.__slideVideoInfo && _this.settings.loadYouTubePoster && !element.poster && element.__slideVideoInfo.youtube) { element.poster = "//img.youtube.com/vi/" + element.__slideVideoInfo.youtube[1] + "/maxresdefault.jpg"; } }); }; /** * Load slide content into slide. * This is used to load content into slides that is not visible too * @param {Number} index - index of the slide. * @param {Boolean} rec - if true call loadcontent() function again. */ LightGallery.prototype.loadContent = function (index, rec) { var _this = this; var currentGalleryItem = this.galleryItems[index]; var $currentSlide = lgQuery_1.$LG(this.getSlideItemId(index)); var poster = currentGalleryItem.poster, srcset = currentGalleryItem.srcset, sizes = currentGalleryItem.sizes, sources = currentGalleryItem.sources; var src = currentGalleryItem.src; var video = currentGalleryItem.video; var _html5Video = video && typeof video === 'string' ? JSON.parse(video) : video; if (currentGalleryItem.responsive) { var srcDyItms = currentGalleryItem.responsive.split(','); src = lg_utils_1.default.getResponsiveSrc(srcDyItms) || src; } var videoInfo = currentGalleryItem.__slideVideoInfo; var lgVideoStyle = ''; var iframe = !!currentGalleryItem.iframe; var isFirstSlide = !this.lGalleryOn; // delay for adding complete class. it is 0 except first time. var delay = 0; if (isFirstSlide) { if (this.zoomFromOrigin && this.currentImageSize) { delay = this.settings.startAnimationDuration + 10; } else { delay = this.settings.backdropDuration + 10; } } if (!$currentSlide.hasClass('lg-loaded')) { if (videoInfo) { var _a = this.mediaContainerPosition, top_2 = _a.top, bottom = _a.bottom; var videoSize = lg_utils_1.default.getSize(this.items[index], this.outer, top_2 + bottom, videoInfo && this.settings.videoMaxSize); lgVideoStyle = this.getVideoContStyle(videoSize); } if (iframe) { var markup = lg_utils_1.default.getIframeMarkup(this.settings.iframeWidth, this.settings.iframeHeight, this.settings.iframeMaxWidth, this.settings.iframeMaxHeight, src, currentGalleryItem.iframeTitle); $currentSlide.prepend(markup); } else if (poster) { var dummyImg = ''; var hasStartAnimation = isFirstSlide && this.zoomFromOrigin && this.currentImageSize; if (hasStartAnimation) { dummyImg = this.getDummyImageContent($currentSlide, index, ''); } var markup = lg_utils_1.default.getVideoPosterMarkup(poster, dummyImg || '', lgVideoStyle, this.settings.strings['playVideo'], videoInfo); $currentSlide.prepend(markup); } else if (videoInfo) { var markup = "<div class=\"lg-video-cont \" style=\"" + lgVideoStyle + "\"></div>"; $currentSlide.prepend(markup); } else { this.setImgMarkup(src, $currentSlide, index); if (srcset || sources) { var $img = $currentSlide.find('.lg-object'); this.initPictureFill($img); } } if (poster || videoInfo) { this.LGel.trigger(lg_events_1.lGEvents.hasVideo, { index: index, src: src, html5Video: _html5Video, hasPoster: !!poster, }); } this.LGel.trigger(lg_events_1.lGEvents.afterAppendSlide, { index: index }); if (this.lGalleryOn && this.settings.appendSubHtmlTo === '.lg-item') { this.addHtml(index); } } // For first time add some delay for displaying the start animation. var _speed = 0; // Do not change the delay value because it is required for zoom plugin. // If gallery opened from direct url (hash) speed value should be 0 if (delay && !lgQuery_1.$LG(document.body).hasClass('lg-from-hash')) { _speed = delay; } // Only for first slide and zoomFromOrigin is enabled if (this.isFirstSlideWithZoomAnimation()) { setTimeout(function () { $currentSlide .removeClass('lg-start-end-progress lg-start-progress') .removeAttr('style'); }, this.settings.startAnimationDuration + 100); if (!$currentSlide.hasClass('lg-loaded')) { setTimeout(function () { if (_this.getSlideType(currentGalleryItem) === 'image') { var alt = currentGalleryItem.alt; var altAttr = alt ? 'alt="' + alt + '"' : ''; $currentSlide .find('.lg-img-wrap') .append(lg_utils_1.default.getImgMarkup(index, src, altAttr, srcset, sizes, currentGalleryItem.sources)); if (srcset || sources) { var $img = $currentSlide.find('.lg-object'); _this.initPictureFill($img); } } if (_this.getSlideType(currentGalleryItem) === 'image' || (_this.getSlideType(currentGalleryItem) === 'video' && poster)) { _this.onLgObjectLoad($currentSlide, index, delay, _speed, true, false); // load remaining slides once the slide is completely loaded _this.onSlideObjectLoad($currentSlide, !!(videoInfo && videoInfo.html5 && !poster), function () { _this.loadContentOnFirstSlideLoad(index, $currentSlide, _speed); }, function () { _this.loadContentOnFirstSlideLoad(index, $currentSlide, _speed); }); } }, this.settings.startAnimationDuration + 100); } } // SLide content has been added to dom $currentSlide.addClass('lg-loaded'); if (!this.isFirstSlideWithZoomAnimation() || (this.getSlideType(currentGalleryItem) === 'video' && !poster)) { this.onLgObjectLoad($currentSlide, index, delay, _speed, isFirstSlide, !!(videoInfo && videoInfo.html5 && !poster)); } // When gallery is opened once content is loaded (second time) need to add lg-complete class for css styling if ((!this.zoomFromOrigin || !this.currentImageSize) && $currentSlide.hasClass('lg-complete_') && !this.lGalleryOn) { setTimeout(function () { $currentSlide.addClass('lg-complete'); }, this.settings.backdropDuration); } // Content loaded // Need to set lGalleryOn before calling preload function this.lGalleryOn = true; if (rec === true) { if (!$currentSlide.hasClass('lg-complete_')) { $currentSlide .find('.lg-object') .first() .on('load.lg error.lg', function () { _this.preload(index); }); } else { this.preload(index); } } }; /** * @desc Remove dummy image content and load next slides * Called only for the first time if zoomFromOrigin animation is enabled * @param index * @param $currentSlide * @param speed */ LightGallery.prototype.loadContentOnFirstSlideLoad = function (index, $currentSlide, speed) { var _this = this; setTimeout(function () { $currentSlide.find('.lg-dummy-img').remove(); $currentSlide.removeClass('lg-first-slide'); _this.outer.removeClass('lg-first-slide-loading'); _this.isDummyImageRemoved = true; _this.preload(index); }, speed + 300); }; LightGallery.prototype.getItemsToBeInsertedToDom = function (index, prevIndex, numberOfItems) { var _this = this; if (numberOfItems === void 0) { numberOfItems = 0; } var itemsToBeInsertedToDom = []; // Minimum 2 items should be there var possibleNumberOfItems = Math.max(numberOfItems, 3); possibleNumberOfItems = Math.min(possibleNumberOfItems, this.galleryItems.length); var prevIndexItem = "lg-item-" + this.lgId + "-" + prevIndex; if (this.galleryItems.length <= 3) { this.galleryItems.forEach(function (_element, index) { itemsToBeInsertedToDom.push("lg-item-" + _this.lgId + "-" + index); }); return itemsToBeInsertedToDom; } if (index < (this.galleryItems.length - 1) / 2) { for (var idx = index; idx > index - possibleNumberOfItems / 2 && idx >= 0; idx--) { itemsToBeInsertedToDom.push("lg-item-" + this.lgId + "-" + idx); } var numberOfExistingItems = itemsToBeInsertedToDom.length; for (var idx = 0; idx < possibleNumberOfItems - numberOfExistingItems; idx++) { itemsToBeInsertedToDom.push("lg-item-" + this.lgId + "-" + (index + idx + 1)); } } else { for (var idx = index; idx <= this.galleryItems.length - 1 && idx < index + possibleNumberOfItems / 2; idx++) { itemsToBeInsertedToDom.push("lg-item-" + this.lgId + "-" + idx); } var numberOfExistingItems = itemsToBeInsertedToDom.length; for (var idx = 0; idx < possibleNumberOfItems - numberOfExistingItems; idx++) { itemsToBeInsertedToDom.push("lg-item-" + this.lgId + "-" + (index - idx - 1)); } } if (this.settings.loop) { if (index === this.galleryItems.length - 1) { itemsToBeInsertedToDom.push("lg-item-" + this.lgId + "-" + 0); } else if (index === 0) { itemsToBeInsertedToDom.push("lg-item-" + this.lgId + "-" + (this.galleryItems.length - 1)); } } if (itemsToBeInsertedToDom.indexOf(prevIndexItem) === -1) { itemsToBeInsertedToDom.push("lg-item-" + this.lgId + "-" + prevIndex); } return itemsToBeInsertedToDom; }; LightGallery.prototype.organizeSlideItems = function (index, prevIndex) { var _this = this; var itemsToBeInsertedToDom = this.getItemsToBeInsertedToDom(index, prevIndex, this.settings.numberOfSlideItemsInDom); itemsToBeInsertedToDom.forEach(function (item) { if (_this.currentItemsInDom.indexOf(item) === -1) { _this.$inner.append("<div id=\"" + item + "\" class=\"lg-item\"></div>"); } }); this.currentItemsInDom.forEach(function (item) { if (itemsToBeInsertedToDom.indexOf(item) === -1) { lgQuery_1.$LG("#" + item).remove(); } }); return itemsToBeInsertedToDom; }; /** * Get previous index of the slide */ LightGallery.prototype.getPreviousSlideIndex = function () { var prevIndex = 0; try { var currentItemId = this.outer .find('.lg-current') .first() .attr('id'); prevIndex = parseInt(currentItemId.split('-')[3]) || 0; } catch (error) { prevIndex = 0; } return prevIndex; }; LightGallery.prototype.setDownloadValue = function (index) { if (this.settings.download) { var currentGalleryItem = this.galleryItems[index]; var hideDownloadBtn = currentGalleryItem.downloadUrl === false || currentGalleryItem.downloadUrl === 'false'; if (hideDownloadBtn) { this.outer.addClass('lg-hide-download'); } else { var $download = this.getElementById('lg-download'); this.outer.removeClass('lg-hide-download'); $download.attr('href', currentGalleryItem.downloadUrl || currentGalleryItem.src); if (currentGalleryItem.download) { $download.attr('download', currentGalleryItem.download); } } } }; LightGallery.prototype.makeSlideAnimation = function (direction, currentSlideItem, previousSlideItem) { var _this = this; if (this.lGalleryOn) { previousSlideItem.addClass('lg-slide-progress'); } setTimeout(function () { // remove all transitions _this.outer.addClass('lg-no-trans'); _this.outer .find('.lg-item') .removeClass('lg-prev-slide lg-next-slide'); if (direction === 'prev') { //prevslide currentSlideItem.addClass('lg-prev-slide'); previousSlideItem.addClass('lg-next-slide'); } else { // next slide currentSlideItem.addClass('lg-next-slide'); previousSlideItem.addClass('lg-prev-slide'); } // give 50 ms for browser to add/remove class setTimeout(function () { _this.outer.find('.lg-item').removeClass('lg-current'); currentSlideItem.addClass('lg-current'); // reset all transitions _this.outer.removeClass('lg-no-trans'); }, 50); }, this.lGalleryOn ? this.settings.slideDelay : 0); }; /** * Goto a specific slide. * @param {Number} index - index of the slide * @param {Boolean} fromTouch - true if slide function called via touch event or mouse drag *