模組:RFX report
此模块已评为alpha版,可接受第三方输入,并可用于少量页面以检查是否存在问题,但需要受到检查。欢迎提供新功能或修改其输入输出机制的建议。 |
此模块用于自动更新申请成为管理人员(RfX)的票数等资料,有两个函数可供外部调用,分别为主函数(main
)和点票函数(count
)。
主函数
输出一份表格,显示当前的RfX得票状况、剩余时间等资料。效果如下:
進行中的管理人员申請刷新 | ||||||||
---|---|---|---|---|---|---|---|---|
管理员候選人 | 支持 | 反對 | 中立 | 支持率 (%) | 狀態 | 完結時間 | 剩餘時間 | 驗票 |
SCP-20002 | 安全投票無法解析 | 投票中 | 2024年11月8日 (五) 00:00 (UTC) | 11小时 | 安全投票 | |||
ATannedBurger3 | 安全投票無法解析 | 投票中 | 2024年11月8日 (五) 00:00 (UTC) | 11小时 | 安全投票 | |||
0xDeadbeef | 安全投票無法解析 | 投票中 | 2024年11月8日 (五) 00:00 (UTC) | 11小时 | 安全投票 | |||
S83214143 | 安全投票無法解析 | 投票中 | 2024年11月8日 (五) 00:00 (UTC) | 11小时 | 安全投票 | |||
ASid5 | 安全投票無法解析 | 投票中 | 2024年11月8日 (五) 00:00 (UTC) | 11小时 | 安全投票 | |||
行政员候選人 | 支持 | 反對 | 中立 | 支持率 (%) | 狀態 | 完結時間 | 剩餘時間 | 驗票 |
Peacearth | 安全投票無法解析 | 投票中 | 2024年11月8日 (五) 00:00 (UTC) | 11小时 | 安全投票 | |||
监督员候選人 | 支持 | 反對 | 中立 | 支持率 (%) | 狀態 | 完結時間 | 剩餘時間 | 驗票 |
Peacearth2 | 安全投票無法解析 | 投票中 | 2024年11月8日 (五) 00:00 (UTC) | 11小时 | 安全投票 |
参数
style
:整个表格的样式,通常为style="..."
的格式以设置内联CSS样式。该参数默认值为:style="white-space:wrap; clear: %s; margin-top: 0em; margin-bottom: .5em; float: %s; padding: .5em 0em 0em 1.4em; background: #ffffff; border-collapse: collapse; border-spacing: 0;"
float
或align
:若不提供style
参数,可提供该参数来设定对齐方式。参数可取的值与CSS中float属性相同,可为none
、left
、right
、initial
、inherit
。clear
:若不提供style
参数,可提供该参数来设定对齐方式。参数可取的值与CSS中clear属性相同,可为none
、left
、right
、both
、initial
、inherit
。
点票函数
输出当前RfX支持、反对、中立的票数比,并提供到对应章节的内链。可用于RfX页面中,则用户投票后无需更新总票数。例如解析Wikipedia:申请成为管理员/Lnnocentius的效果如下:23/8/2
参数
title
:RfX页面的完整标题,默认值为当前页面。split
:分割符,默认值为半角斜杠“/”。
維護分類
- Category:投票計算失效的頁面(0)
- 請檢查{{RFX count}}的
|title=
是否正確。
- 請檢查{{RFX count}}的
-- This module is a replacement for the RfX report bot.
local rfx = require( 'Module:Rfx' )
local colours = mw.loadData( 'Module:RFX report/colour' )
local p = {}
local function getRfxes()
-- Get the title object for [[Wikipedia:Requests for adminship]].
local noError, rfa = pcall( mw.title.new, 'Wikipedia:申请成为管理人员/申请区' )
if not noError or ( noError and not rfa ) then
return nil
end
local rfaText = rfa:getContent()
if not rfaText then
return nil
end
-- Return a table with a list of pages transcluded from
-- [[Wikipedia:Requests for adminship]], minus the exceptions
-- which are always transcluded there.
local t = {}
local exceptions = { 'header' }
for rfxPage, rfxSubpage in mw.ustring.gmatch( rfaText, '{{[ _]*([wW]ikipedia:申[请請]成[为為][^/]-/([^{}]-))[ _]*}}' ) do
local isException = false
for _, v in ipairs( exceptions ) do
if rfxSubpage == v then
isException = true
break
end
end
if not isException then
table.insert( t, rfxPage )
end
end
return t
end
local function makeRow( rfxObject )
if not ( type( rfxObject ) == 'table' and rfxObject.getTitleObject and rfxObject.getSupportUsers ) then
return nil
end
local style = ''
local styleInline = ''
local status = rfxObject:getStatus()
if status == '已结束' then
style = ' style="background: #f8cdc6;" |'
styleInline = ' background: #f8cdc6;'
end
local page = rfxObject:getTitleObject().prefixedText
local user = rfxObject.user or mw.getCurrentFrame():callParserFunction('#titleparts', {rfxObject:getTitleObject().prefixedText, 1, 2})
local supports = rfxObject.supports
local opposes = rfxObject.opposes
local neutrals = rfxObject.neutrals
local percent = rfxObject.percent
local colour
if percent then
colour = colours[ percent ]
end
colour = colour or ''
local votes
if supports and opposes and neutrals and percent then
votes = mw.ustring.format( [==[
| style="text-align: right;%s" | [[%s#支持|%d]]
| style="text-align: right;%s" | [[%s#反對|%d]]
| style="text-align: right;%s" | [[%s#中立|%d]]
| style="text-align: right; background: #%s;" | %d]==],
styleInline, page, supports,
styleInline, page, opposes,
styleInline, page, neutrals,
colour, percent
)
elseif rfxObject:isSecurePoll() then
votes = '\n| colspan="4" style="background: #f8efc6;" | 安全投票無法-{zh-cn:解析;zh-tw:剖析}-'
else
votes = '\n| colspan="4" style="background: #f8cdc6;" | 投票-{zh-cn:解析;zh-tw:剖析}-失败'
end
local securePollNotStart = false
-- XXX: 應對安全投票未設置VoteState時獲取的終止時間錯誤
if status == '尚未開始' and rfxObject:isSecurePoll() then
status = '\n| colspan="3" | 投票尚未開始'
securePollNotStart = true
elseif status then
status = mw.ustring.format( '\n| %s %s', style, status )
elseif rfxObject:isSecurePoll() then
status = '\n| style="background: #f8efc6;" | 安全投票無法-{zh-cn:获取;zh-tw:取得}-狀態'
else
status = '\n| style="background: #f8cdc6;" | 未能-{zh-cn:获取;zh-tw:取得}-狀態'
end
local endTime = mw.language.getContentLanguage():formatDate('Y年n月j日 (D) H:i (T)', rfxObject.endTime)
local secondsLeft = rfxObject:getSecondsLeft()
local timeLeft = rfxObject:getTimeLeft()
local time
if securePollNotStart then
time = ''
elseif endTime and timeLeft then
time = mw.ustring.format( '\n| %s %s\n| %s %s', style, endTime, style, timeLeft )
else
time = '\n| colspan="2" style="background: #f8cdc6;" | 未讀出終止時間'
end
local dupes = rfxObject:dupesExist()
if dupes then
if #dupes > 0 then
dupes = mw.ustring.format([==['''<abbr title="%s">有</abbr>''']==],
table.concat(dupes, '、'))
else
dupes = '无'
end
else
dupes = '--'
end
local report = rfxObject:getReport()
if report then
report = mw.ustring.format( '\n|%s [%s 验票]', style, tostring( report ) )
elseif rfxObject:isSecurePoll() then
report = '\n| style="background: #abcdef;" | 安全投票'
else
report = '\n| style="background: #f8cdc6;" | 找不到工具'
end
-- 第 x 次
local attempt = rfxObject.attempt
if attempt ~= '1' then
user = user .. '<sup>' .. attempt .. '</sup>'
end
return mw.ustring.format(
'\n|-\n|%s [[%s|%s]]%s%s%s %s',
style, page, user, votes, status, time, report
)
end
local function makeHeading( rfxType )
local rfxCaps
if rfxType == 'rfa' then
rfxCaps = '管理员'
elseif rfxType == 'rfb' then
rfxCaps = '行政员'
elseif rfxType == 'rfcu' then
rfxCaps = '用户查核员'
elseif rfxType == 'rfo' then
rfxCaps = '监督员'
elseif rfxType == 'rfia' then
rfxCaps = '界面管理员'
else
return nil
end
local lang = mw.getContentLanguage()
return mw.ustring.format(
'\n|-\n! %s候選人 !! 支持 !! 反對 !! 中立 !! 支持率 (%%) !! 狀態 !! 完結時間 !! 剩餘時間 !! 驗票',
rfxCaps
)
end
local function makeReportRows()
local rfxes = getRfxes()
if not rfxes then
return nil
end
-- Get RfX objects and separate RfAs, RfBs, RfCUs, RfOs and RfIAs.
local rfas, rfbs, rfcus, rfos, rfias = {}, {}, {}, {}, {}
for i, rfxPage in ipairs( rfxes ) do
local rfxObject = rfx.new( rfxPage )
if rfxObject then
if rfxObject.type == 'rfa' then
table.insert( rfas, rfxObject )
elseif rfxObject.type == 'rfb' then
table.insert( rfbs, rfxObject )
elseif rfxObject.type == 'rfcu' then
table.insert( rfcus, rfxObject )
elseif rfxObject.type == 'rfo' then
table.insert( rfos, rfxObject )
elseif rfxObject.type == 'rfia' then
table.insert( rfias, rfxObject )
end
end
end
local ret = {}
if #rfas > 0 then
table.insert( ret, makeHeading( 'rfa' ) )
for i, rfaObject in ipairs( rfas ) do
table.insert( ret, makeRow( rfaObject ) )
end
end
if #rfbs > 0 then
table.insert( ret, makeHeading( 'rfb' ) )
for i, rfbObject in ipairs( rfbs ) do
table.insert( ret, makeRow( rfbObject ) )
end
end
if #rfcus > 0 then
table.insert( ret, makeHeading( 'rfcu' ) )
for i, rfcuObject in ipairs( rfcus ) do
table.insert( ret, makeRow( rfcuObject ) )
end
end
if #rfos > 0 then
table.insert( ret, makeHeading( 'rfo' ) )
for i, rfoObject in ipairs( rfos ) do
table.insert( ret, makeRow( rfoObject ) )
end
end
if #rfias > 0 then
table.insert( ret, makeHeading( 'rfia' ) )
for i, rfiaObject in ipairs( rfias ) do
table.insert( ret, makeRow( rfiaObject ) )
end
end
return table.concat( ret )
end
local function makeReport( args )
local purgeLink = mw.title.getCurrentTitle():fullUrl( 'action=purge' )
local header = mw.ustring.format(
'\n|-\n! colspan="9" style="text-align: center;" | 進行中的[[Wikipedia:申请成为管理人员|管理人员申請]]<span class="plainlinks" style="float: right;"><small>[%s 刷新]</small></span>',
purgeLink
)
local rows = makeReportRows() or ''
if rows == '' then
rows = '\n|-\n| colspan="10" | 当前没有提名。请参阅[[Wikipedia:管理人員任免記錄|最近的管理人员任免记录]]。'
end
local style = args.style
if not style then
local float = args.float or args.align or 'right'
local clear = args.clear or 'left'
style = mw.ustring.format(
'style="white-space:wrap; clear: %s; margin-top: 0em; margin-bottom: .5em; float: %s; padding: .5em 0em 0em 1.4em; background: #ffffff; border-collapse: collapse; border-spacing: 0;"',
clear, float
)
end
return mw.ustring.format( '\n{| class="wikitable" %s%s%s\n|-\n|}', style, header, rows )
end
local function countVotes( args )
local title = args.title or mw.title.getCurrentTitle().prefixedText
local split = args.split or '/'
local rfxObject = rfx.new(title)
if not rfxObject then
return '<span class="error">投票-{zh-cn:解析;zh-tw:剖析}-失败[[Category:投票計算失效的頁面|未]]</span>'
end
if rfxObject:isSecurePoll() then
return '<span class="error">安全投票無法-{zh-cn:解析;zh-tw:剖析}-[[Category:投票計算失效的頁面|安]]</span>'
end
local s, o, n = rfxObject.supports, rfxObject.opposes, rfxObject.neutrals
if s and o and n then
return string.format('[[%s#支持|%d]]%s[[%s#反對|%d]]%s[[%s#中立|%d]]',
title, s, split, title, o, split, title, n)
else
return '<span class="error">投票-{zh-cn:解析;zh-tw:剖析}-失败[[Category:投票計算失效的頁面|錯]]</span>'
end
end
local function countVotes2( args )
local title = args.title or mw.title.getCurrentTitle().prefixedText
local split = args.split or '/'
local rfxObject = rfx.new(title)
if not rfxObject then
return '<span class="error">投票-{zh-cn:解析;zh-tw:剖析}-失败[[Category:投票計算失效的頁面|未]]</span>'
end
if rfxObject:isSecurePoll() then
return '<span class="error">安全投票無法-{zh-cn:解析;zh-tw:剖析}-[[Category:投票計算失效的頁面|安]]</span>'
end
local s, o, n = rfxObject.supports, rfxObject.opposes, rfxObject.neutrals
if s and o and n then
return string.format('%d%s%d%s%d',
s, split, o, split, n)
else
return '<span class="error">投票-{zh-cn:解析;zh-tw:剖析}-失败[[Category:投票計算失效的頁面|錯]]</span>'
end
end
function p.count( frame )
-- Process the arguments.
local args
if frame == mw.getCurrentFrame() then
args = frame:getParent().args
for k, v in pairs( frame.args ) do
args = frame.args
break
end
else
args = frame
end
return countVotes( args )
end
function p.count2( frame )
-- Process the arguments.
local args
if frame == mw.getCurrentFrame() then
args = frame:getParent().args
for k, v in pairs( frame.args ) do
args = frame.args
break
end
else
args = frame
end
return countVotes2( args )
end
function p.main( frame )
-- Process the arguments.
local args
if frame == mw.getCurrentFrame() then
args = frame:getParent().args
for k, v in pairs( frame.args ) do
args = frame.args
break
end
else
args = frame
end
return makeReport( args )
end
return p