Jump to content

Module:Infobox ship

Permanently protected module
From Wikipedia, the free encyclopedia
This is an old revision of this page, as edited by Trappist the monk (talk | contribs) at 00:34, 21 October 2025. The present address (URL) is a permanent link to this revision, which may differ significantly from the current revision.

require('strict');

local utilities = require ('Module:WPSHIPS_utilities');
local infobox = require ('Module:Infobox').infobox;
local infobox_ship_flag = utilities._infobox_ship_flag;
local ship_name_format = utilities._ship_name_format;
local synonym_check = utilities._synonym_check;
local unbulleted_list = utilities._unbulleted_list;

local get_args = require ('Module:Arguments').getArgs;

local data = mw.loadData ('Module:Infobox_ship/data');


--[[--------------------------< L I N E _ I T E M S >-----------------------------------------------------------------------------

spin through <params_t> sequence.  Get parameter name and matching infobox label.  Look in <args_t> for parameter name.  When parameter
name has a value, add infobox label and parameter value to the infobox table <infobox_ship_t>.  <i> identifies where label and data
enumerators begin.

]]

local function line_items (args_t, params_t, infobox_ship_t, i, frame)
	for _, v in ipairs (params_t) do											-- v is a sequence table with parameter name and associated infobox label
		if args_t[v[1]] then													-- if parameter has a value
			infobox_ship_t['label' .. i] = v[2];								-- add the label
			infobox_ship_t['data' .. i] = unbulleted_list (args_t[v[1]]);		-- and add the parameter value as data
			i = i + 1;															-- bump the enumerator
		end
	end
end


--[[--------------------------< A D D _ W A R N I N G >--------------------------------------------------------

for unknown parameters, add a message in the edit-preview message box

<template> is the name of the enclosing infobox ship or one of the subtemplates
<k> is the parameter name
<v> is the parameter value

]]

local function add_warning (template, k, v)
	if v:find (data.stripmarker) then											-- if we find a templatestyles stripmarker
		v = '';																	-- suppress <v> as being too ugly
	end
	mw.addWarning (string.format (data.warning_fmt_str, data.warn_span_style, data.warn_code_style, template, template, data.warn_code_style, k, v));
--	has_unknown_params = (0 == data.namespace) or (118 == data.namespace) or (2 == data.namespace);				-- add unknown params category when infobox is rendered; mainspace and draftspace only
end


--[[--------------------------< U N K N O W N _ P A R A M S _C H E C K >---------------------------------------

check parameters supplied in <template> against known parameters for that template.  Emit preview warning when
a parameter is unknown.

Empty unknown parameters are not identified because Module:Arguments removes blank parameters by default.

]]

local function unknown_params_check (args_t, known_params_t, template)
	local has_unknown_params = false;
	for k, v in pairs (args_t) do
		if 'string' == type (k) then
			local param = k:gsub ('%d+$', '#');									-- for enumerated parameters, replace enumerator with '#'
			if not known_params_t[param] then
				add_warning (template, k, v);									-- add warning message when <param> is not known for <template>
				has_unknown_params = (0 == data.namespace) or (118 == data.namespace) or (2 == data.namespace);	-- add unknown params category when infobox is rendered; mainspace and draftspace only
			end
		else																	-- here when <k> not a string (likely a positional parameter)
			add_warning (template, k, v);										-- add warning message when <param> is not known for <template>
			has_unknown_params = (0 == data.namespace) or (118 == data.namespace) or (2 == data.namespace);	-- add unknown params category when infobox is rendered; mainspace and draftspace only
		end
	end
	return has_unknown_params;
end


--[[--------------------------< F I N A L _ R E N D E R I N G >------------------------------------------------

final rendering for the various subtemplates

]]

