(function () { window.initAlbum = function () { var old = document.getElementById('lightbox') if (old) old.remove() var grid = document.getElementById('album-grid') if (!grid) return var items = Array.from(grid.children) if (!items.length) return var lastFocus = null var lb = document.createElement('div') lb.id = 'lightbox' lb.setAttribute('role', 'dialog') lb.setAttribute('aria-modal', 'true') lb.innerHTML = '' + '' + '' + '' document.body.appendChild(lb) var lbImg = lb.querySelector('img') var current = -1 function open(idx) { lastFocus = document.activeElement current = idx var img = items[current].querySelector('img') lbImg.removeAttribute('src') lbImg.alt = '' lb.classList.add('open') lbImg.src = img.dataset.fullsrc lbImg.alt = img.alt lb.querySelector('#lb-close').focus() } function close() { lb.classList.remove('open') current = -1 if (lastFocus) lastFocus.focus() } function prev() { if (current < 0) return open((current - 1 + items.length) % items.length) } function next() { if (current < 0) return open((current + 1) % items.length) } function trapFocus(e) { if (!lb.classList.contains('open')) return var focusable = lb.querySelectorAll('button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])') if (!focusable.length) return var first = focusable[0] var last = focusable[focusable.length - 1] if (e.key === 'Tab') { if (e.shiftKey) { if (document.activeElement === first) { e.preventDefault() last.focus() } } else { if (document.activeElement === last) { e.preventDefault() first.focus() } } } } items.forEach(function (item, i) { item.addEventListener('click', function () { open(i) }) item.addEventListener('keydown', function (e) { if (e.key === 'Enter' || e.key === ' ') { e.preventDefault() open(i) } }) }) lb.querySelector('#lb-close').addEventListener('click', close) lb.querySelector('#lb-prev').addEventListener('click', function (e) { e.stopPropagation() prev() }) lb.querySelector('#lb-next').addEventListener('click', function (e) { e.stopPropagation() next() }) document.addEventListener('keydown', function (e) { trapFocus(e) if (!lb.classList.contains('open')) return if (e.key === 'Escape') { close(); e.preventDefault() } if (e.key === 'ArrowLeft') { prev(); e.preventDefault() } if (e.key === 'ArrowRight') { next(); e.preventDefault() } }) lb.addEventListener('click', function (e) { if (e.target === lb) close() }) var touchStartX = 0 var touchStartY = 0 lb.addEventListener('touchstart', function (e) { touchStartX = e.changedTouches[0].screenX touchStartY = e.changedTouches[0].screenY }, { passive: true }) lb.addEventListener('touchend', function (e) { var dx = e.changedTouches[0].screenX - touchStartX var dy = e.changedTouches[0].screenY - touchStartY if (Math.abs(dx) > Math.abs(dy) && Math.abs(dx) > 50) { if (dx < 0) next() else prev() } }, { passive: true }) } window.initAlbum() document.addEventListener('htmx:afterSwap', window.initAlbum) })()