China responds after Pete Hegseth says 'the threat China poses is real'
573561
China's representative at the Shangri-La Dialogue in Singapore accused U.S. Defense Secretary Pete Hegseth of making “groundless accusations” of …
More →
Supreme Court lets Trump revoke 'parole' status for migrants
681zg
The Supreme Court let the Trump istration revoke the temporary legal status of hundreds of thousands of Venezuelan, Cuban, Haitian and Nicaragua…
More →
Trump gifts Elon Musk a golden key for his DOGE work
2o6a6k
President Donald Trump gives tech billionaire Elon Musk a gold-colored key for his work establishing the "Department of Government Efficiency,&q…
More →
Trump says China 'totally violated' deal with US on tariffs
w4n3z
'So much for being Mr. NICE GUY!,' US President Donald Trump said in a post on his Truth Social platform, while issuing a veiled threat to ge…
More →
Pope Leo XIV meets Ecumenical Patriarch Bartholomew I at the Vatican
5r5r5r
Pope Leo XIV met on Friday at the Vatican with Ecumenical Patriarch Bartholomew I, the spiritual leader of the world’s Orthodox Christians.
More →
Bolivians protest on the streets amid economic crisis
4wb36
Demonstrations erupted across Bolivia as farmers, truck drivers, and ers of former President Evo Morales took to the streets to protest the co…
More →
Aerial video shows aftermath of glacier collapse in Switzerland
1140v
Aerial footage showed flooded homes and debris scattered around a Swiss village after a huge mass of rock and ice from a glacier crashed down a mount…
More →
South Korea's presidential election set to reshape key policies
4t3k6w
South Korean liberal candidate Lee Jae-myung is projected to win next week's snap presidential election, a result that could reorient a major US …
More →
India's Kerala state on high alert as vessel with hazardous cargo sinks off its coast
2u1k64
India’s southern state of Kerala on Monday asked fishermen not to venture near the site of an accident where a container ship carrying hazardous car…
More →
`;
container.appendChild(feedSection);
const targetElement = document.getElementById(feedConfig.targetElementId);
if (!targetElement) {
console.error(`Elemento target no encontrado: ${feedConfig.targetElementId}`);
const errorDiv = document.createElement('div');
errorDiv.className = 'error-rss';
errorDiv.innerHTML = `Error de configuración: Contenedor para "${sanitizeHtml(feedConfig.title)}" no encontrado.`;
// Adjuntar al feedSection en lugar de al container principal para errores por feed
feedSection.querySelector('.rss-items-wrapper').innerHTML = errorDiv.outerHTML;
return;
}
try {
const apiUrl = `https://api.rss2json.com/v1/api.json?rss_url=${encodeURIComponent(feedConfig.url)}`;
const response = await fetch(apiUrl);
if (!response.ok) {
throw new Error(`Error de red/servidor (${response.status}) al ar rss2json para ${sanitizeHtml(feedConfig.title)}.`);
}
const data = await response.json();
if (data.status !== 'ok') {
// Intenta mostrar el mensaje de error de rss2json si está disponible
const apiErrorMessage = data.message ? `API Error: ${data.message}` : `Error desconocido de rss2json`;
throw new Error(`${apiErrorMessage} para ${sanitizeHtml(feedConfig.title)}.`);
}
if (!data.items || data.items.length === 0) {
targetElement.innerHTML = '';
return;
}
targetElement.innerHTML = ''; // Limpiar "Cargando"
const items = data.items.slice(0, maxItemsPerFeed);
items.forEach((item, index) => {
const title = sanitizeHtml(item.title || 'Sin título');
const link = item.link || '#';
const rawSnippet = item.description || item.content || ''; // rss2json pone el contenido en description
const cleanSnippet = sanitizeHtml(rawSnippet);
const truncatedSnippet = truncateText(cleanSnippet, snippetMaxLength);
const imageUrl = extractImageUrl(item); // Usa la función modificada
const itemDiv = document.createElement('div');
itemDiv.className = 'rss-item';
// onerror para imagen: intenta cargar el placeholder si la imagen principal falla
const imageOnErrorScript = `this.onerror=null; this.src='${placeholderImageUrl}'; this.classList.add('image-load-error');`;
// Si quieres el layout de "1 grande, 2 pequeños" DENTRO de CADA feed
// necesitarías modificar la lógica de cómo se añaden los items aquí.
// Por ahora, mantendré la lógica original de este script que parece ser:
// - El primer item (.featured-item) se añade directamente.
// - Los siguientes items se agrupan en un .small-item-container con .small-item.
// Esta lógica ya estaba en tu script, la he mantenido.
let itemHTML = `
`;
// La lógica de featured-item y small-item-container ya estaba en tu script.
// Si quieres el layout 1 grande, 2 pequeños, 1 grande, 2 pequeños etc.
// esta lógica debería funcionar para el primer grupo (1 grande, N-1 pequeños).
// Si maxItemsPerFeed es 3, tendrás 1 grande y 2 pequeños.
if (index === 0 && maxItemsPerFeed > 1) { // Solo si hay más de 1 item, el primero es "featured"
itemDiv.classList.add('featured-rss-item'); // Renombrada para evitar colisión con AFCM
itemDiv.innerHTML = itemHTML;
targetElement.appendChild(itemDiv);
} else {
// Agrupar los siguientes en un contenedor si no existe ya para este feed
let smallItemsPairContainer = targetElement.querySelector('.secondary-rss-items-pair');
if (!smallItemsPairContainer) {
smallItemsPairContainer = document.createElement('div');
smallItemsPairContainer.className = 'secondary-rss-items-pair'; // Contenedor para pares
targetElement.appendChild(smallItemsPairContainer);
}
const secondaryItemDiv = document.createElement('div');
secondaryItemDiv.className = 'rss-item secondary-rss-item'; // Ítem individual del par
secondaryItemDiv.innerHTML = itemHTML;
smallItemsPairContainer.appendChild(secondaryItemDiv);
}
});
} catch (error) {
console.error(`Error al obtener o procesar el feed "${sanitizeHtml(feedConfig.title)}":`, error.message, error);
targetElement.innerHTML = ``;
}
}
if (mainWidgetContainer) {
if (feedsConfig && feedsConfig.length > 0) {
feedsConfig.forEach((config) => { // No es necesario `async` aquí en el forEach si `fetchAndDisplayFeed` es `async`
fetchAndDisplayFeed(config, mainWidgetContainer); // No esperamos aquí, dejamos que se ejecuten en paralelo
});
// El separador
se añade después de que todos los fetchAndDisplayFeed se hayan INICIADO,
// no necesariamente completado. Si el orden es crítico, se necesitaría un enfoque diferente.
// Para simplificar y asegurar que el
se añade después de cada sección de feed:
// (Esta parte del separador es un poco compleja de hacer bien con async/await en un forEach,
// la forma original de añadirlo podría ser más robusta si el orden importa visualmente)
// Por ahora, lo eliminamos de aquí para no complicar y lo gestionamos con CSS (gap en #dual-rss)
} else {
mainWidgetContainer.innerHTML = "";
}
} else {
console.error("Contenedor principal del widget 'dual-rss' no encontrado.");
}
});
//]]>
Follow us on social networks! 5s334x