Jump to content

Module:Taxobox

From Wikipedia, the free encyclopedia
This is an old revision of this page, as edited by SWinxy (talk | contribs) at 20:51, 12 September 2022 (Range maps, synonyms, text-align: left;, trinomial no longer tries to filter, misspelling). The present address (URL) is a permanent link to this revision, which may differ significantly from the current revision.
local p = {}

local infobox = require("Module:Infobox")
local infoboxImage = require("Module:InfoboxImage")
local arguments = require("Module:Arguments")
local ifPreview = require("Module:If preview")

local colors = {
	animalia = "ebebd2",
	archaea = "c3f5fa",
	archaeplastida = "b4fab4",
	bacteria = "dcebf5",
	eukaryota = "f5d7ff",
	fungi = "91fafa",
	incertae_sedis = "faf0e6",
	sar = "c8fa50",
	veterovata = "fafadc",
	virus = "fafabe",
}

-- aliases that use the same color
-- TODO: combine the tables?
local colorAliases = {
	animal = "animalia",
	
	nanoarchaeota = "archaea",
	nanarchaeota = "archaea",
	korarchaeota = "archaea",
	thaumarchaeota = "archaea",
	crenarchaeota = "archaea",
	euryarchaeota = "archaea",
	
	plantae = "archaeplastida",
	plant = "archaeplastida",
	viridiplantae = "archaeplastida",
	
	firmicutes = "bacteria",
	eubacteria = "bacteria",
	
	eukaryote = "eukaryota",
	eukarya = "eukaryota",
	excavata = "eukaryota",
	excavates = "eukaryota",
	protista = "eukaryota",
	protists = "eukaryota",
	amoebozoa = "eukaryota",
	opisthokonta = "eukaryota",
	choanozoa = "eukaryota",
	
	acritarcha = "incertae_sedis",
	
	chromalveolata = "sar",
	
	viroid = "virus",
	viroids = "virus",
	viruses = "virus",
	i = "virus",
	ii = "virus",
	iii = "virus",
	iv = "virus",
	v = "virus",
	vi = "virus",
	vii = "virus",
	vii = "virus",
}

-- This table shows which order the color search should go
local taxonOrder = {
	"phylum", "unranked_phylum", "divisio", "unranked_superdivisio", "superphylum", "unranked_superphylum", "superdivision", "unranked_superdivisio",
	"subregnum", "unranked_subregnum", "regnum", "unranked_regnum", "superregnum", "unranked_superregnum", "domain", "unranked_domain", "virus_group"
}

-- Gets the background color as a hex code, if possible
--
-- @param args the arguments passed in to the template
--
-- @return a hex color, or nil if no color should be shown
local function getColor(args)
	for _, taxon in ipairs(taxonOrder) do
		local v = args[taxon]
		if v then
			local delinked = mw.ustring.gsub(mw.ustring.lower(v), "[\]\[']", "") -- delink, converting "[[''name'']]" to "name"
			local i = mw.ustring.find(delinked, "|")
			local sanitized = i and mw.ustring.sub(delinked, 0, i - 1) or delinked -- get "abx" from "abc|xyz"
			local hex = colors[sanitized] or colors[colorAliases[sanitized]]
			if hex then
				return hex
			end
		end
	end
end

