# 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