# Module:UserLinks/shared

-- This module stores functions that are shared between Module:UserLinks  
-- and Module:UserLinks/extra.  

-- Load data and define often-used variables  
local cfg = mw.loadData('Module:UserLinks/config')  
local namespaces = mw.site.namespaces  

-- Lazily initialise modules that we may or may not need  
local mCategoryHandler  

-- Define namespaces for which links need to be escaped with the colon trick.  
-- See w:en:Help:Colon trick.  
local colonNamespaces = {  
[6] = true, -- File  
[14] = true, -- Category  
}  

local p = {}  

function p.maybeLoadModule(s)  
-- Attempts to load the module s. If it succeeds, returns the module;  
-- otherwise, returns false.  
local success, mdl = pcall(require, s)  
if success then  
return mdl  
else  
return false  
end  
end  

function p.raiseError(message, section, level)  
-- Raises an error using the Lua error function. The error message is  
-- designed to be caught with pcall and then passed to p.makeWikitextError.  
-- The section, if specified, is the section name on a help page that gives  
-- help to users about that particular error.  
if section then  
message = message .. '|' .. section  
end  
if not level or level == 0 then  
level = 0  
else  
level = level + 1  
end  
error(message, level)  
end  

function p.makeWikitextError(encodedMessage, demo)  
local errorMessage, section = mw.ustring.match(encodedMessage, '^(.-)|(.*)$')  
errorMessage = errorMessage or encodedMessage  

-- If not a demo, get the error category link and pass it through  
-- Module:Category handler's blacklist.  
local category  
if not demo then  
category = string.format(  
'%s:%s',  
namespaces[14].name,  
p.message('error-config-category')  
mCategoryHandler = p.maybeLoadModule('Module:Category handler')  
if mCategoryHandler then  
-- Categorise all namespaces, but not blacklisted pages.  
category = mCategoryHandler.main{all = category}  
end  
end  
category = category or ''  

-- Format the error message and the section link.  
local formattedError  
if section then  
formattedError = p.message(  
'error-config-message-help',  
errorMessage,  
section  
else  
formattedError = p.message(  
'error-config-message-nohelp',  
errorMessage  
end  

-- Return the error message and the category inside html error tags.  
return string.format(  
'<strong>%s</strong>%s',  
formattedError,  
category  
end  

local function formatPage(interwiki, namespace, page)  
-- Formats an interwiki, a namespace and a page into a wikilink-ready  
-- string. The interwiki and namespace are optional. If a namespace is  
-- specified, it should be a valid key to mw.site.namespaces. The page  
-- parameter is required.  
local ret = {}  
interwiki = interwiki or ''  
if interwiki ~= '' or colonNamespaces[namespace] then  
ret[#ret + 1] = ':'  
end  
ret[#ret + 1] = interwiki  
if interwiki ~= '' then  
ret[#ret + 1] = ':'  
end  
if namespace then  
local nsTable = namespaces[namespace]  
if not nsTable then  
error('"' .. tostring(namespace) .. '" is not a valid namespace key', 2)  
end  
ret[#ret + 1] = nsTable.name  
if namespace ~= 0 then  
ret[#ret + 1] = ':'  
end  
end  
ret[#ret + 1] = page  
return table.concat(ret)  
end  

local function formatDisplay(s)  
-- Replaces spaces in a string with "&nbsp;" to make sure they don't wrap.  
-- Don't replace anything if we are substing, as we generally don't want  
-- to use "&nbsp;" in that case.  
if mw.isSubsting then  
return s  
else  
return s:gsub(' ', '&nbsp;')  
end  
end  

function p.makeWikilink(interwiki, namespace, page, display)  
-- Creates a wikilink. The interwiki, namespace and display parameters are  
-- optional. If a namespace parameter is specified it must be a valid key  
-- to mw.site.namespaces.  
local formattedPage = formatPage(interwiki, namespace, page)  
if display then  
display = formatDisplay(display)  
return string.format('%s', formattedPage, display)  
else  
return string.format('%s', formattedPage)  
end  
end  

local function formatUrlLink(url, display)  
-- Formats a URL link with an optional display parameter.  
if display then  
display = formatDisplay(display)  
return string.format('[%s %s]', url, display)  
else  
return string.format('[%s]', url)  
end  
end  

function p.makeUrlLink(s, display)  
-- Makes a URL link with an optional display parameter. The first input  
-- may be any valid input to mw.uri.new.  
local url = mw.uri.new(s)  
url = tostring(url)  
return formatUrlLink(url, display)  
end  

function p.makeFullUrlLink(interwiki, namespace, page, query, display)  
-- Makes a link to the full URL of a page. The interwiki, namespace, query  
-- and display parameters are optional. If a namespace parameter is  
-- specified it must be a valid key to mw.site.namespaces. The query  
-- parameter can be a string or a table as specified in the mw.uri library.  
local formattedPage = formatPage(interwiki, namespace, page)  
local url = mw.uri.fullUrl(formattedPage, query)  
url = tostring(url)  
return formatUrlLink(url, display)  
end  

function p.message(key, ...)  
-- Returns the message with the given key from Module:UserLinks/config.  
-- Extra parameters are substituted in the message for keys $1, $2, $3, etc.  
local msg = cfg[key]  
if not msg then  
p.raiseError(  
'No message found with key "' .. tostring(key) .. '"',  
'No message found',  
2  
end  
local noArgs = select('#', ...)  
if noArgs < 1 then  
return msg  
else  
local msg = mw.message.newRawMessage(msg, ...)  
return msg:plain  
end  
end  

return p