diff --git a/.DS_Store b/.DS_Store
index 65e07fb..d67fa22 100644
Binary files a/.DS_Store and b/.DS_Store differ
diff --git a/cms.py b/cms.py
index d8ecffe..3af7a60 100755
--- a/cms.py
+++ b/cms.py
@@ -37,6 +37,16 @@ FOOTER_PAGE = "footer" # Baustein: wird unter den Inhalt jeder Seite gesetzt
# ---------------------------------------------------------------- markdown
+def inline(s):
+ """Inline-Markdown: bilder, code, fett, kursiv, Links."""
+ s = re.sub(r"`([^`]+)`", r"\1", s)
+ s = re.sub(r"!\[([^\]]*)\]\(([^)]+)\)", r'', s)
+ s = re.sub(r"\*\*([^*]+)\*\*", r"\1", s)
+ s = re.sub(r"\*([^*]+)\*", r"\1", s)
+ s = re.sub(r"\[([^\]]+)\]\(([^)]+)\)", r'\1', s)
+ return s
+
+
def md_to_html(text, headings=None):
"""Minimaler Markdown->HTML-Konverter:
Ueberschriften, **fett**, *kursiv*, `code`, [Links](url),
@@ -44,6 +54,8 @@ def md_to_html(text, headings=None):
Ueberschriften bekommen id-Anker; in headings (Liste) werden
optional (anker, text) aller Ueberschriften gesammelt.
"""
+ # vergessenes Trigger-Wort "image" direkt vor einem Bild nicht mit ausgeben
+ text = re.sub(r"\bimage\s*(?=!\[)", "", text, flags=re.IGNORECASE)
lines = text.replace("\r\n", "\n").split("\n")
out = []
i = 0
@@ -53,13 +65,6 @@ def md_to_html(text, headings=None):
used_ids = {}
sec_stack = [] # offene Sektionen (pro # mehr eine Ebene, eingerueckt)
- def inline(s):
- s = re.sub(r"`([^`]+)`", r"
\1", s)
- s = re.sub(r"\*\*([^*]+)\*\*", r"\1", s)
- s = re.sub(r"\*([^*]+)\*", r"\1", s)
- s = re.sub(r"\[([^\]]+)\]\(([^)]+)\)", r'\1', s)
- return s
-
def close_list():
nonlocal in_list, list_tag
if in_list:
@@ -134,6 +139,24 @@ def md_to_html(text, headings=None):
i += 1
continue
+ # Tabellen: | zelle | zelle | mit --- Trennzeile
+ if stripped.startswith("|"):
+ close_list()
+ rows = []
+ j = i
+ while j < len(lines) and lines[j].strip().startswith("|"):
+ rows.append(lines[j].strip())
+ j += 1
+ tbl = _parse_table(rows)
+ if tbl:
+ out.append(tbl)
+ i = j
+ else:
+ # keine gueltige Tabelle -> als normaler Absatz
+ out.append("
%s
" % inline(_escape(stripped))) + i += 1 + continue + m = re.match(r"^([-*+])\s+(.*)$", stripped) if m: if not in_list or list_tag != "ul": @@ -167,7 +190,7 @@ def md_to_html(text, headings=None): close_list() para = [stripped] while (i + 1 < len(lines) and lines[i + 1].strip() - and not re.match(r"^(#{1,6}\s|[-*+]\s|\d+\.\s|>|```|-{3,}$|<)", + and not re.match(r"^(#{1,6}\s|[-*+]\s|\d+\.\s|>|```|-{3,}$|<|\|)", lines[i + 1].strip())): i += 1 para.append(lines[i].strip()) @@ -185,6 +208,54 @@ def _escape(s): return (s.replace("&", "&").replace("<", "<").replace(">", ">")) +def _parse_table(rows): + """Baut aus |-getrennten Zeilen eine HTML-Tabelle. + Zeile 1: Kopfzeile, Zeile 2: Trenner (---, :---, ---:, :---:), + danach: Datenzeilen. Liefert None, wenn es keine gueltige Tabelle ist. + """ + def split_row(r): + if r.startswith("|"): + r = r[1:] + if r.endswith("|"): + r = r[:-1] + return [c.strip() for c in r.split("|")] + + def is_sep(c): + return re.match(r"^:?-{2,}:?$", c) is not None + + if len(rows) < 2 or not all(is_sep(c) and c for c in split_row(rows[1])): + return None + + aligns = [] + for c in split_row(rows[1]): + left, right = c.startswith(":"), c.endswith(":") + if left and right: + aligns.append("center") + elif right: + aligns.append("right") + else: + aligns.append("left") + + def cell(tag, j, text): + style = ' style="text-align: %s"' % aligns[j] if j < len(aligns) else "" + return "<%s%s>%s%s>" % (tag, style, inline(text), tag) + + out = ["