Module:InfoboxLite
Module:InfoboxLite
A lightweight, optimised variant of Module:Infobox.
Identical interface but with the following removed:
- Navbar
- Italic title
- TemplateStyles loading
- Nested wikitable support
- Per-row styling parameters
autoheaderschild/subboxsupport
These were removed because there are currently no use cases for them on the wiki, and calling them 150~ times on content-heavy pages (such as Research) was causing Lua CPU timeouts.
Row handling
Numbered parameters are not capped. Rows are detected from the parameters actually supplied and rendered in ascending numeric order, so gaps are permitted: |data1= and |data5= render as two consecutive rows.
Duplicate indices resolve to the same row: data7 and data007 are treated as one.
List handling
List markup (* and #) is only supported for data and below.
Styling
Only box-level styling parameters are supported, e.g. bodyclass, bodystyle.
Per-row equivalents (class, rowclass, rowstyle, rowcellstyle, imagerowclass, and numbered subheaderstyle) are not supported.
Usage
Use Template:InfoboxLite in place of Template:Infobox. Most parameters are identical; see above for exceptions.
local p = {}
local common = require("Module:Common")
local ustring = mw.ustring
local html = mw.html
-- ---------- Data ----------
local CATEGORY_EMPTY_ROW_REGEX = "%[%[%s*[Cc][Aa][Tt][Ee][Gg][Oo][Rr][Yy]%s*:[^%]]*%]%]"
-- fields that render on their own; a row exists only if one of these is supplied
local INDEXED_FIELDS = {
subheader = true,
image = true,
header = true,
data = true,
}
-- ---------- Helpers ----------
-- strip categories since category links count as non-whitespace, which can cause empty infobox fields to show up
local function hasVisibleText(s)
if not s then return false end
if s:find("%[%[") then s = ustring.gsub(s, CATEGORY_EMPTY_ROW_REGEX, "") end
return s:find("%S") ~= nil
end
-- collect the numeric suffixes actually supplied for each standalone field
local function collectIndices(args)
local found, seen = {}, {}
for field in pairs(INDEXED_FIELDS) do
found[field] = {}
seen[field] = {}
end
for k in pairs(args) do
local field, digits = k:match("^(%a+)(%d+)$")
if field and INDEXED_FIELDS[field] then
local n = tonumber(digits)
if n and not seen[field][n] then
seen[field][n] = true
local list = found[field]
list[#list + 1] = n
end
end
end
for _, list in pairs(found) do table.sort(list) end
return found
end
-- union of header and data indices, since either alone creates a row
local function mergeIndices(a, b)
local seen, merged = {}, {}
for _, list in ipairs({a, b}) do
for _, n in ipairs(list) do
if not seen[n] then
seen[n] = true
merged[#merged + 1] = n
end
end
end
table.sort(merged)
return merged
end
-- process bullet lists to ensure they render correctly
local function fixChildBoxes(s)
if not s:find("[%*#]") then return s end
s = ustring.gsub(s, "([\r\n][%*#;:][^\r\n]*)$", "%1\n") -- trailing newline after a final list item
s = ustring.gsub(s, "^([%*#;:][^\r\n]*)$", "%1\n") -- single-line list: add trailing newline
s = ustring.gsub(s, "^([%*#;:])", "\n%1") -- list starts at char 1: add leading newline
return s
end
-- ---------- Rendering ----------
local function renderAboveRow(root, args)
local above = args.above
if not above then return end
root
:tag("tr")
:tag("th")
:attr("colspan", "2")
:addClass("infobox-above")
:addClass(args.aboveclass)
:cssText(args.abovestyle)
:wikitext(above)
end
local function renderSubheaders(root, args, indices)
if args.subheader and not args.subheader1 then
args.subheader1 = args.subheader
if indices[1] ~= 1 then table.insert(indices, 1, 1) end
end
local subheaderclass = args.subheaderclass
local subheaderstyle = args.subheaderstyle
for _, i in ipairs(indices) do
local val = args["subheader" .. i]
if hasVisibleText(val) then
root
:tag("tr")
:tag("td")
:attr("colspan", "2")
:addClass("infobox-subheader")
:addClass(subheaderclass)
:cssText(subheaderstyle)
:wikitext(val)
end
end
end
local function renderImages(root, args, indices)
if args.image and not args.image1 then
args.image1 = args.image
if indices[1] ~= 1 then table.insert(indices, 1, 1) end
end
if args.caption and not args.caption1 then args.caption1 = args.caption end
local captionstyle = args.captionstyle
local imageclass = args.imageclass
local imagestyle = args.imagestyle
for _, i in ipairs(indices) do
local img = args["image" .. i]
if hasVisibleText(img) then
local caption = args["caption" .. i]
local content
if caption then
local data = html.create()
data:wikitext(img)
data:tag("div")
:addClass("infobox-caption")
:cssText(captionstyle)
:wikitext(caption)
content = tostring(data)
end
root
:tag("tr")
:tag("td")
:attr("colspan", "2")
:addClass("infobox-image")
:addClass(imageclass)
:cssText(imagestyle)
:wikitext(content or img)
end
end
end
local function renderRows(root, args, indices, empty_row_categories)
local headerclass = args.headerclass
local headerstyle = args.headerstyle
local labelstyle = args.labelstyle
local datastyle = args.datastyle
for _, i in ipairs(indices) do
local header = args["header" .. i]
local data = args["data" .. i]
local label = args["label" .. i]
if header and header ~= "_BLANK_" then
root
:tag("tr")
:tag("th")
:attr("colspan", "2")
:addClass("infobox-header")
:addClass(headerclass)
:cssText(headerstyle)
:wikitext(header)
elseif hasVisibleText(data) then
local row = root:tag("tr")
if label then
row
:tag("th")
:attr("scope", "row")
:addClass("infobox-label")
:cssText(labelstyle)
:wikitext(label)
:done()
end
row:tag("td")
:attr("colspan", not label and "2" or nil)
:addClass(not label and "infobox-full-data" or "infobox-data")
:cssText(datastyle)
:wikitext(fixChildBoxes(data))
elseif data then empty_row_categories[#empty_row_categories + 1] = data end
end
end
local function renderBelowRow(root, args)
local below = args.below
if not below then return end
root
:tag("tr")
:tag("td")
:attr("colspan", "2")
:addClass("infobox-below")
:addClass(args.belowclass)
:cssText(args.belowstyle)
:wikitext(fixChildBoxes(below))
end
local function renderEmptyRowCategories(root, empty_row_categories)
for _, s in ipairs(empty_row_categories) do root:wikitext(s) end
end
-- ---------- Main ----------
local function _infobox(origArgs)
local args = {}
for k, v in pairs(origArgs) do
v = common.trim(v)
if v ~= "" then args[k] = v end
end
local indices = collectIndices(args)
local rowIndices = mergeIndices(indices.header, indices.data)
local empty_row_categories = {}
local root = html.create("table")
root
:addClass("infobox")
:addClass(args.bodyclass)
:cssText(args.bodystyle)
if args.title then
root
:tag("caption")
:addClass("infobox-title")
:addClass(args.titleclass)
:cssText(args.titlestyle)
:wikitext(args.title)
end
renderAboveRow(root, args)
renderSubheaders(root, args, indices.subheader)
renderImages(root, args, indices.image)
renderRows(root, args, rowIndices, empty_row_categories)
renderBelowRow(root, args)
renderEmptyRowCategories(root, empty_row_categories)
return tostring(root)
end
-- ---------- Interface ----------
function p.infobox(frame)
local origArgs
if frame == mw.getCurrentFrame() then origArgs = frame:getParent().args
else origArgs = frame end
return _infobox(origArgs)
end
function p.infoboxTemplate(frame)
return _infobox(frame.args)
end
return p