quikdown 1.2.7 → 1.2.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. package/README.md +9 -4
  2. package/dist/quikdown.cjs +496 -243
  3. package/dist/quikdown.dark.css +1 -1
  4. package/dist/quikdown.esm.js +496 -243
  5. package/dist/quikdown.esm.min.js +2 -2
  6. package/dist/quikdown.esm.min.js.gz +0 -0
  7. package/dist/quikdown.esm.min.js.map +1 -1
  8. package/dist/quikdown.light.css +1 -1
  9. package/dist/quikdown.umd.js +496 -243
  10. package/dist/quikdown.umd.min.js +2 -2
  11. package/dist/quikdown.umd.min.js.gz +0 -0
  12. package/dist/quikdown.umd.min.js.map +1 -1
  13. package/dist/quikdown_ast.cjs +2 -2
  14. package/dist/quikdown_ast.esm.js +2 -2
  15. package/dist/quikdown_ast.esm.min.js +2 -2
  16. package/dist/quikdown_ast.esm.min.js.gz +0 -0
  17. package/dist/quikdown_ast.umd.js +2 -2
  18. package/dist/quikdown_ast.umd.min.js +2 -2
  19. package/dist/quikdown_ast.umd.min.js.gz +0 -0
  20. package/dist/quikdown_ast_html.cjs +3 -3
  21. package/dist/quikdown_ast_html.esm.js +3 -3
  22. package/dist/quikdown_ast_html.esm.min.js +2 -2
  23. package/dist/quikdown_ast_html.esm.min.js.gz +0 -0
  24. package/dist/quikdown_ast_html.umd.js +3 -3
  25. package/dist/quikdown_ast_html.umd.min.js +2 -2
  26. package/dist/quikdown_ast_html.umd.min.js.gz +0 -0
  27. package/dist/quikdown_bd.cjs +496 -243
  28. package/dist/quikdown_bd.esm.js +496 -243
  29. package/dist/quikdown_bd.esm.min.js +2 -2
  30. package/dist/quikdown_bd.esm.min.js.gz +0 -0
  31. package/dist/quikdown_bd.esm.min.js.map +1 -1
  32. package/dist/quikdown_bd.umd.js +496 -243
  33. package/dist/quikdown_bd.umd.min.js +2 -2
  34. package/dist/quikdown_bd.umd.min.js.gz +0 -0
  35. package/dist/quikdown_bd.umd.min.js.map +1 -1
  36. package/dist/quikdown_edit.cjs +760 -327
  37. package/dist/quikdown_edit.esm.js +760 -327
  38. package/dist/quikdown_edit.esm.min.js +3 -3
  39. package/dist/quikdown_edit.esm.min.js.gz +0 -0
  40. package/dist/quikdown_edit.esm.min.js.map +1 -1
  41. package/dist/quikdown_edit.umd.js +760 -327
  42. package/dist/quikdown_edit.umd.min.js +3 -3
  43. package/dist/quikdown_edit.umd.min.js.gz +0 -0
  44. package/dist/quikdown_edit.umd.min.js.map +1 -1
  45. package/dist/quikdown_edit_standalone.esm.min.js.gz +0 -0
  46. package/dist/quikdown_edit_standalone.umd.min.js.gz +0 -0
  47. package/dist/quikdown_json.cjs +3 -3
  48. package/dist/quikdown_json.esm.js +3 -3
  49. package/dist/quikdown_json.esm.min.js +2 -2
  50. package/dist/quikdown_json.esm.min.js.gz +0 -0
  51. package/dist/quikdown_json.umd.js +3 -3
  52. package/dist/quikdown_json.umd.min.js +2 -2
  53. package/dist/quikdown_json.umd.min.js.gz +0 -0
  54. package/dist/quikdown_yaml.cjs +3 -3
  55. package/dist/quikdown_yaml.esm.js +3 -3
  56. package/dist/quikdown_yaml.esm.min.js +2 -2
  57. package/dist/quikdown_yaml.esm.min.js.gz +0 -0
  58. package/dist/quikdown_yaml.umd.js +3 -3
  59. package/dist/quikdown_yaml.umd.min.js +2 -2
  60. package/dist/quikdown_yaml.umd.min.js.gz +0 -0
  61. package/package.json +18 -13
@@ -1 +1 @@
1
- {"version":3,"file":"quikdown_edit.umd.min.js","sources":["../src/quikdown.js","../src/quikdown_bd.js","../src/quikdown_edit_copy.js","../src/quikdown_edit.js"],"sourcesContent":["/**\n * quikdown - A minimal markdown parser optimized for chat/LLM output\n * Supports tables, code blocks, lists, and common formatting\n * @param {string} markdown - The markdown source text\n * @param {Object} options - Optional configuration object\n * @param {Function} options.fence_plugin - Custom renderer for fenced code blocks\n * (content, fence_string) => html string\n * @param {boolean} options.inline_styles - If true, uses inline styles instead of classes\n * @param {boolean} options.bidirectional - If true, adds data-qd attributes for source tracking\n * @param {boolean} options.lazy_linefeeds - If true, single newlines become <br> tags\n * @returns {string} - The rendered HTML\n */\n\n// Version will be injected at build time \nconst quikdownVersion = '__QUIKDOWN_VERSION__';\n\n// Constants for reuse\nconst CLASS_PREFIX = 'quikdown-';\nconst PLACEHOLDER_CB = '§CB';\nconst PLACEHOLDER_IC = '§IC';\n\n// Escape map at module level\nconst ESC_MAP = {'&':'&amp;','<':'&lt;','>':'&gt;','\"':'&quot;',\"'\":'&#39;'};\n\n// Single source of truth for all style definitions - optimized\nconst QUIKDOWN_STYLES = {\n h1: 'font-size:2em;font-weight:600;margin:.67em 0;text-align:left',\n h2: 'font-size:1.5em;font-weight:600;margin:.83em 0',\n h3: 'font-size:1.25em;font-weight:600;margin:1em 0',\n h4: 'font-size:1em;font-weight:600;margin:1.33em 0',\n h5: 'font-size:.875em;font-weight:600;margin:1.67em 0',\n h6: 'font-size:.85em;font-weight:600;margin:2em 0',\n pre: 'background:#f4f4f4;padding:10px;border-radius:4px;overflow-x:auto;margin:1em 0',\n code: 'background:#f0f0f0;padding:2px 4px;border-radius:3px;font-family:monospace',\n blockquote: 'border-left:4px solid #ddd;margin-left:0;padding-left:1em',\n table: 'border-collapse:collapse;width:100%;margin:1em 0',\n th: 'border:1px solid #ddd;padding:8px;background-color:#f2f2f2;font-weight:bold;text-align:left',\n td: 'border:1px solid #ddd;padding:8px;text-align:left',\n hr: 'border:none;border-top:1px solid #ddd;margin:1em 0',\n img: 'max-width:100%;height:auto',\n a: 'color:#06c;text-decoration:underline',\n strong: 'font-weight:bold',\n em: 'font-style:italic',\n del: 'text-decoration:line-through',\n ul: 'margin:.5em 0;padding-left:2em',\n ol: 'margin:.5em 0;padding-left:2em',\n li: 'margin:.25em 0',\n // Task list specific styles\n 'task-item': 'list-style:none',\n 'task-checkbox': 'margin-right:.5em'\n};\n\n// Factory function to create getAttr for a given context\nfunction createGetAttr(inline_styles, styles) {\n return function(tag, additionalStyle = '') {\n if (inline_styles) {\n let style = styles[tag];\n if (!style && !additionalStyle) return '';\n \n // Remove default text-align if we're adding a different alignment\n if (additionalStyle && additionalStyle.includes('text-align') && style && style.includes('text-align')) {\n style = style.replace(/text-align:[^;]+;?/, '').trim();\n // Ensure trailing semicolon before concatenating additionalStyle.\n // Both short-circuit paths of this guard (empty `style` or\n // already-has-`;`) are defensive and unreachable with the\n // current QUIKDOWN_STYLES values — istanbul ignore next.\n /* istanbul ignore next */\n if (style && !style.endsWith(';')) style += ';';\n }\n \n /* istanbul ignore next - defensive: additionalStyle without style doesn't occur with current tags */\n const fullStyle = additionalStyle ? (style ? `${style}${additionalStyle}` : additionalStyle) : style;\n return ` style=\"${fullStyle}\"`;\n } else {\n const classAttr = ` class=\"${CLASS_PREFIX}${tag}\"`;\n // Apply inline styles for alignment even when using CSS classes\n if (additionalStyle) {\n return `${classAttr} style=\"${additionalStyle}\"`;\n }\n return classAttr;\n }\n };\n}\n\nfunction quikdown(markdown, options = {}) {\n if (!markdown || typeof markdown !== 'string') {\n return '';\n }\n \n const { fence_plugin, inline_styles = false, bidirectional = false, lazy_linefeeds = false, allow_unsafe_html = false } = options;\n const styles = QUIKDOWN_STYLES; // Use module-level styles\n const getAttr = createGetAttr(inline_styles, styles); // Create getAttr once\n\n // Escape HTML entities to prevent XSS\n function escapeHtml(text) {\n return text.replace(/[&<>\"']/g, m => ESC_MAP[m]);\n }\n \n // Helper to add data-qd attributes for bidirectional support.\n // The non-bidirectional branch is a trivial no-op arrow; it's exercised in\n // the core bundle but never in quikdown_bd (which always sets bidirectional=true).\n /* istanbul ignore next - trivial no-op fallback */\n const dataQd = bidirectional ? (marker) => ` data-qd=\"${escapeHtml(marker)}\"` : () => '';\n\n // Sanitize URLs to prevent XSS attacks\n function sanitizeUrl(url, allowUnsafe = false) {\n /* istanbul ignore next - defensive programming, regex ensures url is never empty */\n if (!url) return '';\n \n // If unsafe URLs are explicitly allowed, return as-is\n if (allowUnsafe) return url;\n \n const trimmedUrl = url.trim();\n const lowerUrl = trimmedUrl.toLowerCase();\n \n // Block dangerous protocols\n const dangerousProtocols = ['javascript:', 'vbscript:', 'data:'];\n \n for (const protocol of dangerousProtocols) {\n if (lowerUrl.startsWith(protocol)) {\n // Exception: Allow data:image/* for images\n if (protocol === 'data:' && lowerUrl.startsWith('data:image/')) {\n return trimmedUrl;\n }\n // Return safe empty link for dangerous protocols\n return '#';\n }\n }\n \n return trimmedUrl;\n }\n\n // Process the markdown in phases\n let html = markdown;\n \n // Phase 1: Extract and protect code blocks and inline code\n const codeBlocks = [];\n const inlineCodes = [];\n \n // Extract fenced code blocks first (supports both ``` and ~~~)\n // Match paired fences - ``` with ``` and ~~~ with ~~~\n // Fence must be at start of line\n html = html.replace(/^(```|~~~)([^\\n]*)\\n([\\s\\S]*?)^\\1$/gm, (match, fence, lang, code) => {\n const placeholder = `${PLACEHOLDER_CB}${codeBlocks.length}§`;\n \n // Trim the language specification\n const langTrimmed = lang ? lang.trim() : '';\n \n // If custom fence plugin is provided, use it (v1.1.0: object format required)\n if (fence_plugin && fence_plugin.render && typeof fence_plugin.render === 'function') {\n codeBlocks.push({\n lang: langTrimmed,\n code: code.trimEnd(),\n custom: true,\n fence: fence,\n hasReverse: !!fence_plugin.reverse\n });\n } else {\n codeBlocks.push({\n lang: langTrimmed,\n code: escapeHtml(code.trimEnd()),\n custom: false,\n fence: fence\n });\n }\n return placeholder;\n });\n \n // Extract inline code\n html = html.replace(/`([^`]+)`/g, (match, code) => {\n const placeholder = `${PLACEHOLDER_IC}${inlineCodes.length}§`;\n inlineCodes.push(escapeHtml(code));\n return placeholder;\n });\n \n // Escape HTML in the rest of the content (skip if allow_unsafe_html is on —\n // useful for trusted pipelines where the markdown contains intentional HTML)\n if (!allow_unsafe_html) {\n html = escapeHtml(html);\n }\n \n // Phase 2: Process block elements\n \n // Process tables\n html = processTable(html, getAttr);\n \n // Process headings (supports optional trailing #'s)\n html = html.replace(/^(#{1,6})\\s+(.+?)\\s*#*$/gm, (match, hashes, content) => {\n const level = hashes.length;\n return `<h${level}${getAttr('h' + level)}${dataQd(hashes)}>${content}</h${level}>`;\n });\n \n // Process blockquotes (must handle escaped > since we already escaped HTML)\n html = html.replace(/^&gt;\\s+(.+)$/gm, `<blockquote${getAttr('blockquote')}>$1</blockquote>`);\n // Merge consecutive blockquotes\n html = html.replace(/<\\/blockquote>\\n<blockquote>/g, '\\n');\n \n // Process horizontal rules (allow trailing spaces)\n html = html.replace(/^---+\\s*$/gm, `<hr${getAttr('hr')}>`);\n \n // Process lists\n html = processLists(html, getAttr, inline_styles, bidirectional);\n \n // Phase 3: Process inline elements\n \n // Images (must come before links, with URL sanitization)\n html = html.replace(/!\\[([^\\]]*)\\]\\(([^)]+)\\)/g, (match, alt, src) => {\n const sanitizedSrc = sanitizeUrl(src, options.allow_unsafe_urls);\n const altAttr = bidirectional && alt ? ` data-qd-alt=\"${escapeHtml(alt)}\"` : '';\n const srcAttr = bidirectional ? ` data-qd-src=\"${escapeHtml(src)}\"` : '';\n return `<img${getAttr('img')} src=\"${sanitizedSrc}\" alt=\"${alt}\"${altAttr}${srcAttr}${dataQd('!')}>`;\n });\n \n // Links (with URL sanitization)\n html = html.replace(/\\[([^\\]]+)\\]\\(([^)]+)\\)/g, (match, text, href) => {\n // Sanitize URL to prevent XSS\n const sanitizedHref = sanitizeUrl(href, options.allow_unsafe_urls);\n const isExternal = /^https?:\\/\\//i.test(sanitizedHref);\n const rel = isExternal ? ' rel=\"noopener noreferrer\"' : '';\n const textAttr = bidirectional ? ` data-qd-text=\"${escapeHtml(text)}\"` : '';\n return `<a${getAttr('a')} href=\"${sanitizedHref}\"${rel}${textAttr}${dataQd('[')}>${text}</a>`;\n });\n \n // Autolinks - convert bare URLs to clickable links\n html = html.replace(/(^|\\s)(https?:\\/\\/[^\\s<]+)/g, (match, prefix, url) => {\n const sanitizedUrl = sanitizeUrl(url, options.allow_unsafe_urls);\n return `${prefix}<a${getAttr('a')} href=\"${sanitizedUrl}\" rel=\"noopener noreferrer\">${url}</a>`;\n });\n \n // Process inline formatting (bold, italic, strikethrough)\n const inlinePatterns = [\n [/\\*\\*(.+?)\\*\\*/g, 'strong', '**'],\n [/__(.+?)__/g, 'strong', '__'],\n [/(?<!\\*)\\*(?!\\*)(.+?)(?<!\\*)\\*(?!\\*)/g, 'em', '*'],\n [/(?<!_)_(?!_)(.+?)(?<!_)_(?!_)/g, 'em', '_'],\n [/~~(.+?)~~/g, 'del', '~~']\n ];\n \n inlinePatterns.forEach(([pattern, tag, marker]) => {\n html = html.replace(pattern, `<${tag}${getAttr(tag)}${dataQd(marker)}>$1</${tag}>`);\n });\n \n // Line breaks\n if (lazy_linefeeds) {\n // Lazy linefeeds: single newline becomes <br> (except between paragraphs and after/before block elements)\n const blocks = [];\n let bi = 0;\n \n // Protect tables and lists \n html = html.replace(/<(table|[uo]l)[^>]*>[\\s\\S]*?<\\/\\1>/g, m => {\n blocks[bi] = m;\n return `§B${bi++}§`;\n });\n \n // Handle paragraphs and block elements\n html = html.replace(/\\n\\n+/g, '§P§')\n // After block elements\n .replace(/(<\\/(?:h[1-6]|blockquote|pre)>)\\n/g, '$1§N§')\n .replace(/(<(?:h[1-6]|blockquote|pre|hr)[^>]*>)\\n/g, '$1§N§')\n // Before block elements \n .replace(/\\n(<(?:h[1-6]|blockquote|pre|hr)[^>]*>)/g, '§N§$1')\n .replace(/\\n(§B\\d+§)/g, '§N§$1')\n .replace(/(§B\\d+§)\\n/g, '$1§N§')\n // Convert remaining newlines\n .replace(/\\n/g, `<br${getAttr('br')}>`)\n // Restore\n .replace(/§N§/g, '\\n')\n .replace(/§P§/g, '</p><p>');\n \n // Restore protected blocks\n blocks.forEach((b, i) => html = html.replace(`§B${i}§`, b));\n \n html = '<p>' + html + '</p>';\n } else {\n // Standard: two spaces at end of line for line breaks\n html = html.replace(/ {2}$/gm, `<br${getAttr('br')}>`);\n \n // Paragraphs (double newlines)\n // Don't add </p> after block elements (they're not in paragraphs)\n html = html.replace(/\\n\\n+/g, (match, offset) => {\n // Check if we're after a block element closing tag\n const before = html.substring(0, offset);\n if (before.match(/<\\/(h[1-6]|blockquote|ul|ol|table|pre|hr)>$/)) {\n return '<p>'; // Just open a new paragraph\n }\n return '</p><p>'; // Normal paragraph break\n });\n html = '<p>' + html + '</p>';\n }\n \n // Clean up empty paragraphs and unwrap block elements\n const cleanupPatterns = [\n [/<p><\\/p>/g, ''],\n [/<p>(<h[1-6][^>]*>)/g, '$1'],\n [/(<\\/h[1-6]>)<\\/p>/g, '$1'],\n [/<p>(<blockquote[^>]*>)/g, '$1'],\n [/(<\\/blockquote>)<\\/p>/g, '$1'],\n [/<p>(<ul[^>]*>|<ol[^>]*>)/g, '$1'],\n [/(<\\/ul>|<\\/ol>)<\\/p>/g, '$1'],\n [/<p>(<hr[^>]*>)<\\/p>/g, '$1'],\n [/<p>(<table[^>]*>)/g, '$1'],\n [/(<\\/table>)<\\/p>/g, '$1'],\n [/<p>(<pre[^>]*>)/g, '$1'],\n [/(<\\/pre>)<\\/p>/g, '$1'],\n [new RegExp(`<p>(${PLACEHOLDER_CB}\\\\d+§)</p>`, 'g'), '$1']\n ];\n \n cleanupPatterns.forEach(([pattern, replacement]) => {\n html = html.replace(pattern, replacement);\n });\n \n // Fix orphaned closing </p> tags after block elements\n // When a paragraph follows a block element, ensure it has opening <p>\n html = html.replace(/(<\\/(?:h[1-6]|blockquote|ul|ol|table|pre|hr)>)\\n([^<])/g, '$1\\n<p>$2');\n \n // Phase 4: Restore code blocks and inline code\n \n // Restore code blocks\n codeBlocks.forEach((block, i) => {\n let replacement;\n \n if (block.custom && fence_plugin && fence_plugin.render) {\n // Use custom fence plugin (v1.1.0: object format with render function)\n replacement = fence_plugin.render(block.code, block.lang);\n \n // If plugin returns undefined, fall back to default rendering\n if (replacement === undefined) {\n const langClass = !inline_styles && block.lang ? ` class=\"language-${block.lang}\"` : '';\n const codeAttr = inline_styles ? getAttr('code') : langClass;\n const langAttr = bidirectional && block.lang ? ` data-qd-lang=\"${escapeHtml(block.lang)}\"` : '';\n const fenceAttr = bidirectional ? ` data-qd-fence=\"${escapeHtml(block.fence)}\"` : '';\n replacement = `<pre${getAttr('pre')}${fenceAttr}${langAttr}><code${codeAttr}>${escapeHtml(block.code)}</code></pre>`;\n } else if (bidirectional) {\n // If bidirectional and plugin provided HTML, add data attributes for roundtrip\n replacement = replacement.replace(/^<(\\w+)/, \n `<$1 data-qd-fence=\"${escapeHtml(block.fence)}\" data-qd-lang=\"${escapeHtml(block.lang)}\" data-qd-source=\"${escapeHtml(block.code)}\"`);\n }\n } else {\n // Default rendering\n const langClass = !inline_styles && block.lang ? ` class=\"language-${block.lang}\"` : '';\n const codeAttr = inline_styles ? getAttr('code') : langClass;\n const langAttr = bidirectional && block.lang ? ` data-qd-lang=\"${escapeHtml(block.lang)}\"` : '';\n const fenceAttr = bidirectional ? ` data-qd-fence=\"${escapeHtml(block.fence)}\"` : '';\n replacement = `<pre${getAttr('pre')}${fenceAttr}${langAttr}><code${codeAttr}>${block.code}</code></pre>`;\n }\n \n const placeholder = `${PLACEHOLDER_CB}${i}§`;\n html = html.replace(placeholder, replacement);\n });\n \n // Restore inline code\n inlineCodes.forEach((code, i) => {\n const placeholder = `${PLACEHOLDER_IC}${i}§`;\n html = html.replace(placeholder, `<code${getAttr('code')}${dataQd('`')}>${code}</code>`);\n });\n \n return html.trim();\n}\n\n/**\n * Process inline markdown formatting\n */\nfunction processInlineMarkdown(text, getAttr) {\n \n // Process inline formatting patterns\n const patterns = [\n [/\\*\\*(.+?)\\*\\*/g, 'strong'],\n [/__(.+?)__/g, 'strong'],\n [/(?<!\\*)\\*(?!\\*)(.+?)(?<!\\*)\\*(?!\\*)/g, 'em'],\n [/(?<!_)_(?!_)(.+?)(?<!_)_(?!_)/g, 'em'],\n [/~~(.+?)~~/g, 'del'],\n [/`([^`]+)`/g, 'code']\n ];\n \n patterns.forEach(([pattern, tag]) => {\n text = text.replace(pattern, `<${tag}${getAttr(tag)}>$1</${tag}>`);\n });\n \n return text;\n}\n\n/**\n * Process markdown tables\n */\nfunction processTable(text, getAttr) {\n const lines = text.split('\\n');\n const result = [];\n let inTable = false;\n let tableLines = [];\n \n for (let i = 0; i < lines.length; i++) {\n const line = lines[i].trim();\n \n // Check if this line looks like a table row (with or without trailing |)\n if (line.includes('|') && (line.startsWith('|') || /[^\\\\|]/.test(line))) {\n if (!inTable) {\n inTable = true;\n tableLines = [];\n }\n tableLines.push(line);\n } else {\n // Not a table line\n if (inTable) {\n // Process the accumulated table\n const tableHtml = buildTable(tableLines, getAttr);\n if (tableHtml) {\n result.push(tableHtml);\n } else {\n // Not a valid table, restore original lines\n result.push(...tableLines);\n }\n inTable = false;\n tableLines = [];\n }\n result.push(lines[i]);\n }\n }\n \n // Handle table at end of text\n if (inTable && tableLines.length > 0) {\n const tableHtml = buildTable(tableLines, getAttr);\n if (tableHtml) {\n result.push(tableHtml);\n } else {\n result.push(...tableLines);\n }\n }\n \n return result.join('\\n');\n}\n\n/**\n * Build an HTML table from markdown table lines\n */\nfunction buildTable(lines, getAttr) {\n \n if (lines.length < 2) return null;\n \n // Check for separator line (second line should be the separator)\n let separatorIndex = -1;\n for (let i = 1; i < lines.length; i++) {\n // Support separator with or without leading/trailing pipes\n if (/^\\|?[\\s\\-:|]+\\|?$/.test(lines[i]) && lines[i].includes('-')) {\n separatorIndex = i;\n break;\n }\n }\n \n if (separatorIndex === -1) return null;\n \n const headerLines = lines.slice(0, separatorIndex);\n const bodyLines = lines.slice(separatorIndex + 1);\n \n // Parse alignment from separator\n const separator = lines[separatorIndex];\n // Handle pipes at start/end or not\n const separatorCells = separator.trim().replace(/^\\|/, '').replace(/\\|$/, '').split('|');\n const alignments = separatorCells.map(cell => {\n const trimmed = cell.trim();\n if (trimmed.startsWith(':') && trimmed.endsWith(':')) return 'center';\n if (trimmed.endsWith(':')) return 'right';\n return 'left';\n });\n \n let html = `<table${getAttr('table')}>\\n`;\n \n // Build header\n // Note: headerLines will always have length > 0 since separatorIndex starts from 1\n html += `<thead${getAttr('thead')}>\\n`;\n headerLines.forEach(line => {\n html += `<tr${getAttr('tr')}>\\n`;\n // Handle pipes at start/end or not\n const cells = line.trim().replace(/^\\|/, '').replace(/\\|$/, '').split('|');\n cells.forEach((cell, i) => {\n const alignStyle = alignments[i] && alignments[i] !== 'left' ? `text-align:${alignments[i]}` : '';\n const processedCell = processInlineMarkdown(cell.trim(), getAttr);\n html += `<th${getAttr('th', alignStyle)}>${processedCell}</th>\\n`;\n });\n html += '</tr>\\n';\n });\n html += '</thead>\\n';\n \n // Build body\n if (bodyLines.length > 0) {\n html += `<tbody${getAttr('tbody')}>\\n`;\n bodyLines.forEach(line => {\n html += `<tr${getAttr('tr')}>\\n`;\n // Handle pipes at start/end or not\n const cells = line.trim().replace(/^\\|/, '').replace(/\\|$/, '').split('|');\n cells.forEach((cell, i) => {\n const alignStyle = alignments[i] && alignments[i] !== 'left' ? `text-align:${alignments[i]}` : '';\n const processedCell = processInlineMarkdown(cell.trim(), getAttr);\n html += `<td${getAttr('td', alignStyle)}>${processedCell}</td>\\n`;\n });\n html += '</tr>\\n';\n });\n html += '</tbody>\\n';\n }\n \n html += '</table>';\n return html;\n}\n\n/**\n * Process markdown lists (ordered and unordered)\n */\nfunction processLists(text, getAttr, inline_styles, bidirectional) {\n \n const lines = text.split('\\n');\n const result = [];\n const listStack = []; // Track nested lists\n \n // Helper to escape HTML for data-qd attributes. List markers (`-`, `*`,\n // `+`, `1.`, etc.) never contain HTML-special chars, so the replace\n // callback is defensive-only and never actually fires in practice.\n const escapeHtml = (text) => text.replace(/[&<>\"']/g,\n /* istanbul ignore next - defensive: list markers never contain HTML specials */\n m => ({'&':'&amp;','<':'&lt;','>':'&gt;','\"':'&quot;',\"'\":'&#39;'})[m]);\n /* istanbul ignore next - trivial no-op fallback; not exercised via bd bundle */\n const dataQd = bidirectional ? (marker) => ` data-qd=\"${escapeHtml(marker)}\"` : () => '';\n \n for (let i = 0; i < lines.length; i++) {\n const line = lines[i];\n const match = line.match(/^(\\s*)([*\\-+]|\\d+\\.)\\s+(.+)$/);\n \n if (match) {\n const [, indent, marker, content] = match;\n const level = Math.floor(indent.length / 2);\n const isOrdered = /^\\d+\\./.test(marker);\n const listType = isOrdered ? 'ol' : 'ul';\n \n // Check for task list items\n let listItemContent = content;\n let taskListClass = '';\n const taskMatch = content.match(/^\\[([x ])\\]\\s+(.*)$/i);\n if (taskMatch && !isOrdered) {\n const [, checked, taskContent] = taskMatch;\n const isChecked = checked.toLowerCase() === 'x';\n const checkboxAttr = inline_styles \n ? ' style=\"margin-right:.5em\"' \n : ` class=\"${CLASS_PREFIX}task-checkbox\"`;\n listItemContent = `<input type=\"checkbox\"${checkboxAttr}${isChecked ? ' checked' : ''} disabled> ${taskContent}`;\n taskListClass = inline_styles ? ' style=\"list-style:none\"' : ` class=\"${CLASS_PREFIX}task-item\"`;\n }\n \n // Close deeper levels\n while (listStack.length > level + 1) {\n const list = listStack.pop();\n result.push(`</${list.type}>`);\n }\n \n // Open new level if needed\n if (listStack.length === level) {\n // Need to open a new list\n listStack.push({ type: listType, level });\n result.push(`<${listType}${getAttr(listType)}>`);\n } else if (listStack.length === level + 1) {\n // Check if we need to switch list type\n const currentList = listStack[listStack.length - 1];\n if (currentList.type !== listType) {\n result.push(`</${currentList.type}>`);\n listStack.pop();\n listStack.push({ type: listType, level });\n result.push(`<${listType}${getAttr(listType)}>`);\n }\n }\n \n const liAttr = taskListClass || getAttr('li');\n result.push(`<li${liAttr}${dataQd(marker)}>${listItemContent}</li>`);\n } else {\n // Not a list item, close all lists\n while (listStack.length > 0) {\n const list = listStack.pop();\n result.push(`</${list.type}>`);\n }\n result.push(line);\n }\n }\n \n // Close any remaining lists\n while (listStack.length > 0) {\n const list = listStack.pop();\n result.push(`</${list.type}>`);\n }\n \n return result.join('\\n');\n}\n\n/**\n * Emit CSS styles for quikdown elements\n * @param {string} prefix - Optional class prefix (default: 'quikdown-')\n * @param {string} theme - Optional theme: 'light' (default) or 'dark'\n * @returns {string} CSS string with quikdown styles\n */\nquikdown.emitStyles = function(prefix = 'quikdown-', theme = 'light') {\n const styles = QUIKDOWN_STYLES;\n \n // Define theme color overrides\n const themeOverrides = {\n dark: {\n '#f4f4f4': '#2a2a2a', // pre background\n '#f0f0f0': '#2a2a2a', // code background\n '#f2f2f2': '#2a2a2a', // th background\n '#ddd': '#3a3a3a', // borders\n '#06c': '#6db3f2', // links\n _textColor: '#e0e0e0'\n },\n light: {\n _textColor: '#333' // Explicit text color for light theme\n }\n };\n \n let css = '';\n for (const [tag, style] of Object.entries(styles)) {\n let themedStyle = style;\n \n // Apply theme overrides if dark theme\n if (theme === 'dark' && themeOverrides.dark) {\n // Replace colors\n for (const [oldColor, newColor] of Object.entries(themeOverrides.dark)) {\n if (!oldColor.startsWith('_')) {\n themedStyle = themedStyle.replace(new RegExp(oldColor, 'g'), newColor);\n }\n }\n \n // Add text color for certain elements in dark theme\n const needsTextColor = ['h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'td', 'li', 'blockquote'];\n if (needsTextColor.includes(tag)) {\n themedStyle += `;color:${themeOverrides.dark._textColor}`;\n }\n } else if (theme === 'light' && themeOverrides.light) {\n // Add explicit text color for light theme elements too\n const needsTextColor = ['h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'td', 'li', 'blockquote'];\n if (needsTextColor.includes(tag)) {\n themedStyle += `;color:${themeOverrides.light._textColor}`;\n }\n }\n \n css += `.${prefix}${tag} { ${themedStyle} }\\n`;\n }\n \n return css;\n};\n\n/**\n * Configure quikdown with options and return a function\n * @param {Object} options - Configuration options\n * @returns {Function} Configured quikdown function\n */\nquikdown.configure = function(options) {\n return function(markdown) {\n return quikdown(markdown, options);\n };\n};\n\n/**\n * Version information\n */\nquikdown.version = quikdownVersion;\n\n// Export for both CommonJS and ES6\n/* istanbul ignore next */\nif (typeof module !== 'undefined' && module.exports) {\n module.exports = quikdown;\n}\n\n// For browser global\n/* istanbul ignore next */\nif (typeof window !== 'undefined') {\n window.quikdown = quikdown;\n}\n\nexport default quikdown;","/**\n * quikdown_bd - Bidirectional markdown/HTML converter\n * Extends core quikdown with HTML→Markdown conversion\n * \n * Uses data-qd attributes to preserve original markdown syntax\n * Enables HTML→Markdown conversion for quikdown-generated HTML\n */\n\nimport quikdown from './quikdown.js';\n\n/**\n * Create bidirectional version by extending quikdown\n * This wraps quikdown and adds the toMarkdown method\n */\nfunction quikdown_bd(markdown, options = {}) {\n // Use core quikdown with bidirectional flag to add data-qd attributes\n return quikdown(markdown, { ...options, bidirectional: true });\n}\n\n// Copy all properties and methods from quikdown (including version).\n// Skip `configure` — quikdown_bd provides its own override below, so the\n// inner quikdown.configure is dead code in this bundle.\nObject.keys(quikdown).forEach(key => {\n if (key === 'configure') return;\n quikdown_bd[key] = quikdown[key];\n});\n\n// Add the toMarkdown method for HTML→Markdown conversion\nquikdown_bd.toMarkdown = function(htmlOrElement, options = {}) {\n // Accept either HTML string or DOM element\n let container;\n if (typeof htmlOrElement === 'string') {\n container = document.createElement('div');\n container.innerHTML = htmlOrElement;\n } else if (htmlOrElement instanceof Element) {\n /* istanbul ignore next - browser-only code path, not testable in jsdom */\n container = htmlOrElement;\n } else {\n return '';\n }\n \n // Walk the DOM tree and reconstruct markdown\n function walkNode(node, parentContext = {}) {\n if (node.nodeType === Node.TEXT_NODE) {\n // Return text content, preserving whitespace where needed\n return node.textContent;\n }\n \n if (node.nodeType !== Node.ELEMENT_NODE) {\n return '';\n }\n \n const tag = node.tagName.toLowerCase();\n const dataQd = node.getAttribute('data-qd');\n \n // Process children with context\n let childContent = '';\n for (const child of node.childNodes) {\n childContent += walkNode(child, { parentTag: tag, ...parentContext });\n }\n \n // Determine markdown based on element and attributes\n switch (tag) {\n case 'h1':\n case 'h2':\n case 'h3':\n case 'h4':\n case 'h5':\n case 'h6':\n const level = parseInt(tag[1]);\n const prefix = dataQd || '#'.repeat(level);\n return `${prefix} ${childContent.trim()}\\n\\n`;\n \n case 'strong':\n case 'b':\n if (!childContent) return ''; // Don't add markers for empty content\n const boldMarker = dataQd || '**';\n return `${boldMarker}${childContent}${boldMarker}`;\n \n case 'em':\n case 'i':\n if (!childContent) return ''; // Don't add markers for empty content\n const emMarker = dataQd || '*';\n return `${emMarker}${childContent}${emMarker}`;\n \n case 'del':\n case 's':\n case 'strike':\n if (!childContent) return ''; // Don't add markers for empty content\n const delMarker = dataQd || '~~';\n return `${delMarker}${childContent}${delMarker}`;\n \n case 'code':\n // Note: code inside pre is handled directly by the pre case using querySelector\n if (!childContent) return ''; // Don't add markers for empty content\n const codeMarker = dataQd || '`';\n return `${codeMarker}${childContent}${codeMarker}`;\n \n case 'pre':\n const fence = node.getAttribute('data-qd-fence') || dataQd || '```';\n const lang = node.getAttribute('data-qd-lang') || '';\n \n // Check if this was created by a fence plugin with reverse handler\n if (options.fence_plugin && options.fence_plugin.reverse && lang) {\n try {\n const result = options.fence_plugin.reverse(node);\n if (result && result.content) {\n const fenceMarker = result.fence || fence;\n const langStr = result.lang || lang;\n return `${fenceMarker}${langStr}\\n${result.content}\\n${fenceMarker}\\n\\n`;\n }\n } catch (err) {\n console.warn('Fence reverse handler error:', err);\n // Fall through to default handling\n }\n }\n \n // Fallback: use data-qd-source if available\n const source = node.getAttribute('data-qd-source');\n if (source) {\n return `${fence}${lang}\\n${source}\\n${fence}\\n\\n`;\n }\n \n // Final fallback: extract text content\n const codeEl = node.querySelector('code');\n const codeContent = codeEl ? codeEl.textContent : childContent;\n return `${fence}${lang}\\n${codeContent.trimEnd()}\\n${fence}\\n\\n`;\n \n case 'blockquote':\n const quoteMarker = dataQd || '>';\n const lines = childContent.trim().split('\\n');\n return lines.map(line => `${quoteMarker} ${line}`).join('\\n') + '\\n\\n';\n \n case 'hr':\n const hrMarker = dataQd || '---';\n return `${hrMarker}\\n\\n`;\n \n case 'br':\n const brMarker = dataQd || ' ';\n return `${brMarker}\\n`;\n \n case 'a':\n const linkText = node.getAttribute('data-qd-text') || childContent.trim();\n const href = node.getAttribute('href') || '';\n // Check for autolinks\n if (linkText === href && !dataQd) {\n return `<${href}>`;\n }\n return `[${linkText}](${href})`;\n \n case 'img':\n const alt = node.getAttribute('data-qd-alt') || node.getAttribute('alt') || '';\n const src = node.getAttribute('data-qd-src') || node.getAttribute('src') || '';\n const imgMarker = dataQd || '!';\n return `${imgMarker}[${alt}](${src})`;\n \n case 'ul':\n case 'ol':\n return walkList(node, tag === 'ol') + '\\n';\n \n case 'li':\n // Handled by list processor\n return childContent;\n \n case 'table':\n return walkTable(node) + '\\n\\n';\n \n case 'p':\n // Check if it's actually a paragraph or just a wrapper\n if (childContent.trim()) {\n // Check if paragraph ends with a line that's just whitespace\n // This indicates an intentional blank line before the next element\n const lines = childContent.split('\\n');\n let content = childContent.trim();\n \n // If the last line(s) are just whitespace, preserve one blank line\n if (lines.length > 1) {\n let trailingBlankLines = 0;\n for (let i = lines.length - 1; i >= 0; i--) {\n if (lines[i].trim() === '') {\n trailingBlankLines++;\n } else {\n break;\n }\n }\n if (trailingBlankLines > 0) {\n // Add a line with just a space, followed by single newline\n // The \\n\\n will be added below for paragraph separation\n content = content + '\\n ';\n // Only add one newline since we're preserving the space line\n return content + '\\n';\n }\n }\n \n return content + '\\n\\n';\n }\n return '';\n \n case 'div':\n // Check if this was created by a fence plugin with reverse handler\n const divLang = node.getAttribute('data-qd-lang');\n const divFence = node.getAttribute('data-qd-fence');\n \n if (divLang && options.fence_plugin && options.fence_plugin.reverse) {\n try {\n const result = options.fence_plugin.reverse(node);\n if (result && result.content) {\n const fenceMarker = result.fence || divFence || '```';\n const langStr = result.lang || divLang;\n return `${fenceMarker}${langStr}\\n${result.content}\\n${fenceMarker}\\n\\n`;\n }\n } catch (err) {\n console.warn('Fence reverse handler error:', err);\n // Fall through to default handling\n }\n }\n \n // Fallback: use data-qd-source if available\n const divSource = node.getAttribute('data-qd-source');\n if (divSource && divFence) {\n return `${divFence}${divLang || ''}\\n${divSource}\\n${divFence}\\n\\n`;\n }\n \n // Check if it's a mermaid container\n if (node.classList && node.classList.contains('mermaid-container')) {\n const fence = node.getAttribute('data-qd-fence') || '```';\n const lang = node.getAttribute('data-qd-lang') || 'mermaid';\n \n // First check for data-qd-source attribute on the container\n const source = node.getAttribute('data-qd-source');\n if (source) {\n // Decode HTML entities from the attribute (mainly &quot;)\n const temp = document.createElement('textarea');\n temp.innerHTML = source;\n const code = temp.value;\n return `${fence}${lang}\\n${code}\\n${fence}\\n\\n`;\n }\n \n // Check for source on the pre.mermaid element\n const mermaidPre = node.querySelector('pre.mermaid');\n if (mermaidPre) {\n const preSource = mermaidPre.getAttribute('data-qd-source');\n if (preSource) {\n const temp = document.createElement('textarea');\n temp.innerHTML = preSource;\n const code = temp.value;\n return `${fence}${lang}\\n${code}\\n${fence}\\n\\n`;\n }\n }\n \n // Fallback: Look for the legacy .mermaid-source element\n const sourceElement = node.querySelector('.mermaid-source');\n if (sourceElement) {\n // Decode HTML entities\n const temp = document.createElement('div');\n temp.innerHTML = sourceElement.innerHTML;\n const code = temp.textContent;\n return `${fence}${lang}\\n${code}\\n${fence}\\n\\n`;\n }\n \n // Final fallback: try to extract from the mermaid element (unreliable after rendering)\n const mermaidElement = node.querySelector('.mermaid');\n if (mermaidElement && mermaidElement.textContent.includes('graph')) {\n return `${fence}${lang}\\n${mermaidElement.textContent.trim()}\\n${fence}\\n\\n`;\n }\n }\n // Check if it's a standalone mermaid diagram (legacy)\n if (node.classList && node.classList.contains('mermaid')) {\n const fence = node.getAttribute('data-qd-fence') || '```';\n const lang = node.getAttribute('data-qd-lang') || 'mermaid';\n const code = node.textContent.trim();\n return `${fence}${lang}\\n${code}\\n${fence}\\n\\n`;\n }\n // Pass through other divs\n return childContent;\n \n case 'span':\n // Pass through container elements\n return childContent;\n \n default:\n return childContent;\n }\n }\n \n // Walk list elements\n function walkList(listNode, isOrdered, depth = 0) {\n let result = '';\n let index = 1;\n const indent = ' '.repeat(depth);\n \n for (const child of listNode.children) {\n if (child.tagName !== 'LI') continue;\n \n const dataQd = child.getAttribute('data-qd');\n let marker = dataQd || (isOrdered ? `${index}.` : '-');\n \n // Check for task list checkbox\n const checkbox = child.querySelector('input[type=\"checkbox\"]');\n if (checkbox) {\n const checked = checkbox.checked ? 'x' : ' ';\n marker = '-';\n // Get text without the checkbox\n let text = '';\n for (const node of child.childNodes) {\n if (node.nodeType === Node.TEXT_NODE) {\n text += node.textContent;\n } else if (node.tagName && node.tagName !== 'INPUT') {\n text += walkNode(node);\n }\n }\n result += `${indent}${marker} [${checked}] ${text.trim()}\\n`;\n } else {\n let itemContent = '';\n \n for (const node of child.childNodes) {\n if (node.tagName === 'UL' || node.tagName === 'OL') {\n itemContent += walkList(node, node.tagName === 'OL', depth + 1);\n } else {\n itemContent += walkNode(node);\n }\n }\n \n result += `${indent}${marker} ${itemContent.trim()}\\n`;\n }\n \n index++;\n }\n \n return result;\n }\n \n // Walk table elements\n function walkTable(table) {\n let result = '';\n const alignData = table.getAttribute('data-qd-align');\n const alignments = alignData ? alignData.split(',') : [];\n \n // Process header\n const thead = table.querySelector('thead');\n if (thead) {\n const headerRow = thead.querySelector('tr');\n if (headerRow) {\n const headers = [];\n for (const th of headerRow.querySelectorAll('th')) {\n headers.push(th.textContent.trim());\n }\n result += '| ' + headers.join(' | ') + ' |\\n';\n \n // Add separator with alignment\n const separators = headers.map((_, i) => {\n const align = alignments[i] || 'left';\n if (align === 'center') return ':---:';\n if (align === 'right') return '---:';\n return '---';\n });\n result += '| ' + separators.join(' | ') + ' |\\n';\n }\n }\n \n // Process body\n const tbody = table.querySelector('tbody');\n if (tbody) {\n for (const row of tbody.querySelectorAll('tr')) {\n const cells = [];\n for (const td of row.querySelectorAll('td')) {\n cells.push(td.textContent.trim());\n }\n if (cells.length > 0) {\n result += '| ' + cells.join(' | ') + ' |\\n';\n }\n }\n }\n \n return result.trim();\n }\n \n // Process the DOM tree\n let markdown = walkNode(container);\n \n // Clean up\n markdown = markdown.replace(/\\n{3,}/g, '\\n\\n'); // Remove excessive newlines\n markdown = markdown.trim();\n \n return markdown;\n};\n\n// Override the configure method to return a bidirectional version.\n// We delegate to the inner quikdown.configure so the shared closure\n// machinery is exercised in both bundles (no dead code).\nquikdown_bd.configure = function(options) {\n const innerParser = quikdown.configure({ ...options, bidirectional: true });\n return function(markdown) {\n return innerParser(markdown);\n };\n};\n\n// Set version\n// Version is already copied from quikdown via Object.keys loop\n\n// Export for both module and browser\n/* istanbul ignore next */\nif (typeof module !== 'undefined' && module.exports) {\n module.exports = quikdown_bd;\n}\n\n/* istanbul ignore next */\nif (typeof window !== 'undefined') {\n window.quikdown_bd = quikdown_bd;\n}\n\nexport default quikdown_bd;","/**\n * Rich copy functionality for QuikdownEditor\n * Handles copying rendered content with proper formatting for pasting into rich text editors\n */\n\n/**\n * Get platform information\n * @returns {string} The detected platform: 'macos', 'windows', 'linux', or 'unknown'\n */\nfunction getPlatform() {\n const platform = navigator.platform?.toLowerCase() || '';\n const userAgent = navigator.userAgent?.toLowerCase() || '';\n \n if (platform.includes('mac') || userAgent.includes('mac')) {\n return 'macos';\n } else if (userAgent.includes('windows')) {\n return 'windows';\n } else if (userAgent.includes('linux')) {\n return 'linux';\n }\n return 'unknown';\n}\n\n/**\n * Copy to clipboard using HTML selection fallback (for Safari)\n * Uses div with selection to preserve HTML formatting\n * @param {string} html - HTML content to copy\n * @returns {boolean} Success status\n */\nfunction copyToClipboard(html) {\n let tempDiv;\n let result;\n \n try {\n // Use a div instead of textarea to preserve HTML formatting\n tempDiv = document.createElement('div');\n tempDiv.style.position = 'fixed';\n tempDiv.style.left = '-9999px';\n tempDiv.style.top = '0';\n tempDiv.style.width = '1px';\n tempDiv.style.height = '1px';\n tempDiv.style.overflow = 'hidden';\n tempDiv.innerHTML = html;\n \n document.body.appendChild(tempDiv);\n \n // Select the HTML content\n const range = document.createRange();\n range.selectNodeContents(tempDiv);\n const selection = window.getSelection();\n selection.removeAllRanges();\n selection.addRange(range);\n \n // Try to copy\n result = document.execCommand('copy');\n \n // Clear selection\n selection.removeAllRanges();\n } catch (err) {\n console.error('Fallback copy failed:', err);\n result = false;\n } finally {\n if (tempDiv && tempDiv.parentNode) {\n document.body.removeChild(tempDiv);\n }\n }\n \n return result;\n}\n\n/**\n * Convert SVG to PNG blob (based on squibview's implementation)\n * @param {SVGElement} svgElement - The SVG element to convert\n * @returns {Promise<Blob>} A promise that resolves with the PNG blob\n */\nasync function svgToPng(svgElement, needsWhiteBackground = false) {\n return new Promise((resolve, reject) => {\n const svgString = new XMLSerializer().serializeToString(svgElement);\n const canvas = document.createElement('canvas');\n const ctx = canvas.getContext('2d');\n const img = new Image();\n \n const scale = 2;\n \n // Check if this is a Mermaid-generated SVG (they don't have explicit width/height attributes)\n const isMermaidSvg = svgElement.closest('.mermaid') || svgElement.classList.contains('mermaid');\n const hasExplicitDimensions = svgElement.getAttribute('width') && svgElement.getAttribute('height');\n \n let svgWidth, svgHeight;\n \n if (isMermaidSvg || !hasExplicitDimensions) {\n // For Mermaid or other generated SVGs, prioritize computed dimensions\n svgWidth = svgElement.clientWidth || \n (svgElement.viewBox && svgElement.viewBox.baseVal.width) || \n parseFloat(svgElement.getAttribute('width')) || 400;\n svgHeight = svgElement.clientHeight || \n (svgElement.viewBox && svgElement.viewBox.baseVal.height) || \n parseFloat(svgElement.getAttribute('height')) || 300;\n } else {\n // For explicit SVGs (like fenced SVG blocks), prioritize explicit attributes\n svgWidth = parseFloat(svgElement.getAttribute('width')) || \n (svgElement.viewBox && svgElement.viewBox.baseVal.width) || \n svgElement.clientWidth || 400;\n svgHeight = parseFloat(svgElement.getAttribute('height')) || \n (svgElement.viewBox && svgElement.viewBox.baseVal.height) || \n svgElement.clientHeight || 300;\n }\n \n // Ensure the SVG string has explicit dimensions by modifying it if necessary\n let modifiedSvgString = svgString;\n if (svgWidth && svgHeight) {\n // Create a temporary SVG element to modify the serialized string\n const tempDiv = document.createElement('div');\n tempDiv.innerHTML = svgString;\n const tempSvg = tempDiv.querySelector('svg');\n if (tempSvg) {\n tempSvg.setAttribute('width', svgWidth.toString());\n tempSvg.setAttribute('height', svgHeight.toString());\n modifiedSvgString = new XMLSerializer().serializeToString(tempSvg);\n }\n }\n \n canvas.width = svgWidth * scale;\n canvas.height = svgHeight * scale;\n ctx.scale(scale, scale);\n \n img.onload = () => {\n try {\n // Add white background for math equations (they often have transparent backgrounds)\n if (needsWhiteBackground) {\n ctx.fillStyle = 'white';\n ctx.fillRect(0, 0, canvas.width, canvas.height);\n }\n \n ctx.drawImage(img, 0, 0, svgWidth, svgHeight);\n canvas.toBlob(blob => {\n resolve(blob);\n }, 'image/png', 1.0);\n } catch (err) {\n reject(err);\n }\n };\n \n img.onerror = reject;\n // Use data URI instead of blob URL to avoid tainting the canvas\n const svgDataUrl = `data:image/svg+xml;charset=utf-8,${encodeURIComponent(modifiedSvgString)}`;\n img.src = svgDataUrl;\n });\n}\n\n/**\n * Rasterize a GeoJSON Leaflet map to PNG data URL (following Gem's guide)\n * @param {HTMLElement} liveContainer - The live map container element\n * @returns {Promise<string|null>} PNG data URL or null if failed\n */\nasync function rasterizeGeoJSONMap(liveContainer) {\n try {\n const map = liveContainer._map;\n if (!map) {\n console.warn('No map found on container');\n return null;\n }\n \n // Get container dimensions\n const mapRect = liveContainer.getBoundingClientRect();\n const width = Math.round(mapRect.width);\n const height = Math.round(mapRect.height);\n \n if (width === 0 || height === 0) {\n console.warn('Map container has zero dimensions');\n return null;\n }\n \n // Create canvas sized to the map container\n const canvas = document.createElement('canvas');\n const dpr = window.devicePixelRatio || 1;\n \n // Set canvas size with DPR for sharpness\n canvas.width = width * dpr;\n canvas.height = height * dpr;\n canvas.style.width = width + 'px';\n canvas.style.height = height + 'px';\n \n const ctx = canvas.getContext('2d');\n ctx.scale(dpr, dpr);\n \n // White background\n ctx.fillStyle = '#FFFFFF';\n ctx.fillRect(0, 0, width, height);\n \n // 1. Draw tiles from THIS container only\n const tiles = liveContainer.querySelectorAll('.leaflet-tile');\n \n const tilePromises = [];\n for (const tile of tiles) {\n tilePromises.push(new Promise((resolve) => {\n const img = new Image();\n img.crossOrigin = 'anonymous';\n \n img.onload = () => {\n try {\n // Calculate tile position relative to container\n const tileRect = tile.getBoundingClientRect();\n const offsetX = tileRect.left - mapRect.left;\n const offsetY = tileRect.top - mapRect.top;\n \n // Draw tile at correct position\n ctx.drawImage(img, offsetX, offsetY, tileRect.width, tileRect.height);\n } catch (err) {\n console.warn('Failed to draw tile:', err);\n }\n resolve();\n };\n \n img.onerror = () => {\n console.warn('Failed to load tile:', tile.src);\n resolve();\n };\n \n img.src = tile.src;\n }));\n }\n \n // Wait for all tiles to load\n await Promise.all(tilePromises);\n \n // 2. Draw vector overlays (SVG paths for GeoJSON features)\n const svgOverlays = liveContainer.querySelectorAll('svg:not(.leaflet-attribution-flag)');\n \n for (const svg of svgOverlays) {\n // Skip attribution/control overlays\n if (svg.closest('.leaflet-control')) continue;\n \n try {\n const svgRect = svg.getBoundingClientRect();\n const offsetX = svgRect.left - mapRect.left;\n const offsetY = svgRect.top - mapRect.top;\n \n // Serialize SVG\n const serializer = new XMLSerializer();\n const svgStr = serializer.serializeToString(svg);\n const svgBlob = new Blob([svgStr], { type: 'image/svg+xml;charset=utf-8' });\n const url = URL.createObjectURL(svgBlob);\n \n // Draw SVG overlay\n await new Promise((resolve, reject) => {\n const img = new Image();\n img.onload = () => {\n ctx.drawImage(img, offsetX, offsetY, svgRect.width, svgRect.height);\n URL.revokeObjectURL(url);\n resolve();\n };\n img.onerror = () => {\n URL.revokeObjectURL(url);\n reject(new Error('Failed to load SVG overlay'));\n };\n img.src = url;\n });\n } catch (err) {\n console.warn('Failed to draw SVG overlay:', err);\n }\n }\n \n // 3. Draw marker icons if any\n const markerIcons = liveContainer.querySelectorAll('.leaflet-marker-icon');\n \n for (const marker of markerIcons) {\n try {\n const img = new Image();\n img.crossOrigin = 'anonymous';\n \n await new Promise((resolve) => {\n img.onload = () => {\n const markerRect = marker.getBoundingClientRect();\n const offsetX = markerRect.left - mapRect.left;\n const offsetY = markerRect.top - mapRect.top;\n ctx.drawImage(img, offsetX, offsetY, markerRect.width, markerRect.height);\n resolve();\n };\n img.onerror = resolve;\n img.src = marker.src;\n });\n } catch (err) {\n console.warn('Failed to draw marker icon:', err);\n }\n }\n \n // Return PNG data URL\n return canvas.toDataURL('image/png', 1.0);\n \n } catch (error) {\n console.error('Failed to rasterize GeoJSON map:', error);\n return null;\n }\n}\n\n/**\n * Get rendered content as rich HTML suitable for clipboard\n * @param {HTMLElement} previewPanel - The preview panel element to copy from\n * @returns {Promise<{success: boolean, html?: string, text?: string}>}\n */\nexport async function getRenderedContent(previewPanel) {\n if (!previewPanel) {\n throw new Error('No preview panel available');\n }\n \n // Check if MathJax needs to render (only if not already rendered)\n const mathBlocks = previewPanel.querySelectorAll('.math-display');\n if (mathBlocks.length > 0) {\n // Check if already rendered (has mjx-container inside)\n const needsRendering = Array.from(mathBlocks).some(block => !block.querySelector('mjx-container'));\n \n if (needsRendering && window.MathJax && window.MathJax.typesetPromise) {\n try {\n await window.MathJax.typesetPromise(Array.from(mathBlocks));\n } catch (err) {\n console.warn('MathJax typesetting failed:', err);\n }\n }\n }\n \n // Clone the preview panel to avoid modifying the actual DOM\n const clone = previewPanel.cloneNode(true);\n \n // Process different fence types for rich copy\n try {\n // Phase 1: Process basic markdown elements with inline styles\n \n // 1.1 Text formatting - add inline styles\n clone.querySelectorAll('strong, b').forEach(el => {\n el.style.fontWeight = 'bold';\n });\n \n clone.querySelectorAll('em, i').forEach(el => {\n el.style.fontStyle = 'italic';\n });\n \n clone.querySelectorAll('del, s, strike').forEach(el => {\n el.style.textDecoration = 'line-through';\n });\n \n clone.querySelectorAll('u').forEach(el => {\n el.style.textDecoration = 'underline';\n });\n \n clone.querySelectorAll('code:not(pre code)').forEach(el => {\n el.style.backgroundColor = '#f4f4f4';\n el.style.padding = '2px 4px';\n el.style.borderRadius = '3px';\n el.style.fontFamily = 'monospace';\n el.style.fontSize = '0.9em';\n });\n \n // 1.2 Block elements - add inline styles\n clone.querySelectorAll('h1').forEach(el => {\n el.style.fontSize = '2em';\n el.style.fontWeight = 'bold';\n el.style.marginTop = '0.67em';\n el.style.marginBottom = '0.67em';\n });\n \n clone.querySelectorAll('h2').forEach(el => {\n el.style.fontSize = '1.5em';\n el.style.fontWeight = 'bold';\n el.style.marginTop = '0.83em';\n el.style.marginBottom = '0.83em';\n });\n \n clone.querySelectorAll('h3').forEach(el => {\n el.style.fontSize = '1.17em';\n el.style.fontWeight = 'bold';\n el.style.marginTop = '1em';\n el.style.marginBottom = '1em';\n });\n \n clone.querySelectorAll('h4').forEach(el => {\n el.style.fontSize = '1em';\n el.style.fontWeight = 'bold';\n el.style.marginTop = '1.33em';\n el.style.marginBottom = '1.33em';\n });\n \n clone.querySelectorAll('h5').forEach(el => {\n el.style.fontSize = '0.83em';\n el.style.fontWeight = 'bold';\n el.style.marginTop = '1.67em';\n el.style.marginBottom = '1.67em';\n });\n \n clone.querySelectorAll('h6').forEach(el => {\n el.style.fontSize = '0.67em';\n el.style.fontWeight = 'bold';\n el.style.marginTop = '2.33em';\n el.style.marginBottom = '2.33em';\n });\n \n clone.querySelectorAll('blockquote').forEach(el => {\n el.style.borderLeft = '4px solid #ddd';\n el.style.marginLeft = '0';\n el.style.paddingLeft = '1em';\n el.style.color = '#666';\n });\n \n clone.querySelectorAll('hr').forEach(el => {\n el.style.border = 'none';\n el.style.borderTop = '1px solid #ccc';\n el.style.margin = '1em 0';\n });\n \n // 1.3 Tables - add inline styles\n clone.querySelectorAll('table').forEach(table => {\n table.style.borderCollapse = 'collapse';\n table.style.width = '100%';\n table.style.marginBottom = '1em';\n });\n \n clone.querySelectorAll('th').forEach(th => {\n th.style.border = '1px solid #ccc';\n th.style.padding = '8px';\n th.style.textAlign = 'left';\n th.style.backgroundColor = '#f0f0f0';\n th.style.fontWeight = 'bold';\n });\n \n clone.querySelectorAll('td').forEach(td => {\n td.style.border = '1px solid #ccc';\n td.style.padding = '8px';\n td.style.textAlign = 'left';\n });\n \n // 1.4 Links - add inline styles\n clone.querySelectorAll('a').forEach(a => {\n a.style.color = '#0066cc';\n a.style.textDecoration = 'underline';\n });\n \n // Process code blocks - wrap in table and add syntax highlighting colors\n clone.querySelectorAll('pre code').forEach(block => {\n const pre = block.parentElement;\n \n // Add inline styles for syntax highlighting (GitHub theme colors)\n if (block.classList.contains('hljs')) {\n // Apply inline styles to all highlight.js elements\n block.querySelectorAll('.hljs-keyword').forEach(el => {\n el.style.color = '#d73a49';\n el.style.fontWeight = 'bold';\n });\n block.querySelectorAll('.hljs-string').forEach(el => {\n el.style.color = '#032f62';\n });\n block.querySelectorAll('.hljs-number').forEach(el => {\n el.style.color = '#005cc5';\n });\n block.querySelectorAll('.hljs-comment').forEach(el => {\n el.style.color = '#6a737d';\n el.style.fontStyle = 'italic';\n });\n block.querySelectorAll('.hljs-function').forEach(el => {\n el.style.color = '#6f42c1';\n });\n block.querySelectorAll('.hljs-class').forEach(el => {\n el.style.color = '#6f42c1';\n });\n block.querySelectorAll('.hljs-title').forEach(el => {\n el.style.color = '#6f42c1';\n });\n block.querySelectorAll('.hljs-built_in').forEach(el => {\n el.style.color = '#005cc5';\n });\n block.querySelectorAll('.hljs-literal').forEach(el => {\n el.style.color = '#005cc5';\n });\n block.querySelectorAll('.hljs-meta').forEach(el => {\n el.style.color = '#005cc5';\n });\n block.querySelectorAll('.hljs-attr').forEach(el => {\n el.style.color = '#22863a';\n });\n block.querySelectorAll('.hljs-variable').forEach(el => {\n el.style.color = '#e36209';\n });\n block.querySelectorAll('.hljs-regexp').forEach(el => {\n el.style.color = '#032f62';\n });\n block.querySelectorAll('.hljs-selector-class').forEach(el => {\n el.style.color = '#22863a';\n });\n block.querySelectorAll('.hljs-selector-id').forEach(el => {\n el.style.color = '#6f42c1';\n });\n block.querySelectorAll('.hljs-selector-tag').forEach(el => {\n el.style.color = '#22863a';\n });\n block.querySelectorAll('.hljs-tag').forEach(el => {\n el.style.color = '#22863a';\n });\n block.querySelectorAll('.hljs-name').forEach(el => {\n el.style.color = '#22863a';\n });\n block.querySelectorAll('.hljs-attribute').forEach(el => {\n el.style.color = '#6f42c1';\n });\n }\n \n const table = document.createElement('table');\n table.style.width = '100%';\n table.style.borderCollapse = 'collapse';\n table.style.border = 'none';\n table.style.marginBottom = '1em';\n \n const tr = document.createElement('tr');\n const td = document.createElement('td');\n td.style.backgroundColor = '#f7f7f7';\n td.style.padding = '12px';\n td.style.fontFamily = 'Consolas, Monaco, \"Courier New\", monospace';\n td.style.fontSize = '14px';\n td.style.lineHeight = '1.4';\n td.style.whiteSpace = 'pre';\n td.style.overflowX = 'auto';\n td.style.border = '1px solid #ddd';\n td.style.borderRadius = '4px';\n \n // Move the formatted code content with inline styles\n td.innerHTML = block.innerHTML;\n \n tr.appendChild(td);\n table.appendChild(tr);\n \n // Replace the pre element with the table\n pre.parentNode.replaceChild(table, pre);\n });\n \n // Process images - convert to data URLs and ensure proper dimensions\n const images = clone.querySelectorAll('img');\n for (const img of images) {\n // Ensure image has dimensions for Google Docs compatibility\n if (!img.width && img.naturalWidth) {\n img.width = img.naturalWidth;\n }\n if (!img.height && img.naturalHeight) {\n img.height = img.naturalHeight;\n }\n \n // Set max dimensions to prevent huge images\n const maxWidth = 800;\n const maxHeight = 600;\n if (img.width > maxWidth || img.height > maxHeight) {\n const scale = Math.min(maxWidth / img.width, maxHeight / img.height);\n img.width = Math.round(img.width * scale);\n img.height = Math.round(img.height * scale);\n }\n \n // Ensure width and height attributes are set\n if (img.width) {\n img.setAttribute('width', img.width.toString());\n img.style.width = img.width + 'px';\n }\n if (img.height) {\n img.setAttribute('height', img.height.toString());\n img.style.height = img.height + 'px';\n }\n \n // Add v:shapes for Word compatibility\n if (!img.getAttribute('v:shapes')) {\n img.setAttribute('v:shapes', 'image' + Math.random().toString(36).substr(2, 9));\n }\n \n // Skip if already a data URL\n if (img.src && !img.src.startsWith('data:')) {\n try {\n // Try to convert to data URL\n const response = await fetch(img.src);\n const blob = await response.blob();\n \n // Check if image is too large (Google Docs has limits)\n const maxSize = 2 * 1024 * 1024; // 2MB limit for inline images\n if (blob.size > maxSize) {\n console.warn('Image too large for inline data URL:', img.src, 'Size:', blob.size);\n // For large images, we might want to resize or keep the URL\n continue;\n }\n \n const dataUrl = await new Promise(resolve => {\n const reader = new FileReader();\n reader.onloadend = () => resolve(reader.result);\n reader.readAsDataURL(blob);\n });\n img.src = dataUrl;\n } catch (err) {\n console.warn('Failed to convert image to data URL:', img.src, err);\n // Keep original src if conversion fails\n }\n }\n }\n \n // Phase 2: Process fence block types\n // 1. Process STL 3D models - convert canvas to image or placeholder\n const stlContainers = clone.querySelectorAll('.qde-stl-container');\n for (const container of stlContainers) {\n try {\n // Find the corresponding original container to get the canvas\n const containerId = container.dataset.stlId;\n const originalContainer = previewPanel.querySelector(`.qde-stl-container[data-stl-id=\"${containerId}\"]`);\n \n if (originalContainer) {\n // Look for canvas element in the original container (Three.js WebGL canvas)\n const canvas = originalContainer.querySelector('canvas');\n if (canvas && canvas.width > 0 && canvas.height > 0) {\n try {\n // Get Three.js references stored on the container (like squibview)\n const renderer = originalContainer._threeRenderer;\n const scene = originalContainer._threeScene;\n const camera = originalContainer._threeCamera;\n \n // If we have access to the Three.js objects, force render the scene\n if (renderer && scene && camera) {\n renderer.render(scene, camera);\n }\n \n // Try to capture the canvas as an image\n const dataUrl = canvas.toDataURL('image/png', 1.0);\n const img = document.createElement('img');\n img.src = dataUrl;\n \n // Use canvas dimensions for the image\n const imgWidth = canvas.width / 2; // Divide by scale factor (2x for retina)\n const imgHeight = canvas.height / 2;\n \n // Set both HTML attributes and CSS properties for maximum compatibility\n img.width = imgWidth;\n img.height = imgHeight;\n img.setAttribute('width', imgWidth.toString());\n img.setAttribute('height', imgHeight.toString());\n img.style.width = imgWidth + 'px';\n img.style.height = imgHeight + 'px';\n img.style.maxWidth = 'none';\n img.style.maxHeight = 'none';\n img.style.border = '1px solid #ddd';\n img.style.borderRadius = '4px';\n img.style.margin = '0.5em 0';\n img.setAttribute('v:shapes', 'image' + Math.random().toString(36).substr(2, 9));\n img.alt = 'STL 3D Model';\n \n container.parentNode.replaceChild(img, container);\n continue;\n } catch (canvasErr) {\n console.warn('Failed to convert STL canvas to image (likely WebGL context issue):', canvasErr);\n }\n } else {\n console.warn('No valid canvas found in STL container');\n }\n } else {\n console.warn('Could not find original STL container');\n }\n } catch (err) {\n console.error('Error processing STL container for copy:', err);\n }\n \n // Fallback to placeholder if canvas conversion fails\n const placeholder = document.createElement('div');\n placeholder.style.cssText = 'padding: 12px; background-color: #f0f0f0; border: 1px solid #ccc; text-align: center; margin: 0.5em 0; border-radius: 4px;';\n placeholder.textContent = '[STL 3D Model - Interactive content not available in copy]';\n container.parentNode.replaceChild(placeholder, container);\n }\n \n // 2. Process Mermaid diagrams - convert SVG to PNG\n const mermaidContainers = clone.querySelectorAll('.mermaid');\n for (const container of mermaidContainers) {\n const svg = container.querySelector('svg');\n if (svg) {\n try {\n const pngBlob = await svgToPng(svg);\n const dataUrl = await new Promise(resolve => {\n const reader = new FileReader();\n reader.onloadend = () => resolve(reader.result);\n reader.readAsDataURL(pngBlob);\n });\n \n const img = document.createElement('img');\n img.src = dataUrl;\n \n // Use the exact same dimension calculation logic as svgToPng (like squibview)\n const isMermaidSvg = svg.closest('.mermaid') || svg.classList.contains('mermaid');\n const hasExplicitDimensions = svg.getAttribute('width') && svg.getAttribute('height');\n \n let imgWidth, imgHeight;\n \n if (isMermaidSvg || !hasExplicitDimensions) {\n // For Mermaid or other generated SVGs, prioritize computed dimensions\n imgWidth = svg.clientWidth || \n (svg.viewBox && svg.viewBox.baseVal.width) || \n parseFloat(svg.getAttribute('width')) || 400;\n imgHeight = svg.clientHeight || \n (svg.viewBox && svg.viewBox.baseVal.height) || \n parseFloat(svg.getAttribute('height')) || 300;\n } else {\n // For explicit SVGs (like fenced SVG blocks), prioritize explicit attributes\n imgWidth = parseFloat(svg.getAttribute('width')) || \n (svg.viewBox && svg.viewBox.baseVal.width) || \n svg.clientWidth || 400;\n imgHeight = parseFloat(svg.getAttribute('height')) || \n (svg.viewBox && svg.viewBox.baseVal.height) || \n svg.clientHeight || 300;\n }\n \n // Set both HTML attributes and CSS properties for maximum compatibility (like squibview)\n img.width = imgWidth;\n img.height = imgHeight;\n img.setAttribute('width', imgWidth.toString());\n img.setAttribute('height', imgHeight.toString());\n img.style.width = imgWidth + 'px';\n img.style.height = imgHeight + 'px';\n img.style.maxWidth = 'none'; // Prevent CSS from constraining the image\n img.style.maxHeight = 'none';\n img.setAttribute('v:shapes', 'image' + Math.random().toString(36).substr(2, 9));\n img.alt = 'Mermaid Diagram';\n \n container.parentNode.replaceChild(img, container);\n } catch (err) {\n console.warn('Failed to convert Mermaid diagram:', err);\n // Fallback: leave as SVG\n }\n }\n }\n \n // 3. Process Chart.js charts - convert canvas to image\n const chartContainers = clone.querySelectorAll('.qde-chart-container');\n for (const container of chartContainers) {\n try {\n const containerId = container.dataset.chartId;\n const originalContainer = previewPanel.querySelector(`.qde-chart-container[data-chart-id=\"${containerId}\"]`);\n \n if (originalContainer) {\n const canvas = originalContainer.querySelector('canvas');\n if (canvas && canvas.width > 0 && canvas.height > 0) {\n try {\n const dataUrl = canvas.toDataURL('image/png', 1.0);\n const img = document.createElement('img');\n img.src = dataUrl;\n \n // Use canvas dimensions for the image\n const imgWidth = canvas.width;\n const imgHeight = canvas.height;\n \n // Set both HTML attributes and CSS properties for maximum compatibility\n img.width = imgWidth;\n img.height = imgHeight;\n img.setAttribute('width', imgWidth.toString());\n img.setAttribute('height', imgHeight.toString());\n img.style.width = imgWidth + 'px';\n img.style.height = imgHeight + 'px';\n img.style.maxWidth = 'none';\n img.style.maxHeight = 'none';\n img.style.margin = '0.5em 0';\n img.setAttribute('v:shapes', 'image' + Math.random().toString(36).substr(2, 9));\n img.alt = 'Chart';\n \n container.parentNode.replaceChild(img, container);\n continue;\n } catch (canvasErr) {\n console.warn('Failed to convert chart canvas to image:', canvasErr);\n }\n }\n }\n } catch (err) {\n console.warn('Error processing chart container:', err);\n }\n \n // Fallback to placeholder\n const placeholder = document.createElement('div');\n placeholder.style.cssText = 'padding: 12px; background-color: #f0f0f0; border: 1px solid #ccc; text-align: center; margin: 0.5em 0; border-radius: 4px;';\n placeholder.textContent = '[Chart - Interactive content not available in copy]';\n container.parentNode.replaceChild(placeholder, container);\n }\n \n // 4. Process SVG fenced blocks - convert to PNG\n const svgContainers = clone.querySelectorAll('.qde-svg-container svg');\n for (const svg of svgContainers) {\n try {\n const pngBlob = await svgToPng(svg);\n const dataUrl = await new Promise(resolve => {\n const reader = new FileReader();\n reader.onloadend = () => resolve(reader.result);\n reader.readAsDataURL(pngBlob);\n });\n \n const img = document.createElement('img');\n img.src = dataUrl;\n \n // Calculate dimensions for the SVG\n const hasExplicitDimensions = svg.getAttribute('width') && svg.getAttribute('height');\n \n let imgWidth, imgHeight;\n \n if (hasExplicitDimensions) {\n // For explicit SVGs (like fenced SVG blocks), prioritize explicit attributes\n imgWidth = parseFloat(svg.getAttribute('width')) || \n (svg.viewBox && svg.viewBox.baseVal.width) || \n svg.clientWidth || 400;\n imgHeight = parseFloat(svg.getAttribute('height')) || \n (svg.viewBox && svg.viewBox.baseVal.height) || \n svg.clientHeight || 300;\n } else {\n // For generated SVGs, prioritize computed dimensions\n imgWidth = svg.clientWidth || \n (svg.viewBox && svg.viewBox.baseVal.width) || \n parseFloat(svg.getAttribute('width')) || 400;\n imgHeight = svg.clientHeight || \n (svg.viewBox && svg.viewBox.baseVal.height) || \n parseFloat(svg.getAttribute('height')) || 300;\n }\n \n // Set both HTML attributes and CSS properties for maximum compatibility\n img.width = imgWidth;\n img.height = imgHeight;\n img.setAttribute('width', imgWidth.toString());\n img.setAttribute('height', imgHeight.toString());\n img.style.width = imgWidth + 'px';\n img.style.height = imgHeight + 'px';\n img.style.maxWidth = 'none'; // Prevent CSS from constraining the image\n img.style.maxHeight = 'none';\n img.setAttribute('v:shapes', 'image' + Math.random().toString(36).substr(2, 9));\n img.alt = 'SVG Image';\n \n svg.parentNode.replaceChild(img, svg);\n } catch (err) {\n console.warn('Failed to convert SVG to image:', err);\n // Leave as SVG if conversion fails\n }\n }\n \n // 5. Process Math equations - convert to PNG images (exactly like SquibView)\n const mathElements = Array.from(clone.querySelectorAll('.math-display'));\n \n if (mathElements.length > 0) {\n for (const mathEl of mathElements) {\n try {\n // Find SVG inside the math element (MathJax creates it)\n const svg = mathEl.querySelector('svg');\n if (!svg) {\n console.warn('No SVG found in math element, skipping');\n continue;\n }\n \n // Convert SVG to PNG data URL (exactly like SquibView)\n const serializer = new XMLSerializer();\n const svgStr = serializer.serializeToString(svg);\n const svgBlob = new Blob([svgStr], { type: \"image/svg+xml;charset=utf-8\" });\n const url = URL.createObjectURL(svgBlob);\n \n const img = new Image();\n const dataUrl = await new Promise((resolve, reject) => {\n img.onload = function () {\n const canvas = document.createElement('canvas');\n \n // Determine SVG dimensions robustly (exactly like SquibView)\n let width, height;\n try {\n // First try baseVal.value (works for absolute units)\n width = svg.width.baseVal.value;\n height = svg.height.baseVal.value;\n } catch (_e) {\n // Fallback for relative units - use viewBox or rendered size\n if (svg.viewBox && svg.viewBox.baseVal) {\n width = svg.viewBox.baseVal.width;\n height = svg.viewBox.baseVal.height;\n } else {\n // Use the natural size of the loaded image\n width = img.naturalWidth || img.width || 200;\n height = img.naturalHeight || img.height || 50;\n }\n }\n \n // Scale down for much smaller paste sizes\n const targetMaxWidth = 150; // Further reduced\n const targetMaxHeight = 45; // Further reduced\n \n // Apply aggressive downsizing for MathJax SVGs\n let scaleFactor = 0.04; // Further reduced for smaller output\n \n const scaledWidth = width * scaleFactor;\n const scaledHeight = height * scaleFactor;\n \n // If still too large after base scaling, scale down further\n if (scaledWidth > targetMaxWidth || scaledHeight > targetMaxHeight) {\n const scaleX = targetMaxWidth / scaledWidth;\n const scaleY = targetMaxHeight / scaledHeight;\n scaleFactor *= Math.min(scaleX, scaleY);\n }\n \n width *= scaleFactor;\n height *= scaleFactor;\n \n // Use higher DPR for crisp rendering at smaller sizes\n const dpr = 2; // Fixed 2x for consistent quality\n canvas.width = width * dpr;\n canvas.height = height * dpr;\n canvas.style.width = width + 'px';\n canvas.style.height = height + 'px';\n \n const ctx = canvas.getContext('2d');\n ctx.scale(dpr, dpr);\n \n // White background\n ctx.fillStyle = \"#FFFFFF\";\n ctx.fillRect(0, 0, width, height);\n \n // Draw the SVG image at logical size\n ctx.drawImage(img, 0, 0, width, height);\n \n // Clean up URL\n URL.revokeObjectURL(url);\n \n // Return data URL\n resolve(canvas.toDataURL('image/png'));\n };\n \n img.onerror = () => {\n URL.revokeObjectURL(url);\n reject(new Error('Failed to load SVG image'));\n };\n \n img.src = url;\n });\n \n // Replace math element with img tag containing the PNG data URL\n const imgElement = document.createElement('img');\n imgElement.src = dataUrl;\n \n // Extract dimensions from the data URL canvas\n const img2 = new Image();\n img2.src = dataUrl;\n await new Promise((resolve) => {\n img2.onload = resolve;\n img2.onerror = resolve;\n setTimeout(resolve, 100); // Timeout fallback\n });\n \n // Set explicit dimensions (accounting for DPR)\n const displayWidth = img2.naturalWidth / 2; // Divide by DPR\n const displayHeight = img2.naturalHeight / 2;\n \n imgElement.width = displayWidth;\n imgElement.height = displayHeight;\n imgElement.style.cssText = `display:inline-block;margin:0.5em 0;width:${displayWidth}px;height:${displayHeight}px;vertical-align:middle;`;\n imgElement.alt = 'Math equation';\n \n mathEl.parentNode.replaceChild(imgElement, mathEl);\n } catch (error) {\n console.error('Failed to convert math element to image:', error);\n // Keep the original element if conversion fails\n }\n }\n }\n \n // 2. Process GeoJSON maps - convert to static images (following Gem's guide)\n const geojsonContainers = clone.querySelectorAll('.geojson-container');\n if (geojsonContainers.length > 0) {\n \n for (const clonedContainer of geojsonContainers) {\n try {\n // Find the corresponding live container by matching data-original-source\n const originalSource = clonedContainer.getAttribute('data-original-source');\n if (!originalSource) {\n console.warn('No original source found for GeoJSON container');\n continue;\n }\n \n // Find live container with same source\n let liveContainer = null;\n const allLiveContainers = previewPanel.querySelectorAll('.geojson-container');\n for (const candidate of allLiveContainers) {\n if (candidate.getAttribute('data-original-source') === originalSource) {\n liveContainer = candidate;\n break;\n }\n }\n \n if (!liveContainer) {\n console.warn('Could not find live GeoJSON container');\n const placeholder = document.createElement('div');\n placeholder.style.cssText = 'padding: 12px; background-color: #f0f0f0; border: 1px solid #ccc; text-align: center; margin: 0.5em 0; border-radius: 4px;';\n placeholder.textContent = '[GeoJSON Map - Interactive content not available in copy]';\n clonedContainer.parentNode.replaceChild(placeholder, clonedContainer);\n continue;\n }\n \n // Check if map is ready\n const map = liveContainer._map;\n if (!map) {\n console.warn('Map not initialized yet');\n const placeholder = document.createElement('div');\n placeholder.style.cssText = 'padding: 12px; background-color: #f0f0f0; border: 1px solid #ccc; text-align: center; margin: 0.5em 0; border-radius: 4px;';\n placeholder.textContent = '[GeoJSON Map - Still loading]';\n clonedContainer.parentNode.replaceChild(placeholder, clonedContainer);\n continue;\n }\n \n // Rasterize the map to PNG\n const dataUrl = await rasterizeGeoJSONMap(liveContainer);\n \n if (dataUrl) {\n // Replace with image\n const img = document.createElement('img');\n img.src = dataUrl;\n img.style.cssText = 'width: 100%; height: 300px; border: 1px solid #ddd; border-radius: 4px; margin: 0.5em 0;';\n img.alt = 'GeoJSON Map';\n clonedContainer.parentNode.replaceChild(img, clonedContainer);\n } else {\n // Fallback placeholder\n const placeholder = document.createElement('div');\n placeholder.style.cssText = 'padding: 12px; background-color: #f0f0f0; border: 1px solid #ccc; text-align: center; margin: 0.5em 0; border-radius: 4px;';\n placeholder.textContent = '[GeoJSON Map - Interactive content not available in copy]';\n clonedContainer.parentNode.replaceChild(placeholder, clonedContainer);\n }\n \n } catch (error) {\n console.error('Failed to process GeoJSON container:', error);\n // Replace with placeholder\n const placeholder = document.createElement('div');\n placeholder.style.cssText = 'padding: 12px; background-color: #f0f0f0; border: 1px solid #ccc; text-align: center; margin: 0.5em 0; border-radius: 4px;';\n placeholder.textContent = '[GeoJSON Map - Interactive content not available in copy]';\n clonedContainer.parentNode.replaceChild(placeholder, clonedContainer);\n }\n }\n }\n \n \n \n // 6. Process GeoJSON/Leaflet maps - capture as single image (compose tiles + overlays)\n const mapContainers = clone.querySelectorAll('[data-qd-lang=\"geojson\"]');\n for (const container of mapContainers) {\n try {\n const containerId = container.id;\n const originalContainer = containerId ? previewPanel.querySelector(`#${containerId}`) : null;\n if (!originalContainer) continue;\n const leafletContainer = originalContainer.querySelector('.leaflet-container');\n if (!leafletContainer) continue;\n\n const dpr = Math.max(1, window.devicePixelRatio || 1);\n const width = leafletContainer.clientWidth || 600;\n const height = leafletContainer.clientHeight || 400;\n const canvas = document.createElement('canvas');\n canvas.width = Math.round(width * dpr);\n canvas.height = Math.round(height * dpr);\n const ctx = canvas.getContext('2d');\n ctx.scale(dpr, dpr);\n ctx.fillStyle = '#FFFFFF';\n ctx.fillRect(0, 0, width, height);\n\n const leafRect = leafletContainer.getBoundingClientRect();\n\n // Draw tiles (snap to integer pixels to avoid seams)\n const tiles = Array.from(leafletContainer.querySelectorAll('img.leaflet-tile'));\n for (const tile of tiles) {\n try {\n const r = tile.getBoundingClientRect();\n const x = Math.round(r.left - leafRect.left);\n const y = Math.round(r.top - leafRect.top);\n const w = Math.round(r.width);\n const h = Math.round(r.height);\n const overlaps = !(r.right <= leafRect.left || r.left >= leafRect.right || r.bottom <= leafRect.top || r.top >= leafRect.bottom);\n const style = window.getComputedStyle(tile);\n if (w > 0 && h > 0 && overlaps && style.display !== 'none' && style.visibility !== 'hidden') {\n ctx.drawImage(tile, x, y, w + 1, h + 1);\n }\n } catch (e) {\n console.warn('Failed to draw tile:', e);\n }\n }\n\n // Draw SVG overlays (paths, markers)\n const overlaySvgs = originalContainer.querySelectorAll('.leaflet-overlay-pane svg');\n for (const svg of overlaySvgs) {\n try {\n const svgStr = new XMLSerializer().serializeToString(svg);\n const dataUrl = 'data:image/svg+xml;charset=utf-8,' + encodeURIComponent(svgStr);\n const img = new Image();\n await new Promise((resolve) => { img.onload = resolve; img.onerror = resolve; img.src = dataUrl; });\n const r = svg.getBoundingClientRect();\n const x = Math.round(r.left - leafRect.left);\n const y = Math.round(r.top - leafRect.top);\n const w = Math.round(r.width);\n const h = Math.round(r.height);\n const overlaps = !(r.right <= leafRect.left || r.left >= leafRect.right || r.bottom <= leafRect.top || r.top >= leafRect.bottom);\n if (w > 0 && h > 0 && overlaps) ctx.drawImage(img, x, y, w, h);\n } catch (e) {\n console.warn('Failed to draw overlay SVG:', e);\n }\n }\n\n // Draw marker icons (PNG/SVG img elements)\n const markerIcons = originalContainer.querySelectorAll('.leaflet-marker-pane img.leaflet-marker-icon');\n for (const icon of markerIcons) {\n try {\n const r = icon.getBoundingClientRect();\n const x = Math.round(r.left - leafRect.left);\n const y = Math.round(r.top - leafRect.top);\n const w = Math.round(r.width);\n const h = Math.round(r.height);\n const overlaps = !(r.right <= leafRect.left || r.left >= leafRect.right || r.bottom <= leafRect.top || r.top >= leafRect.bottom);\n const style = window.getComputedStyle(icon);\n if (w > 0 && h > 0 && overlaps && style.display !== 'none' && style.visibility !== 'hidden') {\n ctx.drawImage(icon, x, y, w, h);\n }\n } catch (e) {\n console.warn('Failed to draw marker icon:', e);\n }\n }\n\n // Try to produce a data URL (may fail if canvas tainted by CORS tiles)\n let mapDataUrl = '';\n try {\n mapDataUrl = canvas.toDataURL('image/png', 1.0);\n } catch (_e) {\n console.warn('Map canvas tainted; falling back to placeholder');\n }\n\n const img = document.createElement('img');\n if (mapDataUrl) {\n img.src = mapDataUrl;\n img.width = width;\n img.height = height;\n img.setAttribute('width', String(width));\n img.setAttribute('height', String(height));\n img.style.width = width + 'px';\n img.style.height = height + 'px';\n img.style.display = 'block';\n img.style.border = '1px solid #ddd';\n img.setAttribute('v:shapes', 'image' + Math.random().toString(36).substr(2, 9));\n img.alt = 'Map';\n } else {\n img.alt = 'Map';\n img.style.width = width + 'px';\n img.style.height = height + 'px';\n img.style.border = '1px solid #ddd';\n img.style.backgroundColor = '#f0f0f0';\n }\n\n container.parentNode.replaceChild(img, container);\n } catch (err) {\n console.warn('Failed to process map container:', err);\n }\n }\n \n // 7. Process HTML fence blocks - render the HTML content and process images\n const htmlContainers = clone.querySelectorAll('.qde-html-container');\n for (const container of htmlContainers) {\n try {\n // Get the original source HTML\n const source = container.getAttribute('data-qd-source');\n \n // Check if there's a pre element (fallback display) or actual HTML content\n const pre = container.querySelector('pre');\n \n if (source) {\n // Parse the source HTML\n const tempDiv = document.createElement('div');\n tempDiv.innerHTML = source;\n \n // Process all images in the HTML block\n const htmlImages = tempDiv.querySelectorAll('img');\n for (const img of htmlImages) {\n // Preserve original dimensions from HTML attributes\n const widthAttr = img.getAttribute('width');\n const heightAttr = img.getAttribute('height');\n \n if (widthAttr) {\n img.width = parseInt(widthAttr);\n img.style.width = widthAttr.includes('%') ? widthAttr : `${img.width}px`;\n }\n if (heightAttr) {\n img.height = parseInt(heightAttr);\n img.style.height = heightAttr.includes('%') ? heightAttr : `${img.height}px`;\n }\n \n // Convert to data URL using canvas (like squibview)\n if (img.src && !img.src.startsWith('data:')) {\n try {\n // Use canvas to convert image to data URL (avoids CORS issues)\n const canvas = document.createElement('canvas');\n const ctx = canvas.getContext('2d');\n \n // Create new image and wait for it to load\n const tempImg = new Image();\n tempImg.crossOrigin = 'anonymous';\n \n await new Promise((resolve, reject) => {\n tempImg.onload = function() {\n \n // Calculate dimensions preserving aspect ratio\n let displayWidth = 0;\n let displayHeight = 0;\n \n // Use the width specified in HTML (e.g. width=\"250\")\n if (widthAttr && !widthAttr.includes('%')) {\n displayWidth = parseInt(widthAttr);\n }\n \n // Use the height if specified\n if (heightAttr && !heightAttr.includes('%')) {\n displayHeight = parseInt(heightAttr);\n }\n \n \n // If only width is specified, calculate height based on aspect ratio\n if (displayWidth > 0 && displayHeight === 0) {\n if (tempImg.naturalWidth > 0) {\n const aspectRatio = tempImg.naturalHeight / tempImg.naturalWidth;\n displayHeight = Math.round(displayWidth * aspectRatio);\n }\n }\n // If only height is specified, calculate width based on aspect ratio\n else if (displayHeight > 0 && displayWidth === 0) {\n if (tempImg.naturalHeight > 0) {\n const aspectRatio = tempImg.naturalWidth / tempImg.naturalHeight;\n displayWidth = Math.round(displayHeight * aspectRatio);\n }\n }\n // If neither specified, use natural dimensions\n else if (displayWidth === 0 && displayHeight === 0) {\n displayWidth = tempImg.naturalWidth || 250;\n displayHeight = tempImg.naturalHeight || 200;\n }\n \n \n canvas.width = displayWidth;\n canvas.height = displayHeight;\n \n // Draw image to canvas\n ctx.drawImage(tempImg, 0, 0, displayWidth, displayHeight);\n \n // Convert to data URL\n const dataUrl = canvas.toDataURL('image/png', 1.0);\n \n // Update original image\n img.src = dataUrl;\n img.width = displayWidth;\n img.height = displayHeight;\n img.setAttribute('width', displayWidth.toString());\n img.setAttribute('height', displayHeight.toString());\n img.style.width = displayWidth + 'px';\n img.style.height = displayHeight + 'px';\n \n resolve();\n };\n \n tempImg.onerror = function() {\n console.warn('Failed to load HTML fence image:', img.src);\n reject(new Error('Image load failed'));\n };\n \n // Set source - resolve relative paths\n if (img.src.startsWith('http') || img.src.startsWith('//')) {\n tempImg.src = img.src;\n } else {\n // Relative path - let browser resolve it\n const absoluteImg = new Image();\n absoluteImg.src = img.src;\n tempImg.src = absoluteImg.src;\n }\n });\n } catch (err) {\n console.warn('Failed to convert HTML fence image:', img.src, err);\n }\n }\n \n // Add v:shapes for Word compatibility\n img.setAttribute('v:shapes', 'image' + Math.random().toString(36).substr(2, 9));\n }\n \n // Replace container content with processed HTML (whether it had pre or not)\n container.innerHTML = tempDiv.innerHTML;\n } else if (!pre) {\n // Container has rendered HTML already, process its images directly\n const htmlImages = container.querySelectorAll('img');\n for (const img of htmlImages) {\n // Same image processing as above\n const widthAttr = img.getAttribute('width');\n const heightAttr = img.getAttribute('height');\n \n if (widthAttr) {\n img.width = parseInt(widthAttr);\n img.style.width = widthAttr.includes('%') ? widthAttr : `${img.width}px`;\n }\n if (heightAttr) {\n img.height = parseInt(heightAttr);\n img.style.height = heightAttr.includes('%') ? heightAttr : `${img.height}px`;\n }\n \n if (img.src && !img.src.startsWith('data:')) {\n try {\n // Use same canvas approach as above\n const canvas = document.createElement('canvas');\n const ctx = canvas.getContext('2d');\n const tempImg = new Image();\n tempImg.crossOrigin = 'anonymous';\n \n await new Promise((resolve, reject) => {\n tempImg.onload = function() {\n // Calculate dimensions preserving aspect ratio\n let displayWidth = img.width || 0;\n let displayHeight = img.height || 0;\n \n // If only width is specified, calculate height based on aspect ratio\n if (displayWidth && !displayHeight) {\n const aspectRatio = tempImg.naturalHeight / tempImg.naturalWidth;\n displayHeight = Math.round(displayWidth * aspectRatio);\n }\n // If only height is specified, calculate width based on aspect ratio\n else if (displayHeight && !displayWidth) {\n const aspectRatio = tempImg.naturalWidth / tempImg.naturalHeight;\n displayWidth = Math.round(displayHeight * aspectRatio);\n }\n // If neither specified, use natural dimensions\n else if (!displayWidth && !displayHeight) {\n displayWidth = tempImg.naturalWidth || 250;\n displayHeight = tempImg.naturalHeight || Math.round(250 * (tempImg.naturalHeight / tempImg.naturalWidth));\n }\n \n canvas.width = displayWidth;\n canvas.height = displayHeight;\n ctx.drawImage(tempImg, 0, 0, displayWidth, displayHeight);\n \n const dataUrl = canvas.toDataURL('image/png', 1.0);\n img.src = dataUrl;\n img.width = displayWidth;\n img.height = displayHeight;\n img.setAttribute('width', displayWidth.toString());\n img.setAttribute('height', displayHeight.toString());\n img.style.width = displayWidth + 'px';\n img.style.height = displayHeight + 'px';\n \n resolve();\n };\n \n tempImg.onerror = function() {\n console.warn('Failed to load HTML fence image:', img.src);\n reject(new Error('Image load failed'));\n };\n \n if (img.src.startsWith('http') || img.src.startsWith('//')) {\n tempImg.src = img.src;\n } else {\n const absoluteImg = new Image();\n absoluteImg.src = img.src;\n tempImg.src = absoluteImg.src;\n }\n });\n } catch (err) {\n console.warn('Failed to convert HTML fence image:', img.src, err);\n }\n }\n \n img.setAttribute('v:shapes', 'image' + Math.random().toString(36).substr(2, 9));\n }\n }\n } catch (err) {\n console.warn('Failed to process HTML container:', err);\n }\n }\n \n // 8. Tables are already HTML tables from the built-in renderer\n // No processing needed\n \n // Wrap in proper HTML structure for rich text editors\n const fragment = clone.innerHTML;\n const htmlContent = `\n <!DOCTYPE html>\n <html xmlns:v=\"urn:schemas-microsoft-com:vml\"\n xmlns:o=\"urn:schemas-microsoft-com:office:office\"\n xmlns:w=\"urn:schemas-microsoft-com:office:word\">\n <head>\n <meta charset=\"utf-8\">\n <style>\n /* Table styling */\n table { border-collapse: collapse; width: 100%; margin-bottom: 1em; }\n th, td { border: 1px solid #ccc; padding: 8px; text-align: left; }\n th { background-color: #f0f0f0; font-weight: bold; }\n \n /* Code block styling */\n pre { background-color: #f4f4f4; padding: 1em; border-radius: 4px; overflow-x: auto; }\n code { font-family: monospace; background-color: #f4f4f4; padding: 0.2em 0.4em; border-radius: 3px; }\n \n /* Image handling */\n img { display: block; max-width: 100%; height: auto; margin: 0.5em 0; }\n \n /* Blockquote */\n blockquote { border-left: 4px solid #ddd; margin-left: 0; padding-left: 1em; color: #666; }\n \n /* Math equations centered like squibview */\n .math-display { text-align: center; margin: 1em 0; }\n .math-display img { display: inline-block; margin: 0 auto; }\n </style>\n </head>\n <body><!--StartFragment-->${fragment}<!--EndFragment--></body>\n </html>`;\n \n // Get plain text version\n const text = clone.textContent || clone.innerText || '';\n \n // Get platform for clipboard strategy (like squibview)\n const platform = getPlatform();\n \n if (platform === 'macos') {\n // macOS approach (like squibview)\n try {\n await navigator.clipboard.write([\n new ClipboardItem({\n 'text/html': new Blob([htmlContent], { type: 'text/html' }),\n 'text/plain': new Blob([text], { type: 'text/plain' })\n })\n ]);\n return { success: true, html: htmlContent, text };\n } catch (modernErr) {\n console.warn('Modern clipboard API failed, trying Safari fallback:', modernErr);\n // Safari fallback (selection-based HTML of fragment)\n if (copyToClipboard(fragment)) {\n return { success: true, html: htmlContent, text };\n }\n throw new Error('Fallback copy failed');\n }\n } else {\n // Windows/Linux approach (like squibview)\n const tempDiv = document.createElement('div');\n tempDiv.style.position = 'fixed';\n tempDiv.style.left = '-9999px';\n tempDiv.style.top = '0';\n // Use fragment for selection-based fallback copy\n tempDiv.innerHTML = fragment;\n document.body.appendChild(tempDiv);\n \n try {\n await navigator.clipboard.write([\n new ClipboardItem({\n 'text/html': new Blob([htmlContent], { type: 'text/html' }),\n 'text/plain': new Blob([text], { type: 'text/plain' })\n })\n ]);\n return { success: true, html: htmlContent, text };\n } catch (modernErr) {\n console.warn('Modern clipboard API failed, trying execCommand fallback:', modernErr);\n const selection = window.getSelection();\n const range = document.createRange();\n range.selectNodeContents(tempDiv);\n selection.removeAllRanges();\n selection.addRange(range);\n \n const successful = document.execCommand('copy');\n if (!successful) {\n throw new Error('Fallback copy failed');\n }\n return { success: true, html: htmlContent, text };\n } finally {\n if (tempDiv && tempDiv.parentNode) {\n document.body.removeChild(tempDiv);\n }\n }\n }\n \n } catch (err) {\n console.error('Failed to copy rendered content:', err);\n throw err;\n }\n}\n\n","/**\n * Quikdown Editor - A drop-in markdown editor control\n * @version 1.0.5\n * @license BSD-2-Clause\n */\n\nimport quikdown_bd from './quikdown_bd.js';\nimport { getRenderedContent } from './quikdown_edit_copy.js';\n\n// Default options\nconst DEFAULT_OPTIONS = {\n mode: 'split', // 'source' | 'preview' | 'split'\n showToolbar: true,\n showRemoveHR: false, // Show button to remove horizontal rules (---)\n showLazyLinefeeds: false, // Show button to convert lazy linefeeds\n theme: 'auto', // 'light' | 'dark' | 'auto'\n lazy_linefeeds: false,\n inline_styles: false, // Use CSS classes (false) or inline styles (true)\n debounceDelay: 20, // Reduced from 100ms for better responsiveness\n placeholder: 'Start typing markdown...',\n plugins: {\n highlightjs: false,\n mermaid: false\n },\n /**\n * Preload fence-rendering libraries at construction time so the FIRST\n * encounter with a fence type renders instantly (no lazy load delay).\n *\n * Accepts:\n * - 'all' — preload every known library\n * - ['highlightjs','mermaid','math',\n * 'geojson','stl'] — preload specific libraries\n * - [{ name: 'mylib', script: 'https://...', css: '...' }]\n * — preload an arbitrary library\n *\n * Without this, fence libraries are loaded on demand the first time their\n * fence type is encountered. That keeps the editor lightweight, but the\n * first SVG/Mermaid/Math/GeoJSON/STL fence will show \"loading...\" for a\n * moment. Set `preloadFences` if you want zero-delay rendering — at the\n * cost of a few hundred KB of upfront network.\n *\n * Developer's choice. The editor itself is still ~70 KB minified;\n * `preloadFences` only affects the OPTIONAL fence renderers.\n */\n preloadFences: null,\n customFences: {}, // { 'language': (code, lang) => html }\n enableComplexFences: true, // Enable CSV tables, math rendering, SVG, etc.\n showUndoRedo: false, // Show undo/redo toolbar buttons\n undoStackSize: 100 // Maximum number of undo states to keep\n};\n\n// Library catalog used by preloadFences. Each entry knows how to:\n// - check if the library is already on the page (so we don't double-load)\n// - load it via script (and optional CSS)\nconst FENCE_LIBRARIES = {\n highlightjs: {\n check: () => typeof window.hljs !== 'undefined',\n script: 'https://unpkg.com/@highlightjs/cdn-assets/highlight.min.js',\n css: 'https://unpkg.com/@highlightjs/cdn-assets/styles/github.min.css',\n cssDark: 'https://unpkg.com/@highlightjs/cdn-assets/styles/github-dark.min.css'\n },\n mermaid: {\n check: () => typeof window.mermaid !== 'undefined',\n script: 'https://unpkg.com/mermaid/dist/mermaid.min.js',\n afterLoad: () => {\n if (window.mermaid) window.mermaid.initialize({ startOnLoad: false });\n }\n },\n math: {\n check: () => typeof window.MathJax !== 'undefined',\n script: 'https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-svg.js',\n beforeLoad: () => {\n // Configure MathJax before loading (must be set on window before script runs)\n if (!window.MathJax) {\n window.MathJax = {\n tex: { inlineMath: [['$', '$'], ['\\\\(', '\\\\)']], displayMath: [['$$', '$$'], ['\\\\[', '\\\\]']] },\n svg: { fontCache: 'global' },\n startup: { typeset: false }\n };\n }\n }\n },\n geojson: {\n check: () => typeof window.L !== 'undefined',\n script: 'https://unpkg.com/leaflet@1.9.4/dist/leaflet.js',\n css: 'https://unpkg.com/leaflet@1.9.4/dist/leaflet.css'\n },\n stl: {\n check: () => typeof window.THREE !== 'undefined',\n script: 'https://unpkg.com/three@0.147.0/build/three.min.js'\n }\n};\n\n/**\n * Quikdown Editor - A complete markdown editing solution\n */\nclass QuikdownEditor {\n constructor(container, options = {}) {\n // Resolve container\n this.container = typeof container === 'string' \n ? document.querySelector(container) \n : container;\n \n if (!this.container) {\n throw new Error('QuikdownEditor: Invalid container');\n }\n \n // Merge options\n this.options = { ...DEFAULT_OPTIONS, ...options };\n \n // State\n this._markdown = '';\n this._html = '';\n this.currentMode = this.options.mode;\n this.updateTimer = null;\n\n // Undo/redo state\n this._undoStack = [];\n this._redoStack = [];\n this._isUndoRedo = false;\n \n // Initialize\n this.initPromise = this.init();\n }\n \n /**\n * Initialize the editor\n */\n async init() {\n // Load plugins if requested\n await this.loadPlugins();\n \n // Build UI\n this.buildUI();\n \n // Attach event listeners\n this.attachEvents();\n \n // Apply initial theme\n this.applyTheme();\n \n // Set initial mode\n this.setMode(this.currentMode);\n \n // Set initial content if provided\n if (this.options.initialContent) {\n this.setMarkdown(this.options.initialContent);\n }\n }\n \n /**\n * Build the editor UI\n */\n buildUI() {\n // Clear container\n this.container.innerHTML = '';\n \n // Add editor class\n this.container.classList.add('qde-container');\n \n // Create toolbar if enabled\n if (this.options.showToolbar) {\n this.toolbar = this.createToolbar();\n this.container.appendChild(this.toolbar);\n }\n \n // Create editor area\n this.editorArea = document.createElement('div');\n this.editorArea.className = 'qde-editor';\n \n // Create source panel\n this.sourcePanel = document.createElement('div');\n this.sourcePanel.className = 'qde-source';\n \n this.sourceTextarea = document.createElement('textarea');\n this.sourceTextarea.className = 'qde-textarea';\n this.sourceTextarea.spellcheck = false;\n this.sourceTextarea.placeholder = this.options.placeholder;\n this.sourcePanel.appendChild(this.sourceTextarea);\n \n // Create preview panel\n this.previewPanel = document.createElement('div');\n this.previewPanel.className = 'qde-preview';\n this.previewPanel.contentEditable = true;\n this.previewPanel.spellcheck = false;\n \n // Add panels to editor\n this.editorArea.appendChild(this.sourcePanel);\n this.editorArea.appendChild(this.previewPanel);\n this.container.appendChild(this.editorArea);\n \n // Add built-in styles if not already present\n this.injectStyles();\n }\n \n /**\n * Create toolbar\n */\n createToolbar() {\n const toolbar = document.createElement('div');\n toolbar.className = 'qde-toolbar';\n \n // Mode buttons\n const modes = ['source', 'split', 'preview'];\n const modeLabels = { source: 'Source', split: 'Split', preview: 'Rendered' };\n modes.forEach(mode => {\n const btn = document.createElement('button');\n btn.className = 'qde-btn';\n btn.dataset.mode = mode;\n btn.textContent = modeLabels[mode];\n btn.title = `Switch to ${modeLabels[mode]} view`;\n toolbar.appendChild(btn);\n });\n \n // Undo/Redo buttons (if enabled)\n if (this.options.showUndoRedo) {\n const undoBtn = document.createElement('button');\n undoBtn.className = 'qde-btn disabled';\n undoBtn.dataset.action = 'undo';\n undoBtn.textContent = 'Undo';\n undoBtn.title = 'Undo (Ctrl+Z)';\n toolbar.appendChild(undoBtn);\n\n const redoBtn = document.createElement('button');\n redoBtn.className = 'qde-btn disabled';\n redoBtn.dataset.action = 'redo';\n redoBtn.textContent = 'Redo';\n redoBtn.title = 'Redo (Ctrl+Shift+Z / Ctrl+Y)';\n toolbar.appendChild(redoBtn);\n }\n\n // Spacer\n const spacer = document.createElement('span');\n spacer.className = 'qde-spacer';\n toolbar.appendChild(spacer);\n \n // Copy buttons\n const copyButtons = [\n { action: 'copy-markdown', text: 'Copy MD', title: 'Copy markdown to clipboard' },\n { action: 'copy-html', text: 'Copy HTML', title: 'Copy HTML to clipboard' },\n { action: 'copy-rendered', text: 'Copy Rendered', title: 'Copy rich text to clipboard' }\n ];\n \n copyButtons.forEach(({ action, text, title }) => {\n const btn = document.createElement('button');\n btn.className = 'qde-btn';\n btn.dataset.action = action;\n btn.textContent = text;\n btn.title = title;\n toolbar.appendChild(btn);\n });\n \n // Remove HR button (if enabled)\n if (this.options.showRemoveHR) {\n const removeHRBtn = document.createElement('button');\n removeHRBtn.className = 'qde-btn';\n removeHRBtn.dataset.action = 'remove-hr';\n removeHRBtn.textContent = 'Remove HR';\n removeHRBtn.title = 'Remove all horizontal rules (---) from markdown';\n toolbar.appendChild(removeHRBtn);\n }\n\n // Lazy linefeeds button (if enabled)\n if (this.options.showLazyLinefeeds) {\n const lazyLFBtn = document.createElement('button');\n lazyLFBtn.className = 'qde-btn';\n lazyLFBtn.dataset.action = 'lazy-linefeeds';\n lazyLFBtn.textContent = 'Fix Linefeeds';\n lazyLFBtn.title = 'Convert single newlines to paragraph breaks (one-time transform)';\n toolbar.appendChild(lazyLFBtn);\n }\n \n return toolbar;\n }\n \n /**\n * Inject built-in styles\n */\n injectStyles() {\n if (document.getElementById('qde-styles')) return;\n \n const style = document.createElement('style');\n style.id = 'qde-styles';\n style.textContent = `\n .qde-container {\n display: flex;\n flex-direction: column;\n height: 100%;\n border: 1px solid #ddd;\n border-radius: 4px;\n overflow: hidden;\n background: white;\n color: #1f2937;\n }\n \n .qde-toolbar {\n display: flex;\n align-items: center;\n padding: 8px;\n background: #f5f5f5;\n border-bottom: 1px solid #ddd;\n gap: 4px;\n }\n \n .qde-btn {\n padding: 6px 12px;\n border: 1px solid #ccc;\n background: white;\n border-radius: 3px;\n cursor: pointer;\n font-size: 14px;\n transition: all 0.2s;\n }\n \n .qde-btn:hover {\n background: #e9e9e9;\n border-color: #999;\n }\n \n .qde-btn.active {\n background: #007bff;\n color: white;\n border-color: #0056b3;\n }\n\n .qde-btn.disabled {\n opacity: 0.4;\n pointer-events: none;\n }\n \n .qde-spacer {\n flex: 1;\n }\n \n .qde-editor {\n display: flex;\n flex: 1;\n overflow: hidden;\n }\n \n .qde-source, .qde-preview {\n flex: 1 1 0;\n min-width: 0; /* allow flex shrinking below content size */\n min-height: 0;\n overflow: auto;\n padding: 16px;\n box-sizing: border-box;\n }\n\n .qde-source {\n border-right: 1px solid #ddd;\n /* Source pane is just a container for the textarea — make it\n a positioning context so the textarea can fill it absolutely */\n position: relative;\n padding: 0; /* textarea brings its own padding */\n }\n\n .qde-textarea {\n display: block;\n position: absolute;\n inset: 0;\n width: 100%;\n height: 100%;\n border: none;\n outline: none;\n resize: none;\n padding: 16px;\n box-sizing: border-box;\n font-family: 'Monaco', 'Courier New', monospace;\n font-size: 14px;\n line-height: 1.5;\n background: transparent;\n color: inherit;\n /* Wrap long lines so the textarea only scrolls VERTICALLY.\n pre-wrap preserves intentional line breaks/whitespace\n while soft-wrapping at the right edge. */\n white-space: pre-wrap;\n word-wrap: break-word;\n overflow-x: hidden;\n overflow-y: auto;\n }\n \n .qde-preview {\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n font-size: 16px;\n line-height: 1.6;\n outline: none;\n cursor: text; /* Standard text cursor */\n overflow-x: hidden; /* never scroll horizontally; clip wide content */\n }\n\n /* Code blocks and inline code — self-contained so the editor\n does not depend on any external stylesheet for these. */\n .qde-preview pre {\n background: #f4f4f4;\n color: #1f2937;\n padding: 10px;\n border-radius: 4px;\n overflow-x: auto;\n margin: 0.6em 0;\n font-size: 0.9em;\n line-height: 1.5;\n font-family: ui-monospace, \"SF Mono\", Monaco, \"Cascadia Code\",\n \"Roboto Mono\", Consolas, \"Courier New\", monospace;\n }\n .qde-preview code {\n padding: 2px 4px;\n font-size: 0.9em;\n border-radius: 3px;\n background: #f0f0f0;\n color: #1f2937;\n font-family: ui-monospace, \"SF Mono\", Monaco, \"Cascadia Code\",\n \"Roboto Mono\", Consolas, \"Courier New\", monospace;\n }\n .qde-preview pre code {\n padding: 0;\n font-size: inherit;\n border-radius: 0;\n background: transparent;\n color: inherit;\n }\n\n /* Wide fence content (Leaflet maps, large SVGs, STL canvases,\n iframes, raw <img>) must never overflow the preview pane */\n .qde-preview .geojson-container,\n .qde-preview .qde-stl-container,\n .qde-preview .qde-svg-container,\n .qde-preview .leaflet-container,\n .qde-preview iframe,\n .qde-preview img,\n .qde-preview > svg {\n max-width: 100%;\n }\n .qde-preview .leaflet-container { box-sizing: border-box; }\n\n /* Standard markdown tables (the .quikdown-table class) need to\n scroll horizontally inside their own wrapper rather than\n making the whole preview pane scroll */\n .qde-preview table.quikdown-table,\n .qde-preview table.qde-csv-table {\n display: block;\n max-width: 100%;\n overflow-x: auto;\n }\n\n /* Fence-specific styles */\n .qde-svg-container {\n max-width: 100%;\n overflow: auto;\n }\n\n .qde-svg-container svg {\n max-width: 100%;\n height: auto;\n }\n \n .qde-html-container {\n /* HTML containers inherit background */\n margin: 12px 0;\n }\n \n .qde-math-container {\n text-align: center;\n margin: 16px 0;\n overflow-x: auto;\n }\n \n /* All tables in preview (both regular markdown and CSV) */\n .qde-preview table {\n width: 100%;\n border-collapse: collapse;\n margin: 12px 0;\n font-size: 14px;\n }\n \n .qde-preview table th,\n .qde-preview table td {\n border: 1px solid #ddd;\n padding: 8px;\n }\n \n /* Support for alignment classes from quikdown */\n .qde-preview .quikdown-left { text-align: left; }\n .qde-preview .quikdown-center { text-align: center; }\n .qde-preview .quikdown-right { text-align: right; }\n \n .qde-preview table th {\n background: #f5f5f5;\n font-weight: bold;\n }\n \n .qde-preview table tr:nth-child(even) {\n background: #f9f9f9;\n }\n \n /* Specific to CSV-generated tables */\n .qde-data-table {\n /* Can add specific CSV table styles here if needed */\n }\n \n .qde-json {\n /* Let highlight.js handle styling */\n overflow-x: auto;\n }\n \n .qde-error {\n background: #fee;\n border: 1px solid #fcc;\n color: #c00;\n padding: 8px;\n border-radius: 4px;\n font-family: monospace;\n font-size: 12px;\n }\n \n /* Read-only complex fence blocks in preview */\n .qde-preview [contenteditable=\"false\"] {\n cursor: auto; /* Use automatic cursor (arrow for non-text) */\n user-select: text;\n position: relative;\n }\n \n /* Reset headings inside the preview to plain browser defaults so\n parent-page styles (site navs, marketing pages, design systems)\n cannot bleed in. Business-casual: black text, decreasing sizes,\n no decorative borders. See docs/quikdown-editor.md for how\n embedders can override these with their own stylesheet. */\n .qde-preview h1 { font-size: 2em; }\n .qde-preview h2 { font-size: 1.5em; }\n .qde-preview h3 { font-size: 1.25em; }\n .qde-preview h4 { font-size: 1em; }\n .qde-preview h5 { font-size: 0.875em; }\n .qde-preview h6 { font-size: 0.85em; }\n .qde-preview h1,\n .qde-preview h2,\n .qde-preview h3,\n .qde-preview h4,\n .qde-preview h5,\n .qde-preview h6 {\n font-weight: bold;\n color: inherit;\n border: none;\n margin: 0.6em 0 0.3em 0;\n line-height: 1.25;\n }\n .qde-preview p {\n margin: 0.35em 0;\n }\n .qde-preview ul,\n .qde-preview ol {\n padding-left: 1.8em;\n margin: 0.4em 0;\n }\n .qde-preview li {\n margin: 0.15em 0;\n }\n .qde-preview blockquote {\n margin: 0.5em 0;\n padding-left: 1em;\n }\n\n /* Ensure proper cursor for editable text elements */\n .qde-preview p,\n .qde-preview h1,\n .qde-preview h2,\n .qde-preview h3,\n .qde-preview h4,\n .qde-preview h5,\n .qde-preview h6,\n .qde-preview li,\n .qde-preview td,\n .qde-preview th,\n .qde-preview blockquote,\n .qde-preview pre[contenteditable=\"true\"],\n .qde-preview code[contenteditable=\"true\"] {\n cursor: text;\n }\n \n \n /* Non-editable complex renderers */\n .qde-preview .qde-svg-container[contenteditable=\"false\"],\n .qde-preview .qde-html-container[contenteditable=\"false\"],\n .qde-preview .qde-math-container[contenteditable=\"false\"],\n .qde-preview .mermaid[contenteditable=\"false\"] {\n opacity: 0.98;\n }\n \n /* Subtle hover effect for read-only blocks */\n .qde-preview [contenteditable=\"false\"]:hover::after {\n content: \"Read-only\";\n position: absolute;\n top: 2px;\n right: 2px;\n font-size: 10px;\n color: #999;\n background: rgba(255, 255, 255, 0.9);\n padding: 2px 4px;\n border-radius: 2px;\n pointer-events: none;\n }\n \n /* Fix list padding in preview */\n .qde-preview ul,\n .qde-preview ol {\n padding-left: 2em;\n margin: 0.5em 0;\n }\n \n .qde-preview li {\n margin: 0.25em 0;\n }\n \n /* Mode-specific visibility */\n .qde-mode-source .qde-preview { display: none; }\n .qde-mode-source .qde-source { border-right: none; }\n .qde-mode-preview .qde-source { display: none; }\n .qde-mode-split .qde-source,\n .qde-mode-split .qde-preview { display: block; }\n \n /* Dark theme */\n .qde-dark {\n background: #1e1e1e;\n color: #e0e0e0;\n border-color: #444;\n }\n \n .qde-dark .qde-toolbar {\n background: #2d2d2d;\n border-color: #444;\n }\n \n .qde-dark .qde-btn {\n background: #3a3a3a;\n color: #e0e0e0;\n border-color: #555;\n }\n \n .qde-dark .qde-btn:hover {\n background: #4a4a4a;\n }\n \n .qde-dark .qde-source {\n border-color: #444;\n }\n \n .qde-dark .qde-textarea {\n background: #1e1e1e;\n color: #e0e0e0;\n }\n \n .qde-dark .qde-preview {\n background: #1e1e1e;\n color: #e0e0e0;\n }\n \n /* Dark mode code blocks */\n .qde-dark .qde-preview pre {\n background: #2d2d3a;\n color: #e6e6f0;\n }\n .qde-dark .qde-preview code {\n background: #2a2a3a;\n color: #e6e6f0;\n }\n .qde-dark .qde-preview pre code {\n background: transparent;\n color: inherit;\n }\n\n /* Dark mode table styles */\n .qde-dark .qde-preview table th,\n .qde-dark .qde-preview table td {\n border-color: #3a3a3a;\n }\n \n .qde-dark .qde-preview table th {\n background: #2d2d2d;\n }\n \n .qde-dark .qde-preview table tr:nth-child(even) {\n background: #252525;\n }\n \n /* Mobile responsive */\n @media (max-width: 768px) {\n .qde-mode-split .qde-editor {\n flex-direction: column;\n }\n\n .qde-mode-split .qde-source {\n border-right: none;\n border-bottom: 1px solid #ddd;\n }\n .qde-dark.qde-mode-split .qde-source {\n border-bottom-color: #444;\n }\n }\n `;\n \n document.head.appendChild(style);\n }\n \n /**\n * Attach event listeners\n */\n attachEvents() {\n // Source textarea input\n this.sourceTextarea.addEventListener('input', () => {\n this.handleSourceInput();\n });\n \n // Preview contenteditable input\n this.previewPanel.addEventListener('input', () => {\n this.handlePreviewInput();\n });\n \n // Toolbar buttons\n if (this.toolbar) {\n this.toolbar.addEventListener('click', (e) => {\n const btn = e.target.closest('.qde-btn');\n if (!btn) return;\n \n if (btn.dataset.mode) {\n this.setMode(btn.dataset.mode);\n } else if (btn.dataset.action) {\n this.handleAction(btn.dataset.action);\n }\n });\n }\n \n // Keyboard shortcuts\n document.addEventListener('keydown', (e) => {\n if (e.ctrlKey || e.metaKey) {\n switch(e.key) {\n case '1':\n e.preventDefault();\n this.setMode('source');\n break;\n case '2':\n e.preventDefault();\n this.setMode('split');\n break;\n case '3':\n e.preventDefault();\n this.setMode('preview');\n break;\n case 'z':\n case 'Z':\n if (e.shiftKey) {\n e.preventDefault();\n this.redo();\n } else {\n e.preventDefault();\n this.undo();\n }\n break;\n case 'y':\n case 'Y':\n e.preventDefault();\n this.redo();\n break;\n }\n }\n });\n }\n \n /**\n * Handle source textarea input\n */\n handleSourceInput() {\n clearTimeout(this.updateTimer);\n this.updateTimer = setTimeout(() => {\n this.updateFromMarkdown(this.sourceTextarea.value);\n }, this.options.debounceDelay);\n }\n \n /**\n * Handle preview panel input\n */\n handlePreviewInput() {\n clearTimeout(this.updateTimer);\n this.updateTimer = setTimeout(() => {\n this.updateFromHTML();\n }, this.options.debounceDelay);\n }\n \n /**\n * Update from markdown source\n */\n updateFromMarkdown(markdown) {\n // Push current state to undo stack before changing (unless this is an undo/redo operation)\n if (!this._isUndoRedo) {\n this._pushUndoState(markdown || '');\n }\n this._isUndoRedo = false;\n\n this._markdown = markdown || '';\n \n // Show placeholder if empty\n if (!this._markdown.trim()) {\n this._html = '';\n if (this.currentMode !== 'source') {\n this.previewPanel.innerHTML = '<div style=\"color: #999; font-style: italic; padding: 16px;\">Start typing markdown in the source panel...</div>';\n }\n } else {\n this._html = quikdown_bd(markdown, {\n fence_plugin: this.createFencePlugin(),\n lazy_linefeeds: this.options.lazy_linefeeds,\n inline_styles: this.options.inline_styles\n });\n \n // Update preview if visible\n if (this.currentMode !== 'source') {\n this.previewPanel.innerHTML = this._html;\n // Make all fence blocks non-editable\n this.makeFencesNonEditable();\n \n // Process all math elements with MathJax if loaded (like squibview)\n if (window.MathJax && window.MathJax.typesetPromise) {\n const mathElements = this.previewPanel.querySelectorAll('.math-display');\n if (mathElements.length > 0) {\n window.MathJax.typesetPromise(Array.from(mathElements))\n .catch(_err => {\n console.warn('MathJax batch processing failed:', _err);\n });\n }\n }\n }\n }\n \n // Trigger change event\n if (this.options.onChange) {\n this.options.onChange(this._markdown, this._html);\n }\n }\n \n /**\n * Update from HTML preview\n */\n updateFromHTML() {\n // Clone the preview panel to avoid modifying the actual DOM\n const clonedPanel = this.previewPanel.cloneNode(true);\n\n // Pre-process special elements on the clone\n this.preprocessSpecialElements(clonedPanel);\n\n this._html = this.previewPanel.innerHTML;\n const newMarkdown = quikdown_bd.toMarkdown(clonedPanel, {\n fence_plugin: this.createFencePlugin()\n });\n\n // Push previous state to undo stack (now that we know the new markdown)\n if (!this._isUndoRedo) {\n this._pushUndoState(newMarkdown);\n }\n this._isUndoRedo = false;\n\n this._markdown = newMarkdown;\n\n // Update source if visible\n if (this.currentMode !== 'preview') {\n this.sourceTextarea.value = this._markdown;\n }\n\n // Trigger change event\n if (this.options.onChange) {\n this.options.onChange(this._markdown, this._html);\n }\n\n this._updateUndoButtons();\n }\n \n /**\n * Pre-process special elements before markdown conversion\n */\n preprocessSpecialElements(panel) {\n if (!panel) return;\n \n // Restore non-editable complex fences from their data attributes\n const complexFences = panel.querySelectorAll('[contenteditable=\"false\"][data-qd-source]');\n complexFences.forEach(element => {\n const source = element.getAttribute('data-qd-source');\n const fence = element.getAttribute('data-qd-fence') || '```';\n const lang = element.getAttribute('data-qd-lang') || '';\n \n // Create a pre element with the original source\n const pre = document.createElement('pre');\n pre.setAttribute('data-qd-fence', fence);\n if (lang) pre.setAttribute('data-qd-lang', lang);\n const code = document.createElement('code');\n // The source is already the original unescaped content when using setAttribute\n // No need to unescape since browser handles it automatically\n code.textContent = source;\n pre.appendChild(code);\n \n // Replace the complex element with pre\n element.parentNode.replaceChild(pre, element);\n });\n \n // Convert CSV tables back to CSV fence blocks (these ARE editable)\n const csvTables = panel.querySelectorAll('table.qde-csv-table[data-qd-lang]');\n csvTables.forEach(table => {\n const lang = table.getAttribute('data-qd-lang');\n if (!lang || !['csv', 'psv', 'tsv'].includes(lang)) return;\n \n const delimiter = lang === 'csv' ? ',' : lang === 'psv' ? '|' : '\\t';\n \n // Extract data from table\n let csv = '';\n \n // Get headers\n const headers = [];\n const headerCells = table.querySelectorAll('thead th');\n headerCells.forEach(th => {\n const text = th.textContent.trim();\n // Quote if contains delimiter or quotes\n const needsQuoting = text.includes(delimiter) || text.includes('\"') || text.includes('\\n');\n headers.push(needsQuoting ? `\"${text.replace(/\"/g, '\"\"')}\"` : text);\n });\n csv += headers.join(delimiter) + '\\n';\n \n // Get rows\n const rows = table.querySelectorAll('tbody tr');\n rows.forEach(tr => {\n const cells = [];\n tr.querySelectorAll('td').forEach(td => {\n const text = td.textContent.trim();\n const needsQuoting = text.includes(delimiter) || text.includes('\"') || text.includes('\\n');\n cells.push(needsQuoting ? `\"${text.replace(/\"/g, '\"\"')}\"` : text);\n });\n csv += cells.join(delimiter) + '\\n';\n });\n \n // Create a pre element with the CSV data\n const pre = document.createElement('pre');\n pre.setAttribute('data-qd-fence', '```');\n pre.setAttribute('data-qd-lang', lang);\n const code = document.createElement('code');\n code.textContent = csv.trim();\n pre.appendChild(code);\n \n // Replace table with pre\n table.parentNode.replaceChild(pre, table);\n });\n }\n \n /**\n * Create fence plugin for syntax highlighting\n */\n createFencePlugin() {\n const render = (code, lang) => {\n // Check custom fences first (they take precedence)\n if (this.options.customFences && this.options.customFences[lang]) {\n try {\n return this.options.customFences[lang](code, lang);\n } catch (err) {\n console.error(`Custom fence plugin error for ${lang}:`, err);\n return `<pre><code class=\"language-${lang}\">${this.escapeHtml(code)}</code></pre>`;\n }\n }\n \n // For bidirectional editing, only apply syntax highlighting\n // Skip complex transformations that break round-trip conversion\n const skipComplexRendering = !this.options.enableComplexFences;\n \n if (!skipComplexRendering) {\n // Built-in lazy loading fence handlers (disabled for now)\n switch(lang) {\n case 'svg':\n return this.renderSVG(code);\n \n case 'html':\n return this.renderHTML(code);\n \n case 'math':\n case 'tex':\n case 'latex':\n return this.renderMath(code, lang);\n \n case 'csv':\n case 'psv':\n case 'tsv':\n return this.renderTable(code, lang);\n \n case 'json':\n case 'json5':\n return this.renderJSON(code, lang);\n \n case 'katex': // Use MathJax for katex fence blocks (backward compatibility)\n return this.renderMath(code, 'katex');\n \n case 'mermaid':\n if (window.mermaid) {\n return this.renderMermaid(code);\n }\n break;\n \n case 'geojson':\n return this.renderGeoJSON(code);\n \n case 'stl':\n return this.renderSTL(code);\n }\n }\n \n // Syntax highlighting support - keep editable for bidirectional\n if (window.hljs && lang && hljs.getLanguage(lang)) {\n const highlighted = hljs.highlight(code, { language: lang }).value;\n // Don't add contenteditable=\"false\" - the bidirectional system can extract text from the highlighted code\n return `<pre data-qd-fence=\"\\`\\`\\`\" data-qd-lang=\"${lang}\"><code class=\"hljs language-${lang}\">${highlighted}</code></pre>`;\n }\n \n // Default: let quikdown handle it\n return undefined;\n };\n \n // Reverse function to extract raw source from rendered HTML\n const reverse = (element) => {\n // Get the language from data attribute\n const lang = element.getAttribute('data-qd-lang') || '';\n let content = '';\n \n // For syntax-highlighted code, extract the raw text\n if (element.querySelector('code.hljs')) {\n const code = element.querySelector('code.hljs');\n content = code.textContent || code.innerText || '';\n }\n // For other code blocks, just get the text content\n else if (element.querySelector('code')) {\n const codeEl = element.querySelector('code');\n content = codeEl.textContent || codeEl.innerText || '';\n }\n // Fallback to element text\n else {\n content = element.textContent || element.innerText || '';\n }\n \n // Return in the format quikdown_bd expects\n return {\n content: content,\n lang: lang,\n fence: '```'\n };\n };\n \n // Return object format for v1.1.0 API with both render and reverse\n return { render, reverse };\n }\n \n /**\n * Render SVG content\n */\n renderSVG(code) {\n try {\n // Basic SVG validation\n const parser = new DOMParser();\n const doc = parser.parseFromString(code, 'image/svg+xml');\n const parseError = doc.querySelector('parsererror');\n \n if (parseError) {\n throw new Error('Invalid SVG');\n }\n \n // Sanitize SVG by removing script tags and event handlers\n const svg = doc.documentElement;\n svg.querySelectorAll('script').forEach(el => el.remove());\n \n // Remove event handlers\n const walker = document.createTreeWalker(svg, NodeFilter.SHOW_ELEMENT);\n let node;\n while ((node = walker.nextNode())) {\n for (let i = node.attributes.length - 1; i >= 0; i--) {\n const attr = node.attributes[i];\n if (attr.name.startsWith('on') || attr.value.includes('javascript:')) {\n node.removeAttribute(attr.name);\n }\n }\n }\n \n // Create container element programmatically to avoid attribute escaping issues\n const container = document.createElement('div');\n container.className = 'qde-svg-container';\n container.contentEditable = 'false';\n container.setAttribute('data-qd-fence', '```');\n container.setAttribute('data-qd-lang', 'svg');\n container.setAttribute('data-qd-source', code); // No escaping needed when using setAttribute!\n container.innerHTML = new XMLSerializer().serializeToString(svg);\n \n // Return the HTML string\n return container.outerHTML;\n } catch (err) {\n const errorContainer = document.createElement('pre');\n errorContainer.className = 'qde-error';\n errorContainer.contentEditable = 'false';\n errorContainer.setAttribute('data-qd-fence', '```');\n errorContainer.setAttribute('data-qd-lang', 'svg');\n errorContainer.textContent = `Invalid SVG: ${err.message}`;\n return errorContainer.outerHTML;\n }\n }\n \n /**\n * Render HTML content with DOMPurify if available\n */\n renderHTML(code) {\n const id = `html-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;\n \n // If DOMPurify is loaded, use it\n if (window.DOMPurify) {\n const clean = DOMPurify.sanitize(code);\n \n // Create container programmatically\n const container = document.createElement('div');\n container.className = 'qde-html-container';\n container.contentEditable = 'false';\n container.setAttribute('data-qd-fence', '```');\n container.setAttribute('data-qd-lang', 'html');\n container.setAttribute('data-qd-source', code);\n container.innerHTML = clean;\n \n return container.outerHTML;\n }\n \n // Try to lazy load DOMPurify\n this.lazyLoadLibrary(\n 'DOMPurify',\n () => window.DOMPurify,\n 'https://unpkg.com/dompurify/dist/purify.min.js'\n ).then(loaded => {\n if (loaded) {\n const element = document.getElementById(id);\n if (element) {\n const clean = DOMPurify.sanitize(code);\n element.innerHTML = clean;\n // Update attributes after loading\n element.setAttribute('data-qd-source', code);\n element.setAttribute('data-qd-fence', '```');\n element.setAttribute('data-qd-lang', 'html');\n }\n }\n });\n \n // Return placeholder with bidirectional attributes - non-editable\n const placeholder = document.createElement('div');\n placeholder.id = id;\n placeholder.className = 'qde-html-container';\n placeholder.contentEditable = 'false';\n placeholder.setAttribute('data-qd-fence', '```');\n placeholder.setAttribute('data-qd-lang', 'html');\n placeholder.setAttribute('data-qd-source', code);\n const pre = document.createElement('pre');\n pre.textContent = code;\n placeholder.appendChild(pre);\n \n return placeholder.outerHTML;\n }\n \n /**\n * Render math with MathJax (SVG output for better copy support)\n */\n renderMath(code, _lang) {\n const id = `math-${Math.random().toString(36).substring(2, 15)}`;\n \n // Create container exactly like squibview\n const container = document.createElement('div');\n container.id = id;\n container.className = 'math-display';\n container.contentEditable = 'false';\n container.setAttribute('data-source-type', 'math');\n \n // Format content for MathJax (display mode with $$) - exactly like squibview\n const singleLineContent = code.replace(/\\r?\\n/g, ' ').replace(/\\s+/g, ' ').trim();\n container.textContent = `$$${singleLineContent}$$`;\n \n // Add centering style\n container.style.textAlign = 'center';\n container.style.margin = '1em 0';\n \n \n // Ensure MathJax will be loaded (if not already)\n if (!window.MathJax || !window.MathJax.typesetPromise) {\n this.ensureMathJaxLoaded();\n }\n \n // MathJax will be processed in batch after preview update\n return container.outerHTML;\n }\n \n /**\n * Ensures MathJax is loaded (but doesn't process elements)\n */\n ensureMathJaxLoaded() {\n if (typeof window.MathJax === 'undefined' && !window.mathJaxLoading) {\n window.mathJaxLoading = true;\n \n // Configure MathJax before loading\n if (!window.MathJax) {\n window.MathJax = {\n loader: { load: ['input/tex', 'output/svg'] },\n tex: { \n packages: { '[+]': ['ams'] },\n inlineMath: [['$', '$'], ['\\\\(', '\\\\)']],\n displayMath: [['$$', '$$'], ['\\\\[', '\\\\]']],\n processEscapes: true,\n processEnvironments: true\n },\n options: {\n renderActions: { addMenu: [] },\n ignoreHtmlClass: 'tex2jax_ignore',\n processHtmlClass: 'tex2jax_process'\n },\n svg: {\n fontCache: 'none' // Important: self-contained SVGs for copy\n },\n startup: { typeset: false }\n };\n }\n \n const script = document.createElement('script');\n script.src = 'https://cdn.jsdelivr.net/npm/mathjax@3.2.2/es5/tex-svg.js';\n script.async = true;\n script.onload = () => {\n window.mathJaxLoading = false;\n \n // Process any existing math elements (like squibview)\n if (window.MathJax && window.MathJax.typesetPromise) {\n const mathElements = document.querySelectorAll('.math-display');\n if (mathElements.length > 0) {\n window.MathJax.typesetPromise(Array.from(mathElements)).catch(err => {\n console.warn('Initial MathJax processing failed:', err);\n });\n }\n }\n };\n script.onerror = () => {\n window.mathJaxLoading = false;\n console.error('Failed to load MathJax');\n };\n document.head.appendChild(script);\n }\n }\n \n /**\n * Render CSV/PSV/TSV as HTML table\n */\n renderTable(code, lang) {\n const escapedCode = this.escapeHtml(code);\n try {\n const delimiter = lang === 'csv' ? ',' : lang === 'psv' ? '|' : '\\t';\n const lines = code.trim().split('\\n');\n \n if (lines.length === 0) {\n return `<pre data-qd-fence=\"\\`\\`\\`\" data-qd-lang=\"${lang}\" data-qd-source=\"${escapedCode}\">${escapedCode}</pre>`;\n }\n \n // CSV tables CAN be editable - we'll convert HTML table back to CSV\n // Don't need data-qd-source since we convert the table structure back to CSV\n let html = `<table class=\"qde-data-table qde-csv-table\" data-qd-fence=\"\\`\\`\\`\" data-qd-lang=\"${lang}\">`;\n \n // Parse header\n const header = this.parseCSVLine(lines[0], delimiter);\n html += '<thead><tr>';\n header.forEach(cell => {\n html += `<th>${this.escapeHtml(cell.trim())}</th>`;\n });\n html += '</tr></thead>';\n \n // Parse body\n if (lines.length > 1) {\n html += '<tbody>';\n for (let i = 1; i < lines.length; i++) {\n const row = this.parseCSVLine(lines[i], delimiter);\n html += '<tr>';\n row.forEach(cell => {\n html += `<td>${this.escapeHtml(cell.trim())}</td>`;\n });\n html += '</tr>';\n }\n html += '</tbody>';\n }\n \n html += '</table>';\n return html;\n } catch (_err) {\n return `<pre data-qd-fence=\"\\`\\`\\`\" data-qd-lang=\"${lang}\" data-qd-source=\"${escapedCode}\">${escapedCode}</pre>`;\n }\n }\n\n /**\n * Parse CSV line handling quoted values\n */\n parseCSVLine(line, delimiter) {\n const result = [];\n let current = '';\n let inQuotes = false;\n \n for (let i = 0; i < line.length; i++) {\n const char = line[i];\n const nextChar = line[i + 1];\n \n if (char === '\"') {\n if (inQuotes && nextChar === '\"') {\n current += '\"';\n i++; // Skip next quote\n } else {\n inQuotes = !inQuotes;\n }\n } else if (char === delimiter && !inQuotes) {\n result.push(current);\n current = '';\n } else {\n current += char;\n }\n }\n \n result.push(current);\n return result;\n }\n \n /**\n * Render JSON with syntax highlighting\n */\n renderJSON(code, lang) {\n // If highlight.js is available, use it for all JSON\n if (window.hljs && hljs.getLanguage('json')) {\n try {\n // Try to format if valid JSON\n let toHighlight = code;\n try {\n const data = JSON.parse(code);\n toHighlight = JSON.stringify(data, null, 2);\n } catch (_e) {\n // Use original if not valid JSON\n }\n \n const highlighted = hljs.highlight(toHighlight, { language: 'json' }).value;\n return `<pre class=\"qde-json\" data-qd-fence=\"\\`\\`\\`\" data-qd-lang=\"${lang}\"><code class=\"hljs language-json\">${highlighted}</code></pre>`;\n } catch (_e) {\n // Fall through if highlighting fails\n }\n }\n \n // No highlighting available - return plain\n return `<pre class=\"qde-json\" data-qd-fence=\"\\`\\`\\`\" data-qd-lang=\"${lang}\">${this.escapeHtml(code)}</pre>`;\n }\n \n /**\n * Render GeoJSON map\n */\n renderGeoJSON(code) {\n // Generate unique map ID (following SquibView pattern)\n const mapId = `map-${Math.random().toString(36).substr(2, 15)}`;\n \n // Function to render the map\n const renderMap = () => {\n const container = document.getElementById(mapId + '-container');\n if (!container || !window.L) return;\n \n try {\n const data = JSON.parse(code);\n \n // Clear container and set deterministic size for rasterization\n const mapDiv = document.createElement('div');\n mapDiv.id = mapId;\n mapDiv.style.cssText = 'width: 100%; height: 300px;';\n container.innerHTML = '';\n container.appendChild(mapDiv);\n \n // Create the map\n const map = L.map(mapId);\n \n // Store back-reference for capture (per Gem's guide)\n container._map = map; // Avoid window pollution\n \n // Add tile layer with CORS support\n const tileLayer = L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {\n attribution: '',\n crossOrigin: 'anonymous' // Important for canvas capture\n });\n tileLayer.addTo(map);\n \n // Add GeoJSON layer\n const geoJsonLayer = L.geoJSON(data);\n geoJsonLayer.addTo(map);\n \n // Fit bounds if valid\n if (geoJsonLayer.getBounds().isValid()) {\n map.fitBounds(geoJsonLayer.getBounds());\n } else {\n map.setView([0, 0], 2);\n }\n \n // Store references for copy-time capture\n container._tileLayer = tileLayer;\n container._geoJsonLayer = geoJsonLayer;\n \n // Optional: Wait for tiles to load for better capture\n tileLayer.on('load', () => {\n container.setAttribute('data-tiles-loaded', 'true');\n });\n \n } catch (err) {\n container.innerHTML = `<pre class=\"qde-error\">GeoJSON error: ${this.escapeHtml(err.message)}</pre>`;\n }\n };\n \n // Check if Leaflet is already loaded\n if (window.L) {\n // Render after DOM update\n setTimeout(renderMap, 0);\n } else {\n // Lazy load Leaflet only if not already loading\n if (!window._qde_leaflet_loading) {\n window._qde_leaflet_loading = this.lazyLoadLibrary(\n 'Leaflet',\n () => window.L,\n 'https://unpkg.com/leaflet@1.9.4/dist/leaflet.js',\n 'https://unpkg.com/leaflet@1.9.4/dist/leaflet.css'\n ).catch(err => {\n console.warn('Failed to load Leaflet:', err);\n // Clear the loading promise so it can be retried\n window._qde_leaflet_loading = null;\n return false;\n });\n }\n \n window._qde_leaflet_loading.then(loaded => {\n if (loaded) {\n renderMap();\n } else {\n const element = document.getElementById(mapId + '-container');\n if (element) {\n element.innerHTML = '<div style=\"padding: 20px; text-align: center; color: #666;\">Failed to load map library</div>';\n }\n }\n }).catch(() => {\n // Error already handled above\n });\n }\n \n // Return container following SquibView pattern\n const container = document.createElement('div');\n container.className = 'geojson-container';\n container.id = mapId + '-container';\n container.style.cssText = 'width: 100%; height: 300px; border: 1px solid #ddd; border-radius: 4px; margin: 0.5em 0; background: #f0f0f0;';\n container.contentEditable = 'false';\n \n // Preserve source for copy-time identification (per Gem's guide)\n container.setAttribute('data-source-type', 'geojson');\n container.setAttribute('data-original-source', this.escapeHtml(code));\n \n // For bidirectional editing\n container.setAttribute('data-qd-fence', '```');\n container.setAttribute('data-qd-lang', 'geojson');\n container.setAttribute('data-qd-source', code);\n \n container.textContent = 'Loading map...';\n \n return container.outerHTML;\n }\n \n /**\n * Render STL 3D model\n */\n renderSTL(code) {\n const id = `qde-stl-viewer-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;\n\n // Function to render the 3D model (assumes window.THREE is loaded)\n const render3D = () => {\n const element = document.getElementById(id);\n if (!element) return;\n\n try {\n const THREE = window.THREE;\n \n // Create scene\n const scene = new THREE.Scene();\n scene.background = new THREE.Color(0xf0f0f0);\n \n // Create camera\n const camera = new THREE.PerspectiveCamera(75, element.clientWidth / 400, 0.1, 1000);\n \n // Create renderer\n const renderer = new THREE.WebGLRenderer({ antialias: true });\n renderer.setSize(element.clientWidth, 400);\n element.innerHTML = '';\n element.appendChild(renderer.domElement);\n \n // Store Three.js references for copy functionality (like squibview)\n element._threeScene = scene;\n element._threeCamera = camera;\n element._threeRenderer = renderer;\n \n // Parse STL data (ASCII format)\n const geometry = this.parseSTL(code);\n const material = new THREE.MeshLambertMaterial({ color: 0x0066ff });\n const mesh = new THREE.Mesh(geometry, material);\n scene.add(mesh);\n \n // Add lighting\n const ambientLight = new THREE.AmbientLight(0x404040, 0.6);\n scene.add(ambientLight);\n \n const directionalLight = new THREE.DirectionalLight(0xffffff, 0.8);\n directionalLight.position.set(1, 1, 1).normalize();\n scene.add(directionalLight);\n \n // Position camera based on object bounds\n const box = new THREE.Box3().setFromObject(mesh);\n const center = box.getCenter(new THREE.Vector3());\n const size = box.getSize(new THREE.Vector3());\n const maxDim = Math.max(size.x, size.y, size.z);\n \n camera.position.set(center.x + maxDim, center.y + maxDim, center.z + maxDim);\n camera.lookAt(center);\n \n // Animate\n const animate = () => {\n requestAnimationFrame(animate);\n mesh.rotation.y += 0.01;\n renderer.render(scene, camera);\n };\n animate();\n } catch (err) {\n console.error('STL rendering error:', err);\n element.innerHTML = `<pre class=\"qde-error\">STL error: ${this.escapeHtml(err.message)}</pre>`;\n }\n };\n \n // If Three.js is already loaded, render immediately. Otherwise lazy-load\n // it from a CDN (matches the GeoJSON/Leaflet pattern).\n if (window.THREE) {\n setTimeout(render3D, 0);\n } else {\n if (!window._qde_three_loading) {\n window._qde_three_loading = this.lazyLoadLibrary(\n 'Three.js',\n () => window.THREE,\n 'https://unpkg.com/three@0.147.0/build/three.min.js'\n ).catch(_err => {\n console.warn('Failed to load Three.js for STL rendering');\n window._qde_three_loading = null;\n return false;\n });\n }\n window._qde_three_loading.then(loaded => {\n if (loaded) {\n render3D();\n } else {\n const element = document.getElementById(id);\n if (element) {\n element.innerHTML = '<div style=\"padding: 20px; text-align: center; color: #666;\">Failed to load Three.js for STL rendering</div>';\n }\n }\n });\n }\n\n // Return placeholder with data-stl-id for copy functionality\n return `<div id=\"${id}\" class=\"qde-stl-container\" data-stl-id=\"${id}\" data-qd-fence=\"\\`\\`\\`\" data-qd-lang=\"stl\" data-qd-source=\"${this.escapeHtml(code)}\" contenteditable=\"false\" style=\"height: 400px; background: #f0f0f0; display: flex; align-items: center; justify-content: center;\">Loading 3D model...</div>`;\n }\n \n /**\n * Parse ASCII STL format\n * @param {string} stlData - The STL file content\n * @returns {THREE.BufferGeometry} - The parsed geometry\n */\n parseSTL(stlData) {\n const THREE = window.THREE;\n const geometry = new THREE.BufferGeometry();\n const vertices = [];\n const normals = [];\n \n const lines = stlData.split('\\n');\n let currentNormal = null;\n \n for (let line of lines) {\n line = line.trim();\n \n if (line.startsWith('facet normal')) {\n const parts = line.split(/\\s+/);\n currentNormal = [parseFloat(parts[2]), parseFloat(parts[3]), parseFloat(parts[4])];\n } else if (line.startsWith('vertex')) {\n const parts = line.split(/\\s+/);\n vertices.push(parseFloat(parts[1]), parseFloat(parts[2]), parseFloat(parts[3]));\n if (currentNormal) {\n normals.push(currentNormal[0], currentNormal[1], currentNormal[2]);\n }\n }\n }\n \n geometry.setAttribute('position', new THREE.Float32BufferAttribute(vertices, 3));\n geometry.setAttribute('normal', new THREE.Float32BufferAttribute(normals, 3));\n \n return geometry;\n }\n \n /**\n * Render Mermaid diagram\n */\n renderMermaid(code) {\n const id = `mermaid-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;\n setTimeout(() => {\n const element = document.getElementById(id);\n if (element && window.mermaid) {\n mermaid.render(id + '-svg', code).then(result => {\n element.innerHTML = result.svg;\n }).catch(err => {\n element.innerHTML = `<pre>Error rendering diagram: ${err.message}</pre>`;\n });\n }\n }, 0);\n \n // Create container programmatically\n const container = document.createElement('div');\n container.id = id;\n container.className = 'mermaid';\n container.contentEditable = 'false';\n container.setAttribute('data-qd-source', code);\n container.setAttribute('data-qd-fence', '```');\n container.setAttribute('data-qd-lang', 'mermaid');\n container.textContent = 'Loading diagram...';\n \n return container.outerHTML;\n }\n \n /**\n * Escape HTML for attributes\n */\n escapeHtml(text) {\n return (text ?? \"\").replace(/[&\"'<>]/g, m => \n ({'&':'&amp;','\"':'&quot;',\"'\":'&#39;','<':'&lt;','>':'&gt;'}[m]));\n }\n \n /**\n * Make complex fence blocks non-editable\n */\n makeFencesNonEditable() {\n if (!this.previewPanel) return;\n \n // Only make specific complex fence types non-editable\n // SVG, HTML, Math, Mermaid already have contenteditable=\"false\" set\n // Syntax-highlighted code also has it set\n \n // Don't make regular code blocks or tables non-editable\n // They can be edited and properly round-trip\n }\n \n /**\n * Load plugins dynamically — honors both `plugins: { highlightjs, mermaid }`\n * (legacy) and the newer `preloadFences` option which can preload any\n * combination of fence libraries (or 'all') at construction time.\n */\n async loadPlugins() {\n const namesToLoad = new Set();\n\n // Legacy plugins option\n if (this.options.plugins) {\n if (this.options.plugins.highlightjs) namesToLoad.add('highlightjs');\n if (this.options.plugins.mermaid) namesToLoad.add('mermaid');\n }\n\n // New preloadFences option\n const pf = this.options.preloadFences;\n if (pf === 'all') {\n Object.keys(FENCE_LIBRARIES).forEach(n => namesToLoad.add(n));\n } else if (Array.isArray(pf)) {\n for (const entry of pf) {\n if (typeof entry === 'string') {\n if (FENCE_LIBRARIES[entry]) namesToLoad.add(entry);\n else console.warn(`QuikdownEditor: unknown preloadFences entry \"${entry}\"`);\n } else if (entry && typeof entry === 'object' && entry.script) {\n // Custom library: { name, script, css? }\n namesToLoad.add('__custom__:' + (entry.name || entry.script));\n FENCE_LIBRARIES['__custom__:' + (entry.name || entry.script)] = {\n check: () => false,\n script: entry.script,\n css: entry.css\n };\n }\n }\n } else if (pf) {\n console.warn('QuikdownEditor: preloadFences should be \"all\", an array, or null');\n }\n\n // Load each in parallel; respect already-loaded state\n const promises = [];\n for (const name of namesToLoad) {\n const lib = FENCE_LIBRARIES[name];\n if (!lib || lib.check()) continue;\n if (lib.beforeLoad) lib.beforeLoad();\n const p = (async () => {\n try {\n const tasks = [];\n if (lib.script) tasks.push(this.loadScript(lib.script));\n if (lib.css) tasks.push(this.loadCSS(lib.css, 'qde-hljs-light'));\n if (lib.cssDark) tasks.push(this.loadCSS(lib.cssDark, 'qde-hljs-dark'));\n await Promise.all(tasks);\n if (lib.css && lib.cssDark) this._syncHljsTheme();\n if (lib.afterLoad) lib.afterLoad();\n } catch (err) {\n console.warn(`QuikdownEditor: failed to preload ${name}:`, err);\n }\n })();\n promises.push(p);\n }\n\n await Promise.all(promises);\n }\n \n /**\n * Lazy load library if not already loaded\n */\n async lazyLoadLibrary(name, check, scriptUrl, cssUrl = null) {\n // Check if library is already loaded\n if (check()) {\n return true;\n }\n \n try {\n const promises = [];\n \n // Load script\n if (scriptUrl) {\n promises.push(this.loadScript(scriptUrl));\n }\n \n // Load CSS if provided\n if (cssUrl) {\n promises.push(this.loadCSS(cssUrl));\n }\n \n await Promise.all(promises);\n \n // Verify library loaded\n return check();\n } catch (err) {\n console.error(`Failed to load ${name}:`, err);\n return false;\n }\n }\n \n /**\n * Load external script\n */\n loadScript(src) {\n return new Promise((resolve, reject) => {\n const script = document.createElement('script');\n script.src = src;\n script.onload = resolve;\n script.onerror = reject;\n document.head.appendChild(script);\n });\n }\n \n /**\n * Load external CSS\n */\n loadCSS(href, id) {\n return new Promise((resolve) => {\n const link = document.createElement('link');\n link.rel = 'stylesheet';\n link.href = href;\n if (id) link.id = id;\n link.onload = resolve;\n document.head.appendChild(link);\n // Resolve anyway after timeout (CSS doesn't always fire onload)\n setTimeout(resolve, 1000);\n });\n }\n\n /**\n * Enable the hljs stylesheet matching the current theme and disable\n * the other one. Called from applyTheme and after hljs CSS loads.\n */\n _syncHljsTheme() {\n const isDark = this.container.classList.contains('qde-dark');\n const light = document.getElementById('qde-hljs-light');\n const dark = document.getElementById('qde-hljs-dark');\n if (light) light.disabled = isDark;\n if (dark) dark.disabled = !isDark;\n }\n\n /**\n * Apply the current theme (based on this.options.theme)\n */\n applyTheme() {\n const theme = this.options.theme;\n\n // Tear down any previous auto-mode listener so we don't stack them\n if (this._autoThemeListener) {\n window.matchMedia('(prefers-color-scheme: dark)').removeEventListener('change', this._autoThemeListener);\n this._autoThemeListener = null;\n }\n\n if (theme === 'auto') {\n const mq = window.matchMedia('(prefers-color-scheme: dark)');\n this.container.classList.toggle('qde-dark', mq.matches);\n this._autoThemeListener = (e) => {\n this.container.classList.toggle('qde-dark', e.matches);\n this._syncHljsTheme();\n };\n mq.addEventListener('change', this._autoThemeListener);\n } else {\n this.container.classList.toggle('qde-dark', theme === 'dark');\n }\n this._syncHljsTheme();\n }\n\n /**\n * Set theme at runtime. Accepts 'light', 'dark', or 'auto'.\n * @param {'light'|'dark'|'auto'} theme\n */\n setTheme(theme) {\n if (!['light', 'dark', 'auto'].includes(theme)) return;\n this.options.theme = theme;\n this.applyTheme();\n }\n\n /**\n * Get the current theme option (as configured, not resolved).\n * @returns {'light'|'dark'|'auto'}\n */\n getTheme() {\n return this.options.theme;\n }\n \n /**\n * Set lazy linefeeds option\n * @param {boolean} enabled - Whether to enable lazy linefeeds\n */\n setLazyLinefeeds(enabled) {\n this.options.lazy_linefeeds = enabled;\n // Re-render if we have content\n if (this._markdown) {\n this.updateFromMarkdown(this._markdown);\n }\n }\n \n /**\n * Get lazy linefeeds option\n * @returns {boolean}\n */\n getLazyLinefeeds() {\n return this.options.lazy_linefeeds;\n }\n \n /**\n * Set debounce delay for input updates\n * @param {number} delay - Delay in milliseconds (0 for instant)\n */\n setDebounceDelay(delay) {\n this.options.debounceDelay = Math.max(0, delay);\n }\n \n /**\n * Get current debounce delay\n * @returns {number} Delay in milliseconds\n */\n getDebounceDelay() {\n return this.options.debounceDelay;\n }\n \n /**\n * Set editor mode\n */\n setMode(mode) {\n if (!['source', 'preview', 'split'].includes(mode)) return;\n\n // Preserve theme class across mode swap (the assignment to className\n // below would otherwise wipe it out — this used to be a no-op bug\n // where dark mode was lost on every setMode call).\n const wasDark = this.container.classList.contains('qde-dark');\n\n this.currentMode = mode;\n this.container.className = `qde-container qde-mode-${mode}`;\n if (wasDark) {\n this.container.classList.add('qde-dark');\n }\n\n // Update toolbar buttons\n if (this.toolbar) {\n this.toolbar.querySelectorAll('.qde-btn[data-mode]').forEach(btn => {\n btn.classList.toggle('active', btn.dataset.mode === mode);\n });\n }\n \n // Make fence blocks non-editable when showing preview\n if (mode !== 'source') {\n setTimeout(() => this.makeFencesNonEditable(), 0);\n }\n \n // Trigger mode change event\n if (this.options.onModeChange) {\n this.options.onModeChange(mode);\n }\n }\n \n // --- Undo / Redo ---\n\n /**\n * Push current markdown state onto the undo stack (called before a change).\n * Only pushes if the new state differs from the current state.\n * @param {string} newMarkdown - the incoming markdown (used to detect no-op)\n * @private\n */\n _pushUndoState(newMarkdown) {\n // Don't push if the content hasn't actually changed\n if (newMarkdown === this._markdown) return;\n\n this._undoStack.push(this._markdown);\n\n // Enforce max stack size\n const max = this.options.undoStackSize || 100;\n if (this._undoStack.length > max) {\n this._undoStack.splice(0, this._undoStack.length - max);\n }\n\n // Any new edit clears the redo stack\n this._redoStack = [];\n this._updateUndoButtons();\n }\n\n /**\n * Undo the last change. Restores the previous markdown state.\n */\n undo() {\n if (!this.canUndo()) return;\n // Save current state to redo stack\n this._redoStack.push(this._markdown);\n const previous = this._undoStack.pop();\n this._isUndoRedo = true;\n // Update state directly (setMarkdown is async; keep it synchronous here)\n this._markdown = previous;\n if (this.sourceTextarea) {\n this.sourceTextarea.value = previous;\n }\n this.updateFromMarkdown(previous);\n this._updateUndoButtons();\n }\n\n /**\n * Redo the last undone change.\n */\n redo() {\n if (!this.canRedo()) return;\n // Save current state to undo stack\n this._undoStack.push(this._markdown);\n const next = this._redoStack.pop();\n this._isUndoRedo = true;\n this._markdown = next;\n if (this.sourceTextarea) {\n this.sourceTextarea.value = next;\n }\n this.updateFromMarkdown(next);\n this._updateUndoButtons();\n }\n\n /**\n * @returns {boolean} true if undo is possible\n */\n canUndo() {\n return this._undoStack.length > 0;\n }\n\n /**\n * @returns {boolean} true if redo is possible\n */\n canRedo() {\n return this._redoStack.length > 0;\n }\n\n /**\n * Clear the undo and redo history.\n */\n clearHistory() {\n this._undoStack = [];\n this._redoStack = [];\n this._updateUndoButtons();\n }\n\n /**\n * Update the disabled state of the undo/redo toolbar buttons.\n * @private\n */\n _updateUndoButtons() {\n if (!this.toolbar) return;\n const undoBtn = this.toolbar.querySelector('[data-action=\"undo\"]');\n const redoBtn = this.toolbar.querySelector('[data-action=\"redo\"]');\n if (undoBtn) {\n undoBtn.classList.toggle('disabled', !this.canUndo());\n }\n if (redoBtn) {\n redoBtn.classList.toggle('disabled', !this.canRedo());\n }\n }\n\n /**\n * Handle toolbar actions\n */\n handleAction(action) {\n switch(action) {\n case 'copy-markdown':\n this.copy('markdown');\n break;\n case 'copy-html':\n this.copy('html');\n break;\n case 'copy-rendered':\n this.copyRendered();\n break;\n case 'remove-hr':\n this.removeHR();\n break;\n case 'lazy-linefeeds':\n this.convertLazyLinefeeds();\n break;\n case 'undo':\n this.undo();\n break;\n case 'redo':\n this.redo();\n break;\n }\n }\n \n /**\n * Copy content to clipboard\n */\n async copy(type) {\n const content = type === 'markdown' ? this._markdown : this._html;\n \n try {\n await navigator.clipboard.writeText(content);\n \n // Visual feedback\n const btn = this.toolbar.querySelector(`[data-action=\"copy-${type}\"]`);\n if (btn) {\n const originalText = btn.textContent;\n btn.textContent = 'Copied!';\n setTimeout(() => {\n btn.textContent = originalText;\n }, 1500);\n }\n } catch (err) {\n console.error('Failed to copy:', err);\n }\n }\n \n // Public API\n \n /**\n * Get current markdown\n */\n get markdown() {\n return this._markdown;\n }\n \n /**\n * Set markdown content\n */\n set markdown(value) {\n this.setMarkdown(value);\n }\n \n /**\n * Get current HTML\n */\n get html() {\n return this._html;\n }\n \n /**\n * Get current mode\n */\n get mode() {\n return this.currentMode;\n }\n \n /**\n * Set markdown content\n */\n async setMarkdown(markdown) {\n // Wait for initialization if needed\n if (this.initPromise) {\n await this.initPromise;\n }\n \n this._markdown = markdown;\n if (this.sourceTextarea) {\n this.sourceTextarea.value = markdown;\n }\n this.updateFromMarkdown(markdown);\n }\n \n /**\n * Get markdown content\n */\n getMarkdown() {\n return this._markdown;\n }\n \n /**\n * Get HTML content\n */\n getHTML() {\n return this._html;\n }\n \n /**\n * Remove all horizontal rules (---) from markdown source.\n * Preserves content inside fences (``` or ~~~) and table separator rows.\n */\n async removeHR() {\n const cleaned = QuikdownEditor.removeHRFromMarkdown(this._markdown);\n await this.setMarkdown(cleaned);\n\n // Visual feedback if toolbar button exists\n const btn = this.toolbar?.querySelector('[data-action=\"remove-hr\"]');\n if (btn) {\n const originalText = btn.textContent;\n btn.textContent = 'Removed!';\n setTimeout(() => {\n btn.textContent = originalText;\n }, 1500);\n }\n }\n\n /**\n * Static: remove horizontal rules from markdown string.\n * Safe for fences, tables, and all markdown constructs.\n * Can be used headless without an editor instance.\n * @param {string} markdown - source markdown\n * @returns {string} markdown with standalone HRs removed\n */\n static removeHRFromMarkdown(markdown) {\n const lines = (markdown || '').split('\\n');\n const result = [];\n let inFence = false;\n let fenceChar = null; // '`' or '~'\n let fenceLen = 0; // length of opening fence marker\n\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i];\n const trimmed = line.trim();\n\n // Track fence open/close (``` or ~~~, 3+ chars)\n const fenceMatch = trimmed.match(/^(`{3,}|~{3,})/);\n if (fenceMatch) {\n const matchChar = fenceMatch[1][0];\n const matchLen = fenceMatch[1].length;\n if (!inFence) {\n inFence = true;\n fenceChar = matchChar;\n fenceLen = matchLen;\n result.push(line);\n continue;\n } else if (matchChar === fenceChar && matchLen >= fenceLen && /^(`{3,}|~{3,})\\s*$/.test(trimmed)) {\n // Closing fence: same char, at least as many chars, no trailing content\n inFence = false;\n fenceChar = null;\n fenceLen = 0;\n result.push(line);\n continue;\n }\n }\n\n // Inside a fence — keep everything\n if (inFence) {\n result.push(line);\n continue;\n }\n\n // Detect table row/separator with pipes — always keep\n if (/^\\|.*\\|$/.test(trimmed) || (/^[-| :]+$/.test(trimmed) && trimmed.includes('|'))) {\n result.push(line);\n continue;\n }\n\n // Check if this line is a standalone HR\n const isHR = /^[-_*](\\s*[-_*]){2,}\\s*$/.test(trimmed);\n if (isHR) {\n // Table separator heuristic: immediately adjacent lines (no blank\n // lines between) that look like table rows protect this HR-like line\n const prevLine = i > 0 ? lines[i - 1].trim() : '';\n const nextLine = i < lines.length - 1 ? lines[i + 1].trim() : '';\n if (_looksLikeTableRow(prevLine) || _looksLikeTableRow(nextLine)) {\n result.push(line);\n continue;\n }\n // It's a real HR — skip it\n continue;\n }\n\n result.push(line);\n }\n\n return result.join('\\n');\n }\n\n /**\n * Convert lazy linefeeds in markdown source.\n * Replaces single newlines with double newlines (adds real line breaks)\n * except inside fences, tables, and other block-level constructs.\n * Idempotent: calling multiple times produces the same result.\n * Can be used as a toolbar action or headless via the static method.\n */\n async convertLazyLinefeeds() {\n const converted = QuikdownEditor.convertLazyLinefeeds(this._markdown);\n await this.setMarkdown(converted);\n\n // Visual feedback if toolbar button exists\n const btn = this.toolbar?.querySelector('[data-action=\"lazy-linefeeds\"]');\n if (btn) {\n const originalText = btn.textContent;\n btn.textContent = 'Converted!';\n setTimeout(() => {\n btn.textContent = originalText;\n }, 1500);\n }\n }\n\n /**\n * Static: convert lazy linefeeds in markdown source.\n * Turns single \\n between non-blank lines into \\n\\n so each line becomes\n * its own paragraph / hard break. Idempotent — already-doubled newlines\n * are not doubled again. Fences, tables, lists, blockquotes, headings,\n * and HTML blocks are left untouched.\n * @param {string} markdown - source markdown\n * @returns {string} markdown with lazy linefeeds resolved\n */\n static convertLazyLinefeeds(markdown) {\n // Two-phase approach (much cleaner than the old single pass):\n //\n // Phase A: walk lines, classify each as { content, blank, fence }.\n // Inside fences, lines are passed through verbatim.\n // Phase B: emit lines with the rule:\n // \"between two adjacent CONTENT lines, ensure exactly one\n // blank line — never zero, never more than one.\"\n //\n // The rule applies regardless of whether the content lines are\n // headings, lists, blockquotes, table rows, paragraphs, or HR — any\n // adjacent pair of non-fence non-blank lines gets exactly one blank\n // between them. This produces the cleanest possible output for any\n // input and is fully idempotent.\n //\n // Lines that are whitespace-only (e.g. \" \") are normalized to\n // empty strings, eliminating \"phantom\" blank lines.\n //\n // Lists are a special case: adjacent list items (same marker type)\n // should NOT get a blank line between them, otherwise we'd break\n // tight lists.\n //\n // Same applies to blockquote lines and table rows — adjacent rows\n // belong to the same block.\n\n const inputLines = (markdown || '').split('\\n');\n\n // -------- Phase A: classify lines, normalize whitespace-only --------\n // Each entry: { line, kind } where kind is one of:\n // 'fence-open', 'fence-close', 'fence-body', 'blank', 'content'\n // Plus a 'category' for content lines: 'list-ul', 'list-ol',\n // 'blockquote', 'table', 'heading', 'hr', 'paragraph'\n const items = [];\n let inFence = false;\n let fenceChar = null;\n let fenceLen = 0;\n\n for (const rawLine of inputLines) {\n const line = rawLine;\n const trimmed = line.trim();\n\n // Fence tracking\n const fenceMatch = trimmed.match(/^(`{3,}|~{3,})/);\n if (fenceMatch && !inFence) {\n inFence = true;\n fenceChar = fenceMatch[1][0];\n fenceLen = fenceMatch[1].length;\n items.push({ line, kind: 'fence-open' });\n continue;\n }\n if (inFence) {\n if (fenceMatch &&\n fenceMatch[1][0] === fenceChar &&\n fenceMatch[1].length >= fenceLen &&\n /^(`{3,}|~{3,})\\s*$/.test(trimmed)) {\n inFence = false;\n fenceChar = null;\n fenceLen = 0;\n items.push({ line, kind: 'fence-close' });\n } else {\n items.push({ line, kind: 'fence-body' });\n }\n continue;\n }\n\n // Outside fence: whitespace-only lines become canonical blanks\n if (trimmed === '') {\n items.push({ line: '', kind: 'blank' });\n continue;\n }\n\n // Categorize content lines so we can recognize adjacent same-kind blocks\n let category = 'paragraph';\n if (/^#{1,6}\\s/.test(trimmed)) category = 'heading';\n else if (/^[-_*](\\s*[-_*]){2,}\\s*$/.test(trimmed)) category = 'hr';\n else if (/^(\\d+\\.)\\s/.test(trimmed)) category = 'list-ol';\n else if (/^[-*+]\\s/.test(trimmed)) category = 'list-ul';\n else if (/^>/.test(trimmed)) category = 'blockquote';\n else if (/^\\|/.test(trimmed)) category = 'table';\n // Indented continuation of a list (2+ leading spaces or tab)\n else if (/^(?: {4}|\\t| {2,}[-*+]| {2,}\\d+\\.)/.test(line)) category = 'list-cont';\n\n items.push({ line, kind: 'content', category });\n }\n\n // -------- Phase B: emit with exactly-one-blank-line normalization --------\n // Same-block adjacent lines (lists, blockquotes, tables) stay\n // touching; any other adjacent content pair gets exactly one blank.\n const result = [];\n let prev = null; // last emitted non-blank content item\n\n function inSameBlock(a, b) {\n if (!a || !b) return false;\n // Lists: same marker family OR list-content continuation\n if ((a.category === 'list-ul' || a.category === 'list-ol' || a.category === 'list-cont') &&\n (b.category === 'list-ul' || b.category === 'list-ol' || b.category === 'list-cont')) {\n return true;\n }\n // Blockquotes\n if (a.category === 'blockquote' && b.category === 'blockquote') return true;\n // Table rows\n if (a.category === 'table' && b.category === 'table') return true;\n return false;\n }\n\n for (const item of items) {\n if (item.kind === 'fence-open' || item.kind === 'fence-body' || item.kind === 'fence-close') {\n // Fences: ensure exactly one blank line before the fence-open\n if (item.kind === 'fence-open' && prev && result.length > 0 && result[result.length - 1] !== '') {\n result.push('');\n }\n result.push(item.line);\n if (item.kind === 'fence-close') prev = { kind: 'content', category: 'fence' };\n continue;\n }\n\n if (item.kind === 'blank') {\n // Skip — Phase B inserts its own blank lines as needed\n continue;\n }\n\n // item.kind === 'content'\n if (prev) {\n if (inSameBlock(prev, item)) {\n // Adjacent same-block lines: no blank between\n } else {\n // Different blocks (or paragraphs): exactly one blank\n if (result[result.length - 1] !== '') result.push('');\n }\n }\n result.push(item.line);\n prev = item;\n }\n\n // Trim trailing blank lines so output has exactly one terminal newline\n while (result.length > 0 && result[result.length - 1] === '') result.pop();\n\n return result.join('\\n');\n }\n \n /**\n * Copy rendered content as rich text\n */\n async copyRendered() {\n try {\n const result = await getRenderedContent(this.previewPanel);\n if (result.success) {\n // Visual feedback\n const btn = this.toolbar?.querySelector('[data-action=\"copy-rendered\"]');\n if (btn) {\n const originalText = btn.textContent;\n btn.textContent = 'Copied!';\n setTimeout(() => {\n btn.textContent = originalText;\n }, 1500);\n }\n }\n } catch (err) {\n console.error('Failed to copy rendered content:', err);\n }\n }\n \n /**\n * Destroy the editor\n */\n destroy() {\n // Clear timers\n clearTimeout(this.updateTimer);\n \n // Clear container\n this.container.innerHTML = '';\n this.container.classList.remove('qde-container', 'qde-dark');\n \n // Remove injected styles (only if no other editors exist)\n const otherEditors = document.querySelectorAll('.qde-container');\n if (otherEditors.length === 0) {\n const style = document.getElementById('qde-styles');\n if (style) style.remove();\n }\n }\n}\n\n// --- Internal helpers for removeHR fence/table awareness ---\n\n/** Heuristic: does this line look like a markdown table row? */\nfunction _looksLikeTableRow(line) {\n return line.includes('|');\n}\n\n// Export\nexport default QuikdownEditor;\n\n// Export for CommonJS (needed for bundled ESM to work with Jest)\nif (typeof module !== 'undefined' && module.exports) {\n module.exports = QuikdownEditor;\n}\n\n// Also export for UMD builds\nif (typeof window !== 'undefined') {\n window.QuikdownEditor = QuikdownEditor;\n}"],"names":["CLASS_PREFIX","PLACEHOLDER_CB","ESC_MAP","QUIKDOWN_STYLES","h1","h2","h3","h4","h5","h6","pre","code","blockquote","table","th","td","hr","img","a","strong","em","del","ul","ol","li","quikdown","markdown","options","fence_plugin","inline_styles","bidirectional","lazy_linefeeds","allow_unsafe_html","getAttr","styles","tag","additionalStyle","style","includes","replace","trim","endsWith","classAttr","createGetAttr","escapeHtml","text","m","dataQd","marker","sanitizeUrl","url","allowUnsafe","trimmedUrl","lowerUrl","toLowerCase","dangerousProtocols","protocol","startsWith","html","codeBlocks","inlineCodes","match","fence","lang","placeholder","length","langTrimmed","render","push","trimEnd","custom","hasReverse","reverse","lines","split","result","inTable","tableLines","i","line","test","tableHtml","buildTable","join","processTable","hashes","content","level","listStack","indent","Math","floor","isOrdered","listType","listItemContent","taskListClass","taskMatch","checked","taskContent","isChecked","list","pop","type","currentList","liAttr","processLists","alt","src","sanitizedSrc","allow_unsafe_urls","altAttr","srcAttr","href","sanitizedHref","rel","textAttr","prefix","sanitizedUrl","forEach","pattern","blocks","bi","b","offset","substring","RegExp","replacement","block","undefined","langClass","codeAttr","langAttr","fenceAttr","processInlineMarkdown","separatorIndex","headerLines","slice","bodyLines","alignments","map","cell","trimmed","alignStyle","processedCell","quikdown_bd","async","svgToPng","svgElement","needsWhiteBackground","Promise","resolve","reject","svgString","XMLSerializer","serializeToString","canvas","document","createElement","ctx","getContext","Image","isMermaidSvg","closest","classList","contains","hasExplicitDimensions","getAttribute","svgWidth","svgHeight","clientWidth","viewBox","baseVal","width","parseFloat","clientHeight","height","modifiedSvgString","tempDiv","innerHTML","tempSvg","querySelector","setAttribute","toString","scale","onload","fillStyle","fillRect","drawImage","toBlob","blob","err","onerror","svgDataUrl","encodeURIComponent","rasterizeGeoJSONMap","liveContainer","_map","console","warn","mapRect","getBoundingClientRect","round","dpr","window","devicePixelRatio","tiles","querySelectorAll","tilePromises","tile","crossOrigin","tileRect","offsetX","left","offsetY","top","all","svgOverlays","svg","svgRect","svgStr","svgBlob","Blob","URL","createObjectURL","revokeObjectURL","Error","markerIcons","markerRect","toDataURL","error","getRenderedContent","previewPanel","mathBlocks","Array","from","some","MathJax","typesetPromise","clone","cloneNode","el","fontWeight","fontStyle","textDecoration","backgroundColor","padding","borderRadius","fontFamily","fontSize","marginTop","marginBottom","borderLeft","marginLeft","paddingLeft","color","border","borderTop","margin","borderCollapse","textAlign","parentElement","tr","lineHeight","whiteSpace","overflowX","appendChild","parentNode","replaceChild","images","naturalWidth","naturalHeight","maxWidth","maxHeight","min","random","substr","response","fetch","maxSize","size","dataUrl","reader","FileReader","onloadend","readAsDataURL","stlContainers","container","containerId","dataset","stlId","originalContainer","renderer","_threeRenderer","scene","_threeScene","camera","_threeCamera","imgWidth","imgHeight","canvasErr","cssText","textContent","mermaidContainers","pngBlob","chartContainers","chartId","svgContainers","mathElements","mathEl","value","_e","scaleFactor","scaledWidth","scaledHeight","scaleX","scaleY","imgElement","img2","setTimeout","displayWidth","displayHeight","geojsonContainers","clonedContainer","originalSource","allLiveContainers","candidate","mapContainers","id","leafletContainer","max","leafRect","r","x","y","w","h","overlaps","right","bottom","getComputedStyle","display","visibility","e","overlaySvgs","icon","mapDataUrl","String","htmlContainers","source","htmlImages","widthAttr","heightAttr","parseInt","tempImg","aspectRatio","absoluteImg","fragment","htmlContent","innerText","platform","navigator","userAgent","getPlatform","clipboard","write","ClipboardItem","success","modernErr","position","overflow","body","range","createRange","selectNodeContents","selection","getSelection","removeAllRanges","addRange","execCommand","removeChild","copyToClipboard","emitStyles","theme","themeOverrides","_textColor","css","Object","entries","themedStyle","oldColor","newColor","configure","version","module","exports","keys","key","toMarkdown","htmlOrElement","Element","walkNode","node","parentContext","nodeType","Node","TEXT_NODE","ELEMENT_NODE","tagName","childContent","child","childNodes","parentTag","repeat","boldMarker","emMarker","delMarker","codeMarker","fenceMarker","codeEl","quoteMarker","linkText","walkList","alignData","thead","headerRow","headers","_","align","tbody","row","cells","walkTable","trailingBlankLines","divLang","divFence","divSource","temp","mermaidPre","preSource","sourceElement","mermaidElement","listNode","depth","index","children","checkbox","itemContent","innerParser","DEFAULT_OPTIONS","mode","showToolbar","showRemoveHR","showLazyLinefeeds","debounceDelay","plugins","highlightjs","mermaid","preloadFences","customFences","enableComplexFences","showUndoRedo","undoStackSize","FENCE_LIBRARIES","check","hljs","script","cssDark","afterLoad","initialize","startOnLoad","math","beforeLoad","tex","inlineMath","displayMath","fontCache","startup","typeset","geojson","L","stl","THREE","QuikdownEditor","constructor","this","_markdown","_html","currentMode","updateTimer","_undoStack","_redoStack","_isUndoRedo","initPromise","init","loadPlugins","buildUI","attachEvents","applyTheme","setMode","initialContent","setMarkdown","add","toolbar","createToolbar","editorArea","className","sourcePanel","sourceTextarea","spellcheck","contentEditable","injectStyles","modeLabels","preview","btn","title","undoBtn","action","redoBtn","spacer","removeHRBtn","lazyLFBtn","getElementById","head","addEventListener","handleSourceInput","handlePreviewInput","target","handleAction","ctrlKey","metaKey","preventDefault","shiftKey","redo","undo","clearTimeout","updateFromMarkdown","updateFromHTML","_pushUndoState","createFencePlugin","makeFencesNonEditable","catch","_err","onChange","clonedPanel","preprocessSpecialElements","newMarkdown","_updateUndoButtons","panel","element","delimiter","csv","needsQuoting","renderSVG","renderHTML","renderMath","renderTable","renderJSON","renderMermaid","renderGeoJSON","renderSTL","getLanguage","highlight","language","doc","DOMParser","parseFromString","documentElement","remove","walker","createTreeWalker","NodeFilter","SHOW_ELEMENT","nextNode","attributes","attr","name","removeAttribute","outerHTML","errorContainer","message","Date","now","DOMPurify","clean","sanitize","lazyLoadLibrary","then","loaded","_lang","singleLineContent","ensureMathJaxLoaded","mathJaxLoading","loader","load","packages","processEscapes","processEnvironments","renderActions","addMenu","ignoreHtmlClass","processHtmlClass","escapedCode","header","parseCSVLine","current","inQuotes","char","nextChar","toHighlight","data","JSON","parse","stringify","mapId","renderMap","mapDiv","tileLayer","attribution","addTo","geoJsonLayer","geoJSON","getBounds","isValid","fitBounds","setView","_tileLayer","_geoJsonLayer","on","_qde_leaflet_loading","render3D","Scene","background","Color","PerspectiveCamera","WebGLRenderer","antialias","setSize","domElement","geometry","parseSTL","material","MeshLambertMaterial","mesh","Mesh","ambientLight","AmbientLight","directionalLight","DirectionalLight","set","normalize","box","Box3","setFromObject","center","getCenter","Vector3","getSize","maxDim","z","lookAt","animate","requestAnimationFrame","rotation","_qde_three_loading","stlData","BufferGeometry","vertices","normals","currentNormal","parts","Float32BufferAttribute","namesToLoad","Set","pf","n","isArray","entry","promises","lib","p","tasks","loadScript","loadCSS","_syncHljsTheme","scriptUrl","cssUrl","link","isDark","light","dark","disabled","_autoThemeListener","matchMedia","removeEventListener","mq","toggle","matches","setTheme","getTheme","setLazyLinefeeds","enabled","getLazyLinefeeds","setDebounceDelay","delay","getDebounceDelay","wasDark","onModeChange","splice","canUndo","previous","canRedo","next","clearHistory","copy","copyRendered","removeHR","convertLazyLinefeeds","writeText","originalText","getMarkdown","getHTML","cleaned","removeHRFromMarkdown","inFence","fenceChar","fenceLen","fenceMatch","matchChar","matchLen","prevLine","nextLine","_looksLikeTableRow","converted","inputLines","items","rawLine","kind","category","prev","inSameBlock","item","destroy"],"mappings":"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"}
1
+ {"version":3,"file":"quikdown_edit.umd.min.js","sources":["../src/quikdown_classify.js","../src/quikdown.js","../src/quikdown_bd.js","../src/quikdown_edit_copy.js","../src/quikdown_edit.js"],"sourcesContent":["/**\n * quikdown_classify — Shared line-classification utilities\n * ═════════════════════════════════════════════════════════\n *\n * Pure functions for classifying markdown lines. Used by both the main\n * parser (quikdown.js) and the editor (quikdown_edit.js) so the logic\n * lives in one place.\n *\n * All functions operate on a **trimmed** line (caller must trim).\n * None use regexes with nested quantifiers — every check is either a\n * simple regex or a linear scan, so there is zero ReDoS risk.\n */\n\n/**\n * Full CommonMark HR check: three or more identical characters from\n * {-, *, _} with optional interspersed whitespace.\n *\n * Examples that return true: ---, ***, ___, ----, - - -, * * *, _ _ _\n * Examples that return false: --, - text, ---text, mixed -_*, empty\n *\n * Algorithm (O(n), single pass, no backtracking):\n * 1. Strip all whitespace\n * 2. Verify length >= 3\n * 3. First char must be -, *, or _\n * 4. Every remaining char must equal the first\n *\n * @param {string} trimmed The line, already trimmed\n * @returns {boolean}\n */\nexport function isHRLine(trimmed) {\n if (trimmed.length < 3) return false;\n\n // Strip whitespace via linear scan\n let stripped = '';\n for (let i = 0; i < trimmed.length; i++) {\n const ch = trimmed[i];\n if (ch !== ' ' && ch !== '\\t') stripped += ch;\n }\n\n if (stripped.length < 3) return false;\n\n const ch = stripped[0];\n if (ch !== '-' && ch !== '*' && ch !== '_') return false;\n\n for (let i = 1; i < stripped.length; i++) {\n if (stripped[i] !== ch) return false;\n }\n return true;\n}\n\n/**\n * Dash-only HR check — exact parity with the main parser's original\n * regex `/^---+\\s*$/`. Only matches lines of three or more dashes\n * with optional trailing whitespace (no interspersed spaces).\n *\n * @param {string} trimmed The line, already trimmed\n * @returns {boolean}\n */\nexport function isDashHRLine(trimmed) {\n if (trimmed.length < 3) return false;\n for (let i = 0; i < trimmed.length; i++) {\n const ch = trimmed[i];\n if (ch === '-') continue;\n // Allow trailing whitespace only\n if (ch === ' ' || ch === '\\t') {\n for (let j = i + 1; j < trimmed.length; j++) {\n if (trimmed[j] !== ' ' && trimmed[j] !== '\\t') return false;\n }\n return i >= 3; // at least 3 dashes before whitespace\n }\n return false;\n }\n return true; // all dashes\n}\n\n/**\n * Check if a trimmed line opens a code fence.\n * Returns { char, len, lang } if it does, or null otherwise.\n *\n * A fence opener is 3+ identical backticks or tildes at the start of a line,\n * optionally followed by a language tag.\n *\n * @param {string} trimmed The line, already trimmed\n * @returns {{ char: string, len: number, lang: string } | null}\n */\nexport function fenceOpen(trimmed) {\n if (trimmed.length < 3) return null;\n const ch = trimmed[0];\n if (ch !== '`' && ch !== '~') return null;\n\n let len = 1;\n while (len < trimmed.length && trimmed[len] === ch) len++;\n if (len < 3) return null;\n\n const lang = trimmed.slice(len).trim();\n return { char: ch, len, lang };\n}\n\n/**\n * Check if a trimmed line closes an open fence.\n * The closing fence must use the same character, be at least as long,\n * and have no content after (optional trailing whitespace only).\n *\n * @param {string} trimmed The line, already trimmed\n * @param {string} openChar The fence character ('`' or '~')\n * @param {number} openLen Length of the opening fence marker\n * @returns {boolean}\n */\nexport function isFenceClose(trimmed, openChar, openLen) {\n if (trimmed.length < openLen) return false;\n\n let len = 0;\n while (len < trimmed.length && trimmed[len] === openChar) len++;\n if (len < openLen) return false;\n\n // Rest must be whitespace only\n for (let i = len; i < trimmed.length; i++) {\n if (trimmed[i] !== ' ' && trimmed[i] !== '\\t') return false;\n }\n return true;\n}\n\n/**\n * Classify a content line into a category string.\n * Order matters: HR before list-ul (since `- - -` looks like a list start).\n *\n * @param {string} trimmed The line, already trimmed\n * @returns {string} One of: 'heading', 'hr', 'list-ol', 'list-ul',\n * 'blockquote', 'table', 'paragraph'\n */\nexport function classifyLine(trimmed) {\n if (/^#{1,6}\\s/.test(trimmed)) return 'heading';\n if (isHRLine(trimmed)) return 'hr';\n if (/^\\d+\\.\\s/.test(trimmed)) return 'list-ol';\n if (/^[-*+]\\s/.test(trimmed)) return 'list-ul';\n if (/^>/.test(trimmed)) return 'blockquote';\n if (/^\\|/.test(trimmed)) return 'table';\n return 'paragraph';\n}\n\n/**\n * Heuristic: does a line look like a markdown table row?\n * @param {string} line The line (trimmed or untrimmed)\n * @returns {boolean}\n */\nexport function looksLikeTableRow(line) {\n return line.includes('|');\n}\n","/**\n * quikdown — A compact, scanner-based markdown parser\n * ════════════════════════════════════════════════════\n *\n * Architecture overview (v1.2.8 — lexer rewrite)\n * ───────────────────────────────────────────────\n * Prior to v1.2.8, quikdown used a multi-pass regex pipeline: each block\n * type (headings, blockquotes, HR, lists, tables) and each inline format\n * (bold, italic, links, …) was handled by its own global regex applied\n * sequentially to the full document string. That worked but made the code\n * hard to extend and debug — a new construct meant adding another regex\n * pass, and ordering bugs between passes were subtle.\n *\n * Starting in v1.2.8 the parser uses a **line-scanning** approach for\n * block detection and a **per-block inline pass** for formatting:\n *\n * ┌─────────────────────────────────────────────────────────┐\n * │ Phase 1 — Code Extraction │\n * │ Scan for fenced code blocks (``` / ~~~) and inline │\n * │ code spans (`…`). Replace with §CB§ / §IC§ place- │\n * │ holders so code content is never touched by later │\n * │ phases. │\n * ├─────────────────────────────────────────────────────────┤\n * │ Phase 2 — HTML Escaping │\n * │ Escape &, <, >, \", ' in the remaining text to prevent │\n * │ XSS. (Skipped when allow_unsafe_html is true.) │\n * ├─────────────────────────────────────────────────────────┤\n * │ Phase 3 — Block Scanning │\n * │ Walk the text **line by line**. At each line, the │\n * │ scanner checks (in order): │\n * │ • table rows (|) │\n * │ • headings (#) │\n * │ • HR (---) │\n * │ • blockquotes (&gt;) │\n * │ • list items (-, *, +, 1.) │\n * │ • code-block placeholder (§CB…§) │\n * │ • paragraph text (everything else) │\n * │ │\n * │ Block text is run through the **inline formatter** │\n * │ which handles bold, italic, strikethrough, links, │\n * │ images, and autolinks. │\n * │ │\n * │ Paragraphs are wrapped in <p> tags. Lazy linefeeds │\n * │ (single \\n → <br>) are handled here too. │\n * ├─────────────────────────────────────────────────────────┤\n * │ Phase 4 — Code Restoration │\n * │ Replace §CB§ / §IC§ placeholders with rendered <pre> │\n * │ / <code> HTML, applying the fence_plugin if present. │\n * └─────────────────────────────────────────────────────────┘\n *\n * Why this design?\n * • Single pass over lines for block identification — no re-scanning.\n * • Each block type is a clearly separated branch, easy to add new ones.\n * • Inline formatting is confined to block text — can't accidentally\n * match across block boundaries or inside HTML tags.\n * • Code extraction still uses a simple regex (it's one pattern, not a\n * chain) because the §-placeholder approach is proven and simple.\n *\n * @param {string} markdown The markdown source text\n * @param {Object} options Configuration (see below)\n * @returns {string} Rendered HTML\n */\n\nimport { isDashHRLine } from './quikdown_classify.js';\n\n// ────────────────────────────────────────────────────────────────────\n// Constants\n// ────────────────────────────────────────────────────────────────────\n\n/** Build-time version stamp (injected by tools/updateVersion) */\nconst quikdownVersion = '__QUIKDOWN_VERSION__';\n\n/** CSS class prefix used for all generated elements */\nconst CLASS_PREFIX = 'quikdown-';\n\n/** Placeholder sigils — chosen to be extremely unlikely in real text */\nconst PLACEHOLDER_CB = '§CB'; // fenced code blocks\nconst PLACEHOLDER_IC = '§IC'; // inline code spans\n\n/** HTML entity escape map */\nconst ESC_MAP = {'&':'&amp;','<':'&lt;','>':'&gt;','\"':'&quot;',\"'\":'&#39;'};\n\n// ────────────────────────────────────────────────────────────────────\n// Style definitions\n// ────────────────────────────────────────────────────────────────────\n\n/**\n * Inline styles for every element quikdown can emit.\n * When `inline_styles: true` these are injected as style=\"…\" attributes.\n * When `inline_styles: false` (default) we use class=\"quikdown-<tag>\"\n * and these same values are emitted by `quikdown.emitStyles()`.\n */\nconst QUIKDOWN_STYLES = {\n h1: 'font-size:2em;font-weight:600;margin:.67em 0;text-align:left',\n h2: 'font-size:1.5em;font-weight:600;margin:.83em 0',\n h3: 'font-size:1.25em;font-weight:600;margin:1em 0',\n h4: 'font-size:1em;font-weight:600;margin:1.33em 0',\n h5: 'font-size:.875em;font-weight:600;margin:1.67em 0',\n h6: 'font-size:.85em;font-weight:600;margin:2em 0',\n pre: 'background:#f4f4f4;padding:10px;border-radius:4px;overflow-x:auto;margin:1em 0',\n code: 'background:#f0f0f0;padding:2px 4px;border-radius:3px;font-family:monospace',\n blockquote: 'border-left:4px solid #ddd;margin-left:0;padding-left:1em',\n table: 'border-collapse:collapse;width:100%;margin:1em 0',\n th: 'border:1px solid #ddd;padding:8px;background-color:#f2f2f2;font-weight:bold;text-align:left',\n td: 'border:1px solid #ddd;padding:8px;text-align:left',\n hr: 'border:none;border-top:1px solid #ddd;margin:1em 0',\n img: 'max-width:100%;height:auto',\n a: 'color:#06c;text-decoration:underline',\n strong: 'font-weight:bold',\n em: 'font-style:italic',\n del: 'text-decoration:line-through',\n ul: 'margin:.5em 0;padding-left:2em',\n ol: 'margin:.5em 0;padding-left:2em',\n li: 'margin:.25em 0',\n 'task-item': 'list-style:none',\n 'task-checkbox': 'margin-right:.5em'\n};\n\n// ────────────────────────────────────────────────────────────────────\n// Attribute factory\n// ────────────────────────────────────────────────────────────────────\n\n/**\n * Creates a `getAttr(tag, additionalStyle?)` helper that returns\n * either a class=\"…\" or style=\"…\" attribute string depending on mode.\n *\n * @param {boolean} inline_styles True → emit style=\"…\"; false → class=\"…\"\n * @param {Object} styles The QUIKDOWN_STYLES map\n * @returns {Function}\n */\nfunction createGetAttr(inline_styles, styles) {\n return function(tag, additionalStyle = '') {\n if (inline_styles) {\n let style = styles[tag];\n if (!style && !additionalStyle) return '';\n\n // When adding alignment that conflicts with the tag's default,\n // strip the default text-align first.\n if (additionalStyle && additionalStyle.includes('text-align') && style && style.includes('text-align')) {\n style = style.replace(/text-align:[^;]+;?/, '').trim();\n /* istanbul ignore next */\n if (style && !style.endsWith(';')) style += ';';\n }\n\n /* istanbul ignore next - defensive: additionalStyle without style doesn't occur with current tags */\n const fullStyle = additionalStyle ? (style ? `${style}${additionalStyle}` : additionalStyle) : style;\n return ` style=\"${fullStyle}\"`;\n } else {\n const classAttr = ` class=\"${CLASS_PREFIX}${tag}\"`;\n if (additionalStyle) {\n return `${classAttr} style=\"${additionalStyle}\"`;\n }\n return classAttr;\n }\n };\n}\n\n// ════════════════════════════════════════════════════════════════════\n// Main parser function\n// ════════════════════════════════════════════════════════════════════\n\nfunction quikdown(markdown, options = {}) {\n // ── Guard: only process non-empty strings ──\n if (!markdown || typeof markdown !== 'string') {\n return '';\n }\n\n // ── Unpack options ──\n const { fence_plugin, inline_styles = false, bidirectional = false, lazy_linefeeds = false, allow_unsafe_html = false } = options;\n const styles = QUIKDOWN_STYLES;\n const getAttr = createGetAttr(inline_styles, styles);\n\n // ── Helpers (closed over options) ──\n\n /** Escape the five HTML-special characters. */\n function escapeHtml(text) {\n return text.replace(/[&<>\"']/g, m => ESC_MAP[m]);\n }\n\n /**\n * Bidirectional marker helper.\n * When bidirectional mode is on, returns ` data-qd=\"…\"`.\n * The non-bidirectional branch is a trivial no-op arrow; it is\n * exercised in the core bundle but never in quikdown_bd.\n */\n /* istanbul ignore next - trivial no-op fallback */\n const dataQd = bidirectional ? (marker) => ` data-qd=\"${escapeHtml(marker)}\"` : () => '';\n\n /**\n * Sanitize a URL to block javascript:, vbscript:, and non-image data: URIs.\n * Returns '#' for blocked URLs.\n */\n function sanitizeUrl(url, allowUnsafe = false) {\n /* istanbul ignore next - defensive programming, regex ensures url is never empty */\n if (!url) return '';\n if (allowUnsafe) return url;\n\n const trimmedUrl = url.trim();\n const lowerUrl = trimmedUrl.toLowerCase();\n const dangerousProtocols = ['javascript:', 'vbscript:', 'data:'];\n\n for (const protocol of dangerousProtocols) {\n if (lowerUrl.startsWith(protocol)) {\n if (protocol === 'data:' && lowerUrl.startsWith('data:image/')) {\n return trimmedUrl;\n }\n return '#';\n }\n }\n return trimmedUrl;\n }\n\n // ────────────────────────────────────────────────────────────────\n // Phase 1 — Code Extraction\n // ────────────────────────────────────────────────────────────────\n // Why extract code first? Fenced blocks and inline code spans can\n // contain markdown-like characters (*, _, #, |, etc.) that must NOT\n // be interpreted as formatting. By pulling them out and replacing\n // with unique placeholders, the rest of the pipeline never sees them.\n\n let html = markdown;\n const codeBlocks = []; // Array of {lang, code, custom, fence, hasReverse}\n const inlineCodes = []; // Array of escaped-HTML strings\n\n // ── Fenced code blocks ──\n // Matches paired fences: ``` with ``` and ~~~ with ~~~.\n // The fence must start at column 0 of a line (^ with /m flag).\n // Group 1 = fence marker, Group 2 = language hint, Group 3 = code body.\n html = html.replace(/^(```|~~~)([^\\n]*)\\n([\\s\\S]*?)^\\1$/gm, (match, fence, lang, code) => {\n const placeholder = `${PLACEHOLDER_CB}${codeBlocks.length}§`;\n const langTrimmed = lang ? lang.trim() : '';\n\n if (fence_plugin && fence_plugin.render && typeof fence_plugin.render === 'function') {\n // Custom plugin — store raw code (un-escaped) so the plugin\n // receives the original source.\n codeBlocks.push({\n lang: langTrimmed,\n code: code.trimEnd(),\n custom: true,\n fence: fence,\n hasReverse: !!fence_plugin.reverse\n });\n } else {\n // Default — pre-escape the code for safe HTML output.\n codeBlocks.push({\n lang: langTrimmed,\n code: escapeHtml(code.trimEnd()),\n custom: false,\n fence: fence\n });\n }\n return placeholder;\n });\n\n // ── Inline code spans ──\n // Matches a single backtick pair: `content`.\n // Content is captured and HTML-escaped immediately.\n html = html.replace(/`([^`]+)`/g, (match, code) => {\n const placeholder = `${PLACEHOLDER_IC}${inlineCodes.length}§`;\n inlineCodes.push(escapeHtml(code));\n return placeholder;\n });\n\n // ────────────────────────────────────────────────────────────────\n // Phase 2 — HTML Escaping\n // ────────────────────────────────────────────────────────────────\n // All remaining text (everything except code placeholders) is escaped\n // to prevent XSS. The `allow_unsafe_html` option skips this for\n // trusted pipelines that intentionally embed raw HTML.\n\n if (!allow_unsafe_html) {\n html = escapeHtml(html);\n }\n\n // ────────────────────────────────────────────────────────────────\n // Phase 3 — Block Scanning + Inline Formatting + Paragraphs\n // ────────────────────────────────────────────────────────────────\n // This is the heart of the lexer rewrite. Instead of applying\n // 10+ global regex passes, we:\n // 1. Process tables (line walker — tables need multi-line lookahead)\n // 2. Scan remaining lines for headings, HR, blockquotes\n // 3. Process lists (line walker — lists need indent tracking)\n // 4. Apply inline formatting to all text content\n // 5. Wrap remaining text in <p> tags\n //\n // Steps 1 and 3 are line-walkers that process the full text in a\n // single pass each. Step 2 replaces global regex with a per-line\n // scanner. Steps 4-5 are applied to the result.\n //\n // Total: 3 structured passes instead of 10+ regex passes.\n\n // ── Step 1: Tables ──\n // Tables need multi-line lookahead (header → separator → body rows)\n // so they're handled by a dedicated line-walker first.\n html = processTable(html, getAttr);\n\n // ── Step 2: Headings, HR, Blockquotes ──\n // These are simple line-level constructs. We scan each line once\n // and replace matching lines with their HTML representation.\n html = scanLineBlocks(html, getAttr, dataQd);\n\n // ── Step 3: Lists ──\n // Lists need indent-level tracking across lines, so they get their\n // own line-walker.\n html = processLists(html, getAttr, inline_styles, bidirectional);\n\n // ── Step 4: Inline formatting ──\n // Apply bold, italic, strikethrough, images, links, and autolinks\n // to all text content. This runs on the output of steps 1-3, so\n // it sees text inside headings, blockquotes, table cells, list\n // items, and paragraph text.\n\n // Images (must come before links — ![alt](src) vs [text](url))\n html = html.replace(/!\\[([^\\]]*)\\]\\(([^)]+)\\)/g, (match, alt, src) => {\n const sanitizedSrc = sanitizeUrl(src, options.allow_unsafe_urls);\n // Bidirectional attributes are only exercised via quikdown_bd bundle.\n /* istanbul ignore next - bd-only branch */\n const altAttr = bidirectional && alt ? ` data-qd-alt=\"${escapeHtml(alt)}\"` : '';\n /* istanbul ignore next - bd-only branch */\n const srcAttr = bidirectional ? ` data-qd-src=\"${escapeHtml(src)}\"` : '';\n return `<img${getAttr('img')} src=\"${sanitizedSrc}\" alt=\"${alt}\"${altAttr}${srcAttr}${dataQd('!')}>`;\n });\n\n // Links\n html = html.replace(/\\[([^\\]]+)\\]\\(([^)]+)\\)/g, (match, text, href) => {\n const sanitizedHref = sanitizeUrl(href, options.allow_unsafe_urls);\n const isExternal = /^https?:\\/\\//i.test(sanitizedHref);\n const rel = isExternal ? ' rel=\"noopener noreferrer\"' : '';\n /* istanbul ignore next - bd-only branch */\n const textAttr = bidirectional ? ` data-qd-text=\"${escapeHtml(text)}\"` : '';\n return `<a${getAttr('a')} href=\"${sanitizedHref}\"${rel}${textAttr}${dataQd('[')}>${text}</a>`;\n });\n\n // Autolinks — bare https?:// URLs become clickable <a> tags\n html = html.replace(/(^|\\s)(https?:\\/\\/[^\\s<]+)/g, (match, prefix, url) => {\n const sanitizedUrl = sanitizeUrl(url, options.allow_unsafe_urls);\n return `${prefix}<a${getAttr('a')} href=\"${sanitizedUrl}\" rel=\"noopener noreferrer\">${url}</a>`;\n });\n\n // Bold, italic, strikethrough\n // Order matters: ** before * (so ** isn't consumed as two *s)\n const inlinePatterns = [\n [/\\*\\*(.+?)\\*\\*/g, 'strong', '**'],\n [/__(.+?)__/g, 'strong', '__'],\n [/(?<!\\*)\\*(?!\\*)(.+?)(?<!\\*)\\*(?!\\*)/g, 'em', '*'],\n [/(?<!_)_(?!_)(.+?)(?<!_)_(?!_)/g, 'em', '_'],\n [/~~(.+?)~~/g, 'del', '~~']\n ];\n inlinePatterns.forEach(([pattern, tag, marker]) => {\n html = html.replace(pattern, `<${tag}${getAttr(tag)}${dataQd(marker)}>$1</${tag}>`);\n });\n\n // ── Step 5: Line breaks + paragraph wrapping ──\n if (lazy_linefeeds) {\n // Lazy linefeeds mode: every single \\n becomes <br> EXCEPT:\n // • Double newlines → paragraph break\n // • Newlines adjacent to block elements (h, blockquote, pre, hr, table, list)\n //\n // Strategy: protect block-adjacent newlines with §N§, convert\n // the rest, then restore.\n\n const blocks = [];\n let bi = 0;\n\n // Protect tables and lists from <br> injection\n html = html.replace(/<(table|[uo]l)[^>]*>[\\s\\S]*?<\\/\\1>/g, m => {\n blocks[bi] = m;\n return `§B${bi++}§`;\n });\n\n html = html.replace(/\\n\\n+/g, '§P§')\n // After block-level closing tags\n .replace(/(<\\/(?:h[1-6]|blockquote|pre)>)\\n/g, '$1§N§')\n .replace(/(<(?:h[1-6]|blockquote|pre|hr)[^>]*>)\\n/g, '$1§N§')\n // Before block-level opening tags\n .replace(/\\n(<(?:h[1-6]|blockquote|pre|hr)[^>]*>)/g, '§N§$1')\n .replace(/\\n(§B\\d+§)/g, '§N§$1')\n .replace(/(§B\\d+§)\\n/g, '$1§N§')\n // Convert surviving newlines to <br>\n .replace(/\\n/g, `<br${getAttr('br')}>`)\n // Restore\n .replace(/§N§/g, '\\n')\n .replace(/§P§/g, '</p><p>');\n\n // Restore protected blocks\n blocks.forEach((b, i) => html = html.replace(`§B${i}§`, b));\n\n html = '<p>' + html + '</p>';\n } else {\n // Standard mode: two trailing spaces → <br>, double newline → new paragraph\n html = html.replace(/ {2}$/gm, `<br${getAttr('br')}>`);\n\n html = html.replace(/\\n\\n+/g, (match, offset) => {\n const before = html.substring(0, offset);\n if (before.match(/<\\/(h[1-6]|blockquote|ul|ol|table|pre|hr)>$/)) {\n return '<p>';\n }\n return '</p><p>';\n });\n html = '<p>' + html + '</p>';\n }\n\n // ── Step 6: Cleanup ──\n // Remove <p> wrappers that accidentally enclose block elements.\n // This is simpler than trying to prevent them during wrapping.\n const cleanupPatterns = [\n [/<p><\\/p>/g, ''],\n [/<p>(<h[1-6][^>]*>)/g, '$1'],\n [/(<\\/h[1-6]>)<\\/p>/g, '$1'],\n [/<p>(<blockquote[^>]*>)/g, '$1'],\n [/(<\\/blockquote>)<\\/p>/g, '$1'],\n [/<p>(<ul[^>]*>|<ol[^>]*>)/g, '$1'],\n [/(<\\/ul>|<\\/ol>)<\\/p>/g, '$1'],\n [/<p>(<hr[^>]*>)<\\/p>/g, '$1'],\n [/<p>(<table[^>]*>)/g, '$1'],\n [/(<\\/table>)<\\/p>/g, '$1'],\n [/<p>(<pre[^>]*>)/g, '$1'],\n [/(<\\/pre>)<\\/p>/g, '$1'],\n [new RegExp(`<p>(${PLACEHOLDER_CB}\\\\d+§)</p>`, 'g'), '$1']\n ];\n cleanupPatterns.forEach(([pattern, replacement]) => {\n html = html.replace(pattern, replacement);\n });\n\n // When a block element is followed by a newline and then text, open a <p>.\n html = html.replace(/(<\\/(?:h[1-6]|blockquote|ul|ol|table|pre|hr)>)\\n([^<])/g, '$1\\n<p>$2');\n\n // ────────────────────────────────────────────────────────────────\n // Phase 4 — Code Restoration\n // ────────────────────────────────────────────────────────────────\n // Replace placeholders with rendered HTML. For fenced blocks this\n // means wrapping in <pre><code>…</code></pre> (or calling the\n // fence_plugin). For inline code it means <code>…</code>.\n\n codeBlocks.forEach((block, i) => {\n let replacement;\n\n if (block.custom && fence_plugin && fence_plugin.render) {\n // Delegate to the user-provided fence plugin.\n replacement = fence_plugin.render(block.code, block.lang);\n\n if (replacement === undefined) {\n // Plugin declined — fall back to default rendering.\n const langClass = !inline_styles && block.lang ? ` class=\"language-${block.lang}\"` : '';\n const codeAttr = inline_styles ? getAttr('code') : langClass;\n /* istanbul ignore next - bd-only branch */\n const langAttr = bidirectional && block.lang ? ` data-qd-lang=\"${escapeHtml(block.lang)}\"` : '';\n /* istanbul ignore next - bd-only branch */\n const fenceAttr = bidirectional ? ` data-qd-fence=\"${escapeHtml(block.fence)}\"` : '';\n replacement = `<pre${getAttr('pre')}${fenceAttr}${langAttr}><code${codeAttr}>${escapeHtml(block.code)}</code></pre>`;\n } else /* istanbul ignore next - bd-only branch */ if (bidirectional) {\n // Plugin returned HTML — inject data attributes for roundtrip.\n replacement = replacement.replace(/^<(\\w+)/,\n `<$1 data-qd-fence=\"${escapeHtml(block.fence)}\" data-qd-lang=\"${escapeHtml(block.lang)}\" data-qd-source=\"${escapeHtml(block.code)}\"`);\n }\n } else {\n // Default rendering — wrap in <pre><code>.\n const langClass = !inline_styles && block.lang ? ` class=\"language-${block.lang}\"` : '';\n const codeAttr = inline_styles ? getAttr('code') : langClass;\n /* istanbul ignore next - bd-only branch */\n const langAttr = bidirectional && block.lang ? ` data-qd-lang=\"${escapeHtml(block.lang)}\"` : '';\n /* istanbul ignore next - bd-only branch */\n const fenceAttr = bidirectional ? ` data-qd-fence=\"${escapeHtml(block.fence)}\"` : '';\n replacement = `<pre${getAttr('pre')}${fenceAttr}${langAttr}><code${codeAttr}>${block.code}</code></pre>`;\n }\n\n const placeholder = `${PLACEHOLDER_CB}${i}§`;\n html = html.replace(placeholder, replacement);\n });\n\n // Restore inline code spans\n inlineCodes.forEach((code, i) => {\n const placeholder = `${PLACEHOLDER_IC}${i}§`;\n html = html.replace(placeholder, `<code${getAttr('code')}${dataQd('`')}>${code}</code>`);\n });\n\n return html.trim();\n}\n\n// ════════════════════════════════════════════════════════════════════\n// Block-level line scanner\n// ════════════════════════════════════════════════════════════════════\n\n/**\n * scanLineBlocks — single-pass line scanner for headings, HR, blockquotes\n *\n * Walks the text line by line. For each line it checks (in order):\n * 1. Heading — starts with 1-6 '#' followed by a space\n * 2. HR — line is entirely '---…' (3+ dashes, optional trailing space)\n * 3. Blockquote — starts with '&gt; ' (the > was already HTML-escaped)\n *\n * Lines that don't match any block pattern are passed through unchanged.\n *\n * This replaces three separate global regex passes from the pre-1.2.8\n * architecture with one structured scan.\n *\n * @param {string} text The document text (HTML-escaped, code extracted)\n * @param {Function} getAttr Attribute factory (class or style)\n * @param {Function} dataQd Bidirectional marker factory\n * @returns {string} Text with block-level elements rendered\n */\nfunction scanLineBlocks(text, getAttr, dataQd) {\n const lines = text.split('\\n');\n const result = [];\n let i = 0;\n\n while (i < lines.length) {\n const line = lines[i];\n\n // ── Heading ──\n // Count leading '#' characters. Valid heading: 1-6 hashes then a space.\n // Example: \"## Hello World ##\" → <h2>Hello World</h2>\n let hashCount = 0;\n while (hashCount < line.length && hashCount < 7 && line[hashCount] === '#') {\n hashCount++;\n }\n if (hashCount >= 1 && hashCount <= 6 && line[hashCount] === ' ') {\n // Extract content after \"# \" and strip trailing hashes\n const content = line.slice(hashCount + 1).replace(/\\s*#+\\s*$/, '');\n const tag = 'h' + hashCount;\n result.push(`<${tag}${getAttr(tag)}${dataQd('#'.repeat(hashCount))}>${content}</${tag}>`);\n i++;\n continue;\n }\n\n // ── Horizontal Rule ──\n // Three or more dashes, optional trailing whitespace, nothing else.\n if (isDashHRLine(line)) {\n result.push(`<hr${getAttr('hr')}>`);\n i++;\n continue;\n }\n\n // ── Blockquote ──\n // After Phase 2, the '>' character has been escaped to '&gt;'.\n // Pattern: \"&gt; content\" or merged consecutive blockquotes.\n if (/^&gt;\\s+/.test(line)) {\n result.push(`<blockquote${getAttr('blockquote')}>${line.replace(/^&gt;\\s+/, '')}</blockquote>`);\n i++;\n continue;\n }\n\n // ── Pass-through ──\n result.push(line);\n i++;\n }\n\n // Merge consecutive blockquotes into a single element.\n // <blockquote>A</blockquote>\\n<blockquote>B</blockquote>\n // → <blockquote>A\\nB</blockquote>\n let joined = result.join('\\n');\n joined = joined.replace(/<\\/blockquote>\\n<blockquote>/g, '\\n');\n return joined;\n}\n\n// ════════════════════════════════════════════════════════════════════\n// Table processing (line walker)\n// ════════════════════════════════════════════════════════════════════\n\n/**\n * Inline markdown formatter for table cells.\n * Handles bold, italic, strikethrough, and code within cell text.\n * Links / images / autolinks are handled by the global inline pass\n * (Phase 3 Step 4) which runs after table processing.\n */\nfunction processInlineMarkdown(text, getAttr) {\n const patterns = [\n [/\\*\\*(.+?)\\*\\*/g, 'strong'],\n [/__(.+?)__/g, 'strong'],\n [/(?<!\\*)\\*(?!\\*)(.+?)(?<!\\*)\\*(?!\\*)/g, 'em'],\n [/(?<!_)_(?!_)(.+?)(?<!_)_(?!_)/g, 'em'],\n [/~~(.+?)~~/g, 'del'],\n [/`([^`]+)`/g, 'code']\n ];\n patterns.forEach(([pattern, tag]) => {\n text = text.replace(pattern, `<${tag}${getAttr(tag)}>$1</${tag}>`);\n });\n return text;\n}\n\n/**\n * processTable — line walker for markdown tables\n *\n * Walks through lines looking for runs of pipe-containing lines.\n * Each run is validated (must contain a separator row: |---|---|)\n * and rendered as an HTML <table>. Invalid runs are restored as-is.\n *\n * @param {string} text Full document text\n * @param {Function} getAttr Attribute factory\n * @returns {string} Text with tables rendered\n */\nfunction processTable(text, getAttr) {\n const lines = text.split('\\n');\n const result = [];\n let inTable = false;\n let tableLines = [];\n\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i].trim();\n\n if (line.includes('|') && (line.startsWith('|') || /[^\\\\|]/.test(line))) {\n if (!inTable) {\n inTable = true;\n tableLines = [];\n }\n tableLines.push(line);\n } else {\n if (inTable) {\n const tableHtml = buildTable(tableLines, getAttr);\n if (tableHtml) {\n result.push(tableHtml);\n } else {\n result.push(...tableLines);\n }\n inTable = false;\n tableLines = [];\n }\n result.push(lines[i]);\n }\n }\n\n // Handle table at end of document\n if (inTable && tableLines.length > 0) {\n const tableHtml = buildTable(tableLines, getAttr);\n if (tableHtml) {\n result.push(tableHtml);\n } else {\n result.push(...tableLines);\n }\n }\n\n return result.join('\\n');\n}\n\n/**\n * buildTable — validate and render a table from accumulated lines\n *\n * @param {string[]} lines Array of pipe-containing lines\n * @param {Function} getAttr Attribute factory\n * @returns {string|null} HTML table string, or null if invalid\n */\nfunction buildTable(lines, getAttr) {\n if (lines.length < 2) return null;\n\n // Find the separator row (---|---|)\n let separatorIndex = -1;\n for (let i = 1; i < lines.length; i++) {\n if (/^\\|?[\\s\\-:|]+\\|?$/.test(lines[i]) && lines[i].includes('-')) {\n separatorIndex = i;\n break;\n }\n }\n if (separatorIndex === -1) return null;\n\n const headerLines = lines.slice(0, separatorIndex);\n const bodyLines = lines.slice(separatorIndex + 1);\n\n // Parse alignment from separator cells (:--- = left, :---: = center, ---: = right)\n const separator = lines[separatorIndex];\n const separatorCells = separator.trim().replace(/^\\|/, '').replace(/\\|$/, '').split('|');\n const alignments = separatorCells.map(cell => {\n const trimmed = cell.trim();\n if (trimmed.startsWith(':') && trimmed.endsWith(':')) return 'center';\n if (trimmed.endsWith(':')) return 'right';\n return 'left';\n });\n\n let html = `<table${getAttr('table')}>\\n`;\n\n // Header\n html += `<thead${getAttr('thead')}>\\n`;\n headerLines.forEach(line => {\n html += `<tr${getAttr('tr')}>\\n`;\n const cells = line.trim().replace(/^\\|/, '').replace(/\\|$/, '').split('|');\n cells.forEach((cell, i) => {\n const alignStyle = alignments[i] && alignments[i] !== 'left' ? `text-align:${alignments[i]}` : '';\n const processedCell = processInlineMarkdown(cell.trim(), getAttr);\n html += `<th${getAttr('th', alignStyle)}>${processedCell}</th>\\n`;\n });\n html += '</tr>\\n';\n });\n html += '</thead>\\n';\n\n // Body\n if (bodyLines.length > 0) {\n html += `<tbody${getAttr('tbody')}>\\n`;\n bodyLines.forEach(line => {\n html += `<tr${getAttr('tr')}>\\n`;\n const cells = line.trim().replace(/^\\|/, '').replace(/\\|$/, '').split('|');\n cells.forEach((cell, i) => {\n const alignStyle = alignments[i] && alignments[i] !== 'left' ? `text-align:${alignments[i]}` : '';\n const processedCell = processInlineMarkdown(cell.trim(), getAttr);\n html += `<td${getAttr('td', alignStyle)}>${processedCell}</td>\\n`;\n });\n html += '</tr>\\n';\n });\n html += '</tbody>\\n';\n }\n\n html += '</table>';\n return html;\n}\n\n// ════════════════════════════════════════════════════════════════════\n// List processing (line walker)\n// ════════════════════════════════════════════════════════════════════\n\n/**\n * processLists — line walker for ordered, unordered, and task lists\n *\n * Scans each line for list markers (-, *, +, 1., 2., etc.) with\n * optional leading indentation for nesting. Non-list lines close\n * any open lists and pass through unchanged.\n *\n * Task lists (- [ ] / - [x]) are detected and rendered with\n * checkbox inputs.\n *\n * @param {string} text Full document text\n * @param {Function} getAttr Attribute factory\n * @param {boolean} inline_styles Whether to use inline styles\n * @param {boolean} bidirectional Whether to add data-qd markers\n * @returns {string} Text with lists rendered\n */\nfunction processLists(text, getAttr, inline_styles, bidirectional) {\n const lines = text.split('\\n');\n const result = [];\n const listStack = []; // tracks nesting: [{type:'ul', level:0}, …]\n\n // Helper to escape HTML for data-qd attributes. List markers (`-`, `*`,\n // `+`, `1.`, etc.) never contain HTML-special chars, so the replace\n // callback is defensive-only and never actually fires in practice.\n /* istanbul ignore next - defensive: list markers never trigger escaping */\n const escapeHtml = (text) => text.replace(/[&<>\"']/g,\n /* istanbul ignore next - defensive: list markers never contain HTML specials */\n m => ({'&':'&amp;','<':'&lt;','>':'&gt;','\"':'&quot;',\"'\":'&#39;'})[m]);\n /* istanbul ignore next - trivial no-op fallback; not exercised via bd bundle */\n const dataQd = bidirectional ? (marker) => ` data-qd=\"${escapeHtml(marker)}\"` : () => '';\n\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i];\n const match = line.match(/^(\\s*)([*\\-+]|\\d+\\.)\\s+(.+)$/);\n\n if (match) {\n const [, indent, marker, content] = match;\n const level = Math.floor(indent.length / 2);\n const isOrdered = /^\\d+\\./.test(marker);\n const listType = isOrdered ? 'ol' : 'ul';\n\n // Task list detection (only in unordered lists)\n let listItemContent = content;\n let taskListClass = '';\n const taskMatch = content.match(/^\\[([x ])\\]\\s+(.*)$/i);\n if (taskMatch && !isOrdered) {\n const [, checked, taskContent] = taskMatch;\n const isChecked = checked.toLowerCase() === 'x';\n const checkboxAttr = inline_styles\n ? ' style=\"margin-right:.5em\"'\n : ` class=\"${CLASS_PREFIX}task-checkbox\"`;\n listItemContent = `<input type=\"checkbox\"${checkboxAttr}${isChecked ? ' checked' : ''} disabled> ${taskContent}`;\n taskListClass = inline_styles ? ' style=\"list-style:none\"' : ` class=\"${CLASS_PREFIX}task-item\"`;\n }\n\n // Close deeper nesting levels\n while (listStack.length > level + 1) {\n const list = listStack.pop();\n result.push(`</${list.type}>`);\n }\n\n // Open new list or switch type at current level\n if (listStack.length === level) {\n listStack.push({ type: listType, level });\n result.push(`<${listType}${getAttr(listType)}>`);\n } else if (listStack.length === level + 1) {\n const currentList = listStack[listStack.length - 1];\n if (currentList.type !== listType) {\n result.push(`</${currentList.type}>`);\n listStack.pop();\n listStack.push({ type: listType, level });\n result.push(`<${listType}${getAttr(listType)}>`);\n }\n }\n\n const liAttr = taskListClass || getAttr('li');\n result.push(`<li${liAttr}${dataQd(marker)}>${listItemContent}</li>`);\n } else {\n // Not a list item — close all open lists\n while (listStack.length > 0) {\n const list = listStack.pop();\n result.push(`</${list.type}>`);\n }\n result.push(line);\n }\n }\n\n // Close any remaining open lists\n while (listStack.length > 0) {\n const list = listStack.pop();\n result.push(`</${list.type}>`);\n }\n\n return result.join('\\n');\n}\n\n// ════════════════════════════════════════════════════════════════════\n// Static API\n// ════════════════════════════════════════════════════════════════════\n\n/**\n * Emit CSS rules for all quikdown elements.\n *\n * @param {string} prefix Class prefix (default: 'quikdown-')\n * @param {string} theme 'light' (default) or 'dark'\n * @returns {string} CSS text\n */\nquikdown.emitStyles = function(prefix = 'quikdown-', theme = 'light') {\n const styles = QUIKDOWN_STYLES;\n\n const themeOverrides = {\n dark: {\n '#f4f4f4': '#2a2a2a', // pre background\n '#f0f0f0': '#2a2a2a', // code background\n '#f2f2f2': '#2a2a2a', // th background\n '#ddd': '#3a3a3a', // borders\n '#06c': '#6db3f2', // links\n _textColor: '#e0e0e0'\n },\n light: {\n _textColor: '#333'\n }\n };\n\n let css = '';\n for (const [tag, style] of Object.entries(styles)) {\n let themedStyle = style;\n\n if (theme === 'dark' && themeOverrides.dark) {\n for (const [oldColor, newColor] of Object.entries(themeOverrides.dark)) {\n if (!oldColor.startsWith('_')) {\n themedStyle = themedStyle.replaceAll(oldColor, newColor);\n }\n }\n const needsTextColor = ['h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'td', 'li', 'blockquote'];\n if (needsTextColor.includes(tag)) {\n themedStyle += `;color:${themeOverrides.dark._textColor}`;\n }\n } else if (theme === 'light' && themeOverrides.light) {\n const needsTextColor = ['h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'td', 'li', 'blockquote'];\n if (needsTextColor.includes(tag)) {\n themedStyle += `;color:${themeOverrides.light._textColor}`;\n }\n }\n\n css += `.${prefix}${tag} { ${themedStyle} }\\n`;\n }\n\n return css;\n};\n\n/**\n * Create a pre-configured parser with baked-in options.\n *\n * @param {Object} options Options to bake in\n * @returns {Function} Configured quikdown(markdown) function\n */\nquikdown.configure = function(options) {\n return function(markdown) {\n return quikdown(markdown, options);\n };\n};\n\n/** Semantic version (injected at build time) */\nquikdown.version = quikdownVersion;\n\n// ════════════════════════════════════════════════════════════════════\n// Exports\n// ════════════════════════════════════════════════════════════════════\n\n/* istanbul ignore next */\nif (typeof module !== 'undefined' && module.exports) {\n module.exports = quikdown;\n}\n\n/* istanbul ignore next */\nif (typeof window !== 'undefined') {\n window.quikdown = quikdown;\n}\n\nexport default quikdown;\n","/**\n * quikdown_bd - Bidirectional markdown/HTML converter\n * Extends core quikdown with HTML→Markdown conversion\n * \n * Uses data-qd attributes to preserve original markdown syntax\n * Enables HTML→Markdown conversion for quikdown-generated HTML\n */\n\nimport quikdown from './quikdown.js';\n\n/**\n * Create bidirectional version by extending quikdown\n * This wraps quikdown and adds the toMarkdown method\n */\nfunction quikdown_bd(markdown, options = {}) {\n // Use core quikdown with bidirectional flag to add data-qd attributes\n return quikdown(markdown, { ...options, bidirectional: true });\n}\n\n// Copy all properties and methods from quikdown (including version).\n// Skip `configure` — quikdown_bd provides its own override below, so the\n// inner quikdown.configure is dead code in this bundle.\nObject.keys(quikdown).forEach(key => {\n if (key === 'configure') return;\n quikdown_bd[key] = quikdown[key];\n});\n\n// Add the toMarkdown method for HTML→Markdown conversion\nquikdown_bd.toMarkdown = function(htmlOrElement, options = {}) {\n // Accept either HTML string or DOM element\n let container;\n if (typeof htmlOrElement === 'string') {\n container = document.createElement('div');\n container.innerHTML = htmlOrElement;\n } else if (htmlOrElement instanceof Element) {\n /* istanbul ignore next - browser-only code path, not testable in jsdom */\n container = htmlOrElement;\n } else {\n return '';\n }\n \n // Walk the DOM tree and reconstruct markdown\n function walkNode(node, parentContext = {}) {\n if (node.nodeType === Node.TEXT_NODE) {\n // Return text content, preserving whitespace where needed\n return node.textContent;\n }\n \n if (node.nodeType !== Node.ELEMENT_NODE) {\n return '';\n }\n \n const tag = node.tagName.toLowerCase();\n const dataQd = node.getAttribute('data-qd');\n \n // Process children with context\n let childContent = '';\n for (const child of node.childNodes) {\n childContent += walkNode(child, { parentTag: tag, ...parentContext });\n }\n \n // Determine markdown based on element and attributes\n switch (tag) {\n case 'h1':\n case 'h2':\n case 'h3':\n case 'h4':\n case 'h5':\n case 'h6':\n const level = parseInt(tag[1]);\n const prefix = dataQd || '#'.repeat(level);\n return `${prefix} ${childContent.trim()}\\n\\n`;\n \n case 'strong':\n case 'b':\n if (!childContent) return ''; // Don't add markers for empty content\n const boldMarker = dataQd || '**';\n return `${boldMarker}${childContent}${boldMarker}`;\n \n case 'em':\n case 'i':\n if (!childContent) return ''; // Don't add markers for empty content\n const emMarker = dataQd || '*';\n return `${emMarker}${childContent}${emMarker}`;\n \n case 'del':\n case 's':\n case 'strike':\n if (!childContent) return ''; // Don't add markers for empty content\n const delMarker = dataQd || '~~';\n return `${delMarker}${childContent}${delMarker}`;\n \n case 'code':\n // Note: code inside pre is handled directly by the pre case using querySelector\n if (!childContent) return ''; // Don't add markers for empty content\n const codeMarker = dataQd || '`';\n return `${codeMarker}${childContent}${codeMarker}`;\n \n case 'pre':\n const fence = node.getAttribute('data-qd-fence') || dataQd || '```';\n const lang = node.getAttribute('data-qd-lang') || '';\n \n // Check if this was created by a fence plugin with reverse handler\n if (options.fence_plugin && options.fence_plugin.reverse && lang) {\n try {\n const result = options.fence_plugin.reverse(node);\n if (result && result.content) {\n const fenceMarker = result.fence || fence;\n const langStr = result.lang || lang;\n return `${fenceMarker}${langStr}\\n${result.content}\\n${fenceMarker}\\n\\n`;\n }\n } catch (err) {\n console.warn('Fence reverse handler error:', err);\n // Fall through to default handling\n }\n }\n \n // Fallback: use data-qd-source if available\n const source = node.getAttribute('data-qd-source');\n if (source) {\n return `${fence}${lang}\\n${source}\\n${fence}\\n\\n`;\n }\n \n // Final fallback: extract text content\n const codeEl = node.querySelector('code');\n const codeContent = codeEl ? codeEl.textContent : childContent;\n return `${fence}${lang}\\n${codeContent.trimEnd()}\\n${fence}\\n\\n`;\n \n case 'blockquote':\n const quoteMarker = dataQd || '>';\n const lines = childContent.trim().split('\\n');\n return lines.map(line => `${quoteMarker} ${line}`).join('\\n') + '\\n\\n';\n \n case 'hr':\n const hrMarker = dataQd || '---';\n return `${hrMarker}\\n\\n`;\n \n case 'br':\n const brMarker = dataQd || ' ';\n return `${brMarker}\\n`;\n \n case 'a':\n const linkText = node.getAttribute('data-qd-text') || childContent.trim();\n const href = node.getAttribute('href') || '';\n // Check for autolinks\n if (linkText === href && !dataQd) {\n return `<${href}>`;\n }\n return `[${linkText}](${href})`;\n \n case 'img':\n const alt = node.getAttribute('data-qd-alt') || node.getAttribute('alt') || '';\n const src = node.getAttribute('data-qd-src') || node.getAttribute('src') || '';\n const imgMarker = dataQd || '!';\n return `${imgMarker}[${alt}](${src})`;\n \n case 'ul':\n case 'ol':\n return walkList(node, tag === 'ol') + '\\n';\n \n case 'li':\n // Handled by list processor\n return childContent;\n \n case 'table':\n return walkTable(node) + '\\n\\n';\n \n case 'p':\n // Check if it's actually a paragraph or just a wrapper\n if (childContent.trim()) {\n // Check if paragraph ends with a line that's just whitespace\n // This indicates an intentional blank line before the next element\n const lines = childContent.split('\\n');\n let content = childContent.trim();\n \n // If the last line(s) are just whitespace, preserve one blank line\n if (lines.length > 1) {\n let trailingBlankLines = 0;\n for (let i = lines.length - 1; i >= 0; i--) {\n if (lines[i].trim() === '') {\n trailingBlankLines++;\n } else {\n break;\n }\n }\n if (trailingBlankLines > 0) {\n // Add a line with just a space, followed by single newline\n // The \\n\\n will be added below for paragraph separation\n content = content + '\\n ';\n // Only add one newline since we're preserving the space line\n return content + '\\n';\n }\n }\n \n return content + '\\n\\n';\n }\n return '';\n \n case 'div':\n // Check if this was created by a fence plugin with reverse handler\n const divLang = node.getAttribute('data-qd-lang');\n const divFence = node.getAttribute('data-qd-fence');\n \n if (divLang && options.fence_plugin && options.fence_plugin.reverse) {\n try {\n const result = options.fence_plugin.reverse(node);\n if (result && result.content) {\n const fenceMarker = result.fence || divFence || '```';\n const langStr = result.lang || divLang;\n return `${fenceMarker}${langStr}\\n${result.content}\\n${fenceMarker}\\n\\n`;\n }\n } catch (err) {\n console.warn('Fence reverse handler error:', err);\n // Fall through to default handling\n }\n }\n \n // Fallback: use data-qd-source if available\n const divSource = node.getAttribute('data-qd-source');\n if (divSource && divFence) {\n return `${divFence}${divLang || ''}\\n${divSource}\\n${divFence}\\n\\n`;\n }\n \n // Check if it's a mermaid container\n if (node.classList && node.classList.contains('mermaid-container')) {\n const fence = node.getAttribute('data-qd-fence') || '```';\n const lang = node.getAttribute('data-qd-lang') || 'mermaid';\n \n // First check for data-qd-source attribute on the container\n const source = node.getAttribute('data-qd-source');\n if (source) {\n // Decode HTML entities from the attribute (mainly &quot;)\n const temp = document.createElement('textarea');\n temp.innerHTML = source;\n const code = temp.value;\n return `${fence}${lang}\\n${code}\\n${fence}\\n\\n`;\n }\n \n // Check for source on the pre.mermaid element\n const mermaidPre = node.querySelector('pre.mermaid');\n if (mermaidPre) {\n const preSource = mermaidPre.getAttribute('data-qd-source');\n if (preSource) {\n const temp = document.createElement('textarea');\n temp.innerHTML = preSource;\n const code = temp.value;\n return `${fence}${lang}\\n${code}\\n${fence}\\n\\n`;\n }\n }\n \n // Fallback: Look for the legacy .mermaid-source element\n const sourceElement = node.querySelector('.mermaid-source');\n if (sourceElement) {\n // Decode HTML entities\n const temp = document.createElement('div');\n temp.innerHTML = sourceElement.innerHTML;\n const code = temp.textContent;\n return `${fence}${lang}\\n${code}\\n${fence}\\n\\n`;\n }\n \n // Final fallback: try to extract from the mermaid element (unreliable after rendering)\n const mermaidElement = node.querySelector('.mermaid');\n if (mermaidElement && mermaidElement.textContent.includes('graph')) {\n return `${fence}${lang}\\n${mermaidElement.textContent.trim()}\\n${fence}\\n\\n`;\n }\n }\n // Check if it's a standalone mermaid diagram (legacy)\n if (node.classList && node.classList.contains('mermaid')) {\n const fence = node.getAttribute('data-qd-fence') || '```';\n const lang = node.getAttribute('data-qd-lang') || 'mermaid';\n const code = node.textContent.trim();\n return `${fence}${lang}\\n${code}\\n${fence}\\n\\n`;\n }\n // Pass through other divs\n return childContent;\n \n case 'span':\n // Pass through container elements\n return childContent;\n \n default:\n return childContent;\n }\n }\n \n // Walk list elements\n function walkList(listNode, isOrdered, depth = 0) {\n let result = '';\n let index = 1;\n const indent = ' '.repeat(depth);\n \n for (const child of listNode.children) {\n if (child.tagName !== 'LI') continue;\n \n const dataQd = child.getAttribute('data-qd');\n let marker = dataQd || (isOrdered ? `${index}.` : '-');\n \n // Check for task list checkbox\n const checkbox = child.querySelector('input[type=\"checkbox\"]');\n if (checkbox) {\n const checked = checkbox.checked ? 'x' : ' ';\n marker = '-';\n // Get text without the checkbox\n let text = '';\n for (const node of child.childNodes) {\n if (node.nodeType === Node.TEXT_NODE) {\n text += node.textContent;\n } else if (node.tagName && node.tagName !== 'INPUT') {\n text += walkNode(node);\n }\n }\n result += `${indent}${marker} [${checked}] ${text.trim()}\\n`;\n } else {\n let itemContent = '';\n \n for (const node of child.childNodes) {\n if (node.tagName === 'UL' || node.tagName === 'OL') {\n itemContent += walkList(node, node.tagName === 'OL', depth + 1);\n } else {\n itemContent += walkNode(node);\n }\n }\n \n result += `${indent}${marker} ${itemContent.trim()}\\n`;\n }\n \n index++;\n }\n \n return result;\n }\n \n // Walk table elements\n function walkTable(table) {\n let result = '';\n const alignData = table.getAttribute('data-qd-align');\n const alignments = alignData ? alignData.split(',') : [];\n \n // Process header\n const thead = table.querySelector('thead');\n if (thead) {\n const headerRow = thead.querySelector('tr');\n if (headerRow) {\n const headers = [];\n for (const th of headerRow.querySelectorAll('th')) {\n headers.push(th.textContent.trim());\n }\n result += '| ' + headers.join(' | ') + ' |\\n';\n \n // Add separator with alignment\n const separators = headers.map((_, i) => {\n const align = alignments[i] || 'left';\n if (align === 'center') return ':---:';\n if (align === 'right') return '---:';\n return '---';\n });\n result += '| ' + separators.join(' | ') + ' |\\n';\n }\n }\n \n // Process body\n const tbody = table.querySelector('tbody');\n if (tbody) {\n for (const row of tbody.querySelectorAll('tr')) {\n const cells = [];\n for (const td of row.querySelectorAll('td')) {\n cells.push(td.textContent.trim());\n }\n if (cells.length > 0) {\n result += '| ' + cells.join(' | ') + ' |\\n';\n }\n }\n }\n \n return result.trim();\n }\n \n // Process the DOM tree\n let markdown = walkNode(container);\n \n // Clean up\n markdown = markdown.replace(/\\n{3,}/g, '\\n\\n'); // Remove excessive newlines\n markdown = markdown.trim();\n \n return markdown;\n};\n\n// Override the configure method to return a bidirectional version.\n// We delegate to the inner quikdown.configure so the shared closure\n// machinery is exercised in both bundles (no dead code).\nquikdown_bd.configure = function(options) {\n const innerParser = quikdown.configure({ ...options, bidirectional: true });\n return function(markdown) {\n return innerParser(markdown);\n };\n};\n\n// Set version\n// Version is already copied from quikdown via Object.keys loop\n\n// Export for both module and browser\n/* istanbul ignore next */\nif (typeof module !== 'undefined' && module.exports) {\n module.exports = quikdown_bd;\n}\n\n/* istanbul ignore next */\nif (typeof window !== 'undefined') {\n window.quikdown_bd = quikdown_bd;\n}\n\nexport default quikdown_bd;","/**\n * Rich copy functionality for QuikdownEditor\n * Handles copying rendered content with proper formatting for pasting into rich text editors\n */\n\n/**\n * Get platform information\n * @returns {string} The detected platform: 'macos', 'windows', 'linux', or 'unknown'\n */\nfunction getPlatform() {\n const platform = navigator.platform?.toLowerCase() || '';\n const userAgent = navigator.userAgent?.toLowerCase() || '';\n \n if (platform.includes('mac') || userAgent.includes('mac')) {\n return 'macos';\n } else if (userAgent.includes('windows')) {\n return 'windows';\n } else if (userAgent.includes('linux')) {\n return 'linux';\n }\n return 'unknown';\n}\n\n/**\n * Copy to clipboard using HTML selection fallback (for Safari)\n * Uses div with selection to preserve HTML formatting\n * @param {string} html - HTML content to copy\n * @returns {boolean} Success status\n */\nfunction copyToClipboard(html) {\n let tempDiv;\n let result;\n \n try {\n // Use a div instead of textarea to preserve HTML formatting\n tempDiv = document.createElement('div');\n tempDiv.style.position = 'fixed';\n tempDiv.style.left = '-9999px';\n tempDiv.style.top = '0';\n tempDiv.style.width = '1px';\n tempDiv.style.height = '1px';\n tempDiv.style.overflow = 'hidden';\n tempDiv.innerHTML = html;\n \n document.body.appendChild(tempDiv);\n \n // Select the HTML content\n const range = document.createRange();\n range.selectNodeContents(tempDiv);\n const selection = window.getSelection();\n selection.removeAllRanges();\n selection.addRange(range);\n \n // Try to copy\n result = document.execCommand('copy');\n \n // Clear selection\n selection.removeAllRanges();\n } catch (err) {\n console.error('Fallback copy failed:', err);\n result = false;\n } finally {\n if (tempDiv && tempDiv.parentNode) {\n document.body.removeChild(tempDiv);\n }\n }\n \n return result;\n}\n\n/**\n * Convert SVG to PNG blob (based on squibview's implementation)\n * @param {SVGElement} svgElement - The SVG element to convert\n * @returns {Promise<Blob>} A promise that resolves with the PNG blob\n */\nasync function svgToPng(svgElement, needsWhiteBackground = false) {\n return new Promise((resolve, reject) => {\n const svgString = new XMLSerializer().serializeToString(svgElement);\n const canvas = document.createElement('canvas');\n const ctx = canvas.getContext('2d');\n const img = new Image();\n \n const scale = 2;\n \n // Check if this is a Mermaid-generated SVG (they don't have explicit width/height attributes)\n const isMermaidSvg = svgElement.closest('.mermaid') || svgElement.classList.contains('mermaid');\n const hasExplicitDimensions = svgElement.getAttribute('width') && svgElement.getAttribute('height');\n \n let svgWidth, svgHeight;\n \n if (isMermaidSvg || !hasExplicitDimensions) {\n // For Mermaid or other generated SVGs, prioritize computed dimensions\n svgWidth = svgElement.clientWidth || \n (svgElement.viewBox && svgElement.viewBox.baseVal.width) || \n parseFloat(svgElement.getAttribute('width')) || 400;\n svgHeight = svgElement.clientHeight || \n (svgElement.viewBox && svgElement.viewBox.baseVal.height) || \n parseFloat(svgElement.getAttribute('height')) || 300;\n } else {\n // For explicit SVGs (like fenced SVG blocks), prioritize explicit attributes\n svgWidth = parseFloat(svgElement.getAttribute('width')) || \n (svgElement.viewBox && svgElement.viewBox.baseVal.width) || \n svgElement.clientWidth || 400;\n svgHeight = parseFloat(svgElement.getAttribute('height')) || \n (svgElement.viewBox && svgElement.viewBox.baseVal.height) || \n svgElement.clientHeight || 300;\n }\n \n // Ensure the SVG string has explicit dimensions by modifying it if necessary\n let modifiedSvgString = svgString;\n if (svgWidth && svgHeight) {\n // Create a temporary SVG element to modify the serialized string\n const tempDiv = document.createElement('div');\n tempDiv.innerHTML = svgString;\n const tempSvg = tempDiv.querySelector('svg');\n if (tempSvg) {\n tempSvg.setAttribute('width', svgWidth.toString());\n tempSvg.setAttribute('height', svgHeight.toString());\n modifiedSvgString = new XMLSerializer().serializeToString(tempSvg);\n }\n }\n \n canvas.width = svgWidth * scale;\n canvas.height = svgHeight * scale;\n ctx.scale(scale, scale);\n \n img.onload = () => {\n try {\n // Add white background for math equations (they often have transparent backgrounds)\n if (needsWhiteBackground) {\n ctx.fillStyle = 'white';\n ctx.fillRect(0, 0, canvas.width, canvas.height);\n }\n \n ctx.drawImage(img, 0, 0, svgWidth, svgHeight);\n canvas.toBlob(blob => {\n resolve(blob);\n }, 'image/png', 1.0);\n } catch (err) {\n reject(err);\n }\n };\n \n img.onerror = reject;\n // Use data URI instead of blob URL to avoid tainting the canvas\n const svgDataUrl = `data:image/svg+xml;charset=utf-8,${encodeURIComponent(modifiedSvgString)}`;\n img.src = svgDataUrl;\n });\n}\n\n/**\n * Rasterize a GeoJSON Leaflet map to PNG data URL (following Gem's guide)\n * @param {HTMLElement} liveContainer - The live map container element\n * @returns {Promise<string|null>} PNG data URL or null if failed\n */\nasync function rasterizeGeoJSONMap(liveContainer) {\n try {\n const map = liveContainer._map;\n if (!map) {\n console.warn('No map found on container');\n return null;\n }\n \n // Get container dimensions\n const mapRect = liveContainer.getBoundingClientRect();\n const width = Math.round(mapRect.width);\n const height = Math.round(mapRect.height);\n \n if (width === 0 || height === 0) {\n console.warn('Map container has zero dimensions');\n return null;\n }\n \n // Create canvas sized to the map container\n const canvas = document.createElement('canvas');\n const dpr = window.devicePixelRatio || 1;\n \n // Set canvas size with DPR for sharpness\n canvas.width = width * dpr;\n canvas.height = height * dpr;\n canvas.style.width = width + 'px';\n canvas.style.height = height + 'px';\n \n const ctx = canvas.getContext('2d');\n ctx.scale(dpr, dpr);\n \n // White background\n ctx.fillStyle = '#FFFFFF';\n ctx.fillRect(0, 0, width, height);\n \n // 1. Draw tiles from THIS container only\n const tiles = liveContainer.querySelectorAll('.leaflet-tile');\n \n const tilePromises = [];\n for (const tile of tiles) {\n tilePromises.push(new Promise((resolve) => {\n const img = new Image();\n img.crossOrigin = 'anonymous';\n \n img.onload = () => {\n try {\n // Calculate tile position relative to container\n const tileRect = tile.getBoundingClientRect();\n const offsetX = tileRect.left - mapRect.left;\n const offsetY = tileRect.top - mapRect.top;\n \n // Draw tile at correct position\n ctx.drawImage(img, offsetX, offsetY, tileRect.width, tileRect.height);\n } catch (err) {\n console.warn('Failed to draw tile:', err);\n }\n resolve();\n };\n \n img.onerror = () => {\n console.warn('Failed to load tile:', tile.src);\n resolve();\n };\n \n img.src = tile.src;\n }));\n }\n \n // Wait for all tiles to load\n await Promise.all(tilePromises);\n \n // 2. Draw vector overlays (SVG paths for GeoJSON features)\n const svgOverlays = liveContainer.querySelectorAll('svg:not(.leaflet-attribution-flag)');\n \n for (const svg of svgOverlays) {\n // Skip attribution/control overlays\n if (svg.closest('.leaflet-control')) continue;\n \n try {\n const svgRect = svg.getBoundingClientRect();\n const offsetX = svgRect.left - mapRect.left;\n const offsetY = svgRect.top - mapRect.top;\n \n // Serialize SVG\n const serializer = new XMLSerializer();\n const svgStr = serializer.serializeToString(svg);\n const svgBlob = new Blob([svgStr], { type: 'image/svg+xml;charset=utf-8' });\n const url = URL.createObjectURL(svgBlob);\n \n // Draw SVG overlay\n await new Promise((resolve, reject) => {\n const img = new Image();\n img.onload = () => {\n ctx.drawImage(img, offsetX, offsetY, svgRect.width, svgRect.height);\n URL.revokeObjectURL(url);\n resolve();\n };\n img.onerror = () => {\n URL.revokeObjectURL(url);\n reject(new Error('Failed to load SVG overlay'));\n };\n img.src = url;\n });\n } catch (err) {\n console.warn('Failed to draw SVG overlay:', err);\n }\n }\n \n // 3. Draw marker icons if any\n const markerIcons = liveContainer.querySelectorAll('.leaflet-marker-icon');\n \n for (const marker of markerIcons) {\n try {\n const img = new Image();\n img.crossOrigin = 'anonymous';\n \n await new Promise((resolve) => {\n img.onload = () => {\n const markerRect = marker.getBoundingClientRect();\n const offsetX = markerRect.left - mapRect.left;\n const offsetY = markerRect.top - mapRect.top;\n ctx.drawImage(img, offsetX, offsetY, markerRect.width, markerRect.height);\n resolve();\n };\n img.onerror = resolve;\n img.src = marker.src;\n });\n } catch (err) {\n console.warn('Failed to draw marker icon:', err);\n }\n }\n \n // Return PNG data URL\n return canvas.toDataURL('image/png', 1.0);\n \n } catch (error) {\n console.error('Failed to rasterize GeoJSON map:', error);\n return null;\n }\n}\n\n/**\n * Get rendered content as rich HTML suitable for clipboard\n * @param {HTMLElement} previewPanel - The preview panel element to copy from\n * @returns {Promise<{success: boolean, html?: string, text?: string}>}\n */\nexport async function getRenderedContent(previewPanel) {\n if (!previewPanel) {\n throw new Error('No preview panel available');\n }\n \n // Check if MathJax needs to render (only if not already rendered)\n const mathBlocks = previewPanel.querySelectorAll('.math-display');\n if (mathBlocks.length > 0) {\n // Check if already rendered (has mjx-container inside)\n const needsRendering = Array.from(mathBlocks).some(block => !block.querySelector('mjx-container'));\n \n if (needsRendering && window.MathJax && window.MathJax.typesetPromise) {\n try {\n await window.MathJax.typesetPromise(Array.from(mathBlocks));\n } catch (err) {\n console.warn('MathJax typesetting failed:', err);\n }\n }\n }\n \n // Clone the preview panel to avoid modifying the actual DOM\n const clone = previewPanel.cloneNode(true);\n \n // Process different fence types for rich copy\n try {\n // Phase 1: Process basic markdown elements with inline styles\n \n // 1.1 Text formatting - add inline styles\n clone.querySelectorAll('strong, b').forEach(el => {\n el.style.fontWeight = 'bold';\n });\n \n clone.querySelectorAll('em, i').forEach(el => {\n el.style.fontStyle = 'italic';\n });\n \n clone.querySelectorAll('del, s, strike').forEach(el => {\n el.style.textDecoration = 'line-through';\n });\n \n clone.querySelectorAll('u').forEach(el => {\n el.style.textDecoration = 'underline';\n });\n \n clone.querySelectorAll('code:not(pre code)').forEach(el => {\n el.style.backgroundColor = '#f4f4f4';\n el.style.padding = '2px 4px';\n el.style.borderRadius = '3px';\n el.style.fontFamily = 'monospace';\n el.style.fontSize = '0.9em';\n });\n \n // 1.2 Block elements - add inline styles\n clone.querySelectorAll('h1').forEach(el => {\n el.style.fontSize = '2em';\n el.style.fontWeight = 'bold';\n el.style.marginTop = '0.67em';\n el.style.marginBottom = '0.67em';\n });\n \n clone.querySelectorAll('h2').forEach(el => {\n el.style.fontSize = '1.5em';\n el.style.fontWeight = 'bold';\n el.style.marginTop = '0.83em';\n el.style.marginBottom = '0.83em';\n });\n \n clone.querySelectorAll('h3').forEach(el => {\n el.style.fontSize = '1.17em';\n el.style.fontWeight = 'bold';\n el.style.marginTop = '1em';\n el.style.marginBottom = '1em';\n });\n \n clone.querySelectorAll('h4').forEach(el => {\n el.style.fontSize = '1em';\n el.style.fontWeight = 'bold';\n el.style.marginTop = '1.33em';\n el.style.marginBottom = '1.33em';\n });\n \n clone.querySelectorAll('h5').forEach(el => {\n el.style.fontSize = '0.83em';\n el.style.fontWeight = 'bold';\n el.style.marginTop = '1.67em';\n el.style.marginBottom = '1.67em';\n });\n \n clone.querySelectorAll('h6').forEach(el => {\n el.style.fontSize = '0.67em';\n el.style.fontWeight = 'bold';\n el.style.marginTop = '2.33em';\n el.style.marginBottom = '2.33em';\n });\n \n clone.querySelectorAll('blockquote').forEach(el => {\n el.style.borderLeft = '4px solid #ddd';\n el.style.marginLeft = '0';\n el.style.paddingLeft = '1em';\n el.style.color = '#666';\n });\n \n clone.querySelectorAll('hr').forEach(el => {\n el.style.border = 'none';\n el.style.borderTop = '1px solid #ccc';\n el.style.margin = '1em 0';\n });\n \n // 1.3 Tables - add inline styles\n clone.querySelectorAll('table').forEach(table => {\n table.style.borderCollapse = 'collapse';\n table.style.width = '100%';\n table.style.marginBottom = '1em';\n });\n \n clone.querySelectorAll('th').forEach(th => {\n th.style.border = '1px solid #ccc';\n th.style.padding = '8px';\n th.style.textAlign = 'left';\n th.style.backgroundColor = '#f0f0f0';\n th.style.fontWeight = 'bold';\n });\n \n clone.querySelectorAll('td').forEach(td => {\n td.style.border = '1px solid #ccc';\n td.style.padding = '8px';\n td.style.textAlign = 'left';\n });\n \n // 1.4 Links - add inline styles\n clone.querySelectorAll('a').forEach(a => {\n a.style.color = '#0066cc';\n a.style.textDecoration = 'underline';\n });\n \n // Process code blocks - wrap in table and add syntax highlighting colors\n clone.querySelectorAll('pre code').forEach(block => {\n const pre = block.parentElement;\n \n // Add inline styles for syntax highlighting (GitHub theme colors)\n if (block.classList.contains('hljs')) {\n // Apply inline styles to all highlight.js elements\n block.querySelectorAll('.hljs-keyword').forEach(el => {\n el.style.color = '#d73a49';\n el.style.fontWeight = 'bold';\n });\n block.querySelectorAll('.hljs-string').forEach(el => {\n el.style.color = '#032f62';\n });\n block.querySelectorAll('.hljs-number').forEach(el => {\n el.style.color = '#005cc5';\n });\n block.querySelectorAll('.hljs-comment').forEach(el => {\n el.style.color = '#6a737d';\n el.style.fontStyle = 'italic';\n });\n block.querySelectorAll('.hljs-function').forEach(el => {\n el.style.color = '#6f42c1';\n });\n block.querySelectorAll('.hljs-class').forEach(el => {\n el.style.color = '#6f42c1';\n });\n block.querySelectorAll('.hljs-title').forEach(el => {\n el.style.color = '#6f42c1';\n });\n block.querySelectorAll('.hljs-built_in').forEach(el => {\n el.style.color = '#005cc5';\n });\n block.querySelectorAll('.hljs-literal').forEach(el => {\n el.style.color = '#005cc5';\n });\n block.querySelectorAll('.hljs-meta').forEach(el => {\n el.style.color = '#005cc5';\n });\n block.querySelectorAll('.hljs-attr').forEach(el => {\n el.style.color = '#22863a';\n });\n block.querySelectorAll('.hljs-variable').forEach(el => {\n el.style.color = '#e36209';\n });\n block.querySelectorAll('.hljs-regexp').forEach(el => {\n el.style.color = '#032f62';\n });\n block.querySelectorAll('.hljs-selector-class').forEach(el => {\n el.style.color = '#22863a';\n });\n block.querySelectorAll('.hljs-selector-id').forEach(el => {\n el.style.color = '#6f42c1';\n });\n block.querySelectorAll('.hljs-selector-tag').forEach(el => {\n el.style.color = '#22863a';\n });\n block.querySelectorAll('.hljs-tag').forEach(el => {\n el.style.color = '#22863a';\n });\n block.querySelectorAll('.hljs-name').forEach(el => {\n el.style.color = '#22863a';\n });\n block.querySelectorAll('.hljs-attribute').forEach(el => {\n el.style.color = '#6f42c1';\n });\n }\n \n const table = document.createElement('table');\n table.style.width = '100%';\n table.style.borderCollapse = 'collapse';\n table.style.border = 'none';\n table.style.marginBottom = '1em';\n \n const tr = document.createElement('tr');\n const td = document.createElement('td');\n td.style.backgroundColor = '#f7f7f7';\n td.style.padding = '12px';\n td.style.fontFamily = 'Consolas, Monaco, \"Courier New\", monospace';\n td.style.fontSize = '14px';\n td.style.lineHeight = '1.4';\n td.style.whiteSpace = 'pre';\n td.style.overflowX = 'auto';\n td.style.border = '1px solid #ddd';\n td.style.borderRadius = '4px';\n \n // Move the formatted code content with inline styles\n td.innerHTML = block.innerHTML;\n \n tr.appendChild(td);\n table.appendChild(tr);\n \n // Replace the pre element with the table\n pre.parentNode.replaceChild(table, pre);\n });\n \n // Process images - convert to data URLs and ensure proper dimensions\n const images = clone.querySelectorAll('img');\n for (const img of images) {\n // Ensure image has dimensions for Google Docs compatibility\n if (!img.width && img.naturalWidth) {\n img.width = img.naturalWidth;\n }\n if (!img.height && img.naturalHeight) {\n img.height = img.naturalHeight;\n }\n \n // Set max dimensions to prevent huge images\n const maxWidth = 800;\n const maxHeight = 600;\n if (img.width > maxWidth || img.height > maxHeight) {\n const scale = Math.min(maxWidth / img.width, maxHeight / img.height);\n img.width = Math.round(img.width * scale);\n img.height = Math.round(img.height * scale);\n }\n \n // Ensure width and height attributes are set\n if (img.width) {\n img.setAttribute('width', img.width.toString());\n img.style.width = img.width + 'px';\n }\n if (img.height) {\n img.setAttribute('height', img.height.toString());\n img.style.height = img.height + 'px';\n }\n \n // Add v:shapes for Word compatibility\n if (!img.getAttribute('v:shapes')) {\n img.setAttribute('v:shapes', 'image' + Math.random().toString(36).substr(2, 9));\n }\n \n // Skip if already a data URL\n if (img.src && !img.src.startsWith('data:')) {\n try {\n // Try to convert to data URL\n const response = await fetch(img.src);\n const blob = await response.blob();\n \n // Check if image is too large (Google Docs has limits)\n const maxSize = 2 * 1024 * 1024; // 2MB limit for inline images\n if (blob.size > maxSize) {\n console.warn('Image too large for inline data URL:', img.src, 'Size:', blob.size);\n // For large images, we might want to resize or keep the URL\n continue;\n }\n \n const dataUrl = await new Promise(resolve => {\n const reader = new FileReader();\n reader.onloadend = () => resolve(reader.result);\n reader.readAsDataURL(blob);\n });\n img.src = dataUrl;\n } catch (err) {\n console.warn('Failed to convert image to data URL:', img.src, err);\n // Keep original src if conversion fails\n }\n }\n }\n \n // Phase 2: Process fence block types\n // 1. Process STL 3D models - convert canvas to image or placeholder\n const stlContainers = clone.querySelectorAll('.qde-stl-container');\n for (const container of stlContainers) {\n try {\n // Find the corresponding original container to get the canvas\n const containerId = container.dataset.stlId;\n const originalContainer = previewPanel.querySelector(`.qde-stl-container[data-stl-id=\"${containerId}\"]`);\n \n if (originalContainer) {\n // Look for canvas element in the original container (Three.js WebGL canvas)\n const canvas = originalContainer.querySelector('canvas');\n if (canvas && canvas.width > 0 && canvas.height > 0) {\n try {\n // Get Three.js references stored on the container (like squibview)\n const renderer = originalContainer._threeRenderer;\n const scene = originalContainer._threeScene;\n const camera = originalContainer._threeCamera;\n \n // If we have access to the Three.js objects, force render the scene\n if (renderer && scene && camera) {\n renderer.render(scene, camera);\n }\n \n // Try to capture the canvas as an image\n const dataUrl = canvas.toDataURL('image/png', 1.0);\n const img = document.createElement('img');\n img.src = dataUrl;\n \n // Use canvas dimensions for the image\n const imgWidth = canvas.width / 2; // Divide by scale factor (2x for retina)\n const imgHeight = canvas.height / 2;\n \n // Set both HTML attributes and CSS properties for maximum compatibility\n img.width = imgWidth;\n img.height = imgHeight;\n img.setAttribute('width', imgWidth.toString());\n img.setAttribute('height', imgHeight.toString());\n img.style.width = imgWidth + 'px';\n img.style.height = imgHeight + 'px';\n img.style.maxWidth = 'none';\n img.style.maxHeight = 'none';\n img.style.border = '1px solid #ddd';\n img.style.borderRadius = '4px';\n img.style.margin = '0.5em 0';\n img.setAttribute('v:shapes', 'image' + Math.random().toString(36).substr(2, 9));\n img.alt = 'STL 3D Model';\n \n container.parentNode.replaceChild(img, container);\n continue;\n } catch (canvasErr) {\n console.warn('Failed to convert STL canvas to image (likely WebGL context issue):', canvasErr);\n }\n } else {\n console.warn('No valid canvas found in STL container');\n }\n } else {\n console.warn('Could not find original STL container');\n }\n } catch (err) {\n console.error('Error processing STL container for copy:', err);\n }\n \n // Fallback to placeholder if canvas conversion fails\n const placeholder = document.createElement('div');\n placeholder.style.cssText = 'padding: 12px; background-color: #f0f0f0; border: 1px solid #ccc; text-align: center; margin: 0.5em 0; border-radius: 4px;';\n placeholder.textContent = '[STL 3D Model - Interactive content not available in copy]';\n container.parentNode.replaceChild(placeholder, container);\n }\n \n // 2. Process Mermaid diagrams - convert SVG to PNG\n const mermaidContainers = clone.querySelectorAll('.mermaid');\n for (const container of mermaidContainers) {\n const svg = container.querySelector('svg');\n if (svg) {\n try {\n const pngBlob = await svgToPng(svg);\n const dataUrl = await new Promise(resolve => {\n const reader = new FileReader();\n reader.onloadend = () => resolve(reader.result);\n reader.readAsDataURL(pngBlob);\n });\n \n const img = document.createElement('img');\n img.src = dataUrl;\n \n // Use the exact same dimension calculation logic as svgToPng (like squibview)\n const isMermaidSvg = svg.closest('.mermaid') || svg.classList.contains('mermaid');\n const hasExplicitDimensions = svg.getAttribute('width') && svg.getAttribute('height');\n \n let imgWidth, imgHeight;\n \n if (isMermaidSvg || !hasExplicitDimensions) {\n // For Mermaid or other generated SVGs, prioritize computed dimensions\n imgWidth = svg.clientWidth || \n (svg.viewBox && svg.viewBox.baseVal.width) || \n parseFloat(svg.getAttribute('width')) || 400;\n imgHeight = svg.clientHeight || \n (svg.viewBox && svg.viewBox.baseVal.height) || \n parseFloat(svg.getAttribute('height')) || 300;\n } else {\n // For explicit SVGs (like fenced SVG blocks), prioritize explicit attributes\n imgWidth = parseFloat(svg.getAttribute('width')) || \n (svg.viewBox && svg.viewBox.baseVal.width) || \n svg.clientWidth || 400;\n imgHeight = parseFloat(svg.getAttribute('height')) || \n (svg.viewBox && svg.viewBox.baseVal.height) || \n svg.clientHeight || 300;\n }\n \n // Set both HTML attributes and CSS properties for maximum compatibility (like squibview)\n img.width = imgWidth;\n img.height = imgHeight;\n img.setAttribute('width', imgWidth.toString());\n img.setAttribute('height', imgHeight.toString());\n img.style.width = imgWidth + 'px';\n img.style.height = imgHeight + 'px';\n img.style.maxWidth = 'none'; // Prevent CSS from constraining the image\n img.style.maxHeight = 'none';\n img.setAttribute('v:shapes', 'image' + Math.random().toString(36).substr(2, 9));\n img.alt = 'Mermaid Diagram';\n \n container.parentNode.replaceChild(img, container);\n } catch (err) {\n console.warn('Failed to convert Mermaid diagram:', err);\n // Fallback: leave as SVG\n }\n }\n }\n \n // 3. Process Chart.js charts - convert canvas to image\n const chartContainers = clone.querySelectorAll('.qde-chart-container');\n for (const container of chartContainers) {\n try {\n const containerId = container.dataset.chartId;\n const originalContainer = previewPanel.querySelector(`.qde-chart-container[data-chart-id=\"${containerId}\"]`);\n \n if (originalContainer) {\n const canvas = originalContainer.querySelector('canvas');\n if (canvas && canvas.width > 0 && canvas.height > 0) {\n try {\n const dataUrl = canvas.toDataURL('image/png', 1.0);\n const img = document.createElement('img');\n img.src = dataUrl;\n \n // Use canvas dimensions for the image\n const imgWidth = canvas.width;\n const imgHeight = canvas.height;\n \n // Set both HTML attributes and CSS properties for maximum compatibility\n img.width = imgWidth;\n img.height = imgHeight;\n img.setAttribute('width', imgWidth.toString());\n img.setAttribute('height', imgHeight.toString());\n img.style.width = imgWidth + 'px';\n img.style.height = imgHeight + 'px';\n img.style.maxWidth = 'none';\n img.style.maxHeight = 'none';\n img.style.margin = '0.5em 0';\n img.setAttribute('v:shapes', 'image' + Math.random().toString(36).substr(2, 9));\n img.alt = 'Chart';\n \n container.parentNode.replaceChild(img, container);\n continue;\n } catch (canvasErr) {\n console.warn('Failed to convert chart canvas to image:', canvasErr);\n }\n }\n }\n } catch (err) {\n console.warn('Error processing chart container:', err);\n }\n \n // Fallback to placeholder\n const placeholder = document.createElement('div');\n placeholder.style.cssText = 'padding: 12px; background-color: #f0f0f0; border: 1px solid #ccc; text-align: center; margin: 0.5em 0; border-radius: 4px;';\n placeholder.textContent = '[Chart - Interactive content not available in copy]';\n container.parentNode.replaceChild(placeholder, container);\n }\n \n // 4. Process SVG fenced blocks - convert to PNG\n const svgContainers = clone.querySelectorAll('.qde-svg-container svg');\n for (const svg of svgContainers) {\n try {\n const pngBlob = await svgToPng(svg);\n const dataUrl = await new Promise(resolve => {\n const reader = new FileReader();\n reader.onloadend = () => resolve(reader.result);\n reader.readAsDataURL(pngBlob);\n });\n \n const img = document.createElement('img');\n img.src = dataUrl;\n \n // Calculate dimensions for the SVG\n const hasExplicitDimensions = svg.getAttribute('width') && svg.getAttribute('height');\n \n let imgWidth, imgHeight;\n \n if (hasExplicitDimensions) {\n // For explicit SVGs (like fenced SVG blocks), prioritize explicit attributes\n imgWidth = parseFloat(svg.getAttribute('width')) || \n (svg.viewBox && svg.viewBox.baseVal.width) || \n svg.clientWidth || 400;\n imgHeight = parseFloat(svg.getAttribute('height')) || \n (svg.viewBox && svg.viewBox.baseVal.height) || \n svg.clientHeight || 300;\n } else {\n // For generated SVGs, prioritize computed dimensions\n imgWidth = svg.clientWidth || \n (svg.viewBox && svg.viewBox.baseVal.width) || \n parseFloat(svg.getAttribute('width')) || 400;\n imgHeight = svg.clientHeight || \n (svg.viewBox && svg.viewBox.baseVal.height) || \n parseFloat(svg.getAttribute('height')) || 300;\n }\n \n // Set both HTML attributes and CSS properties for maximum compatibility\n img.width = imgWidth;\n img.height = imgHeight;\n img.setAttribute('width', imgWidth.toString());\n img.setAttribute('height', imgHeight.toString());\n img.style.width = imgWidth + 'px';\n img.style.height = imgHeight + 'px';\n img.style.maxWidth = 'none'; // Prevent CSS from constraining the image\n img.style.maxHeight = 'none';\n img.setAttribute('v:shapes', 'image' + Math.random().toString(36).substr(2, 9));\n img.alt = 'SVG Image';\n \n svg.parentNode.replaceChild(img, svg);\n } catch (err) {\n console.warn('Failed to convert SVG to image:', err);\n // Leave as SVG if conversion fails\n }\n }\n \n // 5. Process Math equations - convert to PNG images (exactly like SquibView)\n const mathElements = Array.from(clone.querySelectorAll('.math-display'));\n \n if (mathElements.length > 0) {\n for (const mathEl of mathElements) {\n try {\n // Find SVG inside the math element (MathJax creates it)\n const svg = mathEl.querySelector('svg');\n if (!svg) {\n console.warn('No SVG found in math element, skipping');\n continue;\n }\n \n // Convert SVG to PNG data URL (exactly like SquibView)\n const serializer = new XMLSerializer();\n const svgStr = serializer.serializeToString(svg);\n const svgBlob = new Blob([svgStr], { type: \"image/svg+xml;charset=utf-8\" });\n const url = URL.createObjectURL(svgBlob);\n \n const img = new Image();\n const dataUrl = await new Promise((resolve, reject) => {\n img.onload = function () {\n const canvas = document.createElement('canvas');\n \n // Determine SVG dimensions robustly (exactly like SquibView)\n let width, height;\n try {\n // First try baseVal.value (works for absolute units)\n width = svg.width.baseVal.value;\n height = svg.height.baseVal.value;\n } catch (_e) {\n // Fallback for relative units - use viewBox or rendered size\n if (svg.viewBox && svg.viewBox.baseVal) {\n width = svg.viewBox.baseVal.width;\n height = svg.viewBox.baseVal.height;\n } else {\n // Use the natural size of the loaded image\n width = img.naturalWidth || img.width || 200;\n height = img.naturalHeight || img.height || 50;\n }\n }\n \n // Scale down for much smaller paste sizes\n const targetMaxWidth = 150; // Further reduced\n const targetMaxHeight = 45; // Further reduced\n \n // Apply aggressive downsizing for MathJax SVGs\n let scaleFactor = 0.04; // Further reduced for smaller output\n \n const scaledWidth = width * scaleFactor;\n const scaledHeight = height * scaleFactor;\n \n // If still too large after base scaling, scale down further\n if (scaledWidth > targetMaxWidth || scaledHeight > targetMaxHeight) {\n const scaleX = targetMaxWidth / scaledWidth;\n const scaleY = targetMaxHeight / scaledHeight;\n scaleFactor *= Math.min(scaleX, scaleY);\n }\n \n width *= scaleFactor;\n height *= scaleFactor;\n \n // Use higher DPR for crisp rendering at smaller sizes\n const dpr = 2; // Fixed 2x for consistent quality\n canvas.width = width * dpr;\n canvas.height = height * dpr;\n canvas.style.width = width + 'px';\n canvas.style.height = height + 'px';\n \n const ctx = canvas.getContext('2d');\n ctx.scale(dpr, dpr);\n \n // White background\n ctx.fillStyle = \"#FFFFFF\";\n ctx.fillRect(0, 0, width, height);\n \n // Draw the SVG image at logical size\n ctx.drawImage(img, 0, 0, width, height);\n \n // Clean up URL\n URL.revokeObjectURL(url);\n \n // Return data URL\n resolve(canvas.toDataURL('image/png'));\n };\n \n img.onerror = () => {\n URL.revokeObjectURL(url);\n reject(new Error('Failed to load SVG image'));\n };\n \n img.src = url;\n });\n \n // Replace math element with img tag containing the PNG data URL\n const imgElement = document.createElement('img');\n imgElement.src = dataUrl;\n \n // Extract dimensions from the data URL canvas\n const img2 = new Image();\n img2.src = dataUrl;\n await new Promise((resolve) => {\n img2.onload = resolve;\n img2.onerror = resolve;\n setTimeout(resolve, 100); // Timeout fallback\n });\n \n // Set explicit dimensions (accounting for DPR)\n const displayWidth = img2.naturalWidth / 2; // Divide by DPR\n const displayHeight = img2.naturalHeight / 2;\n \n imgElement.width = displayWidth;\n imgElement.height = displayHeight;\n imgElement.style.cssText = `display:inline-block;margin:0.5em 0;width:${displayWidth}px;height:${displayHeight}px;vertical-align:middle;`;\n imgElement.alt = 'Math equation';\n \n mathEl.parentNode.replaceChild(imgElement, mathEl);\n } catch (error) {\n console.error('Failed to convert math element to image:', error);\n // Keep the original element if conversion fails\n }\n }\n }\n \n // 2. Process GeoJSON maps - convert to static images (following Gem's guide)\n const geojsonContainers = clone.querySelectorAll('.geojson-container');\n if (geojsonContainers.length > 0) {\n \n for (const clonedContainer of geojsonContainers) {\n try {\n // Find the corresponding live container by matching data-original-source\n const originalSource = clonedContainer.getAttribute('data-original-source');\n if (!originalSource) {\n console.warn('No original source found for GeoJSON container');\n continue;\n }\n \n // Find live container with same source\n let liveContainer = null;\n const allLiveContainers = previewPanel.querySelectorAll('.geojson-container');\n for (const candidate of allLiveContainers) {\n if (candidate.getAttribute('data-original-source') === originalSource) {\n liveContainer = candidate;\n break;\n }\n }\n \n if (!liveContainer) {\n console.warn('Could not find live GeoJSON container');\n const placeholder = document.createElement('div');\n placeholder.style.cssText = 'padding: 12px; background-color: #f0f0f0; border: 1px solid #ccc; text-align: center; margin: 0.5em 0; border-radius: 4px;';\n placeholder.textContent = '[GeoJSON Map - Interactive content not available in copy]';\n clonedContainer.parentNode.replaceChild(placeholder, clonedContainer);\n continue;\n }\n \n // Check if map is ready\n const map = liveContainer._map;\n if (!map) {\n console.warn('Map not initialized yet');\n const placeholder = document.createElement('div');\n placeholder.style.cssText = 'padding: 12px; background-color: #f0f0f0; border: 1px solid #ccc; text-align: center; margin: 0.5em 0; border-radius: 4px;';\n placeholder.textContent = '[GeoJSON Map - Still loading]';\n clonedContainer.parentNode.replaceChild(placeholder, clonedContainer);\n continue;\n }\n \n // Rasterize the map to PNG\n const dataUrl = await rasterizeGeoJSONMap(liveContainer);\n \n if (dataUrl) {\n // Replace with image\n const img = document.createElement('img');\n img.src = dataUrl;\n img.style.cssText = 'width: 100%; height: 300px; border: 1px solid #ddd; border-radius: 4px; margin: 0.5em 0;';\n img.alt = 'GeoJSON Map';\n clonedContainer.parentNode.replaceChild(img, clonedContainer);\n } else {\n // Fallback placeholder\n const placeholder = document.createElement('div');\n placeholder.style.cssText = 'padding: 12px; background-color: #f0f0f0; border: 1px solid #ccc; text-align: center; margin: 0.5em 0; border-radius: 4px;';\n placeholder.textContent = '[GeoJSON Map - Interactive content not available in copy]';\n clonedContainer.parentNode.replaceChild(placeholder, clonedContainer);\n }\n \n } catch (error) {\n console.error('Failed to process GeoJSON container:', error);\n // Replace with placeholder\n const placeholder = document.createElement('div');\n placeholder.style.cssText = 'padding: 12px; background-color: #f0f0f0; border: 1px solid #ccc; text-align: center; margin: 0.5em 0; border-radius: 4px;';\n placeholder.textContent = '[GeoJSON Map - Interactive content not available in copy]';\n clonedContainer.parentNode.replaceChild(placeholder, clonedContainer);\n }\n }\n }\n \n \n \n // 6. Process GeoJSON/Leaflet maps - capture as single image (compose tiles + overlays)\n const mapContainers = clone.querySelectorAll('[data-qd-lang=\"geojson\"]');\n for (const container of mapContainers) {\n try {\n const containerId = container.id;\n const originalContainer = containerId ? previewPanel.querySelector(`#${containerId}`) : null;\n if (!originalContainer) continue;\n const leafletContainer = originalContainer.querySelector('.leaflet-container');\n if (!leafletContainer) continue;\n\n const dpr = Math.max(1, window.devicePixelRatio || 1);\n const width = leafletContainer.clientWidth || 600;\n const height = leafletContainer.clientHeight || 400;\n const canvas = document.createElement('canvas');\n canvas.width = Math.round(width * dpr);\n canvas.height = Math.round(height * dpr);\n const ctx = canvas.getContext('2d');\n ctx.scale(dpr, dpr);\n ctx.fillStyle = '#FFFFFF';\n ctx.fillRect(0, 0, width, height);\n\n const leafRect = leafletContainer.getBoundingClientRect();\n\n // Draw tiles (snap to integer pixels to avoid seams)\n const tiles = Array.from(leafletContainer.querySelectorAll('img.leaflet-tile'));\n for (const tile of tiles) {\n try {\n const r = tile.getBoundingClientRect();\n const x = Math.round(r.left - leafRect.left);\n const y = Math.round(r.top - leafRect.top);\n const w = Math.round(r.width);\n const h = Math.round(r.height);\n const overlaps = !(r.right <= leafRect.left || r.left >= leafRect.right || r.bottom <= leafRect.top || r.top >= leafRect.bottom);\n const style = window.getComputedStyle(tile);\n if (w > 0 && h > 0 && overlaps && style.display !== 'none' && style.visibility !== 'hidden') {\n ctx.drawImage(tile, x, y, w + 1, h + 1);\n }\n } catch (_e) {\n console.warn('Failed to draw tile:', _e);\n }\n }\n\n // Draw SVG overlays (paths, markers)\n const overlaySvgs = originalContainer.querySelectorAll('.leaflet-overlay-pane svg');\n for (const svg of overlaySvgs) {\n try {\n const svgStr = new XMLSerializer().serializeToString(svg);\n const dataUrl = 'data:image/svg+xml;charset=utf-8,' + encodeURIComponent(svgStr);\n const img = new Image();\n await new Promise((resolve) => { img.onload = resolve; img.onerror = resolve; img.src = dataUrl; });\n const r = svg.getBoundingClientRect();\n const x = Math.round(r.left - leafRect.left);\n const y = Math.round(r.top - leafRect.top);\n const w = Math.round(r.width);\n const h = Math.round(r.height);\n const overlaps = !(r.right <= leafRect.left || r.left >= leafRect.right || r.bottom <= leafRect.top || r.top >= leafRect.bottom);\n if (w > 0 && h > 0 && overlaps) ctx.drawImage(img, x, y, w, h);\n } catch (_e) {\n console.warn('Failed to draw overlay SVG:', _e);\n }\n }\n\n // Draw marker icons (PNG/SVG img elements)\n const markerIcons = originalContainer.querySelectorAll('.leaflet-marker-pane img.leaflet-marker-icon');\n for (const icon of markerIcons) {\n try {\n const r = icon.getBoundingClientRect();\n const x = Math.round(r.left - leafRect.left);\n const y = Math.round(r.top - leafRect.top);\n const w = Math.round(r.width);\n const h = Math.round(r.height);\n const overlaps = !(r.right <= leafRect.left || r.left >= leafRect.right || r.bottom <= leafRect.top || r.top >= leafRect.bottom);\n const style = window.getComputedStyle(icon);\n if (w > 0 && h > 0 && overlaps && style.display !== 'none' && style.visibility !== 'hidden') {\n ctx.drawImage(icon, x, y, w, h);\n }\n } catch (_e) {\n console.warn('Failed to draw marker icon:', _e);\n }\n }\n\n // Try to produce a data URL (may fail if canvas tainted by CORS tiles)\n let mapDataUrl = '';\n try {\n mapDataUrl = canvas.toDataURL('image/png', 1.0);\n } catch (_e) {\n console.warn('Map canvas tainted; falling back to placeholder');\n }\n\n const img = document.createElement('img');\n if (mapDataUrl) {\n img.src = mapDataUrl;\n img.width = width;\n img.height = height;\n img.setAttribute('width', String(width));\n img.setAttribute('height', String(height));\n img.style.width = width + 'px';\n img.style.height = height + 'px';\n img.style.display = 'block';\n img.style.border = '1px solid #ddd';\n img.setAttribute('v:shapes', 'image' + Math.random().toString(36).substr(2, 9));\n img.alt = 'Map';\n } else {\n img.alt = 'Map';\n img.style.width = width + 'px';\n img.style.height = height + 'px';\n img.style.border = '1px solid #ddd';\n img.style.backgroundColor = '#f0f0f0';\n }\n\n container.parentNode.replaceChild(img, container);\n } catch (err) {\n console.warn('Failed to process map container:', err);\n }\n }\n \n // 7. Process HTML fence blocks - render the HTML content and process images\n const htmlContainers = clone.querySelectorAll('.qde-html-container');\n for (const container of htmlContainers) {\n try {\n // Get the original source HTML\n const source = container.getAttribute('data-qd-source');\n \n // Check if there's a pre element (fallback display) or actual HTML content\n const pre = container.querySelector('pre');\n \n if (source) {\n // Parse the source HTML\n const tempDiv = document.createElement('div');\n tempDiv.innerHTML = source;\n \n // Process all images in the HTML block\n const htmlImages = tempDiv.querySelectorAll('img');\n for (const img of htmlImages) {\n // Preserve original dimensions from HTML attributes\n const widthAttr = img.getAttribute('width');\n const heightAttr = img.getAttribute('height');\n \n if (widthAttr) {\n img.width = parseInt(widthAttr);\n img.style.width = widthAttr.includes('%') ? widthAttr : `${img.width}px`;\n }\n if (heightAttr) {\n img.height = parseInt(heightAttr);\n img.style.height = heightAttr.includes('%') ? heightAttr : `${img.height}px`;\n }\n \n // Convert to data URL using canvas (like squibview)\n if (img.src && !img.src.startsWith('data:')) {\n try {\n // Use canvas to convert image to data URL (avoids CORS issues)\n const canvas = document.createElement('canvas');\n const ctx = canvas.getContext('2d');\n \n // Create new image and wait for it to load\n const tempImg = new Image();\n tempImg.crossOrigin = 'anonymous';\n \n await new Promise((resolve, reject) => {\n tempImg.onload = function() {\n \n // Calculate dimensions preserving aspect ratio\n let displayWidth = 0;\n let displayHeight = 0;\n \n // Use the width specified in HTML (e.g. width=\"250\")\n if (widthAttr && !widthAttr.includes('%')) {\n displayWidth = parseInt(widthAttr);\n }\n \n // Use the height if specified\n if (heightAttr && !heightAttr.includes('%')) {\n displayHeight = parseInt(heightAttr);\n }\n \n \n // If only width is specified, calculate height based on aspect ratio\n if (displayWidth > 0 && displayHeight === 0) {\n if (tempImg.naturalWidth > 0) {\n const aspectRatio = tempImg.naturalHeight / tempImg.naturalWidth;\n displayHeight = Math.round(displayWidth * aspectRatio);\n }\n }\n // If only height is specified, calculate width based on aspect ratio\n else if (displayHeight > 0 && displayWidth === 0) {\n if (tempImg.naturalHeight > 0) {\n const aspectRatio = tempImg.naturalWidth / tempImg.naturalHeight;\n displayWidth = Math.round(displayHeight * aspectRatio);\n }\n }\n // If neither specified, use natural dimensions\n else if (displayWidth === 0 && displayHeight === 0) {\n displayWidth = tempImg.naturalWidth || 250;\n displayHeight = tempImg.naturalHeight || 200;\n }\n \n \n canvas.width = displayWidth;\n canvas.height = displayHeight;\n \n // Draw image to canvas\n ctx.drawImage(tempImg, 0, 0, displayWidth, displayHeight);\n \n // Convert to data URL\n const dataUrl = canvas.toDataURL('image/png', 1.0);\n \n // Update original image\n img.src = dataUrl;\n img.width = displayWidth;\n img.height = displayHeight;\n img.setAttribute('width', displayWidth.toString());\n img.setAttribute('height', displayHeight.toString());\n img.style.width = displayWidth + 'px';\n img.style.height = displayHeight + 'px';\n \n resolve();\n };\n \n tempImg.onerror = function() {\n console.warn('Failed to load HTML fence image:', img.src);\n reject(new Error('Image load failed'));\n };\n \n // Set source - resolve relative paths\n if (img.src.startsWith('http') || img.src.startsWith('//')) {\n tempImg.src = img.src;\n } else {\n // Relative path - let browser resolve it\n const absoluteImg = new Image();\n absoluteImg.src = img.src;\n tempImg.src = absoluteImg.src;\n }\n });\n } catch (err) {\n console.warn('Failed to convert HTML fence image:', img.src, err);\n }\n }\n \n // Add v:shapes for Word compatibility\n img.setAttribute('v:shapes', 'image' + Math.random().toString(36).substr(2, 9));\n }\n \n // Replace container content with processed HTML (whether it had pre or not)\n container.innerHTML = tempDiv.innerHTML;\n } else if (!pre) {\n // Container has rendered HTML already, process its images directly\n const htmlImages = container.querySelectorAll('img');\n for (const img of htmlImages) {\n // Same image processing as above\n const widthAttr = img.getAttribute('width');\n const heightAttr = img.getAttribute('height');\n \n if (widthAttr) {\n img.width = parseInt(widthAttr);\n img.style.width = widthAttr.includes('%') ? widthAttr : `${img.width}px`;\n }\n if (heightAttr) {\n img.height = parseInt(heightAttr);\n img.style.height = heightAttr.includes('%') ? heightAttr : `${img.height}px`;\n }\n \n if (img.src && !img.src.startsWith('data:')) {\n try {\n // Use same canvas approach as above\n const canvas = document.createElement('canvas');\n const ctx = canvas.getContext('2d');\n const tempImg = new Image();\n tempImg.crossOrigin = 'anonymous';\n \n await new Promise((resolve, reject) => {\n tempImg.onload = function() {\n // Calculate dimensions preserving aspect ratio\n let displayWidth = img.width || 0;\n let displayHeight = img.height || 0;\n \n // If only width is specified, calculate height based on aspect ratio\n if (displayWidth && !displayHeight) {\n const aspectRatio = tempImg.naturalHeight / tempImg.naturalWidth;\n displayHeight = Math.round(displayWidth * aspectRatio);\n }\n // If only height is specified, calculate width based on aspect ratio\n else if (displayHeight && !displayWidth) {\n const aspectRatio = tempImg.naturalWidth / tempImg.naturalHeight;\n displayWidth = Math.round(displayHeight * aspectRatio);\n }\n // If neither specified, use natural dimensions\n else if (!displayWidth && !displayHeight) {\n displayWidth = tempImg.naturalWidth || 250;\n displayHeight = tempImg.naturalHeight || Math.round(250 * (tempImg.naturalHeight / tempImg.naturalWidth));\n }\n \n canvas.width = displayWidth;\n canvas.height = displayHeight;\n ctx.drawImage(tempImg, 0, 0, displayWidth, displayHeight);\n \n const dataUrl = canvas.toDataURL('image/png', 1.0);\n img.src = dataUrl;\n img.width = displayWidth;\n img.height = displayHeight;\n img.setAttribute('width', displayWidth.toString());\n img.setAttribute('height', displayHeight.toString());\n img.style.width = displayWidth + 'px';\n img.style.height = displayHeight + 'px';\n \n resolve();\n };\n \n tempImg.onerror = function() {\n console.warn('Failed to load HTML fence image:', img.src);\n reject(new Error('Image load failed'));\n };\n \n if (img.src.startsWith('http') || img.src.startsWith('//')) {\n tempImg.src = img.src;\n } else {\n const absoluteImg = new Image();\n absoluteImg.src = img.src;\n tempImg.src = absoluteImg.src;\n }\n });\n } catch (err) {\n console.warn('Failed to convert HTML fence image:', img.src, err);\n }\n }\n \n img.setAttribute('v:shapes', 'image' + Math.random().toString(36).substr(2, 9));\n }\n }\n } catch (err) {\n console.warn('Failed to process HTML container:', err);\n }\n }\n \n // 8. Tables are already HTML tables from the built-in renderer\n // No processing needed\n \n // Wrap in proper HTML structure for rich text editors\n const fragment = clone.innerHTML;\n const htmlContent = `\n <!DOCTYPE html>\n <html xmlns:v=\"urn:schemas-microsoft-com:vml\"\n xmlns:o=\"urn:schemas-microsoft-com:office:office\"\n xmlns:w=\"urn:schemas-microsoft-com:office:word\">\n <head>\n <meta charset=\"utf-8\">\n <style>\n /* Table styling */\n table { border-collapse: collapse; width: 100%; margin-bottom: 1em; }\n th, td { border: 1px solid #ccc; padding: 8px; text-align: left; }\n th { background-color: #f0f0f0; font-weight: bold; }\n \n /* Code block styling */\n pre { background-color: #f4f4f4; padding: 1em; border-radius: 4px; overflow-x: auto; }\n code { font-family: monospace; background-color: #f4f4f4; padding: 0.2em 0.4em; border-radius: 3px; }\n \n /* Image handling */\n img { display: block; max-width: 100%; height: auto; margin: 0.5em 0; }\n \n /* Blockquote */\n blockquote { border-left: 4px solid #ddd; margin-left: 0; padding-left: 1em; color: #666; }\n \n /* Math equations centered like squibview */\n .math-display { text-align: center; margin: 1em 0; }\n .math-display img { display: inline-block; margin: 0 auto; }\n </style>\n </head>\n <body><!--StartFragment-->${fragment}<!--EndFragment--></body>\n </html>`;\n \n // Get plain text version\n const text = clone.textContent || clone.innerText || '';\n \n // Get platform for clipboard strategy (like squibview)\n const platform = getPlatform();\n \n if (platform === 'macos') {\n // macOS approach (like squibview)\n try {\n await navigator.clipboard.write([\n new ClipboardItem({\n 'text/html': new Blob([htmlContent], { type: 'text/html' }),\n 'text/plain': new Blob([text], { type: 'text/plain' })\n })\n ]);\n return { success: true, html: htmlContent, text };\n } catch (modernErr) {\n console.warn('Modern clipboard API failed, trying Safari fallback:', modernErr);\n // Safari fallback (selection-based HTML of fragment)\n if (copyToClipboard(fragment)) {\n return { success: true, html: htmlContent, text };\n }\n throw new Error('Fallback copy failed');\n }\n } else {\n // Windows/Linux approach (like squibview)\n const tempDiv = document.createElement('div');\n tempDiv.style.position = 'fixed';\n tempDiv.style.left = '-9999px';\n tempDiv.style.top = '0';\n // Use fragment for selection-based fallback copy\n tempDiv.innerHTML = fragment;\n document.body.appendChild(tempDiv);\n \n try {\n await navigator.clipboard.write([\n new ClipboardItem({\n 'text/html': new Blob([htmlContent], { type: 'text/html' }),\n 'text/plain': new Blob([text], { type: 'text/plain' })\n })\n ]);\n return { success: true, html: htmlContent, text };\n } catch (modernErr) {\n console.warn('Modern clipboard API failed, trying execCommand fallback:', modernErr);\n const selection = window.getSelection();\n const range = document.createRange();\n range.selectNodeContents(tempDiv);\n selection.removeAllRanges();\n selection.addRange(range);\n \n const successful = document.execCommand('copy');\n if (!successful) {\n throw new Error('Fallback copy failed');\n }\n return { success: true, html: htmlContent, text };\n } finally {\n if (tempDiv && tempDiv.parentNode) {\n document.body.removeChild(tempDiv);\n }\n }\n }\n \n } catch (err) {\n console.error('Failed to copy rendered content:', err);\n throw err;\n }\n}\n\n","/**\n * Quikdown Editor - A drop-in markdown editor control\n * @version 1.0.5\n * @license BSD-2-Clause\n */\n\nimport quikdown_bd from './quikdown_bd.js';\nimport { getRenderedContent } from './quikdown_edit_copy.js';\nimport { isHRLine, fenceOpen, isFenceClose, classifyLine, looksLikeTableRow } from './quikdown_classify.js';\n\n// Default options\nconst DEFAULT_OPTIONS = {\n mode: 'split', // 'source' | 'preview' | 'split'\n showToolbar: true,\n showRemoveHR: false, // Show button to remove horizontal rules (---)\n showLazyLinefeeds: false, // Show button to convert lazy linefeeds\n theme: 'auto', // 'light' | 'dark' | 'auto'\n lazy_linefeeds: false,\n inline_styles: false, // Use CSS classes (false) or inline styles (true)\n debounceDelay: 20, // Reduced from 100ms for better responsiveness\n placeholder: 'Start typing markdown...',\n plugins: {\n highlightjs: false,\n mermaid: false\n },\n /**\n * Preload fence-rendering libraries at construction time so the FIRST\n * encounter with a fence type renders instantly (no lazy load delay).\n *\n * Accepts:\n * - 'all' — preload every known library\n * - ['highlightjs','mermaid','math',\n * 'geojson','stl'] — preload specific libraries\n * - [{ name: 'mylib', script: 'https://...', css: '...' }]\n * — preload an arbitrary library\n *\n * Without this, fence libraries are loaded on demand the first time their\n * fence type is encountered. That keeps the editor lightweight, but the\n * first SVG/Mermaid/Math/GeoJSON/STL fence will show \"loading...\" for a\n * moment. Set `preloadFences` if you want zero-delay rendering — at the\n * cost of a few hundred KB of upfront network.\n *\n * Developer's choice. The editor itself is still ~70 KB minified;\n * `preloadFences` only affects the OPTIONAL fence renderers.\n */\n preloadFences: null,\n customFences: {}, // { 'language': (code, lang) => html }\n enableComplexFences: true, // Enable CSV tables, math rendering, SVG, etc.\n showUndoRedo: false, // Show undo/redo toolbar buttons\n undoStackSize: 100 // Maximum number of undo states to keep\n};\n\n// Library catalog used by preloadFences. Each entry knows how to:\n// - check if the library is already on the page (so we don't double-load)\n// - load it via script (and optional CSS)\nconst FENCE_LIBRARIES = {\n highlightjs: {\n check: () => typeof window.hljs !== 'undefined',\n script: 'https://unpkg.com/@highlightjs/cdn-assets/highlight.min.js',\n css: 'https://unpkg.com/@highlightjs/cdn-assets/styles/github.min.css',\n cssDark: 'https://unpkg.com/@highlightjs/cdn-assets/styles/github-dark.min.css'\n },\n mermaid: {\n check: () => typeof window.mermaid !== 'undefined',\n script: 'https://unpkg.com/mermaid/dist/mermaid.min.js',\n afterLoad: () => {\n if (window.mermaid) window.mermaid.initialize({ startOnLoad: false });\n }\n },\n math: {\n check: () => typeof window.MathJax !== 'undefined',\n script: 'https://cdn.jsdelivr.net/npm/mathjax@3.2.2/es5/tex-svg.js',\n beforeLoad: () => {\n // Configure MathJax before loading (must be set on window before script runs)\n // Must match the config in ensureMathJaxLoaded() for consistent behavior\n if (!window.MathJax) {\n window.MathJax = {\n loader: { load: ['input/tex', 'output/svg'] },\n tex: {\n packages: { '[+]': ['ams'] },\n inlineMath: [['$', '$'], ['\\\\(', '\\\\)']],\n displayMath: [['$$', '$$'], ['\\\\[', '\\\\]']],\n processEscapes: true,\n processEnvironments: true\n },\n options: {\n renderActions: { addMenu: [] },\n ignoreHtmlClass: 'tex2jax_ignore',\n processHtmlClass: 'tex2jax_process'\n },\n svg: {\n fontCache: 'none' // self-contained SVGs (required for copy-rendered)\n },\n startup: { typeset: false }\n };\n }\n }\n },\n geojson: {\n check: () => typeof window.L !== 'undefined',\n script: 'https://unpkg.com/leaflet@1.9.4/dist/leaflet.js',\n css: 'https://unpkg.com/leaflet@1.9.4/dist/leaflet.css'\n },\n stl: {\n check: () => typeof window.THREE !== 'undefined',\n script: 'https://unpkg.com/three@0.147.0/build/three.min.js'\n }\n};\n\n/**\n * Quikdown Editor - A complete markdown editing solution\n */\nclass QuikdownEditor {\n constructor(container, options = {}) {\n // Resolve container\n this.container = typeof container === 'string' \n ? document.querySelector(container) \n : container;\n \n if (!this.container) {\n throw new Error('QuikdownEditor: Invalid container');\n }\n \n // Merge options\n this.options = { ...DEFAULT_OPTIONS, ...options };\n \n // State\n this._markdown = '';\n this._html = '';\n this.currentMode = this.options.mode;\n this.updateTimer = null;\n\n // Undo/redo state\n this._undoStack = [];\n this._redoStack = [];\n this._isUndoRedo = false;\n \n // Initialize\n this.initPromise = this.init();\n }\n \n /**\n * Initialize the editor\n */\n async init() {\n // Load plugins if requested\n await this.loadPlugins();\n \n // Build UI\n this.buildUI();\n \n // Attach event listeners\n this.attachEvents();\n \n // Apply initial theme\n this.applyTheme();\n \n // Set initial mode\n this.setMode(this.currentMode);\n \n // Set initial content if provided\n if (this.options.initialContent) {\n this.setMarkdown(this.options.initialContent);\n }\n }\n \n /**\n * Build the editor UI\n */\n buildUI() {\n // Clear container\n this.container.innerHTML = '';\n \n // Add editor class\n this.container.classList.add('qde-container');\n \n // Create toolbar if enabled\n if (this.options.showToolbar) {\n this.toolbar = this.createToolbar();\n this.container.appendChild(this.toolbar);\n }\n \n // Create editor area\n this.editorArea = document.createElement('div');\n this.editorArea.className = 'qde-editor';\n \n // Create source panel\n this.sourcePanel = document.createElement('div');\n this.sourcePanel.className = 'qde-source';\n \n this.sourceTextarea = document.createElement('textarea');\n this.sourceTextarea.className = 'qde-textarea';\n this.sourceTextarea.spellcheck = false;\n this.sourceTextarea.placeholder = this.options.placeholder;\n this.sourcePanel.appendChild(this.sourceTextarea);\n \n // Create preview panel\n this.previewPanel = document.createElement('div');\n this.previewPanel.className = 'qde-preview';\n this.previewPanel.contentEditable = true;\n this.previewPanel.spellcheck = false;\n \n // Add panels to editor\n this.editorArea.appendChild(this.sourcePanel);\n this.editorArea.appendChild(this.previewPanel);\n this.container.appendChild(this.editorArea);\n \n // Add built-in styles if not already present\n this.injectStyles();\n }\n \n /**\n * Create toolbar\n */\n createToolbar() {\n const toolbar = document.createElement('div');\n toolbar.className = 'qde-toolbar';\n \n // Mode buttons\n const modes = ['source', 'split', 'preview'];\n const modeLabels = { source: 'Source', split: 'Split', preview: 'Rendered' };\n modes.forEach(mode => {\n const btn = document.createElement('button');\n btn.className = 'qde-btn';\n btn.dataset.mode = mode;\n btn.textContent = modeLabels[mode];\n btn.title = `Switch to ${modeLabels[mode]} view`;\n toolbar.appendChild(btn);\n });\n\n // Mobile split toggle (hidden by default, shown via CSS on narrow viewports)\n const splitToggle = document.createElement('button');\n splitToggle.className = 'qde-btn qde-split-toggle';\n splitToggle.textContent = 'Preview';\n splitToggle.title = 'Toggle between source and preview in split mode';\n toolbar.appendChild(splitToggle);\n\n // Undo/Redo buttons (if enabled)\n if (this.options.showUndoRedo) {\n const undoBtn = document.createElement('button');\n undoBtn.className = 'qde-btn disabled';\n undoBtn.dataset.action = 'undo';\n undoBtn.textContent = 'Undo';\n undoBtn.title = 'Undo (Ctrl+Z)';\n toolbar.appendChild(undoBtn);\n\n const redoBtn = document.createElement('button');\n redoBtn.className = 'qde-btn disabled';\n redoBtn.dataset.action = 'redo';\n redoBtn.textContent = 'Redo';\n redoBtn.title = 'Redo (Ctrl+Shift+Z / Ctrl+Y)';\n toolbar.appendChild(redoBtn);\n }\n\n // Spacer\n const spacer = document.createElement('span');\n spacer.className = 'qde-spacer';\n toolbar.appendChild(spacer);\n \n // Copy buttons\n const copyButtons = [\n { action: 'copy-markdown', text: 'Copy MD', title: 'Copy markdown to clipboard' },\n { action: 'copy-html', text: 'Copy HTML', title: 'Copy HTML to clipboard' },\n { action: 'copy-rendered', text: 'Copy Rendered', title: 'Copy rich text to clipboard' }\n ];\n \n copyButtons.forEach(({ action, text, title }) => {\n const btn = document.createElement('button');\n btn.className = 'qde-btn';\n btn.dataset.action = action;\n btn.textContent = text;\n btn.title = title;\n toolbar.appendChild(btn);\n });\n \n // Remove HR button (if enabled)\n if (this.options.showRemoveHR) {\n const removeHRBtn = document.createElement('button');\n removeHRBtn.className = 'qde-btn';\n removeHRBtn.dataset.action = 'remove-hr';\n removeHRBtn.textContent = 'Remove HR';\n removeHRBtn.title = 'Remove all horizontal rules (---) from markdown';\n toolbar.appendChild(removeHRBtn);\n }\n\n // Lazy linefeeds button (if enabled)\n if (this.options.showLazyLinefeeds) {\n const lazyLFBtn = document.createElement('button');\n lazyLFBtn.className = 'qde-btn';\n lazyLFBtn.dataset.action = 'lazy-linefeeds';\n lazyLFBtn.textContent = 'Fix Linefeeds';\n lazyLFBtn.title = 'Convert single newlines to paragraph breaks (one-time transform)';\n toolbar.appendChild(lazyLFBtn);\n }\n \n return toolbar;\n }\n \n /**\n * Inject built-in styles\n */\n injectStyles() {\n if (document.getElementById('qde-styles')) return;\n \n const style = document.createElement('style');\n style.id = 'qde-styles';\n style.textContent = `\n .qde-container {\n display: flex;\n flex-direction: column;\n height: 100%;\n border: 1px solid #ddd;\n border-radius: 4px;\n overflow: hidden;\n background: white;\n color: #1f2937;\n }\n \n .qde-toolbar {\n display: flex;\n align-items: center;\n flex-wrap: wrap;\n padding: 8px;\n background: #f5f5f5;\n border-bottom: 1px solid #ddd;\n gap: 4px;\n }\n \n .qde-btn {\n padding: 6px 12px;\n border: 1px solid #ccc;\n background: white;\n border-radius: 3px;\n cursor: pointer;\n font-size: 14px;\n transition: all 0.2s;\n }\n \n .qde-btn:hover {\n background: #e9e9e9;\n border-color: #999;\n }\n \n .qde-btn.active {\n background: #007bff;\n color: white;\n border-color: #0056b3;\n }\n\n .qde-btn.disabled {\n opacity: 0.4;\n pointer-events: none;\n }\n \n .qde-spacer {\n flex: 1;\n }\n \n .qde-editor {\n display: flex;\n flex: 1;\n overflow: hidden;\n }\n \n .qde-source, .qde-preview {\n flex: 1 1 0;\n min-width: 0; /* allow flex shrinking below content size */\n min-height: 0;\n overflow: auto;\n padding: 16px;\n box-sizing: border-box;\n }\n\n .qde-source {\n border-right: 1px solid #ddd;\n /* Source pane is just a container for the textarea — make it\n a positioning context so the textarea can fill it absolutely */\n position: relative;\n padding: 0; /* textarea brings its own padding */\n }\n\n .qde-textarea {\n display: block;\n position: absolute;\n inset: 0;\n width: 100%;\n height: 100%;\n border: none;\n outline: none;\n resize: none;\n padding: 16px;\n box-sizing: border-box;\n font-family: 'Monaco', 'Courier New', monospace;\n font-size: 14px;\n line-height: 1.5;\n background: transparent;\n color: inherit;\n /* Wrap long lines so the textarea only scrolls VERTICALLY.\n pre-wrap preserves intentional line breaks/whitespace\n while soft-wrapping at the right edge. */\n white-space: pre-wrap;\n word-wrap: break-word;\n overflow-x: hidden;\n overflow-y: auto;\n }\n \n .qde-preview {\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n font-size: 16px;\n line-height: 1.6;\n outline: none;\n cursor: text; /* Standard text cursor */\n overflow-x: hidden; /* never scroll horizontally; clip wide content */\n }\n\n /* Code blocks and inline code — self-contained so the editor\n does not depend on any external stylesheet for these. */\n .qde-preview pre {\n background: #f4f4f4;\n color: #1f2937;\n padding: 10px;\n border-radius: 4px;\n overflow-x: auto;\n margin: 0.6em 0;\n font-size: 0.9em;\n line-height: 1.5;\n font-family: ui-monospace, \"SF Mono\", Monaco, \"Cascadia Code\",\n \"Roboto Mono\", Consolas, \"Courier New\", monospace;\n }\n .qde-preview code {\n padding: 2px 4px;\n font-size: 0.9em;\n border-radius: 3px;\n background: #f0f0f0;\n color: #1f2937;\n font-family: ui-monospace, \"SF Mono\", Monaco, \"Cascadia Code\",\n \"Roboto Mono\", Consolas, \"Courier New\", monospace;\n }\n .qde-preview pre code {\n padding: 0;\n font-size: inherit;\n border-radius: 0;\n background: transparent;\n color: inherit;\n }\n\n /* Wide fence content (Leaflet maps, large SVGs, STL canvases,\n iframes, raw <img>) must never overflow the preview pane */\n .qde-preview .geojson-container,\n .qde-preview .qde-stl-container,\n .qde-preview .qde-svg-container,\n .qde-preview .leaflet-container,\n .qde-preview iframe,\n .qde-preview img,\n .qde-preview > svg {\n max-width: 100%;\n }\n .qde-preview .leaflet-container { box-sizing: border-box; }\n\n /* Standard markdown tables (the .quikdown-table class) need to\n scroll horizontally inside their own wrapper rather than\n making the whole preview pane scroll */\n .qde-preview table.quikdown-table,\n .qde-preview table.qde-csv-table {\n display: block;\n max-width: 100%;\n overflow-x: auto;\n }\n\n /* Fence-specific styles */\n .qde-svg-container {\n max-width: 100%;\n overflow: auto;\n }\n\n .qde-svg-container svg {\n max-width: 100%;\n height: auto;\n }\n \n .qde-html-container {\n /* HTML containers inherit background */\n margin: 12px 0;\n }\n \n .qde-math-container {\n text-align: center;\n margin: 16px 0;\n overflow-x: auto;\n }\n \n /* All tables in preview (both regular markdown and CSV) */\n .qde-preview table {\n width: 100%;\n border-collapse: collapse;\n margin: 12px 0;\n font-size: 14px;\n }\n \n .qde-preview table th,\n .qde-preview table td {\n border: 1px solid #ddd;\n padding: 8px;\n }\n \n /* Support for alignment classes from quikdown */\n .qde-preview .quikdown-left { text-align: left; }\n .qde-preview .quikdown-center { text-align: center; }\n .qde-preview .quikdown-right { text-align: right; }\n \n .qde-preview table th {\n background: #f5f5f5;\n font-weight: bold;\n }\n \n .qde-preview table tr:nth-child(even) {\n background: #f9f9f9;\n }\n \n /* Specific to CSV-generated tables */\n .qde-data-table {\n /* Can add specific CSV table styles here if needed */\n }\n \n .qde-json {\n /* Let highlight.js handle styling */\n overflow-x: auto;\n }\n \n .qde-error {\n background: #fee;\n border: 1px solid #fcc;\n color: #c00;\n padding: 8px;\n border-radius: 4px;\n font-family: monospace;\n font-size: 12px;\n }\n \n /* Read-only complex fence blocks in preview */\n .qde-preview [contenteditable=\"false\"] {\n cursor: auto; /* Use automatic cursor (arrow for non-text) */\n user-select: text;\n position: relative;\n }\n \n /* Reset headings inside the preview to plain browser defaults so\n parent-page styles (site navs, marketing pages, design systems)\n cannot bleed in. Business-casual: black text, decreasing sizes,\n no decorative borders. See docs/quikdown-editor.md for how\n embedders can override these with their own stylesheet. */\n .qde-preview h1 { font-size: 2em; }\n .qde-preview h2 { font-size: 1.5em; }\n .qde-preview h3 { font-size: 1.25em; }\n .qde-preview h4 { font-size: 1em; }\n .qde-preview h5 { font-size: 0.875em; }\n .qde-preview h6 { font-size: 0.85em; }\n .qde-preview h1,\n .qde-preview h2,\n .qde-preview h3,\n .qde-preview h4,\n .qde-preview h5,\n .qde-preview h6 {\n font-weight: bold;\n color: inherit;\n border: none;\n margin: 0.6em 0 0.3em 0;\n line-height: 1.25;\n }\n .qde-preview p {\n margin: 0.35em 0;\n }\n .qde-preview ul,\n .qde-preview ol {\n padding-left: 1.8em;\n margin: 0.4em 0;\n }\n .qde-preview li {\n margin: 0.15em 0;\n }\n .qde-preview blockquote {\n margin: 0.5em 0;\n padding-left: 1em;\n }\n\n /* Ensure proper cursor for editable text elements */\n .qde-preview p,\n .qde-preview h1,\n .qde-preview h2,\n .qde-preview h3,\n .qde-preview h4,\n .qde-preview h5,\n .qde-preview h6,\n .qde-preview li,\n .qde-preview td,\n .qde-preview th,\n .qde-preview blockquote,\n .qde-preview pre[contenteditable=\"true\"],\n .qde-preview code[contenteditable=\"true\"] {\n cursor: text;\n }\n \n \n /* Non-editable complex renderers */\n .qde-preview .qde-svg-container[contenteditable=\"false\"],\n .qde-preview .qde-html-container[contenteditable=\"false\"],\n .qde-preview .qde-math-container[contenteditable=\"false\"],\n .qde-preview .mermaid[contenteditable=\"false\"] {\n opacity: 0.98;\n }\n \n /* Subtle hover effect for read-only blocks */\n .qde-preview [contenteditable=\"false\"]:hover::after {\n content: \"Read-only\";\n position: absolute;\n top: 2px;\n right: 2px;\n font-size: 10px;\n color: #999;\n background: rgba(255, 255, 255, 0.9);\n padding: 2px 4px;\n border-radius: 2px;\n pointer-events: none;\n }\n \n /* Fix list padding in preview */\n .qde-preview ul,\n .qde-preview ol {\n padding-left: 2em;\n margin: 0.5em 0;\n }\n \n .qde-preview li {\n margin: 0.25em 0;\n }\n \n /* Mode-specific visibility */\n .qde-mode-source .qde-preview { display: none; }\n .qde-mode-source .qde-source { border-right: none; }\n .qde-mode-preview .qde-source { display: none; }\n .qde-mode-split .qde-source,\n .qde-mode-split .qde-preview { display: block; }\n \n /* Dark theme */\n .qde-dark {\n background: #1e1e1e;\n color: #e0e0e0;\n border-color: #444;\n }\n \n .qde-dark .qde-toolbar {\n background: #2d2d2d;\n border-color: #444;\n }\n \n .qde-dark .qde-btn {\n background: #3a3a3a;\n color: #e0e0e0;\n border-color: #555;\n }\n \n .qde-dark .qde-btn:hover {\n background: #4a4a4a;\n }\n \n .qde-dark .qde-source {\n border-color: #444;\n }\n \n .qde-dark .qde-textarea {\n background: #1e1e1e;\n color: #e0e0e0;\n }\n \n .qde-dark .qde-preview {\n background: #1e1e1e;\n color: #e0e0e0;\n }\n \n /* Dark mode code blocks */\n .qde-dark .qde-preview pre {\n background: #2d2d3a;\n color: #e6e6f0;\n }\n .qde-dark .qde-preview code {\n background: #2a2a3a;\n color: #e6e6f0;\n }\n .qde-dark .qde-preview pre code {\n background: transparent;\n color: inherit;\n }\n\n /* Dark mode table styles */\n .qde-dark .qde-preview table th,\n .qde-dark .qde-preview table td {\n border-color: #3a3a3a;\n }\n \n .qde-dark .qde-preview table th {\n background: #2d2d2d;\n }\n \n .qde-dark .qde-preview table tr:nth-child(even) {\n background: #252525;\n }\n \n /* Mobile split toggle — hidden by default */\n .qde-split-toggle { display: none; }\n\n /* Mobile responsive — compact toolbar for all small screens */\n @media (max-width: 720px) {\n .qde-toolbar {\n padding: 6px;\n gap: 3px;\n }\n .qde-btn {\n padding: 5px 8px;\n font-size: 12px;\n }\n .qde-source, .qde-preview {\n padding: 10px;\n }\n .qde-textarea {\n padding: 10px;\n }\n /* Undo/Redo: show circular arrows instead of text */\n .qde-btn[data-action=\"undo\"] { font-size: 0; }\n .qde-btn[data-action=\"undo\"]::after { content: \"\\\\21B6\"; font-size: 14px; }\n .qde-btn[data-action=\"redo\"] { font-size: 0; }\n .qde-btn[data-action=\"redo\"]::after { content: \"\\\\21B7\"; font-size: 14px; }\n /* Hide secondary utility buttons to reduce clutter */\n .qde-btn[data-action=\"remove-hr\"],\n .qde-btn[data-action=\"lazy-linefeeds\"],\n .qde-btn[data-action=\"copy-rendered\"] { display: none; }\n }\n\n /* Portrait mobile: drop split mode entirely */\n @media (max-width: 720px) and (orientation: portrait) {\n .qde-btn[data-mode=\"split\"] { display: none; }\n .qde-split-toggle { display: none !important; }\n /* Fallback: if still in split mode, show source only */\n .qde-mode-split .qde-source { border-right: none; }\n .qde-mode-split .qde-preview { display: none; }\n .qde-mode-split.qde-split-preview .qde-source { display: none; }\n .qde-mode-split.qde-split-preview .qde-preview { display: block; }\n }\n `;\n \n document.head.appendChild(style);\n }\n \n /**\n * Attach event listeners\n */\n attachEvents() {\n // Source textarea input\n this.sourceTextarea.addEventListener('input', () => {\n this.handleSourceInput();\n });\n \n // Preview contenteditable input\n this.previewPanel.addEventListener('input', () => {\n this.handlePreviewInput();\n });\n \n // Toolbar buttons\n if (this.toolbar) {\n this.toolbar.addEventListener('click', (e) => {\n const btn = e.target.closest('.qde-btn');\n if (!btn) return;\n\n // Mobile split-toggle button\n if (btn.classList.contains('qde-split-toggle')) {\n this.container.classList.toggle('qde-split-preview');\n const showingPreview = this.container.classList.contains('qde-split-preview');\n btn.textContent = showingPreview ? 'Source' : 'Preview';\n return;\n }\n\n if (btn.dataset.mode) {\n this.setMode(btn.dataset.mode);\n } else if (btn.dataset.action) {\n this.handleAction(btn.dataset.action);\n }\n });\n }\n \n // Keyboard shortcuts\n document.addEventListener('keydown', (e) => {\n if (e.ctrlKey || e.metaKey) {\n switch(e.key) {\n case '1':\n e.preventDefault();\n this.setMode('source');\n break;\n case '2':\n e.preventDefault();\n this.setMode('split');\n break;\n case '3':\n e.preventDefault();\n this.setMode('preview');\n break;\n case 'z':\n case 'Z':\n if (e.shiftKey) {\n e.preventDefault();\n this.redo();\n } else {\n e.preventDefault();\n this.undo();\n }\n break;\n case 'y':\n case 'Y':\n e.preventDefault();\n this.redo();\n break;\n }\n }\n });\n\n // On narrow portrait viewports, auto-switch out of split mode to source.\n // Split is kept available on landscape where there is enough width.\n if (typeof window.matchMedia === 'function') {\n const portraitQuery = window.matchMedia('(max-width: 720px) and (orientation: portrait)');\n const switchIfPortrait = () => {\n if (portraitQuery.matches && this.currentMode === 'split') {\n this.setMode('source');\n }\n };\n // Check after init's setMode() has run (microtask fires after sync code).\n Promise.resolve().then(switchIfPortrait);\n portraitQuery.addEventListener('change', switchIfPortrait);\n }\n }\n\n /**\n * Handle source textarea input\n */\n handleSourceInput() {\n clearTimeout(this.updateTimer);\n this.updateTimer = setTimeout(() => {\n this.updateFromMarkdown(this.sourceTextarea.value);\n }, this.options.debounceDelay);\n }\n \n /**\n * Handle preview panel input\n */\n handlePreviewInput() {\n clearTimeout(this.updateTimer);\n this.updateTimer = setTimeout(() => {\n this.updateFromHTML();\n }, this.options.debounceDelay);\n }\n \n /**\n * Update from markdown source\n */\n updateFromMarkdown(markdown) {\n // Push current state to undo stack before changing (unless this is an undo/redo operation)\n if (!this._isUndoRedo) {\n this._pushUndoState(markdown || '');\n }\n this._isUndoRedo = false;\n\n this._markdown = markdown || '';\n \n // Show placeholder if empty\n if (!this._markdown.trim()) {\n this._html = '';\n if (this.currentMode !== 'source') {\n this.previewPanel.innerHTML = '<div style=\"color: #999; font-style: italic; padding: 16px;\">Start typing markdown in the source panel...</div>';\n }\n } else {\n this._html = quikdown_bd(markdown, {\n fence_plugin: this.createFencePlugin(),\n lazy_linefeeds: this.options.lazy_linefeeds,\n inline_styles: this.options.inline_styles\n });\n \n // Update preview if visible\n if (this.currentMode !== 'source') {\n this.previewPanel.innerHTML = this._html;\n // Make all fence blocks non-editable\n this.makeFencesNonEditable();\n \n // Process all math elements with MathJax if loaded (like squibview)\n if (window.MathJax && window.MathJax.typesetPromise) {\n const mathElements = this.previewPanel.querySelectorAll('.math-display');\n if (mathElements.length > 0) {\n window.MathJax.typesetPromise(Array.from(mathElements))\n .catch(_err => {\n console.warn('MathJax batch processing failed:', _err);\n });\n }\n }\n }\n }\n \n // Trigger change event\n if (this.options.onChange) {\n this.options.onChange(this._markdown, this._html);\n }\n }\n \n /**\n * Update from HTML preview\n */\n updateFromHTML() {\n // Clone the preview panel to avoid modifying the actual DOM\n const clonedPanel = this.previewPanel.cloneNode(true);\n\n // Pre-process special elements on the clone\n this.preprocessSpecialElements(clonedPanel);\n\n this._html = this.previewPanel.innerHTML;\n const newMarkdown = quikdown_bd.toMarkdown(clonedPanel, {\n fence_plugin: this.createFencePlugin()\n });\n\n // Push previous state to undo stack (now that we know the new markdown)\n if (!this._isUndoRedo) {\n this._pushUndoState(newMarkdown);\n }\n this._isUndoRedo = false;\n\n this._markdown = newMarkdown;\n\n // Update source if visible\n if (this.currentMode !== 'preview') {\n this.sourceTextarea.value = this._markdown;\n }\n\n // Trigger change event\n if (this.options.onChange) {\n this.options.onChange(this._markdown, this._html);\n }\n\n this._updateUndoButtons();\n }\n \n /**\n * Pre-process special elements before markdown conversion\n */\n preprocessSpecialElements(panel) {\n if (!panel) return;\n \n // Restore non-editable complex fences from their data attributes\n const complexFences = panel.querySelectorAll('[contenteditable=\"false\"][data-qd-source]');\n complexFences.forEach(element => {\n const source = element.getAttribute('data-qd-source');\n const fence = element.getAttribute('data-qd-fence') || '```';\n const lang = element.getAttribute('data-qd-lang') || '';\n \n // Create a pre element with the original source\n const pre = document.createElement('pre');\n pre.setAttribute('data-qd-fence', fence);\n if (lang) pre.setAttribute('data-qd-lang', lang);\n const code = document.createElement('code');\n // The source is already the original unescaped content when using setAttribute\n // No need to unescape since browser handles it automatically\n code.textContent = source;\n pre.appendChild(code);\n \n // Replace the complex element with pre\n element.parentNode.replaceChild(pre, element);\n });\n \n // Convert CSV tables back to CSV fence blocks (these ARE editable)\n const csvTables = panel.querySelectorAll('table.qde-csv-table[data-qd-lang]');\n csvTables.forEach(table => {\n const lang = table.getAttribute('data-qd-lang');\n if (!lang || !['csv', 'psv', 'tsv'].includes(lang)) return;\n \n const delimiter = lang === 'csv' ? ',' : lang === 'psv' ? '|' : '\\t';\n \n // Extract data from table\n let csv = '';\n \n // Get headers\n const headers = [];\n const headerCells = table.querySelectorAll('thead th');\n headerCells.forEach(th => {\n const text = th.textContent.trim();\n // Quote if contains delimiter or quotes\n const needsQuoting = text.includes(delimiter) || text.includes('\"') || text.includes('\\n');\n headers.push(needsQuoting ? `\"${text.replace(/\"/g, '\"\"')}\"` : text);\n });\n csv += headers.join(delimiter) + '\\n';\n \n // Get rows\n const rows = table.querySelectorAll('tbody tr');\n rows.forEach(tr => {\n const cells = [];\n tr.querySelectorAll('td').forEach(td => {\n const text = td.textContent.trim();\n const needsQuoting = text.includes(delimiter) || text.includes('\"') || text.includes('\\n');\n cells.push(needsQuoting ? `\"${text.replace(/\"/g, '\"\"')}\"` : text);\n });\n csv += cells.join(delimiter) + '\\n';\n });\n \n // Create a pre element with the CSV data\n const pre = document.createElement('pre');\n pre.setAttribute('data-qd-fence', '```');\n pre.setAttribute('data-qd-lang', lang);\n const code = document.createElement('code');\n code.textContent = csv.trim();\n pre.appendChild(code);\n \n // Replace table with pre\n table.parentNode.replaceChild(pre, table);\n });\n }\n \n /**\n * Create fence plugin for syntax highlighting\n */\n createFencePlugin() {\n const render = (code, lang) => {\n // Check custom fences first (they take precedence)\n if (this.options.customFences && this.options.customFences[lang]) {\n try {\n return this.options.customFences[lang](code, lang);\n } catch (err) {\n console.error(`Custom fence plugin error for ${lang}:`, err);\n return `<pre><code class=\"language-${lang}\">${this.escapeHtml(code)}</code></pre>`;\n }\n }\n \n // For bidirectional editing, only apply syntax highlighting\n // Skip complex transformations that break round-trip conversion\n const skipComplexRendering = !this.options.enableComplexFences;\n \n if (!skipComplexRendering) {\n // Built-in lazy loading fence handlers (disabled for now)\n switch(lang) {\n case 'svg':\n return this.renderSVG(code);\n \n case 'html':\n return this.renderHTML(code);\n \n case 'math':\n case 'tex':\n case 'latex':\n return this.renderMath(code, lang);\n \n case 'csv':\n case 'psv':\n case 'tsv':\n return this.renderTable(code, lang);\n \n case 'json':\n case 'json5':\n return this.renderJSON(code, lang);\n \n case 'katex': // Use MathJax for katex fence blocks (backward compatibility)\n return this.renderMath(code, 'katex');\n \n case 'mermaid':\n if (window.mermaid) {\n return this.renderMermaid(code);\n }\n break;\n \n case 'geojson':\n return this.renderGeoJSON(code);\n \n case 'stl':\n return this.renderSTL(code);\n }\n }\n \n // Syntax highlighting support - keep editable for bidirectional\n if (window.hljs && lang && hljs.getLanguage(lang)) {\n const highlighted = hljs.highlight(code, { language: lang }).value;\n // Don't add contenteditable=\"false\" - the bidirectional system can extract text from the highlighted code\n return `<pre data-qd-fence=\"\\`\\`\\`\" data-qd-lang=\"${lang}\"><code class=\"hljs language-${lang}\">${highlighted}</code></pre>`;\n }\n \n // Default: let quikdown handle it\n return undefined;\n };\n \n // Reverse function to extract raw source from rendered HTML\n const reverse = (element) => {\n // Get the language from data attribute\n const lang = element.getAttribute('data-qd-lang') || '';\n let content = '';\n \n // For syntax-highlighted code, extract the raw text\n if (element.querySelector('code.hljs')) {\n const code = element.querySelector('code.hljs');\n content = code.textContent || code.innerText || '';\n }\n // For other code blocks, just get the text content\n else if (element.querySelector('code')) {\n const codeEl = element.querySelector('code');\n content = codeEl.textContent || codeEl.innerText || '';\n }\n // Fallback to element text\n else {\n content = element.textContent || element.innerText || '';\n }\n \n // Return in the format quikdown_bd expects\n return {\n content: content,\n lang: lang,\n fence: '```'\n };\n };\n \n // Return object format for v1.1.0 API with both render and reverse\n return { render, reverse };\n }\n \n /**\n * Render SVG content\n */\n renderSVG(code) {\n try {\n // Basic SVG validation\n const parser = new DOMParser();\n const doc = parser.parseFromString(code, 'image/svg+xml');\n const parseError = doc.querySelector('parsererror');\n \n if (parseError) {\n throw new Error('Invalid SVG');\n }\n \n // Sanitize SVG by removing script tags and event handlers\n const svg = doc.documentElement;\n svg.querySelectorAll('script').forEach(el => el.remove());\n \n // Remove event handlers\n const walker = document.createTreeWalker(svg, NodeFilter.SHOW_ELEMENT);\n let node;\n while ((node = walker.nextNode())) {\n for (let i = node.attributes.length - 1; i >= 0; i--) {\n const attr = node.attributes[i];\n if (attr.name.startsWith('on') || attr.value.includes('javascript:')) {\n node.removeAttribute(attr.name);\n }\n }\n }\n \n // Create container element programmatically to avoid attribute escaping issues\n const container = document.createElement('div');\n container.className = 'qde-svg-container';\n container.contentEditable = 'false';\n container.setAttribute('data-qd-fence', '```');\n container.setAttribute('data-qd-lang', 'svg');\n container.setAttribute('data-qd-source', code); // No escaping needed when using setAttribute!\n container.innerHTML = new XMLSerializer().serializeToString(svg);\n \n // Return the HTML string\n return container.outerHTML;\n } catch (err) {\n const errorContainer = document.createElement('pre');\n errorContainer.className = 'qde-error';\n errorContainer.contentEditable = 'false';\n errorContainer.setAttribute('data-qd-fence', '```');\n errorContainer.setAttribute('data-qd-lang', 'svg');\n errorContainer.textContent = `Invalid SVG: ${err.message}`;\n return errorContainer.outerHTML;\n }\n }\n \n /**\n * Render HTML content with DOMPurify if available\n */\n renderHTML(code) {\n const id = `html-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;\n \n // If DOMPurify is loaded, use it\n if (window.DOMPurify) {\n const clean = DOMPurify.sanitize(code);\n \n // Create container programmatically\n const container = document.createElement('div');\n container.className = 'qde-html-container';\n container.contentEditable = 'false';\n container.setAttribute('data-qd-fence', '```');\n container.setAttribute('data-qd-lang', 'html');\n container.setAttribute('data-qd-source', code);\n container.innerHTML = clean;\n \n return container.outerHTML;\n }\n \n // Try to lazy load DOMPurify\n this.lazyLoadLibrary(\n 'DOMPurify',\n () => window.DOMPurify,\n 'https://unpkg.com/dompurify/dist/purify.min.js'\n ).then(loaded => {\n if (loaded) {\n const element = document.getElementById(id);\n if (element) {\n const clean = DOMPurify.sanitize(code);\n element.innerHTML = clean;\n // Update attributes after loading\n element.setAttribute('data-qd-source', code);\n element.setAttribute('data-qd-fence', '```');\n element.setAttribute('data-qd-lang', 'html');\n }\n }\n });\n \n // Return placeholder with bidirectional attributes - non-editable\n const placeholder = document.createElement('div');\n placeholder.id = id;\n placeholder.className = 'qde-html-container';\n placeholder.contentEditable = 'false';\n placeholder.setAttribute('data-qd-fence', '```');\n placeholder.setAttribute('data-qd-lang', 'html');\n placeholder.setAttribute('data-qd-source', code);\n const pre = document.createElement('pre');\n pre.textContent = code;\n placeholder.appendChild(pre);\n \n return placeholder.outerHTML;\n }\n \n /**\n * Render math with MathJax (SVG output for better copy support)\n */\n renderMath(code, _lang) {\n const id = `math-${Math.random().toString(36).substring(2, 15)}`;\n \n // Create container exactly like squibview\n const container = document.createElement('div');\n container.id = id;\n container.className = 'math-display';\n container.contentEditable = 'false';\n container.setAttribute('data-source-type', 'math');\n \n // Format content for MathJax (display mode with $$) - exactly like squibview\n const singleLineContent = code.replace(/\\r?\\n/g, ' ').replace(/\\s+/g, ' ').trim();\n container.textContent = `$$${singleLineContent}$$`;\n \n // Add centering style\n container.style.textAlign = 'center';\n container.style.margin = '1em 0';\n \n \n // Ensure MathJax will be loaded (if not already)\n if (!window.MathJax || !window.MathJax.typesetPromise) {\n this.ensureMathJaxLoaded();\n }\n \n // MathJax will be processed in batch after preview update\n return container.outerHTML;\n }\n \n /**\n * Ensures MathJax is loaded (but doesn't process elements)\n */\n ensureMathJaxLoaded() {\n if (typeof window.MathJax === 'undefined' && !window.mathJaxLoading) {\n window.mathJaxLoading = true;\n \n // Configure MathJax before loading\n if (!window.MathJax) {\n window.MathJax = {\n loader: { load: ['input/tex', 'output/svg'] },\n tex: { \n packages: { '[+]': ['ams'] },\n inlineMath: [['$', '$'], ['\\\\(', '\\\\)']],\n displayMath: [['$$', '$$'], ['\\\\[', '\\\\]']],\n processEscapes: true,\n processEnvironments: true\n },\n options: {\n renderActions: { addMenu: [] },\n ignoreHtmlClass: 'tex2jax_ignore',\n processHtmlClass: 'tex2jax_process'\n },\n svg: {\n fontCache: 'none' // Important: self-contained SVGs for copy\n },\n startup: { typeset: false }\n };\n }\n \n const script = document.createElement('script');\n script.src = 'https://cdn.jsdelivr.net/npm/mathjax@3.2.2/es5/tex-svg.js';\n script.async = true;\n script.onload = () => {\n window.mathJaxLoading = false;\n \n // Process any existing math elements (like squibview)\n if (window.MathJax && window.MathJax.typesetPromise) {\n const mathElements = document.querySelectorAll('.math-display');\n if (mathElements.length > 0) {\n window.MathJax.typesetPromise(Array.from(mathElements)).catch(err => {\n console.warn('Initial MathJax processing failed:', err);\n });\n }\n }\n };\n script.onerror = () => {\n window.mathJaxLoading = false;\n console.error('Failed to load MathJax');\n };\n document.head.appendChild(script);\n }\n }\n \n /**\n * Render CSV/PSV/TSV as HTML table\n */\n renderTable(code, lang) {\n const escapedCode = this.escapeHtml(code);\n try {\n const delimiter = lang === 'csv' ? ',' : lang === 'psv' ? '|' : '\\t';\n const lines = code.trim().split('\\n');\n \n if (lines.length === 0) {\n return `<pre data-qd-fence=\"\\`\\`\\`\" data-qd-lang=\"${lang}\" data-qd-source=\"${escapedCode}\">${escapedCode}</pre>`;\n }\n \n // CSV tables CAN be editable - we'll convert HTML table back to CSV\n // Don't need data-qd-source since we convert the table structure back to CSV\n let html = `<table class=\"qde-data-table qde-csv-table\" data-qd-fence=\"\\`\\`\\`\" data-qd-lang=\"${lang}\">`;\n \n // Parse header\n const header = this.parseCSVLine(lines[0], delimiter);\n html += '<thead><tr>';\n header.forEach(cell => {\n html += `<th>${this.escapeHtml(cell.trim())}</th>`;\n });\n html += '</tr></thead>';\n \n // Parse body\n if (lines.length > 1) {\n html += '<tbody>';\n for (let i = 1; i < lines.length; i++) {\n const row = this.parseCSVLine(lines[i], delimiter);\n html += '<tr>';\n row.forEach(cell => {\n html += `<td>${this.escapeHtml(cell.trim())}</td>`;\n });\n html += '</tr>';\n }\n html += '</tbody>';\n }\n \n html += '</table>';\n return html;\n } catch (_err) {\n return `<pre data-qd-fence=\"\\`\\`\\`\" data-qd-lang=\"${lang}\" data-qd-source=\"${escapedCode}\">${escapedCode}</pre>`;\n }\n }\n\n /**\n * Parse CSV line handling quoted values\n */\n parseCSVLine(line, delimiter) {\n const result = [];\n let current = '';\n let inQuotes = false;\n \n for (let i = 0; i < line.length; i++) {\n const char = line[i];\n const nextChar = line[i + 1];\n \n if (char === '\"') {\n if (inQuotes && nextChar === '\"') {\n current += '\"';\n i++; // Skip next quote\n } else {\n inQuotes = !inQuotes;\n }\n } else if (char === delimiter && !inQuotes) {\n result.push(current);\n current = '';\n } else {\n current += char;\n }\n }\n \n result.push(current);\n return result;\n }\n \n /**\n * Render JSON with syntax highlighting\n */\n renderJSON(code, lang) {\n // If highlight.js is available, use it for all JSON\n if (window.hljs && hljs.getLanguage('json')) {\n try {\n // Try to format if valid JSON\n let toHighlight = code;\n try {\n const data = JSON.parse(code);\n toHighlight = JSON.stringify(data, null, 2);\n } catch (_e) {\n // Use original if not valid JSON\n }\n \n const highlighted = hljs.highlight(toHighlight, { language: 'json' }).value;\n return `<pre class=\"qde-json\" data-qd-fence=\"\\`\\`\\`\" data-qd-lang=\"${lang}\"><code class=\"hljs language-json\">${highlighted}</code></pre>`;\n } catch (_e) {\n // Fall through if highlighting fails\n }\n }\n \n // No highlighting available - return plain\n return `<pre class=\"qde-json\" data-qd-fence=\"\\`\\`\\`\" data-qd-lang=\"${lang}\">${this.escapeHtml(code)}</pre>`;\n }\n \n /**\n * Render GeoJSON map\n */\n renderGeoJSON(code) {\n // Generate unique map ID (following SquibView pattern)\n const mapId = `map-${Math.random().toString(36).substr(2, 15)}`;\n \n // Function to render the map\n const renderMap = () => {\n const container = document.getElementById(mapId + '-container');\n if (!container || !window.L) return;\n \n try {\n const data = JSON.parse(code);\n \n // Clear container and set deterministic size for rasterization\n const mapDiv = document.createElement('div');\n mapDiv.id = mapId;\n mapDiv.style.cssText = 'width: 100%; height: 300px;';\n container.innerHTML = '';\n container.appendChild(mapDiv);\n \n // Create the map\n const map = L.map(mapId);\n \n // Store back-reference for capture (per Gem's guide)\n container._map = map; // Avoid window pollution\n \n // Add tile layer with CORS support\n const tileLayer = L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {\n attribution: '',\n crossOrigin: 'anonymous' // Important for canvas capture\n });\n tileLayer.addTo(map);\n \n // Add GeoJSON layer\n const geoJsonLayer = L.geoJSON(data);\n geoJsonLayer.addTo(map);\n \n // Fit bounds if valid\n if (geoJsonLayer.getBounds().isValid()) {\n map.fitBounds(geoJsonLayer.getBounds());\n } else {\n map.setView([0, 0], 2);\n }\n \n // Store references for copy-time capture\n container._tileLayer = tileLayer;\n container._geoJsonLayer = geoJsonLayer;\n \n // Optional: Wait for tiles to load for better capture\n tileLayer.on('load', () => {\n container.setAttribute('data-tiles-loaded', 'true');\n });\n \n } catch (err) {\n container.innerHTML = `<pre class=\"qde-error\">GeoJSON error: ${this.escapeHtml(err.message)}</pre>`;\n }\n };\n \n // Check if Leaflet is already loaded\n if (window.L) {\n // Render after DOM update\n setTimeout(renderMap, 0);\n } else {\n // Lazy load Leaflet only if not already loading\n if (!window._qde_leaflet_loading) {\n window._qde_leaflet_loading = this.lazyLoadLibrary(\n 'Leaflet',\n () => window.L,\n 'https://unpkg.com/leaflet@1.9.4/dist/leaflet.js',\n 'https://unpkg.com/leaflet@1.9.4/dist/leaflet.css'\n ).catch(err => {\n console.warn('Failed to load Leaflet:', err);\n // Clear the loading promise so it can be retried\n window._qde_leaflet_loading = null;\n return false;\n });\n }\n \n window._qde_leaflet_loading.then(loaded => {\n if (loaded) {\n renderMap();\n } else {\n const element = document.getElementById(mapId + '-container');\n if (element) {\n element.innerHTML = '<div style=\"padding: 20px; text-align: center; color: #666;\">Failed to load map library</div>';\n }\n }\n }).catch(() => {\n // Error already handled above\n });\n }\n \n // Return container following SquibView pattern\n const container = document.createElement('div');\n container.className = 'geojson-container';\n container.id = mapId + '-container';\n container.style.cssText = 'width: 100%; height: 300px; border: 1px solid #ddd; border-radius: 4px; margin: 0.5em 0; background: #f0f0f0;';\n container.contentEditable = 'false';\n \n // Preserve source for copy-time identification (per Gem's guide)\n container.setAttribute('data-source-type', 'geojson');\n container.setAttribute('data-original-source', this.escapeHtml(code));\n \n // For bidirectional editing\n container.setAttribute('data-qd-fence', '```');\n container.setAttribute('data-qd-lang', 'geojson');\n container.setAttribute('data-qd-source', code);\n \n container.textContent = 'Loading map...';\n \n return container.outerHTML;\n }\n \n /**\n * Render STL 3D model\n */\n renderSTL(code) {\n const id = `qde-stl-viewer-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;\n\n // Function to render the 3D model (assumes window.THREE is loaded)\n const render3D = () => {\n const element = document.getElementById(id);\n if (!element) return;\n\n try {\n const THREE = window.THREE;\n \n // Create scene\n const scene = new THREE.Scene();\n scene.background = new THREE.Color(0xf0f0f0);\n \n // Create camera\n const camera = new THREE.PerspectiveCamera(75, element.clientWidth / 400, 0.1, 1000);\n \n // Create renderer\n const renderer = new THREE.WebGLRenderer({ antialias: true });\n renderer.setSize(element.clientWidth, 400);\n element.innerHTML = '';\n element.appendChild(renderer.domElement);\n \n // Store Three.js references for copy functionality (like squibview)\n element._threeScene = scene;\n element._threeCamera = camera;\n element._threeRenderer = renderer;\n \n // Parse STL data (ASCII format)\n const geometry = this.parseSTL(code);\n const material = new THREE.MeshLambertMaterial({ color: 0x0066ff });\n const mesh = new THREE.Mesh(geometry, material);\n scene.add(mesh);\n \n // Add lighting\n const ambientLight = new THREE.AmbientLight(0x404040, 0.6);\n scene.add(ambientLight);\n \n const directionalLight = new THREE.DirectionalLight(0xffffff, 0.8);\n directionalLight.position.set(1, 1, 1).normalize();\n scene.add(directionalLight);\n \n // Position camera based on object bounds\n const box = new THREE.Box3().setFromObject(mesh);\n const center = box.getCenter(new THREE.Vector3());\n const size = box.getSize(new THREE.Vector3());\n const maxDim = Math.max(size.x, size.y, size.z);\n \n camera.position.set(center.x + maxDim, center.y + maxDim, center.z + maxDim);\n camera.lookAt(center);\n \n // Animate\n const animate = () => {\n requestAnimationFrame(animate);\n mesh.rotation.y += 0.01;\n renderer.render(scene, camera);\n };\n animate();\n } catch (err) {\n console.error('STL rendering error:', err);\n element.innerHTML = `<pre class=\"qde-error\">STL error: ${this.escapeHtml(err.message)}</pre>`;\n }\n };\n \n // If Three.js is already loaded, render immediately. Otherwise lazy-load\n // it from a CDN (matches the GeoJSON/Leaflet pattern).\n if (window.THREE) {\n setTimeout(render3D, 0);\n } else {\n if (!window._qde_three_loading) {\n window._qde_three_loading = this.lazyLoadLibrary(\n 'Three.js',\n () => window.THREE,\n 'https://unpkg.com/three@0.147.0/build/three.min.js'\n ).catch(_err => {\n console.warn('Failed to load Three.js for STL rendering');\n window._qde_three_loading = null;\n return false;\n });\n }\n window._qde_three_loading.then(loaded => {\n if (loaded) {\n render3D();\n } else {\n const element = document.getElementById(id);\n if (element) {\n element.innerHTML = '<div style=\"padding: 20px; text-align: center; color: #666;\">Failed to load Three.js for STL rendering</div>';\n }\n }\n });\n }\n\n // Return placeholder with data-stl-id for copy functionality\n return `<div id=\"${id}\" class=\"qde-stl-container\" data-stl-id=\"${id}\" data-qd-fence=\"\\`\\`\\`\" data-qd-lang=\"stl\" data-qd-source=\"${this.escapeHtml(code)}\" contenteditable=\"false\" style=\"height: 400px; background: #f0f0f0; display: flex; align-items: center; justify-content: center;\">Loading 3D model...</div>`;\n }\n \n /**\n * Parse ASCII STL format\n * @param {string} stlData - The STL file content\n * @returns {THREE.BufferGeometry} - The parsed geometry\n */\n parseSTL(stlData) {\n const THREE = window.THREE;\n const geometry = new THREE.BufferGeometry();\n const vertices = [];\n const normals = [];\n \n const lines = stlData.split('\\n');\n let currentNormal = null;\n \n for (let line of lines) {\n line = line.trim();\n \n if (line.startsWith('facet normal')) {\n const parts = line.split(/\\s+/);\n currentNormal = [parseFloat(parts[2]), parseFloat(parts[3]), parseFloat(parts[4])];\n } else if (line.startsWith('vertex')) {\n const parts = line.split(/\\s+/);\n vertices.push(parseFloat(parts[1]), parseFloat(parts[2]), parseFloat(parts[3]));\n if (currentNormal) {\n normals.push(currentNormal[0], currentNormal[1], currentNormal[2]);\n }\n }\n }\n \n geometry.setAttribute('position', new THREE.Float32BufferAttribute(vertices, 3));\n geometry.setAttribute('normal', new THREE.Float32BufferAttribute(normals, 3));\n \n return geometry;\n }\n \n /**\n * Render Mermaid diagram\n */\n renderMermaid(code) {\n const id = `mermaid-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;\n setTimeout(() => {\n const element = document.getElementById(id);\n if (element && window.mermaid) {\n mermaid.render(id + '-svg', code).then(result => {\n element.innerHTML = result.svg;\n }).catch(err => {\n element.innerHTML = `<pre>Error rendering diagram: ${err.message}</pre>`;\n });\n }\n }, 0);\n \n // Create container programmatically\n const container = document.createElement('div');\n container.id = id;\n container.className = 'mermaid';\n container.contentEditable = 'false';\n container.setAttribute('data-qd-source', code);\n container.setAttribute('data-qd-fence', '```');\n container.setAttribute('data-qd-lang', 'mermaid');\n container.textContent = 'Loading diagram...';\n \n return container.outerHTML;\n }\n \n /**\n * Escape HTML for attributes\n */\n escapeHtml(text) {\n return (text ?? \"\").replace(/[&\"'<>]/g, m => \n ({'&':'&amp;','\"':'&quot;',\"'\":'&#39;','<':'&lt;','>':'&gt;'}[m]));\n }\n \n /**\n * Make complex fence blocks non-editable\n */\n makeFencesNonEditable() {\n if (!this.previewPanel) return;\n \n // Only make specific complex fence types non-editable\n // SVG, HTML, Math, Mermaid already have contenteditable=\"false\" set\n // Syntax-highlighted code also has it set\n \n // Don't make regular code blocks or tables non-editable\n // They can be edited and properly round-trip\n }\n \n /**\n * Load plugins dynamically — honors both `plugins: { highlightjs, mermaid }`\n * (legacy) and the newer `preloadFences` option which can preload any\n * combination of fence libraries (or 'all') at construction time.\n */\n async loadPlugins() {\n const namesToLoad = new Set();\n\n // Legacy plugins option\n if (this.options.plugins) {\n if (this.options.plugins.highlightjs) namesToLoad.add('highlightjs');\n if (this.options.plugins.mermaid) namesToLoad.add('mermaid');\n }\n\n // New preloadFences option\n const pf = this.options.preloadFences;\n if (pf === 'all') {\n Object.keys(FENCE_LIBRARIES).forEach(n => namesToLoad.add(n));\n } else if (Array.isArray(pf)) {\n for (const entry of pf) {\n if (typeof entry === 'string') {\n if (FENCE_LIBRARIES[entry]) namesToLoad.add(entry);\n else console.warn(`QuikdownEditor: unknown preloadFences entry \"${entry}\"`);\n } else if (entry && typeof entry === 'object' && entry.script) {\n // Custom library: { name, script, css? }\n namesToLoad.add('__custom__:' + (entry.name || entry.script));\n FENCE_LIBRARIES['__custom__:' + (entry.name || entry.script)] = {\n check: () => false,\n script: entry.script,\n css: entry.css\n };\n }\n }\n } else if (pf) {\n console.warn('QuikdownEditor: preloadFences should be \"all\", an array, or null');\n }\n\n // Load each in parallel; respect already-loaded state\n const promises = [];\n for (const name of namesToLoad) {\n const lib = FENCE_LIBRARIES[name];\n if (!lib || lib.check()) continue;\n if (lib.beforeLoad) lib.beforeLoad();\n const p = (async () => {\n try {\n const tasks = [];\n if (lib.script) tasks.push(this.loadScript(lib.script));\n if (lib.css) tasks.push(this.loadCSS(lib.css, 'qde-hljs-light'));\n if (lib.cssDark) tasks.push(this.loadCSS(lib.cssDark, 'qde-hljs-dark'));\n await Promise.all(tasks);\n if (lib.css && lib.cssDark) this._syncHljsTheme();\n if (lib.afterLoad) lib.afterLoad();\n } catch (err) {\n console.warn(`QuikdownEditor: failed to preload ${name}:`, err);\n }\n })();\n promises.push(p);\n }\n\n await Promise.all(promises);\n }\n \n /**\n * Lazy load library if not already loaded\n */\n async lazyLoadLibrary(name, check, scriptUrl, cssUrl = null) {\n // Check if library is already loaded\n if (check()) {\n return true;\n }\n \n try {\n const promises = [];\n \n // Load script\n if (scriptUrl) {\n promises.push(this.loadScript(scriptUrl));\n }\n \n // Load CSS if provided\n if (cssUrl) {\n promises.push(this.loadCSS(cssUrl));\n }\n \n await Promise.all(promises);\n \n // Verify library loaded\n return check();\n } catch (err) {\n console.error(`Failed to load ${name}:`, err);\n return false;\n }\n }\n \n /**\n * Load external script\n */\n loadScript(src) {\n return new Promise((resolve, reject) => {\n const script = document.createElement('script');\n script.src = src;\n script.onload = resolve;\n script.onerror = reject;\n document.head.appendChild(script);\n });\n }\n \n /**\n * Load external CSS\n */\n loadCSS(href, id) {\n return new Promise((resolve) => {\n const link = document.createElement('link');\n link.rel = 'stylesheet';\n link.href = href;\n if (id) link.id = id;\n link.onload = resolve;\n document.head.appendChild(link);\n // Resolve anyway after timeout (CSS doesn't always fire onload)\n setTimeout(resolve, 1000);\n });\n }\n\n /**\n * Enable the hljs stylesheet matching the current theme and disable\n * the other one. Called from applyTheme and after hljs CSS loads.\n */\n _syncHljsTheme() {\n const isDark = this.container.classList.contains('qde-dark');\n const light = document.getElementById('qde-hljs-light');\n const dark = document.getElementById('qde-hljs-dark');\n if (light) light.disabled = isDark;\n if (dark) dark.disabled = !isDark;\n }\n\n /**\n * Apply the current theme (based on this.options.theme)\n */\n applyTheme() {\n const theme = this.options.theme;\n\n // Tear down any previous auto-mode listener so we don't stack them\n if (this._autoThemeListener) {\n window.matchMedia('(prefers-color-scheme: dark)').removeEventListener('change', this._autoThemeListener);\n this._autoThemeListener = null;\n }\n\n if (theme === 'auto') {\n const mq = window.matchMedia('(prefers-color-scheme: dark)');\n this.container.classList.toggle('qde-dark', mq.matches);\n this._autoThemeListener = (e) => {\n this.container.classList.toggle('qde-dark', e.matches);\n this._syncHljsTheme();\n };\n mq.addEventListener('change', this._autoThemeListener);\n } else {\n this.container.classList.toggle('qde-dark', theme === 'dark');\n }\n this._syncHljsTheme();\n }\n\n /**\n * Set theme at runtime. Accepts 'light', 'dark', or 'auto'.\n * @param {'light'|'dark'|'auto'} theme\n */\n setTheme(theme) {\n if (!['light', 'dark', 'auto'].includes(theme)) return;\n this.options.theme = theme;\n this.applyTheme();\n }\n\n /**\n * Get the current theme option (as configured, not resolved).\n * @returns {'light'|'dark'|'auto'}\n */\n getTheme() {\n return this.options.theme;\n }\n \n /**\n * Set lazy linefeeds option\n * @param {boolean} enabled - Whether to enable lazy linefeeds\n */\n setLazyLinefeeds(enabled) {\n this.options.lazy_linefeeds = enabled;\n // Re-render if we have content\n if (this._markdown) {\n this.updateFromMarkdown(this._markdown);\n }\n }\n \n /**\n * Get lazy linefeeds option\n * @returns {boolean}\n */\n getLazyLinefeeds() {\n return this.options.lazy_linefeeds;\n }\n \n /**\n * Set debounce delay for input updates\n * @param {number} delay - Delay in milliseconds (0 for instant)\n */\n setDebounceDelay(delay) {\n this.options.debounceDelay = Math.max(0, delay);\n }\n \n /**\n * Get current debounce delay\n * @returns {number} Delay in milliseconds\n */\n getDebounceDelay() {\n return this.options.debounceDelay;\n }\n \n /**\n * Set editor mode\n */\n setMode(mode) {\n if (!['source', 'preview', 'split'].includes(mode)) return;\n\n // Preserve theme class across mode swap (the assignment to className\n // below would otherwise wipe it out — this used to be a no-op bug\n // where dark mode was lost on every setMode call).\n const wasDark = this.container.classList.contains('qde-dark');\n const previousMode = this.currentMode;\n\n this.currentMode = mode;\n this.container.className = `qde-container qde-mode-${mode}`;\n if (wasDark) {\n this.container.classList.add('qde-dark');\n }\n\n // Reset mobile split-toggle button text\n if (this.toolbar) {\n const splitToggle = this.toolbar.querySelector('.qde-split-toggle');\n if (splitToggle) {\n splitToggle.textContent = 'Preview';\n }\n }\n\n // Update toolbar buttons\n if (this.toolbar) {\n this.toolbar.querySelectorAll('.qde-btn[data-mode]').forEach(btn => {\n btn.classList.toggle('active', btn.dataset.mode === mode);\n });\n }\n\n // If the preview was hidden (source-only) it may have missed content\n // updates. Re-render it now, including MathJax typesetting.\n // Do NOT re-render if the preview was already visible — that would\n // destroy MathJax-typeset SVG output with raw pre-typeset HTML.\n if (mode !== 'source' && previousMode === 'source' && this._html) {\n this.previewPanel.innerHTML = this._html;\n setTimeout(() => this.makeFencesNonEditable(), 0);\n if (typeof window !== 'undefined' && window.MathJax && window.MathJax.typesetPromise) {\n const mathElements = this.previewPanel.querySelectorAll('.math-display');\n if (mathElements.length > 0) {\n window.MathJax.typesetPromise(Array.from(mathElements))\n .catch(() => {});\n }\n }\n }\n\n // Trigger mode change event\n if (this.options.onModeChange) {\n this.options.onModeChange(mode);\n }\n }\n \n // --- Undo / Redo ---\n\n /**\n * Push current markdown state onto the undo stack (called before a change).\n * Only pushes if the new state differs from the current state.\n * @param {string} newMarkdown - the incoming markdown (used to detect no-op)\n * @private\n */\n _pushUndoState(newMarkdown) {\n // Don't push if the content hasn't actually changed\n if (newMarkdown === this._markdown) return;\n\n this._undoStack.push(this._markdown);\n\n // Enforce max stack size\n const max = this.options.undoStackSize || 100;\n if (this._undoStack.length > max) {\n this._undoStack.splice(0, this._undoStack.length - max);\n }\n\n // Any new edit clears the redo stack\n this._redoStack = [];\n this._updateUndoButtons();\n }\n\n /**\n * Undo the last change. Restores the previous markdown state.\n */\n undo() {\n if (!this.canUndo()) return;\n // Save current state to redo stack\n this._redoStack.push(this._markdown);\n const previous = this._undoStack.pop();\n this._isUndoRedo = true;\n // Update state directly (setMarkdown is async; keep it synchronous here)\n this._markdown = previous;\n if (this.sourceTextarea) {\n this.sourceTextarea.value = previous;\n }\n this.updateFromMarkdown(previous);\n this._updateUndoButtons();\n }\n\n /**\n * Redo the last undone change.\n */\n redo() {\n if (!this.canRedo()) return;\n // Save current state to undo stack\n this._undoStack.push(this._markdown);\n const next = this._redoStack.pop();\n this._isUndoRedo = true;\n this._markdown = next;\n if (this.sourceTextarea) {\n this.sourceTextarea.value = next;\n }\n this.updateFromMarkdown(next);\n this._updateUndoButtons();\n }\n\n /**\n * @returns {boolean} true if undo is possible\n */\n canUndo() {\n return this._undoStack.length > 0;\n }\n\n /**\n * @returns {boolean} true if redo is possible\n */\n canRedo() {\n return this._redoStack.length > 0;\n }\n\n /**\n * Clear the undo and redo history.\n */\n clearHistory() {\n this._undoStack = [];\n this._redoStack = [];\n this._updateUndoButtons();\n }\n\n /**\n * Update the disabled state of the undo/redo toolbar buttons.\n * @private\n */\n _updateUndoButtons() {\n if (!this.toolbar) return;\n const undoBtn = this.toolbar.querySelector('[data-action=\"undo\"]');\n const redoBtn = this.toolbar.querySelector('[data-action=\"redo\"]');\n if (undoBtn) {\n undoBtn.classList.toggle('disabled', !this.canUndo());\n }\n if (redoBtn) {\n redoBtn.classList.toggle('disabled', !this.canRedo());\n }\n }\n\n /**\n * Handle toolbar actions\n */\n handleAction(action) {\n switch(action) {\n case 'copy-markdown':\n this.copy('markdown');\n break;\n case 'copy-html':\n this.copy('html');\n break;\n case 'copy-rendered':\n this.copyRendered();\n break;\n case 'remove-hr':\n this.removeHR();\n break;\n case 'lazy-linefeeds':\n this.convertLazyLinefeeds();\n break;\n case 'undo':\n this.undo();\n break;\n case 'redo':\n this.redo();\n break;\n }\n }\n \n /**\n * Copy content to clipboard\n */\n async copy(type) {\n const content = type === 'markdown' ? this._markdown : this._html;\n \n try {\n await navigator.clipboard.writeText(content);\n \n // Visual feedback\n const btn = this.toolbar.querySelector(`[data-action=\"copy-${type}\"]`);\n if (btn) {\n const originalText = btn.textContent;\n btn.textContent = 'Copied!';\n setTimeout(() => {\n btn.textContent = originalText;\n }, 1500);\n }\n } catch (err) {\n console.error('Failed to copy:', err);\n }\n }\n \n // Public API\n \n /**\n * Get current markdown\n */\n get markdown() {\n return this._markdown;\n }\n \n /**\n * Set markdown content\n */\n set markdown(value) {\n this.setMarkdown(value);\n }\n \n /**\n * Get current HTML\n */\n get html() {\n return this._html;\n }\n \n /**\n * Get current mode\n */\n get mode() {\n return this.currentMode;\n }\n \n /**\n * Set markdown content\n */\n async setMarkdown(markdown) {\n // Wait for initialization if needed\n if (this.initPromise) {\n await this.initPromise;\n }\n \n this._markdown = markdown;\n if (this.sourceTextarea) {\n this.sourceTextarea.value = markdown;\n }\n this.updateFromMarkdown(markdown);\n }\n \n /**\n * Get markdown content\n */\n getMarkdown() {\n return this._markdown;\n }\n \n /**\n * Get HTML content\n */\n getHTML() {\n return this._html;\n }\n \n /**\n * Remove all horizontal rules (---) from markdown source.\n * Preserves content inside fences (``` or ~~~) and table separator rows.\n */\n async removeHR() {\n const cleaned = QuikdownEditor.removeHRFromMarkdown(this._markdown);\n await this.setMarkdown(cleaned);\n\n // Visual feedback if toolbar button exists\n const btn = this.toolbar?.querySelector('[data-action=\"remove-hr\"]');\n if (btn) {\n const originalText = btn.textContent;\n btn.textContent = 'Removed!';\n setTimeout(() => {\n btn.textContent = originalText;\n }, 1500);\n }\n }\n\n /**\n * Static: remove horizontal rules from markdown string.\n * Safe for fences, tables, and all markdown constructs.\n * Can be used headless without an editor instance.\n * @param {string} markdown - source markdown\n * @returns {string} markdown with standalone HRs removed\n */\n static removeHRFromMarkdown(markdown) {\n const lines = (markdown || '').split('\\n');\n const result = [];\n let inFence = false;\n let openChar = null;\n let openLen = 0;\n\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i];\n const trimmed = line.trim();\n\n // Track fence open/close\n if (!inFence) {\n const fo = fenceOpen(trimmed);\n if (fo) {\n inFence = true;\n openChar = fo.char;\n openLen = fo.len;\n result.push(line);\n continue;\n }\n } else {\n if (isFenceClose(trimmed, openChar, openLen)) {\n inFence = false;\n openChar = null;\n openLen = 0;\n }\n result.push(line);\n continue;\n }\n\n // Detect table row/separator with pipes — always keep\n if (/^\\|.*\\|$/.test(trimmed) || (/^[-| :]+$/.test(trimmed) && trimmed.includes('|'))) {\n result.push(line);\n continue;\n }\n\n // Check if this line is a standalone HR (no ReDoS — linear scan)\n if (isHRLine(trimmed)) {\n // Table separator heuristic: immediately adjacent lines (no blank\n // lines between) that look like table rows protect this HR-like line\n const prevLine = i > 0 ? lines[i - 1].trim() : '';\n const nextLine = i < lines.length - 1 ? lines[i + 1].trim() : '';\n if (looksLikeTableRow(prevLine) || looksLikeTableRow(nextLine)) {\n result.push(line);\n continue;\n }\n // It's a real HR — skip it\n continue;\n }\n\n result.push(line);\n }\n\n return result.join('\\n');\n }\n\n /**\n * Convert lazy linefeeds in markdown source.\n * Replaces single newlines with double newlines (adds real line breaks)\n * except inside fences, tables, and other block-level constructs.\n * Idempotent: calling multiple times produces the same result.\n * Can be used as a toolbar action or headless via the static method.\n */\n async convertLazyLinefeeds() {\n const converted = QuikdownEditor.convertLazyLinefeeds(this._markdown);\n await this.setMarkdown(converted);\n\n // Visual feedback if toolbar button exists\n const btn = this.toolbar?.querySelector('[data-action=\"lazy-linefeeds\"]');\n if (btn) {\n const originalText = btn.textContent;\n btn.textContent = 'Converted!';\n setTimeout(() => {\n btn.textContent = originalText;\n }, 1500);\n }\n }\n\n /**\n * Static: convert lazy linefeeds in markdown source.\n * Turns single \\n between non-blank lines into \\n\\n so each line becomes\n * its own paragraph / hard break. Idempotent — already-doubled newlines\n * are not doubled again. Fences, tables, lists, blockquotes, headings,\n * and HTML blocks are left untouched.\n * @param {string} markdown - source markdown\n * @returns {string} markdown with lazy linefeeds resolved\n */\n static convertLazyLinefeeds(markdown) {\n // Two-phase approach (much cleaner than the old single pass):\n //\n // Phase A: walk lines, classify each as { content, blank, fence }.\n // Inside fences, lines are passed through verbatim.\n // Phase B: emit lines with the rule:\n // \"between two adjacent CONTENT lines, ensure exactly one\n // blank line — never zero, never more than one.\"\n //\n // The rule applies regardless of whether the content lines are\n // headings, lists, blockquotes, table rows, paragraphs, or HR — any\n // adjacent pair of non-fence non-blank lines gets exactly one blank\n // between them. This produces the cleanest possible output for any\n // input and is fully idempotent.\n //\n // Lines that are whitespace-only (e.g. \" \") are normalized to\n // empty strings, eliminating \"phantom\" blank lines.\n //\n // Lists are a special case: adjacent list items (same marker type)\n // should NOT get a blank line between them, otherwise we'd break\n // tight lists.\n //\n // Same applies to blockquote lines and table rows — adjacent rows\n // belong to the same block.\n\n const inputLines = (markdown || '').split('\\n');\n\n // -------- Phase A: classify lines, normalize whitespace-only --------\n // Each entry: { line, kind } where kind is one of:\n // 'fence-open', 'fence-close', 'fence-body', 'blank', 'content'\n // Plus a 'category' for content lines: 'list-ul', 'list-ol',\n // 'blockquote', 'table', 'heading', 'hr', 'paragraph'\n const items = [];\n let inFence = false;\n let openChar = null;\n let openLen = 0;\n\n for (const rawLine of inputLines) {\n const line = rawLine;\n const trimmed = line.trim();\n\n // Fence tracking via shared utilities\n if (!inFence) {\n const fo = fenceOpen(trimmed);\n if (fo) {\n inFence = true;\n openChar = fo.char;\n openLen = fo.len;\n items.push({ line, kind: 'fence-open' });\n continue;\n }\n } else {\n if (isFenceClose(trimmed, openChar, openLen)) {\n inFence = false;\n openChar = null;\n openLen = 0;\n items.push({ line, kind: 'fence-close' });\n } else {\n items.push({ line, kind: 'fence-body' });\n }\n continue;\n }\n\n // Outside fence: whitespace-only lines become canonical blanks\n if (trimmed === '') {\n items.push({ line: '', kind: 'blank' });\n continue;\n }\n\n // Categorize content lines (no ReDoS — classifyLine uses linear scan for HR)\n let category = classifyLine(trimmed);\n // Indented continuation of a list (2+ leading spaces or tab)\n if (category === 'paragraph' && /^(?: {4}|\\t| {2,}[-*+]| {2,}\\d+\\.)/.test(line)) {\n category = 'list-cont';\n }\n\n items.push({ line, kind: 'content', category });\n }\n\n // -------- Phase B: emit with exactly-one-blank-line normalization --------\n // Same-block adjacent lines (lists, blockquotes, tables) stay\n // touching; any other adjacent content pair gets exactly one blank.\n const result = [];\n let prev = null; // last emitted non-blank content item\n\n function inSameBlock(a, b) {\n if (!a || !b) return false;\n // Lists: same marker family OR list-content continuation\n if ((a.category === 'list-ul' || a.category === 'list-ol' || a.category === 'list-cont') &&\n (b.category === 'list-ul' || b.category === 'list-ol' || b.category === 'list-cont')) {\n return true;\n }\n // Blockquotes\n if (a.category === 'blockquote' && b.category === 'blockquote') return true;\n // Table rows\n if (a.category === 'table' && b.category === 'table') return true;\n return false;\n }\n\n for (const item of items) {\n if (item.kind === 'fence-open' || item.kind === 'fence-body' || item.kind === 'fence-close') {\n // Fences: ensure exactly one blank line before the fence-open\n if (item.kind === 'fence-open' && prev && result.length > 0 && result[result.length - 1] !== '') {\n result.push('');\n }\n result.push(item.line);\n if (item.kind === 'fence-close') prev = { kind: 'content', category: 'fence' };\n continue;\n }\n\n if (item.kind === 'blank') {\n // Skip — Phase B inserts its own blank lines as needed\n continue;\n }\n\n // item.kind === 'content'\n if (prev) {\n if (inSameBlock(prev, item)) {\n // Adjacent same-block lines: no blank between\n } else {\n // Different blocks (or paragraphs): exactly one blank\n if (result[result.length - 1] !== '') result.push('');\n }\n }\n result.push(item.line);\n prev = item;\n }\n\n // Trim trailing blank lines so output has exactly one terminal newline\n while (result.length > 0 && result[result.length - 1] === '') result.pop();\n\n return result.join('\\n');\n }\n \n /**\n * Copy rendered content as rich text\n */\n async copyRendered() {\n try {\n const result = await getRenderedContent(this.previewPanel);\n if (result.success) {\n // Visual feedback\n const btn = this.toolbar?.querySelector('[data-action=\"copy-rendered\"]');\n if (btn) {\n const originalText = btn.textContent;\n btn.textContent = 'Copied!';\n setTimeout(() => {\n btn.textContent = originalText;\n }, 1500);\n }\n }\n } catch (err) {\n console.error('Failed to copy rendered content:', err);\n }\n }\n \n /**\n * Destroy the editor\n */\n destroy() {\n // Clear timers\n clearTimeout(this.updateTimer);\n \n // Clear container\n this.container.innerHTML = '';\n this.container.classList.remove('qde-container', 'qde-dark');\n \n // Remove injected styles (only if no other editors exist)\n const otherEditors = document.querySelectorAll('.qde-container');\n if (otherEditors.length === 0) {\n const style = document.getElementById('qde-styles');\n if (style) style.remove();\n }\n }\n}\n\n// Export\nexport default QuikdownEditor;\n\n// Export for CommonJS (needed for bundled ESM to work with Jest)\nif (typeof module !== 'undefined' && module.exports) {\n module.exports = QuikdownEditor;\n}\n\n// Also export for UMD builds\nif (typeof window !== 'undefined') {\n window.QuikdownEditor = QuikdownEditor;\n}"],"names":["isHRLine","trimmed","length","stripped","i","ch","isDashHRLine","j","fenceOpen","len","char","lang","slice","trim","isFenceClose","openChar","openLen","classifyLine","test","looksLikeTableRow","line","includes","CLASS_PREFIX","PLACEHOLDER_CB","ESC_MAP","QUIKDOWN_STYLES","h1","h2","h3","h4","h5","h6","pre","code","blockquote","table","th","td","hr","img","a","strong","em","del","ul","ol","li","quikdown","markdown","options","fence_plugin","inline_styles","bidirectional","lazy_linefeeds","allow_unsafe_html","getAttr","styles","tag","additionalStyle","style","replace","endsWith","classAttr","createGetAttr","escapeHtml","text","m","dataQd","marker","sanitizeUrl","url","allowUnsafe","trimmedUrl","lowerUrl","toLowerCase","dangerousProtocols","protocol","startsWith","html","codeBlocks","inlineCodes","match","fence","placeholder","langTrimmed","render","push","trimEnd","custom","hasReverse","reverse","lines","split","result","inTable","tableLines","tableHtml","buildTable","join","processTable","hashCount","content","repeat","joined","scanLineBlocks","listStack","indent","level","Math","floor","isOrdered","listType","listItemContent","taskListClass","taskMatch","checked","taskContent","isChecked","list","pop","type","currentList","liAttr","processLists","alt","src","sanitizedSrc","allow_unsafe_urls","altAttr","srcAttr","href","sanitizedHref","rel","textAttr","prefix","sanitizedUrl","forEach","pattern","blocks","bi","b","offset","substring","RegExp","replacement","block","undefined","langClass","codeAttr","langAttr","fenceAttr","processInlineMarkdown","separatorIndex","headerLines","bodyLines","alignments","map","cell","alignStyle","processedCell","quikdown_bd","async","svgToPng","svgElement","needsWhiteBackground","Promise","resolve","reject","svgString","XMLSerializer","serializeToString","canvas","document","createElement","ctx","getContext","Image","isMermaidSvg","closest","classList","contains","hasExplicitDimensions","getAttribute","svgWidth","svgHeight","clientWidth","viewBox","baseVal","width","parseFloat","clientHeight","height","modifiedSvgString","tempDiv","innerHTML","tempSvg","querySelector","setAttribute","toString","scale","onload","fillStyle","fillRect","drawImage","toBlob","blob","err","onerror","svgDataUrl","encodeURIComponent","rasterizeGeoJSONMap","liveContainer","_map","console","warn","mapRect","getBoundingClientRect","round","dpr","window","devicePixelRatio","tiles","querySelectorAll","tilePromises","tile","crossOrigin","tileRect","offsetX","left","offsetY","top","all","svgOverlays","svg","svgRect","svgStr","svgBlob","Blob","URL","createObjectURL","revokeObjectURL","Error","markerIcons","markerRect","toDataURL","error","getRenderedContent","previewPanel","mathBlocks","Array","from","some","MathJax","typesetPromise","clone","cloneNode","el","fontWeight","fontStyle","textDecoration","backgroundColor","padding","borderRadius","fontFamily","fontSize","marginTop","marginBottom","borderLeft","marginLeft","paddingLeft","color","border","borderTop","margin","borderCollapse","textAlign","parentElement","tr","lineHeight","whiteSpace","overflowX","appendChild","parentNode","replaceChild","images","naturalWidth","naturalHeight","maxWidth","maxHeight","min","random","substr","response","fetch","maxSize","size","dataUrl","reader","FileReader","onloadend","readAsDataURL","stlContainers","container","containerId","dataset","stlId","originalContainer","renderer","_threeRenderer","scene","_threeScene","camera","_threeCamera","imgWidth","imgHeight","canvasErr","cssText","textContent","mermaidContainers","pngBlob","chartContainers","chartId","svgContainers","mathElements","mathEl","value","_e","scaleFactor","scaledWidth","scaledHeight","scaleX","scaleY","imgElement","img2","setTimeout","displayWidth","displayHeight","geojsonContainers","clonedContainer","originalSource","allLiveContainers","candidate","mapContainers","id","leafletContainer","max","leafRect","r","x","y","w","h","overlaps","right","bottom","getComputedStyle","display","visibility","overlaySvgs","icon","mapDataUrl","String","htmlContainers","source","htmlImages","widthAttr","heightAttr","parseInt","tempImg","aspectRatio","absoluteImg","fragment","htmlContent","innerText","platform","navigator","userAgent","getPlatform","clipboard","write","ClipboardItem","success","modernErr","position","overflow","body","range","createRange","selectNodeContents","selection","getSelection","removeAllRanges","addRange","execCommand","removeChild","copyToClipboard","emitStyles","theme","themeOverrides","_textColor","css","Object","entries","themedStyle","oldColor","newColor","replaceAll","configure","version","module","exports","keys","key","toMarkdown","htmlOrElement","Element","walkNode","node","parentContext","nodeType","Node","TEXT_NODE","ELEMENT_NODE","tagName","childContent","child","childNodes","parentTag","boldMarker","emMarker","delMarker","codeMarker","fenceMarker","codeEl","quoteMarker","linkText","walkList","alignData","thead","headerRow","headers","_","align","tbody","row","cells","walkTable","trailingBlankLines","divLang","divFence","divSource","temp","mermaidPre","preSource","sourceElement","mermaidElement","listNode","depth","index","children","checkbox","itemContent","innerParser","DEFAULT_OPTIONS","mode","showToolbar","showRemoveHR","showLazyLinefeeds","debounceDelay","plugins","highlightjs","mermaid","preloadFences","customFences","enableComplexFences","showUndoRedo","undoStackSize","FENCE_LIBRARIES","check","hljs","script","cssDark","afterLoad","initialize","startOnLoad","math","beforeLoad","loader","load","tex","packages","inlineMath","displayMath","processEscapes","processEnvironments","renderActions","addMenu","ignoreHtmlClass","processHtmlClass","fontCache","startup","typeset","geojson","L","stl","THREE","QuikdownEditor","constructor","this","_markdown","_html","currentMode","updateTimer","_undoStack","_redoStack","_isUndoRedo","initPromise","init","loadPlugins","buildUI","attachEvents","applyTheme","setMode","initialContent","setMarkdown","add","toolbar","createToolbar","editorArea","className","sourcePanel","sourceTextarea","spellcheck","contentEditable","injectStyles","modeLabels","preview","btn","title","splitToggle","undoBtn","action","redoBtn","spacer","removeHRBtn","lazyLFBtn","getElementById","head","addEventListener","handleSourceInput","handlePreviewInput","e","target","toggle","showingPreview","handleAction","ctrlKey","metaKey","preventDefault","shiftKey","redo","undo","matchMedia","portraitQuery","switchIfPortrait","matches","then","clearTimeout","updateFromMarkdown","updateFromHTML","_pushUndoState","createFencePlugin","makeFencesNonEditable","catch","_err","onChange","clonedPanel","preprocessSpecialElements","newMarkdown","_updateUndoButtons","panel","element","delimiter","csv","needsQuoting","renderSVG","renderHTML","renderMath","renderTable","renderJSON","renderMermaid","renderGeoJSON","renderSTL","getLanguage","highlight","language","doc","DOMParser","parseFromString","documentElement","remove","walker","createTreeWalker","NodeFilter","SHOW_ELEMENT","nextNode","attributes","attr","name","removeAttribute","outerHTML","errorContainer","message","Date","now","DOMPurify","clean","sanitize","lazyLoadLibrary","loaded","_lang","singleLineContent","ensureMathJaxLoaded","mathJaxLoading","escapedCode","header","parseCSVLine","current","inQuotes","nextChar","toHighlight","data","JSON","parse","stringify","mapId","renderMap","mapDiv","tileLayer","attribution","addTo","geoJsonLayer","geoJSON","getBounds","isValid","fitBounds","setView","_tileLayer","_geoJsonLayer","on","_qde_leaflet_loading","render3D","Scene","background","Color","PerspectiveCamera","WebGLRenderer","antialias","setSize","domElement","geometry","parseSTL","material","MeshLambertMaterial","mesh","Mesh","ambientLight","AmbientLight","directionalLight","DirectionalLight","set","normalize","box","Box3","setFromObject","center","getCenter","Vector3","getSize","maxDim","z","lookAt","animate","requestAnimationFrame","rotation","_qde_three_loading","stlData","BufferGeometry","vertices","normals","currentNormal","parts","Float32BufferAttribute","namesToLoad","Set","pf","n","isArray","entry","promises","lib","p","tasks","loadScript","loadCSS","_syncHljsTheme","scriptUrl","cssUrl","link","isDark","light","dark","disabled","_autoThemeListener","removeEventListener","mq","setTheme","getTheme","setLazyLinefeeds","enabled","getLazyLinefeeds","setDebounceDelay","delay","getDebounceDelay","wasDark","previousMode","onModeChange","splice","canUndo","previous","canRedo","next","clearHistory","copy","copyRendered","removeHR","convertLazyLinefeeds","writeText","originalText","getMarkdown","getHTML","cleaned","removeHRFromMarkdown","inFence","fo","prevLine","nextLine","converted","inputLines","items","rawLine","kind","category","prev","inSameBlock","item","destroy"],"mappings":"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"}