(function() { const data = window.KB_DATA; const { meta, competitors, categories, entries } = data; // === Translation Engine (always Chinese) === // Known source suffixes to strip const SOURCE_SUFFIXES = [ 'The Globe and Mail', 'StockStory', 'MSN', 'The Motley Fool', 'ADWEEK', 'Fast Company', 'AD HOC NEWS', 'MediaPost', 'Marketing Dive', 'Investing.com', 'TradingView', 'Sixteen:Nine', 'Storyboard18', '24/7 Wall St.', 'AdExchanger', 'PPC Land', 'Stock Titan', 'Seeking Alpha', 'TIKR.com', 'exchangewire.com', 'Campaign US', 'Ad Age', 'thecurrent.com', 'acrofan.com', 'Kavout', 'About Amazon', 'NZ Herald', 'DecisionMarketing', 'DemandSage', 'Modern Retail', 'CNBC', 'ALM Corp', 'marketech apac', 'Influencer Marketing Hub', 'Business of Apps', 'TechStock\u00b2' ]; function stripSourceSuffix(text) { if (!text) return ''; // Remove HTML entities let t = text.replace(/ /g, ' ').replace(/&#\d+;/g, '').replace(/&/g, '&').trim(); // Remove date stamps like "05/12/2026" or "04/28/2026" t = t.replace(/\s*\d{2}\/\d{2}\/\d{4}\s*/g, ' ').trim(); // Remove known source suffixes (e.g., " - The Motley Fool") for (const src of SOURCE_SUFFIXES) { const idx = t.lastIndexOf(' - ' + src); if (idx > 0) { t = t.substring(0, idx).trim(); break; } const idx2 = t.lastIndexOf(' ' + src); if (idx2 > 0) { t = t.substring(0, idx2).trim(); break; } } // Fallback: strip trailing " - Source" pattern (short source name after last dash) t = t.replace(/\s+[-\u2013\u2014]\s+[A-Z][A-Za-z0-9\s.&\u00b2]{1,30}$/, '').trim(); return t; } function translateText(text) { if (!text) return ''; let t = stripSourceSuffix(text); // If already mostly Chinese, return as-is const chineseRatio = (t.match(/[\u4e00-\u9fff]/g) || []).length / t.length; if (chineseRatio > 0.4) return t; // Return cleaned English (brand names are acceptable in Chinese industry context) return t; } function getTitle(entry) { if (entry.title_zh) return entry.title_zh; return translateText(entry.title); } function getSummary(entry) { if (entry.summary_zh) return entry.summary_zh; return stripSourceSuffix(entry.summary); } // Header document.getElementById('title').textContent = meta.title; document.getElementById('subtitle').textContent = meta.subtitle; document.getElementById('meta-updated').textContent = '\u6700\u540e\u66f4\u65b0: ' + meta.lastUpdated; document.getElementById('meta-count').textContent = '\u5171 ' + entries.length + ' \u6761\u8d44\u8baf'; // Stats const statsEl = document.getElementById('stats'); const highCount = entries.filter(e => e.impact === 'high').length; const weekEntriesCount = entries.filter(e => { const d = new Date(e.date); const now = new Date(); return (now - d) / 86400000 <= 7; }).length; statsEl.innerHTML = '
' + entries.length + '
\u603b\u6761\u76ee\u6570
' + '
' + highCount + '
\u9ad8\u5f71\u54cd\u529b\u4e8b\u4ef6
' + '
' + weekEntriesCount + '
\u8fd1\u4e00\u5468\u65b0\u589e
' + '
' + competitors.length + '
\u8ddf\u8e2a\u7ade\u5bf9
'; // Filters let activeCategory = 'all'; const filtersEl = document.getElementById('filters'); filtersEl.innerHTML = '\u5168\u90e8' + categories.map(c => '' + c.icon + ' ' + c.name + '').join(''); filtersEl.addEventListener('click', e => { const chip = e.target.closest('.filter-chip'); if (!chip) return; filtersEl.querySelectorAll('.filter-chip').forEach(c => c.classList.remove('active')); chip.classList.add('active'); activeCategory = chip.dataset.cat; renderCurrentView(); }); function getFilteredEntries() { if (activeCategory === 'all') return entries; return entries.filter(e => e.category === activeCategory); } function getCategoryInfo(id) { return categories.find(c => c.id === id) || {}; } function getCompetitorInfo(id) { return competitors.find(c => c.id === id) || {}; } function renderCard(entry) { const cat = getCategoryInfo(entry.category); const competitorBadges = (entry.competitors || []).map(cid => { const comp = getCompetitorInfo(cid); return '' + (comp.shortName || cid) + ''; }).join(''); const keyPointsHtml = (entry.keyPoints || []).slice(0, 3).map(p => '
  • ' + translateText(p) + '
  • ').join(''); const tagsHtml = (entry.tags || []).map(t => '' + t + '').join(''); const displayTitle = getTitle(entry); const titleContent = entry.sourceUrl ? '' + displayTitle + '' : displayTitle; const notesHtml = entry.notes ? '
    \ud83d\udccc ' + entry.notes + '
    ' : ''; const displaySummary = getSummary(entry); const impactLabel = entry.impact === 'high' ? '\u9ad8\u5f71\u54cd' : entry.impact === 'medium' ? '\u4e2d\u5f71\u54cd' : '\u4f4e\u5f71\u54cd'; return '
    ' + '
    ' + '' + (cat.icon || '') + ' ' + (cat.name || '') + '' + '' + impactLabel + '' + '
    ' + (competitorBadges ? '
    ' + competitorBadges + '
    ' : '') + '

    ' + titleContent + '

    ' + '
    ' + displaySummary + '
    ' + (keyPointsHtml ? '' : '') + notesHtml + '' + '
    '; } function renderCards() { const grid = document.getElementById('cards-grid'); const filtered = getFilteredEntries().sort((a, b) => b.date.localeCompare(a.date)); grid.innerHTML = filtered.map(renderCard).join(''); } function renderTimeline() { const container = document.getElementById('timeline'); const filtered = getFilteredEntries().sort((a, b) => b.date.localeCompare(a.date)); const grouped = {}; filtered.forEach(e => { (grouped[e.date] = grouped[e.date] || []).push(e); }); container.innerHTML = Object.entries(grouped).map(([date, items]) => '
    ' + date + '
    ' + items.map(e => '
    ' + renderCard(e) + '
    ').join('') + '
    ' ).join(''); } function renderCompetitor() { const container = document.getElementById('competitor-view'); container.innerHTML = competitors.map(comp => { const compEntries = entries.filter(e => (e.competitors || []).includes(comp.id)) .sort((a, b) => b.date.localeCompare(a.date)); return '
    ' + '
    ' + '

    ' + comp.name + '

    ' + '' + compEntries.length + ' \u6761\u76f8\u5173\u8d44\u8baf' + '
    ' + '
    ' + (compEntries.map(renderCard).join('') || '

    \u6682\u65e0\u76f8\u5173\u8d44\u8baf

    ') + '
    ' + '
    '; }).join(''); } function renderReport() { const container = document.getElementById('report-view'); const now = new Date(); const weekAgo = new Date(now - 7 * 86400000); const weekArr = entries.filter(e => new Date(e.date) >= weekAgo).sort((a, b) => b.date.localeCompare(a.date)); const highImpact = weekArr.filter(e => e.impact === 'high'); const byCategory = {}; weekArr.forEach(e => { (byCategory[e.category] = byCategory[e.category] || []).push(e); }); let html = '

    \ud83d\udcc5 \u672c\u5468\u6982\u89c8 (' + weekAgo.toISOString().slice(0,10) + ' ~ ' + now.toISOString().slice(0,10) + ')

    ' + '

    \u672c\u5468\u5171\u65b0\u589e ' + weekArr.length + ' \u6761\u8d44\u8baf\uff0c\u5176\u4e2d\u9ad8\u5f71\u54cd\u529b\u4e8b\u4ef6 ' + highImpact.length + ' \u6761\u3002

    '; if (highImpact.length) { html += '

    \u26a0\ufe0f \u9ad8\u5f71\u54cd\u529b\u4e8b\u4ef6

    '; } html += '
    '; Object.entries(byCategory).forEach(([catId, items]) => { const cat = getCategoryInfo(catId); html += '

    ' + (cat.icon || '') + ' ' + (cat.name || catId) + '

    ' + '
    '; }); container.innerHTML = html; } // View switching const views = { cards: renderCards, timeline: renderTimeline, competitor: renderCompetitor, report: renderReport }; let currentView = 'cards'; function renderCurrentView() { views[currentView](); } document.getElementById('view-tabs').addEventListener('click', e => { const tab = e.target.closest('.tab'); if (!tab) return; document.querySelectorAll('.tab').forEach(t => t.classList.remove('active')); tab.classList.add('active'); const view = tab.dataset.view; document.querySelectorAll('.view-panel').forEach(p => p.classList.add('hidden')); document.getElementById('view-' + view).classList.remove('hidden'); currentView = view; renderCurrentView(); }); // Initial render renderCards(); })();