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

3,806 lines • 137 kB
(function(global, factory) {
  typeof exports === "object" && typeof module !== "undefined" ? module.exports = factory() : typeof define === "function" && define.amd ? define(factory) : (global = typeof globalThis !== "undefined" ? globalThis : global || self, global.lightGallery = factory());
})(this, function() {
  "use strict";/*!
 * lightgallery | 3.0.0 | October 9th 2026
 * http://www.lightgalleryjs.com/
 * Copyright (c) 2020 Sachin Neravath;
 * @license GPLv3
 */

  function getVideoInfo(src, hasHtml5Video) {
    if (!src) {
      return hasHtml5Video ? { html5: true } : void 0;
    }
    const youtube = src.match(
      /\/\/(?:www\.)?youtu(?:\.be|be\.com|be-nocookie\.com)\/(?:watch\?v=|embed\/)?([a-z0-9\-_%]+)([&|?][\S]*)*/i
    );
    if (youtube) {
      return { youtube: [...youtube] };
    }
    const vimeo = src.match(
      /\/\/(?:www\.)?(?:player\.)?vimeo.com\/(?:video\/)?([0-9a-z\-_]+)(.*)?/i
    );
    if (vimeo) {
      return { vimeo: [...vimeo] };
    }
    const wistia = src.match(
      /https?:\/\/(.+)?(wistia\.com|wi\.st)\/(medias|embed)\/([0-9a-z\-_]+)(.*)/
    );
    if (wistia) {
      return { wistia: [...wistia] };
    }
    return hasHtml5Video ? { html5: true } : void 0;
  }
  function getYouTubePosterUrl(videoInfo) {
    if (!(videoInfo == null ? void 0 : videoInfo.youtube)) {
      return void 0;
    }
    return `//img.youtube.com/vi/${videoInfo.youtube[1]}/maxresdefault.jpg`;
  }
  function getFacadePoster(item, videoInfo, loadYouTubePoster) {
    if (!videoInfo || videoInfo.html5) {
      return item.poster || void 0;
    }
    return item.poster || (loadYouTubePoster ? getYouTubePosterUrl(videoInfo) : void 0) || item.thumb || void 0;
  }
  const TESTING_LICENSE_KEY = "0000-0000-000-0000";
  const LICENSE_KEY_PREFIX = "LIG";
  const LICENSE_DOCS = "https://www.lightgalleryjs.com/docs/license/";
  function checkLicenseKey(licenseKey) {
    const key = (licenseKey != null ? licenseKey : "").trim();
    if (!key) {
      return {
        level: "error",
        message: `lightGallery: please provide a valid license key. See ${LICENSE_DOCS}`
      };
    }
    if (key === TESTING_LICENSE_KEY) {
      return {
        level: "warn",
        message: `lightGallery: ${key} license key is not valid for production use. See ${LICENSE_DOCS}`
      };
    }
    if (!key.startsWith(LICENSE_KEY_PREFIX)) {
      return {
        level: "warn",
        message: `lightGallery: this license key is for v1 or v2 and is not valid for v3. Please upgrade to a v3 license. See ${LICENSE_DOCS}`
      };
    }
    return null;
  }
  let pageLicenseKey;
  const loggedNotices = /* @__PURE__ */ new Set();
  function setLicenseKey(licenseKey) {
    pageLicenseKey = licenseKey;
  }
  function resolveLicenseKey(instanceKey) {
    const own = (instanceKey != null ? instanceKey : "").trim();
    if (pageLicenseKey !== void 0 && (!own || own === TESTING_LICENSE_KEY)) {
      return pageLicenseKey;
    }
    return instanceKey != null ? instanceKey : TESTING_LICENSE_KEY;
  }
  function takeLicenseNotice(instanceKey) {
    const notice = checkLicenseKey(resolveLicenseKey(instanceKey));
    if (!notice || loggedNotices.has(notice.message)) return null;
    loggedNotices.add(notice.message);
    return notice;
  }
  function formatSlideAnnouncement(options) {
    const base = options.template.replace("{index}", String(options.index)).replace("{total}", String(options.total));
    const caption = (options.caption || "").replace(/\s+/g, " ").trim();
    return caption ? `${base}, ${caption}` : base;
  }
  const SPRING_SETTLE_DAMPING = 1;
  const SPRING_NATURAL_FREQUENCY = 12;
  const DECELERATION_RATE = 0.995;
  function project(velocity, decelerationRate = DECELERATION_RATE) {
    return velocity * decelerationRate / (1 - decelerationRate);
  }
  function stepSpring(state, target, dtMs, {
    dampingRatio = SPRING_SETTLE_DAMPING,
    naturalFrequency = SPRING_NATURAL_FREQUENCY
  } = {}) {
    const t = dtMs / 1e3;
    const w0 = naturalFrequency;
    const zeta = Math.min(dampingRatio, 1);
    const x0 = state.position - target;
    const v0 = state.velocity * 1e3;
    const decay = Math.exp(-zeta * w0 * t);
    let x;
    let v;
    if (zeta < 1) {
      const wd = w0 * Math.sqrt(1 - zeta * zeta);
      const a = x0;
      const b = (v0 + zeta * w0 * x0) / wd;
      const cos = Math.cos(wd * t);
      const sin = Math.sin(wd * t);
      x = decay * (a * cos + b * sin);
      v = decay * ((b * wd - zeta * w0 * a) * cos - (a * wd + zeta * w0 * b) * sin);
    } else {
      const b = v0 + w0 * x0;
      x = decay * (x0 + b * t);
      v = decay * (b - w0 * (x0 + b * t));
    }
    return { position: target + x, velocity: v / 1e3 };
  }
  function isSpringSettled(state, target, restDelta = 0.3, restVelocity = 0.012) {
    return Math.abs(state.position - target) < restDelta && Math.abs(state.velocity) < restVelocity;
  }
  const SWIPE_AXIS_THRESHOLD = 10;
  const FLICK_VELOCITY = 0.5;
  const FLICK_MIN_DISTANCE = 20;
  const VERTICAL_CLOSE_THRESHOLD = 100;
  const VERTICAL_CLOSE_RATIO = 0.4;
  const VERTICAL_CLOSE_MIN_DRAG = 40;
  const SLIDE_EDGE_FRICTION = 0.35;
  function getEdgeFrictionedDelta(deltaX, hasPrev, hasNext, direction = "ltr") {
    const [towardPrev, towardNext] = direction === "rtl" ? [hasNext, hasPrev] : [hasPrev, hasNext];
    if (deltaX > 0 && !towardPrev || deltaX < 0 && !towardNext) {
      return deltaX * SLIDE_EDGE_FRICTION;
    }
    return deltaX;
  }
  function getSwipeAxis(deltaX, deltaY, current) {
    if (current) {
      return current;
    }
    if (Math.abs(deltaX) > SWIPE_AXIS_THRESHOLD) {
      return "horizontal";
    }
    if (Math.abs(deltaY) > SWIPE_AXIS_THRESHOLD) {
      return "vertical";
    }
    return void 0;
  }
  function getHorizontalDragTransforms(deltaX, slideWidth, direction = "ltr") {
    const slideWidthAmount = slideWidth * 15 / 100;
    const gutter = slideWidthAmount - Math.abs(deltaX * 10 / 100);
    const before = `translate3d(${-slideWidth + deltaX - gutter}px, 0px, 0px)`;
    const after = `translate3d(${slideWidth + deltaX + gutter}px, 0px, 0px)`;
    return {
      current: `translate3d(${deltaX}px, 0px, 0px)`,
      // In RTL the prev slide rests to the physical right (lg-rtl.css
      // flips the resting positions the same way).
      prev: direction === "rtl" ? after : before,
      next: direction === "rtl" ? before : after
    };
  }
  function getVerticalDragEffects(deltaY, viewportWidth, viewportHeight) {
    const distance = Math.abs(deltaY);
    const scale = 1 - distance / (viewportWidth * 2);
    return {
      backdropOpacity: 1 - distance / viewportHeight,
      transform: `translate3d(0px, ${deltaY}px, 0px) scale3d(${scale}, ${scale}, 1)`,
      hideUi: distance > VERTICAL_CLOSE_THRESHOLD
    };
  }
  function getSwipeReleaseVerdict({
    deltaX,
    velocityX,
    threshold,
    flickVelocity = FLICK_VELOCITY,
    viewportWidth,
    direction = "ltr"
  }) {
    const distance = Math.abs(deltaX);
    const directionMatches = deltaX !== 0 && Math.sign(velocityX) === Math.sign(deltaX);
    const projected = deltaX + project(velocityX);
    const passes = distance > threshold || distance > FLICK_MIN_DISTANCE && directionMatches && Math.abs(velocityX) > flickVelocity || viewportWidth !== void 0 && distance > FLICK_MIN_DISTANCE && directionMatches && Math.abs(projected) > viewportWidth / 2;
    if (!passes) {
      return "stay";
    }
    const towardNext = direction === "rtl" ? deltaX > 0 : deltaX < 0;
    return towardNext ? "next" : "prev";
  }
  function shouldCloseOnVerticalDrag(deltaY, velocityY, viewportHeight, options) {
    if (!options.closable || !options.swipeToClose || deltaY === 0) {
      return false;
    }
    if (Math.abs(deltaY) < VERTICAL_CLOSE_MIN_DRAG) {
      return false;
    }
    const projected = deltaY + project(velocityY);
    return Math.sign(projected) === Math.sign(deltaY) && Math.abs(projected) > VERTICAL_CLOSE_RATIO * viewportHeight;
  }
  function resolveSwipeTarget(verdict, currentIndex, slidesCount, loop) {
    if (verdict === "stay") {
      return null;
    }
    const touchLoop = loop && slidesCount >= 3;
    if (verdict === "next") {
      if (currentIndex + 1 < slidesCount) {
        return currentIndex + 1;
      }
      return touchLoop ? 0 : null;
    }
    if (currentIndex > 0) {
      return currentIndex - 1;
    }
    return touchLoop ? slidesCount - 1 : null;
  }
  function parseImageSize(lgSize, viewportWidth) {
    if (!lgSize) {
      return void 0;
    }
    let size = lgSize;
    const responsiveSizes = lgSize.split(",");
    if (responsiveSizes[1]) {
      for (let i = 0; i < responsiveSizes.length; i++) {
        const candidate = responsiveSizes[i].trim();
        const responsiveWidth = parseInt(candidate.split("-")[2], 10);
        if (responsiveWidth > viewportWidth) {
          size = candidate;
          break;
        }
        if (i === responsiveSizes.length - 1) {
          size = candidate;
        }
      }
    }
    const parts = size.trim().split("-");
    const width = parseInt(parts[0], 10);
    const height = parseInt(parts[1], 10);
    if (!Number.isFinite(width) || !Number.isFinite(height)) {
      return void 0;
    }
    return { width, height };
  }
  function fitImageSize(size, containerWidth, containerHeight) {
    const maxWidth = Math.min(containerWidth, size.width);
    const maxHeight = Math.min(containerHeight, size.height);
    const ratio = Math.min(maxWidth / size.width, maxHeight / size.height);
    return { width: size.width * ratio, height: size.height * ratio };
  }
  function isUsableOriginRect(rect) {
    return !!rect && Number.isFinite(rect.left) && Number.isFinite(rect.top) && rect.width > 0 && rect.height > 0;
  }
  const CENTER_CLOSE_SCALE = 0.5;
  function getCenterCloseTransform(scale = CENTER_CLOSE_SCALE) {
    return `translate3d(0, 0, 0) scale3d(${scale}, ${scale}, 1)`;
  }
  function getOriginTransform(input) {
    const { triggerRect, containerRect, top, bottom, imageSize } = input;
    const availableWidth = containerRect.width;
    const availableHeight = containerRect.height - (top + bottom);
    const x = (availableWidth - triggerRect.width) / 2 - triggerRect.left + containerRect.left;
    const y = (availableHeight - triggerRect.height) / 2 - triggerRect.top + top;
    const scaleX = triggerRect.width / imageSize.width;
    const scaleY = triggerRect.height / imageSize.height;
    return `translate3d(${-x}px, ${-y}px, 0) scale3d(${scaleX}, ${scaleY}, 1)`;
  }
  const coreDefaultIcons = {
    close: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024" fill="currentColor"><path transform="translate(0, 960) scale(1, -1)" d="M810 664.667l-238-238 238-238-60-60-238 238-238-238-60 60 238 238-238 238 60 60 238-238 238 238z"/></svg>',
    // Three dots for the toolbar's More options menu button.
    more: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024" fill="currentColor"><circle cx="232" cy="512" r="80"/><circle cx="512" cy="512" r="80"/><circle cx="792" cy="512" r="80"/></svg>',
    prev: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024" fill="currentColor"><path transform="translate(0, 960) scale(1, -1)" d="M426.667 768q17.667 0 30.167-12.5t12.5-30.167q0-18-12.667-30.333l-225.667-225.667h665q17.667 0 30.167-12.5t12.5-30.167-12.5-30.167-30.167-12.5h-665l225.667-225.667q12.667-12.333 12.667-30.333 0-17.667-12.5-30.167t-30.167-12.5q-18 0-30.333 12.333l-298.667 298.667q-12.333 13-12.333 30.333t12.333 30.333l298.667 298.667q12.667 12.333 30.333 12.333z"/></svg>',
    next: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024" fill="currentColor"><path transform="translate(0, 960) scale(1, -1)" d="M597.333 768q18 0 30.333-12.333l298.667-298.667q12.333-12.333 12.333-30.333t-12.333-30.333l-298.667-298.667q-12.333-12.333-30.333-12.333-18.333 0-30.5 12.167t-12.167 30.5q0 18 12.333 30.333l226 225.667h-665q-17.667 0-30.167 12.5t-12.5 30.167 12.5 30.167 30.167 12.5h665l-226 225.667q-12.333 12.333-12.333 30.333 0 18.333 12.167 30.5t30.5 12.167z"/></svg>',
    download: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024" fill="currentColor"><path transform="translate(0, 960) scale(1, -1)" d="M170 128.667h684v-86h-684v86zM682 384.667l-170-172-170 172h128v426h84v-426h128z"/></svg>',
    maximize: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024" fill="currentColor"><path transform="translate(0, 960) scale(1, -1)" d="M793.003 768l-225.835-225.835c-16.683-16.683-16.683-43.691 0-60.331s43.691-16.683 60.331 0l225.835 225.835v-153.003c0-23.552 19.115-42.667 42.667-42.667s42.667 19.115 42.667 42.667v256c0 5.803-1.152 11.307-3.243 16.341s-5.163 9.728-9.216 13.781c-0.043 0.043-0.043 0.043-0.085 0.085-3.925 3.925-8.619 7.083-13.781 9.216-5.035 2.091-10.539 3.243-16.341 3.243h-256c-23.552 0-42.667-19.115-42.667-42.667s19.115-42.667 42.667-42.667zM230.997 85.334l225.835 225.835c16.683 16.683 16.683 43.691 0 60.331s-43.691 16.683-60.331 0l-225.835-225.835v153.003c0 23.552-19.115 42.667-42.667 42.667s-42.667-19.115-42.667-42.667v-256c0-23.552 19.115-42.667 42.667-42.667h256c23.552 0 42.667 19.115 42.667 42.667s-19.115 42.667-42.667 42.667z"/></svg>',
    minimize: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024" fill="currentColor"><path transform="translate(0, 960) scale(1, -1)" d="M700.331 554.667l225.835 225.835c16.683 16.683 16.683 43.691 0 60.331s-43.691 16.683-60.331 0l-225.835-225.835v153.003c0 23.552-19.115 42.667-42.667 42.667s-42.667-19.115-42.667-42.667v-256c0-5.803 1.152-11.307 3.243-16.341s5.163-9.728 9.216-13.781c0.043-0.043 0.043-0.043 0.085-0.085 3.925-3.925 8.619-7.083 13.781-9.216 5.035-2.091 10.539-3.243 16.341-3.243h256c23.552 0 42.667 19.115 42.667 42.667s-19.115 42.667-42.667 42.667zM158.165 12.502l225.835 225.835v-153.003c0-23.552 19.115-42.667 42.667-42.667s42.667 19.115 42.667 42.667v256c0 5.803-1.152 11.307-3.243 16.341s-5.163 9.728-9.216 13.781c-0.043 0.043-0.043 0.043-0.085 0.085-4.096 4.053-8.789 7.125-13.781 9.216-5.035 2.091-10.539 3.243-16.341 3.243h-256c-23.552 0-42.667-19.115-42.667-42.667s19.115-42.667 42.667-42.667h153.003l-225.835-225.835c-16.683-16.683-16.683-43.691 0-60.331s43.691-16.683 60.331 0z"/></svg>'
  };
  var __defProp$1 = Object.defineProperty;
  var __defProps$1 = Object.defineProperties;
  var __getOwnPropDescs$1 = Object.getOwnPropertyDescriptors;
  var __getOwnPropSymbols$1 = Object.getOwnPropertySymbols;
  var __hasOwnProp$1 = Object.prototype.hasOwnProperty;
  var __propIsEnum$1 = Object.prototype.propertyIsEnumerable;
  var __defNormalProp$1 = (obj, key, value) => key in obj ? __defProp$1(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
  var __spreadValues$1 = (a, b) => {
    for (var prop in b || (b = {}))
      if (__hasOwnProp$1.call(b, prop))
        __defNormalProp$1(a, prop, b[prop]);
    if (__getOwnPropSymbols$1)
      for (var prop of __getOwnPropSymbols$1(b)) {
        if (__propIsEnum$1.call(b, prop))
          __defNormalProp$1(a, prop, b[prop]);
      }
    return a;
  };
  var __spreadProps$1 = (a, b) => __defProps$1(a, __getOwnPropDescs$1(b));
  const TOOLBAR_PINNED = Number.POSITIVE_INFINITY;
  const TOOLBAR_DEFAULT_PRIORITY = 20;
  const PRIORITY_BY_CLASS = [
    ["lg-close", TOOLBAR_PINNED],
    ["lg-share", 30],
    ["lg-autoplay-button", 30],
    ["lg-download", 30],
    ["lg-fullscreen", 20],
    ["lg-toggle-thumb", 20],
    ["lg-comment-toggle", 20],
    ["lg-maximize", 10],
    ["lg-rotate-left", 10],
    ["lg-rotate-right", 10],
    ["lg-flip-hor", 10],
    ["lg-flip-ver", 10],
    // Gesture duplicates go first: pinch and double-tap do the same. The
    // actual-size button carries one of these two classes as well.
    ["lg-zoom-in", 0],
    ["lg-zoom-out", 0]
  ];
  function getToolbarItemPriority(classList) {
    const classes = new Set(classList);
    for (const [className, priority] of PRIORITY_BY_CLASS) {
      if (classes.has(className)) {
        return priority;
      }
    }
    return TOOLBAR_DEFAULT_PRIORITY;
  }
  function getToolbarOverflow({
    available,
    reserved,
    moreWidth,
    items
  }) {
    if (available <= 0) {
      return [];
    }
    const total = items.reduce((sum, item) => sum + item.width, 0);
    if (reserved + total <= available) {
      return [];
    }
    const candidates = items.map((item, index) => __spreadProps$1(__spreadValues$1({}, item), { index })).filter((item) => item.priority !== TOOLBAR_PINNED).sort((a, b) => a.priority - b.priority || b.index - a.index);
    let used = reserved + moreWidth + total;
    const moved = [];
    for (const item of candidates) {
      if (used <= available) {
        break;
      }
      moved.push(item.index);
      used -= item.width;
    }
    return moved.sort((a, b) => a - b);
  }
  const BACKDROP_CLASS_NAMES = [
    "lg-outer",
    "lg-item",
    "lg-img-wrap",
    "lg-img-rotate"
  ];
  function consumeBackdropPress(event) {
    var _a;
    const classList = (_a = event.target) == null ? void 0 : _a.classList;
    if (!classList || !BACKDROP_CLASS_NAMES.some((name) => classList.contains(name))) {
      return false;
    }
    event.preventDefault();
    event.stopPropagation();
    return true;
  }
  function onTransitionSettle(element, property, fallbackMs, callback) {
    let settled = false;
    let timer;
    const isOwn = (event) => event.target === element && event.propertyName === property;
    const dispose = () => {
      clearTimeout(timer);
      element.removeEventListener("transitionstart", onStart);
      element.removeEventListener("transitionend", onEnd);
    };
    const settle = () => {
      if (settled) {
        return;
      }
      settled = true;
      dispose();
      callback();
    };
    const onStart = (event) => {
      if (isOwn(event)) {
        clearTimeout(timer);
        timer = setTimeout(settle, fallbackMs);
      }
    };
    const onEnd = (event) => {
      if (isOwn(event)) {
        settle();
      }
    };
    element.addEventListener("transitionstart", onStart);
    element.addEventListener("transitionend", onEnd);
    timer = setTimeout(settle, fallbackMs);
    return () => {
      settled = true;
      dispose();
    };
  }
  const DECODE_TIMEOUT_MS = 500;
  function awaitDecode(img, timeoutMs = DECODE_TIMEOUT_MS) {
    if (typeof img.decode !== "function") {
      return Promise.resolve();
    }
    return new Promise((resolve) => {
      let done = false;
      const finish = () => {
        if (!done) {
          done = true;
          clearTimeout(timer);
          resolve();
        }
      };
      const timer = setTimeout(finish, timeoutMs);
      img.decode().then(finish, finish);
    });
  }
  const VELOCITY_WINDOW_MS = 100;
  const MIN_DISPLACEMENT = 1;
  const MIN_WINDOW_SPAN_MS = 5;
  function pushVelocitySample(samples, sample, windowMs = VELOCITY_WINDOW_MS) {
    return [...samples.filter((s) => sample.t - s.t <= windowMs), sample];
  }
  function getWindowedVelocity(samples, releaseTime, windowMs = VELOCITY_WINDOW_MS) {
    const recent = samples.filter((s) => releaseTime - s.t <= windowMs);
    if (recent.length < 2) {
      return { x: 0, y: 0 };
    }
    const first = recent[0];
    const last = recent[recent.length - 1];
    const dt = last.t - first.t;
    if (dt < MIN_WINDOW_SPAN_MS) {
      return { x: 0, y: 0 };
    }
    const dx = last.x - first.x;
    const dy = last.y - first.y;
    return {
      x: Math.abs(dx) > MIN_DISPLACEMENT ? dx / dt : 0,
      y: Math.abs(dy) > MIN_DISPLACEMENT ? dy / dt : 0
    };
  }
  const lGEvents = {
    afterAppendSlide: "lgAfterAppendSlide",
    init: "lgInit",
    hasVideo: "lgHasVideo",
    containerResize: "lgContainerResize",
    updateSlides: "lgUpdateSlides",
    afterAppendSubHtml: "lgAfterAppendSubHtml",
    beforeOpen: "lgBeforeOpen",
    afterOpen: "lgAfterOpen",
    slideItemLoad: "lgSlideItemLoad",
    beforeSlide: "lgBeforeSlide",
    afterSlide: "lgAfterSlide",
    posterClick: "lgPosterClick",
    dragStart: "lgDragStart",
    dragMove: "lgDragMove",
    dragEnd: "lgDragEnd",
    beforeNextSlide: "lgBeforeNextSlide",
    beforePrevSlide: "lgBeforePrevSlide",
    beforeClose: "lgBeforeClose",
    afterClose: "lgAfterClose"
  };
  const lightGalleryCoreSettings = {
    mode: "lg-slide",
    easing: "ease",
    speed: 400,
    licenseKey: "0000-0000-000-0000",
    height: "100%",
    width: "100%",
    addClass: "",
    startClass: "lg-start-zoom",
    backdropDuration: 300,
    container: "",
    startAnimationDuration: 400,
    zoomFromOrigin: true,
    hideBarsDelay: 0,
    showBarsAfter: 1e4,
    slideDelay: 0,
    allowMediaOverlap: false,
    videoMaxSize: "1280-720",
    loadYouTubePoster: true,
    defaultCaptionHeight: 0,
    ariaLabelledby: "",
    ariaDescribedby: "",
    ariaAnnouncements: true,
    resetScrollPosition: true,
    hideScrollbar: false,
    closable: true,
    swipeToClose: true,
    closeOnTap: true,
    showCloseIcon: true,
    showMaximizeIcon: false,
    loop: true,
    escKey: true,
    keyPress: true,
    trapFocus: true,
    controls: true,
    slideEndAnimation: true,
    hideControlOnEnd: false,
    mousewheel: false,
    direction: "ltr",
    getCaptionFromTitleOrAlt: true,
    appendSubHtmlTo: ".lg-sub-html",
    subHtmlSelectorRelative: false,
    preload: 2,
    numberOfSlideItemsInDom: 10,
    selector: "",
    selectWithin: "",
    nextHtml: "",
    prevHtml: "",
    index: 0,
    iframeWidth: "100%",
    iframeHeight: "100%",
    iframeMaxWidth: "100%",
    iframeMaxHeight: "100%",
    download: true,
    counter: true,
    appendCounterTo: ".lg-toolbar",
    swipeThreshold: 50,
    flickVelocity: 0.5,
    pinchToClose: true,
    enableSwipe: true,
    enableDrag: true,
    dynamic: false,
    dynamicEl: [],
    extraProps: [],
    exThumbImage: "",
    toolbarOverflow: true,
    showGestureButtons: true,
    isMobile: void 0,
    mobileSettings: {
      controls: false,
      showCloseIcon: false,
      download: false,
      showGestureButtons: false
    },
    plugins: [],
    strings: {
      closeGallery: "Close gallery",
      toggleMaximize: "Toggle maximize",
      previousSlide: "Previous slide",
      nextSlide: "Next slide",
      download: "Download",
      playVideo: "Play video",
      mediaLoadingFailed: "Oops... Failed to load content...",
      galleryLabel: "Gallery",
      slideAnnouncement: "Image {index} of {total}",
      moreOptions: "More options",
      share: "Share",
      toggleThumbnails: "Toggle thumbnails",
      toggleAutoplay: "Toggle Autoplay",
      toggleFullscreen: "Toggle Fullscreen",
      zoomIn: "Zoom in",
      zoomOut: "Zoom out",
      viewActualSize: "View actual size",
      rotateLeft: "Rotate left",
      rotateRight: "Rotate right",
      flipHorizontal: "Flip horizontal",
      flipVertical: "Flip vertical",
      toggleComments: "Toggle Comments"
    },
    icons: {}
  };
  const schedule = typeof requestAnimationFrame === "function" ? (callback) => requestAnimationFrame(callback) : (callback) => window.setTimeout(callback, 16);
  const cancel = typeof cancelAnimationFrame === "function" ? (handle) => cancelAnimationFrame(handle) : (handle) => window.clearTimeout(handle);
  function toolbarButtons(toolbar, more) {
    return Array.from(toolbar.querySelectorAll(".lg-icon")).filter(
      (button) => {
        var _a;
        return button !== more && !button.closest(".lg-toolbar-menu, .lg-dropdown") && !((_a = button.parentElement) == null ? void 0 : _a.closest(".lg-icon"));
      }
    );
  }
  function visibleIconMarkup(button) {
    var _a, _b, _c;
    const icons = Array.from(button.querySelectorAll(".lg-ci"));
    if (!icons.length) {
      return (_b = (_a = button.querySelector("svg")) == null ? void 0 : _a.outerHTML) != null ? _b : "";
    }
    const shown = (_c = icons.find(
      (icon) => window.getComputedStyle(icon).display !== "none"
    )) != null ? _c : icons[0];
    return shown.outerHTML;
  }
  class ToolbarOverflow {
    constructor(toolbar, options) {
      this.toolbar = toolbar;
      this.options = options;
      this.menu = null;
      this.frame = 0;
      this.movedSignature = "";
      this.widths = /* @__PURE__ */ new WeakMap();
      this.requestUpdate = () => {
        if (this.frame) {
          return;
        }
        this.frame = schedule(() => {
          this.frame = 0;
          this.update();
        });
      };
      this.onMoreClick = () => {
        if (this.menu) {
          this.close(true);
        } else {
          this.open();
        }
      };
      this.onMenuKeydown = (event) => {
        var _a, _b, _c, _d;
        const items = this.items();
        const index = items.indexOf(document.activeElement);
        switch (event.key) {
          case "Escape":
            this.close(true);
            break;
          case "ArrowDown":
            (_a = items[(index + 1) % items.length]) == null ? void 0 : _a.focus();
            break;
          case "ArrowUp":
            (_b = items[(index - 1 + items.length) % items.length]) == null ? void 0 : _b.focus();
            break;
          case "Home":
            (_c = items[0]) == null ? void 0 : _c.focus();
            break;
          case "End":
            (_d = items[items.length - 1]) == null ? void 0 : _d.focus();
            break;
          case "ArrowLeft":
          case "ArrowRight":
            break;
          case "Tab":
            this.close(false);
            return;
          default:
            return;
        }
        event.preventDefault();
        event.stopPropagation();
      };
      this.onDocumentPointerDown = (event) => {
        var _a;
        const target = event.target;
        if (target && (((_a = this.menu) == null ? void 0 : _a.contains(target)) || this.more.contains(target))) {
          return;
        }
        consumeBackdropPress(event);
        this.close(false);
      };
      const more = document.createElement("button");
      more.type = "button";
      more.id = options.id;
      more.className = "lg-more lg-icon";
      more.hidden = true;
      more.setAttribute("aria-label", options.label);
      more.setAttribute("aria-haspopup", "menu");
      more.setAttribute("aria-expanded", "false");
      more.addEventListener("click", this.onMoreClick);
      const close = toolbar.querySelector(".lg-close");
      if (close) {
        close.insertAdjacentElement("afterend", more);
      } else {
        toolbar.insertBefore(more, toolbar.firstChild);
      }
      this.more = more;
      if (typeof ResizeObserver === "function") {
        this.resizeObserver = new ResizeObserver(this.requestUpdate);
        this.resizeObserver.observe(toolbar);
      }
      if (typeof MutationObserver === "function") {
        this.mutationObserver = new MutationObserver((records) => {
          if (records.some(
            (record) => {
              var _a, _b;
              return !((_b = (_a = record.target).closest) == null ? void 0 : _b.call(
                _a,
                ".lg-toolbar-menu"
              ));
            }
          )) {
            this.requestUpdate();
          }
        });
        this.mutationObserver.observe(toolbar, {
          childList: true,
          subtree: true
        });
      }
    }
    /** Re-measure the row and move buttons in or out of the menu. */
    update() {
      var _a, _b;
      const buttons = toolbarButtons(this.toolbar, this.more);
      buttons.forEach((button) => {
        if (!button.hasAttribute("data-lg-overflow")) {
          const width = button.offsetWidth;
          if (width) {
            this.widths.set(button, width);
          }
        }
      });
      const fallback = (_a = buttons.map((button) => this.widths.get(button)).find((width) => !!width)) != null ? _a : 0;
      const counter = this.toolbar.querySelector(".lg-counter");
      const moved = getToolbarOverflow({
        available: this.toolbar.clientWidth,
        reserved: counter ? counter.offsetWidth : 0,
        moreWidth: (_b = this.widths.get(this.more)) != null ? _b : fallback,
        items: buttons.map((button) => {
          var _a2;
          return {
            width: (_a2 = this.widths.get(button)) != null ? _a2 : fallback,
            priority: getToolbarItemPriority(Array.from(button.classList))
          };
        })
      });
      const overflow = new Set(moved);
      buttons.forEach((button, index) => {
        if (overflow.has(index)) {
          button.setAttribute("data-lg-overflow", "");
        } else {
          button.removeAttribute("data-lg-overflow");
        }
      });
      this.more.hidden = overflow.size === 0;
      if (!this.more.hidden && this.more.offsetWidth) {
        this.widths.set(this.more, this.more.offsetWidth);
      }
      const signature = `${buttons.length}:${moved.join(",")}`;
      const changed = signature !== this.movedSignature;
      this.movedSignature = signature;
      if (!overflow.size) {
        this.close(false);
      } else if (this.menu && changed) {
        this.renderMenu();
      }
    }
    /** Close the menu; optionally hand focus back to the More button. */
    close(returnFocus) {
      if (!this.menu) {
        return;
      }
      this.menu.removeEventListener("keydown", this.onMenuKeydown);
      this.menu.remove();
      this.menu = null;
      document.removeEventListener(
        "pointerdown",
        this.onDocumentPointerDown,
        true
      );
      this.more.setAttribute("aria-expanded", "false");
      this.more.removeAttribute("aria-controls");
      if (returnFocus) {
        this.more.focus();
      }
    }
    destroy() {
      var _a, _b;
      this.close(false);
      cancel(this.frame);
      (_a = this.resizeObserver) == null ? void 0 : _a.disconnect();
      (_b = this.mutationObserver) == null ? void 0 : _b.disconnect();
      toolbarButtons(this.toolbar, this.more).forEach(
        (button) => button.removeAttribute("data-lg-overflow")
      );
      this.more.remove();
    }
    open() {
      var _a;
      const menu = document.createElement("div");
      menu.id = `${this.options.id}-menu`;
      menu.className = "lg-toolbar-menu";
      menu.setAttribute("role", "menu");
      menu.setAttribute("aria-label", this.options.label);
      menu.addEventListener("keydown", this.onMenuKeydown);
      this.menu = menu;
      this.renderMenu();
      this.toolbar.appendChild(menu);
      this.more.setAttribute("aria-expanded", "true");
      this.more.setAttribute("aria-controls", menu.id);
      document.addEventListener(
        "pointerdown",
        this.onDocumentPointerDown,
        true
      );
      (_a = this.items()[0]) == null ? void 0 : _a.focus();
    }
    renderMenu() {
      const menu = this.menu;
      if (!menu) {
        return;
      }
      menu.textContent = "";
      toolbarButtons(this.toolbar, this.more).filter((button) => button.hasAttribute("data-lg-overflow")).forEach((button) => {
        var _a;
        const item = document.createElement("button");
        item.type = "button";
        item.className = "lg-toolbar-menu-item";
        item.setAttribute("role", "menuitem");
        const icon = document.createElement("span");
        icon.className = "lg-toolbar-menu-icon";
        icon.setAttribute("aria-hidden", "true");
        icon.innerHTML = visibleIconMarkup(button);
        const label = document.createElement("span");
        label.textContent = (_a = button.getAttribute("aria-label")) != null ? _a : "";
        item.append(icon, label);
        item.addEventListener("click", () => {
          this.close(true);
          button.click();
        });
        menu.appendChild(item);
      });
    }
    items() {
      return this.menu ? Array.from(
        this.menu.querySelectorAll('[role="menuitem"]')
      ) : [];
    }
  }
  const ICON_TARGETS = [
    { selector: ".lg-close", names: ["close"] },
    { selector: ".lg-prev", names: ["prev"] },
    { selector: ".lg-next", names: ["next"] },
    { selector: ".lg-download", names: ["download"] },
    { selector: ".lg-more", names: ["more"] },
    // Shown while `.lg-inline` (prompting maximize) / after maximizing.
    { selector: ".lg-maximize", names: ["maximize", "minimize"] },
    // The actual-size button's CLASS toggles between the two zoom
    // classes as the zoom state changes (2.x swapped the glyph that
    // way), it carries BOTH zoom icons and the class picks one in
    // CSS. Listed before the class-based zoom targets so the id match
    // claims it first (the pass skips already-processed elements).
    { selector: '[id^="lg-actual-size-"]', names: ["zoomIn", "zoomOut"] },
    { selector: ".lg-zoom-in", names: ["zoomIn"] },
    { selector: ".lg-zoom-out", names: ["zoomOut"] },
    // No '.lg-actual-size' target: vanilla's actual-size BUTTON never
    // carries that class (it rides the zoom classes above; the outer
    // gets `lg-actual-size` as a zoom-state class after build). The
    // `actualSize` name serves the framework ports' static button.
    { selector: ".lg-rotate-left", names: ["rotateLeft"] },
    { selector: ".lg-rotate-right", names: ["rotateRight"] },
    { selector: ".lg-flip-hor", names: ["flipHorizontal"] },
    { selector: ".lg-flip-ver", names: ["flipVertical"] },
    { selector: ".lg-share", names: ["share"] },
    { selector: ".lg-share-facebook .lg-icon", names: ["shareFacebook"] },
    { selector: ".lg-share-twitter .lg-icon", names: ["shareX"] },
    { selector: ".lg-share-pinterest .lg-icon", names: ["sharePinterest"] },
    // Shown while idle (prompting play) / while `.lg-show-autoplay`.
    {
      selector: ".lg-autoplay-button",
      names: ["autoplayPlay", "autoplayPause"]
    },
    // Shown while windowed / while `.lg-fullscreen-on`.
    { selector: ".lg-fullscreen", names: ["fullscreen", "fullscreenExit"] },
    { selector: ".lg-comment-toggle", names: ["comment"] },
    { selector: ".lg-comment-close", names: ["commentClose"] },
    { selector: ".lg-toggle-thumb", names: ["toggleThumbnails"] }
  ];
  const toKebab = (name) => name.replace(/[A-Z]/g, (char) => `-${char.toLowerCase()}`);
  function getCustomIconMarkup(icons, names) {
    if (!names.every((name) => icons[name])) {
      return "";
    }
    return names.map(
      (name) => `<span class="lg-ci lg-ci-${toKebab(
        name
      )}" aria-hidden="true">${icons[name]}</span>`
    ).join("");
  }
  function applyCustomIcons(container, defaults, overrides) {
    ICON_TARGETS.forEach(({ selector, names }) => {
      const source = overrides && names.every((name) => overrides[name]) ? overrides : defaults;
      const markup = getCustomIconMarkup(source, names);
      if (!markup) {
        return;
      }
      container.querySelectorAll(selector).forEach((element) => {
        if (element.classList.contains("lg-icon-custom")) {
          return;
        }
        element.classList.add("lg-icon-custom");
        element.insertAdjacentHTML("afterbegin", markup);
      });
    });
  }
  const MAX_FRAME_MS = 64;
  function runSprings(tracks, onFrame, onDone) {
    let raf = 0;
    let last = Date.now();
    const states = tracks.map((t) => ({
      position: t.from,
      velocity: t.velocity
    }));
    const frame = () => {
      const now = Date.now();
      const dt = Math.min(Math.max(now - last, 0), MAX_FRAME_MS);
      last = now;
      let settled = true;
      tracks.forEach((t, i) => {
        states[i] = stepSpring(states[i], t.target, dt, t);
        if (!isSpringSettled(states[i], t.target)) {
          settled = false;
        }
      });
      if (settled) {
        onFrame(tracks.map((t) => t.target));
        onDone == null ? void 0 : onDone();
        return;
      }
      onFrame(states.map((s) => s.position));
      raf = requestAnimationFrame(frame);
    };
    raf = requestAnimationFrame(frame);
    return () => cancelAnimationFrame(raf);
  }
  const _lgQuery = class _lgQuery2 {
    constructor(selector) {
      this.cssVenderPrefixes = [
        "TransitionDuration",
        "TransitionTimingFunction",
        "Transform",
        "Transition"
      ];
      this.selector = this._getSelector(selector);
      this.firstElement = this._getFirstEl();
      return this;
    }
    static generateUUID() {
      return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(
        /[xy]/g,
        function(c) {
          const r = Math.random() * 16 | 0, v = c == "x" ? r : r & 3 | 8;
          return v.toString(16);
        }
      );
    }
    _getSelector(selector, context = document) {
      if (typeof selector !== "string") {
        return selector;
      }
      context = context || document;
      const fl = selector.substring(0, 1);
      if (fl === "#") {
        return context.querySelector(selector);
      } else {
        return context.querySelectorAll(selector);
      }
    }
    _each(func) {
      if (!this.selector) {
        return this;
      }
      if (this.selector.length !== void 0) {
        [].forEach.call(this.selector, func);
      } else {
        func(this.selector, 0);
      }
      return this;
    }
    _setCssVendorPrefix(el, cssProperty, value) {
      if (cssProperty.startsWith("--")) {
        el.style.setProperty(cssProperty, String(value));
        return;
      }
      const property = cssProperty.replace(/-([a-z])/gi, function(s, group1) {
        return group1.toUpperCase();
      });
      if (this.cssVenderPrefixes.indexOf(property) !== -1) {
        el.style[property.charAt(0).toLowerCase() + property.slice(1)] = value;
        el.style["webkit" + property] = value;
        el.style["moz" + property] = value;
        el.style["ms" + property] = value;
        el.style["o" + property] = value;
      } else {
        el.style[property] = value;
      }
    }
    _getFirstEl() {
      if (this.selector && this.selector.length !== void 0) {
        return this.selector[0];
      } else {
        return this.selector;
      }
    }
    isEventMatched(event, eventName) {
      const eventNamespace = eventName.split(".");
      return event.split(".").filter((e) => e).every((e) => {
        return eventNamespace.indexOf(e) !== -1;
      });
    }
    attr(attr, value) {
      if (value === void 0) {
        if (!this.firstElement) {
          return "";
        }
        return this.firstElement.getAttribute(attr);
      }
      this._each((el) => {
        el.setAttribute(attr, value);
      });
      return this;
    }
    find(selector) {
      return $LG(this._getSelector(selector, this.selector));
    }
    first() {
      if (this.selector && this.selector.length !== void 0) {
        return $LG(this.selector[0]);
      } else {
        return $LG(this.selector);
      }
    }
    eq(index) {
      return $LG(this.selector[index]);
    }
    parent() {
      return $LG(this.selector.parentElement);
    }
    get() {
      return this._getFirstEl();
    }
    removeAttr(attributes) {
      const attrs = attributes.split(" ");
      this._each((el) => {
        attrs.forEach((attr) => el.removeAttribute(attr));
      });
      return this;
    }
    wrap(className) {
      if (!this.firstElement) {
        return this;
      }
      const wrapper = document.createElement("div");
      wrapper.className = className;
      this.firstElement.parentNode.insertBefore(wrapper, this.firstElement);
      this.firstElement.parentNode.removeChild(this.firstElement);
      wrapper.appendChild(this.firstElement);
      return this;
    }
    addClass(classNames = "") {
      this._each((el) => {
        classNames.split(" ").forEach((className) => {
          if (className) {
            el.classList.add(className);
          }
        });
      });
      return this;
    }
    removeClass(classNames) {
      this._each((el) => {
        classNames.split(" ").forEach((className) => {
          if (className) {
            el.classList.remove(className);
          }
        });
      });
      return this;
    }
    hasClass(className) {
      if (!this.firstElement) {
        return false;
      }
      return this.firstElement.classList.contains(className);
    }
    hasAttribute(attribute) {
      if (!this.firstElement) {
        return false;
      }
      return this.firstElement.hasAttribute(attribute);
    }
    toggleClass(className) {
      if (!this.firstElement) {
        return this;
      }
      if (this.hasClass(className)) {
        this.removeClass(className);
      } else {
        this.addClass(className);
      }
      return this;
    }
    css(property, value) {
      this._each((el) => {
        this._setCssVendorPrefix(el, property, value);
      });
      return this;
    }
    // Need to pass separate namespaces for separate elements
    on(events, listener) {
      if (!this.selector) {
        return this;
      }
      events.split(" ").forEach((event) => {
        if (!Array.isArray(_lgQuery2.eventListeners[event])) {
          _lgQuery2.eventListeners[event] = [];
        }
        _lgQuery2.eventListeners[event].push(listener);
        this.selector.addEventListener(event.split(".")[0], listener);
      });
      return this;
    }
    // @todo - test this
    once(event, listener) {
      this.on(event, () => {
        this.off(event);
        listener(event);
      });
      return this;
    }
    off(event) {
      if (!this.selector) {
        return this;
      }
      Object.keys(_lgQuery2.eventListeners).forEach((eventName) => {
        if (this.isEventMatched(event, eventName)) {
          _lgQuery2.eventListeners[eventName].forEach((listener) => {
            this.selector.removeEventListener(
              eventName.split(".")[0],
              listener
            );
          });
          _lgQuery2.eventListeners[eventName] = [];
        }
      });
      return this;
    }
    trigger(event, detail) {
      if (!this.firstElement) {
        return this;
      }
      const customEvent = new CustomEvent(event.split(".")[0], {
        detail: detail || null
      });
      this.firstElement.dispatchEvent(customEvent);
      return this;
    }
    // Does not support IE
    load(url) {
      fetch(url).then((res) => res.text()).then((html) => {
        this.selector.innerHTML = html;
      });
      return this;
    }
    html(html) {
      if (html === void 0) {
        if (!this.firstElement) {
          return "";
        }
        return this.firstElement.innerHTML;
      }
      this._each((el) => {
        el.innerHTML = html;
      });
      return this;
    }
    append(html) {
      this._each((el) => {
        if (typeof html === "string") {
          el.insertAdjacentHTML("beforeend", html);
        } else {
          el.appendChild(html);
        }
      });
      return this;
    }
    prepend(html) {
      this._each((el) => {
        if (typeof html === "string") {
          el.insertAdjacentHTML("afterbegin", html);
        } else if (html instanceof HTMLElement) {
          el.insertBefore(html.cloneNode(true), el.firstChild);
        }
      });
      return this;
    }
    remove() {
      this._each((el) => {
        el.parentNode.removeChild(el);
      });
      return this;
    }
    empty() {
      this._each((el) => {
        el.innerHTML = "";
      });
      return this;
    }
    scrollTop(scrollTop) {
      if (scrollTop !== void 0) {
        window.scrollTo(window.scrollX, scrollTop);
        return this;
      } else {
        return window.scrollY;
      }
    }
    scrollLeft(scrollLeft) {
      if (scrollLeft !== void 0) {
        window.scrollTo(scrollLeft, window.scrollY);
        return this;
      } else {
        return window.scrollX;
      }
    }
    offset() {
      if (!this.firstElement) {
        return {
          left: 0,
          top: 0
        };
      }
      const rect = this.firstElement.getBoundingClientRect();
      const bodyMarginLeft = $LG("body").style().marginLeft;
      return {
        left: rect.left - parseFloat(bodyMarginLeft) + this.scrollLeft(),
        top: rect.top + this.scrollTop()
      };
    }
    style() {
      if (!this.firstElement) {
        return {};
      }
      return this.firstElement.currentStyle || window.getComputedStyle(this.firstElement);
    }
    // Width without padding and border even if box-sizing is used.
    width() {
      const style = this.style();
      return this.firstElement.clientWidth - parseFloat(style.paddingLeft) - parseFloat(style.paddingRight);
    }
    // Height without padding and border even if box-sizing is used.
    height() {
      const style = this.style();
      return this.firstElement.clientHeight - parseFloat(style.paddingTop) - parseFloat(style.paddingBottom);
    }
  };
  _lgQuery.eventListeners = {};
  let lgQuery = _lgQuery;
  function $LG(selector) {
    return new lgQuery(selector);
  }
  const defaultDynamicOptions = [
    "src",
    "sources",
    "subHtml",
    "subHtmlUrl",
    "html",
    "video",
    "poster",
    "slideName",
    "responsive",
    "srcset",
    "sizes",
    "iframe",
    "downloadUrl",
    "download",
    "width",
    "shareUrl",
    "facebookShareUrl",
    "tweetText",
    "iframeTitle",
    "twitterShareUrl",
    "pinterestShareUrl",
    "pinterestText",
    "fbHtml",
    "disqusIdentifier",
    "disqusUrl",
    "lgSize"
  ];
  function convertToData(attr) {
    if (attr === "href") {
      return "src";
    }
    attr = attr.replace("data-", "");
    attr = attr.charAt(0).toLowerCase() + attr.slice(1);
    attr = attr.replace(/-([a-z])/g, (g) => g[1].toUpperCase());
    return attr;
  }
  const utils = {
    /**
     * Fetches HTML content from a given URL and inserts it into a specified element.
     *
     * @param url - The URL to fetch the HTML content from.
     * @param element - The DOM element (jQuery object) to insert the HTML content into.
     * @param insertMethod - The method to insert the HTML ('append' or 'replace').
     */
    fetchCaptionFromUrl(url, element, insertMethod) {
      fetch(url).then((response) => response.text()).then((htmlContent) => {
        if (insertMethod === "append") {
          const contentDiv = `<div class="lg-sub-html">${htmlContent}</div>`;
          element.append(contentDiv);
        } else {
          element.html(htmlContent);
        }
      });
    },
    /**
     * Fit the media's original size into the container. The size comes from
     * the element's `data-lg-size` attribute, then the item's `lgSize`
     * field, then `defaultLgSize`. Used for the zoom-from-origin animation.
     */
    getSize(el, container, spacing = 0, defaultLgSize, itemLgSize) {
      const LGel = $LG(el);
      const lgSize = LGel.attr("data-lg-size") || itemLgSize || defaultLgSize;
      const parsed = parseImageSize(lgSize, window.innerWidth);
      if (!parsed) {
        return;
      }
      return fitImageSize(
        parsed,
        container.width(),
        container.height() - spacing
      );
    },
    /**
     * @desc Get transform value based on the imageSize. Used for ZoomFromOrigin option
     * @param {jQuery Element}
     * @returns {String} Transform CSS string
     */
    getTransform(el, container, top, bottom, imageSize) {
      if (!imageSize || imageSize.width <= 0 || imageSize.height <= 0) {
        return;
      }
      const origin = $LG(el).find("img").first().get() || el;
      if (!origin) {
        return;
      }
      const containerRect = container.get().getBoundingClientRect();
      const rect = origin.getBoundingClientRect();
      const triggerRect = {
        left: rect.left,
        top: rect.top,
        width: rect.width,
        height: rect.height
      };
      if (!isUsableOriginRect(triggerRect)) {
        return;
      }
      return getOriginTransform({
        triggerRect,
        containerRect: {
          left: containerRect.left,
          top: containerRect.top,
          width: containerRect.width,
          // Element height, not rect height, includes the mobile
          // safari bottom bar handling this always had.
          height: container.height()
        },
        top,
        bottom,
        imageSize
      });
    },
    getIframeMarkup(iframeWidth, iframeHeight, iframeMaxWidth, iframeMaxHeight, src, iframeTitle) {
      const title = iframeTitle ? 'title="' + iframeTitle + '"' : "";
      return `<div class="lg-media-cont lg-has-iframe" style="width:${iframeWidth}; max-width:${iframeMaxWidth}; height: ${iframeHeight}; max-height:${iframeMaxHeight}">
                    <iframe class="lg-object" frameborder="0" ${title} src="${src}"  allowfullscreen="true"></iframe>
                </div>`;
    },
    getImgMarkup(index, src, altAttr, srcset, sizes, sources) {
      const srcsetAttr = srcset ? `srcset="${srcset}"` : "";
      const sizesAttr = sizes ? `sizes="${sizes}"` : "";
      const imgMarkup = `<img ${altAttr} ${srcsetAttr}  ${sizesAttr} class="lg-object lg-image" data-index="${index}" src="${src}" />`;
      let sourceTag = "";
      if (sources) {
        const sourceObj = typeof sources === "string" ? JSON.parse(sources) : sources;
        sourceTag = sourceObj.map((source) => {
          let attrs = "";
          Object.keys(source).forEach((key) => {
            attrs += ` ${key}="${source[key]}"`;
          });
          return `<source ${attrs}></source>`;
        });
      }
      return `${sourceTag}${imgMarkup}`;
    },
    // Get src from responsive src
    getResponsiveSrc(srcItms) {
      const rsWidth = [];
      const rsSrc = [];
      let src = "";
      for (let i = 0; i < srcItms.length; i++) {
        const _src = srcItms[i].split(" ");
        if (_src[0] === "") {
          _src.splice(0, 1);
        }
        rsSrc.push(_src[0]);
        rsWidth.push(_src[1]);
      }
      const wWidth = window.innerWidth;
      for (let j = 0; j < rsWidth.length; j++) {
        if (parseInt(rsWidth[j], 10) > wWidth) {
          src = rsSrc[j];
          break;
        }
      }
      return src;
    },
    isImageLoaded(img) {
      if (!img) return false;
      if (!img.complete) {
        return false;
      }
      if (img.naturalWidth === 0) {
        return false;
      }
      return true;
    },
    getVideoPosterMarkup(_poster, dummyImg, videoContStyle, playVideoString, _isVideo) {
      let videoClass = "";
      if (_isVideo && _isVideo.youtube) {
        videoClass = "lg-has-youtube";
      } else if (_isVideo && _isVideo.vimeo) {
        videoClass = "lg-has-vimeo";
      } else if (_isVideo && _isVideo.wistia) {
        videoClass = "lg-has-wistia";
      } else {
        videoClass = "lg-has-html5";
      }
      let _dummy = dummyImg;
      if (typeof dummyImg !== "string") {
        _dummy = dummyImg.outerHTML;
      }
      return `<div class="lg-video-cont ${videoClass}" style="${videoContStyle}">
                <div class="lg-video-play-button">
                <svg
                    viewBox="0 0 20 20"
                    preserveAspectRatio="xMidYMid"
                    focusable="false"
                    aria-labelledby="${playVideoString}"
                    role="img"
                    class="lg-video-play-icon"
                >
                    <title>${playVideoString}</title>
                    <polygon class="lg-video-play-icon-inner" points="1,0 20,10 1,20"></polygon>
                </svg>
                <svg class="lg-video-play-icon-bg" viewBox="0 0 50 50" focusable="false">
                    <circle cx="50%" cy="50%" r="20"></circle></svg>
                <svg class="lg-video-play-icon-circle" viewBox="0 0 50 50" focusable="false">
                    <circle cx="50%" cy="50%" r="20"></circle>
                </svg>
            </div>
            ${_dummy}
            <img class="lg-object lg-video-poster" src="${_poster}" />
        </div>`;
    },
    getFocusableElements(container) {
      const elements = container.querySelectorAll(
        'a[href]:not([disabled]), button:not([disabled]), textarea:not([disabled]), input[type="text"]:not([disabled]), input[type="radio"]:not([disabled]), input[type="checkbox"]:not([disabled]), select:not([disabled]), [tabindex]:not([tabindex="-1"]):not([disabled])'
      );
      const visibleElements = [].filter.call(
        elements,
        (element) => {
          const style = window.getComputedStyle(element);
          return style.display !== "none" && style.visibility !== "hidden" && // Hidden or moved into the toolbar's More menu, whatever
          // the stylesheet says about their display.
          !element.closest("[hidden], [data-lg-overflow]");
        }
      );
      return visibleElements;
    },
    /**
     * @desc Create dynamic elements array from gallery items when dynamic option is false
     * It helps to avoid frequent DOM interaction
     * and avoid multiple checks for dynamic elments
     *
     * @returns {Array} dynamicEl
     */
    getDynamicOptions(items, extraProps, getCaptionFromTitleOrAlt, exThumbImage) {
      const dynamicElements = [];
      const availableDynamicOptions = [
        ...defaultDynamicOptions,
        ...extraProps
      ];
      [].forEach.call(items, (item) => {
        const dynamicEl = {};
        for (let i = 0; i < item.attributes.length; i++) {
          const attr = item.attributes[i];
          if (attr.specified) {
            const dynamicAttr = convertToData(attr.name);
            let label = "";
            if (availableDynamicOptions.indexOf(dynamicAttr) > -1) {
              label = dynamicAttr;
            }
            if (label) {
              dynamicEl[label] = attr.value;
            }
          }
        }
        if (typeof dynamicEl.sources === "string") {
          try {
            dynamicEl.sources = JSON.parse(dynamicEl.sources);
          } catch (e) {
            console.warn(
              "lightGallery :- data-sources must be a JSON array of picture source objects. See https://www.lightgalleryjs.com/docs/responsive-loading/"
            );
            delete dynamicEl.sources;
          }
        }
        const currentItem = $LG(item);
        const alt = currentItem.find("img").first().attr("alt");
        const title = currentItem.attr("title");
        const thumb = exThumbImage ? currentItem.attr(exThumbImage) : currentItem.find("img").first().attr("src");
        dynamicEl.thumb = thumb;
        if (getCaptionFromTitleOrAlt && !dynamicEl.subHtml) {
          dynamicEl.subHtml = title || alt || "";
        }
        dynamicEl.alt = alt || title || "";
        dynamicElements.push(dynamicEl);
      });
      return dynamicElements;
    },
    isMobile() {
      return /iPhone|iPad|iPod|Android/i.test(navigator.userAgent);
    },
    /**
     * @desc Check the given src is video
     * @param {String} src
     * @return {Object} video type
     * Ex:{ youtube  :  ["//www.youtube.com/watch?v=c0asJgSyxcY", "c0asJgSyxcY"] }
     *
     * @todo - this information can be moved to dynamicEl to avoid frequent calls
     */
    isVideo(src, isHTML5VIdeo, index) {
      if (!src) {
        if (isHTML5VIdeo) {
          return {
            html5: true
          };
        } else {
          console.error(
            "lightGallery :- data-src is not provided on slide item " + (index + 1) + ". Please make sure the selector property is properly configured. More info - https://www.lightgalleryjs.com/demos/html-markup/"
          );
          return;
        }
      }
      return getVideoInfo(src, false);
    }
  };
  var __defProp = Object.defineProperty;
  var __defProps = Object.defineProperties;
  var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
  var __getOwnPropSymbols = Object.getOwnPropertySymbols;
  var __hasOwnProp = Object.prototype.hasOwnProperty;
  var __propIsEnum = Object.prototype.propertyIsEnumerable;
  var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
  var __spreadValues = (a, b) => {
    for (var prop in b || (b = {}))
      if (__hasOwnProp.call(b, prop))
        __defNormalProp(a, prop, b[prop]);
    if (__getOwnPropSymbols)
      for (var prop of __getOwnPropSymbols(b)) {
        if (__propIsEnum.call(b, prop))
          __defNormalProp(a, prop, b[prop]);
      }
    return a;
  };
  var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
  let lgId = 0;
  class LightGallery {
    constructor(element, options) {
      this.lgOpened = false;
      this.index = 0;
      this.plugins = [];
      this.lGalleryOn = false;
      this.lgBusy = false;
      this.defaultIcons = __spreadValues({}, coreDefaultIcons);
      this.swipeSamples = [];
      this.currentItemsInDom = [];
      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 = $LG(element);
      this.generateSettings(options);
      this.buildModules();
      if (this.settings.dynamic && this.settings.dynamicEl !== void 0 && !Array.isArray(this.settings.dynamicEl)) {
        throw "When using dynamic mode, you must also define dynamicEl as an Array.";
      }
      this.galleryItems = this.getItems();
      this.normalizeSettings();
      this.init();
      this.validateLicense();
      return this;
    }
    generateSettings(options) {
      var _a;
      this.settings = __spreadProps(__spreadValues(__spreadValues({}, lightGalleryCoreSettings), options), {
        // Strings merge per-key (headless resolveSettings parity), // a partial override keeps every other default.
        strings: __spreadValues(__spreadValues({}, lightGalleryCoreSettings.strings), (_a = options == null ? void 0 : options.strings) != null ? _a : {})
      });
      if (this.settings.isMobile && typeof this.settings.isMobile === "function" ? this.settings.isMobile() : utils.isMobile()) {
        const mobileSettings = __spreadValues({}, this.settings.mobileSettings);
        this.settings = __spreadValues(__spreadValues({}, this.settings), mobileSettings);
      }
      if (typeof window !== "undefined" && typeof window.matchMedia === "function" && window.matchMedia("(prefers-reduced-motion: reduce)").matches) {
        this.settings = __spreadProps(__spreadValues({}, this.settings), {
          speed: 0,
          backdropDuration: 0,
          startAnimationDuration: 0,
          zoomFromOrigin: false,
          slideEndAnimation: false
        });
      }
    }
    normalizeSettings() {
      if (this.settings.direction === "auto") {
        this.settings.direction = typeof window !== "undefined" && typeof window.getComputedStyle === "function" && window.getComputedStyle(this.el).direction === "rtl" ? "rtl" : "ltr";
      }
      if (this.settings.slideEndAnimation) {
        this.settings.hideControlOnEnd = false;
      }
      if (!this.settings.closable) {
        this.settings.swipeToClose = false;
      }
      this.zoomFromOrigin = this.settings.zoomFromOrigin;
      if (this.settings.container) {
        const { container } = this.settings;
        if (typeof container === "function") {
          this.settings.container = container();
        } else if (typeof container === "string") {
          const el = document.querySelector(container);
          this.settings.container = el != null ? el : document.body;
        }
      } else {
        this.settings.container = document.body;
      }
      this.settings.preload = Math.min(
        this.settings.preload,
        this.galleryItems.length
      );
    }
    init() {
      this.addSlideVideoInfo(this.galleryItems);
      this.buildStructure();
      this.LGel.trigger(lGEvents.init, {
        instance: this
      });
      if (this.settings.keyPress) {
        this.keyPress();
      }
      setTimeout(() => {
        this.enableDrag();
        this.enableSwipe();
        this.triggerPosterClick();
      }, 50);
      this.arrow();
      if (this.settings.mousewheel) {
        this.mousewheel();
      }
      if (!this.settings.dynamic) {
        this.openGalleryOnItemClick();
      }
    }
    openGalleryOnItemClick() {
      for (let index = 0; index < this.items.length; index++) {
        const element = this.items[index];
        const $element = $LG(element);
        const uuid = lgQuery.generateUUID();
        $element.attr("data-lg-id", uuid).on(`click.lgcustom-item-${uuid}`, (e) => {
          e.preventDefault();
          const currentItemIndex = this.settings.index || index;
          this.openGallery(currentItemIndex, element);
        });
      }
    }
    /**
     * Module constructor
     * Modules are build incrementally.
     * Gallery should be opened only once all the modules are initialized.
     * use moduleBuildTimeout to make sure this
     */
    buildModules() {
      this.settings.plugins.forEach((plugin) => {
        this.plugins.push(new plugin(this, $LG));
      });
    }
    validateLicense() {
      const notice = takeLicenseNotice(this.settings.licenseKey);
      if (notice) console[notice.level](notice.message);
    }
    getSlideItem(index) {
      return $LG(this.getSlideItemId(index));
    }
    getSlideItemId(index) {
      return `#lg-item-${this.lgId}-${index}`;
    }
    getIdName(id) {
      return `${id}-${this.lgId}`;
    }
    getElementById(id) {
      return $LG(`#${this.getIdName(id)}`);
    }
    manageSingleSlideClassName() {
      if (this.galleryItems.length < 2) {
        this.outer.addClass("lg-single-item");
      } else {
        this.outer.removeClass("lg-single-item");
      }
    }
    buildStructure() {
      const container = this.$container && this.$container.get();
      if (container) {
        return;
      }
      let controls = "";
      let subHtmlCont = "";
      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>
                <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 = this.settings.ariaAnnouncements ? '<div class="lg-sub-html"></div>' : '<div class="lg-sub-html" role="status" aria-live="polite"></div>';
      }
      let addClasses = "";
      if (this.settings.allowMediaOverlap) {
        addClasses += "lg-media-overlap ";
      }
      const ariaLabelledby = this.settings.ariaLabelledby ? 'aria-labelledby="' + this.settings.ariaLabelledby + '"' : `aria-label="${this.settings.strings["galleryLabel"]}"`;
      const ariaDescribedby = this.settings.ariaDescribedby ? 'aria-describedby="' + this.settings.ariaDescribedby + '"' : "";
      const containerClassName = `lg-container ${this.settings.addClass} ${document.body !== this.settings.container ? "lg-inline" : ""}`;
      const 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>` : "";
      const maximizeIcon = this.settings.showMaximizeIcon ? `<button type="button" aria-label="${this.settings.strings["toggleMaximize"]}" id="${this.getIdName(
        "lg-maximize"
      )}" class="lg-maximize lg-icon"></button>` : "";
      const template = `
        <div class="${containerClassName}" id="${this.getIdName(
        "lg-container"
      )}" tabindex="-1" aria-modal="true" ${ariaLabelledby} ${ariaDescribedby} role="dialog" dir="${this.getDirection()}"
        >
            <div id="${this.getIdName(
        "lg-backdrop"
      )}" class="lg-backdrop"></div>
            ${this.settings.ariaAnnouncements ? `<div id="${this.getIdName(
        "lg-announcer"
      )}" class="lg-announcer" role="status" aria-live="polite"></div>` : ""}

            <div id="${this.getIdName(
        "lg-outer"
      )}" class="lg-outer lg-use-css3 lg-css3 lg-hide-items ${addClasses} ">

              <div id="${this.getIdName("lg-content")}" class="lg-content">
                <div id="${this.getIdName("lg-inner")}" class="lg-inner">
                </div>
                ${controls}
              </div>
                <div id="${this.getIdName(
        "lg-toolbar"
      )}" class="lg-toolbar lg-group">
                    ${maximizeIcon}
                    ${closeIcon}
                    </div>
                    ${this.settings.appendSubHtmlTo === ".lg-outer" ? subHtmlCont : ""}
                <div id="${this.getIdName(
        "lg-components"
      )}" class="lg-components">
                    ${this.settings.appendSubHtmlTo === ".lg-sub-html" ? subHtmlCont : ""}
                </div>
            </div>
        </div>
        `;
      $LG(this.settings.container).append(template);
      if (document.body !== this.settings.container) {
        $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"
      );
      let 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");
      this.$inner.css("--lg-speed", 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();
      $LG(window).on(
        `resize.lg.global${this.lgId} orientationchange.lg.global${this.lgId}`,
        () => {
          this.refreshOnResize();
        }
      );
      this.hideBars();
      this.manageCloseGallery();
      this.toggleMaximize();
      this.initModules();
      if (this.settings.toolbarOverflow) {
        this.toolbarOverflow = new ToolbarOverflow(this.$toolbar.get(), {
          id: this.getIdName("lg-more"),
          label: this.settings.strings.moreOptions
        });
        const update = () => {
          var _a;
          return (_a = this.toolbarOverflow) == null ? void 0 : _a.update();
        };
        this.LGel.on(`${lGEvents.afterOpen}.lg`, update);
        this.LGel.on(`${lGEvents.afterSlide}.lg`, update);
        this.LGel.on(`${lGEvents.containerResize}.lg`, update);
        this.LGel.on(
          `${lGEvents.beforeClose}.lg`,
          () => {
            var _a;
            return (_a = this.toolbarOverflow) == null ? void 0 : _a.close(false);
          }
        );
      }
      applyCustomIcons(
        this.$container.get(),
        this.defaultIcons,
        this.settings.icons
      );
    }
    /**
     * Merge a plugin's built-in icon SVGs into the default set (called
     * from plugin `init()`, before the icon pass runs). Consumer
     * `settings.icons` still win over anything registered here.
     */
    registerDefaultIcons(icons) {
      this.defaultIcons = __spreadValues(__spreadValues({}, this.defaultIcons), icons);
    }
    /**
     * Cache the fitted (contain) size of a slide's media. Every consumer
     * of `currentImageSize` measures against the CURRENT slide: the
     * actual-size zoom divides the natural width by it, and the
     * zoom-from-origin close flight positions against it. Recomputed on
     * every slide change, not just at open — one cached landscape size
     * makes a portrait slide zoom to the wrong scale and then snap to
     * its real size when the natural-px swap lands.
     */
    updateCurrentImageSize(index) {
      const { __slideVideoInfo, lgSize } = this.galleryItems[index];
      const { top, bottom } = this.mediaContainerPosition;
      this.currentImageSize = utils.getSize(
        this.items[index],
        this.outer,
        top + bottom,
        __slideVideoInfo && this.settings.videoMaxSize,
        lgSize
      );
    }
    refreshOnResize() {
      if (this.lgOpened) {
        const currentGalleryItem = this.galleryItems[this.index];
        const { __slideVideoInfo } = currentGalleryItem;
        this.mediaContainerPosition = this.getMediaContainerPosition();
        this.updateCurrentImageSize(this.index);
        if (__slideVideoInfo) {
          this.resizeVideoSlide(this.index, this.currentImageSize);
        }
        if (this.zoomFromOrigin && !this.isDummyImageRemoved) {
          const imgStyle = this.getDummyImgStyles(this.currentImageSize);
          this.outer.find(".lg-current .lg-dummy-img").first().attr("style", imgStyle);
        }
        this.LGel.trigger(lGEvents.containerResize);
      }
    }
    resizeVideoSlide(index, imageSize) {
      const lgVideoStyle = this.getVideoContStyle(imageSize);
      const 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 a new list of gallery items
     * - You need to take care of thumbnails outside the gallery if any
     * - use 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(plugin.galleryItems),
     * );
     * galleryItems.shift();
     * plugin.updateSlides(galleryItems, 1);
     * @see <a href="/demos/update-slides/">Demo</a>
     */
    updateSlides(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;
      }
      const currentSrc = this.galleryItems[index].src;
      this.galleryItems = items;
      this.updateControls();
      this.$inner.empty();
      this.currentItemsInDom = [];
      let _index = 0;
      this.galleryItems.some((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(lGEvents.updateSlides);
    }
    // Get gallery items based on multiple conditions
    getItems() {
      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) {
              const selectWithin = $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 utils.getDynamicOptions(
          this.items,
          this.settings.extraProps,
          this.settings.getCaptionFromTitleOrAlt,
          this.settings.exThumbImage
        );
      } else {
        return this.settings.dynamicEl || [];
      }
    }
    shouldHideScrollbar() {
      return this.settings.hideScrollbar && document.body === this.settings.container;
    }
    hideScrollbar() {
      if (!this.shouldHideScrollbar()) {
        return;
      }
      this.bodyPaddingRight = parseFloat($LG("body").style().paddingRight);
      const bodyRect = document.documentElement.getBoundingClientRect();
      const scrollbarWidth = window.innerWidth - bodyRect.width;
      $LG(document.body).css(
        "padding-right",
        scrollbarWidth + this.bodyPaddingRight + "px"
      );
      $LG(document.body).addClass("lg-overlay-open");
    }
    resetScrollBar() {
      if (!this.shouldHideScrollbar()) {
        return;
      }
      $LG(document.body).css("padding-right", this.bodyPaddingRight + "px");
      $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);
     * });
     *
     */
    openGallery(index = this.settings.index, element) {
      if (this.lgOpened) return;
      this.lgOpened = true;
      this.outer.removeClass("lg-hide-items");
      this.hideScrollbar();
      this.$container.addClass("lg-show");
      const itemsToBeInsertedToDom = this.getItemsToBeInsertedToDom(
        index,
        index
      );
      this.currentItemsInDom = itemsToBeInsertedToDom;
      let items = "";
      itemsToBeInsertedToDom.forEach((item) => {
        items = items + `<div id="${item}" class="lg-item"></div>`;
      });
      this.$inner.append(items);
      this.addHtml(index);
      let transform = "";
      this.mediaContainerPosition = this.getMediaContainerPosition();
      const { top, bottom } = this.mediaContainerPosition;
      if (!this.settings.allowMediaOverlap) {
        this.setMediaContainerPosition(top, bottom);
      }
      const { __slideVideoInfo, lgSize } = this.galleryItems[index];
      if (this.zoomFromOrigin && element) {
        this.currentImageSize = utils.getSize(
          element,
          this.outer,
          top + bottom,
          __slideVideoInfo && this.settings.videoMaxSize,
          lgSize
        );
        transform = this.getOriginTransform(element, this.currentImageSize);
      }
      if (!this.zoomFromOrigin || !transform) {
        this.outer.addClass(this.settings.startClass);
        this.getSlideItem(index).removeClass("lg-complete");
      }
      const timeout = this.settings.zoomFromOrigin ? 100 : this.settings.backdropDuration;
      setTimeout(() => {
        this.outer.addClass("lg-components-open");
      }, timeout);
      this.index = index;
      this.LGel.trigger(lGEvents.beforeOpen);
      this.getSlideItem(index).addClass("lg-current");
      this.lGalleryOn = false;
      this.prevScrollTop = $LG(window).scrollTop();
      if (this.settings.trapFocus && document.body === this.settings.container) {
        this.prevActiveElement = document.activeElement instanceof HTMLElement ? document.activeElement : void 0;
      }
      setTimeout(() => {
        if (this.zoomFromOrigin && transform) {
          const currentSlide = this.getSlideItem(index);
          currentSlide.css("transform", transform);
          setTimeout(() => {
            currentSlide.addClass("lg-start-progress lg-start-end-progress").css(
              "transition-duration",
              this.settings.startAnimationDuration + "ms"
            );
            this.outer.addClass("lg-zoom-from-image");
          });
          setTimeout(() => {
            currentSlide.css("transform", "translate3d(0, 0, 0)");
          }, 100);
        }
        setTimeout(() => {
          this.$backdrop.addClass("in");
          this.$container.addClass("lg-show-in");
        }, 10);
        setTimeout(() => {
          if (this.settings.trapFocus && document.body === this.settings.container) {
            this.trapFocus();
          }
        }, this.settings.backdropDuration + 50);
        if (!this.zoomFromOrigin || !transform) {
          setTimeout(() => {
            this.outer.addClass("lg-visible");
          }, this.settings.backdropDuration);
        }
        this.slide(index, false, false, false);
        this.LGel.trigger(lGEvents.afterOpen);
      });
      if (document.body === this.settings.container) {
        $LG("html").addClass("lg-on");
      }
    }
    /**
     * The zoom-from-origin transform for a trigger: it lands the slide on
     * the trigger's thumbnail, the start of the opening flight and the end
     * of the closing one. Undefined when the trigger cannot anchor a flight,
     * and the gallery opens or closes about the stage centre instead.
     * Plugins may replace it on the instance to fly differently.
     */
    getOriginTransform(element, imageSize) {
      const { top, bottom } = this.mediaContainerPosition;
      return utils.getTransform(element, this.outer, top, bottom, imageSize);
    }
    /**
     * 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 defaultCaptionHeight option
     */
    getMediaContainerPosition() {
      if (this.settings.allowMediaOverlap) {
        return {
          top: 0,
          bottom: 0
        };
      }
      const top = this.$toolbar.get().clientHeight || 0;
      const subHtml = this.outer.find(".lg-components .lg-sub-html").get();
      const captionHeight = this.settings.defaultCaptionHeight || subHtml && subHtml.clientHeight || 0;
      const thumbContainer = this.outer.find(".lg-thumb-outer").get();
      const thumbHeight = thumbContainer ? thumbContainer.clientHeight : 0;
      const bottom = thumbHeight + captionHeight;
      return {
        top,
        bottom
      };
    }
    setMediaContainerPosition(top = 0, bottom = 0) {
      this.$content.css("top", top + "px").css("bottom", bottom + "px");
    }
    hideBars() {
      setTimeout(() => {
        this.outer.removeClass("lg-hide-items");
        if (this.settings.hideBarsDelay > 0) {
          this.outer.on("mousemove.lg click.lg touchstart.lg", () => {
            this.outer.removeClass("lg-hide-items");
            clearTimeout(this.hideBarTimeout);
            this.hideBarTimeout = setTimeout(() => {
              this.outer.addClass("lg-hide-items");
            }, this.settings.hideBarsDelay);
          });
          this.outer.trigger("mousemove.lg");
        }
      }, this.settings.showBarsAfter);
    }
    /**
     *  @desc Create image counter
     *  Ex: 1/10
     */
    counter() {
      if (this.settings.counter) {
        const counterA11yAttrs = this.settings.ariaAnnouncements ? 'aria-hidden="true"' : 'role="status" aria-live="polite"';
        const counterHtml = `<div class="lg-counter" ${counterA11yAttrs}>
                <span id="${this.getIdName(
          "lg-counter-current"
        )}" class="lg-counter-current">${this.index + 1} </span> /
                <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
     */
    addHtml(index) {
      let subHtml;
      let subHtmlUrl;
      if (this.galleryItems[index].subHtmlUrl) {
        subHtmlUrl = this.galleryItems[index].subHtmlUrl;
      } else {
        subHtml = this.galleryItems[index].subHtml;
      }
      if (!subHtmlUrl) {
        if (subHtml) {
          const fL = subHtml.substring(0, 1);
          if (fL === "." || fL === "#") {
            try {
              if (this.settings.subHtmlSelectorRelative && !this.settings.dynamic) {
                subHtml = $LG(this.items).eq(index).find(subHtml).first().html();
              } else {
                subHtml = $LG(subHtml).first().html();
              }
            } catch (error) {
              console.warn(
                `lightGallery: error processing subHtml selector "${subHtml}". See https://www.lightgalleryjs.com/demos/captions/`
              );
              subHtml = "";
            }
          }
        } else {
          subHtml = "";
        }
      }
      if (this.settings.appendSubHtmlTo !== ".lg-item") {
        if (subHtmlUrl) {
          utils.fetchCaptionFromUrl(
            subHtmlUrl,
            this.outer.find(".lg-sub-html"),
            "replace"
          );
        } else {
          this.outer.find(".lg-sub-html").html(subHtml);
        }
      } else {
        const currentSlide = $LG(this.getSlideItemId(index));
        if (subHtmlUrl) {
          utils.fetchCaptionFromUrl(subHtmlUrl, currentSlide, "append");
        } else {
          currentSlide.append(
            `<div class="lg-sub-html">${subHtml}</div>`
          );
        }
      }
      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(
        lGEvents.afterAppendSubHtml,
        {
          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
     */
    preload(index) {
      for (let i = 1; i <= this.settings.preload; i++) {
        if (i >= this.galleryItems.length - index) {
          break;
        }
        this.loadContent(index + i, false);
      }
      for (let j = 1; j <= this.settings.preload; j++) {
        if (index - j < 0) {
          break;
        }
        this.loadContent(index - j, false);
      }
    }
    getDummyImgStyles(imageSize) {
      if (!imageSize) return "";
      return `width:${imageSize.width}px;
                margin-left: -${imageSize.width / 2}px;
                margin-top: -${imageSize.height / 2}px;
                height:${imageSize.height}px`;
    }
    getVideoContStyle(imageSize) {
      if (!imageSize) return "";
      return `width:${imageSize.width}px;
                height:${imageSize.height}px`;
    }
    getDummyImageContent($currentSlide, index, alt) {
      let $currentItem;
      if (!this.settings.dynamic) {
        $currentItem = $LG(this.items).eq(index);
      }
      if ($currentItem) {
        let _dummyImgSrc;
        if (!this.settings.exThumbImage) {
          _dummyImgSrc = $currentItem.find("img").first().attr("src");
        } else {
          _dummyImgSrc = $currentItem.attr(this.settings.exThumbImage);
        }
        if (!_dummyImgSrc) return "";
        const imgStyle = this.getDummyImgStyles(this.currentImageSize);
        const dummyImgContentImg = document.createElement("img");
        dummyImgContentImg.alt = alt || "";
        dummyImgContentImg.src = _dummyImgSrc;
        dummyImgContentImg.className = `lg-dummy-img`;
        dummyImgContentImg.style.cssText = imgStyle;
        $currentSlide.addClass("lg-first-slide");
        this.outer.addClass("lg-first-slide-loading");
        return dummyImgContentImg;
      }
      return "";
    }
    setImgMarkup(src, $currentSlide, index) {
      const currentGalleryItem = this.galleryItems[index];
      const { alt, srcset, sizes, sources } = currentGalleryItem;
      let imgContent = "";
      const altAttr = alt ? 'alt="' + alt + '"' : "";
      if (this.isFirstSlideWithZoomAnimation()) {
        imgContent = this.getDummyImageContent(
          $currentSlide,
          index,
          altAttr
        );
      } else {
        imgContent = utils.getImgMarkup(
          index,
          src,
          altAttr,
          srcset,
          sizes,
          sources
        );
      }
      const picture = document.createElement("picture");
      picture.className = "lg-img-wrap";
      $LG(picture).append(imgContent);
      $currentSlide.prepend(picture);
    }
    onSlideObjectLoad($slide, isHTML5VideoWithoutPoster, onLoad, onError) {
      const mediaObject = $slide.find(".lg-object").first();
      const media = mediaObject.get();
      const gated = (handler) => {
        if (media instanceof HTMLImageElement && typeof media.decode === "function") {
          void awaitDecode(media).then(handler);
        } else {
          handler();
        }
      };
      if (utils.isImageLoaded(media) || isHTML5VideoWithoutPoster) {
        gated(onLoad);
      } else {
        mediaObject.on("load.lg error.lg", () => {
          gated(() => onLoad && onLoad());
        });
        mediaObject.on("error.lg", () => {
          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
     */
    onLgObjectLoad(currentSlide, index, delay, speed, isFirstSlide, isHTML5VideoWithoutPoster) {
      this.onSlideObjectLoad(
        currentSlide,
        isHTML5VideoWithoutPoster,
        () => {
          this.triggerSlideItemLoad(
            currentSlide,
            index,
            delay,
            speed,
            isFirstSlide
          );
        },
        () => {
          currentSlide.addClass("lg-complete lg-complete_");
          currentSlide.html(
            '<span class="lg-error-msg">' + this.settings.strings["mediaLoadingFailed"] + "</span>"
          );
        }
      );
    }
    triggerSlideItemLoad($currentSlide, index, delay, speed, isFirstSlide) {
      const currentGalleryItem = this.galleryItems[index];
      const _speed = isFirstSlide && this.getSlideType(currentGalleryItem) === "video" && !currentGalleryItem.poster ? speed : 0;
      setTimeout(() => {
        $currentSlide.addClass("lg-complete lg-complete_");
        this.LGel.trigger(lGEvents.slideItemLoad, {
          index,
          delay: delay || 0,
          isFirstSlide
        });
      }, _speed);
    }
    isFirstSlideWithZoomAnimation() {
      return !!(!this.lGalleryOn && this.zoomFromOrigin && this.currentImageSize);
    }
    // Add video slideInfo
    addSlideVideoInfo(items) {
      items.forEach((element, index) => {
        element.__slideVideoInfo = utils.isVideo(
          element.src,
          !!element.video,
          index
        );
        const videoInfo = element.__slideVideoInfo;
        if (!videoInfo) {
          return;
        }
        if (this.settings.videoFacade !== false) {
          element.poster = getFacadePoster(
            element,
            videoInfo,
            this.settings.loadYouTubePoster
          );
        } else if (this.settings.loadYouTubePoster && !element.poster && videoInfo.youtube) {
          element.poster = getYouTubePosterUrl(videoInfo);
        }
      });
    }
    /**
     *  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.
     */
    loadContent(index, rec) {
      const currentGalleryItem = this.galleryItems[index];
      const $currentSlide = $LG(this.getSlideItemId(index));
      const { poster, srcset, sizes, sources } = currentGalleryItem;
      let { src } = currentGalleryItem;
      const video = currentGalleryItem.video;
      const _html5Video = video && typeof video === "string" ? JSON.parse(video) : video;
      if (currentGalleryItem.responsive) {
        const srcDyItms = currentGalleryItem.responsive.split(",");
        src = utils.getResponsiveSrc(srcDyItms) || src;
      }
      const videoInfo = currentGalleryItem.__slideVideoInfo;
      let lgVideoStyle = "";
      const iframe = !!currentGalleryItem.iframe;
      const isFirstSlide = !this.lGalleryOn;
      let 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) {
          const { top, bottom } = this.mediaContainerPosition;
          const videoSize = utils.getSize(
            this.items[index],
            this.outer,
            top + bottom,
            videoInfo && this.settings.videoMaxSize,
            this.galleryItems[index].lgSize
          );
          lgVideoStyle = this.getVideoContStyle(videoSize);
        }
        if (iframe) {
          const markup = utils.getIframeMarkup(
            this.settings.iframeWidth,
            this.settings.iframeHeight,
            this.settings.iframeMaxWidth,
            this.settings.iframeMaxHeight,
            src,
            currentGalleryItem.iframeTitle
          );
          $currentSlide.prepend(markup);
        } else if (poster) {
          let dummyImg = "";
          const hasStartAnimation = isFirstSlide && this.zoomFromOrigin && this.currentImageSize;
          if (hasStartAnimation) {
            dummyImg = this.getDummyImageContent(
              $currentSlide,
              index,
              ""
            );
          }
          const markup = utils.getVideoPosterMarkup(
            poster,
            dummyImg || "",
            lgVideoStyle,
            this.settings.strings["playVideo"],
            videoInfo
          );
          $currentSlide.prepend(markup);
        } else if (videoInfo) {
          const markup = `<div class="lg-video-cont " style="${lgVideoStyle}"></div>`;
          $currentSlide.prepend(markup);
        } else {
          this.setImgMarkup(src, $currentSlide, index);
        }
        if (poster || videoInfo) {
          this.LGel.trigger(lGEvents.hasVideo, {
            index,
            src,
            html5Video: _html5Video,
            hasPoster: !!poster
          });
        }
        this.LGel.trigger(
          lGEvents.afterAppendSlide,
          { index }
        );
        if (this.lGalleryOn && this.settings.appendSubHtmlTo === ".lg-item") {
          this.addHtml(index);
        }
      }
      let _speed = 0;
      if (delay && !$LG(document.body).hasClass("lg-from-hash")) {
        _speed = delay;
      }
      if (this.isFirstSlideWithZoomAnimation()) {
        const settleFlight = (onLanded) => onTransitionSettle(
          $currentSlide.get(),
          "transform",
          this.settings.startAnimationDuration + 100,
          onLanded
        );
        settleFlight(() => {
          $currentSlide.removeClass("lg-start-end-progress lg-start-progress").removeAttr("style");
        });
        if (!$currentSlide.hasClass("lg-loaded")) {
          settleFlight(() => {
            if (this.getSlideType(currentGalleryItem) === "image") {
              const { alt } = currentGalleryItem;
              const altAttr = alt ? 'alt="' + alt + '"' : "";
              $currentSlide.find(".lg-img-wrap").append(
                utils.getImgMarkup(
                  index,
                  src,
                  altAttr,
                  srcset,
                  sizes,
                  currentGalleryItem.sources
                )
              );
            }
            if (this.getSlideType(currentGalleryItem) === "image" || this.getSlideType(currentGalleryItem) === "video" && poster) {
              this.onLgObjectLoad(
                $currentSlide,
                index,
                delay,
                _speed,
                true,
                false
              );
              this.onSlideObjectLoad(
                $currentSlide,
                !!(videoInfo && videoInfo.html5 && !poster),
                () => {
                  this.loadContentOnFirstSlideLoad(
                    index,
                    $currentSlide,
                    _speed
                  );
                },
                () => {
                  this.loadContentOnFirstSlideLoad(
                    index,
                    $currentSlide,
                    _speed
                  );
                }
              );
            }
          });
        }
      }
      $currentSlide.addClass("lg-loaded");
      if (!this.isFirstSlideWithZoomAnimation() || this.getSlideType(currentGalleryItem) === "video" && !poster) {
        this.onLgObjectLoad(
          $currentSlide,
          index,
          delay,
          _speed,
          isFirstSlide,
          !!(videoInfo && videoInfo.html5 && !poster)
        );
      }
      if ((!this.zoomFromOrigin || !this.currentImageSize) && $currentSlide.hasClass("lg-complete_") && !this.lGalleryOn) {
        setTimeout(() => {
          $currentSlide.addClass("lg-complete");
        }, this.settings.backdropDuration);
      }
      this.lGalleryOn = true;
      if (rec === true) {
        if (!$currentSlide.hasClass("lg-complete_")) {
          $currentSlide.find(".lg-object").first().on("load.lg error.lg", () => {
            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
     */
    loadContentOnFirstSlideLoad(index, $currentSlide, speed) {
      setTimeout(() => {
        $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);
    }
    getItemsToBeInsertedToDom(index, prevIndex, numberOfItems = 0) {
      const itemsToBeInsertedToDom = [];
      let possibleNumberOfItems = Math.max(numberOfItems, 3);
      possibleNumberOfItems = Math.min(
        possibleNumberOfItems,
        this.galleryItems.length
      );
      const prevIndexItem = `lg-item-${this.lgId}-${prevIndex}`;
      if (this.galleryItems.length <= 3) {
        this.galleryItems.forEach((_element, index2) => {
          itemsToBeInsertedToDom.push(`lg-item-${this.lgId}-${index2}`);
        });
        return itemsToBeInsertedToDom;
      }
      if (index < (this.galleryItems.length - 1) / 2) {
        for (let idx = index; idx > index - possibleNumberOfItems / 2 && idx >= 0; idx--) {
          itemsToBeInsertedToDom.push(`lg-item-${this.lgId}-${idx}`);
        }
        const numberOfExistingItems = itemsToBeInsertedToDom.length;
        for (let idx = 0; idx < possibleNumberOfItems - numberOfExistingItems; idx++) {
          itemsToBeInsertedToDom.push(
            `lg-item-${this.lgId}-${index + idx + 1}`
          );
        }
      } else {
        for (let idx = index; idx <= this.galleryItems.length - 1 && idx < index + possibleNumberOfItems / 2; idx++) {
          itemsToBeInsertedToDom.push(`lg-item-${this.lgId}-${idx}`);
        }
        const numberOfExistingItems = itemsToBeInsertedToDom.length;
        for (let 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;
    }
    organizeSlideItems(index, prevIndex) {
      var _a, _b;
      const itemsToBeInsertedToDom = this.getItemsToBeInsertedToDom(
        index,
        prevIndex,
        (_b = (_a = this.settings.virtualization) == null ? void 0 : _a.slides) != null ? _b : this.settings.numberOfSlideItemsInDom
      );
      itemsToBeInsertedToDom.forEach((item) => {
        if (this.currentItemsInDom.indexOf(item) === -1) {
          this.$inner.append(`<div id="${item}" class="lg-item"></div>`);
        }
      });
      this.currentItemsInDom.forEach((item) => {
        if (itemsToBeInsertedToDom.indexOf(item) === -1) {
          $LG(`#${item}`).remove();
        }
      });
      return itemsToBeInsertedToDom;
    }
    /**
     * Get previous index of the slide
     */
    getPreviousSlideIndex() {
      let prevIndex = 0;
      try {
        const currentItemId = this.outer.find(".lg-current").first().attr("id");
        prevIndex = parseInt(currentItemId.split("-")[3]) || 0;
      } catch (error) {
        prevIndex = 0;
      }
      return prevIndex;
    }
    setDownloadValue(index) {
      if (this.settings.download) {
        const currentGalleryItem = this.galleryItems[index];
        const hideDownloadBtn = currentGalleryItem.downloadUrl === false || currentGalleryItem.downloadUrl === "false";
        if (hideDownloadBtn) {
          this.outer.addClass("lg-hide-download");
        } else {
          const $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);
          }
        }
      }
    }
    makeSlideAnimation(direction, currentSlideItem, previousSlideItem) {
      if (this.lGalleryOn) {
        previousSlideItem.addClass("lg-slide-progress");
      }
      setTimeout(
        () => {
          this.outer.addClass("lg-no-trans");
          this.outer.find(".lg-item").removeClass("lg-prev-slide lg-next-slide");
          if (direction === "prev") {
            currentSlideItem.addClass("lg-prev-slide");
            previousSlideItem.addClass("lg-next-slide");
          } else {
            currentSlideItem.addClass("lg-next-slide");
            previousSlideItem.addClass("lg-prev-slide");
          }
          setTimeout(() => {
            this.outer.find(".lg-item").removeClass("lg-current");
            currentSlideItem.addClass("lg-current");
            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
     * @param {Boolean} fromThumb - true if slide function called via thumbnail click
     * @param {String} direction - Direction of the slide(next/prev)
     * @category lGPublicMethods
     * @example
     *  const plugin = lightGallery();
     *  // to go to 3rd slide
     *  plugin.slide(2);
     *
     */
    slide(index, fromTouch, fromThumb, direction) {
      const prevIndex = this.getPreviousSlideIndex();
      this.currentItemsInDom = this.organizeSlideItems(index, prevIndex);
      if (this.lGalleryOn && prevIndex === index) {
        return;
      }
      const numberOfGalleryItems = this.galleryItems.length;
      if (!this.lgBusy) {
        if (this.settings.counter) {
          this.updateCurrentCounter(index);
        }
        this.announceSlide(index);
        const currentSlideItem = this.getSlideItem(index);
        const previousSlideItem = this.getSlideItem(prevIndex);
        const currentGalleryItem = this.galleryItems[index];
        const videoInfo = currentGalleryItem.__slideVideoInfo;
        this.outer.attr(
          "data-lg-slide-type",
          this.getSlideType(currentGalleryItem)
        );
        this.setDownloadValue(index);
        this.updateCurrentImageSize(index);
        if (videoInfo) {
          const { top, bottom } = this.mediaContainerPosition;
          const videoSize = utils.getSize(
            this.items[index],
            this.outer,
            top + bottom,
            videoInfo && this.settings.videoMaxSize,
            this.galleryItems[index].lgSize
          );
          this.resizeVideoSlide(index, videoSize);
        }
        this.LGel.trigger(lGEvents.beforeSlide, {
          prevIndex,
          index,
          fromTouch: !!fromTouch,
          fromThumb: !!fromThumb
        });
        this.lgBusy = true;
        clearTimeout(this.hideBarTimeout);
        this.arrowDisable(index);
        if (!direction) {
          if (index < prevIndex) {
            direction = "prev";
          } else if (index > prevIndex) {
            direction = "next";
          }
        }
        if (!fromTouch) {
          this.makeSlideAnimation(
            direction,
            currentSlideItem,
            previousSlideItem
          );
        } else {
          this.outer.find(".lg-item").removeClass("lg-prev-slide lg-current lg-next-slide");
          let touchPrev;
          let touchNext;
          if (numberOfGalleryItems > 2) {
            touchPrev = index - 1;
            touchNext = index + 1;
            if (index === 0 && prevIndex === numberOfGalleryItems - 1) {
              touchNext = 0;
              touchPrev = numberOfGalleryItems - 1;
            } else if (index === numberOfGalleryItems - 1 && prevIndex === 0) {
              touchNext = 0;
              touchPrev = numberOfGalleryItems - 1;
            }
          } else {
            touchPrev = 0;
            touchNext = 1;
          }
          if (direction === "prev") {
            this.getSlideItem(touchNext).addClass("lg-next-slide");
          } else {
            this.getSlideItem(touchPrev).addClass("lg-prev-slide");
          }
          currentSlideItem.addClass("lg-current");
        }
        if (!this.lGalleryOn) {
          this.loadContent(index, true);
        } else {
          setTimeout(() => {
            this.loadContent(index, true);
            if (this.settings.appendSubHtmlTo !== ".lg-item") {
              this.addHtml(index);
            }
          }, this.settings.speed + 50 + (fromTouch ? 0 : this.settings.slideDelay));
        }
        setTimeout(() => {
          this.lgBusy = false;
          previousSlideItem.removeClass("lg-slide-progress");
          this.LGel.trigger(lGEvents.afterSlide, {
            prevIndex,
            index,
            fromTouch,
            fromThumb
          });
        }, (this.lGalleryOn ? this.settings.speed + 100 : 100) + (fromTouch ? 0 : this.settings.slideDelay));
      }
      this.index = index;
    }
    updateCurrentCounter(index) {
      this.getElementById("lg-counter-current").html(index + 1 + "");
    }
    /**
     * Plain-text caption of a slide for the aria-live announcer. Resolves
     * the same sources addHtml uses (inline subHtml markup or a selector)
     * and strips the markup down to readable text. Remote captions
     * (subHtmlUrl) are skipped, announcing can't wait on a fetch.
     */
    getSlideCaptionText(index) {
      const currentGalleryItem = this.galleryItems[index];
      if (!currentGalleryItem || currentGalleryItem.subHtmlUrl) {
        return "";
      }
      let subHtml = currentGalleryItem.subHtml || "";
      const firstLetter = subHtml.substring(0, 1);
      if (firstLetter === "." || firstLetter === "#") {
        try {
          if (this.settings.subHtmlSelectorRelative && !this.settings.dynamic) {
            subHtml = $LG(this.items).eq(index).find(subHtml).first().html();
          } else {
            subHtml = $LG(subHtml).first().html();
          }
        } catch (error) {
          subHtml = "";
        }
      }
      if (!subHtml) {
        return "";
      }
      const container = document.createElement("div");
      container.innerHTML = subHtml;
      return container.textContent || "";
    }
    /**
     * Update the polite live region with the shown slide's position and
     * caption ("Image X of Y, caption"). The single announcement source,
     * counter and caption bar are not live regions while this is enabled.
     */
    announceSlide(index) {
      if (!this.settings.ariaAnnouncements) {
        return;
      }
      const announcer = this.getElementById("lg-announcer").get();
      if (!announcer) {
        return;
      }
      announcer.textContent = formatSlideAnnouncement({
        template: this.settings.strings["slideAnnouncement"],
        index: index + 1,
        total: this.galleryItems.length,
        caption: this.getSlideCaptionText(index)
      });
    }
    updateCounterTotal() {
      this.getElementById("lg-counter-all").html(
        this.galleryItems.length + ""
      );
    }
    getSlideType(item) {
      if (item.__slideVideoInfo) {
        return "video";
      } else if (item.iframe) {
        return "iframe";
      } else {
        return "image";
      }
    }
    /** Stop a running release spring; visuals stay at the live frame. */
    stopSlideSpring() {
      if (this.cancelSlideSpring) {
        this.cancelSlideSpring();
        this.cancelSlideSpring = void 0;
      }
    }
    touchMove(startCoords, endCoords, e) {
      const distanceX = endCoords.pageX - startCoords.pageX;
      const distanceY = endCoords.pageY - startCoords.pageY;
      this.swipeSamples = pushVelocitySample(this.swipeSamples, {
        x: endCoords.pageX,
        y: endCoords.pageY,
        t: Date.now()
      });
      this.swipeDirection = getSwipeAxis(
        distanceX,
        distanceY,
        this.swipeDirection
      );
      if (!this.swipeDirection) {
        return;
      }
      const $currentSlide = this.getSlideItem(this.index);
      if (this.swipeDirection === "horizontal") {
        e == null ? void 0 : e.preventDefault();
        this.outer.addClass("lg-dragging");
        const transforms = getHorizontalDragTransforms(
          this.getEdgeDragDelta(distanceX),
          $currentSlide.get().offsetWidth,
          this.getDirection()
        );
        $currentSlide.css("transform", transforms.current);
        this.outer.find(".lg-prev-slide").first().css("transform", transforms.prev);
        this.outer.find(".lg-next-slide").first().css("transform", transforms.next);
      } else if (this.swipeDirection === "vertical") {
        if (this.settings.swipeToClose) {
          e == null ? void 0 : e.preventDefault();
          this.$container.addClass("lg-dragging-vertical");
          const effects = getVerticalDragEffects(
            distanceY,
            window.innerWidth,
            window.innerHeight
          );
          this.$backdrop.css("opacity", effects.backdropOpacity);
          $currentSlide.css("transform", effects.transform);
          if (effects.hideUi) {
            this.outer.addClass("lg-hide-items").removeClass("lg-components-open");
          }
        }
      }
    }
    /**
     * The horizontal delta as rendered: rubber-banded when the drag
     * points past the first/last slide with nothing there (loop counts).
     */
    getEdgeDragDelta(distanceX) {
      const count = this.galleryItems.length;
      return getEdgeFrictionedDelta(
        distanceX,
        resolveSwipeTarget(
          "prev",
          this.index,
          count,
          this.settings.loop
        ) !== null,
        resolveSwipeTarget(
          "next",
          this.index,
          count,
          this.settings.loop
        ) !== null,
        this.getDirection()
      );
    }
    /** Resolved reading direction ('auto' is resolved at init). */
    getDirection() {
      return this.settings.direction === "rtl" ? "rtl" : "ltr";
    }
    /**
     * Spring the dragged slides back to rest, seeded with the release
     * velocity. Returns false (no spring) for sub-pixel drags.
     */
    springSlidesBack(deltaX, velocityX) {
      if (Math.abs(deltaX) < 1) {
        return false;
      }
      const $currentSlide = this.getSlideItem(this.index);
      const $prev = this.outer.find(".lg-prev-slide").first();
      const $next = this.outer.find(".lg-next-slide").first();
      const width = $currentSlide.get().offsetWidth;
      this.stopSlideSpring();
      this.cancelSlideSpring = runSprings(
        [{ from: deltaX, velocity: velocityX, target: 0 }],
        ([x]) => {
          const transforms = getHorizontalDragTransforms(
            x,
            width,
            this.getDirection()
          );
          $currentSlide.css("transform", transforms.current);
          $prev.css("transform", transforms.prev);
          $next.css("transform", transforms.next);
        },
        () => {
          this.cancelSlideSpring = void 0;
          this.endDragVisuals();
        }
      );
      return true;
    }
    /**
     * Carry the release velocity into a gesture navigation: navigate
     * immediately (events, counter and busy-lock on time; fromTouch
     * classes flip underneath, inline transforms keep the visuals),
     * then spring the same drag geometry until the arriving slide lands
     * at rest. Falls back to a snap-back when navigation declines
     * (busy, or an edge without loop, the 2.x end animation plays).
     */
    springSlideNavigation(verdict, deltaX, velocityX) {
      const $current = this.getSlideItem(this.index);
      const $prev = this.outer.find(".lg-prev-slide").first();
      const $next = this.outer.find(".lg-next-slide").first();
      const width = $current.get().offsetWidth;
      if (!width) {
        return false;
      }
      const prevIndex = this.index;
      if (verdict === "next") {
        this.goToNextSlide(true);
      } else {
        this.goToPrevSlide(true);
      }
      if (this.index === prevIndex) {
        return this.springSlidesBack(deltaX, velocityX);
      }
      const target = (verdict === "next" ? -1 : 1) * (this.getDirection() === "rtl" ? -1 : 1) * (width * 115 / 110);
      this.stopSlideSpring();
      this.cancelSlideSpring = runSprings(
        [{ from: deltaX, velocity: velocityX, target }],
        ([x]) => {
          const transforms = getHorizontalDragTransforms(
            x,
            width,
            this.getDirection()
          );
          $current.css("transform", transforms.current);
          $prev.css("transform", transforms.prev);
          $next.css("transform", transforms.next);
        },
        () => {
          this.cancelSlideSpring = void 0;
          this.endDragVisuals();
        }
      );
      return true;
    }
    /**
     * Hand the slides back to CSS after a gesture. The inline transforms
     * go first, while lg-dragging still pins transition-duration to 0s,
     * so the snap from the released position to the slide's resting
     * place lands in a single frame. Dropping the class first animates
     * that snap instead, and the outgoing slide is seen travelling back
     * toward the centre while its fade is still running.
     */
    endDragVisuals() {
      this.outer.find(".lg-item").removeAttr("style");
      if (this.settings.mode !== "lg-slide") {
        this.outer.removeClass("lg-slide");
      }
      void this.outer.get().offsetHeight;
      this.outer.removeClass("lg-dragging");
    }
    /**
     * Spring a non-closing vertical drag back to rest, slide transform
     * and backdrop opacity together, seeded with the release velocity.
     */
    springVerticalRestore(deltaY, velocityY) {
      if (Math.abs(deltaY) < 1) {
        return false;
      }
      const $currentSlide = this.getSlideItem(this.index);
      this.stopSlideSpring();
      this.$container.addClass("lg-dragging-vertical");
      this.cancelSlideSpring = runSprings(
        [{ from: deltaY, velocity: velocityY, target: 0 }],
        ([y]) => {
          const effects = getVerticalDragEffects(
            y,
            window.innerWidth,
            window.innerHeight
          );
          this.$backdrop.css("opacity", effects.backdropOpacity);
          $currentSlide.css("transform", effects.transform);
        },
        () => {
          this.cancelSlideSpring = void 0;
          this.$container.removeClass("lg-dragging-vertical");
          this.endDragVisuals();
          this.$backdrop.css("opacity", 1);
        }
      );
      return true;
    }
    touchEnd(endCoords, startCoords, event) {
      const releaseVelocity = getWindowedVelocity(
        this.swipeSamples,
        Date.now()
      );
      if (this.settings.mode !== "lg-slide") {
        this.outer.addClass("lg-slide");
      }
      setTimeout(() => {
        this.$container.removeClass("lg-dragging-vertical");
        this.outer.removeClass("lg-hide-items").addClass("lg-components-open");
        let triggerClick = true;
        let springing = false;
        if (this.swipeDirection === "horizontal") {
          const verdict = getSwipeReleaseVerdict({
            deltaX: endCoords.pageX - startCoords.pageX,
            velocityX: releaseVelocity.x,
            threshold: this.settings.swipeThreshold,
            flickVelocity: this.settings.flickVelocity,
            viewportWidth: this.outer.get().offsetWidth,
            direction: this.getDirection()
          });
          const renderedDeltaX = this.getEdgeDragDelta(
            endCoords.pageX - startCoords.pageX
          );
          if (verdict === "next" || verdict === "prev") {
            triggerClick = false;
            springing = this.springSlideNavigation(
              verdict,
              renderedDeltaX,
              releaseVelocity.x
            );
          } else {
            springing = this.springSlidesBack(
              renderedDeltaX,
              releaseVelocity.x
            );
          }
        } else if (this.swipeDirection === "vertical") {
          if (shouldCloseOnVerticalDrag(
            endCoords.pageY - startCoords.pageY,
            releaseVelocity.y,
            window.innerHeight,
            {
              closable: this.settings.closable,
              swipeToClose: this.settings.swipeToClose
            }
          )) {
            this.closeGallery();
            return;
          }
          if (this.settings.swipeToClose) {
            springing = this.springVerticalRestore(
              endCoords.pageY - startCoords.pageY,
              releaseVelocity.y
            );
          }
        }
        if (!springing) {
          this.endDragVisuals();
          this.$backdrop.css("opacity", 1);
        }
        if (triggerClick && Math.abs(endCoords.pageX - startCoords.pageX) < 5) {
          const target = $LG(event.target);
          if (this.isPosterElement(target)) {
            this.LGel.trigger(lGEvents.posterClick);
          }
        }
        this.swipeDirection = void 0;
      });
      setTimeout(() => {
        if (!this.outer.hasClass("lg-dragging") && this.settings.mode !== "lg-slide") {
          this.outer.removeClass("lg-slide");
        }
      }, this.settings.speed + 100);
    }
    enableSwipe() {
      let startCoords = {};
      let endCoords = {};
      let isMoved = false;
      let isSwiping = false;
      if (this.settings.enableSwipe) {
        this.$inner.on("touchstart.lg", (e) => {
          this.dragOrSwipeEnabled = true;
          const $item = this.getSlideItem(this.index);
          if (($LG(e.target).hasClass("lg-item") || $item.get().contains(e.target)) && !this.outer.hasClass("lg-zoomed") && !this.lgBusy && e.touches.length === 1) {
            isSwiping = true;
            this.touchAction = "swipe";
            isMoved = false;
            endCoords = {};
            this.stopSlideSpring();
            this.manageSwipeClass();
            this.swipeSamples = [
              {
                x: e.touches[0].pageX,
                y: e.touches[0].pageY,
                t: Date.now()
              }
            ];
            startCoords = {
              pageX: e.touches[0].pageX,
              pageY: e.touches[0].pageY
            };
          }
        });
        this.$inner.on("touchmove.lg", (e) => {
          if (isSwiping && this.touchAction === "swipe" && e.touches.length === 1) {
            endCoords = {
              pageX: e.touches[0].pageX,
              pageY: e.touches[0].pageY
            };
            this.touchMove(startCoords, endCoords, e);
            isMoved = true;
          }
        });
        this.$inner.on("touchend.lg", (event) => {
          if (this.touchAction === "swipe") {
            if (isMoved) {
              isMoved = false;
              this.touchEnd(endCoords, startCoords, event);
            } else if (isSwiping) {
              const target = $LG(event.target);
              if (this.isPosterElement(target)) {
                this.LGel.trigger(lGEvents.posterClick);
              }
            }
            this.touchAction = void 0;
            isSwiping = false;
          }
        });
      }
    }
    enableDrag() {
      let startCoords = {};
      let endCoords = {};
      let isDraging = false;
      let isMoved = false;
      if (this.settings.enableDrag) {
        this.outer.on("mousedown.lg", (e) => {
          this.dragOrSwipeEnabled = true;
          const $item = this.getSlideItem(this.index);
          if ($LG(e.target).hasClass("lg-item") || $item.get().contains(e.target)) {
            if (!this.outer.hasClass("lg-zoomed") && !this.lgBusy) {
              e.preventDefault();
              this.stopSlideSpring();
              this.manageSwipeClass();
              this.swipeSamples = [
                { x: e.pageX, y: e.pageY, t: Date.now() }
              ];
              startCoords = {
                pageX: e.pageX,
                pageY: e.pageY
              };
              isDraging = true;
              this.outer.get().scrollLeft += 1;
              this.outer.get().scrollLeft -= 1;
              this.outer.removeClass("lg-grab").addClass("lg-grabbing");
              this.LGel.trigger(lGEvents.dragStart);
            }
          }
        });
        $LG(window).on(`mousemove.lg.global${this.lgId}`, (e) => {
          if (isDraging && this.lgOpened) {
            isMoved = true;
            endCoords = {
              pageX: e.pageX,
              pageY: e.pageY
            };
            this.touchMove(startCoords, endCoords);
            this.LGel.trigger(lGEvents.dragMove);
          }
        });
        $LG(window).on(`mouseup.lg.global${this.lgId}`, (event) => {
          if (!this.lgOpened) {
            return;
          }
          const target = $LG(event.target);
          if (isMoved) {
            isMoved = false;
            this.touchEnd(endCoords, startCoords, event);
            this.LGel.trigger(lGEvents.dragEnd);
          } else if (this.isPosterElement(target)) {
            this.LGel.trigger(lGEvents.posterClick);
          }
          if (isDraging) {
            isDraging = false;
            this.outer.removeClass("lg-grabbing").addClass("lg-grab");
          }
        });
      }
    }
    triggerPosterClick() {
      this.$inner.on("click.lg", (event) => {
        if (!this.dragOrSwipeEnabled && this.isPosterElement($LG(event.target))) {
          this.LGel.trigger(lGEvents.posterClick);
        }
      });
    }
    manageSwipeClass() {
      let _touchNext = this.index + 1;
      let _touchPrev = this.index - 1;
      if (this.settings.loop && this.galleryItems.length > 2) {
        if (this.index === 0) {
          _touchPrev = this.galleryItems.length - 1;
        } else if (this.index === this.galleryItems.length - 1) {
          _touchNext = 0;
        }
      }
      this.outer.find(".lg-item").removeClass("lg-next-slide lg-prev-slide");
      if (_touchPrev > -1) {
        this.getSlideItem(_touchPrev).addClass("lg-prev-slide");
      }
      this.getSlideItem(_touchNext).addClass("lg-next-slide");
    }
    /**
     * Go to next slide
     * @param {Boolean} fromTouch - true if slide function called via touch event
     * @category lGPublicMethods
     * @example
     *  const plugin = lightGallery();
     *  plugin.goToNextSlide();
     * @see <a href="/demos/methods/">Demo</a>
     */
    goToNextSlide(fromTouch) {
      let _loop = this.settings.loop;
      if (fromTouch && this.galleryItems.length < 3) {
        _loop = false;
      }
      if (!this.lgBusy) {
        if (this.index + 1 < this.galleryItems.length) {
          this.index++;
          this.LGel.trigger(lGEvents.beforeNextSlide, {
            index: this.index
          });
          this.slide(this.index, !!fromTouch, false, "next");
        } else {
          if (_loop) {
            this.index = 0;
            this.LGel.trigger(lGEvents.beforeNextSlide, {
              index: this.index
            });
            this.slide(this.index, !!fromTouch, false, "next");
          } else if (this.settings.slideEndAnimation && !fromTouch) {
            this.outer.addClass("lg-right-end");
            setTimeout(() => {
              this.outer.removeClass("lg-right-end");
            }, 400);
          }
        }
      }
    }
    /**
     * Go to previous slide
     * @param {Boolean} fromTouch - true if slide function called via touch event
     * @category lGPublicMethods
     * @example
     *  const plugin = lightGallery({});
     *  plugin.goToPrevSlide();
     * @see <a href="/demos/methods/">Demo</a>
     *
     */
    goToPrevSlide(fromTouch) {
      let _loop = this.settings.loop;
      if (fromTouch && this.galleryItems.length < 3) {
        _loop = false;
      }
      if (!this.lgBusy) {
        if (this.index > 0) {
          this.index--;
          this.LGel.trigger(lGEvents.beforePrevSlide, {
            index: this.index,
            fromTouch
          });
          this.slide(this.index, !!fromTouch, false, "prev");
        } else {
          if (_loop) {
            this.index = this.galleryItems.length - 1;
            this.LGel.trigger(lGEvents.beforePrevSlide, {
              index: this.index,
              fromTouch
            });
            this.slide(this.index, !!fromTouch, false, "prev");
          } else if (this.settings.slideEndAnimation && !fromTouch) {
            this.outer.addClass("lg-left-end");
            setTimeout(() => {
              this.outer.removeClass("lg-left-end");
            }, 400);
          }
        }
      }
    }
    keyPress() {
      $LG(window).on(`keydown.lg.global${this.lgId}`, (e) => {
        if (this.lgOpened && this.settings.escKey === true && e.keyCode === 27) {
          e.preventDefault();
          if (this.settings.allowMediaOverlap && this.outer.hasClass("lg-can-toggle") && this.outer.hasClass("lg-components-open")) {
            this.outer.removeClass("lg-components-open");
          } else {
            this.closeGallery();
          }
        }
        if (this.lgOpened && this.galleryItems.length > 1) {
          const rtl = this.getDirection() === "rtl";
          if (e.keyCode === 37) {
            e.preventDefault();
            if (rtl) {
              this.goToNextSlide();
            } else {
              this.goToPrevSlide();
            }
          }
          if (e.keyCode === 39) {
            e.preventDefault();
            if (rtl) {
              this.goToPrevSlide();
            } else {
              this.goToNextSlide();
            }
          }
        }
      });
    }
    arrow() {
      this.getElementById("lg-prev").on("click.lg", () => {
        this.goToPrevSlide();
      });
      this.getElementById("lg-next").on("click.lg", () => {
        this.goToNextSlide();
      });
    }
    arrowDisable(index) {
      if (!this.settings.loop && this.settings.hideControlOnEnd) {
        const $prev = this.getElementById("lg-prev");
        const $next = this.getElementById("lg-next");
        if (index + 1 === this.galleryItems.length) {
          $next.attr("disabled", "disabled").addClass("disabled");
        } else {
          $next.removeAttr("disabled").removeClass("disabled");
        }
        if (index === 0) {
          $prev.attr("disabled", "disabled").addClass("disabled");
        } else {
          $prev.removeAttr("disabled").removeClass("disabled");
        }
      }
    }
    setTranslate($el, xValue, yValue, scaleX = 1, scaleY = 1) {
      $el.css(
        "transform",
        "translate3d(" + xValue + "px, " + yValue + "px, 0px) scale3d(" + scaleX + ", " + scaleY + ", 1)"
      );
    }
    mousewheel() {
      let lastCall = 0;
      this.outer.on("wheel.lg", (e) => {
        if (!e.deltaY || this.galleryItems.length < 2) {
          return;
        }
        e.preventDefault();
        const now = (/* @__PURE__ */ new Date()).getTime();
        if (now - lastCall < 1e3) {
          return;
        }
        lastCall = now;
        if (e.deltaY > 0) {
          this.goToNextSlide();
        } else if (e.deltaY < 0) {
          this.goToPrevSlide();
        }
      });
    }
    isSlideElement(target) {
      return target.hasClass("lg-outer") || target.hasClass("lg-item") || target.hasClass("lg-img-wrap") || target.hasClass("lg-img-rotate");
    }
    isPosterElement(target) {
      const playButton = this.getSlideItem(this.index).find(".lg-video-play-button").get();
      return target.hasClass("lg-video-poster") || target.hasClass("lg-video-play-button") || playButton && playButton.contains(target.get());
    }
    /**
     * Bind the inline gallery's maximize button: each click toggles the
     * gallery between its container and the full viewport. Called once
     * during initialization.
     */
    toggleMaximize() {
      this.getElementById("lg-maximize").on("click.lg", () => {
        this.$container.toggleClass("lg-inline");
        this.refreshOnResize();
      });
    }
    invalidateItems() {
      for (let index = 0; index < this.items.length; index++) {
        const element = this.items[index];
        const $element = $LG(element);
        $element.off(`click.lgcustom-item-${$element.attr("data-lg-id")}`);
      }
    }
    trapFocus() {
      this.$container.get().focus({
        preventScroll: true
      });
      $LG(window).on(`keydown.lg.global${this.lgId}`, (e) => {
        if (!this.lgOpened) {
          return;
        }
        const isTabPressed = e.key === "Tab" || e.keyCode === 9;
        if (!isTabPressed) {
          return;
        }
        const focusableEls = utils.getFocusableElements(
          this.$container.get()
        );
        const firstFocusableEl = focusableEls[0];
        const lastFocusableEl = focusableEls[focusableEls.length - 1];
        if (e.shiftKey) {
          if (document.activeElement === firstFocusableEl) {
            lastFocusableEl.focus();
            e.preventDefault();
          }
        } else {
          if (document.activeElement === lastFocusableEl) {
            firstFocusableEl.focus();
            e.preventDefault();
          }
        }
      });
    }
    manageCloseGallery() {
      if (!this.settings.closable) return;
      let mousedown = false;
      this.getElementById("lg-close").on("click.lg", () => {
        this.closeGallery();
      });
      if (this.settings.closeOnTap) {
        this.outer.on("mousedown.lg", (e) => {
          const target = $LG(e.target);
          if (this.isSlideElement(target)) {
            mousedown = true;
          } else {
            mousedown = false;
          }
        });
        this.outer.on("mousemove.lg", () => {
          mousedown = false;
        });
        this.outer.on("mouseup.lg", (e) => {
          const target = $LG(e.target);
          if (this.isSlideElement(target) && mousedown) {
            if (!this.outer.hasClass("lg-dragging")) {
              this.closeGallery();
            }
          }
        });
      }
    }
    /**
     * Close lightGallery if it is opened.
     *
     * @description If closable is false in the settings, you need to pass true via closeGallery method to force close gallery
     * @return returns the estimated time to close gallery completely including the close animation duration
     * @category lGPublicMethods
     * @example
     *  const plugin = lightGallery();
     *  plugin.closeGallery();
     *
     */
    closeGallery(force) {
      if (!this.lgOpened || !this.settings.closable && !force) {
        return 0;
      }
      this.LGel.trigger(lGEvents.beforeClose);
      if (this.settings.resetScrollPosition && !this.settings.hideScrollbar) {
        $LG(window).scrollTop(this.prevScrollTop);
      }
      const currentItem = this.items[this.index];
      let transform;
      if (this.zoomFromOrigin && currentItem) {
        const { top, bottom } = this.mediaContainerPosition;
        const { __slideVideoInfo, poster } = this.galleryItems[this.index];
        const imageSize = utils.getSize(
          currentItem,
          this.outer,
          top + bottom,
          __slideVideoInfo && poster && this.settings.videoMaxSize
        );
        transform = this.getOriginTransform(currentItem, imageSize);
      }
      if (!transform) {
        transform = getCenterCloseTransform();
        this.outer.addClass("lg-close-to-center");
      }
      if (transform) {
        this.outer.addClass("lg-closing lg-zoom-from-image");
        this.getSlideItem(this.index).addClass("lg-start-end-progress").css(
          "transition-duration",
          this.settings.startAnimationDuration + "ms"
        ).css("transform", transform);
      } else {
        this.outer.addClass("lg-hide-items");
        this.outer.removeClass("lg-zoom-from-image");
      }
      this.destroyModules();
      this.lGalleryOn = false;
      this.isDummyImageRemoved = false;
      this.zoomFromOrigin = this.settings.zoomFromOrigin;
      clearTimeout(this.hideBarTimeout);
      this.hideBarTimeout = false;
      $LG("html").removeClass("lg-on");
      this.outer.removeClass("lg-visible lg-components-open");
      this.$backdrop.removeClass("in").css("opacity", 0);
      const removeTimeout = transform ? Math.max(
        this.settings.startAnimationDuration,
        this.settings.backdropDuration
      ) : this.settings.backdropDuration;
      this.$container.removeClass("lg-show-in");
      setTimeout(() => {
        if (transform) {
          this.outer.removeClass("lg-zoom-from-image");
        }
        this.$container.removeClass("lg-show");
        this.resetScrollBar();
        this.$backdrop.removeAttr("style").css(
          "transition-duration",
          this.settings.backdropDuration + "ms"
        );
        this.outer.removeClass(
          `lg-closing lg-close-to-center ${this.settings.startClass}`
        );
        this.getSlideItem(this.index).removeClass("lg-start-end-progress");
        this.$inner.empty();
        const announcer = this.getElementById("lg-announcer").get();
        if (announcer) {
          announcer.textContent = "";
        }
        if (this.lgOpened) {
          this.LGel.trigger(lGEvents.afterClose, {
            instance: this
          });
        }
        if (this.$container.get()) {
          this.$container.get().blur();
        }
        if (this.prevActiveElement && this.prevActiveElement.isConnected) {
          this.prevActiveElement.focus({ preventScroll: true });
        }
        this.prevActiveElement = void 0;
        this.lgOpened = false;
      }, removeTimeout + 100);
      return removeTimeout + 100;
    }
    initModules() {
      this.plugins.forEach((module2) => {
        try {
          module2.init();
        } catch (err) {
          console.warn(
            `lightGallery:- make sure lightGallery module is properly initiated. See https://www.lightgalleryjs.com/docs/methods/`
          );
        }
      });
    }
    destroyModules(destroy) {
      this.plugins.forEach((module2) => {
        try {
          if (destroy) {
            module2.destroy();
          } else {
            module2.closeGallery && module2.closeGallery();
          }
        } catch (err) {
          console.warn(
            `lightGallery:- make sure lightGallery module is properly destroyed. See https://www.lightgalleryjs.com/docs/methods/`
          );
        }
      });
    }
    /**
     * Refresh lightGallery with new set of children.
     *
     * @description This is useful to update the gallery when the child elements are changed without calling destroy method.
     *
     * If you are using dynamic mode, you can pass the modified array of dynamicEl as the first parameter to refresh the dynamic gallery
     * @see <a href="/demos/dynamic-mode/">Demo</a>
     * @category lGPublicMethods
     * @example
     *  const plugin = lightGallery();
     *  // Delete or add children, then call
     *  plugin.refresh();
     *
     */
    refresh(galleryItems) {
      if (!this.settings.dynamic) {
        this.invalidateItems();
      }
      if (galleryItems) {
        this.galleryItems = galleryItems;
      } else {
        this.galleryItems = this.getItems();
      }
      this.updateControls();
      this.openGalleryOnItemClick();
      this.LGel.trigger(lGEvents.updateSlides);
    }
    updateControls() {
      this.addSlideVideoInfo(this.galleryItems);
      this.updateCounterTotal();
      this.manageSingleSlideClassName();
    }
    destroyGallery() {
      var _a;
      this.destroyModules(true);
      if (!this.settings.dynamic) {
        this.invalidateItems();
      }
      $LG(window).off(`.lg.global${this.lgId}`);
      this.LGel.off(".lg");
      (_a = this.toolbarOverflow) == null ? void 0 : _a.destroy();
      this.toolbarOverflow = void 0;
      this.$container.remove();
    }
    /**
     * Destroy lightGallery.
     * Destroy lightGallery and its plugin instances completely
     *
     * @description This method also calls closeGallery function internally. Returns the time it takes to completely close and destroy the instance.
     * In case if you want to re-initialize lightGallery right after destroying it, initialize it only once the destroy process is completed.
     * You can use refresh method most of the time.
     * @category lGPublicMethods
     * @example
     *  const plugin = lightGallery();
     *  plugin.destroy();
     *
     */
    destroy() {
      const closeTimeout = this.closeGallery(true);
      if (closeTimeout) {
        setTimeout(this.destroyGallery.bind(this), closeTimeout);
      } else {
        this.destroyGallery();
      }
      return closeTimeout;
    }
  }
  function lightGallery(el, options) {
    return new LightGallery(el, options);
  }
  lightGallery.setLicenseKey = setLicenseKey;
  return lightGallery;
});
//# sourceMappingURL=lightgallery.umd.js.map