- -- Render content below header in three columns
- local multicol_begin = pandoc.RawBlock('latex', [[
- \begin{multicols}{3}\raggedcolumns
- ]])
- local multicol_end = pandoc.RawBlock('latex', [[
- \end{multicols}
- ]])
- local ad_template = [[
- \begin{minipage}[%s][%s\textheight][c]{\textwidth}
- \centering
- \includegraphics[width=\linewidth,height=%s\textheight,keepaspectratio]{%s}
- \end{minipage}
- ]]
- local function has_class(elem, class)
- local classes = elem.classes
- if not classes then
- return false
- end
- for _, c in ipairs(classes) do
- if c == class then
- return true
- end
- end
- return false
- end
- local function is_columnar_header(elem)
- return elem.t == "Header" and elem.level == 1
- end
- local function is_multicols_begin(elem)
- return elem.t == "RawBlock" and elem.text == "\\begin{multicols}{3}\\raggedcolumns"
- end
- local function is_multicols_end(elem)
- return elem.t == "RawBlock" and elem.text == "\\end{multicols}"
- end
- -- a standalone image with optional caption that has class .wide
- -- TODO: detect pre-quarto-filter pattern too
- local function is_wide(elem)
- return ((elem.t == "Para" and has_class(elem.content[1], "wide"))
- or (elem.t == "Figure" and has_class(elem.content[1].content[1], "wide")))
- end
- -- TODO: detect pre-quarto-filter pattern too
- local function is_newpage_command(elem)
- return (elem.t == "RawBlock" and elem.text == "\\newpage{}")
- or (elem.t == "Para" and #elem.content == 5 and elem.content[3] == "pagebreak")
- end
- -- a paragraph where initial element has class .ad is an advertising
- local function is_advertising(elem)
- if elem.t == "Para" then
- local elem1 = elem.content[1]
- if elem1.t == "Image" and has_class(elem1, "ad") then
- return true
- end
- end
- return false
- end
- -- wrap images with class .ad to span half or full page
- local function ad(elem)
- local amount = #elem.content
- -- 1 ad, spanning full page except with class .top or .bottom
- if amount == 1 then
- local elem1 = elem.content[1]
- if elem1.t ~= "Image" or not elem1.src then
- error("failed to parse advertisement")
- return elem
- end
- if has_class(elem1, "top") then
- return pandoc.RawBlock('latex', "\\noindent\n"
- .. string.format(ad_template, "t", "0.5", "0.5", elem1.src))
- elseif has_class(elem1, "bottom") then
- return pandoc.RawBlock('latex', "\\vspace*{\\fill}\\noindent\n"
- .. string.format(ad_template, "b", "0.5", "0.5", elem1.src))
- end
- return pandoc.RawBlock('latex',"\\noindent\n"
- .. string.format(ad_template, "t", "1", "1", elem1.src))
- end
- -- 2 ads spanning full page
- if amount == 3 then
- local elem1 = elem.content[1]
- local elem2 = elem.content[3]
- if elem1.t ~= "Image" or not elem1.src
- or elem2.t ~= "Image" or not elem2.src
- then
- error("failed to parse 2-element advertisement")
- return elem
- end
- return pandoc.RawBlock('latex', "\\noindent\n"
- .. string.format(ad_template, "t", "0.5", "0.5", elem1.src)
- .. string.format(ad_template, "b", "0.5", "0.5", elem2.src))
- end
- error("failed to parse advertisement, wrong amount of elements: "
- .. amount)
- return elem
- end
- function Pandoc(doc)
- if FORMAT:match 'latex' then
- -- locate topmost-only elements where multicol state should change
- local multicol_now = false
- local multicol_places = {}
- for i, elem in ipairs(doc.blocks) do
- if is_columnar_header(elem) then
- multicol_places[i] = multicol_now and "renew" or "begin"
- multicol_now = true
- elseif is_wide(elem) then
- if multicol_now then
- multicol_places[i] = "renew"
- end
- elseif is_advertising(elem) then
- doc.blocks[i] = ad(elem)
- if multicol_now then
- multicol_places[i] = "renew"
- end
- elseif is_newpage_command(elem) then
- if multicol_now then
- multicol_places[i] = "end"
- multicol_now = false
- end
- elseif elem.t == "HorizontalRule" then
- if multicol_now then
- multicol_places[i] = "end"
- multicol_now = false
- end
- elseif is_multicols_begin(elem) then
- multicol_now = true
- elseif is_multicols_end(elem) then
- multicol_now = false
- end
- end
- if multicol_now then
- multicol_places[#doc.blocks] = "end"
- end
- -- apply multicol, in reverse order since it shifts later indices
- for i = #doc.blocks, 1, -1 do
- local state = multicol_places[i]
- if state ~= nil then
- if state == "begin" then
- doc.blocks:insert(i + 1, multicol_begin)
- elseif state == "renew" then
- doc.blocks:insert(i + 1, multicol_begin)
- doc.blocks:insert(i, multicol_end)
- elseif state == "end" then
- doc.blocks:insert(i, multicol_end)
- end
- end
- end
- if #multicol_places >= 1 then
- return doc
- end
- end
- end
|