diff markdown_converter/markdown_to_html.js @ 64:a30944e5719e

Added vibe coded markdown to html script since it is useful for me. Updated Dowa so that it can be compiled without dirnet for windows.
author June Park <parkjune1995@gmail.com>
date Tue, 23 Dec 2025 15:18:46 -0800
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/markdown_converter/markdown_to_html.js	Tue Dec 23 15:18:46 2025 -0800
@@ -0,0 +1,269 @@
+/**
+ * Simple Markdown to HTML Converter
+ * Supports: headers, bold, italic, links, lists, code blocks, line breaks
+ */
+
+/**
+ * Create heading element (H1-H6)
+ * @param {string} text - The heading text
+ * @param {number} level - Heading level (1-6)
+ * @returns {HTMLElement}
+ */
+function createHeadingElement(text, level) {
+  const h = document.createElement(`H${level}`);
+  const t = document.createTextNode(text.trim());
+  h.appendChild(t);
+  return h;
+}
+
+/**
+ * Create paragraph element
+ * @param {string} text - The paragraph text
+ * @returns {HTMLElement}
+ */
+function createParagraphElement(text) {
+  const p = document.createElement("P");
+  p.innerHTML = processInlineMarkdown(text.trim());
+  return p;
+}
+
+/**
+ * Create link element
+ * @param {string} text - Link text
+ * @param {string} url - Link URL
+ * @returns {HTMLElement}
+ */
+function createLinkElement(text, url) {
+  const a = document.createElement("A");
+  a.href = url;
+  a.textContent = text;
+  return a;
+}
+
+/**
+ * Create unordered list element
+ * @param {Array<string>} items - List items
+ * @returns {HTMLElement}
+ */
+function createUnorderedList(items) {
+  const ul = document.createElement("UL");
+  items.forEach(item => {
+    const li = document.createElement("LI");
+    li.innerHTML = processInlineMarkdown(item.trim());
+    ul.appendChild(li);
+  });
+  return ul;
+}
+
+/**
+ * Create ordered list element
+ * @param {Array<string>} items - List items
+ * @returns {HTMLElement}
+ */
+function createOrderedList(items) {
+  const ol = document.createElement("OL");
+  items.forEach(item => {
+    const li = document.createElement("LI");
+    li.innerHTML = processInlineMarkdown(item.trim());
+    ol.appendChild(li);
+  });
+  return ol;
+}
+
+/**
+ * Create code block element
+ * @param {string} code - Code content
+ * @returns {HTMLElement}
+ */
+function createCodeBlock(code) {
+  const pre = document.createElement("PRE");
+  const codeEl = document.createElement("CODE");
+  codeEl.textContent = code;
+  pre.appendChild(codeEl);
+  return pre;
+}
+
+/**
+ * Create blockquote element
+ * @param {string} text - Quote text
+ * @returns {HTMLElement}
+ */
+function createBlockquote(text) {
+  const blockquote = document.createElement("BLOCKQUOTE");
+  blockquote.innerHTML = processInlineMarkdown(text.trim());
+  return blockquote;
+}
+
+/**
+ * Create horizontal rule
+ * @returns {HTMLElement}
+ */
+function createHorizontalRule() {
+  return document.createElement("HR");
+}
+
+/**
+ * Process inline markdown (bold, italic, code, links)
+ * @param {string} text - Text with inline markdown
+ * @returns {string} HTML string
+ */
+function processInlineMarkdown(text) {
+  // Links: [text](url)
+  text = text.replace(/\[([^\]]+)\]\(([^)]+)\)/g, '<a href="$2">$1</a>');
+  
+  // Images: ![alt](url)
+  text = text.replace(/!\[([^\]]*)\]\(([^)]+)\)/g, '<img src="$2" alt="$1">');
+  
+  // Bold: **text** or __text__
+  text = text.replace(/\*\*([^*]+)\*\*/g, '<strong>$1</strong>');
+  text = text.replace(/__([^_]+)__/g, '<strong>$1</strong>');
+  
+  // Italic: *text* or _text_
+  text = text.replace(/\*([^*]+)\*/g, '<em>$1</em>');
+  text = text.replace(/_([^_]+)_/g, '<em>$1</em>');
+  
+  // Inline code: `code`
+  const x = /`([^`]+)`/g;
+  text = text.replace(x, '<code>$1</code>');
+  
+  // Strikethrough: ~~text~~
+  text = text.replace(/~~([^~]+)~~/g, '<del>$1</del>');
+  
+  // Line breaks: two spaces at end of line
+  text = text.replace(/  \n/g, '<br>\n');
+  
+  return text;
+}
+
+/**
+ * Main markdown converter function
+ * @param {string} value - Markdown string
+ * @returns {Array<HTMLElement>} Array of DOM elements
+ */
+function markdownConverter(value) {
+  const lines = value.split('\n');
+  const domElements = [];
+  let i = 0;
+  
+  while (i < lines.length) {
+    const line = lines[i];
+    const trimmedLine = line.trim();
+    
+    // Skip empty lines
+    if (trimmedLine === '') {
+      i++;
+      continue;
+    }
+    
+    if (trimmedLine.startsWith('#'))
+    {
+      const match = trimmedLine.match(/^(#{1,6})\s+(.+)$/);
+      if (match) {
+        const level = match[1].length;
+        const text = match[2];
+        domElements.push(createHeadingElement(text, level));
+        i++;
+        continue;
+      }
+    }
+    
+    if (trimmedLine.startsWith('```')) {
+      let codeContent = '';
+      i++; // Skip opening ```
+      while (i < lines.length && !lines[i].trim().startsWith('```')) {
+        codeContent += lines[i] + '\n';
+        i++;
+      }
+      domElements.push(createCodeBlock(codeContent));
+      i++; // Skip closing ```
+      continue;
+    }
+    
+    // Blockquote: >
+    if (trimmedLine.startsWith('>')) {
+      let quoteContent = '';
+      while (i < lines.length && lines[i].trim().startsWith('>')) {
+        quoteContent += lines[i].trim().substring(1).trim() + ' ';
+        i++;
+      }
+      domElements.push(createBlockquote(quoteContent));
+      continue;
+    }
+    
+    // Horizontal rule: ---, ***, ___
+    if (trimmedLine.match(/^(-{3,}|\*{3,}|_{3,})$/)) {
+      domElements.push(createHorizontalRule());
+      i++;
+      continue;
+    }
+    
+    // Unordered list: -, *, +
+    if (trimmedLine.match(/^[-*+]\s+/)) {
+      const listItems = [];
+      while (i < lines.length && lines[i].trim().match(/^[-*+]\s+/)) {
+        listItems.push(lines[i].trim().substring(2));
+        i++;
+      }
+      domElements.push(createUnorderedList(listItems));
+      continue;
+    }
+    
+    // Ordered list: 1., 2., etc.
+    if (trimmedLine.match(/^\d+\.\s+/)) {
+      const listItems = [];
+      while (i < lines.length && lines[i].trim().match(/^\d+\.\s+/)) {
+        listItems.push(lines[i].trim().replace(/^\d+\.\s+/, ''));
+        i++;
+      }
+      domElements.push(createOrderedList(listItems));
+      continue;
+    }
+    
+    // Regular paragraph
+    let paragraphContent = '';
+    while (i < lines.length && lines[i].trim() !== '' && 
+           !lines[i].trim().match(/^(#{1,6}\s|[-*+]\s|\d+\.\s|>|```|---|\*\*\*|___)/)) {
+      paragraphContent += lines[i] + ' ';
+      i++;
+    }
+    if (paragraphContent.trim()) {
+      domElements.push(createParagraphElement(paragraphContent));
+    }
+  }
+  
+  return domElements;
+}
+
+/**
+ * Helper function to append all elements to a container
+ * @param {HTMLElement} container - Container element
+ * @param {string} markdown - Markdown string
+ */
+function renderMarkdown(container, markdown) {
+  const elements = markdownConverter(markdown);
+  elements.forEach(el => container.appendChild(el));
+}
+
+// Example usage:
+// const markdown = `
+// # Heading 1
+// ## Heading 2
+// 
+// This is a paragraph with **bold** and *italic* text.
+// 
+// - List item 1
+// - List item 2
+// 
+// 1. Ordered item 1
+// 2. Ordered item 2
+// 
+// [Link text](https://example.com)
+// `;
+// 
+// const container = document.getElementById('content');
+// renderMarkdown(container, markdown);
+
+// Export for use in other files
+if (typeof module !== 'undefined' && module.exports) {
+  module.exports = { markdownConverter, renderMarkdown };
+}