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