fix: forum markdown parser - autolinks, line spacing, Windows line endings
Some checks are pending
NordaBiz Tests / Unit & Integration Tests (push) Waiting to run
NordaBiz Tests / E2E Tests (Playwright) (push) Blocked by required conditions
NordaBiz Tests / Smoke Tests (Production) (push) Blocked by required conditions
NordaBiz Tests / Send Failure Notification (push) Blocked by required conditions
Some checks are pending
NordaBiz Tests / Unit & Integration Tests (push) Waiting to run
NordaBiz Tests / E2E Tests (Playwright) (push) Blocked by required conditions
NordaBiz Tests / Smoke Tests (Production) (push) Blocked by required conditions
NordaBiz Tests / Send Failure Notification (push) Blocked by required conditions
- Normalize \r\n to \n before processing - Strip leading whitespace from lines (textarea indentation) - Auto-link bare URLs works correctly inside list items - Smart <br> insertion: skip block elements (ul, li, blockquote, pre) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
53c0d24e2a
commit
7cbd3bb1e7
@ -3,7 +3,7 @@ Simple Markdown Parser for Forum
|
|||||||
================================
|
================================
|
||||||
|
|
||||||
Converts basic markdown to safe HTML.
|
Converts basic markdown to safe HTML.
|
||||||
Supports: bold, italic, code, links, lists, quotes, @mentions
|
Supports: bold, italic, code, links, auto-links, lists, quotes, @mentions
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import re
|
import re
|
||||||
@ -19,6 +19,7 @@ def parse_forum_markdown(text):
|
|||||||
- *italic* or _italic_
|
- *italic* or _italic_
|
||||||
- `inline code`
|
- `inline code`
|
||||||
- [link text](url)
|
- [link text](url)
|
||||||
|
- bare https://... URLs (auto-linked)
|
||||||
- - list items
|
- - list items
|
||||||
- > quotes
|
- > quotes
|
||||||
- @mentions (highlighted)
|
- @mentions (highlighted)
|
||||||
@ -32,6 +33,9 @@ def parse_forum_markdown(text):
|
|||||||
if not text:
|
if not text:
|
||||||
return Markup('')
|
return Markup('')
|
||||||
|
|
||||||
|
# Normalize line endings (Windows \r\n -> \n)
|
||||||
|
text = text.replace('\r\n', '\n').replace('\r', '\n')
|
||||||
|
|
||||||
# Escape HTML first for security
|
# Escape HTML first for security
|
||||||
text = str(escape(text))
|
text = str(escape(text))
|
||||||
|
|
||||||
@ -44,6 +48,17 @@ def parse_forum_markdown(text):
|
|||||||
for line in lines:
|
for line in lines:
|
||||||
stripped = line.strip()
|
stripped = line.strip()
|
||||||
|
|
||||||
|
# Skip empty lines but preserve paragraph spacing
|
||||||
|
if not stripped:
|
||||||
|
if in_list:
|
||||||
|
result_lines.append('</ul>')
|
||||||
|
in_list = False
|
||||||
|
if in_quote:
|
||||||
|
result_lines.append('</blockquote>')
|
||||||
|
in_quote = False
|
||||||
|
result_lines.append('')
|
||||||
|
continue
|
||||||
|
|
||||||
# Quote blocks (> text)
|
# Quote blocks (> text)
|
||||||
if stripped.startswith('> '): # Escaped >
|
if stripped.startswith('> '): # Escaped >
|
||||||
if not in_quote:
|
if not in_quote:
|
||||||
@ -66,7 +81,7 @@ def parse_forum_markdown(text):
|
|||||||
result_lines.append('</ul>')
|
result_lines.append('</ul>')
|
||||||
in_list = False
|
in_list = False
|
||||||
|
|
||||||
result_lines.append(line)
|
result_lines.append(stripped)
|
||||||
|
|
||||||
# Close open blocks
|
# Close open blocks
|
||||||
if in_list:
|
if in_list:
|
||||||
@ -121,11 +136,21 @@ def parse_forum_markdown(text):
|
|||||||
text
|
text
|
||||||
)
|
)
|
||||||
|
|
||||||
# Convert newlines to <br> (but not inside pre/blockquote)
|
# Convert newlines to <br> but skip lines that are HTML block elements
|
||||||
# Simple approach: just convert \n to <br>
|
lines = text.split('\n')
|
||||||
text = text.replace('\n', '<br>\n')
|
output = []
|
||||||
|
for i, line in enumerate(lines):
|
||||||
|
output.append(line)
|
||||||
|
# Don't add <br> after block elements or before them
|
||||||
|
if i < len(lines) - 1:
|
||||||
|
stripped = line.strip()
|
||||||
|
next_stripped = lines[i + 1].strip() if i + 1 < len(lines) else ''
|
||||||
|
is_block = any(stripped.startswith(t) for t in ['<ul', '</ul>', '<li', '</li>', '<blockquote', '</blockquote>', '<pre', '</pre>'])
|
||||||
|
next_is_block = any(next_stripped.startswith(t) for t in ['<ul', '</ul>', '<li', '</li>', '<blockquote', '</blockquote>', '<pre', '</pre>'])
|
||||||
|
if not is_block and not next_is_block:
|
||||||
|
output.append('<br>')
|
||||||
|
|
||||||
return Markup(text)
|
return Markup('\n'.join(output))
|
||||||
|
|
||||||
|
|
||||||
def register_markdown_filter(app):
|
def register_markdown_filter(app):
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user