Module:Ranking movements

-- This module implements Template:Ranking movements local p = {}

local templatestyles = 'Module:Ranking movements/styles.css'

local colors = { ['+'] = '#D8FFEB', ['-'] = '#FFE6E6', ['not released'] = '#999999' } local labels = { ['title'] = 'Ranking movements', ['legend'] = 'Legend', ['week'] = 'Week', ['poll'] = 'Poll', ['pre'] = 'Pre', ['final'] = 'Final', ['not released'] = 'Not released', ['+'] = 'Increase in ranking', ['-'] = 'Decrease in ranking', ['—'] = 'Not ranked', ['RV'] = 'Received votes', ['т'] = 'Tied with team above or below', [''] = 'First-place votes' }

local legend = { ['+'] = false, ['-'] = false, ['—'] = false, ['RV'] = false, ['т'] = false, [''] = false }

local function format_cell_text(s) if s then if s:match('^[Nn][Rr]') or s:match('^—') then legend['—'] = true end if s:match('^[Rr][Vv]') then legend['RV'] = true end if s:match('%d[%-%s]*[Tt]') or s:match('[Tт]') then legend['т'] = true end if s:match('[%(%)]') then legend[''] = true end s = mw.ustring.gsub(s, '^NR', '—') end return s end

local function get_rank(s) -- This is intended to remove any extra stuff after the ranking local result = mw.ustring.match(s or , '^%d*') or  -- Is it numbers? if result == '' then result = mw.ustring.match(s or , '^[%a/—]*') or  -- Is it letters? end return result end

local function get_color(lastweek, thisweek) -- No coloring if first week or this week is blank if (lastweek == 'first week') or (thisweek == ) or (lastweek == ) or (lastweek == 'N/A') or (thisweek == 'N/A') then return nil end -- No coloring if the rank has not changes if (lastweek == thisweek) then return nil end -- If last week was NR then rank has increased if (lastweek == 'NR' or lastweek == '—') then legend['+'] = true return colors['+'] end -- If last week was RV	if (lastweek == 'RV') then -- If this week is NR then rank has decreased, otherwise increased if (thisweek == 'NR' or thisweek == '—') then legend['-'] = true return colors['-'] else legend['+'] = true return colors['+'] end end -- In all other cases, just compare the numbers lastweek = tonumber(lastweek) or 999999 thisweek = tonumber(thisweek) or 999999 if (lastweek > thisweek) then legend['+'] = true return colors['+'] end if (thisweek > lastweek) then legend['-'] = true return colors['-'] end return nil end

local tracking, preview = {}, {}

local function checkargs(args) for k, v in pairs(args) do   	if v ~= '' then if k and type(k) == 'string' then if k:match('^poll[1-6]firstweek$') or k:match('^poll[1-6]lastweek$') or k:match('^poll[1-6]title$') or k:match('^poll[1-6]_final$') or k == 'title' or k == 'nocat' or k:match('^wk1?%d$') or k:match('^wk2[01]') then -- valid elseif k:match('^poll[1-6]_1?%d$') or k:match('^poll[1-6]_2[01]$') then -- valid local i = mw.ustring.gsub(k, '^poll([1-6])_%d+$', '%1') local j = mw.ustring.gsub(k, '^poll[1-6]_(%d+)$', '%1') local maxweeks = tonumber(args['poll' .. i .. 'lastweek']) or 20 if tonumber(j) > maxweeks then table.insert(tracking, '') end else -- invalid local vlen = mw.ustring.len(k) k = mw.ustring.sub(k, 1, (vlen < 25) and vlen or 25) k = mw.ustring.gsub(k, '[^%w\-_ ]', '?') table.insert(tracking, '') table.insert(preview, '"' .. k .. '"') end end end end end

