Module:Sandbox/ChaoticShadow/InfoboxBuilder

local InfoboxBuilder = {} InfoboxBuilder.__index = InfoboxBuilder InfoboxBuilder.__tostring = InfoboxBuilder.tostring

local tagmap = { th = 'th', td = 'td', argth = 'th', argtd = 'td' }

--- Create the infobox -- @return obj metatable --            A metatable describing the infobox function InfoboxBuilder.new local obj = setmetatable({		name = '',		headerColors = {			text = '#000',			bg  = 'transparent'		},		params = {			{ name = 'bg color' },			{ name = 'text color' }		},		paramnames = { 'bg color', 'text color' },		args = {},		final_args = {},		proto_infobox = {},		infobox = mw.html.create('table'):addClass('infobox'),		finished = false	}, InfoboxBuilder)

return obj end

--- Set the infobox name, for use with bottom links -- @param arg string --           Name of the template, not nil or empty -- @return self --        The current object function InfoboxBuilder:setName(arg) if arg == nil or arg == '' then error("Template name must not be nil or empty") end self.name = arg return self end

--- Set the width of the infobox -- @param arg string --           Width of the infobox, should be a valid value for the CSS "width" --           property, not nil or empty -- @return self --        The current object function InfoboxBuilder:setWidth(arg) if arg == nil or arg == '' then error("Width must not be nil or empty") end self.infobox:css('width', arg) return self end

--- Set the text color of the header -- @param arg string --           Text color of the header, should be a valid value for the CSS --           "color" property, not nil or empty -- @return self --        The current object function InfoboxBuilder:setHeaderTextColor(arg) if arg == nil or arg == '' then error("Header text color must not be nil or empty") end self.headerColors.text = arg return self end

--- Set the background color of the header -- @param arg string --           Background color of the header, should be a valid value for the --           CSS "background-color" property, not nil or empty -- @return self --        The current object function InfoboxBuilder:setHeaderBackgroundColor(arg) if arg == nil or arg == '' then error("Header background color must not be nil or empty") end self.headerColors.bg = arg return self end

--- Sets both the text and background color of the header -- @param arg { text, bg } --       text string --            Same as setHeaderTextColor --       bg   string --            Same as setHeaderBackgroundColor -- @return self --        The current object function InfoboxBuilder:setHeaderColors(arg) if arg == nil then error("Header colors must not be nil") end self:setHeaderTextColor(arg.text) self:setHeaderBackgroundColor(arg.bg) return self end

--- Sets both the text and background color of the header -- @param param string --             Parameter name that helps map the colors -- @param color_table { text, bg } --       text string --            Same as setHeaderTextColor --       bg string --            Same as setHeaderBackgroundColor -- @return self --        The current object function InfoboxBuilder:setHeaderColorsByParam(param, color_table) if param == nil then error("Parameter name must not be nil") elseif color_table == nil then error("Header color table must not be nil") end local raw_param_value = self.args[param] local colors = color_table[raw_param_value] if colors == nil then return self end self:setHeaderTextColor(colors.text) self:setHeaderBackgroundColor(colors.bg) return self end

--- Sets the infobox params -- @param ... {{ name, func, default, should_hide }, ...} --       name    string --               The name of the parameter, not nil, cannot be duplicate --       func    function, table or string --               A function that accepts the parameter as an argument and --               returns a string, OR --                A table that has the parameter as a key, OR --                An empty string --       default string or nil --               The default value if no argument is given -- @return self --        The current object function InfoboxBuilder:setParams(...) for i, v in ipairs(...) do		if v.name == nil and v.name == "" then error("name must not be nil or empty") end if self.paramnames[v.name] then error("name cannot be duplicate") end self.params[v.name] = { ['type'] = type(v.func), func = v.func, default = v.default }		table.insert(self.paramnames, v.name) end return self end

--- Sets the infobox arguments -- @param args Frame --            A frame object, passed in when invoked -- @return self --        The current object function InfoboxBuilder:setArgs(args) for k,v in pairs(args) do		if v ~= '' then self.args[k] = v		end end if self.args['bg color'] then self:setHeaderBackgroundColor(self.args['bg color']) end if self.args['text color'] then self:setHeaderTextColor(self.args['text color']) end return self end

--- Gets the content associated with a parameter -- @param param string --             The param name, not nil or empty -- @return content string --                A string containing the content function InfoboxBuilder:getContent(param) if param == nil or param == "" then error("Param must not be nil or empty") end if self.final_args[param] then return self.final_args[param] end local content = nil local current_param = self.params[param] if current_param == nil then error(string.format("No such param: %s", param)) end local raw_param_value = self.args[param] or current_param.default if raw_param_value == nil then return raw_param_value end if current_param['type'] == 'function' then content = current_param.func(raw_param_value) elseif current_param['type'] == 'table' then content = current_param.func[raw_param_value] else content = raw_param_value end self.final_args[param] = content return content end

