feature: render invisible anchor for index

This commit is contained in:
Matthias Jung
2026-04-06 22:17:14 +02:00
parent 5ca687b8d6
commit f6d43fe158
2 changed files with 55 additions and 7 deletions
+25 -2
View File
@@ -1,3 +1,5 @@
import re
from jinja2 import Environment, FileSystemLoader
from mistletoe import Document, HtmlRenderer
@@ -90,6 +92,9 @@ class FiftyOhmHtmlRenderer(HtmlRenderer):
# Single unified counter for all figure types (pictures, photos, tables)
self.figure_counter = 0
# Keep track of index ids already emitted in this document.
self.index_anchor_ids = set()
def render_dash(self, token):
return " – "
@@ -335,6 +340,24 @@ class FiftyOhmHtmlRenderer(HtmlRenderer):
def render_formula(self, token):
return f"\n$${token.formula}$$\n"
@staticmethod
def _normalize_index_part(value: str) -> str:
normalized = value.strip().lower()
normalized = re.sub(r"\s+", "_", normalized)
normalized = re.sub(r"[^\w]", "_", normalized)
normalized = re.sub(r"_+", "_", normalized).strip("_")
return normalized or "index"
def render_index(self, token):
# For HTML just ignore the index
return ""
first = self._normalize_index_part(token.first)
if token.second:
second = self._normalize_index_part(token.second)
span_id = f"index_{first}__{second}"
else:
span_id = f"index_{first}"
if span_id in self.index_anchor_ids:
return ""
self.index_anchor_ids.add(span_id)
return f'<span id="{span_id}" class="index-anchor" aria-hidden="true"></span>'
+30 -5
View File
@@ -9,11 +9,36 @@ from test.util import paragraph
@pytest.mark.html
def test_index_html():
assertions = {
"Im Betrieb werden Yagi-Antennen [index:Antenne:Yagi-Antenne] oft gedreht": "Im Betrieb werden Yagi-Antennen oft gedreht", # noqa: E501
"Im Betrieb werden Yagi-Antennen[index:Antenne:Yagi-Antenne] oft gedreht": "Im Betrieb werden Yagi-Antennen oft gedreht", # noqa: E501
"Im Betrieb werden Yagi-Antennen [index:Antenne] oft gedreht": "Im Betrieb werden Yagi-Antennen oft gedreht",
"Im Betrieb werden Yagi-Antennen[index:Antenne] oft gedreht": "Im Betrieb werden Yagi-Antennen oft gedreht",
"Im Betrieb werden Yagi-Antennen[index:Test Antenne] oft gedreht": "Im Betrieb werden Yagi-Antennen oft gedreht", # noqa: E501
"Im Betrieb werden Yagi-Antennen [index:Antenne:Yagi-Antenne] oft gedreht": (
"Im Betrieb werden Yagi-Antennen"
+ '<span id="index_antenne__yagi_antenne" class="index-anchor" aria-hidden="true"></span>'
+ " oft gedreht"
),
"Im Betrieb werden Yagi-Antennen[index:Antenne:Yagi-Antenne] oft gedreht": (
"Im Betrieb werden Yagi-Antennen"
+ '<span id="index_antenne__yagi_antenne" class="index-anchor" aria-hidden="true"></span>'
+ " oft gedreht"
),
"Im Betrieb werden Yagi-Antennen [index:Antenne] oft gedreht": (
"Im Betrieb werden Yagi-Antennen"
+ '<span id="index_antenne" class="index-anchor" aria-hidden="true"></span>'
+ " oft gedreht"
),
"Im Betrieb werden Yagi-Antennen[index:Antenne] oft gedreht": (
"Im Betrieb werden Yagi-Antennen"
+ '<span id="index_antenne" class="index-anchor" aria-hidden="true"></span>'
+ " oft gedreht"
),
"Im Betrieb werden Yagi-Antennen[index:Test Antenne] oft gedreht": (
"Im Betrieb werden Yagi-Antennen"
+ '<span id="index_test_antenne" class="index-anchor" aria-hidden="true"></span>'
+ " oft gedreht"
),
"Im Betrieb [index:Antenne] und nochmals [index:Antenne] oft gedreht": (
"Im Betrieb"
+ '<span id="index_antenne" class="index-anchor" aria-hidden="true"></span>'
+ " und nochmals oft gedreht"
),
}
for key, value in assertions.items():