Pesquisar neste blogue

Agregador de Notícias - Moçambique

Agregador de Notícias — Moçambique

Fontes: O País · Jornal Notícias · Carta de Moçambique
Carregamento incremental — notícias aparecem assim que chegam
A iniciar... aguarde — carregando fontes.
return html.replace(/[\s\S]*?<\/script>/gi, '') .replace(/on\w+="[^"]*"/gi, '') // remove atributos on* .replace(/on\w+='[^']*'/gi, ''); } /********************************************* * extraiImagem: tenta buscar imagem do _embedded *********************************************/ function extraiImagemFromArticle(article){ // WP REST com _embed geralmente tem: _embedded['wp:featuredmedia'][0].source_url try { if (article._embedded && article._embedded['wp:featuredmedia'] && article._embedded['wp:featuredmedia'][0]) { const fm = article._embedded['wp:featuredmedia'][0]; // diferentes WP setups usam source_url ou media_details.sizes return fm.source_url || (fm.media_details && fm.media_details.sizes && Object.values(fm.media_details.sizes)[0].source_url) || null; } } catch(e){/*ignored*/} // fallback: procurar por primeira imagem no content.rendered try { const match = /]+src=["']([^"']+)["']/i.exec(article.content && article.content.rendered ? article.content.rendered : ''); if (match) return match[1]; } catch(e){} return null; } /********************************************* * formatDate: formata data ISO para pt-PT/pt-MZ *********************************************/ function formatDate(iso){ try { const d = new Date(iso); return d.toLocaleString('pt-PT', { year:'numeric', month:'short', day:'2-digit', hour:'2-digit', minute:'2-digit' }); } catch(e){ return iso; } } /********************************************* * renderSingleArticle: cria cartão e adiciona *********************************************/ function renderSingleArticle(article, sourceName){ // remover loader se presente if (loader) loader.remove(); const card = document.createElement('article'); card.className = 'news-card'; const imageUrl = extraiImagemFromArticle(article); const title = (article.title && (article.title.rendered || article.title)) ? (article.title.rendered || article.title) : 'Sem título'; const date = article.date ? formatDate(article.date) : (article.modified ? formatDate(article.modified) : ''); const excerpt = (article.excerpt && article.excerpt.rendered) ? sanitizeHTML(article.excerpt.rendered) : ''; const contentHTML = (article.content && article.content.rendered) ? sanitizeHTML(article.content.rendered) : ''; // construir inner let inner = ''; if (imageUrl) { inner += `thumb`; } inner += `
`; inner += `

${title}

`; inner += `
${sourceName}${date}
`; if (excerpt) inner += `
${excerpt}
`; inner += `
`; card.innerHTML = inner; card.addEventListener('click', ()=> openModal(title, sourceName, date, contentHTML)); container.prepend(card); // prepend para mostrar as notícias mais recentes primeiro (opcional) } /********************************************* * openModal: mostra notícia completa *********************************************/ const modal = document.getElementById('modal'); const modalTitle = document.getElementById('modal-title'); const modalMeta = document.getElementById('modal-meta'); const modalBody = document.getElementById('modal-body'); const closeBtn = document.getElementById('close-btn'); function openModal(title, source, date, contentHTML){ modalTitle.innerHTML = title; modalMeta.textContent = `${source} • ${date}`; modalBody.innerHTML = contentHTML || '

Sem conteúdo disponível.

'; modal.classList.add('open'); modal.setAttribute('aria-hidden','false'); // rolar para top do modal-content document.getElementById('modal-content').scrollTop = 0; } closeBtn.addEventListener('click', ()=> { modal.classList.remove('open'); modal.setAttribute('aria-hidden','true'); }); modal.addEventListener('click', (e)=>{ if (e.target === modal) { modal.classList.remove('open'); modal.setAttribute('aria-hidden','true'); } }); /********************************************* * Carregamento incremental: fetch cada fonte *********************************************/ async function loadAllSources() { // mostrar loader if (!loader) { const l = document.createElement('div'); l.className = 'loader'; l.id = 'loader'; l.textContent = 'Carregando fontes...'; container.appendChild(l); } for (const s of sources){ // iniciamos cada fetch sem aguardar a anterior terminar? aqui fazemos sequencial por simplicidade. // para paralelizar e ainda renderizar assim que cada promessa resolve, use Promise.allSettled com .then() (async () => { try { const data = await fetchWithCorsFallback(s.url); if (!Array.isArray(data)) { throw new Error('Resposta inesperada (não é array)'); } // iterar e renderizar cada notícia data.forEach(article => { try { renderSingleArticle(article, s.name); } catch(innerErr){ console.error('Erro ao renderizar artigo', innerErr); } }); } catch (err) { console.error('Falha ao carregar fonte', s.name, err); const errDiv = document.createElement('div'); errDiv.className = 'error'; errDiv.textContent = `Erro ao carregar ${s.name}: ${err.message || err}`; container.appendChild(errDiv); if (loader) loader.remove(); } })(); } } // Iniciar loadAllSources(); // Permitir atualização manual com F5? já é padrão. Podemos também adicionar refresh clicável no futuro.

0 Comentários

Type and hit Enter to search

Close