This commit is contained in:
mark committed 2026-10-21 14:09:22 -04:00
1 parent 6edc542ea5
commit 04ea39607d
6 files changed
+158 -10

No files matched your search

+52 -3
View File
@@ -453,11 +453,51 @@ def ref_href(node, book, chapter):
return "%s#%s" % (base, verse_id(target_ch, verse))
return "%s#ch%d" % (base, target_ch)
DROPCAP_BLOCKS = ("paragraph", "line", "item")
def with_dropcap(nodes):
"""Split the first letter of the first text off into a dropcap node.
Returns the new node list, or None when the text does not start with a
letter. The initials font has only A-Z and a-z, so a chapter opening on
a quotation mark or a digit gets no drop cap rather than a fallback one.
"""
nodes = list(nodes)
for i, node in enumerate(nodes):
kind = node["t"]
if kind == "verse":
continue
# A note caller would land between the letter and the rest of its word.
if kind == "noteref":
return None
if kind == "text":
text = node["v"].lstrip()
if not text:
continue
if not ("A" <= text[0] <= "Z" or "a" <= text[0] <= "z"):
return None
nodes[i:i + 1] = [{"t": "dropcap", "v": text[0]},
dict(node, v=text[1:])]
else:
inner = with_dropcap(node.get("c", []))
if inner is None:
return None
nodes[i] = dict(node, c=inner)
# The verse number before the drop cap would otherwise sit between
# the floated letter and the rest of its word.
for j in range(i):
if nodes[j]["t"] == "verse":
nodes[j] = dict(nodes[j], dropcap=True)
return nodes
return None
def render_inline(nodes, book, chapter, out):
for node in nodes:
kind = node["t"]
if kind == "text":
out.append(esc(node["v"]))
elif kind == "dropcap":
out.append('<span class="dropcap">%s</span>' % esc(node["v"]))
elif kind == "verse":
label = esc(node["label"])
vid = verse_id(chapter, node["label"])
@@ -466,10 +506,13 @@ def render_inline(nodes, book, chapter, out):
# that dialog. Being a real link is also what gives it the
# keyboard and context menu a reader expects.
out.append('<a class="v" id="%s" href="#%s" '
# A non-breaking space keeps the number on the same
# line as the word it introduces, as the source does.
'aria-label="Verse %s, options">%s</a>&#160;'
'aria-label="Verse %s, options">%s</a>'
% (vid, vid, label, label))
# A non-breaking space keeps the number on the same line as the
# word it introduces, as the source does. Before a drop cap the
# number is hidden and the space would only push the word away.
if not node.get("dropcap"):
out.append("&#160;")
elif kind == "noteref":
n = node["id"].replace("FN", "")
out.append('<a class="noteref" id="fnref%s_%s" href="#fn%s_%s">'
@@ -550,8 +593,14 @@ def render_chapter(chapter, book, out):
out.append(" </ul>\n")
group = None
dropcap = True
for block in chapter["blocks"]:
btype = block["type"]
if dropcap and btype in DROPCAP_BLOCKS:
dropcap = False
content = with_dropcap(block.get("content", []))
if content is not None:
block = dict(block, content=content)
if btype == "break":
close_group()
continue