#meta/api

This implements the widget API. For a Lua Directive to be rendered as a widget, you need to return it via widget.new. Consider using ^Library/Std/APIs/DOM to construct these.

-- priority: 50

-- Widget APIs
widget = {}

-- Container for widgets
widgets = {}

-- Widget schema for validation
local widgetSchema = {
  type = "object",
  properties = {
    markdown = { type = "string"},
    html = {
      anyOf = {
        -- HTMLElement
        { type = "object"},
        -- Plain HTML code
        { type = "string" }
      }
    },
    cssClasses = {
      type = "array",
      items = { type = "string" },
    },
    display = {
      type = "string",
      enum = {"block", "inline"}
    },
    events = {
      type = "object",
      additionalProperties = true
    },
    -- When true, html + script render inside an isolated sandbox iframe.
    sandbox = { type = "boolean" },
    script = { type = "string" },
  }
}

-- Creates a widget
function widget.new(spec)
  -- Validate spec
  local validationResult = jsonschema.validateObject(widgetSchema, spec)
  if validationResult then
    error(validationResult)
  end
  -- Mark as a widget
  spec._isWidget = true
  return spec
end

-- Convenience function for HTML widgets
function widget.html(html)
  return widget.new {
    html = html
  }
end

function widget.htmlBlock(html)
  return widget.new {
    html = html,
    display = "block"
  }
end

-- Convenience function for markdown widgets
function widget.markdown(markdown)
  return widget.new {
    markdown = markdown
  }
end

function widget.markdownBlock(markdown)
  return widget.new {
    markdown = markdown,
    display = "block"
  }
end

-- A sandboxed, scripted widget: html + script run inside an isolated iframe
-- (the same machinery code widgets use). `script` has access to syscall(),
-- loadJsByUrl, and auto height. The Copy button copies `markdown`. Equivalent to
-- `widget.new` with `sandbox = true`.
function widget.sandbox(spec)
  return widget.new {
    sandbox = true,
    html = spec.html,
    script = spec.script,
    display = spec.display or "block",
    markdown = spec.markdown,
    cssClasses = spec.cssClasses,
  }
end