local function final_rendering (infobox_ship_t, frame)
	if 'yes' ~= infobox_ship_t.child then										-- when not 'yes', we are in stand-alone mode
		infobox_ship_t.bodyclass = 'mainbox';									-- use basic infobox css for stand-alone mode

		return table.concat ({
				frame:extensionTag ('templatestyles', '', {src='Module:Infobox ship/styles.css'}),				-- apply templatestyles
				infobox (infobox_ship_t),										-- render the infobox
				(has_unknown_params and '[[Category:Pages using infobox ship with unknown parameters]]' or '')	-- add category for any unknown parameters
			});
	else
		return frame:expandTemplate ({title='Infobox', args = infobox_ship_t});	-- return a rendering of this infobox
	end
end


--[[--------------------------< I N F O B O X _ S H I P _ B E G I N >------------------------------------------

fill infobox table parameters 'bodystyle' and 'title' (infobox caption); auto-article title formatting ({{DISPLAYTITLE}})

]]

local function infobox_ship_begin (args_t, infobox_ship_t, frame)
	local name = mw.title.getCurrentTitle().text;

	infobox_ship_t['bodyclass'] = 'mainbox';

	if args_t.infobox_caption then
		if 'yes' == args_t.infobox_caption then									-- format article title as infobox caption
			infobox_ship_t.title = ship_name_format ({name=name, adj='off', showerrs=args_t.showerrs, sclass=args_t.sclass});
		elseif 'nodab' == args_t.infobox_caption then							-- format article title without disambiguation as infobox caption
			infobox_ship_t.title = ship_name_format ({name=name, dab='none', showerrs=args_t.showerrs});
		else																	-- use value supplied in |infobox_caption= as infobox caption
			infobox_ship_t.title = args_t.infobox_caption;
		end
	else
		infobox_ship_t.title = '';												-- to allow for possible displaytitle concatenation
	end

	if args_t.display_title then
		if 'ital' == args_t.display_title then									-- use {{italic title}} template
			infobox_ship_t.title = infobox_ship_t.title .. require ('Module:italic title')._main ({});	-- {{italic title}} without template overhead
		elseif ('none' ~= args_t.display_title) then							-- any value but 'none'	use value in |display_title= for {{DISPLAYTITLE}} magic word
			infobox_ship_t.title = infobox_ship_t.title .. frame:preprocess ('{{DISPLAYTITLE:' .. args_t.display_title .. '}}');
		end
	else																		-- |display_title= empty or omitted, use article title
		infobox_ship_t.title = infobox_ship_t.title .. frame:preprocess ('{{DISPLAYTITLE:' .. ship_name_format ({name=name, sclass=args_t.sclass}) .. '}}');
	end
end	


--[[--------------------------< I N F O B O X _ S H I P _ I M A G E >------------------------------------------

Returns a child infobox for Infobox ship/image unless |child=no for a stand-alone rendering

images in {{infobox ship}} default to 300px; upright is ignored

]]

local function infobox_ship_image (frame)
	local args_t = get_args (frame);

	if not args_t.image then
		return ((0 == namespace) or (118 == namespace)) and data.categories_t.no_image;		-- if no image specified, abandon with category
	end
	
	local infobox_ship_t = {
		child = args_t.child or 'yes';											-- default to child
		image1 = require ('Module:InfoboxImage').InfoboxImage ({args = {'InfoboxImage', 'InfoboxImage', image=args_t.image, size=args_t.image_size, alt=args_t.image_alt, sizedefault = '300px'}});	-- upright='1' ignored
		caption1 = args_t.image_caption;
		}

	local has_unknown_params = unknown_params_check (args_t, data.known_infobox_ship_image_params_t, 'Infobox ship/image');

	return table.concat ({
		final_rendering (infobox_ship_t, frame),								-- return final rendering of this infobox
		(has_unknown_params and data.categories_t.unknown) or ''
		});
end


--[[--------------------------< I N F O B O X _ S H I P _ C A R E E R >----------------------------------------

Returns a child infobox for Infobox ship/career unless |child=no for a stand-alone rendering

]]