function p.main(frame) local args = require('Module:Arguments').getArgs(frame) local maxpolls = 6 -- Compute the maximum number of columns local minweeks = 20 local maxweeks = 0 for k = 1,maxpolls do local n = tonumber(args['poll' .. k .. 'lastweek']) or (args['poll' .. k .. 'title'] and 20 or 0) maxweeks = (n > maxweeks) and n or maxweeks local n = tonumber(args['poll' .. k .. 'firstweek']) or (args['poll' .. k .. 'title'] and 0 or 20) minweeks = (n < minweeks) and n or minweeks end

-- Start table local root = mw.html.create('table') :addClass('wikitable ranking-movements')

-- Table caption title local caption = root:tag('caption'):wikitext(args['title'] or labels['title'])

-- Week header row local row = root:tag('tr') row:tag('th') -- Blank space in corner row:tag('th'):attr('colspan', maxweeks - minweeks + 1):wikitext(labels['week'])

-- Poll header row row = root:tag('tr') row:tag('th') :wikitext(labels['poll']) for k = minweeks,maxweeks do local text = args['wk' .. k] or k		if (k == 0) then text = args['wk' .. k] or labels['pre'] elseif (k == maxweeks) then text = args['wk' .. k] or labels['final'] end row:tag('th') :wikitext(text) end -- Poll data rows for i = 1,maxpolls do local ptitle = args['poll' .. i .. 'title'] or '' local pfirstweek = tonumber(args['poll' .. i .. 'firstweek']) or 0 local plastweek = tonumber(args['poll' .. i .. 'lastweek']) or 20 if ptitle ~= '' then row = root:tag('tr') row:tag('th') :wikitext(ptitle) -- Before the first poll if pfirstweek > minweeks then row:tag('td') :attr('colspan', pfirstweek - minweeks) :css('background', colors['not released']) :wikitext(labels['not released']) end -- Results local lastweek = 'first week' for k = pfirstweek,plastweek do local rank = args['poll' .. i .. '_' .. k]				if rank then rank = mw.ustring.gsub(rank, '^&[MNmn][Dd][Aa][Ss][Hh];', '—') rank = mw.ustring.gsub(rank, '^[–%-]', '—') end local thisweek = get_rank(rank) row:tag('td') :css('background', get_color(lastweek, thisweek)) :wikitext(format_cell_text(rank)) lastweek = thisweek end -- After the last poll if plastweek < maxweeks then rank = args['poll' .. i .. '_final'] local colspan = (maxweeks - plastweek) - (rank and 1 or 0) row:tag('td') :attr('colspan', (colspan > 1) and colspan or nil) :css('background', colors['not released']) :wikitext(labels['not released']) if rank and colspan > 0 then rank = mw.ustring.gsub(rank, '^&[MNmn][Dd][Aa][Ss][Hh];', '—') rank = mw.ustring.gsub(rank, '^[–%-]', '—') local thisweek = get_rank(rank) row:tag('td') :css('background', get_color(lastweek, thisweek)) :wikitext(format_cell_text(rank)) end end end end -- Add legend local line1, line2 = ,  if legend['+'] or legend['-'] then for k,v in ipairs({'+', '-'}) do line1 = line1 .. ' ██ ' line1 = line1 .. ' ' .. labels[v] end end for k,v in ipairs({'—', 'RV', 'т', ''}) do if legend[v] then line2 = line2 .. ' ' .. v .. ' = ' .. labels[v] end end if line1 ~=  or line2 ~=  then caption:wikitext(' \'\'\ .. labels['legend'] .. ':\'\'\ .. line1) if line1 ~=  and line2 ~=  then caption:wikitext(' ') end caption:wikitext(line2 .. ' ') end checkargs(args)

local trackstr = (#tracking > 0) and table.concat(tracking, ) or  if #preview > 0 then trackstr = require('Module:If preview')._warning({			'Unknown parameters ' .. table.concat(preview, '; ') .. '.'		}) .. trackstr end

return frame:extensionTag{ name = 'templatestyles', args = { src = templatestyles} } .. tostring(root) .. trackstr end

return p