-- This module implements {{reply to}}.
local p = {}
-- The maximum number of users that can receive notifications in one edit
local MAX_USERS = 50
-- Make an HTML error from the supplied error message.
local function makeHTMLError(msg)
msg = string.format(
'Error in [[Template:Reply to]]: %s.',
msg
)
return require('Module:Error').error{msg}
end
-- Make a title object for the given user's user page. If the username contains
-- invalid characters, returns nil. Usernames can be given as 'Foo' or
-- 'User:Foo'. If a user subpage is supplied, the title for the root user page
-- is returned.
local function makeUserTitle(user)
local title = mw.title.new(user, 2)
if title then
return title.rootPageTitle
else
return nil
end
end
-- Make a wikilink with the given page and display text.
local function makeWikilink(page, display)
return string.format('[[%s|%s]]', page, display)
end
-- Return an array of numbers for all specified positional arguments.
local function findArgNums(args)
local ret = {}
for k in pairs(args) do
if type(k) == 'number' then
table.insert(ret, k)
end
end
table.sort(ret)
return ret
end
-- Validate the number of users. Returns true if the number is valid, and
-- returns false and an error message if invalid.
local function validateArgNums(nums)
local nUsers = #nums
if nUsers < 1 then
return false, 'No usernames given'
elseif nUsers > MAX_USERS then
return false, string.format('More than %d names specified', MAX_USERS)
end
return true
end
-- Make a table of user links from the arg nums and the args table. Returns
-- true plus the table of user links if everything went well; returns false and
-- an error message if there were any errors.
local function makeUserLinks(nums, args)
local links = {}
for i, num in ipairs(nums) do
local username = args[num]
local userTitle = makeUserTitle(username)
if not userTitle then
return false, string.format(
"'%s' is not a valid username or user page",
username
)
end
local display = args['label' .. tostring(num)] or username
table.insert(links, makeWikilink(userTitle.prefixedText, display))
end
return true, links
end
-- Assemble the output string from the table of links and from the arguments.
-- Returns the output string.
local function makeOutputString(links, args)
local prefix = args.prefix or '@'
local separator = ', '
local conjunction
if args.c == '' then
conjunction = separator
elseif args.c then
conjunction = ', ' .. args.c .. ' '
elseif #links == 2 then
conjunction = ' and '
else
conjunction = ', and '
end
local punctuation = args.p or ':'
return string.format(
'<span class="template-ping">%s%s%s</span>',
prefix,
mw.text.listToText(links, separator, conjunction),
punctuation
)
end
-- The entry point from other Lua modules.
function p._replyto(args)
-- Find the numbers of positional arguments that have been specified, and
-- check that they are valid.
local nums = findArgNums(args)
local numsAreValid, message = validateArgNums(nums)
if not numsAreValid then
return makeHTMLError(message)
end
-- Assemble the links
local linksAreValid, links = makeUserLinks(nums, args)
if not linksAreValid then
return makeHTMLError(links)
end
-- Assemble the output
return makeOutputString(links, args)
end
-- The entry point from #invoke.
function p.replyto(frame)
local parentArgs = frame:getParent().args
-- Trim and remove blanks for positional args, but leave named args as is.
-- (Note that named args are trimmed by MediaWiki, so we don't need to do it
-- again.)
local args = {}
for k, v in pairs(parentArgs) do
if type(k) == 'number' then
-- This is a positional arg
v = v:match('^%s*(.-)%s*$') -- Trim whitespace
if v ~= '' then
args[k] = v
end
else
-- This is a named arg
args[k] = v
end
end
return p._replyto(args)
end
return p