104 lines
3.0 KiB
JavaScript
104 lines
3.0 KiB
JavaScript
const IMAGE_DIR = 'images/';
|
|
const MANIFEST = IMAGE_DIR + 'manifest.json';
|
|
|
|
function parseIndexHtmlList(text) {
|
|
// crude parser to extract hrefs from an autoindex HTML listing
|
|
const hrefs = [];
|
|
const re = /href="([^"]+)"/g;
|
|
let m;
|
|
while ((m = re.exec(text)) !== null) {
|
|
const name = m[1];
|
|
if (name.match(/\.(jpe?g|png|webp|gif)$/i)) hrefs.push(name);
|
|
}
|
|
return hrefs;
|
|
}
|
|
|
|
async function loadImageList() {
|
|
// Try manifest first
|
|
try {
|
|
const r = await fetch(MANIFEST, {cache: 'no-cache'});
|
|
if (r.ok) return await r.json();
|
|
} catch (e) {
|
|
// continue to directory probe
|
|
}
|
|
|
|
try {
|
|
const r = await fetch(IMAGE_DIR, {cache: 'no-cache'});
|
|
if (r.ok) {
|
|
const text = await r.text();
|
|
return parseIndexHtmlList(text);
|
|
}
|
|
} catch (e) {
|
|
console.warn('Could not read image directory listing', e);
|
|
}
|
|
return [];
|
|
}
|
|
|
|
function createThumb(src, idx) {
|
|
const img = document.createElement('img');
|
|
img.src = src;
|
|
img.loading = 'lazy';
|
|
img.dataset.index = idx;
|
|
img.alt = `Photo ${idx+1}`;
|
|
img.addEventListener('click', () => openModal(idx));
|
|
return img;
|
|
}
|
|
|
|
let images = [];
|
|
let currentIndex = 0;
|
|
|
|
function openModal(idx) {
|
|
currentIndex = idx;
|
|
const modal = document.getElementById('gallery-modal');
|
|
const mimg = document.getElementById('modal-image');
|
|
mimg.src = IMAGE_DIR + images[idx];
|
|
modal.classList.remove('hidden');
|
|
modal.setAttribute('aria-hidden', 'false');
|
|
}
|
|
|
|
function closeModal() {
|
|
const modal = document.getElementById('gallery-modal');
|
|
modal.classList.add('hidden');
|
|
modal.setAttribute('aria-hidden', 'true');
|
|
document.getElementById('modal-image').src = '';
|
|
}
|
|
|
|
function showNext(delta=1) {
|
|
if (!images.length) return;
|
|
currentIndex = (currentIndex + delta + images.length) % images.length;
|
|
document.getElementById('modal-image').src = IMAGE_DIR + images[currentIndex];
|
|
}
|
|
|
|
function setupModalControls() {
|
|
document.getElementById('modal-close').addEventListener('click', closeModal);
|
|
document.getElementById('modal-prev').addEventListener('click', () => showNext(-1));
|
|
document.getElementById('modal-next').addEventListener('click', () => showNext(1));
|
|
document.addEventListener('keydown', (e) => {
|
|
if (document.getElementById('gallery-modal').classList.contains('hidden')) return;
|
|
if (e.key === 'Escape') closeModal();
|
|
if (e.key === 'ArrowRight') showNext(1);
|
|
if (e.key === 'ArrowLeft') showNext(-1);
|
|
});
|
|
document.getElementById('gallery-modal').addEventListener('click', (e)=>{
|
|
if (e.target.id === 'gallery-modal') closeModal();
|
|
});
|
|
}
|
|
|
|
async function initGallery() {
|
|
const list = await loadImageList();
|
|
images = list;
|
|
const container = document.getElementById('gallery-thumbs');
|
|
container.innerHTML = '';
|
|
if (!images.length) {
|
|
container.textContent = 'No images found. Create images/manifest.json or enable directory listing.';
|
|
return;
|
|
}
|
|
images.forEach((name, idx) => {
|
|
const thumb = createThumb(IMAGE_DIR + name, idx);
|
|
container.appendChild(thumb);
|
|
});
|
|
setupModalControls();
|
|
}
|
|
|
|
document.addEventListener('DOMContentLoaded', initGallery);
|