PageSourceSearch

https://fallas.com/wp-content/plugins/historicos-jcf/assets/js/frontend.js?ver=1.0.0

js fallas.com collected 2026-10-02 08:10:22 UTC 8,727 bytes, 221 lines download raw bytes

1/**
2 * Frontend Lightbox JavaScript with Gallery Navigation for Historicos JCF
3 */
4document.addEventListener('DOMContentLoaded', function() {
5    let currentGalleryItems = [];
6    let currentIndex = -1;
7
8    // Create lightbox HTML structure with navigation arrows and optional sidebar
9    const overlay = document.createElement('div');
10    overlay.className = 'jcf-lightbox-overlay';
11    overlay.innerHTML = `
12        <div class="jcf-lightbox-content">
13            <button class="jcf-lightbox-close" aria-label="Cerrar">&times;</button>
14            <button class="jcf-lightbox-prev" aria-label="Anterior">&#10094;</button>
15            <button class="jcf-lightbox-next" aria-label="Siguiente">&#10095;</button>
16            <div class="jcf-lightbox-main">
17                <img src="" alt="" />
18                <div class="jcf-lightbox-caption"></div>
19            </div>
20            <div class="jcf-lightbox-sidebar" style="display: none;">
21                <h3 class="jcf-lightbox-sidebar-title">Corte de Honor</h3>
22                <ul class="jcf-lightbox-sidebar-list"></ul>
23            </div>
24        </div>
25    `;
26    document.body.appendChild(overlay);
27
28    const lightboxContent = overlay.querySelector('.jcf-lightbox-content');
29    const lightboxImg = overlay.querySelector('.jcf-lightbox-main img');
30    const lightboxCaption = overlay.querySelector('.jcf-lightbox-caption');
31    const lightboxSidebar = overlay.querySelector('.jcf-lightbox-sidebar');
32    const lightboxSidebarTitle = overlay.querySelector('.jcf-lightbox-sidebar-title');
33    const lightboxSidebarList = overlay.querySelector('.jcf-lightbox-sidebar-list');
34    const closeBtn = overlay.querySelector('.jcf-lightbox-close');
35    const prevBtn = overlay.querySelector('.jcf-lightbox-prev');
36    const nextBtn = overlay.querySelector('.jcf-lightbox-next');
37
38    /**
39     * Update the content of the lightbox based on target index.
40     */
41    function updateLightbox(index) {
42        if (index < 0 || index >= currentGalleryItems.length) return;
43        currentIndex = index;
44
45        const item = currentGalleryItems[currentIndex];
46        const imgUrl = item.getAttribute('href');
47        const title = item.getAttribute('title');
48        
49        const type   = item.dataset.type || 'fmv';
50        const year   = item.dataset.year || '';
51        const artist = item.dataset.artist || '';
52        const lema   = item.dataset.lema || '';
53        const cortesanas = item.dataset.cortesanas || '';
54
55        // Set image and caption
56        lightboxImg.src = imgUrl;
57        lightboxImg.alt = title;
58
59        let captionHTML = '';
60        if (type === 'falla_mun' || type === 'falla_mun_inf') {
61            captionHTML = `<strong>${title}</strong> (${year})`;
62            if (artist) {
63                captionHTML += `<br/><span class="jcf-lightbox-artist-sub" style="font-size: 0.9em; opacity: 0.85; font-style: italic; display: block; margin-top: 4px;">Artista: ${artist}</span>`;
64            }
65        } else if (type === 'ninot' || type === 'ninot_inf') {
66            captionHTML = `<strong>${title}</strong> (${year})`;
67            let extra = '';
68            if (artist) {
69                extra += `Artista: ${artist}`;
70            }
71            if (lema) {
72                if (extra) extra += ' - ';
73                extra += `Lema: "${lema}"`;
74            }
75            if (extra) {
76                captionHTML += `<br/><span class="jcf-lightbox-artist-sub" style="font-size: 0.9em; opacity: 0.85; font-style: italic; display: block; margin-top: 4px;">${extra}</span>`;
77            }
78        } else if (type === 'cartel') {
79            captionHTML = `<strong>${title}</strong>`;
80        } else if (type === 'corte_no_photos') {
81            captionHTML = `<strong>Cort d´Honor de la Fallera Mayor de Valencia de ${year}</strong>`;
82        } else if (type === 'corte_inf_no_photos') {
83            captionHTML = `<strong>Cort d´Honor de la Fallera Mayor Infantil de Valencia de ${year}</strong>`;
84        } else {
85            captionHTML = `<strong>${title}</strong>${year ? ' (' + year + ')' : ''}`;
86        }
87        lightboxCaption.innerHTML = captionHTML;
88
89        // Side panel logic for Cortes without photos
90        if (type === 'corte_no_photos' || type === 'corte_inf_no_photos') {
91            lightboxContent.classList.add('has-sidebar');
92            lightboxSidebar.style.display = 'flex';
93            
94            const isInfantil = (type === 'corte_inf_no_photos');
95            lightboxSidebarTitle.textContent = isInfantil ? 'Cort d´Honor Infantil ' + year : 'Cort d´Honor ' + year;
96            
97            lightboxSidebarList.innerHTML = '';
98            if (cortesanas) {
99                const names = cortesanas.split('|');
100                names.forEach(name => {
101                    if (name.trim() !== '') {
102                        const li = document.createElement('li');
103                        li.className = 'jcf-lightbox-sidebar-item';
104                        li.textContent = name;
105                        lightboxSidebarList.appendChild(li);
106                    }
107                });
108            }
109        } else {
110            lightboxContent.classList.remove('has-sidebar');
111            lightboxSidebar.style.display = 'none';
112            lightboxSidebarList.innerHTML = '';
113        }
114
115        // Toggle navigation buttons visibility if there's only 1 item
116        if (currentGalleryItems.length <= 1) {
117            prevBtn.style.display = 'none';
118            nextBtn.style.display = 'none';
119        } else {
120            prevBtn.style.display = '';
121            nextBtn.style.display = '';
122        }
123    }
124
125    // Handle click on grid items to open the lightbox
126    document.addEventListener('click', function(e) {
127        const link = e.target.closest('.jcf-grid-lightbox');
128        if (link) {
129            e.preventDefault();
130            
131            // Gather all items inside the same grid container to enable navigation
132            const container = link.closest('.jcf-grid-container');
133            if (container) {
134                currentGalleryItems = Array.from(container.querySelectorAll('.jcf-grid-lightbox'));
135            } else {
136                currentGalleryItems = [link];
137            }
138            
139            // Find current index
140            currentIndex = currentGalleryItems.indexOf(link);
141
142            // Update content and open
143            updateLightbox(currentIndex);
144            overlay.classList.add('active');
145            document.body.classList.add('jcf-lightbox-open');
146        }
147    });
148
149    /**
150     * Close the lightbox modal.
151     */
152    function closeLightbox() {
153        overlay.classList.remove('active');
154        document.body.classList.remove('jcf-lightbox-open');
155        // Clear source after transition finishes to avoid a flash of previous image
156        setTimeout(function() {
157            lightboxImg.src = '';
158            lightboxImg.alt = '';
159            lightboxContent.classList.remove('has-sidebar');
160            lightboxSidebar.style.display = 'none';
161            lightboxSidebarList.innerHTML = '';
162            currentGalleryItems = [];
163            currentIndex = -1;
164        }, 300);
165    }
166
167    /**
168     * Navigate to next image.
169     */
170    function showNext() {
171        if (currentGalleryItems.length <= 1) return;
172        let nextIndex = currentIndex + 1;
173        if (nextIndex >= currentGalleryItems.length) {
174            nextIndex = 0; // Loop back to the first item
175        }
176        updateLightbox(nextIndex);
177    }
178
179    /**
180     * Navigate to previous image.
181     */
182    function showPrev() {
183        if (currentGalleryItems.length <= 1) return;
184        let prevIndex = currentIndex - 1;
185        if (prevIndex < 0) {
186            prevIndex = currentGalleryItems.length - 1; // Loop to the last item
187        }
188        updateLightbox(prevIndex);
189    }
190
191    // Close and Navigation Event Listeners
192    closeBtn.addEventListener('click', closeLightbox);
193    prevBtn.addEventListener('click', function(e) {
194        e.stopPropagation();
195        showPrev();
196    });
197    nextBtn.addEventListener('click', function(e) {
198        e.stopPropagation();
199        showNext();
200    });
201    
202    overlay.addEventListener('click', function(e) {
203        // Close if click is on the overlay backdrop itself
204        if (e.target === overlay) {
205            closeLightbox();
206        }
207    });
208
209    // Keyboard navigation (Escape, Left Arrow, Right Arrow)
210    document.addEventListener('keydown', function(e) {
211        if (!overlay.classList.contains('active')) return;
212
213        if (e.key === 'Escape') {
214            closeLightbox();
215        } else if (e.key === 'ArrowRight') {
216            showNext();
217        } else if (e.key === 'ArrowLeft') {
218            showPrev();
219        }
220    });
221});

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.