en>Mr. Stradivarius |
en>Ruslik0 |
Line 1: |
Line 1: |
| -- This module implements {{pp-meta}} and its daughter templates such as
| | <tt><nowiki>|</nowiki>{{#if:{{{1|}}}|{{{1}}}<nowiki>=</nowiki>|}}{{{2|}}}</tt><noinclude> |
| -- {{pp-dispute}}, {{pp-vandalism}} and {{pp-sock}}.
| | {{Documentation}} |
| | | {{pp-template|small=yes}} |
| -- Initialise necessary modules.
| | <!--Categories and interwikis go near the bottom of the /doc subpage.--> |
| require('Module:No globals')
| | </noinclude> |
| local class = require('Module:Middleclass').class
| |
| local newFileLink = require('Module:File link').new
| |
| local effectiveProtectionLevel = require('Module:Effective protection level')._main
| |
| local yesno = require('Module:Yesno')
| |
| | |
| -- Lazily initialise modules and objects we don't always need.
| |
| local mArguments, mMessageBox, lang
| |
| | |
| --------------------------------------------------------------------------------
| |
| -- Config class
| |
| --------------------------------------------------------------------------------
| |
| | |
| 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
| |
| | |
| function Config:getBannerConfig(protectionObj)
| |
| if self._bannerConfigTables[protectionObj] then
| |
| return self._bannerConfigTables[protectionObj]
| |
| else
| |
| local ret = {}
| |
| local cfg = self._cfg
| |
| local action = protectionObj.action
| |
| local level = protectionObj.level
| |
| local reason = protectionObj.reason
| |
| local fields = {
| |
| 'text',
| |
| 'explanation',
| |
| 'tooltip',
| |
| 'alt',
| |
| 'link',
| |
| '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
| |
| self._bannerConfigTables[protectionObj] = ret
| |
| return ret
| |
| 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
| |
| | |
| function Config:getMessage(key)
| |
| return self._msg[key]
| |
| end
| |
| | |
| --------------------------------------------------------------------------------
| |
| -- Protection class
| |
| --------------------------------------------------------------------------------
| |
| | |
| local Protection = class('Protection')
| |
| | |
| function Protection:initialize(args, configObj, titleObj)
| |
| -- 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
| |
| | |
| -- Set level
| |
| do
| |
| local level = effectiveProtectionLevel(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
| |
| | |
| -- 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
| |
| | |
| -- Set expiry
| |
| 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
| |
| | |
| -- Set reason
| |
| do
| |
| local reason = args.reason or args[1]
| |
| if reason then
| |
| self.reason = reason:lower()
| |
| end
| |
| end
| |
| | |
| -- Set protection date
| |
| self.protectionDate = validateDate(args.date, 'protection date')
| |
| end
| |
| | |
| function Protection:isProtected()
| |
| return self._level ~= '*'
| |
| end
| |
| | |
| --------------------------------------------------------------------------------
| |
| -- Blurb class
| |
| --------------------------------------------------------------------------------
| |
| | |
| local Blurb = class('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.makeFullUrl(page, query, display)
| |
| local url = mw.uri.fullUrl(page, query)
| |
| url = tostring(url)
| |
| return string.format('[%s %s]', url, display)
| |
| end
| |
| | |
| function Blurb.formatDate(num)
| |
| -- Formats a Unix timestamp into dd Month, YYYY format.
| |
| lang = lang or mw.language.getContentLanguage()
| |
| local success, date = pcall(
| |
| lang.formatDate,
| |
| lang,
| |
| 'j F Y',
| |
| '@' .. tostring(num)
| |
| )
| |
| if success then
| |
| return date
| |
| end
| |
| end
| |
| | |
| -- Private methods --
| |
| | |
| function Blurb:_getExpandedMessage(msg)
| |
| local msg = self._configObj:getMessage(msg)
| |
| return self:_substituteParameters(msg)
| |
| end
| |
| | |
| function Blurb:_substituteParameters(msg)
| |
| if not self._params then
| |
| 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.DELETIONDISCUSSION = self._makeDeletionDiscussionParameter
| |
| parameterFuncs.DISPUTEBLURB = self._makeDisputeBlurbParameter
| |
| parameterFuncs.DISPUTESECTION = self._makeDisputeSectionParameter
| |
| parameterFuncs.EDITREQUEST = self._makeEditRequestParameter
| |
| parameterFuncs.EXPIRY = self._makeExpiryParameter
| |
| parameterFuncs.EXPLANATIONBLURB = self._makeExplanationBlurbParameter
| |
| parameterFuncs.IMAGELINK = self._makeImageLinkParameter
| |
| parameterFuncs.INTROBLURB = self._makeIntroBlurbParameter
| |
| parameterFuncs.OFFICEBLURB = self._makeOfficeBlurbParameter
| |
| parameterFuncs.PAGETYPE = self._makePagetypeParameter
| |
| parameterFuncs.PROTECTIONBLURB = self._makeProtectionBlurbParameter
| |
| parameterFuncs.PROTECTIONDATE = self._makeProtectionDateParameter
| |
| parameterFuncs.PROTECTIONLEVEL = self._makeProtectionLevelParameter
| |
| parameterFuncs.PROTECTIONLOG = self._makeProtectionLogParameter
| |
| parameterFuncs.RESETBLURB = self._makeResetBlurbParameter
| |
| parameterFuncs.TALKPAGE = self._makeTalkPageParameter
| |
| parameterFuncs.TOOLTIPBLURB = self._makeTooltipBlurbParameter
| |
| parameterFuncs.VANDAL = self._makeVandalTemplateParameter
| |
|
| |
| self._params = params
| |
| end
| |
|
| |
| msg = msg:gsub('${(%u+)}', self._params)
| |
| return msg
| |
| end
| |
| | |
| function Blurb:_makeCurrentVersionParameter()
| |
| -- A link to the page history or the move log, depending on the kind of
| |
| -- protection.
| |
| local action = self._protectionObj.action
| |
| 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:_getExpandedMessage('current-version-move-display')
| |
| )
| |
| else
| |
| -- We need the history link.
| |
| return self.makeFullUrl(
| |
| pagename,
| |
| {action = 'history'},
| |
| 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.expiry
| |
| 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
| |
| | |
| function Blurb:_makeEditRequestParameter()
| |
| local mEditRequest = require('Module:Submit an edit request')
| |
| local action = self._protectionObj.action
| |
| local level = self._protectionObj.level
| |
|
| |
| -- 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.
| |
| 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:_makeExpiryParameter()
| |
| local expiry = self._protectionObj.expiry
| |
| if expiry == 'indef' then
| |
| return nil
| |
| elseif type(expiry) == 'number' then
| |
| return Blurb.formatDate(expiry)
| |
| elseif expiry then
| |
| -- Expiry is an error string.
| |
| return expiry
| |
| end
| |
| end
| |
| | |
| function Blurb:_makeExplanationBlurbParameter()
| |
| local action = self._protectionObj.action
| |
| local level = self._protectionObj.level
| |
| 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
| |
| 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
| |
| key = 'explanation-blurb-create-noxfd'
| |
| end
| |
| else
| |
| key = 'explanation-blurb-default'
| |
| end
| |
| return self:_getExpandedMessage(key)
| |
| end
| |
| | |
| function Blurb:_makeImageLinkParameter()
| |
| local imageLinks = self._configObj:getConfigTable('imageLinks')
| |
| local action = self._protectionObj.action
| |
| local level = self._protectionObj.level
| |
| local msg
| |
| if imageLinks[action][level] then
| |
| msg = imageLinks[action][level]
| |
| elseif imageLinks[action].default then
| |
| msg = imageLinks[action].default
| |
| else
| |
| msg = imageLinks.edit.default
| |
| end
| |
| return self:_substituteParameters(msg)
| |
| end
| |
| | |
| function Blurb:_makeIntroBlurbParameter()
| |
| local expiry = self._protectionObj.expiry
| |
| if type(expiry) == 'number' then
| |
| return self:_getExpandedMessage('intro-blurb-expiry')
| |
| else
| |
| return self:_getExpandedMessage('intro-blurb-noexpiry')
| |
| end
| |
| end
| |
| | |
| function Blurb:_makeOfficeBlurbParameter()
| |
| local protectionDate = self._protectionObj.protectionDate
| |
| if protectionDate then
| |
| return self:_getExpandedMessage('office-blurb-protectiondate')
| |
| else
| |
| return self:_getExpandedMessage('office-blurb-noprotectiondate')
| |
| end
| |
| end
| |
| | |
| function Blurb:_makePagetypeParameter()
| |
| local pagetypes = self._configObj:getConfigTable('pagetypes')
| |
| local namespace = self._titleObj.namespace
| |
| return pagetypes[namespace] or pagetypes.default or error('no default pagetype defined')
| |
| end
| |
| | |
| function Blurb:_makeProtectionBlurbParameter()
| |
| local protectionBlurbs = self._configObj:getConfigTable('protectionBlurbs')
| |
| local action = self._protectionObj.action
| |
| local level = self._protectionObj.level
| |
| local msg
| |
| if protectionBlurbs[action][level] then
| |
| msg = protectionBlurbs[action][level]
| |
| elseif protectionBlurbs[action].default then
| |
| msg = protectionBlurbs[action].default
| |
| elseif protectionBlurbs.edit.default then
| |
| msg = protectionBlurbs.edit.default
| |
| else
| |
| error('no protection blurb defined for cfg.protectionBlurbs.edit.default')
| |
| end
| |
| return self:_substituteParameters(msg)
| |
| end
| |
| | |
| function Blurb:_makeProtectionDateParameter()
| |
| local protectionDate = self._protectionObj.protectionDate
| |
| if type(protectionDate) == 'number' then
| |
| return Blurb.formatDate(protectionDate)
| |
| else
| |
| return protectionDate
| |
| end
| |
| end
| |
| | |
| function Blurb:_makeProtectionLevelParameter()
| |
| local protectionLevels = self._configObj:getConfigTable('protectionLevels')
| |
| local action = self._protectionObj.action
| |
| local level = self._protectionObj.level
| |
| local msg
| |
| if protectionLevels[action][level] then
| |
| msg = protectionLevels[action][level]
| |
| elseif protectionLevels[action].default then
| |
| msg = protectionLevels[action].default
| |
| elseif protectionLevels.edit.default then
| |
| msg = protectionLevels.edit.default
| |
| else
| |
| error('no protection level defined for cfg.protectionLevels.edit.default')
| |
| end
| |
| return self:_substituteParameters(msg)
| |
| end
| |
| | |
| function Blurb:_makeProtectionLogParameter()
| |
| local action = self._protectionObj.action
| |
| local pagename = self._titleObj.prefixedText
| |
| if action == 'autoreview' then
| |
| -- We need the pending changes log.
| |
| return self.makeFullUrl(
| |
| 'Special:Log',
| |
| {type = 'stable', page = pagename},
| |
| self:_getExpandedMessage('pc-log-display')
| |
| )
| |
| else
| |
| -- We need the protection log.
| |
| return self.makeFullUrl(
| |
| 'Special:Log',
| |
| {type = 'protect', page = pagename},
| |
| self:_getExpandedMessage('protection-log-display')
| |
| )
| |
| end
| |
| end
| |
| | |
| function Blurb:_makeResetBlurbParameter()
| |
| local protectionDate = self._protectionObj.protectionDate
| |
| if protectionDate then
| |
| return self:_getExpandedMessage('reset-blurb-protectiondate')
| |
| else
| |
| return self:_getExpandedMessage('reset-blurb-noprotectiondate')
| |
| end
| |
| end
| |
| | |
| function Blurb:_makeTalkPageParameter()
| |
| local section = self._section
| |
| local display = self:_getExpandedMessage('talk-page-link-display')
| |
| return string.format(
| |
| '[[%s:%s#%s|%s]]',
| |
| mw.site.namespaces[self._titleObj.namespace].talk.name,
| |
| self._titleObj.text,
| |
| section or 'top',
| |
| display
| |
| )
| |
| end
| |
| | |
| function Blurb:_makeTooltipBlurbParameter()
| |
| local expiry = self._protectionObj.expiry
| |
| if type(expiry) == 'number' then
| |
| return self:_getExpandedMessage('tooltip-blurb-expiry')
| |
| else
| |
| return self:_getExpandedMessage('tooltip-blurb-noexpiry')
| |
| end
| |
| end
| |
| | |
| 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
| |
| if msg then
| |
| return self:_substituteParameters(msg)
| |
| end
| |
| 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._bannerConfig.alt
| |
| return self:_substituteParameters(msg)
| |
| end
| |
| | |
| function Blurb:makeLinkText()
| |
| local msg = self._bannerConfig.link
| |
| return self:_substituteParameters(msg)
| |
| end
| |
| | |
| --------------------------------------------------------------------------------
| |
| -- BannerTemplate class
| |
| --------------------------------------------------------------------------------
| |
| | |
| local BannerTemplate = class('BannerTemplate')
| |
| | |
| function BannerTemplate:initialize(configObj)
| |
| self._configObj = configObj
| |
| end
| |
| | |
| function BannerTemplate:setImageFilename(filename, protectionObj, titleObj)
| |
| if filename then
| |
| self._imageFilename = filename
| |
| return nil
| |
| end
| |
| | |
| local action = protectionObj.action
| |
| local level = protectionObj.level
| |
| local expiry = protectionObj.expiry
| |
| 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
| |
| | |
| return nil
| |
| end
| |
| | |
| function BannerTemplate:setImageWidth(width)
| |
| self._imageWidth = width
| |
| end
| |
| | |
| function BannerTemplate:setImageTooltip(tooltip)
| |
| self._imageCaption = tooltip
| |
| end
| |
| | |
| function BannerTemplate:renderImage()
| |
| local filename = self._imageFilename
| |
| or self._configObj:getMessage('image-filename-default')
| |
| or 'Transparent.gif'
| |
| return newFileLink(filename)
| |
| :width(self._imageWidth or 20)
| |
| :alt(self._imageAlt)
| |
| :link(self._imageLink)
| |
| :caption(self._imageCaption)
| |
| :render()
| |
| end
| |
| | |
| function BannerTemplate:render()
| |
| -- Dummy method, to be implemented by the subclasses.
| |
| return ''
| |
| end
| |
| | |
| --------------------------------------------------------------------------------
| |
| -- Banner class
| |
| --------------------------------------------------------------------------------
| |
| | |
| local Banner = BannerTemplate:subclass('Banner')
| |
| | |
| function Banner:initialize(configObj)
| |
| BannerTemplate.initialize(self, configObj)
| |
| self:setImageWidth(40)
| |
| end
| |
| | |
| function Banner:setReasonText(s)
| |
| self._reasonText = s
| |
| end
| |
| | |
| function Banner:setExplanationText(s)
| |
| self._explanationText = s
| |
| end
| |
| | |
| function Banner:render(page)
| |
| -- Renders the banner.
| |
| -- The page parameter specifies the page to generate the banner for, for
| |
| -- testing purposes.
| |
| mMessageBox = mMessageBox or require('Module:Message box')
| |
| local reasonText = self._reasonText or error('no reason text set')
| |
| local explanationText = self._explanationText
| |
| local mbargs = {
| |
| page = page,
| |
| type = 'protection',
| |
| image = self:renderImage(),
| |
| text = string.format(
| |
| "'''%s'''%s",
| |
| reasonText,
| |
| explanationText and '<br />' .. explanationText or ''
| |
| )
| |
| }
| |
| return mMessageBox.main('mbox', mbargs)
| |
| end
| |
| | |
| --------------------------------------------------------------------------------
| |
| -- Padlock class
| |
| --------------------------------------------------------------------------------
| |
| | |
| local Padlock = BannerTemplate:subclass('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: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
| |
| | |
| --------------------------------------------------------------------------------
| |
| -- Category class
| |
| --------------------------------------------------------------------------------
| |
| | |
| 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 Category:render()
| |
| if self._name then
| |
| return string.format(
| |
| '[[%s:%s]]',
| |
| mw.site.namespaces[14].name,
| |
| self._name
| |
| )
| |
| 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
| |
| 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.
| |
| local expiry = protectionObj.expiry
| |
| 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.reason
| |
| local action = protectionObj.action
| |
| local level = protectionObj.level
| |
|
| |
| --[[
| |
| -- 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
| |
| if cat then
| |
| self:setName(cat)
| |
| end
| |
| return Category.render(self)
| |
| end
| |
| | |
| --------------------------------------------------------------------------------
| |
| -- ExpiryCategory class
| |
| --------------------------------------------------------------------------------
| |
| | |
| local ExpiryCategory = Category:subclass('ExpiryCategory')
| |
| | |
| function ExpiryCategory:render()
| |
| local reasonsWithoutExpiryCheck = self._configObj:getConfigTable('reasonsWithoutExpiryCheck')
| |
| local expiryCheckActions = self._configObj:getConfigTable('expiryCheckActions')
| |
| local expiry = self._protectionObj.expiry
| |
| local action = self._protectionObj.action
| |
| local reason = self._protectionObj.reason
| |
|
| |
| 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.expiry
| |
| local action = protectionObj.action
| |
| local level = protectionObj.level
| |
| | |
| if not protectionObj:isProtected()
| |
| or type(expiry) == 'number' and expiry < os.time()
| |
| then
| |
| self:setName(configObj:getMessage('tracking-category-incorrect'))
| |
| 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 action = self._protectionObj.action
| |
| local level = self._protectionObj.level
| |
| local namespace = self._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
| |
| | |
| 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 blurbObj = Blurb:new(configObj, protectionObj, titleObj)
| |
| blurbObj:setDeletionDiscussionPage(args.xfd)
| |
| blurbObj:setUsername(args.user)
| |
| blurbObj:setSection(args.section)
| |
| | |
| local ret = {}
| |
| | |
| -- Render the banner
| |
| if protectionObj:isProtected() 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
| |
|
| |
| -- 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
| |
|
| |
| 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
| |
| | |
| return ProtectionBanner
| |