Comparing version 1.4.3 to 2.0.0
@@ -5,3 +5,3 @@ /** | ||
* @author Benjamin de Oostfrees | ||
* @version 1.4.3 | ||
* @version 2.0.0 | ||
* @url https://github.com/deoostfrees/parvus | ||
@@ -12,2 +12,11 @@ * | ||
var en = { | ||
lightboxLabel: 'This is a dialog window which overlays the main content of the page. The modal shows the enlarged image. Pressing the Escape key will close the modal and bring you back to where you were on the page.', | ||
lightboxLoadingIndicatorLabel: 'Image loading', | ||
previousButtonLabel: 'Previous image', | ||
nextButtonLabel: 'Next image', | ||
closeButtonLabel: 'Close dialog window' | ||
}; | ||
// Default language | ||
function Parvus(userOptions) { | ||
@@ -23,5 +32,6 @@ /** | ||
slider: null, | ||
sliderElements: [] | ||
sliderElements: [], | ||
images: [] | ||
}; | ||
const GROUPS = {}; | ||
let groups = {}; | ||
let newGroup = null; | ||
@@ -34,2 +44,5 @@ let activeGroup = null; | ||
let lightboxOverlayOpacity = 1; | ||
let toolbar = null; | ||
let toolbarLeft = null; | ||
let toolbarRight = null; | ||
let previousButton = null; | ||
@@ -56,4 +69,4 @@ let nextButton = null; | ||
* | ||
* @param {Object} userOptions - Optional user options | ||
* @returns {Object} - Custom options | ||
* @param {Object} userOptions | ||
* @returns {Object} | ||
*/ | ||
@@ -66,2 +79,5 @@ | ||
gallerySelector: null, | ||
captions: true, | ||
captionsSelector: 'self', | ||
captionsAttribute: 'data-caption', | ||
docClose: true, | ||
@@ -79,12 +95,3 @@ scrollClose: false, | ||
closeButtonIcon: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="M18 6L6 18M6 6l12 12"/></svg>', | ||
lang: 'en', | ||
i18n: { | ||
en: { | ||
lightboxLabel: 'This is a dialog window which overlays the main content of the page. The modal shows the enlarged image. Pressing the Escape key will close the modal and bring you back to where you were on the page.', | ||
lightboxLoadingIndicatorLabel: 'Image loading', | ||
previousButtonLabel: 'Previous image', | ||
nextButtonLabel: 'Next image', | ||
closeButtonLabel: 'Close dialog window' | ||
} | ||
}, | ||
l10n: en, | ||
fileTypes: /\.(png|jpe?g|webp|avif|svg)(\?.*)?$/i | ||
@@ -170,3 +177,3 @@ }; | ||
* @param {HTMLElement} el | ||
* @return {string} | ||
* @return {String} | ||
*/ | ||
@@ -187,4 +194,4 @@ | ||
* | ||
* @param {object} object | ||
* @return {object} | ||
* @param {Object} object | ||
* @return {Object} | ||
*/ | ||
@@ -199,3 +206,3 @@ | ||
* | ||
* @param {HTMLElement} el - Element to add | ||
* @param {HTMLElement} el | ||
*/ | ||
@@ -211,9 +218,9 @@ | ||
if (!Object.prototype.hasOwnProperty.call(GROUPS, newGroup)) { | ||
GROUPS[newGroup] = copyObject(GROUP_ATTS); | ||
if (!Object.prototype.hasOwnProperty.call(groups, newGroup)) { | ||
groups[newGroup] = copyObject(GROUP_ATTS); | ||
} // Check if element already exists | ||
if (!GROUPS[newGroup].gallery.includes(el)) { | ||
GROUPS[newGroup].gallery.push(el); | ||
if (!groups[newGroup].gallery.includes(el)) { | ||
groups[newGroup].gallery.push(el); | ||
@@ -233,4 +240,4 @@ if (el.querySelector('img') !== null) { | ||
if (isOpen() && newGroup === activeGroup) { | ||
createSlide(el, GROUPS[newGroup].gallery.indexOf(el)); | ||
loadImage(GROUPS[newGroup].gallery.indexOf(el)); | ||
createSlide(el, groups[newGroup].gallery.indexOf(el)); | ||
loadImage(groups[newGroup].gallery.indexOf(el)); | ||
updateConfig(); | ||
@@ -247,3 +254,3 @@ updateFocus(); | ||
* | ||
* @param {HTMLElement} el - Element to remove | ||
* @param {HTMLElement} el | ||
*/ | ||
@@ -259,3 +266,3 @@ | ||
if (!GROUPS[GROUP].gallery.includes(el)) { | ||
if (!groups[GROUP].gallery.includes(el)) { | ||
throw new Error('Ups, I can\'t find the element.'); | ||
@@ -265,3 +272,3 @@ } // TODO: Remove elements dynamically | ||
GROUPS[GROUP].gallery.splice(GROUPS[GROUP].gallery.indexOf(el), 1); // Remove lightbox indicator icon if necessary | ||
groups[GROUP].gallery.splice(groups[GROUP].gallery.indexOf(el), 1); // Remove lightbox indicator icon if necessary | ||
@@ -291,3 +298,3 @@ if (el.classList.contains('parvus-zoom')) { | ||
lightbox.setAttribute('tabindex', '-1'); | ||
lightbox.setAttribute('aria-label', config.i18n[config.lang].lightboxLabel); | ||
lightbox.setAttribute('aria-label', config.l10n.lightboxLabel); | ||
lightbox.classList.add('parvus'); // Create the lightbox overlay container | ||
@@ -299,11 +306,16 @@ | ||
lightbox.appendChild(lightboxOverlay); // Create the close button | ||
lightbox.appendChild(lightboxOverlay); // Create the toolbar | ||
toolbar = document.createElement('div'); | ||
toolbar.className = 'parvus__toolbar'; | ||
toolbarLeft = document.createElement('div'); | ||
toolbarRight = document.createElement('div'); // Create the close button | ||
closeButton = document.createElement('button'); | ||
closeButton.className = 'parvus__btn parvus__btn--close'; | ||
closeButton.setAttribute('type', 'button'); | ||
closeButton.setAttribute('aria-label', config.i18n[config.lang].closeButtonLabel); | ||
closeButton.innerHTML = config.closeButtonIcon; // Add close button to lightbox container | ||
closeButton.setAttribute('aria-label', config.l10n.closeButtonLabel); | ||
closeButton.innerHTML = config.closeButtonIcon; // Add close button to right toolbar item | ||
lightbox.appendChild(closeButton); // Create the previous button | ||
toolbarRight.appendChild(closeButton); // Create the previous button | ||
@@ -313,3 +325,3 @@ previousButton = document.createElement('button'); | ||
previousButton.setAttribute('type', 'button'); | ||
previousButton.setAttribute('aria-label', config.i18n[config.lang].previousButtonLabel); | ||
previousButton.setAttribute('aria-label', config.l10n.previousButtonLabel); | ||
previousButton.innerHTML = config.previousButtonIcon; // Add previous button to lightbox container | ||
@@ -322,3 +334,3 @@ | ||
nextButton.setAttribute('type', 'button'); | ||
nextButton.setAttribute('aria-label', config.i18n[config.lang].nextButtonLabel); | ||
nextButton.setAttribute('aria-label', config.l10n.nextButtonLabel); | ||
nextButton.innerHTML = config.nextButtonIcon; // Add next button to lightbox container | ||
@@ -329,6 +341,11 @@ | ||
counter = document.createElement('div'); | ||
counter.className = 'parvus__counter'; // Add counter to lightbox container | ||
counter.className = 'parvus__counter'; // Add counter to left toolbar item | ||
lightbox.appendChild(counter); // Add lightbox container to body | ||
toolbarLeft.appendChild(counter); // Add toolbar items to toolbar | ||
toolbar.appendChild(toolbarLeft); | ||
toolbar.appendChild(toolbarRight); // Add toolbar to lightbox container | ||
lightbox.appendChild(toolbar); // Add lightbox container to body | ||
document.body.appendChild(lightbox); | ||
@@ -343,7 +360,7 @@ }; | ||
const createSlider = function createSlider() { | ||
GROUPS[activeGroup].slider = document.createElement('div'); | ||
GROUPS[activeGroup].slider.className = 'parvus__slider'; // Hide slider | ||
groups[activeGroup].slider = document.createElement('div'); | ||
groups[activeGroup].slider.className = 'parvus__slider'; // Hide slider | ||
GROUPS[activeGroup].slider.setAttribute('aria-hidden', 'true'); | ||
lightbox.appendChild(GROUPS[activeGroup].slider); | ||
groups[activeGroup].slider.setAttribute('aria-hidden', 'true'); | ||
lightbox.appendChild(groups[activeGroup].slider); | ||
}; | ||
@@ -353,2 +370,4 @@ /** | ||
* | ||
* @param {HTMLElement} el | ||
* @param {Number} index | ||
*/ | ||
@@ -365,15 +384,15 @@ | ||
SLIDER_ELEMENT.setAttribute('aria-hidden', 'true'); | ||
createImage(el, SLIDER_ELEMENT_CONTENT); // Add slide content container to slider element | ||
createImage(index, el, SLIDER_ELEMENT_CONTENT); // Add slide content container to slider element | ||
SLIDER_ELEMENT.appendChild(SLIDER_ELEMENT_CONTENT); | ||
GROUPS[activeGroup].sliderElements[index] = SLIDER_ELEMENT; // Add slider element to slider | ||
groups[activeGroup].sliderElements[index] = SLIDER_ELEMENT; // Add slider element to slider | ||
if (index === currentIndex) { | ||
GROUPS[activeGroup].slider.appendChild(SLIDER_ELEMENT); | ||
groups[activeGroup].slider.appendChild(SLIDER_ELEMENT); | ||
} | ||
if (index > currentIndex) { | ||
GROUPS[activeGroup].sliderElements[currentIndex].after(SLIDER_ELEMENT); | ||
groups[activeGroup].sliderElements[currentIndex].after(SLIDER_ELEMENT); | ||
} else { | ||
GROUPS[activeGroup].sliderElements[currentIndex].before(SLIDER_ELEMENT); | ||
groups[activeGroup].sliderElements[currentIndex].before(SLIDER_ELEMENT); | ||
} | ||
@@ -384,3 +403,3 @@ }; | ||
* | ||
* @param {number} index - Index to load | ||
* @param {HTMLElement} el | ||
*/ | ||
@@ -396,7 +415,7 @@ | ||
if (!GROUPS[activeGroup].gallery.includes(el)) { | ||
if (!groups[activeGroup].gallery.includes(el)) { | ||
throw new Error('Ups, I can\'t find the element.'); | ||
} | ||
currentIndex = GROUPS[activeGroup].gallery.indexOf(el); // Save user’s focus | ||
currentIndex = groups[activeGroup].gallery.indexOf(el); // Save user’s focus | ||
@@ -424,3 +443,3 @@ lastFocus = document.activeElement; // Use `history.pushState()` to make sure the 'Back' button behavior | ||
GROUPS[activeGroup].slider.setAttribute('aria-hidden', 'false'); | ||
groups[activeGroup].slider.setAttribute('aria-hidden', 'false'); | ||
updateOffset(); | ||
@@ -444,3 +463,3 @@ updateConfig(); | ||
GROUPS[activeGroup].slider.classList.add('parvus__slider--animate'); // Create and dispatch a new event | ||
groups[activeGroup].slider.classList.add('parvus__slider--animate'); // Create and dispatch a new event | ||
@@ -465,6 +484,5 @@ const OPEN_EVENT = new CustomEvent('open', { | ||
const IMAGE_CONTAINER = GROUPS[activeGroup].sliderElements[currentIndex]; | ||
const IMAGE = IMAGE_CONTAINER.querySelector('img'); | ||
const IMAGE = groups[activeGroup].images[currentIndex]; | ||
const IMAGE_SIZE = IMAGE.getBoundingClientRect(); | ||
const THUMBNAIL = config.backFocus ? GROUPS[activeGroup].gallery[currentIndex] : lastFocus; | ||
const THUMBNAIL = config.backFocus ? groups[activeGroup].gallery[currentIndex] : lastFocus; | ||
const THUMBNAIL_SIZE = THUMBNAIL.getBoundingClientRect(); | ||
@@ -503,3 +521,3 @@ unbindEvents(); | ||
lastFocus = config.backFocus ? GROUPS[activeGroup].gallery[currentIndex] : lastFocus; | ||
lastFocus = config.backFocus ? groups[activeGroup].gallery[currentIndex] : lastFocus; | ||
lastFocus.focus({ | ||
@@ -511,5 +529,5 @@ preventScroll: true | ||
lightbox.classList.remove('parvus--is-closing'); | ||
lightbox.classList.remove('parvus--is-vertical-closing'); // Remove slider | ||
lightbox.classList.remove('parvus--is-vertical-closing'); // Reset groups | ||
GROUPS[activeGroup].slider.remove(); | ||
groups = {}; | ||
IMAGE.style.transform = ''; | ||
@@ -522,3 +540,3 @@ }, { | ||
detail: { | ||
source: GROUPS[activeGroup].gallery[currentIndex] | ||
source: groups[activeGroup].gallery[currentIndex] | ||
} | ||
@@ -531,3 +549,3 @@ }); | ||
* | ||
* @param {number} index - Index to preload | ||
* @param {Number} index | ||
*/ | ||
@@ -537,7 +555,7 @@ | ||
const preload = function preload(index) { | ||
if (GROUPS[activeGroup].gallery[index] === undefined) { | ||
if (groups[activeGroup].gallery[index] === undefined) { | ||
return; | ||
} | ||
createSlide(GROUPS[activeGroup].gallery[index], index); | ||
createSlide(groups[activeGroup].gallery[index], index); | ||
loadImage(index); | ||
@@ -548,3 +566,3 @@ }; | ||
* | ||
* @param {number} index - Index to load | ||
* @param {Number} index | ||
*/ | ||
@@ -554,4 +572,4 @@ | ||
const loadSlide = function loadSlide(index) { | ||
GROUPS[activeGroup].sliderElements[index].classList.add('parvus__slide--is-active'); | ||
GROUPS[activeGroup].sliderElements[index].setAttribute('aria-hidden', 'false'); | ||
groups[activeGroup].sliderElements[index].classList.add('parvus__slide--is-active'); | ||
groups[activeGroup].sliderElements[index].setAttribute('aria-hidden', 'false'); | ||
}; | ||
@@ -561,16 +579,20 @@ /** | ||
* | ||
* @param {number} index - Index to load | ||
* @param {Number} index | ||
* @param {HTMLElement} el | ||
* @param {HTMLElement} container | ||
*/ | ||
const createImage = function createImage(el, container) { | ||
const createImage = function createImage(index, el, container) { | ||
const IMAGE = document.createElement('img'); | ||
const FIGURE = document.createElement('figure'); | ||
const FIGCAPTION = document.createElement('figcaption'); | ||
const IMAGE_CONTAINER = document.createElement('div'); | ||
const CAPTION_CONTAINER = document.createElement('div'); | ||
const THUMBNAIL = el.querySelector('img'); | ||
const LOADING_INDICATOR = document.createElement('div'); // Create loading indicator | ||
const LOADING_INDICATOR = document.createElement('div'); | ||
IMAGE_CONTAINER.className = 'parvus__content'; | ||
CAPTION_CONTAINER.className = 'parvus__caption'; // Create loading indicator | ||
LOADING_INDICATOR.className = 'parvus__loader'; | ||
LOADING_INDICATOR.setAttribute('role', 'progressbar'); | ||
LOADING_INDICATOR.setAttribute('aria-label', config.i18n[config.lang].lightboxLoadingIndicatorLabel); // Add loading indicator to container | ||
LOADING_INDICATOR.setAttribute('aria-label', config.l10n.lightboxLoadingIndicatorLabel); // Add loading indicator to container | ||
@@ -605,10 +627,30 @@ container.appendChild(LOADING_INDICATOR); | ||
IMAGE.style.opacity = 0; | ||
FIGURE.appendChild(IMAGE); // Add caption if available | ||
IMAGE_CONTAINER.appendChild(IMAGE); | ||
groups[activeGroup].images[index] = IMAGE; | ||
container.appendChild(IMAGE_CONTAINER); // Add caption if available | ||
if (el.hasAttribute('data-caption') && el.getAttribute('data-caption') !== '') { | ||
FIGCAPTION.innerHTML = el.getAttribute('data-caption'); | ||
FIGURE.appendChild(FIGCAPTION); | ||
if (config.captions) { | ||
let captionData = null; | ||
if (config.captionsSelector === 'self') { | ||
if (el.hasAttribute(config.captionsAttribute) && el.getAttribute(config.captionsAttribute) !== '') { | ||
captionData = el.getAttribute(config.captionsAttribute); | ||
} | ||
} else { | ||
if (el.querySelector(config.captionsSelector) !== null) { | ||
const CAPTION_SELECTOR = el.querySelector(config.captionsSelector); | ||
if (CAPTION_SELECTOR.hasAttribute(config.captionsAttribute) && CAPTION_SELECTOR.getAttribute(config.captionsAttribute) !== '') { | ||
captionData = CAPTION_SELECTOR.getAttribute(config.captionsAttribute); | ||
} else { | ||
captionData = CAPTION_SELECTOR.innerHTML; | ||
} | ||
} | ||
} | ||
if (captionData !== null) { | ||
CAPTION_CONTAINER.innerHTML = `<p>${captionData}</p>`; | ||
container.appendChild(CAPTION_CONTAINER); | ||
} | ||
} | ||
container.appendChild(FIGURE); | ||
}; | ||
@@ -618,3 +660,3 @@ /** | ||
* | ||
* @param {number} index - Index to load | ||
* @param {Number} index | ||
*/ | ||
@@ -624,6 +666,6 @@ | ||
const loadImage = function loadImage(index) { | ||
const IMAGE_CONTAINER = GROUPS[activeGroup].sliderElements[index]; | ||
const IMAGE = IMAGE_CONTAINER.querySelector('img'); | ||
setImageDimension(groups[activeGroup].sliderElements[index], groups[activeGroup].images[index]); | ||
const IMAGE = groups[activeGroup].images[index]; | ||
const IMAGE_SIZE = IMAGE.getBoundingClientRect(); | ||
const THUMBNAIL = GROUPS[activeGroup].gallery[index]; | ||
const THUMBNAIL = groups[activeGroup].gallery[index]; | ||
const THUMBNAIL_SIZE = THUMBNAIL.getBoundingClientRect(); | ||
@@ -636,2 +678,6 @@ | ||
yDifference = THUMBNAIL_SIZE.top - IMAGE_SIZE.top; | ||
console.log(THUMBNAIL_SIZE.width); | ||
console.log(THUMBNAIL_SIZE.height); | ||
console.log(IMAGE_SIZE.width); | ||
console.log(IMAGE_SIZE.height); | ||
requestAnimationFrame(() => { | ||
@@ -654,3 +700,3 @@ IMAGE.style.transform = `translate(${xDifference}px, ${yDifference}px) scale(${widthDifference}, ${heightDifference})`; | ||
* | ||
* @param {number} index - Index to select | ||
* @param {Number} newIndex | ||
*/ | ||
@@ -673,3 +719,3 @@ | ||
if (newIndex === -1 || newIndex >= GROUPS[activeGroup].gallery.length) { | ||
if (newIndex === -1 || newIndex >= groups[activeGroup].gallery.length) { | ||
throw new Error(`Ups, I can't find slide ${newIndex}.`); | ||
@@ -703,3 +749,3 @@ } | ||
detail: { | ||
source: GROUPS[activeGroup].gallery[currentIndex] | ||
source: groups[activeGroup].gallery[currentIndex] | ||
} | ||
@@ -727,3 +773,3 @@ }); | ||
const next = function next() { | ||
if (currentIndex < GROUPS[activeGroup].gallery.length - 1) { | ||
if (currentIndex < groups[activeGroup].gallery.length - 1) { | ||
select(currentIndex + 1); | ||
@@ -736,3 +782,3 @@ } | ||
* | ||
* @param {number} index - Index to leave | ||
* @param {Number} index | ||
*/ | ||
@@ -742,4 +788,4 @@ | ||
const leaveSlide = function leaveSlide(index) { | ||
GROUPS[activeGroup].sliderElements[index].classList.remove('parvus__slide--is-active'); | ||
GROUPS[activeGroup].sliderElements[index].setAttribute('aria-hidden', 'true'); | ||
groups[activeGroup].sliderElements[index].classList.remove('parvus__slide--is-active'); | ||
groups[activeGroup].sliderElements[index].setAttribute('aria-hidden', 'true'); | ||
}; | ||
@@ -754,4 +800,4 @@ /** | ||
activeGroup = activeGroup !== null ? activeGroup : newGroup; | ||
offset = -currentIndex * lightbox.offsetWidth; | ||
GROUPS[activeGroup].slider.style.transform = `translate3d(${offset}px, 0, 0)`; | ||
offset = currentIndex * lightbox.offsetWidth * -1; | ||
groups[activeGroup].slider.style.transform = `translate3d(${offset}px, 0, 0)`; | ||
offsetTmp = offset; | ||
@@ -762,3 +808,3 @@ }; | ||
* | ||
* @param {string} dir - Current slide direction | ||
* @param {String} dir | ||
*/ | ||
@@ -768,3 +814,3 @@ | ||
const updateFocus = function updateFocus(dir) { | ||
if (GROUPS[activeGroup].gallery.length === 1) { | ||
if (groups[activeGroup].gallery.length === 1) { | ||
closeButton.focus(); | ||
@@ -775,3 +821,3 @@ } else { | ||
nextButton.focus(); // If the last slide is displayed | ||
} else if (currentIndex === GROUPS[activeGroup].gallery.length - 1) { | ||
} else if (currentIndex === groups[activeGroup].gallery.length - 1) { | ||
previousButton.focus(); | ||
@@ -794,3 +840,3 @@ } else { | ||
const updateCounter = function updateCounter() { | ||
counter.textContent = `${currentIndex + 1}/${GROUPS[activeGroup].gallery.length}`; | ||
counter.textContent = `${currentIndex + 1}/${groups[activeGroup].gallery.length}`; | ||
}; | ||
@@ -825,3 +871,3 @@ /** | ||
previous(); | ||
} else if (isDraggingX && MOVEMENT_X < 0 && MOVEMENT_X_DISTANCE >= config.threshold && currentIndex !== GROUPS[activeGroup].gallery.length - 1) { | ||
} else if (isDraggingX && MOVEMENT_X < 0 && MOVEMENT_X_DISTANCE >= config.threshold && currentIndex !== groups[activeGroup].gallery.length - 1) { | ||
next(); | ||
@@ -847,8 +893,8 @@ } else if (isDraggingY && MOVEMENT_Y_DISTANCE > 0) { | ||
const updateConfig = function updateConfig() { | ||
if (config.swipeClose && !GROUPS[activeGroup].slider.classList.contains('parvus__slider--is-draggable') || GROUPS[activeGroup].gallery.length > 1 && !GROUPS[activeGroup].slider.classList.contains('parvus__slider--is-draggable')) { | ||
GROUPS[activeGroup].slider.classList.add('parvus__slider--is-draggable'); | ||
if (config.swipeClose && !groups[activeGroup].slider.classList.contains('parvus__slider--is-draggable') || groups[activeGroup].gallery.length > 1 && !groups[activeGroup].slider.classList.contains('parvus__slider--is-draggable')) { | ||
groups[activeGroup].slider.classList.add('parvus__slider--is-draggable'); | ||
} // Hide buttons if necessary | ||
if (GROUPS[activeGroup].gallery.length === 1) { | ||
if (groups[activeGroup].gallery.length === 1) { | ||
previousButton.setAttribute('aria-hidden', 'true'); | ||
@@ -865,3 +911,3 @@ previousButton.disabled = true; | ||
nextButton.disabled = false; // If the last slide is displayed | ||
} else if (currentIndex === GROUPS[activeGroup].gallery.length - 1) { | ||
} else if (currentIndex === groups[activeGroup].gallery.length - 1) { | ||
previousButton.setAttribute('aria-hidden', 'false'); | ||
@@ -880,3 +926,3 @@ previousButton.disabled = false; | ||
if (GROUPS[activeGroup].gallery.length === 1) { | ||
if (groups[activeGroup].gallery.length === 1) { | ||
counter.setAttribute('aria-hidden', 'true'); | ||
@@ -897,2 +943,3 @@ } else { | ||
BROWSER_WINDOW.requestAnimationFrame(() => { | ||
setImageDimension(groups[activeGroup].sliderElements[currentIndex], groups[activeGroup].images[currentIndex]); | ||
updateOffset(); | ||
@@ -904,2 +951,25 @@ resizeTicking = false; | ||
/** | ||
* Set image with | ||
* | ||
* @param {HTMLElement} slideEl | ||
* @param {HTMLElement} imageEl | ||
*/ | ||
const setImageDimension = function setImageDimension(slideEl, imageEl) { | ||
const computedStyle = getComputedStyle(slideEl); | ||
const captionRec = slideEl.querySelector('.parvus__caption').getBoundingClientRect(); | ||
const srcHeight = imageEl.naturalHeight; | ||
const srcWidth = imageEl.naturalWidth; | ||
let maxHeight = slideEl.getBoundingClientRect().height; | ||
let maxWidth = slideEl.getBoundingClientRect().width; | ||
maxHeight -= parseFloat(computedStyle.paddingTop) + parseFloat(computedStyle.paddingBottom) + parseFloat(captionRec.height); | ||
maxWidth -= parseFloat(computedStyle.paddingLeft) + parseFloat(computedStyle.paddingRight); | ||
const ratio = Math.min(maxWidth / srcWidth || 0, maxHeight / srcHeight); | ||
imageEl.style.width = `${srcWidth * ratio || 0}px`; | ||
imageEl.style.height = `${srcHeight * ratio || 0}px`; | ||
console.log(srcWidth * ratio || 0); | ||
console.log(srcHeight * ratio || 0); | ||
}; | ||
/** | ||
* Click event handler to trigger Parvus | ||
@@ -1012,4 +1082,4 @@ * | ||
drag.startY = event.pageY; | ||
GROUPS[activeGroup].slider.classList.add('parvus__slider--is-dragging'); | ||
GROUPS[activeGroup].slider.style.willChange = 'transform'; | ||
groups[activeGroup].slider.classList.add('parvus__slider--is-dragging'); | ||
groups[activeGroup].slider.style.willChange = 'transform'; | ||
}; | ||
@@ -1040,4 +1110,4 @@ /** | ||
pointerDown = false; | ||
GROUPS[activeGroup].slider.classList.remove('parvus__slider--is-dragging'); | ||
GROUPS[activeGroup].slider.style.willChange = 'auto'; | ||
groups[activeGroup].slider.classList.remove('parvus__slider--is-dragging'); | ||
groups[activeGroup].slider.style.willChange = 'auto'; | ||
@@ -1063,4 +1133,4 @@ if (drag.endX || drag.endY) { | ||
drag.startY = event.touches[0].pageY; | ||
GROUPS[activeGroup].slider.classList.add('parvus__slider--is-dragging'); | ||
GROUPS[activeGroup].slider.style.willChange = 'transform'; | ||
groups[activeGroup].slider.classList.add('parvus__slider--is-dragging'); | ||
groups[activeGroup].slider.style.willChange = 'transform'; | ||
}; | ||
@@ -1092,4 +1162,4 @@ /** | ||
pointerDown = false; | ||
GROUPS[activeGroup].slider.classList.remove('parvus__slider--is-dragging'); | ||
GROUPS[activeGroup].slider.style.willChange = 'auto'; | ||
groups[activeGroup].slider.classList.remove('parvus__slider--is-dragging'); | ||
groups[activeGroup].slider.style.willChange = 'auto'; | ||
@@ -1113,5 +1183,5 @@ if (drag.endX || drag.endY) { | ||
if (Math.abs(MOVEMENT_X) > 0 && !isDraggingY && GROUPS[activeGroup].gallery.length > 1) { | ||
if (Math.abs(MOVEMENT_X) > 0 && !isDraggingY && groups[activeGroup].gallery.length > 1) { | ||
// Horizontal swipe | ||
GROUPS[activeGroup].slider.style.transform = `translate3d(${offsetTmp - Math.round(MOVEMENT_X)}px, 0, 0)`; | ||
groups[activeGroup].slider.style.transform = `translate3d(${offsetTmp - Math.round(MOVEMENT_X)}px, 0, 0)`; | ||
isDraggingX = true; | ||
@@ -1128,3 +1198,3 @@ isDraggingY = false; | ||
lightboxOverlay.style.opacity = lightboxOverlayOpacity; | ||
GROUPS[activeGroup].slider.style.transform = `translate3d(${offsetTmp}px, ${Math.round(MOVEMENT_Y)}px, 0)`; | ||
groups[activeGroup].slider.style.transform = `translate3d(${offsetTmp}px, ${Math.round(MOVEMENT_Y)}px, 0)`; | ||
isDraggingX = false; | ||
@@ -1249,5 +1319,5 @@ isDraggingY = true; | ||
* Bind event | ||
* | ||
* @param {String} eventName | ||
* @param {function} callback - callback to call | ||
* | ||
* @param {Function} callback | ||
*/ | ||
@@ -1263,5 +1333,5 @@ | ||
* Unbind event | ||
* | ||
* @param {String} eventName | ||
* @param {function} callback - callback to call | ||
* | ||
* @param {Function} callback | ||
*/ | ||
@@ -1268,0 +1338,0 @@ |
@@ -5,3 +5,3 @@ /** | ||
* @author Benjamin de Oostfrees | ||
* @version 1.4.3 | ||
* @version 2.0.0 | ||
* @url https://github.com/deoostfrees/parvus | ||
@@ -12,2 +12,2 @@ * | ||
function e(t){const n=window,i=["button:not([disabled]):not([inert])",'[tabindex]:not([tabindex^="-"]):not([inert])'],s={gallery:[],slider:null,sliderElements:[]},r={};let a=null,l=null,o=0,d={},u=null,c=null,p=1,g=null,h=null,m=null,v=null,f=0,b=0,y=0,w=0,E={},L=!1,A=!1,_=!1,C=null,x=null,$=null,T=!1,B=null,S=!0;const M=window.matchMedia("(prefers-reduced-motion)"),I=function(){M.matches?(S=!0,B=d.reducedTransitionDuration):(S=!1,B=d.transitionDuration)};M.addEventListener("change",I);const q=function(e){d=function(e){return{selector:".lightbox",gallerySelector:null,docClose:!0,scrollClose:!1,swipeClose:!0,threshold:50,backFocus:!0,transitionDuration:300,reducedTransitionDuration:.1,transitionTimingFunction:"cubic-bezier(0.4, 0, 0.22, 1)",lightboxIndicatorIcon:'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="M8 3H5a2 2 0 00-2 2v3m18 0V5a2 2 0 00-2-2h-3m0 18h3a2 2 0 002-2v-3M3 16v3a2 2 0 002 2h3"/></svg>',previousButtonIcon:'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path stroke="none" d="M0 0h24v24H0z"/><polyline points="15 6 9 12 15 18" /></svg>',nextButtonIcon:'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path stroke="none" d="M0 0h24v24H0z"/><polyline points="9 6 15 12 9 18" /></svg>',closeButtonIcon:'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="M18 6L6 18M6 6l12 12"/></svg>',lang:"en",i18n:{en:{lightboxLabel:"This is a dialog window which overlays the main content of the page. The modal shows the enlarged image. Pressing the Escape key will close the modal and bring you back to where you were on the page.",lightboxLoadingIndicatorLabel:"Image loading",previousButtonLabel:"Previous image",nextButtonLabel:"Next image",closeButtonLabel:"Close dialog window"}},fileTypes:/\.(png|jpe?g|webp|avif|svg)(\?.*)?$/i,...e}}(e);if(document.querySelectorAll(d.selector).length)if(I(),u||F(),null!==d.gallerySelector){document.querySelectorAll(d.gallerySelector).forEach(((e,t)=>{const n=t;e.querySelectorAll(d.selector).forEach((e=>{e.setAttribute("data-group",`parvus-gallery-${n}`),Y(e)}))}));document.querySelectorAll(`${d.selector}:not(.parvus-trigger)`).forEach((e=>{Y(e)}))}else{document.querySelectorAll(d.selector).forEach((e=>{Y(e)}))}},X=function(e){const t=Math.floor(1e4*Math.random());return e.hasAttribute("data-group")&&""!==e.getAttribute("data-group")||e.setAttribute("data-group",`default-${t}`),e.getAttribute("data-group")},Y=function(e){if(!("A"===e.tagName&&e.hasAttribute("href")&&e.href.match(d.fileTypes)||"BUTTON"===e.tagName&&e.hasAttribute("data-target")&&e.getAttribute("data-target").match(d.fileTypes)))throw new Error(e,`Use a link with the 'href' attribute or a button with the 'data-target' attribute. Both attributes must have a path to the image file. Supported image file types: ${d.fileTypes}.`);var t;if(a=X(e),Object.prototype.hasOwnProperty.call(r,a)||(r[a]=(t=s,JSON.parse(JSON.stringify(t)))),r[a].gallery.includes(e))throw new Error("Ups, element already added.");if(r[a].gallery.push(e),null!==e.querySelector("img")){const t=document.createElement("div");e.classList.add("parvus-zoom"),t.className="parvus-zoom__indicator",t.innerHTML=d.lightboxIndicatorIcon,e.appendChild(t)}e.classList.add("parvus-trigger"),e.addEventListener("click",ne),fe()&&a===l&&(N(e,r[a].gallery.indexOf(e)),P(r[a].gallery.indexOf(e)),ee(),V(),G())},k=function(e){if(fe()||!u||!e||!e.hasAttribute("data-group"))return;const t=X(e);if(!r[t].gallery.includes(e))throw new Error("Ups, I can't find the element.");if(r[t].gallery.splice(r[t].gallery.indexOf(e),1),e.classList.contains("parvus-zoom")){const t=e.querySelector(".parvus-zoom__indicator");e.classList.remove("parvus-zoom"),e.removeChild(t)}e.removeEventListener("click",ne),e.classList.remove("parvus-trigger")},F=function(){u=document.createElement("div"),u.setAttribute("role","dialog"),u.setAttribute("aria-modal","true"),u.setAttribute("aria-hidden","true"),u.setAttribute("tabindex","-1"),u.setAttribute("aria-label",d.i18n[d.lang].lightboxLabel),u.classList.add("parvus"),c=document.createElement("div"),c.classList.add("parvus__overlay"),c.style.opacity=0,u.appendChild(c),m=document.createElement("button"),m.className="parvus__btn parvus__btn--close",m.setAttribute("type","button"),m.setAttribute("aria-label",d.i18n[d.lang].closeButtonLabel),m.innerHTML=d.closeButtonIcon,u.appendChild(m),g=document.createElement("button"),g.className="parvus__btn parvus__btn--previous",g.setAttribute("type","button"),g.setAttribute("aria-label",d.i18n[d.lang].previousButtonLabel),g.innerHTML=d.previousButtonIcon,u.appendChild(g),h=document.createElement("button"),h.className="parvus__btn parvus__btn--next",h.setAttribute("type","button"),h.setAttribute("aria-label",d.i18n[d.lang].nextButtonLabel),h.innerHTML=d.nextButtonIcon,u.appendChild(h),v=document.createElement("div"),v.className="parvus__counter",u.appendChild(v),document.body.appendChild(u)},N=function(e,t){const n=document.createElement("div"),i=document.createElement("div");n.className="parvus__slide",n.style.position="absolute",n.style.left=100*t+"%",n.setAttribute("aria-hidden","true"),U(e,i),n.appendChild(i),r[l].sliderElements[t]=n,t===o&&r[l].slider.appendChild(n),t>o?r[l].sliderElements[o].after(n):r[l].sliderElements[o].before(n)},D=function(e){if(!u||!e||!e.classList.contains("parvus-trigger")||fe())return;if(l=X(e),!r[l].gallery.includes(e))throw new Error("Ups, I can't find the element.");o=r[l].gallery.indexOf(e),C=document.activeElement;const t=window.location.href;history.pushState({parvus:"close"},"Image",t),me();document.querySelectorAll('body > *:not([aria-hidden="true"])').forEach((e=>{e.setAttribute("aria-hidden","true"),e.classList.add("parvus-hidden")})),u.classList.add("parvus--is-opening"),u.setAttribute("aria-hidden","false"),r[l].slider=document.createElement("div"),r[l].slider.className="parvus__slider",r[l].slider.setAttribute("aria-hidden","true"),u.appendChild(r[l].slider),N(e,o),r[l].slider.setAttribute("aria-hidden","false"),K(),ee(),G(),re(),H(o),P(o),requestAnimationFrame((()=>{u.classList.remove("parvus--is-opening"),c.style.opacity=1,c.style.transition=`opacity ${B}ms ${d.transitionTimingFunction}`,c.style.willChange="opacity"})),c.addEventListener("transitionend",(()=>{z(o+1),z(o-1)})),r[l].slider.classList.add("parvus__slider--animate");const n=new CustomEvent("open",{detail:{source:e}});u.dispatchEvent(n)},O=function(){if(!fe())throw new Error("Ups, I'm already closed.");const e=r[l].sliderElements[o].querySelector("img"),t=e.getBoundingClientRect(),n=(d.backFocus?r[l].gallery[o]:C).getBoundingClientRect();ve(),Q(),null!==history.state&&"close"===history.state.parvus&&history.back();document.querySelectorAll(".parvus-hidden").forEach((e=>{e.removeAttribute("aria-hidden"),e.classList.remove("parvus-hidden")})),u.classList.add("parvus--is-closing"),requestAnimationFrame((()=>{f=n.width/t.width,b=n.height/t.height,y=n.left-t.left,w=n.top-t.top,e.style.transform=`translate(${y}px, ${w}px) scale(${f}, ${b})`,e.style.opacity=0,e.style.transition=`transform ${B}ms ${d.transitionTimingFunction}, opacity ${B}ms ${d.transitionTimingFunction} ${B/2}ms`,c.style.opacity=0,c.style.transition=`opacity ${B}ms ${d.transitionTimingFunction}`,c.style.willChange="auto"})),c.addEventListener("transitionend",(()=>{J(o),C=d.backFocus?r[l].gallery[o]:C,C.focus({preventScroll:!0}),u.setAttribute("aria-hidden","true"),u.classList.remove("parvus--is-closing"),u.classList.remove("parvus--is-vertical-closing"),r[l].slider.remove(),e.style.transform=""}),{once:!0});const i=new CustomEvent("close",{detail:{source:r[l].gallery[o]}});u.dispatchEvent(i)},z=function(e){void 0!==r[l].gallery[e]&&(N(r[l].gallery[e],e),P(e))},H=function(e){r[l].sliderElements[e].classList.add("parvus__slide--is-active"),r[l].sliderElements[e].setAttribute("aria-hidden","false")},U=function(e,t){const n=document.createElement("img"),i=document.createElement("figure"),s=document.createElement("figcaption"),r=e.querySelector("img"),a=document.createElement("div");a.className="parvus__loader",a.setAttribute("role","progressbar"),a.setAttribute("aria-label",d.i18n[d.lang].lightboxLoadingIndicatorLabel),t.appendChild(a),n.onload=()=>{t.removeChild(a),n.setAttribute("width",n.naturalWidth),n.setAttribute("height",n.naturalHeight)},"A"===e.tagName?(n.setAttribute("src",e.href),n.alt=r?r.alt||"":e.getAttribute("data-alt")||""):(n.alt=e.getAttribute("data-alt")||"",n.setAttribute("src",e.getAttribute("data-target"))),e.hasAttribute("data-srcset")&&""!==e.getAttribute("data-srcset")&&n.setAttribute("srcset",e.getAttribute("data-srcset")),n.style.opacity=0,i.appendChild(n),e.hasAttribute("data-caption")&&""!==e.getAttribute("data-caption")&&(s.innerHTML=e.getAttribute("data-caption"),i.appendChild(s)),t.appendChild(i)},P=function(e){const t=r[l].sliderElements[e].querySelector("img"),n=t.getBoundingClientRect(),i=r[l].gallery[e].getBoundingClientRect();u.classList.contains("parvus--is-opening")?(f=i.width/n.width,b=i.height/n.height,y=i.left-n.left,w=i.top-n.top,requestAnimationFrame((()=>{t.style.transform=`translate(${y}px, ${w}px) scale(${f}, ${b})`,t.style.transition="transform 0s, opacity 0s",requestAnimationFrame((()=>{t.style.transform="",t.style.opacity=1,t.style.transition=`transform ${B}ms ${d.transitionTimingFunction}, opacity ${B/2}ms ${d.transitionTimingFunction}`}))}))):t.style.opacity=1},R=function(e){const t=o;if(!fe())throw new Error("Ups, I'm closed.");if(!e&&0!==e)throw new Error("Ups, no slide specified.");if(e===o)throw new Error(`Ups, slide ${e} is already selected.`);if(-1===e||e>=r[l].gallery.length)throw new Error(`Ups, I can't find slide ${e}.`);J(t),H(e),P(e),e<t&&(o--,K(),ee(),V("left"),z(e-1)),e>t&&(o++,K(),ee(),V("right"),z(e+1)),G();const n=new CustomEvent("select",{detail:{source:r[l].gallery[o]}});u.dispatchEvent(n)},j=function(){o>0&&R(o-1)},W=function(){o<r[l].gallery.length-1&&R(o+1)},J=function(e){r[l].sliderElements[e].classList.remove("parvus__slide--is-active"),r[l].sliderElements[e].setAttribute("aria-hidden","true")},K=function(){l=null!==l?l:a,x=-o*u.offsetWidth,r[l].slider.style.transform=`translate3d(${x}px, 0, 0)`,$=x},V=function(e){1===r[l].gallery.length?m.focus():0===o?h.focus():o===r[l].gallery.length-1||"left"===e?g.focus():h.focus()},G=function(){v.textContent=`${o+1}/${r[l].gallery.length}`},Q=function(){E={startX:0,endX:0,startY:0,endY:0}},Z=function(){const e=E.endX-E.startX,t=E.endY-E.startY,n=Math.abs(e),i=Math.abs(t);L&&e>0&&n>=d.threshold&&o>0?j():L&&e<0&&n>=d.threshold&&o!==r[l].gallery.length-1?W():A&&i>0?i>=d.threshold&&d.swipeClose?O():(c.style.opacity=1,u.classList.remove("parvus--is-vertical-closing"),K()):K()},ee=function(){(d.swipeClose&&!r[l].slider.classList.contains("parvus__slider--is-draggable")||r[l].gallery.length>1&&!r[l].slider.classList.contains("parvus__slider--is-draggable"))&&r[l].slider.classList.add("parvus__slider--is-draggable"),1===r[l].gallery.length?(g.setAttribute("aria-hidden","true"),g.disabled=!0,h.setAttribute("aria-hidden","true"),h.disabled=!0):0===o?(g.setAttribute("aria-hidden","true"),g.disabled=!0,h.setAttribute("aria-hidden","false"),h.disabled=!1):o===r[l].gallery.length-1?(g.setAttribute("aria-hidden","false"),g.disabled=!1,h.setAttribute("aria-hidden","true"),h.disabled=!0):(g.setAttribute("aria-hidden","false"),g.disabled=!1,h.setAttribute("aria-hidden","false"),h.disabled=!1),1===r[l].gallery.length?v.setAttribute("aria-hidden","true"):v.setAttribute("aria-hidden","false")},te=function(){T||(T=!0,n.requestAnimationFrame((()=>{K(),T=!1})))},ne=function(e){e.preventDefault(),D(this)},ie=function(e){e.target===g?j():e.target===h?W():(e.target===m||!A&&!L&&e.target.classList.contains("parvus__slide")&&d.docClose)&&O(),e.stopPropagation()},se=function(){return Array.prototype.slice.call(u.querySelectorAll(`${i.join(", ")}`)).filter((function(e){return!!(e.offsetWidth||e.offsetHeight||e.getClientRects().length)}))},re=function(){se()[0].focus()},ae=function(e){const t=se(),n=t.indexOf(document.activeElement);"Tab"===e.code?e.shiftKey&&0===n?(t[t.length-1].focus(),e.preventDefault()):e.shiftKey||n!==t.length-1||(t[0].focus(),e.preventDefault()):"Escape"===e.code?(e.preventDefault(),O()):"ArrowLeft"===e.code?(e.preventDefault(),j()):"ArrowRight"===e.code&&(e.preventDefault(),W())},le=function(){O()},oe=function(e){e.preventDefault(),e.stopPropagation(),L=!1,A=!1,_=!0,E.startX=e.pageX,E.startY=e.pageY,r[l].slider.classList.add("parvus__slider--is-dragging"),r[l].slider.style.willChange="transform"},de=function(e){e.preventDefault(),_&&(E.endX=e.pageX,E.endY=e.pageY,he())},ue=function(e){e.stopPropagation(),_=!1,r[l].slider.classList.remove("parvus__slider--is-dragging"),r[l].slider.style.willChange="auto",(E.endX||E.endY)&&Z(),Q()},ce=function(e){e.stopPropagation(),L=!1,A=!1,_=!0,E.startX=e.touches[0].pageX,E.startY=e.touches[0].pageY,r[l].slider.classList.add("parvus__slider--is-dragging"),r[l].slider.style.willChange="transform"},pe=function(e){e.stopPropagation(),_&&(e.preventDefault(),E.endX=e.touches[0].pageX,E.endY=e.touches[0].pageY,he())},ge=function(e){e.stopPropagation(),_=!1,r[l].slider.classList.remove("parvus__slider--is-dragging"),r[l].slider.style.willChange="auto",(E.endX||E.endY)&&Z(),Q()},he=function(){const e=E.startX-E.endX,t=E.endY-E.startY,n=Math.abs(t);Math.abs(e)>0&&!A&&r[l].gallery.length>1?(r[l].slider.style.transform=`translate3d(${$-Math.round(e)}px, 0, 0)`,L=!0,A=!1):Math.abs(t)>0&&!L&&d.swipeClose&&(n<=96&&!S&&(p=1-n/100),u.classList.add("parvus--is-vertical-closing"),c.style.opacity=p,r[l].slider.style.transform=`translate3d(${$}px, ${Math.round(t)}px, 0)`,L=!1,A=!0)},me=function(){n.addEventListener("keydown",ae),n.addEventListener("resize",te),d.scrollClose&&n.addEventListener("wheel",le),n.addEventListener("popstate",O),u.addEventListener("click",ie),be()&&(u.addEventListener("touchstart",ce),u.addEventListener("touchmove",pe),u.addEventListener("touchend",ge)),u.addEventListener("mousedown",oe),u.addEventListener("mouseup",ue),u.addEventListener("mousemove",de)},ve=function(){n.removeEventListener("keydown",ae),n.removeEventListener("resize",te),d.scrollClose&&n.removeEventListener("wheel",le),n.removeEventListener("popstate",O),u.removeEventListener("click",ie),be()&&(u.removeEventListener("touchstart",ce),u.removeEventListener("touchmove",pe),u.removeEventListener("touchend",ge)),u.removeEventListener("mousedown",oe),u.removeEventListener("mouseup",ue),u.removeEventListener("mousemove",de)},fe=function(){return"false"===u.getAttribute("aria-hidden")},be=function(){return"ontouchstart"in window};return q(t),e.init=q,e.open=D,e.close=O,e.select=R,e.previous=j,e.next=W,e.currentIndex=function(){return o},e.add=Y,e.remove=k,e.destroy=function(){if(!u)return;fe()&&O(),u.remove();document.querySelectorAll(".parvus-trigger").forEach((e=>{k(e)}));const e=new CustomEvent("destroy");u.dispatchEvent(e)},e.isOpen=fe,e.on=function(e,t){u&&u.addEventListener(e,t)},e.off=function(e,t){u&&u.removeEventListener(e,t)},e}export{e as default}; | ||
var e={lightboxLabel:"This is a dialog window which overlays the main content of the page. The modal shows the enlarged image. Pressing the Escape key will close the modal and bring you back to where you were on the page.",lightboxLoadingIndicatorLabel:"Image loading",previousButtonLabel:"Previous image",nextButtonLabel:"Next image",closeButtonLabel:"Close dialog window"};function t(n){const i=window,s=["button:not([disabled]):not([inert])",'[tabindex]:not([tabindex^="-"]):not([inert])'],a={gallery:[],slider:null,sliderElements:[],images:[]};let r={},l=null,o=null,d=0,u={},c=null,p=null,g=1,h=null,m=null,v=null,f=null,b=null,y=null,w=null,A=0,E=0,L=0,_=0,C={},x=!1,$=!1,S=!1,B=null,T=null,M=null,q=!1,F=null,I=!0;const N=window.matchMedia("(prefers-reduced-motion)"),X=function(){N.matches?(I=!0,F=u.reducedTransitionDuration):(I=!1,F=u.transitionDuration)};N.addEventListener("change",X);const Y=function(t){u=function(t){return{selector:".lightbox",gallerySelector:null,captions:!0,captionsSelector:"self",captionsAttribute:"data-caption",docClose:!0,scrollClose:!1,swipeClose:!0,threshold:50,backFocus:!0,transitionDuration:300,reducedTransitionDuration:.1,transitionTimingFunction:"cubic-bezier(0.4, 0, 0.22, 1)",lightboxIndicatorIcon:'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="M8 3H5a2 2 0 00-2 2v3m18 0V5a2 2 0 00-2-2h-3m0 18h3a2 2 0 002-2v-3M3 16v3a2 2 0 002 2h3"/></svg>',previousButtonIcon:'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path stroke="none" d="M0 0h24v24H0z"/><polyline points="15 6 9 12 15 18" /></svg>',nextButtonIcon:'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path stroke="none" d="M0 0h24v24H0z"/><polyline points="9 6 15 12 9 18" /></svg>',closeButtonIcon:'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="M18 6L6 18M6 6l12 12"/></svg>',l10n:e,fileTypes:/\.(png|jpe?g|webp|avif|svg)(\?.*)?$/i,...t}}(t);if(document.querySelectorAll(u.selector).length)if(X(),c||O(),null!==u.gallerySelector){document.querySelectorAll(u.gallerySelector).forEach(((e,t)=>{const n=t;e.querySelectorAll(u.selector).forEach((e=>{e.setAttribute("data-group",`parvus-gallery-${n}`),D(e)}))}));document.querySelectorAll(`${u.selector}:not(.parvus-trigger)`).forEach((e=>{D(e)}))}else{document.querySelectorAll(u.selector).forEach((e=>{D(e)}))}},k=function(e){const t=Math.floor(1e4*Math.random());return e.hasAttribute("data-group")&&""!==e.getAttribute("data-group")||e.setAttribute("data-group",`default-${t}`),e.getAttribute("data-group")},D=function(e){if(!("A"===e.tagName&&e.hasAttribute("href")&&e.href.match(u.fileTypes)||"BUTTON"===e.tagName&&e.hasAttribute("data-target")&&e.getAttribute("data-target").match(u.fileTypes)))throw new Error(e,`Use a link with the 'href' attribute or a button with the 'data-target' attribute. Both attributes must have a path to the image file. Supported image file types: ${u.fileTypes}.`);var t;if(l=k(e),Object.prototype.hasOwnProperty.call(r,l)||(r[l]=(t=a,JSON.parse(JSON.stringify(t)))),r[l].gallery.includes(e))throw new Error("Ups, element already added.");if(r[l].gallery.push(e),null!==e.querySelector("img")){const t=document.createElement("div");e.classList.add("parvus-zoom"),t.className="parvus-zoom__indicator",t.innerHTML=u.lightboxIndicatorIcon,e.appendChild(t)}e.classList.add("parvus-trigger"),e.addEventListener("click",le),Ee()&&l===o&&(z(e,r[l].gallery.indexOf(e)),J(r[l].gallery.indexOf(e)),se(),ee(),te())},H=function(e){if(Ee()||!c||!e||!e.hasAttribute("data-group"))return;const t=k(e);if(!r[t].gallery.includes(e))throw new Error("Ups, I can't find the element.");if(r[t].gallery.splice(r[t].gallery.indexOf(e),1),e.classList.contains("parvus-zoom")){const t=e.querySelector(".parvus-zoom__indicator");e.classList.remove("parvus-zoom"),e.removeChild(t)}e.removeEventListener("click",le),e.classList.remove("parvus-trigger")},O=function(){c=document.createElement("div"),c.setAttribute("role","dialog"),c.setAttribute("aria-modal","true"),c.setAttribute("aria-hidden","true"),c.setAttribute("tabindex","-1"),c.setAttribute("aria-label",u.l10n.lightboxLabel),c.classList.add("parvus"),p=document.createElement("div"),p.classList.add("parvus__overlay"),p.style.opacity=0,c.appendChild(p),h=document.createElement("div"),h.className="parvus__toolbar",m=document.createElement("div"),v=document.createElement("div"),y=document.createElement("button"),y.className="parvus__btn parvus__btn--close",y.setAttribute("type","button"),y.setAttribute("aria-label",u.l10n.closeButtonLabel),y.innerHTML=u.closeButtonIcon,v.appendChild(y),f=document.createElement("button"),f.className="parvus__btn parvus__btn--previous",f.setAttribute("type","button"),f.setAttribute("aria-label",u.l10n.previousButtonLabel),f.innerHTML=u.previousButtonIcon,c.appendChild(f),b=document.createElement("button"),b.className="parvus__btn parvus__btn--next",b.setAttribute("type","button"),b.setAttribute("aria-label",u.l10n.nextButtonLabel),b.innerHTML=u.nextButtonIcon,c.appendChild(b),w=document.createElement("div"),w.className="parvus__counter",m.appendChild(w),h.appendChild(m),h.appendChild(v),c.appendChild(h),document.body.appendChild(c)},z=function(e,t){const n=document.createElement("div"),i=document.createElement("div");n.className="parvus__slide",n.style.position="absolute",n.style.left=100*t+"%",n.setAttribute("aria-hidden","true"),j(t,e,i),n.appendChild(i),r[o].sliderElements[t]=n,t===d&&r[o].slider.appendChild(n),t>d?r[o].sliderElements[d].after(n):r[o].sliderElements[d].before(n)},R=function(e){if(!c||!e||!e.classList.contains("parvus-trigger")||Ee())return;if(o=k(e),!r[o].gallery.includes(e))throw new Error("Ups, I can't find the element.");d=r[o].gallery.indexOf(e),B=document.activeElement;const t=window.location.href;history.pushState({parvus:"close"},"Image",t),we();document.querySelectorAll('body > *:not([aria-hidden="true"])').forEach((e=>{e.setAttribute("aria-hidden","true"),e.classList.add("parvus-hidden")})),c.classList.add("parvus--is-opening"),c.setAttribute("aria-hidden","false"),r[o].slider=document.createElement("div"),r[o].slider.className="parvus__slider",r[o].slider.setAttribute("aria-hidden","true"),c.appendChild(r[o].slider),z(e,d),r[o].slider.setAttribute("aria-hidden","false"),Z(),se(),te(),ue(),W(d),J(d),requestAnimationFrame((()=>{c.classList.remove("parvus--is-opening"),p.style.opacity=1,p.style.transition=`opacity ${F}ms ${u.transitionTimingFunction}`,p.style.willChange="opacity"})),p.addEventListener("transitionend",(()=>{P(d+1),P(d-1)})),r[o].slider.classList.add("parvus__slider--animate");const n=new CustomEvent("open",{detail:{source:e}});c.dispatchEvent(n)},U=function(){if(!Ee())throw new Error("Ups, I'm already closed.");const e=r[o].images[d],t=e.getBoundingClientRect(),n=(u.backFocus?r[o].gallery[d]:B).getBoundingClientRect();Ae(),ne(),null!==history.state&&"close"===history.state.parvus&&history.back();document.querySelectorAll(".parvus-hidden").forEach((e=>{e.removeAttribute("aria-hidden"),e.classList.remove("parvus-hidden")})),c.classList.add("parvus--is-closing"),requestAnimationFrame((()=>{A=n.width/t.width,E=n.height/t.height,L=n.left-t.left,_=n.top-t.top,e.style.transform=`translate(${L}px, ${_}px) scale(${A}, ${E})`,e.style.opacity=0,e.style.transition=`transform ${F}ms ${u.transitionTimingFunction}, opacity ${F}ms ${u.transitionTimingFunction} ${F/2}ms`,p.style.opacity=0,p.style.transition=`opacity ${F}ms ${u.transitionTimingFunction}`,p.style.willChange="auto"})),p.addEventListener("transitionend",(()=>{Q(d),B=u.backFocus?r[o].gallery[d]:B,B.focus({preventScroll:!0}),c.setAttribute("aria-hidden","true"),c.classList.remove("parvus--is-closing"),c.classList.remove("parvus--is-vertical-closing"),r={},e.style.transform=""}),{once:!0});const i=new CustomEvent("close",{detail:{source:r[o].gallery[d]}});c.dispatchEvent(i)},P=function(e){void 0!==r[o].gallery[e]&&(z(r[o].gallery[e],e),J(e))},W=function(e){r[o].sliderElements[e].classList.add("parvus__slide--is-active"),r[o].sliderElements[e].setAttribute("aria-hidden","false")},j=function(e,t,n){const i=document.createElement("img"),s=document.createElement("div"),a=document.createElement("div"),l=t.querySelector("img"),d=document.createElement("div");if(s.className="parvus__content",a.className="parvus__caption",d.className="parvus__loader",d.setAttribute("role","progressbar"),d.setAttribute("aria-label",u.l10n.lightboxLoadingIndicatorLabel),n.appendChild(d),i.onload=()=>{n.removeChild(d),i.setAttribute("width",i.naturalWidth),i.setAttribute("height",i.naturalHeight)},"A"===t.tagName?(i.setAttribute("src",t.href),i.alt=l?l.alt||"":t.getAttribute("data-alt")||""):(i.alt=t.getAttribute("data-alt")||"",i.setAttribute("src",t.getAttribute("data-target"))),t.hasAttribute("data-srcset")&&""!==t.getAttribute("data-srcset")&&i.setAttribute("srcset",t.getAttribute("data-srcset")),i.style.opacity=0,s.appendChild(i),r[o].images[e]=i,n.appendChild(s),u.captions){let e=null;if("self"===u.captionsSelector)t.hasAttribute(u.captionsAttribute)&&""!==t.getAttribute(u.captionsAttribute)&&(e=t.getAttribute(u.captionsAttribute));else if(null!==t.querySelector(u.captionsSelector)){const n=t.querySelector(u.captionsSelector);e=n.hasAttribute(u.captionsAttribute)&&""!==n.getAttribute(u.captionsAttribute)?n.getAttribute(u.captionsAttribute):n.innerHTML}null!==e&&(a.innerHTML=`<p>${e}</p>`,n.appendChild(a))}},J=function(e){re(r[o].sliderElements[e],r[o].images[e]);const t=r[o].images[e],n=t.getBoundingClientRect(),i=r[o].gallery[e].getBoundingClientRect();c.classList.contains("parvus--is-opening")?(A=i.width/n.width,E=i.height/n.height,L=i.left-n.left,_=i.top-n.top,console.log(i.width),console.log(i.height),console.log(n.width),console.log(n.height),requestAnimationFrame((()=>{t.style.transform=`translate(${L}px, ${_}px) scale(${A}, ${E})`,t.style.transition="transform 0s, opacity 0s",requestAnimationFrame((()=>{t.style.transform="",t.style.opacity=1,t.style.transition=`transform ${F}ms ${u.transitionTimingFunction}, opacity ${F/2}ms ${u.transitionTimingFunction}`}))}))):t.style.opacity=1},K=function(e){const t=d;if(!Ee())throw new Error("Ups, I'm closed.");if(!e&&0!==e)throw new Error("Ups, no slide specified.");if(e===d)throw new Error(`Ups, slide ${e} is already selected.`);if(-1===e||e>=r[o].gallery.length)throw new Error(`Ups, I can't find slide ${e}.`);Q(t),W(e),J(e),e<t&&(d--,Z(),se(),ee("left"),P(e-1)),e>t&&(d++,Z(),se(),ee("right"),P(e+1)),te();const n=new CustomEvent("select",{detail:{source:r[o].gallery[d]}});c.dispatchEvent(n)},V=function(){d>0&&K(d-1)},G=function(){d<r[o].gallery.length-1&&K(d+1)},Q=function(e){r[o].sliderElements[e].classList.remove("parvus__slide--is-active"),r[o].sliderElements[e].setAttribute("aria-hidden","true")},Z=function(){o=null!==o?o:l,T=d*c.offsetWidth*-1,r[o].slider.style.transform=`translate3d(${T}px, 0, 0)`,M=T},ee=function(e){1===r[o].gallery.length?y.focus():0===d?b.focus():d===r[o].gallery.length-1||"left"===e?f.focus():b.focus()},te=function(){w.textContent=`${d+1}/${r[o].gallery.length}`},ne=function(){C={startX:0,endX:0,startY:0,endY:0}},ie=function(){const e=C.endX-C.startX,t=C.endY-C.startY,n=Math.abs(e),i=Math.abs(t);x&&e>0&&n>=u.threshold&&d>0?V():x&&e<0&&n>=u.threshold&&d!==r[o].gallery.length-1?G():$&&i>0?i>=u.threshold&&u.swipeClose?U():(p.style.opacity=1,c.classList.remove("parvus--is-vertical-closing"),Z()):Z()},se=function(){(u.swipeClose&&!r[o].slider.classList.contains("parvus__slider--is-draggable")||r[o].gallery.length>1&&!r[o].slider.classList.contains("parvus__slider--is-draggable"))&&r[o].slider.classList.add("parvus__slider--is-draggable"),1===r[o].gallery.length?(f.setAttribute("aria-hidden","true"),f.disabled=!0,b.setAttribute("aria-hidden","true"),b.disabled=!0):0===d?(f.setAttribute("aria-hidden","true"),f.disabled=!0,b.setAttribute("aria-hidden","false"),b.disabled=!1):d===r[o].gallery.length-1?(f.setAttribute("aria-hidden","false"),f.disabled=!1,b.setAttribute("aria-hidden","true"),b.disabled=!0):(f.setAttribute("aria-hidden","false"),f.disabled=!1,b.setAttribute("aria-hidden","false"),b.disabled=!1),1===r[o].gallery.length?w.setAttribute("aria-hidden","true"):w.setAttribute("aria-hidden","false")},ae=function(){q||(q=!0,i.requestAnimationFrame((()=>{re(r[o].sliderElements[d],r[o].images[d]),Z(),q=!1})))},re=function(e,t){const n=getComputedStyle(e),i=e.querySelector(".parvus__caption").getBoundingClientRect(),s=t.naturalHeight,a=t.naturalWidth;let r=e.getBoundingClientRect().height,l=e.getBoundingClientRect().width;r-=parseFloat(n.paddingTop)+parseFloat(n.paddingBottom)+parseFloat(i.height),l-=parseFloat(n.paddingLeft)+parseFloat(n.paddingRight);const o=Math.min(l/a||0,r/s);t.style.width=`${a*o||0}px`,t.style.height=`${s*o||0}px`,console.log(a*o||0),console.log(s*o||0)},le=function(e){e.preventDefault(),R(this)},oe=function(e){e.target===f?V():e.target===b?G():(e.target===y||!$&&!x&&e.target.classList.contains("parvus__slide")&&u.docClose)&&U(),e.stopPropagation()},de=function(){return Array.prototype.slice.call(c.querySelectorAll(`${s.join(", ")}`)).filter((function(e){return!!(e.offsetWidth||e.offsetHeight||e.getClientRects().length)}))},ue=function(){de()[0].focus()},ce=function(e){const t=de(),n=t.indexOf(document.activeElement);"Tab"===e.code?e.shiftKey&&0===n?(t[t.length-1].focus(),e.preventDefault()):e.shiftKey||n!==t.length-1||(t[0].focus(),e.preventDefault()):"Escape"===e.code?(e.preventDefault(),U()):"ArrowLeft"===e.code?(e.preventDefault(),V()):"ArrowRight"===e.code&&(e.preventDefault(),G())},pe=function(){U()},ge=function(e){e.preventDefault(),e.stopPropagation(),x=!1,$=!1,S=!0,C.startX=e.pageX,C.startY=e.pageY,r[o].slider.classList.add("parvus__slider--is-dragging"),r[o].slider.style.willChange="transform"},he=function(e){e.preventDefault(),S&&(C.endX=e.pageX,C.endY=e.pageY,ye())},me=function(e){e.stopPropagation(),S=!1,r[o].slider.classList.remove("parvus__slider--is-dragging"),r[o].slider.style.willChange="auto",(C.endX||C.endY)&&ie(),ne()},ve=function(e){e.stopPropagation(),x=!1,$=!1,S=!0,C.startX=e.touches[0].pageX,C.startY=e.touches[0].pageY,r[o].slider.classList.add("parvus__slider--is-dragging"),r[o].slider.style.willChange="transform"},fe=function(e){e.stopPropagation(),S&&(e.preventDefault(),C.endX=e.touches[0].pageX,C.endY=e.touches[0].pageY,ye())},be=function(e){e.stopPropagation(),S=!1,r[o].slider.classList.remove("parvus__slider--is-dragging"),r[o].slider.style.willChange="auto",(C.endX||C.endY)&&ie(),ne()},ye=function(){const e=C.startX-C.endX,t=C.endY-C.startY,n=Math.abs(t);Math.abs(e)>0&&!$&&r[o].gallery.length>1?(r[o].slider.style.transform=`translate3d(${M-Math.round(e)}px, 0, 0)`,x=!0,$=!1):Math.abs(t)>0&&!x&&u.swipeClose&&(n<=96&&!I&&(g=1-n/100),c.classList.add("parvus--is-vertical-closing"),p.style.opacity=g,r[o].slider.style.transform=`translate3d(${M}px, ${Math.round(t)}px, 0)`,x=!1,$=!0)},we=function(){i.addEventListener("keydown",ce),i.addEventListener("resize",ae),u.scrollClose&&i.addEventListener("wheel",pe),i.addEventListener("popstate",U),c.addEventListener("click",oe),Le()&&(c.addEventListener("touchstart",ve),c.addEventListener("touchmove",fe),c.addEventListener("touchend",be)),c.addEventListener("mousedown",ge),c.addEventListener("mouseup",me),c.addEventListener("mousemove",he)},Ae=function(){i.removeEventListener("keydown",ce),i.removeEventListener("resize",ae),u.scrollClose&&i.removeEventListener("wheel",pe),i.removeEventListener("popstate",U),c.removeEventListener("click",oe),Le()&&(c.removeEventListener("touchstart",ve),c.removeEventListener("touchmove",fe),c.removeEventListener("touchend",be)),c.removeEventListener("mousedown",ge),c.removeEventListener("mouseup",me),c.removeEventListener("mousemove",he)},Ee=function(){return"false"===c.getAttribute("aria-hidden")},Le=function(){return"ontouchstart"in window};return Y(n),t.init=Y,t.open=R,t.close=U,t.select=K,t.previous=V,t.next=G,t.currentIndex=function(){return d},t.add=D,t.remove=H,t.destroy=function(){if(!c)return;Ee()&&U(),c.remove();document.querySelectorAll(".parvus-trigger").forEach((e=>{H(e)}));const e=new CustomEvent("destroy");c.dispatchEvent(e)},t.isOpen=Ee,t.on=function(e,t){c&&c.addEventListener(e,t)},t.off=function(e,t){c&&c.removeEventListener(e,t)},t}export{t as default}; |
@@ -5,3 +5,3 @@ /** | ||
* @author Benjamin de Oostfrees | ||
* @version 1.4.3 | ||
* @version 2.0.0 | ||
* @url https://github.com/deoostfrees/parvus | ||
@@ -18,2 +18,11 @@ * | ||
var en = { | ||
lightboxLabel: 'This is a dialog window which overlays the main content of the page. The modal shows the enlarged image. Pressing the Escape key will close the modal and bring you back to where you were on the page.', | ||
lightboxLoadingIndicatorLabel: 'Image loading', | ||
previousButtonLabel: 'Previous image', | ||
nextButtonLabel: 'Next image', | ||
closeButtonLabel: 'Close dialog window' | ||
}; | ||
// Default language | ||
function Parvus(userOptions) { | ||
@@ -29,5 +38,6 @@ /** | ||
slider: null, | ||
sliderElements: [] | ||
sliderElements: [], | ||
images: [] | ||
}; | ||
const GROUPS = {}; | ||
let groups = {}; | ||
let newGroup = null; | ||
@@ -40,2 +50,5 @@ let activeGroup = null; | ||
let lightboxOverlayOpacity = 1; | ||
let toolbar = null; | ||
let toolbarLeft = null; | ||
let toolbarRight = null; | ||
let previousButton = null; | ||
@@ -62,4 +75,4 @@ let nextButton = null; | ||
* | ||
* @param {Object} userOptions - Optional user options | ||
* @returns {Object} - Custom options | ||
* @param {Object} userOptions | ||
* @returns {Object} | ||
*/ | ||
@@ -72,2 +85,5 @@ | ||
gallerySelector: null, | ||
captions: true, | ||
captionsSelector: 'self', | ||
captionsAttribute: 'data-caption', | ||
docClose: true, | ||
@@ -85,12 +101,3 @@ scrollClose: false, | ||
closeButtonIcon: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="M18 6L6 18M6 6l12 12"/></svg>', | ||
lang: 'en', | ||
i18n: { | ||
en: { | ||
lightboxLabel: 'This is a dialog window which overlays the main content of the page. The modal shows the enlarged image. Pressing the Escape key will close the modal and bring you back to where you were on the page.', | ||
lightboxLoadingIndicatorLabel: 'Image loading', | ||
previousButtonLabel: 'Previous image', | ||
nextButtonLabel: 'Next image', | ||
closeButtonLabel: 'Close dialog window' | ||
} | ||
}, | ||
l10n: en, | ||
fileTypes: /\.(png|jpe?g|webp|avif|svg)(\?.*)?$/i | ||
@@ -176,3 +183,3 @@ }; | ||
* @param {HTMLElement} el | ||
* @return {string} | ||
* @return {String} | ||
*/ | ||
@@ -193,4 +200,4 @@ | ||
* | ||
* @param {object} object | ||
* @return {object} | ||
* @param {Object} object | ||
* @return {Object} | ||
*/ | ||
@@ -205,3 +212,3 @@ | ||
* | ||
* @param {HTMLElement} el - Element to add | ||
* @param {HTMLElement} el | ||
*/ | ||
@@ -217,9 +224,9 @@ | ||
if (!Object.prototype.hasOwnProperty.call(GROUPS, newGroup)) { | ||
GROUPS[newGroup] = copyObject(GROUP_ATTS); | ||
if (!Object.prototype.hasOwnProperty.call(groups, newGroup)) { | ||
groups[newGroup] = copyObject(GROUP_ATTS); | ||
} // Check if element already exists | ||
if (!GROUPS[newGroup].gallery.includes(el)) { | ||
GROUPS[newGroup].gallery.push(el); | ||
if (!groups[newGroup].gallery.includes(el)) { | ||
groups[newGroup].gallery.push(el); | ||
@@ -239,4 +246,4 @@ if (el.querySelector('img') !== null) { | ||
if (isOpen() && newGroup === activeGroup) { | ||
createSlide(el, GROUPS[newGroup].gallery.indexOf(el)); | ||
loadImage(GROUPS[newGroup].gallery.indexOf(el)); | ||
createSlide(el, groups[newGroup].gallery.indexOf(el)); | ||
loadImage(groups[newGroup].gallery.indexOf(el)); | ||
updateConfig(); | ||
@@ -253,3 +260,3 @@ updateFocus(); | ||
* | ||
* @param {HTMLElement} el - Element to remove | ||
* @param {HTMLElement} el | ||
*/ | ||
@@ -265,3 +272,3 @@ | ||
if (!GROUPS[GROUP].gallery.includes(el)) { | ||
if (!groups[GROUP].gallery.includes(el)) { | ||
throw new Error('Ups, I can\'t find the element.'); | ||
@@ -271,3 +278,3 @@ } // TODO: Remove elements dynamically | ||
GROUPS[GROUP].gallery.splice(GROUPS[GROUP].gallery.indexOf(el), 1); // Remove lightbox indicator icon if necessary | ||
groups[GROUP].gallery.splice(groups[GROUP].gallery.indexOf(el), 1); // Remove lightbox indicator icon if necessary | ||
@@ -297,3 +304,3 @@ if (el.classList.contains('parvus-zoom')) { | ||
lightbox.setAttribute('tabindex', '-1'); | ||
lightbox.setAttribute('aria-label', config.i18n[config.lang].lightboxLabel); | ||
lightbox.setAttribute('aria-label', config.l10n.lightboxLabel); | ||
lightbox.classList.add('parvus'); // Create the lightbox overlay container | ||
@@ -305,11 +312,16 @@ | ||
lightbox.appendChild(lightboxOverlay); // Create the close button | ||
lightbox.appendChild(lightboxOverlay); // Create the toolbar | ||
toolbar = document.createElement('div'); | ||
toolbar.className = 'parvus__toolbar'; | ||
toolbarLeft = document.createElement('div'); | ||
toolbarRight = document.createElement('div'); // Create the close button | ||
closeButton = document.createElement('button'); | ||
closeButton.className = 'parvus__btn parvus__btn--close'; | ||
closeButton.setAttribute('type', 'button'); | ||
closeButton.setAttribute('aria-label', config.i18n[config.lang].closeButtonLabel); | ||
closeButton.innerHTML = config.closeButtonIcon; // Add close button to lightbox container | ||
closeButton.setAttribute('aria-label', config.l10n.closeButtonLabel); | ||
closeButton.innerHTML = config.closeButtonIcon; // Add close button to right toolbar item | ||
lightbox.appendChild(closeButton); // Create the previous button | ||
toolbarRight.appendChild(closeButton); // Create the previous button | ||
@@ -319,3 +331,3 @@ previousButton = document.createElement('button'); | ||
previousButton.setAttribute('type', 'button'); | ||
previousButton.setAttribute('aria-label', config.i18n[config.lang].previousButtonLabel); | ||
previousButton.setAttribute('aria-label', config.l10n.previousButtonLabel); | ||
previousButton.innerHTML = config.previousButtonIcon; // Add previous button to lightbox container | ||
@@ -328,3 +340,3 @@ | ||
nextButton.setAttribute('type', 'button'); | ||
nextButton.setAttribute('aria-label', config.i18n[config.lang].nextButtonLabel); | ||
nextButton.setAttribute('aria-label', config.l10n.nextButtonLabel); | ||
nextButton.innerHTML = config.nextButtonIcon; // Add next button to lightbox container | ||
@@ -335,6 +347,11 @@ | ||
counter = document.createElement('div'); | ||
counter.className = 'parvus__counter'; // Add counter to lightbox container | ||
counter.className = 'parvus__counter'; // Add counter to left toolbar item | ||
lightbox.appendChild(counter); // Add lightbox container to body | ||
toolbarLeft.appendChild(counter); // Add toolbar items to toolbar | ||
toolbar.appendChild(toolbarLeft); | ||
toolbar.appendChild(toolbarRight); // Add toolbar to lightbox container | ||
lightbox.appendChild(toolbar); // Add lightbox container to body | ||
document.body.appendChild(lightbox); | ||
@@ -349,7 +366,7 @@ }; | ||
const createSlider = function createSlider() { | ||
GROUPS[activeGroup].slider = document.createElement('div'); | ||
GROUPS[activeGroup].slider.className = 'parvus__slider'; // Hide slider | ||
groups[activeGroup].slider = document.createElement('div'); | ||
groups[activeGroup].slider.className = 'parvus__slider'; // Hide slider | ||
GROUPS[activeGroup].slider.setAttribute('aria-hidden', 'true'); | ||
lightbox.appendChild(GROUPS[activeGroup].slider); | ||
groups[activeGroup].slider.setAttribute('aria-hidden', 'true'); | ||
lightbox.appendChild(groups[activeGroup].slider); | ||
}; | ||
@@ -359,2 +376,4 @@ /** | ||
* | ||
* @param {HTMLElement} el | ||
* @param {Number} index | ||
*/ | ||
@@ -371,15 +390,15 @@ | ||
SLIDER_ELEMENT.setAttribute('aria-hidden', 'true'); | ||
createImage(el, SLIDER_ELEMENT_CONTENT); // Add slide content container to slider element | ||
createImage(index, el, SLIDER_ELEMENT_CONTENT); // Add slide content container to slider element | ||
SLIDER_ELEMENT.appendChild(SLIDER_ELEMENT_CONTENT); | ||
GROUPS[activeGroup].sliderElements[index] = SLIDER_ELEMENT; // Add slider element to slider | ||
groups[activeGroup].sliderElements[index] = SLIDER_ELEMENT; // Add slider element to slider | ||
if (index === currentIndex) { | ||
GROUPS[activeGroup].slider.appendChild(SLIDER_ELEMENT); | ||
groups[activeGroup].slider.appendChild(SLIDER_ELEMENT); | ||
} | ||
if (index > currentIndex) { | ||
GROUPS[activeGroup].sliderElements[currentIndex].after(SLIDER_ELEMENT); | ||
groups[activeGroup].sliderElements[currentIndex].after(SLIDER_ELEMENT); | ||
} else { | ||
GROUPS[activeGroup].sliderElements[currentIndex].before(SLIDER_ELEMENT); | ||
groups[activeGroup].sliderElements[currentIndex].before(SLIDER_ELEMENT); | ||
} | ||
@@ -390,3 +409,3 @@ }; | ||
* | ||
* @param {number} index - Index to load | ||
* @param {HTMLElement} el | ||
*/ | ||
@@ -402,7 +421,7 @@ | ||
if (!GROUPS[activeGroup].gallery.includes(el)) { | ||
if (!groups[activeGroup].gallery.includes(el)) { | ||
throw new Error('Ups, I can\'t find the element.'); | ||
} | ||
currentIndex = GROUPS[activeGroup].gallery.indexOf(el); // Save user’s focus | ||
currentIndex = groups[activeGroup].gallery.indexOf(el); // Save user’s focus | ||
@@ -430,3 +449,3 @@ lastFocus = document.activeElement; // Use `history.pushState()` to make sure the 'Back' button behavior | ||
GROUPS[activeGroup].slider.setAttribute('aria-hidden', 'false'); | ||
groups[activeGroup].slider.setAttribute('aria-hidden', 'false'); | ||
updateOffset(); | ||
@@ -450,3 +469,3 @@ updateConfig(); | ||
GROUPS[activeGroup].slider.classList.add('parvus__slider--animate'); // Create and dispatch a new event | ||
groups[activeGroup].slider.classList.add('parvus__slider--animate'); // Create and dispatch a new event | ||
@@ -471,6 +490,5 @@ const OPEN_EVENT = new CustomEvent('open', { | ||
const IMAGE_CONTAINER = GROUPS[activeGroup].sliderElements[currentIndex]; | ||
const IMAGE = IMAGE_CONTAINER.querySelector('img'); | ||
const IMAGE = groups[activeGroup].images[currentIndex]; | ||
const IMAGE_SIZE = IMAGE.getBoundingClientRect(); | ||
const THUMBNAIL = config.backFocus ? GROUPS[activeGroup].gallery[currentIndex] : lastFocus; | ||
const THUMBNAIL = config.backFocus ? groups[activeGroup].gallery[currentIndex] : lastFocus; | ||
const THUMBNAIL_SIZE = THUMBNAIL.getBoundingClientRect(); | ||
@@ -509,3 +527,3 @@ unbindEvents(); | ||
lastFocus = config.backFocus ? GROUPS[activeGroup].gallery[currentIndex] : lastFocus; | ||
lastFocus = config.backFocus ? groups[activeGroup].gallery[currentIndex] : lastFocus; | ||
lastFocus.focus({ | ||
@@ -517,5 +535,5 @@ preventScroll: true | ||
lightbox.classList.remove('parvus--is-closing'); | ||
lightbox.classList.remove('parvus--is-vertical-closing'); // Remove slider | ||
lightbox.classList.remove('parvus--is-vertical-closing'); // Reset groups | ||
GROUPS[activeGroup].slider.remove(); | ||
groups = {}; | ||
IMAGE.style.transform = ''; | ||
@@ -528,3 +546,3 @@ }, { | ||
detail: { | ||
source: GROUPS[activeGroup].gallery[currentIndex] | ||
source: groups[activeGroup].gallery[currentIndex] | ||
} | ||
@@ -537,3 +555,3 @@ }); | ||
* | ||
* @param {number} index - Index to preload | ||
* @param {Number} index | ||
*/ | ||
@@ -543,7 +561,7 @@ | ||
const preload = function preload(index) { | ||
if (GROUPS[activeGroup].gallery[index] === undefined) { | ||
if (groups[activeGroup].gallery[index] === undefined) { | ||
return; | ||
} | ||
createSlide(GROUPS[activeGroup].gallery[index], index); | ||
createSlide(groups[activeGroup].gallery[index], index); | ||
loadImage(index); | ||
@@ -554,3 +572,3 @@ }; | ||
* | ||
* @param {number} index - Index to load | ||
* @param {Number} index | ||
*/ | ||
@@ -560,4 +578,4 @@ | ||
const loadSlide = function loadSlide(index) { | ||
GROUPS[activeGroup].sliderElements[index].classList.add('parvus__slide--is-active'); | ||
GROUPS[activeGroup].sliderElements[index].setAttribute('aria-hidden', 'false'); | ||
groups[activeGroup].sliderElements[index].classList.add('parvus__slide--is-active'); | ||
groups[activeGroup].sliderElements[index].setAttribute('aria-hidden', 'false'); | ||
}; | ||
@@ -567,16 +585,20 @@ /** | ||
* | ||
* @param {number} index - Index to load | ||
* @param {Number} index | ||
* @param {HTMLElement} el | ||
* @param {HTMLElement} container | ||
*/ | ||
const createImage = function createImage(el, container) { | ||
const createImage = function createImage(index, el, container) { | ||
const IMAGE = document.createElement('img'); | ||
const FIGURE = document.createElement('figure'); | ||
const FIGCAPTION = document.createElement('figcaption'); | ||
const IMAGE_CONTAINER = document.createElement('div'); | ||
const CAPTION_CONTAINER = document.createElement('div'); | ||
const THUMBNAIL = el.querySelector('img'); | ||
const LOADING_INDICATOR = document.createElement('div'); // Create loading indicator | ||
const LOADING_INDICATOR = document.createElement('div'); | ||
IMAGE_CONTAINER.className = 'parvus__content'; | ||
CAPTION_CONTAINER.className = 'parvus__caption'; // Create loading indicator | ||
LOADING_INDICATOR.className = 'parvus__loader'; | ||
LOADING_INDICATOR.setAttribute('role', 'progressbar'); | ||
LOADING_INDICATOR.setAttribute('aria-label', config.i18n[config.lang].lightboxLoadingIndicatorLabel); // Add loading indicator to container | ||
LOADING_INDICATOR.setAttribute('aria-label', config.l10n.lightboxLoadingIndicatorLabel); // Add loading indicator to container | ||
@@ -611,10 +633,30 @@ container.appendChild(LOADING_INDICATOR); | ||
IMAGE.style.opacity = 0; | ||
FIGURE.appendChild(IMAGE); // Add caption if available | ||
IMAGE_CONTAINER.appendChild(IMAGE); | ||
groups[activeGroup].images[index] = IMAGE; | ||
container.appendChild(IMAGE_CONTAINER); // Add caption if available | ||
if (el.hasAttribute('data-caption') && el.getAttribute('data-caption') !== '') { | ||
FIGCAPTION.innerHTML = el.getAttribute('data-caption'); | ||
FIGURE.appendChild(FIGCAPTION); | ||
if (config.captions) { | ||
let captionData = null; | ||
if (config.captionsSelector === 'self') { | ||
if (el.hasAttribute(config.captionsAttribute) && el.getAttribute(config.captionsAttribute) !== '') { | ||
captionData = el.getAttribute(config.captionsAttribute); | ||
} | ||
} else { | ||
if (el.querySelector(config.captionsSelector) !== null) { | ||
const CAPTION_SELECTOR = el.querySelector(config.captionsSelector); | ||
if (CAPTION_SELECTOR.hasAttribute(config.captionsAttribute) && CAPTION_SELECTOR.getAttribute(config.captionsAttribute) !== '') { | ||
captionData = CAPTION_SELECTOR.getAttribute(config.captionsAttribute); | ||
} else { | ||
captionData = CAPTION_SELECTOR.innerHTML; | ||
} | ||
} | ||
} | ||
if (captionData !== null) { | ||
CAPTION_CONTAINER.innerHTML = `<p>${captionData}</p>`; | ||
container.appendChild(CAPTION_CONTAINER); | ||
} | ||
} | ||
container.appendChild(FIGURE); | ||
}; | ||
@@ -624,3 +666,3 @@ /** | ||
* | ||
* @param {number} index - Index to load | ||
* @param {Number} index | ||
*/ | ||
@@ -630,6 +672,6 @@ | ||
const loadImage = function loadImage(index) { | ||
const IMAGE_CONTAINER = GROUPS[activeGroup].sliderElements[index]; | ||
const IMAGE = IMAGE_CONTAINER.querySelector('img'); | ||
setImageDimension(groups[activeGroup].sliderElements[index], groups[activeGroup].images[index]); | ||
const IMAGE = groups[activeGroup].images[index]; | ||
const IMAGE_SIZE = IMAGE.getBoundingClientRect(); | ||
const THUMBNAIL = GROUPS[activeGroup].gallery[index]; | ||
const THUMBNAIL = groups[activeGroup].gallery[index]; | ||
const THUMBNAIL_SIZE = THUMBNAIL.getBoundingClientRect(); | ||
@@ -642,2 +684,6 @@ | ||
yDifference = THUMBNAIL_SIZE.top - IMAGE_SIZE.top; | ||
console.log(THUMBNAIL_SIZE.width); | ||
console.log(THUMBNAIL_SIZE.height); | ||
console.log(IMAGE_SIZE.width); | ||
console.log(IMAGE_SIZE.height); | ||
requestAnimationFrame(() => { | ||
@@ -660,3 +706,3 @@ IMAGE.style.transform = `translate(${xDifference}px, ${yDifference}px) scale(${widthDifference}, ${heightDifference})`; | ||
* | ||
* @param {number} index - Index to select | ||
* @param {Number} newIndex | ||
*/ | ||
@@ -679,3 +725,3 @@ | ||
if (newIndex === -1 || newIndex >= GROUPS[activeGroup].gallery.length) { | ||
if (newIndex === -1 || newIndex >= groups[activeGroup].gallery.length) { | ||
throw new Error(`Ups, I can't find slide ${newIndex}.`); | ||
@@ -709,3 +755,3 @@ } | ||
detail: { | ||
source: GROUPS[activeGroup].gallery[currentIndex] | ||
source: groups[activeGroup].gallery[currentIndex] | ||
} | ||
@@ -733,3 +779,3 @@ }); | ||
const next = function next() { | ||
if (currentIndex < GROUPS[activeGroup].gallery.length - 1) { | ||
if (currentIndex < groups[activeGroup].gallery.length - 1) { | ||
select(currentIndex + 1); | ||
@@ -742,3 +788,3 @@ } | ||
* | ||
* @param {number} index - Index to leave | ||
* @param {Number} index | ||
*/ | ||
@@ -748,4 +794,4 @@ | ||
const leaveSlide = function leaveSlide(index) { | ||
GROUPS[activeGroup].sliderElements[index].classList.remove('parvus__slide--is-active'); | ||
GROUPS[activeGroup].sliderElements[index].setAttribute('aria-hidden', 'true'); | ||
groups[activeGroup].sliderElements[index].classList.remove('parvus__slide--is-active'); | ||
groups[activeGroup].sliderElements[index].setAttribute('aria-hidden', 'true'); | ||
}; | ||
@@ -760,4 +806,4 @@ /** | ||
activeGroup = activeGroup !== null ? activeGroup : newGroup; | ||
offset = -currentIndex * lightbox.offsetWidth; | ||
GROUPS[activeGroup].slider.style.transform = `translate3d(${offset}px, 0, 0)`; | ||
offset = currentIndex * lightbox.offsetWidth * -1; | ||
groups[activeGroup].slider.style.transform = `translate3d(${offset}px, 0, 0)`; | ||
offsetTmp = offset; | ||
@@ -768,3 +814,3 @@ }; | ||
* | ||
* @param {string} dir - Current slide direction | ||
* @param {String} dir | ||
*/ | ||
@@ -774,3 +820,3 @@ | ||
const updateFocus = function updateFocus(dir) { | ||
if (GROUPS[activeGroup].gallery.length === 1) { | ||
if (groups[activeGroup].gallery.length === 1) { | ||
closeButton.focus(); | ||
@@ -781,3 +827,3 @@ } else { | ||
nextButton.focus(); // If the last slide is displayed | ||
} else if (currentIndex === GROUPS[activeGroup].gallery.length - 1) { | ||
} else if (currentIndex === groups[activeGroup].gallery.length - 1) { | ||
previousButton.focus(); | ||
@@ -800,3 +846,3 @@ } else { | ||
const updateCounter = function updateCounter() { | ||
counter.textContent = `${currentIndex + 1}/${GROUPS[activeGroup].gallery.length}`; | ||
counter.textContent = `${currentIndex + 1}/${groups[activeGroup].gallery.length}`; | ||
}; | ||
@@ -831,3 +877,3 @@ /** | ||
previous(); | ||
} else if (isDraggingX && MOVEMENT_X < 0 && MOVEMENT_X_DISTANCE >= config.threshold && currentIndex !== GROUPS[activeGroup].gallery.length - 1) { | ||
} else if (isDraggingX && MOVEMENT_X < 0 && MOVEMENT_X_DISTANCE >= config.threshold && currentIndex !== groups[activeGroup].gallery.length - 1) { | ||
next(); | ||
@@ -853,8 +899,8 @@ } else if (isDraggingY && MOVEMENT_Y_DISTANCE > 0) { | ||
const updateConfig = function updateConfig() { | ||
if (config.swipeClose && !GROUPS[activeGroup].slider.classList.contains('parvus__slider--is-draggable') || GROUPS[activeGroup].gallery.length > 1 && !GROUPS[activeGroup].slider.classList.contains('parvus__slider--is-draggable')) { | ||
GROUPS[activeGroup].slider.classList.add('parvus__slider--is-draggable'); | ||
if (config.swipeClose && !groups[activeGroup].slider.classList.contains('parvus__slider--is-draggable') || groups[activeGroup].gallery.length > 1 && !groups[activeGroup].slider.classList.contains('parvus__slider--is-draggable')) { | ||
groups[activeGroup].slider.classList.add('parvus__slider--is-draggable'); | ||
} // Hide buttons if necessary | ||
if (GROUPS[activeGroup].gallery.length === 1) { | ||
if (groups[activeGroup].gallery.length === 1) { | ||
previousButton.setAttribute('aria-hidden', 'true'); | ||
@@ -871,3 +917,3 @@ previousButton.disabled = true; | ||
nextButton.disabled = false; // If the last slide is displayed | ||
} else if (currentIndex === GROUPS[activeGroup].gallery.length - 1) { | ||
} else if (currentIndex === groups[activeGroup].gallery.length - 1) { | ||
previousButton.setAttribute('aria-hidden', 'false'); | ||
@@ -886,3 +932,3 @@ previousButton.disabled = false; | ||
if (GROUPS[activeGroup].gallery.length === 1) { | ||
if (groups[activeGroup].gallery.length === 1) { | ||
counter.setAttribute('aria-hidden', 'true'); | ||
@@ -903,2 +949,3 @@ } else { | ||
BROWSER_WINDOW.requestAnimationFrame(() => { | ||
setImageDimension(groups[activeGroup].sliderElements[currentIndex], groups[activeGroup].images[currentIndex]); | ||
updateOffset(); | ||
@@ -910,2 +957,25 @@ resizeTicking = false; | ||
/** | ||
* Set image with | ||
* | ||
* @param {HTMLElement} slideEl | ||
* @param {HTMLElement} imageEl | ||
*/ | ||
const setImageDimension = function setImageDimension(slideEl, imageEl) { | ||
const computedStyle = getComputedStyle(slideEl); | ||
const captionRec = slideEl.querySelector('.parvus__caption').getBoundingClientRect(); | ||
const srcHeight = imageEl.naturalHeight; | ||
const srcWidth = imageEl.naturalWidth; | ||
let maxHeight = slideEl.getBoundingClientRect().height; | ||
let maxWidth = slideEl.getBoundingClientRect().width; | ||
maxHeight -= parseFloat(computedStyle.paddingTop) + parseFloat(computedStyle.paddingBottom) + parseFloat(captionRec.height); | ||
maxWidth -= parseFloat(computedStyle.paddingLeft) + parseFloat(computedStyle.paddingRight); | ||
const ratio = Math.min(maxWidth / srcWidth || 0, maxHeight / srcHeight); | ||
imageEl.style.width = `${srcWidth * ratio || 0}px`; | ||
imageEl.style.height = `${srcHeight * ratio || 0}px`; | ||
console.log(srcWidth * ratio || 0); | ||
console.log(srcHeight * ratio || 0); | ||
}; | ||
/** | ||
* Click event handler to trigger Parvus | ||
@@ -1018,4 +1088,4 @@ * | ||
drag.startY = event.pageY; | ||
GROUPS[activeGroup].slider.classList.add('parvus__slider--is-dragging'); | ||
GROUPS[activeGroup].slider.style.willChange = 'transform'; | ||
groups[activeGroup].slider.classList.add('parvus__slider--is-dragging'); | ||
groups[activeGroup].slider.style.willChange = 'transform'; | ||
}; | ||
@@ -1046,4 +1116,4 @@ /** | ||
pointerDown = false; | ||
GROUPS[activeGroup].slider.classList.remove('parvus__slider--is-dragging'); | ||
GROUPS[activeGroup].slider.style.willChange = 'auto'; | ||
groups[activeGroup].slider.classList.remove('parvus__slider--is-dragging'); | ||
groups[activeGroup].slider.style.willChange = 'auto'; | ||
@@ -1069,4 +1139,4 @@ if (drag.endX || drag.endY) { | ||
drag.startY = event.touches[0].pageY; | ||
GROUPS[activeGroup].slider.classList.add('parvus__slider--is-dragging'); | ||
GROUPS[activeGroup].slider.style.willChange = 'transform'; | ||
groups[activeGroup].slider.classList.add('parvus__slider--is-dragging'); | ||
groups[activeGroup].slider.style.willChange = 'transform'; | ||
}; | ||
@@ -1098,4 +1168,4 @@ /** | ||
pointerDown = false; | ||
GROUPS[activeGroup].slider.classList.remove('parvus__slider--is-dragging'); | ||
GROUPS[activeGroup].slider.style.willChange = 'auto'; | ||
groups[activeGroup].slider.classList.remove('parvus__slider--is-dragging'); | ||
groups[activeGroup].slider.style.willChange = 'auto'; | ||
@@ -1119,5 +1189,5 @@ if (drag.endX || drag.endY) { | ||
if (Math.abs(MOVEMENT_X) > 0 && !isDraggingY && GROUPS[activeGroup].gallery.length > 1) { | ||
if (Math.abs(MOVEMENT_X) > 0 && !isDraggingY && groups[activeGroup].gallery.length > 1) { | ||
// Horizontal swipe | ||
GROUPS[activeGroup].slider.style.transform = `translate3d(${offsetTmp - Math.round(MOVEMENT_X)}px, 0, 0)`; | ||
groups[activeGroup].slider.style.transform = `translate3d(${offsetTmp - Math.round(MOVEMENT_X)}px, 0, 0)`; | ||
isDraggingX = true; | ||
@@ -1134,3 +1204,3 @@ isDraggingY = false; | ||
lightboxOverlay.style.opacity = lightboxOverlayOpacity; | ||
GROUPS[activeGroup].slider.style.transform = `translate3d(${offsetTmp}px, ${Math.round(MOVEMENT_Y)}px, 0)`; | ||
groups[activeGroup].slider.style.transform = `translate3d(${offsetTmp}px, ${Math.round(MOVEMENT_Y)}px, 0)`; | ||
isDraggingX = false; | ||
@@ -1255,5 +1325,5 @@ isDraggingY = true; | ||
* Bind event | ||
* | ||
* @param {String} eventName | ||
* @param {function} callback - callback to call | ||
* | ||
* @param {Function} callback | ||
*/ | ||
@@ -1269,5 +1339,5 @@ | ||
* Unbind event | ||
* | ||
* @param {String} eventName | ||
* @param {function} callback - callback to call | ||
* | ||
* @param {Function} callback | ||
*/ | ||
@@ -1274,0 +1344,0 @@ |
@@ -5,3 +5,3 @@ /** | ||
* @author Benjamin de Oostfrees | ||
* @version 1.4.3 | ||
* @version 2.0.0 | ||
* @url https://github.com/deoostfrees/parvus | ||
@@ -12,2 +12,2 @@ * | ||
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e="undefined"!=typeof globalThis?globalThis:e||self).Parvus=t()}(this,(function(){"use strict";return function e(t){const n=window,i=["button:not([disabled]):not([inert])",'[tabindex]:not([tabindex^="-"]):not([inert])'],s={gallery:[],slider:null,sliderElements:[]},r={};let a=null,o=null,l=0,d={},u=null,c=null,p=1,g=null,h=null,m=null,f=null,v=0,b=0,y=0,w=0,E={},L=!1,A=!1,_=!1,x=null,C=null,$=null,T=!1,B=null,S=!0;const M=window.matchMedia("(prefers-reduced-motion)"),I=function(){M.matches?(S=!0,B=d.reducedTransitionDuration):(S=!1,B=d.transitionDuration)};M.addEventListener("change",I);const q=function(e){d=function(e){return{selector:".lightbox",gallerySelector:null,docClose:!0,scrollClose:!1,swipeClose:!0,threshold:50,backFocus:!0,transitionDuration:300,reducedTransitionDuration:.1,transitionTimingFunction:"cubic-bezier(0.4, 0, 0.22, 1)",lightboxIndicatorIcon:'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="M8 3H5a2 2 0 00-2 2v3m18 0V5a2 2 0 00-2-2h-3m0 18h3a2 2 0 002-2v-3M3 16v3a2 2 0 002 2h3"/></svg>',previousButtonIcon:'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path stroke="none" d="M0 0h24v24H0z"/><polyline points="15 6 9 12 15 18" /></svg>',nextButtonIcon:'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path stroke="none" d="M0 0h24v24H0z"/><polyline points="9 6 15 12 9 18" /></svg>',closeButtonIcon:'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="M18 6L6 18M6 6l12 12"/></svg>',lang:"en",i18n:{en:{lightboxLabel:"This is a dialog window which overlays the main content of the page. The modal shows the enlarged image. Pressing the Escape key will close the modal and bring you back to where you were on the page.",lightboxLoadingIndicatorLabel:"Image loading",previousButtonLabel:"Previous image",nextButtonLabel:"Next image",closeButtonLabel:"Close dialog window"}},fileTypes:/\.(png|jpe?g|webp|avif|svg)(\?.*)?$/i,...e}}(e);if(document.querySelectorAll(d.selector).length)if(I(),u||F(),null!==d.gallerySelector){document.querySelectorAll(d.gallerySelector).forEach(((e,t)=>{const n=t;e.querySelectorAll(d.selector).forEach((e=>{e.setAttribute("data-group",`parvus-gallery-${n}`),Y(e)}))}));document.querySelectorAll(`${d.selector}:not(.parvus-trigger)`).forEach((e=>{Y(e)}))}else{document.querySelectorAll(d.selector).forEach((e=>{Y(e)}))}},X=function(e){const t=Math.floor(1e4*Math.random());return e.hasAttribute("data-group")&&""!==e.getAttribute("data-group")||e.setAttribute("data-group",`default-${t}`),e.getAttribute("data-group")},Y=function(e){if(!("A"===e.tagName&&e.hasAttribute("href")&&e.href.match(d.fileTypes)||"BUTTON"===e.tagName&&e.hasAttribute("data-target")&&e.getAttribute("data-target").match(d.fileTypes)))throw new Error(e,`Use a link with the 'href' attribute or a button with the 'data-target' attribute. Both attributes must have a path to the image file. Supported image file types: ${d.fileTypes}.`);var t;if(a=X(e),Object.prototype.hasOwnProperty.call(r,a)||(r[a]=(t=s,JSON.parse(JSON.stringify(t)))),r[a].gallery.includes(e))throw new Error("Ups, element already added.");if(r[a].gallery.push(e),null!==e.querySelector("img")){const t=document.createElement("div");e.classList.add("parvus-zoom"),t.className="parvus-zoom__indicator",t.innerHTML=d.lightboxIndicatorIcon,e.appendChild(t)}e.classList.add("parvus-trigger"),e.addEventListener("click",ne),ve()&&a===o&&(N(e,r[a].gallery.indexOf(e)),U(r[a].gallery.indexOf(e)),ee(),V(),G())},k=function(e){if(ve()||!u||!e||!e.hasAttribute("data-group"))return;const t=X(e);if(!r[t].gallery.includes(e))throw new Error("Ups, I can't find the element.");if(r[t].gallery.splice(r[t].gallery.indexOf(e),1),e.classList.contains("parvus-zoom")){const t=e.querySelector(".parvus-zoom__indicator");e.classList.remove("parvus-zoom"),e.removeChild(t)}e.removeEventListener("click",ne),e.classList.remove("parvus-trigger")},F=function(){u=document.createElement("div"),u.setAttribute("role","dialog"),u.setAttribute("aria-modal","true"),u.setAttribute("aria-hidden","true"),u.setAttribute("tabindex","-1"),u.setAttribute("aria-label",d.i18n[d.lang].lightboxLabel),u.classList.add("parvus"),c=document.createElement("div"),c.classList.add("parvus__overlay"),c.style.opacity=0,u.appendChild(c),m=document.createElement("button"),m.className="parvus__btn parvus__btn--close",m.setAttribute("type","button"),m.setAttribute("aria-label",d.i18n[d.lang].closeButtonLabel),m.innerHTML=d.closeButtonIcon,u.appendChild(m),g=document.createElement("button"),g.className="parvus__btn parvus__btn--previous",g.setAttribute("type","button"),g.setAttribute("aria-label",d.i18n[d.lang].previousButtonLabel),g.innerHTML=d.previousButtonIcon,u.appendChild(g),h=document.createElement("button"),h.className="parvus__btn parvus__btn--next",h.setAttribute("type","button"),h.setAttribute("aria-label",d.i18n[d.lang].nextButtonLabel),h.innerHTML=d.nextButtonIcon,u.appendChild(h),f=document.createElement("div"),f.className="parvus__counter",u.appendChild(f),document.body.appendChild(u)},N=function(e,t){const n=document.createElement("div"),i=document.createElement("div");n.className="parvus__slide",n.style.position="absolute",n.style.left=100*t+"%",n.setAttribute("aria-hidden","true"),P(e,i),n.appendChild(i),r[o].sliderElements[t]=n,t===l&&r[o].slider.appendChild(n),t>l?r[o].sliderElements[l].after(n):r[o].sliderElements[l].before(n)},D=function(e){if(!u||!e||!e.classList.contains("parvus-trigger")||ve())return;if(o=X(e),!r[o].gallery.includes(e))throw new Error("Ups, I can't find the element.");l=r[o].gallery.indexOf(e),x=document.activeElement;const t=window.location.href;history.pushState({parvus:"close"},"Image",t),me();document.querySelectorAll('body > *:not([aria-hidden="true"])').forEach((e=>{e.setAttribute("aria-hidden","true"),e.classList.add("parvus-hidden")})),u.classList.add("parvus--is-opening"),u.setAttribute("aria-hidden","false"),r[o].slider=document.createElement("div"),r[o].slider.className="parvus__slider",r[o].slider.setAttribute("aria-hidden","true"),u.appendChild(r[o].slider),N(e,l),r[o].slider.setAttribute("aria-hidden","false"),K(),ee(),G(),re(),H(l),U(l),requestAnimationFrame((()=>{u.classList.remove("parvus--is-opening"),c.style.opacity=1,c.style.transition=`opacity ${B}ms ${d.transitionTimingFunction}`,c.style.willChange="opacity"})),c.addEventListener("transitionend",(()=>{z(l+1),z(l-1)})),r[o].slider.classList.add("parvus__slider--animate");const n=new CustomEvent("open",{detail:{source:e}});u.dispatchEvent(n)},O=function(){if(!ve())throw new Error("Ups, I'm already closed.");const e=r[o].sliderElements[l].querySelector("img"),t=e.getBoundingClientRect(),n=(d.backFocus?r[o].gallery[l]:x).getBoundingClientRect();fe(),Q(),null!==history.state&&"close"===history.state.parvus&&history.back();document.querySelectorAll(".parvus-hidden").forEach((e=>{e.removeAttribute("aria-hidden"),e.classList.remove("parvus-hidden")})),u.classList.add("parvus--is-closing"),requestAnimationFrame((()=>{v=n.width/t.width,b=n.height/t.height,y=n.left-t.left,w=n.top-t.top,e.style.transform=`translate(${y}px, ${w}px) scale(${v}, ${b})`,e.style.opacity=0,e.style.transition=`transform ${B}ms ${d.transitionTimingFunction}, opacity ${B}ms ${d.transitionTimingFunction} ${B/2}ms`,c.style.opacity=0,c.style.transition=`opacity ${B}ms ${d.transitionTimingFunction}`,c.style.willChange="auto"})),c.addEventListener("transitionend",(()=>{J(l),x=d.backFocus?r[o].gallery[l]:x,x.focus({preventScroll:!0}),u.setAttribute("aria-hidden","true"),u.classList.remove("parvus--is-closing"),u.classList.remove("parvus--is-vertical-closing"),r[o].slider.remove(),e.style.transform=""}),{once:!0});const i=new CustomEvent("close",{detail:{source:r[o].gallery[l]}});u.dispatchEvent(i)},z=function(e){void 0!==r[o].gallery[e]&&(N(r[o].gallery[e],e),U(e))},H=function(e){r[o].sliderElements[e].classList.add("parvus__slide--is-active"),r[o].sliderElements[e].setAttribute("aria-hidden","false")},P=function(e,t){const n=document.createElement("img"),i=document.createElement("figure"),s=document.createElement("figcaption"),r=e.querySelector("img"),a=document.createElement("div");a.className="parvus__loader",a.setAttribute("role","progressbar"),a.setAttribute("aria-label",d.i18n[d.lang].lightboxLoadingIndicatorLabel),t.appendChild(a),n.onload=()=>{t.removeChild(a),n.setAttribute("width",n.naturalWidth),n.setAttribute("height",n.naturalHeight)},"A"===e.tagName?(n.setAttribute("src",e.href),n.alt=r?r.alt||"":e.getAttribute("data-alt")||""):(n.alt=e.getAttribute("data-alt")||"",n.setAttribute("src",e.getAttribute("data-target"))),e.hasAttribute("data-srcset")&&""!==e.getAttribute("data-srcset")&&n.setAttribute("srcset",e.getAttribute("data-srcset")),n.style.opacity=0,i.appendChild(n),e.hasAttribute("data-caption")&&""!==e.getAttribute("data-caption")&&(s.innerHTML=e.getAttribute("data-caption"),i.appendChild(s)),t.appendChild(i)},U=function(e){const t=r[o].sliderElements[e].querySelector("img"),n=t.getBoundingClientRect(),i=r[o].gallery[e].getBoundingClientRect();u.classList.contains("parvus--is-opening")?(v=i.width/n.width,b=i.height/n.height,y=i.left-n.left,w=i.top-n.top,requestAnimationFrame((()=>{t.style.transform=`translate(${y}px, ${w}px) scale(${v}, ${b})`,t.style.transition="transform 0s, opacity 0s",requestAnimationFrame((()=>{t.style.transform="",t.style.opacity=1,t.style.transition=`transform ${B}ms ${d.transitionTimingFunction}, opacity ${B/2}ms ${d.transitionTimingFunction}`}))}))):t.style.opacity=1},R=function(e){const t=l;if(!ve())throw new Error("Ups, I'm closed.");if(!e&&0!==e)throw new Error("Ups, no slide specified.");if(e===l)throw new Error(`Ups, slide ${e} is already selected.`);if(-1===e||e>=r[o].gallery.length)throw new Error(`Ups, I can't find slide ${e}.`);J(t),H(e),U(e),e<t&&(l--,K(),ee(),V("left"),z(e-1)),e>t&&(l++,K(),ee(),V("right"),z(e+1)),G();const n=new CustomEvent("select",{detail:{source:r[o].gallery[l]}});u.dispatchEvent(n)},j=function(){l>0&&R(l-1)},W=function(){l<r[o].gallery.length-1&&R(l+1)},J=function(e){r[o].sliderElements[e].classList.remove("parvus__slide--is-active"),r[o].sliderElements[e].setAttribute("aria-hidden","true")},K=function(){o=null!==o?o:a,C=-l*u.offsetWidth,r[o].slider.style.transform=`translate3d(${C}px, 0, 0)`,$=C},V=function(e){1===r[o].gallery.length?m.focus():0===l?h.focus():l===r[o].gallery.length-1||"left"===e?g.focus():h.focus()},G=function(){f.textContent=`${l+1}/${r[o].gallery.length}`},Q=function(){E={startX:0,endX:0,startY:0,endY:0}},Z=function(){const e=E.endX-E.startX,t=E.endY-E.startY,n=Math.abs(e),i=Math.abs(t);L&&e>0&&n>=d.threshold&&l>0?j():L&&e<0&&n>=d.threshold&&l!==r[o].gallery.length-1?W():A&&i>0?i>=d.threshold&&d.swipeClose?O():(c.style.opacity=1,u.classList.remove("parvus--is-vertical-closing"),K()):K()},ee=function(){(d.swipeClose&&!r[o].slider.classList.contains("parvus__slider--is-draggable")||r[o].gallery.length>1&&!r[o].slider.classList.contains("parvus__slider--is-draggable"))&&r[o].slider.classList.add("parvus__slider--is-draggable"),1===r[o].gallery.length?(g.setAttribute("aria-hidden","true"),g.disabled=!0,h.setAttribute("aria-hidden","true"),h.disabled=!0):0===l?(g.setAttribute("aria-hidden","true"),g.disabled=!0,h.setAttribute("aria-hidden","false"),h.disabled=!1):l===r[o].gallery.length-1?(g.setAttribute("aria-hidden","false"),g.disabled=!1,h.setAttribute("aria-hidden","true"),h.disabled=!0):(g.setAttribute("aria-hidden","false"),g.disabled=!1,h.setAttribute("aria-hidden","false"),h.disabled=!1),1===r[o].gallery.length?f.setAttribute("aria-hidden","true"):f.setAttribute("aria-hidden","false")},te=function(){T||(T=!0,n.requestAnimationFrame((()=>{K(),T=!1})))},ne=function(e){e.preventDefault(),D(this)},ie=function(e){e.target===g?j():e.target===h?W():(e.target===m||!A&&!L&&e.target.classList.contains("parvus__slide")&&d.docClose)&&O(),e.stopPropagation()},se=function(){return Array.prototype.slice.call(u.querySelectorAll(`${i.join(", ")}`)).filter((function(e){return!!(e.offsetWidth||e.offsetHeight||e.getClientRects().length)}))},re=function(){se()[0].focus()},ae=function(e){const t=se(),n=t.indexOf(document.activeElement);"Tab"===e.code?e.shiftKey&&0===n?(t[t.length-1].focus(),e.preventDefault()):e.shiftKey||n!==t.length-1||(t[0].focus(),e.preventDefault()):"Escape"===e.code?(e.preventDefault(),O()):"ArrowLeft"===e.code?(e.preventDefault(),j()):"ArrowRight"===e.code&&(e.preventDefault(),W())},oe=function(){O()},le=function(e){e.preventDefault(),e.stopPropagation(),L=!1,A=!1,_=!0,E.startX=e.pageX,E.startY=e.pageY,r[o].slider.classList.add("parvus__slider--is-dragging"),r[o].slider.style.willChange="transform"},de=function(e){e.preventDefault(),_&&(E.endX=e.pageX,E.endY=e.pageY,he())},ue=function(e){e.stopPropagation(),_=!1,r[o].slider.classList.remove("parvus__slider--is-dragging"),r[o].slider.style.willChange="auto",(E.endX||E.endY)&&Z(),Q()},ce=function(e){e.stopPropagation(),L=!1,A=!1,_=!0,E.startX=e.touches[0].pageX,E.startY=e.touches[0].pageY,r[o].slider.classList.add("parvus__slider--is-dragging"),r[o].slider.style.willChange="transform"},pe=function(e){e.stopPropagation(),_&&(e.preventDefault(),E.endX=e.touches[0].pageX,E.endY=e.touches[0].pageY,he())},ge=function(e){e.stopPropagation(),_=!1,r[o].slider.classList.remove("parvus__slider--is-dragging"),r[o].slider.style.willChange="auto",(E.endX||E.endY)&&Z(),Q()},he=function(){const e=E.startX-E.endX,t=E.endY-E.startY,n=Math.abs(t);Math.abs(e)>0&&!A&&r[o].gallery.length>1?(r[o].slider.style.transform=`translate3d(${$-Math.round(e)}px, 0, 0)`,L=!0,A=!1):Math.abs(t)>0&&!L&&d.swipeClose&&(n<=96&&!S&&(p=1-n/100),u.classList.add("parvus--is-vertical-closing"),c.style.opacity=p,r[o].slider.style.transform=`translate3d(${$}px, ${Math.round(t)}px, 0)`,L=!1,A=!0)},me=function(){n.addEventListener("keydown",ae),n.addEventListener("resize",te),d.scrollClose&&n.addEventListener("wheel",oe),n.addEventListener("popstate",O),u.addEventListener("click",ie),be()&&(u.addEventListener("touchstart",ce),u.addEventListener("touchmove",pe),u.addEventListener("touchend",ge)),u.addEventListener("mousedown",le),u.addEventListener("mouseup",ue),u.addEventListener("mousemove",de)},fe=function(){n.removeEventListener("keydown",ae),n.removeEventListener("resize",te),d.scrollClose&&n.removeEventListener("wheel",oe),n.removeEventListener("popstate",O),u.removeEventListener("click",ie),be()&&(u.removeEventListener("touchstart",ce),u.removeEventListener("touchmove",pe),u.removeEventListener("touchend",ge)),u.removeEventListener("mousedown",le),u.removeEventListener("mouseup",ue),u.removeEventListener("mousemove",de)},ve=function(){return"false"===u.getAttribute("aria-hidden")},be=function(){return"ontouchstart"in window};return q(t),e.init=q,e.open=D,e.close=O,e.select=R,e.previous=j,e.next=W,e.currentIndex=function(){return l},e.add=Y,e.remove=k,e.destroy=function(){if(!u)return;ve()&&O(),u.remove();document.querySelectorAll(".parvus-trigger").forEach((e=>{k(e)}));const e=new CustomEvent("destroy");u.dispatchEvent(e)},e.isOpen=ve,e.on=function(e,t){u&&u.addEventListener(e,t)},e.off=function(e,t){u&&u.removeEventListener(e,t)},e}})); | ||
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e="undefined"!=typeof globalThis?globalThis:e||self).Parvus=t()}(this,(function(){"use strict";var e={lightboxLabel:"This is a dialog window which overlays the main content of the page. The modal shows the enlarged image. Pressing the Escape key will close the modal and bring you back to where you were on the page.",lightboxLoadingIndicatorLabel:"Image loading",previousButtonLabel:"Previous image",nextButtonLabel:"Next image",closeButtonLabel:"Close dialog window"};return function t(n){const i=window,s=["button:not([disabled]):not([inert])",'[tabindex]:not([tabindex^="-"]):not([inert])'],a={gallery:[],slider:null,sliderElements:[],images:[]};let r={},o=null,l=null,d=0,u={},c=null,p=null,g=1,h=null,m=null,v=null,f=null,b=null,y=null,w=null,A=0,E=0,L=0,_=0,C={},x=!1,$=!1,S=!1,T=null,B=null,M=null,q=!1,F=null,I=!0;const N=window.matchMedia("(prefers-reduced-motion)"),X=function(){N.matches?(I=!0,F=u.reducedTransitionDuration):(I=!1,F=u.transitionDuration)};N.addEventListener("change",X);const Y=function(t){u=function(t){return{selector:".lightbox",gallerySelector:null,captions:!0,captionsSelector:"self",captionsAttribute:"data-caption",docClose:!0,scrollClose:!1,swipeClose:!0,threshold:50,backFocus:!0,transitionDuration:300,reducedTransitionDuration:.1,transitionTimingFunction:"cubic-bezier(0.4, 0, 0.22, 1)",lightboxIndicatorIcon:'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="M8 3H5a2 2 0 00-2 2v3m18 0V5a2 2 0 00-2-2h-3m0 18h3a2 2 0 002-2v-3M3 16v3a2 2 0 002 2h3"/></svg>',previousButtonIcon:'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path stroke="none" d="M0 0h24v24H0z"/><polyline points="15 6 9 12 15 18" /></svg>',nextButtonIcon:'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path stroke="none" d="M0 0h24v24H0z"/><polyline points="9 6 15 12 9 18" /></svg>',closeButtonIcon:'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="M18 6L6 18M6 6l12 12"/></svg>',l10n:e,fileTypes:/\.(png|jpe?g|webp|avif|svg)(\?.*)?$/i,...t}}(t);if(document.querySelectorAll(u.selector).length)if(X(),c||O(),null!==u.gallerySelector){document.querySelectorAll(u.gallerySelector).forEach(((e,t)=>{const n=t;e.querySelectorAll(u.selector).forEach((e=>{e.setAttribute("data-group",`parvus-gallery-${n}`),D(e)}))}));document.querySelectorAll(`${u.selector}:not(.parvus-trigger)`).forEach((e=>{D(e)}))}else{document.querySelectorAll(u.selector).forEach((e=>{D(e)}))}},k=function(e){const t=Math.floor(1e4*Math.random());return e.hasAttribute("data-group")&&""!==e.getAttribute("data-group")||e.setAttribute("data-group",`default-${t}`),e.getAttribute("data-group")},D=function(e){if(!("A"===e.tagName&&e.hasAttribute("href")&&e.href.match(u.fileTypes)||"BUTTON"===e.tagName&&e.hasAttribute("data-target")&&e.getAttribute("data-target").match(u.fileTypes)))throw new Error(e,`Use a link with the 'href' attribute or a button with the 'data-target' attribute. Both attributes must have a path to the image file. Supported image file types: ${u.fileTypes}.`);var t;if(o=k(e),Object.prototype.hasOwnProperty.call(r,o)||(r[o]=(t=a,JSON.parse(JSON.stringify(t)))),r[o].gallery.includes(e))throw new Error("Ups, element already added.");if(r[o].gallery.push(e),null!==e.querySelector("img")){const t=document.createElement("div");e.classList.add("parvus-zoom"),t.className="parvus-zoom__indicator",t.innerHTML=u.lightboxIndicatorIcon,e.appendChild(t)}e.classList.add("parvus-trigger"),e.addEventListener("click",oe),Ee()&&o===l&&(z(e,r[o].gallery.indexOf(e)),J(r[o].gallery.indexOf(e)),se(),ee(),te())},H=function(e){if(Ee()||!c||!e||!e.hasAttribute("data-group"))return;const t=k(e);if(!r[t].gallery.includes(e))throw new Error("Ups, I can't find the element.");if(r[t].gallery.splice(r[t].gallery.indexOf(e),1),e.classList.contains("parvus-zoom")){const t=e.querySelector(".parvus-zoom__indicator");e.classList.remove("parvus-zoom"),e.removeChild(t)}e.removeEventListener("click",oe),e.classList.remove("parvus-trigger")},O=function(){c=document.createElement("div"),c.setAttribute("role","dialog"),c.setAttribute("aria-modal","true"),c.setAttribute("aria-hidden","true"),c.setAttribute("tabindex","-1"),c.setAttribute("aria-label",u.l10n.lightboxLabel),c.classList.add("parvus"),p=document.createElement("div"),p.classList.add("parvus__overlay"),p.style.opacity=0,c.appendChild(p),h=document.createElement("div"),h.className="parvus__toolbar",m=document.createElement("div"),v=document.createElement("div"),y=document.createElement("button"),y.className="parvus__btn parvus__btn--close",y.setAttribute("type","button"),y.setAttribute("aria-label",u.l10n.closeButtonLabel),y.innerHTML=u.closeButtonIcon,v.appendChild(y),f=document.createElement("button"),f.className="parvus__btn parvus__btn--previous",f.setAttribute("type","button"),f.setAttribute("aria-label",u.l10n.previousButtonLabel),f.innerHTML=u.previousButtonIcon,c.appendChild(f),b=document.createElement("button"),b.className="parvus__btn parvus__btn--next",b.setAttribute("type","button"),b.setAttribute("aria-label",u.l10n.nextButtonLabel),b.innerHTML=u.nextButtonIcon,c.appendChild(b),w=document.createElement("div"),w.className="parvus__counter",m.appendChild(w),h.appendChild(m),h.appendChild(v),c.appendChild(h),document.body.appendChild(c)},z=function(e,t){const n=document.createElement("div"),i=document.createElement("div");n.className="parvus__slide",n.style.position="absolute",n.style.left=100*t+"%",n.setAttribute("aria-hidden","true"),W(t,e,i),n.appendChild(i),r[l].sliderElements[t]=n,t===d&&r[l].slider.appendChild(n),t>d?r[l].sliderElements[d].after(n):r[l].sliderElements[d].before(n)},P=function(e){if(!c||!e||!e.classList.contains("parvus-trigger")||Ee())return;if(l=k(e),!r[l].gallery.includes(e))throw new Error("Ups, I can't find the element.");d=r[l].gallery.indexOf(e),T=document.activeElement;const t=window.location.href;history.pushState({parvus:"close"},"Image",t),we();document.querySelectorAll('body > *:not([aria-hidden="true"])').forEach((e=>{e.setAttribute("aria-hidden","true"),e.classList.add("parvus-hidden")})),c.classList.add("parvus--is-opening"),c.setAttribute("aria-hidden","false"),r[l].slider=document.createElement("div"),r[l].slider.className="parvus__slider",r[l].slider.setAttribute("aria-hidden","true"),c.appendChild(r[l].slider),z(e,d),r[l].slider.setAttribute("aria-hidden","false"),Z(),se(),te(),ue(),j(d),J(d),requestAnimationFrame((()=>{c.classList.remove("parvus--is-opening"),p.style.opacity=1,p.style.transition=`opacity ${F}ms ${u.transitionTimingFunction}`,p.style.willChange="opacity"})),p.addEventListener("transitionend",(()=>{U(d+1),U(d-1)})),r[l].slider.classList.add("parvus__slider--animate");const n=new CustomEvent("open",{detail:{source:e}});c.dispatchEvent(n)},R=function(){if(!Ee())throw new Error("Ups, I'm already closed.");const e=r[l].images[d],t=e.getBoundingClientRect(),n=(u.backFocus?r[l].gallery[d]:T).getBoundingClientRect();Ae(),ne(),null!==history.state&&"close"===history.state.parvus&&history.back();document.querySelectorAll(".parvus-hidden").forEach((e=>{e.removeAttribute("aria-hidden"),e.classList.remove("parvus-hidden")})),c.classList.add("parvus--is-closing"),requestAnimationFrame((()=>{A=n.width/t.width,E=n.height/t.height,L=n.left-t.left,_=n.top-t.top,e.style.transform=`translate(${L}px, ${_}px) scale(${A}, ${E})`,e.style.opacity=0,e.style.transition=`transform ${F}ms ${u.transitionTimingFunction}, opacity ${F}ms ${u.transitionTimingFunction} ${F/2}ms`,p.style.opacity=0,p.style.transition=`opacity ${F}ms ${u.transitionTimingFunction}`,p.style.willChange="auto"})),p.addEventListener("transitionend",(()=>{Q(d),T=u.backFocus?r[l].gallery[d]:T,T.focus({preventScroll:!0}),c.setAttribute("aria-hidden","true"),c.classList.remove("parvus--is-closing"),c.classList.remove("parvus--is-vertical-closing"),r={},e.style.transform=""}),{once:!0});const i=new CustomEvent("close",{detail:{source:r[l].gallery[d]}});c.dispatchEvent(i)},U=function(e){void 0!==r[l].gallery[e]&&(z(r[l].gallery[e],e),J(e))},j=function(e){r[l].sliderElements[e].classList.add("parvus__slide--is-active"),r[l].sliderElements[e].setAttribute("aria-hidden","false")},W=function(e,t,n){const i=document.createElement("img"),s=document.createElement("div"),a=document.createElement("div"),o=t.querySelector("img"),d=document.createElement("div");if(s.className="parvus__content",a.className="parvus__caption",d.className="parvus__loader",d.setAttribute("role","progressbar"),d.setAttribute("aria-label",u.l10n.lightboxLoadingIndicatorLabel),n.appendChild(d),i.onload=()=>{n.removeChild(d),i.setAttribute("width",i.naturalWidth),i.setAttribute("height",i.naturalHeight)},"A"===t.tagName?(i.setAttribute("src",t.href),i.alt=o?o.alt||"":t.getAttribute("data-alt")||""):(i.alt=t.getAttribute("data-alt")||"",i.setAttribute("src",t.getAttribute("data-target"))),t.hasAttribute("data-srcset")&&""!==t.getAttribute("data-srcset")&&i.setAttribute("srcset",t.getAttribute("data-srcset")),i.style.opacity=0,s.appendChild(i),r[l].images[e]=i,n.appendChild(s),u.captions){let e=null;if("self"===u.captionsSelector)t.hasAttribute(u.captionsAttribute)&&""!==t.getAttribute(u.captionsAttribute)&&(e=t.getAttribute(u.captionsAttribute));else if(null!==t.querySelector(u.captionsSelector)){const n=t.querySelector(u.captionsSelector);e=n.hasAttribute(u.captionsAttribute)&&""!==n.getAttribute(u.captionsAttribute)?n.getAttribute(u.captionsAttribute):n.innerHTML}null!==e&&(a.innerHTML=`<p>${e}</p>`,n.appendChild(a))}},J=function(e){re(r[l].sliderElements[e],r[l].images[e]);const t=r[l].images[e],n=t.getBoundingClientRect(),i=r[l].gallery[e].getBoundingClientRect();c.classList.contains("parvus--is-opening")?(A=i.width/n.width,E=i.height/n.height,L=i.left-n.left,_=i.top-n.top,console.log(i.width),console.log(i.height),console.log(n.width),console.log(n.height),requestAnimationFrame((()=>{t.style.transform=`translate(${L}px, ${_}px) scale(${A}, ${E})`,t.style.transition="transform 0s, opacity 0s",requestAnimationFrame((()=>{t.style.transform="",t.style.opacity=1,t.style.transition=`transform ${F}ms ${u.transitionTimingFunction}, opacity ${F/2}ms ${u.transitionTimingFunction}`}))}))):t.style.opacity=1},K=function(e){const t=d;if(!Ee())throw new Error("Ups, I'm closed.");if(!e&&0!==e)throw new Error("Ups, no slide specified.");if(e===d)throw new Error(`Ups, slide ${e} is already selected.`);if(-1===e||e>=r[l].gallery.length)throw new Error(`Ups, I can't find slide ${e}.`);Q(t),j(e),J(e),e<t&&(d--,Z(),se(),ee("left"),U(e-1)),e>t&&(d++,Z(),se(),ee("right"),U(e+1)),te();const n=new CustomEvent("select",{detail:{source:r[l].gallery[d]}});c.dispatchEvent(n)},V=function(){d>0&&K(d-1)},G=function(){d<r[l].gallery.length-1&&K(d+1)},Q=function(e){r[l].sliderElements[e].classList.remove("parvus__slide--is-active"),r[l].sliderElements[e].setAttribute("aria-hidden","true")},Z=function(){l=null!==l?l:o,B=d*c.offsetWidth*-1,r[l].slider.style.transform=`translate3d(${B}px, 0, 0)`,M=B},ee=function(e){1===r[l].gallery.length?y.focus():0===d?b.focus():d===r[l].gallery.length-1||"left"===e?f.focus():b.focus()},te=function(){w.textContent=`${d+1}/${r[l].gallery.length}`},ne=function(){C={startX:0,endX:0,startY:0,endY:0}},ie=function(){const e=C.endX-C.startX,t=C.endY-C.startY,n=Math.abs(e),i=Math.abs(t);x&&e>0&&n>=u.threshold&&d>0?V():x&&e<0&&n>=u.threshold&&d!==r[l].gallery.length-1?G():$&&i>0?i>=u.threshold&&u.swipeClose?R():(p.style.opacity=1,c.classList.remove("parvus--is-vertical-closing"),Z()):Z()},se=function(){(u.swipeClose&&!r[l].slider.classList.contains("parvus__slider--is-draggable")||r[l].gallery.length>1&&!r[l].slider.classList.contains("parvus__slider--is-draggable"))&&r[l].slider.classList.add("parvus__slider--is-draggable"),1===r[l].gallery.length?(f.setAttribute("aria-hidden","true"),f.disabled=!0,b.setAttribute("aria-hidden","true"),b.disabled=!0):0===d?(f.setAttribute("aria-hidden","true"),f.disabled=!0,b.setAttribute("aria-hidden","false"),b.disabled=!1):d===r[l].gallery.length-1?(f.setAttribute("aria-hidden","false"),f.disabled=!1,b.setAttribute("aria-hidden","true"),b.disabled=!0):(f.setAttribute("aria-hidden","false"),f.disabled=!1,b.setAttribute("aria-hidden","false"),b.disabled=!1),1===r[l].gallery.length?w.setAttribute("aria-hidden","true"):w.setAttribute("aria-hidden","false")},ae=function(){q||(q=!0,i.requestAnimationFrame((()=>{re(r[l].sliderElements[d],r[l].images[d]),Z(),q=!1})))},re=function(e,t){const n=getComputedStyle(e),i=e.querySelector(".parvus__caption").getBoundingClientRect(),s=t.naturalHeight,a=t.naturalWidth;let r=e.getBoundingClientRect().height,o=e.getBoundingClientRect().width;r-=parseFloat(n.paddingTop)+parseFloat(n.paddingBottom)+parseFloat(i.height),o-=parseFloat(n.paddingLeft)+parseFloat(n.paddingRight);const l=Math.min(o/a||0,r/s);t.style.width=`${a*l||0}px`,t.style.height=`${s*l||0}px`,console.log(a*l||0),console.log(s*l||0)},oe=function(e){e.preventDefault(),P(this)},le=function(e){e.target===f?V():e.target===b?G():(e.target===y||!$&&!x&&e.target.classList.contains("parvus__slide")&&u.docClose)&&R(),e.stopPropagation()},de=function(){return Array.prototype.slice.call(c.querySelectorAll(`${s.join(", ")}`)).filter((function(e){return!!(e.offsetWidth||e.offsetHeight||e.getClientRects().length)}))},ue=function(){de()[0].focus()},ce=function(e){const t=de(),n=t.indexOf(document.activeElement);"Tab"===e.code?e.shiftKey&&0===n?(t[t.length-1].focus(),e.preventDefault()):e.shiftKey||n!==t.length-1||(t[0].focus(),e.preventDefault()):"Escape"===e.code?(e.preventDefault(),R()):"ArrowLeft"===e.code?(e.preventDefault(),V()):"ArrowRight"===e.code&&(e.preventDefault(),G())},pe=function(){R()},ge=function(e){e.preventDefault(),e.stopPropagation(),x=!1,$=!1,S=!0,C.startX=e.pageX,C.startY=e.pageY,r[l].slider.classList.add("parvus__slider--is-dragging"),r[l].slider.style.willChange="transform"},he=function(e){e.preventDefault(),S&&(C.endX=e.pageX,C.endY=e.pageY,ye())},me=function(e){e.stopPropagation(),S=!1,r[l].slider.classList.remove("parvus__slider--is-dragging"),r[l].slider.style.willChange="auto",(C.endX||C.endY)&&ie(),ne()},ve=function(e){e.stopPropagation(),x=!1,$=!1,S=!0,C.startX=e.touches[0].pageX,C.startY=e.touches[0].pageY,r[l].slider.classList.add("parvus__slider--is-dragging"),r[l].slider.style.willChange="transform"},fe=function(e){e.stopPropagation(),S&&(e.preventDefault(),C.endX=e.touches[0].pageX,C.endY=e.touches[0].pageY,ye())},be=function(e){e.stopPropagation(),S=!1,r[l].slider.classList.remove("parvus__slider--is-dragging"),r[l].slider.style.willChange="auto",(C.endX||C.endY)&&ie(),ne()},ye=function(){const e=C.startX-C.endX,t=C.endY-C.startY,n=Math.abs(t);Math.abs(e)>0&&!$&&r[l].gallery.length>1?(r[l].slider.style.transform=`translate3d(${M-Math.round(e)}px, 0, 0)`,x=!0,$=!1):Math.abs(t)>0&&!x&&u.swipeClose&&(n<=96&&!I&&(g=1-n/100),c.classList.add("parvus--is-vertical-closing"),p.style.opacity=g,r[l].slider.style.transform=`translate3d(${M}px, ${Math.round(t)}px, 0)`,x=!1,$=!0)},we=function(){i.addEventListener("keydown",ce),i.addEventListener("resize",ae),u.scrollClose&&i.addEventListener("wheel",pe),i.addEventListener("popstate",R),c.addEventListener("click",le),Le()&&(c.addEventListener("touchstart",ve),c.addEventListener("touchmove",fe),c.addEventListener("touchend",be)),c.addEventListener("mousedown",ge),c.addEventListener("mouseup",me),c.addEventListener("mousemove",he)},Ae=function(){i.removeEventListener("keydown",ce),i.removeEventListener("resize",ae),u.scrollClose&&i.removeEventListener("wheel",pe),i.removeEventListener("popstate",R),c.removeEventListener("click",le),Le()&&(c.removeEventListener("touchstart",ve),c.removeEventListener("touchmove",fe),c.removeEventListener("touchend",be)),c.removeEventListener("mousedown",ge),c.removeEventListener("mouseup",me),c.removeEventListener("mousemove",he)},Ee=function(){return"false"===c.getAttribute("aria-hidden")},Le=function(){return"ontouchstart"in window};return Y(n),t.init=Y,t.open=P,t.close=R,t.select=K,t.previous=V,t.next=G,t.currentIndex=function(){return d},t.add=D,t.remove=H,t.destroy=function(){if(!c)return;Ee()&&R(),c.remove();document.querySelectorAll(".parvus-trigger").forEach((e=>{H(e)}));const e=new CustomEvent("destroy");c.dispatchEvent(e)},t.isOpen=Ee,t.on=function(e,t){c&&c.addEventListener(e,t)},t.off=function(e,t){c&&c.removeEventListener(e,t)},t}})); |
{ | ||
"name": "parvus", | ||
"version": "1.4.3", | ||
"version": "2.0.0", | ||
"description": "An accessible, open-source image lightbox with no dependencies.", | ||
@@ -8,16 +8,16 @@ "main": "dist/js/parvus.js", | ||
"devDependencies": { | ||
"@babel/core": "^7.15.5", | ||
"@babel/preset-env": "^7.15.6", | ||
"@babel/core": "^7.16.7", | ||
"@babel/preset-env": "^7.16.8", | ||
"@rollup/plugin-babel": "^5.3.0", | ||
"@rollup/plugin-commonjs": "^20.0.0", | ||
"@rollup/plugin-node-resolve": "^13.0.5", | ||
"core-js": "^3.18.1", | ||
"node-sass": "^6.0.1", | ||
"postcss": "^8.3.8", | ||
"rollup": "^2.57.0", | ||
"rollup-plugin-license": "^2.5.0", | ||
"rollup-plugin-postcss": "^4.0.1", | ||
"@rollup/plugin-commonjs": "^21.0.1", | ||
"@rollup/plugin-node-resolve": "^13.1.3", | ||
"core-js": "^3.20.2", | ||
"node-sass": "^7.0.1", | ||
"postcss": "^8.4.5", | ||
"rollup": "^2.64.0", | ||
"rollup-plugin-license": "^2.6.1", | ||
"rollup-plugin-postcss": "^4.0.2", | ||
"rollup-plugin-terser": "^7.0.2", | ||
"standard": "^16.0.3", | ||
"stylelint": "^13.13.1" | ||
"standard": "^16.0.4", | ||
"stylelint": "^14.2.0" | ||
}, | ||
@@ -64,3 +64,4 @@ "browserslist": [ | ||
}, | ||
"homepage": "https://github.com/deoostfrees/parvus" | ||
"homepage": "https://github.com/deoostfrees/parvus", | ||
"dependencies": {} | ||
} |
101
README.md
# Parvus | ||
Parvus is an accessible, open-source image lightbox with no dependencies. | ||
Overlays sucks, don't use them. But if you must use one, use Parvus. Parvus tries to be an accessible, open-source image lightbox with no dependencies. | ||
@@ -15,5 +15,6 @@  | ||
- [Usage](#usage) | ||
- [Caption](#caption) | ||
- [Captions](#captions) | ||
- [Gallery](#gallery) | ||
- [scrset](#scrset) | ||
- [Localization](#lokalization) | ||
- [Options](#options) | ||
@@ -28,8 +29,11 @@ - [API](#api) | ||
CSS: `dist/css/parvus.min.css` minified, or `dist/css/parvus.css` un-minified | ||
- CSS: | ||
- `dist/css/parvus.min.css` minified, or | ||
- `dist/css/parvus.css` un-minified | ||
- JavaScript: | ||
- `dist/js/parvus.min.js` minified, or | ||
- `dist/js/parvus.js` un-minified | ||
JavaScript: `dist/js/parvus.min.js` minified, or `dist/js/parvus.js` un-minified | ||
Link the `.css` and `.js` files to your HTML file. The HTML code may look like this: | ||
Linking the `.css` and `.js` files to your HTML file. The HTML code may look like this: | ||
```html | ||
@@ -60,3 +64,3 @@ <!DOCTYPE html> | ||
``` | ||
npm install parvus --save | ||
npm install parvus | ||
``` | ||
@@ -76,3 +80,3 @@ | ||
The standard way of using Parvus is a linked thumbnail image with the class `lightbox` to a larger image: | ||
The standard way of using Parvus is a linked thumbnail image with the class `lightbox` to a larger image. | ||
@@ -91,4 +95,6 @@ ```html | ||
### Caption | ||
### Captions | ||
Add a `data-caption` attribute if you want to show a caption under the image. | ||
```html | ||
@@ -100,5 +106,25 @@ <a href="path/to/image.jpg" class="lightbox" data-caption="I'm a caption"> | ||
Instead of `data-caption`, you can also set the option `captionsSelector` to set the captions from the innerHTML of an element. | ||
```html | ||
<a href="path/to/image.jpg" class="lightbox"> | ||
<figure class="figure"> | ||
<img src="path/to/thumbnail.jpg" alt=""> | ||
<figcaption class="figure__caption"> | ||
<p>I'm a caption</p> | ||
</figcaption> | ||
</figure> | ||
</a> | ||
``` | ||
```js | ||
const prvs = new Parvus({ | ||
captionsSelector: '.figure__caption', | ||
}) | ||
``` | ||
### Gallery | ||
If you have a group of related images that you would like to combine into a set, add the `data-group` attribute: | ||
If you have a group of related images that you would like to combine into a set, add a `data-group` attribute: | ||
@@ -121,3 +147,3 @@ ```html | ||
Instead of `data-group`, you can also set the option `gallerySelector` to combine all images with the `selector` class within this selector into a group. | ||
Instead of `data-group`, you can also set the option `gallerySelector` to combine all images with a `selector` class within this selector into a group. | ||
@@ -152,2 +178,12 @@ ```html | ||
### Localization | ||
```js | ||
import de from 'parvus/src/l10n/de.js' | ||
const prvs = new Parvus({ | ||
l10n: de | ||
}) | ||
``` | ||
## Options | ||
@@ -159,15 +195,4 @@ | ||
const prvs = new Parvus({ | ||
lang: 'de', | ||
i18n: { | ||
en: { | ||
lightboxLabel: 'This is a dialog window which overlays the main content of the page. The modal shows the enlarged image. Pressing the Escape key will close the modal and bring you back to where you were on the page.', | ||
lightboxLoadingIndicatorLabel: 'Image loading', | ||
closeButtonLabel: 'Close dialog window' | ||
}, | ||
de: { | ||
lightboxLabel: 'Dies ist ein Dialogfenster, das den Hauptinhalt der Seite überlagert. Das Modal zeigt das vergrößerte Bild. Durch Drücken der Escape-Taste wird das Modal geschlossen und Sie kehren an die Stelle zurück, an der Sie sich auf der Seite befanden.', | ||
lightboxLoadingIndicatorLabel: 'Bild wird geladen', | ||
closeButtonLabel: 'Dialogfenster schließen' | ||
} | ||
} | ||
// Click outside to close Parvus | ||
docClose: false | ||
}) | ||
@@ -186,2 +211,11 @@ ``` | ||
// Display captions, if available | ||
captions: true, | ||
// Set the element where the caption is. Set it to "self" for the `a` tag itself | ||
captionsSelector: 'self', | ||
// Get the caption from given attribute | ||
captionsAttribute: 'data-caption', | ||
// Click outside to close Parvus | ||
@@ -193,3 +227,3 @@ docClose: true, | ||
// Swipe up to close Parvus | ||
// Swipe up/ down to close Parvus | ||
swipeClose: true, | ||
@@ -200,3 +234,3 @@ | ||
// Focus thumbnail from the last active slide after closing instead focus last active element before opening | ||
// Set focus back to trigger element after closing Parvus | ||
backFocus: true, | ||
@@ -216,13 +250,4 @@ | ||
// Internationalization | ||
lang: 'en', | ||
i18n: { | ||
en: { | ||
lightboxLabel: 'This is a dialog window which overlays the main content of the page. The modal shows the enlarged image. Pressing the Escape key will close the modal and bring you back to where you were on the page.', | ||
lightboxLoadingIndicatorLabel: 'Image loading', | ||
previousButtonLabel: 'Previous image', | ||
nextButtonLabel: 'Next image', | ||
closeButtonLabel: 'Close dialog window' | ||
} | ||
}, | ||
// Localization of strings | ||
l10n: en, | ||
@@ -290,3 +315,1 @@ // Regular expression for supported image file types | ||
- Safari | ||
Use the [`:focus-visible` polyfill](https://github.com/WICG/focus-visible) to support Safari and other Browsers. |
@@ -0,1 +1,4 @@ | ||
// Default language | ||
import en from '../l10n/en.js' | ||
export default function Parvus (userOptions) { | ||
@@ -14,5 +17,6 @@ /** | ||
slider: null, | ||
sliderElements: [] | ||
sliderElements: [], | ||
images: [] | ||
} | ||
const GROUPS = {} | ||
let groups = {} | ||
let newGroup = null | ||
@@ -25,2 +29,5 @@ let activeGroup = null | ||
let lightboxOverlayOpacity = 1 | ||
let toolbar = null | ||
let toolbarLeft = null | ||
let toolbarRight = null | ||
let previousButton = null | ||
@@ -48,4 +55,4 @@ let nextButton = null | ||
* | ||
* @param {Object} userOptions - Optional user options | ||
* @returns {Object} - Custom options | ||
* @param {Object} userOptions | ||
* @returns {Object} | ||
*/ | ||
@@ -57,2 +64,5 @@ const mergeOptions = function mergeOptions (userOptions) { | ||
gallerySelector: null, | ||
captions: true, | ||
captionsSelector: 'self', | ||
captionsAttribute: 'data-caption', | ||
docClose: true, | ||
@@ -70,12 +80,3 @@ scrollClose: false, | ||
closeButtonIcon: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="M18 6L6 18M6 6l12 12"/></svg>', | ||
lang: 'en', | ||
i18n: { | ||
en: { | ||
lightboxLabel: 'This is a dialog window which overlays the main content of the page. The modal shows the enlarged image. Pressing the Escape key will close the modal and bring you back to where you were on the page.', | ||
lightboxLoadingIndicatorLabel: 'Image loading', | ||
previousButtonLabel: 'Previous image', | ||
nextButtonLabel: 'Next image', | ||
closeButtonLabel: 'Close dialog window' | ||
} | ||
}, | ||
l10n: en, | ||
fileTypes: /\.(png|jpe?g|webp|avif|svg)(\?.*)?$/i | ||
@@ -170,3 +171,3 @@ } | ||
* @param {HTMLElement} el | ||
* @return {string} | ||
* @return {String} | ||
*/ | ||
@@ -186,4 +187,4 @@ const getGroup = function getGroup (el) { | ||
* | ||
* @param {object} object | ||
* @return {object} | ||
* @param {Object} object | ||
* @return {Object} | ||
*/ | ||
@@ -197,3 +198,3 @@ const copyObject = function copyObject (object) { | ||
* | ||
* @param {HTMLElement} el - Element to add | ||
* @param {HTMLElement} el | ||
*/ | ||
@@ -207,9 +208,9 @@ const add = function add (el) { | ||
if (!Object.prototype.hasOwnProperty.call(GROUPS, newGroup)) { | ||
GROUPS[newGroup] = copyObject(GROUP_ATTS) | ||
if (!Object.prototype.hasOwnProperty.call(groups, newGroup)) { | ||
groups[newGroup] = copyObject(GROUP_ATTS) | ||
} | ||
// Check if element already exists | ||
if (!GROUPS[newGroup].gallery.includes(el)) { | ||
GROUPS[newGroup].gallery.push(el) | ||
if (!groups[newGroup].gallery.includes(el)) { | ||
groups[newGroup].gallery.push(el) | ||
@@ -233,4 +234,4 @@ if (el.querySelector('img') !== null) { | ||
if (isOpen() && newGroup === activeGroup) { | ||
createSlide(el, GROUPS[newGroup].gallery.indexOf(el)) | ||
loadImage(GROUPS[newGroup].gallery.indexOf(el)) | ||
createSlide(el, groups[newGroup].gallery.indexOf(el)) | ||
loadImage(groups[newGroup].gallery.indexOf(el)) | ||
updateConfig() | ||
@@ -248,3 +249,3 @@ updateFocus() | ||
* | ||
* @param {HTMLElement} el - Element to remove | ||
* @param {HTMLElement} el | ||
*/ | ||
@@ -259,3 +260,3 @@ const remove = function remove (el) { | ||
// Check if element exists | ||
if (!GROUPS[GROUP].gallery.includes(el)) { | ||
if (!groups[GROUP].gallery.includes(el)) { | ||
throw new Error('Ups, I can\'t find the element.') | ||
@@ -266,3 +267,3 @@ } | ||
GROUPS[GROUP].gallery.splice(GROUPS[GROUP].gallery.indexOf(el), 1) | ||
groups[GROUP].gallery.splice(groups[GROUP].gallery.indexOf(el), 1) | ||
@@ -294,3 +295,3 @@ // Remove lightbox indicator icon if necessary | ||
lightbox.setAttribute('tabindex', '-1') | ||
lightbox.setAttribute('aria-label', config.i18n[config.lang].lightboxLabel) | ||
lightbox.setAttribute('aria-label', config.l10n.lightboxLabel) | ||
lightbox.classList.add('parvus') | ||
@@ -307,2 +308,10 @@ | ||
// Create the toolbar | ||
toolbar = document.createElement('div') | ||
toolbar.className = 'parvus__toolbar' | ||
toolbarLeft = document.createElement('div') | ||
toolbarRight = document.createElement('div') | ||
// Create the close button | ||
@@ -312,7 +321,7 @@ closeButton = document.createElement('button') | ||
closeButton.setAttribute('type', 'button') | ||
closeButton.setAttribute('aria-label', config.i18n[config.lang].closeButtonLabel) | ||
closeButton.setAttribute('aria-label', config.l10n.closeButtonLabel) | ||
closeButton.innerHTML = config.closeButtonIcon | ||
// Add close button to lightbox container | ||
lightbox.appendChild(closeButton) | ||
// Add close button to right toolbar item | ||
toolbarRight.appendChild(closeButton) | ||
@@ -323,3 +332,3 @@ // Create the previous button | ||
previousButton.setAttribute('type', 'button') | ||
previousButton.setAttribute('aria-label', config.i18n[config.lang].previousButtonLabel) | ||
previousButton.setAttribute('aria-label', config.l10n.previousButtonLabel) | ||
previousButton.innerHTML = config.previousButtonIcon | ||
@@ -334,3 +343,3 @@ | ||
nextButton.setAttribute('type', 'button') | ||
nextButton.setAttribute('aria-label', config.i18n[config.lang].nextButtonLabel) | ||
nextButton.setAttribute('aria-label', config.l10n.nextButtonLabel) | ||
nextButton.innerHTML = config.nextButtonIcon | ||
@@ -345,5 +354,12 @@ | ||
// Add counter to lightbox container | ||
lightbox.appendChild(counter) | ||
// Add counter to left toolbar item | ||
toolbarLeft.appendChild(counter) | ||
// Add toolbar items to toolbar | ||
toolbar.appendChild(toolbarLeft) | ||
toolbar.appendChild(toolbarRight) | ||
// Add toolbar to lightbox container | ||
lightbox.appendChild(toolbar) | ||
// Add lightbox container to body | ||
@@ -358,9 +374,9 @@ document.body.appendChild(lightbox) | ||
const createSlider = function createSlider () { | ||
GROUPS[activeGroup].slider = document.createElement('div') | ||
GROUPS[activeGroup].slider.className = 'parvus__slider' | ||
groups[activeGroup].slider = document.createElement('div') | ||
groups[activeGroup].slider.className = 'parvus__slider' | ||
// Hide slider | ||
GROUPS[activeGroup].slider.setAttribute('aria-hidden', 'true') | ||
groups[activeGroup].slider.setAttribute('aria-hidden', 'true') | ||
lightbox.appendChild(GROUPS[activeGroup].slider) | ||
lightbox.appendChild(groups[activeGroup].slider) | ||
} | ||
@@ -371,2 +387,4 @@ | ||
* | ||
* @param {HTMLElement} el | ||
* @param {Number} index | ||
*/ | ||
@@ -384,3 +402,3 @@ const createSlide = function createSlide (el, index) { | ||
createImage(el, SLIDER_ELEMENT_CONTENT) | ||
createImage(index, el, SLIDER_ELEMENT_CONTENT) | ||
@@ -390,13 +408,13 @@ // Add slide content container to slider element | ||
GROUPS[activeGroup].sliderElements[index] = SLIDER_ELEMENT | ||
groups[activeGroup].sliderElements[index] = SLIDER_ELEMENT | ||
// Add slider element to slider | ||
if (index === currentIndex) { | ||
GROUPS[activeGroup].slider.appendChild(SLIDER_ELEMENT) | ||
groups[activeGroup].slider.appendChild(SLIDER_ELEMENT) | ||
} | ||
if (index > currentIndex) { | ||
GROUPS[activeGroup].sliderElements[currentIndex].after(SLIDER_ELEMENT) | ||
groups[activeGroup].sliderElements[currentIndex].after(SLIDER_ELEMENT) | ||
} else { | ||
GROUPS[activeGroup].sliderElements[currentIndex].before(SLIDER_ELEMENT) | ||
groups[activeGroup].sliderElements[currentIndex].before(SLIDER_ELEMENT) | ||
} | ||
@@ -408,3 +426,3 @@ } | ||
* | ||
* @param {number} index - Index to load | ||
* @param {HTMLElement} el | ||
*/ | ||
@@ -419,7 +437,7 @@ const open = function open (el) { | ||
// Check if element exists | ||
if (!GROUPS[activeGroup].gallery.includes(el)) { | ||
if (!groups[activeGroup].gallery.includes(el)) { | ||
throw new Error('Ups, I can\'t find the element.') | ||
} | ||
currentIndex = GROUPS[activeGroup].gallery.indexOf(el) | ||
currentIndex = groups[activeGroup].gallery.indexOf(el) | ||
@@ -458,3 +476,3 @@ // Save user’s focus | ||
// Show slider | ||
GROUPS[activeGroup].slider.setAttribute('aria-hidden', 'false') | ||
groups[activeGroup].slider.setAttribute('aria-hidden', 'false') | ||
@@ -485,3 +503,3 @@ updateOffset() | ||
// Add class for slider animation | ||
GROUPS[activeGroup].slider.classList.add('parvus__slider--animate') | ||
groups[activeGroup].slider.classList.add('parvus__slider--animate') | ||
@@ -507,6 +525,5 @@ // Create and dispatch a new event | ||
const IMAGE_CONTAINER = GROUPS[activeGroup].sliderElements[currentIndex] | ||
const IMAGE = IMAGE_CONTAINER.querySelector('img') | ||
const IMAGE = groups[activeGroup].images[currentIndex] | ||
const IMAGE_SIZE = IMAGE.getBoundingClientRect() | ||
const THUMBNAIL = config.backFocus ? GROUPS[activeGroup].gallery[currentIndex] : lastFocus | ||
const THUMBNAIL = config.backFocus ? groups[activeGroup].gallery[currentIndex] : lastFocus | ||
const THUMBNAIL_SIZE = THUMBNAIL.getBoundingClientRect() | ||
@@ -555,3 +572,3 @@ | ||
// Reenable the user’s focus | ||
lastFocus = config.backFocus ? GROUPS[activeGroup].gallery[currentIndex] : lastFocus | ||
lastFocus = config.backFocus ? groups[activeGroup].gallery[currentIndex] : lastFocus | ||
@@ -568,4 +585,4 @@ lastFocus.focus({ | ||
// Remove slider | ||
GROUPS[activeGroup].slider.remove() | ||
// Reset groups | ||
groups = {} | ||
@@ -581,3 +598,3 @@ IMAGE.style.transform = '' | ||
detail: { | ||
source: GROUPS[activeGroup].gallery[currentIndex] | ||
source: groups[activeGroup].gallery[currentIndex] | ||
} | ||
@@ -592,10 +609,10 @@ }) | ||
* | ||
* @param {number} index - Index to preload | ||
* @param {Number} index | ||
*/ | ||
const preload = function preload (index) { | ||
if (GROUPS[activeGroup].gallery[index] === undefined) { | ||
if (groups[activeGroup].gallery[index] === undefined) { | ||
return | ||
} | ||
createSlide(GROUPS[activeGroup].gallery[index], index) | ||
createSlide(groups[activeGroup].gallery[index], index) | ||
loadImage(index) | ||
@@ -607,7 +624,7 @@ } | ||
* | ||
* @param {number} index - Index to load | ||
* @param {Number} index | ||
*/ | ||
const loadSlide = function loadSlide (index) { | ||
GROUPS[activeGroup].sliderElements[index].classList.add('parvus__slide--is-active') | ||
GROUPS[activeGroup].sliderElements[index].setAttribute('aria-hidden', 'false') | ||
groups[activeGroup].sliderElements[index].classList.add('parvus__slide--is-active') | ||
groups[activeGroup].sliderElements[index].setAttribute('aria-hidden', 'false') | ||
} | ||
@@ -618,15 +635,20 @@ | ||
* | ||
* @param {number} index - Index to load | ||
* @param {Number} index | ||
* @param {HTMLElement} el | ||
* @param {HTMLElement} container | ||
*/ | ||
const createImage = function createImage (el, container) { | ||
const createImage = function createImage (index, el, container) { | ||
const IMAGE = document.createElement('img') | ||
const FIGURE = document.createElement('figure') | ||
const FIGCAPTION = document.createElement('figcaption') | ||
const IMAGE_CONTAINER = document.createElement('div') | ||
const CAPTION_CONTAINER = document.createElement('div') | ||
const THUMBNAIL = el.querySelector('img') | ||
const LOADING_INDICATOR = document.createElement('div') | ||
IMAGE_CONTAINER.className = 'parvus__content' | ||
CAPTION_CONTAINER.className = 'parvus__caption' | ||
// Create loading indicator | ||
LOADING_INDICATOR.className = 'parvus__loader' | ||
LOADING_INDICATOR.setAttribute('role', 'progressbar') | ||
LOADING_INDICATOR.setAttribute('aria-label', config.i18n[config.lang].lightboxLoadingIndicatorLabel) | ||
LOADING_INDICATOR.setAttribute('aria-label', config.l10n.lightboxLoadingIndicatorLabel) | ||
@@ -664,12 +686,34 @@ // Add loading indicator to container | ||
FIGURE.appendChild(IMAGE) | ||
IMAGE_CONTAINER.appendChild(IMAGE) | ||
groups[activeGroup].images[index] = IMAGE | ||
container.appendChild(IMAGE_CONTAINER) | ||
// Add caption if available | ||
if (el.hasAttribute('data-caption') && el.getAttribute('data-caption') !== '') { | ||
FIGCAPTION.innerHTML = el.getAttribute('data-caption') | ||
if (config.captions) { | ||
let captionData = null | ||
FIGURE.appendChild(FIGCAPTION) | ||
if (config.captionsSelector === 'self') { | ||
if (el.hasAttribute(config.captionsAttribute) && el.getAttribute(config.captionsAttribute) !== '') { | ||
captionData = el.getAttribute(config.captionsAttribute) | ||
} | ||
} else { | ||
if (el.querySelector(config.captionsSelector) !== null) { | ||
const CAPTION_SELECTOR = el.querySelector(config.captionsSelector) | ||
if (CAPTION_SELECTOR.hasAttribute(config.captionsAttribute) && CAPTION_SELECTOR.getAttribute(config.captionsAttribute) !== '') { | ||
captionData = CAPTION_SELECTOR.getAttribute(config.captionsAttribute) | ||
} else { | ||
captionData = CAPTION_SELECTOR.innerHTML | ||
} | ||
} | ||
} | ||
if (captionData !== null) { | ||
CAPTION_CONTAINER.innerHTML = `<p>${captionData}</p>` | ||
container.appendChild(CAPTION_CONTAINER) | ||
} | ||
} | ||
container.appendChild(FIGURE) | ||
} | ||
@@ -680,9 +724,10 @@ | ||
* | ||
* @param {number} index - Index to load | ||
* @param {Number} index | ||
*/ | ||
const loadImage = function loadImage (index) { | ||
const IMAGE_CONTAINER = GROUPS[activeGroup].sliderElements[index] | ||
const IMAGE = IMAGE_CONTAINER.querySelector('img') | ||
setImageDimension(groups[activeGroup].sliderElements[index], groups[activeGroup].images[index]) | ||
const IMAGE = groups[activeGroup].images[index] | ||
const IMAGE_SIZE = IMAGE.getBoundingClientRect() | ||
const THUMBNAIL = GROUPS[activeGroup].gallery[index] | ||
const THUMBNAIL = groups[activeGroup].gallery[index] | ||
const THUMBNAIL_SIZE = THUMBNAIL.getBoundingClientRect() | ||
@@ -696,2 +741,7 @@ | ||
console.log(THUMBNAIL_SIZE.width) | ||
console.log(THUMBNAIL_SIZE.height) | ||
console.log(IMAGE_SIZE.width) | ||
console.log(IMAGE_SIZE.height) | ||
requestAnimationFrame(() => { | ||
@@ -716,3 +766,3 @@ IMAGE.style.transform = `translate(${xDifference}px, ${yDifference}px) scale(${widthDifference}, ${heightDifference})` | ||
* | ||
* @param {number} index - Index to select | ||
* @param {Number} newIndex | ||
*/ | ||
@@ -733,3 +783,3 @@ const select = function select (newIndex) { | ||
if (newIndex === -1 || newIndex >= GROUPS[activeGroup].gallery.length) { | ||
if (newIndex === -1 || newIndex >= groups[activeGroup].gallery.length) { | ||
throw new Error(`Ups, I can't find slide ${newIndex}.`) | ||
@@ -767,3 +817,3 @@ } | ||
detail: { | ||
source: GROUPS[activeGroup].gallery[currentIndex] | ||
source: groups[activeGroup].gallery[currentIndex] | ||
} | ||
@@ -790,3 +840,3 @@ }) | ||
const next = function next () { | ||
if (currentIndex < GROUPS[activeGroup].gallery.length - 1) { | ||
if (currentIndex < groups[activeGroup].gallery.length - 1) { | ||
select(currentIndex + 1) | ||
@@ -800,7 +850,7 @@ } | ||
* | ||
* @param {number} index - Index to leave | ||
* @param {Number} index | ||
*/ | ||
const leaveSlide = function leaveSlide (index) { | ||
GROUPS[activeGroup].sliderElements[index].classList.remove('parvus__slide--is-active') | ||
GROUPS[activeGroup].sliderElements[index].setAttribute('aria-hidden', 'true') | ||
groups[activeGroup].sliderElements[index].classList.remove('parvus__slide--is-active') | ||
groups[activeGroup].sliderElements[index].setAttribute('aria-hidden', 'true') | ||
} | ||
@@ -815,5 +865,5 @@ | ||
offset = -currentIndex * lightbox.offsetWidth | ||
offset = (currentIndex * lightbox.offsetWidth) * -1 | ||
GROUPS[activeGroup].slider.style.transform = `translate3d(${offset}px, 0, 0)` | ||
groups[activeGroup].slider.style.transform = `translate3d(${offset}px, 0, 0)` | ||
offsetTmp = offset | ||
@@ -825,6 +875,6 @@ } | ||
* | ||
* @param {string} dir - Current slide direction | ||
* @param {String} dir | ||
*/ | ||
const updateFocus = function updateFocus (dir) { | ||
if (GROUPS[activeGroup].gallery.length === 1) { | ||
if (groups[activeGroup].gallery.length === 1) { | ||
closeButton.focus() | ||
@@ -836,3 +886,3 @@ } else { | ||
// If the last slide is displayed | ||
} else if (currentIndex === GROUPS[activeGroup].gallery.length - 1) { | ||
} else if (currentIndex === groups[activeGroup].gallery.length - 1) { | ||
previousButton.focus() | ||
@@ -854,3 +904,3 @@ } else { | ||
const updateCounter = function updateCounter () { | ||
counter.textContent = `${currentIndex + 1}/${GROUPS[activeGroup].gallery.length}` | ||
counter.textContent = `${currentIndex + 1}/${groups[activeGroup].gallery.length}` | ||
} | ||
@@ -883,3 +933,3 @@ | ||
previous() | ||
} else if (isDraggingX && MOVEMENT_X < 0 && MOVEMENT_X_DISTANCE >= config.threshold && currentIndex !== GROUPS[activeGroup].gallery.length - 1) { | ||
} else if (isDraggingX && MOVEMENT_X < 0 && MOVEMENT_X_DISTANCE >= config.threshold && currentIndex !== groups[activeGroup].gallery.length - 1) { | ||
next() | ||
@@ -906,8 +956,8 @@ } else if (isDraggingY && MOVEMENT_Y_DISTANCE > 0) { | ||
const updateConfig = function updateConfig () { | ||
if ((config.swipeClose && !GROUPS[activeGroup].slider.classList.contains('parvus__slider--is-draggable')) || (GROUPS[activeGroup].gallery.length > 1 && !GROUPS[activeGroup].slider.classList.contains('parvus__slider--is-draggable'))) { | ||
GROUPS[activeGroup].slider.classList.add('parvus__slider--is-draggable') | ||
if ((config.swipeClose && !groups[activeGroup].slider.classList.contains('parvus__slider--is-draggable')) || (groups[activeGroup].gallery.length > 1 && !groups[activeGroup].slider.classList.contains('parvus__slider--is-draggable'))) { | ||
groups[activeGroup].slider.classList.add('parvus__slider--is-draggable') | ||
} | ||
// Hide buttons if necessary | ||
if (GROUPS[activeGroup].gallery.length === 1) { | ||
if (groups[activeGroup].gallery.length === 1) { | ||
previousButton.setAttribute('aria-hidden', 'true') | ||
@@ -925,3 +975,3 @@ previousButton.disabled = true | ||
// If the last slide is displayed | ||
} else if (currentIndex === GROUPS[activeGroup].gallery.length - 1) { | ||
} else if (currentIndex === groups[activeGroup].gallery.length - 1) { | ||
previousButton.setAttribute('aria-hidden', 'false') | ||
@@ -940,3 +990,3 @@ previousButton.disabled = false | ||
// Hide counter if necessary | ||
if (GROUPS[activeGroup].gallery.length === 1) { | ||
if (groups[activeGroup].gallery.length === 1) { | ||
counter.setAttribute('aria-hidden', 'true') | ||
@@ -957,2 +1007,3 @@ } else { | ||
BROWSER_WINDOW.requestAnimationFrame(() => { | ||
setImageDimension(groups[activeGroup].sliderElements[currentIndex], groups[activeGroup].images[currentIndex]) | ||
updateOffset() | ||
@@ -966,2 +1017,29 @@ | ||
/** | ||
* Set image with | ||
* | ||
* @param {HTMLElement} slideEl | ||
* @param {HTMLElement} imageEl | ||
*/ | ||
const setImageDimension = function setImageDimension (slideEl, imageEl) { | ||
const computedStyle = getComputedStyle(slideEl) | ||
const captionRec = slideEl.querySelector('.parvus__caption').getBoundingClientRect() | ||
const srcHeight = imageEl.naturalHeight | ||
const srcWidth = imageEl.naturalWidth | ||
let maxHeight = slideEl.getBoundingClientRect().height | ||
let maxWidth = slideEl.getBoundingClientRect().width | ||
maxHeight -= parseFloat(computedStyle.paddingTop) + parseFloat(computedStyle.paddingBottom) + parseFloat(captionRec.height) | ||
maxWidth -= parseFloat(computedStyle.paddingLeft) + parseFloat(computedStyle.paddingRight) | ||
const ratio = Math.min(maxWidth / srcWidth || 0, maxHeight / srcHeight) | ||
imageEl.style.width = `${srcWidth * ratio || 0}px` | ||
imageEl.style.height = `${srcHeight * ratio || 0}px` | ||
console.log(srcWidth * ratio || 0) | ||
console.log(srcHeight * ratio || 0) | ||
} | ||
/** | ||
* Click event handler to trigger Parvus | ||
@@ -1077,4 +1155,4 @@ * | ||
GROUPS[activeGroup].slider.classList.add('parvus__slider--is-dragging') | ||
GROUPS[activeGroup].slider.style.willChange = 'transform' | ||
groups[activeGroup].slider.classList.add('parvus__slider--is-dragging') | ||
groups[activeGroup].slider.style.willChange = 'transform' | ||
} | ||
@@ -1106,4 +1184,4 @@ | ||
GROUPS[activeGroup].slider.classList.remove('parvus__slider--is-dragging') | ||
GROUPS[activeGroup].slider.style.willChange = 'auto' | ||
groups[activeGroup].slider.classList.remove('parvus__slider--is-dragging') | ||
groups[activeGroup].slider.style.willChange = 'auto' | ||
@@ -1132,4 +1210,4 @@ if (drag.endX || drag.endY) { | ||
GROUPS[activeGroup].slider.classList.add('parvus__slider--is-dragging') | ||
GROUPS[activeGroup].slider.style.willChange = 'transform' | ||
groups[activeGroup].slider.classList.add('parvus__slider--is-dragging') | ||
groups[activeGroup].slider.style.willChange = 'transform' | ||
} | ||
@@ -1163,4 +1241,4 @@ | ||
GROUPS[activeGroup].slider.classList.remove('parvus__slider--is-dragging') | ||
GROUPS[activeGroup].slider.style.willChange = 'auto' | ||
groups[activeGroup].slider.classList.remove('parvus__slider--is-dragging') | ||
groups[activeGroup].slider.style.willChange = 'auto' | ||
@@ -1183,5 +1261,5 @@ if (drag.endX || drag.endY) { | ||
if (Math.abs(MOVEMENT_X) > 0 && !isDraggingY && GROUPS[activeGroup].gallery.length > 1) { | ||
if (Math.abs(MOVEMENT_X) > 0 && !isDraggingY && groups[activeGroup].gallery.length > 1) { | ||
// Horizontal swipe | ||
GROUPS[activeGroup].slider.style.transform = `translate3d(${offsetTmp - Math.round(MOVEMENT_X)}px, 0, 0)` | ||
groups[activeGroup].slider.style.transform = `translate3d(${offsetTmp - Math.round(MOVEMENT_X)}px, 0, 0)` | ||
@@ -1199,3 +1277,3 @@ isDraggingX = true | ||
GROUPS[activeGroup].slider.style.transform = `translate3d(${offsetTmp}px, ${Math.round(MOVEMENT_Y)}px, 0)` | ||
groups[activeGroup].slider.style.transform = `translate3d(${offsetTmp}px, ${Math.round(MOVEMENT_Y)}px, 0)` | ||
@@ -1322,5 +1400,5 @@ isDraggingX = false | ||
* Bind event | ||
* | ||
* @param {String} eventName | ||
* @param {function} callback - callback to call | ||
* | ||
* @param {Function} callback | ||
*/ | ||
@@ -1335,5 +1413,5 @@ const on = function on (eventName, callback) { | ||
* Unbind event | ||
* | ||
* @param {String} eventName | ||
* @param {function} callback - callback to call | ||
* | ||
* @param {Function} callback | ||
*/ | ||
@@ -1340,0 +1418,0 @@ const off = function off (eventName, callback) { |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
188415
16
3798
302