local function infobox_ship_career (frame)
	local template_name = 'Infobox ship/career';
	local args_t = get_args (frame);
	args_t.hide_header= args_t.hide_header and args_t.hide_header:lower();		-- set to lowercase if set

	local infobox_ship_t = {
		child = args_t.child or 'yes';											-- default to child
		headerclass = 'country';
		}

	if args_t.infobox_caption then												-- special case for |infobox_caption=
		if 'yes' == infobox_ship_t.child then									-- if not stand-alone
			add_warning (template_name, 'infobox_caption', args_t.infobox_caption);	--emit preview warning message
		else
			infobox_ship_t.title = args_t.infobox_caption;						-- translate |infobox_caption= to |title= used by Module:Infobox
			args_t.infobox_caption = nil;										-- unset to avoid preview error message; no longer needed
		end
	end
		
	local i = 1;

	if 'yes' ~= args_t.hide_header then											-- |hide_header=yes then no header
		if not ('title' == args_t.hide_header) then								-- |hide_header=title then no title bar
			local spoof_t = {
				child = 'yes',													-- default to child
				decat = 'yes',													-- spoof infobox does not have data; don't categorize in Category:Articles using infobox templates with no data rows
				header1 = 'History',
				headerclass = "history",
				}

			infobox_ship_t.data1 = frame:expandTemplate ({title='Infobox', args = spoof_t});	-- return a rendering of this spoof infobox
			i = i + 1;
		end

		if args_t.ship_country and args_t.ship_flag then
			infobox_ship_t['header' .. i] = infobox_ship_flag (args_t.ship_flag) .. '<span style="padding-left:1em">' .. args_t.ship_country .. '</span>';
		elseif args_t.ship_country then
			infobox_ship_t['header' .. i] = args_t.ship_country;
		elseif args_t.ship_flag then
			infobox_ship_t['header' .. i] = infobox_ship_flag (args_t.ship_flag);
		end
	end

	if infobox_ship_t['header' .. i] then
		i = i + 1;
	end
	
	local error_flag;
	error_flag = synonym_check (args_t, 'ship_stricken', 'ship_struck', error_flag);	-- error if both synonymous parameters set
	synonym_check (args_t, 'ship_honours', 'ship_honors', error_flag);

	line_items (args_t, data.infobox_career_params_t, infobox_ship_t, i, frame);		-- go do all of the other infobox parameters
	local has_unknown_params = unknown_params_check (args_t, data.known_infobox_ship_career_params_t, 'Infobox ship/career');

	return table.concat ({
		final_rendering (infobox_ship_t, frame),								-- return final rendering of this infobox
		(has_unknown_params and data.categories_t.unknown) or ''
		});
end


--[[--------------------------< I N F O B O X _ S H I P _ C H A R A C T E R I S T I C S >----------------------

Returns a child infobox for Infobox ship/characteristics unless |child=no for a stand-alone rendering

]]

local function infobox_ship_characteristics (frame)
	local template_name = 'Infobox ship/characteristics';
	local args_t = get_args (frame);
	args_t.hide_header= args_t.hide_header and args_t.hide_header:lower();		-- set to lowercase if set

	local infobox_ship_t = {
		child = args_t.child or 'yes',											-- default to child
		headerclass = 'general'
		}
	
	if args_t.infobox_caption then												-- special case for |infobox_caption=
		if 'yes' == infobox_ship_t.child then									-- if not stand-alone
			add_warning (template_name, 'infobox_caption', args_t.infobox_caption);	--emit preview warning message
		else
			infobox_ship_t.title = args_t.infobox_caption;						-- translate |infobox_caption= to |title= used by Module:Infobox
			args_t.infobox_caption = nil;										-- unset to avoid preview error message; no longer needed
		end
	end
		
	local i = 1;

	if 'yes' ~= args_t.hide_header then											-- |hide_header=yes then no header
		local header = 'General characteristics';								-- the default header
		if args_t.header_caption then
			header = header .. ' ' .. args_t.header_caption;					-- concatenate |header_caption= onto default header
		end
		infobox_ship_t['header' .. i] = header;									-- add the header
		i = i + 1;																-- bump the enumerator
	end

	local error_flag;
	error_flag = synonym_check (args_t, 'ship_armour', 'ship_armor', error_flag);	-- error if both synonymous parameters set
	synonym_check (args_t, 'ship_draught', 'ship_draft', error_flag);				-- when both set modify with error message and category

	line_items (args_t, data.infobox_characteristics_params_t, infobox_ship_t, i, frame);	-- go do all of the other infobox parameters
	local has_unknown_params = unknown_params_check (args_t, data.known_infobox_ship_characteristics_params_t, template_name);

	return table.concat ({
		final_rendering (infobox_ship_t, frame),								-- return final rendering of this infobox
		(has_unknown_params and data.categories_t.unknown) or ''
		});
