From Wikipedia, the free encyclopedia

require('strict')

local p = {}



local function items(args, year, oldrange)

	local itemList = {}

	

	-- First loop through is to find the lowest year range, if any. If oldrange is supplied, the year range must also be greater than it.

	local range = 0;

	if argsyear .. '_to' or argsyear .. 'a_to' then

		local newrange = tonumber(argsyear .. '_to' or argsyear .. 'a_to'])

		if newrange and (oldrange == nil or newrange > oldrange) then

			range = newrange;

		end

	end

	for asciiletter = 98, 106 do -- 98 > b, 106 > j

		if argsyear .. string.char(asciiletter) .. '_to' then

			local newrange = tonumber(argsyear .. string.char(asciiletter) .. '_to'])

			if newrange and (oldrange == nil or newrange > oldrange) and (range == 0 or newrange < range) then

				range = newrange;

			end			

		end

	end



	-- Find items, filtered by range if available.

	if argsyear or argsyear .. 'a' then

		local thisrange = tonumber(argsyear .. '_to' or argsyear .. 'a_to'])

		if (range == 0 and thisrange == nil) or (thisrange and thisrange == range) then

			table.insert(itemList, argsyear or argsyear .. 'a'])

		end

	end

	for asciiletter = 98, 106 do -- 98 > b, 106 > j

		if argsyear .. string.char(asciiletter)] then

			local thisrange = tonumber(argsyear .. string.char(asciiletter) .. '_to'])

			if (range == 0 and thisrange == nil) or (thisrange and thisrange == range) then

				table.insert(itemList, argsyear .. string.char(asciiletter)])

			end

		end

	end

	return table.maxn(itemList), itemList, range

end



local function color(args, year, itemNum, to_range)



	if argsyear .. '_color' then

		return argsyear .. '_color' 

	end

	

	if to_range and argsyear .. '_to_' .. to_range .. '_color' then

		return argsyear .. '_to_' .. to_range .. '_color'

	end



	for yearrange = 1, 10 do

		if args'range' .. yearrange and args'range' .. yearrange .. '_color' then

			local _, _, beginyear, endyear = string.find( args'range' .. yearrange], '^(%d%d%d%d)%D+(%d%d%d%d)$' )



			local year = tonumber(year) or 9999 -- For year == 'TBA'

			beginyear = tonumber(beginyear) or 0

			endyear =  tonumber(endyear) or 9999



			if year >= beginyear and year <= endyear then

				local _, _, color1, color2 = string.find( args'range' .. yearrange .. '_color'], '^(%S*)%s*(%S*)$' )

				color2 = string.find(color2, '^#?%w+$') and color2 or color1

				return itemNum > 0 and color1 or color2

			end

		end

	end



	return itemNum > 0 and '#0BDA51' or '#228B22'

end



local function left(builder, args, year, itemNum, range)

	builder = builder:tag('th')

		:attr('scope', 'row')

		:css('border-right', '1.4em solid ' .. color(args, year, itemNum, range))

	if itemNum > 1 then

		builder = builder:attr('rowspan', itemNum)

	end

	if year == 'TBA' then

		builder:tag('abbr'):attr('title', 'To be announced'):wikitext('TBA')

	else

		builder:wikitext(range ~= 0 and year .. '–' .. range or year)

	end

end



local function right(builder, itemNum, itemList)

	if itemNum == 0 then return end



	if itemNum == 1 then

		builder:tag('td')

			:wikitext(itemList1])

		return

	end



	-- if itemNum >= 2

	builder:tag('td')

		:addClass('rt-first')

		:wikitext(itemList1])



	for key = 2, itemNum - 1 do

		builder = builder:tag('tr')

			:tag('td')

			:addClass('rt-next')

			:wikitext(itemListkey])

	end



	builder = builder:tag('tr')

		:tag('td')

		:addClass('rt-last')

		:wikitext(itemListitemNum])



