Minnesota lawmaker Melissa Hortman and husband shot and killed
k3ia
A Minnesota lawmaker and her husband were shot and killed in their home early Saturday by someone posing as a police officer and a second lawmaker an…
More →
Israel threatens to 'burn' Tehran after retaliatory strikes
91s8
A day after Israel struck several sites in Iran and killed several military commanders and nuclear scientists, Tehran retaliated by firing around 20…
More →
Iran strikes back at Israel with missiles over Jerusalem, Tel Aviv
696g2i
Iran launched retaliatory airstrikes at Israel, with explosions heard in Jerusalem and Tel Aviv, the country's two biggest cities, following Isra…
More →
Israel says it struck Iran's nuclear facilities, missile factories
3c5m6p
Israel launched widescale strikes against Iran, targeting nuclear facilities, ballistic missile factories and military commanders, saying this was th…
More →
Air India plane headed to London crashes with more than 240 onboard
2f535p
An Air India enger plane with over 240 people onboard has crashed Thursday in India’s northwestern city of Ahmedabad, according to the airline an…
More →
UK economy shrinks by the most since 2023 as US tariffs hit
1s2j67
Britain's economic output fell sharply in April, reflecting shockwaves from US President Trump's announcement of wide-ranging tariffs and the…
More →
Northern Ireland burns for third night, police unleash water cannon
3o5d6b
Rioters attacked police and set fires in the streets of Northern Ireland's Ballymena as violence erupted in various locations for a third success…
More →
Hawaii's Kilauea volcano spews lava as it erupts again
6d4c3g
The Kilauea volcano in Hawaii erupts again, with lava fountaining approximately 330 feet high.
More →
Former pupil kills nine, then himself in shooting at Austrian school
585b2s
A 21-year-old shooter, who was a former pupil, killed nine people and then himself at a secondary school in the southern Austrian city of Graz. Inter…
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! i634w