Module:Documentation: Difference between revisions

Content deleted Content added
No edit summary
Tag: Reverted
No edit summary
Tag: Manual revert
 
Line 1:
-- This module implements {{pp-metadocumentation}} and its daughter templates such as.
-- {{pp-dispute}}, {{pp-vandalism}} and {{pp-sock}}.
 
-- InitialiseGet necessaryrequired modules.
local getArgs = require('strictModule:Arguments').getArgs
local makeFileLink = require('Module:File link')._main
local effectiveProtectionLevel = require('Module:Effective protection level')._main
local effectiveProtectionExpiry = require('Module:Effective protection expiry')._main
local yesno = require('Module:Yesno')
 
-- Get the config table.
-- Lazily initialise modules and objects we don't always need.
local cfg = mw.loadData('Module:Documentation/config')
local getArgs, makeMessageBox, lang
 
local p = {}
-- Set constants.
local CONFIG_MODULE = 'Module:Protection banner/config'
 
-- Often-used functions.
--------------------------------------------------------------------------------
local ugsub = mw.ustring.gsub
local format = mw.ustring.format
 
----------------------------------------------------------------------------
-- Helper functions
--
--------------------------------------------------------------------------------
-- These are defined as local functions, but are made available in the p
-- table for testing purposes.
----------------------------------------------------------------------------
 
local function makeCategoryLinkmessage(catcfgKey, sortvalArray, expectType)
--[[
if cat then
-- Gets a message from the cfg table and formats it if appropriate.
return string.format(
-- The function raises an error if the value from the cfg table is not
'[[%s:%s|%s]]',
-- of the type expectType. The default type for expectType is 'string'.
mw.site.namespaces[14].name,
-- If the table valArray is present, strings such as $1, $2 etc. in the
cat,
-- message are substituted with values from the table keys [1], [2] etc.
sort
-- For example, if the message "foo-message" had the value 'Foo $2 bar $1.',
)
-- message('foo-message', {'baz', 'qux'}) would return "Foo qux bar baz."
--]]
local msg = cfg[cfgKey]
expectType = expectType or 'string'
if type(msg) ~= expectType then
error('message: type error in message cfg.' .. cfgKey .. ' (' .. expectType .. ' expected, got ' .. type(msg) .. ')', 2)
end
if not valArray then
return msg
end
end
 
local function getMessageVal(match)
-- Validation function for the expiry and the protection date
match = tonumber(match)
local function validateDate(dateString, dateType)
return valArray[match] or error('message: no value found for key $' .. match .. ' in message cfg.' .. cfgKey, 4)
if not lang then
lang = mw.language.getContentLanguage()
end
local success, result = pcall(lang.formatDate, lang, 'U', dateString)
if success then
result = tonumber(result)
if result then
return result
end
end
error(string.format(
'invalid %s: %s',
dateType,
tostring(dateString)
), 4)
end
 
return ugsub(msg, '$([1-9][0-9]*)', getMessageVal)
local function makeFullUrl(page, query, display)
return string.format(
'[%s %s]',
tostring(mw.uri.fullUrl(page, query)),
display
)
end
 
p.message = message
-- Given a directed graph formatted as node -> table of direct successors,
 
-- get a table of all nodes reachable from a given node (though always
local function makeWikilink(page, display)
-- including the given node).
if display then
local function getReachableNodes(graph, start)
return format('[[%s|%s]]', page, display)
local toWalk, retval = {[start] = true}, {}
else
while true do
return format('[[%s]]', page)
-- Can't use pairs() since we're adding and removing things as we're iterating
local k = next(toWalk) -- This always gets the "first" key
if k == nil then
return retval
end
toWalk[k] = nil
retval[k] = true
for _,v in ipairs(graph[k]) do
if not retval[v] then
toWalk[v] = true
end
end
end
end
 
p.makeWikilink = makeWikilink
--------------------------------------------------------------------------------
-- Protection class
--------------------------------------------------------------------------------
 
local function makeCategoryLink(cat, sort)
local Protection = {}
local catns = mw.site.namespaces[14].name
Protection.__index = Protection
return makeWikilink(catns .. ':' .. cat, sort)
end
 
p.makeCategoryLink = makeCategoryLink
Protection.supportedActions = {
edit = true,
move = true,
autoreview = true,
upload = true
}
 
local function makeUrlLink(url, display)
Protection.bannerConfigFields = {
return format('[%s %s]', url, display)
'text',
end
'explanation',
'tooltip',
'alt',
'link',
'image'
}
 
p.makeUrlLink = makeUrlLink
function Protection.new(args, cfg, title)
local obj = {}
obj._cfg = cfg
obj.title = title or mw.title.getCurrentTitle()
 
local function makeToolbar(...)
-- Set action
local ret = {}
if not args.action then
local lim = select('#', ...)
obj.action = 'edit'
if lim < 1 then
elseif Protection.supportedActions[args.action] then
return nil
obj.action = args.action
else
error(string.format(
'invalid action: %s',
tostring(args.action)
), 3)
end
for i = 1, lim do
 
