1/** 2 * OP Custom Fields - Simple Lightbox 3 * 4 * Lightweight vanilla JavaScript lightbox for image galleries. 5 * Shows title and caption below the image. 6 * 7 * @package OP_Custom_Fields 8 * @version 1.0.71 9 */ 10(function() { 11 'use strict'; 12 13 // Lightbox state. 14 let currentGallery = []; 15 let currentIndex = 0; 16 let lightboxElement = null; 17 18 /** 19 * Initialize lightbox when DOM is ready. 20 */ 21 function init() { 22 // Create lightbox HTML structure. 23 createLightbox(); 24 25 // Bind click events to all lightbox links. 26 document.addEventListener('click', handleClick); 27 28 // Keyboard navigation. 29 document.addEventListener('keydown', handleKeydown); 30 } 31 32 /** 33 * Create lightbox DOM structure. 34 */ 35 function createLightbox() { 36 const html = ` 37 <div class="op-lightbox" role="dialog" aria-modal="true" aria-label="Bildansicht"> 38 <div class="op-lightbox-overlay"></div> 39 <div class="op-lightbox-container"> 40 <button class="op-lightbox-close" aria-label="SchlieÃen">×</button> 41 <button class="op-lightbox-prev" aria-label="Vorheriges Bild">❮</button> 42 <button class="op-lightbox-next" aria-label="Nächstes Bild">❯</button> 43 <div class="op-lightbox-content"> 44 <img class="op-lightbox-image" src="" alt=""> 45 <div class="op-lightbox-info"> 46 <h3 class="op-lightbox-title"></h3> 47 <p class="op-lightbox-caption"></p> 48 </div> 49 </div> 50 <div class="op-lightbox-counter"></div> 51 </div> 52 </div> 53 `; 54 55 // Insert lightbox into body. 56 document.body.insertAdjacentHTML('beforeend', html); 57 lightboxElement = document.querySelector('.op-lightbox'); 58 59 // Bind lightbox events. 60 lightboxElement.querySelector('.op-lightbox-overlay').addEventListener('click', close); 61 lightboxElement.querySelector('.op-lightbox-close').addEventListener('click', close); 62 lightboxElement.querySelector('.op-lightbox-prev').addEventListener('click', showPrev); 63 lightboxElement.querySelector('.op-lightbox-next').addEventListener('click', showNext); 64 } 65 66 /** 67 * Handle click on lightbox links. 68 * 69 * @param {Event} e Click event. 70 */ 71 function handleClick(e) { 72 const link = e.target.closest('a[data-lightbox]'); 73 if (!link) return; 74 75 e.preventDefault(); 76 77 // Get gallery group name. 78 const groupName = link.getAttribute('data-lightbox'); 79 80 // Find all images in this gallery group. 81 currentGallery = Array.from(document.querySelectorAll(`a[data-lightbox="${groupName}"]`)); 82 currentIndex = currentGallery.indexOf(link); 83 84 open(); 85 } 86 87 /** 88 * Handle keyboard navigation. 89 * 90 * @param {KeyboardEvent} e Keyboard event. 91 */ 92 function handleKeydown(e) { 93 if (!lightboxElement.classList.contains('is-open')) return; 94 95 switch (e.key) { 96 case 'Escape': 97 close(); 98 break; 99 case 'ArrowLeft': 100 showPrev(); 101 break; 102 case 'ArrowRight': 103 showNext(); 104 break; 105 } 106 } 107 108 /** 109 * Open lightbox and show current image. 110 */ 111 function open() { 112 lightboxElement.classList.add('is-open'); 113 document.body.style.overflow = 'hidden'; 114 updateImage(); 115 updateNavigation(); 116 } 117 118 /** 119 * Close lightbox. 120 */ 121 function close() { 122 lightboxElement.classList.remove('is-open'); 123 document.body.style.overflow = ''; 124 } 125 126 /** 127 * Show previous image. 128 */ 129 function showPrev() { 130 if (currentIndex > 0) { 131 currentIndex--; 132 updateImage(); 133 updateNavigation(); 134 } 135 } 136 137 /** 138 * Show next image. 139 */ 140 function showNext() { 141 if (currentIndex < currentGallery.length - 1) { 142 currentIndex++; 143 updateImage(); 144 updateNavigation(); 145 } 146 } 147 148 /** 149 * Update displayed image and info. 150 */ 151 function updateImage() { 152 const link = currentGallery[currentIndex]; 153 const img = lightboxElement.querySelector('.op-lightbox-image'); 154 const titleEl = lightboxElement.querySelector('.op-lightbox-title'); 155 const captionEl = lightboxElement.querySelector('.op-lightbox-caption'); 156 const counterEl = lightboxElement.querySelector('.op-lightbox-counter'); 157 158 // Get image data. 159 const src = link.getAttribute('href'); 160 const title = link.getAttribute('data-title') || ''; 161 const caption = link.getAttribute('data-caption') || ''; 162 const alt = link.querySelector('img')?.getAttribute('alt') || title; 163 164 // Update image. 165 img.src = src; 166 img.alt = alt; 167 168 // Update title and caption. 169 titleEl.textContent = title; 170 titleEl.style.display = title ? 'block' : 'none'; 171 172 captionEl.textContent = caption; 173 captionEl.style.display = caption ? 'block' : 'none'; 174 175 // Hide info section if both empty. 176 const infoEl = lightboxElement.querySelector('.op-lightbox-info'); 177 infoEl.style.display = (title || caption) ? 'block' : 'none'; 178 179 // Update counter. 180 if (currentGallery.length > 1) { 181 counterEl.textContent = `${currentIndex + 1} / ${currentGallery.length}`; 182 counterEl.style.display = 'block'; 183 } else {
184 counterEl.style.display = 'none'; 185 } 186 } 187 188 /** 189 * Update navigation button visibility. 190 */ 191 function updateNavigation() { 192 const prevBtn = lightboxElement.querySelector('.op-lightbox-prev'); 193 const nextBtn = lightboxElement.querySelector('.op-lightbox-next'); 194 195 // Show/hide navigation based on position. 196 prevBtn.style.display = currentIndex > 0 ? 'block' : 'none'; 197 nextBtn.style.display = currentIndex < currentGallery.length - 1 ? 'block' : 'none'; 198 } 199 200 // Initialize on DOM ready. 201 if (document.readyState === 'loading') { 202 document.addEventListener('DOMContentLoaded', init); 203 } else { 204 init(); 205 } 206})();
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.