260
edits
No edit summary Tag: Reverted |
No edit summary Tag: Reverted |
||
| Line 1: | Line 1: | ||
-- Module:Tree chart | -- Module:Tree chart | ||
-- Defensive renderer | -- Defensive renderer that emits a scoped inline stylesheet next to the table. | ||
pcall(function() require('strict') end) | pcall(function() require('strict') end) | ||
local p = {} | local p = {} | ||
local cells = mw.loadData('Module:Tree chart/data') | |||
-- safe wrapper to insert raw HTML fragments into mw.html nodes | |||
local function safe_wikitext(node, html) | |||
node:wikitext(html) | |||
end | |||
function p._main(cell_args) | function p._main(cell_args) | ||
local | local out = mw.html.create() | ||
-- | |||
local tbl = | -- Inline style block scoped to .tree-chart-inline-style (highly specific, uses !important) | ||
local style = [[ | |||
<style type="text/css"> | |||
/* Scoped tree styles that override global rules */ | |||
.tree-chart-inline-style { border-collapse: collapse !important; border-spacing: 0 !important; vertical-align: top !important; display: inline-table !important; font-family: inherit !important; } | |||
.tree-chart-inline-style td { padding: 0 !important; margin: 0 !important; vertical-align: top !important; box-sizing: border-box !important; white-space: nowrap !important; line-height: 1 !important; font-size: 0.9rem !important; } | |||
.tree-chart-inline-style td.connector { padding: 0 !important; width:1em !important; height:1em !important; min-width:1em !important; min-height:1em !important; max-width:1em !important; max-height:1em !important; line-height:1 !important; } | |||
.tree-chart-inline-style td.box { padding: 0.35em 0.9em !important; white-space: normal !important; font-size: 1rem !important; text-align: center !important; } | |||
.tree-chart-inline-style td[style*="border-bottom"], .tree-chart-inline-style td[style*="border-right"], .tree-chart-inline-style td[style*="border"] { box-sizing: border-box !important; } | |||
</style> | |||
]] | |||
out:wikitext(style) | |||
-- Build table with explicit style attribute (avoid :css camelCase pitfalls) | |||
local tbl = out:tag('table') | |||
:addClass('tree-chart-inline-style') | |||
:attr{ style = 'border-collapse: collapse; border-spacing: 0; vertical-align: top;' } | |||
local top = tbl:tag('tr'): | local top = tbl:tag('tr'):attr{ style = 'height:1px; text-align:center;' } | ||
local bottom = tbl:tag('tr'): | local bottom = tbl:tag('tr'):attr{ style = 'height:1px; text-align:center;' } | ||
for _, v in ipairs(cell_args) do | for _, v in ipairs(cell_args) do | ||
| Line 27: | Line 39: | ||
local celldef = cells[v] | local celldef = cells[v] | ||
if celldef then | if celldef then | ||
-- celldef.t / celldef.b are fragments produced by Module:Tree chart/data (strings) | |||
-- Tag their <td> elements as connector cells by adding class="connector" | |||
if celldef.t then | if celldef.t then | ||
local tstr = tostring(celldef.t) | |||
-- add class only if not already present | |||
tstr = tstr:gsub('<td(.-)>', function(attrs) | |||
-- if class attribute exists, append connector; otherwise add it | |||
if attrs:match('class%s*=') then | |||
return '<td' .. attrs:gsub('class%s*=%s*"(.-)"', function(c) return string.format(' class="%s connector"', c) end) .. '>' | |||
else | |||
return '<td' .. attrs .. ' class="connector">' | |||
end | |||
end) | |||
safe_wikitext(top, tstr) | |||
else | else | ||
top:tag('td'): | top:tag('td'):addClass('connector'):attr{ style = 'width:1em; height:1em;' } | ||
end | end | ||
if celldef.b then | if celldef.b then | ||
local bstr = tostring(celldef.b) | |||
bstr = bstr:gsub('<td(.-)>', function(attrs) | |||
if attrs:match('class%s*=') then | |||
return '<td' .. attrs:gsub('class%s*=%s*"(.-)"', function(c) return string.format(' class="%s connector"', c) end) .. '>' | |||
else | |||
return '<td' .. attrs .. ' class="connector">' | |||
end | |||
end) | |||
safe_wikitext(bottom, bstr) | |||
else | else | ||
bottom:tag('td'): | bottom:tag('td'):addClass('connector'):attr{ style = 'width:1em; height:1em;' } | ||
end | end | ||
else | else | ||
top:tag('td'): | -- unknown symbol: render empty connector td | ||
bottom:tag('td'): | top:tag('td'):addClass('connector'):attr{ style = 'width:1em; height:1em;' } | ||
bottom:tag('td'):addClass('connector'):attr{ style = 'width:1em; height:1em;' } | |||
end | end | ||
else | else | ||
-- custom cell with text (a boxed cell) | |||
local colspan = v.colspan or cell_args.colspan or 6 | local colspan = v.colspan or cell_args.colspan or 6 | ||
local rowspan = v.rowspan or cell_args.rowspan or 2 | local rowspan = v.rowspan or cell_args.rowspan or 2 | ||
| Line 48: | Line 83: | ||
top:tag('td') | top:tag('td') | ||
:attr{ colspan = tostring(colspan), rowspan = tostring(rowspan) | :addClass('box') | ||
:attr{ | |||
colspan = tostring(colspan), | |||
rowspan = tostring(rowspan), | |||
style = 'padding:0.35em 0.9em; border: ' .. border .. '; box-sizing: border-box;' | |||
} | |||
:wikitext(v.text or '') | :wikitext(v.text or '') | ||
if tonumber(rowspan) | -- if rowspan < 2 we need a bottom placeholder; most boxes use rowspan=2 so bottom is empty | ||
bottom:tag('td'): | if not tonumber(rowspan) or tonumber(rowspan) < 2 then | ||
bottom:tag('td'):addClass('connector'):attr{ style = 'width:1em; height:1em;' } | |||
end | end | ||
end | end | ||
| Line 64: | Line 102: | ||
function p.main(frame) | function p.main(frame) | ||
local args = require('Module:Arguments').getArgs(frame, | local args = require('Module:Arguments').getArgs(frame, | ||
wrappers = 'Template:Tree chart', | { wrappers = 'Template:Tree chart', trim = false, removeBlanks = false }) | ||
local cell_args = { | local cell_args = { | ||
| Line 79: | Line 114: | ||
for _, val in ipairs(args) do | for _, val in ipairs(args) do | ||
local trimmedVal = val:match('^%s*(.-)%s*$') | local trimmedVal = val:match('^%s*(.-)%s*$') | ||
if trimmedVal == '' then | if trimmedVal == '' then trimmedVal = '$' end | ||
if cells[trimmedVal] then | if cells[trimmedVal] then | ||