Disney Magic Kingdoms Wiki

The Sword in the Stone Part 3 Update has arrived! ✨
Visit this page to learn all about what's coming up in Disney Magic Kingdoms!

READ MORE

Disney Magic Kingdoms Wiki
mNo edit summary
No edit summary
(45 intermediate revisions by the same user not shown)
Line 4: Line 4:
 
-- * Fully CSS styled (inline styles possible but not default)
 
-- * Fully CSS styled (inline styles possible but not default)
 
-- * Supports unlimited rows
 
-- * Supports unlimited rows
  +
-- * Supports collapsible groups (just set parameter withcollapsiblegroups)
 
--
 
--
-- By User:Tjcool007 from layton.wikia.com
+
-- By User:Effan_R from disneymagickingdomswiki.fandom.com
  +
-- Adapted from Navbox Module by User:Tjcool007 from layton.wikia.com
 
--------------------------------------------------------------------
 
--------------------------------------------------------------------
   
Line 13: Line 15:
 
local navbox -- Actual navbox
 
local navbox -- Actual navbox
   
--local working = {}
+
local rownums = {}
local rownums, skiprows = {}, {}
+
local hasrows, alt, altg, isChild = false, false, false, false
  +
local cimage, cimageleft
local hasrows, alt, hasData, isChild = false, false, false, false
 
local activeSection, sections, cimage, cimageleft
 
 
local colspan, rowspan
 
local colspan, rowspan
 
local spacer = false
 
local spacer = false
Line 32: Line 33:
 
titlecell:wikitext(mw.getCurrentFrame():expandTemplate({
 
titlecell:wikitext(mw.getCurrentFrame():expandTemplate({
 
title = 'Navbar',
 
title = 'Navbar',
args = { args.name, ['border'] = 'none', ['mini'] = 1}
+
args = { args.name,
  +
['fontstyle'] = (args.basestyle or '') .. ';' .. (args.titlestyle or '') .. ';border:none;',
  +
['mini'] = 1
  +
}
 
}))
 
}))
 
end
 
end
Line 44: Line 48:
   
 
if args.titlegroup then
 
if args.titlegroup then
titleRow
+
titleRow:tag('td')
:tag('td')
 
 
:addClass('navbox-group')
 
:addClass('navbox-group')
:cssText(args.titlegroupstyle)
 
 
:wikitext(args.titlegroup)
 
:wikitext(args.titlegroup)
  +
if args.titlegroupstyle then titlerow:cssText(args.titlegroupstyle) end
 
end
 
end
   
Line 54: Line 57:
   
 
if args.titlegroup then
 
if args.titlegroup then
titleCell
+
titleCell:css('border-left', '2px solid #fdfdfd')
:css('border-left', '2px solid #fdfdfd')
+
:css('width', '100%')
:css('width', '100%')
 
 
end
 
end
   
titleCell
+
titleCell:addClass('navbox-title')
  +
:attr('colspan', colspan)
:cssText(args.basestyle)
 
  +
:cssText(args.titlestyle)
 
  +
if args.basestyle then titleCell:cssText(args.basestyle) end
:addClass('navbox-title')
 
  +
if args.titlestyle then titleCell:cssText(args.titlestyle) end
:attr('colspan', colspan)
 
   
 
local titlebar = titleCell:tag('div')
 
local titlebar = titleCell:tag('div')
Line 72: Line 74:
 
if args.state == 'plain' then
 
if args.state == 'plain' then
 
titlebar:css('float', 'right')
 
titlebar:css('float', 'right')
:wikitext(' ')
+
:wikitext(' ')
 
end
 
end
 
else
 
else
 
if args.state ~= 'plain' then
 
if args.state ~= 'plain' then
 
titlebar:css('float', 'left')
 
titlebar:css('float', 'left')
:css('text-align', 'left')
+
:css('text-align', 'left')
:wikitext(' ')
+
:wikitext(' ')
 
end
 
end
 
end
 
end
Line 92: Line 94:
 
:css('font-size', (isChild and '100%' or '110%'))
 
:css('font-size', (isChild and '100%' or '110%'))
 
:wikitext(args.title)
 
:wikitext(args.title)
  +
  +
spacer = true
  +
end
  +
  +
--- Processes the group title row
  +
local function processGroupTitle(parent, num)
  +
-- Nothing to do if no group # --
  +
if not args['group' .. num] then return end
  +
  +
local titleRow = parent:tag('tr')
  +
  +
local titleCell = titleRow:tag('th')
  +
  +
titleCell:addClass('navbox-title')
  +
:attr('colspan', colspan)
  +
  +
if args.basestyle then titleCell:cssText(args.basestyle) end
  +
if args.groupstyle then titleCell:cssText(args.groupstyle) end
  +
if args['group' .. num .. 'style'] then
  +
titleCell:cssText(args['group' .. num .. 'style'])
  +
