| 1 |
(function () { |
| 2 |
'use strict'; |
| 3 |
|
| 4 |
/* ── Lightbox ──────────────────────────────────────────────────────────── */ |
| 5 |
var lb = null; |
| 6 |
var lbImages = []; |
| 7 |
var lbIndex = 0; |
| 8 |
|
| 9 |
function createLightbox() { |
| 10 |
if (lb) return lb; |
| 11 |
|
| 12 |
var overlay = document.createElement('div'); |
| 13 |
overlay.className = 'bkbg-ig-lightbox'; |
| 14 |
overlay.setAttribute('role', 'dialog'); |
| 15 |
overlay.setAttribute('aria-modal', 'true'); |
| 16 |
overlay.setAttribute('aria-label', 'Image lightbox'); |
| 17 |
|
| 18 |
var inner = document.createElement('div'); |
| 19 |
inner.className = 'bkbg-ig-lb-inner'; |
| 20 |
|
| 21 |
var img = document.createElement('img'); |
| 22 |
img.className = 'bkbg-ig-lb-img'; |
| 23 |
img.alt = ''; |
| 24 |
|
| 25 |
var caption = document.createElement('div'); |
| 26 |
caption.className = 'bkbg-ig-lb-caption'; |
| 27 |
|
| 28 |
var closeBtn = document.createElement('button'); |
| 29 |
closeBtn.className = 'bkbg-ig-lb-close'; |
| 30 |
closeBtn.setAttribute('aria-label', 'Close lightbox'); |
| 31 |
closeBtn.innerHTML = '×'; |
| 32 |
closeBtn.addEventListener('click', closeLightbox); |
| 33 |
|
| 34 |
var prevBtn = document.createElement('button'); |
| 35 |
prevBtn.className = 'bkbg-ig-lb-prev'; |
| 36 |
prevBtn.setAttribute('aria-label', 'Previous image'); |
| 37 |
prevBtn.innerHTML = '‹'; |
| 38 |
prevBtn.addEventListener('click', function () { navigate(-1); }); |
| 39 |
|
| 40 |
var nextBtn = document.createElement('button'); |
| 41 |
nextBtn.className = 'bkbg-ig-lb-next'; |
| 42 |
nextBtn.setAttribute('aria-label', 'Next image'); |
| 43 |
nextBtn.innerHTML = '›'; |
| 44 |
nextBtn.addEventListener('click', function () { navigate(1); }); |
| 45 |
|
| 46 |
var counter = document.createElement('div'); |
| 47 |
counter.className = 'bkbg-ig-lb-counter'; |
| 48 |
|
| 49 |
inner.appendChild(img); |
| 50 |
inner.appendChild(caption); |
| 51 |
overlay.appendChild(inner); |
| 52 |
overlay.appendChild(closeBtn); |
| 53 |
overlay.appendChild(prevBtn); |
| 54 |
overlay.appendChild(nextBtn); |
| 55 |
overlay.appendChild(counter); |
| 56 |
document.body.appendChild(overlay); |
| 57 |
|
| 58 |
overlay.addEventListener('click', function (e) { |
| 59 |
if (e.target === overlay) closeLightbox(); |
| 60 |
}); |
| 61 |
|
| 62 |
document.addEventListener('keydown', function (e) { |
| 63 |
if (!overlay.classList.contains('is-open')) return; |
| 64 |
if (e.key === 'Escape') closeLightbox(); |
| 65 |
if (e.key === 'ArrowLeft') navigate(-1); |
| 66 |
if (e.key === 'ArrowRight') navigate(1); |
| 67 |
}); |
| 68 |
|
| 69 |
lb = { overlay: overlay, img: img, caption: caption, counter: counter, prevBtn: prevBtn, nextBtn: nextBtn }; |
| 70 |
return lb; |
| 71 |
} |
| 72 |
|
| 73 |
function openLightbox(images, index) { |
| 74 |
lbImages = images; |
| 75 |
lbIndex = index; |
| 76 |
var l = createLightbox(); |
| 77 |
showImage(l); |
| 78 |
l.overlay.classList.add('is-open'); |
| 79 |
document.body.style.overflow = 'hidden'; |
| 80 |
l.overlay.querySelector('.bkbg-ig-lb-close').focus(); |
| 81 |
} |
| 82 |
|
| 83 |
function closeLightbox() { |
| 84 |
if (!lb) return; |
| 85 |
lb.overlay.classList.remove('is-open'); |
| 86 |
document.body.style.overflow = ''; |
| 87 |
} |
| 88 |
|
| 89 |
function navigate(dir) { |
| 90 |
lbIndex = (lbIndex + dir + lbImages.length) % lbImages.length; |
| 91 |
showImage(lb); |
| 92 |
} |
| 93 |
|
| 94 |
function showImage(l) { |
| 95 |
var entry = lbImages[lbIndex]; |
| 96 |
l.img.style.opacity = '0'; |
| 97 |
l.img.onload = function () { l.img.style.opacity = '1'; }; |
| 98 |
l.img.src = entry.url; |
| 99 |
l.img.alt = entry.alt || ''; |
| 100 |
l.caption.textContent = entry.caption || ''; |
| 101 |
l.counter.textContent = (lbIndex + 1) + ' / ' + lbImages.length; |
| 102 |
l.prevBtn.style.display = lbImages.length < 2 ? 'none' : ''; |
| 103 |
l.nextBtn.style.display = lbImages.length < 2 ? 'none' : ''; |
| 104 |
} |
| 105 |
|
| 106 |
/* ── Init one gallery ──────────────────────────────────────────────────── */ |
| 107 |
function initGallery(wrapper) { |
| 108 |
var grid = wrapper.querySelector('.bkbg-ig-grid'); |
| 109 |
if (!grid) return; |
| 110 |
|
| 111 |
var useLightbox = grid.dataset.lightbox === '1'; |
| 112 |
var items = Array.from(wrapper.querySelectorAll('.bkbg-ig-item')); |
| 113 |
|
| 114 |
/* Build image list for lightbox */ |
| 115 |
var imageList = items.map(function (item) { |
| 116 |
var link = item.querySelector('.bkbg-ig-link'); |
| 117 |
var img = item.querySelector('.bkbg-ig-img'); |
| 118 |
var cap = item.querySelector('.bkbg-ig-caption'); |
| 119 |
return { |
| 120 |
url : link ? link.href : (img ? img.src : ''), |
| 121 |
alt : img ? (img.alt || '') : '', |
| 122 |
caption: cap ? cap.textContent : '' |
| 123 |
}; |
| 124 |
}); |
| 125 |
|
| 126 |
/* Attach lightbox click handlers */ |
| 127 |
if (useLightbox) { |
| 128 |
items.forEach(function (item, idx) { |
| 129 |
var link = item.querySelector('.bkbg-ig-lb-trigger'); |
| 130 |
if (!link) return; |
| 131 |
link.addEventListener('click', function (e) { |
| 132 |
e.preventDefault(); |
| 133 |
openLightbox(imageList, idx); |
| 134 |
}); |
| 135 |
}); |
| 136 |
} |
| 137 |
|
| 138 |
/* Filter bar */ |
| 139 |
var filterBtns = Array.from(wrapper.querySelectorAll('.bkbg-ig-filter-btn')); |
| 140 |
if (filterBtns.length === 0) return; |
| 141 |
|
| 142 |
filterBtns.forEach(function (btn) { |
| 143 |
btn.addEventListener('click', function () { |
| 144 |
var filter = btn.dataset.filter; |
| 145 |
filterBtns.forEach(function (b) { b.classList.remove('is-active'); }); |
| 146 |
btn.classList.add('is-active'); |
| 147 |
|
| 148 |
items.forEach(function (item) { |
| 149 |
if (filter === 'all' || item.dataset.category === filter) { |
| 150 |
item.classList.remove('is-hidden'); |
| 151 |
} else { |
| 152 |
item.classList.add('is-hidden'); |
| 153 |
} |
| 154 |
}); |
| 155 |
}); |
| 156 |
}); |
| 157 |
} |
| 158 |
|
| 159 |
/* ── Init all ────────────────────────────────────────────────────────── */ |
| 160 |
function initAll() { |
| 161 |
var galleries = document.querySelectorAll('.bkbg-ig-wrapper'); |
| 162 |
galleries.forEach(initGallery); |
| 163 |
} |
| 164 |
|
| 165 |
if (document.readyState === 'loading') { |
| 166 |
document.addEventListener('DOMContentLoaded', initAll); |
| 167 |
} else { |
| 168 |
initAll(); |
| 169 |
} |
| 170 |
})(); |
| 171 |
|