Move verse selector to htmx
This commit is contained in:
1 parent
dd0021ce15
commit
ba3b588ac5
9 files changed
+394
-135
No files matched your search
@@ -45,6 +45,7 @@ from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import html
|
||||
import json
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
@@ -777,6 +778,91 @@ def render_index(books, translation, out_dir):
|
||||
return path
|
||||
|
||||
|
||||
# ==========================================================================
|
||||
# WRITING -- the reference map
|
||||
# ==========================================================================
|
||||
|
||||
# bible/verses.json: every book's chapters, and every chapter's verse labels.
|
||||
#
|
||||
# The navbar's reference picker is built from this, by the service worker. It
|
||||
# used to be built in the browser by reading the book already on the page --
|
||||
# the chapters were the sections and a chapter's verses were the anchors inside
|
||||
# it -- which was free but only worked where there was a document to read. A
|
||||
# worker has no DOM, and the picker now lives in a shell the worker composes
|
||||
# before any document exists, so what the picker needs has to be a fact on
|
||||
# disk rather than something recovered from markup.
|
||||
#
|
||||
# Written here, from the same tree the fragments are rendered from, so the two
|
||||
# cannot disagree: every option this file produces names an anchor render_book
|
||||
# wrote, because both come from the same verse nodes.
|
||||
#
|
||||
# The encoding is compact on purpose. A chapter whose verses run 1..n is
|
||||
# written as the number n; only the eight in the corpus with a gap or a range
|
||||
# -- Sirach 26 ends "19-27", 28, 29 -- spell their labels out:
|
||||
#
|
||||
# {"GEN": [31, 25, 24, ...], "SIR": [..., ["1", ..., "19-27", "28", "29"]]}
|
||||
#
|
||||
# That is 6 KB for 38,000 verses against 180 KB of spelled-out labels, which is
|
||||
# the difference between a file the worker can parse every time it wakes and
|
||||
# one it would have to find somewhere to keep.
|
||||
#
|
||||
# Chapter numbers are not in the file at all: they are the array index plus
|
||||
# one. render_verses checks that, rather than assuming it.
|
||||
|
||||
VERSES_FILE = "verses.json"
|
||||
|
||||
|
||||
def chapter_verses(chapter):
|
||||
"""The verse labels of one chapter, in document order.
|
||||
|
||||
Blocks only. Footnotes hang inside the chapter section too, but a note's
|
||||
content never carries a verse node -- and if one ever did, it would be a
|
||||
citation rather than a place in the text.
|
||||
"""
|
||||
labels = []
|
||||
|
||||
def walk(nodes):
|
||||
for node in nodes:
|
||||
if node["t"] == "verse":
|
||||
labels.append(node["label"])
|
||||
elif "c" in node:
|
||||
walk(node["c"])
|
||||
|
||||
for block in chapter["blocks"]:
|
||||
walk(block.get("content", []))
|
||||
return labels
|
||||
|
||||
|
||||
def render_verses(books, out_dir):
|
||||
"""Write the reference map. Returns its path and the verses in it.
|
||||
|
||||
See the note above for the encoding.
|
||||
"""
|
||||
out = {}
|
||||
total = 0
|
||||
for book in books:
|
||||
numbers = [c["number"] for c in book["chapters"]]
|
||||
if numbers != list(range(1, len(numbers) + 1)):
|
||||
# The map addresses chapters by position, so a book that skips or
|
||||
# repeats one would silently mislabel every option after the gap.
|
||||
# Better to stop the build than to ship a picker that lies.
|
||||
raise RuntimeError("%s: chapters are not 1..%d (%s)"
|
||||
% (book["code"], len(numbers), numbers))
|
||||
chapters = []
|
||||
for chapter in book["chapters"]:
|
||||
labels = chapter_verses(chapter)
|
||||
plain = [str(i + 1) for i in range(len(labels))]
|
||||
chapters.append(len(labels) if labels == plain else labels)
|
||||
total += len(labels)
|
||||
out[book["code"]] = chapters
|
||||
|
||||
path = os.path.join(out_dir, VERSES_FILE)
|
||||
with open(path, "w", encoding="utf-8") as fh:
|
||||
json.dump(out, fh, separators=(",", ":"), ensure_ascii=False)
|
||||
fh.write("\n")
|
||||
return path, total
|
||||
|
||||
|
||||
# ==========================================================================
|
||||
# Entry point
|
||||
# ==========================================================================
|
||||
@@ -797,6 +883,7 @@ def main(argv=None):
|
||||
for book in data["books"]:
|
||||
total += os.path.getsize(render_book(book, data["translation"], args.out))
|
||||
render_index(data["books"], data["translation"], args.out)
|
||||
verses, count = render_verses(data["books"], args.out)
|
||||
|
||||
chapters = sum(len(b["chapters"]) for b in data["books"])
|
||||
notes = sum(len(c["notes"]) for b in data["books"] for c in b["chapters"])
|
||||
@@ -807,6 +894,9 @@ def main(argv=None):
|
||||
print("skipped %d (contents pages)" % len(skipped), file=sys.stderr)
|
||||
print("html %.1f MB total, %.0f KB average"
|
||||
% (total / 1e6, total / len(data["books"]) / 1e3), file=sys.stderr)
|
||||
print("verses %d in %s (%.1f KB)"
|
||||
% (count, os.path.basename(verses), os.path.getsize(verses) / 1e3),
|
||||
file=sys.stderr)
|
||||
print("wrote %s/" % args.out.rstrip("/"), file=sys.stderr)
|
||||
return 0
|
||||
|
||||
|
||||
Reference in new issue
Block a user