Module:Infobox

--[=[ -- For documentation, see Module:Infobox/doc --]=]

-- local Infobox = {} Infobox.__index = Infobox Infobox.__tostring = Infobox.tostring

-- Edit button for unknown params local editbutton = require('Module:Edit button') local edit = editbutton("? (edit)")

-- Page title local pagename = mw.title.getCurrentTitle.fullText

-- map of flags to html tags used by Infobox.addRow -- let's only define it once, since :addRow is used multiple times per module local tagmap = { tr = 'tr', th = 'th', td = 'td', argh = 'th', argd = 'td' }

--[=[ -- Standardized functions -- called as string with defineParams --]=]

-- Standardized "has content" function function hasContent(arg, default) -- Return arg if any non-whitespace character is found return string.match(arg or '','%S') and arg or default end

-- Standardized "name" function function subjectName(arg) return string.match(arg or '','%S') and arg or nil end

-- Create a standardized release function, since so many pages use it -- Turns release and update into a single parameter function releaseUpdate(release,update) -- "release (Update)" or	-- "release (update unknown)" or	-- unknown if release and release:find('%S') then if update and update:find('%S') then return string.format('%s (Update)',release,update) else return string.format('%s (Update unknown)',release) end else return nil end end

-- Standardized image function function image(img) if img and img:find('%S') then return img else return nil end end

-- Standardized numbers function numbers(num) num = string.gsub(num or ,',',) return tonumber(num) end

-- map of names to pre-defined functions, used by Infobox:defineParams local func_map = { name = subjectName, release = { name = releaseUpdate, params = { 'release', 'update' }, flag = 'p' }, removal = { name = releaseUpdate, params = { 'removal', 'removalupdate' }, flag = 'p' }, has_content = hasContent, hasContent = hasContent, image = image, numbers = numbers, }

-- used to fill nil params in switching sections -- this message isn't kidding -- If you see this message anywhere outside of this code -- (including inside switchfo box data) -- report it local nil_param = 'UH OH YOU SHOULDN\'T SEE THIS!'

-- In case the nil_param is needed outside of this module -- give it an easy way to be accessed function Infobox.nilParam return nil_param end

-- quick test to see if a value is considered nil function Infobox.isDefined(arg) if arg == nil then return false end

if type(arg) == 'string' then if arg == nil_param then return false elseif arg:find('%S') then if arg:find('action=edit') then return false else return true end else return false end end

return true end

--	Infobox class	-- args : parameters from frame to pass through	-- Sets a meta table and creates a tag wrapper	-- other fields are initialized in other functions -- function Infobox.new(args) local rdiv = mw.html.create('div') :addClass('infobox-wrapper')

local obj = setmetatable({				args = args, -- parameters (uncleaned)				rargs = {}, -- parameters (cleaned)				params = {}, -- parameters mapped to functions				paramnames = {}, -- parameter names				dupeable = {}, -- parameters that are allowed to have duplicated switch data				switchfo = false, -- switch infobox? or not?				switchfoattr = {}, -- switch data class changes				maxbuttons = 5, -- maximum number of buttons before switching becomes a menu				rdiv = rdiv, -- returned div wrapper				rtable = nil, -- returned infobox table				labels = nil, -- returned labels				_smw = { -- semantic mediawiki data						members = 'Is members only',						release = 'Release date'				},				_smwOne = {}, -- semantic mediawiki data part 2				versions = -1, -- number of switch versions (-1 is uncalculated)				infoboxname = nil, -- template name				bottomlinks = { -- template bottom links						{ 'Template talk:%s', 'talk' }, { 'Template:%s', 'view' }, },				catdata = {}, -- meta category data catlist = {}, -- defined table of category names (strings) __finished = false, -- infobox status },			Infobox)	return obj end

