1(function () { 2 'use strict'; 3 4 var grid = document.getElementById('galleryGrid'); 5 var loading = document.getElementById('galleryLoading'); 6 var empty = document.getElementById('galleryEmpty'); 7 var error = document.getElementById('galleryError'); 8 9 var lightbox = document.getElementById('screenshot-lightbox'); 10 var lightboxImg = lightbox && lightbox.querySelector('.lightbox-image'); 11 var lightboxCounter = lightbox && lightbox.querySelector('.lightbox-counter'); 12 var lightboxClose = lightbox && lightbox.querySelector('.lightbox-close'); 13 var lightboxPrev = lightbox && lightbox.querySelector('.lightbox-prev'); 14 var lightboxNext = lightbox && lightbox.querySelector('.lightbox-next'); 15 16 var screenshots = []; 17 var lightboxIndex = 0; 18 19 function setHidden(el, hidden) { 20 if (!el) return; 21 if (hidden) el.setAttribute('hidden', ''); 22 else el.removeAttribute('hidden'); 23 } 24 25 function visibleScreenshots() { 26 return screenshots; 27 } 28 29 function renderGrid() { 30 var items = visibleScreenshots(); 31 grid.innerHTML = ''; 32 setHidden(empty, items.length > 0); 33 34 items.forEach(function (s, index) { 35 var card = document.createElement('article'); 36 card.className = 'gallery-card'; 37 38 var thumb = document.createElement('button'); 39 thumb.type = 'button'; 40 thumb.className = 'gallery-thumb'; 41 thumb.setAttribute('aria-label', 'Open ' + s.title + ' at full size'); 42 43 var img = document.createElement('img'); 44 img.src = s.file; 45 img.alt = s.alt || s.title; 46 img.loading = 'lazy'; 47 thumb.appendChild(img); 48 49 thumb.addEventListener('click', function () { 50 openLightbox(index); 51 }); 52 53 var body = document.createElement('div'); 54 body.className = 'gallery-body'; 55 56 var h3 = document.createElement('h3'); 57 h3.className = 'gallery-title'; 58 h3.textContent = s.title; 59 body.appendChild(h3); 60 61 var desc = document.createElement('p'); 62 desc.className = 'gallery-desc'; 63 desc.textContent = s.description; 64 body.appendChild(desc); 65 66 if (Array.isArray(s.tags) && s.tags.length) { 67 var tagList = document.createElement('ul'); 68 tagList.className = 'gallery-tags';
69 s.tags.forEach(function (t) { 70 var li = document.createElement('li'); 71 li.className = 'gallery-tag'; 72 li.setAttribute('data-tag', t); 73 li.textContent = t; 74 tagList.appendChild(li); 75 }); 76 body.appendChild(tagList); 77 } 78 79 if (s.helpAnchor) { 80 var link = document.createElement('a'); 81 link.className = 'gallery-link'; 82 link.href = 'help#' + s.helpAnchor; 83 link.innerHTML = (s.helpLabel || 'Read more') + 84 ' <span class="icon icon-ui-arrow-right" aria-hidden="true"></span>'; 85 body.appendChild(link); 86 } 87 88 card.appendChild(thumb); 89 card.appendChild(body); 90 grid.appendChild(card); 91 }); 92 } 93 94 function openLightbox(index) { 95 if (!lightbox || !lightboxImg) return; 96 var items = visibleScreenshots(); 97 if (!items.length) return; 98 lightboxIndex = ((index % items.length) + items.length) % items.length; 99 var s = items[lightboxIndex]; 100 lightboxImg.src = s.file; 101 lightboxImg.alt = s.alt || s.title; 102 lightboxCounter.textContent = (lightboxIndex + 1) + ' / ' + items.length; 103 lightbox.classList.add('active'); 104 document.body.style.overflow = 'hidden'; 105 } 106 107 function closeLightbox() { 108 lightbox.classList.remove('active'); 109 document.body.style.overflow = ''; 110 lightboxImg.src = ''; 111 } 112 113 function step(delta) { 114 var items = visibleScreenshots(); 115 if (!items.length) return; 116 openLightbox(lightboxIndex + delta); 117 } 118 119 if (lightbox && lightboxImg) { 120 lightboxClose.addEventListener('click', closeLightbox); 121 lightboxPrev.addEventListener('click', function () { step(-1); }); 122 lightboxNext.addEventListener('click', function () { step(1); }); 123 lightbox.addEventListener('click', function (e) { 124 if (e.target === lightbox) closeLightbox(); 125 }); 126 document.addEventListener('keydown', function (e) { 127 if (!lightbox.classList.contains('active')) return; 128 if (e.key === 'Escape') closeLightbox(); 129 else if (e.key === 'ArrowLeft') step(-1); 130 else if (e.key === 'ArrowRight') step(1); 131 }); 132 } 133 134 function init() { 135 var inline = document.getElementById('gallery-data'); 136 if (!inline) { 137 setHidden(loading, true); 138 setHidden(error, false); 139 return; 140 } 141 try { 142 var data = JSON.parse(inline.textContent); 143 screenshots = (data && data.screenshots) || []; 144 setHidden(loading, true); 145 renderGrid(); 146 } catch (e) { 147 setHidden(loading, true); 148 setHidden(error, false); 149 } 150 } 151 152 if (document.readyState === 'loading') { 153 document.addEventListener('DOMContentLoaded', init); 154 } else { 155 init(); 156 } 157})();
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.