- Welcome to Touhou Wiki!
- Registering is temporarily disabled. Check in our Discord server to request an account and for assistance of any kind.
Module:Navbox: Difference between revisions
Jump to navigation
Jump to search
DennouNeko (talk | contribs) m (a bit of documentation (function comments) + type -> ttype to avoid collision with type() function) |
DennouNeko (talk | contribs) (attempt to cleanup and improve the code a bit + more comments) |
||
Line 11: | Line 11: | ||
-- == Helper functions == | -- == Helper functions == | ||
-- [[ libraries ]] | --[[ libraries ]] | ||
require("Module:Common") | require("Module:Common") | ||
Line 25: | Line 25: | ||
--[[ Retrieve a full list of 'list#', 'list#style', 'group#' and 'group#style' arguments | --[[ Retrieve a full list of 'list#', 'list#style', 'group#' and 'group#style' arguments | ||
as a table of objects with 'list', 'liststyle', 'group' and 'groupstyle' fields. | as a table of objects with 'index', 'list', 'liststyle', 'group' and 'groupstyle' fields, | ||
Only 'list' | where 'index' is the number in 'list#' argument name. | ||
Only 'list' and 'index' are always defined. Elements that weren't specified will be empty. | |||
If 'list#' wasn't defined, rest of elements for that given index will be ignored. | If 'list#' wasn't defined, rest of elements for that given index will be ignored. | ||
Key of argument matches the number in arguments name. ]] | Key of argument matches the number in arguments name. ]] | ||
Line 41: | Line 42: | ||
for k,v in frame:argumentPairs() do | for k,v in frame:argumentPairs() do | ||
s,e,t = string.find(k, '^group(%d | -- accept only parameters without leading zeros | ||
s,e,t = string.find(k, '^group([1-9]%d*)style$') | |||
if s ~= nil then groupstyle[tonumber(t)] = v end | if s ~= nil then groupstyle[tonumber(t)] = v end | ||
s,e,t = string.find(k, '^list(%d | s,e,t = string.find(k, '^list([1-9]%d*)style$') | ||
if s ~= nil then liststyle[tonumber(t)] = v end | if s ~= nil then liststyle[tonumber(t)] = v end | ||
s,e,t = string.find(k, '^group(%d | s,e,t = string.find(k, '^group([1-9]%d*)$') | ||
if s ~= nil then group[tonumber(t)] = v end | if s ~= nil then group[tonumber(t)] = v end | ||
s,e,t = string.find(k, '^list(%d | s,e,t = string.find(k, '^list([1-9]%d*)$') | ||
if s ~= nil then | if s ~= nil then | ||
list[tonumber(t)] = v | list[tonumber(t)] = v | ||
Line 59: | Line 61: | ||
table.sort(idx) | table.sort(idx) | ||
for k,v in | for k,v in pairs(idx) do | ||
local tmp = {} | local tmp = {} | ||
tmp['index'] = v | tmp['index'] = v | ||
Line 66: | Line 68: | ||
if isset(liststyle[v]) then tmp['liststyle'] = liststyle[v] end | if isset(liststyle[v]) then tmp['liststyle'] = liststyle[v] end | ||
if isset(groupstyle[v]) then tmp['groupstyle'] = groupstyle[v] end | if isset(groupstyle[v]) then tmp['groupstyle'] = groupstyle[v] end | ||
ret[#ret+1] = tmp | |||
end | end | ||
Line 77: | Line 79: | ||
--[[ Generates the beginning of box, based on specified 'ttype' and 'border'. ]] | --[[ Generates the beginning of box, based on specified 'ttype' and 'border'. ]] | ||
local function start_box(frame, border, ttype) | local function start_box(frame, border, ttype) | ||
local ret = { | local ret = {} | ||
if border == "subgroup" or border == "child" then | if border == "subgroup" or border == "child" then | ||
-- since we're in a cell of parent navbox, we have to close its <div> element | |||
ret[#ret+1] = '</div>' | |||
elseif border == "none" then | elseif border == "none" then | ||
-- nothing to do | -- nothing to do | ||
else | else | ||
-- new, independent navbox - create a frame around it | |||
if isset(frame.args['bodyclass']) then | ret[#ret+1] = '<table class="navbox' | ||
if isset(frame.args['bodyclass']) then ret[#ret+1] = " " .. frame.args['bodyclass'] end | |||
if isset(colors[ttype]) then | ret[#ret+1] = '" cellspacing="0" style="' | ||
if isset(colors[ttype]) then ret[#ret+1] = 'background:' .. colors[ttype]['background'] .. ';' end | |||
ret[#ret+1] = 'border:1px solid #aaa; padding:1px;width:100%;vertical-align:middle;margin:auto;clear:both;font-size:88%;text-align:center;' | |||
addstyle(ret, frame.args['bodystyle']) | addstyle(ret, frame.args['bodystyle']) | ||
addstyle(ret, frame.args['style']) | addstyle(ret, frame.args['style']) | ||
ret[#ret+1] = '"><tr><td style="padding: 2px;">' | |||
end | end | ||
table | -- The actual navbox table starts here | ||
ret[#ret+1] = '<table cellspacing="0" class="nowraplinks' | |||
if isset(frame.args['title']) and frame.args['state'] ~= "plain" and frame.args['state'] ~= "off" then | if isset(frame.args['title']) and frame.args['state'] ~= "plain" and frame.args['state'] ~= "off" then | ||
-- | --TODO: If there is support for collapsible and autocollapse, swap comments here | ||
--ret[#ret+1] = ' collapsible ' | |||
ret[#ret+1] = ' mw-collapsible ' | |||
if isset(frame.args['state']) then | if isset(frame.args['state']) then | ||
ret[#ret+1] = frame.args['state'] | |||
else | else | ||
-- | --ret[#ret+1] = 'autocollapse' | ||
ret[#ret+1] = 'mw-collapsed' | |||
end | end | ||
end | end | ||
if border == "subgroup" or border == "child" or border == "none" then | if border == "subgroup" or border == "child" or border == "none" then | ||
ret[#ret+1] = ' navbox-subgroup" style="' | |||
if isset(colors[ttype]) then table.insert(ret, 'background:' .. colors[ttype]['background'] .. ';') end | if isset(colors[ttype]) then table.insert(ret, 'background:' .. colors[ttype]['background'] .. ';') end | ||
ret[#ret+1] = 'margin:auto;clear:both;font-size:88%;text-align:center;width:100%;vertical-align:middle;' | |||
addstyle(ret, frame.args['bodystyle']) | addstyle(ret, frame.args['bodystyle']) | ||
addstyle(ret, frame.args['style']) | addstyle(ret, frame.args['style']) | ||
ret[#ret+1] = '">' | |||
else | else | ||
ret[#ret+1] = '" style="width:100%;background:transparent;color:inherit;">' | |||
end | end | ||
Line 123: | Line 127: | ||
local function end_box(frame, border, ttype) | local function end_box(frame, border, ttype) | ||
local ret = {""} | local ret = {""} | ||
ret[#ret+1] = '</table>' | |||
if border == "subgroup" or border == "child" then | if border == "subgroup" or border == "child" then | ||
-- open a <div>, since we closed one when starting this child navbox | |||
ret[#ret+1] = '<div>' | |||
elseif border == "none" then | elseif border == "none" then | ||
-- nothing to do | -- nothing to do | ||
else | else | ||
table | -- close the table we started as a frame | ||
ret[#ret+1] = '</td></tr></table>' | |||
end | end | ||
return table.concat(ret) | return table.concat(ret) | ||
Line 141: | Line 147: | ||
table.insert(ret, '<tr>') | table.insert(ret, '<tr>') | ||
if isset(frame.args['titlegroup']) then | if isset(frame.args['titlegroup']) then | ||
-- in case that there's a group for title | |||
if isset(colors[ttype]) then | ret[#ret+1] = '<td class="navbox-group" style="' | ||
if isset(colors[ttype]) then ret[#ret+1] = 'background:' .. colors[ttype]['group'] .. ';' end | |||
ret[#ret+1] = 'padding-left:1em;padding-right:1em;white-space:nowrap;text-align:right;' | |||
addstyle(ret, frame.args['basestyle']) | addstyle(ret, frame.args['basestyle']) | ||
addstyle(ret, frame.args['groupstyle']) | addstyle(ret, frame.args['groupstyle']) | ||
addstyle(ret, frame.args['titlegroupstyle']) | addstyle(ret, frame.args['titlegroupstyle']) | ||
ret[#ret+1] = '">\n' | |||
ret[#ret+1] = frame.args['titlegroup'] | |||
ret[#ret+1] = '</td>' | |||
ret[#ret+1] = '<th style="border-left:2px solid ' | |||
ret[#ret+1] = condval(isset(colors[ttype]), colors[ttype]['background'], '#fdfdfd') | |||
ret[#ret+1] = ';width:100%;' | |||
else | else | ||
-- no group for title | |||
table.insert(ret, '<th style="') | table.insert(ret, '<th style="') | ||
end | end | ||
if isset(colors[ttype]) then | if isset(colors[ttype]) then ret[#ret+1] = 'background:' .. colors[ttype]['title'] .. ';' end | ||
ret[#ret+1] = 'text-align:center;' | |||
addstyle(ret, frame.args['basestyle']) | addstyle(ret, frame.args['basestyle']) | ||
addstyle(ret, frame.args['titlestyle']) | addstyle(ret, frame.args['titlestyle']) | ||
ret[#ret+1] = '"' | |||
local cs = 2 | -- calculate the colspan for title | ||
local cs = 2 -- 2 because each list element with group occupies 2 columns | |||
if isset(frame.args['imageleft']) then cs = cs + 1 end | if isset(frame.args['imageleft']) then cs = cs + 1 end | ||
if isset(frame.args['image']) then cs = cs + 1 end | if isset(frame.args['image']) then cs = cs + 1 end | ||
if isset(frame.args['titlegroup']) then cs = cs - 1 end | if isset(frame.args['titlegroup']) then cs = cs - 1 end -- if there was a titlegroup, it occupies one cell already | ||
ret[#ret+1] = ' colspan = "' .. cs .. '"' | |||
ret[#ret+1] = ' class="navbox-title">' | |||
-- add navbars and/or padding when needed | |||
if frame.args['navbar'] == "plain" or frame.args['navbar'] == "off" or border == "subgroup" or border == "child" or border == "none" then | if frame.args['navbar'] == "plain" or frame.args['navbar'] == "off" or border == "subgroup" or border == "child" or border == "none" then | ||
if frame.args['navbar'] == "off" then | if frame.args['navbar'] == "off" then | ||
if frame.args['state'] == "plain" then | if frame.args['state'] == "plain" then ret[#ret+1] = '<div style="float:right;width:6em;"> </div>' end | ||
else | else | ||
if frame.args['state'] ~= "plain" then | if frame.args['state'] ~= "plain" then ret[#ret+1] = '<div style="float:left; width:6em;text-align:left;"> </div>' end | ||
end | end | ||
else | else | ||
if frame.args['state'] == "plain" then | if frame.args['state'] == "plain" then ret[#ret+1] = '<div style="float:right;width:6em;"> </div>' end | ||
ret[#ret+1] = '<div style="float:left; width:6em;text-align:left;">' | |||
if frame.args['name'] ~= nil then | if frame.args['name'] ~= nil then | ||
local args = {} | local args = {} | ||
args[#args+1] = frame.args['name'] | args[#args+1] = frame.args['name'] | ||
args['mini'] = '1' | |||
-- TODO: Build the navbar without using external template? | |||
local q = {""} | local q = {""} | ||
q[#q+1] = 'text-align:left;' | |||
addstyle(q, frame.args['basestyle']) | addstyle(q, frame.args['basestyle']) | ||
addstyle(q, frame.args['titlestyle']) | addstyle(q, frame.args['titlestyle']) | ||
q[#q+1] = 'border:none;' | |||
args['fontstyle'] = table.concat(q) | args['fontstyle'] = table.concat(q) | ||
ret[#ret+1] = frame:expandTemplate{title = 'Navbar', args = args} | |||
else | else | ||
ret[#ret+1] = ' ' | |||
ret[#ret+1] = '[\[Category:Navboxes without name]]' | |||
end | end | ||
ret[#ret+1] = '</div>' | |||
end | |||
table.insert(ret, '</ | -- the title starts here | ||
ret[#ret+1] = '<span' | |||
if isset(frame.args['titleclass']) then ret[#ret+1] = ' class="' .. frame.args['titleclass'] .. '"' end | |||
ret[#ret+1] = ' style="font-size:' .. condval((border == "subgroup" or border == "child" or border == "none"), '100%', '110%') .. ';">\n' | |||
ret[#ret+1] = frame.args['title'] | |||
ret[#ret+1] = '</span>' | |||
ret[#ret+1] = '</th></tr>' | |||
return table.concat(ret) | |||
end | |||
--[[ Generates the 'above' and 'below' rows. | |||
Returns the generated row and updated 'sep' value (if separation is going to be needed). ]] | |||
local function build_above_below(frame, border, ttype, text, style, sep) | |||
local ret = {''} | |||
if isset(text) then | |||
if sep then -- if separation is needed | |||
table.insert(ret, '<tr style="height: 2px;"><td></td></tr>') | |||
end | |||
-- start the 'above' or 'below' row | |||
ret[#ret+1] = '<tr>' | |||
ret[#ret+1] = '<td class="navbox-abovebelow" style="' | |||
if isset(colors[ttype]) then | |||
-- both above and below share same default color from 'colors' table | |||
ret[#ret+1] = 'background:' .. condval((border ~= "subgroup" and border ~= "child"), colors[ttype]['above'], colors[ttype]['group']) .. ';' | |||
end | |||
ret[#ret+1] = 'padding-left:1em;padding-right:1em;text-align:center;' | |||
addstyle(ret, frame.args['basestyle']) | |||
addstyle(ret, style) | |||
ret[#ret+1] = '"' | |||
-- calculate and add the colspan (always full table width) | |||
local cs = 2 | |||
if isset(frame.args['imageleft']) then cs = cs + 1 end | |||
if isset(frame.args['image']) then cs = cs + 1 end | |||
ret[#ret+1] = ' colspan="' .. cs .. '">\n' | |||
-- row content | |||
ret[#ret+1] = text | |||
ret[#ret+1] = '</td></tr>' | |||
return table.concat(ret) | sep = true -- now we're going to need separation | ||
end | |||
return table.concat(ret),sep | |||
end | end | ||
--[[ Generates a single row of the list. ]] | --[[ Generates a single row of the list. ]] | ||
local function build_row(frame, k, group, list, groupstyle, liststyle | local function build_row(frame, border, ttype, k, group, list, groupstyle, liststyle) | ||
local ret = {""} | local ret = {""} | ||
if isset(group) then | if isset(group) then | ||
-- there's a group name for current list, so add a cell for it | |||
if border ~= "subgroup" and border ~= "child" | ret[#ret+1] = '<td class="navbox-group" style="' | ||
if isset(colors[ttype]) then | |||
ret[#ret+1] = 'background:' .. condval((border ~= "subgroup" and border ~= "child"), colors[ttype]['group'], colors[ttype]['subgroup']) .. ';' | |||
end | end | ||
ret[#ret+1] = 'padding-left:1em; padding-right:1em; white-space:nowrap; text-align:right;' | |||
addstyle(ret, frame.args['basestyle']) | addstyle(ret, frame.args['basestyle']) | ||
if isset(frame.args['groupwidth']) then | if isset(frame.args['groupwidth']) then ret[#ret+1] = 'width:' .. frame.args['groupwidth'] .. ';' end | ||
addstyle(ret, frame.args['groupstyle']) | addstyle(ret, frame.args['groupstyle']) | ||
addstyle(ret, groupstyle) | addstyle(ret, groupstyle) | ||
ret[#ret+1] = '">' | |||
ret[#ret+1] = '<div style="padding:0;">\n' | |||
ret[#ret+1] = group | |||
ret[#ret+1] = '</div></td>' | |||
-- start the content cell | |||
ret[#ret+1] = '<td style="text-align:left;border-left-width:2px;border-left-style:solid;' | |||
else | else | ||
-- no group name, start the content already | |||
ret[#ret+1] = '<td colspan=2 style="' | |||
end | end | ||
-- a bit tricky, but | -- a bit tricky, but this works as XOR | ||
if (frame.args['evenodd'] == "swap") ~= ((k % 2) == 0) then | if (frame.args['evenodd'] == "swap") ~= ((k % 2) == 0) then | ||
if isset(colors[ttype]) then | if isset(colors[ttype]) then ret[#ret+1] = 'background:' .. colors[ttype]['dark'] .. ';' end | ||
else | else | ||
ret[#ret+1] = 'background:transparent;' | |||
end | end | ||
if not isset(frame.args['groupwidth']) then ret[#ret+1] = 'width:100%;' end | |||
if not isset(frame.args['groupwidth']) then | ret[#ret+1] = 'padding: 0;' | ||
addstyle(ret, frame.args['liststyle']) | addstyle(ret, frame.args['liststyle']) | ||
addstyle(ret, condval((frame.args['evenodd'] == "swap") ~= ((k % 2) == 0), frame.args['evenstyle'], frame.args['oddstyle'])) | |||
addstyle(ret, liststyle) | addstyle(ret, liststyle) | ||
ret[#ret+1] = '" class="navbox-list ' .. condval((frame.args['evenodd'] == "swap") ~= ((k % 2) == 0), 'navbox-even', 'navbox-odd') .. '">' | |||
table | -- add the <div> with content (same <div> that child navbox has to close when starting table) | ||
ret[#ret+1] = '<div style="padding:' | |||
if isset(frame.args['list' .. k .. 'padding']) then | if isset(frame.args['list' .. k .. 'padding']) then | ||
ret[#ret+1] = frame.args['list' .. k .. 'padding'] | |||
elseif isset(frame.args['listpadding']) then | elseif isset(frame.args['listpadding']) then | ||
ret[#ret+1] = frame.args['listpadding'] | |||
else | else | ||
ret[#ret+1] = '0em 0.25em' | |||
end | end | ||
ret[#ret+1] = ';">\n' | |||
ret[#ret+1] = list | |||
ret[#ret+1] = '</div></td>' | |||
return table.concat(ret) | return table.concat(ret) | ||
end | end | ||
--[[ Generates the "body" of table (everything below title) ]] | --[[ Generates the "body" of table (everything below title) ]] | ||
local function build_body(frame, border, ttype) | local function build_body(frame, border, ttype, lists) | ||
local ret = { | local ret = {} | ||
local sep = isset(frame.args['title']) | local sep = isset(frame.args['title']) -- if there was a title, we have to add separation for first row | ||
local imgs = true -- add images if present | |||
local irows = condval( (#lists > 0), (2 * #lists - 1), 1 ) | |||
-- aff the 'above' row | |||
ret[#ret+1],sep = build_above_below(frame, border, ttype, frame.args['above'], frame.args['abovestyle'], sep) | |||
for k,v in pairs(lists) do | |||
if sep then | if sep then -- add separation if needed | ||
ret[#ret+1] = '<tr style="height: 2px;"><td></td></tr>' | |||
end | end | ||
table.insert(ret, '<tr>') | table.insert(ret, '<tr>') | ||
-- add left image (if wasn't added yet and is present) | |||
if imgs then | if imgs then | ||
if isset(frame.args['imageleft']) then | if isset(frame.args['imageleft']) then | ||
ret[#ret+1] = '<td style="width:0%;padding:0px 2px 0px 0px;' | |||
addstyle(ret, frame.args['imageleftstyle']) | addstyle(ret, frame.args['imageleftstyle']) | ||
ret[#ret+1] = '" rowspan="' .. irows .. '">' .. frame.args['imageleft'] .. '</td>' | |||
end | end | ||
end | end | ||
-- add the list content | |||
ret[#ret+1] = build_row(frame, border, ttype, v['index'], v['group'], v['list'], v['groupstyle'], v['liststyle']) | |||
-- add right image (if wasn't added yet and is present) | |||
if imgs then | if imgs then | ||
if isset(frame.args['image']) then | if isset(frame.args['image']) then | ||
ret[#ret+1] = '<td style="width:0%;padding:0px 0px 0px 2px;' | |||
addstyle(ret, frame.args['imagestyle']) | addstyle(ret, frame.args['imagestyle']) | ||
ret[#ret+1] = '" rowspan="' .. irows .. '">' .. frame.args['image'] .. '</td>' | |||
end | end | ||
-- mark that images were added already | |||
imgs = false | imgs = false | ||
end | end | ||
ret[#ret+1] = '</tr>' | |||
sep = true -- now the separation is going to be needed for sure | |||
end | end | ||
ret[#ret+1],sep = build_above_below(frame, border, ttype, frame.args['below'], frame.args['belowstyle'], sep) | |||
return table.concat(ret) | return table.concat(ret) | ||
Line 378: | Line 365: | ||
--[[ Generates and returns the whole navbox table. ]] | --[[ Generates and returns the whole navbox table. ]] | ||
local function buildNavbox(frame) | local function buildNavbox(frame) | ||
local template = { | local template = {} | ||
local border = "" | local border = "" | ||
local ttype = "" | local ttype = "" | ||
Line 394: | Line 381: | ||
-- TODO: filtering of border and type values? | -- TODO: filtering of border and type values? | ||
-- prepare the data first | |||
local lists = scan_lists(frame) | |||
-- build the content | |||
template[#template+1] = start_box(frame, border, ttype) | |||
template[#template+1] = build_title(frame, border, ttype) | |||
template[#template+1] = build_body(frame, border, ttype, lists) | |||
template[#template+1] = end_box(frame, border, ttype) | |||
return table.concat(template) | return table.concat(template) |
Revision as of 18:16, 3 October 2012
Documentation for this module may be created at Module:Navbox/doc
Script error: Lua error at line 208: invalid escape sequence near ''['.
-- lua port of [[Template:Navbox]]
-- by DennouNeko
-- constants
local colors = {
game = {title = '#FFC9C2', above = '#FFD1CA', group = '#FFD9D2', subgroup = '#FFE1DA', dark = '#FFEEE8', background = '#FFF4EE'};
music = {title = '#FFF3B4', above = '#FFF6C0', group = '#FFF7C8', subgroup = '#FFF8D0', dark = '#FFFBE4', background = '#FFFBEE'};
printwork = {title = '#DDE6FF', above = '#E1E7FF', group = '#E6E9FF', subgroup = '#EAECFF', dark = '#EDF2FF', background = '#F4F9FF'}
}
-- == Helper functions ==
--[[ libraries ]]
require("Module:Common")
--[[ For easy adding of styles to a table.
It doesn't start or end a 'style=""' HTML argument. ]]
local function addstyle(tbl, val)
if isset(val) then
local av = string.trim(val)
if string.sub(av, -1) ~= ';' then av = av .. ';' end
table.insert(tbl, av)
end
end
--[[ Retrieve a full list of 'list#', 'list#style', 'group#' and 'group#style' arguments
as a table of objects with 'index', 'list', 'liststyle', 'group' and 'groupstyle' fields,
where 'index' is the number in 'list#' argument name.
Only 'list' and 'index' are always defined. Elements that weren't specified will be empty.
If 'list#' wasn't defined, rest of elements for that given index will be ignored.
Key of argument matches the number in arguments name. ]]
local function scan_lists(frame)
local idx = {}
local list = {}
local group = {}
local liststyle = {}
local groupstyle = {}
local ret = {}
local s,e,t
for k,v in frame:argumentPairs() do
-- accept only parameters without leading zeros
s,e,t = string.find(k, '^group([1-9]%d*)style$')
if s ~= nil then groupstyle[tonumber(t)] = v end
s,e,t = string.find(k, '^list([1-9]%d*)style$')
if s ~= nil then liststyle[tonumber(t)] = v end
s,e,t = string.find(k, '^group([1-9]%d*)$')
if s ~= nil then group[tonumber(t)] = v end
s,e,t = string.find(k, '^list([1-9]%d*)$')
if s ~= nil then
list[tonumber(t)] = v
idx[#idx+1] = tonumber(t)
end
end
table.sort(idx)
for k,v in pairs(idx) do
local tmp = {}
tmp['index'] = v
tmp['list'] = list[v]
if isset(group[v]) then tmp['group'] = group[v] end
if isset(liststyle[v]) then tmp['liststyle'] = liststyle[v] end
if isset(groupstyle[v]) then tmp['groupstyle'] = groupstyle[v] end
ret[#ret+1] = tmp
end
return ret
end
-- == Functions generating the document elements ==
--[[ Generates the beginning of box, based on specified 'ttype' and 'border'. ]]
local function start_box(frame, border, ttype)
local ret = {}
if border == "subgroup" or border == "child" then
-- since we're in a cell of parent navbox, we have to close its <div> element
ret[#ret+1] = '</div>'
elseif border == "none" then
-- nothing to do
else
-- new, independent navbox - create a frame around it
ret[#ret+1] = '<table class="navbox'
if isset(frame.args['bodyclass']) then ret[#ret+1] = " " .. frame.args['bodyclass'] end
ret[#ret+1] = '" cellspacing="0" style="'
if isset(colors[ttype]) then ret[#ret+1] = 'background:' .. colors[ttype]['background'] .. ';' end
ret[#ret+1] = 'border:1px solid #aaa; padding:1px;width:100%;vertical-align:middle;margin:auto;clear:both;font-size:88%;text-align:center;'
addstyle(ret, frame.args['bodystyle'])
addstyle(ret, frame.args['style'])
ret[#ret+1] = '"><tr><td style="padding: 2px;">'
end
-- The actual navbox table starts here
ret[#ret+1] = '<table cellspacing="0" class="nowraplinks'
if isset(frame.args['title']) and frame.args['state'] ~= "plain" and frame.args['state'] ~= "off" then
--TODO: If there is support for collapsible and autocollapse, swap comments here
--ret[#ret+1] = ' collapsible '
ret[#ret+1] = ' mw-collapsible '
if isset(frame.args['state']) then
ret[#ret+1] = frame.args['state']
else
--ret[#ret+1] = 'autocollapse'
ret[#ret+1] = 'mw-collapsed'
end
end
if border == "subgroup" or border == "child" or border == "none" then
ret[#ret+1] = ' navbox-subgroup" style="'
if isset(colors[ttype]) then table.insert(ret, 'background:' .. colors[ttype]['background'] .. ';') end
ret[#ret+1] = 'margin:auto;clear:both;font-size:88%;text-align:center;width:100%;vertical-align:middle;'
addstyle(ret, frame.args['bodystyle'])
addstyle(ret, frame.args['style'])
ret[#ret+1] = '">'
else
ret[#ret+1] = '" style="width:100%;background:transparent;color:inherit;">'
end
return table.concat(ret)
end
--[[ Finalizes the box, based on specified 'ttype' and 'border' ]]
local function end_box(frame, border, ttype)
local ret = {""}
ret[#ret+1] = '</table>'
if border == "subgroup" or border == "child" then
-- open a <div>, since we closed one when starting this child navbox
ret[#ret+1] = '<div>'
elseif border == "none" then
-- nothing to do
else
-- close the table we started as a frame
ret[#ret+1] = '</td></tr></table>'
end
return table.concat(ret)
end
--[[ Generates the title row: 'v(iew) • d(iscuss) • e(dit)' + title + '[Expand]'/'[Collapse]' buttons. ]]
local function build_title(frame, border, ttype)
local ret = {""}
if not isset(frame.args['title']) then return '' end
table.insert(ret, '<tr>')
if isset(frame.args['titlegroup']) then
-- in case that there's a group for title
ret[#ret+1] = '<td class="navbox-group" style="'
if isset(colors[ttype]) then ret[#ret+1] = 'background:' .. colors[ttype]['group'] .. ';' end
ret[#ret+1] = 'padding-left:1em;padding-right:1em;white-space:nowrap;text-align:right;'
addstyle(ret, frame.args['basestyle'])
addstyle(ret, frame.args['groupstyle'])
addstyle(ret, frame.args['titlegroupstyle'])
ret[#ret+1] = '">\n'
ret[#ret+1] = frame.args['titlegroup']
ret[#ret+1] = '</td>'
ret[#ret+1] = '<th style="border-left:2px solid '
ret[#ret+1] = condval(isset(colors[ttype]), colors[ttype]['background'], '#fdfdfd')
ret[#ret+1] = ';width:100%;'
else
-- no group for title
table.insert(ret, '<th style="')
end
if isset(colors[ttype]) then ret[#ret+1] = 'background:' .. colors[ttype]['title'] .. ';' end
ret[#ret+1] = 'text-align:center;'
addstyle(ret, frame.args['basestyle'])
addstyle(ret, frame.args['titlestyle'])
ret[#ret+1] = '"'
-- calculate the colspan for title
local cs = 2 -- 2 because each list element with group occupies 2 columns
if isset(frame.args['imageleft']) then cs = cs + 1 end
if isset(frame.args['image']) then cs = cs + 1 end
if isset(frame.args['titlegroup']) then cs = cs - 1 end -- if there was a titlegroup, it occupies one cell already
ret[#ret+1] = ' colspan = "' .. cs .. '"'
ret[#ret+1] = ' class="navbox-title">'
-- add navbars and/or padding when needed
if frame.args['navbar'] == "plain" or frame.args['navbar'] == "off" or border == "subgroup" or border == "child" or border == "none" then
if frame.args['navbar'] == "off" then
if frame.args['state'] == "plain" then ret[#ret+1] = '<div style="float:right;width:6em;"> </div>' end
else
if frame.args['state'] ~= "plain" then ret[#ret+1] = '<div style="float:left; width:6em;text-align:left;"> </div>' end
end
else
if frame.args['state'] == "plain" then ret[#ret+1] = '<div style="float:right;width:6em;"> </div>' end
ret[#ret+1] = '<div style="float:left; width:6em;text-align:left;">'
if frame.args['name'] ~= nil then
local args = {}
args[#args+1] = frame.args['name']
args['mini'] = '1'
-- TODO: Build the navbar without using external template?
local q = {""}
q[#q+1] = 'text-align:left;'
addstyle(q, frame.args['basestyle'])
addstyle(q, frame.args['titlestyle'])
q[#q+1] = 'border:none;'
args['fontstyle'] = table.concat(q)
ret[#ret+1] = frame:expandTemplate{title = 'Navbar', args = args}
else
ret[#ret+1] = ' '
ret[#ret+1] = '[\[Category:Navboxes without name]]'
end
ret[#ret+1] = '</div>'
end
-- the title starts here
ret[#ret+1] = '<span'
if isset(frame.args['titleclass']) then ret[#ret+1] = ' class="' .. frame.args['titleclass'] .. '"' end
ret[#ret+1] = ' style="font-size:' .. condval((border == "subgroup" or border == "child" or border == "none"), '100%', '110%') .. ';">\n'
ret[#ret+1] = frame.args['title']
ret[#ret+1] = '</span>'
ret[#ret+1] = '</th></tr>'
return table.concat(ret)
end
--[[ Generates the 'above' and 'below' rows.
Returns the generated row and updated 'sep' value (if separation is going to be needed). ]]
local function build_above_below(frame, border, ttype, text, style, sep)
local ret = {''}
if isset(text) then
if sep then -- if separation is needed
table.insert(ret, '<tr style="height: 2px;"><td></td></tr>')
end
-- start the 'above' or 'below' row
ret[#ret+1] = '<tr>'
ret[#ret+1] = '<td class="navbox-abovebelow" style="'
if isset(colors[ttype]) then
-- both above and below share same default color from 'colors' table
ret[#ret+1] = 'background:' .. condval((border ~= "subgroup" and border ~= "child"), colors[ttype]['above'], colors[ttype]['group']) .. ';'
end
ret[#ret+1] = 'padding-left:1em;padding-right:1em;text-align:center;'
addstyle(ret, frame.args['basestyle'])
addstyle(ret, style)
ret[#ret+1] = '"'
-- calculate and add the colspan (always full table width)
local cs = 2
if isset(frame.args['imageleft']) then cs = cs + 1 end
if isset(frame.args['image']) then cs = cs + 1 end
ret[#ret+1] = ' colspan="' .. cs .. '">\n'
-- row content
ret[#ret+1] = text
ret[#ret+1] = '</td></tr>'
sep = true -- now we're going to need separation
end
return table.concat(ret),sep
end
--[[ Generates a single row of the list. ]]
local function build_row(frame, border, ttype, k, group, list, groupstyle, liststyle)
local ret = {""}
if isset(group) then
-- there's a group name for current list, so add a cell for it
ret[#ret+1] = '<td class="navbox-group" style="'
if isset(colors[ttype]) then
ret[#ret+1] = 'background:' .. condval((border ~= "subgroup" and border ~= "child"), colors[ttype]['group'], colors[ttype]['subgroup']) .. ';'
end
ret[#ret+1] = 'padding-left:1em; padding-right:1em; white-space:nowrap; text-align:right;'
addstyle(ret, frame.args['basestyle'])
if isset(frame.args['groupwidth']) then ret[#ret+1] = 'width:' .. frame.args['groupwidth'] .. ';' end
addstyle(ret, frame.args['groupstyle'])
addstyle(ret, groupstyle)
ret[#ret+1] = '">'
ret[#ret+1] = '<div style="padding:0;">\n'
ret[#ret+1] = group
ret[#ret+1] = '</div></td>'
-- start the content cell
ret[#ret+1] = '<td style="text-align:left;border-left-width:2px;border-left-style:solid;'
else
-- no group name, start the content already
ret[#ret+1] = '<td colspan=2 style="'
end
-- a bit tricky, but this works as XOR
if (frame.args['evenodd'] == "swap") ~= ((k % 2) == 0) then
if isset(colors[ttype]) then ret[#ret+1] = 'background:' .. colors[ttype]['dark'] .. ';' end
else
ret[#ret+1] = 'background:transparent;'
end
if not isset(frame.args['groupwidth']) then ret[#ret+1] = 'width:100%;' end
ret[#ret+1] = 'padding: 0;'
addstyle(ret, frame.args['liststyle'])
addstyle(ret, condval((frame.args['evenodd'] == "swap") ~= ((k % 2) == 0), frame.args['evenstyle'], frame.args['oddstyle']))
addstyle(ret, liststyle)
ret[#ret+1] = '" class="navbox-list ' .. condval((frame.args['evenodd'] == "swap") ~= ((k % 2) == 0), 'navbox-even', 'navbox-odd') .. '">'
-- add the <div> with content (same <div> that child navbox has to close when starting table)
ret[#ret+1] = '<div style="padding:'
if isset(frame.args['list' .. k .. 'padding']) then
ret[#ret+1] = frame.args['list' .. k .. 'padding']
elseif isset(frame.args['listpadding']) then
ret[#ret+1] = frame.args['listpadding']
else
ret[#ret+1] = '0em 0.25em'
end
ret[#ret+1] = ';">\n'
ret[#ret+1] = list
ret[#ret+1] = '</div></td>'
return table.concat(ret)
end
--[[ Generates the "body" of table (everything below title) ]]
local function build_body(frame, border, ttype, lists)
local ret = {}
local sep = isset(frame.args['title']) -- if there was a title, we have to add separation for first row
local imgs = true -- add images if present
local irows = condval( (#lists > 0), (2 * #lists - 1), 1 )
-- aff the 'above' row
ret[#ret+1],sep = build_above_below(frame, border, ttype, frame.args['above'], frame.args['abovestyle'], sep)
for k,v in pairs(lists) do
if sep then -- add separation if needed
ret[#ret+1] = '<tr style="height: 2px;"><td></td></tr>'
end
table.insert(ret, '<tr>')
-- add left image (if wasn't added yet and is present)
if imgs then
if isset(frame.args['imageleft']) then
ret[#ret+1] = '<td style="width:0%;padding:0px 2px 0px 0px;'
addstyle(ret, frame.args['imageleftstyle'])
ret[#ret+1] = '" rowspan="' .. irows .. '">' .. frame.args['imageleft'] .. '</td>'
end
end
-- add the list content
ret[#ret+1] = build_row(frame, border, ttype, v['index'], v['group'], v['list'], v['groupstyle'], v['liststyle'])
-- add right image (if wasn't added yet and is present)
if imgs then
if isset(frame.args['image']) then
ret[#ret+1] = '<td style="width:0%;padding:0px 0px 0px 2px;'
addstyle(ret, frame.args['imagestyle'])
ret[#ret+1] = '" rowspan="' .. irows .. '">' .. frame.args['image'] .. '</td>'
end
-- mark that images were added already
imgs = false
end
ret[#ret+1] = '</tr>'
sep = true -- now the separation is going to be needed for sure
end
ret[#ret+1],sep = build_above_below(frame, border, ttype, frame.args['below'], frame.args['belowstyle'], sep)
return table.concat(ret)
end
-- == Exported functions ==
--[[ Generates and returns the whole navbox table. ]]
local function buildNavbox(frame)
local template = {}
local border = ""
local ttype = ""
if isset(frame.args['border']) then
border = frame.args['border']
elseif isset(frame.args[1]) then
border = string.trim(frame.args[1])
end
if isset(frame.args['type']) then
ttype = frame.args['type']
end
-- TODO: filtering of border and type values?
-- prepare the data first
local lists = scan_lists(frame)
-- build the content
template[#template+1] = start_box(frame, border, ttype)
template[#template+1] = build_title(frame, border, ttype)
template[#template+1] = build_body(frame, border, ttype, lists)
template[#template+1] = end_box(frame, border, ttype)
return table.concat(template)
end
--[[ Mostly for debugging, generates and returns a table of sets of colors
and the values in cells with colors used as backgrounds. ]]
local function buildColorTable(frame)
local ret = {""}
table.insert(ret, '<table class="wikitable" style="text-align: center;">')
table.insert(ret, '<caption>List of colors in order from darkest to brigthest one</caption>')
table.insert(ret, '<tr><th>"type"</th><th>title</th><th>above, below</th><th>group,<br/>sub-above/below</th><th>sub-group</th><th>dark background</th><th>background</th></tr>')
for k,v in pairs(colors) do
table.insert(ret, '<tr>')
table.insert(ret, '<td>' .. k .. '</td>')
table.insert(ret, '<td style="background:' .. v['title'] .. '">' .. v['title'] .. '</td>')
table.insert(ret, '<td style="background:' .. v['above'] .. '">' .. v['above'] .. '</td>')
table.insert(ret, '<td style="background:' .. v['group'] .. '">' .. v['group'] .. '</td>')
table.insert(ret, '<td style="background:' .. v['subgroup'] .. '">' .. v['subgroup'] .. '</td>')
table.insert(ret, '<td style="background:' .. v['dark'] .. '">' .. v['dark'] .. '</td>')
table.insert(ret, '<td style="background:' .. v['background'] .. '">' .. v['background'] .. '</td>')
table.insert(ret, '</tr>')
end
table.insert(ret, '</table>')
return table.concat(ret)
end
-- export local functions
return {
['buildNavbox'] = buildNavbox,
['buildNavboxTemplate'] = function(frame) return buildNavbox(frame:getParent()) end, -- for wrappers
['buildColorTable'] = buildColorTable
}
-- [[Category:Lua Scripts|{{PAGENAME}}]]