From 2dbed4a66680e1caa0df7abb7d75e66fd3bc9f2c Mon Sep 17 00:00:00 2001 From: deoostfrees <68224180+deoostfrees@users.noreply.github.com> Date: Wed, 10 Apr 2024 14:45:24 +0200 Subject: [PATCH] [BUGFIX] Issue if no language options are set --- CHANGELOG.md | 6 ++++++ dist/js/parvus.esm.js | 18 ++++++++++++------ dist/js/parvus.esm.min.js | 4 ++-- dist/js/parvus.js | 18 ++++++++++++------ dist/js/parvus.min.js | 4 ++-- package.json | 2 +- src/js/parvus.js | 15 ++++++++++++--- 7 files changed, 47 insertions(+), 20 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d80c4fa..92a7231 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,12 @@ - Pinch zoom gestures +## [2.5.1] - 2024-04-10 + +### Fixed + +- Issue if no language options are set + ## [2.5.0] - 2024-04-07 ### Added diff --git a/dist/js/parvus.esm.js b/dist/js/parvus.esm.js index bf9c37c..0a9c75e 100644 --- a/dist/js/parvus.esm.js +++ b/dist/js/parvus.esm.js @@ -2,7 +2,7 @@ * Parvus * * @author Benjamin de Oostfrees - * @version 2.5.0 + * @version 2.5.1 * @url https://github.com/deoostfrees/parvus * * MIT license @@ -111,14 +111,17 @@ function Parvus(userOptions) { closeButtonIcon: '', l10n: en }; - return { + const MERGED_OPTIONS = { ...DEFAULT_OPTIONS, - ...userOptions, - l10n: { + ...userOptions + }; + if (userOptions && userOptions.l10n) { + MERGED_OPTIONS.l10n = { ...DEFAULT_OPTIONS.l10n, ...userOptions.l10n - } - }; + }; + } + return MERGED_OPTIONS; }; /** @@ -179,6 +182,9 @@ function Parvus(userOptions) { * @param {HTMLElement} el - The element to be added */ const add = el => { + if (!lightbox) { + return; + } if (!(el.tagName === 'A' && el.hasAttribute('href') || el.tagName === 'BUTTON' && el.hasAttribute('data-target'))) { throw new Error('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.'); } diff --git a/dist/js/parvus.esm.min.js b/dist/js/parvus.esm.min.js index 09c66d3..2a751f0 100644 --- a/dist/js/parvus.esm.min.js +++ b/dist/js/parvus.esm.min.js @@ -2,10 +2,10 @@ * Parvus * * @author Benjamin de Oostfrees - * @version 2.5.0 + * @version 2.5.1 * @url https://github.com/deoostfrees/parvus * * MIT license */ -const e=['a:not([inert]):not([tabindex^="-"])','button:not([inert]):not([tabindex^="-"]):not(:disabled)','[tabindex]:not([inert]):not([tabindex^="-"])'],t=t=>Array.from(t.querySelectorAll(e.join(", "))).filter((e=>null!==e.offsetParent)),r=window,s=()=>r.innerWidth-document.documentElement.clientWidth;var i={lightboxLabel:"This is a dialog window that overlays the main content of the page. The modal displays 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",lightboxLoadingError:"The requested image cannot be loaded.",controlsLabel:"Controls",previousButtonLabel:"Previous image",nextButtonLabel:"Next image",closeButtonLabel:"Close dialog window",sliderLabel:"Images",slideLabel:"Image"};function n(e){const r=window,n={triggerElements:[],slider:null,sliderElements:[],contentElements:[]},a={};let o=0,l=null,d=null,u=0,c={},m=null,p=null,g=1,h=null,b=null,v=null,f=null,E=null,A=null,y=null,w=null,L={},_=!1,C=!1,x=!1,$=null,k=null,I=null,S=!1,M=null,T=!0;const B=window.matchMedia("(prefers-reduced-motion)"),N=()=>{B.matches?(T=!0,M=.1):(T=!1,M=c.transitionDuration)};B.addEventListener("change",N);const q=e=>{const t=e.dataset.group||`default-${o}`;return++o,e.hasAttribute("data-group")||e.setAttribute("data-group",t),t},F=e=>{if(!("A"===e.tagName&&e.hasAttribute("href")||"BUTTON"===e.tagName&&e.hasAttribute("data-target")))throw new Error("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.");if(l=q(e),a[l]||(a[l]=structuredClone(n)),a[l].triggerElements.includes(e))throw new Error("Ups, element already added.");if(a[l].triggerElements.push(e),(e=>{if(e.querySelector("img")){const t=document.createElement("div");e.classList.add("parvus-zoom"),t.className="parvus-zoom__indicator",t.innerHTML=c.lightboxIndicatorIcon,e.appendChild(t)}})(e),e.classList.add("parvus-trigger"),e.addEventListener("click",se),be()&&l===d){const t=a[l].triggerElements.indexOf(e);Y(t),P(e,t,(()=>{R(t)})),ee(),K(),J()}},X=e=>{if(!e||!e.hasAttribute("data-group"))return;const t=q(e);if(!a[t]||!a[t].triggerElements.includes(e))return;const r=a[t].triggerElements.indexOf(e);if(a[t].triggerElements.splice(r,1),a[t].sliderElements.splice(r,1),e.classList.contains("parvus-zoom")){const t=e.querySelector(".parvus-zoom__indicator");e.classList.remove("parvus-zoom"),e.removeChild(t)}be()&&t===d&&(ee(),K(),J()),e.removeEventListener("click",se),e.classList.remove("parvus-trigger")},Y=e=>{if(void 0!==a[d].sliderElements[e])return;const t=document.createElement("div"),r=document.createElement("div"),s=a[d].triggerElements.length;if(t.className="parvus__slide",t.style.position="absolute",t.style.left=100*e+"%",t.setAttribute("aria-hidden","true"),t.appendChild(r),s>1&&(t.setAttribute("role","group"),t.setAttribute("aria-label",`${c.l10n.slideLabel} ${e+1}/${s}`)),a[d].sliderElements[e]=t,e>=u){const r=(e=>{const t=a[d].sliderElements,r=t.length;for(let s=e+1;s{const t=a[d].sliderElements;for(let r=e-1;r>=0;r--)if(void 0!==t[r])return r;return-1})(e);-1!==r?a[d].sliderElements[r].after(t):a[d].slider.prepend(t)}},z=e=>{if(!m||!e||!e.classList.contains("parvus-trigger")||be())return;if(d=q(e),!a[d].triggerElements.includes(e))throw new Error("Ups, I can't find the element.");u=a[d].triggerElements.indexOf(e),$=document.activeElement,history.pushState({parvus:"close"},"Image",window.location.href),ge();document.querySelectorAll('body > *:not([aria-hidden="true"])').forEach((e=>{e.setAttribute("aria-hidden","true"),e.classList.add("parvus-hidden")})),c.hideScrollbar&&(document.body.style.marginInlineEnd=`${s()}px`,document.body.style.overflow="hidden"),m.classList.add("parvus--is-opening"),m.setAttribute("aria-hidden","false"),(()=>{const e=document.createElement("div");e.className="parvus__slider",e.setAttribute("aria-hidden","true"),a[d].slider=e,m.appendChild(e)})(),Y(u),a[d].slider.setAttribute("aria-hidden","false"),V(),ee(),K(),J(),ne(),O(u),P(e,u,(()=>{R(u,!0),m.classList.remove("parvus--is-opening"),a[d].slider.classList.add("parvus__slider--animate")})),D(u+1),D(u-1),fe("open",{source:e})},H=()=>{if(!be())throw new Error("Ups, I'm already closed.");const e=a[d].contentElements[u],t=a[d].triggerElements[u];he(),Q(),"close"===history.state?.parvus&&history.back();document.querySelectorAll(".parvus-hidden").forEach((e=>{e.removeAttribute("aria-hidden"),e.classList.remove("parvus-hidden")})),m.classList.add("parvus--is-closing"),requestAnimationFrame((()=>{const r=t.getBoundingClientRect();if(e&&"IMG"===e.tagName){const t=e.getBoundingClientRect(),s=r.width/t.width,i=r.height/t.height,n=r.left-t.left,a=r.top-t.top;e.style.transform=`translate(${n}px, ${a}px) scale(${s}, ${i})`}e.style.opacity=0,e.style.transition=`transform ${M}ms ${c.transitionTimingFunction}, opacity ${M}ms ${c.transitionTimingFunction} ${M/2}ms`}));const r=()=>{G(u),$=c.backFocus?$:a[d].triggerElements[u],$.focus({preventScroll:!0}),m.setAttribute("aria-hidden","true"),m.classList.remove("parvus--is-closing"),m.classList.remove("parvus--is-vertical-closing"),e.style.transform="",e.removeEventListener("transitionend",r),a[d].slider.remove(),a[d].slider=null,a[d].sliderElements=[],a[d].contentElements=[],w.removeAttribute("aria-hidden"),E.removeAttribute("aria-hidden"),E.removeAttribute("aria-disabled"),A.removeAttribute("aria-hidden"),A.removeAttribute("aria-disabled"),c.hideScrollbar&&(document.body.style.marginInlineEnd="",document.body.style.overflow="")};e.addEventListener("transitionend",r,{once:!0}),fe("close",{detail:{source:a[d].triggerElements[u]}})},D=e=>{e<0||e>=a[d].triggerElements.length||void 0!==a[d].sliderElements[e]||(Y(e),P(a[d].triggerElements[e],e,(()=>{R(e)})))},O=e=>{a[d].sliderElements[e].setAttribute("aria-hidden","false")},P=(e,t,r)=>{const{contentElements:s,sliderElements:i}=a[d];if(void 0!==s[t])return void(r&&"function"==typeof r&&r());const n=i[t].querySelector("div"),o=new Image,l=document.createElement("div"),u=e.querySelector("img"),m=document.createElement("div");l.className="parvus__content",m.className="parvus__loader",m.setAttribute("role","progressbar"),m.setAttribute("aria-label",c.l10n.lightboxLoadingIndicatorLabel),n.appendChild(m);new Promise(((e,t)=>{o.onload=()=>e(o),o.onerror=e=>t(e)})).then((r=>{r.style.opacity=0,l.appendChild(r),n.appendChild(l),c.captions&&((e,t,r)=>{const s=document.createElement("div");let i=null;if(s.className="parvus__caption","self"===c.captionsSelector)t.hasAttribute(c.captionsAttribute)&&""!==t.getAttribute(c.captionsAttribute)&&(i=t.getAttribute(c.captionsAttribute));else{const e=t.querySelector(c.captionsSelector);null!==e&&(i=e.hasAttribute(c.captionsAttribute)&&""!==e.getAttribute(c.captionsAttribute)?e.getAttribute(c.captionsAttribute):e.innerHTML)}if(null!==i){const t=`parvus__caption-${r}`;s.setAttribute("aria-labelledby",t),s.id=t,s.innerHTML=`

${i}

