Difference between revisions of "Module:Autotaxobox"
(something strange going on with Firefox) |
m (1 revision imported) |
(No difference)
|
Latest revision as of 22:40, 24 October 2018
This Lua module is used on approximately 210,000 pages. To avoid large-scale disruption and unnecessary server load, any changes to it should first be tested in the module's /sandbox or /testcases subpages. The tested changes can then be added to this page in a single edit. Please consider discussing changes on the talk page before implementing them. |
This module is subject to page protection. It is a highly visible module in use by a very large number of pages, or is substituted very frequently. Because vandalism or mistakes would affect many pages, and even trivial editing might cause substantial load on the servers, it is protected from editing. |
Module:Autotaxobox (talk⧼dot-separator⧽ ⧼dot-separator⧽hist⧼dot-separator⧽links⧼dot-separator⧽doc⧼dot-separator⧽subpages⧼dot-separator⧽sandbox⧼dot-separator⧽testcases)
The purpose of this module is to provide support for automated taxobox templates (such as {{Automatic taxobox}} or {{Speciesbox}}), avoiding Mediawiki template expansion depth errors in the traversal of the taxonomic hierarchies encoded in taxonomy templates.
Currently, processing is arbitrarily limited to hierarchies containing at most 100 levels.
Contents
taxoboxColour
Given a taxon name, this function returns the correct colour of an automated taxobox for that taxon. It does so by searching up the taxonomic hierarchy for a 'real' taxon (i.e. not incertae sedis) that sets the taxobox colour, and then returning that colour. If no 'real' taxon is found, then if an incertae sedis taxon was found, the incertae sedis colour is returned, otherwise "transparent" is returned. (If the taxonomic hierarchy is too deep to process, the error colour is returned.)
Usage:
{{#invoke:Autotaxobox|taxoboxColour|taxon_name}}
Parameters:
- The unnamed parameter should be the name of a taxon for which "Template:Taxonomy/taxon_name" exists.
Examples:
- {{#invoke:Autotaxobox|taxoboxColour|Felis}} → rgb(235,235,210)
- {{#invoke:Autotaxobox|taxoboxColour|Acacia}} → rgb(180,250,180)
taxoboxList
Given a taxon name, this function returns the rows of taxa in an automated taxobox, based on the taxonomic hierarchy for the supplied taxon.
Usage:
{{#invoke:Autotaxobox|taxoboxList|taxon_name
|display_taxa = the number of taxa above taxon_name to force to be displayed
|authority = taxonomic authority for taxon_name
|parent_authority = taxonomic authority for taxon_name's parent
|gparent_authority = taxonomic authority for taxon_name's grandparent
|ggparent_authority = taxonomic authority for taxon_name's greatgrandparent
|ggparent_authority = taxonomic authority for taxon_name's greatgreatgrandparent
|bold_first = bold to embolden taxon_name in its row
}}
Parameters:
- The unnamed parameter should be the name of a taxon for which "Template:Taxonomy/taxon_name" exists. The others are explained above.
Examples:
{| class="wikitable" {{#invoke:Autotaxobox|taxoboxList|Felis|authority=Linnaeus, 1758}} |}→
Kingdom: | Animalia |
Phylum: | Chordata |
Class: | Mammalia |
Order: | Carnivora |
Suborder: | Feliformia |
Family: | Felidae |
Subfamily: | Felinae |
Genus: | Felis Linnaeus, 1758 |
taxonomyList
Given a taxon name, this function returns the rows of the taxonomy table displayed on the "Template:Taxonomy/taxon_name" page, based on the taxonomic hierarchy for the supplied taxon name.
When descending the taxonomic hierarchy, if a rank is found that is at either the same or a higher level than a rank already encountered (e.g. a family is found below a subfamily), the cell displaying the rank is given a reddish background; if it's the target taxon, the article is put into the tracking category Category:Taxonomy templates showing anomalous ranks. The numerical values defined in getRankTable()
are used to determine the correct sequence of ranks.
Usage:
{{#invoke:Autotaxobox|taxonomyList|taxon_name}}
Parameters:
- The unnamed parameter should be the name of a taxon for which "Template:Taxonomy/taxon_name" exists.
Examples:
{| class="wikitable" {{#invoke:Autotaxobox|taxonomyList|Felis}} |}→
callTaxonomyKey
This function prepares for, and then calls, {{Taxonomy key}} to display a taxonomy
template page. It does this by building up the information the template
requires, following one same_as
link if present, and then calling it.
Usage:
{{#invoke:Autotaxobox|callTaxonomyKey
|parent=
|rank=
|extinct=
|always_display=
|link_target=value of 'link' parameter in the taxonomy template
|link_text=value of unnamed parameter in the taxonomy template
|same_as=
}}
taxonInfo
Given the names of a taxon and the required item of information stored in the taxon's taxonomy template, this function returns the value of the item, following one "same as" link if available and the value would otherwise be the empty string. The function would normally be used externally via {{Taxon info}}.
Usage:
{{#invoke:Autotaxobox|taxonInfo|taxon_name|item_name}}
Parameters:
- The first unnamed parameter should be the name of a taxon for which "Template:Taxonomy/taxon_name" exists.
- The possible values of the second unnamed parameter are given at {{Taxon info/doc}}.
Examples:
- {{#invoke:Autotaxobox|taxonInfo|Felis|rank}} → genus
- {{#invoke:Autotaxobox|taxonInfo|Aves/skip|same_as}} → Aves
- {{#invoke:Autotaxobox|taxonInfo|Aves/skip|parent}} → Tetrapoda
taxonLink
Returns a wikilink to a taxon, if required including '†' before it and ' (?)' after it, and optionally italicized or bolded without a wikilink. It would normally be used via {{Taxon link}}. Some parameters can, under some circumstances, be omitted.
Usage:
{{#invoke:Autotaxobox|taxonLink
(having '/?' at the end triggers the output of ' (?)')
|taxon=
('yes' or 'true' triggers the output of '†')
|extinct=
('yes' makes the core output bold and not wikilinked)
|bold=
('yes' makes the core output italic)
|italic=
(without †, italics, etc.)
|link_target=target for the wikilink
|plain_link_text= text of the wikilink
}}
Examples:
- {{#invoke:Autotaxobox|taxonLink|taxon=Felis|italic=yes}} → Felis
- {{#invoke:Autotaxobox|taxonLink|taxon=Incertae sedis/Animalia}} → incertae sedis
- {{#invoke:Autotaxobox|taxonLink|link_target=Pterosaur|plain_link_text=Pterosauromorpha|extinct=yes}} → †Pterosauromorpha
- {{#invoke:Autotaxobox|taxonLink|taxon=Dinosauria/?|link_target=Dinosaur|plain_link_text=Dinosauria|extinct=yes}} → †Dinosauria (?)
showRankTable
Returns a sortable wikitable containing the ranks and corresponding numerical values defined in getRankTable()
and used in checking the consistency of a taxonomic hierarchy. If a taxon has a value in the rank table, it should always be lower than one higher in the taxonomic hierarchy.
Usage:
{{#invoke:Autotaxobox|showRankTable}}
Utilities
These functions are intended to be used only in analysing taxonomic hierarchies, e.g. in testing and debugging, and not for direct use in templates used in the automated taxobox system.
nth
Given a taxon name, this function returns the nth taxon above it in the taxonomic hierarchy.
Usage:
{{#invoke:Autotaxobox|nth|taxon_name|n=integer}}
Parameters:
- The unnamed parameter should be the name of a taxon for which "Template:Taxonomy/taxon_name" exists.
- n is the level whose taxon is to be found
Examples:
- {{#invoke:Autotaxobox|nth|Felis|n=1}} → Felis
- {{#invoke:Autotaxobox|nth|Felis|n=15}} → Theria
nLevels
Given a taxon name, this function returns the number of levels at and above it in the taxonomic hierarchy.
Usage:
{{#invoke:Autotaxobox|nLevels|taxon_name}}
Parameters:
- The unnamed parameter should be the name of a taxon for which "Template:Taxonomy/taxon_name" exists.
Examples:
- {{#invoke:Autotaxobox|nLevels|Felis}} → 44
- {{#invoke:Autotaxobox|nLevels|Pteranodon}} → 41
listAll
Given a taxon name, this function returns a comma-separated list of all the levels at and above it in the taxonomic hierarchy.
Usage:
{{#invoke:Autotaxobox|listAll|taxon_name}}
Parameters:
- The unnamed parameter should be the name of a taxon for which "Template:Taxonomy/taxon_name" exists.
Examples:
- {{#invoke:Autotaxobox|listAll|Plantae}} → Plantae, Eukaryota, Life
- {{#invoke:Autotaxobox|listAll|Felis}} → Felis, Felinae, Felidae, Feliformia, Carnivora, Carnivoramorpha, Ferae, Fereuungulata, Scrotifera, Laurasiatheria, Boreoeutheria, Exafroplacentalia, Placentalia, Eutheria, Theria, Tribosphenida, Zatheria, Cladotheria, Trechnotheria
, Holotheria, Mammalia, Mammaliaformes/skip, Synapsida, Amniota, Reptiliomorpha, Tetrapoda, Teleostomi, Eugnathostomata, Gnathostomata, Vertebrata, Olfactores, Chordata, Deuterostomia, Nephrozoa, Bilateria, Eumetazoa, Animalia, Filozoa, Holozoa, Opisthokonta, Obazoa, Unikonta, Eukaryota, Life
--[[ This module provides support to the automated taxobox system – the templates Automatic taxobox, Speciesbox, Subspeciesbox, Infraspeciesbox, etc. In particular it provides a way of traversing the taxonomic hierarchy encoded in taxonomy templates (templates with names of the form "Template:Taxonomy/TAXON_NAME") without causing template expansion depth errors. ]] local TaxonItalics = require('Module:TaxonItalics') -- use a function from Module:TaxonItalics to italicize a taxon name local p = {} --[[========================================================================= Limit the maximum depth of a taxonomic hierarchy that can be traversed; avoids excessive processing time and protects against incorrectly set up hierarchies, e.g. loops. =============================================================================]] local MaxSearchLevels = 100 function p.getMaxSearchLevels() return MaxSearchLevels end --[[========================== taxoboxColour ================================ Determines the correct colour for a taxobox, by searching up the taxonomic hierarchy from the supplied taxon for the first taxon (other than 'incertae sedis') that sets a taxobox colour. It is assumed that a valid taxobox colour is defined using CSS rgb() syntax. If no taxon that sets a taxobox colour is found, then 'transparent' is returned unless the taxonomic hierarchy is too deep, when the error colour is returned. Usage: {{#invoke:Autotaxobox|taxoboxColour|TAXON}} =============================================================================]] function p.taxoboxColour(frame) local currTaxon = frame.args[1] or '' local i = 1 -- count levels processed local searching = currTaxon ~= '' -- still searching for a colour? local foundICTaxon = false -- record whether 'incertae sedis' found local colour = '' -- default is no colour while searching and i <= MaxSearchLevels do local plainCurrTaxon = p.stripExtra(currTaxon) -- remove trailing text after / if string.lower(plainCurrTaxon) == 'incertae sedis' then foundICTaxon = true else local possibleColour = frame:expandTemplate{ title = 'Template:Taxobox colour', args = { plainCurrTaxon } } if string.sub(possibleColour,1,3) == 'rgb' then colour = possibleColour searching = false end end if searching then local ok, parent = p.getTaxonInfoItem(frame, currTaxon, 'parent') if ok and parent ~= '' then currTaxon = parent i = i + 1 else searching = false -- run off the top of the hierarchy or tried to use non-existent taxonomy template end end end if colour ~= '' then return colour elseif foundICTaxon then return frame:expandTemplate{ title = 'Template:Taxobox colour', args = { 'incertae sedis' } } elseif searching then -- hierarchy exceeds MaxSearchLevels levels return frame:expandTemplate{ title = 'Template:Taxobox/Error colour', args = { } } else return 'transparent' end end --[[=========================== taxoboxList ================================= Returns the rows of taxa in an automated taxobox, based on the taxonomic hierarchy for the supplied taxon. Usage: {{#invoke:Autotaxobox|taxoboxList|TAXON |display_taxa = the number of taxa *above* TAXON to force to be displayed |authority = taxonomic authority for TAXON |parent_authority = taxonomic authority for TAXON's parent |gparent_authority = taxonomic authority for TAXON's grandparent |ggparent_authority = taxonomic authority for TAXON's greatgrandparent |ggparent_authority = taxonomic authority for TAXON's greatgreatgrandparent |bold_first = 'bold' to bold TAXON in its row }} =============================================================================]] function p.taxoboxList(frame) local currTaxon = frame.args[1] or '' local displayN = (tonumber(frame.args['display_taxa']) or 1) + 1 local auth = frame.args['authority'] or '' local parentAuth = frame.args['parent_authority'] or '' local gParentAuth = frame.args['gparent_authority'] or '' local ggParentAuth = frame.args['ggparent_authority'] or '' local gggParentAuth = frame.args['gggparent_authority'] or '' local boldFirst = frame.args['bold_first'] or 'link' -- values 'link' or 'bold' local taxonTable = p.makeTable(frame, currTaxon) local res = '' -- display all taxa above possible greatgreatgrandparent for i = taxonTable.n, 6, -1 do res = res .. frame:expandTemplate{ title = 'Template:Taxobox/showtaxon', args = { taxonTable[i], fc = tostring(displayN >= i) } } end -- display greatgreatgrandparent, if it exists if taxonTable.n >= 5 then res = res .. frame:expandTemplate{ title = 'Template:Taxobox/showtaxon', args = { taxonTable[5], authority = gggParentAuth, fc = tostring(displayN >= 5) } } end -- display greatgrandparent, if it exists; force the display if an infrataxon is below if taxonTable.n >= 4 then local force = tostring(displayN >= 4) or frame.expandTemplate{ title = 'Template:Infrataxon()', args = { taxonTable[3] } } == 'true' or frame.expandTemplate{ title = 'Template:Infrataxon()', args = { taxonTable[2] } } == 'true' res = res .. frame:expandTemplate{ title = 'Template:Taxobox/showtaxon', args = { taxonTable[4], authority = ggParentAuth, fc = tostring(force) } } end -- display grandparent, if it exists; force the display if an infrataxon is below if taxonTable.n >= 3 then local force = tostring(displayN >= 3) or frame.expandTemplate{ title = 'Template:Infrataxon()', args = { taxonTable[2] } } == 'true' res = res .. frame:expandTemplate{ title = 'Template:Taxobox/showtaxon', args = { taxonTable[3], authority = gParentAuth, fc = tostring(force) } } end -- display parent, if it exists if taxonTable.n >= 2 then res = res .. frame:expandTemplate{ title = 'Template:Taxobox/showtaxon', args = { taxonTable[2], authority = parentAuth, fc = tostring(displayN >= 2) } } end -- display target taxon res = res .. frame:expandTemplate{ title = 'Template:Taxobox/showtaxon', args = { taxonTable[1], authority = auth, fc = 'true', format = boldFirst } } return res end --[[========================== taxonomyList ================================= Returns the cells of the taxonomy table displayed on the right hand side of "Template:Taxonomy...." pages. Usage: {{#invoke:Autotaxobox|taxonomyList|TAXON}} =============================================================================]] function p.taxonomyList(frame) local currTaxon = frame.args[1] or '' if currTaxon == '' then return '| ||ERROR: no taxon supplied\n|-' end local taxonTable = p.makeTable(frame, currTaxon) local rankTable = p.getRankTable() local lastRankVal = 1000000 local orderOk local res = '' for i = taxonTable.n, 1, -1 do -- check ranks are in right order in the hierarchy local ok, rank = p.getTaxonInfoItem(frame, taxonTable[i], 'rank') local currRankVal = rankTable[string.lower(rank)] if currRankVal then orderOk = currRankVal < lastRankVal if orderOk then lastRankVal = currRankVal end else orderOk = true end -- now return a row of the taxonomy table with anomalous ranks marked local errorStr = '' if not orderOk then errorStr = 'true' end res = res .. frame:expandTemplate{ title = 'Template:Taxonomy links', args = { taxonTable[i], error = errorStr } } end -- if the last row has an anomalous rank, put the page in the error-tracking category; category statements don't work -- inside tables, so need to close the current table first and then open a dummy one (close is in Template:Taxonomy key) if not orderOk then res = res .. '\n|}\n[[Category:Taxonomy templates showing anomalous ranks]]\n{|\n' end return res end --[[========================= callTaxonomyKey =============================== Prepares for, and then calls, Template:Taxonomy key to display a taxonomy template page. It does this by building up the information the template requires, following one 'same as' link, if required. Usage: {{#invoke:Autotaxobox|callTaxonomyKey |parent= |rank= |extinct= |always_display= |link_target=value of 'link' parameter in taxonomy template |link_text=value of parameter 2 in taxonomy template |same_as= }} =============================================================================]] local SAME_AS = 7 local PARENT = 1 local RANK = 2 local LINK_TARGET = 3 local LINK_TEXT = 4 local ALWAYS_DISPLAY = 5 local EXTINCT = 6 local REFS = 8 function p.callTaxonomyKey(frame) local parent = frame.args['parent'] or '' local rank = frame.args['rank'] or '' local extinct = string.lower(frame.args['extinct']) or '' local alwaysDisplay = string.lower(frame.args['always_display']) or '' local linkTarget = frame.args['link_target'] or '' local linkText = frame.args['link_text'] or '' -- this is the "raw" link text, and can be '' local refs = frame.args['refs'] or '' local sameAsTaxon = frame.args['same_as'] or '' if sameAsTaxon ~= '' then -- try using the 'same as' taxon; it's an error if it doesn't exist local ok, sameAsInfoStr = pcall(frame.expandTemplate, frame, { title = 'Template:Taxonomy/' .. sameAsTaxon, args = {['machine code'] = 'all' } }) if ok then local sameAsInfo = mw.text.split(sameAsInfoStr, '$', true) --'same as' taxon's taxonomy template must not have a 'same as' link if sameAsInfo[SAME_AS] == '' then if parent == '' then parent = sameAsInfo[PARENT] end if rank == '' then rank = sameAsInfo[RANK] end if extinct == '' then extinct = string.lower(sameAsInfo[EXTINCT]) end if alwaysDisplay == '' then alwaysDisplay = string.lower(sameAsInfo[ALWAYS_DISPLAY]) end if linkTarget == '' then linkTarget = sameAsInfo[LINK_TARGET] end if linkText == '' then linkText = sameAsInfo[LINK_TEXT] end if refs == '' and parent == sameAsInfo[PARENT] then refs = sameAsInfo[REFS] end else return '<span style="color:red; font-size:1.1em">Error: attempt to follow two "same as" links</span>: <code>same_as = ' .. sameAsTaxon .. '</code>, but [[Template:Taxonomy/' .. sameAsTaxon .. ']] also has a<code>same_as</code> parameter.' end else return frame:expandTemplate{ title = 'Template:Taxonomy key/missing template', args = {taxon=sameAsTaxon, msg='given as the value of <code>same as</code>'} } end end local link = linkTarget if linkText ~= '' and linkText ~= linkTarget then link = link .. "|" .. linkText end return frame:expandTemplate{ title = 'Template:Taxonomy key', args = {parent=parent, rank=rank, extinct=extinct, always_display=alwaysDisplay, link_target=linkTarget, link=link, refs=refs, same_as=sameAsTaxon} } end --[[============================ taxonInfo ================================== Extracts and returns information from Template:Taxonomy/TAXON, following one 'same as' link if required. Usage: {{#invoke:Autotaxobox|taxonInfo|TAXON|ITEM}} ITEM is one of: 'parent', 'rank', 'link target', 'link text', 'link', 'extinct', 'always display', 'refs', 'same as' or 'all'. If ITEM is not specified, the default is 'all' – all values in a single string separated by '$'. =============================================================================]] function p.taxonInfo(frame) local taxon = frame.args[1] or '' local item = frame.args[2] or '' if item == '' then item = 'all' end local ok, info = p.getTaxonInfoItem(frame, taxon, item) return info end --[[============================ taxonLink ================================== Returns a wikilink to a taxon, if required including '†' before it and ' (?)' after it, and optionally italicized or bolded without a wikilink. Usage: {{#invoke:Autotaxobox|taxonLink |taxon= : having '/?' at the end triggers the output of ' (?)' |extinct= : 'yes' or 'true' trigger the output of '†' |bold= : 'yes' makes the core output bold and not wikilinked |italic= : 'yes' makes the core output italic |link_target= : target for the wikilink link_text= : text of the wikilink (may be same as link_target), without †, italics, etc. }} =============================================================================]] function p.taxonLink(frame) local taxon = frame.args['taxon'] or '' local extinct = string.lower(frame.args['extinct'] or '') local bold = frame.args['bold'] or '' local italic = frame.args['italic'] or '' local linkTarget = frame.args['link_target'] or '' local linkText = frame.args['link_text'] or frame.args['plain_link_text'] or '' --temporarily allow alternative args -- if link text is missing, try to find a replacement if linkText == '' then if string.find(taxon, 'Incertae sedis', 1, true) then linkText = "''incertae sedis''" linkTarget = 'Incertae sedis' else linkText = p.stripExtra(taxon) end end if linkTarget == '' then linkTarget = linkText end if italic == 'yes' then linkText = TaxonItalics.italicizeTaxonName(linkText, false) end local link = '' if bold == 'yes' then link = '<b>' .. linkText .. '</b>' else if linkTarget == linkText then link = linkText else link = linkTarget .. '|' .. linkText end link = '[[' .. link .. ']]' end if (extinct == 'yes' or extinct == 'true') and not string.find(link, '†', 1, true) then link = '<span style="font-style:normal;font-weight:normal;">†</span>' .. link end if string.sub(taxon, -2) == '/?' and not string.find(link, '?', 1, true) then link = link .. '<span style="font-style:normal;font-weight:normal;"> (?)</span>' end return link end --[[========================== showRankTable ================================ Returns a wikitable showing the ranks and their values as set up by getRankTable(). Usage: {{#invoke:Autotaxobox|showRankTable}} =============================================================================]] function p.showRankTable(frame) local rankTable = p.getRankTable() local res = '{| class="wikitable sortable"\n|+ Ranks checked in taxonomy templates\n! Rank !! Shown as !! Value\n' for k, v in pairs(rankTable) do local rankShown = frame:expandTemplate{ title = 'Template:Anglicise rank', args = { k } } res = res .. '|-\n|' .. k .. '||' .. rankShown .. '||' .. v .. '\n' end return res .. '|}\n' end --[[============================== find ===================================== Returns the taxon above the specified taxon with a given rank. Usage: {{#invoke:Autotaxobox|find|TAXON|RANK}} =============================================================================]] function p.find(frame) local currTaxon = frame.args[1] or '' if currTaxon == '' then return '<span class="error">no taxon supplied</span>' end local rank = frame.args[2] or '' if rank == '' then return '<span class="error">no rank supplied</span>' end local inHierarchy = true -- still in the taxonomic hierarchy or off the top? local searching = true -- still searching while inHierarchy and searching do local ok, parent = p.getTaxonInfoItem(frame, currTaxon, 'parent') if ok and parent ~= '' then currTaxon = parent local ok, currRank = p.getTaxonInfoItem(frame, currTaxon, 'rank') if currRank == rank then searching = false end else inHierarchy = false end end if inHierarchy and not searching then return currTaxon else return '<span class="error">rank not found</span>' end end --[[=============================== nth ===================================== External utility function primarily intended for use in checking and debugging. Returns the nth level above a taxon in a taxonomic hierarchy, where the taxon itself is counted as the first level. Usage: {{#invoke:Autotaxobox|nth|TAXON|n=N}} =============================================================================]] function p.nth(frame) local currTaxon = frame.args[1] or '' if currTaxon == '' then return 'ERROR: no taxon supplied' end local n = tonumber(frame.args['n'] or 1) if n > MaxSearchLevels then return 'Exceeded maximum number of levels allowed (' .. MaxSearchLevels .. ')' end local i = 1 local inHierarchy = true -- still in the taxonomic hierarchy or off the top? while i < n and inHierarchy do local ok, parent = p.getTaxonInfoItem(frame, currTaxon, 'parent') if ok and parent ~= '' then currTaxon = parent i = i + 1 else inHierarchy = false end end if inHierarchy then return currTaxon else return 'Level ' .. n .. ' is past the top of the taxonomic hierarchy' end end --[[============================= nLevels =================================== External utility function primarily intended for use in checking and debugging. Returns number of levels in a taxonomic hierarchy, starting from the supplied taxon as level 1. Usage: {{#invoke:Autotaxobox|nLevels|TAXON}} =============================================================================]] function p.nLevels(frame) local currTaxon = frame.args[1] or '' if currTaxon == '' then return 'ERROR: no taxon supplied' end local i = 1 local inHierarchy = true -- still in the taxonomic hierarchy or off the top? while inHierarchy and i < MaxSearchLevels do local ok, parent = p.getTaxonInfoItem(frame, currTaxon, 'parent') if ok and parent ~= '' then currTaxon = parent i = i + 1 else inHierarchy = false end end if inHierarchy then return MaxSearchLevels .. '+' else return i end end --[[============================= listAll =================================== External utility function primarily intended for use in checking and debugging. Returns a comma separated list of a taxonomic hierarchy, starting from the supplied taxon. Usage: {{#invoke:Autotaxobox|listAll|TAXON}} =============================================================================]] function p.listAll(frame) local currTaxon = frame.args[1] or '' if currTaxon == '' then return 'ERROR: no taxon supplied' end return p.listTaxa(p.makeTable(frame, currTaxon)) end --[[========================================================================= Internal functions =============================================================================]] --[[= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = Internal utility function to strip off any extra parts of a taxon name, i.e. anything after a '/'. Thus "Felidae/?" would be reduced to "Felidae". = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =]] function p.stripExtra(taxonName) local i = string.find(taxonName,'/') if i then return string.sub(taxonName,1,i-1) else return taxonName end end --[[= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = Internal utility function to convert a taxon table to a comma-separated list. = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =]] function p.listTaxa(taxonTable) local lst = taxonTable[1] for i = 2, taxonTable.n, 1 do lst = lst .. ', ' .. taxonTable[i] end return lst end --[[= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = Internal utility function to extract an item of information from a taxonomy template, following one 'same as' link if required. = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =]] function p.getTaxonInfoItem(frame, taxon, item) -- item == 'link' is a special case if item == 'link' then return p.getTaxonInfoLink(frame, taxon) end local ok, info -- item == 'dagger' is another special case if item == 'dagger' then ok, info = p.getTaxonInfoItem(frame, taxon, 'extinct') if ok then if info == 'yes' or info == 'true' then info = '†' else info = '' end end -- item ~= 'link' or 'dagger' else ok, info = pcall(frame.expandTemplate, frame, { title = 'Template:Taxonomy/' .. taxon, args = {['machine code'] = item } }) if ok then if info == '' then -- try 'same as' local sameAsTaxon = frame:expandTemplate{ title = 'Template:Taxonomy/' .. taxon, args = {['machine code'] = 'same as' } } if sameAsTaxon ~= '' then ok, info = pcall(frame.expandTemplate, frame, { title = 'Template:Taxonomy/' .. sameAsTaxon, args = {['machine code'] = item } }) end end end end if ok then -- if item is 'link_text' check whether '(?)' needs to be added if item == 'link_text' and string.sub(taxon, -2) == '/?' and not string.find(info, '?', 1, true) then info = info .. '<span style="font-style:normal;font-weight:normal;"> (?)</span>' end else info = '[[Template:Taxonomy/' .. taxon .. ']]' --error indicator in code before conversion to Lua end return ok, info end function p.getTaxonInfoLink(frame, taxon) local ok, linkText, linkTarget local link = '' ok, linkText = p.getTaxonInfoItem(frame, taxon, 'link_text') if ok then ok, linkTarget = p.getTaxonInfoItem(frame, taxon, 'link_target') if ok then if linkText == linkTarget then link = linkText else link = linkTarget .. '|' .. linkText end end end return ok, link end --[[= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = Internal utility function to return a table (array) constructed from a taxonomic hierarchy stored in "Template:Taxonomy/..." templates. TABLE.n holds the total number of taxa; TABLE[1]..TABLE[TABLE.n] the taxon names. = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =]] function p.makeTable(frame, currTaxon) local i = 1 local inHierarchy = true -- still in the taxonomic hierarchy or off the top? local taxonTable = {} taxonTable[1] = currTaxon; while i < MaxSearchLevels and inHierarchy do local ok, parent = p.getTaxonInfoItem(frame, currTaxon, 'parent') if ok and parent ~= '' then currTaxon = parent i = i + 1 taxonTable[i] = currTaxon else inHierarchy = false -- run off the top of the hierarchy or tried to use non-existent taxonomy template end end taxonTable.n = i return taxonTable end --[[= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = Internal utility function to set up a table of numerical values corresponding to 'Linnaean' ranks, with upper ranks having higher values. In a valid taxonomic hierarchy, a lower rank should never have a higher value than a higher rank. The actual numerical values are arbitrary so long as they are ordered. The ranks should correspond to those in Template:Anglicise ranks. = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =]] function p.getRankTable() return { classis = 1400, cohort = 1100, divisio = 1500, domain = 1700, familia = 800, forma = 100, genus = 600, grandordo = 1005, ['grandordo-mb'] = 1002, infraclassis = 1397, infralegio = 1197, infraordo = 997, infraphylum = 1497, infraregnum = 1597, infratribus = 697, legio = 1200, magnordo = 1006, microphylum = 1495, micrordo = 995, mirordo = 1004, ['mirordo-mb'] = 1001, nanophylum = 1494, nanordo = 994, ordo = 1000, parafamilia = 800, parvordo = 996, phylum = 1500, regnum = 1600, sectio = 500, --series = 400, used too inconsistently to check species = 300, subclassis = 1398, subcohort = 1098, subdivisio = 1498, subfamilia = 798, subgenus = 598, sublegio = 1198, subordo = 998, subphylum = 1498, subregnum = 1598, subsectio = 498, subspecies = 298, subtribus = 698, superclassis = 1403, supercohort = 1103, superdivisio = 1503, superdomain = 1703, superfamilia = 803, superlegio = 1203, superordo = 1003, superphylum = 1503, superregnum = 1603, supertribus = 703, tribus = 700, varietas = 200, zoodivisio = 1300, zoosectio = 900, zoosubdivisio = 1298, zoosubsectio = 898, } end return p