require('strict')
local yesno, makeMessageBox -- passed in from Module:Protected edit requestlocal makeToolbar = require('Module:Toolbar')._mainlocal getPagetype = require('Module:Pagetype')._mainlocal effectiveProtectionLevel = require('Module:Effective protection level')._main
------------------------------------------------------------------------ Helper functions----------------------------------------------------------------------
local function makeWikilink(page, display) if display then return mw.ustring.format('%s', page, display) else return mw.ustring.format('%s', page) endend
------------------------------------------------------------------------ Title class----------------------------------------------------------------------
-- This is basically the mw.title class with some extras thrown in.
local title = title.__index = title
function title.getProtectionLevelText(protectionLevel) -- Gets the text to use in anchors and urn links. local levels = return levels[protectionLevel]end
function title.new(...) local success, obj = pcall(mw.title.new, ...) if not (success and obj) then return end title.init(obj) return objend
function title.init(obj) -- Add a protectionLevel property. obj.protectionLevel = effectiveProtectionLevel(obj.exists and 'edit' or 'create', obj) if obj.protectionLevel
'user' then -- If we just need to be registered, pretend we need to be autoconfirmed, since it's the closest thing we have. obj.protectionLevel = 'autoconfirmed' end
-- Add a pagetype property. obj.pagetype = getPagetype -- Add link-making methods. function obj:makeUrlLink(query, display) return mw.ustring.format('[%s %s]', self:fullUrl(query), display) end
function obj:makeViewLink(display) return self:makeUrlLink(
, display) end
function obj:makeEditLink(display) return self:makeUrlLink(display) end
function obj:makeHistoryLink(display) return self:makeUrlLink(display) end
function obj:makeLastEditLink(display) return self:makeUrlLink(display) end
function obj:makeWhatLinksHereLink(display) return makeWikilink('Special:WhatLinksHere/' .. self.prefixedText, display) end
function obj:makeCompareLink(otherTitle, display) display = display or 'diff' local comparePagesTitle = title.new('Special:ComparePages') return comparePagesTitle:makeUrlLink(display) end
function obj:makeLogLink(logType, display) local logTitle = title.new('Special:Log') return logTitle:makeUrlLink(display) end
function obj:urlEncode return mw.uri.encode(self.prefixedText, 'WIKI') end
function obj:makeUrnLink(boxProtectionLevel) -- Outputs a urn link. The protection level is taken from the template, rather than detected from page itself, -- as the detection may be inaccurate for cascade-protected and title-blacklisted pages as of Nov 2013. local protectionLinkText = title.getProtectionLevelText(boxProtectionLevel) return mw.ustring.format('[urn:x-wp-%s:%s <span></span>]', protectionLinkText, self:urlEncode) end
-- Get a subpage title object, but go through pcall rather than use the unprotected mw.title:subPageTitle. function obj:getSubpageTitle(subpage) return title.new(self.prefixedText .. '/' .. subpage) end
function obj:getSandboxTitle if self.isSubpage and self.contentModel
------------------------------------------------------------------------ TitleTable class----------------------------------------------------------------------
local titleTable = titleTable.__index = titleTable
function titleTable.new(args) -- Get numerical arguments and make title objects for each of them. local nums = for k, v in pairs(args) do if type(k)
function titleTable:memoize(memoField, func, ...) if self[memoField] ~= nil then return self[memoField] else self[memoField] = func(...) return self[memoField] endend
function titleTable:titleIterator local i = 0 local n = #self return function i = i + 1 if i <= n then return self[i] end endend
function titleTable:hasSameProperty(memoField, getPropertyFunc) -- If the titles table has more than one title in it, check if they have the same property. -- The property is found using the getPropertyFunc function, which takes a title object as its single argument. local function hasSameProperty(getPropertyFunc) local property for i, obj in ipairs(self) do if i
return self:memoize(memoField, hasSameProperty, getPropertyFunc)end
function titleTable:hasSameExistenceStatus -- Returns true if all the titles exist, or if they all don't exist. Returns false if there is a mixture of existence statuses. return self:hasSameProperty('sameExistenceStatus', function (title) return title.exists end)end
function titleTable:hasSameProtectionStatus -- Checks if all the titles have the same protection status (either for creation protection or for edit-protection - the two are not mixed). local sameExistenceStatus = self:hasSameExistenceStatus if sameExistenceStatus then return self:hasSameProperty('sameProtectionStatus', function (title) return title.protectionLevel end) else return sameExistenceStatus endend
function titleTable:hasSamePagetype -- Checks if all the titles have the same pagetype. return self:hasSameProperty('samePagetype', function (title) return title.pagetype end)end
function titleTable:propertyExists(memoField, getPropertyFunc) -- Checks if a title with a certain property exists. -- The property is found using the getPropertyFunc function, which takes a title object as its single argument -- and should return a boolean value. local function propertyExists(getPropertyFunc) for titleObj in self:titleIterator do if getPropertyFunc(titleObj) then return true end end return false end return self:memoize(memoField, propertyExists, getPropertyFunc)end
function titleTable:hasNonInterfacePage return self:propertyExists('nonInterfacePage', function (titleObj) return titleObj.namespace ~= 8 end)end
function titleTable:hasTemplateOrModule return self:propertyExists('templateOrModule', function (titleObj) return titleObj.namespace
828 end)end
function titleTable:hasNonTemplateOrModule return self:propertyExists('nontemplateormodule', function (titleobj) return titleobj.namespace ~= 10 and titleobj.namespace ~= 828 end)end
function titleTable:hasOtherProtectionLevel(level) for titleObj in self:titleIterator do if titleObj.protectionLevel ~= level then return true end end return falseend
function titleTable:getProtectionLevels local function getProtectionLevels local levels = for titleObj in self:titleIterator do local level = titleObj.protectionLevel levels[level] = true end return levels end return self:memoize('protectionLevels', getProtectionLevels)end
------------------------------------------------------------------------ Blurb class definition----------------------------------------------------------------------
local blurb = blurb.__index = blurb
function blurb.new(titleTable, boxProtectionLevel) local obj = obj.titles = titleTable obj.boxProtectionLevel = boxProtectionLevel obj.linkCount = 0 -- Counter for the number of total items in the object's link lists. setmetatable(obj, blurb) return objend
-- Static methods --
function blurb.makeParaText(name, val) local pipe = mw.text.nowiki('|') local equals = mw.text.nowiki('=') val = val and ("" .. val .. "") or return mw.ustring.format('%s%s%s%s
', pipe, name, equals, val)end
function blurb.makeTemplateLink(s) return mw.ustring.format('%s%s%s', mw.text.nowiki(''))end
function blurb:makeProtectionText local boxProtectionLevel = self.boxProtectionLevel local levels = for level, protectionText in pairs(levels) do if level
function blurb.getPagetypePlural(title) local pagetype = title.pagetype if pagetype
-- Normal methods --
function blurb:makeLinkList(title) local tbargs = -- The argument list to pass to Module:Toolbar tbargs.style = 'font-size: smaller;' tbargs.separator = 'dot' -- Page links. table.insert(tbargs, title:makeEditLink('edit')) table.insert(tbargs, title:makeHistoryLink('history')) table.insert(tbargs, title:makeLastEditLink('last')) table.insert(tbargs, title:makeWhatLinksHereLink('links')) -- Sandbox links. local sandboxTitle = title:getSandboxTitle if sandboxTitle and sandboxTitle.exists then table.insert(tbargs, sandboxTitle:makeViewLink('sandbox')) table.insert(tbargs, sandboxTitle:makeEditLink('edit sandbox')) table.insert(tbargs, sandboxTitle:makeHistoryLink('sandbox history')) table.insert(tbargs, sandboxTitle:makeLastEditLink('sandbox last edit')) table.insert(tbargs, title:makeCompareLink(sandboxTitle, 'sandbox diff')) end -- Test cases links. local testcasesTitle = title:getSubpageTitle('testcases') if testcasesTitle and testcasesTitle.exists then table.insert(tbargs, testcasesTitle:makeViewLink('test cases')) end -- Transclusion count link. if title.namespace
828 then -- Only add the transclusion count link for templates and modules. local tclink = mw.uri.new tclink = string.format('[%s transclusion count]', tostring(tclink)) table.insert(tbargs, tclink) end -- Protection log link. if title.namespace ~= 8 then -- MediaWiki pages don't have protection log entries. table.insert(tbargs, title:makeLogLink('protect', 'protection log')) end self.linkCount = self.linkCount + #tbargs -- Keep track of the number of total links created by the object. return makeToolbar(tbargs)end
function blurb:makeLinkLists local titles = self.titles if #titles
function blurb:makeIntro local titles = self.titles local requested = 'It is requested that' local protectionText if titles:hasNonInterfacePage then protectionText = ' ' .. self:makeProtectionText else protectionText = -- Interface pages cannot be unprotected, so we don't need to explicitly say they are protected. end -- Deal with cases where we are passed multiple titles. if #titles > 1 then local pagetype if titles:hasSamePagetype then pagetype = blurb.getPagetypePlural(titles[1]) else pagetype = 'pages' end return mw.ustring.format("%s edits be made to the following%s %s:", requested, protectionText, pagetype) end -- Deal with cases where we are passed only one title. local title = titles[1] local stringToFormat if title.exists then stringToFormat = '%s an edit be made to the%s %s at %s.' else stringToFormat = '%s the%s %s at %s be created.' end stringToFormat = "" .. stringToFormat .. "" return mw.ustring.format(stringToFormat, requested, protectionText, title.pagetype, title:makeViewLink(title.prefixedText))end
function blurb:makeBody local titles = self.titles local protectionLevels = titles:getProtectionLevels local boxProtectionLevel = self.boxProtectionLevel local hasNonInterfacePage = titles:hasNonInterfacePage local isPlural = false if #titles > 1 then isPlural = true end
local descriptionText = "This template must be followed by a complete and specific description of the request, " if boxProtectionLevel
'templateeditor' then local editText = 'edit' if isPlural then editText = editText .. 's' end local descriptionCompleteText = mw.ustring.format('so that an editor unfamiliar with the subject matter could complete the requested %s immediately.', editText) descriptionText = descriptionText .. descriptionCompleteText else descriptionText = descriptionText .. 'that is, specify what text should be removed and a verbatim copy of the text that should replace it. ' .. "Please change X" is not acceptable and will be rejected; the request must be of the form "please change X to Y". end
local smallText = if boxProtectionLevel
'templateeditor' then local templateFullText if boxProtectionLevel
'templateeditor' then templateFullText = 'template-protected' end smallText = 'Edit requests to ' .. templateFullText .. " pages should only be used for edits that are either uncontroversial or supported by consensus." .. " If the proposed edit might be controversial, discuss it on the protected page's talk page before using this template." else local userText local responseTemplate if boxProtectionLevel
'autoconfirmed' then userText = 'autoconfirmed user' responseTemplate = blurb.makeTemplateLink('ESp') elseif boxProtectionLevel
if not isPlural then local title = titles[1] if title.namespace
828 then local sandboxTitle = title:getSubpageTitle('sandbox') if sandboxTitle and sandboxTitle.exists then smallText = smallText .. ' Consider making changes first to the ' .. sandboxTitle:makeViewLink(title.pagetype .. "'s sandbox") local testcasesTitle = title:getSubpageTitle('testcases') if testcasesTitle and testcasesTitle.exists then smallText = smallText .. ' and ' .. testcasesTitle:makeViewLink('test them thoroughly here') end smallText = smallText .. ' before submitting an edit request.' end end end if hasNonInterfacePage then smallText = smallText .. ' To request that a page be protected or unprotected, make a protection request.' end if boxProtectionLevel
'templateeditor' or boxProtectionLevel
\n%s\n
', descriptionText, smallText)endfunction blurb:export local intro = self:makeIntro local linkLists = self:makeLinkLists local body = self:makeBody -- Start long links lists on a new line. local linkListSep = ' ' if self.linkCount > 5 then linkListSep = '
' end return mw.ustring.format('%s%s%s\n\n%s', intro, linkListSep, linkLists, body)end
------------------------------------------------------------------------ Subclass of Module:Protected edit request's box class for active boxes----------------------------------------------------------------------
local box = box.__index = box
function box.new(protectionType, args) -- In the inheritance system used here, an object's metatable is its class, and a class's metatable is its superclass local obj = getmetatable(box).new(protectionType, args) setmetatable(obj, box) local boxProtectionLevels = obj.boxProtectionLevel = boxProtectionLevels[protectionType] obj.demo = yesno(args.demo) -- Set dependent objects. obj.titles = titleTable.new(args) if not yesno(args.force) and obj.titles:hasSameProperty('sameProtectionStatus', function (title) return title.protectionLevel end) and obj.titles[1].protectionLevel ~= 'unprotected' then obj.boxProtectionLevel = obj.titles[1].protectionLevel end obj.blurb = blurb.new(obj.titles, obj.boxProtectionLevel) return objend
function box:setImage local titles = self.titles local boxProtectionLevel = self.boxProtectionLevel local padlock if boxProtectionLevel
'interfaceadmin' then padlock = 'Interface-protection-shackle.svg ' elseif boxProtectionLevel
'autoconfirmed' then padlock = 'Semi-protection-shackle.svg' elseif boxProtectionLevel
function box:buildUrnLinks local ret = local boxProtectionLevel = self.boxProtectionLevel for titleObj in self.titles:titleIterator do table.insert(ret, titleObj:makeUrnLink(boxProtectionLevel)) end return mw.ustring.format('
', table.concat(ret))endfunction box:setBlurbText self:setArg('text', self.blurb:export .. self:buildUrnLinks)end
function box:exportRequestTmbox self:setImage self:setBlurbText self:setArg('class', 'editrequest') self:setArg('id', title.getProtectionLevelText(self.boxProtectionLevel)) -- for anchor. yes, this leads to multiple elements with the same ID. we should probably fix this at some point return makeMessageBox('tmbox', self.tmboxArgs)end
function box:exportRequestCategories local cats = local boxProtectionLevel = self.boxProtectionLevel local function addCat(cat) table.insert(cats, mw.ustring.format('', cat)) end local protectionCats = addCat(protectionCats[boxProtectionLevel]) if self.titles:hasOtherProtectionLevel(boxProtectionLevel) then addCat('Wikipedia edit requests possibly using incorrect templates') end return table.concat(cats)end
function box:export local title = self.titles.currentTitle if not title.isTalkPage and not self.demo and not yesno(self.args.skiptalk) then return '
Error: Protected edit requests can only be made on the talk page.' end local ret = table.insert(ret, self:exportRequestTmbox) if not self.demo then table.insert(ret, self:exportRequestCategories) end return table.concat(ret)end------------------------------------------------------------------------ Function exported to Module:Protected edit request----------------------------------------------------------------------
return function(superclass, yn, mb) yesno = yn makeMessageBox = mb return setmetatable(box, superclass)end