m (Debug trace) |
m (Protected "Module:Navbox" ([Edit=Allow only administrators] (indefinite) [Move=Allow only administrators] (indefinite))) |
||
(42 intermediate revisions by 4 users not shown) | |||
Line 28: | Line 28: | ||
Like list{} except it formats as a straight run of text rather than hlist. Can only contain |
Like list{} except it formats as a straight run of text rather than hlist. Can only contain |
||
string. ni{} or l{} |
string. ni{} or l{} |
||
+ | |||
ni{} |
ni{} |
||
⚫ | |||
Invokes {{NI}} (or a facsimile, anyway) |
Invokes {{NI}} (or a facsimile, anyway) |
||
+ | |||
+ | nid{} |
||
+ | Invokes {{NID}} (or a facsimile, anyway) |
||
l{} |
l{} |
||
Line 53: | Line 56: | ||
[1] = Name of the navbox definition to use |
[1] = Name of the navbox definition to use |
||
name = template name for generating the v.d.e links |
name = template name for generating the v.d.e links |
||
− | collapse = null or "navbox" to hide the navbox |
||
− | "groups" to collapse just the groups |
||
− | "open" to leave it entirely open. |
||
− | opengroups = space-delimited string of groups to open. Give hthe group a "name" argument |
||
⚫ | |||
} |
} |
||
]] |
]] |
||
+ | |||
+ | local ipairs, pairs, rawget, type = ipairs, pairs, rawget, type |
||
local util = require("Module:Utility_functions") |
local util = require("Module:Utility_functions") |
||
Line 67: | Line 67: | ||
addDataToOutput = function(self, context, output, options) |
addDataToOutput = function(self, context, output, options) |
||
local oldmod = context.mod |
local oldmod = context.mod |
||
− | context.mod = self.data.mod or oldmod |
+ | context.mod = self.data.mod or oldmod or "UNDEFINED" |
+ | local oldmodname = context.modname |
||
+ | context.modname = self.data.modname or oldmodname or "Undefined" |
||
for i, item in ipairs(self.data) do |
for i, item in ipairs(self.data) do |
||
output((options.surround or {''})[1]) |
output((options.surround or {''})[1]) |
||
Line 101: | Line 103: | ||
expand = function(self, context, output) |
expand = function(self, context, output) |
||
output('<table class="navbox" cellspacing="0"><tr><td style="padding: 2px;">') |
output('<table class="navbox" cellspacing="0"><tr><td style="padding: 2px;">') |
||
− | output('<table class="nowraplinks |
+ | output('<table class="nowraplinks') |
⚫ | |||
− | if |
+ | if context.state == "plain" or context.state == "off" then |
⚫ | |||
− | + | output('mw-collapsed') |
|
⚫ | |||
end |
end |
||
− | output('" cellspacing="0" style="width:100%; background: transparent; color: inherit;" |
+ | output('" cellspacing="0" style="width:100%; background: transparent; color: inherit;"') |
+ | output(' data-expandtext="show" data-collapsetext="hide">') |
||
output('<tr><th colspan="2" class="navbox-title"><span style="float:left;width:6em;text-align:left;">') |
output('<tr><th colspan="2" class="navbox-title"><span style="float:left;width:6em;text-align:left;">') |
||
output(mw.getCurrentFrame():expandTemplate{title="Navbar", args={mini="1", context.name}}) |
output(mw.getCurrentFrame():expandTemplate{title="Navbar", args={mini="1", context.name}}) |
||
Line 130: | Line 132: | ||
output('<tr><td colspan="2" class="navbox-list" style="width:100%; padding:0px;">') |
output('<tr><td colspan="2" class="navbox-list" style="width:100%; padding:0px;">') |
||
output('<div style="padding:0em 0.25em"> </div>') |
output('<div style="padding:0em 0.25em"> </div>') |
||
− | output('<table class="nowraplinks collapsible |
+ | output('<table class="nowraplinks mw-collapsible') |
− | if (context.collapse == "groups") and (not context.opengroups[self.data.name]) then |
||
⚫ | |||
⚫ | |||
− | output('uncollapsed') |
||
⚫ | |||
-- These two semicolons stops something from wrapping tables in gratuitous divs |
-- These two semicolons stops something from wrapping tables in gratuitous divs |
||
− | output(' navbox-subgroup" cellspacing="0" style="width:100% |
+ | output(' navbox-subgroup" cellspacing="0" style="width:100%;"') |
+ | output(' data-expandtext="show" data-collapsetext="hide">') |
||
output('<tr><th class="navbox-title" colspan="2">') |
output('<tr><th class="navbox-title" colspan="2">') |
||
output('<span style="float:left;width:6em;"> </span><span style="font-size: 100%;">') |
output('<span style="float:left;width:6em;"> </span><span style="font-size: 100%;">') |
||
Line 166: | Line 164: | ||
return |
return |
||
end |
end |
||
+ | |||
⚫ | |||
output('<tr>') |
output('<tr>') |
||
Line 174: | Line 174: | ||
output('<td style="text-align:left;border-left-width:2px;border-left-style:solid;width:100%;padding:0px;"') |
output('<td style="text-align:left;border-left-width:2px;border-left-style:solid;width:100%;padding:0px;"') |
||
else |
else |
||
− | output('<td |
+ | output('<td colspan="2" style="') |
+ | if hasChildLists then |
||
⚫ | |||
⚫ | |||
+ | output('border-left-width:2px;border-left-style:solid;width:100%;padding:0px;"') |
||
end |
end |
||
Line 183: | Line 187: | ||
end |
end |
||
⚫ | |||
if hasChildLists then |
if hasChildLists then |
||
Line 192: | Line 195: | ||
context.odd = not context.odd |
context.odd = not context.odd |
||
output('<ul class="hlist" style="padding:0em 0.25em; margin: 0;">') |
output('<ul class="hlist" style="padding:0em 0.25em; margin: 0;">') |
||
− | self:addDataToOutput(context, output, {surround = {'<li>','</li>'}}) |
+ | self:addDataToOutput(context, output, {surround = {' <li class="nowrap"> ',' </li> '}}) |
output('</ul>') |
output('</ul>') |
||
end |
end |
||
Line 208: | Line 211: | ||
output('<td>') |
output('<td>') |
||
else |
else |
||
− | output('<td |
+ | output('<td colspan="2">') |
end |
end |
||
Line 224: | Line 227: | ||
else |
else |
||
local iconargs = { |
local iconargs = { |
||
+ | "", |
||
item = (self.data.gicon or self.data[1]), |
item = (self.data.gicon or self.data[1]), |
||
size=16, |
size=16, |
||
− | mod=(self.data.mod or context.mod |
+ | mod=(self.data.mod or context.mod) |
} |
} |
||
output(mw.getCurrentFrame():callParserFunction("#icon", iconargs)) |
output(mw.getCurrentFrame():callParserFunction("#icon", iconargs)) |
||
end |
end |
||
− | output(" |
+ | output(" ") |
− | local linkargs = { self.data[2] or self.data[1], (self.data[3] or self.data[2]) or self.data[1] } |
+ | local linkargs = { self.data[2] or self.data[1], (self.data[3] or self.data[2]) or mw.getCurrentFrame():callParserFunction("#iconloc", {self.data[1], self.data.mod or context.mod, "name", mw.title.getCurrentTitle().subpageText:lower()})} |
+ | output(language.link(linkargs)) |
||
⚫ | |||
+ | } |
||
+ | |||
+ | -- Invocation of {{NID}}, or at least the equivalent thereof. |
||
+ | element.nid = { |
||
+ | expand = function(self, context, output) |
||
⚫ | |||
+ | output("[[File:" .. self.data.icon .. "|16px|link=]]") |
||
⚫ | |||
⚫ | |||
+ | "", |
||
⚫ | |||
⚫ | |||
+ | mod = (self.data.mod or context.mod) |
||
+ | } |
||
+ | output(mw.getCurrentFrame():callParserFunction("#icon", iconargs)) |
||
⚫ | |||
⚫ | |||
+ | local linkargs = { self.data[1] .. " (" .. context.modname .. ")", (self.data[2]) or mw.getCurrentFrame():callParserFunction("#iconloc", {self.data[1], self.data.mod or context.mod, "name", mw.title.getCurrentTitle().subpageText:lower()})} |
||
output(language.link(linkargs)) |
output(language.link(linkargs)) |
||
end |
end |
||
Line 275: | Line 299: | ||
setmetatable(newthing, element[name]) |
setmetatable(newthing, element[name]) |
||
⚫ | |||
− | local named = {} |
||
− | local positional = {} |
||
⚫ | |||
if type(k) == "number" then |
if type(k) == "number" then |
||
− | + | if type(v) == "function" then |
|
⚫ | |||
⚫ | |||
− | + | table.insert(newthing.data, w) |
|
− | end |
+ | end |
− | + | else |
|
⚫ | |||
− | |||
− | + | end |
|
⚫ | |||
⚫ | |||
⚫ | |||
⚫ | |||
⚫ | |||
− | end |
||
− | |||
− | for i,v in ipairs(positional) do |
||
− | if type(v) == "function" then |
||
⚫ | |||
⚫ | |||
⚫ | |||
else |
else |
||
− | + | if type(v) == "function" then |
|
+ | newthing.data[k] = invokeInDefinition(v) |
||
⚫ | |||
+ | newthing.data[k] = v |
||
⚫ | |||
end |
end |
||
end |
end |
||
Line 340: | Line 354: | ||
local success = false |
local success = false |
||
− | local module = |
+ | local module = {} |
local moduleName = "Module:Navbox/" .. frame.args[1] |
local moduleName = "Module:Navbox/" .. frame.args[1] |
||
if frame.args.forceUntranslated then |
if frame.args.forceUntranslated then |
||
Line 353: | Line 367: | ||
success, module = tryLoadModule(moduleName) |
success, module = tryLoadModule(moduleName) |
||
if not success then |
if not success then |
||
− | return out .. "<br/>!!! Could not load [[" .. moduleName .. "]] : " .. module .. " !!!" |
+ | return out .. "<br />!!! Could not load [[" .. moduleName .. "]] : " .. module .. " !!!" |
end |
end |
||
end |
end |
||
Line 366: | Line 380: | ||
definitionEnvironment.line, |
definitionEnvironment.line, |
||
definitionEnvironment.ni, |
definitionEnvironment.ni, |
||
+ | definitionEnvironment.nid, |
||
definitionEnvironment.l) |
definitionEnvironment.l) |
||
local context = {} |
local context = {} |
||
context.name = frame.args.name |
context.name = frame.args.name |
||
− | context. |
+ | context.state = getParameter(frame, "state") or "autocollapse" |
context.opengroups = {} |
context.opengroups = {} |
||
-- opengroups is a set, not a list. |
-- opengroups is a set, not a list. |
Latest revision as of 03:15, 24 August 2020
Exported functions
Emit a navbox. Has three named parameters:
Parameter | Function |
---|---|
1 |
Mandatory Subpage of Module:Navbox to load the definition from. |
name |
Mandatory Page to link to in the v.d.e bit of the navbox header. |
fromParent |
If present, read the previous two parameters from the page that invoked the one the #invoke is on. ie, use this in your wrapper template
|
forceUntranslated |
Debugging only If present, load the untranslated version of the navbox, instead of a translation. |
The module must have one member, navbox
, which must be a function with the following signature:
function(navbox, highlightline, group, list, line, ni, nid, l)
The function returns a navbox definition built by calling the functions passed to it.
The top of the tree is a navbox{} title: Mandatory wikitext to display as the navbox's title Can contain a mix of group{}, list{}, and highlightline{} group{} are the collapsible groups. title: Mandatory wikitext to title the group with. name: Untranslated name to refer to it in things like the opengroups template parameter. Can contain list{} and highlightline{} list{} title: Optional title to display at the left. Can contain list{}/line{}, in which case the lists will be formatted tabley/subgroupy, or string/ni{}/l{}, which will be formatted as a hlist. Note that the *first* positional argument determines if it's a table or not. highlightline{} Contents are concatenated (with space between) and displayed in a highlighted line like wp:Template:Navbox before= and after= line{} Like list{} except it formats as a straight run of text rather than hlist. Can only contain string. ni{} or l{} ni{} Invokes {{NI}} (or a facsimile, anyway) nid{} Invokes {{NID}} (or a facsimile, anyway) l{} Invokes the guts of {{L}} text{} You should never need to use this directly. It's what strings are wrapped in.
--[[
All of the items in the definition tree for the navbox have an expand() method that
causes them to produce their markup:
expand(state, output)
where output is a function that adds its argument to the output, and state is state variables.
output's job also includes calling expand() on any tables!
The top of the tree is a navbox{}
title: Mandatory wikitext to display as the navbox's title
Can contain a mix of group{}, list{}, and highlightline{}
group{} are the collapsible groups.
title: Mandatory wikitext to title the group with.
name: Untranslated name to refer to it in things like the opengroups template parameter.
Can contain list{} and highlightline{}
list{}
title: Optional title to display at the left.
Can contain list{}/line{}, in which case the lists will be formatted tabley/subgroupy,
or string/ni{}/l{}, which will be formatted as a hlist. Note that the *first*
positional argument determines if it's a table or not.
highlightline{}
Contents are concatenated (with space between) and displayed in a highlighted
line like wp:Template:Navbox before= and after=
line{}
Like list{} except it formats as a straight run of text rather than hlist. Can only contain
string. ni{} or l{}
ni{}
Invokes {{NI}} (or a facsimile, anyway)
nid{}
Invokes {{NID}} (or a facsimile, anyway)
l{}
Invokes the guts of {{L}}
text{}
You should never need to use this directly. It's what strings are wrapped in.
Strings will be presented literally in the output. Functions are allowed: in the positional
arguments to any of the above functions, any function will be evaluated in the same way as
navbox{}, and then be replaced by the positional elements of the table it returns. Same deal
in the named arguments except the return is used directly. In the interests of non-silly
output, strings are joined with a space.
line{ "a", function() return { "1", "2" } end, "b" } is equivalent to,
line{ "a", "1", "2", "b" }
list{ title = function() return "foo" end, "1", "2" } is equivalent to,
list{ title = "foo", "1", "2" }
The exported function, navbox(), has three template parameters: {
[1] = Name of the navbox definition to use
name = template name for generating the v.d.e links
}
]]
local ipairs, pairs, rawget, type = ipairs, pairs, rawget, type
local util = require("Module:Utility_functions")
local language = require("Module:Language")
local element = {
addDataToOutput = function(self, context, output, options)
local oldmod = context.mod
context.mod = self.data.mod or oldmod or "UNDEFINED"
local oldmodname = context.modname
context.modname = self.data.modname or oldmodname or "Undefined"
for i, item in ipairs(self.data) do
output((options.surround or {''})[1])
self:expandItem(item, context, output, options.spacer)
output((options.surround or {'',''})[2])
if (i < #(self.data)) and options.separator then
output(options.separator)
end
end
context.mod = oldmod
end,
expandItem = function(self, item, context, output, spacer)
if type(item) == "table" then
item:expand(context, output)
else
output(tostring(item or ''))
end
output(spacer or '')
end,
expandOrMessage = function(self, item, context, output, spacer, message)
if item then
self:expandItem(item, context, output, spacer)
else
output(message)
end
end
}
-- The navbox as a whole.
element.navbox = {
expand = function(self, context, output)
output('<table class="navbox" cellspacing="0"><tr><td style="padding: 2px;">')
output('<table class="nowraplinks')
output(' mw-collapsible ')
if context.state == "plain" or context.state == "off" then
output('mw-collapsed')
end
output('" cellspacing="0" style="width:100%; background: transparent; color: inherit;"')
output(' data-expandtext="show" data-collapsetext="hide">')
output('<tr><th colspan="2" class="navbox-title"><span style="float:left;width:6em;text-align:left;">')
output(mw.getCurrentFrame():expandTemplate{title="Navbar", args={mini="1", context.name}})
output('</span><span style="font-size: 110%">')
self:expandOrMessage(self.data.title, context, output, ' ', '!!! Missing title !!!')
output('</span>')
output('</th></tr>')
output('<tr style="height: 2px;"><td></td></tr>')
self:addDataToOutput(context, output, {separator = '<tr style="height: 2px;"><td></td></tr>'})
output('</table>')
output('</td></tr></table>')
end
}
-- The collapsible groups that are the first division of the navbox.
element.group = {
expand = function(self, context, output)
context.odd = true
output('<tr><td colspan="2" class="navbox-list" style="width:100%; padding:0px;">')
output('<div style="padding:0em 0.25em"> </div>')
output('<table class="nowraplinks mw-collapsible')
-- These two semicolons stops something from wrapping tables in gratuitous divs
output(' navbox-subgroup" cellspacing="0" style="width:100%;"')
output(' data-expandtext="show" data-collapsetext="hide">')
output('<tr><th class="navbox-title" colspan="2">')
output('<span style="float:left;width:6em;"> </span><span style="font-size: 100%;">')
self:expandOrMessage(self.data.title, context, output, ' ', '!!! Missing title !!!')
output('</span></th></tr>')
output('<tr style="height: 2px;"><td></td></tr>')
self:addDataToOutput(context, output, {spacer = '', separator='<tr style="height: 2px;"><td></td></tr>'})
output('</table>')
output('</td></tr>')
end
}
-- A group-level thingy that displays text in a contrasting background.
element.highlightline = {
expand = function(self, context, output)
output('<tr><td colspan="2" class="navbox-abovebelow">')
self:addDataToOutput(context, output, {spacer = ' '})
output('</td></tr>')
end
}
-- The remaining subdivisions of the navbox; with the title at the left, optionally.
element.list = {
expand = function(self, context, output)
if #(self.data) == 0 then
return
end
local hasChildLists = (type(self.data[1]) == "table") and ((self.data[1].elementType == "list") or (self.data[1].elementType == "line"))
output('<tr>')
if self.data.title then
output('<td class="navbox-group" style="padding-left: 0em; padding-right:0em;"><div style="padding:0em 0.75em;">')
self:expandItem(self.data.title, context, output)
output('</div></td>')
output('<td style="text-align:left;border-left-width:2px;border-left-style:solid;width:100%;padding:0px;"')
else
output('<td colspan="2" style="')
if hasChildLists then
output('text-align:left;')
end
output('border-left-width:2px;border-left-style:solid;width:100%;padding:0px;"')
end
if context.odd then
output(' class="navbox-list navbox-odd">')
else
output(' class="navbox-list navbox-even">')
end
if hasChildLists then
output('<table class="nowraplinks navbox-subgroup" cellspacing="0" style="width: 100%;">')
self:addDataToOutput(context, output, {separator = '<tr style="height: 2px;"><td></td></tr>'})
output('</table>')
else
context.odd = not context.odd
output('<ul class="hlist" style="padding:0em 0.25em; margin: 0;">')
self:addDataToOutput(context, output, {surround = {' <li class="nowrap"> ',' </li> '}})
output('</ul>')
end
output('</td></tr>')
end
}
-- Like list, except it doesn't format as a list.
element.line = {
expand = function(self, context, output)
output('<tr>')
if self.data.title then
output('<th>' .. tostring(self.data.title) .. '</th>')
output('<td>')
else
output('<td colspan="2">')
end
self:addDataToOutput(context, output, {spacer = ' '})
output('</td></tr>')
end
}
-- Invocation of {{NI}}, or at least the equivalent thereof.
element.ni = {
expand = function(self, context, output)
if self.data.icon then
output("[[File:" .. self.data.icon .. "|16px|link=]]")
else
local iconargs = {
"",
item = (self.data.gicon or self.data[1]),
size=16,
mod=(self.data.mod or context.mod)
}
output(mw.getCurrentFrame():callParserFunction("#icon", iconargs))
end
output(" ")
local linkargs = { self.data[2] or self.data[1], (self.data[3] or self.data[2]) or mw.getCurrentFrame():callParserFunction("#iconloc", {self.data[1], self.data.mod or context.mod, "name", mw.title.getCurrentTitle().subpageText:lower()})}
output(language.link(linkargs))
end
}
-- Invocation of {{NID}}, or at least the equivalent thereof.
element.nid = {
expand = function(self, context, output)
if self.data.icon then
output("[[File:" .. self.data.icon .. "|16px|link=]]")
else
local iconargs = {
"",
item = (self.data.gicon or self.data[1]),
size = 16,
mod = (self.data.mod or context.mod)
}
output(mw.getCurrentFrame():callParserFunction("#icon", iconargs))
end
output(" ")
local linkargs = { self.data[1] .. " (" .. context.modname .. ")", (self.data[2]) or mw.getCurrentFrame():callParserFunction("#iconloc", {self.data[1], self.data.mod or context.mod, "name", mw.title.getCurrentTitle().subpageText:lower()})}
output(language.link(linkargs))
end
}
-- Invocation of {{L}}, or an equivalent.
element.l = {
expand = function(self, context, output)
output(language.link(self.data))
end
}
-- literal string
element.text = {
expand = function(self, context, output)
output(self.data)
end
}
-- This environment is interposed in the one available to the function in definition.navbox.
local definitionEnvironment = {}
-- Note that this doesn't handle arguments!
--[[local function invokeInDefinition(func)
local origEnv = getfenv(func)
local newEnv = {}
setmetatable(newenv, { __index = function(tab, key)
return definitionEnvironment[key] or origEnv[key]
end})
setfenv(func, newEnv)
local result = func()
setfenv(func, origEnv)
return result
end]]
-- stub because getfenv doesn't exist.
local function invokeInDefinition(func)
return func()
end
local function createElement(name, metatable, args)
local newthing = { elementType = name, data = {} }
setmetatable(newthing, element[name])
for k, v in pairs(args) do
if type(k) == "number" then
if type(v) == "function" then
for j, w in ipairs(invokeInDefinition(v)) do
table.insert(newthing.data, w)
end
else
table.insert(newthing.data, v)
end
else
if type(v) == "function" then
newthing.data[k] = invokeInDefinition(v)
else
newthing.data[k] = v
end
end
end
return newthing
end
for name, metatable in pairs(element) do
if type(metatable) == "table" then
metatable.__index = function(tab, key)
return (rawget(tab, key) or rawget(metatable, key)) or rawget(element, key)
end
definitionEnvironment[name] = function(args)
return createElement(name, metatable, args)
end
end
end
local p = {}
local function tryLoadModule(name)
return pcall(function()
return require(name)
end)
end
local function getParameter(frame, name)
if frame.args.fromParent then
return frame.args[name] or frame:getParent().args[name]
else
return frame.args[name]
end
end
function p.navbox(frame)
local out = ""
local output = function(text)
out = out .. tostring(text or '')
end
local success = false
local module = {}
local moduleName = "Module:Navbox/" .. frame.args[1]
if frame.args.forceUntranslated then
success, module = tryLoadModule(moduleName)
if not success then
return "!!! Could not load [[" .. moduleName .. "]] : " .. module .. " !!!"
end
else
success, module = tryLoadModule(moduleName .. util.pageSuffix())
if not success then
output("!!! Could not load [[" .. moduleName .. util.pageSuffix() .. "]], loading untranslated fallback. " .. module .. " !!!")
success, module = tryLoadModule(moduleName)
if not success then
return out .. "<br />!!! Could not load [[" .. moduleName .. "]] : " .. module .. " !!!"
end
end
end
local navboxModule = module
local navboxData = navboxModule.navbox(
definitionEnvironment.navbox,
definitionEnvironment.highlightline,
definitionEnvironment.group,
definitionEnvironment.list,
definitionEnvironment.line,
definitionEnvironment.ni,
definitionEnvironment.nid,
definitionEnvironment.l)
local context = {}
context.name = frame.args.name
context.state = getParameter(frame, "state") or "autocollapse"
context.opengroups = {}
-- opengroups is a set, not a list.
for str in string.gmatch(getParameter(frame, "opengroups") or '', "%S+") do
context.opengroups[str] = true
end
output('<div style="display:none">')
output(util.table_print(frame.args))
output('</div>')
navboxData:expand(context, output)
return out
end
return p