mirror of
https://github.com/discourse/discourse.git
synced 2025-05-24 01:14:12 +08:00
94 lines
2.1 KiB
JavaScript
94 lines
2.1 KiB
JavaScript
function highlight(node, pattern, nodeName, className) {
|
|
if (
|
|
![Node.ELEMENT_NODE, Node.TEXT_NODE].includes(node.nodeType) ||
|
|
["SCRIPT", "STYLE"].includes(node.tagName) ||
|
|
(node.tagName === nodeName && node.className === className)
|
|
) {
|
|
return 0;
|
|
}
|
|
|
|
if (node.nodeType === Node.ELEMENT_NODE && node.childNodes) {
|
|
for (let i = 0; i < node.childNodes.length; i++) {
|
|
i += highlight(node.childNodes[i], pattern, nodeName, className);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
if (node.nodeType === Node.TEXT_NODE) {
|
|
const match = node.data.match(pattern);
|
|
|
|
if (!match) {
|
|
return 0;
|
|
}
|
|
|
|
const element = document.createElement(nodeName);
|
|
element.className = className;
|
|
element.innerText = match[0];
|
|
const matchNode = node.splitText(match.index);
|
|
matchNode.splitText(match[0].length);
|
|
matchNode.parentNode.replaceChild(element, matchNode);
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
export default function(node, words, opts = {}) {
|
|
let settings = {
|
|
nodeName: "span",
|
|
className: "highlighted",
|
|
wholeWord: false,
|
|
matchCase: false
|
|
};
|
|
|
|
Object.assign(settings, opts);
|
|
words = typeof words === "string" ? [words] : words;
|
|
words = words
|
|
.filter(Boolean)
|
|
.map(word => word.replace(/[-\/\\^$*+?.()|[\]{}]/g, "\\$&"));
|
|
|
|
if (!words.length) return node;
|
|
|
|
let pattern = `(${words.join("|")})`;
|
|
let flag;
|
|
|
|
if (settings.wholeWord) {
|
|
const hasUnicode = words.some(word => {
|
|
return !word.match(new RegExp(`\b${word}\b`));
|
|
});
|
|
pattern = hasUnicode
|
|
? `(?<=[\\s,.:;"']|^)${pattern}(?=[\\s,.:;"']|$)`
|
|
: `\b${pattern}\b`;
|
|
}
|
|
|
|
if (settings.matchCase) {
|
|
flag = "i";
|
|
}
|
|
|
|
highlight(
|
|
node,
|
|
new RegExp(pattern, flag),
|
|
settings.nodeName.toUpperCase(),
|
|
settings.className
|
|
);
|
|
|
|
return node;
|
|
}
|
|
|
|
export function unhighlightHTML(opts = {}) {
|
|
let settings = {
|
|
nodeName: "span",
|
|
className: "highlighted"
|
|
};
|
|
|
|
Object.assign(settings, opts);
|
|
|
|
document
|
|
.querySelectorAll(`${settings.nodeName}.${settings.className}`)
|
|
.forEach(e => {
|
|
const parentNode = e.parentNode;
|
|
parentNode.replaceChild(e.firstChild, e);
|
|
parentNode.normalize();
|
|
});
|
|
}
|