Simpler code for content enhancement

Also fixed some shortcodes not converted
This commit is contained in:
Lim Chee Aun 2022-12-13 20:15:02 +08:00
parent 19074844be
commit 3e80ee03f3
3 changed files with 69 additions and 80 deletions

View file

@ -475,7 +475,6 @@ a.card:hover {
margin: 8px 0; margin: 8px 0;
overflow: auto; overflow: auto;
width: 100%; width: 100%;
font-size: 90%;
border: 1px solid var(--outline-color); border: 1px solid var(--outline-color);
background: linear-gradient( background: linear-gradient(
to bottom right, to bottom right,
@ -484,6 +483,10 @@ a.card:hover {
); );
} }
.status .content p code {
color: var(--green-color);
}
/* MISC */ /* MISC */
.status-aside { .status-aside {

View file

@ -36,7 +36,7 @@
:root { :root {
--blue-color: CornflowerBlue; --blue-color: CornflowerBlue;
--purple-color: mediumpurple; --purple-color: mediumpurple;
--green-color: MediumSeaGreen; --green-color: limegreen;
--bg-color: #242526; --bg-color: #242526;
--bg-faded-color: #18191a; --bg-faded-color: #18191a;
--bg-blur-color: #0009; --bg-blur-color: #0009;
@ -187,6 +187,13 @@ select.plain {
background-color: transparent; background-color: transparent;
} }
pre code,
code {
font-size: 95%;
font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, Courier,
monospace;
}
@media (prefers-color-scheme: dark) { @media (prefers-color-scheme: dark) {
img, img,
video { video {

View file

@ -1,97 +1,61 @@
import emojifyText from './emojify-text'; import emojifyText from './emojify-text';
const fauxDiv = document.createElement('div');
export default (content, opts = {}) => { export default (content, opts = {}) => {
const { emojis, postEnhanceDOM = () => {} } = opts; const { emojis, postEnhanceDOM = () => {} } = opts;
let enhancedContent = content; let enhancedContent = content;
const dom = document.createElement('div'); const dom = document.createElement('div');
dom.innerHTML = enhancedContent; dom.innerHTML = enhancedContent;
// 1. Emojis // Add target="_blank" to all links with no target="_blank"
if (emojis) {
enhancedContent = emojifyText(enhancedContent, emojis);
}
// 2. Add target="_blank" to all links with no target="_blank"
// E.g. `note` in `account` // E.g. `note` in `account`
const links = Array.from(dom.querySelectorAll('a:not([target="_blank"])')); const links = Array.from(dom.querySelectorAll('a:not([target="_blank"])'));
links.forEach((link) => { links.forEach((link) => {
link.setAttribute('target', '_blank'); link.setAttribute('target', '_blank');
}); });
// 3. Code blocks // EMOJIS
// Check for <p> with markdown-like content "```" // ======
{ // Convert :shortcode: to <img />
const blocks = Array.from(dom.querySelectorAll('p')).filter((p) => let textNodes = extractTextNodes(dom);
/^```[^]+```$/g.test(p.innerText.trim()), textNodes.forEach((node) => {
); let html = node.nodeValue;
blocks.forEach((block) => { if (emojis) {
const pre = document.createElement('pre'); html = emojifyText(html, emojis);
const code = document.createElement('code'); }
const breaks = block.querySelectorAll('br'); fauxDiv.innerHTML = html;
breaks.forEach((br) => br.replaceWith('\n')); const nodes = Array.from(fauxDiv.childNodes);
code.innerHTML = block.innerText node.replaceWith(...nodes);
.trim() });
// .replace(/^```/g, '')
// .replace(/```$/g, '')
.replace(/^[\n\r]+/, '');
pre.appendChild(code);
block.replaceWith(pre);
});
}
// 4. Inline code // INLINE CODE
{ // ===========
// Get all text nodes in the DOM // Convert `code` to <code>code</code>
const textNodes = []; textNodes = extractTextNodes(dom);
const walk = document.createTreeWalker( textNodes.forEach((node) => {
dom, let html = node.nodeValue;
NodeFilter.SHOW_TEXT, if (/`[^`]+`/g.test(html)) {
null, html = html.replaceAll(/(`[^]+?`)/g, '<code>$1</code>');
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) { fauxDiv.innerHTML = html;
// - Split text nodes into array of text and DOM nodes const nodes = Array.from(fauxDiv.childNodes);
// - Replace markdown-like code syntax with <code> element node.replaceWith(...nodes);
// - Apply them all back to parent node });
textNodes.forEach((node) => {
const parent = node.parentNode; // CODE BLOCKS
const text = node.nodeValue; // ===========
const nodes = []; // Convert ```code``` to <pre><code>code</code></pre>
let i = 0; const blocks = Array.from(dom.querySelectorAll('p')).filter((p) =>
let j = 0; /^```[^]+```$/g.test(p.innerText.trim()),
let k = 0; );
while ((i = text.indexOf('`', j)) !== -1) { blocks.forEach((block) => {
if (i > j) { const pre = document.createElement('pre');
nodes.push(document.createTextNode(text.substring(j, i))); // Replace <br /> with newlines
} block.querySelectorAll('br').forEach((br) => br.replaceWith('\n'));
j = i + 1; pre.innerHTML = `<code>${block.innerText.trim()}</code>`;
if ((k = text.indexOf('`', j)) === -1) { block.replaceWith(pre);
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);
});
}
}
if (postEnhanceDOM) { if (postEnhanceDOM) {
postEnhanceDOM(dom); // mutate dom postEnhanceDOM(dom); // mutate dom
@ -101,3 +65,18 @@ export default (content, opts = {}) => {
return enhancedContent; return enhancedContent;
}; };
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;
}