currently running: 2.0-beta (0.10.4-242-gb1b13635)
Motivation
I’m not a web developer – I’m sure there are easier ways to do this directly in js, but I was working off of the APIs and for fun
One particular workflow that I had going in V1 was a table in my index.md
that had:
Recently Modified Pages
name | status |
---|---|
page1 | [delete] |
page2 | [protected] |
Where [delete] or [protected] are buttons – one that deletes the page, and one disabled one to prevent oopsies. I used this quite a bit because I often create scratch pages for testing.
Which looks fine until you mouseout of the markdown text – then it looks like
Ah, the dreaded html _isWidget true
End Result
Strategy Over Time:
- Build table / tr / td by hand using the DOM API, generating one row per table row, and one cell per key/val pair
- Realize that constructing by hand means you have to implement everything
- Find a way to convert markdown back into the dom API to enable reuse (see below)
- Customize the table implementation to inject data classes, and other custom definitions.
Key Insight
Looking over the implementation of the DOM API, I figured I could copy how the current library constructs nodes – a little stackoverflow later, I get:
-- takes HTML and translates back to DOM
-- helpful for integrating w. the dom API while reusing
-- other HTML components like markdown rendering
function dom_.fromHtml(html)
local div = js.window.document.createElement('div')
div.innerHTML = html
return div.firstChild
end
-- Takes raw table values and reuses linkifying, hashtags, etc..
function dom_.fromMarkdown(md)
return dom_.fromHtml(markdown.markdownToHtml(md))
end
What this allowed me to do was reuse most of the cell rendering while retaining the ability to customize
Code
The actual table implementation is not very interesting – namely lots of pairs, ipairs (and util methods to convert between the various forms). But the API surface to reach the level of specificity might be of interest
tbl = tbl or {}
function tbl.deletePageWidget(data, cssPrefix)
function css_class(elm)
unique = cssPrefix .. elm
return table.concat({unique, cssPrefix}," ")
-- this allows for both targeted: css-prefix-td
-- and compound: css-prefix td
end
cssPrefix = cssPrefix or "delete-table-"
-- I don't know how to map from lists in lua so I wrote one
return tbl.table(tbl.foreach(
data,
function(row)
return {
name = row.name,
-- protected == key below
protected = table.includes(row.tags, "protected")
}
end
), tbl.opts{
-- injectable / customizable
rowOpts = {
tdClass = css_class("td"),
trClass = css_class("tr"),
headerClass = css_class("header"),
-- also have
-- onRow(data, isHeader, onCell, onCellMatch, refKeys, tagKeys)
-- onCell(key, cell, row, header)
-- onCellMatch(key, cell, row, header)
-- key is the column, cell is the value
-- row is the entire row (i.e. for constructing the delete function)
onCell = function(key, cell, row, isHeader)
if key == "name" and not isHeader then
-- references are otherwise just text in a cell; need to do this explicitly
-- or otherwise pass information on which columns are refs
return navigation.refLink{ ref = cell }
elseif key == "protected" and cell then
return dom.button { "Protected", disabled="" }
elseif key == "protected" and not cell then
return dom.button {
"Delete", class=css_class("button"),
onclick = function()
-- my own delete function with other hooks
delete.deletePage(row.name)
end
}
end
-- sane defaults for rendering hashtags, other table text
return dom_.fromMarkdown(cell)
end
},
})
end
If there’s a way to lift a lot of the business logic to JS (like table manipulation – I found lua tables somewhat confusing), would love to hear it!
Otherwise this was a fun little detour, during which I took no notes and was just tinkering with the environment