Difference between revisions of "Module:Documentation"
Alynnidalar (talk | contribs) m (1 revision imported) |
Sahartionary>Benwing2 (handle lang-specific poscatboiler data modules such as Module:category tree/poscatboiler/data/lang-specific/ajp, rewrite documentation on `module_regex`, clean it up) |
||
Line 1: | Line 1: | ||
local export = {} | |||
-- | -- it is either here, or in [[Module:ugly hacks]], and it is not in ugly hacks. | ||
function export.CONTENTMODEL() | |||
return mw.title.getCurrentTitle().contentModel | |||
end | |||
local skins = { | |||
["common" ] = ""; | |||
["vector" ] = "Vector"; | |||
["monobook" ] = "Monobook"; | |||
["cologneblue"] = "Cologne Blue"; | |||
["modern" ] = "Modern"; | |||
} | |||
local Array = require "Module:array" | |||
local function | local function compare_pages(page1, page2, text) | ||
return "[" .. tostring( | |||
mw.uri.fullUrl("Special:ComparePages", { page1 = page1, page2 = page2 })) | |||
.. " " .. text .. "]" | |||
end | end | ||
local function page_exists(title) | |||
local success, title_obj = pcall(mw.title.new, title) | |||
local function | return success and title_obj.exists | ||
end | end | ||
-- Avoid transcluding [[Module:languages/cache]] everywhere. | |||
local lang_cache = setmetatable({}, { __index = function (self, k) | |||
return require "Module:languages/cache"[k] | |||
end }) | |||
local function | local function zh_link(word) | ||
return require("Module:links").full_link{ | |||
return | lang = lang_cache.zh, | ||
term = word | |||
} | |||
end | end | ||
local function make_Unicode_data_documentation(title, cats) | |||
local subpage, first_three_of_code_point | |||
= title.fullText:match("^Module:Unicode data/([^/]+)/(%x%x%x)$") | |||
if subpage == "names" or subpage == "images" then | |||
local low, high = | |||
tonumber(first_three_of_code_point .. "000", 16), | |||
tonumber(first_three_of_code_point .. "FFF", 16) | |||
return string.format( | |||
"This data module contains the %s of " .. | |||
"[[Appendix:Unicode|Unicode]] code points within the range U+%04X to U+%04X.", | |||
subpage == "images" and "titles of images" or "names", | |||
low, high) | |||
end | |||
end | end | ||
-- This provides categories and documentation for various data modules, so that | |||
-- [[Category:Uncategorized modules]] isn’t unnecessarily cluttered. | |||
-- It is a list of tables, each of which have the following possible fields: | |||
-- `regex` (required): A Lua pattern to match the module's title. If it matches, the data in this entry will be used. | |||
-- Any captures in the pattern can by referenced in the `cat` field using %1 for the first capture, %2 for the | |||
-- second, etc. (often used for creating the sortkey for the category). In addition, the captures are passed to the | |||
-- `process` function as the third and subsequent parameters. | |||
-- `process` (optional): This may be a function or a string. If it is a function, it is called as follows: | |||
-- process(TITLE, CATS, CAPTURE1, CAPTURE2, ...) | |||
-- where: | |||
-- * TITLE is a title object describing the module's title; see [https://www.mediawiki.org/wiki/Extension:Scribunto/Lua_reference_manual#Title_objects]. | |||
-- * CATS is an array object (see [[Module:array]]) of categories that the module will be added to. | |||
-- * CAPTURE1, CAPTURE2, ... contain any captures in the `regex` field. | |||
-- The return value of `process` should be a string and will be used as the module's documentation. | |||
-- If `process` is a string, it is the name of a submodule under 'Module:documentation/functions/' which returns a | |||
-- function, of the same type as described above. If `process` is omitted entirely, the module will have no | |||
-- documentation. | |||
------------------------- | -- `cat` (optional): A string naming the category into which the module should be placed. Captures specified in `regex` | ||
- | -- may be referenced in this string using %1 for the first capture, %2 for the second, etc. Currently, in order to put | ||
-- the module into multiple categories, you need to write a `process` function that adds categories to the CATS | |||
-- parameter passed in. | |||
local module_regex = { | |||
{ | |||
regex = "^Module:languages/.+$", | |||
cat = "Language and script modules", | |||
}, | |||
{ | |||
if | regex = "^Module:scripts/.+$", | ||
cat = "Language and script modules", | |||
}, | |||
{ | |||
regex = "^Module:data tables/data..?.?.?$", | |||
cat = "Reference module sharded data tables", | |||
}, | |||
{ | |||
regex = "^Module:Quotations/...?.?.?.?.?.?$", | |||
cat = "Quotation data modules", | |||
}, | |||
{ | |||
regex = "^Module:zh/data/dial%-pron/.+$", | |||
cat = "Chinese dialectal pronunciation data modules", | |||
process = "zh dial or syn", | |||
}, | |||
{ | |||
regex = "^Module:zh/data/dial%-syn/.+$", | |||
cat = "Chinese dialectal synonyms data modules", | |||
process = "zh dial or syn", | |||
}, | |||
{ | |||
regex = "^Module:zh/data/glyph%-data/.+$", | |||
cat = "Chinese historical character forms data modules", | |||
process = function(title, cats) | |||
local character = title.fullText:match("^Module:zh/data/glyph%-data/(.+)") | |||
if character then | |||
return ("This module contains data on historical forms of the Chinese character %s.") | |||
:format(zh_link(character)) | |||
end | |||
end, | |||
}, | |||
{ | |||
regex = "^Module:zh/data/ltc%-pron/(.+)$", | |||
cat = "Middle Chinese pronunciation data modules|%1", | |||
process = "zh data", | |||
}, | |||
{ | |||
regex = "^Module:zh/data/och%-pron%-BS/(.+)$", | |||
cat = "Old Chinese (Baxter-Sagart) pronunciation data modules|%1", | |||
process = "zh data", | |||
}, | |||
{ | |||
regex = "^Module:zh/data/och%-pron%-ZS/(.+)$", | |||
cat = "Old Chinese (Zhengzhang) pronunciation data modules|%1", | |||
process = "zh data", | |||
}, | |||
{ | |||
-- capture rest of zh/data submodules | |||
regex = "^Module:zh/data/(.+)$", | |||
cat = "Chinese data modules|%1", | |||
}, | |||
{ | |||
regex = "^Module:mul/guoxue%-data/cjk%-?(.*)$", | |||
process = "guoxue-data", | |||
}, | |||
{ | |||
regex = "^Module:Unicode data/(.+)$", | |||
cat = "Unicode data modules|%1", | |||
process = make_Unicode_data_documentation, | |||
}, | |||
{ | |||
regex = "^Module:number list/data/(.+)$", | |||
process = "number list", | |||
}, | |||
{ | |||
regex = "^Module:accel/(.+)$", | |||
process = function(title, cats) | |||
local lang_code = title.subpageText | |||
local lang = lang_cache[lang_code] | |||
if lang then | |||
cats:insert(lang:getCanonicalName() .. " modules|accel") | |||
cats:insert(("Accel submodules|%s"):format(lang:getCanonicalName())) | |||
return ("This module contains new entry creation rules for %s; see [[WT:ACCEL]] for an overview, and [[Module:accel]] for information on creating new rules.") | |||
:format(lang:makeCategoryLink()) | |||
end | |||
end, | |||
}, | |||
{ | |||
regex = "^Module:inc%-ash/dial/data/(.+)$", | |||
cat = "Ashokan Prakrit modules|%1", | |||
process = function(title, cats) | |||
local word = title.fullText:match("^Module:inc%-ash/dial/data/(.+)$") | |||
if word then | |||
local lang = lang_cache["inc-ash"] | |||
return ("This module contains data on the pronunciation of %s in dialects of %s.") | |||
:format(require("Module:links").full_link({ term = word, lang = lang }, "term"), | |||
lang:makeCategoryLink()) | |||
end | |||
end, | |||
}, | |||
{ | |||
regex = "^Module:[%l-]+:Dialects$", | |||
process = function(title, cats) | |||
local content = title:getContent() | |||
local has_aliases = content:find("aliases") ~= nil | |||
return mw.getCurrentFrame():expandTemplate { | |||
title = "dialectal data module", | |||
args = { ["labels-aliases"] = has_aliases }, | |||
} | |||
end, | |||
}, | |||
{ | |||
regex = "^.+%-translit$", | |||
process = "translit", | |||
}, | |||
{ | |||
regex = "^Module:category tree/poscatboiler/data/lang%-specific/(.+)$", | |||
process = function(title, cats, lang_code) | |||
local lang = lang_cache[lang_code] | |||
if lang then | |||
local langname = lang:getCanonicalName() | |||
cats:insert("Category tree data modules/poscatboiler|" .. langname) | |||
cats:insert(langname .. " modules") | |||
cats:insert(langname .. " data modules") | |||
return "This module handles generating the descriptions and categorization for " .. langname .. " category pages " | |||
.. "of the format \"" .. langname .. " LABEL\" where LABEL can be any text. Examples are " | |||
.. "[[:Category:Bulgarian conjugation 2.1 verbs]] and [[:Category:Russian velar-stem neuter-form nouns]]. " | |||
.. "This module is part of the poscatboiler system, which is a general framework for generating the " | |||
.. "descriptions and categorization of category pages.\n\n" | |||
.. "For more information, see [[Module:category tree/poscatboiler/data/lang-specific/documentation]]." | |||
end | |||
end | |||
}, | |||
{ | |||
regex = "^Module:category tree/poscatboiler/data/(.+)$", | |||
cat = "Category tree data modules/poscatboiler|%1", | |||
}, | |||
{ | |||
regex = "^Module:ja/data/(.+)$", | |||
cat = "Japanese data modules|%1", | |||
}, | |||
{ | |||
regex = "^Module:Swadesh/data/(.+)$", | |||
cat = "Swadesh modules|%1", | |||
}, | |||
{ | |||
regex = "^Module:typing%-aids", | |||
process = function(title, cats) | |||
local data_suffix = title.fullText:match("^Module:typing%-aids/data/(.+)$") | |||
if data_suffix then | |||
cats:insert("Data modules") | |||
if data_suffix:find "^[%l-]+$" then | |||
local lang = require "Module:languages".getByCode(data_suffix) | |||
if lang then | |||
cats:insert(lang:getCanonicalName() .. " modules") | |||
end | |||
elseif data_suffix:find "^%u%l%l%l$" then | |||
local script = require "Module:scripts".getByCode(data_suffix) | |||
if script then | |||
cats:insert(script:getCategoryName()) | |||
end | end | ||
end | end | ||
end | end | ||
}) | end, | ||
}, | |||
{ | |||
end | regex = "^Module:R:([a-z%-]+):(.+)$", | ||
process = function(title, cats, lang_code, refname) | |||
local lang = lang_cache[lang_code] | |||
if lang then | |||
cats:insert(lang:getCanonicalName() .. " modules|" .. refname) | |||
cats:insert(("Reference modules|%s"):format(lang:getCanonicalName())) | |||
return mw.getCurrentFrame():preprocess("This module implements the reference template {{temp|R:" .. | |||
lang_code .. ":" .. refname .. "}}.") | |||
end | |||
end, | |||
}, | |||
} | |||
function export.show(frame) | |||
local params = { | |||
["hr"] = {}, | |||
["for"] = {}, | |||
["from"] = {}, | |||
if | ["notsubpage"] = { type = "boolean", default = false }, | ||
["nodoc"] = { type = "boolean", default = false }, | |||
} | |||
local args = require("Module:parameters").process(frame.args, params) | |||
local output = Array('\n<div class="documentation" style="display:block; clear:both">\n') | |||
local cats = Array() | |||
local nodoc = args.nodoc | |||
if (not args.hr) or (args.hr == "above") then | |||
output:insert("----\n") | |||
end | end | ||
local | local title = ((args['for'] ~= "") and args['for']) and mw.title.new(args['for']) | ||
or mw.title.getCurrentTitle() | |||
local doc_title = mw.title.new((args['from'] ~= "") and args['from'] | |||
or (title.fullText .. '/documentation')) | |||
local contentModel = title.contentModel | |||
local pagetype = mw.getContentLanguage():lcfirst(title.nsText) .. " page" | |||
local preload, fallback_docs, doc_content, doc_content_module, | |||
old_doc_title, user_name, skin_name, needs_doc | |||
if contentModel == "javascript" then | |||
pagetype = "script" | |||
if title.nsText == 'MediaWiki' then | |||
if title.text:find('Gadget-') then | |||
preload = 'Template:documentation/preloadGadget' | |||
else | |||
preload = 'Template:documentation/preloadMediaWikiJavaScript' | |||
end | end | ||
else | |||
preload = 'Template:documentation/preloadTemplate' -- XXX | |||
end | end | ||
if title.nsText == 'User' then | |||
user_name = title.rootText | |||
end | end | ||
elseif contentModel == "css" then | |||
pagetype = "style sheet" | |||
preload = 'Template:documentation/preloadTemplate' -- XXX | |||
if title.nsText == 'User' then | |||
user_name = title.rootText | |||
end | end | ||
elseif contentModel == "Scribunto" then | |||
pagetype = "module" | |||
user_name = title.rootText:match("^[Uu]ser:(.+)") | |||
if user_name then | |||
preload = 'Template:documentation/preloadModuleSandbox' | |||
if | |||
else | else | ||
preload = 'Template:documentation/preloadModule' | |||
end | end | ||
elseif title.nsText == "Template" then | |||
pagetype = "template" | |||
preload = 'Template:documentation/preloadTemplate' | |||
elseif title.nsText == "Wiktionary" then | |||
pagetype = "project page" | |||
preload = 'Template:documentation/preloadTemplate' -- XXX | |||
end | end | ||
if doc_title.isRedirect then | |||
old_doc_title = doc_title | |||
doc_title = mw.title.new(string.match(doc_title:getContent(), | |||
"^#[Rr][Ee][Dd][Ii][Rr][Ee][Cc][Tt]%s*:?%s*%[%[([^%[%]]-)%]%]")) | |||
end | end | ||
function | output:insert("<dl class=\"plainlinks\" style=\"font-size: smaller;\">") | ||
if doc_title.exists then | |||
output:insert( | |||
"<dd><i style=\"font-size: larger;\">The following " .. | |||
"[[Help:Documenting templates and modules|documentation]] is located at [[" .. | |||
doc_title.fullText .. "]]. " .. | |||
"<sup>[[" .. doc_title:fullUrl { action = 'edit' } .. " edit]]</sup> </i></dd>") | |||
else | |||
if contentModel == "Scribunto" then | |||
local automatic_cats = nil | |||
if user_name then | |||
fallback_docs = "documentation/fallback/user module" | |||
automatic_cats = {"User sandbox modules"} | |||
else | |||
for _, data in ipairs(module_regex) do | |||
local captures = {mw.ustring.match(title.fullText, data.regex)} | |||
if #captures > 0 then | |||
local cat | |||
local process_function | |||
if type(data.process) == "function" then | |||
process_function = data.process | |||
elseif type(data.process) == "string" then | |||
doc_content_module = "Module:documentation/functions/" .. data.process | |||
process_function = require(doc_content_module) | |||
end | |||
if process_function then | |||
doc_content = process_function(title, cats, unpack(captures)) | |||
end | |||
cat = data.cat | |||
if cat then | |||
if type(cat) == "string" then | |||
cat = {cat} | |||
end | |||
for _, c in ipairs(cat) do | |||
-- gsub() and Lua :gsub() return two arguments, which causes all sorts of problems. | |||
-- Terrible design, there should have been a separate two-argument function. | |||
local gsub_sucks = mw.ustring.gsub(title.fullText, data.regex, c) | |||
table.insert(cats, gsub_sucks) | |||
end | |||
end | |||
break | |||
end | |||
end | |||
end | |||
if not automatic_cats then | |||
local success, auto_cats = | |||
pcall(require("Module:module categorization").categorize, frame, true) | |||
if success then | |||
for _, category in ipairs(auto_cats) do | |||
cats:insert(category) | |||
end | |||
end | |||
end | |||
if title.subpageText == "templates" then | |||
cats:insert("Template interface modules") | |||
end | |||
if automatic_cats then | |||
for _, c in ipairs(automatic_cats) do | |||
cats:insert(c) | |||
end | |||
- | end | ||
if | -- meaning module is not in user’s sandbox or one of many datamodule boring series | ||
needs_doc = not (automatic_cats or doc_content or fallback_docs) | |||
elseif title.nsText == "Template" then | |||
--cats:insert("Uncategorized templates") | |||
needs_doc = not (fallback_docs or nodoc) | |||
elseif (contentModel == "css") or (contentModel == "javascript") then | |||
if user_name then | |||
skin_name = skins[title.text:sub(#title.rootText + 1):match("^/([a-z]+)%.[jc]ss?$")] | |||
if skin_name then | |||
fallback_docs = 'documentation/fallback/user ' .. contentModel | |||
end | |||
end | |||
end | |||
if doc_content then | |||
output:insert( | |||
"<dd><i style=\"font-size: larger;\">The following " .. | |||
"[[Help:Documenting templates and modules|documentation]] is " .. | |||
"generated by [[" .. (doc_content_module or "Module:documentation") .. "]]. <sup>[[" .. | |||
mw.title.new("Module:documentation"):fullUrl { action = 'edit' } .. | |||
" edit]]</sup> </i></dd>") | |||
elseif not nodoc then | |||
output:insert( | |||
"<dd><i style=\"font-size: larger;\">This " .. pagetype .. | |||
" lacks a [[Help:Documenting templates and modules|documentation subpage]]. " .. | |||
(fallback_docs and "You may " or "Please ") .. | |||
"[" .. doc_title:fullUrl { action = 'edit', preload = preload } | |||
.. " create it].</i></dd>\n") | |||
end | end | ||
end | end | ||
if title.fullText:match("^MediaWiki:Gadget%-") then | |||
local is_gadget = false | |||
local | local gadget_list = mw.title.new("MediaWiki:Gadgets-definition"):getContent() | ||
for line in mw.text.gsplit(gadget_list, "\n") do | |||
local | local gadget, opts, items = line:match("^%*%s*([A-Za-z][A-Za-z0-9_%-]*)%[(.-)%]|(.+)$") -- opts is unused | ||
if not gadget then | |||
gadget, items = line:match("^%*%s*([A-Za-z][A-Za-z0-9_%-]*)|(.+)$") | |||
end | |||
if gadget then | |||
items = Array(mw.text.split(items, "|")) | |||
for i, item in ipairs(items) do | |||
if title.fullText == ("MediaWiki:Gadget-" .. item) then | |||
is_gadget = true | |||
output:insert("<dd> ''This script is a part of the <code>") | |||
output:insert(gadget) | |||
output:insert("</code> gadget ([") | |||
output:insert(tostring(mw.uri.fullUrl('MediaWiki:Gadgets-definition', 'action=edit'))) | |||
output:insert(" edit definitions])'' <dl>") | |||
output:insert("<dd> ''Description ([") | |||
output:insert(tostring(mw.uri.fullUrl('MediaWiki:Gadget-' .. gadget, 'action=edit'))) | |||
output:insert(" edit])'': ") | |||
local gadget_description = mw.message.new('Gadget-' .. gadget):plain() | |||
gadget_description = frame:preprocess(gadget_description) | |||
output:insert(gadget_description) | |||
output:insert(" </dd>") | |||
- | items:remove(i) | ||
if #items > 0 then | |||
for j, item in ipairs(items) do | |||
items[j] = '[[MediaWiki:Gadget-' .. item .. '|' .. item .. ']]' | |||
end | |||
output:insert("<dd> ''Other parts'': ") | |||
output:insert(mw.text.listToText(items)) | |||
output:insert("</dd>") | |||
end | |||
output:insert("</dl></dd>") | |||
break | |||
end | |||
end | |||
end | |||
end | |||
if not is_gadget then | |||
output:insert("<dd> ''This script is not a part of any [") | |||
output:insert(tostring(mw.uri.fullUrl('Special:Gadgets', 'uselang=en'))) | |||
output:insert(' gadget] ([') | |||
output:insert(tostring(mw.uri.fullUrl('MediaWiki:Gadgets-definition', 'action=edit'))) | |||
output:insert(' edit definitions]).</dd>') | |||
-- else | |||
-- cats:insert("Wiktionary gadgets") | |||
end | |||
end | end | ||
if old_doc_title then | |||
output:insert("<dd> ''Redirected from'' [") | |||
output:insert(old_doc_title:fullUrl { redirect = 'no' }) | |||
output:insert(" ") | |||
output:insert(old_doc_title.fullText) | |||
output:insert("] ([") | |||
output:insert(old_doc_title:fullUrl { action = 'edit' }) | |||
output:insert(" edit]).</dd>\n") | |||
end | end | ||
local | local links = Array() | ||
if title.isSubpage and not args.notsubpage then | |||
links:insert("[[:" .. title.nsText .. ":" .. title.rootText .. "|root page]]") | |||
links:insert("[[Special:PrefixIndex/" .. title.nsText .. ":" .. title.rootText .. "/|root page’s subpages]]") | |||
else | else | ||
links:insert("[[Special:PrefixIndex/" .. title.fullText .. "/|subpage list]]") | |||
end | end | ||
links:insert( | |||
'[' .. tostring(mw.uri.fullUrl('Special:WhatLinksHere/' .. title.fullText, | |||
'hidetrans=1&hideredirs=1')) .. ' links]') | |||
if contentModel ~= "Scribunto" then | |||
links:insert( | |||
'[' .. tostring(mw.uri.fullUrl('Special:WhatLinksHere/' .. title.fullText, | |||
'hidelinks=1&hidetrans=1')) .. ' redirects]') | |||
end | end | ||
if (contentModel == "javascript") or (contentModel == "css") then | |||
if user_name then | |||
links:insert("[[Special:MyPage" .. title.text:sub(#title.rootText + 1) .. "|your own]]") | |||
end | end | ||
else | else | ||
links:insert( | |||
'[' .. tostring(mw.uri.fullUrl('Special:WhatLinksHere/' .. title.fullText, | |||
'hidelinks=1&hideredirs=1')) .. ' transclusions]') | |||
end | end | ||
if contentModel == "Scribunto" then | |||
local is_testcases = title.isSubpage and title.subpageText == "testcases" | |||
local without_subpage = title.nsText .. ":" .. title.baseText | |||
if is_testcases then | |||
links:insert("[[:" .. without_subpage .. "|tested module]]") | |||
else | |||
links:insert("[[" .. title.fullText .. "/testcases|testcases]]") | |||
end | |||
if user_name then | |||
links:insert("[[User:" .. user_name .. "|user page]]") | |||
links:insert("[[User talk:" .. user_name .. "|user talk page]]") | |||
links:insert("[[Special:PrefixIndex/User:" .. user_name .. "/|userspace]]") | |||
if | |||
else | else | ||
-- If sandbox module, add a link to the module that this is a sandbox of. | |||
-- Exclude user sandbox modules like [[User:Dine2016/sandbox]]. | |||
if title.text:find("/sandbox%d*%f[/%z]") then | |||
cats:insert("Sandbox modules") | |||
-- Sandbox modules don’t really need documentation. | |||
needs_doc = false | |||
-- Will behave badly if “/sandbox” occurs twice in title! | |||
local sandbox_of = title.fullText:gsub("/sandbox%d*%f[/%z]", "") | |||
local diff | |||
if page_exists(sandbox_of) then | |||
diff = " (" .. compare_pages(title.fullText, sandbox_of, "diff") .. ")" | |||
else | |||
require("Module:debug").track("documentation/no sandbox of") | |||
end | |||
links:insert("[[:" .. sandbox_of .. "|sandbox of]]" .. (diff or "")) | |||
-- If not a sandbox module, add link to sandbox module. | |||
-- Sometimes there are multiple sandboxes for a single module: | |||
-- [[Module:sa-pronunc/sandbox]], [[Module:sa-pronunc/sandbox2]]. | |||
-- Occasionally sandbox modules have their own subpages that are also | |||
-- sandboxes: [[Module:grc-decl/sandbox/decl]]. | |||
else | |||
local sandbox_title | |||
if title.fullText:find("^Module:grc%-decl/") then | |||
sandbox_title = title.fullText:gsub("^Module:grc%-decl/", "Module:grc-decl/sandbox/") | |||
elseif is_testcases then | |||
sandbox_title = title.fullText:gsub("/testcases", "/sandbox/testcases") | |||
else | |||
sandbox_title = title.fullText .. "/sandbox" | |||
end | |||
local sandbox_link = "[[:" .. sandbox_title .. "|sandbox]]" | |||
local diff | |||
if page_exists(sandbox_title) then | |||
diff = " (" .. compare_pages(title.fullText, sandbox_title, "diff") .. ")" | |||
end | |||
links:insert(sandbox_link .. (diff or "")) | |||
end | |||
end | end | ||
end | end | ||
if title.nsText == "Template" then | |||
-- | -- Error search: all(any namespace), hastemplate (show pages using the template), insource (show source code), incategory (any/specific error) -- [[mw:Help:CirrusSearch]], [[w:Help:Searching/Regex]] | ||
-- apparently same with/without: &profile=advanced&fulltext=1 | |||
local errorq = 'searchengineselect=mediawiki&search=all: hastemplate:\"'..title.rootText..'\" insource:\"'..title.rootText..'\" incategory:' | |||
local eincategory = "Pages_with_module_errors|ParserFunction_errors|DisplayTitle_errors|Pages_with_ISBN_errors|Pages_with_ISSN_errors|Pages_with_reference_errors|Pages_with_syntax_highlighting_errors|Pages_with_TemplateStyles_errors" | |||
links:insert( | |||
'[' .. tostring(mw.uri.fullUrl('Special:Search', errorq..eincategory )) .. ' errors]' | |||
.. ' (' .. | |||
'[' .. tostring(mw.uri.fullUrl('Special:Search', errorq..'ParserFunction_errors' )) .. ' parser]' | |||
.. '/' .. | |||
'[' .. tostring(mw.uri.fullUrl('Special:Search', errorq..'Pages_with_module_errors' )) .. ' module]' | |||
.. ')' | |||
) | |||
if title.isSubpage and title.text:find("/sandbox%d*%f[/%z]") then -- This is a sandbox template. | |||
-- At the moment there are no user sandbox templates with subpage | |||
-- “/sandbox”. | |||
cats:insert("Sandbox templates") | |||
-- Sandbox templates don’t really need documentation. | |||
needs_doc = false | |||
-- Will behave badly if “/sandbox” occurs twice in title! | |||
local sandbox_of = title.fullText:gsub("/sandbox%d*%f[/%z]", "") | |||
local diff | |||
if page_exists(sandbox_of) then | |||
diff = " (" .. compare_pages(title.fullText, sandbox_of, "diff") .. ")" | |||
else | |||
require("Module:debug").track("documentation/no sandbox of") | |||
end | |||
links:insert("[[:" .. sandbox_of .. "|sandbox of]]" .. (diff or "")) | |||
else -- This is a template that can have a sandbox. | |||
local sandbox_title = title.fullText .. "/sandbox" | |||
local diff | |||
if page_exists(sandbox_title) then | |||
diff = " (" .. compare_pages(title.fullText, sandbox_title, "diff") .. ")" | |||
end | |||
links:insert("[[:" .. sandbox_title .. "|sandbox]]" .. (diff or "")) | |||
end | |||
end | end | ||
if #links > 0 then | |||
output:insert("<dd> ''Useful links'': " .. links:concat(" • ") .. "</dd>") | |||
if | |||
end | end | ||
output:insert("</dl>\n") | |||
-- | -- Show error from [[Module:category tree/topic cat/data]] on its submodules' | ||
if | -- documentation to, for instance, warn about duplicate labels. | ||
if title.fullText:find("Module:category tree/topic cat/data", 1, true) == 1 then | |||
local ok, err = pcall(require, "Module:category tree/topic cat/data") | |||
if not ok then | |||
output:insert('<span class="error">' .. err .. '</span>\n\n') | |||
end | |||
end | end | ||
if doc_title.exists then | |||
-- Override automatic documentation, if present. | |||
doc_content = frame:expandTemplate { title = doc_title.fullText } | |||
elseif not doc_content and fallback_docs then | |||
doc_content = frame:expandTemplate { | |||
title = fallback_docs; | |||
args = { | |||
['user'] = user_name; | |||
['page'] = title.fullText; | |||
['skin name'] = skin_name; | |||
} | |||
: | } | ||
end | end | ||
if doc_content then | |||
output:insert(doc_content) | |||
if | |||
end | end | ||
output:insert(('\n<%s style="clear: both;" />'):format(args.hr == "below" and "hr" or "br")) | |||
if not cats[1] and not doc_content then | |||
if contentModel == "Scribunto" then | |||
cats:insert("Uncategorized modules") | |||
if not | -- elseif title.nsText == "Template" then | ||
-- cats:insert("Uncategorized templates") | |||
end | |||
end | end | ||
if needs_doc then | |||
cats:insert("Templates and modules needing documentation") | |||
if | |||
end | end | ||
for _, cat in ipairs(cats) do | |||
output:insert("[[Category:" .. cat .. "]]") | |||
end | end | ||
output:insert("</div>\n") | |||
return | return output:concat() | ||
end | end | ||
-- Used by {{translit module documentation}}. | |||
function export.translitModuleLangList(frame) | |||
local pagename, subpage | |||
if frame.args[1] then | |||
pagename = frame.args[1] | |||
else | else | ||
local | local title = mw.title.getCurrentTitle() | ||
subpage = title.subpageText | |||
pagename = title.text | |||
if subpage ~= pagename then | |||
pagename = title.rootText | |||
end | end | ||
end | |||
local translitModule = pagename | |||
local languageObjects = require("Module:languages/byTranslitModule")(translitModule) | |||
local codeInPagename = pagename:match("^([%l-]+)%-.*translit$") | |||
if | |||
local categories = Array() | |||
local codeInPagenameInList = false | |||
if codeInPagename then | |||
if languageObjects[1] and subpage ~= "documentation" then | |||
local agreement = languageObjects[2] and "s" or "" | |||
categories:insert("[[Category:Transliteration modules used by " .. | |||
#languageObjects .. " language" .. agreement .. "]]") | |||
end | end | ||
languageObjects = Array(languageObjects) | |||
:filter( | |||
function (lang) | |||
local result = lang:getCode() ~= codeInPagename | |||
codeInPagenameInList = codeInPagenameInList or result | |||
return result | |||
end) | |||
end | end | ||
if | |||
if subpage ~= "documentation" then | |||
for script_code in pagename:gmatch("%f[^-%z]%u%l%l%l%f[-]") do | |||
local script = require "Module:scripts".getByCode(script_code) | |||
if script then | |||
categories:insert("[[Category:" .. script:getCategoryName() .. "]]") | |||
end | |||
end | end | ||
end | end | ||
if | if subpage ~= "documentation" and not page_exists("Module:" .. pagename .. "/testcases") then | ||
categories:insert("[[Category:Transliteration modules without a testcases subpage]]") | |||
end | end | ||
if not languageObjects[1] then | |||
return categories:concat() | |||
return | |||
end | end | ||
local langs = Array(languageObjects) | |||
:sort( | |||
function(lang1, lang2) | |||
return lang1:getCode() < lang2:getCode() | |||
end) | |||
-- This will not error because languageObjects is not empty. | |||
:map(languageObjects[1].makeCategoryLink) | |||
:serial_comma_join() | |||
local | |||
end | |||
return "It is " .. ( codeInPagenameInList and "also" or "" ) .. | |||
" used to transliterate " .. langs .. "." .. categories:concat() | |||
end | end | ||
return | return export |
Revision as of 02:51, 19 December 2021
File:Ambox important.svg | This Lua module is used in system messages, and on approximately 127,000 pages. Changes to it can cause immediate changes to the Wikipedia user interface. To avoid major disruption and server load, any changes should be tested in the module's /sandbox or /testcases subpages, or in your own module sandbox. The tested changes can be added to this page in a single edit. Please discuss changes on the talk page before implementing them. |
File:Full-protection-shackle.svg | 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. |
Lua error in Module:Lua_banner at line 112: attempt to index field 'edit' (a nil value). Lua error in Module:TNT at line 160: attempt to index field 'data' (a nil value). This module displays a blue box containing documentation for templates, Lua modules, or other pages. The {{documentation}} template invokes it.
Normal usage
For most uses, you should use the {{documentation}} template; please see that template's page for its usage instructions and parameters.
Use in other modules
To use this module from another Lua module, first load it with require
:
local documentation = require('Module:Documentation').main
Then you can simply call it using a table of arguments.
documentation{content = 'Some documentation', ['link box'] = 'My custom link box'}
Please refer to the template documentation for usage instructions and a list of parameters.
Porting to other wikis
The module has a configuration file at Module:Documentation/config which is intended to allow easy translation and porting to other wikis. Please see the code comments in the config page for instructions. If you have any questions, or you need a feature which is not currently implemented, please leave a message at Template talk:Documentation to get the attention of a developer.
The messages that need to be customized to display a documentation template/module at the top of module pages are MediaWiki:Scribunto-doc-page-show and MediaWiki:Scribunto-doc-page-does-not-exist.
local export = {}
-- it is either here, or in [[Module:ugly hacks]], and it is not in ugly hacks.
function export.CONTENTMODEL()
return mw.title.getCurrentTitle().contentModel
end
local skins = {
["common" ] = "";
["vector" ] = "Vector";
["monobook" ] = "Monobook";
["cologneblue"] = "Cologne Blue";
["modern" ] = "Modern";
}
local Array = require "Module:array"
local function compare_pages(page1, page2, text)
return "[" .. tostring(
mw.uri.fullUrl("Special:ComparePages", { page1 = page1, page2 = page2 }))
.. " " .. text .. "]"
end
local function page_exists(title)
local success, title_obj = pcall(mw.title.new, title)
return success and title_obj.exists
end
-- Avoid transcluding [[Module:languages/cache]] everywhere.
local lang_cache = setmetatable({}, { __index = function (self, k)
return require "Module:languages/cache"[k]
end })
local function zh_link(word)
return require("Module:links").full_link{
lang = lang_cache.zh,
term = word
}
end
local function make_Unicode_data_documentation(title, cats)
local subpage, first_three_of_code_point
= title.fullText:match("^Module:Unicode data/([^/]+)/(%x%x%x)$")
if subpage == "names" or subpage == "images" then
local low, high =
tonumber(first_three_of_code_point .. "000", 16),
tonumber(first_three_of_code_point .. "FFF", 16)
return string.format(
"This data module contains the %s of " ..
"[[Appendix:Unicode|Unicode]] code points within the range U+%04X to U+%04X.",
subpage == "images" and "titles of images" or "names",
low, high)
end
end
-- This provides categories and documentation for various data modules, so that
-- [[Category:Uncategorized modules]] isn’t unnecessarily cluttered.
-- It is a list of tables, each of which have the following possible fields:
-- `regex` (required): A Lua pattern to match the module's title. If it matches, the data in this entry will be used.
-- Any captures in the pattern can by referenced in the `cat` field using %1 for the first capture, %2 for the
-- second, etc. (often used for creating the sortkey for the category). In addition, the captures are passed to the
-- `process` function as the third and subsequent parameters.
-- `process` (optional): This may be a function or a string. If it is a function, it is called as follows:
-- process(TITLE, CATS, CAPTURE1, CAPTURE2, ...)
-- where:
-- * TITLE is a title object describing the module's title; see [https://www.mediawiki.org/wiki/Extension:Scribunto/Lua_reference_manual#Title_objects].
-- * CATS is an array object (see [[Module:array]]) of categories that the module will be added to.
-- * CAPTURE1, CAPTURE2, ... contain any captures in the `regex` field.
-- The return value of `process` should be a string and will be used as the module's documentation.
-- If `process` is a string, it is the name of a submodule under 'Module:documentation/functions/' which returns a
-- function, of the same type as described above. If `process` is omitted entirely, the module will have no
-- documentation.
-- `cat` (optional): A string naming the category into which the module should be placed. Captures specified in `regex`
-- may be referenced in this string using %1 for the first capture, %2 for the second, etc. Currently, in order to put
-- the module into multiple categories, you need to write a `process` function that adds categories to the CATS
-- parameter passed in.
local module_regex = {
{
regex = "^Module:languages/.+$",
cat = "Language and script modules",
},
{
regex = "^Module:scripts/.+$",
cat = "Language and script modules",
},
{
regex = "^Module:data tables/data..?.?.?$",
cat = "Reference module sharded data tables",
},
{
regex = "^Module:Quotations/...?.?.?.?.?.?$",
cat = "Quotation data modules",
},
{
regex = "^Module:zh/data/dial%-pron/.+$",
cat = "Chinese dialectal pronunciation data modules",
process = "zh dial or syn",
},
{
regex = "^Module:zh/data/dial%-syn/.+$",
cat = "Chinese dialectal synonyms data modules",
process = "zh dial or syn",
},
{
regex = "^Module:zh/data/glyph%-data/.+$",
cat = "Chinese historical character forms data modules",
process = function(title, cats)
local character = title.fullText:match("^Module:zh/data/glyph%-data/(.+)")
if character then
return ("This module contains data on historical forms of the Chinese character %s.")
:format(zh_link(character))
end
end,
},
{
regex = "^Module:zh/data/ltc%-pron/(.+)$",
cat = "Middle Chinese pronunciation data modules|%1",
process = "zh data",
},
{
regex = "^Module:zh/data/och%-pron%-BS/(.+)$",
cat = "Old Chinese (Baxter-Sagart) pronunciation data modules|%1",
process = "zh data",
},
{
regex = "^Module:zh/data/och%-pron%-ZS/(.+)$",
cat = "Old Chinese (Zhengzhang) pronunciation data modules|%1",
process = "zh data",
},
{
-- capture rest of zh/data submodules
regex = "^Module:zh/data/(.+)$",
cat = "Chinese data modules|%1",
},
{
regex = "^Module:mul/guoxue%-data/cjk%-?(.*)$",
process = "guoxue-data",
},
{
regex = "^Module:Unicode data/(.+)$",
cat = "Unicode data modules|%1",
process = make_Unicode_data_documentation,
},
{
regex = "^Module:number list/data/(.+)$",
process = "number list",
},
{
regex = "^Module:accel/(.+)$",
process = function(title, cats)
local lang_code = title.subpageText
local lang = lang_cache[lang_code]
if lang then
cats:insert(lang:getCanonicalName() .. " modules|accel")
cats:insert(("Accel submodules|%s"):format(lang:getCanonicalName()))
return ("This module contains new entry creation rules for %s; see [[WT:ACCEL]] for an overview, and [[Module:accel]] for information on creating new rules.")
:format(lang:makeCategoryLink())
end
end,
},
{
regex = "^Module:inc%-ash/dial/data/(.+)$",
cat = "Ashokan Prakrit modules|%1",
process = function(title, cats)
local word = title.fullText:match("^Module:inc%-ash/dial/data/(.+)$")
if word then
local lang = lang_cache["inc-ash"]
return ("This module contains data on the pronunciation of %s in dialects of %s.")
:format(require("Module:links").full_link({ term = word, lang = lang }, "term"),
lang:makeCategoryLink())
end
end,
},
{
regex = "^Module:[%l-]+:Dialects$",
process = function(title, cats)
local content = title:getContent()
local has_aliases = content:find("aliases") ~= nil
return mw.getCurrentFrame():expandTemplate {
title = "dialectal data module",
args = { ["labels-aliases"] = has_aliases },
}
end,
},
{
regex = "^.+%-translit$",
process = "translit",
},
{
regex = "^Module:category tree/poscatboiler/data/lang%-specific/(.+)$",
process = function(title, cats, lang_code)
local lang = lang_cache[lang_code]
if lang then
local langname = lang:getCanonicalName()
cats:insert("Category tree data modules/poscatboiler|" .. langname)
cats:insert(langname .. " modules")
cats:insert(langname .. " data modules")
return "This module handles generating the descriptions and categorization for " .. langname .. " category pages "
.. "of the format \"" .. langname .. " LABEL\" where LABEL can be any text. Examples are "
.. "[[:Category:Bulgarian conjugation 2.1 verbs]] and [[:Category:Russian velar-stem neuter-form nouns]]. "
.. "This module is part of the poscatboiler system, which is a general framework for generating the "
.. "descriptions and categorization of category pages.\n\n"
.. "For more information, see [[Module:category tree/poscatboiler/data/lang-specific/documentation]]."
end
end
},
{
regex = "^Module:category tree/poscatboiler/data/(.+)$",
cat = "Category tree data modules/poscatboiler|%1",
},
{
regex = "^Module:ja/data/(.+)$",
cat = "Japanese data modules|%1",
},
{
regex = "^Module:Swadesh/data/(.+)$",
cat = "Swadesh modules|%1",
},
{
regex = "^Module:typing%-aids",
process = function(title, cats)
local data_suffix = title.fullText:match("^Module:typing%-aids/data/(.+)$")
if data_suffix then
cats:insert("Data modules")
if data_suffix:find "^[%l-]+$" then
local lang = require "Module:languages".getByCode(data_suffix)
if lang then
cats:insert(lang:getCanonicalName() .. " modules")
end
elseif data_suffix:find "^%u%l%l%l$" then
local script = require "Module:scripts".getByCode(data_suffix)
if script then
cats:insert(script:getCategoryName())
end
end
end
end,
},
{
regex = "^Module:R:([a-z%-]+):(.+)$",
process = function(title, cats, lang_code, refname)
local lang = lang_cache[lang_code]
if lang then
cats:insert(lang:getCanonicalName() .. " modules|" .. refname)
cats:insert(("Reference modules|%s"):format(lang:getCanonicalName()))
return mw.getCurrentFrame():preprocess("This module implements the reference template {{temp|R:" ..
lang_code .. ":" .. refname .. "}}.")
end
end,
},
}
function export.show(frame)
local params = {
["hr"] = {},
["for"] = {},
["from"] = {},
["notsubpage"] = { type = "boolean", default = false },
["nodoc"] = { type = "boolean", default = false },
}
local args = require("Module:parameters").process(frame.args, params)
local output = Array('\n<div class="documentation" style="display:block; clear:both">\n')
local cats = Array()
local nodoc = args.nodoc
if (not args.hr) or (args.hr == "above") then
output:insert("----\n")
end
local title = ((args['for'] ~= "") and args['for']) and mw.title.new(args['for'])
or mw.title.getCurrentTitle()
local doc_title = mw.title.new((args['from'] ~= "") and args['from']
or (title.fullText .. '/documentation'))
local contentModel = title.contentModel
local pagetype = mw.getContentLanguage():lcfirst(title.nsText) .. " page"
local preload, fallback_docs, doc_content, doc_content_module,
old_doc_title, user_name, skin_name, needs_doc
if contentModel == "javascript" then
pagetype = "script"
if title.nsText == 'MediaWiki' then
if title.text:find('Gadget-') then
preload = 'Template:documentation/preloadGadget'
else
preload = 'Template:documentation/preloadMediaWikiJavaScript'
end
else
preload = 'Template:documentation/preloadTemplate' -- XXX
end
if title.nsText == 'User' then
user_name = title.rootText
end
elseif contentModel == "css" then
pagetype = "style sheet"
preload = 'Template:documentation/preloadTemplate' -- XXX
if title.nsText == 'User' then
user_name = title.rootText
end
elseif contentModel == "Scribunto" then
pagetype = "module"
user_name = title.rootText:match("^[Uu]ser:(.+)")
if user_name then
preload = 'Template:documentation/preloadModuleSandbox'
else
preload = 'Template:documentation/preloadModule'
end
elseif title.nsText == "Template" then
pagetype = "template"
preload = 'Template:documentation/preloadTemplate'
elseif title.nsText == "Wiktionary" then
pagetype = "project page"
preload = 'Template:documentation/preloadTemplate' -- XXX
end
if doc_title.isRedirect then
old_doc_title = doc_title
doc_title = mw.title.new(string.match(doc_title:getContent(),
"^#[Rr][Ee][Dd][Ii][Rr][Ee][Cc][Tt]%s*:?%s*%[%[([^%[%]]-)%]%]"))
end
output:insert("<dl class=\"plainlinks\" style=\"font-size: smaller;\">")
if doc_title.exists then
output:insert(
"<dd><i style=\"font-size: larger;\">The following " ..
"[[Help:Documenting templates and modules|documentation]] is located at [[" ..
doc_title.fullText .. "]]. " ..
"<sup>[[" .. doc_title:fullUrl { action = 'edit' } .. " edit]]</sup> </i></dd>")
else
if contentModel == "Scribunto" then
local automatic_cats = nil
if user_name then
fallback_docs = "documentation/fallback/user module"
automatic_cats = {"User sandbox modules"}
else
for _, data in ipairs(module_regex) do
local captures = {mw.ustring.match(title.fullText, data.regex)}
if #captures > 0 then
local cat
local process_function
if type(data.process) == "function" then
process_function = data.process
elseif type(data.process) == "string" then
doc_content_module = "Module:documentation/functions/" .. data.process
process_function = require(doc_content_module)
end
if process_function then
doc_content = process_function(title, cats, unpack(captures))
end
cat = data.cat
if cat then
if type(cat) == "string" then
cat = {cat}
end
for _, c in ipairs(cat) do
-- gsub() and Lua :gsub() return two arguments, which causes all sorts of problems.
-- Terrible design, there should have been a separate two-argument function.
local gsub_sucks = mw.ustring.gsub(title.fullText, data.regex, c)
table.insert(cats, gsub_sucks)
end
end
break
end
end
end
if not automatic_cats then
local success, auto_cats =
pcall(require("Module:module categorization").categorize, frame, true)
if success then
for _, category in ipairs(auto_cats) do
cats:insert(category)
end
end
end
if title.subpageText == "templates" then
cats:insert("Template interface modules")
end
if automatic_cats then
for _, c in ipairs(automatic_cats) do
cats:insert(c)
end
end
-- meaning module is not in user’s sandbox or one of many datamodule boring series
needs_doc = not (automatic_cats or doc_content or fallback_docs)
elseif title.nsText == "Template" then
--cats:insert("Uncategorized templates")
needs_doc = not (fallback_docs or nodoc)
elseif (contentModel == "css") or (contentModel == "javascript") then
if user_name then
skin_name = skins[title.text:sub(#title.rootText + 1):match("^/([a-z]+)%.[jc]ss?$")]
if skin_name then
fallback_docs = 'documentation/fallback/user ' .. contentModel
end
end
end
if doc_content then
output:insert(
"<dd><i style=\"font-size: larger;\">The following " ..
"[[Help:Documenting templates and modules|documentation]] is " ..
"generated by [[" .. (doc_content_module or "Module:documentation") .. "]]. <sup>[[" ..
mw.title.new("Module:documentation"):fullUrl { action = 'edit' } ..
" edit]]</sup> </i></dd>")
elseif not nodoc then
output:insert(
"<dd><i style=\"font-size: larger;\">This " .. pagetype ..
" lacks a [[Help:Documenting templates and modules|documentation subpage]]. " ..
(fallback_docs and "You may " or "Please ") ..
"[" .. doc_title:fullUrl { action = 'edit', preload = preload }
.. " create it].</i></dd>\n")
end
end
if title.fullText:match("^MediaWiki:Gadget%-") then
local is_gadget = false
local gadget_list = mw.title.new("MediaWiki:Gadgets-definition"):getContent()
for line in mw.text.gsplit(gadget_list, "\n") do
local gadget, opts, items = line:match("^%*%s*([A-Za-z][A-Za-z0-9_%-]*)%[(.-)%]|(.+)$") -- opts is unused
if not gadget then
gadget, items = line:match("^%*%s*([A-Za-z][A-Za-z0-9_%-]*)|(.+)$")
end
if gadget then
items = Array(mw.text.split(items, "|"))
for i, item in ipairs(items) do
if title.fullText == ("MediaWiki:Gadget-" .. item) then
is_gadget = true
output:insert("<dd> ''This script is a part of the <code>")
output:insert(gadget)
output:insert("</code> gadget ([")
output:insert(tostring(mw.uri.fullUrl('MediaWiki:Gadgets-definition', 'action=edit')))
output:insert(" edit definitions])'' <dl>")
output:insert("<dd> ''Description ([")
output:insert(tostring(mw.uri.fullUrl('MediaWiki:Gadget-' .. gadget, 'action=edit')))
output:insert(" edit])'': ")
local gadget_description = mw.message.new('Gadget-' .. gadget):plain()
gadget_description = frame:preprocess(gadget_description)
output:insert(gadget_description)
output:insert(" </dd>")
items:remove(i)
if #items > 0 then
for j, item in ipairs(items) do
items[j] = '[[MediaWiki:Gadget-' .. item .. '|' .. item .. ']]'
end
output:insert("<dd> ''Other parts'': ")
output:insert(mw.text.listToText(items))
output:insert("</dd>")
end
output:insert("</dl></dd>")
break
end
end
end
end
if not is_gadget then
output:insert("<dd> ''This script is not a part of any [")
output:insert(tostring(mw.uri.fullUrl('Special:Gadgets', 'uselang=en')))
output:insert(' gadget] ([')
output:insert(tostring(mw.uri.fullUrl('MediaWiki:Gadgets-definition', 'action=edit')))
output:insert(' edit definitions]).</dd>')
-- else
-- cats:insert("Wiktionary gadgets")
end
end
if old_doc_title then
output:insert("<dd> ''Redirected from'' [")
output:insert(old_doc_title:fullUrl { redirect = 'no' })
output:insert(" ")
output:insert(old_doc_title.fullText)
output:insert("] ([")
output:insert(old_doc_title:fullUrl { action = 'edit' })
output:insert(" edit]).</dd>\n")
end
local links = Array()
if title.isSubpage and not args.notsubpage then
links:insert("[[:" .. title.nsText .. ":" .. title.rootText .. "|root page]]")
links:insert("[[Special:PrefixIndex/" .. title.nsText .. ":" .. title.rootText .. "/|root page’s subpages]]")
else
links:insert("[[Special:PrefixIndex/" .. title.fullText .. "/|subpage list]]")
end
links:insert(
'[' .. tostring(mw.uri.fullUrl('Special:WhatLinksHere/' .. title.fullText,
'hidetrans=1&hideredirs=1')) .. ' links]')
if contentModel ~= "Scribunto" then
links:insert(
'[' .. tostring(mw.uri.fullUrl('Special:WhatLinksHere/' .. title.fullText,
'hidelinks=1&hidetrans=1')) .. ' redirects]')
end
if (contentModel == "javascript") or (contentModel == "css") then
if user_name then
links:insert("[[Special:MyPage" .. title.text:sub(#title.rootText + 1) .. "|your own]]")
end
else
links:insert(
'[' .. tostring(mw.uri.fullUrl('Special:WhatLinksHere/' .. title.fullText,
'hidelinks=1&hideredirs=1')) .. ' transclusions]')
end
if contentModel == "Scribunto" then
local is_testcases = title.isSubpage and title.subpageText == "testcases"
local without_subpage = title.nsText .. ":" .. title.baseText
if is_testcases then
links:insert("[[:" .. without_subpage .. "|tested module]]")
else
links:insert("[[" .. title.fullText .. "/testcases|testcases]]")
end
if user_name then
links:insert("[[User:" .. user_name .. "|user page]]")
links:insert("[[User talk:" .. user_name .. "|user talk page]]")
links:insert("[[Special:PrefixIndex/User:" .. user_name .. "/|userspace]]")
else
-- If sandbox module, add a link to the module that this is a sandbox of.
-- Exclude user sandbox modules like [[User:Dine2016/sandbox]].
if title.text:find("/sandbox%d*%f[/%z]") then
cats:insert("Sandbox modules")
-- Sandbox modules don’t really need documentation.
needs_doc = false
-- Will behave badly if “/sandbox” occurs twice in title!
local sandbox_of = title.fullText:gsub("/sandbox%d*%f[/%z]", "")
local diff
if page_exists(sandbox_of) then
diff = " (" .. compare_pages(title.fullText, sandbox_of, "diff") .. ")"
else
require("Module:debug").track("documentation/no sandbox of")
end
links:insert("[[:" .. sandbox_of .. "|sandbox of]]" .. (diff or ""))
-- If not a sandbox module, add link to sandbox module.
-- Sometimes there are multiple sandboxes for a single module:
-- [[Module:sa-pronunc/sandbox]], [[Module:sa-pronunc/sandbox2]].
-- Occasionally sandbox modules have their own subpages that are also
-- sandboxes: [[Module:grc-decl/sandbox/decl]].
else
local sandbox_title
if title.fullText:find("^Module:grc%-decl/") then
sandbox_title = title.fullText:gsub("^Module:grc%-decl/", "Module:grc-decl/sandbox/")
elseif is_testcases then
sandbox_title = title.fullText:gsub("/testcases", "/sandbox/testcases")
else
sandbox_title = title.fullText .. "/sandbox"
end
local sandbox_link = "[[:" .. sandbox_title .. "|sandbox]]"
local diff
if page_exists(sandbox_title) then
diff = " (" .. compare_pages(title.fullText, sandbox_title, "diff") .. ")"
end
links:insert(sandbox_link .. (diff or ""))
end
end
end
if title.nsText == "Template" then
-- Error search: all(any namespace), hastemplate (show pages using the template), insource (show source code), incategory (any/specific error) -- [[mw:Help:CirrusSearch]], [[w:Help:Searching/Regex]]
-- apparently same with/without: &profile=advanced&fulltext=1
local errorq = 'searchengineselect=mediawiki&search=all: hastemplate:\"'..title.rootText..'\" insource:\"'..title.rootText..'\" incategory:'
local eincategory = "Pages_with_module_errors|ParserFunction_errors|DisplayTitle_errors|Pages_with_ISBN_errors|Pages_with_ISSN_errors|Pages_with_reference_errors|Pages_with_syntax_highlighting_errors|Pages_with_TemplateStyles_errors"
links:insert(
'[' .. tostring(mw.uri.fullUrl('Special:Search', errorq..eincategory )) .. ' errors]'
.. ' (' ..
'[' .. tostring(mw.uri.fullUrl('Special:Search', errorq..'ParserFunction_errors' )) .. ' parser]'
.. '/' ..
'[' .. tostring(mw.uri.fullUrl('Special:Search', errorq..'Pages_with_module_errors' )) .. ' module]'
.. ')'
)
if title.isSubpage and title.text:find("/sandbox%d*%f[/%z]") then -- This is a sandbox template.
-- At the moment there are no user sandbox templates with subpage
-- “/sandbox”.
cats:insert("Sandbox templates")
-- Sandbox templates don’t really need documentation.
needs_doc = false
-- Will behave badly if “/sandbox” occurs twice in title!
local sandbox_of = title.fullText:gsub("/sandbox%d*%f[/%z]", "")
local diff
if page_exists(sandbox_of) then
diff = " (" .. compare_pages(title.fullText, sandbox_of, "diff") .. ")"
else
require("Module:debug").track("documentation/no sandbox of")
end
links:insert("[[:" .. sandbox_of .. "|sandbox of]]" .. (diff or ""))
else -- This is a template that can have a sandbox.
local sandbox_title = title.fullText .. "/sandbox"
local diff
if page_exists(sandbox_title) then
diff = " (" .. compare_pages(title.fullText, sandbox_title, "diff") .. ")"
end
links:insert("[[:" .. sandbox_title .. "|sandbox]]" .. (diff or ""))
end
end
if #links > 0 then
output:insert("<dd> ''Useful links'': " .. links:concat(" • ") .. "</dd>")
end
output:insert("</dl>\n")
-- Show error from [[Module:category tree/topic cat/data]] on its submodules'
-- documentation to, for instance, warn about duplicate labels.
if title.fullText:find("Module:category tree/topic cat/data", 1, true) == 1 then
local ok, err = pcall(require, "Module:category tree/topic cat/data")
if not ok then
output:insert('<span class="error">' .. err .. '</span>\n\n')
end
end
if doc_title.exists then
-- Override automatic documentation, if present.
doc_content = frame:expandTemplate { title = doc_title.fullText }
elseif not doc_content and fallback_docs then
doc_content = frame:expandTemplate {
title = fallback_docs;
args = {
['user'] = user_name;
['page'] = title.fullText;
['skin name'] = skin_name;
}
}
end
if doc_content then
output:insert(doc_content)
end
output:insert(('\n<%s style="clear: both;" />'):format(args.hr == "below" and "hr" or "br"))
if not cats[1] and not doc_content then
if contentModel == "Scribunto" then
cats:insert("Uncategorized modules")
-- elseif title.nsText == "Template" then
-- cats:insert("Uncategorized templates")
end
end
if needs_doc then
cats:insert("Templates and modules needing documentation")
end
for _, cat in ipairs(cats) do
output:insert("[[Category:" .. cat .. "]]")
end
output:insert("</div>\n")
return output:concat()
end
-- Used by {{translit module documentation}}.
function export.translitModuleLangList(frame)
local pagename, subpage
if frame.args[1] then
pagename = frame.args[1]
else
local title = mw.title.getCurrentTitle()
subpage = title.subpageText
pagename = title.text
if subpage ~= pagename then
pagename = title.rootText
end
end
local translitModule = pagename
local languageObjects = require("Module:languages/byTranslitModule")(translitModule)
local codeInPagename = pagename:match("^([%l-]+)%-.*translit$")
local categories = Array()
local codeInPagenameInList = false
if codeInPagename then
if languageObjects[1] and subpage ~= "documentation" then
local agreement = languageObjects[2] and "s" or ""
categories:insert("[[Category:Transliteration modules used by " ..
#languageObjects .. " language" .. agreement .. "]]")
end
languageObjects = Array(languageObjects)
:filter(
function (lang)
local result = lang:getCode() ~= codeInPagename
codeInPagenameInList = codeInPagenameInList or result
return result
end)
end
if subpage ~= "documentation" then
for script_code in pagename:gmatch("%f[^-%z]%u%l%l%l%f[-]") do
local script = require "Module:scripts".getByCode(script_code)
if script then
categories:insert("[[Category:" .. script:getCategoryName() .. "]]")
end
end
end
if subpage ~= "documentation" and not page_exists("Module:" .. pagename .. "/testcases") then
categories:insert("[[Category:Transliteration modules without a testcases subpage]]")
end
if not languageObjects[1] then
return categories:concat()
end
local langs = Array(languageObjects)
:sort(
function(lang1, lang2)
return lang1:getCode() < lang2:getCode()
end)
-- This will not error because languageObjects is not empty.
:map(languageObjects[1].makeCategoryLink)
:serial_comma_join()
return "It is " .. ( codeInPagenameInList and "also" or "" ) ..
" used to transliterate " .. langs .. "." .. categories:concat()
end
return export