zoomora 1.0.0 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,10 +1,10 @@
1
- !function(t){"function"==typeof define&&define.amd?define(t):t()}(function(){"use strict";var t,e,s=Object.defineProperty,o=Object.defineProperties,i=Object.getOwnPropertyDescriptors,n=Object.getOwnPropertySymbols,a=Object.prototype.hasOwnProperty,r=Object.prototype.propertyIsEnumerable,l=(t,e,o)=>e in t?s(t,e,{enumerable:!0,configurable:!0,writable:!0,value:o}):t[e]=o,h=(t,e)=>{for(var s in e||(e={}))a.call(e,s)&&l(t,s,e[s]);if(n)for(var s of n(e))r.call(e,s)&&l(t,s,e[s]);return t};
1
+ !function(t){"function"==typeof define&&define.amd?define(t):t()}(function(){"use strict";var t,e,s=Object.defineProperty,i=Object.defineProperties,n=Object.getOwnPropertyDescriptors,o=Object.getOwnPropertySymbols,a=Object.prototype.hasOwnProperty,r=Object.prototype.propertyIsEnumerable,l=(t,e,i)=>e in t?s(t,e,{enumerable:!0,configurable:!0,writable:!0,value:i}):t[e]=i,h=(t,e)=>{for(var s in e||(e={}))a.call(e,s)&&l(t,s,e[s]);if(o)for(var s of o(e))r.call(e,s)&&l(t,s,e[s]);return t};
2
2
  /*!
3
- * Zoomora Lightbox Plugin v1.0.0
3
+ * Zoomora Lightbox Plugin v1.1.0
4
4
  * A modern, responsive lightbox plugin with zoom, fullscreen, and gallery features
5
5
  *
6
6
  * Copyright (c) 2025 Faruk Ahmed (FrontTheme)
7
7
  * Licensed under MIT License
8
8
  */
9
- t="undefined"!=typeof window?window:void 0,e=function(){class t{static get defaults(){return{selector:"[data-zoomora]",showCounter:!0,showThumbnails:!0,showFullscreen:!0,showZoom:!0,transition:"fade",useHref:!1,maxZoomScale:3,zoomStep:.1,animationDuration:300,onOpen:null,onClose:null,onNext:null,onPrev:null,showAutoHideToggle:!0,autoHideDelay:3e3,autoHideEnabled:!1}}constructor(e={}){this.options=h(h({},t.defaults),e),this.currentIndex=0,this.items=[],this.isZoomed=!1,this.isFullscreen=!1,this.isDragging=!1,this.thumbnailsVisible=!0,this.startX=0,this.startY=0,this.currentX=0,this.currentY=0,this.currentScale=1,this.isInitialized=!1,this.eventListeners=new Map,this.autoHideEnabled=!1,this.autoHideTimeout=null,this.autoHideDelay=3e3,this.isControlsVisible=!0,this.idleTimer=null,this.boundMethods={handleDocumentClick:this.handleDocumentClick.bind(this),handleKeydown:this.handleKeydown.bind(this),handleFullscreenChange:this.handleFullscreenChange.bind(this),handleZoomoraClick:this.handleZoomoraClick.bind(this),handleContentClick:this.handleContentClick.bind(this),handleMouseDown:this.handleMouseDown.bind(this),handleMouseMove:this.handleMouseMove.bind(this),handleMouseUp:this.handleMouseUp.bind(this),handleTouchStart:this.handleTouchStart.bind(this),handleTouchMove:this.handleTouchMove.bind(this),handleTouchEnd:this.handleTouchEnd.bind(this)},this.init()}init(){if(this.isInitialized)console.warn("Zoomora: Plugin already initialized");else try{this.createLightbox(),this.bindEvents(),this.isInitialized=!0}catch(t){console.error("Zoomora: Initialization failed",t)}}static bind(e,s={}){const n=(a=h({},s),o(a,i({selector:e,useHref:!0})));var a;return new t(n)}createLightbox(){if(document.getElementById("zoomoraLightbox"))console.warn("Zoomora: Lightbox already exists in DOM");else if(document.body.insertAdjacentHTML("beforeend",'\n <div class="zoomora" id="zoomoraLightbox">\n <div class="zoomora-container">\n <div class="zoomora-header" id="zoomoraHeader">\n <div class="zoomora-counter" id="zoomoraCounter">1 / 1</div>\n <div class="zoomora-controls">\n <button class="zoomora-btn" id="zoomoraThumbnailBtn" title="Toggle Thumbnails">\n <i class="zoomorai-thumbnails"></i>\n </button>\n <button class="zoomora-btn" id="zoomoraAutoHideBtn" title="Toggle Auto-Hide Controls">\n <i class="zoomorai-controls-off"></i>\n </button>\n <button class="zoomora-btn" id="zoomoraZoomBtn" title="Zoom">\n <i class="zoomorai-zoom"></i>\n </button>\n <button class="zoomora-btn" id="zoomoraFullscreenBtn" title="Fullscreen">\n <i class="zoomorai-expand"></i>\n </button>\n <button class="zoomora-btn" id="zoomoraCollapseBtn" title="Exit Fullscreen" style="display: none;">\n <i class="zoomorai-collapse"></i>\n </button>\n <button class="zoomora-btn" id="zoomoraCloseBtn" title="Close">\n <i class="zoomorai-close"></i>\n </button>\n </div>\n </div>\n \n <div class="zoomora-content" id="zoomoraContent">\n <div class="zoomora-loading" id="zoomoraLoading"></div>\n <div class="zoomora-slides-container" id="zoomoraSlidesContainer"></div>\n </div>\n \n <button class="zoomora-nav prev" id="zoomoraPrevBtn">\n <i class="zoomorai-arrow-left"></i>\n </button>\n <button class="zoomora-nav next" id="zoomoraNextBtn">\n <i class="zoomorai-arrow-right"></i>\n </button>\n \n <div class="zoomora-caption" id="zoomoraCaption"></div>\n <div class="zoomora-thumbnails" id="zoomoraThumbs"></div>\n </div>\n </div>\n '),this.zoomora=document.getElementById("zoomoraLightbox"),this.header=document.getElementById("zoomoraHeader"),this.content=document.getElementById("zoomoraContent"),this.slidesContainer=document.getElementById("zoomoraSlidesContainer"),this.counter=document.getElementById("zoomoraCounter"),this.thumbs=document.getElementById("zoomoraThumbs"),this.loading=document.getElementById("zoomoraLoading"),this.caption=document.getElementById("zoomoraCaption"),this.prevBtn=document.getElementById("zoomoraPrevBtn"),this.nextBtn=document.getElementById("zoomoraNextBtn"),!(this.zoomora&&this.content&&this.counter&&this.thumbs&&this.loading&&this.caption))throw new Error("Failed to create required DOM elements")}bindEvents(){this.addEventListener(document,"click",this.boundMethods.handleDocumentClick),this.addEventListener(document.getElementById("zoomoraCloseBtn"),"click",()=>this.close()),this.addEventListener(document.getElementById("zoomoraPrevBtn"),"click",()=>this.prev()),this.addEventListener(document.getElementById("zoomoraNextBtn"),"click",()=>this.next()),this.addEventListener(document.getElementById("zoomoraZoomBtn"),"click",()=>this.toggleZoom()),this.addEventListener(document.getElementById("zoomoraFullscreenBtn"),"click",()=>this.toggleFullscreen()),this.addEventListener(document.getElementById("zoomoraCollapseBtn"),"click",()=>this.exitFullscreen()),this.addEventListener(document.getElementById("zoomoraThumbnailBtn"),"click",()=>this.toggleThumbnails()),this.addEventListener(document,"fullscreenchange",this.boundMethods.handleFullscreenChange),this.addEventListener(document,"webkitfullscreenchange",this.boundMethods.handleFullscreenChange),this.addEventListener(document,"mozfullscreenchange",this.boundMethods.handleFullscreenChange),this.addEventListener(document,"MSFullscreenChange",this.boundMethods.handleFullscreenChange),this.addEventListener(document,"keydown",this.boundMethods.handleKeydown),this.addEventListener(this.zoomora,"click",this.boundMethods.handleZoomoraClick),this.addEventListener(this.content,"click",this.boundMethods.handleContentClick),this.addEventListener(this.content,"mousedown",this.boundMethods.handleMouseDown),this.addEventListener(this.content,"mousemove",this.boundMethods.handleMouseMove),this.addEventListener(this.content,"mouseup",this.boundMethods.handleMouseUp),this.addEventListener(this.content,"mouseleave",this.boundMethods.handleMouseUp),this.addEventListener(this.content,"touchstart",this.boundMethods.handleTouchStart,{passive:!1}),this.addEventListener(this.content,"touchmove",this.boundMethods.handleTouchMove,{passive:!1}),this.addEventListener(this.content,"touchend",this.boundMethods.handleTouchEnd),this.addEventListener(document.getElementById("zoomoraAutoHideBtn"),"click",()=>this.toggleAutoHide()),this.addEventListener(this.zoomora,"mousemove",()=>this.handleUserActivity()),this.addEventListener(this.zoomora,"touchstart",()=>this.handleUserActivity()),this.addEventListener(this.zoomora,"keydown",()=>this.handleUserActivity())}addEventListener(t,e,s,o={}){if(!t)return;t.addEventListener(e,s,o);const i=`${t.constructor.name}_${e}`;this.eventListeners.has(i)||this.eventListeners.set(i,[]),this.eventListeners.get(i).push({element:t,event:e,handler:s,options:o})}handleDocumentClick(t){const e=t.target.closest(this.options.selector);e&&(t.preventDefault(),this.open(e))}handleKeydown(t){if(this.zoomora.classList.contains("active"))switch(t.key){case"Escape":this.isFullscreen?this.exitFullscreen():this.close();break;case"ArrowLeft":this.prev();break;case"ArrowRight":this.next();break;case"z":case"Z":this.toggleZoom();break;case"f":case"F":this.toggleFullscreen();break;case"t":case"T":this.toggleThumbnails()}}handleFullscreenChange(){!(document.fullscreenElement||document.webkitFullscreenElement||document.mozFullScreenElement||document.msFullscreenElement)&&this.isFullscreen&&(this.isFullscreen=!1,this.zoomora.classList.remove("fullscreen"),this.updateButtons())}handleZoomoraClick(t){t.target===this.zoomora&&this.close()}handleContentClick(t){const e=t.target.closest(".zoomora-media");!e||e.classList.contains("no-zoom")||this.isDragging||this.toggleZoom()}handleMouseDown(t){this.startDrag(t)}handleMouseMove(t){this.drag(t)}handleMouseUp(){this.endDrag()}handleTouchStart(t){this.startDrag(t)}handleTouchMove(t){this.drag(t)}handleTouchEnd(){this.endDrag()}getImageSource(t){const e=t.dataset.src||t.src||t.getAttribute("src");return"video"===(t.dataset.type||"image")&&e?this.convertToEmbedUrl(e):e}convertToEmbedUrl(t){if(t.includes("youtube.com/embed/"))return t;let e=null,s=null;if(t.includes("youtube.com/watch")){const o=new URLSearchParams(t.split("?")[1]);e=o.get("v");const i=o.get("t");i&&(s=i.replace("s",""))}else if(t.includes("youtu.be/")){const o=t.split("/"),i=o[o.length-1];if(i.includes("?")){e=i.split("?")[0];const t=new URLSearchParams(i.split("?")[1]).get("t");t&&(s=t.replace("s",""))}else e=i}if(e){let t=`https://www.youtube.com/embed/${e}`;const o=new URLSearchParams;return s&&o.append("start",s),o.append("rel","0"),o.append("modestbranding","1"),o.toString()&&(t+="?"+o.toString()),t}return t}getThumbnailSource(t){return"video"===(t.dataset.type||"image")?t.src||t.getAttribute("src"):t.dataset.src||t.src||t.getAttribute("src")}getGroup(t){return this.options.useHref?t.dataset.lightbox||t.dataset.gallery||"default":t.dataset.zoomora||"default"}open(t){if(!t)return;const e=this.getGroup(t);let s;s=this.options.useHref?t.dataset.lightbox?`[data-lightbox="${e}"]`:t.dataset.gallery?`[data-gallery="${e}"]`:this.options.selector:`[data-zoomora="${e}"]`,this.items=Array.from(document.querySelectorAll(s)),this.currentIndex=Math.max(0,this.items.indexOf(t)),this.isZoomed=!1,this.isFullscreen=!1,this.thumbnailsVisible=!0,this.currentX=0,this.currentY=0,this.currentScale=1,this.zoomora.classList.add("active"),document.body.style.overflow="hidden",this.loadContent(),this.updateThumbnails(),this.updateCounter(),this.updateNavigation(),this.updateCaption(),this.updateButtons(),this.autoHideEnabled?this.startAutoHideTimer():this.showControls(),"function"==typeof this.options.onOpen&&this.options.onOpen(t,this.currentIndex)}close(){this.isFullscreen&&this.exitFullscreen(),this.zoomora.classList.remove("active"),document.body.style.overflow="",this.isZoomed=!1,this.isFullscreen=!1,this.currentX=0,this.currentY=0,this.currentScale=1;const t=this.content.querySelector(".zoomora-media");t&&(t.classList.remove("zoomed"),t.style.transform="",t.style.cursor=""),this.zoomora.classList.remove("fullscreen"),this.updateButtons(),this.stopAutoHideTimer(),this.showControls(),"function"==typeof this.options.onClose&&this.options.onClose(this.currentIndex)}prev(){this.currentIndex>0&&(this.currentIndex--,this.loadContent(),this.updateCounter(),this.updateThumbnails(),this.updateNavigation(),this.updateCaption(),"function"==typeof this.options.onPrev&&this.options.onPrev(this.currentIndex))}next(){this.currentIndex<this.items.length-1&&(this.currentIndex++,this.loadContent(),this.updateCounter(),this.updateThumbnails(),this.updateNavigation(),this.updateCaption(),"function"==typeof this.options.onNext&&this.options.onNext(this.currentIndex))}loadContent(){if(!this.items[this.currentIndex])return;const t=this.items[this.currentIndex],e=this.getImageSource(t),s=t.dataset.type||"image";e?(this.loading.style.display="block",this.slidesContainer&&(this.slidesContainer.innerHTML=""),setTimeout(()=>{this.renderContent(e,s,t)},100)):console.error("Zoomora: No source found for item")}renderContent(t,e,s){const o=document.createElement("div");o.className="zoomora-slide-container";const i=document.createElement("div");let n;i.className="zoomora-slide "+("slide"===this.options.transition?"slide-effect":"fade-effect"),i.style.opacity="0",i.style.transform="slide"===this.options.transition?"translateX(100%)":"scale(0.8)";try{switch(e){case"video":if(t.endsWith(".mp4")||t.endsWith(".webm")||t.endsWith(".ogg")){const e=document.createElement("div");e.className="zoomora-video-container",n=document.createElement("video"),n.src=t,n.className="zoomora-video",n.setAttribute("preload","metadata");const i=s.src||s.getAttribute("src");i&&n.setAttribute("poster",i);const a=document.createElement("div");a.className="zoomora-play-button",a.innerHTML='<svg viewBox="0 0 24 24" fill="currentColor"><path d="M8 5v14l11-7z"/></svg>',a.addEventListener("click",()=>{n.play(),a.style.display="none",n.setAttribute("controls","")}),n.addEventListener("ended",()=>{a.style.display="flex"}),e.appendChild(n),e.appendChild(a),o.appendChild(e)}else n=document.createElement("iframe"),n.src=t,n.className="zoomora-video",n.setAttribute("allowfullscreen",""),n.setAttribute("frameborder","0"),o.appendChild(n);break;case"iframe":n=document.createElement("iframe"),n.src=t,n.className="zoomora-iframe",n.setAttribute("frameborder","0"),o.appendChild(n);break;default:n=document.createElement("img"),n.src=t,n.className="zoomora-media",n.alt=s.alt||s.title||"",n.onload=()=>{this.loading.style.display="none",this.checkZoomability(n),this.animateSlideIn(i)},n.onerror=()=>{this.loading.style.display="none",console.error("Zoomora: Failed to load image:",t),this.animateSlideIn(i)},o.appendChild(n)}i.appendChild(o),this.slidesContainer.innerHTML="",this.slidesContainer.appendChild(i),"image"!==e&&(this.loading.style.display="none",this.animateSlideIn(i))}catch(t){console.error("Zoomora: Error rendering content:",t),this.loading.style.display="none"}}animateSlideIn(t){t.offsetHeight,t.classList.add("active"),"slide"===this.options.transition?(t.style.transition=`transform ${this.options.animationDuration}ms ease, opacity ${this.options.animationDuration}ms ease`,t.style.transform="translateX(0)",t.style.opacity="1"):(t.style.transition=`transform ${this.options.animationDuration}ms ease, opacity ${this.options.animationDuration}ms ease`,t.style.transform="scale(1)",t.style.opacity="1")}toggleAutoHide(){this.autoHideEnabled=!this.autoHideEnabled;const t=document.getElementById("zoomoraAutoHideBtn");this.autoHideEnabled?(t.classList.add("active"),t.title="Disable Auto-Hide Controls",this.startAutoHideTimer()):(t.classList.remove("active"),t.title="Enable Auto-Hide Controls",this.stopAutoHideTimer(),this.showControls())}handleUserActivity(){this.autoHideEnabled&&(this.showControls(),this.startAutoHideTimer())}startAutoHideTimer(){this.stopAutoHideTimer(),this.autoHideTimeout=setTimeout(()=>{this.hideControls()},this.options.autoHideDelay)}stopAutoHideTimer(){this.autoHideTimeout&&(clearTimeout(this.autoHideTimeout),this.autoHideTimeout=null)}showControls(){this.isControlsVisible||(this.isControlsVisible=!0,this.zoomora.classList.remove("controls-hidden"),this.header&&(this.header.style.transform="translateY(0)",this.header.style.opacity="1"),this.caption&&(this.caption.style.transform="translateX(-50%) translateY(0)",this.caption.style.opacity="1"),this.thumbs&&(this.thumbs.style.transform="translateX(-50%) translateY(0)",this.thumbs.style.opacity="1"),this.prevBtn&&(this.prevBtn.style.transform="translateX(0)",this.prevBtn.style.opacity="1"),this.nextBtn&&(this.nextBtn.style.transform="translateX(0)",this.nextBtn.style.opacity="1"))}hideControls(){this.isControlsVisible&&(this.isControlsVisible=!1,this.zoomora.classList.add("controls-hidden"),this.header&&(this.header.style.transform="translateY(-100%)",this.header.style.opacity="0"),this.caption&&(this.caption.style.transform="translateX(-50%) translateY(100%)",this.caption.style.opacity="0"),this.thumbs&&(this.thumbs.style.transform="translateX(-50%) translateY(100%)",this.thumbs.style.opacity="0"),this.prevBtn&&(this.prevBtn.style.transform="translateX(-100%)",this.prevBtn.style.opacity="0"),this.nextBtn&&(this.nextBtn.style.transform="translateX(100%)",this.nextBtn.style.opacity="0"))}checkZoomability(t){if(!t||!t.naturalWidth||!t.naturalHeight)return;const e=t.getBoundingClientRect(),s=e.width,o=e.height,i=t.naturalWidth,n=t.naturalHeight,a=i>s||n>o,r=i/s,l=n/o,h=Math.max(r,l);t.dataset.zoomRatio=h,t.dataset.naturalWidth=i,t.dataset.naturalHeight=n,t.dataset.renderedWidth=s,t.dataset.renderedHeight=o,a&&h>1.1?t.classList.remove("no-zoom"):t.classList.add("no-zoom")}updateCounter(){this.options.showCounter&&this.counter&&(this.counter.textContent=`${this.currentIndex+1} / ${this.items.length}`)}updateCaption(){if(!this.caption||!this.items[this.currentIndex])return;const t=this.items[this.currentIndex],e=t.dataset.caption||t.title||"";e?(this.caption.textContent=e,this.caption.style.transform="translateX(-50%) translateY(0)",this.caption.style.opacity="1",this.caption.style.pointerEvents="auto",this.caption.style.transition="opacity 0.3s ease, transform 0.3s ease"):(this.caption.style.transform="translateX(-50%) translateY(100%)",this.caption.style.opacity="0",this.caption.style.pointerEvents="none",this.caption.style.transition="opacity 0.3s ease, transform 0.3s ease")}updateThumbnails(){if(this.options.showThumbnails&&this.thumbs){if(1===this.items.length)return this.caption.classList.add("single-item-thumbnail"),void(this.thumbs.style.display="none");this.caption.classList.remove("single-item-thumbnail"),this.thumbs.style.display="flex",this.thumbs.innerHTML="",this.items.forEach((t,e)=>{const s=document.createElement("div");s.className="zoomora-thumb",e===this.currentIndex&&s.classList.add("active");const o=document.createElement("img"),i=this.getThumbnailSource(t);i&&(o.src=i,o.alt=t.alt||t.title||"",o.onerror=()=>{s.style.display="none"}),s.appendChild(o),s.addEventListener("click",()=>{this.currentIndex=e,this.loadContent(),this.updateCounter(),this.updateThumbnails(),this.updateNavigation(),this.updateCaption()}),this.thumbs.appendChild(s)})}}updateNavigation(){const t=document.getElementById("zoomoraPrevBtn"),e=document.getElementById("zoomoraNextBtn");t&&(t.style.display=this.currentIndex>0?"flex":"none"),e&&(e.style.display=this.currentIndex<this.items.length-1?"flex":"none")}updateButtons(){const t=document.getElementById("zoomoraFullscreenBtn"),e=document.getElementById("zoomoraCollapseBtn");t&&e&&(this.isFullscreen?(t.style.display="none",e.style.display="flex"):(t.style.display="flex",e.style.display="none"))}toggleZoom(){const t=this.content.querySelector(".zoomora-media");if(t&&"IMG"===t.tagName&&!t.classList.contains("no-zoom"))if(this.isZoomed=!this.isZoomed,t.classList.toggle("zoomed",this.isZoomed),this.isZoomed){const e=parseFloat(t.dataset.zoomRatio)||2;let s=Math.min(e,this.options.maxZoomScale);e>2.5&&(s=Math.min(.7*e,2.5)),t.style.transform=`scale(${s})`,t.style.cursor="grab",t.dataset.currentZoomScale=s,this.currentScale=s}else t.style.transform="",t.style.cursor="",this.currentX=0,this.currentY=0,this.currentScale=1}toggleFullscreen(){this.isFullscreen?this.exitFullscreen():this.enterFullscreen()}enterFullscreen(){const t=this.zoomora,e=t.requestFullscreen||t.webkitRequestFullscreen||t.mozRequestFullScreen||t.msRequestFullscreen;e?e.call(t).then(()=>{this.isFullscreen=!0,this.zoomora.classList.add("fullscreen"),this.updateButtons()}).catch(t=>{console.warn("Zoomora: Could not enter fullscreen:",t),this.fallbackFullscreen()}):this.fallbackFullscreen()}exitFullscreen(){if(document.fullscreenElement||document.webkitFullscreenElement||document.mozFullScreenElement||document.msFullscreenElement){const t=document.exitFullscreen||document.webkitExitFullscreen||document.mozCancelFullScreen||document.msExitFullscreen;t?t.call(document).then(()=>{this.isFullscreen=!1,this.zoomora.classList.remove("fullscreen"),this.updateButtons()}).catch(t=>{console.warn("Zoomora: Could not exit fullscreen:",t),this.fallbackExitFullscreen()}):this.fallbackExitFullscreen()}else this.fallbackExitFullscreen()}fallbackFullscreen(){this.isFullscreen=!0,this.zoomora.classList.add("fullscreen"),this.updateButtons()}fallbackExitFullscreen(){this.isFullscreen=!1,this.zoomora.classList.remove("fullscreen"),this.updateButtons()}toggleThumbnails(){if(1!==this.items.length&&(this.thumbnailsVisible=!this.thumbnailsVisible,this.thumbs)){if(this.thumbs.classList.toggle("thumbs-hidden",!this.thumbnailsVisible),!this.caption||!this.items[this.currentIndex])return;const t=this.items[this.currentIndex];(t.dataset.caption||t.title)&&this.thumbs.classList.contains("thumbs-hidden")?(this.caption.style.bottom="20px",this.caption.style.transition="bottom 0.3s ease, transform 0.3s ease"):this.caption.style.bottom="120px"}}startDrag(t){const e=this.content.querySelector(".zoomora-media");if(!e||!this.isZoomed)return;this.isDragging=!0,e.style.cursor="grabbing",this.startX=t.clientX||t.touches&&t.touches[0].clientX||0,this.startY=t.clientY||t.touches&&t.touches[0].clientY||0;const s=e.style.transform,o=s.match(/scale\(([^)]+)\)/),i=s.match(/translate\(([^,]+),\s*([^)]+)\)/);this.currentScale=o?parseFloat(o[1]):1,this.currentX=i?parseFloat(i[1]):0,this.currentY=i?parseFloat(i[2]):0,t.preventDefault()}drag(t){if(!this.isDragging)return;t.preventDefault();const e=t.clientX||t.touches&&t.touches[0].clientX||0,s=t.clientY||t.touches&&t.touches[0].clientY||0,o=e-this.startX,i=s-this.startY,n=this.currentX+o,a=this.currentY+i,r=this.content.querySelector(".zoomora-media");if(!r)return;const l=r.getBoundingClientRect(),h=this.currentScale,d=l.width*(h-1)/2,c=l.height*(h-1)/2,u=Math.max(-d,Math.min(d,n)),m=Math.max(-c,Math.min(c,a));r.style.transform=`scale(${h}) translate(${u}px, ${m}px)`}endDrag(){if(!this.isDragging)return;this.isDragging=!1;const t=this.content.querySelector(".zoomora-media");t&&this.isZoomed&&(t.style.cursor="grab")}goTo(t){t<0||t>=this.items.length||(this.currentIndex=t,this.loadContent(),this.updateCounter(),this.updateThumbnails(),this.updateNavigation(),this.updateCaption())}getCurrentIndex(){return this.currentIndex}getTotalItems(){return this.items.length}isOpen(){return this.zoomora&&this.zoomora.classList.contains("active")}updateOptions(t){this.options=h(h({},this.options),t)}refresh(){if(this.isOpen()){const t=this.items[this.currentIndex];t&&this.open(t)}}destroy(){this.isInitialized&&(this.isOpen()&&this.close(),this.stopAutoHideTimer(),this.eventListeners.forEach((t,e)=>{t.forEach(({element:t,event:e,handler:s,options:o})=>{t&&t.removeEventListener&&t.removeEventListener(e,s,o)})}),this.eventListeners.clear(),this.zoomora&&this.zoomora.parentNode&&this.zoomora.parentNode.removeChild(this.zoomora),this.isInitialized=!1,this.items=[],this.currentIndex=0,this.zoomora=null,this.content=null,this.counter=null,this.thumbs=null,this.loading=null,this.caption=null)}}return t},"object"==typeof module&&"object"==typeof module.exports?module.exports=e():"function"==typeof define&&define.amd?define(e):t.Zoomora=e()});
9
+ t="undefined"!=typeof window?window:void 0,e=function(){class t{static get defaults(){return{selector:"[data-zoomora]",showCounter:!0,showThumbnails:!0,showFullscreen:!0,showZoom:!0,transition:"fade",useHref:!1,maxZoomScale:3,zoomStep:.1,animationDuration:300,onOpen:null,onClose:null,onNext:null,onPrev:null,showAutoHideToggle:!0,autoHideDelay:3e3,autoHideEnabled:!1}}constructor(e={}){this.options=h(h({},t.defaults),e),this.currentIndex=0,this.items=[],this.isZoomed=!1,this.isFullscreen=!1,this.isDragging=!1,this.thumbnailsVisible=!0,this.startX=0,this.startY=0,this.currentX=0,this.currentY=0,this.currentScale=1,this.isInitialized=!1,this.eventListeners=new Map,this.autoHideEnabled=!1,this.autoHideTimeout=null,this.autoHideDelay=3e3,this.isControlsVisible=!0,this.idleTimer=null,this.lastDragTime=0,this.boundMethods={handleDocumentClick:this.handleDocumentClick.bind(this),handleKeydown:this.handleKeydown.bind(this),handleFullscreenChange:this.handleFullscreenChange.bind(this),handleZoomoraClick:this.handleZoomoraClick.bind(this),handleContentClick:this.handleContentClick.bind(this),handleMouseDown:this.handleMouseDown.bind(this),handleMouseMove:this.handleMouseMove.bind(this),handleMouseUp:this.handleMouseUp.bind(this),handleTouchStart:this.handleTouchStart.bind(this),handleTouchMove:this.handleTouchMove.bind(this),handleTouchEnd:this.handleTouchEnd.bind(this)},this.init()}init(){if(!this.isInitialized)try{this.createLightbox(),this.bindEvents(),this.isInitialized=!0}catch(t){}}static bind(e,s={}){const o=(a=h({},s),i(a,n({selector:e,useHref:!0})));var a;return new t(o)}createLightbox(){if(document.getElementById("zoomoraLightbox"))return;const t=`\n <div class="zoomora" id="zoomoraLightbox">\n <div class="zoomora-container">\n <div class="zoomora-header" id="zoomoraHeader">\n <div class="zoomora-counter" id="zoomoraCounter">1 / 1</div>\n <div class="zoomora-controls">\n <button class="zoomora-btn" id="zoomoraThumbnailBtn" title="Toggle Thumbnails">\n <i class="zoomorai-thumbnails"></i>\n </button>\n ${this.options.showAutoHideToggle?'\n <button class="zoomora-btn" id="zoomoraAutoHideBtn" title="Toggle Auto-Hide Controls">\n <i class="zoomorai-controls-off"></i>\n </button>\n ':""}\n <button class="zoomora-btn" id="zoomoraZoomBtn" title="Zoom">\n <i class="zoomorai-zoom"></i>\n </button>\n <button class="zoomora-btn" id="zoomoraFullscreenBtn" title="Fullscreen">\n <i class="zoomorai-expand"></i>\n </button>\n <button class="zoomora-btn" id="zoomoraCollapseBtn" title="Exit Fullscreen" style="display: none;">\n <i class="zoomorai-collapse"></i>\n </button>\n <button class="zoomora-btn" id="zoomoraCloseBtn" title="Close">\n <i class="zoomorai-close"></i>\n </button>\n </div>\n </div>\n \n <div class="zoomora-content" id="zoomoraContent">\n <div class="zoomora-loading" id="zoomoraLoading"></div>\n <div class="zoomora-slides-container" id="zoomoraSlidesContainer"></div>\n </div>\n \n <button class="zoomora-nav prev" id="zoomoraPrevBtn">\n <i class="zoomorai-arrow-left"></i>\n </button>\n <button class="zoomora-nav next" id="zoomoraNextBtn">\n <i class="zoomorai-arrow-right"></i>\n </button>\n \n <div class="zoomora-caption" id="zoomoraCaption"></div>\n <div class="zoomora-thumbnails" id="zoomoraThumbs"></div>\n </div>\n </div>\n `;if(document.body.insertAdjacentHTML("beforeend",t),this.zoomora=document.getElementById("zoomoraLightbox"),this.header=document.getElementById("zoomoraHeader"),this.content=document.getElementById("zoomoraContent"),this.slidesContainer=document.getElementById("zoomoraSlidesContainer"),this.counter=document.getElementById("zoomoraCounter"),this.thumbs=document.getElementById("zoomoraThumbs"),this.loading=document.getElementById("zoomoraLoading"),this.caption=document.getElementById("zoomoraCaption"),this.prevBtn=document.getElementById("zoomoraPrevBtn"),this.nextBtn=document.getElementById("zoomoraNextBtn"),!(this.zoomora&&this.content&&this.counter&&this.thumbs&&this.loading&&this.caption))throw new Error("Failed to create required DOM elements")}bindEvents(){this.addEventListener(document,"click",this.boundMethods.handleDocumentClick),this.addEventListener(document.getElementById("zoomoraCloseBtn"),"click",()=>this.close()),this.addEventListener(document.getElementById("zoomoraPrevBtn"),"click",()=>this.prev()),this.addEventListener(document.getElementById("zoomoraNextBtn"),"click",()=>this.next()),this.addEventListener(document.getElementById("zoomoraZoomBtn"),"click",()=>this.toggleZoom()),this.addEventListener(document.getElementById("zoomoraFullscreenBtn"),"click",()=>this.toggleFullscreen()),this.addEventListener(document.getElementById("zoomoraCollapseBtn"),"click",()=>this.exitFullscreen()),this.addEventListener(document.getElementById("zoomoraThumbnailBtn"),"click",()=>this.toggleThumbnails()),this.addEventListener(document,"fullscreenchange",this.boundMethods.handleFullscreenChange),this.addEventListener(document,"webkitfullscreenchange",this.boundMethods.handleFullscreenChange),this.addEventListener(document,"mozfullscreenchange",this.boundMethods.handleFullscreenChange),this.addEventListener(document,"MSFullscreenChange",this.boundMethods.handleFullscreenChange),this.addEventListener(document,"keydown",this.boundMethods.handleKeydown),this.addEventListener(this.zoomora,"click",this.boundMethods.handleZoomoraClick),this.addEventListener(this.content,"click",this.boundMethods.handleContentClick),this.addEventListener(this.content,"mousedown",this.boundMethods.handleMouseDown),this.addEventListener(this.content,"mousemove",this.boundMethods.handleMouseMove),this.addEventListener(this.content,"mouseup",this.boundMethods.handleMouseUp),this.addEventListener(this.content,"mouseleave",this.boundMethods.handleMouseUp),this.addEventListener(this.content,"touchstart",this.boundMethods.handleTouchStart,{passive:!1}),this.addEventListener(this.content,"touchmove",this.boundMethods.handleTouchMove,{passive:!1}),this.addEventListener(this.content,"touchend",this.boundMethods.handleTouchEnd),this.options.showAutoHideToggle&&(this.addEventListener(document.getElementById("zoomoraAutoHideBtn"),"click",()=>this.toggleAutoHide()),this.addEventListener(this.zoomora,"mousemove",()=>this.handleUserActivity()),this.addEventListener(this.zoomora,"touchstart",()=>this.handleUserActivity()),this.addEventListener(this.zoomora,"keydown",()=>this.handleUserActivity()))}addEventListener(t,e,s,i={}){if(!t)return;t.addEventListener(e,s,i);const n=`${t.constructor.name}_${e}`;this.eventListeners.has(n)||this.eventListeners.set(n,[]),this.eventListeners.get(n).push({element:t,event:e,handler:s,options:i})}handleDocumentClick(t){const e=t.target.closest(this.options.selector);e&&(t.preventDefault(),this.open(e))}handleKeydown(t){if(this.zoomora.classList.contains("active"))switch(t.key){case"Escape":this.isFullscreen?this.exitFullscreen():this.close();break;case"ArrowLeft":this.prev();break;case"ArrowRight":this.next();break;case"z":case"Z":this.toggleZoom();break;case"f":case"F":this.toggleFullscreen();break;case"t":case"T":this.toggleThumbnails()}}handleFullscreenChange(){!(document.fullscreenElement||document.webkitFullscreenElement||document.mozFullScreenElement||document.msFullscreenElement)&&this.isFullscreen&&(this.isFullscreen=!1,this.zoomora.classList.remove("fullscreen"),this.updateButtons())}handleZoomoraClick(t){t.target===this.zoomora&&this.close()}handleContentClick(t){if(Date.now()-this.lastDragTime<200)return;const e=t.target.closest(".zoomora-media");e&&!e.classList.contains("no-zoom")&&this.toggleZoom()}handleMouseDown(t){this.startDrag(t)}handleMouseMove(t){this.drag(t)}handleMouseUp(){this.endDrag()}handleTouchStart(t){this.startDrag(t)}handleTouchMove(t){this.drag(t)}handleTouchEnd(){this.endDrag()}getImageSource(t){const e=t.dataset.src||t.src||t.getAttribute("src");return"video"===(t.dataset.type||"image")&&e?this.convertToEmbedUrl(e):e}convertToEmbedUrl(t){if(t.includes("youtube.com/embed/"))return t;let e=null,s=null;if(t.includes("youtube.com/watch")){const i=new URLSearchParams(t.split("?")[1]);e=i.get("v");const n=i.get("t");n&&(s=n.replace("s",""))}else if(t.includes("youtu.be/")){const i=t.split("/"),n=i[i.length-1];if(n.includes("?")){e=n.split("?")[0];const t=new URLSearchParams(n.split("?")[1]).get("t");t&&(s=t.replace("s",""))}else e=n}if(e){let t=`https://www.youtube.com/embed/${e}`;const i=new URLSearchParams;return s&&i.append("start",s),i.append("rel","0"),i.append("modestbranding","1"),i.toString()&&(t+="?"+i.toString()),t}return t}getThumbnailSource(t){return"video"===(t.dataset.type||"image")?t.src||t.getAttribute("src"):t.dataset.src||t.src||t.getAttribute("src")}getGroup(t){return this.options.useHref?t.dataset.lightbox||t.dataset.gallery||"default":t.dataset.zoomora||"default"}open(t){if(!t)return;const e=this.getGroup(t);let s;s=this.options.useHref?t.dataset.lightbox?`[data-lightbox="${e}"]`:t.dataset.gallery?`[data-gallery="${e}"]`:this.options.selector:`[data-zoomora="${e}"]`,this.items=Array.from(document.querySelectorAll(s)),this.currentIndex=Math.max(0,this.items.indexOf(t)),this.isZoomed=!1,this.isFullscreen=!1,this.thumbnailsVisible=!0,this.currentX=0,this.currentY=0,this.currentScale=1,this.zoomora.classList.add("active"),document.body.style.overflow="hidden",this.loadContent(),this.updateThumbnails(),this.updateCounter(),this.updateNavigation(),this.updateCaption(),this.updateButtons(),this.autoHideEnabled?this.startAutoHideTimer():this.showControls(),"function"==typeof this.options.onOpen&&this.options.onOpen(t,this.currentIndex)}close(){this.isFullscreen&&this.exitFullscreen(),this.zoomora.classList.remove("active"),document.body.style.overflow="",this.isZoomed=!1,this.isFullscreen=!1,this.currentX=0,this.currentY=0,this.currentScale=1;const t=this.content.querySelector(".zoomora-media");t&&(t.classList.remove("zoomed"),t.style.transform="",t.style.cursor=""),this.zoomora.classList.remove("fullscreen"),this.updateButtons(),this.stopAutoHideTimer(),this.showControls(),"function"==typeof this.options.onClose&&this.options.onClose(this.currentIndex)}prev(){this.currentIndex>0&&(this.currentIndex--,this.loadContent(),this.updateCounter(),this.updateThumbnails(),this.updateNavigation(),this.updateCaption(),"function"==typeof this.options.onPrev&&this.options.onPrev(this.currentIndex))}next(){this.currentIndex<this.items.length-1&&(this.currentIndex++,this.loadContent(),this.updateCounter(),this.updateThumbnails(),this.updateNavigation(),this.updateCaption(),"function"==typeof this.options.onNext&&this.options.onNext(this.currentIndex))}loadContent(){if(!this.items[this.currentIndex])return;const t=this.items[this.currentIndex],e=this.getImageSource(t),s=t.dataset.type||"image";e&&(this.isZoomed=!1,this.currentX=0,this.currentY=0,this.currentScale=1,this.loading.style.display="block",this.slidesContainer&&(this.slidesContainer.innerHTML=""),setTimeout(()=>{this.renderContent(e,s,t)},100))}renderContent(t,e,s){const i=document.createElement("div");i.className="zoomora-slide-container";const n=document.createElement("div");let o;n.className="zoomora-slide "+("slide"===this.options.transition?"slide-effect":"fade-effect"),n.style.opacity="0",n.style.transform="slide"===this.options.transition?"translateX(100%)":"scale(0.8)";try{switch(e){case"video":if(t.endsWith(".mp4")||t.endsWith(".webm")||t.endsWith(".ogg")){const e=document.createElement("div");e.className="zoomora-video-container",o=document.createElement("video"),o.src=t,o.className="zoomora-video",o.setAttribute("preload","metadata");const n=s.src||s.getAttribute("src");n&&o.setAttribute("poster",n);const a=document.createElement("div");a.className="zoomora-play-button",a.innerHTML='<svg viewBox="0 0 24 24" fill="currentColor"><path d="M8 5v14l11-7z"/></svg>',a.addEventListener("click",()=>{o.play(),a.style.display="none",o.setAttribute("controls","")}),o.addEventListener("ended",()=>{a.style.display="flex"}),e.appendChild(o),e.appendChild(a),i.appendChild(e)}else o=document.createElement("iframe"),o.src=t,o.className="zoomora-video",o.setAttribute("allowfullscreen",""),o.setAttribute("frameborder","0"),i.appendChild(o);break;case"iframe":o=document.createElement("iframe"),o.src=t,o.className="zoomora-iframe",o.setAttribute("frameborder","0"),i.appendChild(o);break;default:o=document.createElement("img"),o.src=t,o.className="zoomora-media",o.alt=s.alt||s.title||"",o.onload=()=>{this.loading.style.display="none",this.checkZoomability(o),this.animateSlideIn(n)},o.onerror=()=>{this.loading.style.display="none",this.animateSlideIn(n)},i.appendChild(o)}n.appendChild(i),this.slidesContainer.innerHTML="",this.slidesContainer.appendChild(n),"image"!==e&&(this.loading.style.display="none",this.animateSlideIn(n))}catch(t){this.loading.style.display="none"}}animateSlideIn(t){t.offsetHeight,t.classList.add("active"),"slide"===this.options.transition?(t.style.transition=`transform ${this.options.animationDuration}ms ease, opacity ${this.options.animationDuration}ms ease`,t.style.transform="translateX(0)",t.style.opacity="1"):(t.style.transition=`transform ${this.options.animationDuration}ms ease, opacity ${this.options.animationDuration}ms ease`,t.style.transform="scale(1)",t.style.opacity="1")}toggleAutoHide(){this.autoHideEnabled=!this.autoHideEnabled;const t=document.getElementById("zoomoraAutoHideBtn");this.autoHideEnabled?(t.classList.add("active"),t.title="Disable Auto-Hide Controls",this.startAutoHideTimer()):(t.classList.remove("active"),t.title="Enable Auto-Hide Controls",this.stopAutoHideTimer(),this.showControls())}handleUserActivity(){this.autoHideEnabled&&(this.showControls(),this.startAutoHideTimer())}startAutoHideTimer(){this.stopAutoHideTimer(),this.autoHideTimeout=setTimeout(()=>{this.hideControls()},this.options.autoHideDelay)}stopAutoHideTimer(){this.autoHideTimeout&&(clearTimeout(this.autoHideTimeout),this.autoHideTimeout=null)}showControls(){this.isControlsVisible||(this.isControlsVisible=!0,this.zoomora.classList.remove("controls-hidden"),this.header&&(this.header.style.transform="translateY(0)",this.header.style.opacity="1"),this.caption&&(this.caption.style.transform="translateX(-50%) translateY(0)",this.caption.style.opacity="1"),this.thumbs&&(this.thumbs.style.transform="translateX(-50%) translateY(0)",this.thumbs.style.opacity="1"),this.prevBtn&&(this.prevBtn.style.transform="translateX(0)",this.prevBtn.style.opacity="1"),this.nextBtn&&(this.nextBtn.style.transform="translateX(0)",this.nextBtn.style.opacity="1"))}hideControls(){this.isControlsVisible&&(this.isControlsVisible=!1,this.zoomora.classList.add("controls-hidden"),this.header&&(this.header.style.transform="translateY(-100%)",this.header.style.opacity="0"),this.caption&&(this.caption.style.transform="translateX(-50%) translateY(100%)",this.caption.style.opacity="0"),this.thumbs&&(this.thumbs.style.transform="translateX(-50%) translateY(100%)",this.thumbs.style.opacity="0"),this.prevBtn&&(this.prevBtn.style.transform="translateX(-100%)",this.prevBtn.style.opacity="0"),this.nextBtn&&(this.nextBtn.style.transform="translateX(100%)",this.nextBtn.style.opacity="0"))}checkZoomability(t){if(!t||!t.naturalWidth||!t.naturalHeight)return;const e=t.getBoundingClientRect(),s=e.width,i=e.height,n=t.naturalWidth,o=t.naturalHeight,a=n>s||o>i,r=n/s,l=o/i,h=Math.max(r,l);t.dataset.zoomRatio=h,t.dataset.naturalWidth=n,t.dataset.naturalHeight=o,t.dataset.renderedWidth=s,t.dataset.renderedHeight=i,a&&h>1.1?t.classList.remove("no-zoom"):t.classList.add("no-zoom")}calculateZoomLevels(t){if(!t||!t.naturalWidth||!t.naturalHeight)return{canZoom:!1,levels:[],currentLevel:0};const e=this.content.getBoundingClientRect(),s=e.width,i=e.height,n=t.naturalWidth,o=t.naturalHeight,a=s/n,r=i/o,l=Math.min(a,r);if(l>=.95)return{canZoom:!1,levels:[],currentLevel:0};const h=[1];1.5*l<=1&&h.push(1.5),2*l<=1&&h.push(2),3*l<=1&&h.push(3);const d=1/l;return d>h[h.length-1]&&h.push(d),{canZoom:h.length>1,levels:h,currentLevel:0,baseScale:l,naturalWidth:n,naturalHeight:o}}updateCounter(){this.options.showCounter&&this.counter&&(this.counter.textContent=`${this.currentIndex+1} / ${this.items.length}`)}updateCaption(){if(!this.caption||!this.items[this.currentIndex])return;const t=this.items[this.currentIndex],e=t.dataset.caption||t.title||"";e?(this.caption.textContent=e,this.caption.style.transform="translateX(-50%) translateY(0)",this.caption.style.opacity="1",this.caption.style.pointerEvents="auto",this.caption.style.transition="opacity 0.3s ease, transform 0.3s ease"):(this.caption.style.transform="translateX(-50%) translateY(100%)",this.caption.style.opacity="0",this.caption.style.pointerEvents="none",this.caption.style.transition="opacity 0.3s ease, transform 0.3s ease")}updateThumbnails(){if(this.options.showThumbnails&&this.thumbs){if(1===this.items.length)return this.caption.classList.add("single-item-thumbnail"),void(this.thumbs.style.display="none");this.caption.classList.remove("single-item-thumbnail"),this.thumbs.style.display="flex",this.thumbs.innerHTML="",this.items.forEach((t,e)=>{const s=document.createElement("div");s.className="zoomora-thumb",e===this.currentIndex&&s.classList.add("active");const i=document.createElement("img"),n=this.getThumbnailSource(t);n&&(i.src=n,i.alt=t.alt||t.title||"",i.onerror=()=>{s.style.display="none"}),s.appendChild(i),s.addEventListener("click",()=>{this.currentIndex=e,this.loadContent(),this.updateCounter(),this.updateThumbnails(),this.updateNavigation(),this.updateCaption()}),this.thumbs.appendChild(s)})}}updateNavigation(){const t=document.getElementById("zoomoraPrevBtn"),e=document.getElementById("zoomoraNextBtn");t&&(t.style.display=this.currentIndex>0?"flex":"none"),e&&(e.style.display=this.currentIndex<this.items.length-1?"flex":"none")}updateButtons(){const t=document.getElementById("zoomoraFullscreenBtn"),e=document.getElementById("zoomoraCollapseBtn");t&&e&&(this.isFullscreen?(t.style.display="none",e.style.display="flex"):(t.style.display="flex",e.style.display="none"))}toggleZoom(){const t=this.content.querySelector(".zoomora-media");if(!t||"IMG"!==t.tagName)return;const e=this.calculateZoomLevels(t);if(!e.canZoom)return;t.dataset.zoomLevel||(t.dataset.zoomLevel="0");let s=parseInt(t.dataset.zoomLevel)||0;s++,s>=e.levels.length&&(s=0);const i=e.levels[s];t.dataset.zoomLevel=s.toString(),0===s?(this.isZoomed=!1,this.isDragging=!1,t.classList.remove("dragging"),t.style.transform="",t.style.cursor="pointer",t.classList.remove("zoomed"),this.currentX=0,this.currentY=0,this.currentScale=1):(this.isZoomed=!0,this.currentScale=i,this.currentX=0,this.currentY=0,t.style.transform=`translate(0px, 0px) scale(${i})`,t.style.cursor="grab",t.classList.add("zoomed"))}updateImageTransform(t){if(t)if(1===this.currentScale)t.style.transform="";else{const e=this.currentX/this.currentScale,s=this.currentY/this.currentScale;t.style.transform=`scale(${this.currentScale}) translate(${e}px, ${s}px)`}}toggleFullscreen(){this.isFullscreen?this.exitFullscreen():this.enterFullscreen()}enterFullscreen(){const t=this.zoomora,e=t.requestFullscreen||t.webkitRequestFullscreen||t.mozRequestFullScreen||t.msRequestFullscreen;e?e.call(t).then(()=>{this.isFullscreen=!0,this.zoomora.classList.add("fullscreen"),this.updateButtons()}).catch(t=>{this.fallbackFullscreen()}):this.fallbackFullscreen()}exitFullscreen(){if(document.fullscreenElement||document.webkitFullscreenElement||document.mozFullScreenElement||document.msFullscreenElement){const t=document.exitFullscreen||document.webkitExitFullscreen||document.mozCancelFullScreen||document.msExitFullscreen;t?t.call(document).then(()=>{this.isFullscreen=!1,this.zoomora.classList.remove("fullscreen"),this.updateButtons()}).catch(t=>{this.fallbackExitFullscreen()}):this.fallbackExitFullscreen()}else this.fallbackExitFullscreen()}fallbackFullscreen(){this.isFullscreen=!0,this.zoomora.classList.add("fullscreen"),this.updateButtons()}fallbackExitFullscreen(){this.isFullscreen=!1,this.zoomora.classList.remove("fullscreen"),this.updateButtons()}toggleThumbnails(){if(1!==this.items.length&&(this.thumbnailsVisible=!this.thumbnailsVisible,this.thumbs)){if(this.thumbs.classList.toggle("thumbs-hidden",!this.thumbnailsVisible),!this.caption||!this.items[this.currentIndex])return;const t=this.items[this.currentIndex];(t.dataset.caption||t.title)&&this.thumbs.classList.contains("thumbs-hidden")?(this.caption.style.bottom="20px",this.caption.style.transition="bottom 0.3s ease, transform 0.3s ease"):this.caption.style.bottom="120px"}}startDrag(t){const e=this.content.querySelector(".zoomora-media");if(!e||!this.isZoomed)return;this.isDragging=!0,e.classList.add("dragging"),e.style.cursor="grabbing",this.startX=t.clientX||t.touches&&t.touches[0].clientX||0,this.startY=t.clientY||t.touches&&t.touches[0].clientY||0;const s=window.getComputedStyle(e).transform;if(s&&"none"!==s){const t=new DOMMatrix(s);this.currentX=t.m41,this.currentY=t.m42}else this.currentX=0,this.currentY=0;t.preventDefault()}drag(t){if(!this.isDragging)return;t.preventDefault();const e=this.content.querySelector(".zoomora-media");if(!e)return;const s=t.clientX||t.touches&&t.touches[0].clientX||0,i=t.clientY||t.touches&&t.touches[0].clientY||0,n=s-this.startX,o=i-this.startY;let a=this.currentX+n,r=this.currentY+o;const l=this.content.getBoundingClientRect(),h=e.getBoundingClientRect(),d=Math.max(0,(h.width-l.width)/2),c=Math.max(0,(h.height-l.height)/2);a=d>0?Math.max(-d,Math.min(d,a)):0,r=c>0?Math.max(-c,Math.min(c,r)):0,e.style.transform=`translate(${a}px, ${r}px) scale(${this.currentScale})`,this.startX=s,this.startY=i,this.currentX=a,this.currentY=r}endDrag(){if(!this.isDragging)return;this.isDragging=!1,this.lastDragTime=Date.now();const t=this.content.querySelector(".zoomora-media");t&&(t.classList.remove("dragging"),this.isZoomed&&(t.style.cursor="grab"))}goTo(t){t<0||t>=this.items.length||(this.currentIndex=t,this.loadContent(),this.updateCounter(),this.updateThumbnails(),this.updateNavigation(),this.updateCaption())}getCurrentIndex(){return this.currentIndex}getTotalItems(){return this.items.length}isOpen(){return this.zoomora&&this.zoomora.classList.contains("active")}updateOptions(t){this.options=h(h({},this.options),t)}refresh(){if(this.isOpen()){const t=this.items[this.currentIndex];t&&this.open(t)}}destroy(){this.isInitialized&&(this.isOpen()&&this.close(),this.stopAutoHideTimer(),this.eventListeners.forEach((t,e)=>{t.forEach(({element:t,event:e,handler:s,options:i})=>{t&&t.removeEventListener&&t.removeEventListener(e,s,i)})}),this.eventListeners.clear(),this.zoomora&&this.zoomora.parentNode&&this.zoomora.parentNode.removeChild(this.zoomora),this.isInitialized=!1,this.items=[],this.currentIndex=0,this.zoomora=null,this.content=null,this.counter=null,this.thumbs=null,this.loading=null,this.caption=null)}}return t},"object"==typeof module&&"object"==typeof module.exports?module.exports=e():"function"==typeof define&&define.amd?define(e):t.Zoomora=e()});
10
10
  //# sourceMappingURL=zoomora.umd.min.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"zoomora.umd.min.js","sources":["../src/zoomora.js"],"sourcesContent":["/*!\n * Zoomora Lightbox Plugin v1.0.0\n * A modern, responsive lightbox plugin with zoom, fullscreen, and gallery features\n *\n * Copyright (c) 2025 Faruk Ahmed (FrontTheme)\n * Licensed under MIT License\n */\n\n// Import styles\nimport './styles/zoomora.scss';\n\n(function (global, factory) {\n 'use strict';\n\n if (typeof module === 'object' && typeof module.exports === 'object') {\n // CommonJS/Node.js\n module.exports = factory();\n } else if (typeof define === 'function' && define.amd) {\n // AMD\n define(factory);\n } else {\n // Browser globals\n global.Zoomora = factory();\n }\n}(typeof window !== 'undefined' ? window : this, function () {\n 'use strict';\n\n /**\n * Zoomora Lightbox Plugin\n * @class\n */\n class Zoomora {\n /**\n * Default configuration options\n * @type {Object}\n */\n static get defaults() {\n return {\n selector: '[data-zoomora]',\n showCounter: true,\n showThumbnails: true,\n showFullscreen: true,\n showZoom: true,\n transition: 'fade', // 'fade' or 'slide'\n useHref: false, // Use href instead of data-src\n maxZoomScale: 3, // Maximum zoom scale\n zoomStep: 0.1, // Zoom step for scroll wheel\n animationDuration: 300, // Animation duration in ms\n onOpen: null, // Callback when lightbox opens\n onClose: null, // Callback when lightbox closes\n onNext: null, // Callback when navigating to next item\n onPrev: null, // Callback when navigating to previous item\n\n // Auto-hide controls\n showAutoHideToggle: true, // Show auto-hide toggle button\n autoHideDelay: 3000, // Delay in ms before hiding controls\n autoHideEnabled: false, // Default state of auto-hide\n };\n }\n\n /**\n * Constructor\n * @param {Object} options - Configuration options\n */\n constructor(options = {}) {\n this.options = {...Zoomora.defaults, ...options};\n this.currentIndex = 0;\n this.items = [];\n this.isZoomed = false;\n this.isFullscreen = false;\n this.isDragging = false;\n this.thumbnailsVisible = true;\n this.startX = 0;\n this.startY = 0;\n this.currentX = 0;\n this.currentY = 0;\n this.currentScale = 1;\n this.isInitialized = false;\n this.eventListeners = new Map();\n\n // Auto-hide controls\n this.autoHideEnabled = false;\n this.autoHideTimeout = null;\n this.autoHideDelay = 3000;\n this.isControlsVisible = true;\n this.idleTimer = null;\n\n // Bound methods for event listeners\n this.boundMethods = {\n handleDocumentClick: this.handleDocumentClick.bind(this),\n handleKeydown: this.handleKeydown.bind(this),\n handleFullscreenChange: this.handleFullscreenChange.bind(this),\n handleZoomoraClick: this.handleZoomoraClick.bind(this),\n handleContentClick: this.handleContentClick.bind(this),\n handleMouseDown: this.handleMouseDown.bind(this),\n handleMouseMove: this.handleMouseMove.bind(this),\n handleMouseUp: this.handleMouseUp.bind(this),\n handleTouchStart: this.handleTouchStart.bind(this),\n handleTouchMove: this.handleTouchMove.bind(this),\n handleTouchEnd: this.handleTouchEnd.bind(this),\n };\n\n this.init();\n }\n\n /**\n * Initialize the plugin\n */\n init() {\n if (this.isInitialized) {\n console.warn('Zoomora: Plugin already initialized');\n return;\n }\n\n try {\n this.createLightbox();\n this.bindEvents();\n\n this.isInitialized = true;\n } catch (error) {\n console.error('Zoomora: Initialization failed', error);\n }\n }\n\n /**\n * Static method to bind to anchor tags with href\n * @param {string} selector - CSS selector\n * @param {Object} options - Configuration options\n * @returns {Zoomora} - New Zoomora instance\n */\n static bind(selector, options = {}) {\n const enhancedOptions = {\n ...options,\n selector: selector,\n useHref: true\n };\n return new Zoomora(enhancedOptions);\n }\n\n /**\n * Create lightbox HTML structure\n */\n createLightbox() {\n // Check if lightbox already exists\n if (document.getElementById('zoomoraLightbox')) {\n console.warn('Zoomora: Lightbox already exists in DOM');\n return;\n }\n\n const zoomoraHTML = `\n <div class=\"zoomora\" id=\"zoomoraLightbox\">\n <div class=\"zoomora-container\">\n <div class=\"zoomora-header\" id=\"zoomoraHeader\">\n <div class=\"zoomora-counter\" id=\"zoomoraCounter\">1 / 1</div>\n <div class=\"zoomora-controls\">\n <button class=\"zoomora-btn\" id=\"zoomoraThumbnailBtn\" title=\"Toggle Thumbnails\">\n <i class=\"zoomorai-thumbnails\"></i>\n </button>\n <button class=\"zoomora-btn\" id=\"zoomoraAutoHideBtn\" title=\"Toggle Auto-Hide Controls\">\n <i class=\"zoomorai-controls-off\"></i>\n </button>\n <button class=\"zoomora-btn\" id=\"zoomoraZoomBtn\" title=\"Zoom\">\n <i class=\"zoomorai-zoom\"></i>\n </button>\n <button class=\"zoomora-btn\" id=\"zoomoraFullscreenBtn\" title=\"Fullscreen\">\n <i class=\"zoomorai-expand\"></i>\n </button>\n <button class=\"zoomora-btn\" id=\"zoomoraCollapseBtn\" title=\"Exit Fullscreen\" style=\"display: none;\">\n <i class=\"zoomorai-collapse\"></i>\n </button>\n <button class=\"zoomora-btn\" id=\"zoomoraCloseBtn\" title=\"Close\">\n <i class=\"zoomorai-close\"></i>\n </button>\n </div>\n </div>\n \n <div class=\"zoomora-content\" id=\"zoomoraContent\">\n <div class=\"zoomora-loading\" id=\"zoomoraLoading\"></div>\n <div class=\"zoomora-slides-container\" id=\"zoomoraSlidesContainer\"></div>\n </div>\n \n <button class=\"zoomora-nav prev\" id=\"zoomoraPrevBtn\">\n <i class=\"zoomorai-arrow-left\"></i>\n </button>\n <button class=\"zoomora-nav next\" id=\"zoomoraNextBtn\">\n <i class=\"zoomorai-arrow-right\"></i>\n </button>\n \n <div class=\"zoomora-caption\" id=\"zoomoraCaption\"></div>\n <div class=\"zoomora-thumbnails\" id=\"zoomoraThumbs\"></div>\n </div>\n </div>\n `;\n\n document.body.insertAdjacentHTML('beforeend', zoomoraHTML);\n\n // Cache DOM elements\n this.zoomora = document.getElementById('zoomoraLightbox');\n this.header = document.getElementById('zoomoraHeader');\n this.content = document.getElementById('zoomoraContent');\n this.slidesContainer = document.getElementById('zoomoraSlidesContainer');\n this.counter = document.getElementById('zoomoraCounter');\n this.thumbs = document.getElementById('zoomoraThumbs');\n this.loading = document.getElementById('zoomoraLoading');\n this.caption = document.getElementById('zoomoraCaption');\n this.prevBtn = document.getElementById('zoomoraPrevBtn');\n this.nextBtn = document.getElementById('zoomoraNextBtn');\n\n // Verify all elements were created\n if (!this.zoomora || !this.content || !this.counter || !this.thumbs || !this.loading || !this.caption) {\n throw new Error('Failed to create required DOM elements');\n }\n }\n\n /**\n * Bind event listeners\n */\n bindEvents() {\n // Document click handler for opening lightbox\n this.addEventListener(document, 'click', this.boundMethods.handleDocumentClick);\n\n // Control button handlers\n this.addEventListener(document.getElementById('zoomoraCloseBtn'), 'click', () => this.close());\n this.addEventListener(document.getElementById('zoomoraPrevBtn'), 'click', () => this.prev());\n this.addEventListener(document.getElementById('zoomoraNextBtn'), 'click', () => this.next());\n this.addEventListener(document.getElementById('zoomoraZoomBtn'), 'click', () => this.toggleZoom());\n this.addEventListener(document.getElementById('zoomoraFullscreenBtn'), 'click', () => this.toggleFullscreen());\n this.addEventListener(document.getElementById('zoomoraCollapseBtn'), 'click', () => this.exitFullscreen());\n this.addEventListener(document.getElementById('zoomoraThumbnailBtn'), 'click', () => this.toggleThumbnails());\n\n // Fullscreen change events\n this.addEventListener(document, 'fullscreenchange', this.boundMethods.handleFullscreenChange);\n this.addEventListener(document, 'webkitfullscreenchange', this.boundMethods.handleFullscreenChange);\n this.addEventListener(document, 'mozfullscreenchange', this.boundMethods.handleFullscreenChange);\n this.addEventListener(document, 'MSFullscreenChange', this.boundMethods.handleFullscreenChange);\n\n // Keyboard navigation\n this.addEventListener(document, 'keydown', this.boundMethods.handleKeydown);\n\n // Lightbox click to close\n this.addEventListener(this.zoomora, 'click', this.boundMethods.handleZoomoraClick);\n\n // Content click for zoom toggle\n this.addEventListener(this.content, 'click', this.boundMethods.handleContentClick);\n\n // Mouse drag events\n this.addEventListener(this.content, 'mousedown', this.boundMethods.handleMouseDown);\n this.addEventListener(this.content, 'mousemove', this.boundMethods.handleMouseMove);\n this.addEventListener(this.content, 'mouseup', this.boundMethods.handleMouseUp);\n this.addEventListener(this.content, 'mouseleave', this.boundMethods.handleMouseUp);\n\n // Touch events\n this.addEventListener(this.content, 'touchstart', this.boundMethods.handleTouchStart, {passive: false});\n this.addEventListener(this.content, 'touchmove', this.boundMethods.handleTouchMove, {passive: false});\n this.addEventListener(this.content, 'touchend', this.boundMethods.handleTouchEnd);\n\n // Add auto-hide toggle button handler\n this.addEventListener(document.getElementById('zoomoraAutoHideBtn'), 'click', () => this.toggleAutoHide());\n\n // Add mouse/touch activity listeners for auto-hide\n this.addEventListener(this.zoomora, 'mousemove', () => this.handleUserActivity());\n this.addEventListener(this.zoomora, 'touchstart', () => this.handleUserActivity());\n this.addEventListener(this.zoomora, 'keydown', () => this.handleUserActivity());\n }\n\n /**\n * Add event listener with cleanup tracking\n * @param {Element} element - DOM element\n * @param {string} event - Event type\n * @param {Function} handler - Event handler\n * @param {Object} options - Event options\n */\n addEventListener(element, event, handler, options = {}) {\n if (!element) return;\n\n element.addEventListener(event, handler, options);\n\n // Track for cleanup\n const key = `${element.constructor.name}_${event}`;\n if (!this.eventListeners.has(key)) {\n this.eventListeners.set(key, []);\n }\n this.eventListeners.get(key).push({element, event, handler, options});\n }\n\n /**\n * Handle document click events\n * @param {Event} e - Click event\n */\n handleDocumentClick(e) {\n const target = e.target.closest(this.options.selector);\n if (target) {\n e.preventDefault();\n this.open(target);\n }\n }\n\n /**\n * Handle keyboard events\n * @param {KeyboardEvent} e - Keyboard event\n */\n handleKeydown(e) {\n if (!this.zoomora.classList.contains('active')) return;\n\n switch (e.key) {\n case 'Escape':\n if (this.isFullscreen) {\n this.exitFullscreen();\n } else {\n this.close();\n }\n break;\n case 'ArrowLeft':\n this.prev();\n break;\n case 'ArrowRight':\n this.next();\n break;\n case 'z':\n case 'Z':\n this.toggleZoom();\n break;\n case 'f':\n case 'F':\n this.toggleFullscreen();\n break;\n case 't':\n case 'T':\n this.toggleThumbnails();\n break;\n }\n }\n\n /**\n * Handle fullscreen change events\n */\n handleFullscreenChange() {\n const isInFullscreen = document.fullscreenElement ||\n document.webkitFullscreenElement ||\n document.mozFullScreenElement ||\n document.msFullscreenElement;\n\n if (!isInFullscreen && this.isFullscreen) {\n this.isFullscreen = false;\n this.zoomora.classList.remove('fullscreen');\n this.updateButtons();\n }\n }\n\n /**\n * Handle zoomora container clicks\n * @param {Event} e - Click event\n */\n handleZoomoraClick(e) {\n if (e.target === this.zoomora) {\n this.close();\n }\n }\n\n /**\n * Handle content clicks\n * @param {Event} e - Click event\n */\n handleContentClick(e) {\n const media = e.target.closest('.zoomora-media');\n if (media && !media.classList.contains('no-zoom') && !this.isDragging) {\n this.toggleZoom();\n }\n }\n\n /**\n * Handle mouse down events\n * @param {MouseEvent} e - Mouse event\n */\n handleMouseDown(e) {\n this.startDrag(e);\n }\n\n /**\n * Handle mouse move events\n * @param {MouseEvent} e - Mouse event\n */\n handleMouseMove(e) {\n this.drag(e);\n }\n\n /**\n * Handle mouse up events\n */\n handleMouseUp() {\n this.endDrag();\n }\n\n /**\n * Handle touch start events\n * @param {TouchEvent} e - Touch event\n */\n handleTouchStart(e) {\n this.startDrag(e);\n }\n\n /**\n * Handle touch move events\n * @param {TouchEvent} e - Touch event\n */\n handleTouchMove(e) {\n this.drag(e);\n }\n\n /**\n * Handle touch end events\n */\n handleTouchEnd() {\n this.endDrag();\n }\n\n /**\n * Get image source from element\n * @param {Element} item - DOM element\n * @returns {string} - Image source URL\n */\n getImageSource(item) {\n const src = item.dataset.src || item.src || item.getAttribute('src');\n const type = item.dataset.type || 'image';\n\n // Handle YouTube URLs for video types\n if (type === 'video' && src) {\n return this.convertToEmbedUrl(src);\n }\n\n return src;\n }\n\n /**\n * Convert YouTube URLs to embed format\n * @param url\n * @returns {*|string}\n */\n convertToEmbedUrl(url) {\n // If already an embed URL, return as is\n if (url.includes('youtube.com/embed/')) {\n return url;\n }\n\n // Handle different YouTube URL formats\n let videoId = null;\n let startTime = null;\n\n // Extract video ID and start time from different YouTube URL formats\n if (url.includes('youtube.com/watch')) {\n const urlParams = new URLSearchParams(url.split('?')[1]);\n videoId = urlParams.get('v');\n const t = urlParams.get('t');\n if (t) {\n // Convert time format (e.g., \"111s\" to seconds)\n startTime = t.replace('s', '');\n }\n } else if (url.includes('youtu.be/')) {\n const parts = url.split('/');\n const videoAndParams = parts[parts.length - 1];\n if (videoAndParams.includes('?')) {\n videoId = videoAndParams.split('?')[0];\n const urlParams = new URLSearchParams(videoAndParams.split('?')[1]);\n const t = urlParams.get('t');\n if (t) startTime = t.replace('s', '');\n } else {\n videoId = videoAndParams;\n }\n }\n\n if (videoId) {\n let embedUrl = `https://www.youtube.com/embed/${videoId}`;\n const params = new URLSearchParams();\n\n if (startTime) {\n params.append('start', startTime);\n }\n\n // Add other useful parameters\n params.append('rel', '0'); // Don't show related videos\n params.append('modestbranding', '1'); // Modest branding\n\n // Option: Add autoplay for YouTube videos (uncomment if desired)\n // params.append('autoplay', '1');\n\n if (params.toString()) {\n embedUrl += '?' + params.toString();\n }\n\n return embedUrl;\n }\n\n // If not a YouTube URL or couldn't parse, return original\n return url;\n }\n\n /**\n * Get thumbnail source from element\n * @param {Element} item - DOM element\n * @returns {string} - Thumbnail source URL\n */\n getThumbnailSource(item) {\n const type = item.dataset.type || 'image';\n\n // For video items, always use the img.src as thumbnail (poster image)\n if (type === 'video') {\n return item.src || item.getAttribute('src');\n }\n\n // For regular images, use data-src or fallback to src\n return item.dataset.src || item.src || item.getAttribute('src');\n }\n\n /**\n * Get group identifier from element\n * @param {Element} element - DOM element\n * @returns {string} - Group identifier\n */\n getGroup(element) {\n if (this.options.useHref) {\n return element.dataset.lightbox || element.dataset.gallery || 'default';\n }\n return element.dataset.zoomora || 'default';\n }\n\n /**\n * Open lightbox with specified element\n * @param {Element} element - DOM element to open\n */\n open(element) {\n if (!element) return;\n\n const group = this.getGroup(element);\n let groupSelector;\n\n if (this.options.useHref) {\n if (element.dataset.lightbox) {\n groupSelector = `[data-lightbox=\"${group}\"]`;\n } else if (element.dataset.gallery) {\n groupSelector = `[data-gallery=\"${group}\"]`;\n } else {\n groupSelector = this.options.selector;\n }\n } else {\n groupSelector = `[data-zoomora=\"${group}\"]`;\n }\n\n this.items = Array.from(document.querySelectorAll(groupSelector));\n this.currentIndex = Math.max(0, this.items.indexOf(element));\n\n // Reset states\n this.isZoomed = false;\n this.isFullscreen = false;\n this.thumbnailsVisible = true;\n this.currentX = 0;\n this.currentY = 0;\n this.currentScale = 1;\n\n this.zoomora.classList.add('active');\n document.body.style.overflow = 'hidden';\n\n this.loadContent();\n this.updateThumbnails();\n this.updateCounter();\n this.updateNavigation();\n this.updateCaption();\n this.updateButtons();\n\n // Initialize auto-hide if enabled\n if (this.autoHideEnabled) {\n this.startAutoHideTimer();\n } else {\n this.showControls();\n }\n\n // Trigger callback\n if (typeof this.options.onOpen === 'function') {\n this.options.onOpen(element, this.currentIndex);\n }\n }\n\n /**\n * Close lightbox\n */\n close() {\n if (this.isFullscreen) {\n this.exitFullscreen();\n }\n\n this.zoomora.classList.remove('active');\n document.body.style.overflow = '';\n this.isZoomed = false;\n this.isFullscreen = false;\n this.currentX = 0;\n this.currentY = 0;\n this.currentScale = 1;\n\n const media = this.content.querySelector('.zoomora-media');\n if (media) {\n media.classList.remove('zoomed');\n media.style.transform = '';\n media.style.cursor = '';\n }\n\n this.zoomora.classList.remove('fullscreen');\n this.updateButtons();\n\n // Clean up auto-hide\n this.stopAutoHideTimer();\n this.showControls();\n\n // Trigger callback\n if (typeof this.options.onClose === 'function') {\n this.options.onClose(this.currentIndex);\n }\n }\n\n /**\n * Navigate to previous item\n */\n prev() {\n if (this.currentIndex > 0) {\n this.currentIndex--;\n this.loadContent();\n this.updateCounter();\n this.updateThumbnails();\n this.updateNavigation();\n this.updateCaption();\n\n // Trigger callback\n if (typeof this.options.onPrev === 'function') {\n this.options.onPrev(this.currentIndex);\n }\n }\n }\n\n /**\n * Navigate to next item\n */\n next() {\n if (this.currentIndex < this.items.length - 1) {\n this.currentIndex++;\n this.loadContent();\n this.updateCounter();\n this.updateThumbnails();\n this.updateNavigation();\n this.updateCaption();\n\n // Trigger callback\n if (typeof this.options.onNext === 'function') {\n this.options.onNext(this.currentIndex);\n }\n }\n }\n\n /**\n * Load content for current item\n */\n loadContent() {\n if (!this.items[this.currentIndex]) return;\n\n const item = this.items[this.currentIndex];\n const src = this.getImageSource(item);\n const type = item.dataset.type || 'image';\n\n if (!src) {\n console.error('Zoomora: No source found for item');\n return;\n }\n\n // Show loading spinner\n this.loading.style.display = 'block';\n\n // Clear content but keep the loading reference intact\n // Don't replace innerHTML, just clear the slides\n if (this.slidesContainer) {\n this.slidesContainer.innerHTML = '';\n }\n\n // Add slight delay for smooth transition\n setTimeout(() => {\n this.renderContent(src, type, item);\n }, 100);\n }\n\n /**\n * Render content based on type\n * @param {string} src - Source URL\n * @param {string} type - Content type\n * @param {Element} item - Original item element\n */\n renderContent(src, type, item) {\n const slideContainer = document.createElement('div');\n slideContainer.className = 'zoomora-slide-container';\n\n // Create slide wrapper\n const slide = document.createElement('div');\n slide.className = `zoomora-slide ${this.options.transition === 'slide' ? 'slide-effect' : 'fade-effect'}`;\n slide.style.opacity = '0';\n slide.style.transform = this.options.transition === 'slide' ? 'translateX(100%)' : 'scale(0.8)';\n\n let mediaElement;\n\n try {\n switch (type) {\n case 'video':\n if (src.endsWith('.mp4') || src.endsWith('.webm') || src.endsWith('.ogg')) {\n const videoContainer = document.createElement('div');\n videoContainer.className = 'zoomora-video-container';\n\n mediaElement = document.createElement('video');\n mediaElement.src = src;\n mediaElement.className = 'zoomora-video';\n mediaElement.setAttribute('preload', 'metadata');\n\n const posterSrc = item.src || item.getAttribute('src');\n if (posterSrc) {\n mediaElement.setAttribute('poster', posterSrc);\n }\n\n const playButton = document.createElement('div');\n playButton.className = 'zoomora-play-button';\n playButton.innerHTML = `<svg viewBox=\"0 0 24 24\" fill=\"currentColor\"><path d=\"M8 5v14l11-7z\"/></svg>`;\n\n playButton.addEventListener('click', () => {\n mediaElement.play();\n playButton.style.display = 'none';\n mediaElement.setAttribute('controls', '');\n });\n\n mediaElement.addEventListener('ended', () => {\n playButton.style.display = 'flex';\n });\n\n videoContainer.appendChild(mediaElement);\n videoContainer.appendChild(playButton);\n slideContainer.appendChild(videoContainer);\n } else {\n mediaElement = document.createElement('iframe');\n mediaElement.src = src;\n mediaElement.className = 'zoomora-video';\n mediaElement.setAttribute('allowfullscreen', '');\n mediaElement.setAttribute('frameborder', '0');\n slideContainer.appendChild(mediaElement);\n }\n break;\n\n case 'iframe':\n mediaElement = document.createElement('iframe');\n mediaElement.src = src;\n mediaElement.className = 'zoomora-iframe';\n mediaElement.setAttribute('frameborder', '0');\n slideContainer.appendChild(mediaElement);\n break;\n\n default:\n mediaElement = document.createElement('img');\n mediaElement.src = src;\n mediaElement.className = 'zoomora-media';\n mediaElement.alt = item.alt || item.title || '';\n\n mediaElement.onload = () => {\n this.loading.style.display = 'none';\n this.checkZoomability(mediaElement);\n this.animateSlideIn(slide);\n };\n\n mediaElement.onerror = () => {\n this.loading.style.display = 'none';\n console.error('Zoomora: Failed to load image:', src);\n this.animateSlideIn(slide);\n };\n\n slideContainer.appendChild(mediaElement);\n }\n\n slide.appendChild(slideContainer);\n\n // Clear existing slides and add new one\n this.slidesContainer.innerHTML = '';\n this.slidesContainer.appendChild(slide);\n\n if (type !== 'image') {\n this.loading.style.display = 'none';\n this.animateSlideIn(slide);\n }\n\n } catch (error) {\n console.error('Zoomora: Error rendering content:', error);\n this.loading.style.display = 'none';\n }\n }\n\n // Animation helper\n animateSlideIn(slide) {\n // Force reflow\n slide.offsetHeight;\n\n // Add active class and animate\n slide.classList.add('active');\n\n if (this.options.transition === 'slide') {\n slide.style.transition = `transform ${this.options.animationDuration}ms ease, opacity ${this.options.animationDuration}ms ease`;\n slide.style.transform = 'translateX(0)';\n slide.style.opacity = '1';\n } else {\n slide.style.transition = `transform ${this.options.animationDuration}ms ease, opacity ${this.options.animationDuration}ms ease`;\n slide.style.transform = 'scale(1)';\n slide.style.opacity = '1';\n }\n }\n\n // Toggle auto-hide controls\n toggleAutoHide() {\n this.autoHideEnabled = !this.autoHideEnabled;\n const autoHideBtn = document.getElementById('zoomoraAutoHideBtn');\n\n if (this.autoHideEnabled) {\n autoHideBtn.classList.add('active');\n autoHideBtn.title = 'Disable Auto-Hide Controls';\n this.startAutoHideTimer();\n } else {\n autoHideBtn.classList.remove('active');\n autoHideBtn.title = 'Enable Auto-Hide Controls';\n this.stopAutoHideTimer();\n this.showControls();\n }\n }\n\n // Handle user activity\n handleUserActivity() {\n if (!this.autoHideEnabled) return;\n\n this.showControls();\n this.startAutoHideTimer();\n }\n\n // Start auto-hide timer\n startAutoHideTimer() {\n this.stopAutoHideTimer();\n\n this.autoHideTimeout = setTimeout(() => {\n this.hideControls();\n }, this.options.autoHideDelay);\n }\n\n // Stop auto-hide timer\n stopAutoHideTimer() {\n if (this.autoHideTimeout) {\n clearTimeout(this.autoHideTimeout);\n this.autoHideTimeout = null;\n }\n }\n\n // Show controls\n showControls() {\n if (this.isControlsVisible) return;\n\n this.isControlsVisible = true;\n this.zoomora.classList.remove('controls-hidden');\n\n // Animate controls back in\n if (this.header) {\n this.header.style.transform = 'translateY(0)';\n this.header.style.opacity = '1';\n }\n\n if (this.caption) {\n this.caption.style.transform = 'translateX(-50%) translateY(0)';\n this.caption.style.opacity = '1';\n }\n\n if (this.thumbs) {\n this.thumbs.style.transform = 'translateX(-50%) translateY(0)';\n this.thumbs.style.opacity = '1';\n }\n\n if (this.prevBtn) {\n this.prevBtn.style.transform = 'translateX(0)';\n this.prevBtn.style.opacity = '1';\n }\n\n if (this.nextBtn) {\n this.nextBtn.style.transform = 'translateX(0)';\n this.nextBtn.style.opacity = '1';\n }\n }\n\n // Hide controls\n hideControls() {\n if (!this.isControlsVisible) return;\n\n this.isControlsVisible = false;\n this.zoomora.classList.add('controls-hidden');\n\n // Animate controls out\n if (this.header) {\n this.header.style.transform = 'translateY(-100%)';\n this.header.style.opacity = '0';\n }\n\n if (this.caption) {\n this.caption.style.transform = 'translateX(-50%) translateY(100%)';\n this.caption.style.opacity = '0';\n }\n\n if (this.thumbs) {\n this.thumbs.style.transform = 'translateX(-50%) translateY(100%)';\n this.thumbs.style.opacity = '0';\n }\n\n if (this.prevBtn) {\n this.prevBtn.style.transform = 'translateX(-100%)';\n this.prevBtn.style.opacity = '0';\n }\n\n if (this.nextBtn) {\n this.nextBtn.style.transform = 'translateX(100%)';\n this.nextBtn.style.opacity = '0';\n }\n }\n\n /**\n * Check if image can be zoomed\n * @param {HTMLImageElement} img - Image element\n */\n checkZoomability(img) {\n if (!img || !img.naturalWidth || !img.naturalHeight) return;\n\n const imgRect = img.getBoundingClientRect();\n const renderedWidth = imgRect.width;\n const renderedHeight = imgRect.height;\n const naturalWidth = img.naturalWidth;\n const naturalHeight = img.naturalHeight;\n\n const isScaledDown = naturalWidth > renderedWidth || naturalHeight > renderedHeight;\n const zoomRatioX = naturalWidth / renderedWidth;\n const zoomRatioY = naturalHeight / renderedHeight;\n const maxZoomRatio = Math.max(zoomRatioX, zoomRatioY);\n\n // Store zoom info\n img.dataset.zoomRatio = maxZoomRatio;\n img.dataset.naturalWidth = naturalWidth;\n img.dataset.naturalHeight = naturalHeight;\n img.dataset.renderedWidth = renderedWidth;\n img.dataset.renderedHeight = renderedHeight;\n\n // Enable zoom if significantly scaled down\n if (isScaledDown && maxZoomRatio > 1.1) {\n img.classList.remove('no-zoom');\n } else {\n img.classList.add('no-zoom');\n }\n }\n\n /**\n * Update counter display\n */\n updateCounter() {\n if (this.options.showCounter && this.counter) {\n this.counter.textContent = `${this.currentIndex + 1} / ${this.items.length}`;\n }\n }\n\n /**\n * Update caption display\n */\n updateCaption() {\n if (!this.caption || !this.items[this.currentIndex]) return;\n\n const item = this.items[this.currentIndex];\n const caption = item.dataset.caption || item.title || '';\n\n if (caption) {\n this.caption.textContent = caption;\n this.caption.style.transform = 'translateX(-50%) translateY(0)';\n this.caption.style.opacity = '1';\n this.caption.style.pointerEvents = 'auto';\n this.caption.style.transition = 'opacity 0.3s ease, transform 0.3s ease';\n } else {\n this.caption.style.transform = 'translateX(-50%) translateY(100%)';\n this.caption.style.opacity = '0';\n this.caption.style.pointerEvents = 'none';\n this.caption.style.transition = 'opacity 0.3s ease, transform 0.3s ease';\n }\n }\n\n /**\n * Update thumbnails display\n */\n updateThumbnails() {\n if (!this.options.showThumbnails || !this.thumbs) return;\n\n if (this.items.length === 1) {\n this.caption.classList.add('single-item-thumbnail');\n this.thumbs.style.display = 'none';\n return;\n }\n\n this.caption.classList.remove('single-item-thumbnail');\n\n this.thumbs.style.display = 'flex';\n this.thumbs.innerHTML = '';\n\n this.items.forEach((item, index) => {\n const thumb = document.createElement('div');\n thumb.className = 'zoomora-thumb';\n if (index === this.currentIndex) thumb.classList.add('active');\n\n const img = document.createElement('img');\n const thumbSrc = this.getThumbnailSource(item);\n\n if (thumbSrc) {\n img.src = thumbSrc;\n img.alt = item.alt || item.title || '';\n img.onerror = () => {\n thumb.style.display = 'none';\n };\n }\n\n thumb.appendChild(img);\n\n thumb.addEventListener('click', () => {\n this.currentIndex = index;\n this.loadContent();\n this.updateCounter();\n this.updateThumbnails();\n this.updateNavigation();\n this.updateCaption();\n });\n\n this.thumbs.appendChild(thumb);\n });\n }\n\n /**\n * Update navigation buttons\n */\n updateNavigation() {\n const prevBtn = document.getElementById('zoomoraPrevBtn');\n const nextBtn = document.getElementById('zoomoraNextBtn');\n\n if (prevBtn) {\n prevBtn.style.display = this.currentIndex > 0 ? 'flex' : 'none';\n }\n if (nextBtn) {\n nextBtn.style.display = this.currentIndex < this.items.length - 1 ? 'flex' : 'none';\n }\n }\n\n /**\n * Update control buttons\n */\n updateButtons() {\n const fullscreenBtn = document.getElementById('zoomoraFullscreenBtn');\n const collapseBtn = document.getElementById('zoomoraCollapseBtn');\n\n if (fullscreenBtn && collapseBtn) {\n if (this.isFullscreen) {\n fullscreenBtn.style.display = 'none';\n collapseBtn.style.display = 'flex';\n } else {\n fullscreenBtn.style.display = 'flex';\n collapseBtn.style.display = 'none';\n }\n }\n }\n\n /**\n * Toggle zoom state\n */\n toggleZoom() {\n const media = this.content.querySelector('.zoomora-media');\n if (!media || media.tagName !== 'IMG' || media.classList.contains('no-zoom')) return;\n\n this.isZoomed = !this.isZoomed;\n media.classList.toggle('zoomed', this.isZoomed);\n\n if (this.isZoomed) {\n const zoomRatio = parseFloat(media.dataset.zoomRatio) || 2;\n let zoomScale = Math.min(zoomRatio, this.options.maxZoomScale);\n\n if (zoomRatio > 2.5) {\n zoomScale = Math.min(zoomRatio * 0.7, 2.5);\n }\n\n media.style.transform = `scale(${zoomScale})`;\n media.style.cursor = 'grab';\n media.dataset.currentZoomScale = zoomScale;\n this.currentScale = zoomScale;\n } else {\n media.style.transform = '';\n media.style.cursor = '';\n this.currentX = 0;\n this.currentY = 0;\n this.currentScale = 1;\n }\n }\n\n /**\n * Toggle fullscreen mode\n */\n toggleFullscreen() {\n if (!this.isFullscreen) {\n this.enterFullscreen();\n } else {\n this.exitFullscreen();\n }\n }\n\n /**\n * Enter fullscreen mode\n */\n enterFullscreen() {\n const element = this.zoomora;\n const requestFullscreen = element.requestFullscreen ||\n element.webkitRequestFullscreen ||\n element.mozRequestFullScreen ||\n element.msRequestFullscreen;\n\n if (requestFullscreen) {\n requestFullscreen.call(element).then(() => {\n this.isFullscreen = true;\n this.zoomora.classList.add('fullscreen');\n this.updateButtons();\n }).catch(err => {\n console.warn('Zoomora: Could not enter fullscreen:', err);\n this.fallbackFullscreen();\n });\n } else {\n this.fallbackFullscreen();\n }\n }\n\n /**\n * Exit fullscreen mode\n */\n exitFullscreen() {\n const isInFullscreen = document.fullscreenElement ||\n document.webkitFullscreenElement ||\n document.mozFullScreenElement ||\n document.msFullscreenElement;\n\n if (isInFullscreen) {\n const exitFullscreen = document.exitFullscreen ||\n document.webkitExitFullscreen ||\n document.mozCancelFullScreen ||\n document.msExitFullscreen;\n\n if (exitFullscreen) {\n exitFullscreen.call(document).then(() => {\n this.isFullscreen = false;\n this.zoomora.classList.remove('fullscreen');\n this.updateButtons();\n }).catch(err => {\n console.warn('Zoomora: Could not exit fullscreen:', err);\n this.fallbackExitFullscreen();\n });\n } else {\n this.fallbackExitFullscreen();\n }\n } else {\n this.fallbackExitFullscreen();\n }\n }\n\n /**\n * Fallback fullscreen using CSS\n */\n fallbackFullscreen() {\n this.isFullscreen = true;\n this.zoomora.classList.add('fullscreen');\n this.updateButtons();\n }\n\n /**\n * Exit CSS fullscreen\n */\n fallbackExitFullscreen() {\n this.isFullscreen = false;\n this.zoomora.classList.remove('fullscreen');\n this.updateButtons();\n }\n\n /**\n * Toggle thumbnails visibility\n */\n toggleThumbnails() {\n if (this.items.length === 1) return;\n\n this.thumbnailsVisible = !this.thumbnailsVisible;\n if (this.thumbs) {\n this.thumbs.classList.toggle('thumbs-hidden', !this.thumbnailsVisible);\n\n if (!this.caption || !this.items[this.currentIndex]) return;\n\n const item = this.items[this.currentIndex];\n const caption = item.dataset.caption || item.title || '';\n\n if (caption && this.thumbs.classList.contains('thumbs-hidden')) {\n this.caption.style.bottom = '20px';\n this.caption.style.transition = 'bottom 0.3s ease, transform 0.3s ease';\n } else {\n this.caption.style.bottom = '120px';\n }\n }\n }\n\n /**\n * Start drag operation\n * @param {Event} e - Mouse or touch event\n */\n startDrag(e) {\n const media = this.content.querySelector('.zoomora-media');\n if (!media || !this.isZoomed) return;\n\n this.isDragging = true;\n media.style.cursor = 'grabbing';\n\n this.startX = e.clientX || (e.touches && e.touches[0].clientX) || 0;\n this.startY = e.clientY || (e.touches && e.touches[0].clientY) || 0;\n\n // Parse current transform\n const transform = media.style.transform;\n const scaleMatch = transform.match(/scale\\(([^)]+)\\)/);\n const translateMatch = transform.match(/translate\\(([^,]+),\\s*([^)]+)\\)/);\n\n this.currentScale = scaleMatch ? parseFloat(scaleMatch[1]) : 1;\n this.currentX = translateMatch ? parseFloat(translateMatch[1]) : 0;\n this.currentY = translateMatch ? parseFloat(translateMatch[2]) : 0;\n\n e.preventDefault();\n }\n\n /**\n * Handle drag movement\n * @param {Event} e - Mouse or touch event\n */\n drag(e) {\n if (!this.isDragging) return;\n\n e.preventDefault();\n const clientX = e.clientX || (e.touches && e.touches[0].clientX) || 0;\n const clientY = e.clientY || (e.touches && e.touches[0].clientY) || 0;\n\n const deltaX = clientX - this.startX;\n const deltaY = clientY - this.startY;\n\n const newX = this.currentX + deltaX;\n const newY = this.currentY + deltaY;\n\n const media = this.content.querySelector('.zoomora-media');\n if (!media) return;\n\n const mediaRect = media.getBoundingClientRect();\n const scale = this.currentScale;\n const maxX = (mediaRect.width * (scale - 1)) / 2;\n const maxY = (mediaRect.height * (scale - 1)) / 2;\n\n const constrainedX = Math.max(-maxX, Math.min(maxX, newX));\n const constrainedY = Math.max(-maxY, Math.min(maxY, newY));\n\n media.style.transform = `scale(${scale}) translate(${constrainedX}px, ${constrainedY}px)`;\n }\n\n /**\n * End drag operation\n */\n endDrag() {\n if (!this.isDragging) return;\n\n this.isDragging = false;\n const media = this.content.querySelector('.zoomora-media');\n if (media && this.isZoomed) {\n media.style.cursor = 'grab';\n }\n }\n\n /**\n * Go to specific item by index\n * @param {number} index - Item index\n */\n goTo(index) {\n if (index < 0 || index >= this.items.length) return;\n\n this.currentIndex = index;\n this.loadContent();\n this.updateCounter();\n this.updateThumbnails();\n this.updateNavigation();\n this.updateCaption();\n }\n\n /**\n * Get current item index\n * @returns {number} - Current index\n */\n getCurrentIndex() {\n return this.currentIndex;\n }\n\n /**\n * Get total number of items\n * @returns {number} - Total items\n */\n getTotalItems() {\n return this.items.length;\n }\n\n /**\n * Check if lightbox is open\n * @returns {boolean} - True if open\n */\n isOpen() {\n return this.zoomora && this.zoomora.classList.contains('active');\n }\n\n /**\n * Update options\n * @param {Object} newOptions - New options to merge\n */\n updateOptions(newOptions) {\n this.options = {...this.options, ...newOptions};\n }\n\n /**\n * Refresh the lightbox (re-scan for items)\n */\n refresh() {\n if (this.isOpen()) {\n const currentItem = this.items[this.currentIndex];\n if (currentItem) {\n this.open(currentItem);\n }\n }\n }\n\n /**\n * Destroy the lightbox instance\n */\n destroy() {\n if (!this.isInitialized) return;\n\n // Close if open\n if (this.isOpen()) {\n this.close();\n }\n\n // Clean up auto-hide\n this.stopAutoHideTimer();\n\n // Remove all event listeners\n this.eventListeners.forEach((listeners, key) => {\n listeners.forEach(({element, event, handler, options}) => {\n if (element && element.removeEventListener) {\n element.removeEventListener(event, handler, options);\n }\n });\n });\n this.eventListeners.clear();\n\n // Remove DOM elements\n if (this.zoomora && this.zoomora.parentNode) {\n this.zoomora.parentNode.removeChild(this.zoomora);\n }\n\n // Reset properties\n this.isInitialized = false;\n this.items = [];\n this.currentIndex = 0;\n this.zoomora = null;\n this.content = null;\n this.counter = null;\n this.thumbs = null;\n this.loading = null;\n this.caption = null;\n }\n }\n\n // Export the class\n return Zoomora;\n}));"],"names":["global","factory","window","this","Zoomora","defaults","selector","showCounter","showThumbnails","showFullscreen","showZoom","transition","useHref","maxZoomScale","zoomStep","animationDuration","onOpen","onClose","onNext","onPrev","showAutoHideToggle","autoHideDelay","autoHideEnabled","constructor","options","__spreadValues","currentIndex","items","isZoomed","isFullscreen","isDragging","thumbnailsVisible","startX","startY","currentX","currentY","currentScale","isInitialized","eventListeners","Map","autoHideTimeout","isControlsVisible","idleTimer","boundMethods","handleDocumentClick","bind","handleKeydown","handleFullscreenChange","handleZoomoraClick","handleContentClick","handleMouseDown","handleMouseMove","handleMouseUp","handleTouchStart","handleTouchMove","handleTouchEnd","init","console","warn","createLightbox","bindEvents","error","enhancedOptions","document","getElementById","body","insertAdjacentHTML","zoomora","header","content","slidesContainer","counter","thumbs","loading","caption","prevBtn","nextBtn","Error","addEventListener","close","prev","next","toggleZoom","toggleFullscreen","exitFullscreen","toggleThumbnails","passive","toggleAutoHide","handleUserActivity","element","event","handler","key","name","has","set","get","push","e","target","closest","preventDefault","open","classList","contains","fullscreenElement","webkitFullscreenElement","mozFullScreenElement","msFullscreenElement","remove","updateButtons","media","startDrag","drag","endDrag","getImageSource","item","src","dataset","getAttribute","type","convertToEmbedUrl","url","includes","videoId","startTime","urlParams","URLSearchParams","split","t","replace","parts","videoAndParams","length","embedUrl","params","append","toString","getThumbnailSource","getGroup","lightbox","gallery","group","groupSelector","Array","from","querySelectorAll","Math","max","indexOf","add","style","overflow","loadContent","updateThumbnails","updateCounter","updateNavigation","updateCaption","startAutoHideTimer","showControls","querySelector","transform","cursor","stopAutoHideTimer","display","innerHTML","setTimeout","renderContent","slideContainer","createElement","className","slide","mediaElement","opacity","endsWith","videoContainer","setAttribute","posterSrc","playButton","play","appendChild","alt","title","onload","checkZoomability","animateSlideIn","onerror","offsetHeight","autoHideBtn","hideControls","clearTimeout","img","naturalWidth","naturalHeight","imgRect","getBoundingClientRect","renderedWidth","width","renderedHeight","height","isScaledDown","zoomRatioX","zoomRatioY","maxZoomRatio","zoomRatio","textContent","pointerEvents","forEach","index","thumb","thumbSrc","fullscreenBtn","collapseBtn","tagName","toggle","parseFloat","zoomScale","min","currentZoomScale","enterFullscreen","requestFullscreen","webkitRequestFullscreen","mozRequestFullScreen","msRequestFullscreen","call","then","catch","err","fallbackFullscreen","webkitExitFullscreen","mozCancelFullScreen","msExitFullscreen","fallbackExitFullscreen","bottom","clientX","touches","clientY","scaleMatch","match","translateMatch","deltaX","deltaY","newX","newY","mediaRect","scale","maxX","maxY","constrainedX","constrainedY","goTo","getCurrentIndex","getTotalItems","isOpen","updateOptions","newOptions","refresh","currentItem","destroy","listeners","removeEventListener","clear","parentNode","removeChild","module","exports","define","amd"],"mappings":"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"}
