Jump to content

Module:Category series navigation

Permanently protected module
From Wikipedia, the free encyclopedia
This is an old revision of this page, as edited by Tom.Reding (talk | contribs) at 21:40, 11 April 2019 (Move everything to Lua & combine all separate modules). The present address (URL) is a permanent link to this revision, which may differ significantly from the current revision.
(diff) ← Previous revision | Latest revision (diff) | Newer revision → (diff)

local p = {}

--[[==========================================================================]]
--[[                            Utility functions                             ]]
--[[==========================================================================]]

--Standardized error handling
function errorclass(msg)
	return mw.text.tag( 'span', {class='error mw-ext-cite-error'}, '<b>Error!</b> '..msg )
end

--Make a piped link to a category, if it exists
--If it doesn't exist, just display the greyed the link title without linking
function makeCatLink(catname, disp)
	local displaytext = nil
	local greyLinkColor = '#888'
	if (disp ~= '') and (disp ~= nil) then
		--use 'disp' parameter, but strip any trailing disambiguator
		displaytext = mw.ustring.gsub(disp, '%s+%(.+$', '');
	else
		displaytext = catname
	end
	local fmtlink
	local catPage = mw.title.new( catname, 'Category' )
	if (catPage.exists) then
		fmtlink = '[[:Category:'..catname..'|'..displaytext..']]'
	else
		fmtlink = '<span style="color:'..greyLinkColor..'">'..displaytext..'span>'
	end

	return fmtlink
end

--[[==========================================================================]]
--[[                   Formerly separated templates/modules                   ]]
--[[==========================================================================]]

--[[============================={{  navyear  }}==============================]]

function navyear(arg1, arg2, arg3, arg4, arg5, frame)
	--Expects a PAGENAME of the form "Some sequential 1760 example cat", where 
	--	{{{1}}}=Some sequential
	--	{{{2}}}=1760
	--	{{{3}}}=example cat
	--	{{{4}}}=1758 ('min' year parameter; optional)
	--	{{{5}}}=1800 ('max' year parameter; optional)
	arg2 = tonumber(arg2)
	arg4 = tonumber(arg4)
	arg5 = tonumber(arg5)
	if arg4 == nil then arg4 = -9999 end
	if arg5 == nil then arg5 = 9999 end
	
	local navyear = '{| class="toccolours hlist" style="text-align: center; margin: auto;"\n'..'|\n'
	
	local i = -5
	while i <= 5 do
		local year = arg2 + i
		if i ~= 0 then
			if (year >= arg4) and (year <= arg5) then -- ex: 1758, 1759, 1761, 1762, 1763, 1764, 1765
				navyear = navyear..'*'..makeCatLink( arg1..' '..year..' '..arg3, year )..'\n'
			else -- ex: 1755, 1756, 1757
				navyear = navyear..'*<span style="visibility:hidden">'..year..'</span>\n'
			end
		else -- ex: 1760
			navyear = navyear..'*<b>'..arg2..'</b>\n'
		end
		i = i + 1
	end
	return navyear..'|}'
end

--[[============================{{  navdecade  }}=============================]]

