fix: Seitenmarken aus Kastentiteln vor den Kasten setzen; <mark> dokumentiert
- Marken im Kastentitel landen über marker_sink vor dem Kasten (wie bei
Überschriften) statt im fetten Titel ("**\[S. 62\]Wozu …**")
- Doku: --no-css-emphasis lässt <mark> bestehen, das steuert --styles
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
20494742a3
commit
6e3d05fef1
5 changed files with 41 additions and 9 deletions
|
|
@ -510,7 +510,7 @@ python3 epub2md_merge.py --help
|
||||||
| `--boxes callout/quote/html/plain` | Darstellung von Infokästen |
|
| `--boxes callout/quote/html/plain` | Darstellung von Infokästen |
|
||||||
| `--styles semantic/html` | Farben, Schriften, Größen, Ausrichtung und Sprache als HTML übernehmen (`html`) |
|
| `--styles semantic/html` | Farben, Schriften, Größen, Ausrichtung und Sprache als HTML übernehmen (`html`) |
|
||||||
| `--page-markers none/visible/comment` | Seitenzahlen der Druckausgabe als `[S. 123]` oder `<!-- S. 123 -->` |
|
| `--page-markers none/visible/comment` | Seitenzahlen der Druckausgabe als `[S. 123]` oder `<!-- S. 123 -->` |
|
||||||
| `--no-css-emphasis` | Hervorhebungen nur aus HTML-Tags übernehmen, nicht aus dem Stylesheet des Buches |
|
| `--no-css-emphasis` | Hervorhebungen nur aus HTML-Tags übernehmen, nicht aus dem Stylesheet des Buches (farbige Markierungen `<mark>` bleiben, sie gehören zu `--styles`) |
|
||||||
| `--math auto/tex/mathml/image` | Formeldarstellung |
|
| `--math auto/tex/mathml/image` | Formeldarstellung |
|
||||||
| `--footnotes end-of-chapter/end-of-book/inline/keep-links` | Fußnoten-Platzierung |
|
| `--footnotes end-of-chapter/end-of-book/inline/keep-links` | Fußnoten-Platzierung |
|
||||||
| `--format gfm/commonmark` | Markdown-Variante; `commonmark` für sehr strikte Programme |
|
| `--format gfm/commonmark` | Markdown-Variante; `commonmark` für sehr strikte Programme |
|
||||||
|
|
|
||||||
12
CHANGELOG.md
12
CHANGELOG.md
|
|
@ -3,6 +3,17 @@
|
||||||
Alle nennenswerten Änderungen an epub2md. Format nach [Keep a Changelog](https://keepachangelog.com/de/1.1.0/),
|
Alle nennenswerten Änderungen an epub2md. Format nach [Keep a Changelog](https://keepachangelog.com/de/1.1.0/),
|
||||||
Versionsnummern nach [Semantic Versioning](https://semver.org/lang/de/).
|
Versionsnummern nach [Semantic Versioning](https://semver.org/lang/de/).
|
||||||
|
|
||||||
|
## [Unveröffentlicht]
|
||||||
|
|
||||||
|
### Geändert
|
||||||
|
|
||||||
|
- Seitenmarken (`--page-markers`) aus einem Kastentitel stehen jetzt vor dem Kasten statt im fetten Titel,
|
||||||
|
wie bei Überschriften.
|
||||||
|
|
||||||
|
### Dokumentation
|
||||||
|
|
||||||
|
- `--no-css-emphasis` lässt `<mark>`-Markierungen bestehen; diese steuert `--styles`.
|
||||||
|
|
||||||
## [0.2.0] – 2026-10-06
|
## [0.2.0] – 2026-10-06
|
||||||
|
|
||||||
Schwerpunkt: Typografie und Gestaltung des Buches im Markdown abbilden.
|
Schwerpunkt: Typografie und Gestaltung des Buches im Markdown abbilden.
|
||||||
|
|
@ -49,5 +60,6 @@ Erste Fassung.
|
||||||
- Alle Befunde der QA-Prüfungen (R1–R7, QA2-01 bis QA2-19) behoben oder abgemildert.
|
- Alle Befunde der QA-Prüfungen (R1–R7, QA2-01 bis QA2-19) behoben oder abgemildert.
|
||||||
- README und Bedienungsanleitung.
|
- README und Bedienungsanleitung.
|
||||||
|
|
||||||
|
[Unveröffentlicht]: https://kitux.de/forgejo/dschlueter/epub2md/compare/v0.2.0...main
|
||||||
[0.2.0]: https://kitux.de/forgejo/dschlueter/epub2md/compare/v0.1.0...v0.2.0
|
[0.2.0]: https://kitux.de/forgejo/dschlueter/epub2md/compare/v0.1.0...v0.2.0
|
||||||
[0.1.0]: https://kitux.de/forgejo/dschlueter/epub2md/src/tag/v0.1.0
|
[0.1.0]: https://kitux.de/forgejo/dschlueter/epub2md/src/tag/v0.1.0
|
||||||
|
|
|
||||||
|
|
@ -100,7 +100,7 @@ python3 epub2md.py buch.epub output/buch --force --report berichte/buch.json
|
||||||
| `--boxes {callout,quote,html,plain}` | `callout` | Infokästen (Tipp, Hinweis, Warnung, Exkurs, Merke …): `callout` = `> [!TIP]` mit fettem Titel (GitHub-Alerts, Obsidian-Callouts; anderswo ein Zitatblock), `quote` = Zitatblock mit fettem Titel, `html` = `<div class="box box-tip">`, `plain` = normaler Text wie bisher |
|
| `--boxes {callout,quote,html,plain}` | `callout` | Infokästen (Tipp, Hinweis, Warnung, Exkurs, Merke …): `callout` = `> [!TIP]` mit fettem Titel (GitHub-Alerts, Obsidian-Callouts; anderswo ein Zitatblock), `quote` = Zitatblock mit fettem Titel, `html` = `<div class="box box-tip">`, `plain` = normaler Text wie bisher |
|
||||||
| `--styles {semantic,html}` | `semantic` | `semantic`: nur bedeutungstragende Gestaltung (Hintergrundmarkierung → `<mark>`). `html`: zusätzlich Farbe, Hintergrund, Schriftgröße, Schriftart, Kapitälchen, Ausrichtung als `<span style>`/`<div style>` und fremdsprachige Passagen als `<span lang>`, jeweils nur, wo sie vom normalen Text des Buches abweichen. Obsidian, VS Code und Pandoc (HTML/PDF/EPUB) zeigen das an, GitHub nicht |
|
| `--styles {semantic,html}` | `semantic` | `semantic`: nur bedeutungstragende Gestaltung (Hintergrundmarkierung → `<mark>`). `html`: zusätzlich Farbe, Hintergrund, Schriftgröße, Schriftart, Kapitälchen, Ausrichtung als `<span style>`/`<div style>` und fremdsprachige Passagen als `<span lang>`, jeweils nur, wo sie vom normalen Text des Buches abweichen. Obsidian, VS Code und Pandoc (HTML/PDF/EPUB) zeigen das an, GitHub nicht |
|
||||||
| `--page-markers {none,visible,comment}` | `none` | Seitenzahlen der Druckausgabe an der Stelle des Seitenwechsels: `visible` = `\[S. 123\]` im Text (zum Zitieren), `comment` = `<!-- S. 123 -->` (unsichtbar, aber durchsuchbar), `none` = weglassen |
|
| `--page-markers {none,visible,comment}` | `none` | Seitenzahlen der Druckausgabe an der Stelle des Seitenwechsels: `visible` = `\[S. 123\]` im Text (zum Zitieren), `comment` = `<!-- S. 123 -->` (unsichtbar, aber durchsuchbar), `none` = weglassen |
|
||||||
| `--css-emphasis` / `--no-css-emphasis` | an | Fett, kursiv, unterstrichen, durchgestrichen, hoch-/tiefgestellt auch übernehmen, wenn das Buch sie nur per CSS-Klasse setzt (z. B. `span.italic`). Einzelwörter in Monospace-Schrift werden zu Inline-Code; per CSS ausgeblendete Elemente (`display:none`) entfallen. Statistik im Bericht unter `css` |
|
| `--css-emphasis` / `--no-css-emphasis` | an | Fett, kursiv, unterstrichen, durchgestrichen, hoch-/tiefgestellt auch übernehmen, wenn das Buch sie nur per CSS-Klasse setzt (z. B. `span.italic`). Einzelwörter in Monospace-Schrift werden zu Inline-Code; per CSS ausgeblendete Elemente (`display:none`) entfallen. Statistik im Bericht unter `css`. Hintergrundmarkierungen (`<mark>`) und Stile steuert unabhängig davon `--styles` |
|
||||||
| `--keep-invisible-chars` | aus | Nullbreiten-Zeichen und weiche Trennstriche im Fließtext behalten. Standard: entfernen, weil sie Suche und RAG stören (Anzahl im Bericht: `text_cleanup`). Code bleibt immer unverändert |
|
| `--keep-invisible-chars` | aus | Nullbreiten-Zeichen und weiche Trennstriche im Fließtext behalten. Standard: entfernen, weil sie Suche und RAG stören (Anzahl im Bericht: `text_cleanup`). Code bleibt immer unverändert |
|
||||||
| `--keep-html` | aus | Unbekannte/nicht sicher konvertierbare Elemente als bereinigtes HTML erhalten (sonst: Text übernommen + Eintrag in `diagnostics/unsupported-elements.md`) |
|
| `--keep-html` | aus | Unbekannte/nicht sicher konvertierbare Elemente als bereinigtes HTML erhalten (sonst: Text übernommen + Eintrag in `diagnostics/unsupported-elements.md`) |
|
||||||
| `--strict` | aus | Abbruch bei kritischen Fehlern (fehlende/unlesbare Spine-Dokumente, unsichere ZIP-Pfade, ungültige Spine-Verweise) |
|
| `--strict` | aus | Abbruch bei kritischen Fehlern (fehlende/unlesbare Spine-Dokumente, unsichere ZIP-Pfade, ungültige Spine-Verweise) |
|
||||||
|
|
|
||||||
|
|
@ -303,6 +303,7 @@ class Renderer:
|
||||||
self.css = stylesheet
|
self.css = stylesheet
|
||||||
self.scene_breaks = 0
|
self.scene_breaks = 0
|
||||||
self.page_markers = 0
|
self.page_markers = 0
|
||||||
|
self.marker_sink: list[str] | None = None # collects page markers instead of emitting them inline
|
||||||
self.poems = 0
|
self.poems = 0
|
||||||
self.boxes = 0
|
self.boxes = 0
|
||||||
self.in_box = False
|
self.in_box = False
|
||||||
|
|
@ -417,7 +418,11 @@ class Renderer:
|
||||||
return ""
|
return ""
|
||||||
self.page_markers += 1
|
self.page_markers += 1
|
||||||
page = html.escape(page, quote=False).replace("--", "")
|
page = html.escape(page, quote=False).replace("--", "")
|
||||||
return f"<!-- S. {page} -->" if self.opt.page_markers == "comment" else f"\\[S. {md_escape(page)}\\]"
|
marker = f"<!-- S. {page} -->" if self.opt.page_markers == "comment" else f"\\[S. {md_escape(page)}\\]"
|
||||||
|
if self.marker_sink is not None:
|
||||||
|
self.marker_sink.append(marker)
|
||||||
|
return ""
|
||||||
|
return marker
|
||||||
|
|
||||||
def anchors_of(self, el: Any, subtree: bool = False) -> str:
|
def anchors_of(self, el: Any, subtree: bool = False) -> str:
|
||||||
nodes = iter_elements(el) if subtree else [el]
|
nodes = iter_elements(el) if subtree else [el]
|
||||||
|
|
@ -622,13 +627,18 @@ class Renderer:
|
||||||
break
|
break
|
||||||
title_el = self._box_title(members)
|
title_el = self._box_title(members)
|
||||||
title = ""
|
title = ""
|
||||||
|
markers: list[str] = [] # page breaks in the title go before the box, like for headings
|
||||||
if title_el is not None:
|
if title_el is not None:
|
||||||
pieces: list[Piece] = [("t", self._text(title_el.text))] if title_el.text else []
|
pieces: list[Piece] = [("t", self._text(title_el.text))] if title_el.text else []
|
||||||
for child in title_el:
|
self.marker_sink = markers
|
||||||
if is_element(child) and not self._title_symbol(child):
|
try:
|
||||||
pieces.extend(self.inline(child))
|
for child in title_el:
|
||||||
if child.tail:
|
if is_element(child) and not self._title_symbol(child):
|
||||||
pieces.append(("t", self._text(child.tail)))
|
pieces.extend(self.inline(child))
|
||||||
|
if child.tail:
|
||||||
|
pieces.append(("t", self._text(child.tail)))
|
||||||
|
finally:
|
||||||
|
self.marker_sink = None
|
||||||
title = join_inline(pieces, hard_break=" ").strip()
|
title = join_inline(pieces, hard_break=" ").strip()
|
||||||
kind = kind or _box_type(norm_ws(text_content(title_el)))
|
kind = kind or _box_type(norm_ws(text_content(title_el)))
|
||||||
saved = self.in_box
|
saved = self.in_box
|
||||||
|
|
@ -653,7 +663,9 @@ class Renderer:
|
||||||
if title and norm_ws(re.sub(r"[*_\\:]", "", title)).lower() in TYPE_WORDS:
|
if title and norm_ws(re.sub(r"[*_\\:]", "", title)).lower() in TYPE_WORDS:
|
||||||
title = "" # 'Tipp' as title of a TIP box adds nothing
|
title = "" # 'Tipp' as title of a TIP box adds nothing
|
||||||
self.boxes += 1
|
self.boxes += 1
|
||||||
out = [anchor] if anchor else []
|
out = ["".join(markers)] if markers else []
|
||||||
|
if anchor:
|
||||||
|
out.append(anchor)
|
||||||
head = [f"**{title}**"] if title else []
|
head = [f"**{title}**"] if title else []
|
||||||
if self.opt.boxes == "html":
|
if self.opt.boxes == "html":
|
||||||
out.append(f'<div class="box box-{kind}">\n\n' + "\n\n".join(head + blocks) + "\n\n</div>")
|
out.append(f'<div class="box box-{kind}">\n\n' + "\n\n".join(head + blocks) + "\n\n</div>")
|
||||||
|
|
|
||||||
|
|
@ -201,3 +201,11 @@ def test_hidden_span_gets_no_field_separator_and_class_type_wins(convert):
|
||||||
text = convert(Book(docs=[Doc("c.xhtml", body)], media={"s.css": css})).chapter("001")
|
text = convert(Book(docs=[Doc("c.xhtml", body)], media={"s.css": css})).chapter("001")
|
||||||
assert "<u>unterstrichen</u>." in text and "VERSTECKT" not in text
|
assert "<u>unterstrichen</u>." in text and "VERSTECKT" not in text
|
||||||
assert "> [!NOTE]\n> **Wichtige Regel**" in text # class 'hinweis' beats the word in the title
|
assert "> [!NOTE]\n> **Wichtige Regel**" in text # class 'hinweis' beats the word in the title
|
||||||
|
|
||||||
|
|
||||||
|
def test_page_marker_in_box_title_goes_before_the_box(convert):
|
||||||
|
body = ('<h1>K</h1><div class="box"><h3 class="boxheading"><a id="page_62"/>Wozu Deklarationen?</h3>'
|
||||||
|
'<p>Weil es <a id="page_63"/>hilft.</p></div>')
|
||||||
|
text = convert(Book(docs=[Doc("c.xhtml", body)]), "--page-markers", "visible").chapter("001")
|
||||||
|
assert "\\[S. 62\\]\n\n> [!NOTE]\n> **Wozu Deklarationen?**" in text
|
||||||
|
assert "> Weil es \\[S. 63\\]hilft." in text # markers in the box body stay in place
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue