--[[ 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:
after the cover, only if the book has no title page of its own
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 into
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 --
as Pandoc's HTML template writes it. local function title_block(meta) local html = { '
', '

' .. esc(pandoc.utils.stringify(meta.title)) .. "

" } if meta.subtitle then html[#html + 1] = '

' .. esc(pandoc.utils.stringify(meta.subtitle)) .. "

" 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] = '

' .. esc(pandoc.utils.stringify(a)) .. "

" end if meta.date then html[#html + 1] = '

' .. esc(pandoc.utils.stringify(meta.date)) .. "

" end html[#html + 1] = "
" return pandoc.RawBlock("html", table.concat(html, "\n")) end -- Paragraph that only holds chapter start anchors () → 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('^$') or inl.text:match('^$') if found then id = id or found elseif inl.text ~= "" 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