feat: autolink URLs in list items, link picker, and inline edit
- Add autolink Jinja2 filter to detect URLs and make them clickable - Add link picker dropdown to insert existing link URLs into list item content - Add inline edit with link picker on each list item row - Apply autolink filter on list detail and focus available list items Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
49
core/template_filters.py
Normal file
49
core/template_filters.py
Normal file
@@ -0,0 +1,49 @@
|
||||
"""Jinja2 custom template filters."""
|
||||
|
||||
import re
|
||||
from markupsafe import Markup, escape
|
||||
|
||||
# Match http(s):// URLs and bare www. URLs
|
||||
_URL_RE = re.compile(
|
||||
r'(https?://[^\s<>\"\'\]]+|www\.[^\s<>\"\'\]]+)',
|
||||
re.IGNORECASE,
|
||||
)
|
||||
|
||||
# Trailing punctuation that usually isn't part of the URL
|
||||
_TRAILING_PUNCT = re.compile(r'[.,;:!?\)]+$')
|
||||
|
||||
|
||||
def autolink(text):
|
||||
"""Detect URLs in plain text and wrap them in clickable <a> tags.
|
||||
|
||||
Escapes all content first (XSS-safe), then replaces URL patterns.
|
||||
Returns Markup so Jinja2 won't double-escape.
|
||||
"""
|
||||
if not text:
|
||||
return text
|
||||
|
||||
escaped = str(escape(text))
|
||||
|
||||
def _replace(match):
|
||||
raw = match.group(0)
|
||||
# Strip trailing punctuation that got captured
|
||||
trail = ''
|
||||
m = _TRAILING_PUNCT.search(raw)
|
||||
if m:
|
||||
trail = m.group(0)
|
||||
raw = raw[:m.start()]
|
||||
|
||||
href = raw
|
||||
if raw.lower().startswith('www.'):
|
||||
href = 'https://' + raw
|
||||
|
||||
# Truncate display text for readability
|
||||
display = raw if len(raw) <= 60 else raw[:57] + '...'
|
||||
|
||||
return (
|
||||
f'<a href="{href}" target="_blank" rel="noopener noreferrer" '
|
||||
f'class="autolink">{display}</a>{trail}'
|
||||
)
|
||||
|
||||
result = _URL_RE.sub(_replace, escaped)
|
||||
return Markup(result)
|
||||
Reference in New Issue
Block a user