end
  +
  +
local titlebar = titleCell:tag('div')
  +
titlebar:css('width', '6em')
  +
:css('float', 'left')
  +
:css('text-align', 'left')
  +
:wikitext(' ')
  +
  +
titleCell
  +
:tag('span')
  +
:css('font-size', '100%')
  +
:wikitext(args['group' .. num])
   
 
spacer = true
 
spacer = true
Line 105: Line 139:
 
local function _addGutter( parent, incRowspan )
 
local function _addGutter( parent, incRowspan )
 
if spacer then
 
if spacer then
parent:tag('tr'):css('height', '2px'):tag('td')
+
local gutterCell = parent:tag('tr'):css('height', '2px')
  +
gutterCell:tag('td')
 
end
 
end
   
Line 125: Line 160:
   
 
local abrow = mw.html.create('tr')
 
local abrow = mw.html.create('tr')
  +
local abcell = mw.html.create('td')
:addClass('navbox-abovebelow')
 
:addClass( args[rowtype .. 'class'] )
 
   
local abcell = abrow:tag('td')
+
abcell:addClass('navbox-abovebelow')
:attr('colspan', colspan)
+
:attr('colspan', colspan)
  +
:cssText(args[rowtype .. 'style'])
 
  +
if args[rowtype .. 'class'] then abcell:addClass(args[rowtype .. 'class']) end
:cssText(args.basestyle)
 
  +
if args.basestyle then abcell:cssText(args.basestyle) end
  +
if args[rowtype .. 'style'] then abcell:cssText(args[rowtype .. 'style']) end
   
 
abcell:tag('div')
 
abcell:tag('div')
 
:wikitext(args[rowtype])
 
:wikitext(args[rowtype])
   
  +
abrow:node(abcell)
 
_addGutter( navbox )
 
_addGutter( navbox )
 
navbox:node( abrow )
 
navbox:node( abrow )
Line 150: Line 187:
 
if not args[imgtype] then return end
 
if not args[imgtype] then return end
   
  +
local imagecell = row:tag('td')
local iclass = imgtype == 'image' and 'navbox-image-right' or 'navbox-image-left'
 
  +
:addClass('navbox-image')
   
  +
imagecell:css('width', '0%')
local imagecell = mw.html.create('td'):addClass('navbox-image'):addClass(iclass)
 
  +
:css('padding', '0px 0px 0px 2px')
   
  +
if args.imageclass then imagecell:addClass(args.imageclass) end
local image = args[imgtype]
 
  +
if args.imagestyle then imagecell:cssText(args.imagestyle) end
if image:sub(1,1) ~= '[' then
 
local width = args[imgtype .. 'width'] or '100px'
 
imagecell:css('width',width):wikitext('['..'[' .. image .. '|' .. width .. '|link=' .. (args[imgtype .. 'link'] or '') .. ']]')
 
else
 
imagecell:css('width','0%'):wikitext(image)
 
end
 
   
if args[imgtype .. 'class'] then imagecell:addClass( args[imgtype .. 'class'] ) end
+
local imagediv = imagecell:tag('div')
  +
:wikitext(args[imgtype])
if args[imgtype .. 'style'] then imagecell:cssText( args[imgtype .. 'style'] ) end
 
   
row:node( imagecell )
 
 
if imgtype == 'image' then
 
if imgtype == 'image' then
 
cimage = imagecell
 
cimage = imagecell
Line 173: Line 206:
 
end
 
end
   
  +
--- Handles Odd Even Groups
--- Closes the currently active section (if any)
 
  +
--
local function _closeCurrentSection()
 
  +
-- @return Alternatingly returns true (odd) or false (even). Returns fixed value of
if not activeSection then return end
 
  +
-- true (odd) or false (even) if specified by args.evenodd
  +
local function _evenoddGroup()
  +
if args.evenodd == 'even' then return false end
  +
if args.evenodd == 'odd' then return true end
   
  +
altg = not altg
local row = mw.html.create('tr'):addClass('navbox-section-row')
 
local cell = mw.html.create('td'):attr('colspan',2)
 
 
if not hasrows then
 
_processImage(row,'imageleft')
 
end
 
 
cell:node(sections[activeSection])
 
row:node(cell)
 
 
local firstRow = false
 
if not hasrows then
 
firstRow = true
 
hasrows = true
 
_processImage(row,'image')
 
end
 
 
_addGutter(navbox,not firstRow)
 
navbox:node(row)
 
rowspan = rowspan + 1
 
   
  +
return altg
activeSection = false
 
hasData = false
 
 
end
 
end
   
Line 215: Line 232:
 
end
 
end
   
--- Process a single Header "row"
+
--- Processes a single list row
 
--
 
--
 
-- @param num Number of the row to be processed
 
-- @param num Number of the row to be processed
local function processHeader(num)
+
local function processList(num)
if not args['header'..num] then return end
+
if not args['list'..num] then return end
   
  +
