| 
									
										
										
										
											2025-09-03 14:35:18 -03:00
										 |  |  | // frontend/public/bootstrap.js
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-03 15:03:15 -03:00
										 |  |  | (function () { | 
					
						
							| 
									
										
										
										
											2025-09-03 14:35:18 -03:00
										 |  |  |   // El dominio donde se alojan los widgets
 | 
					
						
							|  |  |  |   const WIDGETS_HOST = 'https://elecciones2025.eldia.com'; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-10-27 12:25:30 -03:00
										 |  |  |   // Estado interno para evitar recargas y re-fetch innecesarios
 | 
					
						
							|  |  |  |   const __state = { | 
					
						
							|  |  |  |     assetsLoaded: false, | 
					
						
							|  |  |  |     manifest: null, | 
					
						
							|  |  |  |   }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // Función para cargar dinámicamente un script (evita duplicados)
 | 
					
						
							| 
									
										
										
										
											2025-09-03 13:49:35 -03:00
										 |  |  |   function loadScript(src) { | 
					
						
							|  |  |  |     return new Promise((resolve, reject) => { | 
					
						
							| 
									
										
										
										
											2025-10-27 12:25:30 -03:00
										 |  |  |       if ([...document.scripts].some(s => s.src === src)) return resolve(); | 
					
						
							| 
									
										
										
										
											2025-09-03 13:49:35 -03:00
										 |  |  |       const script = document.createElement('script'); | 
					
						
							|  |  |  |       script.type = 'module'; | 
					
						
							|  |  |  |       script.src = src; | 
					
						
							|  |  |  |       script.onload = resolve; | 
					
						
							|  |  |  |       script.onerror = reject; | 
					
						
							|  |  |  |       document.head.appendChild(script); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-10-27 12:25:30 -03:00
										 |  |  |   // Función para cargar dinámicamente una hoja de estilos (evita duplicados)
 | 
					
						
							| 
									
										
										
										
											2025-09-03 13:49:35 -03:00
										 |  |  |   function loadCSS(href) { | 
					
						
							| 
									
										
										
										
											2025-10-27 12:25:30 -03:00
										 |  |  |     if ([...document.querySelectorAll('link[rel="stylesheet"]')].some(l => l.href === href)) return; | 
					
						
							| 
									
										
										
										
											2025-09-03 13:49:35 -03:00
										 |  |  |     const link = document.createElement('link'); | 
					
						
							|  |  |  |     link.rel = 'stylesheet'; | 
					
						
							|  |  |  |     link.href = href; | 
					
						
							|  |  |  |     document.head.appendChild(link); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-10-27 12:25:30 -03:00
										 |  |  |   // Carga (una sola vez) JS/CSS definidos por el manifest
 | 
					
						
							|  |  |  |   async function ensureAssetsFromManifest() { | 
					
						
							|  |  |  |     if (__state.assetsLoaded) return; | 
					
						
							| 
									
										
										
										
											2025-09-03 13:49:35 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-10-27 12:25:30 -03:00
										 |  |  |     // 1) Obtener el manifest.json (cache: no-store por si hay deploys frecuentes)
 | 
					
						
							|  |  |  |     if (!__state.manifest) { | 
					
						
							|  |  |  |       const response = await fetch(`${WIDGETS_HOST}/manifest.json`, { cache: 'no-store' }); | 
					
						
							|  |  |  |       if (!response.ok) throw new Error('No se pudo cargar el manifest de los widgets.'); | 
					
						
							|  |  |  |       __state.manifest = await response.json(); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2025-09-03 15:03:15 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-10-27 12:25:30 -03:00
										 |  |  |     // 2) Encontrar el entry principal (isEntry=true)
 | 
					
						
							|  |  |  |     const entryKey = Object.keys(__state.manifest).find(key => __state.manifest[key].isEntry); | 
					
						
							|  |  |  |     if (!entryKey) throw new Error('No se encontró el punto de entrada en el manifest.'); | 
					
						
							| 
									
										
										
										
											2025-09-03 15:03:15 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-10-27 12:25:30 -03:00
										 |  |  |     const entry = __state.manifest[entryKey]; | 
					
						
							|  |  |  |     const jsUrl = `${WIDGETS_HOST}/${entry.file}`; | 
					
						
							| 
									
										
										
										
											2025-09-03 13:49:35 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-10-27 12:25:30 -03:00
										 |  |  |     // 3) Cargar el CSS si existe (una sola vez)
 | 
					
						
							|  |  |  |     if (entry.css && entry.css.length > 0) { | 
					
						
							|  |  |  |       entry.css.forEach(cssFile => loadCSS(`${WIDGETS_HOST}/${cssFile}`)); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // 4) Cargar el JS principal (una sola vez)
 | 
					
						
							|  |  |  |     await loadScript(jsUrl); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     __state.assetsLoaded = true; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // Render: busca contenedores y llama a la API global del widget
 | 
					
						
							|  |  |  |   function renderWidgetsOnPage() { | 
					
						
							|  |  |  |     if (!(window.EleccionesWidgets && typeof window.EleccionesWidgets.render === 'function')) { | 
					
						
							|  |  |  |       // La librería aún no expuso la API (puede ocurrir en primeros ms tras cargar)
 | 
					
						
							|  |  |  |       return; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2025-09-03 14:35:18 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-10-27 12:25:30 -03:00
										 |  |  |     const widgetContainers = document.querySelectorAll('[data-elecciones-widget]'); | 
					
						
							|  |  |  |     if (widgetContainers.length === 0) { | 
					
						
							|  |  |  |       // En algunas rutas no habrá widgets: no es error.
 | 
					
						
							|  |  |  |       return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     widgetContainers.forEach(container => { | 
					
						
							|  |  |  |       window.EleccionesWidgets.render(container, container.dataset); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // Función principal (re-usable) para inicializar y renderizar
 | 
					
						
							|  |  |  |   async function initWidgets() { | 
					
						
							|  |  |  |     try { | 
					
						
							|  |  |  |       await ensureAssetsFromManifest(); | 
					
						
							|  |  |  |       renderWidgetsOnPage(); | 
					
						
							| 
									
										
										
										
											2025-09-03 13:49:35 -03:00
										 |  |  |     } catch (error) { | 
					
						
							| 
									
										
										
										
											2025-09-03 14:35:18 -03:00
										 |  |  |       console.error('Error al inicializar los widgets de elecciones:', error); | 
					
						
							| 
									
										
										
										
											2025-09-03 13:49:35 -03:00
										 |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2025-09-03 14:35:18 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-10-27 12:25:30 -03:00
										 |  |  |   // Exponer para invocación manual (por ejemplo, en hooks del router)
 | 
					
						
							|  |  |  |   window.__eleccionesInit = initWidgets; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // Primer render en carga inicial
 | 
					
						
							|  |  |  |   if (document.readyState === 'loading') { | 
					
						
							| 
									
										
										
										
											2025-09-03 15:01:09 -03:00
										 |  |  |     document.addEventListener('DOMContentLoaded', initWidgets); | 
					
						
							| 
									
										
										
										
											2025-10-27 12:25:30 -03:00
										 |  |  |   } else { | 
					
						
							| 
									
										
										
										
											2025-09-03 15:01:09 -03:00
										 |  |  |     initWidgets(); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2025-09-03 14:35:18 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-10-27 12:25:30 -03:00
										 |  |  |   // --- Reinvocar en cada navegación de SPA ---
 | 
					
						
							|  |  |  |   function dispatchLocationChange() { | 
					
						
							|  |  |  |     window.dispatchEvent(new Event('locationchange')); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   ['pushState', 'replaceState'].forEach(method => { | 
					
						
							|  |  |  |     const orig = history[method]; | 
					
						
							|  |  |  |     history[method] = function () { | 
					
						
							|  |  |  |       const ret = orig.apply(this, arguments); | 
					
						
							|  |  |  |       dispatchLocationChange(); | 
					
						
							|  |  |  |       return ret; | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  |   window.addEventListener('popstate', dispatchLocationChange); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   let navDebounce = null; | 
					
						
							|  |  |  |   window.addEventListener('locationchange', () => { | 
					
						
							|  |  |  |     clearTimeout(navDebounce); | 
					
						
							|  |  |  |     navDebounce = setTimeout(() => { | 
					
						
							|  |  |  |       initWidgets(); | 
					
						
							|  |  |  |     }, 0); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // --- (Opcional) Re-render si aparecen contenedores luego del montaje de la vista ---
 | 
					
						
							|  |  |  |   const mo = new MutationObserver((mutations) => { | 
					
						
							|  |  |  |     for (const m of mutations) { | 
					
						
							|  |  |  |       if (m.type === 'childList') { | 
					
						
							|  |  |  |         const added = [...m.addedNodes].some(n => | 
					
						
							|  |  |  |           n.nodeType === 1 && | 
					
						
							|  |  |  |           (n.matches?.('[data-elecciones-widget]') || n.querySelector?.('[data-elecciones-widget]')) | 
					
						
							|  |  |  |         ); | 
					
						
							|  |  |  |         if (added) { renderWidgetsOnPage(); break; } | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  |   mo.observe(document.body, { childList: true, subtree: true }); | 
					
						
							|  |  |  | })(); |