Module:Infobox: Difference between revisions

Ganaram inukshuk (talk | contribs)
m bugfix entering rows: each row is a table with one or two entries (how it already was)
Sintel (talk | contribs)
Add infobox class
 
(72 intermediate revisions by 3 users not shown)
Line 1: Line 1:
-- This module follows [[User:Ganaram inukshuk/Provisional style guide for Lua]]
local getArgs = require("Module:Arguments").getArgs
local getArgs = require("Module:Arguments").getArgs
local navbar  = require("Module:Navbar")._navbar
local tiu    = require("Module:Template input utils")
local yesno  = require("Module:Yesno")
local p = {}
local p = {}


-- TODO:
-- TODO (medium priority):
-- Transfer functionality to new functions (in-progress)
-- - Use templatestyles
-- Once done, convert old functions into wrapper functions (note that only
-- infobox mos needs the 8-link form, so the 8-link function can be removed and
-- infobox mos updated to use new "main" function)


--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
------------------------------- HELPER FUNCTIONS -------------------------------
-------------------------------- MAIN FUNCTIONS --------------------------------
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------


-- Infobox header with adjacent links
-- Function to be called by other modules; also called by wrapper function
-- Adjacent links are placed on the sides of the title, with options for 0, 2,
function p._infobox(args)
-- or 8 links.
local title         = args["Title"] or "Infobox Title"
function p.infobox_header(title, adjacent_links)
local adjacent_links = args["Adjacent Links"]
local header = ''
local header_row = args["Header Row"]
if adjacent_links == nil then
local rows      = args["Rows"]
header = header .. title
local footer_row = args["Footer Row"]
header = header .. '\n'
local name      = args["name"]
elseif #adjacent_links == 2 then
local prev_link = adjacent_links[1]
-- Helper function; preprocess rows
local next_link = adjacent_links[2]
function preprocess_rows()
header = header
-- Preproces rows
.. '<table style="width: 100%; margin: 0;">\n'
local is_jagged = true
.. '<tr>\n'
for i = 1, #rows do
.. '<td style="width: 15%; text-align: left; white-space: nowrap; font-size: 0.75em;">\n' .. (prev_link or '') .. '</td>\n'
local row = rows[i]
.. '<td style="width: 70%; padding-left: 1em; padding-right: 1em; text-align: center;">\n' .. title             .. '</td>\n'
is_jagged = is_jagged and (#row == 1 or #row == 2)
.. '<td style="width: 15%; text-align: right; white-space: nowrap; font-size: 0.75em;">\n' .. (next_link or '') .. '</td>\n'
end
.. '</tr>\n'
.. '</table>'
if is_jagged then return tiu.jagged_array_to_header_data_pairs(rows)
elseif #adjacent_links == 8 then
else return rows end
-- First row
end
header = header
.. '<table style="width: 100%; margin: 0;">\n'
-- Preprocess rows
.. '<tr>\n' -- First row
rows = preprocess_rows()
.. '<td style="width: 15%; text-align: left; white-space: nowrap; font-size: 0.75em;">\n' .. (adjacent_links[1] or '') .. '</td>\n'
.. '<td style="width: 70%; padding-left: 1em; padding-right: 1em; text-align: center;">\n' .. (adjacent_links[2] or '') .. '</td>\n'
-- Nested helper function
.. '<td style="width: 15%; text-align: right; white-space: nowrap; font-size: 0.75em;">\n' .. (adjacent_links[3] or '') .. '</td>\n'
-- Produces the title and, if present, prev/next links
.. '</tr>\n'
function infobox_title()
.. '<tr>\n' -- Second row
if adjacent_links == nil then
.. '<td style="width: 15%; text-align: left; white-space: nowrap; font-size: 0.75em;">\n' .. (adjacent_links[4] or '') .. '</td>\n'
return title
.. '<td style="width: 70%; padding-left: 1em; padding-right: 1em; text-align: center;">\n' .. title                     .. '</td>\n'
elseif #adjacent_links == 2 then
.. '<td style="width: 15%; text-align: right; white-space: nowrap; font-size: 0.75em;">\n' .. (adjacent_links[5] or '') .. '</td>\n'
lines = {}
.. '</tr>\n'
--table.insert(lines, "\n")
.. '<tr>\n' -- Third row
table.insert(lines, '{| style="width: 100%;"')
.. '<td style="width: 15%; text-align: left; white-space: nowrap; font-size: 0.75em;">\n' .. (adjacent_links[6] or '') .. '</td>\n'
table.insert(lines, '|-')
.. '<td style="width: 70%; padding-left: 1em; padding-right: 1em; text-align: center;">\n' .. (adjacent_links[7] or '') .. '</td>\n'
table.insert(lines, '| style="font-size: 0.75em;" | ' .. adjacent_links[1])
.. '<td style="width: 15%; text-align: right; white-space: nowrap; font-size: 0.75em;">\n' .. (adjacent_links[8] or '') .. '</td>\n'
table.insert(lines, '| style="width: 50%;" | ' .. title)
.. '</tr>\n'
table.insert(lines, '| style="font-size: 0.75em;" | ' .. adjacent_links[2])
table.insert(lines, '|}')
return table.concat(lines, "\n")
elseif #adjacent_links == 8 then
lines = {}
--table.insert(lines, "\n")
table.insert(lines, '{| style="width: 100%;"')
table.insert(lines, '|-')
table.insert(lines, '| style="font-size: 0.75em;" | ' .. adjacent_links[1])
table.insert(lines, '| style="font-size: 0.75em; width: 50%;" | ' .. adjacent_links[2])
table.insert(lines, '| style="font-size: 0.75em;" | ' .. adjacent_links[3])
table.insert(lines, '|-')
table.insert(lines, '| style="font-size: 0.75em;" | ' .. adjacent_links[4])
table.insert(lines, '| style="width: 50%;" | ' .. title)
table.insert(lines, '| style="font-size: 0.75em;" | ' .. adjacent_links[5])
table.insert(lines, '|-')
table.insert(lines, '| style="font-size: 0.75em;" | ' .. adjacent_links[6])
table.insert(lines, '| style="font-size: 0.75em; width: 50%;" | ' .. adjacent_links[7])
table.insert(lines, '| style="font-size: 0.75em;" | ' .. adjacent_links[8])
table.insert(lines, '|}')
return table.concat(lines, "\n")
else
return title
end
end
-- Nested helper function
-- Produces a row in the infobox
function infobox_row(row_content)
local header = row_content["Header"]
local data  = row_content["Data"  ]
if header and data then
local lines = {}
table.insert(lines, '|-')
table.insert(lines, '| style="text-align: right; padding-right: 0.25em;" | ' .. header)
table.insert(lines, '| style="background-color: white; padding-left: 0.25em; font-weight: bold;" | ' .. data)
-- End
return table.concat(lines, "\n")
.. '</table>'
elseif header and not data then
else
local lines = {}
header = title
table.insert(lines, '|-')
table.insert(lines, '| colspan="2" style="text-align: center;" | ' .. header)
return table.concat(lines, "\n")
elseif data and not header then
local lines = {}
table.insert(lines, '|-')
table.insert(lines, '| colspan="2" style="text-align: center;" | ' .. data)
return table.concat(lines, "\n")
end
end
-- Nested helper function
-- Produces a header or footer row
function header_footer_row(row_content)
local lines = {}
table.insert(lines, '|-')
table.insert(lines, '| colspan="2" style="text-align: center; font-size: 0.8em;" | ' .. row_content)
return table.concat(lines, "\n")
end
end
return header
-- Nested helper function
end
-- Produces the navbar, if specified
 
function navbar_row()
-- Row of an infobox
local lines = {}
-- Infobox is set up as a Mediawiki table with two cols.
table.insert(lines, '|-')
function p.infobox_row(row_content)
table.insert(lines, '| colspan="2" style="text-align: center;" | ' .. navbar(name, "mini", ""))
local row = ""
if #row_content > 1 then
return table.concat(lines, "\n")
local caption = row_content[1]
local text    = row_content[2]
row = row
.. '|-\n'
.. '| style="text-align: right; padding-right: 0.25em;" | ' .. caption .. '\n'
.. '| style="background-color: white; padding-left: 0.25em; font-weight: bold;" | ' .. text '\n'
elseif #row_content == 1 then
local text = row_content[1]
row = row
.. '|-\n'
.. '| colspan="2" style="text-align: center;" | ' .. text .. '\n'
end
end
return row
end
--------------------------------------------------------------------------------
-------------------------------- MAIN FUNCTIONS --------------------------------
--------------------------------------------------------------------------------
-- Function to be called by other modules; also called by wrapper function
function p._infobox(args)
local title = args["Title"] or "Infobox Title"
local adjacent_links = args["Adjacent Links"]
local rows = args["Rows"]
-- Start of infobox; outer div and start of table
-- Start of infobox; outer div and start of table
local infobox = '<div style="'
local lines = {}
.. 'border: 1px solid #999; '
.. 'margin: 0; '
-- Infobox boilerplate
.. 'margin-left: 1em; '
table.insert(lines,
.. 'margin-bottom: 0.5em; '
[[<div class="infobox" style="
.. 'padding: 0.5em; '
border: 1px solid #999;  
.. 'background-color: #f0f0f0; '
margin: 0;  
.. 'min-width: 15em; '
margin-left: 1em;  
.. 'float: right; '
margin-bottom: 0.5em;  
.. 'max-width: 100%; '
padding: 0.5em;  
.. 'overflow: auto;">\n'
background-color: #f0f0f0;  
min-width: 15em;  
float: right;  
max-width: 100%;
overflow: auto;">]]
)
table.insert(lines, '{| style="border-collapse: collapse; width: 100%;"')
table.insert(lines, '|+ style="font-size: 105%; font-weight: bold; text-align: center;" | ')
-- Title
table.insert(lines, infobox_title())
-- Header
if header_row then
table.insert(lines, header_footer_row(header_row))
end
-- Infobox table, starting with table
-- Rows
.. '{| width="100%" style="border-collapse: collapse;"\n'
.. '|+ style="font-size: 105%; font-weight: bold; text-align: center;" | ' .. p.infobox_header(title, adjacent_links) .. '\n'
-- For loop for populating entries
for i = 1, #rows do
for i = 1, #rows do
infobox = infobox .. p.infobox_row(rows[i])
table.insert(lines, infobox_row(rows[i]))
end
-- Footer
if footer_row then
table.insert(lines, header_footer_row(footer_row))
end
end
infobox = infobox .. "|}</div>"
return infobox
-- Template navbar
if name then
table.insert(lines, navbar_row())
end
-- End of infobox
table.insert(lines, "|}")
table.insert(lines, "</div>")
 
return table.concat(lines, "\n")
end
end


Line 123: Line 184:
-- Preprocess adjacent links
-- Preprocess adjacent links
-- If there are two adjacent links (such as with edos), then links
-- If there are two adjacent links (such as with edos), then links will be
-- will be placed on the left and right of the title
-- placed on the left and right of the title:
-- [Link 1] Title [Link 2]
-- [Link 1] Title [Link 2]
-- - Link 1 is previous, link 2 is next
-- If there are eight adjacent links (such as with mosses), then links
-- If there are eight adjacent links (such as with mosses), then
-- surround the title in a 3x3 grid:
-- links surround the title, forming a 3x3 grid as such:
-- [Link 1] [Link 2] [Link 3]
-- [Link 1] [Link 2] [Link 3]
-- [Link 4]  Title  [Link 5]
-- [Link 4] Title   [Link 5]
-- [Link 6] [Link 7] [Link 8]
-- [Link 6] [Link 7] [Link 8]
-- - 1: prev_A, prev_B
local function any_keys_present(tbl, keys)
-- - 2: prev_B
for _, key in ipairs(keys) do
-- - 3: next_A, prev_B
if tbl[key] ~= nil then
-- - 4: prev_A, 
return true
-- - 5: next_A, 
end
-- - 6: prev_A, next_B
end
-- - 7: next_B,
return false
-- - 8: next_A, next_B
end
-- Leaving this field nil defaults to only having the title; individual
-- links, as with "border" cases (eg, nothing comes before 0edo), can be
-- Keys to links
-- left blank.
-- Left and right are added if at least one is present -> 2-element table.
-- All three rows are added if at least one link from the upper or lower
-- rows is present, regardless of side links -> 8-element table.
-- No links are added if none of them are present -> 0-element table.
local upper_links = { "Upper Left Link", "Upper Link", "Upper Right Link" }
local side_links  = { "Left Link", "Right Link" }
local lower_links = { "Lower Left Link", "Lower Link", "Lower Right Link" }
-- Check which links are present
local is_upper_lower_links_present =
any_keys_present(args, upper_links) or any_keys_present(args, lower_links)
local is_side_links_present = any_keys_present(args, side_links)
-- Build adjacent_links
-- Links from args are removed, as they're stored in a separate table
local adjacent_links = {}
local adjacent_links = {}
local link_count = tonumber(args["Link Count"]) -- This is 0, 2, or 8
if is_upper_lower_links_present then
if link_count == 2 then
-- Upper row of links
table.insert(adjacent_links, args["Left Link" ])
for _, key in ipairs(upper_links) do
table.insert(adjacent_links, args["Right Link"])
table.insert(adjacent_links, args[key] or "")
elseif link_count == 8 then
args[key] = nil
table.insert(adjacent_links, args["Upper Left Link" ])
end
table.insert(adjacent_links, args["Upper Link"      ])
-- Middle row of links
table.insert(adjacent_links, args["Upper Right Link"])
for _, key in ipairs(side_links) do
table.insert(adjacent_links, args["Left Link"       ])
table.insert(adjacent_links, args[key] or "")
table.insert(adjacent_links, args["Right Link"      ])
args[key] = nil
table.insert(adjacent_links, args["Lower Left Link" ])
end
table.insert(adjacent_links, args["Lower Link"     ])
-- Bottom row of links
table.insert(adjacent_links, args["Lower Right Link"])
for _, key in ipairs(lower_links) do
table.insert(adjacent_links, args[key] or "")
args[key] = nil
end
elseif is_side_links_present then
-- Left and right links only
for _, key in ipairs(side_links) do
table.insert(adjacent_links, args[key] or "")
args[key] = nil
end
end
end
args["Upper Left Link" ] = nil
args["Adjacent Links"] = adjacent_links
args["Upper Link"      ] = nil
args["Upper Right Link"] = nil
args["Left Link"      ] = nil
args["Right Link"      ] = nil
args["Lower Left Link" ] = nil
args["Lower Link"      ] = nil
args["Lower Right Link"] = nil
-- Preprocess rows
-- Preprocess rows
-- Set row count to 30; if more rows are needed, this can be changed or a
-- Set row count to 30, under the reasoning that an infobox may need more
-- module can be written for that.
-- rows and/or headers. This may be increased to 40 if needed.
local rows = {}
args["Rows"] = tiu.numbered_header_data_args_to_table(args, 30)
for i = 1, 30 do
local header = args["Header " .. i]
local result = p._infobox(args)
local data  = args["Data "   .. i]
local debugg = yesno(args["debug"])
if debugg == true then
local row = nil
result = "<syntaxhighlight lang=\"wikitext\">" .. result .. "</syntaxhighlight>"
if (header == nil and data ~= nil) then
table.insert(row, data)
elseif (header ~= nil and data ~= nil) then
table.insert(row, header)
table.insert(row, data)
end
if row ~= nil then
table.insert(rows, row)
end
-- Remove original entries as cleanup
args["Header " .. i] = nil
args["Data "   .. i] = nil
end
end
args["Rows"] = rows
return p._infobox(args)
return result
end
end


--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
------------------------------ EXISTING FUNCTIONS ------------------------------
------------------------------- LEGACY FUNCTIONS -------------------------------
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------


-- Original function; kept for supporting old navboxes
-- These functions are kept in the meantime to support older infoboxes and WILL
-- be entirely deleted later! Please switch to the new functions!
 
-- Original function signature, kept for legacy support (for now).
function p.build(title, entries, prev_link, next_link)
function p.build(title, entries, prev_link, next_link)
local s = "<div style=\""
local args = {
.. "border: 1px solid #999; "
["Adjacent Links"] = { (prev_link or ""), (next_link or "") },
.. "margin: 0; "
["Title"] = title,
.. "margin-left: 1em; "
["Rows"] = entries
.. "margin-bottom: 0.5em; "
}
.. "padding: 0.5em; "
 
.. "background-color: #f0f0f0; "
return p._infobox(args)
.. "min-width: 15em; "
.. "float: right; "
.. "max-width: 100%; "
.. "overflow: auto; "
.. "\">\n"
.. "{| width=\"100%\" style=\"border-collapse: collapse;\"\n"
.. "|+ style=\"font-size: 105%; font-weight: bold; text-align: center;\" | "
local has_adjacent = (prev_link and #prev_link > 0) or (next_link and #next_link > 0)
if has_adjacent then
s = s
.. "<table style=\"width: 100%; margin: 0;\"><tr>"
.. "<td style=\"width: 15%; text-align: left; white-space: nowrap; font-size: 0.75em;\">"
.. (prev_link or "")
.. "</td>"
.. "<td style=\"width: 70%; padding-left: 1em; padding-right: 1em; text-align: center;\">"
.. title
.. "</td>"
.. "<td style=\"width: 15%; text-align: right; white-space: nowrap; font-size: 0.75em;\">"
.. (next_link or "")
.. "</td>"
.. "</tr></table>"
else
s = s .. title
end
s = s .. "\n"
for _, entry in ipairs(entries) do
if #entry > 1 then
local caption = entry[1]
local text = entry[2]
s = s
.. "|-\n"
.. "| style=\"text-align: right; padding-right: 0.25em;\" | "
.. caption
.. "\n"
.. "| style=\"background-color: white; padding-left: 0.25em; font-weight: bold;\" | "
.. text
.. "\n"
elseif #entry == 1 then
local text = entry[1]
s = s .. "|-\n" .. "| colspan=\"2\" style=\"text-align: center;\" | ".. text .. "\n"
end
end
s = s .. "|}</div>"
return s
end
end


-- Multilink infobox
-- Original 8-link function signature, pulled from infobox mos.
-- The following must be passed in:
-- - Title (self-explanatory)
-- - Sections (see comments for details)
-- - Adjacent links; supports 0, 2, or 8 adjacent links
function p.build_multilink(title, entries, adjacent_links)
function p.build_multilink(title, entries, adjacent_links)
-- Boilerplate stuff
local args = {
local s = "<div style=\""
["Adjacent Links"] = adjacent_links,
.. "border: 1px solid #999; "
["Title"] = title,
.. "margin: 0; "
["Rows"] = entries
.. "margin-left: 1em; "
}
.. "margin-bottom: 0.5em; "
 
.. "padding: 0.5em; "
return p._infobox(args)
.. "background-color: #f0f0f0; "
.. "min-width: 15em; "
.. "float: right; "
.. "max-width: 100%; "
.. "overflow: auto;"
.. "\">\n"
.. "{| width=\"100%\" style=\"border-collapse: collapse;\"\n"
.. "|+ style=\"font-size: 105%; font-weight: bold; text-align: center;\" | "
-- Adjacent links
-- If there are two adjacent links (such as with edos), then links
-- will be placed on the left and right of the title
-- [Link 1] Title [Link 2]
-- - Link 1 is previous, link 2 is next
-- If there are eight adjacent links (such as with mosses), then
-- links surround the title, forming a 3x3 grid as such:
-- [Link 1] [Link 2] [Link 3]
-- [Link 4]  Title  [Link 5]
-- [Link 6] [Link 7] [Link 8]
-- - 1: prev_A, prev_B
-- - 2: prev_B
-- - 3: next_A, prev_B
-- - 4: prev_A, 
-- - 5: next_A, 
-- - 6: prev_A, next_B
-- - 7: next_B, 
-- - 8: next_A, next_B
-- Leaving this field nil defaults to only having the title; individual
-- links, as with "border" cases (eg, nothing comes before 0edo), can be
-- left blank.
if adjacent_links == nil then
s = s .. title
s = s .. "\n"
elseif #adjacent_links == 2 then
local prev_link = adjacent_links[1]
local next_link = adjacent_links[2]
s = s
.. "<table style=\"width: 100%; margin: 0;\"><tr>"
.. "<td style=\"width: 15%; text-align: left; white-space: nowrap; font-size: 0.75em;\">"
.. (prev_link or "")
.. "</td>"
.. "<td style=\"width: 70%; padding-left: 1em; padding-right: 1em; text-align: center;\">"
.. title
.. "</td>"
.. "<td style=\"width: 15%; text-align: right; white-space: nowrap; font-size: 0.75em;\">"
.. (next_link or "")
.. "</td>"
.. "</tr></table>"
s = s .. "\n"
elseif #adjacent_links == 8 then
-- First row
s = s .. "<table style=\"width: 100%; margin: 0;\"><tr>"
.. "<td style=\"width: 15%; text-align: left; white-space: nowrap; font-size: 0.75em;\">"
.. (adjacent_links[1] or "")
.. "</td>"
.. "<td style=\"width: 75%; padding-left: 1em; padding-right: 1em; text-align: center; font-size: 0.75em;\">"
.. (adjacent_links[2] or "")
.. "\n</td><td style=\"width: 15%; text-align: right; white-space: nowrap; font-size: 0.75em;\">"
.. (adjacent_links[3] or "")
.. "</td>"
-- Second row
.. "\n<tr>"
.. "<td style=\"width: 15%; text-align: left; white-space: nowrap; font-size: 0.75em;\">"
.. (adjacent_links[4] or "")
.. "</td>"
.. "<td style=\"width: 75%; padding-left: 1em; padding-right: 1em; text-align: center;\">"
.. title
.. "</td>"
.. "<td style=\"width: 15%; text-align: right; white-space: nowrap; font-size: 0.75em;\">"
.. (adjacent_links[5] or "")
.. "</td>"
.. "</tr>"
.. "<tr>"
-- Third row
.. "<td style=\"width: 15%; text-align: left; white-space: nowrap; font-size: 0.75em;\">"
.. (adjacent_links[6] or "")
.. "</td><td style=\"width: 75%; padding-left: 1em; padding-right: 1em; text-align: center; font-size: 0.75em;\">"
.. (adjacent_links[7] or "")
.. "\n</td>"
.. "<td style=\"width: 15%; text-align: right; white-space: nowrap; font-size: 0.75em;\">"
.. (adjacent_links[8] or "")
.. "</td>"
.. "</tr>"
.. "</table>"
s = s .. "\n"
else
s = s .. title
s = s .. "\n"
end
-- Add infobox entries
-- Entries are entered as a jagged array (array of arrays) where each
-- subarray has either one or two entries.
-- These entries form the rows of a two-column table.
-- One-entry arrays are used for entries that must span both columns,
-- such as a section header. Two-entry arrays are used for the main content.
for _, entry in ipairs(entries) do
if #entry > 1 then
local caption = entry[1]
local text = entry[2]
s = s
.. "|-\n"
.. "| style=\"text-align: right; padding-right: 0.25em;\" | "
.. caption
.. "\n"
.. "| style=\"background-color: white; padding-left: 0.25em; font-weight: bold;\" | "
.. text
.. "\n"
elseif #entry == 1 then
local text = entry[1]
s = s .. "|-\n" .. "| colspan=\"2\" style=\"text-align: center;\" | " .. text .. "\n"
end
end
-- End of infobox
s = s .. "|}\n"
    .. "</div>"
return s
end
end


return p
return p