Module:Taxonavigation
Jump to navigation
Jump to search
Lua
CodeDiscussionEditHistoryLinksLink count Subpages:DocumentationTestsResultsSandboxLive code All modules
- Usage
- This module is used to display Navigation bar for taxa (called taxonavigation) by {{Taxonavigation}}, {{TaxonavigationIncluded}} and {{TaxonavigationIncluded2}}
- Functions and their usage
-
- taxonavigation() is called by {{Taxonavigation}}, {{TaxonavigationIncluded}} and {{TaxonavigationIncluded2}}
- findCurrentPageTaxonRank() is called by {{Taxonavigation}} and {{TaxonavigationIncluded2}}
- serializeCurrentParameters() is called by {{Taxonavigation}}
- How to improve and test this module
-
- develop your modification in Module:Taxonavigation/sandbox, the sandbox of this module
which is used in the sandbox templates {{Taxonavigation/sandbox}} - verify your changes in Module_talk:Taxonavigation/sandbox/testcases
- if needed improve the testcases Module:Taxonavigation/sandbox/testcases
- ask an administrator to report your modifications in Module:Taxonavigation
- verify again your changes in Module_talk:Taxonavigation/testcases
- if needed improve the testcases Module:Taxonavigation/testcases
- develop your modification in Module:Taxonavigation/sandbox, the sandbox of this module
- See also
Code
-- require('strict')
local getArgs = require('Module:Arguments').getArgs
-- The default language object of pagenames on the local wiki (not the current user language), for lc, uc, ucfirst.
local lang = mw.language.getContentLanguage()
local _common = require('Module:Biology')
----------------------------------------------------------------------------------------------------
---------- Exists utilities ------------------------------------------------------------------------
----------------------------------------------------------------------------------------------------
local function articleExists(articleName)
local page = mw.title.new(articleName, nil )
if page then
-- _common.addDebug('articleExists(“' .. articleName .. '”)', tostring(page.exists))
return page.exists
else
return false
end
end
local function categoryExists(categoryName)
if not string.startsWith(lang:lc(categoryName), 'category:') then
categoryName = 'Category:' .. categoryName
end
local category = mw.title.new(categoryName, nil)
if category then
-- _common.addDebug('categoryExists(“' .. categoryName .. '”)', tostring(category.exists))
return category.exists
else
return false
end
end
----------------------------------------------------------------------------------------------------
---------- Rank utilities --------------------------------------------------------------------------
----------------------------------------------------------------------------------------------------
local _singularLatinRanksNeedingItalic = {
cladus = false,
subtaxon = false,
['???'] = false,
['(unranked)'] = false,
['⇒'] = false,
supergroup = false,
group = false,
['informal group'] = false,
empire = false,
kingdom = false,
superdomain = false,
domain = false,
subdomain = false,
realm = false,
subrealm = false,
superregnum = false,
regnum = false,
subregnum = false,
infraregnum = false,
superdivisio = false,
divisio = false,
subdivisio = false,
infradivisio = false,
superphylum = false,
phylum = false,
subphylum = false,
infraphylum = false,
superclassis = false,
classis = false,
subclassis = false,
parvclassis = false,
infraclassis = false,
megacohors = false,
supercohors = false,
cohors = false,
subcohors = false,
infracohors = false,
superordo = false,
ordo = false,
subordo = false,
parvordo = false,
infraordo = false,
microordo = false,
superfamilia = false,
familia = false,
subfamilia = false,
supertribus = false,
tribus = false,
subtribus = false,
infratribus = false,
['genus group'] = true,
genus = true,
nothogenus = true,
subgenus = true,
--[====[
Here we manage botanic section (between species/series and genus)
and zoology section (between family and ordo).
--]====]
supersectio = true,
sectio = true,
subsectio = true,
series = true,
subseries = true,
species = true,
hybrid = true,
nothospecies = true,
subspecies = true,
nothosubspecies = true,
varietas = true,
cultivar = true,
forma = true,
subforma = true,
}
--[====[
true means must contain a space.
false means must not contain a space.
nil means it depends.
--]====]
local _singularLatinRanksNeedingMultiWordTaxonName = {
-- cladus = false,
-- subtaxon = false,
-- ['???'] = false,
-- ['(unranked)'] = false,
-- ['⇒'] = false,
-- supergroup = false,
-- group = false,
-- ['informal group'] = false,
-- empire = false,
-- kingdom = false,
-- superdomain = false,
-- domain = false,
-- subdomain = false,
superregnum = false,
regnum = false,
subregnum = false,
infraregnum = false,
superdivisio = false,
divisio = false,
subdivisio = false,
infradivisio = false,
superphylum = false,
phylum = false,
subphylum = false,
infraphylum = false,
superclassis = false,
classis = false,
subclassis = false,
parvclassis = false,
infraclassis = false,
megacohors = false,
supercohors = false,
cohors = false,
subcohors = false,
infracohors = false,
superordo = false,
ordo = false,
subordo = false,
parvordo = false,
infraordo = false,
microordo = false,
suprafamilia = false,
superfamilia = false,
familia = false,
subfamilia = false,
supertribus = false,
tribus = false,
subtribus = false,
infratribus = false,
['genus group'] = true, -- 'Campiglossa group'
genus = false,
nothogenus = true, -- 'x Rhododendron'
subgenus = true, -- 'Rhododendron subg. Hymenanthes' or 'Rhododendron (Hymenanthes)'
--[====[
Here we manage botanic section (between species/series and genus) and zoology section (between family and ordo).
--]====]
-- supersectio = false,
-- sectio = false, -- I don't know 'Rhododendron sect. Pontica'
-- subsectio = false, -- I don't know 'Rhododendron subsect. Taliensia'
-- series = false, -- I don't know 'Liatris ser. Scariosae'
-- subseries = false, -- I don't know 'Liatris ser. Scariosae'
species = true,
hybrid = true, -- 'Rhododendron x Hymenanthes'
nothospecies = true, -- 'Rhododendron x Hymenanthes'
subspecies = true,
nothosubspecies = true,
varietas = true,
cultivar = true,
forma = true,
subforma = true,
}
local _singularLatinRanksThatCanHaveX = {
nothogenus = true, -- 'x Rhododendron'
nothospecies = true, -- 'Rhododendron x Hymenanthes'
nothosubspecies = true,
varietas = true,
cultivar = true,
}
--[====[
Must be similar to 'c:Template:CheckSingularLatinRank'.
--]====]
function doesSingularLatinRankExist(singularLatinRank)
local singularLatinRankLC = lang:lc(singularLatinRank)
local needItalic = _singularLatinRanksNeedingItalic[singularLatinRankLC]
return not (needItalic == nil)
end
--[====[
Must be similar to 'c:Template:RankNeedsItalic'.
--]====]
function rankNeedsItalic(singularLatinRank)
local singularLatinRankLC = lang:lc(singularLatinRank)
local needItalic = _singularLatinRanksNeedingItalic[singularLatinRankLC]
if needItalic == nil then
_common.addDebug('rankNeedsItalic(“' .. singularLatinRankLC .. '”)', '“' .. tostring(needItalic) .. '”')
return true
else
return needItalic
end
end
--[====[
Will be used to get parameter 'categorizeTribesIn'.
--]====]
local _pluralEnglishRankUPFBySingularLatinRankLC = {
species = 'Species',
genus = 'Genera',
subtribus = 'Subtribes',
tribus = 'Tribes',
subfamilia = 'Subfamilies',
familia = 'Families',
superfamilia = 'Superfamilies',
subordo = 'Suborders',
ordo = 'Orders',
}
--[====[
Will be used to create 'Lauraceae by subtribe'.
--]====]
local _singularEnglishRankLCBySingularLatinRankLC = {
species = 'species',
genus = 'genus',
subtribus = 'subtribe',
tribus = 'tribe',
subfamilia = 'subfamily',
familia = 'family',
superfamilia = 'superfamily',
infraordo = 'infraorder',
subordo = 'suborder',
ordo = 'order',
}
--[====[
Returns '', if everything in 'taxonName' looks coherent to its rank.
Returns an error + category otherwise.
--]====]
function checkTaxonNameForARank(singularLatinRank, taxonName)
local singularLatinRankLC = lang:lc(singularLatinRank)
-- Check 1: some ranks require taxonName with space, others require taxonName without space.
local needsMultiWordTaxonName = _singularLatinRanksNeedingMultiWordTaxonName[singularLatinRankLC]
if needsMultiWordTaxonName == nil then
-- No way to determine if the taxon name needs a space.
else
if string.find(taxonName, 'Virus', 1, true) -- like ?
or string.find(taxonName, 'virus', 1, true) -- like 'Coxsackievirus'
or string.find(taxonName, '-', 1, true) -- like 'HIV-1'
then
-- Viruses have their own classification usage => no check can be done.
else
local containsSpace = string.find(taxonName, ' ', 1, true)
if containsSpace and not needsMultiWordTaxonName then
-- More complex because there are disambiguation like 'genus (familia)'.
local taxonNameLC = lang:lc(taxonName)
if string.find(taxonNameLC,' (', 1, true) -- Disambiguation like 'genus (familia)' => no check can be done.
or string.find(taxonNameLC, 'incertae sedis', 1, true) -- IncertaeSedis like 'Euheterodonta incertae sedis' => no check can be done.
or string.find(taxonNameLC, 'unassigned', 1, true) -- IncertaeSedis like 'Unassigned Cyprinidae' => no check can be done Unassigned.
or string.find(taxonNameLC, 'unplaced', 1, true) -- IncertaeSedis like 'Elapidae unplaced' => no check can be done Unassigned.
or string.find(taxonNameLC, 'bacter', 1, true) -- Bacteria like 'Gamma Proteobacteria' or 'Candidatus Liberibacter' have strange naming => no check can be done.
or string.find(taxonNameLC, 'fossil', 1, true) -- Fossils like 'Diadectes fossils' or 'Fossil Diadectes' => no check can be done.
then
-- Some taxonName cannot be checked.
else
return _common.incorrectBiologyTemplateUsage('Taxonavigation', 'Incorrect “' .. singularLatinRankLC .. '” with space.', 'Taxonavigation')
end
elseif needsMultiWordTaxonName and not containsSpace then
return _common.incorrectBiologyTemplateUsage('Taxonavigation', 'Incorrect “' .. singularLatinRankLC .. '” without space.', 'Taxonavigation')
end
end
end
-- Check 2: taxonName should not contain “ X ” or “ x ”, nor start by “X ” or “x ”.
if string.startsWith(taxonName, 'X ')
or string.find(taxonName,' X ', 1, true) then
return _common.incorrectBiologyTemplateUsage('Taxonavigation', 'Incorrect taxonName “' .. taxonName .. '” (and category name) containing “ X ” instead of “ × ”.', 'Taxonavigation')
elseif string.startsWith(taxonName, 'x ')
or string.find(taxonName,' x ', 1, true) then
return _common.incorrectBiologyTemplateUsage('Taxonavigation', 'Incorrect taxonName “' .. taxonName .. '” (and category name) containing “ x ” instead of “ × ”.', 'Taxonavigation')
end
local xpos = mw.ustring.find(taxonName, '×', 1, true)
if xpos then
-- Check 2bis: taxonName should not contain “×” not followed by space.
_common.addDebug('checkTaxonNameForARank', 'string.len(taxonName)=' .. tostring(mw.ustring.len(taxonName)) .. ', xpos=' .. tostring(xpos))
if mw.ustring.len(taxonName) == xpos then
return _common.incorrectBiologyTemplateUsage('Taxonavigation', 'Incorrect taxonName “' .. taxonName .. '” ending with “×”.', 'Taxonavigation')
end
local nextCar = mw.ustring.sub(taxonName, xpos + 1, xpos + 1)
_common.addDebug('checkTaxonNameForARank', 'nextCar=“' .. tostring(nextCar) .. '”')
if nextCar ~= ' ' then
return _common.incorrectBiologyTemplateUsage('Taxonavigation', 'Incorrect taxonName “' .. taxonName .. '” containing “×” not followed by space.', 'Taxonavigation')
end
-- Check 3: taxonName containing “×” should be “nothoXXX”.
local canHaveX = _singularLatinRanksThatCanHaveX[singularLatinRankLC]
if not canHaveX then
return _common.incorrectBiologyTemplateUsage('Taxonavigation', 'Incorrect rank “' .. singularLatinRankLC .. '” for a taxon containing “×” (maybe it is a “notho' .. singularLatinRankLC .. '”).', 'Taxonavigation')
end
end
return ''
end
--[====[
Calculates a category/gallery's title out of the taxonavigation parameters.
We need to find the category/article's taxonName in the taxonavigation parameters
to ensure that its associated rank requires italic.
--]====]
function calcItalicTitle(taxonName)
-- Is it a category/article with disambiguation?
local taxonNameSecondPart = ''
if string.endsWith(taxonName,')') then
-- “Bombus (disamb)” but also subgenera like “Bombus (Psithyrus)” but NOT species like “genus (subgenus) species”.
local parenthesisStart = string.find(taxonName,' (', 1, true)
if parenthesisStart then
taxonNameSecondPart = ' <small>' .. string.sub(taxonName,parenthesisStart + 1) .. '</small>'
taxonName = string.sub(taxonName, 1, parenthesisStart - 1)
end
end
local namespace = mw.title.getCurrentTitle().nsText
if not string.isNilOrEmpty(namespace) then
namespace = namespace .. ':' -- Like “Category:”.
end
return namespace .. "''" .. taxonName .. "''" .. taxonNameSecondPart
end
--[====[
Returns:
- ' • Genus<b>: <i>[[:Category:Cinnamomum|Cinnamomum]]</i></b>'
out of:
- rank='Genus',
- taxonName='Cinnamomum'.
The returned string is to be added to a Taxonavigation.
--]====]
function addRankAndTaxonName(frame, namespace, pagename, firstTaxon, singularLatinRank, taxonName)
-- Separator 1.
local taxonavigationStr = not firstTaxon and ' • ' or ''
-- Check singularLatinRank.
if not doesSingularLatinRankExist(singularLatinRank) then
taxonavigationStr = taxonavigationStr .. _common.incorrectBiologyTemplateUsage('Taxonavigation', 'Incorrect rank “' .. singularLatinRank .. '”.', 'Taxonavigation')
end
-- Detect extinct sign: |Eohiodon†| or |†Eohiodon| (must be before calc of currentTaxonNameIsPagename).
local rankNeedsItalic = rankNeedsItalic(singularLatinRank)
local extinctCross = ''
if string.find(taxonName,'†',1,true) then
if rankNeedsItalic then
extinctCross = "</i>†<i>"
else
extinctCross = '†'
end
taxonName = string.gsub(taxonName, '†', '', 5)
taxonName = mw.text.trim(taxonName)
end
-- Add rank + open bold.
local currentTaxonNameIsPagename = (lang:ucfirst(taxonName) == lang:ucfirst(pagename))
singularLatinRank = lang:ucfirst(singularLatinRank)
if currentTaxonNameIsPagename then
if not string.isNilOrEmpty(extinctCross) then
-- we need to change the cross because it must be more visible
if rankNeedsItalic then
extinctCross = "</i><big>†</big><i>"
else
extinctCross = '<big>†</big>'
end
end
taxonavigationStr = taxonavigationStr .. '<b>' .. singularLatinRank .. ': '
else
taxonavigationStr = taxonavigationStr .. singularLatinRank .. '<b>: '
end
-- Open italic.
local openItalicIfNeeded = ''
local closeItalicIfNeeded = ''
if rankNeedsItalic then
openItalicIfNeeded = '<i>'
closeItalicIfNeeded = '</i>'
end
taxonavigationStr = taxonavigationStr .. openItalicIfNeeded
-- Check that taxonName knowing its ranks.
taxonavigationStr = taxonavigationStr .. checkTaxonNameForARank(singularLatinRank, taxonName)
-- Add taxonName.
local taxonNameToDisplay = nil
if taxonName == 'Incertae Sedis'
or taxonName == 'Incertae sedis'
or taxonName == 'incertae sedis'
or taxonName == '?' then
taxonNameToDisplay = "''Incertae sedis''"
else
-- Disambiguation: '|Ibicella (Martyniaceae)|'.
local taxonDisplayName = taxonName
if string.endsWith(taxonName, ')') then
-- "Bombus (disamb)" but also subgenera like "Bombus (Psithyrus)" but NOT species like "genus (subgenus) species"
local parenthesisStart = string.find(taxonName,' (', 1, true)
if parenthesisStart then
taxonDisplayName = string.sub(taxonName, 1, parenthesisStart - 1) ..
'<small style="font-style:normal"> ' ..
string.sub(taxonName, parenthesisStart + 1) ..
'</small>'
end
end
taxonDisplayName = string.gsub(taxonDisplayName, ' ', ' ')
taxonDisplayName = string.gsub(taxonDisplayName, '<small style="font%-style:normal;?">', '<small style="font-style:normal">')
if namespace == 0 then
-- article/gallery
if (not currentTaxonNameIsPagename) and articleExists(taxonName) then
-- Higher taxon => link to existing articles
taxonNameToDisplay = '[[' .. taxonName ..'|<span style="color:#005896">' .. taxonDisplayName ..'</span>]]'
end
elseif namespace == mw.site.namespaces.Category.id then
-- category
if currentTaxonNameIsPagename and articleExists(taxonName) then
-- article's taxon => link to existing article
taxonNameToDisplay = '[[' .. taxonName ..'|<span style="color:#005896">' .. taxonDisplayName ..'</span>]]'
end
end
if not taxonNameToDisplay then
-- general case
taxonNameToDisplay = '[[:Category:' .. taxonName ..'|' .. taxonDisplayName ..']]'
end
end
taxonavigationStr = taxonavigationStr .. extinctCross .. taxonNameToDisplay
-- Close italic.
taxonavigationStr = taxonavigationStr .. closeItalicIfNeeded
-- Close bold.
taxonavigationStr = taxonavigationStr .. '</b>'
-- Change title.
if currentTaxonNameIsPagename and rankNeedsItalic then
local title = calcItalicTitle(taxonName)
if title then
_common.addDebug('addRankAndTaxonName', 'displaytitle=“' .. title .. '”')
taxonavigationStr = taxonavigationStr .. ' ' .. frame:preprocess('{{DISPLAYTITLE:' .. title .. '}}') .. ' '
end
end
return taxonavigationStr
end
--[====[
Returns:
- '[[Category:Lauraceae by subtribe|Cinnamomum]]', or
- '[[Category:Subtribes of Lauraceae|Cinnamomum]]',
out of:
- categorizeIn='Lauraceae',
- currentPageTaxonSingularEnglishRankLC='subtribe',
- currentPageTaxonPluralEnglishRankUPF='Subtribes',
- pagename='Cinnamomum',
in: 'Category:Cinnamomum'.
The returned string is to be added to a Taxonavigation.
It uses these parameters:
- categorizeIn: like 'Lauraceae' or 'FAMILIA';
- currentPageTaxonSingularEnglishRankLC: the lowercase singular English rank of the taxon described by the Taxonavigation
(among 'species', 'genus', 'subtribe', 'tribe', 'subfamily', 'family');
- currentPageTaxonPluralEnglishRankUPF: the uppercase-first plural English rank of the taxon described by the Taxonavigation
(among 'Species', 'Genera', 'Subtribes', 'Tribes', 'Subfamilies', 'Families').
--]====]
function calcCategory(options, categorizeIn, pagename, currentPageTaxonSingularEnglishRankLC, currentPageTaxonPluralEnglishRankUPF)
local categorizeInLC = lang:lc(categorizeIn)
local cleverCategorization = doesSingularLatinRankExist(categorizeInLC)
if cleverCategorization then
-- categorizeIn like 'FAMILIA', so we need to find the family
local parametersStr = options.parameters
if not parametersStr then
_common.addDebug('calcCategory', 'Failed to find rank “' .. categorizeInLC .. '” (unspecified parameters)')
return nil
end
local parameters = mw.text.jsonDecode(parametersStr)
if not parameters then
_common.addDebug('calcCategory', 'Failed to find rank “' .. categorizeInLC .. '” (non-JSON parameters)')
return nil
end
local realCategorizeIn = parameters[categorizeInLC]
if string.isNilOrEmpty(realCategorizeIn) then
_common.addDebug('calcCategory', 'Failed to find rank “' .. categorizeInLC .. '” (in ' .. tostring(table.getn(parameters)) .. ' JSON parameters)')
return nil
end
realCategorizeIn = string.gsub(realCategorizeIn, '†', '', 5)
realCategorizeIn = mw.text.trim(realCategorizeIn)
-- categorizeIn='FAMILIA' => we replace it with the family name => categorizeIn='Lauraceae'.
_common.addDebug('calcCategory', 'Modified categorizeIn=“' .. tostring(realCategorizeIn) .. '”')
categorizeIn = realCategorizeIn
end
-- Step1: try fullCategory like 'Lauraceae by subtribe' or 'Plantae by family'.
local fullCategory = categorizeIn .. ' by ' .. currentPageTaxonSingularEnglishRankLC
if categoryExists(fullCategory) then
_common.addDebug('calcCategory', 'fullCategory(first case)=“' .. fullCategory ..'”')
else
_common.addDebug('calcCategory', 'fullCategory(first case)=“' .. fullCategory .. '” does not exists')
-- Step2: try fullCategory like 'Subtribes of Lauraceae'.
fullCategory = currentPageTaxonPluralEnglishRankUPF .. ' of ' .. categorizeIn
if cleverCategorization and not categoryExists(fullCategory) then
_common.addDebug('calcCategory', 'fullCategory(second case+clever)=“' .. fullCategory .. '” does not exists')
return nil
else
_common.addDebug('calcCategory', 'fullCategory(second case)=“' .. fullCategory .. '”')
end
end
return '[[Category:' .. fullCategory .. '|' .. pagename .. ']]'
end
--[====[
Returns:
- '[[Category:Lauraceae by subtribe|Cinnamomum]]', or
- '[[Category:Subtribes of Lauraceae|Cinnamomum]]',
out of:
- currentPageTaxonSingularLatinRankLC='subtribus',
- pagename='Cinnamomum',
in: 'Category:Cinnamomum'.
The returned string is to be added to a Taxonavigation.
It uses these parameters:
- currentPageTaxonSingularLatinRankLC: the singular lowercase Latin rank of the taxon described by the Taxonavigation (species, genus ...).
--]====]
function calcCategories(options, pagename, currentPageTaxonSingularLatinRankLC)
if string.startsWith(currentPageTaxonSingularLatinRankLC, 'notho') then
-- nothogenus, nothospecies, nothosubspecies should be categorizes like genus, species, subspecies
currentPageTaxonSingularLatinRankLC = string.sub(currentPageTaxonSingularLatinRankLC, string.len('notho')+1)
_common.addDebug('calcCategories', 'currentPageTaxonSingularLatinRankLC=“' .. tostring(currentPageTaxonSingularLatinRankLC) .. '” was a notho')
end
local currentPageTaxonPluralEnglishRankUPF = _pluralEnglishRankUPFBySingularLatinRankLC[currentPageTaxonSingularLatinRankLC]
if not currentPageTaxonPluralEnglishRankUPF then
_common.addDebug('calcCategories', 'currentPageTaxonSingularLatinRankLC=“' .. tostring(currentPageTaxonSingularLatinRankLC) .. '” seems incorrect')
return nil
end
local currentPageTaxonSingularEnglishRankLC = _singularEnglishRankLCBySingularLatinRankLC[currentPageTaxonSingularLatinRankLC]
if not currentPageTaxonSingularEnglishRankLC then
_common.addDebug('calcCategories', 'currentPageTaxonSingularLatinRankLC=“' .. tostring(currentPageTaxonSingularLatinRankLC) .. '” seems incorrect')
return nil
end
local optionBase = 'categorize' .. currentPageTaxonPluralEnglishRankUPF .. 'In'
local categories = ''
for optionIndex = 1, 5 do
local optionName = optionBase
if (optionIndex > 1) then
optionName = optionBase .. tostring(optionIndex)
end
local categorizeIn = options[optionName]
_common.addDebug('calcCategories', 'optionName=“' .. tostring(optionName) .. '”, categorizeIn=“' .. tostring(categorizeIn) .. '”')
if not categorizeIn then
-- categorizeSubtribesInX does not exists => stop iteration on X
_common.addDebug('calcCategories', 'categories=“' .. categories .. '”')
return categories -- Returns less than 5 categories
end
local newCategory = calcCategory(options, categorizeIn, pagename, currentPageTaxonSingularEnglishRankLC, currentPageTaxonPluralEnglishRankUPF)
if newCategory then
categories = categories .. newCategory
else
-- categorizeSubtribesInX led to nothing, let us try categorizeSubtribesInX + 1
end
end
_common.addDebug('calcCategories', 'categories=“' .. categories .. '”')
return categories -- Returns 5 categories
end
--[====[
Returns a string containing a category for include templates like Template:Angiospermes and 'Template:Lauraceae (APG)'.
You can test the result of this function in Template:Angiosperms/sandbox and 'Template:Lauraceae (APG)/sandbox'.
--]====]
function calcIncludeTemplateCategory(options, namespace, pagename)
local categorizeTemplate = options.categorizeTemplate
if categorizeTemplate == 'no' then
return ''
end
local categoryName = 'Templates to include in Taxonavigation' -- for templates without include using TaxonavigationIncluded
local includeOption = options.include
if not string.isNilOrEmpty(includeOption) then
includeOption = string.gsub(includeOption, '/sandbox', '', 1) -- for include=Angiosperms/sandbox
categoryName = includeOption .. ' Templates to include in Taxonavigation' -- for templates with include using TaxonavigationIncluded2
end
local errorCategory = ''
if not categoryExists(categoryName) then
errorCategory = _common.incorrectBiologyTemplateUsage('Taxonavigation', 'Category “' .. categoryName .. '” does not exist.', 'Taxonavigation')
end
return '[[Category:' .. categoryName .. ']]' .. errorCategory
end
--[====[
Returns a string containing a documentation for include templates like Template:Angiospermes and 'Template:Lauraceae (APG)'.
You can test the result of this function in Template:Angiosperms/sandbox and 'Template:Lauraceae (APG)/sandbox'.
--]====]
function calcIncludeTemplateDocumentation(options, namespace, pagename)
if options.documentTemplate == 'no' then
return ''
end
local classificationLine = ''
local documentTemplateWithClassification = options.documentTemplateWithClassification
if string.isNilOrEmpty(documentTemplateWithClassification) then
local classification = options['classification']
if string.isNilOrEmpty(classification) then
-- Classification has not been provided by 'Template:Angiospermes' to 'Template:TaxonavigationIncluded'.
-- => Ask the user to call '{{Taxonavigation|include=CurrentTemplate|' with 'classification='.
-- _common.addDebug('calcIncludeTemplateDocumentation', '(case1) documentTemplateWithClassification and classification are empty => display IOC.')
classificationLine = '<dd><kbd>|classification = </kbd>?<!-- Please specify. --></dd>'
else
-- Classification has been provided by 'Template:Lauraceae (APG)' to 'Template:TaxonavigationIncluded2'.
-- => Don't tell the user to call '{{Taxonavigation|include=CurrentTemplate|' with 'classification='.
-- _common.addDebug('calcIncludeTemplateDocumentation', '(case2) documentTemplateWithClassification is empty AND classification has been provided => do not document classification.')
end
elseif documentTemplateWithClassification == 'none' then
-- _common.addDebug('calcIncludeTemplateDocumentation', '(case3) documentTemplateWithClassification=“none”.')
else
-- _common.addDebug('calcIncludeTemplateDocumentation', '(case4) documentTemplateWithClassification displayed.')
classificationLine = '<dd><kbd>|classification = ' .. tostring(documentTemplateWithClassification) .. '</kbd></dd>'
end
local taxonavigationAutoCategory = nil
local space = string.find(pagename, ' ', 1, true)
if space then
local taxonName = string.sub(pagename, 1, space - 1)
taxonavigationAutoCategory = '{{TaxonavigationAutoCategory|' .. taxonName .. '|includename=' .. pagename .. '}}'
else
taxonavigationAutoCategory = '{{TaxonavigationAutoCategory|' .. pagename .. '}}'
end
local doc = [=[
<dl>
<dt>Usage</dt>
<dd>This template should be used in categories and articles as [[:Template:Taxonavigation|{{Taxonavigation}}]]'s parameter include=</dd>
<dd>For that reason, those kind of templates are called 'taxonavigation include templates' or simply 'include templates'.</dd>
<dd>There are such templates for:
<table style="text-align:left">
<tr>
<td><ul><li>[[:Category:Templates to include in Taxonavigation|all classes]]</li></ul></td>
</tr>
<tr>
<td><ul><li>[[:Category:Insecta Templates to include in Taxonavigation|all insect orders]]</li></ul></td>
<td>WARNING: they are named '''[[Template:Orthoptera|<orderName>]]''' except for '''[[Template:Coleoptera (include)|Coleoptera (include)]]''' and '''[[Template:Lepidoptera (include)|Lepidoptera (include)]]'''</td>
</tr>
<tr>
<td><ul><li>[[:Category:Angiosperms Templates to include in Taxonavigation|all angiospermes families]]</li></ul></td>
<td>WARNING: as these families template follow [[APGIII]], they are named '''[[Template:Cactaceae (APG)|<familyName> (APG)]]''' and contain classification=APGIII</td>
</tr>
<tr>
<td><ul><li>[[:Category:Pinopsida Templates to include in Taxonavigation|all conifer families]]</li></ul></td>
</tr>
<tr>
<td><ul><li>[[:Category:Pteridophyta Templates to include in Taxonavigation|all fern families]]</li></ul></td>
<td>WARNING: as these families template follow [[Smith System]], they are named '''[[Template:Schizaeaceae (Smith)|<familyName> (Smith)]]''' and contain classification=Smith</td>
</tr>
<tr>
<td><ul><li>[[:Category:Aves Templates to include in Taxonavigation|all bird families]]</li></ul></td>
<td>WARNING: as these families template follow [[Template:Taxonavigation/IOC_Classification|IOC classification]], they are named '''[[Template:Diomedeidae (IOC)|<familyName> (IOC)]]''' and contain classification=IOC</td>
</tr>
</table>
</dd>
<dt>Example</dt>
<dd><kbd>{{Taxonavigation</kbd></dd>
<dd><kbd>|include = ]=] .. pagename .. [=[</kbd></dd>
]=] .. classificationLine .. [=[
<dd>...</dd>
<dd><kbd>|authority = Linnaeus, 1758</kbd></dd>
<dd><kbd>}}</kbd></dd>
<dt>Automatic categories</dt>]=]
local needsParameterRanks = false
local needsParameterParameters = false
local categoriesOptionFound = false
-- First iteration: we display non-clever categories, second iteration: we display clever categories.
for clever = 0,1 do
for singularLatinRankLC, pluralEnglishRankUPF in pairs(_pluralEnglishRankUPFBySingularLatinRankLC) do
local optionBase = 'categorize' .. pluralEnglishRankUPF .. 'In'
local singularEnglishRankLC = _singularEnglishRankLCBySingularLatinRankLC[singularLatinRankLC]
for optionIndex = 1, 5 do
local optionName = optionBase
if optionIndex > 1 then
optionName = optionBase .. tostring(optionIndex)
end
local categorizeIn = options[optionName]
_common.addDebug('calcIncludeTemplateDocumentation', optionName .. '=“' .. tostring(categorizeIn) .. "”")
if not categorizeIn then
break
end
categoriesOptionFound = true
local cat1 = categorizeIn .. ' by ' .. singularEnglishRankLC
local cat2 = pluralEnglishRankUPF .. ' of ' .. categorizeIn
local cleverCategorization = doesSingularLatinRankExist(categorizeIn)
if not cleverCategorization and clever == 0 then
cat1 = cat1 .. '|' .. cat1
cat2 = cat2 .. '|' .. cat2
doc = doc .. [=[
<dd>As you provided parameter ]=] .. optionName .. ', [[:Category:' .. cat1 .. ']] or [[:Category:' .. cat2 .. ']] will be automatically added to ' ..
string.lower(pluralEnglishRankUPF) .. ' using this template.</dd>'
needsParameterRanks = true
elseif cleverCategorization and (clever == 1) then
-- categorizeIn like 'FAMILIA', so we need to find the family
cat1 = cat1 .. '|<' .. categorizeIn .. '> by ' .. singularEnglishRankLC
cat2 = cat2 .. '|' .. pluralEnglishRankUPF .. ' of <' .. categorizeIn .. '>'
doc = doc .. [=[
<dd>As you provided parameter ]=] .. optionName .. ', [[:Category:' .. cat1 .. ']] or [[:Category:' .. cat2 .. ']] will be automatically added to ' ..
string.lower(pluralEnglishRankUPF) .. ' using this template.</dd>' .. [=[
<dl>
<dd>This automatic category should only contain <b>{{TaxonavigationAutoCategory|<]=] .. categorizeIn .. '>|includename=' .. pagename .. '}}</b></dd>' .. [=[
</dl>]=]
needsParameterRanks = true
needsParameterParameters = true
end
end
end
if clever == 0 and categoriesOptionFound then
doc = doc .. '<dd><dl><dd>These automatic category should only contain <b>' .. taxonavigationAutoCategory .. '</b></dd></dl></dd>'
end
end
if categoriesOptionFound then
local wikicode = mw.title.getCurrentTitle():getContent()
local parameter = 'rank={{{rank|}}}'
if needsParameterRanks and not string.find(wikicode, parameter, 1, true) then
doc = doc .. _common.incorrectBiologyTemplateUsage('Taxonavigation', 'Please add “' .. parameter .. '”.', 'Taxonavigation')
end
parameter = 'parameters={{{parameters|}}}'
if needsParameterParameters and not string.find(wikicode, parameter, 1, true) then
doc = doc .. _common.incorrectBiologyTemplateUsage('Taxonavigation', 'Please add “' .. parameter .. '”.', 'Taxonavigation')
end
else
doc = doc .. [=[
<dd>You should provide the following parameters to have automatic categories added to species and genera:
<table role="presentation" border="0" cellspacing="0" cellpadding="0">
<tr><td><kbd>|rank={{{rank|}}}</kbd><td></tr>
<tr><td><kbd>|categorizeSpeciesIn=</kbd><i>parentName</i></td><td><!-- Only if <i>parent</i> contains multiple genera --></td></tr>
<tr><td><kbd>|categorizeGeneraIn=</kbd><i>parentName</i></td><td><!-- Only if <i>parent</i> contains subfamilies or tribes --></td></tr>
<tr><td><kbd>|categorizeSubtribesIn=</kbd><i>parentName</i></td><td><!-- Only if <i>parent</i> contains tribes AND subtribes --></td></tr>
<tr><td><kbd>|categorizeTribesIn=</kbd><i>parentName</i></td><td><!-- Only if <i>parent</i> contains subfamilies AND tribes --></td></tr>
<tr><td><kbd>|categorizeSubfamiliesIn=</kbd><i>parentName</i></td><td><!-- Only if <i>parent</i> contains clades containing subfamilies --></td></tr>
<tr><td><kbd>|categorizeFamiliesIn=</kbd><i>parentName</i></td><td><!-- Only if <i>parent</i> contains multiple families --></td></tr>
</table>
</dd>]=]
end
doc = doc ..[=[
<dt>See also</dt>
<dd>
<ul>
<li>[[Template:Taxonavigation|{{Taxonavigation}}]] to use in categories and articles</li>
<li>[[Template:TaxonavigationIncluded|{{TaxonavigationIncluded}}]] to use in include templates</li>
<li>[[Template:TaxonavigationIncluded2|{{TaxonavigationIncluded2}}]] to use in include templates that themself use include=</li>
<li>[[Template:TaxonavigationAutoCategory|{{TaxonavigationAutoCategory}}]] to use in automatic categories</li>
<li>[[Module:Taxonavigation]] that displays this documentation and adds categories</li>
</ul>
</dd>
</dl>]=]
return doc
end
local _templatesThatShouldNotBeAutoDocumented = {
Taxonavigation = true,
Coleoptera = true,
['Coleoptera/sandbox'] = true,
Coleoptera2 = true,
Lepidoptera = true,
Lepidoptera2 = true,
}
--[====[
Returns a string containing documentation and categories for include templates like 'Template:Angiospermes' and 'Template:Lauraceae (APG)'.
You can test the result of this function in 'Template:Angiosperms/sandbox' and 'Template:Lauraceae (APG)/sandbox'.
--]====]
function calcIncludeTemplateDocumentationAndCategory(options, namespace, pagename)
if namespace ~= mw.site.namespaces.Template.id then
return ''
end
if _templatesThatShouldNotBeAutoDocumented[pagename]
or string.startsWith(pagename, 'Taxonavigation/')
or string.startsWith(pagename, 'TaxonavigationIncluded')
or string.startsWith(pagename, 'Biohist')
then
--[=[
'Template:Taxonavigation', 'Template:Coleoptera*', 'Template:Lepidoptera*' have no need for documentation nor categories.
'Template:Taxonavigation/testcases', 'Template:Taxonavigation/sandbox/testcases' have no need for documentation nor categories.
'Template:TaxonavigationIncluded', ..., 'Template:TaxonavigationIncluded2/sandbox' have their own documentation that add their own categories.
'Template:Biohist' and 'Template:Biohist/sandbox' have no need for documentation nor categories.
--]=]
return ''
end
return calcIncludeTemplateDocumentation(options, namespace, pagename) ..
calcIncludeTemplateCategory(options, namespace, pagename)
end
--[====[
Returns a string that Template:Taxonavigation will display.
It uses parameters:
* indexed parameters containing Cladus,magnoliids,Ordo,Laurales,Familia,Lauraceae,Genus,Cinnamomum...
* namespaceForDebug
* pagenameForDebug
* rank (when called by TaxanavigationIncluded or TaxanavigationIncluded2)
* categorizeSpeciesIn2, categorizeSubtribesIn (when called by TaxanavigationIncluded)
--]====]
function taxonavigation(frame, options)
local taxonavigationStr = ''
local firstTaxon = string.isNilOrEmpty(options['include']) -- include=XXX => taxonHaveAlreadyBeenDisplayed=true.
local currentTitle = mw.title.getCurrentTitle()
local namespace = currentTitle.namespace
local pagename = currentTitle.text
-- prepare NonRegression
local namespaceForDebug = options['namespaceForDebug']
local pagenameForDebug = options['pagenameForDebug']
if not string.isNilOrEmpty(namespaceForDebug) then
namespace = tonumber(namespaceForDebug,10)
end
if not string.isNilOrEmpty(pagenameForDebug) then
pagename = pagenameForDebug
end
local isGalleryOrCategory = (namespace == 0) or (namespace == mw.site.namespaces.Category.id)
_common.addDebug('taxonavigation', [=[
----------------------------------------------------------
caller=“]=] .. tostring(options['caller']) .. '”'
-- .. ', namespaceForDebug=“' .. tostring(namespaceForDebug) .. '”'
-- .. ', pagenameForDebug=“' .. tostring(pagenameForDebug) .. '”'
-- .. ', namespace=“' .. tostring(namespace) .. '”'
-- .. ', pagename=“' .. tostring(pagename) .. '”'
-- .. ', isGalleryOrCategory=“' .. tostring(isGalleryOrCategory) .. '”'
-- .. ', serializeCurrentParameters=“' ..serializeCurrentParameters(options) .. '”'
.. ', options[parameters]=“' .. tostring(options['parameters']) .. '”'
-- .. ', options[1]=“' .. tostring(options['1']) .. '”'
-- .. ', options[2]=“' .. tostring(options['2']) .. '”.'
)
for paramIndex = 1, 1602, 2 do
local singularLatinRank = options[tostring(paramIndex)]
local taxonName = options[tostring(paramIndex+1)]
if string.isNilOrEmpty(taxonName) then
if string.isNilOrEmpty(singularLatinRank) then
-- _common.addDebug('taxonavigation', 'Stopped at index ' .. tostring(paramIndex) .. ', singularLatinRank=“' .. tostring(singularLatinRank).. '”, taxonName=“' .. tostring(taxonName) .. '”.')
else
taxonavigationStr = taxonavigationStr .. _common.incorrectBiologyTemplateUsage('Taxonavigation', 'Strange parameter “' .. singularLatinRank .. '”.', 'Taxonavigation')
end
break
end
singularLatinRank = mw.text.trim(singularLatinRank)
taxonName = mw.text.trim(taxonName) -- Don't suppress “†”, it will be done by addRankAndTaxonName()
if taxonName == 'NOTTOBEDISPLAYED'
or taxonName == 'EMPTY' and singularLatinRank == 'EMPTY' then
-- 'Template:Coleoptera' and 'Template:Lepidoptera' have strange empty lines.
else
taxonavigationStr = taxonavigationStr .. addRankAndTaxonName(frame, namespace, pagename, firstTaxon, singularLatinRank, taxonName)
firstTaxon = false
end
end
if isGalleryOrCategory then
local currentPageTaxonSingularLatinRank = options['rank'] -- rank of the taxon described by the Taxonavigation
_common.addDebug('taxonavigation', 'currentPageTaxonSingularLatinRank=“' ..tostring(currentPageTaxonSingularLatinRank) .. '” (available in include templates only).')
if not string.isNilOrEmpty(currentPageTaxonSingularLatinRank) then
-- Called by Template:TaxonavigationIncluded
local categories = calcCategories(options, pagename, lang:lc(currentPageTaxonSingularLatinRank))
if categories then
taxonavigationStr = taxonavigationStr .. categories
end
end
end
local mustBeEmpty = options.mustBeEmpty
if not string.isNilOrEmpty(mustBeEmpty) then
taxonavigationStr = taxonavigationStr .. _common.incorrectBiologyTemplateUsage('Taxonavigation', 'Parameter “mustBeEmpty” is not empty.', 'Taxonavigation')
end
return taxonavigationStr .. calcIncludeTemplateDocumentationAndCategory(options, currentTitle.namespace, currentTitle.text)
end
--[====[
Finds current page taxon singularLatinRank from Taxonavigation parameters. For example,
it returns: 'Genus' out of {{Taxonavigation|...|Genus|Cinnamomum|..}} in 'Category:Cinnamomum'.
--]====]
function findCurrentPageTaxonSingularLatinRank(options)
local currentTitle = mw.title.getCurrentTitle()
local pagename = currentTitle.text
-- Prepare non-regression.
local pagenameForDebug = options.pagenameForDebug
if not string.isNilOrEmpty(pagenameForDebug) then
pagename = pagenameForDebug
end
for paramIndex = 1, 1602, 2 do
local singularLatinRank = options[tostring(paramIndex)]
local taxonName = options[tostring(paramIndex + 1)]
if string.isNilOrEmpty(singularLatinRank) or string.isNilOrEmpty(taxonName) then
break
end
singularLatinRank = mw.text.trim(singularLatinRank)
taxonName = mw.text.trim(string.gsub(taxonName, '†', '', 5))
if taxonName == 'NOTTOBEDISPLAYED'
or taxonName == 'EMPTY' and singularLatinRank == 'EMPTY' then
-- 'Template:Coleoptera' and 'Template:Lepidoptera' have strange empty lines.
elseif lang:ucfirst(taxonName) == lang:ucfirst(pagename) then
return lang:ucfirst(singularLatinRank)
end
end
return ''
end
--[====[
Serializes rank and taxon parameters from Taxonavigation. For example,
it returns: '{"species":"Cinnamomum camphora","CurrentPageTaxonRank":"Familia","genus":"Cinnamomum"}',
out of: {{Taxonavigation|...|Genus|Cinnamomum|Species|Cinnamomum camphora|..}} in 'Category:Cinnamomum'.
--]====]
function serializeCurrentParameters(options)
local currentTitle = mw.title.getCurrentTitle()
local pagename = currentTitle.text
-- Prepare non-regression.
local pagenameForDebug = options.pagenameForDebug
if not string.isNilOrEmpty(pagenameForDebug) then
pagename = pagenameForDebug
end
-- Parameters is the table to be returned serialized with JSON.
local parameters = {}
-- Provide caller for debug.
local caller = options.caller
if not string.isNilOrEmpty(caller) then
parameters.caller = caller
end
for paramIndex = 1, 1602, 2 do
local singularLatinRank = options[tostring(paramIndex)]
local taxonName = options[tostring(paramIndex + 1)]
if string.isNilOrEmpty(singularLatinRank) or string.isNilOrEmpty(taxonName) then
break
end
singularLatinRank = mw.text.trim(singularLatinRank)
taxonName = mw.text.trim(string.gsub(taxonName, '†', '', 5))
if taxonName == 'NOTTOBEDISPLAYED'
or taxonName == 'EMPTY' and singularLatinRank == 'EMPTY' then
-- 'Template:Coleoptera' and 'Template:Lepidoptera' have strange empty lines.
else
parameters[lang:lc(singularLatinRank)] = taxonName -- can contains extinct sign
if lang:ucfirst(taxonName) == lang:ucfirst(pagename) then
parameters.CurrentPageTaxonRank = lang:ucfirst(singularLatinRank)
end
end
end
return mw.text.jsonEncode(parameters)
end
local _acceptedNamedParameters = {
authority = true,
include = true,
documentTemplate = true,
documentTemplateWithClassification = true,
categorizeTemplate = true,
classification = true,
parameters = true,
namespaceForDebug = true,
pagenameForDebug = true,
caller = true,
rank = true,
mustBeEmpty = true,
-- + categorizeFamiliesInX,
}
--[====[
Detects that incorrect parameters have been passed to {{Taxonavigation}}.
--]====]
function detectTaxonavigationBadParameters(options)
local authority = options['authority']
if authority and string.find(authority, '†', 1, true) then
return _common.incorrectBiologyTemplateUsage('Taxonavigation', 'Please transfer “†” from “authority” to Taxonavigation last taxon.', 'Taxonavigation')
end
for index, lang in pairs(options) do
if type(index) == 'string' then
if _acceptedNamedParameters[index] then -- Normal argument pair: include='Angiosperms', authority='L.'.
-- _common.addDebug('detectTaxonavigationBadParameters', 'parameter “' .. index .. '” is in _acceptedNamedParameters.')
elseif string.startsWith(index, 'categorize') then -- Normal argument pair: categorizeFamiliesIn='FAMILIA'.
-- _common.addDebug('detectTaxonavigationBadParameters', 'parameter “' .. index .. '” starts with “categorize”.')
else -- Bad argument pair: Authority='BadOrtho', Familia='Saturniidae'.
-- _common.addDebug('detectTaxonavigationBadParameters', 'parameter “' .. index .. '” seems bad.')
-- return _common.incorrectBiologyTemplateUsage('Taxonavigation', 'Incorrect parameter [' .. index .. '].', 'Taxonavigation')
end
else -- Normal argument pair: 1='Familia', 2='Saturniidae'.
-- _common.addDebug('detectTaxonavigationBadParameters', 'parameter[' .. tostring(index) .. '] is not a string.')
end
end
return ''
end
----------------------------------------------------------------------------------------------------
---------- PUBLIC FUNCTIONS ------------------------------------------------------------------------
----------------------------------------------------------------------------------------------------
local p = {}
-- public version of taxonavigation
-- Used by {{Taxonavigation}}, {{TaxonavigationIncluded}} and {{TaxonavigationIncluded2}}
function p.taxonavigation(frame)
local args = getArgs(frame)
local taxonavigationStr = taxonavigation(frame, args)
-- _common.addDebug('p.taxonavigation', detectTaxonavigationBadParameters(args)
return taxonavigationStr .. _common.getDebug('<BR/>') .. detectTaxonavigationBadParameters(args)
end
--[====[
Public version of findCurrentPageTaxonRank.
Used by {{Taxonavigation}} and {{TaxonavigationIncluded2}}.
--]====]
function p.findCurrentPageTaxonRank(frame)
local args = getArgs(frame)
return findCurrentPageTaxonSingularLatinRank(args)
end
--[====[
Public version of serializeCurrentParameters.
Used by {{Taxonavigation}}.
--]====]
function p.serializeCurrentParameters(frame)
local args = getArgs(frame)
return serializeCurrentParameters(args)
end
----------------------------------------------------------------------------------------------------
---------- Testcase public functions (return string) -----------------------------------------------
----------------------------------------------------------------------------------------------------
function p.testcase_stringTrim(frame)
local args = frame.args
return mw.text.trim(tostring(args['1']))
end
function p.testcase_doesSingularLatinRankExist(frame)
local args = frame.args
local singularLatinRank = args['1']
if string.isNilOrEmpty(singularLatinRank) then
return false
end
return tostring(doesSingularLatinRankExist(singularLatinRank))
end
function p.testcase_rankNeedsItalic(frame)
local args = frame.args
local singularLatinRank = args['1']
if string.isNilOrEmpty(singularLatinRank) then
return true
else
return tostring(rankNeedsItalic(singularLatinRank))
end
end
function p.testcase_articleExists(frame)
local args = frame.args
local article = args['1']
if string.isNilOrEmpty(article) then
return false
else
return tostring(articleExists(article))
end
end
function p.testcase_categoryExists(frame)
local args = frame.args
local category = args['1']
if string.isNilOrEmpty(category) then
return false
else
return tostring(categoryExists(category))
end
end
function p.testcase_calcItalicTitle(frame)
local args = frame.args
return mw.text.nowiki(calcItalicTitle(args['1']))
end
return p