![]() | This is the module sandbox page for Module:UserLinks (diff). See also the companion subpage for test cases (run). |
![]() | This Lua module is used in system messages, and on approximately 1,050,000 pages, or roughly 2% of all 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. |
![]() | This module is rated as ready for general use. It has reached a mature form and is thought to be relatively bug-free and ready for use wherever appropriate. It is ready to mention on help pages and other Wikipedia resources as an option for new users to learn. To reduce server load and bad output, it should be improved by sandbox testing rather than repeated trial-and-error editing. |
![]() | This module is subject to page protection. It is a highly visible module in use by a very large number of pages, or is substituted very frequently. Because vandalism or mistakes would affect many pages, and even trivial editing might cause substantial load on the servers, it is protected from editing. |
![]() | This module depends on the following other modules: |
This module generates links about a given user. It is used to generate templates such as {{user}}, {{user5}}, and {{admin}}, usually through its wrapper template {{user-multi}}.
Functions
Main
The main
function implements the {{user-multi}} template. It generates a list of links about a given user. Please see the template page for documentation.
Single
The single
function generates a single link about a given user. See {{user-multi/link}} for documentation.
Porting to other wikis
If you want to use this module on another wiki, there are a few modules that you must also copy across, and some that can be used but are not essential.
Required modules:
- Module:UserLinks
- Module:UserLinks/shared
- Module:UserLinks/config
- Module:Arguments
- Module:Yesno
- Module:Toolbar
- Module:InterwikiTable
- Module:TableTools (optional in Module:UserLinks, but required by Module:Toolbar)
Optional modules:
- Module:UserLinks/extra - used for testing new link functions before they are moved to the main module.
- Module:Category handler - if an error occurs, and this module is present, pages are not categorised if they match the module's blacklist.
After you have copied over the necessary modules, you should adjust the configuration settings in Module:UserLinks/config for your language and for your wiki's setup.
-- Require necessary modules
local yesno = require('Module:Yesno')
-- Lazily initialise modules that we might or might not need
local mArguments
local mToolbar
local mCategoryHandler
local mTableTools
local interwikiTable -- Module:InterwikiTable, loaded with mw.loadData
-- Load shared helper functions
local mShared = require('Module:UserLinks/shared')
local raiseError = mShared.raiseError
local makeWikitextError = mShared.makeWikitextError
local makeWikilink = mShared.makeWikilink
local makeUrlLink = mShared.makeUrlLink
local p = {}
--------------------------------------------------------------------------------
-- Link functions
--------------------------------------------------------------------------------
function p.getLinkFunctions()
local linkFunctions = {}
-- Get extra link functions first, and allow the built-in link functions to
-- overwrite them. Extra link functions are stored in /extra. We need to
-- give the built-in functions priority, or a vandal could change high-risk
-- link functions from the /extra module.
local success, mExtra = pcall(require, 'Module:UserLinks/extra')
if success then
local extraLinkFunctions = type(mExtra) == 'table' and mExtra.linkFunctions
if type(extraLinkFunctions) == 'table' then
for code, func in pairs(extraLinkFunctions) do
if type(code) == 'string'
and code ~= ''
and type(func) == 'function'
then
linkFunctions[code] = func
end
end
end
end
-- Built-in link functions
function linkFunctions.u(snippets)
-- User page
return makeWikilink(snippets.interwiki .. 'User:' .. snippets.username, snippets.username)
end
function linkFunctions.t(snippets)
-- User talk page
return makeWikilink(snippets.interwiki .. 'User talk:' .. snippets.username, 'talk')
end
function linkFunctions.c(snippets)
-- Contributions
return makeWikilink(snippets.interwiki .. 'Special:Contributions/' .. snippets.username, 'contribs')
end
function linkFunctions.ct(snippets)
-- Edit count
return string.format(
'[//tools.wmflabs.org/supercount/index.php?user=%s&project=%s.%s count]',
snippets.usernameHtml, snippets.toolLang, snippets.projectLong
)
end
function linkFunctions.m(snippets)
-- Page moves
return makeWikilink(snippets.interwiki .. 'Special:Log/move/' .. snippets.username, 'page moves')
end
function linkFunctions.l(snippets)
-- Logs
return makeWikilink(snippets.interwiki .. 'Special:Log/' .. snippets.username, 'logs')
end
function linkFunctions.bl(snippets)
-- Block log
return makeUrlLink(snippets.interwiki .. 'Special:Log/block', {page = 'User:' .. snippets.username}, 'block log')
end
function linkFunctions.bls(snippets)
-- Blocks
return makeWikilink(snippets.interwiki .. 'Special:Log/block/' .. snippets.username, 'blocks')
end
function linkFunctions.bu(snippets)
-- Block user
return makeWikilink(snippets.interwiki .. 'Special:Block/' .. snippets.username, 'block user')
end
function linkFunctions.ca(snippets)
-- Central auth
return makeWikilink(snippets.interwiki .. 'Special:CentralAuth/' .. snippets.username, 'central auth')
end
function linkFunctions.dc(snippets)
-- Deleted contribs
return makeWikilink(snippets.interwiki .. 'Special:DeletedContributions/' .. snippets.username, 'deleted contribs')
end
function linkFunctions.e(snippets)
-- Email
return makeWikilink(snippets.interwiki .. 'Special:EmailUser/' .. snippets.username, 'email')
end
function linkFunctions.es(snippets)
-- Edit summaries
return string.format(
'[//tools.wmflabs.org/xtools/editsummary/index.php?name=%s&lang=%s&wiki=%s edit summaries]',
snippets.usernameHtml, snippets.toolLang, snippets.projectLong
)
end
function linkFunctions.del(snippets)
-- Deletions
return makeWikilink(snippets.interwiki .. 'Special:Log/delete/' .. snippets.username, 'deletions')
end
function linkFunctions.lu(snippets)
-- List user
return makeUrlLink(snippets.interwiki .. 'Special:ListUsers', {limit = 1, user = snippets.username}, 'list user')
end
function linkFunctions.sul(snippets)
-- SUL
return makeWikilink('sulutil:' .. snippets.username, 'global contribs')
end
function linkFunctions.tl(snippets)
-- Target logs
return makeUrlLink(snippets.interwiki .. 'Special:Log', {page = 'User:' .. snippets.username}, 'target logs')
end
function linkFunctions.efl(snippets)
-- Edit filter log
return makeUrlLink(snippets.interwiki .. 'Special:AbuseLog', {wpSearchUser = snippets.username}, 'edit filter log')
end
function linkFunctions.pr(snippets)
-- Protections
return makeWikilink(snippets.interwiki .. 'Special:Log/protect/' .. snippets.username, 'protections')
end
function linkFunctions.rl(snippets)
-- User rights
return makeWikilink(snippets.interwiki .. 'Special:Log/rights/' .. snippets.username, 'rights')
end
function linkFunctions.ren(snippets)
-- Renames
return makeWikilink(snippets.interwiki .. 'Special:Log/renameuser/' .. snippets.username, 'renames')
end
function linkFunctions.rfa(snippets)
-- Requests for adminship
return makeWikilink('Special:PrefixIndex/Wikipedia:Requests for adminship/' .. snippets.username, 'RfA')
end
function linkFunctions.api(snippets)
-- API user data
return string.format(
'[//%s/w/api.php?action=query&list=users&usprop=editcount&ususers=%s api]',
snippets.fullDomain, snippets.usernameHtml
)
end
function linkFunctions.up(snippets)
-- Uploads
return makeWikilink(snippets.interwiki .. 'Special:ListFiles/' .. snippets.username, 'uploads')
end
return linkFunctions
end
--------------------------------------------------------------------------------
-- User data snippets
--------------------------------------------------------------------------------
function p.getSnippets(args)
local snippets, snippetFunctions = {}, {}
setmetatable(snippets, {
__index = function (t, key)
local snippetFunction = snippetFunctions[key]
if snippetFunction then
snippets[key] = snippetFunction() or ''
return snippets[key]
else
raiseError('no snippet exists for the key "' .. key .. '"', 'No snippet exists')
end
end
})
local function snippetExists(key)
-- We have set the metatable up to make snippets default to '', so we
-- don't have to test for false or nil.
return snippets[key] ~= ''
end
local function getSnippet(key)
local ret = snippets[key]
if ret == '' then
return nil
else
return ret
end
end
function snippetFunctions.username()
-- The username.
local username = args.user or args.User
return username or raiseError('no username detected', 'No username detected')
end
function snippetFunctions.usernameHtml()
-- The username html-encoded. Spaces are encoded as pluses.
return mw.uri.encode(snippets.username)
end
function snippetFunctions.project()
-- The project name.
-- Also does the work for snippetFunctions.interwikiTableKey.
local project = args.Project or args.project
if not project then
return nil
end
local projectValidated, interwikiTableKey = p.validateProjectCode(project)
if not projectValidated then
raiseError('"' .. project .. '" is not a valid interwiki prefix', 'Not a valid interwiki prefix')
end
snippets.interwikiTableKey = interwikiTableKey
return project
end
function snippetFunctions.interwikiTableKey()
-- The key for the project in Module:InterwikiTable.
-- Relies on snippetFunctions.project to do the real work.
local temp = snippets.project -- required, as it puts the key in the snippets table
return rawget(snippets, 'interwikiTableKey')
end
function snippetFunctions.projectLong()
-- The long form of the project name, e.g. "wikipedia" or "wikibooks".
local key = getSnippet('interwikiTableKey')
if not key then
return nil
end
interwikiTable = interwikiTable or mw.loadData('Module:InterwikiTable')
local prefixes = interwikiTable[key].iw_prefix
return prefixes[2] or prefixes[1] -- A bit of a hack, but should find the long name most of the time
end
function snippetFunctions.lang()
-- The language code.
local lang = args.lang or args.Lang
if not lang then
return nil
end
if mw.language.isKnownLanguageTag(lang) then
return lang
else
raiseError('"' .. lang .. '" is not a valid language code', 'Not a valid language code')
end
end
function snippetFunctions.toolLang()
-- The language code for use with toolserver or labs tools. It is always
-- present, even if the "lang" argument is absent. The default value is "en".
return getSnippet('lang') or 'en'
end
function snippetFunctions.interwiki()
-- The interwiki prefix, consisting of the project and language values,
-- separated by colons, e.g. ":wikt:es:".
local project = getSnippet('project')
local lang = getSnippet('lang')
if not project and not lang then
return nil
end
local ret = {}
ret[#ret + 1] = project
ret[#ret + 1] = lang
return ':' .. table.concat(ret, ':') .. ':'
end
function snippetFunctions.fullDomain()
-- The full ___domain name of the site, e.g. www.mediawiki.org,
-- en.wikpedia.org, or ja.wikibooks.org.
local fullDomain
local lang = getSnippet('toolLang')
local key = getSnippet('interwikiTableKey')
if key then
interwikiTable = interwikiTable or mw.loadData('Module:InterwikiTable')
local ___domain = interwikiTable[key].___domain
local takesLangPrefix = interwikiTable[key].takes_lang_prefix
if takesLangPrefix then
fullDomain = lang .. '.' .. ___domain
else
fullDomain = ___domain
end
else
fullDomain = lang .. '.wikipedia.org'
end
return fullDomain
end
return snippets
end
function p.validateProjectCode(s)
-- Validates a project code, by seeing whether it is present in
-- [[Module:InterwikiTable]]. If it is present, returns the code and the
-- InterwikiTable key for the corresponding site. If not present,
-- returns nil for both.
interwikiTable = interwikiTable or mw.loadData('Module:InterwikiTable')
for key, t in pairs(interwikiTable) do
for i, prefix in ipairs(t.iw_prefix) do
if s == prefix then
return s, key
end
end
end
return nil, nil
end
--------------------------------------------------------------------------------
-- Main functions
--------------------------------------------------------------------------------
local function makeInvokeFunction(funcName)
return function (frame)
mArguments = require('Module:Arguments')
local args = mArguments.getArgs(frame)
return p[funcName](args)
end
end
p.main = makeInvokeFunction('_main')
function p._main(args)
local options = p.getOptions(args)
local snippets = p.getSnippets(args)
local codes = p.getCodes(args)
local linkFunctions = p.getLinkFunctions()
local success, result = pcall(p.export, codes, snippets, linkFunctions, options)
if success then
return result
else
return makeWikitextError(result, options.isDemo)
end
end
function p.getOptions(args)
local options = {}
options.isDemo = yesno(args.demo) or false
options.toolbarStyle = yesno(args.small) and 'font-size: 90%;' or nil
options.sup = yesno(args.sup, true)
options.separator = args.separator
options.span = args.span
return options
end
function p.getCodes(args)
mTableTools = require('Module:TableTools')
local codes = mTableTools.compressSparseArray(args)
return codes
end
function p.export(codes, snippets, linkFunctions, options)
-- Make the user link.
local userLink = linkFunctions.u(snippets)
-- Check to see that we were passed at least one code, and return the
-- blank string otherwise.
if #codes < 1 then
return ''
end
-- Make the toolbar.
mToolbar = require('Module:Toolbar')
local toolbarArgs = {}
for i, code in ipairs(codes) do
local linkFunction = linkFunctions[code]
if not linkFunction then
raiseError('"' .. code .. '" is not a valid link code', 'Not a valid link code')
end
local link = linkFunction(snippets)
toolbarArgs[#toolbarArgs + 1] = link
end
toolbarArgs.style = options.toolbarStyle
toolbarArgs.separator = options.separator or 'dot'
toolbarArgs.span = options.span
local toolbar = mToolbar.main(toolbarArgs)
-- Apply the sup option and return the result.
if options.sup then
toolbar = '<sup>' .. toolbar .. '</sup>'
end
return userLink .. ' ' .. toolbar
end
--------------------------------------------------------------------------------
-- Single link function
--------------------------------------------------------------------------------
p.single = makeInvokeFunction('_single')
function p._single(args)
local options = p.getOptions(args)
local code = args[1]
if not code then
return makeWikitextError(
'no link type specified|No link type specified',
options.isDemo
)
end
local snippets = p.getSnippets(args)
local linkFunctions = p.getLinkFunctions()
local linkFunction = linkFunctions[code]
local success, result = pcall(linkFunction, snippets)
if success then
return result
else
return makeWikitextError(result, options.isDemo)
end
end
--------------------------------------------------------------------------------
-- Link table
--------------------------------------------------------------------------------
function p.linktable()
local args = {user = 'Example'}
local snippets = p.getSnippets(args)
local linkFunctions = p.getLinkFunctions()
-- Assemble the codes and links in order
local firstCodes = {'u', 't', 'c'}
local firstLinks, firstCodesKeys = {}, {}
for i, code in ipairs(firstCodes) do
firstCodesKeys[code] = true
local success, link = pcall(linkFunctions[code], snippets)
if success then
firstLinks[#firstLinks + 1] = {code, link}
else
return makeWikitextError(result, true)
end
end
local secondLinks = {}
for code, linkFunction in pairs(linkFunctions) do
if not firstCodesKeys[code] then
local success, link = pcall(linkFunction, snippets)
if success then
secondLinks[#secondLinks + 1] = {code, link}
else
return makeWikitextError(result, true)
end
end
end
table.sort(secondLinks, function(t1, t2)
return t1[1] < t2[1]
end)
local links = {}
for i, t in ipairs(firstLinks) do
links[#links + 1] = t
end
for i, t in ipairs(secondLinks) do
links[#links + 1] = t
end
-- Output the code table in table format
local ret = {}
ret[#ret + 1] = '{| class="wikitable plainlinks sortable"'
ret[#ret + 1] = '|-'
ret[#ret + 1] = '! Code'
ret[#ret + 1] = '! Preview'
for i, t in ipairs(links) do
local code = t[1]
local link = t[2]
ret[#ret + 1] = '|-'
ret[#ret + 1] = "| '''" .. code .. "'''"
ret[#ret + 1] = '| ' .. link
end
ret[#ret + 1] = '|}'
return table.concat(ret, '\n')
end
return p