Documentation for this module may be created at Module:Multi-section template/doc
-- This module takes a list of parameters (of two types) and a template name
-- It can then create multiple layers of that same template under section headers
-- When a page wants to use the multi-layered template, it can define section names
--- with "sec 1", "sec 2" etc. It can give a title to the tabber with "tabber"
-- To assign values for each section, they can be prefixed by their tab number,
--- e.g. "1 name"
-- Parameters can be "override" or "additive".
-- "override" means "1 name" will be used instead of "name".
-- "additive" means "1 name" will appear a line after "name".
-- Section names can be formatted from given parameters (as long as they are
--- unique to the tab)
p = {}
local getArgs = require('Dev:Arguments').getArgs
local params = {
override = {},
additive = {}
}
local templatename
local sectionheaderformat = {}
-- format has parameters put in [], e.g. "#[bestiary]"
-- first tab's would be "#{{{1 bestiary}}}", second "#{{{2 bestiary}}}" etc.
-- multiple formats can be used, semi-colon separated, in order of priority
-- a format will only be used if all the contained parameters are used
-- "tab 1" etc. has highest priority and doesn't need to be stated
function p.main(frame)
-- PARAMETERS FOR THE MODULE
--- "override parameters", a ";"-separated list of override parameters
---- or a {} if used in Lua
--- "additive parameters", a ";"-separated list of additive parameters
---- or a {} if used in Lua
--- "default tabber title", the default tabber title
--- "template pagename", the page name of the template
--- "template type", type of template. "infobox"
--- "tab name format", a ";"-separated list of formats in priority order
local args = getArgs(frame)
-- split a string by semicolons, filter out whitespace-only parts, and trim
-- whitespace
local function splitter(str)
if type(str) ~= "string" then
return str
end
local parts = {}
for part in mw.text.gsplit(str, ";") do
if not part:find("^%s+$") then
table.insert(parts, mw.text.trim(part))
end
end
return parts
end
for _, v in ipairs{"override", "additive"} do
local tmp = args[v .. " parameters"]
if tmp then
params[v] = splitter(tmp)
end
end
if args["section header format"] then
local formats = splitter(args["section header format"])
for _, f in ipairs(formats) do
local parameters = {}
local format, count = f:gsub("%[([^%]]*)%]", function (capture)
-- this overwrites `parameters` on each iteration, effectively
-- storing the last capture in a table. might be a bug? idk
parameters = {capture}
return "%s"
end)
if count == 0 then
return require "Module:HF".err("Section format '" .. format .. "' contains no parameters. Parameters are enclosed in square brackets.")
end
table.insert(sectionheaderformat, {format = format, parameters = parameters})
end
end
templatename = args["template pagename"]
local struct = p.structure(args)
return p.create(struct)
end
-- The creation of the table structure
function p.structure(args, prefix)
if not prefix then
prefix = {}
end
local o = {}
local thisprefix = prefix[#prefix] and (prefix[#prefix] .. " ") or ""
if p.secname(args, (thisprefix .. 1)) then
o.section = args -- likely is causing an error
o.sect = p.secname(args, mw.text.trim(thisprefix))
o._depth = #prefix
end
for i = 1, 255 do
table.insert(prefix, thisprefix .. i)
if p.secname(args, (thisprefix .. i .. " " .. 1)) then
table.insert(o, p.structure(args, prefix))
else
table.insert(o, p.consolidateArgs(args, prefix))
end
table.remove(prefix)
if not p.secname(args, (thisprefix .. i + 1)) then
break
end
end
return o
end
-- The consolidation of template parameters into individual tables
function p.consolidateArgs(a, prefix)
-- prefix is an array of prefixed from least to most important
local o = {}
o._depth = #prefix
-- returned is a table of final args
for _, parameter in ipairs(params.override) do
local value
for j = #prefix, 1, -1 do
value = a[prefix[j] .. " " .. parameter]
if value then
break
end
end
o[parameter] = value or a[parameter]
end
for _, parameter in ipairs(params.additive) do
local list = {}
local value
if a[parameter] then
table.insert(list, a[parameter])
end
for _, val in ipairs(prefix) do
local k = val .. " " .. parameter
if a[k] then
table.insert(list, a[k])
end
end
if #list > 0 then
value = list[1]
for j = 2, #list do
value = value .. "<br/>" .. list[j]
end
end
o[parameter] = value
end
o.sect = p.secname(a, prefix[#prefix])
return o
end
-- The determining of section names
function p.secname(a, prefix)
-- a is the args table
-- prefix is the prefix /STRING/ -- not the table
if prefix == "" then
return "You should never see this"
end
local thissecname = a[mw.text.trim("sec " .. prefix)]
if not thissecname then
for i, thisformat in ipairs(sectionheaderformat) do
local allparams = true
for _, p in ipairs(thisformat.parameters) do
if not a[mw.text.trim(prefix .. " " .. p)] then
allparams = false
end
end
if allparams then
local secparams = {}
for _, p in ipairs(thisformat.parameters) do
secparams[i] = a[mw.text.trim(prefix .. " " .. p)]
end
thissecname = thisformat.format:format(unpack(secparams))
break
end
end
end
return thissecname
end
-- The output
function p.create(data)
local container = mw.html.create("div") -- things are just easier with a container
for _, val in ipairs(data) do
if #data ~= 1 then
container:tag("h" .. (val._depth + 2)):wikitext(val.sect)
end
if val.section then
container:node(p.create(val))
else
container:wikitext(p.sect(val))
end
end
return container
end
-- The template expanding
function p.sect(data)
if templatename:sub(1, 7) == "Module:" then
return require(templatename).init(data)
end
return mw.getCurrentFrame():expandTemplate({
title = templatename,
args = data
})
end
return p