Module:Diagram
Appearance
This module provides the functionality of the {{diagram}} template.
The module can be called from wikitext with the following functions:
{#invoke:Diagram| render }
- Renders the diagram.
The module is only intended to be called from the template mentioned above. The parameters passed in the transclusions of that template (e.g. {diagram|A|-|B|A=Alice|B=Bob}) are recognized and handled by this module. See the template documentation for details about the parameters.
Template:Category/db-en[[Category:Template:Tr ]] Lua error in package.lua at line 80: module 'Module:Language_info/data' not found.
--------------------------------------------------------------------------------
--
-- =============================================================================
--
-- Module:Diagram
--
-- Rendering a family tree-like diagram
--
-- =============================================================================
--
-- Code annotations:
-- This module is documented according to LuaCATS (Lua Comment and Type System).
-- LuaCATS comments are prefixed with three dashes (---) and use Markdown syntax.
-- For a full list of annotations, see the following link:
-- https://luals.github.io/wiki/annotations/
--
--------------------------------------------------------------------------------
local trim = mw.text.trim
---Holds the arguments from the template call.
---@type table<string, string>
local inputArgs
---Return a trimmed version of the value of the template parameter with the specified `key`.
---Return `nil` if the parameter is empty or unset.
---@param key string|integer
---@return string?
local function getArg(key)
local value = inputArgs[key]
if not value then
return nil
end
value = trim(value)
if value == '' then
return nil
end
return value
end
---Combine all the buffered cells during this row.
---@param row1 string Buffer from the iteration
---@param row2 string Buffer from the iteration
---@return string row HTML output for this row
local function processRow(row1, row2)
return '<tr class="x"> ' .. row1 .. '</tr><tr class="y">' .. row2 .. '</tr>'
end
---Merge the common styles for all boxes (from the `boxstyle` argument) with the
---styles for this current box.
---@param commonBoxstyle string
---@param arg string Current box name
---@return string
local function mergeStyles(commonBoxstyle, arg)
return table.concat({
commonBoxstyle,
getArg(arg .. '_boxstyle') or getArg(arg .. '_style') or getArg(arg .. '_css')
}, ';')
end
---Table cells for connectors, i.e. horizontal and vertical lines, line corners,
---crossings, etc.
local connectorCells = {
['_'] = {
row1 = '<td class="l nr nb"></td><td class="l"></td>',
row2 = '<td class="l" colspan="2"></td>',
},
['-'] = {
row1 = '<td colspan="2" class="l sb"></td>',
row2 = '<td class="l nr"></td><td class="l"></td>',
},
['I'] = {
row1 = '<td rowspan="2" class="l sr"></td><td class="l nb"></td>',
row2 = '<td class="l"></td>',
},
[','] = {
row1 = '<td class="l cf"></td><td class="l sb"></td>',
row2 = '<td class="l sr"></td><td class="l"></td>',
},
['v'] = {
row1 = '<td colspan="2" class="l sb"></td>',
row2 = '<td class="l sr"></td><td class="l"></td>',
},
['.'] = {
row1 = '<td class="l sb"></td><td class="l" rowspan="2"></td>',
row2 = '<td class="l sr"></td>',
},
[')'] = {
row1 = '<td rowspan="2" class="l sr"></td><td class="l sb"></td>',
row2 = '<td class="l"></td>',
},
['+'] = {
row1 = '<td class="l sr sb"></td><td class="l sb"></td>',
row2 = '<td class="l sr"></td><td class="l"></td>',
},
['('] = {
row1 = '<td class="l sb sr"></td><td class="l" rowspan="2"></td>',
row2 = '<td class="l sr"></td>',
},
['`'] = {
row1 = '<td class="l sr"></td><td class="l sb"></td>',
row2 = '<td class="l" colspan="2"></td>',
},
['^'] = {
row1 = '<td class="l sr sb"></td><td class="l sb"></td>',
row2 = '<td class="l" colspan="2"></td>',
},
["'"] = {
row1 = '<td class="l sr sb"></td><td class="l"></td>',
row2 = '<td class="l" colspan="2"></td>',
},
['~'] = {
row1 = '<td colspan="2" class="l db"></td>',
row2 = '<td class="l nr"></td><td class="l"></td>',
},
[':'] = {
row1 = '<td rowspan="2" class="l dr"></td><td class="l nb"></td>',
row2 = '<td class="l"></td>',
},
['F'] = {
row1 = '<td class="l cf"></td><td class="l db"></td>',
row2 = '<td class="l dr"></td><td class="l"></td>',
},
['V'] = {
row1 = '<td colspan="2" class="l db"></td>',
row2 = '<td class="l dr"></td><td class="l"></td>',
},
['7'] = {
row1 = '<td class="l db"></td><td class="l" rowspan="2"></td>',
row2 = '<td class="l dr"></td>',
},
['D'] = {
row1 = '<td rowspan="2" class="l dr"></td><td class="l db"></td>',
row2 = '<td class="l"></td>',
},
['X'] = {
row1 = '<td class="l dr db"></td><td class="l db"></td>',
row2 = '<td class="l dr"></td><td class="l"></td>',
},
['C'] = {
row1 = '<td class="l db dr"></td><td class="l" rowspan="2"></td>',
row2 = '<td class="l dr"></td>',
},
['L'] = {
row1 = '<td class="l dr"></td><td class="l db"></td>',
row2 = '<td class="l" colspan="2"></td>',
},
['A'] = {
row1 = '<td class="l dr db"></td><td class="l db"></td>',
row2 = '<td class="l" colspan="2"></td>',
},
['J'] = {
row1 = '<td class="l dr db"></td><td class="l"></td>',
row2 = '<td class="l" colspan="2"></td>',
},
['r'] = {
row1 = '<td class="l cf"></td><td class="l db"></td>',
row2 = '<td class="l sr"></td><td class="l"></td>',
},
['y'] = {
row1 = '<td colspan="2" class="l db"></td>',
row2 = '<td class="l sr"></td><td class="l"></td>',
},
['n'] = {
row1 = '<td class="l db"></td><td class="l" rowspan="2"></td>',
row2 = '<td class="l sr"></td>',
},
[']'] = {
row1 = '<td rowspan="2" class="l sr"></td><td class="l db"></td>',
row2 = '<td class="l"></td>',
},
['$'] = {
row1 = '<td class="l sr db"></td><td class="l db"></td>',
row2 = '<td class="l sr"></td><td class="l"></td>',
},
['['] = {
row1 = '<td class="l db sr"></td><td class="l" rowspan="2"></td>',
row2 = '<td class="l sr"></td>',
},
['c'] = {
row1 = '<td class="l sr"></td><td class="l db"></td>',
row2 = '<td class="l" colspan="2"></td>',
},
['h'] = {
row1 = '<td class="l sr db"></td><td class="l db"></td>',
row2 = '<td class="l" colspan="2"></td>',
},
['j'] = {
row1 = '<td class="l sr db"></td><td class="l"></td>',
row2 = '<td class="l" colspan="2"></td>',
},
['p'] = {
row1 = '<td class="l cf"></td><td class="l sb"></td>',
row2 = '<td class="l dr"></td><td class="l"></td>',
},
['u'] = {
row1 = '<td colspan="2" class="l sb"></td>',
row2 = '<td class="l dr"></td><td class="l"></td>',
},
['q'] = {
row1 = '<td class="l sb"></td><td class="l" rowspan="2"></td>',
row2 = '<td class="l dr"></td>',
},
['E'] = {
row1 = '<td rowspan="2" class="l dr"></td><td class="l sb"></td>',
row2 = '<td class="l"></td>',
},
['x'] = {
row1 = '<td class="l dr sb"></td><td class="l sb"></td>',
row2 = '<td class="l dr"></td><td class="l"></td>',
},
['3'] = {
row1 = '<td class="l sb dr"></td><td class="l" rowspan="2"></td>',
row2 = '<td class="l dr"></td>',
},
['b'] = {
row1 = '<td class="l dr"></td><td class="l sb"></td>',
row2 = '<td class="l" colspan="2"></td>',
},
['t'] = {
row1 = '<td class="l dr sb"></td><td class="l sb"></td>',
row2 = '<td class="l" colspan="2"></td>',
},
['d'] = {
row1 = '<td class="l dr sb"></td><td class="l"></td>',
row2 = '<td class="l" colspan="2"></td>',
},
['/'] = {
row1 = '<td class="l dr db"></td><td class="l sb"></td>',
row2 = '<td class="l sr"></td><td class="l"></td>',
},
['Y'] = {
row1 = '<td class="l dr sb"></td><td class="l sb"></td>',
row2 = '<td class="l sr"></td><td class="l"></td>',
},
['\\'] = {
row1 = '<td class="l dr sb"></td><td class="l db"></td>',
row2 = '<td class="l sr"></td><td class="l"></td>',
},
['B'] = {
row1 = '<td class="l sr db"></td><td class="l sb"></td>',
row2 = '<td class="l sr"></td><td class="l"></td>',
},
['G'] = {
row1 = '<td class="l sr sb"></td><td class="l db"></td>',
row2 = '<td class="l sr"></td><td class="l"></td>',
},
['R'] = {
row1 = '<td class="l sr db"></td><td class="l sb"></td>',
row2 = '<td class="l dr"></td><td class="l"></td>',
},
['U'] = {
row1 = '<td class="l sr sb"></td><td class="l sb"></td>',
row2 = '<td class="l dr"></td><td class="l"></td>',
},
['4'] = {
row1 = '<td class="l sr sb"></td><td class="l db"></td>',
row2 = '<td class="l dr"></td><td class="l"></td>',
},
['!'] = {
row1 = '<td class="l sr nb"></td><td class="l" rowspan="2"></td>',
row2 = '<td class="l dr"></td>',
},
['i'] = {
row1 = '<td class="l dr nb"></td><td class="l" rowspan="2"></td>',
row2 = '<td class="l sr"></td>',
},
['<'] = {
row1 = '<td class="l sb nr"></td><td class="l db"></td>',
row2 = '<td class="l" colspan="2"></td>',
},
['>'] = {
row1 = '<td class="l db nr"></td><td class="l sb"></td>',
row2 = '<td class="l" colspan="2"></td>',
},
['9'] = {
row1 = '<td class="l sr nb"></td><td class="l" rowspan="2"></td>',
row2 = '<td class="l"></td>',
},
['6'] = {
row1 = '<td colspan="2" class="l nb"></td>',
row2 = '<td class="l sr"></td><td class="l"></td>',
},
['&'] = {
row1 = '<td class="l sb nr"></td><td class="l"></td>',
row2 = '<td class="l" colspan="2"></td>',
},
['?'] = {
row1 = '<td class="l nr"></td><td class="l sb"></td>',
row2 = '<td class="l" colspan="2"></td>',
},
['"'] = {
row1 = '<td class="l dr nb"></td><td class="l" rowspan="2"></td>',
row2 = '<td class="l"></td>',
},
[';'] = {
row1 = '<td colspan="2" class="l nb"></td>',
row2 = '<td class="l dr"></td><td class="l"></td>',
},
['a'] = {
row1 = '<td class="l db nr"></td><td class="l"></td>',
row2 = '<td class="l" colspan="2"></td>',
},
['e'] = {
row1 = '<td class="l nr"></td><td class="l db"></td>',
row2 = '<td class="l" colspan="2"></td>',
},
['M'] = {
row1 = '<td class="l dr db"></td><td class="l db"></td>',
row2 = '<td class="l sr"></td><td class="l"></td>',
},
['W'] = {
row1 = '<td class="l sr db"></td><td class="l db"></td>',
row2 = '<td class="l dr"></td><td class="l"></td>',
},
['2'] = {
row1 = '<td class="l dr sb"></td><td class="l db"></td>',
row2 = '<td class="l dr"></td><td class="l"></td>',
},
['5'] = {
row1 = '<td class="l dr db"></td><td class="l sb"></td>',
row2 = '<td class="l dr"></td><td class="l"></td>',
},
['f'] = {
row1 = '<td class="l sr nb"></td><td class="l db"></td>',
row2 = '<td class="l dr"></td><td class="l"></td>',
},
['g'] = {
row1 = '<td class="l sr db"></td><td class="l" rowspan="2"></td>',
row2 = '<td class="l dr"></td>',
},
['k'] = {
row1 = '<td class="l dr nb"></td><td class="l db"></td>',
row2 = '<td class="l sr"></td><td class="l"></td>',
},
['s'] = {
row1 = '<td class="l dr db"></td><td class="l" rowspan="2"></td>',
row2 = '<td class="l sr"></td>',
},
['o'] = {
row1 = '<td class="l nr sb"></td><td class="l db"></td>',
row2 = '<td class="l dr"></td><td class="l"></td>',
},
['m'] = {
row1 = '<td class="l nr db"></td><td class="l sb"></td>',
row2 = '<td class="l dr"></td><td class="l"></td>',
},
['w'] = {
row1 = '<td class="l dr sb"></td><td class="l db"></td>',
row2 = '<td class="l" colspan="2"></td>',
},
['z'] = {
row1 = '<td class="l dr db"></td><td class="l sb"></td>',
row2 = '<td class="l" colspan="2"></td>',
},
['P'] = {
row1 = '<td class="l dr nb"></td><td class="l sb"></td>',
row2 = '<td class="l sr"></td><td class="l"></td>',
},
['H'] = {
row1 = '<td class="l dr sb"></td><td class="l" rowspan="2"></td>',
row2 = '<td class="l sr"></td>',
},
['K'] = {
row1 = '<td class="l sr nb"></td><td class="l sb"></td>',
row2 = '<td class="l dr"></td><td class="l"></td>',
},
['N'] = {
row1 = '<td class="l sr sb"></td><td class="l" rowspan="2"></td>',
row2 = '<td class="l dr"></td>',
},
['T'] = {
row1 = '<td class="l nr db"></td><td class="l sb"></td>',
row2 = '<td class="l sr"></td><td class="l"></td>',
},
['Z'] = {
row1 = '<td class="l nr sb"></td><td class="l db"></td>',
row2 = '<td class="l sr"></td><td class="l"></td>',
},
['S'] = {
row1 = '<td class="l sr db"></td><td class="l sb"></td>',
row2 = '<td class="l" colspan="2"></td>',
},
['Q'] = {
row1 = '<td class="l sr sb"></td><td class="l db"></td>',
row2 = '<td class="l" colspan="2"></td>',
},
['←'] = {
row1 = '<td class="l sb alt"></td><td class="l sb"></td>',
row2 = '<td class="l alb" colspan="2"></td>',
},
['→'] = {
row1 = '<td class="l sb"></td><td class="l sb art"></td>',
row2 = '<td class="l arb" colspan="2"></td>',
},
['↑'] = {
row1 = '<td class="l sr atl"></td><td class="l atr" rowspan="2"></td>',
row2 = '<td class="l sr"></td>',
},
['↓'] = {
row1 = '<td class="l sr"></td><td class="l abr" rowspan="2"></td>',
row2 = '<td class="l sr abl"></td>',
},
['⇠'] = {
row1 = '<td class="l db alt"></td><td class="l db"></td>',
row2 = '<td class="l alb" colspan="2"></td>',
},
['⇢'] = {
row1 = '<td class="l db"></td><td class="l db art"></td>',
row2 = '<td class="l arb" colspan="2"></td>',
},
['⇡'] = {
row1 = '<td class="l dr atl"></td><td class="l atr" rowspan="2"></td>',
row2 = '<td class="l dr"></td>',
},
['⇣'] = {
row1 = '<td class="l dr"></td><td class="l abr" rowspan="2"></td>',
row2 = '<td class="l dr abl"></td>',
},
['*'] = { -- unlinked crossing
row1 = '<td class="l sb ct"></td><td class="l sb"></td>',
row2 = '<td class="l sr cb"></td><td class="l"></td>',
},
}
-- aliases
connectorCells['0'] = connectorCells['_']
connectorCells['O'] = connectorCells['_']
--------------------------------------------------------------------------------
---Main return object
local p = {}
---Process the arguments to render a HTML `<table>` element.
---@param frame table Interface to the parser (`mw.frame`)
---@return string
p.render = function(frame)
inputArgs = frame:getParent().args -- global input args cache
local boxclass = getArg('boxclass')
local boxstyle = getArg('boxstyle') or ''
-- The unnamed arguments come in rows, e.g.:
-- |A|_|B|#
-- |C|^|D|#
-- Unnamed args = { 'A', '_', 'B', '#', 'C', '^', 'D', '#' }
-- We will iterate over these arguments in rows, which means: Create the table
-- cell HTML for each argument and store it in a buffer. When we reach the
-- end of a row, i.e. a '#' argument, then combine the buffered cells, add
-- them to the processedRows, and clear the buffer for the next row.
---HTML table rows
local processedRows = {}
---Argument index during iteration
local argIndex = 1
---Argument value during iteration
local arg
-- Each row of arguments will actually consist of *two* table rows in
-- the HTML output (one `<tr class="x">`, one `<tr class="y">`). So the buffer
-- consists of two variables, `row1` and `row2`.
---Row buffer during iteration (children of `<tr class="x">`).
local row1 = ''
---Row buffer during iteration (children of `<tr class="y">`).
local row2 = ''
-- Start iterating
while true do
arg = inputArgs[argIndex] -- current unnamed argument
if not arg then
break
end
argIndex = argIndex+1
arg = trim(arg)
-- `arg` is one of these:
-- * a row terminator, then complete the current row and start a new one
-- * a connector (line drawing) or box (content), then create its HTML
-- and insert it into the buffer
-- * a blank string (argument consisting only of whitespace), then ignore it
if arg == '#' then
-- row terminator
processedRows[#processedRows + 1] = processRow(row1, row2)
-- clear the buffer for the next row
row1 = ''
row2 = ''
elseif connectorCells[arg] then
-- connector
row1 = row1 .. connectorCells[arg].row1
row2 = row2 .. connectorCells[arg].row2
elseif arg == '' then
-- blank string, skipped
else
-- content box
local td = mw.html.create('td')
:attr({
class = 'diagram-box',
colspan = 2 * tonumber(getArg(arg .. '_cols') or 3),
rowspan = 2 * tonumber(getArg(arg .. '_rows') or 1),
id = getArg(arg .. '_id'),
})
:addClass(boxclass)
:addClass(getArg(arg .. '_class'))
local style = mergeStyles(boxstyle, arg)
if style then
td:attr('style', style)
end
td:wikitext(trim(inputArgs[arg] or ''))
row1 = row1 .. tostring(td)
end
end
-- We reached the end of the unnamed arguments. If the last argument was not
-- a row terminator, then the buffer still contains the last row, so add that
-- to the output.
if row1 ~= '' then
processedRows[#processedRows + 1] = processRow(row1, row2)
end
-- Insert all the table rows into an HTML `<table>`.
local output = mw.html.create('table')
:attr({
class = 'diagram',
id = getArg('id'),
style = getArg('style') or getArg('css'),
title = getArg('summary'),
})
:addClass(getArg('class'))
:wikitext(table.concat(processedRows)) -- insert the rows
return tostring(output)
end
return p