--	Creates an infobox	-- If Infobox:maxVersions has not been run, it will be run here	-- If the infobox should be a switch infobox, all labels will be added	-- Creates a wikitable that will be the infobox	THIS SHOULD BE DONE AFTER ADDING AND CLEANING PARAMETERS -- function Infobox:create -- Run to find if this is a switch infobox and if so, how many boxes if self.versions == -1 then self:maxVersion end -- Run if switch infobox if self.switchfo then -- Buttons wrapper -- Hidden by default, unhidden by javascript local btns = self.rdiv:tag('div') :addClass('infobox-buttons')

-- default version to immediately switch to via js		local defv = tonumber(self.args.defver) if defv and defv <= self.versions then -- you troll, don't try to show something that isn't there btns:attr('data-default-version',defv) end

-- Used by JavaScript to turn the buttons into a menu list if too many variants if self.versions > self.maxbuttons then btns:addClass('infobox-buttons-select') end

-- Add individual buttons to the wrapper for i=1,self.versions do			btns:tag('span') :attr('data-switch-index',tostring(i)) -- space to underscore :attr('data-switch-anchor','#'..string.gsub(self.labels[i] or i,' ','_')) :addClass('button') :wikitext(self.labels[i] or i)				:done end btns:done end

-- Create infobox table self.rtable = self.rdiv:tag('table') :addClass('rsw-infobox') :addClass('plainlinks') -- Add necessary class if switch infobox if self.switchfo then self.rtable:addClass('infobox-switch') end

end

-- Defines an infobox name -- Used to create a link at the bottom of pages function Infobox:defineName(arg) self.infoboxname = arg end