local row = mw.html.create('tr')
_closeCurrentSection()
 
  +
local listrow = row
   
  +
if not hasrows then
local subtable = mw.html.create('table'):addClass('navbox-section')
 
  +
_processImage(row, 'imageleft')
local headerrow = mw.html.create('tr')
 
  +
end
local header = mw.html.create('th'):addClass('navbox-header'):attr('colspan',2):attr('scope','col'):wikitext( args['header'..num] )
 
   
local collapseme = args['state'..num] or false
+
local listpadding = args['list' .. num .. 'padding'] or args.listpadding or '0em 0.25em'
local state = false
 
   
if collapseme then
+
if args['group'..num] then
  +
if args.withcollapsiblegroups then
-- Look at this one
 
  +
-- convert Group to collapsible title row --
if collapseme ~= 'plain' then
 
  +
_addGutter(navbox)
state = collapseme == 'expanded' and 'expanded' or 'collapsed'
 
end
 
else
 
-- Look at default
 
local collapseall = args.defaultstate or false
 
if collapseall then
 
state = collapseall == 'expanded' and 'expanded' or 'collapsed'
 
end
 
end
 
   
  +
local altGroup = _evenoddGroup()
if state then
 
subtable:addClass('mw-collapsible'):attr('data-expandtext',args['expandtext'..num] or args['defaultexpandtext'] or showText):attr('data-collapsetext',args['collapsetext'..num] or args['defaultcollapsetext'] or hideText)
 
if state == 'collapsed' then
 
subtable:addClass('mw-collapsed')
 
end
 
header:addClass('navbox-header-collapsible')
 
end
 
   
  +
local headercell = row:tag('td')
if args.headerclass then headerrow:addClass( args.headerclass ) end
 
  +
:addClass('navbox-list')
if args.headerstyle then header:cssText( args.headerstyle ) end
 
  +
:attr('colspan', 2)
  +
:css('padding', '0px')
   
  +
if altGroup then
headerrow:node(header)
 
  +
headercell:addClass('navbox-odd')
subtable:node(headerrow)
 
  +
if args.oddstyle then headercell:cssText(args.oddstyle) end
  +
else
  +
headercell:addClass('navbox-even')
  +
if args.evenstyle then headercell:cssText(args.evenstyle) end
  +
end
   
  +
if args.listclass then headercell:addClass(args.listclass) end
sections[num] = subtable
 
  +
if args.liststyle then headercell:cssText(args.liststyle) end
activeSection = num
 
  +
if args['list' .. num .. 'style'] then headercell:cssText(args['list' .. num .. 'style']) end
end
 
  +
if not args.groupwidth then headercell:css('width', '100%') end
   
  +
headercell:tag('div')
--- Processes a single list row
 
  +
:css('padding', listpadding)
--
 
-- @param num Number of the row to be processed
 
local function processList(num)
 
if not args['list'..num] then return end
 
   
local row = mw.html.create('tr')
+
local headertable = headercell:tag('table')
  +
headertable:addClass('navbox-subgroup')
  +
if args.bodystyle then headertable:cssText(args.bodystyle) end
  +
if args.style then headertable:cssText(args.style) end
   
  +
headertable:addClass('nowraplinks')
if not hasrows and not activeSection then
 
  +
:addClass('mw-collapsible')
_processImage(row, 'imageleft')
 
  +
:attr('cellspacing', '0')
end
 
  +
:attr('data-expandtext', 'show')
  +
:attr('data-collapsetext', 'hide')
  +
:css('border-spacing', 0)
   
  +
if args.bodyclass then headertable:addClass(args.bodyclass) end
if args['group'..num] then
 
  +
if args.innerstyle then headertable:cssText(args.innerstyle) end
local groupcell = row:tag('th'):addClass('navbox-group'):attr('scope','row'):wikitext( args['group'..num] )
 
   
if args.groupclass then groupcell:addClass( args.groupclass ) end
+
if args.selected ~= args['abbr' .. num] then
  +
if args['state' .. num] then
if args.groupstyle then groupcell:cssText( args.groupstyle ) end
 
  +
headertable:addClass(args['state' .. num])
if args.basestyle then groupcell:cssText( args.basestyle ) end
 
  +
else
  +
headertable:addClass('mw-collapsed')
  +
end
  +
end
   
  +
processGroupTitle(headertable, num)
if args['group' .. num .. 'style'] then
 
  +
_addGutter(headertable)
groupcell:cssText(args['group' .. num .. 'style'])
 
end
 
   
  +
alt = (args.evenodd == 'swap')
row:node( groupcell )
 
else
 
listcell:attr('colspan',2)
 
end
 
   
  +
listrow = headertable:tag('tr')
local listcell = mw.html.create('td'):addClass('navbox-list')
 
  +
