Open main menu

Changes

Module:Protection banner

6,448 bytes removed, 15:26, 8 June 2014
Yet Another Rewrite - this time using Module:Middleclass
-- Initialise necessary modules.
local class = require('Module:Middleclass').class
local mArguments = require('Module:Arguments')
local mProtectionLevel = require('Module:Effective protection level')._main
local mFileLink = require('Module:File link')
local mProtectionLevel = require('Module:Effective protection level')
local yesno = require('Module:Yesno')
local mMessageBox -- only needs to be loaded if we are outputting a banner, so lazily initialise
-- Load config------------------------------------------------------------------------------local cfg = mw.loadData('Module:Protection banner/config')-- ProtectionStatus class--------------------------------------------------------------------------------
local p ProtectionStatus = {}class('ProtectionStatus')
function ProtectionStatus:initialize(args, 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'-- Helper functions end-------------------------------------------------------------------------------- end
local function validateField(tName, t, field, expectType, nilOk) -- Set level local val = t[field]do local valType level = typemProtectionLevel._main(valself._action, titleObj) if not (valType == expectType or nilOk and valType level == 'nilaccountcreator') then error(string.format( "type error -- Lump titleblacklisted pages in '%s' field '%s' (%s%s expected, got %s)"with template-protected pages, tName,-- since templateeditors can do both. tostring(field),level = 'templateeditor' expectType, end nilOk and ' or nil' self._level = level or '*', valType ), 2)
end
 
-- Set reason
self._reason = args.reason
 
-- Set expiry
self._expiry = args.expiry
end
local function toTableEndProtectionStatus:getAction(t, pos) -- Sends the value at position pos to the return self._actionend of array t, and shifts the function ProtectionStatus:getLevel() -- other items down accordinglyreturn self._levelend function ProtectionStatus:getReason() return tableself.insert_reasonend function ProtectionStatus:getExpiry(t, table) return self.remove(t, pos))_expiry
end
--------------------------------------------------------------------------------
-- Main functionsConfig class
--------------------------------------------------------------------------------
function p.mainlocal Config = class(frame'Config') local args = mArguments.getArgsfunction Config:initialize(frame) return pself._cfg = mw._mainloadData(args'Module:Protection banner/config')
end
function p._mainConfig:getBannerConfig(argsprotectionStatusObj) local protectionLevel cfg = pself.getProtectionLevel(args)_cfg local isSmall action = yesnoprotectionStatusObj:getAction(args.small) or false local bannerConfig reason = p.getBannerConfigprotectionStatusObj:getReason(protectionLevel, args) if cfg.banners[action][reason] then return cfg.banners[action][reason] else return cfg.defaultBanners[action] endend
function Config:getConfigTable(key) local ret whitelisted = { images = true, categories = true, categoryNamespaces = ''true, pagetypeNamespaces = true, errorCategories = true } if isSmall whitelisted[key] then ret = ret .. preturn self.makePadlock(protectionLevel, args, bannerConfig)_cfg[key]
else
ret = ret .. p.makeBanner(protectionLevel, args, bannerConfig)return nil
end
ret = ret .. p.getProtectionCategory(protectionLevel, args)
ret = ret .. p.getTrackingCategories(protectionLevel, args)
return ret
end
--------------------------------------------------------------------------------
-- Protection functionsImage class
--------------------------------------------------------------------------------
function p.getProtectionLevel(args) local title if args.page then title = mw.title.new(args.page) else title = mw.title.getCurrentTitle() end local protectionData Image = p.getProtectionDataclass(title) protectionLevel = protectionData[args.action or 'editImage'] return protectionLevel or '*'end function p.getProtectionData(title) -- Gets a table containing protection data for the given title. The data -- is cached using a metatable, and so can be indexed as needed without -- a performance loss. local protectionData = {} local actions = { create = true, edit = true, move = true, autoreview = true } setmetatable(protectionData, { __index = function (t, key) local level if actions[key] then level = mProtectionLevel(key, title) if level == 'accountcreator' then -- Lump titleblacklisted pages in with template-protected pages, -- since templateeditors can do both. level = 'templateeditor' end end protectionData[key] = level return level end }) return protectionDataend
--------------------------------------------------------------------------------
-- Banner config functionsBlurb class
--------------------------------------------------------------------------------
local Blurb = class('Blurb') function p.getBannerConfigBlurb:initialize(protectionLevel, argsbannerConfig) self._config = bannerConfig
end
--------------------------------------------------------------------------------
-- Padlock functionsBannerTemplate class
--------------------------------------------------------------------------------
function p.makePadlock(protectionLevel, args, bannerConfig) local data BannerTemplate = p.makePadlockData(protectionLevel, args, bannerConfig) return p.renderPadlockclass(data'BannerTemplate')end
function p.makePadlockDataBannerTemplate:initialize(protectionLevel, args, bannerConfig)
end
function p.renderPadlock(data) data = data or {} local image = mFileLink.new(data.filename or 'Transparent.gif') :width(20) :link(data.link) :alt(data.alt) BannerTemplate:render() local root = mw.html.create('div') root :addClass('metadata topicon nopopups') :attr('id', 'protected-icon') :css{display = 'none', right = data.right or '55px'} :wikitext(image) return tostring(root)
end
--------------------------------------------------------------------------------
-- Banner functionsclass
--------------------------------------------------------------------------------
function p.makeBanner(protectionLevel, args, bannerConfig) local data Banner = p.makeBannerData(protectionLevel, args, bannerConfig) return p.renderBannerBannerTemplate:subclass(data'Banner')end
function p.makeBannerData(protectionLevel, args, bannerConfig)--------------------------------------------------------------------------------end-- Padlock class--------------------------------------------------------------------------------
function p.renderBanner(data) data = data or {} local image Padlock = mFileLink.new(data.filename) BannerTemplate:width(40) :caption(data.mouseover) :render() local mbargs = { page = data.page, type = 'protection', image = image, text = string.format( "'''%s'''%s", data.reasonText, data.explanationText and '<br />' .. data.explanationText or '' ) } return mMessageBox.mainsubclass('mboxPadlock', mbargs)end
--------------------------------------------------------------------------------
-- Protection category functionsCategory class
--------------------------------------------------------------------------------
local Category = class('Category') function p.getProtectionCategoryCategory:initialize(protectionLevel, args)
end
function p.getPagetypeCategory:export(ns) -- Returns a if self._categoryName then return string with the page.format( '[[%s type:%s]]', mw. Takes a namespace number as inputsite. local pagetype = pagetypeNamespacesnamespaces[ns14] or pagetypeNamespaces.defaultname, self._categoryName ) if not pagetype thenelse error(return 'the page type could not be found; please define a name for the key "default"')
end
return pagetype
end
function p.matchNamespace(ns)-------------------------------------------------------------------------------- -- Matches a namespace number to a string that can be passed to theProtectionCategory class -- namespace parameter of p.getCategoryName. if not ns or type(ns) ~= 'number' then return nil end local nskey = cfg.categoryNamespaces[ns] if not nskey and ns % 2 == 1 then nskey = 'talk' end return nskeyend------------------------------------------------------------------------------
function p.getCategoryNamelocal ProtectionCategory = Category:subclass(cats, action, level, namespace, reason, expiry'ProtectionCategory') --[[ -- Gets a category name from the category table, given a combination of -- the protection type, the protection level, the namespace number, the -- reason for protection, and the expiry date. --]] cats = cats or cfg.categories
--[[------------------------------------------------------------------------------ -- Define the properties table. Each property is a table containing theErrorCategory class -- 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, keypos = 5, val = expiry}, namespace = {order = 2, keypos = 3, val = p.matchNamespace(namespace)}, reason = {order = 3, keypos = 4, val = reason}, level = {order = 4, keypos = 2, val = level}, action = {order = 5, keypos = 1, val = action} }--------------------------------------------------------------------------
--[[ -- Load the category order configuration for the reason specified. -- The configuration is stored in the categoryOrder field of each reason -- subtable of cfg.reasons. If the value is a table, then the order is the -- values specified in the table. If the value is a string, then 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 the value is of -- any other type then the canonical order is used. --]] local reasonTable = reason and cfg.reasons[reason] local categoryOrder = reasonTable and reasonTable.categoryOrder local categoryOrderType = type(categoryOrder) local configOrder = {} if categoryOrderType == 'table' then local dupes = {} for i = 1, 5 do local propertiesKey = categoryOrder[i] if not propertiesKey then local msg = 'no entry found for key ' .. i .. ' in the cfg.reasons.' .. reason .. '.categoryOrder table' error(msg) end local property = properties[propertiesKey] if not property then local msg = 'invalid value "' .. propertiesKey .. '" detected in the cfg.reasons.' .. reason .. '.categoryOrder table' error(msg) end if dupes[propertiesKey] then local msg = 'duplicate values "' .. propertiesKey .. '" detected in the cfg.reasons.' .. reason .. '.categoryOrder table' error(msg) else dupes[propertiesKey] ErrorCategory = true end configOrder[i] = property end else for propertiesKey, t in pairsCategory:subclass(properties) do configOrder[t.order] = t end if categoryOrderType == 'stringErrorCategory' then local property = properties[categoryOrder] if not property then local msg = '"' .. categoryOrder .. '" is not a valid value of cfg.reasons.' .. reason .. '.categoryOrder' error(msg) end toTableEnd(configOrder, property.order) end end
--[[------------------------------------------------------------------------------ -- Define the attempt order. Properties with no value defined are movedExpiryCategory class -- 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 active, inactive = {}, {} for i, t in ipairs(configOrder) do if t.val then active[#active + 1] = t else inactive[#inactive + 1] = t end end local noActive = #active local attemptOrder = active for i, t in ipairs(inactive) do attemptOrder[#attemptOrder + 1] = t 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. --]] for i = 1, 2^noActive do local key ExpiryCategory = {} for j, t in ipairs(attemptOrder) do if j > noActive then key[t.keypos] = 'all' else local quotient = i / 2 ^ (j - 1) quotient = math.ceil(quotient) if quotient % 2 == 1 then key[t.keypos] = t.val else key[t.keypos] = 'all' end end end key = table.concatCategory:subclass(key, '-') local attempt = cats[key] if attempt then return attempt end end error( 'No category match found;' .. ' please define the category for key "all-all-all-all-all"ExpiryCategory' )end
--------------------------------------------------------------------------------
-- Tracking category functionsProtectionBanner class
--------------------------------------------------------------------------------
local ProtectionBanner = {} function pProtectionBanner.getTrackingCategories_newBannerTemplate(protectionLevelargs) -- Makes a new banner template object. This will be a new instance of -- the most suitable subclass of BannerTemplate, e.g. Banner or Padlock. if yesno(args.small) then return Padlock:new(args) else return Banner:new(args) end
end
--[[function ProtectionBanner.exportToWiki(frame, titleObj)When to add "Category:Wikipedia pages with incorrect protection templates": local args = mArguments.getArgs(frame)* If it uses a type which is incompatible with the actual protection level of a page return ProtectionBanner.exportToLua(args, ortitleObj)* If an expiry date is set and is in the pastend
When to add "Category:Wikipedia protected pages without expiry":* No expiry is set, and* Expiry can be set, and* The protection type is not "move" (could change this?), and* The reason doesn't have "indefinitely protected" categories function ProtectionBanner.exportToLua(pp-blp, pp-semi-indef and pp-move-indef have these)args, and* The reason is not the generic pp-protected (could change this?title) title = title or mw.title.getCurrentTitle(This leaves reasons "dispute", "vandalism", "usertalk", and "sock")]]end
return pProtectionBanner
Anonymous user