ret[#ret + 1] = select(i, ...)
-- Set level
obj.level = args.demolevel or effectiveProtectionLevel(obj.action, obj.title)
if not obj.level or (obj.action == 'move' and obj.level == 'autoconfirmed') then
-- Users need to be autoconfirmed to move pages anyway, so treat
-- semi-move-protected pages as unprotected.
obj.level = '*'
end
-- 'documentation-toolbar'
return format(
'<span class="%s">(%s)</span>',
message('toolbar-class'),
table.concat(ret, ' &#124; ')
)
end
 
p.makeToolbar = makeToolbar
-- Set expiry
local effectiveExpiry = effectiveProtectionExpiry(obj.action, obj.title)
if effectiveExpiry == 'infinity' then
obj.expiry = 'indef'
elseif effectiveExpiry ~= 'unknown' then
obj.expiry = validateDate(effectiveExpiry, 'expiry date')
end
 
----------------------------------------------------------------------------
-- Set reason
-- Argument processing
if args[1] then
----------------------------------------------------------------------------
obj.reason = mw.ustring.lower(args[1])
if obj.reason:find('|') then
error('reasons cannot contain the pipe character ("|")', 3)
end
end
 
local function makeInvokeFunc(funcName)
-- Set protection date
return function (frame)
if args.date then
local args = getArgs(frame, {
obj.protectionDate = validateDate(args.date, 'protection date')
valueFunc = function (key, value)
end
if type(value) == 'string' then
value = value:match('^%s*(.-)%s*$') -- Remove whitespace.
-- Set banner config
if key == 'heading' or value ~= '' then
do
return value
obj.bannerConfig = {}
else
local configTables = {}
return nil
if cfg.banners[obj.action] then
end
configTables[#configTables + 1] = cfg.banners[obj.action][obj.reason]
end else
return value
if cfg.defaultBanners[obj.action] then
configTables[#configTables + 1] = cfg.defaultBanners[obj.action][obj.level]
configTables[#configTables + 1] = cfg.defaultBanners[obj.action].default
end
configTables[#configTables + 1] = cfg.masterBanner
for i, field in ipairs(Protection.bannerConfigFields) do
for j, t in ipairs(configTables) do
if t[field] then
obj.bannerConfig[field] = t[field]
break
end
end
end})
return p[funcName](args)
end
return setmetatable(obj, Protection)
end
 
----------------------------------------------------------------------------
function Protection:isUserScript()
-- Entry points
-- 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
 
function Protection:isProtectedp.nonexistent(frame)
if mw.title.getCurrentTitle().subpageText == 'testcases' then
return self.level ~= '*'
return frame:expandTemplate{title = 'module test cases notice'}
else
return p.main(frame)
end
end
 
p.main = makeInvokeFunc('_main')
function Protection:shouldShowLock()
-- Whether we should output a banner/padlock
return self:isProtected() and not self:isUserScript()
end
 
function p._main(args)
-- Whether this page needs a protection category.
--[[
Protection.shouldHaveProtectionCategory = Protection.shouldShowLock
-- This function defines logic flow for the module.
 
-- @args - table of arguments passed by the user
function Protection:isTemporary()
--]]
return type(self.expiry) == 'number'
local env = p.getEnvironment(args)
local root = mw.html.create()
root
:wikitext(p._getModuleWikitext(args, env))
:wikitext(p.protectionTemplate(env))
:wikitext(p.sandboxNotice(args, env))
:tag('div')
-- 'documentation-container'
:addClass(message('container'))
:attr('role', 'complementary')
:attr('aria-labelledby', args.heading ~= '' and 'documentation-heading' or nil)
:attr('aria-label', args.heading == '' and 'Documentation' or nil)
:newline()
:tag('div')
-- 'documentation'
:addClass(message('main-div-classes'))
:newline()
:wikitext(p._startBox(args, env))
:wikitext(p._content(args, env))
:tag('div')
-- 'documentation-clear'
:addClass(message('clear'))
:done()
:newline()
:done()
:wikitext(p._endBox(args, env))
:done()
:wikitext(p.addTrackingCategories(env))
-- 'Module:Documentation/styles.css'
return mw.getCurrentFrame():extensionTag (
'templatestyles', '', {src=cfg['templatestyles']
}) .. tostring(root)
end
 
----------------------------------------------------------------------------
function Protection:makeProtectionCategory()
-- Environment settings
if not self:shouldHaveProtectionCategory() then
----------------------------------------------------------------------------
return ''
end
 
local cfg = self._cfg
local title = self.title
-- Get the expiry key fragment.
local expiryFragment
if self.expiry == 'indef' then
expiryFragment = self.expiry
elseif type(self.expiry) == 'number' then
expiryFragment = 'temp'
end
 
-- Get the namespace key fragment.
local namespaceFragment = cfg.categoryNamespaceKeys[title.namespace]
if not namespaceFragment and title.namespace % 2 == 1 then
namespaceFragment = 'talk'
end
 
-- 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
-- position in the cfg.protectionCategories table.
local order = {
{val = expiryFragment, keypos = 1},
{val = namespaceFragment, keypos = 2},
{val = self.reason, keypos = 3},
{val = self.level, keypos = 4},
{val = self.action, keypos = 5}
}
 
function p.getEnvironment(args)
--[[
-- Returns a table with information about the environment, including title
-- The old protection templates used an ad-hoc protection category system,
-- objects and other namespace- or path-related data.
-- with some templates prioritising namespaces in their categories, and
-- @args - table of arguments passed by the user
-- others prioritising the protection reason. To emulate this in this module
--
-- we use the config table cfg.reasonsWithNamespacePriority to set the
-- Title objects include:
-- reasons for which namespaces have priority over protection reason.
-- env.title - the page we are making documentation for (usually the current title)
-- If we are dealing with one of those reasons, move the namespace table to
-- env.templateTitle - the template (or module, file, etc.)
-- the end of the order table, i.e. give it highest priority. If not, the
-- env.docTitle - the /doc subpage.
-- reason should have highest priority, so move that to the end of the table
-- env.sandboxTitle - the /sandbox subpage.
-- instead.
-- env.testcasesTitle - the /testcases subpage.
--]]
table.insert(order, table.remove(order, self.reason and cfg.reasonsWithNamespacePriority[self.reason] and 2 or 3))
--[[
-- Define the attempt order. Inactive subtables (subtables with nil "value"
-- fields) are moved to the end, where they will later be given the key
-- "all". This is to cut down on the number of table lookups in
-- cfg.protectionCategories, which grows exponentially with the number of
-- non-nil keys. We keep track of the number of active subtables with the
-- noActive parameter.
--]]
local noActive, attemptOrder
do
local active, inactive = {}, {}
for i, t in ipairs(order) 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 key fragments we are
-- given, that match will be found first. If not, we keep trying different
-- key fragment combinations until we match using the key
-- "all-all-all-all-all".
--
-- Data includes:
-- To generate the keys, we index the key subtables using a binary matrix
-- env.protectionLevels - the protection levels table of the title object.
-- with indexes i and j. j is only calculated up to the number of active
-- env.subjectSpace - the number of the title's subject namespace.
-- subtables. For example, if there were three active subtables, the matrix
-- env.docSpace - the number of the namespace the title puts its documentation in.
-- would look like this, with 0 corresponding to the key fragment "all", and
-- env.docpageBase - the text of the base page of the /doc, /sandbox and /testcases pages, with namespace.
-- 1 corresponding to other key fragments.
-- env.compareUrl - URL of the Special:ComparePages page comparing the sandbox with the template.
--
-- All table lookups are passed through pcall so that errors are caught. If an error occurs, the value
-- j 1 2 3
-- ireturned will be nil.
-- 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 subtables are set
-- to the string "all".
--
-- A key for cfg.protectionCategories is constructed for each value of i.
-- The position of the value in the key is determined by the keypos field in
-- each subtable.
--]]
local cats = cfg.protectionCategories
local env, envFuncs = {}, {}
for i = 1, 2^noActive do
 
local key = {}
-- Set up the metatable. If triggered we call the corresponding function in the envFuncs table. The value
for j, t in ipairs(attemptOrder) do
-- returned by that function is memoized in the env table so that we don't call any of the functions
if j > noActive then
-- more than once. (Nils won't be memoized.)
key[t.keypos] = 'all'
setmetatable(env, {
else
local quotient__index = i / 2 ^function (j -t, 1key)
local envFunc = envFuncs[key]
quotient = math.ceil(quotient)
if quotient % 2 == 1envFunc then
local success, val = pcall(envFunc)
key[t.keypos] = t.val
elseif success then
keyenv[t.keyposkey] = 'all'val -- Memoise the value.
return val
end
end
return nil
end
})
key = table.concat(key, '|')
 
local attempt = cats[key]
function envFuncs.title()
if attempt then
-- The title object for the current page, or a test page passed with args.page.
return makeCategoryLink(attempt, title.text)
local title
local titleArg = args.page
if titleArg then
title = mw.title.new(titleArg)
else
title = mw.title.getCurrentTitle()
end
return title
end
return ''
end
 
function Protection:isIncorrectenvFuncs.templateTitle()
--[[
local expiry = self.expiry
-- The template (or module, etc.) title object.
return not self:shouldHaveProtectionCategory()
-- Messages:
or type(expiry) == 'number' and expiry < os.time()
-- 'sandbox-subpage' --> 'sandbox'
end
-- 'testcases-subpage' --> 'testcases'
--]]
local subjectSpace = env.subjectSpace
local title = env.title
local subpage = title.subpageText
if subpage == message('sandbox-subpage') or subpage == message('testcases-subpage') or (subpage == message('doc-subpage') and mw.title.getCurrentTitle().namespace == env.docSpace) then
return mw.title.makeTitle(subjectSpace, title.baseText)
else
return mw.title.makeTitle(subjectSpace, title.text)
end
end
 
function Protection:isTemplateProtectedNonTemplateenvFuncs.docTitle()
--[[
local action, namespace = self.action, self.title.namespace
-- Title object of the /doc subpage.
return self.level == 'templateeditor'
-- Messages:
and (
-- 'doc-subpage' --> 'doc'
(action ~= 'edit' and action ~= 'move')
--]]
or (namespace ~= 10 and namespace ~= 828)
local title = env.title
)
local docname = args[1] -- User-specified doc page.
end
local docpage
if docname then
docpage = docname
else
docpage = env.docpageBase .. '/' .. message('doc-subpage')
end
return mw.title.new(docpage)
end
function envFuncs.sandboxTitle()
--[[
-- Title object for the /sandbox subpage.
-- Messages:
-- 'sandbox-subpage' --> 'sandbox'
--]]
return mw.title.new(env.docpageBase .. '/' .. message('sandbox-subpage'))
end
function envFuncs.testcasesTitle()
--[[
-- Title object for the /testcases subpage.
-- Messages:
-- 'testcases-subpage' --> 'testcases'
--]]
return mw.title.new(env.docpageBase .. '/' .. message('testcases-subpage'))
end
 
function Protection:makeCategoryLinksenvFuncs.protectionLevels()
-- The protection levels table of the title object.
local msg = self._cfg.msg
return env.title.protectionLevels
local ret = {self:makeProtectionCategory()}
if self:isIncorrect() then
ret[#ret + 1] = makeCategoryLink(
msg['tracking-category-incorrect'],
self.title.text
)
end
 
if self:isTemplateProtectedNonTemplate() then
function envFuncs.subjectSpace()
ret[#ret + 1] = makeCategoryLink(
-- The subject namespace number.
msg['tracking-category-template'],
return mw.site.namespaces[env.title.namespace].subject.id
self.title.text
)
end
return table.concat(ret)
end
 
function envFuncs.docSpace()
--------------------------------------------------------------------------------
-- The documentation namespace number. For most namespaces this is the
-- Blurb class
-- same as the subject namespace. However, pages in the Article, File,
--------------------------------------------------------------------------------
-- MediaWiki or Category namespaces must have their /doc, /sandbox and
-- /testcases pages in talk space.
local subjectSpace = env.subjectSpace
if subjectSpace == 0 or subjectSpace == 6 or subjectSpace == 8 or subjectSpace == 14 then
return subjectSpace + 1
else
return subjectSpace
end
end
 
function envFuncs.docpageBase()
local Blurb = {}
-- The base page of the /doc, /sandbox, and /testcases subpages.
Blurb.__index = Blurb
-- For some namespaces this is the talk page, rather than the template page.
local templateTitle = env.templateTitle
local docSpace = env.docSpace
local docSpaceText = mw.site.namespaces[docSpace].name
-- Assemble the link. docSpace is never the main namespace, so we can hardcode the colon.
return docSpaceText .. ':' .. templateTitle.text
end
function envFuncs.compareUrl()
-- Diff link between the sandbox and the main template using [[Special:ComparePages]].
local templateTitle = env.templateTitle
local sandboxTitle = env.sandboxTitle
if templateTitle.exists and sandboxTitle.exists then
local compareUrl = mw.uri.canonicalUrl(
'Special:ComparePages',
{ page1 = templateTitle.prefixedText, page2 = sandboxTitle.prefixedText}
)
return tostring(compareUrl)
else
return nil
end
end
 
return env
Blurb.bannerTextFields = {
end
text = true,
explanation = true,
tooltip = true,
alt = true,
link = true
}
 
----------------------------------------------------------------------------
function Blurb.new(protectionObj, args, cfg)
-- Auxiliary templates
return setmetatable({
----------------------------------------------------------------------------
_cfg = cfg,
_protectionObj = protectionObj,
_args = args
}, Blurb)
end
 
p.getModuleWikitext = makeInvokeFunc('_getModuleWikitext')
-- Private methods --
 
function Blurb:_formatDatep._getModuleWikitext(numargs, env)
local currentTitle = mw.title.getCurrentTitle()
-- Formats a Unix timestamp into dd Month, YYYY format.
if currentTitle.contentModel ~= 'Scribunto' then return end
lang = lang or mw.language.getContentLanguage()
pcall(require, currentTitle.prefixedText) -- if it fails, we don't care
local success, date = pcall(
local moduleWikitext = package.loaded["Module:Module wikitext"]
lang.formatDate,
if moduleWikitext then
lang,
return moduleWikitext.main()
self._cfg.msg['expiry-date-format'] or 'j F Y',
'@' .. tostring(num)
)
if success then
return date
end
end
 
function Blurb:_getExpandedMessagep.sandboxNotice(msgKeyargs, env)
--[=[
return self:_substituteParameters(self._cfg.msg[msgKey])
-- Generates a sandbox notice for display above sandbox pages.
end
-- @args - a table of arguments passed by the user
 
-- @env - environment table containing title objects, etc., generated with p.getEnvironment
function Blurb:_substituteParameters(msg)
--
if not self._params then
-- Messages:
local parameterFuncs = {}
-- 'sandbox-notice-image' --> '[[File:Sandbox.svg|50px|alt=|link=]]'
 
-- 'sandbox-notice-blurb' --> 'This is the $1 for $2.'
parameterFuncs.CURRENTVERSION = self._makeCurrentVersionParameter
-- 'sandbox-notice-diff-blurb' --> 'This is the $1 for $2 ($3).'
parameterFuncs.EDITREQUEST = self._makeEditRequestParameter
-- 'sandbox-notice-pagetype-template' --> '[[Wikipedia:Template test cases|template sandbox]] page'
parameterFuncs.EXPIRY = self._makeExpiryParameter
-- 'sandbox-notice-pagetype-module' --> '[[Wikipedia:Template test cases|module sandbox]] page'
parameterFuncs.EXPLANATIONBLURB = self._makeExplanationBlurbParameter
-- 'sandbox-notice-pagetype-other' --> 'sandbox page'
parameterFuncs.IMAGELINK = self._makeImageLinkParameter
-- 'sandbox-notice-compare-link-display' --> 'diff'
parameterFuncs.INTROBLURB = self._makeIntroBlurbParameter
-- 'sandbox-notice-testcases-blurb' --> 'See also the companion subpage for $1.'
parameterFuncs.INTROFRAGMENT = self._makeIntroFragmentParameter
-- 'sandbox-notice-testcases-link-display' --> 'test cases'
parameterFuncs.PAGETYPE = self._makePagetypeParameter
-- 'sandbox-category' --> 'Template sandboxes'
parameterFuncs.PROTECTIONBLURB = self._makeProtectionBlurbParameter
-- 'module-sandbox-category' --> 'Module sandboxes'
parameterFuncs.PROTECTIONDATE = self._makeProtectionDateParameter
-- 'other-sandbox-category' --> 'Sandboxes outside of template or module namespace'
parameterFuncs.PROTECTIONLEVEL = self._makeProtectionLevelParameter
--]=]
parameterFuncs.PROTECTIONLOG = self._makeProtectionLogParameter
local title = env.title
parameterFuncs.TALKPAGE = self._makeTalkPageParameter
local sandboxTitle = env.sandboxTitle
parameterFuncs.TOOLTIPBLURB = self._makeTooltipBlurbParameter
local templateTitle = env.templateTitle
parameterFuncs.TOOLTIPFRAGMENT = self._makeTooltipFragmentParameter
local subjectSpace = env.subjectSpace
parameterFuncs.VANDAL = self._makeVandalTemplateParameter
if not (subjectSpace and title and sandboxTitle and templateTitle
and mw.title.equals(title, sandboxTitle)) then
self._params = setmetatable({}, {
return nil
__index = function (t, k)
local param
if parameterFuncs[k] then
param = parameterFuncs[k](self)
end
param = param or ''
t[k] = param
return param
end
})
end
-- Build the table of arguments to pass to {{ombox}}. We need just two fields, "image" and "text".
local omargs = {}
msg = msg:gsub('${(%u+)}', self._params)
omargs.image = message('sandbox-notice-image')
return msg
-- Get the text. We start with the opening blurb, which is something like
end
-- "This is the template sandbox for [[Template:Foo]] (diff)."
 
local text = '__EXPECTUNUSEDTEMPLATE__'
function Blurb:_makeCurrentVersionParameter()
local pagetype, sandboxCat
-- A link to the page history or the move log, depending on the kind of
if subjectSpace == 10 then
-- protection.
pagetype = message('sandbox-notice-pagetype-template')
local pagename = self._protectionObj.title.prefixedText
sandboxCat = message('sandbox-category')
if self._protectionObj.action == 'move' then
elseif subjectSpace == 828 then
-- We need the move log link.
pagetype = message('sandbox-notice-pagetype-module')
return makeFullUrl(
sandboxCat = message('module-sandbox-category')
'Special:Log',
{type = 'move', page = pagename},
self:_getExpandedMessage('current-version-move-display')
)
else
pagetype = message('sandbox-notice-pagetype-other')
-- We need the history link.
sandboxCat = message('other-sandbox-category')
return makeFullUrl(
end
pagename,
local templateLink = makeWikilink(templateTitle.prefixedText)
{action = 'history'},
local compareUrl = env.compareUrl
self:_getExpandedMessage('current-version-edit-display')
if compareUrl then
)
local compareDisplay = message('sandbox-notice-compare-link-display')
local compareLink = makeUrlLink(compareUrl, compareDisplay)
text = text .. message('sandbox-notice-diff-blurb', {pagetype, templateLink, compareLink})
else
text = text .. message('sandbox-notice-blurb', {pagetype, templateLink})
end
-- Get the test cases page blurb if the page exists. This is something like
end
-- "See also the companion subpage for [[Template:Foo/testcases|test cases]]."
 
local testcasesTitle = env.testcasesTitle
function Blurb:_makeEditRequestParameter()
if testcasesTitle and testcasesTitle.exists then
local mEditRequest = require('Module:Submit an edit request')
if testcasesTitle.contentModel == "Scribunto" then
local action = self._protectionObj.action
local testcasesLinkDisplay = message('sandbox-notice-testcases-link-display')
local level = self._protectionObj.level
local testcasesRunLinkDisplay = message('sandbox-notice-testcases-run-link-display')
local testcasesLink = makeWikilink(testcasesTitle.prefixedText, testcasesLinkDisplay)
-- Get the edit request type.
local testcasesRunLink = makeWikilink(testcasesTitle.talkPageTitle.prefixedText, testcasesRunLinkDisplay)
local requestType
text = text .. '<br />' .. message('sandbox-notice-testcases-run-blurb', {testcasesLink, testcasesRunLink})
if action == 'edit' then
else
if level == 'autoconfirmed' then
local testcasesLinkDisplay = message('sandbox-notice-testcases-link-display')
requestType = 'semi'
local testcasesLink = makeWikilink(testcasesTitle.prefixedText, testcasesLinkDisplay)
elseif level == 'extendedconfirmed' then
text = text .. '<br />' .. message('sandbox-notice-testcases-blurb', {testcasesLink})
requestType = 'extended'
elseif level == 'templateeditor' then
requestType = 'template'
end
end
requestType = requestType or 'full'
-- GetAdd the displaysandbox valueto the sandbox category.
omargs.text = text .. makeCategoryLink(sandboxCat)
local display = self:_getExpandedMessage('edit-request-display')
 
-- 'documentation-clear'
return mEditRequest._link{type = requestType, display = display}
return '<div class="' .. message('clear') .. '"></div>'
.. require('Module:Message box').main('ombox', omargs)
end
 
function Blurb:_makeExpiryParameterp.protectionTemplate(env)
-- Generates the padlock icon in the top right.
local expiry = self._protectionObj.expiry
-- @env - environment table containing title objects, etc., generated with p.getEnvironment
if type(expiry) == 'number' then
-- Messages:
return self:_formatDate(expiry)
-- 'protection-template' --> 'pp-template'
-- 'protection-template-args' --> {docusage = 'yes'}
local protectionLevels = env.protectionLevels
if not protectionLevels then
return nil
end
local editProt = protectionLevels.edit and protectionLevels.edit[1]
local moveProt = protectionLevels.move and protectionLevels.move[1]
if editProt then
-- The page is edit-protected.
return require('Module:Protection banner')._main{
message('protection-reason-edit'), small = true
}
elseif moveProt and moveProt ~= 'autoconfirmed' then
-- The page is move-protected but not edit-protected. Exclude move
-- protection with the level "autoconfirmed", as this is equivalent to
-- no move protection at all.
return require('Module:Protection banner')._main{
action = 'move', small = true
}
else
return expirynil
end
end
 
----------------------------------------------------------------------------
function Blurb:_makeExplanationBlurbParameter()
-- Start box
-- Cover special cases first.
----------------------------------------------------------------------------
if self._protectionObj.title.namespace == 8 then
-- MediaWiki namespace
return self:_getExpandedMessage('explanation-blurb-nounprotect')
end
 
p.startBox = makeInvokeFunc('_startBox')
-- Get explanation blurb table keys
local action = self._protectionObj.action
local level = self._protectionObj.level
local talkKey = self._protectionObj.title.isTalkPage and 'talk' or 'subject'
 
function p._startBox(args, env)
-- Find the message in the explanation blurb table and substitute any
--[[
-- parameters.
-- This function generates the start box.
local explanations = self._cfg.explanationBlurbs
-- @args - a table of arguments passed by the user
local msg
-- @env - environment table containing title objects, etc., generated with p.getEnvironment
if explanations[action][level] and explanations[action][level][talkKey] then
--
msg = explanations[action][level][talkKey]
-- The actual work is done by p.makeStartBoxLinksData and p.renderStartBoxLinks which make
elseif explanations[action][level] and explanations[action][level].default then
-- the [view] [edit] [history] [purge] links, and by p.makeStartBoxData and p.renderStartBox
msg = explanations[action][level].default
-- which generate the box HTML.
elseif explanations[action].default and explanations[action].default[talkKey] then
--]]
msg = explanations[action].default[talkKey]
env = env or p.getEnvironment(args)
elseif explanations[action].default and explanations[action].default.default then
local links
msg = explanations[action].default.default
local content = args.content
else
if not content or args[1] then
error(string.format(
-- No need to include the links if the documentation is on the template page itself.
'could not find explanation blurb for action "%s", level "%s" and talk key "%s"',
local linksData = p.makeStartBoxLinksData(args, env)
action,
if linksData then
level,
links = p.renderStartBoxLinks(linksData)
talkKey
), 8)end
end
-- Generate the start box html.
return self:_substituteParameters(msg)
local data = p.makeStartBoxData(args, env, links)
end
if data then
 
return p.renderStartBox(data)
function Blurb:_makeImageLinkParameter()
local imageLinks = self._cfg.imageLinks
local action = self._protectionObj.action
local level = self._protectionObj.level
local msg
if imageLinks[action][level] then
msg = imageLinks[action][level]
elseif imageLinks[action].default then
msg = imageLinks[action].default
else
-- User specified no heading.
msg = imageLinks.edit.default
return nil
end
return self:_substituteParameters(msg)
end
 
function Blurb:_makeIntroBlurbParameterp.makeStartBoxLinksData(args, env)
--[[
if self._protectionObj:isTemporary() then
-- Does initial processing of data to make the [view] [edit] [history] [purge] links.
return self:_getExpandedMessage('intro-blurb-expiry')
-- @args - a table of arguments passed by the user
else
-- @env - environment table containing title objects, etc., generated with p.getEnvironment
return self:_getExpandedMessage('intro-blurb-noexpiry')
--
-- Messages:
-- 'view-link-display' --> 'view'
-- 'edit-link-display' --> 'edit'
-- 'history-link-display' --> 'history'
-- 'purge-link-display' --> 'purge'
-- 'module-preload' --> 'Template:Documentation/preload-module-doc'
-- 'docpage-preload' --> 'Template:Documentation/preload'
-- 'create-link-display' --> 'create'
--]]
local subjectSpace = env.subjectSpace
local title = env.title
local docTitle = env.docTitle
if not title or not docTitle then
return nil
end
if docTitle.isRedirect then
docTitle = docTitle.redirectTarget
end
end
 
-- Create link if /doc doesn't exist.
function Blurb:_makeIntroFragmentParameter()
local preload = args.preload
if self._protectionObj:isTemporary() then
if not preload then
return self:_getExpandedMessage('intro-fragment-expiry')
if subjectSpace == 828 then -- Module namespace
else
preload = message('module-preload')
return self:_getExpandedMessage('intro-fragment-noexpiry')
else
preload = message('docpage-preload')
end
end
return {
title = title,
docTitle = docTitle,
-- View, display, edit, and purge links if /doc exists.
viewLinkDisplay = message('view-link-display'),
editLinkDisplay = message('edit-link-display'),
historyLinkDisplay = message('history-link-display'),
purgeLinkDisplay = message('purge-link-display'),
preload = preload,
createLinkDisplay = message('create-link-display')
}
end
 
function Blurb:_makePagetypeParameterp.renderStartBoxLinks(data)
--[[
local pagetypes = self._cfg.pagetypes
-- Generates the [view][edit][history][purge] or [create][purge] links from the data table.
return pagetypes[self._protectionObj.title.namespace]
-- @data - a table of data generated by p.makeStartBoxLinksData
or pagetypes.default
--]]
or error('no default pagetype defined', 8)
local docTitle = data.docTitle
end
-- yes, we do intend to purge the template page on which the documentation appears
 
local purgeLink = makeWikilink("Special:Purge/" .. data.title.prefixedText, data.purgeLinkDisplay)
function Blurb:_makeProtectionBlurbParameter()
local protectionBlurbs = self._cfg.protectionBlurbs
if docTitle.exists then
local action = self._protectionObj.action
local viewLink = makeWikilink(docTitle.prefixedText, data.viewLinkDisplay)
local level = self._protectionObj.level
local editLink = makeWikilink("Special:EditPage/" .. docTitle.prefixedText, data.editLinkDisplay)
local msg
local historyLink = makeWikilink("Special:PageHistory/" .. docTitle.prefixedText, data.historyLinkDisplay)
if protectionBlurbs[action][level] then
return "&#91;" .. viewLink .. "&#93; &#91;" .. editLink .. "&#93; &#91;" .. historyLink .. "&#93; &#91;" .. purgeLink .. "&#93;"
msg = protectionBlurbs[action][level]
elseif protectionBlurbs[action].default then
msg = protectionBlurbs[action].default
elseif protectionBlurbs.edit.default then
msg = protectionBlurbs.edit.default
else
local createLink = makeUrlLink(docTitle:canonicalUrl{action = 'edit', preload = data.preload}, data.createLinkDisplay)
error('no protection blurb defined for protectionBlurbs.edit.default', 8)
return "&#91;" .. createLink .. "&#93; &#91;" .. purgeLink .. "&#93;"
end
return self:_substituteParameters(msg)ret
end
 
function p.makeStartBoxData(args, env, links)
function Blurb:_makeProtectionDateParameter()
--[=[
local protectionDate = self._protectionObj.protectionDate
-- Does initial processing of data to pass to the start-box render function, p.renderStartBox.
if type(protectionDate) == 'number' then
-- @args - a table of arguments passed by the user
return self:_formatDate(protectionDate)
-- @env - environment table containing title objects, etc., generated with p.getEnvironment
-- @links - a string containing the [view][edit][history][purge] links - could be nil if there's an error.
--
-- Messages:
-- 'documentation-icon-wikitext' --> '[[File:Test Template Info-Icon - Version (2).svg|50px|link=|alt=]]'
-- 'template-namespace-heading' --> 'Template documentation'
-- 'module-namespace-heading' --> 'Module documentation'
-- 'file-namespace-heading' --> 'Summary'
-- 'other-namespaces-heading' --> 'Documentation'
-- 'testcases-create-link-display' --> 'create'
--]=]
local subjectSpace = env.subjectSpace
if not subjectSpace then
-- Default to an "other namespaces" namespace, so that we get at least some output
-- if an error occurs.
subjectSpace = 2
end
local data = {}
-- Heading
local heading = args.heading -- Blank values are not removed.
if heading == '' then
-- Don't display the start box if the heading arg is defined but blank.
return nil
end
if heading then
data.heading = heading
elseif subjectSpace == 10 then -- Template namespace
data.heading = message('documentation-icon-wikitext') .. ' ' .. message('template-namespace-heading')
elseif subjectSpace == 828 then -- Module namespace
data.heading = message('documentation-icon-wikitext') .. ' ' .. message('module-namespace-heading')
elseif subjectSpace == 6 then -- File namespace
data.heading = message('file-namespace-heading')
else
data.heading = message('other-namespaces-heading')
return protectionDate
end
end
-- Heading CSS
 
local headingStyle = args['heading-style']
function Blurb:_makeProtectionLevelParameter()
if headingStyle then
local protectionLevels = self._cfg.protectionLevels
data.headingStyleText = headingStyle
local action = self._protectionObj.action
local level = self._protectionObj.level
local msg
if protectionLevels[action][level] then
msg = protectionLevels[action][level]
elseif protectionLevels[action].default then
msg = protectionLevels[action].default
elseif protectionLevels.edit.default then
msg = protectionLevels.edit.default
else
-- 'documentation-heading'
error('no protection level defined for protectionLevels.edit.default', 8)
data.headingClass = message('main-div-heading-class')
end
return self:_substituteParameters(msg)
-- Data for the [view][edit][history][purge] or [create] links.
if links then
-- 'mw-editsection-like plainlinks'
data.linksClass = message('start-box-link-classes')
data.links = links
end
return data
end
 
function Blurb:_makeProtectionLogParameterp.renderStartBox(data)
-- Renders the start box html.
local pagename = self._protectionObj.title.prefixedText
-- @data - a table of data generated by p.makeStartBoxData.
if self._protectionObj.action == 'autoreview' then
local sbox = mw.html.create('div')
-- We need the pending changes log.
sbox
return makeFullUrl(
-- 'documentation-startbox'
'Special:Log',
:addClass(message('start-box-class'))
{type = 'stable', page = pagename},
:newline()
self:_getExpandedMessage('pc-log-display')
:tag('span')
:addClass(data.headingClass)
else
:attr('id', 'documentation-heading')
-- We need the protection log.
:cssText(data.headingStyleText)
return makeFullUrl(
:wikitext(data.heading)
'Special:Log',
local links = data.links
{type = 'protect', page = pagename},
if links then
self:_getExpandedMessage('protection-log-display')
sbox:tag('span')
)
:addClass(data.linksClass)
:attr('id', data.linksId)
:wikitext(links)
end
return tostring(sbox)
end
 
----------------------------------------------------------------------------
function Blurb:_makeTalkPageParameter()
-- Documentation content
return string.format(
----------------------------------------------------------------------------
'[[%s:%s#%s|%s]]',
mw.site.namespaces[self._protectionObj.title.namespace].talk.name,
self._protectionObj.title.text,
self._args.section or 'top',
self:_getExpandedMessage('talk-page-link-display')
)
end
 
p.content = makeInvokeFunc('_content')
function Blurb:_makeTooltipBlurbParameter()
 
if self._protectionObj:isTemporary() then
function p._content(args, env)
return self:_getExpandedMessage('tooltip-blurb-expiry')
-- Displays the documentation contents
else
-- @args - a table of arguments passed by the user
return self:_getExpandedMessage('tooltip-blurb-noexpiry')
-- @env - environment table containing title objects, etc., generated with p.getEnvironment
env = env or p.getEnvironment(args)
local docTitle = env.docTitle
local content = args.content
if not content and docTitle and docTitle.exists then
content = args._content or mw.getCurrentFrame():expandTemplate{title = docTitle.prefixedText}
end
-- The line breaks below are necessary so that "=== Headings ===" at the start and end
-- of docs are interpreted correctly.
return '\n' .. (content or '') .. '\n'
end
 
p.contentTitle = makeInvokeFunc('_contentTitle')
function Blurb:_makeTooltipFragmentParameter()
 
if self._protectionObj:isTemporary() then
function p._contentTitle(args, env)
return self:_getExpandedMessage('tooltip-fragment-expiry')
env = env or p.getEnvironment(args)
local docTitle = env.docTitle
if not args.content and docTitle and docTitle.exists then
return docTitle.prefixedText
else
return ''
return self:_getExpandedMessage('tooltip-fragment-noexpiry')
end
end
 
----------------------------------------------------------------------------
function Blurb:_makeVandalTemplateParameter()
-- End box
return mw.getCurrentFrame():expandTemplate{
----------------------------------------------------------------------------
title="vandal-m",
args={self._args.user or self._protectionObj.title.baseText}
}
end
 
p.endBox = makeInvokeFunc('_endBox')
-- Public methods --
 
function Blurb:makeBannerTextp._endBox(keyargs, env)
--[=[
-- Validate input.
-- This function generates the end box (also known as the link box).
if not key or not Blurb.bannerTextFields[key] then
-- @args - a table of arguments passed by the user
error(string.format(
-- @env - environment table containing title objects, etc., generated with p.getEnvironment
'"%s" is not a valid banner config field',
--
tostring(key)
--]=]
), 2)
-- Get environment data.
env = env or p.getEnvironment(args)
local subjectSpace = env.subjectSpace
local docTitle = env.docTitle
if not subjectSpace or not docTitle then
return nil
end
 
-- Check whether we should output the end box at all. Add the end
-- Generate the text.
-- box by default if the documentation exists or if we are in the
local msg = self._protectionObj.bannerConfig[key]
-- user, module or template namespaces.
if type(msg) == 'string' then
local linkBox = args['link box']
return self:_substituteParameters(msg)
elseifif type(msg)linkBox == 'functionoff' then
or not (
msg = msg(self._protectionObj, self._args)
docTitle.exists
if type(msg) ~= 'string' then
or subjectSpace == 2
error(string.format(
or subjectSpace == 828
'bad output from banner config function with key "%s"'
or subjectSpace == 10
.. ' (expected string, got %s)',
)
tostring(key),
then
type(msg)
),return 4)nil
end
return self:_substituteParameters(msg)
end
end
 
-- Assemble the link box.
--------------------------------------------------------------------------------
local text = ''
-- BannerTemplate class
if linkBox then
--------------------------------------------------------------------------------
text = text .. linkBox
 
local BannerTemplate = {}
BannerTemplate.__index = BannerTemplate
 
function BannerTemplate.new(protectionObj, cfg)
local obj = {}
obj._cfg = cfg
 
-- Set the image filename.
local imageFilename = protectionObj.bannerConfig.image
if imageFilename then
obj._imageFilename = imageFilename
else
text = text .. (p.makeDocPageBlurb(args, env) or '') -- "This documentation is transcluded from [[Foo]]."
-- If an image filename isn't specified explicitly in the banner config,
if subjectSpace == 2 or subjectSpace == 10 or subjectSpace == 828 then
-- generate it from the protection status and the namespace.
-- We are in the user, template or module namespaces.
local action = protectionObj.action
-- Add sandbox and testcases links.
local level = protectionObj.level
-- "Editors can experiment in this template's sandbox and testcases pages."
local namespace = protectionObj.title.namespace
text = text .. (p.makeExperimentBlurb(args, env) or '') .. '<br />'
local reason = protectionObj.reason
if not args.content and not args[1] then
-- "Please add categories to the /doc subpage."
-- Deal with special cases first.
-- Don't show this message with inline docs or with an explicitly specified doc page,
if (
-- as then it is unclear where to add the categories.
namespace == 10
text = text .. (p.makeCategoriesBlurb(args, env) or '')
or namespace == 828
or reason and obj._cfg.indefImageReasons[reason]
)
and action == 'edit'
and level == 'sysop'
and not protectionObj:isTemporary()
then
-- Fully protected modules and templates get the special red "indef"
-- padlock.
obj._imageFilename = obj._cfg.msg['image-filename-indef']
else
-- Deal with regular protection types.
local images = obj._cfg.images
if images[action] then
if images[action][level] then
obj._imageFilename = images[action][level]
elseif images[action].default then
obj._imageFilename = images[action].default
end
end
text = text .. ' ' .. (p.makeSubpagesBlurb(args, env) or '') --"Subpages of this template"
end
end
return setmetatable(obj, BannerTemplate)
local box = mw.html.create('div')
end
-- 'documentation-metadata'
box:attr('role', 'note')
:addClass(message('end-box-class'))
-- 'plainlinks'
:addClass(message('end-box-plainlinks'))
:wikitext(text)
:done()
 
return '\n' .. tostring(box)
function BannerTemplate:renderImage()
local filename = self._imageFilename
or self._cfg.msg['image-filename-default']
or 'Transparent.gif'
return makeFileLink{
file = filename,
size = (self.imageWidth or 20) .. 'px',
alt = self._imageAlt,
link = self._imageLink,
caption = self.imageCaption
}
end
 
function p.makeDocPageBlurb(args, env)
--------------------------------------------------------------------------------
--[=[
-- Banner class
-- Makes the blurb "This documentation is transcluded from [[Template:Foo]] (edit, history)".
--------------------------------------------------------------------------------
-- @args - a table of arguments passed by the user
 
-- @env - environment table containing title objects, etc., generated with p.getEnvironment
local Banner = setmetatable({}, BannerTemplate)
--
Banner.__index = Banner
-- Messages:
 
-- 'edit-link-display' --> 'edit'
function Banner.new(protectionObj, blurbObj, cfg)
-- 'history-link-display' --> 'history'
local obj = BannerTemplate.new(protectionObj, cfg) -- This doesn't need the blurb.
-- 'transcluded-from-blurb' -->
obj.imageWidth = 40
-- 'The above [[Wikipedia:Template documentation|documentation]]
obj.imageCaption = blurbObj:makeBannerText('alt') -- Large banners use the alt text for the tooltip.
-- is [[Help:Transclusion|transcluded]] from $1.'
obj._reasonText = blurbObj:makeBannerText('text')
-- 'module-preload' --> 'Template:Documentation/preload-module-doc'
obj._explanationText = blurbObj:makeBannerText('explanation')
-- 'create-link-display' --> 'create'
obj._page = protectionObj.title.prefixedText -- Only makes a difference in testing.
-- 'create-module-doc-blurb' -->
return setmetatable(obj, Banner)
-- 'You might want to $1 a documentation page for this [[Wikipedia:Lua|Scribunto module]].'
--]=]
local docTitle = env.docTitle
if not docTitle then
return nil
end
if docTitle.exists then
-- /doc exists; link to it.
local docLink = makeWikilink(docTitle.prefixedText)
local editDisplay = message('edit-link-display')
local editLink = makeWikilink("Special:EditPage/" .. docTitle.prefixedText, editDisplay)
local historyDisplay = message('history-link-display')
local historyLink = makeWikilink("Special:PageHistory/" .. docTitle.prefixedText, historyDisplay)
return message('transcluded-from-blurb', {docLink})
.. ' '
.. makeToolbar(editLink, historyLink)
.. '<br />'
elseif env.subjectSpace == 828 then
-- /doc does not exist; ask to create it.
local createUrl = docTitle:canonicalUrl{action = 'edit', preload = message('module-preload')}
local createDisplay = message('create-link-display')
local createLink = makeUrlLink(createUrl, createDisplay)
return message('create-module-doc-blurb', {createLink})
.. '<br />'
end
end
 
function Banner:__tostringp.makeExperimentBlurb(args, env)
--[[
-- Renders the banner.
-- Renders the text "Editors can experiment in this template's sandbox (edit | diff) and testcases (edit) pages."
makeMessageBox = makeMessageBox or require('Module:Message box').main
-- @args - a table of arguments passed by the user
local reasonText = self._reasonText or error('no reason text set', 2)
-- @env - environment table containing title objects, etc., generated with p.getEnvironment
local explanationText = self._explanationText
--
local mbargs = {
-- Messages:
page = self._page,
-- 'sandbox-link-display' --> 'sandbox'
type = 'protection',
-- 'sandbox-edit-link-display' --> 'edit'
image = self:renderImage(),
-- 'compare-link-display' --> 'diff'
text = string.format(
-- 'module-sandbox-preload' --> 'Template:Documentation/preload-module-sandbox'
"'''%s'''%s",
-- 'template-sandbox-preload' --> 'Template:Documentation/preload-sandbox'
reasonText,
-- 'sandbox-create-link-display' --> 'create'
explanationText and '<br />' .. explanationText or ''
-- 'mirror-edit-summary' --> 'Create sandbox version of $1'
)
-- 'mirror-link-display' --> 'mirror'
}
-- 'mirror-link-preload' --> 'Template:Documentation/mirror'
return makeMessageBox('mbox', mbargs)
-- 'sandbox-link-display' --> 'sandbox'
-- 'testcases-link-display' --> 'testcases'
-- 'testcases-edit-link-display'--> 'edit'
-- 'template-sandbox-preload' --> 'Template:Documentation/preload-sandbox'
-- 'testcases-create-link-display' --> 'create'
-- 'testcases-link-display' --> 'testcases'
-- 'testcases-edit-link-display' --> 'edit'
-- 'module-testcases-preload' --> 'Template:Documentation/preload-module-testcases'
-- 'template-testcases-preload' --> 'Template:Documentation/preload-testcases'
-- 'experiment-blurb-module' --> 'Editors can experiment in this module's $1 and $2 pages.'
-- 'experiment-blurb-template' --> 'Editors can experiment in this template's $1 and $2 pages.'
--]]
local subjectSpace = env.subjectSpace
local templateTitle = env.templateTitle
local sandboxTitle = env.sandboxTitle
local testcasesTitle = env.testcasesTitle
local templatePage = templateTitle.prefixedText
if not subjectSpace or not templateTitle or not sandboxTitle or not testcasesTitle then
return nil
end
-- Make links.
local sandboxLinks, testcasesLinks
if sandboxTitle.exists then
local sandboxPage = sandboxTitle.prefixedText
local sandboxDisplay = message('sandbox-link-display')
local sandboxLink = makeWikilink(sandboxPage, sandboxDisplay)
local sandboxEditDisplay = message('sandbox-edit-link-display')
local sandboxEditLink = makeWikilink("Special:EditPage/" .. sandboxPage, sandboxEditDisplay)
local compareUrl = env.compareUrl
local compareLink
if compareUrl then
local compareDisplay = message('compare-link-display')
compareLink = makeUrlLink(compareUrl, compareDisplay)
end
sandboxLinks = sandboxLink .. ' ' .. makeToolbar(sandboxEditLink, compareLink)
else
local sandboxPreload
if subjectSpace == 828 then
sandboxPreload = message('module-sandbox-preload')
else
sandboxPreload = message('template-sandbox-preload')
end
local sandboxCreateUrl = sandboxTitle:canonicalUrl{action = 'edit', preload = sandboxPreload}
local sandboxCreateDisplay = message('sandbox-create-link-display')
local sandboxCreateLink = makeUrlLink(sandboxCreateUrl, sandboxCreateDisplay)
local mirrorSummary = message('mirror-edit-summary', {makeWikilink(templatePage)})
local mirrorPreload = message('mirror-link-preload')
local mirrorUrl = sandboxTitle:canonicalUrl{action = 'edit', preload = mirrorPreload, summary = mirrorSummary}
if subjectSpace == 828 then
mirrorUrl = sandboxTitle:canonicalUrl{action = 'edit', preload = templateTitle.prefixedText, summary = mirrorSummary}
end
local mirrorDisplay = message('mirror-link-display')
local mirrorLink = makeUrlLink(mirrorUrl, mirrorDisplay)
sandboxLinks = message('sandbox-link-display') .. ' ' .. makeToolbar(sandboxCreateLink, mirrorLink)
end
if testcasesTitle.exists then
local testcasesPage = testcasesTitle.prefixedText
local testcasesDisplay = message('testcases-link-display')
local testcasesLink = makeWikilink(testcasesPage, testcasesDisplay)
local testcasesEditUrl = testcasesTitle:canonicalUrl{action = 'edit'}
local testcasesEditDisplay = message('testcases-edit-link-display')
local testcasesEditLink = makeWikilink("Special:EditPage/" .. testcasesPage, testcasesEditDisplay)
-- for Modules, add testcases run link if exists
if testcasesTitle.contentModel == "Scribunto" and testcasesTitle.talkPageTitle and testcasesTitle.talkPageTitle.exists then
local testcasesRunLinkDisplay = message('testcases-run-link-display')
local testcasesRunLink = makeWikilink(testcasesTitle.talkPageTitle.prefixedText, testcasesRunLinkDisplay)
testcasesLinks = testcasesLink .. ' ' .. makeToolbar(testcasesEditLink, testcasesRunLink)
else
testcasesLinks = testcasesLink .. ' ' .. makeToolbar(testcasesEditLink)
end
else
local testcasesPreload
if subjectSpace == 828 then
testcasesPreload = message('module-testcases-preload')
else
testcasesPreload = message('template-testcases-preload')
end
local testcasesCreateUrl = testcasesTitle:canonicalUrl{action = 'edit', preload = testcasesPreload}
local testcasesCreateDisplay = message('testcases-create-link-display')
local testcasesCreateLink = makeUrlLink(testcasesCreateUrl, testcasesCreateDisplay)
testcasesLinks = message('testcases-link-display') .. ' ' .. makeToolbar(testcasesCreateLink)
end
local messageName
if subjectSpace == 828 then
messageName = 'experiment-blurb-module'
else
messageName = 'experiment-blurb-template'
end
return message(messageName, {sandboxLinks, testcasesLinks})
end
 
function p.makeCategoriesBlurb(args, env)
--------------------------------------------------------------------------------
--[[
-- Padlock class
-- Generates the text "Please add categories to the /doc subpage."
--------------------------------------------------------------------------------
-- @args - a table of arguments passed by the user
 
-- @env - environment table containing title objects, etc., generated with p.getEnvironment
local Padlock = setmetatable({}, BannerTemplate)
-- Messages:
Padlock.__index = Padlock
-- 'doc-link-display' --> '/doc'
 
-- 'add-categories-blurb' --> 'Please add categories to the $1 subpage.'
function Padlock.new(protectionObj, blurbObj, cfg)
--]]
local obj = BannerTemplate.new(protectionObj, cfg) -- This doesn't need the blurb.
local docTitle = env.docTitle
obj.imageWidth = 20
if not docTitle then
obj.imageCaption = blurbObj:makeBannerText('tooltip')
return nil
obj._imageAlt = blurbObj:makeBannerText('alt')
end
obj._imageLink = blurbObj:makeBannerText('link')
local docPathLink = makeWikilink(docTitle.prefixedText, message('doc-link-display'))
obj._indicatorName = cfg.padlockIndicatorNames[protectionObj.action]
return message('add-categories-blurb', {docPathLink})
or cfg.padlockIndicatorNames.default
or 'pp-default'
return setmetatable(obj, Padlock)
end
 
function Padlock:__tostringp.makeSubpagesBlurb(args, env)
--[[
local frame = mw.getCurrentFrame()
-- Generates the "Subpages of this template" link.
-- The nowiki tag helps prevent whitespace at the top of articles.
-- @args - a table of arguments passed by the user
return frame:extensionTag{name = 'nowiki'} .. frame:extensionTag{
-- @env - environment table containing title objects, etc., generated with p.getEnvironment
name = 'indicator',
args = {name = self._indicatorName},
content = self:renderImage()
}
end
 
--------------------------------------------------------------------------------
-- Exports
--------------------------------------------------------------------------------
 
local p = {}
 
function p._exportClasses()
-- This is used for testing purposes.
return {
Protection = Protection,
Blurb = Blurb,
BannerTemplate = BannerTemplate,
Banner = Banner,
Padlock = Padlock,
}
end
 
function p._main(args, cfg, title)
args = args or {}
cfg = cfg or require(CONFIG_MODULE)
 
local protectionObj = Protection.new(args, cfg, title)
 
local ret = {}
 
-- If a page's edit protection is equally or more restrictive than its
-- protection from some other action, then don't bother displaying anything
-- for the other action (except categories).
if not yesno(args.catonly) and (protectionObj.action == 'edit' or
args.demolevel or
not getReachableNodes(
cfg.hierarchy,
protectionObj.level
)[effectiveProtectionLevel('edit', protectionObj.title)])
then
-- Initialise the blurb object
local blurbObj = Blurb.new(protectionObj, args, cfg)
-- Messages:
-- Render the banner
-- 'template-pagetype' --> 'template'
if protectionObj:shouldShowLock() then
-- 'module-pagetype' --> 'module'
ret[#ret + 1] = tostring(
-- 'default-pagetype' --> 'page'
(yesno(args.small) and Padlock or Banner)
-- 'subpages-link-display' --> 'Subpages of this $1'
.new(protectionObj, blurbObj, cfg)
--]]
)
local subjectSpace = env.subjectSpace
end
local templateTitle = env.templateTitle
if not subjectSpace or not templateTitle then
return nil
end
local pagetype
 
if subjectSpace == 10 then
-- Render the categories
pagetype = message('template-pagetype')
if yesno(args.category) ~= false then
elseif subjectSpace == 828 then
ret[#ret + 1] = protectionObj:makeCategoryLinks()
pagetype = message('module-pagetype')
else
pagetype = message('default-pagetype')
end
local subpagesLink = makeWikilink(
'Special:PrefixIndex/' .. templateTitle.prefixedText .. '/',
-- For arbitration enforcement, flagging [[WP:PIA]] pages to enable [[Special:AbuseFilter/1339]] to flag edits to them
message('subpages-link-display', {pagetype})
if protectionObj.level == "extendedconfirmed" then
)
if require("Module:TableTools").inArray(protectionObj.title.talkPageTitle.categories, "Wikipedia pages subject to the extended confirmed restriction related to the Arab-Israeli conflict") then
return message('subpages-blurb', {subpagesLink})
ret[#ret + 1] = "<p class='PIA-flag' style='display:none; visibility:hidden;' title='This page is subject to the extended confirmed restriction related to the Arab-Israeli conflict.'></p>"
end
end
return table.concat(ret)
end
 
----------------------------------------------------------------------------
function p.main(frame, cfg)
-- Tracking categories
cfg = cfg or require(CONFIG_MODULE)
----------------------------------------------------------------------------
 
function p.addTrackingCategories(env)
-- Find default args, if any.
--[[
local parent = frame.getParent and frame:getParent()
-- Check if {{documentation}} is transcluded on a /doc or /testcases page.
local defaultArgs = parent and cfg.wrappers[parent:getTitle():gsub('/sandbox$', '')]
-- @env - environment table containing title objects, etc., generated with p.getEnvironment
 
-- Find user args, and use the parent frame if we are being called from a
-- Messages:
-- wrapper template.
-- 'display-strange-usage-category' --> true
getArgs = getArgs or require('Module:Arguments').getArgs
-- 'doc-subpage' --> 'doc'
local userArgs = getArgs(frame, {
-- 'testcases-subpage' --> 'testcases'
parentOnly = defaultArgs,
-- 'strange-usage-category' --> 'Wikipedia pages with strange ((documentation)) usage'
frameOnly = not defaultArgs
})--
-- /testcases pages in the module namespace are not categorised, as they may have
 
-- {{documentation}} transcluded automatically.
-- Build the args table. User-specified args overwrite default args.
--]]
local args = {}
local title = env.title
for k, v in pairs(defaultArgs or {}) do
local subjectSpace = env.subjectSpace
args[k] = v
if not title or not subjectSpace then
return nil
end
local subpage = title.subpageText
for k, v in pairs(userArgs) do
if message('display-strange-usage-category', nil, 'boolean')
args[k] = v
and (
subpage == message('doc-subpage')
or subjectSpace ~= 828 and subpage == message('testcases-subpage')
)
then
return makeCategoryLink(message('strange-usage-category'))
end
return p._main(args, cfg)''
end