else
local hlistcell = listcell:tag('div'):addClass('hlist')
 
  +
local groupcell = row:tag('th')
  +
:addClass('navbox-group')
  +
:attr('scope','row')
  +
:wikitext( args['group'..num] )
   
  +
if args.groupclass then groupcell:addClass( args.groupclass ) end
local data = args['list'..num]
 
  +
if args.groupstyle then groupcell:cssText( args.groupstyle ) end
 
  +
if args.basestyle then groupcell:cssText( args.basestyle ) end
if data:sub(1,1) == '*' then
 
  +
if args['group' .. num .. 'style'] then groupcell:cssText(args['group' .. num .. 'style']) end
-- Add newlines to support lists properly
 
  +
if args.groupwidth then groupcell:css('width', args.groupwidth) end
hlistcell
 
  +
end
:newline()
 
:wikitext( data )
 
:newline()
 
else
 
hlistcell:wikitext( data )
 
 
end
 
end
   
 
local altRow = _evenoddRow()
 
local altRow = _evenoddRow()
  +
  +
local listcell = listrow:tag('td')
  +
:addClass('navbox-list')
  +
:css('padding', '0px')
   
 
if altRow then
 
if altRow then
row:addClass( args.altrowclass or 'alt' )
+
listcell:addClass('navbox-odd')
  +
if args.oddstyle then listcell:cssText(args.oddstyle) end
 
local listclass = args.altlistclass or args.listclass or false
 
if listclass then listcell:addClass( listclass ) end
 
 
local liststyle = args.altliststyle or args.liststyle or false
 
if liststyle then listcell:cssText( liststyle ) end
 
 
else
 
else
if args.rowclass then row:addClass( args.rowclass ) end
+
listcell:addClass('navbox-even')
if args.listclass then listcell:addClass( args.listclass ) end
+
if args.evenstyle then listcell:cssText(args.evenstyle) end
if args.liststyle then listcell:cssText( args.liststyle ) end
 
 
end
 
end
   
  +
if not args.withcollapsiblegroups and args.listclass then listcell:addClass(args.listclass) end
if args['group'..num] then
 
  +
if args.liststyle then listcell:cssText(args.liststyle) end
  +
if args['list' .. num .. 'style'] then listcell:cssText(args['list' .. num .. 'style']) end
  +
if not args.groupwidth then listcell:css('width', '100%') end
  +
  +
if not args.withcollapsiblegroups and args['group'..num] then
 
listcell:css('text-align', 'left')
 
listcell:css('text-align', 'left')
 
:css('border-left-width', '2px')
 
:css('border-left-width', '2px')
Line 328: Line 345:
 
end
 
end
   
  +
row:node( listcell )
 
  +
local hlistcell = listcell:tag('div')
  +
:css('padding', listpadding)
  +
  +
local data = args['list'..num]
  +
  +
local srchpat = args['stripbegin' .. num] or args.stripbegin
  +
  +
if srchpat and srchpat ~= "" then
  +
srchpat = string.gsub(srchpat, "([%^%$%(%)%.%+%-%?])", "%%%1")
  +
data = string.gsub(data, "%[%[(" .. srchpat .. "%s*)([^%]|]-)%]%]", "[[%1%2|%2]]")
  +
data = string.gsub(data, "%[%[([^%]]-|)(" .. srchpat .. "%s*)([^%]|]-)%]%]", "[[%1%3]]")
  +
end
  +
  +
srchpat = args['stripend' .. num] or args.stripend
  +
  +
if srchpat and srchpat ~= "" then
  +
srchpat = string.gsub(srchpat, "([%^%$%(%)%.%+%-%?])", "%%%1")
  +
data = string.gsub(data, "%[%[([^%]]-|[^%]]-)(%s*" .. srchpat .. ")%]%]", "[[%1]]")
  +
data = string.gsub(data, "%[%[([^%]%|]-)(%s*" .. srchpat .. ")%]%]", "[[%1%2|%1]]")
  +
end
  +
  +
if data:match('^[*:;#]') then
  +
-- Add newlines to support lists properly
  +
hlistcell
  +
:newline()
  +
:wikitext( data )
  +
:newline()
  +
else
  +
hlistcell:wikitext( data )
  +
end
   
 
local firstRow = false
 
local firstRow = false
if not hasrows and not activeSection then
+
if not hasrows then
 
firstRow = true
 
firstRow = true
 
hasrows = true
 
hasrows = true
Line 337: Line 384:
 
end
 
end
   
  +
_addGutter(navbox,not firstRow)
if activeSection then
 
  +
navbox:node( row )
local parent = sections[activeSection]
 
  +
rowspan = rowspan + 1
if not isChild or not firstRow then
 
_addGutter(parent)
 
end
 
parent:node(row)
 
hasData = true
 
else
 
if not isChild or not firstRow then
 
_addGutter(navbox,not firstRow)
 
