/* EwoooC base interactions extracted from templates/ewoooc_base.html. */ (function () { if (window.__momoLinkGuardInstalled) return; window.__momoLinkGuardInstalled = true; const MOMO_CODE_RE = /^[A-Za-z0-9_-]{4,}$/; function toText(value) { return value == null ? '' : String(value); } function isLikelyMomoCode(value) { const cleaned = toText(value).trim(); if (!cleaned) return false; const lowered = cleaned.toLowerCase(); if (['nan', 'none', 'null', 'undefined'].includes(lowered)) return false; if (lowered.startsWith('momo_') || lowered.startsWith('manual_') || lowered.startsWith('pchome_')) return false; return MOMO_CODE_RE.test(cleaned); } function extractIcode(url) { const target = toText(url).trim(); if (!target) return ''; try { const parsed = new URL(target, location.origin); return toText(parsed.searchParams.get('i_code')).trim(); } catch (error) { const match = /[?&]i_code=([^&#]+)/i.exec(target); return match ? decodeURIComponent(match[1] || '').trim() : ''; } } function buildSafeMomoUrl(iCode) { const cleaned = toText(iCode).trim(); if (!isLikelyMomoCode(cleaned)) return ''; return `https://www.momoshop.com.tw/goods/GoodsDetail.jsp?i_code=${encodeURIComponent(cleaned)}`; } document.addEventListener('click', function (event) { const link = event.target.closest ? event.target.closest('a.momo-tracked-link') : null; if (!link) return; const href = toText(link.getAttribute('href')).trim(); const original = toText(link.dataset && link.dataset.momoOriginalUrl).trim(); const iCode = toText(link.dataset && (link.dataset.trackIcode || link.dataset.trackProductId)).trim() || extractIcode(original) || extractIcode(href); const safeUrl = buildSafeMomoUrl(iCode); if (safeUrl && (!href || href === '#' || /ec404/i.test(href) || /ec404/i.test(original))) { event.preventDefault(); link.setAttribute('href', safeUrl); window.open(safeUrl, link.getAttribute('target') || '_self', 'noopener,noreferrer'); } }, true); })(); (function () { const csrfToken = document.querySelector('meta[name="csrf-token"]')?.getAttribute('content'); window.fetchWithCSRF = (url, options = {}) => { options.headers = { ...options.headers, 'X-CSRFToken': csrfToken }; return fetch(url, options); }; })(); (function () { const shell = document.getElementById('momo-shell'); const toggle = document.querySelector('[data-momo-sidebar-toggle]'); const close = document.querySelector('[data-momo-sidebar-close]'); if (!shell || !toggle) return; toggle.addEventListener('click', () => shell.classList.toggle('is-sidebar-open')); if (close) close.addEventListener('click', () => shell.classList.remove('is-sidebar-open')); })(); (function() { const link = document.getElementById('momo-obs-link'); const badge = document.getElementById('momo-obs-badge'); if (!link || !badge) return; const cacheKey = 'momoObsHealthIndicator:v1'; const cacheTtlMs = 60000; function applyIndicator(d) { if (!d || !d.ok) return; link.title = d.tooltip || 'AI 觀測台'; if (d.alert_count > 0) { badge.textContent = d.alert_count; badge.hidden = false; link.classList.add('is-alert'); } else { badge.hidden = true; link.classList.remove('is-alert'); } } function readCachedIndicator() { try { const cached = JSON.parse(sessionStorage.getItem(cacheKey) || 'null'); if (!cached || !cached.data || Date.now() - cached.ts > cacheTtlMs) return null; return cached.data; } catch (e) { return null; } } function writeCachedIndicator(data) { try { sessionStorage.setItem(cacheKey, JSON.stringify({ ts: Date.now(), data })); } catch (e) {} } async function refresh(useCache = true) { if (useCache) { const cached = readCachedIndicator(); if (cached) { applyIndicator(cached); return; } } const controller = new AbortController(); const timer = setTimeout(() => controller.abort(), 2500); try { const r = await fetch('/observability/api/health_indicator', { credentials: 'same-origin', signal: controller.signal, }); if (!r.ok) return; const d = await r.json(); writeCachedIndicator(d); applyIndicator(d); } catch (e) { } finally { clearTimeout(timer); } } refresh(); setInterval(() => refresh(false), 60000); })();