# Module:Find sources

-- This module implements and other similar templates, and  
-- also provides a mechanism to easily create new source-finding templates.  

-- Define constants  
local ROOT_PAGE = 'Module:Find sources'  
local TEMPLATE_ROOT = ROOT_PAGE .. '/templates/' -- for template config modules  
local LINK_ROOT = ROOT_PAGE .. '/links/' -- for link config modules  
local CONFIG_PAGE = ROOT_PAGE .. '/config' -- for global config  

-- Load required modules  
local checkType = require('libraryUtil').checkType  
local cfg = mw.loadData(CONFIG_PAGE)  

local p = {}  

local function maybeLoadData(page)  
local success, data = pcall(mw.loadData, page)  
return success and data  
end  

local function substituteParams(msg, ...)  
return mw.message.newRawMessage(msg, ...):plain  
end  

local function renderSearchString(searchTerms, separator, transformFunc)  
-- This takes a table of search terms and turns it into a search string  
-- that can be used in a URL or in a display value. The transformFunc  
-- parameter can be used to transform each search term in some way (for  
-- example, URL-encoding them).  
local searchStrings = {}  
for i, s in ipairs(searchTerms) do  
searchStrings[i] = s  
end  
if transformFunc then  
for i, s in ipairs(searchStrings) do  
searchStrings[i] = transformFunc(s)  
end  
end  
return table.concat(searchStrings, separator)  
end  

function p._renderLink(code, searchTerms, display)  
-- Renders the external link wikicode for one link, given the link code,  
-- a table of search terms, and an optional display value.  

-- Get link config.  
local linkCfg = maybeLoadData(LINK_ROOT .. code)  
if not linkCfg then  
error(string.format(  
"invalid link code '%s'; no link config found at %s",  
code,  
LINK_ROOT .. code  
))  
end  

-- Make URL.  
local url  
do  
local separator = linkCfg.separator or "+"  
local searchString = renderSearchString(  
searchTerms,  
separator,  
mw.uri.encode  
url = substituteParams(linkCfg.url, searchString)  
end  

return string.format('[%s %s]', url, display or linkCfg.display)  
end  

function p._main(template, args)  
-- The main access point from Lua.  
checkType('_main', 1, template, 'string')  
checkType('_main', 2, args, 'table', true)  
args = args or {}  
local title = mw.title.getCurrentTitle  

-- Get the template config.  
local templateCfgPage = TEMPLATE_ROOT .. template  
local templateCfg = maybeLoadData(templateCfgPage)  
if not templateCfg then  
error(string.format(  
"invalid template name '%s'; no template config found at %s",  
template, templateCfgPage  
))  
end  

-- Namespace check.  
if not templateCfg.isUsedInMainspace and title.namespace == 0 then  
local formatString = '<strong>%s</strong>'  
if cfg['namespace-error-category'] then  
formatString = formatString .. '%s:%s'  
end  
return string.format(  
formatString,  
cfg['namespace-error'],  
mw.site.namespaces[14].name,  
cfg['namespace-error-category']  
end  

-- Get the search terms from the arguments.  
local searchTerms = {}  
for i, s in ipairs(args) do  
searchTerms[i] = s  
end  
searchTerms[1] = searchTerms[1] or title.subpageText  
searchTerms[1] = '"' .. searchTerms[1] .. '"'  

-- Make the intro link  
local introLink  
if templateCfg.introLink then  
local code = templateCfg.introLink.code  
local display = templateCfg.introLink.display or renderSearchString(  
searchTerms,  
'&nbsp;'  
introLink = p._renderLink(code, searchTerms, display)  
else  
introLink = ''  
end  

-- Make the other links  
local links = {}  
for i, t in ipairs(templateCfg.links) do  
links[i] = p._renderLink(t.code, searchTerms, t.display)  
end  
local separator = templateCfg.separator or cfg['default-separator']  
links = table.concat(links, separator)  

-- Make the blurb.  
local blurb = substituteParams(templateCfg.blurb, introLink, links)  
local span = mw.html.create('span')  
span  
:addClass('plainlinks')  
:addClass(templateCfg.class)  
:cssText(templateCfg.style)  
:wikitext(blurb)  

return tostring(span)  
end  

setmetatable(p, { __index = function(t, template)  
-- The main access point from #invoke.  
-- Invocations will look like ,  
-- where "template name" is a subpage of Module:Find sources/templates.  
return function  
local args = require('Module:Arguments').getArgs(, {  
wrappers = mw.site.namespaces[10].name .. ':' .. template  
})  
return t._main(template, args)  
end  
end})  

return p