1// Gallery.js 2function initGallery() { 3 const galleries = document.querySelectorAll('[data-js="gallery"]') 4 5 for (const gallery of galleries) { 6 const dialog = gallery.querySelector('#lightbox') 7 const lightboxImage = gallery.querySelector('#lightboxImage') 8 const lightboxClose = gallery.querySelector('#lightboxClose') 9 10 // Solo configura el lightbox si existen todos los elementos necesarios 11 if (dialog && lightboxImage && lightboxClose) { 12 for (const button of gallery.querySelectorAll( 13 '[data-js="gallery__image-button"]', 14 )) { 15 const img = button.querySelector('img') 16 17 const openModal = () => { 18 lightboxImage.src = img.src 19 dialog.showModal() 20 } 21 22 button.addEventListener('click', openModal) 23 24 button.addEventListener('keydown', (e) => { 25 if (e.key === 'Enter' || e.key === ' ') { 26 e.preventDefault() 27 openModal() 28 } 29 }) 30 } 31 32 lightboxClose.addEventListener('click', () => { 33 dialog.close() 34 lightboxImage.src = '' 35 }) 36 37 dialog.addEventListener('click', (e) => { 38 const lightboxFigure = dialog.querySelector('.lightbox-figure') 39 if (!lightboxFigure.contains(e.target)) { 40 dialog.close() 41 lightboxImage.src = '' 42 } 43 }) 44 } 45 46 const carousel = gallery.querySelector('[data-js="gallery__carousel"]') 47 48 if (!carousel) { 49 return 50 } 51 52 const prevButton = gallery.querySelector('#prev') 53 const nextButton = gallery.querySelector('#next') 54 const controls = 55 gallery.querySelector('.section-title__controls') || 56 gallery.querySelector('.article-gallery__controls') 57 const shouldShowControls = carousel.scrollWidth > carousel.clientWidth 58 if (shouldShowControls && controls) { 59 controls.style.display = 'grid' 60 } 61 62 function updateButtonState() { 63 const slides = carousel.querySelectorAll( 64 '[data-js="gallery__carousel-slide"]', 65 ) 66 if (!slides.length) return 67 68 const firstSlide = slides[0] 69 const lastSlide = slides[slides.length - 1] 70 71 const carouselRect = carousel.getBoundingClientRect() 72 const firstRect = firstSlide.getBoundingClientRect() 73 const lastRect = lastSlide.getBoundingClientRect() 74 75 const isAtStart = firstRect.left >= carouselRect.left - 8 76 const isAtEnd = lastRect.right <= carouselRect.right + 8 77 78 prevButton.disabled = isAtStart 79 nextButton.disabled = isAtEnd 80 } 81 82 updateButtonState() 83 window.addEventListener('resize', () => { 84 const shouldShowControls = carousel.scrollWidth > carousel.clientWidth 85 const dynamicControls = 86 gallery.querySelector('.section-title__controls') || 87 gallery.querySelector('.article-gallery__controls') 88 if (dynamicControls) { 89 dynamicControls.style.display = shouldShowControls ? 'grid' : 'none' 90 } 91 updateButtonState() 92 }) 93 94 function scrollToSlide(direction) { 95 const slides = carousel.querySelectorAll( 96 '[data-js="gallery__carousel-slide"]', 97 ) 98 if (!slides.length) return 99 100 let currentIndex = 0 101 let minDelta = Number.POSITIVE_INFINITY 102 for (let i = 0; i < slides.length; i++) { 103 const slide = slides[i] 104 const delta = Math.abs(slide.offsetLeft - carousel.scrollLeft) 105 if (delta < minDelta) { 106 minDelta = delta 107 currentIndex = i 108 } 109 } 110 111 let targetIndex = currentIndex + direction 112 if (targetIndex < 0) targetIndex = 0 113 if (targetIndex >= slides.length) targetIndex = slides.length - 1 114 const targetSlide = slides[targetIndex] 115 if (!targetSlide) return 116 let targetScrollLeft = targetSlide.offsetLeft 117 118 const isMobile = window.innerWidth <= 992 119 if (targetIndex === 0 && isMobile) { 120 targetScrollLeft = 0 121 } 122 123 carousel.scrollTo({ left: targetScrollLeft, behavior: 'smooth' }) 124 125 function waitForScroll() { 126 if (Math.abs(carousel.scrollLeft - targetSlide.offsetLeft) < 2) { 127 updateButtonState() 128 return 129 } 130 requestAnimationFrame(waitForScroll) 131 } 132 requestAnimationFrame(waitForScroll) 133 } 134 135 prevButton.addEventListener('click', () => { 136 scrollToSlide(-1) 137 }) 138 prevButton.addEventListener('keydown', (e) => { 139 if (e.key === 'Enter' || e.key === ' ') { 140 e.preventDefault() 141 scrollToSlide(-1) 142 } 143 }) 144 145 nextButton.addEventListener('click', () => { 146 scrollToSlide(1) 147 }) 148 nextButton.addEventListener('keydown', (e) => { 149 if (e.key === 'Enter' || e.key === ' ') { 150 e.preventDefault() 151 scrollToSlide(1) 152 } 153 }) 154 155 carousel.addEventListener('scroll', updateButtonState) 156 } 157} 158 159initGallery()
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.