`,e.appendChild(s)}})(n,e,t),s[t]=r,r.setAttribute("width",r.naturalWidth),r.setAttribute("height",r.naturalHeight),re(i[t],r)})).catch((()=>{const e=document.createElement("div");e.classList.add("parvus__content"),e.classList.add("parvus__content--error"),e.innerHTML=`${c.l10n.lightboxLoadingError}`,n.appendChild(e),s[t]=e})).finally((()=>{n.removeChild(m),r&&"function"==typeof r&&r()})),e.hasAttribute("data-sizes")&&""!==e.getAttribute("data-sizes")&&o.setAttribute("sizes",e.getAttribute("data-sizes")),e.hasAttribute("data-srcset")&&""!==e.getAttribute("data-srcset")&&o.setAttribute("srcset",e.getAttribute("data-srcset")),"A"===e.tagName?o.setAttribute("src",e.href):o.setAttribute("src",e.getAttribute("data-target")),u&&u.hasAttribute("alt")&&""!==u.getAttribute("alt")?o.alt=u.alt:e.hasAttribute("data-alt")&&""!==e.getAttribute("data-alt")?o.alt=e.getAttribute("data-alt"):o.alt=""},R=(e,t)=>{const r=a[d].contentElements[e];if(r&&"IMG"===r.tagName){const s=a[d].triggerElements[e];if(t){const e=r.getBoundingClientRect(),t=s.getBoundingClientRect(),i=t.width/e.width,n=t.height/e.height,a=t.left-e.left,o=t.top-e.top;requestAnimationFrame((()=>{r.style.transform=`translate(${a}px, ${o}px) scale(${i}, ${n})`,r.style.transition="transform 0s, opacity 0s",requestAnimationFrame((()=>{r.style.transform="",r.style.opacity=1,r.style.transition=`transform ${M}ms ${c.transitionTimingFunction}, opacity ${M/2}ms ${c.transitionTimingFunction}`}))}))}else r.style.opacity=1}else r.style.opacity=1},j=e=>{const t=u;if(!be())throw new Error("Oops, I'm closed.");{if("number"!=typeof e||isNaN(e))throw new Error("Oops, no slide specified.");const t=a[d].triggerElements;if(e===u)throw new Error(`Oops, slide ${e} is already selected.`);if(e<-1||e>=t.length)throw new Error(`Oops, I can't find slide ${e}.`)}void 0!==a[d].sliderElements[e]||(Y(e),P(a[d].triggerElements[e],e,(()=>{R(e)}))),O(e),u=e,V(),et&&(K(),D(e+1)),G(t),J(),fe("select",{detail:{source:a[d].triggerElements[u]}})},U=()=>{u>0&&j(u-1)},W=()=>{const{triggerElements:e}=a[d];u{void 0!==a[d].sliderElements[e]&&a[d].sliderElements[e].setAttribute("aria-hidden","true")},V=()=>{d=null!==d?d:l,k=-u*m.offsetWidth,a[d].slider.style.transform=`translate3d(${k}px, 0, 0)`,I=k},K=()=>{const{triggerElements:e}=a[d],t=e.length,r=u===t-1;t>1&&(0===u?(E.setAttribute("aria-disabled","true"),A.removeAttribute("aria-disabled")):r?(E.removeAttribute("aria-disabled"),A.setAttribute("aria-disabled","true")):(E.removeAttribute("aria-disabled"),A.removeAttribute("aria-disabled")))},J=()=>{w.textContent=`${u+1}/${a[d].triggerElements.length}`},Q=()=>{L={startX:0,endX:0,startY:0,endY:0}},Z=()=>{const{startX:e,startY:t,endX:r,endY:s}=L,i=r-e,n=s-t,o=Math.abs(i),l=Math.abs(n),{triggerElements:g}=a[d],h=g.length;_?i>2&&o>=c.threshold&&u>0?U():i<2&&o>=c.threshold&&u!==h-1?W():V():C?(l>2&&c.swipeClose&&l>=c.threshold?H():(m.classList.remove("parvus--is-vertical-closing"),V()),p.style.opacity=""):V()},ee=()=>{const e=a[d].triggerElements.length,t=a[d].slider,r=a[d].sliderElements,s=c.simulateTouch||ve(),i=t.classList.contains("parvus__slider--is-draggable");s&&c.swipeClose&&!i||s&&e>1&&!i?t.classList.add("parvus__slider--is-draggable"):t.classList.remove("parvus__slider--is-draggable"),e>1?(t.setAttribute("role","region"),t.setAttribute("aria-roledescription","carousel"),t.setAttribute("aria-label",c.l10n.sliderLabel),r.forEach(((t,r)=>{t.setAttribute("role","group"),t.setAttribute("aria-label",`${c.l10n.slideLabel} ${r+1}/${e}`)}))):(t.removeAttribute("role"),t.removeAttribute("aria-roledescription"),t.removeAttribute("aria-label"),r.forEach((e=>{e.removeAttribute("role"),e.removeAttribute("aria-label")}))),1===e?(w.setAttribute("aria-hidden","true"),E.setAttribute("aria-hidden","true"),A.setAttribute("aria-hidden","true")):(w.removeAttribute("aria-hidden"),E.removeAttribute("aria-hidden"),A.removeAttribute("aria-hidden"))},te=()=>{S||(S=!0,r.requestAnimationFrame((()=>{a[d].sliderElements.forEach(((e,t)=>{re(e,a[d].contentElements[t])})),V(),S=!1})))},re=(e,t)=>{if("IMG"!==t.tagName)return;const r=getComputedStyle(e),s=e.querySelector(".parvus__caption"),i=s?s.getBoundingClientRect().height:0,n=t.getAttribute("height"),a=t.getAttribute("width");let o=e.offsetHeight,l=e.offsetWidth;o-=parseFloat(r.paddingTop)+parseFloat(r.paddingBottom)+parseFloat(i),l-=parseFloat(r.paddingLeft)+parseFloat(r.paddingRight);const d=Math.min(l/a||0,o/n),u=a*d||0,c=n*d||0;n>c&&nu&&a{const{target:t}=e;t===E?U():t===A?W():(t===y||c.docClose&&!C&&!_&&t.classList.contains("parvus__slide"))&&H(),e.stopPropagation()},ne=()=>{t(m)[0].focus()},ae=e=>{const r=t(m),s=r.indexOf(document.activeElement),i=r.length-1;switch(e.code){case"Tab":e.shiftKey?0===s&&(r[i].focus(),e.preventDefault()):s===i&&(r[0].focus(),e.preventDefault());break;case"Escape":H(),e.preventDefault();break;case"ArrowLeft":U(),e.preventDefault();break;case"ArrowRight":W(),e.preventDefault()}},oe=e=>{_=!1,C=!1,x=!0;const{pageX:t,pageY:r}=e;L.startX=t,L.startY=r;const{slider:s}=a[d];s.classList.add("parvus__slider--is-dragging"),s.style.willChange="transform",e.stopPropagation(),g=getComputedStyle(p).opacity},le=e=>{if(x){const{pageX:t,pageY:r}=e;L.endX=t,L.endY=r,pe()}e.preventDefault()},de=()=>{x=!1;const{slider:e}=a[d];e.classList.remove("parvus__slider--is-dragging"),e.style.willChange="",(L.endX||L.endY)&&Z(),Q()},ue=e=>{_=!1,C=!1;const{clientX:t,clientY:r}=e.changedTouches[0];L.startX=parseInt(t,10),L.startY=parseInt(r,10);const{slider:s}=a[d];s.classList.add("parvus__slider--is-dragging"),s.style.willChange="transform",g=getComputedStyle(p).getPropertyValue("opacity"),e.stopPropagation()},ce=e=>{const{clientX:t,clientY:r}=e.changedTouches[0];L.endX=parseInt(t,10),L.endY=parseInt(r,10),pe(),e.preventDefault()},me=()=>{const{slider:e}=a[d];e.classList.remove("parvus__slider--is-dragging"),e.style.willChange="",(L.endX||L.endY)&&Z(),Q()},pe=()=>{const{startX:e,endX:t,startY:r,endY:s}=L,i=e-t,n=s-r,o=Math.abs(n);Math.abs(i)>2&&!C&&a[d].triggerElements.length>1?(a[d].slider.style.transform=`translate3d(${I-Math.round(i)}px, 0, 0)`,_=!0,C=!1):Math.abs(n)>2&&!_&&c.swipeClose&&(!T&&o<=100&&(p.style.opacity=g-o/100),m.classList.add("parvus--is-vertical-closing"),a[d].slider.style.transform=`translate3d(${I}px, ${Math.round(n)}px, 0)`,_=!1,C=!0)},ge=()=>{r.addEventListener("keydown",ae),r.addEventListener("resize",te),r.addEventListener("popstate",H),m.addEventListener("click",ie),ve()&&(m.addEventListener("touchstart",ue),m.addEventListener("touchmove",ce),m.addEventListener("touchend",me)),c.simulateTouch&&(m.addEventListener("mousedown",oe),m.addEventListener("mouseup",de),m.addEventListener("mousemove",le))},he=()=>{r.removeEventListener("keydown",ae),r.removeEventListener("resize",te),r.removeEventListener("popstate",H),m.removeEventListener("click",ie),ve()&&(m.removeEventListener("touchstart",ue),m.removeEventListener("touchmove",ce),m.removeEventListener("touchend",me)),c.simulateTouch&&(m.removeEventListener("mousedown",oe),m.removeEventListener("mouseup",de),m.removeEventListener("mousemove",le))},be=()=>"false"===m.getAttribute("aria-hidden"),ve=()=>"ontouchstart"in window,fe=(e,t={})=>{const r=new CustomEvent(e,{detail:t,cancelable:!0});m.dispatchEvent(r)},Ee=()=>{if(c=(e=>{const t={loadEmpty:!1,selector:".lightbox",gallerySelector:null,captions:!0,captionsSelector:"self",captionsAttribute:"data-caption",docClose:!0,swipeClose:!0,simulateTouch:!0,threshold:50,backFocus:!0,hideScrollbar:!0,transitionDuration:300,transitionTimingFunction:"cubic-bezier(0.62, 0.16, 0.13, 1.01)",lightboxIndicatorIcon:'',previousButtonIcon:'',nextButtonIcon:'',closeButtonIcon:'',l10n:i};return{...t,...e,l10n:{...t.l10n,...e.l10n}}})(e),!c.loadEmpty&&!document.querySelectorAll(c.selector).length)return;if(N(),m||(m=document.createElement("div"),m.setAttribute("role","dialog"),m.setAttribute("aria-modal","true"),m.setAttribute("aria-hidden","true"),m.setAttribute("tabindex","-1"),m.setAttribute("aria-label",c.l10n.lightboxLabel),m.classList.add("parvus"),p=document.createElement("div"),p.classList.add("parvus__overlay"),m.appendChild(p),h=document.createElement("div"),h.className="parvus__toolbar",b=document.createElement("div"),v=document.createElement("div"),f=document.createElement("div"),f.className="parvus__controls",f.setAttribute("role","group"),f.setAttribute("aria-label",c.l10n.controlsLabel),v.appendChild(f),y=document.createElement("button"),y.className="parvus__btn parvus__btn--close",y.setAttribute("type","button"),y.setAttribute("aria-label",c.l10n.closeButtonLabel),y.innerHTML=c.closeButtonIcon,f.appendChild(y),E=document.createElement("button"),E.className="parvus__btn parvus__btn--previous",E.setAttribute("type","button"),E.setAttribute("aria-label",c.l10n.previousButtonLabel),E.innerHTML=c.previousButtonIcon,f.appendChild(E),A=document.createElement("button"),A.className="parvus__btn parvus__btn--next",A.setAttribute("type","button"),A.setAttribute("aria-label",c.l10n.nextButtonLabel),A.innerHTML=c.nextButtonIcon,f.appendChild(A),w=document.createElement("div"),w.className="parvus__counter",b.appendChild(w),h.appendChild(b),h.appendChild(v),m.appendChild(h),document.body.appendChild(m)),null!==c.gallerySelector){document.querySelectorAll(c.gallerySelector).forEach(((e,t)=>{const r=t;e.querySelectorAll(c.selector).forEach((e=>{e.setAttribute("data-group",`parvus-gallery-${r}`),F(e)}))}))}document.querySelectorAll(`${c.selector}:not(.parvus-trigger)`).forEach(F)};return Ee(),{init:Ee,open:z,close:H,select:j,previous:U,next:W,currentIndex:()=>u,add:F,remove:X,destroy:()=>{if(!m)return;be()&&H(),m.remove();document.querySelectorAll(".parvus-trigger").forEach(X),fe("destroy")},isOpen:be,on:(e,t)=>{m&&m.addEventListener(e,t)},off:(e,t)=>{m&&m.removeEventListener(e,t)}}}export{n as default}; +const e=['a:not([inert]):not([tabindex^="-"])','button:not([inert]):not([tabindex^="-"]):not(:disabled)','[tabindex]:not([inert]):not([tabindex^="-"])'],t=t=>Array.from(t.querySelectorAll(e.join(", "))).filter((e=>null!==e.offsetParent)),r=window,s=()=>r.innerWidth-document.documentElement.clientWidth;var i={lightboxLabel:"This is a dialog window that overlays the main content of the page. The modal displays 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",lightboxLoadingError:"The requested image cannot be loaded.",controlsLabel:"Controls",previousButtonLabel:"Previous image",nextButtonLabel:"Next image",closeButtonLabel:"Close dialog window",sliderLabel:"Images",slideLabel:"Image"};function n(e){const r=window,n={triggerElements:[],slider:null,sliderElements:[],contentElements:[]},a={};let o=0,l=null,d=null,u=0,c={},m=null,p=null,g=1,h=null,b=null,v=null,f=null,E=null,A=null,y=null,w=null,L={},_=!1,C=!1,x=!1,$=null,k=null,I=null,S=!1,M=null,T=!0;const B=window.matchMedia("(prefers-reduced-motion)"),N=()=>{B.matches?(T=!0,M=.1):(T=!1,M=c.transitionDuration)};B.addEventListener("change",N);const q=e=>{const t=e.dataset.group||`default-${o}`;return++o,e.hasAttribute("data-group")||e.setAttribute("data-group",t),t},F=e=>{if(m){if(!("A"===e.tagName&&e.hasAttribute("href")||"BUTTON"===e.tagName&&e.hasAttribute("data-target")))throw new Error("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.");if(l=q(e),a[l]||(a[l]=structuredClone(n)),a[l].triggerElements.includes(e))throw new Error("Ups, element already added.");if(a[l].triggerElements.push(e),(e=>{if(e.querySelector("img")){const t=document.createElement("div");e.classList.add("parvus-zoom"),t.className="parvus-zoom__indicator",t.innerHTML=c.lightboxIndicatorIcon,e.appendChild(t)}})(e),e.classList.add("parvus-trigger"),e.addEventListener("click",se),be()&&l===d){const t=a[l].triggerElements.indexOf(e);Y(t),P(e,t,(()=>{R(t)})),ee(),K(),J()}}},X=e=>{if(!e||!e.hasAttribute("data-group"))return;const t=q(e);if(!a[t]||!a[t].triggerElements.includes(e))return;const r=a[t].triggerElements.indexOf(e);if(a[t].triggerElements.splice(r,1),a[t].sliderElements.splice(r,1),e.classList.contains("parvus-zoom")){const t=e.querySelector(".parvus-zoom__indicator");e.classList.remove("parvus-zoom"),e.removeChild(t)}be()&&t===d&&(ee(),K(),J()),e.removeEventListener("click",se),e.classList.remove("parvus-trigger")},Y=e=>{if(void 0!==a[d].sliderElements[e])return;const t=document.createElement("div"),r=document.createElement("div"),s=a[d].triggerElements.length;if(t.className="parvus__slide",t.style.position="absolute",t.style.left=100*e+"%",t.setAttribute("aria-hidden","true"),t.appendChild(r),s>1&&(t.setAttribute("role","group"),t.setAttribute("aria-label",`${c.l10n.slideLabel} ${e+1}/${s}`)),a[d].sliderElements[e]=t,e>=u){const r=(e=>{const t=a[d].sliderElements,r=t.length;for(let s=e+1;s{const t=a[d].sliderElements;for(let r=e-1;r>=0;r--)if(void 0!==t[r])return r;return-1})(e);-1!==r?a[d].sliderElements[r].after(t):a[d].slider.prepend(t)}},z=e=>{if(!m||!e||!e.classList.contains("parvus-trigger")||be())return;if(d=q(e),!a[d].triggerElements.includes(e))throw new Error("Ups, I can't find the element.");u=a[d].triggerElements.indexOf(e),$=document.activeElement,history.pushState({parvus:"close"},"Image",window.location.href),ge();document.querySelectorAll('body > *:not([aria-hidden="true"])').forEach((e=>{e.setAttribute("aria-hidden","true"),e.classList.add("parvus-hidden")})),c.hideScrollbar&&(document.body.style.marginInlineEnd=`${s()}px`,document.body.style.overflow="hidden"),m.classList.add("parvus--is-opening"),m.setAttribute("aria-hidden","false"),(()=>{const e=document.createElement("div");e.className="parvus__slider",e.setAttribute("aria-hidden","true"),a[d].slider=e,m.appendChild(e)})(),Y(u),a[d].slider.setAttribute("aria-hidden","false"),V(),ee(),K(),J(),ne(),O(u),P(e,u,(()=>{R(u,!0),m.classList.remove("parvus--is-opening"),a[d].slider.classList.add("parvus__slider--animate")})),D(u+1),D(u-1),fe("open",{source:e})},H=()=>{if(!be())throw new Error("Ups, I'm already closed.");const e=a[d].contentElements[u],t=a[d].triggerElements[u];he(),Q(),"close"===history.state?.parvus&&history.back();document.querySelectorAll(".parvus-hidden").forEach((e=>{e.removeAttribute("aria-hidden"),e.classList.remove("parvus-hidden")})),m.classList.add("parvus--is-closing"),requestAnimationFrame((()=>{const r=t.getBoundingClientRect();if(e&&"IMG"===e.tagName){const t=e.getBoundingClientRect(),s=r.width/t.width,i=r.height/t.height,n=r.left-t.left,a=r.top-t.top;e.style.transform=`translate(${n}px, ${a}px) scale(${s}, ${i})`}e.style.opacity=0,e.style.transition=`transform ${M}ms ${c.transitionTimingFunction}, opacity ${M}ms ${c.transitionTimingFunction} ${M/2}ms`}));const r=()=>{G(u),$=c.backFocus?$:a[d].triggerElements[u],$.focus({preventScroll:!0}),m.setAttribute("aria-hidden","true"),m.classList.remove("parvus--is-closing"),m.classList.remove("parvus--is-vertical-closing"),e.style.transform="",e.removeEventListener("transitionend",r),a[d].slider.remove(),a[d].slider=null,a[d].sliderElements=[],a[d].contentElements=[],w.removeAttribute("aria-hidden"),E.removeAttribute("aria-hidden"),E.removeAttribute("aria-disabled"),A.removeAttribute("aria-hidden"),A.removeAttribute("aria-disabled"),c.hideScrollbar&&(document.body.style.marginInlineEnd="",document.body.style.overflow="")};e.addEventListener("transitionend",r,{once:!0}),fe("close",{detail:{source:a[d].triggerElements[u]}})},D=e=>{e<0||e>=a[d].triggerElements.length||void 0!==a[d].sliderElements[e]||(Y(e),P(a[d].triggerElements[e],e,(()=>{R(e)})))},O=e=>{a[d].sliderElements[e].setAttribute("aria-hidden","false")},P=(e,t,r)=>{const{contentElements:s,sliderElements:i}=a[d];if(void 0!==s[t])return void(r&&"function"==typeof r&&r());const n=i[t].querySelector("div"),o=new Image,l=document.createElement("div"),u=e.querySelector("img"),m=document.createElement("div");l.className="parvus__content",m.className="parvus__loader",m.setAttribute("role","progressbar"),m.setAttribute("aria-label",c.l10n.lightboxLoadingIndicatorLabel),n.appendChild(m);new Promise(((e,t)=>{o.onload=()=>e(o),o.onerror=e=>t(e)})).then((r=>{r.style.opacity=0,l.appendChild(r),n.appendChild(l),c.captions&&((e,t,r)=>{const s=document.createElement("div");let i=null;if(s.className="parvus__caption","self"===c.captionsSelector)t.hasAttribute(c.captionsAttribute)&&""!==t.getAttribute(c.captionsAttribute)&&(i=t.getAttribute(c.captionsAttribute));else{const e=t.querySelector(c.captionsSelector);null!==e&&(i=e.hasAttribute(c.captionsAttribute)&&""!==e.getAttribute(c.captionsAttribute)?e.getAttribute(c.captionsAttribute):e.innerHTML)}if(null!==i){const t=`parvus__caption-${r}`;s.setAttribute("aria-labelledby",t),s.id=t,s.innerHTML=`