1
+ {"version":3,"file":"zoomora.umd.min.js","sources":["../src/zoomora.js"],"sourcesContent":["/*!\n * Zoomora Lightbox Plugin v1.1.0\n * A modern, responsive lightbox plugin with zoom, fullscreen, and gallery features\n *\n * Copyright (c) 2025 Faruk Ahmed (FrontTheme)\n * Licensed under MIT License\n */\n\n// Import styles\nimport './styles/zoomora.scss';\n\n(function (global, factory) {\n 'use strict';\n\n if (typeof module === 'object' && typeof module.exports === 'object') {\n // CommonJS/Node.js\n module.exports = factory();\n } else if (typeof define === 'function' && define.amd) {\n // AMD\n define(factory);\n } else {\n // Browser globals\n global.Zoomora = factory();\n }\n}(typeof window !== 'undefined' ? window : this, function () {\n 'use strict';\n\n /**\n * Zoomora Lightbox Plugin\n * @class\n */\n class Zoomora {\n /**\n * Default configuration options\n * @type {Object}\n */\n static get defaults() {\n return {\n selector: '[data-zoomora]',\n showCounter: true,\n showThumbnails: true,\n showFullscreen: true,\n showZoom: true,\n transition: 'fade', // 'fade' or 'slide'\n useHref: false, // Use href instead of data-src\n maxZoomScale: 3, // Maximum zoom scale\n zoomStep: 0.1, // Zoom step for scroll wheel\n animationDuration: 300, // Animation duration in ms\n onOpen: null, // Callback when lightbox opens\n onClose: null, // Callback when lightbox closes\n onNext: null, // Callback when navigating to next item\n onPrev: null, // Callback when navigating to previous item\n\n // Auto-hide controls\n showAutoHideToggle: true, // Show auto-hide toggle button\n autoHideDelay: 3000, // Delay in ms before hiding controls\n autoHideEnabled: false, // Default state of auto-hide\n };\n }\n\n /**\n * Constructor\n * @param {Object} options - Configuration options\n */\n constructor(options = {}) {\n this.options = {...Zoomora.defaults, ...options};\n this.currentIndex = 0;\n this.items = [];\n this.isZoomed = false;\n this.isFullscreen = false;\n this.isDragging = false;\n this.thumbnailsVisible = true;\n this.startX = 0;\n this.startY = 0;\n this.currentX = 0;\n this.currentY = 0;\n this.currentScale = 1;\n this.isInitialized = false;\n this.eventListeners = new Map();\n\n // Auto-hide controls\n this.autoHideEnabled = false;\n this.autoHideTimeout = null;\n this.autoHideDelay = 3000;\n this.isControlsVisible = true;\n this.idleTimer = null;\n\n this.lastDragTime = 0;\n\n // Bound methods for event listeners\n this.boundMethods = {\n handleDocumentClick: this.handleDocumentClick.bind(this),\n handleKeydown: this.handleKeydown.bind(this),\n handleFullscreenChange: this.handleFullscreenChange.bind(this),\n handleZoomoraClick: this.handleZoomoraClick.bind(this),\n handleContentClick: this.handleContentClick.bind(this),\n handleMouseDown: this.handleMouseDown.bind(this),\n handleMouseMove: this.handleMouseMove.bind(this),\n handleMouseUp: this.handleMouseUp.bind(this),\n handleTouchStart: this.handleTouchStart.bind(this),\n handleTouchMove: this.handleTouchMove.bind(this),\n handleTouchEnd: this.handleTouchEnd.bind(this),\n };\n\n this.init();\n }\n\n /**\n * Initialize the plugin\n */\n init() {\n if (this.isInitialized) {\n console.warn('Zoomora: Plugin already initialized');\n return;\n }\n\n try {\n this.createLightbox();\n this.bindEvents();\n\n this.isInitialized = true;\n } catch (error) {\n console.error('Zoomora: Initialization failed', error);\n }\n }\n\n /**\n * Static method to bind to anchor tags with href\n * @param {string} selector - CSS selector\n * @param {Object} options - Configuration options\n * @returns {Zoomora} - New Zoomora instance\n */\n static bind(selector, options = {}) {\n const enhancedOptions = {\n ...options,\n selector: selector,\n useHref: true\n };\n return new Zoomora(enhancedOptions);\n }\n\n /**\n * Create lightbox HTML structure\n */\n createLightbox() {\n // Check if lightbox already exists\n if (document.getElementById('zoomoraLightbox')) {\n console.warn('Zoomora: Lightbox already exists in DOM');\n return;\n }\n\n // Build auto-hide button conditionally\n const autoHideButtonHTML = this.options.showAutoHideToggle ? `\n <button class=\"zoomora-btn\" id=\"zoomoraAutoHideBtn\" title=\"Toggle Auto-Hide Controls\">\n <i class=\"zoomorai-controls-off\"></i>\n </button>\n ` : '';\n\n const zoomoraHTML = `\n <div class=\"zoomora\" id=\"zoomoraLightbox\">\n <div class=\"zoomora-container\">\n <div class=\"zoomora-header\" id=\"zoomoraHeader\">\n <div class=\"zoomora-counter\" id=\"zoomoraCounter\">1 / 1</div>\n <div class=\"zoomora-controls\">\n <button class=\"zoomora-btn\" id=\"zoomoraThumbnailBtn\" title=\"Toggle Thumbnails\">\n <i class=\"zoomorai-thumbnails\"></i>\n </button>\n ${autoHideButtonHTML}\n <button class=\"zoomora-btn\" id=\"zoomoraZoomBtn\" title=\"Zoom\">\n <i class=\"zoomorai-zoom\"></i>\n </button>\n <button class=\"zoomora-btn\" id=\"zoomoraFullscreenBtn\" title=\"Fullscreen\">\n <i class=\"zoomorai-expand\"></i>\n </button>\n <button class=\"zoomora-btn\" id=\"zoomoraCollapseBtn\" title=\"Exit Fullscreen\" style=\"display: none;\">\n <i class=\"zoomorai-collapse\"></i>\n </button>\n <button class=\"zoomora-btn\" id=\"zoomoraCloseBtn\" title=\"Close\">\n <i class=\"zoomorai-close\"></i>\n </button>\n </div>\n </div>\n \n <div class=\"zoomora-content\" id=\"zoomoraContent\">\n <div class=\"zoomora-loading\" id=\"zoomoraLoading\"></div>\n <div class=\"zoomora-slides-container\" id=\"zoomoraSlidesContainer\"></div>\n </div>\n \n <button class=\"zoomora-nav prev\" id=\"zoomoraPrevBtn\">\n <i class=\"zoomorai-arrow-left\"></i>\n </button>\n <button class=\"zoomora-nav next\" id=\"zoomoraNextBtn\">\n <i class=\"zoomorai-arrow-right\"></i>\n </button>\n \n <div class=\"zoomora-caption\" id=\"zoomoraCaption\"></div>\n <div class=\"zoomora-thumbnails\" id=\"zoomoraThumbs\"></div>\n </div>\n </div>\n `;\n\n document.body.insertAdjacentHTML('beforeend', zoomoraHTML);\n\n // Cache DOM elements\n this.zoomora = document.getElementById('zoomoraLightbox');\n this.header = document.getElementById('zoomoraHeader');\n this.content = document.getElementById('zoomoraContent');\n this.slidesContainer = document.getElementById('zoomoraSlidesContainer');\n this.counter = document.getElementById('zoomoraCounter');\n this.thumbs = document.getElementById('zoomoraThumbs');\n this.loading = document.getElementById('zoomoraLoading');\n this.caption = document.getElementById('zoomoraCaption');\n this.prevBtn = document.getElementById('zoomoraPrevBtn');\n this.nextBtn = document.getElementById('zoomoraNextBtn');\n\n // Verify all elements were created\n if (!this.zoomora || !this.content || !this.counter || !this.thumbs || !this.loading || !this.caption) {\n throw new Error('Failed to create required DOM elements');\n }\n }\n\n /**\n * Bind event listeners\n */\n bindEvents() {\n // Document click handler for opening lightbox\n this.addEventListener(document, 'click', this.boundMethods.handleDocumentClick);\n\n // Control button handlers\n this.addEventListener(document.getElementById('zoomoraCloseBtn'), 'click', () => this.close());\n this.addEventListener(document.getElementById('zoomoraPrevBtn'), 'click', () => this.prev());\n this.addEventListener(document.getElementById('zoomoraNextBtn'), 'click', () => this.next());\n this.addEventListener(document.getElementById('zoomoraZoomBtn'), 'click', () => this.toggleZoom());\n this.addEventListener(document.getElementById('zoomoraFullscreenBtn'), 'click', () => this.toggleFullscreen());\n this.addEventListener(document.getElementById('zoomoraCollapseBtn'), 'click', () => this.exitFullscreen());\n this.addEventListener(document.getElementById('zoomoraThumbnailBtn'), 'click', () => this.toggleThumbnails());\n\n // Fullscreen change events\n this.addEventListener(document, 'fullscreenchange', this.boundMethods.handleFullscreenChange);\n this.addEventListener(document, 'webkitfullscreenchange', this.boundMethods.handleFullscreenChange);\n this.addEventListener(document, 'mozfullscreenchange', this.boundMethods.handleFullscreenChange);\n this.addEventListener(document, 'MSFullscreenChange', this.boundMethods.handleFullscreenChange);\n\n // Keyboard navigation\n this.addEventListener(document, 'keydown', this.boundMethods.handleKeydown);\n\n // Lightbox click to close\n this.addEventListener(this.zoomora, 'click', this.boundMethods.handleZoomoraClick);\n\n // Content click for zoom toggle\n this.addEventListener(this.content, 'click', this.boundMethods.handleContentClick);\n\n // Mouse drag events\n this.addEventListener(this.content, 'mousedown', this.boundMethods.handleMouseDown);\n this.addEventListener(this.content, 'mousemove', this.boundMethods.handleMouseMove);\n this.addEventListener(this.content, 'mouseup', this.boundMethods.handleMouseUp);\n this.addEventListener(this.content, 'mouseleave', this.boundMethods.handleMouseUp);\n\n // Touch events\n this.addEventListener(this.content, 'touchstart', this.boundMethods.handleTouchStart, {passive: false});\n this.addEventListener(this.content, 'touchmove', this.boundMethods.handleTouchMove, {passive: false});\n this.addEventListener(this.content, 'touchend', this.boundMethods.handleTouchEnd);\n\n // Add auto-hide toggle button handler (only if enabled)\n if (this.options.showAutoHideToggle) {\n this.addEventListener(document.getElementById('zoomoraAutoHideBtn'), 'click', () => this.toggleAutoHide());\n\n // Add mouse/touch activity listeners for auto-hide\n this.addEventListener(this.zoomora, 'mousemove', () => this.handleUserActivity());\n this.addEventListener(this.zoomora, 'touchstart', () => this.handleUserActivity());\n this.addEventListener(this.zoomora, 'keydown', () => this.handleUserActivity());\n }\n }\n\n /**\n * Add event listener with cleanup tracking\n * @param {Element} element - DOM element\n * @param {string} event - Event type\n * @param {Function} handler - Event handler\n * @param {Object} options - Event options\n */\n addEventListener(element, event, handler, options = {}) {\n if (!element) return;\n\n element.addEventListener(event, handler, options);\n\n // Track for cleanup\n const key = `${element.constructor.name}_${event}`;\n if (!this.eventListeners.has(key)) {\n this.eventListeners.set(key, []);\n }\n this.eventListeners.get(key).push({element, event, handler, options});\n }\n\n /**\n * Handle document click events\n * @param {Event} e - Click event\n */\n handleDocumentClick(e) {\n const target = e.target.closest(this.options.selector);\n if (target) {\n e.preventDefault();\n this.open(target);\n }\n }\n\n /**\n * Handle keyboard events\n * @param {KeyboardEvent} e - Keyboard event\n */\n handleKeydown(e) {\n if (!this.zoomora.classList.contains('active')) return;\n\n switch (e.key) {\n case 'Escape':\n if (this.isFullscreen) {\n this.exitFullscreen();\n } else {\n this.close();\n }\n break;\n case 'ArrowLeft':\n this.prev();\n break;\n case 'ArrowRight':\n this.next();\n break;\n case 'z':\n case 'Z':\n this.toggleZoom();\n break;\n case 'f':\n case 'F':\n this.toggleFullscreen();\n break;\n case 't':\n case 'T':\n this.toggleThumbnails();\n break;\n }\n }\n\n /**\n * Handle fullscreen change events\n */\n handleFullscreenChange() {\n const isInFullscreen = document.fullscreenElement ||\n document.webkitFullscreenElement ||\n document.mozFullScreenElement ||\n document.msFullscreenElement;\n\n if (!isInFullscreen && this.isFullscreen) {\n this.isFullscreen = false;\n this.zoomora.classList.remove('fullscreen');\n this.updateButtons();\n }\n }\n\n /**\n * Handle zoomora container clicks\n * @param {Event} e - Click event\n */\n handleZoomoraClick(e) {\n if (e.target === this.zoomora) {\n this.close();\n }\n }\n\n /**\n * Handle content clicks\n * @param {Event} e - Click event\n */\n handleContentClick(e) {\n // Ignore click if we just finished dragging (within 200ms)\n if (Date.now() - this.lastDragTime < 200) {\n return;\n }\n\n const media = e.target.closest('.zoomora-media');\n if (media && !media.classList.contains('no-zoom')) {\n this.toggleZoom();\n }\n }\n\n /**\n * Handle mouse down events\n * @param {MouseEvent} e - Mouse event\n */\n handleMouseDown(e) {\n this.startDrag(e);\n }\n\n /**\n * Handle mouse move events\n * @param {MouseEvent} e - Mouse event\n */\n handleMouseMove(e) {\n this.drag(e);\n }\n\n /**\n * Handle mouse up events\n */\n handleMouseUp() {\n this.endDrag();\n }\n\n /**\n * Handle touch start events\n * @param {TouchEvent} e - Touch event\n */\n handleTouchStart(e) {\n this.startDrag(e);\n }\n\n /**\n * Handle touch move events\n * @param {TouchEvent} e - Touch event\n */\n handleTouchMove(e) {\n this.drag(e);\n }\n\n /**\n * Handle touch end events\n */\n handleTouchEnd() {\n this.endDrag();\n }\n\n /**\n * Get image source from element\n * @param {Element} item - DOM element\n * @returns {string} - Image source URL\n */\n getImageSource(item) {\n const src = item.dataset.src || item.src || item.getAttribute('src');\n const type = item.dataset.type || 'image';\n\n // Handle YouTube URLs for video types\n if (type === 'video' && src) {\n return this.convertToEmbedUrl(src);\n }\n\n return src;\n }\n\n /**\n * Convert YouTube URLs to embed format\n * @param url\n * @returns {*|string}\n */\n convertToEmbedUrl(url) {\n // If already an embed URL, return as is\n if (url.includes('youtube.com/embed/')) {\n return url;\n }\n\n // Handle different YouTube URL formats\n let videoId = null;\n let startTime = null;\n\n // Extract video ID and start time from different YouTube URL formats\n if (url.includes('youtube.com/watch')) {\n const urlParams = new URLSearchParams(url.split('?')[1]);\n videoId = urlParams.get('v');\n const t = urlParams.get('t');\n if (t) {\n // Convert time format (e.g., \"111s\" to seconds)\n startTime = t.replace('s', '');\n }\n } else if (url.includes('youtu.be/')) {\n const parts = url.split('/');\n const videoAndParams = parts[parts.length - 1];\n if (videoAndParams.includes('?')) {\n videoId = videoAndParams.split('?')[0];\n const urlParams = new URLSearchParams(videoAndParams.split('?')[1]);\n const t = urlParams.get('t');\n if (t) startTime = t.replace('s', '');\n } else {\n videoId = videoAndParams;\n }\n }\n\n if (videoId) {\n let embedUrl = `https://www.youtube.com/embed/${videoId}`;\n const params = new URLSearchParams();\n\n if (startTime) {\n params.append('start', startTime);\n }\n\n // Add other useful parameters\n params.append('rel', '0'); // Don't show related videos\n params.append('modestbranding', '1'); // Modest branding\n\n // Option: Add autoplay for YouTube videos (uncomment if desired)\n // params.append('autoplay', '1');\n\n if (params.toString()) {\n embedUrl += '?' + params.toString();\n }\n\n return embedUrl;\n }\n\n // If not a YouTube URL or couldn't parse, return original\n return url;\n }\n\n /**\n * Get thumbnail source from element\n * @param {Element} item - DOM element\n * @returns {string} - Thumbnail source URL\n */\n getThumbnailSource(item) {\n const type = item.dataset.type || 'image';\n\n // For video items, always use the img.src as thumbnail (poster image)\n if (type === 'video') {\n return item.src || item.getAttribute('src');\n }\n\n // For regular images, use data-src or fallback to src\n return item.dataset.src || item.src || item.getAttribute('src');\n }\n\n /**\n * Get group identifier from element\n * @param {Element} element - DOM element\n * @returns {string} - Group identifier\n */\n getGroup(element) {\n if (this.options.useHref) {\n return element.dataset.lightbox || element.dataset.gallery || 'default';\n }\n return element.dataset.zoomora || 'default';\n }\n\n /**\n * Open lightbox with specified element\n * @param {Element} element - DOM element to open\n */\n open(element) {\n if (!element) return;\n\n const group = this.getGroup(element);\n let groupSelector;\n\n if (this.options.useHref) {\n if (element.dataset.lightbox) {\n groupSelector = `[data-lightbox=\"${group}\"]`;\n } else if (element.dataset.gallery) {\n groupSelector = `[data-gallery=\"${group}\"]`;\n } else {\n groupSelector = this.options.selector;\n }\n } else {\n groupSelector = `[data-zoomora=\"${group}\"]`;\n }\n\n this.items = Array.from(document.querySelectorAll(groupSelector));\n this.currentIndex = Math.max(0, this.items.indexOf(element));\n\n // Reset states\n this.isZoomed = false;\n this.isFullscreen = false;\n this.thumbnailsVisible = true;\n this.currentX = 0;\n this.currentY = 0;\n this.currentScale = 1;\n\n this.zoomora.classList.add('active');\n document.body.style.overflow = 'hidden';\n\n this.loadContent();\n this.updateThumbnails();\n this.updateCounter();\n this.updateNavigation();\n this.updateCaption();\n this.updateButtons();\n\n // Initialize auto-hide if enabled\n if (this.autoHideEnabled) {\n this.startAutoHideTimer();\n } else {\n this.showControls();\n }\n\n // Trigger callback\n if (typeof this.options.onOpen === 'function') {\n this.options.onOpen(element, this.currentIndex);\n }\n }\n\n /**\n * Close lightbox\n */\n close() {\n if (this.isFullscreen) {\n this.exitFullscreen();\n }\n\n this.zoomora.classList.remove('active');\n document.body.style.overflow = '';\n this.isZoomed = false;\n this.isFullscreen = false;\n this.currentX = 0;\n this.currentY = 0;\n this.currentScale = 1;\n\n const media = this.content.querySelector('.zoomora-media');\n if (media) {\n media.classList.remove('zoomed');\n media.style.transform = '';\n media.style.cursor = '';\n }\n\n this.zoomora.classList.remove('fullscreen');\n this.updateButtons();\n\n // Clean up auto-hide\n this.stopAutoHideTimer();\n this.showControls();\n\n // Trigger callback\n if (typeof this.options.onClose === 'function') {\n this.options.onClose(this.currentIndex);\n }\n }\n\n /**\n * Navigate to previous item\n */\n prev() {\n if (this.currentIndex > 0) {\n this.currentIndex--;\n this.loadContent();\n this.updateCounter();\n this.updateThumbnails();\n this.updateNavigation();\n this.updateCaption();\n\n // Trigger callback\n if (typeof this.options.onPrev === 'function') {\n this.options.onPrev(this.currentIndex);\n }\n }\n }\n\n /**\n * Navigate to next item\n */\n next() {\n if (this.currentIndex < this.items.length - 1) {\n this.currentIndex++;\n this.loadContent();\n this.updateCounter();\n this.updateThumbnails();\n this.updateNavigation();\n this.updateCaption();\n\n // Trigger callback\n if (typeof this.options.onNext === 'function') {\n this.options.onNext(this.currentIndex);\n }\n }\n }\n\n /**\n * Load content for current item\n */\n loadContent() {\n if (!this.items[this.currentIndex]) return;\n\n const item = this.items[this.currentIndex];\n const src = this.getImageSource(item);\n const type = item.dataset.type || 'image';\n\n if (!src) {\n console.error('Zoomora: No source found for item');\n return;\n }\n\n // Reset zoom state\n this.isZoomed = false;\n this.currentX = 0;\n this.currentY = 0;\n this.currentScale = 1;\n\n // Show loading spinner\n this.loading.style.display = 'block';\n\n if (this.slidesContainer) {\n this.slidesContainer.innerHTML = '';\n }\n\n setTimeout(() => {\n this.renderContent(src, type, item);\n }, 100);\n }\n\n /**\n * Render content based on type\n * @param {string} src - Source URL\n * @param {string} type - Content type\n * @param {Element} item - Original item element\n */\n renderContent(src, type, item) {\n const slideContainer = document.createElement('div');\n slideContainer.className = 'zoomora-slide-container';\n\n // Create slide wrapper\n const slide = document.createElement('div');\n slide.className = `zoomora-slide ${this.options.transition === 'slide' ? 'slide-effect' : 'fade-effect'}`;\n slide.style.opacity = '0';\n slide.style.transform = this.options.transition === 'slide' ? 'translateX(100%)' : 'scale(0.8)';\n\n let mediaElement;\n\n try {\n switch (type) {\n case 'video':\n if (src.endsWith('.mp4') || src.endsWith('.webm') || src.endsWith('.ogg')) {\n const videoContainer = document.createElement('div');\n videoContainer.className = 'zoomora-video-container';\n\n mediaElement = document.createElement('video');\n mediaElement.src = src;\n mediaElement.className = 'zoomora-video';\n mediaElement.setAttribute('preload', 'metadata');\n\n const posterSrc = item.src || item.getAttribute('src');\n if (posterSrc) {\n mediaElement.setAttribute('poster', posterSrc);\n }\n\n const playButton = document.createElement('div');\n playButton.className = 'zoomora-play-button';\n playButton.innerHTML = `<svg viewBox=\"0 0 24 24\" fill=\"currentColor\"><path d=\"M8 5v14l11-7z\"/></svg>`;\n\n playButton.addEventListener('click', () => {\n mediaElement.play();\n playButton.style.display = 'none';\n mediaElement.setAttribute('controls', '');\n });\n\n mediaElement.addEventListener('ended', () => {\n playButton.style.display = 'flex';\n });\n\n videoContainer.appendChild(mediaElement);\n videoContainer.appendChild(playButton);\n slideContainer.appendChild(videoContainer);\n } else {\n mediaElement = document.createElement('iframe');\n mediaElement.src = src;\n mediaElement.className = 'zoomora-video';\n mediaElement.setAttribute('allowfullscreen', '');\n mediaElement.setAttribute('frameborder', '0');\n slideContainer.appendChild(mediaElement);\n }\n break;\n\n case 'iframe':\n mediaElement = document.createElement('iframe');\n mediaElement.src = src;\n mediaElement.className = 'zoomora-iframe';\n mediaElement.setAttribute('frameborder', '0');\n slideContainer.appendChild(mediaElement);\n break;\n\n default:\n mediaElement = document.createElement('img');\n mediaElement.src = src;\n mediaElement.className = 'zoomora-media';\n mediaElement.alt = item.alt || item.title || '';\n\n mediaElement.onload = () => {\n this.loading.style.display = 'none';\n this.checkZoomability(mediaElement);\n this.animateSlideIn(slide);\n };\n\n mediaElement.onerror = () => {\n this.loading.style.display = 'none';\n console.error('Zoomora: Failed to load image:', src);\n this.animateSlideIn(slide);\n };\n\n slideContainer.appendChild(mediaElement);\n }\n\n slide.appendChild(slideContainer);\n\n // Clear existing slides and add new one\n this.slidesContainer.innerHTML = '';\n this.slidesContainer.appendChild(slide);\n\n if (type !== 'image') {\n this.loading.style.display = 'none';\n this.animateSlideIn(slide);\n }\n\n } catch (error) {\n console.error('Zoomora: Error rendering content:', error);\n this.loading.style.display = 'none';\n }\n }\n\n // Animation helper\n animateSlideIn(slide) {\n // Force reflow\n slide.offsetHeight;\n\n // Add active class and animate\n slide.classList.add('active');\n\n if (this.options.transition === 'slide') {\n slide.style.transition = `transform ${this.options.animationDuration}ms ease, opacity ${this.options.animationDuration}ms ease`;\n slide.style.transform = 'translateX(0)';\n slide.style.opacity = '1';\n } else {\n slide.style.transition = `transform ${this.options.animationDuration}ms ease, opacity ${this.options.animationDuration}ms ease`;\n slide.style.transform = 'scale(1)';\n slide.style.opacity = '1';\n }\n }\n\n // Toggle auto-hide controls\n toggleAutoHide() {\n this.autoHideEnabled = !this.autoHideEnabled;\n const autoHideBtn = document.getElementById('zoomoraAutoHideBtn');\n\n if (this.autoHideEnabled) {\n autoHideBtn.classList.add('active');\n autoHideBtn.title = 'Disable Auto-Hide Controls';\n this.startAutoHideTimer();\n } else {\n autoHideBtn.classList.remove('active');\n autoHideBtn.title = 'Enable Auto-Hide Controls';\n this.stopAutoHideTimer();\n this.showControls();\n }\n }\n\n // Handle user activity\n handleUserActivity() {\n if (!this.autoHideEnabled) return;\n\n this.showControls();\n this.startAutoHideTimer();\n }\n\n // Start auto-hide timer\n startAutoHideTimer() {\n this.stopAutoHideTimer();\n\n this.autoHideTimeout = setTimeout(() => {\n this.hideControls();\n }, this.options.autoHideDelay);\n }\n\n // Stop auto-hide timer\n stopAutoHideTimer() {\n if (this.autoHideTimeout) {\n clearTimeout(this.autoHideTimeout);\n this.autoHideTimeout = null;\n }\n }\n\n // Show controls\n showControls() {\n if (this.isControlsVisible) return;\n\n this.isControlsVisible = true;\n this.zoomora.classList.remove('controls-hidden');\n\n // Animate controls back in\n if (this.header) {\n this.header.style.transform = 'translateY(0)';\n this.header.style.opacity = '1';\n }\n\n if (this.caption) {\n this.caption.style.transform = 'translateX(-50%) translateY(0)';\n this.caption.style.opacity = '1';\n }\n\n if (this.thumbs) {\n this.thumbs.style.transform = 'translateX(-50%) translateY(0)';\n this.thumbs.style.opacity = '1';\n }\n\n if (this.prevBtn) {\n this.prevBtn.style.transform = 'translateX(0)';\n this.prevBtn.style.opacity = '1';\n }\n\n if (this.nextBtn) {\n this.nextBtn.style.transform = 'translateX(0)';\n this.nextBtn.style.opacity = '1';\n }\n }\n\n // Hide controls\n hideControls() {\n if (!this.isControlsVisible) return;\n\n this.isControlsVisible = false;\n this.zoomora.classList.add('controls-hidden');\n\n // Animate controls out\n if (this.header) {\n this.header.style.transform = 'translateY(-100%)';\n this.header.style.opacity = '0';\n }\n\n if (this.caption) {\n this.caption.style.transform = 'translateX(-50%) translateY(100%)';\n this.caption.style.opacity = '0';\n }\n\n if (this.thumbs) {\n this.thumbs.style.transform = 'translateX(-50%) translateY(100%)';\n this.thumbs.style.opacity = '0';\n }\n\n if (this.prevBtn) {\n this.prevBtn.style.transform = 'translateX(-100%)';\n this.prevBtn.style.opacity = '0';\n }\n\n if (this.nextBtn) {\n this.nextBtn.style.transform = 'translateX(100%)';\n this.nextBtn.style.opacity = '0';\n }\n }\n\n /**\n * Check if image can be zoomed\n * @param {HTMLImageElement} img - Image element\n */\n checkZoomability(img) {\n if (!img || !img.naturalWidth || !img.naturalHeight) return;\n\n const imgRect = img.getBoundingClientRect();\n const renderedWidth = imgRect.width;\n const renderedHeight = imgRect.height;\n const naturalWidth = img.naturalWidth;\n const naturalHeight = img.naturalHeight;\n\n const isScaledDown = naturalWidth > renderedWidth || naturalHeight > renderedHeight;\n const zoomRatioX = naturalWidth / renderedWidth;\n const zoomRatioY = naturalHeight / renderedHeight;\n const maxZoomRatio = Math.max(zoomRatioX, zoomRatioY);\n\n // Store zoom info\n img.dataset.zoomRatio = maxZoomRatio;\n img.dataset.naturalWidth = naturalWidth;\n img.dataset.naturalHeight = naturalHeight;\n img.dataset.renderedWidth = renderedWidth;\n img.dataset.renderedHeight = renderedHeight;\n\n // Enable zoom if significantly scaled down\n if (isScaledDown && maxZoomRatio > 1.1) {\n img.classList.remove('no-zoom');\n } else {\n img.classList.add('no-zoom');\n }\n }\n\n /**\n * Calculate zoom levels for an image\n * @param {HTMLImageElement} img - Image element\n * @returns {Object} Zoom configuration\n */\n /**\n * Calculate zoom levels for an image\n * @param {HTMLImageElement} img - Image element\n * @returns {Object} Zoom configuration\n */\n calculateZoomLevels(img) {\n if (!img || !img.naturalWidth || !img.naturalHeight) {\n return {canZoom: false, levels: [], currentLevel: 0};\n }\n\n // Get CONTAINER size (not current displayed image size)\n const container = this.content.getBoundingClientRect();\n const containerWidth = container.width;\n const containerHeight = container.height;\n\n const naturalWidth = img.naturalWidth;\n const naturalHeight = img.naturalHeight;\n\n // Calculate what the ORIGINAL fit-to-screen scale would be\n const scaleToFitWidth = containerWidth / naturalWidth;\n const scaleToFitHeight = containerHeight / naturalHeight;\n const fitScale = Math.min(scaleToFitWidth, scaleToFitHeight);\n\n // If image naturally fits or is smaller than container, can't zoom\n if (fitScale >= 0.95) {\n return {canZoom: false, levels: [], currentLevel: 0};\n }\n\n // Calculate zoom levels based on FIT scale (not current scale)\n const levels = [1]; // Start with fit-to-screen\n\n // Add progressive levels: 1.5x, 2x, 3x\n if (fitScale * 1.5 <= 1) levels.push(1.5);\n if (fitScale * 2 <= 1) levels.push(2);\n if (fitScale * 3 <= 1) levels.push(3);\n\n // Add actual size (100%) as final level\n const actualSizeScale = 1 / fitScale;\n if (actualSizeScale > levels[levels.length - 1]) {\n levels.push(actualSizeScale);\n }\n\n return {\n canZoom: levels.length > 1,\n levels: levels,\n currentLevel: 0,\n baseScale: fitScale,\n naturalWidth: naturalWidth,\n naturalHeight: naturalHeight\n };\n }\n\n /**\n * Update counter display\n */\n updateCounter() {\n if (this.options.showCounter && this.counter) {\n this.counter.textContent = `${this.currentIndex + 1} / ${this.items.length}`;\n }\n }\n\n /**\n * Update caption display\n */\n updateCaption() {\n if (!this.caption || !this.items[this.currentIndex]) return;\n\n const item = this.items[this.currentIndex];\n const caption = item.dataset.caption || item.title || '';\n\n if (caption) {\n this.caption.textContent = caption;\n this.caption.style.transform = 'translateX(-50%) translateY(0)';\n this.caption.style.opacity = '1';\n this.caption.style.pointerEvents = 'auto';\n this.caption.style.transition = 'opacity 0.3s ease, transform 0.3s ease';\n } else {\n this.caption.style.transform = 'translateX(-50%) translateY(100%)';\n this.caption.style.opacity = '0';\n this.caption.style.pointerEvents = 'none';\n this.caption.style.transition = 'opacity 0.3s ease, transform 0.3s ease';\n }\n }\n\n /**\n * Update thumbnails display\n */\n updateThumbnails() {\n if (!this.options.showThumbnails || !this.thumbs) return;\n\n if (this.items.length === 1) {\n this.caption.classList.add('single-item-thumbnail');\n this.thumbs.style.display = 'none';\n return;\n }\n\n this.caption.classList.remove('single-item-thumbnail');\n\n this.thumbs.style.display = 'flex';\n this.thumbs.innerHTML = '';\n\n this.items.forEach((item, index) => {\n const thumb = document.createElement('div');\n thumb.className = 'zoomora-thumb';\n if (index === this.currentIndex) thumb.classList.add('active');\n\n const img = document.createElement('img');\n const thumbSrc = this.getThumbnailSource(item);\n\n if (thumbSrc) {\n img.src = thumbSrc;\n img.alt = item.alt || item.title || '';\n img.onerror = () => {\n thumb.style.display = 'none';\n };\n }\n\n thumb.appendChild(img);\n\n thumb.addEventListener('click', () => {\n this.currentIndex = index;\n this.loadContent();\n this.updateCounter();\n this.updateThumbnails();\n this.updateNavigation();\n this.updateCaption();\n });\n\n this.thumbs.appendChild(thumb);\n });\n }\n\n /**\n * Update navigation buttons\n */\n updateNavigation() {\n const prevBtn = document.getElementById('zoomoraPrevBtn');\n const nextBtn = document.getElementById('zoomoraNextBtn');\n\n if (prevBtn) {\n prevBtn.style.display = this.currentIndex > 0 ? 'flex' : 'none';\n }\n if (nextBtn) {\n nextBtn.style.display = this.currentIndex < this.items.length - 1 ? 'flex' : 'none';\n }\n }\n\n /**\n * Update control buttons\n */\n updateButtons() {\n const fullscreenBtn = document.getElementById('zoomoraFullscreenBtn');\n const collapseBtn = document.getElementById('zoomoraCollapseBtn');\n\n if (fullscreenBtn && collapseBtn) {\n if (this.isFullscreen) {\n fullscreenBtn.style.display = 'none';\n collapseBtn.style.display = 'flex';\n } else {\n fullscreenBtn.style.display = 'flex';\n collapseBtn.style.display = 'none';\n }\n }\n }\n\n /**\n * Toggle zoom state\n */\n toggleZoom() {\n const media = this.content.querySelector('.zoomora-media');\n if (!media || media.tagName !== 'IMG') return;\n\n // Calculate zoom levels\n const zoomConfig = this.calculateZoomLevels(media);\n\n if (!zoomConfig.canZoom) {\n console.log('Image cannot be zoomed (already at full size or larger)');\n return;\n }\n\n // Get or initialize current zoom level\n if (!media.dataset.zoomLevel) {\n media.dataset.zoomLevel = '0';\n }\n\n let currentLevel = parseInt(media.dataset.zoomLevel) || 0;\n\n // Cycle to next level\n currentLevel++;\n if (currentLevel >= zoomConfig.levels.length) {\n // Reset to fit-to-screen\n currentLevel = 0;\n }\n\n const targetScale = zoomConfig.levels[currentLevel];\n media.dataset.zoomLevel = currentLevel.toString();\n\n if (currentLevel === 0) {\n // Back to fit-to-screen\n this.isZoomed = false;\n this.isDragging = false;\n media.classList.remove('dragging');\n media.style.transform = '';\n media.style.cursor = 'pointer';\n media.classList.remove('zoomed');\n this.currentX = 0;\n this.currentY = 0;\n this.currentScale = 1;\n } else {\n // Zoom in - reset position to center\n this.isZoomed = true;\n this.currentScale = targetScale;\n this.currentX = 0; // Always reset to center on zoom change\n this.currentY = 0;\n\n media.style.transform = `translate(0px, 0px) scale(${targetScale})`;\n media.style.cursor = 'grab';\n media.classList.add('zoomed');\n\n console.log(`Zoomed to level ${currentLevel}/${zoomConfig.levels.length - 1} (${(targetScale * 100).toFixed(0)}%)`);\n }\n }\n\n /**\n * Update image transform based on current state\n * @param {HTMLElement} media - Media element\n */\n updateImageTransform(media) {\n if (!media) return;\n\n if (this.currentScale === 1) {\n media.style.transform = '';\n } else {\n // IMPORTANT: translate in scaled space, so divide by scale\n const translateX = this.currentX / this.currentScale;\n const translateY = this.currentY / this.currentScale;\n media.style.transform = `scale(${this.currentScale}) translate(${translateX}px, ${translateY}px)`;\n }\n }\n\n /**\n * Toggle fullscreen mode\n */\n toggleFullscreen() {\n if (!this.isFullscreen) {\n this.enterFullscreen();\n } else {\n this.exitFullscreen();\n }\n }\n\n /**\n * Enter fullscreen mode\n */\n enterFullscreen() {\n const element = this.zoomora;\n const requestFullscreen = element.requestFullscreen ||\n element.webkitRequestFullscreen ||\n element.mozRequestFullScreen ||\n element.msRequestFullscreen;\n\n if (requestFullscreen) {\n requestFullscreen.call(element).then(() => {\n this.isFullscreen = true;\n this.zoomora.classList.add('fullscreen');\n this.updateButtons();\n }).catch(err => {\n console.warn('Zoomora: Could not enter fullscreen:', err);\n this.fallbackFullscreen();\n });\n } else {\n this.fallbackFullscreen();\n }\n }\n\n /**\n * Exit fullscreen mode\n */\n exitFullscreen() {\n const isInFullscreen = document.fullscreenElement ||\n document.webkitFullscreenElement ||\n document.mozFullScreenElement ||\n document.msFullscreenElement;\n\n if (isInFullscreen) {\n const exitFullscreen = document.exitFullscreen ||\n document.webkitExitFullscreen ||\n document.mozCancelFullScreen ||\n document.msExitFullscreen;\n\n if (exitFullscreen) {\n exitFullscreen.call(document).then(() => {\n this.isFullscreen = false;\n this.zoomora.classList.remove('fullscreen');\n this.updateButtons();\n }).catch(err => {\n console.warn('Zoomora: Could not exit fullscreen:', err);\n this.fallbackExitFullscreen();\n });\n } else {\n this.fallbackExitFullscreen();\n }\n } else {\n this.fallbackExitFullscreen();\n }\n }\n\n /**\n * Fallback fullscreen using CSS\n */\n fallbackFullscreen() {\n this.isFullscreen = true;\n this.zoomora.classList.add('fullscreen');\n this.updateButtons();\n }\n\n /**\n * Exit CSS fullscreen\n */\n fallbackExitFullscreen() {\n this.isFullscreen = false;\n this.zoomora.classList.remove('fullscreen');\n this.updateButtons();\n }\n\n /**\n * Toggle thumbnails visibility\n */\n toggleThumbnails() {\n if (this.items.length === 1) return;\n\n this.thumbnailsVisible = !this.thumbnailsVisible;\n if (this.thumbs) {\n this.thumbs.classList.toggle('thumbs-hidden', !this.thumbnailsVisible);\n\n if (!this.caption || !this.items[this.currentIndex]) return;\n\n const item = this.items[this.currentIndex];\n const caption = item.dataset.caption || item.title || '';\n\n if (caption && this.thumbs.classList.contains('thumbs-hidden')) {\n this.caption.style.bottom = '20px';\n this.caption.style.transition = 'bottom 0.3s ease, transform 0.3s ease';\n } else {\n this.caption.style.bottom = '120px';\n }\n }\n }\n\n /**\n * Start drag operation\n * @param {Event} e - Mouse or touch event\n */\n startDrag(e) {\n const media = this.content.querySelector('.zoomora-media');\n if (!media || !this.isZoomed) return;\n\n this.isDragging = true;\n media.classList.add('dragging');\n media.style.cursor = 'grabbing';\n\n this.startX = e.clientX || (e.touches && e.touches[0].clientX) || 0;\n this.startY = e.clientY || (e.touches && e.touches[0].clientY) || 0;\n\n // Read current position from transform\n const transform = window.getComputedStyle(media).transform;\n if (transform && transform !== 'none') {\n const matrix = new DOMMatrix(transform);\n this.currentX = matrix.m41;\n this.currentY = matrix.m42;\n } else {\n this.currentX = 0;\n this.currentY = 0;\n }\n\n e.preventDefault();\n }\n\n /**\n * Handle drag movement\n * @param {Event} e - Mouse or touch event\n */\n drag(e) {\n if (!this.isDragging) return;\n e.preventDefault();\n\n const media = this.content.querySelector('.zoomora-media');\n if (!media) return;\n\n const clientX = e.clientX || (e.touches && e.touches[0].clientX) || 0;\n const clientY = e.clientY || (e.touches && e.touches[0].clientY) || 0;\n\n const deltaX = clientX - this.startX;\n const deltaY = clientY - this.startY;\n\n let newX = this.currentX + deltaX;\n let newY = this.currentY + deltaY;\n\n // Calculate boundaries for BOTH width AND height\n const container = this.content.getBoundingClientRect();\n const mediaRect = media.getBoundingClientRect();\n\n // How much the scaled image overflows the container\n const overflowX = Math.max(0, (mediaRect.width - container.width) / 2);\n const overflowY = Math.max(0, (mediaRect.height - container.height) / 2);\n\n // Constrain drag to overflow boundaries\n if (overflowX > 0) {\n newX = Math.max(-overflowX, Math.min(overflowX, newX));\n } else {\n newX = 0; // Center horizontally if no overflow\n }\n\n if (overflowY > 0) {\n newY = Math.max(-overflowY, Math.min(overflowY, newY));\n } else {\n newY = 0; // Center vertically if no overflow\n }\n\n // Apply transform\n media.style.transform = `translate(${newX}px, ${newY}px) scale(${this.currentScale})`;\n\n // Update for next frame\n this.startX = clientX;\n this.startY = clientY;\n this.currentX = newX;\n this.currentY = newY;\n }\n\n /**\n * End drag operation\n */\n endDrag() {\n if (!this.isDragging) return;\n\n this.isDragging = false;\n this.lastDragTime = Date.now();\n\n const media = this.content.querySelector('.zoomora-media');\n if (media) {\n media.classList.remove('dragging');\n if (this.isZoomed) {\n media.style.cursor = 'grab';\n }\n }\n }\n\n /**\n * Go to specific item by index\n * @param {number} index - Item index\n */\n goTo(index) {\n if (index < 0 || index >= this.items.length) return;\n\n this.currentIndex = index;\n this.loadContent();\n this.updateCounter();\n this.updateThumbnails();\n this.updateNavigation();\n this.updateCaption();\n }\n\n /**\n * Get current item index\n * @returns {number} - Current index\n */\n getCurrentIndex() {\n return this.currentIndex;\n }\n\n /**\n * Get total number of items\n * @returns {number} - Total items\n */\n getTotalItems() {\n return this.items.length;\n }\n\n /**\n * Check if lightbox is open\n * @returns {boolean} - True if open\n */\n isOpen() {\n return this.zoomora && this.zoomora.classList.contains('active');\n }\n\n /**\n * Update options\n * @param {Object} newOptions - New options to merge\n */\n updateOptions(newOptions) {\n this.options = {...this.options, ...newOptions};\n }\n\n /**\n * Refresh the lightbox (re-scan for items)\n */\n refresh() {\n if (this.isOpen()) {\n const currentItem = this.items[this.currentIndex];\n if (currentItem) {\n this.open(currentItem);\n }\n }\n }\n\n /**\n * Destroy the lightbox instance\n */\n destroy() {\n if (!this.isInitialized) return;\n\n // Close if open\n if (this.isOpen()) {\n this.close();\n }\n\n // Clean up auto-hide\n this.stopAutoHideTimer();\n\n // Remove all event listeners\n this.eventListeners.forEach((listeners, key) => {\n listeners.forEach(({element, event, handler, options}) => {\n if (element && element.removeEventListener) {\n element.removeEventListener(event, handler, options);\n }\n });\n });\n this.eventListeners.clear();\n\n // Remove DOM elements\n if (this.zoomora && this.zoomora.parentNode) {\n this.zoomora.parentNode.removeChild(this.zoomora);\n }\n\n // Reset properties\n this.isInitialized = false;\n this.items = [];\n this.currentIndex = 0;\n this.zoomora = null;\n this.content = null;\n this.counter = null;\n this.thumbs = null;\n this.loading = null;\n this.caption = null;\n }\n }\n\n // Export the class\n return Zoomora;\n}));"],"names":["global","factory","window","this","Zoomora","defaults","selector","showCounter","showThumbnails","showFullscreen","showZoom","transition","useHref","maxZoomScale","zoomStep","animationDuration","onOpen","onClose","onNext","onPrev","showAutoHideToggle","autoHideDelay","autoHideEnabled","constructor","options","__spreadValues","currentIndex","items","isZoomed","isFullscreen","isDragging","thumbnailsVisible","startX","startY","currentX","currentY","currentScale","isInitialized","eventListeners","Map","autoHideTimeout","isControlsVisible","idleTimer","lastDragTime","boundMethods","handleDocumentClick","bind","handleKeydown","handleFullscreenChange","handleZoomoraClick","handleContentClick","handleMouseDown","handleMouseMove","handleMouseUp","handleTouchStart","handleTouchMove","handleTouchEnd","init","createLightbox","bindEvents","error","enhancedOptions","document","getElementById","zoomoraHTML","body","insertAdjacentHTML","zoomora","header","content","slidesContainer","counter","thumbs","loading","caption","prevBtn","nextBtn","Error","addEventListener","close","prev","next","toggleZoom","toggleFullscreen","exitFullscreen","toggleThumbnails","passive","toggleAutoHide","handleUserActivity","element","event","handler","key","name","has","set","get","push","e","target","closest","preventDefault","open","classList","contains","fullscreenElement","webkitFullscreenElement","mozFullScreenElement","msFullscreenElement","remove","updateButtons","Date","now","media","startDrag","drag","endDrag","getImageSource","item","src","dataset","getAttribute","type","convertToEmbedUrl","url","includes","videoId","startTime","urlParams","URLSearchParams","split","t","replace","parts","videoAndParams","length","embedUrl","params","append","toString","getThumbnailSource","getGroup","lightbox","gallery","group","groupSelector","Array","from","querySelectorAll","Math","max","indexOf","add","style","overflow","loadContent","updateThumbnails","updateCounter","updateNavigation","updateCaption","startAutoHideTimer","showControls","querySelector","transform","cursor","stopAutoHideTimer","display","innerHTML","setTimeout","renderContent","slideContainer","createElement","className","slide","mediaElement","opacity","endsWith","videoContainer","setAttribute","posterSrc","playButton","play","appendChild","alt","title","onload","checkZoomability","animateSlideIn","onerror","offsetHeight","autoHideBtn","hideControls","clearTimeout","img","naturalWidth","naturalHeight","imgRect","getBoundingClientRect","renderedWidth","width","renderedHeight","height","isScaledDown","zoomRatioX","zoomRatioY","maxZoomRatio","zoomRatio","calculateZoomLevels","canZoom","levels","currentLevel","container","containerWidth","containerHeight","scaleToFitWidth","scaleToFitHeight","fitScale","min","actualSizeScale","baseScale","textContent","pointerEvents","forEach","index","thumb","thumbSrc","fullscreenBtn","collapseBtn","tagName","zoomConfig","zoomLevel","parseInt","targetScale","updateImageTransform","translateX","translateY","enterFullscreen","requestFullscreen","webkitRequestFullscreen","mozRequestFullScreen","msRequestFullscreen","call","then","catch","err","fallbackFullscreen","webkitExitFullscreen","mozCancelFullScreen","msExitFullscreen","fallbackExitFullscreen","toggle","bottom","clientX","touches","clientY","getComputedStyle","matrix","DOMMatrix","m41","m42","deltaX","deltaY","newX","newY","mediaRect","overflowX","overflowY","goTo","getCurrentIndex","getTotalItems","isOpen","updateOptions","newOptions","refresh","currentItem","destroy","listeners","removeEventListener","clear","parentNode","removeChild","module","exports","define","amd"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zoomora",
3
- "version": "1.0.0",
3
+ "version": "1.1.0",
4
4
  "description": "A modern, responsive lightbox plugin with zoom, fullscreen, and gallery features",
5
5
  "type": "module",
6
6
  "main": "dist/zoomora.umd.js",
@@ -172,10 +172,17 @@ i[class^="zoomorai-"] {
172
172
  max-width: 100%;
173
173
  max-height: 100%;
174
174
  object-fit: contain;
175
- transition: transform 0.3s ease;
176
175
  cursor: pointer;
177
176
  }
178
177
 
178
+ .zoomora-media:not(.dragging) {
179
+ transition: transform 0.3s ease;
180
+ }
181
+
182
+ .zoomora-media.dragging {
183
+ transition: none;
184
+ }
185
+
179
186
  .zoomora-media.zoomed {
180
187
  cursor: grab;
181
188
  }