end



local function row(builder, args, year, emptyyear, lastyear, highrange)

	local oldrange = nil

	

	repeat

		local itemNum, itemList, range = items(args, year, oldrange)

		

		-- Now check for a new high range and catch it. We need to know what highrange was prior to update though.

		local oldhighrange = nil

		if(range > 0 and (highrange == nil or range > highrange)) then

			oldhighrange = (highrange or range)

			highrange = range

		end

		oldhighrange = (oldhighrange or highrange)



		-- If compressempty is set, check for empty items, track empty years and high ranges, and

		-- put out a compressed range when next year is found.

		if args.compressempty and oldrange == nil then

			-- If we're compressing and there's no items, return this year for tracking.

			if #itemList < 1 then

				return year, highrange

			end



			-- If emptyyear is below or equal the highrange, we need to make adjustments.

			if(emptyyear and oldhighrange and emptyyear <= oldhighrange) then

				-- If the current year is highrange or highrange +1, suppress empty row output entirely.

				-- If the current year is highrange+2 or more, adjust the emptyyear to be above highrange)				

				if(year <= (oldhighrange+1)) then

					emptyyear = nil

				elseif(year > (oldhighrange+1)) then

					emptyyear = oldhighrange+1

				end

			end



			-- If we have items but are tracking an empty year, output compressed range row.

			if emptyyear ~= nil then

				builder = builder:tag('tr')

				if year == 'TBA' then

					left(builder, args, emptyyear, 0, lastyear)

				elseif year-1 == emptyyear then

					left(builder, args, emptyyear, 0, 0)

				else

					left(builder, args, emptyyear, 0, year-1)

				end

			end

		end

		

		-- We can break out if this is the case. This means we have looped through more than once, but there were no more items remaining.

		if range == 0 and oldrange and #itemList < 1 then

			break

		end



		builder = builder:tag('tr')

		left(builder, args, year, itemNum, range)

		right(builder, itemNum, itemList)



		if range ~= 0 then

			oldrange = range

		end

	until range == 0

	

	return nil, highrange

end



function p._main(args)

	-- Main module code goes here.

	local currentyear = os.date('%Y')



	local ret

	local firstyear, lastyear

	local TBA = items(args, 'TBA') > 0



	ret = mw.html.create( 'table' )

		:addClass('release-timeline wikitable')

		:addClass(args.align == 'left' and 'rt-left' or nil)



	ret:tag('caption')

		:wikitext((args.title or 'Release timeline') ..

			(args.subtitle and ('<div class="rt-subtitle">'..args.subtitle..'</div>') or ''))



	if tonumber(args.first) then

		firstyear = tonumber(args.first)

	else

		for i = 1, currentyear do

			if items(args, i) > 0 then

				firstyear = i

				break

			end

		end

		firstyear = firstyear or (currentyear + 3)

	end



	if tonumber(args.last) then

		lastyear = tonumber(args.last)

	else

		for i = currentyear + 3, TBA and currentyear or firstyear, -1 do

			if items(args, i) > 0 then

				lastyear = i

				break

			end

		end

		lastyear = lastyear or (currentyear - 1)

	end



	local emptyyear = nil

	local highrange = nil

	for year = firstyear, lastyear do

		local yearcheck, newhighrange = row(ret, args, year, emptyyear, lastyear, highrange)

		if (emptyyear == nil and yearcheck ~= nil) or (emptyyear ~= nil and yearcheck == nil) then

			emptyyear = yearcheck

		end

		highrange = newhighrange		

	end



	if TBA then

		row(ret, args, 'TBA')

	end



	return mw.getCurrentFrame():extensionTag{

		name = 'templatestyles', args = { src = 'Module:Timeline of release years/styles.css'}

	} .. tostring(ret)

end



function p.main(frame)

	local args = require('Module:Arguments').getArgs(frame)

	return p._main(args)

end



return p