end


--[[--------------------------< I N F O B O X _ S H I P _ C L A S S _ O V E R V I E W >------------------------

Returns a child infobox for Infobox ship/class overview unless |child=no for a stand-alone rendering

]]

local function infobox_ship_class_overview (frame)
	local template_name = 'Infobox ship/class overview';
	local args_t = get_args (frame);
	args_t.hide_header= args_t.hide_header and args_t.hide_header:lower();		-- set to lowercase if set

	local infobox_ship_t = {
		child = args_t.child or 'yes',											-- default to child
		headerclass = 'general'
		}
	
	if args_t.infobox_caption then												-- special case for |infobox_caption=
		if 'yes' == infobox_ship_t.child then									-- if not stand-alone
			add_warning (template_name, 'infobox_caption', args_t.infobox_caption);	--emit preview warning message
		else
			infobox_ship_t.title = args_t.infobox_caption;						-- translate |infobox_caption= to |title= used by Module:Infobox
			args_t.infobox_caption = nil;										-- unset to avoid preview error message; no longer needed
		end
	end

	local i = 1;

	if 'yes' ~= args_t.hide_header then											-- |hide_header=yes then no header
		infobox_ship_t['header' .. i] = 'Class overview';						-- add the header
		i = i + 1;																-- bump the enumerator
	end

	synonym_check (args_t, 'total_ships_cancelled', 'total_ships_canceled', nil);	-- error if both synonymous parameters set

	line_items (args_t, data.infobox_class_overview_params_t, infobox_ship_t, i, frame);	-- go do all of the other infobox parameters
	local has_unknown_params = unknown_params_check (args_t, data.known_infobox_ship_class_overview_params_t, template_name);

	return table.concat ({
		final_rendering (infobox_ship_t, frame),								-- return final rendering of this infobox
		(has_unknown_params and data.categories_t.unknown) or ''
		});
end


--[[--------------------------< I N F O B O X _ S H I P _ S E R V I C E _ R E C O R D >------------------------

Returns a child infobox for Infobox ship/service record unless |child=no for a stand-alone rendering.  This
function implements the ship-only portion of {{Infobox service record}}; does not know about |is_ship= and
|is_multi= parameters.  Adds support for |hide_header= parameter

]]

local function infobox_ship_service_record (frame)
	local template_name = 'Infobox ship/service record';
	local args_t = get_args (frame);
	args_t.hide_header= args_t.hide_header and args_t.hide_header:lower();		-- set to lowercase if set

	local infobox_ship_t = {
		child = args_t.child or 'yes',											-- default to child
		headerclass = 'general'
		}
	
	if args_t.infobox_caption then												-- special case for |infobox_caption=
		if 'yes' == infobox_ship_t.child then									-- if not stand-alone
			add_warning (template_name, 'infobox_caption', args_t.infobox_caption);	--emit preview warning message
		else
			infobox_ship_t.title = args_t.infobox_caption;						-- translate |infobox_caption= to |title= used by Module:Infobox
			args_t.infobox_caption = nil;										-- unset to avoid preview error message; no longer needed
		end
	end

	local i = 1;

	if 'yes' ~= args_t.hide_header then											-- |hide_header=yes then no header
		infobox_ship_t['header' .. i] = args_t.header_caption or args_t.label or 'Service record';		-- add the header; |label= is deprecated
		i = i + 1;																-- bump the enumerator
	end

	line_items (args_t, data.infobox_ship_service_record_params_t, infobox_ship_t, i, frame);	-- go do all of the other infobox parameters
	local has_unknown_params = unknown_params_check (args_t, data.known_infobox_ship_service_record_params_t, template_name);

	return table.concat ({
		final_rendering (infobox_ship_t, frame),								-- return final rendering of this infobox
		(has_unknown_params and data.categories_t.unknown) or ''
		});
