new functions and fixes

This commit is contained in:
Mateusz Gruszczyński
2026-08-06 09:43:49 +02:00
parent 7989a873e7
commit ce368cf3fd
8 changed files with 88 additions and 24 deletions
+27 -5
View File
@@ -152,7 +152,10 @@ function inline(value) {
});
html = html.replace(/\[([^\]]+)\]\(([^\s)]+)(?:\s+["']([^"']*)["'])?\)/g, (_, label, url, title) => {
const titleAttr = title ? ` title="${escapeHtml(title)}"` : "";
return stash(`<a href="${safeUrl(url)}" target="_blank" rel="noopener noreferrer" referrerpolicy="no-referrer"${titleAttr}>${label}</a>`);
const navigationAttrs = String(url).trim().startsWith("#")
? ""
: ' target="_blank" rel="noopener noreferrer" referrerpolicy="no-referrer"';
return stash(`<a href="${safeUrl(url)}"${navigationAttrs}${titleAttr}>${label}</a>`);
});
html = html.replace(/\[\^([^\]\s]+)\]/g, (_, id) => stash(`<sup class="footnote-ref"><a href="#fn-${escapeHtml(id)}" id="fnref-${escapeHtml(id)}">?</a></sup>`));
@@ -335,6 +338,26 @@ function collectHeadings(lines) {
return headings;
}
function tableOfContentsTree(headings) {
const roots = [];
const stack = [];
headings.forEach(item => {
while (stack.length && item.level <= stack[stack.length - 1].level) stack.pop();
const node = { ...item, children: [] };
const parent = stack[stack.length - 1];
(parent ? parent.children : roots).push(node);
stack.push(node);
});
return roots;
}
function renderTableOfContentsList(nodes) {
if (!nodes.length) return "";
return `<ul>${nodes.map(node => `<li class="toc-level-${node.level}"><a href="#${escapeHtml(node.id)}">${inline(node.text)}</a>${renderTableOfContentsList(node.children)}</li>`).join("")}</ul>`;
}
export function alignPreviewLineNumbers(root) {
if (!root) return;
@@ -454,10 +477,9 @@ export function renderMarkdown(source, lineOffset = 0) {
if (/^\s*\[TOC\]\s*$/i.test(line)) {
closeList();
if (headings.length) {
html += `<nav class="markdown-toc preview-source-line" data-source-line="${index + lineOffset + 1}" aria-label="Table of contents"><ol>`;
headings.forEach(item => html += `<li class="toc-level-${item.level}"><a href="#${escapeHtml(item.id)}">${inline(item.text)}</a></li>`);
html += `</ol></nav>`;
const tocHeadings = headings.filter(item => item.index > index);
if (tocHeadings.length) {
html += `<nav class="markdown-toc preview-source-line" data-source-line="${index + lineOffset + 1}" aria-label="Table of contents">${renderTableOfContentsList(tableOfContentsTree(tocHeadings))}</nav>`;
}
continue;
}