-- Defines the bottom links of the infobox -- pass a table whose elements are tables that define a link and a label -- { --	{ 'link', 'label }, --	... -- } -- The template name can be substituted into the tables using '%s' -- If we wanted Template:InFooBar to link to it's /doc page with a "doc" label: -- { ... --	{ 'Template:%s/doc', 'doc' }, -- ... } -- The template's name can only be called 5 times function Infobox:defineLinks(arg) if type(arg) == 'table' then self.bottomlinks = arg end end

-- Change max number of buttons before switching to menu -- defaults to 5 -- MUST BE RUN BEFORE :create function Infobox:setMaxButtons(arg) -- if not a number, just go back to default self.maxbuttons = tonumber(arg) or 5 end

--[[	Add parameters functions	All parameters should be tables	The first parameter defines the type of cell to create		-- th : 		-- td : 		-- argh : 		-- argd : 	The second parameter defines what is inside the tag		-- th | th : text passed		-- argh | argd : parameter with the name passed	Additional named parameters can be used to add any styling or attributes		-- attr : mw.html:attr({ arg1 = '1', ... })		-- css : mw.html:css({ arg1 = '1', ...)		-- class : mw.html:addClass('arg')		 class also supports a table of values, even though mw.html:addClass does not		-- rowspan : mw.html:attr('rowspan',arg)		-- colspan : mw.html:attr('colspan',arg)		-- title : mw.html:attr('title',arg)	Example:		ipsobox:addRow( { 'th', 'Header', title = 'Title' },				{ 'argh', 'arg1', class = 'parameter' } })	produces:		 Header args.arg1

adding it to the infobox table of ipsobox

Cells defined as 'argh' and 'argd' will automatically have data-attr-param="" added, and defined as the passed argument if the infobox in creation is defined as a switch infobox

The row itself may be modified with metadata using the named index at "meta" -- meta.addClass : mw.html:addClass('arg') -- this function currently only supports a single string --]] function Infobox.addRow(box, ...) -- New row to add local args = ... local _row = box.rtable:tag('tr') -- For each member of tags for i, v in ipairs(args) do		-- map tag name to appropriate tag, default to 		local _cell = _row:tag(tagmap[v.tag] or 'td')

-- mw.html:attr and mw.html:css both accept table input -- colspan, rowspan, title will be quick ways to access attr -- these functions also do all the necessary work if v.attr then _cell:attr(v.attr) end if v.colspan then _cell:attr('colspan',v.colspan) end if v.rowspan then _cell:attr('rowspan',v.rowspan) end if v.title then _cell:attr('title',v.title) end if v.css then _cell:css(v.css) end

-- if class is a string, it can be added directly -- if a table, add every value -- mw.html:addClass doesn't function with tables -- so iterate over the class names here and add them individually if v.class then if type(v.class) == 'string' then _cell:addClass(v.class) elseif type(v.class) == 'table' then for _, w in ipairs(v.class) do					_cell:addClass(w) end end end

-- if the cell is a normal th or td, add the exact argument passed if v.tag == 'th' or v.tag == 'td' then _cell:wikitext(v.content) -- if defined with "arg", add the argument with name passed elseif v.tag == 'argh' or v.tag == 'argd' then local content = box.rargs[v.content] -- if the requested parameter doesn't exist whatsoever, just return a blank string if not content then content = '' -- If switches exist, first attempt to use the version1 values elseif content.switches then if content.switches[1] ~= nil_param then content = content.switches[1] or '' else content = content.d or '' end -- fallback to default value else content = content.d or '' end

_cell:wikitext(content)

-- add necessary attribute for switch infoboxes if box.switchfo then _cell:attr('data-attr-param',v.content) end end end

-- not that meta -- allow classes to be defined on the whole row -- okay, sort of meta if args.meta then if args.meta.addClass then _row:addClass(args.meta.addClass) end end

return box end

--	-- functions the same as mw.html:wikitext on the wrapper	-- Should only be used for categories really -- function Infobox.wikitext(box, arg) box.rdiv:wikitext(arg) return box end

--	-- Adds a caption to the infobox	-- defaults to the pagename	-- or the default argument if defined -- function Infobox.caption(box) -- default to the article's name local name = pagename -- first see if the name parameter exists if box.rargs.name then -- then try the default if box.rargs.name.d then name = box.rargs.name.d		-- then look for swithes elseif box.rargs.name.switches then -- then look at version 1 if box.rargs.name.switches[1] ~= nil_param then name = box.rargs.name.switches[1] end end end

local caption = box.rtable:tag('caption') :wikitext(name)

-- add necessary attribute for switch infoboxes if box.switchfo then caption:attr('data-attr-param','name') end

return box end

--	-- Functions for styling the infobox	-- works the same as the respective mw.html functions -- -- attr function Infobox.attr(box, arg) box.rtable:attr(arg) return box end

-- css function Infobox.float(box,float) box.rdiv:css('float',float) return box end

function Infobox.css(box, ...) box.rtable:css(...) return box end

-- addClass function Infobox.addClass(box, arg) box.rtable:addClass(arg) return box end

-- Much like Infobox.addClass, but adds multiple classes function Infobox.addClasses(box, ...) for _, v in ipairs(...) do		box.rtable:addClass(box) end return box end

--	Add tags directly to the infobox table	Use sparingly	Returns the tag created rather than the entire box	Which is an mw.html object	Further uses of :tag will be mw.html.tag, rather than Infobox.tag	As such, Infobox:addRow cannot be used afterwards without restating the infobox as the object -- function Infobox.tag(box, arg) return box.rtable:tag(arg) end

--[[	Allows the infobox to use Semantic Media Wiki and give parameters properties	Pass a table to this function to map parameter names to properties

Calling syntax: -- :	-- " " - unqualified and without a number will display the default value -- "" - with a number will show the switch data from that index -- "all " - adding all will display every unique value in a comma separated list

Properties initiated in Infobox:finish --]] function Infobox:useSMW(arg) if type(arg) == 'table' or true then for w, v in pairs(arg) do			self._smw[w] = v		end end end --[[	As above, but only assigns to " ", which will act like "all " - " #" not present

Properties initiated in Infobox:finish --]] function Infobox:useSMWOne(arg) if type(arg) == 'table' or true then for w, v in pairs(arg) do			self._smwOne[w] = v		end end end --	Finishing function	-- Finishes the return, adding necessary final tags -- function Infobox:finish local onmain = mw.title.getCurrentTitle.namespace == 0 -- Don't finish twice if self.__finished then return end

-- Add switch infobox resources if self.switchfo then -- Wrapper tag, hidden local res_tag = self.rdiv:tag('div') :addClass('infobox-switch-resources') :addClass('hidden')

for _, v in ipairs(self.paramnames) do			local param = self.rargs[v] -- Parameters may not have any switches data, those are ignored if param.switches then local switchattr = self.switchfoattr[v] -- Parameter data wrapper local res_span = res_tag:tag('span') :attr('data-attr-param',v) -- Child for default value local def = res_span:tag('span') :attr('data-attr-index',0) :wikitext(tostring(param.d or edit))

-- Switch classes if switchattr then def:attr('data-addclass',switchattr.d)				end

def:done

-- Add all switches, ignore those defined as nil for i, w in ipairs(param.switches) do					if w ~= nil_param and w ~= nil then local _w = res_span:tag('span') :attr('data-attr-index',i) :wikitext(tostring(w)) -- Switch classes if switchattr then _w:attr('data-addclass',switchattr.switches[i]) end

_w:done end end res_span:done end end

-- Add a tracking category for mainspace pages that have more than 1 version if onmain then -- version count data res_tag:tag('span') :wikitext(string.format('Versions: Version count::%s',self.versions)) :done res_tag:wikitext('') end

res_tag:done end

-- smw data if onmain then -- members smw display, yes --> true; no --> false; other --> unknown local function smwMembers(smw_arg) local smw_argv = string.lower(smw_arg or '') if smw_argv == 'yes' then return 'true' elseif smw_argv == 'no' then return 'false' else return 'unknown' end end

-- release date smw display local function smwRelease(smw_arg) local _d,_m,_y = string.match(smw_arg or '', '%[%[(%d%d?) (%a+)%]%] %[%[(%d%d%d%d)%]%]') return table.concat({_d,_m,_y},' ') end

-- default, just return the text local function smwDefault(smw_arg) if smw_arg ~= nil_param and smw_arg ~= edit then return smw_arg else return 'unknown' end end

local smw_to_func = { members = smwMembers, release = smwRelease, default = smwDefault }		local smw_data_arr = {}

-- custom properties for w, v in pairs(self._smw) do			-- only needed to give special formatting to release -- and to make members true/false local smwfunc = smw_to_func[w] or smw_to_func.default

local curarg = self.rargs[w] if curarg then local _arg = curarg.d				local argdefault = _arg if _arg == edit then argdefault = 'Unknown' else local temp_smw_data = smwfunc(_arg) if not smw_data_arr[v] then smw_data_arr[v] = {} end table.insert(smw_data_arr[v], temp_smw_data) if not smw_data_arr['All '..v] then smw_data_arr['All '..v] = {} end table.insert(smw_data_arr['All '..v], temp_smw_data) end

if curarg.switches then local _args = {}

for _, x in ipairs(curarg.switches) do						if x ~= nil_param then table.insert(_args,x) else table.insert(_args,argdefault or nil_param) end end

for i, x in ipairs(_args) do						local temp_smw_data = smwfunc(x) if not smw_data_arr[v..i] then smw_data_arr[v..i] = {} end table.insert(smw_data_arr[v..i], temp_smw_data) if not smw_data_arr['All '..v] then smw_data_arr['All '..v] = {} end table.insert(smw_data_arr['All '..v], temp_smw_data) end end end end for w, v in pairs(self._smwOne) do			-- only needed to give special formatting to release -- and to make members true/false local smwfunc = smw_to_func[w] or smw_to_func.default

local curarg = self.rargs[w] local _arg = curarg.d			local argdefault = _arg if _arg == edit then argdefault = 'Unknown' end if curarg then if curarg.switches then local _args = {}

for _, x in ipairs(curarg.switches) do						if x ~= nil_param then table.insert(_args,x) else table.insert(_args,argdefault or nil_param) end end

for i, x in ipairs(_args) do						local _x = mw.text.split(x, '&&SPLITPOINT&&', true) for _,y in ipairs(_x) do							local temp_smw_data = smwfunc(y) if not smw_data_arr[v] then smw_data_arr[v] = {} end table.insert(smw_data_arr[v], temp_smw_data) end end else if _arg ~= edit then local _targ = mw.text.split(_arg, '&&SPLITPOINT&&', true) for _,y in ipairs(_targ) do							local temp_smw_data = smwfunc(y) if not smw_data_arr[v] then smw_data_arr[v] = {} end table.insert(smw_data_arr[v], temp_smw_data) end end end end end local res = mw.smw.set(smw_data_arr) if not res == true then ret_tag:tag('div'):css('display','none'):wikitext('Error setting SMW properties: '+res.error):done end end

-- Add view and talk links to infobox -- Only done if a name is defined if self.infoboxname then local bottom_links = {} for _, v in ipairs(self.bottomlinks) do			table.insert(bottom_links,					string.format( table.concat({'&#91;',								v[2],								'&#93;'}), self.infoboxname, self.infoboxname, self.infoboxname, self.infoboxname, self.infoboxname)				) end

bottom_links = table.concat(bottom_links,' &bull; ') self.rdiv:tag('span') :addClass('infobox-bottom-links') :wikitext(bottom_links) :done end -- Define as finished self.__finished = true end

--	Function for defining parameters	-- name : parameter name	-- func : function to define param, defaults to looking at blanks	DO NOT DEFINE VERSION HERE	USE :maxVersion	Can be used any number of times for efficient definition -- function Infobox:defineParams(...) for _, v in ipairs(...) do		-- For every parameter, store its corresponding function to self.params if v.name then -- If the value is a function or a table (which should define a function) if type(v.func) == 'function' or type(v.func) == 'table' then self.params[v.name] = v.func -- If the value is a string, use the predefined Infobox function of that name elseif type(v.func) == 'string' then self.params[v.name] = func_map[v.func] or hasContent -- Everything else just looks for blanks else self.params[v.name] = hasContent end -- Create a list of all param names table.insert(self.paramnames,v.name) -- function to allow duplicated values if v.dupes then self.dupeable[v.name] = true end end end end

--	-- Forces an infobox to only use 1 variant	-- Mainly used by lite infoboxes	-- This should be run before creation -- function Infobox:noSwitch self.versions = 1 self.switchfo = false end

--	-- Calculates the max version	-- Adds labels	-- Sees if this needs to be a switch infobox	-- Returns extra version count (even if already run) -- function Infobox.maxVersion(box) -- Only allowed to run once if box.versions ~= -1 then return box.versions end

box.labels = {} box.versions = 0

-- Look for up to 125 variants, defined in order for i=1, 125 do		-- If variant# exists if box.args['version'..i] then -- Increase version count box.versions = box.versions + 1

-- Add its label table.insert(box.labels,box.args['version'..i] or ('Version '..i)) -- Stop if it doesn't exist else break end end

-- Define self as a switch infobox if at least 1 other version is found if box.versions > 0 then box.switchfo = true end

-- versions calculated return box.versions end

-- #default : use the cleaned parameter first, otherwise passed				p : use the passed value of parameters				r | l : use raw (literal) text, rather than values		-- Defining a single flag will use that flag on all parameters		-- Defining a table of flags will use the respective flag by position -- function Infobox:cleanParams -- map of flags to functionality local flagmap = { r = 'r', l = 'r', d = 'd', p = 'p'	} -- For all parameters named for _, v in ipairs(self.paramnames) do		-- Parameter to add local _add = {} local catdata = { all_defined = true, one_defined = false } -- If the value of params is a function if type(self.params[v]) == 'function' then -- Perform that function with the parameter _add.d = self.params[v](self.args[v]) -- If it's a table, parse it into a function elseif type(self.params[v]) == 'table' then -- Find the functions name local func = self.params[v].name

if type(func) == 'string' then func = func_map[func] end

-- catch all if type(func) ~= 'function' then func = has_content end

-- Recreate table of args and flags local func_args = {} local flag = {} -- If the flags are NOT a table, turn them into a table -- Same size as the parameter table -- Every flag will be the same if type(self.params[v].flag) ~= 'table' then -- Map flags, if unmapped, use default local _flag = flagmap[self.params[v].flag] or 'd'				-- recreate table for x=1,#self.params[v].params do					table.insert(flag,_flag) end -- If flags are already a table, recreate them in new table elseif type(self.params[v].flag) == 'table' then local _flag = self.params[v].flag -- recreate table for x=1,#self.params[v].params do					-- Map flags, if unmapped, use default table.insert(flag,flagmap[_flag[x]] or 'd') end end -- Recreate param table, parsing flags as instructions for x, w in ipairs(self.params[v].params) do				local xarg -- By default or defined as 'd'				-- looks for the cleaned value of the named parameter first -- if it doesn't exist, look at the passed value next -- if that doesn't exist, use blank if flag[x] == 'd' then xarg = (self.rargs[w] and self.rargs[w].d) or self.args[w] or '' -- Look only at the passed value of the named parameter -- if that doesn't exist, use blank elseif flag[x] == 'p' then xarg = self.args[w] or '' -- Don't interpret value as a parameter name, and paste the as is				elseif flag[x] == 'r' then xarg = w				end -- Add parsed argument to table table.insert(func_args,xarg) end -- Run function _add.d = func(unpack(func_args)) end

if _add.d == nil or _add.d == nil_param then -- have to do pagename defaults here to prevent weird behaviour with switch values if v == 'name' then _add.d = pagename else _add.d = edit end catdata.all_defined = false else --_add.d is not nil catdata.one_defined = true end if self.switchfo then -- Table of switches values and count of them local _add_switch = {} local switches = 0 -- Look for up to the maximum number for i=1, self.versions do				local _addarg -- see if this param is allowed to have switch if v ~= 'image' and v ~= 'examine' and string.find(self.args[v..i] or '','%$%d') then local refi = string.match(self.args[v..i],'%$(%d+)') _addarg = _add_switch[tonumber(refi)] or nil_param else -- If the value of params is a function if type(self.params[v]) == 'function' then -- Perform that function with the parameter at that index _addarg = self.params[v](self.args[v..i]) -- If it's a table, parse it into a function elseif type(self.params[v]) == 'table' then -- Find the functions name local func = self.params[v].name

if type(func) == 'string' then func = func_map[func] end

-- catch all if type(func) ~= 'function' then func = has_content end

-- Recreate table of args and flags local func_args = {} local flag = {} -- If the flags are NOT a table, turn them into a table -- Same size as the parameter table -- Every flag will be the same if type(self.params[v].flag) ~= 'table' then -- Map flags, if unmapped, use default local _flag = flagmap[self.params[v].flag] or 'd'							 -- recreate table for x=1,#self.params[v].params do								table.insert(flag,_flag) end -- If flags are already a table, recreate them in new table elseif type(self.params[v].flag) == 'table' then local _flag = self.params[v].flag -- recreate table for x=1,#self.params[v].params do								-- Map flags, if unmapped, use default table.insert(flag,flagmap[_flag[x]] or 'd') end end -- Recreate param table, parsing flags as instructions for x, w in ipairs(self.params[v].params) do							local xarg -- By default or defined as 'd'							-- looks for the cleaned value of the named parameter first -- if it doesn't exist, look at the passed value next -- if that doesn't exist, look at the default -- if that doesn't exist, use blank if flag[x] == 'd' then if self.rargs[w] then if self.rargs[w].switches then xarg = self.rargs[w].switches[i] else xarg = self.args[w..i]									end if xarg == nil or xarg == nil_param then xarg = self.rargs[w].d									end end -- multiple catches in a row just to cover everything if xarg == nil or xarg == nil_param then xarg = self.args[w..i]								end if xarg == nil or xarg == edit or xarg == nil_param then xarg = self.args[w] end if xarg == nil or xarg == edit or xarg == nil_param then xarg = '' end -- Look only at the passed value of the named parameter -- if that doesn't exist, use unnumbered parameter -- if that doesn't exist, use blank elseif flag[x] == 'p' then xarg = self.args[w..i] or self.args[w] or '' -- Don't interpret value as a parameter name, and paste the as is							elseif flag[x] == 'r' then xarg = w							end -- Add parsed argument to table table.insert(func_args,xarg) end -- Run function _addarg = func(unpack(func_args)) end end -- If not defined, add the nil_param value -- An actual nil would cause errors in placement -- So it needs to be filled with an actual value -- "nil_param" is understood as nil in other functions -- Include table in case parameter isn't defined by template

if _addarg == nil or _addarg == nil_param then table.insert(_add_switch, nil_param) else switches = switches + 1 table.insert(_add_switch, _addarg) catdata.one_defined = true end end -- If there are actually other values to switch to			-- Define a switches subtable, otherwise ignore it			if switches > 0 then _add.switches = _add_switch end end

-- Quick fix for names (which defaults to pagename) if v == 'name' then if _add.d == pagename then if _add.switches and _add.switches[1] ~= pagename and _add.switches[1] ~= nil_param then _add.d = _add.switches[1] end end end

-- Parameter cleaning finished, add to table of cleaned args self.rargs[v] = _add

-- Category metadata -- If every param except default is defined, all_defined = true if catdata.all_defined == false then if _add.d == edit then if _add.switches then catdata.all_defined = true for _, v in ipairs(_add.switches) do						if v == nil_param then all_defined = false break end end end end end

self.catdata[v] = catdata end

-- mass dupe removal -- this needs to be done at the end to keep dependent parameters working -- also removes incompatible data types for _, v in ipairs(self.paramnames) do		-- not removed from dupe enabled params parameters if not self.dupeable[v] and self.rargs[v] and self.rargs[v].switches then -- tells us whether or not we'll need to remove the switch data -- switched to false if a switch values does not match the default local rmvswitch = true for q, z in ipairs(self.rargs[v].switches) do				-- if it matches the default, switch it to nil if z == self.rargs[v].d then self.rargs[v].switches[q] = nil_param

-- remove types that don't turn into strings properly elseif type(z) == 'table' or type(z) == 'function' then self.rargs[v].switches[q] = nil_param

-- if it doesn't match and also isn't nil or an edit button -- change variable to keep the switch data elseif z ~= nil_param and z ~= edit then rmvswitch = false end end -- remove switch data if everything was a dupe if rmvswitch then self.rargs[v].switches = nil end end end

-- Title parentheses (has to be done here, sadly) local _name if self.rargs.name then _name = self.rargs.name.d		-- replace html entities to their actual character _name = mw.text.decode(_name)

-- if the page name matches the item name, don't add parentheses if _name == mw.title.getCurrentTitle.fullText then self.rtable:addClass('no-parenthesis-style') end end end

--	Function to link internal use parameters with JS class attribution	-- self:linkParams{ { arg1, arg2 }, ... { arg1a, arg2a } }	-- arg1: parameter name being linked	-- arg2: parameter name that holds the classes	-- THIS FUNCTION SHOULD BE RUN AFTER :cleanParams	-- THIS FUNCTION SHOULD BE RUN BEFORE :finish	-- The second argument's data should always contain a value (a CSS class name) at every index	-- This function is cancelled for non switch boxes -- function Infobox:linkParams(...) if not self.switchfo then return end for _, v in ipairs(...) do		self.switchfoattr[v[1]] = self.rargs[v[2]] end end

--[==========================================[ -- Functions for accessing parameters easily --]==========================================] -- #default : self.rargs[arg].d -- Default value		f | full : self.rargs[arg] -- Entire table		s | switches : self.rargs[arg].switches -- Entire switch table		s# : self.rargs[arg].switches[#] -- Single switch value at index #		r : switches[1] or d -- function Infobox:param(arg, retp) -- All parameters if arg == 'all' then return self.rargs end -- case-insensitive flagging retp = tostring(retp):lower local fmap = { d = 'd', default = 'd', s0 = 'd', -- let s-naught count as default (since that's what it is) f = 'f', full = 'f', s = 's', switch = 's', switches = 's', r = 'r'	} local ret_func -- quickly see if the parameter is a value greater than 0 if retp:match('s[1-9]') then ret_func = 's2' else -- Otherwise map it to the correct flag, or the default ret_func = fmap[retp] or fmap.d	end

-- Fetch parameter local param = self.rargs[arg] -- Return nil if no table found if not param then return nil end

-- Return default if ret_func == 'd' then return param.d	end

-- Return full table if ret_func == 'f' then return param end

-- Return switch table if ret_func == 's' then return param.switches end

-- Return the first switch, otherwise the default if ret_func == 'r' then if not param.switches then return param.d		elseif param.switches[1] == nil_param then return param.d		else return param.switches[1] end end

-- If s2, reread the param if ret_func == 's2' then -- no switches if not param.switches then return nil end -- Parse index by removing the s		local index = retp:match('s(%d+)') -- nil_param if param.switches[index] == nil_param then return nil else return param.switches[index] end end end

--	Checks if a parameter is defined and not blank	-- arg : parameter to look at	-- index : index of switches to look at (defaults to default param)		-- defining 'all' will look at every possible value for the parameter -- function Infobox:paramDefined(arg,index) -- Can use cleaned params for switches -- but need the passed to identify blanks in the template local param = self.rargs[arg] local _arg = self.args[arg] if string.find(_arg or '','%?action=edit') then _arg = '' end index = index or 0 local ret -- create a long strong of every value to test for things if 'all' if string.lower(index) == 'all' then return self.catdata[arg] and (self.catdata[arg].one_defined or self.catdata[arg].all_defined) -- index to number otherwise else index = tonumber(index) or 0 if index == 0 then ret = _arg else if not param.switches then return nil end if param.switches[index] == nil_param then return nil end ret = param.switches[index] end end return tostring(ret or ''):find('%S') end

--	Function to perform a search on all parameters of a defined name	-- param: param name	-- val: a value or function		-- functions passed must return either true or false		-- with true being counted as a match -- function Infobox:paramGrep(param,val) local arg = self.rargs[param] -- if no parameters, return nil if not arg then return nil end

local ret local valtype = type(val) -- start with the default value -- if it's a function, run it	if valtype == 'function' then ret = val(arg.d)

-- true means it matched if ret == true then return ret end

-- switches up here for functions if arg.switches then for _, v in ipairs(arg.switches) do				ret = val(v) if ret == true then return true end end end

-- if it's just a value, compare the two -- only run if types match to avoid errors -- compare switches later elseif valtype == type(arg.d) then -- if a string, make case insensitive if valtype == 'string' then if string.lower(val) == string.lower(arg.d) then return true end -- everything else just test directly elseif val == arg.d then return true end end

-- switch cases -- more organized putting them here if arg.switches then for _, v in ipairs(arg.switches) do			if valtype == type(v) then if valtype == 'string' then if val:lower == v:lower then return true end elseif val == v then return true end end end end

-- return false in every other case return false end --

function Infobox.paramRead(arg,val) -- if no parameters, return nil if not arg then return nil end

local ret local valtype = type(val) -- start with the default value -- if it's a function, run it	if valtype == 'function' then ret = val(arg.d)

-- true means it matched if ret == true then return ret end

-- switches up here for functions if arg.switches then for _, v in ipairs(arg.switches) do				ret = val(v) if ret == true then return true end end end

-- if it's just a value, compare the two -- only run if types match to avoid errors -- compare switches later elseif valtype == type(arg.d) then -- if a string, make case insensitive if valtype == 'string' then if string.lower(val) == string.lower(arg.d) then return true end -- everything else just test directly elseif val == arg.d then return true end end

-- switch cases -- more organized putting them here if arg.switches then for _, v in ipairs(arg.switches) do			if valtype == type(v) then if valtype == 'string' then if val:lower == v:lower then return true end elseif val == v then return true end end end end

-- return false in every other case return false end

-- Return collected category data function Infobox:categoryData return self.catdata end

-- Override tostring function Infobox.tostring(box) -- If not finished, finish if not box.__finished then box:finish end

-- Make entire html wrapper a string and return it	return tostring(box.rdiv) end

return Infobox