Module:Navbox

-- Navbox Module -- -- * Fully CSS styled (inline styles possible but not default) -- * Supports unlimited rows -- -- By User:Tjcool007 from layton.wikia.com

local p = {}

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

--local working = {} local rownums, skiprows = {}, {} local hasrows, alt, hasData, isChild = false, false, false, false local activeSection, sections, 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, ['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') :cssText(args.titlegroupstyle) :wikitext(args.titlegroup) end

local titleCell = titleRow:tag('th')

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

titleCell :cssText(args.basestyle) :cssText(args.titlestyle) :addClass('navbox-title') :attr('colspan', colspan)

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(' ') end else if args.state ~= 'plain' then titlebar:css('float', 'left') :css('text-align', 'left') :wikitext(' ') 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

-- Gutter

--- Add gutter between rows -- -- @param parent node, inRowspan to increment image rowspan local function _addGutter( parent, incRowspan ) if spacer then parent:tag('tr'):css('height', '2px'):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') :addClass('navbox-abovebelow') :addClass( args[rowtype .. 'class'] )

local abcell = abrow:tag('td') :attr('colspan', colspan) :cssText(args[rowtype .. 'style']) :cssText(args.basestyle)

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

_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 iclass = imgtype == 'image' and 'navbox-image-right' or 'navbox-image-left'

local imagecell = mw.html.create('td'):addClass('navbox-image'):addClass(iclass)

local image = args[imgtype] 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 if args[imgtype .. 'style'] then imagecell:cssText( args[imgtype .. 'style'] ) end

row:node( imagecell ) if imgtype == 'image' then cimage = imagecell else cimageleft = imagecell end end

--- Closes the currently active section (if any) local function _closeCurrentSection if not activeSection then return end

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

activeSection = false hasData = false 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

--- Process a single Header "row" -- -- @param num Number of the row to be processed local function processHeader(num) if not args['header'..num] then return end

_closeCurrentSection

local subtable = mw.html.create('table'):addClass('navbox-section') local headerrow = mw.html.create('tr') 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 state = false

if collapseme then -- Look at this one if collapseme ~= 'plain' then 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

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

if args.headerclass then headerrow:addClass( args.headerclass ) end if args.headerstyle then header:cssText( args.headerstyle ) end

headerrow:node(header) subtable:node(headerrow)

sections[num] = subtable activeSection = num 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'):addClass('navbox-row')

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

local listcell = mw.html.create('td'):addClass('navbox-list') local hlistcell = listcell:tag('div'):addClass('hlist')

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

if data:sub(1,1) == '*' then -- Add newlines to support lists properly hlistcell :newline :wikitext( data ) :newline else hlistcell:wikitext( data ) end

local altRow = _evenoddRow if altRow then row:addClass( args.altrowclass or 'alt' )

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 if args.rowclass then row:addClass( args.rowclass ) end if args.listclass then listcell:addClass( args.listclass ) end if args.liststyle then listcell:cssText( args.liststyle ) end end

if args['group'..num] then local groupcell = mw.html.create('th'):addClass('navbox-group'):attr('scope','row'):wikitext( args['group'..num] )

if altRow then local groupclass = args.altgroupclass or args.groupclass or false if groupclass then groupcell:addClass( groupclass ) end

local groupstyle = args.altgroupstyle or args.groupstyle or false if groupstyle then groupcell:cssText( groupstyle ) end else if args.groupclass then groupcell:addClass( args.groupclass ) end if args.groupstyle then groupcell:cssText( args.groupstyle ) end end

row:node( groupcell ) else listcell:attr('colspan',2):addClass('no-group') end

row:node( listcell )

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

if activeSection then local parent = sections[activeSection] 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; end

--- Processes all rows local function processRows sections = {} for i=1,#rownums do		local num = rownums[i] if not skiprows[num] then processHeader(num) processList(num) end end _closeCurrentSection

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 == 'header' or 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

if args.evenodd == 'swap' then alt = true end

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

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

-- 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') :cssText(args.bodystyle) :cssText(args.style) 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') navbox:addClass(args.state) 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) :cssText(args.bodystyle) :cssText(args.style) :tag('tr') :tag('td') :css('padding', '2px') :node(navbox) return tostring(wrapper) else local wrapper = mw.html.create('') wrapper:wikitext(' ') wrapper:node(navbox) wrapper:wikitext(' ') return tostring(wrapper) end end

--- Main module entry point. -- To be called with 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