Add clickable article links to Live News Ticker
RSS and GDELT ticker items now open the source article in a new tab when clicked. Telegram/WHO items without URLs remain non-clickable. Changes: - Extract <link> from RSS feed items in inject.mjs - Carry url field through fetchAllNews() and buildNewsFeed() - Add data-url attribute and pointer cursor to clickable ticker cards - Add delegated click listener to open articles in new tab
This commit is contained in:
@@ -69,8 +69,9 @@ async function fetchRSS(url, source) {
|
|||||||
while ((match = itemRegex.exec(xml)) !== null) {
|
while ((match = itemRegex.exec(xml)) !== null) {
|
||||||
const block = match[1];
|
const block = match[1];
|
||||||
const title = (block.match(/<title>(?:<!\[CDATA\[)?(.*?)(?:\]\]>)?<\/title>/)?.[1] || '').trim();
|
const title = (block.match(/<title>(?:<!\[CDATA\[)?(.*?)(?:\]\]>)?<\/title>/)?.[1] || '').trim();
|
||||||
|
const link = (block.match(/<link>(?:<!\[CDATA\[)?(.*?)(?:\]\]>)?<\/link>/)?.[1] || '').trim();
|
||||||
const pubDate = block.match(/<pubDate>(.*?)<\/pubDate>/)?.[1] || '';
|
const pubDate = block.match(/<pubDate>(.*?)<\/pubDate>/)?.[1] || '';
|
||||||
if (title && title !== source) items.push({ title, date: pubDate, source });
|
if (title && title !== source) items.push({ title, date: pubDate, source, url: link || undefined });
|
||||||
}
|
}
|
||||||
return items;
|
return items;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@@ -107,6 +108,7 @@ export async function fetchAllNews() {
|
|||||||
title: item.title.substring(0, 100),
|
title: item.title.substring(0, 100),
|
||||||
source: item.source,
|
source: item.source,
|
||||||
date: item.date,
|
date: item.date,
|
||||||
|
url: item.url,
|
||||||
lat: geo.lat + (Math.random() - 0.5) * 2,
|
lat: geo.lat + (Math.random() - 0.5) * 2,
|
||||||
lon: geo.lon + (Math.random() - 0.5) * 2,
|
lon: geo.lon + (Math.random() - 0.5) * 2,
|
||||||
region: geo.region
|
region: geo.region
|
||||||
@@ -409,17 +411,17 @@ function buildNewsFeed(rssNews, gdeltData, tgUrgent, tgTop) {
|
|||||||
for (const n of rssNews) {
|
for (const n of rssNews) {
|
||||||
feed.push({
|
feed.push({
|
||||||
headline: n.title, source: n.source, type: 'rss',
|
headline: n.title, source: n.source, type: 'rss',
|
||||||
timestamp: n.date, region: n.region, urgent: false
|
timestamp: n.date, region: n.region, urgent: false, url: n.url
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// GDELT top articles
|
// GDELT top articles
|
||||||
for (const title of (gdeltData.allArticles || []).slice(0, 10).map(a => a.title)) {
|
for (const a of (gdeltData.allArticles || []).slice(0, 10)) {
|
||||||
if (title) {
|
if (a.title) {
|
||||||
const geo = geoTagText(title);
|
const geo = geoTagText(a.title);
|
||||||
feed.push({
|
feed.push({
|
||||||
headline: title.substring(0, 100), source: 'GDELT', type: 'gdelt',
|
headline: a.title.substring(0, 100), source: 'GDELT', type: 'gdelt',
|
||||||
timestamp: new Date().toISOString(), region: geo?.region || 'Global', urgent: false
|
timestamp: new Date().toISOString(), region: geo?.region || 'Global', urgent: false, url: a.url
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -182,6 +182,7 @@ html,body{height:100%;background:var(--bg);color:var(--text);font-family:var(--s
|
|||||||
.ticker-wrap:hover .ticker-track{animation-play-state:paused}
|
.ticker-wrap:hover .ticker-track{animation-play-state:paused}
|
||||||
@keyframes tickerScroll{0%{transform:translateY(0)}100%{transform:translateY(-50%)}}
|
@keyframes tickerScroll{0%{transform:translateY(0)}100%{transform:translateY(-50%)}}
|
||||||
.tk-card{padding:8px 10px;border-bottom:1px solid rgba(255,255,255,0.03);cursor:default;transition:background 0.2s}
|
.tk-card{padding:8px 10px;border-bottom:1px solid rgba(255,255,255,0.03);cursor:default;transition:background 0.2s}
|
||||||
|
.tk-card.clickable{cursor:pointer}
|
||||||
.tk-card:hover{background:rgba(100,240,200,0.04)}
|
.tk-card:hover{background:rgba(100,240,200,0.04)}
|
||||||
.tk-card.urgent{border-left:2px solid var(--danger)}
|
.tk-card.urgent{border-left:2px solid var(--danger)}
|
||||||
.tk-src{font-family:var(--mono);font-size:8px;letter-spacing:0.08em;text-transform:uppercase;padding:1px 5px;border:1px solid;display:inline-block;margin-right:4px}
|
.tk-src{font-family:var(--mono);font-size:8px;letter-spacing:0.08em;text-transform:uppercase;padding:1px 5px;border:1px solid;display:inline-block;margin-right:4px}
|
||||||
@@ -815,7 +816,8 @@ function renderLower(){
|
|||||||
const tickerCards = feed.map(n => {
|
const tickerCards = feed.map(n => {
|
||||||
const sc = srcClass(n.source);
|
const sc = srcClass(n.source);
|
||||||
const age = n.timestamp ? getAge(n.timestamp) : '';
|
const age = n.timestamp ? getAge(n.timestamp) : '';
|
||||||
return `<div class="tk-card ${n.urgent?'urgent':''}"><span class="tk-src ${sc}">${(n.source||'NEWS').substring(0,12)}</span><span class="tk-time">${age}</span><div class="tk-head">${cleanText(n.headline||'')}</div></div>`;
|
const urlAttr = n.url ? ` data-url="${String(n.url).replace(/&/g,'&').replace(/"/g,'"')}"` : '';
|
||||||
|
return `<div class="tk-card ${n.urgent?'urgent':''} ${n.url?'clickable':''}"${urlAttr}><span class="tk-src ${sc}">${(n.source||'NEWS').substring(0,12)}</span><span class="tk-time">${age}</span><div class="tk-head">${cleanText(n.headline||'')}</div></div>`;
|
||||||
}).join('');
|
}).join('');
|
||||||
const tickerDuration = Math.max(20, feed.length * 2.5);
|
const tickerDuration = Math.max(20, feed.length * 2.5);
|
||||||
|
|
||||||
@@ -1047,6 +1049,11 @@ function init(){
|
|||||||
document.getElementById('mapContainer').addEventListener('click',e=>{
|
document.getElementById('mapContainer').addEventListener('click',e=>{
|
||||||
if(!e.target.closest('.map-popup')) closePopup();
|
if(!e.target.closest('.map-popup')) closePopup();
|
||||||
});
|
});
|
||||||
|
// Open article links from ticker cards
|
||||||
|
document.addEventListener('click',e=>{
|
||||||
|
const card=e.target.closest('.tk-card[data-url]');
|
||||||
|
if(card) window.open(card.dataset.url,'_blank','noopener');
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
document.addEventListener('DOMContentLoaded', () => {
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
|
|||||||
Reference in New Issue
Block a user