end
 
navbox:node( row )
 
rowspan = rowspan + 1
 
end
 
 
 
spacer = true
 
spacer = true
 
end
 
end
Line 357: Line 392:
 
--- Processes all rows
 
--- Processes all rows
 
local function processRows()
 
local function processRows()
sections = {}
 
 
for i=1,#rownums do
 
for i=1,#rownums do
local num = rownums[i]
+
processList(rownums[i])
if not skiprows[num] then
 
processHeader(num)
 
processList(num)
 
end
 
 
end
 
end
_closeCurrentSection()
 
   
 
if cimageleft then
 
if cimageleft then
Line 403: Line 432:
 
local cat,num = tostring(k):match('^(%a+)([1-9]%d*)$')
 
local cat,num = tostring(k):match('^(%a+)([1-9]%d*)$')
   
if cat == 'header' or cat == 'list' then
+
if cat == 'list' then
 
nums[num] = true
 
nums[num] = true
 
end
 
end
Line 417: Line 446:
 
rowspan = 0
 
rowspan = 0
   
if args.evenodd == 'swap' then
+
alt = (args.evenodd == 'swap')
alt = true
+
altg = alt
end
 
   
 
for k, v in pairs(nums) do
 
for k, v in pairs(nums) do
Line 426: Line 454:
   
 
table.sort(rownums)
 
table.sort(rownums)
 
-- Calculate skip rows
 
local cSection, cSkip
 
local showall = args.showall
 
for i=1,#rownums do
 
local num = rownums[i]
 
if args['header'..num] then
 
cSection = true
 
cSkip = false
 
local showme = args['show'..num]
 
if showme == 'no' then
 
cSkip = true
 
elseif showme == 'auto' or (showme ~= 'yes' and showall ~= 'yes') then
 
if not args['list'..num] then
 
local nextNum = rownums[i+1]
 
cSkip = not nextNum or args['header'..nextNum] -- If next has a header -> skip
 
end
 
end
 
end
 
if cSection and cSkip then
 
skiprows[num] = true
 
end
 
end
 
 
end
 
end
   
Line 469: Line 474:
 
navbox = mw.html.create('table')
 
navbox = mw.html.create('table')
 
navbox:addClass('navbox-subgroup')
 
navbox:addClass('navbox-subgroup')
:cssText(args.bodystyle)
+
if args.bodystyle then navbox:cssText(args.bodystyle) end
:cssText(args.style)
+
if args.style then navbox:cssText(args.style) end
 
else
 
else
 
navbox = mw.html.create('table')
 
navbox = mw.html.create('table')
Line 489: Line 494:
 
if args.state ~= 'plain' and args.stat ~= 'off' then
 
if args.state ~= 'plain' and args.stat ~= 'off' then
 
navbox:addClass('mw-collapsible')
 
navbox:addClass('mw-collapsible')
navbox:addClass(args.state)
+
if args.state then navbox:addClass(args.state) end
 
end
 
end
 
end
 
end
Line 507: Line 512:
 
:attr('cellspacing', '0')
 
:attr('cellspacing', '0')
 
:css('border-spacing', 0)
 
:css('border-spacing', 0)
:cssText(args.bodystyle)
+
if args.bodystyle then wrapper:cssText(args.bodystyle) end
:cssText(args.style)
+
if args.style then wrapper:cssText(args.style) end
:tag('tr')
+
local wrapperrow = wrapper:tag('tr')
:tag('td')
+
wrapperrow:tag('td')
 
:css('padding', '2px')
 
:css('padding', '2px')
 
:node(navbox)
 
:node(navbox)

Revision as of 00:38, 9 February 2020

Description

This module is the Lua back-end for {{Navbox}}.

Usage

