コンテンツにスキップ

モジュール:Navbox/former/sandbox

モジュールの解説[表示] [編集] [履歴] [キャッシュを破棄]

{{Navbox}}を実装するモジュールです。詳しい使い方は当該テンプレートの説明文を参照してください。

require('strict')
local p = {}
local cfg = mw.loadData('Module:Navbox/configuration')

--[[
Define Arguments
]]
local getArgs
local args = {}
local border
local child, none = false, false
local rowspan = 0
local odd, even = 'odd', 'even'

local list, liststyle, listclass = {}, {}, {}
local group, groupstyle = {}, {}
local colheader, colheadercolspan, colheaderstyle = {}, {}, {}
local col, colstyle, colwidth = {}, {}, {}
local colfooter, colfootercolspan, colfooterstyle = {}, {}, {}
local abbr, state = {}, {}
local sect, section = {}, {}
local secttitlestyle = {}
local content, contentstyle = {}
local image, imageleft = {}, {}

local function defArgs(frame, wrappers)
	if not getArgs then
		getArgs = require('Module:Arguments').getArgs
	end
	args = getArgs(frame, {wrappers = wrappers})
	border = args.border or args[1]
	child, none = (child or border == 'subgroup' or border == 'child'), (border == 'none')
	
	local sortable_mt = {
		__lt = function(a, b) return a.index < b.index end,
		__concat = function(a, b)
			local strA = (type(a) == 'table') and a.content or a or ''
			local strB = (type(b) == 'table') and b.content or b or ''
			return strA .. strB
		end
	}
	local function sortable_args(tbl, index, content)
		table.insert(tbl, {index = index, content = content})
		setmetatable(tbl[#tbl], sortable_mt)
	end
	local switch = {
		--common
		list = function(num, v) sortable_args(list, num, v) end,
		liststyle = function(num, v) liststyle[num] = v end,
		listclass = function(num, v) listclass[num] = v end,
		group = function(num, v) group[num] = v end,
		groupstyle = function(num, v) groupstyle[num] = v end,
		--for with_columns
		colheader = function(num,v) colheader[num] = v end,
		colheadercolspan = function(num,v) colheadercolspan[num] = v end,
		colheaderstyle = function(num,v) colheaderstyle[num] = v end,
		col = function(num, v) sortable_args(col, num, v) end,
		colstyle = function(num,v) colstyle[num] = v end,
		colwidth = function(num,v) colwidth[num] = v end,
		colfooter = function(num,v) colfooter[num] = v end,
		colfootercolspan = function(num,v) colfootercolspan[num] = v end,
		colfooterstyle = function(num,v) colfooterstyle[num] = v end,
		--for with_collapsible_groups
		abbr = function(num, v) abbr[num] = v end,
		state = function(num, v) state[num] = v end,
		sect = function(num, v) group[num] = v end,
		section = function(num, v) group[num] = v end,
		secttitlestyle = function(num, v) groupstyle[num] = v end,
		content = function(num, v) sortable_args(content, num, v) end,
		contentstyle = function(num, v) liststyle[num] = v end,
		image = function(num, v) image[num] = v end,
		imageleft = function(num, v) imageleft[num] = v end,
	}
	
	for k, v in pairs(args) do
		local str1, num, str2 = string.match(k, '^(%D+)(%d+)(%D*)$')
		str1, num, str2 = str1 or '', tonumber(num), str2 or ''
		if switch[str1 .. str2] and num then switch[str1 .. str2](num, v) end
	end
	
	table.sort(list)
	rowspan = #list
end

local function processItem(item, nowrapitems)
	if item:sub(1, 2) == '{|' then
		-- Applying nowrap to lines in a table does not make sense.
		-- Add newlines to compensate for trim of x in |parm=x in a template.
		return '\n' .. item ..'\n'
	end
	if nowrapitems == cfg.keyword.nowrapitems_yes then
		local lines = {}
		for line in (item .. '\n'):gmatch('([^\n]*)\n') do
			local prefix, content = line:match('^([*:;#]+)%s*(.*)')
			if prefix and not content:match(cfg.pattern.nowrap) then
				line = format(cfg.nowrap_item, prefix, content)
			end
			table.insert(lines, line)
		end
		item = table.concat(lines, '\n')
	end
	if item:match('^[*:;#]') then
		return '\n' .. item ..'\n'
	end
	return item
end

local function has_navbar()
	return args[cfg.arg.navbar] ~= cfg.keyword.navbar_off
		and args[cfg.arg.navbar] ~= cfg.keyword.navbar_plain
		and not (child or none)
		and (
			args[cfg.arg.name]
			or mw.getCurrentFrame():getParent():getTitle():gsub(cfg.pattern.sandbox, '')
				~= cfg.pattern.navbox
		)
end

--[[
top
]]
local function top(baseTag)
	local function has_list_class(htmlclass)
		local patterns = {
			'^' .. htmlclass .. '$',
			'%s' .. htmlclass .. '$',
			'^' .. htmlclass .. '%s',
			'%s' .. htmlclass .. '%s'
		}
		
		for arg, _ in pairs(args) do
			if type(arg) == 'string' and mw.ustring.find(arg, cfg.pattern.class) then
				for _, pattern in ipairs(patterns) do
					if mw.ustring.find(args[arg] or '', pattern) then
						return true
					end
				end
			end
		end
		return false
	end
	
	-- there are a lot of list classes in the wild, so we add their TemplateStyles
	local function add_list_styles()
		local frame = mw.getCurrentFrame()
		local function add_list_templatestyles(htmlclass, templatestyles)
			if has_list_class(htmlclass) then
				return frame:extensionTag{
					name = 'templatestyles', args = { src = templatestyles }
				}
			else
				return ''
			end
		end
		
		local hlist_styles = add_list_templatestyles('hlist', cfg.hlist_templatestyles)
		local plainlist_styles = add_list_templatestyles('plainlist', cfg.plainlist_templatestyles)
		
		-- a second workaround for [[phab:T303378]]
		-- when that issue is fixed, we can actually use has_navbar not to emit the
		-- tag here if we want
		if has_navbar() and hlist_styles == '' then
			hlist_styles = frame:extensionTag{
				name = 'templatestyles', args = { src = cfg.hlist_templatestyles }
			}
		end
		
		-- hlist -> plainlist is best-effort to preserve old Common.css ordering.
		-- this ordering is not a guarantee because most navboxes will emit only
		-- one of these classes [hlist_note]
		return hlist_styles .. plainlist_styles
	end
	
	local function add_navbox_styles(hiding_templatestyles)
		local frame = mw.getCurrentFrame()
		-- This is a lambda so that it doesn't need the frame as a parameter
		local function add_user_styles(templatestyles)
			if templatestyles and templatestyles ~= '' then
				return frame:extensionTag{
					name = 'templatestyles', args = { src = templatestyles }
				}
			end
			return ''
		end
	
		-- get templatestyles. load base from config so that Lua only needs to do
		-- the work once of parser tag expansion
		local base_templatestyles = cfg.templatestyles
		local templatestyles = add_user_styles(args[cfg.arg.templatestyles])
		local child_templatestyles = add_user_styles(args[cfg.arg.child_templatestyles])
	
		-- The 'navbox-styles' div exists to wrap the styles to work around T200206
		-- more elegantly. Instead of combinatorial rules, this ends up being linear
		-- number of CSS rules.
		return mw.html.create('div')
			:addClass(cfg.class.navbox_styles)
			:wikitext(
				add_list_styles() .. -- see [hlist_note] applied to 'before base_templatestyles'
				base_templatestyles ..
				templatestyles ..
				child_templatestyles ..
				table.concat(hiding_templatestyles)
			)
			:done()
	end
	
	-- work around [[phab:T303378]]
	-- for each arg: find all the templatestyles strip markers, insert them into a
	-- table. then remove all templatestyles markers from the arg
	local function move_hiding_templatestyles(args)
		local gfind = string.gfind
		local gsub = string.gsub
		local templatestyles_markers = {}
		local strip_marker_pattern = '(\127[^\127]*UNIQ%-%-templatestyles%-%x+%-QINU[^\127]*\127)'
		for k, arg in pairs(args) do
			for marker in gfind(arg, strip_marker_pattern) do
				table.insert(templatestyles_markers, marker)
			end
			args[k] = gsub(arg, strip_marker_pattern, '')
		end
		return templatestyles_markers
	end
	
	local hiding_templatestyles = move_hiding_templatestyles(args)
	local listnums = {}
	
	for k, _ in pairs(args) do
		if type(k) == 'string' then
			local listnum = k:match(cfg.pattern.listnum)
			if listnum then table.insert(listnums, tonumber(listnum)) end
		end
	end
	table.sort(listnums)
	
	local nav
	local bodyTable
	if baseTag == nil or baseTag == '' then
		baseTag = mw.html.create()
	end
	if child then
		baseTag:wikitext('</div>')
		nav = baseTag
	elseif not none then
		baseTag:node(add_navbox_styles(hiding_templatestyles))
		nav = baseTag:tag('div')
			:attr('role', 'navigation')
			:addClass('navbox')
			:addClass(args.navboxclass)
			:cssText(args.bodystyle)
			:cssText(args.style)
			:css('padding', '3px')
		if args.title or args.above then
			nav:attr('aria-labelledby', mw.uri.anchorEncode(args.title or args.above))
		else
			nav:attr('aria-label', 'Navbox')
		end
	else
		baseTag:node(add_navbox_styles(hiding_templatestyles))
		nav = baseTag
	end
	
	bodyTable = nav:tag('table')
		:addClass('nowraplinks')
		:addClass(args.bodyclass)

	if args.title and (args.state ~= 'plain' and args.state ~= 'off') then
		if args.state == 'collapsed' then args.state = 'mw-collapsed' end
		bodyTable
			:addClass('mw-collapsible')
			:addClass(args.state or 'autocollapse')
	end

	bodyTable:css('border-spacing', 0)
	if child or border == 'none' then
		bodyTable
			:addClass('navbox-subgroup')
			:cssText(args.bodystyle)
			:cssText(args.style)
	else  -- regular navbox - bodystyle and style will be applied to the wrapper table
		bodyTable
			:addClass('navbox-inner')
			:css('border-spacing', 0)
			:css('background', 'transparent')
			:css('color', 'inherit')
	end
	bodyTable:cssText(args.innerstyle)
	
	return baseTag, bodyTable
end

--[[
title and navbar
]]
local function title(tbl)
	if not args.title then return tbl end
	local titleRow = tbl:tag('tr')
	local titleCell = titleRow:tag('th'):attr('scope', 'col')
	local titleColspan = 2
	if args.imageleft then titleColspan = titleColspan + 1 end
	if args.image then titleColspan = titleColspan + 1 end
	if args.titlegroup then titleColspan = titleColspan - 1 end

	titleCell
		:cssText(args.basestyle)
		:cssText(args.titlestyle)
		:addClass('navbox-title')
		:attr('colspan', titleColspan)
	
	-- extract text color from css, which is the only permitted inline CSS for the navbar
	local function extract_color(css_str)
		-- return nil because navbar takes its argument into mw.html which handles
		-- nil gracefully, removing the associated style attribute
		return mw.ustring.match(';' .. css_str .. ';', '.*;%s*([Cc][Oo][Ll][Oo][Rr]%s*:%s*.-)%s*;') or nil
	end
	
	local function renderNavBar(titleCell)
		if has_navbar() then
			local navbar = require('Module:Navbar/sandbox')._navbar
			titleCell:wikitext(navbar{
				[cfg.navbar.name] = args[cfg.arg.name],
				[cfg.navbar.mini] = 1,
				[cfg.navbar.fontstyle] = extract_color(
					(args[cfg.arg.basestyle] or '') .. ';' .. (args[cfg.arg.titlestyle] or '')
				)
			})
		end
	end
	
	renderNavBar(titleCell)
	
	titleCell
		:tag('div')
			:attr('id', mw.uri.anchorEncode(args.title))
			:addClass(args.titleclass)
			:css('font-size', '110%')	-- [[:en:Module:Navbox]]では114%
			:css('margin', '0 6em')	-- [[:en:Module:Navbox]]では横マージンが4em(日本語版のNavbarは幅が4emを超える)
			:wikitext(processItem(args.title))

	return tbl
end

local function getAboveBelowColspan()
	local ret = 2
	if args.imageleft then ret = ret + 1 end
	if args.image then ret = ret + 1 end
	return ret
end

--[[
above
]]
local function above(tbl)
	if not args.above then return tbl end

	tbl:tag('tr')
		:tag('td')
			:addClass('navbox-abovebelow')
			:addClass(args.aboveclass)
			:cssText(args.basestyle)
			:cssText(args.abovestyle)
			:attr('colspan', getAboveBelowColspan())
			-- id for aria-labelledby attribute, if no title
			:attr('id', (not args.title) and mw.uri.anchorEncode(args.above) or nil)
			:wikitext(processItem(args.above, arg.nowrapitems))
	return tbl
end
	
--[[
body
]]
--first group/list and images
local function body1(tbl)
	local row = tbl:tag('tr')
	if args.imageleft then
		row
			:tag('td')
				:addClass('noviewer')
				:addClass('navbox-image')
				:addClass(args.imageclass)
				:css('width', '1px')
				:css('padding', '0 2px 0 0')
				:cssText(args.imageleftstyle)
				:attr('rowspan', rowspan)
				:tag('div')
					:wikitext(processItem(args.imageleft))
	end
	local j = list[1].index
	if group[j] then
		local groupCell = row:tag('th')

		groupCell
			:attr('scope', 'row')
			:addClass('navbox-group')
			:addClass(args.groupclass)
			:cssText(args.basestyle)
			:css('width', args.groupwidth or '1%')

		groupCell
			:cssText(args.groupstyle)
			:cssText(groupstyle[j])
			:wikitext(group[j])
	end

	local listCell = row:tag('td')

	if group[j] then
		listCell
			:addClass('navbox-list-with-group')
	else
		listCell:attr('colspan', 2)
	end

	if not args.groupwidth then
		listCell:css('width', '100%')
	end

	local rowstyle
	if odd == 'odd' then
		rowstyle = args.oddstyle
	else
		rowstyle = args.evenstyle
	end

	listCell
		:css('padding', '0')
		:cssText(args.liststyle)
		:cssText(rowstyle)
		:cssText(liststyle[j])
		:addClass('navbox-list')
		:addClass('navbox-' .. (args.evenodd == 'swap' and even or args.evenodd or odd))
		:addClass(args.listclass)
		:addClass(listclass[j])
		:tag('div')
			:css('padding', (args.list1padding or args.listpadding or '0 0.25em'))
			:wikitext(processItem(list[1].content, args.nowrapitems))
	if args.image then
		row
			:tag('td')
				:addClass('noviewer')
				:addClass('navbox-image')
				:addClass(args.imageclass)
				:css('width', '1px')
				:css('padding', '0 0 0 2px')
				:cssText(args.imagestyle)
				:attr('rowspan', rowspan)
				:tag('div')
					:wikitext(processItem(args.image))
	end
	return tbl
end

--remaining groups/lists
local function body2(tbl)
	for i = 2, #list do
		odd, even = even, odd
		local j = list[i].index
		local row = tbl:tag('tr')
		if group[j] then
			local groupCell = row:tag('th')
			groupCell
				:attr('scope', 'row')
				:addClass('navbox-group')
				:addClass(args.groupclass)
				:cssText(args.basestyle)
				:css('width', args.groupwidth or '1%')

			groupCell
				:cssText(args.groupstyle)
				:cssText(groupstyle[j])
				:wikitext(group[j])
		end

		local listCell = row:tag('td')

		if group[j] then
			listCell:addClass('navbox-list-with-group')
		else
			listCell:attr('colspan', 2)
		end

		if not args.groupwidth then
			listCell:css('width', '100%')
		end

		local rowstyle
		if odd == 'odd' then
			rowstyle = args.oddstyle
		else
			rowstyle = args.evenstyle
		end
		listCell
			:css('padding', '0')
			:cssText(args.liststyle)
			:cssText(rowstyle)
			:cssText(liststyle[j])
			:addClass('navbox-list')
			:addClass('navbox-' .. (args.evenodd == 'swap' and even or args.evenodd or odd))
			:addClass(args.listclass)
			:addClass(listclass[j])
			:tag('div')
				:css('padding', (args.listpadding or '0 0.25em'))
				:wikitext(processItem(list[i].content, args.nowrapitems))
	end
	return tbl
end

--[[
below
]]
local function below(tbl)
	if not args.below then return tbl end

	tbl:tag('tr')
		:tag('td')
			:addClass('navbox-abovebelow')
			:addClass(args.belowclass)
			:cssText(args.basestyle)
			:cssText(args.belowstyle)
			:attr('colspan', getAboveBelowColspan())
			:wikitext(processItem(args.below, args.nowrapitems))
	return tbl
end

--[[
Template:Navbox
]]
function p.navbox(frame)
	defArgs(frame, {'Template:Navbox', 'Template:Navbox subgroup'})
	local res
	local firstTableTag
	res, firstTableTag = top()
	firstTableTag = title(firstTableTag)
	firstTableTag = above(firstTableTag)
	if list[1] then
		firstTableTag = body1(firstTableTag)
	end
	firstTableTag = body2(firstTableTag)
	firstTableTag = below(firstTableTag)
	if child then
		res:wikitext('<div>')
	end
	return tostring(res)
end

--[[
Template:Navbox subgroup
]]
function p.subgroup(frame)
	child = true
	return p.navbox(frame)
end

--[[
Template:Navbox with columns
]]
function p.with_columns(frame)
	defArgs(frame, 'Template:Navbox with columns')
	table.sort(col)
	local res
	local firstTableTag
	res, firstTableTag = top()
	
	firstTableTag = title(firstTableTag)
	firstTableTag = above(firstTableTag)
	
	if col[1] then
		local j = col[1].index
		local cols = mw.html.create('table')
			:addClass('navbox-columns-table')
			:css('border-spacing', '0px')
			:css('text-align', 'left')
			:cssText((colheader[j] or args.fullwidth) and 'width:100%' or 'width:auto; margin-left:auto; margin-right:auto')
			:cssText(args.coltablestyle)
		local row
		
		--Header row
		if colheader[j] then
			row = cols:tag('tr')
			for i = 1, #col do
				local j = col[i].index
				if colheader[j] then
					local td = row:tag('td')
						:addClass('navbox-abovebelow')
						:cssText((i > 1) and 'border-left:2px solid #fdfdfd' or nil)
						:css('font-weight', 'bold')
						:cssText(args.colheaderstyle)
						:cssText(colheaderstyle[j])
						:wikitext(colheader[j])
					if tonumber(colheadercolspan[j]) then
						td:attr('colspan', colheadercolspan[j])
					end
				end
			end
		end
		
		--Main columns
		row = cols:tag('tr'):css('vertical-align', 'top')
		if not (colheader[j] or colfooter[j] or args.fullwidth) then
			local paddingoff = args.padding and string.find(args.padding, '^0[ep]?[mx]?%?;?')
			if not paddingoff then
				row:tag('td')
					:css('width', args.padding or '5em')
					:wikitext('&nbsp;&nbsp;&nbsp;')
			end
		end
		for i = 1, #col do
			local j = col[i].index
			row:tag('td')
				:addClass('navbox-list')
				:cssText((i > 1) and 'border-left:2px solid #fdfdfd' or nil)
				:css('padding', '0px')
				:cssText(args.colstyle)
				:cssText(args.oddcolstyle)
				:cssText(colstyle[j])
				:css('width', colwidth[j] or args.colwidth or '10em')
				:tag('div')
					:newline()
					:wikitext(col[i].content)
					:newline()
			args.oddcolstyle, args.evencolstyle = args.evencolstyle, args.oddcolstyle
		end
		
		--Footer row
		if colfooter[j] then
			row = cols:tag('tr')
			for i = 1, #col do
				local j = col[i].index
				if colfooter[j] then
					local td = row:tag('td')
						:addClass('navbox-abovebelow')
						:cssText((i > 1) and 'border-left:2px solid #fdfdfd' or nil)
						:css('font-weight', 'bold')
						:cssText(args.colfooterstyle)
						:cssText(colfooterstyle[j])
						:wikitext(colfooter[j])
					if tonumber(colheadercolspan[j]) then
						td:attr('colspan', colheadercolspan[j])
					end
				end
			end
		end
		table.insert(list, {index=1, content=tostring(cols)})
		rowspan = rowspan + 1
	end
	
	args.list1padding = '0px'
	args.liststyle = 'background:transparent;color:inherit;'
	
	firstTableTag = body1(firstTableTag)
	firstTableTag = body2(firstTableTag)
	firstTableTag = below(firstTableTag)
	return tostring(res)
end

--[[
Template:Navbox with collapsible groups
]]
function p.with_collapsible_groups(frame)
	local res
	local firstTableTag
	defArgs(frame, 'Template:Navbox with collapsible groups')
	table.sort(content)
	res, firstTableTag = top()
	firstTableTag = title(firstTableTag)
	firstTableTag = above(firstTableTag)
	
	local i = 1
	local function funcList(rowTag)
		list[i] = list[i] or content[i]
		local j = list[i].index
		args.state = state[j] or args.selected and (args.selected == abbr[j] or args.selected == group[j]) and '' or 'mw-collapsed'
		args.name = nil
		args.titlestyle = (args.basestyle or '') .. ';' .. (args.groupstyle or '') .. ';' .. (args.secttitlestyle or '') .. ';' .. (groupstyle[j] or '')
		args.liststyle = (args.liststyle or '') .. ';' .. (args.contentstyle or '') .. ';' .. (liststyle[j] or '')
		args.title, group[j] = group[j], nil
		args.image = image[j]
		args.imageleft = imageleft[j]
		rowspan = 1
		local baseTag = rowTag:tag('td')
			:cssText(args.groupwidth and '' or 'width:100%;')
			:css('padding', '0')
			:cssText(args.liststyle)
			:cssText(odd == 'odd' and (args.oddstyle or '') or (args.evenstyle or ''))
			:cssText(liststyle[j])
			:addClass('navbox-list')
			:addClass('navbox-' .. (args.evenodd == 'swap' and even or args.evenodd or odd))
			:addClass(args.listclass)
			:tag('div')
		if args.title then
			local tableTag
			none = true
			baseTag, tableTag = top(baseTag)
			tableTag = title(tableTag)
			tableTag = body1(tableTag)
    		if child then
    		    baseTag:wikitext('<div>')
			end
		else
			baseTag:wikitext(list[i].content)
		end
	end
	
	--i = 1
	local row = firstTableTag:tag('tr')
	if args.imageleft then
		row:tag('td')
			:addClass('navbox-image')
			:addClass(args.imageclass)
			:css('width', '0')
			:css('padding', '0 2px 0 0')
			:cssText(args.imageleftstyle)
			:attr('rowspan', rowspan)
			:wikitext(args.imageleft)
	end
	funcList(row)
	if args.image then
		row:tag('td')
			:css('width', '0%')
			:css('padding', '0 0 0 2px')
			:cssText(args.imagestyle)
			:attr('rowspan', rowspan)
			:wikitext(args.image)
	end
	--i > 2
	for i = 2, #list do
		row = firstTableTag:tag('tr')
		list[1] = list[i]
		funcList(row)
	end
	
	firstTableTag = below(firstTableTag)
	if child then
		res:wikitext('<div>')
	end
	child, none = (child or border == 'subgroup' or border == 'child'), (border == 'none') --再定義
	return tostring(res)
end

--[[
Template:NavboxYears
Template:NavboxYears2
]]
local function calc_years(args, fmtLink)
	local numtab = tonumber(args.tab) or 0
	local numstart = tonumber(args.start)
	local numend = tonumber(args['end'])
	local numstep = tonumber(args.step) or 1
	if numstart and numend then
		if numtab > 0 then
			for i = 2, numtab + 1 do
				args[i] = nil
			end
		end
		local numD = numend - numstart + 1
		for i = 1, numD, numstep do
			args[i + numtab + 1] = numstart + i - 1
		end
	end
	local res = mw.html.create('table')
	res
		:css('width', '100%')
		:css('border-spacing', 0)
		:css('text-align', 'center')
	local h = 1
	repeat
		h = h + 1
		local row = res:tag('tr')
		for i = 2, 11 do
			local tdTag = row:tag('td')
				:css('width', '10%')
			if (tonumber(args[i]) or -1) > 0 then
				tdTag:wikitext('[[' .. fmtLink(args[1], args[i]) .. '|' .. args[i] .. ']]')
			else
				tdTag:wikitext(args[i])
			end
			args[i], args[i + 10] = args[i + 10], args[i + h * 10]
		end
	until not args[2]
	return tostring(res)
end

local function years(frame, fmtLink, wrappers)
	defArgs(frame, wrappers)
	if args.var then fmtLink = function(str, num) return str:gsub(args.var, num) end end
	if args.name then
		args.style = 'width:' .. (args.width or '38em') .. ';' .. (args.style or '')
		local res
		local firstTableTag
		res, firstTableTag = top()
		if args.title then 
			firstTableTag = title(firstTableTag)
		end
		if args.above then
			firstTableTag = above(firstTableTag)
		end
		if not list[1] and args[1] then list[1] = {index = 1, content = calc_years(args, fmtLink)} end
		if list[1] then
			firstTableTag = body1(firstTableTag)
		end
		firstTableTag = body2(firstTableTag)
		if args.below then
			firstTableTag = below(firstTableTag)
		end
		return tostring(res)
	else
		return calc_years(args, fmtLink)
	end
end

function p.years(frame)
	local fmtLink = function(str, num) return str .. num end
	return years(frame, fmtLink, 'Template:NavboxYears')
end

function p.years2(frame)
	local fmtLink = function(str, num) return num .. str end
	return years(frame, fmtLink, 'Template:NavboxYears2')
end

return p