Anonymous

Changes

From Polyphasic Sleep Wiki
don't add protection categories or show padlock icons for user js/css pages; based on code contributed by User:ProcrastinatingReader
Line 6: Line 6:  
local makeFileLink = require('Module:File link')._main
 
local makeFileLink = require('Module:File link')._main
 
local effectiveProtectionLevel = require('Module:Effective protection level')._main
 
local effectiveProtectionLevel = require('Module:Effective protection level')._main
 +
local effectiveProtectionExpiry = require('Module:Effective protection expiry')._main
 
local yesno = require('Module:Yesno')
 
local yesno = require('Module:Yesno')
   Line 19: Line 20:     
local function makeCategoryLink(cat, sort)
 
local function makeCategoryLink(cat, sort)
local nsText = mw.site.namespaces[14].name
+
if cat then
if cat and sort then
   
return string.format(
 
return string.format(
 
'[[%s:%s|%s]]',
 
'[[%s:%s|%s]]',
nsText,
+
mw.site.namespaces[14].name,
 
cat,
 
cat,
 
sort
 
sort
 
)
 
)
elseif cat then
  −
return string.format(
  −
'[[%s:%s]]',
  −
nsText,
  −
cat
  −
)
  −
else
  −
return ''
   
end
 
end
 
end
 
end
Line 40: Line 32:  
-- 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()
+
if not lang then
 +
lang = mw.language.getContentLanguage()
 +
end
 
local success, result = pcall(lang.formatDate, lang, 'U', dateString)
 
local success, result = pcall(lang.formatDate, lang, 'U', dateString)
 
if success then
 
if success then
Line 49: Line 43:  
end
 
end
 
error(string.format(
 
error(string.format(
'invalid %s ("%s")',
+
'invalid %s: %s',
 
dateType,
 
dateType,
 
tostring(dateString)
 
tostring(dateString)
Line 63: Line 57:  
end
 
end
   −
local function toTableEnd(t, pos)
+
-- Given a directed graph formatted as node -> table of direct successors,
-- Sends the value at position pos to the end of array t, and shifts the
+
-- get a table of all nodes reachable from a given node (though always
-- other items down accordingly.
+
-- including the given node).
return table.insert(t, table.remove(t, pos))
+
local function getReachableNodes(graph, start)
end
  −
 
  −
local function walkHierarchy(hierarchy, start)
   
local toWalk, retval = {[start] = true}, {}
 
local toWalk, retval = {[start] = true}, {}
 
while true do
 
while true do
 
-- Can't use pairs() since we're adding and removing things as we're iterating
 
-- Can't use pairs() since we're adding and removing things as we're iterating
local k = next(toWalk)
+
local k = next(toWalk) -- This always gets the "first" key
if k == nil then break end
+
if k == nil then
 +
return retval
 +
end
 
toWalk[k] = nil
 
toWalk[k] = nil
 
retval[k] = true
 
retval[k] = true
for _,v in ipairs(hierarchy[k]) do
+
for _,v in ipairs(graph[k]) do
 
if not retval[v] then
 
if not retval[v] then
 
toWalk[v] = true
 
toWalk[v] = true
Line 83: Line 76:  
end
 
end
 
end
 
end
return retval
   
end
 
end
   Line 96: Line 88:  
edit = true,
 
edit = true,
 
move = true,
 
move = true,
autoreview = true
+
autoreview = true,
 +
upload = true
 
}
 
}
   Line 120: Line 113:  
else
 
else
 
error(string.format(
 
error(string.format(
'invalid action ("%s")',
+
'invalid action: %s',
 
tostring(args.action)
 
tostring(args.action)
 
), 3)
 
), 3)
Line 134: Line 127:     
-- Set expiry
 
-- Set expiry
if args.expiry then
+
local effectiveExpiry = effectiveProtectionExpiry(obj.action, obj.title)
if cfg.indefStrings[args.expiry] then
+
if effectiveExpiry == 'infinity' then
obj.expiry = 'indef'
+
obj.expiry = 'indef'
elseif type(args.expiry) == 'number' then
+
elseif effectiveExpiry ~= 'unknown' then
obj.expiry = args.expiry
+
obj.expiry = validateDate(effectiveExpiry, 'expiry date')
else
  −
obj.expiry = validateDate(args.expiry, 'expiry date')
  −
end
   
end
 
end
   Line 179: Line 169:  
end
 
end
 
return setmetatable(obj, Protection)
 
return setmetatable(obj, Protection)
 +
end
 +
 +
function Protection:isUserScript()
 +
-- Whether the page is a user JavaScript or CSS page.
 +
local title = self.title
 +
return title.namespace == 2 and (
 +
title.contentModel == 'javascript' or title.contentModel == 'css'
 +
)
 
end
 
end
   Line 184: Line 182:  
return self.level ~= '*'
 
return self.level ~= '*'
 
end
 
end
 +
 +
function Protection:shouldShowLock()
 +
-- Whether we should output a banner/padlock
 +
return self:isProtected() and not self:isUserScript()
 +
end
 +
 +
-- Whether this page needs a protection category.
 +
Protection.shouldHaveProtectionCategory = Protection.shouldShowLock
    
function Protection:isTemporary()
 
function Protection:isTemporary()
Line 190: Line 196:     
function Protection:makeProtectionCategory()
 
function Protection:makeProtectionCategory()
 +
if not self:shouldHaveProtectionCategory() then
 +
return ''
 +
end
 +
 
local cfg = self._cfg
 
local cfg = self._cfg
 
local title = self.title
 
local title = self.title
  −
-- Exit if the page is not protected.
  −
if not self:isProtected() then
  −
return ''
  −
end
   
 
 
-- Get the expiry key fragment.
 
-- Get the expiry key fragment.
Line 207: Line 212:     
-- Get the namespace key fragment.
 
-- Get the namespace key fragment.
local namespaceFragment
+
local namespaceFragment = cfg.categoryNamespaceKeys[title.namespace]
do
+
if not namespaceFragment and title.namespace % 2 == 1 then
namespaceFragment = cfg.categoryNamespaceKeys[title.namespace]
+
namespaceFragment = 'talk'
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
Line 237: Line 239:  
-- instead.
 
-- instead.
 
--]]
 
