-- Table to store footnotes, so they can be included at the end. local notes = {} -- Rendering state local in_slide = false local build_slide = false local in_notes = false -- Character escaping local function escape(s, in_attribute) s = s:gsub("[<>&\"']", function(x) if x == '<' then return '<' elseif x == '>' then return '>' elseif x == '&' then return '&' elseif x == '"' then return '"' elseif x == "'" then return ''' else return x end end) return s end -- Helper function to convert an attributes table into -- a string that can be put into HTML tags. local function attributes(attr) local attr_table = {} for x,y in pairs(attr) do if y and y ~= "" then table.insert(attr_table, ' ' .. x .. '="' .. escape(y,true) .. '"') end end return table.concat(attr_table) end -- Blocksep is used to separate block elements. function Blocksep() return "\n\n" end local function CompleteSlide() if (in_slide) then in_slide = false return "" else return "" end end -- This function is called once for the whole document. Parameters: -- body is a string, metadata is a table, variables is a table. -- One could use some kind of templating -- system here; this just gives you a simple standalone HTML file. function Doc(body, metadata, variables) -- complete any active slide local suffix = CompleteSlide() return body .. suffix end -- The functions that follow render corresponding pandoc elements. -- s is always a string, attr is always a table of attributes, and -- items is always an array of strings (the items in a list). -- Comments indicate the types of other variables. function Str(s) s = escape(s) if smart then s = s:gsub("%-%-%-", "—") s = s:gsub("%-%-", "–") s = s:gsub("%.%.%.", "…") end return s end function Space() return " " end function LineBreak() return "
" end function Emph(s) return "" .. s .. "" end function Strong(s) return "" .. s .. "" end function Subscript(s) return "" .. s .. "" end function Superscript(s) return "" .. s .. "" end function SmallCaps(s) return '' .. s .. '' end function Strikeout(s) return '' .. s .. '' end function SingleQuoted(s) if smart then return '‘' .. s .. '’' else return '"' .. s .. '"' end end function DoubleQuoted(s) if smart then return '“' .. s .. '”' else return '"' .. s .. '"' end end function Link(s, src, tit) return "" .. s .. "" end function Image(s, src, tit) return "" end function CaptionedImage(src, tit, s) local caption = "" if fig_caption and (string.len(s) > 0) then caption = "

" .. s .. "

" end return Image(s, src, tit) .. caption end function Code(s, attr) return "" .. escape(s) .. "" end function InlineMath(s) s = escape(s) if mathjax then return "\\(" .. s .. "\\)" else return "$" .. s .. "$" end end function DisplayMath(s) s = escape(s) if mathjax then return "\\[" .. s .. "\\]" else return "$$" .. s .. "$$" end end function Note(s) local num = #notes + 1 -- insert the back reference right before the final closing tag. s = string.gsub(s, '(.*)' .. s .. '') -- return the footnote reference, linked to the note. return '' .. num .. '' end function Span(s, attr) return "" .. s .. "" end function Cite(s) return "" .. s .. "" end function Plain(s) return s end function Para(s) return "

" .. s .. "

" end -- lev is an integer, the header level. function Header(lev, s, attr) -- detect level 1 header and convert it to a segue slide local slide_class = "" local hgroup_class = "" if lev == 1 then slide_class = "segue dark nobackground" hgroup_class = " class = 'auto-fadein'" lev = 2 end -- extract optional subtitle local subtitle = "" if lev == 2 then local i, j = string.find(s, "|") if i then subtitle = string.sub(s, i+1, string.len(s)) s = string.sub(s, 1, i-1) end end -- build slide header (including optional subtitle) local header = "" .. s .. "" if string.len(subtitle) > 0 then header = header .. "

" .. subtitle .. "

" end -- treat level 2 headers as slides if lev == 2 then -- complete previous slide local preface = CompleteSlide() -- start a new slide in_slide = true -- update build flag (used by ol and ul) if attr["class"] and string.find(attr["class"], "build") then build_slide = true else build_slide = false end -- add 'smaller' class if it was globally specified if smaller then attr["class"] = "smaller " .. attr["class"] end -- return the beginning of the slide return preface .. "" .. "" .. header .. "" .. "
" else return header end end function BlockQuote(s) -- if this is a list then blockquote means invert the default -- incremental behavior local prefix = string.sub(s, 1, 3) if prefix == "", prefix .. " class = 'build'>", 1) else s = s:gsub(prefix .. " class = 'build'>", prefix .. ">", 1) end return s else return "
\n" .. s .. "\n
" end end function HorizontalRule() return Header(2, "", {}) end function CodeBlock(s, attr) -- if this code block has a class then add prettyprint to it local class_attrib = '' if attr["class"] then local class = attr["class"] if string.len(class) > 0 then class_attrib = "class = 'prettyprint lang-" .. class .. "'" end end -- substitute for code highlighting/emphasis local code = escape(s) code_sub = code:gsub("[ \t]*[#/]+[ \t]*<b>[ \t]*\n", "") code = code_sub:gsub("[ \t]*[#/]+[ \t]*</b>[ \t]*\n", "") return "
" .. code .. "
" end function BulletList(items) local buffer = {} for _, item in pairs(items) do table.insert(buffer, "
  • " .. item .. "
  • ") end list_class = "" if incremental then list_class = " class = 'build'" end return "\n" .. table.concat(buffer, "\n") .. "\n" end function OrderedList(items) local buffer = {} for _, item in pairs(items) do table.insert(buffer, "
  • " .. item .. "
  • ") end list_class = "" if incremental then list_class = " class = 'build'" end return "\n" .. table.concat(buffer, "\n") .. "\n" end -- Revisit association list STackValue instance. function DefinitionList(items) local buffer = {} for _,item in pairs(items) do for k, v in pairs(item) do table.insert(buffer,"
    " .. k .. "
    \n
    " .. table.concat(v,"
    \n
    ") .. "
    ") end end return "
    \n" .. table.concat(buffer, "\n") .. "\n
    " end -- Convert pandoc alignment to something HTML can use. -- align is AlignLeft, AlignRight, AlignCenter, or AlignDefault. function html_align(align) if align == 'AlignLeft' then return 'left' elseif align == 'AlignRight' then return 'right' elseif align == 'AlignCenter' then return 'center' else return 'left' end end -- Caption is a string, aligns is an array of strings, -- widths is an array of floats, headers is an array of -- strings, rows is an array of arrays of strings. function Table(caption, aligns, widths, headers, rows) local buffer = {} local function add(s) table.insert(buffer, s) end add("") if caption ~= "" then add("") end if widths and widths[1] ~= 0 then for _, w in pairs(widths) do add('') end end local header_row = {} local empty_header = true for i, h in pairs(headers) do local align = html_align(aligns[i]) table.insert(header_row,'') empty_header = empty_header and h == "" end if empty_header then head = "" else add('') for _,h in pairs(header_row) do add(h) end add('') end local class = "even" for _, row in pairs(rows) do class = (class == "even" and "odd") or "even" add('') for i,c in pairs(row) do add('') end add('') end add('
    " .. caption .. "
    ' .. h .. '
    ' .. c .. '
    ') return table.concat(buffer,'\n') end function Div(s, attr) if attr["class"] == "notes" then return "" else return "\n" .. s .. "" end end function Span(s, attr) return "\n" .. s .. "" end function RawInline(f, s) if f == "html" then return s else return '' end end function RawBlock(f, s) if f == "html" then return s else return '' end end -- The following code will produce runtime warnings when you haven't defined -- all of the functions you need for the custom writer, so it's useful -- to include when you're working on a writer. local meta = {} meta.__index = function(_, key) io.stderr:write(string.format("WARNING: Undefined function '%s'\n",key)) return function() return "" end end setmetatable(_G, meta)