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 @@ + + + + + + + + + + +
+

Deep Zoom plugin for the PhotoSwipe

+

+ 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.

+ + +
+ +
+ + + +
+ + \ 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,eh?e:h),this.vFill=Math.min(1,h),this.initial=this.t(),this.secondary=this.i(),this.max=Math.max(this.initial,this.secondary,this.o()),this.min=Math.min(this.fit,this.initial,this.secondary),this.pswp&&this.pswp.dispatch("zoomLevelsUpdate",{zoomLevels:this,slideData:this.itemData})}u(t){const i=this.options[t+"ZoomLevel"];if(i)return"function"==typeof i?i(this):"fill"===i?this.fill:"fit"===i?this.fit:Number(i)}i(){let t=this.u("secondary");return t||(t=Math.min(1,2.5*this.fit),t*this.elementSize.x>3e3&&(t=3e3/this.elementSize.x),t)}t(){return this.u("initial")||this.fit}o(){const t=this.u("max");return t||Math.max(1,4*this.fit)}}function s(t,s,e){if(t.src&&t.w&&t.h){const{options:h}=s,n=s.viewportSize||function(t,i){if(t.getViewportSizeFn){const s=t.getViewportSizeFn(t,i);if(s)return s}return{x:document.documentElement.clientWidth,y:window.innerHeight}}(h),o=function(t,i){return{x:i.x-(t.paddingLeft||0)-(t.paddingRight||0),y:i.y-(t.paddingTop||0)-(t.paddingBottom||0)}}(h,n),r=new i(h,t,-1);r.update(t.w,t.h,o);const a=document.createElement("img");return a.decoding="async",a.sizes=Math.ceil(t.w*r.initial)+"px",t.srcset&&(a.srcset=t.srcset),a.src=t.src,e&&"decode"in a&&a.decode(),a}}class e{constructor(t,i){this.type=t,i&&Object.assign(this,i)}preventDefault(){this.defaultPrevented=!0}}class h extends class extends class{constructor(){this.l={}}on(t,i){this.l[t]||(this.l[t]=[]),this.l[t].push(i),this.pswp&&this.pswp.on(t,i)}off(t,i){this.l[t]&&(this.l[t]=this.l[t].filter((t=>i!==t))),this.pswp&&this.pswp.off(t,i)}dispatch(t,i){if(this.pswp)return this.pswp.dispatch(t,i);const s=new e(t,i);return this.l?(this.l[t]&&this.l[t].forEach((t=>{t.call(this,s)})),s):s}}{getNumItems(){let t;const{dataSource:i}=this.options;i?i.length?t=i.length:i.gallery&&(i.items||(i.items=this.m(i.gallery)),i.items&&(t=i.items.length)):t=0;return this.dispatch("numItems",{dataSource:i,numItems:t}).numItems}getItemData(t){const{dataSource:i}=this.options;let s;Array.isArray(i)?s=i[t]:i&&i.gallery&&(i.items||(i.items=this.m(i.gallery)),s=i.items[t]);let e=s;e instanceof Element&&(e=this.p(e));return this.dispatch("itemData",{itemData:e||{},index:t}).itemData}m(i){return this.options.children||this.options.childSelector?t(this.options.children,this.options.childSelector,i)||[]:[i]}p(t){const i={element:t},s="A"===t.tagName?t:t.querySelector("a");if(!s)return i;i.src=s.dataset.pswpSrc||s.href,i.srcset=s.dataset.pswpSrcset,i.w=parseInt(s.dataset.pswpWidth,10),i.h=parseInt(s.dataset.pswpHeight,10);const e=t.querySelector("img");return e&&(i.msrc=e.currentSrc||e.src,i.alt=e.getAttribute("alt")),s.dataset.cropped&&(i.thumbCropped=!0),i}}{constructor(t){super(),this.options=t||{},this.g=0}init(){this.onThumbnailsClick=this.onThumbnailsClick.bind(this),t(this.options.gallery,this.options.gallerySelector).forEach((t=>{t.addEventListener("click",this.onThumbnailsClick,!1)}))}onThumbnailsClick(t){if(function(t){if(2===t.which||t.ctrlKey||t.metaKey||t.altKey||t.shiftKey)return!0}(t)||window.pswp||!1===window.navigator.onLine)return;let i={x:t.clientX,y:t.clientY};i.x||i.y||(i=null);const s=this.getClickedIndex(t),e={gallery:t.currentTarget};s>=0&&(t.preventDefault(),this.loadAndOpen(s,e,i))}getClickedIndex(i){if(this.options.getClickedIndexFn)return this.options.getClickedIndexFn.call(this,i);const s=i.target,e=t(this.options.children,this.options.childSelector,i.currentTarget).findIndex((t=>t===s||t.contains(s)));return-1!==e?e:this.options.children||this.options.childSelector?-1:0}loadAndOpen(t,i,s){return!window.pswp&&(this.options.index=t,this.options.initialPointerPos=s,this.shouldOpen=!0,this.preload(t,i),!0)}preload(t,i){const{options:e}=this;i&&(e.dataSource=i);const h=[(n=e.pswpModule,"string"==typeof n?import(n):n)];var n;"function"==typeof e.openPromise&&h.push(e.openPromise()),!1!==e.preloadFirstSlide&&t>=0&&function(t,i){const e=i.getItemData(t);i.dispatch("lazyLoadSlide",{index:t,itemData:e}).defaultPrevented||s(e,i)}(t,this);const o=++this.g;Promise.all(h).then((t=>{if(this.shouldOpen){const i=t[0];this.M(i,o)}}))}M(t,i){if(i!==this.g&&this.shouldOpen)return;if(this.shouldOpen=!1,window.pswp)return;const s="object"==typeof t?new t.default(null,this.options):new t(null,this.options);this.pswp=s,window.pswp=s,Object.keys(this.l).forEach((t=>{this.l[t].forEach((i=>{s.on(t,i)}))})),s.on("destroy",(()=>{this.pswp=null,window.pswp=null})),s.init()}destroy(){this.pswp&&this.pswp.close(),this.shouldOpen=!1,this.l=null,t(this.options.gallery,this.options.gallerySelector).forEach((t=>{t.removeEventListener("click",this.onThumbnailsClick,!1)}))}}export{h as default}; diff --git a/lib/photoswipe/photoswipe.css b/lib/photoswipe/photoswipe.css new file mode 100644 index 00000000..89b15a84 --- /dev/null +++ b/lib/photoswipe/photoswipe.css @@ -0,0 +1,446 @@ +/*! PhotoSwipe main CSS by Dmytro Semenov | photoswipe.com */ + +.pswp { + --pswp-bg: #000; + --pswp-placeholder-bg: #222; + --pswp-error-text-color: #f7f7f7; + + --pswp-root-z-index: 100000; + + --pswp-preloader-color: rgba(79, 79, 79, 0.4); + --pswp-preloader-color-secondary: rgba(255, 255, 255, 0.9); + + /* defined via js: + --pswp-transition-duration: 333ms; */ + + --pswp-icon-color: #fff; + --pswp-icon-color-secondary: #4f4f4f; + --pswp-icon-stroke-color: #4f4f4f; + --pswp-icon-stroke-width: 2px; +} + + +/* + Styles for basic PhotoSwipe (pswp) functionality (sliding area, open/close transitions) +*/ + +.pswp { + position: fixed; + z-index: var(--pswp-root-z-index); + display: none; + touch-action: none; + outline: 0; + opacity: 0.003; + contain: layout style size; + -webkit-tap-highlight-color: rgba(0, 0, 0, 0); +} + +/* Prevents focus outline on the root element, + (it may be focused initially) */ +.pswp:focus { + outline: 0; +} + +.pswp * { + box-sizing: border-box; +} + +.pswp img { + max-width: none; +} + +.pswp--open { + display: block; +} + +.pswp, +.pswp__bg { + transform: translateZ(0); + will-change: opacity; +} + +.pswp__bg { + opacity: 0.005; + background: var(--pswp-bg); +} + +.pswp, +.pswp__scroll-wrap { + overflow: hidden; +} + +.pswp, +.pswp__scroll-wrap, +.pswp__bg, +.pswp__container, +.pswp__item, +.pswp__img, +.pswp__zoom-wrap { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; +} + +.pswp { + position: fixed; +} + +.pswp__img, +.pswp__zoom-wrap { + width: auto; + height: auto; +} + +.pswp--click-to-zoom.pswp--zoom-allowed .pswp__img { + cursor: -webkit-zoom-in; + cursor: -moz-zoom-in; + cursor: zoom-in; +} + +.pswp--click-to-zoom.pswp--zoomed-in .pswp__img { + cursor: move; + cursor: -webkit-grab; + cursor: -moz-grab; + cursor: grab; +} + +.pswp--click-to-zoom.pswp--zoomed-in .pswp__img:active { + cursor: -webkit-grabbing; + cursor: -moz-grabbing; + cursor: grabbing; +} + +/* :active to override grabbing cursor */ +.pswp--no-mouse-drag.pswp--zoomed-in .pswp__img, +.pswp--no-mouse-drag.pswp--zoomed-in .pswp__img:active, +.pswp__img { + cursor: -webkit-zoom-out; + cursor: -moz-zoom-out; + cursor: zoom-out; +} + + +/* Prevent selection and tap highlights */ +.pswp__container, +.pswp__img, +.pswp__button { + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} + +.pswp__item { + /* z-index for fade transition */ + z-index: 1; + overflow: hidden; +} + +.pswp__hidden { + display: none !important; +} + + +/* + + PhotoSwipe UI + +*/ + +/* + Error message appears when image is not loaded + (JS option errorMsg controls markup) +*/ +.pswp__error-msg { + position: absolute; + top: 50%; + left: 0; + width: 100%; + padding: 0 10px; + margin-top: -0.5em; + font-size: 1em; + line-height: 1; + color: var(--pswp-error-text-color); + text-align: center; +} + +.pswp__error-msg a { + color: var(--pswp-error-text-color); + text-decoration: underline; +} + +/* +class pswp__hide-on-close is applied to elements that +should hide (for example fade out) when PhotoSwipe is closed +and show (for example fade in) when PhotoSwipe is opened + */ +.pswp .pswp__hide-on-close { + opacity: 0.005; + will-change: opacity; + transition: opacity var(--pswp-transition-duration) cubic-bezier(0.4, 0, 0.22, 1); + z-index: 10; /* always overlap slide content */ + pointer-events: none; /* hidden elements should not be clickable */ +} + +/* class pswp--ui-visible is added when opening or closing transition starts */ +.pswp--ui-visible .pswp__hide-on-close { + opacity: 1; + pointer-events: auto; +} + +/*