Module:Infobox

local p = {}

local function table_print (tt, indent, done) done = done or {} indent = indent or 0 if type(tt) == "table" then local sb = {} for key, value in pairs (tt) do     table.insert(sb, string.rep (" ", indent)) -- indent it      if type (value) == "table" and not done [value] then done [value] = true table.insert(sb, "{\n"); table.insert(sb, table_print (value, indent + 2, done)) table.insert(sb, string.rep (" ", indent)) -- indent it       table.insert(sb, "}\n"); elseif "number" == type(key) then table.insert(sb, string.format("\"%s\"\n", tostring(value))) else table.insert(sb, string.format( "%s = \"%s\"\n", tostring (key), tostring(value))) end end return table.concat(sb) else return tt .. "\n" end end

local function to_string( tbl ) if "nil"       == type( tbl ) then return tostring(nil) elseif "table" == type( tbl ) then return table_print(tbl) elseif "string" == type( tbl ) then return tbl else return tostring(tbl) end end

local langNames = mw.loadData( Module:Language/Names ) local code = function( title ) local subPage = ( title or mw.title.getCurrentTitle ).subpageText:lower if langNames[subPage] then return subPage end end local pageSuffix = function local langCode = code if langCode then return '/' .. langCode end return '/en' end

local strings = require("Module:Infobox/strings" .. pageSuffix)

local infoboxName = nil local infoboxDefinition = nil local infoboxFormat = nil

local function loadInfoboxData(frame) infoboxName = frame.args[1] or "thing" infoboxDefinition = require("Module:Infobox/" .. infoboxName .. pageSuffix) infoboxFormat = infoboxDefinition.format end

local function trim(s) -- from PiL2 20.4 return (s:gsub("^%s*(.-)%s*$", "%1")) end

local function __genOrderedIndex( t ) local orderedIndex = {} for key in pairs(t) do       table.insert( orderedIndex, key ) end table.sort( orderedIndex, function(left, right)       if type(left) == "table" then            left = left[1]        end        if type(right) == "table" then            right = right[1]        end        return left < right    end) return orderedIndex end

local function orderedNext(t, state) -- Equivalent of the next function, but returns the keys in the alphabetic -- order. We use a temporary ordered key table that is stored in the -- table being iterated.

--print("orderedNext: state = "..tostring(state) ) if state == nil then -- the first time, generate the index t.__orderedIndex = __genOrderedIndex( t ) key = t.__orderedIndex[1] return key, t[key] end -- fetch the next value key = nil for i = 1,table.getn(t.__orderedIndex) do       if t.__orderedIndex[i] == state then key = t.__orderedIndex[i+1] end end

if key then return key, t[key] end

-- no more value to return, cleanup t.__orderedIndex = nil return end

local function orderedPairs(t) -- Equivalent of the pairs function on tables. Allows to iterate -- in order return orderedNext, t, nil end

-- Using the given frame as context, produce the string required for argdata. local function resolveArgument(frame, argdata) if not argdata then return nil end if type(argdata) == "string" then return argdata end

local text = frame.args[argdata.arg] if type(argdata.arg) == "table" then for i,name in ipairs(argdata.arg) do           if not text then text = frame.args[name] end end end if (not text) then return argdata.default end

text = trim(text) if (text == "") then return nil end out = "" if not argdata.type then out = text elseif argdata.type == "text" then out = text elseif argdata.type=="image" then out = '' elseif argdata.type=="switch" then local data = argdata.allowedValues[text] if string.find(text, "") then out = text elseif (not data) then -- TODO: Only in main! out = '??? '       else out = data end end if argdata.units then out = out .. " " .. argdata.units end return out end

local function resolveArgumentCanonicalName(argdata) if not argdata then return nil end if type(argdata.arg) == "table" then return argdata.arg[1] else return argdata.arg end end

local function curryResolveArg(frame) return function(argdata) return resolveArgument(frame, argdata) end end

local function renderInfobox(effectiveBox, class) result = {} local out = function(thing) result[#result+1] = thing end out(" ") return table.concat(result, "") end

function p.infobox(frame) loadInfoboxData(frame)

local argFrame = frame if frame.args.fromParent then argFrame = frame:getParent end local resolveArg = curryResolveArg(argFrame) effectiveBox = {} for i,section in ipairs(infoboxFormat) do       local newSection = { title = resolveArg(section.title)} for j,subsection in ipairs(section) do           local newSubsection = {} for k,row in ipairs(subsection) do               local newRow = { resolveArg(row[1]), resolveArg(row[2])} if (#row == #newRow) then newSubsection[#newSubsection+1] = newRow end end if not (#newSubsection == 0) then newSection[#newSection+1] = newSubsection end end if not (#newSection == 0) then effectiveBox[#effectiveBox+1] = newSection end end --return table_print(effectiveBox) return renderInfobox(effectiveBox, frame.args.class) end

local function parameterList parameters = {} for i,section in ipairs(infoboxFormat) do       if type(section.title) == "table" then parameters[#parameters + 1] = section.title end for j,subsection in ipairs(section) do           for k,row in ipairs(subsection) do                for m,cell in ipairs(row) do                    if type(cell) == "table" then parameters[#parameters + 1] = cell end end end end end return parameters end

function p.parameterHelp(frame) loadInfoboxData(frame)

local parameters = {} for i,section in ipairs(infoboxFormat) do       local sectiondata = { name = section.name} if (not parameters[#parameters]) or (not (sectiondata.name == parameters[#parameters].name)) then parameters[#parameters+1] = sectiondata else sectiondata = parameters[#parameters] end if type(section.title) == "table" then sectiondata[#sectiondata+1] = section.title end

for j,subsection in ipairs(section) do           for k,row in ipairs(subsection) do                for m,cell in ipairs(row) do                    if (type(cell) == "table") and (cell.desc) then sectiondata[#sectiondata+1] = cell end end end end end local collapseByValue = function(tab) local iv={} for k,v in pairs(tab) do           if not iv[v] then iv[v]={k} else iv[v][#(iv[v]) + 1] = k           end end local s={} for k,v in pairs(iv) do           if not s[v] then s[v]=k end end return s   end

result = "" for i,section in ipairs(parameters) do       if section.name then result = result .. "===" .. section.name .. "===\n" end for j,parameter in ipairs(section) do           local namelist = parameter.arg if type(parameter.arg) == "table" then namelist = table.concat(parameter.arg, " " .. strings.nameorname .. " ") end result = result .. "* '''" .. namelist .. "''': " .. parameter.desc if parameter.type == "switch" then result = result .. " " .. strings.switchdoc .."\n" for key,value in orderedPairs(collapseByValue(parameter.allowedValues)) do                   result = result .. "** " .. table.concat(key, "" .. strings.nameorname .. "''") .. "'': " .. value .. "\n" end else result = result .. "\n" end end end

return result end

function p.emptyBox(frame) loadInfoboxData(frame)

local parameters = parameterList local arglist = {class="infoboxNoCollapse"} for i,parameter in ipairs(parameters) do       local cname = resolveArgumentCanonicalName(parameter) arglist[cname] = "" end return p.infobox({args=arglist}) end

return p