diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 00000000..dfe07704
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1,2 @@
+# Auto detect text files and perform LF normalization
+* text=auto
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 00000000..a203bce5
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,2 @@
+img/
+node_modules/
\ No newline at end of file
diff --git a/index.html b/index.html
new file mode 100644
index 00000000..65447b7f
--- /dev/null
+++ b/index.html
@@ -0,0 +1,208 @@
+
+
+
+
+
+
+ A plugin that adds tile-based zoom support to PhotoSwipe. Supports Deepzoom and Zoomify tile formats.
+
+
Unlike conventional viewers such as OpenLayers or OpenSeaDragon , it displays tiles only when user zooms beyond the primary image size. If user does not zoom - PhotoSwipe operates as usual.
+
Also adds incremental zoom buttons and overrides double-tap behaviour.
+
+
+
+
+
+
+
The Starry Night
+
+ Vincent van Gogh
+
+ DeepZoom tile format
+
+ size 30000x23756px
+
+
+
+
+
+
+
+
+
+
+
+
+ Display layer borders
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/lib/photoswipe/photoswipe-lightbox.esm.js b/lib/photoswipe/photoswipe-lightbox.esm.js
new file mode 100644
index 00000000..87674fdc
--- /dev/null
+++ b/lib/photoswipe/photoswipe-lightbox.esm.js
@@ -0,0 +1,709 @@
+/*!
+ * PhotoSwipe Lightbox 5.1.5 - https://photoswipe.com
+ * (c) 2021 Dmitry Semenov
+ */
+/**
+ * Creates element and optionally appends it to another.
+ *
+ * @param {String} className
+ * @param {String|NULL} tagName
+ * @param {Element|NULL} appendToEl
+ */
+
+/**
+ * Check if click or keydown event was dispatched
+ * with a special key or via mouse wheel.
+ *
+ * @param {Event} e
+ */
+function specialKeyUsed(e) {
+ if (e.which === 2 || e.ctrlKey || e.metaKey || e.altKey || e.shiftKey) {
+ return true;
+ }
+}
+
+/**
+ * Parse `gallery` or `children` options.
+ *
+ * @param {Element|NodeList|String} option
+ * @param {String|null} legacySelector
+ * @param {Element|null} parent
+ * @returns Element[]
+ */
+function getElementsFromOption(option, legacySelector, parent = document) {
+ let elements = [];
+
+ if (option instanceof Element) {
+ elements = [option];
+ } else if (option instanceof NodeList || Array.isArray(option)) {
+ elements = Array.from(option);
+ } else {
+ const selector = typeof option === 'string' ? option : legacySelector;
+ if (selector) {
+ elements = Array.from(parent.querySelectorAll(selector));
+ }
+ }
+
+ return elements;
+}
+
+function getViewportSize(options, pswp) {
+ if (options.getViewportSizeFn) {
+ const newViewportSize = options.getViewportSizeFn(options, pswp);
+ if (newViewportSize) {
+ return newViewportSize;
+ }
+ }
+
+ return {
+ x: document.documentElement.clientWidth,
+
+ // TODO: height on mobile is very incosistent due to toolbar
+ // find a way to improve this
+ //
+ // document.documentElement.clientHeight - doesn't seem to work well
+ y: window.innerHeight
+ };
+}
+
+function getPanAreaSize(options, viewportSize/*, pswp*/) {
+ return {
+ x: viewportSize.x - (options.paddingLeft || 0) - (options.paddingRight || 0),
+ y: viewportSize.y - (options.paddingTop || 0) - (options.paddingBottom || 0)
+ };
+}
+
+/**
+ * Calculates zoom levels for specific slide.
+ * Depends on viewport size and image size.
+ */
+
+const MAX_IMAGE_WIDTH = 3000;
+
+class ZoomLevel {
+ /**
+ * @param {Object} options PhotoSwipe options
+ * @param {Object} itemData Slide data
+ * @param {Integer} index Slide index
+ * @param {PhotoSwipe|undefined} pswp PhotoSwipe instance, can be undefined if not initialized yet
+ */
+ constructor(options, itemData, index, pswp) {
+ this.pswp = pswp;
+ this.options = options;
+ this.itemData = itemData;
+ this.index = index;
+ }
+
+ /**
+ * Calculate initial, secondary and maximum zoom level for the specified slide.
+ *
+ * It should be called when either image or viewport size changes.
+ *
+ * @param {Slide} slide
+ */
+ update(maxWidth, maxHeight, panAreaSize) {
+ this.elementSize = {
+ x: maxWidth,
+ y: maxHeight
+ };
+
+ this.panAreaSize = panAreaSize;
+
+ const hRatio = this.panAreaSize.x / this.elementSize.x;
+ const vRatio = this.panAreaSize.y / this.elementSize.y;
+
+ this.fit = Math.min(1, hRatio < vRatio ? hRatio : vRatio);
+ this.fill = Math.min(1, hRatio > vRatio ? hRatio : vRatio);
+
+ // zoom.vFill defines zoom level of the image
+ // when it has 100% of viewport vertical space (height)
+ this.vFill = Math.min(1, vRatio);
+
+ this.initial = this._getInitial();
+ this.secondary = this._getSecondary();
+ this.max = Math.max(
+ this.initial,
+ this.secondary,
+ this._getMax()
+ );
+
+ this.min = Math.min(
+ this.fit,
+ this.initial,
+ this.secondary
+ );
+
+ if (this.pswp) {
+ this.pswp.dispatch('zoomLevelsUpdate', { zoomLevels: this, slideData: this.itemData });
+ }
+ }
+
+ /**
+ * Parses user-defined zoom option.
+ *
+ * @param {Mixed} optionPrefix Zoom level option prefix (initial, secondary, max)
+ */
+ _parseZoomLevelOption(optionPrefix) {
+ // zoom.initial
+ // zoom.secondary
+ // zoom.max
+ const optionValue = this.options[optionPrefix + 'ZoomLevel'];
+
+ if (!optionValue) {
+ return;
+ }
+
+ if (typeof optionValue === 'function') {
+ return optionValue(this);
+ }
+
+ if (optionValue === 'fill') {
+ return this.fill;
+ }
+
+ if (optionValue === 'fit') {
+ return this.fit;
+ }
+
+ return Number(optionValue);
+ }
+
+ /**
+ * Get zoom level to which image will be zoomed after double-tap gesture,
+ * or when user clicks on zoom icon,
+ * or mouse-click on image itself.
+ * If you return 1 image will be zoomed to its original size.
+ *
+ * @return {Number}
+ */
+ _getSecondary() {
+ let currZoomLevel = this._parseZoomLevelOption('secondary');
+
+ if (currZoomLevel) {
+ return currZoomLevel;
+ }
+
+ // 2.5x of "fit" state, but not larger than original
+ currZoomLevel = Math.min(1, this.fit * 2.5);
+
+ if (currZoomLevel * this.elementSize.x > MAX_IMAGE_WIDTH) {
+ currZoomLevel = MAX_IMAGE_WIDTH / this.elementSize.x;
+ }
+
+ return currZoomLevel;
+ }
+
+ /**
+ * Get initial image zoom level.
+ *
+ * @return {Number}
+ */
+ _getInitial() {
+ return this._parseZoomLevelOption('initial') || this.fit;
+ }
+
+ /**
+ * Maximum zoom level when user zooms
+ * via zoom/pinch gesture,
+ * via cmd/ctrl-wheel or via trackpad.
+ *
+ * @return {Number}
+ */
+ _getMax() {
+ const currZoomLevel = this._parseZoomLevelOption('max');
+
+ if (currZoomLevel) {
+ return currZoomLevel;
+ }
+
+ // max zoom level is x4 from "fit state",
+ // used for zoom gesture and ctrl/trackpad zoom
+ return Math.max(1, this.fit * 4);
+ }
+}
+
+/**
+ * Lazy-load an image
+ * This function is used both by Lightbox and PhotoSwipe core,
+ * thus it can be called before dialog is opened.
+ *
+ * @param {Object} itemData Data about the slide
+ * @param {Object} instance PhotoSwipe or PhotoSwipeLightbox eventable instance
+ * @param {Boolean} decode Wether decode() should be used.
+ * @returns {Object|Boolean} Image that is being decoded or false.
+ */
+function lazyLoadData(itemData, instance, decode) {
+ if (itemData.src && itemData.w && itemData.h) {
+ const { options } = instance;
+
+ // We need to know dimensions of the image to preload it,
+ // as it might use srcset and we need to define sizes
+ const viewportSize = instance.viewportSize || getViewportSize(options);
+ const panAreaSize = getPanAreaSize(options, viewportSize);
+
+ const zoomLevel = new ZoomLevel(options, itemData, -1);
+ zoomLevel.update(itemData.w, itemData.h, panAreaSize);
+
+ const image = document.createElement('img');
+ image.decoding = 'async';
+ image.sizes = Math.ceil(itemData.w * zoomLevel.initial) + 'px';
+ if (itemData.srcset) {
+ image.srcset = itemData.srcset;
+ }
+ image.src = itemData.src;
+ if (decode && ('decode' in image)) {
+ image.decode();
+ }
+
+ return image;
+ }
+}
+
+/**
+ * Lazy-loads specific slide.
+ * This function is used both by Lightbox and PhotoSwipe core,
+ * thus it can be called before dialog is opened.
+ *
+ * By default it loads image based on viewport size and initial zoom level.
+ *
+ * @param {Integer} index Slide index
+ * @param {Object} instance PhotoSwipe or PhotoSwipeLightbox eventable instance
+ */
+function lazyLoadSlide(index, instance) {
+ const itemData = instance.getItemData(index);
+
+ if (instance.dispatch('lazyLoadSlide', { index, itemData }).defaultPrevented) {
+ return;
+ }
+
+ lazyLoadData(itemData, instance);
+}
+
+function dynamicImportModule(module) {
+ return typeof module === 'string' ? import(/* webpackIgnore: true */ module) : module;
+}
+
+/**
+ * Base PhotoSwipe event object
+ */
+class PhotoSwipeEvent {
+ constructor(type, details) {
+ this.type = type;
+ if (details) {
+ Object.assign(this, details);
+ }
+ }
+
+ preventDefault() {
+ this.defaultPrevented = true;
+ }
+}
+
+/**
+ * PhotoSwipe base class that can listen and dispatch for events.
+ * Shared by PhotoSwipe Core and PhotoSwipe Lightbox, extended by base.js
+ */
+class Eventable {
+ constructor() {
+ this._listeners = {};
+ }
+
+ on(name, fn) {
+ if (!this._listeners[name]) {
+ this._listeners[name] = [];
+ }
+ this._listeners[name].push(fn);
+
+ // When binding events to lightbox,
+ // also bind events to PhotoSwipe Core,
+ // if it's open.
+ if (this.pswp) {
+ this.pswp.on(name, fn);
+ }
+ }
+
+ off(name, fn) {
+ if (this._listeners[name]) {
+ this._listeners[name] = this._listeners[name].filter(listener => (fn !== listener));
+ }
+
+ if (this.pswp) {
+ this.pswp.off(name, fn);
+ }
+ }
+
+ dispatch(name, details) {
+ if (this.pswp) {
+ return this.pswp.dispatch(name, details);
+ }
+
+ const event = new PhotoSwipeEvent(name, details);
+
+ if (!this._listeners) {
+ return event;
+ }
+
+ if (this._listeners[name]) {
+ this._listeners[name].forEach((listener) => {
+ listener.call(this, event);
+ });
+ }
+
+ return event;
+ }
+}
+
+/**
+ * PhotoSwipe base class that can retrieve data about every slide.
+ * Shared by PhotoSwipe Core and PhotoSwipe Lightbox
+ */
+
+class PhotoSwipeBase extends Eventable {
+ /**
+ * Get total number of slides
+ */
+ getNumItems() {
+ let numItems;
+ const { dataSource } = this.options;
+ if (!dataSource) {
+ numItems = 0;
+ } else if (dataSource.length) {
+ // may be an array or just object with length property
+ numItems = dataSource.length;
+ } else if (dataSource.gallery) {
+ // query DOM elements
+ if (!dataSource.items) {
+ dataSource.items = this._getGalleryDOMElements(dataSource.gallery);
+ }
+
+ if (dataSource.items) {
+ numItems = dataSource.items.length;
+ }
+ }
+
+ // allow to filter number of items
+ const event = this.dispatch('numItems', {
+ dataSource,
+ numItems
+ });
+
+ return event.numItems;
+ }
+
+ /**
+ * Get item data by index.
+ *
+ * "item data" should contain normalized information that PhotoSwipe needs to generate a slide.
+ * For example, it may contain properties like
+ * `src`, `srcset`, `w`, `h`, which will be used to generate a slide with image.
+ *
+ * @param {Integer} index
+ */
+ getItemData(index) {
+ const { dataSource } = this.options;
+ let dataSourceItem;
+ if (Array.isArray(dataSource)) {
+ // Datasource is an array of elements
+ dataSourceItem = dataSource[index];
+ } else if (dataSource && dataSource.gallery) {
+ // dataSource has gallery property,
+ // thus it was created by Lightbox, based on
+ // gallerySelecor and childSelector options
+
+ // query DOM elements
+ if (!dataSource.items) {
+ dataSource.items = this._getGalleryDOMElements(dataSource.gallery);
+ }
+
+ dataSourceItem = dataSource.items[index];
+ }
+
+ let itemData = dataSourceItem;
+
+ if (itemData instanceof Element) {
+ itemData = this._domElementToItemData(itemData);
+ }
+
+ // allow to filter itemData
+ const event = this.dispatch('itemData', {
+ itemData: itemData || {},
+ index
+ });
+
+ return event.itemData;
+ }
+
+ /**
+ * Get array of gallery DOM elements,
+ * based on childSelector and gallery element.
+ *
+ * @param {Element} galleryElement
+ */
+ _getGalleryDOMElements(galleryElement) {
+ if (this.options.children || this.options.childSelector) {
+ return getElementsFromOption(
+ this.options.children,
+ this.options.childSelector,
+ galleryElement
+ ) || [];
+ }
+
+ return [galleryElement];
+ }
+
+ /**
+ * Converts DOM element to item data object.
+ *
+ * @param {Element} element DOM element
+ */
+ // eslint-disable-next-line class-methods-use-this
+ _domElementToItemData(element) {
+ const itemData = {
+ element
+ };
+
+ const linkEl = element.tagName === 'A' ? element : element.querySelector('a');
+
+ if (!linkEl) {
+ return itemData;
+ }
+
+ // src comes from data-pswp-src attribute,
+ // if it's empty link href is used
+ itemData.src = linkEl.dataset.pswpSrc || linkEl.href;
+
+ itemData.srcset = linkEl.dataset.pswpSrcset;
+
+ itemData.w = parseInt(linkEl.dataset.pswpWidth, 10);
+ itemData.h = parseInt(linkEl.dataset.pswpHeight, 10);
+
+ const thumbnailEl = element.querySelector('img');
+
+ if (thumbnailEl) {
+ // define msrc only if it's the first slide,
+ // as rendering (even small stretched thumbnail) is an expensive operation
+ itemData.msrc = thumbnailEl.currentSrc || thumbnailEl.src;
+ itemData.alt = thumbnailEl.getAttribute('alt');
+ }
+
+ if (linkEl.dataset.cropped) {
+ itemData.thumbCropped = true;
+ }
+
+ return itemData;
+ }
+}
+
+/**
+ * PhotoSwipe lightbox
+ *
+ * - If user has unsupported browser it falls back to default browser action (just opens URL)
+ * - Binds click event to links that should open PhotoSwipe
+ * - parses DOM strcture for PhotoSwipe (retrieves large image URLs and sizes)
+ * - Initializes PhotoSwipe
+ *
+ *
+ * Loader options use the same object as PhotoSwipe, and supports such options:
+ *
+ * gallery - Element | Element[] | NodeList | string selector for the gallery element
+ * children - Element | Element[] | NodeList | string selector for the gallery children
+ *
+ */
+
+class PhotoSwipeLightbox extends PhotoSwipeBase {
+ constructor(options) {
+ super();
+ this.options = options || {};
+ this._uid = 0;
+ }
+
+ init() {
+ this.onThumbnailsClick = this.onThumbnailsClick.bind(this);
+
+ // Bind click events to each gallery
+ getElementsFromOption(this.options.gallery, this.options.gallerySelector)
+ .forEach((galleryElement) => {
+ galleryElement.addEventListener('click', this.onThumbnailsClick, false);
+ });
+ }
+
+ onThumbnailsClick(e) {
+ // Exit and allow default browser action if:
+ if (specialKeyUsed(e) // ... if clicked with a special key (ctrl/cmd...)
+ || window.pswp // ... if PhotoSwipe is already open
+ || window.navigator.onLine === false) { // ... if offline
+ return;
+ }
+
+ // If both clientX and clientY are 0 or not defined,
+ // the event is likely triggered by keyboard,
+ // so we do not pass the initialPoint
+ //
+ // Note that some screen readers emulate the mouse position,
+ // so it's not ideal way to detect them.
+ //
+ let initialPoint = { x: e.clientX, y: e.clientY };
+
+ if (!initialPoint.x && !initialPoint.y) {
+ initialPoint = null;
+ }
+
+ const clickedIndex = this.getClickedIndex(e);
+ const dataSource = {
+ gallery: e.currentTarget
+ };
+
+ if (clickedIndex >= 0) {
+ e.preventDefault();
+ this.loadAndOpen(clickedIndex, dataSource, initialPoint);
+ }
+ }
+
+ /**
+ * Get index of gallery item that was clicked.
+ *
+ * @param {Event} e click event
+ */
+ getClickedIndex(e) {
+ if (this.options.getClickedIndexFn) {
+ return this.options.getClickedIndexFn.call(this, e);
+ }
+
+ const clickedTarget = e.target;
+ const childElements = getElementsFromOption(
+ this.options.children,
+ this.options.childSelector,
+ e.currentTarget
+ );
+ const clickedChildIndex = childElements.findIndex(
+ child => child === clickedTarget || child.contains(clickedTarget)
+ );
+
+ if (clickedChildIndex !== -1) {
+ return clickedChildIndex;
+ } else if (this.options.children || this.options.childSelector) {
+ // click wasn't on a child element
+ return -1;
+ }
+
+ // There is only one item (which is the gallery)
+ return 0;
+ }
+
+ /**
+ * Load and open PhotoSwipe
+ *
+ * @param {Integer} index
+ * @param {Array|Object|null} dataSource
+ * @param {Point|null} initialPoint
+ */
+ loadAndOpen(index, dataSource, initialPoint) {
+ // Check if the gallery is already open
+ if (window.pswp) {
+ return false;
+ }
+
+ // set initial index
+ this.options.index = index;
+
+ // define options for PhotoSwipe constructor
+ this.options.initialPointerPos = initialPoint;
+
+ this.shouldOpen = true;
+ this.preload(index, dataSource);
+ return true;
+ }
+
+ /**
+ * Load the main module and the slide content by index
+ *
+ * @param {Integer} index
+ */
+ preload(index, dataSource) {
+ const { options } = this;
+
+ if (dataSource) {
+ options.dataSource = dataSource;
+ }
+
+ // Add the main module
+ const promiseArray = [dynamicImportModule(options.pswpModule)];
+
+ // Add custom-defined promise, if any
+ if (typeof options.openPromise === 'function') {
+ // allow developers to perform some task before opening
+ promiseArray.push(options.openPromise());
+ }
+
+ if (options.preloadFirstSlide !== false && index >= 0) {
+ lazyLoadSlide(index, this);
+ }
+
+ // Wait till all promises resolve and open PhotoSwipe
+ const uid = ++this._uid;
+ Promise.all(promiseArray).then((iterableModules) => {
+ if (this.shouldOpen) {
+ const mainModule = iterableModules[0];
+ this._openPhotoswipe(mainModule, uid);
+ }
+ });
+ }
+
+ _openPhotoswipe(module, uid) {
+ // Cancel opening if UID doesn't match the current one
+ // (if user clicked on another gallery item before current was loaded).
+ //
+ // Or if shouldOpen flag is set to false
+ // (developer may modify it via public API)
+ if (uid !== this._uid && this.shouldOpen) {
+ return;
+ }
+
+ this.shouldOpen = false;
+
+ // PhotoSwipe is already open
+ if (window.pswp) {
+ return;
+ }
+
+ // Pass data to PhotoSwipe and open init
+ const pswp = typeof module === 'object'
+ ? new module.default(null, this.options) // eslint-disable-line
+ : new module(null, this.options); // eslint-disable-line
+
+ this.pswp = pswp;
+ window.pswp = pswp;
+
+ // map listeners from Lightbox to PhotoSwipe Core
+ Object.keys(this._listeners).forEach((name) => {
+ this._listeners[name].forEach((fn) => {
+ pswp.on(name, fn);
+ });
+ });
+
+ pswp.on('destroy', () => {
+ // clean up public variables
+ this.pswp = null;
+ window.pswp = null;
+ });
+
+ pswp.init();
+ }
+
+ destroy() {
+ if (this.pswp) {
+ this.pswp.close();
+ }
+
+ this.shouldOpen = false;
+ this._listeners = null;
+
+ getElementsFromOption(this.options.gallery, this.options.gallerySelector)
+ .forEach((galleryElement) => {
+ galleryElement.removeEventListener('click', this.onThumbnailsClick, false);
+ });
+ }
+}
+
+export { PhotoSwipeLightbox as default };
+//# sourceMappingURL=photoswipe-lightbox.esm.js.map
diff --git a/lib/photoswipe/photoswipe-lightbox.esm.js.map b/lib/photoswipe/photoswipe-lightbox.esm.js.map
new file mode 100644
index 00000000..5b5f042e
--- /dev/null
+++ b/lib/photoswipe/photoswipe-lightbox.esm.js.map
@@ -0,0 +1 @@
+{"version":3,"file":"photoswipe-lightbox.esm.js","sources":["../../../src/js/util/util.js","../../../src/js/util/viewport-size.js","../../../src/js/slide/zoom-level.js","../../../src/js/slide/lazy-load.js","../../../src/js/lightbox/dynamic-import.js","../../../src/js/core/eventable.js","../../../src/js/core/base.js","../../../src/js/lightbox/lightbox.js"],"sourcesContent":["/**\r\n * Creates element and optionally appends it to another.\r\n *\r\n * @param {String} className\r\n * @param {String|NULL} tagName\r\n * @param {Element|NULL} appendToEl\r\n */\r\nexport function createElement(className, tagName, appendToEl) {\r\n const el = document.createElement(tagName || 'div');\r\n if (className) {\r\n el.className = className;\r\n }\r\n if (appendToEl) {\r\n appendToEl.appendChild(el);\r\n }\r\n return el;\r\n}\r\n\r\nexport function equalizePoints(p1, p2) {\r\n p1.x = p2.x;\r\n p1.y = p2.y;\r\n if (p2.id !== undefined) {\r\n p1.id = p2.id;\r\n }\r\n return p1;\r\n}\r\n\r\n\r\nexport function roundPoint(p) {\r\n p.x = Math.round(p.x);\r\n p.y = Math.round(p.y);\r\n}\r\n\r\n/**\r\n * Returns distance between two points.\r\n *\r\n * @param {Object} p1 Point\r\n * @param {Object} p2 Point\r\n */\r\nexport function getDistanceBetween(p1, p2) {\r\n const x = Math.abs(p1.x - p2.x);\r\n const y = Math.abs(p1.y - p2.y);\r\n return Math.sqrt((x * x) + (y * y));\r\n}\r\n\r\n/**\r\n * Whether X and Y positions of points are qual\r\n *\r\n * @param {Object} p1\r\n * @param {Object} p2\r\n */\r\nexport function pointsEqual(p1, p2) {\r\n return p1.x === p2.x && p1.y === p2.y;\r\n}\r\n\r\n/**\r\n * The float result between the min and max values.\r\n *\r\n * @param {Number} val\r\n * @param {Number} min\r\n * @param {Number} max\r\n */\r\nexport function clamp(val, min, max) {\r\n return Math.min(Math.max(val, min), max);\r\n}\r\n\r\n/**\r\n * Get transform string\r\n *\r\n * @param {Number} x\r\n * @param {Number|null} y\r\n * @param {Number|null} scale\r\n */\r\nexport function toTransformString(x, y, scale) {\r\n let propValue = 'translate3d('\r\n + x + 'px,' + (y || 0) + 'px'\r\n + ',0)';\r\n\r\n if (scale !== undefined) {\r\n propValue += ' scale3d('\r\n + scale + ',' + scale\r\n + ',1)';\r\n }\r\n\r\n return propValue;\r\n}\r\n\r\n/**\r\n * Apply transform:translate(x, y) scale(scale) to element\r\n *\r\n * @param {DOMElement} el\r\n * @param {Number} x\r\n * @param {Number|null} y\r\n * @param {Number|null} scale\r\n */\r\nexport function setTransform(el, x, y, scale) {\r\n el.style.transform = toTransformString(x, y, scale);\r\n}\r\n\r\nconst defaultCSSEasing = 'cubic-bezier(.4,0,.22,1)';\r\n\r\n/**\r\n * Apply CSS transition to element\r\n *\r\n * @param {Element} el\r\n * @param {String} prop CSS property to animate\r\n * @param {Number} duration in ms\r\n * @param {String|NULL} ease CSS easing function\r\n */\r\nexport function setTransitionStyle(el, prop, duration, ease) {\r\n // inOut: 'cubic-bezier(.4, 0, .22, 1)', // for \"toggle state\" transitions\r\n // out: 'cubic-bezier(0, 0, .22, 1)', // for \"show\" transitions\r\n // in: 'cubic-bezier(.4, 0, 1, 1)'// for \"hide\" transitions\r\n el.style.transition = prop\r\n ? (prop + ' ' + duration + 'ms ' + (ease || defaultCSSEasing))\r\n : 'none';\r\n}\r\n\r\n/**\r\n * Apply width and height CSS properties to element\r\n */\r\nexport function setWidthHeight(el, w, h) {\r\n el.style.width = (typeof w === 'number') ? (w + 'px') : w;\r\n el.style.height = (typeof h === 'number') ? (h + 'px') : h;\r\n}\r\n\r\nexport function removeTransitionStyle(el) {\r\n setTransitionStyle(el);\r\n}\r\n\r\nexport function decodeImage(img) {\r\n if ('decode' in img) {\r\n return img.decode();\r\n }\r\n\r\n if (img.complete) {\r\n return Promise.resolve(img);\r\n }\r\n\r\n return new Promise((resolve, reject) => {\r\n img.onload = () => resolve(img);\r\n img.onerror = reject;\r\n });\r\n}\r\n\r\n/**\r\n * Check if click or keydown event was dispatched\r\n * with a special key or via mouse wheel.\r\n *\r\n * @param {Event} e\r\n */\r\nexport function specialKeyUsed(e) {\r\n if (e.which === 2 || e.ctrlKey || e.metaKey || e.altKey || e.shiftKey) {\r\n return true;\r\n }\r\n}\r\n\r\n/**\r\n * Parse `gallery` or `children` options.\r\n *\r\n * @param {Element|NodeList|String} option\r\n * @param {String|null} legacySelector\r\n * @param {Element|null} parent\r\n * @returns Element[]\r\n */\r\nexport function getElementsFromOption(option, legacySelector, parent = document) {\r\n let elements = [];\r\n\r\n if (option instanceof Element) {\r\n elements = [option];\r\n } else if (option instanceof NodeList || Array.isArray(option)) {\r\n elements = Array.from(option);\r\n } else {\r\n const selector = typeof option === 'string' ? option : legacySelector;\r\n if (selector) {\r\n elements = Array.from(parent.querySelectorAll(selector));\r\n }\r\n }\r\n\r\n return elements;\r\n}\r\n","export function getViewportSize(options, pswp) {\r\n if (options.getViewportSizeFn) {\r\n const newViewportSize = options.getViewportSizeFn(options, pswp);\r\n if (newViewportSize) {\r\n return newViewportSize;\r\n }\r\n }\r\n\r\n return {\r\n x: document.documentElement.clientWidth,\r\n\r\n // TODO: height on mobile is very incosistent due to toolbar\r\n // find a way to improve this\r\n //\r\n // document.documentElement.clientHeight - doesn't seem to work well\r\n y: window.innerHeight\r\n };\r\n}\r\n\r\nexport function getPanAreaSize(options, viewportSize/*, pswp*/) {\r\n return {\r\n x: viewportSize.x - (options.paddingLeft || 0) - (options.paddingRight || 0),\r\n y: viewportSize.y - (options.paddingTop || 0) - (options.paddingBottom || 0)\r\n };\r\n}\r\n","/**\r\n * Calculates zoom levels for specific slide.\r\n * Depends on viewport size and image size.\r\n */\r\n\r\nconst MAX_IMAGE_WIDTH = 3000;\r\n\r\nclass ZoomLevel {\r\n /**\r\n * @param {Object} options PhotoSwipe options\r\n * @param {Object} itemData Slide data\r\n * @param {Integer} index Slide index\r\n * @param {PhotoSwipe|undefined} pswp PhotoSwipe instance, can be undefined if not initialized yet\r\n */\r\n constructor(options, itemData, index, pswp) {\r\n this.pswp = pswp;\r\n this.options = options;\r\n this.itemData = itemData;\r\n this.index = index;\r\n }\r\n\r\n /**\r\n * Calculate initial, secondary and maximum zoom level for the specified slide.\r\n *\r\n * It should be called when either image or viewport size changes.\r\n *\r\n * @param {Slide} slide\r\n */\r\n update(maxWidth, maxHeight, panAreaSize) {\r\n this.elementSize = {\r\n x: maxWidth,\r\n y: maxHeight\r\n };\r\n\r\n this.panAreaSize = panAreaSize;\r\n\r\n const hRatio = this.panAreaSize.x / this.elementSize.x;\r\n const vRatio = this.panAreaSize.y / this.elementSize.y;\r\n\r\n this.fit = Math.min(1, hRatio < vRatio ? hRatio : vRatio);\r\n this.fill = Math.min(1, hRatio > vRatio ? hRatio : vRatio);\r\n\r\n // zoom.vFill defines zoom level of the image\r\n // when it has 100% of viewport vertical space (height)\r\n this.vFill = Math.min(1, vRatio);\r\n\r\n this.initial = this._getInitial();\r\n this.secondary = this._getSecondary();\r\n this.max = Math.max(\r\n this.initial,\r\n this.secondary,\r\n this._getMax()\r\n );\r\n\r\n this.min = Math.min(\r\n this.fit,\r\n this.initial,\r\n this.secondary\r\n );\r\n\r\n if (this.pswp) {\r\n this.pswp.dispatch('zoomLevelsUpdate', { zoomLevels: this, slideData: this.itemData });\r\n }\r\n }\r\n\r\n /**\r\n * Parses user-defined zoom option.\r\n *\r\n * @param {Mixed} optionPrefix Zoom level option prefix (initial, secondary, max)\r\n */\r\n _parseZoomLevelOption(optionPrefix) {\r\n // zoom.initial\r\n // zoom.secondary\r\n // zoom.max\r\n const optionValue = this.options[optionPrefix + 'ZoomLevel'];\r\n\r\n if (!optionValue) {\r\n return;\r\n }\r\n\r\n if (typeof optionValue === 'function') {\r\n return optionValue(this);\r\n }\r\n\r\n if (optionValue === 'fill') {\r\n return this.fill;\r\n }\r\n\r\n if (optionValue === 'fit') {\r\n return this.fit;\r\n }\r\n\r\n return Number(optionValue);\r\n }\r\n\r\n /**\r\n * Get zoom level to which image will be zoomed after double-tap gesture,\r\n * or when user clicks on zoom icon,\r\n * or mouse-click on image itself.\r\n * If you return 1 image will be zoomed to its original size.\r\n *\r\n * @return {Number}\r\n */\r\n _getSecondary() {\r\n let currZoomLevel = this._parseZoomLevelOption('secondary');\r\n\r\n if (currZoomLevel) {\r\n return currZoomLevel;\r\n }\r\n\r\n // 2.5x of \"fit\" state, but not larger than original\r\n currZoomLevel = Math.min(1, this.fit * 2.5);\r\n\r\n if (currZoomLevel * this.elementSize.x > MAX_IMAGE_WIDTH) {\r\n currZoomLevel = MAX_IMAGE_WIDTH / this.elementSize.x;\r\n }\r\n\r\n return currZoomLevel;\r\n }\r\n\r\n /**\r\n * Get initial image zoom level.\r\n *\r\n * @return {Number}\r\n */\r\n _getInitial() {\r\n return this._parseZoomLevelOption('initial') || this.fit;\r\n }\r\n\r\n /**\r\n * Maximum zoom level when user zooms\r\n * via zoom/pinch gesture,\r\n * via cmd/ctrl-wheel or via trackpad.\r\n *\r\n * @return {Number}\r\n */\r\n _getMax() {\r\n const currZoomLevel = this._parseZoomLevelOption('max');\r\n\r\n if (currZoomLevel) {\r\n return currZoomLevel;\r\n }\r\n\r\n // max zoom level is x4 from \"fit state\",\r\n // used for zoom gesture and ctrl/trackpad zoom\r\n return Math.max(1, this.fit * 4);\r\n }\r\n}\r\n\r\nexport default ZoomLevel;\r\n","import { getViewportSize, getPanAreaSize } from '../util/viewport-size.js';\r\nimport ZoomLevel from './zoom-level.js';\r\n\r\n// This much recently lazy-loaded images will not be lazy-loaded again\r\nconst MAX_SLIDES_TO_LAZY_LOAD = 15;\r\n\r\n/**\r\n * Lazy-load an image\r\n * This function is used both by Lightbox and PhotoSwipe core,\r\n * thus it can be called before dialog is opened.\r\n *\r\n * @param {Object} itemData Data about the slide\r\n * @param {Object} instance PhotoSwipe or PhotoSwipeLightbox eventable instance\r\n * @param {Boolean} decode Wether decode() should be used.\r\n * @returns {Object|Boolean} Image that is being decoded or false.\r\n */\r\nexport function lazyLoadData(itemData, instance, decode) {\r\n if (itemData.src && itemData.w && itemData.h) {\r\n const { options } = instance;\r\n\r\n // We need to know dimensions of the image to preload it,\r\n // as it might use srcset and we need to define sizes\r\n const viewportSize = instance.viewportSize || getViewportSize(options);\r\n const panAreaSize = getPanAreaSize(options, viewportSize);\r\n\r\n const zoomLevel = new ZoomLevel(options, itemData, -1);\r\n zoomLevel.update(itemData.w, itemData.h, panAreaSize);\r\n\r\n const image = document.createElement('img');\r\n image.decoding = 'async';\r\n image.sizes = Math.ceil(itemData.w * zoomLevel.initial) + 'px';\r\n if (itemData.srcset) {\r\n image.srcset = itemData.srcset;\r\n }\r\n image.src = itemData.src;\r\n if (decode && ('decode' in image)) {\r\n image.decode();\r\n }\r\n\r\n return image;\r\n }\r\n}\r\n\r\n/**\r\n * Lazy-loads specific slide.\r\n * This function is used both by Lightbox and PhotoSwipe core,\r\n * thus it can be called before dialog is opened.\r\n *\r\n * By default it loads image based on viewport size and initial zoom level.\r\n *\r\n * @param {Integer} index Slide index\r\n * @param {Object} instance PhotoSwipe or PhotoSwipeLightbox eventable instance\r\n */\r\nexport function lazyLoadSlide(index, instance) {\r\n const itemData = instance.getItemData(index);\r\n\r\n if (instance.dispatch('lazyLoadSlide', { index, itemData }).defaultPrevented) {\r\n return;\r\n }\r\n\r\n lazyLoadData(itemData, instance);\r\n}\r\n\r\nclass LazyLoader {\r\n constructor(pswp) {\r\n this.pswp = pswp;\r\n this.clearRecent();\r\n }\r\n\r\n /**\r\n * Lazy load nearby slides based on `preload` option.\r\n *\r\n * @param {Integer} diff Difference between slide indexes that was changed recently, or 0.\r\n */\r\n update(diff) {\r\n const { pswp } = this;\r\n\r\n if (pswp.dispatch('lazyLoad').defaultPrevented) {\r\n return;\r\n }\r\n\r\n const { preload } = pswp.options;\r\n const isForward = diff === undefined ? true : (diff >= 0);\r\n let i;\r\n\r\n // preload[1] - num items to preload in forward direction\r\n for (i = 0; i <= preload[1]; i++) {\r\n this.loadSlideByIndex(pswp.currIndex + (isForward ? i : (-i)));\r\n }\r\n\r\n // preload[0] - num items to preload in backward direction\r\n for (i = 1; i <= preload[0]; i++) {\r\n this.loadSlideByIndex(pswp.currIndex + (isForward ? (-i) : i));\r\n }\r\n }\r\n\r\n clearRecent() {\r\n this._recentlyLazyLoadedIndexes = [];\r\n }\r\n\r\n /**\r\n * Add index to recently lazy-loaded slides.\r\n *\r\n * To prevent duplciate downloads,\r\n * we keep track of recently preloaded slides.\r\n *\r\n * @param {Integer} index\r\n */\r\n addRecent(index) {\r\n if (this._recentlyLazyLoadedIndexes.indexOf(index) > -1) {\r\n // already exists\r\n return;\r\n }\r\n\r\n if (this._recentlyLazyLoadedIndexes.length > MAX_SLIDES_TO_LAZY_LOAD - 1) {\r\n this._recentlyLazyLoadedIndexes.pop();\r\n }\r\n\r\n // the most recent lazy loaded index is the first\r\n // (thus push to the beginning)\r\n this._recentlyLazyLoadedIndexes.unshift(index);\r\n\r\n return true;\r\n }\r\n\r\n loadSlideByIndex(index) {\r\n index = this.pswp.getLoopedIndex(index);\r\n\r\n if (this.addRecent(index)) {\r\n lazyLoadSlide(index, this.pswp);\r\n }\r\n }\r\n\r\n // @see lazyLoadData\r\n loadSlideByData(data, decode) {\r\n lazyLoadData(data, this.pswp, decode);\r\n }\r\n}\r\n\r\nexport default LazyLoader;\r\n","export function dynamicImportModule(module) {\r\n return typeof module === 'string' ? import(/* webpackIgnore: true */ module) : module;\r\n}\r\n","/**\r\n * Base PhotoSwipe event object\r\n */\r\nclass PhotoSwipeEvent {\r\n constructor(type, details) {\r\n this.type = type;\r\n if (details) {\r\n Object.assign(this, details);\r\n }\r\n }\r\n\r\n preventDefault() {\r\n this.defaultPrevented = true;\r\n }\r\n}\r\n\r\n/**\r\n * PhotoSwipe base class that can listen and dispatch for events.\r\n * Shared by PhotoSwipe Core and PhotoSwipe Lightbox, extended by base.js\r\n */\r\nclass Eventable {\r\n constructor() {\r\n this._listeners = {};\r\n }\r\n\r\n on(name, fn) {\r\n if (!this._listeners[name]) {\r\n this._listeners[name] = [];\r\n }\r\n this._listeners[name].push(fn);\r\n\r\n // When binding events to lightbox,\r\n // also bind events to PhotoSwipe Core,\r\n // if it's open.\r\n if (this.pswp) {\r\n this.pswp.on(name, fn);\r\n }\r\n }\r\n\r\n off(name, fn) {\r\n if (this._listeners[name]) {\r\n this._listeners[name] = this._listeners[name].filter(listener => (fn !== listener));\r\n }\r\n\r\n if (this.pswp) {\r\n this.pswp.off(name, fn);\r\n }\r\n }\r\n\r\n dispatch(name, details) {\r\n if (this.pswp) {\r\n return this.pswp.dispatch(name, details);\r\n }\r\n\r\n const event = new PhotoSwipeEvent(name, details);\r\n\r\n if (!this._listeners) {\r\n return event;\r\n }\r\n\r\n if (this._listeners[name]) {\r\n this._listeners[name].forEach((listener) => {\r\n listener.call(this, event);\r\n });\r\n }\r\n\r\n return event;\r\n }\r\n}\r\n\r\nexport default Eventable;\r\n","/**\r\n * PhotoSwipe base class that can retrieve data about every slide.\r\n * Shared by PhotoSwipe Core and PhotoSwipe Lightbox\r\n */\r\nimport Eventable from './eventable';\r\nimport {\r\n getElementsFromOption\r\n} from '../util/util.js';\r\n\r\nclass PhotoSwipeBase extends Eventable {\r\n /**\r\n * Get total number of slides\r\n */\r\n getNumItems() {\r\n let numItems;\r\n const { dataSource } = this.options;\r\n if (!dataSource) {\r\n numItems = 0;\r\n } else if (dataSource.length) {\r\n // may be an array or just object with length property\r\n numItems = dataSource.length;\r\n } else if (dataSource.gallery) {\r\n // query DOM elements\r\n if (!dataSource.items) {\r\n dataSource.items = this._getGalleryDOMElements(dataSource.gallery);\r\n }\r\n\r\n if (dataSource.items) {\r\n numItems = dataSource.items.length;\r\n }\r\n }\r\n\r\n // allow to filter number of items\r\n const event = this.dispatch('numItems', {\r\n dataSource,\r\n numItems\r\n });\r\n\r\n return event.numItems;\r\n }\r\n\r\n /**\r\n * Get item data by index.\r\n *\r\n * \"item data\" should contain normalized information that PhotoSwipe needs to generate a slide.\r\n * For example, it may contain properties like\r\n * `src`, `srcset`, `w`, `h`, which will be used to generate a slide with image.\r\n *\r\n * @param {Integer} index\r\n */\r\n getItemData(index) {\r\n const { dataSource } = this.options;\r\n let dataSourceItem;\r\n if (Array.isArray(dataSource)) {\r\n // Datasource is an array of elements\r\n dataSourceItem = dataSource[index];\r\n } else if (dataSource && dataSource.gallery) {\r\n // dataSource has gallery property,\r\n // thus it was created by Lightbox, based on\r\n // gallerySelecor and childSelector options\r\n\r\n // query DOM elements\r\n if (!dataSource.items) {\r\n dataSource.items = this._getGalleryDOMElements(dataSource.gallery);\r\n }\r\n\r\n dataSourceItem = dataSource.items[index];\r\n }\r\n\r\n let itemData = dataSourceItem;\r\n\r\n if (itemData instanceof Element) {\r\n itemData = this._domElementToItemData(itemData);\r\n }\r\n\r\n // allow to filter itemData\r\n const event = this.dispatch('itemData', {\r\n itemData: itemData || {},\r\n index\r\n });\r\n\r\n return event.itemData;\r\n }\r\n\r\n /**\r\n * Get array of gallery DOM elements,\r\n * based on childSelector and gallery element.\r\n *\r\n * @param {Element} galleryElement\r\n */\r\n _getGalleryDOMElements(galleryElement) {\r\n if (this.options.children || this.options.childSelector) {\r\n return getElementsFromOption(\r\n this.options.children,\r\n this.options.childSelector,\r\n galleryElement\r\n ) || [];\r\n }\r\n\r\n return [galleryElement];\r\n }\r\n\r\n /**\r\n * Converts DOM element to item data object.\r\n *\r\n * @param {Element} element DOM element\r\n */\r\n // eslint-disable-next-line class-methods-use-this\r\n _domElementToItemData(element) {\r\n const itemData = {\r\n element\r\n };\r\n\r\n const linkEl = element.tagName === 'A' ? element : element.querySelector('a');\r\n\r\n if (!linkEl) {\r\n return itemData;\r\n }\r\n\r\n // src comes from data-pswp-src attribute,\r\n // if it's empty link href is used\r\n itemData.src = linkEl.dataset.pswpSrc || linkEl.href;\r\n\r\n itemData.srcset = linkEl.dataset.pswpSrcset;\r\n\r\n itemData.w = parseInt(linkEl.dataset.pswpWidth, 10);\r\n itemData.h = parseInt(linkEl.dataset.pswpHeight, 10);\r\n\r\n const thumbnailEl = element.querySelector('img');\r\n\r\n if (thumbnailEl) {\r\n // define msrc only if it's the first slide,\r\n // as rendering (even small stretched thumbnail) is an expensive operation\r\n itemData.msrc = thumbnailEl.currentSrc || thumbnailEl.src;\r\n itemData.alt = thumbnailEl.getAttribute('alt');\r\n }\r\n\r\n if (linkEl.dataset.cropped) {\r\n itemData.thumbCropped = true;\r\n }\r\n\r\n return itemData;\r\n }\r\n}\r\n\r\nexport default PhotoSwipeBase;\r\n","/**\r\n * PhotoSwipe lightbox\r\n *\r\n * - If user has unsupported browser it falls back to default browser action (just opens URL)\r\n * - Binds click event to links that should open PhotoSwipe\r\n * - parses DOM strcture for PhotoSwipe (retrieves large image URLs and sizes)\r\n * - Initializes PhotoSwipe\r\n *\r\n *\r\n * Loader options use the same object as PhotoSwipe, and supports such options:\r\n *\r\n * gallery - Element | Element[] | NodeList | string selector for the gallery element\r\n * children - Element | Element[] | NodeList | string selector for the gallery children\r\n *\r\n */\r\n\r\nimport {\r\n specialKeyUsed,\r\n getElementsFromOption\r\n} from '../util/util.js';\r\n\r\nimport { lazyLoadSlide } from '../slide/lazy-load.js';\r\nimport { dynamicImportModule } from './dynamic-import.js';\r\nimport PhotoSwipeBase from '../core/base.js';\r\n\r\nclass PhotoSwipeLightbox extends PhotoSwipeBase {\r\n constructor(options) {\r\n super();\r\n this.options = options || {};\r\n this._uid = 0;\r\n }\r\n\r\n init() {\r\n this.onThumbnailsClick = this.onThumbnailsClick.bind(this);\r\n\r\n // Bind click events to each gallery\r\n getElementsFromOption(this.options.gallery, this.options.gallerySelector)\r\n .forEach((galleryElement) => {\r\n galleryElement.addEventListener('click', this.onThumbnailsClick, false);\r\n });\r\n }\r\n\r\n onThumbnailsClick(e) {\r\n // Exit and allow default browser action if:\r\n if (specialKeyUsed(e) // ... if clicked with a special key (ctrl/cmd...)\r\n || window.pswp // ... if PhotoSwipe is already open\r\n || window.navigator.onLine === false) { // ... if offline\r\n return;\r\n }\r\n\r\n // If both clientX and clientY are 0 or not defined,\r\n // the event is likely triggered by keyboard,\r\n // so we do not pass the initialPoint\r\n //\r\n // Note that some screen readers emulate the mouse position,\r\n // so it's not ideal way to detect them.\r\n //\r\n let initialPoint = { x: e.clientX, y: e.clientY };\r\n\r\n if (!initialPoint.x && !initialPoint.y) {\r\n initialPoint = null;\r\n }\r\n\r\n const clickedIndex = this.getClickedIndex(e);\r\n const dataSource = {\r\n gallery: e.currentTarget\r\n };\r\n\r\n if (clickedIndex >= 0) {\r\n e.preventDefault();\r\n this.loadAndOpen(clickedIndex, dataSource, initialPoint);\r\n }\r\n }\r\n\r\n /**\r\n * Get index of gallery item that was clicked.\r\n *\r\n * @param {Event} e click event\r\n */\r\n getClickedIndex(e) {\r\n if (this.options.getClickedIndexFn) {\r\n return this.options.getClickedIndexFn.call(this, e);\r\n }\r\n\r\n const clickedTarget = e.target;\r\n const childElements = getElementsFromOption(\r\n this.options.children,\r\n this.options.childSelector,\r\n e.currentTarget\r\n );\r\n const clickedChildIndex = childElements.findIndex(\r\n child => child === clickedTarget || child.contains(clickedTarget)\r\n );\r\n\r\n if (clickedChildIndex !== -1) {\r\n return clickedChildIndex;\r\n } else if (this.options.children || this.options.childSelector) {\r\n // click wasn't on a child element\r\n return -1;\r\n }\r\n\r\n // There is only one item (which is the gallery)\r\n return 0;\r\n }\r\n\r\n /**\r\n * Load and open PhotoSwipe\r\n *\r\n * @param {Integer} index\r\n * @param {Array|Object|null} dataSource\r\n * @param {Point|null} initialPoint\r\n */\r\n loadAndOpen(index, dataSource, initialPoint) {\r\n // Check if the gallery is already open\r\n if (window.pswp) {\r\n return false;\r\n }\r\n\r\n // set initial index\r\n this.options.index = index;\r\n\r\n // define options for PhotoSwipe constructor\r\n this.options.initialPointerPos = initialPoint;\r\n\r\n this.shouldOpen = true;\r\n this.preload(index, dataSource);\r\n return true;\r\n }\r\n\r\n /**\r\n * Load the main module and the slide content by index\r\n *\r\n * @param {Integer} index\r\n */\r\n preload(index, dataSource) {\r\n const { options } = this;\r\n\r\n if (dataSource) {\r\n options.dataSource = dataSource;\r\n }\r\n\r\n // Add the main module\r\n const promiseArray = [dynamicImportModule(options.pswpModule)];\r\n\r\n // Add custom-defined promise, if any\r\n if (typeof options.openPromise === 'function') {\r\n // allow developers to perform some task before opening\r\n promiseArray.push(options.openPromise());\r\n }\r\n\r\n if (options.preloadFirstSlide !== false && index >= 0) {\r\n lazyLoadSlide(index, this);\r\n }\r\n\r\n // Wait till all promises resolve and open PhotoSwipe\r\n const uid = ++this._uid;\r\n Promise.all(promiseArray).then((iterableModules) => {\r\n if (this.shouldOpen) {\r\n const mainModule = iterableModules[0];\r\n this._openPhotoswipe(mainModule, uid);\r\n }\r\n });\r\n }\r\n\r\n _openPhotoswipe(module, uid) {\r\n // Cancel opening if UID doesn't match the current one\r\n // (if user clicked on another gallery item before current was loaded).\r\n //\r\n // Or if shouldOpen flag is set to false\r\n // (developer may modify it via public API)\r\n if (uid !== this._uid && this.shouldOpen) {\r\n return;\r\n }\r\n\r\n this.shouldOpen = false;\r\n\r\n // PhotoSwipe is already open\r\n if (window.pswp) {\r\n return;\r\n }\r\n\r\n // Pass data to PhotoSwipe and open init\r\n const pswp = typeof module === 'object'\r\n ? new module.default(null, this.options) // eslint-disable-line\r\n : new module(null, this.options); // eslint-disable-line\r\n\r\n this.pswp = pswp;\r\n window.pswp = pswp;\r\n\r\n // map listeners from Lightbox to PhotoSwipe Core\r\n Object.keys(this._listeners).forEach((name) => {\r\n this._listeners[name].forEach((fn) => {\r\n pswp.on(name, fn);\r\n });\r\n });\r\n\r\n pswp.on('destroy', () => {\r\n // clean up public variables\r\n this.pswp = null;\r\n window.pswp = null;\r\n });\r\n\r\n pswp.init();\r\n }\r\n\r\n destroy() {\r\n if (this.pswp) {\r\n this.pswp.close();\r\n }\r\n\r\n this.shouldOpen = false;\r\n this._listeners = null;\r\n\r\n getElementsFromOption(this.options.gallery, this.options.gallerySelector)\r\n .forEach((galleryElement) => {\r\n galleryElement.removeEventListener('click', this.onThumbnailsClick, false);\r\n });\r\n }\r\n}\r\n\r\nexport default PhotoSwipeLightbox;\r\n"],"names":[],"mappings":"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"}
\ No newline at end of file
diff --git a/lib/photoswipe/photoswipe-lightbox.esm.min.js b/lib/photoswipe/photoswipe-lightbox.esm.min.js
new file mode 100644
index 00000000..daa3b5b0
--- /dev/null
+++ b/lib/photoswipe/photoswipe-lightbox.esm.min.js
@@ -0,0 +1,5 @@
+/*!
+ * PhotoSwipe Lightbox 5.1.5 - https://photoswipe.com
+ * (c) 2021 Dmitry Semenov
+ */
+function t(t,i,s=document){let e=[];if(t instanceof Element)e=[t];else if(t instanceof NodeList||Array.isArray(t))e=Array.from(t);else{const h="string"==typeof t?t:i;h&&(e=Array.from(s.querySelectorAll(h)))}return e}class i{constructor(t,i,s,e){this.pswp=e,this.options=t,this.itemData=i,this.index=s}update(t,i,s){this.elementSize={x:t,y:i},this.panAreaSize=s;const e=this.panAreaSize.x/this.elementSize.x,h=this.panAreaSize.y/this.elementSize.y;this.fit=Math.min(1,e