#meta

Some useful widgets.

Buttons

Types of button widgets:

  • widgets.button(text, callback) renders a simple button running the callback when clicked
  • widgets.commandButton(commandName) renders a button for a particular command (where the button text is the command name itself)
  • widgets.commandButton(text, commandName) renders a button for a particular command with a custom button text
  • widgets.commandButton(text, commandName, args) renders a button for a particular command and arguments (specified as a table list) with a custom button text


-- priority: 10
function widgets.button(text, callback)
  return dom.button {
    onclick=callback,
    text
  }
end

function widgets.commandButton(text, commandName, args)
  if not commandName then
    -- When only passed one argument, then let's assume it's a command name
    commandName = text
  end
  return dom.button {
    onclick = function()
      system.invokeCommand(commandName, args)
    end,
    text
  }
end


Examples:

${widgets.button("Hello", function()
  editor.flashNotification "Hi there!"
end)}


${widgets.commandButton("System: Reload")}

Table of contents

widgets = widgets or {}

local tocSchema = {
  type = "object",
  properties = {
    minHeaders = { type = "number" },
  }
}

function widgets.toc(options)
  options = options or {}
  local validationResult = jsonschema.validateObject(tocSchema, options)
  if validationResult then
    error(validationResult)
  end
  options.minHeaders = options.minHeaders or 3
  local text = editor.getText()
  local pageName = editor.getCurrentPage()
  local lines = string.split(text, "\n")
  local pos = 0
  -- Collect all headers
  local headers = {}
  for _, line in ipairs(lines) do
    local headerSign, text = string.match(line, "^(%#+)%s+(.+){{CONTENT}}quot;)
    if headerSign then
      table.insert(headers, {
        name = text,
        pos = pos,
        level = #headerSign,
      })
    end
    pos = pos + #line + 1
  end
  if options.minHeaders and options.minHeaders > #headers then
    return widget.new{}
  end
  -- Find min level
  local minLevel = 6
  for _, header in ipairs(headers) do
    if header.level < minLevel then
      minLevel = header.level
    end
  end
  -- Build up markdown
  local md = (options.header or "# Table of Contents") .. "\n"
  for _, header in ipairs(headers) do
    if not(options.maxHeader and header.level > options.maxHeader or
           options.minLevel and header.level < options.minLevel) then
      md = md .. string.rep(" ", (header.level - minLevel) * 2) +
         "* [[" .. pageName .. "@" .. header.pos .. "|" .. header.name .. "]]\n"
    end
  end
  return widget.new {
    markdown = md
  }
end

event.listen {
  name = "hooks:renderTopWidgets",
  run = function(e)
    local pageText = editor.getText()
    local fm = index.extractFrontmatter(pageText)
    if fm.frontmatter.pageDecoration and fm.frontmatter.pageDecoration.disableTOC then
      return
    end
    return widgets.toc()
  end
}


Linked mentions

widgets = widgets or {}

local mentionTemplate = template.new [==[
* [[${_.ref}]]: “${_.snippet}”
]==]

function widgets.linkedMentions(pageName)
  pageName = pageName or editor.getCurrentPage()
  local linkedMentions = query[[
    from index.tag "link"
    where _.page != pageName and _.toPage == pageName
    order by page
  ]]
  if #linkedMentions > 0 then
    return widget.new {
      markdown = "# Linked Mentions\n"
        .. template.each(linkedMentions, mentionTemplate)
    }
  end
end

event.listen {
  name = "hooks:renderBottomWidgets",
  run = function(e)
    return widgets.linkedMentions()
  end
}


Linked tasks

function widgets.linkedTasks(pageName)
  pageName = pageName or editor.getCurrentPage()
  local tasks = query[[
    from index.tag "task"
    where not _.done
      and string.find(_.name, "[[" .. pageName .. "]]", 1, true)
  ]]
  local md = ""
  if #tasks > 0 then
    md = "# Linked Tasks\n"
       .. template.each(tasks, templates.taskItem)
  else
    md = ""
  end
  return widget.new {
    markdown = md
  }
end

event.listen {
  name = "hooks:renderTopWidgets",
  run = function(e)
    return widgets.linkedTasks()
  end
}