Module:Simple navbox
Jump to navigation
Jump to search
local p = {}
local getArgs = require('Module:Arguments').getArgs
-- Utilities
local function lc(v)
return type(v) == 'string' and mw.ustring.lower(v) or v
end
local function hasBackground(s)
return type(s) == 'string' and (
s:find('background', 1, true) or
s:find('background%-color', 1, true)
)
end
local function hasColor(s)
if type(s) ~= 'string' then return false end
s = s:lower()
return s:match('^%s*color%s*:') or s:match('[;%s]color%s*:')
end
-- Helper to prepend basestyle if present
local function prependBaseStyle(basestyle, otherstyle)
if not basestyle or basestyle == '' then
return otherstyle or ''
end
if not otherstyle or otherstyle == '' then
return basestyle
end
return basestyle .. ';' .. otherstyle
end
-- Main entry point
function p.main(frame)
local args = getArgs(frame, {
removeBlanks = false
})
-- Stylesheets (these must be raw strings, not mw.html nodes)
local stylesheets = {}
table.insert(stylesheets, frame:extensionTag{ name = 'templatestyles', args = { src = 'Simple navbox/styles.css' } })
table.insert(stylesheets, frame:extensionTag{ name = 'templatestyles', args = { src = 'Hlist/styles.css' } })
if args.templatestyles then
table.insert(stylesheets, frame:extensionTag{ name = 'templatestyles', args = { src = args.templatestyles } })
end
-- Get basestyle parameter
local basestyle = args.basestyle or ''
-- State logic: collapse/collapsible take precedence over state for legacy compatibility
local state = lc(args.collapse or args.collapsible or args.state or '')
-- Treat "no" as an alias for "plain"
if state == 'no' then
state = 'plain'
end
local collapsible = state ~= 'plain'
local allowOuterImages = not collapsible
local userSetOuterImage = args['image-outer'] or args.imageouter or args.imageouterleft or args['image-outer-right'] or args.imageouterright or args.imageouter2
if userSetOuterImage and collapsible then
mw.addWarning("<code>imageouter</code> type images will not be shown unless <code>|state = plain</code> or <code>|collapse = no</code>.")
end
-- Outer image args
local imageOuterLeft = allowOuterImages and (args['image-outer'] or args.imageouter or args.imageouterleft)
local imageOuterRight = allowOuterImages and (args['image-outer-right'] or args.imageouterright or args.imageouter2)
local hasOuterImages = imageOuterLeft or imageOuterRight
-- Inner images
local imageLeftArg = args.image2 or args.imageleft
local hasInnerImages = args.image or imageLeftArg
if hasOuterImages and hasInnerImages then
mw.addWarning("When <code>|state = plain</code> or <code>|collapse = no</code>, <code>image</code> ''or'' <code>imageouter</code> type images can be used, but ''not'' both.")
end
-- Classes
local bodyclass = args.bodyclass or args.class or ''
local classes = { 'simple-navbox', bodyclass, 'noprint' }
if collapsible then
table.insert(classes, 'NavFrame')
if state == 'collapsed' or state == 'closed' then
table.insert(classes, 'NavClosed')
elseif state == 'expanded' or state == 'uncollapsed' or state == 'open' then
table.insert(classes, 'NavOpen')
end
elseif hasOuterImages then
table.insert(classes, 'simple-outer')
end
-- Add simple-basestyle class if basestyle is present
if basestyle ~= '' then
table.insert(classes, 'simple-basestyle')
end
-- Check for modified groups early
if args.group1 and (hasBackground(args.groupstyle) or hasBackground(args.oddgroupstyle) or hasBackground(args.evengroupstyle)) then
table.insert(classes, 'simple-has-modified-groups')
end
-- Body style
local bodystyle = args.bodystyle or ''
-- Build the outer div
local outerDiv = mw.html.create('div')
:addClass(table.concat(classes, ' '))
:cssText(bodystyle)
-- Outer left image
if imageOuterLeft then
outerDiv:tag('div')
:addClass('simple-outer-image')
:wikitext(imageOuterLeft)
end
-- Header (prepend basestyle before headerstyle/titlestyle)
local headerstyle = prependBaseStyle(basestyle, args.headerstyle or args.titlestyle or '')
local headerClass = 'simple-header NavHead'
if headerstyle ~= '' and hasColor(headerstyle) then
headerClass = headerClass .. ' simple-header-modified'
end
local headerContent = {}
if args.name then
table.insert(headerContent, frame:expandTemplate{ title = 'simple navbar', args = { args.name } })
end
table.insert(headerContent, args.title or 'Default title: add a value for <code>title</code> in the template.')
outerDiv:tag('div')
:addClass(headerClass)
:cssText(headerstyle)
:wikitext(table.concat(headerContent))
-- Nav content wrapper
local navContent = outerDiv:tag('div')
:addClass('simple-navcontent NavContent')
:cssText(args.navcontentstyle or '')
-- Above block (prepend basestyle before abovestyle)
if args.above then
local abovestyle = prependBaseStyle(basestyle, args.abovestyle or '')
navContent:tag('div')
:addClass('simple-group-above')
:cssText(abovestyle)
:wikitext('\n' .. frame:preprocess(args.above) .. '\n')
end
-- Flex container
local imageAlign = lc(args['image-align'] or args.imagealign or '')
local flex = 'display:flex; flex-flow:row;'
if imageAlign == 'left' then
flex = 'display:flex; flex-flow:row-reverse; justify-content:flex-end;'
end
local container = navContent:tag('div')
:addClass('simple-content-container')
:cssText(flex .. ' ' .. (args.containerstyle or ''))
-- Left inner image
local imageLeft = args.image2 or args.imageleft
local imageValign = args['image-valign'] or args.imagevalign or 'center'
if not hasOuterImages and imageLeft then
container:tag('div')
:addClass('simple-image')
:css('align-self', imageValign)
:wikitext(imageLeft)
end
-- Content div
local contentDiv = container:tag('div')
:addClass('simple-content')
:addClass(args.listclass or '')
:cssText(args.contentstyle or '')
-- Grouped mode
if args.group1 then
-- Prepend basestyle to groupstyle base
local groupstyleBase = prependBaseStyle(basestyle, args.groupstyle or '')
local oddGStyle = groupstyleBase .. (args.oddgroupstyle and ';' .. args.oddgroupstyle or '')
local evenGStyle = groupstyleBase .. (args.evengroupstyle and ';' .. args.evengroupstyle or '')
local oddLStyle = (args.liststyle or '') .. (args.oddliststyle and ';' .. args.oddliststyle or '')
local evenLStyle = (args.liststyle or '') .. (args.evenliststyle and ';' .. args.evenliststyle or '')
local tableClass = 'simple-group-container'
if hasBackground(args.groupstyle) or hasBackground(args.oddgroupstyle) or hasBackground(args.evengroupstyle) then
tableClass = tableClass .. ' simple-group-modified'
end
if hasBackground(args.liststyle) or hasBackground(args.oddliststyle) or hasBackground(args.evenliststyle) then
tableClass = tableClass .. ' simple-list-modified'
end
if hasColor(oddGStyle) or hasColor(evenGStyle) then
tableClass = tableClass .. ' simple-group-inherit'
end
local groupTable = contentDiv:tag('table')
:addClass(tableClass)
:cssText(args.tablestyle or '')
local batchLists, groupIndices = {}, {}
for i = 1, 50 do
if args['group' .. i] then
table.insert(batchLists, args['list' .. i] or '')
table.insert(groupIndices, i)
end
end
local preprocessedLists = {}
if #batchLists > 0 then
local sep = '@@SIMPLE_SEPARATOR@@'
local concatenated = table.concat(batchLists, sep)
local processed = frame:preprocess(concatenated)
for part in mw.ustring.gmatch(processed, '(.-)' .. sep) do
table.insert(preprocessedLists, part)
end
if #preprocessedLists < #batchLists then
table.insert(preprocessedLists, mw.ustring.match(processed, '.*' .. sep .. '(.*)') or batchLists[#batchLists])
end
end
for idx, i in ipairs(groupIndices) do
local group = args['group' .. i]
local listContent = preprocessedLists[idx] or ''
local odd = (i % 2 == 1)
local gstyle = (odd and oddGStyle or evenGStyle) .. ';' .. (args['group' .. i .. 'style'] or '')
local lstyle = (odd and oddLStyle or evenLStyle) .. ';' .. (args['list' .. i .. 'style'] or '')
local row = groupTable:tag('tr')
:addClass('simple-group-row')
:cssText(args.rowstyle or '')
row:tag('td')
:addClass('simple-group')
:cssText(gstyle)
:wikitext(group)
row:tag('td')
:addClass('simple-list')
:cssText(lstyle)
:wikitext('\n' .. listContent .. '\n')
end
else
local list = args.list or args.list1 or 'Error: <code>list</code> is empty!'
if list ~= '' then
list = frame:preprocess(list)
end
contentDiv:tag('div')
:addClass('simple-list simple-list-only')
:cssText(args.liststyle or '')
:wikitext('\n' .. list .. '\n')
end
-- Right inner image
if not hasOuterImages and args.image then
container:tag('div')
:addClass('simple-image')
:css('align-self', imageValign)
:wikitext(args.image)
end
-- Below block (prepend basestyle before belowstyle)
if args.below then
local belowstyle = prependBaseStyle(basestyle, args.belowstyle or args.abovestyle or '')
navContent:tag('div')
:addClass('simple-group-above simple-group-below')
:cssText(belowstyle)
:wikitext('\n' .. frame:preprocess(args.below) .. '\n')
end
-- Outer right image
if imageOuterRight then
outerDiv:tag('div')
:addClass('simple-outer-imageright')
:wikitext(imageOuterRight)
end
-- Combine stylesheets with the HTML structure
return table.concat(stylesheets) .. tostring(outerDiv)
end
return p