Tropedia

  • Before making a single edit, Tropedia EXPECTS our site policy and manual of style to be followed. Failure to do so may result in deletion of contributions and blocks of users who refuse to learn to do so. Our policies can be reviewed here.
  • All images MUST now have proper attribution, those who neglect to assign at least the "fair use" licensing to an image may have it deleted. All new pages should use the preloadable templates feature on the edit page to add the appropriate basic page markup. Pages that don't do this will be subject to deletion, with or without explanation.
  • All new trope pages will be made with the "Trope Workshop" found on the "Troper Tools" menu and worked on until they have at least three examples. The Trope workshop specific templates can then be removed and it will be regarded as a regular trope page after being moved to the Main namespace. THIS SHOULD BE WORKING NOW, REPORT ANY ISSUES TO Janna2000, SelfCloak or RRabbit42. DON'T MAKE PAGES MANUALLY UNLESS A TEMPLATE IS BROKEN, AND REPORT IT THAT IS THE CASE. PAGES WILL BE DELETED OTHERWISE IF THEY ARE MISSING BASIC MARKUP.

READ MORE

Tropedia
Advertisement

Documentation for this module may be created at Module:Navbox/doc

--------------------------------------------------------------------
--<pre> Navbox Module
--
-- * Fully CSS styled (inline styles possible but not default)
-- * Supports unlimited rows
--
-- By User:Tjcool007 from layton.fandom.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 showText, hideText = 'Show', 'Hide'

local langCode = mw.getContentLanguage():getCode()
local localization = {} --localized strings table
localization['en'] = {show = 'Show', hide = 'Hide'}
localization['ru'] = {show = 'показать', hide = 'скрыть'}
localization['zh'] = {show = '显示', hide = '隐藏'}
if localization[langCode] then
    showText = localization[langCode]['show']
    hideText = localization[langCode]['hide']
end

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

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

	titlecell:wikitext('<span class="navbox-vde">'
		.. mw.getCurrentFrame():expandTemplate({
			title = 'vdelinks',
			args = { args.template, ['type'] = 'navbox' }
		}) .. '</span>')
end

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

	if not pcall( processVde, titlecell ) then
		titlecell:wikitext( '<b class="navbox-vde error" title="Missing Template:Vdelinks">!!!</b>' )
	end

	titlecell:wikitext( args.title or '{{{title}}}' )

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

	if hasTemplate ~= hasState then
		if hasTemplate then
			titlecell:addClass('navbox-title-padright')
		else
			titlecell:addClass('navbox-title-padleft')
		end
	end

	if args.titleclass then titlerow:addClass( args.titleclass ) end
	if args.titlestyle then titlecell:cssText( args.titlestyle ) end

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

local function _addGutter( parent, incRowspan )
	parent:tag('tr'):addClass('navbox-gutter'):tag('td'):attr('colspan',2)

	if incRowspan then
		rowspan = rowspan + 1
	end
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-'..rowtype)
	local abcell = mw.html.create('td'):attr('colspan',colspan):wikitext( args[rowtype] )

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

	abrow:node( abcell )
	_addGutter( navbox )
	navbox:node( abrow )
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 alternating rows
--
-- @return Alternatingly returns true or false. Always returns false if alternating rows
--         are disabled with "alternaterows = no"
local function _alternateRow()
	if args.alternaterows == 'no' then return false end
	if alt then
		alt = false
		return true
	else
		alt = true
		return false
	end
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 = _alternateRow()
	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
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
	rowspan = 0

	if args.alternaterows == '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')

	if isChild then
		navbox = mw.html.create('table'):addClass('navbox-subgroup')
	else
		navbox = mw.html.create('table'):addClass('navbox')

		if args.state ~= 'plain' then
			navbox:addClass('mw-collapsible'):attr('data-expandtext',args['expandtext'] or args['defaultexpandtext'] or showText):attr('data-collapsetext',args['collapsetext'] or args['defaultcollapsetext'] or hideText)
			if args.state == 'collapsed' then
				navbox:addClass('mw-collapsed')
			end
		end
	end

 	if args.bodyclass then navbox:addClass(args.bodyclass) end
	if args.bodystyle then navbox:cssText(args.bodystyle) end

	-- Process...
	if not isChild then
		processTitle()
		processAboveBelow('above')
		processRows()
		processAboveBelow('below')

		return tostring(navbox)
	else
		processRows()

		local wrapper = mw.html.create('')
		wrapper:wikitext('</div>')
		wrapper:node(navbox)
		wrapper:wikitext('<div class="hlist">')
		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
Advertisement