Module:Navbox

-- Navbox Module -- -- * Supports unlimited rows -- -- Originally written by User:Tjcool007 from layton.fandom.com -- Taken and modified from dev.fandom.com -- Modified to function more closely to the existing Template:Navibox

local p = {}

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

--local working = {} local rownums = {} local activeSection, sections local colspan, rowspan

local showText, hideText = 'Expand', 'Collapse'

local localColors = nil local groupModif = 'group' -- modif marker for applyCS, to differentiate groups

Applies the colorscheme or back/text colors to an HTML element -- -- @param html The html element where the colors should be applied -- @param cond Conditions to be followed. Acceptable values are "group" or a # local function applyCS( html, cond ) -- if a group, use the stored number when checking -- if not a group but cond is defined, its a header and reset if cond == groupModif then cond = localColors elseif cond then localColors = nil end -- check for colors of the specified number or global local cs = (args['colorscheme'..(cond or '')] or args.colorscheme) local bc = (args['backcolor'..(cond or '')] or args.backcolor) local tc = (args['textcolor'..(cond or '')] or args.textcolor) -- apply any colors we found if cs then html:addClass('cs '..(cs or '')) end if not cs and bc then html:cssText('background:#'..bc..';') end if not cs and tc then html:cssText('color:#'..tc..';') end if not localColors and cond then -- is this a header? if args['colorscheme'..cond] or		   args['backcolor'..cond] or		    args['textcolor'..cond] then localColors = cond -- if yes w/ a color, save else localColors = nil end -- if yes w/o a color, reset end -- if no, do nothing end

-- Title

--- Processes the VDE links in the title -- -- @param titlecell The table cell of the title local function processVeq( titlecell ) if not args.template then return end local between = ' · '

local vde = mw.html.create('div') :cssText('position:absolute; left:50px; font-size:80%;') vde:wikitext('&#91; v ') -- V   vde:wikitext(between) vde:wikitext('args.template   	:gsub(' ', '_') ..'?action=edit e') -- E    vde:wikitext(between) vde:wikitext('? &#93;') -- ?

titlecell:node(vde) end

--- Processes the main title row local function processTitle local titlerow = mw.html.create('tr') local titlecell = mw.html.create('th'):attr('colspan',colspan) :attr('scope','col') applyCS(titlerow)

processVeq(titlecell)

local titlediv = mw.html.create('div'):cssText('margin: 0 7em;') titlediv:wikitext(args.title or '')

titlecell:node(titlediv)

-- Padding local hasTemplate = args.template ~= nil local hasState = not args.state or args.state ~= 'plain'

titlerow:node(titlecell) navbox:node(titlerow) end

-- Main Rows

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

local row = mw.html.create('tr') local cell = mw.html.create('td'):attr('colspan',2)

cell:node(sections[activeSection]) row:node(cell)

navbox:node(row) rowspan = rowspan + 1

activeSection = false end

--- Processes a single generic Header "row" -- -- @param num Number of the row to be processed local function processGenericHeader(num) _closeCurrentSection local table_attrs = { align='center', border='0', cellpadding='1', cellspacing='1' }	local subtable = mw.html.create('table'):addClass('collapsible') :attr(table_attrs) :cssText('clear: both; text-align: center; width: 100%;') sections[num] = subtable activeSection = num return subtable 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 -- Special exception: if the first Header, create a generic table -- > Create consistent spacing in the first Group(s) even when -- > header1 isn't explicit if num == 1 then processGenericHeader(1) end return end local subtable = processGenericHeader(num)

local headerrow = mw.html.create('tr') local header = mw.html.create('th'):attr('colspan',2):attr('scope','col') :wikitext( args['header'..num] ):attr('align', 'center') applyCS(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

headerrow:node(header) subtable:node(headerrow) 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')

local listcell = mw.html.create('td') local hlistcell = listcell:tag('div'):addClass('hlist') :attr('align', 'left') 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

if args['group'..num] then local groupcell = mw.html.create('th'):attr('scope','row') :wikitext( args['group'..num]..':' ) groupcell:attr('align', 'center'):attr('width', '15%') applyCS(groupcell, groupModif) row:node( groupcell ) else listcell:attr('colspan',2):addClass('no-group') end

row:node( listcell )

if activeSection then local parent = sections[activeSection] parent:node(row) else navbox:node( row ) rowspan = rowspan + 1 end end

--- Processes all rows local function processRows sections = {} for i=1,#rownums do		local num = rownums[i] processHeader(num) processList(num) end _closeCurrentSection 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 = 2 rowspan = 0

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 -- NOTE: Navibox uses a wrapper table to enforce special spacing. -- Current Navbox implementation bypasses the wrapper table. navbox = mw.html.create('table'):addClass('navbox'):addClass('toccolours') navbox:addClass('mw-collapsible'):attr('align', 'center') navbox:attr('title', args.template or '') navbox:cssText('margin-bottom:5px;') -- no idea if will work if args.state ~= 'plain' then navbox:addClass('mw-collapsed') end

processTitle processRows return tostring(navbox) 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