78 lines
2.6 KiB
JavaScript
78 lines
2.6 KiB
JavaScript
|
|
/**
|
||
|
|
* Simple Markdown Parser for Tinker Tickets
|
||
|
|
* Supports basic markdown formatting without external dependencies
|
||
|
|
*/
|
||
|
|
|
||
|
|
function parseMarkdown(markdown) {
|
||
|
|
if (!markdown) return '';
|
||
|
|
|
||
|
|
let html = markdown;
|
||
|
|
|
||
|
|
// Escape HTML first to prevent XSS
|
||
|
|
html = html.replace(/&/g, '&')
|
||
|
|
.replace(/</g, '<')
|
||
|
|
.replace(/>/g, '>');
|
||
|
|
|
||
|
|
// Code blocks (```code```)
|
||
|
|
html = html.replace(/```([\s\S]*?)```/g, '<pre class="code-block"><code>$1</code></pre>');
|
||
|
|
|
||
|
|
// Inline code (`code`)
|
||
|
|
html = html.replace(/`([^`]+)`/g, '<code class="inline-code">$1</code>');
|
||
|
|
|
||
|
|
// Bold (**text** or __text__)
|
||
|
|
html = html.replace(/\*\*(.+?)\*\*/g, '<strong>$1</strong>');
|
||
|
|
html = html.replace(/__(.+?)__/g, '<strong>$1</strong>');
|
||
|
|
|
||
|
|
// Italic (*text* or _text_)
|
||
|
|
html = html.replace(/\*(.+?)\*/g, '<em>$1</em>');
|
||
|
|
html = html.replace(/_(.+?)_/g, '<em>$1</em>');
|
||
|
|
|
||
|
|
// Links [text](url)
|
||
|
|
html = html.replace(/\[([^\]]+)\]\(([^)]+)\)/g, '<a href="$2" target="_blank" rel="noopener noreferrer">$1</a>');
|
||
|
|
|
||
|
|
// Headers (# H1, ## H2, etc.)
|
||
|
|
html = html.replace(/^### (.+)$/gm, '<h3>$1</h3>');
|
||
|
|
html = html.replace(/^## (.+)$/gm, '<h2>$1</h2>');
|
||
|
|
html = html.replace(/^# (.+)$/gm, '<h1>$1</h1>');
|
||
|
|
|
||
|
|
// Lists
|
||
|
|
// Unordered lists (- item or * item)
|
||
|
|
html = html.replace(/^\s*[-*]\s+(.+)$/gm, '<li>$1</li>');
|
||
|
|
html = html.replace(/(<li>.*<\/li>)/s, '<ul>$1</ul>');
|
||
|
|
|
||
|
|
// Ordered lists (1. item)
|
||
|
|
html = html.replace(/^\s*\d+\.\s+(.+)$/gm, '<li>$1</li>');
|
||
|
|
|
||
|
|
// Blockquotes (> text)
|
||
|
|
html = html.replace(/^>\s+(.+)$/gm, '<blockquote>$1</blockquote>');
|
||
|
|
|
||
|
|
// Horizontal rules (--- or ***)
|
||
|
|
html = html.replace(/^(?:---|___|\*\*\*)$/gm, '<hr>');
|
||
|
|
|
||
|
|
// Line breaks (two spaces at end of line or double newline)
|
||
|
|
html = html.replace(/ \n/g, '<br>');
|
||
|
|
html = html.replace(/\n\n/g, '</p><p>');
|
||
|
|
|
||
|
|
// Wrap in paragraph if not already wrapped
|
||
|
|
if (!html.startsWith('<')) {
|
||
|
|
html = '<p>' + html + '</p>';
|
||
|
|
}
|
||
|
|
|
||
|
|
return html;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Apply markdown rendering to all elements with data-markdown attribute
|
||
|
|
function renderMarkdownElements() {
|
||
|
|
document.querySelectorAll('[data-markdown]').forEach(element => {
|
||
|
|
const markdownText = element.getAttribute('data-markdown') || element.textContent;
|
||
|
|
element.innerHTML = parseMarkdown(markdownText);
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
// Apply markdown to description and comments on page load
|
||
|
|
document.addEventListener('DOMContentLoaded', renderMarkdownElements);
|
||
|
|
|
||
|
|
// Expose for manual use
|
||
|
|
window.parseMarkdown = parseMarkdown;
|
||
|
|
window.renderMarkdownElements = renderMarkdownElements;
|