FANDOM


--------------------------------------------------------------------
--<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
Community content is available under CC-BY-SA unless otherwise noted.