편집을 취소할 수 있습니다. 이 편집을 되돌리려면 아래의 바뀐 내용을 확인한 후 게시해주세요.
최신판 | 당신의 편집 | ||
4번째 줄: | 4번째 줄: | ||
-- Initialise necessary modules. | -- Initialise necessary modules. | ||
require('Module:No globals') | require('Module:No globals') | ||
local | local class = require('Module:Middleclass').class | ||
local | local mFileLink = require('Module:File link') | ||
local | local mProtectionLevel = require('Module:Effective protection level') | ||
local yesno = require('Module:Yesno') | local yesno = require('Module:Yesno') | ||
-- Lazily initialise modules and objects we don't always need. | -- Lazily initialise modules and objects we don't always need. | ||
local | local mArguments, mMessageBox, lang | ||
-------------------------------------------------------------------------------- | -------------------------------------------------------------------------------- | ||
-- | -- Config class | ||
-------------------------------------------------------------------------------- | -------------------------------------------------------------------------------- | ||
local function | local Config = class('Config') | ||
function Config:initialize(data) | |||
data = data or mw.loadData('Module:Protection banner/config') | |||
self._cfg = data.cfg | |||
self._msg = data.msg | |||
self._bannerConfigTables = {} | |||
end | end | ||
function Config:getBannerConfig(protectionObj) | |||
if self._bannerConfigTables[protectionObj] then | |||
if | return self._bannerConfigTables[protectionObj] | ||
else | |||
local ret = {} | |||
local cfg = self._cfg | |||
local action = protectionObj:getAction() | |||
local level = protectionObj:getLevel() | |||
local reason = protectionObj:getReason() | |||
local fields = { | |||
'text', | |||
'explanation', | |||
'tooltip', | |||
'alt', | |||
'image' | |||
} | |||
local configTables = {} | |||
if cfg.banners[action] then | |||
configTables[#configTables + 1] = cfg.banners[action][reason] | |||
end | |||
if cfg.defaultBanners[action] then | |||
configTables[#configTables + 1] = cfg.defaultBanners[action][level] | |||
configTables[#configTables + 1] = cfg.defaultBanners[action].default | |||
end | |||
configTables[#configTables + 1] = cfg.masterBanner | |||
for i, field in ipairs(fields) do | |||
for j, t in ipairs(configTables) do | |||
if t[field] then | |||
ret[field] = t[field] | |||
break | |||
end | |||
end | |||
end | end | ||
self._bannerConfigTables[protectionObj] = ret | |||
return ret | |||
end | end | ||
end | end | ||
function Config:getConfigTable(key) | |||
local blacklist = { | |||
banners = true, | |||
defaultBanners = true, | |||
masterBanner = true | |||
} | |||
if not blacklist[key] then | |||
return self._cfg[key] | |||
else | |||
return nil | |||
end | |||
end | end | ||
function Config:getMessage(key) | |||
return self._msg[key] | |||
end | end | ||
82번째 줄: | 84번째 줄: | ||
-------------------------------------------------------------------------------- | -------------------------------------------------------------------------------- | ||
local Protection = | local Protection = class('Protection') | ||
Protection | |||
function Protection:initialize(args, configObj, titleObj) | |||
-- Set action | -- Set action | ||
do | |||
local actions = { | |||
create = true, | |||
edit = true, | |||
move = true, | |||
autoreview = true | |||
} | |||
if args.action and actions[args.action] then | |||
self._action = args.action | |||
else | |||
self._action = 'edit' | |||
end | |||
end | end | ||
-- Set level | -- Set level | ||
do | |||
local level = mProtectionLevel._main(self._action, titleObj) | |||
if level == 'accountcreator' then | |||
-- Lump titleblacklisted pages in with template-protected pages, | |||
-- since templateeditors can do both. | |||
level = 'templateeditor' | |||
end | |||
if self._action == 'move' and level == 'autoconfirmed' then | |||
-- Users need to be autoconfirmed to move pages anyway, so treat | |||
-- semi-move-protected pages as unprotected. | |||
level = '*' | |||
end | |||
self._level = level or '*' | |||
end | end | ||
-- | -- Validation function for the expiry and the protection date | ||
local | local function validateDate(date, dateType) | ||
lang = lang or mw.language.getContentLanguage() | |||
local success, expiry = pcall(lang.formatDate, lang, 'U', args.expiry) | |||
expiry = tonumber(expiry) | |||
if success and expiry then | |||
return expiry | |||
else | |||
return string.format( | |||
'<strong class="error">Error: invalid %s ("%s")</strong>', | |||
dateType, | |||
tostring(args.expiry) | |||
) | |||
end | |||
end | end | ||
-- Set | -- Set expiry | ||
if args | if args.expiry then | ||
local indefStrings = configObj:getConfigTable('indefStrings') | |||
if | if indefStrings[args.expiry] then | ||
self._expiry = 'indef' | |||
elseif type(args.expiry) == 'number' then | |||
self._expiry = args.expiry | |||
else | |||
self._expiry = validateDate(args.expiry, 'expiry date') | |||
end | end | ||
end | end | ||
-- Set | -- Set reason | ||
do | do | ||
local reason = args.reason or args[1] | |||
local | if reason then | ||
self._reason = reason:lower() | |||
if | |||
end | end | ||
end | end | ||
-- Set protection date | |||
-- | self._protectionDate = validateDate(args.date, 'protection date') | ||
end | end | ||
function Protection: | function Protection:getAction() | ||
return self. | return self._action | ||
end | end | ||
function Protection: | function Protection:getLevel() | ||
return self._level | |||
return self | |||
end | end | ||
function Protection:isProtected() | |||
return self._level ~= '*' | |||
function Protection: | |||
return | |||
end | end | ||
function Protection: | function Protection:getReason() | ||
return self._reason | |||
return | |||
end | end | ||
function Protection: | function Protection:getExpiry() | ||
return self._expiry | |||
return self. | |||
end | end | ||
function Protection: | function Protection:getProtectionDate() | ||
return self._protectionDate | |||
end | end | ||
359번째 줄: | 186번째 줄: | ||
-------------------------------------------------------------------------------- | -------------------------------------------------------------------------------- | ||
local Blurb = | local Blurb = class('Blurb') | ||
Blurb. | |||
function Blurb:initialize(configObj, protectionObj, titleObj) | |||
self._configObj = configObj | |||
self._protectionObj = protectionObj | |||
self._bannerConfig = configObj:getBannerConfig(protectionObj) | |||
self._titleObj = titleObj | |||
end | |||
-- Static methods -- | |||
function Blurb. | function Blurb.makeFullUrl(page, query, display) | ||
local url = mw.uri.fullUrl(page, query) | |||
url = tostring(url) | |||
return string.format('[%s %s]', url, display) | |||
end | end | ||
function Blurb.formatDate(num) | |||
function Blurb | |||
-- Formats a Unix timestamp into dd Month, YYYY format. | -- Formats a Unix timestamp into dd Month, YYYY format. | ||
lang = lang or mw.language.getContentLanguage() | lang = lang or mw.language.getContentLanguage() | ||
386번째 줄: | 209번째 줄: | ||
lang.formatDate, | lang.formatDate, | ||
lang, | lang, | ||
'j F Y', | |||
'@' .. tostring(num) | '@' .. tostring(num) | ||
) | ) | ||
394번째 줄: | 217번째 줄: | ||
end | end | ||
function Blurb:_getExpandedMessage( | -- Private methods -- | ||
return self:_substituteParameters( | |||
function Blurb:_getExpandedMessage(msg) | |||
local msg = self._configObj:getMessage(msg) | |||
return self:_substituteParameters(msg) | |||
end | end | ||
function Blurb:_substituteParameters(msg) | function Blurb:_substituteParameters(msg) | ||
if not self._params then | if not self._params then | ||
local parameterFuncs = {} | local params, parameterFuncs = {}, {} | ||
setmetatable(params, { | |||
__index = function (t, k) | |||
local param | |||
if parameterFuncs[k] then | |||
param = parameterFuncs[k](self) | |||
end | |||
param = param or '' | |||
params[k] = param | |||
return param | |||
end | |||
}) | |||
parameterFuncs.CURRENTVERSION = self._makeCurrentVersionParameter | parameterFuncs.CURRENTVERSION = self._makeCurrentVersionParameter | ||
parameterFuncs.DELETIONDISCUSSION = self._makeDeletionDiscussionParameter | |||
parameterFuncs.DISPUTEBLURB = self._makeDisputeBlurbParameter | |||
parameterFuncs.DISPUTESECTION = self._makeDisputeSectionParameter | |||
parameterFuncs.EDITREQUEST = self._makeEditRequestParameter | parameterFuncs.EDITREQUEST = self._makeEditRequestParameter | ||
parameterFuncs.EXPIRY = self._makeExpiryParameter | parameterFuncs.EXPIRY = self._makeExpiryParameter | ||
parameterFuncs.EXPLANATIONBLURB = self._makeExplanationBlurbParameter | parameterFuncs.EXPLANATIONBLURB = self._makeExplanationBlurbParameter | ||
parameterFuncs.INTROBLURB = self._makeIntroBlurbParameter | parameterFuncs.INTROBLURB = self._makeIntroBlurbParameter | ||
parameterFuncs. | parameterFuncs.OFFICEBLURB = self._makeOfficeBlurbParameter | ||
parameterFuncs.PAGETYPE = self._makePagetypeParameter | parameterFuncs.PAGETYPE = self._makePagetypeParameter | ||
parameterFuncs.PROTECTIONBLURB = self._makeProtectionBlurbParameter | parameterFuncs.PROTECTIONBLURB = self._makeProtectionBlurbParameter | ||
414번째 줄: | 253번째 줄: | ||
parameterFuncs.PROTECTIONLEVEL = self._makeProtectionLevelParameter | parameterFuncs.PROTECTIONLEVEL = self._makeProtectionLevelParameter | ||
parameterFuncs.PROTECTIONLOG = self._makeProtectionLogParameter | parameterFuncs.PROTECTIONLOG = self._makeProtectionLogParameter | ||
parameterFuncs.RESETBLURB = self._makeResetBlurbParameter | |||
parameterFuncs.TALKPAGE = self._makeTalkPageParameter | parameterFuncs.TALKPAGE = self._makeTalkPageParameter | ||
parameterFuncs.TOOLTIPBLURB = self._makeTooltipBlurbParameter | parameterFuncs.TOOLTIPBLURB = self._makeTooltipBlurbParameter | ||
parameterFuncs.VANDAL = self._makeVandalTemplateParameter | parameterFuncs.VANDAL = self._makeVandalTemplateParameter | ||
self._params = | self._params = params | ||
end | end | ||
439번째 줄: | 268번째 줄: | ||
-- A link to the page history or the move log, depending on the kind of | -- A link to the page history or the move log, depending on the kind of | ||
-- protection. | -- protection. | ||
local | local action = self._protectionObj:getAction() | ||
if | local pagename = self._titleObj.prefixedText | ||
if action == 'move' then | |||
-- We need the move log link. | -- We need the move log link. | ||
return makeFullUrl( | return self.makeFullUrl( | ||
'Special:Log', | 'Special:Log', | ||
{type = 'move', page = pagename}, | {type = 'move', page = pagename}, | ||
449번째 줄: | 279번째 줄: | ||
else | else | ||
-- We need the history link. | -- We need the history link. | ||
return makeFullUrl( | return self.makeFullUrl( | ||
pagename, | pagename, | ||
{action = 'history'}, | {action = 'history'}, | ||
self:_getExpandedMessage('current-version-edit-display') | self:_getExpandedMessage('current-version-edit-display') | ||
) | ) | ||
end | |||
end | |||
function Blurb:_makeDeletionDiscussionLinkParameter() | |||
local deletionDiscussionPage = self._deletionDiscussionPage | |||
if deletionDiscussionPage then | |||
local display = self:_getExpandedMessage('deletion-discussion-link-display') | |||
return string.format('[[%s|%s]]', deletionDiscussionPage, display) | |||
end | |||
end | |||
function Blurb:_makeDisputeBlurbParameter() | |||
local expiry = self._protectionObj:getExpiry() | |||
if type(expiry) == 'number' then | |||
return self:_getExpandedMessage('dispute-blurb-expiry') | |||
else | |||
return self:_getExpandedMessage('dispute-blurb-noexpiry') | |||
end | |||
end | |||
function Blurb:_makeDisputeSectionParameter() | |||
-- "disputes", with or without a section link | |||
local section = self._section | |||
local disputes = self:_getExpandedMessage('dispute-section-link-display') | |||
if section then | |||
return string.format( | |||
'[[%s:%s#%s|%s]]', | |||
mw.site.namespaces[self._titleObj.namespace].talk.name, | |||
self._titleObj.text, | |||
section, | |||
disputes | |||
) | |||
else | |||
return disputes | |||
end | end | ||
end | end | ||
459번째 줄: | 323번째 줄: | ||
function Blurb:_makeEditRequestParameter() | function Blurb:_makeEditRequestParameter() | ||
local mEditRequest = require('Module:Submit an edit request') | local mEditRequest = require('Module:Submit an edit request') | ||
local action = self._protectionObj | local action = self._protectionObj:getAction() | ||
local level = self._protectionObj.level | local level = self._protectionObj:getLevel() | ||
-- Get the display message key. | |||
local key | |||
if action == 'edit' and level == 'autoconfirmed' then | |||
key = 'edit-request-semi-display' | |||
else | |||
key = 'edit-request-full-display' | |||
end | |||
local display = self:_getExpandedMessage(key) | |||
-- Get the edit request type. | -- Get the edit request type. | ||
467번째 줄: | 340번째 줄: | ||
if level == 'autoconfirmed' then | if level == 'autoconfirmed' then | ||
requestType = 'semi' | requestType = 'semi' | ||
elseif level == 'templateeditor' then | elseif level == 'templateeditor' then | ||
requestType = 'template' | requestType = 'template' | ||
475번째 줄: | 346번째 줄: | ||
requestType = requestType or 'full' | requestType = requestType or 'full' | ||
return mEditRequest.exportLinkToLua{type = requestType, display = display} | |||
return mEditRequest. | |||
end | end | ||
function Blurb:_makeExpiryParameter() | function Blurb:_makeExpiryParameter() | ||
local expiry = self._protectionObj | local expiry = self._protectionObj:getExpiry() | ||
if expiry == 'indef' then | |||
return | return nil | ||
elseif type(expiry) == 'number' then | |||
return Blurb.formatDate(expiry) | |||
elseif expiry then | |||
-- Expiry is an error string. | |||
return expiry | return expiry | ||
end | end | ||
491번째 줄: | 362번째 줄: | ||
function Blurb:_makeExplanationBlurbParameter() | function Blurb:_makeExplanationBlurbParameter() | ||
local action = self._protectionObj:getAction() | |||
local level = self._protectionObj:getLevel() | |||
local namespace = self._titleObj.namespace | |||
local isTalk = self._titleObj.isTalkPage | |||
-- @TODO: add semi-protection and pending changes blurbs | |||
local key | |||
if namespace == 8 then | |||
-- MediaWiki namespace | -- MediaWiki namespace | ||
key = 'explanation-blurb-full-nounprotect' | |||
elseif action == 'edit' and level == 'sysop' and not isTalk then | |||
key = 'explanation-blurb-full-subject' | |||
elseif action == 'move' then | |||
if isTalk then | |||
key = 'explanation-blurb-move-talk' | |||
else | |||
key = 'explanation-blurb-move-subject' | |||
end | |||
elseif action == 'create' then | |||
local xfd = self._deletionDiscussion | |||
if xfd then | |||
key = 'explanation-blurb-create-xfd' | |||
else | |||
elseif | key = 'explanation-blurb-create-noxfd' | ||
end | |||
else | else | ||
key = 'explanation-blurb-default' | |||
end | end | ||
return self: | return self:_getExpandedMessage(key) | ||
end | end | ||
function Blurb:_makeIntroBlurbParameter() | function Blurb:_makeIntroBlurbParameter() | ||
local expiry = self._protectionObj:getExpiry() | |||
if type(expiry) == 'number' then | |||
return self:_getExpandedMessage('intro-blurb-expiry') | return self:_getExpandedMessage('intro-blurb-expiry') | ||
else | else | ||
548번째 줄: | 402번째 줄: | ||
end | end | ||
function Blurb: | function Blurb:_makeOfficeBlurbParameter() | ||
local protectionDate = self._protectionObj:getProtectionDate() | |||
return self:_getExpandedMessage(' | if protectionDate then | ||
return self:_getExpandedMessage('office-blurb-protectiondate') | |||
else | else | ||
return self:_getExpandedMessage(' | return self:_getExpandedMessage('office-blurb-noprotectiondate') | ||
end | end | ||
end | end | ||
function Blurb:_makePagetypeParameter() | function Blurb:_makePagetypeParameter() | ||
local pagetypes = self. | local pagetypes = self._configObj:getConfigTable('pagetypes') | ||
return pagetypes[ | local namespace = self._titleObj.namespace | ||
return pagetypes[namespace] or pagetypes.default or error('no default pagetype defined') | |||
end | end | ||
function Blurb:_makeProtectionBlurbParameter() | function Blurb:_makeProtectionBlurbParameter() | ||
local protectionBlurbs = self. | local protectionBlurbs = self._configObj:getConfigTable('protectionBlurbs') | ||
local action = self._protectionObj | local action = self._protectionObj:getAction() | ||
local level = self._protectionObj | local level = self._protectionObj:getLevel() | ||
local msg | local msg | ||
if protectionBlurbs[action][level] then | if protectionBlurbs[action][level] then | ||
575번째 줄: | 429번째 줄: | ||
msg = protectionBlurbs.edit.default | msg = protectionBlurbs.edit.default | ||
else | else | ||
error('no protection blurb defined for protectionBlurbs.edit.default' | error('no protection blurb defined for cfg.protectionBlurbs.edit.default') | ||
end | end | ||
return self:_substituteParameters(msg) | return self:_substituteParameters(msg) | ||
581번째 줄: | 435번째 줄: | ||
function Blurb:_makeProtectionDateParameter() | function Blurb:_makeProtectionDateParameter() | ||
local protectionDate = self._protectionObj | local protectionDate = self._protectionObj:getProtectionDate() | ||
if type(protectionDate) == 'number' then | if type(protectionDate) == 'number' then | ||
return | return Blurb.formatDate(protectionDate) | ||
else | else | ||
return protectionDate | return protectionDate | ||
590번째 줄: | 444번째 줄: | ||
function Blurb:_makeProtectionLevelParameter() | function Blurb:_makeProtectionLevelParameter() | ||
local protectionLevels = self. | local protectionLevels = self._configObj:getConfigTable('protectionLevels') | ||
local action = self._protectionObj | local action = self._protectionObj:getAction() | ||
local level = self._protectionObj | local level = self._protectionObj:getLevel() | ||
local msg | local msg | ||
if protectionLevels[action][level] then | if protectionLevels[action][level] then | ||
601번째 줄: | 455번째 줄: | ||
msg = protectionLevels.edit.default | msg = protectionLevels.edit.default | ||
else | else | ||
error('no protection level defined for protectionLevels.edit.default' | error('no protection level defined for cfg.protectionLevels.edit.default') | ||
end | end | ||
return self:_substituteParameters(msg) | return self:_substituteParameters(msg) | ||
607번째 줄: | 461번째 줄: | ||
function Blurb:_makeProtectionLogParameter() | function Blurb:_makeProtectionLogParameter() | ||
local | local action = self._protectionObj:getAction() | ||
if | local pagename = self._titleObj.prefixedText | ||
if action == 'autoreview' then | |||
-- We need the pending changes log. | -- We need the pending changes log. | ||
return makeFullUrl( | return self.makeFullUrl( | ||
'Special:Log', | 'Special:Log', | ||
{type = 'stable', page = pagename}, | {type = 'stable', page = pagename}, | ||
617번째 줄: | 472번째 줄: | ||
else | else | ||
-- We need the protection log. | -- We need the protection log. | ||
return makeFullUrl( | return self.makeFullUrl( | ||
'Special:Log', | 'Special:Log', | ||
{type = 'protect', page = pagename}, | {type = 'protect', page = pagename}, | ||
self:_getExpandedMessage('protection-log-display') | self:_getExpandedMessage('protection-log-display') | ||
) | ) | ||
end | |||
end | |||
function Blurb:_makeResetBlurbParameter() | |||
local protectionDate = self._protectionObj:getProtectionDate() | |||
if protectionDate then | |||
return self:_getExpandedMessage('reset-blurb-protectiondate') | |||
else | |||
return self:_getExpandedMessage('reset-blurb-noprotectiondate') | |||
end | end | ||
end | end | ||
function Blurb:_makeTalkPageParameter() | function Blurb:_makeTalkPageParameter() | ||
local section = self._section | |||
local display = self:_getExpandedMessage('talk-page-link-display') | |||
return string.format( | return string.format( | ||
'[[%s:%s#%s|%s]]', | '[[%s:%s#%s|%s]]', | ||
mw.site.namespaces[self. | mw.site.namespaces[self._titleObj.namespace].talk.name, | ||
self. | self._titleObj.text, | ||
section or 'top', | |||
display | |||
) | ) | ||
end | end | ||
function Blurb:_makeTooltipBlurbParameter() | function Blurb:_makeTooltipBlurbParameter() | ||
local expiry = self._protectionObj:getExpiry() | |||
if type(expiry) == 'number' then | |||
return self:_getExpandedMessage('tooltip-blurb-expiry') | return self:_getExpandedMessage('tooltip-blurb-expiry') | ||
else | else | ||
643번째 줄: | 510번째 줄: | ||
end | end | ||
function Blurb: | function Blurb:_makeVandalTemplateParameter() | ||
local mVandalM = require('Module:Vandal-m') | |||
local username = self._username | |||
username = username or self._titleObj.baseText | |||
return mVandalM._main{username} | |||
end | |||
-- Public methods -- | |||
function Blurb:setDeletionDiscussionPage(page) | |||
self._deletionDiscussionPage = page | |||
end | |||
function Blurb:setUsername(username) | |||
self._username = username | |||
end | |||
function Blurb:setSection(section) | |||
self._section = section | |||
end | |||
function Blurb:makeReasonText() | |||
local msg = self._bannerConfig.text | |||
return self:_substituteParameters(msg) | |||
end | end | ||
function Blurb: | function Blurb:makeExplanationText() | ||
local msg = self._bannerConfig.explanation | |||
return self:_substituteParameters(msg) | |||
end | end | ||
function Blurb:makeTooltipText() | |||
local msg = self._bannerConfig.tooltip | |||
return self:_substituteParameters(msg) | |||
end | |||
function Blurb: | function Blurb:makeAltText() | ||
local msg = self._bannerConfig.alt | |||
return self:_substituteParameters(msg) | |||
end | |||
function Blurb:makeLinkText() | |||
local msg = self._bannerConfig.link | |||
if msg then | |||
return self:_substituteParameters(msg) | return self:_substituteParameters(msg) | ||
end | end | ||
691번째 줄: | 562번째 줄: | ||
-------------------------------------------------------------------------------- | -------------------------------------------------------------------------------- | ||
local BannerTemplate = | local BannerTemplate = class('BannerTemplate') | ||
function BannerTemplate | function BannerTemplate:initialize(configObj) | ||
self._configObj = configObj | |||
end | |||
function BannerTemplate:setImageFilename(filename, protectionObj, titleObj) | |||
if filename then | |||
if | self._imageFilename = filename | ||
return nil | |||
end | |||
local action = protectionObj:getAction() | |||
local level = protectionObj:getAction() | |||
local expiry = protectionObj:getExpiry() | |||
local namespace = titleObj.namespace | |||
-- Deal with special cases first. | |||
if (namespace == 10 or namespace == 828) -- Maybe we don't need the namespace check? | |||
and action == 'edit' | |||
and level == 'sysop' | |||
and not expiry | |||
then | |||
-- Fully protected modules and templates get the special red "indef" | |||
-- padlock. | |||
self._imageFilename = self._configObj:getMessage('image-filename-indef') | |||
return nil | |||
end | |||
-- Deal with regular protection types. | |||
local images = self._configObj:getConfigTable('images') | |||
if images[action] then | |||
if images[action][level] then | |||
self._imageFilename = images[action][level] | |||
return nil | |||
elseif images[action].default then | |||
self._imageFilename = images[action].default | |||
return nil | |||
end | end | ||
end | end | ||
return | |||
return nil | |||
end | |||
function BannerTemplate:setImageWidth(width) | |||
self._imageWidth = width | |||
end | |||
function BannerTemplate:setImageTooltip(tooltip) | |||
self._imageCaption = tooltip | |||
end | end | ||
function BannerTemplate:renderImage() | function BannerTemplate:renderImage() | ||
local filename = self._imageFilename | local filename = self._imageFilename | ||
or self. | or self._configObj:getMessage('image-filename-default') | ||
or 'Transparent.gif' | or 'Transparent.gif' | ||
return | return mFileLink.new(filename) | ||
:width(self._imageWidth or 20) | |||
:alt(self._imageAlt) | |||
alt | :link(self._imageLink) | ||
link | :caption(self._imageCaption) | ||
caption | :render() | ||
end | |||
function BannerTemplate:render() | |||
-- Dummy method, to be implemented by the subclasses. | |||
return '' | |||
end | end | ||
755번째 줄: | 635번째 줄: | ||
-------------------------------------------------------------------------------- | -------------------------------------------------------------------------------- | ||
local Banner = | local Banner = BannerTemplate:subclass('Banner') | ||
function Banner | function Banner:initialize(configObj) | ||
BannerTemplate.initialize(self, configObj) | |||
self:setImageWidth(40) | |||
end | end | ||
function Banner: | function Banner:setReasonText(s) | ||
self._reasonText = s | |||
end | |||
function Banner:setExplanationText(s) | |||
self._explanationText = s | |||
end | |||
function Banner:render(page) | |||
-- Renders the banner. | -- Renders the banner. | ||
-- The page parameter specifies the page to generate the banner for, for | |||
local reasonText = self._reasonText or error('no reason text set' | -- testing purposes. | ||
mMessageBox = mMessageBox or require('Module:Message box') | |||
local reasonText = self._reasonText or error('no reason text set') | |||
local explanationText = self._explanationText | local explanationText = self._explanationText | ||
local mbargs = { | local mbargs = { | ||
page = | page = page, | ||
type = 'protection', | type = 'protection', | ||
image = self:renderImage(), | image = self:renderImage(), | ||
783번째 줄: | 667번째 줄: | ||
) | ) | ||
} | } | ||
return | return mMessageBox.main('mbox', mbargs) | ||
end | end | ||
790번째 줄: | 674번째 줄: | ||
-------------------------------------------------------------------------------- | -------------------------------------------------------------------------------- | ||
local Padlock = | local Padlock = BannerTemplate:subclass('Padlock') | ||
function Padlock | function Padlock:initialize(configObj) | ||
BannerTemplate.initialize(self, configObj) | |||
self:setImageWidth(20) | |||
end | end | ||
function Padlock: | function Padlock:setImageAlt(alt) | ||
self._imageAlt = alt | |||
end | |||
function Padlock:setImageLink(link) | |||
self._imageLink = link | |||
end | |||
function Padlock:setRight(px) | |||
self._right = px | |||
end | |||
function Padlock:render() | |||
local root = mw.html.create('div') | |||
root | |||
:addClass('metadata topicon nopopups') | |||
:attr('id', 'protected-icon') | |||
:css{display = 'none', right = self._right or '55px'} | |||
:wikitext(self:renderImage()) | |||
return tostring(root) | |||
end | end | ||
-------------------------------------------------------------------------------- | -------------------------------------------------------------------------------- | ||
-- | -- Category class | ||
-------------------------------------------------------------------------------- | -------------------------------------------------------------------------------- | ||
local | local Category = class('Category') | ||
function Category:initialize(configObj, protectionObj) | |||
self._configObj = configObj | |||
self._protectionObj = protectionObj | |||
end | |||
function Category:setName(name) | |||
self._name = name | |||
end | |||
function | function Category:render() | ||
if self._name then | |||
return string.format( | |||
'[[%s:%s]]', | |||
mw.site.namespaces[14].name, | |||
self._name | |||
) | |||
end | |||
end | end | ||
-------------------------------------------------------------------------------- | |||
-- ProtectionCategory class | |||
-------------------------------------------------------------------------------- | |||
local ProtectionCategory = Category:subclass('ProtectionCategory') | |||
function ProtectionCategory:initialize(configObj, protectionObj, titleObj) | |||
Category.initialize(self, configObj, protectionObj) | |||
self._titleObj = titleObj | |||
end | |||
function ProtectionCategory:render() | |||
local configObj = self._configObj | |||
-- | local protectionObj = self._protectionObj | ||
if not | local titleObj = self._titleObj | ||
-- Get the level and exit if the page is not protected. | |||
if not protectionObj:isProtected() then | |||
return '' | |||
end | |||
-- | -- Get the expiry. | ||
if protectionObj: | local expiry = protectionObj:getExpiry() | ||
if type(expiry) == 'number' then | |||
expiry = 'temp' | |||
. | elseif expiry ~= 'indef' then | ||
expiry = nil | |||
end | |||
-- Get the namespace category key. | |||
local nskey | |||
do | |||
local namespace = titleObj.namespace | |||
local categoryNamespaces = configObj:getConfigTable('categoryNamespaceKeys') | |||
nskey = categoryNamespaces[namespace] | |||
if not nskey and namespace % 2 == 1 then | |||
nskey = 'talk' | |||
end | |||
end | |||
-- Get the other inputs. | |||
local reason = protectionObj:getReason() | |||
local action = protectionObj:getAction() | |||
local level = protectionObj:getLevel() | |||
--[[ | |||
-- Define the properties table. Each property is a table containing the | |||
-- canonical order that the property is tested in, the position the | |||
-- property has in the category key strings, and the property value itself. | |||
--]] | |||
local properties = { | |||
expiry = {order = 1, val = expiry}, | |||
namespace = {order = 2, val = nskey}, | |||
reason = {order = 3, val = reason}, | |||
level = {order = 4, val = level}, | |||
action = {order = 5, val = action} | |||
} | |||
--[[ | |||
-- Apply the category order configuration, if any. The configuration value | |||
-- will be a property string, e.g. 'reason', 'namespace', etc. The property | |||
-- corresponding to that string is tested last (i.e. it is the most | |||
-- important, because it keeps its specified value the longest) and the | |||
-- other properties are tested in the canonical order. If no configuration | |||
-- value is specified then the canonical order is used. | |||
--]] | |||
local configOrder = {} | |||
do | |||
local reasonsWithNamespacePriority = configObj:getConfigTable('reasonsWithNamespacePriority') | |||
local namespaceFirst = reason and reasonsWithNamespacePriority[reason] or false | |||
for propertiesKey, t in pairs(properties) do | |||
configOrder[t.order] = t | |||
end | |||
if namespaceFirst then | |||
-- Swap namespace and reason around. | |||
local namespaceTable = table.remove(configOrder, 2) | |||
table.insert(configOrder, 3, namespaceTable) | |||
end | |||
end | |||
--[[ | |||
-- Define the attempt order. Properties with no value defined are moved | |||
-- to the end, where they will later be given the value "all". This is | |||
-- to cut down on the number of table lookups in the cats table, which | |||
-- grows exponentially with the number of properties with valid values. | |||
-- We keep track of the number of active properties with the noActive | |||
-- parameter. | |||
--]] | |||
local noActive, attemptOrder | |||
do | |||
local active, inactive = {}, {} | |||
for i, t in ipairs(configOrder) do | |||
if t.val then | |||
active[#active + 1] = t | |||
else | |||
inactive[#inactive + 1] = t | |||
end | |||
end | |||
noActive = #active | |||
attemptOrder = active | |||
for i, t in ipairs(inactive) do | |||
attemptOrder[#attemptOrder + 1] = t | |||
end | |||
end | |||
--[[ | |||
-- Check increasingly generic key combinations until we find a match. | |||
-- If a specific category exists for the combination of properties | |||
-- we are given, that match will be found first. If not, we keep | |||
-- trying different key combinations until we match using the key | |||
-- "all-all-all-all-all". | |||
-- | |||
-- To generate the keys, we index the property subtables using a | |||
-- binary matrix with indexes i and j. j is only calculated up to | |||
-- the number of active properties. For example, if there were three | |||
-- active properties, the matrix would look like this, with 0 | |||
-- corresponding to the string "all", and 1 corresponding to the | |||
-- val field in the property table: | |||
-- | |||
-- j 1 2 3 | |||
-- i | |||
-- 1 1 1 1 | |||
-- 2 0 1 1 | |||
-- 3 1 0 1 | |||
-- 4 0 0 1 | |||
-- 5 1 1 0 | |||
-- 6 0 1 0 | |||
-- 7 1 0 0 | |||
-- 8 0 0 0 | |||
-- | |||
-- Values of j higher than the number of active properties are set | |||
-- to the string "all". | |||
-- | |||
-- A key for the category table is constructed for each value of i. | |||
-- The correct position of the value in the key is determined by the | |||
-- pos field in the property table. | |||
--]] | |||
local cats = configObj:getConfigTable('protectionCategories') | |||
local cat | |||
for i = 1, 2^noActive do | |||
local key = {} | |||
for j, t in ipairs(attemptOrder) do | |||
if j > noActive then | |||
key[t.order] = 'all' | |||
else | |||
local quotient = i / 2 ^ (j - 1) | |||
quotient = math.ceil(quotient) | |||
if quotient % 2 == 1 then | |||
key[t.order] = t.val | |||
else | |||
key[t.order] = 'all' | |||
end | |||
end | |||
end | |||
key = table.concat(key, '-') | |||
local attempt = cats[key] | |||
if attempt then | |||
cat = attempt | |||
break | |||
end | end | ||
end | end | ||
if cat then | |||
self:setName(cat) | |||
end | |||
return Category.render(self) | |||
end | |||
-- | -------------------------------------------------------------------------------- | ||
if | -- ExpiryCategory class | ||
-------------------------------------------------------------------------------- | |||
local ExpiryCategory = Category:subclass('ExpiryCategory') | |||
function ExpiryCategory:render() | |||
local configObj = self._configObj | |||
local protectionObj = self._protectionObj | |||
local reasonsWithoutExpiryCheck = configObj:getConfigTable('reasonsWithoutExpiryCheck') | |||
local expiryCheckActions = configObj:getConfigTable('expiryCheckActions') | |||
local expiry = protectionObj:getExpiry() | |||
local action = protectionObj:getAction() | |||
local reason = protectionObj:getReason() | |||
if not expiry | |||
and expiryCheckActions[action] | |||
and reason -- the old {{pp-protected}} didn't check for expiry | |||
and not reasonsWithoutExpiryCheck[reason] | |||
then | |||
self:setName(configObj:getMessage('tracking-category-expiry')) | |||
end | |||
return Category.render(self) | |||
end | |||
-------------------------------------------------------------------------------- | |||
-- ErrorCategory class | |||
-------------------------------------------------------------------------------- | |||
local ErrorCategory = Category:subclass('ErrorCategory') | |||
function ErrorCategory:render() | |||
local configObj = self._configObj | |||
local protectionObj = self._protectionObj | |||
local expiry = protectionObj:getExpiry() | |||
local action = protectionObj:getAction() | |||
local level = protectionObj:getLevel() | |||
if not protectionObj:isProtected() | |||
or type(expiry) == 'number' and expiry < os.time() | |||
then | |||
self:setName(configObj:getMessage('tracking-category-incorrect')) | |||
end | end | ||
return Category.render(self) | |||
end | |||
-------------------------------------------------------------------------------- | |||
-- TemplateCategory class | |||
-------------------------------------------------------------------------------- | |||
local TemplateCategory = Category:subclass('TemplateCategory') | |||
function TemplateCategory:initialize(configObj, protectionObj, titleObj) | |||
Category.initialize(self, configObj, protectionObj) | |||
self._titleObj = titleObj | |||
end | |||
function TemplateCategory:render() | |||
local configObj = self._configObj | |||
local protectionObj = self._protectionObj | |||
local titleObj = self._titleObj | |||
return | local action = protectionObj:getAction() | ||
local level = protectionObj:getLevel() | |||
local namespace = titleObj.namespace | |||
if level == 'templateeditor' | |||
and ( | |||
(action ~= 'edit' and action ~= 'move') | |||
or (namespace ~= 10 and namespace ~= 828) | |||
) | |||
then | |||
self:setName(configObj:getMessage('tracking-category-template')) | |||
end | |||
return Category.render(self) | |||
end | |||
-------------------------------------------------------------------------------- | |||
-- ProtectionBanner class | |||
-------------------------------------------------------------------------------- | |||
local ProtectionBanner = {} | |||
function ProtectionBanner.exportToWiki(frame, titleObj) | |||
mArguments = mArguments or require('Module:Arguments') | |||
local args = mArguments.getArgs(frame) | |||
return ProtectionBanner.exportToLua(args, titleObj) | |||
end | end | ||
function | function ProtectionBanner.exportToLua(args, titleObj) | ||
titleObj = titleObj or mw.title.getCurrentTitle() | |||
-- Get data objects | |||
local configObj = Config:new() | |||
local protectionObj = Protection:new(args, configObj, titleObj) | |||
-- | -- Initialise the blurb object | ||
local | local blurbObj = Blurb:new(configObj, protectionObj, titleObj) | ||
blurbObj:setDeletionDiscussionPage(args.xfd) | |||
blurbObj:setUsername(args.user) | |||
blurbObj:setSection(args.section) | |||
local ret = {} | |||
local | |||
-- | -- Render the banner | ||
if protectionObj:getLevel() ~= '*' then | |||
-- Get the banner object | |||
local isPadlock = yesno(args.small) | |||
local bannerObj | |||
if isPadlock then | |||
bannerObj = Padlock:new(configObj) | |||
else | |||
bannerObj = Banner:new(configObj) | |||
end | |||
-- Set the image fields | |||
local bannerConfig = configObj:getBannerConfig(protectionObj) | |||
bannerObj:setImageFilename(bannerConfig.image, protectionObj, titleObj) | |||
if isPadlock then | |||
bannerObj:setImageTooltip(blurbObj:makeTooltipText()) | |||
bannerObj:setImageAlt(blurbObj:makeAltText()) | |||
bannerObj:setImageLink(blurbObj:makeLinkText()) | |||
else | |||
-- Large banners use the alt text for the tooltip. | |||
bannerObj:setImageTooltip(blurbObj:makeAltText()) | |||
end | |||
-- Set the text fields | |||
if not isPadlock then | |||
bannerObj:setReasonText(blurbObj:makeReasonText()) | |||
bannerObj:setExplanationText(blurbObj:makeExplanationText()) | |||
end | |||
ret[#ret + 1] = bannerObj:render() | |||
end | end | ||
for | |||
-- Render the categories | |||
if yesno(args.category) ~= false then | |||
local objects = { | |||
ProtectionCategory:new(configObj, protectionObj, titleObj), | |||
ExpiryCategory:new(configObj, protectionObj), | |||
ErrorCategory:new(configObj, protectionObj), | |||
TemplateCategory:new(configObj, protectionObj, titleObj) | |||
} | |||
for _, obj in ipairs(objects) do | |||
ret[#ret + 1] = obj:render() | |||
end | |||
end | end | ||
return | |||
return table.concat(ret) | |||
end | |||
function ProtectionBanner._exportClasses() | |||
-- This is used to export the classes for testing purposes. | |||
return { | |||
Protection = Protection, | |||
Config = Config, | |||
Blurb = Blurb, | |||
BannerTemplate = BannerTemplate, | |||
Banner = Banner, | |||
Padlock = Padlock, | |||
Category = Category, | |||
ProtectionCategory = ProtectionCategory, | |||
ErrorCategory = ErrorCategory, | |||
ExpiryCategory = ExpiryCategory, | |||
} | |||
end | end | ||
return | return ProtectionBanner |