local classification = {
	{ arg_name = "superdomain", label = "Superdomain" },
	{ arg_name = "domain", label = "Domain" },
	{ arg_name = "superregnum", label = "Superkingdom" },
	{ arg_name = "regnum", label = "Kingdom" },
	{ arg_name = "subregnum", label = "Subkingdom" },
	{ arg_name = "superdivisio", label = "Superdivision" },
	{ arg_name = "superphylum", label = "Superphylum" },
	{ arg_name = "divisio", label = "Division" },
	{ arg_name = "phylum", label = "Phylum" },
	{ arg_name = "subdivisio", label = "Subdivision" },
	{ arg_name = "subphylum", label = "Subphylum" },
	{ arg_name = "infraphylum", label = "Infraphylum" },
	{ arg_name = "microphylum", label = "Microphylum" },
	{ arg_name = "nanophylum", label = "Nanophylum" },
	{ arg_name = "superclassis", label = "Superclass" },
	{ arg_name = "classis", label = "Class" },
	{ arg_name = "subclassis", label = "Subclass" },
	{ arg_name = "infraclassis", "Infraclass" },
	{ arg_name = "magnordo", label = "Magnorder" },
	{ arg_name = "superordo", label = "Superorder" },
	{ arg_name = "ordo", label = "Order" },
	{ arg_name = "subordo", label = "Suborder" },
	{ arg_name = "infraordo", label = "Infraorder" },
	{ arg_name = "parvordo", label = "Parvorder" },
	{ arg_name = "zoodivisio", label = "Division" },
	{ arg_name = "zoosectio", label = "Section" },
	{ arg_name = "zoosubsectio", label = "Subsection" },
	{ arg_name = "superfamilia", label = "Superfamily" },
	{ arg_name = "familia", label = "Family" },
	{ arg_name = "subfamilia", label = "Subfamily" },
	{ arg_name = "supertribus", label = "Supertribe" },
	{ arg_name = "tribus", label = "Tribe" },
	{ arg_name = "subtribus", label = "Subtribe" },
	{ arg_name = "alliance", label = "''Alliance''" },
	{ arg_name = "genus", label = "Genus" },
	{ arg_name = "subgenus", label = "Subgenus" },
	{ arg_name = "sectio", label = "Section" },
	{ arg_name = "subsectio", label = "Subsection" },
	{ arg_name = "series", label = "Series" },
	{ arg_name = "subseries", label = "Subseries" },
	{ arg_name = "species_group", label = "''Species group''" },
	{ arg_name = "species_subgroup", label = "''Species subgroup''" },
	{ arg_name = "species_complex", label = "''Species complex''" },
	{ arg_name = "species", label = "Species" },
	{ arg_name = "subspecies", label = "Subspecies" },
	{ arg_name = "variety", label = "Variety" }, -- no unranked
	{ arg_name = "varias", label = "Variety" }, -- no unranked; alias of variety
	{ arg_name = "forma", label = "Form" }, -- no unranked
}

-- InfoboxImage: [[File:Status <status_system> <file>.svg|link=|alt=<category>]]
-- AddCaption: <label>
-- AddCategory: [[Category:<category>]]
local statusSystems = {
	["iucn2.3"] = {
		link = "IUCN Red List",
		EX = { file = "EX", label = "[[Extinct]]", category = "IUCN Red List extinct species" },
		EW = { file = "EW", label = "[[Extinct in the wild]]", category = "IUCN Red List extinct in the wild species" },
		CR = { file = "CR", label = "[[Critically endangered]]", category = "IUCN Red List critically endangered species" },
		EN = { file = "EN", label = "[[Endangered species|Endangered]]", category = "IUCN Red List endangered species" },
		VU = { file = "VU", label = "[[Vulnerable species|Vulnerable]]", category = "IUCN Red List vulnerable species" },
		LR = {file = "blank", label = "Lower risk", category = "Invalid conservation status" },
		CD = { file = "CD", label = "[[Conservation dependent]]", category = "IUCN Red List conservation dependent species" },
		["LR/CD"] = { file = "CD", label = "[[Conservation dependent]]", category = "IUCN Red List conservation dependent species" }, -- duplicate
		NT = { file = "NT", label = "[[Near threatened]]", category = "IUCN Red List near threatened species" },
		["LR/NT"] = { file = "NT", label = "[[Near threatened]]", category = "IUCN Red List near threatened species" }, -- duplicate
		LC = { file = "LC", label = "[[Least concern]]", category = "IUCN Red List near threatened species" },
		["LR/LC"] = { file = "LC", label = "[[Least concern]]", category = "IUCN Red List near threatened species" },
		DD = { file = "blank", label = "[[Least deficient]]", category = "IUCN Red List data deficient species" },
		NE = { label = "''Not evaluated''" },
		NR = { label = "''Not recognized''" },
		PE = { file = "CR", label = "[[Critically endangered]], possibly extinct", category = "IUCN Red List critically endangered species" },
		PEW = { file = "CR", label = "[[Critically endangered]], possibly extinct in the wild", category = "IUCN Red List critically endangered species" },
	},
	["iucn3.1"] = {
		link = "IUCN Red List",
		EX = { file = "EX", label = "[[Extinct]]", category = "IUCN Red List extinct species" },
		EW = { file = "EW", label = "[[Extinct in the wild]]", category = "IUCN Red List extinct in the wild species" },
		CR = { file = "CR", label = "[[Critically endangered species|Critically endangered]]", category = "IUCN Red List critically endangered species" },
		EN = { file = "EN", label = "[[Endangered species (IUCN status)|Endangered]]", category = "IUCN Red List endangered species" },
		VU = { file = "VU", label = "[[Vulnerable species|Vulnerable]]", category = "IUCN Red List vulnerable species" },
		NT = { file = "NT", label = "[[Near threatened]]", category = "IUCN Red List near threatened species" },
		LC = { file = "LC", label = "[[Least concern]]", category = "IUCN Red List least concern species" },
		DD = { file = "blank", label = "[[Data deficient]]", category = "IUCN Red List data deficient species" },
		NE = { label = "''Not evaluated''" },
		NR = { label = "''Not recognized''" },
		PE = { file = "CR", label = "[[Critically endangered]]", category = "IUCN Red List critically endangered species" },
		PEW = { file = "CR", label = "[[Critically endangered]]", category = "IUCN Red List critically endangered species" },
	},
	["epbc"] = {
		link = "EPBC Act",
		EX = { file = "EX", label = "[[Extinct]]", category = "EPBC Act extinct biota" },
		EW = { file = "EW", label = "[[Extinct in the wild]]", category = "EPBC Act extinct in the wild biota" },
		CR = { file = "CR", label = "[[Critically endangered]]", category = "EPBC Act critically endangered biota" },
		EN = { file = "EN", label = "[[Endangered]]", category = "EPBC Act endangered biota" },
		VU = { file = "VU", label = "[[Vulnerable species|Vulnerable]]", category = "EPBC Act vulnerable biota" },
		CD = { file = "CD", label = "[[Conservation dependent]]", category = "EPBC Act conservation dependent biota" },
		DL = { file = "DL", label = "Delisted" },
	},
}

