This repository has been archived on 2023-03-18. You can view files and clone it, but cannot push or open issues or pull requests.
osr-discourse-src/app/assets/javascripts/discourse/lib/highlight-html.js

85 lines
1.9 KiB
JavaScript

import { makeArray } from "discourse-common/lib/helpers";
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",
matchCase: false
};
settings = Object.assign({}, settings, opts);
words = makeArray(words)
.filter(Boolean)
.map(word => word.replace(/[-\/\\^$*+?.()|[\]{}]/g, "\\$&"));
if (!words.length) return node;
const pattern = `(${words.join(" ")})`;
let flag;
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"
};
settings = Object.assign({}, settings, opts);
document
.querySelectorAll(`${settings.nodeName}.${settings.className}`)
.forEach(element => {
const parentNode = element.parentNode;
parentNode.replaceChild(element.firstChild, element);
parentNode.normalize();
});
}