モジュール:Navbox/former

    提供:Wikiminati

    テンプレート:使用箇所の多いテンプレート

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


    local p = {}
    
    --[[
    Template:Tnavbar
    ]]
    function p.tnavbar(frame)
    	local r = mw.html.create()													--出力用
    	local args = frame.args
    	if not args[1] then return ' ' end
    	
    	local function tf(x)
    		return x == '1' and true or false
    	end
    	args.plain = tf(args.plain)
    	args.div = tf(args.div)
    	args.nodiv = tf(args.nodiv)
    	args.mini = tf(args.mini)
    	args.viewplain = tf(args.viewplain)
    	args.fontstyle = args.fontcolor ~= '' and ((args.fontstyle or '') .. ';color:' .. args.fontcolor .. ';') or args.fontstyle or ''
    	
    	local divTag = r:tag('div')
    		:addClass('noprint')
    		:addClass('plainlinks')
    		:addClass('navbar')
    		:addClass('hlist')
    		:css('white-space', 'nowrap')
    		:css('font-size', '60%')
    		:css('font-weight', 'normal')
    	
    	if args.nodiv then
    		divTag:css('display', 'inline')
    			:css('padding', '0 0.5em')
    	else
    		divTag:css('background-color', 'transparent')
    			:css('padding', '0')
    			:css('color', '#000')
    	end
    	divTag:cssText(args.fontstyle)
    		:cssText(args.style)
    	
    	if not (args.plain or args.mini or args.viewplain) then
    		divTag:tag('span')
    			:css('font-size', '125%')
    			:node('このテンプレートを: ')
    	end
    	
    	local disp = args.mini and {'表', '話', '編', '歴'} or {'表示', 'ノート', '編集', '履歴'}
    	local ns = {'Template:', 'Template‐ノート:', 'Template:', 'Template:'}
    	local query = {nil, nil, 'action=edit', 'action=history'}
    	local title = {'このテンプレートを表示します', 'このテンプレートのノートを表示します', 'このテンプレートを編集します。保存の前にプレビューを忘れずに。', 'このテンプレートの過去の版を表示します'}
    	local color = {'', 'color:#002bb8;', 'color:#002bb8;', 'color:#002bb8;'}
    	local i = 0
    	local i_end = args.viewplain and 1 or 4
    	local ulTag = divTag:tag('ul')
    		:css('display', 'inline')
    	for i = 1, i_end do
    		local liTag = ulTag:tag('li')
    		local l = {open = '', link = '', close = ''}
    		if query[i] then
    			l.open = '['
    			l.link = tostring(mw.uri.canonicalUrl(ns[i] .. args[1], query[i])) .. ' '
    			l.close = ']'
    		else
    			l.open = '[['
    			l.link = ns[i] .. args[1] .. '|'
    			l.close = ']]'
    		end
    		liTag:wikitext(l.open .. l.link)
    			:tag('span')
    				:attr('title', title[i])
    				:css('font-size', '125%')
    				:cssText(color[i])
    				:cssText(args.fontstyle)
    				:node(disp[i])
    				:done()
    			:wikitext(l.close)
    	end
    	
    	return tostring(r)
    end
    
    
    --[[
    Define Arguments
    ]]
    local getArgs
    local args = {}
    local border
    local child, none = false, false
    local rowspan = 0
    local basestyle = ''
    local odd, even = 'odd', 'even'
    
    local list, liststyle = {}, {}
    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)
    	if not getArgs then
    		getArgs = require('Module:Arguments').getArgs
    	end
    	args = getArgs(frame, {parentOnly = true})
    	border = args.border or args[1]
    	child, none = (border == 'subgroup' or border == 'child'), (border == 'none')
    	collapsible = (args.state == 'plain' or args.state == 'off') and '' or 'mw-collapsible '
    	
    	if args.basestyle then basestyle = args.basestyle .. ';' end
    	
    	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, '\n' .. v) end,
    		liststyle = function(num, v) liststyle[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, '\n' .. 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, '\n' .. 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
    
    --[[
    top
    ]]
    local function top(baseTag)
    	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
    		nav = baseTag:tag('div')
    			:addClass('navbox')
    			:addClass(args.navboxclass)
    			:css('border-collapse', 'collapse')
    			: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
    		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
    
    	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('background', 'transparent')
    			:css('color', 'inherit')
    	end
    	bodyTable:css('min-width', '100%')
    		:css('border-spacing', '0px')
    		:css('border-collapse', 'separate')
    		: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')
    	
    	if args.titlegroup then
    		titleRow
    			:tag('th')
    				:attr('scope', 'row')
    				:addClass('navbox-group')
    				:addClass(args.titlegroupclass)
    				:cssText(args.basestyle)
    				:cssText(args.groupstyle)
    				:cssText(args.titlegroupstyle)
    				:wikitext(args.titlegroup)
    	end
    
    	local titleCell = titleRow:tag('th'):attr('scope', 'col')
    
    	if args.titlegroup then
    		titleCell
    			:css('width', '100%')
    	end
    	
    	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)
    	
    	if (args.navbar == 'plain') or (not args.name and (child or none)) then
    		titleCell
    			:tag('div')
    				:css('float', 'left')
    				:css('width', '6em')
    				:node('&nbsp;')
    	elseif args.navbar ~= 'off' then
    		local tbl = {args = {args.name, mini = '1', fontstyle = basestyle .. (args.titlestyle or '') .. ';border:none;', fontcolor = ''}}
    		titleCell
    			:tag('div')
    				:css('float', 'left')
    				:css('width', '6em')
    				:css('text-align', 'left')
    				:node(p.tnavbar(tbl))
    	end
    	
    	if child or border == 'none' then
    		titleCell
    			:tag('div')
    				:attr('id', mw.uri.anchorEncode(args.title))
    				:addClass(args.titleclass)
    				:css('font-size', '100%')
    				:css('margin', '0 6em')
    				:node(args.title)
    	else
    		titleCell
    			:tag('div')
    				:attr('id', mw.uri.anchorEncode(args.title))
    				:addClass(args.titleclass)
    				:css('font-size', '110%')
    				:css('margin', '0 6em')
    				:node(args.title)
    	end
    
    	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())
    			:newline()
    			:node(args.above)
    	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('navbox-image')
    				:addClass(args.imageclass)
    				:css('width', '1px')
    				:css('padding', '0px 2px 0px 0px')
    				:cssText(args.imageleftstyle)
    				:attr('rowspan', rowspan)
    				:tag('div')
    					:node(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
    			:css('text-align', 'left')
    			:css('border-left-width', '2px')
    			:css('border-left-style', 'solid')
    	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', '0px')
    		: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)
    		:tag('div')
    			:css('padding', (args.list1padding or args.listpadding or '0em 0.25em'))
    			:node(list[1].content)
    			:newline()
    	if args.image then
    		row
    			:tag('td')
    				:addClass('navbox-image')
    				:addClass(args.imageclass)
    				:css('width', '1px')
    				:css('padding', '0px 0px 0px 2px')
    				:cssText(args.imagestyle)
    				:attr('rowspan', rowspan)
    				:tag('div')
    					:node(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])
    				:node(group[j])
    		end
    
    		local listCell = row:tag('td')
    
    		if group[j] then
    			listCell
    				:css('text-align', 'left')
    				:css('border-left-width', '2px')
    				:css('border-left-style', 'solid')
    		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', '0px')
    			: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)
    			:tag('div')
    				:css('padding', (args.listpadding or '0em 0.25em'))
    				:node(list[i].content)
    				:newline()
    	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())
    			:newline()
    			:node(args.below)
    	return tbl
    end
    
    --[[
    Template:Navbox
    ]]
    function p.navbox(frame)
    	defArgs(frame)
    	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)
    	defArgs(frame)
    	if not border then child = true end
    	args.groupstyle = 'padding:' .. (args.grouppadding or '0 0.75em') .. ';' .. (args.groupstyle or '')
    	
    	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 not border then res:wikitext('<div>') end
    	return tostring(res)
    end
    
    --[[
    Template:Navbox with columns
    ]]
    function p.with_columns(frame)
    	defArgs(frame)
    	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('border-collapse', 'separate')
    			:css('text-align', 'left')
    			:cssText((colheader[j] or args.fullwidth) and 'width:100%;' or 'margin:0 auto;')
    			:cssText(args.coltablestyle)
    		--Header row
    		if colheader[j] then
    			local headerRow = cols:tag('tr')
    				:addClass('navbox-abovebelow')
    				:css('font-weight', 'bold')
    				:cssText(args.colheaderstyle)
    			for i = 1, #col do
    				local j = col[i].index
    				if colheader[j] then
    					headerRow:tag('td')
    						:attr('colspan', colheadercolspan[j] or '1')
    						:cssText(colheaderstyle[j])
    						:node(colheader[j])
    				end
    			end
    		end
    		--Main columns
    		local row = cols:tag('tr')
    			:css('vertical-align', 'top')
    			:cssText(args.colstyle)
    		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')
    				:css('padding', '0')
    				:cssText(args.oddcolstyle)
    				:cssText(colstyle[j])
    				:css('width', colwidth[j] or args.colwidth or '10em')
    				:node(col[i].content)
    			args.oddcolstyle, args.evencolstyle = args.evencolstyle, args.oddcolstyle
    		end
    		--Footer row
    		if colfooter[j] then
    			row = cols:tag('tr')
    				:addClass('navbox-abovebelow')
    				:css('font-weight', 'bold')
    				:cssText(args.colfooterstyle)
    			for i = 1, #col do
    				local j = col[i].index
    				if colfooter[j] then
    					row:tag('td')
    						:attr('colspan', colfootercolspan[j] or '1')
    						:cssText(colfooterstyle[j])
    						:node(colfooter[j])
    				end
    			end
    		end
    		cols = mw.html.create():wikitext('</div>'):wikitext(tostring(cols)):wikitext('<div>')
    		table.insert(list, {index=1, content=cols})
    		rowspan = rowspan + 1
    	end
    	
    	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)
    	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 = basestyle .. (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', '0px')
    			: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:node(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)
    			:node(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)
    			:node(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 = (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', '0px')
    		:css('border-collapse', 'separate')
    		: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)
    	defArgs(frame)
    	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)
    end
    
    function p.years2(frame)
    	local fmtLink = function(str, num) return num .. str end
    	return years(frame, fmtLink)
    end
    
    return p