2022-12-10 12:14:48 +03:00
|
|
|
import emojifyText from './emojify-text';
|
|
|
|
|
2022-12-13 15:15:02 +03:00
|
|
|
const fauxDiv = document.createElement('div');
|
|
|
|
|
2022-12-16 08:27:04 +03:00
|
|
|
function enhanceContent(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-13 15:15:02 +03:00
|
|
|
// Add target="_blank" to all links with no target="_blank"
|
2022-12-10 14:16:11 +03:00
|
|
|
// E.g. `note` in `account`
|
|
|
|
const links = Array.from(dom.querySelectorAll('a:not([target="_blank"])'));
|
|
|
|
links.forEach((link) => {
|
|
|
|
link.setAttribute('target', '_blank');
|
|
|
|
});
|
|
|
|
|
2022-12-13 15:15:02 +03:00
|
|
|
// EMOJIS
|
|
|
|
// ======
|
|
|
|
// Convert :shortcode: to <img />
|
|
|
|
let textNodes = extractTextNodes(dom);
|
|
|
|
textNodes.forEach((node) => {
|
|
|
|
let html = node.nodeValue;
|
|
|
|
if (emojis) {
|
|
|
|
html = emojifyText(html, emojis);
|
2022-12-12 16:51:59 +03:00
|
|
|
}
|
2022-12-13 15:15:02 +03:00
|
|
|
fauxDiv.innerHTML = html;
|
|
|
|
const nodes = Array.from(fauxDiv.childNodes);
|
|
|
|
node.replaceWith(...nodes);
|
|
|
|
});
|
|
|
|
|
|
|
|
// INLINE CODE
|
|
|
|
// ===========
|
|
|
|
// Convert `code` to <code>code</code>
|
|
|
|
textNodes = extractTextNodes(dom);
|
|
|
|
textNodes.forEach((node) => {
|
|
|
|
let html = node.nodeValue;
|
|
|
|
if (/`[^`]+`/g.test(html)) {
|
|
|
|
html = html.replaceAll(/(`[^]+?`)/g, '<code>$1</code>');
|
2022-12-12 16:51:59 +03:00
|
|
|
}
|
2022-12-13 15:15:02 +03:00
|
|
|
fauxDiv.innerHTML = html;
|
|
|
|
const nodes = Array.from(fauxDiv.childNodes);
|
|
|
|
node.replaceWith(...nodes);
|
|
|
|
});
|
|
|
|
|
|
|
|
// CODE BLOCKS
|
|
|
|
// ===========
|
|
|
|
// Convert ```code``` to <pre><code>code</code></pre>
|
|
|
|
const blocks = Array.from(dom.querySelectorAll('p')).filter((p) =>
|
|
|
|
/^```[^]+```$/g.test(p.innerText.trim()),
|
|
|
|
);
|
|
|
|
blocks.forEach((block) => {
|
|
|
|
const pre = document.createElement('pre');
|
|
|
|
// Replace <br /> with newlines
|
|
|
|
block.querySelectorAll('br').forEach((br) => br.replaceWith('\n'));
|
|
|
|
pre.innerHTML = `<code>${block.innerText.trim()}</code>`;
|
|
|
|
block.replaceWith(pre);
|
|
|
|
});
|
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;
|
2022-12-16 08:27:04 +03:00
|
|
|
}
|
2022-12-13 15:15:02 +03:00
|
|
|
|
|
|
|
function extractTextNodes(dom) {
|
|
|
|
const textNodes = [];
|
|
|
|
const walk = document.createTreeWalker(
|
|
|
|
dom,
|
|
|
|
NodeFilter.SHOW_TEXT,
|
|
|
|
null,
|
|
|
|
false,
|
|
|
|
);
|
|
|
|
let node;
|
|
|
|
while ((node = walk.nextNode())) {
|
|
|
|
textNodes.push(node);
|
|
|
|
}
|
|
|
|
return textNodes;
|
|
|
|
}
|
2022-12-16 08:27:04 +03:00
|
|
|
|
|
|
|
export default enhanceContent;
|