Remove unused lt.markdown module (#43)
lt.markdown was confirmed dead code app-wide (zero callers outside
base.js itself — markdown.js's parseMarkdown() is what's actually
wired up everywhere). The issue flagged its link handler as lacking a
URL-protocol allowlist unlike markdown.js's equivalent; checking the
current code, that link handler already restricts to http(s)/relative/
hash URLs (blocking javascript:/data: URIs) — the allowlist claim
didn't match what's actually there. Since the module is unused either
way, and its own doc comment invites exactly the kind of future
misuse the issue warned about ("For full GFM, swap in marked.js"),
deleted it outright rather than hardening dead code, removing the
landmine permanently instead of leaving an unused copy that could
still drift out of sync with markdown.js in some other way later.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Lhz7pGMaoTfL5sdYS5XiKv
This commit is contained in:
@@ -2930,73 +2930,6 @@
|
||||
},
|
||||
};
|
||||
|
||||
/* ================================================================
|
||||
MODULE 54 — MARKDOWN RENDERER
|
||||
lt.markdown.render(mdString) → HTML string (sanitized)
|
||||
lt.markdown.init(selector) → renders all matching el's .textContent
|
||||
Uses a built-in micro-renderer (no deps) for common syntax.
|
||||
For full GFM, swap in marked.js: window.marked && marked.parse()
|
||||
================================================================ */
|
||||
const markdown = {
|
||||
render(md) {
|
||||
// Always use the built-in XSS-safe micro-renderer. Do NOT delegate to
|
||||
// window.marked / window.markdownit: their raw HTML output is not sanitized
|
||||
// here, so delegating would enable stored XSS if such a lib were ever loaded.
|
||||
// Micro-renderer: covers headings, bold, italic, code, links, lists, blockquote, hr
|
||||
let html = escHtml(md)
|
||||
// Fenced code blocks
|
||||
.replace(/```(\w*)\n([\s\S]*?)```/g, (_, lang, code) => `<pre class="lt-code-block"><code class="lt-tok tok-${lang || 'plain'}">${code.trim()}</code></pre>`)
|
||||
// Inline code
|
||||
.replace(/`([^`]+)`/g, '<code>$1</code>')
|
||||
// Headings
|
||||
.replace(/^######\s(.+)$/gm, '<h6>$1</h6>')
|
||||
.replace(/^#####\s(.+)$/gm, '<h5>$1</h5>')
|
||||
.replace(/^####\s(.+)$/gm, '<h4>$1</h4>')
|
||||
.replace(/^###\s(.+)$/gm, '<h3>$1</h3>')
|
||||
.replace(/^##\s(.+)$/gm, '<h2>$1</h2>')
|
||||
.replace(/^#\s(.+)$/gm, '<h1>$1</h1>')
|
||||
// Bold / italic
|
||||
.replace(/\*\*\*(.+?)\*\*\*/g, '<strong><em>$1</em></strong>')
|
||||
.replace(/\*\*(.+?)\*\*/g, '<strong>$1</strong>')
|
||||
.replace(/\*(.+?)\*/g, '<em>$1</em>')
|
||||
.replace(/__(.+?)__/g, '<strong>$1</strong>')
|
||||
.replace(/_(.+?)_/g, '<em>$1</em>')
|
||||
// Links — block javascript: and data: URIs
|
||||
.replace(/\[([^\]]+)\]\(([^)]+)\)/g, (_, text, url) => {
|
||||
const safeUrl = /^(https?:\/\/|\/|#|\.\.?\/)/i.test(url) ? url : '#';
|
||||
return `<a href="${safeUrl}" target="_blank" rel="noopener noreferrer">${escHtml(text)}</a>`;
|
||||
})
|
||||
// Images — block javascript: and data: URIs
|
||||
.replace(/!\[([^\]]*)\]\(([^)]+)\)/g, (_, alt, src) => {
|
||||
const safeSrc = /^(https?:\/\/|\/|\.\.?\/)/i.test(src) ? src : '';
|
||||
return `<img src="${safeSrc}" alt="${escHtml(alt)}" style="max-width:100%">`;
|
||||
})
|
||||
// Blockquote
|
||||
.replace(/^>\s(.+)$/gm, '<blockquote>$1</blockquote>')
|
||||
// Horizontal rule
|
||||
.replace(/^(-{3,}|\*{3,}|_{3,})$/gm, '<hr>')
|
||||
// Unordered list items
|
||||
.replace(/^[-*+]\s(.+)$/gm, '<li>$1</li>')
|
||||
.replace(/(<li>[\s\S]+?<\/li>\n?)+/g, m => `<ul>${m}</ul>`)
|
||||
// Ordered list items
|
||||
.replace(/^\d+\.\s(.+)$/gm, '<li>$1</li>')
|
||||
// Paragraphs (double newline)
|
||||
.replace(/\n{2,}/g, '</p><p>')
|
||||
.replace(/\n/g, '<br>');
|
||||
return `<p>${html}</p>`
|
||||
.replace(/<p>(<(?:pre|ul|ol|h[1-6]|blockquote|hr)[^>]*>)/g, '$1')
|
||||
.replace(/(<\/(?:pre|ul|ol|h[1-6]|blockquote|hr)>)<\/p>/g, '$1');
|
||||
},
|
||||
|
||||
init(selector) {
|
||||
document.querySelectorAll(selector).forEach(el => {
|
||||
const raw = el.getAttribute('data-markdown') || el.textContent;
|
||||
el.innerHTML = markdown.render(raw);
|
||||
el.classList.add('lt-markdown');
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
/* ================================================================
|
||||
MODULE 55 — PAGINATION
|
||||
lt.pagination.init(navEl, opts)
|
||||
@@ -3159,7 +3092,6 @@
|
||||
timer,
|
||||
lightbox,
|
||||
auth,
|
||||
markdown,
|
||||
ticketStatus,
|
||||
pagination,
|
||||
sidebarSubmenus: { init: initSidebarSubmenus },
|
||||
|
||||
Reference in New Issue
Block a user