--]]
if self.reason and cfg.reasonsWithNamespacePriority[self.reason] then
+
table.insert(order, table.remove(order, self.reason and cfg.reasonsWithNamespacePriority[self.reason] and 2 or 3))
-- table.insert(order, 3, table.remove(order, 2))
  −
toTableEnd(order, 2)
  −
else
  −
toTableEnd(order, 3)
  −
end
   
   
 
   
 
--[[
 
--[[
Line 323: Line 320:  
end
 
end
 
return ''
 
return ''
end
  −
  −
function Protection:needsExpiry()
  −
local cfg = self._cfg
  −
local actionNeedsCheck = cfg.expiryCheckActions[self.action]
  −
return not self.expiry and (
  −
actionNeedsCheck or (
  −
actionNeedsCheck == nil
  −
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:isProtected()
+
return not self:shouldHaveProtectionCategory()
 
or type(expiry) == 'number' and expiry < os.time()
 
or type(expiry) == 'number' and expiry < os.time()
 
end
 
end
Line 354: Line 339:  
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'],
  −
self.title.text
  −
)
  −
end
   
if self:isIncorrect() then
 
if self:isIncorrect() then
 
ret[#ret + 1] = makeCategoryLink(
 
ret[#ret + 1] = makeCategoryLink(
Line 488: Line 467:  
if level == 'autoconfirmed' then
 
if level == 'autoconfirmed' then
 
requestType = 'semi'
 
requestType = 'semi'
 +
elseif level == 'extendedconfirmed' then
 +
requestType = 'extended'
 
elseif level == 'templateeditor' then
 
elseif level == 'templateeditor' then
 
requestType = 'template'
 
requestType = 'template'
Line 754: Line 735:  
end
 
end
 
return setmetatable(obj, BannerTemplate)
 
return setmetatable(obj, BannerTemplate)
end
  −
  −
function BannerTemplate:setImageWidth(width)
  −
self._imageWidth = width
  −
end
  −
  −
function BannerTemplate:setImageTooltip(tooltip)
  −
self._imageCaption = tooltip
   
end
 
end
   Line 770: Line 743:  
return makeFileLink{
 
return makeFileLink{
 
file = filename,
 
file = filename,
size = (self._imageWidth or 20) .. 'px',
+
size = (self.imageWidth or 20) .. 'px',
 
alt = self._imageAlt,
 
alt = self._imageAlt,
 
link = self._imageLink,
 
link = self._imageLink,
caption = self._imageCaption
+
caption = self.imageCaption
 
}
 
}
 
end
 
end
Line 786: Line 759:  
function Banner.new(protectionObj, blurbObj, cfg)
 
function Banner.new(protectionObj, blurbObj, cfg)
 
local obj = BannerTemplate.new(protectionObj, cfg) -- This doesn't need the blurb.
 
local obj = BannerTemplate.new(protectionObj, cfg) -- This doesn't need the blurb.
obj:setImageWidth(40)
+
obj.imageWidth = 40
obj:setImageTooltip(blurbObj:makeBannerText('alt')) -- Large banners use the alt text for the tooltip.
+
obj.imageCaption = blurbObj:makeBannerText('alt') -- Large banners use the alt text for the tooltip.
 
obj._reasonText = blurbObj:makeBannerText('text')
 
obj._reasonText = blurbObj:makeBannerText('text')
 
obj._explanationText = blurbObj:makeBannerText('explanation')
 
obj._explanationText = blurbObj:makeBannerText('explanation')
Line 821: Line 794:  
function Padlock.new(protectionObj, blurbObj, cfg)
 
function Padlock.new(protectionObj, blurbObj, cfg)
 
local obj = BannerTemplate.new(protectionObj, cfg) -- This doesn't need the blurb.
 
local obj = BannerTemplate.new(protectionObj, cfg) -- This doesn't need the blurb.
obj:setImageWidth(20)
+
obj.imageWidth = 20
obj:setImageTooltip(blurbObj:makeBannerText('tooltip'))
+
obj.imageCaption = blurbObj:makeBannerText('tooltip')
 
obj._imageAlt = blurbObj:makeBannerText('alt')
 
obj._imageAlt = blurbObj:makeBannerText('alt')
 
obj._imageLink = blurbObj:makeBannerText('link')
 
obj._imageLink = blurbObj:makeBannerText('link')
Line 834: Line 807:  
local frame = mw.getCurrentFrame()
 
local frame = mw.getCurrentFrame()
 
-- The nowiki tag helps prevent whitespace at the top of articles.
 
-- The nowiki tag helps prevent whitespace at the top of articles.
local nowiki = frame:extensionTag{name = 'nowiki'}
+
return frame:extensionTag{name = 'nowiki'} .. frame:extensionTag{
local indicator = frame:extensionTag{
   
name = 'indicator',
 
name = 'indicator',
 
args = {name = self._indicatorName},
 
args = {name = self._indicatorName},
 
content = self:renderImage()
 
content = self:renderImage()
 
}
 
}
return nowiki .. indicator
   
end
 
end
   Line 868: Line 839:  
local ret = {}
 
local ret = {}
   −
-- If a page's edit protection is equally or more restrictive than its protection from some other action,
+
-- If a page's edit protection is equally or more restrictive than its
-- then don't bother displaying anything for the other action (except categories).
+
-- protection from some other action, then don't bother displaying anything
if protectionObj.action == 'edit' or args.demolevel or not walkHierarchy(cfg.hierarchy, protectionObj.level)[effectiveProtectionLevel('edit', protectionObj.title)] then
+
-- for the other action (except categories).
 +
if protectionObj.action == 'edit' or
 +
args.demolevel or
 +
not getReachableNodes(
 +
cfg.hierarchy,
 +
protectionObj.level
 +
)[effectiveProtectionLevel('edit', protectionObj.title)]
 +
then
 
-- Initialise the blurb object
 
-- Initialise the blurb object
 
local blurbObj = Blurb.new(protectionObj, args, cfg)
 
local blurbObj = Blurb.new(protectionObj, args, cfg)
 
 
 
-- Render the banner
 
-- Render the banner
if protectionObj:isProtected() then
+
if protectionObj:shouldShowLock() then
 
ret[#ret + 1] = tostring(
 
ret[#ret + 1] = tostring(
 
(yesno(args.small) and Padlock or Banner)
 
(yesno(args.small) and Padlock or Banner)