Module:Taxonavigation/sandbox
Lua
CodeDiscussionEditHistoryLinksLink count Subpages:DocumentationTestsResultsSandboxLive code All modules
Module:Taxonavigation (talk · edit · hist · links · doc · subpages · tests / results · sandbox · all modules)
- Usage
- This module is used by {{Taxonavigation/sandbox}} which are the sandbox template (to test new developments) of {{Taxonavigation}}
- The final module is Module: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 and Template:Taxonavigation/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
Code
local _common=require('Module:Biology/sandbox')
-- Get a language object for formatDate and ucfirst.
local lang = mw.language.getContentLanguage()
----------------------------------------------------------------------------------------------------
---------- Exists utilities ------------------------------------------------------------------------
----------------------------------------------------------------------------------------------------
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
function categoryExists(categoryName)
local categoryNameLC = lang:lc(categoryName)
if not string.startsWith(categoryNameLC, '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,
supergroup=false,
group=false,
['informal group']=false,
['⇒']=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,
--suprafamilia=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,
--supergroup=false,
--group=false,
--['informal group']=false,
--['⇒']=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 https://commons.wikimedia.org/wiki/Template:CheckSingularLatinRank
function doesSingularLatinRankExist(singularLatinRank)
local singularLatinRankLC = lang:lc(singularLatinRank)
local needItalic = _singularLatinRanksNeedingItalic[singularLatinRankLC]
return not (needItalic == nil)
end
-- Must be similar to https://commons.wikimedia.org/wiki/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 is 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
local strangeTaxonName = 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'
if strangeTaxonName 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)
strangeTaxonName = string.find(taxonName,' (',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
if strangeTaxonName 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 ' nor ' x ' but ' × '
if string.find(taxonName,' X ',1,true) or string.startsWith(taxonName, 'X ') then
return _common.incorrectBiologyTemplateUsage('Taxonavigation', "Incorrect taxonName '" .. taxonName .. "' (and category name) containing X instead of ×", 'Taxonavigation')
elseif string.find(taxonName,' x ',1,true) or string.startsWith(taxonName, 'x ') 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)))
_common.addDebug('checkTaxonNameForARank','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
-- paramaters 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 rank=Genus, taxonName=Cinnamomum
-- The returned string is to be added to a Taxonavigation
function addRankAndTaxonName(frame, namespace, pagename, firstTaxon, singularLatinRank, taxonName)
local taxonavigationStr = ''
-- Separator 1
if not firstTaxon then
taxonavigationStr = ' • '
else
taxonHaveAlreadyBeenDisplayed = true
end
-- Check singularLatinRank
if not doesSingularLatinRankExist(singularLatinRank) then
taxonavigationStr = taxonavigationStr .. _common.incorrectBiologyTemplateUsage('Taxonavigation', 'Incorrect rank:', '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','title: ' .. 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 parameters:
-- * categorizeIn like 'Lauraceae' or 'FAMILIA'
-- * currentPageTaxonSingularEnglishRankLC is the singular english rank lowercase of the taxon described by the Taxonavigation (among 'species', 'genus', 'subtribe', 'tribe', 'subfamily', 'family')
-- * currentPageTaxonPluralEnglishRankUPF is the plural english rank uppercase first 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 .. ' in non present parameters')
return nil
end
local parameters = mw.text.jsonDecode(parametersStr)
if not parameters then
_common.addDebug('calcCategory','Failed to find rank ' .. categorizeInLC .. ' in 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)) .. ' 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','categorizeIn(modified)=' .. tostring(realCategorizeIn))
categorizeIn = realCategorizeIn
end
-- Step1: try fullCategory like 'Lauraceae by subtribe' or 'Plantae by family'
local fullCategory = categorizeIn .. ' by ' .. currentPageTaxonSingularEnglishRankLC
_common.addDebug('calcCategory','fullCategory(first case)=' .. fullCategory)
if not categoryExists(fullCategory) then
_common.addDebug('calcCategory','fullCategory(first case) "' .. fullCategory .. '" does not exists')
-- Step2: try fullCategory like 'Subtribes of Lauraceae'
fullCategory = currentPageTaxonPluralEnglishRankUPF .. ' of ' .. categorizeIn
_common.addDebug('calcCategory','fullCategory(second case)=' .. fullCategory)
if cleverCategorization and not categoryExists(fullCategory) then
_common.addDebug('calcCategory','fullCategory(second case+clever) "' .. fullCategory .. '" does not exists')
return nil
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 parameters:
-- * currentPageTaxonSingularLatinRankLC is the singular latin rank lowercase 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))
_common.addDebug('calcCategories','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)
local documentTemplate = options['documentTemplate']
if documentTemplate == 'no' then
return ''
end
local classificationLine = ''
local documentTemplateWithClassification = options['documentTemplateWithClassification']
if documentTemplateWithClassification == 'none' then
_common.addDebug('displayIncludeDocumentation','documentTemplateWithClassification(case1): documentTemplateWithClassification=none')
else
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
-- => need to ask the user to call {{Taxonavigation|include=CurrentTemplate| with classification=
classificationLine = '<dd>classification=?|</dd>'
_common.addDebug('displayIncludeDocumentation','documentTemplateWithClassification(case2): documentTemplateWithClassification and classification are empty => display IOC')
else
-- classification= has been provided by 'Template:Lauraceae (APG)' to Template:TaxonavigationIncluded2
-- => no need to ask the user to call {{Taxonavigation|include=CurrentTemplate| with classification=
_common.addDebug('displayIncludeDocumentation','documentTemplateWithClassification(case3): documentTemplateWithClassification is empty AND classification has been provided => do not document classification')
end
else
classificationLine = '<dd>classification=' .. documentTemplateWithClassification .. '|</dd>'
_common.addDebug('displayIncludeDocumentation','documentTemplateWithClassification(case4): display ' .. tostring(documentTemplateWithClassification))
end
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 = [=[<br/>
<br/>
<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>
</dl>
<br/>
<dl>
<dt>Example</dt>
<dd>{{Taxonavigation|<br /></dd>
<dd><b>include=]=] .. pagename .. [=[</b>|<br /></dd>]=]
.. classificationLine ..
[=[<dd>...<br /></dd>
<dd>authority=Linnaeus, 1758}}<br /></dd>
</dl>
<br/>
<dl>
<dt>Automatic categories</dt>]=]
local needsParameterRanks = false
local needsParameterParameters = false
local categoriesOptionFound = false
for clever = 0,1 do
-- First iteration: we display non clever categories, second iteration: we display clever categories
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('displayIncludeDocumentation',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>'
doc = doc ..
'<dd><dl><dd>This automatic category should only contain <b>{{TaxonavigationAutoCategory|<' .. categorizeIn .. '>|includename=' .. pagename .. '}}</b></dd></dl></dd>'
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 could provide following parameters to have automatic categories added to species and genera:
<dl>
<dd><table style="text-align:left">
<tr>
<td><b>rank={{{rank|}}}|</b></td>
</tr>
<tr>
<td><b>categorizeSpeciesIn=<i>parentName</i>|</b></td>
<td><-- Only if <i>parent</i> contains multiple genera</td>
</tr>
<tr>
<td><b>categorizeGeneraIn=<i>parentName</i>|</b></td>
<td><-- Only if <i>parent</i> contains subfamilies or tribes</td>
</tr>
<tr>
<td><b>categorizeSubtribesIn=<i>parentName</i>|</b></td>
<td><-- Only if <i>parent</i> contains tribes AND subtribes</td>
</tr>
<tr>
<td><b>categorizeTribesIn=<i>parentName</i>|</b></td>
<td><-- Only if <i>parent</i> contains subfamilies AND tribes</td>
</tr>
<tr>
<td><b>categorizeSubfamiliesIn=<i>parentName</i>|</b></td>
<td><-- Only if <i>parent</i> contains clades containing subfamilies</td>
</tr>
<tr>
<td><b>categorizeFamiliesIn=<i>parentName</i>|</b></td>
<td><-- Only if <i>parent</i> contains multiple families</td>
</tr>
</table></dd>
</dl>
</dd>
]=]
end
doc = doc ..
[=[</dl>
<br/>
<dl>
<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,
Lepidoptera=true,
Coleoptera2=true,
Lepidoptera2=true,
['Coleoptera/sandbox']=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 string.startsWith(pagename,'TaxonavigationIncluded') or
string.startsWith(pagename,'Taxonavigation/') or
string.startsWith(pagename,'Biohist') or
_templatesThatShouldNotBeAutoDocumented[pagename] then
-- Template:TaxonavigationIncluded, ..., Template:TaxonavigationIncluded2/sandbox have their own documentation that add their own categories
-- Template:Taxonavigation/testcases, Template:Taxonavigation/sandbox/testcases have no need for documentation nor categories
-- Template:Taxonavigation, Coleoptera, Lepidoptera have no need for documentation nor 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']) .. '----------------------------------------------------------')
--_common.addDebug('taxonavigation','namespaceForDebug=' .. tostring(namespaceForDebug))
--_common.addDebug('taxonavigation','pagenameForDebug=' .. tostring(pagenameForDebug))
--_common.addDebug('taxonavigation','namespace=' .. tostring(namespace))
--_common.addDebug('taxonavigation','pagename=' .. tostring(pagename))
--_common.addDebug('taxonavigation','isGalleryOrCategory=' .. tostring(isGalleryOrCategory))
--_common.addDebug('taxonavigation','serializeCurrentParameters=' ..serializeCurrentParameters(options))
_common.addDebug('taxonavigation','options[parameters]=' .. tostring(options['parameters']))
--_common.addDebug('taxonavigation','options[1]=' .. tostring(options['1']))
--_common.addDebug('taxonavigation','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 (singularLatinRank == 'EMPTY') and (taxonName == 'EMPTY') then
-- Template:Coleoptera and Template:Lepidoptera have strange empty lines
elseif (taxonName == 'NOTTOBEDISPLAYED') then
-- 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 NonRegression
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
return ''
end
singularLatinRank = mw.text.trim(singularLatinRank)
taxonName = string.gsub(taxonName, '†', '', 5)
taxonName = mw.text.trim(taxonName)
if (singularLatinRank == 'EMPTY') and (taxonName == 'EMPTY') then
-- Template:Coleoptera and Template:Lepidoptera have strange empty lines
elseif (taxonName == 'NOTTOBEDISPLAYED') then
-- Template:Lepidoptera have strange empty lines
else
local currentTaxonNameIsPagename = (lang:ucfirst(taxonName) == lang:ucfirst(pagename))
if currentTaxonNameIsPagename then
local currentPageTaxonSingularLatinRank = lang:ucfirst(singularLatinRank)
return currentPageTaxonSingularLatinRank
end
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 NonRegression
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
return mw.text.jsonEncode(parameters)
end
singularLatinRank = mw.text.trim(singularLatinRank)
taxonName = string.gsub(taxonName, '†', '', 5)
taxonName = mw.text.trim(taxonName)
if (singularLatinRank == 'EMPTY') and (taxonName == 'EMPTY') then
-- Template:Coleoptera and Template:Lepidoptera have strange empty lines
elseif (taxonName == 'NOTTOBEDISPLAYED') then
-- Template:Lepidoptera have strange empty lines
else
parameters[lang:lc(singularLatinRank)] = taxonName -- can contains extinct sign
local currentTaxonNameIsPagename = (lang:ucfirst(taxonName) == lang:ucfirst(pagename))
if currentTaxonNameIsPagename then
local currentPageTaxonSingularLatinRank = lang:ucfirst(singularLatinRank)
parameters['CurrentPageTaxonRank'] = currentPageTaxonSingularLatinRank
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', index .. ' is in _acceptedNamedParameters')
elseif string.startsWith(index, 'categorize') then
-- normal argument pair: categorizeFamiliesIn=FAMILIA
-- _common.addDebug('detectTaxonavigationBadParameters', index .. ' starts with categorize')
else
-- bad argument pair: Authority=BadOrtho, Familia=Saturniidae
-- _common.addDebug('detectTaxonavigationBadParameters', index .. ' seems bad')
return _common.incorrectBiologyTemplateUsage('Taxonavigation', 'Incorrect parameter "' .. index .. '"', 'Taxonavigation')
end
else
-- normal argument pair: 1=Familia, 2=Saturniidae
-- _common.addDebug('detectTaxonavigationBadParameters', tostring(index) .. ' is not a string')
end
end
return ''
end
----------------------------------------------------------------------------------------------------
---------- PUBLIC FUNCTIONS ------------------------------------------------------------------------
----------------------------------------------------------------------------------------------------
local p = {}
local getArgs = require('Module:Arguments').getArgs
-- public version of taxonavigation
-- Used by {{Taxonavigation}}, {{TaxonavigationIncluded}} and {{TaxonavigationIncluded2}}
function p.taxonavigation(frame)
local taxonavigationStr = taxonavigation(frame, getArgs(frame))
--_common.addDebug('p.taxonavigation', detectTaxonavigationBadParameters(getArgs(frame)))
taxonavigationStr = taxonavigationStr .. _common.getDebug('<BR/>')
return taxonavigationStr .. detectTaxonavigationBadParameters(getArgs(frame))
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)
return mw.text.trim(tostring(frame.args['1']))
end
function p.testcase_doesSingularLatinRankExist(frame)
local singularLatinRank = frame.args['1']
if string.isNilOrEmpty(singularLatinRank) then
return false
end
return tostring(doesSingularLatinRankExist(singularLatinRank))
end
function p.testcase_rankNeedsItalic(frame)
local singularLatinRank = frame.args['1']
if string.isNilOrEmpty(singularLatinRank) then
return true
end
return tostring(rankNeedsItalic(singularLatinRank))
end
function p.testcase_articleExists(frame)
local article = frame.args['1']
if string.isNilOrEmpty(article) then
return false
end
return tostring(articleExists(article))
end
function p.testcase_categoryExists(frame)
local category = frame.args['1']
if string.isNilOrEmpty(category) then
return false
end
return tostring(categoryExists(category))
end
function p.testcase_calcItalicTitle(frame)
return mw.text.nowiki(calcItalicTitle(frame.args['1']))
end
return p