92 lines
3.0 KiB
Python
92 lines
3.0 KiB
Python
# -*- coding: utf-8 -*-
|
|
"""Baut aus content_html und faq eine Elementor-Struktur (_elementor_data).
|
|
|
|
Der Artikel wird an den H2-Grenzen in einzelne Text-Editor-Widgets zerlegt,
|
|
damit er im Builder abschnittsweise bearbeitbar bleibt. Das FAQ wird zu einem
|
|
nested-accordion mit aktiviertem faq_schema, also demselben Widget, das die
|
|
Leistungsseiten von skrift.de bereits verwenden.
|
|
"""
|
|
import json, re, secrets
|
|
|
|
|
|
def eid():
|
|
return secrets.token_hex(4)[:7]
|
|
|
|
|
|
def text_widget(html):
|
|
return {"id": eid(), "elType": "widget", "settings": {"editor": html},
|
|
"elements": [], "widgetType": "text-editor"}
|
|
|
|
|
|
def container(kinder, innen=False):
|
|
s = {"content_width": "full"}
|
|
if innen:
|
|
s.update({"_title": "Element", "padding": {"unit": "px", "top": "8", "right": "8",
|
|
"bottom": "8", "left": "8", "isLinked": True},
|
|
"flex_gap": {"column": "20", "row": "20", "isLinked": True,
|
|
"unit": "px", "size": 20}})
|
|
c = {"id": eid(), "elType": "container", "settings": s, "elements": kinder}
|
|
if innen:
|
|
c["isInner"] = True
|
|
c["isLocked"] = True
|
|
return c
|
|
|
|
|
|
def accordion(faq, titel="Häufige Fragen"):
|
|
"""nested-accordion: settings.items und elements laufen parallel."""
|
|
items, kinder = [], []
|
|
for f in faq:
|
|
if not f.get("frage"):
|
|
continue
|
|
items.append({"item_title": f["frage"], "_id": eid()})
|
|
kinder.append(container([text_widget(f"<p>{f.get('antwort', '')}</p>")], innen=True))
|
|
return {
|
|
"id": eid(), "elType": "widget", "widgetType": "nested-accordion",
|
|
"settings": {"items": items, "faq_schema": "yes", "default_state": "all_collapsed"},
|
|
"elements": kinder,
|
|
}
|
|
|
|
|
|
def teile_an_h2(html):
|
|
"""Zerlegt den Artikel an <h2>, behält alles davor als Einleitung."""
|
|
stellen = [m.start() for m in re.finditer(r'<h2[ >]', html)]
|
|
if not stellen:
|
|
return [html]
|
|
bloecke = []
|
|
if stellen[0] > 0:
|
|
kopf = html[:stellen[0]].strip()
|
|
if kopf:
|
|
bloecke.append(kopf)
|
|
for i, s in enumerate(stellen):
|
|
ende = stellen[i + 1] if i + 1 < len(stellen) else len(html)
|
|
bloecke.append(html[s:ende].strip())
|
|
return [b for b in bloecke if b]
|
|
|
|
|
|
def baue(artikel, faq_ueberschrift="Häufige Fragen"):
|
|
wurzel = []
|
|
|
|
# Kurzantwort als eigener, hervorgehobener Block
|
|
if artikel.get("kurzantwort"):
|
|
wurzel.append(container([text_widget(
|
|
f'<div class="skrift-kurzantwort"><p>{artikel["kurzantwort"]}</p></div>')]))
|
|
|
|
for block in teile_an_h2(artikel.get("content_html", "")):
|
|
wurzel.append(container([text_widget(block)]))
|
|
|
|
faq = artikel.get("faq") or []
|
|
if faq:
|
|
wurzel.append(container([
|
|
text_widget(f"<h2>{faq_ueberschrift}</h2>"),
|
|
accordion(faq),
|
|
]))
|
|
|
|
return wurzel
|
|
|
|
|
|
if __name__ == "__main__":
|
|
import sys
|
|
a = json.load(open(sys.argv[1], encoding="utf-8"))
|
|
baum = baue(a)
|
|
print(json.dumps(baum, ensure_ascii=False))
|