mirror of
https://github.com/SPLURT-Station/S.P.L.U.R.T-Station-13.git
synced 2025-12-10 18:02:57 +00:00
129 lines
3.2 KiB
JavaScript
129 lines
3.2 KiB
JavaScript
/**
|
|
* @file
|
|
* @copyright 2020 Aleksej Komarov
|
|
* @license MIT
|
|
*/
|
|
|
|
/**
|
|
* Replaces text matching a regular expression with a custom node.
|
|
*/
|
|
export const replaceInTextNode = (regex, createNode) => node => {
|
|
const text = node.textContent;
|
|
const textLength = text.length;
|
|
let match;
|
|
let lastIndex = 0;
|
|
let fragment;
|
|
let n = 0;
|
|
// eslint-disable-next-line no-cond-assign
|
|
while (match = regex.exec(text)) {
|
|
n += 1;
|
|
// Lazy init fragment
|
|
if (!fragment) {
|
|
fragment = document.createDocumentFragment();
|
|
}
|
|
const matchText = match[0];
|
|
const matchLength = matchText.length;
|
|
const matchIndex = match.index;
|
|
// Insert previous unmatched chunk
|
|
if (lastIndex < matchIndex) {
|
|
fragment.appendChild(document.createTextNode(
|
|
text.substring(lastIndex, matchIndex)));
|
|
}
|
|
lastIndex = matchIndex + matchLength;
|
|
// Create a wrapper node
|
|
fragment.appendChild(createNode(matchText));
|
|
}
|
|
if (fragment) {
|
|
// Insert the remaining unmatched chunk
|
|
if (lastIndex < textLength) {
|
|
fragment.appendChild(document.createTextNode(
|
|
text.substring(lastIndex, textLength)));
|
|
}
|
|
// Commit the fragment
|
|
node.parentNode.replaceChild(fragment, node);
|
|
}
|
|
return n;
|
|
};
|
|
|
|
|
|
// Highlight
|
|
// --------------------------------------------------------
|
|
|
|
/**
|
|
* Default highlight node.
|
|
*/
|
|
const createHighlightNode = text => {
|
|
const node = document.createElement('span');
|
|
node.setAttribute('style',
|
|
'background-color:#fd4;color:#000');
|
|
node.textContent = text;
|
|
return node;
|
|
};
|
|
|
|
/**
|
|
* Highlights the text in the node based on the provided regular expression.
|
|
*
|
|
* @param {Node} node Node which you want to process
|
|
* @param {RegExp} regex Regular expression to highlight
|
|
* @param {(text: string) => Node} createNode Highlight node creator
|
|
* @returns {number} Number of matches
|
|
*/
|
|
export const highlightNode = (
|
|
node,
|
|
regex,
|
|
createNode = createHighlightNode,
|
|
) => {
|
|
if (!createNode) {
|
|
createNode = createHighlightNode;
|
|
}
|
|
let n = 0;
|
|
const childNodes = node.childNodes;
|
|
for (let i = 0; i < childNodes.length; i++) {
|
|
const node = childNodes[i];
|
|
// Is a text node
|
|
if (node.nodeType === 3) {
|
|
n += replaceInTextNode(regex, createNode)(node);
|
|
}
|
|
else {
|
|
n += highlightNode(node, regex, createNode);
|
|
}
|
|
}
|
|
return n;
|
|
};
|
|
|
|
|
|
// Linkify
|
|
// --------------------------------------------------------
|
|
|
|
const URL_REGEX = /(?:(?:https?:\/\/)|(?:www\.))(?:[^ ]*?\.[^ ]*?)+[-A-Za-z0-9+&@#/%?=~_|$!:,.;()]+/ig;
|
|
|
|
/**
|
|
* Highlights the text in the node based on the provided regular expression.
|
|
*
|
|
* @param {Node} node Node which you want to process
|
|
* @returns {number} Number of matches
|
|
*/
|
|
export const linkifyNode = node => {
|
|
let n = 0;
|
|
const childNodes = node.childNodes;
|
|
for (let i = 0; i < childNodes.length; i++) {
|
|
const node = childNodes[i];
|
|
const tag = String(node.nodeName).toLowerCase();
|
|
// Is a text node
|
|
if (node.nodeType === 3) {
|
|
n += linkifyTextNode(node);
|
|
}
|
|
else if (tag !== 'a') {
|
|
n += linkifyNode(node);
|
|
}
|
|
}
|
|
return n;
|
|
};
|
|
|
|
const linkifyTextNode = replaceInTextNode(URL_REGEX, text => {
|
|
const node = document.createElement('a');
|
|
node.href = text;
|
|
node.textContent = text;
|
|
return node;
|
|
});
|