Module:Unsubst: Difference between revisions
meta>Jc86035 m fix whitespace removal; remove empty parameters after handling aliases and prevent removal of two or fewer consecutive empty parameters in a sequence |
m Syntax tweaks |
||
(5 intermediate revisions by 5 users not shown) | |||
Line 9: | Line 9: | ||
['$aliases'] = 'parameter aliases', | ['$aliases'] = 'parameter aliases', | ||
['$flags'] = 'flags', | ['$flags'] = 'flags', | ||
['$B'] = 'template content' | ['$B'] = 'template content', | ||
['$template-name'] = 'template invocation name override', | |||
} | } | ||
--[[ | |||
If we are subst'ing, 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. | |||
--]] | |||
function p.main(frame, body) | function p.main(frame, body) | ||
-- Return the template body if we aren't subst'ing. | |||
-- Return the template body if we aren't | |||
if not mw.isSubsting() then | if not mw.isSubsting() then | ||
if body ~= nil then | if body ~= nil then | ||
Line 47: | Line 48: | ||
-- Find the invocation name. | -- Find the invocation name. | ||
local mTemplateInvocation = require('Module:Template invocation') | local mTemplateInvocation = require('Module:Template invocation') | ||
local name = mTemplateInvocation.name(frame:getParent():getTitle()) | local name | ||
if frame.args['$template-name'] and '' ~= frame.args['$template-name'] then | |||
-- Override whatever the template name is with this name. | |||
name = frame.args['$template-name'] | |||
else | |||
name = mTemplateInvocation.name(frame:getParent():getTitle()) | |||
end | |||
-- Combine passed args with passed defaults | -- Combine passed args with passed defaults. | ||
local args = {} | local args = {} | ||
if string.find( ','..(frame.args['$flags'] or '')..',', ',%s*override%s*,' ) then | if string.find( ','..(frame.args['$flags'] or '')..',', ',%s*override%s*,' ) then | ||
Line 77: | Line 85: | ||
end | end | ||
-- Trim parameters, if not specified otherwise | -- Trim parameters, if not specified otherwise. | ||
if not string.find( ','..(frame.args['$flags'] or '')..',', ',%s*keep%-whitespace%s*,' ) then | 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 | for k, v in pairs( args ) do args[k] = mw.ustring.match(v, '^%s*(.*)%s*$') or '' end | ||
end | end | ||
-- Pull information from parameter aliases | -- Pull information from parameter aliases. | ||
local aliases = {} | local aliases = {} | ||
if frame.args['$aliases'] then | if frame.args['$aliases'] then | ||
Line 98: | Line 106: | ||
end | end | ||
-- Remove empty parameters, if specified | -- Remove empty parameters, if specified. | ||
if string.find( ','..(frame.args['$flags'] or '')..',', ',%s*remove%-empty%s*,' ) then | if string.find( ','..(frame.args['$flags'] or '')..',', ',%s*remove%-empty%s*,' ) then | ||
local tmp = 0 | local tmp = 0 | ||
Line 115: | Line 123: | ||
end | end | ||
-- Order parameters | -- Order parameters. | ||
if frame.args['$params'] then | if frame.args['$params'] then | ||
local params, tmp = mw.text.split( frame.args['$params'], '%s*,%s*' ), {} | local params, tmp = mw.text.split( frame.args['$params'], '%s*,%s*' ), {} |
Latest revision as of 20:53, 23 November 2024
This is a helper module to facilitate a substituted template's transformation into a normal template transclusion.
Maintenance templates, such as {{Citation needed}}
or {{More citations needed}}
, should never be substituted. A trick to avoid that is to make a template substitute to its transcluded form.
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-delimited (e.g. egg,bacon,sausage,cheese,spam
). Numbered parameters should be before others in the list, then 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-delimited as well (e.g. œuf>egg,melt>cheese
). Note that this parameter can function with or without |$params=
.
The |$flags=
parameter can be used to modify other facets of the module's behaviour, and again, entries are comma-delimited. 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 |
---|---|
{{subst:example}} |
{{Example|date=November 2024}}
|
{{subst:example|foo=X}} |
{{Example|foo=X|date=November 2024}}
|
{{subst:example|baz=X}} |
{{Example|baz=X|date=November 2024}}
|
{{subst:example|date=January 2001}} |
{{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',
['$template-name'] = 'template invocation name override',
}
--[[
If we are subst'ing, 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.
--]]
function p.main(frame, body)
-- Return the template body if we aren't subst'ing.
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
if frame.args['$template-name'] and '' ~= frame.args['$template-name'] then
-- Override whatever the template name is with this name.
name = frame.args['$template-name']
else
name = mTemplateInvocation.name(frame:getParent():getTitle())
end
-- 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
-- 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
-- Remove empty parameters, if specified.
if string.find( ','..(frame.args['$flags'] or '')..',', ',%s*remove%-empty%s*,' ) then
local tmp = 0
for k, v in ipairs( args ) do
if v ~= '' or ( args[k+1] and args[k+1] ~= '' ) or ( args[k+2] and args[k+2] ~= '' ) then
tmp = k
else
break
end
end
for k, v in pairs( args ) do
if v == '' then
if not (type(k) == 'number' and k < tmp) then args[k] = nil end
end
end
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