Difference between revisions of "Module:Unsubst"

From blackwiki
Jump to navigation Jump to search
test>Jc86035
m (all uses removed)
test>Jc86035
(add parameter list, aliases, flags; use Module:Template invocation)
Line 1: Line 1:
 +
local checkType = require('libraryUtil').checkType
 +
 
local p = {}
 
local p = {}
 +
 +
local BODY_PARAM = '$B'
  
 
local specialParams = {
 
local specialParams = {
['$B'] = 'template content',
+
['$params'] = 'parameter list',
 +
['$aliases'] = 'parameter aliases',
 +
['$flags'] = 'flags',
 +
['$B'] = 'template content'
 
}
 
}
  
p[''] = function ( frame )
+
function p.main(frame, body)
if not frame:getParent() then
+
-- If we are substing, this function returns a template invocation, and if
error( '{{#invoke:Unsubst|}} makes no sense without a parent frame' )
+
-- not, it returns the template body. The template body can be specified in
 +
-- the body parameter, or in the template parameter defined in the
 +
-- BODY_PARAM variable. This function can be called from Lua or from
 +
-- #invoke.
 +
 
 +
-- Return the template body if we aren't substing.
 +
if not mw.isSubsting() then
 +
if body ~= nil then
 +
return body
 +
elseif frame.args[BODY_PARAM] ~= nil then
 +
return frame.args[BODY_PARAM]
 +
else
 +
error(string.format(
 +
"no template content specified (use parameter '%s' from #invoke)",
 +
BODY_PARAM
 +
), 2)
 +
end
 
end
 
end
if not frame.args['$B'] then
+
 
error( '{{#invoke:Unsubst|}} requires parameter $B (template content)' )
+
-- Sanity check for the frame object.
 +
if type(frame) ~= 'table'
 +
or type(frame.getParent) ~= 'function'
 +
or not frame:getParent()
 +
then
 +
error(
 +
"argument #1 to 'main' must be a frame object with a parent " ..
 +
"frame available",
 +
2
 +
)
 
end
 
end
+
 
if mw.isSubsting() then
+
-- Find the invocation name.
---- substing
+
local mTemplateInvocation = require('Module:Template invocation')
-- Combine passed args with passed defaults
+
local name = mTemplateInvocation.name(frame:getParent():getTitle())
local args = {}
+
 
 +
-- Combine passed args with passed defaults
 +
local args = {}
 +
if string.find( ','..(frame.args['$flags'] or '')..',', ',%s*override%s*,' ) then
 +
for k, v in pairs( frame:getParent().args ) do
 +
args[k] = v
 +
end
 +
for k, v in pairs( frame.args ) do
 +
if not specialParams[k] then
 +
if v == '__DATE__' then
 +
v = mw.getContentLanguage():formatDate( 'F Y' )
 +
end
 +
args[k] = v
 +
end
 +
end
 +
else
 
for k, v in pairs( frame.args ) do
 
for k, v in pairs( frame.args ) do
 
if not specialParams[k] then
 
if not specialParams[k] then
Line 28: Line 75:
 
args[k] = v
 
args[k] = v
 
end
 
end
 +
end
  
-- Build an equivalent template invocation
+
-- Trim parameters, if not specified otherwise
-- First, find the title to use
+
if not string.find( ','..(frame.args['$flags'] or '')..',', ',%s*keep%-whitespace%s*,' ) then
local titleobj = mw.title.new(frame:getParent():getTitle())
+
for k, v in pairs( args ) do args[k] = mw.ustring.match(v, '%s*(.*)%s*') or '' end
local title
+
end
if titleobj.namespace == 10 then -- NS_TEMPLATE
+
title = titleobj.text
+
-- Remove empty parameters, if specified
elseif titleobj.namespace == 0 then -- NS_MAIN
+
if string.find( ','..(frame.args['$flags'] or '')..',', ',%s*remove%-empty%s*,' ) then
title = ':' .. titleobj.text
+
for k, v in pairs( args ) do
else
+
if v == '' then args[k] = nil end
title = titleobj.prefixedText
 
 
end
 
end
 +
end
  
