document.body.addEventListener('htmx:responseError', (event) => { const target = event.detail.target; if (target) { target.innerHTML = '
요청 처리 중 오류가 발생했습니다.
'; } }); function escapeHtml(value) { return value .replaceAll('&', '&') .replaceAll('<', '<') .replaceAll('>', '>') .replaceAll('"', '"') .replaceAll("'", '''); } function renderInlineMarkdown(value) { return escapeHtml(value) .replace(/\*\*([^*]+)\*\*/g, '$1') .replace(/`([^`]+)`/g, '$1'); } function isMarkdownTable(lines, index) { if (index + 1 >= lines.length) { return false; } return lines[index].trim().startsWith('|') && lines[index + 1].trim().startsWith('|') && /^\|?\s*:?-{3,}:?\s*(\|\s*:?-{3,}:?\s*)+\|?$/.test(lines[index + 1].trim()); } function splitMarkdownTableRow(line) { return line.trim() .replace(/^\|/, '') .replace(/\|$/, '') .split('|') .map((cell) => cell.trim()); } function renderMarkdownTable(lines, start) { const headers = splitMarkdownTableRow(lines[start]); let cursor = start + 2; const rows = []; while (cursor < lines.length && lines[cursor].trim().startsWith('|')) { rows.push(splitMarkdownTableRow(lines[cursor])); cursor += 1; } const headerHtml = headers.map((cell) => `${renderInlineMarkdown(cell)}`).join(''); const bodyHtml = rows.map((row) => { const cells = headers.map((_, index) => `${renderInlineMarkdown(row[index] || '')}`).join(''); return `${cells}`; }).join(''); return { html: `${headerHtml}${bodyHtml}
`, next: cursor }; } function renderMarkdownText(markdown) { const lines = markdown.replace(/\r\n/g, '\n').split('\n'); const html = []; let listType = null; const closeList = () => { if (listType) { html.push(``); listType = null; } }; for (let i = 0; i < lines.length; i += 1) { const line = lines[i]; const trimmed = line.trim(); if (!trimmed) { closeList(); continue; } if (isMarkdownTable(lines, i)) { closeList(); const table = renderMarkdownTable(lines, i); html.push(table.html); i = table.next - 1; continue; } const heading = trimmed.match(/^(#{2,4})\s+(.+)$/); if (heading) { closeList(); const level = Math.min(heading[1].length, 3); html.push(`${renderInlineMarkdown(heading[2])}`); continue; } const unordered = trimmed.match(/^[-*]\s+(.+)$/); if (unordered) { if (listType !== 'ul') { closeList(); listType = 'ul'; html.push('