Module:Contentious topics talk banner
Appearance
![]() | This module is rated as beta, and is ready for widespread use. It is still new and should be used with some caution to ensure the results are as expected. |
![]() | This module is subject to page protection. It is a highly visible module in use by a very large number of pages, or is substituted very frequently. Because vandalism or mistakes would affect many pages, and even trivial editing might cause substantial load on the servers, it is protected from editing. |
![]() | This template is within the jurisdiction of the Arbitration Committee, as one of its associated enforcement processes. Therefore, you must not make significant changes to the wording or functionality of this template without the Committee's consent. Thank you! |
![]() | This module depends on the following other modules: |
To learn about the template {{Contentious topics/talk notice}}, please see its documentation. This page documents the technical details of the module. There is probably little of interest here unless you are an arbitrator or clerk (or you are curious how things work under the hood!).
Usage
{{#invoke:Contentious topics talk banner|main}}
Technical details
This module is designed to be extensible without needing to edit the module code. Much of its data comes from the following JSON pages:
- Template:Contentious topics/Additional restrictions.json contains per-topic additional restrictions. The
topic-wide
restrictions apply whenever the corresponding CTOP code is given. Theadditional-available
restrictions can be passed as parameters (e.g.|ECR=yes
), and can be used either when a restriction is added to the topic's standard set or when it applies to all articles within a subtopic of the contentious topic designation. - Template:Contentious topics/Restrictions definition.json is the text of the bullet point indicating a restriction is active
- Template:Contentious topics/Standard set.json is a list of all standard set restrictions
- Template:Contentious topics/Category database.json is the name of the category added when a restriction is active (without the
Category:
prefix). The following codes have special meaning:- The
all
category activates for every page tagged with the contentious topic banner - The
bad-topic
category is used whenever a contentious topic code is not found at Template:Contentious topics/list - The
no-date
category is used when there are active, manually-placed restrictions but no|placed-date=
is specified - The
no-topic
category is used when no topics are specified - The
protection-error
category is used when|protection=yes
, but the page is not actually protected
- The
local p = {}
local TableTools = require('Module:TableTools')
local yesno = require('Module:Yesno')
local setToList = require('Module:Set to list')
local restrictionsDatabase = mw.loadJsonData("Template:Contentious topics/Additional restrictions.json")
local restrictionsDefinition = mw.loadJsonData("Template:Contentious topics/Restrictions definition.json")
local standardSet = mw.loadJsonData("Template:Contentious topics/Standard set.json")
local function collectTopics(args)
local seen = {}
local topics = {}
local function add(value)
if value then
value = mw.text.trim(value)
if value ~= '' and not seen[value] then
seen[value] = true
table.insert(topics, value)
end
end
end
-- Primary topic params
add(args.topic)
add(args.t)
add(args[1])
-- Additional topics via numbered forms
for i = 2, 10 do
add(args[i])
add(args['t' .. i])
add(args['topic' .. i])
end
return topics
end
function p.main(frame)
local args = require('Module:Arguments').getArgs(frame)
local topics = collectTopics(args)
local multipleTopics = #topics > 1
local restrictions = {} -- A list of which restrictions are enabled for easier iteration
local restrictionFlags = {} -- Track which restrictions are enabled, as a set
local currentTitleObject = mw.title.getCurrentTitle()
local subjectTitleObject = currentTitleObject.subjectPageTitle
local underRestrictions -- a boolean for whether there are any active restrictions
local articleOrPage -- the string "article" (if a mainspace page) or "page" (if not)
local protectionLevel -- the edit protection level
local messageBody
--[[
This area sets active restrictions
The end goal is to get the restrictions variable into a nice, neat, sorted list of which restrictions are active
This is a somewhat intense process
--]]
-- Helpers to add a restriction if it's active and hasn't been added yet
local function addRestriction(restriction, bypassLookup)
if yesno(args[restriction]) or bypassLookup then
restrictionFlags[restriction] = true
end
end
local function maybeAddRestriction(restriction) return addRestriction(restriction, false) end
local function alwaysAddRestriction(restriction) return addRestriction(restriction, true) end
-- Add the always-available restrictions
for _, r in ipairs(standardSet) do
maybeAddRestriction(r)
end
-- Topic-based restrictions
for _, topic in ipairs(topics) do
local topicWide = restrictionsDatabase["topic-wide"][topic]
if topicWide then
for _, restriction in ipairs(topicWide) do
alwaysAddRestriction(restriction)
end
end
local additional = restrictionsDatabase["additional-available"][topic]
if additional then
for _, restriction in ipairs(additional) do
maybeAddRestriction(restriction)
end
end
end
-- Add the protection level
protectionLevel = subjectTitleObject.protectionLevels["edit"][1]
if protectionLevel then
-- we have page protection
-- so we check if ECR is active, and if so only care about full protection
if restrictionFlags["ECR"] then
if protectionLevel == "full" then alwaysAddRestriction("full") end
else
alwaysAddRestriction(protectionLevel)
end
end
--[[
Clear duplicate restrictions (e.g. 0RR and 1RR; 1RR and 1RR-nocat, etc; consensus-required is stronger than BRD)
--]]
-- helper function which clears all revert rules, except for the given one
local function clearOtherRevertRules(rr)
restrictionFlags["0RR"] = nil
restrictionFlags["0RR-nocat"] = nil
restrictionFlags["1RR"] = nil
restrictionFlags["1RR-nocat"] = nil
restrictionFlags[rr] = true
end
-- then use the most applicable revert rule
if restrictionFlags["0RR"] then
clearOtherRevertRules("0RR")
elseif restrictionFlags["0RR-nocat"] then
clearOtherRevertRules("0RR-nocat")
elseif restrictionFlags["1RR"] then
clearOtherRevertRules("1RR")
end
-- if we make it to this point, 1RR-nocat is the only one potentially enabled
-- so we don't need to disable the rest
-- clear BRD if consensus-required is enabled
if restrictionFlags["consensus-required"] then restrictionFlags["BRD"] = nil end
-- and finally, convert our set to a list to make it easy to work with
restrictions = setToList(restrictionFlags)
--[[
Restrictions are now all set. Here, we add additional helper functions and variables necessary for generating the banner
--]]
-- Check whether any of the added restrictions are enabled
underRestrictions = #restrictions > 0
-- Determines whether we should use the string "article" or "page"
local articleOrPage = currentTitleObject:inNamespaces(1) and "article" or "page"
-- Makes a bullet point for a given contentious topic
local function makeTopicBulletPoint(code)
topicBlurb = frame:expandTemplate{ title = "Contentious topics/list", args = { scope=code } }
if topicBlurb == '' then
return '' -- maybe throw an error?
else
return '* <b>' .. topicBlurb .. '</b>\n'
end
end
-- Makes a restriction bullet point
local function makeRestrictionBulletPoint(code)
local def = restrictionsDefinition[code]
return def and ('* <b>' .. def .. '</b>\n') or ''
end
--[[
Begin building the messageBody
--]]
messageBody = '<p><b>The [[Wikipedia:Contentious topics|contentious topics]] procedure applies to this '
.. articleOrPage .. '.</b>'
.. (yesno(args.section) and (' Parts of this ' .. articleOrPage .. ' relate ') or (' This ' .. articleOrPage .. ' relates '))
if multipleTopics then
messageBody = messageBody .. 'to the following contentious topics:</p>\n'
for _, topic in ipairs(topics) do
messageBody = messageBody .. makeTopicBulletPoint(topic)
end
else
messageBody = messageBody .. 'to <b>'
.. frame:expandTemplate{ title = "Contentious topics/list", args = { scope=topics[1] } }
.. '</b>, a contentious topic.</p>'
end
if underRestrictions then
messageBody = '<strong style="text-transform: uppercase;">Warning: active arbitration remedies</strong>'
.. messageBody
.. '<p style="text-decoration:underline; text-align:center; font-size:120%;">The following restrictions apply to everyone editing this ' .. articleOrPage .. ':</p>\n'
for _, restriction in ipairs(restrictions) do
messageBody = messageBody .. makeRestrictionBulletPoint(restriction)
end
end
messageBody = messageBody .. ((yesno(args.brief) and '<p>Editors who repeatedly or seriously fail to adhere to the [[WP:Five pillars|purpose of Wikipedia]], any expected [[WP:Etiquette|standards of behaviour]], '
.. 'or any [[WP:List of policies|normal editorial process]] may be blocked or restricted by an administrator. '
.. 'Editors are advised to familiarise themselves with the [[Wikipedia:Contentious topics|contentious topics procedures]] before editing this page.</p>')
or '<p>Please consult the [[Wikipedia:Contentious topics|procedures]] and edit carefully.</p>')
.. (yesno(args.section) and '<p>If it is unclear which parts of the page are related to this contentious topic, the content in question should be marked within the wiki text by an invisible comment.'
.. 'If no comment is present, please ask an administrator for assistance. If in doubt it is better to assume that the content is covered.</p>' or '')
local messageBox = require('Module:Message box').main("tmbox", {
["type"] = underRestrictions and "delete" or "content",
["small"] = yesno(args.small),
["image"] = "[[File:Commons-emblem-"
.. (underRestrictions and "hand" or "issue")
.. ".svg|"
.. (yesno(args.small) and "30" or "40")
.. "px]]",
["text"] = messageBody
})
return messageBox
end
return p