import { getImageUrl } from "./firebaseImages.js"; let modal = null; let modalImage = null; let teller = null; let vorigeKnop = null; let volgendeKnop = null; let groep = []; // alle thumbnails van het album waarin je klikte let index = 0; // welke foto nu getoond wordt let isOpen = false; // Eigen stijl, omdat jouw style.css van elke .btn 100% breed maakt. const PIJL_STIJL = ` position:absolute; top:50%; transform:translateY(-50%); z-index:5; width:44px; height:44px; border:0; border-radius:50%; background:rgba(0,0,0,.55); color:#fff; font-size:2rem; line-height:1; padding:0 0 4px 0; display:flex; align-items:center; justify-content:center; cursor:pointer; `; // De modal wordt pas gemaakt bij de eerste klik. Pagina's hoeven er dus geen HTML voor te hebben. function ensureModal() { if (modal) return; const element = document.createElement("div"); element.className = "modal fade"; element.tabIndex = -1; element.setAttribute("aria-hidden", "true"); element.innerHTML = ` `; document.body.appendChild(element); modalImage = element.querySelector("img"); teller = element.querySelector(".badge"); vorigeKnop = element.querySelector(".lightbox-vorige"); volgendeKnop = element.querySelector(".lightbox-volgende"); modal = new bootstrap.Modal(element); vorigeKnop.addEventListener("click", () => toon(index - 1)); volgendeKnop.addEventListener("click", () => toon(index + 1)); element.addEventListener("shown.bs.modal", () => { isOpen = true; }); element.addEventListener("hidden.bs.modal", () => { isOpen = false; modalImage.removeAttribute("src"); // volgende keer niet even de vorige foto tonen }); // Pijltjestoetsen op het toetsenbord document.addEventListener("keydown", event => { if (!isOpen) return; if (event.key === "ArrowLeft") toon(index - 1); if (event.key === "ArrowRight") toon(index + 1); }); // Vegen op gsm const body = element.querySelector(".modal-body"); let startX = null; body.addEventListener("touchstart", event => { startX = event.changedTouches[0].clientX; }, { passive: true }); body.addEventListener("touchend", event => { if (startX === null) return; const verschil = event.changedTouches[0].clientX - startX; startX = null; if (Math.abs(verschil) > 50) { toon(index + (verschil < 0 ? 1 : -1)); } }); } /* * Toont één foto in twee stappen: * 1. de thumbnail meteen, uitvergroot. Is die op de pagina nog niet geladen * (bv. omdat je er nog niet naartoe gescrold bent), dan halen we hem zelf op; * 2. de grote versie op de achtergrond laden en ertussen wisselen zodra ze klaar is. */ function toonFoto(thumbnail) { const { album, foto } = thumbnail.dataset; const url = getImageUrl(album, foto, false); const thumbUrl = getImageUrl(album, foto, true); // Onthoud welke foto nu gevraagd is, zodat een trage oudere foto nooit een nieuwere overschrijft. modalImage.dataset.requested = url; modalImage.alt = thumbnail.alt; modalImage.classList.remove("firebase-image-error"); const isHuidig = () => modalImage.dataset.requested === url; let groteGetoond = false; let thumbGetoond = false; // Het formaat volgt uit de foto zelf, zodat thumbnail en grote foto dezelfde plek innemen. const zetMaat = bron => { const verhouding = bron.naturalWidth / bron.naturalHeight; modalImage.style.aspectRatio = `${bron.naturalWidth} / ${bron.naturalHeight}`; modalImage.style.width = `min(100%, ${(90 * verhouding).toFixed(2)}vh)`; }; const toonThumb = bron => { if (!isHuidig() || groteGetoond || !bron.naturalWidth) return; thumbGetoond = true; zetMaat(bron); modalImage.src = thumbUrl; }; const groot = new Image(); groot.onload = () => { if (!isHuidig()) return; groteGetoond = true; zetMaat(groot); modalImage.src = url; }; groot.onerror = () => { console.error(`Afbeelding kon niet geladen worden: ${url}`); // Is er geen thumbnail om op terug te vallen, dan tonen we de foutstijl. if (isHuidig() && !thumbGetoond) { modalImage.classList.add("firebase-image-error"); modalImage.alt = "Afbeelding kon niet geladen worden"; } }; groot.src = url; // Al in de cache (bv. een vooraf opgehaalde buurfoto): meteen de grote tonen. if (groot.complete && groot.naturalWidth > 0) { groot.onload(); return; } if (thumbnail.complete && thumbnail.naturalWidth > 0) { toonThumb(thumbnail); // thumbnail staat al op de pagina } else { const kleine = new Image(); // thumbnail nog niet geladen: zelf ophalen kleine.onload = () => toonThumb(kleine); kleine.src = thumbUrl; } } // Toont foto nummer i van de groep. Na de laatste foto begin je weer bij de eerste. function toon(nieuweIndex) { index = (nieuweIndex + groep.length) % groep.length; toonFoto(groep[index]); teller.textContent = `${index + 1} / ${groep.length}`; const metPijlen = groep.length > 1; vorigeKnop.style.display = metPijlen ? "flex" : "none"; volgendeKnop.style.display = metPijlen ? "flex" : "none"; teller.style.display = metPijlen ? "" : "none"; // De volgende en vorige foto alvast ophalen, zodat bladeren snel gaat. if (metPijlen) { [index + 1, index - 1].forEach(i => { const buur = groep[(i + groep.length) % groep.length]; new Image().src = getImageUrl(buur.dataset.album, buur.dataset.foto, false); }); } } // Alle thumbnails van hetzelfde album, in de volgorde van de pagina. function verzamelGroep(thumbnail) { return Array.from(document.querySelectorAll("img[data-album][data-foto]")) .filter(img => img.dataset.album === thumbnail.dataset.album && !img.classList.contains("firebase-image-error") ); } /** * Zet de lightbox aan voor de hele pagina. * * Werkt met event delegation: elke opent bij een * klik de normale versie, ook als die pas later aan de pagina wordt toegevoegd. */ export function initLightbox() { document.addEventListener("click", event => { const thumbnail = event.target.closest("img[data-album][data-foto]"); if (!thumbnail || thumbnail.classList.contains("firebase-image-error")) { return; } ensureModal(); groep = verzamelGroep(thumbnail); modalImage.removeAttribute("src"); modal.show(); toon(groep.indexOf(thumbnail)); }); }