140 lines
5.4 KiB
Lua
140 lines
5.4 KiB
Lua
|
|
--[[
|
|||
|
|
book.lua – Pandoc filter for book files from epub2md_merge.py (HTML output, e.g. PDF via weasyprint).
|
|||
|
|
|
|||
|
|
Pandoc's --toc always puts the table of contents (and its own title block) before the whole text,
|
|||
|
|
i.e. before the book's cover, title page and imprint. epub2md_merge.py marks the right places:
|
|||
|
|
|
|||
|
|
<div id="epub2md-titlepage"></div> after the cover, only if the book has no title page of its own
|
|||
|
|
<div id="epub2md-toc"></div> after the front matter (cover, title page, imprint …)
|
|||
|
|
|
|||
|
|
This filter, for HTML output:
|
|||
|
|
* builds the table of contents at the placeholder (use it INSTEAD of --toc; --toc-depth is honoured),
|
|||
|
|
* drops Pandoc's title block when the book has its own title page, or moves it to the placeholder,
|
|||
|
|
* shows the cover picture (chapter "NNN-cover") without the caption "Cover",
|
|||
|
|
* turns the chapter anchors <a id="001-…"></a> into <div class="chapter-start"> so that print.css can
|
|||
|
|
start every chapter – including cover, title page and imprint – on a new page.
|
|||
|
|
|
|||
|
|
For other formats it only removes the placeholders (EPUB, DOCX, ODT: use --toc there).
|
|||
|
|
|
|||
|
|
Usage:
|
|||
|
|
pandoc buch.md -s --lua-filter /pfad/zu/epub2md/pandoc/book.lua \
|
|||
|
|
--lua-filter /pfad/zu/epub2md/pandoc/callouts.lua --css /pfad/zu/epub2md/pandoc/print.css \
|
|||
|
|
--pdf-engine=weasyprint -o buch.pdf
|
|||
|
|
]]
|
|||
|
|
|
|||
|
|
local TOC_ID, TITLE_ID = "epub2md-toc", "epub2md-titlepage"
|
|||
|
|
local TOC_TITLE = { de = "Inhaltsverzeichnis", en = "Contents" }
|
|||
|
|
|
|||
|
|
local function is_placeholder(block, id)
|
|||
|
|
return block.t == "Div" and block.identifier == id and #block.content == 0
|
|||
|
|
end
|
|||
|
|
|
|||
|
|
local function esc(s)
|
|||
|
|
return (s:gsub("&", "&"):gsub("<", "<"):gsub(">", ">"))
|
|||
|
|
end
|
|||
|
|
|
|||
|
|
-- <header id="title-block-header"> as Pandoc's HTML template writes it.
|
|||
|
|
local function title_block(meta)
|
|||
|
|
local html = { '<header id="title-block-header">', '<h1 class="title">' .. esc(pandoc.utils.stringify(meta.title)) .. "</h1>" }
|
|||
|
|
if meta.subtitle then
|
|||
|
|
html[#html + 1] = '<p class="subtitle">' .. esc(pandoc.utils.stringify(meta.subtitle)) .. "</p>"
|
|||
|
|
end
|
|||
|
|
local authors = meta.author
|
|||
|
|
if authors and pandoc.utils.type(authors) ~= "List" then
|
|||
|
|
authors = { authors }
|
|||
|
|
end
|
|||
|
|
for _, a in ipairs(authors or {}) do
|
|||
|
|
html[#html + 1] = '<p class="author">' .. esc(pandoc.utils.stringify(a)) .. "</p>"
|
|||
|
|
end
|
|||
|
|
if meta.date then
|
|||
|
|
html[#html + 1] = '<p class="date">' .. esc(pandoc.utils.stringify(meta.date)) .. "</p>"
|
|||
|
|
end
|
|||
|
|
html[#html + 1] = "</header>"
|
|||
|
|
return pandoc.RawBlock("html", table.concat(html, "\n"))
|
|||
|
|
end
|
|||
|
|
|
|||
|
|
-- Paragraph that only holds chapter start anchors (<a id="001-cover"></a>) → id of the first one.
|
|||
|
|
local function chapter_anchor(block)
|
|||
|
|
if block.t ~= "Para" and block.t ~= "Plain" then
|
|||
|
|
return nil
|
|||
|
|
end
|
|||
|
|
local id = nil
|
|||
|
|
for _, inl in ipairs(block.content) do
|
|||
|
|
if inl.t ~= "RawInline" then
|
|||
|
|
return nil
|
|||
|
|
end
|
|||
|
|
local found = inl.text:match('^<a id="(%d%d%d%-[^"]*)">$') or inl.text:match('^<a id="(%d%d%d%-[^"]*)"></a>$')
|
|||
|
|
if found then
|
|||
|
|
id = id or found
|
|||
|
|
elseif inl.text ~= "</a>" then
|
|||
|
|
return nil
|
|||
|
|
end
|
|||
|
|
end
|
|||
|
|
return id
|
|||
|
|
end
|
|||
|
|
|
|||
|
|
function Pandoc(doc)
|
|||
|
|
local html = FORMAT:match("html") and not FORMAT:match("epub")
|
|||
|
|
local toc_at, title_at = nil, nil
|
|||
|
|
for i, block in ipairs(doc.blocks) do
|
|||
|
|
if is_placeholder(block, TOC_ID) then
|
|||
|
|
toc_at = i
|
|||
|
|
elseif is_placeholder(block, TITLE_ID) then
|
|||
|
|
title_at = i
|
|||
|
|
end
|
|||
|
|
end
|
|||
|
|
if not toc_at and not title_at then
|
|||
|
|
return nil -- not a file from epub2md_merge.py
|
|||
|
|
end
|
|||
|
|
if not html then -- placeholders are top-level blocks: just drop them
|
|||
|
|
local kept = pandoc.Blocks({})
|
|||
|
|
for _, block in ipairs(doc.blocks) do
|
|||
|
|
if not is_placeholder(block, TOC_ID) and not is_placeholder(block, TITLE_ID) then
|
|||
|
|
kept:insert(block)
|
|||
|
|
end
|
|||
|
|
end
|
|||
|
|
doc.blocks = kept
|
|||
|
|
return doc
|
|||
|
|
end
|
|||
|
|
|
|||
|
|
local blocks = pandoc.Blocks({})
|
|||
|
|
for i, block in ipairs(doc.blocks) do
|
|||
|
|
local anchor = chapter_anchor(block)
|
|||
|
|
if i == toc_at then
|
|||
|
|
if PANDOC_WRITER_OPTIONS.table_of_contents then
|
|||
|
|
-- --toc given as well: Pandoc's own table of contents stays at the top, no second one
|
|||
|
|
else
|
|||
|
|
local lang = doc.meta.lang and pandoc.utils.stringify(doc.meta.lang):sub(1, 2):lower() or "de"
|
|||
|
|
local toc = pandoc.structure.table_of_contents(doc.blocks, PANDOC_WRITER_OPTIONS)
|
|||
|
|
blocks:insert(pandoc.Div({
|
|||
|
|
pandoc.Header(1, TOC_TITLE[lang] or TOC_TITLE.de, pandoc.Attr("toc-title", { "unnumbered", "unlisted" })),
|
|||
|
|
toc,
|
|||
|
|
}, pandoc.Attr("TOC", { "toc" })))
|
|||
|
|
end
|
|||
|
|
elseif i == title_at then
|
|||
|
|
if doc.meta.title then
|
|||
|
|
blocks:insert(title_block(doc.meta))
|
|||
|
|
end
|
|||
|
|
elseif anchor then
|
|||
|
|
blocks:insert(pandoc.Div({}, pandoc.Attr(anchor, { "chapter-start" })))
|
|||
|
|
local nxt = doc.blocks[i + 1]
|
|||
|
|
if anchor:match("^%d%d%d%-cover") and nxt and nxt.t == "Figure" then
|
|||
|
|
-- cover chapter: the picture without the caption "Cover", centred on its own page
|
|||
|
|
local imgs = {}
|
|||
|
|
nxt:walk({ Image = function(img) imgs[#imgs + 1] = img end })
|
|||
|
|
if #imgs == 1 then
|
|||
|
|
doc.blocks[i + 1] = pandoc.Div({ pandoc.Plain({ imgs[1] }) }, pandoc.Attr("", { "cover" }))
|
|||
|
|
end
|
|||
|
|
end
|
|||
|
|
else
|
|||
|
|
blocks:insert(block)
|
|||
|
|
end
|
|||
|
|
end
|
|||
|
|
doc.blocks = blocks
|
|||
|
|
-- The book's own title page (or the moved block) replaces Pandoc's title block at the very top.
|
|||
|
|
if doc.meta.title then
|
|||
|
|
doc.meta.pagetitle = doc.meta.pagetitle or pandoc.utils.stringify(doc.meta.title)
|
|||
|
|
doc.meta.title = nil
|
|||
|
|
end
|
|||
|
|
return doc
|
|||
|
|
end
|