| 1 |
/* Masonry Grid — frontend */ |
| 2 |
( function () { |
| 3 |
function normalizeColumns() { |
| 4 |
document.querySelectorAll('.bkmg-wrap').forEach(function (wrap) { |
| 5 |
var grid = wrap.querySelector('.bkmg-grid'); |
| 6 |
if (!grid) return; |
| 7 |
|
| 8 |
// React inline styles for `columns` can serialize numbers as px (e.g. "3px"), |
| 9 |
// which makes the layout effectively invisible. Use unitless columnCount instead. |
| 10 |
var cols = wrap.style.getPropertyValue('--bkmg-cols'); |
| 11 |
var gap = wrap.style.getPropertyValue('--bkmg-gap'); |
| 12 |
var colCount = parseInt(cols, 10); |
| 13 |
if (!isNaN(colCount) && colCount > 0) { |
| 14 |
grid.style.columnCount = String(colCount); |
| 15 |
grid.style.removeProperty('columns'); |
| 16 |
grid.style.columnWidth = 'auto'; |
| 17 |
grid.style.removeProperty('column-width'); |
| 18 |
} |
| 19 |
if (gap && String(gap).trim()) { |
| 20 |
grid.style.columnGap = String(gap).trim(); |
| 21 |
} |
| 22 |
}); |
| 23 |
} |
| 24 |
|
| 25 |
function initLightbox() { |
| 26 |
normalizeColumns(); |
| 27 |
document.querySelectorAll('.bkmg-wrap[data-lightbox="1"]').forEach(function(wrap) { |
| 28 |
if (wrap._bkmgInit) return; |
| 29 |
wrap._bkmgInit = true; |
| 30 |
|
| 31 |
var lb = null; |
| 32 |
|
| 33 |
function openLightbox(src, alt) { |
| 34 |
if (lb) return; |
| 35 |
lb = document.createElement('div'); |
| 36 |
lb.className = 'bkmg-lightbox'; |
| 37 |
lb.setAttribute('role','dialog'); |
| 38 |
lb.setAttribute('aria-modal','true'); |
| 39 |
lb.setAttribute('aria-label',alt||'Image'); |
| 40 |
|
| 41 |
var img = document.createElement('img'); |
| 42 |
img.src = src; |
| 43 |
img.alt = alt||''; |
| 44 |
|
| 45 |
var closeBtn = document.createElement('button'); |
| 46 |
closeBtn.className = 'bkmg-lightbox-close'; |
| 47 |
closeBtn.innerHTML = '×'; |
| 48 |
closeBtn.setAttribute('aria-label','Close lightbox'); |
| 49 |
|
| 50 |
lb.appendChild(img); |
| 51 |
lb.appendChild(closeBtn); |
| 52 |
document.body.appendChild(lb); |
| 53 |
document.body.style.overflow = 'hidden'; |
| 54 |
|
| 55 |
function close() { |
| 56 |
if (lb) { document.body.removeChild(lb); lb=null; } |
| 57 |
document.body.style.overflow = ''; |
| 58 |
document.removeEventListener('keydown', escHandler); |
| 59 |
} |
| 60 |
function escHandler(e) { if (e.key==='Escape') close(); } |
| 61 |
|
| 62 |
closeBtn.addEventListener('click', close); |
| 63 |
lb.addEventListener('click', function(e){ if (e.target===lb) close(); }); |
| 64 |
document.addEventListener('keydown', escHandler); |
| 65 |
} |
| 66 |
|
| 67 |
wrap.querySelectorAll('.bkmg-item img, .bkmg-link img').forEach(function(img) { |
| 68 |
img.parentElement.style.cursor = 'zoom-in'; |
| 69 |
img.parentElement.addEventListener('click', function(e) { |
| 70 |
e.preventDefault(); |
| 71 |
openLightbox(img.src, img.alt); |
| 72 |
}); |
| 73 |
}); |
| 74 |
}); |
| 75 |
} |
| 76 |
|
| 77 |
if (document.readyState === 'loading') { |
| 78 |
document.addEventListener('DOMContentLoaded', function () { |
| 79 |
normalizeColumns(); |
| 80 |
initLightbox(); |
| 81 |
}); |
| 82 |
} else { |
| 83 |
normalizeColumns(); |
| 84 |
initLightbox(); |
| 85 |
} |
| 86 |
}() ); |
| 87 |
|