Highlight Words
目前為
此腳本不應該直接安裝,它是一個供其他腳本使用的函式庫。欲使用本函式庫,請在腳本 metadata 寫上: // @require https://update.cn-greasyfork.org/scripts/535935/1588724/highlightWords.js
function escapeRegex(string) {
return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
}
function highlightWords(words, highlightClass = 'highlight') {
if (!words || words.length === 0) return;
const regex = new RegExp('\\b(' + words.map(escapeRegex).join('|') + ')\\b', 'gi');
const xpath = `//text()[not(ancestor::script) and not(ancestor::style) and not(ancestor::*[contains(concat(" ", normalize-space(@class), " "), " ${highlightClass} ")])]`;
const textNodes = document.evaluate(xpath, document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
for (let i = 0; i < textNodes.snapshotLength; i++) {
const textNode = textNodes.snapshotItem(i);
const text = textNode.nodeValue;
const matches = [...text.matchAll(regex)];
if (matches.length > 0) {
const fragment = document.createDocumentFragment();
let lastIndex = 0;
for (const match of matches) {
const offset = match.index;
if (offset > lastIndex) {
fragment.appendChild(document.createTextNode(text.slice(lastIndex, offset)));
}
const span = document.createElement('span');
span.className = highlightClass;
span.textContent = match[0];
fragment.appendChild(span);
lastIndex = offset + match[0].length;
}
if (lastIndex < text.length) {
fragment.appendChild(document.createTextNode(text.slice(lastIndex)));
}
textNode.parentNode.replaceChild(fragment, textNode);
}
}
}