0byt3m1n1
Path:
C:
/
Program Files
/
RStudio
/
resources
/
app
/
bin
/
quarto
/
share
/
filters
/
modules
/
dashboard
/
[
Home
]
File: valuebox.lua
-- valuebox.lua -- Copyright (C) 2020-2022 Posit Software, PBC local card = require 'modules/dashboard/card' -- Valuebox classes local kValueBoxClz = "valuebox" local kValueBoxShowcaseClz = "value-box-showcase" local kValueBoxAreaClz = "value-box-area" local kValueBoxTitleClz = "value-box-title" local kValueBoxValueClz = "value-box-value" -- Valuebox attributes local kValueBoxValue = "value" local kValueBoxTitle = "title" local kValueBoxColor = "color" local kValueBoxBgColor = "bg-color" local kValueBoxFgColor = "fg-color" local kValueBoxShowcasePosition= "showcase-position" local kValueBoxIcon = "icon" local kValueBoxOptions = pandoc.List({kValueBoxIcon, kValueBoxColor, kValueBoxBgColor, kValueBoxFgColor}) local kValueBoxDataAttr = {kValueBoxColor, kValueBoxBgColor, kValueBoxFgColor} local kValueBoxShowcaseDataAttr = {kValueBoxIcon, kValueBoxShowcasePosition} local kForwardValueFromCodeCell = pandoc.List({kValueBoxTitle, kValueBoxValue, kValueBoxColor, kValueBoxBgColor, kValueBoxFgColor, kValueBoxIcon }) -- Component / content attributes local kComponentAttr = "component" local kContentAttr = "content" local kContentAttrs = pandoc.List({kComponentAttr, kContentAttr}) local kComponentValuebox = "valuebox" local function isValueBoxContent(el) if el.attributes ~= nil and kContentAttrs:find_if(function(attrName) return el.attributes[attrName] == kComponentValuebox end) then return true end end local function isValueBox(el) if isValueBoxContent(el) then return true end return el.classes ~= nil and el.classes:includes(kValueBoxClz) end local function toLines(s) if s:sub(-1)~="\n" then s=s.."\n" end return s:gmatch("(.-)\n") end local kRListValuePattern = '%[1%] "?([^"]*)' local kRListKeyPattern = "%$(.*)" local function parseStdOutToOptions(stdOut) local options = {} local value = nil -- if it starts with `{`, treat it as jupyter output local firstChar = stdOut:match("^(.)") if firstChar == "{" then -- Remove the single quotes around the keys -- Replace colons with equals and single-quoted keys with unquoted keys local luaTableLiteral = stdOut:gsub("'([^']-)': ", "%1=") -- Load the string as a Lua table local parsed = load("return " .. luaTableLiteral)() -- the value value = tostring(parsed[kValueBoxValue]) -- the options for k, v in pairs(parsed) do if kValueBoxOptions:includes(k) then options[k] = v end end elseif firstChar == '$' then -- parse the stdout (look for knitr style output) local pendingKey = nil for line in toLines(stdOut) do if pendingKey ~= nil then local cleaned = line:match(kRListValuePattern) if pendingKey == kValueBoxValue then value = cleaned pendingKey = nil else options[pendingKey] = cleaned pendingKey = nil end else local key = line:match(kRListKeyPattern) if kForwardValueFromCodeCell:includes(key) then pendingKey = key end end end elseif firstChar == '[' then local cleaned = stdOut:match(kRListValuePattern) value = cleaned else -- python stdout strings are surrounded with single quotes, so -- remove these value = stdOut:gsub("^'", ""):gsub("'$", "") end return options, value end local function valueboxContent(el) if isValueBoxContent(el) then -- read the title from attributes, if possible local title = {} local value = el.content local content = {} local options = {} if el.attributes[kValueBoxTitle] ~= nil then title = el.attributes[kValueBoxTitle] end -- try to find stdout local stdOut _quarto.ast.walk(el, { Div = function(divEl) if divEl.classes:includes('cell-output-stdout') then if divEl.content[1] ~= nil and divEl.content[1].t == "CodeBlock" then stdOut = divEl.content[1].text end elseif divEl.classes:includes('cell-output-display') and divEl.content[1] ~= nil and divEl.content[1].t == "CodeBlock" then stdOut = divEl.content[1].text end end }) -- Found stdout, try parsing it if stdOut ~= nil then local stdOptions, stdValue = parseStdOutToOptions(stdOut) options = stdOptions if stdValue ~= nil then value = stdValue end if options[kValueBoxTitle] ~= nil then title = options[kValueBoxTitle] end end return title, value, content, options else -- If there is only one child, that is the value local title = {} local value = el.content local content = {} -- First retrieve the title local pendingContent = el.content if el.attributes[kValueBoxTitle] ~= nil then title = el.attributes[kValueBoxTitle] elseif #pendingContent > 1 then title = pendingContent[1]:clone() pendingContent = tslice(pendingContent, 2) end -- Now read the value value = pendingContent[1]:clone() pendingContent = tslice(pendingContent, 2) -- Finally, the contents content = pendingContent return title, value, content, {} end end local function wrapValueBox(box, classes) local valueBoxClz = pandoc.List({kValueBoxClz}) valueBoxClz:extend(classes) return card.makeCard({box}, valueBoxClz) end -- Make a valuebox -- ValueBox DOM structure -- .card .value-box[showcase(left-center,top-right,bottom), color(scss name, actual value)] -- .value-box-grid -- .value-box-showcase -- .value-box-area -- .value-box-title -- .value-box-value -- other content -- attributes local function makeValueBox(el) -- read the title, value, and content local classes = el.classes local title, value, content, attr = valueboxContent(el) if pandoc.utils.type(value) ~= "table" and pandoc.utils.type(value) ~= "Blocks" then value = {value} end if value == nil then error("Value boxes must have a value - the structure of this valuebox appears malformed.") end -- Forward attributes local attrs = {} for _i,attrName in ipairs(kValueBoxDataAttr) do local attrValue = el.attributes[attrName] if attrValue ~= nil then attrs['data-' .. attrName] = attrValue end end -- send any explicitly provided attributes for key,val in pairs(attr) do attrs['data-' .. key] = val end local vbDiv = pandoc.Div({}, pandoc.Attr("", {}, attrs)) -- The valuebox icon local showcaseAttr = {} for _i,attrName in ipairs(kValueBoxShowcaseDataAttr) do local attrValue = el.attributes[attrName] or attr[attrName] if attrValue ~= nil then showcaseAttr['data-' .. attrName] = attrValue end end -- add the showcase if next(showcaseAttr) ~= nil then local vbShowcase = pandoc.Div({}, pandoc.Attr("", {kValueBoxShowcaseClz}, showcaseAttr)) vbDiv.content:insert(vbShowcase) end local vbArea = pandoc.Div({}, pandoc.Attr("", {kValueBoxAreaClz})) -- The valuebox title local titleEl = title if titleEl.t == "string" then titleEl = pandoc.Plain(title) elseif pandoc.utils.type(title) == "table" and #table == 0 then titleEl = pandoc.Para({nbspString()}) end local vbTitle = pandoc.Div(titleEl, pandoc.Attr("", {kValueBoxTitleClz})) vbArea.content:insert(vbTitle) -- The valuebox value local vbValue = pandoc.Div(value, pandoc.Attr("", {kValueBoxValueClz})) vbArea.content:insert(vbValue) -- The rest of the contents if next(content) ~= nil then vbArea.content:extend(content) end vbDiv.content:insert(vbArea) return wrapValueBox(vbDiv, classes) end return { isValueBox = isValueBox, makeValueBox = makeValueBox, }