Module:Sandbox/Frostly
Appearance
local messageBox = require('Module:Message box')
local navbarModule = require('Module:Navbar')
local p = {}
-- Get constants.
local lang = mw.language.getContentLanguage()
local currentUnixDate = lang:formatDate('U')
currentUnixDate = tonumber(currentUnixDate)
local function err(msg)
return mw.ustring.format('<b class="error">%s</b>', 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
-- Make the numbers red and bold, because that's what {{countdown}} does and it makes them look important.
local timeLeft = mw.ustring.gsub(timeLeft, '(%d+)', '<span style="color: #F00; font-weight: bold;">%1</span>')
-- Make the refresh link, and join it all together.
local refreshLink = mw.title.getCurrentTitle():fullUrl{action = 'purge'}
refreshLink = mw.ustring.format('<small><span class="plainlinks">([%s refresh])</span></small>', refreshLink)
return mw.ustring.format('There %s %s until %s. %s', isOrAre, timeLeft, event, refreshLink)
end
local function collapse(s, heading, bg)
local ret = [=[
<div style="margin-left: 0px;">
{| class="navbox collapsible collapsed" style="background: transparent; text-align: left; border: 1px solid silver; margin-top: 0.2em;"
|-
! style="background-color: %s; text-align: center; font-size: 112%%;" | %s
|-
| style="border: solid 1px silver; padding: 8px; background-color: white; font-size: 112%%;" | %s
|}</div>]=]
return mw.ustring.format(ret, bg or '#e0f8e2', heading, s)
end
local function getYearFromName(name)
return name:match('%d+$')
end
local function getYearAndName(args)
local year = args.year
local name = args.name
if year and name then
if getYearFromName(name) ~= year then
error(mw.ustring.format(
"'name' (%s) ends in a number different from 'year' (%s)",
name, year
), 3)
end
elseif year and not name then
name = 'ACE' .. year
elseif name and not year then
year = getYearFromName(name)
if not year then
error("'year' is missing and 'name' does not end in a number", 3)
end
else
error("neither 'year' nor 'name' is specified (at least one must be)", 3)
end
return year, name
end
local function getDateArgument(args, name)
local value = args[name]
if not value then
error(string.format('No %s date supplied', name), 3)
end
return value
end
function p._main(args)
-- Get data for the box, plus the box title.
local year, name = getYearAndName(args)
local root = args.rootpagename or mw.ustring.format(
'Arbitration Committee Elections December %s', year
)
local projroot = 'Wikipedia:' .. root
local talkroot = 'Wikipedia talk:' .. root
local navbar = makeNavbar(name)
local electionpage = args.electionpage or mw.ustring.format(
'[[%s|%s Arbitration Committee Elections]]',
projroot, year
)
-- Get nomination or voting link, depending on the date.
local beforenomlink = args.beforenomlink or mw.ustring.format('[[Wikipedia:Requests for comment/%s|%s ArbCom pre-election RFC]]', root, year)
local nomstart = getDateArgument(args, "nomstart")
local nomlink = args.nomlink or mw.ustring.format('[[%s/Candidates|Nominate]]', projroot)
local nomend = getDateArgument(args, "nomend")
local votestart = getDateArgument(args, "votestart")
local votepage = args.votepage or '[[Special:SecurePoll|Cast your vote]]'
local votelog = args.votelog or mw.ustring.format('[[%s/Log|Voter log]]', projroot)
local votelink = args.votelink or mw.ustring.format("'''%s'''\n* %s", votepage, votelog)
local voteend = getDateArgument(args, "voteend")
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}
}
-- Get other links.
local contact = args.contact or mw.ustring.format('[[%s/Coordination|Contact the coordinators]]', talkroot)
local discuss = args.discuss or mw.ustring.format('[[%s|Discuss the elections]]', talkroot)
local cguide = args.cguide or mw.ustring.format('[[%s/Candidates/Guide|Candidate guide]]', projroot)
local cstatements = args.cstatements or mw.ustring.format('[[%s/Candidates|Candidate statements]]', projroot)
local cquestions = args.cquestions or mw.ustring.format('[[%s/Questions|Questions for the candidates]]', projroot)
local cdiscuss = args.cdiscuss or mw.ustring.format('[[%s/Candidates/Discussion|Discuss the candidates]]', projroot)
-- Get voter guides
local guideNums = getArgNums(args, 'guide')
local guides = {}
for _, num in ipairs(guideNums) do
table.insert(guides, '\n* ' .. args['guide' .. tostring(num)])
end
guides = randomizeArray(guides)
guides = table.concat(guides)
guides = mw.ustring.format('<div class="hlist">\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. Guides to other guides are ineligible.\n%s</div>', year, guides)
guides = collapse(guides, 'Voter guides', '#e0f8e2')
-- Get the text field of ombox.
local text = [=[
<div style="float: right">%s</div><div class="hlist">
* '''%s'''
* %s
* %s
* %s
* [[Wikipedia:5-minute guide to ArbCom elections|Quick guide]]</div>
----
<div class="hlist">
; Candidates
: %s
: %s
: %s
: %s</div>
%s]=]
text = mw.ustring.format(
text,
navbar,
electionpage,
scheduleText,
contact,
discuss,
cguide,
cstatements,
cquestions,
cdiscuss,
guides
)
-- Build the ombox args
local oargs = {}
oargs.image = args.image or '[[File:Judges cupola.svg|50px|ArbCom|link=]]'
oargs.style = args.style or 'background-color: #e0f8e2'
oargs.text = text
return makeOmbox(oargs)
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