Module:Arbcom election banner

local messageBox = require('Module:Message box')local navbarModule = require('Module:Navbar')local horizontal = require('Module:List').horizontallocal p = {}-- Get constants.local lang = mw.language.getContentLanguage()local currentUnixDate = tonumber(lang:formatDate('U'))local function err(msg)return mw.ustring.format('<strong class="error">%s</strong>', msg)endlocal function getUnixDate(date)local success, unixDate = pcall(lang.formatDate, lang, 'U', date)if success thenreturn tonumber(unixDate)endendlocal function unixDateError(date)return err(tostring(date) .. ' is not a valid date.')endlocal function makeOmbox(oargs)return messageBox.main('ombox', oargs)endlocal function makeNavbar(name)return navbarModule.navbar{name, mini = '1'}endlocal function randomizeArray(t)-- Iterate through the array backwards, each time swapping the entry "i" with a random entry.-- Courtesy of Xinhuan at http://forums.wowace.com/showthread.php?p=279756math.randomseed(mw.site.stats.edits)for i = #t, 2, -1 dolocal r = math.random(i)t[i], t[r] = t[r], t[i]endreturn tendlocal function getArgNums(args, prefix)-- Returns a table containing the numbers of the arguments that exist for the specified prefix. For example, if the prefix-- was 'data', and 'data1', 'data2', and 'data5' exist, it would return {1, 2, 5}.local nums = {}for k, v in pairs(args) dok = tostring(k)local num = mw.ustring.match(k, '^' .. prefix .. '([1-9]%d*)$')if num thentable.insert(nums, tonumber(num))endendtable.sort(nums)return numsendlocal function showBeforeDate(datePairs)-- Shows a value if it is before a given date.for i, datePair in ipairs(datePairs) dolocal date = datePair.datelocal val = datePair.valif not date then -- No date specified, so assume we have no more dates to process.return valendlocal unixDate = getUnixDate(date)if not unixDate then return unixDateError(date) endif currentUnixDate < unixDate then -- The specified date is in the future.return valendendendlocal function countdown(date, event)if type(event) ~= 'string' then return err('No event name provided.') end-- Get the current date unix timestamp.local unixDate = getUnixDate(date)if not unixDate then return unixDateError(date) endunixDate = tonumber(unixDate)-- Subtract the timestamp from the current unix timestamp to find the time left, and output that in a readable way.local secondsLeft = unixDate - currentUnixDateif secondsLeft <= 0 then return endlocal timeLeft = lang:formatDuration(secondsLeft, {'weeks', 'days', 'hours'})-- Find whether we are plural or not.local isOrAreif mw.ustring.match(timeLeft, '^%d+') == '1' thenisOrAre = 'is'elseisOrAre = 'are'endlocal timeLeft = mw.ustring.gsub(timeLeft, '(%d+)', '<span class="ace-banner-timeleft">%1</span>')-- Make the refresh link, and join it all together.local refreshLink = mw.title.getCurrentTitle():fullUrl{action = 'purge'}refreshLink = mw.ustring.format('<span class="ace-banner-refresh plainlinks">([%s refresh])</span>', refreshLink)return mw.ustring.format('There %s %s until %s. %s', isOrAre, timeLeft, event, refreshLink)endlocal function format_guides(args, year)local guideNums = getArgNums(args, 'guide')local guides = {}for _, num in ipairs(guideNums) dotable.insert(guides, args['guide' .. tostring(num)])endlocal guide_text = mw.ustring.format('\nThese [[:Category:Wikipedia Arbitration Committee Elections %s voter guides|guides]] '.. 'represent the thoughts of their authors. All individually written '.. 'voter guides are eligible for inclusion.\n',year)guides = randomizeArray(guides)guides = horizontal(guides)local ret = [=[<div class="mw-collapsible mw-collapsed"><div class="ace-banner-guides-title"><div>Personal voter guides</div></div><div class="mw-collapsible-content">%s%s</div></div>]=]return mw.ustring.format(ret, guide_text, guides)endlocal function getElectionInfo(year, key)local frame = mw.getCurrentFrame()local result = frame:expandTemplate{title = 'Arbitration Committee candidate/data', args = {year, key}}if result ~= '' thenreturn resultelsereturn nilendendlocal function getStartDate(year, key)local date = getElectionInfo(year, key)if not date thenreturn nilelsereturn '00:00, ' .. lang:formatDate('d F Y', date)endendlocal function getEndDate(year, key)local date = getElectionInfo(year, key)if not date thenreturn nilelsereturn '23:59, ' .. lang:formatDate('d F Y', date .. ' -1 day')endendlocal function getVotePage(year)local pollId = getElectionInfo(year, 'poll')if pollId thenreturn string.format('[https://www.search.com.vn/wiki/en/Special:SecurePoll/vote/%s Vote]', pollId)elsereturn '<span style="color:gray">Vote</span>'endendlocal function getVoteLog(year)local voteWikiId = getElectionInfo(year, 'votewikiid')if voteWikiId thenreturn string.format('[https://vote.wikimedia.org/wiki/Special:SecurePoll/list/%s Voter log]', voteWikiId)elsereturn '<span style="color:gray">Voter log</span>'endendfunction p._main(args)-- Get data for the box, plus the box title.local year = args.year or lang:formatDate('Y')local name = args.name or 'ACE' .. yearlocal navbar = makeNavbar(name)local electionpage = args.electionpage or mw.ustring.format('[[Wikipedia:Arbitration Committee Elections December %s|%s Arbitration Committee Elections]]',year, year)-- Get nomination or voting link, depending on the date.local beforenomlink = args.beforenomlink or mw.ustring.format('[[Wikipedia:Requests for comment/Arbitration Committee Elections December %s/Electoral Commission|Electoral Commission RFC]]', year)local nomstart = args.nomstart or getStartDate(year, 'nombegin') or error('No nomstart date supplied')local nomlink = args.nomlink or mw.ustring.format('[[Wikipedia:Arbitration Committee Elections December %s/Candidates|Nominate]]', year)local nomend = args.nomend or getEndDate(year, 'nomend') or error('No nomend date supplied')local votestart = args.votestart or getStartDate(year, 'begin') or error('No votestart date supplied')local votepage = args.votepage or getVotePage(year)local votelink = args.votelink or mw.ustring.format('<span class="ace-banner-votelink">%s</span>', votepage)local votelog = args.votelog or getVoteLog(year)local voteend = args.voteend or getEndDate(year, 'end') or error('No voteend date supplied')local voteendlink = args.voteendlink or voteloglocal scheduleText = showBeforeDate{{val = beforenomlink, date = nomstart},{val = nomlink, date = nomend},{val = countdown(votestart, 'voting begins'), date = votestart},{val = votelink, date = voteend},{val = voteendlink}}-- support votelog as its own element. must be done after we have scheduleTextif scheduleText ~= votelink thenvotelog = nilend-- Get other links.local contact = args.contact or mw.ustring.format('[[Wikipedia talk:Arbitration Committee Elections December %s/Coordination|Contact the coordinators]]', year)local discuss = args.discuss or mw.ustring.format('[[Wikipedia talk:Arbitration Committee Elections December %s|Discuss the elections]]', year)local cguide = args.cguide or mw.ustring.format('[[Wikipedia:Arbitration Committee Elections December %s/Candidates/Guide|Candidate guide]]', year)local cstatements = args.cstatements or mw.ustring.format('[[Wikipedia:Arbitration Committee Elections December %s/Candidates|Candidate statements]]', year)local cquestions = args.cquestions or mw.ustring.format('[[Wikipedia:Arbitration Committee Elections December %s/Questions|Questions for the candidates]]', year)local cdiscuss = args.cdiscuss or mw.ustring.format('[[Wikipedia:Arbitration Committee Elections December %s/Candidates/Discussion|Discuss the candidates]]', year)local guidecat = args.guidecat or mw.ustring.format('')local guides = format_guides(args, year)-- Get the text field of ombox.local lead_links = horizontal({class = 'ace-banner-lead-links','<span class="ace-banner-mainpage">' .. electionpage .. '</span>',scheduleText,votelog,contact,discuss,'[[Wikipedia:5-minute guide to ArbCom elections|Quick guide]]'})local candidate_links = horizontal({class = 'ace-banner-candidates-links inline',cguide,cstatements,cquestions,cdiscuss,})return makeOmbox({image = args.image or '[[File:Judges cupola.svg|50px|ArbCom|link=]]',style = args.style or nil,text = mw.ustring.format('<div class="ace-banner-navbar">%s</div>%s<span class="ace-banner-candidates">Candidates: </span>%s%s',navbar,lead_links,candidate_links,guides),templatestyles = 'Module:Arbcom election banner/styles.css',class = 'ace-banner'})end function p.main(frame)-- If called via #invoke, use the args passed into the invoking template, or the args passed to #invoke if any exist.-- Otherwise assume args are being passed directly in from the debug console or from another Lua module.local origArgsif frame == mw.getCurrentFrame() thenorigArgs = frame:getParent().argsfor k, v in pairs(frame.args) doorigArgs = frame.argsbreakendelseorigArgs = frameend-- Trim whitespace and remove blank arguments.local args = {}for k, v in pairs(origArgs) doif type(v) == 'string' thenv = mw.text.trim(v)endif v ~= '' thenargs[k] = vendendreturn p._main(args)end return p