Module:Arbcom election banner/sandbox

local messageBox = require('Module:Message box')

local navbarModule = require('Module:Navbar')

local horizontal = require('Module:List').horizontal

local p = {}

-- Get constants.

local lang = mw.language.getContentLanguage()

local currentUnixDate = tonumber(lang:formatDate('U'))

local function err(msg)

return mw.ustring.format('%s', msg)

end

local function getUnixDate(date)

local success, unixDate = pcall(lang.formatDate, lang, 'U', date)

if success then

return tonumber(unixDate)

end

end

local function unixDateError(date)

return err(tostring(date) .. ' is not a valid date.')

end

local function makeOmbox(oargs)

return messageBox.main('ombox', oargs)

end

local function makeNavbar(name)

return navbarModule.navbar{name, mini = '1'}

end

local 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=279756

math.randomseed(mw.site.stats.edits)

for i = #t, 2, -1 do

local r = math.random(i)

t[i], t[r] = t[r], t[i]

end

return t

end

local 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) do

k = tostring(k)

local num = mw.ustring.match(k, '^' .. prefix .. '([1-9]%d*)$')

if num then

table.insert(nums, tonumber(num))

end

end

table.sort(nums)

return nums

end

local function showBeforeDate(datePairs)

-- Shows a value if it is before a given date.

for i, datePair in ipairs(datePairs) do

local date = datePair.date

local val = datePair.val

if not date then -- No date specified, so assume we have no more dates to process.

return val

end

local unixDate = getUnixDate(date)

if not unixDate then return unixDateError(date) end

if currentUnixDate < unixDate then -- The specified date is in the future.

return val

end

end

end

local 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) end

unixDate = 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 - currentUnixDate

if secondsLeft <= 0 then return end

local timeLeft = lang:formatDuration(secondsLeft, {'weeks', 'days', 'hours'})

-- Find whether we are plural or not.

local isOrAre

if mw.ustring.match(timeLeft, '^%d+') == '1' then

isOrAre = 'is'

else

isOrAre = 'are'

end

local timeLeft = mw.ustring.gsub(timeLeft, '(%d+)', '%1')

-- Make the refresh link, and join it all together.

local refreshLink = mw.title.getCurrentTitle():fullUrl{action = 'purge'}

refreshLink = mw.ustring.format('([%s refresh])', refreshLink)

return mw.ustring.format('There %s %s until %s. %s', isOrAre, timeLeft, event, refreshLink)

end

local function format_guides(args)

local guideNums = getArgNums(args, 'guide')

local guides = {}

for _, num in ipairs(guideNums) do

table.insert(guides, args['guide' .. tostring(num)])

end

local guide_text = '\nThese guides represent the thoughts of their authors. All individually written voter guides are eligible for inclusion.\n'

guides = randomizeArray(guides)

guides = horizontal(guides)

local ret = [=[

Personal voter guides

%s%s

]=]

return mw.ustring.format(ret, guide_text, guides)

end

local function getElectionInfo(year, key)

local frame = mw.getCurrentFrame()

local result = frame:expandTemplate{title = 'Arbitration Committee candidate/data', args = {year, key}}

if result ~= '' then

return result

else

return nil

end

end

local function getStartDate(year, key)

local date = getElectionInfo(year, key)

if not date then

return nil

else

return '00:00, ' .. lang:formatDate('d F Y', date)

end

end

local function getEndDate(year, key)

local date = getElectionInfo(year, key)

if not date then

return nil

else

return '23:59, ' .. lang:formatDate('d F Y', date .. ' -1 day')

end

end

local function getVotePage(year)

local pollId = getElectionInfo(year, 'poll')

if pollId then

return string.format('[https://en.wikipedia.org/wiki/Special:SecurePoll/vote/%s Vote]', pollId)

else

return 'Vote'

end

end

local function getVoteLog(year)

local voteWikiId = getElectionInfo(year, 'votewikiid')

if voteWikiId then

return string.format('[https://vote.wikimedia.org/wiki/Special:SecurePoll/list/%s Voter log]', voteWikiId)

else

return 'Voter log'

end

end

function 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' .. year

local navbar = makeNavbar(name)

local electionpage = args.electionpage or mw.ustring.format(

'%s Arbitration Committee Elections',

year, year

)

-- Get nomination or voting link, depending on the date.

local beforenomlink = args.beforenomlink or mw.ustring.format('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('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('%s', 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 votelog

local 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 scheduleText

if scheduleText ~= votelink then

votelog = nil

end

-- Get other links.

local contact = args.contact or mw.ustring.format('Contact the coordinators', mw.ustring.sub(year, 3, 4))

local discuss = args.discuss or mw.ustring.format('Discuss the elections', year)

local cguide = args.cguide or mw.ustring.format('Candidate guide', year)

local cstatements = args.cstatements or mw.ustring.format('Candidate statements', year)

local cquestions = args.cquestions or mw.ustring.format('Questions for the candidates', year)

local cdiscuss = args.cdiscuss or mw.ustring.format('Discuss the candidates', year)

local guides = format_guides(args)

-- Get the text field of ombox.

local lead_links = horizontal({

class = 'ace-banner-lead-links',

'' .. electionpage .. '',

scheduleText,

votelog,

contact,

discuss,

'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',

style = args.style or nil,

text = mw.ustring.format(

'

%s
%sCandidates: %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 origArgs

if frame == mw.getCurrentFrame() then

origArgs = frame:getParent().args

for k, v in pairs(frame.args) do

origArgs = frame.args

break

end

else

origArgs = frame

end

-- Trim whitespace and remove blank arguments.

local args = {}

for k, v in pairs(origArgs) do

if type(v) == 'string' then

v = mw.text.trim(v)

end

if v ~= '' then

args[k] = v

end

end

return p._main(args)

end

return p