${i}

`,e.appendChild(s)}})(n,e,t),s[t]=r,r.setAttribute("width",r.naturalWidth),r.setAttribute("height",r.naturalHeight),re(i[t],r)})).catch((()=>{const e=document.createElement("div");e.classList.add("parvus__content"),e.classList.add("parvus__content--error"),e.innerHTML=`${c.l10n.lightboxLoadingError}`,n.appendChild(e),s[t]=e})).finally((()=>{n.removeChild(m),r&&"function"==typeof r&&r()})),e.hasAttribute("data-sizes")&&""!==e.getAttribute("data-sizes")&&o.setAttribute("sizes",e.getAttribute("data-sizes")),e.hasAttribute("data-srcset")&&""!==e.getAttribute("data-srcset")&&o.setAttribute("srcset",e.getAttribute("data-srcset")),"A"===e.tagName?o.setAttribute("src",e.href):o.setAttribute("src",e.getAttribute("data-target")),u&&u.hasAttribute("alt")&&""!==u.getAttribute("alt")?o.alt=u.alt:e.hasAttribute("data-alt")&&""!==e.getAttribute("data-alt")?o.alt=e.getAttribute("data-alt"):o.alt=""},R=(e,t)=>{const r=a[d].contentElements[e];if(r&&"IMG"===r.tagName){const s=a[d].triggerElements[e];if(t){const e=r.getBoundingClientRect(),t=s.getBoundingClientRect(),i=t.width/e.width,n=t.height/e.height,a=t.left-e.left,o=t.top-e.top;requestAnimationFrame((()=>{r.style.transform=`translate(${a}px, ${o}px) scale(${i}, ${n})`,r.style.transition="transform 0s, opacity 0s",requestAnimationFrame((()=>{r.style.transform="",r.style.opacity=1,r.style.transition=`transform ${M}ms ${c.transitionTimingFunction}, opacity ${M/2}ms ${c.transitionTimingFunction}`}))}))}else r.style.opacity=1}else r.style.opacity=1},j=e=>{const t=u;if(!be())throw new Error("Oops, I'm closed.");{if("number"!=typeof e||isNaN(e))throw new Error("Oops, no slide specified.");const t=a[d].triggerElements;if(e===u)throw new Error(`Oops, slide ${e} is already selected.`);if(e<-1||e>=t.length)throw new Error(`Oops, I can't find slide ${e}.`)}void 0!==a[d].sliderElements[e]||(Y(e),P(a[d].triggerElements[e],e,(()=>{R(e)}))),O(e),u=e,V(),et&&(K(),D(e+1)),G(t),J(),fe("select",{detail:{source:a[d].triggerElements[u]}})},U=()=>{u>0&&j(u-1)},W=()=>{const{triggerElements:e}=a[d];u{void 0!==a[d].sliderElements[e]&&a[d].sliderElements[e].setAttribute("aria-hidden","true")},V=()=>{d=null!==d?d:l,k=-u*m.offsetWidth,a[d].slider.style.transform=`translate3d(${k}px, 0, 0)`,I=k},K=()=>{const{triggerElements:e}=a[d],t=e.length,r=u===t-1;t>1&&(0===u?(E.setAttribute("aria-disabled","true"),A.removeAttribute("aria-disabled")):r?(E.removeAttribute("aria-disabled"),A.setAttribute("aria-disabled","true")):(E.removeAttribute("aria-disabled"),A.removeAttribute("aria-disabled")))},J=()=>{w.textContent=`${u+1}/${a[d].triggerElements.length}`},Q=()=>{L={startX:0,endX:0,startY:0,endY:0}},Z=()=>{const{startX:e,startY:t,endX:r,endY:s}=L,i=r-e,n=s-t,o=Math.abs(i),l=Math.abs(n),{triggerElements:g}=a[d],h=g.length;_?i>2&&o>=c.threshold&&u>0?U():i<2&&o>=c.threshold&&u!==h-1?W():V():C?(l>2&&c.swipeClose&&l>=c.threshold?H():(m.classList.remove("parvus--is-vertical-closing"),V()),p.style.opacity=""):V()},ee=()=>{const e=a[d].triggerElements.length,t=a[d].slider,r=a[d].sliderElements,s=c.simulateTouch||ve(),i=t.classList.contains("parvus__slider--is-draggable");s&&c.swipeClose&&!i||s&&e>1&&!i?t.classList.add("parvus__slider--is-draggable"):t.classList.remove("parvus__slider--is-draggable"),e>1?(t.setAttribute("role","region"),t.setAttribute("aria-roledescription","carousel"),t.setAttribute("aria-label",c.l10n.sliderLabel),r.forEach(((t,r)=>{t.setAttribute("role","group"),t.setAttribute("aria-label",`${c.l10n.slideLabel} ${r+1}/${e}`)}))):(t.removeAttribute("role"),t.removeAttribute("aria-roledescription"),t.removeAttribute("aria-label"),r.forEach((e=>{e.removeAttribute("role"),e.removeAttribute("aria-label")}))),1===e?(w.setAttribute("aria-hidden","true"),E.setAttribute("aria-hidden","true"),A.setAttribute("aria-hidden","true")):(w.removeAttribute("aria-hidden"),E.removeAttribute("aria-hidden"),A.removeAttribute("aria-hidden"))},te=()=>{S||(S=!0,r.requestAnimationFrame((()=>{a[d].sliderElements.forEach(((e,t)=>{re(e,a[d].contentElements[t])})),V(),S=!1})))},re=(e,t)=>{if("IMG"!==t.tagName)return;const r=getComputedStyle(e),s=e.querySelector(".parvus__caption"),i=s?s.getBoundingClientRect().height:0,n=t.getAttribute("height"),a=t.getAttribute("width");let o=e.offsetHeight,l=e.offsetWidth;o-=parseFloat(r.paddingTop)+parseFloat(r.paddingBottom)+parseFloat(i),l-=parseFloat(r.paddingLeft)+parseFloat(r.paddingRight);const d=Math.min(l/a||0,o/n),u=a*d||0,c=n*d||0;n>c&&nu&&a{const{target:t}=e;t===E?U():t===A?W():(t===y||c.docClose&&!C&&!_&&t.classList.contains("parvus__slide"))&&H(),e.stopPropagation()},ne=()=>{t(m)[0].focus()},ae=e=>{const r=t(m),s=r.indexOf(document.activeElement),i=r.length-1;switch(e.code){case"Tab":e.shiftKey?0===s&&(r[i].focus(),e.preventDefault()):s===i&&(r[0].focus(),e.preventDefault());break;case"Escape":H(),e.preventDefault();break;case"ArrowLeft":U(),e.preventDefault();break;case"ArrowRight":W(),e.preventDefault()}},oe=e=>{_=!1,C=!1,x=!0;const{pageX:t,pageY:r}=e;L.startX=t,L.startY=r;const{slider:s}=a[d];s.classList.add("parvus__slider--is-dragging"),s.style.willChange="transform",e.stopPropagation(),g=getComputedStyle(p).opacity},le=e=>{if(x){const{pageX:t,pageY:r}=e;L.endX=t,L.endY=r,pe()}e.preventDefault()},de=()=>{x=!1;const{slider:e}=a[d];e.classList.remove("parvus__slider--is-dragging"),e.style.willChange="",(L.endX||L.endY)&&Z(),Q()},ue=e=>{_=!1,C=!1;const{clientX:t,clientY:r}=e.changedTouches[0];L.startX=parseInt(t,10),L.startY=parseInt(r,10);const{slider:s}=a[d];s.classList.add("parvus__slider--is-dragging"),s.style.willChange="transform",g=getComputedStyle(p).getPropertyValue("opacity"),e.stopPropagation()},ce=e=>{const{clientX:t,clientY:r}=e.changedTouches[0];L.endX=parseInt(t,10),L.endY=parseInt(r,10),pe(),e.preventDefault()},me=()=>{const{slider:e}=a[d];e.classList.remove("parvus__slider--is-dragging"),e.style.willChange="",(L.endX||L.endY)&&Z(),Q()},pe=()=>{const{startX:e,endX:t,startY:r,endY:s}=L,i=e-t,n=s-r,o=Math.abs(n);Math.abs(i)>2&&!C&&a[d].triggerElements.length>1?(a[d].slider.style.transform=`translate3d(${I-Math.round(i)}px, 0, 0)`,_=!0,C=!1):Math.abs(n)>2&&!_&&c.swipeClose&&(!T&&o<=100&&(p.style.opacity=g-o/100),m.classList.add("parvus--is-vertical-closing"),a[d].slider.style.transform=`translate3d(${I}px, ${Math.round(n)}px, 0)`,_=!1,C=!0)},ge=()=>{r.addEventListener("keydown",ae),r.addEventListener("resize",te),r.addEventListener("popstate",H),m.addEventListener("click",ie),ve()&&(m.addEventListener("touchstart",ue),m.addEventListener("touchmove",ce),m.addEventListener("touchend",me)),c.simulateTouch&&(m.addEventListener("mousedown",oe),m.addEventListener("mouseup",de),m.addEventListener("mousemove",le))},he=()=>{r.removeEventListener("keydown",ae),r.removeEventListener("resize",te),r.removeEventListener("popstate",H),m.removeEventListener("click",ie),ve()&&(m.removeEventListener("touchstart",ue),m.removeEventListener("touchmove",ce),m.removeEventListener("touchend",me)),c.simulateTouch&&(m.removeEventListener("mousedown",oe),m.removeEventListener("mouseup",de),m.removeEventListener("mousemove",le))},be=()=>"false"===m.getAttribute("aria-hidden"),ve=()=>"ontouchstart"in window,fe=(e,t={})=>{const r=new CustomEvent(e,{detail:t,cancelable:!0});m.dispatchEvent(r)},Ee=()=>{if(c=(e=>{const t={loadEmpty:!1,selector:".lightbox",gallerySelector:null,captions:!0,captionsSelector:"self",captionsAttribute:"data-caption",docClose:!0,swipeClose:!0,simulateTouch:!0,threshold:50,backFocus:!0,hideScrollbar:!0,transitionDuration:300,transitionTimingFunction:"cubic-bezier(0.62, 0.16, 0.13, 1.01)",lightboxIndicatorIcon:'',previousButtonIcon:'',nextButtonIcon:'',closeButtonIcon:'',l10n:i},r={...t,...e};return e&&e.l10n&&(r.l10n={...t.l10n,...e.l10n}),r})(e),!c.loadEmpty&&!document.querySelectorAll(c.selector).length)return;if(N(),m||(m=document.createElement("div"),m.setAttribute("role","dialog"),m.setAttribute("aria-modal","true"),m.setAttribute("aria-hidden","true"),m.setAttribute("tabindex","-1"),m.setAttribute("aria-label",c.l10n.lightboxLabel),m.classList.add("parvus"),p=document.createElement("div"),p.classList.add("parvus__overlay"),m.appendChild(p),h=document.createElement("div"),h.className="parvus__toolbar",b=document.createElement("div"),v=document.createElement("div"),f=document.createElement("div"),f.className="parvus__controls",f.setAttribute("role","group"),f.setAttribute("aria-label",c.l10n.controlsLabel),v.appendChild(f),y=document.createElement("button"),y.className="parvus__btn parvus__btn--close",y.setAttribute("type","button"),y.setAttribute("aria-label",c.l10n.closeButtonLabel),y.innerHTML=c.closeButtonIcon,f.appendChild(y),E=document.createElement("button"),E.className="parvus__btn parvus__btn--previous",E.setAttribute("type","button"),E.setAttribute("aria-label",c.l10n.previousButtonLabel),E.innerHTML=c.previousButtonIcon,f.appendChild(E),A=document.createElement("button"),A.className="parvus__btn parvus__btn--next",A.setAttribute("type","button"),A.setAttribute("aria-label",c.l10n.nextButtonLabel),A.innerHTML=c.nextButtonIcon,f.appendChild(A),w=document.createElement("div"),w.className="parvus__counter",b.appendChild(w),h.appendChild(b),h.appendChild(v),m.appendChild(h),document.body.appendChild(m)),null!==c.gallerySelector){document.querySelectorAll(c.gallerySelector).forEach(((e,t)=>{const r=t;e.querySelectorAll(c.selector).forEach((e=>{e.setAttribute("data-group",`parvus-gallery-${r}`),F(e)}))}))}document.querySelectorAll(`${c.selector}:not(.parvus-trigger)`).forEach(F)};return Ee(),{init:Ee,open:z,close:H,select:j,previous:U,next:W,currentIndex:()=>u,add:F,remove:X,destroy:()=>{if(!m)return;be()&&H(),m.remove();document.querySelectorAll(".parvus-trigger").forEach(X),fe("destroy")},isOpen:be,on:(e,t)=>{m&&m.addEventListener(e,t)},off:(e,t)=>{m&&m.removeEventListener(e,t)}}}export{n as default}; diff --git a/dist/js/parvus.js b/dist/js/parvus.js index 8e8c31a..896bd44 100644 --- a/dist/js/parvus.js +++ b/dist/js/parvus.js @@ -2,7 +2,7 @@ * Parvus * * @author Benjamin de Oostfrees - * @version 2.5.0 + * @version 2.5.1 * @url https://github.com/deoostfrees/parvus * * MIT license @@ -117,14 +117,17 @@ closeButtonIcon: '', l10n: en }; - return { + const MERGED_OPTIONS = { ...DEFAULT_OPTIONS, - ...userOptions, - l10n: { + ...userOptions + }; + if (userOptions && userOptions.l10n) { + MERGED_OPTIONS.l10n = { ...DEFAULT_OPTIONS.l10n, ...userOptions.l10n - } - }; + }; + } + return MERGED_OPTIONS; }; /** @@ -185,6 +188,9 @@ * @param {HTMLElement} el - The element to be added */ const add = el => { + if (!lightbox) { + return; + } if (!(el.tagName === 'A' && el.hasAttribute('href') || el.tagName === 'BUTTON' && el.hasAttribute('data-target'))) { throw new Error('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.'); } diff --git a/dist/js/parvus.min.js b/dist/js/parvus.min.js index 1708ad7..d4d02a0 100644 --- a/dist/js/parvus.min.js +++ b/dist/js/parvus.min.js @@ -2,10 +2,10 @@ * Parvus * * @author Benjamin de Oostfrees - * @version 2.5.0 + * @version 2.5.1 * @url https://github.com/deoostfrees/parvus * * MIT license */ -!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";const e=['a:not([inert]):not([tabindex^="-"])','button:not([inert]):not([tabindex^="-"]):not(:disabled)','[tabindex]:not([inert]):not([tabindex^="-"])'],t=t=>Array.from(t.querySelectorAll(e.join(", "))).filter((e=>null!==e.offsetParent)),r=window,i=()=>r.innerWidth-document.documentElement.clientWidth;var n={lightboxLabel:"This is a dialog window that overlays the main content of the page. The modal displays 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",lightboxLoadingError:"The requested image cannot be loaded.",controlsLabel:"Controls",previousButtonLabel:"Previous image",nextButtonLabel:"Next image",closeButtonLabel:"Close dialog window",sliderLabel:"Images",slideLabel:"Image"};return function(e){const r=window,s={triggerElements:[],slider:null,sliderElements:[],contentElements:[]},a={};let o=0,l=null,d=null,u=0,c={},m=null,p=null,g=1,h=null,b=null,v=null,f=null,E=null,A=null,y=null,w=null,L={},_=!1,x=!1,C=!1,$=null,k=null,I=null,S=!1,T=null,M=!0;const B=window.matchMedia("(prefers-reduced-motion)"),N=()=>{B.matches?(M=!0,T=.1):(M=!1,T=c.transitionDuration)};B.addEventListener("change",N);const q=e=>{const t=e.dataset.group||`default-${o}`;return++o,e.hasAttribute("data-group")||e.setAttribute("data-group",t),t},F=e=>{if(!("A"===e.tagName&&e.hasAttribute("href")||"BUTTON"===e.tagName&&e.hasAttribute("data-target")))throw new Error("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.");if(l=q(e),a[l]||(a[l]=structuredClone(s)),a[l].triggerElements.includes(e))throw new Error("Ups, element already added.");if(a[l].triggerElements.push(e),(e=>{if(e.querySelector("img")){const t=document.createElement("div");e.classList.add("parvus-zoom"),t.className="parvus-zoom__indicator",t.innerHTML=c.lightboxIndicatorIcon,e.appendChild(t)}})(e),e.classList.add("parvus-trigger"),e.addEventListener("click",ie),be()&&l===d){const t=a[l].triggerElements.indexOf(e);Y(t),P(e,t,(()=>{R(t)})),ee(),K(),J()}},X=e=>{if(!e||!e.hasAttribute("data-group"))return;const t=q(e);if(!a[t]||!a[t].triggerElements.includes(e))return;const r=a[t].triggerElements.indexOf(e);if(a[t].triggerElements.splice(r,1),a[t].sliderElements.splice(r,1),e.classList.contains("parvus-zoom")){const t=e.querySelector(".parvus-zoom__indicator");e.classList.remove("parvus-zoom"),e.removeChild(t)}be()&&t===d&&(ee(),K(),J()),e.removeEventListener("click",ie),e.classList.remove("parvus-trigger")},Y=e=>{if(void 0!==a[d].sliderElements[e])return;const t=document.createElement("div"),r=document.createElement("div"),i=a[d].triggerElements.length;if(t.className="parvus__slide",t.style.position="absolute",t.style.left=100*e+"%",t.setAttribute("aria-hidden","true"),t.appendChild(r),i>1&&(t.setAttribute("role","group"),t.setAttribute("aria-label",`${c.l10n.slideLabel} ${e+1}/${i}`)),a[d].sliderElements[e]=t,e>=u){const r=(e=>{const t=a[d].sliderElements,r=t.length;for(let i=e+1;i{const t=a[d].sliderElements;for(let r=e-1;r>=0;r--)if(void 0!==t[r])return r;return-1})(e);-1!==r?a[d].sliderElements[r].after(t):a[d].slider.prepend(t)}},z=e=>{if(!m||!e||!e.classList.contains("parvus-trigger")||be())return;if(d=q(e),!a[d].triggerElements.includes(e))throw new Error("Ups, I can't find the element.");u=a[d].triggerElements.indexOf(e),$=document.activeElement,history.pushState({parvus:"close"},"Image",window.location.href),ge();document.querySelectorAll('body > *:not([aria-hidden="true"])').forEach((e=>{e.setAttribute("aria-hidden","true"),e.classList.add("parvus-hidden")})),c.hideScrollbar&&(document.body.style.marginInlineEnd=`${i()}px`,document.body.style.overflow="hidden"),m.classList.add("parvus--is-opening"),m.setAttribute("aria-hidden","false"),(()=>{const e=document.createElement("div");e.className="parvus__slider",e.setAttribute("aria-hidden","true"),a[d].slider=e,m.appendChild(e)})(),Y(u),a[d].slider.setAttribute("aria-hidden","false"),V(),ee(),K(),J(),se(),O(u),P(e,u,(()=>{R(u,!0),m.classList.remove("parvus--is-opening"),a[d].slider.classList.add("parvus__slider--animate")})),D(u+1),D(u-1),fe("open",{source:e})},H=()=>{if(!be())throw new Error("Ups, I'm already closed.");const e=a[d].contentElements[u],t=a[d].triggerElements[u];he(),Q(),"close"===history.state?.parvus&&history.back();document.querySelectorAll(".parvus-hidden").forEach((e=>{e.removeAttribute("aria-hidden"),e.classList.remove("parvus-hidden")})),m.classList.add("parvus--is-closing"),requestAnimationFrame((()=>{const r=t.getBoundingClientRect();if(e&&"IMG"===e.tagName){const t=e.getBoundingClientRect(),i=r.width/t.width,n=r.height/t.height,s=r.left-t.left,a=r.top-t.top;e.style.transform=`translate(${s}px, ${a}px) scale(${i}, ${n})`}e.style.opacity=0,e.style.transition=`transform ${T}ms ${c.transitionTimingFunction}, opacity ${T}ms ${c.transitionTimingFunction} ${T/2}ms`}));const r=()=>{G(u),$=c.backFocus?$:a[d].triggerElements[u],$.focus({preventScroll:!0}),m.setAttribute("aria-hidden","true"),m.classList.remove("parvus--is-closing"),m.classList.remove("parvus--is-vertical-closing"),e.style.transform="",e.removeEventListener("transitionend",r),a[d].slider.remove(),a[d].slider=null,a[d].sliderElements=[],a[d].contentElements=[],w.removeAttribute("aria-hidden"),E.removeAttribute("aria-hidden"),E.removeAttribute("aria-disabled"),A.removeAttribute("aria-hidden"),A.removeAttribute("aria-disabled"),c.hideScrollbar&&(document.body.style.marginInlineEnd="",document.body.style.overflow="")};e.addEventListener("transitionend",r,{once:!0}),fe("close",{detail:{source:a[d].triggerElements[u]}})},D=e=>{e<0||e>=a[d].triggerElements.length||void 0!==a[d].sliderElements[e]||(Y(e),P(a[d].triggerElements[e],e,(()=>{R(e)})))},O=e=>{a[d].sliderElements[e].setAttribute("aria-hidden","false")},P=(e,t,r)=>{const{contentElements:i,sliderElements:n}=a[d];if(void 0!==i[t])return void(r&&"function"==typeof r&&r());const s=n[t].querySelector("div"),o=new Image,l=document.createElement("div"),u=e.querySelector("img"),m=document.createElement("div");l.className="parvus__content",m.className="parvus__loader",m.setAttribute("role","progressbar"),m.setAttribute("aria-label",c.l10n.lightboxLoadingIndicatorLabel),s.appendChild(m);new Promise(((e,t)=>{o.onload=()=>e(o),o.onerror=e=>t(e)})).then((r=>{r.style.opacity=0,l.appendChild(r),s.appendChild(l),c.captions&&((e,t,r)=>{const i=document.createElement("div");let n=null;if(i.className="parvus__caption","self"===c.captionsSelector)t.hasAttribute(c.captionsAttribute)&&""!==t.getAttribute(c.captionsAttribute)&&(n=t.getAttribute(c.captionsAttribute));else{const e=t.querySelector(c.captionsSelector);null!==e&&(n=e.hasAttribute(c.captionsAttribute)&&""!==e.getAttribute(c.captionsAttribute)?e.getAttribute(c.captionsAttribute):e.innerHTML)}if(null!==n){const t=`parvus__caption-${r}`;i.setAttribute("aria-labelledby",t),i.id=t,i.innerHTML=`

