// /app/static/js/modal-pagination.js document.addEventListener('DOMContentLoaded', () => { const modal = document.getElementById('imageModal'); const modalPrev = document.getElementById('modalPrev'); const modalNext = document.getElementById('modalNext'); const modalClose = document.getElementById('modalClose'); const modalImageWrapper = document.querySelector('.modal-image-wrapper'); let images = Array.from(document.querySelectorAll('.img-clickable')); let currentIndex = -1; let isZoomed = false; let isDragging = false; let startX, startY, scrollLeft, scrollTop; let dragStartX = 0; let dragStartY = 0; let dragMoved = false; const hasNextPageInput = document.getElementById('hasNextPage'); const nextPageUrlInput = document.getElementById('nextPageUrl'); const hasPrevPageInput = document.getElementById('hasPrevPage'); const prevPageUrlInput = document.getElementById('prevPageUrl'); function updateImage(index) { const img = images[index]; const fileType = img.dataset.type || "image"; modalImageWrapper.innerHTML = ""; if (fileType === "video") { const video = document.createElement("video"); video.src = img.dataset.full; video.controls = true; video.autoplay = true; video.style.maxWidth = "100%"; video.style.maxHeight = "100%"; modalImageWrapper.appendChild(video); } else { const image = document.createElement("img"); image.src = img.dataset.full; image.alt = "Full View"; image.setAttribute("draggable", "false"); image.id = "modalImage"; modalImageWrapper.appendChild(image); } currentIndex = index; resetZoom(); } function openModal(index) { modal.classList.add('active'); updateImage(index); history.replaceState({ modalIndex: index }, '', window.location.href); } function closeModal() { modal.classList.remove('active'); modalImageWrapper.innerHTML = ''; currentIndex = -1; resetZoom(); history.replaceState({}, '', window.location.pathname + window.location.search); } function showNext() { if (currentIndex < images.length - 1) { updateImage(currentIndex + 1); } else if (hasNextPageInput?.value === "true") { fetch(nextPageUrlInput.value) .then(res => res.text()) .then(html => { const parser = new DOMParser(); const doc = parser.parseFromString(html, 'text/html'); const newGallery = doc.querySelector('.gallery-grid'); const newImages = doc.querySelectorAll('.img-clickable'); if (newGallery && newImages.length > 0) { const gallery = document.querySelector('.gallery-grid'); gallery.innerHTML = newGallery.innerHTML; images = Array.from(document.querySelectorAll('.img-clickable')); images.forEach((img, i) => { img.addEventListener('click', () => openModal(i)); }); hasNextPageInput.value = doc.getElementById('hasNextPage')?.value || "false"; nextPageUrlInput.value = doc.getElementById('nextPageUrl')?.value || ""; hasPrevPageInput.value = doc.getElementById('hasPrevPage')?.value || "false"; prevPageUrlInput.value = doc.getElementById('prevPageUrl')?.value || ""; history.pushState({}, '', nextPageUrlInput.value); openModal(0); } }); } } function showPrev() { if (currentIndex > 0) { updateImage(currentIndex - 1); } else if (hasPrevPageInput?.value === "true") { fetch(prevPageUrlInput.value) .then(res => res.text()) .then(html => { const parser = new DOMParser(); const doc = parser.parseFromString(html, 'text/html'); const newGallery = doc.querySelector('.gallery-grid'); const newImages = doc.querySelectorAll('.img-clickable'); if (newGallery && newImages.length > 0) { const gallery = document.querySelector('.gallery-grid'); gallery.innerHTML = newGallery.innerHTML; images = Array.from(document.querySelectorAll('.img-clickable')); images.forEach((img, i) => { img.addEventListener('click', () => openModal(i)); }); hasNextPageInput.value = doc.getElementById('hasNextPage')?.value || "false"; nextPageUrlInput.value = doc.getElementById('nextPageUrl')?.value || ""; hasPrevPageInput.value = doc.getElementById('hasPrevPage')?.value || "false"; prevPageUrlInput.value = doc.getElementById('prevPageUrl')?.value || ""; history.pushState({}, '', prevPageUrlInput.value); openModal(images.length - 1); } }); } } function toggleZoom() { const isImage = modalImageWrapper.querySelector('img') !== null; if (!isImage) return; isZoomed = !isZoomed; modalImageWrapper.classList.toggle('zoomed', isZoomed); modalImageWrapper.style.cursor = isZoomed ? 'grab' : ''; if (!isZoomed) { modalImageWrapper.scrollLeft = 0; modalImageWrapper.scrollTop = 0; } } function resetZoom() { isZoomed = false; modalImageWrapper.classList.remove('zoomed'); modalImageWrapper.scrollLeft = 0; modalImageWrapper.scrollTop = 0; modalImageWrapper.style.cursor = ''; } modalImageWrapper.addEventListener('mousedown', (e) => { const isImage = modalImageWrapper.querySelector('img') !== null; if (!isZoomed || !isImage) return; isDragging = true; dragMoved = false; modalImageWrapper.style.cursor = 'grabbing'; startX = e.pageX - modalImageWrapper.offsetLeft; startY = e.pageY - modalImageWrapper.offsetTop; scrollLeft = modalImageWrapper.scrollLeft; scrollTop = modalImageWrapper.scrollTop; dragStartX = e.pageX; dragStartY = e.pageY; }); modalImageWrapper.addEventListener('mouseleave', () => { isDragging = false; const isImage = modalImageWrapper.querySelector('img') !== null; if (isZoomed && isImage) modalImageWrapper.style.cursor = 'grab'; }); modalImageWrapper.addEventListener('mouseup', () => { isDragging = false; const isImage = modalImageWrapper.querySelector('img') !== null; if (isZoomed && isImage) modalImageWrapper.style.cursor = 'grab'; }); modalImageWrapper.addEventListener('mousemove', (e) => { const isImage = modalImageWrapper.querySelector('img') !== null; if (!isDragging || !isZoomed || !isImage) return; e.preventDefault(); dragMoved = true; const x = e.pageX - modalImageWrapper.offsetLeft; const y = e.pageY - modalImageWrapper.offsetTop; const walkX = x - startX; const walkY = y - startY; modalImageWrapper.scrollLeft = scrollLeft - walkX; modalImageWrapper.scrollTop = scrollTop - walkY; }); modalImageWrapper.addEventListener('click', (e) => { if (dragMoved) { dragMoved = false; return; } toggleZoom(); }); modalClose?.addEventListener('click', closeModal); modalPrev?.addEventListener('click', showPrev); modalNext?.addEventListener('click', showNext); modal.addEventListener('click', (e) => { if (e.target === modal) closeModal(); }); document.addEventListener('keydown', (e) => { if (!modal.classList.contains('active')) return; if (e.key === 'ArrowRight') showNext(); if (e.key === 'ArrowLeft') showPrev(); if (e.key === 'Escape') closeModal(); }); images.forEach((img, index) => { img.addEventListener('click', () => openModal(index)); }); window.addEventListener('popstate', () => { if (modal.classList.contains('active')) { closeModal(); } else { location.reload(); } }); });