ሞደል:Module rating ሞደል:High-risk

{{SAFESUBST:<noinclude />#invoke:Unsubst-infobox||$B=template body|$params=parameters}}

Infoboxes should never be substituted. A trick to avoid that is to make a template substitute to its transcluded form. This module is similar to Module:Unsubst. parameters is a comma-separated list of the names of parameters the invoking infobox template can take.

Parameter list

ኣመዓራርይ
$B
The content of the template, as it would be without the module being used.
$params
A comma-separated list of template parameters, without any aliases. There is a bug when including positional parameters like $params=1 in the template and {{subst:example|a}} in the article where it will be overwritten like {{subst:example|a|1=}}.
$aliases
A comma-separated list of parameter replacements, in the format old1>new1,old2>new2. There is a bug when including positional parameters like |$aliases=2>details|$params=details in the template and {{subst:example|abc|def|ghi}} in the article where there is an inconsistency that causes data to be lost like {{subst:example|abc|details=def}}
$set3
Usually a shorter list of parameters, comma-separated. Replaces $params when all the parameters used in a substitution (ignoring those erroneously absent from $params) are in this list. This might be used if an infobox has multiple parameters that are only applicable to some group of articles.
$set2
Conditionally replaces $set3 or $params, whichever was last chosen. Usually bigger than them.
$set1
Conditionally replaces $set3, $set2 or $params, whichever was last chosen. Usually bigger than them.
$extra
A comma-separated list of any parameters listed in $params (or $set1, $set2, or $set3, whichever was chosen) which don't need to be shown after substitution unless they are already being used in the template; i.e. if a parameter is in both lists and is not used or blank in a particular transclusion, then on substitution the parameter will not be displayed.
$indent
The number of additional spaces before each line. Useful for child infoboxes.
$flags
A list of comma-separated flags. The only valid input for this parameter at present is "override", which tells the template to supersede the original input to the template with any parameters which are set in the module; i.e. if the template transclusion uses |number=6 but the module invocation uses |date=7, if the module invocation contains override in |$flags= then the output will be |date=7 and if it doesn't then the output will be |date=6.
$template-name
May be used to override the default template name.

All other parameters are treated as input to the template. If the input value is not blank and the input parameter is a valid parameter of the template, then the value will appear in the post-substitution content if the transclusion's value is blank; if the module invocation contains override in |$flags= then the value will appear in the post-substitution content regardless of what the transclusion's value is.



local p = {}

local specialParams = {
	['$params'] = 'all parameters',
	['$extra'] = 'extra parameters',
	['$set1'] = 'parameter set 1',
	['$set2'] = 'parameter set 2',
	['$set3'] = 'parameter set 3',
	['$aliases'] = 'parameter aliases',
	['$indent'] = 'indent',
	['$flags'] = 'flags',
	['$B'] = 'template content',
	['$template-name'] = 'template invocation name override'
}

p[''] = function ( frame )
	if not frame:getParent() then
		error( '{{#invoke:Unsubst-infobox|}} makes no sense without a parent frame' )
	end
	if not frame.args['$B'] then
		error( '{{#invoke:Unsubst-infobox|}} requires parameter $B (template content)' )
	end
	if not frame.args['$params'] then
		error( '{{#invoke:Unsubst-infobox|}} requires parameter $params (parameter list)' )
	end

	if mw.isSubsting() then
		---- substing
		-- 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

		-- Build an equivalent template invocation
		-- First, find the title to use
		local titleobj = mw.title.new(frame:getParent():getTitle())
		local title
		if titleobj.namespace == 10 then -- NS_TEMPLATE
			title = titleobj.text
		elseif titleobj.namespace == 0 then -- NS_MAIN
			title = ':' .. titleobj.text
		else
			title = titleobj.prefixedText
		end

		if frame.args['$template-name'] and '' ~= frame.args['$template-name'] then
			title = frame.args['$template-name'] -- override whatever the template name is with this name
		end

		-- Remove empty fields
		for k, v in pairs( args ) do
			if v == '' then args[k] = nil end
		end

		-- Pull information from parameter aliases
		local aliases, extra = {}, {}
		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*' )
				local alias = (tonumber(mw.ustring.match(tmp[1], '^[1-9][0-9]*$'))) or tmp[1]
				aliases[alias] = ((tonumber(mw.ustring.match(tmp[2], '^[1-9][0-9]*$'))) or tmp[2])
				extra[alias] = true
			end
		end
		for k, v in pairs( aliases ) do
			if args[k] and not args[v] then args[v], args[k] = args[k], nil end
		end

		-- Build the invocation body with numbered args first, then named
		local ret = '{{' .. title
		for k, v in ipairs( args ) do
			if mw.ustring.find( v, '=', 1, true ) then
				-- likely something like 1=foo=bar, we need to do it as a named arg
				break
			end
			ret = ret .. '|' .. v
			args[k] = nil
		end

		-- Pull lists from special parameters
		local discard = {}
		local params = mw.text.split( frame.args['$params'], '%s*,%s*' )
		for k, v in ipairs( params ) do
			-- Numbered args don't go here
			if mw.ustring.match(v, '^[1-9][0-9]*$') then
				table.insert( discard, 1, k )
			end
		end
		for k, v in ipairs( discard ) do table.remove( params, v ) end
		local sets, setparams = {{}, {}, {}}, {}
		for k = 1, 3 do
			local v = frame.args['$set' .. k]
			if v then
				setparams[k] = mw.text.split( v, '%s*,%s*' )
				discard = {}
				for x, y in ipairs( setparams[k] ) do
					sets[k][setparams[k][x]] = true
					-- Numbered args don't go here
					if mw.ustring.match(y, '^[1-9][0-9]*$') then
						table.insert( discard, 1, x )
					end
				end
    			for x, y in ipairs( discard ) do table.remove( setparams[k], y ) end
			end
		end
		if frame.args['$extra'] then
			local tmp = mw.text.split( frame.args['$extra'], '%s*,%s*' )
			for k, v in ipairs( tmp ) do extra[(tonumber(mw.ustring.match(v, '^[1-9][0-9]*$'))) or v] = true end
		end

		-- Replace parameter list with short version if full version not necessary
		local tmp = {}
		for k, v in ipairs( sets ) do
			if next(v) then  -- if table v is not empty
				for _, x in ipairs( params ) do
					if args[x] and not v[x] then
						tmp[k] = true
						break
					end
				end
				if not tmp[k] then params = setparams[k] end
			end
		end

		-- Align parameters correctly and remove extra ones
		local maxlength = 0
		discard = {}
		for k, v in ipairs( params ) do
			if (not extra[v]) or args[v] then
				local tmp = mw.ustring.len( tostring( v ) )
				if tmp > maxlength then maxlength = tmp end
			else
				table.insert( discard, 1, k )
			end
		end
		for k, v in ipairs( discard ) do table.remove( params, v ) end
		local indent = mw.ustring.rep(' ', (tonumber(frame.args['$indent']) or 0))
		-- Numbered args after discontinuity continue first
		discard = {}
		for k, v in pairs( args ) do
			if mw.ustring.match(k, '^[1-9][0-9]*$') then table.insert ( discard, 1, k ) end
		end
		for k, v in ipairs( discard ) do table.insert( params, 1, v ) end

		local space, newline = ' ', '\n'
		if not next(params) then space, newline = '', '' end

		for k, v in ipairs( params ) do
			local tmp = space
			if mw.ustring.match( mw.ustring.sub( ( args[v] or '' ) .. ' ', 1, 1 ), '[%*:;#]' ) then tmp = '\n' end
			ret = ret .. newline .. indent .. '|' .. space .. v .. string.rep(' ', (maxlength - mw.ustring.len( v ))) .. space .. '=' .. tmp .. (args[v] or '')
		end
		
		ret = ret .. newline .. '}}'

		ret = mw.ustring.gsub(ret, '%s+\n', '\n')

		return ret
	else
		-- Not substing
		-- Just return the "body"
		return frame.args['$B']
	end
end

return params