${n}

`,e.appendChild(i)}})(s,e,t),i[t]=r,r.setAttribute("width",r.naturalWidth),r.setAttribute("height",r.naturalHeight),re(n[t],r)})).catch((()=>{const e=document.createElement("div");e.classList.add("parvus__content"),e.classList.add("parvus__content--error"),e.innerHTML=`${c.l10n.lightboxLoadingError}`,s.appendChild(e),i[t]=e})).finally((()=>{s.removeChild(m),r&&"function"==typeof r&&r()})),e.hasAttribute("data-sizes")&&""!==e.getAttribute("data-sizes")&&o.setAttribute("sizes",e.getAttribute("data-sizes")),e.hasAttribute("data-srcset")&&""!==e.getAttribute("data-srcset")&&o.setAttribute("srcset",e.getAttribute("data-srcset")),"A"===e.tagName?o.setAttribute("src",e.href):o.setAttribute("src",e.getAttribute("data-target")),u&&u.hasAttribute("alt")&&""!==u.getAttribute("alt")?o.alt=u.alt:e.hasAttribute("data-alt")&&""!==e.getAttribute("data-alt")?o.alt=e.getAttribute("data-alt"):o.alt=""},R=(e,t)=>{const r=a[d].contentElements[e];if(r&&"IMG"===r.tagName){const i=a[d].triggerElements[e];if(t){const e=r.getBoundingClientRect(),t=i.getBoundingClientRect(),n=t.width/e.width,s=t.height/e.height,a=t.left-e.left,o=t.top-e.top;requestAnimationFrame((()=>{r.style.transform=`translate(${a}px, ${o}px) scale(${n}, ${s})`,r.style.transition="transform 0s, opacity 0s",requestAnimationFrame((()=>{r.style.transform="",r.style.opacity=1,r.style.transition=`transform ${T}ms ${c.transitionTimingFunction}, opacity ${T/2}ms ${c.transitionTimingFunction}`}))}))}else r.style.opacity=1}else r.style.opacity=1},j=e=>{const t=u;if(!be())throw new Error("Oops, I'm closed.");{if("number"!=typeof e||isNaN(e))throw new Error("Oops, no slide specified.");const t=a[d].triggerElements;if(e===u)throw new Error(`Oops, slide ${e} is already selected.`);if(e<-1||e>=t.length)throw new Error(`Oops, I can't find slide ${e}.`)}void 0!==a[d].sliderElements[e]||(Y(e),P(a[d].triggerElements[e],e,(()=>{R(e)}))),O(e),u=e,V(),et&&(K(),D(e+1)),G(t),J(),fe("select",{detail:{source:a[d].triggerElements[u]}})},U=()=>{u>0&&j(u-1)},W=()=>{const{triggerElements:e}=a[d];u{void 0!==a[d].sliderElements[e]&&a[d].sliderElements[e].setAttribute("aria-hidden","true")},V=()=>{d=null!==d?d:l,k=-u*m.offsetWidth,a[d].slider.style.transform=`translate3d(${k}px, 0, 0)`,I=k},K=()=>{const{triggerElements:e}=a[d],t=e.length,r=u===t-1;t>1&&(0===u?(E.setAttribute("aria-disabled","true"),A.removeAttribute("aria-disabled")):r?(E.removeAttribute("aria-disabled"),A.setAttribute("aria-disabled","true")):(E.removeAttribute("aria-disabled"),A.removeAttribute("aria-disabled")))},J=()=>{w.textContent=`${u+1}/${a[d].triggerElements.length}`},Q=()=>{L={startX:0,endX:0,startY:0,endY:0}},Z=()=>{const{startX:e,startY:t,endX:r,endY:i}=L,n=r-e,s=i-t,o=Math.abs(n),l=Math.abs(s),{triggerElements:g}=a[d],h=g.length;_?n>2&&o>=c.threshold&&u>0?U():n<2&&o>=c.threshold&&u!==h-1?W():V():x?(l>2&&c.swipeClose&&l>=c.threshold?H():(m.classList.remove("parvus--is-vertical-closing"),V()),p.style.opacity=""):V()},ee=()=>{const e=a[d].triggerElements.length,t=a[d].slider,r=a[d].sliderElements,i=c.simulateTouch||ve(),n=t.classList.contains("parvus__slider--is-draggable");i&&c.swipeClose&&!n||i&&e>1&&!n?t.classList.add("parvus__slider--is-draggable"):t.classList.remove("parvus__slider--is-draggable"),e>1?(t.setAttribute("role","region"),t.setAttribute("aria-roledescription","carousel"),t.setAttribute("aria-label",c.l10n.sliderLabel),r.forEach(((t,r)=>{t.setAttribute("role","group"),t.setAttribute("aria-label",`${c.l10n.slideLabel} ${r+1}/${e}`)}))):(t.removeAttribute("role"),t.removeAttribute("aria-roledescription"),t.removeAttribute("aria-label"),r.forEach((e=>{e.removeAttribute("role"),e.removeAttribute("aria-label")}))),1===e?(w.setAttribute("aria-hidden","true"),E.setAttribute("aria-hidden","true"),A.setAttribute("aria-hidden","true")):(w.removeAttribute("aria-hidden"),E.removeAttribute("aria-hidden"),A.removeAttribute("aria-hidden"))},te=()=>{S||(S=!0,r.requestAnimationFrame((()=>{a[d].sliderElements.forEach(((e,t)=>{re(e,a[d].contentElements[t])})),V(),S=!1})))},re=(e,t)=>{if("IMG"!==t.tagName)return;const r=getComputedStyle(e),i=e.querySelector(".parvus__caption"),n=i?i.getBoundingClientRect().height:0,s=t.getAttribute("height"),a=t.getAttribute("width");let o=e.offsetHeight,l=e.offsetWidth;o-=parseFloat(r.paddingTop)+parseFloat(r.paddingBottom)+parseFloat(n),l-=parseFloat(r.paddingLeft)+parseFloat(r.paddingRight);const d=Math.min(l/a||0,o/s),u=a*d||0,c=s*d||0;s>c&&su&&a{const{target:t}=e;t===E?U():t===A?W():(t===y||c.docClose&&!x&&!_&&t.classList.contains("parvus__slide"))&&H(),e.stopPropagation()},se=()=>{t(m)[0].focus()},ae=e=>{const r=t(m),i=r.indexOf(document.activeElement),n=r.length-1;switch(e.code){case"Tab":e.shiftKey?0===i&&(r[n].focus(),e.preventDefault()):i===n&&(r[0].focus(),e.preventDefault());break;case"Escape":H(),e.preventDefault();break;case"ArrowLeft":U(),e.preventDefault();break;case"ArrowRight":W(),e.preventDefault()}},oe=e=>{_=!1,x=!1,C=!0;const{pageX:t,pageY:r}=e;L.startX=t,L.startY=r;const{slider:i}=a[d];i.classList.add("parvus__slider--is-dragging"),i.style.willChange="transform",e.stopPropagation(),g=getComputedStyle(p).opacity},le=e=>{if(C){const{pageX:t,pageY:r}=e;L.endX=t,L.endY=r,pe()}e.preventDefault()},de=()=>{C=!1;const{slider:e}=a[d];e.classList.remove("parvus__slider--is-dragging"),e.style.willChange="",(L.endX||L.endY)&&Z(),Q()},ue=e=>{_=!1,x=!1;const{clientX:t,clientY:r}=e.changedTouches[0];L.startX=parseInt(t,10),L.startY=parseInt(r,10);const{slider:i}=a[d];i.classList.add("parvus__slider--is-dragging"),i.style.willChange="transform",g=getComputedStyle(p).getPropertyValue("opacity"),e.stopPropagation()},ce=e=>{const{clientX:t,clientY:r}=e.changedTouches[0];L.endX=parseInt(t,10),L.endY=parseInt(r,10),pe(),e.preventDefault()},me=()=>{const{slider:e}=a[d];e.classList.remove("parvus__slider--is-dragging"),e.style.willChange="",(L.endX||L.endY)&&Z(),Q()},pe=()=>{const{startX:e,endX:t,startY:r,endY:i}=L,n=e-t,s=i-r,o=Math.abs(s);Math.abs(n)>2&&!x&&a[d].triggerElements.length>1?(a[d].slider.style.transform=`translate3d(${I-Math.round(n)}px, 0, 0)`,_=!0,x=!1):Math.abs(s)>2&&!_&&c.swipeClose&&(!M&&o<=100&&(p.style.opacity=g-o/100),m.classList.add("parvus--is-vertical-closing"),a[d].slider.style.transform=`translate3d(${I}px, ${Math.round(s)}px, 0)`,_=!1,x=!0)},ge=()=>{r.addEventListener("keydown",ae),r.addEventListener("resize",te),r.addEventListener("popstate",H),m.addEventListener("click",ne),ve()&&(m.addEventListener("touchstart",ue),m.addEventListener("touchmove",ce),m.addEventListener("touchend",me)),c.simulateTouch&&(m.addEventListener("mousedown",oe),m.addEventListener("mouseup",de),m.addEventListener("mousemove",le))},he=()=>{r.removeEventListener("keydown",ae),r.removeEventListener("resize",te),r.removeEventListener("popstate",H),m.removeEventListener("click",ne),ve()&&(m.removeEventListener("touchstart",ue),m.removeEventListener("touchmove",ce),m.removeEventListener("touchend",me)),c.simulateTouch&&(m.removeEventListener("mousedown",oe),m.removeEventListener("mouseup",de),m.removeEventListener("mousemove",le))},be=()=>"false"===m.getAttribute("aria-hidden"),ve=()=>"ontouchstart"in window,fe=(e,t={})=>{const r=new CustomEvent(e,{detail:t,cancelable:!0});m.dispatchEvent(r)},Ee=()=>{if(c=(e=>{const t={loadEmpty:!1,selector:".lightbox",gallerySelector:null,captions:!0,captionsSelector:"self",captionsAttribute:"data-caption",docClose:!0,swipeClose:!0,simulateTouch:!0,threshold:50,backFocus:!0,hideScrollbar:!0,transitionDuration:300,transitionTimingFunction:"cubic-bezier(0.62, 0.16, 0.13, 1.01)",lightboxIndicatorIcon:'',previousButtonIcon:'',nextButtonIcon:'',closeButtonIcon:'',l10n:n};return{...t,...e,l10n:{...t.l10n,...e.l10n}}})(e),!c.loadEmpty&&!document.querySelectorAll(c.selector).length)return;if(N(),m||(m=document.createElement("div"),m.setAttribute("role","dialog"),m.setAttribute("aria-modal","true"),m.setAttribute("aria-hidden","true"),m.setAttribute("tabindex","-1"),m.setAttribute("aria-label",c.l10n.lightboxLabel),m.classList.add("parvus"),p=document.createElement("div"),p.classList.add("parvus__overlay"),m.appendChild(p),h=document.createElement("div"),h.className="parvus__toolbar",b=document.createElement("div"),v=document.createElement("div"),f=document.createElement("div"),f.className="parvus__controls",f.setAttribute("role","group"),f.setAttribute("aria-label",c.l10n.controlsLabel),v.appendChild(f),y=document.createElement("button"),y.className="parvus__btn parvus__btn--close",y.setAttribute("type","button"),y.setAttribute("aria-label",c.l10n.closeButtonLabel),y.innerHTML=c.closeButtonIcon,f.appendChild(y),E=document.createElement("button"),E.className="parvus__btn parvus__btn--previous",E.setAttribute("type","button"),E.setAttribute("aria-label",c.l10n.previousButtonLabel),E.innerHTML=c.previousButtonIcon,f.appendChild(E),A=document.createElement("button"),A.className="parvus__btn parvus__btn--next",A.setAttribute("type","button"),A.setAttribute("aria-label",c.l10n.nextButtonLabel),A.innerHTML=c.nextButtonIcon,f.appendChild(A),w=document.createElement("div"),w.className="parvus__counter",b.appendChild(w),h.appendChild(b),h.appendChild(v),m.appendChild(h),document.body.appendChild(m)),null!==c.gallerySelector){document.querySelectorAll(c.gallerySelector).forEach(((e,t)=>{const r=t;e.querySelectorAll(c.selector).forEach((e=>{e.setAttribute("data-group",`parvus-gallery-${r}`),F(e)}))}))}document.querySelectorAll(`${c.selector}:not(.parvus-trigger)`).forEach(F)};return Ee(),{init:Ee,open:z,close:H,select:j,previous:U,next:W,currentIndex:()=>u,add:F,remove:X,destroy:()=>{if(!m)return;be()&&H(),m.remove();document.querySelectorAll(".parvus-trigger").forEach(X),fe("destroy")},isOpen:be,on:(e,t)=>{m&&m.addEventListener(e,t)},off:(e,t)=>{m&&m.removeEventListener(e,t)}}}})); +!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";const e=['a:not([inert]):not([tabindex^="-"])','button:not([inert]):not([tabindex^="-"]):not(:disabled)','[tabindex]:not([inert]):not([tabindex^="-"])'],t=t=>Array.from(t.querySelectorAll(e.join(", "))).filter((e=>null!==e.offsetParent)),r=window,i=()=>r.innerWidth-document.documentElement.clientWidth;var n={lightboxLabel:"This is a dialog window that overlays the main content of the page. The modal displays 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",lightboxLoadingError:"The requested image cannot be loaded.",controlsLabel:"Controls",previousButtonLabel:"Previous image",nextButtonLabel:"Next image",closeButtonLabel:"Close dialog window",sliderLabel:"Images",slideLabel:"Image"};return function(e){const r=window,s={triggerElements:[],slider:null,sliderElements:[],contentElements:[]},a={};let o=0,l=null,d=null,u=0,c={},m=null,p=null,g=1,h=null,b=null,v=null,f=null,E=null,A=null,y=null,w=null,L={},_=!1,x=!1,C=!1,$=null,k=null,I=null,S=!1,T=null,M=!0;const B=window.matchMedia("(prefers-reduced-motion)"),N=()=>{B.matches?(M=!0,T=.1):(M=!1,T=c.transitionDuration)};B.addEventListener("change",N);const q=e=>{const t=e.dataset.group||`default-${o}`;return++o,e.hasAttribute("data-group")||e.setAttribute("data-group",t),t},F=e=>{if(m){if(!("A"===e.tagName&&e.hasAttribute("href")||"BUTTON"===e.tagName&&e.hasAttribute("data-target")))throw new Error("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.");if(l=q(e),a[l]||(a[l]=structuredClone(s)),a[l].triggerElements.includes(e))throw new Error("Ups, element already added.");if(a[l].triggerElements.push(e),(e=>{if(e.querySelector("img")){const t=document.createElement("div");e.classList.add("parvus-zoom"),t.className="parvus-zoom__indicator",t.innerHTML=c.lightboxIndicatorIcon,e.appendChild(t)}})(e),e.classList.add("parvus-trigger"),e.addEventListener("click",ie),be()&&l===d){const t=a[l].triggerElements.indexOf(e);Y(t),P(e,t,(()=>{R(t)})),ee(),K(),J()}}},X=e=>{if(!e||!e.hasAttribute("data-group"))return;const t=q(e);if(!a[t]||!a[t].triggerElements.includes(e))return;const r=a[t].triggerElements.indexOf(e);if(a[t].triggerElements.splice(r,1),a[t].sliderElements.splice(r,1),e.classList.contains("parvus-zoom")){const t=e.querySelector(".parvus-zoom__indicator");e.classList.remove("parvus-zoom"),e.removeChild(t)}be()&&t===d&&(ee(),K(),J()),e.removeEventListener("click",ie),e.classList.remove("parvus-trigger")},Y=e=>{if(void 0!==a[d].sliderElements[e])return;const t=document.createElement("div"),r=document.createElement("div"),i=a[d].triggerElements.length;if(t.className="parvus__slide",t.style.position="absolute",t.style.left=100*e+"%",t.setAttribute("aria-hidden","true"),t.appendChild(r),i>1&&(t.setAttribute("role","group"),t.setAttribute("aria-label",`${c.l10n.slideLabel} ${e+1}/${i}`)),a[d].sliderElements[e]=t,e>=u){const r=(e=>{const t=a[d].sliderElements,r=t.length;for(let i=e+1;i{const t=a[d].sliderElements;for(let r=e-1;r>=0;r--)if(void 0!==t[r])return r;return-1})(e);-1!==r?a[d].sliderElements[r].after(t):a[d].slider.prepend(t)}},z=e=>{if(!m||!e||!e.classList.contains("parvus-trigger")||be())return;if(d=q(e),!a[d].triggerElements.includes(e))throw new Error("Ups, I can't find the element.");u=a[d].triggerElements.indexOf(e),$=document.activeElement,history.pushState({parvus:"close"},"Image",window.location.href),ge();document.querySelectorAll('body > *:not([aria-hidden="true"])').forEach((e=>{e.setAttribute("aria-hidden","true"),e.classList.add("parvus-hidden")})),c.hideScrollbar&&(document.body.style.marginInlineEnd=`${i()}px`,document.body.style.overflow="hidden"),m.classList.add("parvus--is-opening"),m.setAttribute("aria-hidden","false"),(()=>{const e=document.createElement("div");e.className="parvus__slider",e.setAttribute("aria-hidden","true"),a[d].slider=e,m.appendChild(e)})(),Y(u),a[d].slider.setAttribute("aria-hidden","false"),V(),ee(),K(),J(),se(),O(u),P(e,u,(()=>{R(u,!0),m.classList.remove("parvus--is-opening"),a[d].slider.classList.add("parvus__slider--animate")})),D(u+1),D(u-1),fe("open",{source:e})},H=()=>{if(!be())throw new Error("Ups, I'm already closed.");const e=a[d].contentElements[u],t=a[d].triggerElements[u];he(),Q(),"close"===history.state?.parvus&&history.back();document.querySelectorAll(".parvus-hidden").forEach((e=>{e.removeAttribute("aria-hidden"),e.classList.remove("parvus-hidden")})),m.classList.add("parvus--is-closing"),requestAnimationFrame((()=>{const r=t.getBoundingClientRect();if(e&&"IMG"===e.tagName){const t=e.getBoundingClientRect(),i=r.width/t.width,n=r.height/t.height,s=r.left-t.left,a=r.top-t.top;e.style.transform=`translate(${s}px, ${a}px) scale(${i}, ${n})`}e.style.opacity=0,e.style.transition=`transform ${T}ms ${c.transitionTimingFunction}, opacity ${T}ms ${c.transitionTimingFunction} ${T/2}ms`}));const r=()=>{G(u),$=c.backFocus?$:a[d].triggerElements[u],$.focus({preventScroll:!0}),m.setAttribute("aria-hidden","true"),m.classList.remove("parvus--is-closing"),m.classList.remove("parvus--is-vertical-closing"),e.style.transform="",e.removeEventListener("transitionend",r),a[d].slider.remove(),a[d].slider=null,a[d].sliderElements=[],a[d].contentElements=[],w.removeAttribute("aria-hidden"),E.removeAttribute("aria-hidden"),E.removeAttribute("aria-disabled"),A.removeAttribute("aria-hidden"),A.removeAttribute("aria-disabled"),c.hideScrollbar&&(document.body.style.marginInlineEnd="",document.body.style.overflow="")};e.addEventListener("transitionend",r,{once:!0}),fe("close",{detail:{source:a[d].triggerElements[u]}})},D=e=>{e<0||e>=a[d].triggerElements.length||void 0!==a[d].sliderElements[e]||(Y(e),P(a[d].triggerElements[e],e,(()=>{R(e)})))},O=e=>{a[d].sliderElements[e].setAttribute("aria-hidden","false")},P=(e,t,r)=>{const{contentElements:i,sliderElements:n}=a[d];if(void 0!==i[t])return void(r&&"function"==typeof r&&r());const s=n[t].querySelector("div"),o=new Image,l=document.createElement("div"),u=e.querySelector("img"),m=document.createElement("div");l.className="parvus__content",m.className="parvus__loader",m.setAttribute("role","progressbar"),m.setAttribute("aria-label",c.l10n.lightboxLoadingIndicatorLabel),s.appendChild(m);new Promise(((e,t)=>{o.onload=()=>e(o),o.onerror=e=>t(e)})).then((r=>{r.style.opacity=0,l.appendChild(r),s.appendChild(l),c.captions&&((e,t,r)=>{const i=document.createElement("div");let n=null;if(i.className="parvus__caption","self"===c.captionsSelector)t.hasAttribute(c.captionsAttribute)&&""!==t.getAttribute(c.captionsAttribute)&&(n=t.getAttribute(c.captionsAttribute));else{const e=t.querySelector(c.captionsSelector);null!==e&&(n=e.hasAttribute(c.captionsAttribute)&&""!==e.getAttribute(c.captionsAttribute)?e.getAttribute(c.captionsAttribute):e.innerHTML)}if(null!==n){const t=`parvus__caption-${r}`;i.setAttribute("aria-labelledby",t),i.id=t,i.innerHTML=`

