(function() { console.log("loaded amsk-fix-tm"); // 正则:匹配 “Arthrosamid” (整词、不分大小写),且后面没 ® 或 ® const RX = /\b(Arthrosamid)\b(?!\s*(?:®|®))/gi; const ATTRS = ['title', 'alt', 'placeholder', 'aria-label', 'data-tooltip']; // 简易 throttle:fn 最多每 interval 毫秒执行一次 function throttle(fn, interval) { let last = 0, timer = null; return function(...args) { const now = Date.now(); const remaining = interval - (now - last); if (remaining <= 0) { clearTimeout(timer); timer = null; last = now; fn.apply(this, args); } else if (!timer) { timer = setTimeout(() => { last = Date.now(); timer = null; fn.apply(this, args); }, remaining); } }; } // 给 el 或 el subtree 中的文本节点加 ® function replaceInTextNodes(root) { const walker = document.createTreeWalker(root, NodeFilter.SHOW_TEXT, null, false); let node; while (node = walker.nextNode()) { const parent = node.parentNode; if (parent && parent.dataset.arthroChecked) continue; const orig = node.nodeValue; const replaced = orig.replace(RX, (m, p1) => p1 + '®'); if (replaced !== orig) { node.nodeValue = replaced; } } } // 给单个元素属性加 ® function replaceInAttributes(el) { if (el.dataset.arthroChecked) return; let changed = false; ATTRS.forEach(attr => { if (!el.hasAttribute(attr)) return; const val = el.getAttribute(attr); const newVal = val.replace(RX, (m, p1) => p1 + '®'); if (newVal !== val) { el.setAttribute(attr, newVal); changed = true; } }); if (changed) { el.dataset.arthroChecked = '1'; } } // 对 root (元素节点或 document.body)做批量处理,并打标记 function processRoot(root) { if (root.nodeType === 1) { replaceInAttributes(root); root.dataset.arthroChecked = '1'; } replaceInTextNodes(root); if (root.querySelectorAll) { // 批量处理子元素属性 ATTRS.forEach(attr => { root.querySelectorAll('[' + attr + ']').forEach(el => replaceInAttributes(el)); }); } } // 初次全页扫描(可拆帧以防大页面阻塞,这里简单一次跑完) function initialScan() { processRoot(document.body); } window.initialScan = initialScan; if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', initialScan); } else { initialScan(); } // 用节流合并频繁的 MutationObserver 回调 const pending = new Set(); function flushPending() { pending.forEach(node => processRoot(node)); pending.clear(); } const throttledFlush = throttle(flushPending, 100); // 每 100ms 最多执行一次 // 观察新增节点和属性变化 const observer = new MutationObserver(muts => { muts.forEach(m => { if (m.type === 'childList') { m.addedNodes.forEach(n => { if (n.nodeType === 1 || n.nodeType === 3) { pending.add(n.nodeType === 3 ? n.parentNode : n); } }); } else if (m.type === 'attributes' && ATTRS.includes(m.attributeName)) { pending.add(m.target); } }); throttledFlush(); }); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ATTRS }); })();