PageSourceSearch

https://diocesisarmenia.org/scripts.js

js diocesisarmenia.org collected 2026-10-03 02:56:33 UTC 13,608 bytes, 316 lines download raw bytes

1// scripts.js
2document.addEventListener("DOMContentLoaded", function() {
3
4    // --- SECCIÓN 1: Carga de Componentes (Header/Footer) ---
5
6    /**
7     * Carga un componente HTML (como el header o footer) desde una URL 
8     * y lo inserta en un elemento contenedor en la página principal.
9     */
10    const loadComponent = (url, placeholderId) => {
11        fetch(url)
12            .then(response => {
13                if (!response.ok) {
14                    throw new Error(`Error al cargar el componente: ${response.statusText}`);
15                }
16                return response.text();
17            })
18            .then(data => {
19                const placeholder = document.getElementById(placeholderId);
20                if (placeholder) {
21                    placeholder.innerHTML = data;
22                }
23                
24                // Configurar interactividad post-carga
25                if (placeholderId === 'header-placeholder') {
26                    setupHeader();
27                }
28                if (placeholderId === 'footer-placeholder') {
29                    setupFooter();
30                }
31            })
32            .catch(error => console.error(`Error al cargar ${url}:`, error));
33    };
34
35    function setupHeader() {
36        const mobileMenuButton = document.getElementById('mobile-menu-button');
37        const mobileMenu = document.getElementById('mobile-menu');
38        if (mobileMenuButton && mobileMenu) {
39            mobileMenuButton.addEventListener('click', () => {
40                mobileMenu.classList.toggle('hidden');
41            });
42        }
43
44        const currentPage = window.location.pathname.split("/").pop() || "index.html";
45        const navLinksDesktop = document.querySelectorAll('header .hidden.lg\\:flex nav a');
46        const navLinksMobile = document.querySelectorAll('#mobile-menu a');
47
48        const highlightLink = (links) => {
49            links.forEach(link => {
50                const linkPage = (link.getAttribute('href') || "").split("/").pop();
51                if (linkPage === currentPage) {
52                    link.classList.add('text-teal-600', 'font-bold');
53                    if (link.closest('#mobile-menu')) {
54                        link.classList.add('bg-teal-50');
55                    }
56                }
57            });
58        };
59        
60        highlightLink(navLinksDesktop);
61        highlightLink(navLinksMobile);
62    }
63
64    function setupFooter() {
65       const yearEl = document.getElementById('year');
66       if (yearEl) {
67        yearEl.textContent = new Date().getFullYear();
68       }
69    }
70
71    // Iniciar carga de componentes
72    // Siempre usar rutas absolutas desde la raíz
73    const basePath = '/';
74
75    loadComponent(basePath + 'header.html', 'header-placeholder');
76    loadComponent(basePath + 'footer.html', 'footer-placeholder');
77
78
79    // --- SECCIÓN 2: Lógica de Noticias (JSON) ---
80
81    /**
82     * Carga noticias desde un archivo JSON.
83     * Si estamos en noticias.html, maneja filtros y carga dinámica (paginación).
84     * Si estamos en index.html, carga el carrusel.
85     */
86    function loadNews() {
87        const newsSectionIndex = document.getElementById('noticias-carrusel');
88        const newsGridPage = document.getElementById('news-grid');
89        
90        // Si no estamos en la página de noticias ni en la home, no hacemos nada
91        if (!newsSectionIndex && !newsGridPage) return;
92
93        fetch(basePath + 'noticias.json')
94            .then(response => {
95                if (!response.ok) throw new Error('No se pudo cargar noticias.json');
96                return response.json();
97            })
98            .then(noticias => {
99                if (noticias.length === 0) return;
100
101                // Lógica para la Home (Carrusel)
102                if (newsSectionIndex) {
103                    renderHomeCarousel(noticias, newsSectionIndex);
104                }
105
106                // Lógica para la Página de Noticias (Grid + Filtros)
107                if (newsGridPage) {
108                    renderNewsPage(noticias, newsGridPage);
109                }
110            })
111            .catch(error => console.error('Error cargando noticias:', error));
112    }
113
114    /**
115     * Renderiza el carrusel en la página principal
116     */
117    function renderHomeCarousel(noticias, section) {
118        const slider = document.getElementById('news-slider');
119        if (!slider) return;
120
121        section.classList.remove('hidden');
122        
123        // Mostrar las 5 más recientes
124        noticias.slice(0, 5).forEach(noticia => {
125            const slide = document.createElement('div');
126            slide.className = 'news-slide flex-shrink-0 w-full flex flex-col md:flex-row';
127            slide.innerHTML = `
128                <div class="md:w-1/2 h-64 md:h-[450px] overflow-hidden">
129                    <img src="${noticia.imagen}" alt="${noticia.titulo}" class="h-full w-full object-cover transition hover:scale-105 duration-700">
130                </div>
131                <div class="md:w-1/2 p-8 md:p-12 flex flex-col justify-center bg-white">
132                    <span class="text-teal-600 font-bold uppercase tracking-wider text-sm mb-2">${noticia.categoria || 'Actualidad'}</span>
133                    <h3 class="text-2xl md:text-3xl font-bold mb-4 text-gray-800 line-clamp-3">${noticia.titulo}</h3>
134                    <p class="text-gray-600 mb-6 line-clamp-3 text-lg">${noticia.descripcion || ''}</p>
135                    <a href="${noticia.enlace}" class="inline-block bg-teal-600 text-white font-bold py-3 px-6 rounded-lg hover:bg-teal-700 transition self-start shadow-md hover:shadow-lg">${noticia.texto_enlace || 'Leer más'}</a>
136                </div>
137            `;
138            slider.appendChild(slide);
139        });
140
141        // 3. Añadir tarjeta "Ver Todas" al final del carrusel
142        const allNewsSlide = document.createElement('div');
143        allNewsSlide.className = 'news-slide flex-shrink-0 w-full flex flex-col md:flex-row bg-teal-800 text-white';
144        allNewsSlide.innerHTML = `
145            <div class="md:w-1/2 h-64 md:h-[450px] flex items-center justify-center bg-teal-900">
146                <i class="fas fa-newspaper text-9xl text-teal-700 opacity-50"></i>
147            </div>
148            <div class="md:w-1/2 p-8 md:p-12 flex flex-col justify-center">
149                <span class="text-teal-300 font-bold uppercase tracking-wider text-sm mb-2">Archivo de Noticias</span>
150                <h3 class="text-3xl md:text-4xl font-bold mb-6">¿Te perdiste alguna noticia?</h3>
151                <p class="text-teal-100 mb-8 text-lg">Consulta nuestro archivo completo de noticias, comunicados y eventos pasados.</p>
152                <a href="/noticias/news.html" class="inline-block bg-white text-teal-800 font-bold py-3 px-8 rounded-lg hover:bg-teal-50 transition self-start shadow-md hover:shadow-lg">
153                    Ver todas las noticias <i class="fas fa-arrow-right ml-2"></i>
154                </a>
155            </div>
156        `;
157        slider.appendChild(allNewsSlide);
158
159        setupNewsCarousel();
160    }
161
162    function setupNewsCarousel() {
163        const slider = document.getElementById('news-slider');
164        const prev = document.getElementById('news-prev');
165        const next = document.getElementById('news-next');
166        let currentSlide = 0;
167        
168        // Esperar un momento para asegurar que el DOM se actualizó
169        setTimeout(() => {
170            const slides = document.querySelectorAll('.news-slide');
171            const totalSlides = slides.length;
172
173            if (totalSlides === 0) return;
174
175            const moveSlider = () => {
176                slider.style.transform = `translateX(-${currentSlide * 100}%)`;
177            };
178
179            if (next) {
180                next.addEventListener('click', () => {
181                    currentSlide = (currentSlide + 1) % totalSlides;
182                    moveSlider();
183                });
184            }
185
186            if (prev) {
187                prev.addEventListener('click', () => {
188                    currentSlide = (currentSlide - 1 + totalSlides) % totalSlides;
189                    moveSlider();
190                });
191            }
192
193            // Auto-play opcional
194            setInterval(() => {
195                currentSlide = (currentSlide + 1) % totalSlides;
196                moveSlider();
197            }, 7000);
198        }, 100);
199    }
200
201    /**
202     * Renderiza la página completa de noticias con filtros y paginación
203     */
204    function renderNewsPage(allNews, gridContainer) {
205        const filtersContainer = document.getElementById('category-filters');
206        const loadMoreContainer = document.getElementById('load-more-container');
207        const loadMoreBtn = document.getElementById('load-more-btn');
208        const noNewsMsg = document.getElementById('no-news-message');
209
210        let currentFilter = 'all';
211        let itemsToShow = 6;
212        let visibleItems = 0;
213        let filteredNews = [...allNews];
214
215        // 1. Generar Filtros
216        const categories = [...new Set(allNews.map(n => n.categoria).filter(c => c))];
217        categories.forEach(cat => {
218            const btn = document.createElement('button');
219            btn.className = 'filter-btn border border-teal-600 text-teal-700 px-5 py-2 rounded-full hover:bg-teal-600 hover:text-white transition uppercase text-sm font-semibold tracking-wide';
220            btn.textContent = cat;
221            btn.dataset.category = cat;
222            btn.addEventListener('click', (e) => filterNews(cat, e.target));
223            filtersContainer.appendChild(btn);
224        });
225
226        // 2. Renderizado Grid
227        const renderGrid = (append = false) => {
228            if (!append) {
229                gridContainer.innerHTML = '';
230                visibleItems = 0;
231            }
232
233            const nextBatch = filteredNews.slice(visibleItems, visibleItems + itemsToShow);
234            visibleItems += nextBatch.length;
235            
236            if (filteredNews.length === 0) {
237                noNewsMsg.classList.remove('hidden');
238                loadMoreContainer.classList.add('hidden');
239                return;
240            } else {
241                noNewsMsg.classList.add('hidden');
242            }
243
244            nextBatch.forEach(noticia => {
245                const card = document.createElement('div');
246                card.className = 'news-card bg-white rounded-xl overflow-hidden shadow-sm border border-gray-100 hover:shadow-xl transition flex flex-col h-full';
247                card.innerHTML = `
248                    <div class="h-48 overflow-hidden relative group">
249                        <img src="${noticia.imagen}" alt="${noticia.titulo}" class="w-full h-full object-cover transition duration-500 group-hover:scale-110">
250                        <span class="absolute top-4 left-4 bg-teal-600 text-white text-xs font-bold px-3 py-1 rounded-full uppercase tracking-wider shadow-md">
251                            ${noticia.categoria || 'General'}
252                        </span>
253                    </div>
254                    <div class="p-6 flex flex-col flex-grow">
255                        <div class="text-xs text-gray-400 mb-2 flex items-center gap-2">
256                            <i class="far fa-calendar-alt"></i> ${noticia.fecha}
257                        </div>
258                        <h3 class="font-bold text-lg text-gray-800 mb-3 hover:text-teal-600 transition line-clamp-3 leading-tight">
259                            <a href="${noticia.enlace}">${noticia.titulo}</a>
260                        </h3>
261                        <p class="text-gray-600 text-sm mb-4 line-clamp-3 flex-grow">${noticia.descripcion || ''}</p>
262                        <a href="${noticia.enlace}" class="text-teal-600 font-bold text-sm hover:underline mt-auto flex items-center gap-1 group-hover:gap-2 transition-all">
263                            Leer nota completa <i class="fas fa-arrow-right text-xs"></i>
264                        </a>
265                    </div>
266                `;
267                gridContainer.appendChild(card);
268            });
269
270            if (visibleItems >= filteredNews.length) {
271                loadMoreContainer.classList.add('hidden');
272            } else {
273                loadMoreContainer.classList.remove('hidden');
274            }
275        };
276
277        // 3. Filtrado
278        const filterNews = (category, btnClicked) => {
279            currentFilter = category;
280            
281            const allButtons = document.querySelectorAll('.filter-btn');
282            allButtons.forEach(btn => {
283                btn.classList.remove('active', 'bg-teal-600', 'text-white');
284                btn.classList.add('text-teal-700', 'bg-transparent');
285            });
286            
287            btnClicked.classList.add('active', 'bg-teal-600', 'text-white');
288            btnClicked.classList.remove('text-teal-700', 'bg-transparent');
289
290            if (category === 'all') {
291                filteredNews = [...allNews];
292            } else {
293                filteredNews = allNews.filter(n => n.categoria === category);
294            }
295
296            renderGrid(false);
297        };
298
299        if (loadMoreBtn) {
300            loadMoreBtn.addEventListener('click', () => renderGrid(true));
301        }
302        
303        const allBtn = document.querySelector('.filter-btn[data-category="all"]');
304        if(allBtn) {
305             allBtn.addEventListener('click', (e) => filterNews('all', e.target));
306             // Estilo activo por defecto
307             allBtn.classList.add('active', 'bg-teal-600', 'text-white');
308             allBtn.classList.remove('text-teal-700', 'bg-transparent');
309        }
310
311        renderGrid();
312    }
313
314    // Ejecutar carga de noticias
315    loadNews();
316});

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.