Module:Infobox: Difference between revisions
From koreapedia
Created page with "-- Module:Infobox -- Minimal, dependency-free infobox builder that outputs HTML. -- All styling comes from your site CSS classes (e.g., .infobox, .infobox-label). local p = {} local function isNonEmpty(s) if type(s) ~= "string" then return s ~= nil end return mw.text.trim(s) ~= "" end local function cellText(s) if not isNonEmpty(s) then return nil end return mw.text.trim(s) end -- Render an File:... wikitext for the image; callers pass only the filename. local..." |
No edit summary |
||
(4 intermediate revisions by the same user not shown) | |||
Line 1: | Line 1: | ||
-- Module:Infobox | -- Module:Infobox (robust) | ||
-- | -- Outputs HTML with shared CSS classes; auto-hides empty rows. | ||
-- | -- Tolerant to underscore/space mismatches and safe in previews. | ||
local p = {} | local p = {} | ||
local function | -- ---------- helpers ---------- | ||
local function trim(s) | |||
if type(s) ~= "string" then return s end | |||
return mw.text.trim(s) | |||
end | end | ||
local function | local function isNonEmpty(v) | ||
if v == nil then return false end | |||
if type(v) ~= "string" then return true end | |||
return mw.text.trim(v) ~= "" | |||
end | end | ||
local function renderImage(filename, size) | local function renderImage(filename, size) | ||
if not isNonEmpty(filename) then return nil end | |||
size = size or "280px" | |||
return string.format("[[File:%s|%s|center]]", trim(filename), size) | |||
end | |||
local function splitPipeList(s) | |||
local t = {} | |||
if not isNonEmpty(s) then return t end | |||
for seg in tostring(s):gmatch("([^|]+)") do | |||
seg = mw.text.trim(seg) | |||
if seg ~= "" then table.insert(t, seg) end | |||
end | |||
return t | |||
end | end | ||
-- | -- Turn a raw website value into a clickable external link | ||
local function linkifyWebsite(value) | |||
if not isNonEmpty(value) then return nil end | |||
local url = trim(value) | |||
-- Prepend protocol if missing | |||
if not url:match("^https?://") then | |||
url = "https://" .. url | |||
end | |||
-- Extract domain for short label (remove protocol and trailing slash) | |||
local label = url:gsub("^https?://", ""):gsub("/$", "") | |||
-- Return wikitext external link format | |||
return string.format("[%s %s]", url, label) | |||
end | |||
-- try multiple key variants in user args: "birth_place" <-> "birth place" | |||
local function getUserValue(user, key) | |||
if not isNonEmpty(key) then return nil end | |||
local k1 = key | |||
local k2 = key:gsub("_", " ") | |||
local k3 = key:gsub(" ", "_") | |||
return user[k1] or user[k2] or user[k3] | |||
end | |||
-- ---------- core builder ---------- | |||
local function buildTable(args) | local function buildTable(args) | ||
local root = mw.html.create("table"):addClass("infobox") | |||
-- Title | |||
local title = args.title or args.name or mw.title.getCurrentTitle().text | |||
root:tag("tr") | |||
:tag("th") | |||
:attr("colspan", "2") | |||
:addClass("infobox-title") | |||
:wikitext(title) | |||
-- Image | |||
local image = renderImage(args.image, args.image_size) | |||
if image then | |||
root:tag("tr") | |||
:tag("td") | |||
:attr("colspan", "2") | |||
:addClass("infobox-image") | |||
:wikitext(image) | |||
end | |||
-- Caption | |||
if isNonEmpty(args.caption) then | |||
root:tag("tr") | |||
:tag("td") | |||
:attr("colspan", "2") | |||
:addClass("infobox-caption") | |||
:wikitext(args.caption) | |||
end | |||
-- Numbered rows | |||
local maxRows = tonumber(args.maxrows) or 50 | |||
for i = 1, maxRows do | |||
local label = trim(args["label"..i] or "") | |||
local data = trim(args["data"..i] or "") | |||
if isNonEmpty(label) or isNonEmpty(data) then | |||
local tr = root:tag("tr") | |||
tr:tag("th"):addClass("infobox-label"):wikitext(label or "") | |||
tr:tag("td"):addClass("infobox-data") :wikitext(data or "") | |||
end | |||
end | |||
return tostring(root) | |||
end | end | ||
-- Direct builder for numbered label/data pairs | |||
function p.build(frame) | function p.build(frame) | ||
local args = {} | |||
-- parent args | |||
if type(frame.getParent) == "function" then | |||
local parent = frame:getParent() | |||
if parent and parent.args then | |||
for k, v in pairs(parent.args) do args[k] = v end | |||
end | |||
end | |||
-- direct args | |||
if frame and frame.args then | |||
for k, v in pairs(frame.args) do args[k] = v end | |||
end | |||
return buildTable(args) | |||
end | |||
-- Smart builder: wrappers pass Label=paramName; only non-empty values render. | |||
function p.smart(frame) | |||
-- safe parent | |||
local parent = nil | |||
if type(frame.getParent) == "function" then | |||
parent = frame:getParent() | |||
end | |||
-- values supplied by the article transclusion | |||
local user = (parent and parent.args) or frame.args or {} | |||
-- wrapper map (Label=paramKey), plus optional "order" | |||
local map = frame.args or {} | |||
local newArgs, added = {}, 0 | |||
local function addRow(label, key) | |||
local value = getUserValue(user, key) | |||
if isNonEmpty(value) then | |||
-- Auto-link website fields | |||
if label:lower():match("website") then | |||
value = linkifyWebsite(value) | |||
end | |||
added = added + 1 | |||
newArgs["label"..added] = label | |||
newArgs["data"..added] = value | |||
end | end | ||
end | |||
-- explicit order first | |||
local orderList = splitPipeList(map.order) | |||
for _, label in ipairs(orderList) do | |||
local key = map[label] | |||
if isNonEmpty(key) then addRow(label, key) end | |||
end | |||
-- remaining labels | |||
for label, key in pairs(map) do | |||
if label ~= "order" and type(label) == "string" then | |||
local already = false | |||
for _, ol in ipairs(orderList) do if ol == label then already = true; break end end | |||
if not already and isNonEmpty(key) then addRow(label, key) end | |||
end | |||
end | |||
-- headers | |||
newArgs.title = user.title or user.name or mw.title.getCurrentTitle().text | |||
newArgs.image = getUserValue(user, "image") | |||
newArgs.image_size = getUserValue(user, "image_size") | |||
newArgs.caption = getUserValue(user, "caption") | |||
newArgs.maxrows = user.maxrows or 50 | |||
return buildTable(newArgs) | |||
end | end | ||
return p | return p |
Latest revision as of 18:15, 8 October 2025
Documentation for this module may be created at Module:Infobox/doc
-- Module:Infobox (robust)
-- Outputs HTML with shared CSS classes; auto-hides empty rows.
-- Tolerant to underscore/space mismatches and safe in previews.
local p = {}
-- ---------- helpers ----------
local function trim(s)
if type(s) ~= "string" then return s end
return mw.text.trim(s)
end
local function isNonEmpty(v)
if v == nil then return false end
if type(v) ~= "string" then return true end
return mw.text.trim(v) ~= ""
end
local function renderImage(filename, size)
if not isNonEmpty(filename) then return nil end
size = size or "280px"
return string.format("[[File:%s|%s|center]]", trim(filename), size)
end
local function splitPipeList(s)
local t = {}
if not isNonEmpty(s) then return t end
for seg in tostring(s):gmatch("([^|]+)") do
seg = mw.text.trim(seg)
if seg ~= "" then table.insert(t, seg) end
end
return t
end
-- Turn a raw website value into a clickable external link
local function linkifyWebsite(value)
if not isNonEmpty(value) then return nil end
local url = trim(value)
-- Prepend protocol if missing
if not url:match("^https?://") then
url = "https://" .. url
end
-- Extract domain for short label (remove protocol and trailing slash)
local label = url:gsub("^https?://", ""):gsub("/$", "")
-- Return wikitext external link format
return string.format("[%s %s]", url, label)
end
-- try multiple key variants in user args: "birth_place" <-> "birth place"
local function getUserValue(user, key)
if not isNonEmpty(key) then return nil end
local k1 = key
local k2 = key:gsub("_", " ")
local k3 = key:gsub(" ", "_")
return user[k1] or user[k2] or user[k3]
end
-- ---------- core builder ----------
local function buildTable(args)
local root = mw.html.create("table"):addClass("infobox")
-- Title
local title = args.title or args.name or mw.title.getCurrentTitle().text
root:tag("tr")
:tag("th")
:attr("colspan", "2")
:addClass("infobox-title")
:wikitext(title)
-- Image
local image = renderImage(args.image, args.image_size)
if image then
root:tag("tr")
:tag("td")
:attr("colspan", "2")
:addClass("infobox-image")
:wikitext(image)
end
-- Caption
if isNonEmpty(args.caption) then
root:tag("tr")
:tag("td")
:attr("colspan", "2")
:addClass("infobox-caption")
:wikitext(args.caption)
end
-- Numbered rows
local maxRows = tonumber(args.maxrows) or 50
for i = 1, maxRows do
local label = trim(args["label"..i] or "")
local data = trim(args["data"..i] or "")
if isNonEmpty(label) or isNonEmpty(data) then
local tr = root:tag("tr")
tr:tag("th"):addClass("infobox-label"):wikitext(label or "")
tr:tag("td"):addClass("infobox-data") :wikitext(data or "")
end
end
return tostring(root)
end
-- Direct builder for numbered label/data pairs
function p.build(frame)
local args = {}
-- parent args
if type(frame.getParent) == "function" then
local parent = frame:getParent()
if parent and parent.args then
for k, v in pairs(parent.args) do args[k] = v end
end
end
-- direct args
if frame and frame.args then
for k, v in pairs(frame.args) do args[k] = v end
end
return buildTable(args)
end
-- Smart builder: wrappers pass Label=paramName; only non-empty values render.
function p.smart(frame)
-- safe parent
local parent = nil
if type(frame.getParent) == "function" then
parent = frame:getParent()
end
-- values supplied by the article transclusion
local user = (parent and parent.args) or frame.args or {}
-- wrapper map (Label=paramKey), plus optional "order"
local map = frame.args or {}
local newArgs, added = {}, 0
local function addRow(label, key)
local value = getUserValue(user, key)
if isNonEmpty(value) then
-- Auto-link website fields
if label:lower():match("website") then
value = linkifyWebsite(value)
end
added = added + 1
newArgs["label"..added] = label
newArgs["data"..added] = value
end
end
-- explicit order first
local orderList = splitPipeList(map.order)
for _, label in ipairs(orderList) do
local key = map[label]
if isNonEmpty(key) then addRow(label, key) end
end
-- remaining labels
for label, key in pairs(map) do
if label ~= "order" and type(label) == "string" then
local already = false
for _, ol in ipairs(orderList) do if ol == label then already = true; break end end
if not already and isNonEmpty(key) then addRow(label, key) end
end
end
-- headers
newArgs.title = user.title or user.name or mw.title.getCurrentTitle().text
newArgs.image = getUserValue(user, "image")
newArgs.image_size = getUserValue(user, "image_size")
newArgs.caption = getUserValue(user, "caption")
newArgs.maxrows = user.maxrows or 50
return buildTable(newArgs)
end
return p