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(
 		'&lt;strong class=&quot;error&quot;&gt;%s&lt;/strong&gt;%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('&quot;' .. tostring(namespace) .. '&quot; 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 &quot;&amp;nbsp;&quot; to make sure they don't wrap.
 	-- Don't replace anything if we are substing, as we generally don't want
 	-- to use &quot;&amp;nbsp;&quot; in that case.
 	if mw.isSubsting() then
 		return s
 	else
 		return s:gsub(' ', '&amp;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|%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 &quot;' .. tostring(key) .. '&quot;',
 			'No message found',
 			2
 		)
 	end
 	local noArgs = select('#', ...)
 	if noArgs &lt; 1 then
 		return msg
 	else
 		local msg = mw.message.newRawMessage(msg, ...)
 		return msg:plain()
 	end
 end