function navdecade(arg1, arg2, arg3, arg4, frame)
	--Expects a PAGENAME of the form "Some sequential 2015 example cat", where 
	--	{{{1}}}=Some sequential
	--	{{{2}}}=2015
	--	{{{3}}}=example cat
	--and
	--	{{{4}}}=2010
	--the penultimate decade to be shown, normally the current 4-digit decade.
	local narg2 = tonumber(arg2)
	local narg4 = tonumber(arg4)
	local errors = '' --TODO: use local regex for these checks instead of template-expands
	if string.len(arg2) ~= 4 then --expecting e.g. yyyy
		errors = errorclass('Decade module at Navseasoncats/navdecade has been sent "'..arg2..'" but is expecting a 4-digit year ending in zero, of the form yyy0 - there should be 4 digits only. '..
							'So e.g. the 2010s should be cut down to 2010.')
	elseif string.len(arg4) ~= 4 then --expecting e.g. yyyy
		errors = errorclass('Decade module at Navseasoncats/navdecade can\'t recognise a number in the "year" '..arg4..' that has been passed to it as the penultimate decade to be shown. '..
							'It expects to be sent e.g. 2010.')
	else
		local strnumber = frame:expandTemplate{ title = 'Str number/trim', args = { arg2 } }
		if string.len(strnumber) < string.len(arg2) then --if 4-digit but non-numeric, e.g. 201t
			errors = errorclass('Decade module at Navseasoncats/navdecade can\'t recognise a number in the "year" '..arg2..' that has been passed to it. '..
								'It expects to be sent e.g. 2010.')
			if narg2 == nil then narg2 = tonumber(strnumber) end
		else
			local strrightc = frame:expandTemplate{ title = 'Str rightc', args = { arg4, 1 } }
			if strrightc ~= '0' then --expecting 2010
				errors = errorclass('Decade module at Navseasoncats/navdecade has been sent "'..arg4..'" but is expecting a 4-digit year ending in zero, of the form yyy0 - there should be no trailing s. '..
									'So e.g. the 1990s should be cut down to 1990.')
			end
			if narg4 == nil then narg4 = tonumber( frame:expandTemplate{ title = 'Str number/trim', args = { arg4 } } ) end
		end
	end
	if errors ~= '' then errors = errors..'\n' end
	
	local nav = '{| class="toccolours" style="text-align: center; margin: auto;"\n'
	
	local i = 0
	while i <= 20 do
		nav = nav..'|'
		if narg2 > (narg4 - (1+i)) then
			nav = nav..frame:expandTemplate{ title = 'LinkCatIfExists2', args = { arg1..' '..(narg2 - (70-i))..'s '..arg3, (narg2 - (70-i))..'s' } }..' &bull;'
		end
		nav = nav..'\n'
		i = i + 10
	end
	
	local j = 0
	while j <= 30 do
		nav = nav..'|'..frame:expandTemplate{ title = 'LinkCatIfExists2', args = { arg1..' '..(narg2 - (40-j))..'s '..arg3, (narg2 - (40-j))..'s' } }..' &bull;\n'
		j = j + 10
	end
	
	nav = nav..'|<b>'..arg2..'s</b>\n'..
		  '\n'..
		  '| &bull; '..frame:expandTemplate{ title = 'LinkCatIfExists2', args = { arg1..' '..(narg2 + 10)..'s '..arg3, (narg2 + 10)..'s' } }..'\n'
		  
	local k = 0
	while k <= 20 do
		nav = nav..'|'
		if narg2 < (narg4 - (1+k)) then
			nav = nav..'&bull; '..frame:expandTemplate{ title = 'LinkCatIfExists2', args = { arg1..' '..(narg2 + (20+k))..'s '..arg3, (narg2 + (20+k))..'s' } }
		end
		nav = nav..'\n'
		k = k + 10
	end
	
	return errors..nav..'|}'
end

--[[============================{{  navhyphen  }}=============================]]

