|
| 1 | +-- Glossary.lua |
| 2 | +-- Author: Lisa DeBruine |
| 3 | + |
| 4 | +-- Global glossary table |
| 5 | +globalGlossaryTable = {} |
| 6 | + |
| 7 | +-- Helper Functions |
| 8 | + |
| 9 | +local function addHTMLDeps() |
| 10 | + -- add the HTML requirements for the library used |
| 11 | + quarto.doc.add_html_dependency({ |
| 12 | + name = 'glossary', |
| 13 | + stylesheets = {'glossary.css'} |
| 14 | + }) |
| 15 | +end |
| 16 | + |
| 17 | +local function kwExists(kwargs, keyword) |
| 18 | + for key, value in pairs(kwargs) do |
| 19 | + if key == keyword then |
| 20 | + return true |
| 21 | + end |
| 22 | + end |
| 23 | + return false |
| 24 | +end |
| 25 | + |
| 26 | +-- Function to sort a Lua table by keys |
| 27 | +function sortByKeys(tbl) |
| 28 | + local sortedKeys = {} |
| 29 | + |
| 30 | + -- Extract keys from the table and store them in the 'sortedKeys' array |
| 31 | + for key, _ in pairs(tbl) do |
| 32 | + table.insert(sortedKeys, key) |
| 33 | + end |
| 34 | + |
| 35 | + -- Sort the keys alphabetically |
| 36 | + table.sort(sortedKeys) |
| 37 | + |
| 38 | + -- Create a new table with the sorted keys |
| 39 | + local sortedTable = {} |
| 40 | + for _, key in pairs(sortedKeys) do |
| 41 | + sortedTable[key] = tbl[key] |
| 42 | + end |
| 43 | + |
| 44 | + return sortedTable |
| 45 | +end |
| 46 | + |
| 47 | +local function read_metadata_file(fname) |
| 48 | + local metafile = io.open(fname, 'r') |
| 49 | + local content = metafile:read("*a") |
| 50 | + metafile:close() |
| 51 | + local metadata = pandoc.read(content, "markdown").meta |
| 52 | + return metadata |
| 53 | +end |
| 54 | + |
| 55 | +local function readGlossary(path) |
| 56 | + local f = io.open(path, "r") |
| 57 | + if not f then |
| 58 | + io.stderr:write("Cannot open file " .. path) |
| 59 | + else |
| 60 | + local lines = f:read("*all") |
| 61 | + f:close() |
| 62 | + return(lines) |
| 63 | + end |
| 64 | +end |
| 65 | + |
| 66 | +---Merge user provided options with defaults |
| 67 | +---@param userOptions table |
| 68 | +local function mergeOptions(userOptions, meta) |
| 69 | + local defaultOptions = { |
| 70 | + path = "glossary.yml", |
| 71 | + popup = "hover", |
| 72 | + show = true, |
| 73 | + add_to_table = true |
| 74 | + } |
| 75 | + |
| 76 | + -- override with meta values first |
| 77 | + if meta.glossary ~= nil then |
| 78 | + for k, v in pairs(meta.glossary) do |
| 79 | + local value = pandoc.utils.stringify(v) |
| 80 | + if value == 'true' then value = true end |
| 81 | + if value == 'false' then value = false end |
| 82 | + defaultOptions[k] = value |
| 83 | + end |
| 84 | + end |
| 85 | + |
| 86 | + -- then override with function keyword values |
| 87 | + if userOptions ~= nil then |
| 88 | + for k, v in pairs(userOptions) do |
| 89 | + local value = pandoc.utils.stringify(v) |
| 90 | + if value == 'true' then value = true end |
| 91 | + if value == 'false' then value = false end |
| 92 | + defaultOptions[k] = value |
| 93 | + end |
| 94 | + end |
| 95 | + |
| 96 | + return defaultOptions |
| 97 | +end |
| 98 | + |
| 99 | + |
| 100 | +-- Main Glossary Function Shortcode |
| 101 | + |
| 102 | +return { |
| 103 | + |
| 104 | +["glossary"] = function(args, kwargs, meta) |
| 105 | + |
| 106 | + -- this will only run for HTML documents |
| 107 | + if not quarto.doc.isFormat("html:js") then |
| 108 | + return pandoc.Null() |
| 109 | + end |
| 110 | + |
| 111 | + addHTMLDeps() |
| 112 | + |
| 113 | + -- create glossary table |
| 114 | + if kwExists(kwargs, "table") then |
| 115 | + local gt = "<table class='glossary_table'>\n" |
| 116 | + gt = gt .. "<tr><th> Term </th><th> Definition </th></tr>\n" |
| 117 | + |
| 118 | + local sortedTable = sortByKeys(globalGlossaryTable) |
| 119 | + |
| 120 | + for key, value in pairs(sortedTable) do |
| 121 | + gt = gt .. "<tr><td>" .. key |
| 122 | + gt = gt .. "</td><td>" .. value .. "</td></tr>\n" |
| 123 | + end |
| 124 | + gt = gt .. "</table>" |
| 125 | + |
| 126 | + return pandoc.RawBlock('html', gt) |
| 127 | + end |
| 128 | + |
| 129 | + -- or set up in-text term |
| 130 | + local options = mergeOptions(kwargs, meta) |
| 131 | + |
| 132 | + local display = pandoc.utils.stringify(args[1]) |
| 133 | + local term = string.lower(display) |
| 134 | + |
| 135 | + if kwExists(kwargs, "display") then |
| 136 | + display = pandoc.utils.stringify(kwargs.display) |
| 137 | + end |
| 138 | + |
| 139 | + -- get definition |
| 140 | + local def = "" |
| 141 | + if kwExists(kwargs, "def") then |
| 142 | + def = pandoc.utils.stringify(kwargs.def) |
| 143 | + else |
| 144 | + local metafile = io.open(options.path, 'r') |
| 145 | + local content = "---\n" .. metafile:read("*a") .. "\n---\n" |
| 146 | + metafile:close() |
| 147 | + local glossary = pandoc.read(content, "markdown").meta |
| 148 | + for key, value in pairs(glossary) do |
| 149 | + glossary[string.lower(key)] = value |
| 150 | + end |
| 151 | + -- quarto.log.output() |
| 152 | + if kwExists(glossary, term) then |
| 153 | + def = pandoc.utils.stringify(glossary[term]) |
| 154 | + end |
| 155 | + end |
| 156 | + |
| 157 | + -- add to global table |
| 158 | + if options.add_to_table then |
| 159 | + globalGlossaryTable[term] = def |
| 160 | + end |
| 161 | + |
| 162 | + if options.popup == "hover" then |
| 163 | + glosstext = "<button class='glossary' title='" .. def .."'>" .. display .. "</button>" |
| 164 | + elseif options.popup == "click" then |
| 165 | + glosstext = "<button class='glossary'><span class='def'>" .. def .."</span>" .. display .. "</button>" |
| 166 | + elseif options.popup == "none" then |
| 167 | + glosstext = "<button class='glossary'>" .. display .. "</button>" |
| 168 | + end |
| 169 | + |
| 170 | + return pandoc.RawInline("html", glosstext) |
| 171 | + |
| 172 | +end |
| 173 | + |
| 174 | +} |
0 commit comments