diff --git a/content.js b/content.js
index 9760e16..6f48de7 100644
--- a/content.js
+++ b/content.js
@@ -3,51 +3,77 @@ function escapeRegex(s) {
}
function highlightWords(lists) {
- const textNodes = [];
- const walker = document.createTreeWalker(document.body, NodeFilter.SHOW_TEXT, {
- acceptNode: node => {
- if (node.parentNode && ['SCRIPT', 'STYLE', 'NOSCRIPT', 'IFRAME'].includes(node.parentNode.nodeName)) return NodeFilter.FILTER_REJECT;
- if (!node.nodeValue.trim()) return NodeFilter.FILTER_SKIP;
- return NodeFilter.FILTER_ACCEPT;
- }
- });
-
- while (walker.nextNode()) textNodes.push(walker.currentNode);
-
- const activeWords = [];
-
- for (const list of lists) {
- if (!list.active) continue;
- for (const word of list.words) {
- if (!word.active) continue;
- activeWords.push({
- text: word.wordStr,
- background: word.background || list.background,
- foreground: word.foreground || list.foreground
- });
- }
- }
-
- if (activeWords.length === 0) return;
-
- const wordMap = new Map();
- for (const word of activeWords) wordMap.set(word.text.toLowerCase(), word);
-
- const pattern = new RegExp(`(${Array.from(wordMap.keys()).map(escapeRegex).join('|')})`, 'gi');
-
- for (const node of textNodes) {
- if (!pattern.test(node.nodeValue)) continue;
-
- const span = document.createElement('span');
- span.innerHTML = node.nodeValue.replace(pattern, match => {
- const word = wordMap.get(match.toLowerCase()) || { background: '#ffff00', foreground: '#000000' };
- return `${match}`;
+ const processNodes = () => {
+ const textNodes = [];
+ const walker = document.createTreeWalker(document.body, NodeFilter.SHOW_TEXT, {
+ acceptNode: node => {
+ if (node.parentNode && node.parentNode.nodeName === 'MARK') return NodeFilter.FILTER_REJECT;
+ if (node.parentNode && ['SCRIPT', 'STYLE', 'NOSCRIPT', 'IFRAME'].includes(node.parentNode.nodeName)) return NodeFilter.FILTER_REJECT;
+ if (!node.nodeValue.trim()) return NodeFilter.FILTER_SKIP;
+ return NodeFilter.FILTER_ACCEPT;
+ }
});
- node.parentNode.replaceChild(span, node);
- }
+ while (walker.nextNode()) textNodes.push(walker.currentNode);
+
+ const activeWords = [];
+
+ for (const list of lists) {
+ if (!list.active) continue;
+ for (const word of list.words) {
+ if (!word.active) continue;
+ activeWords.push({
+ text: word.wordStr,
+ background: word.background || list.background,
+ foreground: word.foreground || list.foreground
+ });
+ }
+ }
+
+ if (activeWords.length === 0) return;
+
+ const wordMap = new Map();
+ for (const word of activeWords) wordMap.set(word.text.toLowerCase(), word);
+
+ const pattern = new RegExp(`(${Array.from(wordMap.keys()).map(escapeRegex).join('|')})`, 'gi');
+
+ for (const node of textNodes) {
+ if (!pattern.test(node.nodeValue)) continue;
+
+ const span = document.createElement('span');
+ span.innerHTML = node.nodeValue.replace(pattern, match => {
+ const word = wordMap.get(match.toLowerCase()) || { background: '#ffff00', foreground: '#000000' };
+ return `${match}`;
+ });
+
+ node.parentNode.replaceChild(span, node);
+ }
+ };
+
+ const debouncedProcessNodes = debounce(processNodes, 300);
+
+ debouncedProcessNodes();
+
+ const observer = new MutationObserver(debouncedProcessNodes);
+ observer.observe(document.body, {
+ childList: true,
+ subtree: true,
+ characterData: true
+ });
+
+ window.addEventListener('scroll', debouncedProcessNodes);
+}
+
+// Debounce helper function
+function debounce(func, wait) {
+ let timeout;
+ return function () {
+ const context = this, args = arguments;
+ clearTimeout(timeout);
+ timeout = setTimeout(() => func.apply(context, args), wait);
+ };
}
chrome.storage.local.get("lists", ({ lists }) => {
if (Array.isArray(lists)) highlightWords(lists);
-});
+});
\ No newline at end of file