end


--[[--------------------------< I N F O B O X _ S H I P >------------------------------------------------------

{{#invoke:Infobox ship|infobox_ship}}

To discover when two child infoboxen are concatenated without a proper |sectionn= parameter between them, this
function looks for and counts template styles strip markers.  Each child prepends a <templatestyles>...</templatestyles>
tags to its rendering.  MediaWiki returns stripmarkers for those tags which will be replaced at the final rendering
of the page.  This function counts the stripmarkers in each parameter.  If there are:
	0 stripmarkers – ok; parameter does not include a child infobox rendering
	1 – ok; parameter holds a child infobox
	2 – ok if one of them has has class="infobox-header history"; {{infobox ship/history}} creates a child of its own for the history header; TODO: is there a better way to do that?
	2 – not ok when neither has class="infobox-header history"
	3+ – not ok

]]

local function infobox_ship (frame)
	local args_t = get_args (frame);

	local infobox_ship_t = {}													-- table that holds infobox parameters

	infobox_ship_begin (args_t, infobox_ship_t, frame);							-- fetch parameters that once belonged to obsolete {{infobox ship begin}}

	for k, v in pairs (args_t) do												-- copy infobox parameters from the frame into our local table
		if 'string' == type (k) then											-- must be string; positional parameters no supported
			local enum = k:match ('section(%d+)');								-- <enum> gets a value when this parameter is |section<n>= 
			if enum then
				infobox_ship_t['data'..enum] = v;								-- translate |section<n> = to |data<n>=
			else
				infobox_ship_t[k] = v;											-- assume that parameter name is one known to Module:Infobox
			end
		end
	end
mw.logObject (infobox_ship_t)
	for k, v in pairs (infobox_ship_t) do										-- look for malformed input (concatenated child infoboxen)
		local _, count = v:gsub (data.stripmarker, '');							-- count templatestyles stripmarkers; there should only be one 

		if ((2 == count) and not v:find ('class="infobox-header history"', 1, true)) or 	-- plain-text find the <spoof_t> ibox that is the history header which will emit a second stripmarker
			2 < count then
				infobox_ship_t[k] = table.concat ({
					string.format (data.error_messages_t.missing_section, k:match ('%d')),		-- emit an error message
					((0 == namespace) or (118 == namespace)) and data.categories_t.no_image or '',
					});
		end
	end

	local has_unknown_params = unknown_params_check (args_t, data.known_infobox_ship_params_t, 'Infobox ship');

	return table.concat ({
			frame:extensionTag ('templatestyles', '', {src='Module:Infobox ship/styles.css'}),	-- apply template styles
			infobox (infobox_ship_t),											-- render the infobox
			(has_unknown_params and data.categories_t.unknown) or ''			-- add category for any unknown parameters
		});
end

		
--[[--------------------------< E X P O R T S >----------------------------------------------------------------
]]

return {
	infobox_ship = infobox_ship,
	infobox_ship_image = infobox_ship_image,
	infobox_ship_career = infobox_ship_career,
	infobox_ship_characteristics = infobox_ship_characteristics,
	infobox_ship_class_overview = infobox_ship_class_overview,
	infobox_ship_service_record = infobox_ship_service_record,
	}