summaryrefslogtreecommitdiff
path: root/_extensions/js/multicol-nohead/multicol-nohead.lua
blob: 85e0dd8e9cb93abbac607dcc57aaa5ef2bdd0367 (plain)
  1. -- Render content below header in three columns
  2. local multicol_begin = pandoc.RawBlock('latex', [[
  3. \begin{multicols}{3}\raggedcolumns
  4. ]])
  5. local multicol_end = pandoc.RawBlock('latex', [[
  6. \end{multicols}
  7. ]])
  8. local ad_template = [[
  9. \begin{minipage}[%s][%s\textheight][c]{\textwidth}
  10. \centering
  11. \includegraphics[width=\linewidth,height=%s\textheight,keepaspectratio]{%s}
  12. \end{minipage}
  13. ]]
  14. local function has_class(elem, class)
  15. local classes = elem.classes
  16. if not classes then
  17. return false
  18. end
  19. for _, c in ipairs(classes) do
  20. if c == class then
  21. return true
  22. end
  23. end
  24. return false
  25. end
  26. local function is_columnar_header(elem)
  27. return elem.t == "Header" and elem.level == 1
  28. end
  29. -- TODO: detect pre-quarto-filter pattern too
  30. local function is_newpage_command(elem)
  31. return (elem.t == "RawBlock" and elem.text == "\\newpage{}")
  32. or (elem.t == "Para" and #elem.content == 5 and elem.content[3] == "pagebreak")
  33. end
  34. -- a paragraph where initial element has class .ad is an advertising
  35. local function is_advertising(elem)
  36. if elem.t == "Para" then
  37. local elem1 = elem.content[1]
  38. if elem1.t == "Image" and has_class(elem1, "ad") then
  39. return true
  40. end
  41. end
  42. return false
  43. end
  44. -- wrap images with class .ad to span half or full page
  45. local function ad(elem)
  46. local amount = #elem.content
  47. -- 1 ad, spanning full page except with class .top or .bottom
  48. if amount == 1 then
  49. local elem1 = elem.content[1]
  50. if elem1.t ~= "Image" or not elem1.src then
  51. error("failed to parse advertisement")
  52. return elem
  53. end
  54. if has_class(elem1, "top") then
  55. return pandoc.RawBlock('latex', "\\noindent\n"
  56. .. string.format(ad_template, "t", "0.5", "0.5", elem1.src))
  57. elseif has_class(elem1, "bottom") then
  58. return pandoc.RawBlock('latex', "\\vspace*{\\fill}\\noindent\n"
  59. .. string.format(ad_template, "b", "0.5", "0.5", elem1.src))
  60. end
  61. return pandoc.RawBlock('latex',"\\noindent\n"
  62. .. string.format(ad_template, "t", "1", "1", elem1.src))
  63. end
  64. -- 2 ads spanning full page
  65. if amount == 3 then
  66. local elem1 = elem.content[1]
  67. local elem2 = elem.content[3]
  68. if elem1.t ~= "Image" or not elem1.src
  69. or elem2.t ~= "Image" or not elem2.src
  70. then
  71. error("failed to parse 2-element advertisement")
  72. return elem
  73. end
  74. return pandoc.RawBlock('latex', "\\noindent\n"
  75. .. string.format(ad_template, "t", "0.5", "0.5", elem1.src)
  76. .. string.format(ad_template, "b", "0.5", "0.5", elem2.src))
  77. end
  78. error("failed to parse advertisement, wrong amount of elements: "
  79. .. amount)
  80. return elem
  81. end
  82. function Pandoc(doc)
  83. if FORMAT:match 'latex' then
  84. -- locate topmost-only elements where multicol state should change
  85. local multicol_now = false
  86. local multicol_places = {}
  87. for i, elem in ipairs(doc.blocks) do
  88. if is_columnar_header(elem) then
  89. multicol_places[i] = multicol_now and "renew" or "begin"
  90. multicol_now = true
  91. elseif is_advertising(elem) then
  92. doc.blocks[i] = ad(elem)
  93. if multicol_now then
  94. multicol_places[i] = "renew"
  95. end
  96. elseif is_newpage_command(elem) then
  97. if multicol_now then
  98. multicol_places[i] = "end"
  99. multicol_now = false
  100. end
  101. elseif elem.t == "HorizontalRule" then
  102. if multicol_now then
  103. multicol_places[i] = "end"
  104. multicol_now = false
  105. end
  106. end
  107. end
  108. if multicol_now then
  109. multicol_places[#doc.blocks] = "end"
  110. end
  111. -- apply multicol, in reverse order since it shifts later indices
  112. for i = #doc.blocks, 1, -1 do
  113. local state = multicol_places[i]
  114. if state ~= nil then
  115. if state == "begin" then
  116. doc.blocks:insert(i + 1, multicol_begin)
  117. elseif state == "renew" then
  118. doc.blocks:insert(i + 1, multicol_begin)
  119. doc.blocks:insert(i, multicol_end)
  120. elseif state == "end" then
  121. doc.blocks:insert(i, multicol_end)
  122. end
  123. end
  124. end
  125. if #multicol_places >= 1 then
  126. return doc
  127. end
  128. end
  129. end