Editing
Module:Infobox
Jump to navigation
Jump to search
Warning:
You are not logged in. Your IP address will be publicly visible if you make any edits. If you
log in
or
create an account
, your edits will be attributed to your username, along with other benefits.
Anti-spam check. Do
not
fill this in!
--[=[ -- For documentation, see [[Module:Infobox/doc]] --]=] -- <nowiki> local Infobox = {} Infobox.__index = Infobox Infobox.__tostring = Infobox.tostring -- Edit button for unknown params local editbutton = require('Module:Edit button') local var = mw.ext.VariablesLua 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' } --[=[ -- Standardised functions -- called as string with defineParams --]=] -- Standardised "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 -- Standardised "name" function function subjectName(arg) return string.match(arg or '','%S') and arg or nil end -- Create a standardised release function, since so many pages use it -- Turns release and update into a single parameter function releaseUpdate(release, update) if not Infobox.isDefined(release) then return nil end if string.lower(release) == 'no' then return 'N/A' end if not Infobox.isDefined(update) then return string.format('%s (Update unknown)',release) end if string.lower(update) == 'no' then return release end return string.format('%s ([[Update:%s|Update]])', release, update) end -- Standardised image function function image(img) if img and img:find('%S') then return img else return nil end end -- Standardised numbers function numbers(num) num = string.gsub(num or '',',','') return tonumber(num) end -- Wrap content with line breaks if it contains list-like wiki syntax function wrapContent(content) if type(content) == "string" then local firstListItem = math.min(content:find('^[*#]') or math.huge, content:find('\n[*#]') or math.huge) if firstListItem ~= math.huge then local suffix = content:find('\n[*#][^\n]+$') and '\n' or '' content = content:sub(1, firstListItem - 1) .. '\n' .. content:sub(firstListItem) .. suffix end end return content 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 -- switch infobox globals local LINE_WIDTH = 300 local MAX_LINES = 2 local DEFAULT_MAX_BUTTONS = 6 -- calculate with width of a switch infobox button -- potential @TODO: rework to use actual character widths function button_width(label) local PX_PER_CHAR = 6 local PX_PAD_MAR = 24 return string.len(label) * PX_PER_CHAR + PX_PAD_MAR end Infobox.splitpoint = '&&SPLITPOINT&&' -- 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 <div> tag wrapper -- other fields are initialised in other functions --]] function Infobox.new(args) 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 addrswibclass = true, switchfo = false, -- switch infobox? or not? switchfoattr = {}, -- switch data class changes maxbuttons = DEFAULT_MAX_BUTTONS, -- maximum number of buttons before switching becomes a menu switch_tag = '', -- switchfo data switch_buttons_tag = '', -- switchfo buttons custom_buttons = false, smw_error_tag = '', rtable = nil, -- returned infobox table labels = nil, -- returned labels _smw = {}, -- semantic mediawiki data _smwOne = {}, -- semantic mediawiki data part 2 _smwSubobject = {}, -- semantic mediawiki data part 3 _smwSubobjectName = nil, -- semantic mediawiki data part 3.5 _smwElement = {}, -- semantic mediawiki data part 4 set_default_version_smw = false, -- whether to set [[Property:Default version]] setSMWElement = true, suppressAllSMW = false, suppressVersionSMW = {}, versions = -1, -- number of switch versions (-1 is uncalculated) infoboxname = nil, -- template name appendStrs = {}, bottomlinks = { -- template bottom links links = { { 'Template talk:%s', 'talk' }, { 'Template:%s', 'view' } }, colspan = 2 }, catdata = {}, -- meta category data catlist = {}, -- defined table of category names (strings) __finished = false, -- infobox status }, Infobox) return obj end --[[ Toggles the addition of infobox class use before :create() noop if not a boolean --]] function Infobox:setAddRSWInfoboxClass(bool) if type(bool) == 'boolean' then self.addrswibclass = bool end 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 self.switch_buttons_tag = mw.html.create('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 self.switch_buttons_tag:attr('data-default-version',defv) end local numlines = 1 local width_working = 0 local total_width = 0 local buttons = {} -- Add individual buttons to the wrapper for i=1,self.versions do local wid = button_width(self.labels[i] or i) width_working = width_working + wid total_width = total_width + wid if width_working > LINE_WIDTH then numlines = numlines + 1 width_working = wid end local b = mw.html.create('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) table.insert(buttons, {b, wid}) end local best = {-1, 100000} if (numlines > 1) and (numlines <= MAX_LINES) then -- attempt to balance line widths local w_s, w_e = 0,total_width for i = 1,#buttons-1 do w_s = w_s + buttons[i][2] w_e = w_e - buttons[i][2] if w_s > LINE_WIDTH then -- w_s only increases, so we're done once it exceeds the width break end if w_e <= LINE_WIDTH then -- w_e only decreases, so just continue if it exceeds line local diff = math.abs(w_s - w_e) if diff < best[2] then best = { i, diff } end end end if best[1] == -1 then best = { math.floor(#buttons/2), 100000 } end end for i,v in ipairs(buttons) do self.switch_buttons_tag:node(v[1]) if i == best[1] then self.switch_buttons_tag:tag('span'):addClass('line-break') end end -- Used by JavaScript to turn the buttons into a menu list if too many variants if self.versions > self.maxbuttons or numlines > MAX_LINES then self.switch_buttons_tag:addClass('infobox-buttons-select') end self.switch_buttons_tag:done() end -- Create infobox table self.rtable = mw.html.create('table') if self.addrswibclass then self.rtable:addClass('infobox') end -- Add necessary class if switch infobox if self.switchfo then self.rtable:addClass('infobox-switch') end end -- Defines an infobox name ({{Template:arg}}) -- 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 if arg.colspan then self.bottomlinks.colspan = arg.colspan end if arg.links then if type(arg.links) == 'table' then self.bottomlinks.links = arg.links end end if arg.hide then self.bottomlinks.hide = arg.hide end 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 DEFAULT_MAX_BUTTONS end --[[ Add parameters functions All parameters should be tables The first parameter defines the type of cell to create -- th : <th> -- td : <td> -- argh : <th> -- argd : <td> 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: <tr><th title="Title">Header</th><th class="parameter">args.arg1</th></tr> 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 <td> 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(wrapContent(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(wrapContent(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 function Infobox.customButtonPlacement(box,arg) box.custom_buttons = arg return box end -- Choose whether to set [[Property:Default version]] -- Defaults to false. function Infobox.setDefaultVersionSMW(box, arg) box.set_default_version_smw = arg return box end function Infobox.addButtonsRow(box, args) if box.switchfo then box.custom_buttons = true local _row = box.rtable:tag('tr') :addClass('infobox-switch-buttons-row') :tag('td') :addClass('infobox-switch-buttons') :attr('colspan', args.colspan) :node(box.switch_buttons_tag) end return box end function Infobox.addButtonsCaption(box) if box.switchfo then box.custom_buttons = true local _row = box.rtable:tag('caption') :addClass('infobox-switch-buttons-caption') :node(box.switch_buttons_tag) end return box end --[[ -- adds a blank row of padding spanning the given number of columns --]] function Infobox.pad(box, colspan, class) local tr = box:tag('tr') :tag('td'):attr('colspan', colspan or 1):addClass('infobox-padding') :done() if class then tr:addClass(class) end tr:done() 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.rtable:wikitext(arg) return box end --[[ -- Adds the specified item(s) to the end of the infobox, outside of the table -- items are concatenated together with an empty space --]] function Infobox.append(box, ...) for i,v in ipairs({...}) do table.insert(box.appendStrs, v) end 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.rtable: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: -- {{#show:page|?property}}: -- "<property>" - unqualified and without a number will display the default value -- "<property#>" - with a number will show the switch data from that index -- "all <property>" - 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' then for w, v in pairs(arg) do self._smw[w] = v end end end --[[ As above, but only assigns to "<property>", which will act like "all <property>" - "<property>#" not present Properties initiated in Infobox:finish() --]] function Infobox:useSMWOne(arg) if type(arg) == 'table' then for w, v in pairs(arg) do self._smwOne[w] = v end end end --[[ Set up the infobox to set properties in a SMW subobject. This will create a subobject for each version - if there is only one version, it will put the properties directly on to the page, like useSMWOne Properties initiated in Infobox:finish() --]] function Infobox:useSMWSubobject(arg) if type(arg) == 'table' then for w, v in pairs(arg) do self._smwSubobject[w] = v end end end function Infobox:useSMWElement(arg) if type(arg) == 'table' then for w, v in pairs(arg) do self._smwElement[w] = v end self.setSMWElement = true end end --[[ Finishing function -- Finishes the return, adding necessary final tags --]] function Infobox:finish() local currentNamespace = mw.title.getCurrentTitle().namespace -- 0 = mainspace, 4 = RuneScape local onContentNamespace = currentNamespace == 0 or currentNamespace == 4 -- Don't finish twice if self.__finished then return end -- Add switch infobox resources if self.switchfo then self.rtable:attr('data-resource-class', '.infobox-resources-'..string.gsub(tostring(self.infoboxname), ' ', '_')) -- Wrapper tag, hidden self.switch_tag = mw.html.create('div') :addClass('infobox-switch-resources') :addClass('infobox-resources-'..string.gsub(tostring(self.infoboxname), ' ', '_')) :addClass('hidden') for _, v in ipairs(self.paramnames) do local param = self.rargs[v] local default_value = param.d or edit -- Parameters may not have any switches data, those are ignored local switchattr = self.switchfoattr[v] -- Parameter data wrapper local res_span = self.switch_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(default_value)) -- Switch classes if switchattr then def:attr('data-addclass',switchattr.d) end def:done() if param.switches then -- Add all switches, ignore those defined as nil for i, w in ipairs(param.switches) do if w ~= nil_param and w ~= nil and w ~= default_value then local _w = res_span:tag('span') :attr('data-attr-index',i) :wikitext(tostring(w)) -- Switch classes if switchattr and switchattr.switches then _w:attr('data-addclass',switchattr.switches[i]) elseif switchattr then mw.logObject({string.format("Expected switches for `%s` but got none:", v), switchattr}) end _w:done() end end res_span:done() end end -- Add a tracking category for pages that have more than 1 version if onContentNamespace and self.versions > 1 then -- version count data self.switch_tag:wikitext('[[Category:Pages that contain switch infobox data]]') if not self.suppressAllSMW then self.switch_tag:tag('span') :wikitext(string.format('Versions: [[Version count::%s]]',self.versions)) :done() -- set default version smw local defver = tonumber(self.args.defver) or 1 local default_subobject_value = self.args['smwname'..defver] or self.args['version'..defver] if default_subobject_value and self.set_default_version_smw then -- Only take first subobject if multiple are defined using "Β¦" local default_subobject_name = default_subobject_value:match("[^Β¦]+") self.switch_tag:tag('span') :wikitext(string.format('Default version: [[Default version::%s]]',default_subobject_name)) end end end self.switch_tag:done() end -- smw data if onContentNamespace and not self.suppressAllSMW 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)%]%]') if _d == nil then return nil end 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, removal = 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 _x = mw.text.split(tostring(_arg), Infobox.splitpoint, true) if not smw_data_arr[v] then smw_data_arr[v] = {} end if not smw_data_arr['All '..v] then smw_data_arr['All '..v] = {} end for _,y in ipairs(_x) do local temp_smw_data = smwfunc(y) table.insert(smw_data_arr[v], temp_smw_data) table.insert(smw_data_arr['All '..v], temp_smw_data) end end if curarg.switches then local _args = {} for x_i, x in ipairs(curarg.switches) do if not self.suppressVersionSMW[x_i] then if x ~= nil_param then table.insert(_args,x) else table.insert(_args,argdefault or nil_param) end end end for i, x in ipairs(_args) do local _x = mw.text.split(tostring(x), Infobox.splitpoint, true) if not smw_data_arr[v..i] then smw_data_arr[v..i] = {} end if not smw_data_arr['All '..v] then smw_data_arr['All '..v] = {} end for _,y in ipairs(_x) do local temp_smw_data = smwfunc(y) table.insert(smw_data_arr[v..i], temp_smw_data) table.insert(smw_data_arr['All '..v], temp_smw_data) end end end end end -- if one version, put smwSubobject into smwOne and just do that if self.versions < 2 and not self._smwSubobjectName then for w,v in pairs(self._smwSubobject) do if not self._smwOne[w] then self._smwOne[w] = v elseif type(self._smwOne[w]) == 'table' then table.insert(self._smwOne[w], v) else self._smwOne[w] = { self._smwOne[w], v } 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] if curarg then local _arg = curarg.d local argdefault = _arg if _arg == edit then argdefault = 'unknown' end if curarg.switches then local _args = {} for x_i, x in ipairs(curarg.switches) do if not self.suppressVersionSMW[x_i] then if x ~= nil_param then table.insert(_args,x) else table.insert(_args,argdefault or nil_param) end end end for i, x in ipairs(_args) do local _x = mw.text.split(tostring(x), Infobox.splitpoint, true) for _,y in ipairs(_x) do local temp_smw_data = smwfunc(y) for _,v in ipairs(type(_v) == 'table' and _v or {_v}) do if not smw_data_arr[v] then smw_data_arr[v] = {} end table.insert(smw_data_arr[v], temp_smw_data) end end end else if Infobox.isDefined(_arg) then local _targ = mw.text.split(tostring(_arg), Infobox.splitpoint, true) for _,y in ipairs(_targ) do local temp_smw_data = smwfunc(y) for _,v in ipairs(type(_v) == 'table' and _v or {_v}) do 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 end local smw_data_arr_elem = {} for w, v in pairs(self._smwElement) 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' end if curarg.switches then local _args = {} for x_i, x in ipairs(curarg.switches) do if not self.suppressVersionSMW[x_i] then if x ~= nil_param then table.insert(_args,x) else table.insert(_args,argdefault or nil_param) end end end for i, x in ipairs(_args) do if Infobox.isDefined(x) then local _x = mw.text.split(tostring(x), Infobox.splitpoint, true) for _,y in ipairs(_x) do local temp_smw_data = smwfunc(y) if not smw_data_arr_elem[v] then smw_data_arr_elem[v] = {} end table.insert(smw_data_arr_elem[v], temp_smw_data) end end end else if Infobox.isDefined(_arg) then local _targ = mw.text.split(tostring(_arg), Infobox.splitpoint, true) for _,y in ipairs(_targ) do local temp_smw_data = smwfunc(y) if not smw_data_arr_elem[v] then smw_data_arr_elem[v] = {} end table.insert(smw_data_arr_elem[v], temp_smw_data) end end end end end -- if is a switchfo, setup for subobjects local smw_data_arr_subobj = {} if self._smwSubobjectName then for i,k in ipairs(self._smwSubobjectName) do if not self.suppressVersionSMW[i] then local subobj_data = { ['Is variant of'] = {pagename}, } for w,v in pairs(self._smwSubobject) do local smwfunc = smw_to_func[w] or smw_to_func.default local curarg = self.rargs[w] if curarg then local argval = curarg.d if curarg.switches then argval = curarg.switches[i] if not Infobox.isDefined(argval) then argval = curarg.d end end if Infobox.isDefined(argval) then local _x = mw.text.split(tostring(argval), Infobox.splitpoint, true) for _, _x1 in ipairs(_x) do _x1 = smwfunc(_x1) if _x1 ~= 'unknown' then if not subobj_data[v] then subobj_data[v] = {} end table.insert(subobj_data[v], _x1) end end end end end for w,v in ipairs(k) do local subobj_name = v -- can't have a . in the first 5 characters of a subobject identifier if mw.ustring.find(mw.ustring.sub(subobj_name,0,5), '%.') then self:wikitext('[[Category:Pages with an invalid subobject name]]') subobj_name = mw.ustring.gsub(subobj_name, '%.', '') end if subobj_name == '0' or subobj_name == '' then self:wikitext('[[Category:Pages with an invalid subobject name]]') subobj_name = 'v_'..subobj_name end smw_data_arr_subobj[subobj_name] = subobj_data end end end end local res = mw.smw.set(smw_data_arr) local res_subobj = true for w,v in pairs(smw_data_arr_subobj) do res_subobj = mw.smw.subobject(v, w) if not res_subobj == true then break end end if not (res == true and res_subobj == true) then self.smw_error_tag = mw.html.create('div'):css('display','none'):addClass('infobox-smw-data') if not res == true then self.smw_error_tag:tag('div'):wikitext('Error setting SMW properties: '+res.error):done() end if not res_subobj == true then self.smw_error_tag:tag('div'):wikitext('Error setting SMW subobject properties: '+res_subobj.error):done() end end if self.setSMWElement then if self.smw_error_tag == '' then self.smw_error_tag = mw.html.create('div'):css('display','none'):addClass('infobox-smw-data') end for i,v in pairs(smw_data_arr_elem) do for j,k in ipairs(v) do if k ~= 'unknown' then self.smw_error_tag:tag('span'):wikitext(mw.ustring.format('%s: [[%s::%s]]', i,i,k )) end end end end if self._smwSubobjectName then if self.smw_error_tag == '' then self.smw_error_tag = mw.html.create('div'):css('display','none'):addClass('infobox-smw-data') end for w,v in pairs(smw_data_arr_subobj) do local subobjdiv = self.smw_error_tag:tag('div') subobjdiv:tag('span'):wikitext('SMW Subobject for '..w) for j,k in pairs(v) do subobjdiv:tag('span'):wikitext(mw.ustring.format('%s: %s', j, table.concat(k, ', '))) end end end end -- Add view and talk links to infobox -- Only done if a name is defined if self.infoboxname and not self.bottomlinks.hide then local bottom_links = {} for _, v in ipairs(self.bottomlinks.links) do table.insert(bottom_links, string.format( table.concat({'[[', v[1], '|', v[2], ']]'}), self.infoboxname, self.infoboxname, self.infoboxname, self.infoboxname, self.infoboxname) ) end bottom_links = table.concat(bottom_links,' • ') self.rtable:tag('tr'):tag('td') :addClass('infobox-template-links') :attr('colspan', self.bottomlinks.colspan) :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 local smwname = {} if string.lower(box.args['smw'] or '') == 'no' then box.suppressAllSMW = true end -- 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 local label = box.args['version'..i] or ('Version '..i) table.insert(box.labels,label) -- add to smwname if box.args['smwname'..i] then table.insert(smwname, mw.text.split(box.args['smwname'..i], 'Β¦')) else table.insert(smwname, {label}) end box.suppressVersionSMW[i] = (box.args['smw'..i] and string.lower(box.args['smw'..i] or '') == 'no') else -- Stop if it doesn't exist 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 box._smwSubobjectName = smwname else -- single version, check for smwname if box.args['smwname'] then box._smwSubobjectName = {mw.text.split(box.args['smwname'], 'Β¦')} end end -- versions calculated return box.versions end --[[ -- Cleans parameters as defined by the above function -- SHOULD NOT BE RUN UNTIL ALL THINGS ARE DEFINED -- Handles switches as well -- adds table _add to rargs, a cleaned up version of arguments -- d : default value -- switches : table of switches (in numerical order) -- Functions can be defined with tables ---- name : name of function ---- params : table of args to pass to functions ---- flag : flags for input d | #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 -- compare to nil explicitly because false is a valid value if xarg == nil then xarg = self.args[w] or '' end -- 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 catdata.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 -- remove types that don't turn into strings properly if type(z) == 'table' or type(z) == 'function' then self.rargs[v].switches[q] = nil_param -- if it 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 --]==========================================] --[[ Access the param -- arg : param name -- retp : return type d | #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 if param.switches then if Infobox.isDefined(param.switches[1]) then ret = param.switches[1] else ret = _arg end else ret = _arg end 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 organised 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 organised 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 -- Infobox:addDropLevelVars("thieving", "skilllvl1") function Infobox:addDropLevelVars(key, paramName) local levelParams = self:param(paramName, 'f') local dropParams = self:param('dropversion', 'f') if levelParams == nil then return end if dropParams == nil or not self:paramDefined("dropversion", "all") then dropParams = {d = 'DEFAULT'} end if dropParams.switches == nil then dropParams.switches = {} end local levels = levelParams.switches or {levelParams.d} local dropVersions = {} for i=1,#levels do local dropVersionFromInfobox = dropParams.switches[i] or dropParams.d if dropVersionFromInfobox == nil_param then dropVersionFromInfobox = 'DEFAULT' else dropVersionFromInfobox = dropVersionFromInfobox .. ",DEFAULT" end for dropVersion in string.gmatch(dropVersionFromInfobox, ' *([^,]+) *') do if dropVersions[dropVersion] == nil then dropVersions[dropVersion] = {} end dropVersions[dropVersion][levels[i]] = true end end -- This part is to append levels from previous Infobox invocations for dropVersion, dropLevels in pairs(dropVersions) do -- example variable: DropLevel_combat_High_level local var_name = string.format("DropLevel_%s_%s", key, dropVersion) local previousVar = var.var(var_name) if previousVar ~= "" then for v in string.gmatch(previousVar, ' *([^,]+) *') do dropVersions[dropVersion][v] = true end end local ordered = {} for k, v in pairs(dropVersions[dropVersion]) do local n = tonumber(k) if n ~= nil then table.insert(ordered, n) end end table.sort(ordered) var.vardefine(var_name, table.concat(ordered, ',')) end 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 local btns = box.switch_buttons_tag if box.custom_buttons then btns = '' end if box.args.__dump__ then return '<' .. 'pre>'..mw.dumpObject(box) .. '</' .. 'pre>[[Category:Dumping infoboxes]]' end return tostring(btns) .. tostring(box.rtable) .. table.concat(box.appendStrs, '') .. tostring(box.switch_tag) .. tostring(box.smw_error_tag) end return Infobox -- </nowiki>
Summary:
Please note that all contributions to OtherX may be edited, altered, or removed by other contributors. If you do not want your writing to be edited mercilessly, then do not submit it here.
You are also promising us that you wrote this yourself, or copied it from a public domain or similar free resource (see
OtherX:Copyrights
for details).
Do not submit copyrighted work without permission!
Cancel
Editing help
(opens in new window)
Templates used on this page:
Template:Documentation
(
edit
)
Template:Main
(
edit
)
Template:ToC
(
edit
)
Module:Array
(
edit
)
Module:DPLlua
(
edit
)
Module:DependencyList
(
edit
)
Module:Documentation
(
edit
)
Module:Hatnote
(
edit
)
Module:Infobox
(
edit
)
Module:Infobox/doc
(
edit
)
Module:Main article
(
edit
)
Module:Paramtest
(
edit
)
Module:Tooltip
(
edit
)
Module:Yesno
(
edit
)
This page is a member of a hidden category:
Category:Pages with broken file links
Navigation menu
Personal tools
Not logged in
Talk
Contributions
Create account
Log in
Namespaces
Module
Discussion
English
Views
Read
Edit source
View history
More
Purge cache
Search
Discord
Discord
Navigation
Main page
About us
Random page
Otherside
Legends of the Mara
Otherside Trips
Otherside Test Events
LOTM Guides & Info
Basics Guide
Hunting Guide
Farming Guide
Enchanting Guide
Game Updates
Oda Information
Quick References
Koda Weapons
Oda Abilities Table
Oda Stats Table
Tools
What links here
Related changes
Special pages
Page information
Page values