| import { Panel } from './Panel'; |
| import type { NewsItem } from '@/types'; |
| import { escapeHtml, sanitizeUrl } from '@/utils/sanitize'; |
| import { t } from '@/services/i18n'; |
| import { setTrustedHtml, trustedHtml } from '@/utils/dom-utils'; |
|
|
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| export class BreakthroughsTickerPanel extends Panel { |
| private tickerTrack: HTMLElement | null = null; |
|
|
| constructor() { |
| super({ id: 'breakthroughs', title: 'Breakthroughs', trackActivity: false }); |
| this.createTickerDOM(); |
| } |
|
|
| |
| |
| |
| private createTickerDOM(): void { |
| const wrapper = document.createElement('div'); |
| wrapper.className = 'breakthroughs-ticker-wrapper'; |
|
|
| const track = document.createElement('div'); |
| track.className = 'breakthroughs-ticker-track'; |
|
|
| wrapper.appendChild(track); |
| this.tickerTrack = track; |
|
|
| |
| setTrustedHtml(this.content, trustedHtml('', "legacy direct innerHTML migration")); |
| this.content.appendChild(wrapper); |
| } |
|
|
| |
| |
| |
| |
| public setItems(items: NewsItem[]): void { |
| if (!this.tickerTrack) return; |
|
|
| if (items.length === 0) { |
| setTrustedHtml(this.tickerTrack, trustedHtml(`<span class="ticker-item ticker-placeholder">${t('components.breakthroughsTicker.noData')}</span>`, "legacy direct innerHTML migration")); |
| return; |
| } |
|
|
| |
| const itemsHtml = items |
| .map( |
| (item) => |
| `<a class="ticker-item" href="${sanitizeUrl(item.link)}" target="_blank" rel="noopener">` + |
| `<span class="ticker-item-source">${escapeHtml(item.source)}</span>` + |
| `<span class="ticker-item-title">${escapeHtml(item.title)}</span>` + |
| `</a>`, |
| ) |
| .join(''); |
|
|
| |
| setTrustedHtml(this.tickerTrack, trustedHtml(itemsHtml + itemsHtml, "legacy direct innerHTML migration")); |
| } |
|
|
| |
| |
| |
| public destroy(): void { |
| if (this.tickerTrack) { |
| this.tickerTrack.style.animationPlayState = 'paused'; |
| this.tickerTrack = null; |
| } |
| super.destroy(); |
| } |
| } |
|
|