mirror of
https://git.cmoser.eu/tinytools/django-tinywiki.git
synced 2026-02-04 06:06:33 +01:00
2025.09.17-19:07:57
This commit is contained in:
4
tinywiki/parser/__init__.py
Normal file
4
tinywiki/parser/__init__.py
Normal file
@@ -0,0 +1,4 @@
|
||||
from .bbcode import PARSER as BBCODE_PARSER
|
||||
|
||||
def parse_bbcode(text:str):
|
||||
return BBCODE_PARSER.format(text)
|
||||
28
tinywiki/parser/bbcode/__init__.py
Normal file
28
tinywiki/parser/bbcode/__init__.py
Normal file
@@ -0,0 +1,28 @@
|
||||
import bbcode
|
||||
from . import formatters
|
||||
PARSER = bbcode.Parser(newline="\n",escape_html=True)
|
||||
|
||||
def _():
|
||||
for i in formatters.SIMPLE_FORMATTERS:
|
||||
if len(i) == 0:
|
||||
continue
|
||||
|
||||
if len(i) == 1:
|
||||
kwargs = {}
|
||||
else:
|
||||
kwargs = i[1]
|
||||
PARSER.add_simple_formatter(*i[0],**kwargs)
|
||||
|
||||
for i in formatters.FORMATTERS:
|
||||
if len(i) == 0:
|
||||
continue
|
||||
|
||||
if len(i) == 1:
|
||||
kwargs = {}
|
||||
else:
|
||||
kwargs = i[1]
|
||||
|
||||
PARSER.add_formatter(*i[0],**kwargs)
|
||||
|
||||
_()
|
||||
del _
|
||||
35
tinywiki/parser/bbcode/formatters.py
Normal file
35
tinywiki/parser/bbcode/formatters.py
Normal file
@@ -0,0 +1,35 @@
|
||||
|
||||
from .text_formatters import (
|
||||
render_codeblock,
|
||||
render_url,
|
||||
render_list_item,
|
||||
render_ordered_list,
|
||||
render_unordered_list,
|
||||
render_paragraph,
|
||||
render_image,
|
||||
render_wiki_image,
|
||||
render_wiki_link,
|
||||
render_wiki_url,
|
||||
)
|
||||
from .simple_formatters import (
|
||||
SIMPLE_HEADER_FORMATTERS,
|
||||
)
|
||||
|
||||
# a list of tuples containig an tuple args and a dict of kwargs
|
||||
SIMPLE_FORMATTERS=[
|
||||
*SIMPLE_HEADER_FORMATTERS,
|
||||
]
|
||||
|
||||
#a list of tuples containing an tuple of args and a dict of kwargs
|
||||
FORMATTERS=[
|
||||
(('url',render_url),{'strip':True,'swallow_trailing_newline':True,'same_tag_closes':True}),
|
||||
(('wiki-url',render_wiki_url),{'strip':True,'swallow_trailing_newline':True,'same_tag_closes':True}),
|
||||
(('wiki',render_wiki_link),{'strip':True,'swallow_tailin_newline':True,'standalone':True}),
|
||||
(('codeblock',render_codeblock),{'strip':False,'swallow_trailing_newline':False,'same_tag_closes':True}),
|
||||
(('ol',render_ordered_list),{}),
|
||||
(('ul',render_unordered_list),{}),
|
||||
(('li',render_list_item),{}),
|
||||
(('p',render_paragraph),{}),
|
||||
(('image',render_image),{}),
|
||||
(('wiki-image',render_wiki_image),{'standalone':True})
|
||||
]
|
||||
12
tinywiki/parser/bbcode/simple_formatters.py
Normal file
12
tinywiki/parser/bbcode/simple_formatters.py
Normal file
@@ -0,0 +1,12 @@
|
||||
|
||||
SIMPLE_HEADER_FORMATTERS = [
|
||||
(('h1',"<h1>%(value)s</h1>"),{}),
|
||||
(('h2',"<h2>%(value)s</h2>"),{}),
|
||||
(('h3',"<h3>%(value)s</h3>"),{}),
|
||||
(('h4',"<h4>%(value)s</h4>"),{}),
|
||||
(('h5',"<h5>%(value)s</h5>"),{}),
|
||||
(('h6',"<h6>%(value)s</h6>"),{}),
|
||||
(('copy',"©"),{'standalone':True}),
|
||||
(('reg',"®"),{'standalone':True}),
|
||||
(('trade',"™"),{'standalone':True}),
|
||||
]
|
||||
221
tinywiki/parser/bbcode/text_formatters.py
Normal file
221
tinywiki/parser/bbcode/text_formatters.py
Normal file
@@ -0,0 +1,221 @@
|
||||
from django_project.settings import STATIC_URL
|
||||
from django.urls import reverse
|
||||
from django.template.loader import render_to_string
|
||||
from django.utils.translation import gettext as _
|
||||
from ... import settings
|
||||
from ... import models
|
||||
|
||||
|
||||
def render_url(tag_name:str,value,options,parent,context):
|
||||
try:
|
||||
url = options['url']
|
||||
except KeyError:
|
||||
url = value
|
||||
|
||||
if '://' not in url:
|
||||
url = "http://" + url
|
||||
|
||||
if settings.USE_BOOTSTRAP:
|
||||
return f"<a href=\"{url}\" class=\"icon-link icon-link-hover\" referrer-policy=\"no-referrer\" rel=\"noreferrer noopener\">{value}{render_to_string('tinywiki/icons/box-arrow-up-right.svg')}</a>"
|
||||
return f"<a href=\"{url}\" referrer-policy=\"no-referrer\" rel=\"noreferrer noopener\">{value}</a>"
|
||||
|
||||
def render_wiki_url(tag_name,value,options,parent,context):
|
||||
if tag_name in options:
|
||||
url = reverse("tinywiki:page",kwargs={'slug':options[tag_name]})
|
||||
slug=options['tag_name']
|
||||
try:
|
||||
page = models.Page.objects.get(slug=slug)
|
||||
except models.Page.DoesNotExist:
|
||||
page = None
|
||||
|
||||
else:
|
||||
url = reverse('tinywiki:home')
|
||||
slug=None
|
||||
|
||||
if settings.USE_BOOTSTRAP:
|
||||
if page:
|
||||
if page.slug.startswith('tw-'):
|
||||
svg=render_to_string('tinywiki/icons/journal.svg')
|
||||
elif page.slug:
|
||||
svg=render_to_string('tinywiki/icons/book.svg')
|
||||
else:
|
||||
svg=render_to_string('tinywiki/icons/file-earmark-x')
|
||||
|
||||
return f"<a href=\"{url}\" class=\"icon-link icon-link-hover\">{value}{svg}</a>"
|
||||
return f"<a href=\"{url}\">{value}</a>"
|
||||
|
||||
|
||||
def render_wiki_link(tag_name,value,options,parent,context):
|
||||
if tag_name in options:
|
||||
slug = options['tag_name']
|
||||
try:
|
||||
page = models.Page.objects.get(slug=slug)
|
||||
title = page.title
|
||||
if slug.starts_with('tw-'):
|
||||
svg = "tinywiki/icons/journal.svg"
|
||||
else:
|
||||
svg = "tinywiki/icons/book.svg"
|
||||
except:
|
||||
page = None
|
||||
title = _("Page not found")
|
||||
svg_template = "tinywiki/icons/file-earmark-x.svg"
|
||||
url = reverse("tinywiki:page",kwargs={'slug':slug})
|
||||
else:
|
||||
slug = None
|
||||
title = _("Home")
|
||||
url = reverse("tinywiki:home")
|
||||
svg_template = "tinywiki/icons/house.svg"
|
||||
|
||||
if settings.USE_BOOTSTRAP:
|
||||
return f"<a href=\"{url}\" class=\"icon-link icon-link-hover\">{value}{render_to_string(svg_template)}</a>"
|
||||
return f"<a href=\"{url}\">{value}</a>"
|
||||
|
||||
def render_codeblock(tag_name:str,value,options,parent,context)->str:
|
||||
if 'codeblock' in options:
|
||||
return f"<pre><code class=\"language-{options['codeblock']}\">{value}</pre></code>"
|
||||
return f"<pre><code>{value}</pre></code>"
|
||||
|
||||
def render_ordered_list(tag_name:str,value,options,parent,context)->str:
|
||||
return f"<ol>{value}</ol>"
|
||||
|
||||
def render_unordered_list(tag_name:str,value,options,parent,context)->str:
|
||||
return f"<ul>{value}</ul>"
|
||||
|
||||
def render_list_item(tag_name:str,value,options,parent,context)->str:
|
||||
return f"<li>{value}</li>"
|
||||
|
||||
|
||||
def render_paragraph(tag_name:str,value,options,parent,context):
|
||||
if settings.USE_BOOTSTRAP:
|
||||
return f"<p style=\"text-align:justify;\">{value}</p>"
|
||||
return f"<p>{value}</p>"
|
||||
|
||||
def render_image(tag_name:str,value,options,parent,context):
|
||||
if tag_name not in options:
|
||||
return ""
|
||||
|
||||
if 'alt' in options:
|
||||
alt=options['alt']
|
||||
else:
|
||||
alt=""
|
||||
|
||||
if settings.USE_BOOTSTRAP:
|
||||
classes=["img-fluid","figure-img","rounded"]
|
||||
fig_classes=["figure","my-1"]
|
||||
styles=[]
|
||||
fig_styles=[]
|
||||
else:
|
||||
styles=["max-width:100%;"]
|
||||
classes=[]
|
||||
fig_classes=[]
|
||||
fig_styles=[]
|
||||
|
||||
if 'width' in options:
|
||||
_w = options['width']
|
||||
if _w.endswith('px'):
|
||||
fig_styles.append(f"width:{_w};")
|
||||
else:
|
||||
if _w.endswith('%'):
|
||||
_w = _w[:-1]
|
||||
if _w.isdigit():
|
||||
_w=int(_w)
|
||||
if _w > 100:
|
||||
_w = 100
|
||||
if settings.USE_BOOTSTRAP:
|
||||
if 1 < int(_w) <= 25:
|
||||
width = 25
|
||||
else:
|
||||
width = ((_w // 25) * 25)
|
||||
fig_classes.append(f'w-{width}')
|
||||
else:
|
||||
fig_styles.append(f"width:{_w}%;")
|
||||
|
||||
if "position" in options:
|
||||
pos = options['position']
|
||||
if settings.USE_BOOTSTRAP:
|
||||
if pos == "left" or pos=="start":
|
||||
fig_classes += ["float-start","me-2"]
|
||||
elif pos == "right" or pos == "end":
|
||||
fig_classes += ["float-end","ms-2"]
|
||||
elif pos == "center":
|
||||
fig_classes += ["mx-auto","d-block"]
|
||||
|
||||
if styles:
|
||||
style=f"style=\"{"".join(styles)}\""
|
||||
else:
|
||||
style=""
|
||||
|
||||
if fig_styles:
|
||||
fig_style=f'style="{"".join(fig_styles)}"'
|
||||
else:
|
||||
fig_style=""
|
||||
if settings.USE_BOOTSTRAP:
|
||||
return f'<figure class="{" ".join(fig_classes)} {fig_style}"><img src="{options[tag_name]}" class="{' '.join(classes)}" alt="{alt}" {style}><figcaption class="figure-caption text-end">{value}</figcaption></figure>'
|
||||
else:
|
||||
return f'<figure {fig_style}><img src="{options[tag_name]}" {style}><figcaption>{value}</figcaption></figure>'
|
||||
|
||||
def render_wiki_image(tag_name:str,value,options,parent,context):
|
||||
if tag_name not in options:
|
||||
return ""
|
||||
|
||||
try:
|
||||
image = models.Image.objects.get(slug=options[tag_name])
|
||||
except models.Image.DoesNotExist:
|
||||
return ""
|
||||
|
||||
if settings.USE_BOOTSTRAP:
|
||||
classes=["img-fluid","figure-img","rounded"]
|
||||
fig_classes=["figure","my-1"]
|
||||
styles=[]
|
||||
fig_styles=[]
|
||||
else:
|
||||
styles=["max-width:100%;"]
|
||||
classes=[]
|
||||
fig_classes=[]
|
||||
fig_styles=[]
|
||||
|
||||
if 'width' in options:
|
||||
_w = options['width']
|
||||
if _w.endswith('px'):
|
||||
fig_styles.append(f"width:{_w};")
|
||||
else:
|
||||
if _w.endswith('%'):
|
||||
_w = _w[:-1]
|
||||
if _w.isdigit():
|
||||
_w=int(_w)
|
||||
if _w > 100:
|
||||
_w = 100
|
||||
if settings.USE_BOOTSTRAP:
|
||||
if 1 < int(_w) <= 25:
|
||||
width = 25
|
||||
else:
|
||||
width = ((_w // 25) * 25)
|
||||
fig_classes.append(f'w-{width}')
|
||||
else:
|
||||
fig_styles.append(f"width:{_w}%;")
|
||||
|
||||
if "position" in options:
|
||||
pos = options['position']
|
||||
if settings.USE_BOOTSTRAP:
|
||||
if pos == "left" or pos=="start":
|
||||
fig_classes += ["float-start","me-2"]
|
||||
elif pos == "right" or pos == "end":
|
||||
fig_classes += ["float-end","ms-2"]
|
||||
elif pos == "center":
|
||||
fig_classes += ["mx-auto","d-block"]
|
||||
|
||||
if styles:
|
||||
style=f"style=\"{"".join(styles)}\""
|
||||
else:
|
||||
style=""
|
||||
|
||||
if fig_styles:
|
||||
fig_style=f'style="{"".join(fig_styles)}"'
|
||||
else:
|
||||
fig_style=""
|
||||
|
||||
if settings.USE_BOOTSTRAP:
|
||||
return f'<figure class="{" ".join(fig_classes)}" {fig_style}><img src="{image.image.url}" alt="{image.alt}" class="{' '.join(classes)}" {style}><figcaption class="figure-caption text-end">{image.description}</figcaption></figure>'
|
||||
else:
|
||||
return f'<figure {fig_style}><img src="{image.image.url}" alt="{image.alt}" {style}><figcaption>{image.description}</figcaption></figure>'
|
||||
|
||||
Reference in New Issue
Block a user