{{#invoke:Navbox|main|<parameter list>}}

For parameter details see Template:Navbox/doc


--------------------------------------------------------------------
--<pre> Navbox Module
--
-- * Fully CSS styled (inline styles possible but not default)
-- * Supports unlimited rows
-- * Supports collapsible groups (just set parameter withcollapsiblegroups)
--
-- By User:Effan_R from disneymagickingdomswiki.fandom.com
-- Adapted from Navbox Module by User:Tjcool007 from layton.wikia.com
--------------------------------------------------------------------

local p = {}

local args = {} -- Arguments passed to template
local navbox -- Actual navbox

local rownums = {}
local hasrows, alt, altg, isChild = false, false, false, false
local cimage, cimageleft
local colspan, rowspan
local spacer = false

------------------------------------------------
-- Title
------------------------------------------------

--- Processes the VDE links in the title
--
-- @param titlecell The table cell of the title
local function processVde( titlecell )
	if not args.name then return end

	titlecell:wikitext(mw.getCurrentFrame():expandTemplate({
			title = 'Navbar',
			args = { args.name,
					['fontstyle'] = (args.basestyle or '') .. ';' .. (args.titlestyle or '') .. ';border:none;',
					['mini'] = 1
					}
		}))
end

--- Processes the main title row
local function processTitle()
	-- Nothing to do if no title --
	if not args.title then return end

	local titleRow = navbox:tag('tr')

	if args.titlegroup then
		titleRow:tag('td')
				:addClass('navbox-group')
				:wikitext(args.titlegroup)
		if args.titlegroupstyle then titlerow:cssText(args.titlegroupstyle) end
	end

	local titleCell = titleRow:tag('th')

	if args.titlegroup then
		titleCell:css('border-left', '2px solid #fdfdfd')
				:css('width', '100%')
	end

	titleCell:addClass('navbox-title')
			:attr('colspan', colspan)

	if args.basestyle then titleCell:cssText(args.basestyle) end
	if args.titlestyle then titleCell:cssText(args.titlestyle) end

	local titlebar = titleCell:tag('div')
	titlebar:css('width', '6em')

	if not args.name and isChild or args.navbar == 'plain' or args.navbar == 'off' then
		if args.navbar == 'off' then
			if args.state == 'plain' then
				titlebar:css('float', 'right')
						:wikitext('&nbsp;')
			end
		else
			if args.state ~= 'plain' then
				titlebar:css('float', 'left')
						:css('text-align', 'left')
						:wikitext('&nbsp;')
			end
		end
	else
		titlebar:css('float', 'left')
			:css('text-align', 'left')
		processVde(titlebar)
	end

	titleCell
		:tag('span')
			:addClass(args.titleclass)
			:css('font-size', (isChild and '100%' or '110%'))
			:wikitext(args.title)

	spacer = true
end

--- Processes the group title row
local function processGroupTitle(parent, num)
	-- Nothing to do if no group #	--
	if not args['group' .. num] then return end

	local titleRow = parent:tag('tr')

	local titleCell = titleRow:tag('th')

	titleCell:addClass('navbox-title')
			:attr('colspan', colspan)

	if args.basestyle then titleCell:cssText(args.basestyle) end
	if args.groupstyle then titleCell:cssText(args.groupstyle) end
	if args['group' .. num .. 'style'] then
		titleCell:cssText(args['group' .. num .. 'style'])
	end

	local titlebar = titleCell:tag('div')
	titlebar:css('width', '6em')
		:css('float', 'left')
		:css('text-align', 'left')
		:wikitext('&nbsp;')

	titleCell
		:tag('span')
			:css('font-size', '100%')
			:wikitext(args['group' .. num])

	spacer = true
end

------------------------------------------------
-- Gutter
------------------------------------------------

--- Add gutter between rows
--
-- @param parent node, inRowspan to increment image rowspan
local function _addGutter( parent, incRowspan )
	if spacer then
		local gutterCell = parent:tag('tr'):css('height', '2px')
		gutterCell:tag('td')
	end

	if incRowspan then
		rowspan = rowspan + 1
	end
	spacer = false
end

------------------------------------------------
-- Above/Below
------------------------------------------------

--- Processes the above and below rows
--
-- @param rowtype Either 'above' or 'below'
local function processAboveBelow( rowtype )
	if not args[rowtype] then return end

	local abrow = mw.html.create('tr')
	local abcell = mw.html.create('td')

	abcell:addClass('navbox-abovebelow')
		:attr('colspan', colspan)

	if args[rowtype .. 'class'] then abcell:addClass(args[rowtype .. 'class']) end
	if args.basestyle then abcell:cssText(args.basestyle) end
	if args[rowtype .. 'style'] then abcell:cssText(args[rowtype .. 'style']) end

	abcell:tag('div')
		:wikitext(args[rowtype])

	abrow:node(abcell)
	_addGutter( navbox )
	navbox:node( abrow )

	spacer = true
end

------------------------------------------------
-- Main Rows
------------------------------------------------

--- Processes the images
local function _processImage(row, imgtype)
	if not args[imgtype] then return end

	local imagecell = row:tag('td')
						:addClass('navbox-image')

	imagecell:css('width', '0%')
			:css('padding', '0px 0px 0px 2px')

	if args.imageclass then imagecell:addClass(args.imageclass) end
	if args.imagestyle then imagecell:cssText(args.imagestyle) end

	local imagediv = imagecell:tag('div')
							:wikitext(args[imgtype])

	if imgtype == 'image' then
		cimage = imagecell
	else
		cimageleft = imagecell
	end
end

--- Handles Odd Even Groups
--
-- @return Alternatingly returns true (odd) or false (even). Returns fixed value of
--	       true (odd) or false (even) if specified by args.evenodd
local function _evenoddGroup()
	if args.evenodd == 'even' then return false end
	if args.evenodd == 'odd' then return true end

	altg = not altg

	return altg
end

--- Handles Odd Even rows
--
-- @return Alternatingly returns true (odd) or false (even). Returns fixed value of
--	       true (odd) or false (even) if specified by args.evenodd
local function _evenoddRow()
	if args.evenodd == 'even' then return false end
	if args.evenodd == 'odd' then return true end

	alt = not alt

	return alt
end

--- Processes a single list row
--
-- @param num Number of the row to be processed
local function processList(num)
	if not args['list'..num] then return end

	local row = mw.html.create('tr')
	local listrow = row

	if not hasrows then
		_processImage(row, 'imageleft')
	end

	local listpadding = args['list' .. num .. 'padding'] or args.listpadding or '0em 0.25em'

	if args['group'..num] then
		if args.withcollapsiblegroups then
			-- convert Group to collapsible title row --
			_addGutter(navbox)

			local altGroup = _evenoddGroup()

			local headercell = row:tag('td')
								:addClass('navbox-list')
								:attr('colspan', 2)
								:css('padding', '0px')

			if altGroup then
				headercell:addClass('navbox-odd')
				if args.oddstyle then headercell:cssText(args.oddstyle) end
			else
				headercell:addClass('navbox-even')
				if args.evenstyle then headercell:cssText(args.evenstyle) end
			end

			if args.listclass then headercell:addClass(args.listclass) end
			if args.liststyle then headercell:cssText(args.liststyle) end
			if args['list' .. num .. 'style'] then headercell:cssText(args['list' .. num .. 'style']) end
			if not args.groupwidth then headercell:css('width', '100%') end

			headercell:tag('div')
						:css('padding', listpadding)

			local headertable = headercell:tag('table')
			headertable:addClass('navbox-subgroup')
			if args.bodystyle then headertable:cssText(args.bodystyle) end
			if args.style then headertable:cssText(args.style) end

			headertable:addClass('nowraplinks')
				:addClass('mw-collapsible')
				:attr('cellspacing', '0')
				:attr('data-expandtext', 'show')
				:attr('data-collapsetext', 'hide')
				:css('border-spacing', 0)

			if args.bodyclass then headertable:addClass(args.bodyclass) end
			if args.innerstyle then headertable:cssText(args.innerstyle) end

			if args.selected ~= args['abbr' .. num] then
				if args['state' .. num] then
					headertable:addClass(args['state' .. num])
				else
					headertable:addClass('mw-collapsed')
				end
			end

			processGroupTitle(headertable, num)
			_addGutter(headertable)

			alt =  (args.evenodd == 'swap')

			listrow = headertable:tag('tr')
		else
			local groupcell = row:tag('th')
								:addClass('navbox-group')
								:attr('scope','row')
								:wikitext( args['group'..num] )

			if args.groupclass then groupcell:addClass( args.groupclass ) end
			if args.groupstyle then groupcell:cssText( args.groupstyle ) end
			if args.basestyle then groupcell:cssText( args.basestyle ) end
			if args['group' .. num .. 'style'] then groupcell:cssText(args['group' .. num .. 'style'])	end
			if args.groupwidth then groupcell:css('width', args.groupwidth) end
		end
	end

	local altRow = _evenoddRow()

	local listcell = listrow:tag('td')
						:addClass('navbox-list')
						:css('padding', '0px')

	if altRow then
		listcell:addClass('navbox-odd')
		if args.oddstyle then listcell:cssText(args.oddstyle) end
	else
		listcell:addClass('navbox-even')
		if args.evenstyle then listcell:cssText(args.evenstyle) end
	end

	if not args.withcollapsiblegroups and args.listclass then listcell:addClass(args.listclass) end
	if args.liststyle then listcell:cssText(args.liststyle) end
	if args['list' .. num .. 'style'] then listcell:cssText(args['list' .. num .. 'style']) end
	if not args.groupwidth then listcell:css('width', '100%') end

	if not args.withcollapsiblegroups and args['group'..num] then
		listcell:css('text-align', 'left')
			:css('border-left-width', '2px')
			:css('border-left-style', 'solid')
	else
		listcell:attr('colspan',2)
	end


	local hlistcell = listcell:tag('div')
				:css('padding', listpadding)

	local data = args['list'..num]

	local srchpat = args['stripbegin' .. num] or args.stripbegin

	if srchpat and srchpat ~= "" then
		srchpat = string.gsub(srchpat, "([%^%$%(%)%.%+%-%?])", "%%%1")
		data = string.gsub(data, "%[%[(" .. srchpat .. "%s*)([^%]|]-)%]%]", "[[%1%2|%2]]")
		data = string.gsub(data, "%[%[([^%]]-|)(" .. srchpat .. "%s*)([^%]|]-)%]%]", "[[%1%3]]")
	end

	srchpat = args['stripend' .. num] or args.stripend

	if srchpat and srchpat ~= "" then
		srchpat = string.gsub(srchpat, "([%^%$%(%)%.%+%-%?])", "%%%1")
		data = string.gsub(data, "%[%[([^%]]-|[^%]]-)(%s*" .. srchpat .. ")%]%]", "[[%1]]")
		data = string.gsub(data, "%[%[([^%]%|]-)(%s*" .. srchpat .. ")%]%]", "[[%1%2|%1]]")
	end

	if data:match('^[*:;#]') then
		-- Add newlines to support lists properly
		hlistcell
			:newline()
			:wikitext( data )
			:newline()
	else
		hlistcell:wikitext( data )
	end

	local firstRow = false
	if not hasrows then
		firstRow = true
		hasrows = true
		_processImage(row, 'image')
	end

	_addGutter(navbox,not firstRow)
	navbox:node( row )
	rowspan = rowspan + 1
	spacer = true
end

--- Processes all rows
local function processRows()
	for i=1,#rownums do
		processList(rownums[i])
	end

	if cimageleft then
		cimageleft:attr('rowspan',rowspan)
	end
	if cimage then
		cimage:attr('rowspan',rowspan)
	end
end

------------------------------------------------
-- ARGUMENTS PREPROCESSOR
-- * Extracts arguments from frame and stores them in args table
-- * At the same time, checks for valid row numbers
------------------------------------------------

--- Preprocessor for the arguments.
-- Will fill up the args table with the parameters from the frame grouped by their type.
--
-- @param frame The frame passed to the Module.
local function preProcessArgs(frame)
	local tmp = {}

	if frame == mw.getCurrentFrame() then
		tmp = frame:getParent().args
	else
		tmp = frame
	end

	-- Storage tables
	local nums = {}

	-- Loop over all the args
	for k,v in pairs(tmp) do
		-- Skip empty args, which are useless
		if v ~= '' then
			local cat,num = tostring(k):match('^(%a+)([1-9]%d*)$')

			if cat == 'list' then
				nums[num] = true
			end

			args[k] = v -- Simple copy
		end
	end

	colspan = args.image and 3 or 2
	if args.imageleft then colspan = colspan + 1 end
	if args.titlegroup then colspan = colspan - 1 end

	rowspan = 0

	alt =  (args.evenodd == 'swap')
	altg = alt

	for k, v in pairs(nums) do
		rownums[#rownums+1] = tonumber(k)
	end

	table.sort(rownums)
end

------------------------------------------------
-- MAIN FUNCTIONS
------------------------------------------------

--- Processes the arguments to create the navbox.
--
-- @return A string with HTML that is the navbox.
local function _navbox()
	-- Create the root HTML element
	local trim = function(s)
		return s and mw.ustring.gsub(s, "^%s*(.-)%s*$", "%1") or ''
	end
	local border = args.border or trim(args[1])  or ''
	isChild = (border == 'child' or border == 'subgroup' or border == 'none')

	if isChild then
		navbox = mw.html.create('table')
		navbox:addClass('navbox-subgroup')
		if args.bodystyle then navbox:cssText(args.bodystyle) end
		if args.style then navbox:cssText(args.style) end
	else
		navbox = mw.html.create('table')
		navbox:addClass('navbox-inner')
			:css('background', 'transparent')
			:css('color', 'inherit')
	end

	navbox:addClass('nowraplinks')
		:addClass(args.bodyclass)
		:attr('cellspacing', '0')
		:attr('data-expandtext', 'show')
		:attr('data-collapsetext', 'hide')
		:css('border-spacing', 0)
		:cssText(args.innerstyle)

	if args.title then
		if args.state ~= 'plain' and args.stat ~= 'off' then
			navbox:addClass('mw-collapsible')
			if args.state then	navbox:addClass(args.state) end
		end
	end

	-- Process...
	spacer = false

	processTitle()
	processAboveBelow('above')
	processRows()
	processAboveBelow('below')

	-- Wrapper Table --
	if not isChild then
		local wrapper = mw.html.create('table')
		wrapper:addClass('navbox')
				:attr('cellspacing', '0')
				:css('border-spacing', 0)
		if args.bodystyle then wrapper:cssText(args.bodystyle) end
		if args.style then wrapper:cssText(args.style) end
		local wrapperrow = wrapper:tag('tr')
		wrapperrow:tag('td')
				:css('padding', '2px')
				:node(navbox)
		return tostring(wrapper)
	else
		local wrapper = mw.html.create('')
		wrapper:wikitext('</div>')
		wrapper:node(navbox)
		wrapper:wikitext('<div>')
		return tostring(wrapper)
	end
end

--- Main module entry point.
-- To be called with {{#invoke:navbox|main}} or directly from another module.
--
-- @param frame The frame passed to the module via the #invoke. If called from another
--              module directly, this should be a table with the parameter definition.
function p.main(frame)
	-- Save the arguments in a local variable so other functions can use them.
	preProcessArgs(frame)

	return _navbox()
end

return p