2022-12-10 12:14:48 +03:00
|
|
|
import emojifyText from './emojify-text';
|
|
|
|
|
2022-12-10 14:16:11 +03:00
|
|
|
export default (content, opts = {}) => {
|
2022-12-11 04:28:02 +03:00
|
|
|
const { emojis, postEnhanceDOM = () => {} } = opts;
|
2022-12-10 12:14:48 +03:00
|
|
|
let enhancedContent = content;
|
2022-12-10 14:16:11 +03:00
|
|
|
const dom = document.createElement('div');
|
|
|
|
dom.innerHTML = enhancedContent;
|
2022-12-10 12:14:48 +03:00
|
|
|
|
2022-12-10 14:16:11 +03:00
|
|
|
// 1. Emojis
|
2022-12-10 12:14:48 +03:00
|
|
|
if (emojis) {
|
|
|
|
enhancedContent = emojifyText(enhancedContent, emojis);
|
|
|
|
}
|
|
|
|
|
2022-12-10 14:16:11 +03:00
|
|
|
// 2. Add target="_blank" to all links with no target="_blank"
|
|
|
|
// E.g. `note` in `account`
|
|
|
|
const links = Array.from(dom.querySelectorAll('a:not([target="_blank"])'));
|
|
|
|
links.forEach((link) => {
|
|
|
|
link.setAttribute('target', '_blank');
|
|
|
|
});
|
|
|
|
|
|
|
|
// 3. Code blocks
|
2022-12-10 12:14:48 +03:00
|
|
|
// Check for <p> with markdown-like content "```"
|
2022-12-12 16:51:59 +03:00
|
|
|
{
|
|
|
|
const blocks = Array.from(dom.querySelectorAll('p')).filter((p) =>
|
|
|
|
/^```[^]+```$/g.test(p.innerText.trim()),
|
|
|
|
);
|
|
|
|
blocks.forEach((block) => {
|
|
|
|
const pre = document.createElement('pre');
|
|
|
|
const code = document.createElement('code');
|
|
|
|
const breaks = block.querySelectorAll('br');
|
|
|
|
breaks.forEach((br) => br.replaceWith('\n'));
|
|
|
|
code.innerHTML = block.innerText
|
|
|
|
.trim()
|
|
|
|
// .replace(/^```/g, '')
|
|
|
|
// .replace(/```$/g, '')
|
|
|
|
.replace(/^[\n\r]+/, '');
|
|
|
|
pre.appendChild(code);
|
|
|
|
block.replaceWith(pre);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
// 4. Inline code
|
|
|
|
{
|
|
|
|
// Get all text nodes in the DOM
|
|
|
|
const textNodes = [];
|
|
|
|
const walk = document.createTreeWalker(
|
|
|
|
dom,
|
|
|
|
NodeFilter.SHOW_TEXT,
|
|
|
|
null,
|
|
|
|
false,
|
|
|
|
);
|
|
|
|
let node;
|
|
|
|
while ((node = walk.nextNode())) {
|
|
|
|
// Only get text that contains markdown-like code syntax
|
|
|
|
if (/`[^]+`/g.test(node.nodeValue)) {
|
|
|
|
textNodes.push(node);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (textNodes.length) {
|
|
|
|
// - Split text nodes into array of text and DOM nodes
|
|
|
|
// - Replace markdown-like code syntax with <code> element
|
|
|
|
// - Apply them all back to parent node
|
|
|
|
textNodes.forEach((node) => {
|
|
|
|
const parent = node.parentNode;
|
|
|
|
const text = node.nodeValue;
|
|
|
|
const nodes = [];
|
|
|
|
let i = 0;
|
|
|
|
let j = 0;
|
|
|
|
let k = 0;
|
|
|
|
while ((i = text.indexOf('`', j)) !== -1) {
|
|
|
|
if (i > j) {
|
|
|
|
nodes.push(document.createTextNode(text.substring(j, i)));
|
|
|
|
}
|
|
|
|
j = i + 1;
|
|
|
|
if ((k = text.indexOf('`', j)) === -1) {
|
|
|
|
k = j;
|
|
|
|
}
|
|
|
|
if (j < k) {
|
|
|
|
const code = document.createElement('code');
|
|
|
|
code.appendChild(document.createTextNode(text.substring(j, k)));
|
|
|
|
nodes.push(document.createTextNode('`'));
|
|
|
|
nodes.push(code);
|
|
|
|
nodes.push(document.createTextNode('`'));
|
|
|
|
}
|
|
|
|
j = k + 1;
|
|
|
|
}
|
|
|
|
if (j < text.length) {
|
|
|
|
nodes.push(document.createTextNode(text.substring(j)));
|
|
|
|
}
|
|
|
|
nodes.forEach((n) => parent.insertBefore(n, node));
|
|
|
|
parent.removeChild(node);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
2022-12-10 12:14:48 +03:00
|
|
|
|
2022-12-11 04:28:02 +03:00
|
|
|
if (postEnhanceDOM) {
|
|
|
|
postEnhanceDOM(dom); // mutate dom
|
|
|
|
}
|
|
|
|
|
2022-12-10 14:16:11 +03:00
|
|
|
enhancedContent = dom.innerHTML;
|
2022-12-11 04:28:02 +03:00
|
|
|
|
2022-12-10 12:14:48 +03:00
|
|
|
return enhancedContent;
|
|
|
|
};
|