Module:Find sources: Difference between revisions

From Zoophilia Wiki
Jump to navigationJump to search
meta>Mr. Stradivarius
(add blurb code)
meta>Mr. Stradivarius
(add namespace check, split search string rendering out into a separate function, and fix a couple of typos)
Line 11: Line 11:
local LINK_ROOT = ROOT_PAGE .. '/links/'
local LINK_ROOT = ROOT_PAGE .. '/links/'


local checkType = require('libraryUtils').checkType
local checkType = require('libraryUtil').checkType


local p = {}
local p = {}
Line 33: Line 33:
end
end


local function renderLink(code, searchStrings, display)
local function renderSearchString(searchTerms, separator, transformFunc)
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
 
local function renderLink(code, searchTerms, display)
-- Get link config.
-- Get link config.
local linkCfg = maybeLoadData(LINK_ROOT .. code)
local linkCfg = maybeLoadData(LINK_ROOT .. code)
Line 47: Line 60:
local url
local url
do
do
local firstFormat = linkCfg.firstFormat or '"$1"'
searchStrings[1] = substituteParams(firstFormat, searchStrings[1])
local separator = linkCfg.separator or "+"
local separator = linkCfg.separator or "+"
local searchString = table.concat(searchStrings, separator)
local searchString = renderSearchString(
searchTerms,
separator,
mw.uri.encode
)
url = linkCfg.url or error(string.format(
url = linkCfg.url or error(string.format(
"no 'url' field found in the link config at [[%s]]",
"no 'url' field found in the link config at [[%s]]",
Line 127: Line 142:
end
end


-- Get the search strings from the arguments.
-- Namespace check.
local searchStrings = {}
if not templateCfg.isUsedInMainspace and title.namespace == 0 then
return '<strong class="error">' ..
'Error: Please do not use this template in articles.' ..
'</strong>' ..
'[[Category:Pages with templates in the wrong namespace]]' ..
'[[Category:Find sources multi transclusions with errors]]'
end
 
-- Get the search terms from the arguments.
local searchTerms = {}
for i, s in ipairs(args) do
for i, s in ipairs(args) do
searchStrings[i] = mw.uri.encode(s)
searchTerms[i] = s
end
end
searchStrings[1] = searchStrings[1] or title.subpageText
searchTerms[1] = searchTerms[1] or title.subpageText
searchTerms[1] = '"' .. searchTerms[1] .. '"'


-- Make the intro link
-- Make the intro link
Line 138: Line 163:
if templateCfg.introLink then
if templateCfg.introLink then
local code = templateCfg.introLink[1]
local code = templateCfg.introLink[1]
local display = templateCfg.introLink[2]
local display = templateCfg.introLink[2] or renderSearchString(
introLink = renderLink(code, searchStrings, display)
searchTerms,
'&nbsp;'
)
introLink = renderLink(code, searchTerms, display)
else
else
introLink = ''
introLink = ''
Line 149: Line 177:
local code = t[1]
local code = t[1]
local display = t[2]
local display = t[2]
links[i] = renderLink(code, searchStrings, display)
links[i] = renderLink(code, searchTerms, display)
end
end
local separator = templateCfg.separator or mw.message.new('Dot-separator'):plain()
local separator = templateCfg.separator or mw.message.new('Dot-separator'):plain()

Revision as of 11:16, 26 September 2014

Documentation for this module may be created at Module:Find sources/doc

-- This module implements {{find sources}} and other similar templates, and also
-- provides a mechanism to easily create new source-finding templates.
--
-- Template settings are found in subpages of [[Module:Find sources/templates]].
-- Link functions are defined in subpages of [[Module:Find sources/links]].
-- Functions shared between the link modules are stored at
-- [[Module:Find sources/shared]].

local ROOT_PAGE = 'Module:Find sources'
local TEMPLATE_ROOT = ROOT_PAGE .. '/templates/'
local LINK_ROOT = ROOT_PAGE .. '/links/'

local checkType = require('libraryUtil').checkType

local p = {}

local function maybeLoadData(page)
	local success, data = pcall(mw.loadData, page)
	if success then
		return data
	else
		return nil
	end
end

local function substituteParams(msg, ...)
	local params = {...}
	if params[1] then
		return mw.message.newRawMessage(msg):params(params):plain()
	else
		return msg
	end
end

local function renderSearchString(searchTerms, separator, transformFunc)
	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

local function renderLink(code, searchTerms, display)
	-- 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 = linkCfg.url or error(string.format(
			"no 'url' field found in the link config at [[%s]]",
			LINK_ROOT .. code
		))
		url = substituteParams(url, searchString)
	end
	
	-- Fetch display.
	display = display or linkCfg.display or error(string.format(
		"no 'display' field found in the link config at [[%s]]",
		LINK_ROOT .. code
	))

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

local function checkTemplateCfgLinkTable(cfgPage, key, t)
	if type(t) ~= 'table' then
		error(string.format(
			"invalid link table found in key '%s' of template config at [[%s]] " ..
				"(expected type table, got type %s)",
			key, cfgPage, type(t)
		))
	elseif type(t[1]) ~= 'string' then
		error(string.format(
			"invalid link table found in key '%s' of template config at [[%s]] " ..
				"(the first table value must be a string)",
			key, cfgPage
		))
	elseif t[2] and type(t[2]) ~= 'string' then
		error(string.format(
			"invalid link table found in key '%s' of template config at [[%s]] " ..
				"(if the second table value is specified, it must be a string)",
			key, cfgPage
		))
	end
end

function p._main(template, args)
	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

	-- Template config sanity check.
	if templateCfg.introLink then
		checkTemplateCfgLinkTable(templateCfgPage, 'introLink', templateCfg.introLink)
	end
	if type(templateCfg.links) ~= 'table' then
		error(string.format(
			"type error in the 'links' field of the template config at [[%s]] " ..
				"(expected table, got %s)",
			templateCfgPage, type(templateCfg.links)
		))
	end
	for _, t in ipairs(templateCfg.links) do
		checkTemplateCfgLinkTable(templateCfgPage, 'links', t)
	end
	if type(templateCfg.blurb) ~= 'string' then
		error(string.format(
			"type error in the 'blurb' field of the template config at [[%s]] " ..
				"(expected string, got %s)",
			templateCfgPage, type(templateCfg.blurb)
		))
	end

	-- Namespace check.
	if not templateCfg.isUsedInMainspace and title.namespace == 0 then
		return '<strong class="error">' ..
			'Error: Please do not use this template in articles.' ..
			'</strong>' ..
			'[[Category:Pages with templates in the wrong namespace]]' ..
			'[[Category:Find sources multi transclusions with errors]]'
	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[1]
		local display = templateCfg.introLink[2] or renderSearchString(
			searchTerms,
			'&nbsp;'
		)
		introLink = renderLink(code, searchTerms, display)
	else
		introLink = ''
	end

	-- Make the other links
	local links = {}
	for i, t in ipairs(templateCfg.links) do
		local code = t[1]
		local display = t[2]
		links[i] = renderLink(code, searchTerms, display)
	end
	local separator = templateCfg.separator or mw.message.new('Dot-separator'):plain()
	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)
	return function(frame)
		local args = require('Module:Arguments').getArgs(frame, {
			wrappers = mw.site.namespaces[10].name .. ':' .. template
		})
		return t._main(template, args)
	end
end})

return p