function onReady(fn){ if(document.readyState !== 'loading') fn(); else document.addEventListener('DOMContentLoaded', fn); } // Función que realiza la transformación visual function formatearItemsMenu() { // Seleccionamos todos los enlaces del menú const links = document.querySelectorAll('.nav-link'); links.forEach(link => { // Obtenemos el HTML actual (para no borrar el div del icono) let htmlContent = link.innerHTML; // Verificamos si ya fue modificado para evitar bucles infinitos if (htmlContent.includes('class="fw-semibold d-block text-center"')) return; // CASO 1: Panorama INTERNACIONAL if (htmlContent.includes('Panorama INTERNACIONAL')) { // Reemplazamos el texto por la versión con salto de línea y estilos link.innerHTML = htmlContent.replace( 'Panorama INTERNACIONAL', 'Panorama INTERNACIONAL' ); } // CASO 2: Panorama NACIONAL else if (htmlContent.includes('Panorama NACIONAL')) { link.innerHTML = htmlContent.replace( 'Panorama NACIONAL', 'Panorama NACIONAL' ); } }); } // Crear el MutationObserver para detectar cambios en el DOM const observer = new MutationObserver((mutations) => { // Verificamos si el menú ya existe en el DOM const menu = document.getElementById('navbarClassicCollapse'); if (menu) { formatearItemsMenu(); // Si el menú carga una sola vez y no cambia más, podrías desconectar el observer: // observer.disconnect(); } }); // Observamos todo el 'body' buscando cambios en los hijos (childList) y subárboles (subtree) observer.observe(document.body, { childList: true, subtree: true }); // Intentamos ejecutarlo una vez al inicio por si el menú ya está cargado document.addEventListener('DOMContentLoaded', formatearItemsMenu); /* =============================== INFORMACIÓN PÁGINA PRINCIPAL ================================= */ (() => { const API_URL = "https://portal.ucol.mx/culturaf/gaceta/ws/all/"; const API_URL_AUTOR = "https://portal.ucol.mx/culturaf/gaceta/ws/authors/"; const $left = document.getElementById("colLeft"); const $center = document.getElementById("colCenter"); const $right = document.getElementById("colRight"); const $list = document.getElementById("authorsList"); if (!$left || !$center || !$right) { console.warn("[newsGrid] Faltan contenedores:", { colLeft: !!$left, colCenter: !!$center, colRight: !!$right }); return; } function esc(s) { return String(s ?? "") .replace(/&/g, "&") .replace(//g, ">") .replace(/"/g, """) .replace(/'/g, "'"); } function trunc(s, n) { s = String(s ?? "").trim(); if (!s) return ""; return s.length > n ? s.slice(0, n - 3).trimEnd() + "..." : s; } function byline(item) { const tipo = esc(item?.tipo || "Artículo"); const foto = esc(item?.autor?.foto || ""); const autor = esc(item?.autor?.nombre || ""); const puesto = esc(item?.autor?.puesto || ""); return `
${foto ? `
${autor ? autor : ''}
` : ""} ${tipo} ${autor ? `por ${autor}` : ""} ${puesto ? ` | ${puesto}` : ""}
`; } function slugTipo(tipo) { return String(tipo ?? "") .trim() .toLowerCase() .normalize("NFD") .replace(/[\u0300-\u036f]/g, "") .replace(/\s+/g, "-") .replace(/[^a-z0-9-]/g, ""); } function decodeEntities(input) { const s = String(input ?? ""); if (!s) return ""; const t = document.createElement("textarea"); t.innerHTML = s; // convierte " -> " (1 pasada) const once = t.value; // segunda pasada por si venía doble-encodado (") t.innerHTML = once; return t.value; } // Texto seguro para pintar: decode -> esc function safeText(input) { return esc(decodeEntities(input)); } function truncText(input, n) { const s = decodeEntities(input).trim(); if (!s) return ""; return s.length > n ? s.slice(0, n - 3).trimEnd() + "..." : s; } function href(item) { const tipo = slugTipo(item?.tipo); const id = String(item?.id ?? "").trim(); return `nota.htm#${encodeURIComponent(tipo)}-${encodeURIComponent(id)}`; } function cardLeftMain(item) { return `
NUEVAS
${esc(item?.titulo)}

${safeText(truncText(item?.descripcion, 220))}

${byline(item)}
`; } function cardLeftImage(item) { return `
${esc(item?.titulo)}
${byline(item)}
`; } function cardCenterBig(item) { return `

${esc(item?.titulo)}

${safeText(truncText(item?.descripcion, 140))}

${byline(item)}
`; } function cardRightSmall(item) { return `
${esc(item?.titulo)}
${byline(item)}
`; } function showError(msg) { const html = ` `; $left.innerHTML = html; $center.innerHTML = ""; $right.innerHTML = ""; } function renderRow(items, rowIndex) { const base = rowIndex * 5; const a = items[base + 0]; const b = items[base + 1]; const c = items[base + 2]; const d = items[base + 3]; const e = items[base + 4]; // Si no hay suficientes para una fila completa, NO revienta: // renderiza lo que exista siguiendo el mismo patrón. const leftHTML = (a ? cardLeftMain(a) : "") + (b ? cardLeftImage(b) : ""); const centerHTML = c ? `
${cardCenterBig(c)}
` : ""; const rightHTML = (d ? cardRightSmall(d) : "") + (e ? cardRightSmall(e) : ""); return { leftHTML, centerHTML, rightHTML }; } async function init() { try { // Loading (opcional) $left.innerHTML = `

`; $center.innerHTML = `

`; $right.innerHTML = `

`; const res = await fetch(API_URL, { method: "GET" }); if (!res.ok) throw new Error(`HTTP ${res.status}`); const data = await res.json(); if (!Array.isArray(data) || data.length === 0) { showError("No hay elementos para mostrar."); return; } const totalRows = Math.ceil(data.length / 5); let leftAll = ""; let centerAll = ""; let rightAll = ""; for (let i = 0; i < totalRows; i++) { const { leftHTML, centerHTML, rightHTML } = renderRow(data, i); leftAll += leftHTML; centerAll += centerHTML; rightAll += rightHTML; } $left.innerHTML = leftAll || ""; $center.innerHTML = centerAll || ""; $right.innerHTML = rightAll || ""; } catch (err) { console.error(err); showError("No se pudo cargar la información del servicio. Intenta más tarde."); } } function hrefAutor(id) { return `autores.htm#${encodeURIComponent(String(id ?? "").trim())}`; } function renderAuthors(items) { const html = items.map(a => { const nombre = esc(a.nombre); const puesto = esc(a.puesto); const foto = esc(a.foto); // Primera letra (con fallback a "?") const inicial = (String(a.nombre || "").trim().charAt(0) || "?").toUpperCase(); return `
Foto de ${nombre}

${nombre}

${puesto}

`; }).join(""); $list.innerHTML = html; } async function load() { try { if (!$list) return; // (opcional) limpia $list.innerHTML = ""; const res = await fetch(API_URL_AUTOR, { method: "GET", headers: { "Accept": "application/json" }, cache: "no-store" }); if (!res.ok) throw new Error("HTTP " + res.status); const data = await res.json(); if (!Array.isArray(data)) throw new Error("Respuesta inesperada: no es un arreglo"); renderAuthors(data); $list.classList.remove("d-none"); } catch (e) { console.error("[authors]", e); } } load(); init(); })();