Module:UserLinks: Difference between revisions
From the Croc Wiki, the Croc encyclopedia
Jump to navigationJump to search
Content added Content deleted
(Undid revision 602835579 by Mr. Stradivarius (talk) revert for now, generated an unexpected script error) |
(reinstate the rewrite - the script error was only occurring on the template page) |
||
Line 1: | Line 1: | ||
-------------------------------------------------------------------------------- |
|||
local ToolbarBuilder = require('Module:Toolbar') |
|||
-- UserLinks -- |
|||
local interwikiTable = mw.loadData("Module:InterwikiTable") |
|||
-- This module creates a list of links about a given user. It can be used on -- |
|||
-- its own or from a template. See the /doc page for more documentation. -- |
|||
-------------------------------------------------------------------------------- |
|||
-- Require necessary modules |
|||
local u = {} -- Table for user-data helper strings. |
|||
local yesno = require('Module:Yesno') |
|||
local trackingCategories = {} -- Table for storing the tracking categories. |
|||
local demo |
|||
-- Lazily initialise modules that we might or might not need |
|||
-- Define a custom error message for this module. |
|||
local mExtra -- [[Module:UserLinks/extra]] |
|||
local function err(msg, section) |
|||
local mArguments -- [[Module:Arguments]] |
|||
local help |
|||
local mToolbar -- [[Module:Toolbar]] |
|||
if section then |
|||
local mCategoryHandler -- [[Module:Category handler]] |
|||
help = ' ([[Template:User-multi#' .. section .. '|help]])' |
|||
local mTableTools -- [[Module:TableTools]] |
|||
else |
|||
local interwikiTable -- [[Module:InterwikiTable]], loaded with mw.loadData |
|||
help = '' |
|||
end |
|||
local cat |
|||
if demo == 'yes' then |
|||
cat = '' |
|||
else |
|||
cat = '[[Category:UserLinks transclusions with errors]]' |
|||
end |
|||
return '<span class="error">[[Template:User-multi|User-multi]] error: ' .. msg |
|||
.. help .. '.</span>' .. cat |
|||
end |
|||
-- Load shared helper functions |
|||
---------------------------------------------------------------------------------------------- |
|||
local mShared = require('Module:UserLinks/shared') |
|||
-- To add more link types, write a function that produces an individual link, and put -- |
|||
local raiseError = mShared.raiseError |
|||
-- it at the bottom of the list below. Then, add a link code for your function to the -- |
|||
local maybeLoadModule = mShared.maybeLoadModule |
|||
-- "linktypes" table. Try and make the code three letters or less. There are a number -- |
|||
local makeWikitextError = mShared.makeWikitextError |
|||
-- of helper strings available for writing the functions: -- |
|||
local makeWikilink = mShared.makeWikilink |
|||
-- -- |
|||
local makeUrlLink = mShared.makeUrlLink |
|||
-- u.username The plain username. If the username is not present then the -- |
|||
local makeFullUrlLink = mShared.makeFullUrlLink |
|||
-- module returns an error. -- |
|||
local message = mShared.message |
|||
-- u.usernameHtml The username html-encoded. Spaces are encoded with plus signs. -- |
|||
-- u.project The project name. Nil if not specified. -- |
|||
-- u.lang The language code. Nil if not specified. -- |
|||
-- u.interwiki The interwiki prefix, consisting of the project and language -- |
|||
-- values, separated by colons, e.g. ":wikt:es:". If no project -- |
|||
-- or language values are found, this is the blank string, "". -- |
|||
-- u.projectCode If a valid project is specified, this is the code for that -- |
|||
-- project in [[Module:InterwikiTable]]. Otherwise this is nil. -- |
|||
-- u.projectLong The long project name, e.g. "wikipedia" or "wikibooks". If -- |
|||
-- not specified the default is "wikipedia". -- |
|||
-- u.toolLang The language code for use with toolserver or labs tools. The -- |
|||
-- default is "en". -- |
|||
-- -- |
|||
-- If you want more helper strings, you can define them in the generateUserDataStrings -- |
|||
-- function below. -- |
|||
---------------------------------------------------------------------------------------------- |
|||
local p = {} |
|||
---------------------------------------------------------------------------------------------- |
|||
-- LINK FUNCTIONS START -- |
|||
---------------------------------------------------------------------------------------------- |
|||
-------------------------------------------------------------------------------- |
|||
local function makeUserLink() |
|||
-- Link table |
|||
return '[[' .. u.interwiki .. 'User:' .. u.username .. '|' .. u.username .. ']]' |
|||
-------------------------------------------------------------------------------- |
|||
end |
|||
function p.getLinks(snippets) |
|||
--[=[ |
|||
return '[[' .. u.interwiki .. 'User talk:' .. u.username .. '|talk]]' |
|||
-- Get a table of links that can be indexed with link codes. The table |
|||
end |
|||
-- returned is blank, but links are added to it on demand when it is |
|||
-- indexed. This is made possible by the metatable and by the various link |
|||
-- functions, some of which are defined here, and some of which are defined |
|||
-- at [[Module:UserLinks/extra]]. |
|||
--]=] |
|||
local links, linkFunctions = {}, {} |
|||
---------------------------------------------------------------------------- |
|||
local function makeContribsLink() |
|||
-- Link functions |
|||
return '[[' .. u.interwiki .. 'Special:Contributions/' .. u.username .. '|contribs]]' |
|||
-- |
|||
end |
|||
-- The following functions make the links from the link codes and the user |
|||
-- data snippets. New link functions should be added below the existing |
|||
-- functions. |
|||
-- |
|||
-- For documentation on how to add new link functions, please see |
|||
-- [[Module:UserLinks#Adding new links]]. |
|||
---------------------------------------------------------------------------- |
|||
function linkFunctions.u(snippets) |
|||
-- User page |
|||
return '[//tools.wmflabs.org/supercount/index.php?user=' .. u.usernameHtml |
|||
return makeWikilink( |
|||
.. '&project=' .. u.toolLang .. '.' .. u.projectLong |
|||
snippets.interwiki, |
|||
.. ' count]' |
|||
2, |
|||
end |
|||
snippets.username, |
|||
snippets.username |
|||
) |
|||
end |
|||
function linkFunctions.t(snippets) |
|||
-- User talk page |
|||
return '[[' .. u.interwiki .. 'Special:Log/move/' .. u.username .. '|page moves]]' |
|||
return makeWikilink( |
|||
end |
|||
snippets.interwiki, |
|||
3, |
|||
snippets.username, |
|||
message('display-talk') |
|||
) |
|||
end |
|||
function linkFunctions.c(snippets) |
|||
-- Contributions |
|||
return '[[' .. u.interwiki .. 'Special:Log/' .. u.username .. '|logs]]' |
|||
return makeWikilink( |
|||
end |
|||
snippets.interwiki, |
|||
-1, |
|||
'Contributions/' .. snippets.username, |
|||
message('display-contributions') |
|||
) |
|||
end |
|||
function linkFunctions.ct(snippets) |
|||
-- Edit count |
|||
local url = mw.uri.fullUrl(u.interwiki .. 'Special:Log/block', 'page=User:' .. u.usernameHtml) |
|||
return makeUrlLink( |
|||
return '[' .. tostring(url) .. ' block log]' |
|||
{ |
|||
end |
|||
host = 'tools.wmflabs.org', |
|||
path = '/supercount/index.php', |
|||
query = { |
|||
user = snippets.username, |
|||
project = snippets.toolLang .. '.' .. snippets.projectLong |
|||
} |
|||
}, |
|||
message('display-count') |
|||
) |
|||
end |
|||
function linkFunctions.m(snippets) |
|||
-- Page moves |
|||
return '[[' .. u.interwiki .. 'Special:Log/block/' .. u.username .. '|blocks]]' |
|||
return makeWikilink( |
|||
end |
|||
snippets.interwiki, |
|||
-1, |
|||
'Log/move/' .. snippets.username, |
|||
message('display-moves') |
|||
) |
|||
end |
|||
function linkFunctions.l(snippets) |
|||
-- Logs |
|||
return '[[' .. u.interwiki .. 'Special:Block/' .. u.username .. '|block user]]' |
|||
return makeWikilink( |
|||
end |
|||
snippets.interwiki, |
|||
-1, |
|||
'Log/' .. snippets.username, |
|||
message('display-logs') |
|||
) |
|||
end |
|||
function linkFunctions.bl(snippets) |
|||
-- Block log |
|||
return '[[' .. u.interwiki .. 'Special:CentralAuth/' .. u.username .. '|central auth]]' |
|||
return makeFullUrlLink( |
|||
end |
|||
snippets.interwiki, |
|||
-1, |
|||
'Log/block', |
|||
{page = 'User:' .. snippets.username}, |
|||
message('display-blocklog') |
|||
) |
|||
end |
|||
function linkFunctions.bls(snippets) |
|||
-- Blocks |
|||
return '[[' .. u.interwiki .. 'Special:DeletedContributions/' .. u.username .. '|deleted contribs]]' |
|||
return makeWikilink( |
|||
end |
|||
snippets.interwiki, |
|||
-1, |
|||
'Log/block/' .. snippets.username, |
|||
message('display-blocks') |
|||
) |
|||
end |
|||
function linkFunctions.bu(snippets) |
|||
-- Block user |
|||
return '[[' .. u.interwiki .. 'Special:Emailuser/' .. u.username .. '|email]]' |
|||
return makeWikilink( |
|||
end |
|||
snippets.interwiki, |
|||
-1, |
|||
'Block/' .. snippets.username, |
|||
message('display-blockuser') |
|||
) |
|||
end |
|||
function linkFunctions.ca(snippets) |
|||
-- Central auth |
|||
return '[http://tools.wmflabs.org/xtools/editsummary/index.php?name=' .. u.usernameHtml |
|||
return makeWikilink( |
|||
.. '&lang=' .. u.toolLang |
|||
snippets.interwiki, |
|||
.. '&wiki=' .. u.projectLong |
|||
-1, |
|||
.. ' edit summaries]' |
|||
'CentralAuth/' .. snippets.username, |
|||
end |
|||
message('display-centralauth') |
|||
) |
|||
end |
|||
function linkFunctions.dc(snippets) |
|||
-- Deleted contribs |
|||
return '[[' .. u.interwiki .. 'Special:Log/delete/' .. u.username .. '|deletions]]' |
|||
return makeWikilink( |
|||
end |
|||
snippets.interwiki, |
|||
-1, |
|||
'DeletedContributions/' .. snippets.username, |
|||
message('display-deletedcontributions') |
|||
) |
|||
end |
|||
function linkFunctions.e(snippets) |
|||
-- Email |
|||
local url = mw.uri.fullUrl(u.interwiki .. 'Special:ListUsers', 'limit=1&username=' .. u.usernameHtml) |
|||
return makeWikilink( |
|||
return '[' .. tostring(url) .. ' list user]' |
|||
snippets.interwiki, |
|||
end |
|||
-1, |
|||
'EmailUser/' .. snippets.username, |
|||
message('display-email') |
|||
) |
|||
end |
|||
function linkFunctions.es(snippets) |
|||
-- Edit summaries |
|||
return '[[sulutil:' .. u.username .. '|global contribs]]' |
|||
return makeUrlLink( |
|||
end |
|||
{ |
|||
host = 'tools.wmflabs.org', |
|||
path = '/xtools/editsummary/index.php', |
|||
query = { |
|||
name = snippets.username, |
|||
lang = snippets.toolLang, |
|||
wiki = snippets.projectLong |
|||
} |
|||
}, |
|||
message('display-editsummaries') |
|||
) |
|||
end |
|||
function linkFunctions.del(snippets) |
|||
-- Deletions |
|||
local url = mw.uri.fullUrl(u.interwiki .. 'Special:Log', 'page=User:' .. u.usernameHtml) |
|||
return makeWikilink( |
|||
return '[' .. tostring(url) .. ' target logs]' |
|||
snippets.interwiki, |
|||
end |
|||
-1, |
|||
'Log/delete/' .. snippets.username, |
|||
message('display-deletions') |
|||
) |
|||
end |
|||
function linkFunctions.lu(snippets) |
|||
-- List user |
|||
local url = mw.uri.fullUrl(u.interwiki .. 'Special:AbuseLog', 'wpSearchUser=' .. u.usernameHtml) |
|||
return makeFullUrlLink( |
|||
return '[' .. tostring(url) .. ' edit filter log]' |
|||
snippets.interwiki, |
|||
end |
|||
-1, |
|||
'ListUsers', |
|||
{limit = 1, user = snippets.username}, |
|||
message('display-listuser') |
|||
) |
|||
end |
|||
function linkFunctions.sul(snippets) |
|||
-- SUL |
|||
return '[[' .. u.interwiki .. 'Special:Log/protect/' .. u.username .. '|protections]]' |
|||
return makeWikilink( |
|||
end |
|||
nil, |
|||
nil, |
|||
'sulutil:' .. snippets.username, |
|||
message('display-sul') |
|||
) |
|||
end |
|||
function linkFunctions.tl(snippets) |
|||
-- Target logs |
|||
return '[[' .. u.interwiki .. 'Special:Log/rights/' .. u.username .. '|rights]]' |
|||
return makeFullUrlLink( |
|||
end |
|||
snippets.interwiki, |
|||
-1, |
|||
'Log', |
|||
{page = mw.site.namespaces[2].name .. ':' .. snippets.username}, |
|||
message('display-targetlogs') |
|||
) |
|||
end |
|||
function linkFunctions.efl(snippets) |
|||
-- Edit filter log |
|||
return '[[' .. u.interwiki .. 'Special:Log/renameuser/' .. u.username .. '|renames]]' |
|||
return makeFullUrlLink( |
|||
end |
|||
snippets.interwiki, |
|||
-1, |
|||
'AbuseLog', |
|||
{wpSearchUser = snippets.username}, |
|||
message('display-abuselog') |
|||
) |
|||
end |
|||
function linkFunctions.pr(snippets) |
|||
-- Protections |
|||
if u.project or u.lang then |
|||
return makeWikilink( |
|||
table.insert( trackingCategories, '[[Category:UserLinks transclusions with unresolvable interwiki links]]' ) |
|||
snippets.interwiki, |
|||
end |
|||
-1, |
|||
return '[[Special:PrefixIndex/Wikipedia:Requests for adminship/' .. u.username .. '|RfA]]' |
|||
'Log/protect/' .. snippets.username, |
|||
end |
|||
message('display-protections') |
|||
) |
|||
end |
|||
function linkFunctions.rl(snippets) |
|||
-- User rights |
|||
-- Find the full domain, as the API can't be accessed through the interwiki system. |
|||
return makeWikilink( |
|||
local fulldomain |
|||
snippets.interwiki, |
|||
local lang = u.lang or 'en' |
|||
-1, |
|||
if u.projectCode then |
|||
'Log/rights/' .. snippets.username, |
|||
local domain = interwikiTable[u.projectCode].domain |
|||
message('display-rights') |
|||
local takesLangPrefix = interwikiTable[u.projectCode].takes_lang_prefix |
|||
) |
|||
if not takesLangPrefix then |
|||
end |
|||
fulldomain = domain |
|||
else |
|||
fulldomain = lang .. '.' .. domain |
|||
end |
|||
else |
|||
fulldomain = lang .. '.wikipedia.org' |
|||
end |
|||
-- Return the API link |
|||
return '[//' .. fulldomain .. '/w/api.php?action=query&list=users&usprop=editcount&ususers=' .. u.usernameHtml .. ' api]' |
|||
end |
|||
function linkFunctions.ren(snippets) |
|||
-- Renames |
|||
return '[[' .. u.interwiki .. 'Special:ListFiles/' .. u.username .. '|uploads]]' |
|||
return makeWikilink( |
|||
end |
|||
snippets.interwiki, |
|||
-1, |
|||
'Log/renameuser/' .. snippets.username, |
|||
message('display-renames') |
|||
) |
|||
end |
|||
function linkFunctions.rfa(snippets) |
|||
---------------------------------------------------------------------------------------------- |
|||
-- Requests for adminship |
|||
-- LINK FUNCTIONS END -- |
|||
return makeWikilink( |
|||
-- To enable new link functions, add the code to the "linktypes" table directly below. -- |
|||
nil, |
|||
---------------------------------------------------------------------------------------------- |
|||
-1, |
|||
'PrefixIndex/' .. message('page-rfa') .. '/' .. snippets.username, |
|||
message('display-rfa') |
|||
) |
|||
end |
|||
function linkFunctions.api(snippets) |
|||
local linktypes = { |
|||
-- API user data |
|||
{'t' , makeTalkLink}, |
|||
return makeUrlLink( |
|||
{'c' , makeContribsLink}, |
|||
{ |
|||
{'ct' , makeCountLink}, |
|||
host = snippets.fullDomain, |
|||
{'m' , makeMovesLink}, |
|||
path = '/w/api.php', |
|||
{'l' , makeLogsLink}, |
|||
query = { |
|||
{'bl' , makeBlockLogLink}, |
|||
action = 'query', |
|||
{'bls' , makeBlocksLink}, |
|||
list = 'users', |
|||
{'bu' , makeBlockUserLink}, |
|||
usprop = 'editcount', |
|||
{'ca' , makeCentralAuthLink}, |
|||
ususers = snippets.username |
|||
{'dc' , makeDeletedContribsLink}, |
|||
} |
|||
{'e' , makeEmailLink}, |
|||
}, |
|||
{'es' , makeEditSummariesLink}, |
|||
message('display-api') |
|||
{'del' , makeDeletionsLink}, |
|||
) |
|||
{'lu' , makeListUserLink}, |
|||
end |
|||
{'sul' , makeSulLink}, |
|||
{'tl' , makeTargetLogsLink}, |
|||
{'efl' , makeEditFilterLogLink}, |
|||
{'pr' , makeProtectionsLink}, |
|||
{'rl' , makeRightsLink}, |
|||
{'ren' , makeRenamesLink}, |
|||
{'rfa' , makeRfaLink}, |
|||
{'api' , makeApiLink}, |
|||
{'up' , makeUploadsLink} |
|||
} |
|||
function linkFunctions.up(snippets) |
|||
-- Uploads |
|||
local linkNumber |
|||
return makeWikilink( |
|||
for i, value in ipairs(linktypes) do |
|||
snippets.interwiki, |
|||
if value[1] == linktype then |
|||
-1, |
|||
linkNumber = i |
|||
'ListFiles/' .. snippets.username, |
|||
break |
|||
message('display-uploads') |
|||
end |
|||
) |
|||
end |
|||
end |
|||
if not linkNumber then |
|||
return err('"' .. linktype .. '" is not a valid link code', 'Not a valid link code') |
|||
---------------------------------------------------------------------------- |
|||
end |
|||
-- End of link functions |
|||
local result = linktypes[linkNumber][2]() |
|||
---------------------------------------------------------------------------- |
|||
if type(result) ~= 'string' then |
|||
return err( |
|||
-- Define the metatable that memoizes the link functions, and fetches link |
|||
'the function for code "' .. linktype .. '" did not return a string value', |
|||
-- functions from [[Module:UserLinks/extra]] if necessary. |
|||
'Function did not return a string value' |
|||
) |
|||
-- Lazily initialise the extraLinkFunctions table. We only want to load |
|||
end |
|||
-- [[Module:UserLinks/extra]] as necessary, so it has a low transclusion |
|||
return result |
|||
-- count. |
|||
end |
|||
local extraLinkFunctions |
|||
-- Define functions for shared code in the metatable. |
|||
local function makeToolbar(args) |
|||
local function validateCode(code) |
|||
local targs = {} |
|||
-- Checks whether code is a valid link code - i.e. checks that it is a |
|||
local numArgsExist = false |
|||
-- string and that it is not the blank string. Returns the code if |
|||
for k, v in pairs(args) do |
|||
-- the check passes, and nil if not. |
|||
if type(k) == 'number' then |
|||
if type(code) == 'string' and code ~= '' then |
|||
numArgsExist = true |
|||
return code |
|||
targs[k] = getLink(v) |
|||
else |
|||
end |
|||
return nil |
|||
end |
|||
end |
|||
targs.style = args.small and 'font-size: 90%;' |
|||
end |
|||
targs.separator = args.separator or 'dot' |
|||
local function getExtraLinkFunctions() |
|||
if numArgsExist == false then |
|||
-- Loads the table of extra link functions from the /extra module. |
|||
return nil -- Don't return a toolbar if no numeric arguments exist. |
|||
-- If there is a problem with loading it, return false. We use the |
|||
else |
|||
-- distinction between false and nil to record whether we have already |
|||
return ToolbarBuilder.main(targs) |
|||
-- tried to load it. |
|||
end |
|||
if extraLinkFunctions ~= nil then |
|||
return extraLinkFunctions |
|||
end |
|||
if mExtra == nil then |
|||
-- If loading the module fails, maybeLoadModule returns false. |
|||
-- Here we use the distinction between false and nil to record |
|||
-- whether we have already tried to load the /extra module. |
|||
mExtra = maybeLoadModule('Module:UserLinks/extra') |
|||
end |
|||
if type(mExtra) == 'table' |
|||
and type(mExtra.linkFunctions) == 'table' |
|||
then |
|||
extraLinkFunctions = mExtra.linkFunctions |
|||
else |
|||
extraLinkFunctions = false |
|||
end |
|||
return extraLinkFunctions |
|||
end |
|||
local function memoizeExtraLink(code, func) |
|||
local success, link = pcall(func, snippets) |
|||
if success and type(link) == 'string' then |
|||
links[code] = link |
|||
return link |
|||
end |
|||
return nil |
|||
end |
|||
-- Define the metatable. |
|||
setmetatable(links, { |
|||
__index = function (t, key) |
|||
local code = validateCode(key) |
|||
if not code then |
|||
raiseError( |
|||
message('error-malformedlinkcode'), |
|||
message('error-malformedlinkcode-section') |
|||
) |
|||
end |
|||
local linkFunction = linkFunctions[code] |
|||
local link |
|||
if linkFunction then |
|||
link = linkFunction(snippets) |
|||
links[code] = link |
|||
else |
|||
extraLinkFunctions = getExtraLinkFunctions() |
|||
if extraLinkFunctions then |
|||
local extraLinkFunction = extraLinkFunctions[code] |
|||
if type(extraLinkFunction) == 'function' then |
|||
link = memoizeExtraLink(code, extraLinkFunction) |
|||
end |
|||
end |
|||
end |
|||
if link then |
|||
return link |
|||
else |
|||
raiseError( |
|||
message('error-invalidlinkcode', code), |
|||
message('error-invalidlinkcode-section') |
|||
) |
|||
end |
|||
end, |
|||
__pairs = function () |
|||
extraLinkFunctions = getExtraLinkFunctions() |
|||
if extraLinkFunctions then |
|||
for code, func in pairs(extraLinkFunctions) do |
|||
if validateCode(code) and type(func) == 'function' then |
|||
memoizeExtraLink(code, func) |
|||
end |
|||
end |
|||
end |
|||
-- Allow built-in functions to overwrite extra functions. |
|||
for code, func in pairs(linkFunctions) do |
|||
local link = func(snippets) |
|||
links[code] = link |
|||
end |
|||
return function (t, key) |
|||
return next(links, key) |
|||
end |
|||
end |
|||
}) |
|||
return links |
|||
end |
end |
||
-------------------------------------------------------------------------------- |
|||
-- This function finds whether a string is a valid interwiki project prefix. |
|||
-- User data snippets |
|||
-- If the string is valid, the function outputs two values: true, and the site code |
|||
-------------------------------------------------------------------------------- |
|||
-- used in [[Module:InterwikiTable]]. If the string is valid, the function outputs |
|||
-- false and nil. |
|||
function p.getSnippets(args) |
|||
--[=[ |
|||
for projectCode, projectVal in pairs(interwikiTable) do |
|||
-- This function gets user data snippets from the arguments, and from |
|||
for _, iwCode in ipairs(projectVal.iw_prefix) do |
|||
-- [[Module:InterwikiTable]]. The data is loaded as necessary and memoized |
|||
if iwCode == prefix then |
|||
-- in the snippets table for performance. |
|||
return true, projectCode |
|||
-- |
|||
-- Snippets default to the blank string, '', so they can be used in |
|||
-- concatenation operations without coders having to worry about raising |
|||
-- errors. Because of this, the local functions snippetExists and |
|||
-- getSnippet have been written to aid people writing new snippets. These |
|||
-- functions treat the blank string as false. It is not necessary to return |
|||
-- the blank string from a snippet function, as nil and false values are |
|||
-- automatically converted into the blank string by the metatable. |
|||
-- |
|||
-- If you add a new snippet, please document it at |
|||
-- [[Module:UserLinks#Adding new links]]. |
|||
--]=] |
|||
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( |
|||
message('error-nosnippet', key), |
|||
message('error-nosnippet-section') |
|||
) |
|||
end |
|||
end |
|||
}) |
|||
-- Define helper functions for writting the snippet functions. |
|||
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 |
|||
-- Start snippet functions. |
|||
function snippetFunctions.username() |
|||
-- The username. |
|||
local username = args.user or args.User |
|||
return username or raiseError( |
|||
message('error-nousername'), |
|||
message('error-nousername-section') |
|||
) |
|||
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, and adds |
|||
-- the project value to snippets.lang if it is a valid language code. |
|||
local project = args.Project or args.project |
|||
if not project then |
|||
return nil |
|||
end |
|||
local projectValidated, interwikiTableKey = p.validateProjectCode(project) |
|||
if not projectValidated then |
|||
if mw.language.isKnownLanguageTag(project) then |
|||
if not snippetExists('lang') then |
|||
snippets.lang = project |
|||
end |
|||
else |
|||
raiseError( |
|||
message('error-invalidproject', project), |
|||
message('error-invalidproject-section') |
|||
) |
|||
end |
|||
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; puts key in snippets table |
|||
return rawget(snippets, 'interwikiTableKey') |
|||
end |
|||
function snippetFunctions.toolProject() |
|||
-- The short project code for use with toolserver or labs. It is always |
|||
-- present, even if the "project" argument is absent. The default value |
|||
-- is the "snippet-project-default" message. |
|||
local project = getSnippet('project') |
|||
if not project then |
|||
return message('snippet-project-default') |
|||
else |
|||
return project |
|||
end |
|||
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 message('snippet-projectlong-default') |
|||
end |
|||
interwikiTable = interwikiTable or mw.loadData('Module:InterwikiTable') |
|||
local prefixes = interwikiTable[key].iw_prefix |
|||
-- Using prefixes[2] is a bit of a hack, but should find the long name |
|||
-- most of the time. |
|||
return prefixes[2] or prefixes[1] |
|||
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( |
|||
message('error-invalidlanguage', lang), |
|||
message('error-invalidlanguage-section') |
|||
) |
|||
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 |
|||
-- the "snippet-lang-default" message. |
|||
return getSnippet('lang') or message('snippet-lang-default') |
|||
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 |
|||
-- End snippet functions. If you add a new snippet function, please |
|||
-- document it at [[Module:UserLinks#Adding new links]]. |
|||
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 |
end |
||
end |
end |
||
return |
return nil, nil |
||
end |
end |
||
-------------------------------------------------------------------------------- |
|||
local function generateUserDataStrings(args) |
|||
-- Main functions |
|||
-- If the username is absent or blank, return an error and a tracking category. |
|||
-------------------------------------------------------------------------------- |
|||
if args.user == '' or (not args.user and (not args.User or args.User == '')) then |
|||
return err('no username detected', 'No username detected') |
|||
else |
|||
u.username = args.user or args.User |
|||
end |
|||
-- Get other basic user data strings. |
|||
u.project = args.Project or args.project |
|||
u.lang = args.lang or args.Lang |
|||
if u.lang then |
|||
if mw.language.isKnownLanguageTag(u.lang) then |
|||
table.insert(trackingCategories, '[[Category:UserLinks transclusions with language parameters]]') |
|||
else |
|||
return err('"' .. u.lang .. '" is not a valid language code', 'Not a valid language code') |
|||
end |
|||
end |
|||
-- Process the project value if it is present. |
|||
if u.project then |
|||
table.insert( trackingCategories, '[[Category:UserLinks transclusions with project parameters]]' ) |
|||
-- If u.project is a known project, we only need to get the project code. If the project |
|||
-- isn't known, first check whether it is a valid language code, and if not then see if it's |
|||
-- an interwiki code separated by colons, e.g. "wikt:es". |
|||
local uprojectIsKnownProject, uprojectProjectCode = isKnownProject(u.project) |
|||
if uprojectIsKnownProject then |
|||
u.projectCode = uprojectProjectCode |
|||
else |
|||
if mw.language.isKnownLanguageTag(u.project) then |
|||
u.lang = u.project |
|||
u.project = nil |
|||
else |
|||
local pref1, pref2 = mw.ustring.match( u.project, '^(%w+):(%w+)$' ) |
|||
if pref1 and pref2 then |
|||
local pref1IsKnownProject, pref1ProjectCode = isKnownProject(pref1) |
|||
local pref2IsKnownProject, pref2ProjectCode = isKnownProject(pref2) |
|||
if pref1IsKnownProject |
|||
and mw.language.isKnownLanguageTag(pref2) |
|||
and interwikiTable[pref1ProjectCode].takes_lang_prefix then |
|||
u.project = pref1 |
|||
u.lang = pref2 |
|||
u.projectCode = pref1ProjectCode |
|||
table.insert( |
|||
trackingCategories, |
|||
'[[Category:UserLinks transclusions with project parameters containing language codes]]' |
|||
) |
|||
elseif pref2IsKnownProject |
|||
and mw.language.isKnownLanguageTag(pref1) |
|||
and interwikiTable[pref2ProjectCode].takes_lang_prefix then |
|||
u.project = pref2 |
|||
u.lang = pref1 |
|||
u.projectCode = pref2ProjectCode |
|||
table.insert( |
|||
trackingCategories, |
|||
'[[Category:UserLinks transclusions with project parameters containing language codes]]' |
|||
) |
|||
else |
|||
return err( |
|||
'"' .. u.project .. '" is not a valid interwiki prefix', |
|||
'Not a valid interwiki prefix' |
|||
) |
|||
end |
|||
else |
|||
return err( |
|||
'"' .. u.project .. '" is not a valid interwiki prefix', |
|||
'Not a valid interwiki prefix' |
|||
) |
|||
end |
|||
end |
|||
end |
|||
end |
|||
-- Generate the interwiki prefix. This includes colons. |
|||
if u.project or u.lang then |
|||
u.interwiki = '' |
|||
if u.project then |
|||
u.interwiki = u.interwiki .. ':' .. u.project |
|||
end |
|||
if u.lang then |
|||
u.interwiki = u.interwiki .. ':' .. u.lang |
|||
end |
|||
u.interwiki = u.interwiki .. ':' |
|||
else |
|||
u.interwiki = '' |
|||
end |
|||
local function makeInvokeFunction(funcName) |
|||
-- Generate the other helper strings. |
|||
-- Makes a function that can be accessed from #invoke. This is only required |
|||
u.usernameHtml = mw.uri.encode(u.username) -- Html-encoded username. Spaces are encoded as pluses. |
|||
-- for functions that need to access arguments. |
|||
if u.project then |
|||
return function (frame) |
|||
local prefixes = interwikiTable[u.projectCode].iw_prefix |
|||
mArguments = require('Module:Arguments') |
|||
u.projectLong = prefixes[2] or prefixes[1] -- A bit of a hack, but should find the long prefix name most of the time. |
|||
local args = mArguments.getArgs(frame) |
|||
else |
|||
return p[funcName](args) |
|||
u.projectLong = 'wikipedia' |
|||
end |
|||
u.toolLang = u.lang or 'en' -- set the default language for tools on the toolserver or labs. |
|||
end |
end |
||
p.main = makeInvokeFunction('_main') |
|||
local function generateTrackingCategories() |
|||
if demo == 'yes' then |
|||
function p._main(args) |
|||
return '' |
|||
-- The main function. This is the one called from [[Template:User-multi]], |
|||
else |
|||
-- via p.main. |
|||
return table.concat(trackingCategories) |
|||
local options = p.getOptions(args) |
|||
end |
|||
local snippets = p.getSnippets(args) |
|||
local codes = p.getCodes(args) |
|||
local links = p.getLinks(snippets) |
|||
-- Overload the built-in Lua error function to generate wikitext errors |
|||
-- meant for end users to see. This makes things harder to debug when |
|||
-- real errors occur, but it is the only realistic way to show wikitext |
|||
-- errors and and still have sane code when using metatables, etc. |
|||
local success, result = pcall(p.export, codes, links, options) |
|||
if success then |
|||
return result |
|||
else |
|||
return makeWikitextError(result, options.isDemo) |
|||
end |
|||
end |
end |
||
function p.getOptions(args) |
|||
-- This function generates a table of all available link types, with their previews. |
|||
-- Gets the options from the args table, so that we don't have to pass |
|||
-- It is used in the module documentation. |
|||
-- around the whole args table all the time. |
|||
local function getLinkTable(args) |
|||
local options = {} |
|||
demo = args.demo -- Set the demo variable. |
|||
options.isDemo = yesno(args.demo) or false |
|||
-- Generate the user data strings and return any errors. |
|||
options.toolbarStyle = yesno(args.small) and 'font-size: 90%;' or nil |
|||
local dataStringError = generateUserDataStrings(args) |
|||
options.sup = yesno(args.sup, true) |
|||
if dataStringError then |
|||
options.separator = args.separator |
|||
return dataStringError |
|||
options.span = args.span |
|||
end |
|||
return options |
|||
-- Build a table of all of the links. |
|||
local result = '<table class="wikitable plainlinks sortable">' |
|||
.. '\n<tr><th>Code</th><th>Preview</th></tr>' |
|||
for i, value in ipairs(linktypes) do |
|||
local code = value[1] |
|||
result = result .. "\n<tr><td>'''" .. code .. "'''</td><td>" .. getLink(code) .. '</td></tr>' |
|||
end |
|||
result = result .. '\n</table>' |
|||
return result |
|||
end |
end |
||
function p.getCodes(args) |
|||
-- Gets the link codes from the arguments. The codes aren't validated |
|||
demo = args.demo -- Set the demo variable. |
|||
-- at this point. |
|||
-- Generate the user data strings and return any errors. |
|||
mTableTools = maybeLoadModule('Module:TableTools') |
|||
local dataStringError = generateUserDataStrings(args) |
|||
local codes |
|||
if dataStringError then |
|||
if mTableTools then |
|||
return dataStringError |
|||
codes = mTableTools.compressSparseArray(args) |
|||
end |
|||
else |
|||
codes = {} |
|||
local linktype = args[1] |
|||
for i, code in ipairs(args) do |
|||
if not linktype then |
|||
codes[i] = code |
|||
return err('no link type specified') |
|||
end |
|||
end |
|||
local result = getLink(linktype) |
|||
return codes |
|||
result = result .. generateTrackingCategories() |
|||
return result |
|||
end |
end |
||
function p.export(codes, links, options) |
|||
-- Make the user link. |
|||
local userLink = links.u |
|||
-- Generate the user data strings and return any errors. |
|||
local dataStringError = generateUserDataStrings(args) |
|||
-- If we weren't passed any link codes, just return the user link. |
|||
if dataStringError then |
|||
if #codes < 1 then |
|||
return dataStringError |
|||
return userLink |
|||
end |
|||
end |
|||
-- Build the template output. |
|||
-- Make the toolbar. |
|||
mToolbar = require('Module:Toolbar') |
|||
if result then |
|||
local toolbarArgs = {} |
|||
if args.sup then |
|||
for i, code in ipairs(codes) do |
|||
result = '<sup>' .. result .. '</sup>' |
|||
local link = links[code] |
|||
end |
|||
toolbarArgs[#toolbarArgs + 1] = link |
|||
result = ' ' .. result |
|||
end |
|||
else |
|||
toolbarArgs.style = options.toolbarStyle |
|||
result = '' -- If there are no links specified, don't return the toolbar at all. |
|||
toolbarArgs.separator = options.separator or 'dot' |
|||
end |
|||
toolbarArgs.span = options.span |
|||
result = '<span>' .. makeUserLink() .. result .. '</span>' |
|||
local toolbar = mToolbar.main(toolbarArgs) |
|||
result = result .. generateTrackingCategories() |
|||
return result |
-- Apply the sup option and return the result. |
||
if options.sup then |
|||
toolbar = '<sup>' .. toolbar .. '</sup>' |
|||
end |
|||
return userLink .. ' ' .. toolbar |
|||
end |
end |
||
-------------------------------------------------------------------------------- |
|||
local function getExampleLinks(args) |
|||
-- Single link function |
|||
-- This function enables example output without having to specify any |
|||
-------------------------------------------------------------------------------- |
|||
-- parameters to #invoke. |
|||
args.demo = 'yes' |
|||
p.single = makeInvokeFunction('_single') |
|||
args.user = 'Example' |
|||
args.User = nil |
|||
function p._single(args) |
|||
-- Fetches a single link from the link table. |
|||
local options = p.getOptions(args) |
|||
local snippets = p.getSnippets(args) |
|||
local links = p.getLinks(snippets) |
|||
local code = args[1] |
|||
local success, link = pcall(p.exportSingle, links, code) |
|||
if success then |
|||
return link |
|||
else |
|||
return makeWikitextError(link, options.isDemo) |
|||
end |
|||
end |
end |
||
function p.exportSingle(links, code) |
|||
-- If any errors occur, they will probably occur here. This function |
|||
return function (frame) |
|||
-- exists purely so that all the errors that will occur in p._single can |
|||
-- If called via #invoke, use the args passed into the invoking template. |
|||
-- be handled using a single pcall. |
|||
-- Otherwise, for testing purposes, assume args are being passed directly in. |
|||
if not code then |
|||
local origArgs |
|||
raiseError( |
|||
if frame == mw.getCurrentFrame() then |
|||
message('error-nolinkcode'), |
|||
origArgs = frame:getParent().args |
|||
message('error-nolinkcode-section') |
|||
for k, v in pairs(frame.args) do |
|||
) |
|||
origArgs = frame.args |
|||
end |
|||
break |
|||
return links[code] |
|||
end |
|||
else |
|||
origArgs = frame |
|||
end |
|||
-- Strip whitespace, and treat blank arguments as nil. |
|||
-- 'user', 'User', and 'separator' have different behaviour depending on |
|||
-- whether they are blank or nil, so keep them as they are. |
|||
local args = {} |
|||
for k, v in pairs(origArgs) do |
|||
v = mw.text.trim(v) |
|||
if v ~= '' or k == 'user' or k == 'User' or k == 'separator' then |
|||
args[k] = v |
|||
end |
|||
end |
|||
return func(args) |
|||
end |
|||
end |
end |
||
-------------------------------------------------------------------------------- |
|||
return { |
|||
-- Link table |
|||
main = makeWrapper(getLinks), |
|||
-------------------------------------------------------------------------------- |
|||
single = makeWrapper(getSingleLink), |
|||
linktable = makeWrapper(getLinkTable), |
|||
function p.linktable() |
|||
example = makeWrapper(getExampleLinks) |
|||
-- Returns a wikitext table of link codes, with an example link for each |
|||
} |
|||
-- one. This function doesn't take any arguments, so it can be accessed |
|||
-- directly from wiki pages without using makeInvokeFunction. |
|||
local args = {user = 'Example'} |
|||
local snippets = p.getSnippets(args) |
|||
local links = p.getLinks(snippets) |
|||
-- 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 |
|||
firstLinks[#firstLinks + 1] = {code, links[code]} |
|||
end |
|||
local secondLinks = {} |
|||
for code, link in pairs(links) do |
|||
if not firstCodesKeys[code] then |
|||
secondLinks[#secondLinks + 1] = {code, link} |
|||
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] = '! ' .. message('linktable-codeheader') |
|||
ret[#ret + 1] = '! ' .. message('linktable-previewheader') |
|||
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 |