-- Build the invocation body with numbered args first, then named
+
-- Pull information from parameter aliases
local ret = '{{' .. title
+
local aliases = {}
for k, v in ipairs( args ) do
+
if frame.args['$aliases'] then
if string.find( v, '=', 1, true ) then
+
local list = mw.text.split( frame.args['$aliases'], '%s*,%s*' )
-- likely something like 1=foo=bar, we need to do it as a named arg
+
for k, v in ipairs( list ) do
break
+
local tmp = mw.text.split( v, '%s*>%s*' )
end
+
aliases[tonumber(mw.ustring.match(tmp[1], '^[1-9][0-9]*$')) or tmp[1]] = ((tonumber(mw.ustring.match(tmp[2], '^[1-9][0-9]*$'))) or tmp[2])
ret = ret .. '|' .. v
+
end
args[k] = nil
+
end
 +
for k, v in pairs( aliases ) do
 +
if args[k] and ( not args[v] or args[v] == '' ) then
 +
args[v] = args[k]
 
end
 
end
for k, v in pairs( args ) do
+
args[k] = nil
ret = ret .. '|' .. k .. '=' .. v
+
end
 +
 
 +
-- Order parameters
 +
if frame.args['$params'] then
 +
local params, tmp = mw.text.split( frame.args['$params'], '%s*,%s*' ), {}
 +
for k, v in ipairs(params) do
 +
v = tonumber(mw.ustring.match(v, '^[1-9][0-9]*$')) or v
 +
if args[v] then tmp[v], args[v] = args[v], nil end
 
end
 
end
+
for k, v in pairs(args) do tmp[k], args[k] = args[k], nil end
return ret .. '}}'
+
args = tmp
else
 
---- Not substing
 
-- Just return the "body"
 
return frame.args['$B']
 
 
end
 
end
 +
 +
return mTemplateInvocation.invocation(name, args)
 
end
 
end
 +
 +
p[''] = p.main -- For backwards compatibility
  
 
return p
 
return p

Revision as of 08:31, 7 June 2017

Helper module to facilitate a substituted template transform into a template transclusion.

Maintenance templates, such as {{Citation needed}} or {{Refimprove}}, should never be substituted. A trick to avoid that is to make a template substitute to its transcluded form.

Infoboxes should use Module:Unsubst-infobox, as should any other templates with parameters listed in block format by default.

Usage

To turn a template into a self-substituting template, wrap the existing template code with:

{{SAFESUBST:<noinclude />#invoke:Unsubst||$B=

 [ ... existing template code ... ]

}}

The wikitext to display when not substed must be given as "$B". All other parameters passed to the #invoke will be copied to the generated template invocation as default values. If the value of any of these default parameters is __DATE__, that value in the generated template invocation will be the current month and year.

Some templates have a <noinclude> but no matching </noinclude> at the end of the template. In such cases the missing </noinclude> must be added before the ending }}.

Advanced

{{SAFESUBST:<noinclude />#invoke:Unsubst||$params=[ parameters ]|$aliases=[ aliases ]|$flags=[ flags ]|$B=

 [ ... existing template code ... ]

}}

Due to Lua limitations, parameters are normally ordered randomly when the template is substituted. |$params= can be used in #invoke:Unsubst to list template parameters in order, comma-separated (e.g. egg,bacon,sausage,cheese,spam). Numbered parameters should be before others in the list. Any remaining parameters are tacked onto the end of the generated invocation.

