diff --git a/Common/markdown2html.js b/Common/markdown2html.js index db1a4085..18e831bd 100644 --- a/Common/markdown2html.js +++ b/Common/markdown2html.js @@ -3,9 +3,36 @@ function markdownToHtml(text) { if (!text) return ""; - let html = text; + // Store code blocks and inline code to protect them from further processing + const codeBlocks = []; + const inlineCode = []; + let blockIndex = 0; + let inlineIndex = 0; - // Escape HTML entities first + // First, extract and replace code blocks with placeholders + let html = text.replace(/```([\s\S]*?)```/g, (match, code) => { + // Trim leading and trailing blank lines only + const trimmedCode = code.replace(/^\n+|\n+$/g, ''); + // Escape HTML entities in code + const escapedCode = trimmedCode.replace(/&/g, '&') + .replace(//g, '>'); + codeBlocks.push(`
${escapedCode}
`); + return `\x00CODEBLOCK${blockIndex++}\x00`; + }); + + // Extract and replace inline code + html = html.replace(/`([^`]+)`/g, (match, code) => { + // Escape HTML entities in code + const escapedCode = code.replace(/&/g, '&') + .replace(//g, '>'); + inlineCode.push(`${escapedCode}`); + return `\x00INLINECODE${inlineIndex++}\x00`; + }); + + // Now process everything else + // Escape HTML entities (but not in code blocks) html = html.replace(/&/g, '&') .replace(//g, '>'); @@ -15,7 +42,7 @@ function markdownToHtml(text) { html = html.replace(/^## (.*?)$/gm, '

$1

'); html = html.replace(/^# (.*?)$/gm, '

$1

'); - // Bold and italic + // Bold and italic (order matters!) html = html.replace(/\*\*\*(.*?)\*\*\*/g, '$1'); html = html.replace(/\*\*(.*?)\*\*/g, '$1'); html = html.replace(/\*(.*?)\*/g, '$1'); @@ -23,10 +50,6 @@ function markdownToHtml(text) { html = html.replace(/__(.*?)__/g, '$1'); html = html.replace(/_(.*?)_/g, '$1'); - // Code blocks - html = html.replace(/```([\s\S]*?)```/g, '
$1
'); - html = html.replace(/`(.*?)`/g, '$1'); - // Links html = html.replace(/\[([^\]]+)\]\(([^)]+)\)/g, '$1'); @@ -43,8 +66,16 @@ function markdownToHtml(text) { // Detect plain URLs and wrap them in anchor tags (but not inside existing or markdown links) html = html.replace(/(^|[^"'>])((https?|file):\/\/[^\s<]+)/g, '$1$2'); + // Restore code blocks and inline code BEFORE line break processing + html = html.replace(/\x00CODEBLOCK(\d+)\x00/g, (match, index) => { + return codeBlocks[parseInt(index)]; + }); - // Line breaks + html = html.replace(/\x00INLINECODE(\d+)\x00/g, (match, index) => { + return inlineCode[parseInt(index)]; + }); + + // Line breaks (after code blocks are restored) html = html.replace(/\n\n/g, '

'); html = html.replace(/\n/g, '
'); @@ -53,5 +84,22 @@ function markdownToHtml(text) { html = '

' + html + '

'; } + // Clean up the final HTML + // Remove
tags immediately before block elements + html = html.replace(/\s*
/g, '
');
+    html = html.replace(/\s*
    /g, '
      '); + html = html.replace(/\s*/g, ''); + + // Remove empty paragraphs + html = html.replace(/

      \s*<\/p>/g, ''); + html = html.replace(/

      \s*\s*<\/p>/g, ''); + + // Remove excessive line breaks + html = html.replace(/(){3,}/g, '

      '); // Max 2 consecutive line breaks + html = html.replace(/(<\/p>)\s*(

      )/g, '$1$2'); // Remove whitespace between paragraphs + + // Remove leading/trailing whitespace + html = html.trim(); + return html; } \ No newline at end of file