편집을 취소할 수 있습니다. 이 편집을 되돌리려면 아래의 바뀐 내용을 확인한 후 게시해주세요.
최신판 | 당신의 편집 | ||
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(protectionStatusObj) | |||
if self._bannerConfigTables[protectionStatusObj] then | |||
if | return self._bannerConfigTables[protectionStatusObj] | ||
else | |||
local ret = {} | |||
local cfg = self._cfg | |||
local action = protectionStatusObj:getAction() | |||
local level = protectionStatusObj:getLevel() | |||
local reason = protectionStatusObj:getReason() | |||
local fields = { | |||
'text', | |||
'explanation', | |||
'tooltip', | |||
'alt', | |||
'image', | |||
'categoryOrder', | |||
'categoryReason' | |||
} | |||
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 | |||
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[protectionStatusObj] = ret | |||
return ret | |||
end | end | ||
end | end | ||
function Config:getConfigTable(key) | |||
local blacklist = { | |||
banners = true, | |||
defaultBanners = 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 | ||
-------------------------------------------------------------------------------- | -------------------------------------------------------------------------------- | ||
-- | -- ProtectionStatus class | ||
-------------------------------------------------------------------------------- | -------------------------------------------------------------------------------- | ||
local | local ProtectionStatus = class('ProtectionStatus') | ||
function ProtectionStatus: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 | |||
self._level = level or '*' | |||
end | |||
-- Validation function for the expiry and the protection date | |||
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 expiry | -- Set expiry | ||
local | if args.expiry then | ||
local indefStrings = configObj:getConfigTable('indefStrings') | |||
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 | ||
-- Set reason | -- Set reason | ||
if args | if args.reason then | ||
self._reason = args.reason:lower() | |||
end | end | ||
-- Set protection date | -- Set protection date | ||
self._protectionDate = validateDate(args.date, 'protection date') | |||
end | end | ||
function ProtectionStatus:getAction() | |||
return self._action | |||
function | |||
return | |||
end | end | ||
function | function ProtectionStatus:getLevel() | ||
return self._level | |||
end | end | ||
function | function ProtectionStatus:getReason() | ||
return self._reason | |||
return | |||
end | end | ||
function | function ProtectionStatus:getExpiry() | ||
return self._expiry | |||
return self. | |||
end | end | ||
function | function ProtectionStatus:getProtectionDate() | ||
return self._protectionDate | |||
end | end | ||
359번째 줄: | 174번째 줄: | ||
-------------------------------------------------------------------------------- | -------------------------------------------------------------------------------- | ||
local Blurb = | local Blurb = class('Blurb') | ||
Blurb | function Blurb:initialize(configObj, protectionStatusObj, titleObj) | ||
self._configObj = configObj | |||
self._protectionStatusObj = protectionStatusObj | |||
self._bannerConfig = configObj:getBannerConfig(protectionStatusObj) | |||
self._titleObj = titleObj | |||
end | |||
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) | |||
-- Formats a Unix timestamp into dd M, YYYY format. | |||
function Blurb | |||
-- Formats a Unix timestamp into dd | |||
lang = lang or mw.language.getContentLanguage() | lang = lang or mw.language.getContentLanguage() | ||
local success, date = pcall( | local success, date = pcall( | ||
lang.formatDate, | lang.formatDate, | ||
lang, | lang, | ||
'j F Y', | |||
'@' .. tostring(num) | '@' .. tostring(num) | ||
) | ) | ||
394번째 줄: | 203번째 줄: | ||
end | end | ||
function Blurb: | function Blurb:setDeletionDiscussionPage(page) | ||
self._deletionDiscussionPage = page | |||
end | |||
function Blurb:setUsername(username) | |||
self._username = username | |||
end | |||
function Blurb:setSection(section) | |||
self._section = section | |||
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) | __index = function (t, k) | ||
local param | local param | ||
426번째 줄: | 225번째 줄: | ||
end | end | ||
param = param or '' | param = param or '' | ||
params[k] = param | |||
return param | return param | ||
end | end | ||
}) | }) | ||
parameterFuncs[1] = self._makeIntroParameter | |||
parameterFuncs[2] = self._makeUntilParameter | |||
parameterFuncs[3] = self._makeDisputesParameter | |||
parameterFuncs[4] = self._makePagetypeParameter | |||
parameterFuncs[5] = self._makeProtectionDateParameter | |||
parameterFuncs[6] = self._makeVandalTemplateParameter | |||
parameterFuncs[7] = self._makeProtectionLevelParameter | |||
parameterFuncs[8] = self._makeExpiryParameter | |||
parameterFuncs[9] = self._makeDisputeLinkParameter -- A link to the page history or the move log | |||
-- | parameterFuncs[10] = self._makeProtectionLogParameter | ||
parameterFuncs[11] = self._makeTalkLinkParameter | |||
parameterFuncs[12] = self._makeEditRequestParameter | |||
parameterFuncs[13] = self._makeRequestUnprotectionParameter | |||
parameterFuncs[14] = self._makeSubjectPageLinksParameter -- Adds links to edit requests and the talk page if we are on a subject page | |||
parameterFuncs[15] = self._makeDeletionBlurbParameter | |||
parameterFuncs[16] = self._makeDeletionDiscussionLinkParameter | |||
parameterFuncs[17] = self._makeDeletionLogParameter | |||
parameterFuncs[18] = self._makeExplanationTextParameter | |||
self._params = params | |||
end | end | ||
function | local function getParameter(match) | ||
match = tonumber(match) | |||
return self._params[match] | |||
end | end | ||
msg = msg:gsub('$([1-9][0-9]*)', getParameter) | |||
return msg | |||
end | end | ||
function Blurb: | function Blurb:_makeIntroParameter() | ||
local | -- parameter $1 | ||
if | local key | ||
local action = self._protectionStatusObj:getAction() | |||
local level = self._protectionStatusObj:getLevel() | |||
if action == 'edit' and level == 'autoconfirmed' then | |||
key = 'reason-text-semi' | |||
elseif action == 'move' then | |||
key = 'reason-text-move' | |||
elseif action == 'create' then | |||
key = 'reason-text-create' | |||
else | else | ||
key = 'reason-text-default' | |||
end | end | ||
local msg = self._configObj:getMessage(key) | |||
return self:_substituteParameters(msg) | |||
end | end | ||
function Blurb: | function Blurb:_makeUntilParameter() | ||
-- | -- parameter $2 | ||
-- "until" or "or until" depending on the expiry | |||
local expiry = self._protectionStatusObj:getExpiry() | |||
if expiry then | |||
return 'or until' | |||
local | |||
if | |||
else | else | ||
return 'until' | |||
end | end | ||
end | end | ||
function Blurb: | function Blurb:_makeDisputesParameter() | ||
-- parameter $3 | |||
local | -- "disputes", with or without a section link | ||
local | local section = self._section | ||
local disputes = self.configObj:getMessage('dispute-section-link-display') | |||
if | if section then | ||
return string.format( | |||
'[[%s:%s#%s|%s]]', | |||
mw.site.namespaces[self._titleObj.namespace].talk.name, | |||
self._titleObj.text, | |||
section, | |||
disputes | |||
) | |||
else | else | ||
return disputes | |||
end | end | ||
end | end | ||
function Blurb: | function Blurb:_makePagetypeParameter() | ||
-- parameter $4 | |||
local pagetypes = self._configObj:getConfigTable('bannerPagetypes') | |||
local namespace = self._titleObj.namespace | |||
return pagetypes[namespace] or pagetypes.default or 'page' | |||
end | end | ||
function Blurb: | function Blurb:_makeProtectionDateParameter() | ||
-- parameter $5 | |||
return | local protectionDate = self._protectionStatusObj:getProtectionDate() | ||
if type(protectionDate) == 'number' then | |||
return Blurb.formatDate(protectionDate) | |||
else | else | ||
return | return protectionDate | ||
end | end | ||
end | end | ||
function Blurb: | function Blurb:_makeVandalTemplateParameter() | ||
local | -- parameter $6 | ||
local mVandalM = require('Module:Vandal-m') | |||
local username = self._username | |||
username = username or self._titleObj.baseText | |||
return mVandalM.luaMain{username} | |||
end | end | ||
function Blurb: | function Blurb:_makeProtectionLevelParameter() | ||
-- parameter $7 | |||
local action = self. | local action = self._protectionStatusObj:getAction() | ||
local level = self. | local level = self._protectionStatusObj:getLevel() | ||
local | local key | ||
if | if action == 'edit' then | ||
if level == 'sysop' then | |||
elseif | key = 'protection-level-full' | ||
elseif level == 'templateeditor' then | |||
elseif | key = 'protection-level-template' | ||
elseif level == 'autoconfirmed' then | |||
key = 'protection-level-semi' | |||
end | |||
elseif action == 'move' then | |||
key = 'protection-level-move' | |||
elseif action == 'create' then | |||
key = 'protection-level-create' | |||
else | else | ||
key = 'protection-level-default' | |||
end | end | ||
return self: | return self._configObj:getMessage(key) | ||
end | end | ||
function Blurb: | function Blurb:_makeExpiryParameter() | ||
local | -- parameter $8 | ||
if type( | -- @TODO: Check to see if the expiry is valid. | ||
local expiry = self._protectionStatusObj:getExpiry() | |||
if expiry == 'indef' then | |||
return | return nil | ||
elseif type(expiry) == 'number' then | |||
local formatted = Blurb.formatDate(expiry) | |||
return ' until ' .. formatted | |||
elseif expiry then | |||
-- Expiry is an error string. | |||
return expiry | |||
end | end | ||
end | end | ||
function Blurb: | function Blurb:_makeDisputeLinkParameter() | ||
-- parameter $9 | |||
local action = self. | -- A link to the page history or the move log, depending on the kind of | ||
local | -- protection. | ||
local action = self._protectionStatusObj:getAction() | |||
if | local pagename = self._titleObj.prefixedText | ||
if action == 'move' then | |||
-- We need the move log link. | |||
return self.makeFullUrl( | |||
'Special:Log', | |||
{type = 'move', page = pagename}, | |||
self._configObj:getMessage('dispute-move-link-display') | |||
) | |||
else | else | ||
-- We need the history link. | |||
return self.makeFullUrl( | |||
pagename, | |||
{action = 'history'}, | |||
self._configObj:getMessage('dispute-edit-link-display') | |||
) | |||
end | end | ||
end | end | ||
function Blurb:_makeProtectionLogParameter() | function Blurb:_makeProtectionLogParameter() | ||
local pagename = self. | -- parameter $10 | ||
if | local action = self._protectionStatusObj:getAction() | ||
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}, | ||
self: | self._configObj:getMessage('more-details-pc-log-display') | ||
) | ) | ||
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: | self._configObj:getMessage('more-details-protection-log-display') | ||
) | ) | ||
end | end | ||
end | end | ||
function Blurb: | function Blurb:_makeTalkLinkParameter() | ||
return string.format( | -- parameter $11 | ||
local section = self._section | |||
local display = self._configObj:getMessage('talk-page-link-display') | |||
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: | function Blurb:_makeEditRequestParameter() | ||
-- parameter $12 | |||
local mEditRequest = require('Module:Submit an edit request') | |||
local action = self._protectionStatusObj:getAction() | |||
local level = self._protectionStatusObj:getLevel() | |||
-- Get the display message key. | |||
local key | |||
if action == 'edit' and level == 'autoconfirmed' then | |||
key = 'edit-request-semi-display' | |||
else | else | ||
return self: | key = 'edit-request-full-display' | ||
end | |||
local display = self._configObj:getMessage(key) | |||
-- Get the edit request type. | |||
local requestType | |||
if action == 'edit' then | |||
if level == 'autoconfirmed' then | |||
requestType = 'semi' | |||
elseif level == 'templateeditor' then | |||
requestType = 'template' | |||
end | |||
end | |||
requestType = requestType or 'full' | |||
return mEditRequest.exportLinkToLua{type = requestType, display = display} | |||
end | |||
function Blurb:_makeRequestUnprotectionParameter() | |||
-- parameter $13 | |||
if self._titleObj.namespace ~= 8 then | |||
-- MediaWiki pages can't be unprotected. | |||
return self._configObj:getMessage('request-unprotection-blurb') | |||
end | |||
end | |||
function Blurb:_makeSubjectPageLinksParameter() | |||
-- parameter $14 | |||
-- Don't display these links if we are on a talk page. | |||
if not self._titleObj.isTalkPage then | |||
local msg = self._configObj:getMessage('semi-subject-page-links') | |||
return self:_substituteParameters(msg) | |||
end | end | ||
end | end | ||
function Blurb: | function Blurb:_makeDeletionBlurbParameter() | ||
-- parameter $15 | |||
local deletionDiscussionPage = self._deletionDiscussionPage | |||
local key | |||
if deletionDiscussionPage then | |||
key = 'deletion-discussion-blurb-xfd' | |||
else | else | ||
key = 'deletion-discussion-blurb-noxfd' | |||
end | end | ||
local msg = self._configObj:getMessage(msg) | |||
return self._substituteParameters(msg) | |||
end | end | ||
function Blurb: | function Blurb:_makeDeletionDiscussionLinkParameter() | ||
-- parameter $16 | |||
local deletionDiscussionPage = self._deletionDiscussionPage | |||
if deletionDiscussionPage then | |||
local display = self._configObj:getMessage('deletion-discussion-link-display') | |||
return string.format('[[%s|%s]]', deletionDiscussionPage, display) | |||
end | |||
end | end | ||
-- | function Blurb:_makeDeletionLogParameter() | ||
-- parameter $17 | |||
return Blurb.makeFullUrl( | |||
'Special:Log', | |||
{type = 'delete', page = self._titleObj.prefixedText}, | |||
self._configObj:getMessage('deletion-log-link-display') | |||
) | |||
end | |||
function Blurb: | function Blurb:_makeExplanationTextParameter() | ||
-- | -- parameter $18 | ||
if | local action = self._protectionStatusObj:getAction() | ||
local level = self._protectionStatusObj:getLevel() | |||
local key | |||
if action == 'edit' and level == 'autoconfirmed' then | |||
key = 'explanation-text-semi' | |||
elseif action == 'move' then | |||
key = 'explanation-text-move' | |||
elseif action == 'create' then | |||
key = 'explanation-text-create' | |||
else | |||
key = 'explanation-text-default' | |||
end | end | ||
local msg = self._configObj:getMessage(key) | |||
return self:_substituteParameters(msg) | |||
end | |||
function Blurb:makeReasonText() | |||
local msg = self._bannerConfig.text | |||
return self:_substituteParameters(msg) | |||
end | |||
function Blurb:makeExplanationText() | |||
local msg = self._bannerConfig.explanation | |||
return self:_substituteParameters(msg) | |||
end | |||
function Blurb:makeTooltipText() | |||
local msg = self._bannerConfig.tooltip | |||
return self:_substituteParameters(msg) | |||
end | |||
function Blurb:makeAltText() | |||
local msg = self. | local msg = self._bannerConfig.alt | ||
return self:_substituteParameters(msg) | |||
end | |||
function Blurb:makeLinkText() | |||
local msg = self._bannerConfig.link | |||
return self:_substituteParameters(msg) | |||
end | end | ||
691번째 줄: | 552번째 줄: | ||
-------------------------------------------------------------------------------- | -------------------------------------------------------------------------------- | ||
local BannerTemplate = | local BannerTemplate = class('BannerTemplate') | ||
function BannerTemplate. | function BannerTemplate:initialize(configObj) | ||
self._configObj = configObj | |||
end | |||
function BannerTemplate:setImageFilename(filename, action, level, namespace, expiry) | |||
if filename then | |||
self._imageFilename = filename | |||
return nil | |||
end | |||
if not action or not level then | |||
-- If the filename is not specified, we need the action and the level | |||
-- to find the image name. The namespace and the expiry are optional, | |||
-- however. | |||
return nil | |||
end | |||
-- 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번째 줄: | 627번째 줄: | ||
-------------------------------------------------------------------------------- | -------------------------------------------------------------------------------- | ||
local Banner = | local Banner = BannerTemplate:subclass('Banner') | ||
Banner. | |||
function Banner:initialize(configObj) | |||
BannerTemplate.initialize(self, configObj) | |||
self:setImageWidth(40) | |||
end | |||
function Banner:setReasonText(s) | |||
self._reasonText = s | |||
end | |||
function Banner | function Banner:setExplanationText(s) | ||
self._explanationText = s | |||
end | end | ||
function Banner: | 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번째 줄: | 659번째 줄: | ||
) | ) | ||
} | } | ||
return | return mMessageBox.main('mbox', mbargs) | ||
end | end | ||
790번째 줄: | 666번째 줄: | ||
-------------------------------------------------------------------------------- | -------------------------------------------------------------------------------- | ||
local Padlock = | local Padlock = BannerTemplate:subclass('Padlock') | ||
Padlock. | |||
function Padlock:initialize(configObj) | |||
BannerTemplate.initialize(self, configObj) | |||
self:setImageWidth(20) | |||
end | |||
function Padlock:setImageAlt(alt) | |||
self._imageAlt = alt | |||
end | |||
function Padlock:setImageLink(link) | |||
self._imageLink = link | |||
end | |||
function Padlock | function Padlock:setRight(px) | ||
self._right = px | |||
end | end | ||
function Padlock: | function Padlock:render() | ||
local | 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 | function Category:initialize() | ||
end | |||
function Category:setName(name) | |||
self._name = name | |||
end | end | ||
function | function Category:export() | ||
if self._categoryName then | |||
return string.format( | |||
'[[%s:%s]]', | |||
mw.site.namespaces[14].name, | |||
self._categoryName | |||
) | |||
else | |||
return '' | |||
end | |||
end | |||
-------------------------------------------------------------------------------- | |||
-- ProtectionCategory class | |||
-------------------------------------------------------------------------------- | |||
local ProtectionCategory = Category:subclass('ProtectionCategory') | |||
-- If a | function ProtectionCategory:setName( | ||
-- | name, | ||
-- | configObj, | ||
protectionStatusObj, | |||
namespace | |||
) | |||
--[[ | |||
-- Sets the protection category. If a category name is not provided, this | |||
-- method gets a category name from the module config, given a combination | |||
then | -- of the protection type, the protection level, the namespace number, the | ||
-- reason for protection, and the expiry date. | |||
--]] | |||
-- If a name was provided, use that. | |||
if name then | |||
Category.setName(self, name) | |||
end | |||
-- | -- Get the namespace category key from the namespace number. | ||
if | local nskey | ||
do | |||
local categoryNamespaces = configObj:getConfigTable('categoryNamespaces') | |||
. | if not namespace or type(namespace) ~= 'number' then | ||
nskey = nil | |||
else | |||
nskey = categoryNamespaces[ns] | |||
if not nskey and ns % 2 == 1 then | |||
nskey = 'talk' | |||
end | |||
end | |||
end | |||
--[[ | |||
-- 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, keypos = 5, val = protectionStatusObj:getExpiry()}, | |||
namespace = {order = 2, keypos = 3, val = nskey}, | |||
reason = {order = 3, keypos = 4, val = protectionStatusObj:getReason()}, | |||
level = {order = 4, keypos = 2, val = protectionStatusObj:getLevel()}, | |||
action = {order = 5, keypos = 1, val = protectionStatusObj:getAction()} | |||
} | |||
--[[ | |||
-- 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 bannerConfig = configObj:getBannerConfig(protectionStatusObj) | |||
local categoryOrder = bannerConfig.categoryOrder | |||
for propertiesKey, t in pairs(properties) do | |||
configOrder[t.order] = t | |||
end | |||
if categoryOrder then | |||
local property = properties[categoryOrder] | |||
if not property then | |||
local msg = '"' | |||
.. categoryOrder | |||
.. '" is not a valid value of cfg.reasons.' | |||
.. reason | |||
.. '.categoryOrder' | |||
error(msg) | |||
end | |||
table.insert(configOrder, table.remove(configOrder, property.order)) | |||
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('categories') | |||
local cat | |||
for i = 1, 2^noActive do | |||
local key = {} | |||
for j, t in ipairs(attemptOrder) do | |||
if j > noActive then | |||
key[t.keypos] = 'all' | |||
else | |||
local quotient = i / 2 ^ (j - 1) | |||
quotient = math.ceil(quotient) | |||
if quotient % 2 == 1 then | |||
key[t.keypos] = t.val | |||
else | |||
key[t.keypos] = '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 | |||
Category.setName(self, cat) | |||
else | |||
error( | |||
'No category match found;' | |||
.. ' please define the category for key "all-all-all-all-all"' | |||
) | |||
end | |||
end | |||
-------------------------------------------------------------------------------- | |||
-- ExpiryCategory class | |||
-------------------------------------------------------------------------------- | |||
local ExpiryCategory = Category:subclass('ExpiryCategory') | |||
-------------------------------------------------------------------------------- | |||
-- ErrorCategory class | |||
-------------------------------------------------------------------------------- | |||
local ErrorCategory = Category:subclass('ErrorCategory') | |||
-------------------------------------------------------------------------------- | |||
-- ProtectionBanner class | |||
-------------------------------------------------------------------------------- | |||
local ProtectionBanner = {} | |||
function ProtectionBanner.exportToWiki(frame, titleObj) | |||
mArguments = mArguments or require('Module:Arguments') | |||
local args = mArguments.getArgs(frame) | |||
return | 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 = ProtectionStatus:new(args, configObj, titleObj) | |||
-- Initialise the blurb object | |||
local blurbObj = Blurb:new(configObj, protectionObj, titleObj) | |||
blurbObj:setDeletionDiscussionPage(args.xfd) | |||
blurbObj:setUsername(args.user) | |||
blurbObj:setSection(args.section) | |||
local ret = {} | |||
-- Render the banner | |||
do | |||
-- 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) | |||
local imageFilename = bannerConfig.image | |||
bannerObj:setImageFilename( | |||
imageFilename, | |||
protectionObj:getAction(), | |||
protectionObj:getLevel(), | |||
titleObj.namespace, | |||
protectionObj:getExpiry() | |||
) | |||
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 | ||
-- Render the categories | |||
return | return table.concat(ret) | ||
end | |||
function ProtectionBanner._exportClasses() | |||
-- This is used to export the classes for testing purposes. | |||
return { | |||
ProtectionStatus = ProtectionStatus, | |||
Config = Config, | |||
Blurb = Blurb, | |||
BannerTemplate = BannerTemplate, | |||
Banner = Banner, | |||
Padlock = Padlock, | |||
Category = Category, | |||
ProtectionCategory = ProtectionCategory, | |||
ErrorCategory = ErrorCategory, | |||
ExpiryCategory = ExpiryCategory, | |||
} | |||
end | end | ||
return | return ProtectionBanner |