Files
ewoooc/web/static/js/ewoooc-base.js
OoO ebc6f2cfe5
Some checks failed
CD Pipeline / deploy (push) Failing after 27s
perf: 外部化共用底板資源
2026-05-18 00:31:21 +08:00

99 lines
4.2 KiB
JavaScript

/* 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;
async function refresh() {
try {
const r = await fetch('/observability/api/health_indicator', { credentials: 'same-origin' });
if (!r.ok) return;
const d = await r.json();
if (!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');
}
} catch (e) {}
}
refresh();
setInterval(refresh, 60000);
})();