请输入您要查询的百科知识:

 

词条 Module:Signpost poll
释义 -- This module implements polls used in articles of the Signpost.

local CONFIG_MODULE = 'Module:Signpost poll/config'

local yesno = require('Module:Yesno')

local mStringCount = require('Module:String count')

local lang = mw.language.getContentLanguage()


-- Message method-- This method is available in every class, so it is defined separately.

local function message(self, key, params, isPreprocessed)

local msg = self.cfg.msg[key]

if params and #params > 0 then

msg = mw.message.newRawMessage(msg, params):plain()

end

if isPreprocessed then

msg = self.frame:preprocess(msg)

end

return msg

end


-- Option class

local Option = {}

Option.__index = Option

Option.message = message

function Option.new(t)

local self = setmetatable({}, Option)

self.cfg = t.cfg

self.frame = t.frame

self.nOption = t.nOption

self.votePage = t.votePage

self.preload = t.preload

self.text = t.text

self.voteText = t.voteText

self.color = t.color

return self

end

function Option:getCount()

if self.count then

return self.count

else

self.count = mStringCount._count{

page = self.votePage,

search = self:getVoteText(n)

}

return self.count

end

end

function Option:setVoteTotal(n)

self.total = n

end

function Option:getVoteTotal()

return self.total or error('total number of votes has not been set')

end

function Option:getPercentage()

if self.percentage then

return self.percentage

else

self.percentage = self:getCount() / self:getVoteTotal() * 100

return self.percentage

end

end

function Option:getColor()

-- Get the default color for option n

if self.color then

return self.color

end

local colors = self.cfg.colors

local color = colors[self.nOption]

if color then

self.color = color

else

-- Loop to find the length of colors. We can't use the # operator as

-- a metatable is set by mw.loadData. This is bad for polls with

-- more options than there are colors in the config, as we would loop

-- for every single option object. This will likely never be a problem

-- in practice, however.

local nColors = 0

for i in ipairs(colors) do

nColors = i

end

-- colors[nColors] is necessary as Lua arrays are indexed starting at

-- 1, and n % self.nColors might sometimes equal 0.

self.color = colors[self.nOption % nColors] or colors[nColors]

end

return self.color

end

function Option:getVoteText()

self.voteText = self.voteText or self:message(

'vote-default',

{self.nOption},

true

)

return self.voteText

end

function Option:makeVoteURL()

local url = mw.uri.fullUrl(

self.votePage,

{

action = 'edit',

section = 'new',

nosummary = 'true',

preload = self.preload,

['preloadparams[]'] = self:getVoteText()

}

)

return tostring(url)

end

function Option:renderButton()

local button = mw.html.create('span')

:addClass('mw-ui-button mw-ui-progressive')

:attr('role', 'button')

:attr('aria-disabled', 'false')

:wikitext(self.text)

local wrapper = mw.html.create('span')

:addClass('plainlinks')

:css('margin', '0 4px')

:wikitext(string.format(

'[%s %s]',

self:makeVoteURL(),

tostring(button)

))

return wrapper

end

function Option:renderLegendRow()

local legend = mw.html.create('div')

legend

:css('margin', '4px')

:tag('span')

:css('display', 'inline-block')

:css('width', '1.5em')

:css('height', '1.5em')

:css('margin', '1px 0')

:css('border', '1px solid black')

:css('background-color', self:getColor())

:css('text-align', 'center')

:wikitext(' ')

:done()

:wikitext(' ')

:wikitext(self:message('legend-option-text', {

self.text,

self:getCount(),

string.format('%.0f', self:getPercentage())

}, true))

return legend

end


-- Poll class

local Poll = {}

Poll.__index = Poll

Poll.message = message

function Poll.new(args, cfg, frame)

local self = setmetatable({}, Poll)

self.cfg = cfg or mw.loadData(CONFIG_MODULE)

self.frame = frame or mw.getCurrentFrame()

-- Set required fields

self.question = assert(args.question, self:message('no-question-error'))

self.votePage = assert(args.votepage, self:message('no-votepage-error'))

-- Set optional fields

self.headerText = args.header or self:message('header-text')

self.icon = args.icon or self:message('icon-default')

self.overlay = args.overlay or self:message('overlay-default')

self.minimum = tonumber(args.minimum) or self:message('minimum-default')

self.expiry = args.expiry

self.lineBreak = args['break']

-- Set options

self.options = {}

do

local preload = self:message('preload-page')

local i = 1

while true do

local key = 'option' .. tostring(i)

local text = args[key]

if not text then

break

end

table.insert(self.options, Option.new{

nOption = i,

text = text,

voteText = args[key .. 'vote'],

color = args[key .. 'color'],

cfg = self.cfg,

frame = self.frame,

votePage = self.votePage,

preload = preload

})

i = i + 1

end

if #self.options < 2 then

error(self:message('not-enough-options-error'))

end

end

-- Check for duplicate vote text

do

local votes = {}

for option in self:iterateOptions() do

if votes[option:getVoteText()] then

error(self:message(

'duplicate-vote-text-error',

{votes[option:getVoteText()], option.nOption},

true

))

else

votes[option:getVoteText()] = option.nOption

end

end

end

-- Prompt users to create the vote page if it doesn't exist.

do

local success, votePageContent = pcall(function ()

return mw.title.new(self.votePage):getContent()

end)

if not success or not votePageContent then

local createVotePageUrl = mw.uri.fullUrl(

self.votePage,

{

action = 'edit',

preload = self:message('vote-page-preload-default'),

['preloadparams[]'] = mw.title.getCurrentTitle().prefixedText,

summary = self:message('vote-page-create-summary'),

editintro = self:message('vote-page-create-editintro')

}

)