--- Adds a header -- @param arg { content, attr, colspan, rowspan, css } --       content string or nil The wikitext to be rendered --       attr    {...} or nil  The attributes of the cell in table form --       colspan number or nil The colspan of the cell --       roswpan number or nil The rowspan of the cell --       css     {...} or nil  The css of the cell in table form -- @return self --        The current object function InfoboxBuilder:addHeader(arg) self:addSpacer local _cell = self.infobox:tag('tr'):tag('th'):attr('colspan', 30) _cell:css({		['text-align']      = 'center',		['background-color'] = self.headerColors.bg,		['color']            = self.headerColors.text	}) if arg.attr then _cell:attr(arg.attr) end if arg.colspan then _cell:attr('colspan', arg.colspan) end if arg.rowspan then _cell:attr('rowspan', arg.rowspan) end if arg.css then _cell:css(arg.css) end if arg.tag == 'th' then _cell:wikitext(arg.content) elseif arg.tag == 'argth' then _cell:wikitext(self:getContent(arg.content)) end self:addSpacer return self end

--- Adds an image, or switchable images -- @param ... { { tag, content, title }, ... } --       tag     "artd" or "td" Whether or not an it is based off a parameter --       content string         The content or the parameter name --       title   string or nil  The title, if using switchable images -- @return self --        The current object function InfoboxBuilder:addImage(...) local argt = ... local _cell = self.infobox:tag('tr'):tag('td'):css('text-align', 'center') local content = '?' local actual_args = {} for _,v in ipairs(argt) do		local c = v.content if v.tag == 'argtd' then c = self:getContent(c) end if c ~= nil then table.insert(actual_args, { title = v.title, content = c }) end end if #actual_args == 0 then return self elseif #actual_args < 2 then content = actual_args[1].content else local t = {} for _,v in ipairs(actual_args) do table.insert(t, v.title .. '=' .. v.content) end content = mw.getCurrentFrame:callParserFunction({					name = '#tag',					args = { 'tabber', table.concat(t, '|-|') }				}) end _cell:attr('colspan', 30) _cell:wikitext(content) return self end

--- Adds a row, with columns up to 30 columns spanned -- @param should_hide boolean --       The row will be hidden if all varying columns are nil -- @param cols   { { tag, content, hide, attr, colspan, rowspan, css }, ... } --       tag     "th", "td", "argth", "argtd" --                             A string containing one of the above, "th" or --                              "td" uses content as the wikitext, "argth" or --                              "argtd" uses content as the parameter name --                             to produce the suitable content --       content string        Content to be used as wikitext or a parameter --                             name --       attr    {...} or nil  The attributes of the cell in table form --       colspan number or nil The colspan of the cell --       rowspan number or nil The rowspan of the cell --       css     {...} or nil  The css of the cell in table form -- @return self --        The current object function InfoboxBuilder:addRow(should_hide, cols) local actual_values = {} for i,v in ipairs(cols) do		if v.tag == 'argth' or v.tag == 'argtd' then table.insert(actual_values, self:getContent(v.content)) end end if should_hide and #actual_values == 0 then return self end local _row = self.infobox:tag('tr') for i,v in ipairs(cols) do		local _cell = _row:tag(tagmap[v.tag] or 'td') :attr('colspan', 30 / #cols) 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.css then _cell:css(v.css) end if v.tag == 'th' or v.tag == 'td' then _cell:wikitext(v.content) elseif v.tag == 'argth' or v.tag == 'argtd' then _cell:wikitext(self:getContent(v.content)) end end return self end

--- Creates the 30-col layout function InfoboxBuilder:addSpacer local spacer = self.infobox:tag('tr') for i=1,30,1 do		spacer:tag('td') :attr('colspan', 1) :css('width', 'calc(100% / 30)') end end

--- Adds links to the bottom of the infobox function InfoboxBuilder:addLinks if not self.finished then self.finished = true local links = { "View ", "Talk " }		self:addHeader{ tag = 'th', content = string.format(links[1], self.name, self.headerColors.text) .. " &bull; " .. string.format(links[2], self.name, self.headerColors.text) }	end end

--- Generates the infobox -- @return string --        The html of the infobox function InfoboxBuilder:tostring if not self.finished then self:addLinks end self.finished = true return tostring(self.infobox) end

return InfoboxBuilder