Module:Protection banner: Difference between revisions

move the category methods to the Protection class, and get rid of all the category objects
Enwikipedia>Mr. Stradivarius
(allow passing the config object into the exportToLua and exportToWiki functions)
Enwikipedia>Mr. Stradivarius
(move the category methods to the Protection class, and get rid of all the category objects)
Line 19:
 
function Protection:initialize(args, configObj, titleObj)
self._configObj = configObj
self._titleObj = titleObj
 
-- Set action
do
Line 123 ⟶ 126:
function Protection:isProtected()
return self.level ~= '*'
end
 
function Protection._makeCategoryLink(cat)
-- Static method for rendering category wikitext.
if cat then
return string.format(
'[[%s:%s]]',
mw.site.namespaces[14].name,
cat
)
else
return ''
end
end
 
function Protection:makeProtectionCategory()
local configObj = self._configObj
local titleObj = self._titleObj
-- Exit if the page is not protected.
if not self:isProtected() then
return ''
end
-- Get the expiry.
local expiry = self.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.cfg.categoryNamespaceKeys
nskey = categoryNamespaces[namespace]
if not nskey and namespace % 2 == 1 then
nskey = 'talk'
end
end
 
-- Get the other inputs.
local reason = self.reason
local action = self.action
local level = self.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.cfg.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.cfg.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
 
return self._makeCategoryLink(cat)
end
 
function Protection:makeExpiryCategory()
local reasonsWithoutExpiryCheck = self._configObj.cfg.reasonsWithoutExpiryCheck
local expiryCheckActions = self._configObj.cfg.expiryCheckActions
local cat
if not self.expiry
and expiryCheckActions[self.action]
and self.reason -- the old {{pp-protected}} didn't check for expiry
and not reasonsWithoutExpiryCheck[self.reason]
then
cat = self._configObj.msg['tracking-category-expiry']
end
return self._makeCategoryLink(cat)
end
 
function Protection:makeErrorCategory()
local configObj = self._configObj
local cat
if not self:isProtected()
or type(self.expiry) == 'number' and self.expiry < os.time()
then
cat = configObj.msg['tracking-category-incorrect']
end
return self._makeCategoryLink(cat)
end
 
function Protection:makeTemplateCategory()
local configObj = self._configObj
local titleObj = self._titleObj
local cat
if self.level == 'templateeditor'
and (
(self.action ~= 'edit' and self.action ~= 'move')
or (titleObj.namespace ~= 10 and titleObj.namespace ~= 828)
)
then
cat = configObj.msg['tracking-category-template']
end
return self._makeCategoryLink(cat)
end
 
Line 660 ⟶ 871:
: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.cfg.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.cfg.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.cfg.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.cfg.reasonsWithoutExpiryCheck
local expiryCheckActions = self._configObj.cfg.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(self._configObj.msg['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.msg['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 titleObj = self._titleObj
local action = self._protectionObj.action
local level = self._protectionObj.level
local namespace = titleObj.namespace
if level == 'templateeditor'
and (
(action ~= 'edit' and action ~= 'move')
or (namespace ~= 10 and namespace ~= 828)
)
then
self:setName(configObj.msg['tracking-category-template'])
end
return Category.render(self)
end
 
Line 986 ⟶ 932:
-- Render the categories
if yesno(args.category) ~= false then
ret[#ret + 1] = protectionObj:makeProtectionCategory()
local objects = {
ret[#ret + 1] = protectionObj:makeExpiryCategory()
ProtectionCategory:new(configObj, protectionObj, titleObj),
ExpiryCategory:new(configObj,ret[#ret + 1] = protectionObj:makeErrorCategory(),
ErrorCategory:new(configObj,ret[#ret + 1] = protectionObj:makeTemplateCategory(),
TemplateCategory:new(configObj, protectionObj, titleObj)
}
for _, obj in ipairs(objects) do
ret[#ret + 1] = obj:render()
end
end
Line 1,008 ⟶ 949:
Banner = Banner,
Padlock = Padlock,
Category = Category,
ProtectionCategory = ProtectionCategory,
ErrorCategory = ErrorCategory,
ExpiryCategory = ExpiryCategory,
}
end