function navhyphen(arg1, arg2, arg3, arg4, arg5, frame)
	--Expects a PAGENAME of the form "Some sequential 2015–16 example cat", where 
	--	{{{1}}}=2015
	--	{{{2}}}=–
	--	{{{3}}}=16
	--	{{{4}}}=Some sequential
	--	{{{5}}}=example cat
	-- For "1999-2000", "2000" must be truncated so {{{3}}} is "00".
	local narg1 = tonumber(arg1)
	local narg3 = tonumber(arg3)
	
	local errors = '' --TODO: use local regex for these checks instead of template-expands
	if string.len(arg3) > 2 then --expecting 16
		errors = errorclass('Second part of season passed to Navseasoncats/navhyphen should only be two digits, not '..arg3..'. '..
							'Also, e.g. 1999-2000 should be cut down to 1999-00.')
	else
		local strnumber = frame:expandTemplate{ title = 'Str number/trim', args = { arg1 } }
		if string.len(strnumber) < string.len(arg1) then --if 4-digit but non-numeric, e.g. 201t
			errors = errorclass('Navseasoncats/navhyphen can\'t recognise the number '..arg1..' in the first part of the "season" that has been passed to it. '..
								'For e.g. 2015–16, 16 is expected via |2015|–|16|.')
			if narg1 == nil then narg1 = tonumber(strnumber) end
		else
			local strnumber = frame:expandTemplate{ title = 'Str number/trim', args = { arg3 } }
			if string.len(strnumber) < string.len(arg3) then --if 2-digit but non-numeric, e.g. 1O
				errors = errorclass('Navseasoncats/navhyphen can\'t recognise the number '..arg3..' in the second part of the "season" that has been passed to it. '..
									'For e.g. 2015–16, 16 is expected via |2015|–|16|.')
			end
		end
	end
	if narg1 == nil then narg1 = tonumber( frame:expandTemplate{ title = 'Str number/trim', args = { arg1 } } ) end
	if narg3 == nil then narg3 = tonumber( frame:expandTemplate{ title = 'Str number/trim', args = { arg3 } } ) end
	if errors ~= '' then errors = errors..'\n' end
	
	local nav = '{| class="toccolours" style="text-align: center; margin: auto;"\n'
	
	local i = 0
	while i <= 2 do
		local zero1 = ''
		local cent1 = ''
		if narg3 > (3-i) and narg3 < (13-i) then zero1 = '0' end
		if narg3 > (3-i) then cent1 = tostring(narg3 - (3-i))
		elseif narg3 == (3-i) then cent1 = mw.ustring.match(arg1, '^%s*(%d%d)')..'00'
		else cent1 = tostring(narg3 + (97+i))
		end
		
		local zero2 = ''
		local cent2 = ''
		if narg3 > (2-i) and narg3 < (13-i) then zero2 = '0' end
		if narg3 > (2-i) then cent2 = tostring(narg3 - (3-i))
		else cent2 = tostring(narg3 + (97+i))
		end
		
		nav = nav..'|'..
				frame:expandTemplate{
					title = 'LinkCatIfExists2',
					args = { 
						arg4..' '..(narg1 - (3-i))..arg2..zero1..cent1..' '..arg5,
						(narg1 - (3-i))..arg2..zero2..cent2
					}
				}..' &bull;'
		nav = nav..'\n\n'
		i = i + 1
	end
	
	nav = nav..'|<b>'..arg1..arg2..arg3..'</b> &bull; \n\n'
	
	local j = 0
	while j <= 2 do
		local zero1 = ''
		local cent1 = ''
		if narg3 < (9-j) or narg3 > (99-j) then zero1 = '0' end
		if narg3 < (99-j) then cent1 = tostring(narg3 + (1+j))
		elseif narg3 == (99-j) then
			cent1 = tostring(tonumber(mw.ustring.match(arg1, '^%s*(%d%d)')) + 1)..'00'
		else cent1 = tostring(narg3 - (99-j))
		end
		
		local zero2 = ''
		local cent2 = ''
		if narg3 < (9-j) or narg3 > (98-j) then zero2 = '0' end
		if narg3 < (99-j) then cent2 = tostring(narg3 + (1+j))
		else cent2 = tostring(narg3 - (99-j))
		end
		
		local bull = ''
		if j < 2 then bull = ' &bull;' end
		nav = nav..'|'..
				frame:expandTemplate{
					title = 'LinkCatIfExists2',
					args = { 
						arg4..' '..(narg1 + (1+j))..arg2..zero1..cent1..' '..arg5,
						(narg1 + (1+j))..arg2..zero2..cent2
					}
				}..bull
		nav = nav..'\n\n'
		j = j + 1
	end
	
	return errors..nav..'|}'
end

--[[============================{{  var_season  }}============================]]

function var_season(testcase, frame)
	--Extracts e.g. 2015–16 or 2015 out of a string
	local pagename, titleyear = nil
	if testcase and testcase ~= '' then
		pagename = testcase
		titleyear = frame:expandTemplate{ title = 'Title year', args = { page = pagename } }
	else
		pagename = mw.title.getCurrentTitle().text
		titleyear = frame:expandTemplate{ title = 'Title year', args = { pagename } }
	end

	local strleft4 = string.match(pagename, '^[%d%D]?[%d%D]?[%d%D]?[%d%D]?')
	if titleyear == strleft4 then
		local firstword = frame:expandTemplate{ title = 'First word', args = { pagename } }
		return firstword
	else
		local pos = mw.ustring.find( pagename, titleyear, 1, true ) or 0
		local posm1 = pos - 1
		local strright = frame:expandTemplate{ title = 'Str right', args = { pagename, posm1 } }
		local firstword = frame:expandTemplate{ title = 'First word', args = { strright } }
		return firstword
	end