error(self:message(

'votepage-nonexistent-error',

{tostring(createVotePageUrl)}

), 0)

end

end

-- Find total number of votes

do

local total = 0

for option in self:iterateOptions() do

total = total + option:getCount()

end

for option in self:iterateOptions() do

option:setVoteTotal(total)

end

self.voteTotal = total

end

return self

end

-- Static methods

function Poll.getUnixDate(date)

date = lang:formatDate('U', date)

return tonumber(date)

end

-- Normal methods

function Poll:iterateOptions()

local i = 0

local n = #self.options

return function ()

i = i + 1

if i <= n then

return self.options[i]

end

end

end

function Poll:renderHeader()

local headerDiv = mw.html.create('div')

headerDiv

:css('border-top', '1px solid #CCC')

:css('font-family', 'Georgia, Palatino, Palatino Linotype, Times, Times New Roman, serif')

:css('color', '#333')

:css('padding', '5px 0')

:css('line-height', '120%')

:wikitext(string.format(

,

self.icon

))

:tag('span')

:css('text-transform', 'uppercase')

:css('color', '#999')

:css('font-size', '105%')

:css('font-weight', 'bold')

:wikitext(self.headerText)

return headerDiv

end

function Poll:renderQuestion()

local question = mw.html.create('div')

:css('margin-top', '10px')

:css('margin-bottom', '10px')

:css('line-height', '100%')

:css('font-size', '95%')

:wikitext(self.question)

return question

end

function Poll:renderVisualization()

local overlayWidth = '253px'

local vzn = mw.html.create('div')

:css('height', '250px')

:css('border-spacing', '0')

:css('width', overlayWidth)

:css('margin-left', 'auto')

:css('margin-right', 'auto')

-- Overlay

vzn

:tag('div')

:css('position', 'absolute')

:css('z-index', '2')

:css('padding', '0')

:css('margin', '0')

:wikitext(string.format(

'  ',

self.overlay,

overlayWidth

))

-- Option colors

for option in self:iterateOptions() do

vzn:tag('div')

:css('background', option:getColor())

:css('padding', '0')

:css('margin', '0')

:css('width', '250px')

:css('height', string.format(

'%.3f%%', -- Round to 3 decimal places and add a percent sign

option:getPercentage()

))

:wikitext(' ')

end

return vzn

end

function Poll:renderLegend()

local legend = mw.html.create('div')

:css('margin-top', '3px')

:css('display', 'flex')

:css('justify-content', 'center')

local centered = legend:tag('div')

for option in self:iterateOptions() do

centered:node(option:renderLegendRow())

end

return legend

end

function Poll:hasLineBreaks()

-- Try to auto-detect whether we should have line breaks

if self.lineBreak then

return yesno(self.lineBreak) or true

end

local nOptions = #self.options

if nOptions > 3 then

return true

end

local wordCount = 0

for option in self:iterateOptions() do

wordCount = wordCount + mw.ustring.len(option.text)

end

if nOptions == 3 then

return wordCount >= 12

else

return wordCount >= 15

end

end

function Poll:renderButtons()

local hasBreaks = self:hasLineBreaks()

local buttons = mw.html.create('div')

:css('margin-top', '5px')

:css('display', 'flex')

:css('justify-content', 'center')

local centered = buttons:tag('div')

if not hasBreaks then

centered:css('text-align', 'center')

end

for option in self:iterateOptions() do

local button

if hasBreaks then

button = centered:tag('div')

:css('margin', '4px 0')

else

button = centered

end

button:node(option:renderButton())

end

return buttons

end

function Poll:renderWarning(s)

local warning = mw.html.create('div')

warning

:css('line-height', '90%')

:css('width', '100%')

:css('margin-top', '5px')

:css('text-align', 'center')

:css('color', 'red')

:css('font-size', '85%')

:wikitext(s)

return warning

end

function Poll:hasMinimumVoteCount()

return self.voteTotal >= self.minimum

end

function Poll:isOpen()

if self.expiry then

return self.getUnixDate() < self.getUnixDate(self.expiry)

else

return true

end

end

function Poll:__tostring()

local root = mw.html.create('div')

:css('width', '270px')

:css('float', 'right')

:css('clear', 'right')

:css('background', 'none')

:css('margin-bottom', '10px')

:css('margin-left', '10px')

:addClass('signpost-sidebar')

root:node(self:renderHeader())

root:node(self:renderQuestion())

-- Visualization and legend

if self:hasMinimumVoteCount() then

root:node(self:renderVisualization())

root:node(self:renderLegend())

else

root:node(self:renderWarning(self:message(

'not-enough-votes-warning',

{self.minimum - self.voteTotal},

true

)))

end

-- Buttons

if self:isOpen() then

root:node(self:renderButtons())

else

root:node(self:renderWarning(self:message('poll-closed-warning')))

end

return tostring(root)

end


-- Exports

local p = {}

function p._main(args, cfg, frame)

return tostring(Poll.new(args, cfg, frame))

end

function p.main(frame, cfg)

cfg = cfg or mw.loadData(CONFIG_MODULE)

local args = require('Module:Arguments').getArgs(frame, {

wrappers = cfg.wrappers

})

return p._main(args, cfg, frame)

end

return p

随便看

 

开放百科全书收录14589846条英语、德语、日语等多语种百科知识,基本涵盖了大多数领域的百科知识,是一部内容自由、开放的电子版国际百科全书。

 

Copyright © 2023 OENC.NET All Rights Reserved
京ICP备2021023879号 更新时间:2024/9/20 17:52:46