improved Modal with zoom and pagination. also implementing thumbnail generation
This commit is contained in:
@@ -0,0 +1,209 @@
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
const modal = document.getElementById('imageModal');
|
||||
const modalImage = document.getElementById('modalImage');
|
||||
const modalPrev = document.getElementById('modalPrev');
|
||||
const modalNext = document.getElementById('modalNext');
|
||||
const modalClose = document.getElementById('modalClose');
|
||||
const modalImageWrapper = document.querySelector('.modal-image-wrapper');
|
||||
|
||||
modalImage.setAttribute('draggable', 'false');
|
||||
|
||||
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];
|
||||
modalImage.src = img.dataset.full;
|
||||
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');
|
||||
modalImage.src = '';
|
||||
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));
|
||||
});
|
||||
|
||||
const newHasNext = doc.getElementById('hasNextPage')?.value || "false";
|
||||
const newNextUrl = doc.getElementById('nextPageUrl')?.value || "";
|
||||
const newHasPrev = doc.getElementById('hasPrevPage')?.value || "false";
|
||||
const newPrevUrl = doc.getElementById('prevPageUrl')?.value || "";
|
||||
|
||||
hasNextPageInput.value = newHasNext;
|
||||
nextPageUrlInput.value = newNextUrl;
|
||||
hasPrevPageInput.value = newHasPrev;
|
||||
prevPageUrlInput.value = newPrevUrl;
|
||||
|
||||
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));
|
||||
});
|
||||
|
||||
const newHasNext = doc.getElementById('hasNextPage')?.value || "false";
|
||||
const newNextUrl = doc.getElementById('nextPageUrl')?.value || "";
|
||||
const newHasPrev = doc.getElementById('hasPrevPage')?.value || "false";
|
||||
const newPrevUrl = doc.getElementById('prevPageUrl')?.value || "";
|
||||
|
||||
hasNextPageInput.value = newHasNext;
|
||||
nextPageUrlInput.value = newNextUrl;
|
||||
hasPrevPageInput.value = newHasPrev;
|
||||
prevPageUrlInput.value = newPrevUrl;
|
||||
|
||||
history.pushState({}, '', prevPageUrlInput.value);
|
||||
openModal(images.length - 1);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function toggleZoom() {
|
||||
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) => {
|
||||
if (!isZoomed) 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;
|
||||
if (isZoomed) modalImageWrapper.style.cursor = 'grab';
|
||||
});
|
||||
|
||||
modalImageWrapper.addEventListener('mouseup', () => {
|
||||
isDragging = false;
|
||||
if (isZoomed) modalImageWrapper.style.cursor = 'grab';
|
||||
});
|
||||
|
||||
modalImageWrapper.addEventListener('mousemove', (e) => {
|
||||
if (!isDragging || !isZoomed) 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();
|
||||
}
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user