diff --git a/build/config-builder.js b/build/config-builder.js index e065b7397..50b4aa8d8 100644 --- a/build/config-builder.js +++ b/build/config-builder.js @@ -77,7 +77,7 @@ export const minCoreJS = { }; // UMD config -const umdBaseOutputDir = 'demo-docs-website/static/photoswipe/umd/'; +const umdBaseOutputDir = `${baseOutputDir}/umd/`; export const umdMinLightboxJS = { input: 'src/js/lightbox/lightbox.js', output: { @@ -99,3 +99,24 @@ export const umdMinCoreJS = { }, plugins: [getBabelPlugin(), getMinifyPlugin()] }; + +const commonJsBaseOutputDir = `${baseOutputDir}/cjs/`; +export const lightboxCommonJS = { + input: 'src/js/lightbox/lightbox.js', + output: { + banner: getBanner('PhotoSwipe Lightbox'), + file: commonJsBaseOutputDir + 'photoswipe-lightbox.cjs', + format: 'commonjs', + sourcemap: true + } +}; + +export const coreCommonJS = { + input: 'src/js/photoswipe.js', + output: { + banner: getBanner('PhotoSwipe'), + file: commonJsBaseOutputDir + 'photoswipe.cjs', + format: 'commonjs', + sourcemap: true + } +}; \ No newline at end of file diff --git a/build/rollup.config.js b/build/rollup.config.js index 1f94646e4..bfbc111f7 100644 --- a/build/rollup.config.js +++ b/build/rollup.config.js @@ -4,7 +4,9 @@ import { minLightboxJS, minCoreJS, umdMinLightboxJS, - umdMinCoreJS + umdMinCoreJS, + lightboxCommonJS, + coreCommonJS } from './config-builder'; -export default [lightboxJS, coreJS, minLightboxJS, minCoreJS, umdMinLightboxJS, umdMinCoreJS]; +export default [lightboxJS, coreJS, minLightboxJS, minCoreJS, lightboxCommonJS, coreCommonJS, umdMinLightboxJS, umdMinCoreJS]; diff --git a/dist/cjs/photoswipe-lightbox.cjs b/dist/cjs/photoswipe-lightbox.cjs new file mode 100644 index 000000000..49634e7d1 --- /dev/null +++ b/dist/cjs/photoswipe-lightbox.cjs @@ -0,0 +1,1843 @@ +/*! + * PhotoSwipe Lightbox 5.3.9 - https://photoswipe.com + * (c) 2023 Dmytro Semenov + */ +'use strict'; + +/** @typedef {import('../photoswipe.js').Point} Point */ + +/** + * @template {keyof HTMLElementTagNameMap} T + * @param {string} className + * @param {T} tagName + * @param {Node} [appendToEl] + * @returns {HTMLElementTagNameMap[T]} + */ +function createElement(className, tagName, appendToEl) { + const el = document.createElement(tagName); + if (className) { + el.className = className; + } + if (appendToEl) { + appendToEl.appendChild(el); + } + return el; +} + +/** + * Get transform string + * + * @param {number} x + * @param {number} [y] + * @param {number} [scale] + * @returns {string} + */ +function toTransformString(x, y, scale) { + let propValue = `translate3d(${x}px,${y || 0}px,0)`; + + if (scale !== undefined) { + propValue += ` scale3d(${scale},${scale},1)`; + } + + return propValue; +} + +/** + * Apply width and height CSS properties to element + * + * @param {HTMLElement} el + * @param {string | number} w + * @param {string | number} h + */ +function setWidthHeight(el, w, h) { + el.style.width = (typeof w === 'number') ? `${w}px` : w; + el.style.height = (typeof h === 'number') ? `${h}px` : h; +} + +/** @typedef {LOAD_STATE[keyof LOAD_STATE]} LoadState */ +/** @type {{ IDLE: 'idle'; LOADING: 'loading'; LOADED: 'loaded'; ERROR: 'error' }} */ +const LOAD_STATE = { + IDLE: 'idle', + LOADING: 'loading', + LOADED: 'loaded', + ERROR: 'error', +}; + + +/** + * Check if click or keydown event was dispatched + * with a special key or via mouse wheel. + * + * @param {MouseEvent | KeyboardEvent} e + * @returns {boolean} + */ +function specialKeyUsed(e) { + return ('button' in e && e.button === 1) || e.ctrlKey || e.metaKey || e.altKey || e.shiftKey; +} + +/** + * Parse `gallery` or `children` options. + * + * @param {import('../photoswipe.js').ElementProvider} [option] + * @param {string} [legacySelector] + * @param {HTMLElement | Document} [parent] + * @returns HTMLElement[] + */ +function getElementsFromOption(option, legacySelector, parent = document) { + /** @type {HTMLElement[]} */ + 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; +} + +/** + * Check if variable is PhotoSwipe class + * + * @param {any} fn + * @returns {boolean} + */ +function isPswpClass(fn) { + return typeof fn === 'function' + && fn.prototype + && fn.prototype.goTo; +} + +/** + * Check if browser is Safari + * + * @returns {boolean} + */ +function isSafari() { + return !!(navigator.vendor && navigator.vendor.match(/apple/i)); +} + +/** @typedef {import('../lightbox/lightbox.js').default} PhotoSwipeLightbox */ +/** @typedef {import('../photoswipe.js').default} PhotoSwipe */ +/** @typedef {import('../photoswipe.js').PhotoSwipeOptions} PhotoSwipeOptions */ +/** @typedef {import('../photoswipe.js').DataSource} DataSource */ +/** @typedef {import('../ui/ui-element.js').UIElementData} UIElementData */ +/** @typedef {import('../slide/content.js').default} ContentDefault */ +/** @typedef {import('../slide/slide.js').default} Slide */ +/** @typedef {import('../slide/slide.js').SlideData} SlideData */ +/** @typedef {import('../slide/zoom-level.js').default} ZoomLevel */ +/** @typedef {import('../slide/get-thumb-bounds.js').Bounds} Bounds */ + +/** + * Allow adding an arbitrary props to the Content + * https://photoswipe.com/custom-content/#using-webp-image-format + * @typedef {ContentDefault & Record} Content + */ +/** @typedef {{ x?: number; y?: number }} Point */ + +/** + * @typedef {Object} PhotoSwipeEventsMap https://photoswipe.com/events/ + * + * + * https://photoswipe.com/adding-ui-elements/ + * + * @prop {undefined} uiRegister + * @prop {{ data: UIElementData }} uiElementCreate + * + * + * https://photoswipe.com/events/#initialization-events + * + * @prop {undefined} beforeOpen + * @prop {undefined} firstUpdate + * @prop {undefined} initialLayout + * @prop {undefined} change + * @prop {undefined} afterInit + * @prop {undefined} bindEvents + * + * + * https://photoswipe.com/events/#opening-or-closing-transition-events + * + * @prop {undefined} openingAnimationStart + * @prop {undefined} openingAnimationEnd + * @prop {undefined} closingAnimationStart + * @prop {undefined} closingAnimationEnd + * + * + * https://photoswipe.com/events/#closing-events + * + * @prop {undefined} close + * @prop {undefined} destroy + * + * + * https://photoswipe.com/events/#pointer-and-gesture-events + * + * @prop {{ originalEvent: PointerEvent }} pointerDown + * @prop {{ originalEvent: PointerEvent }} pointerMove + * @prop {{ originalEvent: PointerEvent }} pointerUp + * @prop {{ bgOpacity: number }} pinchClose can be default prevented + * @prop {{ panY: number }} verticalDrag can be default prevented + * + * + * https://photoswipe.com/events/#slide-content-events + * + * @prop {{ content: Content }} contentInit + * @prop {{ content: Content; isLazy: boolean }} contentLoad can be default prevented + * @prop {{ content: Content; isLazy: boolean }} contentLoadImage can be default prevented + * @prop {{ content: Content; slide: Slide; isError?: boolean }} loadComplete + * @prop {{ content: Content; slide: Slide }} loadError + * @prop {{ content: Content; width: number; height: number }} contentResize can be default prevented + * @prop {{ content: Content; width: number; height: number; slide: Slide }} imageSizeChange + * @prop {{ content: Content }} contentLazyLoad can be default prevented + * @prop {{ content: Content }} contentAppend can be default prevented + * @prop {{ content: Content }} contentActivate can be default prevented + * @prop {{ content: Content }} contentDeactivate can be default prevented + * @prop {{ content: Content }} contentRemove can be default prevented + * @prop {{ content: Content }} contentDestroy can be default prevented + * + * + * undocumented + * + * @prop {{ point: Point; originalEvent: PointerEvent }} imageClickAction can be default prevented + * @prop {{ point: Point; originalEvent: PointerEvent }} bgClickAction can be default prevented + * @prop {{ point: Point; originalEvent: PointerEvent }} tapAction can be default prevented + * @prop {{ point: Point; originalEvent: PointerEvent }} doubleTapAction can be default prevented + * + * @prop {{ originalEvent: KeyboardEvent }} keydown can be default prevented + * @prop {{ x: number; dragging: boolean }} moveMainScroll + * @prop {{ slide: Slide }} firstZoomPan + * @prop {{ slide: Slide | undefined, data: SlideData, index: number }} gettingData + * @prop {undefined} beforeResize + * @prop {undefined} resize + * @prop {undefined} viewportSize + * @prop {undefined} updateScrollOffset + * @prop {{ slide: Slide }} slideInit + * @prop {{ slide: Slide }} afterSetContent + * @prop {{ slide: Slide }} slideLoad + * @prop {{ slide: Slide }} appendHeavy can be default prevented + * @prop {{ slide: Slide }} appendHeavyContent + * @prop {{ slide: Slide }} slideActivate + * @prop {{ slide: Slide }} slideDeactivate + * @prop {{ slide: Slide }} slideDestroy + * @prop {{ destZoomLevel: number, centerPoint: Point | undefined, transitionDuration: number | false | undefined }} beforeZoomTo + * @prop {{ slide: Slide }} zoomPanUpdate + * @prop {{ slide: Slide }} initialZoomPan + * @prop {{ slide: Slide }} calcSlideSize + * @prop {undefined} resolutionChanged + * @prop {{ originalEvent: WheelEvent }} wheel can be default prevented + * @prop {{ content: Content }} contentAppendImage can be default prevented + * @prop {{ index: number; itemData: SlideData }} lazyLoadSlide can be default prevented + * @prop {undefined} lazyLoad + * @prop {{ slide: Slide }} calcBounds + * @prop {{ zoomLevels: ZoomLevel, slideData: SlideData }} zoomLevelsUpdate + * + * + * legacy + * + * @prop {undefined} init + * @prop {undefined} initialZoomIn + * @prop {undefined} initialZoomOut + * @prop {undefined} initialZoomInEnd + * @prop {undefined} initialZoomOutEnd + * @prop {{ dataSource: DataSource | undefined, numItems: number }} numItems + * @prop {{ itemData: SlideData; index: number }} itemData + * @prop {{ index: number, itemData: SlideData, instance: PhotoSwipe }} thumbBounds + */ + +/** + * @typedef {Object} PhotoSwipeFiltersMap https://photoswipe.com/filters/ + * + * @prop {(numItems: number, dataSource: DataSource | undefined) => number} numItems + * Modify the total amount of slides. Example on Data sources page. + * https://photoswipe.com/filters/#numitems + * + * @prop {(itemData: SlideData, index: number) => SlideData} itemData + * Modify slide item data. Example on Data sources page. + * https://photoswipe.com/filters/#itemdata + * + * @prop {(itemData: SlideData, element: HTMLElement, linkEl: HTMLAnchorElement) => SlideData} domItemData + * Modify item data when it's parsed from DOM element. Example on Data sources page. + * https://photoswipe.com/filters/#domitemdata + * + * @prop {(clickedIndex: number, e: MouseEvent, instance: PhotoSwipeLightbox) => number} clickedIndex + * Modify clicked gallery item index. + * https://photoswipe.com/filters/#clickedindex + * + * @prop {(placeholderSrc: string | false, content: Content) => string | false} placeholderSrc + * Modify placeholder image source. + * https://photoswipe.com/filters/#placeholdersrc + * + * @prop {(isContentLoading: boolean, content: Content) => boolean} isContentLoading + * Modify if the content is currently loading. + * https://photoswipe.com/filters/#iscontentloading + * + * @prop {(isContentZoomable: boolean, content: Content) => boolean} isContentZoomable + * Modify if the content can be zoomed. + * https://photoswipe.com/filters/#iscontentzoomable + * + * @prop {(useContentPlaceholder: boolean, content: Content) => boolean} useContentPlaceholder + * Modify if the placeholder should be used for the content. + * https://photoswipe.com/filters/#usecontentplaceholder + * + * @prop {(isKeepingPlaceholder: boolean, content: Content) => boolean} isKeepingPlaceholder + * Modify if the placeholder should be kept after the content is loaded. + * https://photoswipe.com/filters/#iskeepingplaceholder + * + * + * @prop {(contentErrorElement: HTMLElement, content: Content) => HTMLElement} contentErrorElement + * Modify an element when the content has error state (for example, if image cannot be loaded). + * https://photoswipe.com/filters/#contenterrorelement + * + * @prop {(element: HTMLElement, data: UIElementData) => HTMLElement} uiElement + * Modify a UI element that's being created. + * https://photoswipe.com/filters/#uielement + * + * @prop {(thumbnail: HTMLElement | null | undefined, itemData: SlideData, index: number) => HTMLElement} thumbEl + * Modify the thubmnail element from which opening zoom animation starts or ends. + * https://photoswipe.com/filters/#thumbel + * + * @prop {(thumbBounds: Bounds | undefined, itemData: SlideData, index: number) => Bounds} thumbBounds + * Modify the thubmnail bounds from which opening zoom animation starts or ends. + * https://photoswipe.com/filters/#thumbbounds + * + * @prop {(srcsetSizesWidth: number, content: Content) => number} srcsetSizesWidth + * + */ + +/** + * @template {keyof PhotoSwipeFiltersMap} T + * @typedef {{ fn: PhotoSwipeFiltersMap[T], priority: number }} Filter + */ + +/** + * @template {keyof PhotoSwipeEventsMap} T + * @typedef {PhotoSwipeEventsMap[T] extends undefined ? PhotoSwipeEvent : PhotoSwipeEvent & PhotoSwipeEventsMap[T]} AugmentedEvent + */ + +/** + * @template {keyof PhotoSwipeEventsMap} T + * @typedef {(event: AugmentedEvent) => void} EventCallback + */ + +/** + * Base PhotoSwipe event object + * + * @template {keyof PhotoSwipeEventsMap} T + */ +class PhotoSwipeEvent { + /** + * @param {T} type + * @param {PhotoSwipeEventsMap[T]} [details] + */ + constructor(type, details) { + this.type = type; + this.defaultPrevented = false; + 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() { + /** + * @type {{ [T in keyof PhotoSwipeEventsMap]?: ((event: AugmentedEvent) => void)[] }} + */ + this._listeners = {}; + + /** + * @type {{ [T in keyof PhotoSwipeFiltersMap]?: Filter[] }} + */ + this._filters = {}; + + /** @type {PhotoSwipe | undefined} */ + this.pswp = undefined; + + /** @type {PhotoSwipeOptions | undefined} */ + this.options = undefined; + } + + /** + * @template {keyof PhotoSwipeFiltersMap} T + * @param {T} name + * @param {PhotoSwipeFiltersMap[T]} fn + * @param {number} priority + */ + addFilter(name, fn, priority = 100) { + if (!this._filters[name]) { + this._filters[name] = []; + } + + this._filters[name]?.push({ fn, priority }); + this._filters[name]?.sort((f1, f2) => f1.priority - f2.priority); + + this.pswp?.addFilter(name, fn, priority); + } + + /** + * @template {keyof PhotoSwipeFiltersMap} T + * @param {T} name + * @param {PhotoSwipeFiltersMap[T]} fn + */ + removeFilter(name, fn) { + if (this._filters[name]) { + // @ts-expect-error + this._filters[name] = this._filters[name].filter(filter => (filter.fn !== fn)); + } + + if (this.pswp) { + this.pswp.removeFilter(name, fn); + } + } + + /** + * @template {keyof PhotoSwipeFiltersMap} T + * @param {T} name + * @param {Parameters} args + * @returns {Parameters[0]} + */ + applyFilters(name, ...args) { + this._filters[name]?.forEach((filter) => { + // @ts-expect-error + args[0] = filter.fn.apply(this, args); + }); + return args[0]; + } + + /** + * @template {keyof PhotoSwipeEventsMap} T + * @param {T} name + * @param {EventCallback} fn + */ + 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. + this.pswp?.on(name, fn); + } + + /** + * @template {keyof PhotoSwipeEventsMap} T + * @param {T} name + * @param {EventCallback} fn + */ + off(name, fn) { + if (this._listeners[name]) { + // @ts-expect-error + this._listeners[name] = this._listeners[name].filter(listener => (fn !== listener)); + } + + this.pswp?.off(name, fn); + } + + /** + * @template {keyof PhotoSwipeEventsMap} T + * @param {T} name + * @param {PhotoSwipeEventsMap[T]} [details] + * @returns {AugmentedEvent} + */ + dispatch(name, details) { + if (this.pswp) { + return this.pswp.dispatch(name, details); + } + + const event = /** @type {AugmentedEvent} */ (new PhotoSwipeEvent(name, details)); + + this._listeners[name]?.forEach((listener) => { + listener.call(this, event); + }); + + return event; + } +} + +class Placeholder { + /** + * @param {string | false} imageSrc + * @param {HTMLElement} container + */ + constructor(imageSrc, container) { + // Create placeholder + // (stretched thumbnail or simple div behind the main image) + /** @type {HTMLImageElement | HTMLDivElement | null} */ + this.element = createElement( + 'pswp__img pswp__img--placeholder', + imageSrc ? 'img' : 'div', + container + ); + + if (imageSrc) { + const imgEl = /** @type {HTMLImageElement} */ (this.element); + imgEl.decoding = 'async'; + imgEl.alt = ''; + imgEl.src = imageSrc; + imgEl.setAttribute('role', 'presentation'); + } + + this.element.setAttribute('aria-hidden', 'true'); + } + + /** + * @param {number} width + * @param {number} height + */ + setDisplayedSize(width, height) { + if (!this.element) { + return; + } + + if (this.element.tagName === 'IMG') { + // Use transform scale() to modify img placeholder size + // (instead of changing width/height directly). + // This helps with performance, specifically in iOS15 Safari. + setWidthHeight(this.element, 250, 'auto'); + this.element.style.transformOrigin = '0 0'; + this.element.style.transform = toTransformString(0, 0, width / 250); + } else { + setWidthHeight(this.element, width, height); + } + } + + destroy() { + if (this.element?.parentNode) { + this.element.remove(); + } + this.element = null; + } +} + +/** @typedef {import('./slide.js').default} Slide */ +/** @typedef {import('./slide.js').SlideData} SlideData */ +/** @typedef {import('../core/base.js').default} PhotoSwipeBase */ +/** @typedef {import('../util/util.js').LoadState} LoadState */ + +class Content { + /** + * @param {SlideData} itemData Slide data + * @param {PhotoSwipeBase} instance PhotoSwipe or PhotoSwipeLightbox instance + * @param {number} index + */ + constructor(itemData, instance, index) { + this.instance = instance; + this.data = itemData; + this.index = index; + + /** @type {HTMLImageElement | HTMLDivElement | undefined} */ + this.element = undefined; + /** @type {Placeholder | undefined} */ + this.placeholder = undefined; + /** @type {Slide | undefined} */ + this.slide = undefined; + + this.displayedImageWidth = 0; + this.displayedImageHeight = 0; + + this.width = Number(this.data.w) || Number(this.data.width) || 0; + this.height = Number(this.data.h) || Number(this.data.height) || 0; + + this.isAttached = false; + this.hasSlide = false; + this.isDecoding = false; + /** @type {LoadState} */ + this.state = LOAD_STATE.IDLE; + + if (this.data.type) { + this.type = this.data.type; + } else if (this.data.src) { + this.type = 'image'; + } else { + this.type = 'html'; + } + + this.instance.dispatch('contentInit', { content: this }); + } + + removePlaceholder() { + if (this.placeholder && !this.keepPlaceholder()) { + // With delay, as image might be loaded, but not rendered + setTimeout(() => { + if (this.placeholder) { + this.placeholder.destroy(); + this.placeholder = undefined; + } + }, 1000); + } + } + + /** + * Preload content + * + * @param {boolean} isLazy + * @param {boolean} [reload] + */ + load(isLazy, reload) { + if (this.slide && this.usePlaceholder()) { + if (!this.placeholder) { + const placeholderSrc = this.instance.applyFilters( + 'placeholderSrc', + // use image-based placeholder only for the first slide, + // as rendering (even small stretched thumbnail) is an expensive operation + (this.data.msrc && this.slide.isFirstSlide) ? this.data.msrc : false, + this + ); + this.placeholder = new Placeholder( + placeholderSrc, + this.slide.container + ); + } else { + const placeholderEl = this.placeholder.element; + // Add placeholder to DOM if it was already created + if (placeholderEl && !placeholderEl.parentElement) { + this.slide.container.prepend(placeholderEl); + } + } + } + + if (this.element && !reload) { + return; + } + + if (this.instance.dispatch('contentLoad', { content: this, isLazy }).defaultPrevented) { + return; + } + + if (this.isImageContent()) { + this.element = createElement('pswp__img', 'img'); + // Start loading only after width is defined, as sizes might depend on it. + // Due to Safari feature, we must define sizes before srcset. + if (this.displayedImageWidth) { + this.loadImage(isLazy); + } + } else { + this.element = createElement('pswp__content', 'div'); + this.element.innerHTML = this.data.html || ''; + } + + if (reload && this.slide) { + this.slide.updateContentSize(true); + } + } + + /** + * Preload image + * + * @param {boolean} isLazy + */ + loadImage(isLazy) { + if (!this.isImageContent() + || !this.element + || this.instance.dispatch('contentLoadImage', { content: this, isLazy }).defaultPrevented) { + return; + } + + const imageElement = /** @type HTMLImageElement */ (this.element); + + this.updateSrcsetSizes(); + + if (this.data.srcset) { + imageElement.srcset = this.data.srcset; + } + + imageElement.src = this.data.src ?? ''; + imageElement.alt = this.data.alt ?? ''; + + this.state = LOAD_STATE.LOADING; + + if (imageElement.complete) { + this.onLoaded(); + } else { + imageElement.onload = () => { + this.onLoaded(); + }; + + imageElement.onerror = () => { + this.onError(); + }; + } + } + + /** + * Assign slide to content + * + * @param {Slide} slide + */ + setSlide(slide) { + this.slide = slide; + this.hasSlide = true; + this.instance = slide.pswp; + + // todo: do we need to unset slide? + } + + /** + * Content load success handler + */ + onLoaded() { + this.state = LOAD_STATE.LOADED; + + if (this.slide && this.element) { + this.instance.dispatch('loadComplete', { slide: this.slide, content: this }); + + // if content is reloaded + if (this.slide.isActive + && this.slide.heavyAppended + && !this.element.parentNode) { + this.append(); + this.slide.updateContentSize(true); + } + + if (this.state === LOAD_STATE.LOADED || this.state === LOAD_STATE.ERROR) { + this.removePlaceholder(); + } + } + } + + /** + * Content load error handler + */ + onError() { + this.state = LOAD_STATE.ERROR; + + if (this.slide) { + this.displayError(); + this.instance.dispatch('loadComplete', { slide: this.slide, isError: true, content: this }); + this.instance.dispatch('loadError', { slide: this.slide, content: this }); + } + } + + /** + * @returns {Boolean} If the content is currently loading + */ + isLoading() { + return this.instance.applyFilters( + 'isContentLoading', + this.state === LOAD_STATE.LOADING, + this + ); + } + + /** + * @returns {Boolean} If the content is in error state + */ + isError() { + return this.state === LOAD_STATE.ERROR; + } + + /** + * @returns {boolean} If the content is image + */ + isImageContent() { + return this.type === 'image'; + } + + /** + * Update content size + * + * @param {Number} width + * @param {Number} height + */ + setDisplayedSize(width, height) { + if (!this.element) { + return; + } + + if (this.placeholder) { + this.placeholder.setDisplayedSize(width, height); + } + + if (this.instance.dispatch( + 'contentResize', + { content: this, width, height }).defaultPrevented + ) { + return; + } + + setWidthHeight(this.element, width, height); + + if (this.isImageContent() && !this.isError()) { + const isInitialSizeUpdate = (!this.displayedImageWidth && width); + + this.displayedImageWidth = width; + this.displayedImageHeight = height; + + if (isInitialSizeUpdate) { + this.loadImage(false); + } else { + this.updateSrcsetSizes(); + } + + if (this.slide) { + this.instance.dispatch( + 'imageSizeChange', + { slide: this.slide, width, height, content: this } + ); + } + } + } + + /** + * @returns {boolean} If the content can be zoomed + */ + isZoomable() { + return this.instance.applyFilters( + 'isContentZoomable', + this.isImageContent() && (this.state !== LOAD_STATE.ERROR), + this + ); + } + + /** + * Update image srcset sizes attribute based on width and height + */ + updateSrcsetSizes() { + // Handle srcset sizes attribute. + // + // Never lower quality, if it was increased previously. + // Chrome does this automatically, Firefox and Safari do not, + // so we store largest used size in dataset. + if (!this.isImageContent() || !this.element || !this.data.srcset) { + return; + } + + const image = /** @type HTMLImageElement */ (this.element); + const sizesWidth = this.instance.applyFilters( + 'srcsetSizesWidth', + this.displayedImageWidth, + this + ); + + if ( + !image.dataset.largestUsedSize + || sizesWidth > parseInt(image.dataset.largestUsedSize, 10) + ) { + image.sizes = sizesWidth + 'px'; + image.dataset.largestUsedSize = String(sizesWidth); + } + } + + /** + * @returns {boolean} If content should use a placeholder (from msrc by default) + */ + usePlaceholder() { + return this.instance.applyFilters( + 'useContentPlaceholder', + this.isImageContent(), + this + ); + } + + /** + * Preload content with lazy-loading param + */ + lazyLoad() { + if (this.instance.dispatch('contentLazyLoad', { content: this }).defaultPrevented) { + return; + } + + this.load(true); + } + + /** + * @returns {boolean} If placeholder should be kept after content is loaded + */ + keepPlaceholder() { + return this.instance.applyFilters( + 'isKeepingPlaceholder', + this.isLoading(), + this + ); + } + + /** + * Destroy the content + */ + destroy() { + this.hasSlide = false; + this.slide = undefined; + + if (this.instance.dispatch('contentDestroy', { content: this }).defaultPrevented) { + return; + } + + this.remove(); + + if (this.placeholder) { + this.placeholder.destroy(); + this.placeholder = undefined; + } + + if (this.isImageContent() && this.element) { + this.element.onload = null; + this.element.onerror = null; + this.element = undefined; + } + } + + /** + * Display error message + */ + displayError() { + if (this.slide) { + let errorMsgEl = createElement('pswp__error-msg', 'div'); + errorMsgEl.innerText = this.instance.options?.errorMsg ?? ''; + errorMsgEl = /** @type {HTMLDivElement} */ (this.instance.applyFilters( + 'contentErrorElement', + errorMsgEl, + this + )); + this.element = createElement('pswp__content pswp__error-msg-container', 'div'); + this.element.appendChild(errorMsgEl); + this.slide.container.innerText = ''; + this.slide.container.appendChild(this.element); + this.slide.updateContentSize(true); + this.removePlaceholder(); + } + } + + /** + * Append the content + */ + append() { + if (this.isAttached || !this.element) { + return; + } + + this.isAttached = true; + + if (this.state === LOAD_STATE.ERROR) { + this.displayError(); + return; + } + + if (this.instance.dispatch('contentAppend', { content: this }).defaultPrevented) { + return; + } + + const supportsDecode = ('decode' in this.element); + + if (this.isImageContent()) { + // Use decode() on nearby slides + // + // Nearby slide images are in DOM and not hidden via display:none. + // However, they are placed offscreen (to the left and right side). + // + // Some browsers do not composite the image until it's actually visible, + // using decode() helps. + // + // You might ask "why dont you just decode() and then append all images", + // that's because I want to show image before it's fully loaded, + // as browser can render parts of image while it is loading. + // We do not do this in Safari due to partial loading bug. + if (supportsDecode && this.slide && (!this.slide.isActive || isSafari())) { + this.isDecoding = true; + // purposefully using finally instead of then, + // as if srcset sizes changes dynamically - it may cause decode error + /** @type {HTMLImageElement} */ + (this.element).decode().catch(() => {}).finally(() => { + this.isDecoding = false; + this.appendImage(); + }); + } else { + this.appendImage(); + } + } else if (this.slide && !this.element.parentNode) { + this.slide.container.appendChild(this.element); + } + } + + /** + * Activate the slide, + * active slide is generally the current one, + * meaning the user can see it. + */ + activate() { + if (this.instance.dispatch('contentActivate', { content: this }).defaultPrevented + || !this.slide) { + return; + } + + if (this.isImageContent() && this.isDecoding && !isSafari()) { + // add image to slide when it becomes active, + // even if it's not finished decoding + this.appendImage(); + } else if (this.isError()) { + this.load(false, true); // try to reload + } + + if (this.slide.holderElement) { + this.slide.holderElement.setAttribute('aria-hidden', 'false'); + } + } + + /** + * Deactivate the content + */ + deactivate() { + this.instance.dispatch('contentDeactivate', { content: this }); + if (this.slide && this.slide.holderElement) { + this.slide.holderElement.setAttribute('aria-hidden', 'true'); + } + } + + + /** + * Remove the content from DOM + */ + remove() { + this.isAttached = false; + + if (this.instance.dispatch('contentRemove', { content: this }).defaultPrevented) { + return; + } + + if (this.element && this.element.parentNode) { + this.element.remove(); + } + + if (this.placeholder && this.placeholder.element) { + this.placeholder.element.remove(); + } + } + + /** + * Append the image content to slide container + */ + appendImage() { + if (!this.isAttached) { + return; + } + + if (this.instance.dispatch('contentAppendImage', { content: this }).defaultPrevented) { + return; + } + + // ensure that element exists and is not already appended + if (this.slide && this.element && !this.element.parentNode) { + this.slide.container.appendChild(this.element); + } + + if (this.state === LOAD_STATE.LOADED || this.state === LOAD_STATE.ERROR) { + this.removePlaceholder(); + } + } +} + +/** @typedef {import('../photoswipe.js').PhotoSwipeOptions} PhotoSwipeOptions */ +/** @typedef {import('../core/base.js').default} PhotoSwipeBase */ +/** @typedef {import('../photoswipe.js').Point} Point */ +/** @typedef {import('../slide/slide.js').SlideData} SlideData */ + +/** + * @param {PhotoSwipeOptions} options + * @param {PhotoSwipeBase} pswp + * @returns {Point} + */ +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 + }; +} + +/** + * Parses padding option. + * Supported formats: + * + * // Object + * padding: { + * top: 0, + * bottom: 0, + * left: 0, + * right: 0 + * } + * + * // A function that returns the object + * paddingFn: (viewportSize, itemData, index) => { + * return { + * top: 0, + * bottom: 0, + * left: 0, + * right: 0 + * }; + * } + * + * // Legacy variant + * paddingLeft: 0, + * paddingRight: 0, + * paddingTop: 0, + * paddingBottom: 0, + * + * @param {'left' | 'top' | 'bottom' | 'right'} prop + * @param {PhotoSwipeOptions} options PhotoSwipe options + * @param {Point} viewportSize PhotoSwipe viewport size, for example: { x:800, y:600 } + * @param {SlideData} itemData Data about the slide + * @param {number} index Slide index + * @returns {number} + */ +function parsePaddingOption(prop, options, viewportSize, itemData, index) { + let paddingValue = 0; + + if (options.paddingFn) { + paddingValue = options.paddingFn(viewportSize, itemData, index)[prop]; + } else if (options.padding) { + paddingValue = options.padding[prop]; + } else { + const legacyPropName = 'padding' + prop[0].toUpperCase() + prop.slice(1); + // @ts-expect-error + if (options[legacyPropName]) { + // @ts-expect-error + paddingValue = options[legacyPropName]; + } + } + + return Number(paddingValue) || 0; +} + +/** + * @param {PhotoSwipeOptions} options + * @param {Point} viewportSize + * @param {SlideData} itemData + * @param {number} index + * @returns {Point} + */ +function getPanAreaSize(options, viewportSize, itemData, index) { + return { + x: viewportSize.x + - parsePaddingOption('left', options, viewportSize, itemData, index) + - parsePaddingOption('right', options, viewportSize, itemData, index), + y: viewportSize.y + - parsePaddingOption('top', options, viewportSize, itemData, index) + - parsePaddingOption('bottom', options, viewportSize, itemData, index) + }; +} + +const MAX_IMAGE_WIDTH = 4000; + +/** @typedef {import('../photoswipe.js').default} PhotoSwipe */ +/** @typedef {import('../photoswipe.js').PhotoSwipeOptions} PhotoSwipeOptions */ +/** @typedef {import('../photoswipe.js').Point} Point */ +/** @typedef {import('../slide/slide.js').SlideData} SlideData */ + +/** @typedef {'fit' | 'fill' | number | ((zoomLevelObject: ZoomLevel) => number)} ZoomLevelOption */ + +/** + * Calculates zoom levels for specific slide. + * Depends on viewport size and image size. + */ +class ZoomLevel { + /** + * @param {PhotoSwipeOptions} options PhotoSwipe options + * @param {SlideData} itemData Slide data + * @param {number} index Slide index + * @param {PhotoSwipe} [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; + /** @type { Point | null } */ + this.panAreaSize = null; + /** @type { Point | null } */ + this.elementSize = null; + this.fit = 1; + this.fill = 1; + this.vFill = 1; + this.initial = 1; + this.secondary = 1; + this.max = 1; + this.min = 1; + } + + /** + * Calculate initial, secondary and maximum zoom level for the specified slide. + * + * It should be called when either image or viewport size changes. + * + * @param {number} maxWidth + * @param {number} maxHeight + * @param {Point} panAreaSize + */ + update(maxWidth, maxHeight, panAreaSize) { + /** @type {Point} */ + const elementSize = { x: maxWidth, y: maxHeight }; + this.elementSize = elementSize; + this.panAreaSize = panAreaSize; + + const hRatio = panAreaSize.x / elementSize.x; + const vRatio = panAreaSize.y / 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. + * + * @private + * @param {'initial' | 'secondary' | 'max'} optionPrefix Zoom level option prefix (initial, secondary, max) + * @returns { number | undefined } + */ + _parseZoomLevelOption(optionPrefix) { + const optionName = /** @type {'initialZoomLevel' | 'secondaryZoomLevel' | 'maxZoomLevel'} */ ( + optionPrefix + 'ZoomLevel' + ); + const optionValue = this.options[optionName]; + + 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. + * + * @private + * @return {number} + */ + _getSecondary() { + let currZoomLevel = this._parseZoomLevelOption('secondary'); + + if (currZoomLevel) { + return currZoomLevel; + } + + // 3x of "fit" state, but not larger than original + currZoomLevel = Math.min(1, this.fit * 3); + + if (this.elementSize && currZoomLevel * this.elementSize.x > MAX_IMAGE_WIDTH) { + currZoomLevel = MAX_IMAGE_WIDTH / this.elementSize.x; + } + + return currZoomLevel; + } + + /** + * Get initial image zoom level. + * + * @private + * @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. + * + * @private + * @return {number} + */ + _getMax() { + // max zoom level is x4 from "fit state", + // used for zoom gesture and ctrl/trackpad zoom + return this._parseZoomLevelOption('max') || 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 {SlideData} itemData Data about the slide + * @param {PhotoSwipeBase} instance PhotoSwipe or PhotoSwipeLightbox instance + * @param {number} index + * @returns {Content} Image that is being decoded or false. + */ +function lazyLoadData(itemData, instance, index) { + const content = instance.createContentFromData(itemData, index); + /** @type {ZoomLevel | undefined} */ + let zoomLevel; + + 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 + if (options) { + zoomLevel = new ZoomLevel(options, itemData, -1); + + let viewportSize; + if (instance.pswp) { + viewportSize = instance.pswp.viewportSize; + } else { + viewportSize = getViewportSize(options, instance); + } + + const panAreaSize = getPanAreaSize(options, viewportSize, itemData, index); + zoomLevel.update(content.width, content.height, panAreaSize); + } + + content.lazyLoad(); + + if (zoomLevel) { + content.setDisplayedSize( + Math.ceil(content.width * zoomLevel.initial), + Math.ceil(content.height * zoomLevel.initial) + ); + } + + return content; +} + + +/** + * 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 {number} index Slide index + * @param {PhotoSwipeBase} instance PhotoSwipe or PhotoSwipeLightbox eventable instance + * @returns {Content | undefined} + */ +function lazyLoadSlide(index, instance) { + const itemData = instance.getItemData(index); + + if (instance.dispatch('lazyLoadSlide', { index, itemData }).defaultPrevented) { + return; + } + + return lazyLoadData(itemData, instance, index); +} + +/** @typedef {import("../photoswipe.js").default} PhotoSwipe */ +/** @typedef {import("../slide/slide.js").SlideData} SlideData */ + +/** + * 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 + * + * @returns {number} + */ + getNumItems() { + let numItems = 0; + const dataSource = this.options?.dataSource; + + if (dataSource && 'length' in dataSource) { + // may be an array or just object with length property + numItems = dataSource.length; + } else if (dataSource && 'gallery' in dataSource) { + // query DOM elements + if (!dataSource.items) { + dataSource.items = this._getGalleryDOMElements(dataSource.gallery); + } + + if (dataSource.items) { + numItems = dataSource.items.length; + } + } + + // legacy event, before filters were introduced + const event = this.dispatch('numItems', { + dataSource, + numItems + }); + return this.applyFilters('numItems', event.numItems, dataSource); + } + + /** + * @param {SlideData} slideData + * @param {number} index + * @returns {Content} + */ + createContentFromData(slideData, index) { + return new Content(slideData, this, index); + } + + /** + * 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 {number} index + * @returns {SlideData} + */ + getItemData(index) { + const dataSource = this.options?.dataSource; + /** @type {SlideData | HTMLElement} */ + let dataSourceItem = {}; + if (Array.isArray(dataSource)) { + // Datasource is an array of elements + dataSourceItem = dataSource[index]; + } else if (dataSource && 'gallery' in dataSource) { + // dataSource has gallery property, + // thus it was created by Lightbox, based on + // gallery and children 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); + } + + // Dispatching the itemData event, + // it's a legacy verion before filters were introduced + const event = this.dispatch('itemData', { + itemData: itemData || {}, + index + }); + + return this.applyFilters('itemData', event.itemData, index); + } + + /** + * Get array of gallery DOM elements, + * based on childSelector and gallery element. + * + * @param {HTMLElement} galleryElement + * @returns {HTMLElement[]} + */ + _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 {HTMLElement} element DOM element + * @returns {SlideData} + */ + _domElementToItemData(element) { + /** @type {SlideData} */ + const itemData = { + element + }; + + const linkEl = /** @type {HTMLAnchorElement} */ ( + element.tagName === 'A' + ? element + : element.querySelector('a') + ); + + if (linkEl) { + // src comes from data-pswp-src attribute, + // if it's empty link href is used + itemData.src = linkEl.dataset.pswpSrc || linkEl.href; + + if (linkEl.dataset.pswpSrcset) { + itemData.srcset = linkEl.dataset.pswpSrcset; + } + + itemData.width = linkEl.dataset.pswpWidth ? parseInt(linkEl.dataset.pswpWidth, 10) : 0; + itemData.height = linkEl.dataset.pswpHeight ? parseInt(linkEl.dataset.pswpHeight, 10) : 0; + + // support legacy w & h properties + itemData.w = itemData.width; + itemData.h = itemData.height; + + if (linkEl.dataset.pswpType) { + itemData.type = linkEl.dataset.pswpType; + } + + const thumbnailEl = element.querySelector('img'); + + if (thumbnailEl) { + // msrc is URL to placeholder image that's displayed before large image is loaded + // by default it's displayed only for the first slide + itemData.msrc = thumbnailEl.currentSrc || thumbnailEl.src; + itemData.alt = thumbnailEl.getAttribute('alt') ?? ''; + } + + if (linkEl.dataset.pswpCropped || linkEl.dataset.cropped) { + itemData.thumbCropped = true; + } + } + + return this.applyFilters('domItemData', itemData, element, linkEl); + } + + /** + * Lazy-load by slide data + * + * @param {SlideData} itemData Data about the slide + * @param {number} index + * @returns {Content} Image that is being decoded or false. + */ + lazyLoadData(itemData, index) { + return lazyLoadData(itemData, this, index); + } +} + +/** + * @template T + * @typedef {import('../types.js').Type} Type + */ + +/** @typedef {import('../photoswipe.js').default} PhotoSwipe */ +/** @typedef {import('../photoswipe.js').PhotoSwipeOptions} PhotoSwipeOptions */ +/** @typedef {import('../photoswipe.js').DataSource} DataSource */ +/** @typedef {import('../photoswipe.js').Point} Point */ +/** @typedef {import('../slide/content.js').default} Content */ +/** @typedef {import('../core/eventable.js').PhotoSwipeEventsMap} PhotoSwipeEventsMap */ +/** @typedef {import('../core/eventable.js').PhotoSwipeFiltersMap} PhotoSwipeFiltersMap */ + +/** + * @template {keyof PhotoSwipeEventsMap} T + * @typedef {import('../core/eventable.js').EventCallback} EventCallback + */ + +/** + * 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 { + /** + * @param {PhotoSwipeOptions} [options] + */ + constructor(options) { + super(); + /** @type {PhotoSwipeOptions} */ + this.options = options || {}; + this._uid = 0; + this.shouldOpen = false; + /** + * @private + * @type {Content | undefined} + */ + this._preloadedContent = undefined; + + this.onThumbnailsClick = this.onThumbnailsClick.bind(this); + } + + /** + * Initialize lightbox, should be called only once. + * It's not included in the main constructor, so you may bind events before it. + */ + init() { + // Bind click events to each gallery + getElementsFromOption(this.options.gallery, this.options.gallerySelector) + .forEach((galleryElement) => { + galleryElement.addEventListener('click', this.onThumbnailsClick, false); + }); + } + + /** + * @param {MouseEvent} e + */ + 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 + 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 the ideal way to detect them. + // + /** @type {Point | null} */ + let initialPoint = { x: e.clientX, y: e.clientY }; + + if (!initialPoint.x && !initialPoint.y) { + initialPoint = null; + } + + let clickedIndex = this.getClickedIndex(e); + clickedIndex = this.applyFilters('clickedIndex', clickedIndex, e, this); + /** @type {DataSource} */ + const dataSource = { + gallery: /** @type {HTMLElement} */ (e.currentTarget) + }; + + if (clickedIndex >= 0) { + e.preventDefault(); + this.loadAndOpen(clickedIndex, dataSource, initialPoint); + } + } + + /** + * Get index of gallery item that was clicked. + * + * @param {MouseEvent} e click event + * @returns {number} + */ + getClickedIndex(e) { + // legacy option + if (this.options.getClickedIndexFn) { + return this.options.getClickedIndexFn.call(this, e); + } + + const clickedTarget = /** @type {HTMLElement} */ (e.target); + const childElements = getElementsFromOption( + this.options.children, + this.options.childSelector, + /** @type {HTMLElement} */ (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 {number} index + * @param {DataSource} dataSource + * @param {Point | null} [initialPoint] + * @returns {boolean} + */ + 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 {number} index + * @param {DataSource} [dataSource] + */ + preload(index, dataSource) { + const { options } = this; + + if (dataSource) { + options.dataSource = dataSource; + } + + // Add the main module + /** @type {Promise>[]} */ + const promiseArray = []; + + const pswpModuleType = typeof options.pswpModule; + if (isPswpClass(options.pswpModule)) { + promiseArray.push(Promise.resolve(/** @type {Type} */ (options.pswpModule))); + } else if (pswpModuleType === 'string') { + throw new Error('pswpModule as string is no longer supported'); + } else if (pswpModuleType === 'function') { + promiseArray.push(/** @type {() => Promise>} */ (options.pswpModule)()); + } else { + throw new Error('pswpModule is not valid'); + } + + // 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) { + this._preloadedContent = 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); + } + }); + } + + /** + * @private + * @param {Type | { default: Type }} module + * @param {number} 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 + * + * @type {PhotoSwipe} + */ + const pswp = typeof module === 'object' + ? new module.default(this.options) // eslint-disable-line + : new module(this.options); // eslint-disable-line + + this.pswp = pswp; + window.pswp = pswp; + + // map listeners from Lightbox to PhotoSwipe Core + /** @type {(keyof PhotoSwipeEventsMap)[]} */ + (Object.keys(this._listeners)).forEach((name) => { + this._listeners[name]?.forEach((fn) => { + pswp.on(name, /** @type {EventCallback} */(fn)); + }); + }); + + // same with filters + /** @type {(keyof PhotoSwipeFiltersMap)[]} */ + (Object.keys(this._filters)).forEach((name) => { + this._filters[name]?.forEach((filter) => { + pswp.addFilter(name, filter.fn, filter.priority); + }); + }); + + if (this._preloadedContent) { + pswp.contentLoader.addToCache(this._preloadedContent); + this._preloadedContent = undefined; + } + + pswp.on('destroy', () => { + // clean up public variables + this.pswp = undefined; + delete window.pswp; + }); + + pswp.init(); + } + + /** + * Unbinds all events, closes PhotoSwipe if it's open. + */ + destroy() { + this.pswp?.destroy(); + + this.shouldOpen = false; + this._listeners = {}; + + getElementsFromOption(this.options.gallery, this.options.gallerySelector) + .forEach((galleryElement) => { + galleryElement.removeEventListener('click', this.onThumbnailsClick, false); + }); + } +} + +module.exports = PhotoSwipeLightbox; +//# sourceMappingURL=photoswipe-lightbox.cjs.map diff --git a/dist/cjs/photoswipe-lightbox.cjs.map b/dist/cjs/photoswipe-lightbox.cjs.map new file mode 100644 index 000000000..b89f9a6e4 --- /dev/null +++ b/dist/cjs/photoswipe-lightbox.cjs.map @@ -0,0 +1 @@ +{"version":3,"file":"photoswipe-lightbox.cjs","sources":["../../../../src/js/util/util.js","../../../../src/js/core/eventable.js","../../../../src/js/slide/placeholder.js","../../../../src/js/slide/content.js","../../../../src/js/util/viewport-size.js","../../../../src/js/slide/zoom-level.js","../../../../src/js/slide/loader.js","../../../../src/js/core/base.js","../../../../src/js/lightbox/lightbox.js"],"sourcesContent":["/** @typedef {import('../photoswipe.js').Point} Point */\n\n/**\n * @template {keyof HTMLElementTagNameMap} T\n * @param {string} className\n * @param {T} tagName\n * @param {Node} [appendToEl]\n * @returns {HTMLElementTagNameMap[T]}\n */\nexport function createElement(className, tagName, appendToEl) {\n const el = document.createElement(tagName);\n if (className) {\n el.className = className;\n }\n if (appendToEl) {\n appendToEl.appendChild(el);\n }\n return el;\n}\n\n/**\n * @param {Point} p1\n * @param {Point} p2\n * @returns {Point}\n */\nexport function equalizePoints(p1, p2) {\n p1.x = p2.x;\n p1.y = p2.y;\n if (p2.id !== undefined) {\n p1.id = p2.id;\n }\n return p1;\n}\n\n/**\n * @param {Point} p\n */\nexport function roundPoint(p) {\n p.x = Math.round(p.x);\n p.y = Math.round(p.y);\n}\n\n/**\n * Returns distance between two points.\n *\n * @param {Point} p1\n * @param {Point} p2\n * @returns {number}\n */\nexport function getDistanceBetween(p1, p2) {\n const x = Math.abs(p1.x - p2.x);\n const y = Math.abs(p1.y - p2.y);\n return Math.sqrt((x * x) + (y * y));\n}\n\n/**\n * Whether X and Y positions of points are equal\n *\n * @param {Point} p1\n * @param {Point} p2\n * @returns {boolean}\n */\nexport function pointsEqual(p1, p2) {\n return p1.x === p2.x && p1.y === p2.y;\n}\n\n/**\n * The float result between the min and max values.\n *\n * @param {number} val\n * @param {number} min\n * @param {number} max\n * @returns {number}\n */\nexport function clamp(val, min, max) {\n return Math.min(Math.max(val, min), max);\n}\n\n/**\n * Get transform string\n *\n * @param {number} x\n * @param {number} [y]\n * @param {number} [scale]\n * @returns {string}\n */\nexport function toTransformString(x, y, scale) {\n let propValue = `translate3d(${x}px,${y || 0}px,0)`;\n\n if (scale !== undefined) {\n propValue += ` scale3d(${scale},${scale},1)`;\n }\n\n return propValue;\n}\n\n/**\n * Apply transform:translate(x, y) scale(scale) to element\n *\n * @param {HTMLElement} el\n * @param {number} x\n * @param {number} [y]\n * @param {number} [scale]\n */\nexport function setTransform(el, x, y, scale) {\n el.style.transform = toTransformString(x, y, scale);\n}\n\nconst defaultCSSEasing = 'cubic-bezier(.4,0,.22,1)';\n\n/**\n * Apply CSS transition to element\n *\n * @param {HTMLElement} el\n * @param {string} [prop] CSS property to animate\n * @param {number} [duration] in ms\n * @param {string} [ease] CSS easing function\n */\nexport function setTransitionStyle(el, prop, duration, ease) {\n // inOut: 'cubic-bezier(.4, 0, .22, 1)', // for \"toggle state\" transitions\n // out: 'cubic-bezier(0, 0, .22, 1)', // for \"show\" transitions\n // in: 'cubic-bezier(.4, 0, 1, 1)'// for \"hide\" transitions\n el.style.transition = prop\n ? `${prop} ${duration}ms ${ease || defaultCSSEasing}`\n : 'none';\n}\n\n/**\n * Apply width and height CSS properties to element\n *\n * @param {HTMLElement} el\n * @param {string | number} w\n * @param {string | number} h\n */\nexport function setWidthHeight(el, w, h) {\n el.style.width = (typeof w === 'number') ? `${w}px` : w;\n el.style.height = (typeof h === 'number') ? `${h}px` : h;\n}\n\n/**\n * @param {HTMLElement} el\n */\nexport function removeTransitionStyle(el) {\n setTransitionStyle(el);\n}\n\n/**\n * @param {HTMLImageElement} img\n * @returns {Promise}\n */\nexport function decodeImage(img) {\n if ('decode' in img) {\n return img.decode().catch(() => {});\n }\n\n if (img.complete) {\n return Promise.resolve(img);\n }\n\n return new Promise((resolve, reject) => {\n img.onload = () => resolve(img);\n img.onerror = reject;\n });\n}\n\n/** @typedef {LOAD_STATE[keyof LOAD_STATE]} LoadState */\n/** @type {{ IDLE: 'idle'; LOADING: 'loading'; LOADED: 'loaded'; ERROR: 'error' }} */\nexport const LOAD_STATE = {\n IDLE: 'idle',\n LOADING: 'loading',\n LOADED: 'loaded',\n ERROR: 'error',\n};\n\n\n/**\n * Check if click or keydown event was dispatched\n * with a special key or via mouse wheel.\n *\n * @param {MouseEvent | KeyboardEvent} e\n * @returns {boolean}\n */\nexport function specialKeyUsed(e) {\n return ('button' in e && e.button === 1) || e.ctrlKey || e.metaKey || e.altKey || e.shiftKey;\n}\n\n/**\n * Parse `gallery` or `children` options.\n *\n * @param {import('../photoswipe.js').ElementProvider} [option]\n * @param {string} [legacySelector]\n * @param {HTMLElement | Document} [parent]\n * @returns HTMLElement[]\n */\nexport function getElementsFromOption(option, legacySelector, parent = document) {\n /** @type {HTMLElement[]} */\n let elements = [];\n\n if (option instanceof Element) {\n elements = [option];\n } else if (option instanceof NodeList || Array.isArray(option)) {\n elements = Array.from(option);\n } else {\n const selector = typeof option === 'string' ? option : legacySelector;\n if (selector) {\n elements = Array.from(parent.querySelectorAll(selector));\n }\n }\n\n return elements;\n}\n\n/**\n * Check if variable is PhotoSwipe class\n *\n * @param {any} fn\n * @returns {boolean}\n */\nexport function isPswpClass(fn) {\n return typeof fn === 'function'\n && fn.prototype\n && fn.prototype.goTo;\n}\n\n/**\n * Check if browser is Safari\n *\n * @returns {boolean}\n */\nexport function isSafari() {\n return !!(navigator.vendor && navigator.vendor.match(/apple/i));\n}\n\n","/** @typedef {import('../lightbox/lightbox.js').default} PhotoSwipeLightbox */\n/** @typedef {import('../photoswipe.js').default} PhotoSwipe */\n/** @typedef {import('../photoswipe.js').PhotoSwipeOptions} PhotoSwipeOptions */\n/** @typedef {import('../photoswipe.js').DataSource} DataSource */\n/** @typedef {import('../ui/ui-element.js').UIElementData} UIElementData */\n/** @typedef {import('../slide/content.js').default} ContentDefault */\n/** @typedef {import('../slide/slide.js').default} Slide */\n/** @typedef {import('../slide/slide.js').SlideData} SlideData */\n/** @typedef {import('../slide/zoom-level.js').default} ZoomLevel */\n/** @typedef {import('../slide/get-thumb-bounds.js').Bounds} Bounds */\n\n/**\n * Allow adding an arbitrary props to the Content\n * https://photoswipe.com/custom-content/#using-webp-image-format\n * @typedef {ContentDefault & Record} Content\n */\n/** @typedef {{ x?: number; y?: number }} Point */\n\n/**\n * @typedef {Object} PhotoSwipeEventsMap https://photoswipe.com/events/\n *\n *\n * https://photoswipe.com/adding-ui-elements/\n *\n * @prop {undefined} uiRegister\n * @prop {{ data: UIElementData }} uiElementCreate\n *\n *\n * https://photoswipe.com/events/#initialization-events\n *\n * @prop {undefined} beforeOpen\n * @prop {undefined} firstUpdate\n * @prop {undefined} initialLayout\n * @prop {undefined} change\n * @prop {undefined} afterInit\n * @prop {undefined} bindEvents\n *\n *\n * https://photoswipe.com/events/#opening-or-closing-transition-events\n *\n * @prop {undefined} openingAnimationStart\n * @prop {undefined} openingAnimationEnd\n * @prop {undefined} closingAnimationStart\n * @prop {undefined} closingAnimationEnd\n *\n *\n * https://photoswipe.com/events/#closing-events\n *\n * @prop {undefined} close\n * @prop {undefined} destroy\n *\n *\n * https://photoswipe.com/events/#pointer-and-gesture-events\n *\n * @prop {{ originalEvent: PointerEvent }} pointerDown\n * @prop {{ originalEvent: PointerEvent }} pointerMove\n * @prop {{ originalEvent: PointerEvent }} pointerUp\n * @prop {{ bgOpacity: number }} pinchClose can be default prevented\n * @prop {{ panY: number }} verticalDrag can be default prevented\n *\n *\n * https://photoswipe.com/events/#slide-content-events\n *\n * @prop {{ content: Content }} contentInit\n * @prop {{ content: Content; isLazy: boolean }} contentLoad can be default prevented\n * @prop {{ content: Content; isLazy: boolean }} contentLoadImage can be default prevented\n * @prop {{ content: Content; slide: Slide; isError?: boolean }} loadComplete\n * @prop {{ content: Content; slide: Slide }} loadError\n * @prop {{ content: Content; width: number; height: number }} contentResize can be default prevented\n * @prop {{ content: Content; width: number; height: number; slide: Slide }} imageSizeChange\n * @prop {{ content: Content }} contentLazyLoad can be default prevented\n * @prop {{ content: Content }} contentAppend can be default prevented\n * @prop {{ content: Content }} contentActivate can be default prevented\n * @prop {{ content: Content }} contentDeactivate can be default prevented\n * @prop {{ content: Content }} contentRemove can be default prevented\n * @prop {{ content: Content }} contentDestroy can be default prevented\n *\n *\n * undocumented\n *\n * @prop {{ point: Point; originalEvent: PointerEvent }} imageClickAction can be default prevented\n * @prop {{ point: Point; originalEvent: PointerEvent }} bgClickAction can be default prevented\n * @prop {{ point: Point; originalEvent: PointerEvent }} tapAction can be default prevented\n * @prop {{ point: Point; originalEvent: PointerEvent }} doubleTapAction can be default prevented\n *\n * @prop {{ originalEvent: KeyboardEvent }} keydown can be default prevented\n * @prop {{ x: number; dragging: boolean }} moveMainScroll\n * @prop {{ slide: Slide }} firstZoomPan\n * @prop {{ slide: Slide | undefined, data: SlideData, index: number }} gettingData\n * @prop {undefined} beforeResize\n * @prop {undefined} resize\n * @prop {undefined} viewportSize\n * @prop {undefined} updateScrollOffset\n * @prop {{ slide: Slide }} slideInit\n * @prop {{ slide: Slide }} afterSetContent\n * @prop {{ slide: Slide }} slideLoad\n * @prop {{ slide: Slide }} appendHeavy can be default prevented\n * @prop {{ slide: Slide }} appendHeavyContent\n * @prop {{ slide: Slide }} slideActivate\n * @prop {{ slide: Slide }} slideDeactivate\n * @prop {{ slide: Slide }} slideDestroy\n * @prop {{ destZoomLevel: number, centerPoint: Point | undefined, transitionDuration: number | false | undefined }} beforeZoomTo\n * @prop {{ slide: Slide }} zoomPanUpdate\n * @prop {{ slide: Slide }} initialZoomPan\n * @prop {{ slide: Slide }} calcSlideSize\n * @prop {undefined} resolutionChanged\n * @prop {{ originalEvent: WheelEvent }} wheel can be default prevented\n * @prop {{ content: Content }} contentAppendImage can be default prevented\n * @prop {{ index: number; itemData: SlideData }} lazyLoadSlide can be default prevented\n * @prop {undefined} lazyLoad\n * @prop {{ slide: Slide }} calcBounds\n * @prop {{ zoomLevels: ZoomLevel, slideData: SlideData }} zoomLevelsUpdate\n *\n *\n * legacy\n *\n * @prop {undefined} init\n * @prop {undefined} initialZoomIn\n * @prop {undefined} initialZoomOut\n * @prop {undefined} initialZoomInEnd\n * @prop {undefined} initialZoomOutEnd\n * @prop {{ dataSource: DataSource | undefined, numItems: number }} numItems\n * @prop {{ itemData: SlideData; index: number }} itemData\n * @prop {{ index: number, itemData: SlideData, instance: PhotoSwipe }} thumbBounds\n */\n\n/**\n * @typedef {Object} PhotoSwipeFiltersMap https://photoswipe.com/filters/\n *\n * @prop {(numItems: number, dataSource: DataSource | undefined) => number} numItems\n * Modify the total amount of slides. Example on Data sources page.\n * https://photoswipe.com/filters/#numitems\n *\n * @prop {(itemData: SlideData, index: number) => SlideData} itemData\n * Modify slide item data. Example on Data sources page.\n * https://photoswipe.com/filters/#itemdata\n *\n * @prop {(itemData: SlideData, element: HTMLElement, linkEl: HTMLAnchorElement) => SlideData} domItemData\n * Modify item data when it's parsed from DOM element. Example on Data sources page.\n * https://photoswipe.com/filters/#domitemdata\n *\n * @prop {(clickedIndex: number, e: MouseEvent, instance: PhotoSwipeLightbox) => number} clickedIndex\n * Modify clicked gallery item index.\n * https://photoswipe.com/filters/#clickedindex\n *\n * @prop {(placeholderSrc: string | false, content: Content) => string | false} placeholderSrc\n * Modify placeholder image source.\n * https://photoswipe.com/filters/#placeholdersrc\n *\n * @prop {(isContentLoading: boolean, content: Content) => boolean} isContentLoading\n * Modify if the content is currently loading.\n * https://photoswipe.com/filters/#iscontentloading\n *\n * @prop {(isContentZoomable: boolean, content: Content) => boolean} isContentZoomable\n * Modify if the content can be zoomed.\n * https://photoswipe.com/filters/#iscontentzoomable\n *\n * @prop {(useContentPlaceholder: boolean, content: Content) => boolean} useContentPlaceholder\n * Modify if the placeholder should be used for the content.\n * https://photoswipe.com/filters/#usecontentplaceholder\n *\n * @prop {(isKeepingPlaceholder: boolean, content: Content) => boolean} isKeepingPlaceholder\n * Modify if the placeholder should be kept after the content is loaded.\n * https://photoswipe.com/filters/#iskeepingplaceholder\n *\n *\n * @prop {(contentErrorElement: HTMLElement, content: Content) => HTMLElement} contentErrorElement\n * Modify an element when the content has error state (for example, if image cannot be loaded).\n * https://photoswipe.com/filters/#contenterrorelement\n *\n * @prop {(element: HTMLElement, data: UIElementData) => HTMLElement} uiElement\n * Modify a UI element that's being created.\n * https://photoswipe.com/filters/#uielement\n *\n * @prop {(thumbnail: HTMLElement | null | undefined, itemData: SlideData, index: number) => HTMLElement} thumbEl\n * Modify the thubmnail element from which opening zoom animation starts or ends.\n * https://photoswipe.com/filters/#thumbel\n *\n * @prop {(thumbBounds: Bounds | undefined, itemData: SlideData, index: number) => Bounds} thumbBounds\n * Modify the thubmnail bounds from which opening zoom animation starts or ends.\n * https://photoswipe.com/filters/#thumbbounds\n *\n * @prop {(srcsetSizesWidth: number, content: Content) => number} srcsetSizesWidth\n *\n */\n\n/**\n * @template {keyof PhotoSwipeFiltersMap} T\n * @typedef {{ fn: PhotoSwipeFiltersMap[T], priority: number }} Filter\n */\n\n/**\n * @template {keyof PhotoSwipeEventsMap} T\n * @typedef {PhotoSwipeEventsMap[T] extends undefined ? PhotoSwipeEvent : PhotoSwipeEvent & PhotoSwipeEventsMap[T]} AugmentedEvent\n */\n\n/**\n * @template {keyof PhotoSwipeEventsMap} T\n * @typedef {(event: AugmentedEvent) => void} EventCallback\n */\n\n/**\n * Base PhotoSwipe event object\n *\n * @template {keyof PhotoSwipeEventsMap} T\n */\nclass PhotoSwipeEvent {\n /**\n * @param {T} type\n * @param {PhotoSwipeEventsMap[T]} [details]\n */\n constructor(type, details) {\n this.type = type;\n this.defaultPrevented = false;\n if (details) {\n Object.assign(this, details);\n }\n }\n\n preventDefault() {\n this.defaultPrevented = true;\n }\n}\n\n/**\n * PhotoSwipe base class that can listen and dispatch for events.\n * Shared by PhotoSwipe Core and PhotoSwipe Lightbox, extended by base.js\n */\nclass Eventable {\n constructor() {\n /**\n * @type {{ [T in keyof PhotoSwipeEventsMap]?: ((event: AugmentedEvent) => void)[] }}\n */\n this._listeners = {};\n\n /**\n * @type {{ [T in keyof PhotoSwipeFiltersMap]?: Filter[] }}\n */\n this._filters = {};\n\n /** @type {PhotoSwipe | undefined} */\n this.pswp = undefined;\n\n /** @type {PhotoSwipeOptions | undefined} */\n this.options = undefined;\n }\n\n /**\n * @template {keyof PhotoSwipeFiltersMap} T\n * @param {T} name\n * @param {PhotoSwipeFiltersMap[T]} fn\n * @param {number} priority\n */\n addFilter(name, fn, priority = 100) {\n if (!this._filters[name]) {\n this._filters[name] = [];\n }\n\n this._filters[name]?.push({ fn, priority });\n this._filters[name]?.sort((f1, f2) => f1.priority - f2.priority);\n\n this.pswp?.addFilter(name, fn, priority);\n }\n\n /**\n * @template {keyof PhotoSwipeFiltersMap} T\n * @param {T} name\n * @param {PhotoSwipeFiltersMap[T]} fn\n */\n removeFilter(name, fn) {\n if (this._filters[name]) {\n // @ts-expect-error\n this._filters[name] = this._filters[name].filter(filter => (filter.fn !== fn));\n }\n\n if (this.pswp) {\n this.pswp.removeFilter(name, fn);\n }\n }\n\n /**\n * @template {keyof PhotoSwipeFiltersMap} T\n * @param {T} name\n * @param {Parameters} args\n * @returns {Parameters[0]}\n */\n applyFilters(name, ...args) {\n this._filters[name]?.forEach((filter) => {\n // @ts-expect-error\n args[0] = filter.fn.apply(this, args);\n });\n return args[0];\n }\n\n /**\n * @template {keyof PhotoSwipeEventsMap} T\n * @param {T} name\n * @param {EventCallback} fn\n */\n on(name, fn) {\n if (!this._listeners[name]) {\n this._listeners[name] = [];\n }\n this._listeners[name]?.push(fn);\n\n // When binding events to lightbox,\n // also bind events to PhotoSwipe Core,\n // if it's open.\n this.pswp?.on(name, fn);\n }\n\n /**\n * @template {keyof PhotoSwipeEventsMap} T\n * @param {T} name\n * @param {EventCallback} fn\n */\n off(name, fn) {\n if (this._listeners[name]) {\n // @ts-expect-error\n this._listeners[name] = this._listeners[name].filter(listener => (fn !== listener));\n }\n\n this.pswp?.off(name, fn);\n }\n\n /**\n * @template {keyof PhotoSwipeEventsMap} T\n * @param {T} name\n * @param {PhotoSwipeEventsMap[T]} [details]\n * @returns {AugmentedEvent}\n */\n dispatch(name, details) {\n if (this.pswp) {\n return this.pswp.dispatch(name, details);\n }\n\n const event = /** @type {AugmentedEvent} */ (new PhotoSwipeEvent(name, details));\n\n this._listeners[name]?.forEach((listener) => {\n listener.call(this, event);\n });\n\n return event;\n }\n}\n\nexport default Eventable;\n","import { createElement, setWidthHeight, toTransformString } from '../util/util.js';\n\nclass Placeholder {\n /**\n * @param {string | false} imageSrc\n * @param {HTMLElement} container\n */\n constructor(imageSrc, container) {\n // Create placeholder\n // (stretched thumbnail or simple div behind the main image)\n /** @type {HTMLImageElement | HTMLDivElement | null} */\n this.element = createElement(\n 'pswp__img pswp__img--placeholder',\n imageSrc ? 'img' : 'div',\n container\n );\n\n if (imageSrc) {\n const imgEl = /** @type {HTMLImageElement} */ (this.element);\n imgEl.decoding = 'async';\n imgEl.alt = '';\n imgEl.src = imageSrc;\n imgEl.setAttribute('role', 'presentation');\n }\n\n this.element.setAttribute('aria-hidden', 'true');\n }\n\n /**\n * @param {number} width\n * @param {number} height\n */\n setDisplayedSize(width, height) {\n if (!this.element) {\n return;\n }\n\n if (this.element.tagName === 'IMG') {\n // Use transform scale() to modify img placeholder size\n // (instead of changing width/height directly).\n // This helps with performance, specifically in iOS15 Safari.\n setWidthHeight(this.element, 250, 'auto');\n this.element.style.transformOrigin = '0 0';\n this.element.style.transform = toTransformString(0, 0, width / 250);\n } else {\n setWidthHeight(this.element, width, height);\n }\n }\n\n destroy() {\n if (this.element?.parentNode) {\n this.element.remove();\n }\n this.element = null;\n }\n}\n\nexport default Placeholder;\n","import { createElement, isSafari, LOAD_STATE, setWidthHeight } from '../util/util.js';\nimport Placeholder from './placeholder.js';\n\n/** @typedef {import('./slide.js').default} Slide */\n/** @typedef {import('./slide.js').SlideData} SlideData */\n/** @typedef {import('../core/base.js').default} PhotoSwipeBase */\n/** @typedef {import('../util/util.js').LoadState} LoadState */\n\nclass Content {\n /**\n * @param {SlideData} itemData Slide data\n * @param {PhotoSwipeBase} instance PhotoSwipe or PhotoSwipeLightbox instance\n * @param {number} index\n */\n constructor(itemData, instance, index) {\n this.instance = instance;\n this.data = itemData;\n this.index = index;\n\n /** @type {HTMLImageElement | HTMLDivElement | undefined} */\n this.element = undefined;\n /** @type {Placeholder | undefined} */\n this.placeholder = undefined;\n /** @type {Slide | undefined} */\n this.slide = undefined;\n\n this.displayedImageWidth = 0;\n this.displayedImageHeight = 0;\n\n this.width = Number(this.data.w) || Number(this.data.width) || 0;\n this.height = Number(this.data.h) || Number(this.data.height) || 0;\n\n this.isAttached = false;\n this.hasSlide = false;\n this.isDecoding = false;\n /** @type {LoadState} */\n this.state = LOAD_STATE.IDLE;\n\n if (this.data.type) {\n this.type = this.data.type;\n } else if (this.data.src) {\n this.type = 'image';\n } else {\n this.type = 'html';\n }\n\n this.instance.dispatch('contentInit', { content: this });\n }\n\n removePlaceholder() {\n if (this.placeholder && !this.keepPlaceholder()) {\n // With delay, as image might be loaded, but not rendered\n setTimeout(() => {\n if (this.placeholder) {\n this.placeholder.destroy();\n this.placeholder = undefined;\n }\n }, 1000);\n }\n }\n\n /**\n * Preload content\n *\n * @param {boolean} isLazy\n * @param {boolean} [reload]\n */\n load(isLazy, reload) {\n if (this.slide && this.usePlaceholder()) {\n if (!this.placeholder) {\n const placeholderSrc = this.instance.applyFilters(\n 'placeholderSrc',\n // use image-based placeholder only for the first slide,\n // as rendering (even small stretched thumbnail) is an expensive operation\n (this.data.msrc && this.slide.isFirstSlide) ? this.data.msrc : false,\n this\n );\n this.placeholder = new Placeholder(\n placeholderSrc,\n this.slide.container\n );\n } else {\n const placeholderEl = this.placeholder.element;\n // Add placeholder to DOM if it was already created\n if (placeholderEl && !placeholderEl.parentElement) {\n this.slide.container.prepend(placeholderEl);\n }\n }\n }\n\n if (this.element && !reload) {\n return;\n }\n\n if (this.instance.dispatch('contentLoad', { content: this, isLazy }).defaultPrevented) {\n return;\n }\n\n if (this.isImageContent()) {\n this.element = createElement('pswp__img', 'img');\n // Start loading only after width is defined, as sizes might depend on it.\n // Due to Safari feature, we must define sizes before srcset.\n if (this.displayedImageWidth) {\n this.loadImage(isLazy);\n }\n } else {\n this.element = createElement('pswp__content', 'div');\n this.element.innerHTML = this.data.html || '';\n }\n\n if (reload && this.slide) {\n this.slide.updateContentSize(true);\n }\n }\n\n /**\n * Preload image\n *\n * @param {boolean} isLazy\n */\n loadImage(isLazy) {\n if (!this.isImageContent()\n || !this.element\n || this.instance.dispatch('contentLoadImage', { content: this, isLazy }).defaultPrevented) {\n return;\n }\n\n const imageElement = /** @type HTMLImageElement */ (this.element);\n\n this.updateSrcsetSizes();\n\n if (this.data.srcset) {\n imageElement.srcset = this.data.srcset;\n }\n\n imageElement.src = this.data.src ?? '';\n imageElement.alt = this.data.alt ?? '';\n\n this.state = LOAD_STATE.LOADING;\n\n if (imageElement.complete) {\n this.onLoaded();\n } else {\n imageElement.onload = () => {\n this.onLoaded();\n };\n\n imageElement.onerror = () => {\n this.onError();\n };\n }\n }\n\n /**\n * Assign slide to content\n *\n * @param {Slide} slide\n */\n setSlide(slide) {\n this.slide = slide;\n this.hasSlide = true;\n this.instance = slide.pswp;\n\n // todo: do we need to unset slide?\n }\n\n /**\n * Content load success handler\n */\n onLoaded() {\n this.state = LOAD_STATE.LOADED;\n\n if (this.slide && this.element) {\n this.instance.dispatch('loadComplete', { slide: this.slide, content: this });\n\n // if content is reloaded\n if (this.slide.isActive\n && this.slide.heavyAppended\n && !this.element.parentNode) {\n this.append();\n this.slide.updateContentSize(true);\n }\n\n if (this.state === LOAD_STATE.LOADED || this.state === LOAD_STATE.ERROR) {\n this.removePlaceholder();\n }\n }\n }\n\n /**\n * Content load error handler\n */\n onError() {\n this.state = LOAD_STATE.ERROR;\n\n if (this.slide) {\n this.displayError();\n this.instance.dispatch('loadComplete', { slide: this.slide, isError: true, content: this });\n this.instance.dispatch('loadError', { slide: this.slide, content: this });\n }\n }\n\n /**\n * @returns {Boolean} If the content is currently loading\n */\n isLoading() {\n return this.instance.applyFilters(\n 'isContentLoading',\n this.state === LOAD_STATE.LOADING,\n this\n );\n }\n\n /**\n * @returns {Boolean} If the content is in error state\n */\n isError() {\n return this.state === LOAD_STATE.ERROR;\n }\n\n /**\n * @returns {boolean} If the content is image\n */\n isImageContent() {\n return this.type === 'image';\n }\n\n /**\n * Update content size\n *\n * @param {Number} width\n * @param {Number} height\n */\n setDisplayedSize(width, height) {\n if (!this.element) {\n return;\n }\n\n if (this.placeholder) {\n this.placeholder.setDisplayedSize(width, height);\n }\n\n if (this.instance.dispatch(\n 'contentResize',\n { content: this, width, height }).defaultPrevented\n ) {\n return;\n }\n\n setWidthHeight(this.element, width, height);\n\n if (this.isImageContent() && !this.isError()) {\n const isInitialSizeUpdate = (!this.displayedImageWidth && width);\n\n this.displayedImageWidth = width;\n this.displayedImageHeight = height;\n\n if (isInitialSizeUpdate) {\n this.loadImage(false);\n } else {\n this.updateSrcsetSizes();\n }\n\n if (this.slide) {\n this.instance.dispatch(\n 'imageSizeChange',\n { slide: this.slide, width, height, content: this }\n );\n }\n }\n }\n\n /**\n * @returns {boolean} If the content can be zoomed\n */\n isZoomable() {\n return this.instance.applyFilters(\n 'isContentZoomable',\n this.isImageContent() && (this.state !== LOAD_STATE.ERROR),\n this\n );\n }\n\n /**\n * Update image srcset sizes attribute based on width and height\n */\n updateSrcsetSizes() {\n // Handle srcset sizes attribute.\n //\n // Never lower quality, if it was increased previously.\n // Chrome does this automatically, Firefox and Safari do not,\n // so we store largest used size in dataset.\n if (!this.isImageContent() || !this.element || !this.data.srcset) {\n return;\n }\n\n const image = /** @type HTMLImageElement */ (this.element);\n const sizesWidth = this.instance.applyFilters(\n 'srcsetSizesWidth',\n this.displayedImageWidth,\n this\n );\n\n if (\n !image.dataset.largestUsedSize\n || sizesWidth > parseInt(image.dataset.largestUsedSize, 10)\n ) {\n image.sizes = sizesWidth + 'px';\n image.dataset.largestUsedSize = String(sizesWidth);\n }\n }\n\n /**\n * @returns {boolean} If content should use a placeholder (from msrc by default)\n */\n usePlaceholder() {\n return this.instance.applyFilters(\n 'useContentPlaceholder',\n this.isImageContent(),\n this\n );\n }\n\n /**\n * Preload content with lazy-loading param\n */\n lazyLoad() {\n if (this.instance.dispatch('contentLazyLoad', { content: this }).defaultPrevented) {\n return;\n }\n\n this.load(true);\n }\n\n /**\n * @returns {boolean} If placeholder should be kept after content is loaded\n */\n keepPlaceholder() {\n return this.instance.applyFilters(\n 'isKeepingPlaceholder',\n this.isLoading(),\n this\n );\n }\n\n /**\n * Destroy the content\n */\n destroy() {\n this.hasSlide = false;\n this.slide = undefined;\n\n if (this.instance.dispatch('contentDestroy', { content: this }).defaultPrevented) {\n return;\n }\n\n this.remove();\n\n if (this.placeholder) {\n this.placeholder.destroy();\n this.placeholder = undefined;\n }\n\n if (this.isImageContent() && this.element) {\n this.element.onload = null;\n this.element.onerror = null;\n this.element = undefined;\n }\n }\n\n /**\n * Display error message\n */\n displayError() {\n if (this.slide) {\n let errorMsgEl = createElement('pswp__error-msg', 'div');\n errorMsgEl.innerText = this.instance.options?.errorMsg ?? '';\n errorMsgEl = /** @type {HTMLDivElement} */ (this.instance.applyFilters(\n 'contentErrorElement',\n errorMsgEl,\n this\n ));\n this.element = createElement('pswp__content pswp__error-msg-container', 'div');\n this.element.appendChild(errorMsgEl);\n this.slide.container.innerText = '';\n this.slide.container.appendChild(this.element);\n this.slide.updateContentSize(true);\n this.removePlaceholder();\n }\n }\n\n /**\n * Append the content\n */\n append() {\n if (this.isAttached || !this.element) {\n return;\n }\n\n this.isAttached = true;\n\n if (this.state === LOAD_STATE.ERROR) {\n this.displayError();\n return;\n }\n\n if (this.instance.dispatch('contentAppend', { content: this }).defaultPrevented) {\n return;\n }\n\n const supportsDecode = ('decode' in this.element);\n\n if (this.isImageContent()) {\n // Use decode() on nearby slides\n //\n // Nearby slide images are in DOM and not hidden via display:none.\n // However, they are placed offscreen (to the left and right side).\n //\n // Some browsers do not composite the image until it's actually visible,\n // using decode() helps.\n //\n // You might ask \"why dont you just decode() and then append all images\",\n // that's because I want to show image before it's fully loaded,\n // as browser can render parts of image while it is loading.\n // We do not do this in Safari due to partial loading bug.\n if (supportsDecode && this.slide && (!this.slide.isActive || isSafari())) {\n this.isDecoding = true;\n // purposefully using finally instead of then,\n // as if srcset sizes changes dynamically - it may cause decode error\n /** @type {HTMLImageElement} */\n (this.element).decode().catch(() => {}).finally(() => {\n this.isDecoding = false;\n this.appendImage();\n });\n } else {\n this.appendImage();\n }\n } else if (this.slide && !this.element.parentNode) {\n this.slide.container.appendChild(this.element);\n }\n }\n\n /**\n * Activate the slide,\n * active slide is generally the current one,\n * meaning the user can see it.\n */\n activate() {\n if (this.instance.dispatch('contentActivate', { content: this }).defaultPrevented\n || !this.slide) {\n return;\n }\n\n if (this.isImageContent() && this.isDecoding && !isSafari()) {\n // add image to slide when it becomes active,\n // even if it's not finished decoding\n this.appendImage();\n } else if (this.isError()) {\n this.load(false, true); // try to reload\n }\n\n if (this.slide.holderElement) {\n this.slide.holderElement.setAttribute('aria-hidden', 'false');\n }\n }\n\n /**\n * Deactivate the content\n */\n deactivate() {\n this.instance.dispatch('contentDeactivate', { content: this });\n if (this.slide && this.slide.holderElement) {\n this.slide.holderElement.setAttribute('aria-hidden', 'true');\n }\n }\n\n\n /**\n * Remove the content from DOM\n */\n remove() {\n this.isAttached = false;\n\n if (this.instance.dispatch('contentRemove', { content: this }).defaultPrevented) {\n return;\n }\n\n if (this.element && this.element.parentNode) {\n this.element.remove();\n }\n\n if (this.placeholder && this.placeholder.element) {\n this.placeholder.element.remove();\n }\n }\n\n /**\n * Append the image content to slide container\n */\n appendImage() {\n if (!this.isAttached) {\n return;\n }\n\n if (this.instance.dispatch('contentAppendImage', { content: this }).defaultPrevented) {\n return;\n }\n\n // ensure that element exists and is not already appended\n if (this.slide && this.element && !this.element.parentNode) {\n this.slide.container.appendChild(this.element);\n }\n\n if (this.state === LOAD_STATE.LOADED || this.state === LOAD_STATE.ERROR) {\n this.removePlaceholder();\n }\n }\n}\n\nexport default Content;\n","/** @typedef {import('../photoswipe.js').PhotoSwipeOptions} PhotoSwipeOptions */\n/** @typedef {import('../core/base.js').default} PhotoSwipeBase */\n/** @typedef {import('../photoswipe.js').Point} Point */\n/** @typedef {import('../slide/slide.js').SlideData} SlideData */\n\n/**\n * @param {PhotoSwipeOptions} options\n * @param {PhotoSwipeBase} pswp\n * @returns {Point}\n */\nexport function getViewportSize(options, pswp) {\n if (options.getViewportSizeFn) {\n const newViewportSize = options.getViewportSizeFn(options, pswp);\n if (newViewportSize) {\n return newViewportSize;\n }\n }\n\n return {\n x: document.documentElement.clientWidth,\n\n // TODO: height on mobile is very incosistent due to toolbar\n // find a way to improve this\n //\n // document.documentElement.clientHeight - doesn't seem to work well\n y: window.innerHeight\n };\n}\n\n/**\n * Parses padding option.\n * Supported formats:\n *\n * // Object\n * padding: {\n * top: 0,\n * bottom: 0,\n * left: 0,\n * right: 0\n * }\n *\n * // A function that returns the object\n * paddingFn: (viewportSize, itemData, index) => {\n * return {\n * top: 0,\n * bottom: 0,\n * left: 0,\n * right: 0\n * };\n * }\n *\n * // Legacy variant\n * paddingLeft: 0,\n * paddingRight: 0,\n * paddingTop: 0,\n * paddingBottom: 0,\n *\n * @param {'left' | 'top' | 'bottom' | 'right'} prop\n * @param {PhotoSwipeOptions} options PhotoSwipe options\n * @param {Point} viewportSize PhotoSwipe viewport size, for example: { x:800, y:600 }\n * @param {SlideData} itemData Data about the slide\n * @param {number} index Slide index\n * @returns {number}\n */\nexport function parsePaddingOption(prop, options, viewportSize, itemData, index) {\n let paddingValue = 0;\n\n if (options.paddingFn) {\n paddingValue = options.paddingFn(viewportSize, itemData, index)[prop];\n } else if (options.padding) {\n paddingValue = options.padding[prop];\n } else {\n const legacyPropName = 'padding' + prop[0].toUpperCase() + prop.slice(1);\n // @ts-expect-error\n if (options[legacyPropName]) {\n // @ts-expect-error\n paddingValue = options[legacyPropName];\n }\n }\n\n return Number(paddingValue) || 0;\n}\n\n/**\n * @param {PhotoSwipeOptions} options\n * @param {Point} viewportSize\n * @param {SlideData} itemData\n * @param {number} index\n * @returns {Point}\n */\nexport function getPanAreaSize(options, viewportSize, itemData, index) {\n return {\n x: viewportSize.x\n - parsePaddingOption('left', options, viewportSize, itemData, index)\n - parsePaddingOption('right', options, viewportSize, itemData, index),\n y: viewportSize.y\n - parsePaddingOption('top', options, viewportSize, itemData, index)\n - parsePaddingOption('bottom', options, viewportSize, itemData, index)\n };\n}\n","const MAX_IMAGE_WIDTH = 4000;\n\n/** @typedef {import('../photoswipe.js').default} PhotoSwipe */\n/** @typedef {import('../photoswipe.js').PhotoSwipeOptions} PhotoSwipeOptions */\n/** @typedef {import('../photoswipe.js').Point} Point */\n/** @typedef {import('../slide/slide.js').SlideData} SlideData */\n\n/** @typedef {'fit' | 'fill' | number | ((zoomLevelObject: ZoomLevel) => number)} ZoomLevelOption */\n\n/**\n * Calculates zoom levels for specific slide.\n * Depends on viewport size and image size.\n */\nclass ZoomLevel {\n /**\n * @param {PhotoSwipeOptions} options PhotoSwipe options\n * @param {SlideData} itemData Slide data\n * @param {number} index Slide index\n * @param {PhotoSwipe} [pswp] PhotoSwipe instance, can be undefined if not initialized yet\n */\n constructor(options, itemData, index, pswp) {\n this.pswp = pswp;\n this.options = options;\n this.itemData = itemData;\n this.index = index;\n /** @type { Point | null } */\n this.panAreaSize = null;\n /** @type { Point | null } */\n this.elementSize = null;\n this.fit = 1;\n this.fill = 1;\n this.vFill = 1;\n this.initial = 1;\n this.secondary = 1;\n this.max = 1;\n this.min = 1;\n }\n\n /**\n * Calculate initial, secondary and maximum zoom level for the specified slide.\n *\n * It should be called when either image or viewport size changes.\n *\n * @param {number} maxWidth\n * @param {number} maxHeight\n * @param {Point} panAreaSize\n */\n update(maxWidth, maxHeight, panAreaSize) {\n /** @type {Point} */\n const elementSize = { x: maxWidth, y: maxHeight };\n this.elementSize = elementSize;\n this.panAreaSize = panAreaSize;\n\n const hRatio = panAreaSize.x / elementSize.x;\n const vRatio = panAreaSize.y / elementSize.y;\n\n this.fit = Math.min(1, hRatio < vRatio ? hRatio : vRatio);\n this.fill = Math.min(1, hRatio > vRatio ? hRatio : vRatio);\n\n // zoom.vFill defines zoom level of the image\n // when it has 100% of viewport vertical space (height)\n this.vFill = Math.min(1, vRatio);\n\n this.initial = this._getInitial();\n this.secondary = this._getSecondary();\n this.max = Math.max(\n this.initial,\n this.secondary,\n this._getMax()\n );\n\n this.min = Math.min(\n this.fit,\n this.initial,\n this.secondary\n );\n\n if (this.pswp) {\n this.pswp.dispatch('zoomLevelsUpdate', { zoomLevels: this, slideData: this.itemData });\n }\n }\n\n /**\n * Parses user-defined zoom option.\n *\n * @private\n * @param {'initial' | 'secondary' | 'max'} optionPrefix Zoom level option prefix (initial, secondary, max)\n * @returns { number | undefined }\n */\n _parseZoomLevelOption(optionPrefix) {\n const optionName = /** @type {'initialZoomLevel' | 'secondaryZoomLevel' | 'maxZoomLevel'} */ (\n optionPrefix + 'ZoomLevel'\n );\n const optionValue = this.options[optionName];\n\n if (!optionValue) {\n return;\n }\n\n if (typeof optionValue === 'function') {\n return optionValue(this);\n }\n\n if (optionValue === 'fill') {\n return this.fill;\n }\n\n if (optionValue === 'fit') {\n return this.fit;\n }\n\n return Number(optionValue);\n }\n\n /**\n * Get zoom level to which image will be zoomed after double-tap gesture,\n * or when user clicks on zoom icon,\n * or mouse-click on image itself.\n * If you return 1 image will be zoomed to its original size.\n *\n * @private\n * @return {number}\n */\n _getSecondary() {\n let currZoomLevel = this._parseZoomLevelOption('secondary');\n\n if (currZoomLevel) {\n return currZoomLevel;\n }\n\n // 3x of \"fit\" state, but not larger than original\n currZoomLevel = Math.min(1, this.fit * 3);\n\n if (this.elementSize && currZoomLevel * this.elementSize.x > MAX_IMAGE_WIDTH) {\n currZoomLevel = MAX_IMAGE_WIDTH / this.elementSize.x;\n }\n\n return currZoomLevel;\n }\n\n /**\n * Get initial image zoom level.\n *\n * @private\n * @return {number}\n */\n _getInitial() {\n return this._parseZoomLevelOption('initial') || this.fit;\n }\n\n /**\n * Maximum zoom level when user zooms\n * via zoom/pinch gesture,\n * via cmd/ctrl-wheel or via trackpad.\n *\n * @private\n * @return {number}\n */\n _getMax() {\n // max zoom level is x4 from \"fit state\",\n // used for zoom gesture and ctrl/trackpad zoom\n return this._parseZoomLevelOption('max') || Math.max(1, this.fit * 4);\n }\n}\n\nexport default ZoomLevel;\n","import { getViewportSize, getPanAreaSize } from '../util/viewport-size.js';\nimport ZoomLevel from './zoom-level.js';\n\n/** @typedef {import('./content.js').default} Content */\n/** @typedef {import('./slide.js').default} Slide */\n/** @typedef {import('./slide.js').SlideData} SlideData */\n/** @typedef {import('../core/base.js').default} PhotoSwipeBase */\n/** @typedef {import('../photoswipe.js').default} PhotoSwipe */\n\nconst MIN_SLIDES_TO_CACHE = 5;\n\n/**\n * Lazy-load an image\n * This function is used both by Lightbox and PhotoSwipe core,\n * thus it can be called before dialog is opened.\n *\n * @param {SlideData} itemData Data about the slide\n * @param {PhotoSwipeBase} instance PhotoSwipe or PhotoSwipeLightbox instance\n * @param {number} index\n * @returns {Content} Image that is being decoded or false.\n */\nexport function lazyLoadData(itemData, instance, index) {\n const content = instance.createContentFromData(itemData, index);\n /** @type {ZoomLevel | undefined} */\n let zoomLevel;\n\n const { options } = instance;\n\n // We need to know dimensions of the image to preload it,\n // as it might use srcset, and we need to define sizes\n if (options) {\n zoomLevel = new ZoomLevel(options, itemData, -1);\n\n let viewportSize;\n if (instance.pswp) {\n viewportSize = instance.pswp.viewportSize;\n } else {\n viewportSize = getViewportSize(options, instance);\n }\n\n const panAreaSize = getPanAreaSize(options, viewportSize, itemData, index);\n zoomLevel.update(content.width, content.height, panAreaSize);\n }\n\n content.lazyLoad();\n\n if (zoomLevel) {\n content.setDisplayedSize(\n Math.ceil(content.width * zoomLevel.initial),\n Math.ceil(content.height * zoomLevel.initial)\n );\n }\n\n return content;\n}\n\n\n/**\n * Lazy-loads specific slide.\n * This function is used both by Lightbox and PhotoSwipe core,\n * thus it can be called before dialog is opened.\n *\n * By default, it loads image based on viewport size and initial zoom level.\n *\n * @param {number} index Slide index\n * @param {PhotoSwipeBase} instance PhotoSwipe or PhotoSwipeLightbox eventable instance\n * @returns {Content | undefined}\n */\nexport function lazyLoadSlide(index, instance) {\n const itemData = instance.getItemData(index);\n\n if (instance.dispatch('lazyLoadSlide', { index, itemData }).defaultPrevented) {\n return;\n }\n\n return lazyLoadData(itemData, instance, index);\n}\n\nclass ContentLoader {\n /**\n * @param {PhotoSwipe} pswp\n */\n constructor(pswp) {\n this.pswp = pswp;\n // Total amount of cached images\n this.limit = Math.max(\n pswp.options.preload[0] + pswp.options.preload[1] + 1,\n MIN_SLIDES_TO_CACHE\n );\n /** @type {Content[]} */\n this._cachedItems = [];\n }\n\n /**\n * Lazy load nearby slides based on `preload` option.\n *\n * @param {number} [diff] Difference between slide indexes that was changed recently, or 0.\n */\n updateLazy(diff) {\n const { pswp } = this;\n\n if (pswp.dispatch('lazyLoad').defaultPrevented) {\n return;\n }\n\n const { preload } = pswp.options;\n const isForward = diff === undefined ? true : (diff >= 0);\n let i;\n\n // preload[1] - num items to preload in forward direction\n for (i = 0; i <= preload[1]; i++) {\n this.loadSlideByIndex(pswp.currIndex + (isForward ? i : (-i)));\n }\n\n // preload[0] - num items to preload in backward direction\n for (i = 1; i <= preload[0]; i++) {\n this.loadSlideByIndex(pswp.currIndex + (isForward ? (-i) : i));\n }\n }\n\n /**\n * @param {number} initialIndex\n */\n loadSlideByIndex(initialIndex) {\n const index = this.pswp.getLoopedIndex(initialIndex);\n // try to get cached content\n let content = this.getContentByIndex(index);\n if (!content) {\n // no cached content, so try to load from scratch:\n content = lazyLoadSlide(index, this.pswp);\n // if content can be loaded, add it to cache:\n if (content) {\n this.addToCache(content);\n }\n }\n }\n\n /**\n * @param {Slide} slide\n * @returns {Content}\n */\n getContentBySlide(slide) {\n let content = this.getContentByIndex(slide.index);\n if (!content) {\n // create content if not found in cache\n content = this.pswp.createContentFromData(slide.data, slide.index);\n this.addToCache(content);\n }\n\n // assign slide to content\n content.setSlide(slide);\n\n return content;\n }\n\n /**\n * @param {Content} content\n */\n addToCache(content) {\n // move to the end of array\n this.removeByIndex(content.index);\n this._cachedItems.push(content);\n\n if (this._cachedItems.length > this.limit) {\n // Destroy the first content that's not attached\n const indexToRemove = this._cachedItems.findIndex((item) => {\n return !item.isAttached && !item.hasSlide;\n });\n if (indexToRemove !== -1) {\n const removedItem = this._cachedItems.splice(indexToRemove, 1)[0];\n removedItem.destroy();\n }\n }\n }\n\n /**\n * Removes an image from cache, does not destroy() it, just removes.\n *\n * @param {number} index\n */\n removeByIndex(index) {\n const indexToRemove = this._cachedItems.findIndex(item => item.index === index);\n if (indexToRemove !== -1) {\n this._cachedItems.splice(indexToRemove, 1);\n }\n }\n\n /**\n * @param {number} index\n * @returns {Content | undefined}\n */\n getContentByIndex(index) {\n return this._cachedItems.find(content => content.index === index);\n }\n\n destroy() {\n this._cachedItems.forEach(content => content.destroy());\n this._cachedItems = [];\n }\n}\n\nexport default ContentLoader;\n","import Eventable from './eventable.js';\nimport { getElementsFromOption } from '../util/util.js';\nimport Content from '../slide/content.js';\nimport { lazyLoadData } from '../slide/loader.js';\n\n/** @typedef {import(\"../photoswipe.js\").default} PhotoSwipe */\n/** @typedef {import(\"../slide/slide.js\").SlideData} SlideData */\n\n/**\n * PhotoSwipe base class that can retrieve data about every slide.\n * Shared by PhotoSwipe Core and PhotoSwipe Lightbox\n */\nclass PhotoSwipeBase extends Eventable {\n /**\n * Get total number of slides\n *\n * @returns {number}\n */\n getNumItems() {\n let numItems = 0;\n const dataSource = this.options?.dataSource;\n\n if (dataSource && 'length' in dataSource) {\n // may be an array or just object with length property\n numItems = dataSource.length;\n } else if (dataSource && 'gallery' in dataSource) {\n // query DOM elements\n if (!dataSource.items) {\n dataSource.items = this._getGalleryDOMElements(dataSource.gallery);\n }\n\n if (dataSource.items) {\n numItems = dataSource.items.length;\n }\n }\n\n // legacy event, before filters were introduced\n const event = this.dispatch('numItems', {\n dataSource,\n numItems\n });\n return this.applyFilters('numItems', event.numItems, dataSource);\n }\n\n /**\n * @param {SlideData} slideData\n * @param {number} index\n * @returns {Content}\n */\n createContentFromData(slideData, index) {\n return new Content(slideData, this, index);\n }\n\n /**\n * Get item data by index.\n *\n * \"item data\" should contain normalized information that PhotoSwipe needs to generate a slide.\n * For example, it may contain properties like\n * `src`, `srcset`, `w`, `h`, which will be used to generate a slide with image.\n *\n * @param {number} index\n * @returns {SlideData}\n */\n getItemData(index) {\n const dataSource = this.options?.dataSource;\n /** @type {SlideData | HTMLElement} */\n let dataSourceItem = {};\n if (Array.isArray(dataSource)) {\n // Datasource is an array of elements\n dataSourceItem = dataSource[index];\n } else if (dataSource && 'gallery' in dataSource) {\n // dataSource has gallery property,\n // thus it was created by Lightbox, based on\n // gallery and children options\n\n // query DOM elements\n if (!dataSource.items) {\n dataSource.items = this._getGalleryDOMElements(dataSource.gallery);\n }\n\n dataSourceItem = dataSource.items[index];\n }\n\n let itemData = dataSourceItem;\n\n if (itemData instanceof Element) {\n itemData = this._domElementToItemData(itemData);\n }\n\n // Dispatching the itemData event,\n // it's a legacy verion before filters were introduced\n const event = this.dispatch('itemData', {\n itemData: itemData || {},\n index\n });\n\n return this.applyFilters('itemData', event.itemData, index);\n }\n\n /**\n * Get array of gallery DOM elements,\n * based on childSelector and gallery element.\n *\n * @param {HTMLElement} galleryElement\n * @returns {HTMLElement[]}\n */\n _getGalleryDOMElements(galleryElement) {\n if (this.options?.children || this.options?.childSelector) {\n return getElementsFromOption(\n this.options.children,\n this.options.childSelector,\n galleryElement\n ) || [];\n }\n\n return [galleryElement];\n }\n\n /**\n * Converts DOM element to item data object.\n *\n * @param {HTMLElement} element DOM element\n * @returns {SlideData}\n */\n _domElementToItemData(element) {\n /** @type {SlideData} */\n const itemData = {\n element\n };\n\n const linkEl = /** @type {HTMLAnchorElement} */ (\n element.tagName === 'A'\n ? element\n : element.querySelector('a')\n );\n\n if (linkEl) {\n // src comes from data-pswp-src attribute,\n // if it's empty link href is used\n itemData.src = linkEl.dataset.pswpSrc || linkEl.href;\n\n if (linkEl.dataset.pswpSrcset) {\n itemData.srcset = linkEl.dataset.pswpSrcset;\n }\n\n itemData.width = linkEl.dataset.pswpWidth ? parseInt(linkEl.dataset.pswpWidth, 10) : 0;\n itemData.height = linkEl.dataset.pswpHeight ? parseInt(linkEl.dataset.pswpHeight, 10) : 0;\n\n // support legacy w & h properties\n itemData.w = itemData.width;\n itemData.h = itemData.height;\n\n if (linkEl.dataset.pswpType) {\n itemData.type = linkEl.dataset.pswpType;\n }\n\n const thumbnailEl = element.querySelector('img');\n\n if (thumbnailEl) {\n // msrc is URL to placeholder image that's displayed before large image is loaded\n // by default it's displayed only for the first slide\n itemData.msrc = thumbnailEl.currentSrc || thumbnailEl.src;\n itemData.alt = thumbnailEl.getAttribute('alt') ?? '';\n }\n\n if (linkEl.dataset.pswpCropped || linkEl.dataset.cropped) {\n itemData.thumbCropped = true;\n }\n }\n\n return this.applyFilters('domItemData', itemData, element, linkEl);\n }\n\n /**\n * Lazy-load by slide data\n *\n * @param {SlideData} itemData Data about the slide\n * @param {number} index\n * @returns {Content} Image that is being decoded or false.\n */\n lazyLoadData(itemData, index) {\n return lazyLoadData(itemData, this, index);\n }\n}\n\nexport default PhotoSwipeBase;\n","import {\n specialKeyUsed,\n getElementsFromOption,\n isPswpClass\n} from '../util/util.js';\n\nimport PhotoSwipeBase from '../core/base.js';\nimport { lazyLoadSlide } from '../slide/loader.js';\n\n/**\n * @template T\n * @typedef {import('../types.js').Type} Type\n */\n\n/** @typedef {import('../photoswipe.js').default} PhotoSwipe */\n/** @typedef {import('../photoswipe.js').PhotoSwipeOptions} PhotoSwipeOptions */\n/** @typedef {import('../photoswipe.js').DataSource} DataSource */\n/** @typedef {import('../photoswipe.js').Point} Point */\n/** @typedef {import('../slide/content.js').default} Content */\n/** @typedef {import('../core/eventable.js').PhotoSwipeEventsMap} PhotoSwipeEventsMap */\n/** @typedef {import('../core/eventable.js').PhotoSwipeFiltersMap} PhotoSwipeFiltersMap */\n\n/**\n * @template {keyof PhotoSwipeEventsMap} T\n * @typedef {import('../core/eventable.js').EventCallback} EventCallback\n */\n\n/**\n * PhotoSwipe Lightbox\n *\n * - If user has unsupported browser it falls back to default browser action (just opens URL)\n * - Binds click event to links that should open PhotoSwipe\n * - parses DOM strcture for PhotoSwipe (retrieves large image URLs and sizes)\n * - Initializes PhotoSwipe\n *\n *\n * Loader options use the same object as PhotoSwipe, and supports such options:\n *\n * gallery - Element | Element[] | NodeList | string selector for the gallery element\n * children - Element | Element[] | NodeList | string selector for the gallery children\n *\n */\nclass PhotoSwipeLightbox extends PhotoSwipeBase {\n /**\n * @param {PhotoSwipeOptions} [options]\n */\n constructor(options) {\n super();\n /** @type {PhotoSwipeOptions} */\n this.options = options || {};\n this._uid = 0;\n this.shouldOpen = false;\n /**\n * @private\n * @type {Content | undefined}\n */\n this._preloadedContent = undefined;\n\n this.onThumbnailsClick = this.onThumbnailsClick.bind(this);\n }\n\n /**\n * Initialize lightbox, should be called only once.\n * It's not included in the main constructor, so you may bind events before it.\n */\n init() {\n // Bind click events to each gallery\n getElementsFromOption(this.options.gallery, this.options.gallerySelector)\n .forEach((galleryElement) => {\n galleryElement.addEventListener('click', this.onThumbnailsClick, false);\n });\n }\n\n /**\n * @param {MouseEvent} e\n */\n onThumbnailsClick(e) {\n // Exit and allow default browser action if:\n if (specialKeyUsed(e) // ... if clicked with a special key (ctrl/cmd...)\n || window.pswp) { // ... if PhotoSwipe is already open\n return;\n }\n\n // If both clientX and clientY are 0 or not defined,\n // the event is likely triggered by keyboard,\n // so we do not pass the initialPoint\n //\n // Note that some screen readers emulate the mouse position,\n // so it's not the ideal way to detect them.\n //\n /** @type {Point | null} */\n let initialPoint = { x: e.clientX, y: e.clientY };\n\n if (!initialPoint.x && !initialPoint.y) {\n initialPoint = null;\n }\n\n let clickedIndex = this.getClickedIndex(e);\n clickedIndex = this.applyFilters('clickedIndex', clickedIndex, e, this);\n /** @type {DataSource} */\n const dataSource = {\n gallery: /** @type {HTMLElement} */ (e.currentTarget)\n };\n\n if (clickedIndex >= 0) {\n e.preventDefault();\n this.loadAndOpen(clickedIndex, dataSource, initialPoint);\n }\n }\n\n /**\n * Get index of gallery item that was clicked.\n *\n * @param {MouseEvent} e click event\n * @returns {number}\n */\n getClickedIndex(e) {\n // legacy option\n if (this.options.getClickedIndexFn) {\n return this.options.getClickedIndexFn.call(this, e);\n }\n\n const clickedTarget = /** @type {HTMLElement} */ (e.target);\n const childElements = getElementsFromOption(\n this.options.children,\n this.options.childSelector,\n /** @type {HTMLElement} */ (e.currentTarget)\n );\n const clickedChildIndex = childElements.findIndex(\n child => child === clickedTarget || child.contains(clickedTarget)\n );\n\n if (clickedChildIndex !== -1) {\n return clickedChildIndex;\n } else if (this.options.children || this.options.childSelector) {\n // click wasn't on a child element\n return -1;\n }\n\n // There is only one item (which is the gallery)\n return 0;\n }\n\n /**\n * Load and open PhotoSwipe\n *\n * @param {number} index\n * @param {DataSource} dataSource\n * @param {Point | null} [initialPoint]\n * @returns {boolean}\n */\n loadAndOpen(index, dataSource, initialPoint) {\n // Check if the gallery is already open\n if (window.pswp) {\n return false;\n }\n\n // set initial index\n this.options.index = index;\n\n // define options for PhotoSwipe constructor\n this.options.initialPointerPos = initialPoint;\n\n this.shouldOpen = true;\n this.preload(index, dataSource);\n return true;\n }\n\n /**\n * Load the main module and the slide content by index\n *\n * @param {number} index\n * @param {DataSource} [dataSource]\n */\n preload(index, dataSource) {\n const { options } = this;\n\n if (dataSource) {\n options.dataSource = dataSource;\n }\n\n // Add the main module\n /** @type {Promise>[]} */\n const promiseArray = [];\n\n const pswpModuleType = typeof options.pswpModule;\n if (isPswpClass(options.pswpModule)) {\n promiseArray.push(Promise.resolve(/** @type {Type} */ (options.pswpModule)));\n } else if (pswpModuleType === 'string') {\n throw new Error('pswpModule as string is no longer supported');\n } else if (pswpModuleType === 'function') {\n promiseArray.push(/** @type {() => Promise>} */ (options.pswpModule)());\n } else {\n throw new Error('pswpModule is not valid');\n }\n\n // Add custom-defined promise, if any\n if (typeof options.openPromise === 'function') {\n // allow developers to perform some task before opening\n promiseArray.push(options.openPromise());\n }\n\n if (options.preloadFirstSlide !== false && index >= 0) {\n this._preloadedContent = lazyLoadSlide(index, this);\n }\n\n // Wait till all promises resolve and open PhotoSwipe\n const uid = ++this._uid;\n Promise.all(promiseArray).then((iterableModules) => {\n if (this.shouldOpen) {\n const mainModule = iterableModules[0];\n this._openPhotoswipe(mainModule, uid);\n }\n });\n }\n\n /**\n * @private\n * @param {Type | { default: Type }} module\n * @param {number} uid\n */\n _openPhotoswipe(module, uid) {\n // Cancel opening if UID doesn't match the current one\n // (if user clicked on another gallery item before current was loaded).\n //\n // Or if shouldOpen flag is set to false\n // (developer may modify it via public API)\n if (uid !== this._uid && this.shouldOpen) {\n return;\n }\n\n this.shouldOpen = false;\n\n // PhotoSwipe is already open\n if (window.pswp) {\n return;\n }\n\n /**\n * Pass data to PhotoSwipe and open init\n *\n * @type {PhotoSwipe}\n */\n const pswp = typeof module === 'object'\n ? new module.default(this.options) // eslint-disable-line\n : new module(this.options); // eslint-disable-line\n\n this.pswp = pswp;\n window.pswp = pswp;\n\n // map listeners from Lightbox to PhotoSwipe Core\n /** @type {(keyof PhotoSwipeEventsMap)[]} */\n (Object.keys(this._listeners)).forEach((name) => {\n this._listeners[name]?.forEach((fn) => {\n pswp.on(name, /** @type {EventCallback} */(fn));\n });\n });\n\n // same with filters\n /** @type {(keyof PhotoSwipeFiltersMap)[]} */\n (Object.keys(this._filters)).forEach((name) => {\n this._filters[name]?.forEach((filter) => {\n pswp.addFilter(name, filter.fn, filter.priority);\n });\n });\n\n if (this._preloadedContent) {\n pswp.contentLoader.addToCache(this._preloadedContent);\n this._preloadedContent = undefined;\n }\n\n pswp.on('destroy', () => {\n // clean up public variables\n this.pswp = undefined;\n delete window.pswp;\n });\n\n pswp.init();\n }\n\n /**\n * Unbinds all events, closes PhotoSwipe if it's open.\n */\n destroy() {\n this.pswp?.destroy();\n\n this.shouldOpen = false;\n this._listeners = {};\n\n getElementsFromOption(this.options.gallery, this.options.gallerySelector)\n .forEach((galleryElement) => {\n galleryElement.removeEventListener('click', this.onThumbnailsClick, false);\n });\n }\n}\n\nexport default PhotoSwipeLightbox;\n"],"names":[],"mappings":"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;;ACvOA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,MAAM,eAAe,CAAC;AACtB;AACA;AACA;AACA;AACA,EAAE,WAAW,CAAC,IAAI,EAAE,OAAO,EAAE;AAC7B,IAAI,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;AACrB,IAAI,IAAI,CAAC,gBAAgB,GAAG,KAAK,CAAC;AA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"} \ No newline at end of file diff --git a/dist/cjs/photoswipe.cjs b/dist/cjs/photoswipe.cjs new file mode 100644 index 000000000..ae516f3fa --- /dev/null +++ b/dist/cjs/photoswipe.cjs @@ -0,0 +1,6619 @@ +/*! + * PhotoSwipe 5.3.9 - https://photoswipe.com + * (c) 2023 Dmytro Semenov + */ +'use strict'; + +/** @typedef {import('../photoswipe.js').Point} Point */ + +/** + * @template {keyof HTMLElementTagNameMap} T + * @param {string} className + * @param {T} tagName + * @param {Node} [appendToEl] + * @returns {HTMLElementTagNameMap[T]} + */ +function createElement(className, tagName, appendToEl) { + const el = document.createElement(tagName); + if (className) { + el.className = className; + } + if (appendToEl) { + appendToEl.appendChild(el); + } + return el; +} + +/** + * @param {Point} p1 + * @param {Point} p2 + * @returns {Point} + */ +function equalizePoints(p1, p2) { + p1.x = p2.x; + p1.y = p2.y; + if (p2.id !== undefined) { + p1.id = p2.id; + } + return p1; +} + +/** + * @param {Point} p + */ +function roundPoint(p) { + p.x = Math.round(p.x); + p.y = Math.round(p.y); +} + +/** + * Returns distance between two points. + * + * @param {Point} p1 + * @param {Point} p2 + * @returns {number} + */ +function getDistanceBetween(p1, p2) { + const x = Math.abs(p1.x - p2.x); + const y = Math.abs(p1.y - p2.y); + return Math.sqrt((x * x) + (y * y)); +} + +/** + * Whether X and Y positions of points are equal + * + * @param {Point} p1 + * @param {Point} p2 + * @returns {boolean} + */ +function pointsEqual(p1, p2) { + return p1.x === p2.x && p1.y === p2.y; +} + +/** + * The float result between the min and max values. + * + * @param {number} val + * @param {number} min + * @param {number} max + * @returns {number} + */ +function clamp(val, min, max) { + return Math.min(Math.max(val, min), max); +} + +/** + * Get transform string + * + * @param {number} x + * @param {number} [y] + * @param {number} [scale] + * @returns {string} + */ +function toTransformString(x, y, scale) { + let propValue = `translate3d(${x}px,${y || 0}px,0)`; + + if (scale !== undefined) { + propValue += ` scale3d(${scale},${scale},1)`; + } + + return propValue; +} + +/** + * Apply transform:translate(x, y) scale(scale) to element + * + * @param {HTMLElement} el + * @param {number} x + * @param {number} [y] + * @param {number} [scale] + */ +function setTransform(el, x, y, scale) { + el.style.transform = toTransformString(x, y, scale); +} + +const defaultCSSEasing = 'cubic-bezier(.4,0,.22,1)'; + +/** + * Apply CSS transition to element + * + * @param {HTMLElement} el + * @param {string} [prop] CSS property to animate + * @param {number} [duration] in ms + * @param {string} [ease] CSS easing function + */ +function setTransitionStyle(el, prop, duration, ease) { + // inOut: 'cubic-bezier(.4, 0, .22, 1)', // for "toggle state" transitions + // out: 'cubic-bezier(0, 0, .22, 1)', // for "show" transitions + // in: 'cubic-bezier(.4, 0, 1, 1)'// for "hide" transitions + el.style.transition = prop + ? `${prop} ${duration}ms ${ease || defaultCSSEasing}` + : 'none'; +} + +/** + * Apply width and height CSS properties to element + * + * @param {HTMLElement} el + * @param {string | number} w + * @param {string | number} h + */ +function setWidthHeight(el, w, h) { + el.style.width = (typeof w === 'number') ? `${w}px` : w; + el.style.height = (typeof h === 'number') ? `${h}px` : h; +} + +/** + * @param {HTMLElement} el + */ +function removeTransitionStyle(el) { + setTransitionStyle(el); +} + +/** + * @param {HTMLImageElement} img + * @returns {Promise} + */ +function decodeImage(img) { + if ('decode' in img) { + return img.decode().catch(() => {}); + } + + if (img.complete) { + return Promise.resolve(img); + } + + return new Promise((resolve, reject) => { + img.onload = () => resolve(img); + img.onerror = reject; + }); +} + +/** @typedef {LOAD_STATE[keyof LOAD_STATE]} LoadState */ +/** @type {{ IDLE: 'idle'; LOADING: 'loading'; LOADED: 'loaded'; ERROR: 'error' }} */ +const LOAD_STATE = { + IDLE: 'idle', + LOADING: 'loading', + LOADED: 'loaded', + ERROR: 'error', +}; + + +/** + * Check if click or keydown event was dispatched + * with a special key or via mouse wheel. + * + * @param {MouseEvent | KeyboardEvent} e + * @returns {boolean} + */ +function specialKeyUsed(e) { + return ('button' in e && e.button === 1) || e.ctrlKey || e.metaKey || e.altKey || e.shiftKey; +} + +/** + * Parse `gallery` or `children` options. + * + * @param {import('../photoswipe.js').ElementProvider} [option] + * @param {string} [legacySelector] + * @param {HTMLElement | Document} [parent] + * @returns HTMLElement[] + */ +function getElementsFromOption(option, legacySelector, parent = document) { + /** @type {HTMLElement[]} */ + 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; +} + +/** + * Check if browser is Safari + * + * @returns {boolean} + */ +function isSafari() { + return !!(navigator.vendor && navigator.vendor.match(/apple/i)); +} + +// Detect passive event listener support +let supportsPassive = false; +/* eslint-disable */ +try { + /* @ts-ignore */ + window.addEventListener('test', null, Object.defineProperty({}, 'passive', { + get: () => { + supportsPassive = true; + } + })); +} catch (e) {} +/* eslint-enable */ + +/** + * @typedef {Object} PoolItem + * @prop {HTMLElement | Window | Document | undefined | null} target + * @prop {string} type + * @prop {EventListenerOrEventListenerObject} listener + * @prop {boolean} [passive] + */ + +class DOMEvents { + constructor() { + /** + * @type {PoolItem[]} + * @private + */ + this._pool = []; + } + + /** + * Adds event listeners + * + * @param {PoolItem['target']} target + * @param {PoolItem['type']} type Can be multiple, separated by space. + * @param {PoolItem['listener']} listener + * @param {PoolItem['passive']} [passive] + */ + add(target, type, listener, passive) { + this._toggleListener(target, type, listener, passive); + } + + /** + * Removes event listeners + * + * @param {PoolItem['target']} target + * @param {PoolItem['type']} type + * @param {PoolItem['listener']} listener + * @param {PoolItem['passive']} [passive] + */ + remove(target, type, listener, passive) { + this._toggleListener(target, type, listener, passive, true); + } + + /** + * Removes all bound events + */ + removeAll() { + this._pool.forEach((poolItem) => { + this._toggleListener( + poolItem.target, + poolItem.type, + poolItem.listener, + poolItem.passive, + true, + true + ); + }); + this._pool = []; + } + + /** + * Adds or removes event + * + * @private + * @param {PoolItem['target']} target + * @param {PoolItem['type']} type + * @param {PoolItem['listener']} listener + * @param {PoolItem['passive']} [passive] + * @param {boolean} [unbind] Whether the event should be added or removed + * @param {boolean} [skipPool] Whether events pool should be skipped + */ + _toggleListener(target, type, listener, passive, unbind, skipPool) { + if (!target) { + return; + } + + const methodName = unbind ? 'removeEventListener' : 'addEventListener'; + const types = type.split(' '); + types.forEach((eType) => { + if (eType) { + // Events pool is used to easily unbind all events when PhotoSwipe is closed, + // so developer doesn't need to do this manually + if (!skipPool) { + if (unbind) { + // Remove from the events pool + this._pool = this._pool.filter((poolItem) => { + return poolItem.type !== eType + || poolItem.listener !== listener + || poolItem.target !== target; + }); + } else { + // Add to the events pool + this._pool.push({ + target, + type: eType, + listener, + passive + }); + } + } + + // most PhotoSwipe events call preventDefault, + // and we do not need browser to scroll the page + const eventOptions = supportsPassive ? { passive: (passive || false) } : false; + + target[methodName]( + eType, + listener, + eventOptions + ); + } + }); + } +} + +/** @typedef {import('../photoswipe.js').PhotoSwipeOptions} PhotoSwipeOptions */ +/** @typedef {import('../core/base.js').default} PhotoSwipeBase */ +/** @typedef {import('../photoswipe.js').Point} Point */ +/** @typedef {import('../slide/slide.js').SlideData} SlideData */ + +/** + * @param {PhotoSwipeOptions} options + * @param {PhotoSwipeBase} pswp + * @returns {Point} + */ +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 + }; +} + +/** + * Parses padding option. + * Supported formats: + * + * // Object + * padding: { + * top: 0, + * bottom: 0, + * left: 0, + * right: 0 + * } + * + * // A function that returns the object + * paddingFn: (viewportSize, itemData, index) => { + * return { + * top: 0, + * bottom: 0, + * left: 0, + * right: 0 + * }; + * } + * + * // Legacy variant + * paddingLeft: 0, + * paddingRight: 0, + * paddingTop: 0, + * paddingBottom: 0, + * + * @param {'left' | 'top' | 'bottom' | 'right'} prop + * @param {PhotoSwipeOptions} options PhotoSwipe options + * @param {Point} viewportSize PhotoSwipe viewport size, for example: { x:800, y:600 } + * @param {SlideData} itemData Data about the slide + * @param {number} index Slide index + * @returns {number} + */ +function parsePaddingOption(prop, options, viewportSize, itemData, index) { + let paddingValue = 0; + + if (options.paddingFn) { + paddingValue = options.paddingFn(viewportSize, itemData, index)[prop]; + } else if (options.padding) { + paddingValue = options.padding[prop]; + } else { + const legacyPropName = 'padding' + prop[0].toUpperCase() + prop.slice(1); + // @ts-expect-error + if (options[legacyPropName]) { + // @ts-expect-error + paddingValue = options[legacyPropName]; + } + } + + return Number(paddingValue) || 0; +} + +/** + * @param {PhotoSwipeOptions} options + * @param {Point} viewportSize + * @param {SlideData} itemData + * @param {number} index + * @returns {Point} + */ +function getPanAreaSize(options, viewportSize, itemData, index) { + return { + x: viewportSize.x + - parsePaddingOption('left', options, viewportSize, itemData, index) + - parsePaddingOption('right', options, viewportSize, itemData, index), + y: viewportSize.y + - parsePaddingOption('top', options, viewportSize, itemData, index) + - parsePaddingOption('bottom', options, viewportSize, itemData, index) + }; +} + +/** @typedef {import('./slide.js').default} Slide */ +/** @typedef {Record} Point */ +/** @typedef {'x' | 'y'} Axis */ + +/** + * Calculates minimum, maximum and initial (center) bounds of a slide + */ +class PanBounds { + /** + * @param {Slide} slide + */ + constructor(slide) { + this.slide = slide; + this.currZoomLevel = 1; + this.center = /** @type {Point} */ { x: 0, y: 0 }; + this.max = /** @type {Point} */ { x: 0, y: 0 }; + this.min = /** @type {Point} */ { x: 0, y: 0 }; + } + + /** + * _getItemBounds + * + * @param {number} currZoomLevel + */ + update(currZoomLevel) { + this.currZoomLevel = currZoomLevel; + + if (!this.slide.width) { + this.reset(); + } else { + this._updateAxis('x'); + this._updateAxis('y'); + this.slide.pswp.dispatch('calcBounds', { slide: this.slide }); + } + } + + /** + * _calculateItemBoundsForAxis + * + * @param {Axis} axis + */ + _updateAxis(axis) { + const { pswp } = this.slide; + const elSize = this.slide[axis === 'x' ? 'width' : 'height'] * this.currZoomLevel; + const paddingProp = axis === 'x' ? 'left' : 'top'; + const padding = parsePaddingOption( + paddingProp, + pswp.options, + pswp.viewportSize, + this.slide.data, + this.slide.index + ); + + const panAreaSize = this.slide.panAreaSize[axis]; + + // Default position of element. + // By default, it is center of viewport: + this.center[axis] = Math.round((panAreaSize - elSize) / 2) + padding; + + // maximum pan position + this.max[axis] = (elSize > panAreaSize) + ? Math.round(panAreaSize - elSize) + padding + : this.center[axis]; + + // minimum pan position + this.min[axis] = (elSize > panAreaSize) + ? padding + : this.center[axis]; + } + + // _getZeroBounds + reset() { + this.center.x = 0; + this.center.y = 0; + this.max.x = 0; + this.max.y = 0; + this.min.x = 0; + this.min.y = 0; + } + + /** + * Correct pan position if it's beyond the bounds + * + * @param {Axis} axis x or y + * @param {number} panOffset + * @returns {number} + */ + correctPan(axis, panOffset) { // checkPanBounds + return clamp(panOffset, this.max[axis], this.min[axis]); + } +} + +const MAX_IMAGE_WIDTH = 4000; + +/** @typedef {import('../photoswipe.js').default} PhotoSwipe */ +/** @typedef {import('../photoswipe.js').PhotoSwipeOptions} PhotoSwipeOptions */ +/** @typedef {import('../photoswipe.js').Point} Point */ +/** @typedef {import('../slide/slide.js').SlideData} SlideData */ + +/** @typedef {'fit' | 'fill' | number | ((zoomLevelObject: ZoomLevel) => number)} ZoomLevelOption */ + +/** + * Calculates zoom levels for specific slide. + * Depends on viewport size and image size. + */ +class ZoomLevel { + /** + * @param {PhotoSwipeOptions} options PhotoSwipe options + * @param {SlideData} itemData Slide data + * @param {number} index Slide index + * @param {PhotoSwipe} [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; + /** @type { Point | null } */ + this.panAreaSize = null; + /** @type { Point | null } */ + this.elementSize = null; + this.fit = 1; + this.fill = 1; + this.vFill = 1; + this.initial = 1; + this.secondary = 1; + this.max = 1; + this.min = 1; + } + + /** + * Calculate initial, secondary and maximum zoom level for the specified slide. + * + * It should be called when either image or viewport size changes. + * + * @param {number} maxWidth + * @param {number} maxHeight + * @param {Point} panAreaSize + */ + update(maxWidth, maxHeight, panAreaSize) { + /** @type {Point} */ + const elementSize = { x: maxWidth, y: maxHeight }; + this.elementSize = elementSize; + this.panAreaSize = panAreaSize; + + const hRatio = panAreaSize.x / elementSize.x; + const vRatio = panAreaSize.y / 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. + * + * @private + * @param {'initial' | 'secondary' | 'max'} optionPrefix Zoom level option prefix (initial, secondary, max) + * @returns { number | undefined } + */ + _parseZoomLevelOption(optionPrefix) { + const optionName = /** @type {'initialZoomLevel' | 'secondaryZoomLevel' | 'maxZoomLevel'} */ ( + optionPrefix + 'ZoomLevel' + ); + const optionValue = this.options[optionName]; + + 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. + * + * @private + * @return {number} + */ + _getSecondary() { + let currZoomLevel = this._parseZoomLevelOption('secondary'); + + if (currZoomLevel) { + return currZoomLevel; + } + + // 3x of "fit" state, but not larger than original + currZoomLevel = Math.min(1, this.fit * 3); + + if (this.elementSize && currZoomLevel * this.elementSize.x > MAX_IMAGE_WIDTH) { + currZoomLevel = MAX_IMAGE_WIDTH / this.elementSize.x; + } + + return currZoomLevel; + } + + /** + * Get initial image zoom level. + * + * @private + * @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. + * + * @private + * @return {number} + */ + _getMax() { + // max zoom level is x4 from "fit state", + // used for zoom gesture and ctrl/trackpad zoom + return this._parseZoomLevelOption('max') || Math.max(1, this.fit * 4); + } +} + +/** @typedef {import('../photoswipe.js').default} PhotoSwipe */ + +/** + * Renders and allows to control a single slide + */ +class Slide { + /** + * @param {SlideData} data + * @param {number} index + * @param {PhotoSwipe} pswp + */ + constructor(data, index, pswp) { + this.data = data; + this.index = index; + this.pswp = pswp; + this.isActive = (index === pswp.currIndex); + this.currentResolution = 0; + /** @type {Point} */ + this.panAreaSize = { x: 0, y: 0 }; + /** @type {Point} */ + this.pan = { x: 0, y: 0 }; + + this.isFirstSlide = (this.isActive && !pswp.opener.isOpen); + + this.zoomLevels = new ZoomLevel(pswp.options, data, index, pswp); + + this.pswp.dispatch('gettingData', { + slide: this, + data: this.data, + index + }); + + this.content = this.pswp.contentLoader.getContentBySlide(this); + this.container = createElement('pswp__zoom-wrap', 'div'); + /** @type {HTMLElement | null} */ + this.holderElement = null; + + this.currZoomLevel = 1; + /** @type {number} */ + this.width = this.content.width; + /** @type {number} */ + this.height = this.content.height; + this.heavyAppended = false; + this.bounds = new PanBounds(this); + + this.prevDisplayedWidth = -1; + this.prevDisplayedHeight = -1; + + this.pswp.dispatch('slideInit', { slide: this }); + } + + /** + * If this slide is active/current/visible + * + * @param {boolean} isActive + */ + setIsActive(isActive) { + if (isActive && !this.isActive) { + // slide just became active + this.activate(); + } else if (!isActive && this.isActive) { + // slide just became non-active + this.deactivate(); + } + } + + /** + * Appends slide content to DOM + * + * @param {HTMLElement} holderElement + */ + append(holderElement) { + this.holderElement = holderElement; + + this.container.style.transformOrigin = '0 0'; + + // Slide appended to DOM + if (!this.data) { + return; + } + + this.calculateSize(); + + this.load(); + this.updateContentSize(); + this.appendHeavy(); + + this.holderElement.appendChild(this.container); + + this.zoomAndPanToInitial(); + + this.pswp.dispatch('firstZoomPan', { slide: this }); + + this.applyCurrentZoomPan(); + + this.pswp.dispatch('afterSetContent', { slide: this }); + + if (this.isActive) { + this.activate(); + } + } + + load() { + this.content.load(false); + this.pswp.dispatch('slideLoad', { slide: this }); + } + + /** + * Append "heavy" DOM elements + * + * This may depend on a type of slide, + * but generally these are large images. + */ + appendHeavy() { + const { pswp } = this; + const appendHeavyNearby = true; // todo + + // Avoid appending heavy elements during animations + if (this.heavyAppended + || !pswp.opener.isOpen + || pswp.mainScroll.isShifted() + || (!this.isActive && !appendHeavyNearby)) { + return; + } + + if (this.pswp.dispatch('appendHeavy', { slide: this }).defaultPrevented) { + return; + } + + this.heavyAppended = true; + + this.content.append(); + + this.pswp.dispatch('appendHeavyContent', { slide: this }); + } + + /** + * Triggered when this slide is active (selected). + * + * If it's part of opening/closing transition - + * activate() will trigger after the transition is ended. + */ + activate() { + this.isActive = true; + this.appendHeavy(); + this.content.activate(); + this.pswp.dispatch('slideActivate', { slide: this }); + } + + /** + * Triggered when this slide becomes inactive. + * + * Slide can become inactive only after it was active. + */ + deactivate() { + this.isActive = false; + this.content.deactivate(); + + if (this.currZoomLevel !== this.zoomLevels.initial) { + // allow filtering + this.calculateSize(); + } + + // reset zoom level + this.currentResolution = 0; + this.zoomAndPanToInitial(); + this.applyCurrentZoomPan(); + this.updateContentSize(); + + this.pswp.dispatch('slideDeactivate', { slide: this }); + } + + /** + * The slide should destroy itself, it will never be used again. + * (unbind all events and destroy internal components) + */ + destroy() { + this.content.hasSlide = false; + this.content.remove(); + this.container.remove(); + this.pswp.dispatch('slideDestroy', { slide: this }); + } + + resize() { + if (this.currZoomLevel === this.zoomLevels.initial || !this.isActive) { + // Keep initial zoom level if it was before the resize, + // as well as when this slide is not active + + // Reset position and scale to original state + this.calculateSize(); + this.currentResolution = 0; + this.zoomAndPanToInitial(); + this.applyCurrentZoomPan(); + this.updateContentSize(); + } else { + // readjust pan position if it's beyond the bounds + this.calculateSize(); + this.bounds.update(this.currZoomLevel); + this.panTo(this.pan.x, this.pan.y); + } + } + + + /** + * Apply size to current slide content, + * based on the current resolution and scale. + * + * @param {boolean} [force] if size should be updated even if dimensions weren't changed + */ + updateContentSize(force) { + // Use initial zoom level + // if resolution is not defined (user didn't zoom yet) + const scaleMultiplier = this.currentResolution || this.zoomLevels.initial; + + if (!scaleMultiplier) { + return; + } + + const width = Math.round(this.width * scaleMultiplier) || this.pswp.viewportSize.x; + const height = Math.round(this.height * scaleMultiplier) || this.pswp.viewportSize.y; + + if (!this.sizeChanged(width, height) && !force) { + return; + } + this.content.setDisplayedSize(width, height); + } + + /** + * @param {number} width + * @param {number} height + */ + sizeChanged(width, height) { + if (width !== this.prevDisplayedWidth + || height !== this.prevDisplayedHeight) { + this.prevDisplayedWidth = width; + this.prevDisplayedHeight = height; + return true; + } + + return false; + } + + /** @returns {HTMLImageElement | HTMLDivElement | null | undefined} */ + getPlaceholderElement() { + return this.content.placeholder?.element; + } + + /** + * Zoom current slide image to... + * + * @param {number} destZoomLevel Destination zoom level. + * @param {Point} [centerPoint] + * Transform origin center point, or false if viewport center should be used. + * @param {number | false} [transitionDuration] Transition duration, may be set to 0. + * @param {boolean} [ignoreBounds] Minimum and maximum zoom levels will be ignored. + */ + zoomTo(destZoomLevel, centerPoint, transitionDuration, ignoreBounds) { + const { pswp } = this; + if (!this.isZoomable() + || pswp.mainScroll.isShifted()) { + return; + } + + pswp.dispatch('beforeZoomTo', { + destZoomLevel, centerPoint, transitionDuration + }); + + // stop all pan and zoom transitions + pswp.animations.stopAllPan(); + + // if (!centerPoint) { + // centerPoint = pswp.getViewportCenterPoint(); + // } + + const prevZoomLevel = this.currZoomLevel; + + if (!ignoreBounds) { + destZoomLevel = clamp(destZoomLevel, this.zoomLevels.min, this.zoomLevels.max); + } + + // if (transitionDuration === undefined) { + // transitionDuration = this.pswp.options.zoomAnimationDuration; + // } + + this.setZoomLevel(destZoomLevel); + this.pan.x = this.calculateZoomToPanOffset('x', centerPoint, prevZoomLevel); + this.pan.y = this.calculateZoomToPanOffset('y', centerPoint, prevZoomLevel); + roundPoint(this.pan); + + const finishTransition = () => { + this._setResolution(destZoomLevel); + this.applyCurrentZoomPan(); + }; + + if (!transitionDuration) { + finishTransition(); + } else { + pswp.animations.startTransition({ + isPan: true, + name: 'zoomTo', + target: this.container, + transform: this.getCurrentTransform(), + onComplete: finishTransition, + duration: transitionDuration, + easing: pswp.options.easing + }); + } + } + + /** + * @param {Point} [centerPoint] + */ + toggleZoom(centerPoint) { + this.zoomTo( + this.currZoomLevel === this.zoomLevels.initial + ? this.zoomLevels.secondary : this.zoomLevels.initial, + centerPoint, + this.pswp.options.zoomAnimationDuration + ); + } + + /** + * Updates zoom level property and recalculates new pan bounds, + * unlike zoomTo it does not apply transform (use applyCurrentZoomPan) + * + * @param {number} currZoomLevel + */ + setZoomLevel(currZoomLevel) { + this.currZoomLevel = currZoomLevel; + this.bounds.update(this.currZoomLevel); + } + + /** + * Get pan position after zoom at a given `point`. + * + * Always call setZoomLevel(newZoomLevel) beforehand to recalculate + * pan bounds according to the new zoom level. + * + * @param {'x' | 'y'} axis + * @param {Point} [point] + * point based on which zoom is performed, usually refers to the current mouse position, + * if false - viewport center will be used. + * @param {number} [prevZoomLevel] Zoom level before new zoom was applied. + * @returns {number} + */ + calculateZoomToPanOffset(axis, point, prevZoomLevel) { + const totalPanDistance = this.bounds.max[axis] - this.bounds.min[axis]; + if (totalPanDistance === 0) { + return this.bounds.center[axis]; + } + + if (!point) { + point = this.pswp.getViewportCenterPoint(); + } + + if (!prevZoomLevel) { + prevZoomLevel = this.zoomLevels.initial; + } + + const zoomFactor = this.currZoomLevel / prevZoomLevel; + return this.bounds.correctPan( + axis, + (this.pan[axis] - point[axis]) * zoomFactor + point[axis] + ); + } + + /** + * Apply pan and keep it within bounds. + * + * @param {number} panX + * @param {number} panY + */ + panTo(panX, panY) { + this.pan.x = this.bounds.correctPan('x', panX); + this.pan.y = this.bounds.correctPan('y', panY); + this.applyCurrentZoomPan(); + } + + /** + * If the slide in the current state can be panned by the user + * @returns {boolean} + */ + isPannable() { + return Boolean(this.width) && (this.currZoomLevel > this.zoomLevels.fit); + } + + /** + * If the slide can be zoomed + * @returns {boolean} + */ + isZoomable() { + return Boolean(this.width) && this.content.isZoomable(); + } + + /** + * Apply transform and scale based on + * the current pan position (this.pan) and zoom level (this.currZoomLevel) + */ + applyCurrentZoomPan() { + this._applyZoomTransform(this.pan.x, this.pan.y, this.currZoomLevel); + if (this === this.pswp.currSlide) { + this.pswp.dispatch('zoomPanUpdate', { slide: this }); + } + } + + zoomAndPanToInitial() { + this.currZoomLevel = this.zoomLevels.initial; + + // pan according to the zoom level + this.bounds.update(this.currZoomLevel); + equalizePoints(this.pan, this.bounds.center); + this.pswp.dispatch('initialZoomPan', { slide: this }); + } + + /** + * Set translate and scale based on current resolution + * + * @param {number} x + * @param {number} y + * @param {number} zoom + * @private + */ + _applyZoomTransform(x, y, zoom) { + zoom /= this.currentResolution || this.zoomLevels.initial; + setTransform(this.container, x, y, zoom); + } + + calculateSize() { + const { pswp } = this; + + equalizePoints( + this.panAreaSize, + getPanAreaSize(pswp.options, pswp.viewportSize, this.data, this.index) + ); + + this.zoomLevels.update(this.width, this.height, this.panAreaSize); + + pswp.dispatch('calcSlideSize', { + slide: this + }); + } + + /** @returns {string} */ + getCurrentTransform() { + const scale = this.currZoomLevel / (this.currentResolution || this.zoomLevels.initial); + return toTransformString(this.pan.x, this.pan.y, scale); + } + + /** + * Set resolution and re-render the image. + * + * For example, if the real image size is 2000x1500, + * and resolution is 0.5 - it will be rendered as 1000x750. + * + * Image with zoom level 2 and resolution 0.5 is + * the same as image with zoom level 1 and resolution 1. + * + * Used to optimize animations and make + * sure that browser renders image in the highest quality. + * Also used by responsive images to load the correct one. + * + * @param {number} newResolution + */ + _setResolution(newResolution) { + if (newResolution === this.currentResolution) { + return; + } + + this.currentResolution = newResolution; + this.updateContentSize(); + + this.pswp.dispatch('resolutionChanged'); + } +} + +/** @typedef {import('../photoswipe.js').Point} Point */ +/** @typedef {import('./gestures.js').default} Gestures */ + +const PAN_END_FRICTION = 0.35; +const VERTICAL_DRAG_FRICTION = 0.6; + +// 1 corresponds to the third of viewport height +const MIN_RATIO_TO_CLOSE = 0.4; + +// Minimum speed required to navigate +// to next or previous slide +const MIN_NEXT_SLIDE_SPEED = 0.5; + +/** + * @param {number} initialVelocity + * @param {number} decelerationRate + * @returns {number} + */ +function project(initialVelocity, decelerationRate) { + return initialVelocity * decelerationRate / (1 - decelerationRate); +} + +/** + * Handles single pointer dragging + */ +class DragHandler { + /** + * @param {Gestures} gestures + */ + constructor(gestures) { + this.gestures = gestures; + this.pswp = gestures.pswp; + /** @type {Point} */ + this.startPan = { x: 0, y: 0 }; + } + + start() { + if (this.pswp.currSlide) { + equalizePoints(this.startPan, this.pswp.currSlide.pan); + } + this.pswp.animations.stopAll(); + } + + change() { + const { p1, prevP1, dragAxis } = this.gestures; + const { currSlide } = this.pswp; + + if (dragAxis === 'y' + && this.pswp.options.closeOnVerticalDrag + && (currSlide && currSlide.currZoomLevel <= currSlide.zoomLevels.fit) + && !this.gestures.isMultitouch) { + // Handle vertical drag to close + const panY = currSlide.pan.y + (p1.y - prevP1.y); + if (!this.pswp.dispatch('verticalDrag', { panY }).defaultPrevented) { + this._setPanWithFriction('y', panY, VERTICAL_DRAG_FRICTION); + const bgOpacity = 1 - Math.abs(this._getVerticalDragRatio(currSlide.pan.y)); + this.pswp.applyBgOpacity(bgOpacity); + currSlide.applyCurrentZoomPan(); + } + } else { + const mainScrollChanged = this._panOrMoveMainScroll('x'); + if (!mainScrollChanged) { + this._panOrMoveMainScroll('y'); + + if (currSlide) { + roundPoint(currSlide.pan); + currSlide.applyCurrentZoomPan(); + } + } + } + } + + end() { + const { velocity } = this.gestures; + const { mainScroll, currSlide } = this.pswp; + let indexDiff = 0; + + this.pswp.animations.stopAll(); + + // Handle main scroll if it's shifted + if (mainScroll.isShifted()) { + // Position of the main scroll relative to the viewport + const mainScrollShiftDiff = mainScroll.x - mainScroll.getCurrSlideX(); + + // Ratio between 0 and 1: + // 0 - slide is not visible at all, + // 0.5 - half of the slide is visible + // 1 - slide is fully visible + const currentSlideVisibilityRatio = (mainScrollShiftDiff / this.pswp.viewportSize.x); + + // Go next slide. + // + // - if velocity and its direction is matched, + // and we see at least tiny part of the next slide + // + // - or if we see less than 50% of the current slide + // and velocity is close to 0 + // + if ((velocity.x < -MIN_NEXT_SLIDE_SPEED && currentSlideVisibilityRatio < 0) + || (velocity.x < 0.1 && currentSlideVisibilityRatio < -0.5)) { + // Go to next slide + indexDiff = 1; + velocity.x = Math.min(velocity.x, 0); + } else if ((velocity.x > MIN_NEXT_SLIDE_SPEED && currentSlideVisibilityRatio > 0) + || (velocity.x > -0.1 && currentSlideVisibilityRatio > 0.5)) { + // Go to prev slide + indexDiff = -1; + velocity.x = Math.max(velocity.x, 0); + } + + mainScroll.moveIndexBy(indexDiff, true, velocity.x); + } + + // Restore zoom level + if ((currSlide && currSlide.currZoomLevel > currSlide.zoomLevels.max) + || this.gestures.isMultitouch) { + this.gestures.zoomLevels.correctZoomPan(true); + } else { + // we run two animations instead of one, + // as each axis has own pan boundaries and thus different spring function + // (correctZoomPan does not have this functionality, + // it animates all properties with single timing function) + this._finishPanGestureForAxis('x'); + this._finishPanGestureForAxis('y'); + } + } + + /** + * @private + * @param {'x' | 'y'} axis + */ + _finishPanGestureForAxis(axis) { + const { velocity } = this.gestures; + const { currSlide } = this.pswp; + + if (!currSlide) { + return; + } + + const { pan, bounds } = currSlide; + const panPos = pan[axis]; + const restoreBgOpacity = (this.pswp.bgOpacity < 1 && axis === 'y'); + + // 0.995 means - scroll view loses 0.5% of its velocity per millisecond + // Increasing this number will reduce travel distance + const decelerationRate = 0.995; // 0.99 + + // Pan position if there is no bounds + const projectedPosition = panPos + project(velocity[axis], decelerationRate); + + if (restoreBgOpacity) { + const vDragRatio = this._getVerticalDragRatio(panPos); + const projectedVDragRatio = this._getVerticalDragRatio(projectedPosition); + + // If we are above and moving upwards, + // or if we are below and moving downwards + if ((vDragRatio < 0 && projectedVDragRatio < -MIN_RATIO_TO_CLOSE) + || (vDragRatio > 0 && projectedVDragRatio > MIN_RATIO_TO_CLOSE)) { + this.pswp.close(); + return; + } + } + + // Pan position with corrected bounds + const correctedPanPosition = bounds.correctPan(axis, projectedPosition); + + // Exit if pan position should not be changed + // or if speed it too low + if (panPos === correctedPanPosition) { + return; + } + + // Overshoot if the final position is out of pan bounds + const dampingRatio = (correctedPanPosition === projectedPosition) ? 1 : 0.82; + + const initialBgOpacity = this.pswp.bgOpacity; + const totalPanDist = correctedPanPosition - panPos; + + this.pswp.animations.startSpring({ + name: 'panGesture' + axis, + isPan: true, + start: panPos, + end: correctedPanPosition, + velocity: velocity[axis], + dampingRatio, + onUpdate: (pos) => { + // Animate opacity of background relative to Y pan position of an image + if (restoreBgOpacity && this.pswp.bgOpacity < 1) { + // 0 - start of animation, 1 - end of animation + const animationProgressRatio = 1 - (correctedPanPosition - pos) / totalPanDist; + + // We clamp opacity to keep it between 0 and 1. + // As progress ratio can be larger than 1 due to overshoot, + // and we do not want to bounce opacity. + this.pswp.applyBgOpacity(clamp( + initialBgOpacity + (1 - initialBgOpacity) * animationProgressRatio, + 0, + 1 + )); + } + + pan[axis] = Math.floor(pos); + currSlide.applyCurrentZoomPan(); + }, + }); + } + + /** + * Update position of the main scroll, + * or/and update pan position of the current slide. + * + * Should return true if it changes (or can change) main scroll. + * + * @private + * @param {'x' | 'y'} axis + * @returns {boolean} + */ + _panOrMoveMainScroll(axis) { + const { p1, dragAxis, prevP1, isMultitouch } = this.gestures; + const { currSlide, mainScroll } = this.pswp; + const delta = (p1[axis] - prevP1[axis]); + const newMainScrollX = mainScroll.x + delta; + + if (!delta || !currSlide) { + return false; + } + + // Always move main scroll if image can not be panned + if (axis === 'x' && !currSlide.isPannable() && !isMultitouch) { + mainScroll.moveTo(newMainScrollX, true); + return true; // changed main scroll + } + + const { bounds } = currSlide; + const newPan = currSlide.pan[axis] + delta; + + if (this.pswp.options.allowPanToNext + && dragAxis === 'x' + && axis === 'x' + && !isMultitouch) { + const currSlideMainScrollX = mainScroll.getCurrSlideX(); + + // Position of the main scroll relative to the viewport + const mainScrollShiftDiff = mainScroll.x - currSlideMainScrollX; + + const isLeftToRight = delta > 0; + const isRightToLeft = !isLeftToRight; + + if (newPan > bounds.min[axis] && isLeftToRight) { + // Panning from left to right, beyond the left edge + + // Wether the image was at minimum pan position (or less) + // when this drag gesture started. + // Minimum pan position refers to the left edge of the image. + const wasAtMinPanPosition = (bounds.min[axis] <= this.startPan[axis]); + + if (wasAtMinPanPosition) { + mainScroll.moveTo(newMainScrollX, true); + return true; + } else { + this._setPanWithFriction(axis, newPan); + //currSlide.pan[axis] = newPan; + } + } else if (newPan < bounds.max[axis] && isRightToLeft) { + // Paning from right to left, beyond the right edge + + // Maximum pan position refers to the right edge of the image. + const wasAtMaxPanPosition = (this.startPan[axis] <= bounds.max[axis]); + + if (wasAtMaxPanPosition) { + mainScroll.moveTo(newMainScrollX, true); + return true; + } else { + this._setPanWithFriction(axis, newPan); + //currSlide.pan[axis] = newPan; + } + } else { + // If main scroll is shifted + if (mainScrollShiftDiff !== 0) { + // If main scroll is shifted right + if (mainScrollShiftDiff > 0 /*&& isRightToLeft*/) { + mainScroll.moveTo(Math.max(newMainScrollX, currSlideMainScrollX), true); + return true; + } else if (mainScrollShiftDiff < 0 /*&& isLeftToRight*/) { + // Main scroll is shifted left (Position is less than 0 comparing to the viewport 0) + mainScroll.moveTo(Math.min(newMainScrollX, currSlideMainScrollX), true); + return true; + } + } else { + // We are within pan bounds, so just pan + this._setPanWithFriction(axis, newPan); + } + } + } else { + if (axis === 'y') { + // Do not pan vertically if main scroll is shifted o + if (!mainScroll.isShifted() && bounds.min.y !== bounds.max.y) { + this._setPanWithFriction(axis, newPan); + } + } else { + this._setPanWithFriction(axis, newPan); + } + } + + return false; + } + + // If we move above - the ratio is negative + // If we move below the ratio is positive + + /** + * Relation between pan Y position and third of viewport height. + * + * When we are at initial position (center bounds) - the ratio is 0, + * if position is shifted upwards - the ratio is negative, + * if position is shifted downwards - the ratio is positive. + * + * @private + * @param {number} panY The current pan Y position. + * @returns {number} + */ + _getVerticalDragRatio(panY) { + return (panY - (this.pswp.currSlide?.bounds.center.y ?? 0)) / (this.pswp.viewportSize.y / 3); + } + + /** + * Set pan position of the current slide. + * Apply friction if the position is beyond the pan bounds, + * or if custom friction is defined. + * + * @private + * @param {'x' | 'y'} axis + * @param {number} potentialPan + * @param {number} [customFriction] (0.1 - 1) + */ + _setPanWithFriction(axis, potentialPan, customFriction) { + const { currSlide } = this.pswp; + + if (!currSlide) { + return; + } + + const { pan, bounds } = currSlide; + const correctedPan = bounds.correctPan(axis, potentialPan); + // If we are out of pan bounds + if (correctedPan !== potentialPan || customFriction) { + const delta = Math.round(potentialPan - pan[axis]); + pan[axis] += delta * (customFriction || PAN_END_FRICTION); + } else { + pan[axis] = potentialPan; + } + } +} + +/** @typedef {import('../photoswipe.js').Point} Point */ +/** @typedef {import('./gestures.js').default} Gestures */ + +const UPPER_ZOOM_FRICTION = 0.05; +const LOWER_ZOOM_FRICTION = 0.15; + + +/** + * Get center point between two points + * + * @param {Point} p + * @param {Point} p1 + * @param {Point} p2 + * @returns {Point} + */ +function getZoomPointsCenter(p, p1, p2) { + p.x = (p1.x + p2.x) / 2; + p.y = (p1.y + p2.y) / 2; + return p; +} + +class ZoomHandler { + /** + * @param {Gestures} gestures + */ + constructor(gestures) { + this.gestures = gestures; + /** + * @private + * @type {Point} + */ + this._startPan = { x: 0, y: 0 }; + /** + * @private + * @type {Point} + */ + this._startZoomPoint = { x: 0, y: 0 }; + /** + * @private + * @type {Point} + */ + this._zoomPoint = { x: 0, y: 0 }; + /** @private */ + this._wasOverFitZoomLevel = false; + /** @private */ + this._startZoomLevel = 1; + } + + start() { + const { currSlide } = this.gestures.pswp; + if (currSlide) { + this._startZoomLevel = currSlide.currZoomLevel; + equalizePoints(this._startPan, currSlide.pan); + } + + this.gestures.pswp.animations.stopAllPan(); + this._wasOverFitZoomLevel = false; + } + + change() { + const { p1, startP1, p2, startP2, pswp } = this.gestures; + const { currSlide } = pswp; + + if (!currSlide) { + return; + } + + const minZoomLevel = currSlide.zoomLevels.min; + const maxZoomLevel = currSlide.zoomLevels.max; + + if (!currSlide.isZoomable() || pswp.mainScroll.isShifted()) { + return; + } + + getZoomPointsCenter(this._startZoomPoint, startP1, startP2); + getZoomPointsCenter(this._zoomPoint, p1, p2); + + let currZoomLevel = (1 / getDistanceBetween(startP1, startP2)) + * getDistanceBetween(p1, p2) + * this._startZoomLevel; + + // slightly over the zoom.fit + if (currZoomLevel > currSlide.zoomLevels.initial + (currSlide.zoomLevels.initial / 15)) { + this._wasOverFitZoomLevel = true; + } + + if (currZoomLevel < minZoomLevel) { + if (pswp.options.pinchToClose + && !this._wasOverFitZoomLevel + && this._startZoomLevel <= currSlide.zoomLevels.initial) { + // fade out background if zooming out + const bgOpacity = 1 - ((minZoomLevel - currZoomLevel) / (minZoomLevel / 1.2)); + if (!pswp.dispatch('pinchClose', { bgOpacity }).defaultPrevented) { + pswp.applyBgOpacity(bgOpacity); + } + } else { + // Apply the friction if zoom level is below the min + currZoomLevel = minZoomLevel - (minZoomLevel - currZoomLevel) * LOWER_ZOOM_FRICTION; + } + } else if (currZoomLevel > maxZoomLevel) { + // Apply the friction if zoom level is above the max + currZoomLevel = maxZoomLevel + (currZoomLevel - maxZoomLevel) * UPPER_ZOOM_FRICTION; + } + + currSlide.pan.x = this._calculatePanForZoomLevel('x', currZoomLevel); + currSlide.pan.y = this._calculatePanForZoomLevel('y', currZoomLevel); + + currSlide.setZoomLevel(currZoomLevel); + currSlide.applyCurrentZoomPan(); + } + + end() { + const { pswp } = this.gestures; + const { currSlide } = pswp; + if ((!currSlide || currSlide.currZoomLevel < currSlide.zoomLevels.initial) + && !this._wasOverFitZoomLevel + && pswp.options.pinchToClose) { + pswp.close(); + } else { + this.correctZoomPan(); + } + } + + /** + * @private + * @param {'x' | 'y'} axis + * @param {number} currZoomLevel + * @returns {number} + */ + _calculatePanForZoomLevel(axis, currZoomLevel) { + const zoomFactor = currZoomLevel / this._startZoomLevel; + return this._zoomPoint[axis] + - ((this._startZoomPoint[axis] - this._startPan[axis]) * zoomFactor); + } + + /** + * Correct currZoomLevel and pan if they are + * beyond minimum or maximum values. + * With animation. + * + * @param {boolean} [ignoreGesture] + * Wether gesture coordinates should be ignored when calculating destination pan position. + */ + correctZoomPan(ignoreGesture) { + const { pswp } = this.gestures; + const { currSlide } = pswp; + + if (!currSlide?.isZoomable()) { + return; + } + + if (this._zoomPoint.x === 0) { + ignoreGesture = true; + } + + const prevZoomLevel = currSlide.currZoomLevel; + + /** @type {number} */ + let destinationZoomLevel; + let currZoomLevelNeedsChange = true; + + if (prevZoomLevel < currSlide.zoomLevels.initial) { + destinationZoomLevel = currSlide.zoomLevels.initial; + // zoom to min + } else if (prevZoomLevel > currSlide.zoomLevels.max) { + destinationZoomLevel = currSlide.zoomLevels.max; + // zoom to max + } else { + currZoomLevelNeedsChange = false; + destinationZoomLevel = prevZoomLevel; + } + + const initialBgOpacity = pswp.bgOpacity; + const restoreBgOpacity = pswp.bgOpacity < 1; + + const initialPan = equalizePoints({ x: 0, y: 0 }, currSlide.pan); + let destinationPan = equalizePoints({ x: 0, y: 0 }, initialPan); + + if (ignoreGesture) { + this._zoomPoint.x = 0; + this._zoomPoint.y = 0; + this._startZoomPoint.x = 0; + this._startZoomPoint.y = 0; + this._startZoomLevel = prevZoomLevel; + equalizePoints(this._startPan, initialPan); + } + + if (currZoomLevelNeedsChange) { + destinationPan = { + x: this._calculatePanForZoomLevel('x', destinationZoomLevel), + y: this._calculatePanForZoomLevel('y', destinationZoomLevel) + }; + } + + // set zoom level, so pan bounds are updated according to it + currSlide.setZoomLevel(destinationZoomLevel); + + destinationPan = { + x: currSlide.bounds.correctPan('x', destinationPan.x), + y: currSlide.bounds.correctPan('y', destinationPan.y) + }; + + // return zoom level and its bounds to initial + currSlide.setZoomLevel(prevZoomLevel); + + const panNeedsChange = !pointsEqual(destinationPan, initialPan); + + if (!panNeedsChange && !currZoomLevelNeedsChange && !restoreBgOpacity) { + // update resolution after gesture + currSlide._setResolution(destinationZoomLevel); + currSlide.applyCurrentZoomPan(); + + // nothing to animate + return; + } + + pswp.animations.stopAllPan(); + + pswp.animations.startSpring({ + isPan: true, + start: 0, + end: 1000, + velocity: 0, + dampingRatio: 1, + naturalFrequency: 40, + onUpdate: (now) => { + now /= 1000; // 0 - start, 1 - end + + if (panNeedsChange || currZoomLevelNeedsChange) { + if (panNeedsChange) { + currSlide.pan.x = initialPan.x + (destinationPan.x - initialPan.x) * now; + currSlide.pan.y = initialPan.y + (destinationPan.y - initialPan.y) * now; + } + + if (currZoomLevelNeedsChange) { + const newZoomLevel = prevZoomLevel + + (destinationZoomLevel - prevZoomLevel) * now; + currSlide.setZoomLevel(newZoomLevel); + } + + currSlide.applyCurrentZoomPan(); + } + + // Restore background opacity + if (restoreBgOpacity && pswp.bgOpacity < 1) { + // We clamp opacity to keep it between 0 and 1. + // As progress ratio can be larger than 1 due to overshoot, + // and we do not want to bounce opacity. + pswp.applyBgOpacity(clamp( + initialBgOpacity + (1 - initialBgOpacity) * now, 0, 1 + )); + } + }, + onComplete: () => { + // update resolution after transition ends + currSlide._setResolution(destinationZoomLevel); + currSlide.applyCurrentZoomPan(); + } + }); + } +} + +/** + * @template {string} T + * @template {string} P + * @typedef {import('../types.js').AddPostfix} AddPostfix + */ + +/** @typedef {import('./gestures.js').default} Gestures */ +/** @typedef {import('../photoswipe.js').Point} Point */ + +/** @typedef {'imageClick' | 'bgClick' | 'tap' | 'doubleTap'} Actions */ + +/** + * Whether the tap was performed on the main slide + * (rather than controls or caption). + * + * @param {PointerEvent} event + * @returns {boolean} + */ +function didTapOnMainContent(event) { + return !!(/** @type {HTMLElement} */ (event.target).closest('.pswp__container')); +} + +/** + * Tap, double-tap handler. + */ +class TapHandler { + /** + * @param {Gestures} gestures + */ + constructor(gestures) { + this.gestures = gestures; + } + + /** + * @param {Point} point + * @param {PointerEvent} originalEvent + */ + click(point, originalEvent) { + const targetClassList = /** @type {HTMLElement} */ (originalEvent.target).classList; + const isImageClick = targetClassList.contains('pswp__img'); + const isBackgroundClick = targetClassList.contains('pswp__item') + || targetClassList.contains('pswp__zoom-wrap'); + + if (isImageClick) { + this._doClickOrTapAction('imageClick', point, originalEvent); + } else if (isBackgroundClick) { + this._doClickOrTapAction('bgClick', point, originalEvent); + } + } + + /** + * @param {Point} point + * @param {PointerEvent} originalEvent + */ + tap(point, originalEvent) { + if (didTapOnMainContent(originalEvent)) { + this._doClickOrTapAction('tap', point, originalEvent); + } + } + + /** + * @param {Point} point + * @param {PointerEvent} originalEvent + */ + doubleTap(point, originalEvent) { + if (didTapOnMainContent(originalEvent)) { + this._doClickOrTapAction('doubleTap', point, originalEvent); + } + } + + /** + * @private + * @param {Actions} actionName + * @param {Point} point + * @param {PointerEvent} originalEvent + */ + _doClickOrTapAction(actionName, point, originalEvent) { + const { pswp } = this.gestures; + const { currSlide } = pswp; + const actionFullName = /** @type {AddPostfix} */ (actionName + 'Action'); + const optionValue = pswp.options[actionFullName]; + + if (pswp.dispatch(actionFullName, { point, originalEvent }).defaultPrevented) { + return; + } + + if (typeof optionValue === 'function') { + optionValue.call(pswp, point, originalEvent); + return; + } + + switch (optionValue) { + case 'close': + case 'next': + pswp[optionValue](); + break; + case 'zoom': + currSlide?.toggleZoom(point); + break; + case 'zoom-or-close': + // by default click zooms current image, + // if it can not be zoomed - gallery will be closed + if (currSlide?.isZoomable() + && currSlide.zoomLevels.secondary !== currSlide.zoomLevels.initial) { + currSlide.toggleZoom(point); + } else if (pswp.options.clickToCloseNonZoomable) { + pswp.close(); + } + break; + case 'toggle-controls': + this.gestures.pswp.element?.classList.toggle('pswp--ui-visible'); + // if (_controlsVisible) { + // _ui.hideControls(); + // } else { + // _ui.showControls(); + // } + break; + } + } +} + +/** @typedef {import('../photoswipe.js').default} PhotoSwipe */ +/** @typedef {import('../photoswipe.js').Point} Point */ + +// How far should user should drag +// until we can determine that the gesture is swipe and its direction +const AXIS_SWIPE_HYSTERISIS = 10; +//const PAN_END_FRICTION = 0.35; + +const DOUBLE_TAP_DELAY = 300; // ms +const MIN_TAP_DISTANCE = 25; // px + +/** + * Gestures class bind touch, pointer or mouse events + * and emits drag to drag-handler and zoom events zoom-handler. + * + * Drag and zoom events are emited in requestAnimationFrame, + * and only when one of pointers was actually changed. + */ +class Gestures { + /** + * @param {PhotoSwipe} pswp + */ + constructor(pswp) { + this.pswp = pswp; + + /** @type {'x' | 'y' | null} */ + this.dragAxis = null; + + // point objects are defined once and reused + // PhotoSwipe keeps track only of two pointers, others are ignored + /** @type {Point} */ + this.p1 = { x: 0, y: 0 }; // the first pressed pointer + /** @type {Point} */ + this.p2 = { x: 0, y: 0 }; // the second pressed pointer + /** @type {Point} */ + this.prevP1 = { x: 0, y: 0 }; + /** @type {Point} */ + this.prevP2 = { x: 0, y: 0 }; + /** @type {Point} */ + this.startP1 = { x: 0, y: 0 }; + /** @type {Point} */ + this.startP2 = { x: 0, y: 0 }; + /** @type {Point} */ + this.velocity = { x: 0, y: 0 }; + + /** @type {Point} + * @private + */ + this._lastStartP1 = { x: 0, y: 0 }; + /** @type {Point} + * @private + */ + this._intervalP1 = { x: 0, y: 0 }; + /** @private */ + this._numActivePoints = 0; + /** @type {Point[]} + * @private + */ + this._ongoingPointers = []; + /** @private */ + this._touchEventEnabled = 'ontouchstart' in window; + /** @private */ + this._pointerEventEnabled = !!(window.PointerEvent); + this.supportsTouch = this._touchEventEnabled + || (this._pointerEventEnabled && navigator.maxTouchPoints > 1); + /** @private */ + this._numActivePoints = 0; + /** @private */ + this._intervalTime = 0; + /** @private */ + this._velocityCalculated = false; + this.isMultitouch = false; + this.isDragging = false; + this.isZooming = false; + /** @type {number | null} */ + this.raf = null; + /** @type {NodeJS.Timeout | null} + * @private + */ + this._tapTimer = null; + + if (!this.supportsTouch) { + // disable pan to next slide for non-touch devices + pswp.options.allowPanToNext = false; + } + + this.drag = new DragHandler(this); + this.zoomLevels = new ZoomHandler(this); + this.tapHandler = new TapHandler(this); + + pswp.on('bindEvents', () => { + pswp.events.add( + pswp.scrollWrap, + 'click', + /** @type EventListener */(this._onClick.bind(this)) + ); + + if (this._pointerEventEnabled) { + this._bindEvents('pointer', 'down', 'up', 'cancel'); + } else if (this._touchEventEnabled) { + this._bindEvents('touch', 'start', 'end', 'cancel'); + + // In previous versions we also bound mouse event here, + // in case device supports both touch and mouse events, + // but newer versions of browsers now support PointerEvent. + + // on iOS10 if you bind touchmove/end after touchstart, + // and you don't preventDefault touchstart (which PhotoSwipe does), + // preventDefault will have no effect on touchmove and touchend. + // Unless you bind it previously. + if (pswp.scrollWrap) { + pswp.scrollWrap.ontouchmove = () => {}; + pswp.scrollWrap.ontouchend = () => {}; + } + } else { + this._bindEvents('mouse', 'down', 'up'); + } + }); + } + + /** + * @private + * @param {'mouse' | 'touch' | 'pointer'} pref + * @param {'down' | 'start'} down + * @param {'up' | 'end'} up + * @param {'cancel'} [cancel] + */ + _bindEvents(pref, down, up, cancel) { + const { pswp } = this; + const { events } = pswp; + + const cancelEvent = cancel ? pref + cancel : ''; + + events.add( + pswp.scrollWrap, + pref + down, + /** @type EventListener */(this.onPointerDown.bind(this)) + ); + events.add(window, pref + 'move', /** @type EventListener */(this.onPointerMove.bind(this))); + events.add(window, pref + up, /** @type EventListener */(this.onPointerUp.bind(this))); + if (cancelEvent) { + events.add( + pswp.scrollWrap, + cancelEvent, + /** @type EventListener */(this.onPointerUp.bind(this)) + ); + } + } + + /** + * @param {PointerEvent} e + */ + onPointerDown(e) { + // We do not call preventDefault for touch events + // to allow browser to show native dialog on longpress + // (the one that allows to save image or open it in new tab). + // + // Desktop Safari allows to drag images when preventDefault isn't called on mousedown, + // even though preventDefault IS called on mousemove. That's why we preventDefault mousedown. + const isMousePointer = e.type === 'mousedown' || e.pointerType === 'mouse'; + + // Allow dragging only via left mouse button. + // http://www.quirksmode.org/js/events_properties.html + // https://developer.mozilla.org/en-US/docs/Web/API/event.button + if (isMousePointer && e.button > 0) { + return; + } + + const { pswp } = this; + + // if PhotoSwipe is opening or closing + if (!pswp.opener.isOpen) { + e.preventDefault(); + return; + } + + if (pswp.dispatch('pointerDown', { originalEvent: e }).defaultPrevented) { + return; + } + + if (isMousePointer) { + pswp.mouseDetected(); + + // preventDefault mouse event to prevent + // browser image drag feature + this._preventPointerEventBehaviour(e); + } + + pswp.animations.stopAll(); + + this._updatePoints(e, 'down'); + + if (this._numActivePoints === 1) { + this.dragAxis = null; + // we need to store initial point to determine the main axis, + // drag is activated only after the axis is determined + equalizePoints(this.startP1, this.p1); + } + + if (this._numActivePoints > 1) { + // Tap or double tap should not trigger if more than one pointer + this._clearTapTimer(); + this.isMultitouch = true; + } else { + this.isMultitouch = false; + } + } + + /** + * @param {PointerEvent} e + */ + onPointerMove(e) { + e.preventDefault(); // always preventDefault move event + + if (!this._numActivePoints) { + return; + } + + this._updatePoints(e, 'move'); + + if (this.pswp.dispatch('pointerMove', { originalEvent: e }).defaultPrevented) { + return; + } + + if (this._numActivePoints === 1 && !this.isDragging) { + if (!this.dragAxis) { + this._calculateDragDirection(); + } + + // Drag axis was detected, emit drag.start + if (this.dragAxis && !this.isDragging) { + if (this.isZooming) { + this.isZooming = false; + this.zoomLevels.end(); + } + + this.isDragging = true; + this._clearTapTimer(); // Tap can not trigger after drag + + // Adjust starting point + this._updateStartPoints(); + this._intervalTime = Date.now(); + //this._startTime = this._intervalTime; + this._velocityCalculated = false; + equalizePoints(this._intervalP1, this.p1); + this.velocity.x = 0; + this.velocity.y = 0; + this.drag.start(); + + this._rafStopLoop(); + this._rafRenderLoop(); + } + } else if (this._numActivePoints > 1 && !this.isZooming) { + this._finishDrag(); + + this.isZooming = true; + + // Adjust starting points + this._updateStartPoints(); + + this.zoomLevels.start(); + + this._rafStopLoop(); + this._rafRenderLoop(); + } + } + + /** + * @private + */ + _finishDrag() { + if (this.isDragging) { + this.isDragging = false; + + // Try to calculate velocity, + // if it wasn't calculated yet in drag.change + if (!this._velocityCalculated) { + this._updateVelocity(true); + } + + this.drag.end(); + this.dragAxis = null; + } + } + + /** + * @param {PointerEvent} e + */ + onPointerUp(e) { + if (!this._numActivePoints) { + return; + } + + this._updatePoints(e, 'up'); + + if (this.pswp.dispatch('pointerUp', { originalEvent: e }).defaultPrevented) { + return; + } + + if (this._numActivePoints === 0) { + this._rafStopLoop(); + + if (this.isDragging) { + this._finishDrag(); + } else if (!this.isZooming && !this.isMultitouch) { + //this.zoomLevels.correctZoomPan(); + this._finishTap(e); + } + } + + if (this._numActivePoints < 2 && this.isZooming) { + this.isZooming = false; + this.zoomLevels.end(); + + if (this._numActivePoints === 1) { + // Since we have 1 point left, we need to reinitiate drag + this.dragAxis = null; + this._updateStartPoints(); + } + } + } + + /** + * @private + */ + _rafRenderLoop() { + if (this.isDragging || this.isZooming) { + this._updateVelocity(); + + if (this.isDragging) { + // make sure that pointer moved since the last update + if (!pointsEqual(this.p1, this.prevP1)) { + this.drag.change(); + } + } else /* if (this.isZooming) */ { + if (!pointsEqual(this.p1, this.prevP1) + || !pointsEqual(this.p2, this.prevP2)) { + this.zoomLevels.change(); + } + } + + this._updatePrevPoints(); + this.raf = requestAnimationFrame(this._rafRenderLoop.bind(this)); + } + } + + /** + * Update velocity at 50ms interval + * + * @private + * @param {boolean} [force] + */ + _updateVelocity(force) { + const time = Date.now(); + const duration = time - this._intervalTime; + + if (duration < 50 && !force) { + return; + } + + + this.velocity.x = this._getVelocity('x', duration); + this.velocity.y = this._getVelocity('y', duration); + + this._intervalTime = time; + equalizePoints(this._intervalP1, this.p1); + this._velocityCalculated = true; + } + + /** + * @private + * @param {PointerEvent} e + */ + _finishTap(e) { + const { mainScroll } = this.pswp; + + // Do not trigger tap events if main scroll is shifted + if (mainScroll.isShifted()) { + // restore main scroll position + // (usually happens if stopped in the middle of animation) + mainScroll.moveIndexBy(0, true); + return; + } + + // Do not trigger tap for touchcancel or pointercancel + if (e.type.indexOf('cancel') > 0) { + return; + } + + // Trigger click instead of tap for mouse events + if (e.type === 'mouseup' || e.pointerType === 'mouse') { + this.tapHandler.click(this.startP1, e); + return; + } + + // Disable delay if there is no doubleTapAction + const tapDelay = this.pswp.options.doubleTapAction ? DOUBLE_TAP_DELAY : 0; + + // If tapTimer is defined - we tapped recently, + // check if the current tap is close to the previous one, + // if yes - trigger double tap + if (this._tapTimer) { + this._clearTapTimer(); + // Check if two taps were more or less on the same place + if (getDistanceBetween(this._lastStartP1, this.startP1) < MIN_TAP_DISTANCE) { + this.tapHandler.doubleTap(this.startP1, e); + } + } else { + equalizePoints(this._lastStartP1, this.startP1); + this._tapTimer = setTimeout(() => { + this.tapHandler.tap(this.startP1, e); + this._clearTapTimer(); + }, tapDelay); + } + } + + /** + * @private + */ + _clearTapTimer() { + if (this._tapTimer) { + clearTimeout(this._tapTimer); + this._tapTimer = null; + } + } + + /** + * Get velocity for axis + * + * @private + * @param {'x' | 'y'} axis + * @param {number} duration + * @returns {number} + */ + _getVelocity(axis, duration) { + // displacement is like distance, but can be negative. + const displacement = this.p1[axis] - this._intervalP1[axis]; + + if (Math.abs(displacement) > 1 && duration > 5) { + return displacement / duration; + } + + return 0; + } + + /** + * @private + */ + _rafStopLoop() { + if (this.raf) { + cancelAnimationFrame(this.raf); + this.raf = null; + } + } + + /** + * @private + * @param {PointerEvent} e + */ + _preventPointerEventBehaviour(e) { + // TODO find a way to disable e.preventDefault on some elements + // via event or some class or something + e.preventDefault(); + } + + /** + * Parses and normalizes points from the touch, mouse or pointer event. + * Updates p1 and p2. + * + * @private + * @param {PointerEvent | TouchEvent} e + * @param {'up' | 'down' | 'move'} pointerType Normalized pointer type + */ + _updatePoints(e, pointerType) { + if (this._pointerEventEnabled) { + const pointerEvent = /** @type {PointerEvent} */ (e); + // Try to find the current pointer in ongoing pointers by its ID + const pointerIndex = this._ongoingPointers.findIndex((ongoingPointer) => { + return ongoingPointer.id === pointerEvent.pointerId; + }); + + if (pointerType === 'up' && pointerIndex > -1) { + // release the pointer - remove it from ongoing + this._ongoingPointers.splice(pointerIndex, 1); + } else if (pointerType === 'down' && pointerIndex === -1) { + // add new pointer + this._ongoingPointers.push(this._convertEventPosToPoint(pointerEvent, { x: 0, y: 0 })); + } else if (pointerIndex > -1) { + // update existing pointer + this._convertEventPosToPoint(pointerEvent, this._ongoingPointers[pointerIndex]); + } + + this._numActivePoints = this._ongoingPointers.length; + + // update points that PhotoSwipe uses + // to calculate position and scale + if (this._numActivePoints > 0) { + equalizePoints(this.p1, this._ongoingPointers[0]); + } + + if (this._numActivePoints > 1) { + equalizePoints(this.p2, this._ongoingPointers[1]); + } + } else { + const touchEvent = /** @type {TouchEvent} */ (e); + + this._numActivePoints = 0; + if (touchEvent.type.indexOf('touch') > -1) { + // Touch Event + // https://developer.mozilla.org/en-US/docs/Web/API/TouchEvent + if (touchEvent.touches && touchEvent.touches.length > 0) { + this._convertEventPosToPoint(touchEvent.touches[0], this.p1); + this._numActivePoints++; + if (touchEvent.touches.length > 1) { + this._convertEventPosToPoint(touchEvent.touches[1], this.p2); + this._numActivePoints++; + } + } + } else { + // Mouse Event + this._convertEventPosToPoint(/** @type {PointerEvent} */ (e), this.p1); + if (pointerType === 'up') { + // clear all points on mouseup + this._numActivePoints = 0; + } else { + this._numActivePoints++; + } + } + } + } + + /** update points that were used during previous rAF tick + * @private + */ + _updatePrevPoints() { + equalizePoints(this.prevP1, this.p1); + equalizePoints(this.prevP2, this.p2); + } + + /** update points at the start of gesture + * @private + */ + _updateStartPoints() { + equalizePoints(this.startP1, this.p1); + equalizePoints(this.startP2, this.p2); + this._updatePrevPoints(); + } + + /** @private */ + _calculateDragDirection() { + if (this.pswp.mainScroll.isShifted()) { + // if main scroll position is shifted – direction is always horizontal + this.dragAxis = 'x'; + } else { + // calculate delta of the last touchmove tick + const diff = Math.abs(this.p1.x - this.startP1.x) - Math.abs(this.p1.y - this.startP1.y); + + if (diff !== 0) { + // check if pointer was shifted horizontally or vertically + const axisToCheck = diff > 0 ? 'x' : 'y'; + + if (Math.abs(this.p1[axisToCheck] - this.startP1[axisToCheck]) >= AXIS_SWIPE_HYSTERISIS) { + this.dragAxis = axisToCheck; + } + } + } + } + + /** + * Converts touch, pointer or mouse event + * to PhotoSwipe point. + * + * @private + * @param {Touch | PointerEvent} e + * @param {Point} p + * @returns {Point} + */ + _convertEventPosToPoint(e, p) { + p.x = e.pageX - this.pswp.offset.x; + p.y = e.pageY - this.pswp.offset.y; + + if ('pointerId' in e) { + p.id = e.pointerId; + } else if (e.identifier !== undefined) { + p.id = e.identifier; + } + + return p; + } + + /** + * @private + * @param {PointerEvent} e + */ + _onClick(e) { + // Do not allow click event to pass through after drag + if (this.pswp.mainScroll.isShifted()) { + e.preventDefault(); + e.stopPropagation(); + } + } +} + +/** @typedef {import('./photoswipe.js').default} PhotoSwipe */ +/** @typedef {import('./slide/slide.js').default} Slide */ + +/** @typedef {{ el: HTMLDivElement; slide?: Slide }} ItemHolder */ + +const MAIN_SCROLL_END_FRICTION = 0.35; + + +// const MIN_SWIPE_TRANSITION_DURATION = 250; +// const MAX_SWIPE_TRABSITION_DURATION = 500; +// const DEFAULT_SWIPE_TRANSITION_DURATION = 333; + +/** + * Handles movement of the main scrolling container + * (for example, it repositions when user swipes left or right). + * + * Also stores its state. + */ +class MainScroll { + /** + * @param {PhotoSwipe} pswp + */ + constructor(pswp) { + this.pswp = pswp; + this.x = 0; + this.slideWidth = 0; + /** @private */ + this._currPositionIndex = 0; + /** @private */ + this._prevPositionIndex = 0; + /** @private */ + this._containerShiftIndex = -1; + + /** @type {ItemHolder[]} */ + this.itemHolders = []; + } + + /** + * Position the scroller and slide containers + * according to viewport size. + * + * @param {boolean} [resizeSlides] Whether slides content should resized + */ + resize(resizeSlides) { + const { pswp } = this; + const newSlideWidth = Math.round( + pswp.viewportSize.x + pswp.viewportSize.x * pswp.options.spacing + ); + // Mobile browsers might trigger a resize event during a gesture. + // (due to toolbar appearing or hiding). + // Avoid re-adjusting main scroll position if width wasn't changed + const slideWidthChanged = (newSlideWidth !== this.slideWidth); + + if (slideWidthChanged) { + this.slideWidth = newSlideWidth; + this.moveTo(this.getCurrSlideX()); + } + + this.itemHolders.forEach((itemHolder, index) => { + if (slideWidthChanged) { + setTransform(itemHolder.el, (index + this._containerShiftIndex) + * this.slideWidth); + } + + if (resizeSlides && itemHolder.slide) { + itemHolder.slide.resize(); + } + }); + } + + /** + * Reset X position of the main scroller to zero + */ + resetPosition() { + // Position on the main scroller (offset) + // it is independent from slide index + this._currPositionIndex = 0; + this._prevPositionIndex = 0; + + // This will force recalculation of size on next resize() + this.slideWidth = 0; + + // _containerShiftIndex*viewportSize will give you amount of transform of the current slide + this._containerShiftIndex = -1; + } + + /** + * Create and append array of three items + * that hold data about slides in DOM + */ + appendHolders() { + this.itemHolders = []; + + // append our three slide holders - + // previous, current, and next + for (let i = 0; i < 3; i++) { + const el = createElement('pswp__item', 'div', this.pswp.container); + el.setAttribute('role', 'group'); + el.setAttribute('aria-roledescription', 'slide'); + el.setAttribute('aria-hidden', 'true'); + + // hide nearby item holders until initial zoom animation finishes (to avoid extra Paints) + el.style.display = (i === 1) ? 'block' : 'none'; + + this.itemHolders.push({ + el, + //index: -1 + }); + } + } + + /** + * Whether the main scroll can be horizontally swiped to the next or previous slide. + * @returns {boolean} + */ + canBeSwiped() { + return this.pswp.getNumItems() > 1; + } + + /** + * Move main scroll by X amount of slides. + * For example: + * `-1` will move to the previous slide, + * `0` will reset the scroll position of the current slide, + * `3` will move three slides forward + * + * If loop option is enabled - index will be automatically looped too, + * (for example `-1` will move to the last slide of the gallery). + * + * @param {number} diff + * @param {boolean} [animate] + * @param {number} [velocityX] + * @returns {boolean} whether index was changed or not + */ + moveIndexBy(diff, animate, velocityX) { + const { pswp } = this; + let newIndex = pswp.potentialIndex + diff; + const numSlides = pswp.getNumItems(); + + if (pswp.canLoop()) { + newIndex = pswp.getLoopedIndex(newIndex); + const distance = (diff + numSlides) % numSlides; + if (distance <= numSlides / 2) { + // go forward + diff = distance; + } else { + // go backwards + diff = distance - numSlides; + } + } else { + if (newIndex < 0) { + newIndex = 0; + } else if (newIndex >= numSlides) { + newIndex = numSlides - 1; + } + diff = newIndex - pswp.potentialIndex; + } + + pswp.potentialIndex = newIndex; + this._currPositionIndex -= diff; + + pswp.animations.stopMainScroll(); + + const destinationX = this.getCurrSlideX(); + if (!animate) { + this.moveTo(destinationX); + this.updateCurrItem(); + } else { + pswp.animations.startSpring({ + isMainScroll: true, + start: this.x, + end: destinationX, + velocity: velocityX || 0, + naturalFrequency: 30, + dampingRatio: 1, //0.7, + onUpdate: (x) => { + this.moveTo(x); + }, + onComplete: () => { + this.updateCurrItem(); + pswp.appendHeavy(); + } + }); + + let currDiff = pswp.potentialIndex - pswp.currIndex; + if (pswp.canLoop()) { + const currDistance = (currDiff + numSlides) % numSlides; + if (currDistance <= numSlides / 2) { + // go forward + currDiff = currDistance; + } else { + // go backwards + currDiff = currDistance - numSlides; + } + } + + // Force-append new slides during transition + // if difference between slides is more than 1 + if (Math.abs(currDiff) > 1) { + this.updateCurrItem(); + } + } + + return Boolean(diff); + } + + /** + * X position of the main scroll for the current slide + * (ignores position during dragging) + * @returns {number} + */ + getCurrSlideX() { + return this.slideWidth * this._currPositionIndex; + } + + /** + * Whether scroll position is shifted. + * For example, it will return true if the scroll is being dragged or animated. + * @returns {boolean} + */ + isShifted() { + return this.x !== this.getCurrSlideX(); + } + + /** + * Update slides X positions and set their content + */ + updateCurrItem() { + const { pswp } = this; + const positionDifference = this._prevPositionIndex - this._currPositionIndex; + + if (!positionDifference) { + return; + } + + this._prevPositionIndex = this._currPositionIndex; + + pswp.currIndex = pswp.potentialIndex; + + let diffAbs = Math.abs(positionDifference); + /** @type {ItemHolder | undefined} */ + let tempHolder; + + if (diffAbs >= 3) { + this._containerShiftIndex += positionDifference + (positionDifference > 0 ? -3 : 3); + diffAbs = 3; + } + + for (let i = 0; i < diffAbs; i++) { + if (positionDifference > 0) { + tempHolder = this.itemHolders.shift(); + if (tempHolder) { + this.itemHolders[2] = tempHolder; // move first to last + + this._containerShiftIndex++; + + setTransform(tempHolder.el, (this._containerShiftIndex + 2) * this.slideWidth); + + pswp.setContent(tempHolder, (pswp.currIndex - diffAbs) + i + 2); + } + } else { + tempHolder = this.itemHolders.pop(); + if (tempHolder) { + this.itemHolders.unshift(tempHolder); // move last to first + + this._containerShiftIndex--; + + setTransform(tempHolder.el, this._containerShiftIndex * this.slideWidth); + + pswp.setContent(tempHolder, (pswp.currIndex + diffAbs) - i - 2); + } + } + } + + // Reset transfrom every 50ish navigations in one direction. + // + // Otherwise transform will keep growing indefinitely, + // which might cause issues as browsers have a maximum transform limit. + // I wasn't able to reach it, but just to be safe. + // This should not cause noticable lag. + if (Math.abs(this._containerShiftIndex) > 50 && !this.isShifted()) { + this.resetPosition(); + this.resize(); + } + + // Pan transition might be running (and consntantly updating pan position) + pswp.animations.stopAllPan(); + + this.itemHolders.forEach((itemHolder, i) => { + if (itemHolder.slide) { + // Slide in the 2nd holder is always active + itemHolder.slide.setIsActive(i === 1); + } + }); + + pswp.currSlide = this.itemHolders[1]?.slide; + pswp.contentLoader.updateLazy(positionDifference); + + if (pswp.currSlide) { + pswp.currSlide.applyCurrentZoomPan(); + } + + pswp.dispatch('change'); + } + + /** + * Move the X position of the main scroll container + * + * @param {number} x + * @param {boolean} [dragging] + */ + moveTo(x, dragging) { + if (!this.pswp.canLoop() && dragging) { + // Apply friction + let newSlideIndexOffset = ((this.slideWidth * this._currPositionIndex) - x) / this.slideWidth; + newSlideIndexOffset += this.pswp.currIndex; + const delta = Math.round(x - this.x); + + if ((newSlideIndexOffset < 0 && delta > 0) + || (newSlideIndexOffset >= this.pswp.getNumItems() - 1 && delta < 0)) { + x = this.x + (delta * MAIN_SCROLL_END_FRICTION); + } + } + + this.x = x; + + if (this.pswp.container) { + setTransform(this.pswp.container, x); + } + + this.pswp.dispatch('moveMainScroll', { x, dragging: dragging ?? false }); + } +} + +/** @typedef {import('./photoswipe.js').default} PhotoSwipe */ + +/** + * @template T + * @typedef {import('./types.js').Methods} Methods + */ + +const KeyboardKeyCodesMap = { + Escape: 27, + z: 90, + ArrowLeft: 37, + ArrowUp: 38, + ArrowRight: 39, + ArrowDown: 40, + Tab: 9, +}; + +/** + * @template {keyof KeyboardKeyCodesMap} T + * @param {T} key + * @param {boolean} isKeySupported + * @returns {T | number | undefined} + */ +const getKeyboardEventKey = (key, isKeySupported) => { + return isKeySupported ? key : KeyboardKeyCodesMap[key]; +}; + +/** + * - Manages keyboard shortcuts. + * - Helps trap focus within photoswipe. + */ +class Keyboard { + /** + * @param {PhotoSwipe} pswp + */ + constructor(pswp) { + this.pswp = pswp; + /** @private */ + this._wasFocused = false; + + pswp.on('bindEvents', () => { + // Dialog was likely opened by keyboard if initial point is not defined + if (!pswp.options.initialPointerPos) { + // focus causes layout, + // which causes lag during the animation, + // that's why we delay it until the opener transition ends + this._focusRoot(); + } + + pswp.events.add(document, 'focusin', /** @type EventListener */(this._onFocusIn.bind(this))); + pswp.events.add(document, 'keydown', /** @type EventListener */(this._onKeyDown.bind(this))); + }); + + const lastActiveElement = /** @type {HTMLElement} */ (document.activeElement); + pswp.on('destroy', () => { + if (pswp.options.returnFocus + && lastActiveElement + && this._wasFocused) { + lastActiveElement.focus(); + } + }); + } + + /** @private */ + _focusRoot() { + if (!this._wasFocused && this.pswp.element) { + this.pswp.element.focus(); + this._wasFocused = true; + } + } + + /** + * @private + * @param {KeyboardEvent} e + */ + _onKeyDown(e) { + const { pswp } = this; + + if (pswp.dispatch('keydown', { originalEvent: e }).defaultPrevented) { + return; + } + + if (specialKeyUsed(e)) { + // don't do anything if special key pressed + // to prevent from overriding default browser actions + // for example, in Chrome on Mac cmd+arrow-left returns to previous page + return; + } + + /** @type {Methods | undefined} */ + let keydownAction; + /** @type {'x' | 'y' | undefined} */ + let axis; + let isForward = false; + const isKeySupported = 'key' in e; + + switch (isKeySupported ? e.key : e.keyCode) { + case getKeyboardEventKey('Escape', isKeySupported): + if (pswp.options.escKey) { + keydownAction = 'close'; + } + break; + case getKeyboardEventKey('z', isKeySupported): + keydownAction = 'toggleZoom'; + break; + case getKeyboardEventKey('ArrowLeft', isKeySupported): + axis = 'x'; + break; + case getKeyboardEventKey('ArrowUp', isKeySupported): + axis = 'y'; + break; + case getKeyboardEventKey('ArrowRight', isKeySupported): + axis = 'x'; + isForward = true; + break; + case getKeyboardEventKey('ArrowDown', isKeySupported): + isForward = true; + axis = 'y'; + break; + case getKeyboardEventKey('Tab', isKeySupported): + this._focusRoot(); + break; + } + + // if left/right/top/bottom key + if (axis) { + // prevent page scroll + e.preventDefault(); + + const { currSlide } = pswp; + + if (pswp.options.arrowKeys + && axis === 'x' + && pswp.getNumItems() > 1) { + keydownAction = isForward ? 'next' : 'prev'; + } else if (currSlide && currSlide.currZoomLevel > currSlide.zoomLevels.fit) { + // up/down arrow keys pan the image vertically + // left/right arrow keys pan horizontally. + // Unless there is only one image, + // or arrowKeys option is disabled + currSlide.pan[axis] += isForward ? -80 : 80; + currSlide.panTo(currSlide.pan.x, currSlide.pan.y); + } + } + + if (keydownAction) { + e.preventDefault(); + // @ts-ignore + pswp[keydownAction](); + } + } + + /** + * Trap focus inside photoswipe + * + * @private + * @param {FocusEvent} e + */ + _onFocusIn(e) { + const { template } = this.pswp; + if (template + && document !== e.target + && template !== e.target + && !template.contains(/** @type {Node} */ (e.target))) { + // focus root element + template.focus(); + } + } +} + +const DEFAULT_EASING = 'cubic-bezier(.4,0,.22,1)'; + +/** @typedef {import('./animations.js').SharedAnimationProps} SharedAnimationProps */ + +/** @typedef {Object} DefaultCssAnimationProps + * + * @prop {HTMLElement} target + * @prop {number} [duration] + * @prop {string} [easing] + * @prop {string} [transform] + * @prop {string} [opacity] + * */ + +/** @typedef {SharedAnimationProps & DefaultCssAnimationProps} CssAnimationProps */ + +/** + * Runs CSS transition. + */ +class CSSAnimation { + /** + * onComplete can be unpredictable, be careful about current state + * + * @param {CssAnimationProps} props + */ + constructor(props) { + this.props = props; + const { + target, + onComplete, + transform, + onFinish = () => {}, + duration = 333, + easing = DEFAULT_EASING, + } = props; + + this.onFinish = onFinish; + + // support only transform and opacity + const prop = transform ? 'transform' : 'opacity'; + const propValue = props[prop] ?? ''; + + /** @private */ + this._target = target; + /** @private */ + this._onComplete = onComplete; + /** @private */ + this._finished = false; + + /** @private */ + this._onTransitionEnd = this._onTransitionEnd.bind(this); + + // Using timeout hack to make sure that animation + // starts even if the animated property was changed recently, + // otherwise transitionend might not fire or transition won't start. + // https://drafts.csswg.org/css-transitions/#starting + // + // ¯\_(ツ)_/¯ + /** @private */ + this._helperTimeout = setTimeout(() => { + setTransitionStyle(target, prop, duration, easing); + this._helperTimeout = setTimeout(() => { + target.addEventListener('transitionend', this._onTransitionEnd, false); + target.addEventListener('transitioncancel', this._onTransitionEnd, false); + + // Safari occasionally does not emit transitionend event + // if element property was modified during the transition, + // which may be caused by resize or third party component, + // using timeout as a safety fallback + this._helperTimeout = setTimeout(() => { + this._finalizeAnimation(); + }, duration + 500); + target.style[prop] = propValue; + }, 30); // Do not reduce this number + }, 0); + } + + /** + * @private + * @param {TransitionEvent} e + */ + _onTransitionEnd(e) { + if (e.target === this._target) { + this._finalizeAnimation(); + } + } + + /** + * @private + */ + _finalizeAnimation() { + if (!this._finished) { + this._finished = true; + this.onFinish(); + if (this._onComplete) { + this._onComplete(); + } + } + } + + // Destroy is called automatically onFinish + destroy() { + if (this._helperTimeout) { + clearTimeout(this._helperTimeout); + } + removeTransitionStyle(this._target); + this._target.removeEventListener('transitionend', this._onTransitionEnd, false); + this._target.removeEventListener('transitioncancel', this._onTransitionEnd, false); + if (!this._finished) { + this._finalizeAnimation(); + } + } +} + +const DEFAULT_NATURAL_FREQUENCY = 12; +const DEFAULT_DAMPING_RATIO = 0.75; + +/** + * Spring easing helper + */ +class SpringEaser { + /** + * @param {number} initialVelocity Initial velocity, px per ms. + * + * @param {number} [dampingRatio] + * Determines how bouncy animation will be. + * From 0 to 1, 0 - always overshoot, 1 - do not overshoot. + * "overshoot" refers to part of animation that + * goes beyond the final value. + * + * @param {number} [naturalFrequency] + * Determines how fast animation will slow down. + * The higher value - the stiffer the transition will be, + * and the faster it will slow down. + * Recommended value from 10 to 50 + */ + constructor(initialVelocity, dampingRatio, naturalFrequency) { + this.velocity = initialVelocity * 1000; // convert to "pixels per second" + + // https://en.wikipedia.org/wiki/Damping_ratio + this._dampingRatio = dampingRatio || DEFAULT_DAMPING_RATIO; + + // https://en.wikipedia.org/wiki/Natural_frequency + this._naturalFrequency = naturalFrequency || DEFAULT_NATURAL_FREQUENCY; + + this._dampedFrequency = this._naturalFrequency; + + if (this._dampingRatio < 1) { + this._dampedFrequency *= Math.sqrt(1 - this._dampingRatio * this._dampingRatio); + } + } + + /** + * @param {number} deltaPosition Difference between current and end position of the animation + * @param {number} deltaTime Frame duration in milliseconds + * + * @returns {number} Displacement, relative to the end position. + */ + easeFrame(deltaPosition, deltaTime) { + // Inspired by Apple Webkit and Android spring function implementation + // https://en.wikipedia.org/wiki/Oscillation + // https://en.wikipedia.org/wiki/Damping_ratio + // we ignore mass (assume that it's 1kg) + + let displacement = 0; + let coeff; + + deltaTime /= 1000; + + const naturalDumpingPow = Math.E ** (-this._dampingRatio * this._naturalFrequency * deltaTime); + + if (this._dampingRatio === 1) { + coeff = this.velocity + this._naturalFrequency * deltaPosition; + + displacement = (deltaPosition + coeff * deltaTime) * naturalDumpingPow; + + this.velocity = displacement + * (-this._naturalFrequency) + coeff + * naturalDumpingPow; + } else if (this._dampingRatio < 1) { + coeff = (1 / this._dampedFrequency) + * (this._dampingRatio * this._naturalFrequency * deltaPosition + this.velocity); + + const dumpedFCos = Math.cos(this._dampedFrequency * deltaTime); + const dumpedFSin = Math.sin(this._dampedFrequency * deltaTime); + + displacement = naturalDumpingPow + * (deltaPosition * dumpedFCos + coeff * dumpedFSin); + + this.velocity = displacement + * (-this._naturalFrequency) + * this._dampingRatio + + naturalDumpingPow + * (-this._dampedFrequency * deltaPosition * dumpedFSin + + this._dampedFrequency * coeff * dumpedFCos); + } + + // Overdamped (>1) damping ratio is not supported + + return displacement; + } +} + +/** @typedef {import('./animations.js').SharedAnimationProps} SharedAnimationProps */ + +/** + * @typedef {Object} DefaultSpringAnimationProps + * + * @prop {number} start + * @prop {number} end + * @prop {number} velocity + * @prop {number} [dampingRatio] + * @prop {number} [naturalFrequency] + * @prop {(end: number) => void} onUpdate + */ + +/** @typedef {SharedAnimationProps & DefaultSpringAnimationProps} SpringAnimationProps */ + +class SpringAnimation { + /** + * @param {SpringAnimationProps} props + */ + constructor(props) { + this.props = props; + this._raf = 0; + + const { + start, + end, + velocity, + onUpdate, + onComplete, + onFinish = () => {}, + dampingRatio, + naturalFrequency + } = props; + + this.onFinish = onFinish; + + const easer = new SpringEaser(velocity, dampingRatio, naturalFrequency); + let prevTime = Date.now(); + let deltaPosition = start - end; + + const animationLoop = () => { + if (this._raf) { + deltaPosition = easer.easeFrame(deltaPosition, Date.now() - prevTime); + + // Stop the animation if velocity is low and position is close to end + if (Math.abs(deltaPosition) < 1 && Math.abs(easer.velocity) < 50) { + // Finalize the animation + onUpdate(end); + if (onComplete) { + onComplete(); + } + this.onFinish(); + } else { + prevTime = Date.now(); + onUpdate(deltaPosition + end); + this._raf = requestAnimationFrame(animationLoop); + } + } + }; + + this._raf = requestAnimationFrame(animationLoop); + } + + // Destroy is called automatically onFinish + destroy() { + if (this._raf >= 0) { + cancelAnimationFrame(this._raf); + } + this._raf = 0; + } +} + +/** @typedef {import('./css-animation.js').CssAnimationProps} CssAnimationProps */ +/** @typedef {import('./spring-animation.js').SpringAnimationProps} SpringAnimationProps */ + +/** @typedef {Object} SharedAnimationProps + * @prop {string} [name] + * @prop {boolean} [isPan] + * @prop {boolean} [isMainScroll] + * @prop {VoidFunction} [onComplete] + * @prop {VoidFunction} [onFinish] + */ + +/** @typedef {SpringAnimation | CSSAnimation} Animation */ +/** @typedef {SpringAnimationProps | CssAnimationProps} AnimationProps */ + +/** + * Manages animations + */ +class Animations { + constructor() { + /** @type {Animation[]} */ + this.activeAnimations = []; + } + + /** + * @param {SpringAnimationProps} props + */ + startSpring(props) { + this._start(props, true); + } + + /** + * @param {CssAnimationProps} props + */ + startTransition(props) { + this._start(props); + } + + /** + * @private + * @param {AnimationProps} props + * @param {boolean} [isSpring] + * @returns {Animation} + */ + _start(props, isSpring) { + const animation = isSpring + ? new SpringAnimation(/** @type SpringAnimationProps */ (props)) + : new CSSAnimation(/** @type CssAnimationProps */ (props)); + + this.activeAnimations.push(animation); + animation.onFinish = () => this.stop(animation); + + return animation; + } + + /** + * @param {Animation} animation + */ + stop(animation) { + animation.destroy(); + const index = this.activeAnimations.indexOf(animation); + if (index > -1) { + this.activeAnimations.splice(index, 1); + } + } + + stopAll() { // _stopAllAnimations + this.activeAnimations.forEach((animation) => { + animation.destroy(); + }); + this.activeAnimations = []; + } + + /** + * Stop all pan or zoom transitions + */ + stopAllPan() { + this.activeAnimations = this.activeAnimations.filter((animation) => { + if (animation.props.isPan) { + animation.destroy(); + return false; + } + + return true; + }); + } + + stopMainScroll() { + this.activeAnimations = this.activeAnimations.filter((animation) => { + if (animation.props.isMainScroll) { + animation.destroy(); + return false; + } + + return true; + }); + } + + /** + * Returns true if main scroll transition is running + */ + // isMainScrollRunning() { + // return this.activeAnimations.some((animation) => { + // return animation.props.isMainScroll; + // }); + // } + + /** + * Returns true if any pan or zoom transition is running + */ + isPanRunning() { + return this.activeAnimations.some((animation) => { + return animation.props.isPan; + }); + } +} + +/** @typedef {import('./photoswipe.js').default} PhotoSwipe */ + +/** + * Handles scroll wheel. + * Can pan and zoom current slide image. + */ +class ScrollWheel { + /** + * @param {PhotoSwipe} pswp + */ + constructor(pswp) { + this.pswp = pswp; + pswp.events.add(pswp.element, 'wheel', /** @type EventListener */(this._onWheel.bind(this))); + } + + /** + * @private + * @param {WheelEvent} e + */ + _onWheel(e) { + e.preventDefault(); + const { currSlide } = this.pswp; + let { deltaX, deltaY } = e; + + if (!currSlide) { + return; + } + + if (this.pswp.dispatch('wheel', { originalEvent: e }).defaultPrevented) { + return; + } + + if (e.ctrlKey || this.pswp.options.wheelToZoom) { + // zoom + if (currSlide.isZoomable()) { + let zoomFactor = -deltaY; + if (e.deltaMode === 1 /* DOM_DELTA_LINE */) { + zoomFactor *= 0.05; + } else { + zoomFactor *= e.deltaMode ? 1 : 0.002; + } + zoomFactor = 2 ** zoomFactor; + + const destZoomLevel = currSlide.currZoomLevel * zoomFactor; + currSlide.zoomTo(destZoomLevel, { + x: e.clientX, + y: e.clientY + }); + } + } else { + // pan + if (currSlide.isPannable()) { + if (e.deltaMode === 1 /* DOM_DELTA_LINE */) { + // 18 - average line height + deltaX *= 18; + deltaY *= 18; + } + + currSlide.panTo( + currSlide.pan.x - deltaX, + currSlide.pan.y - deltaY + ); + } + } + } +} + +/** @typedef {import('../photoswipe.js').default} PhotoSwipe */ + +/** + * @template T + * @typedef {import('../types.js').Methods} Methods + */ + +/** + * @typedef {Object} UIElementMarkupProps + * @prop {boolean} [isCustomSVG] + * @prop {string} inner + * @prop {string} [outlineID] + * @prop {number | string} [size] + */ + +/** + * @typedef {Object} UIElementData + * @prop {DefaultUIElements | string} [name] + * @prop {string} [className] + * @prop {UIElementMarkup} [html] + * @prop {boolean} [isButton] + * @prop {keyof HTMLElementTagNameMap} [tagName] + * @prop {string} [title] + * @prop {string} [ariaLabel] + * @prop {(element: HTMLElement, pswp: PhotoSwipe) => void} [onInit] + * @prop {Methods | ((e: MouseEvent, element: HTMLElement, pswp: PhotoSwipe) => void)} [onClick] + * @prop {'bar' | 'wrapper' | 'root'} [appendTo] + * @prop {number} [order] + */ + +/** @typedef {'arrowPrev' | 'arrowNext' | 'close' | 'zoom' | 'counter'} DefaultUIElements */ + +/** @typedef {string | UIElementMarkupProps} UIElementMarkup */ + +/** + * @param {UIElementMarkup} [htmlData] + * @returns {string} + */ +function addElementHTML(htmlData) { + if (typeof htmlData === 'string') { + // Allow developers to provide full svg, + // For example: + // + // Can also be any HTML string. + return htmlData; + } + + if (!htmlData || !htmlData.isCustomSVG) { + return ''; + } + + const svgData = htmlData; + let out = ''; + + return out; +} + +class UIElement { + /** + * @param {PhotoSwipe} pswp + * @param {UIElementData} data + */ + constructor(pswp, data) { + const name = data.name || data.className; + let elementHTML = data.html; + + // @ts-expect-error lookup only by `data.name` maybe? + if (pswp.options[name] === false) { + // exit if element is disabled from options + return; + } + + // Allow to override SVG icons from options + // @ts-expect-error lookup only by `data.name` maybe? + if (typeof pswp.options[name + 'SVG'] === 'string') { + // arrowPrevSVG + // arrowNextSVG + // closeSVG + // zoomSVG + // @ts-expect-error lookup only by `data.name` maybe? + elementHTML = pswp.options[name + 'SVG']; + } + + pswp.dispatch('uiElementCreate', { data }); + + let className = ''; + if (data.isButton) { + className += 'pswp__button '; + className += (data.className || `pswp__button--${data.name}`); + } else { + className += (data.className || `pswp__${data.name}`); + } + + let tagName = data.isButton ? (data.tagName || 'button') : (data.tagName || 'div'); + tagName = /** @type {keyof HTMLElementTagNameMap} */ (tagName.toLowerCase()); + /** @type {HTMLElement} */ + const element = createElement(className, tagName); + + if (data.isButton) { + if (tagName === 'button') { + /** @type {HTMLButtonElement} */ (element).type = 'button'; + } + + let { title } = data; + const { ariaLabel } = data; + + // @ts-expect-error lookup only by `data.name` maybe? + if (typeof pswp.options[name + 'Title'] === 'string') { + // @ts-expect-error lookup only by `data.name` maybe? + title = pswp.options[name + 'Title']; + } + + if (title) { + element.title = title; + } + + const ariaText = ariaLabel || title; + if (ariaText) { + element.setAttribute('aria-label', ariaText); + } + } + + element.innerHTML = addElementHTML(elementHTML); + + if (data.onInit) { + data.onInit(element, pswp); + } + + if (data.onClick) { + element.onclick = (e) => { + if (typeof data.onClick === 'string') { + // @ts-ignore + pswp[data.onClick](); + } else if (typeof data.onClick === 'function') { + data.onClick(e, element, pswp); + } + }; + } + + // Top bar is default position + const appendTo = data.appendTo || 'bar'; + /** @type {HTMLElement | undefined} root element by default */ + let container = pswp.element; + if (appendTo === 'bar') { + if (!pswp.topBar) { + pswp.topBar = createElement('pswp__top-bar pswp__hide-on-close', 'div', pswp.scrollWrap); + } + container = pswp.topBar; + } else { + // element outside of top bar gets a secondary class + // that makes element fade out on close + element.classList.add('pswp__hide-on-close'); + + if (appendTo === 'wrapper') { + container = pswp.scrollWrap; + } + } + + container?.appendChild(pswp.applyFilters('uiElement', element, data)); + } +} + +/* + Backward and forward arrow buttons + */ + +/** @typedef {import('./ui-element.js').UIElementData} UIElementData */ +/** @typedef {import('../photoswipe.js').default} PhotoSwipe */ + +/** + * + * @param {HTMLElement} element + * @param {PhotoSwipe} pswp + * @param {boolean} [isNextButton] + */ +function initArrowButton(element, pswp, isNextButton) { + element.classList.add('pswp__button--arrow'); + // TODO: this should point to a unique id for this instance + element.setAttribute('aria-controls', 'pswp__items'); + pswp.on('change', () => { + if (!pswp.options.loop) { + if (isNextButton) { + /** @type {HTMLButtonElement} */ + (element).disabled = !(pswp.currIndex < pswp.getNumItems() - 1); + } else { + /** @type {HTMLButtonElement} */ + (element).disabled = !(pswp.currIndex > 0); + } + } + }); +} + +/** @type {UIElementData} */ +const arrowPrev = { + name: 'arrowPrev', + className: 'pswp__button--arrow--prev', + title: 'Previous', + order: 10, + isButton: true, + appendTo: 'wrapper', + html: { + isCustomSVG: true, + size: 60, + inner: '', + outlineID: 'pswp__icn-arrow' + }, + onClick: 'prev', + onInit: initArrowButton +}; + +/** @type {UIElementData} */ +const arrowNext = { + name: 'arrowNext', + className: 'pswp__button--arrow--next', + title: 'Next', + order: 11, + isButton: true, + appendTo: 'wrapper', + html: { + isCustomSVG: true, + size: 60, + inner: '', + outlineID: 'pswp__icn-arrow' + }, + onClick: 'next', + onInit: (el, pswp) => { + initArrowButton(el, pswp, true); + } +}; + +/** @type {import('./ui-element.js').UIElementData} UIElementData */ +const closeButton = { + name: 'close', + title: 'Close', + order: 20, + isButton: true, + html: { + isCustomSVG: true, + inner: '', + outlineID: 'pswp__icn-close' + }, + onClick: 'close' +}; + +/** @type {import('./ui-element.js').UIElementData} UIElementData */ +const zoomButton = { + name: 'zoom', + title: 'Zoom', + order: 10, + isButton: true, + html: { + isCustomSVG: true, + // eslint-disable-next-line max-len + inner: '' + + '' + + '', + outlineID: 'pswp__icn-zoom' + }, + onClick: 'toggleZoom' +}; + +/** @type {import('./ui-element.js').UIElementData} UIElementData */ +const loadingIndicator = { + name: 'preloader', + appendTo: 'bar', + order: 7, + html: { + isCustomSVG: true, + // eslint-disable-next-line max-len + inner: '', + outlineID: 'pswp__icn-loading' + }, + onInit: (indicatorElement, pswp) => { + /** @type {boolean | undefined} */ + let isVisible; + /** @type {NodeJS.Timeout | null} */ + let delayTimeout = null; + + /** + * @param {string} className + * @param {boolean} add + */ + const toggleIndicatorClass = (className, add) => { + indicatorElement.classList.toggle('pswp__preloader--' + className, add); + }; + + /** + * @param {boolean} visible + */ + const setIndicatorVisibility = (visible) => { + if (isVisible !== visible) { + isVisible = visible; + toggleIndicatorClass('active', visible); + } + }; + + const updatePreloaderVisibility = () => { + if (!pswp.currSlide?.content.isLoading()) { + setIndicatorVisibility(false); + if (delayTimeout) { + clearTimeout(delayTimeout); + delayTimeout = null; + } + return; + } + + if (!delayTimeout) { + // display loading indicator with delay + delayTimeout = setTimeout(() => { + setIndicatorVisibility(Boolean(pswp.currSlide?.content.isLoading())); + delayTimeout = null; + }, pswp.options.preloaderDelay); + } + }; + + pswp.on('change', updatePreloaderVisibility); + + pswp.on('loadComplete', (e) => { + if (pswp.currSlide === e.slide) { + updatePreloaderVisibility(); + } + }); + + // expose the method + if (pswp.ui) { + pswp.ui.updatePreloaderVisibility = updatePreloaderVisibility; + } + } +}; + +/** @type {import('./ui-element.js').UIElementData} UIElementData */ +const counterIndicator = { + name: 'counter', + order: 5, + onInit: (counterElement, pswp) => { + pswp.on('change', () => { + counterElement.innerText = (pswp.currIndex + 1) + + pswp.options.indexIndicatorSep + + pswp.getNumItems(); + }); + } +}; + +/** @typedef {import('../photoswipe.js').default} PhotoSwipe */ +/** @typedef {import('./ui-element.js').UIElementData} UIElementData */ + +/** + * Set special class on element when image is zoomed. + * + * By default, it is used to adjust + * zoom icon and zoom cursor via CSS. + * + * @param {HTMLElement} el + * @param {boolean} isZoomedIn + */ +function setZoomedIn(el, isZoomedIn) { + el.classList.toggle('pswp--zoomed-in', isZoomedIn); +} + +class UI { + /** + * @param {PhotoSwipe} pswp + */ + constructor(pswp) { + this.pswp = pswp; + this.isRegistered = false; + /** @type {UIElementData[]} */ + this.uiElementsData = []; + /** @type {(UIElement | UIElementData)[]} */ + this.items = []; + /** @type {() => void} */ + this.updatePreloaderVisibility = () => {}; + + /** + * @private + * @type {number | undefined} + */ + this._lastUpdatedZoomLevel = undefined; + } + + init() { + const { pswp } = this; + this.isRegistered = false; + this.uiElementsData = [ + closeButton, + arrowPrev, + arrowNext, + zoomButton, + loadingIndicator, + counterIndicator + ]; + + pswp.dispatch('uiRegister'); + + // sort by order + this.uiElementsData.sort((a, b) => { + // default order is 0 + return (a.order || 0) - (b.order || 0); + }); + + this.items = []; + + this.isRegistered = true; + this.uiElementsData.forEach((uiElementData) => { + this.registerElement(uiElementData); + }); + + pswp.on('change', () => { + pswp.element?.classList.toggle('pswp--one-slide', pswp.getNumItems() === 1); + }); + + pswp.on('zoomPanUpdate', () => this._onZoomPanUpdate()); + } + + /** + * @param {UIElementData} elementData + */ + registerElement(elementData) { + if (this.isRegistered) { + this.items.push( + new UIElement(this.pswp, elementData) + ); + } else { + this.uiElementsData.push(elementData); + } + } + + /** + * Fired each time zoom or pan position is changed. + * Update classes that control visibility of zoom button and cursor icon. + * + * @private + */ + _onZoomPanUpdate() { + const { template, currSlide, options } = this.pswp; + + if (this.pswp.opener.isClosing || !template || !currSlide) { + return; + } + + let { currZoomLevel } = currSlide; + + // if not open yet - check against initial zoom level + if (!this.pswp.opener.isOpen) { + currZoomLevel = currSlide.zoomLevels.initial; + } + + if (currZoomLevel === this._lastUpdatedZoomLevel) { + return; + } + this._lastUpdatedZoomLevel = currZoomLevel; + + const currZoomLevelDiff = currSlide.zoomLevels.initial - currSlide.zoomLevels.secondary; + + // Initial and secondary zoom levels are almost equal + if (Math.abs(currZoomLevelDiff) < 0.01 || !currSlide.isZoomable()) { + // disable zoom + setZoomedIn(template, false); + template.classList.remove('pswp--zoom-allowed'); + return; + } + + template.classList.add('pswp--zoom-allowed'); + + const potentialZoomLevel = currZoomLevel === currSlide.zoomLevels.initial + ? currSlide.zoomLevels.secondary : currSlide.zoomLevels.initial; + + setZoomedIn(template, potentialZoomLevel <= currZoomLevel); + + if (options.imageClickAction === 'zoom' + || options.imageClickAction === 'zoom-or-close') { + template.classList.add('pswp--click-to-zoom'); + } + } +} + +/** @typedef {import('./slide.js').SlideData} SlideData */ +/** @typedef {import('../photoswipe.js').default} PhotoSwipe */ + +/** @typedef {{ x: number; y: number; w: number; innerRect?: { w: number; h: number; x: number; y: number } }} Bounds */ + +/** + * @param {HTMLElement} el + * @returns Bounds + */ +function getBoundsByElement(el) { + const thumbAreaRect = el.getBoundingClientRect(); + return { + x: thumbAreaRect.left, + y: thumbAreaRect.top, + w: thumbAreaRect.width + }; +} + +/** + * @param {HTMLElement} el + * @param {number} imageWidth + * @param {number} imageHeight + * @returns Bounds + */ +function getCroppedBoundsByElement(el, imageWidth, imageHeight) { + const thumbAreaRect = el.getBoundingClientRect(); + + // fill image into the area + // (do they same as object-fit:cover does to retrieve coordinates) + const hRatio = thumbAreaRect.width / imageWidth; + const vRatio = thumbAreaRect.height / imageHeight; + const fillZoomLevel = hRatio > vRatio ? hRatio : vRatio; + + const offsetX = (thumbAreaRect.width - imageWidth * fillZoomLevel) / 2; + const offsetY = (thumbAreaRect.height - imageHeight * fillZoomLevel) / 2; + + /** + * Coordinates of the image, + * as if it was not cropped, + * height is calculated automatically + * + * @type {Bounds} + */ + const bounds = { + x: thumbAreaRect.left + offsetX, + y: thumbAreaRect.top + offsetY, + w: imageWidth * fillZoomLevel + }; + + // Coordinates of inner crop area + // relative to the image + bounds.innerRect = { + w: thumbAreaRect.width, + h: thumbAreaRect.height, + x: offsetX, + y: offsetY + }; + + return bounds; +} + +/** + * Get dimensions of thumbnail image + * (click on which opens photoswipe or closes photoswipe to) + * + * @param {number} index + * @param {SlideData} itemData + * @param {PhotoSwipe} instance PhotoSwipe instance + * @returns {Bounds | undefined} + */ +function getThumbBounds(index, itemData, instance) { + // legacy event, before filters were introduced + const event = instance.dispatch('thumbBounds', { + index, + itemData, + instance + }); + // @ts-expect-error + if (event.thumbBounds) { + // @ts-expect-error + return event.thumbBounds; + } + + const { element } = itemData; + /** @type {Bounds | undefined} */ + let thumbBounds; + /** @type {HTMLElement | null | undefined} */ + let thumbnail; + + if (element && instance.options.thumbSelector !== false) { + const thumbSelector = instance.options.thumbSelector || 'img'; + thumbnail = element.matches(thumbSelector) + ? element : /** @type {HTMLElement | null} */ (element.querySelector(thumbSelector)); + } + + thumbnail = instance.applyFilters('thumbEl', thumbnail, itemData, index); + + if (thumbnail) { + if (!itemData.thumbCropped) { + thumbBounds = getBoundsByElement(thumbnail); + } else { + thumbBounds = getCroppedBoundsByElement( + thumbnail, + itemData.width || itemData.w || 0, + itemData.height || itemData.h || 0 + ); + } + } + + return instance.applyFilters('thumbBounds', thumbBounds, itemData, index); +} + +/** @typedef {import('../lightbox/lightbox.js').default} PhotoSwipeLightbox */ +/** @typedef {import('../photoswipe.js').default} PhotoSwipe */ +/** @typedef {import('../photoswipe.js').PhotoSwipeOptions} PhotoSwipeOptions */ +/** @typedef {import('../photoswipe.js').DataSource} DataSource */ +/** @typedef {import('../ui/ui-element.js').UIElementData} UIElementData */ +/** @typedef {import('../slide/content.js').default} ContentDefault */ +/** @typedef {import('../slide/slide.js').default} Slide */ +/** @typedef {import('../slide/slide.js').SlideData} SlideData */ +/** @typedef {import('../slide/zoom-level.js').default} ZoomLevel */ +/** @typedef {import('../slide/get-thumb-bounds.js').Bounds} Bounds */ + +/** + * Allow adding an arbitrary props to the Content + * https://photoswipe.com/custom-content/#using-webp-image-format + * @typedef {ContentDefault & Record} Content + */ +/** @typedef {{ x?: number; y?: number }} Point */ + +/** + * @typedef {Object} PhotoSwipeEventsMap https://photoswipe.com/events/ + * + * + * https://photoswipe.com/adding-ui-elements/ + * + * @prop {undefined} uiRegister + * @prop {{ data: UIElementData }} uiElementCreate + * + * + * https://photoswipe.com/events/#initialization-events + * + * @prop {undefined} beforeOpen + * @prop {undefined} firstUpdate + * @prop {undefined} initialLayout + * @prop {undefined} change + * @prop {undefined} afterInit + * @prop {undefined} bindEvents + * + * + * https://photoswipe.com/events/#opening-or-closing-transition-events + * + * @prop {undefined} openingAnimationStart + * @prop {undefined} openingAnimationEnd + * @prop {undefined} closingAnimationStart + * @prop {undefined} closingAnimationEnd + * + * + * https://photoswipe.com/events/#closing-events + * + * @prop {undefined} close + * @prop {undefined} destroy + * + * + * https://photoswipe.com/events/#pointer-and-gesture-events + * + * @prop {{ originalEvent: PointerEvent }} pointerDown + * @prop {{ originalEvent: PointerEvent }} pointerMove + * @prop {{ originalEvent: PointerEvent }} pointerUp + * @prop {{ bgOpacity: number }} pinchClose can be default prevented + * @prop {{ panY: number }} verticalDrag can be default prevented + * + * + * https://photoswipe.com/events/#slide-content-events + * + * @prop {{ content: Content }} contentInit + * @prop {{ content: Content; isLazy: boolean }} contentLoad can be default prevented + * @prop {{ content: Content; isLazy: boolean }} contentLoadImage can be default prevented + * @prop {{ content: Content; slide: Slide; isError?: boolean }} loadComplete + * @prop {{ content: Content; slide: Slide }} loadError + * @prop {{ content: Content; width: number; height: number }} contentResize can be default prevented + * @prop {{ content: Content; width: number; height: number; slide: Slide }} imageSizeChange + * @prop {{ content: Content }} contentLazyLoad can be default prevented + * @prop {{ content: Content }} contentAppend can be default prevented + * @prop {{ content: Content }} contentActivate can be default prevented + * @prop {{ content: Content }} contentDeactivate can be default prevented + * @prop {{ content: Content }} contentRemove can be default prevented + * @prop {{ content: Content }} contentDestroy can be default prevented + * + * + * undocumented + * + * @prop {{ point: Point; originalEvent: PointerEvent }} imageClickAction can be default prevented + * @prop {{ point: Point; originalEvent: PointerEvent }} bgClickAction can be default prevented + * @prop {{ point: Point; originalEvent: PointerEvent }} tapAction can be default prevented + * @prop {{ point: Point; originalEvent: PointerEvent }} doubleTapAction can be default prevented + * + * @prop {{ originalEvent: KeyboardEvent }} keydown can be default prevented + * @prop {{ x: number; dragging: boolean }} moveMainScroll + * @prop {{ slide: Slide }} firstZoomPan + * @prop {{ slide: Slide | undefined, data: SlideData, index: number }} gettingData + * @prop {undefined} beforeResize + * @prop {undefined} resize + * @prop {undefined} viewportSize + * @prop {undefined} updateScrollOffset + * @prop {{ slide: Slide }} slideInit + * @prop {{ slide: Slide }} afterSetContent + * @prop {{ slide: Slide }} slideLoad + * @prop {{ slide: Slide }} appendHeavy can be default prevented + * @prop {{ slide: Slide }} appendHeavyContent + * @prop {{ slide: Slide }} slideActivate + * @prop {{ slide: Slide }} slideDeactivate + * @prop {{ slide: Slide }} slideDestroy + * @prop {{ destZoomLevel: number, centerPoint: Point | undefined, transitionDuration: number | false | undefined }} beforeZoomTo + * @prop {{ slide: Slide }} zoomPanUpdate + * @prop {{ slide: Slide }} initialZoomPan + * @prop {{ slide: Slide }} calcSlideSize + * @prop {undefined} resolutionChanged + * @prop {{ originalEvent: WheelEvent }} wheel can be default prevented + * @prop {{ content: Content }} contentAppendImage can be default prevented + * @prop {{ index: number; itemData: SlideData }} lazyLoadSlide can be default prevented + * @prop {undefined} lazyLoad + * @prop {{ slide: Slide }} calcBounds + * @prop {{ zoomLevels: ZoomLevel, slideData: SlideData }} zoomLevelsUpdate + * + * + * legacy + * + * @prop {undefined} init + * @prop {undefined} initialZoomIn + * @prop {undefined} initialZoomOut + * @prop {undefined} initialZoomInEnd + * @prop {undefined} initialZoomOutEnd + * @prop {{ dataSource: DataSource | undefined, numItems: number }} numItems + * @prop {{ itemData: SlideData; index: number }} itemData + * @prop {{ index: number, itemData: SlideData, instance: PhotoSwipe }} thumbBounds + */ + +/** + * @typedef {Object} PhotoSwipeFiltersMap https://photoswipe.com/filters/ + * + * @prop {(numItems: number, dataSource: DataSource | undefined) => number} numItems + * Modify the total amount of slides. Example on Data sources page. + * https://photoswipe.com/filters/#numitems + * + * @prop {(itemData: SlideData, index: number) => SlideData} itemData + * Modify slide item data. Example on Data sources page. + * https://photoswipe.com/filters/#itemdata + * + * @prop {(itemData: SlideData, element: HTMLElement, linkEl: HTMLAnchorElement) => SlideData} domItemData + * Modify item data when it's parsed from DOM element. Example on Data sources page. + * https://photoswipe.com/filters/#domitemdata + * + * @prop {(clickedIndex: number, e: MouseEvent, instance: PhotoSwipeLightbox) => number} clickedIndex + * Modify clicked gallery item index. + * https://photoswipe.com/filters/#clickedindex + * + * @prop {(placeholderSrc: string | false, content: Content) => string | false} placeholderSrc + * Modify placeholder image source. + * https://photoswipe.com/filters/#placeholdersrc + * + * @prop {(isContentLoading: boolean, content: Content) => boolean} isContentLoading + * Modify if the content is currently loading. + * https://photoswipe.com/filters/#iscontentloading + * + * @prop {(isContentZoomable: boolean, content: Content) => boolean} isContentZoomable + * Modify if the content can be zoomed. + * https://photoswipe.com/filters/#iscontentzoomable + * + * @prop {(useContentPlaceholder: boolean, content: Content) => boolean} useContentPlaceholder + * Modify if the placeholder should be used for the content. + * https://photoswipe.com/filters/#usecontentplaceholder + * + * @prop {(isKeepingPlaceholder: boolean, content: Content) => boolean} isKeepingPlaceholder + * Modify if the placeholder should be kept after the content is loaded. + * https://photoswipe.com/filters/#iskeepingplaceholder + * + * + * @prop {(contentErrorElement: HTMLElement, content: Content) => HTMLElement} contentErrorElement + * Modify an element when the content has error state (for example, if image cannot be loaded). + * https://photoswipe.com/filters/#contenterrorelement + * + * @prop {(element: HTMLElement, data: UIElementData) => HTMLElement} uiElement + * Modify a UI element that's being created. + * https://photoswipe.com/filters/#uielement + * + * @prop {(thumbnail: HTMLElement | null | undefined, itemData: SlideData, index: number) => HTMLElement} thumbEl + * Modify the thubmnail element from which opening zoom animation starts or ends. + * https://photoswipe.com/filters/#thumbel + * + * @prop {(thumbBounds: Bounds | undefined, itemData: SlideData, index: number) => Bounds} thumbBounds + * Modify the thubmnail bounds from which opening zoom animation starts or ends. + * https://photoswipe.com/filters/#thumbbounds + * + * @prop {(srcsetSizesWidth: number, content: Content) => number} srcsetSizesWidth + * + */ + +/** + * @template {keyof PhotoSwipeFiltersMap} T + * @typedef {{ fn: PhotoSwipeFiltersMap[T], priority: number }} Filter + */ + +/** + * @template {keyof PhotoSwipeEventsMap} T + * @typedef {PhotoSwipeEventsMap[T] extends undefined ? PhotoSwipeEvent : PhotoSwipeEvent & PhotoSwipeEventsMap[T]} AugmentedEvent + */ + +/** + * @template {keyof PhotoSwipeEventsMap} T + * @typedef {(event: AugmentedEvent) => void} EventCallback + */ + +/** + * Base PhotoSwipe event object + * + * @template {keyof PhotoSwipeEventsMap} T + */ +class PhotoSwipeEvent { + /** + * @param {T} type + * @param {PhotoSwipeEventsMap[T]} [details] + */ + constructor(type, details) { + this.type = type; + this.defaultPrevented = false; + 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() { + /** + * @type {{ [T in keyof PhotoSwipeEventsMap]?: ((event: AugmentedEvent) => void)[] }} + */ + this._listeners = {}; + + /** + * @type {{ [T in keyof PhotoSwipeFiltersMap]?: Filter[] }} + */ + this._filters = {}; + + /** @type {PhotoSwipe | undefined} */ + this.pswp = undefined; + + /** @type {PhotoSwipeOptions | undefined} */ + this.options = undefined; + } + + /** + * @template {keyof PhotoSwipeFiltersMap} T + * @param {T} name + * @param {PhotoSwipeFiltersMap[T]} fn + * @param {number} priority + */ + addFilter(name, fn, priority = 100) { + if (!this._filters[name]) { + this._filters[name] = []; + } + + this._filters[name]?.push({ fn, priority }); + this._filters[name]?.sort((f1, f2) => f1.priority - f2.priority); + + this.pswp?.addFilter(name, fn, priority); + } + + /** + * @template {keyof PhotoSwipeFiltersMap} T + * @param {T} name + * @param {PhotoSwipeFiltersMap[T]} fn + */ + removeFilter(name, fn) { + if (this._filters[name]) { + // @ts-expect-error + this._filters[name] = this._filters[name].filter(filter => (filter.fn !== fn)); + } + + if (this.pswp) { + this.pswp.removeFilter(name, fn); + } + } + + /** + * @template {keyof PhotoSwipeFiltersMap} T + * @param {T} name + * @param {Parameters} args + * @returns {Parameters[0]} + */ + applyFilters(name, ...args) { + this._filters[name]?.forEach((filter) => { + // @ts-expect-error + args[0] = filter.fn.apply(this, args); + }); + return args[0]; + } + + /** + * @template {keyof PhotoSwipeEventsMap} T + * @param {T} name + * @param {EventCallback} fn + */ + 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. + this.pswp?.on(name, fn); + } + + /** + * @template {keyof PhotoSwipeEventsMap} T + * @param {T} name + * @param {EventCallback} fn + */ + off(name, fn) { + if (this._listeners[name]) { + // @ts-expect-error + this._listeners[name] = this._listeners[name].filter(listener => (fn !== listener)); + } + + this.pswp?.off(name, fn); + } + + /** + * @template {keyof PhotoSwipeEventsMap} T + * @param {T} name + * @param {PhotoSwipeEventsMap[T]} [details] + * @returns {AugmentedEvent} + */ + dispatch(name, details) { + if (this.pswp) { + return this.pswp.dispatch(name, details); + } + + const event = /** @type {AugmentedEvent} */ (new PhotoSwipeEvent(name, details)); + + this._listeners[name]?.forEach((listener) => { + listener.call(this, event); + }); + + return event; + } +} + +class Placeholder { + /** + * @param {string | false} imageSrc + * @param {HTMLElement} container + */ + constructor(imageSrc, container) { + // Create placeholder + // (stretched thumbnail or simple div behind the main image) + /** @type {HTMLImageElement | HTMLDivElement | null} */ + this.element = createElement( + 'pswp__img pswp__img--placeholder', + imageSrc ? 'img' : 'div', + container + ); + + if (imageSrc) { + const imgEl = /** @type {HTMLImageElement} */ (this.element); + imgEl.decoding = 'async'; + imgEl.alt = ''; + imgEl.src = imageSrc; + imgEl.setAttribute('role', 'presentation'); + } + + this.element.setAttribute('aria-hidden', 'true'); + } + + /** + * @param {number} width + * @param {number} height + */ + setDisplayedSize(width, height) { + if (!this.element) { + return; + } + + if (this.element.tagName === 'IMG') { + // Use transform scale() to modify img placeholder size + // (instead of changing width/height directly). + // This helps with performance, specifically in iOS15 Safari. + setWidthHeight(this.element, 250, 'auto'); + this.element.style.transformOrigin = '0 0'; + this.element.style.transform = toTransformString(0, 0, width / 250); + } else { + setWidthHeight(this.element, width, height); + } + } + + destroy() { + if (this.element?.parentNode) { + this.element.remove(); + } + this.element = null; + } +} + +/** @typedef {import('./slide.js').default} Slide */ +/** @typedef {import('./slide.js').SlideData} SlideData */ +/** @typedef {import('../core/base.js').default} PhotoSwipeBase */ +/** @typedef {import('../util/util.js').LoadState} LoadState */ + +class Content { + /** + * @param {SlideData} itemData Slide data + * @param {PhotoSwipeBase} instance PhotoSwipe or PhotoSwipeLightbox instance + * @param {number} index + */ + constructor(itemData, instance, index) { + this.instance = instance; + this.data = itemData; + this.index = index; + + /** @type {HTMLImageElement | HTMLDivElement | undefined} */ + this.element = undefined; + /** @type {Placeholder | undefined} */ + this.placeholder = undefined; + /** @type {Slide | undefined} */ + this.slide = undefined; + + this.displayedImageWidth = 0; + this.displayedImageHeight = 0; + + this.width = Number(this.data.w) || Number(this.data.width) || 0; + this.height = Number(this.data.h) || Number(this.data.height) || 0; + + this.isAttached = false; + this.hasSlide = false; + this.isDecoding = false; + /** @type {LoadState} */ + this.state = LOAD_STATE.IDLE; + + if (this.data.type) { + this.type = this.data.type; + } else if (this.data.src) { + this.type = 'image'; + } else { + this.type = 'html'; + } + + this.instance.dispatch('contentInit', { content: this }); + } + + removePlaceholder() { + if (this.placeholder && !this.keepPlaceholder()) { + // With delay, as image might be loaded, but not rendered + setTimeout(() => { + if (this.placeholder) { + this.placeholder.destroy(); + this.placeholder = undefined; + } + }, 1000); + } + } + + /** + * Preload content + * + * @param {boolean} isLazy + * @param {boolean} [reload] + */ + load(isLazy, reload) { + if (this.slide && this.usePlaceholder()) { + if (!this.placeholder) { + const placeholderSrc = this.instance.applyFilters( + 'placeholderSrc', + // use image-based placeholder only for the first slide, + // as rendering (even small stretched thumbnail) is an expensive operation + (this.data.msrc && this.slide.isFirstSlide) ? this.data.msrc : false, + this + ); + this.placeholder = new Placeholder( + placeholderSrc, + this.slide.container + ); + } else { + const placeholderEl = this.placeholder.element; + // Add placeholder to DOM if it was already created + if (placeholderEl && !placeholderEl.parentElement) { + this.slide.container.prepend(placeholderEl); + } + } + } + + if (this.element && !reload) { + return; + } + + if (this.instance.dispatch('contentLoad', { content: this, isLazy }).defaultPrevented) { + return; + } + + if (this.isImageContent()) { + this.element = createElement('pswp__img', 'img'); + // Start loading only after width is defined, as sizes might depend on it. + // Due to Safari feature, we must define sizes before srcset. + if (this.displayedImageWidth) { + this.loadImage(isLazy); + } + } else { + this.element = createElement('pswp__content', 'div'); + this.element.innerHTML = this.data.html || ''; + } + + if (reload && this.slide) { + this.slide.updateContentSize(true); + } + } + + /** + * Preload image + * + * @param {boolean} isLazy + */ + loadImage(isLazy) { + if (!this.isImageContent() + || !this.element + || this.instance.dispatch('contentLoadImage', { content: this, isLazy }).defaultPrevented) { + return; + } + + const imageElement = /** @type HTMLImageElement */ (this.element); + + this.updateSrcsetSizes(); + + if (this.data.srcset) { + imageElement.srcset = this.data.srcset; + } + + imageElement.src = this.data.src ?? ''; + imageElement.alt = this.data.alt ?? ''; + + this.state = LOAD_STATE.LOADING; + + if (imageElement.complete) { + this.onLoaded(); + } else { + imageElement.onload = () => { + this.onLoaded(); + }; + + imageElement.onerror = () => { + this.onError(); + }; + } + } + + /** + * Assign slide to content + * + * @param {Slide} slide + */ + setSlide(slide) { + this.slide = slide; + this.hasSlide = true; + this.instance = slide.pswp; + + // todo: do we need to unset slide? + } + + /** + * Content load success handler + */ + onLoaded() { + this.state = LOAD_STATE.LOADED; + + if (this.slide && this.element) { + this.instance.dispatch('loadComplete', { slide: this.slide, content: this }); + + // if content is reloaded + if (this.slide.isActive + && this.slide.heavyAppended + && !this.element.parentNode) { + this.append(); + this.slide.updateContentSize(true); + } + + if (this.state === LOAD_STATE.LOADED || this.state === LOAD_STATE.ERROR) { + this.removePlaceholder(); + } + } + } + + /** + * Content load error handler + */ + onError() { + this.state = LOAD_STATE.ERROR; + + if (this.slide) { + this.displayError(); + this.instance.dispatch('loadComplete', { slide: this.slide, isError: true, content: this }); + this.instance.dispatch('loadError', { slide: this.slide, content: this }); + } + } + + /** + * @returns {Boolean} If the content is currently loading + */ + isLoading() { + return this.instance.applyFilters( + 'isContentLoading', + this.state === LOAD_STATE.LOADING, + this + ); + } + + /** + * @returns {Boolean} If the content is in error state + */ + isError() { + return this.state === LOAD_STATE.ERROR; + } + + /** + * @returns {boolean} If the content is image + */ + isImageContent() { + return this.type === 'image'; + } + + /** + * Update content size + * + * @param {Number} width + * @param {Number} height + */ + setDisplayedSize(width, height) { + if (!this.element) { + return; + } + + if (this.placeholder) { + this.placeholder.setDisplayedSize(width, height); + } + + if (this.instance.dispatch( + 'contentResize', + { content: this, width, height }).defaultPrevented + ) { + return; + } + + setWidthHeight(this.element, width, height); + + if (this.isImageContent() && !this.isError()) { + const isInitialSizeUpdate = (!this.displayedImageWidth && width); + + this.displayedImageWidth = width; + this.displayedImageHeight = height; + + if (isInitialSizeUpdate) { + this.loadImage(false); + } else { + this.updateSrcsetSizes(); + } + + if (this.slide) { + this.instance.dispatch( + 'imageSizeChange', + { slide: this.slide, width, height, content: this } + ); + } + } + } + + /** + * @returns {boolean} If the content can be zoomed + */ + isZoomable() { + return this.instance.applyFilters( + 'isContentZoomable', + this.isImageContent() && (this.state !== LOAD_STATE.ERROR), + this + ); + } + + /** + * Update image srcset sizes attribute based on width and height + */ + updateSrcsetSizes() { + // Handle srcset sizes attribute. + // + // Never lower quality, if it was increased previously. + // Chrome does this automatically, Firefox and Safari do not, + // so we store largest used size in dataset. + if (!this.isImageContent() || !this.element || !this.data.srcset) { + return; + } + + const image = /** @type HTMLImageElement */ (this.element); + const sizesWidth = this.instance.applyFilters( + 'srcsetSizesWidth', + this.displayedImageWidth, + this + ); + + if ( + !image.dataset.largestUsedSize + || sizesWidth > parseInt(image.dataset.largestUsedSize, 10) + ) { + image.sizes = sizesWidth + 'px'; + image.dataset.largestUsedSize = String(sizesWidth); + } + } + + /** + * @returns {boolean} If content should use a placeholder (from msrc by default) + */ + usePlaceholder() { + return this.instance.applyFilters( + 'useContentPlaceholder', + this.isImageContent(), + this + ); + } + + /** + * Preload content with lazy-loading param + */ + lazyLoad() { + if (this.instance.dispatch('contentLazyLoad', { content: this }).defaultPrevented) { + return; + } + + this.load(true); + } + + /** + * @returns {boolean} If placeholder should be kept after content is loaded + */ + keepPlaceholder() { + return this.instance.applyFilters( + 'isKeepingPlaceholder', + this.isLoading(), + this + ); + } + + /** + * Destroy the content + */ + destroy() { + this.hasSlide = false; + this.slide = undefined; + + if (this.instance.dispatch('contentDestroy', { content: this }).defaultPrevented) { + return; + } + + this.remove(); + + if (this.placeholder) { + this.placeholder.destroy(); + this.placeholder = undefined; + } + + if (this.isImageContent() && this.element) { + this.element.onload = null; + this.element.onerror = null; + this.element = undefined; + } + } + + /** + * Display error message + */ + displayError() { + if (this.slide) { + let errorMsgEl = createElement('pswp__error-msg', 'div'); + errorMsgEl.innerText = this.instance.options?.errorMsg ?? ''; + errorMsgEl = /** @type {HTMLDivElement} */ (this.instance.applyFilters( + 'contentErrorElement', + errorMsgEl, + this + )); + this.element = createElement('pswp__content pswp__error-msg-container', 'div'); + this.element.appendChild(errorMsgEl); + this.slide.container.innerText = ''; + this.slide.container.appendChild(this.element); + this.slide.updateContentSize(true); + this.removePlaceholder(); + } + } + + /** + * Append the content + */ + append() { + if (this.isAttached || !this.element) { + return; + } + + this.isAttached = true; + + if (this.state === LOAD_STATE.ERROR) { + this.displayError(); + return; + } + + if (this.instance.dispatch('contentAppend', { content: this }).defaultPrevented) { + return; + } + + const supportsDecode = ('decode' in this.element); + + if (this.isImageContent()) { + // Use decode() on nearby slides + // + // Nearby slide images are in DOM and not hidden via display:none. + // However, they are placed offscreen (to the left and right side). + // + // Some browsers do not composite the image until it's actually visible, + // using decode() helps. + // + // You might ask "why dont you just decode() and then append all images", + // that's because I want to show image before it's fully loaded, + // as browser can render parts of image while it is loading. + // We do not do this in Safari due to partial loading bug. + if (supportsDecode && this.slide && (!this.slide.isActive || isSafari())) { + this.isDecoding = true; + // purposefully using finally instead of then, + // as if srcset sizes changes dynamically - it may cause decode error + /** @type {HTMLImageElement} */ + (this.element).decode().catch(() => {}).finally(() => { + this.isDecoding = false; + this.appendImage(); + }); + } else { + this.appendImage(); + } + } else if (this.slide && !this.element.parentNode) { + this.slide.container.appendChild(this.element); + } + } + + /** + * Activate the slide, + * active slide is generally the current one, + * meaning the user can see it. + */ + activate() { + if (this.instance.dispatch('contentActivate', { content: this }).defaultPrevented + || !this.slide) { + return; + } + + if (this.isImageContent() && this.isDecoding && !isSafari()) { + // add image to slide when it becomes active, + // even if it's not finished decoding + this.appendImage(); + } else if (this.isError()) { + this.load(false, true); // try to reload + } + + if (this.slide.holderElement) { + this.slide.holderElement.setAttribute('aria-hidden', 'false'); + } + } + + /** + * Deactivate the content + */ + deactivate() { + this.instance.dispatch('contentDeactivate', { content: this }); + if (this.slide && this.slide.holderElement) { + this.slide.holderElement.setAttribute('aria-hidden', 'true'); + } + } + + + /** + * Remove the content from DOM + */ + remove() { + this.isAttached = false; + + if (this.instance.dispatch('contentRemove', { content: this }).defaultPrevented) { + return; + } + + if (this.element && this.element.parentNode) { + this.element.remove(); + } + + if (this.placeholder && this.placeholder.element) { + this.placeholder.element.remove(); + } + } + + /** + * Append the image content to slide container + */ + appendImage() { + if (!this.isAttached) { + return; + } + + if (this.instance.dispatch('contentAppendImage', { content: this }).defaultPrevented) { + return; + } + + // ensure that element exists and is not already appended + if (this.slide && this.element && !this.element.parentNode) { + this.slide.container.appendChild(this.element); + } + + if (this.state === LOAD_STATE.LOADED || this.state === LOAD_STATE.ERROR) { + this.removePlaceholder(); + } + } +} + +/** @typedef {import('./content.js').default} Content */ +/** @typedef {import('./slide.js').default} Slide */ +/** @typedef {import('./slide.js').SlideData} SlideData */ +/** @typedef {import('../core/base.js').default} PhotoSwipeBase */ +/** @typedef {import('../photoswipe.js').default} PhotoSwipe */ + +const MIN_SLIDES_TO_CACHE = 5; + +/** + * Lazy-load an image + * This function is used both by Lightbox and PhotoSwipe core, + * thus it can be called before dialog is opened. + * + * @param {SlideData} itemData Data about the slide + * @param {PhotoSwipeBase} instance PhotoSwipe or PhotoSwipeLightbox instance + * @param {number} index + * @returns {Content} Image that is being decoded or false. + */ +function lazyLoadData(itemData, instance, index) { + const content = instance.createContentFromData(itemData, index); + /** @type {ZoomLevel | undefined} */ + let zoomLevel; + + 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 + if (options) { + zoomLevel = new ZoomLevel(options, itemData, -1); + + let viewportSize; + if (instance.pswp) { + viewportSize = instance.pswp.viewportSize; + } else { + viewportSize = getViewportSize(options, instance); + } + + const panAreaSize = getPanAreaSize(options, viewportSize, itemData, index); + zoomLevel.update(content.width, content.height, panAreaSize); + } + + content.lazyLoad(); + + if (zoomLevel) { + content.setDisplayedSize( + Math.ceil(content.width * zoomLevel.initial), + Math.ceil(content.height * zoomLevel.initial) + ); + } + + return content; +} + + +/** + * 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 {number} index Slide index + * @param {PhotoSwipeBase} instance PhotoSwipe or PhotoSwipeLightbox eventable instance + * @returns {Content | undefined} + */ +function lazyLoadSlide(index, instance) { + const itemData = instance.getItemData(index); + + if (instance.dispatch('lazyLoadSlide', { index, itemData }).defaultPrevented) { + return; + } + + return lazyLoadData(itemData, instance, index); +} + +class ContentLoader { + /** + * @param {PhotoSwipe} pswp + */ + constructor(pswp) { + this.pswp = pswp; + // Total amount of cached images + this.limit = Math.max( + pswp.options.preload[0] + pswp.options.preload[1] + 1, + MIN_SLIDES_TO_CACHE + ); + /** @type {Content[]} */ + this._cachedItems = []; + } + + /** + * Lazy load nearby slides based on `preload` option. + * + * @param {number} [diff] Difference between slide indexes that was changed recently, or 0. + */ + updateLazy(diff) { + const { pswp } = this; + + if (pswp.dispatch('lazyLoad').defaultPrevented) { + return; + } + + const { preload } = pswp.options; + const isForward = diff === undefined ? true : (diff >= 0); + let i; + + // preload[1] - num items to preload in forward direction + for (i = 0; i <= preload[1]; i++) { + this.loadSlideByIndex(pswp.currIndex + (isForward ? i : (-i))); + } + + // preload[0] - num items to preload in backward direction + for (i = 1; i <= preload[0]; i++) { + this.loadSlideByIndex(pswp.currIndex + (isForward ? (-i) : i)); + } + } + + /** + * @param {number} initialIndex + */ + loadSlideByIndex(initialIndex) { + const index = this.pswp.getLoopedIndex(initialIndex); + // try to get cached content + let content = this.getContentByIndex(index); + if (!content) { + // no cached content, so try to load from scratch: + content = lazyLoadSlide(index, this.pswp); + // if content can be loaded, add it to cache: + if (content) { + this.addToCache(content); + } + } + } + + /** + * @param {Slide} slide + * @returns {Content} + */ + getContentBySlide(slide) { + let content = this.getContentByIndex(slide.index); + if (!content) { + // create content if not found in cache + content = this.pswp.createContentFromData(slide.data, slide.index); + this.addToCache(content); + } + + // assign slide to content + content.setSlide(slide); + + return content; + } + + /** + * @param {Content} content + */ + addToCache(content) { + // move to the end of array + this.removeByIndex(content.index); + this._cachedItems.push(content); + + if (this._cachedItems.length > this.limit) { + // Destroy the first content that's not attached + const indexToRemove = this._cachedItems.findIndex((item) => { + return !item.isAttached && !item.hasSlide; + }); + if (indexToRemove !== -1) { + const removedItem = this._cachedItems.splice(indexToRemove, 1)[0]; + removedItem.destroy(); + } + } + } + + /** + * Removes an image from cache, does not destroy() it, just removes. + * + * @param {number} index + */ + removeByIndex(index) { + const indexToRemove = this._cachedItems.findIndex(item => item.index === index); + if (indexToRemove !== -1) { + this._cachedItems.splice(indexToRemove, 1); + } + } + + /** + * @param {number} index + * @returns {Content | undefined} + */ + getContentByIndex(index) { + return this._cachedItems.find(content => content.index === index); + } + + destroy() { + this._cachedItems.forEach(content => content.destroy()); + this._cachedItems = []; + } +} + +/** @typedef {import("../photoswipe.js").default} PhotoSwipe */ +/** @typedef {import("../slide/slide.js").SlideData} SlideData */ + +/** + * 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 + * + * @returns {number} + */ + getNumItems() { + let numItems = 0; + const dataSource = this.options?.dataSource; + + if (dataSource && 'length' in dataSource) { + // may be an array or just object with length property + numItems = dataSource.length; + } else if (dataSource && 'gallery' in dataSource) { + // query DOM elements + if (!dataSource.items) { + dataSource.items = this._getGalleryDOMElements(dataSource.gallery); + } + + if (dataSource.items) { + numItems = dataSource.items.length; + } + } + + // legacy event, before filters were introduced + const event = this.dispatch('numItems', { + dataSource, + numItems + }); + return this.applyFilters('numItems', event.numItems, dataSource); + } + + /** + * @param {SlideData} slideData + * @param {number} index + * @returns {Content} + */ + createContentFromData(slideData, index) { + return new Content(slideData, this, index); + } + + /** + * 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 {number} index + * @returns {SlideData} + */ + getItemData(index) { + const dataSource = this.options?.dataSource; + /** @type {SlideData | HTMLElement} */ + let dataSourceItem = {}; + if (Array.isArray(dataSource)) { + // Datasource is an array of elements + dataSourceItem = dataSource[index]; + } else if (dataSource && 'gallery' in dataSource) { + // dataSource has gallery property, + // thus it was created by Lightbox, based on + // gallery and children 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); + } + + // Dispatching the itemData event, + // it's a legacy verion before filters were introduced + const event = this.dispatch('itemData', { + itemData: itemData || {}, + index + }); + + return this.applyFilters('itemData', event.itemData, index); + } + + /** + * Get array of gallery DOM elements, + * based on childSelector and gallery element. + * + * @param {HTMLElement} galleryElement + * @returns {HTMLElement[]} + */ + _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 {HTMLElement} element DOM element + * @returns {SlideData} + */ + _domElementToItemData(element) { + /** @type {SlideData} */ + const itemData = { + element + }; + + const linkEl = /** @type {HTMLAnchorElement} */ ( + element.tagName === 'A' + ? element + : element.querySelector('a') + ); + + if (linkEl) { + // src comes from data-pswp-src attribute, + // if it's empty link href is used + itemData.src = linkEl.dataset.pswpSrc || linkEl.href; + + if (linkEl.dataset.pswpSrcset) { + itemData.srcset = linkEl.dataset.pswpSrcset; + } + + itemData.width = linkEl.dataset.pswpWidth ? parseInt(linkEl.dataset.pswpWidth, 10) : 0; + itemData.height = linkEl.dataset.pswpHeight ? parseInt(linkEl.dataset.pswpHeight, 10) : 0; + + // support legacy w & h properties + itemData.w = itemData.width; + itemData.h = itemData.height; + + if (linkEl.dataset.pswpType) { + itemData.type = linkEl.dataset.pswpType; + } + + const thumbnailEl = element.querySelector('img'); + + if (thumbnailEl) { + // msrc is URL to placeholder image that's displayed before large image is loaded + // by default it's displayed only for the first slide + itemData.msrc = thumbnailEl.currentSrc || thumbnailEl.src; + itemData.alt = thumbnailEl.getAttribute('alt') ?? ''; + } + + if (linkEl.dataset.pswpCropped || linkEl.dataset.cropped) { + itemData.thumbCropped = true; + } + } + + return this.applyFilters('domItemData', itemData, element, linkEl); + } + + /** + * Lazy-load by slide data + * + * @param {SlideData} itemData Data about the slide + * @param {number} index + * @returns {Content} Image that is being decoded or false. + */ + lazyLoadData(itemData, index) { + return lazyLoadData(itemData, this, index); + } +} + +/** @typedef {import('./photoswipe.js').default} PhotoSwipe */ +/** @typedef {import('./slide/get-thumb-bounds.js').Bounds} Bounds */ +/** @typedef {import('./util/animations.js').AnimationProps} AnimationProps */ + +// some browsers do not paint +// elements which opacity is set to 0, +// since we need to pre-render elements for the animation - +// we set it to the minimum amount +const MIN_OPACITY = 0.003; + +/** + * Manages opening and closing transitions of the PhotoSwipe. + * + * It can perform zoom, fade or no transition. + */ +class Opener { + /** + * @param {PhotoSwipe} pswp + */ + constructor(pswp) { + this.pswp = pswp; + this.isClosed = true; + this.isOpen = false; + this.isClosing = false; + this.isOpening = false; + /** + * @private + * @type {number | false | undefined} + */ + this._duration = undefined; + /** @private */ + this._useAnimation = false; + /** @private */ + this._croppedZoom = false; + /** @private */ + this._animateRootOpacity = false; + /** @private */ + this._animateBgOpacity = false; + /** + * @private + * @type { HTMLDivElement | HTMLImageElement | null | undefined } + */ + this._placeholder = undefined; + /** + * @private + * @type { HTMLDivElement | undefined } + */ + this._opacityElement = undefined; + /** + * @private + * @type { HTMLDivElement | undefined } + */ + this._cropContainer1 = undefined; + /** + * @private + * @type { HTMLElement | null | undefined } + */ + this._cropContainer2 = undefined; + + /** + * @private + * @type {Bounds | undefined} + */ + this._thumbBounds = undefined; + + + this._prepareOpen = this._prepareOpen.bind(this); + + // Override initial zoom and pan position + pswp.on('firstZoomPan', this._prepareOpen); + } + + open() { + this._prepareOpen(); + this._start(); + } + + close() { + if (this.isClosed || this.isClosing || this.isOpening) { + // if we close during opening animation + // for now do nothing, + // browsers aren't good at changing the direction of the CSS transition + return; + } + + const slide = this.pswp.currSlide; + + this.isOpen = false; + this.isOpening = false; + this.isClosing = true; + this._duration = this.pswp.options.hideAnimationDuration; + + if (slide && slide.currZoomLevel * slide.width >= this.pswp.options.maxWidthToAnimate) { + this._duration = 0; + } + + this._applyStartProps(); + setTimeout(() => { + this._start(); + }, this._croppedZoom ? 30 : 0); + } + + /** @private */ + _prepareOpen() { + this.pswp.off('firstZoomPan', this._prepareOpen); + if (!this.isOpening) { + const slide = this.pswp.currSlide; + this.isOpening = true; + this.isClosing = false; + this._duration = this.pswp.options.showAnimationDuration; + if (slide && slide.zoomLevels.initial * slide.width >= this.pswp.options.maxWidthToAnimate) { + this._duration = 0; + } + this._applyStartProps(); + } + } + + /** @private */ + _applyStartProps() { + const { pswp } = this; + const slide = this.pswp.currSlide; + const { options } = pswp; + + if (options.showHideAnimationType === 'fade') { + options.showHideOpacity = true; + this._thumbBounds = undefined; + } else if (options.showHideAnimationType === 'none') { + options.showHideOpacity = false; + this._duration = 0; + this._thumbBounds = undefined; + } else if (this.isOpening && pswp._initialThumbBounds) { + // Use initial bounds if defined + this._thumbBounds = pswp._initialThumbBounds; + } else { + this._thumbBounds = this.pswp.getThumbBounds(); + } + + this._placeholder = slide?.getPlaceholderElement(); + + pswp.animations.stopAll(); + + // Discard animations when duration is less than 50ms + this._useAnimation = Boolean(this._duration && this._duration > 50); + this._animateZoom = Boolean(this._thumbBounds) + && slide?.content.usePlaceholder() + && (!this.isClosing || !pswp.mainScroll.isShifted()); + if (!this._animateZoom) { + this._animateRootOpacity = true; + + if (this.isOpening && slide) { + slide.zoomAndPanToInitial(); + slide.applyCurrentZoomPan(); + } + } else { + this._animateRootOpacity = options.showHideOpacity ?? false; + } + this._animateBgOpacity = !this._animateRootOpacity && this.pswp.options.bgOpacity > MIN_OPACITY; + this._opacityElement = this._animateRootOpacity ? pswp.element : pswp.bg; + + if (!this._useAnimation) { + this._duration = 0; + this._animateZoom = false; + this._animateBgOpacity = false; + this._animateRootOpacity = true; + if (this.isOpening) { + if (pswp.element) { + pswp.element.style.opacity = String(MIN_OPACITY); + } + pswp.applyBgOpacity(1); + } + return; + } + + if (this._animateZoom && this._thumbBounds && this._thumbBounds.innerRect) { + // Properties are used when animation from cropped thumbnail + this._croppedZoom = true; + this._cropContainer1 = this.pswp.container; + this._cropContainer2 = this.pswp.currSlide?.holderElement; + + if (pswp.container) { + pswp.container.style.overflow = 'hidden'; + pswp.container.style.width = pswp.viewportSize.x + 'px'; + } + } else { + this._croppedZoom = false; + } + + if (this.isOpening) { + // Apply styles before opening transition + if (this._animateRootOpacity) { + if (pswp.element) { + pswp.element.style.opacity = String(MIN_OPACITY); + } + pswp.applyBgOpacity(1); + } else { + if (this._animateBgOpacity && pswp.bg) { + pswp.bg.style.opacity = String(MIN_OPACITY); + } + if (pswp.element) { + pswp.element.style.opacity = '1'; + } + } + + if (this._animateZoom) { + this._setClosedStateZoomPan(); + if (this._placeholder) { + // tell browser that we plan to animate the placeholder + this._placeholder.style.willChange = 'transform'; + + // hide placeholder to allow hiding of + // elements that overlap it (such as icons over the thumbnail) + this._placeholder.style.opacity = String(MIN_OPACITY); + } + } + } else if (this.isClosing) { + // hide nearby slides to make sure that + // they are not painted during the transition + if (pswp.mainScroll.itemHolders[0]) { + pswp.mainScroll.itemHolders[0].el.style.display = 'none'; + } + if (pswp.mainScroll.itemHolders[2]) { + pswp.mainScroll.itemHolders[2].el.style.display = 'none'; + } + + if (this._croppedZoom) { + if (pswp.mainScroll.x !== 0) { + // shift the main scroller to zero position + pswp.mainScroll.resetPosition(); + pswp.mainScroll.resize(); + } + } + } + } + + /** @private */ + _start() { + if (this.isOpening + && this._useAnimation + && this._placeholder + && this._placeholder.tagName === 'IMG') { + // To ensure smooth animation + // we wait till the current slide image placeholder is decoded, + // but no longer than 250ms, + // and no shorter than 50ms + // (just using requestanimationframe is not enough in Firefox, + // for some reason) + new Promise((resolve) => { + let decoded = false; + let isDelaying = true; + decodeImage(/** @type {HTMLImageElement} */ (this._placeholder)).finally(() => { + decoded = true; + if (!isDelaying) { + resolve(true); + } + }); + setTimeout(() => { + isDelaying = false; + if (decoded) { + resolve(true); + } + }, 50); + setTimeout(resolve, 250); + }).finally(() => this._initiate()); + } else { + this._initiate(); + } + } + + /** @private */ + _initiate() { + this.pswp.element?.style.setProperty('--pswp-transition-duration', this._duration + 'ms'); + + this.pswp.dispatch( + this.isOpening ? 'openingAnimationStart' : 'closingAnimationStart' + ); + + // legacy event + this.pswp.dispatch( + /** @type {'initialZoomIn' | 'initialZoomOut'} */ + ('initialZoom' + (this.isOpening ? 'In' : 'Out')) + ); + + this.pswp.element?.classList.toggle('pswp--ui-visible', this.isOpening); + + if (this.isOpening) { + if (this._placeholder) { + // unhide the placeholder + this._placeholder.style.opacity = '1'; + } + this._animateToOpenState(); + } else if (this.isClosing) { + this._animateToClosedState(); + } + + if (!this._useAnimation) { + this._onAnimationComplete(); + } + } + + /** @private */ + _onAnimationComplete() { + const { pswp } = this; + this.isOpen = this.isOpening; + this.isClosed = this.isClosing; + this.isOpening = false; + this.isClosing = false; + + pswp.dispatch( + this.isOpen ? 'openingAnimationEnd' : 'closingAnimationEnd' + ); + + // legacy event + pswp.dispatch( + /** @type {'initialZoomInEnd' | 'initialZoomOutEnd'} */ + ('initialZoom' + (this.isOpen ? 'InEnd' : 'OutEnd')) + ); + + if (this.isClosed) { + pswp.destroy(); + } else if (this.isOpen) { + if (this._animateZoom && pswp.container) { + pswp.container.style.overflow = 'visible'; + pswp.container.style.width = '100%'; + } + pswp.currSlide?.applyCurrentZoomPan(); + } + } + + /** @private */ + _animateToOpenState() { + const { pswp } = this; + if (this._animateZoom) { + if (this._croppedZoom && this._cropContainer1 && this._cropContainer2) { + this._animateTo(this._cropContainer1, 'transform', 'translate3d(0,0,0)'); + this._animateTo(this._cropContainer2, 'transform', 'none'); + } + + if (pswp.currSlide) { + pswp.currSlide.zoomAndPanToInitial(); + this._animateTo( + pswp.currSlide.container, + 'transform', + pswp.currSlide.getCurrentTransform() + ); + } + } + + if (this._animateBgOpacity && pswp.bg) { + this._animateTo(pswp.bg, 'opacity', String(pswp.options.bgOpacity)); + } + + if (this._animateRootOpacity && pswp.element) { + this._animateTo(pswp.element, 'opacity', '1'); + } + } + + /** @private */ + _animateToClosedState() { + const { pswp } = this; + + if (this._animateZoom) { + this._setClosedStateZoomPan(true); + } + + // do not animate opacity if it's already at 0 + if (this._animateBgOpacity && pswp.bgOpacity > 0.01 && pswp.bg) { + this._animateTo(pswp.bg, 'opacity', '0'); + } + + if (this._animateRootOpacity && pswp.element) { + this._animateTo(pswp.element, 'opacity', '0'); + } + } + + /** + * @private + * @param {boolean} [animate] + */ + _setClosedStateZoomPan(animate) { + if (!this._thumbBounds) return; + + const { pswp } = this; + const { innerRect } = this._thumbBounds; + const { currSlide, viewportSize } = pswp; + + if (this._croppedZoom && innerRect && this._cropContainer1 && this._cropContainer2) { + const containerOnePanX = -viewportSize.x + (this._thumbBounds.x - innerRect.x) + innerRect.w; + const containerOnePanY = -viewportSize.y + (this._thumbBounds.y - innerRect.y) + innerRect.h; + const containerTwoPanX = viewportSize.x - innerRect.w; + const containerTwoPanY = viewportSize.y - innerRect.h; + + + if (animate) { + this._animateTo( + this._cropContainer1, + 'transform', + toTransformString(containerOnePanX, containerOnePanY) + ); + + this._animateTo( + this._cropContainer2, + 'transform', + toTransformString(containerTwoPanX, containerTwoPanY) + ); + } else { + setTransform(this._cropContainer1, containerOnePanX, containerOnePanY); + setTransform(this._cropContainer2, containerTwoPanX, containerTwoPanY); + } + } + + if (currSlide) { + equalizePoints(currSlide.pan, innerRect || this._thumbBounds); + currSlide.currZoomLevel = this._thumbBounds.w / currSlide.width; + if (animate) { + this._animateTo(currSlide.container, 'transform', currSlide.getCurrentTransform()); + } else { + currSlide.applyCurrentZoomPan(); + } + } + } + + /** + * @private + * @param {HTMLElement} target + * @param {'transform' | 'opacity'} prop + * @param {string} propValue + */ + _animateTo(target, prop, propValue) { + if (!this._duration) { + target.style[prop] = propValue; + return; + } + + const { animations } = this.pswp; + /** @type {AnimationProps} */ + const animProps = { + duration: this._duration, + easing: this.pswp.options.easing, + onComplete: () => { + if (!animations.activeAnimations.length) { + this._onAnimationComplete(); + } + }, + target, + }; + animProps[prop] = propValue; + animations.startTransition(animProps); + } +} + +/** + * @template T + * @typedef {import('./types.js').Type} Type + */ + +/** @typedef {import('./slide/slide.js').SlideData} SlideData */ +/** @typedef {import('./slide/zoom-level.js').ZoomLevelOption} ZoomLevelOption */ +/** @typedef {import('./ui/ui-element.js').UIElementData} UIElementData */ +/** @typedef {import('./main-scroll.js').ItemHolder} ItemHolder */ +/** @typedef {import('./core/eventable.js').PhotoSwipeEventsMap} PhotoSwipeEventsMap */ +/** @typedef {import('./core/eventable.js').PhotoSwipeFiltersMap} PhotoSwipeFiltersMap */ +/** @typedef {import('./slide/get-thumb-bounds').Bounds} Bounds */ +/** + * @template {keyof PhotoSwipeEventsMap} T + * @typedef {import('./core/eventable.js').EventCallback} EventCallback + */ +/** + * @template {keyof PhotoSwipeEventsMap} T + * @typedef {import('./core/eventable.js').AugmentedEvent} AugmentedEvent + */ + +/** @typedef {{ x: number; y: number; id?: string | number }} Point */ +/** @typedef {{ top: number; bottom: number; left: number; right: number }} Padding */ +/** @typedef {SlideData[]} DataSourceArray */ +/** @typedef {{ gallery: HTMLElement; items?: HTMLElement[] }} DataSourceObject */ +/** @typedef {DataSourceArray | DataSourceObject} DataSource */ +/** @typedef {(point: Point, originalEvent: PointerEvent) => void} ActionFn */ +/** @typedef {'close' | 'next' | 'zoom' | 'zoom-or-close' | 'toggle-controls'} ActionType */ +/** @typedef {Type | { default: Type }} PhotoSwipeModule */ +/** @typedef {PhotoSwipeModule | Promise | (() => Promise)} PhotoSwipeModuleOption */ + +/** + * @typedef {string | NodeListOf | HTMLElement[] | HTMLElement} ElementProvider + */ + +/** @typedef {Partial} PhotoSwipeOptions https://photoswipe.com/options/ */ +/** + * @typedef {Object} PreparedPhotoSwipeOptions + * + * @prop {DataSource} [dataSource] + * Pass an array of any items via dataSource option. Its length will determine amount of slides + * (which may be modified further from numItems event). + * + * Each item should contain data that you need to generate slide + * (for image slide it would be src (image URL), width (image width), height, srcset, alt). + * + * If these properties are not present in your initial array, you may "pre-parse" each item from itemData filter. + * + * @prop {number} bgOpacity + * Background backdrop opacity, always define it via this option and not via CSS rgba color. + * + * @prop {number} spacing + * Spacing between slides. Defined as ratio relative to the viewport width (0.1 = 10% of viewport). + * + * @prop {boolean} allowPanToNext + * Allow swipe navigation to the next slide when the current slide is zoomed. Does not apply to mouse events. + * + * @prop {boolean} loop + * If set to true you'll be able to swipe from the last to the first image. + * Option is always false when there are less than 3 slides. + * + * @prop {boolean} [wheelToZoom] + * By default PhotoSwipe zooms image with ctrl-wheel, if you enable this option - image will zoom just via wheel. + * + * @prop {boolean} pinchToClose + * Pinch touch gesture to close the gallery. + * + * @prop {boolean} closeOnVerticalDrag + * Vertical drag gesture to close the PhotoSwipe. + * + * @prop {Padding} [padding] + * Slide area padding (in pixels). + * + * @prop {(viewportSize: Point, itemData: SlideData, index: number) => Padding} [paddingFn] + * The option is checked frequently, so make sure it's performant. Overrides padding option if defined. For example: + * + * @prop {number | false} hideAnimationDuration + * Transition duration in milliseconds, can be 0. + * + * @prop {number | false} showAnimationDuration + * Transition duration in milliseconds, can be 0. + * + * @prop {number | false} zoomAnimationDuration + * Transition duration in milliseconds, can be 0. + * + * @prop {string} easing + * String, 'cubic-bezier(.4,0,.22,1)'. CSS easing function for open/close/zoom transitions. + * + * @prop {boolean} escKey + * Esc key to close. + * + * @prop {boolean} arrowKeys + * Left/right arrow keys for navigation. + * + * @prop {boolean} returnFocus + * Restore focus the last active element after PhotoSwipe is closed. + * + * @prop {boolean} clickToCloseNonZoomable + * If image is not zoomable (for example, smaller than viewport) it can be closed by clicking on it. + * + * @prop {ActionType | ActionFn | false} imageClickAction + * Refer to click and tap actions page. + * + * @prop {ActionType | ActionFn | false} bgClickAction + * Refer to click and tap actions page. + * + * @prop {ActionType | ActionFn | false} tapAction + * Refer to click and tap actions page. + * + * @prop {ActionType | ActionFn | false} doubleTapAction + * Refer to click and tap actions page. + * + * @prop {number} preloaderDelay + * Delay before the loading indicator will be displayed, + * if image is loaded during it - the indicator will not be displayed at all. Can be zero. + * + * @prop {string} indexIndicatorSep + * Used for slide count indicator ("1 of 10 "). + * + * @prop {(options: PhotoSwipeOptions, pswp: PhotoSwipeBase) => Point} [getViewportSizeFn] + * A function that should return slide viewport width and height, in format {x: 100, y: 100}. + * + * @prop {string} errorMsg + * Message to display when the image wasn't able to load. If you need to display HTML - use contentErrorElement filter. + * + * @prop {[number, number]} preload + * Lazy loading of nearby slides based on direction of movement. Should be an array with two integers, + * first one - number of items to preload before the current image, second one - after the current image. + * Two nearby images are always loaded. + * + * @prop {string} [mainClass] + * Class that will be added to the root element of PhotoSwipe, may contain multiple separated by space. + * Example on Styling page. + * + * @prop {HTMLElement} [appendToEl] + * Element to which PhotoSwipe dialog will be appended when it opens. + * + * @prop {number} maxWidthToAnimate + * Maximum width of image to animate, if initial rendered image width + * is larger than this value - the opening/closing transition will be automatically disabled. + * + * @prop {string} [closeTitle] + * Translating + * + * @prop {string} [zoomTitle] + * Translating + * + * @prop {string} [arrowPrevTitle] + * Translating + * + * @prop {string} [arrowNextTitle] + * Translating + * + * @prop {'zoom' | 'fade' | 'none'} [showHideAnimationType] + * To adjust opening or closing transition type use lightbox option `showHideAnimationType` (`String`). + * It supports three values - `zoom` (default), `fade` (default if there is no thumbnail) and `none`. + * + * Animations are automatically disabled if user `(prefers-reduced-motion: reduce)`. + * + * @prop {number} index + * Defines start slide index. + * + * @prop {(e: MouseEvent) => number} [getClickedIndexFn] + * + * @prop {boolean} [arrowPrev] + * @prop {boolean} [arrowNext] + * @prop {boolean} [zoom] + * @prop {boolean} [close] + * @prop {boolean} [counter] + * + * @prop {string} [arrowPrevSVG] + * @prop {string} [arrowNextSVG] + * @prop {string} [zoomSVG] + * @prop {string} [closeSVG] + * @prop {string} [counterSVG] + * + * @prop {string} [arrowPrevTitle] + * @prop {string} [arrowNextTitle] + * @prop {string} [zoomTitle] + * @prop {string} [closeTitle] + * @prop {string} [counterTitle] + * + * @prop {ZoomLevelOption} [initialZoomLevel] + * @prop {ZoomLevelOption} [secondaryZoomLevel] + * @prop {ZoomLevelOption} [maxZoomLevel] + * + * @prop {boolean} [mouseMovePan] + * @prop {Point | null} [initialPointerPos] + * @prop {boolean} [showHideOpacity] + * + * @prop {PhotoSwipeModuleOption} [pswpModule] + * @prop {() => Promise} [openPromise] + * @prop {boolean} [preloadFirstSlide] + * @prop {ElementProvider} [gallery] + * @prop {string} [gallerySelector] + * @prop {ElementProvider} [children] + * @prop {string} [childSelector] + * @prop {string | false} [thumbSelector] + */ + +/** @type {PreparedPhotoSwipeOptions} */ +const defaultOptions = { + allowPanToNext: true, + spacing: 0.1, + loop: true, + pinchToClose: true, + closeOnVerticalDrag: true, + hideAnimationDuration: 333, + showAnimationDuration: 333, + zoomAnimationDuration: 333, + escKey: true, + arrowKeys: true, + returnFocus: true, + maxWidthToAnimate: 4000, + clickToCloseNonZoomable: true, + imageClickAction: 'zoom-or-close', + bgClickAction: 'close', + tapAction: 'toggle-controls', + doubleTapAction: 'zoom', + indexIndicatorSep: ' / ', + preloaderDelay: 2000, + bgOpacity: 0.8, + + index: 0, + errorMsg: 'The image cannot be loaded', + preload: [1, 2], + easing: 'cubic-bezier(.4,0,.22,1)' +}; + +/** + * PhotoSwipe Core + */ +class PhotoSwipe extends PhotoSwipeBase { + /** + * @param {PhotoSwipeOptions} [options] + */ + constructor(options) { + super(); + + this.options = this._prepareOptions(options || {}); + + /** + * offset of viewport relative to document + * + * @type {Point} + */ + this.offset = { x: 0, y: 0 }; + + /** + * @type {Point} + * @private + */ + this._prevViewportSize = { x: 0, y: 0 }; + + /** + * Size of scrollable PhotoSwipe viewport + * + * @type {Point} + */ + this.viewportSize = { x: 0, y: 0 }; + + /** + * background (backdrop) opacity + */ + this.bgOpacity = 1; + this.currIndex = 0; + this.potentialIndex = 0; + this.isOpen = false; + this.isDestroying = false; + this.hasMouse = false; + + /** + * @private + * @type {SlideData} + */ + this._initialItemData = {}; + /** @type {Bounds | undefined} */ + this._initialThumbBounds = undefined; + + /** @type {HTMLDivElement | undefined} */ + this.topBar = undefined; + /** @type {HTMLDivElement | undefined} */ + this.element = undefined; + /** @type {HTMLDivElement | undefined} */ + this.template = undefined; + /** @type {HTMLDivElement | undefined} */ + this.container = undefined; + /** @type {HTMLElement | undefined} */ + this.scrollWrap = undefined; + /** @type {Slide | undefined} */ + this.currSlide = undefined; + + this.events = new DOMEvents(); + this.animations = new Animations(); + this.mainScroll = new MainScroll(this); + this.gestures = new Gestures(this); + this.opener = new Opener(this); + this.keyboard = new Keyboard(this); + this.contentLoader = new ContentLoader(this); + } + + /** @returns {boolean} */ + init() { + if (this.isOpen || this.isDestroying) { + return false; + } + + this.isOpen = true; + this.dispatch('init'); // legacy + this.dispatch('beforeOpen'); + + this._createMainStructure(); + + // add classes to the root element of PhotoSwipe + let rootClasses = 'pswp--open'; + if (this.gestures.supportsTouch) { + rootClasses += ' pswp--touch'; + } + if (this.options.mainClass) { + rootClasses += ' ' + this.options.mainClass; + } + if (this.element) { + this.element.className += ' ' + rootClasses; + } + + this.currIndex = this.options.index || 0; + this.potentialIndex = this.currIndex; + this.dispatch('firstUpdate'); // starting index can be modified here + + // initialize scroll wheel handler to block the scroll + this.scrollWheel = new ScrollWheel(this); + + // sanitize index + if (Number.isNaN(this.currIndex) + || this.currIndex < 0 + || this.currIndex >= this.getNumItems()) { + this.currIndex = 0; + } + + if (!this.gestures.supportsTouch) { + // enable mouse features if no touch support detected + this.mouseDetected(); + } + + // causes forced synchronous layout + this.updateSize(); + + this.offset.y = window.pageYOffset; + + this._initialItemData = this.getItemData(this.currIndex); + this.dispatch('gettingData', { + index: this.currIndex, + data: this._initialItemData, + slide: undefined + }); + + // *Layout* - calculate size and position of elements here + this._initialThumbBounds = this.getThumbBounds(); + this.dispatch('initialLayout'); + + this.on('openingAnimationEnd', () => { + const { itemHolders } = this.mainScroll; + + // Add content to the previous and next slide + if (itemHolders[0]) { + itemHolders[0].el.style.display = 'block'; + this.setContent(itemHolders[0], this.currIndex - 1); + } + if (itemHolders[2]) { + itemHolders[2].el.style.display = 'block'; + this.setContent(itemHolders[2], this.currIndex + 1); + } + + this.appendHeavy(); + + this.contentLoader.updateLazy(); + + this.events.add(window, 'resize', this._handlePageResize.bind(this)); + this.events.add(window, 'scroll', this._updatePageScrollOffset.bind(this)); + this.dispatch('bindEvents'); + }); + + // set content for center slide (first time) + if (this.mainScroll.itemHolders[1]) { + this.setContent(this.mainScroll.itemHolders[1], this.currIndex); + } + this.dispatch('change'); + + this.opener.open(); + + this.dispatch('afterInit'); + + return true; + } + + /** + * Get looped slide index + * (for example, -1 will return the last slide) + * + * @param {number} index + * @returns {number} + */ + getLoopedIndex(index) { + const numSlides = this.getNumItems(); + + if (this.options.loop) { + if (index > numSlides - 1) { + index -= numSlides; + } + + if (index < 0) { + index += numSlides; + } + } + + return clamp(index, 0, numSlides - 1); + } + + appendHeavy() { + this.mainScroll.itemHolders.forEach((itemHolder) => { + itemHolder.slide?.appendHeavy(); + }); + } + + /** + * Change the slide + * @param {number} index New index + */ + goTo(index) { + this.mainScroll.moveIndexBy( + this.getLoopedIndex(index) - this.potentialIndex + ); + } + + /** + * Go to the next slide. + */ + next() { + this.goTo(this.potentialIndex + 1); + } + + /** + * Go to the previous slide. + */ + prev() { + this.goTo(this.potentialIndex - 1); + } + + /** + * @see slide/slide.js zoomTo + * + * @param {Parameters} args + */ + zoomTo(...args) { + this.currSlide?.zoomTo(...args); + } + + /** + * @see slide/slide.js toggleZoom + */ + toggleZoom() { + this.currSlide?.toggleZoom(); + } + + /** + * Close the gallery. + * After closing transition ends - destroy it + */ + close() { + if (!this.opener.isOpen || this.isDestroying) { + return; + } + + this.isDestroying = true; + + this.dispatch('close'); + + this.events.removeAll(); + this.opener.close(); + } + + /** + * Destroys the gallery: + * - instantly closes the gallery + * - unbinds events, + * - cleans intervals and timeouts + * - removes elements from DOM + */ + destroy() { + if (!this.isDestroying) { + this.options.showHideAnimationType = 'none'; + this.close(); + return; + } + + this.dispatch('destroy'); + + this._listeners = {}; + + if (this.scrollWrap) { + this.scrollWrap.ontouchmove = null; + this.scrollWrap.ontouchend = null; + } + + this.element?.remove(); + + this.mainScroll.itemHolders.forEach((itemHolder) => { + itemHolder.slide?.destroy(); + }); + + this.contentLoader.destroy(); + this.events.removeAll(); + } + + /** + * Refresh/reload content of a slide by its index + * + * @param {number} slideIndex + */ + refreshSlideContent(slideIndex) { + this.contentLoader.removeByIndex(slideIndex); + this.mainScroll.itemHolders.forEach((itemHolder, i) => { + let potentialHolderIndex = (this.currSlide?.index ?? 0) - 1 + i; + if (this.canLoop()) { + potentialHolderIndex = this.getLoopedIndex(potentialHolderIndex); + } + if (potentialHolderIndex === slideIndex) { + // set the new slide content + this.setContent(itemHolder, slideIndex, true); + + // activate the new slide if it's current + if (i === 1) { + this.currSlide = itemHolder.slide; + itemHolder.slide?.setIsActive(true); + } + } + }); + + this.dispatch('change'); + } + + + /** + * Set slide content + * + * @param {ItemHolder} holder mainScroll.itemHolders array item + * @param {number} index Slide index + * @param {boolean} [force] If content should be set even if index wasn't changed + */ + setContent(holder, index, force) { + if (this.canLoop()) { + index = this.getLoopedIndex(index); + } + + if (holder.slide) { + if (holder.slide.index === index && !force) { + // exit if holder already contains this slide + // this could be common when just three slides are used + return; + } + + // destroy previous slide + holder.slide.destroy(); + holder.slide = undefined; + } + + // exit if no loop and index is out of bounds + if (!this.canLoop() && (index < 0 || index >= this.getNumItems())) { + return; + } + + const itemData = this.getItemData(index); + holder.slide = new Slide(itemData, index, this); + + // set current slide + if (index === this.currIndex) { + this.currSlide = holder.slide; + } + + holder.slide.append(holder.el); + } + + /** @returns {Point} */ + getViewportCenterPoint() { + return { + x: this.viewportSize.x / 2, + y: this.viewportSize.y / 2 + }; + } + + /** + * Update size of all elements. + * Executed on init and on page resize. + * + * @param {boolean} [force] Update size even if size of viewport was not changed. + */ + updateSize(force) { + // let item; + // let itemIndex; + + if (this.isDestroying) { + // exit if PhotoSwipe is closed or closing + // (to avoid errors, as resize event might be delayed) + return; + } + + //const newWidth = this.scrollWrap.clientWidth; + //const newHeight = this.scrollWrap.clientHeight; + + const newViewportSize = getViewportSize(this.options, this); + + if (!force && pointsEqual(newViewportSize, this._prevViewportSize)) { + // Exit if dimensions were not changed + return; + } + + //this._prevViewportSize.x = newWidth; + //this._prevViewportSize.y = newHeight; + equalizePoints(this._prevViewportSize, newViewportSize); + + this.dispatch('beforeResize'); + + equalizePoints(this.viewportSize, this._prevViewportSize); + + this._updatePageScrollOffset(); + + this.dispatch('viewportSize'); + + // Resize slides only after opener animation is finished + // and don't re-calculate size on inital size update + this.mainScroll.resize(this.opener.isOpen); + + if (!this.hasMouse && window.matchMedia('(any-hover: hover)').matches) { + this.mouseDetected(); + } + + this.dispatch('resize'); + } + + /** + * @param {number} opacity + */ + applyBgOpacity(opacity) { + this.bgOpacity = Math.max(opacity, 0); + if (this.bg) { + this.bg.style.opacity = String(this.bgOpacity * this.options.bgOpacity); + } + } + + /** + * Whether mouse is detected + */ + mouseDetected() { + if (!this.hasMouse) { + this.hasMouse = true; + this.element?.classList.add('pswp--has_mouse'); + } + } + + /** + * Page resize event handler + * + * @private + */ + _handlePageResize() { + this.updateSize(); + + // In iOS webview, if element size depends on document size, + // it'll be measured incorrectly in resize event + // + // https://bugs.webkit.org/show_bug.cgi?id=170595 + // https://hackernoon.com/onresize-event-broken-in-mobile-safari-d8469027bf4d + if (/iPhone|iPad|iPod/i.test(window.navigator.userAgent)) { + setTimeout(() => { + this.updateSize(); + }, 500); + } + } + + /** + * Page scroll offset is used + * to get correct coordinates + * relative to PhotoSwipe viewport. + * + * @private + */ + _updatePageScrollOffset() { + this.setScrollOffset(0, window.pageYOffset); + } + + /** + * @param {number} x + * @param {number} y + */ + setScrollOffset(x, y) { + this.offset.x = x; + this.offset.y = y; + this.dispatch('updateScrollOffset'); + } + + /** + * Create main HTML structure of PhotoSwipe, + * and add it to DOM + * + * @private + */ + _createMainStructure() { + // root DOM element of PhotoSwipe (.pswp) + this.element = createElement('pswp', 'div'); + this.element.setAttribute('tabindex', '-1'); + this.element.setAttribute('role', 'dialog'); + + // template is legacy prop + this.template = this.element; + + // Background is added as a separate element, + // as animating opacity is faster than animating rgba() + this.bg = createElement('pswp__bg', 'div', this.element); + this.scrollWrap = createElement('pswp__scroll-wrap', 'section', this.element); + this.container = createElement('pswp__container', 'div', this.scrollWrap); + + // aria pattern: carousel + this.scrollWrap.setAttribute('aria-roledescription', 'carousel'); + this.container.setAttribute('aria-live', 'off'); + this.container.setAttribute('id', 'pswp__items'); + + this.mainScroll.appendHolders(); + + this.ui = new UI(this); + this.ui.init(); + + // append to DOM + (this.options.appendToEl || document.body).appendChild(this.element); + } + + + /** + * Get position and dimensions of small thumbnail + * {x:,y:,w:} + * + * Height is optional (calculated based on the large image) + * + * @returns {Bounds | undefined} + */ + getThumbBounds() { + return getThumbBounds( + this.currIndex, + this.currSlide ? this.currSlide.data : this._initialItemData, + this + ); + } + + /** + * If the PhotoSwipe can have continuous loop + * @returns Boolean + */ + canLoop() { + return (this.options.loop && this.getNumItems() > 2); + } + + /** + * @private + * @param {PhotoSwipeOptions} options + * @returns {PreparedPhotoSwipeOptions} + */ + _prepareOptions(options) { + if (window.matchMedia('(prefers-reduced-motion), (update: slow)').matches) { + options.showHideAnimationType = 'none'; + options.zoomAnimationDuration = 0; + } + + /** @type {PreparedPhotoSwipeOptions} */ + return { + ...defaultOptions, + ...options + }; + } +} + +module.exports = PhotoSwipe; +//# sourceMappingURL=photoswipe.cjs.map diff --git a/dist/cjs/photoswipe.cjs.map b/dist/cjs/photoswipe.cjs.map new file mode 100644 index 000000000..ec6cb9b2f --- /dev/null +++ b/dist/cjs/photoswipe.cjs.map @@ -0,0 +1 @@ +{"version":3,"file":"photoswipe.cjs","sources":["../../../../src/js/util/util.js","../../../../src/js/util/dom-events.js","../../../../src/js/util/viewport-size.js","../../../../src/js/slide/pan-bounds.js","../../../../src/js/slide/zoom-level.js","../../../../src/js/slide/slide.js","../../../../src/js/gestures/drag-handler.js","../../../../src/js/gestures/zoom-handler.js","../../../../src/js/gestures/tap-handler.js","../../../../src/js/gestures/gestures.js","../../../../src/js/main-scroll.js","../../../../src/js/keyboard.js","../../../../src/js/util/css-animation.js","../../../../src/js/util/spring-easer.js","../../../../src/js/util/spring-animation.js","../../../../src/js/util/animations.js","../../../../src/js/scroll-wheel.js","../../../../src/js/ui/ui-element.js","../../../../src/js/ui/button-arrow.js","../../../../src/js/ui/button-close.js","../../../../src/js/ui/button-zoom.js","../../../../src/js/ui/loading-indicator.js","../../../../src/js/ui/counter-indicator.js","../../../../src/js/ui/ui.js","../../../../src/js/slide/get-thumb-bounds.js","../../../../src/js/core/eventable.js","../../../../src/js/slide/placeholder.js","../../../../src/js/slide/content.js","../../../../src/js/slide/loader.js","../../../../src/js/core/base.js","../../../../src/js/opener.js","../../../../src/js/photoswipe.js"],"sourcesContent":["/** @typedef {import('../photoswipe.js').Point} Point */\n\n/**\n * @template {keyof HTMLElementTagNameMap} T\n * @param {string} className\n * @param {T} tagName\n * @param {Node} [appendToEl]\n * @returns {HTMLElementTagNameMap[T]}\n */\nexport function createElement(className, tagName, appendToEl) {\n const el = document.createElement(tagName);\n if (className) {\n el.className = className;\n }\n if (appendToEl) {\n appendToEl.appendChild(el);\n }\n return el;\n}\n\n/**\n * @param {Point} p1\n * @param {Point} p2\n * @returns {Point}\n */\nexport function equalizePoints(p1, p2) {\n p1.x = p2.x;\n p1.y = p2.y;\n if (p2.id !== undefined) {\n p1.id = p2.id;\n }\n return p1;\n}\n\n/**\n * @param {Point} p\n */\nexport function roundPoint(p) {\n p.x = Math.round(p.x);\n p.y = Math.round(p.y);\n}\n\n/**\n * Returns distance between two points.\n *\n * @param {Point} p1\n * @param {Point} p2\n * @returns {number}\n */\nexport function getDistanceBetween(p1, p2) {\n const x = Math.abs(p1.x - p2.x);\n const y = Math.abs(p1.y - p2.y);\n return Math.sqrt((x * x) + (y * y));\n}\n\n/**\n * Whether X and Y positions of points are equal\n *\n * @param {Point} p1\n * @param {Point} p2\n * @returns {boolean}\n */\nexport function pointsEqual(p1, p2) {\n return p1.x === p2.x && p1.y === p2.y;\n}\n\n/**\n * The float result between the min and max values.\n *\n * @param {number} val\n * @param {number} min\n * @param {number} max\n * @returns {number}\n */\nexport function clamp(val, min, max) {\n return Math.min(Math.max(val, min), max);\n}\n\n/**\n * Get transform string\n *\n * @param {number} x\n * @param {number} [y]\n * @param {number} [scale]\n * @returns {string}\n */\nexport function toTransformString(x, y, scale) {\n let propValue = `translate3d(${x}px,${y || 0}px,0)`;\n\n if (scale !== undefined) {\n propValue += ` scale3d(${scale},${scale},1)`;\n }\n\n return propValue;\n}\n\n/**\n * Apply transform:translate(x, y) scale(scale) to element\n *\n * @param {HTMLElement} el\n * @param {number} x\n * @param {number} [y]\n * @param {number} [scale]\n */\nexport function setTransform(el, x, y, scale) {\n el.style.transform = toTransformString(x, y, scale);\n}\n\nconst defaultCSSEasing = 'cubic-bezier(.4,0,.22,1)';\n\n/**\n * Apply CSS transition to element\n *\n * @param {HTMLElement} el\n * @param {string} [prop] CSS property to animate\n * @param {number} [duration] in ms\n * @param {string} [ease] CSS easing function\n */\nexport function setTransitionStyle(el, prop, duration, ease) {\n // inOut: 'cubic-bezier(.4, 0, .22, 1)', // for \"toggle state\" transitions\n // out: 'cubic-bezier(0, 0, .22, 1)', // for \"show\" transitions\n // in: 'cubic-bezier(.4, 0, 1, 1)'// for \"hide\" transitions\n el.style.transition = prop\n ? `${prop} ${duration}ms ${ease || defaultCSSEasing}`\n : 'none';\n}\n\n/**\n * Apply width and height CSS properties to element\n *\n * @param {HTMLElement} el\n * @param {string | number} w\n * @param {string | number} h\n */\nexport function setWidthHeight(el, w, h) {\n el.style.width = (typeof w === 'number') ? `${w}px` : w;\n el.style.height = (typeof h === 'number') ? `${h}px` : h;\n}\n\n/**\n * @param {HTMLElement} el\n */\nexport function removeTransitionStyle(el) {\n setTransitionStyle(el);\n}\n\n/**\n * @param {HTMLImageElement} img\n * @returns {Promise}\n */\nexport function decodeImage(img) {\n if ('decode' in img) {\n return img.decode().catch(() => {});\n }\n\n if (img.complete) {\n return Promise.resolve(img);\n }\n\n return new Promise((resolve, reject) => {\n img.onload = () => resolve(img);\n img.onerror = reject;\n });\n}\n\n/** @typedef {LOAD_STATE[keyof LOAD_STATE]} LoadState */\n/** @type {{ IDLE: 'idle'; LOADING: 'loading'; LOADED: 'loaded'; ERROR: 'error' }} */\nexport const LOAD_STATE = {\n IDLE: 'idle',\n LOADING: 'loading',\n LOADED: 'loaded',\n ERROR: 'error',\n};\n\n\n/**\n * Check if click or keydown event was dispatched\n * with a special key or via mouse wheel.\n *\n * @param {MouseEvent | KeyboardEvent} e\n * @returns {boolean}\n */\nexport function specialKeyUsed(e) {\n return ('button' in e && e.button === 1) || e.ctrlKey || e.metaKey || e.altKey || e.shiftKey;\n}\n\n/**\n * Parse `gallery` or `children` options.\n *\n * @param {import('../photoswipe.js').ElementProvider} [option]\n * @param {string} [legacySelector]\n * @param {HTMLElement | Document} [parent]\n * @returns HTMLElement[]\n */\nexport function getElementsFromOption(option, legacySelector, parent = document) {\n /** @type {HTMLElement[]} */\n let elements = [];\n\n if (option instanceof Element) {\n elements = [option];\n } else if (option instanceof NodeList || Array.isArray(option)) {\n elements = Array.from(option);\n } else {\n const selector = typeof option === 'string' ? option : legacySelector;\n if (selector) {\n elements = Array.from(parent.querySelectorAll(selector));\n }\n }\n\n return elements;\n}\n\n/**\n * Check if variable is PhotoSwipe class\n *\n * @param {any} fn\n * @returns {boolean}\n */\nexport function isPswpClass(fn) {\n return typeof fn === 'function'\n && fn.prototype\n && fn.prototype.goTo;\n}\n\n/**\n * Check if browser is Safari\n *\n * @returns {boolean}\n */\nexport function isSafari() {\n return !!(navigator.vendor && navigator.vendor.match(/apple/i));\n}\n\n","// Detect passive event listener support\nlet supportsPassive = false;\n/* eslint-disable */\ntry {\n /* @ts-ignore */\n window.addEventListener('test', null, Object.defineProperty({}, 'passive', {\n get: () => {\n supportsPassive = true;\n }\n }));\n} catch (e) {}\n/* eslint-enable */\n\n/**\n * @typedef {Object} PoolItem\n * @prop {HTMLElement | Window | Document | undefined | null} target\n * @prop {string} type\n * @prop {EventListenerOrEventListenerObject} listener\n * @prop {boolean} [passive]\n */\n\nclass DOMEvents {\n constructor() {\n /**\n * @type {PoolItem[]}\n * @private\n */\n this._pool = [];\n }\n\n /**\n * Adds event listeners\n *\n * @param {PoolItem['target']} target\n * @param {PoolItem['type']} type Can be multiple, separated by space.\n * @param {PoolItem['listener']} listener\n * @param {PoolItem['passive']} [passive]\n */\n add(target, type, listener, passive) {\n this._toggleListener(target, type, listener, passive);\n }\n\n /**\n * Removes event listeners\n *\n * @param {PoolItem['target']} target\n * @param {PoolItem['type']} type\n * @param {PoolItem['listener']} listener\n * @param {PoolItem['passive']} [passive]\n */\n remove(target, type, listener, passive) {\n this._toggleListener(target, type, listener, passive, true);\n }\n\n /**\n * Removes all bound events\n */\n removeAll() {\n this._pool.forEach((poolItem) => {\n this._toggleListener(\n poolItem.target,\n poolItem.type,\n poolItem.listener,\n poolItem.passive,\n true,\n true\n );\n });\n this._pool = [];\n }\n\n /**\n * Adds or removes event\n *\n * @private\n * @param {PoolItem['target']} target\n * @param {PoolItem['type']} type\n * @param {PoolItem['listener']} listener\n * @param {PoolItem['passive']} [passive]\n * @param {boolean} [unbind] Whether the event should be added or removed\n * @param {boolean} [skipPool] Whether events pool should be skipped\n */\n _toggleListener(target, type, listener, passive, unbind, skipPool) {\n if (!target) {\n return;\n }\n\n const methodName = unbind ? 'removeEventListener' : 'addEventListener';\n const types = type.split(' ');\n types.forEach((eType) => {\n if (eType) {\n // Events pool is used to easily unbind all events when PhotoSwipe is closed,\n // so developer doesn't need to do this manually\n if (!skipPool) {\n if (unbind) {\n // Remove from the events pool\n this._pool = this._pool.filter((poolItem) => {\n return poolItem.type !== eType\n || poolItem.listener !== listener\n || poolItem.target !== target;\n });\n } else {\n // Add to the events pool\n this._pool.push({\n target,\n type: eType,\n listener,\n passive\n });\n }\n }\n\n // most PhotoSwipe events call preventDefault,\n // and we do not need browser to scroll the page\n const eventOptions = supportsPassive ? { passive: (passive || false) } : false;\n\n target[methodName](\n eType,\n listener,\n eventOptions\n );\n }\n });\n }\n}\n\nexport default DOMEvents;\n","/** @typedef {import('../photoswipe.js').PhotoSwipeOptions} PhotoSwipeOptions */\n/** @typedef {import('../core/base.js').default} PhotoSwipeBase */\n/** @typedef {import('../photoswipe.js').Point} Point */\n/** @typedef {import('../slide/slide.js').SlideData} SlideData */\n\n/**\n * @param {PhotoSwipeOptions} options\n * @param {PhotoSwipeBase} pswp\n * @returns {Point}\n */\nexport function getViewportSize(options, pswp) {\n if (options.getViewportSizeFn) {\n const newViewportSize = options.getViewportSizeFn(options, pswp);\n if (newViewportSize) {\n return newViewportSize;\n }\n }\n\n return {\n x: document.documentElement.clientWidth,\n\n // TODO: height on mobile is very incosistent due to toolbar\n // find a way to improve this\n //\n // document.documentElement.clientHeight - doesn't seem to work well\n y: window.innerHeight\n };\n}\n\n/**\n * Parses padding option.\n * Supported formats:\n *\n * // Object\n * padding: {\n * top: 0,\n * bottom: 0,\n * left: 0,\n * right: 0\n * }\n *\n * // A function that returns the object\n * paddingFn: (viewportSize, itemData, index) => {\n * return {\n * top: 0,\n * bottom: 0,\n * left: 0,\n * right: 0\n * };\n * }\n *\n * // Legacy variant\n * paddingLeft: 0,\n * paddingRight: 0,\n * paddingTop: 0,\n * paddingBottom: 0,\n *\n * @param {'left' | 'top' | 'bottom' | 'right'} prop\n * @param {PhotoSwipeOptions} options PhotoSwipe options\n * @param {Point} viewportSize PhotoSwipe viewport size, for example: { x:800, y:600 }\n * @param {SlideData} itemData Data about the slide\n * @param {number} index Slide index\n * @returns {number}\n */\nexport function parsePaddingOption(prop, options, viewportSize, itemData, index) {\n let paddingValue = 0;\n\n if (options.paddingFn) {\n paddingValue = options.paddingFn(viewportSize, itemData, index)[prop];\n } else if (options.padding) {\n paddingValue = options.padding[prop];\n } else {\n const legacyPropName = 'padding' + prop[0].toUpperCase() + prop.slice(1);\n // @ts-expect-error\n if (options[legacyPropName]) {\n // @ts-expect-error\n paddingValue = options[legacyPropName];\n }\n }\n\n return Number(paddingValue) || 0;\n}\n\n/**\n * @param {PhotoSwipeOptions} options\n * @param {Point} viewportSize\n * @param {SlideData} itemData\n * @param {number} index\n * @returns {Point}\n */\nexport function getPanAreaSize(options, viewportSize, itemData, index) {\n return {\n x: viewportSize.x\n - parsePaddingOption('left', options, viewportSize, itemData, index)\n - parsePaddingOption('right', options, viewportSize, itemData, index),\n y: viewportSize.y\n - parsePaddingOption('top', options, viewportSize, itemData, index)\n - parsePaddingOption('bottom', options, viewportSize, itemData, index)\n };\n}\n","import { clamp } from '../util/util.js';\nimport { parsePaddingOption } from '../util/viewport-size.js';\n\n/** @typedef {import('./slide.js').default} Slide */\n/** @typedef {Record} Point */\n/** @typedef {'x' | 'y'} Axis */\n\n/**\n * Calculates minimum, maximum and initial (center) bounds of a slide\n */\nclass PanBounds {\n /**\n * @param {Slide} slide\n */\n constructor(slide) {\n this.slide = slide;\n this.currZoomLevel = 1;\n this.center = /** @type {Point} */ { x: 0, y: 0 };\n this.max = /** @type {Point} */ { x: 0, y: 0 };\n this.min = /** @type {Point} */ { x: 0, y: 0 };\n }\n\n /**\n * _getItemBounds\n *\n * @param {number} currZoomLevel\n */\n update(currZoomLevel) {\n this.currZoomLevel = currZoomLevel;\n\n if (!this.slide.width) {\n this.reset();\n } else {\n this._updateAxis('x');\n this._updateAxis('y');\n this.slide.pswp.dispatch('calcBounds', { slide: this.slide });\n }\n }\n\n /**\n * _calculateItemBoundsForAxis\n *\n * @param {Axis} axis\n */\n _updateAxis(axis) {\n const { pswp } = this.slide;\n const elSize = this.slide[axis === 'x' ? 'width' : 'height'] * this.currZoomLevel;\n const paddingProp = axis === 'x' ? 'left' : 'top';\n const padding = parsePaddingOption(\n paddingProp,\n pswp.options,\n pswp.viewportSize,\n this.slide.data,\n this.slide.index\n );\n\n const panAreaSize = this.slide.panAreaSize[axis];\n\n // Default position of element.\n // By default, it is center of viewport:\n this.center[axis] = Math.round((panAreaSize - elSize) / 2) + padding;\n\n // maximum pan position\n this.max[axis] = (elSize > panAreaSize)\n ? Math.round(panAreaSize - elSize) + padding\n : this.center[axis];\n\n // minimum pan position\n this.min[axis] = (elSize > panAreaSize)\n ? padding\n : this.center[axis];\n }\n\n // _getZeroBounds\n reset() {\n this.center.x = 0;\n this.center.y = 0;\n this.max.x = 0;\n this.max.y = 0;\n this.min.x = 0;\n this.min.y = 0;\n }\n\n /**\n * Correct pan position if it's beyond the bounds\n *\n * @param {Axis} axis x or y\n * @param {number} panOffset\n * @returns {number}\n */\n correctPan(axis, panOffset) { // checkPanBounds\n return clamp(panOffset, this.max[axis], this.min[axis]);\n }\n}\n\nexport default PanBounds;\n","const MAX_IMAGE_WIDTH = 4000;\n\n/** @typedef {import('../photoswipe.js').default} PhotoSwipe */\n/** @typedef {import('../photoswipe.js').PhotoSwipeOptions} PhotoSwipeOptions */\n/** @typedef {import('../photoswipe.js').Point} Point */\n/** @typedef {import('../slide/slide.js').SlideData} SlideData */\n\n/** @typedef {'fit' | 'fill' | number | ((zoomLevelObject: ZoomLevel) => number)} ZoomLevelOption */\n\n/**\n * Calculates zoom levels for specific slide.\n * Depends on viewport size and image size.\n */\nclass ZoomLevel {\n /**\n * @param {PhotoSwipeOptions} options PhotoSwipe options\n * @param {SlideData} itemData Slide data\n * @param {number} index Slide index\n * @param {PhotoSwipe} [pswp] PhotoSwipe instance, can be undefined if not initialized yet\n */\n constructor(options, itemData, index, pswp) {\n this.pswp = pswp;\n this.options = options;\n this.itemData = itemData;\n this.index = index;\n /** @type { Point | null } */\n this.panAreaSize = null;\n /** @type { Point | null } */\n this.elementSize = null;\n this.fit = 1;\n this.fill = 1;\n this.vFill = 1;\n this.initial = 1;\n this.secondary = 1;\n this.max = 1;\n this.min = 1;\n }\n\n /**\n * Calculate initial, secondary and maximum zoom level for the specified slide.\n *\n * It should be called when either image or viewport size changes.\n *\n * @param {number} maxWidth\n * @param {number} maxHeight\n * @param {Point} panAreaSize\n */\n update(maxWidth, maxHeight, panAreaSize) {\n /** @type {Point} */\n const elementSize = { x: maxWidth, y: maxHeight };\n this.elementSize = elementSize;\n this.panAreaSize = panAreaSize;\n\n const hRatio = panAreaSize.x / elementSize.x;\n const vRatio = panAreaSize.y / elementSize.y;\n\n this.fit = Math.min(1, hRatio < vRatio ? hRatio : vRatio);\n this.fill = Math.min(1, hRatio > vRatio ? hRatio : vRatio);\n\n // zoom.vFill defines zoom level of the image\n // when it has 100% of viewport vertical space (height)\n this.vFill = Math.min(1, vRatio);\n\n this.initial = this._getInitial();\n this.secondary = this._getSecondary();\n this.max = Math.max(\n this.initial,\n this.secondary,\n this._getMax()\n );\n\n this.min = Math.min(\n this.fit,\n this.initial,\n this.secondary\n );\n\n if (this.pswp) {\n this.pswp.dispatch('zoomLevelsUpdate', { zoomLevels: this, slideData: this.itemData });\n }\n }\n\n /**\n * Parses user-defined zoom option.\n *\n * @private\n * @param {'initial' | 'secondary' | 'max'} optionPrefix Zoom level option prefix (initial, secondary, max)\n * @returns { number | undefined }\n */\n _parseZoomLevelOption(optionPrefix) {\n const optionName = /** @type {'initialZoomLevel' | 'secondaryZoomLevel' | 'maxZoomLevel'} */ (\n optionPrefix + 'ZoomLevel'\n );\n const optionValue = this.options[optionName];\n\n if (!optionValue) {\n return;\n }\n\n if (typeof optionValue === 'function') {\n return optionValue(this);\n }\n\n if (optionValue === 'fill') {\n return this.fill;\n }\n\n if (optionValue === 'fit') {\n return this.fit;\n }\n\n return Number(optionValue);\n }\n\n /**\n * Get zoom level to which image will be zoomed after double-tap gesture,\n * or when user clicks on zoom icon,\n * or mouse-click on image itself.\n * If you return 1 image will be zoomed to its original size.\n *\n * @private\n * @return {number}\n */\n _getSecondary() {\n let currZoomLevel = this._parseZoomLevelOption('secondary');\n\n if (currZoomLevel) {\n return currZoomLevel;\n }\n\n // 3x of \"fit\" state, but not larger than original\n currZoomLevel = Math.min(1, this.fit * 3);\n\n if (this.elementSize && currZoomLevel * this.elementSize.x > MAX_IMAGE_WIDTH) {\n currZoomLevel = MAX_IMAGE_WIDTH / this.elementSize.x;\n }\n\n return currZoomLevel;\n }\n\n /**\n * Get initial image zoom level.\n *\n * @private\n * @return {number}\n */\n _getInitial() {\n return this._parseZoomLevelOption('initial') || this.fit;\n }\n\n /**\n * Maximum zoom level when user zooms\n * via zoom/pinch gesture,\n * via cmd/ctrl-wheel or via trackpad.\n *\n * @private\n * @return {number}\n */\n _getMax() {\n // max zoom level is x4 from \"fit state\",\n // used for zoom gesture and ctrl/trackpad zoom\n return this._parseZoomLevelOption('max') || Math.max(1, this.fit * 4);\n }\n}\n\nexport default ZoomLevel;\n","/** @typedef {import('../photoswipe.js').default} PhotoSwipe */\n/** @typedef {import('../photoswipe.js').Point} Point */\n\n/**\n * @typedef {_SlideData & Record} SlideData\n * @typedef {Object} _SlideData\n * @prop {HTMLElement} [element] thumbnail element\n * @prop {string} [src] image URL\n * @prop {string} [srcset] image srcset\n * @prop {number} [w] image width (deprecated)\n * @prop {number} [h] image height (deprecated)\n * @prop {number} [width] image width\n * @prop {number} [height] image height\n * @prop {string} [msrc] placeholder image URL that's displayed before large image is loaded\n * @prop {string} [alt] image alt text\n * @prop {boolean} [thumbCropped] whether thumbnail is cropped client-side or not\n * @prop {string} [html] html content of a slide\n * @prop {'image' | 'html' | string} [type] slide type\n */\n\nimport {\n createElement,\n setTransform,\n equalizePoints,\n roundPoint,\n toTransformString,\n clamp,\n} from '../util/util.js';\n\nimport PanBounds from './pan-bounds.js';\nimport ZoomLevel from './zoom-level.js';\nimport { getPanAreaSize } from '../util/viewport-size.js';\n\n/**\n * Renders and allows to control a single slide\n */\nclass Slide {\n /**\n * @param {SlideData} data\n * @param {number} index\n * @param {PhotoSwipe} pswp\n */\n constructor(data, index, pswp) {\n this.data = data;\n this.index = index;\n this.pswp = pswp;\n this.isActive = (index === pswp.currIndex);\n this.currentResolution = 0;\n /** @type {Point} */\n this.panAreaSize = { x: 0, y: 0 };\n /** @type {Point} */\n this.pan = { x: 0, y: 0 };\n\n this.isFirstSlide = (this.isActive && !pswp.opener.isOpen);\n\n this.zoomLevels = new ZoomLevel(pswp.options, data, index, pswp);\n\n this.pswp.dispatch('gettingData', {\n slide: this,\n data: this.data,\n index\n });\n\n this.content = this.pswp.contentLoader.getContentBySlide(this);\n this.container = createElement('pswp__zoom-wrap', 'div');\n /** @type {HTMLElement | null} */\n this.holderElement = null;\n\n this.currZoomLevel = 1;\n /** @type {number} */\n this.width = this.content.width;\n /** @type {number} */\n this.height = this.content.height;\n this.heavyAppended = false;\n this.bounds = new PanBounds(this);\n\n this.prevDisplayedWidth = -1;\n this.prevDisplayedHeight = -1;\n\n this.pswp.dispatch('slideInit', { slide: this });\n }\n\n /**\n * If this slide is active/current/visible\n *\n * @param {boolean} isActive\n */\n setIsActive(isActive) {\n if (isActive && !this.isActive) {\n // slide just became active\n this.activate();\n } else if (!isActive && this.isActive) {\n // slide just became non-active\n this.deactivate();\n }\n }\n\n /**\n * Appends slide content to DOM\n *\n * @param {HTMLElement} holderElement\n */\n append(holderElement) {\n this.holderElement = holderElement;\n\n this.container.style.transformOrigin = '0 0';\n\n // Slide appended to DOM\n if (!this.data) {\n return;\n }\n\n this.calculateSize();\n\n this.load();\n this.updateContentSize();\n this.appendHeavy();\n\n this.holderElement.appendChild(this.container);\n\n this.zoomAndPanToInitial();\n\n this.pswp.dispatch('firstZoomPan', { slide: this });\n\n this.applyCurrentZoomPan();\n\n this.pswp.dispatch('afterSetContent', { slide: this });\n\n if (this.isActive) {\n this.activate();\n }\n }\n\n load() {\n this.content.load(false);\n this.pswp.dispatch('slideLoad', { slide: this });\n }\n\n /**\n * Append \"heavy\" DOM elements\n *\n * This may depend on a type of slide,\n * but generally these are large images.\n */\n appendHeavy() {\n const { pswp } = this;\n const appendHeavyNearby = true; // todo\n\n // Avoid appending heavy elements during animations\n if (this.heavyAppended\n || !pswp.opener.isOpen\n || pswp.mainScroll.isShifted()\n || (!this.isActive && !appendHeavyNearby)) {\n return;\n }\n\n if (this.pswp.dispatch('appendHeavy', { slide: this }).defaultPrevented) {\n return;\n }\n\n this.heavyAppended = true;\n\n this.content.append();\n\n this.pswp.dispatch('appendHeavyContent', { slide: this });\n }\n\n /**\n * Triggered when this slide is active (selected).\n *\n * If it's part of opening/closing transition -\n * activate() will trigger after the transition is ended.\n */\n activate() {\n this.isActive = true;\n this.appendHeavy();\n this.content.activate();\n this.pswp.dispatch('slideActivate', { slide: this });\n }\n\n /**\n * Triggered when this slide becomes inactive.\n *\n * Slide can become inactive only after it was active.\n */\n deactivate() {\n this.isActive = false;\n this.content.deactivate();\n\n if (this.currZoomLevel !== this.zoomLevels.initial) {\n // allow filtering\n this.calculateSize();\n }\n\n // reset zoom level\n this.currentResolution = 0;\n this.zoomAndPanToInitial();\n this.applyCurrentZoomPan();\n this.updateContentSize();\n\n this.pswp.dispatch('slideDeactivate', { slide: this });\n }\n\n /**\n * The slide should destroy itself, it will never be used again.\n * (unbind all events and destroy internal components)\n */\n destroy() {\n this.content.hasSlide = false;\n this.content.remove();\n this.container.remove();\n this.pswp.dispatch('slideDestroy', { slide: this });\n }\n\n resize() {\n if (this.currZoomLevel === this.zoomLevels.initial || !this.isActive) {\n // Keep initial zoom level if it was before the resize,\n // as well as when this slide is not active\n\n // Reset position and scale to original state\n this.calculateSize();\n this.currentResolution = 0;\n this.zoomAndPanToInitial();\n this.applyCurrentZoomPan();\n this.updateContentSize();\n } else {\n // readjust pan position if it's beyond the bounds\n this.calculateSize();\n this.bounds.update(this.currZoomLevel);\n this.panTo(this.pan.x, this.pan.y);\n }\n }\n\n\n /**\n * Apply size to current slide content,\n * based on the current resolution and scale.\n *\n * @param {boolean} [force] if size should be updated even if dimensions weren't changed\n */\n updateContentSize(force) {\n // Use initial zoom level\n // if resolution is not defined (user didn't zoom yet)\n const scaleMultiplier = this.currentResolution || this.zoomLevels.initial;\n\n if (!scaleMultiplier) {\n return;\n }\n\n const width = Math.round(this.width * scaleMultiplier) || this.pswp.viewportSize.x;\n const height = Math.round(this.height * scaleMultiplier) || this.pswp.viewportSize.y;\n\n if (!this.sizeChanged(width, height) && !force) {\n return;\n }\n this.content.setDisplayedSize(width, height);\n }\n\n /**\n * @param {number} width\n * @param {number} height\n */\n sizeChanged(width, height) {\n if (width !== this.prevDisplayedWidth\n || height !== this.prevDisplayedHeight) {\n this.prevDisplayedWidth = width;\n this.prevDisplayedHeight = height;\n return true;\n }\n\n return false;\n }\n\n /** @returns {HTMLImageElement | HTMLDivElement | null | undefined} */\n getPlaceholderElement() {\n return this.content.placeholder?.element;\n }\n\n /**\n * Zoom current slide image to...\n *\n * @param {number} destZoomLevel Destination zoom level.\n * @param {Point} [centerPoint]\n * Transform origin center point, or false if viewport center should be used.\n * @param {number | false} [transitionDuration] Transition duration, may be set to 0.\n * @param {boolean} [ignoreBounds] Minimum and maximum zoom levels will be ignored.\n */\n zoomTo(destZoomLevel, centerPoint, transitionDuration, ignoreBounds) {\n const { pswp } = this;\n if (!this.isZoomable()\n || pswp.mainScroll.isShifted()) {\n return;\n }\n\n pswp.dispatch('beforeZoomTo', {\n destZoomLevel, centerPoint, transitionDuration\n });\n\n // stop all pan and zoom transitions\n pswp.animations.stopAllPan();\n\n // if (!centerPoint) {\n // centerPoint = pswp.getViewportCenterPoint();\n // }\n\n const prevZoomLevel = this.currZoomLevel;\n\n if (!ignoreBounds) {\n destZoomLevel = clamp(destZoomLevel, this.zoomLevels.min, this.zoomLevels.max);\n }\n\n // if (transitionDuration === undefined) {\n // transitionDuration = this.pswp.options.zoomAnimationDuration;\n // }\n\n this.setZoomLevel(destZoomLevel);\n this.pan.x = this.calculateZoomToPanOffset('x', centerPoint, prevZoomLevel);\n this.pan.y = this.calculateZoomToPanOffset('y', centerPoint, prevZoomLevel);\n roundPoint(this.pan);\n\n const finishTransition = () => {\n this._setResolution(destZoomLevel);\n this.applyCurrentZoomPan();\n };\n\n if (!transitionDuration) {\n finishTransition();\n } else {\n pswp.animations.startTransition({\n isPan: true,\n name: 'zoomTo',\n target: this.container,\n transform: this.getCurrentTransform(),\n onComplete: finishTransition,\n duration: transitionDuration,\n easing: pswp.options.easing\n });\n }\n }\n\n /**\n * @param {Point} [centerPoint]\n */\n toggleZoom(centerPoint) {\n this.zoomTo(\n this.currZoomLevel === this.zoomLevels.initial\n ? this.zoomLevels.secondary : this.zoomLevels.initial,\n centerPoint,\n this.pswp.options.zoomAnimationDuration\n );\n }\n\n /**\n * Updates zoom level property and recalculates new pan bounds,\n * unlike zoomTo it does not apply transform (use applyCurrentZoomPan)\n *\n * @param {number} currZoomLevel\n */\n setZoomLevel(currZoomLevel) {\n this.currZoomLevel = currZoomLevel;\n this.bounds.update(this.currZoomLevel);\n }\n\n /**\n * Get pan position after zoom at a given `point`.\n *\n * Always call setZoomLevel(newZoomLevel) beforehand to recalculate\n * pan bounds according to the new zoom level.\n *\n * @param {'x' | 'y'} axis\n * @param {Point} [point]\n * point based on which zoom is performed, usually refers to the current mouse position,\n * if false - viewport center will be used.\n * @param {number} [prevZoomLevel] Zoom level before new zoom was applied.\n * @returns {number}\n */\n calculateZoomToPanOffset(axis, point, prevZoomLevel) {\n const totalPanDistance = this.bounds.max[axis] - this.bounds.min[axis];\n if (totalPanDistance === 0) {\n return this.bounds.center[axis];\n }\n\n if (!point) {\n point = this.pswp.getViewportCenterPoint();\n }\n\n if (!prevZoomLevel) {\n prevZoomLevel = this.zoomLevels.initial;\n }\n\n const zoomFactor = this.currZoomLevel / prevZoomLevel;\n return this.bounds.correctPan(\n axis,\n (this.pan[axis] - point[axis]) * zoomFactor + point[axis]\n );\n }\n\n /**\n * Apply pan and keep it within bounds.\n *\n * @param {number} panX\n * @param {number} panY\n */\n panTo(panX, panY) {\n this.pan.x = this.bounds.correctPan('x', panX);\n this.pan.y = this.bounds.correctPan('y', panY);\n this.applyCurrentZoomPan();\n }\n\n /**\n * If the slide in the current state can be panned by the user\n * @returns {boolean}\n */\n isPannable() {\n return Boolean(this.width) && (this.currZoomLevel > this.zoomLevels.fit);\n }\n\n /**\n * If the slide can be zoomed\n * @returns {boolean}\n */\n isZoomable() {\n return Boolean(this.width) && this.content.isZoomable();\n }\n\n /**\n * Apply transform and scale based on\n * the current pan position (this.pan) and zoom level (this.currZoomLevel)\n */\n applyCurrentZoomPan() {\n this._applyZoomTransform(this.pan.x, this.pan.y, this.currZoomLevel);\n if (this === this.pswp.currSlide) {\n this.pswp.dispatch('zoomPanUpdate', { slide: this });\n }\n }\n\n zoomAndPanToInitial() {\n this.currZoomLevel = this.zoomLevels.initial;\n\n // pan according to the zoom level\n this.bounds.update(this.currZoomLevel);\n equalizePoints(this.pan, this.bounds.center);\n this.pswp.dispatch('initialZoomPan', { slide: this });\n }\n\n /**\n * Set translate and scale based on current resolution\n *\n * @param {number} x\n * @param {number} y\n * @param {number} zoom\n * @private\n */\n _applyZoomTransform(x, y, zoom) {\n zoom /= this.currentResolution || this.zoomLevels.initial;\n setTransform(this.container, x, y, zoom);\n }\n\n calculateSize() {\n const { pswp } = this;\n\n equalizePoints(\n this.panAreaSize,\n getPanAreaSize(pswp.options, pswp.viewportSize, this.data, this.index)\n );\n\n this.zoomLevels.update(this.width, this.height, this.panAreaSize);\n\n pswp.dispatch('calcSlideSize', {\n slide: this\n });\n }\n\n /** @returns {string} */\n getCurrentTransform() {\n const scale = this.currZoomLevel / (this.currentResolution || this.zoomLevels.initial);\n return toTransformString(this.pan.x, this.pan.y, scale);\n }\n\n /**\n * Set resolution and re-render the image.\n *\n * For example, if the real image size is 2000x1500,\n * and resolution is 0.5 - it will be rendered as 1000x750.\n *\n * Image with zoom level 2 and resolution 0.5 is\n * the same as image with zoom level 1 and resolution 1.\n *\n * Used to optimize animations and make\n * sure that browser renders image in the highest quality.\n * Also used by responsive images to load the correct one.\n *\n * @param {number} newResolution\n */\n _setResolution(newResolution) {\n if (newResolution === this.currentResolution) {\n return;\n }\n\n this.currentResolution = newResolution;\n this.updateContentSize();\n\n this.pswp.dispatch('resolutionChanged');\n }\n}\n\nexport default Slide;\n","import {\n equalizePoints, roundPoint, clamp\n} from '../util/util.js';\n\n/** @typedef {import('../photoswipe.js').Point} Point */\n/** @typedef {import('./gestures.js').default} Gestures */\n\nconst PAN_END_FRICTION = 0.35;\nconst VERTICAL_DRAG_FRICTION = 0.6;\n\n// 1 corresponds to the third of viewport height\nconst MIN_RATIO_TO_CLOSE = 0.4;\n\n// Minimum speed required to navigate\n// to next or previous slide\nconst MIN_NEXT_SLIDE_SPEED = 0.5;\n\n/**\n * @param {number} initialVelocity\n * @param {number} decelerationRate\n * @returns {number}\n */\nfunction project(initialVelocity, decelerationRate) {\n return initialVelocity * decelerationRate / (1 - decelerationRate);\n}\n\n/**\n * Handles single pointer dragging\n */\nclass DragHandler {\n /**\n * @param {Gestures} gestures\n */\n constructor(gestures) {\n this.gestures = gestures;\n this.pswp = gestures.pswp;\n /** @type {Point} */\n this.startPan = { x: 0, y: 0 };\n }\n\n start() {\n if (this.pswp.currSlide) {\n equalizePoints(this.startPan, this.pswp.currSlide.pan);\n }\n this.pswp.animations.stopAll();\n }\n\n change() {\n const { p1, prevP1, dragAxis } = this.gestures;\n const { currSlide } = this.pswp;\n\n if (dragAxis === 'y'\n && this.pswp.options.closeOnVerticalDrag\n && (currSlide && currSlide.currZoomLevel <= currSlide.zoomLevels.fit)\n && !this.gestures.isMultitouch) {\n // Handle vertical drag to close\n const panY = currSlide.pan.y + (p1.y - prevP1.y);\n if (!this.pswp.dispatch('verticalDrag', { panY }).defaultPrevented) {\n this._setPanWithFriction('y', panY, VERTICAL_DRAG_FRICTION);\n const bgOpacity = 1 - Math.abs(this._getVerticalDragRatio(currSlide.pan.y));\n this.pswp.applyBgOpacity(bgOpacity);\n currSlide.applyCurrentZoomPan();\n }\n } else {\n const mainScrollChanged = this._panOrMoveMainScroll('x');\n if (!mainScrollChanged) {\n this._panOrMoveMainScroll('y');\n\n if (currSlide) {\n roundPoint(currSlide.pan);\n currSlide.applyCurrentZoomPan();\n }\n }\n }\n }\n\n end() {\n const { velocity } = this.gestures;\n const { mainScroll, currSlide } = this.pswp;\n let indexDiff = 0;\n\n this.pswp.animations.stopAll();\n\n // Handle main scroll if it's shifted\n if (mainScroll.isShifted()) {\n // Position of the main scroll relative to the viewport\n const mainScrollShiftDiff = mainScroll.x - mainScroll.getCurrSlideX();\n\n // Ratio between 0 and 1:\n // 0 - slide is not visible at all,\n // 0.5 - half of the slide is visible\n // 1 - slide is fully visible\n const currentSlideVisibilityRatio = (mainScrollShiftDiff / this.pswp.viewportSize.x);\n\n // Go next slide.\n //\n // - if velocity and its direction is matched,\n // and we see at least tiny part of the next slide\n //\n // - or if we see less than 50% of the current slide\n // and velocity is close to 0\n //\n if ((velocity.x < -MIN_NEXT_SLIDE_SPEED && currentSlideVisibilityRatio < 0)\n || (velocity.x < 0.1 && currentSlideVisibilityRatio < -0.5)) {\n // Go to next slide\n indexDiff = 1;\n velocity.x = Math.min(velocity.x, 0);\n } else if ((velocity.x > MIN_NEXT_SLIDE_SPEED && currentSlideVisibilityRatio > 0)\n || (velocity.x > -0.1 && currentSlideVisibilityRatio > 0.5)) {\n // Go to prev slide\n indexDiff = -1;\n velocity.x = Math.max(velocity.x, 0);\n }\n\n mainScroll.moveIndexBy(indexDiff, true, velocity.x);\n }\n\n // Restore zoom level\n if ((currSlide && currSlide.currZoomLevel > currSlide.zoomLevels.max)\n || this.gestures.isMultitouch) {\n this.gestures.zoomLevels.correctZoomPan(true);\n } else {\n // we run two animations instead of one,\n // as each axis has own pan boundaries and thus different spring function\n // (correctZoomPan does not have this functionality,\n // it animates all properties with single timing function)\n this._finishPanGestureForAxis('x');\n this._finishPanGestureForAxis('y');\n }\n }\n\n /**\n * @private\n * @param {'x' | 'y'} axis\n */\n _finishPanGestureForAxis(axis) {\n const { velocity } = this.gestures;\n const { currSlide } = this.pswp;\n\n if (!currSlide) {\n return;\n }\n\n const { pan, bounds } = currSlide;\n const panPos = pan[axis];\n const restoreBgOpacity = (this.pswp.bgOpacity < 1 && axis === 'y');\n\n // 0.995 means - scroll view loses 0.5% of its velocity per millisecond\n // Increasing this number will reduce travel distance\n const decelerationRate = 0.995; // 0.99\n\n // Pan position if there is no bounds\n const projectedPosition = panPos + project(velocity[axis], decelerationRate);\n\n if (restoreBgOpacity) {\n const vDragRatio = this._getVerticalDragRatio(panPos);\n const projectedVDragRatio = this._getVerticalDragRatio(projectedPosition);\n\n // If we are above and moving upwards,\n // or if we are below and moving downwards\n if ((vDragRatio < 0 && projectedVDragRatio < -MIN_RATIO_TO_CLOSE)\n || (vDragRatio > 0 && projectedVDragRatio > MIN_RATIO_TO_CLOSE)) {\n this.pswp.close();\n return;\n }\n }\n\n // Pan position with corrected bounds\n const correctedPanPosition = bounds.correctPan(axis, projectedPosition);\n\n // Exit if pan position should not be changed\n // or if speed it too low\n if (panPos === correctedPanPosition) {\n return;\n }\n\n // Overshoot if the final position is out of pan bounds\n const dampingRatio = (correctedPanPosition === projectedPosition) ? 1 : 0.82;\n\n const initialBgOpacity = this.pswp.bgOpacity;\n const totalPanDist = correctedPanPosition - panPos;\n\n this.pswp.animations.startSpring({\n name: 'panGesture' + axis,\n isPan: true,\n start: panPos,\n end: correctedPanPosition,\n velocity: velocity[axis],\n dampingRatio,\n onUpdate: (pos) => {\n // Animate opacity of background relative to Y pan position of an image\n if (restoreBgOpacity && this.pswp.bgOpacity < 1) {\n // 0 - start of animation, 1 - end of animation\n const animationProgressRatio = 1 - (correctedPanPosition - pos) / totalPanDist;\n\n // We clamp opacity to keep it between 0 and 1.\n // As progress ratio can be larger than 1 due to overshoot,\n // and we do not want to bounce opacity.\n this.pswp.applyBgOpacity(clamp(\n initialBgOpacity + (1 - initialBgOpacity) * animationProgressRatio,\n 0,\n 1\n ));\n }\n\n pan[axis] = Math.floor(pos);\n currSlide.applyCurrentZoomPan();\n },\n });\n }\n\n /**\n * Update position of the main scroll,\n * or/and update pan position of the current slide.\n *\n * Should return true if it changes (or can change) main scroll.\n *\n * @private\n * @param {'x' | 'y'} axis\n * @returns {boolean}\n */\n _panOrMoveMainScroll(axis) {\n const { p1, dragAxis, prevP1, isMultitouch } = this.gestures;\n const { currSlide, mainScroll } = this.pswp;\n const delta = (p1[axis] - prevP1[axis]);\n const newMainScrollX = mainScroll.x + delta;\n\n if (!delta || !currSlide) {\n return false;\n }\n\n // Always move main scroll if image can not be panned\n if (axis === 'x' && !currSlide.isPannable() && !isMultitouch) {\n mainScroll.moveTo(newMainScrollX, true);\n return true; // changed main scroll\n }\n\n const { bounds } = currSlide;\n const newPan = currSlide.pan[axis] + delta;\n\n if (this.pswp.options.allowPanToNext\n && dragAxis === 'x'\n && axis === 'x'\n && !isMultitouch) {\n const currSlideMainScrollX = mainScroll.getCurrSlideX();\n\n // Position of the main scroll relative to the viewport\n const mainScrollShiftDiff = mainScroll.x - currSlideMainScrollX;\n\n const isLeftToRight = delta > 0;\n const isRightToLeft = !isLeftToRight;\n\n if (newPan > bounds.min[axis] && isLeftToRight) {\n // Panning from left to right, beyond the left edge\n\n // Wether the image was at minimum pan position (or less)\n // when this drag gesture started.\n // Minimum pan position refers to the left edge of the image.\n const wasAtMinPanPosition = (bounds.min[axis] <= this.startPan[axis]);\n\n if (wasAtMinPanPosition) {\n mainScroll.moveTo(newMainScrollX, true);\n return true;\n } else {\n this._setPanWithFriction(axis, newPan);\n //currSlide.pan[axis] = newPan;\n }\n } else if (newPan < bounds.max[axis] && isRightToLeft) {\n // Paning from right to left, beyond the right edge\n\n // Maximum pan position refers to the right edge of the image.\n const wasAtMaxPanPosition = (this.startPan[axis] <= bounds.max[axis]);\n\n if (wasAtMaxPanPosition) {\n mainScroll.moveTo(newMainScrollX, true);\n return true;\n } else {\n this._setPanWithFriction(axis, newPan);\n //currSlide.pan[axis] = newPan;\n }\n } else {\n // If main scroll is shifted\n if (mainScrollShiftDiff !== 0) {\n // If main scroll is shifted right\n if (mainScrollShiftDiff > 0 /*&& isRightToLeft*/) {\n mainScroll.moveTo(Math.max(newMainScrollX, currSlideMainScrollX), true);\n return true;\n } else if (mainScrollShiftDiff < 0 /*&& isLeftToRight*/) {\n // Main scroll is shifted left (Position is less than 0 comparing to the viewport 0)\n mainScroll.moveTo(Math.min(newMainScrollX, currSlideMainScrollX), true);\n return true;\n }\n } else {\n // We are within pan bounds, so just pan\n this._setPanWithFriction(axis, newPan);\n }\n }\n } else {\n if (axis === 'y') {\n // Do not pan vertically if main scroll is shifted o\n if (!mainScroll.isShifted() && bounds.min.y !== bounds.max.y) {\n this._setPanWithFriction(axis, newPan);\n }\n } else {\n this._setPanWithFriction(axis, newPan);\n }\n }\n\n return false;\n }\n\n // If we move above - the ratio is negative\n // If we move below the ratio is positive\n\n /**\n * Relation between pan Y position and third of viewport height.\n *\n * When we are at initial position (center bounds) - the ratio is 0,\n * if position is shifted upwards - the ratio is negative,\n * if position is shifted downwards - the ratio is positive.\n *\n * @private\n * @param {number} panY The current pan Y position.\n * @returns {number}\n */\n _getVerticalDragRatio(panY) {\n return (panY - (this.pswp.currSlide?.bounds.center.y ?? 0)) / (this.pswp.viewportSize.y / 3);\n }\n\n /**\n * Set pan position of the current slide.\n * Apply friction if the position is beyond the pan bounds,\n * or if custom friction is defined.\n *\n * @private\n * @param {'x' | 'y'} axis\n * @param {number} potentialPan\n * @param {number} [customFriction] (0.1 - 1)\n */\n _setPanWithFriction(axis, potentialPan, customFriction) {\n const { currSlide } = this.pswp;\n\n if (!currSlide) {\n return;\n }\n\n const { pan, bounds } = currSlide;\n const correctedPan = bounds.correctPan(axis, potentialPan);\n // If we are out of pan bounds\n if (correctedPan !== potentialPan || customFriction) {\n const delta = Math.round(potentialPan - pan[axis]);\n pan[axis] += delta * (customFriction || PAN_END_FRICTION);\n } else {\n pan[axis] = potentialPan;\n }\n }\n}\n\nexport default DragHandler;\n","import {\n equalizePoints, getDistanceBetween, clamp, pointsEqual\n} from '../util/util.js';\n\n/** @typedef {import('../photoswipe.js').Point} Point */\n/** @typedef {import('./gestures.js').default} Gestures */\n\nconst UPPER_ZOOM_FRICTION = 0.05;\nconst LOWER_ZOOM_FRICTION = 0.15;\n\n\n/**\n * Get center point between two points\n *\n * @param {Point} p\n * @param {Point} p1\n * @param {Point} p2\n * @returns {Point}\n */\nfunction getZoomPointsCenter(p, p1, p2) {\n p.x = (p1.x + p2.x) / 2;\n p.y = (p1.y + p2.y) / 2;\n return p;\n}\n\nclass ZoomHandler {\n /**\n * @param {Gestures} gestures\n */\n constructor(gestures) {\n this.gestures = gestures;\n /**\n * @private\n * @type {Point}\n */\n this._startPan = { x: 0, y: 0 };\n /**\n * @private\n * @type {Point}\n */\n this._startZoomPoint = { x: 0, y: 0 };\n /**\n * @private\n * @type {Point}\n */\n this._zoomPoint = { x: 0, y: 0 };\n /** @private */\n this._wasOverFitZoomLevel = false;\n /** @private */\n this._startZoomLevel = 1;\n }\n\n start() {\n const { currSlide } = this.gestures.pswp;\n if (currSlide) {\n this._startZoomLevel = currSlide.currZoomLevel;\n equalizePoints(this._startPan, currSlide.pan);\n }\n\n this.gestures.pswp.animations.stopAllPan();\n this._wasOverFitZoomLevel = false;\n }\n\n change() {\n const { p1, startP1, p2, startP2, pswp } = this.gestures;\n const { currSlide } = pswp;\n\n if (!currSlide) {\n return;\n }\n\n const minZoomLevel = currSlide.zoomLevels.min;\n const maxZoomLevel = currSlide.zoomLevels.max;\n\n if (!currSlide.isZoomable() || pswp.mainScroll.isShifted()) {\n return;\n }\n\n getZoomPointsCenter(this._startZoomPoint, startP1, startP2);\n getZoomPointsCenter(this._zoomPoint, p1, p2);\n\n let currZoomLevel = (1 / getDistanceBetween(startP1, startP2))\n * getDistanceBetween(p1, p2)\n * this._startZoomLevel;\n\n // slightly over the zoom.fit\n if (currZoomLevel > currSlide.zoomLevels.initial + (currSlide.zoomLevels.initial / 15)) {\n this._wasOverFitZoomLevel = true;\n }\n\n if (currZoomLevel < minZoomLevel) {\n if (pswp.options.pinchToClose\n && !this._wasOverFitZoomLevel\n && this._startZoomLevel <= currSlide.zoomLevels.initial) {\n // fade out background if zooming out\n const bgOpacity = 1 - ((minZoomLevel - currZoomLevel) / (minZoomLevel / 1.2));\n if (!pswp.dispatch('pinchClose', { bgOpacity }).defaultPrevented) {\n pswp.applyBgOpacity(bgOpacity);\n }\n } else {\n // Apply the friction if zoom level is below the min\n currZoomLevel = minZoomLevel - (minZoomLevel - currZoomLevel) * LOWER_ZOOM_FRICTION;\n }\n } else if (currZoomLevel > maxZoomLevel) {\n // Apply the friction if zoom level is above the max\n currZoomLevel = maxZoomLevel + (currZoomLevel - maxZoomLevel) * UPPER_ZOOM_FRICTION;\n }\n\n currSlide.pan.x = this._calculatePanForZoomLevel('x', currZoomLevel);\n currSlide.pan.y = this._calculatePanForZoomLevel('y', currZoomLevel);\n\n currSlide.setZoomLevel(currZoomLevel);\n currSlide.applyCurrentZoomPan();\n }\n\n end() {\n const { pswp } = this.gestures;\n const { currSlide } = pswp;\n if ((!currSlide || currSlide.currZoomLevel < currSlide.zoomLevels.initial)\n && !this._wasOverFitZoomLevel\n && pswp.options.pinchToClose) {\n pswp.close();\n } else {\n this.correctZoomPan();\n }\n }\n\n /**\n * @private\n * @param {'x' | 'y'} axis\n * @param {number} currZoomLevel\n * @returns {number}\n */\n _calculatePanForZoomLevel(axis, currZoomLevel) {\n const zoomFactor = currZoomLevel / this._startZoomLevel;\n return this._zoomPoint[axis]\n - ((this._startZoomPoint[axis] - this._startPan[axis]) * zoomFactor);\n }\n\n /**\n * Correct currZoomLevel and pan if they are\n * beyond minimum or maximum values.\n * With animation.\n *\n * @param {boolean} [ignoreGesture]\n * Wether gesture coordinates should be ignored when calculating destination pan position.\n */\n correctZoomPan(ignoreGesture) {\n const { pswp } = this.gestures;\n const { currSlide } = pswp;\n\n if (!currSlide?.isZoomable()) {\n return;\n }\n\n if (this._zoomPoint.x === 0) {\n ignoreGesture = true;\n }\n\n const prevZoomLevel = currSlide.currZoomLevel;\n\n /** @type {number} */\n let destinationZoomLevel;\n let currZoomLevelNeedsChange = true;\n\n if (prevZoomLevel < currSlide.zoomLevels.initial) {\n destinationZoomLevel = currSlide.zoomLevels.initial;\n // zoom to min\n } else if (prevZoomLevel > currSlide.zoomLevels.max) {\n destinationZoomLevel = currSlide.zoomLevels.max;\n // zoom to max\n } else {\n currZoomLevelNeedsChange = false;\n destinationZoomLevel = prevZoomLevel;\n }\n\n const initialBgOpacity = pswp.bgOpacity;\n const restoreBgOpacity = pswp.bgOpacity < 1;\n\n const initialPan = equalizePoints({ x: 0, y: 0 }, currSlide.pan);\n let destinationPan = equalizePoints({ x: 0, y: 0 }, initialPan);\n\n if (ignoreGesture) {\n this._zoomPoint.x = 0;\n this._zoomPoint.y = 0;\n this._startZoomPoint.x = 0;\n this._startZoomPoint.y = 0;\n this._startZoomLevel = prevZoomLevel;\n equalizePoints(this._startPan, initialPan);\n }\n\n if (currZoomLevelNeedsChange) {\n destinationPan = {\n x: this._calculatePanForZoomLevel('x', destinationZoomLevel),\n y: this._calculatePanForZoomLevel('y', destinationZoomLevel)\n };\n }\n\n // set zoom level, so pan bounds are updated according to it\n currSlide.setZoomLevel(destinationZoomLevel);\n\n destinationPan = {\n x: currSlide.bounds.correctPan('x', destinationPan.x),\n y: currSlide.bounds.correctPan('y', destinationPan.y)\n };\n\n // return zoom level and its bounds to initial\n currSlide.setZoomLevel(prevZoomLevel);\n\n const panNeedsChange = !pointsEqual(destinationPan, initialPan);\n\n if (!panNeedsChange && !currZoomLevelNeedsChange && !restoreBgOpacity) {\n // update resolution after gesture\n currSlide._setResolution(destinationZoomLevel);\n currSlide.applyCurrentZoomPan();\n\n // nothing to animate\n return;\n }\n\n pswp.animations.stopAllPan();\n\n pswp.animations.startSpring({\n isPan: true,\n start: 0,\n end: 1000,\n velocity: 0,\n dampingRatio: 1,\n naturalFrequency: 40,\n onUpdate: (now) => {\n now /= 1000; // 0 - start, 1 - end\n\n if (panNeedsChange || currZoomLevelNeedsChange) {\n if (panNeedsChange) {\n currSlide.pan.x = initialPan.x + (destinationPan.x - initialPan.x) * now;\n currSlide.pan.y = initialPan.y + (destinationPan.y - initialPan.y) * now;\n }\n\n if (currZoomLevelNeedsChange) {\n const newZoomLevel = prevZoomLevel\n + (destinationZoomLevel - prevZoomLevel) * now;\n currSlide.setZoomLevel(newZoomLevel);\n }\n\n currSlide.applyCurrentZoomPan();\n }\n\n // Restore background opacity\n if (restoreBgOpacity && pswp.bgOpacity < 1) {\n // We clamp opacity to keep it between 0 and 1.\n // As progress ratio can be larger than 1 due to overshoot,\n // and we do not want to bounce opacity.\n pswp.applyBgOpacity(clamp(\n initialBgOpacity + (1 - initialBgOpacity) * now, 0, 1\n ));\n }\n },\n onComplete: () => {\n // update resolution after transition ends\n currSlide._setResolution(destinationZoomLevel);\n currSlide.applyCurrentZoomPan();\n }\n });\n }\n}\n\nexport default ZoomHandler;\n","/**\n * @template {string} T\n * @template {string} P\n * @typedef {import('../types.js').AddPostfix} AddPostfix\n */\n\n/** @typedef {import('./gestures.js').default} Gestures */\n/** @typedef {import('../photoswipe.js').Point} Point */\n\n/** @typedef {'imageClick' | 'bgClick' | 'tap' | 'doubleTap'} Actions */\n\n/**\n * Whether the tap was performed on the main slide\n * (rather than controls or caption).\n *\n * @param {PointerEvent} event\n * @returns {boolean}\n */\nfunction didTapOnMainContent(event) {\n return !!(/** @type {HTMLElement} */ (event.target).closest('.pswp__container'));\n}\n\n/**\n * Tap, double-tap handler.\n */\nclass TapHandler {\n /**\n * @param {Gestures} gestures\n */\n constructor(gestures) {\n this.gestures = gestures;\n }\n\n /**\n * @param {Point} point\n * @param {PointerEvent} originalEvent\n */\n click(point, originalEvent) {\n const targetClassList = /** @type {HTMLElement} */ (originalEvent.target).classList;\n const isImageClick = targetClassList.contains('pswp__img');\n const isBackgroundClick = targetClassList.contains('pswp__item')\n || targetClassList.contains('pswp__zoom-wrap');\n\n if (isImageClick) {\n this._doClickOrTapAction('imageClick', point, originalEvent);\n } else if (isBackgroundClick) {\n this._doClickOrTapAction('bgClick', point, originalEvent);\n }\n }\n\n /**\n * @param {Point} point\n * @param {PointerEvent} originalEvent\n */\n tap(point, originalEvent) {\n if (didTapOnMainContent(originalEvent)) {\n this._doClickOrTapAction('tap', point, originalEvent);\n }\n }\n\n /**\n * @param {Point} point\n * @param {PointerEvent} originalEvent\n */\n doubleTap(point, originalEvent) {\n if (didTapOnMainContent(originalEvent)) {\n this._doClickOrTapAction('doubleTap', point, originalEvent);\n }\n }\n\n /**\n * @private\n * @param {Actions} actionName\n * @param {Point} point\n * @param {PointerEvent} originalEvent\n */\n _doClickOrTapAction(actionName, point, originalEvent) {\n const { pswp } = this.gestures;\n const { currSlide } = pswp;\n const actionFullName = /** @type {AddPostfix} */ (actionName + 'Action');\n const optionValue = pswp.options[actionFullName];\n\n if (pswp.dispatch(actionFullName, { point, originalEvent }).defaultPrevented) {\n return;\n }\n\n if (typeof optionValue === 'function') {\n optionValue.call(pswp, point, originalEvent);\n return;\n }\n\n switch (optionValue) {\n case 'close':\n case 'next':\n pswp[optionValue]();\n break;\n case 'zoom':\n currSlide?.toggleZoom(point);\n break;\n case 'zoom-or-close':\n // by default click zooms current image,\n // if it can not be zoomed - gallery will be closed\n if (currSlide?.isZoomable()\n && currSlide.zoomLevels.secondary !== currSlide.zoomLevels.initial) {\n currSlide.toggleZoom(point);\n } else if (pswp.options.clickToCloseNonZoomable) {\n pswp.close();\n }\n break;\n case 'toggle-controls':\n this.gestures.pswp.element?.classList.toggle('pswp--ui-visible');\n // if (_controlsVisible) {\n // _ui.hideControls();\n // } else {\n // _ui.showControls();\n // }\n break;\n }\n }\n}\n\nexport default TapHandler;\n","import {\n equalizePoints, pointsEqual, getDistanceBetween\n} from '../util/util.js';\n\nimport DragHandler from './drag-handler.js';\nimport ZoomHandler from './zoom-handler.js';\nimport TapHandler from './tap-handler.js';\n\n/** @typedef {import('../photoswipe.js').default} PhotoSwipe */\n/** @typedef {import('../photoswipe.js').Point} Point */\n\n// How far should user should drag\n// until we can determine that the gesture is swipe and its direction\nconst AXIS_SWIPE_HYSTERISIS = 10;\n//const PAN_END_FRICTION = 0.35;\n\nconst DOUBLE_TAP_DELAY = 300; // ms\nconst MIN_TAP_DISTANCE = 25; // px\n\n/**\n * Gestures class bind touch, pointer or mouse events\n * and emits drag to drag-handler and zoom events zoom-handler.\n *\n * Drag and zoom events are emited in requestAnimationFrame,\n * and only when one of pointers was actually changed.\n */\nclass Gestures {\n /**\n * @param {PhotoSwipe} pswp\n */\n constructor(pswp) {\n this.pswp = pswp;\n\n /** @type {'x' | 'y' | null} */\n this.dragAxis = null;\n\n // point objects are defined once and reused\n // PhotoSwipe keeps track only of two pointers, others are ignored\n /** @type {Point} */\n this.p1 = { x: 0, y: 0 }; // the first pressed pointer\n /** @type {Point} */\n this.p2 = { x: 0, y: 0 }; // the second pressed pointer\n /** @type {Point} */\n this.prevP1 = { x: 0, y: 0 };\n /** @type {Point} */\n this.prevP2 = { x: 0, y: 0 };\n /** @type {Point} */\n this.startP1 = { x: 0, y: 0 };\n /** @type {Point} */\n this.startP2 = { x: 0, y: 0 };\n /** @type {Point} */\n this.velocity = { x: 0, y: 0 };\n\n /** @type {Point}\n * @private\n */\n this._lastStartP1 = { x: 0, y: 0 };\n /** @type {Point}\n * @private\n */\n this._intervalP1 = { x: 0, y: 0 };\n /** @private */\n this._numActivePoints = 0;\n /** @type {Point[]}\n * @private\n */\n this._ongoingPointers = [];\n /** @private */\n this._touchEventEnabled = 'ontouchstart' in window;\n /** @private */\n this._pointerEventEnabled = !!(window.PointerEvent);\n this.supportsTouch = this._touchEventEnabled\n || (this._pointerEventEnabled && navigator.maxTouchPoints > 1);\n /** @private */\n this._numActivePoints = 0;\n /** @private */\n this._intervalTime = 0;\n /** @private */\n this._velocityCalculated = false;\n this.isMultitouch = false;\n this.isDragging = false;\n this.isZooming = false;\n /** @type {number | null} */\n this.raf = null;\n /** @type {NodeJS.Timeout | null}\n * @private\n */\n this._tapTimer = null;\n\n if (!this.supportsTouch) {\n // disable pan to next slide for non-touch devices\n pswp.options.allowPanToNext = false;\n }\n\n this.drag = new DragHandler(this);\n this.zoomLevels = new ZoomHandler(this);\n this.tapHandler = new TapHandler(this);\n\n pswp.on('bindEvents', () => {\n pswp.events.add(\n pswp.scrollWrap,\n 'click',\n /** @type EventListener */(this._onClick.bind(this))\n );\n\n if (this._pointerEventEnabled) {\n this._bindEvents('pointer', 'down', 'up', 'cancel');\n } else if (this._touchEventEnabled) {\n this._bindEvents('touch', 'start', 'end', 'cancel');\n\n // In previous versions we also bound mouse event here,\n // in case device supports both touch and mouse events,\n // but newer versions of browsers now support PointerEvent.\n\n // on iOS10 if you bind touchmove/end after touchstart,\n // and you don't preventDefault touchstart (which PhotoSwipe does),\n // preventDefault will have no effect on touchmove and touchend.\n // Unless you bind it previously.\n if (pswp.scrollWrap) {\n pswp.scrollWrap.ontouchmove = () => {};\n pswp.scrollWrap.ontouchend = () => {};\n }\n } else {\n this._bindEvents('mouse', 'down', 'up');\n }\n });\n }\n\n /**\n * @private\n * @param {'mouse' | 'touch' | 'pointer'} pref\n * @param {'down' | 'start'} down\n * @param {'up' | 'end'} up\n * @param {'cancel'} [cancel]\n */\n _bindEvents(pref, down, up, cancel) {\n const { pswp } = this;\n const { events } = pswp;\n\n const cancelEvent = cancel ? pref + cancel : '';\n\n events.add(\n pswp.scrollWrap,\n pref + down,\n /** @type EventListener */(this.onPointerDown.bind(this))\n );\n events.add(window, pref + 'move', /** @type EventListener */(this.onPointerMove.bind(this)));\n events.add(window, pref + up, /** @type EventListener */(this.onPointerUp.bind(this)));\n if (cancelEvent) {\n events.add(\n pswp.scrollWrap,\n cancelEvent,\n /** @type EventListener */(this.onPointerUp.bind(this))\n );\n }\n }\n\n /**\n * @param {PointerEvent} e\n */\n onPointerDown(e) {\n // We do not call preventDefault for touch events\n // to allow browser to show native dialog on longpress\n // (the one that allows to save image or open it in new tab).\n //\n // Desktop Safari allows to drag images when preventDefault isn't called on mousedown,\n // even though preventDefault IS called on mousemove. That's why we preventDefault mousedown.\n const isMousePointer = e.type === 'mousedown' || e.pointerType === 'mouse';\n\n // Allow dragging only via left mouse button.\n // http://www.quirksmode.org/js/events_properties.html\n // https://developer.mozilla.org/en-US/docs/Web/API/event.button\n if (isMousePointer && e.button > 0) {\n return;\n }\n\n const { pswp } = this;\n\n // if PhotoSwipe is opening or closing\n if (!pswp.opener.isOpen) {\n e.preventDefault();\n return;\n }\n\n if (pswp.dispatch('pointerDown', { originalEvent: e }).defaultPrevented) {\n return;\n }\n\n if (isMousePointer) {\n pswp.mouseDetected();\n\n // preventDefault mouse event to prevent\n // browser image drag feature\n this._preventPointerEventBehaviour(e);\n }\n\n pswp.animations.stopAll();\n\n this._updatePoints(e, 'down');\n\n if (this._numActivePoints === 1) {\n this.dragAxis = null;\n // we need to store initial point to determine the main axis,\n // drag is activated only after the axis is determined\n equalizePoints(this.startP1, this.p1);\n }\n\n if (this._numActivePoints > 1) {\n // Tap or double tap should not trigger if more than one pointer\n this._clearTapTimer();\n this.isMultitouch = true;\n } else {\n this.isMultitouch = false;\n }\n }\n\n /**\n * @param {PointerEvent} e\n */\n onPointerMove(e) {\n e.preventDefault(); // always preventDefault move event\n\n if (!this._numActivePoints) {\n return;\n }\n\n this._updatePoints(e, 'move');\n\n if (this.pswp.dispatch('pointerMove', { originalEvent: e }).defaultPrevented) {\n return;\n }\n\n if (this._numActivePoints === 1 && !this.isDragging) {\n if (!this.dragAxis) {\n this._calculateDragDirection();\n }\n\n // Drag axis was detected, emit drag.start\n if (this.dragAxis && !this.isDragging) {\n if (this.isZooming) {\n this.isZooming = false;\n this.zoomLevels.end();\n }\n\n this.isDragging = true;\n this._clearTapTimer(); // Tap can not trigger after drag\n\n // Adjust starting point\n this._updateStartPoints();\n this._intervalTime = Date.now();\n //this._startTime = this._intervalTime;\n this._velocityCalculated = false;\n equalizePoints(this._intervalP1, this.p1);\n this.velocity.x = 0;\n this.velocity.y = 0;\n this.drag.start();\n\n this._rafStopLoop();\n this._rafRenderLoop();\n }\n } else if (this._numActivePoints > 1 && !this.isZooming) {\n this._finishDrag();\n\n this.isZooming = true;\n\n // Adjust starting points\n this._updateStartPoints();\n\n this.zoomLevels.start();\n\n this._rafStopLoop();\n this._rafRenderLoop();\n }\n }\n\n /**\n * @private\n */\n _finishDrag() {\n if (this.isDragging) {\n this.isDragging = false;\n\n // Try to calculate velocity,\n // if it wasn't calculated yet in drag.change\n if (!this._velocityCalculated) {\n this._updateVelocity(true);\n }\n\n this.drag.end();\n this.dragAxis = null;\n }\n }\n\n /**\n * @param {PointerEvent} e\n */\n onPointerUp(e) {\n if (!this._numActivePoints) {\n return;\n }\n\n this._updatePoints(e, 'up');\n\n if (this.pswp.dispatch('pointerUp', { originalEvent: e }).defaultPrevented) {\n return;\n }\n\n if (this._numActivePoints === 0) {\n this._rafStopLoop();\n\n if (this.isDragging) {\n this._finishDrag();\n } else if (!this.isZooming && !this.isMultitouch) {\n //this.zoomLevels.correctZoomPan();\n this._finishTap(e);\n }\n }\n\n if (this._numActivePoints < 2 && this.isZooming) {\n this.isZooming = false;\n this.zoomLevels.end();\n\n if (this._numActivePoints === 1) {\n // Since we have 1 point left, we need to reinitiate drag\n this.dragAxis = null;\n this._updateStartPoints();\n }\n }\n }\n\n /**\n * @private\n */\n _rafRenderLoop() {\n if (this.isDragging || this.isZooming) {\n this._updateVelocity();\n\n if (this.isDragging) {\n // make sure that pointer moved since the last update\n if (!pointsEqual(this.p1, this.prevP1)) {\n this.drag.change();\n }\n } else /* if (this.isZooming) */ {\n if (!pointsEqual(this.p1, this.prevP1)\n || !pointsEqual(this.p2, this.prevP2)) {\n this.zoomLevels.change();\n }\n }\n\n this._updatePrevPoints();\n this.raf = requestAnimationFrame(this._rafRenderLoop.bind(this));\n }\n }\n\n /**\n * Update velocity at 50ms interval\n *\n * @private\n * @param {boolean} [force]\n */\n _updateVelocity(force) {\n const time = Date.now();\n const duration = time - this._intervalTime;\n\n if (duration < 50 && !force) {\n return;\n }\n\n\n this.velocity.x = this._getVelocity('x', duration);\n this.velocity.y = this._getVelocity('y', duration);\n\n this._intervalTime = time;\n equalizePoints(this._intervalP1, this.p1);\n this._velocityCalculated = true;\n }\n\n /**\n * @private\n * @param {PointerEvent} e\n */\n _finishTap(e) {\n const { mainScroll } = this.pswp;\n\n // Do not trigger tap events if main scroll is shifted\n if (mainScroll.isShifted()) {\n // restore main scroll position\n // (usually happens if stopped in the middle of animation)\n mainScroll.moveIndexBy(0, true);\n return;\n }\n\n // Do not trigger tap for touchcancel or pointercancel\n if (e.type.indexOf('cancel') > 0) {\n return;\n }\n\n // Trigger click instead of tap for mouse events\n if (e.type === 'mouseup' || e.pointerType === 'mouse') {\n this.tapHandler.click(this.startP1, e);\n return;\n }\n\n // Disable delay if there is no doubleTapAction\n const tapDelay = this.pswp.options.doubleTapAction ? DOUBLE_TAP_DELAY : 0;\n\n // If tapTimer is defined - we tapped recently,\n // check if the current tap is close to the previous one,\n // if yes - trigger double tap\n if (this._tapTimer) {\n this._clearTapTimer();\n // Check if two taps were more or less on the same place\n if (getDistanceBetween(this._lastStartP1, this.startP1) < MIN_TAP_DISTANCE) {\n this.tapHandler.doubleTap(this.startP1, e);\n }\n } else {\n equalizePoints(this._lastStartP1, this.startP1);\n this._tapTimer = setTimeout(() => {\n this.tapHandler.tap(this.startP1, e);\n this._clearTapTimer();\n }, tapDelay);\n }\n }\n\n /**\n * @private\n */\n _clearTapTimer() {\n if (this._tapTimer) {\n clearTimeout(this._tapTimer);\n this._tapTimer = null;\n }\n }\n\n /**\n * Get velocity for axis\n *\n * @private\n * @param {'x' | 'y'} axis\n * @param {number} duration\n * @returns {number}\n */\n _getVelocity(axis, duration) {\n // displacement is like distance, but can be negative.\n const displacement = this.p1[axis] - this._intervalP1[axis];\n\n if (Math.abs(displacement) > 1 && duration > 5) {\n return displacement / duration;\n }\n\n return 0;\n }\n\n /**\n * @private\n */\n _rafStopLoop() {\n if (this.raf) {\n cancelAnimationFrame(this.raf);\n this.raf = null;\n }\n }\n\n /**\n * @private\n * @param {PointerEvent} e\n */\n _preventPointerEventBehaviour(e) {\n // TODO find a way to disable e.preventDefault on some elements\n // via event or some class or something\n e.preventDefault();\n }\n\n /**\n * Parses and normalizes points from the touch, mouse or pointer event.\n * Updates p1 and p2.\n *\n * @private\n * @param {PointerEvent | TouchEvent} e\n * @param {'up' | 'down' | 'move'} pointerType Normalized pointer type\n */\n _updatePoints(e, pointerType) {\n if (this._pointerEventEnabled) {\n const pointerEvent = /** @type {PointerEvent} */ (e);\n // Try to find the current pointer in ongoing pointers by its ID\n const pointerIndex = this._ongoingPointers.findIndex((ongoingPointer) => {\n return ongoingPointer.id === pointerEvent.pointerId;\n });\n\n if (pointerType === 'up' && pointerIndex > -1) {\n // release the pointer - remove it from ongoing\n this._ongoingPointers.splice(pointerIndex, 1);\n } else if (pointerType === 'down' && pointerIndex === -1) {\n // add new pointer\n this._ongoingPointers.push(this._convertEventPosToPoint(pointerEvent, { x: 0, y: 0 }));\n } else if (pointerIndex > -1) {\n // update existing pointer\n this._convertEventPosToPoint(pointerEvent, this._ongoingPointers[pointerIndex]);\n }\n\n this._numActivePoints = this._ongoingPointers.length;\n\n // update points that PhotoSwipe uses\n // to calculate position and scale\n if (this._numActivePoints > 0) {\n equalizePoints(this.p1, this._ongoingPointers[0]);\n }\n\n if (this._numActivePoints > 1) {\n equalizePoints(this.p2, this._ongoingPointers[1]);\n }\n } else {\n const touchEvent = /** @type {TouchEvent} */ (e);\n\n this._numActivePoints = 0;\n if (touchEvent.type.indexOf('touch') > -1) {\n // Touch Event\n // https://developer.mozilla.org/en-US/docs/Web/API/TouchEvent\n if (touchEvent.touches && touchEvent.touches.length > 0) {\n this._convertEventPosToPoint(touchEvent.touches[0], this.p1);\n this._numActivePoints++;\n if (touchEvent.touches.length > 1) {\n this._convertEventPosToPoint(touchEvent.touches[1], this.p2);\n this._numActivePoints++;\n }\n }\n } else {\n // Mouse Event\n this._convertEventPosToPoint(/** @type {PointerEvent} */ (e), this.p1);\n if (pointerType === 'up') {\n // clear all points on mouseup\n this._numActivePoints = 0;\n } else {\n this._numActivePoints++;\n }\n }\n }\n }\n\n /** update points that were used during previous rAF tick\n * @private\n */\n _updatePrevPoints() {\n equalizePoints(this.prevP1, this.p1);\n equalizePoints(this.prevP2, this.p2);\n }\n\n /** update points at the start of gesture\n * @private\n */\n _updateStartPoints() {\n equalizePoints(this.startP1, this.p1);\n equalizePoints(this.startP2, this.p2);\n this._updatePrevPoints();\n }\n\n /** @private */\n _calculateDragDirection() {\n if (this.pswp.mainScroll.isShifted()) {\n // if main scroll position is shifted – direction is always horizontal\n this.dragAxis = 'x';\n } else {\n // calculate delta of the last touchmove tick\n const diff = Math.abs(this.p1.x - this.startP1.x) - Math.abs(this.p1.y - this.startP1.y);\n\n if (diff !== 0) {\n // check if pointer was shifted horizontally or vertically\n const axisToCheck = diff > 0 ? 'x' : 'y';\n\n if (Math.abs(this.p1[axisToCheck] - this.startP1[axisToCheck]) >= AXIS_SWIPE_HYSTERISIS) {\n this.dragAxis = axisToCheck;\n }\n }\n }\n }\n\n /**\n * Converts touch, pointer or mouse event\n * to PhotoSwipe point.\n *\n * @private\n * @param {Touch | PointerEvent} e\n * @param {Point} p\n * @returns {Point}\n */\n _convertEventPosToPoint(e, p) {\n p.x = e.pageX - this.pswp.offset.x;\n p.y = e.pageY - this.pswp.offset.y;\n\n if ('pointerId' in e) {\n p.id = e.pointerId;\n } else if (e.identifier !== undefined) {\n p.id = e.identifier;\n }\n\n return p;\n }\n\n /**\n * @private\n * @param {PointerEvent} e\n */\n _onClick(e) {\n // Do not allow click event to pass through after drag\n if (this.pswp.mainScroll.isShifted()) {\n e.preventDefault();\n e.stopPropagation();\n }\n }\n}\n\nexport default Gestures;\n","import {\n setTransform,\n createElement,\n} from './util/util.js';\n\n/** @typedef {import('./photoswipe.js').default} PhotoSwipe */\n/** @typedef {import('./slide/slide.js').default} Slide */\n\n/** @typedef {{ el: HTMLDivElement; slide?: Slide }} ItemHolder */\n\nconst MAIN_SCROLL_END_FRICTION = 0.35;\n\n\n// const MIN_SWIPE_TRANSITION_DURATION = 250;\n// const MAX_SWIPE_TRABSITION_DURATION = 500;\n// const DEFAULT_SWIPE_TRANSITION_DURATION = 333;\n\n/**\n * Handles movement of the main scrolling container\n * (for example, it repositions when user swipes left or right).\n *\n * Also stores its state.\n */\nclass MainScroll {\n /**\n * @param {PhotoSwipe} pswp\n */\n constructor(pswp) {\n this.pswp = pswp;\n this.x = 0;\n this.slideWidth = 0;\n /** @private */\n this._currPositionIndex = 0;\n /** @private */\n this._prevPositionIndex = 0;\n /** @private */\n this._containerShiftIndex = -1;\n\n /** @type {ItemHolder[]} */\n this.itemHolders = [];\n }\n\n /**\n * Position the scroller and slide containers\n * according to viewport size.\n *\n * @param {boolean} [resizeSlides] Whether slides content should resized\n */\n resize(resizeSlides) {\n const { pswp } = this;\n const newSlideWidth = Math.round(\n pswp.viewportSize.x + pswp.viewportSize.x * pswp.options.spacing\n );\n // Mobile browsers might trigger a resize event during a gesture.\n // (due to toolbar appearing or hiding).\n // Avoid re-adjusting main scroll position if width wasn't changed\n const slideWidthChanged = (newSlideWidth !== this.slideWidth);\n\n if (slideWidthChanged) {\n this.slideWidth = newSlideWidth;\n this.moveTo(this.getCurrSlideX());\n }\n\n this.itemHolders.forEach((itemHolder, index) => {\n if (slideWidthChanged) {\n setTransform(itemHolder.el, (index + this._containerShiftIndex)\n * this.slideWidth);\n }\n\n if (resizeSlides && itemHolder.slide) {\n itemHolder.slide.resize();\n }\n });\n }\n\n /**\n * Reset X position of the main scroller to zero\n */\n resetPosition() {\n // Position on the main scroller (offset)\n // it is independent from slide index\n this._currPositionIndex = 0;\n this._prevPositionIndex = 0;\n\n // This will force recalculation of size on next resize()\n this.slideWidth = 0;\n\n // _containerShiftIndex*viewportSize will give you amount of transform of the current slide\n this._containerShiftIndex = -1;\n }\n\n /**\n * Create and append array of three items\n * that hold data about slides in DOM\n */\n appendHolders() {\n this.itemHolders = [];\n\n // append our three slide holders -\n // previous, current, and next\n for (let i = 0; i < 3; i++) {\n const el = createElement('pswp__item', 'div', this.pswp.container);\n el.setAttribute('role', 'group');\n el.setAttribute('aria-roledescription', 'slide');\n el.setAttribute('aria-hidden', 'true');\n\n // hide nearby item holders until initial zoom animation finishes (to avoid extra Paints)\n el.style.display = (i === 1) ? 'block' : 'none';\n\n this.itemHolders.push({\n el,\n //index: -1\n });\n }\n }\n\n /**\n * Whether the main scroll can be horizontally swiped to the next or previous slide.\n * @returns {boolean}\n */\n canBeSwiped() {\n return this.pswp.getNumItems() > 1;\n }\n\n /**\n * Move main scroll by X amount of slides.\n * For example:\n * `-1` will move to the previous slide,\n * `0` will reset the scroll position of the current slide,\n * `3` will move three slides forward\n *\n * If loop option is enabled - index will be automatically looped too,\n * (for example `-1` will move to the last slide of the gallery).\n *\n * @param {number} diff\n * @param {boolean} [animate]\n * @param {number} [velocityX]\n * @returns {boolean} whether index was changed or not\n */\n moveIndexBy(diff, animate, velocityX) {\n const { pswp } = this;\n let newIndex = pswp.potentialIndex + diff;\n const numSlides = pswp.getNumItems();\n\n if (pswp.canLoop()) {\n newIndex = pswp.getLoopedIndex(newIndex);\n const distance = (diff + numSlides) % numSlides;\n if (distance <= numSlides / 2) {\n // go forward\n diff = distance;\n } else {\n // go backwards\n diff = distance - numSlides;\n }\n } else {\n if (newIndex < 0) {\n newIndex = 0;\n } else if (newIndex >= numSlides) {\n newIndex = numSlides - 1;\n }\n diff = newIndex - pswp.potentialIndex;\n }\n\n pswp.potentialIndex = newIndex;\n this._currPositionIndex -= diff;\n\n pswp.animations.stopMainScroll();\n\n const destinationX = this.getCurrSlideX();\n if (!animate) {\n this.moveTo(destinationX);\n this.updateCurrItem();\n } else {\n pswp.animations.startSpring({\n isMainScroll: true,\n start: this.x,\n end: destinationX,\n velocity: velocityX || 0,\n naturalFrequency: 30,\n dampingRatio: 1, //0.7,\n onUpdate: (x) => {\n this.moveTo(x);\n },\n onComplete: () => {\n this.updateCurrItem();\n pswp.appendHeavy();\n }\n });\n\n let currDiff = pswp.potentialIndex - pswp.currIndex;\n if (pswp.canLoop()) {\n const currDistance = (currDiff + numSlides) % numSlides;\n if (currDistance <= numSlides / 2) {\n // go forward\n currDiff = currDistance;\n } else {\n // go backwards\n currDiff = currDistance - numSlides;\n }\n }\n\n // Force-append new slides during transition\n // if difference between slides is more than 1\n if (Math.abs(currDiff) > 1) {\n this.updateCurrItem();\n }\n }\n\n return Boolean(diff);\n }\n\n /**\n * X position of the main scroll for the current slide\n * (ignores position during dragging)\n * @returns {number}\n */\n getCurrSlideX() {\n return this.slideWidth * this._currPositionIndex;\n }\n\n /**\n * Whether scroll position is shifted.\n * For example, it will return true if the scroll is being dragged or animated.\n * @returns {boolean}\n */\n isShifted() {\n return this.x !== this.getCurrSlideX();\n }\n\n /**\n * Update slides X positions and set their content\n */\n updateCurrItem() {\n const { pswp } = this;\n const positionDifference = this._prevPositionIndex - this._currPositionIndex;\n\n if (!positionDifference) {\n return;\n }\n\n this._prevPositionIndex = this._currPositionIndex;\n\n pswp.currIndex = pswp.potentialIndex;\n\n let diffAbs = Math.abs(positionDifference);\n /** @type {ItemHolder | undefined} */\n let tempHolder;\n\n if (diffAbs >= 3) {\n this._containerShiftIndex += positionDifference + (positionDifference > 0 ? -3 : 3);\n diffAbs = 3;\n }\n\n for (let i = 0; i < diffAbs; i++) {\n if (positionDifference > 0) {\n tempHolder = this.itemHolders.shift();\n if (tempHolder) {\n this.itemHolders[2] = tempHolder; // move first to last\n\n this._containerShiftIndex++;\n\n setTransform(tempHolder.el, (this._containerShiftIndex + 2) * this.slideWidth);\n\n pswp.setContent(tempHolder, (pswp.currIndex - diffAbs) + i + 2);\n }\n } else {\n tempHolder = this.itemHolders.pop();\n if (tempHolder) {\n this.itemHolders.unshift(tempHolder); // move last to first\n\n this._containerShiftIndex--;\n\n setTransform(tempHolder.el, this._containerShiftIndex * this.slideWidth);\n\n pswp.setContent(tempHolder, (pswp.currIndex + diffAbs) - i - 2);\n }\n }\n }\n\n // Reset transfrom every 50ish navigations in one direction.\n //\n // Otherwise transform will keep growing indefinitely,\n // which might cause issues as browsers have a maximum transform limit.\n // I wasn't able to reach it, but just to be safe.\n // This should not cause noticable lag.\n if (Math.abs(this._containerShiftIndex) > 50 && !this.isShifted()) {\n this.resetPosition();\n this.resize();\n }\n\n // Pan transition might be running (and consntantly updating pan position)\n pswp.animations.stopAllPan();\n\n this.itemHolders.forEach((itemHolder, i) => {\n if (itemHolder.slide) {\n // Slide in the 2nd holder is always active\n itemHolder.slide.setIsActive(i === 1);\n }\n });\n\n pswp.currSlide = this.itemHolders[1]?.slide;\n pswp.contentLoader.updateLazy(positionDifference);\n\n if (pswp.currSlide) {\n pswp.currSlide.applyCurrentZoomPan();\n }\n\n pswp.dispatch('change');\n }\n\n /**\n * Move the X position of the main scroll container\n *\n * @param {number} x\n * @param {boolean} [dragging]\n */\n moveTo(x, dragging) {\n if (!this.pswp.canLoop() && dragging) {\n // Apply friction\n let newSlideIndexOffset = ((this.slideWidth * this._currPositionIndex) - x) / this.slideWidth;\n newSlideIndexOffset += this.pswp.currIndex;\n const delta = Math.round(x - this.x);\n\n if ((newSlideIndexOffset < 0 && delta > 0)\n || (newSlideIndexOffset >= this.pswp.getNumItems() - 1 && delta < 0)) {\n x = this.x + (delta * MAIN_SCROLL_END_FRICTION);\n }\n }\n\n this.x = x;\n\n if (this.pswp.container) {\n setTransform(this.pswp.container, x);\n }\n\n this.pswp.dispatch('moveMainScroll', { x, dragging: dragging ?? false });\n }\n}\n\nexport default MainScroll;\n","import { specialKeyUsed } from './util/util.js';\n\n/** @typedef {import('./photoswipe.js').default} PhotoSwipe */\n\n/**\n * @template T\n * @typedef {import('./types.js').Methods} Methods\n */\n\nconst KeyboardKeyCodesMap = {\n Escape: 27,\n z: 90,\n ArrowLeft: 37,\n ArrowUp: 38,\n ArrowRight: 39,\n ArrowDown: 40,\n Tab: 9,\n};\n\n/**\n * @template {keyof KeyboardKeyCodesMap} T\n * @param {T} key\n * @param {boolean} isKeySupported\n * @returns {T | number | undefined}\n */\nconst getKeyboardEventKey = (key, isKeySupported) => {\n return isKeySupported ? key : KeyboardKeyCodesMap[key];\n};\n\n/**\n * - Manages keyboard shortcuts.\n * - Helps trap focus within photoswipe.\n */\nclass Keyboard {\n /**\n * @param {PhotoSwipe} pswp\n */\n constructor(pswp) {\n this.pswp = pswp;\n /** @private */\n this._wasFocused = false;\n\n pswp.on('bindEvents', () => {\n // Dialog was likely opened by keyboard if initial point is not defined\n if (!pswp.options.initialPointerPos) {\n // focus causes layout,\n // which causes lag during the animation,\n // that's why we delay it until the opener transition ends\n this._focusRoot();\n }\n\n pswp.events.add(document, 'focusin', /** @type EventListener */(this._onFocusIn.bind(this)));\n pswp.events.add(document, 'keydown', /** @type EventListener */(this._onKeyDown.bind(this)));\n });\n\n const lastActiveElement = /** @type {HTMLElement} */ (document.activeElement);\n pswp.on('destroy', () => {\n if (pswp.options.returnFocus\n && lastActiveElement\n && this._wasFocused) {\n lastActiveElement.focus();\n }\n });\n }\n\n /** @private */\n _focusRoot() {\n if (!this._wasFocused && this.pswp.element) {\n this.pswp.element.focus();\n this._wasFocused = true;\n }\n }\n\n /**\n * @private\n * @param {KeyboardEvent} e\n */\n _onKeyDown(e) {\n const { pswp } = this;\n\n if (pswp.dispatch('keydown', { originalEvent: e }).defaultPrevented) {\n return;\n }\n\n if (specialKeyUsed(e)) {\n // don't do anything if special key pressed\n // to prevent from overriding default browser actions\n // for example, in Chrome on Mac cmd+arrow-left returns to previous page\n return;\n }\n\n /** @type {Methods | undefined} */\n let keydownAction;\n /** @type {'x' | 'y' | undefined} */\n let axis;\n let isForward = false;\n const isKeySupported = 'key' in e;\n\n switch (isKeySupported ? e.key : e.keyCode) {\n case getKeyboardEventKey('Escape', isKeySupported):\n if (pswp.options.escKey) {\n keydownAction = 'close';\n }\n break;\n case getKeyboardEventKey('z', isKeySupported):\n keydownAction = 'toggleZoom';\n break;\n case getKeyboardEventKey('ArrowLeft', isKeySupported):\n axis = 'x';\n break;\n case getKeyboardEventKey('ArrowUp', isKeySupported):\n axis = 'y';\n break;\n case getKeyboardEventKey('ArrowRight', isKeySupported):\n axis = 'x';\n isForward = true;\n break;\n case getKeyboardEventKey('ArrowDown', isKeySupported):\n isForward = true;\n axis = 'y';\n break;\n case getKeyboardEventKey('Tab', isKeySupported):\n this._focusRoot();\n break;\n default:\n }\n\n // if left/right/top/bottom key\n if (axis) {\n // prevent page scroll\n e.preventDefault();\n\n const { currSlide } = pswp;\n\n if (pswp.options.arrowKeys\n && axis === 'x'\n && pswp.getNumItems() > 1) {\n keydownAction = isForward ? 'next' : 'prev';\n } else if (currSlide && currSlide.currZoomLevel > currSlide.zoomLevels.fit) {\n // up/down arrow keys pan the image vertically\n // left/right arrow keys pan horizontally.\n // Unless there is only one image,\n // or arrowKeys option is disabled\n currSlide.pan[axis] += isForward ? -80 : 80;\n currSlide.panTo(currSlide.pan.x, currSlide.pan.y);\n }\n }\n\n if (keydownAction) {\n e.preventDefault();\n // @ts-ignore\n pswp[keydownAction]();\n }\n }\n\n /**\n * Trap focus inside photoswipe\n *\n * @private\n * @param {FocusEvent} e\n */\n _onFocusIn(e) {\n const { template } = this.pswp;\n if (template\n && document !== e.target\n && template !== e.target\n && !template.contains(/** @type {Node} */ (e.target))) {\n // focus root element\n template.focus();\n }\n }\n}\n\nexport default Keyboard;\n","import { setTransitionStyle, removeTransitionStyle } from './util.js';\n\nconst DEFAULT_EASING = 'cubic-bezier(.4,0,.22,1)';\n\n/** @typedef {import('./animations.js').SharedAnimationProps} SharedAnimationProps */\n\n/** @typedef {Object} DefaultCssAnimationProps\n *\n * @prop {HTMLElement} target\n * @prop {number} [duration]\n * @prop {string} [easing]\n * @prop {string} [transform]\n * @prop {string} [opacity]\n * */\n\n/** @typedef {SharedAnimationProps & DefaultCssAnimationProps} CssAnimationProps */\n\n/**\n * Runs CSS transition.\n */\nclass CSSAnimation {\n /**\n * onComplete can be unpredictable, be careful about current state\n *\n * @param {CssAnimationProps} props\n */\n constructor(props) {\n this.props = props;\n const {\n target,\n onComplete,\n transform,\n onFinish = () => {},\n duration = 333,\n easing = DEFAULT_EASING,\n } = props;\n\n this.onFinish = onFinish;\n\n // support only transform and opacity\n const prop = transform ? 'transform' : 'opacity';\n const propValue = props[prop] ?? '';\n\n /** @private */\n this._target = target;\n /** @private */\n this._onComplete = onComplete;\n /** @private */\n this._finished = false;\n\n /** @private */\n this._onTransitionEnd = this._onTransitionEnd.bind(this);\n\n // Using timeout hack to make sure that animation\n // starts even if the animated property was changed recently,\n // otherwise transitionend might not fire or transition won't start.\n // https://drafts.csswg.org/css-transitions/#starting\n //\n // ¯\\_(ツ)_/¯\n /** @private */\n this._helperTimeout = setTimeout(() => {\n setTransitionStyle(target, prop, duration, easing);\n this._helperTimeout = setTimeout(() => {\n target.addEventListener('transitionend', this._onTransitionEnd, false);\n target.addEventListener('transitioncancel', this._onTransitionEnd, false);\n\n // Safari occasionally does not emit transitionend event\n // if element property was modified during the transition,\n // which may be caused by resize or third party component,\n // using timeout as a safety fallback\n this._helperTimeout = setTimeout(() => {\n this._finalizeAnimation();\n }, duration + 500);\n target.style[prop] = propValue;\n }, 30); // Do not reduce this number\n }, 0);\n }\n\n /**\n * @private\n * @param {TransitionEvent} e\n */\n _onTransitionEnd(e) {\n if (e.target === this._target) {\n this._finalizeAnimation();\n }\n }\n\n /**\n * @private\n */\n _finalizeAnimation() {\n if (!this._finished) {\n this._finished = true;\n this.onFinish();\n if (this._onComplete) {\n this._onComplete();\n }\n }\n }\n\n // Destroy is called automatically onFinish\n destroy() {\n if (this._helperTimeout) {\n clearTimeout(this._helperTimeout);\n }\n removeTransitionStyle(this._target);\n this._target.removeEventListener('transitionend', this._onTransitionEnd, false);\n this._target.removeEventListener('transitioncancel', this._onTransitionEnd, false);\n if (!this._finished) {\n this._finalizeAnimation();\n }\n }\n}\n\nexport default CSSAnimation;\n","const DEFAULT_NATURAL_FREQUENCY = 12;\nconst DEFAULT_DAMPING_RATIO = 0.75;\n\n/**\n * Spring easing helper\n */\nclass SpringEaser {\n /**\n * @param {number} initialVelocity Initial velocity, px per ms.\n *\n * @param {number} [dampingRatio]\n * Determines how bouncy animation will be.\n * From 0 to 1, 0 - always overshoot, 1 - do not overshoot.\n * \"overshoot\" refers to part of animation that\n * goes beyond the final value.\n *\n * @param {number} [naturalFrequency]\n * Determines how fast animation will slow down.\n * The higher value - the stiffer the transition will be,\n * and the faster it will slow down.\n * Recommended value from 10 to 50\n */\n constructor(initialVelocity, dampingRatio, naturalFrequency) {\n this.velocity = initialVelocity * 1000; // convert to \"pixels per second\"\n\n // https://en.wikipedia.org/wiki/Damping_ratio\n this._dampingRatio = dampingRatio || DEFAULT_DAMPING_RATIO;\n\n // https://en.wikipedia.org/wiki/Natural_frequency\n this._naturalFrequency = naturalFrequency || DEFAULT_NATURAL_FREQUENCY;\n\n this._dampedFrequency = this._naturalFrequency;\n\n if (this._dampingRatio < 1) {\n this._dampedFrequency *= Math.sqrt(1 - this._dampingRatio * this._dampingRatio);\n }\n }\n\n /**\n * @param {number} deltaPosition Difference between current and end position of the animation\n * @param {number} deltaTime Frame duration in milliseconds\n *\n * @returns {number} Displacement, relative to the end position.\n */\n easeFrame(deltaPosition, deltaTime) {\n // Inspired by Apple Webkit and Android spring function implementation\n // https://en.wikipedia.org/wiki/Oscillation\n // https://en.wikipedia.org/wiki/Damping_ratio\n // we ignore mass (assume that it's 1kg)\n\n let displacement = 0;\n let coeff;\n\n deltaTime /= 1000;\n\n const naturalDumpingPow = Math.E ** (-this._dampingRatio * this._naturalFrequency * deltaTime);\n\n if (this._dampingRatio === 1) {\n coeff = this.velocity + this._naturalFrequency * deltaPosition;\n\n displacement = (deltaPosition + coeff * deltaTime) * naturalDumpingPow;\n\n this.velocity = displacement\n * (-this._naturalFrequency) + coeff\n * naturalDumpingPow;\n } else if (this._dampingRatio < 1) {\n coeff = (1 / this._dampedFrequency)\n * (this._dampingRatio * this._naturalFrequency * deltaPosition + this.velocity);\n\n const dumpedFCos = Math.cos(this._dampedFrequency * deltaTime);\n const dumpedFSin = Math.sin(this._dampedFrequency * deltaTime);\n\n displacement = naturalDumpingPow\n * (deltaPosition * dumpedFCos + coeff * dumpedFSin);\n\n this.velocity = displacement\n * (-this._naturalFrequency)\n * this._dampingRatio\n + naturalDumpingPow\n * (-this._dampedFrequency * deltaPosition * dumpedFSin\n + this._dampedFrequency * coeff * dumpedFCos);\n }\n\n // Overdamped (>1) damping ratio is not supported\n\n return displacement;\n }\n}\n\nexport default SpringEaser;\n","import SpringEaser from './spring-easer.js';\n\n/** @typedef {import('./animations.js').SharedAnimationProps} SharedAnimationProps */\n\n/**\n * @typedef {Object} DefaultSpringAnimationProps\n *\n * @prop {number} start\n * @prop {number} end\n * @prop {number} velocity\n * @prop {number} [dampingRatio]\n * @prop {number} [naturalFrequency]\n * @prop {(end: number) => void} onUpdate\n */\n\n/** @typedef {SharedAnimationProps & DefaultSpringAnimationProps} SpringAnimationProps */\n\nclass SpringAnimation {\n /**\n * @param {SpringAnimationProps} props\n */\n constructor(props) {\n this.props = props;\n this._raf = 0;\n\n const {\n start,\n end,\n velocity,\n onUpdate,\n onComplete,\n onFinish = () => {},\n dampingRatio,\n naturalFrequency\n } = props;\n\n this.onFinish = onFinish;\n\n const easer = new SpringEaser(velocity, dampingRatio, naturalFrequency);\n let prevTime = Date.now();\n let deltaPosition = start - end;\n\n const animationLoop = () => {\n if (this._raf) {\n deltaPosition = easer.easeFrame(deltaPosition, Date.now() - prevTime);\n\n // Stop the animation if velocity is low and position is close to end\n if (Math.abs(deltaPosition) < 1 && Math.abs(easer.velocity) < 50) {\n // Finalize the animation\n onUpdate(end);\n if (onComplete) {\n onComplete();\n }\n this.onFinish();\n } else {\n prevTime = Date.now();\n onUpdate(deltaPosition + end);\n this._raf = requestAnimationFrame(animationLoop);\n }\n }\n };\n\n this._raf = requestAnimationFrame(animationLoop);\n }\n\n // Destroy is called automatically onFinish\n destroy() {\n if (this._raf >= 0) {\n cancelAnimationFrame(this._raf);\n }\n this._raf = 0;\n }\n}\n\nexport default SpringAnimation;\n","import CSSAnimation from './css-animation.js';\nimport SpringAnimation from './spring-animation.js';\n\n/** @typedef {import('./css-animation.js').CssAnimationProps} CssAnimationProps */\n/** @typedef {import('./spring-animation.js').SpringAnimationProps} SpringAnimationProps */\n\n/** @typedef {Object} SharedAnimationProps\n * @prop {string} [name]\n * @prop {boolean} [isPan]\n * @prop {boolean} [isMainScroll]\n * @prop {VoidFunction} [onComplete]\n * @prop {VoidFunction} [onFinish]\n */\n\n/** @typedef {SpringAnimation | CSSAnimation} Animation */\n/** @typedef {SpringAnimationProps | CssAnimationProps} AnimationProps */\n\n/**\n * Manages animations\n */\nclass Animations {\n constructor() {\n /** @type {Animation[]} */\n this.activeAnimations = [];\n }\n\n /**\n * @param {SpringAnimationProps} props\n */\n startSpring(props) {\n this._start(props, true);\n }\n\n /**\n * @param {CssAnimationProps} props\n */\n startTransition(props) {\n this._start(props);\n }\n\n /**\n * @private\n * @param {AnimationProps} props\n * @param {boolean} [isSpring]\n * @returns {Animation}\n */\n _start(props, isSpring) {\n const animation = isSpring\n ? new SpringAnimation(/** @type SpringAnimationProps */ (props))\n : new CSSAnimation(/** @type CssAnimationProps */ (props));\n\n this.activeAnimations.push(animation);\n animation.onFinish = () => this.stop(animation);\n\n return animation;\n }\n\n /**\n * @param {Animation} animation\n */\n stop(animation) {\n animation.destroy();\n const index = this.activeAnimations.indexOf(animation);\n if (index > -1) {\n this.activeAnimations.splice(index, 1);\n }\n }\n\n stopAll() { // _stopAllAnimations\n this.activeAnimations.forEach((animation) => {\n animation.destroy();\n });\n this.activeAnimations = [];\n }\n\n /**\n * Stop all pan or zoom transitions\n */\n stopAllPan() {\n this.activeAnimations = this.activeAnimations.filter((animation) => {\n if (animation.props.isPan) {\n animation.destroy();\n return false;\n }\n\n return true;\n });\n }\n\n stopMainScroll() {\n this.activeAnimations = this.activeAnimations.filter((animation) => {\n if (animation.props.isMainScroll) {\n animation.destroy();\n return false;\n }\n\n return true;\n });\n }\n\n /**\n * Returns true if main scroll transition is running\n */\n // isMainScrollRunning() {\n // return this.activeAnimations.some((animation) => {\n // return animation.props.isMainScroll;\n // });\n // }\n\n /**\n * Returns true if any pan or zoom transition is running\n */\n isPanRunning() {\n return this.activeAnimations.some((animation) => {\n return animation.props.isPan;\n });\n }\n}\n\nexport default Animations;\n","/** @typedef {import('./photoswipe.js').default} PhotoSwipe */\n\n/**\n * Handles scroll wheel.\n * Can pan and zoom current slide image.\n */\nclass ScrollWheel {\n /**\n * @param {PhotoSwipe} pswp\n */\n constructor(pswp) {\n this.pswp = pswp;\n pswp.events.add(pswp.element, 'wheel', /** @type EventListener */(this._onWheel.bind(this)));\n }\n\n /**\n * @private\n * @param {WheelEvent} e\n */\n _onWheel(e) {\n e.preventDefault();\n const { currSlide } = this.pswp;\n let { deltaX, deltaY } = e;\n\n if (!currSlide) {\n return;\n }\n\n if (this.pswp.dispatch('wheel', { originalEvent: e }).defaultPrevented) {\n return;\n }\n\n if (e.ctrlKey || this.pswp.options.wheelToZoom) {\n // zoom\n if (currSlide.isZoomable()) {\n let zoomFactor = -deltaY;\n if (e.deltaMode === 1 /* DOM_DELTA_LINE */) {\n zoomFactor *= 0.05;\n } else {\n zoomFactor *= e.deltaMode ? 1 : 0.002;\n }\n zoomFactor = 2 ** zoomFactor;\n\n const destZoomLevel = currSlide.currZoomLevel * zoomFactor;\n currSlide.zoomTo(destZoomLevel, {\n x: e.clientX,\n y: e.clientY\n });\n }\n } else {\n // pan\n if (currSlide.isPannable()) {\n if (e.deltaMode === 1 /* DOM_DELTA_LINE */) {\n // 18 - average line height\n deltaX *= 18;\n deltaY *= 18;\n }\n\n currSlide.panTo(\n currSlide.pan.x - deltaX,\n currSlide.pan.y - deltaY\n );\n }\n }\n }\n}\n\nexport default ScrollWheel;\n","import { createElement } from '../util/util.js';\n\n/** @typedef {import('../photoswipe.js').default} PhotoSwipe */\n\n/**\n * @template T\n * @typedef {import('../types.js').Methods} Methods\n */\n\n/**\n * @typedef {Object} UIElementMarkupProps\n * @prop {boolean} [isCustomSVG]\n * @prop {string} inner\n * @prop {string} [outlineID]\n * @prop {number | string} [size]\n */\n\n/**\n * @typedef {Object} UIElementData\n * @prop {DefaultUIElements | string} [name]\n * @prop {string} [className]\n * @prop {UIElementMarkup} [html]\n * @prop {boolean} [isButton]\n * @prop {keyof HTMLElementTagNameMap} [tagName]\n * @prop {string} [title]\n * @prop {string} [ariaLabel]\n * @prop {(element: HTMLElement, pswp: PhotoSwipe) => void} [onInit]\n * @prop {Methods | ((e: MouseEvent, element: HTMLElement, pswp: PhotoSwipe) => void)} [onClick]\n * @prop {'bar' | 'wrapper' | 'root'} [appendTo]\n * @prop {number} [order]\n */\n\n/** @typedef {'arrowPrev' | 'arrowNext' | 'close' | 'zoom' | 'counter'} DefaultUIElements */\n\n/** @typedef {string | UIElementMarkupProps} UIElementMarkup */\n\n/**\n * @param {UIElementMarkup} [htmlData]\n * @returns {string}\n */\nfunction addElementHTML(htmlData) {\n if (typeof htmlData === 'string') {\n // Allow developers to provide full svg,\n // For example:\n // \n // \n // \n // \n // Can also be any HTML string.\n return htmlData;\n }\n\n if (!htmlData || !htmlData.isCustomSVG) {\n return '';\n }\n\n const svgData = htmlData;\n let out = '';\n // replace all %d with size\n out = out.split('%d').join(/** @type {string} */ (svgData.size || 32));\n\n // Icons may contain outline/shadow,\n // to make it we \"clone\" base icon shape and add border to it.\n // Icon itself and border are styled via CSS.\n //\n // Property shadowID defines ID of element that should be cloned.\n if (svgData.outlineID) {\n out += '';\n }\n\n out += svgData.inner;\n\n out += '';\n\n return out;\n}\n\nclass UIElement {\n /**\n * @param {PhotoSwipe} pswp\n * @param {UIElementData} data\n */\n constructor(pswp, data) {\n const name = data.name || data.className;\n let elementHTML = data.html;\n\n // @ts-expect-error lookup only by `data.name` maybe?\n if (pswp.options[name] === false) {\n // exit if element is disabled from options\n return;\n }\n\n // Allow to override SVG icons from options\n // @ts-expect-error lookup only by `data.name` maybe?\n if (typeof pswp.options[name + 'SVG'] === 'string') {\n // arrowPrevSVG\n // arrowNextSVG\n // closeSVG\n // zoomSVG\n // @ts-expect-error lookup only by `data.name` maybe?\n elementHTML = pswp.options[name + 'SVG'];\n }\n\n pswp.dispatch('uiElementCreate', { data });\n\n let className = '';\n if (data.isButton) {\n className += 'pswp__button ';\n className += (data.className || `pswp__button--${data.name}`);\n } else {\n className += (data.className || `pswp__${data.name}`);\n }\n\n let tagName = data.isButton ? (data.tagName || 'button') : (data.tagName || 'div');\n tagName = /** @type {keyof HTMLElementTagNameMap} */ (tagName.toLowerCase());\n /** @type {HTMLElement} */\n const element = createElement(className, tagName);\n\n if (data.isButton) {\n if (tagName === 'button') {\n /** @type {HTMLButtonElement} */ (element).type = 'button';\n }\n\n let { title } = data;\n const { ariaLabel } = data;\n\n // @ts-expect-error lookup only by `data.name` maybe?\n if (typeof pswp.options[name + 'Title'] === 'string') {\n // @ts-expect-error lookup only by `data.name` maybe?\n title = pswp.options[name + 'Title'];\n }\n\n if (title) {\n element.title = title;\n }\n\n const ariaText = ariaLabel || title;\n if (ariaText) {\n element.setAttribute('aria-label', ariaText);\n }\n }\n\n element.innerHTML = addElementHTML(elementHTML);\n\n if (data.onInit) {\n data.onInit(element, pswp);\n }\n\n if (data.onClick) {\n element.onclick = (e) => {\n if (typeof data.onClick === 'string') {\n // @ts-ignore\n pswp[data.onClick]();\n } else if (typeof data.onClick === 'function') {\n data.onClick(e, element, pswp);\n }\n };\n }\n\n // Top bar is default position\n const appendTo = data.appendTo || 'bar';\n /** @type {HTMLElement | undefined} root element by default */\n let container = pswp.element;\n if (appendTo === 'bar') {\n if (!pswp.topBar) {\n pswp.topBar = createElement('pswp__top-bar pswp__hide-on-close', 'div', pswp.scrollWrap);\n }\n container = pswp.topBar;\n } else {\n // element outside of top bar gets a secondary class\n // that makes element fade out on close\n element.classList.add('pswp__hide-on-close');\n\n if (appendTo === 'wrapper') {\n container = pswp.scrollWrap;\n }\n }\n\n container?.appendChild(pswp.applyFilters('uiElement', element, data));\n }\n}\n\nexport default UIElement;\n","/*\n Backward and forward arrow buttons\n */\n\n/** @typedef {import('./ui-element.js').UIElementData} UIElementData */\n/** @typedef {import('../photoswipe.js').default} PhotoSwipe */\n\n/**\n *\n * @param {HTMLElement} element\n * @param {PhotoSwipe} pswp\n * @param {boolean} [isNextButton]\n */\nfunction initArrowButton(element, pswp, isNextButton) {\n element.classList.add('pswp__button--arrow');\n // TODO: this should point to a unique id for this instance\n element.setAttribute('aria-controls', 'pswp__items');\n pswp.on('change', () => {\n if (!pswp.options.loop) {\n if (isNextButton) {\n /** @type {HTMLButtonElement} */\n (element).disabled = !(pswp.currIndex < pswp.getNumItems() - 1);\n } else {\n /** @type {HTMLButtonElement} */\n (element).disabled = !(pswp.currIndex > 0);\n }\n }\n });\n}\n\n/** @type {UIElementData} */\nexport const arrowPrev = {\n name: 'arrowPrev',\n className: 'pswp__button--arrow--prev',\n title: 'Previous',\n order: 10,\n isButton: true,\n appendTo: 'wrapper',\n html: {\n isCustomSVG: true,\n size: 60,\n inner: '',\n outlineID: 'pswp__icn-arrow'\n },\n onClick: 'prev',\n onInit: initArrowButton\n};\n\n/** @type {UIElementData} */\nexport const arrowNext = {\n name: 'arrowNext',\n className: 'pswp__button--arrow--next',\n title: 'Next',\n order: 11,\n isButton: true,\n appendTo: 'wrapper',\n html: {\n isCustomSVG: true,\n size: 60,\n inner: '',\n outlineID: 'pswp__icn-arrow'\n },\n onClick: 'next',\n onInit: (el, pswp) => {\n initArrowButton(el, pswp, true);\n }\n};\n","/** @type {import('./ui-element.js').UIElementData} UIElementData */\nconst closeButton = {\n name: 'close',\n title: 'Close',\n order: 20,\n isButton: true,\n html: {\n isCustomSVG: true,\n inner: '',\n outlineID: 'pswp__icn-close'\n },\n onClick: 'close'\n};\n\nexport default closeButton;\n","/** @type {import('./ui-element.js').UIElementData} UIElementData */\nconst zoomButton = {\n name: 'zoom',\n title: 'Zoom',\n order: 10,\n isButton: true,\n html: {\n isCustomSVG: true,\n // eslint-disable-next-line max-len\n inner: ''\n + ''\n + '',\n outlineID: 'pswp__icn-zoom'\n },\n onClick: 'toggleZoom'\n};\n\nexport default zoomButton;\n","/** @type {import('./ui-element.js').UIElementData} UIElementData */\nexport const loadingIndicator = {\n name: 'preloader',\n appendTo: 'bar',\n order: 7,\n html: {\n isCustomSVG: true,\n // eslint-disable-next-line max-len\n inner: '',\n outlineID: 'pswp__icn-loading'\n },\n onInit: (indicatorElement, pswp) => {\n /** @type {boolean | undefined} */\n let isVisible;\n /** @type {NodeJS.Timeout | null} */\n let delayTimeout = null;\n\n /**\n * @param {string} className\n * @param {boolean} add\n */\n const toggleIndicatorClass = (className, add) => {\n indicatorElement.classList.toggle('pswp__preloader--' + className, add);\n };\n\n /**\n * @param {boolean} visible\n */\n const setIndicatorVisibility = (visible) => {\n if (isVisible !== visible) {\n isVisible = visible;\n toggleIndicatorClass('active', visible);\n }\n };\n\n const updatePreloaderVisibility = () => {\n if (!pswp.currSlide?.content.isLoading()) {\n setIndicatorVisibility(false);\n if (delayTimeout) {\n clearTimeout(delayTimeout);\n delayTimeout = null;\n }\n return;\n }\n\n if (!delayTimeout) {\n // display loading indicator with delay\n delayTimeout = setTimeout(() => {\n setIndicatorVisibility(Boolean(pswp.currSlide?.content.isLoading()));\n delayTimeout = null;\n }, pswp.options.preloaderDelay);\n }\n };\n\n pswp.on('change', updatePreloaderVisibility);\n\n pswp.on('loadComplete', (e) => {\n if (pswp.currSlide === e.slide) {\n updatePreloaderVisibility();\n }\n });\n\n // expose the method\n if (pswp.ui) {\n pswp.ui.updatePreloaderVisibility = updatePreloaderVisibility;\n }\n }\n};\n","/** @type {import('./ui-element.js').UIElementData} UIElementData */\nexport const counterIndicator = {\n name: 'counter',\n order: 5,\n onInit: (counterElement, pswp) => {\n pswp.on('change', () => {\n counterElement.innerText = (pswp.currIndex + 1)\n + pswp.options.indexIndicatorSep\n + pswp.getNumItems();\n });\n }\n};\n","import UIElement from './ui-element.js';\nimport { arrowPrev, arrowNext } from './button-arrow.js';\nimport closeButton from './button-close.js';\nimport zoomButton from './button-zoom.js';\nimport { loadingIndicator } from './loading-indicator.js';\nimport { counterIndicator } from './counter-indicator.js';\n\n/** @typedef {import('../photoswipe.js').default} PhotoSwipe */\n/** @typedef {import('./ui-element.js').UIElementData} UIElementData */\n\n/**\n * Set special class on element when image is zoomed.\n *\n * By default, it is used to adjust\n * zoom icon and zoom cursor via CSS.\n *\n * @param {HTMLElement} el\n * @param {boolean} isZoomedIn\n */\nfunction setZoomedIn(el, isZoomedIn) {\n el.classList.toggle('pswp--zoomed-in', isZoomedIn);\n}\n\nclass UI {\n /**\n * @param {PhotoSwipe} pswp\n */\n constructor(pswp) {\n this.pswp = pswp;\n this.isRegistered = false;\n /** @type {UIElementData[]} */\n this.uiElementsData = [];\n /** @type {(UIElement | UIElementData)[]} */\n this.items = [];\n /** @type {() => void} */\n this.updatePreloaderVisibility = () => {};\n\n /**\n * @private\n * @type {number | undefined}\n */\n this._lastUpdatedZoomLevel = undefined;\n }\n\n init() {\n const { pswp } = this;\n this.isRegistered = false;\n this.uiElementsData = [\n closeButton,\n arrowPrev,\n arrowNext,\n zoomButton,\n loadingIndicator,\n counterIndicator\n ];\n\n pswp.dispatch('uiRegister');\n\n // sort by order\n this.uiElementsData.sort((a, b) => {\n // default order is 0\n return (a.order || 0) - (b.order || 0);\n });\n\n this.items = [];\n\n this.isRegistered = true;\n this.uiElementsData.forEach((uiElementData) => {\n this.registerElement(uiElementData);\n });\n\n pswp.on('change', () => {\n pswp.element?.classList.toggle('pswp--one-slide', pswp.getNumItems() === 1);\n });\n\n pswp.on('zoomPanUpdate', () => this._onZoomPanUpdate());\n }\n\n /**\n * @param {UIElementData} elementData\n */\n registerElement(elementData) {\n if (this.isRegistered) {\n this.items.push(\n new UIElement(this.pswp, elementData)\n );\n } else {\n this.uiElementsData.push(elementData);\n }\n }\n\n /**\n * Fired each time zoom or pan position is changed.\n * Update classes that control visibility of zoom button and cursor icon.\n *\n * @private\n */\n _onZoomPanUpdate() {\n const { template, currSlide, options } = this.pswp;\n\n if (this.pswp.opener.isClosing || !template || !currSlide) {\n return;\n }\n\n let { currZoomLevel } = currSlide;\n\n // if not open yet - check against initial zoom level\n if (!this.pswp.opener.isOpen) {\n currZoomLevel = currSlide.zoomLevels.initial;\n }\n\n if (currZoomLevel === this._lastUpdatedZoomLevel) {\n return;\n }\n this._lastUpdatedZoomLevel = currZoomLevel;\n\n const currZoomLevelDiff = currSlide.zoomLevels.initial - currSlide.zoomLevels.secondary;\n\n // Initial and secondary zoom levels are almost equal\n if (Math.abs(currZoomLevelDiff) < 0.01 || !currSlide.isZoomable()) {\n // disable zoom\n setZoomedIn(template, false);\n template.classList.remove('pswp--zoom-allowed');\n return;\n }\n\n template.classList.add('pswp--zoom-allowed');\n\n const potentialZoomLevel = currZoomLevel === currSlide.zoomLevels.initial\n ? currSlide.zoomLevels.secondary : currSlide.zoomLevels.initial;\n\n setZoomedIn(template, potentialZoomLevel <= currZoomLevel);\n\n if (options.imageClickAction === 'zoom'\n || options.imageClickAction === 'zoom-or-close') {\n template.classList.add('pswp--click-to-zoom');\n }\n }\n}\n\nexport default UI;\n","/** @typedef {import('./slide.js').SlideData} SlideData */\n/** @typedef {import('../photoswipe.js').default} PhotoSwipe */\n\n/** @typedef {{ x: number; y: number; w: number; innerRect?: { w: number; h: number; x: number; y: number } }} Bounds */\n\n/**\n * @param {HTMLElement} el\n * @returns Bounds\n */\nfunction getBoundsByElement(el) {\n const thumbAreaRect = el.getBoundingClientRect();\n return {\n x: thumbAreaRect.left,\n y: thumbAreaRect.top,\n w: thumbAreaRect.width\n };\n}\n\n/**\n * @param {HTMLElement} el\n * @param {number} imageWidth\n * @param {number} imageHeight\n * @returns Bounds\n */\nfunction getCroppedBoundsByElement(el, imageWidth, imageHeight) {\n const thumbAreaRect = el.getBoundingClientRect();\n\n // fill image into the area\n // (do they same as object-fit:cover does to retrieve coordinates)\n const hRatio = thumbAreaRect.width / imageWidth;\n const vRatio = thumbAreaRect.height / imageHeight;\n const fillZoomLevel = hRatio > vRatio ? hRatio : vRatio;\n\n const offsetX = (thumbAreaRect.width - imageWidth * fillZoomLevel) / 2;\n const offsetY = (thumbAreaRect.height - imageHeight * fillZoomLevel) / 2;\n\n /**\n * Coordinates of the image,\n * as if it was not cropped,\n * height is calculated automatically\n *\n * @type {Bounds}\n */\n const bounds = {\n x: thumbAreaRect.left + offsetX,\n y: thumbAreaRect.top + offsetY,\n w: imageWidth * fillZoomLevel\n };\n\n // Coordinates of inner crop area\n // relative to the image\n bounds.innerRect = {\n w: thumbAreaRect.width,\n h: thumbAreaRect.height,\n x: offsetX,\n y: offsetY\n };\n\n return bounds;\n}\n\n/**\n * Get dimensions of thumbnail image\n * (click on which opens photoswipe or closes photoswipe to)\n *\n * @param {number} index\n * @param {SlideData} itemData\n * @param {PhotoSwipe} instance PhotoSwipe instance\n * @returns {Bounds | undefined}\n */\nexport function getThumbBounds(index, itemData, instance) {\n // legacy event, before filters were introduced\n const event = instance.dispatch('thumbBounds', {\n index,\n itemData,\n instance\n });\n // @ts-expect-error\n if (event.thumbBounds) {\n // @ts-expect-error\n return event.thumbBounds;\n }\n\n const { element } = itemData;\n /** @type {Bounds | undefined} */\n let thumbBounds;\n /** @type {HTMLElement | null | undefined} */\n let thumbnail;\n\n if (element && instance.options.thumbSelector !== false) {\n const thumbSelector = instance.options.thumbSelector || 'img';\n thumbnail = element.matches(thumbSelector)\n ? element : /** @type {HTMLElement | null} */ (element.querySelector(thumbSelector));\n }\n\n thumbnail = instance.applyFilters('thumbEl', thumbnail, itemData, index);\n\n if (thumbnail) {\n if (!itemData.thumbCropped) {\n thumbBounds = getBoundsByElement(thumbnail);\n } else {\n thumbBounds = getCroppedBoundsByElement(\n thumbnail,\n itemData.width || itemData.w || 0,\n itemData.height || itemData.h || 0\n );\n }\n }\n\n return instance.applyFilters('thumbBounds', thumbBounds, itemData, index);\n}\n","/** @typedef {import('../lightbox/lightbox.js').default} PhotoSwipeLightbox */\n/** @typedef {import('../photoswipe.js').default} PhotoSwipe */\n/** @typedef {import('../photoswipe.js').PhotoSwipeOptions} PhotoSwipeOptions */\n/** @typedef {import('../photoswipe.js').DataSource} DataSource */\n/** @typedef {import('../ui/ui-element.js').UIElementData} UIElementData */\n/** @typedef {import('../slide/content.js').default} ContentDefault */\n/** @typedef {import('../slide/slide.js').default} Slide */\n/** @typedef {import('../slide/slide.js').SlideData} SlideData */\n/** @typedef {import('../slide/zoom-level.js').default} ZoomLevel */\n/** @typedef {import('../slide/get-thumb-bounds.js').Bounds} Bounds */\n\n/**\n * Allow adding an arbitrary props to the Content\n * https://photoswipe.com/custom-content/#using-webp-image-format\n * @typedef {ContentDefault & Record} Content\n */\n/** @typedef {{ x?: number; y?: number }} Point */\n\n/**\n * @typedef {Object} PhotoSwipeEventsMap https://photoswipe.com/events/\n *\n *\n * https://photoswipe.com/adding-ui-elements/\n *\n * @prop {undefined} uiRegister\n * @prop {{ data: UIElementData }} uiElementCreate\n *\n *\n * https://photoswipe.com/events/#initialization-events\n *\n * @prop {undefined} beforeOpen\n * @prop {undefined} firstUpdate\n * @prop {undefined} initialLayout\n * @prop {undefined} change\n * @prop {undefined} afterInit\n * @prop {undefined} bindEvents\n *\n *\n * https://photoswipe.com/events/#opening-or-closing-transition-events\n *\n * @prop {undefined} openingAnimationStart\n * @prop {undefined} openingAnimationEnd\n * @prop {undefined} closingAnimationStart\n * @prop {undefined} closingAnimationEnd\n *\n *\n * https://photoswipe.com/events/#closing-events\n *\n * @prop {undefined} close\n * @prop {undefined} destroy\n *\n *\n * https://photoswipe.com/events/#pointer-and-gesture-events\n *\n * @prop {{ originalEvent: PointerEvent }} pointerDown\n * @prop {{ originalEvent: PointerEvent }} pointerMove\n * @prop {{ originalEvent: PointerEvent }} pointerUp\n * @prop {{ bgOpacity: number }} pinchClose can be default prevented\n * @prop {{ panY: number }} verticalDrag can be default prevented\n *\n *\n * https://photoswipe.com/events/#slide-content-events\n *\n * @prop {{ content: Content }} contentInit\n * @prop {{ content: Content; isLazy: boolean }} contentLoad can be default prevented\n * @prop {{ content: Content; isLazy: boolean }} contentLoadImage can be default prevented\n * @prop {{ content: Content; slide: Slide; isError?: boolean }} loadComplete\n * @prop {{ content: Content; slide: Slide }} loadError\n * @prop {{ content: Content; width: number; height: number }} contentResize can be default prevented\n * @prop {{ content: Content; width: number; height: number; slide: Slide }} imageSizeChange\n * @prop {{ content: Content }} contentLazyLoad can be default prevented\n * @prop {{ content: Content }} contentAppend can be default prevented\n * @prop {{ content: Content }} contentActivate can be default prevented\n * @prop {{ content: Content }} contentDeactivate can be default prevented\n * @prop {{ content: Content }} contentRemove can be default prevented\n * @prop {{ content: Content }} contentDestroy can be default prevented\n *\n *\n * undocumented\n *\n * @prop {{ point: Point; originalEvent: PointerEvent }} imageClickAction can be default prevented\n * @prop {{ point: Point; originalEvent: PointerEvent }} bgClickAction can be default prevented\n * @prop {{ point: Point; originalEvent: PointerEvent }} tapAction can be default prevented\n * @prop {{ point: Point; originalEvent: PointerEvent }} doubleTapAction can be default prevented\n *\n * @prop {{ originalEvent: KeyboardEvent }} keydown can be default prevented\n * @prop {{ x: number; dragging: boolean }} moveMainScroll\n * @prop {{ slide: Slide }} firstZoomPan\n * @prop {{ slide: Slide | undefined, data: SlideData, index: number }} gettingData\n * @prop {undefined} beforeResize\n * @prop {undefined} resize\n * @prop {undefined} viewportSize\n * @prop {undefined} updateScrollOffset\n * @prop {{ slide: Slide }} slideInit\n * @prop {{ slide: Slide }} afterSetContent\n * @prop {{ slide: Slide }} slideLoad\n * @prop {{ slide: Slide }} appendHeavy can be default prevented\n * @prop {{ slide: Slide }} appendHeavyContent\n * @prop {{ slide: Slide }} slideActivate\n * @prop {{ slide: Slide }} slideDeactivate\n * @prop {{ slide: Slide }} slideDestroy\n * @prop {{ destZoomLevel: number, centerPoint: Point | undefined, transitionDuration: number | false | undefined }} beforeZoomTo\n * @prop {{ slide: Slide }} zoomPanUpdate\n * @prop {{ slide: Slide }} initialZoomPan\n * @prop {{ slide: Slide }} calcSlideSize\n * @prop {undefined} resolutionChanged\n * @prop {{ originalEvent: WheelEvent }} wheel can be default prevented\n * @prop {{ content: Content }} contentAppendImage can be default prevented\n * @prop {{ index: number; itemData: SlideData }} lazyLoadSlide can be default prevented\n * @prop {undefined} lazyLoad\n * @prop {{ slide: Slide }} calcBounds\n * @prop {{ zoomLevels: ZoomLevel, slideData: SlideData }} zoomLevelsUpdate\n *\n *\n * legacy\n *\n * @prop {undefined} init\n * @prop {undefined} initialZoomIn\n * @prop {undefined} initialZoomOut\n * @prop {undefined} initialZoomInEnd\n * @prop {undefined} initialZoomOutEnd\n * @prop {{ dataSource: DataSource | undefined, numItems: number }} numItems\n * @prop {{ itemData: SlideData; index: number }} itemData\n * @prop {{ index: number, itemData: SlideData, instance: PhotoSwipe }} thumbBounds\n */\n\n/**\n * @typedef {Object} PhotoSwipeFiltersMap https://photoswipe.com/filters/\n *\n * @prop {(numItems: number, dataSource: DataSource | undefined) => number} numItems\n * Modify the total amount of slides. Example on Data sources page.\n * https://photoswipe.com/filters/#numitems\n *\n * @prop {(itemData: SlideData, index: number) => SlideData} itemData\n * Modify slide item data. Example on Data sources page.\n * https://photoswipe.com/filters/#itemdata\n *\n * @prop {(itemData: SlideData, element: HTMLElement, linkEl: HTMLAnchorElement) => SlideData} domItemData\n * Modify item data when it's parsed from DOM element. Example on Data sources page.\n * https://photoswipe.com/filters/#domitemdata\n *\n * @prop {(clickedIndex: number, e: MouseEvent, instance: PhotoSwipeLightbox) => number} clickedIndex\n * Modify clicked gallery item index.\n * https://photoswipe.com/filters/#clickedindex\n *\n * @prop {(placeholderSrc: string | false, content: Content) => string | false} placeholderSrc\n * Modify placeholder image source.\n * https://photoswipe.com/filters/#placeholdersrc\n *\n * @prop {(isContentLoading: boolean, content: Content) => boolean} isContentLoading\n * Modify if the content is currently loading.\n * https://photoswipe.com/filters/#iscontentloading\n *\n * @prop {(isContentZoomable: boolean, content: Content) => boolean} isContentZoomable\n * Modify if the content can be zoomed.\n * https://photoswipe.com/filters/#iscontentzoomable\n *\n * @prop {(useContentPlaceholder: boolean, content: Content) => boolean} useContentPlaceholder\n * Modify if the placeholder should be used for the content.\n * https://photoswipe.com/filters/#usecontentplaceholder\n *\n * @prop {(isKeepingPlaceholder: boolean, content: Content) => boolean} isKeepingPlaceholder\n * Modify if the placeholder should be kept after the content is loaded.\n * https://photoswipe.com/filters/#iskeepingplaceholder\n *\n *\n * @prop {(contentErrorElement: HTMLElement, content: Content) => HTMLElement} contentErrorElement\n * Modify an element when the content has error state (for example, if image cannot be loaded).\n * https://photoswipe.com/filters/#contenterrorelement\n *\n * @prop {(element: HTMLElement, data: UIElementData) => HTMLElement} uiElement\n * Modify a UI element that's being created.\n * https://photoswipe.com/filters/#uielement\n *\n * @prop {(thumbnail: HTMLElement | null | undefined, itemData: SlideData, index: number) => HTMLElement} thumbEl\n * Modify the thubmnail element from which opening zoom animation starts or ends.\n * https://photoswipe.com/filters/#thumbel\n *\n * @prop {(thumbBounds: Bounds | undefined, itemData: SlideData, index: number) => Bounds} thumbBounds\n * Modify the thubmnail bounds from which opening zoom animation starts or ends.\n * https://photoswipe.com/filters/#thumbbounds\n *\n * @prop {(srcsetSizesWidth: number, content: Content) => number} srcsetSizesWidth\n *\n */\n\n/**\n * @template {keyof PhotoSwipeFiltersMap} T\n * @typedef {{ fn: PhotoSwipeFiltersMap[T], priority: number }} Filter\n */\n\n/**\n * @template {keyof PhotoSwipeEventsMap} T\n * @typedef {PhotoSwipeEventsMap[T] extends undefined ? PhotoSwipeEvent : PhotoSwipeEvent & PhotoSwipeEventsMap[T]} AugmentedEvent\n */\n\n/**\n * @template {keyof PhotoSwipeEventsMap} T\n * @typedef {(event: AugmentedEvent) => void} EventCallback\n */\n\n/**\n * Base PhotoSwipe event object\n *\n * @template {keyof PhotoSwipeEventsMap} T\n */\nclass PhotoSwipeEvent {\n /**\n * @param {T} type\n * @param {PhotoSwipeEventsMap[T]} [details]\n */\n constructor(type, details) {\n this.type = type;\n this.defaultPrevented = false;\n if (details) {\n Object.assign(this, details);\n }\n }\n\n preventDefault() {\n this.defaultPrevented = true;\n }\n}\n\n/**\n * PhotoSwipe base class that can listen and dispatch for events.\n * Shared by PhotoSwipe Core and PhotoSwipe Lightbox, extended by base.js\n */\nclass Eventable {\n constructor() {\n /**\n * @type {{ [T in keyof PhotoSwipeEventsMap]?: ((event: AugmentedEvent) => void)[] }}\n */\n this._listeners = {};\n\n /**\n * @type {{ [T in keyof PhotoSwipeFiltersMap]?: Filter[] }}\n */\n this._filters = {};\n\n /** @type {PhotoSwipe | undefined} */\n this.pswp = undefined;\n\n /** @type {PhotoSwipeOptions | undefined} */\n this.options = undefined;\n }\n\n /**\n * @template {keyof PhotoSwipeFiltersMap} T\n * @param {T} name\n * @param {PhotoSwipeFiltersMap[T]} fn\n * @param {number} priority\n */\n addFilter(name, fn, priority = 100) {\n if (!this._filters[name]) {\n this._filters[name] = [];\n }\n\n this._filters[name]?.push({ fn, priority });\n this._filters[name]?.sort((f1, f2) => f1.priority - f2.priority);\n\n this.pswp?.addFilter(name, fn, priority);\n }\n\n /**\n * @template {keyof PhotoSwipeFiltersMap} T\n * @param {T} name\n * @param {PhotoSwipeFiltersMap[T]} fn\n */\n removeFilter(name, fn) {\n if (this._filters[name]) {\n // @ts-expect-error\n this._filters[name] = this._filters[name].filter(filter => (filter.fn !== fn));\n }\n\n if (this.pswp) {\n this.pswp.removeFilter(name, fn);\n }\n }\n\n /**\n * @template {keyof PhotoSwipeFiltersMap} T\n * @param {T} name\n * @param {Parameters} args\n * @returns {Parameters[0]}\n */\n applyFilters(name, ...args) {\n this._filters[name]?.forEach((filter) => {\n // @ts-expect-error\n args[0] = filter.fn.apply(this, args);\n });\n return args[0];\n }\n\n /**\n * @template {keyof PhotoSwipeEventsMap} T\n * @param {T} name\n * @param {EventCallback} fn\n */\n on(name, fn) {\n if (!this._listeners[name]) {\n this._listeners[name] = [];\n }\n this._listeners[name]?.push(fn);\n\n // When binding events to lightbox,\n // also bind events to PhotoSwipe Core,\n // if it's open.\n this.pswp?.on(name, fn);\n }\n\n /**\n * @template {keyof PhotoSwipeEventsMap} T\n * @param {T} name\n * @param {EventCallback} fn\n */\n off(name, fn) {\n if (this._listeners[name]) {\n // @ts-expect-error\n this._listeners[name] = this._listeners[name].filter(listener => (fn !== listener));\n }\n\n this.pswp?.off(name, fn);\n }\n\n /**\n * @template {keyof PhotoSwipeEventsMap} T\n * @param {T} name\n * @param {PhotoSwipeEventsMap[T]} [details]\n * @returns {AugmentedEvent}\n */\n dispatch(name, details) {\n if (this.pswp) {\n return this.pswp.dispatch(name, details);\n }\n\n const event = /** @type {AugmentedEvent} */ (new PhotoSwipeEvent(name, details));\n\n this._listeners[name]?.forEach((listener) => {\n listener.call(this, event);\n });\n\n return event;\n }\n}\n\nexport default Eventable;\n","import { createElement, setWidthHeight, toTransformString } from '../util/util.js';\n\nclass Placeholder {\n /**\n * @param {string | false} imageSrc\n * @param {HTMLElement} container\n */\n constructor(imageSrc, container) {\n // Create placeholder\n // (stretched thumbnail or simple div behind the main image)\n /** @type {HTMLImageElement | HTMLDivElement | null} */\n this.element = createElement(\n 'pswp__img pswp__img--placeholder',\n imageSrc ? 'img' : 'div',\n container\n );\n\n if (imageSrc) {\n const imgEl = /** @type {HTMLImageElement} */ (this.element);\n imgEl.decoding = 'async';\n imgEl.alt = '';\n imgEl.src = imageSrc;\n imgEl.setAttribute('role', 'presentation');\n }\n\n this.element.setAttribute('aria-hidden', 'true');\n }\n\n /**\n * @param {number} width\n * @param {number} height\n */\n setDisplayedSize(width, height) {\n if (!this.element) {\n return;\n }\n\n if (this.element.tagName === 'IMG') {\n // Use transform scale() to modify img placeholder size\n // (instead of changing width/height directly).\n // This helps with performance, specifically in iOS15 Safari.\n setWidthHeight(this.element, 250, 'auto');\n this.element.style.transformOrigin = '0 0';\n this.element.style.transform = toTransformString(0, 0, width / 250);\n } else {\n setWidthHeight(this.element, width, height);\n }\n }\n\n destroy() {\n if (this.element?.parentNode) {\n this.element.remove();\n }\n this.element = null;\n }\n}\n\nexport default Placeholder;\n","import { createElement, isSafari, LOAD_STATE, setWidthHeight } from '../util/util.js';\nimport Placeholder from './placeholder.js';\n\n/** @typedef {import('./slide.js').default} Slide */\n/** @typedef {import('./slide.js').SlideData} SlideData */\n/** @typedef {import('../core/base.js').default} PhotoSwipeBase */\n/** @typedef {import('../util/util.js').LoadState} LoadState */\n\nclass Content {\n /**\n * @param {SlideData} itemData Slide data\n * @param {PhotoSwipeBase} instance PhotoSwipe or PhotoSwipeLightbox instance\n * @param {number} index\n */\n constructor(itemData, instance, index) {\n this.instance = instance;\n this.data = itemData;\n this.index = index;\n\n /** @type {HTMLImageElement | HTMLDivElement | undefined} */\n this.element = undefined;\n /** @type {Placeholder | undefined} */\n this.placeholder = undefined;\n /** @type {Slide | undefined} */\n this.slide = undefined;\n\n this.displayedImageWidth = 0;\n this.displayedImageHeight = 0;\n\n this.width = Number(this.data.w) || Number(this.data.width) || 0;\n this.height = Number(this.data.h) || Number(this.data.height) || 0;\n\n this.isAttached = false;\n this.hasSlide = false;\n this.isDecoding = false;\n /** @type {LoadState} */\n this.state = LOAD_STATE.IDLE;\n\n if (this.data.type) {\n this.type = this.data.type;\n } else if (this.data.src) {\n this.type = 'image';\n } else {\n this.type = 'html';\n }\n\n this.instance.dispatch('contentInit', { content: this });\n }\n\n removePlaceholder() {\n if (this.placeholder && !this.keepPlaceholder()) {\n // With delay, as image might be loaded, but not rendered\n setTimeout(() => {\n if (this.placeholder) {\n this.placeholder.destroy();\n this.placeholder = undefined;\n }\n }, 1000);\n }\n }\n\n /**\n * Preload content\n *\n * @param {boolean} isLazy\n * @param {boolean} [reload]\n */\n load(isLazy, reload) {\n if (this.slide && this.usePlaceholder()) {\n if (!this.placeholder) {\n const placeholderSrc = this.instance.applyFilters(\n 'placeholderSrc',\n // use image-based placeholder only for the first slide,\n // as rendering (even small stretched thumbnail) is an expensive operation\n (this.data.msrc && this.slide.isFirstSlide) ? this.data.msrc : false,\n this\n );\n this.placeholder = new Placeholder(\n placeholderSrc,\n this.slide.container\n );\n } else {\n const placeholderEl = this.placeholder.element;\n // Add placeholder to DOM if it was already created\n if (placeholderEl && !placeholderEl.parentElement) {\n this.slide.container.prepend(placeholderEl);\n }\n }\n }\n\n if (this.element && !reload) {\n return;\n }\n\n if (this.instance.dispatch('contentLoad', { content: this, isLazy }).defaultPrevented) {\n return;\n }\n\n if (this.isImageContent()) {\n this.element = createElement('pswp__img', 'img');\n // Start loading only after width is defined, as sizes might depend on it.\n // Due to Safari feature, we must define sizes before srcset.\n if (this.displayedImageWidth) {\n this.loadImage(isLazy);\n }\n } else {\n this.element = createElement('pswp__content', 'div');\n this.element.innerHTML = this.data.html || '';\n }\n\n if (reload && this.slide) {\n this.slide.updateContentSize(true);\n }\n }\n\n /**\n * Preload image\n *\n * @param {boolean} isLazy\n */\n loadImage(isLazy) {\n if (!this.isImageContent()\n || !this.element\n || this.instance.dispatch('contentLoadImage', { content: this, isLazy }).defaultPrevented) {\n return;\n }\n\n const imageElement = /** @type HTMLImageElement */ (this.element);\n\n this.updateSrcsetSizes();\n\n if (this.data.srcset) {\n imageElement.srcset = this.data.srcset;\n }\n\n imageElement.src = this.data.src ?? '';\n imageElement.alt = this.data.alt ?? '';\n\n this.state = LOAD_STATE.LOADING;\n\n if (imageElement.complete) {\n this.onLoaded();\n } else {\n imageElement.onload = () => {\n this.onLoaded();\n };\n\n imageElement.onerror = () => {\n this.onError();\n };\n }\n }\n\n /**\n * Assign slide to content\n *\n * @param {Slide} slide\n */\n setSlide(slide) {\n this.slide = slide;\n this.hasSlide = true;\n this.instance = slide.pswp;\n\n // todo: do we need to unset slide?\n }\n\n /**\n * Content load success handler\n */\n onLoaded() {\n this.state = LOAD_STATE.LOADED;\n\n if (this.slide && this.element) {\n this.instance.dispatch('loadComplete', { slide: this.slide, content: this });\n\n // if content is reloaded\n if (this.slide.isActive\n && this.slide.heavyAppended\n && !this.element.parentNode) {\n this.append();\n this.slide.updateContentSize(true);\n }\n\n if (this.state === LOAD_STATE.LOADED || this.state === LOAD_STATE.ERROR) {\n this.removePlaceholder();\n }\n }\n }\n\n /**\n * Content load error handler\n */\n onError() {\n this.state = LOAD_STATE.ERROR;\n\n if (this.slide) {\n this.displayError();\n this.instance.dispatch('loadComplete', { slide: this.slide, isError: true, content: this });\n this.instance.dispatch('loadError', { slide: this.slide, content: this });\n }\n }\n\n /**\n * @returns {Boolean} If the content is currently loading\n */\n isLoading() {\n return this.instance.applyFilters(\n 'isContentLoading',\n this.state === LOAD_STATE.LOADING,\n this\n );\n }\n\n /**\n * @returns {Boolean} If the content is in error state\n */\n isError() {\n return this.state === LOAD_STATE.ERROR;\n }\n\n /**\n * @returns {boolean} If the content is image\n */\n isImageContent() {\n return this.type === 'image';\n }\n\n /**\n * Update content size\n *\n * @param {Number} width\n * @param {Number} height\n */\n setDisplayedSize(width, height) {\n if (!this.element) {\n return;\n }\n\n if (this.placeholder) {\n this.placeholder.setDisplayedSize(width, height);\n }\n\n if (this.instance.dispatch(\n 'contentResize',\n { content: this, width, height }).defaultPrevented\n ) {\n return;\n }\n\n setWidthHeight(this.element, width, height);\n\n if (this.isImageContent() && !this.isError()) {\n const isInitialSizeUpdate = (!this.displayedImageWidth && width);\n\n this.displayedImageWidth = width;\n this.displayedImageHeight = height;\n\n if (isInitialSizeUpdate) {\n this.loadImage(false);\n } else {\n this.updateSrcsetSizes();\n }\n\n if (this.slide) {\n this.instance.dispatch(\n 'imageSizeChange',\n { slide: this.slide, width, height, content: this }\n );\n }\n }\n }\n\n /**\n * @returns {boolean} If the content can be zoomed\n */\n isZoomable() {\n return this.instance.applyFilters(\n 'isContentZoomable',\n this.isImageContent() && (this.state !== LOAD_STATE.ERROR),\n this\n );\n }\n\n /**\n * Update image srcset sizes attribute based on width and height\n */\n updateSrcsetSizes() {\n // Handle srcset sizes attribute.\n //\n // Never lower quality, if it was increased previously.\n // Chrome does this automatically, Firefox and Safari do not,\n // so we store largest used size in dataset.\n if (!this.isImageContent() || !this.element || !this.data.srcset) {\n return;\n }\n\n const image = /** @type HTMLImageElement */ (this.element);\n const sizesWidth = this.instance.applyFilters(\n 'srcsetSizesWidth',\n this.displayedImageWidth,\n this\n );\n\n if (\n !image.dataset.largestUsedSize\n || sizesWidth > parseInt(image.dataset.largestUsedSize, 10)\n ) {\n image.sizes = sizesWidth + 'px';\n image.dataset.largestUsedSize = String(sizesWidth);\n }\n }\n\n /**\n * @returns {boolean} If content should use a placeholder (from msrc by default)\n */\n usePlaceholder() {\n return this.instance.applyFilters(\n 'useContentPlaceholder',\n this.isImageContent(),\n this\n );\n }\n\n /**\n * Preload content with lazy-loading param\n */\n lazyLoad() {\n if (this.instance.dispatch('contentLazyLoad', { content: this }).defaultPrevented) {\n return;\n }\n\n this.load(true);\n }\n\n /**\n * @returns {boolean} If placeholder should be kept after content is loaded\n */\n keepPlaceholder() {\n return this.instance.applyFilters(\n 'isKeepingPlaceholder',\n this.isLoading(),\n this\n );\n }\n\n /**\n * Destroy the content\n */\n destroy() {\n this.hasSlide = false;\n this.slide = undefined;\n\n if (this.instance.dispatch('contentDestroy', { content: this }).defaultPrevented) {\n return;\n }\n\n this.remove();\n\n if (this.placeholder) {\n this.placeholder.destroy();\n this.placeholder = undefined;\n }\n\n if (this.isImageContent() && this.element) {\n this.element.onload = null;\n this.element.onerror = null;\n this.element = undefined;\n }\n }\n\n /**\n * Display error message\n */\n displayError() {\n if (this.slide) {\n let errorMsgEl = createElement('pswp__error-msg', 'div');\n errorMsgEl.innerText = this.instance.options?.errorMsg ?? '';\n errorMsgEl = /** @type {HTMLDivElement} */ (this.instance.applyFilters(\n 'contentErrorElement',\n errorMsgEl,\n this\n ));\n this.element = createElement('pswp__content pswp__error-msg-container', 'div');\n this.element.appendChild(errorMsgEl);\n this.slide.container.innerText = '';\n this.slide.container.appendChild(this.element);\n this.slide.updateContentSize(true);\n this.removePlaceholder();\n }\n }\n\n /**\n * Append the content\n */\n append() {\n if (this.isAttached || !this.element) {\n return;\n }\n\n this.isAttached = true;\n\n if (this.state === LOAD_STATE.ERROR) {\n this.displayError();\n return;\n }\n\n if (this.instance.dispatch('contentAppend', { content: this }).defaultPrevented) {\n return;\n }\n\n const supportsDecode = ('decode' in this.element);\n\n if (this.isImageContent()) {\n // Use decode() on nearby slides\n //\n // Nearby slide images are in DOM and not hidden via display:none.\n // However, they are placed offscreen (to the left and right side).\n //\n // Some browsers do not composite the image until it's actually visible,\n // using decode() helps.\n //\n // You might ask \"why dont you just decode() and then append all images\",\n // that's because I want to show image before it's fully loaded,\n // as browser can render parts of image while it is loading.\n // We do not do this in Safari due to partial loading bug.\n if (supportsDecode && this.slide && (!this.slide.isActive || isSafari())) {\n this.isDecoding = true;\n // purposefully using finally instead of then,\n // as if srcset sizes changes dynamically - it may cause decode error\n /** @type {HTMLImageElement} */\n (this.element).decode().catch(() => {}).finally(() => {\n this.isDecoding = false;\n this.appendImage();\n });\n } else {\n this.appendImage();\n }\n } else if (this.slide && !this.element.parentNode) {\n this.slide.container.appendChild(this.element);\n }\n }\n\n /**\n * Activate the slide,\n * active slide is generally the current one,\n * meaning the user can see it.\n */\n activate() {\n if (this.instance.dispatch('contentActivate', { content: this }).defaultPrevented\n || !this.slide) {\n return;\n }\n\n if (this.isImageContent() && this.isDecoding && !isSafari()) {\n // add image to slide when it becomes active,\n // even if it's not finished decoding\n this.appendImage();\n } else if (this.isError()) {\n this.load(false, true); // try to reload\n }\n\n if (this.slide.holderElement) {\n this.slide.holderElement.setAttribute('aria-hidden', 'false');\n }\n }\n\n /**\n * Deactivate the content\n */\n deactivate() {\n this.instance.dispatch('contentDeactivate', { content: this });\n if (this.slide && this.slide.holderElement) {\n this.slide.holderElement.setAttribute('aria-hidden', 'true');\n }\n }\n\n\n /**\n * Remove the content from DOM\n */\n remove() {\n this.isAttached = false;\n\n if (this.instance.dispatch('contentRemove', { content: this }).defaultPrevented) {\n return;\n }\n\n if (this.element && this.element.parentNode) {\n this.element.remove();\n }\n\n if (this.placeholder && this.placeholder.element) {\n this.placeholder.element.remove();\n }\n }\n\n /**\n * Append the image content to slide container\n */\n appendImage() {\n if (!this.isAttached) {\n return;\n }\n\n if (this.instance.dispatch('contentAppendImage', { content: this }).defaultPrevented) {\n return;\n }\n\n // ensure that element exists and is not already appended\n if (this.slide && this.element && !this.element.parentNode) {\n this.slide.container.appendChild(this.element);\n }\n\n if (this.state === LOAD_STATE.LOADED || this.state === LOAD_STATE.ERROR) {\n this.removePlaceholder();\n }\n }\n}\n\nexport default Content;\n","import { getViewportSize, getPanAreaSize } from '../util/viewport-size.js';\nimport ZoomLevel from './zoom-level.js';\n\n/** @typedef {import('./content.js').default} Content */\n/** @typedef {import('./slide.js').default} Slide */\n/** @typedef {import('./slide.js').SlideData} SlideData */\n/** @typedef {import('../core/base.js').default} PhotoSwipeBase */\n/** @typedef {import('../photoswipe.js').default} PhotoSwipe */\n\nconst MIN_SLIDES_TO_CACHE = 5;\n\n/**\n * Lazy-load an image\n * This function is used both by Lightbox and PhotoSwipe core,\n * thus it can be called before dialog is opened.\n *\n * @param {SlideData} itemData Data about the slide\n * @param {PhotoSwipeBase} instance PhotoSwipe or PhotoSwipeLightbox instance\n * @param {number} index\n * @returns {Content} Image that is being decoded or false.\n */\nexport function lazyLoadData(itemData, instance, index) {\n const content = instance.createContentFromData(itemData, index);\n /** @type {ZoomLevel | undefined} */\n let zoomLevel;\n\n const { options } = instance;\n\n // We need to know dimensions of the image to preload it,\n // as it might use srcset, and we need to define sizes\n if (options) {\n zoomLevel = new ZoomLevel(options, itemData, -1);\n\n let viewportSize;\n if (instance.pswp) {\n viewportSize = instance.pswp.viewportSize;\n } else {\n viewportSize = getViewportSize(options, instance);\n }\n\n const panAreaSize = getPanAreaSize(options, viewportSize, itemData, index);\n zoomLevel.update(content.width, content.height, panAreaSize);\n }\n\n content.lazyLoad();\n\n if (zoomLevel) {\n content.setDisplayedSize(\n Math.ceil(content.width * zoomLevel.initial),\n Math.ceil(content.height * zoomLevel.initial)\n );\n }\n\n return content;\n}\n\n\n/**\n * Lazy-loads specific slide.\n * This function is used both by Lightbox and PhotoSwipe core,\n * thus it can be called before dialog is opened.\n *\n * By default, it loads image based on viewport size and initial zoom level.\n *\n * @param {number} index Slide index\n * @param {PhotoSwipeBase} instance PhotoSwipe or PhotoSwipeLightbox eventable instance\n * @returns {Content | undefined}\n */\nexport function lazyLoadSlide(index, instance) {\n const itemData = instance.getItemData(index);\n\n if (instance.dispatch('lazyLoadSlide', { index, itemData }).defaultPrevented) {\n return;\n }\n\n return lazyLoadData(itemData, instance, index);\n}\n\nclass ContentLoader {\n /**\n * @param {PhotoSwipe} pswp\n */\n constructor(pswp) {\n this.pswp = pswp;\n // Total amount of cached images\n this.limit = Math.max(\n pswp.options.preload[0] + pswp.options.preload[1] + 1,\n MIN_SLIDES_TO_CACHE\n );\n /** @type {Content[]} */\n this._cachedItems = [];\n }\n\n /**\n * Lazy load nearby slides based on `preload` option.\n *\n * @param {number} [diff] Difference between slide indexes that was changed recently, or 0.\n */\n updateLazy(diff) {\n const { pswp } = this;\n\n if (pswp.dispatch('lazyLoad').defaultPrevented) {\n return;\n }\n\n const { preload } = pswp.options;\n const isForward = diff === undefined ? true : (diff >= 0);\n let i;\n\n // preload[1] - num items to preload in forward direction\n for (i = 0; i <= preload[1]; i++) {\n this.loadSlideByIndex(pswp.currIndex + (isForward ? i : (-i)));\n }\n\n // preload[0] - num items to preload in backward direction\n for (i = 1; i <= preload[0]; i++) {\n this.loadSlideByIndex(pswp.currIndex + (isForward ? (-i) : i));\n }\n }\n\n /**\n * @param {number} initialIndex\n */\n loadSlideByIndex(initialIndex) {\n const index = this.pswp.getLoopedIndex(initialIndex);\n // try to get cached content\n let content = this.getContentByIndex(index);\n if (!content) {\n // no cached content, so try to load from scratch:\n content = lazyLoadSlide(index, this.pswp);\n // if content can be loaded, add it to cache:\n if (content) {\n this.addToCache(content);\n }\n }\n }\n\n /**\n * @param {Slide} slide\n * @returns {Content}\n */\n getContentBySlide(slide) {\n let content = this.getContentByIndex(slide.index);\n if (!content) {\n // create content if not found in cache\n content = this.pswp.createContentFromData(slide.data, slide.index);\n this.addToCache(content);\n }\n\n // assign slide to content\n content.setSlide(slide);\n\n return content;\n }\n\n /**\n * @param {Content} content\n */\n addToCache(content) {\n // move to the end of array\n this.removeByIndex(content.index);\n this._cachedItems.push(content);\n\n if (this._cachedItems.length > this.limit) {\n // Destroy the first content that's not attached\n const indexToRemove = this._cachedItems.findIndex((item) => {\n return !item.isAttached && !item.hasSlide;\n });\n if (indexToRemove !== -1) {\n const removedItem = this._cachedItems.splice(indexToRemove, 1)[0];\n removedItem.destroy();\n }\n }\n }\n\n /**\n * Removes an image from cache, does not destroy() it, just removes.\n *\n * @param {number} index\n */\n removeByIndex(index) {\n const indexToRemove = this._cachedItems.findIndex(item => item.index === index);\n if (indexToRemove !== -1) {\n this._cachedItems.splice(indexToRemove, 1);\n }\n }\n\n /**\n * @param {number} index\n * @returns {Content | undefined}\n */\n getContentByIndex(index) {\n return this._cachedItems.find(content => content.index === index);\n }\n\n destroy() {\n this._cachedItems.forEach(content => content.destroy());\n this._cachedItems = [];\n }\n}\n\nexport default ContentLoader;\n","import Eventable from './eventable.js';\nimport { getElementsFromOption } from '../util/util.js';\nimport Content from '../slide/content.js';\nimport { lazyLoadData } from '../slide/loader.js';\n\n/** @typedef {import(\"../photoswipe.js\").default} PhotoSwipe */\n/** @typedef {import(\"../slide/slide.js\").SlideData} SlideData */\n\n/**\n * PhotoSwipe base class that can retrieve data about every slide.\n * Shared by PhotoSwipe Core and PhotoSwipe Lightbox\n */\nclass PhotoSwipeBase extends Eventable {\n /**\n * Get total number of slides\n *\n * @returns {number}\n */\n getNumItems() {\n let numItems = 0;\n const dataSource = this.options?.dataSource;\n\n if (dataSource && 'length' in dataSource) {\n // may be an array or just object with length property\n numItems = dataSource.length;\n } else if (dataSource && 'gallery' in dataSource) {\n // query DOM elements\n if (!dataSource.items) {\n dataSource.items = this._getGalleryDOMElements(dataSource.gallery);\n }\n\n if (dataSource.items) {\n numItems = dataSource.items.length;\n }\n }\n\n // legacy event, before filters were introduced\n const event = this.dispatch('numItems', {\n dataSource,\n numItems\n });\n return this.applyFilters('numItems', event.numItems, dataSource);\n }\n\n /**\n * @param {SlideData} slideData\n * @param {number} index\n * @returns {Content}\n */\n createContentFromData(slideData, index) {\n return new Content(slideData, this, index);\n }\n\n /**\n * Get item data by index.\n *\n * \"item data\" should contain normalized information that PhotoSwipe needs to generate a slide.\n * For example, it may contain properties like\n * `src`, `srcset`, `w`, `h`, which will be used to generate a slide with image.\n *\n * @param {number} index\n * @returns {SlideData}\n */\n getItemData(index) {\n const dataSource = this.options?.dataSource;\n /** @type {SlideData | HTMLElement} */\n let dataSourceItem = {};\n if (Array.isArray(dataSource)) {\n // Datasource is an array of elements\n dataSourceItem = dataSource[index];\n } else if (dataSource && 'gallery' in dataSource) {\n // dataSource has gallery property,\n // thus it was created by Lightbox, based on\n // gallery and children options\n\n // query DOM elements\n if (!dataSource.items) {\n dataSource.items = this._getGalleryDOMElements(dataSource.gallery);\n }\n\n dataSourceItem = dataSource.items[index];\n }\n\n let itemData = dataSourceItem;\n\n if (itemData instanceof Element) {\n itemData = this._domElementToItemData(itemData);\n }\n\n // Dispatching the itemData event,\n // it's a legacy verion before filters were introduced\n const event = this.dispatch('itemData', {\n itemData: itemData || {},\n index\n });\n\n return this.applyFilters('itemData', event.itemData, index);\n }\n\n /**\n * Get array of gallery DOM elements,\n * based on childSelector and gallery element.\n *\n * @param {HTMLElement} galleryElement\n * @returns {HTMLElement[]}\n */\n _getGalleryDOMElements(galleryElement) {\n if (this.options?.children || this.options?.childSelector) {\n return getElementsFromOption(\n this.options.children,\n this.options.childSelector,\n galleryElement\n ) || [];\n }\n\n return [galleryElement];\n }\n\n /**\n * Converts DOM element to item data object.\n *\n * @param {HTMLElement} element DOM element\n * @returns {SlideData}\n */\n _domElementToItemData(element) {\n /** @type {SlideData} */\n const itemData = {\n element\n };\n\n const linkEl = /** @type {HTMLAnchorElement} */ (\n element.tagName === 'A'\n ? element\n : element.querySelector('a')\n );\n\n if (linkEl) {\n // src comes from data-pswp-src attribute,\n // if it's empty link href is used\n itemData.src = linkEl.dataset.pswpSrc || linkEl.href;\n\n if (linkEl.dataset.pswpSrcset) {\n itemData.srcset = linkEl.dataset.pswpSrcset;\n }\n\n itemData.width = linkEl.dataset.pswpWidth ? parseInt(linkEl.dataset.pswpWidth, 10) : 0;\n itemData.height = linkEl.dataset.pswpHeight ? parseInt(linkEl.dataset.pswpHeight, 10) : 0;\n\n // support legacy w & h properties\n itemData.w = itemData.width;\n itemData.h = itemData.height;\n\n if (linkEl.dataset.pswpType) {\n itemData.type = linkEl.dataset.pswpType;\n }\n\n const thumbnailEl = element.querySelector('img');\n\n if (thumbnailEl) {\n // msrc is URL to placeholder image that's displayed before large image is loaded\n // by default it's displayed only for the first slide\n itemData.msrc = thumbnailEl.currentSrc || thumbnailEl.src;\n itemData.alt = thumbnailEl.getAttribute('alt') ?? '';\n }\n\n if (linkEl.dataset.pswpCropped || linkEl.dataset.cropped) {\n itemData.thumbCropped = true;\n }\n }\n\n return this.applyFilters('domItemData', itemData, element, linkEl);\n }\n\n /**\n * Lazy-load by slide data\n *\n * @param {SlideData} itemData Data about the slide\n * @param {number} index\n * @returns {Content} Image that is being decoded or false.\n */\n lazyLoadData(itemData, index) {\n return lazyLoadData(itemData, this, index);\n }\n}\n\nexport default PhotoSwipeBase;\n","import {\n setTransform,\n equalizePoints,\n decodeImage,\n toTransformString\n} from './util/util.js';\n\n/** @typedef {import('./photoswipe.js').default} PhotoSwipe */\n/** @typedef {import('./slide/get-thumb-bounds.js').Bounds} Bounds */\n/** @typedef {import('./util/animations.js').AnimationProps} AnimationProps */\n\n// some browsers do not paint\n// elements which opacity is set to 0,\n// since we need to pre-render elements for the animation -\n// we set it to the minimum amount\nconst MIN_OPACITY = 0.003;\n\n/**\n * Manages opening and closing transitions of the PhotoSwipe.\n *\n * It can perform zoom, fade or no transition.\n */\nclass Opener {\n /**\n * @param {PhotoSwipe} pswp\n */\n constructor(pswp) {\n this.pswp = pswp;\n this.isClosed = true;\n this.isOpen = false;\n this.isClosing = false;\n this.isOpening = false;\n /**\n * @private\n * @type {number | false | undefined}\n */\n this._duration = undefined;\n /** @private */\n this._useAnimation = false;\n /** @private */\n this._croppedZoom = false;\n /** @private */\n this._animateRootOpacity = false;\n /** @private */\n this._animateBgOpacity = false;\n /**\n * @private\n * @type { HTMLDivElement | HTMLImageElement | null | undefined }\n */\n this._placeholder = undefined;\n /**\n * @private\n * @type { HTMLDivElement | undefined }\n */\n this._opacityElement = undefined;\n /**\n * @private\n * @type { HTMLDivElement | undefined }\n */\n this._cropContainer1 = undefined;\n /**\n * @private\n * @type { HTMLElement | null | undefined }\n */\n this._cropContainer2 = undefined;\n\n /**\n * @private\n * @type {Bounds | undefined}\n */\n this._thumbBounds = undefined;\n\n\n this._prepareOpen = this._prepareOpen.bind(this);\n\n // Override initial zoom and pan position\n pswp.on('firstZoomPan', this._prepareOpen);\n }\n\n open() {\n this._prepareOpen();\n this._start();\n }\n\n close() {\n if (this.isClosed || this.isClosing || this.isOpening) {\n // if we close during opening animation\n // for now do nothing,\n // browsers aren't good at changing the direction of the CSS transition\n return;\n }\n\n const slide = this.pswp.currSlide;\n\n this.isOpen = false;\n this.isOpening = false;\n this.isClosing = true;\n this._duration = this.pswp.options.hideAnimationDuration;\n\n if (slide && slide.currZoomLevel * slide.width >= this.pswp.options.maxWidthToAnimate) {\n this._duration = 0;\n }\n\n this._applyStartProps();\n setTimeout(() => {\n this._start();\n }, this._croppedZoom ? 30 : 0);\n }\n\n /** @private */\n _prepareOpen() {\n this.pswp.off('firstZoomPan', this._prepareOpen);\n if (!this.isOpening) {\n const slide = this.pswp.currSlide;\n this.isOpening = true;\n this.isClosing = false;\n this._duration = this.pswp.options.showAnimationDuration;\n if (slide && slide.zoomLevels.initial * slide.width >= this.pswp.options.maxWidthToAnimate) {\n this._duration = 0;\n }\n this._applyStartProps();\n }\n }\n\n /** @private */\n _applyStartProps() {\n const { pswp } = this;\n const slide = this.pswp.currSlide;\n const { options } = pswp;\n\n if (options.showHideAnimationType === 'fade') {\n options.showHideOpacity = true;\n this._thumbBounds = undefined;\n } else if (options.showHideAnimationType === 'none') {\n options.showHideOpacity = false;\n this._duration = 0;\n this._thumbBounds = undefined;\n } else if (this.isOpening && pswp._initialThumbBounds) {\n // Use initial bounds if defined\n this._thumbBounds = pswp._initialThumbBounds;\n } else {\n this._thumbBounds = this.pswp.getThumbBounds();\n }\n\n this._placeholder = slide?.getPlaceholderElement();\n\n pswp.animations.stopAll();\n\n // Discard animations when duration is less than 50ms\n this._useAnimation = Boolean(this._duration && this._duration > 50);\n this._animateZoom = Boolean(this._thumbBounds)\n && slide?.content.usePlaceholder()\n && (!this.isClosing || !pswp.mainScroll.isShifted());\n if (!this._animateZoom) {\n this._animateRootOpacity = true;\n\n if (this.isOpening && slide) {\n slide.zoomAndPanToInitial();\n slide.applyCurrentZoomPan();\n }\n } else {\n this._animateRootOpacity = options.showHideOpacity ?? false;\n }\n this._animateBgOpacity = !this._animateRootOpacity && this.pswp.options.bgOpacity > MIN_OPACITY;\n this._opacityElement = this._animateRootOpacity ? pswp.element : pswp.bg;\n\n if (!this._useAnimation) {\n this._duration = 0;\n this._animateZoom = false;\n this._animateBgOpacity = false;\n this._animateRootOpacity = true;\n if (this.isOpening) {\n if (pswp.element) {\n pswp.element.style.opacity = String(MIN_OPACITY);\n }\n pswp.applyBgOpacity(1);\n }\n return;\n }\n\n if (this._animateZoom && this._thumbBounds && this._thumbBounds.innerRect) {\n // Properties are used when animation from cropped thumbnail\n this._croppedZoom = true;\n this._cropContainer1 = this.pswp.container;\n this._cropContainer2 = this.pswp.currSlide?.holderElement;\n\n if (pswp.container) {\n pswp.container.style.overflow = 'hidden';\n pswp.container.style.width = pswp.viewportSize.x + 'px';\n }\n } else {\n this._croppedZoom = false;\n }\n\n if (this.isOpening) {\n // Apply styles before opening transition\n if (this._animateRootOpacity) {\n if (pswp.element) {\n pswp.element.style.opacity = String(MIN_OPACITY);\n }\n pswp.applyBgOpacity(1);\n } else {\n if (this._animateBgOpacity && pswp.bg) {\n pswp.bg.style.opacity = String(MIN_OPACITY);\n }\n if (pswp.element) {\n pswp.element.style.opacity = '1';\n }\n }\n\n if (this._animateZoom) {\n this._setClosedStateZoomPan();\n if (this._placeholder) {\n // tell browser that we plan to animate the placeholder\n this._placeholder.style.willChange = 'transform';\n\n // hide placeholder to allow hiding of\n // elements that overlap it (such as icons over the thumbnail)\n this._placeholder.style.opacity = String(MIN_OPACITY);\n }\n }\n } else if (this.isClosing) {\n // hide nearby slides to make sure that\n // they are not painted during the transition\n if (pswp.mainScroll.itemHolders[0]) {\n pswp.mainScroll.itemHolders[0].el.style.display = 'none';\n }\n if (pswp.mainScroll.itemHolders[2]) {\n pswp.mainScroll.itemHolders[2].el.style.display = 'none';\n }\n\n if (this._croppedZoom) {\n if (pswp.mainScroll.x !== 0) {\n // shift the main scroller to zero position\n pswp.mainScroll.resetPosition();\n pswp.mainScroll.resize();\n }\n }\n }\n }\n\n /** @private */\n _start() {\n if (this.isOpening\n && this._useAnimation\n && this._placeholder\n && this._placeholder.tagName === 'IMG') {\n // To ensure smooth animation\n // we wait till the current slide image placeholder is decoded,\n // but no longer than 250ms,\n // and no shorter than 50ms\n // (just using requestanimationframe is not enough in Firefox,\n // for some reason)\n new Promise((resolve) => {\n let decoded = false;\n let isDelaying = true;\n decodeImage(/** @type {HTMLImageElement} */ (this._placeholder)).finally(() => {\n decoded = true;\n if (!isDelaying) {\n resolve(true);\n }\n });\n setTimeout(() => {\n isDelaying = false;\n if (decoded) {\n resolve(true);\n }\n }, 50);\n setTimeout(resolve, 250);\n }).finally(() => this._initiate());\n } else {\n this._initiate();\n }\n }\n\n /** @private */\n _initiate() {\n this.pswp.element?.style.setProperty('--pswp-transition-duration', this._duration + 'ms');\n\n this.pswp.dispatch(\n this.isOpening ? 'openingAnimationStart' : 'closingAnimationStart'\n );\n\n // legacy event\n this.pswp.dispatch(\n /** @type {'initialZoomIn' | 'initialZoomOut'} */\n ('initialZoom' + (this.isOpening ? 'In' : 'Out'))\n );\n\n this.pswp.element?.classList.toggle('pswp--ui-visible', this.isOpening);\n\n if (this.isOpening) {\n if (this._placeholder) {\n // unhide the placeholder\n this._placeholder.style.opacity = '1';\n }\n this._animateToOpenState();\n } else if (this.isClosing) {\n this._animateToClosedState();\n }\n\n if (!this._useAnimation) {\n this._onAnimationComplete();\n }\n }\n\n /** @private */\n _onAnimationComplete() {\n const { pswp } = this;\n this.isOpen = this.isOpening;\n this.isClosed = this.isClosing;\n this.isOpening = false;\n this.isClosing = false;\n\n pswp.dispatch(\n this.isOpen ? 'openingAnimationEnd' : 'closingAnimationEnd'\n );\n\n // legacy event\n pswp.dispatch(\n /** @type {'initialZoomInEnd' | 'initialZoomOutEnd'} */\n ('initialZoom' + (this.isOpen ? 'InEnd' : 'OutEnd'))\n );\n\n if (this.isClosed) {\n pswp.destroy();\n } else if (this.isOpen) {\n if (this._animateZoom && pswp.container) {\n pswp.container.style.overflow = 'visible';\n pswp.container.style.width = '100%';\n }\n pswp.currSlide?.applyCurrentZoomPan();\n }\n }\n\n /** @private */\n _animateToOpenState() {\n const { pswp } = this;\n if (this._animateZoom) {\n if (this._croppedZoom && this._cropContainer1 && this._cropContainer2) {\n this._animateTo(this._cropContainer1, 'transform', 'translate3d(0,0,0)');\n this._animateTo(this._cropContainer2, 'transform', 'none');\n }\n\n if (pswp.currSlide) {\n pswp.currSlide.zoomAndPanToInitial();\n this._animateTo(\n pswp.currSlide.container,\n 'transform',\n pswp.currSlide.getCurrentTransform()\n );\n }\n }\n\n if (this._animateBgOpacity && pswp.bg) {\n this._animateTo(pswp.bg, 'opacity', String(pswp.options.bgOpacity));\n }\n\n if (this._animateRootOpacity && pswp.element) {\n this._animateTo(pswp.element, 'opacity', '1');\n }\n }\n\n /** @private */\n _animateToClosedState() {\n const { pswp } = this;\n\n if (this._animateZoom) {\n this._setClosedStateZoomPan(true);\n }\n\n // do not animate opacity if it's already at 0\n if (this._animateBgOpacity && pswp.bgOpacity > 0.01 && pswp.bg) {\n this._animateTo(pswp.bg, 'opacity', '0');\n }\n\n if (this._animateRootOpacity && pswp.element) {\n this._animateTo(pswp.element, 'opacity', '0');\n }\n }\n\n /**\n * @private\n * @param {boolean} [animate]\n */\n _setClosedStateZoomPan(animate) {\n if (!this._thumbBounds) return;\n\n const { pswp } = this;\n const { innerRect } = this._thumbBounds;\n const { currSlide, viewportSize } = pswp;\n\n if (this._croppedZoom && innerRect && this._cropContainer1 && this._cropContainer2) {\n const containerOnePanX = -viewportSize.x + (this._thumbBounds.x - innerRect.x) + innerRect.w;\n const containerOnePanY = -viewportSize.y + (this._thumbBounds.y - innerRect.y) + innerRect.h;\n const containerTwoPanX = viewportSize.x - innerRect.w;\n const containerTwoPanY = viewportSize.y - innerRect.h;\n\n\n if (animate) {\n this._animateTo(\n this._cropContainer1,\n 'transform',\n toTransformString(containerOnePanX, containerOnePanY)\n );\n\n this._animateTo(\n this._cropContainer2,\n 'transform',\n toTransformString(containerTwoPanX, containerTwoPanY)\n );\n } else {\n setTransform(this._cropContainer1, containerOnePanX, containerOnePanY);\n setTransform(this._cropContainer2, containerTwoPanX, containerTwoPanY);\n }\n }\n\n if (currSlide) {\n equalizePoints(currSlide.pan, innerRect || this._thumbBounds);\n currSlide.currZoomLevel = this._thumbBounds.w / currSlide.width;\n if (animate) {\n this._animateTo(currSlide.container, 'transform', currSlide.getCurrentTransform());\n } else {\n currSlide.applyCurrentZoomPan();\n }\n }\n }\n\n /**\n * @private\n * @param {HTMLElement} target\n * @param {'transform' | 'opacity'} prop\n * @param {string} propValue\n */\n _animateTo(target, prop, propValue) {\n if (!this._duration) {\n target.style[prop] = propValue;\n return;\n }\n\n const { animations } = this.pswp;\n /** @type {AnimationProps} */\n const animProps = {\n duration: this._duration,\n easing: this.pswp.options.easing,\n onComplete: () => {\n if (!animations.activeAnimations.length) {\n this._onAnimationComplete();\n }\n },\n target,\n };\n animProps[prop] = propValue;\n animations.startTransition(animProps);\n }\n}\n\nexport default Opener;\n","import {\n createElement,\n equalizePoints,\n pointsEqual,\n clamp,\n} from './util/util.js';\n\nimport DOMEvents from './util/dom-events.js';\nimport Slide from './slide/slide.js';\nimport Gestures from './gestures/gestures.js';\nimport MainScroll from './main-scroll.js';\n\nimport Keyboard from './keyboard.js';\nimport Animations from './util/animations.js';\nimport ScrollWheel from './scroll-wheel.js';\nimport UI from './ui/ui.js';\nimport { getViewportSize } from './util/viewport-size.js';\nimport { getThumbBounds } from './slide/get-thumb-bounds.js';\nimport PhotoSwipeBase from './core/base.js';\nimport Opener from './opener.js';\nimport ContentLoader from './slide/loader.js';\n\n/**\n * @template T\n * @typedef {import('./types.js').Type} Type\n */\n\n/** @typedef {import('./slide/slide.js').SlideData} SlideData */\n/** @typedef {import('./slide/zoom-level.js').ZoomLevelOption} ZoomLevelOption */\n/** @typedef {import('./ui/ui-element.js').UIElementData} UIElementData */\n/** @typedef {import('./main-scroll.js').ItemHolder} ItemHolder */\n/** @typedef {import('./core/eventable.js').PhotoSwipeEventsMap} PhotoSwipeEventsMap */\n/** @typedef {import('./core/eventable.js').PhotoSwipeFiltersMap} PhotoSwipeFiltersMap */\n/** @typedef {import('./slide/get-thumb-bounds').Bounds} Bounds */\n/**\n * @template {keyof PhotoSwipeEventsMap} T\n * @typedef {import('./core/eventable.js').EventCallback} EventCallback\n */\n/**\n * @template {keyof PhotoSwipeEventsMap} T\n * @typedef {import('./core/eventable.js').AugmentedEvent} AugmentedEvent\n */\n\n/** @typedef {{ x: number; y: number; id?: string | number }} Point */\n/** @typedef {{ top: number; bottom: number; left: number; right: number }} Padding */\n/** @typedef {SlideData[]} DataSourceArray */\n/** @typedef {{ gallery: HTMLElement; items?: HTMLElement[] }} DataSourceObject */\n/** @typedef {DataSourceArray | DataSourceObject} DataSource */\n/** @typedef {(point: Point, originalEvent: PointerEvent) => void} ActionFn */\n/** @typedef {'close' | 'next' | 'zoom' | 'zoom-or-close' | 'toggle-controls'} ActionType */\n/** @typedef {Type | { default: Type }} PhotoSwipeModule */\n/** @typedef {PhotoSwipeModule | Promise | (() => Promise)} PhotoSwipeModuleOption */\n\n/**\n * @typedef {string | NodeListOf | HTMLElement[] | HTMLElement} ElementProvider\n */\n\n/** @typedef {Partial} PhotoSwipeOptions https://photoswipe.com/options/ */\n/**\n * @typedef {Object} PreparedPhotoSwipeOptions\n *\n * @prop {DataSource} [dataSource]\n * Pass an array of any items via dataSource option. Its length will determine amount of slides\n * (which may be modified further from numItems event).\n *\n * Each item should contain data that you need to generate slide\n * (for image slide it would be src (image URL), width (image width), height, srcset, alt).\n *\n * If these properties are not present in your initial array, you may \"pre-parse\" each item from itemData filter.\n *\n * @prop {number} bgOpacity\n * Background backdrop opacity, always define it via this option and not via CSS rgba color.\n *\n * @prop {number} spacing\n * Spacing between slides. Defined as ratio relative to the viewport width (0.1 = 10% of viewport).\n *\n * @prop {boolean} allowPanToNext\n * Allow swipe navigation to the next slide when the current slide is zoomed. Does not apply to mouse events.\n *\n * @prop {boolean} loop\n * If set to true you'll be able to swipe from the last to the first image.\n * Option is always false when there are less than 3 slides.\n *\n * @prop {boolean} [wheelToZoom]\n * By default PhotoSwipe zooms image with ctrl-wheel, if you enable this option - image will zoom just via wheel.\n *\n * @prop {boolean} pinchToClose\n * Pinch touch gesture to close the gallery.\n *\n * @prop {boolean} closeOnVerticalDrag\n * Vertical drag gesture to close the PhotoSwipe.\n *\n * @prop {Padding} [padding]\n * Slide area padding (in pixels).\n *\n * @prop {(viewportSize: Point, itemData: SlideData, index: number) => Padding} [paddingFn]\n * The option is checked frequently, so make sure it's performant. Overrides padding option if defined. For example:\n *\n * @prop {number | false} hideAnimationDuration\n * Transition duration in milliseconds, can be 0.\n *\n * @prop {number | false} showAnimationDuration\n * Transition duration in milliseconds, can be 0.\n *\n * @prop {number | false} zoomAnimationDuration\n * Transition duration in milliseconds, can be 0.\n *\n * @prop {string} easing\n * String, 'cubic-bezier(.4,0,.22,1)'. CSS easing function for open/close/zoom transitions.\n *\n * @prop {boolean} escKey\n * Esc key to close.\n *\n * @prop {boolean} arrowKeys\n * Left/right arrow keys for navigation.\n *\n * @prop {boolean} returnFocus\n * Restore focus the last active element after PhotoSwipe is closed.\n *\n * @prop {boolean} clickToCloseNonZoomable\n * If image is not zoomable (for example, smaller than viewport) it can be closed by clicking on it.\n *\n * @prop {ActionType | ActionFn | false} imageClickAction\n * Refer to click and tap actions page.\n *\n * @prop {ActionType | ActionFn | false} bgClickAction\n * Refer to click and tap actions page.\n *\n * @prop {ActionType | ActionFn | false} tapAction\n * Refer to click and tap actions page.\n *\n * @prop {ActionType | ActionFn | false} doubleTapAction\n * Refer to click and tap actions page.\n *\n * @prop {number} preloaderDelay\n * Delay before the loading indicator will be displayed,\n * if image is loaded during it - the indicator will not be displayed at all. Can be zero.\n *\n * @prop {string} indexIndicatorSep\n * Used for slide count indicator (\"1 of 10 \").\n *\n * @prop {(options: PhotoSwipeOptions, pswp: PhotoSwipeBase) => Point} [getViewportSizeFn]\n * A function that should return slide viewport width and height, in format {x: 100, y: 100}.\n *\n * @prop {string} errorMsg\n * Message to display when the image wasn't able to load. If you need to display HTML - use contentErrorElement filter.\n *\n * @prop {[number, number]} preload\n * Lazy loading of nearby slides based on direction of movement. Should be an array with two integers,\n * first one - number of items to preload before the current image, second one - after the current image.\n * Two nearby images are always loaded.\n *\n * @prop {string} [mainClass]\n * Class that will be added to the root element of PhotoSwipe, may contain multiple separated by space.\n * Example on Styling page.\n *\n * @prop {HTMLElement} [appendToEl]\n * Element to which PhotoSwipe dialog will be appended when it opens.\n *\n * @prop {number} maxWidthToAnimate\n * Maximum width of image to animate, if initial rendered image width\n * is larger than this value - the opening/closing transition will be automatically disabled.\n *\n * @prop {string} [closeTitle]\n * Translating\n *\n * @prop {string} [zoomTitle]\n * Translating\n *\n * @prop {string} [arrowPrevTitle]\n * Translating\n *\n * @prop {string} [arrowNextTitle]\n * Translating\n *\n * @prop {'zoom' | 'fade' | 'none'} [showHideAnimationType]\n * To adjust opening or closing transition type use lightbox option `showHideAnimationType` (`String`).\n * It supports three values - `zoom` (default), `fade` (default if there is no thumbnail) and `none`.\n *\n * Animations are automatically disabled if user `(prefers-reduced-motion: reduce)`.\n *\n * @prop {number} index\n * Defines start slide index.\n *\n * @prop {(e: MouseEvent) => number} [getClickedIndexFn]\n *\n * @prop {boolean} [arrowPrev]\n * @prop {boolean} [arrowNext]\n * @prop {boolean} [zoom]\n * @prop {boolean} [close]\n * @prop {boolean} [counter]\n *\n * @prop {string} [arrowPrevSVG]\n * @prop {string} [arrowNextSVG]\n * @prop {string} [zoomSVG]\n * @prop {string} [closeSVG]\n * @prop {string} [counterSVG]\n *\n * @prop {string} [arrowPrevTitle]\n * @prop {string} [arrowNextTitle]\n * @prop {string} [zoomTitle]\n * @prop {string} [closeTitle]\n * @prop {string} [counterTitle]\n *\n * @prop {ZoomLevelOption} [initialZoomLevel]\n * @prop {ZoomLevelOption} [secondaryZoomLevel]\n * @prop {ZoomLevelOption} [maxZoomLevel]\n *\n * @prop {boolean} [mouseMovePan]\n * @prop {Point | null} [initialPointerPos]\n * @prop {boolean} [showHideOpacity]\n *\n * @prop {PhotoSwipeModuleOption} [pswpModule]\n * @prop {() => Promise} [openPromise]\n * @prop {boolean} [preloadFirstSlide]\n * @prop {ElementProvider} [gallery]\n * @prop {string} [gallerySelector]\n * @prop {ElementProvider} [children]\n * @prop {string} [childSelector]\n * @prop {string | false} [thumbSelector]\n */\n\n/** @type {PreparedPhotoSwipeOptions} */\nconst defaultOptions = {\n allowPanToNext: true,\n spacing: 0.1,\n loop: true,\n pinchToClose: true,\n closeOnVerticalDrag: true,\n hideAnimationDuration: 333,\n showAnimationDuration: 333,\n zoomAnimationDuration: 333,\n escKey: true,\n arrowKeys: true,\n returnFocus: true,\n maxWidthToAnimate: 4000,\n clickToCloseNonZoomable: true,\n imageClickAction: 'zoom-or-close',\n bgClickAction: 'close',\n tapAction: 'toggle-controls',\n doubleTapAction: 'zoom',\n indexIndicatorSep: ' / ',\n preloaderDelay: 2000,\n bgOpacity: 0.8,\n\n index: 0,\n errorMsg: 'The image cannot be loaded',\n preload: [1, 2],\n easing: 'cubic-bezier(.4,0,.22,1)'\n};\n\n/**\n * PhotoSwipe Core\n */\nclass PhotoSwipe extends PhotoSwipeBase {\n /**\n * @param {PhotoSwipeOptions} [options]\n */\n constructor(options) {\n super();\n\n this.options = this._prepareOptions(options || {});\n\n /**\n * offset of viewport relative to document\n *\n * @type {Point}\n */\n this.offset = { x: 0, y: 0 };\n\n /**\n * @type {Point}\n * @private\n */\n this._prevViewportSize = { x: 0, y: 0 };\n\n /**\n * Size of scrollable PhotoSwipe viewport\n *\n * @type {Point}\n */\n this.viewportSize = { x: 0, y: 0 };\n\n /**\n * background (backdrop) opacity\n */\n this.bgOpacity = 1;\n this.currIndex = 0;\n this.potentialIndex = 0;\n this.isOpen = false;\n this.isDestroying = false;\n this.hasMouse = false;\n\n /**\n * @private\n * @type {SlideData}\n */\n this._initialItemData = {};\n /** @type {Bounds | undefined} */\n this._initialThumbBounds = undefined;\n\n /** @type {HTMLDivElement | undefined} */\n this.topBar = undefined;\n /** @type {HTMLDivElement | undefined} */\n this.element = undefined;\n /** @type {HTMLDivElement | undefined} */\n this.template = undefined;\n /** @type {HTMLDivElement | undefined} */\n this.container = undefined;\n /** @type {HTMLElement | undefined} */\n this.scrollWrap = undefined;\n /** @type {Slide | undefined} */\n this.currSlide = undefined;\n\n this.events = new DOMEvents();\n this.animations = new Animations();\n this.mainScroll = new MainScroll(this);\n this.gestures = new Gestures(this);\n this.opener = new Opener(this);\n this.keyboard = new Keyboard(this);\n this.contentLoader = new ContentLoader(this);\n }\n\n /** @returns {boolean} */\n init() {\n if (this.isOpen || this.isDestroying) {\n return false;\n }\n\n this.isOpen = true;\n this.dispatch('init'); // legacy\n this.dispatch('beforeOpen');\n\n this._createMainStructure();\n\n // add classes to the root element of PhotoSwipe\n let rootClasses = 'pswp--open';\n if (this.gestures.supportsTouch) {\n rootClasses += ' pswp--touch';\n }\n if (this.options.mainClass) {\n rootClasses += ' ' + this.options.mainClass;\n }\n if (this.element) {\n this.element.className += ' ' + rootClasses;\n }\n\n this.currIndex = this.options.index || 0;\n this.potentialIndex = this.currIndex;\n this.dispatch('firstUpdate'); // starting index can be modified here\n\n // initialize scroll wheel handler to block the scroll\n this.scrollWheel = new ScrollWheel(this);\n\n // sanitize index\n if (Number.isNaN(this.currIndex)\n || this.currIndex < 0\n || this.currIndex >= this.getNumItems()) {\n this.currIndex = 0;\n }\n\n if (!this.gestures.supportsTouch) {\n // enable mouse features if no touch support detected\n this.mouseDetected();\n }\n\n // causes forced synchronous layout\n this.updateSize();\n\n this.offset.y = window.pageYOffset;\n\n this._initialItemData = this.getItemData(this.currIndex);\n this.dispatch('gettingData', {\n index: this.currIndex,\n data: this._initialItemData,\n slide: undefined\n });\n\n // *Layout* - calculate size and position of elements here\n this._initialThumbBounds = this.getThumbBounds();\n this.dispatch('initialLayout');\n\n this.on('openingAnimationEnd', () => {\n const { itemHolders } = this.mainScroll;\n\n // Add content to the previous and next slide\n if (itemHolders[0]) {\n itemHolders[0].el.style.display = 'block';\n this.setContent(itemHolders[0], this.currIndex - 1);\n }\n if (itemHolders[2]) {\n itemHolders[2].el.style.display = 'block';\n this.setContent(itemHolders[2], this.currIndex + 1);\n }\n\n this.appendHeavy();\n\n this.contentLoader.updateLazy();\n\n this.events.add(window, 'resize', this._handlePageResize.bind(this));\n this.events.add(window, 'scroll', this._updatePageScrollOffset.bind(this));\n this.dispatch('bindEvents');\n });\n\n // set content for center slide (first time)\n if (this.mainScroll.itemHolders[1]) {\n this.setContent(this.mainScroll.itemHolders[1], this.currIndex);\n }\n this.dispatch('change');\n\n this.opener.open();\n\n this.dispatch('afterInit');\n\n return true;\n }\n\n /**\n * Get looped slide index\n * (for example, -1 will return the last slide)\n *\n * @param {number} index\n * @returns {number}\n */\n getLoopedIndex(index) {\n const numSlides = this.getNumItems();\n\n if (this.options.loop) {\n if (index > numSlides - 1) {\n index -= numSlides;\n }\n\n if (index < 0) {\n index += numSlides;\n }\n }\n\n return clamp(index, 0, numSlides - 1);\n }\n\n appendHeavy() {\n this.mainScroll.itemHolders.forEach((itemHolder) => {\n itemHolder.slide?.appendHeavy();\n });\n }\n\n /**\n * Change the slide\n * @param {number} index New index\n */\n goTo(index) {\n this.mainScroll.moveIndexBy(\n this.getLoopedIndex(index) - this.potentialIndex\n );\n }\n\n /**\n * Go to the next slide.\n */\n next() {\n this.goTo(this.potentialIndex + 1);\n }\n\n /**\n * Go to the previous slide.\n */\n prev() {\n this.goTo(this.potentialIndex - 1);\n }\n\n /**\n * @see slide/slide.js zoomTo\n *\n * @param {Parameters} args\n */\n zoomTo(...args) {\n this.currSlide?.zoomTo(...args);\n }\n\n /**\n * @see slide/slide.js toggleZoom\n */\n toggleZoom() {\n this.currSlide?.toggleZoom();\n }\n\n /**\n * Close the gallery.\n * After closing transition ends - destroy it\n */\n close() {\n if (!this.opener.isOpen || this.isDestroying) {\n return;\n }\n\n this.isDestroying = true;\n\n this.dispatch('close');\n\n this.events.removeAll();\n this.opener.close();\n }\n\n /**\n * Destroys the gallery:\n * - instantly closes the gallery\n * - unbinds events,\n * - cleans intervals and timeouts\n * - removes elements from DOM\n */\n destroy() {\n if (!this.isDestroying) {\n this.options.showHideAnimationType = 'none';\n this.close();\n return;\n }\n\n this.dispatch('destroy');\n\n this._listeners = {};\n\n if (this.scrollWrap) {\n this.scrollWrap.ontouchmove = null;\n this.scrollWrap.ontouchend = null;\n }\n\n this.element?.remove();\n\n this.mainScroll.itemHolders.forEach((itemHolder) => {\n itemHolder.slide?.destroy();\n });\n\n this.contentLoader.destroy();\n this.events.removeAll();\n }\n\n /**\n * Refresh/reload content of a slide by its index\n *\n * @param {number} slideIndex\n */\n refreshSlideContent(slideIndex) {\n this.contentLoader.removeByIndex(slideIndex);\n this.mainScroll.itemHolders.forEach((itemHolder, i) => {\n let potentialHolderIndex = (this.currSlide?.index ?? 0) - 1 + i;\n if (this.canLoop()) {\n potentialHolderIndex = this.getLoopedIndex(potentialHolderIndex);\n }\n if (potentialHolderIndex === slideIndex) {\n // set the new slide content\n this.setContent(itemHolder, slideIndex, true);\n\n // activate the new slide if it's current\n if (i === 1) {\n this.currSlide = itemHolder.slide;\n itemHolder.slide?.setIsActive(true);\n }\n }\n });\n\n this.dispatch('change');\n }\n\n\n /**\n * Set slide content\n *\n * @param {ItemHolder} holder mainScroll.itemHolders array item\n * @param {number} index Slide index\n * @param {boolean} [force] If content should be set even if index wasn't changed\n */\n setContent(holder, index, force) {\n if (this.canLoop()) {\n index = this.getLoopedIndex(index);\n }\n\n if (holder.slide) {\n if (holder.slide.index === index && !force) {\n // exit if holder already contains this slide\n // this could be common when just three slides are used\n return;\n }\n\n // destroy previous slide\n holder.slide.destroy();\n holder.slide = undefined;\n }\n\n // exit if no loop and index is out of bounds\n if (!this.canLoop() && (index < 0 || index >= this.getNumItems())) {\n return;\n }\n\n const itemData = this.getItemData(index);\n holder.slide = new Slide(itemData, index, this);\n\n // set current slide\n if (index === this.currIndex) {\n this.currSlide = holder.slide;\n }\n\n holder.slide.append(holder.el);\n }\n\n /** @returns {Point} */\n getViewportCenterPoint() {\n return {\n x: this.viewportSize.x / 2,\n y: this.viewportSize.y / 2\n };\n }\n\n /**\n * Update size of all elements.\n * Executed on init and on page resize.\n *\n * @param {boolean} [force] Update size even if size of viewport was not changed.\n */\n updateSize(force) {\n // let item;\n // let itemIndex;\n\n if (this.isDestroying) {\n // exit if PhotoSwipe is closed or closing\n // (to avoid errors, as resize event might be delayed)\n return;\n }\n\n //const newWidth = this.scrollWrap.clientWidth;\n //const newHeight = this.scrollWrap.clientHeight;\n\n const newViewportSize = getViewportSize(this.options, this);\n\n if (!force && pointsEqual(newViewportSize, this._prevViewportSize)) {\n // Exit if dimensions were not changed\n return;\n }\n\n //this._prevViewportSize.x = newWidth;\n //this._prevViewportSize.y = newHeight;\n equalizePoints(this._prevViewportSize, newViewportSize);\n\n this.dispatch('beforeResize');\n\n equalizePoints(this.viewportSize, this._prevViewportSize);\n\n this._updatePageScrollOffset();\n\n this.dispatch('viewportSize');\n\n // Resize slides only after opener animation is finished\n // and don't re-calculate size on inital size update\n this.mainScroll.resize(this.opener.isOpen);\n\n if (!this.hasMouse && window.matchMedia('(any-hover: hover)').matches) {\n this.mouseDetected();\n }\n\n this.dispatch('resize');\n }\n\n /**\n * @param {number} opacity\n */\n applyBgOpacity(opacity) {\n this.bgOpacity = Math.max(opacity, 0);\n if (this.bg) {\n this.bg.style.opacity = String(this.bgOpacity * this.options.bgOpacity);\n }\n }\n\n /**\n * Whether mouse is detected\n */\n mouseDetected() {\n if (!this.hasMouse) {\n this.hasMouse = true;\n this.element?.classList.add('pswp--has_mouse');\n }\n }\n\n /**\n * Page resize event handler\n *\n * @private\n */\n _handlePageResize() {\n this.updateSize();\n\n // In iOS webview, if element size depends on document size,\n // it'll be measured incorrectly in resize event\n //\n // https://bugs.webkit.org/show_bug.cgi?id=170595\n // https://hackernoon.com/onresize-event-broken-in-mobile-safari-d8469027bf4d\n if (/iPhone|iPad|iPod/i.test(window.navigator.userAgent)) {\n setTimeout(() => {\n this.updateSize();\n }, 500);\n }\n }\n\n /**\n * Page scroll offset is used\n * to get correct coordinates\n * relative to PhotoSwipe viewport.\n *\n * @private\n */\n _updatePageScrollOffset() {\n this.setScrollOffset(0, window.pageYOffset);\n }\n\n /**\n * @param {number} x\n * @param {number} y\n */\n setScrollOffset(x, y) {\n this.offset.x = x;\n this.offset.y = y;\n this.dispatch('updateScrollOffset');\n }\n\n /**\n * Create main HTML structure of PhotoSwipe,\n * and add it to DOM\n *\n * @private\n */\n _createMainStructure() {\n // root DOM element of PhotoSwipe (.pswp)\n this.element = createElement('pswp', 'div');\n this.element.setAttribute('tabindex', '-1');\n this.element.setAttribute('role', 'dialog');\n\n // template is legacy prop\n this.template = this.element;\n\n // Background is added as a separate element,\n // as animating opacity is faster than animating rgba()\n this.bg = createElement('pswp__bg', 'div', this.element);\n this.scrollWrap = createElement('pswp__scroll-wrap', 'section', this.element);\n this.container = createElement('pswp__container', 'div', this.scrollWrap);\n\n // aria pattern: carousel\n this.scrollWrap.setAttribute('aria-roledescription', 'carousel');\n this.container.setAttribute('aria-live', 'off');\n this.container.setAttribute('id', 'pswp__items');\n\n this.mainScroll.appendHolders();\n\n this.ui = new UI(this);\n this.ui.init();\n\n // append to DOM\n (this.options.appendToEl || document.body).appendChild(this.element);\n }\n\n\n /**\n * Get position and dimensions of small thumbnail\n * {x:,y:,w:}\n *\n * Height is optional (calculated based on the large image)\n *\n * @returns {Bounds | undefined}\n */\n getThumbBounds() {\n return getThumbBounds(\n this.currIndex,\n this.currSlide ? this.currSlide.data : this._initialItemData,\n this\n );\n }\n\n /**\n * If the PhotoSwipe can have continuous loop\n * @returns Boolean\n */\n canLoop() {\n return (this.options.loop && this.getNumItems() > 2);\n }\n\n /**\n * @private\n * @param {PhotoSwipeOptions} options\n * @returns {PreparedPhotoSwipeOptions}\n */\n _prepareOptions(options) {\n if (window.matchMedia('(prefers-reduced-motion), (update: slow)').matches) {\n options.showHideAnimationType = 'none';\n options.zoomAnimationDuration = 0;\n }\n\n /** @type {PreparedPhotoSwipeOptions} */\n return {\n ...defaultOptions,\n ...options\n };\n }\n}\n\nexport default PhotoSwipe;\n"],"names":[],"mappings":"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AC;AAC3F,GAAG;AACH;AACA,EAAE,SAAS,GAAG,QAAQ,CAAC,YAAY,CAAC,SAAS,EAAE,SAAS,EAAE,QAAQ,EAAE,KAAK,CAAC,CAAC;AAC3E;AACA,EAAE,IAAI,SAAS,EAAE;AACjB,IAAI,IAAI,CAAC,QAAQ,CAAC,YAAY,EAAE;AAChC,MAAM,WAAW,GAAG,kBAAkB,CAAC,SAAS,CAAC,CAAC;AAClD,KAAK,MAAM;AACX,MAAM,WAAW,GAAG,yBAAyB;AAC7C,QAAQ,SAAS;AACjB,QAAQ,QAAQ,CAAC,KAAK,IAAI,QAAQ,CAAC,CAAC,IAAI,CAAC;AACzC,QAAQ,QAAQ,CAAC,MAAM,IAAI,QAAQ,CAAC,CAAC,IAAI,CAAC;AAC1C,OAAO,CAAC;AACR,KAAK;AACL,GAAG;AACH;AACA,EAAE,OAAO,QAAQ,CAAC,YAAY,CAAC,aAAa,EAAE,WAAW,EAAE,QAAQ,EAAE,KAAK,CAAC,CAAC;AAC5E;;AC9GA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,MAAM,eAAe,CAAC;AACtB;AACA;AACA;AACA;AACA,EAAE,WAAW,CAAC,IAAI,EAAE,OAAO,EAAE;AAC7B,IAAI,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;AACrB,IAAI,IAAI,CAAC,gBAAgB,GAAG,KAAK,CAAC;AAClC,IAAI,IAAI,OAAO,EAAE;AACjB,MAAM,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;AACnC,KAAK;AACL,GAAG;AACH;AACA,EAAE,cAAc,GAAG;AACnB,IAAI,IAAI,CAAC,gBAAgB,GAAG,IAAI,CAAC;AACjC,GAAG;AACH,CAAC;AACD;AACA;AACA;AACA;AACA;AACA,MAAM,SAAS,CAAC;AAChB,EAAE,WAAW,GAAG;AAChB;AACA;AACA;AACA,IAAI,IAAI,CAAC,UAAU,GAAG,EAAE,CAAC;AACzB;AACA;AACA;AACA;AACA,IAAI,IAAI,CAAC,QAAQ,GAAG,EAAE,CAAC;AACvB;AACA;AACA,IAAI,IAAI,CAAC,IAAI,GAAG,SAAS,CAAC;AAC1B;AACA;AACA,IAAI,IAAI,CAAC,OAAO,GAAG,SAAS,CAAC;AAC7B,GAAG;AACH;AACA;AACA;AACA;AACA;AACA;AACA;AACA,EAAE,SAAS,CAAC,IAAI,EAAE,EAAE,EAAE,QAAQ,GAAG,GAAG,EAAE;AACtC,IAAI,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE;AAC9B,MAAM,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,G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xC,OAAO;AACP,KAAK;AACL,GAAG;AACH;AACA;AACA;AACA;AACA;AACA;AACA;AACA,EAAE,UAAU,CAAC,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE;AACtC,IAAI,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE;AACzB,MAAM,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,SAAS,CAAC;AACrC,MAAM,OAAO;AACb,KAAK;AACL;AACA,IAAI,MAAM,EAAE,UAAU,EAAE,GAAG,IAAI,CAAC,IAAI,CAAC;AACrC;AACA,IAAI,MAAM,SAAS,GAAG;AACtB,MAAM,QAAQ,EAAE,IAAI,CAAC,SAAS;AAC9B,MAAM,MAAM,EAAE,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM;AACtC,MAAM,UAAU,EAAE,MAAM;AACxB,QAAQ,IAAI,CAAC,UAAU,CAAC,gBAAgB,CAAC,MAAM,EAAE;AACjD,UAAU,IAAI,CAAC,oBAAoB,EAAE,CAAC;AACtC,SAAS;AACT,OAAO;AACP,MAAM,MAAM;AACZ,KAAK,CAAC;AACN,IAAI,SAAS,CAAC,IAAI,CAAC,GAAG,SAAS,CAAC;AAChC,IAAI,UAAU,CAAC,eAAe,CAAC,SAAS,CAAC,CAAC;AAC1C,GAAG;AACH;;ACjbA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,MAAM,cAAc,GAAG;AACvB,EAAE,cAAc,EAAE,IAAI;AACtB,EAAE,OAAO,EAAE,GAAG;AACd,EAAE,IAAI,EAAE,IAAI;AACZ,EAAE,YAAY,EAAE,IAAI;AACpB,EAAE,mBAAmB,EAAE,IAAI;AAC3B,EAAE,qBAAqB,EAAE,GAAG;AAC5B,EAAE,qBAAqB,EAAE,GAAG;AAC5B,EAAE,qBAAqB,EAAE,GAAG;AAC5B,EAAE,MAAM,EAAE,IAAI;AACd,EAAE,SAAS,EAAE,IAAI;AACjB,EAAE,WAAW,EAAE,IAAI;AACnB,EAAE,iBAAiB,EAAE,IAAI;AACzB,EAAE,uBAAuB,EAAE,IAAI;AAC/B,EAAE,gBAAgB,EAAE,eAAe;AACnC,EAAE,aAAa,EAAE,OAAO;AACxB,EAAE,SAAS,EAAE,iBAAiB;AAC9B,EAAE,eAAe,EAAE,MAAM;AACzB,EAAE,iBAAiB,EAAE,KAAK;AAC1B,EAAE,cAAc,EAAE,IAAI;AACtB,EAAE,SAAS,EAAE,GAAG;AAChB;AACA,EAAE,KAAK,EAAE,CAAC;AACV,EAAE,QAAQ,EAAE,4BAA4B;AACxC,EAAE,OAAO,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC;AACjB,EAAE,MAAM,EAAE,0BAA0B;AACpC,CAAC,C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"} \ No newline at end of file diff --git a/package.json b/package.json index 0efd05615..2442dc701 100644 --- a/package.json +++ b/package.json @@ -43,7 +43,7 @@ "watch-css": "chokidar \"src/*.css\" --command \"npm run build-css\"", "watch-docs": "cd demo-docs-website/ && npm start", "watch-docs-local": "cd demo-docs-website/ && npm start -- --host 192.168.1.120", - "copy-to-dist": "copyfiles -f demo-docs-website/static/photoswipe/* dist/ && copyfiles -f demo-docs-website/static/photoswipe/umd/* dist/umd/", + "copy-to-dist": "copyfiles -f demo-docs-website/static/photoswipe/* dist/ && copyfiles -f demo-docs-website/static/photoswipe/umd/* dist/umd/ && copyfiles -f demo-docs-website/static/photoswipe/cjs/* dist/cjs/", "lint": "eslint src/js/**/*.js", "lint-auto-fix": "eslint src/js/**/*.js --fix", "test": "npm run lint",