Модуль:InfoboxBuilder: различия между версиями
Материал из FetbukWiki
https://projectsekai.miraheze.org/wiki/>ChaoticShadow (add variable class) |
м (1 версия импортирована) |
(нет различий)
|
Текущая версия от 22:44, 9 марта 2022
Для документации этого модуля может быть создана страница Модуль:InfoboxBuilder/doc
local navbar = require('Module:Navbar')._navbar
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 = {
['color'] = nil,
['background-color'] = nil
},
params = {
['bg color'] = {},
['text color'] = {}
},
param_names = { 'bg color', 'text color' },
raw_args = {},
proc_args = {},
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['color'] = 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['background-color'] = arg
return self
end
--- Sets both the text and background color of the header
-- @param arg { color, background-color }
-- color string
-- Same as setHeaderTextColor
-- background-color 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['color'])
self:setHeaderBackgroundColor(arg['background-color'])
return self
end
--- Sets both the text and background color of the header
-- @param param_name string
-- Parameter name that helps map the colors
-- @param color_func { color, background-color } or function
-- color string
-- Same as setHeaderTextColor
-- background-color string
-- Same as setHeaderBackgroundColor
-- function
-- Accepts one argument, and returns a table with color and
-- background-color keys.
-- @return self
-- The current object
function InfoboxBuilder:setHeaderColorsByParam(param_name, color_func)
if param_name == nil then
error("Parameter name must not be nil")
elseif color_func == nil then
error("Header color function or table must not be nil")
elseif type(color_func) ~= "table" and type(color_func) ~= "function" then
error("Must pass in table or function as 'color_func'.")
end
local raw_param_value = self.raw_args[param_name]
local colors = nil
if type(color_func) == "table" then
colors = color_func[raw_param_value]
else
colors = color_func(raw_param_value)
end
if colors == nil then
return self
end
self:setHeaderTextColor(colors['color'])
self:setHeaderBackgroundColor(colors['background-color'])
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 or v.name == "" then
error("name must not be nil or empty")
end
if self.param_names[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.param_names, 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.raw_args[k] = v
end
end
if self.raw_args['bg color'] then
self:setHeaderBackgroundColor(self.raw_args['bg color'])
end
if self.raw_args['text color'] then
self:setHeaderTextColor(self.raw_args['text color'])
end
return self
end
--- Gets the raw argument values passed
-- @return args table
-- A table containing the args
function InfoboxBuilder:getRawArgs()
return self.raw_args
end
--- Gets the argument values after being processed
-- @return args table
-- A table containing the args
function InfoboxBuilder:getProcessedArgs()
return self.proc_args
end
--- Gets the argument values of the table, for either raw or processed
-- @param which string
-- A string that determines which argument values to return
-- @retun args table
-- A table containing the args
function InfoboxBuilder:getArgs(which)
if which == 'raw' then
return self:getRawArgs()
elseif which == 'processed' then
return self:getProcessedArgs()
end
return {}
end
--- Gets the content associated with a parameter
-- @param param_name string
-- The param name, not nil or empty
-- @return content string
-- A string containing the content
function InfoboxBuilder:getContent(param_name)
if param_name == nil or param_name == "" then
error("Param must not be nil or empty")
end
if self.proc_args[param_name] then
return self.proc_args[param_name]
end
local content = nil
local current_param = self.params[param_name]
if current_param == nil then
error(string.format("No such param with name: %s", param_name))
end
local raw_param_value = self.raw_args[param_name] 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.proc_args[param_name] = content
return content
end
--- Determines if the row should be shown based of a list of param names
-- @param param_names { param_name, ... }
-- param_name string
-- The param name
-- @return should_show boolean
function InfoboxBuilder:shouldShow(param_names)
if param_names and #param_names > 0 then
local actual_values = {}
for i,v in ipairs(param_names) do
table.insert(actual_values, self:getContent(v))
end
if #actual_values == 0 then
return false
end
end
return true
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
-- @param options { hideIfEmpty, subheader }
-- hideIfEmpty { param_name, ... }
-- param_name string
-- The param_name that will be used to check if corresponding
-- content is nil
-- subheader boolean
-- Whether the header is a subheader or not
-- @return self
-- The current object
function InfoboxBuilder:addHeader(arg, options)
local is_subheader = false
if options then
if not self:shouldShow(options.hideIfEmpty) then
return self
end
if options.subheader then
is_subheader = true
end
end
self:addSpacer()
local _cell = self.infobox:tag('tr'):tag('th'):attr('colspan', 30)
_cell:css(self.headerColors)
if not is_subheader then
_cell:addClass('infobox-header')
else
_cell:addClass('infobox-subheader')
end
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 cols { { 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
-- @param options { hideIfEmpty }
-- hideIfEmpty { param_name, ... }
-- param_name string
-- The param_name that will be used to check if corresponding
-- content is nil
-- @return self
-- The current object
function InfoboxBuilder:addImage(cols, options)
if options then
if not self:shouldShow(options.hideIfEmpty) then
return self
end
end
local _cell = self.infobox:tag('tr')
:tag('td')
:css('text-align', 'center')
:attr('colspan', 30)
local content = '?'
local actual_args = {}
for _,v in ipairs(cols) 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
_cell:tag('span'):addClass('plainlinks')
:wikitext(
string.format("[%s?action=edit ? (edit)]",
tostring(mw.uri.fullUrl(mw.title.getCurrentTitle().text))
)
)
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:wikitext(content)
return self
end
--- Adds a row, with columns up to 30 columns spanned
-- @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
-- param_css { func , ... }
-- func function
-- A function that returns css in table form
-- @param options { hideIfEmpty }
-- hideIfEmpty { param_name, ... }
-- param_name string
-- The param_name that will be used to check if corresponding
-- content is nil
-- default_css {...} or nil
-- The css of all cells in table form
-- @return self
-- The current object
function InfoboxBuilder:addRow(cols, options)
local default_css = nil
if options then
if not self:shouldShow(options.hideIfEmpty) then
return self
end
if options.default_css then
default_css = options.default_css
end
end
local _row = self.infobox:tag('tr')
for _,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 default_css then
_cell:css(default_css)
end
if v.css then
_cell:css(v.css)
end
if v.class then
_cell:addClass(v.class)
end
if v.tag == 'th' or v.tag == 'td' then
_cell:wikitext(v.content)
elseif v.tag == 'argth' or v.tag == 'argtd' then
local content = self:getContent(v.content)
if content then
if v.param_css and #v.param_css > 0 then
for _,func in ipairs(v.param_css) do
local cell_css = func(self.raw_args[v.content])
if cell_css then
_cell:css(cell_css)
end
end
end
if v.classFunc then
local cellClass = v.classFunc(self.raw_args[v.content])
if cellClass then
_cell:addClass(cellClass)
end
end
_cell:wikitext(content)
else
_cell:tag('span'):addClass('plainlinks')
:wikitext(
string.format("[%s?action=edit ? (edit)]",
tostring(mw.uri.fullUrl(mw.title.getCurrentTitle().text))
)
)
end
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
self:addRow({
{
tag = 'td',
content = navbar({ self.name, plain = 1, noedit = 1 }),
colspan = 30,
css = { ['text-align'] = 'center' }
}
})
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
mw.getCurrentFrame():extensionTag{
name = 'templatestyles',
args = { src = 'Template:Infobox/styles.css' }
} ..
tostring(self.infobox)
end
return InfoboxBuilder