편집을 취소할 수 있습니다. 이 편집을 되돌리려면 아래의 바뀐 내용을 확인한 후 게시해주세요.
최신판 | 당신의 편집 | ||
4번째 줄: | 4번째 줄: | ||
-- Initialise necessary modules. | -- Initialise necessary modules. | ||
require('Module:No globals') | require('Module:No globals') | ||
local | local class = require('Module:Middleclass').class | ||
local newFileLink = require('Module:File link').new | |||
local effectiveProtectionLevel = require('Module:Effective protection level')._main | local effectiveProtectionLevel = require('Module:Effective protection level')._main | ||
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 getArgs, makeMessageBox, lang | local getArgs, makeMessageBox, lang | ||
-------------------------------------------------------------------------------- | -------------------------------------------------------------------------------- | ||
19번째 줄: | 16번째 줄: | ||
-------------------------------------------------------------------------------- | -------------------------------------------------------------------------------- | ||
local function makeCategoryLink(cat | local function makeCategoryLink(cat) | ||
if cat then | if cat then | ||
return string.format( | return string.format( | ||
'[[%s: | '[[%s:%s]]', | ||
mw.site.namespaces[14].name, | mw.site.namespaces[14].name, | ||
cat | cat | ||
) | ) | ||
else | |||
return '' | |||
end | end | ||
end | end | ||
32번째 줄: | 30번째 줄: | ||
-- Validation function for the expiry and the protection date | -- Validation function for the expiry and the protection date | ||
local function validateDate(dateString, dateType) | local function validateDate(dateString, dateType) | ||
lang = lang or mw.language.getContentLanguage() | |||
local success, result = pcall(lang.formatDate, lang, 'U', dateString) | local success, result = pcall(lang.formatDate, lang, 'U', dateString) | ||
if success then | if success then | ||
43번째 줄: | 39번째 줄: | ||
end | end | ||
error(string.format( | error(string.format( | ||
'invalid %s | 'invalid %s ("%s")', | ||
dateType, | dateType, | ||
tostring(dateString) | tostring(dateString) | ||
), | ), 0) | ||
end | end | ||
57번째 줄: | 53번째 줄: | ||
end | end | ||
local function toTableEnd(t, pos) | |||
-- Sends the value at position pos to the end of array t, and shifts the | |||
-- other items down accordingly. | |||
local function | return table.insert(t, table.remove(t, pos)) | ||
end | end | ||
82번째 줄: | 63번째 줄: | ||
-------------------------------------------------------------------------------- | -------------------------------------------------------------------------------- | ||
local Protection = | local Protection = class('Protection') | ||
Protection.supportedActions = { | Protection.supportedActions = { | ||
edit = true, | edit = true, | ||
move = true, | move = true, | ||
autoreview | autoreview = true | ||
} | } | ||
101번째 줄: | 80번째 줄: | ||
} | } | ||
function Protection | function Protection:initialize(args, cfg, title) | ||
self._cfg = cfg | |||
self.title = title or mw.title.getCurrentTitle() | |||
-- Set action | -- Set action | ||
if not args.action then | if not args.action then | ||
self.action = 'edit' | |||
elseif | elseif self.supportedActions[args.action] then | ||
self.action = args.action | |||
else | else | ||
error(string.format( | error(string.format( | ||
'invalid action | 'invalid action ("%s")', | ||
tostring(args.action) | tostring(args.action) | ||
), | ), 0) | ||
end | end | ||
-- Set level | -- Set level | ||
self.level = effectiveProtectionLevel(self.action, self.title) | |||
if not | if self.level == 'accountcreator' then | ||
-- Lump titleblacklisted pages in with template-protected pages, | |||
-- since templateeditors can do both. | |||
self.level = 'templateeditor' | |||
elseif not self.level or (self.action == 'move' and self.level == 'autoconfirmed') then | |||
-- Users need to be autoconfirmed to move pages anyway, so treat | -- Users need to be autoconfirmed to move pages anyway, so treat | ||
-- semi-move-protected pages as unprotected. | -- semi-move-protected pages as unprotected. | ||
self.level = '*' | |||
end | end | ||
-- Set expiry | -- Set expiry | ||
if args.expiry then | |||
if cfg.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[1] then | if args[1] then | ||
self.reason = mw.ustring.lower(args[1]) | |||
if | if self.reason:find('|') then | ||
error('reasons cannot contain the pipe character ("|")', | error('reasons cannot contain the pipe character ("|")', 0) | ||
end | end | ||
end | end | ||
144번째 줄: | 129번째 줄: | ||
-- Set protection date | -- Set protection date | ||
if args.date then | if args.date then | ||
self.protectionDate = validateDate(args.date, 'protection date') | |||
end | end | ||
-- Set banner config | -- Set banner config | ||
do | do | ||
self.bannerConfig = {} | |||
local configTables = {} | local configTables = {} | ||
if cfg.banners[ | if cfg.banners[self.action] then | ||
configTables[#configTables + 1] = cfg.banners[ | configTables[#configTables + 1] = cfg.banners[self.action][self.reason] | ||
end | end | ||
if cfg.defaultBanners[ | if cfg.defaultBanners[self.action] then | ||
configTables[#configTables + 1] = cfg.defaultBanners[ | configTables[#configTables + 1] = cfg.defaultBanners[self.action][self.level] | ||
configTables[#configTables + 1] = cfg.defaultBanners[ | configTables[#configTables + 1] = cfg.defaultBanners[self.action].default | ||
end | end | ||
configTables[#configTables + 1] = cfg.masterBanner | configTables[#configTables + 1] = cfg.masterBanner | ||
for i, field in ipairs( | for i, field in ipairs(self.bannerConfigFields) do | ||
for j, t in ipairs(configTables) do | for j, t in ipairs(configTables) do | ||
if t[field] then | if t[field] then | ||
self.bannerConfig[field] = t[field] | |||
break | break | ||
end | end | ||
168번째 줄: | 153번째 줄: | ||
end | end | ||
end | end | ||
end | end | ||
182번째 줄: | 158번째 줄: | ||
return self.level ~= '*' | return self.level ~= '*' | ||
end | end | ||
function Protection:isTemporary() | function Protection:isTemporary() | ||
196번째 줄: | 164번째 줄: | ||
function Protection:makeProtectionCategory() | function Protection:makeProtectionCategory() | ||
if not self: | local cfg = self._cfg | ||
local title = self.title | |||
-- Exit if the page is not protected. | |||
if not self:isProtected() then | |||
return '' | return '' | ||
end | end | ||
-- Get the expiry key fragment. | -- Get the expiry key fragment. | ||
212번째 줄: | 181번째 줄: | ||
-- Get the namespace key fragment. | -- Get the namespace key fragment. | ||
local namespaceFragment = cfg.categoryNamespaceKeys[title.namespace] | local namespaceFragment | ||
do | |||
namespaceFragment = cfg.categoryNamespaceKeys[title.namespace] | |||
if not namespaceFragment and title.namespace % 2 == 1 then | |||
namespaceFragment = 'talk' | |||
end | |||
end | end | ||
-- Define the order that key fragments are tested in. This is done with an | -- Define the order that key fragments are tested in. This is done with an | ||
-- array of tables containing the value to be tested, along with its | -- array of tables containing the value to be tested, along with its | ||
239번째 줄: | 211번째 줄: | ||
-- instead. | -- instead. | ||
--]] | --]] | ||
table.insert(order, table.remove(order, | if self.reason and cfg.reasonsWithNamespacePriority[self.reason] then | ||
-- table.insert(order, 3, table.remove(order, 2)) | |||
toTableEnd(order, 2) | |||
else | |||
toTableEnd(order, 3) | |||
end | |||
--[[ | --[[ | ||
316번째 줄: | 293번째 줄: | ||
local attempt = cats[key] | local attempt = cats[key] | ||
if attempt then | if attempt then | ||
return makeCategoryLink(attempt | return makeCategoryLink(attempt) | ||
end | end | ||
end | end | ||
return '' | return '' | ||
end | |||
function Protection:needsExpiry() | |||
local cfg = self._cfg | |||
return not self.expiry | |||
and cfg.expiryCheckActions[self.action] | |||
and self.reason -- the old {{pp-protected}} didn't check for expiry | |||
and not cfg.reasonsWithoutExpiryCheck[self.reason] | |||
end | end | ||
function Protection:isIncorrect() | function Protection:isIncorrect() | ||
local expiry = self.expiry | local expiry = self.expiry | ||
return not self: | return not self:isProtected() | ||
or type(expiry) == 'number' and expiry < os.time() | or type(expiry) == 'number' and expiry < os.time() | ||
end | end | ||
339번째 줄: | 324번째 줄: | ||
function Protection:makeCategoryLinks() | function Protection:makeCategoryLinks() | ||
local msg = self._cfg.msg | local msg = self._cfg.msg | ||
local ret = {self:makeProtectionCategory()} | local ret = { self:makeProtectionCategory() } | ||
if self:needsExpiry() then | |||
ret[#ret + 1] = makeCategoryLink(msg['tracking-category-expiry']) | |||
end | |||
if self:isIncorrect() then | if self:isIncorrect() then | ||
ret[#ret + 1] = makeCategoryLink( | ret[#ret + 1] = makeCategoryLink(msg['tracking-category-incorrect']) | ||
end | end | ||
if self:isTemplateProtectedNonTemplate() then | if self:isTemplateProtectedNonTemplate() then | ||
ret[#ret + 1] = makeCategoryLink( | ret[#ret + 1] = makeCategoryLink(msg['tracking-category-template']) | ||
end | end | ||
return table.concat(ret) | return table.concat(ret) | ||
359번째 줄: | 341번째 줄: | ||
-------------------------------------------------------------------------------- | -------------------------------------------------------------------------------- | ||
local Blurb = | local Blurb = class('Blurb') | ||
Blurb.bannerTextFields = { | Blurb.bannerTextFields = { | ||
370번째 줄: | 351번째 줄: | ||
} | } | ||
function Blurb | function Blurb:initialize(protectionObj, args, cfg) | ||
self._cfg = cfg | |||
self._protectionObj = protectionObj | |||
self._args = args | |||
end | end | ||
408번째 줄: | 387번째 줄: | ||
parameterFuncs.IMAGELINK = self._makeImageLinkParameter | parameterFuncs.IMAGELINK = self._makeImageLinkParameter | ||
parameterFuncs.INTROBLURB = self._makeIntroBlurbParameter | parameterFuncs.INTROBLURB = self._makeIntroBlurbParameter | ||
parameterFuncs.PAGETYPE = self._makePagetypeParameter | parameterFuncs.PAGETYPE = self._makePagetypeParameter | ||
parameterFuncs.PROTECTIONBLURB = self._makeProtectionBlurbParameter | parameterFuncs.PROTECTIONBLURB = self._makeProtectionBlurbParameter | ||
416번째 줄: | 394번째 줄: | ||
parameterFuncs.TALKPAGE = self._makeTalkPageParameter | parameterFuncs.TALKPAGE = self._makeTalkPageParameter | ||
parameterFuncs.TOOLTIPBLURB = self._makeTooltipBlurbParameter | parameterFuncs.TOOLTIPBLURB = self._makeTooltipBlurbParameter | ||
parameterFuncs.VANDAL = self._makeVandalTemplateParameter | parameterFuncs.VANDAL = self._makeVandalTemplateParameter | ||
467번째 줄: | 444번째 줄: | ||
if level == 'autoconfirmed' then | if level == 'autoconfirmed' then | ||
requestType = 'semi' | requestType = 'semi' | ||
elseif level == 'templateeditor' then | elseif level == 'templateeditor' then | ||
requestType = 'template' | requestType = 'template' | ||
520번째 줄: | 495번째 줄: | ||
level, | level, | ||
talkKey | talkKey | ||
) | )) | ||
end | end | ||
return self:_substituteParameters(msg) | return self:_substituteParameters(msg) | ||
545번째 줄: | 520번째 줄: | ||
else | else | ||
return self:_getExpandedMessage('intro-blurb-noexpiry') | return self:_getExpandedMessage('intro-blurb-noexpiry') | ||
end | end | ||
end | end | ||
560번째 줄: | 527번째 줄: | ||
return pagetypes[self._protectionObj.title.namespace] | return pagetypes[self._protectionObj.title.namespace] | ||
or pagetypes.default | or pagetypes.default | ||
or error('no default pagetype defined' | or error('no default pagetype defined') | ||
end | end | ||
575번째 줄: | 542번째 줄: | ||
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 protectionBlurbs.edit.default') | ||
end | end | ||
return self:_substituteParameters(msg) | return self:_substituteParameters(msg) | ||
601번째 줄: | 568번째 줄: | ||
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 protectionLevels.edit.default') | ||
end | end | ||
return self:_substituteParameters(msg) | return self:_substituteParameters(msg) | ||
640번째 줄: | 607번째 줄: | ||
else | else | ||
return self:_getExpandedMessage('tooltip-blurb-noexpiry') | return self:_getExpandedMessage('tooltip-blurb-noexpiry') | ||
end | end | ||
end | end | ||
function Blurb:_makeVandalTemplateParameter() | function Blurb:_makeVandalTemplateParameter() | ||
return | return require('Module:Vandal-m')._main{ | ||
self._args.user or self._protectionObj.title.baseText | |||
} | } | ||
end | end | ||
681번째 줄: | 639번째 줄: | ||
tostring(key), | tostring(key), | ||
type(msg) | type(msg) | ||
) | )) | ||
end | end | ||
return self:_substituteParameters(msg) | return self:_substituteParameters(msg) | ||
691번째 줄: | 649번째 줄: | ||
-------------------------------------------------------------------------------- | -------------------------------------------------------------------------------- | ||
local BannerTemplate = | local BannerTemplate = class('BannerTemplate') | ||
function BannerTemplate | function BannerTemplate:initialize(protectionObj, cfg) | ||
self._cfg = cfg | |||
-- Set the image filename. | -- Set the image filename. | ||
local imageFilename = protectionObj.bannerConfig.image | local imageFilename = protectionObj.bannerConfig.image | ||
if imageFilename then | if imageFilename then | ||
self._imageFilename = imageFilename | |||
else | else | ||
-- If an image filename isn't specified explicitly in the banner config, | -- If an image filename isn't specified explicitly in the banner config, | ||
708번째 줄: | 664번째 줄: | ||
local level = protectionObj.level | local level = protectionObj.level | ||
local namespace = protectionObj.title.namespace | local namespace = protectionObj.title.namespace | ||
-- Deal with special cases first. | -- Deal with special cases first. | ||
if ( | if (namespace == 10 or namespace == 828) | ||
and action == 'edit' | and action == 'edit' | ||
and level == 'sysop' | and level == 'sysop' | ||
722번째 줄: | 673번째 줄: | ||
-- Fully protected modules and templates get the special red "indef" | -- Fully protected modules and templates get the special red "indef" | ||
-- padlock. | -- padlock. | ||
self._imageFilename = self._cfg.msg['image-filename-indef'] | |||
else | else | ||
-- Deal with regular protection types. | -- Deal with regular protection types. | ||
local images = | local images = self._cfg.images | ||
if images[action] then | if images[action] then | ||
if images[action][level] then | if images[action][level] then | ||
self._imageFilename = images[action][level] | |||
elseif images[action].default then | elseif images[action].default then | ||
self._imageFilename = images[action].default | |||
end | end | ||
end | end | ||
end | end | ||
end | end | ||
end | |||
function BannerTemplate:setImageWidth(width) | |||
self._imageWidth = width | |||
end | |||
function BannerTemplate:setImageTooltip(tooltip) | |||
self._imageCaption = tooltip | |||
end | end | ||
742번째 줄: | 700번째 줄: | ||
or self._cfg.msg['image-filename-default'] | or self._cfg.msg['image-filename-default'] | ||
or 'Transparent.gif' | or 'Transparent.gif' | ||
return | return newFileLink(filename) | ||
:width(self._imageWidth or 20) | |||
:alt(self._imageAlt) | |||
alt | :link(self._imageLink) | ||
link | :caption(self._imageCaption) | ||
caption | :render() | ||
end | end | ||
755번째 줄: | 712번째 줄: | ||
-------------------------------------------------------------------------------- | -------------------------------------------------------------------------------- | ||
local Banner = | local Banner = BannerTemplate:subclass('Banner') | ||
function Banner | function Banner:initialize(protectionObj, blurbObj, cfg) | ||
BannerTemplate.initialize(self, protectionObj, cfg) -- This doesn't need the blurb. | |||
self:setImageWidth(40) | |||
self:setImageTooltip(blurbObj:makeBannerText('alt')) -- Large banners use the alt text for the tooltip. | |||
self._reasonText = blurbObj:makeBannerText('text') | |||
self._explanationText = blurbObj:makeBannerText('explanation') | |||
self._page = protectionObj.title.prefixedText -- Only makes a difference in testing. | |||
end | end | ||
771번째 줄: | 726번째 줄: | ||
-- Renders the banner. | -- Renders the banner. | ||
makeMessageBox = makeMessageBox or require('Module:Message box').main | makeMessageBox = makeMessageBox or require('Module:Message box').main | ||
local reasonText = self._reasonText or error('no reason text set' | local reasonText = self._reasonText or error('no reason text set') | ||
local explanationText = self._explanationText | local explanationText = self._explanationText | ||
local mbargs = { | local mbargs = { | ||
790번째 줄: | 745번째 줄: | ||
-------------------------------------------------------------------------------- | -------------------------------------------------------------------------------- | ||
local Padlock = | local Padlock = BannerTemplate:subclass('Padlock') | ||
function Padlock | function Padlock:initialize(protectionObj, blurbObj, cfg) | ||
BannerTemplate.initialize(self, protectionObj, cfg) -- This doesn't need the blurb. | |||
self:setImageWidth(20) | |||
self:setImageTooltip(blurbObj:makeBannerText('tooltip')) | |||
self._imageAlt = blurbObj:makeBannerText('alt') | |||
self._imageLink = blurbObj:makeBannerText('link') | |||
self._right = cfg.padlockPositions[protectionObj.action] | |||
or cfg. | or cfg.padlockPositions.default | ||
or ' | or '55px' | ||
end | end | ||
function Padlock:__tostring() | function Padlock:__tostring() | ||
local | local root = mw.html.create('div') | ||
root | |||
:addClass('metadata topicon nopopups') | |||
:attr('id', 'protected-icon') | |||
:css{display = 'none', right = self._right} | |||
:wikitext(self:renderImage()) | |||
return tostring(root) | |||
end | end | ||
834번째 줄: | 787번째 줄: | ||
function p._main(args, cfg, title) | function p._main(args, cfg, title) | ||
args = args or {} | args = args or {} | ||
cfg = cfg or require( | cfg = cfg or require('Module:Protection banner/config') | ||
local protectionObj = Protection.new(args, cfg, title) | -- Initialise the protection object and check for errors | ||
local protectionObjCreated, protectionObj = pcall( | |||
Protection.new, Protection, -- equivalent to Protection:new() | |||
args, | |||
cfg, | |||
title | |||
) | |||
if not protectionObjCreated then | |||
local errorBlurb = cfg.msg['error-message-blurb'] or 'Error: $1.' | |||
local errorText = mw.message.newRawMessage(errorBlurb) | |||
:params(protectionObj) -- protectionObj is the error message | |||
:plain() | |||
return string.format( | |||
'<strong class="error">%s</strong>%s', | |||
errorText, | |||
makeCategoryLink(cfg.msg['tracking-category-incorrect']) | |||
) | |||
end | |||
-- Initialise the blurb object | |||
local blurbObj = Blurb:new(protectionObj, args, cfg) | |||
local ret = {} | local ret = {} | ||
-- | -- Render the banner | ||
if protectionObj:isProtected() then | |||
ret[#ret + 1] = tostring( | |||
if | (yesno(args.small) and Padlock or Banner) | ||
:new(protectionObj, blurbObj, cfg) | |||
) | |||
end | |||
-- Render the categories | -- Render the categories | ||
if yesno(args.category) ~= false then | if yesno(args.category) ~= false then | ||
871번째 줄: | 830번째 줄: | ||
function p.main(frame, cfg) | function p.main(frame, cfg) | ||
getArgs = getArgs or require('Module:Arguments').getArgs | getArgs = getArgs or require('Module:Arguments').getArgs | ||
local | cfg = cfg or require('Module:Protection banner/config') | ||
local parentTitle = frame:getParent():getTitle() | |||
parentTitle = parentTitle:gsub('/sandbox$', '') | |||
local defaultArgs = cfg.wrappers[parentTitle] or {} | |||
local args = getArgs(frame, {parentOnly = defaultArgs and true}) | |||
for k, v in pairs(defaultArgs) do | |||
local args = { | |||
for k, v in pairs( | |||
args[k] = v | args[k] = v | ||
end | end |