function p.main(frame)
	local args = arguments.getArgs(frame)
	return p._main(args, frame)
end

-- Helper function to dynamically retrieve the taxon "authority"
-- and present it in paretheses
--
-- @param args the table of arguments passed into the template
-- @param taxon the taxon to check
--
-- @return nil or text to serve as the taxon name and its authority
local function authorityHelp(args, taxon)
	if args[taxon] then
		local authority = args[taxon .. "_authority"]
		return args[taxon] .. (authority and " (" .. authority .. ")" or "") -- when authority is nil no parentheses appear
	end
end

function p._main(args, frame)
	
	local warnings = {} -- warnings to display on preview
	local passing = {} -- arguments passed to Module:Infobox
	
	-- Safely replace spaces in parameters with underscores, removing the original parameter and sending a warning
	for k, _ in pairs(args) do
		if mw.ustring.find(k, " ") then
			local k1 = mw.ustring.gsub(s, " ", "_")
			if not args[k1] then
				table.insert(warnings, "deprecated parameter \"" .. k .. "\". Please use \"" .. k1 .. "\" instead.")
				args[k1] = args[k] -- copy value
				args[k] = nil -- empty
			else
				table.insert(warnings, "found \"" .. k .. "\" and \"" .. k1 .. "\". Using \"" .. k1 .. "\" instead.")
			end
		end
	end
	
	if args.name then
		passing.above = args.name
	elseif args.genus or args.species or args.binomial then
		local title = mw.title.getCurrentTitle().baseText
		local g = mw.ustring.gsub(args.genus or args.species or args.binomial, "'", "")
		if title == g or "<abbr title=\"Extinct\" aria-label=\"Extinct\" style=\"border: none; text-decoration: none; cursor: inherit; font-weight: normal; font-style: normal;\">†</abbr>" .. title == g or "†" .. title == g then
			passing.above = "''" .. g .. "''"
			-- TODO: add {{Italic title}}
		else
			passing.above = title
		end
	else
		passing.above = mw.title.getCurrentTitle().baseText
	end
	
	if args.fossil_range then
		passing.subheader = "Temporal range: " .. args.fossil_range
	end
	
	-- apply header styles
	local hex = args.color_as or args.colour_as or getColor(args)
	if hex then
		local style = "background-color: #" .. hex .. ";"
		passing.abovestyle = style
		passing.subheaderstyle = style
		passing.headerstyle = style
	end
	
	if args.image then
		passing.image = infoboxImage.InfoboxImage({args = {image = args.image, upright = args.upright or args.image_upright, alt = args.alt or args.image_alt}})
		passing.caption = args.caption or args.image_caption
	end
	if args.image2 then
		passing.image2 = infoboxImage.InfoboxImage({args = {image = args.image2, upright = args.upright2 or args.image2_upright, alt = args.alt2 or args.image2_alt}})
		passing.caption2 = args.caption2 or args.image2_caption
	end
	
	
	local i = 1
	
	-- Embed photos into the infobox via frame:expandTemplate
	-- Trying to call Module:Infobox keeps the previous state
	if args.status or args.status2 then
		local subbox = {
			child = "yes",
		}
		
		if args.status and args.status_system then
			args.status = mw.ustring.upper(args.status)
			if args.status_system == "IUCN2.3" or args.status_system == "IUCN3.1" then
				args.status_system = mw.ustring.lower(args.status_system)
			end
			
			if statusSystems[args.status_system] and statusSystems[args.status_system][args.status] then
				local x = statusSystems[args.status_system][args.status]
				subbox.image1 = infoboxImage.InfoboxImage({args = { image = "Status " .. args.status_system .. " " .. args.status .. ".svg", alt = (x.category or nil)}})
				subbox.caption1 = x.label .. " ([[" .. statusSystems[args.status_system].link .. "|" .. args.status_system .. "]])" .. (args.status_ref or "")
			end
		end
		
		if args.status2 and args.status2_system then
			args.status2 = mw.ustring.upper(args.status2)
			if args.status2_system == "IUCN2.3" or args.status2_system == "IUCN3.1" then
				args.status2_system = mw.ustring.lower(args.status2_system)
			end
			
			if statusSystems[args.status2_system] and statusSystems[args.status2_system][args.status2] then
				local x = statusSystems[args.status2_system][args.status2]
				subbox.image2 = infoboxImage.InfoboxImage({args = { image = "Status " .. args.status2_system .. " " .. args.status .. ".svg", alt = (x.category or nil)}})
				subbox.caption2 = x.label .. " ([[" .. statusSystems[args.status2_system].link .. "|" .. args.status2_system .. "]])" .. (args.status2_ref or "")
			end
		end
		
		passing["header" .. i] = "[[Conservation status]]"
		passing["data" .. i + 1] = frame:expandTemplate({title = "infobox", args = subbox})
		
		i = i + 2
	end
	
	if args.virus or args.virus_group then
		passing["header" .. i] = "[[Virus classification]]"
	elseif args.ichnos then
		passing["header" .. i] = "[[Trace fossil classification]]"
	elseif args.veterovata then
		passing["header" .. i] = "[[Egg fossil classification]]"
	else
		passing["header" .. i] = "[[Scientific classification]]"
	end
	
	i = i + 1
	
	if args.virus_group then
		local g = {
			i = "Group I ([[dsDNA]])",
			ii = "Group II ([[ssDNA]])",
			iii = "Group III ([[dsRDNA]])",
			iv = "Group IV ([[(+)ssRNA]])",
			v = "Group V ([[(-)ssRNA]])",
			vi = "Group VI ([[ssRNA-RT]])",
			["vi/vii"] = "Groups VI and VII",
			vii = "Group VII ([[dsDNA-RT]])",
		}
		
		passing["label" .. i] = "Virus group"
		passing["data" .. i] = g[args.virus_group] or args.virus_group
		i = i + 1
	end
	
	for _, t in ipairs(classification) do
		local k = t.arg_name
		local v = t.label
		if args["unranked_" .. k] then
			passing["label" .. i] = "(unranked)"
			passing["data" .. i] = authorityHelp(args, "unranked_" .. k)
			i = i + 1
		end
		if args[k] then
			passing["label" .. i] = v
			passing["data" .. i] = authorityHelp(args, k)
			i = i + 1
		end
	end
	
	if args.virus_infrasp and not args.virus_infrasp_rank then
		table.insert(warnings, "\"virus_infrasp_rank\" missing")
	elseif args.virus_infrasp then
		passing["label" .. i] = args.virus_infrasp_rank
	end
	
	
	if args.binomial then
		passing["header" .. i] = "[[Binomial name]]"
		passing["data" .. i + 1] = authorityHelp(args, "binomial")
		i = i + 2
	end
	
	
	if args.trinomial then
		local g = {
			animalia = "Trinomen",
			plantae = "Infraspecific name (botany)",
			fungi = "Infraspecific name (botany)",
			["fungus|fungi"] = "Infraspecific name (botany)",
			archaeplastida = "Infraspecific name (botany)"
		}
		passing["header" .. i] = "[[" .. (g[args.trinomial] or "Trinomial nomenclature") .. "|Trinomial name]]"
		passing["data" .. i + 1] = authorityHelp(args, "trinomial")
		i = i + 2
	end
	
	
	if args.range_map then
		passing["data" .. i] = frame:expandTemplate({title = "Infobox", args = { child = "yes", image = infoboxImage.InfoboxImage({args = {image = args.range_map, alt = args.range_map_alt, upright = args.range_map_upright}}), caption = args.range_map_caption}})
		i = i + 1
	end
	
	
	if args.range_map2 then
		passing["data" .. i] = frame:expandTemplate({title = "Infobox", args = { child = "yes", image = infoboxImage.InfoboxImage({args = {image = args.range_map2, alt = args.range_map2_alt, upright = args.range_map2_upright}}), caption = args.range_map2_caption}})
		i = i + 1
	end
	
	
	if args.range_map3 then
		passing["data" .. i] = frame:expandTemplate({title = "Infobox", args = { child = "yes", image = infoboxImage.InfoboxImage({args = {image = args.range_map3, alt = args.range_map3_alt, upright = args.range_map3_upright}}), caption = args.range_map3_caption}})
		i = i + 1
	end
	
	
	if args.range_map4 then
		passing["data" .. i] = frame:expandTemplate({title = "Infobox", args = { child = "yes", image = infoboxImage.InfoboxImage({args = {image = args.range_map4, alt = args.range_map4_alt, upright = args.range_map4_upright}}), caption = args.range_map4_caption}})
		i = i + 1
	end
	
	
	if args.type_genus then
		passing["header" .. i] = "[[Type ichnogenus]]"
		passing["data" .. i + 1] = authorityHelp(args, "type_genus")
		i = i + 2
	end
	
	
	if args.type_oogenus then
		passing["header" .. i] = "[[Type oogenus]]"
		passing["data" .. i + 1] = authorityHelp(args, "type_oogenus")
		i = i + 2
	end
	
	
	if args.type_species then
		passing["header" .. i] = "[[Type species]]"
		passing["data" .. i + 1] = authorityHelp(args, "type_species")
		i = i + 2
	end
	
	
	if args.type_oospecies then
		passing["header" .. i] = "[[Type oospecies]]"
		passing["data" .. i + 1] = authorityHelp(args, "type_oospecies")
		i = i + 2
	end
	
	
	if args.type_strain then
		passing["header" .. i] = "[[Type strain]]"
		passing["data" .. i + 1] = authorityHelp(args, "type_strain") .. (args.type_strain_ref or "")
		i = i + 2
	end
	
	
	if args.subdivision then
		mw.log(args.subdivision)
		passing["header" .. i] = args.subdivision_ranks or "Species" .. (args.subdivision_ref or "")
		passing["data" .. i + 1] = "<div style=\"text-align: left;\">\n" .. args.subdivision .. "</div>"
		i = i + 2
	end
	
	
	if args.possible_subdivision then
		passing["header" .. i] = args.possible_subdivision_ranks or "Possible species" .. (args.possible_subdividion_ref or "")
		passing["data" .. i + 1] = args.possible_subdivision
		i = i + 2
	end
	
	if args.synonyms then
		passing["header" .. i] = "[[Synonym (taxonomy)|Synonyms]]" .. ( args.synonyms_ref or "")
		passing["data" .. i + 1] = "<div style=\"text-align: left;\">\n" .. args.synonyms .. "</div>"
	end
	
	local out = infobox.infobox(passing)
	
	table.insert(warnings, "Help!")
	
	for _, warning in ipairs(warnings) do
		local w = ifPreview._warning({warning})
		if w and not w == '' then
			out = out .. w
		end
	end
	
	return out
end

return p