Parameter aliases can be listed in |$aliases= (and shouldn't be listed in |$params=), and will be replaced automatically. Each alias and its replacement should be formatted as alias>replacement, and each of those pairs should be comma-separated (e.g. œuf>egg,melt>cheese). Note that this parameter can function with or without |$params=.

Parameter |$flags= can be used to modify other facets of the module's behaviour; entries are comma-separated. Valid flags are override (allows parameters in the #invoke: to take precedence over parameters in the original template invocation); keep-whitespace (prevents whitespace from being trimmed from unnamed parameters); and remove-empty (removes empty parameters).

These parameters can be manipulated using parser functions to provide more complicated options (note that in the parameters any parser function, or template or module invocation, should also have SAFESUBST:<noinclude />).

Example

Consider a template Template:Example containing the following code:

{{SAFESUBST:<noinclude />#invoke:Unsubst||foo=bar |date=__DATE__ |$B=

 [ ... Template code goes here ... ]

}}
Original Result
Template:Tlsc {{Example|date=December 2025}}
Template:Tlsc {{Example|foo=X|date=December 2025}}
Template:Tlsc {{Example|baz=X|date=December 2025}}
Template:Tlsc {{Example|foo=bar|date=January 2001}}



local checkType = require('libraryUtil').checkType

local p = {}

local BODY_PARAM = '$B'

local specialParams = {
	['$params'] = 'parameter list',
	['$aliases'] = 'parameter aliases',
	['$flags'] = 'flags',
	['$B'] = 'template content'
}

function p.main(frame, body)
	-- If we are substing, this function returns a template invocation, and if
	-- not, it returns the template body. The template body can be specified in
	-- the body parameter, or in the template parameter defined in the
	-- BODY_PARAM variable. This function can be called from Lua or from
	-- #invoke.

	-- Return the template body if we aren't substing.
	if not mw.isSubsting() then
		if body ~= nil then
			return body
		elseif frame.args[BODY_PARAM] ~= nil then
			return frame.args[BODY_PARAM]
		else
			error(string.format(
				"no template content specified (use parameter '%s' from #invoke)",
				BODY_PARAM
			), 2)
		end
	end

	-- Sanity check for the frame object.
	if type(frame) ~= 'table'
		or type(frame.getParent) ~= 'function'
		or not frame:getParent()
	then
		error(
			"argument #1 to 'main' must be a frame object with a parent " ..
			"frame available",
			2
		)
	end

	-- Find the invocation name.
	local mTemplateInvocation = require('Module:Template invocation')
	local name = mTemplateInvocation.name(frame:getParent():getTitle())

	-- Combine passed args with passed defaults
	local args = {}
	if string.find( ','..(frame.args['$flags'] or '')..',', ',%s*override%s*,' ) then
		for k, v in pairs( frame:getParent().args ) do
			args[k] = v
		end
		for k, v in pairs( frame.args ) do
			if not specialParams[k] then
				if v == '__DATE__' then
					v = mw.getContentLanguage():formatDate( 'F Y' )
				end
				args[k] = v
			end
		end
	else
		for k, v in pairs( frame.args ) do
			if not specialParams[k] then
				if v == '__DATE__' then
					v = mw.getContentLanguage():formatDate( 'F Y' )
				end
				args[k] = v
			end
		end
		for k, v in pairs( frame:getParent().args ) do
			args[k] = v
		end
	end

	-- Trim parameters, if not specified otherwise
	if not string.find( ','..(frame.args['$flags'] or '')..',', ',%s*keep%-whitespace%s*,' ) then
		for k, v in pairs( args ) do args[k] = mw.ustring.match(v, '%s*(.*)%s*') or '' end
	end
	
	-- Remove empty parameters, if specified
	if string.find( ','..(frame.args['$flags'] or '')..',', ',%s*remove%-empty%s*,' ) then
		for k, v in pairs( args ) do
			if v == '' then args[k] = nil end
		end
	end

	-- Pull information from parameter aliases
	local aliases = {}
	if frame.args['$aliases'] then
		local list = mw.text.split( frame.args['$aliases'], '%s*,%s*' )
		for k, v in ipairs( list ) do
			local tmp = mw.text.split( v, '%s*>%s*' )
			aliases[tonumber(mw.ustring.match(tmp[1], '^[1-9][0-9]*$')) or tmp[1]] = ((tonumber(mw.ustring.match(tmp[2], '^[1-9][0-9]*$'))) or tmp[2])
		end
	end
	for k, v in pairs( aliases ) do
		if args[k] and ( not args[v] or args[v] == '' ) then
			args[v] = args[k]
		end
		args[k] = nil
	end

	-- Order parameters
	if frame.args['$params'] then
		local params, tmp = mw.text.split( frame.args['$params'], '%s*,%s*' ), {}
		for k, v in ipairs(params) do
			v = tonumber(mw.ustring.match(v, '^[1-9][0-9]*$')) or v
			if args[v] then tmp[v], args[v] = args[v], nil end
		end
		for k, v in pairs(args) do tmp[k], args[k] = args[k], nil end
		args = tmp
	end

	return mTemplateInvocation.invocation(name, args)
end

p[''] = p.main -- For backwards compatibility

return p