${n}

`,e.appendChild(i)}})(s,e,t),i[t]=r,r.setAttribute("width",r.naturalWidth),r.setAttribute("height",r.naturalHeight),re(n[t],r)})).catch((()=>{const e=document.createElement("div");e.classList.add("parvus__content"),e.classList.add("parvus__content--error"),e.innerHTML=`${c.l10n.lightboxLoadingError}`,s.appendChild(e),i[t]=e})).finally((()=>{s.removeChild(m),r&&"function"==typeof r&&r()})),e.hasAttribute("data-sizes")&&""!==e.getAttribute("data-sizes")&&o.setAttribute("sizes",e.getAttribute("data-sizes")),e.hasAttribute("data-srcset")&&""!==e.getAttribute("data-srcset")&&o.setAttribute("srcset",e.getAttribute("data-srcset")),"A"===e.tagName?o.setAttribute("src",e.href):o.setAttribute("src",e.getAttribute("data-target")),u&&u.hasAttribute("alt")&&""!==u.getAttribute("alt")?o.alt=u.alt:e.hasAttribute("data-alt")&&""!==e.getAttribute("data-alt")?o.alt=e.getAttribute("data-alt"):o.alt=""},R=(e,t)=>{const r=a[d].contentElements[e];if(r&&"IMG"===r.tagName){const i=a[d].triggerElements[e];if(t){const e=r.getBoundingClientRect(),t=i.getBoundingClientRect(),n=t.width/e.width,s=t.height/e.height,a=t.left-e.left,o=t.top-e.top;requestAnimationFrame((()=>{r.style.transform=`translate(${a}px, ${o}px) scale(${n}, ${s})`,r.style.transition="transform 0s, opacity 0s",requestAnimationFrame((()=>{r.style.transform="",r.style.opacity=1,r.style.transition=`transform ${T}ms ${c.transitionTimingFunction}, opacity ${T/2}ms ${c.transitionTimingFunction}`}))}))}else r.style.opacity=1}else r.style.opacity=1},j=e=>{const t=u;if(!be())throw new Error("Oops, I'm closed.");{if("number"!=typeof e||isNaN(e))throw new Error("Oops, no slide specified.");const t=a[d].triggerElements;if(e===u)throw new Error(`Oops, slide ${e} is already selected.`);if(e<-1||e>=t.length)throw new Error(`Oops, I can't find slide ${e}.`)}void 0!==a[d].sliderElements[e]||(Y(e),P(a[d].triggerElements[e],e,(()=>{R(e)}))),O(e),u=e,V(),et&&(K(),D(e+1)),G(t),J(),fe("select",{detail:{source:a[d].triggerElements[u]}})},U=()=>{u>0&&j(u-1)},W=()=>{const{triggerElements:e}=a[d];u{void 0!==a[d].sliderElements[e]&&a[d].sliderElements[e].setAttribute("aria-hidden","true")},V=()=>{d=null!==d?d:l,k=-u*m.offsetWidth,a[d].slider.style.transform=`translate3d(${k}px, 0, 0)`,I=k},K=()=>{const{triggerElements:e}=a[d],t=e.length,r=u===t-1;t>1&&(0===u?(E.setAttribute("aria-disabled","true"),A.removeAttribute("aria-disabled")):r?(E.removeAttribute("aria-disabled"),A.setAttribute("aria-disabled","true")):(E.removeAttribute("aria-disabled"),A.removeAttribute("aria-disabled")))},J=()=>{w.textContent=`${u+1}/${a[d].triggerElements.length}`},Q=()=>{L={startX:0,endX:0,startY:0,endY:0}},Z=()=>{const{startX:e,startY:t,endX:r,endY:i}=L,n=r-e,s=i-t,o=Math.abs(n),l=Math.abs(s),{triggerElements:g}=a[d],h=g.length;_?n>2&&o>=c.threshold&&u>0?U():n<2&&o>=c.threshold&&u!==h-1?W():V():x?(l>2&&c.swipeClose&&l>=c.threshold?H():(m.classList.remove("parvus--is-vertical-closing"),V()),p.style.opacity=""):V()},ee=()=>{const e=a[d].triggerElements.length,t=a[d].slider,r=a[d].sliderElements,i=c.simulateTouch||ve(),n=t.classList.contains("parvus__slider--is-draggable");i&&c.swipeClose&&!n||i&&e>1&&!n?t.classList.add("parvus__slider--is-draggable"):t.classList.remove("parvus__slider--is-draggable"),e>1?(t.setAttribute("role","region"),t.setAttribute("aria-roledescription","carousel"),t.setAttribute("aria-label",c.l10n.sliderLabel),r.forEach(((t,r)=>{t.setAttribute("role","group"),t.setAttribute("aria-label",`${c.l10n.slideLabel} ${r+1}/${e}`)}))):(t.removeAttribute("role"),t.removeAttribute("aria-roledescription"),t.removeAttribute("aria-label"),r.forEach((e=>{e.removeAttribute("role"),e.removeAttribute("aria-label")}))),1===e?(w.setAttribute("aria-hidden","true"),E.setAttribute("aria-hidden","true"),A.setAttribute("aria-hidden","true")):(w.removeAttribute("aria-hidden"),E.removeAttribute("aria-hidden"),A.removeAttribute("aria-hidden"))},te=()=>{S||(S=!0,r.requestAnimationFrame((()=>{a[d].sliderElements.forEach(((e,t)=>{re(e,a[d].contentElements[t])})),V(),S=!1})))},re=(e,t)=>{if("IMG"!==t.tagName)return;const r=getComputedStyle(e),i=e.querySelector(".parvus__caption"),n=i?i.getBoundingClientRect().height:0,s=t.getAttribute("height"),a=t.getAttribute("width");let o=e.offsetHeight,l=e.offsetWidth;o-=parseFloat(r.paddingTop)+parseFloat(r.paddingBottom)+parseFloat(n),l-=parseFloat(r.paddingLeft)+parseFloat(r.paddingRight);const d=Math.min(l/a||0,o/s),u=a*d||0,c=s*d||0;s>c&&su&&a{const{target:t}=e;t===E?U():t===A?W():(t===y||c.docClose&&!x&&!_&&t.classList.contains("parvus__slide"))&&H(),e.stopPropagation()},se=()=>{t(m)[0].focus()},ae=e=>{const r=t(m),i=r.indexOf(document.activeElement),n=r.length-1;switch(e.code){case"Tab":e.shiftKey?0===i&&(r[n].focus(),e.preventDefault()):i===n&&(r[0].focus(),e.preventDefault());break;case"Escape":H(),e.preventDefault();break;case"ArrowLeft":U(),e.preventDefault();break;case"ArrowRight":W(),e.preventDefault()}},oe=e=>{_=!1,x=!1,C=!0;const{pageX:t,pageY:r}=e;L.startX=t,L.startY=r;const{slider:i}=a[d];i.classList.add("parvus__slider--is-dragging"),i.style.willChange="transform",e.stopPropagation(),g=getComputedStyle(p).opacity},le=e=>{if(C){const{pageX:t,pageY:r}=e;L.endX=t,L.endY=r,pe()}e.preventDefault()},de=()=>{C=!1;const{slider:e}=a[d];e.classList.remove("parvus__slider--is-dragging"),e.style.willChange="",(L.endX||L.endY)&&Z(),Q()},ue=e=>{_=!1,x=!1;const{clientX:t,clientY:r}=e.changedTouches[0];L.startX=parseInt(t,10),L.startY=parseInt(r,10);const{slider:i}=a[d];i.classList.add("parvus__slider--is-dragging"),i.style.willChange="transform",g=getComputedStyle(p).getPropertyValue("opacity"),e.stopPropagation()},ce=e=>{const{clientX:t,clientY:r}=e.changedTouches[0];L.endX=parseInt(t,10),L.endY=parseInt(r,10),pe(),e.preventDefault()},me=()=>{const{slider:e}=a[d];e.classList.remove("parvus__slider--is-dragging"),e.style.willChange="",(L.endX||L.endY)&&Z(),Q()},pe=()=>{const{startX:e,endX:t,startY:r,endY:i}=L,n=e-t,s=i-r,o=Math.abs(s);Math.abs(n)>2&&!x&&a[d].triggerElements.length>1?(a[d].slider.style.transform=`translate3d(${I-Math.round(n)}px, 0, 0)`,_=!0,x=!1):Math.abs(s)>2&&!_&&c.swipeClose&&(!M&&o<=100&&(p.style.opacity=g-o/100),m.classList.add("parvus--is-vertical-closing"),a[d].slider.style.transform=`translate3d(${I}px, ${Math.round(s)}px, 0)`,_=!1,x=!0)},ge=()=>{r.addEventListener("keydown",ae),r.addEventListener("resize",te),r.addEventListener("popstate",H),m.addEventListener("click",ne),ve()&&(m.addEventListener("touchstart",ue),m.addEventListener("touchmove",ce),m.addEventListener("touchend",me)),c.simulateTouch&&(m.addEventListener("mousedown",oe),m.addEventListener("mouseup",de),m.addEventListener("mousemove",le))},he=()=>{r.removeEventListener("keydown",ae),r.removeEventListener("resize",te),r.removeEventListener("popstate",H),m.removeEventListener("click",ne),ve()&&(m.removeEventListener("touchstart",ue),m.removeEventListener("touchmove",ce),m.removeEventListener("touchend",me)),c.simulateTouch&&(m.removeEventListener("mousedown",oe),m.removeEventListener("mouseup",de),m.removeEventListener("mousemove",le))},be=()=>"false"===m.getAttribute("aria-hidden"),ve=()=>"ontouchstart"in window,fe=(e,t={})=>{const r=new CustomEvent(e,{detail:t,cancelable:!0});m.dispatchEvent(r)},Ee=()=>{if(c=(e=>{const t={loadEmpty:!1,selector:".lightbox",gallerySelector:null,captions:!0,captionsSelector:"self",captionsAttribute:"data-caption",docClose:!0,swipeClose:!0,simulateTouch:!0,threshold:50,backFocus:!0,hideScrollbar:!0,transitionDuration:300,transitionTimingFunction:"cubic-bezier(0.62, 0.16, 0.13, 1.01)",lightboxIndicatorIcon:'',previousButtonIcon:'',nextButtonIcon:'',closeButtonIcon:'',l10n:n},r={...t,...e};return e&&e.l10n&&(r.l10n={...t.l10n,...e.l10n}),r})(e),!c.loadEmpty&&!document.querySelectorAll(c.selector).length)return;if(N(),m||(m=document.createElement("div"),m.setAttribute("role","dialog"),m.setAttribute("aria-modal","true"),m.setAttribute("aria-hidden","true"),m.setAttribute("tabindex","-1"),m.setAttribute("aria-label",c.l10n.lightboxLabel),m.classList.add("parvus"),p=document.createElement("div"),p.classList.add("parvus__overlay"),m.appendChild(p),h=document.createElement("div"),h.className="parvus__toolbar",b=document.createElement("div"),v=document.createElement("div"),f=document.createElement("div"),f.className="parvus__controls",f.setAttribute("role","group"),f.setAttribute("aria-label",c.l10n.controlsLabel),v.appendChild(f),y=document.createElement("button"),y.className="parvus__btn parvus__btn--close",y.setAttribute("type","button"),y.setAttribute("aria-label",c.l10n.closeButtonLabel),y.innerHTML=c.closeButtonIcon,f.appendChild(y),E=document.createElement("button"),E.className="parvus__btn parvus__btn--previous",E.setAttribute("type","button"),E.setAttribute("aria-label",c.l10n.previousButtonLabel),E.innerHTML=c.previousButtonIcon,f.appendChild(E),A=document.createElement("button"),A.className="parvus__btn parvus__btn--next",A.setAttribute("type","button"),A.setAttribute("aria-label",c.l10n.nextButtonLabel),A.innerHTML=c.nextButtonIcon,f.appendChild(A),w=document.createElement("div"),w.className="parvus__counter",b.appendChild(w),h.appendChild(b),h.appendChild(v),m.appendChild(h),document.body.appendChild(m)),null!==c.gallerySelector){document.querySelectorAll(c.gallerySelector).forEach(((e,t)=>{const r=t;e.querySelectorAll(c.selector).forEach((e=>{e.setAttribute("data-group",`parvus-gallery-${r}`),F(e)}))}))}document.querySelectorAll(`${c.selector}:not(.parvus-trigger)`).forEach(F)};return Ee(),{init:Ee,open:z,close:H,select:j,previous:U,next:W,currentIndex:()=>u,add:F,remove:X,destroy:()=>{if(!m)return;be()&&H(),m.remove();document.querySelectorAll(".parvus-trigger").forEach(X),fe("destroy")},isOpen:be,on:(e,t)=>{m&&m.addEventListener(e,t)},off:(e,t)=>{m&&m.removeEventListener(e,t)}}}})); diff --git a/package.json b/package.json index 098318f..f4c9e98 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "parvus", "type": "module", - "version": "2.5.0", + "version": "2.5.1", "description": "An accessible, open-source image lightbox with no dependencies.", "main": "./dist/js/parvus.js", "module": "./dist/js/parvus.esm.js", diff --git a/src/js/parvus.js b/src/js/parvus.js index 6d942c0..87f96e8 100644 --- a/src/js/parvus.js +++ b/src/js/parvus.js @@ -74,14 +74,19 @@ export default function Parvus (userOptions) { l10n: en } - return { + const MERGED_OPTIONS = { ...DEFAULT_OPTIONS, - ...userOptions, - l10n: { + ...userOptions + } + + if (userOptions && userOptions.l10n) { + MERGED_OPTIONS.l10n = { ...DEFAULT_OPTIONS.l10n, ...userOptions.l10n } } + + return MERGED_OPTIONS } /** @@ -148,6 +153,10 @@ export default function Parvus (userOptions) { * @param {HTMLElement} el - The element to be added */ const add = (el) => { + if (!lightbox) { + return + } + if (!((el.tagName === 'A' && el.hasAttribute('href')) || (el.tagName === 'BUTTON' && el.hasAttribute('data-target')))) { throw new Error('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.') }