end

--[[=========================={{  var_firsthalf  }}===========================]]

function var_firsthalf(arg, frame)
	--Extracts the part of the string before the year
	local pagename, titleyear = nil
	if arg then arg = mw.text.trim(arg) end
	if arg and arg ~= '' then
		pagename = arg
		titleyear = frame:expandTemplate{ title = 'Title year', args = { page = pagename } }
	else
		pagename = mw.title.getCurrentTitle().text
		titleyear = frame:expandTemplate{ title = 'Title year', args = { pagename } }
	end
	
	local strleft4 = string.match(pagename, '^[%d%D]?[%d%D]?[%d%D]?[%d%D]?')
	if strleft4 == titleyear then
		return ''
	else
		local pos = mw.ustring.find( pagename, titleyear, 1, true ) or 0
		local posm2 = pos - 2
		local out = frame:expandTemplate{ title = 'Str left', args = { pagename, posm2 } }
		return mw.text.trim(out)
	end
end

--[[==========================={{  var_lasthalf  }}===========================]]

function var_lasthalf(arg, frame)
	--Extracts the part of the string after the word with the year
	local pagename, titleyear = nil
	if arg then arg = mw.text.trim(arg) end
	if arg and arg ~= '' then
		pagename = arg
		titleyear = frame:expandTemplate{ title = 'Title year', args = { page = pagename } }
	else
		pagename = mw.title.getCurrentTitle().text
		titleyear = frame:expandTemplate{ title = 'Title year', args = { pagename } }
	end
	
	local pos = mw.ustring.find( pagename, titleyear, 1, true ) or 0
	local posm1 = pos - 1
	local strright = frame:expandTemplate{ title = 'Str right', args = { pagename, posm1 } }
	local removefirstword = frame:expandTemplate{ title = 'Remove first word', args = { strright } }
	return removefirstword
end

--[[==========================================================================]]
--[[                                   Main                                   ]]
--[[==========================================================================]]

function p.navseasoncats(frame)
	local testcase = frame.args['testcase'] or ''
	local minyear = frame.args['min']
	local maxyear = frame.args['max']
	local varseason    = var_season(testcase, frame)
	local varfirsthalf = var_firsthalf(testcase, frame)
	local varlasthalf  = var_lasthalf(testcase, frame)
	local hyphen = mw.ustring.match(varseason, '[–-]') --ascii 150 & 45 (ndash & keyboard hyphen)
	local strleft = frame:expandTemplate{ title = 'Str left',   args = { varseason, 4 } }
	
	if string.len(varseason) > 5 and string.len(varseason) < 10 or hyphen then
		local strmid    = frame:expandTemplate{ title = 'Str mid',    args = { varseason, 5, 1 } }
		local strrightc = frame:expandTemplate{ title = 'Str rightc', args = { varseason, 2 } }
		return navhyphen( strleft, strmid, strrightc, varfirsthalf, varlasthalf, frame )
	elseif string.len(varseason) == 4 then
		return navyear( varfirsthalf, strleft, varlasthalf, minyear, maxyear, frame )
	else
		local strmid = frame:expandTemplate{ title = 'Str mid', args = { varseason, 4, 2 } }
		if string.len(varseason) == 5 and strmid == '0s' then
			local year = mw.getContentLanguage():formatDate( 'Y' )
			local decade = mw.ustring.match(year, '^(%d%d%d)')..'0'
			return navdecade( varfirsthalf, strleft, varlasthalf, decade )
		else
			return '<nowiki>***Navseasoncats failed to generate navbox***</nowiki>[[Category:Navseasoncats failed to generate navbox]]'
		end
	end
end

return p