Module:Protection banner: Difference between revisions
move the category methods to the Protection class, and get rid of all the category objects
(allow passing the config object into the exportToLua and exportToWiki functions) |
(move the category methods to the Protection class, and get rid of all the category objects) |
||
Line 19: | Line 19: | ||
function Protection:initialize(args, configObj, titleObj) | function Protection:initialize(args, configObj, titleObj) | ||
self._configObj = configObj | |||
self._titleObj = titleObj | |||
-- Set action | -- Set action | ||
do | do | ||
Line 123: | Line 126: | ||
function Protection:isProtected() | function Protection:isProtected() | ||
return self.level ~= '*' | 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 | end | ||
Line 660: | Line 871: | ||
:wikitext(self:renderImage()) | :wikitext(self:renderImage()) | ||
return tostring(root) | return tostring(root) | ||
end | end | ||
Line 986: | Line 932: | ||
-- Render the categories | -- Render the categories | ||
if yesno(args.category) ~= false then | if yesno(args.category) ~= false then | ||
ret[#ret + 1] = protectionObj:makeProtectionCategory() | |||
ret[#ret + 1] = protectionObj:makeExpiryCategory() | |||
ret[#ret + 1] = protectionObj:makeErrorCategory() | |||
ret[#ret + 1] = protectionObj:makeTemplateCategory() | |||
end | end | ||
Line 1,008: | Line 949: | ||
Banner = Banner, | Banner = Banner, | ||
Padlock = Padlock, | Padlock = Padlock, | ||
} | } | ||
end | end | ||
return ProtectionBanner | return ProtectionBanner |