Module:InfoboxBasic: Difference between revisions
Appearance
No edit summary |
No edit summary |
||
(5 intermediate revisions by the same user not shown) | |||
Line 2: | Line 2: | ||
local p = {} | local p = {} | ||
local trim = mw.text.trim | local trim = mw.text.trim | ||
local function isBlank(v) return v == nil or trim(tostring(v)) == '' end | local function isBlank(v) return v == nil or trim(tostring(v)) == '' end | ||
local function labelFromKey(k) | local function labelFromKey(k) return trim((k:gsub('_',' '))) end | ||
-- Extract optional numeric prefix to force ordering, e.g. "01 Born", "002_Born" | |||
local function splitOrderPrefix(key) | |||
local n, rest = tostring(key):match('^%s*(%d+)[%s_%-%.]*(.+)$') | |||
if n then | |||
return tonumber(n), trim(rest) | |||
end | |||
return nil, key | |||
end | |||
function p.render(frame) | function p.render(frame) | ||
local parent = frame:getParent() | local parent = frame:getParent() or frame | ||
local args = | local args = parent.args or {} -- never nil | ||
local title = args.name or args.Name or args.title or args.Title or 'Infobox' | local title = args.name or args.Name or args.title or args.Title or 'Infobox' | ||
local image = args.image or args.Image | local image = args.image or args.Image | ||
local color = args.color or args.Color or args.colour or args.Colour | local caption = args.caption or args.Caption | ||
local color = args.color or args.Color or args.colour or args.Colour | |||
-- Table | |||
local tbl = mw.html.create('table') | local tbl = mw.html.create('table') | ||
:addClass('infobox') | :addClass('infobox') | ||
Line 19: | Line 31: | ||
:css('margin','0 0 1em 1em') | :css('margin','0 0 1em 1em') | ||
-- Title | -- Title | ||
local th = tbl:tag('tr'):tag('th') | local th = tbl:tag('tr'):tag('th') | ||
:attr('colspan','2') | :attr('colspan','2') | ||
Line 28: | Line 40: | ||
if not isBlank(color) then | if not isBlank(color) then | ||
th:addClass('has-title-color') | th:addClass('has-title-color') | ||
th:css('--ib-title-bg', color) | th:css('--ib-title-bg', color) -- only used by light-mode CSS | ||
end | end | ||
-- Optional image | -- Optional image | ||
if not isBlank(image) then | if not isBlank(image) then | ||
tbl:tag('tr') | local cell = tbl:tag('tr'):tag('td') | ||
:attr('colspan','2') | :attr('colspan','2') | ||
:addClass('infobox-image-cell') | :addClass('infobox-image-cell') | ||
cell:wikitext('[[File:' .. image .. '|frameless]]') | |||
if not isBlank(caption) then | |||
cell:tag('div') | |||
:css('text-align','center') | |||
:css('font-size','90%') | |||
:css('font-style','italic') | |||
:css('margin-top','0.2em') | |||
:wikitext(caption) | |||
end | |||
end | end | ||
-- Keys to skip (already handled) | |||
local skip = { | local skip = { | ||
name=true, Name=true, title=true, Title=true, | name=true, Name=true, title=true, Title=true, | ||
image=true, Image=true, color=true, Color=true, colour=true, Colour=true, | image=true, Image=true, | ||
caption=true, Caption=true, | |||
color=true, Color=true, colour=true, Colour=true, | |||
class=true, style=true | class=true, style=true | ||
} | } | ||
local function addRow(label, value) | |||
local row = tbl:tag('tr') | |||
row:tag('th'):attr('scope','row'):wikitext(labelFromKey(label)) | |||
row:tag('td'):wikitext(value) | |||
end | |||
-- Build a stable order map from the editor's source order if possible | |||
end | local sourceOrder = {} | ||
if parent.argumentPairs then | |||
local temp = {} | |||
for key, _ in parent:argumentPairs() do | |||
temp[#temp+1] = key | |||
end | |||
for i = #temp, 1, -1 do | |||
sourceOrder[temp[i]] = i | |||
end | |||
elseif parent.getArgumentNames then | |||
local names = parent:getArgumentNames() or {} | |||
for i, key in ipairs(names) do | |||
sourceOrder[key] = i | |||
end | |||
end | |||
-- Collect rows with computed sort keys | |||
local rows = {} | |||
for key, value in pairs(args) do | |||
if not skip[key] and not tonumber(key) and not isBlank(value) then | |||
local forcedN, displayKey = splitOrderPrefix(key) | |||
local srcIndex = sourceOrder[key] or 10^9 | |||
rows[#rows+1] = { | |||
forced = forcedN or 10^8, | |||
src = srcIndex, | |||
key = displayKey, | |||
rawkey = key, | |||
value = value | |||
} | |||
end | |||
end | |||
-- Sort: first by explicit numeric prefix (if any), then by source order | |||
table.sort(rows, function(a,b) | |||
if a.forced ~= b.forced then | |||
return a.forced < b.forced | |||
end | end | ||
return a.src < b.src | |||
end) | |||
-- Render rows | |||
for _, r in ipairs(rows) do | |||
addRow(r.key, r.value) | |||
end | end | ||
Latest revision as of 00:30, 2 October 2025
Documentation for this module may be created at Module:InfoboxBasic/doc
-- Module:InfoboxBasic
local p = {}
local trim = mw.text.trim
local function isBlank(v) return v == nil or trim(tostring(v)) == '' end
local function labelFromKey(k) return trim((k:gsub('_',' '))) end
-- Extract optional numeric prefix to force ordering, e.g. "01 Born", "002_Born"
local function splitOrderPrefix(key)
local n, rest = tostring(key):match('^%s*(%d+)[%s_%-%.]*(.+)$')
if n then
return tonumber(n), trim(rest)
end
return nil, key
end
function p.render(frame)
local parent = frame:getParent() or frame
local args = parent.args or {} -- never nil
local title = args.name or args.Name or args.title or args.Title or 'Infobox'
local image = args.image or args.Image
local caption = args.caption or args.Caption
local color = args.color or args.Color or args.colour or args.Colour
-- Table
local tbl = mw.html.create('table')
:addClass('infobox')
:css('float','right')
:css('clear','right')
:css('margin','0 0 1em 1em')
-- Title
local th = tbl:tag('tr'):tag('th')
:attr('colspan','2')
:addClass('infobox-title')
:css('text-align','center')
:css('font-size','125%')
:wikitext(title)
if not isBlank(color) then
th:addClass('has-title-color')
th:css('--ib-title-bg', color) -- only used by light-mode CSS
end
-- Optional image
if not isBlank(image) then
local cell = tbl:tag('tr'):tag('td')
:attr('colspan','2')
:addClass('infobox-image-cell')
cell:wikitext('[[File:' .. image .. '|frameless]]')
if not isBlank(caption) then
cell:tag('div')
:css('text-align','center')
:css('font-size','90%')
:css('font-style','italic')
:css('margin-top','0.2em')
:wikitext(caption)
end
end
-- Keys to skip (already handled)
local skip = {
name=true, Name=true, title=true, Title=true,
image=true, Image=true,
caption=true, Caption=true,
color=true, Color=true, colour=true, Colour=true,
class=true, style=true
}
local function addRow(label, value)
local row = tbl:tag('tr')
row:tag('th'):attr('scope','row'):wikitext(labelFromKey(label))
row:tag('td'):wikitext(value)
end
-- Build a stable order map from the editor's source order if possible
local sourceOrder = {}
if parent.argumentPairs then
local temp = {}
for key, _ in parent:argumentPairs() do
temp[#temp+1] = key
end
for i = #temp, 1, -1 do
sourceOrder[temp[i]] = i
end
elseif parent.getArgumentNames then
local names = parent:getArgumentNames() or {}
for i, key in ipairs(names) do
sourceOrder[key] = i
end
end
-- Collect rows with computed sort keys
local rows = {}
for key, value in pairs(args) do
if not skip[key] and not tonumber(key) and not isBlank(value) then
local forcedN, displayKey = splitOrderPrefix(key)
local srcIndex = sourceOrder[key] or 10^9
rows[#rows+1] = {
forced = forcedN or 10^8,
src = srcIndex,
key = displayKey,
rawkey = key,
value = value
}
end
end
-- Sort: first by explicit numeric prefix (if any), then by source order
table.sort(rows, function(a,b)
if a.forced ~= b.forced then
return a.forced < b.forced
end
return a.src < b.src
end)
-- Render rows
for _, r in ipairs(rows) do
addRow(r.key, r.value)
end
return tostring(tbl)
end
return p