Wikipedia
acewiki
https://ace.wikipedia.org/wiki/%C3%94n_Keue
MediaWiki 1.47.0-wmf.23
first-letter
Alat
Kusuih
Marit
Ureuëng Ngui
Marit Ureuëng Ngui
Wikipedia
Marit Wikipedia
Beureukaih
Marit Beureukaih
MediaWiki
Marit MediaWiki
Seunaleuëk
Marit Seunaleuëk
Beunantu
Marit Beunantu
Kawan
Marit Kawan
TimedText
TimedText talk
Modul
Pembicaraan Modul
Acara
Pembicaraan Acara
Teubai bibi
0
9678
159040
158857
2026-10-10T17:20:14Z
Rachmat04
7338
159040
wikitext
text/x-wiki
{{Speciesbox|name=Teubai bibi|image=Plectorhinchus chaetodonoides.JPG|taxon=Plectorhinchus chaetodonoides|authority=[[Bernard Germain de Lacépède|Lacépède]], 1801|synonyms=* ''Gaterin chaetodonoides'' <small>(Lacépède, 1801)</small>|synonyms_ref=<ref name = Fishbase>{{FishBase|Plectorhinchus|chaetodonoides|month=February|year=2021}}</ref>}}
'''Tubai bibi''' (nan Latèn: ''Plectrorhinchus chaetodontoides'') nakeuh saboh jeunèh [[eungkôt]] kareueng lam kawan tubai bibi nyang na di la'ôt Acèh. Eungkôt nyoe kayém geudrop lé ureueng meula'ôt keu geupeubloe.<ref name="acehjaya.org_Nama-NamaI">{{Cite web |title=Nama-Nama Ikan Laut Commercial Di Perairan Aceh |author= |work=acehjaya.org |date= |accessdate=2016-04-11 |url=http://www.acehjaya.org/2015/12/nama-nama-ikan-laut-commercial-di.html |language= |quote= |archivedate=2016-05-16 |archiveurl=https://web.archive.org/web/20160516191132/http://www.acehjaya.org/2015/12/nama-nama-ikan-laut-commercial-di.html |dead-url=no }}</ref>
== Asai seunurat ==
{{reflist}}
[[Kawan:Eungkôt]]
[[Kawan:Gamba Peuniléh Thôn 2026]]
[[Kawan:Haemulidae]]
eibp3n3r23ujyukyyr0gq9h08zkdoi4
159044
159040
2026-10-11T10:14:13Z
Si Gam
4266
159044
wikitext
text/x-wiki
{{Speciesbox
|name = Teubai bibi
|image = Plectorhinchus chaetodonoides.JPG
|taxon = Plectorhinchus chaetodonoides
|authority = [[Bernard Germain de Lacépède|Lacépède]], 1801
|synonyms =* ''Gaterin chaetodonoides'' <small>(Lacépède, 1801)</small>
|synonyms_ref = <ref name = Fishbase>{{FishBase|Plectorhinchus|chaetodonoides|month=February|year=2021}}</ref>
}}
'''Tubai bibi''' (nan Latèn: ''Plectrorhinchus chaetodontoides'') nakeuh saboh jeunèh [[eungkôt]] kareueng lam kawan tubai bibi nyang na di la'ôt Acèh. Eungkôt nyoe kayém geudrop lé ureueng meula'ôt keu geupeubloe.<ref name="acehjaya.org_Nama-NamaI">{{Cite web |title=Nama-Nama Ikan Laut Commercial Di Perairan Aceh |author= |work=acehjaya.org |date= |accessdate=2016-04-11 |url=http://www.acehjaya.org/2015/12/nama-nama-ikan-laut-commercial-di.html |language= |quote= |archivedate=2016-05-16 |archiveurl=https://web.archive.org/web/20160516191132/http://www.acehjaya.org/2015/12/nama-nama-ikan-laut-commercial-di.html |dead-url=no }}</ref>
== Asai seunurat ==
{{reflist}}
[[Kawan:Eungkôt]]
[[Kawan:Gamba Peuniléh Thôn 2026]]
[[Kawan:Haemulidae]]
b7ki8zlpbpybg7nzlg198q2b9djqexq
Seunaleuëk:Speciesbox
10
10603
159006
92316
2026-10-10T16:50:53Z
Rachmat04
7338
159006
wikitext
text/x-wiki
<noinclude><!--
-====================================================================
- Template:Speciesbox - Generate a taxobox infobox for species
-====================================================================
--
-- This template chooses parameters to send to {Taxobox/core}, to
-- generate a right-side taxobox infobox. Most parameters are just
-- passed directly; some are explained with a comment. When run as
-- stand-alone, the template shows Acacia aemula as sample output.
--
-- The genus name of the species is found by looking in order at
-- (1) the genus parameter
-- (2) the first word of the taxon parameter
-- (3) the first word of the page name.
-- The species name/specific epithet is found by looking in order at
-- (1) the species parameter
-- (2) the rest of the taxon parameter after removing the first word
-- (3) the rest of the page name after removing any final part in
-- parentheses and then removing the first word.
--
-- The genus name is then the entry into the taxonomic hierarchy.
--
-- A complication is that if the taxonomy template for the genus needs
-- disambiguation (i.e. is "Template:Taxonomy/GENUS (DISAMBIG)") then
-- the parameters will be genus=GENUS (DISAMBIG) | species=EPITHET
-- Can also have genus=GENUS/QUALIFIER
--
-------------------------------- Invoke {Taxobox/core}
The nowiki that follows is needed because of parser bug T18700--></noinclude><nowiki/>{{Taxobox/core<includeonly>
| edit link = {{if empty|{{{edit link|}}}|{{{edit_link|}}}|edit}}</includeonly><noinclude><!--
--
-- fossil_range: If the specified fossil range is a period supported
-- by templates {period_start} and {next_period}, then it incorporates
-- the specified range in template {geological range}, but checking
-- to display properly. Otherwise, just passes parameter.
--></noinclude>
| temporal_range = {{#if:{{{fossil_range|}}}{{{fossil range|}}}|{{#iferror:{{geological range|{{if empty|{{{temporal_range|}}}|{{{temporal range|}}}|{{{fossil_range|}}}|{{{fossil range|}}}}} }}|{{if empty|{{{temporal_range|}}}|{{{temporal range|}}}|{{{fossil_range|}}}|{{{fossil range|}}}}}|{{geological range|{{if empty|{{{temporal_range|}}}|{{{temporal range|}}}|{{{fossil_range|}}}|{{{fossil range|}}}}} }} }} | {{#if:{{{oldest fossil|}}}{{{oldest_fossil|}}}|{{geological range|{{if empty|{{{oldest fossil|}}}|{{{oldest_fossil}}}}}|{{if empty|{{{youngest fossil|}}}|{{{youngest_fossil|}}}|Recent}} }} }} }}<noinclude><!--
PARENT: this is the taxon whose taxonomy template is used to find the taxonomic hierarchy; if
not supplied as a parameter value, it defaults to the genus name.
Template:Taxonomy/PARENT must exist. --></noinclude>
| parent = <includeonly>{{{parent|{{Speciesbox/getGenus|{{{taxon|}}}|{{{genus|}}}}}}}}</includeonly><noinclude>Acacia<!--
DISPLAY PARENTS:
Number of immediate parents to display. Defaults to 1 above species, normally the genus (which is displayed as
a major rank, anyway).
--></noinclude>
| display_taxa = {{#expr:{{if empty|{{{display parents|}}}|{{{display_parents|}}}|1}}-1}}<noinclude><!--
AUTHORITY (etc):
In the format "author, year".
Species-authority is redundant to binomial_authority; we'll just list it the once. (This avoids reference-duplication errors, too.
| species_authority = {{if empty|{{{authority|}}}|{{{binomial authority|}}}|{{{binomial_authority|}}}}}--></noinclude>
| authority = {{{authority|}}}
| parent_authority = {{if empty|{{{parent_authority|}}}|{{{parent authority|}}}}}
| grandparent_authority = {{if empty|{{{grandparent_authority|}}}|{{{grandparent authority|}}}}}
| greatgrandparent_authority = {{if empty|{{{greatgrandparent_authority|}}}|{{{greatgrandparent authority|}}}}}
| greatgreatgrandparent_authority = {{if empty|{{{greatgreatgrandparent_authority|}}}|{{{greatgreatgrandparent authority|}}}}}
| greatgreatgreatgrandparent_authority = {{if empty|{{{greatgreatgreatgrandparent_authority|}}}|{{{greatgreatgreatgrandparent authority|}}}}}
| offset = 1
<noinclude><!--
NAME:
{{Speciesbox/name}} both determines the taxobox name and whether the page title should be italicized by
adding the {{italic title}} template.
--></noinclude>
| name = {{Speciesbox/name|{{if empty|{{{name|}}}|<noinclude>''Acacia aemula''</noinclude>}}|{{{taxon|}}}|{{{genus|}}}|{{{species|}}}|{{PAGENAMEBASE}}|{{if empty|{{{italic_title|}}}|{{{italic title|}}}|yes}}}}<noinclude><!--
-- colour: (Note UK spelling here) There are two cases:
1) the parameter color_as has a value – the colour is found directly using {{Taxobox colour|color_as}}
2) otherwise – Module:Autotaxobox|taxoboxColour searches up the taxonomic hierarchy to try to find a taxon that
determines the taxobox colour
--></noinclude>
| colour = {{#if:{{{color_as|}}}{{{colour_as|}}}{{{color as|}}}{{{colour as|}}}|{{Taxobox colour|{{if empty|{{{color_as|}}}|{{{colour_as|}}}|{{{color as|}}}|{{{colour as|}}}}}}}|{{#invoke:Autotaxobox|taxoboxColour|<includeonly>{{{parent|{{Speciesbox/getGenus|{{{taxon|}}}|{{{genus|}}}}}}}}</includeonly><noinclude>Acacia</noinclude> }} }}
| status = {{{status|}}}
| status_system = {{if empty|{{{status system|}}}|{{{status_system|}}}}}
| status_ref = {{if empty|{{{status ref|}}}|{{{status_ref|}}}}}
| status2 = {{{status2|}}}
| status2_system = {{if empty|{{{status2 system|}}}|{{{status2_system|}}}}}
| status2_ref = {{if empty|{{{status2 ref|}}}|{{{status2_ref|}}}}}
| status3 = {{{status3|}}}
| status3_system = {{if empty|{{{status3 system|}}}|{{{status3_system|}}}}}
| status3_ref = {{if empty|{{{status3 ref|}}}|{{{status3_ref|}}}}}
| trend = {{{trend|}}}
| image = {{{image|}}}
| upright = {{if empty|{{{image_upright|}}}|{{{image upright|}}}}}
| image_alt = {{if empty|{{{image alt|}}}|{{{image_alt|}}}}}
| image_caption = {{if empty|{{{image caption|}}}|{{{image_caption|}}}}}
| image2 = {{{image2|}}}
| upright2 = {{if empty|{{{image2_upright|}}}|{{{image2 upright|}}}}}
| image2_alt = {{if empty|{{{image2 alt|}}}|{{{image2_alt|}}}}}
| image2_caption = {{if empty|{{{image2 caption|}}}|{{{image2_caption|}}}}}
| classification_status = {{if empty|{{{classification status|}}}|{{{classification_status|}}}}}
| diversity = {{{diversity|}}}
| diversity_ref = {{if empty|{{{diversity ref|}}}|{{{diversity_ref|}}}}}
| diversity_link = {{if empty|{{{diversity link|}}}|{{{diversity_link|}}}}}
| extinct = {{{extinct|}}}
| species = {{#if:{{{extinct|}}}|†|{{#ifeq:{{{status|}}}|EX|†|{{Taxon info|<includeonly>{{Speciesbox/getGenus|{{{taxon|}}}|{{{genus|}}}}}</includeonly><noinclude>Acacia</noinclude>|dagger}}}}}}<!--
-->'''{{taxon italics|abbreviated=yes|<includeonly>{{Speciesbox/trim|{{Speciesbox/getGenus|{{{taxon|}}}|{{{genus|}}}}}}} {{Speciesbox/getSpecies|{{{taxon|}}}|{{{species|}}}}}</includeonly><noinclude>Acacia aemula</noinclude>}}'''
| binomial = <span style="font-weight:normal;">{{#if:{{{extinct|}}}|†|{{#ifeq:{{{status|}}}|EX|†|{{Taxon info|<includeonly>{{Speciesbox/getGenus|{{{taxon|}}}|{{{genus|}}}}}</includeonly><noinclude>Acacia</noinclude>|dagger}}}}}}</span><!--
-->{{taxon italics|<includeonly>{{Speciesbox/trim|{{Speciesbox/getGenus|{{{taxon|}}}|{{{genus|}}}}}}} {{Speciesbox/getSpecies|{{{taxon|}}}|{{{species|}}}}}</includeonly><noinclude>Acacia aemula</noinclude>}}
| binomial_authority = {{if empty|{{{authority|}}}|{{{binomial authority|}}}|{{{binomial_authority|}}}}}
| subdivision = {{{subdivision|}}}
| subdivision_ranks = {{if empty|{{{subdivision ranks|}}}|{{{subdivision_ranks|}}}|Subspecies}}
| subdivision_ref = {{if empty|{{{subdivision_ref|}}}|{{{subdivision ref|}}}}}
| type_strain = {{if empty|{{{type strain|}}}|{{{type_strain|}}}}}
| type_strain_ref = {{if empty|{{{type_strain_ref|}}}|{{{type strain ref|}}}}}
| range_map = {{if empty|{{{range map|}}}|{{{range_map|}}}}}
| range_map_upright = {{if empty|{{{range_map_upright|}}}|{{{range map upright|}}}}}
| range_map_alt = {{if empty|{{{range map alt|}}}|{{{range_map_alt|}}}}}
| range_map_caption = {{if empty|{{{range map caption|}}}|{{{range_map_caption|}}}}}
| range_map2 = {{if empty|{{{range map2|}}}|{{{range_map2|}}}}}
| range_map2_upright = {{if empty|{{{range_map2_upright|}}}|{{{range map2 upright|}}}}}
| range_map2_alt = {{if empty|{{{range map2 alt|}}}|{{{range_map2_alt|}}}}}
| range_map2_caption = {{if empty|{{{range map2 caption|}}}|{{{range_map2_caption|}}}}}
| range_map3 = {{if empty|{{{range map3|}}}|{{{range_map3|}}}}}
| range_map3_upright = {{if empty|{{{range_map3_upright|}}}|{{{range map3 upright|}}}}}
| range_map3_alt = {{if empty|{{{range map3 alt|}}}|{{{range_map3_alt|}}}}}
| range_map3_caption = {{if empty|{{{range map3 caption|}}}|{{{range_map3_caption|}}}}}
| range_map4 = {{#invoke:Infobox mapframe|autoWithCaption}}
| synonyms_ref = {{if empty|{{{synonyms ref|}}}|{{{synonyms_ref|}}}}}
| synonyms = {{{synonyms|}}}
| audio = {{{audio|}}}
| audio_caption = {{if empty|{{{audio caption|}}}|{{{audio_caption|}}}}}
}}{{Speciesbox/parameterCheck|{{{taxon|}}}|{{{genus|}}}|{{{species|}}}}}{{#invoke:Check for unknown parameters|check|unknown={{main other|[[Category:Pages using speciesbox with unknown parameters|_VALUE_{{PAGENAME}}]]}}|preview=Page using [[Template:Speciesbox]] with unknown parameter "_VALUE_"|ignoreblank=y| mapframe_args = y | audio | audio_caption | authority | binomial authority | binomial_authority | classification status | classification_status | color as | color_as | colour as | colour_as | display parents | display_parents | diversity | diversity link | diversity ref | diversity_link | diversity_ref | edit link | edit_link | extinct | fossil range | fossil_range | genus | grandparent authority | grandparent_authority | greatgrandparent authority | greatgrandparent_authority | greatgreatgrandparent authority | greatgreatgrandparent_authority | greatgreatgreatgrandparent authority | greatgreatgreatgrandparent_authority | image | image alt | image caption | image upright | image_alt | image_caption | image_upright | image2 | image2 alt | image2 caption | image2 upright | image2_alt | image2_caption | image2_upright | italic title | italic_title | name | oldest fossil | oldest_fossil | parent | parent authority | parent_authority | range map | range map alt | range map caption | range map upright | range map2 | range map2 alt | range map2 caption | range map2 upright | range map3 | range map3 alt | range map3 caption | range map3 upright | range_map | range_map_alt | range_map_caption | range_map_upright | range_map2 | range_map2_alt | range_map2_caption | range_map2_upright | range_map3 | range_map3_alt | range_map3_caption | range_map3_upright | species | status | status ref | status system | status_ref | status_system | status2 | status2 ref | status2 system | status2_ref | status2_system | status3 | status3_ref | status3_system | subdivision | subdivision ranks | subdivision ref | subdivision_ranks | subdivision_ref | synonyms | synonyms ref | synonyms_ref | taxon | temporal range | temporal_range | trend | type strain | type strain ref | type_strain | type_strain_ref | youngest fossil | youngest_fossil }}{{#invoke:Check for conflicting parameters|check
| template = [[Template:Speciesbox]]
| cat = {{main other|Category:Pages using speciesbox with conflicting parameters}}
| edit link; edit_link
| temporal_range; temporal range; fossil_range; fossil range
| oldest fossil; oldest_fossil
| youngest fossil; youngest_fossil
| display parents; display_parents
| authority; binomial authority; binomial_authority
| parent_authority; parent authority
| grandparent_authority; grandparent authority
| greatgrandparent_authority; greatgrandparent authority
| greatgreatgrandparent_authority; greatgreatgrandparent authority
| greatgreatgreatgrandparent_authority; greatgreatgreatgrandparent authority
| italic_title; italic title
| color_as; colour_as; color as; colour as
| status system; status_system
| status ref; status_ref
| status2 system; status2_system
| status2 ref; status2_ref
| image_upright; image upright
| image alt; image_alt
| image caption; image_caption
| image2_upright; image2 upright
| image2 alt; image2_alt
| image2 caption; image2_caption
| classification status; classification_status
| diversity ref; diversity_ref
| diversity link; diversity_link
| subdivision ranks; subdivision_ranks
| subdivision_ref; subdivision ref
| type strain; type_strain
| type_strain_ref; type strain ref
| range map; range_map
| range_map_upright; range map upright
| range map alt; range_map_alt
| range map caption; range_map_caption
| range map2; range_map2
| range_map2_upright; range map2 upright
| range map2 alt; range_map2_alt
| range map2 caption; range_map2_caption
| range map3; range_map3
| range_map3_upright; range map3 upright
| range map3 alt; range_map3_alt
| range map3 caption; range_map3_caption
| synonyms ref; synonyms_ref
}}<noinclude>
{{documentation}}</noinclude>
qinvv83fxpg4vegekiukv70lx0ei6s8
Modul:Infobox/bakpasir
828
20748
159000
121118
2026-10-10T16:41:23Z
Rachmat04
7338
←Mengalihkan ke [[Modul:Infobox/bak pasir]]
159000
Scribunto
text/plain
return require [[Modul:Infobox/bak pasir]]
qrq80kb09xhejvrqaea76yj1h4tsilo
Modul:Wikidata
828
20752
159004
121123
2026-10-10T16:46:56Z
Rachmat04
7338
159004
Scribunto
text/plain
-- vim: set noexpandtab ft=lua ts=4 sw=4:
require('strict')
local p = {}
local debug = false
------------------------------------------------------------------------------
-- module local variables and functions
local wiki =
{
langcode = mw.language.getContentLanguage().code
}
-- internationalisation
local i18n =
{
["errors"] =
{
["property-not-found"] = "Property not found.",
["entity-not-found"] = "Wikidata entity not found.",
["unknown-claim-type"] = "Unknown claim type.",
["unknown-entity-type"] = "Unknown entity type.",
["qualifier-not-found"] = "Qualifier not found.",
["site-not-found"] = "Wikimedia project not found.",
["unknown-datetime-format"] = "Unknown datetime format.",
["local-article-not-found"] = "Article is not yet available in this wiki."
},
["datetime"] =
{
-- $1 is a placeholder for the actual number
[0] = "$1 billion years", -- precision: billion years
[1] = "$100 million years", -- precision: hundred million years
[2] = "$10 million years", -- precision: ten million years
[3] = "$1 million years", -- precision: million years
[4] = "$100,000 years", -- precision: hundred thousand years
[5] = "$10,000 years", -- precision: ten thousand years
[6] = "$1 millennium", -- precision: millennium
[7] = "$1 century", -- precision: century
[8] = "$1s", -- precision: decade
-- the following use the format of #time parser function
[9] = "Y", -- precision: year,
[10] = "F Y", -- precision: month
[11] = "F j, Y", -- precision: day
[12] = "F j, Y ga", -- precision: hour
[13] = "F j, Y g:ia", -- precision: minute
[14] = "F j, Y g:i:sa", -- precision: second
["beforenow"] = "$1 BCE", -- how to format negative numbers for precisions 0 to 5
["afternow"] = "$1 CE", -- how to format positive numbers for precisions 0 to 5
["bc"] = '$1 "BCE"', -- how print negative years
["ad"] = "$1", -- how print positive years
-- the following are for function getDateValue() and getQualifierDateValue()
["default-format"] = "dmy", -- default value of the #3 (getDateValue) or
-- #4 (getQualifierDateValue) argument
["default-addon"] = "BC", -- default value of the #4 (getDateValue) or
-- #5 (getQualifierDateValue) argument
["prefix-addon"] = false, -- set to true for languages put "BC" in front of the
-- datetime string; or the addon will be suffixed
["addon-sep"] = " ", -- separator between datetime string and addon (or inverse)
["format"] = -- options of the 3rd argument
{
["mdy"] = "F j, Y",
["my"] = "F Y",
["y"] = "Y",
["dmy"] = "j F Y",
["ymd"] = "Y-m-d",
["ym"] = "Y-m"
}
},
["monolingualtext"] = '<span lang="%language">%text</span>',
["warnDump"] = "[[Category:Called function 'Dump' from module Wikidata]]",
["ordinal"] =
{
[1] = "st",
[2] = "nd",
[3] = "rd",
["default"] = "th"
}
}
if wiki.langcode ~= "en" then
--require("Module:i18n").loadI18n("Module:Wikidata/i18n", i18n)
-- got idea from [[:w:Module:Wd]]
local module_title; if ... == nil then
module_title = mw.getCurrentFrame():getTitle()
else
module_title = ...
end
require('Module:i18n').loadI18n(module_title..'/i18n', i18n)
end
-- this function needs to be internationalised along with the above:
-- takes cardinal numer as a numeric and returns the ordinal as a string
-- we need three exceptions in English for 1st, 2nd, 3rd, 21st, .. 31st, etc.
local function makeOrdinal (cardinal)
local ordsuffix = i18n.ordinal.default
if cardinal % 10 == 1 then
ordsuffix = i18n.ordinal[1]
elseif cardinal % 10 == 2 then
ordsuffix = i18n.ordinal[2]
elseif cardinal % 10 == 3 then
ordsuffix = i18n.ordinal[3]
end
-- In English, 1, 21, 31, etc. use 'st', but 11, 111, etc. use 'th'
-- similarly for 12 and 13, etc.
if (cardinal % 100 == 11) or (cardinal % 100 == 12) or (cardinal % 100 == 13) then
ordsuffix = i18n.ordinal.default
end
return tostring(cardinal) .. ordsuffix
end
local function printError(code)
return '<span class="error">' .. (i18n.errors[code] or code) .. '</span>'
end
local function parseDateFormat(f, timestamp, addon, prefix_addon, addon_sep)
local year_suffix
local tstr = ""
local lang_obj = mw.language.new(wiki.langcode)
local f_parts = mw.text.split(f, 'Y', true)
for idx, f_part in pairs(f_parts) do
year_suffix = ''
if string.match(f_part, "x[mijkot]$") then
-- for non-Gregorian year
f_part = f_part .. 'Y'
elseif idx < #f_parts then
-- supress leading zeros in year
year_suffix = lang_obj:formatDate('Y', timestamp)
year_suffix = string.gsub(year_suffix, '^0+', '', 1)
end
tstr = tstr .. lang_obj:formatDate(f_part, timestamp) .. year_suffix
end
if addon ~= "" and prefix_addon then
return addon .. addon_sep .. tstr
elseif addon ~= "" then
return tstr .. addon_sep .. addon
else
return tstr
end
end
local function parseDateValue(timestamp, date_format, date_addon)
local prefix_addon = i18n["datetime"]["prefix-addon"]
local addon_sep = i18n["datetime"]["addon-sep"]
local addon = ""
-- check for negative date
if string.sub(timestamp, 1, 1) == '-' then
timestamp = '+' .. string.sub(timestamp, 2)
addon = date_addon
end
local _date_format = i18n["datetime"]["format"][date_format]
if _date_format ~= nil then
return parseDateFormat(_date_format, timestamp, addon, prefix_addon, addon_sep)
else
return printError("unknown-datetime-format")
end
end
-- This local function combines the year/month/day/BC/BCE handling of parseDateValue{}
-- with the millennium/century/decade handling of formatDate()
local function parseDateFull(timestamp, precision, date_format, date_addon)
local prefix_addon = i18n["datetime"]["prefix-addon"]
local addon_sep = i18n["datetime"]["addon-sep"]
local addon = ""
-- check for negative date
if string.sub(timestamp, 1, 1) == '-' then
timestamp = '+' .. string.sub(timestamp, 2)
addon = date_addon
end
-- get the next four characters after the + (should be the year now in all cases)
-- ok, so this is dirty, but let's get it working first
local intyear = tonumber(string.sub(timestamp, 2, 5))
if intyear == 0 and precision <= 9 then
return ""
end
-- precision is 10000 years or more
if precision <= 5 then
local factor = 10 ^ ((5 - precision) + 4)
local y2 = math.ceil(math.abs(intyear) / factor)
local relative = mw.ustring.gsub(i18n.datetime[precision], "$1", tostring(y2))
if addon ~= "" then
-- negative date
relative = mw.ustring.gsub(i18n.datetime.beforenow, "$1", relative)
else
relative = mw.ustring.gsub(i18n.datetime.afternow, "$1", relative)
end
return relative
end
-- precision is decades (8), centuries (7) and millennia (6)
local era, card
if precision == 6 then
card = math.floor((intyear - 1) / 1000) + 1
era = mw.ustring.gsub(i18n.datetime[6], "$1", makeOrdinal(card))
end
if precision == 7 then
card = math.floor((intyear - 1) / 100) + 1
era = mw.ustring.gsub(i18n.datetime[7], "$1", makeOrdinal(card))
end
if precision == 8 then
era = mw.ustring.gsub(i18n.datetime[8], "$1", tostring(math.floor(math.abs(intyear) / 10) * 10))
end
if era then
if addon ~= "" then
era = mw.ustring.gsub(mw.ustring.gsub(i18n.datetime.bc, '"', ""), "$1", era)
else
era = mw.ustring.gsub(mw.ustring.gsub(i18n.datetime.ad, '"', ""), "$1", era)
end
return era
end
local _date_format = i18n["datetime"]["format"][date_format]
if _date_format ~= nil then
-- check for precision is year and override supplied date_format
if precision == 9 then
_date_format = i18n["datetime"][9]
end
return parseDateFormat(_date_format, timestamp, addon, prefix_addon, addon_sep)
else
return printError("unknown-datetime-format")
end
end
-- the "qualifiers" and "snaks" field have a respective "qualifiers-order" and "snaks-order" field
-- use these as the second parameter and this function instead of the built-in "pairs" function
-- to iterate over all qualifiers and snaks in the intended order.
local function orderedpairs(array, order)
if not order then return pairs(array) end
-- return iterator function
local i = 0
return function()
i = i + 1
if order[i] then
return order[i], array[order[i]]
end
end
end
-- precision: 0 - billion years, 1 - hundred million years, ..., 6 - millennia, 7 - century, 8 - decade, 9 - year, 10 - month, 11 - day, 12 - hour, 13 - minute, 14 - second
local function normalizeDate(date)
date = mw.text.trim(date, "+")
-- extract year
local yearstr = mw.ustring.match(date, "^\-?%d+")
local year = tonumber(yearstr)
-- remove leading zeros of year
return year .. mw.ustring.sub(date, #yearstr + 1), year
end
local function formatDate(date, precision, timezone)
precision = precision or 11
local date, year = normalizeDate(date)
if year == 0 and precision <= 9 then return "" end
-- precision is 10000 years or more
if precision <= 5 then
local factor = 10 ^ ((5 - precision) + 4)
local y2 = math.ceil(math.abs(year) / factor)
local relative = mw.ustring.gsub(i18n.datetime[precision], "$1", tostring(y2))
if year < 0 then
relative = mw.ustring.gsub(i18n.datetime.beforenow, "$1", relative)
else
relative = mw.ustring.gsub(i18n.datetime.afternow, "$1", relative)
end
return relative
end
-- precision is decades, centuries and millennia
local era
if precision == 6 then era = mw.ustring.gsub(i18n.datetime[6], "$1", tostring(math.floor((math.abs(year) - 1) / 1000) + 1)) end
if precision == 7 then era = mw.ustring.gsub(i18n.datetime[7], "$1", tostring(math.floor((math.abs(year) - 1) / 100) + 1)) end
if precision == 8 then era = mw.ustring.gsub(i18n.datetime[8], "$1", tostring(math.floor(math.abs(year) / 10) * 10)) end
if era then
if year < 0 then era = mw.ustring.gsub(mw.ustring.gsub(i18n.datetime.bc, '"', ""), "$1", era)
elseif year > 0 then era = mw.ustring.gsub(mw.ustring.gsub(i18n.datetime.ad, '"', ""), "$1", era) end
return era
end
-- precision is year
if precision == 9 then
return year
end
-- precision is less than years
if precision > 9 then
--[[ the following code replaces the UTC suffix with the given negated timezone to convert the global time to the given local time
timezone = tonumber(timezone)
if timezone and timezone ~= 0 then
timezone = -timezone
timezone = string.format("%.2d%.2d", timezone / 60, timezone % 60)
if timezone[1] ~= '-' then timezone = "+" .. timezone end
date = mw.text.trim(date, "Z") .. " " .. timezone
end
]]--
local formatstr = i18n.datetime[precision]
if year == 0 then formatstr = mw.ustring.gsub(formatstr, i18n.datetime[9], "")
elseif year < 0 then
-- Mediawiki formatDate doesn't support negative years
date = mw.ustring.sub(date, 2)
formatstr = mw.ustring.gsub(formatstr, i18n.datetime[9], mw.ustring.gsub(i18n.datetime.bc, "$1", i18n.datetime[9]))
elseif year > 0 and i18n.datetime.ad ~= "$1" then
formatstr = mw.ustring.gsub(formatstr, i18n.datetime[9], mw.ustring.gsub(i18n.datetime.ad, "$1", i18n.datetime[9]))
end
return mw.language.new(wiki.langcode):formatDate(formatstr, date)
end
end
local function printDatavalueEntity(data, parameter)
-- data fields: entity-type [string], numeric-id [int, Wikidata id]
local id
if data["entity-type"] == "item" then id = "Q" .. data["numeric-id"]
elseif data["entity-type"] == "property" then id = "P" .. data["numeric-id"]
else return printError("unknown-entity-type")
end
if parameter then
if parameter == "link" then
local linkTarget = mw.wikibase.getSitelink(id)
local linkName = mw.wikibase.getLabel(id)
if linkTarget then
-- if there is a local Wikipedia article link to it using the label or the article title
return "[[" .. linkTarget .. "|" .. (linkName or linkTarget) .. "]]"
else
-- if there is no local Wikipedia article output the label or link to the Wikidata object to let the user input a proper label
if linkName then return linkName else return "[[:d:" .. id .. "|" .. id .. "]]" end
end
else
return data[parameter]
end
else
return mw.wikibase.getLabel(id) or id
end
end
local function printDatavalueTime(data, parameter)
-- data fields: time [ISO 8601 time], timezone [int in minutes], before [int], after [int], precision [int], calendarmodel [wikidata URI]
-- precision: 0 - billion years, 1 - hundred million years, ..., 6 - millennia, 7 - century, 8 - decade, 9 - year, 10 - month, 11 - day, 12 - hour, 13 - minute, 14 - second
-- calendarmodel: e.g. http://www.wikidata.org/entity/Q1985727 for the proleptic Gregorian calendar or http://www.wikidata.org/wiki/Q11184 for the Julian calendar]
if parameter then
if parameter == "calendarmodel" then data.calendarmodel = mw.ustring.match(data.calendarmodel, "Q%d+") -- extract entity id from the calendar model URI
elseif parameter == "time" then data.time = normalizeDate(data.time) end
return data[parameter]
else
return formatDate(data.time, data.precision, data.timezone)
end
end
local function printDatavalueMonolingualText(data, parameter)
-- data fields: language [string], text [string]
if parameter then
return data[parameter]
else
local result = mw.ustring.gsub(mw.ustring.gsub(i18n.monolingualtext, "%%language", data["language"]), "%%text", data["text"])
return result
end
end
local function findClaims(entity, property)
if not property or not entity or not entity.claims then return end
if mw.ustring.match(property, "^P%d+$") then
-- if the property is given by an id (P..) access the claim list by this id
return entity.claims[property]
else
property = mw.wikibase.resolvePropertyId(property)
if not property then return end
return entity.claims[property]
end
end
local function getSnakValue(snak, parameter)
if snak.snaktype == "value" then
-- call the respective snak parser
if snak.datavalue.type == "string" then return snak.datavalue.value
elseif snak.datavalue.type == "globecoordinate" then return printDatavalueCoordinate(snak.datavalue.value, parameter)
elseif snak.datavalue.type == "quantity" then return printDatavalueQuantity(snak.datavalue.value, parameter)
elseif snak.datavalue.type == "time" then return printDatavalueTime(snak.datavalue.value, parameter)
elseif snak.datavalue.type == "wikibase-entityid" then return printDatavalueEntity(snak.datavalue.value, parameter)
elseif snak.datavalue.type == "monolingualtext" then return printDatavalueMonolingualText(snak.datavalue.value, parameter)
end
end
return mw.wikibase.renderSnak(snak)
end
local function getQualifierSnak(claim, qualifierId)
-- a "snak" is Wikidata terminology for a typed key/value pair
-- a claim consists of a main snak holding the main information of this claim,
-- as well as a list of attribute snaks and a list of references snaks
if qualifierId then
-- search the attribute snak with the given qualifier as key
if claim.qualifiers then
local qualifier = claim.qualifiers[qualifierId]
if qualifier then return qualifier[1] end
end
return nil, printError("qualifier-not-found")
else
-- otherwise return the main snak
return claim.mainsnak
end
end
local function getValueOfClaim(claim, qualifierId, parameter)
local error
local snak
snak, error = getQualifierSnak(claim, qualifierId)
if snak then
return getSnakValue(snak, parameter)
else
return nil, error
end
end
local function getReferences(frame, claim)
local result = ""
-- traverse through all references
for ref in pairs(claim.references or {}) do
local refparts
-- traverse through all parts of the current reference
for snakkey, snakval in orderedpairs(claim.references[ref].snaks or {}, claim.references[ref]["snaks-order"]) do
if refparts then refparts = refparts .. ", " else refparts = "" end
-- output the label of the property of the reference part, e.g. "imported from" for P143
refparts = refparts .. tostring(mw.wikibase.getLabel(snakkey)) .. ": "
-- output all values of this reference part, e.g. "German Wikipedia" and "English Wikipedia" if the referenced claim was imported from both sites
for snakidx = 1, #snakval do
if snakidx > 1 then refparts = refparts .. ", " end
refparts = refparts .. getSnakValue(snakval[snakidx])
end
end
if refparts then result = result .. frame:extensionTag("ref", refparts) end
end
return result
end
local function parseInput(frame)
local qid = frame.args.qid
if qid and (#qid == 0) then qid = nil end
local propertyID = mw.text.trim(frame.args[1] or "")
local input_parm = mw.text.trim(frame.args[2] or "")
if input_parm ~= "FETCH_WIKIDATA" then
return false, input_parm, nil, nil
end
local entity = mw.wikibase.getEntity(qid)
local claims
if entity and entity.claims then
claims = entity.claims[propertyID]
if not claims then
return false, "", nil, nil
end
else
return false, "", nil, nil
end
return true, entity, claims, propertyID
end
local function isType(claims, type)
return claims[1] and claims[1].mainsnak.snaktype == "value" and claims[1].mainsnak.datavalue.type == type
end
local function getValue(entity, claims, propertyID, delim, labelHook)
if labelHook == nil then
labelHook = function (qnumber)
return nil;
end
end
if isType(claims, "wikibase-entityid") then
local out = {}
for k, v in pairs(claims) do
local qnumber = "Q" .. v.mainsnak.datavalue.value["numeric-id"]
local sitelink = mw.wikibase.getSitelink(qnumber)
local label = labelHook(qnumber) or mw.wikibase.getLabel(qnumber) or qnumber
if sitelink then
out[#out + 1] = "[[" .. sitelink .. "|" .. label .. "]]"
else
out[#out + 1] = "[[:d:" .. qnumber .. "|" .. label .. "]]<abbr title='" .. i18n["errors"]["local-article-not-found"] .. "'>[*]</abbr>"
end
end
return table.concat(out, delim)
else
-- just return best values
return entity:formatPropertyValues(propertyID).value
end
end
------------------------------------------------------------------------------
-- module global functions
if debug then
function p.inspectI18n(frame)
local val = i18n
for _, key in pairs(frame.args) do
key = mw.text.trim(key)
val = val[key]
end
return val
end
end
function p.descriptionIn(frame)
local langcode = frame.args[1]
local id = frame.args[2]
-- return description of a Wikidata entity in the given language or the default language of this Wikipedia site
return mw.wikibase.getEntity(id):getDescription(langcode or wiki.langcode)
end
function p.labelIn(frame)
local langcode = frame.args[1]
local id = frame.args[2]
-- return label of a Wikidata entity in the given language or the default language of this Wikipedia site
return mw.wikibase.getEntity(id):getLabel(langcode or wiki.langcode)
end
-- This is used to get a value, or a comma separated list of them if multiple values exist
p.getValue = function(frame)
local delimdefault = ", " -- **internationalise later**
local delim = frame.args.delimiter or ""
delim = string.gsub(delim, '"', '')
if #delim == 0 then
delim = delimdefault
end
local go, errorOrentity, claims, propertyID = parseInput(frame)
if not go then
return errorOrentity
end
return getValue(errorOrentity, claims, propertyID, delim)
end
-- Same as above, but uses the short name property for label if available.
p.getValueShortName = function(frame)
local go, errorOrentity, claims, propertyID = parseInput(frame)
if not go then
return errorOrentity
end
local entity = errorOrentity
-- if wiki-linked value output as link if possible
local function labelHook (qnumber)
local label
local claimEntity = mw.wikibase.getEntity(qnumber)
if claimEntity ~= nil then
if claimEntity.claims.P1813 then
for k2, v2 in pairs(claimEntity.claims.P1813) do
if v2.mainsnak.datavalue.value.language == "en" then
label = v2.mainsnak.datavalue.value.text
end
end
end
end
if label == nil or label == "" then return nil end
return label
end
return getValue(errorOrentity, claims, propertyID, ", ", labelHook);
end
-- This is used to get a value, or a comma separated list of them if multiple values exist
-- from an arbitrary entry by using its QID.
-- Use : {{#invoke:Wikidata|getValueFromID|<ID>|<Property>|FETCH_WIKIDATA}}
-- E.g.: {{#invoke:Wikidata|getValueFromID|Q151973|P26|FETCH_WIKIDATA}} - to fetch value of 'spouse' (P26) from 'Richard Burton' (Q151973)
-- Please use sparingly - this is an *expensive call*.
p.getValueFromID = function(frame)
local itemID = mw.text.trim(frame.args[1] or "")
local propertyID = mw.text.trim(frame.args[2] or "")
local input_parm = mw.text.trim(frame.args[3] or "")
if input_parm == "FETCH_WIKIDATA" then
local entity = mw.wikibase.getEntity(itemID)
local claims
if entity and entity.claims then
claims = entity.claims[propertyID]
end
if claims then
return getValue(entity, claims, propertyID, ", ")
else
return ""
end
else
return input_parm
end
end
local function getQualifier(frame, outputHook)
local propertyID = mw.text.trim(frame.args[1] or "")
local qualifierID = mw.text.trim(frame.args[2] or "")
local input_parm = mw.text.trim(frame.args[3] or "")
if input_parm == "FETCH_WIKIDATA" then
local entity = mw.wikibase.getEntity()
if entity.claims[propertyID] ~= nil then
local out = {}
for k, v in pairs(entity.claims[propertyID]) do
for k2, v2 in pairs(v.qualifiers[qualifierID]) do
if v2.snaktype == 'value' then
out[#out + 1] = outputHook(v2);
end
end
end
return table.concat(out, ", "), true
else
return "", false
end
else
return input_parm, false
end
end
p.getQualifierValue = function(frame)
local function outputValue(value)
local qnumber = "Q" .. value.datavalue.value["numeric-id"]
if (mw.wikibase.getSitelink(qnumber)) then
return "[[" .. mw.wikibase.getSitelink(qnumber) .. "]]"
else
return "[[:d:" .. qnumber .. "|" ..qnumber .. "]]<abbr title='" .. i18n["errors"]["local-article-not-found"] .. "'>[*]</abbr>"
end
end
return (getQualifier(frame, outputValue))
end
-- This is used to get a value like 'male' (for property p21) which won't be linked and numbers without the thousand separators
p.getRawValue = function(frame)
local go, errorOrentity, claims, propertyID = parseInput(frame)
if not go then
return errorOrentity
end
local entity = errorOrentity
local result = entity:formatPropertyValues(propertyID, mw.wikibase.entity.claimRanks).value
-- if number type: remove thousand separators, bounds and units
if isType(claims, "quantity") then
result = mw.ustring.gsub(result, "(%d),(%d)", "%1%2")
result = mw.ustring.gsub(result, "(%d)±.*", "%1")
end
return result
end
-- This is used to get the unit name for the numeric value returned by getRawValue
p.getUnits = function(frame)
local go, errorOrentity, claims, propertyID = parseInput(frame)
if not go then
return errorOrentity
end
local entity = errorOrentity
local result = entity:formatPropertyValues(propertyID, mw.wikibase.entity.claimRanks).value
if isType(claims, "quantity") then
result = mw.ustring.sub(result, mw.ustring.find(result, " ")+1, -1)
end
return result
end
-- This is used to get the unit's QID to use with the numeric value returned by getRawValue
p.getUnitID = function(frame)
local go, errorOrentity, claims = parseInput(frame)
if not go then
return errorOrentity
end
local entity = errorOrentity
local result
if isType(claims, "quantity") then
-- get the url for the unit entry on Wikidata:
result = claims[1].mainsnak.datavalue.value.unit
-- and just reurn the last bit from "Q" to the end (which is the QID):
result = mw.ustring.sub(result, mw.ustring.find(result, "Q"), -1)
end
return result
end
p.getRawQualifierValue = function(frame)
local function outputHook(value)
if value.datavalue.value["numeric-id"] then
return mw.wikibase.getLabel("Q" .. value.datavalue.value["numeric-id"])
else
return value.datavalue.value
end
end
local ret, gotData = getQualifier(frame, outputHook)
if gotData then
ret = string.upper(string.sub(ret, 1, 1)) .. string.sub(ret, 2)
end
return ret
end
-- This is used to get a date value for date_of_birth (P569), etc. which won't be linked
-- Dates and times are stored in ISO 8601 format (sort of).
-- At present the local formatDate(date, precision, timezone) function doesn't handle timezone
-- So I'll just supply "Z" in the call to formatDate below:
p.getDateValue = function(frame)
local date_format = mw.text.trim(frame.args[3] or i18n["datetime"]["default-format"])
local date_addon = mw.text.trim(frame.args[4] or i18n["datetime"]["default-addon"])
local go, errorOrentity, claims = parseInput(frame)
if not go then
return errorOrentity
end
local entity = errorOrentity
local out = {}
for k, v in pairs(claims) do
if v.mainsnak.datavalue.type == 'time' then
local timestamp = v.mainsnak.datavalue.value.time
local dateprecision = v.mainsnak.datavalue.value.precision
-- A year can be stored like this: "+1872-00-00T00:00:00Z",
-- which is processed here as if it were the day before "+1872-01-01T00:00:00Z",
-- and that's the last day of 1871, so the year is wrong.
-- So fix the month 0, day 0 timestamp to become 1 January instead:
timestamp = timestamp:gsub("%-00%-00T", "-01-01T")
out[#out + 1] = parseDateFull(timestamp, dateprecision, date_format, date_addon)
end
end
return table.concat(out, ", ")
end
p.getQualifierDateValue = function(frame)
local date_format = mw.text.trim(frame.args[4] or i18n["datetime"]["default-format"])
local date_addon = mw.text.trim(frame.args[5] or i18n["datetime"]["default-addon"])
local function outputHook(value)
local timestamp = value.datavalue.value.time
return parseDateValue(timestamp, date_format, date_addon)
end
return (getQualifier(frame, outputHook))
end
-- This is used to fetch all of the images with a particular property, e.g. image (P18), Gene Atlas Image (P692), etc.
-- Parameters are | propertyID | value / FETCH_WIKIDATA / nil | separator (default=space) | size (default=frameless)
-- It will return a standard wiki-markup [[File:Filename | size]] for each image with a selectable size and separator (which may be html)
-- e.g. {{#invoke:Wikidata|getImages|P18|FETCH_WIKIDATA}}
-- e.g. {{#invoke:Wikidata|getImages|P18|FETCH_WIKIDATA|<br>|250px}}
-- If a property is chosen that is not of type "commonsMedia", it will return empty text.
p.getImages = function(frame)
local sep = mw.text.trim(frame.args[3] or " ")
local imgsize = mw.text.trim(frame.args[4] or "frameless")
local go, errorOrentity, claims = parseInput(frame)
if not go then
return errorOrentity
end
local entity = errorOrentity
if (claims[1] and claims[1].mainsnak.datatype == "commonsMedia") then
local out = {}
for k, v in pairs(claims) do
local filename = v.mainsnak.datavalue.value
out[#out + 1] = "[[File:" .. filename .. "|" .. imgsize .. "]]"
end
return table.concat(out, sep)
else
return ""
end
end
-- This is used to get the TA98 (Terminologia Anatomica first edition 1998) values like 'A01.1.00.005' (property P1323)
-- which are then linked to https://ifaa.unifr.ch/Public/EntryPage/TA98%20Tree/Entity%20TA98%20EN/01.1.00.005%20Entity%20TA98%20EN.htm
-- uses the newer mw.wikibase calls instead of directly using the snaks
-- formatPropertyValues returns a table with the P1323 values concatenated with ", " so we have to split them out into a table in order to construct the return string
p.getTAValue = function(frame)
local ent = mw.wikibase.getEntity()
local props = ent:formatPropertyValues('P1323')
local out = {}
local t = {}
for k, v in pairs(props) do
if k == 'value' then
t = mw.text.split( v, ", ")
for k2, v2 in pairs(t) do
out[#out + 1] = "[https://ifaa.unifr.ch/Public/EntryPage/TA98%20Tree/Entity%20TA98%20EN/" .. string.sub(v2, 2) .. "%20Entity%20TA98%20EN.htm " .. v2 .. "]"
end
end
end
local ret = table.concat(out, "<br> ")
if #ret == 0 then
ret = "Invalid TA"
end
return ret
end
--[[
This is used to return an image legend from Wikidata
image is property P18
image legend is property P2096
Call as {{#invoke:Wikidata |getImageLegend | <PARAMETER> | lang=<ISO-639code> |id=<QID>}}
Returns PARAMETER, unless it is equal to "FETCH_WIKIDATA", from Item QID (expensive call)
If QID is omitted or blank, the current article is used (not an expensive call)
If lang is omitted, it uses the local wiki language, otherwise it uses the provided ISO-639 language code
ISO-639: https://docs.oracle.com/cd/E13214_01/wli/docs92/xref/xqisocodes.html#wp1252447
Ranks are: 'preferred' > 'normal'
This returns the label from the first image with 'preferred' rank
Or the label from the first image with 'normal' rank if preferred returns nothing
Ranks: https://www.mediawiki.org/wiki/Extension:Wikibase_Client/Lua
]]
p.getImageLegend = function(frame)
-- look for named parameter id; if it's blank make it nil
local id = frame.args.id
if id and (#id == 0) then
id = nil
end
-- look for named parameter lang
-- it should contain a two-character ISO-639 language code
-- if it's blank fetch the language of the local wiki
local lang = frame.args.lang
if (not lang) or (#lang < 2) then
lang = mw.language.getContentLanguage().code
end
-- first unnamed parameter is the local parameter, if supplied
local input_parm = mw.text.trim(frame.args[1] or "")
if input_parm == "FETCH_WIKIDATA" then
local ent = mw.wikibase.getEntity(id)
local imgs
if ent and ent.claims then
imgs = ent.claims.P18
end
local imglbl
if imgs then
-- look for an image with 'preferred' rank
for k1, v1 in pairs(imgs) do
if v1.rank == "preferred" and v1.qualifiers and v1.qualifiers.P2096 then
local imglbls = v1.qualifiers.P2096
for k2, v2 in pairs(imglbls) do
if v2.datavalue.value.language == lang then
imglbl = v2.datavalue.value.text
break
end
end
end
end
-- if we don't find one, look for an image with 'normal' rank
if (not imglbl) then
for k1, v1 in pairs(imgs) do
if v1.rank == "normal" and v1.qualifiers and v1.qualifiers.P2096 then
local imglbls = v1.qualifiers.P2096
for k2, v2 in pairs(imglbls) do
if v2.datavalue.value.language == lang then
imglbl = v2.datavalue.value.text
break
end
end
end
end
end
end
return imglbl
else
return input_parm
end
end
-- This is used to get the QIDs of all of the values of a property, as a comma separated list if multiple values exist
-- Usage: {{#invoke:Wikidata |getPropertyIDs |<PropertyID> |FETCH_WIKIDATA}}
-- Usage: {{#invoke:Wikidata |getPropertyIDs |<PropertyID> |<InputParameter> |qid=<QID>}}
p.getPropertyIDs = function(frame)
local go, errorOrentity, propclaims = parseInput(frame)
if not go then
return errorOrentity
end
local entity = errorOrentity
-- if wiki-linked value collect the QID in a table
if (propclaims[1] and propclaims[1].mainsnak.snaktype == "value" and propclaims[1].mainsnak.datavalue.type == "wikibase-entityid") then
local out = {}
for k, v in pairs(propclaims) do
out[#out + 1] = "Q" .. v.mainsnak.datavalue.value["numeric-id"]
end
return table.concat(out, ", ")
else
-- not a wikibase-entityid, so return empty
return ""
end
end
-- returns the page id (Q...) of the current page or nothing of the page is not connected to Wikidata
function p.pageId(frame)
return mw.wikibase.getEntityIdForCurrentPage()
end
function p.claim(frame)
local property = frame.args[1] or ""
local id = frame.args["id"]
local qualifierId = frame.args["qualifier"]
local parameter = frame.args["parameter"]
local list = frame.args["list"]
local references = frame.args["references"]
local showerrors = frame.args["showerrors"]
local default = frame.args["default"]
if default then showerrors = nil end
-- get wikidata entity
local entity = mw.wikibase.getEntity(id)
if not entity then
if showerrors then return printError("entity-not-found") else return default end
end
-- fetch the first claim of satisfying the given property
local claims = findClaims(entity, property)
if not claims or not claims[1] then
if showerrors then return printError("property-not-found") else return default end
end
-- get initial sort indices
local sortindices = {}
for idx in pairs(claims) do
sortindices[#sortindices + 1] = idx
end
-- sort by claim rank
local comparator = function(a, b)
local rankmap = { deprecated = 2, normal = 1, preferred = 0 }
local ranka = rankmap[claims[a].rank or "normal"] .. string.format("%08d", a)
local rankb = rankmap[claims[b].rank or "normal"] .. string.format("%08d", b)
return ranka < rankb
end
table.sort(sortindices, comparator)
local result
local error
if list then
local value
-- iterate over all elements and return their value (if existing)
result = {}
for idx in pairs(claims) do
local claim = claims[sortindices[idx]]
value, error = getValueOfClaim(claim, qualifierId, parameter)
if not value and showerrors then value = error end
if value and references then value = value .. getReferences(frame, claim) end
result[#result + 1] = value
end
result = table.concat(result, list)
else
-- return first element
local claim = claims[sortindices[1]]
result, error = getValueOfClaim(claim, qualifierId, parameter)
if result and references then result = result .. getReferences(frame, claim) end
end
if result then return result else
if showerrors then return error else return default end
end
end
-- look into entity object
function p.ViewSomething(frame)
local f = (frame.args[1] or frame.args.id) and frame or frame:getParent()
local id = f.args.id
if id and (#id == 0) then
id = nil
end
local data = mw.wikibase.getEntity(id)
if not data then
return nil
end
local i = 1
while true do
local index = f.args[i]
if not index then
if type(data) == "table" then
return mw.text.jsonEncode(data, mw.text.JSON_PRESERVE_KEYS + mw.text.JSON_PRETTY)
else
return tostring(data)
end
end
data = data[index] or data[tonumber(index)]
if not data then
return
end
i = i + 1
end
end
-- getting sitelink of a given wiki
-- get sitelink of current item if qid not supplied
function p.getSiteLink(frame)
local qid = frame.args.qid
if qid == "" then qid = nil end
local f = mw.text.trim( frame.args[1] or "")
local entity = mw.wikibase.getEntity(qid)
if not entity then
return
end
local link = entity:getSitelink( f )
if not link then
return
end
return link
end
function p.Dump(frame)
local f = (frame.args[1] or frame.args.id) and frame or frame:getParent()
local data = mw.wikibase.getEntity(f.args.id)
if not data then
return i18n.warnDump
end
local i = 1
while true do
local index = f.args[i]
if not index then
return "<pre>"..mw.dumpObject(data).."</pre>".. i18n.warnDump
end
data = data[index] or data[tonumber(index)]
if not data then
return i18n.warnDump
end
i = i + 1
end
end
return p
0ut9ea611aebtqxr1j5hmyqvjdhhyh8
159005
159004
2026-10-10T16:47:41Z
Rachmat04
7338
Membatalkan [[Special:Diff/159004|suntingan]] oleh Rachmat04 · [[w:id:Pengguna:Rachmat04/Tengu.js|⛩️]]
159005
Scribunto
text/plain
-- version 20200701 from master @cawiki
local p = {}
-- Initialization of variables --------------------
local i18n = { -- internationalisation at [[Module:Wikidata/i18n]]
["errors"] = {
["property-not-found"] = "Property not found.",
["qualifier-not-found"] = "Qualifier not found.",
},
["datetime"] = {
-- $1 is a placeholder for the actual number
["beforenow"] = "$1 BCE", -- how to format negative numbers for precisions 0 to 5
["afternow"] = "$1 CE", -- how to format positive numbers for precisions 0 to 5
["bc"] = "$1 BCE", -- how print negative years
["ad"] = "$1", -- how print 1st century AD dates
[0] = "$1 billion years", -- precision: billion years
[1] = "$100 million years", -- precision: hundred million years
[2] = "$10 million years", -- precision: ten million years
[3] = "$1 million years", -- precision: million years
[4] = "$100000 years", -- precision: hundred thousand years; thousand separators added afterwards
[5] = "$10000 years", -- precision: ten thousand years; thousand separators added afterwards
[6] = "$1 millennium", -- precision: millennium
[7] = "$1 century", -- precision: century
[8] = "$1s", -- precision: decade
-- the following use the format of #time parser function
[9] = "Y", -- precision: year,
[10] = "F Y", -- precision: month
[11] = "F j, Y", -- precision: day
["hms"] = {["hours"] = "h", ["minutes"] = "m", ["seconds"] = "s"}, -- duration: xh xm xs
},
["years-old"] = {
["singular"] = "", -- year old, as in {{PLURAL:$1|singular|plural}}
["plural"] = "", -- years old
["paucal"] = "", -- for languages with 3 plural forms as in {{PLURAL:$1|singular|paucal|plural}}
},
["cite"] = { -- cite parameters
["title"] = "title",
["author"] = "author",
["date"] = "date",
["pages"] = "pages",
["language"] = "language",
-- cite web parameters
["url"] = "url",
["website"] = "website",
["access-date"] = "access-date",
["archive-url"] = "archive-url",
["archive-date"] = "archive-date",
["publisher"] = "publisher",
["quote"] = "quote",
-- cite journal parameters
["work"] = "work",
["issue"] = "issue",
["issn"] = "issn",
["doi"] = "doi"
},
-- local wiki settings
["addpencil"] = false, -- adds a pencil icon linked to Wikidata statement, planned to overwrite by Wikidata Bridge
["categorylabels"] = "", -- Category:Pages with Wikidata labels not translated (void for no local category)
["addfallback"] = {} -- additional fallback language codes
}
local cases = {} -- functions for local grammatical cases defined at [[Module:Wikidata/i18n]]
local required = ... -- variadic arguments from require function
local wiki =
{
langcode = mw.language.getContentLanguage().code,
module_title = required or mw.getCurrentFrame():getTitle()
}
local untranslated -- used in infobox modules: nil or true
local _ -- variable for unused returned values, avoiding globals
-- Module local functions --------------------------------------------
-- Credit to http://stackoverflow.com/a/1283608/2644759, cc-by-sa 3.0
local function tableMerge(t1, t2)
for k, v in pairs(t2) do
if type(v) == "table" then
if type(t1[k] or false) == "table" then
tableMerge(t1[k] or {}, t2[k] or {})
else
t1[k] = v
end
else
t1[k] = v
end
end
return t1
end
local function loadI18n(lang)
local exist, res = pcall(require, wiki.module_title .. "/i18n")
if exist and next(res) ~= nil then
tableMerge(i18n, res.i18n)
cases = res.cases
end
if lang ~= wiki.langcode then
exist, res = pcall(require, wiki.module_title .. "/i18n/" .. lang)
if exist and next(res) ~= nil then
tableMerge(i18n, res.i18n)
tableMerge(cases, res.cases)
end
end
end
-- Table of language codes: requested or default and its fallbacks
local function findLang(langcode)
if mw.language.isKnownLanguageTag(langcode or '') == false then
local cframe = mw.getCurrentFrame()
local pframe = cframe:getParent()
langcode = pframe and pframe.args.lang
if mw.language.isKnownLanguageTag(langcode or '') == false then
if not mw.title.getCurrentTitle().isContentPage then
langcode = cframe:preprocess('{{int:lang}}')
end
if mw.language.isKnownLanguageTag(langcode or '') == false then
langcode = wiki.langcode
end
end
end
loadI18n(langcode)
local languages = mw.language.getFallbacksFor(langcode)
table.insert(languages, 1, langcode)
if langcode == wiki.langcode then
for _, l in ipairs(i18n.addfallback) do
table.insert(languages, l)
end
end
return languages
end
-- Argument is 'set' when it exists (not nil) or when it is not an empty string.
local function isSet(var)
return not (not var or var == '')
end
-- Set local case to a label
local function case(localcase, label, ...)
if not isSet(label) then return label end
if localcase == "smallcaps" then
return '<span style="font-variant: small-caps;">' .. label .. '</span>'
elseif cases[localcase] then
return cases[localcase](label, ...)
end
return label
end
-- get safely a serialized snak
local function getSnak(statement, snaks)
local ret = statement
for i, v in ipairs(snaks) do
if not ret then return end
ret = ret[v]
end
return ret
end
-- mw.wikibase.getLabelWithLang or getLabelByLang with a table of languages
local function getLabelByLangs(id, languages)
local label
local lang
for _, l in ipairs(languages) do
if l == wiki.langcode then
-- using getLabelWithLang when possible instead of getLabelByLang, do not solve redirects pending phab:T157868
label, l = mw.wikibase.getLabelWithLang(id)
else
label = mw.wikibase.getLabelByLang(id, l)
end
if label then
lang = l
break
end
end
return label, lang
end
-- getBestStatements if bestrank=true, else getAllStatements with no deprecated
local function getStatements(entityId, property, bestrank)
local claims = {}
if not (entityId and mw.ustring.match(property, "^P%d+$")) then return claims end
if bestrank then
claims = mw.wikibase.getBestStatements(entityId, property)
else
local allclaims = mw.wikibase.getAllStatements(entityId, property)
for _, c in ipairs(allclaims) do
if c.rank ~= "deprecated" then
table.insert(claims, c)
end
end
end
return claims
end
-- Is gender femenine? true or false
local function feminineGender(id)
local claims = mw.wikibase.getBestStatements(id or mw.wikibase.getEntityIdForCurrentPage(),'P21')
if getSnak(claims, {1, "mainsnak", "datavalue"}) == nil then -- no claim, novalue or somevalue
return false
else
local genderId = claims[1].mainsnak.datavalue.value.id
if genderId == "Q6581072" or genderId == "Q1052281" or genderId == "Q43445" then -- female, transgender female, female organism
return true
end
end
return false
end
-- Fetch female form of label
local function feminineForm(id, lang)
local feminine_claims = getStatements(id, 'P2521')
for _, feminine_claim in ipairs(feminine_claims) do
if getSnak(feminine_claim, {'mainsnak', 'datavalue', 'value', 'language'}) == lang then
return feminine_claim.mainsnak.datavalue.value.text
end
end
end
-- Add an icon for no label in requested language
local function addLabelIcon(label_id, lang, uselang, icon)
local ret_lang, ret_icon = '', ''
if icon then
if lang and lang ~= uselang then
ret_lang = " <sup>(" .. lang .. ")</sup>"
end
if label_id and (lang == nil or lang ~= uselang) then
ret_icon = " [[File:OOjs_UI_icon_tag-rtl-progressive.svg|10px|baseline|"
.. mw.message.new('Translate-taction-translate'):inLanguage(uselang):plain()
.. "|link=https://www.wikidata.org/wiki/Special:EntityPage/" .. label_id .. "?uselang=" .. uselang .. "]]"
untranslated = true
end
if isSet(i18n.categorylabels) and lang ~= uselang and uselang == wiki.langcode then
ret_icon = ret_icon .. '[[' .. i18n.categorylabels .. (lang and ']]' or '/Q]]')
end
end
return ret_lang .. ret_icon
end
-- editicon values: true/false (no=false), right, void defaults to i18n.addpencil
local function setEditIcon(param)
if not isSet(param) then return i18n.addpencil end
if param == "false" or param == "no" then return false end
return param
end
-- Add an icon for editing a statement with requirements for Wikidata Bridge
local function addEditIcon(parameters)
local ret = ''
if parameters.editicon and parameters.id and parameters.property then
local icon_style = parameters.editicon == "right" and ' style="float: right;"' or ''
ret = ' <span class="penicon" data-bridge-edit-flow="single-best-value"' .. icon_style .. '>'
.. "[[File:OOjs UI icon edit-ltr-progressive.svg|10px|baseline|"
.. string.gsub(mw.message.new('Wikibase-client-data-bridge-bailout-suggestion-go-to-repo-button'):inLanguage(parameters.lang[1]):plain(), '{{WBREPONAME}}', 'Wikidata')
.. "|link=https://www.wikidata.org/wiki/" .. parameters.id .. "?uselang=" .. parameters.lang[1] .. "#" .. parameters.property .. "]]"
.. "</span>"
end
return ret
end
-- add edit icon to the last element of a table
local function addEditIconTable(thetable, parameters)
if #thetable == 0 or parameters.editicon == false then
return thetable
end
local last_element = thetable[#thetable]
local the_icon = addEditIcon(parameters)
-- add it before last html closing tags
local tags = ''
local rev_element = string.reverse(last_element)
for tag in string.gmatch(rev_element, '(>%l+/<)') do
if string.match(rev_element, '^' .. tags .. tag) then
tags = tags .. tag
else
break
end
end
local last_tags = string.reverse(tags)
local offset = string.find(last_element, last_tags .. '$')
if offset then
thetable[#thetable] = string.sub(last_element, 1, offset - 1) .. the_icon .. last_tags
else
thetable[#thetable] = last_element .. the_icon
end
return thetable
end
-- Escape Lua captures
local function captureEscapes(text)
return mw.ustring.gsub(text, "(%%%d)", "%%%1")
end
-- expandTemplate or callParserFunction
local function expandBraces(text, formatting)
if text == nil or formatting == nil then return text end
-- only expand braces if provided in argument, not included in value as in Q1164668
if mw.ustring.find(formatting, '{{', 1, true) == nil then return text end
if type(text) ~= "string" then
text = tostring(text)
end
for braces in mw.ustring.gmatch(text, "{{(.-)}}") do
local parts = mw.text.split(braces, "|")
local title_part = parts[1]
local parameters = {}
for i = 2, #parts do
local subparts = mw.ustring.find(parts[i], "=")
if subparts then
parameters[mw.ustring.sub(parts[i], 1, subparts-1)] = mw.ustring.sub(parts[i], subparts+1, -1)
else
table.insert(parameters, parts[i])
end
end
local braces_expanded
if mw.ustring.find(title_part, ":")
and mw.text.split(title_part, ":")[1] ~= mw.site.namespaces[10].name -- not a prefix Template:
then
braces_expanded = mw.getCurrentFrame():callParserFunction{name=title_part, args=parameters}
else
braces_expanded = mw.getCurrentFrame():expandTemplate{title=title_part, args=parameters}
end
braces = mw.ustring.gsub(braces, "([%^%$%(%)%%%.%[%]%*%+%-%?])", "%%%1") -- escape magic characters
braces_expanded = captureEscapes(braces_expanded)
text = mw.ustring.gsub(text, "{{" .. braces .. "}}", braces_expanded)
end
return text
end
-- Resolve Wikidata redirects, pending phab:T157868
local function resolveEntityId(id)
if not id or not mw.wikibase.isValidEntityId(id) then return id end
-- if no label in English, maybe it is a redirect
-- not using mw.title.new(id).isRedirect as it is expensive
-- currently getLabelByLang does not follows redirects
if mw.wikibase.getLabelByLang(id, 'en') == nil then
local entity = mw.wikibase.getEntity(id) -- expensive function
if not entity then return nil end
if id ~= entity.id then
-- Qid redirected to be fixed
-- see [[Special:WhatLinksHere/Template:Track/wikidata/redirect]]
require(wiki.module_title .. '/debug').track('redirect')
require(wiki.module_title .. '/debug').track('redirect/' .. id)
else
-- no redirect and no English label, fix it to avoid expensive functions
require(wiki.module_title .. '/debug').track('label')
require(wiki.module_title .. '/debug').track('label/' .. id)
end
return entity.id
end
return id
end
-- format data type math
local function printDatatypeMath(data)
return mw.getCurrentFrame():callParserFunction('#tag:math', data)
end
-- format data type musical-notation
local function printDatatypeMusical(data, formatting)
local attr = {}
if formatting == 'sound' then
attr.sound = 1
end
return mw.getCurrentFrame():extensionTag('score', data, attr)
end
-- format data type string
local function printDatatypeString(data, parameters)
if mw.ustring.find((parameters.formatting or ''), '$1', 1, true) then -- formatting = a pattern
return expandBraces(mw.ustring.gsub(parameters.formatting, '$1', {['$1'] = data}), parameters.formatting)
elseif parameters.case then
return case(parameters.case, data, parameters.lang[1])
end
local data_number = string.match(data, "^%d+")
if data_number then -- sort key by initial number and remaining string
local sortkey = string.format("%019d", data_number * 1000)
return data, sortkey .. string.sub(data, #data_number + 1)
end
return data
end
-- format data type url
local function printDatatypeUrl(data, parameters)
if parameters.formatting == 'weblink' then
local label_parts = mw.text.split(string.gsub(data, '/$', ''), '/')
local label = string.gsub(label_parts[3], '^www%.', '')
if #label_parts > 3 then
label = label .. '…'
end
return '[' .. data .. ' ' .. label .. ']'
end
return printDatatypeString(data, parameters)
end
-- format data type external-id
local function printDatatypeExternal(data, parameters)
if parameters.formatting == 'externalid' then
local p_stat = mw.wikibase.getBestStatements(parameters.property, 'P1630') -- formatter URL
local p_link_pattern = getSnak(p_stat, {1, "mainsnak", "datavalue", "value"})
if p_link_pattern then
local p_link = mw.ustring.gsub(p_link_pattern, '$1', {['$1'] = data})
return '[' .. p_link .. ' ' .. data .. ']'
end
end
return printDatatypeString(data, parameters)
end
-- format data type commonsMedia
local function printDatatypeMedia(data, parameters)
local icon
if not string.find((parameters.formatting or ''), '$1', 1, true) then
icon = "no-icon"
end
return printDatatypeString(data, parameters), icon
end
-- format data type globe-coordinate
local function printDatatypeCoordinate(data, formatting)
local function globes(globe_id)
local globes = {['Q3134']='callisto',['Q596']='ceres',['Q15040']='dione',['Q2']='earth',['Q3303']='enceladus',
['Q3143']='europa',['Q17975']='phoebe',['Q3169']='ganymede',['Q3123']='io',['Q17958']='iapetus',
['Q308']='mercury',['Q15034']='mimas',['Q405']='moon',['Q15050']='rhea',['Q15047']='tethys',
['Q111']='mars',['Q2565']='titan',['Q3359']='triton',['Q313']='venus',['Q3030']='vesta'}
return globes[globe_id]
end
local function roundPrecision(num, prec)
if prec == nil or prec <= 0 then return num end
local sig = 10^math.floor(math.log10(prec)+.5) -- significant figure from sexagesimal precision: 0.00123 -> 0.001
return math.floor(num / sig + 0.5) * sig
end
local precision = data.precision
local latitude = roundPrecision(data.latitude, precision)
local longitude = roundPrecision(data.longitude, precision)
if formatting and string.find(formatting, '$lat', 1, true) and string.find(formatting, '$lon', 1, true) then
local ret = mw.ustring.gsub(formatting, '$l[ao][tn]', {['$lat'] = latitude, ['$lon'] = longitude})
if string.find(formatting, '$globe', 1, true) then
local myglobe = 'earth'
if isSet(data.globe) then
local globenum = mw.text.split(data.globe, 'entity/')[2] -- http://www.wikidata.org/wiki/Q2
myglobe = globes(globenum) or 'earth'
end
ret = mw.ustring.gsub(ret, '$globe', myglobe)
end
return expandBraces(ret, formatting)
elseif formatting == 'latitude' then
return latitude, "no-icon"
elseif formatting == 'longitude' then
return longitude, "no-icon"
elseif formatting == 'dimension' then
return data.dimension, "no-icon"
else --default formatting='globe'
if isSet(data.globe) == false or data.globe == 'http://www.wikidata.org/entity/Q2' then
return 'earth', "no-icon"
else
local globenum = mw.text.split(data.globe, 'entity/')[2]
return globes(globenum) or globenum, "no-icon"
end
end
end
-- Local functions for data value quantity
local function unitSymbol(id, lang) -- get unit symbol or code
local unit_symbol = ''
if lang == wiki.langcode and pcall(require, wiki.module_title .. "/Units") then
unit_symbol = require(wiki.module_title .. "/Units").getUnit(0, '', id, true)
end
if unit_symbol == '' then
-- fetch it
local claims = mw.wikibase.getBestStatements(id, 'P5061')
if #claims > 0 then
local langclaims = {}
table.insert(lang, 'mul') -- multilingual as last try
for _, snak in ipairs(claims) do
local snak_language = getSnak(snak, {"mainsnak", "datavalue", "value", "language"})
if snak_language and not langclaims[snak_language] then -- just the first one by language
langclaims[snak_language] = snak.mainsnak.datavalue.value.text
end
end
for _, l in ipairs(lang) do
if langclaims[l] then
return langclaims[l]
end
end
end
end
return unit_symbol
end
local function getUnit(amount, id, parameters) -- get unit symbol or name
local suffix = ''
if parameters.formatting == "unitcode" then
-- get unit symbol
local unit_symbol = unitSymbol(id, parameters.lang)
if isSet(unit_symbol) then
suffix = unit_symbol
end
end
if suffix == '' then -- formatting=unit, or formatting=unitcode not found
-- get unit name
local unit_label, lang = getLabelByLangs(id, parameters.lang)
if lang == wiki.langcode and pcall(require, wiki.module_title .. "/Units") then
suffix = require(wiki.module_title .. "/Units").getUnit(amount, unit_label, id, false)
else
suffix = (unit_label or id) .. addLabelIcon(id, lang, parameters.lang[1], parameters.editicon)
end
end
if suffix ~= '' then
suffix = ' ' .. suffix
end
return suffix
end
local function roundDefPrecision(in_num, factor)
-- rounds out_num with significant figures of in_num (default precision)
local out_num = in_num * factor
if factor/60 == math.floor(factor/60) then -- sexagesimal integer
return out_num
end
-- first, count digits after decimal mark, handling cases like '12.345e6'
local exponent, prec
local integer, dot, decimals, expstr = in_num:match('^(%d*)(%.?)(%d*)(.*)')
local e = expstr:sub(1, 1)
if e == 'e' or e == 'E' then
exponent = tonumber(expstr:sub(2))
end
if dot == '' then
prec = -integer:match('0*$'):len()
else
prec = #decimals
end
if exponent then
-- So '1230' and '1.23e3' both give prec = -1, and '0.00123' and '1.23e-3' give 5.
prec = prec - exponent
end
-- significant figures
local in_bracket = 10^-prec -- -1 -> 10, 5 -> 0.00001
local out_bracket = in_bracket * out_num / in_num
out_bracket = 10^math.floor(math.log10(out_bracket)+.5) -- 1230 -> 1000, 0.00123 -> 0.001
-- round it (credit to Luc Bloom from http://lua-users.org/wiki/SimpleRound)
return math.floor(out_num/out_bracket + (out_num >=0 and 1 or -1) * 0.5) * out_bracket
end
-- format data type quantity
local function printDatatypeQuantity(data, parameters)
local amount = data.amount
amount = mw.ustring.gsub(amount, "%+", "")
local suffix = ""
local conv_amount, conv_suffix
if string.sub(parameters.formatting or '', 1, 4) == "unit" or string.sub(parameters.formatting or '', 1, 8) == "duration" or parameters.convert then
local unit_id = data.unit
unit_id = mw.ustring.sub(unit_id, mw.ustring.find(unit_id, "Q"), -1)
if string.sub(unit_id, 1, 1) == "Q" then
suffix = getUnit(amount, unit_id, parameters)
local convert_to
if parameters.convert == "default" or parameters.convert == "default2" then
local exist, units = pcall(require, wiki.module_title .. "/Units")
if exist and next(units.convert_default) ~= nil then
convert_to = units.convert_default[unit_id]
end
elseif string.sub(parameters.convert or '', 1, 1) == "Q" then
convert_to = resolveEntityId(parameters.convert)
elseif string.sub(parameters.formatting or '', 1, 8) == "duration" then
convert_to = 'Q11574' -- seconds
end
if convert_to and convert_to ~= unit_id then
-- convert units
local conv_temp = { -- formulae for temperatures ºC, ºF, ªK: [from] = {[to] = 'formula'}
['Q25267'] = {['Q42289'] = '$1*1.8+32', ['Q11597'] = '$1+273.15'},
['Q42289'] = {['Q25267'] = '($1-32)/1.8', ['Q11597'] = '($1+459.67)*5/9'},
['Q11597'] = {['Q25267'] = '$1-273.15', ['Q42289'] = '($1-273.15)*1.8000+32.00'}
}
if conv_temp[unit_id] and conv_temp[unit_id][convert_to] then
local amount_f = mw.getCurrentFrame():callParserFunction('#expr', mw.ustring.gsub(conv_temp[unit_id][convert_to], "$1", amount))
conv_amount = math.floor(tonumber(amount_f) + 0.5)
else
local conversions = getStatements(unit_id, 'P2442') -- conversion to standard unit
table.insert(conversions, mw.wikibase.getBestStatements(unit_id, 'P2370')[1]) -- conversion to SI unit
for _, conv in ipairs(conversions) do
if conv.mainsnak.snaktype == 'value' then -- no somevalue nor novalue
if conv.mainsnak.datavalue.value.unit == "http://www.wikidata.org/entity/" .. convert_to then
conv_amount = roundDefPrecision(amount, tonumber(conv.mainsnak.datavalue.value.amount))
break
end
end
end
end
if conv_amount then
conv_suffix = getUnit(conv_amount, convert_to, parameters)
end
elseif parameters.convert == 'M' and tonumber(amount) > 10^8 then
conv_amount = math.floor(amount/10^6 + 0.5)
conv_suffix = ' M' .. string.sub(suffix, 2)
end
end
end
local lang_obj = mw.language.new(parameters.lang[1])
local sortkey = string.format("%019d", tonumber(amount) * 1000)
if string.sub(parameters.formatting or '', 1, 8) == "duration" then
local sec = tonumber(conv_amount or amount)
if parameters.formatting == 'durationhms' or parameters.formatting == 'durationh:m:s' then
local intervals = {"hours", "minutes", "seconds"}
local sec2table = lang_obj:getDurationIntervals(sec, intervals)
sec2table["seconds"] = (sec2table["seconds"] or 0) + tonumber("." .. (tostring(sec):match("%.(%d+)") or "0")) -- add decimals
local duration = ''
for i, v in ipairs(intervals) do
if parameters.formatting == 'durationh:m:s' then
if i == 1 and sec2table[v] then
duration = duration .. sec2table[v] .. ":"
elseif i == 2 then
duration = duration .. string.format("%02d", sec2table[v] or 0) .. ":"
elseif i == 3 then
local sec_str = tostring(lang_obj:formatNum(sec2table[v] or 0))
duration = duration .. (sec2table[v] < 10 and "0" or "") .. sec_str
end
elseif sec2table[v] then
duration = duration .. lang_obj:formatNum(sec2table[v]) .. i18n.datetime.hms[v] .. (i < 3 and " " or "")
end
end
return duration
else
return lang_obj:formatDuration(sec)
end
end
if parameters.case then
amount = case(parameters.case, amount, parameters.lang[1])
else
amount = lang_obj:formatNum(tonumber(amount))
end
if conv_amount then
local conv_sortkey = string.format("%019d", tonumber(conv_amount) * 1000)
conv_amount = lang_obj:formatNum(tonumber(conv_amount))
if parameters.convert == 'default2' then
return conv_amount .. conv_suffix .. ' (' .. amount .. suffix .. ')', conv_sortkey
else
return conv_amount .. conv_suffix, conv_sortkey
end
end
return amount .. suffix, sortkey
end
-- format data type time
local function printDatatypeTime(data, parameters)
-- Dates and times are stored in ISO 8601 format
local timestamp = data.time
local post_format
local calendar_add = ""
local precision = data.precision or 11
if string.sub(timestamp, 1, 1) == '-' then
post_format = i18n.datetime["bc"]
elseif string.sub(timestamp, 2, 3) == '00' then
post_format = i18n.datetime["ad"]
elseif precision > 8 then
-- calendar model
local calendar_model = {["Q12138"] = "gregorian", ["Q1985727"] = "gregorian", ["Q11184"] = "julian", ["Q1985786"] = "julian"}
local calendar_id = mw.text.split(data.calendarmodel, 'entity/')[2]
if (timestamp < "+1582-10-15T00:00:00Z" and calendar_model[calendar_id] == "gregorian")
or (timestamp > "+1582-10-04T00:00:00Z" and calendar_model[calendar_id] == "julian")
then
calendar_add = " <sup>(" .. mw.message.new('Wikibase-time-calendar-' .. calendar_model[calendar_id]):inLanguage(parameters.lang[1]):plain() .. ")</sup>"
end
end
local function formatTime(form, stamp)
local pattern
if type(form) == "function" then
pattern = form(stamp)
else
pattern = form
end
stamp = tostring(stamp)
if mw.ustring.find(pattern, "$1") then
return mw.ustring.gsub(pattern, "$1", stamp)
elseif string.sub(stamp, 1, 1) == '-' then -- formatDate() only supports years from 0
stamp = '+' .. string.sub(stamp, 2)
elseif string.sub(stamp, 1, 1) ~= '+' then -- not a valid timestamp, it is a number
stamp = string.format("%04d", stamp)
end
local ret = mw.language.new(parameters.lang[1]):formatDate(pattern, stamp)
ret = string.gsub(ret, "^(%[?%[?)0+", "%1") -- supress leading zeros
ret = string.gsub(ret, "( %[?%[?)0+", "%1")
return ret
end
local function postFormat(t)
if post_format and mw.ustring.find(post_format, "$1") then
return mw.ustring.gsub(post_format, "$1", t)
end
return t
end
local intyear = tonumber(string.match(timestamp, "[+-](%d+)"))
local ret = ""
if precision <= 5 then -- precision is 10000 years or more
local factor = 10 ^ ((5 - precision) + 4)
local y2 = math.ceil(math.abs(intyear) / factor)
local relative = formatTime(i18n.datetime[precision], y2)
if post_format == i18n.datetime["bc"] then
ret = mw.ustring.gsub(i18n.datetime.beforenow, "$1", relative)
else
ret = mw.ustring.gsub(i18n.datetime.afternow, "$1", relative)
end
local ret_number = string.match(ret, "%d+")
if ret_number ~= nil then
ret = mw.ustring.gsub(ret, ret_number, mw.language.new(parameters.lang[1]):formatNum(tonumber(ret_number)))
end
elseif precision == 6 or precision == 7 then -- millennia or centuries
local card = math.floor((intyear - 1) / 10^(9 - precision)) + 1
ret = formatTime(i18n.datetime[precision], card)
ret = postFormat(ret)
elseif precision == 8 then -- decades
local card = math.floor(math.abs(intyear) / 10) * 10
ret = formatTime(i18n.datetime[8], card)
ret = postFormat(ret)
elseif intyear > 9999 then -- not a valid timestamp
return
elseif precision == 9 or parameters.formatting == 'Y' then -- precision is year
ret = formatTime(i18n.datetime[9], intyear)
ret = postFormat(ret) .. calendar_add
elseif precision == 10 then -- month
ret = formatTime(i18n.datetime[10], timestamp .. " + 1 day") -- formatDate yyyy-mm-00 returns the previous month
ret = postFormat(ret) .. calendar_add
else -- precision 11, day
ret = formatTime(parameters.formatting or i18n.datetime[11], timestamp)
ret = postFormat(ret) .. calendar_add
end
return ret, timestamp
end
-- format data value wikibase-entityid: types wikibase-item, wikibase-property
local function printDatatypeEntity(data, parameters)
local entity_id = data['id']
if parameters.formatting == 'raw' then
return entity_id, entity_id
end
local entity_page = 'Special:EntityPage/' .. entity_id
local label, lang = getLabelByLangs(entity_id, parameters.lang)
local sitelink = mw.wikibase.getSitelink(entity_id)
local parameter = parameters.formatting
local labelcase = label or sitelink
if parameters.gender == 'feminineform' then
labelcase = feminineForm(entity_id, lang) or labelcase
end
if parameters.case ~= 'gender' then
labelcase = case(parameters.case, labelcase, lang, parameters.lang[1], entity_id, parameters.id)
end
local ret1, ret2
if parameter == 'label' then
ret1 = labelcase or entity_id
ret2 = labelcase or entity_id
elseif parameter == 'sitelink' then
ret1 = (sitelink or 'd:' .. entity_page)
ret2 = sitelink or entity_id
elseif mw.ustring.find((parameter or ''), '$1', 1, true) then -- formatting = a pattern
ret1 = mw.ustring.gsub(parameter, '$1', labelcase or entity_id)
ret1 = expandBraces(ret1, parameter)
ret2 = labelcase or entity_id
else
if parameter == "ucfirst" or parameter == "ucinternallink" then
if labelcase and lang then
labelcase = mw.language.new(lang):ucfirst(labelcase)
end
-- only first of a list, reset formatting for next ones
if parameter == "ucinterlanllink" then
parameters.formatting = 'internallink'
else
parameters.formatting = nil -- default format
end
end
if sitelink then
ret1 = '[[' .. sitelink .. '|' .. labelcase .. ']]'
ret2 = labelcase
elseif label and string.match(parameter or '', 'internallink$') and not mw.wikibase.getEntityIdForTitle(label) then
ret1 = '[[' .. label .. '|' .. labelcase .. ']]'
ret2 = labelcase
else
ret1 = '[[d:' .. entity_page .. '|' .. (labelcase or entity_id) .. ']]'
ret2 = labelcase or entity_id
end
end
return ret1 .. addLabelIcon(entity_id, lang, parameters.lang[1], parameters.editicon), ret2
end
-- format data type monolingualtext
local function printDatatypeMonolingual(data, parameters)
-- data fields: language [string], text [string]
if parameters.list == "lang" and data["language"] ~= parameters.lang[1] then
return
elseif parameters.formatting == "language" or parameters.formatting == "text" then
return data[parameters.formatting]
end
local result = data["text"]
if data["language"] ~= wiki.langcode then
result = mw.ustring.gsub('<span lang="$1">$2</span>', '$[12]', {["$1"]=data["language"], ["$2"]=data["text"]})
end
if mw.ustring.find((parameters.formatting or ''), '$', 1, true) then
-- output format defined with $text, $language
result = mw.ustring.gsub(parameters.formatting, '$text', result)
result = mw.ustring.gsub(result, '$language', data["language"])
end
return result
end
local function getSnakValue(snak, parameters)
if snak.snaktype == 'value' then
-- see Special:ListDatatypes
if snak.datatype == "string" then
return printDatatypeString(snak.datavalue.value, parameters)
-- other data value string, tabular-data not implemented
elseif snak.datatype == "commonsMedia" then
return printDatatypeMedia(snak.datavalue.value, parameters)
elseif snak.datatype == "url" then
return printDatatypeUrl(snak.datavalue.value, parameters)
elseif snak.datatype == "external-id" then
return printDatatypeExternal(snak.datavalue.value, parameters)
elseif snak.datatype == 'math' then
return printDatatypeMath(snak.datavalue.value)
elseif snak.datatype == 'musical-notation' then
return printDatatypeMusical(snak.datavalue.value, parameters.formatting)
-- other data types
elseif snak.datatype == 'wikibase-item' or snak.datatype == 'wikibase-property' then
return printDatatypeEntity(snak.datavalue.value, parameters)
elseif snak.datatype == 'monolingualtext' then
return printDatatypeMonolingual(snak.datavalue.value, parameters)
elseif snak.datatype == "globe-coordinate" then
return printDatatypeCoordinate(snak.datavalue.value, parameters.formatting)
elseif snak.datatype == "quantity" then
return printDatatypeQuantity(snak.datavalue.value, parameters)
elseif snak.datatype == "time" then
return printDatatypeTime(snak.datavalue.value, parameters)
end
elseif snak.snaktype == 'novalue' then
if parameters.formatting == 'raw' or parameters.shownovalue == false then return end
return mw.message.new('Wikibase-snakview-snaktypeselector-novalue'):inLanguage(parameters.lang[1]):plain()
elseif snak.snaktype == 'somevalue' then
if parameters.formatting == 'raw' then return end
return mw.message.new('Wikibase-snakview-snaktypeselector-somevalue'):inLanguage(parameters.lang[1]):plain()
end
return mw.wikibase.renderSnak(snak)
end
local function printError(key)
return '<span class="error">' .. i18n.errors[key] .. '</span>'
end
local function getQualifierSnak(claim, qualifierId, parameters)
-- a "snak" is Wikidata terminology for a typed key/value pair
-- a claim consists of a main snak holding the main information of this claim,
-- as well as a list of attribute snaks and a list of references snaks
if qualifierId then
-- search the attribute snak with the given qualifier as key
if claim.qualifiers then
local qualifier = claim.qualifiers[qualifierId]
if qualifier then
if qualifier[1].datatype == "monolingualtext" then
-- iterate over monolingualtext qualifiers to get local language
for idx in pairs(qualifier) do
if getSnak(qualifier[idx], {"datavalue", "value", "language"}) == parameters.lang[1] then
return qualifier[idx]
end
end
elseif parameters.list then
return qualifier
else
return qualifier[1]
end
end
end
return nil, printError("qualifier-not-found")
else
-- otherwise return the main snak
return claim.mainsnak
end
end
local function getValue(entity, claims, propertyID, delim, labelHook)
if labelHook == nil then
labelHook = function (qnumber)
return nil;
end
end
if isType(claims, "wikibase-entityid") then
local out = {}
for k, v in pairs(claims) do
local qnumber = "Q" .. v.mainsnak.datavalue.value["numeric-id"]
local sitelink = mw.wikibase.getSitelink(qnumber)
local label = labelHook(qnumber) or mw.wikibase.getLabel(qnumber) or qnumber
if sitelink then
out[#out + 1] = "[[" .. sitelink .. "|" .. label .. "]]"
else
out[#out + 1] = "[[:d:" .. qnumber .. "|" .. label .. "]]<abbr title='" .. i18n["errors"]["local-article-not-found"] .. "'>[*]</abbr>"
end
end
return table.concat(out, delim)
else
-- just return best values
return entity:formatPropertyValues(propertyID).value
end
end
local function getValueOfClaim(claim, qualifierId, parameters)
local snak, error = getQualifierSnak(claim, qualifierId, parameters)
if not snak then
return nil, nil, error
elseif snak[1] then -- a multi qualifier
local result, sortkey = {}, {}
local maxvals = tonumber(parameters.list)
for idx in pairs(snak) do
result[#result + 1], sortkey[#sortkey + 1] = getSnakValue(snak[idx], parameters)
if maxvals and maxvals == #result then break end
end
return mw.text.listToText(result, parameters.qseparator, parameters.qconjunction), sortkey[1]
else -- a property or a qualifier
return getSnakValue(snak, parameters)
end
end
local function getValueOfParentClaim(claim, qualifierId, parameters)
local qids = mw.text.split(qualifierId, '/', true)
local value, sortkey, valueraw = {}, {}, {}
local parent_raw, value_text
if qids[1] == parameters.property then
parent_raw, _, _ = getValueOfClaim(claim, nil, {["formatting"]="raw", ["lang"]=parameters.lang})
else
parent_raw, _, _ = getValueOfClaim(claim, qids[1], {["formatting"]="raw", ["lang"]=parameters.lang, ["list"]=true, ["qseparator"]='/', ["qconjunction"]='/'})
end
if string.sub(parent_raw or '', 1, 1) == "Q" then -- protection for 'no value'
local parent_qids = mw.text.split(parent_raw, '/', true)
for idx, p_qid in ipairs(parent_qids) do
local parent_claims = mw.wikibase.getBestStatements(p_qid, qids[2])
if parent_claims[1] then
value[idx], sortkey[idx], _ = getValueOfClaim(parent_claims[1], nil, parameters)
-- raw parent value needed for while/black lists, lang for avoiding an error on types other than entity
valueraw[idx], _, _ = getValueOfClaim(parent_claims[1], nil, {["formatting"]="raw", ["lang"]=parameters.lang})
end
end
end
if value[1] then
value_text = mw.text.listToText(value, parameters.qseparator, parameters.qconjunction)
end
return value_text, sortkey[1], valueraw[1]
end
-- see d:Help:Sources
local function getReferences(claim, lang)
local notproperref = {
["P143"] = true, -- imported from
["P3452"] = true, -- inferred from
["P887"] = true, -- based on heuristic
["P4656"] = true -- Wikimedia import URL
}
local result = ""
-- traverse through all references
for ref in pairs(claim.references or {}) do
local refparts
local refs = {}
local validref = true
local ref_name
-- traverse through all parts of the current reference
for snakkey, snakval in pairs(claim.references[ref].snaks or {}) do
for partkey, _ in pairs(claim.references[ref].snaks[snakkey] or {}) do
if notproperref[snakkey] then -- not a proper reference
validref = false
break
end
end
if validref then
for snakidx = 1, #snakval do
if snakidx > 1 then refparts = refparts .. ", " end
refparts = refparts or '' .. getSnakValue(snakval[snakidx], {lang=lang})
end
refs[snakkey] = refparts
refparts = nil
if snakkey == "P248" then -- stated in
ref_name = snakval[1].datavalue.value.id
end
end
end
-- fill missing values with parent item
if ref_name then
local function refParent(qid, pid, formatting)
local snak = getSnak(mw.wikibase.getBestStatements(qid, pid), {1, "mainsnak"})
return snak and getSnakValue(snak, {formatting=formatting, lang=lang})
end
refs['P50'] = refs['P50'] or refParent(ref_name, 'P50', 'label') -- author
refs['P407'] = refs['P407'] or refParent(ref_name, 'P407', 'label') -- language of work
refs['P123'] = refs['P123'] or refParent(ref_name, 'P123', 'label') -- publisher
refs['P577'] = refs['P577'] or refParent(ref_name, 'P577') -- date
refs['P1433'] = refs['P1433'] or refParent(ref_name, 'P1433', 'label') -- published in
refs['P304'] = refs['P304'] or refParent(ref_name, 'P304') -- page(s)
refs['P433'] = refs['P433'] or refParent(ref_name, 'P433') -- issue
refs['P236'] = refs['P236'] or refParent(ref_name, 'P236') -- ISSN
refs['P356'] = refs['P356'] or refParent(ref_name, 'P356') -- DOI
end
-- get title of local templates for citing references
local template_web = mw.wikibase.getSitelink('Q5637226') or ""
template_web = mw.text.split(template_web, ":")[2] -- split off namespace from front
local template_journal = mw.wikibase.getSitelink('Q5624899') or ""
template_journal = mw.text.split(template_journal, ":")[2]
local citeParams = {}
if refs['P854'] and (refs['P1476'] or refs['P248']) and template_web then
-- if both "reference URL" and "title" (or "stated in") are present, then use cite web template
citeParams[i18n['cite']['url']] = refs['P854']
if refs['P248'] and refs['P1476'] == nil then
citeParams[i18n['cite']['title']] = refs['P248']:match("^%[%[.-|(.-)%]%]")
else
citeParams[i18n['cite']['title']] = refs['P1476']
citeParams[i18n['cite']['website']] = refs['P248']
end
citeParams[i18n['cite']['author']] = refs['P50']
citeParams[i18n['cite']['language']] = refs['P407']
citeParams[i18n['cite']['publisher']] = refs['P123']
citeParams[i18n['cite']['date']] = refs['P577']
citeParams[i18n['cite']['pages']] = refs['P304']
citeParams[i18n['cite']['access-date']] = refs['P813']
citeParams[i18n['cite']['archive-url']] = refs['P1065']
citeParams[i18n['cite']['archive-date']] = refs['P2960']
citeParams[i18n['cite']['quote']] = refs['P1683']
refparts = mw.getCurrentFrame():expandTemplate{title=template_web, args=citeParams}
elseif refs['P1433'] and (refs['P1476'] or refs['P248']) and template_journal then
-- if both "published in" and "title" (or "stated in") are present, then use cite journal template
citeParams[i18n['cite']['work']] = refs['P1433']
citeParams[i18n['cite']['title']] = refs['P1476'] or refs['P248']
citeParams[i18n['cite']['author']] = refs['P50']
citeParams[i18n['cite']['date']] = refs['P577']
citeParams[i18n['cite']['issue']] = refs['P433']
citeParams[i18n['cite']['pages']] = refs['P304']
citeParams[i18n['cite']['language']] = refs['P407']
citeParams[i18n['cite']['issn']] = refs['P236']
citeParams[i18n['cite']['doi']] = refs['P356']
refparts = mw.getCurrentFrame():expandTemplate{title=template_journal, args=citeParams}
elseif validref then
-- raw ouput
local snaksorder = claim.references[ref]["snaks-order"]
local function indexed(a)
for _, b in ipairs(snaksorder) do
if b == a then return true end
end
return false
end
for k, _ in pairs(refs or {}) do
if not indexed(k) then
table.insert(snaksorder, k)
end
end
local italics = "''"
for _, k in ipairs(snaksorder) do
if refs[k] then
refparts = refparts and refparts .. " " or ""
refparts = refparts .. mw.ustring.gsub(getLabelByLangs(k, lang), "^%l", mw.ustring.upper) .. ": "
refparts = refparts .. italics .. refs[k] .. italics .. "."
italics = ""
end
end
end
if refparts then result = mw.getCurrentFrame():extensionTag("ref", refparts, {name=ref_name}) end
end
return result
end
-- Set whitelist or blacklist values
local function setWhiteOrBlackList(num_qual, args)
local lists = {['whitelist']={}, ['blacklist']={}, ['ignorevalue']={}, ['selectvalue']={}}
for i = 0, num_qual do
for k, _ in pairs(lists) do
if isSet(args[k .. i]) then
lists[k][tostring(i)] = {}
for q in string.gmatch(args[k .. i], 'Q%d+') do
lists[k][tostring(i)][resolveEntityId(q)] = true
end
end
end
end
return lists['whitelist'], lists['blacklist'], lists['ignorevalue'], lists['selectvalue']
end
local function tableParameters(args, parameters, column)
local column_params = mw.clone(parameters)
column_params.formatting = args["colformat"..column]; if column_params.formatting == "" then column_params.formatting = nil end
column_params.convert = args["convert" .. column]
if args["case" .. column] then
column_params.case = args["case" .. column]
end
return column_params
end
local function getEntityId(args, pargs, unnamed)
pargs = pargs or {}
local id = args.item or args.from or (unnamed and mw.text.trim(args[1] or '') or nil)
if not isSet(id) then
id = pargs.item or pargs.from or (unnamed and mw.text.trim(pargs[1] or '') or nil)
end
if isSet(id) then
if string.find(id, ":") then -- remove prefix as Property:Pid
id = mw.text.split(id, ":")[2]
end
else
id = mw.wikibase.getEntityIdForCurrentPage()
end
return id
end
-- Main function claim ---------------------------------------------
-- on debug console use: =p.claim{item="Q...", property="P...", ...}
function p.claim(frame)
local args = frame.args or frame -- via invoke or require
local pargs = frame.args and frame:getParent().args or {}
local is_sandbox = isSet(pargs.sandbox)
if not required and is_sandbox then
return require(wiki.module_title .. "/" .. mw.message.new('Sandboxlink-subpage-name'):inLanguage(wiki.langcode):plain()).claim(frame)
end
--If a value is already set, use it
if isSet(args.value) then
if args.value == 'NONE' then
return
else
return args.value
end
end
-- arguments
local id = getEntityId(args, pargs)
if id == nil then return end
local property = string.upper(args.property or "")
local qualifierId = {}
qualifierId[1] = isSet(args.qualifier) and string.upper(args.qualifier) or nil
local i = 2
while isSet(args["qualifier" .. i]) do
qualifierId[i] = string.upper(args["qualifier" .. i])
i = i + 1
end
local formatting = isSet(args.formatting) and args.formatting or nil
local convert = isSet(args.convert) and args.convert or nil
local case = args.case
local list = args.list or true; if (list == "false" or list == "no") then list = false end
if list == 'firstrank' then list = 'bestrank' end -- alias
local shownovalue = args.shownovalue or true; if (shownovalue == "false" or shownovalue == "no") then shownovalue = false end
local sorting_col = args.tablesort
local sorting_up = (args.sorting or "") ~= "-1"
local separator = isSet(args.separator) and args.separator
local conjunction = isSet(args.conjunction) and args.conjunction or separator
local rowformat = args.rowformat
local references = args.references
local showerrors = args.showerrors
local default = args.default
if default then showerrors = nil end
local parameters = {["id"] = id, ["property"] = property, ["formatting"] = formatting, ["convert"] = convert,
["list"] = list, ["case"] = case, ["shownovalue"] = shownovalue,
["separator"] = separator, ["conjunction"] = conjunction, ["qseparator"] = separator, ["qconjunction"] = conjunction}
parameters.lang = findLang(args.lang)
parameters.editicon = formatting ~= "raw" and setEditIcon(args.editicon or pargs.editicon) or false -- needs loadI18n by findLand
-- fetch property
local claims = {}
local bestrank = (parameters.list == false or parameters.list == 'bestrank') and parameters.list ~= 'lang'
for p in string.gmatch(parameters.property, 'P%d+') do
claims = getStatements(id, p, bestrank)
if #claims > 0 then
parameters.property = p
break
end
end
if #claims == 0 then
if showerrors then return printError("property-not-found") else return default end
end
-- defaults for table
local preformat, postformat = "", ""
local whitelisted = false
local whitelist, blacklist, ignorevalue, selectvalue = {}, {}, {}, {}
if parameters.formatting == "table" then
parameters.separator = parameters.separator or "<br />"
parameters.conjunction = parameters.conjunction or "<br />"
parameters.qseparator = ", "
parameters.qconjunction = ", "
if not rowformat then
rowformat = "$0 ($1"
i = 2
while qualifierId[i] do
rowformat = rowformat .. ", $" .. i
i = i + 1
end
rowformat = rowformat .. ")"
elseif mw.ustring.find(rowformat, "^[*#]") then
parameters.separator = "</li><li>"
parameters.conjunction = "</li><li>"
if mw.ustring.match(rowformat, "^[*#]") == "*" then
preformat = "<ul><li>"
postformat = "</li></ul>"
else
preformat = "<ol><li>"
postformat = "</li></ol>"
end
rowformat = mw.ustring.gsub(rowformat, "^[*#] ?", "")
end
-- set whitelist and blacklist values
whitelist, blacklist, ignorevalue, selectvalue = setWhiteOrBlackList(#qualifierId, args)
local next = next
if next(whitelist) ~= nil then whitelisted = true end
end
-- set feminine case if gender is requested
local itemgender = args.itemgender
local idgender
if itemgender then
if string.match(itemgender, "^P%d+$") then
local snak_id = getSnak(mw.wikibase.getBestStatements(id, itemgender), {1, "mainsnak", "datavalue", "value", "id"})
if snak_id then
idgender = snak_id
end
elseif string.match(itemgender, "^Q%d+$") then
idgender = itemgender
end
end
local gender_requested = false
if parameters.case == "gender" or idgender then
gender_requested = true
elseif parameters.formatting == "table" then
for i=0, #qualifierId do
if args["case" .. i] and args["case" .. i] == "gender" then
gender_requested = true
break
end
end
end
if gender_requested then
if feminineGender(idgender or id) then
parameters.gender = "feminineform"
end
end
-- get initial sort indices
local sortindices = {}
for idx in pairs(claims) do
sortindices[#sortindices + 1] = idx
end
-- sort by claim rank
local comparator = function(a, b)
local rankmap = { deprecated = 2, normal = 1, preferred = 0 }
local ranka = rankmap[claims[a].rank or "normal"] .. string.format("%08d", a)
local rankb = rankmap[claims[b].rank or "normal"] .. string.format("%08d", b)
return ranka < rankb
end
table.sort(sortindices, comparator)
local result, result2
local error
if parameters.list or parameters.formatting == "table" then
-- convert LF to line feed, <br /> may not work on some cases
parameters.separator = parameters.separator == "LF" and "\010" or parameters.separator
parameters.conjunction = parameters.conjunction == "LF" and "\010" or parameters.conjunction
-- i18n separators
parameters.separator = parameters.separator or mw.message.new('Comma-separator'):inLanguage(parameters.lang[1]):plain()
parameters.conjunction = parameters.conjunction or (mw.message.new('And'):inLanguage(parameters.lang[1]):plain() .. mw.message.new('Word-separator'):inLanguage(parameters.lang[1]):plain())
-- iterate over all elements and return their value (if existing)
local value, valueq
local sortkey, sortkeyq
local values = {}
local sortkeys = {}
local refs = {}
local rowlist = {} -- rows to list with whitelist or blacklist
for idx in pairs(claims) do
local claim = claims[sortindices[idx]]
local reference = {}
if not whitelisted then rowlist[idx] = true end
if parameters.formatting == "table" then
local params = tableParameters(args, parameters, "0")
value, sortkey, error = getValueOfClaim(claim, nil, params)
if value then
values[#values + 1] = {}
sortkeys[#sortkeys + 1] = {}
refs[#refs + 1] = {}
if whitelist["0"] or blacklist["0"] then
local valueraw, _, _ = getValueOfClaim(claim, nil, {["formatting"]="raw", ["lang"]=params.lang})
if whitelist["0"] and whitelist["0"][valueraw or ""] then
rowlist[#values] = true
elseif blacklist["0"] and blacklist["0"][valueraw or ""] then
rowlist[#values] = false
end
end
for i, qual in ipairs(qualifierId) do
local j = tostring(i)
params = tableParameters(args, parameters, j)
local valueq, sortkeyq, valueraw
if qual == parameters.property then -- hack for getting the property with another formatting, i.e. colformat1=raw
valueq, sortkeyq, _ = getValueOfClaim(claim, nil, params)
else
for q in mw.text.gsplit(qual, '%s*OR%s*') do
if string.find(q, ".+/.+") then
valueq, sortkeyq, valueraw = getValueOfParentClaim(claim, q, params)
elseif string.find(q, "^/.+") then
local claim2 = getStatements(id, string.sub(q, 2), bestrank)
if #claim2 > 0 then
valueq, sortkeyq, _ = getValueOfClaim(claim2[1], nil, params)
end
else
valueq, sortkeyq, _ = getValueOfClaim(claim, q, params)
end
if valueq then break end
end
end
values[#values]["col" .. j] = valueq
sortkeys[#sortkeys]["col" .. j] = sortkeyq or valueq
if whitelist[j] or blacklist[j] or ignorevalue[j] or selectvalue[j] then
valueq = valueraw or getValueOfClaim(claim, qual, {["formatting"]="raw", ["lang"]=params.lang})
if whitelist[j] and whitelist[j][valueq or ""] then
rowlist[#values] = true
elseif blacklist[j] and blacklist[j][valueq or ""] then
rowlist[#values] = false
elseif ignorevalue[j] and ignorevalue[j][valueq or ""] then
values[#values]["col" .. j] = nil
elseif selectvalue[j] and not selectvalue[j][valueq or ""] then
values[#values]["col" .. j] = nil
end
end
end
end
else
value, sortkey, error = getValueOfClaim(claim, qualifierId[1], parameters)
values[#values + 1] = {}
sortkeys[#sortkeys + 1] = {}
refs[#refs + 1] = {}
end
if not value and showerrors then value = error end
if value then
if references and claim.references then reference = claim.references end
refs[#refs]["col0"] = reference
values[#values]["col0"] = value
sortkeys[#sortkeys]["col0"] = sortkey or value
end
end
-- sort and format results
sortindices = {}
for idx in pairs(values) do
sortindices[#sortindices + 1] = idx
end
if sorting_col then
local sorting_table = mw.text.split(sorting_col, '%D+')
local comparator = function(a, b)
local valuea, valueb
local i = 1
while valuea == valueb and i <= #sorting_table do
valuea = sortkeys[a]["col" .. sorting_table[i]] or ''
valueb = sortkeys[b]["col" .. sorting_table[i]] or ''
i = i + 1
end
if sorting_up then
return valueb > valuea
end
return valueb < valuea
end
table.sort(sortindices, comparator)
end
local maxvals = tonumber(parameters.list)
result = {}
for idx in pairs(values) do
local valuerow = values[sortindices[idx]]
local reference = getReferences({["references"] = refs[sortindices[idx]]["col0"]}, parameters.lang)
value = valuerow["col0"]
if parameters.formatting == "table" then
if not rowlist[sortindices[idx]] then
value = nil
else
local rowformatting = rowformat .. "$" -- fake end character added for easy gsub
value = mw.ustring.gsub(rowformatting, "$0", value)
value = mw.ustring.gsub(value, "$R0", reference) -- add reference
for i, _ in ipairs(qualifierId) do
local valueq = valuerow["col" .. i]
if args["rowsubformat" .. i] and isSet(valueq) then
-- add fake end character $
-- gsub $i not followed by a number so $1 doesn't match $10, $11...
-- remove fake end character
valueq = captureEscapes(valueq)
valueq = mw.ustring.gsub(args["rowsubformat" .. i] .. "$", "$" .. i .. "(%D)", valueq .. "%1")
valueq = string.sub(valueq, 1, -2)
rowformatting = mw.ustring.gsub(rowformatting, "$" .. i .. "(%D)", args["rowsubformat" .. i] .. "%1")
end
valueq = valueq and captureEscapes(valueq) or ''
value = mw.ustring.gsub(value, "$" .. i .. "(%D)", valueq .. "%1")
end
value = string.sub(value, 1, -2) -- remove fake end character
value = expandBraces(value, rowformatting)
end
elseif value then
value = expandBraces(value, parameters.formatting)
value = value .. reference
end
if isSet(value) then
result[#result + 1] = value
if not parameters.list or (maxvals and maxvals == #result) then
break
end
end
end
-- in a table, add edit icon on last element
if parameters.formatting == 'table' then
result = addEditIconTable(result, parameters)
end
result = preformat .. mw.text.listToText(result, parameters.separator, parameters.conjunction) .. postformat
else
-- return first element
local claim = claims[sortindices[1]]
result, result2, error = getValueOfClaim(claim, qualifierId[1], parameters)
if result and references then result = result .. getReferences(claim, parameters.lang) end
end
if isSet(result) then
if not (parameters.formatting == 'table' or (result2 and result2 == 'no-icon')) then
-- add edit icon, except table added previously and except explicit no-icon internal flag
result = result .. addEditIcon(parameters)
end
else
if showerrors then result = error else result = default end
end
return result, (required and not is_sandbox) and untranslated or ''
end
-- Local functions for getParentValues -----------------------
local function uc_first(word)
return mw.ustring.upper(mw.ustring.sub(word, 1, 1)) .. mw.ustring.sub(word, 2)
end
local function getPropertyValue(id, property, parameter, langs, editicon, case)
local snaks = mw.wikibase.getBestStatements(id, property)
local mysnak = getSnak(snaks, {1, "mainsnak"})
if mysnak == nil then
return
end
local entity_id
local result = '-' -- default for 'no value'
if mysnak.datavalue then
entity_id = "Q" .. tostring(mysnak.datavalue.value['numeric-id'])
result, _ = getSnakValue(mysnak, {formatting=parameter, lang=langs, editicon=editicon, case=case})
end
return entity_id, result
end
local function getParentObjects(id,
prop_format,
label_format,
languages,
propertySupString,
propertyLabel,
propertyLink,
labelShow,
editicon,
upto,
upto_linkId,
last_only,
grammatical_case,
include_self)
if upto_linkId == nil then upto_linkId = "" end
local upto_link_ids = {}
for q in mw.text.gsplit(upto_linkId, '[^Q%d]') do
upto_link_ids[resolveEntityId(q)] = true
end
local propertySups = mw.text.split(propertySupString, '[^P%d]')
local lastlabel = uc_first(upto or '')
local maxloop = tonumber(upto) or ((lastlabel .. upto_linkId) == '' and 10 or 50)
local labelFilter = {}
if labelShow then
for _, v in ipairs(mw.text.split(labelShow, "/")) do
labelFilter[uc_first(v)] = true
end
end
local label_self
_, label_self = getPropertyValue(id, propertyLabel, label_format, languages)
local result = {}
for iter = 1, maxloop do
local link, label, linktext, _id, _link
for _, propertySup in pairs(propertySups) do
_id, _link = getPropertyValue(id, propertySup, prop_format, languages, editicon, grammatical_case)
if _id and _link then id = _id; link = _link break end
end
if not id or not link then break end
if propertyLink then
_, linktext = getPropertyValue(id, propertyLink, "label", languages)
if linktext then
link = mw.ustring.gsub(link, "%[%[(.*)%|.+%]%]", "[[%1|" .. linktext .. "]]")
end
end
_, label = getPropertyValue(id, propertyLabel, label_format, languages, false, "infoboxlabel")
if labelShow == nil or labelFilter[label] then
result[#result + 1] = {label, link}
if label then
labelFilter[label] = nil -- only first label found
end
end
if label == lastlabel or upto_link_ids[id] then
break
end
end
if last_only then
result = {result[#result]}
end
if include_self then table.insert(result, 1, {label_self, mw.title.getCurrentTitle().text}) end
return result
end
local function parentObjectsToString(result,
rowformat,
cascade,
sorting)
local ret = {}
local first = 1
local last = #result
local iter = 1
if sorting == "-1" then first = #result; last = 1; iter = -1 end
for i = first, last, iter do
local rowtext = mw.ustring.gsub(rowformat, "$[01]", {["$0"] = result[i][1], ["$1"] = result[i][2]})
ret[#ret +1] = expandBraces(rowtext, rowformat)
end
if cascade then
local prefix = ""
for i = 1, #ret do
ret[i] = prefix .. "• " .. ret[i]
prefix = prefix .. " "
end
end
return ret
end
-- Returns pairs of instance label and property value fetching a recursive tree
function p.getParentValues(frame)
local args = frame.args or frame -- via invoke or require
local pargs = frame.args and frame:getParent().args or {}
if not required and isSet(pargs.sandbox) then
return require(wiki.module_title .. "/" .. mw.message.new('Sandboxlink-subpage-name'):inLanguage(wiki.langcode):plain()).getParentValues(frame)
end
local id = getEntityId(args, pargs)
if id == nil then return end
local languages = findLang(args.lang)
local propertySup = args.property; if not isSet(propertySup) then propertySup = "P131" end --administrative entity
local propertyLabel = args.label; if not isSet(propertyLabel) then propertyLabel = "P31" end --instance
local propertyLink = args.valuetext; if propertyLink == "" then propertyLink = nil end --internallink
local property_format = args.formatting; if property_format == "" then property_format = nil end
local label_format = args.labelformat; if not isSet(label_format) then label_format = "label" end
local upto = args.upto; if upto == "" then upto = nil end
local last_only = (args.last_only == "true" or args.last_only == "yes")
local labelShow = args.labelshow; if labelShow == "" then labelShow = nil end
local editicon = setEditIcon(args.editicon or pargs.editicon)
local include_self = (args.include_self == "true" or args.include_self == "yes")
local case = args.case; if case == "" then case = nil end
if isSet(args.uptolabelid) then
upto, _ = getLabelByLangs(args.uptolabelid, languages)
end
if isSet(args.showlabelid) then
local showLabelList = {}
for substring in mw.text.gsplit(args.showlabelid, '[^Q%d]') do
table.insert(showLabelList, (getLabelByLangs(substring, languages)))
end
if #showLabelList > 0 then
labelShow = table.concat(showLabelList,"/")
end
end
local result = getParentObjects(id,
property_format,
label_format,
languages,
propertySup,
propertyLabel,
propertyLink,
labelShow,
editicon,
upto,
args.uptovalueid or args.uptolinkid,
last_only,
case,
include_self)
if #result == 0 then return end
local rowformat = args.rowformat; if not isSet(rowformat) then rowformat = "$0 = $1" end
local separator = args.separator; if not isSet(separator) then separator = "<br />" end
local sorting = args.sorting; if sorting == "" then sorting = nil end
local cascade = (args.cascade == "true" or args.cascade == "yes")
local ret = parentObjectsToString(result,
rowformat,
cascade,
sorting)
ret = addEditIconTable(ret, {property=propertySup, editicon=editicon, id=id, lang=languages})
return mw.text.listToText(ret, separator, separator)
end
-- Link with a parent label --------------------
function p.linkWithParentLabel(frame)
local pargs = frame.args and frame:getParent().args or {}
if not required and isSet(pargs.sandbox) then
return require(wiki.module_title .. "/" .. mw.message.new('Sandboxlink-subpage-name'):inLanguage(wiki.langcode):plain()).linkWithParentLabel(frame)
end
local args = {}
if frame.args then
for k, v in pairs(frame.args) do -- metatable
args[k] = v
end
else
args = frame -- via require
end
if isSet(args.value) then
return args.value
end
-- get id value of property/qualifier
local largs = mw.clone(args)
largs.list = tonumber(args.list) and args.list or "true"
largs.formatting = "raw"
largs.separator = "/·/"
largs.editicon = "false"
local items_list, _ = p.claim(largs)
if not isSet(items_list) then return end
local items_table = mw.text.split(items_list, "/·/", true)
-- get internal link of property/qualifier
largs.formatting = "internallink"
local link_list, _ = p.claim(largs)
local link_table = mw.text.split(link_list, "/·/", true)
-- get label of parent property
local parent_claim = getSnak(getStatements(items_table[1], args.parent, true), {1, "mainsnak", "datatype"})
if parent_claim == 'monolingualtext' then
largs.formatting = nil
largs.list = 'lang'
else
largs.formatting = "label"
largs.list = "false"
end
largs.property = args.parent
largs.qualifier = nil
for i, v in ipairs(items_table) do
largs.item = v
local link_label, _ = p.claim(largs)
if isSet(link_label) then
link_table[i] = mw.ustring.gsub(link_table[i] or '', "%[%[(.*)%|.+%]%]", "[[%1|" .. link_label .. "]]")
end
end
args.editicon = setEditIcon(args.editicon or pargs.editicon)
args.id = getEntityId(args, pargs)
args.lang = findLang(args.lang)
return mw.text.listToText(link_table) .. addEditIcon(args)
end
-- Calculate number of years old ----------------------------
function p.yearsOld(frame)
if not required and frame.args and isSet(frame:getParent().args.sandbox) then
return require(wiki.module_title .. "/" .. mw.message.new('Sandboxlink-subpage-name'):inLanguage(wiki.langcode):plain()).yearsOld(frame)
end
local args = frame.args or frame -- via invoke or require
local pargs = frame.args and frame:getParent().args or {}
local id = getEntityId(args, pargs)
local lang = mw.language.new('en')
local function getBestValue(id, prop)
local snak_value = getSnak(mw.wikibase.getBestStatements(id, prop), {1, "mainsnak", "datavalue", "value"})
return snak_value
end
local birth = getBestValue(id, 'P569')
if type(birth) ~= 'table' or birth.time == nil or birth.precision == nil or birth.precision < 8 then
return
end
local death = getBestValue(id, 'P570')
if type(death) ~= 'table' or death.time == nil or death.precision == nil then
death = {['time'] = lang:formatDate('c'), ['precision'] = 11} -- current date
elseif death.precision < 8 then
return
end
local dates = {}
dates[1] = {['min'] = {}, ['max'] = {}, ['precision'] = birth.precision}
dates[1].min.year = tonumber(mw.ustring.match(birth.time, "^[+-]?%d+"))
dates[1].min.month = tonumber(mw.ustring.match(birth.time, "\-(%d%d)\-"))
dates[1].min.day = tonumber(mw.ustring.match(birth.time, "\-(%d%d)T"))
dates[1].max = mw.clone(dates[1].min)
dates[2] = {['min'] = {}, ['max'] = {}, ['precision'] = death.precision}
dates[2].min.year = tonumber(mw.ustring.match(death.time, "^[+-]?%d+"))
dates[2].min.month = tonumber(mw.ustring.match(death.time, "\-(%d%d)\-"))
dates[2].min.day = tonumber(mw.ustring.match(death.time, "\-(%d%d)T"))
dates[2].max = mw.clone(dates[2].min)
for i, d in ipairs(dates) do
if d.precision == 10 then -- month
d.min.day = 1
local timestamp = string.format("%04d", tostring(math.abs(d.max.year)))
.. string.format("%02d", tostring(d.max.month))
.. "01"
d.max.day = tonumber(lang:formatDate("j", timestamp .. " + 1 month - 1 day"))
elseif d.precision < 10 then -- year or decade
d.min.day = 1
d.min.month = 1
d.max.day = 31
d.max.month = 12
if d.precision == 8 then -- decade
d.max.year = d.max.year + 9
end
end
end
local function age(d1, d2)
local years = d2.year - d1.year
if d2.month < d1.month or (d2.month == d1.month and d2.day < d1.day) then
years = years - 1
end
if d2.year > 0 and d1.year < 0 then
years = years - 1 -- no year 0
end
return years
end
local old_min = age(dates[1].max, dates[2].min)
local old_max = age(dates[1].min, dates[2].max)
local old, old_expr
if old_min == 0 and old_max == 0 then
old = "< 1"
old_max = 1 -- expression in singular
elseif old_min == old_max then
old = old_min
else
old = old_min .. "/" .. old_max
end
if args.formatting == 'unit' then
local langs = findLang(args.lang)
local yo, yo_sg, yo_pl, yo_pau
if langs[1] == wiki.langcode then
yo_sg = i18n["years-old"].singular
yo_pl = i18n["years-old"].plural
yo_pau = i18n["years-old"].paucal
end
if not isSet(yo_pl) then
yo_pl, _ = getLabelByLangs('Q24564698', langs)
yo_sg = yo_pl
end
if not isSet(yo_pau) then
yo_pau = yo_pl
end
yo = mw.language.new(langs[1]):plural(old_max, {yo_sg, yo_pau, yo_pl})
if mw.ustring.find(yo, '$1', 1, true) then
old_expr = mw.ustring.gsub(yo, "$1", old)
else
old_expr = old .. ' ' .. yo
end
elseif args.formatting then
old_expr = expandBraces(mw.ustring.gsub(args.formatting, '$1', old), args.formatting)
else
old_expr = old
end
return old_expr
end
-- Gets a label in a given language (content language by default) or its fallbacks, optionnally linked.
function p.getLabel(frame)
local args = frame.args or frame -- via invoke or require
local pargs = frame.args and frame:getParent().args or {}
if not required and isSet(pargs.sandbox) then
return require(wiki.module_title .. "/" .. mw.message.new('Sandboxlink-subpage-name'):inLanguage(wiki.langcode):plain()).getLabel(frame)
end
local id = getEntityId(args, pargs, 1)
if id == nil then return end
local languages = findLang(args.lang)
local editicon = mw.wikibase.isValidEntityId(id) and setEditIcon(args.editicon or pargs.editicon) or false
local label_icon = ''
local label, lang
if args.label then
label = args.label
else
-- exceptions or labels fixed
local exist, labels = pcall(require, wiki.module_title .. "/labels" .. (languages[1] == wiki.langcode and '' or '/' .. languages[1]))
if exist and next(labels.infoboxLabelsFromId) ~= nil then
label = labels.infoboxLabelsFromId[id]
end
if label == nil then
label, lang = getLabelByLangs(id, languages)
if label then
if args.itemgender and feminineGender(args.itemgender) then
label = feminineForm(id, lang) or label
end
label = mw.language.new(lang):ucfirst(mw.text.nowiki(label)) -- sanitize
end
label_icon = addLabelIcon(id, lang, languages[1], editicon)
end
end
local linked = args.linked
if isSet(linked) and linked ~= "no" then
local article = mw.wikibase.getSitelink(id) or ("d:Special:EntityPage/" .. id)
return "[[" .. article .. "|" .. (label or id) .. "]]" .. label_icon, not required and '' or untranslated
else
return (label or id) .. label_icon, not required and '' or untranslated
end
end
-- Utilities -----------------------------
-- See also module ../debug.
-- Copied from Module:Wikibase
function p.getSiteLink(frame)
local args = frame.args or frame -- via invoke or require
local pargs = frame.args and frame:getParent().args or {}
local id = getEntityId(args, pargs, 1)
if id == nil then
return
end
return mw.wikibase.getSitelink(id, mw.text.trim(frame.args[2] or ''))
end
-- Helper function for the default language code used
function p.lang(frame)
local lang = frame and frame.args[1] -- nil via require
return findLang(lang)[1]
end
-- Number of statements
function p.numStatements(frame)
local args = frame.args or frame -- via invoke or require
local pargs = frame.args and frame:getParent().args or {}
local id = getEntityId(args, pargs)
if id == nil then return 0 end
local prop = mw.text.trim(args[1])
local num = {}
if args[2] then -- qualifier
local qual = mw.text.trim(args[2])
local values = p.claim{item=id, property=prop, qualifier=qual, formatting='raw', separator='/·/'}
if values then
num = mw.text.split(values, '/·/')
end
else
num = mw.wikibase.getBestStatements(id, prop)
end
return #num
end
-- Returns true if property datavalue is found excluding novalue/somevalue
function p.validProperty(frame)
local args = frame.args or frame -- via invoke or require
local pargs = frame.args and frame:getParent().args or {}
local item = getEntityId(args, pargs)
if item == nil then return end
local property = mw.text.trim(args[1])
local prop_data = getSnak(mw.wikibase.getBestStatements(item, property), {1, "mainsnak", "datavalue"})
return prop_data and true or nil
end
function p.editAtWikidata(frame)
local args = frame.args or frame -- via invoke or require
local pargs = frame.args and frame:getParent().args or {}
local value = isSet(args[1])
if value then return end
local param = {}
param.id = getEntityId(args, pargs)
param.property = args.property
param.lang = findLang(args.lang)
param.editicon = setEditIcon(args.editicon)
return addEditIcon(param)
end
-- returns the page id (Q...) of the current page or nothing of the page is not connected to Wikidata (fix missing page id on some infobox from enwiki)
function p.pageId(frame)
local entity = mw.wikibase.getEntityObject()
if not entity then return nil else return entity.id end
end
function p.getImageLegend(frame)
-- look for named parameter id; if it's blank make it nil
local id = frame.args.id
if id and (#id == 0) then
id = nil
end
-- look for named parameter lang
-- it should contain a two-character ISO-639 language code
-- if it's blank fetch the language of the local wiki
local lang = frame.args.lang
if (not lang) or (#lang < 2) then
lang = mw.language.getContentLanguage().code
end
-- first unnamed parameter is the local parameter, if supplied
local input_parm = mw.text.trim(frame.args[1] or "")
if input_parm == "FETCH_WIKIDATA" then
local ent = mw.wikibase.getEntity(id)
local imgs
if ent and ent.claims then
imgs = ent.claims.P18
end
local imglbl
if imgs then
-- look for an image with 'preferred' rank
for k1, v1 in pairs(imgs) do
if v1.rank == "preferred" and v1.qualifiers and v1.qualifiers.P2096 then
local imglbls = v1.qualifiers.P2096
for k2, v2 in pairs(imglbls) do
if v2.datavalue.value.language == lang then
imglbl = v2.datavalue.value.text
break
end
end
end
end
-- if we don't find one, look for an image with 'normal' rank
if (not imglbl) then
for k1, v1 in pairs(imgs) do
if v1.rank == "normal" and v1.qualifiers and v1.qualifiers.P2096 then
local imglbls = v1.qualifiers.P2096
for k2, v2 in pairs(imglbls) do
if v2.datavalue.value.language == lang then
imglbl = v2.datavalue.value.text
break
end
end
end
end
end
end
return imglbl
else
return input_parm
end
end
return p
r1e1sk7seyrvkfnsg53zb0g4hr2efnm
Modul:If empty
828
20765
158999
121136
2026-10-10T16:40:09Z
Rachmat04
7338
158999
Scribunto
text/plain
local p = {}
function p.main(frame)
local args = require('Module:Arguments').getArgs(frame, {wrappers = 'Template:If empty', removeBlanks = false})
for k,v in ipairs(args) do
if v ~= '' then
return v
end
end
end
return p
letbsxftv5nn63rb2g6fewvi3ipqbw9
159027
158999
2026-10-10T17:06:25Z
Rachmat04
7338
159027
Scribunto
text/plain
local p = {}
function p.main(frame)
local args = require('Module:Arguments').getArgs(frame, {wrappers = 'Template:If empty', removeBlanks = false})
for k,v in ipairs(args) do
if v ~= '' then
return v
end
end
end
return p
8cxs60bq7ivex6wukqrel0fi3yogyu4
Marit:Teubai bibi
1
33802
159041
158858
2026-10-10T17:25:28Z
Rachmat04
7338
/* Plôk info */ Balah
159041
wikitext
text/x-wiki
== Plôk info ==
@[[Ureuëng Ngui:Rachmat04|Rachmat04]], neutulong peusaneut plôk info siat. Neupeuidin. [[Pengguna:Si Gam|Si Gam]] ([[Pembicaraan Pengguna:Si Gam|marit]]) 6 Buleuen Siplôh 2026 14.28 (WIB)
:Ka lon peusaneut. Lon gantoe infobox nyan ngon infobox laen, sabab infobox nyan jitarek data nibak Wikidata mantong reuloh, gohlom lon tupat pat asai reulohjih. '''· · ·''' <span title="Cherry blossom">🌸</span> [[User:Rachmat04|'''Rachmat04''']] '''·''' [[User talk:Rachmat04|<span title="Let's discuss!">🍵</span>]] 11 Buleuen Siplôh 2026 00.25 (WIB)
4ld7yo0no5l3dwl897as4kq1e1v6t67
159042
159041
2026-10-10T17:25:53Z
Rachmat04
7338
/* Plôk info */
159042
wikitext
text/x-wiki
== Plôk info ==
@[[Ureuëng Ngui:Rachmat04|Rachmat04]], neutulong peusaneut plôk info siat. Neupeuidin. [[Pengguna:Si Gam|Si Gam]] ([[Pembicaraan Pengguna:Si Gam|marit]]) 6 Buleuen Siplôh 2026 14.28 (WIB)
:Ka lon peusaneut. Lon gantoe infobox nyan ngon infobox laen, sabab infobox awai nyang jeuet jitarek data nibak Wikidata mantong reuloh, gohlom lon tupat pat asai reulohjih. '''· · ·''' <span title="Cherry blossom">🌸</span> [[User:Rachmat04|'''Rachmat04''']] '''·''' [[User talk:Rachmat04|<span title="Let's discuss!">🍵</span>]] 11 Buleuen Siplôh 2026 00.25 (WIB)
hk1d3q83dl8vt3zws3wuxbtff4iyu7r
159043
159042
2026-10-11T04:22:18Z
Si Gam
4266
/* Plôk info */ Balah
159043
wikitext
text/x-wiki
== Plôk info ==
@[[Ureuëng Ngui:Rachmat04|Rachmat04]], neutulong peusaneut plôk info siat. Neupeuidin. [[Pengguna:Si Gam|Si Gam]] ([[Pembicaraan Pengguna:Si Gam|marit]]) 6 Buleuen Siplôh 2026 14.28 (WIB)
:Ka lon peusaneut. Lon gantoe infobox nyan ngon infobox laen, sabab infobox awai nyang jeuet jitarek data nibak Wikidata mantong reuloh, gohlom lon tupat pat asai reulohjih. '''· · ·''' <span title="Cherry blossom">🌸</span> [[User:Rachmat04|'''Rachmat04''']] '''·''' [[User talk:Rachmat04|<span title="Let's discuss!">🍵</span>]] 11 Buleuen Siplôh 2026 00.25 (WIB)
::Teurimong gaséh. [[Pengguna:Si Gam|Si Gam]] ([[Pembicaraan Pengguna:Si Gam|marit]]) 11 Buleuen Siplôh 2026 11.22 (WIB)
6x7av0s94xw4nfjd4g1rxtqvcw3hu2c
Modul:Infobox/bak pasir
828
33874
159001
2026-10-10T16:41:49Z
Rachmat04
7338
Geupeugöt laman ngön asoë 'local p = {} local args = {} local origArgs = {} local root local empty_row_categories = {} local category_in_empty_row_pattern = '%[%[%s*[Cc][Aa][Tt][Ee][Gg][Oo][Rr][Yy]%s*:[^]]*]]' local has_rows = false local lists = { plainlist_t = { patterns = { '^plainlist$', '%splainlist$', '^plainlist%s', '%splainlist%s' }, found = false, styles = 'Plainlist/styles.css' }, hlist_t = { patterns = { '^hlist$', '%shlist$', '^hlist%s',...'
159001
Scribunto
text/plain
local p = {}
local args = {}
local origArgs = {}
local root
local empty_row_categories = {}
local category_in_empty_row_pattern = '%[%[%s*[Cc][Aa][Tt][Ee][Gg][Oo][Rr][Yy]%s*:[^]]*]]'
local has_rows = false
local lists = {
plainlist_t = {
patterns = {
'^plainlist$',
'%splainlist$',
'^plainlist%s',
'%splainlist%s'
},
found = false,
styles = 'Plainlist/styles.css'
},
hlist_t = {
patterns = {
'^hlist$',
'%shlist$',
'^hlist%s',
'%shlist%s'
},
found = false,
styles = 'Hlist/styles.css'
}
}
local function has_list_class(args_to_check)
for _, list in pairs(lists) do
if not list.found then
for _, arg in pairs(args_to_check) do
for _, pattern in ipairs(list.patterns) do
if mw.ustring.find(arg or '', pattern) then
list.found = true
break
end
end
if list.found then break end
end
end
end
end
local function fixChildBoxes(sval, tt)
local function notempty( s ) return s and s:match( '%S' ) end
if notempty(sval) then
local marker = '<span class=special_infobox_marker>'
local s = sval
-- start moving templatestyles and categories inside of table rows
local slast = ''
while slast ~= s do
slast = s
s = mw.ustring.gsub(s, '(</[Tt][Rr]%s*>%s*)(%[%[%s*[Cc][Aa][Tt][Ee][Gg][Oo][Rr][Yy]%s*:[^]]*%]%])', '%2%1')
s = mw.ustring.gsub(s, '(</[Tt][Rr]%s*>%s*)(\127[^\127]*UNIQ%-%-templatestyles%-%x+%-QINU[^\127]*\127)', '%2%1')
end
-- end moving templatestyles and categories inside of table rows
s = mw.ustring.gsub(s, '(<%s*[Tt][Rr])', marker .. '%1')
s = mw.ustring.gsub(s, '(</[Tt][Rr]%s*>)', '%1' .. marker)
if s:match(marker) then
s = mw.ustring.gsub(s, marker .. '%s*' .. marker, '')
s = mw.ustring.gsub(s, '([\r\n]|-[^\r\n]*[\r\n])%s*' .. marker, '%1')
s = mw.ustring.gsub(s, marker .. '%s*([\r\n]|-)', '%1')
s = mw.ustring.gsub(s, '(</[Cc][Aa][Pp][Tt][Ii][Oo][Nn]%s*>%s*)' .. marker, '%1')
s = mw.ustring.gsub(s, '(<%s*[Tt][Aa][Bb][Ll][Ee][^<>]*>%s*)' .. marker, '%1')
s = mw.ustring.gsub(s, '^(%{|[^\r\n]*[\r\n]%s*)' .. marker, '%1')
s = mw.ustring.gsub(s, '([\r\n]%{|[^\r\n]*[\r\n]%s*)' .. marker, '%1')
s = mw.ustring.gsub(s, marker .. '(%s*</[Tt][Aa][Bb][Ll][Ee]%s*>)', '%1')
s = mw.ustring.gsub(s, marker .. '(%s*\n|%})', '%1')
end
if s:match(marker) then
local subcells = mw.text.split(s, marker)
s = ''
for k = 1, #subcells do
if k == 1 then
s = s .. subcells[k] .. '</' .. tt .. '></tr>'
elseif k == #subcells then
local rowstyle = ' style="display:none"'
if notempty(subcells[k]) then rowstyle = '' end
s = s .. '<tr' .. rowstyle ..'><' .. tt .. ' colspan=2>\n' ..
subcells[k]
elseif notempty(subcells[k]) then
if (k % 2) == 0 then
s = s .. subcells[k]
else
s = s .. '<tr><' .. tt .. ' colspan=2>\n' ..
subcells[k] .. '</' .. tt .. '></tr>'
end
end
end
end
-- the next two lines add a newline at the end of lists for the PHP parser
-- [[Special:Diff/849054481]]
-- remove when [[:phab:T191516]] is fixed or OBE
s = mw.ustring.gsub(s, '([\r\n][%*#;:][^\r\n]*)$', '%1\n')
s = mw.ustring.gsub(s, '^([%*#;:][^\r\n]*)$', '%1\n')
s = mw.ustring.gsub(s, '^([%*#;:])', '\n%1')
s = mw.ustring.gsub(s, '^(%{%|)', '\n%1')
return s
else
return sval
end
end
-- Cleans empty tables
local function cleanInfobox()
root = tostring(root)
if has_rows == false then
root = mw.ustring.gsub(root, '<table[^<>]*>%s*</table>', '')
end
end
-- Returns the union of the values of two tables, as a sequence.
local function union(t1, t2)
local vals = {}
for k, v in pairs(t1) do
vals[v] = true
end
for k, v in pairs(t2) do
vals[v] = true
end
local ret = {}
for k, v in pairs(vals) do
table.insert(ret, k)
end
return ret
end
-- Returns a table containing the numbers of the arguments that exist
-- for the specified prefix. For example, if the prefix was 'data', and
-- 'data1', 'data2', and 'data5' exist, it would return {1, 2, 5}.
local function getArgNums(prefix)
local nums = {}
for k, v in pairs(args) do
local num = tostring(k):match('^' .. prefix .. '([1-9]%d*)$')
if num then table.insert(nums, tonumber(num)) end
end
table.sort(nums)
return nums
end
-- Adds a row to the infobox, with either a header cell
-- or a label/data cell combination.
local function addRow(rowArgs)
if rowArgs.header and rowArgs.header ~= '_BLANK_' then
has_rows = true
has_list_class({ rowArgs.rowclass, rowArgs.class, args.headerclass })
root
:tag('tr')
:addClass(rowArgs.rowclass)
:cssText(rowArgs.rowstyle)
:tag('th')
:attr('colspan', '2')
:addClass('infobox-header')
:addClass(rowArgs.class)
:addClass(args.headerclass)
-- @deprecated next; target .infobox-<name> .infobox-header
:cssText(args.headerstyle)
:cssText(rowArgs.rowcellstyle)
:wikitext(fixChildBoxes(rowArgs.header, 'th'))
if rowArgs.data then
root:wikitext(
'[[Category:Pages using infobox templates with ignored data cells]]'
)
end
elseif rowArgs.data and rowArgs.data:gsub(category_in_empty_row_pattern, ''):match('^%S') then
has_rows = true
has_list_class({ rowArgs.rowclass, rowArgs.class })
local row = root:tag('tr')
row:addClass(rowArgs.rowclass)
row:cssText(rowArgs.rowstyle)
if rowArgs.label then
row
:tag('th')
:attr('scope', 'row')
:addClass('infobox-label')
-- @deprecated next; target .infobox-<name> .infobox-label
:cssText(args.labelstyle)
:cssText(rowArgs.rowcellstyle)
:wikitext(rowArgs.label)
:done()
end
local dataCell = row:tag('td')
dataCell
:attr('colspan', not rowArgs.label and '2' or nil)
:addClass(not rowArgs.label and 'infobox-full-data' or 'infobox-data')
:addClass(rowArgs.class)
-- @deprecated next; target .infobox-<name> .infobox(-full)-data
:cssText(rowArgs.datastyle)
:cssText(rowArgs.rowcellstyle)
:wikitext(fixChildBoxes(rowArgs.data, 'td'))
else
table.insert(empty_row_categories, rowArgs.data or '')
end
end
local function renderTitle()
if not args.title then return end
has_rows = true
has_list_class({args.titleclass})
root
:tag('caption')
:addClass('infobox-title')
:addClass(args.titleclass)
-- @deprecated next; target .infobox-<name> .infobox-title
:cssText(args.titlestyle)
:wikitext(args.title)
end
local function renderAboveRow()
if not args.above then return end
has_rows = true
has_list_class({ args.aboveclass })
root
:tag('tr')
:tag('th')
:attr('colspan', '2')
:addClass('infobox-above')
:addClass(args.aboveclass)
-- @deprecated next; target .infobox-<name> .infobox-above
:cssText(args.abovestyle)
:wikitext(fixChildBoxes(args.above,'th'))
end
local function renderBelowRow()
if not args.below then return end
has_rows = true
has_list_class({ args.belowclass })
root
:tag('tr')
:tag('td')
:attr('colspan', '2')
:addClass('infobox-below')
:addClass(args.belowclass)
-- @deprecated next; target .infobox-<name> .infobox-below
:cssText(args.belowstyle)
:wikitext(fixChildBoxes(args.below,'td'))
end
local function addSubheaderRow(subheaderArgs)
if subheaderArgs.data and
subheaderArgs.data:gsub(category_in_empty_row_pattern, ''):match('^%S') then
has_rows = true
has_list_class({ subheaderArgs.rowclass, subheaderArgs.class })
local row = root:tag('tr')
row:addClass(subheaderArgs.rowclass)
local dataCell = row:tag('td')
dataCell
:attr('colspan', '2')
:addClass('infobox-subheader')
:addClass(subheaderArgs.class)
:cssText(subheaderArgs.datastyle)
:cssText(subheaderArgs.rowcellstyle)
:wikitext(fixChildBoxes(subheaderArgs.data, 'td'))
else
table.insert(empty_row_categories, subheaderArgs.data or '')
end
end
local function renderSubheaders()
if args.subheader then
args.subheader1 = args.subheader
end
if args.subheaderrowclass then
args.subheaderrowclass1 = args.subheaderrowclass
end
local subheadernums = getArgNums('subheader')
for k, num in ipairs(subheadernums) do
addSubheaderRow({
data = args['subheader' .. tostring(num)],
-- @deprecated next; target .infobox-<name> .infobox-subheader
datastyle = args.subheaderstyle,
rowcellstyle = args['subheaderstyle' .. tostring(num)],
class = args.subheaderclass,
rowclass = args['subheaderrowclass' .. tostring(num)]
})
end
end
local function addImageRow(imageArgs)
if imageArgs.data and
imageArgs.data:gsub(category_in_empty_row_pattern, ''):match('^%S') then
has_rows = true
has_list_class({ imageArgs.rowclass, imageArgs.class })
local row = root:tag('tr')
row:addClass(imageArgs.rowclass)
local dataCell = row:tag('td')
dataCell
:attr('colspan', '2')
:addClass('infobox-image')
:addClass(imageArgs.class)
:cssText(imageArgs.datastyle)
:wikitext(fixChildBoxes(imageArgs.data, 'td'))
else
table.insert(empty_row_categories, imageArgs.data or '')
end
end
local function renderImages()
if args.image then
args.image1 = args.image
end
if args.caption then
args.caption1 = args.caption
end
local imagenums = getArgNums('image')
for k, num in ipairs(imagenums) do
local caption = args['caption' .. tostring(num)]
local data = mw.html.create():wikitext(args['image' .. tostring(num)])
if caption then
data
:tag('div')
:addClass('infobox-caption')
-- @deprecated next; target .infobox-<name> .infobox-caption
:cssText(args.captionstyle)
:wikitext(caption)
end
addImageRow({
data = tostring(data),
-- @deprecated next; target .infobox-<name> .infobox-image
datastyle = args.imagestyle,
class = args.imageclass,
rowclass = args['imagerowclass' .. tostring(num)]
})
end
end
-- When autoheaders are turned on, preprocesses the rows
local function preprocessRows()
if not args.autoheaders then return end
local rownums = union(getArgNums('header'), getArgNums('data'))
table.sort(rownums)
local lastheader
for k, num in ipairs(rownums) do
if args['header' .. tostring(num)] then
if lastheader then
args['header' .. tostring(lastheader)] = nil
end
lastheader = num
elseif args['data' .. tostring(num)] and
args['data' .. tostring(num)]:gsub(
category_in_empty_row_pattern, ''
):match('^%S') then
local data = args['data' .. tostring(num)]
if data:gsub(category_in_empty_row_pattern, ''):match('%S') then
lastheader = nil
end
end
end
if lastheader then
args['header' .. tostring(lastheader)] = nil
end
end
-- Gets the union of the header and data argument numbers,
-- and renders them all in order
local function renderRows()
local rownums = union(getArgNums('header'), getArgNums('data'))
table.sort(rownums)
for k, num in ipairs(rownums) do
addRow({
header = args['header' .. tostring(num)],
label = args['label' .. tostring(num)],
data = args['data' .. tostring(num)],
datastyle = args.datastyle,
class = args['class' .. tostring(num)],
rowclass = args['rowclass' .. tostring(num)],
-- @deprecated next; target .infobox-<name> rowclass
rowstyle = args['rowstyle' .. tostring(num)],
rowcellstyle = args['rowcellstyle' .. tostring(num)]
})
end
end
local function renderNavBar()
if not args.name then return end
has_rows = true
root
:tag('tr')
:tag('td')
:attr('colspan', '2')
:addClass('infobox-navbar')
:wikitext(require('Module:Navbar')._navbar{
args.name,
mini = 1,
})
end
local function renderItalicTitle()
local italicTitle = args['italic title'] and mw.ustring.lower(args['italic title'])
if italicTitle == '' or italicTitle == 'force' or italicTitle == 'yes' then
root:wikitext(require('Module:Italic title')._main({}))
end
end
-- Categories in otherwise empty rows are collected in empty_row_categories.
-- This function adds them to the module output. It is not affected by
-- args.decat because this module should not prevent module-external categories
-- from rendering.
local function renderEmptyRowCategories()
for _, s in ipairs(empty_row_categories) do
root:wikitext(s)
end
end
-- Render tracking categories. args.decat == turns off tracking categories.
local function renderTrackingCategories()
if args.decat == 'yes' then return end
if args.child == 'yes' then
if args.title then
root:wikitext(
'[[Category:Pages using embedded infobox templates with the title parameter]]'
)
end
elseif #(getArgNums('data')) == 0 and mw.title.getCurrentTitle().namespace == 0 then
root:wikitext('[[Category:Articles using infobox templates with no data rows]]')
end
end
--[=[
Loads the templatestyles for the infobox.
TODO: FINISH loading base templatestyles here rather than in
MediaWiki:Common.css. There are 4-5000 pages with 'raw' infobox tables.
See [[Mediawiki_talk:Common.css/to_do#Infobox]] and/or come help :).
When we do this we should clean up the inline CSS below too.
Will have to do some bizarre conversion category like with sidebar.
]=]
local function loadTemplateStyles()
local frame = mw.getCurrentFrame()
local hlist_templatestyles = ''
if lists.hlist_t.found then
hlist_templatestyles = frame:extensionTag{
name = 'templatestyles', args = { src = lists.hlist_t.styles }
}
end
local plainlist_templatestyles = ''
if lists.plainlist_t.found then
plainlist_templatestyles = frame:extensionTag{
name = 'templatestyles', args = { src = lists.plainlist_t.styles }
}
end
-- See function description
local base_templatestyles = frame:extensionTag{
name = 'templatestyles', args = { src = 'Module:Infobox/styles.css' }
}
local templatestyles = ''
if args['templatestyles'] then
templatestyles = frame:extensionTag{
name = 'templatestyles', args = { src = args['templatestyles'] }
}
end
local child_templatestyles = ''
if args['child templatestyles'] then
child_templatestyles = frame:extensionTag{
name = 'templatestyles', args = { src = args['child templatestyles'] }
}
end
local grandchild_templatestyles = ''
if args['grandchild templatestyles'] then
grandchild_templatestyles = frame:extensionTag{
name = 'templatestyles', args = { src = args['grandchild templatestyles'] }
}
end
return table.concat({
-- hlist -> plainlist -> base is best-effort to preserve old Common.css ordering.
-- this ordering is not a guarantee because the rows of interest invoking
-- each class may not be on a specific page
hlist_templatestyles,
plainlist_templatestyles,
base_templatestyles,
templatestyles,
child_templatestyles,
grandchild_templatestyles
})
end
-- common functions between the child and non child cases
local function structure_infobox_common()
renderSubheaders()
renderImages()
preprocessRows()
renderRows()
renderBelowRow()
renderNavBar()
renderItalicTitle()
renderEmptyRowCategories()
renderTrackingCategories()
cleanInfobox()
end
-- Specify the overall layout of the infobox, with special settings if the
-- infobox is used as a 'child' inside another infobox.
local function _infobox()
if args.child ~= 'yes' then
root = mw.html.create('table')
root
:addClass(args.subbox == 'yes' and 'infobox-subbox' or 'infobox')
:addClass(args.bodyclass)
-- @deprecated next; target .infobox-<name>
:cssText(args.bodystyle)
has_list_class({ args.bodyclass })
renderTitle()
renderAboveRow()
else
root = mw.html.create()
root
:wikitext(args.title)
end
structure_infobox_common()
return loadTemplateStyles() .. root
end
-- If the argument exists and isn't blank, add it to the argument table.
-- Blank arguments are treated as nil to match the behaviour of ParserFunctions.
local function preprocessSingleArg(argName)
if origArgs[argName] and origArgs[argName] ~= '' then
args[argName] = origArgs[argName]
end
end
-- Assign the parameters with the given prefixes to the args table, in order, in
-- batches of the step size specified. This is to prevent references etc. from
-- appearing in the wrong order. The prefixTable should be an array containing
-- tables, each of which has two possible fields, a "prefix" string and a
-- "depend" table. The function always parses parameters containing the "prefix"
-- string, but only parses parameters in the "depend" table if the prefix
-- parameter is present and non-blank.
local function preprocessArgs(prefixTable, step)
if type(prefixTable) ~= 'table' then
error("Non-table value detected for the prefix table", 2)
end
if type(step) ~= 'number' then
error("Invalid step value detected", 2)
end
-- Get arguments without a number suffix, and check for bad input.
for i,v in ipairs(prefixTable) do
if type(v) ~= 'table' or type(v.prefix) ~= "string" or
(v.depend and type(v.depend) ~= 'table') then
error('Invalid input detected to preprocessArgs prefix table', 2)
end
preprocessSingleArg(v.prefix)
-- Only parse the depend parameter if the prefix parameter is present
-- and not blank.
if args[v.prefix] and v.depend then
for j, dependValue in ipairs(v.depend) do
if type(dependValue) ~= 'string' then
error('Invalid "depend" parameter value detected in preprocessArgs')
end
preprocessSingleArg(dependValue)
end
end
end
-- Get arguments with number suffixes.
local a = 1 -- Counter variable.
local moreArgumentsExist = true
while moreArgumentsExist == true do
moreArgumentsExist = false
for i = a, a + step - 1 do
for j,v in ipairs(prefixTable) do
local prefixArgName = v.prefix .. tostring(i)
if origArgs[prefixArgName] then
-- Do another loop if any arguments are found, even blank ones.
moreArgumentsExist = true
preprocessSingleArg(prefixArgName)
end
-- Process the depend table if the prefix argument is present
-- and not blank, or we are processing "prefix1" and "prefix" is
-- present and not blank, and if the depend table is present.
if v.depend and (args[prefixArgName] or (i == 1 and args[v.prefix])) then
for j,dependValue in ipairs(v.depend) do
local dependArgName = dependValue .. tostring(i)
preprocessSingleArg(dependArgName)
end
end
end
end
a = a + step
end
end
-- Parse the data parameters in the same order that the old {{infobox}} did, so
-- that references etc. will display in the expected places. Parameters that
-- depend on another parameter are only processed if that parameter is present,
-- to avoid phantom references appearing in article reference lists.
local function parseDataParameters()
preprocessSingleArg('autoheaders')
preprocessSingleArg('child')
preprocessSingleArg('bodyclass')
preprocessSingleArg('subbox')
preprocessSingleArg('bodystyle')
preprocessSingleArg('title')
preprocessSingleArg('titleclass')
preprocessSingleArg('titlestyle')
preprocessSingleArg('above')
preprocessSingleArg('aboveclass')
preprocessSingleArg('abovestyle')
preprocessArgs({
{prefix = 'subheader', depend = {'subheaderstyle', 'subheaderrowclass'}}
}, 10)
preprocessSingleArg('subheaderstyle')
preprocessSingleArg('subheaderclass')
preprocessArgs({
{prefix = 'image', depend = {'caption', 'imagerowclass'}}
}, 10)
preprocessSingleArg('captionstyle')
preprocessSingleArg('imagestyle')
preprocessSingleArg('imageclass')
preprocessArgs({
{prefix = 'header'},
{prefix = 'data', depend = {'label'}},
{prefix = 'rowclass'},
{prefix = 'rowstyle'},
{prefix = 'rowcellstyle'},
{prefix = 'class'}
}, 50)
preprocessSingleArg('headerclass')
preprocessSingleArg('headerstyle')
preprocessSingleArg('labelstyle')
preprocessSingleArg('datastyle')
preprocessSingleArg('below')
preprocessSingleArg('belowclass')
preprocessSingleArg('belowstyle')
preprocessSingleArg('name')
-- different behaviour for italics if blank or absent
args['italic title'] = origArgs['italic title']
preprocessSingleArg('decat')
preprocessSingleArg('templatestyles')
preprocessSingleArg('child templatestyles')
preprocessSingleArg('grandchild templatestyles')
end
-- If called via #invoke, use the args passed into the invoking template.
-- Otherwise, for testing purposes, assume args are being passed directly in.
function p.infobox(frame)
if frame == mw.getCurrentFrame() then
origArgs = frame:getParent().args
else
origArgs = frame
end
parseDataParameters()
return _infobox()
end
-- For calling via #invoke within a template
function p.infoboxTemplate(frame)
origArgs = {}
for k,v in pairs(frame.args) do origArgs[k] = mw.text.trim(v) end
parseDataParameters()
return _infobox()
end
return p
1m9tzydwofr8cj9bzzm2am6moool42y
159002
159001
2026-10-10T16:43:48Z
Rachmat04
7338
159002
Scribunto
text/plain
local p = {}
local args = {}
local origArgs = {}
local root
local empty_row_categories = {}
local category_in_empty_row_pattern = '%[%[%s*[Cc][Aa][Tt][Ee][Gg][Oo][Rr][Yy]%s*:[^]]*]]'
local has_rows = false
local yesno = require("Module:Yesno")
local lists = {
plainlist_t = {
patterns = {
'^plainlist$',
'%splainlist$',
'^plainlist%s',
'%splainlist%s'
},
found = false,
styles = 'Plainlist/styles.css'
},
hlist_t = {
patterns = {
'^hlist$',
'%shlist$',
'^hlist%s',
'%shlist%s'
},
found = false,
styles = 'Hlist/styles.css'
}
}
local function has_list_class(args_to_check)
for _, list in pairs(lists) do
if not list.found then
for _, arg in pairs(args_to_check) do
for _, pattern in ipairs(list.patterns) do
if mw.ustring.find(arg or '', pattern) then
list.found = true
break
end
end
if list.found then break end
end
end
end
end
local function fixChildBoxes(sval, tt)
local function notempty( s ) return s and s:match( '%S' ) end
if notempty(sval) then
local marker = '<span class=special_infobox_marker>'
local s = sval
-- start moving templatestyles and categories inside of table rows
local slast = ''
while slast ~= s do
slast = s
s = mw.ustring.gsub(s, '(</[Tt][Rr]%s*>%s*)(%[%[%s*[Cc][Aa][Tt][Ee][Gg][Oo][Rr][Yy]%s*:[^]]*%]%])', '%2%1')
s = mw.ustring.gsub(s, '(</[Tt][Rr]%s*>%s*)(\127[^\127]*UNIQ%-%-templatestyles%-%x+%-QINU[^\127]*\127)', '%2%1')
end
-- end moving templatestyles and categories inside of table rows
s = mw.ustring.gsub(s, '(<%s*[Tt][Rr])', marker .. '%1')
s = mw.ustring.gsub(s, '(</[Tt][Rr]%s*>)', '%1' .. marker)
if s:match(marker) then
s = mw.ustring.gsub(s, marker .. '%s*' .. marker, '')
s = mw.ustring.gsub(s, '([\r\n]|-[^\r\n]*[\r\n])%s*' .. marker, '%1')
s = mw.ustring.gsub(s, marker .. '%s*([\r\n]|-)', '%1')
s = mw.ustring.gsub(s, '(</[Cc][Aa][Pp][Tt][Ii][Oo][Nn]%s*>%s*)' .. marker, '%1')
s = mw.ustring.gsub(s, '(<%s*[Tt][Aa][Bb][Ll][Ee][^<>]*>%s*)' .. marker, '%1')
s = mw.ustring.gsub(s, '^(%{|[^\r\n]*[\r\n]%s*)' .. marker, '%1')
s = mw.ustring.gsub(s, '([\r\n]%{|[^\r\n]*[\r\n]%s*)' .. marker, '%1')
s = mw.ustring.gsub(s, marker .. '(%s*</[Tt][Aa][Bb][Ll][Ee]%s*>)', '%1')
s = mw.ustring.gsub(s, marker .. '(%s*\n|%})', '%1')
end
if s:match(marker) then
local subcells = mw.text.split(s, marker)
s = ''
for k = 1, #subcells do
if k == 1 then
s = s .. subcells[k] .. '</' .. tt .. '></tr>'
elseif k == #subcells then
local rowstyle = ' style="display:none"'
if notempty(subcells[k]) then rowstyle = '' end
s = s .. '<tr' .. rowstyle ..'><' .. tt .. ' colspan=2>\n' ..
subcells[k]
elseif notempty(subcells[k]) then
if (k % 2) == 0 then
s = s .. subcells[k]
else
s = s .. '<tr><' .. tt .. ' colspan=2>\n' ..
subcells[k] .. '</' .. tt .. '></tr>'
end
end
end
end
-- the next two lines add a newline at the end of lists for the PHP parser
-- [[Special:Diff/849054481]]
-- remove when [[:phab:T191516]] is fixed or OBE
s = mw.ustring.gsub(s, '([\r\n][%*#;:][^\r\n]*)$', '%1\n')
s = mw.ustring.gsub(s, '^([%*#;:][^\r\n]*)$', '%1\n')
s = mw.ustring.gsub(s, '^([%*#;:])', '\n%1')
s = mw.ustring.gsub(s, '^(%{%|)', '\n%1')
return s
else
return sval
end
end
-- Cleans empty tables
local function cleanInfobox()
root = tostring(root)
if has_rows == false then
root = mw.ustring.gsub(root, '<table[^<>]*>%s*</table>', '')
end
end
-- Returns the union of the values of two tables, as a sequence.
local function union(t1, t2)
local vals = {}
for k, v in pairs(t1) do
vals[v] = true
end
for k, v in pairs(t2) do
vals[v] = true
end
local ret = {}
for k, v in pairs(vals) do
table.insert(ret, k)
end
return ret
end
-- Returns a table containing the numbers of the arguments that exist
-- for the specified prefix. For example, if the prefix was 'data', and
-- 'data1', 'data2', and 'data5' exist, it would return {1, 2, 5}.
local function getArgNums(prefix)
local nums = {}
for k, v in pairs(args) do
local num = tostring(k):match('^' .. prefix .. '([1-9]%d*)$')
if num then table.insert(nums, tonumber(num)) end
end
table.sort(nums)
return nums
end
-- Adds a row to the infobox, with either a header cell
-- or a label/data cell combination.
local function addRow(rowArgs)
if rowArgs.header and rowArgs.header ~= '_BLANK_' then
has_rows = true
has_list_class({ rowArgs.rowclass, rowArgs.class, args.headerclass })
root
:tag('tr')
:addClass(rowArgs.rowclass)
:cssText(rowArgs.rowstyle)
:tag('th')
:attr('colspan', '2')
:addClass('infobox-header')
:addClass(rowArgs.class)
:addClass(args.headerclass)
-- @deprecated next; target .infobox-<name> .infobox-header
:cssText(args.headerstyle)
:cssText(rowArgs.rowcellstyle)
:wikitext(fixChildBoxes(rowArgs.header, 'th'))
if rowArgs.data and not yesno(args.decat) then
root:wikitext(
'[[Category:Pages using infobox templates with ignored data cells]]'
)
end
elseif rowArgs.data and rowArgs.data:gsub(category_in_empty_row_pattern, ''):match('^%S') then
has_rows = true
has_list_class({ rowArgs.rowclass, rowArgs.class })
local row = root:tag('tr')
row:addClass(rowArgs.rowclass)
row:cssText(rowArgs.rowstyle)
if rowArgs.label then
row
:tag('th')
:attr('scope', 'row')
:addClass('infobox-label')
-- @deprecated next; target .infobox-<name> .infobox-label
:cssText(args.labelstyle)
:cssText(rowArgs.rowcellstyle)
:wikitext(rowArgs.label)
:done()
end
local dataCell = row:tag('td')
dataCell
:attr('colspan', not rowArgs.label and '2' or nil)
:addClass(not rowArgs.label and 'infobox-full-data' or 'infobox-data')
:addClass(rowArgs.class)
-- @deprecated next; target .infobox-<name> .infobox(-full)-data
:cssText(rowArgs.datastyle)
:cssText(rowArgs.rowcellstyle)
:wikitext(fixChildBoxes(rowArgs.data, 'td'))
else
table.insert(empty_row_categories, rowArgs.data or '')
end
end
local function renderTitle()
if not args.title then return end
has_rows = true
has_list_class({args.titleclass})
root
:tag('caption')
:addClass('infobox-title')
:addClass(args.titleclass)
-- @deprecated next; target .infobox-<name> .infobox-title
:cssText(args.titlestyle)
:wikitext(args.title)
end
local function renderAboveRow()
if not args.above then return end
has_rows = true
has_list_class({ args.aboveclass })
root
:tag('tr')
:tag('th')
:attr('colspan', '2')
:addClass('infobox-above')
:addClass(args.aboveclass)
-- @deprecated next; target .infobox-<name> .infobox-above
:cssText(args.abovestyle)
:wikitext(fixChildBoxes(args.above,'th'))
end
local function renderBelowRow()
if not args.below then return end
has_rows = true
has_list_class({ args.belowclass })
root
:tag('tr')
:tag('td')
:attr('colspan', '2')
:addClass('infobox-below')
:addClass(args.belowclass)
-- @deprecated next; target .infobox-<name> .infobox-below
:cssText(args.belowstyle)
:wikitext(fixChildBoxes(args.below,'td'))
end
local function addSubheaderRow(subheaderArgs)
if subheaderArgs.data and
subheaderArgs.data:gsub(category_in_empty_row_pattern, ''):match('^%S') then
has_rows = true
has_list_class({ subheaderArgs.rowclass, subheaderArgs.class })
local row = root:tag('tr')
row:addClass(subheaderArgs.rowclass)
local dataCell = row:tag('td')
dataCell
:attr('colspan', '2')
:addClass('infobox-subheader')
:addClass(subheaderArgs.class)
:cssText(subheaderArgs.datastyle)
:cssText(subheaderArgs.rowcellstyle)
:wikitext(fixChildBoxes(subheaderArgs.data, 'td'))
else
table.insert(empty_row_categories, subheaderArgs.data or '')
end
end
local function renderSubheaders()
if args.subheader then
args.subheader1 = args.subheader
end
if args.subheaderrowclass then
args.subheaderrowclass1 = args.subheaderrowclass
end
local subheadernums = getArgNums('subheader')
for k, num in ipairs(subheadernums) do
addSubheaderRow({
data = args['subheader' .. tostring(num)],
-- @deprecated next; target .infobox-<name> .infobox-subheader
datastyle = args.subheaderstyle,
rowcellstyle = args['subheaderstyle' .. tostring(num)],
class = args.subheaderclass,
rowclass = args['subheaderrowclass' .. tostring(num)]
})
end
end
local function addImageRow(imageArgs)
if imageArgs.data and
imageArgs.data:gsub(category_in_empty_row_pattern, ''):match('^%S') then
has_rows = true
has_list_class({ imageArgs.rowclass, imageArgs.class })
local row = root:tag('tr')
row:addClass(imageArgs.rowclass)
local dataCell = row:tag('td')
dataCell
:attr('colspan', '2')
:addClass('infobox-image')
:addClass(imageArgs.class)
:cssText(imageArgs.datastyle)
:wikitext(fixChildBoxes(imageArgs.data, 'td'))
else
table.insert(empty_row_categories, imageArgs.data or '')
end
end
local function renderImages()
if args.image then
args.image1 = args.image
end
if args.caption then
args.caption1 = args.caption
end
local imagenums = getArgNums('image')
for k, num in ipairs(imagenums) do
local caption = args['caption' .. tostring(num)]
local data = mw.html.create():wikitext(args['image' .. tostring(num)])
if caption then
data
:tag('div')
:addClass('infobox-caption')
-- @deprecated next; target .infobox-<name> .infobox-caption
:cssText(args.captionstyle)
:wikitext(caption)
end
addImageRow({
data = tostring(data),
-- @deprecated next; target .infobox-<name> .infobox-image
datastyle = args.imagestyle,
class = args.imageclass,
rowclass = args['imagerowclass' .. tostring(num)]
})
end
end
-- When autoheaders are turned on, preprocesses the rows
local function preprocessRows()
if not args.autoheaders then return end
local rownums = union(getArgNums('header'), getArgNums('data'))
table.sort(rownums)
local lastheader
for k, num in ipairs(rownums) do
if args['header' .. tostring(num)] then
if lastheader then
args['header' .. tostring(lastheader)] = nil
end
lastheader = num
elseif args['data' .. tostring(num)] and
args['data' .. tostring(num)]:gsub(
category_in_empty_row_pattern, ''
):match('^%S') then
local data = args['data' .. tostring(num)]
if data:gsub(category_in_empty_row_pattern, ''):match('%S') then
lastheader = nil
end
end
end
if lastheader then
args['header' .. tostring(lastheader)] = nil
end
end
-- Gets the union of the header and data argument numbers,
-- and renders them all in order
local function renderRows()
local rownums = union(getArgNums('header'), getArgNums('data'))
table.sort(rownums)
for k, num in ipairs(rownums) do
addRow({
header = args['header' .. tostring(num)],
label = args['label' .. tostring(num)],
data = args['data' .. tostring(num)],
datastyle = args.datastyle,
class = args['class' .. tostring(num)],
rowclass = args['rowclass' .. tostring(num)],
-- @deprecated next; target .infobox-<name> rowclass
rowstyle = args['rowstyle' .. tostring(num)],
rowcellstyle = args['rowcellstyle' .. tostring(num)]
})
end
end
local function renderNavBar()
if not args.name then return end
has_rows = true
root
:tag('tr')
:tag('td')
:attr('colspan', '2')
:addClass('infobox-navbar')
:wikitext(require('Module:Navbar')._navbar{
args.name,
mini = 1,
})
end
local function renderItalicTitle()
local italicTitle = args['italic title'] and mw.ustring.lower(args['italic title'])
if italicTitle == '' or italicTitle == 'force' or italicTitle == 'yes' then
root:wikitext(require('Module:Italic title')._main({}))
end
end
-- Categories in otherwise empty rows are collected in empty_row_categories.
-- This function adds them to the module output. It is not affected by
-- args.decat because this module should not prevent module-external categories
-- from rendering.
local function renderEmptyRowCategories()
for _, s in ipairs(empty_row_categories) do
root:wikitext(s)
end
end
-- Render tracking categories. args.decat == turns off tracking categories.
local function renderTrackingCategories()
if yesno(args.decat) then return end
if args.child == 'yes' then
if args.title then
root:wikitext(
'[[Category:Pages using embedded infobox templates with the title parameter]]'
)
end
elseif #(getArgNums('data')) == 0 and mw.title.getCurrentTitle().namespace == 0 then
root:wikitext('[[Category:Articles using infobox templates with no data rows]]')
end
end
--[=[
Loads the templatestyles for the infobox.
TODO: FINISH loading base templatestyles here rather than in
MediaWiki:Common.css. There are 4-5000 pages with 'raw' infobox tables.
See [[Mediawiki_talk:Common.css/to_do#Infobox]] and/or come help :).
When we do this we should clean up the inline CSS below too.
Will have to do some bizarre conversion category like with sidebar.
]=]
local function loadTemplateStyles()
local frame = mw.getCurrentFrame()
local hlist_templatestyles = ''
if lists.hlist_t.found then
hlist_templatestyles = frame:extensionTag{
name = 'templatestyles', args = { src = lists.hlist_t.styles }
}
end
local plainlist_templatestyles = ''
if lists.plainlist_t.found then
plainlist_templatestyles = frame:extensionTag{
name = 'templatestyles', args = { src = lists.plainlist_t.styles }
}
end
-- See function description
local base_templatestyles = frame:extensionTag{
name = 'templatestyles', args = { src = 'Module:Infobox/sandbox/styles.css' }
}
local templatestyles = ''
if args['templatestyles'] then
templatestyles = frame:extensionTag{
name = 'templatestyles', args = { src = args['templatestyles'] }
}
end
local child_templatestyles = ''
if args['child templatestyles'] then
child_templatestyles = frame:extensionTag{
name = 'templatestyles', args = { src = args['child templatestyles'] }
}
end
local grandchild_templatestyles = ''
if args['grandchild templatestyles'] then
grandchild_templatestyles = frame:extensionTag{
name = 'templatestyles', args = { src = args['grandchild templatestyles'] }
}
end
return table.concat({
-- hlist -> plainlist -> base is best-effort to preserve old Common.css ordering.
-- this ordering is not a guarantee because the rows of interest invoking
-- each class may not be on a specific page
hlist_templatestyles,
plainlist_templatestyles,
base_templatestyles,
templatestyles,
child_templatestyles,
grandchild_templatestyles
})
end
-- common functions between the child and non child cases
local function structure_infobox_common()
renderSubheaders()
renderImages()
preprocessRows()
renderRows()
renderBelowRow()
renderNavBar()
renderItalicTitle()
renderEmptyRowCategories()
renderTrackingCategories()
cleanInfobox()
end
-- Specify the overall layout of the infobox, with special settings if the
-- infobox is used as a 'child' inside another infobox.
local function _infobox()
if args.child ~= 'yes' then
root = mw.html.create('table')
root
:addClass(args.subbox == 'yes' and 'infobox-subbox' or 'infobox')
:addClass(args.bodyclass)
-- @deprecated next; target .infobox-<name>
:cssText(args.bodystyle)
has_list_class({ args.bodyclass })
renderTitle()
renderAboveRow()
else
root = mw.html.create()
root
:wikitext(args.title)
end
structure_infobox_common()
return loadTemplateStyles() .. root
end
-- If the argument exists and isn't blank, add it to the argument table.
-- Blank arguments are treated as nil to match the behaviour of ParserFunctions.
local function preprocessSingleArg(argName)
if origArgs[argName] and origArgs[argName] ~= '' then
args[argName] = origArgs[argName]
end
end
-- Assign the parameters with the given prefixes to the args table, in order, in
-- batches of the step size specified. This is to prevent references etc. from
-- appearing in the wrong order. The prefixTable should be an array containing
-- tables, each of which has two possible fields, a "prefix" string and a
-- "depend" table. The function always parses parameters containing the "prefix"
-- string, but only parses parameters in the "depend" table if the prefix
-- parameter is present and non-blank.
local function preprocessArgs(prefixTable, step)
if type(prefixTable) ~= 'table' then
error("Non-table value detected for the prefix table", 2)
end
if type(step) ~= 'number' then
error("Invalid step value detected", 2)
end
-- Get arguments without a number suffix, and check for bad input.
for i,v in ipairs(prefixTable) do
if type(v) ~= 'table' or type(v.prefix) ~= "string" or
(v.depend and type(v.depend) ~= 'table') then
error('Invalid input detected to preprocessArgs prefix table', 2)
end
preprocessSingleArg(v.prefix)
-- Only parse the depend parameter if the prefix parameter is present
-- and not blank.
if args[v.prefix] and v.depend then
for j, dependValue in ipairs(v.depend) do
if type(dependValue) ~= 'string' then
error('Invalid "depend" parameter value detected in preprocessArgs')
end
preprocessSingleArg(dependValue)
end
end
end
-- Get arguments with number suffixes.
local a = 1 -- Counter variable.
local moreArgumentsExist = true
while moreArgumentsExist == true do
moreArgumentsExist = false
for i = a, a + step - 1 do
for j,v in ipairs(prefixTable) do
local prefixArgName = v.prefix .. tostring(i)
if origArgs[prefixArgName] then
-- Do another loop if any arguments are found, even blank ones.
moreArgumentsExist = true
preprocessSingleArg(prefixArgName)
end
-- Process the depend table if the prefix argument is present
-- and not blank, or we are processing "prefix1" and "prefix" is
-- present and not blank, and if the depend table is present.
if v.depend and (args[prefixArgName] or (i == 1 and args[v.prefix])) then
for j,dependValue in ipairs(v.depend) do
local dependArgName = dependValue .. tostring(i)
preprocessSingleArg(dependArgName)
end
end
end
end
a = a + step
end
end
-- Parse the data parameters in the same order that the old {{infobox}} did, so
-- that references etc. will display in the expected places. Parameters that
-- depend on another parameter are only processed if that parameter is present,
-- to avoid phantom references appearing in article reference lists.
local function parseDataParameters()
preprocessSingleArg('autoheaders')
preprocessSingleArg('child')
preprocessSingleArg('bodyclass')
preprocessSingleArg('subbox')
preprocessSingleArg('bodystyle')
preprocessSingleArg('title')
preprocessSingleArg('titleclass')
preprocessSingleArg('titlestyle')
preprocessSingleArg('above')
preprocessSingleArg('aboveclass')
preprocessSingleArg('abovestyle')
preprocessArgs({
{prefix = 'subheader', depend = {'subheaderstyle', 'subheaderrowclass'}}
}, 10)
preprocessSingleArg('subheaderstyle')
preprocessSingleArg('subheaderclass')
preprocessArgs({
{prefix = 'image', depend = {'caption', 'imagerowclass'}}
}, 10)
preprocessSingleArg('captionstyle')
preprocessSingleArg('imagestyle')
preprocessSingleArg('imageclass')
preprocessArgs({
{prefix = 'header'},
{prefix = 'data', depend = {'label'}},
{prefix = 'rowclass'},
{prefix = 'rowstyle'},
{prefix = 'rowcellstyle'},
{prefix = 'class'}
}, 50)
preprocessSingleArg('headerclass')
preprocessSingleArg('headerstyle')
preprocessSingleArg('labelstyle')
preprocessSingleArg('datastyle')
preprocessSingleArg('below')
preprocessSingleArg('belowclass')
preprocessSingleArg('belowstyle')
preprocessSingleArg('name')
-- different behaviour for italics if blank or absent
args['italic title'] = origArgs['italic title']
preprocessSingleArg('decat')
preprocessSingleArg('templatestyles')
preprocessSingleArg('child templatestyles')
preprocessSingleArg('grandchild templatestyles')
end
-- If called via #invoke, use the args passed into the invoking template.
-- Otherwise, for testing purposes, assume args are being passed directly in.
function p.infobox(frame)
if frame == mw.getCurrentFrame() then
origArgs = frame:getParent().args
else
origArgs = frame
end
parseDataParameters()
return _infobox()
end
-- For calling via #invoke within a template
function p.infoboxTemplate(frame)
origArgs = {}
for k,v in pairs(frame.args) do origArgs[k] = mw.text.trim(v) end
parseDataParameters()
return _infobox()
end
return p
smlunuofv2cc43booczlrtig5apgpn9
Modul:Infobox/sandbox/styles.css
828
33875
159003
2026-10-10T16:45:07Z
Rachmat04
7338
Geupeugöt laman ngön asoë '/* {{pp|small=y}} */ /* * This TemplateStyles sheet deliberately does NOT include the full set of * infobox styles. We are still working to migrate all of the manual * infoboxes. See [[MediaWiki talk:Common.css/to do#Infobox]] * DO NOT ADD THEM HERE */ /* * not strictly certain these styles are necessary since the modules now * exclusively output infobox-subbox or infobox, not both * just replicating the module faithfully */ .infobox-subbox { padding...'
159003
sanitized-css
text/css
/* {{pp|small=y}} */
/*
* This TemplateStyles sheet deliberately does NOT include the full set of
* infobox styles. We are still working to migrate all of the manual
* infoboxes. See [[MediaWiki talk:Common.css/to do#Infobox]]
* DO NOT ADD THEM HERE
*/
/*
* not strictly certain these styles are necessary since the modules now
* exclusively output infobox-subbox or infobox, not both
* just replicating the module faithfully
*/
.infobox-subbox {
padding: 0;
border: none;
margin: -3px;
width: auto;
min-width: 100%;
font-size: 100%;
clear: none;
float: none;
background-color: transparent;
}
.infobox-3cols-child {
margin: auto;
}
.infobox .navbar {
font-size: 100%;
}
/* Dark theme: [[William_Wragg]], [[Coral_Castle]] */
@media screen {
html.skin-theme-clientpref-night .infobox-full-data:not(.notheme) > div:not(.notheme)[style] {
background: #1f1f23 !important;
/* switch with var( --color-base ) when supported. */
color: #f8f9fa;
}
}
@media screen and ( prefers-color-scheme: dark) {
html.skin-theme-clientpref-os .infobox-full-data:not(.notheme) div:not(.notheme) {
background: #1f1f23 !important;
/* switch with var( --color-base ) when supported. */
color: #f8f9fa;
}
}
/* Since infobox is a table, many infobox templates take advantage of this to add columns and rows to the infobox itself rather than as part of a new table inside them. This class should be discouraged and removed on the long term, but allows us to at least identify these tables going forward
Currently in use on: [[Module:Infobox3cols]]
Fixes issue described in https://phabricator.wikimedia.org/F55300125 on Vector 2022.
*/
@media (min-width: 640px) {
body.skin--responsive .infobox-table {
display: table !important;
}
body.skin--responsive .infobox-table > caption {
display: table-caption !important;
}
body.skin--responsive .infobox-table > tbody {
display: table-row-group;
}
body.skin--responsive .infobox-table tr {
display: table-row !important;
}
body.skin--responsive .infobox-table th,
body.skin--responsive .infobox-table td {
padding-left: inherit;
padding-right: inherit;
}
}
2pxfxg7rwc3jv0w8wyi0wqelqle32m2
Seunaleuëk:Speciesbox/parameterCheck
10
33876
159007
2026-10-10T16:51:28Z
Rachmat04
7338
Geupeugöt laman ngön asoë '<noinclude>{{pp-template|small=yes}}</noinclude>{{#ifeq:{{NAMESPACENUMBER}}|0|{{#if:{{{1|}}}|{{#if:{{{2|}}}{{{3|}}}|[[Category:Speciesboxes with incorrect parameters specifying the taxon]]|{{Speciesbox/checkgenus|{{Speciesbox/getGenus|{{{1}}}|}}}}}}|{{#if:{{{2|}}}|{{#if:{{{3|}}}|{{Speciesbox/checkgenus|{{{2}}}}}|[[Category:Speciesboxes with incorrect parameters specifying the taxon]]}}|{{#if:{{{3|}}}|Category:Speciesboxes with incorrect parameters specifying...'
159007
wikitext
text/x-wiki
<noinclude>{{pp-template|small=yes}}</noinclude>{{#ifeq:{{NAMESPACENUMBER}}|0|{{#if:{{{1|}}}|{{#if:{{{2|}}}{{{3|}}}|[[Category:Speciesboxes with incorrect parameters specifying the taxon]]|{{Speciesbox/checkgenus|{{Speciesbox/getGenus|{{{1}}}|}}}}}}|{{#if:{{{2|}}}|{{#if:{{{3|}}}|{{Speciesbox/checkgenus|{{{2}}}}}|[[Category:Speciesboxes with incorrect parameters specifying the taxon]]}}|{{#if:{{{3|}}}|[[Category:Speciesboxes with incorrect parameters specifying the taxon]]|[[Category:Speciesboxes relying on page title]]}}}}}}}}<noinclude>{{documentation}}</noinclude>
bfftsh4ojs2pofxc3dlqrghlf3civy1
Seunaleuëk:Speciesbox/name
10
33877
159008
2026-10-10T16:52:07Z
Rachmat04
7338
Geupeugöt laman ngön asoë '<noinclude><!--Parameters: 1=name, 2=taxon, 3=genus, 4=species, 5=PAGENAMEBASE, 6=italic_title (obey no) --></noinclude><includeonly>{{#invoke:Automated taxobox|speciesboxName|{{{1|}}}|{{{2|}}}|{{{3|}}}|{{{4|}}}|{{{5|}}}|{{{6|}}}}}</includeonly><noinclude>{{documentation}}</noinclude>'
159008
wikitext
text/x-wiki
<noinclude><!--Parameters: 1=name, 2=taxon, 3=genus, 4=species, 5=PAGENAMEBASE, 6=italic_title (obey no)
--></noinclude><includeonly>{{#invoke:Automated taxobox|speciesboxName|{{{1|}}}|{{{2|}}}|{{{3|}}}|{{{4|}}}|{{{5|}}}|{{{6|}}}}}</includeonly><noinclude>{{documentation}}</noinclude>
7c69z3c95uj8fuq6jywzqscgk1l1qru
Seunaleuëk:Taxon info
10
33878
159009
2026-10-10T16:52:31Z
Rachmat04
7338
Geupeugöt laman ngön asoë '{{#invoke:Autotaxobox|taxonInfo|{{{1|<noinclude>Acacia</noinclude>}}}|{{{2|<noinclude>parent</noinclude>}}}}}<noinclude>{{documentation}}</noinclude>'
159009
wikitext
text/x-wiki
{{#invoke:Autotaxobox|taxonInfo|{{{1|<noinclude>Acacia</noinclude>}}}|{{{2|<noinclude>parent</noinclude>}}}}}<noinclude>{{documentation}}</noinclude>
81398n6a16baqofp8mue2gyw3jh5xdx
Seunaleuëk:Taxon italics
10
33879
159010
2026-10-10T16:53:09Z
Rachmat04
7338
Geupeugöt laman ngön asoë '{{#invoke:TaxonItalics|main|{{{1|<noinclude>Homo sapiens</noinclude>}}}|abbreviated={{{abbreviated|no}}}|linked={{{linked|no}}}}}<noinclude> {{Documentation}} </noinclude>'
159010
wikitext
text/x-wiki
{{#invoke:TaxonItalics|main|{{{1|<noinclude>Homo sapiens</noinclude>}}}|abbreviated={{{abbreviated|no}}}|linked={{{linked|no}}}}}<noinclude>
{{Documentation}}
</noinclude>
s6sde18ux7dt230781bpz8ljyslnn19
Seunaleuëk:Taxonomy/Acacia
10
33880
159011
2026-10-10T16:54:21Z
Rachmat04
7338
Geupeugöt laman ngön asoë '{{Don't edit this line {{{machine code|}}} |rank=genus |link=Acacia |parent=Mimosoid clade |refs={{cite journal | author = The Legume Phylogeny Working Group (LPWG). | year = 2017 | title = A new subfamily classification of the Leguminosae based on a taxonomically comprehensive phylogeny | journal = [[Taxon (journal)|Taxon]] | volume = 66 | issue = 1 | pages = 44–77 | doi = 10.12705/661.3| doi-access = free }} }}'
159011
wikitext
text/x-wiki
{{Don't edit this line {{{machine code|}}}
|rank=genus
|link=Acacia
|parent=Mimosoid clade
|refs={{cite journal | author = The Legume Phylogeny Working Group (LPWG). | year = 2017 | title = A new subfamily classification of the Leguminosae based on a taxonomically comprehensive phylogeny | journal = [[Taxon (journal)|Taxon]] | volume = 66 | issue = 1 | pages = 44–77 | doi = 10.12705/661.3| doi-access = free }}
}}
h6a9ifb8o7yfr1cdst0s67tf8ahtbc2
Modul:Automated taxobox
828
33881
159012
2026-10-10T16:54:51Z
Rachmat04
7338
Geupeugöt laman ngön asoë 'require('strict') local TaxonItalics = require('Module:TaxonItalics') local Autotaxobox = require('Module:Autotaxobox') local ItalicTitle = require('Module:Italic title') local p = {} -- functions made public local l = {} -- nonpublic internal functions and variables global to the module l.system = '' -- '' for normal scientific classification (default) -- 'ichnos' for trace fossil classification -- 'veterovata' for egg fossil class...'
159012
Scribunto
text/plain
require('strict')
local TaxonItalics = require('Module:TaxonItalics')
local Autotaxobox = require('Module:Autotaxobox')
local ItalicTitle = require('Module:Italic title')
local p = {} -- functions made public
local l = {} -- nonpublic internal functions and variables global to the module
l.system = '' -- '' for normal scientific classification (default)
-- 'ichnos' for trace fossil classification
-- 'veterovata' for egg fossil classification
-- =============================================================================
-- ichnobox implements Template:Ichnobox; see the documentation of that
-- template for details.
-- The only difference from Template:Automatic taxobox is in the taxobox colour
-- and classification link and the parameters for type species and genera.
-- =============================================================================
function p.ichnobox(frame)
l.system = 'ichnos'
return p.automaticTaxobox(frame)
end
-- =============================================================================
-- oobox implements Template:Oobox; see the documentation of that
-- template for details.
-- The only difference from Template:Automatic taxobox is in the taxobox colour
-- and classification link and the parameters for type species and genera.
-- =============================================================================
function p.oobox(frame)
l.system = 'veterovata'
return p.automaticTaxobox(frame)
end
-- =============================================================================
-- automaticTaxobox implements Template:Automatic taxobox; see the documentation
-- of that template for details.
-- It also implements Template:Ichnobox and Template:Oobox. The small
-- differences are signalled by the module-wide variable l.system.
-- The following parameters present in the old template code version of
-- Template:Automatic taxobox were not used and have not been implemented:
-- image_caption_align
-- image2_caption_align
-- binomial2
-- binomial2_authority
-- binomial3
-- binomial3_authority
-- binomial4
-- binomial4_authority
-- =============================================================================
function p.automaticTaxobox(frame)
local args
if frame.args['direct'] == 'yes' then args = frame.args
else args = frame:getParent().args end
local res = ''
-- ---------------------------------------------------------------------
-- pick up taxobox parameters from the caller that need to be processed;
-- most will be passed on unchanged
-- ---------------------------------------------------------------------
local pagename = args['pagename'] or '' -- for testing and debugging only
local italicTitle = args['italic_title'] or args['italic title'] or ''
local ichnos = ''
if l.system == 'ichnos' then ichnos = 'true' end
local veterovata = ''
if l.system == 'veterovata' then veterovata = 'true' end
local fossilRange = args['fossil_range'] or args['fossil range'] or args['temporal_range'] or args['temporal range'] or ''
local oldestFossil = args['oldest_fossil'] or args['oldest fossil'] or ''
local youngestFossil = args['youngest_fossil'] or args['youngest fossil'] or ''
local name = args['name'] or ''
local colourAs = args['color_as'] or args['color as'] or args['colour_as'] or args['colour as'] or ''
local taxon = args['taxon'] or ''
local authority = args['authority'] or ''
local parentAuthority = args['parent_authority'] or args['parent authority'] or ''
local manualFlag = 'text' -- marks manually specified ranks
local binomial = args['binomial'] or args['binomial_'..manualFlag] or args['binomial '..manualFlag] or ''
local binomialAuthority = args['binomial_authority'] or args['binomial authority'] or ''
local genusManual = args['genus_'..manualFlag] or args['genus '..manualFlag] or''
local speciesManual = args['species_'..manualFlag] or args['species '..manualFlag] or''
-- ------------------------------------------------------
-- set the taxobox parameters determined by this function
-- ------------------------------------------------------
fossilRange = l.setfossilRange(frame, fossilRange, oldestFossil, youngestFossil)
-- use the base page name as the taxon if the taxon parameter is missing
local currentPagename = mw.title.getCurrentTitle()
if pagename == '' then pagename = currentPagename.text end -- pagename para only used in testing and
local basePagename = pagename
if italicTitle ~= 'taxon' then basePagename = mw.ustring.gsub(basePagename, '%s+%b()$', '', 1) end
local taxonParaMissingError = false
if taxon == '' then
taxonParaMissingError = true
taxon = basePagename
end
-- decide if the page name and taxobox name need to be italicized;
-- if italic_title is not set, then if the names are the taxon, use its rank to decide
local ok, taxonRank = Autotaxobox.getTaxonInfoItem(frame, taxon, 'rank') -- taxonRank needed later if not here
if italicTitle == '' then
if not (ok and taxonRank ~= '' and
frame:expandTemplate{ title = 'Is italic taxon', args = {taxonRank} } == 'yes') then
italicTitle = 'no'
end
end
-- remove any " (DISAMBIG)" or "/MODIFIER" from the taxon's name;
-- if the base page name is the same as the base taxon name, then italicization can be applied
local baseTaxon = taxon
if italicTitle ~= 'taxon' then baseTaxon = mw.ustring.gsub(baseTaxon, '%s+%b()$', '', 1) end
baseTaxon = mw.ustring.gsub(baseTaxon, '/.*$', '', 1)
if italicTitle == '' and basePagename == baseTaxon then
italicTitle = 'yes'
end
-- italicize the page name (page title) if required
if currentPagename.namespace == 0 and (italicTitle == 'yes' or italicTitle == 'taxon') then
if italicTitle == 'taxon' or TaxonItalics.hasConnectingTerm(baseTaxon) then
res = res .. frame:expandTemplate{ title = 'Italic taxon title', args = {} }
italicTitle = 'yes'
else ItalicTitle._main({})
end
end
-- set the taxobox name if not supplied, italicizing it if appropriate.
if name == '' then
name = basePagename
if italicTitle == 'yes' then
name = TaxonItalics.italicizeTaxonName(name, false, false)
end
-- name = name .. '/' .. baseTaxon .. '/' .. nameRank
end
-- determine taxobox colour
local colour = ''
if colourAs ~= '' then
colour = frame:expandTemplate{ title = 'Taxobox colour', args = {colourAs} }
elseif l.system == 'ichnos' then
colour = frame:expandTemplate{ title = 'Taxobox colour', args = {'Ichnos'} }
elseif l.system == 'veterovata' then
colour = frame:expandTemplate{ title = 'Taxobox colour', args = {'Veterovata'} }
else
colour = Autotaxobox.getTaxoboxColour(frame, taxon)
end
-- set binomial parameters if the target taxon is (unusually) a species
local genusAuthority = ''
if binomial == '' then
if ok and taxonRank == 'species' then
binomial = TaxonItalics.italicizeTaxonName(taxon, false, false)
binomialAuthority = authority
end
end
-- handle any manually set ranks
local boldFirst = ''
local offset = 0
if speciesManual ~= '' then
offset = offset + 1
binomialAuthority = authority
if binomial == '' then binomial = '<span class="error">Error: binomial parameter value is missing</span>' end
end
if genusManual ~= '' then
boldFirst = 'link'
offset = offset + 1
if offset == 1 then
genusAuthority = authority
else
genusAuthority = parentAuthority
end
end
-- process type genus and type species if present; italicize if they seem not to have an authority attached
local typeGenus = ''
local typeGenusRef = ''
local typeGenusAuthority = ''
local typeSpecies = ''
local typeSpeciesRef = ''
local typeSpeciesAuthority = ''
local typeIchnogenus = ''
local typeIchnogenusRef = ''
local typeIchnogenusAuthority = ''
local typeIchnospecies = ''
local typeIchnospeciesRef = ''
local typeIchnospeciesAuthority = ''
local typeOogenus = ''
local typeOogenusRef = ''
local typeOogenusAuthority = ''
local typeOospecies = ''
local typeOospeciesRef = ''
local typeOospeciesAuthority = ''
if l.system == '' then
typeGenus = l.italicizeTypeName(args['type_genus'] or args['type genus'] or '')
typeGenusRef = args['type_genus_ref'] or args['type genus ref'] or ''
typeGenusAuthority = args['type_genus_authority'] or args['type genus authority'] or ''
typeSpecies = l.italicizeTypeName(args['type_species'] or args['type species'] or '')
typeSpeciesRef = args['type_species_ref'] or args['type species ref'] or ''
typeSpeciesAuthority = args['type_species_authority'] or args['type species authority'] or ''
elseif l.system == 'ichnos' then
typeIchnogenus = l.italicizeTypeName(args['type_ichnogenus'] or args['type ichnogenus'] or '')
typeIchnogenusRef = args['type_ichnogenus_ref'] or args['type ichnogenus ref'] or ''
typeIchnogenusAuthority = args['type_ichnogenus_authority'] or args['type ichnogenus authority'] or ''
typeIchnospecies = l.italicizeTypeName(args['type_ichnospecies'] or args['type ichnospecies'] or '')
typeIchnospeciesRef = args['type_ichnospecies_ref'] or args['type ichnospecies ref'] or ''
typeIchnospeciesAuthority = args['type_ichnospecies_authority'] or args['type ichnospecies authority'] or ''
elseif l.system == 'veterovata' then
typeOogenus = l.italicizeTypeName(args['type_oogenus'] or args['type oogenus'] or '')
typeOogenusRef = args['type_oogenus_ref'] or args['type oogenus ref'] or ''
typeOogenusAuthority = args['type_oogenus_authority'] or args['type oogenus authority'] or ''
typeOospecies = l.italicizeTypeName(args['type_oospecies'] or args['type oospecies'] or '')
typeOospeciesRef = args['type_oospecies_ref'] or args['type oospecies ref'] or ''
typeOospeciesAuthority = args['type_oospecies_authority'] or args['type oospecies authority'] or ''
end
-- fill in a missing subdivision_ranks parameter
local subdivision = args['subdivision'] or ''
local subdivisionRef = args['subdivision_ref'] or args['subdivision ref'] or ''
local subdivisionRanks = args['subdivision_ranks'] or args['subdivision ranks'] or ''
if subdivision ~= '' and subdivisionRanks == '' and ok and taxonRank ~= '' then
subdivisionRanks = frame:expandTemplate{ title = 'Children rank', args = {taxonRank} }
end
-- ------------------------------------------------
-- now call Taxobox/core with all of its parameters
-- ------------------------------------------------
res = res .. frame:expandTemplate{ title = 'Taxobox/core', args =
{ ichnos = ichnos,
veterovata = veterovata,
['edit link'] = 'e',
temporal_range = fossilRange,
display_taxa = args['display_parents'] or args['display parents'] or '1',
parent = taxon,
authority = authority,
parent_authority = parentAuthority,
grandparent_authority = args['grandparent_authority'] or args['grandparent authority'] or '',
greatgrandparent_authority = args['greatgrandparent_authority'] or args['greatgrandparent authority'] or '',
greatgreatgrandparent_authority = args['greatgreatgrandparent_authority'] or args['greatgreatgrandparent authority'] or '',
name = name,
colour = colour,
status = args['status'] or '',
status_system = args['status_system'] or args['status system'] or '',
status_ref = args['status_ref'] or args['status ref'] or '',
status2 = args['status2'] or '',
status2_system = args['status2_system'] or args['status2 system'] or '',
status2_ref = args['status2_ref'] or args['status2 ref'] or '',
trend = args['trend'] or '',
extinct = args['extinct'] or '',
image = args['image'] or '',
upright = args['image_upright'] or args['image upright'] or '',
image_alt = args['image_alt'] or args['image alt'] or '',
image_caption = args['image_caption'] or args['image caption'] or '',
image2 = args['image2'] or '',
upright2 = args['image2_upright'] or args['image2 upright'] or '',
image2_alt = args['image2_alt'] or args['image2 alt'] or '',
image2_caption = args['image2_caption'] or args['image2 caption'] or '',
audio = args['audio'] or '',
audio_alt = args['audio_alt'] or args['audio alt'] or '',
audio_caption = args['audio_caption'] or args['audio caption'] or '',
classification_status = args['classification_status'] or args['classification status'] or '',
diversity = args['diversity'] or '',
diversity_ref = args['diversity_ref'] or args['diversity ref'] or '',
diversity_link = args['diversity_link'] or args['diversity link'] or '',
bold_first = boldFirst,
offset = offset,
genus = genusManual,
genus_authority = genusAuthority,
species = speciesManual,
binomial = binomial,
binomial_authority = binomialAuthority,
trinomial = args['trinomial'] or '',
trinomial_authority = args['trinomial_authority'] or args['trinomial authority'] or '',
type_genus = typeGenus,
type_genus_ref = typeGenusRef,
type_genus_authority = typeGenusAuthority,
type_species = typeSpecies,
type_species_ref = typeSpeciesRef,
type_species_authority = typeSpeciesAuthority,
type_ichnogenus = typeIchnogenus,
type_ichnogenus_ref = typeIchnogenusRef,
type_ichnogenus_authority = typeIchnogenusAuthority,
type_ichnospecies = typeIchnospecies,
type_ichnospecies_ref = typeIchnospeciesRef,
type_ichnospecies_authority = typeIchnospeciesAuthority,
type_oogenus = typeOogenus,
type_oogenus_ref = typeOogenusRef,
type_oogenus_authority = typeOogenusAuthority,
type_oospecies = typeOospecies,
type_oospecies_ref = typeOospeciesRef,
type_oospecies_authority = typeOospeciesAuthority,
subdivision = subdivision,
subdivision_ref = subdivisionRef,
subdivision_ranks = subdivisionRanks,
type_strain = args['type_strain'] or args['type strain'] or '',
type_strain_ref = args['type_strain_ref'] or args['type strain ref'] or '',
range_map = args['range_map'] or args['range map'] or '',
range_map_upright = args['range_map_upright'] or args['range map upright'] or '',
range_map_alt = args['range_map_alt'] or args['range map alt'] or '',
range_map_caption = args['range_map_caption'] or args['range map caption'] or '',
range_map2 = args['range_map2'] or args['range map2'] or '',
range_map2_upright = args['range_map2_upright'] or args['range map2 upright'] or '',
range_map2_alt = args['range_map2_alt'] or args['range map2 alt'] or '',
range_map2_caption = args['range_map2_caption'] or args['range map2 caption'] or '',
range_map3 = args['range_map3'] or args['range map3'] or '',
range_map3_upright = args['range_map3_upright'] or args['range map3 upright'] or '',
range_map3_alt = args['range_map3_alt'] or args['range map3 alt'] or '',
range_map3_caption = args['range_map3_caption'] or args['range map3 caption'] or '',
range_map4 = args['range_map4'] or args['range map4'] or '',
range_map4_upright = args['range_map4_upright'] or args['range map4 upright'] or '',
range_map4_alt = args['range_map4_alt'] or args['range map4 alt'] or '',
range_map4_caption = args['range_map4_caption'] or args['range map4 caption'] or '',
synonyms_ref = args['synonyms_ref'] or args['synonyms ref'] or '',
synonyms = args['synonyms'] or ''
} }
-- put page in error-tracking categories if required
local errCat1 = ''
if genusManual ~= '' or speciesManual ~= '' or binomial ~= '' then errCat1 = '[[Category:Automatic taxoboxes using manual parameters]]' end
local errCat2 = ''
if taxonParaMissingError then errCat2 = '[[Category:Automatic taxoboxes relying on page title]]' end
res = res .. frame:expandTemplate{ title = 'Main other', args = {errCat1..errCat2} }
return res
end
-- =============================================================================
-- l.setfossilRange(frame, fossilRange, oldestFossil, youngestFossil) checks
-- the parameters that determine the fossil range, returning an appropriate
-- range.
-- =============================================================================
-- temporary public function for debugging
function p.chkFossilRange(frame)
local args = frame.args
local fossilRange = args['temporal_range'] or args['temporal range'] or args['fossil_range'] or args['fossil range'] or ''
local oldestFossil = args['oldest_fossil'] or args['oldest fossil'] or ''
local youngestFossil = args['youngest_fossil'] or args['youngest fossil'] or ''
local fossilRange = l.setfossilRange(frame, fossilRange, oldestFossil, youngestFossil)
return fossilRange
end
function l.setfossilRange(frame, fossilRange, oldestFossil, youngestFossil)
local res = ''
if fossilRange ~= '' then
if mw.ustring.find(frame:expandTemplate{ title = 'Period start', args = { fossilRange } }, '[Ee]rror') then
res = fossilRange
else
res = frame:expandTemplate{ title = 'Geological range', args = { fossilRange } }
end
elseif oldestFossil ~= '' then
if youngestFossil == '' then youngestFossil = 'Recent' end
if mw.ustring.find(frame:expandTemplate{ title = 'Period start', args = { oldestFossil } }, '[Ee]rror') or
mw.ustring.find(frame:expandTemplate{ title = 'Period start', args = { youngestFossil } }, '[Ee]rror') then
res = oldestFossil..'–'..youngestFossil
else
res = frame:expandTemplate{ title = 'Geological range', args = { oldestFossil, youngestFossil } }
end
end
return res
end
-- =============================================================================
-- l.italicizeTypeName(typeName) checks whether the name of a type genus or
-- species should be italicized, because it appears to be a bare name.
-- =============================================================================
function l.italicizeTypeName(typeName)
if typeName and not (string.find(typeName, "<", 1, true) or string.find(typeName, ">", 1, true)) then
typeName = TaxonItalics.italicizeTaxonName(typeName, false, false)
end
return typeName
end
-- **************************** Speciesbox support *****************************
-- =============================================================================
-- l.genusOf(str) extracts the genus from a string. Normally this will be the
-- first word of the string (e.g. given 'Bellis perennis' it returns 'Bellis').
-- It also handles a string containing a nothogenus with a spaced × (e.g. given
-- '× Heucherella tiarelloides' it returns '× Heucherella').
-- =============================================================================
function l.genusOf(str)
local res = mw.ustring.match(str, '^[^%s]*', 1)
if res == mw.ustring.char(215) then
res = res .. ' ' .. mw.ustring.match(str, '^[^%s]*', 3)
end
return res
end
-- =============================================================================
-- l.doSpeciesboxName(name, taxon, genus, species, basePageTitle, italicTitle)
-- returns a name for a taxobox created by Template:Speciesbox. The name will be
-- italicized if appropriate. It also generates code to italicize the page title
-- if appropropriate. In both cases the test for italicization is that the base
-- taxon name (stripped of any disambiguation or qualifier) is the same as the
-- base page title.
-- =============================================================================
function p.speciesboxName(frame)
local name = frame.args[1] or ''
local taxon = frame.args[2] or ''
local genus = frame.args[3] or ''
local species = frame.args[4] or ''
local basePageTitle = frame.args[5] or ''
local italicTitle = frame.args[6] or ''
return l.doSpeciesboxName(name, taxon, genus, species, basePageTitle, italicTitle)
end
function l.doSpeciesboxName(name, taxon, genus, species, basePageTitle, italicTitle)
if taxon ~= '' then
genus = mw.ustring.gsub(l.genusOf(taxon), '/.*$', '', 1) -- strip any qualifier
else
genus = mw.ustring.gsub(mw.ustring.gsub(genus, '%s+%b()$', '', 1), '/.*$', '', 1) -- strip any disambig and qualifier
if species == '' then taxon = genus
else taxon = genus .. ' ' .. species
end
end
local italicizeP = italicTitle ~= 'no' and (basePageTitle == taxon or basePageTitle == genus) -- use basePageTitle to match taxon/genus
-- deal with taxobox name (i.e. its caption)
if name == '' then
name = basePageTitle
if italicizeP then name = TaxonItalics.italicizeTaxonName(name, false, false) end
end
-- deal with page title
if italicizeP then
local pageTitle = mw.title.getCurrentTitle().text -- formatting the page title with DISPLAYTITLE needs the full page title
if italicTitle ~= 'test' then
pageTitle = TaxonItalics.italicizeTaxonName(pageTitle, false, false, true) -- format pageTitle, not italicizing any parenthesized term
local nsText = mw.title.getCurrentTitle().nsText -- for drafts and other pages not in mainspace
if nsText ~= '' then
pageTitle = nsText:gsub('_', ' ') .. ':' .. pageTitle -- [[phab:T369784]]
end
mw.getCurrentFrame():callParserFunction('DISPLAYTITLE', pageTitle)
else
name = name .. ' \\Italic title\\ ' .. pageTitle -- for testing and debugging
end
end
return name
end
-- =============================================================================
-- =============================================================================
function p.infraspeciesboxName(frame)
local name = frame.args[1] or ''
local genus = frame.args[2] or ''
local species = frame.args[3] or ''
local ct = frame.args[4] or ''
local infraspecies = frame.args[5] or ''
local basePageTitle = frame.args[6] or ''
local italicTitle = frame.args[7] or ''
return l.doinfraspeciesboxName(name, genus, species, ct, infraspecies, basePageTitle, italicTitle)
end
function l.doinfraspeciesboxName(name, genus, species, ct, infraspecies, basePageTitle, italicTitle)
genus = mw.ustring.gsub(mw.ustring.gsub(genus, '%s+%b()$', '', 1), '/.*$', '', 1) -- strip any disambig and qualifier
local taxon = genus .. ' ' .. species
if ct == '' then taxon = taxon .. ' ' .. infraspecies
else taxon = taxon .. ' ' .. ct .. ' ' .. infraspecies
end
local italicizeP = italicTitle ~= 'no' and (basePageTitle == taxon) -- use basePageTitle to match taxon
-- deal with taxobox name (i.e. its caption)
if name == '' then
name = basePageTitle
if italicizeP then name = TaxonItalics.italicizeTaxonName(name, false, false) end
end
-- deal with page title
if italicizeP then
local pageTitle = mw.title.getCurrentTitle().text -- formatting the page title with DISPLAYTITLE needs the full page title
pageTitle = TaxonItalics.italicizeTaxonName(pageTitle, false, false, true) -- format pageTitle, not italicizing any parenthesized term
if italicTitle ~= 'test' then
mw.getCurrentFrame():callParserFunction('DISPLAYTITLE', pageTitle)
else
name = name .. ' \\Italic title\\ ' .. pageTitle -- for testing and debugging
end
end
return name
end
return p
lfjm728ksq5c87l0ay462czvhkf2xzd
Modul:Autotaxobox
828
33882
159013
2026-10-10T16:55:18Z
Rachmat04
7338
Geupeugöt laman ngön asoë '--[[************************************************************************* 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. ***********************...'
159013
Scribunto
text/plain
--[[*************************************************************************
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.
*****************************************************************************]]
require('strict')
local TaxonRanks = require('Module:Taxobox ranks') -- use functions from Module:Taxobox ranks to handle ranks
local TaxonItalics = require('Module:TaxonItalics') -- use a function from Module:TaxonItalics to italicize a taxon name
local TableRow = '|- class="taxonrow" \n'
local TableEnd = '|}\n'
local p = {} -- functions made public
local l = {} -- internal functions, kept separate
local colour = '' -- colour for taxobox and taxonomy listings
--[[=========================================================================
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.
The value can be obtained externally via
{{#invoke:Autotaxobox|getMaxSearchLevels}}
=============================================================================]]
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)
return p.getTaxoboxColour(frame, frame.args[1] or '')
end
function p.getTaxoboxColour(frame, currTaxon)
-- note that colour is global to this function; default is empty string
local i = 1 -- count levels processed
local searching = currTaxon ~= '' -- still searching for a colour?
local foundICTaxon = false -- record whether 'incertae sedis' found
while searching and i <= MaxSearchLevels do
local plainCurrTaxon, dummy = l.stripExtra(currTaxon) -- remove trailing text after /
if string.lower(plainCurrTaxon) == 'incertae sedis' then
foundICTaxon = true
else
local possibleColour = frame:expandTemplate{ title = '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
if foundICTaxon then
colour = frame:expandTemplate{ title = 'Taxobox colour', args = { 'incertae sedis' } }
elseif searching then
-- hierarchy exceeds MaxSearchLevels levels
colour = frame:expandTemplate{ title = 'Taxobox/Error colour', args = { } }
else
colour = 'transparent'
end
end
return colour
end
--[[= = = = = = = = = = = = = topLevelTaxon = = = = = = = = = = = = = = = =
Defines the correct top level taxa, one of which should terminate every
taxonomic hierarchy encoded in taxonomy templates.
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =]]
function l.topLevelTaxon(taxon)
return taxon == 'Life' or taxon == 'Veterovata' or taxon == 'Ichnos'
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
|gggparent_authority = taxonomic authority for TAXON's greatgreatgrandparent
|ggggparent_authority = taxonomic authority for TAXON's greatgreatgreatgrandparent
|bold_first = 'bold' to bold TAXON in its row
|virus = 'yes' to apply virus taxa italicization standards
}}
=============================================================================]]
function p.taxoboxList(frame)
local currTaxon = frame.args[1] or ''
if currTaxon == '' then return '' end
local displayN = (tonumber(frame.args['display_taxa']) or 1) + 1
local authTable = {}
authTable[1] = frame.args['authority'] or ''
authTable[2] = frame.args['parent_authority'] or ''
authTable[3] = frame.args['gparent_authority'] or ''
authTable[4] = frame.args['ggparent_authority'] or ''
authTable[5] = frame.args['gggparent_authority'] or ''
authTable[6] = frame.args['ggggparent_authority'] or ''
local authTableMax = 6
local boldFirst = frame.args['bold_first'] or 'link' -- values 'link' or 'bold'
local virus = frame.args['virus'] or 'no' -- values 'yes' or 'no'
local offset = tonumber(frame.args['offset'] or 0)
-- adjust the authority table if 'authority' refers to a rank lower than the target taxon
if offset ~= 0 then
for i = 1, authTableMax do
local j = i + offset
if j <= authTableMax then
authTable[i] = authTable[j]
else
authTable[i] = ''
end
end
end
local taxonTable, taxonRankTable = l.makeTable(frame, currTaxon)
local res = ''
local topTaxonN = taxonTable.n
-- display all taxa above possible greatgreatgrandparent, without authority
for i = topTaxonN, authTableMax+1, -1 do
res = res .. l.showTaxon(frame, taxonTable[i], taxonRankTable[i], topTaxonN==i, '', displayN >= i, '', virus)
end
-- display all taxa above possible parent, with authority if given
for i = math.min(topTaxonN, authTableMax), 2, -1 do
res = res .. l.showTaxon(frame, taxonTable[i], taxonRankTable[i], topTaxonN==i, authTable[i], displayN >= i, '', virus)
end
-- display target taxon, always displayed and emboldened
res = res .. l.showTaxon(frame, taxonTable[1], taxonRankTable[1], topTaxonN==1, authTable[1], true, boldFirst, virus)
return res
end
--[[= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
Show one taxon row in a taxobox.
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =]]
function l.showTaxon(frame, taxon, rank, isTopTaxon, auth, force, boldFirst, virus)
-- it's an error if this is the top taxon and it's not a top level taxon (e.g. "Life")
if isTopTaxon then
if l.topLevelTaxon(taxon) then
return '' -- don't display a top level taxon
elseif (mw.title.new('Taxonomy/'..taxon, 'Template') or {}).exists then
-- taxonomy template for this taxon has no parent specified
return frame:expandTemplate{ title = 'Create taxonomy', args = {taxon, msg='Taxonomy template does not specify a parent'} } .. '\n' .. TableRow
else
-- no taxonomy template for this taxon
return frame:expandTemplate{ title = 'Create taxonomy', args = {taxon, msg='Missing taxonomy template'} } .. '\n' .. TableRow
end
else
-- if showing is not already forced, force if it's a principal rank or an authority is specified
force = force or frame:expandTemplate{ title = 'Principal rank', args = {rank} } == 'yes' or
auth ~= ''
if not force then
-- if showing is still not already forced, force if the taxonomy template has 'always_display' set
local ok, alwaysDisplay = p.getTaxonInfoItem(frame, taxon, 'always_display')
force = alwaysDisplay == 'yes' or alwaysDisplay == 'true'
end
if force then
local res = l.tableCell(TaxonRanks.doAngliciseRank(rank, 'no') .. ':')
local bold = 'no'
if boldFirst == 'bold' then bold = 'yes' end
if auth ~= '' then
auth = '<br><small>' .. auth .. '</small>'
end
local res = res .. l.tableCell(l.getTaxonLink(frame, taxon, rank, bold, '', '', virus) .. auth) -- italic, abbreviated
return res .. TableRow
else
return ''
end
end
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 '{|class="infobox biota"\n' .. TableRow .. l.tableCell('') .. l.tableCell('ERROR: no taxon supplied') .. TableEnd
end
local taxonTable, taxonRankTable = l.makeTable(frame, currTaxon)
local lastRankVal = 1000000
local orderOk = true
-- check whether the taxonomy is for viruses; use already determined taxon colour if possible
local virus = 'no'
local taxoColour = colour
if taxoColour == '' then
if taxonTable[taxonTable.n] == 'Ichnos' or taxonTable[taxonTable.n] == 'Veterovata' then
taxoColour = frame:expandTemplate{ title = 'Taxobox colour', args = { taxonTable[taxonTable.n] } }
else
taxoColour = frame:expandTemplate{ title = 'Taxobox colour', args = { taxonTable[taxonTable.n - 1] } }
end
end
if taxoColour == frame:expandTemplate{ title = 'Taxobox colour', args = { 'virus' } } then
virus = 'yes'
end
-- add information message
local res = '<p style="float:right">Bold ranks show taxa that will be shown in taxoboxes<br>because rank is principal or <code>always_display=yes</code>.</p>\n'
-- start table
res = res .. '{| class="infobox biota" style="text-align: left; font-size:100%"\n' .. TableRow .. '! colspan=4 style="text-align: center; color:var(--color-base,#202122); background-color: '
.. taxoColour .. '"|Ancestral taxa\n'
-- deal first with the top level taxon; if there are no errors, it should be Life/Veterovata/Ichnos, which are
-- not displayed
local taxon = taxonTable[taxonTable.n]
if not l.topLevelTaxon(taxon) then
local msg = 'Taxonomy template missing'
if mw.title.new('Taxonomy/'..taxon, 'Template').exists then
msg = 'Parent taxon needed'
end
res = res .. TableRow .. l.tableCell('colspan=2', frame:expandTemplate{title = 'Create taxonomy', args = {taxon, msg = msg}})
end
-- now output the rest of the table
local currRankVal
for i = taxonTable.n-1, 1, -1 do
-- check ranks are in right order in the hierarchy
taxon = taxonTable[i]
local rank = taxonRankTable[i]
currRankVal = TaxonRanks.lookupRankVal(rank)
if currRankVal then
orderOk = currRankVal < lastRankVal
if orderOk then lastRankVal = currRankVal end
else
orderOk = true
end
-- see if the row will be displayed in a taxobox; bold the rank if so
local boldRank = false
local ok, alwaysDisplay = p.getTaxonInfoItem(frame, taxon, 'always_display')
if ok and (alwaysDisplay == 'yes' or alwaysDisplay == 'true') then
boldRank = true
else
boldRank = frame:expandTemplate{ title = 'Principal rank', args = {rank} } == 'yes'
end
-- now return a row of the taxonomy table with anomalous ranks marked
local errorStr = ''
if not orderOk then errorStr = 'yes' end
local link = l.getTaxonLink(frame, taxon, rank, '', '', '', virus) -- bold, italic, abbreviated
res = res .. l.taxonomyListRow(frame, taxon, rank, link, boldRank, errorStr)
end
-- close table
res = res .. TableEnd
-- error-tracking for taxonomy templates
-- if the last row has an anomalous rank, put the page in an error-tracking category
local errCat1 = ''
if not orderOk then
errCat1 = '[[Category:Taxonomy templates showing anomalous ranks]]\n'
end
-- if the last row has a taxon name in the page name that does not match the link text,
-- put the taxonomy template in a tracking category
local dummy, linkText = p.getTaxonInfoItem(frame, taxon, 'link_text')
local match = l.matchTaxonLink(taxon, linkText, currRankVal and currRankVal < TaxonRanks.lookupRankVal('genus'))
local errCat2 = ''
if not match then
errCat2 = '[[Category:Taxonomy templates with name and link text not matching|' .. taxon .. ']]\n'
end
if errCat1..errCat2 ~= '' then
res = res .. frame:expandTemplate{ title = 'Template other', args = { errCat1..errCat2} }
end
return res
end
--[[ = = = = = = = = = = = = = = taxonomyListRow = = = = = = = = = = = = = =
Returns a single row of the taxonomy table displayed on the right hand side
of "Template:Taxonomy...." pages.
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =]]
function l.taxonomyListRow(frame, taxon, rank, link, boldRank, error)
local res = ''
if taxon == '' or rank == '' then return res end
local baseTaxon, qualifier = l.stripExtra(taxon)
-- if appropriate, make it clear that some taxa have been skipped via a ... row
if qualifier == '/skip' then
res = res .. TableRow .. l.tableCell('.....') .. l.tableCell('.....')
end
-- now generate a row of the table
res = res .. TableRow
local cellContent = ''
local anglicizedRank = TaxonRanks.doAngliciseRank(rank, 'no')
if boldRank then
cellContent = cellContent .. '<b>' .. anglicizedRank .. '</b>:'
else
cellContent = cellContent .. anglicizedRank .. ':'
end
if error == 'yes' then
cellContent = '<span style="background-color:#FDD">' .. cellContent .. '</span>'
end
res = res .. l.tableCell(cellContent)
.. l.tableCell('<span style="white-space:nowrap;">' .. link .. '</span>')
.. l.tableCell('<span style="font-size:smaller;white-space:nowrap;">' .. qualifier .. '</span>')
.. l.tableCell('<span style="white-space:nowrap;">' .. frame:expandTemplate{ title = 'Edit a taxon', args = { taxon } } .. '</span>')
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 PARENT = 1
local RANK = 2
local LINK_TARGET = 3
local LINK_TEXT = 4
local ALWAYS_DISPLAY = 5
local EXTINCT = 6
local SAME_AS = 7
local REFS = 8
function p.callTaxonomyKey(frame)
local taxon = frame.args['taxon'] or ''
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
-- check consistency of extinct status; if this taxon is not extinct, parent must not be either
local extinctError = 'no'
if parent ~= '' and (extinct == '' or extinct == 'no' or extinct == 'false') then
local ok, parentExtinct = p.getTaxonInfoItem(frame, parent, 'extinct')
if ok and (parentExtinct == 'yes' or parentExtinct == 'true') then extinctError = 'yes' end
end
return frame:expandTemplate{ title = 'Taxonomy key',
args = {taxon=taxon, parent=parent, rank=rank, extinct=extinct, always_display=alwaysDisplay, link_target=linkTarget, link=link, refs=refs, same_as=sameAsTaxon, extinct_error = extinctError} }
end
--[[============================= showRefs ==================================
Shows the refs field in a taxonomy template, handing incertae sedis taxa and
using '–' for absent refs.
Usage: {{#invoke:Autotaxobox|showRefs|TAXON|REFS}}
=============================================================================]]
function p.showRefs(frame)
local taxonName = frame.args[1] or ''
local refs = frame.args[2] or ''
return l.doShowRefs(taxonName, refs)
end
--[[= = = = = = = = = = = = = = doShowRefs = = = = = = = = = = = = = = = = =
Show the refs field in a taxonomy template.
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =]]
function l.doShowRefs(taxonName, refs)
if mw.text.split(taxonName, '/', true)[1] == 'Incertae sedis' then
refs = 'not applicable (<i>incertae sedis</i>)'
elseif refs == '' then
refs = '–'
end
return refs
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', '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
--[[= = = = = = = = = = = getTaxonInfoItem = = = = = = = = = = = = = = = = =
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)
local ok, info
-- item == 'dagger' is a 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 ~= 'dagger'
else
ok, info = pcall(frame.expandTemplate, frame, { title = 'Taxonomy/' .. taxon, args = {['machine code'] = item } })
if ok then
if info == '' then
-- try 'same as'
local sameAsTaxon = frame:expandTemplate{ title = 'Taxonomy/' .. taxon, args = {['machine code'] = 'same as' } }
if sameAsTaxon ~= '' then
ok, info = pcall(frame.expandTemplate, frame, { title = 'Taxonomy/' .. sameAsTaxon, args = {['machine code'] = item } })
end
end
end
end
if ok then
-- if item is 'link_text', trim info and check whether '(?)' needs to be added
if item == 'link_text' then
-- there is a newline at the end of linkText when taxonomy template has "|link = LINK_TARGET|LINK_TEXT"
info = mw.text.trim(info)
if string.sub(taxon, -2) == '/?' and not string.find(info, '?', 1, true) then
info = info .. '<span style="font-style:normal;font-weight:normal;"> (?)</span>'
end
end
else
info = '[[Template:Taxonomy/' .. taxon .. ']]' --error indicator in code before conversion to Lua
end
return ok, 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 abbreviated = frame.args['abbreviated'] 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
return l.makeLink(taxon, extinct, bold, italic, abbreviated, linkTarget, linkText)
end
--[[= = = = = = = = = = = = = = getTaxonLink = = = = = = = = = = = = = = = =
Internal function to drive l.makeLink().
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =]]
function l.getTaxonLink(frame, taxon, rank, bold, italic, abbreviated, virus)
local ok, extinct = p.getTaxonInfoItem(frame, taxon, 'extinct')
if italic == '' then
italic = frame:expandTemplate{ title = 'Is italic taxon', args = { rank, virus = virus } }
end
local ok, linkTarget = p.getTaxonInfoItem(frame, taxon, 'link_target')
local ok, linkText = p.getTaxonInfoItem(frame, taxon, 'link_text')
return l.makeLink(taxon, extinct, bold, italic, abbreviated, linkTarget, linkText)
end
--[[= = = = = = = = = = = = = = makeLink = = = = = = = = = = = = = = = = = =
Actually make the link.
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =]]
function l.makeLink(taxon, extinct, bold, italic, abbreviated, linkTarget, linkText)
local dummy
-- 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, dummy = l.stripExtra(taxon)
end
end
if linkTarget == '' then linkTarget = linkText end
if italic == 'yes' then linkText = TaxonItalics.italicizeTaxonName(linkText, false, abbreviated=='yes') 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
--[[============================== 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
--[[============================ hasRankVal =================================
External utility function to determine whether the rank has an arbitrary
value attached in order to allow rank order consistency checking.
Usage: {{#invoke:Autotaxobox|hasRankVal|RANK}}
=============================================================================]]
function p.hasRankVal(frame)
local rank = frame.args[1] or ''
if rank == '' then return '<span class="error">no rank supplied</span>' end
local rankVal = TaxonRanks.lookupRankVal(rank)
if not rankVal then rankVal = 'no' else rankVal = 'yes' end
return rankVal
end
--[[=========================== hasRankVal1 =================================
External utility function to determine whether the rank has an arbitrary
value attached in order to allow rank order consistency checking.
Usage: {{#invoke:Autotaxobox|hasRankVal|RANK}}
=============================================================================]]
function p.hasRankVal1(rank)
if rank == '' then return 'no' end
local rankVal = TaxonRanks.lookupRankVal(rank)
if not rankVal then rankVal = 'no' else rankVal = 'yes' end
return rankVal
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 l.doListAll(l.makeTable(frame, currTaxon))
end
function l.doListAll(taxonTable, taxonRankTable)
local lst = taxonTable[1] .. '-' .. tostring(taxonRankTable[1])
for i = 2, taxonTable.n, 1 do
lst = lst .. ', ' .. taxonTable[i] .. '-' .. taxonRankTable[i]
end
return lst
end
--[[=========================== removeQualifier ================================
External utility function to remove a qualifier (any part after a "/") from a
taxon name.
Usage: {{#invoke:Autotaxobox|removeQualifier|TAXON}}
=============================================================================]]
function p.removeQualifier(frame)
local baseName, qualifier = l.stripExtra(frame.args[1])
return baseName
end
--[[=========================================================================
Internal functions
=============================================================================]]
--[[= = = = = = = = = = = = stripExtra = = = = = = = = = = = = = = = = = = =
Internal utility function to strip off any extra parts of a taxon name, i.e.
anything after a '/'. Thus 'Felidae/?' would be split into 'Felidae' and '?'.
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =]]
function l.stripExtra(taxonName)
local i = mw.ustring.find(taxonName, '/', 1, true)
if i then
return mw.ustring.sub(taxonName, 1, i-1), mw.ustring.sub(taxonName, i, -1)
else
return taxonName, ''
end
end
--[[= = = = = = = = = = = = splitTaxonName = = = = = = = = = = = = = = = = =
Internal utility function to split a taxon name into its parts and return
them. Possible formats include:
* taxon
* taxon (disambig)
* taxon (Subgenus)
* taxon/qualifier
* combinations, e.g. taxon (disambig)/qualifier
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =]]
function l.splitTaxonName(taxon)
-- get any qualifier present
local qualifier = ''
local i = mw.ustring.find(taxon, '/', 1, true)
if i then
qualifier = mw.ustring.sub(taxon, i+1, -1)
taxon = mw.ustring.sub(taxon, 1, i-1)
end
-- get any disambiguator or subgenus
local disambig = ''
local subgenus = ''
i = mw.ustring.find(taxon, ' (', 1, true)
if i then
local parenTerm = mw.ustring.sub(taxon, i+2, -2)
taxon = mw.ustring.sub(taxon, 1, i-1)
local char1 = mw.ustring.sub(parenTerm, 1, 1)
if char1 == mw.ustring.lower(char1) then
disambig = parenTerm
else
subgenus = parenTerm
end
end
return taxon, disambig, subgenus, qualifier
end
--[[= = = = = = = = = = = = matchTaxonLink = = = = = = = = = = = = = = = = =
Function to determine whether the taxon name derived from the name of the
taxonomy template (passed in the parameter taxon) matches the link text
(passed in the parameter linkText).
The taxon name may have any of the formats:
* baseTaxon/qualifier
* baseTaxon (disambig)
* baseTaxon (Subgenus) [distinguished by the capital letter]
* a qualifier may be present after the previous two formats.
Examples of matches (baseTaxon ~ linkText):
* Pinus ~ Pinus
* Pinus sect. Trifoliae ~ Pinus sect. Trifoliae
* Pinus sect. Trifoliae ~ ''Pinus'' sect. ''Trifoliae'' [italic markers ignored]
* Pinus sect. Trifoliae ~ P. sect. Trifoliae [abbreviated genus name matches]
* Bombus (Pyrobombus) ~ Bombus (Pyrobombus)
* Bombus (Pyrobombus) ~ B. (Pyrobombus)
* Bombus (Pyrobombus) ~ Pyrobombus [link text may just be the subgenus]
* Heteractinida ~ "Heteractinida" [double-quotes are ignored in link text]
* "Heteractinida" ~ Heteractinida [double-quotes are ignored in base taxon name]
* Incertae sedis ~ anything [link text is ignored for matching in this case]
* Cetotheriidae with qualifier=? ~ Cetotheriidae (?)
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =]]
function l.matchTaxonLink(taxon, linkText, rankBelowGenus)
local dummy
linkText, dummy = mw.ustring.gsub(linkText, "''", '') -- remove any italic wikitext in the link text
linkText, dummy = mw.ustring.gsub(linkText, '<.->', '') -- strip all tags used to format the link text
linkText, dummy = mw.ustring.gsub(linkText, '"', '') -- remove any occurrences of " in the link text
local baseTaxon, disambig, subgenus, qualifier = l.splitTaxonName(taxon) -- split up the taxon name
baseTaxon, dummy = mw.ustring.gsub(linkText, '"', '') -- remove any occurrences of " in the base taxon name
local match = linkText == baseTaxon or
linkText == subgenus or
linkText == baseTaxon .. ' (' .. subgenus .. ')' or
linkText == mw.ustring.sub(baseTaxon, 1, 1) .. '. (' .. subgenus .. ')' or
baseTaxon == 'Incertae sedis' or
rankBelowGenus and linkText == mw.ustring.gsub(baseTaxon, '([A-Z]).- (.*)', '%1. %2') or
mw.ustring.find(qualifier, '?', 1, true) and mw.ustring.find(linkText, baseTaxon, 1, true) == 1
return match
end
--[[= = = = = = = = = = = = = makeTable = = = = = = = = = = = = = = = = = = =
Internal utility function to return two tables (arrays) constructed from a
taxonomic hierarchy stored in "Template:Taxonomy/..." templates.
taxonTable.n holds the total number of taxa; taxonTable[1]..taxonTable[taxonTable.n]
the taxon names.
The last taxon in the table will either (a) have a taxonomy template but with
no parent given (e.g. 'Life') or (b) not have a taxonomy template.
taxonRankTable hold the corresponding ranks of the taxa.
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =]]
function l.makeTable(frame, currTaxon)
local taxonTable = {}
local taxonRankTable = {}
local ok, rank, parent
local i = 1
local topReached = false -- reached the top of the taxonomic hierarchy?
repeat
taxonTable[i] = currTaxon
ok, rank = p.getTaxonInfoItem(frame, currTaxon, 'rank')
if ok then taxonRankTable[i] = string.lower(rank) else taxonRankTable[i] = '' end
ok, parent = p.getTaxonInfoItem(frame, currTaxon, 'parent')
if ok and parent ~= '' then
currTaxon = parent
i = i + 1
else
topReached = true -- reached the top of the hierarchy or tried to use a non-existent taxonomy template
end
until topReached or i > MaxSearchLevels
taxonTable.n = math.min(i, MaxSearchLevels)
return taxonTable, taxonRankTable
end
--[[= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =]]
function l.tableCell(arg1, arg2)
local text, style
if arg2 then
style = arg1
text = arg2
else
style = ''
text = arg1
end
local res = '|'
if style ~= '' then
res = res .. style .. '|'
end
return res .. text .. '\n'
end
return p
0ls4threhlb9ombc1rra23mp3gtxcn5
Modul:Check for conflicting parameters
828
33883
159014
2026-10-10T16:55:50Z
Rachmat04
7338
Geupeugöt laman ngön asoë 'local p = {} local function trim(s) return s:match('^%s*(.-)%s*$') end local function isnotempty(s) return s and s:match('%S') end function p.check(frame) local args = frame.args local pargs = frame:getParent().args local checknested = isnotempty(args['nested']) local delimiter = isnotempty(args['delimiter']) and args['delimiter'] or ';' local argpairs = {} for k, v in pairs(args) do if type(k) == 'number' then local plist = mw.text.split(v,...'
159014
Scribunto
text/plain
local p = {}
local function trim(s)
return s:match('^%s*(.-)%s*$')
end
local function isnotempty(s)
return s and s:match('%S')
end
function p.check(frame)
local args = frame.args
local pargs = frame:getParent().args
local checknested = isnotempty(args['nested'])
local delimiter = isnotempty(args['delimiter']) and args['delimiter'] or ';'
local argpairs = {}
for k, v in pairs(args) do
if type(k) == 'number' then
local plist = mw.text.split(v, delimiter)
local pfound = {}
local count = 0
for ii, vv in ipairs(plist) do
vv = trim(vv)
if checknested and pargs[vv] or isnotempty(pargs[vv]) then
count = count + 1
table.insert(pfound, vv)
end
end
if count > 1 then
table.insert(argpairs, pfound)
end
end
end
local warnmsg = {}
local res = ''
local cat = ''
if args['cat'] and mw.ustring.match(args['cat'],'^[Cc][Aa][Tt][Ee][Gg][Oo][Rr][Yy]:') then
cat = args['cat']
end
local template = args['template'] and ' in ' .. args['template'] or ''
if #argpairs > 0 then
for i, v in ipairs( argpairs ) do
table.insert(
warnmsg,
mw.ustring.format(
'Using more than one of the following parameters%s: <code>%s</code>.',
template,
table.concat(v, '</code>, <code>')
)
)
if cat ~= '' then
res = res .. '[[' .. cat .. '|' .. (v[1] == '' and ' ' or '') .. v[1] .. ']]'
end
end
end
if #warnmsg > 0 then
res = require('Module:If preview')._warning({
table.concat(warnmsg, '<br>')
}) .. res
end
return res
end
return p
59n770hna40q9pw4oa0dsp86euaks0u
Modul:Infobox mapframe
828
33884
159015
2026-10-10T16:56:40Z
Rachmat04
7338
Geupeugöt laman ngön asoë 'local mf = require('Module:Mapframe') local getArgs = require('Module:Arguments').getArgs local yesno = require('Module:Yesno') local infoboxImage = require('Module:InfoboxImage').InfoboxImage -- Defaults local DEFAULT_FRAME_WIDTH = "270" local DEFAULT_FRAME_HEIGHT = "200" local DEFAULT_ZOOM = 10 local DEFAULT_GEOMASK_STROKE_WIDTH = "1" local DEFAULT_GEOMASK_STROKE_COLOR = "#777777" local DEFAULT_GEOMASK_FILL = "#888888" local DEFAULT_GEOMASK_FILL_OPACITY = "...'
159015
Scribunto
text/plain
local mf = require('Module:Mapframe')
local getArgs = require('Module:Arguments').getArgs
local yesno = require('Module:Yesno')
local infoboxImage = require('Module:InfoboxImage').InfoboxImage
-- Defaults
local DEFAULT_FRAME_WIDTH = "270"
local DEFAULT_FRAME_HEIGHT = "200"
local DEFAULT_ZOOM = 10
local DEFAULT_GEOMASK_STROKE_WIDTH = "1"
local DEFAULT_GEOMASK_STROKE_COLOR = "#777777"
local DEFAULT_GEOMASK_FILL = "#888888"
local DEFAULT_GEOMASK_FILL_OPACITY = "0.25"
local DEFAULT_SHAPE_STROKE_WIDTH = "2"
local DEFAULT_SHAPE_STROKE_COLOR = "#FF0000"
local DEFAULT_SHAPE_FILL = "#606060"
local DEFAULT_SHAPE_FILL_OPACITY = "0.1"
local DEFAULT_LINE_STROKE_WIDTH = "5"
local DEFAULT_LINE_STROKE_COLOR = "#FF0000"
local DEFAULT_MARKER_COLOR = "#5E74F3"
local util = {}
function util.noop(info)
local DEFAULT_NOOP_OUTPUT = ""
-- uncomment this when debugging
-- DEFAULT_NOOP_OUTPUT = "debug: mapframe no-op: " .. info
-- mw.log(DEFAULT_NOOP_OUTPUT)
return DEFAULT_NOOP_OUTPUT
end
-- Trim whitespace from args, and remove empty args
function util.trimArgs(argsTable)
local cleanArgs = {}
for key, val in pairs(argsTable) do
if type(val) == 'string' then
val = val:match('^%s*(.-)%s*$')
if val ~= '' then
cleanArgs[key] = val
end
else
cleanArgs[key] = val
end
end
return cleanArgs
end
function util.getBestStatement(item_id, property_id)
if not(item_id) or not(mw.wikibase.isValidEntityId(item_id)) or not(mw.wikibase.entityExists(item_id)) then
return false
end
local statements = mw.wikibase.getBestStatements(item_id, property_id)
if not statements or #statements == 0 then
return false
end
local hasNoValue = ( statements[1].mainsnak and statements[1].mainsnak.snaktype == 'novalue' )
if hasNoValue then
return false
end
return statements[1]
end
function util.hasWikidataProperty(item_id, property_id)
return util.getBestStatement(item_id, property_id) and true or false
end
function util.getStatementValue(statement)
return statement and statement.mainsnak and statement.mainsnak.datavalue and statement.mainsnak.datavalue.value or nil
end
function util.relatedEntity(item_id, property_id)
local value = util.getStatementValue( util.getBestStatement(item_id, property_id) )
return value and value.id or false
end
function util.idType(id)
if not id then
return nil
elseif mw.ustring.match(id, "[Pp]%d+") then
return "property"
elseif mw.ustring.match(id, "[Qq]%d+") then
return "item"
else
return nil
end
end
function util.shouldAutoRun(frame)
-- Check if should be running
local pargs = frame.getParent(frame).args
local explicitlyOn = yesno(mw.text.trim(pargs.mapframe or "")) -- true of false or nil
if pargs.coordinates == "{{{coordinates}}}" then explicitlyOn = false end
if type(pargs.coordinates) == 'string' and string.match(pargs.coordinates, 'coord.missing') then explicitlyOn = false end
local onByDefault = (explicitlyOn == nil) and yesno(mw.text.trim(frame.args.onByDefault or ""), false) -- true or false
return explicitlyOn or onByDefault
end
function util.argsFromAuto(frame)
-- Get args from the frame (invoke call) and the parent (template call).
-- Frame arguments are default values which are overridden by parent values
-- when both are present
local args = getArgs(frame, {parentFirst = true})
-- Discard args not prefixed with "mapframe-", remove that prefix from those that remain
local fixedArgs = {}
for name, val in pairs(args) do
local fixedName = string.match(name, "^mapframe%-(.+)$" )
if fixedName then
fixedArgs[fixedName] = val
-- allow coord, coordinates, etc to be unprefixed
elseif name == "coordinates" or name == "coordinate" and not fixedArgs.coord then
fixedArgs.coord = val
-- allow id, qid to be unprefixed, map to id (if not already present)
elseif name == "id" or name == "qid" and not fixedArgs.id then
fixedArgs.id = val
-- allow captionstyle to be unprefixed, for compatibility with [[Module:Infobox]]
elseif name == "captionstyle" and not fixedArgs.captionstyle then
fixedArgs.captionstyle = val
end
end
return fixedArgs
end
function util.parseCustomWikitext(customWikitext)
-- infoboxImage will format an image if given wikitext containing an
-- image, or else pass through the wikitext unmodified
return infoboxImage({
args = {
image = customWikitext
}
})
end
function util.trackAndWarn(trackingCat, warning)
local title = mw.title.getCurrentTitle()
local results = title and title.namespace == 0 and trackingCat and '[[Category:'..trackingCat..']]' or ''
if warning then
local warn = require('Module:If preview')._warning
results = results..warn({warning})
end
return results
end
function util.ternary(flag, other)
other = other or 'other'
flag = flag == 'none' and 'no' or flag
local yesNoOut = yesno(flag,other)
local yes = (yesNoOut == true)
local no = (yesNoOut == false)
return yes, no
end
local p = {}
p._caption = function(args)
if args.caption then
return args.caption
elseif args.switcher then
return util.noop("no caption or switcher")
end
local maskItem
local maskType = util.idType(args.geomask)
if maskType == 'item' then
maskItem = args.geomask
elseif maskType == "property" then
maskItem = util.relatedEntity(args.id or mw.wikibase.getEntityIdForCurrentPage(), args.geomask)
end
local maskItemLabel = maskItem and mw.wikibase.getLabel( maskItem )
return maskItemLabel and "Location in "..maskItemLabel
or util.noop("missing maskItemLabel with type " .. (maskType or "nil") .. " and item " .. (maskItem or "nil"))
end
--A list of types for objects that are too small to allow Kartographer to take over zoom
local tinyType = {
landmark=true,
railwaystation=true,
edu=true,
pass=true,
camera=true
}
p._main = function(_config)
-- accumulate tracking cats
local tracking = ''
-- `config` is the args passed to this module
local config = util.trimArgs(_config)
-- allow alias for config.coord
config.coord = config.coord or config.coordinates
-- Require wikidata item, or specified coords
local wikidataId = config.id or mw.wikibase.getEntityIdForCurrentPage()
if not(wikidataId) and not(config.coord) then
return false, util.trackAndWarn('Pages using infobox mapframe with missing coordinates')
end
-- Require coords (specified or from wikidata), so that map will be centred somewhere
-- (P625 = coordinate location)
local wdCoordinates = util.getStatementValue(util.getBestStatement(wikidataId, 'P625'))
if not (config.coord or wdCoordinates) then
return false, util.trackAndWarn('Pages using infobox mapframe with missing coordinates')
end
-- `args` is the arguments which will be passed to the mapframe module
local args = {}
-- Some defaults/overrides for infobox presentation
args.display = "inline"
args.frame = "yes"
args.plain = "yes"
args["frame-width"] = config["frame-width"] or config.width or DEFAULT_FRAME_WIDTH
args["frame-height"] = config["frame-height"] or config.height or DEFAULT_FRAME_HEIGHT
args["frame-align"] = "center"
args["frame-coord"] = config["frame-coordinates"] or config["frame-coord"]
-- Note: config["coordinates"] or config["coord"] should not be used for the alignment of the frame;
-- see talk page ( https://en.wikipedia.org/wiki/Special:Diff/876492931 )
-- deprecated lat and long parameters
args["frame-lat"] = config["frame-lat"] or config["frame-latitude"]
args["frame-long"] = config["frame-long"] or config["frame-longitude"]
-- if zoom isn't specified from config, first check wikidata
local zoom = config.zoom or util.getStatementValue(util.getBestStatement(wikidataId, 'P6592'))
if not zoom then
-- Calculate zoom from length or area (converted to km or km2)
-- Zoom so that length or area is completely included in mapframe
local getZoom = require('Module:Infobox dim')._zoom
zoom = getZoom({length_km=config.length_km, length_mi=config.length_mi,
width_km=config.width_km, width_mi=config.width_mi,
area_km2=config.area_km2, area_mi2=config.area_mi2,
area_ha=config.area_ha, area_acre=config.area_acre,
type=config.type, population=config.population,
viewport_px=math.min(args["frame-width"],args["frame-height"]),
latitude=wdCoordinates and wdCoordinates.latitude})
end
args.zoom = zoom or DEFAULT_ZOOM
-- Use OSM relation ID if available; otherwise use geoshape if that is available
-- (geoshape is required for defunct entities, which are outside OSM's scope)
local hasOsmRelationId = util.hasWikidataProperty(wikidataId, 'P402') -- P402 is OSM relation ID
local hasGeoshape = util.hasWikidataProperty(wikidataId, 'P3896') -- P3896 is geoshape
local wikidataProvidesGeo = hasOsmRelationId or hasGeoshape
-- determine marker argument value, determine whether to show marker
local forcePoint, suppressPoint = util.ternary(config.point)
local forceMarker, suppressMarker = util.ternary(config.marker,true)
forcePoint = forcePoint or forceMarker
suppressPoint = suppressPoint or suppressMarker
local showMarker = not suppressPoint and (forcePoint or not wikidataProvidesGeo or config.coord)
-- wikidata = "yes" turns on both shape and line
-- wikidata = "no" turns off both shape and line
-- otherwise show both if wikidata provides geo
local forceWikidata, suppressWikidata = util.ternary(config.wikidata)
local showShape = not suppressWikidata and (forceWikidata or wikidataProvidesGeo or not config.coord)
local showLine = showShape
-- determine shape parameter value, determine whether to show or suppress shape
-- also determine whether to invert shape
local forceShape, suppressShape = util.ternary(config.shape)
showShape = wikidataId and not suppressShape and (forceShape or showShape)
local shapeType = config.shape == 'inverse' and 'shape-inverse' or 'shape'
-- determine line parameter value, determine whether to show or suppress line
local forceLine, suppressLine = util.ternary(config.line)
showLine = wikidataId and not suppressLine and (forceLine or showLine)
local maskItem
-- Switcher
if config.switcher == "zooms" then
-- switching between zoom levels
local maxZoom = math.max(tonumber(args.zoom), 3) -- what zoom would have otherwise been (if 3 or more, otherwise 3)
local minZoom = 1 -- completely zoomed out
local midZoom = math.floor((maxZoom + minZoom)/2) -- midway between maxn and min
args.switch = "zoomed in, zoomed midway, zoomed out"
args.zoom = string.format("SWITCH:%d,%d,%d", maxZoom, midZoom, minZoom)
elseif config.switcher == "auto" then
-- switching between P276 and P131 areas with recursive lookup, e.g. item's city,
-- that city's state, and that state's country
args.zoom = nil -- let kartographer determine the zoom
local maskLabels = {}
local maskItems = {}
local maskItemId = util.relatedEntity(wikidataId, "P276") or util.relatedEntity(wikidataId, "P131")
local maskLabel = mw.wikibase.getLabel(maskItemId)
while maskItemId and maskLabel and mw.text.trim(maskLabel) ~= "" do
table.insert(maskLabels, maskLabel)
table.insert(maskItems, maskItemId)
maskItemId = maskItemId and util.relatedEntity(maskItemId, "P131")
maskLabel = maskItemId and mw.wikibase.getLabel(maskItemId)
end
if #maskLabels > 1 then
args.switch = table.concat(maskLabels, "###")
maskItem = "SWITCH:" .. table.concat(maskItems, ",")
elseif #maskLabels == 1 then
maskItem = maskItemId[1]
end
elseif config.switcher == "geomasks" and config.geomask then
-- switching between items in geomask parameter
args.zoom = nil -- let kartographer determine the zoom
local separator = (mw.ustring.find(config.geomask, "###", 0, true ) and "###") or
(mw.ustring.find(config.geomask, ";", 0, true ) and ";") or ","
local pattern = "%s*"..separator.."%s*"
local maskItems = mw.text.split(mw.ustring.gsub(config.geomask, "SWITCH:", ""), pattern)
local maskLabels = {}
if #maskItems > 1 then
for i, item in ipairs(maskItems) do
table.insert(maskLabels, mw.wikibase.getLabel(item))
end
args.switch = table.concat(maskLabels, "###")
maskItem = "SWITCH:" .. table.concat(maskItems, ",")
end
end
-- resolve geomask item id (if not using geomask switcher)
if not maskItem then --
local maskType = util.idType(config.geomask)
if maskType == 'item' then
maskItem = config.geomask
elseif maskType == "property" then
maskItem = util.relatedEntity(wikidataId, config.geomask)
end
end
-- if asking for shape or line from Wikidata
-- and if Wikidata actually has shape/line data (wikidataProvidesGeo=true)
-- and if no geomask
-- and if zoom not explicitly set
-- and if the object size inferred from its type is not too small
-- then let Kartographer "take over" zoom
if (showLine or showShape) and wikidataProvidesGeo and not maskItem
and not config.zoom and not (config.type and tinyType[config.type]) then
args.zoom = nil
end
if not maskItem and not showShape and not showLine and not showMarker then
return false, util.trackAndWarn('Pages using infobox mapframe with no geometry','No geometry specified for mapframe')
end
-- Keep track of arg numbering
local argNumber = ''
local function incrementArgNumber()
if argNumber == '' then
argNumber = 2
else
argNumber = argNumber + 1
end
end
-- Geomask
if maskItem then
args["type"..argNumber] = "shape-inverse"
args["id"..argNumber] = maskItem
args["stroke-width"..argNumber] = config["geomask-stroke-width"] or DEFAULT_GEOMASK_STROKE_WIDTH
args["stroke-color"..argNumber] = config["geomask-stroke-color"] or config["geomask-stroke-colour"] or DEFAULT_GEOMASK_STROKE_COLOR
args["fill"..argNumber] = config["geomask-fill"] or DEFAULT_GEOMASK_FILL
args["fill-opacity"..argNumber] = config["geomask-fill-opacity"] or DEFAULT_SHAPE_FILL_OPACITY
-- Let kartographer determine zoom and position, unless it is explicitly set in config
if not config.zoom and not config.switcher then
args.zoom = nil
args["frame-coord"] = nil
args["frame-lat"] = nil
args["frame-long"] = nil
local maskArea = util.getStatementValue( util.getBestStatement(maskItem, 'P2046') )
end
incrementArgNumber()
-- Hack to fix phab:T255932
if not args.zoom then
args["type"..argNumber] = "line"
args["id"..argNumber] = maskItem
args["stroke-width"..argNumber] = 0
incrementArgNumber()
end
end
-- Shape (or shape-inverse)
if showShape then
args["type"..argNumber] = shapeType
if hasGeoshape and not hasOsmRelationId then
args["from"..argNumber] = string.sub( util.getStatementValue( util.getBestStatement(wikidataId, 'P3896') ), 6)
elseif config.id then
args["id"..argNumber] = config.id
end
args["stroke-width"..argNumber] = config["shape-stroke-width"] or config["stroke-width"] or DEFAULT_SHAPE_STROKE_WIDTH
args["stroke-color"..argNumber] = config["shape-stroke-color"] or config["shape-stroke-colour"] or config["stroke-color"] or config["stroke-colour"] or DEFAULT_SHAPE_STROKE_COLOR
args["fill"..argNumber] = config["shape-fill"] or DEFAULT_SHAPE_FILL
args["fill-opacity"..argNumber] = config["shape-fill-opacity"] or DEFAULT_SHAPE_FILL_OPACITY
incrementArgNumber()
end
-- Line
if showLine then
args["type"..argNumber] = "line"
if hasGeoshape and not hasOsmRelationId then
args["from"..argNumber] = string.sub( util.getStatementValue( util.getBestStatement(wikidataId, 'P3896') ), 6)
elseif config.id then
args["id"..argNumber] = config.id
end
args["stroke-width"..argNumber] = config["line-stroke-width"] or config["stroke-width"] or DEFAULT_LINE_STROKE_WIDTH
args["stroke-color"..argNumber] = config["line-stroke-color"] or config["line-stroke-colour"] or config["stroke-color"] or config["stroke-colour"] or DEFAULT_LINE_STROKE_COLOR
incrementArgNumber()
end
-- Point marker
if showMarker then
args["type"..argNumber] = "point"
if config.id then args["id"..argNumber] = config.id end
if config.coord then args["coord"..argNumber] = config.coord end
if config.marker then args["marker"..argNumber] = config.marker end
args["marker-color"..argNumber] = config["marker-color"] or config["marker-colour"] or DEFAULT_MARKER_COLOR
incrementArgNumber()
end
-- if Wikidata doesn't link to OSM and the map has no mask or point,
-- then center the map on the coordinates either from the infobox or from wikidata
if not maskItem and not showMarker and not wikidataProvidesGeo then
if config.coord then
args["frame-coord"] = args["frame-coord"] or config.coord
else
args["frame-lat"] = args["frame-lat"] or wdCoordinates.latitude
args["frame-long"] = args["frame-long"] or wdCoordinates.longitude
end
tracking = tracking..util.trackAndWarn('Pages using infobox mapframe with forced centering')
end
-- protect against nil frame arguments
args["frame-coord"] = args["frame-coord"] or ""
args["frame-lat"] = args["frame-lat"] or ""
args["frame-long"] = args["frame-long"] or ""
local mapframe = args.switch and mf.multi(args) or mf._main(args)
tracking = tracking..((showLine or showShape) and not wikidataProvidesGeo
and util.trackAndWarn('Pages using infobox mapframe without shape links in Wikidata')
or '')
return true, mapframe.. tracking
end
-- Entry points
p.main = function(frame)
local parent = frame.getParent(frame)
local parentArgs = parent.args
local _, mapframe = p._main(parentArgs)
return frame:preprocess(mapframe)
end
p.auto = function(frame)
if not util.shouldAutoRun(frame) then
return util.noop("auto should not autorun")
end
local args = util.argsFromAuto(frame)
if args.custom then
return frame:preprocess(util.parseCustomWikitext(args.custom))
end
local _, mapframe = p._main(args)
return frame:preprocess(mapframe)
end
p.autocaption = function(frame)
if not util.shouldAutoRun(frame) then
return util.noop("autocaption should not autorun")
end
local args = util.argsFromAuto(frame)
local caption = p._caption(args)
return caption
end
p.autoWithCaption = function(frame)
if not util.shouldAutoRun(frame) then
return util.noop("autoWithCaption should not autorun")
end
local args = util.argsFromAuto(frame)
local wikitext
local caption
local ok
if args.custom then
ok = true
wikitext = util.parseCustomWikitext(args.custom)
else
ok, wikitext = p._main(args)
end
if not ok then return wikitext end
wikitext = frame:preprocess(wikitext)
caption = p._caption(args)
local data = mw.html.create():wikitext(wikitext)
data:tag('div')
:addClass('infobox-caption')
:cssText(args.captionstyle)
:wikitext(caption)
return tostring(data)
end
return p
875oxmrlaiy3xr3n98jl2ndg6rcmzou
Modul:Mapframe
828
33885
159016
2026-10-10T16:57:45Z
Rachmat04
7338
Geupeugöt laman ngön asoë '-- Note: Originally written on English Wikipedia at https://en.wikipedia.org/wiki/Module:Mapframe --[[---------------------------------------------------------------------------- ##### Localisation (L10n) settings ##### Replace values in quotes ("") with localised values ----------------------------------------------------------------------------]]-- local L10n = {} local wb = mw.wikibase -- Modue dependencies local parser -- local copy of https://www.medi...'
159016
Scribunto
text/plain
-- Note: Originally written on English Wikipedia at https://en.wikipedia.org/wiki/Module:Mapframe
--[[----------------------------------------------------------------------------
##### Localisation (L10n) settings #####
Replace values in quotes ("") with localised values
----------------------------------------------------------------------------]]--
local L10n = {}
local wb = mw.wikibase
-- Modue dependencies
local parser -- local copy of https://www.mediawiki.org/wiki/Module:WikitextParser loaded lazily
-- "strict" should not be used, at least until all other modules which require this module are not using globals.
-- Template parameter names (unnumbered versions only)
-- Specify each as either a single string, or a table of strings (aliases)
-- Aliases are checked left-to-right, i.e. `{ "one", "two" }` is equivalent to using `{{{one| {{{two|}}} }}}` in a template
L10n.para = {
display = "display",
type = "type",
id = { "id", "ids" },
from = "from",
raw = "raw",
title = "title",
description = "description",
strokeColor = { "stroke-color", "stroke-colour" },
strokeWidth = "stroke-width",
strokeOpacity = "stroke-opacity",
fill = "fill",
fillOpacity = "fill-opacity",
coord = "coord",
marker = "marker",
markerColor = { "marker-color", "marker-colour" },
markerSize = "marker-size",
radius = { "radius", "radius_m" },
radiusKm = "radius_km",
radiusFt = "radius_ft",
radiusMi = "radius_mi",
edges = "edges",
text = "text",
icon = "icon",
zoom = "zoom",
frame = "frame",
plain = "plain",
frameWidth = "frame-width",
frameHeight = "frame-height",
frameCoordinates= { "frame-coordinates", "frame-coord" },
frameLatitude = { "frame-lat", "frame-latitude" },
frameLongitude = { "frame-long", "frame-longitude" },
frameAlign = "frame-align",
switch = "switch",
overlay = "overlay",
overlayBorder = "overlay-border",
overlayHorizontalAlignment = "overlay-horizontal-alignment",
overlayVerticalAlignment = "overlay-vertical-alignment",
overlayHorizontalOffset = "overlay-horizontal-offset",
overlayVerticalOffset = "overlay-vertical-offset"
}
-- Names of other templates this module can extract coordinates from
L10n.template = {
templates = { -- The coord template, as well as templates with output that contains {{coord}}
"Coord", "Coord/sandbox",
"NRHP row", "NRHP row/sandbox",
"WikidataCoord", "WikidataCoord/sandbox", "Wikidatacoord", "Wikidata coord"
},
modules = { -- The coordinates module, as well as modules with output that contains {{coord}}
"Coordinates", "Coordinates/sandbox",
"WikidataCoord", "WikidataCoord/sandbox"
}
}
-- Error messages
L10n.error = {
badDisplayPara = "Invalid display parameter",
noCoords = "Coordinates must be specified on Wikidata or in |" .. ( type(L10n.para.coord)== 'table' and L10n.para.coord[1] or L10n.para.coord ) .. "=",
wikidataCoords = "Coordinates not found on Wikidata",
noCircleCoords = "Circle centre coordinates must be specified, or available via Wikidata",
negativeRadius = "Circle radius must be a positive number",
noRadius = "Circle radius must be specified",
negativeEdges = "Circle edges must be a positive number",
noSwitchPara = "Found only one switch value in |" .. ( type(L10n.para.switch)== 'table' and L10n.para.switch[1] or L10n.para.switch ) .. "=",
oneSwitchLabel = "Found only one label in |" .. ( type(L10n.para.switch)== 'table' and L10n.para.switch[1] or L10n.para.switch ) .. "=",
noSwitchLists = "At least one parameter must have a SWITCH: list",
switchMismatches = "All SWITCH: lists must have the same number of values",
-- "%s" and "%d" tokens will be replaced with strings and numbers when used
oneSwitchValue = "Found only one switch value in |%s=",
fewerSwitchLabels = "Found %d switch values but only %d labels in |" .. ( type(L10n.para.switch)== 'table' and L10n.para.switch[1] or L10n.para.switch ) .. "=",
noNamedCoords = "No named coordinates found in %s"
}
-- Other strings
L10n.str = {
-- valid values for display parameter, e.g. (|display=inline) or (|display=title) or (|display=inline,title) or (|display=title,inline)
inline = "inline",
title = "title",
dsep = ",", -- separator between inline and title (comma in the example above)
-- valid values for type parameter
line = "line", -- geoline feature (e.g. a road)
shape = "shape", -- geoshape feature (e.g. a state or province)
shapeInverse = "shape-inverse", -- geomask feature (the inverse of a geoshape)
data = "data", -- geoJSON data page on Commons
point = "point", -- single point feature (coordinates)
circle = "circle", -- circular area around a point
named = "named", -- all named coordinates in an article or section
-- Keyword to indicate a switch list. Must NOT use the special characters ^$()%.[]*+-?
switch = "SWITCH",
-- valid values for icon, frame, and plain parameters
affirmedWords = ' '..table.concat({
"add",
"added",
"affirm",
"affirmed",
"include",
"included",
"on",
"true",
"yes",
"y"
}, ' ')..' ',
declinedWords = ' '..table.concat({
"decline",
"declined",
"exclude",
"excluded",
"false",
"none",
"not",
"no",
"n",
"off",
"omit",
"omitted",
"remove",
"removed"
}, ' ')..' '
}
-- Default values for parameters
L10n.defaults = {
display = L10n.str.inline,
text = "Map",
frameWidth = "300",
frameHeight = "200",
frameAlign = "right",
markerColor = "5E74F3",
markerSize = nil,
strokeColor = "#ff0000",
strokeWidth = 6,
edges = 32, -- number of edges used to approximate a circle
overlayBorder = "1px solid white",
overlayHorizontalAlignment = "right",
overlayHorizontalOffset = "0",
overlayVerticalAlignment = "bottom",
overlayVerticalOffset = "0"
}
-- #### End of L10n settings ####
--[[----------------------------------------------------------------------------
Utility methods
----------------------------------------------------------------------------]]--
local util = {}
--[[
Looks up a parameter value based on the id (a key from the L10n.para table) and
optionally a suffix, for parameters that can be suffixed (e.g. type2 is type
with suffix 2).
@param {table} args key-value pairs of parameter names and their values
@param {string} param_id id for parameter name (key from the L10n.para table)
@param {string} [suffix] suffix for parameter name
@returns {string|nil} parameter value if found, or nil if not found
]]--
function util.getParameterValue(args, param_id, suffix)
suffix = suffix or ''
if type( L10n.para[param_id] ) ~= 'table' then
return args[L10n.para[param_id]..suffix]
end
for _i, paramAlias in ipairs(L10n.para[param_id]) do
if args[paramAlias..suffix] then
return args[paramAlias..suffix]
end
end
return nil
end
--[[
Trim whitespace from args, and remove empty args. Also fix control characters.
@param {table} argsTable
@returns {table} trimmed args table
]]--
function util.trimArgs(argsTable)
local cleanArgs = {}
for key, val in pairs(argsTable) do
if type(key) == 'string' and type(val) == 'string' then
val = val:match('^%s*(.-)%s*$')
if val ~= '' then
-- control characters inside json need to be escaped, but stripping them is simpler
-- See also T214984
-- However, *don't* strip control characters from wikitext (text or description parameters) or you'll break strip markers
-- Alternatively it might be better to only strip control char from raw parameter content
if util.matchesParam('text', key) or util.matchesParam('description', key, key:gsub('^%D+(%d+)$', '%1') ) then
cleanArgs[key] = val
else
cleanArgs[key] = val:gsub('%c',' ')
end
end
else
cleanArgs[key] = val
end
end
return cleanArgs
end
--[[
Check if a parameter name matches an unlocalized parameter key
@param {string} key - the unlocalized parameter name to search through
@param {string} name - the localized parameter name to check
@param {string|nil} - an optional suffix to apply to the value(s) from the localization key
@returns {boolean} true if the name matches the parameter, false otherwise
]]--
function util.matchesParam(key, name, suffix)
local param = L10n.para[key]
suffix = suffix or ''
if type(param) == 'table' then
for _, v in pairs(param) do
if (v .. suffix) == name then return true end
end
return false
end
return ((param .. suffix) == name)
end
--[[
Check if a value is affirmed (one of the values in L10n.str.affirmedWords)
@param {string} val Value to be checked
@returns {boolean} true if affirmed, false otherwise
]]--
function util.isAffirmed(val)
if not(val) then return false end
return string.find(L10n.str.affirmedWords, ' '..val..' ', 1, true ) and true or false
end
--[[
Check if a value is declined (one of the values in L10n.str.declinedWords)
@param {string} val Value to be checked
@returns {boolean} true if declined, false otherwise
]]--
function util.isDeclined(val)
if not(val) then return false end
return string.find(L10n.str.declinedWords , ' '..val..' ', 1, true ) and true or false
end
--[[
Check if the name of a template matches the known coord templates or wrappers
(in L10n.template.templates and L10n.template.modules). The name is normalised
when checked, so e.g. the names "Coord", "coord", and " Coord" all return true.
@param {string} name
@returns {boolean} true if it is a coord template or wrapper, false otherwise
]]--
function util.isCoordTemplateOrWrapper(name)
name = mw.text.trim(name)
local modName = mw.ustring.gsub(name, '#invoke:', '')
local inputTitle = mw.title.new(modName, (name ~= modName) and 'Module' or 'Template')
if not inputTitle then
return false
end
-- Create (or reuse) mw.title objects for each known coord template/wrapper.
-- Stored in L10n.template.title so that they don't need to be recreated
-- each time this function is called
if not L10n.template.titles then
L10n.template.titles = {}
for _, v in pairs(L10n.template.templates) do
table.insert(L10n.template.titles, mw.title.new(v, 'Template'))
end
for _, v in pairs(L10n.template.modules) do
table.insert(L10n.template.titles, mw.title.new(v, 'Module'))
end
end
for _, templateTitle in pairs(L10n.template.titles) do
if mw.title.equals(inputTitle, templateTitle) then
return true
end
end
return false
end
--[[
Recursively extract coord templates which have a name parameter.
@param {string} wikitext
@returns {table} table sequence of coord templates
]]--
function util.extractCoordTemplates(wikitext)
local output = {}
local templates = mw.ustring.gmatch(wikitext, '{%b{}}')
for template in templates do
local templateName = mw.ustring.match(template, '{{([^}|]+)')
local nameParam = mw.ustring.match(template, "|%s*name%s*=%s*[^}|]+")
if util.isCoordTemplateOrWrapper(templateName) then
if nameParam then table.insert(output, template) end
elseif mw.ustring.find(mw.ustring.sub(template, 2), "{{") then
local subOutput = util.extractCoordTemplates(mw.ustring.sub(template, 2))
for _, t in pairs(subOutput) do
table.insert(output, t)
end
end
end
-- ensure coords are not using title display
for k, v in pairs(output) do
output[k] = mw.ustring.gsub(v, "|%s*display%s*=[^|}]+", "|display=inline")
end
return output
end
--[[
Gets all named coordiates from a page or a section of a page.
@param {string|nil} page Page name, or name#section, to get named coordinates
from. If the name is omitted, i.e. #section or nil or empty string, then
the current page will be used.
@returns {table} sequence of {coord, name, description} tables where coord is
the coordinates in a format suitable for #util.parseCoords, name is a string,
and description is a string (coordinates in a format suitable for displaying
to the reader). If for some reason the name can't be found, the description
is nil and the name contains display-format coordinates.
@throws {L10n.error.noNamedCoords} if no named coordinates are found.
]]--
function util.getNamedCoords(page)
local parts = mw.text.split(page or "", "#", true)
local name = parts[1] == "" and mw.title.getCurrentTitle().prefixedText or parts[1]
local section = parts[2]
local title = mw.title.new(name)
if title.isRedirect then
title = title.redirectTarget
end
local pageWikitext = title:getContent()
if section then
if parser == nil then
-- load [[Module:WikitextParser]] lazily so it is only transcluded on pages that use it
parser = require("Module:WikitextParser")
end
pageWikitext = parser.getSection(pageWikitext, section) or ''
end
local coordTemplates = util.extractCoordTemplates(pageWikitext)
if #coordTemplates == 0 then error(string.format(L10n.error.noNamedCoords, page or name), 0) end
local frame = mw.getCurrentFrame()
local sep = "________"
local expandedContent = frame:preprocess(table.concat(coordTemplates, sep))
local expandedTemplates = mw.text.split(expandedContent, sep)
local namedCoords = {}
for _, expandedTemplate in pairs(expandedTemplates) do
local coord = mw.ustring.match(expandedTemplate, "<span class=\"geo%-dec\".->(.-)</span>")
if coord then
local coordname = (
-- name specified by a wrapper template, e.g [[Article|Name]]
mw.ustring.match(expandedTemplate, "<span class=\"mapframe%-coord%-name\">(.-)</span>") or
-- name passed into coord template
mw.ustring.match(expandedTemplate, "<span class=\"fn org\">(.-)</span>") or
-- default to the coordinates if the name can't be retrieved
coord
)
local description = coordname ~= coord and coord
table.insert(namedCoords, {
coord=mw.ustring.gsub(coord, "[° ]", "_"),
name=coordname, description=description
})
end
end
if #namedCoords == 0 then error(string.format(L10n.error.noNamedCoords, page or name), 0) end
return namedCoords
end
--[[
Parse coordinate values from the params passed in a GeoHack url (such as
//tools.wmflabs.org/geohack/geohack.php?pagename=Example¶ms=1_2_N_3_4_W_ or
//tools.wmflabs.org/geohack/geohack.php?pagename=Example¶ms=1.23_S_4.56_E_ )
or non-url string in the same format (such as `1_2_N_3_4_W_` or `1.23_S_4.56_E_`)
@param {string} coords string containing coordinates
@returns {number, number} latitude, longitude
]]--
function util.parseCoords(coords)
local coordsPatt
if mw.ustring.find(coords, "params=", 1, true) then
-- prevent false matches from page name, e.g. ?pagename=Lorem_S._Ipsum
coordsPatt = 'params=([_%.%d]+[NS][_%.%d]+[EW])'
else
-- not actually a geohack url, just the same format
coordsPatt = '[_%.%d]+[NS][_%.%d]+[EW]'
end
local parts = mw.text.split((mw.ustring.match(coords, coordsPatt) or ''), '_')
local lat_d = tonumber(parts[1])
assert(lat_d, "Unable to get latitude from input '"..coords.."'.")
local lat_m = tonumber(parts[2]) -- nil if coords are in decimal format
local lat_s = lat_m and tonumber(parts[3]) -- nil if coords are either in decimal format or degrees and minutes only
local lat = lat_d + (lat_m or 0)/60 + (lat_s or 0)/3600
if parts[#parts/2] == 'S' then
lat = lat * -1
end
local long_d = tonumber(parts[1+#parts/2])
assert(long_d, "Unable to get longitude from input '"..coords.."'.")
local long_m = tonumber(parts[2+#parts/2]) -- nil if coords are in decimal format
local long_s = long_m and tonumber(parts[3+#parts/2]) -- nil if coords are either in decimal format or degrees and minutes only
local long = long_d + (long_m or 0)/60 + (long_s or 0)/3600
if parts[#parts] == 'W' then
long = long * -1
end
return lat, long
end
--[[
Get coordinates from a Wikidata item
@param {string} item_id Wikidata item id (Q number)
@returns {number, number} latitude, longitude
@throws {L10n.error.noCoords} if item_id is invalid or the item does not exist
@throws {L10n.error.wikidataCoords} if the the item does not have a P625
statement (coordinates), or it is set to "no value"
]]--
function util.wikidataCoords(item_id)
if not (item_id and wb.isValidEntityId(item_id) and wb.entityExists(item_id)) then
error(L10n.error.noCoords, 0)
end
local coordStatements = wb.getBestStatements(item_id, 'P625')
if not coordStatements or #coordStatements == 0 then
error(L10n.error.wikidataCoords, 0)
end
local hasNoValue = ( coordStatements[1].mainsnak and (coordStatements[1].mainsnak.snaktype == 'novalue' or coordStatements[1].mainsnak.snaktype == 'somevalue') )
if hasNoValue then
error(L10n.error.wikidataCoords, 0)
end
local wdCoords = coordStatements[1]['mainsnak']['datavalue']['value']
return tonumber(wdCoords['latitude']), tonumber(wdCoords['longitude'])
end
--[[
Creates a polygon that approximates a circle
@param {number} lat Latitude
@param {number} long Longitude
@param {number} radius Radius in metres
@param {number} n Number of edges for the polygon
@returns {table} sequence of {latitude, longitude} table sequences, where
latitude and longitude are both numbers
]]--
function util.circleToPolygon(lat, long, radius, n) -- n is number of edges
-- Based on https://github.com/gabzim/circle-to-polygon, ISC licence
local function offset(cLat, cLon, distance, bearing)
local lat1 = math.rad(cLat)
local lon1 = math.rad(cLon)
local dByR = distance / 6378137 -- distance divided by 6378137 (radius of the earth) wgs84
local offet_lat = math.asin(
math.sin(lat1) * math.cos(dByR) +
math.cos(lat1) * math.sin(dByR) * math.cos(bearing)
)
local offet_lon = lon1 + math.atan2(
math.sin(bearing) * math.sin(dByR) * math.cos(lat1),
math.cos(dByR) - math.sin(lat1) * math.sin(offet_lat)
)
return {math.deg(offet_lon), math.deg(offet_lat)}
end
local coordinates = {};
local i = 0;
while i < n do
table.insert(coordinates,
offset(lat, long, radius, (2*math.pi*i*-1)/n)
)
i = i + 1
end
table.insert(coordinates, offset(lat, long, radius, 0))
return coordinates
end
--[[
Get the number of key-value pairs in a table, which might not be a sequence.
@param {table} t
@returns {number} count of key-value pairs
]]--
function util.tableCount(t)
local count = 0
for k, v in pairs(t) do
count = count + 1
end
return count
end
--[[
For a table where the values are all tables, returns either the util.tableCount
of the subtables if they are all the same, or nil if they are not all the same.
@param {table} t
@returns {number|nil} count of key-value pairs of subtable, or nil if subtables
have different counts
]]--
function util.subTablesCount(t)
local count = nil
for k, v in pairs(t) do
if count == nil then
count = util.tableCount(v)
elseif count ~= util.tableCount(v) then
return nil
end
end
return count
end
--[[
Splits a list into a table sequence. The items in the list may be separated by
commas, or by semicolons (if items may contain commas), or by "###" (if items
may contain semicolons).
@param {string} listString
@returns {table} sequence of list items
]]--
function util.tableFromList(listString)
if type(listString) ~= "string" or listString == "" then return nil end
local separator = (mw.ustring.find(listString, "###", 0, true ) and "###") or
(mw.ustring.find(listString, ";", 0, true ) and ";") or ","
local pattern = "%s*"..separator.."%s*"
return mw.text.split(listString, pattern)
end
-- Boolean in outer scope indicating if Kartographer should be able to
-- automatically calculate coordinates (see phab:T227402)
local coordsDerivedFromFeatures = false;
--[[----------------------------------------------------------------------------
Make methods: These take in a table of arguments, and return either a string
or a table to be used in the eventual output.
----------------------------------------------------------------------------]]--
local make = {}
--[[
Makes content to go inside the maplink or mapframe tag.
@param {table} args
@returns {string} tag content
]]--
function make.content(args)
if util.getParameterValue(args, 'raw') then
coordsDerivedFromFeatures = true -- Kartographer should be able to automatically calculate coords from raw geoJSON
return util.getParameterValue(args, 'raw')
end
local content = {}
local argsExpanded = {}
for k, v in pairs(args) do
local index = string.match( k, '^[^0-9]+([0-9]*)$' )
if index ~= nil then
local indexNumber
if index ~= '' then
indexNumber = tonumber(index)
else
indexNumber = 1
end
if argsExpanded[indexNumber] == nil then
argsExpanded[indexNumber] = {}
end
argsExpanded[indexNumber][ string.gsub(k, index, '') ] = v
end
end
for contentIndex, contentArgs in pairs(argsExpanded) do
local argType = util.getParameterValue(contentArgs, "type")
-- Kartographer automatically calculates coords if geolines/shapes are used (T227402)
if not coordsDerivedFromFeatures then
coordsDerivedFromFeatures = ( argType == L10n.str.line or argType == L10n.str.shape ) and true or false
end
if argType == L10n.str.named then
local namedCoords = util.getNamedCoords(util.getParameterValue(contentArgs, "from"))
local typeKey = type(L10n.para.type) == "table" and L10n.para.type[1] or L10n.para.type
local coordKey = type(L10n.para.coord) == "table" and L10n.para.coord[1] or L10n.para.coord
local titleKey = type(L10n.para.title) == "table" and L10n.para.title[1] or L10n.para.title
local descKey = type(L10n.para.description) == "table" and L10n.para.description[1] or L10n.para.description
for _, namedCoord in pairs(namedCoords) do
contentArgs[typeKey] = "point"
contentArgs[coordKey] = namedCoord.coord
contentArgs[titleKey] = namedCoord.name
contentArgs[descKey] = namedCoord.description
content[#content+1] = make.contentJson(contentArgs)
end
else
content[#content + 1] = make.contentJson(contentArgs)
end
end
--Single item, no array needed
if #content==1 then return content[1] end
--Multiple items get placed in a FeatureCollection
local contentArray = '[\n' .. table.concat( content, ',\n') .. '\n]'
return contentArray
end
--[[
Make coordinates from the coord arg, or the id arg, or the current page's
Wikidata item.
@param {table} args
@param {boolean} [plainOutput]
@returns {Mixed} Either:
{number, number} latitude, longitude if plainOutput is true; or
{table} table sequence of longitude, then latitude (gives the required format
for GeoJSON when encoded)
]]--
function make.coords(args, plainOutput)
local coords, lat, long
local frame = mw.getCurrentFrame()
if util.getParameterValue(args, 'coord') then
coords = frame:preprocess( util.getParameterValue(args, 'coord') )
lat, long = util.parseCoords(coords)
else
lat, long = util.wikidataCoords(util.getParameterValue(args, 'id') or wb.getEntityIdForCurrentPage())
end
if plainOutput then
return lat, long
end
return {[0] = long, [1] = lat}
end
--[[
Makes a table of coordinates that approximate a circle.
@param {table} args
@returns {table} sequence of {latitude, longitude} table sequences, where
latitude and longitude are both numbers
@throws {L10n.error.noCircleCoords} if centre coordinates are not specified
@throws {L10n.error.noRadius} if radius is not specified
@throws {L10n.error.negativeRadius} if radius is negative or zero
@throws {L10n.error.negativeEdges} if edges is negative or zero
]]--
function make.circleCoords(args)
local lat, long = make.coords(args, true)
local radius = util.getParameterValue(args, 'radius')
if not radius then
radius = util.getParameterValue(args, 'radiusKm') and tonumber(util.getParameterValue(args, 'radiusKm'))*1000
if not radius then
radius = util.getParameterValue(args, 'radiusMi') and tonumber(util.getParameterValue(args, 'radiusMi'))*1609.344
if not radius then
radius = util.getParameterValue(args, 'radiusFt') and tonumber(util.getParameterValue(args, 'radiusFt'))*0.3048
end
end
end
local edges = util.getParameterValue(args, 'edges') or L10n.defaults.edges
if not lat or not long then
error(L10n.error.noCircleCoords, 0)
elseif not radius then
error(L10n.error.noRadius, 0)
elseif tonumber(radius) <= 0 then
error(L10n.error.negativeRadius, 0)
elseif tonumber(edges) <= 0 then
error(L10n.error.negativeEdges, 0)
end
return util.circleToPolygon(lat, long, radius, tonumber(edges))
end
--[[
Makes JSON data for a feature
@param contentArgs args for this feature. Keys must be the non-suffixed version
of the parameter names, i.e. use type, stroke, fill,... rather than type3,
stroke3, fill3,...
@returns {string} JSON encoded data
]]--
function make.contentJson(contentArgs)
local data = {}
if util.getParameterValue(contentArgs, 'type') == L10n.str.point or util.getParameterValue(contentArgs, 'type') == L10n.str.circle then
local isCircle = util.getParameterValue(contentArgs, 'type') == L10n.str.circle
data.type = "Feature"
data.geometry = {
type = isCircle and "LineString" or "Point",
coordinates = isCircle and make.circleCoords(contentArgs) or make.coords(contentArgs)
}
data.properties = {
title = util.getParameterValue(contentArgs, 'title') or mw.getCurrentFrame():getParent():getTitle()
}
if isCircle then
-- TODO: This is very similar to below, should be extracted into a function
data.properties.stroke = util.getParameterValue(contentArgs, 'strokeColor') or L10n.defaults.strokeColor
data.properties["stroke-width"] = tonumber(util.getParameterValue(contentArgs, 'strokeWidth')) or L10n.defaults.strokeWidth
local strokeOpacity = util.getParameterValue(contentArgs, 'strokeOpacity')
if strokeOpacity then
data.properties['stroke-opacity'] = tonumber(strokeOpacity)
end
local fill = util.getParameterValue(contentArgs, 'fill')
if fill then
data.properties.fill = fill
local fillOpacity = util.getParameterValue(contentArgs, 'fillOpacity')
data.properties['fill-opacity'] = fillOpacity and tonumber(fillOpacity) or 0.6
end
else -- is a point
local markerSymbol = util.getParameterValue(contentArgs, 'marker') or L10n.defaults.marker
-- allow blank to be explicitly specified, for overriding infoboxes or other templates with a default value
if markerSymbol ~= "blank" then
data.properties["marker-symbol"] = markerSymbol
end
data.properties["marker-color"] = util.getParameterValue(contentArgs, 'markerColor') or L10n.defaults.markerColor
data.properties["marker-size"] = util.getParameterValue(contentArgs, 'markerSize') or L10n.defaults.markerSize
end
else
data.type = "ExternalData"
if util.getParameterValue(contentArgs, 'type') == L10n.str.data or util.getParameterValue(contentArgs, 'from') then
data.service = "page"
elseif util.getParameterValue(contentArgs, 'type') == L10n.str.line then
data.service = "geoline"
elseif util.getParameterValue(contentArgs, 'type') == L10n.str.shape then
data.service = "geoshape"
elseif util.getParameterValue(contentArgs, 'type') == L10n.str.shapeInverse then
data.service = "geomask"
end
if util.getParameterValue(contentArgs, 'id') or (not (util.getParameterValue(contentArgs, 'from')) and wb.getEntityIdForCurrentPage()) then
data.ids = util.getParameterValue(contentArgs, 'id') or wb.getEntityIdForCurrentPage()
else
data.title = util.getParameterValue(contentArgs, 'from')
end
data.properties = {
stroke = util.getParameterValue(contentArgs, 'strokeColor') or L10n.defaults.strokeColor,
["stroke-width"] = tonumber(util.getParameterValue(contentArgs, 'strokeWidth')) or L10n.defaults.strokeWidth
}
local strokeOpacity = util.getParameterValue(contentArgs, 'strokeOpacity')
if strokeOpacity then
data.properties['stroke-opacity'] = tonumber(strokeOpacity)
end
local fill = util.getParameterValue(contentArgs, 'fill')
if fill and (data.service == "geoshape" or data.service == "geomask") then
data.properties.fill = fill
local fillOpacity = util.getParameterValue(contentArgs, 'fillOpacity')
if fillOpacity then
data.properties['fill-opacity'] = tonumber(fillOpacity)
end
end
end
data.properties.title = util.getParameterValue(contentArgs, 'title') or mw.title.getCurrentTitle().text
if util.getParameterValue(contentArgs, 'description') then
data.properties.description = util.getParameterValue(contentArgs, 'description')
end
return mw.text.jsonEncode(data)
end
--[[
Makes attributes for the maplink or mapframe tag.
@param {table} args
@param {boolean} [isTitle] Tag is to be displayed in the title of page rather
than inline
@returns {table<string,string>} key-value pairs of attribute names and values
]]--
function make.tagAttribs(args, isTitle)
local attribs = {}
if util.getParameterValue(args, 'zoom') then
attribs.zoom = util.getParameterValue(args, 'zoom')
end
if util.isDeclined(util.getParameterValue(args, 'icon')) then
attribs.class = "no-icon"
end
if util.getParameterValue(args, 'type') == L10n.str.point and not coordsDerivedFromFeatures then
local lat, long = make.coords(args, 'plainOutput')
attribs.latitude = tostring(lat)
attribs.longitude = tostring(long)
end
if util.isAffirmed(util.getParameterValue(args, 'frame')) and not(isTitle) then
attribs.width = util.getParameterValue(args, 'frameWidth') or L10n.defaults.frameWidth
attribs.height = util.getParameterValue(args, 'frameHeight') or L10n.defaults.frameHeight
if util.getParameterValue(args, 'frameCoordinates') then
local frameLat, frameLong = util.parseCoords(util.getParameterValue(args, 'frameCoordinates'))
attribs.latitude = frameLat
attribs.longitude = frameLong
else
if util.getParameterValue(args, 'frameLatitude') then
attribs.latitude = util.getParameterValue(args, 'frameLatitude')
end
if util.getParameterValue(args, 'frameLongitude') then
attribs.longitude = util.getParameterValue(args, 'frameLongitude')
end
end
if not attribs.latitude and not attribs.longitude and not coordsDerivedFromFeatures then
local success, lat, long = pcall(util.wikidataCoords, util.getParameterValue(args, 'id') or wb.getEntityIdForCurrentPage())
if success then
attribs.latitude = tostring(lat)
attribs.longitude = tostring(long)
end
end
if util.getParameterValue(args, 'frameAlign') then
attribs.align = util.getParameterValue(args, 'frameAlign')
end
if util.isAffirmed(util.getParameterValue(args, 'plain')) then
attribs.frameless = "1"
else
attribs.text = util.getParameterValue(args, 'text') or L10n.defaults.text
end
else
attribs.text = util.getParameterValue(args, 'text') or L10n.defaults.text
end
return attribs
end
--[[
Makes maplink wikitext that will be located in the top-right of the title of the
page (the same place where coords with |display=title are positioned).
@param {table} args
@param {string} tagContent Content for the maplink tag
@returns {string}
]]--
function make.titleOutput(args, tagContent)
local titleTag = mw.text.tag('maplink', make.tagAttribs(args, true), tagContent)
local spanAttribs = {
style = "font-size: small;",
id = "mapframe-coordinates"
}
local indicatorContent = mw.text.tag('span', spanAttribs, titleTag)
return mw.getCurrentFrame():extensionTag {
name = "indicator",
content = indicatorContent,
args = {
name = "zzz-mapframe" --zzz: show as last indicator
}
}
end
--[[
Makes maplink or mapframe wikitext that will be located inline.
@param {table} args
@param {string} tagContent Content for the maplink tag
@returns {string}
]]--
function make.inlineOutput(args, tagContent)
local tagName = 'maplink'
if util.getParameterValue(args, 'frame') then
tagName = 'mapframe'
end
return mw.text.tag(tagName, make.tagAttribs(args), tagContent)
end
--[[
Makes the HTML required for the swicther to work, including the templatestyles
tag.
@param {table} params table sequence of {map, label} tables
@param {string} params{}.map Wikitext for mapframe map
@param {string} params{}.label Label text for swicther option
@param {table} options
@param {string} options.alignment "left" or "center" or "right"
@param {boolean} options.isThumbnail Display in a thumbnail
@param {string} options.width Width of frame, e.g. "200"
@param {string} [options.caption] Caption wikitext for thumnail
@retruns {string} swicther HTML
]]--
function make.switcherHtml(params, options)
options = options or {}
local frame = mw.getCurrentFrame()
local styles = frame:extensionTag{
name = "templatestyles",
args = {src = "Template:Maplink/styles-multi.css"}
}
local container = mw.html.create("div")
:addClass("switcher-container")
:addClass("mapframe-multi-container")
if options.alignment == "left" or options.alignment == "right" then
container:addClass("float"..options.alignment)
else -- alignment is "center"
container:addClass("center")
end
for i = 1, #params do
container
:tag("div")
:wikitext(params[i].map)
:tag("span")
:addClass("switcher-label")
:css("display", "none")
:wikitext(mw.text.trim(params[i].label))
end
if not options.isThumbnail then
return styles .. tostring(container)
end
local classlist = container:getAttr("class")
classlist = mw.ustring.gsub(classlist, "%a*"..options.alignment, "")
container:attr("class", classlist)
local outerCountainer = mw.html.create("div")
:addClass("mapframe-multi-outer-container")
:addClass("mw-kartographer-container")
:addClass("thumb")
if options.alignment == "left" or options.alignment == "right" then
outerCountainer:addClass("float"..options.alignment)
else -- alignment is "center"
outerCountainer
:addClass("tnone")
:addClass("center")
end
outerCountainer
:tag("div")
:addClass("thumbinner")
:css("width", options.width.."px")
:node(container)
:node(options.caption and mw.html.create("div")
:addClass("thumbcaption")
:wikitext(options.caption)
)
return styles .. tostring(outerCountainer)
end
--[[
Makes the HTML required for an overlay map to work
tag.
@param {string} overlayMap wikitext for the overlay map
@param {string} baseMap wikitext for the base map
@param {table} options various styling/display options
@param {string} options.align "left" or "center" or "right"
@param {string|number} options.width Width of the base map, e.g. "300"
@param {string|number} options.width Height of the base map, e.g. "200"
@param {string} options.border Border style for the overlayed map, e.g. "1px solid white"
@param {string} options.horizontalAlignment Horizontal alignment for overlay map, "left" or "right"
@param {string|number} options.horizontalOffset Horizontal offset in pixels from the alignment edge, e.g "10"
@param {string} options.verticalAlignment Vertical alignment for overlay map, "top" or "bottom"
@param {string|number} options.verticalOffset Vertical offset in pixels from the alignment edge, e.g. is "10"
@param {boolean} options.isThumbnail Display in a thumbnail
@param {string} [options.caption] Caption wikitext for thumnail
@retruns {string} HTML for basemap with overlay
]]--
function make.overlayHtml(overlayMap, baseMap, options)
options = options or {}
local containerFloatClass = "float"..(options.align or "none")
if options.align == "center" then
containerFloatClass = "center"
end
local containerStyle = {
position = "relative",
width = options.width .. "px",
height = options.height .. "px",
overflow = "hidden" -- mobile/minerva tends to add scrollbars for a couple of pixels
}
if options.align == "center" then
containerStyle["margin-left"] = "auto"
containerStyle["margin-right"] = "auto"
end
local container = mw.html.create("div")
:addClass("mapframe-withOverlay-container")
:addClass(containerFloatClass)
:addClass("noresize")
:css(containerStyle)
local overlayStyle = {
position = "absolute",
["z-index"] = "1",
border = options.border or "1px solid white"
}
if options.horizontalAlignment == "right" then
overlayStyle.right = options.horizontalOffset .. "px"
else
overlayStyle.left = options.horizontalOffset .. "px"
end
if options.verticalAlignment == "bottom" then
overlayStyle.bottom = options.verticalOffset .. "px"
else
overlayStyle.top = options.verticalOffset .. "px"
end
local overlayDiv = mw.html.create("div")
:css(overlayStyle)
:wikitext(overlayMap)
container
:node(overlayDiv)
:wikitext(baseMap)
if not options.isThumbnail then
return tostring(container)
end
local classlist = container:getAttr("class")
classlist = mw.ustring.gsub(classlist, "%a*"..options.align, "")
container:attr("class", classlist)
local outerCountainer = mw.html.create("div")
:addClass("mapframe-withOverlay-outerContainer")
:addClass("mw-kartographer-container")
:addClass("thumb")
if options.align == "left" or options.align == "right" then
outerCountainer:addClass("t"..options.align)
else -- alignment is "center"
outerCountainer
:addClass("tnone")
:addClass("center")
end
outerCountainer
:tag("div")
:addClass("thumbinner")
:css("width", options.width.."px")
:node(container)
:node(options.caption and mw.html.create("div")
:addClass("thumbcaption")
:wikitext(options.caption)
)
return tostring(outerCountainer)
end
--[[----------------------------------------------------------------------------
Package to be exported, i.e. methods which will available to templates and
other modules.
----------------------------------------------------------------------------]]--
local p = {}
-- Entry point for templates
function p.main(frame)
local parent = frame.getParent(frame)
-- Check for overlay option
local overlay = util.getParameterValue(parent.args, 'overlay')
local hasOverlay = overlay and mw.text.trim(overlay) ~= ""
-- Check for switch option
local switch = util.getParameterValue(parent.args, 'switch')
local isMulti = switch and mw.text.trim(switch) ~= ""
-- Create output by choosing method to suit options
local output
if hasOverlay then
output = p.withOverlay(parent.args)
elseif isMulti then
output = p.multi(parent.args)
else
output = p._main(parent.args)
end
-- Preprocess output before returning it
return frame:preprocess(output)
end
-- Entry points for modules
function p._main(_args)
local args = util.trimArgs(_args)
local tagContent = make.content(args)
local display = mw.text.split(util.getParameterValue(args, 'display') or L10n.defaults.display, '%s*' .. L10n.str.dsep .. '%s*')
local displayInTitle = display[1] == L10n.str.title or display[2] == L10n.str.title
local displayInline = display[1] == L10n.str.inline or display[2] == L10n.str.inline
local output
if displayInTitle and displayInline then
output = make.titleOutput(args, tagContent) .. make.inlineOutput(args, tagContent)
elseif displayInTitle then
output = make.titleOutput(args, tagContent)
elseif displayInline then
output = make.inlineOutput(args, tagContent)
else
error(L10n.error.badDisplayPara)
end
return output
end
function p.multi(_args)
local args = util.trimArgs(_args)
if not args[L10n.para.switch] then error(L10n.error.noSwitchPara, 0) end
local switchParamValue = util.getParameterValue(args, 'switch')
local switchLabels = util.tableFromList(switchParamValue)
if #switchLabels == 1 then error(L10n.error.oneSwitchLabel, 0) end
local mapframeArgs = {}
local switchParams = {}
for name, val in pairs(args) do
-- Copy to mapframeArgs, if not the switch labels or a switch parameter
if val ~= switchParamValue and not string.match(val, "^"..L10n.str.switch..":") then
mapframeArgs[name] = val
end
-- Check if this is a param to switch. If so, store the name and switch
-- values in switchParams table.
local switchList = string.match(val, "^"..L10n.str.switch..":(.+)")
if switchList ~= nil then
local values = util.tableFromList(switchList)
if #values == 1 then
error(string.format(L10n.error.oneSwitchValue, name), 0)
end
switchParams[name] = values
end
end
if util.tableCount(switchParams) == 0 then
error(L10n.error.noSwitchLists, 0)
end
local switchCount = util.subTablesCount(switchParams)
if not switchCount then
error(L10n.error.switchMismatches, 0)
elseif switchCount > #switchLabels then
error(string.format(L10n.error.fewerSwitchLabels, switchCount, #switchLabels), 0)
end
-- Ensure a plain frame will be used (thumbnail will be built by the
-- make.switcherHtml function if required, so that switcher options are
-- inside the thumnail)
mapframeArgs.plain = "yes"
local switcher = {}
for i = 1, switchCount do
local label = switchLabels[i]
for name, values in pairs(switchParams) do
mapframeArgs[name] = values[i]
end
table.insert(switcher, {
map = p._main(mapframeArgs),
label = "Show "..label
})
end
return make.switcherHtml(switcher, {
alignment = args["frame-align"] or "right",
isThumbnail = (args.frame and not args.plain) and true or false,
width = args["frame-width"] or L10n.defaults.frameWidth,
caption = args.text
})
end
function p.withOverlay(_args)
-- Get and trim wikitext for overlay map
local overlayMap = _args.overlay
if type(overlayMap) == 'string' then
overlayMap = overlayMap:match('^%s*(.-)%s*$')
end
local isThumbnail = (util.getParameterValue(_args, "frame") and not util.getParameterValue(_args, "plain")) and true or false
-- Get base map using the _main function, as a plain map
local args = util.trimArgs(_args)
args.plain = "yes"
local basemap = p._main(args)
-- Extract overlay options from args
local overlayOptions = {
width = util.getParameterValue(args, "frameWidth") or L10n.defaults.frameWidth,
height = util.getParameterValue(args, "frameHeight") or L10n.defaults.frameHeight,
align = util.getParameterValue(args, "frameAlign") or L10n.defaults.frameAlign,
border = util.getParameterValue(args, "overlayBorder") or L10n.defaults.overlayBorder,
horizontalAlignment = util.getParameterValue(args, "overlayHorizontalAlignment") or L10n.defaults.overlayHorizontalAlignment,
horizontalOffset = util.getParameterValue(args, "overlayHorizontalOffset") or L10n.defaults.overlayHorizontalOffset,
verticalAlignment = util.getParameterValue(args, "overlayVerticalAlignment") or L10n.defaults.overlayVerticalAlignment,
verticalOffset = util.getParameterValue(args, "overlayVerticalOffset") or L10n.defaults.overlayVerticalOffset,
isThumbnail = isThumbnail,
caption = util.getParameterValue(args, "text") or L10n.defaults.text
}
-- Make the HTML for the overlaying maps
return make.overlayHtml(overlayMap, basemap, overlayOptions)
end
-- Entry point for testcase tests
p.test = util
return p
ctsgv4ln5giysy1bit377346v8nejri
Modul:Taxobox ranks
828
33886
159017
2026-10-10T16:58:18Z
Rachmat04
7338
Geupeugöt laman ngön asoë '--[[************************************************************************* This module provides support to the automated taxobox system – the templates Automatic taxobox, Speciesbox, Subspeciesbox, Infraspeciesbox, etc. In particular it is part of the configuration of the system, defining the rank names that are recognized and the way they are displayed in English in taxoboxes and viewed taxonomy templates. ***********************************************...'
159017
Scribunto
text/plain
--[[*************************************************************************
This module provides support to the automated taxobox system – the templates
Automatic taxobox, Speciesbox, Subspeciesbox, Infraspeciesbox, etc.
In particular it is part of the configuration of the system, defining the
rank names that are recognized and the way they are displayed in English in
taxoboxes and viewed taxonomy templates.
*****************************************************************************]]
require('strict')
local TableRow = '|-\n'
local TableEnd = '|}\n'
local p = {} -- functions made public
local l = {} -- internal functions, kept separate
--*************************** CONFIGURATION *********************************
--[[============================ ranks ======================================
Set up a constant to hold the rank names and their English equivalents.
If adding to this list, note that rank names containing spaces or - must be
enclosed in [' '].
=============================================================================]]
local ranks =
{
--Special cases, alphabetic order
alliance = '<i>Alliance</i>',
['basic shell type'] = '<i>Basic shell type</i>',
branch = '<i>Branch</i>',
clade = '<i>Clade</i>',
cladus= '<i>Clade</i>',
['form taxon'] = '<i>Form taxon</i>',
grade = '<i>Grade</i>',
gradus = '<i>Grade</i>',
informal = '<i>Informal group</i>',
['informal group'] = '<i>Informal group</i>',
morphotype = '<i>Morphotype</i>',
node = '<i>Node</i>',
plesion = '<i>Plesion</i>',
['plesion-group'] = '<i>Plesion-group</i>',
['possible clade'] = '<i>Clade?</i>',
['species complex'] = '<i>Species complex</i>',
['species group'] = '<i>Species group</i>',
['species subgroup'] = '<i>Species subgroup</i>',
['stem group'] = '<i>Stem group</i>',
supergroup = '<i>Supergroup</i>',
['total group'] = '<i>Total group</i>',
--Special virus ranks
realm = 'Realm',
serotype = 'Serotype',
strain = 'Strain',
virus = 'Virus',
['virus group'] = 'Group',
--Linnaean taxonomy, alphabetic order
classis = 'Class',
cohort = 'Cohort',
divisio = 'Division',
domain = 'Domain',
epifamilia = 'Epifamily',
familia = 'Family',
forma = 'Form',
genus = 'Genus',
grandordo = 'Grandorder',
['grandordo-mb'] = 'Grandorder', --McKenna & Bell version
hyperfamilia = 'Hyperfamily',
infraclassis = 'Infraclass',
infrafamilia = 'Infrafamily',
infralegio = 'Infralegion',
infralegion = 'Infralegion',
infraordo = 'Infraorder',
infraphylum = 'Infraphylum',
infraregnum = 'Infrakingdom',
infratribus = 'Infratribe',
legio = 'Legion',
legion = 'Legion',
magnordo = 'Magnorder',
micrordo = 'Microrder',
microphylum = 'Microphylum',
mirordo = 'Mirorder',
['mirordo-mb'] = 'Mirorder', --McKenna & Bell version
nanordo = 'Nanorder',
nanophylum = 'Nanophylum',
ordo = 'Order',
parafamilia = 'Parafamily',
parvclassis = 'Parvclass',
parvordo = 'Parvorder',
phylum = 'Phylum',
regnum = 'Kingdom',
sectio = 'Section',
series = 'Series',
species = 'Species',
subclassis = 'Subclass',
subcohort = 'Subcohort',
subdivisio = 'Subdivision',
subfamilia = 'Subfamily',
subgenus = 'Subgenus',
sublegio = 'Sublegion',
sublegion = 'Sublegion',
subordo = 'Suborder',
subphylum = 'Subphylum',
subregnum = 'Subkingdom',
subsectio = 'Subsection',
subseries = 'Subseries',
subspecies = 'Subspecies',
subterclassis = 'Subterclass', --used in WoRMS
subtribus = 'Subtribe',
superclassis = 'Superclass',
supercohort = 'Supercohort',
superdivisio = 'Superdivision',
superdomain = 'Superdomain',
superfamilia = 'Superfamily',
superlegio = 'Superlegion',
superlegion = 'Superlegion',
superordo = 'Superorder',
superphylum = 'Superphylum',
superregnum = 'Superkingdom',
supersectio = 'Supersection',
supertribus = 'Supertribe',
tribus = 'Tribe',
varietas = 'Variety',
zoodivisio = 'Division',
zoosectio = 'Section',
zooseries = 'Series',
zoosubdivisio = 'Subdivision',
zoosubsectio = 'Subsection',
--trace fossil taxonomy, alphabetic order-->',
ichnoclassis = 'Ichnoclass',
ichnocohort = 'Ichnocohort',
ichnodivisio = 'Ichnodivision',
ichnofamilia = 'Ichnofamily',
ichnogenus = 'Ichnogenus',
ichnograndordo = 'Ichnograndorder',
['ichnograndordo-mb'] = 'Ichnograndorder', --McKenna & Bell version
ichnoinfraclassis = 'Ichnoinfraclass',
ichnoinfradivisio = 'Ichnoinfradivision',
ichnoinfraordo = 'Ichnoinfraorder',
ichnolegio = 'Ichnolegion',
ichnolegion = 'Ichnolegion',
ichnomagnordo = 'Ichnomagnorder',
ichnomicrordo = 'Ichnomicrorder',
ichnoordo = 'Ichnoorder',
ichnoparvordo = 'Ichnoparvorder',
ichnospecies = 'Ichnospecies',
['ichnostem-group'] = 'Ichnostem-Group',
ichnosubclassis = 'Ichnosubclass',
ichnosubdivisio = 'Ichnosubdivision',
ichnosubfamilia = 'Ichnosubfamily',
ichnosublegio = 'Ichnosublegion',
ichnosublegion = 'Ichnosublegion',
ichnosubordo = 'Ichnosuborder',
ichnosuperclassis = 'Ichnosuperclass',
ichnosupercohort = 'Ichnosupercohort',
ichnosuperfamilia = 'Ichnosuperfamily',
ichnosuperordo = 'Ichnosuperorder',
--fossilized egg taxonomy, alphabetic order
ooclassis = 'Ooclass',
oocohort = 'Oocohort',
oofamilia = 'Oofamily',
oogenus = 'Oogenus',
oomagnordo = 'Oomagnorder',
oordo = 'Oorder',
oospecies = 'Oospecies',
oosubclassis = 'Oosubclass',
oosubgenus = 'Oosubgenus',
oosubspecies = 'Oosubspecies',
oosupercohort = 'Oosupercohort',
oosuperordo = 'Oosuperorder',
}
--[[========================== rank values===================================
Constant 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 be a subset of those in Template:Anglicise ranks.
=============================================================================]]
local rankValTable =
{
classis = 1400,
cohort = 1100,
divisio = 1500,
domain = 1700,
epifamilia = 802,
familia = 800,
forma = 100,
genus = 600,
grandordo = 1005,
['grandordo-mb'] = 1002,
hyperfamilia = 805;
infraclassis = 1397,
infrafamilia = 797,
infralegio = 1197,
infralegion = 1197,
infraordo = 997,
infraphylum = 1497,
infraregnum = 1597,
infratribus = 697,
legio = 1200,
legion = 1200,
magnordo = 1006,
microphylum = 1495,
micrordo = 995,
mirordo = 1004,
['mirordo-mb'] = 1001,
nanophylum = 1494,
nanordo = 994,
ordo = 1000,
parafamilia = 800,
parvclassis = 1396; -- same as subterclassis
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,
sublegion = 1198,
subordo = 998,
subphylum = 1498,
subregnum = 1598,
subsectio = 498,
subspecies = 298,
subterclassis = 1396; -- same as parvclassis
subtribus = 698,
superclassis = 1403,
supercohort = 1103,
superdivisio = 1503,
superdomain = 1703,
superfamilia = 803,
superlegio = 1203,
superlegion = 1203,
superordo = 1003,
superphylum = 1503,
superregnum = 1603,
supersectio = 503,
supertribus = 703,
tribus = 700,
varietas = 200,
zoodivisio = 1300,
zoosectio = 900,
zoosubdivisio = 1298,
zoosubsectio = 898,
}
--***************** Process ranks + English equivalents *********************
--[[======================== angliciseRank ==================================
Returns the English language equivalent of a rank name used in a taxonomy
template.
If the rank name is not in the table of ranks, then the first letter
of the rank name is capitalized and used as the English name.
If checked=yes, then the generated English name is highlighted in red. If
called from a taxonomy template, the page is put in
Category:Taxonomy templates using capitalized rank parameters
=============================================================================]]
function p.doAngliciseRank(rankName, check)
rankName = string.gsub(rankName, '_', ' ') -- replace all underscores by spaces
-- is rankName capitalized?
local testName = string.lower(string.sub(rankName,1,1)) .. string.sub(rankName,2)
local wasCapitalized = testName ~= rankName
if wasCapitalized then rankName = testName end -- try uncapitalized version
if string.sub(rankName, 1,8) == 'unranked' then return '(unranked)' end
-- now look for an English version of the rank name
local res = ranks[rankName]
local notFound = not res
if notFound then
--rankName is not in the table of recognized ranks; just capitalize rankName
res = string.upper(string.sub(rankName,1,1)) .. string.sub(rankName,2)
end
if check == 'no' then
return res
elseif notFound then
res = '<span style="background-color:#F99">' .. res .. '</span>' -- highlight returned English name
end
-- tracking caegories required only if called from a taxonomy template
local pageTitle = mw.title.getCurrentTitle()
if pageTitle.nsText == 'Template' and pageTitle.rootText == 'Taxonomy' then
if notFound then res = res .. '[[Category:Taxonomy templates using unrecognized rank parameters]]'
elseif wasCapitalized then res = res .. '[[Category:Taxonomy templates using capitalized rank parameters]]'
end
end
return res
end
function p.angliciseRank(frame)
local rankName = frame.args[1]
local check = frame.args['check'] or 'no'
return p.doAngliciseRank(rankName, check)
end
--[[========================== showRanks ====================================
Returns a wikitable showing all the recognized ranks, how they are shown in
taxoboxes, whether they are automatically italicized, and whether they are
checked for consistency of rank order.
Usage: {{#invoke:Taxobox ranks|showRanks}}
=============================================================================]]
function p.showRanks(frame)
local res = '{| class="wikitable sortable"\n'
res = res ..'|+ Ranks recognized in taxonomy templates\n'
res = res .. '!style="text-align: left;"|Rank name in<br/>taxonomy<br/>template'
res = res .. '!!style="text-align: left;"|Shown in<br/>taxobox as'
res = res .. '!! style="text-align: left;" |Taxon name<br/>automatically<br/>italicized?'
res = res .. '!! style="text-align: left;" |Rank checked<br/>for consistent<br/>order?'
res = res .. '\n'
for k, t in pairs(ranks) do
res = res .. TableRow .. '|' .. k .. '||' .. t .. '||' .. frame:expandTemplate{ title = 'Is italic taxon', args = { k } } .. '||' .. l.hasRankVal(k) .. '\n'
end
return res .. TableEnd
end
--************************* Process rank values *****************************
--[[========================= lookupRankVal =================================
Function to look up the arbitrary numerical value of a rank in a rank value
table. "Ichno" and "oo" ranks are not stored separately, so if present the
prefix is removed.
=============================================================================]]
function p.lookupRankVal(rank)
local rankVal = rankValTable[rank]
if not rankVal then
-- may be an "ichno" or "oo" rank; try removing "ichno-" or "oo-"
local baseRank = mw.ustring.gsub(mw.ustring.gsub(rank, '^ichno', ''), '^oo', '')
if baseRank == 'rdo' then baseRank = 'ordo' end
-- if an "ichno" or "oo" rank, lower rank value slightly so it is ok below the base rank
rankVal = rankValTable[baseRank]
if rankVal then
rankVal = rankVal - 0.1
end
end
return rankVal
end
--[[=========================== hasRankVal =================================
Utility function to determine whether the rank has a value in rank value
table. Returns 'yes' or 'no'.
=============================================================================]]
function l.hasRankVal(rank)
if rank == '' then return 'no' end
local rankVal = p.lookupRankVal(rank)
if not rankVal then rankVal = 'no' else rankVal = 'yes' end
return rankVal
end
--[[========================== showRankTable ================================
Returns a wikitable showing the ranks and their values as set up in the
constant rankValTable.
Usage: {{#invoke:Taxobox ranks|showRankTable}}
=============================================================================]]
function p.showRankTable(frame)
local res = '{| class="wikitable sortable"\n|+ Ranks checked in taxonomy templates\n! Rank !! Shown as !! Value\n'
for k, v in pairs(rankValTable) do
local rankShown = p.doAngliciseRank(k, 'no')
res = res .. TableRow .. '|' .. k .. '||' .. rankShown .. '||' .. v .. '\n'
end
return res .. TableEnd
end
return p
7j9k1r2lz4zyoczf1fliruybzhsroqx
Seunaleuëk:Taxonomy/Mimosoid clade
10
33887
159018
2026-10-10T16:59:13Z
Rachmat04
7338
Geupeugöt laman ngön asoë '{{Don't edit this line {{{machine code|}}} |rank=cladus |link=Mimosoideae|Mimosoid clade |parent=Caesalpinioideae |refs={{cite journal | author = The Legume Phylogeny Working Group (LPWG). | year = 2017 | title = A new subfamily classification of the Leguminosae based on a taxonomically comprehensive phylogeny | journal = [[Taxon (journal)|Taxon]] | volume = 66 | issue = 1 | pages = 44–77 | doi = 10.12705/661.3| doi-access = free }} |always_display=yes }}'
159018
wikitext
text/x-wiki
{{Don't edit this line {{{machine code|}}}
|rank=cladus
|link=Mimosoideae|Mimosoid clade
|parent=Caesalpinioideae
|refs={{cite journal | author = The Legume Phylogeny Working Group (LPWG). | year = 2017 | title = A new subfamily classification of the Leguminosae based on a taxonomically comprehensive phylogeny | journal = [[Taxon (journal)|Taxon]] | volume = 66 | issue = 1 | pages = 44–77 | doi = 10.12705/661.3| doi-access = free }}
|always_display=yes
}}
da5g8h08cnlznevzos805ljejf51t65
Seunaleuëk:Taxonomy/Caesalpinioideae
10
33888
159019
2026-10-10T16:59:40Z
Rachmat04
7338
Geupeugöt laman ngön asoë '<noinclude>{{High-use}} </noinclude>{{Don't edit this line {{{machine code|}}} |rank=subfamilia |link=Caesalpinioideae |parent=Fabaceae |always_display=yes |refs={{cite journal | author = The Legume Phylogeny Working Group (LPWG). | year = 2017 | title = A new subfamily classification of the Leguminosae based on a taxonomically comprehensive phylogeny | journal = [[Taxon (journal)|Taxon]] | volume = 66 | issue = 1 | pages = 44–77 | url = http://www.ingentaco...'
159019
wikitext
text/x-wiki
<noinclude>{{High-use}}
</noinclude>{{Don't edit this line {{{machine code|}}}
|rank=subfamilia
|link=Caesalpinioideae
|parent=Fabaceae
|always_display=yes
|refs={{cite journal | author = The Legume Phylogeny Working Group (LPWG). | year = 2017 | title = A new subfamily classification of the Leguminosae based on a taxonomically comprehensive phylogeny | journal = [[Taxon (journal)|Taxon]] | volume = 66 | issue = 1 | pages = 44–77 | url = http://www.ingentaconnect.com/contentone/iapt/tax/2017/00000066/00000001/art00004 | doi = 10.12705/661.3}}
}}
q9r4ocd18qg30eziom7gvnxknu6ynev
Seunaleuëk:Don't edit this line extinct
10
33889
159020
2026-10-10T17:00:03Z
Rachmat04
7338
Geupeugöt laman ngön asoë '{{lcfirst:{{{extinct|}}}}}<noinclude>{{documentation|Template:Don't edit this line/doc/variant}}</noinclude>'
159020
wikitext
text/x-wiki
{{lcfirst:{{{extinct|}}}}}<noinclude>{{documentation|Template:Don't edit this line/doc/variant}}</noinclude>
7tinboxaqn5rskz8wukveydv97mz41a
Seunaleuëk:Taxonomy/Fabaceae
10
33890
159021
2026-10-10T17:01:13Z
Rachmat04
7338
Geupeugöt laman ngön asoë '<noinclude>{{High-use}} </noinclude>{{Don't edit this line {{{machine code|}}} |rank=familia |link=Fabaceae |parent=Fabales |refs={{Cite journal|author=Angiosperm Phylogeny Group|year=2016|title=An update of the Angiosperm Phylogeny Group classification for the orders and families of flowering plants: APG IV|journal=Botanical Journal of the Linnean Society|volume=181|issue=1|pages=1–20|url=http://onlinelibrary.wiley.com/doi/10.1111/boj.12385/epdf|format=PDF|...'
159021
wikitext
text/x-wiki
<noinclude>{{High-use}}
</noinclude>{{Don't edit this line {{{machine code|}}}
|rank=familia
|link=Fabaceae
|parent=Fabales
|refs={{Cite journal|author=Angiosperm Phylogeny Group|year=2016|title=An update of the Angiosperm Phylogeny Group classification for the orders and families of flowering plants: APG IV|journal=Botanical Journal of the Linnean Society|volume=181|issue=1|pages=1–20|url=http://onlinelibrary.wiley.com/doi/10.1111/boj.12385/epdf|format=PDF|issn=00244074|doi=10.1111/boj.12385}}
}}
oxvaluoa3ob15pe6dxg37e4y5ea8sym
Seunaleuëk:Taxonomy/Fabales
10
33891
159022
2026-10-10T17:01:35Z
Rachmat04
7338
Geupeugöt laman ngön asoë '<noinclude>{{High-use}} </noinclude>{{Don't edit this line {{{machine code|}}} |rank=ordo |link=Fabales |parent=Fabids |refs={{Cite journal|author=Angiosperm Phylogeny Group|year=2016|title=An update of the Angiosperm Phylogeny Group classification for the orders and families of flowering plants: APG IV|journal=Botanical Journal of the Linnean Society|volume=181|issue=1|pages=1–20|url=http://onlinelibrary.wiley.com/doi/10.1111/boj.12385/epdf|format=PDF|issn=...'
159022
wikitext
text/x-wiki
<noinclude>{{High-use}}
</noinclude>{{Don't edit this line {{{machine code|}}}
|rank=ordo
|link=Fabales
|parent=Fabids
|refs={{Cite journal|author=Angiosperm Phylogeny Group|year=2016|title=An update of the Angiosperm Phylogeny Group classification for the orders and families of flowering plants: APG IV|journal=Botanical Journal of the Linnean Society|volume=181|issue=1|pages=1–20|url=http://onlinelibrary.wiley.com/doi/10.1111/boj.12385/epdf|format=PDF|issn=00244074|doi=10.1111/boj.12385}}
}}
lc0nlsxf1ntchvorvm6qspophwuasdy
Seunaleuëk:Don't edit this line same as
10
33892
159023
2026-10-10T17:01:58Z
Rachmat04
7338
Geupeugöt laman ngön asoë '{{{same_as|{{{same as|}}}}}}<noinclude>{{documentation|Template:Don't edit this line/doc/variant}}</noinclude>'
159023
wikitext
text/x-wiki
{{{same_as|{{{same as|}}}}}}<noinclude>{{documentation|Template:Don't edit this line/doc/variant}}</noinclude>
qk0efbep22ilnitktx3lg5fha52f19o
Seunaleuëk:Speciesbox/getGenus
10
33893
159024
2026-10-10T17:03:44Z
Rachmat04
7338
Geupeugöt laman ngön asoë '{{#if:{{{1|}}}|{{first word|{{{1}}}}}|{{#if:{{{2|}}}|{{{2}}}|{{first word|<includeonly>{{PAGENAME}}</includeonly><noinclude>Acacia aemula</noinclude>}}}}}}'
159024
wikitext
text/x-wiki
{{#if:{{{1|}}}|{{first word|{{{1}}}}}|{{#if:{{{2|}}}|{{{2}}}|{{first word|<includeonly>{{PAGENAME}}</includeonly><noinclude>Acacia aemula</noinclude>}}}}}}
kcudeyuze696e63pak3t1twtki4kc8a
Seunaleuëk:Speciesbox/getSpecies
10
33894
159025
2026-10-10T17:04:11Z
Rachmat04
7338
Geupeugöt laman ngön asoë '<noinclude>{{pp-template|small=yes}}</noinclude>{{#if:{{{1|}}}|{{remove first word|{{{1}}}}}|{{#if:{{{2|}}}|{{{2}}}|{{remove first word|<includeonly>{{PAGENAME}}</includeonly><noinclude>Acacia aemula</noinclude>}}}}}}'
159025
wikitext
text/x-wiki
<noinclude>{{pp-template|small=yes}}</noinclude>{{#if:{{{1|}}}|{{remove first word|{{{1}}}}}|{{#if:{{{2|}}}|{{{2}}}|{{remove first word|<includeonly>{{PAGENAME}}</includeonly><noinclude>Acacia aemula</noinclude>}}}}}}
5mmygzcbw6segs1q7w7nbtzjyyu4mla
Seunaleuëk:Speciesbox/trim
10
33895
159026
2026-10-10T17:04:31Z
Rachmat04
7338
Geupeugöt laman ngön asoë '{{if empty|{{#invoke:String|match|s={{{1}}}|^×?[%a%-"]+|ignore_errors=true}}|{{#invoke:String|match|s={{{1}}}|^× [%a%-"]+|ignore_errors=true}}}}<noinclude>{{Documentation}}</noinclude>'
159026
wikitext
text/x-wiki
{{if empty|{{#invoke:String|match|s={{{1}}}|^×?[%a%-"]+|ignore_errors=true}}|{{#invoke:String|match|s={{{1}}}|^× [%a%-"]+|ignore_errors=true}}}}<noinclude>{{Documentation}}</noinclude>
s0hiwu03jtgcal5hl0kwv1yzb2ak144
Seunaleuëk:FishBase
10
33896
159028
2026-10-10T17:10:06Z
Rachmat04
7338
Geupeugöt laman ngön asoë '<noinclude><!-- For testing only (old template in sandbox2). These examples will be moved to the documentation page. --> ; Species with with positional parameters [with month and year] *{{Fishbase|Danio|rerio|month=May|year=2018}} *{{FishBase/sandbox2|Danio|rerio|month=May|year=2018}} ; Species with named parameters [no month and year provided] *{{FishBase|genus=Danio|species=rerio}} *{{FishBase/sandbox2|genus=Danio|species=rerio}} ; Subspecies with positi...'
159028
wikitext
text/x-wiki
<noinclude><!-- For testing only (old template in sandbox2). These examples will be moved to the documentation page. -->
; Species with with positional parameters [with month and year]
*{{Fishbase|Danio|rerio|month=May|year=2018}}
*{{FishBase/sandbox2|Danio|rerio|month=May|year=2018}}
; Species with named parameters [no month and year provided]
*{{FishBase|genus=Danio|species=rerio}}
*{{FishBase/sandbox2|genus=Danio|species=rerio}}
; Subspecies with positional parameters (old template didn't handle subspecies) [with year only]
*{{FishBase|Emmelichthys|nitidus|cyanescens|year=2020}}
*{{FishBase/sandbox2|Emmelichthys|nitidus|cyanescens|year=2020}}
; Subspecies with named parameters [no month and year provided]
*{{FishBase|genus=Emmelichthys|species=nitidus|subspecies=cyanescens}}
*{{FishBase/sandbox2|genus=Emmelichthys|species=nitidus|subspecies=cyanescens}}
; Genus, family and order examples [with access-date]
*{{FishBase|genus=Emmelichthys|access-date=1 September 2024}}
*{{FishBase|family=Percidae |access-date=1 September 2024}}
*{{FishBase|order=Perciformes|access-date=19 November 2018|mode=cs2}}
</noinclude><includeonly>{{#invoke:Cite taxon|main|fishbase|genus={{{1|}}}|species={{{2|}}}|subspecies={{{3|}}}}}</includeonly><noinclude>
{{documentation}}</noinclude>
pfslf0sem6vmth1k86d734rotzc1hd2
Seunaleuëk:Speciesbox/checkgenus
10
33897
159029
2026-10-10T17:10:45Z
Rachmat04
7338
Geupeugöt laman ngön asoë '<noinclude><!-- Only intended to be called from Template:Speciesbox/parameterCheck; determines whether its first parameter has the rank of genus in its taxonomy template. --></noinclude><nowiki/>{{#switch:{{Taxon info|{{{1|Felis}}}|rank}}|genus=|ichnogenus=|oogenus=|[[Category:Speciesboxes with genus parameter not a genus]]}}<noinclude> {{documentation}}</noinclude>'
159029
wikitext
text/x-wiki
<noinclude><!--
Only intended to be called from Template:Speciesbox/parameterCheck; determines whether its first parameter has the rank of genus in its taxonomy template.
--></noinclude><nowiki/>{{#switch:{{Taxon info|{{{1|Felis}}}|rank}}|genus=|ichnogenus=|oogenus=|[[Category:Speciesboxes with genus parameter not a genus]]}}<noinclude>
{{documentation}}</noinclude>
9ne11biulvhtm1kxprwg0jcrtuq5i8j
Seunaleuëk:Taxonomy/Plectorhinchus
10
33898
159030
2026-10-10T17:11:09Z
Rachmat04
7338
Geupeugöt laman ngön asoë '{{Don't edit this line {{{machine code|}}} |rank=genus |link=Plectorhinchus |parent=Plectorhinchinae |extinct= |refs={{FishBase genus | genus = Plectorhinchus | month = December | year = 2021}} }}'
159030
wikitext
text/x-wiki
{{Don't edit this line {{{machine code|}}}
|rank=genus
|link=Plectorhinchus
|parent=Plectorhinchinae
|extinct=
|refs={{FishBase genus | genus = Plectorhinchus | month = December | year = 2021}}
}}
nnvkzop07befy943nd8twsbvrddf2x2
Modul:Cite taxon
828
33899
159031
2026-10-10T17:11:42Z
Rachmat04
7338
Geupeugöt laman ngön asoë 'require('strict') local p = {} local data = {} local templateArgs = {} -- contains arguments passed to cite web local target = {} -- short cut to target table, e.g. fishbase, cof, etc local function error_msg(errorString) if p.errorString ~= "" then return '<span style="font-size:100%" class="error">' .. errorString .. '</span>' .. "[[Category:Pages with Cite taxon errors]]" end end local function firstToUpper(str) return (str:...'
159031
Scribunto
text/plain
require('strict')
local p = {}
local data = {}
local templateArgs = {} -- contains arguments passed to cite web
local target = {} -- short cut to target table, e.g. fishbase, cof, etc
local function error_msg(errorString)
if p.errorString ~= "" then
return '<span style="font-size:100%" class="error">' .. errorString .. '</span>'
.. "[[Category:Pages with Cite taxon errors]]"
end
end
local function firstToUpper(str)
return (str:gsub("^%l", string.upper))
end
-- define citation template and custom parameters for various sources
--####################### Default functions ##########################
data.default = {}
-- currently being tested on Avibase, but Fossilworks, Tropicos, FNA and a few others are candidates
data.default.id = function (id, source)
local title = id
local url = source.customArgs['baseURL'] .. (source.customArgs['searchStr'] or "") .. id
return title, url
end
data.default.error = function()
return "Minimal requirement is two of id, url and title parameters"
end
data.default.search = function (search, source)
local title = "Search for " .. search
local url = source.customArgs['baseURL'] .. source.customArgs['searchString'] .. search .. source.customArgs['searchSuffix']
return title, url
end
--[[ handling for ID only (unused, original concept)
p.genericIdCitation = function(frame, title, url)
if not templateArgs['id'] then return "no id parameter detected" end
templateArgs['url']= target.CustomArgs['baseURL'] .. target.CustomArgs['searchStr'] .. templateArgs['id']
return p.citeWeb(frame, title, url)
end]]
--####################### FISH #####################################
--======================== Fishbase =================================
data.fishbase = {
citationArgs = {
['editor1-last']="Froese", ['editor1-first']="Rainer", ['editor1-link']="Rainer Froese",
['editor2-last']="Pauly", ['editor2-first']="Daniel", ['editor2-link']="Daniel Pauly",
--['last-author-amp'] ="yes",
['website'] = "[[FishBase]]",
--['publisher'] = ""
},
customArgs = { exclude= "order, family,genus, species, subspecies, 1, 2, 3, 4, month",
baseURL = "https://www.fishbase.org/",
defaultTitle = "Search FishBase"
},
}
data.fishbase.species = function(genus, species, subspecies)
data.fishbase.version()
local title = genus .. " " .. species
local url = data.fishbase.customArgs['baseURL']
.. "summary/SpeciesSummary.php?genusname=" .. genus .. "&speciesname=" .. species
if subspecies then
url = url .. "+" .. subspecies
title = title .. " " .. subspecies
end
title = "''" .. title .. "''"
return title, url
end
data.fishbase.genus = function(genus)
data.fishbase.version()
local title = "Species in genus ''" .. firstToUpper(genus) .. "''"
local url = data.fishbase.customArgs['baseURL'] .. "identification/SpeciesList.php?genus=" .. genus
return title, url
end
data.fishbase.order = function(order)
data.fishbase.version()
local title = "Order " .. firstToUpper(order)
local url = data.fishbase.customArgs['baseURL'] .. "summary/OrdersSummary.php?order=" .. order
return title, url
end
data.fishbase.family = function(family)
-- family names no longer redirecting
-- must use code https://www.fishbase.org/summary/FamilySummary.php?ID=412
local families = {
{ "Acanthuridae", 412 },
{ "Percidae", 306 }
}
local familyID = 0
for k,v in pairs(families) do
if v[1] == family then familyID = v[2] end
end
data.fishbase.version()
local title = "Family " .. firstToUpper(family)
local url = data.fishbase.customArgs['baseURL'] .. "summary/FamilySummary.php?family=" .. family
--local url = data.fishbase.customArgs['baseURL'] .. "summary/FamilySummary.php?ID=" .. familyID
return title, url
end
data.fishbase.error = function()
return "No recognised taxon options: order, family, genus, species, subspecies."
end
data.fishbase.version = function()
local defaultDate = false
if defaultDate then -- default month and year as original template (now not used)
local month = templateArgs['month'] or "April" -- default month
local year = templateArgs['year'] or "2006" -- default year
--if isnumber(tostring(month)))
templateArgs['version'] = month .. " " .. year .. " version"
templateArgs['year'] =year -- old template gave redundant version and year
else --But defaulting the date to April 2006 invites errors and isn't helpful
local month = templateArgs['month'] -- no default month
local year = templateArgs['year']
if month and year then
if tonumber(month) then
local months = { "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" }
month = months[tonumber(month)] -- convert digital month to month name
end
templateArgs['version'] = month .. " " .. year .. " version" -- set version if month and year provided
templateArgs['year'] = nil -- don't use year as well as version
templateArgs['month'] = nil
end
end
end
--[[ ================================ Catalog of Fishes ================================================
Note: sequence of authors changed in Sept 2018,
4 Sept 2018: Eschmeyer, W. N. and R. Fricke, and R. van der Laan (eds). CATALOG OF FISHES: GENERA, SPECIES, REFERENCES.
(http://researcharchive.calacademy.org/research/ichthyology/catalog/fishcatmain.asp). Electronic version accessed dd mmm 2018. [This version was edited by Bill Eschmeyer.]
26 Sept 2018: Fricke, R., Eschmeyer, W. N. & R. van der Laan (eds) 2018. CATALOG OF FISHES: GENERA, SPECIES, REFERENCES.
(http://researcharchive.calacademy.org/research/ichthyology/catalog/fishcatmain.asp). Electronic version accessed dd mmm 2018.
--]]
data.cof = {
citationArgs = {
--baseURL = "http://researcharchive.calacademy.org/research/ichthyology/catalog/fishcatget.asp?",
['editor2-last']="Eschmeyer", ['editor2-first']="William N.", ['editor2-link']="William N. Eschmeyer",
['editor1-last']="Fricke", ['editor1-first']="Ron",
['editor3-last']="van der Laan", ['editor3-first']="Richard",
['name-list-style'] ="amp",
['website'] = "[[Catalog of Fishes]]",
['publisher'] = "[[California Academy of Sciences]]"
},
customArgs = { exclude= "family,genus,species,genid,spid,id,list,1,2,3",
baseURL = "http://researcharchive.calacademy.org/research/ichthyology/catalog/fishcatget.asp?",
defaultTitle = "CAS - Eschmeyer's Catalog of Fishes"
}
}
data.cof.species = function(genus, species, subspecies)
data.cof.checkDate()
local taxon = genus .. " " .. species
local url = data.cof.customArgs['baseURL'] .. 'tbl=species&genus=' .. genus .. '&species=' .. species
local title = "Species related to " .. "''" .. firstToUpper(taxon) .. "''" -- .. "" species synonyms"
return title, url
end
data.cof.genus = function(genus)
data.cof.checkDate()
local url = data.cof.customArgs['baseURL'] .. 'tbl=species&genus=' .. genus
local title = "Species in the genus ''" .. firstToUpper(genus) .. "''"
return title, url
end
-- note the family works with subfamilies using &family=SUBFAMILY
data.cof.family = function(family)
data.cof.checkDate()
local list = templateArgs['list'] or "genus"
local url = data.cof.customArgs['baseURL'] .. 'tbl=' .. list .. '&family=' .. family
local title = "Species"
if list == "genus" then title = "Genera" end
title = title .. ' in the family ' .. firstToUpper(family)
return title, url
end
data.cof.genid = function(genid)
data.cof.checkDate()
local searchStr = "genid" .. '=' .. genid
local title = searchStr
local url = data.cof.customArgs['baseURL'] .. searchStr
return title, url
end
data.cof.spid = function(spid)
data.cof.checkDate()
local searchStr = "spid" .. '=' .. spid
local title = searchStr
local url = data.cof.customArgs['baseURL'] .. searchStr
return title, url
end
data.cof.checkDate = function ()
local accessDate = templateArgs['access-date'] or templateArgs['accessdate']
local Date = require('Module:Date')._Date
local date = Date(accessDate)
if date and date < Date('5 September 2018') then -- switch author order for accessdates before 5 Sept 2018
data.cof.citationArgs['editor1-last']="Eschmeyer"
data.cof.citationArgs['editor1-first']="William N."
data.cof.citationArgs['editor1-link']="William N. Eschmeyer"
data.cof.citationArgs['editor2-last']="Fricke"
data.cof.citationArgs['editor2-first']="Ron"
data.cof.citationArgs['editor2-link']=nil
end
end
data.cof.error = function()
return "Error. No recognised option set by template (need one of family, genus, species (also requires genus), spid, or genid"
end
--======================Fishes of the World 5===============================
data.fotw5 = {
citeTemplate = "Cite book",
citationArgs = {
--['website'] = "[[]]",
first1 = "Joseph S.", last1 = "Nelson",
first2="Terry C.", last2="Grande",
first3="Mark V. H.", last3="Wilson",
--work = "Fishes of the World (work)",
title = "Fishes of the World", edition="5th", year = 2016,
publisher ="John Wiley and Sons", location="Hoboken",
isbn = "978-1-118-34233-6", doi="10.1002/9781119174844" ,
},
customArgs = {exclude="gb-page,q,dq,1",
baseURL = "https://onlinelibrary.wiley.com/doi/book/10.1002/9781119174844", -- online library
defaultTitle = "Fishes of the World",
altTitle = "[[Fishes of the World]]", -- wikilinked for when using chapter/section title
altURL = "https://sites.google.com/site/fotw5th/", -- classification
},
GoogleBooks = { baseURL = "https://books.google.co.uk/books?id=",
id = "E-MLDAAAQBAJ",
defaultPage = "&pg=PP1"
}
}
data.fotw5.default2 = function(targs)
local title = data.fotw5.citationArgs['work']
local url = data.fotw5.customArgs['baseURL']
local chapterParams = { title = title,
['chapter-url']= data.fotw5.customArgs['googleBooks']
}
--return title, url, chapterParams
end
data.BentonVP4 = {
citeTemplate = "Cite book",
citationArgs = {
first1 = "Michael J.", last1 = "Benton",
title = "Vertebrate Palaeontology", edition="4th", year = 2014,
publisher ="John Wiley & Sons",
isbn = "978-1-118-40764-6",
},
customArgs = {exclude="gb-page,q,dq,1",
--baseURL = "",
defaultTitle = "Vertebrate Palaeontology",
altTitle = "[[Vertebrate Palaeontology]]" -- wikilinked for when using chapter/section title
},
GoogleBooks = { baseURL = "https://books.google.co.uk/books?id=",
id = "qak-BAAAQBAJ",
defaultPage = "&pg=PP1",
}
}
--====================TODO FishWisePro==================================================
data.fishwisepro = {
citationArgs = {
['website'] = "[[FishWisePro]]",
},
customArgs = {exclude="family,genus,species,1",
baseURL = ""
}
}
-- #################### AMPHIBIA and REPTILES ###############################
-- ================= Amphibian Species of the World (ASW6)
--[[Recommended citation: Frost, Darrel R. 2019. Amphibian Species of the World: an Online Reference. Version 6.0 (Date of access). Electronic Database accessible at http://research.amnh.org/herpetology/amphibia/index.html. American Museum of Natural History, New York, USA.
URL for family page: http://research.amnh.org/vz/herpetology/amphibia/Amphibia/Anura/Allophrynidae
baseURL = http://research.amnh.org/vz/herpetology/amphibia/
suffix = Amphibia/Anura/Allophrynidae
note: needs the whole hierarchy (except the superfamily which is optional)
Template for main taxonomic listing: {{BioRef|ASW6 |title=Amphibia |year=2019 |url=http://research.amnh.org/herpetology/amphibia/index.html |access-date=27 September 2019}}
SEARCH http://research.amnh.org/vz/herpetology/amphibia/amphib/basic_search?basic_query=Atelopus&stree=&stree_id=
searchSuffix = amphib/basic_search?basic_query=Atelopus&stree=&stree_id=
SEARCH http://research.amnh.org/vz/herpetology/amphibia/content/search?taxon=Allophryn*&subtree=&subtree_id=&english_name=&author=&year=&country=
searchSuffix = /content/search?taxon=Allophryn*&subtree=&subtree_id=&english_name=&author=&year=&country=
minimul = /content/search?taxon=Allophryn*&subtree
]]
data.ASW6 ={
citationArgs = {
website ="Amphibian Species of the World, an Online Reference.",
version = "Version 6.0",
publisher = "American Museum of Natural History, New York",
['last1']="Frost", ['first1']="Darrel R.", ['author1-link']="Darrel R. Frost",
},
customArgs = { exclude = "taxon,species,genus,family, superfamily,1,2,3",
baseURL = "http://research.amnh.org/herpetology/amphibia/",
defaultSuffix = "index.html",
defaultTitle = "ASW Home"
}
}
data.ASW6.species = function(genus, species, subspecies)
-- search for genus+species ()
local title = "Search for taxon: " .. "''" .. genus .. " " .. species .. "''"
--local search = ""?action=names&taxon="" -- old version (pre ASW6)
--local search = "amphib/basic_search?basic_query=" -- basic search
local search = "content/search?taxon=" -- guided search for taxon name
local url = data.ASW6.customArgs['baseURL'] .. search -- .. genus .. '+AND+' .. species
.. '"' .. genus .. '+' .. species .. '"'
return title, url
end
data.ASW6.genus = function(genus)
return data.ASW6.taxon(genus) -- use genus as alias of taxon
end
data.ASW6.taxon = function(taxon)
local title = "Search for Taxon: " .. taxon
local url= data.ASW6.customArgs['baseURL'] .. "content/search?taxon=" .. taxon
return title, url
end
data.ASW6.family = function(family)
local order = data.ASW6.checkOrder(family)
local url= data.ASW6.customArgs['baseURL'] .. "Amphibia/" .. order .. "/" .. firstToUpper(family)
local title = firstToUpper(family)
return title, url
end
data.ASW6.checkOrder = function(family)
local gymnophiona={ "Caeciliidae", "Chikilidae", "Dermophiidae", "Herpelidae", "Ichthyophiidae", "Grandisoniidae", "Indotyphlidae", "Rhinatrematidae", "Scolecomorphidae", "Siphonopidae", "Typhlonectidae" }
local caudata = { "Ambystomatidae", "Amphiumidae", "Cryptobranchidae", "Hynobiidae", "Plethodontidae", "Proteidae", "Rhyacotritonidae", "Salamandridae", "Sirenidae" }
for k,v in pairs(caudata) do
if v == family then return "Caudata" end
end
for k,v in pairs(gymnophiona) do
if v == family then return "Gymnophiona" end
end
return "Anura"
end
--============================= AmphibiaWeb ===================================
--[[ Citation: AmphibiaWeb. 2019. <https://amphibiaweb.org> University of California, Berkeley, CA, USA. Accessed 27 Sep 2019.
Code: {{BioRef|amphibiaweb |title=Amphibia |year=2019 |url=https://amphibiaweb.org/taxonomy/AW_FamilyPhylogeny.html |access-date=27 September 2019}}
--]]
data.amphibiaweb = {
citationArgs = {
website = "AmphibiaWeb",
publisher = "University of California, Berkeley",
--['editor1-last']="", ['editor1-first']="", ['editor1-link']="",
},
customArgs = { exclude = "taxon,species,genus,family,1,2,3",
baseURL = "https://amphibiaweb.org/",
defaultSuffix = "taxonomy/AW_FamilyPhylogeny.html",
defaultTitle = "AmphibiaWeb Family Taxonomy"
}
}
data.amphibiaweb.species = function (genus, species, subspecies)
local title = "''" .. genus .. " " .. species .. "''"
--https://amphibiaweb.org/cgi/amphib_query?where-genus=Altiphrynoides&where-species=malcolmi
local url = data.amphibiaweb.customArgs['baseURL'] .. "cgi/amphib_query?rel-genus=equals&where-genus="
.. genus .. "&rel-species=equals&where-species=" .. species
return title, url
end
data.amphibiaweb.genus = function (genus)
local title = "''" .. genus .. "''"
--https://amphibiaweb.org/cgi/amphib_query?where-genus=Altiphrynoides&where-species=malcolmi
local url = data.amphibiaweb.customArgs['baseURL'] .. "cgi/amphib_query?rel-genus=equals&where-genus="
.. genus .. "&include_synonymies=Yes&show_photos=Yes"
return title, url
end
data.amphibiaweb.family = function (family) -- if family use standardised url
local url = data.amphibiaweb.customArgs['baseURL'] .. "lists/" .. firstToUpper(templateArgs['family']) .. ".shtml"
local title = templateArgs['family']
return title, url
end
--=========================== The Reptile Database
data.reptileDB = {
-- http://reptile-database.reptarium.cz/species?genus=Epacrophis&species=boulengeri
-- recommended citation: Uetz, P., Freed, P. & Hošek, J. (eds.) (2019) The Reptile Database, http://www.reptile-database.org, accessed [insert date here]
-- newer: Uetz, P., Freed, P, Aguilar, R., Reyes, F., Kudera, J. & Hošek, J. (eds.) (2024) The Reptile Database, http://www.reptile-database.org, accessed [insert date here
citationArgs = {
--website="reptile-database.org",
website="[[Reptile Database|The Reptile Database]]",
['editor1-last']="Uetz", ['editor1-first']="P.", --['editor1-link']="Peter Uetz",
['editor2-last']="Freed", ['editor2-first']="P.",
['editor3-last']="Hošek", ['editor3-first']="J.",
--year=2019,
['display-editors'] = 1 -- shows eds as Uetz et al as number of editors has increased and is date dependent
},
customArgs = { exclude = "taxon,species,genus,family,1,2,3",
defaultURL = "http://reptile-database.org/",
baseURL = "http://reptile-database.reptarium.cz/",
defaultTitle = "The Reptile Database"
}
}
data.reptileDB.species = function(genus, species)
data.reptileDB.getDate()
local title = "''" .. genus .. " " .. species .. "''"
--http://reptile-database.reptarium.cz/species?genus=Loxocemus&species=bicolor
local url = data.reptileDB.customArgs['baseURL'] .. "species?genus=" .. genus .. "&species=" .. species
return title, url
end
data.reptileDB.genus = function(genus)
data.reptileDB.getDate()
local title = "''" .. genus .. "''"
--http://reptile-database.reptarium.cz/advanced_search?genus=Malayopython&submit=Search
local url = data.reptileDB.customArgs['baseURL'] .. "advanced_search?genus=" .. genus .. "&exact%5B0%5D=taxon&submit=search"
return title, url
end
data.reptileDB.family = function(family)
return data.reptileDB.taxon(family)
end
data.reptileDB.order = function(order)
return data.reptileDB.taxon(order)
end
data.reptileDB.taxon = function(taxon)
data.reptileDB.getDate()
local title = taxon
--http://reptile-database.reptarium.cz/advanced_search?taxon=Viperidae&exact%5B0%5D=taxon&submit=Search
local url = data.reptileDB.customArgs['baseURL'] .. "advanced_search?taxon=" .. taxon .. "&exact%5B0%5D=taxon&submit=search"
return title, url
end
data.reptileDB.getDate = function()
if templateArgs['date'] and templateArgs['year'] then
templateArgs['access-date'] = templateArgs['date'] .. " " .. templateArgs['year']
templateArgs['date'] = nil
templateArgs['year'] = nil
end
end
data.reptileDB.default = function()
local url = data.reptileDB.customArgs['defaultURL']
local title = data.reptileDB.customArgs['defaultTitle']
return title, url
end
--################################### BIRDS ########################################
--====================Handbook of the Birds of the World Alive (HBW Alive)==============
data.HBWalive = {
citationArgs = {
website="[[Handbook of the Birds of the World|Handbook of the Birds of the World Alive]]",
publisher="Lynx Edicions"
},
customArgs = { exclude="order,family,genus,species,taxon,id,1",
baseURL = "https://www.hbw.com/",
defaultSuffix = "family/home",
defaultTitle = "Family | HBW Alive"
}
}
--############################## HBW ALIVE #########################################
-- family and species entries have mix of common name and taxon name so cannot be prempted;
-- must use title + url (which uses default functions in this module)
data.HBWalive.order = function(order)
local title = "Order " .. firstToUpper(order)
--https://www.hbw.com/order/struthioniformes
local url = target.customArgs['baseURL'] .. "order/" .. order
return title, url
end
--[[======================IOC World Bird List==========================
Gill, F & D Donsker (Eds). 2019. IOC World Bird List (v9.2). doi : 10.14344/IOC.ML.9.2.
Gill F, D Donsker & P Rasmussen (Eds). 2020. IOC World Bird List (v10.2). doi : 10.14344/IOC.ML.10.1.
]]
data.IOC = {
citationArgs = {
website="[[IOC World Bird List]]",
-- version="Version 9.2", -- shouldn't default; should be hardcode so it doesn't change
['editor1-last']="Gill", ['editor1-first']="Frank", ['editor1-link']="Frank Gill (ornithologist)",
['editor2-last']="Donsker", ['editor2-first']="David",
['editor3-last']="Rasmussen", ['editor3-first']="Pamela C.", ['editor3-link']="Pamela C. Rasmussen", -- only shown from version 10.1 onwards
-- doi = "10.14344/IOC.ML.9.2", -- this changes by version number and is not a useful part of the citation
-- publisher="International Ornithological Congress" -- relationship confusing, see https://www.worldbirdnames.org/new/history/
},
customArgs = { exclude="order,family,genus,species,taxon,id,1",
baseURL = "https://www.worldbirdnames.org/",
defaultSuffix = "",
defaultTitle = "IOC World Bird List: Welcome"
},
}
data.IOC.version = function()
local version = templateArgs['version']
local old = false
if version then
version = string.gsub( version, "[Vv]ersion ", "")
local versionNumber = tonumber(version)
if versionNumber < 10.1 then
old = true
end
else
local Date = require('Module:Date')._Date
if Date(templateArgs['access-date']) < Date('1 January 2020') then
old = true
end
end
if old then
data.IOC.citationArgs['editor3-last'] = nil
data.IOC.citationArgs['editor3-first'] = nil
end
end
data.IOC.order = function(order)
data.IOC.version()
local IOCorders = {Struthioniformes='ratites',Rheiformes='ratites',Apterygiformes='ratites',Casuariiformes='ratites',Tinamiformes='ratites',Galliformes='megapodes',Anseriformes='waterfowl',Caprimulgiformes='nightjars',Apodiformes='swifts',Musophagiformes='turacos',Otidiformes='turacos',Cuculiformes='turacos',Mesitornithiformes='turacos',Pterocliformes='turacos',Columbiformes='pigeons',Gruiformes='flufftails',Podicipediformes='grebes',Phoenicopteriformes='grebes',Charadriiformes='sandpipers',Eurypygiformes='loons',Phaethontiformes='loons',Gaviiformes='loons',Sphenisciformes='loons',Procellariiformes='loons',Ciconiiformes='storks',Suliformes='storks',Pelecaniformes='pelicans',Opisthocomiformes='raptors',Accipitriformes='raptors',Strigiformes='owls',Coliiformes='mousebirds',Leptosomiformes='mousebirds',Trogoniformes='mousebirds',Bucerotiformes='mousebirds',Coraciiformes='rollers',Piciformes='woodpeckers',Cariamiformes='falcons',Falconiformes='falcons',Psittaciformes='parrots',
Passeriformes='nz_wrens'} -- passeriformes link not very useful
local title = "Order " .. firstToUpper(order)
local url = data.IOC.customArgs['baseURL'] .. "/bow/" .. IOCorders[order]
return title, url
end
data.IOC.family = function(family)
data.IOC.version()
local IOCfamilies = { Struthionidae = {"ratites", 4}, Alcippeidae = {"babblers", 24989 } } -- temporary partial list for testing
local title = "Family " .. firstToUpper(family)
--https://www.worldbirdnames.org/Family/Struthionidae
local url = data.IOC.customArgs['baseURL'] .. "Family/" .. family -- old version (might be resurrected by IOC)
-- https://www.worldbirdnames.org/new/bow/babblers/#1338626516R24989
if IOCfamilies[family] then -- test version local partial list
url = data.IOC.customArgs['baseURL'] .. "new/bow/" .. IOCfamilies[family][1] .. "/#1338626516R" .. IOCfamilies[family][2]
end
return title, url
end
data.IOC.default = function( title, url)
data.IOC.version()
return title, url
end
data.BOW = {
citationArgs = {
website="Birds of the World Online",
-- doi = "",
-- ['last1']="Winkler", ['first1']="David W.", -- are these always the authors in version 1? no, perhaps for family page
-- ['last2']="Billerman", ['first2']="Shawn M.",
-- ['last3']="Lovette", ['first3']="Irby J.",
-- ['editor1-last']="Billerman", ['editor1-first']="S. M.", --['editor1-link']="",
-- ['editor2-last']="Keeney", ['editor2-first']="B. K.",
-- ['editor3-last']="Rodewald", ['editor3-first']="P. G.",
-- ['editor4-last']="Schulenberg", ['editor4-first']="T. S.",
-- ['version'] = 1, ['year'] = 2020, -- may not want to default
publisher="[[Cornell Lab of Ornithology]], Ithaca, NY."
},
customArgs = { exclude="citation,make,order,family,genus,species,taxon,id,1",
baseURL = "https://birdsoftheworld.org/bow/species/",
defaultSuffix = "",
defaultTitle = "Explore Taxonomy"
},
}
-- function not needed of not adding anything else
data.BOW.default2 = function( title, url)
--data.BOW.citationArgs['version'] = "Version 1"
--mw.addWarning("testing BOW.default function")
return title, url
end
-- id works with the default function data.default.id (id, source)
data.BOW.id2 = function( id)
local url = data.IOC.customArgs['baseURL'] ..id
local title = "BOW id=" .. id
end
--[[ make BOW to parse standard citation, {{BioRef|BOW|citation=CITATION}}
vesrion 1 (family): Winkler, D. W., S. M. Billerman, and I.J. Lovette (2020). Bulbuls (Pycnonotidae), version 1.0. In Birds of the World
(S. M. Billerman, B. K. Keeney, P. G. Rodewald, and T. S. Schulenberg, Editors). Cornell Lab of Ornithology, Ithaca, NY, USA.
https://doi.org/10.2173/bow.pycnon4.01
version 2 (species): Limparungpatthanakij , W. L., L. Fishpool, and J. Tobias (2020). Buff-vented Bulbul (Iole crypta), version 2.0. In Birds of the World
(S. M. Billerman and B. K. Keeney, Editors). Cornell Lab of Ornithology, Ithaca, NY, USA.
https://doi.org/10.2173/bow.buvbul1.02
]]
data.BOW.citation = function( value)
local citation = templateArgs['citation']
data.BOW.citationArgs['year'] = citation:match ('^%D+(%d%d%d%d)')
data.BOW.citationArgs['doi'] = citation:match ('10%.2173/bow%..+') -- https://doi.org/10.2173/bow.pycnon4.01
--data.BOW.citationArgs['version'] = citation:match ('version %d%.%d') -- version applies to page, not whole BOW
local title = citation:match ('%d%d%d%d%)%.(.*, version %d%.%d)'); -- include version number in title
local suffix = citation:match ('10%.2173/bow%.(.+%d?)%.') -- https://doi.org/10.2173/bow.pycnon4.01
local version = "/cur/" -- for the current version
version = citation:match ('version (%d%.%d)') -- for the cited version
local url = data.BOW.customArgs['baseURL'] .. suffix .. '/' .. version .. '/'
title = title:gsub( '%((%D+) (%D+)%)' , "(''%1 %2'')")
local authors = citation:match ('^(%D+) %(%d%d%d%d%)')
if authors then -- split authors with modified code from make cite iucn
local list = {}
--mw.addWarning ("author string: " .. authors)
authors = authors:gsub(", Jr.", "XYZJrX") -- protect author name from splitting on comma
authors = authors:gsub(", and ", ", ") -- for 3 or more authors
authors = authors:gsub(" and ", ", ") -- for 2 editors
list = mw.text.split (authors, ','); -- split the string on the commas into entries in list
if #list == 0 then
--mw.addWarning ("Zero length author list. Please report example of BOW citation at Cite BOW template talk page.");
data.BOW.citationArgs['author'] = authors -- no 'names' of the proper form; return the original as a single |author= parameter
else
for i, name in ipairs (list) do -- for each author in list
--mw.addWarning ("list " .. i .. "=" .. list[i])
if i==1 then --note the first name has last name followed by initials after comma, so takes fill first two parts of the split
data.BOW.citationArgs['last1'] = data.BOW.citationArgs['last1'] or name -- don't everwrite supplied name
elseif i==2 then
data.BOW.citationArgs['first1'] = data.BOW.citationArgs['first1'] or name
elseif i > 2 then
--mw.addWarning ("name " .. i .. "=" .. name)
--data.BOW.citationArgs['last'..i-1] = name:match ('%s(%a-)$')
--data.BOW.citationArgs['first'..i-1] = name:match ('(.+)%s%a-$')
-- regex note: allow for space in names such as del Hoyo
-- used supplied parameter if available (used when fixing diacrticis) or parse name or use unparsed name if that fails
data.BOW.citationArgs['last'..i-1] = data.BOW.citationArgs['last'..i-1] or name:match ('%s([%a ]-)$') or name
data.BOW.citationArgs['first'..i-1] = data.BOW.citationArgs['first'..i-1] or name:match ('(.-)%s[%a ]-$')
--data.BOW.citationArgs['author'..i-1] = nil
else -- something has gone wrong (use author)
data.BOW.citationArgs['author'..i-1] = name
end
if i>1 and 1==2 then
--mw.addWarning ("last" .. tostring(i-1) .. "=" .. data.BOW.citationArgs['last'..i-1])
--mw.addWarning ("first".. tostring(i-1) .. "=" .. data.BOW.citationArgs['first'..i-1])
end
end
for i, name in ipairs (list) do -- for each author in list
if data.BOW.citationArgs['last'..i] then
--mw.addWarning ("check " .. i .. "=" .. data.BOW.citationArgs['last'..i] )
data.BOW.citationArgs['last'..i] =string.gsub(data.BOW.citationArgs['last'..i], "XYZJrX", ", Jr.") -- restored protected string
end
end
end
end
-- now parse editors
local editors = citation:match ('In Birds of the World %((.-), Editors?%)' ) -- omit editors as cite web psoitioning is weird
if editors then -- split editors with modified code from make cite iucn
local list = {}
--mw.addWarning ("editor string: " .. editors)
editors = editors:gsub(", and ", ", ") -- for 3 or more authors
editors = editors:gsub(" and ", ", ") -- for 2 editors
list = mw.text.split (editors, ','); -- split the string on the commas into entries in list
if #list == 0 then
mw.addWarning ("problem with editor splitting")
data.BOW.citationArgs['editor'] = editors -- no 'names' of the proper form; return the original as a single |author= parameter
else
for i, name in ipairs (list) do -- for each author in list
if i>0 then --note the editor names are all same format (unlike authors)
-- data.BOW.citationArgs['editor-last'..i] = name:match ('%s(%a-)$')
-- data.BOW.citationArgs['editor-first'..i] = name:match ('(.+)%s%a-$')
data.BOW.citationArgs['editor-last'..i] = name:match ('%s([%a ]-)$') -- [%a ] for "del Hoyo" or "de Juana"
data.BOW.citationArgs['editor-first'..i] = name:match ('(.-)%s[%a ]-$')
--data.BOW.citationArgs['editor'..i-1] = nil
else -- something has gone wrong (use editor)
-- data.BOW.citationArgs['editor'..i] = name
end
if i>0 and 1==2 then
mw.addWarning ("editor-last" .. tostring(i) .. "=" .. data.BOW.citationArgs['editor-last'..i])
mw.addWarning ("editor-first".. tostring(i) .. "=" .. data.BOW.citationArgs['editor-first'..i])
end
end
end
end
--if not url then url = data.BOW.customArgs['baseURL'] end
--if not title then title = "Title parameter required" end
return title, url
end
--[[ Birdlife International datazone
BirdLife International (2024). Species factsheet: Variable Antshrike Thamnophilus caerulescens.
Downloaded from https://datazone.birdlife.org/species/factsheet/variable-antshrike-thamnophilus-caerulescens on 22/10/2025
--]]
data.birdlife = {
citationArgs = {
website="Birdlife International",
--['editor1-last']="", ['editor1-first']="", --['editor1-link']="",
},
customArgs = { exclude="id,1",
baseURL = "https://datazone.birdlife.org/",
defaultSuffix = "",
defaultTitle = "Species factsheet"
},
}
-- H&M4 website
-- https://www.aviansystematics.org/checklist?viewfamilies=155
data.howardmoore = {
citationArgs = {
website="Trust for Avian Systematics",
},
customArgs = { exclude="order,family,genus,species,taxon,id,1",
baseURL = "https://www.aviansystematics.org/",
defaultSuffix = "",
defaultTitle = "Howard & Moore Checklist Online"
},
}
data.howardmoore.id = function (id)
local title = "Family Id: " .. id
local url = data.howardmoore.customArgs['baseURL'] .. "checklist?viewfamilies=" .. id
return title, url
end
-- basic handling for Taxonomy in Flux website
data.tif = {
citationArgs = {
website="Taxonomy in Flux",
['editor1-last']="Boyd III", ['editor1-first']="John H.", --['editor1-link']="",
},
customArgs = { exclude="order,family,genus,species,taxon,id,1",
baseURL = "http://jboyd.net/Taxo/",
defaultSuffix = "List.html",
defaultTitle = "Taxonomy in Flux"
},
}
--[[ ------------- Avibase
e.g. https://avibase.bsc-eoc.org/species.jsp?avibaseid=9144EF4017F2D8B1
]]
data.avibase = {
citationArgs = {
website="Avibase",
['editor1-last']="Lepage", ['editor1-first']="Denis", --['editor1-link']="",
},
customArgs = { exclude="order,family,genus,species,taxon,id,1",
baseURL = "https://avibase.bsc-eoc.org/",
searchStr = "species.jsp?avibaseid=",
defaultTitle = "Avibase - The World Bird Database"
}
}
--[[ use default function
data.avibase.id = function (id)
local title = "Avibase id: " .. id
local url = data.avibase.customArgs['baseURL'] .. data.avibase.customArgs['searchStr'] .. id
return title, url
end
--]]
-- ============================= IUCN =================================================
-- for species in taxon; for species assessments, use {{cite iucn}}
-- https://www.iucnredlist.org/search?query=Murexia&searchType=species
-- https://www.iucnredlist.org/search?query=aonyx&searchType=species
data.iucn = {
citationArgs = {
website="[[IUCN Red List of Threatened Species]]",
--publisher="[[IUCN]]"
},
customArgs = { exclude="family,genus,species,taxon,id,1",
baseURL = "https://www.iucnredlist.org",
searchString = "/search?query=",
searchSuffix = "&searchType=species",
defaultSuffix = "",
defaultTitle="IUCN Red List of Threatened Species"
}
}
data.iucn.genus = function(genus) return data.iucn.taxon(genus, "TITLE_ITALICS") end
data.iucn.family = function(family) return data.iucn.taxon(family) end
data.iucn.order = function(order) return data.iucn.taxon(order) end
data.iucn.taxon = function(taxon, titleItalics)
local title = firstToUpper(taxon)
if titleItalics then title = "''" .. title .. "''" end
local url = data.iucn.customArgs['baseURL'] .. data.iucn.customArgs['searchString'] .. taxon .. data.iucn.customArgs['searchSuffix']
return title, url
end
-- ============================= NatureServe/TNC =================================================
-- NatureServe Network Biodiversity Location Data. NatureServe, Arlington, Virginia. NatureServe.
-- https://explorer.natureserve.org/Taxon/ELEMENT_GLOBAL.2.747305/Lucanus_capreolus
-- https://explorer.natureserve.org/Taxon/ELEMENT_GLOBAL.2.1253051/Monarda_fistulosa
data.tnc = {
citationArgs = {
website="[[NatureServe|NatureServe Explorer]]",
publisher="NatureServe",
location = "Arlington, Virginia"
},
customArgs = { exclude="family,genus,species,taxon,id,1",
baseURL = "https://explorer.natureserve.org/",
taxonString = "Taxon/ELEMENT_GLOBAL.2.",
defaultTitle="NatureServe Network Biodiversity Location Data"
}
}
data.tnc.species = function(genus,species)
local title = "''" .. firstToUpper(genus) .. " " .. species .. "''"
local url = data.tnc.customArgs['baseURL'] .. data.tnc.customArgs['taxonString'] .. templateArgs['id'] .. "/" .. genus .. "_" .. species
return title, url
end
data.tnc.id = function(id)
local title = data.tnc.customArgs['defaultTitle']
local url = data.tnc.customArgs['baseURL'] .. data.tnc.customArgs['taxonString'] .. templateArgs['id']
return title, url
end
-- ============================= Batnames ==========================================
-- Simmons, N.B. and A.L. Cirranello. 2026. Bat Species of the World: A taxonomic and geographic database. Version 1.11. Accessed on 08/23/2026.
-- https://batnames.org/
-- ============================= ASM Mammal Diversity Database ========================
data.batnames = {
citationArgs = {
website="Bat Species of the World: A taxonomic and geographic database.",
['last1'] = "Simmons", ['first1'] = "Nancy B.", ['author1-link'] = "Nancy Simmons",
['last2'] = "Cirranello", ['first2'] = "Andrea L.",
--publisher="[[American Museum of Natural History]]"
},
customArgs = { exclude="family,genus,species,taxon,id,1,2,3",
baseURL = "https://batnames.org/",
defaultTitle="Batnames"
}
}
--Species: https://batnames.org/species/Nycteris+aurita
data.batnames.species = function(genus, species)
local title = "''" .. firstToUpper(genus) .. " " .. species .. "''"
local url = data.batnames.customArgs['baseURL'] .. "species/" .. genus .. "+" .. species -- case insensitive
return title, url
end
data.batnames.genus = function(genus)
local title = "''" .. firstToUpper(genus) .. "''"
local url = data.batnames.customArgs['baseURL'] .. "genera/" .. genus -- case insensitive
return title, url
end
-- Family: https://batnames.org/family/=Nycteridae [works with family names (super, sub, tribe) and suborders]
data.batnames.family = function(family)
local title = firstToUpper(family)
local url = data.batnames.customArgs['baseURL'] .. "family/=" .. firstToUpper(family) --case sensitive
return title, url
end
data.batnames.taxon = function(taxon) return data.batnames.family (taxon) end
-- ============================= ASM Mammal Diversity Database ========================
data.asm = {
citationArgs = {
website="ASM Mammal Diversity Database",
publisher="[[American Society of Mammalogists]]"
},
customArgs = { exclude="family,genus,species,taxon,id,1,2,3",
baseURL = "https://www.mammaldiversity.org/",
defaultTitle="ASM Mammal Diversity Database"
}
}
data.asm.species2 = function(genus, species) -- use species function below
-- old url = https://mammaldiversity.org/species-account.php?genus=ursus&species=arctos
-- new url = https://www.mammaldiversity.org/explore.html#genus=Dipodomys&species=deserti&id=1001892 (only id required)
local title = "''" .. genus .. " " .. species .. "''"
local url = data.asm.customArgs['baseURL'] .. "explore.html#genus=" .. genus .. "&species=" .. species
if templateArgs['id'] then url = url .. "&id=" .. templateArgs['id'] end
return title, url
end
data.asm.id = function(id)
--local url = data.asm.customArgs['baseURL'] .. "species-account/species-id=" .. templateArgs['id']
-- new format https://www.mammaldiversity.org/explore.html#species-id=1006310
--local url = data.asm.customArgs['baseURL'] .. "explore.html#species-id=" .. id -- templateArgs['id']
-- newer format https://www.mammaldiversity.org/explore.html#genus=Leopardus&species=colocola&id=1005993 (genus and species can be blank)
-- newer (Mar 2024) https://www.mammaldiversity.org/taxon/1006020
local title = "Species-id=" .. id
local hashString = "genus=&species=&id=" .. id -- if id only, requires blank genus and species (superceded by /taxon/link)
if templateArgs['genus'] and templateArgs['species'] then
title = "''" .. templateArgs['genus'] .. " " .. templateArgs['species'] .. "'' (id=" .. id ..")"
hashString = "genus=" .. templateArgs['genus'] .. "&species=" .. templateArgs['species'] .. "&id=" .. id
end
--local url = data.asm.customArgs['baseURL'] .. "explore.html#genus=&species=&id=" .. id -- templateArgs['id']
-- url = data.asm.customArgs['baseURL'] .. "explore.html#" .. hashString
local url = data.asm.customArgs['baseURL'] .. "taxon/" .. id
return title, url
end
data.asm.species = function(genus, species)
if templateArgs['id'] then
return data.asm.id(templateArgs['id']) -- use the ASM explore page if ID given (as permalink)
end
if genus and species then -- otherwisee use the treeview page with the species info
local title = "''" .. firstToUpper(genus) .. " " .. species .. "''"
local url = data.asm.customArgs['baseURL'] .. "tree.html#genus=" .. genus .. "&species=" .. species
return title, url
end
end
data.asm.genus = function(genus) return data.asm.taxon(genus, "genus", "TITLE_ITALICS") end
data.asm.family = function(family) return data.asm.taxon(family, "family") end
data.asm.order = function(order) return data.asm.taxon(order, "order") end
data.asm.taxon = function(taxon, rank, titleItalics)
--https://mammaldiversity.org/#ZmVsaWRhZSZnbG9iYWxfc2VhcmNoPXRydWUmbG9vc2U9dHJ1ZQ
-- Base64.encode(felidae&global_search=true&loose=true)
local title = firstToUpper(taxon)
if titleItalics then title = "''" .. title .. "''" end
local url = data.asm.customArgs['baseURL'] .. "tree.html"
if rank then -- no rank if taxon called directly
url = data.asm.customArgs['baseURL'] .. rank .. "/" .. taxon:lower()
end
return title, url
end
--############################## Base64 encode and decode (used for ASM#####################
local b='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
-- encoding
data.asm.Base64 = {}
data.asm.Base64.encode = function(data)
return ((data:gsub('.', function(x)
local r,b='',x:byte()
for i=8,1,-1 do r=r..(b%2^i-b%2^(i-1)>0 and '1' or '0') end
return r;
end)..'0000'):gsub('%d%d%d?%d?%d?%d?', function(x)
if (#x < 6) then return '' end
local c=0
for i=1,6 do c=c+(x:sub(i,i)=='1' and 2^(6-i) or 0) end
return b:sub(c+1,c+1)
end)..({ '', '==', '=' })[#data%3+1])
end
-- decoding
data.asm.Base64.decode=function(data)
data = string.gsub(data, '[^'..b..'=]', '')
return (data:gsub('.', function(x)
if (x == '=') then return '' end
local r,f='',(b:find(x)-1)
for i=6,1,-1 do r=r..(f%2^i-f%2^(i-1)>0 and '1' or '0') end
return r;
end):gsub('%d%d%d?%d?%d?%d?%d?%d?', function(x)
if (#x ~= 8) then return '' end
local c=0
for i=1,8 do c=c+(x:sub(i,i)=='1' and 2^(8-i) or 0) end
return string.char(c)
end))
end
--######################## Misc ##################################
--[[ 3 approaches to handling DB:
1) use DB as website and use author for editors (if known)
(a) use via to append WoRMS
(b) use postscript to append WoRMs
(c) use publisher for WoRMS
2) use WoRMS as website and designate DB as author (recommended by WoRMS) CURRENT
(option) add editors [TODO see cite WoRMS for list]
issue: what to do about editors changing (need to use access-date)
]]
data.WoRMS = {
citationArgs = {
author = "WoRMS",
website = "[[World Register of Marine Species]]",
--['via'] = "[[World Register of Marine Species]]",
--postscript = ' from the [[World Register of Marine Species]].'
},
customArgs = {exclude="id,db,1",
baseURL = "http://www.marinespecies.org/aphia.php?",
searchStr = "p=taxdetails&id=",
defaultTitle="World Register of Marine Species"
}
}
data.WoRMS.id = function(id)
--[[ Two styles
1. http://www.marinespecies.org/aphia.php?p=taxdetails&id=14712
> WoRMS (2018). Heterobranchia. Accessed at: http://marinespecies.org/aphia.php?p=taxdetails&id=14712 on 2018-11-28
2. http://www.marinespecies.org/aphia.php?p=taxdetails&id=1057249
> MolluscaBase (2018). Ringipleura. Accessed through: World Register of Marine Species at: http://www.marinespecies.org/aphia.php?p=taxdetails&id=1057249 on 2018-11-28
]]
if not templateArgs['id'] then return "no id parameter detected" end
local searchStr = "p=taxdetails&id=" .. templateArgs['id']
if templateArgs['db'] then
data.WoRMS.db (templateArgs['db'])
--[[else -- WoRMS is primary source (note cite WoRMs uses WoRMS as publisher and the db as the work)
templateArgs['via'] = nil
templateArgs['postscript'] = nil]]
end
--templateArgs['website'] = templateArgs['db'] -- alternative (and use |postscript)
--templateArgs['publisher'] = templateArgs['via']
--page <title>WoRMS - World Register of Marine Species - Heterobranchia</title>
local title = "WoRMS taxon details: AphiaID " .. id
local url = data.WoRMS.customArgs['baseURL'] .. data.WoRMS.customArgs['searchStr'] .. id
return title, url
end
data.WoRMS.default = function()
if templateArgs['db'] then
data.WoRMS.db (templateArgs['db'])
end
end
data.WoRMS.db = function(db) -- if database hosted by WoRMS
db = string.lower( db )
if db == "world list of octocorallia" or db == "octocorallia" then
templateArgs['author'] = "World List of Octocorallia"
templateArgs['editor-last1']="McFadden"; templateArgs['editor-first1']="C.S." -- , ; , R.; Samimi-Namin, K.; , G.; , L.
templateArgs['editor-last2']="Cordeiro"; templateArgs['editor-first2']="R."
templateArgs['editor-last3']="Samimi-Namin"; templateArgs['editor-first3']="K."
templateArgs['editor-last4']="Williams"; templateArgs['editor-first4']="G."
templateArgs['editor-last5']="van Ofwegen"; templateArgs['editor-first5']="L."
-- year ? (2022).
elseif db == "world of copepods database" or db == "copepoda" or db == "copepods" or db == "copepod" then
templateArgs['author'] = "World of Copepods Database"
templateArgs['editor-last1']="Walter"; templateArgs['editor-first1']="T.C."
templateArgs['editor-last2']="Boxshall"; templateArgs['editor-first2']="G."
-- year ? (2022).
elseif db == "world amphipoda database" or db == "amphipoda" or db == "amphipod"then
templateArgs['author'] = "World Amphipoda Database"
templateArgs['editor-last1']="Horton"; templateArgs['editor-first1']="T."
templateArgs['editor-last2']="Lowry"; templateArgs['editor-first2']="J."
templateArgs['editor-last3']="De Broyer"; templateArgs['editor-first3']="C."
templateArgs['display-editors']="etal"; -- full list is about 20 names
elseif db == "world isopoda database" or db == "isopoda" or db == "isopod"then
templateArgs['author'] = "World Marine, Freshwater and Terrestrial Isopod Crustaceans database"
templateArgs['editor-last1']="Boyko"; templateArgs['editor-first1']="C.B."
templateArgs['editor-last2']="Bruce"; templateArgs['editor-first2']="N.L."
templateArgs['editor-last3']="Hadfield"; templateArgs['editor-first3']="K.A."
templateArgs['editor-last4']="Merrin"; templateArgs['editor-first4']="K.L."
templateArgs['editor-last5']="Ota."; templateArgs['editor-first5']="Y."
templateArgs['editor-last6']="Poore"; templateArgs['editor-first6']="G.C.B."
templateArgs['editor-last7']="Taiti"; templateArgs['editor-first7']="S."
elseif db == "millibase" or db == "diplopoda" or db == "diplopod"then
templateArgs['author'] = "MilliBase"
templateArgs['editor-last1']="Sierwald"; templateArgs['editor-first1']="P."
templateArgs['editor-last2']="Spelda"; templateArgs['editor-first2']="J."
elseif db == "molluscabase" or db == "mollusca" or db == "mollusc" then
templateArgs['author'] = "MolluscaBase"
else
templateArgs['author'] = templateArgs['db'] -- this is recommended by WoRMS
end
end
--[[ Species files
-- takes db parameter
--https://db.speciesfile.org/otus/$ID/overview
--https://plecoptera.speciesfile.org/otus/890815/overview
]]
data.speciesfile = {
citationArgs = {
website = " Species File",
--publisher = "",
},
customArgs = {exclude="id,1,2,3,4,5,db",
--baseURL = "https://" .. firstToUpper(templateArgs['db'] ) .. ".speciesfile.org/",
--searchStr = "otus/",
-- defaultSuffix = "/overview",
--defaultTitle= " Species File"
}
}
data.speciesfile.id = function(id) -- e.g. https://plecoptera.speciesfile.org/otus/890815/overview
local db = data.speciesfile.db() -- customise for speciesfile
local title = firstToUpper(db) .. " Species File id=" .. id -- use entity = for = to avoid missing pipe CS1 warning
--local url = data.speciesfile.customArgs['baseURL'] .. data.speciesfile.customArgs['searchStr'] .. id .. data.speciesfile.customArgs['defaultSuffix ']
local url = "https://" ..db .. ".speciesfile.org/otus/" .. id .. "/overview"
return title, url
end
data.speciesfile.default = function()
local db = data.speciesfile.db ()
local title = firstToUpper(db) .. " Species File"
local url = "https://" ..db .. ".speciesfile.org/"
return title, url
end
data.speciesfile.db = function()
local db = string.lower( templateArgs['db'] )
-- templateArgs['editor-last1']="Hopkins"; templateArgs['editor-first1']="H."
if db == "zoraptera" then -- ed: Hopkins, H.
templateArgs['editor-last1']="Hopkins"; templateArgs['editor-first1']="H."
elseif db == "dermaptera" then -- eds: Hopkins, H., Haas, F. & Deem, L.S.
templateArgs['editor-last1']="Hopkins"; templateArgs['editor-first1']="H."
templateArgs['editor-last2']="Johnson"; templateArgs['editor-first2']="K.P."
templateArgs['editor-last3']="Smith"; templateArgs['editor-first3']="V.S."
elseif db == "plecoptera" then -- (eds) DeWalt RE, Hopkins H, Neu-Becker U, and Stueber G
templateArgs['editor-last1']="DeWalt"; templateArgs['editor-first1']="R.E."
templateArgs['editor-last2']="Hopkins"; templateArgs['editor-first2']="H."
templateArgs['editor-last3']="Neu-Becker"; templateArgs['editor-first3']="U."
templateArgs['editor-last4']="Stueber"; templateArgs['editor-first4']="G."
elseif db == "orthoptera" then --eds: Cigliano, M.M., H. Braun, D.C. Eades & D. Otte.
templateArgs['editor-last1']="Cigliano"; templateArgs['editor-first1']="M.M."
templateArgs['editor-last2']="Braun"; templateArgs['editor-first2']="H."
templateArgs['editor-last3']="Eades"; templateArgs['editor-first3']="D.C."
templateArgs['editor-last4']="Otte"; templateArgs['editor-first4']="D."
elseif db == "grylloblattodea" then -- ed: Hopkins, H.
templateArgs['editor-last1']="Hopkins"; templateArgs['editor-first1']="H."
elseif db == "mantophasmatodea" then -- ed: Hopkins, H.
templateArgs['editor-last1']="Hopkins"; templateArgs['editor-first1']="H."
elseif db == "embioptera" then -- ed: Hopkins, H.
templateArgs['editor-last1']="Hopkins"; templateArgs['editor-first1']="H."
elseif db == "phasmida" then -- eds: Brock PD, Büscher TH, Baker E.
templateArgs['editor-last1']="Brock"; templateArgs['editor-first1']="P.D."
templateArgs['editor-last2']="Büscher"; templateArgs['editor-first2']="T.H."
templateArgs['editor-last3']="Baker"; templateArgs['editor-first3']="E."
elseif db == "mantodea" then -- not updated yet
elseif db == "cockroach" then -- ed: Beccaloni, G.W.
templateArgs['editor-last1']="Beccaloni"; templateArgs['editor-first1']="G.W."
elseif db == "isoptera" then -- ed: Hopkins, H.
templateArgs['editor-last1']="Hopkins"; templateArgs['editor-first1']="H."
elseif db == "psocodea" then --eds: Hopkins, H., Johnson, K.P., & Smith, V.S.
templateArgs['editor-last1']="Hopkins"; templateArgs['editor-first1']="H."
templateArgs['editor-last2']="Johnson"; templateArgs['editor-first2']="K.P."
templateArgs['editor-last3']="Smith"; templateArgs['editor-first3']="V.S."
elseif db == "aphid" then -- ed: Colin FAVRET
templateArgs['editor-last1']="Favret"; templateArgs['editor-first1']="Colin"
elseif db == "coleorrhyncha" then -- ed: Hopkins, H.
templateArgs['editor-last1']="Hopkins"; templateArgs['editor-first1']="H."
elseif db == "coreoidea" then -- not updated yet
elseif db == "lygaeoidea" then -- eds: Dellapé, Pablo M. & Thomas J. Henry
templateArgs['editor-last1']="Dellapé"; templateArgs['editor-first1']="Pablo M."
templateArgs['editor-last2']="Henry"; templateArgs['editor-first2']="Thomas J."
elseif db == "hoppers" then -- eds: Dmitriev, D.A., Anufriev, G.A., Bartlett, C.R., Blanco-Rodríguez, E., Borodin, Oleg I., Cao, Y.-H., Deitz, L.L., Dietrich, C.H., Dmitrieva, M.O., El-Sonbati, S.A., Evangelista de Souza, O., Gjonov, I.V., Gonçalves, A.C., Hendrix, S., McKamey, S., Kohler, M., Kunz, G., Malenovský, I., Morris, B.O., Novoselova, M., Pinedo-Escatel, J.A., Rakitov, R.A., Rothschild, M.J., Sanborn, A.F., Takiya, D.M., Wallace, M.S., Zahniser, J.N.
templateArgs['editor-last1']="Dmitriev"; templateArgs['editor-first1']="D.A."
templateArgs['editor-last2']="Anufriev"; templateArgs['editor-first2']="G.A."
templateArgs['editor-last3']="Bartlett"; templateArgs['editor-first3']="C.R."
templateArgs['display-editors']="etal"; -- full list is about 28 names
else
--return "Species File database not recognised"
end
if db == "hoppers" then
data.speciesfile.citationArgs['website'] = "World Auchenorrhyncha Database"
else
data.speciesfile.citationArgs['website'] = firstToUpper(db) .. data.speciesfile.citationArgs['website']
end
return db
end
--[[ WaspWeb and FigWeb
WaspWeb: https://www.waspweb.org/Chalcidoidea/Neodiparidae/index.htm
Web authors Simon van Noort (Iziko South African Museum)
Citation: van Noort, S. 2025. WaspWeb: Hymenoptera of the World. URL: www.waspweb.org (accessed on <day/month/year>).
FigWeb
Web authors Simon van Noort (Iziko South African Museum) and Jean-Yves Rasplus (INRA, France)
Citation: van Noort, S. & Rasplus, JY. 2025. Figweb: figs and fig wasps of the world. URL: www.figweb.org(Accessed on <day-month-year>).
]]
data.waspweb = {
citationArgs = {
website = "WaspWeb: Hymenoptera of the World",
['last1'] = "van Noort", ['first1'] = "Simon",
publisher = "[[Iziko South African Museum]]",
},
customArgs = {exclude="id,1,2,3,4,5",
baseURL = "https://www.waspweb.org/",
suffixStr = "Classification/index.htm",
defaultTitle="Classification of World Hymenoptera (Wasps, Bees, Ants)", --
}
}
data.waspweb.default = function(title, url) -- https://www.waspweb.org/Chalcidoidea/Neodiparidae/index.htm
local title = data.waspweb.customArgs['defaultTitle']
local url = data.waspweb.customArgs['baseURL'] .. data.waspweb.customArgs['suffixStr']
return title, url
end
data.figweb = {
citationArgs = {
website = "FigWeb",
['last1'] = "van Noort", ['first1'] = "Simon",
['last2'] = "Rasplus", ['first2'] = "Jean-Yves",
publisher = "[[Iziko South African Museum]]",
},
customArgs = {exclude="id,1,2,3,4,5",
baseURL = "https://www.figweb.org/Fig_wasps/",
suffixStr = "Classification/index.htm",
defaultTitle="Classification of fig wasps"
}
}
data.figweb.default = function(title, url) -- https://www.figweb.org/Fig_wasps/Agaonidae/Agaoninae/index.htm
local title = data.figweb.customArgs['defaultTitle']
local url = data.figweb.customArgs['baseURL'] .. data.figweb.customArgs['suffixStr']
return title, url
end
--[[ Lepindex
]]
data.lepindex = {
citationArgs = {
website = "[[The Global Lepidoptera Names Index]]",
['editor-last1'] = "Beccaloni", ['editor-first1'] = "George", ['editor-last2'] = "Scoble", ['editor-first2'] = "Malcolm",
['editor-last3'] = "Kitching", ['editor-first3'] = "Ian", ['editor-last4'] = "Simonsen", ['editor-first4'] = "Thomas",
['editor-last5'] = "Robinson", ['editor-first5'] = "Gaden", ['editor-last6'] = "Pitkin", ['editor-first6'] = "Brian",
['editor-last7'] = "Hine", ['editor-first7'] = "Adrian", ['editor-last8'] = "Lyal", ['editor-first8'] = "Chris",
publisher = "[[Natural History Museum, London|Natural History Museum]]",
},
customArgs = {exclude="id,1,2,3,4,5",
baseURL = "https://www.nhm.ac.uk/our-science/data/lepindex/",
suffixStr = "detail/?taxonno=",
defaultTitle="Lepindex"
}
}
data.lepindex.id = function(id) -- https://www.nhm.ac.uk/our-science/data/lepindex/detail/?taxonno=51506
local title = "Lepindex id=" .. id
local url = data.lepindex.customArgs['baseURL'] .. data.lepindex.customArgs['suffixStr'] .. id
return title, url
end
--[[ Global Lepidoptra Index
]]
data.gli = {
--Beccaloni, G., Scoble, M., Kitching, I., Simonsen, T., Robinson, G., Pitkin, B., Hine, A., Lyal, C., Ollerenshaw, J., Wing, P., & Hobern, D. (2024). Global Lepidoptera Index (D. Hobern, Ed.; 1.1.24.171).
citationArgs = {
website = "Global Lepidoptera Index",
['last1'] = "Beccaloni", ['first1'] = "George",
['last2'] = "Scoble", ['first2'] = "Malcolm",
['last3'] = "Kitching", ['first3'] = "Ian",
['last4'] = "Simonsen", ['first4'] = "Thomas",
['last5'] = "Robinson", ['first5'] = "Gaden",
['last6'] = "Pitkin", ['first6'] = "Brian",
['last7'] = "Hine", ['first7'] = "Adrian",
['last8'] = "Lyal", ['first8'] = "Chris",
['last9'] = "Ollerenshaw", ['first9'] = "Justin",
['last10'] = "Wing", ['first10'] = "Peter",
['last11'] = "Hobern", ['first11'] = "Donald",
['editor-last'] = "Hobern", ['editor-first'] = "Donald",
publisher = "[[Natural History Museum, London|Natural History Museum]]",
via = "ChecklistBank",
},
customArgs = {exclude="id,1,2,3,4,5",
baseURL = "https://www.checklistbank.org/dataset/55434/",
suffixStr = "taxon/",
defaultTitle="Global Lepidoptera Index",
defaultURL = "https://www.checklistbank.org/dataset/55434/about",
}
}
data.gli.id = function(id) -- https://www.checklistbank.org/dataset/55434/taxon/233256
-- https://www.checklistbank.org/dataset/DATASET_ID/taxon/TAXON_ID -- the dataset ID will change with version so need version handling or just use URL
local title = "GLI id=" .. id
local url = data.gli.customArgs['baseURL'] .. data.gli.customArgs['suffixStr'] .. id
return title, url
end
data.gli.default2 = function()
local title = ""
local url = ""
return title, url
end
--[[ CarabCat - Ground Beetles of the World
https://www.checklistbank.org/dataset/1146/taxon/208583
]]
data.carabcat = {
citationArgs = {
work = "CarabCat",
['last'] = "Lorenz", ['first'] = "Wolfgang",
publisher = "ChecklistBank",
version = "03 (08/2021)",
year = 2021
},
customArgs = {exclude="id,1,2,3,4,5",
baseURL = "https://www.checklistbank.org/dataset/1146/",
searchStr = "taxon/",
defaultTitle="CarabCat"
}
}
data.carabcat.id = function(id)
local title = "CarabCat on ChecklistBank id=" .. id
local url = data.carabcat.customArgs['baseURL'] .. data.carabcat.customArgs['searchStr'] .. id
return title, url
end
--[[ World Scarabaeidae Database (ed. Paul Schoolmeester):
https://www.checklistbank.org/dataset/1027/classification
https://www.checklistbank.org/dataset/1027/taxon/18-.00-.00-.00-.000-.000-.000-.-
]]
data.scarabs = {
citationArgs = {
work = "World Scarabaeidae Database",
['last'] = "Schoolmeester", ['first'] = "Paul",
publisher = "ChecklistBank",
--version = "2026-09-01" -- don't default this
},
customArgs = {exclude="id,1,2,3,4,5",
baseURL = "https://www.checklistbank.org/dataset/1027/",
searchStr = "taxon/",
defaultTitle="World Scarabaeidae Database"
}
}
data.scarabs.id = function(id)
local title = "Scarabs on ChecklistBank id=" .. id
local url = data.scarabs.customArgs['baseURL'] .. data.scarabs.customArgs['searchStr'] .. id
return title, url
end
--[[ ITIS - Integrated Taxonomic Information System
https://www.itis.gov/servlet/SingleRpt/SingleRpt?search_topic=TSN&search_value=95601#null
]]
data.itis = {
citationArgs = {
website = "[[Integrated Taxonomic Information System]]",
--publisher = "",
},
customArgs = {exclude="id,1,2,3,4,5",
baseURL = "https://www.itis.gov/",
searchStr = "servlet/SingleRpt/SingleRpt?search_topic=TSN&search_value=",
defaultTitle="Integrated Taxonomic Information System"
}
}
data.itis.id = function(id)
local title = "ITIS id=" .. id
local url = data.itis.customArgs['baseURL'] .. data.itis.customArgs['searchStr'] .. id
return title, url
end
--[[ Catalogue of Life:
Roskov Y., Ower G., Orrell T., Nicolson D., Bailly N., Kirk P.M., Bourgoin T., DeWalt R.E., Decock W., van Nieukerken E.J., Penev L. (eds.) (2020).
Species 2000 & ITIS Catalogue of Life, 2020-12-01.
Digital resource at www.catalogueoflife.org. Species 2000: Naturalis, Leiden, the Netherlands. ISSN 2405-8858.
Species 2000 & ITIS Catalogue of Life, 2020-12-01. Digital resource at www.catalogueoflife.org.
Species 2000: Naturalis, Leiden, the Netherlands. ISSN 2405-8858.
]]
data.col = {
db = "col", -- need rethink this
citationArgs = {
--author = "Catalogue of Life",
--['editor-last1'] = "Roskov", ['editor-first1'] = "Y.", ['editor-last2'] = "Ower", ['editor-first2'] = "G.", ['editor-last3'] = "Orrell", ['editor-first3'] = "T.", ['editor-last4'] = "Nicolson", ['editor-first4'] = "D.", ['editor-last5'] = "Bailly", ['editor-first5'] = "N.", ['editor-last6'] = "Kirk", ['editor-first6'] = "P.M.", ['editor-last7'] = "Bourgoin", ['editor-first7'] = "T.", ['editor-last8'] = "DeWalt", ['editor-first8'] = "R.E.", ['editor-last9'] = "Decock", ['editor-first9'] = "W.", ['editor-last10'] = "van Nieukerken", ['editor-first10'] = "E.J.", ['editor-last11'] = "Penev", ['editor-first11'] = "L.",
--website = "[[Catalogue of Life]]",
--website = "[[Catalogue of Life|Species 2000 & ITIS Catalogue of Life]]",
-- website = "[[Species 2000]] & [[ITIS]] [[Catalogue of Life]]",
website = "[[Catalogue of Life]]",
publisher = "[[Species 2000]]: Leiden, the Netherlands",
--others = "Species 2000 & ITIS"
},
customArgs = {exclude="id,db,1,2,3,4,5,legacy,option",
baseURL = "https://www.catalogueoflife.org/data/",
searchStr = "browse?taxonKey=",
defaultTitle="Catalogue of Life"
}
}
data.col.id = function(id)
--[[ Catalogue of Life
browse option: https://www.catalogueoflife.org/data/browse?taxonKey=4JQ8
use id for taxoKey
taxon option https://www.catalogueoflife.org/data/taxon/6HR5M
]]
local title = "Catalogue of Life taxonKey " .. id
local url = data.col.customArgs['baseURL']
-- some new CoL are numbers e.g. 64553 in https://www.catalogueoflife.org/data/taxon/64553
if not tonumber(id) and string.find( id, "^[0-9abcdef]+$" ) then -- if old-style id
local year = "2019" -- last old-style version available
if templateArgs['version'] and string.find( templateArgs['version'], "^%d%d%d%d$" ) then --if version specied
year = templateArgs['version']
end
if templateArgs['option'] == "browse" then
url = "http://www.catalogueoflife.org/annual-checklist/" .. year .. "/browse/tree/id/" .. id
else -- default to option=taxon
url = "http://www.catalogueoflife.org/annual-checklist/" .. year .. "/details/species/id/" .. id
end
else -- else use current version
if templateArgs['option'] == "browse" then
url = url .. "browse?taxonKey=" .. id
else -- default to option=taxon
url = url .. "taxon/" .. id
end
end
return title, url
end
--[[ current links
https://www.catalogueoflife.org/data/search?q=" Chinchilla+chinchilla&type=EXACT
legacy links with redirect
Species pages: http://www.catalogueoflife.org/col/details/species/id/12dca9c49741815f82400bb7bff50553
Species searches: http://www.catalogueoflife.org/col/search/all/key/Dracula+antonii/
old-style links
http://www.catalogueoflife.org/col/details/species/id/7539827da517bd6273a4a3836578cb24
http://www.catalogueoflife.org/col/search/scientific/genus/Chinchilla/species/chinchilla/match/1/
http://www.catalogueoflife.org/col/browse/tree/id/003e480e646d0e7647ab67efc1218197
year specific links
2019 http://www.catalogueoflife.org/annual-checklist/2019/details/species/id/7539827da517bd6273a4a3836578cb24
http://www.catalogueoflife.org/annual-checklist/2019/search/all/key/Chinchilla+chinchilla/fossil/1/match/1
http://www.catalogueoflife.org/annual-checklist/2019/search/scientific/genus/Chinchilla/species/chinchilla/match/1/
? http://www.catalogueoflife.org/annual-checklist/2016/browse/tree?6d600f4985f19b1207d41d847424edd0
? http://www.catalogueoflife.org/col/browse/tree/id/003e480e646d0e7647ab67efc1218197
browse http://www.catalogueoflife.org/annual-checklist/2019/browse/tree/id/003e480e646d0e7647ab67efc1218197
]]
data.col.default = function(mode) -- this handles the old style template with positional parameters (mode unused?)
local para1 = templateArgs[2]
local para2 = templateArgs[3]
local para3 = templateArgs[4]
local para4 = templateArgs[5]
if para1 then para1 = mw.text.trim(para1) end
if para2 then para2 = mw.text.trim(para2) end
if para3 then para3 = mw.text.trim(para3) end
if para4 then para4 = mw.text.trim(para4) end
local title, url
if para1 then
--local match = "7539827da517bd6273a4a3836578cb24"
local match = "^[0-9abcdef]+$"
if string.find( para1, match ) then
url = "http://www.catalogueoflife.org/col/details/species/id/" .. para1 -- ""Old style id"
--url ="https://www.catalogueoflife.org/data/search?q=" .. para1
if para2 then
title = para2
else
title = "Oldstyle id: " .. para1
end
else
--https://www.catalogueoflife.org/data/search?q=" Chinchilla+chinchilla&type=EXACT
if para1 ~= "" then
url = "https://www.catalogueoflife.org/data/search?q=" .. para1
title = "''" .. para1
if para2 then
url = url .. "+" .. para2
title = title .. " " .. para2
end
url = url .. "&type=EXACT"
title = title .. "''"
end
end
if para3 then title = title .. " " .. para3 end -- add authority
if para4 == "nv" then templateArgs['trans-title'] = "synonym" end -- if nv add [synonym]. Note that this parameter is not used to add COinS metadata
else
-- no parameter 1
end
return title, url
end
--====================== Fossilworks =======================================
data.fossilworks = {
citationArgs = {
website="[[Fossilworks]]",
agency="Gateway to the [[Paleobiology Database]]",
--publisher="Paleobiology Database",
--postscript = 'none',
-- postscript = " from the [[Paleobiology Database]].", -- gives maintenance warning
--via="''fossilworks.org''" -- an alternative format to using |website=
},
customArgs = { exclude = "id,collection,1",
baseURL = "http://www.fossilworks.org/cgi-bin/",
searchStr ="bridge.pl?a=taxonInfo&taxon_no=",
defaultTitle = "Fossilworks: Gateway to the Paleobiology Database"
}
--id = function(id) return p.genericIdCitation (frame, title, url)
}
data.fossilworks.id = function(id)
--[[ http://fossilworks.org/cgi-bin/bridge.pl?a=taxonInfo&taxon_no=83087
if not templateArgs['id'] then return "no id parameter detected" end
local searchStr = "bridge.pl?a=taxonInfo&taxon_no=" .. templateArgs['id']
templateArgs['url']= target.CustomArgs['baseURL'] .. searchStr
]]
local title = "PaleoDB taxon number: " .. id
local url = data.fossilworks.customArgs['baseURL'] .. data.fossilworks.customArgs['searchStr'] .. id
return title, url
end
data.fossilworks.collection = function(collection)
-- http://fossilworks.org/bridge.pl?a=collectionSearch&collection_no=20072
local title = "PaleoDB collection number: " .. collection
local url = data.fossilworks.customArgs['baseURL'] .. "bridge.pl?a=collectionSearch&collection_no=" .. collection
return title, url
end
data.fossilworks.error = function()
return "Requires id and title parameters"
end
--====================== Paleobiology Database: paleobiodb.org =======================================
data.paleobiodb = {
citationArgs = {
website="[[Paleobiology Database]]"
},
customArgs = { exclude = "id,collection,1",
baseURL = "https://paleobiodb.org/classic/",
searchStr ="basicTaxonInfo?taxon_no=",
defaultTitle = "Paleobiology Database"
}
--id = function(id) return p.genericIdCitation (frame, title, url)
}
data.paleobiodb.id = function(id)
--[[ https://paleobiodb.org/classic/basicTaxonInfo?taxon_no=22786
if not templateArgs['id'] then return "no id parameter detected" end
]]
local title = "PaleoDB taxon number: " .. id
local url = data.paleobiodb.customArgs['baseURL'] .. data.paleobiodb.customArgs['searchStr'] .. id
return title, url
end
data.paleobiodb.collection = function(collection)
-- https://paleobiodb.org/classic/basicCollectionSearch?collection_no=24193
local title = "PaleoDB collection number: " .. collection
local url = data.paleobiodb.customArgs['baseURL'] .. "basicCollectionSearch?collection_no=" .. collection
return title, url
end
data.paleobiodb.error = function()
return "Requires id and title parameters"
end
--======================================= PLANTS =========================
--[[ Plant authorities can end in a period. This is stripped by the citation templates.
This function encloses titles ending in such authorities in double parentheses, i.e. ((title))
]]
local addAuthority = function(formattedTaxonName)
if templateArgs['authority'] then
local title = formattedTaxonName .. " " .. templateArgs['authority']
return string.gsub( title, "(.*%.)$", "((%1))") -- if authority ends in "." enclose ((title)) to prevent removal
end
return formattedTaxonName
end
--[[ Hassler, Michael (2004 - 2020): World Plants. Synonymic Checklist and Distribution of the World Flora.
Version x.xx; last update xx.xx.xxxx. - www.worldplants.de. Last accessed dd/mm/yyyy.
https://www.worldplants.de/world-plants-complete-list/complete-plant-list#1599996425
Hassler, Michael (2004 - 2020): World Ferns. Synonymic Checklist and Distribution of Ferns and Lycophytes of the World.
Version x.xx; last update xx.xx.xxxx. - www.worldplants.de/ferns/. Last accessed dd/mm/yyyy.
https://www.worldplants.de/world-ferns/ferns-and-lycophytes-list#1599997555
deeplinks:
Genus: [https://www.worldplants.de?deeplink=Helosciadium-Koch ''Helosciadium'']
Species: [https://www.worldplants.de?deeplink=Helosciadium-longipedunculatum ''Helosciadium longipedunculatum'']
Genus: [https://www.worldplants.de?deeplink=Lycopodium-L. ''Lycopodium'']
Species: [https://www.worldplants.de?deeplink=Lycopodium-clavatum ''Lycopodium clavatum'']
--]]
data.worldplants = {
citationArgs = {
last1 = "Hassler", first1 = "Michael",
website="World Plants. Synonymic Checklist and Distribution of the World Flora.",
--publisher=""
},
customArgs = { exclude = "id,authority,family,genus,species,1",
baseURL = "https://www.worldplants.de",
searchStr ="/world-plants-complete-list/complete-plant-list#",
defaultSuffix = "",
defaultTitle = "World Plants"
}
}
data.worldplants.genus = function(genus)
local title = addAuthority("''" .. genus .. "''")
local genusString = genus
if templateArgs['authority'] then genusString = genus .. "-" .. templateArgs['authority'] end
local url = data.worldplants.customArgs['baseURL'] .. "?deeplink=" .. genusString
return title, url
end
data.worldplants.species = function(genus, species)
local title = addAuthority("''" .. genus .. " " .. species .. "''")
local url = data.worldplants.customArgs['baseURL'] .. "?deeplink=" .. genus .. "-" .. species .. " " .. (templateArgs['authority'] or "")
return title, url
end
--[[ experimental, don't leave live
data.worldplants.taxon = function(taxon)
local title = taxon .. " " .. (templateArgs['authority'] or "")
local url = data.worldplants.customArgs['baseURL'] .. "?deeplink=" .. taxon
return title, url
end
data.worldplants.family = function(family)
local title = family .. " " .. (templateArgs['authority'] or "")
local url = data.worldplants.customArgs['baseURL'] .. "?deeplink=" .. family
return title, url
end
--]]
data.worldferns = {
citationArgs = {
last1 = "Hassler", first1 = "Michael",
website="World Ferns. Synonymic Checklist and Distribution of the World Flora.",
--publisher=""
},
customArgs = { exclude = "id,authority,family,genus,species,1",
baseURL = "https://www.worldplants.de/",
searchStr ="world-ferns/ferns-and-lycophytes-list?name=",
defaultSuffix = "",
defaultTitle = "World Ferns"
}
}
data.worldferns.genus = function(genus)
local title = addAuthority("''" .. genus .. "''")
local genusString = genus
if templateArgs['authority'] then genusString = genus .. "-" .. templateArgs['authority'] end
local url = data.worldferns.customArgs['baseURL'] .. data.worldferns.customArgs['searchStr'] .. genusString
return title, url
end
data.worldferns.species = function(genus, species)
local title = addAuthority("''" .. genus .. " " .. species .. "''")
local url = data.worldferns.customArgs['baseURL'] .. data.worldferns.customArgs['searchStr'] .. genus .. "-" .. species .. " " .. (templateArgs['authority'] or "")
return title, url
end
--[[Plants of the World online
http://powo.science.kew.org/taxon/urn:lsid:ipni.org:names:30003057-2 -- use id
http://powo.science.kew.org/?q=Selaginellaceae -- use search
http://powo.science.kew.org/?family=Selaginellaceae -- can also use family= [gets same result as q=]
http://powo.science.kew.org/?genus=Selago -- or genus
http://powo.science.kew.org/?genus=Selago&species=abietina -- or genus + species
http://powo.science.kew.org/?genus=Selago&f=accepted_names -- filter for accepted names
http://powo.science.kew.org/?genus=Selago&f=genus_f -- filter for genus (no species selected)
http://powo.science.kew.org/?genus=Selago&f=genus_f%2Caccepted_names -- filter for genus and accepted names
http://powo.science.kew.org/?page.size=480&f=family_f%2Caccepted_names -- list of accepted families
-- all these searches get the search result (no apparent way to target the article when unique)
]]
data.POWO = {
citationArgs = {
website="[[Plants of the World Online]]",
publisher="Royal Botanic Gardens, Kew",
--postscript = 'none',
},
customArgs = { exclude = "id,authority,family,genus,species,1",
baseURL = "http://powo.science.kew.org/taxon/",
searchStr ="urn:lsid:ipni.org:names:",
defaultSuffix = "",
defaultTitle = "Plants of the World Online"
}
--id = function(id) return p.genericIdCitation (frame, title, url)
}
--[[ http://powo.science.kew.org/taxon/urn:lsid:ipni.org:names:30003057-2 ]]
data.POWO.id = function(id)
local id = data.POWO.getValidID()
if not id then return data.POWO.error() end
local title = id -- as default value
local url = data.POWO.customArgs['baseURL'] .. data.POWO.customArgs['searchStr'] .. id
return title, url
end
data.POWO.family = function(family)
local title = addAuthority(family)
local id = templateArgs['id']
if not id then return data.POWO.error() end
local url = data.POWO.customArgs['baseURL'] .. data.POWO.customArgs['searchStr'] .. id
return title, url
end
data.POWO.genus = function(genus)
local title = addAuthority("''" .. genus .. "''")
local id = data.POWO.getValidID()
if not id then return data.POWO.error() end
local url = data.POWO.customArgs['baseURL'] .. data.POWO.customArgs['searchStr'] .. id
return title, url
end
data.POWO.species = function(genus,species)
local title = addAuthority("''" .. genus .. " " .. species .. "''")
local id = data.POWO.getValidID()
if not id then return data.POWO.error() end
local url = data.POWO.customArgs['baseURL'] .. data.POWO.customArgs['searchStr'] ..id
return title, url
end
data.POWO.getValidID = function()
local id = templateArgs['id']
if id then
return string.gsub( id, "urn:lsid:ipni.org:names:", "") -- don't want this twice
end
return nil
end
data.POWO.error = function()
return '<span style="color:red">Requires id and one of title, family, genus or species parameters</span>'
end
--[[Gouda, E.J., Butcher, D. & Gouda, C.S. (cont.updated)
Encyclopaedia of Bromeliads, Version 4. http://bromeliad.nl/encyclopedia/ Utrecht University Botanic Gardens
]]
data.bromeliad = {
citationArgs = {
last1="Gouda", first1="E.J.",
last2="Butcher", first2="D.",
last3="Gouda", first3="C.S",
website="[[Encyclopaedia of Bromeliads]]",
version="Version 4",
publisher="Utrecht University Botanic Gardens",
--postscript = 'none',
},
customArgs = { exclude = "id,authority,family,genus,species,list,1",
baseURL = "https://bromeliad.nl/",
searchStr ="encyclopedia/index.php?find=",
defaultSuffix = "",
defaultTitle = "Encyclopaedia of Bromeliads, Version 4"
}
--id = function(id) return p.genericIdCitation (frame, title, url)
}
--[[ https://bromeliad.nl/encyclopedia/index.php?find=Hylaeaicum ]]
data.bromeliad.search = function(search)
local title = search -- as default value
local url = data.bromeliad.customArgs['baseURL'] .. data.bromeliad.customArgs['searchStr'] .. search
return title, url
end
--[[ http://bromeliad.nl/species/Bromeliaceae ]]
data.bromeliad.taxon = function(taxon)
local title = addAuthority(taxon) -- as default value
local url = data.bromeliad.customArgs['baseURL'] .. "species/" .. taxon
return title, url
end
--[[ genus ]]
data.bromeliad.genus = function(genus)
local title = addAuthority("''" .. genus .. "''") -- as default value
local url = data.bromeliad.customArgs['baseURL'] .. "species/" .. genus
if templateArgs['list'] == "species" then
url = data.bromeliad.customArgs['baseURL'] .. "encyclopedia/brome.php?action=showSpeciesIndex&name=" .. genus .. "&flags="
end
return title, url
end
--[[ ]]
data.bromeliad.species = function(genus, species)
local title = addAuthority("''" .. genus .. " " .. species .. "''") -- as default value
local url = data.bromeliad.customArgs['baseURL'] .. "species/" .. genus .. "/" .. species
return title, url
end
--[[ https://bromeliad.nl/encyclopedia/brome.php?action=showTaxon&id=10093 ]]
data.bromeliad.id = function(id)
local title = id -- as default value
local url = data.bromeliad.customArgs['baseURL'] .. "encyclopedia/brome.php?action=showTaxon&id=" .. id
return title, url
end
--[[GRIN
Cite as: USDA, Agricultural Research Service, National Plant Germplasm System. 2021. Germplasm Resources Information Network (GRIN Taxonomy). National Germplasm Resources Laboratory, Beltsville, Maryland.
URL: https://npgsweb.ars-grin.gov/gringlobal/taxon/taxonomyfamily?type=tribe&id=1571. Accessed 27 October 2021.
Family record: https://npgsweb.ars-grin.gov/gringlobal/taxon/taxonomyfamily?id=440
Genus list: https://npgsweb.ars-grin.gov/gringlobal/taxon/taxonomygenuslist?id=440&type=family
Subfamily record: https://npgsweb.ars-grin.gov/gringlobal/taxon/taxonomyfamily?type=subfamily&id=1507
Genus list: https://npgsweb.ars-grin.gov/gringlobal/taxon/taxonomygenuslist?id=3265&type=subfamily
Tribe record: https://npgsweb.ars-grin.gov/gringlobal/taxon/taxonomyfamily?type=tribe&id=1551 (Millettieae)
Genus list: https://npgsweb.ars-grin.gov/gringlobal/taxon/taxonomygenuslist?id=1551&type=tribe
Subtribe record: https://npgsweb.ars-grin.gov/gringlobal/taxon/taxonomyfamily?type=subtribe&id=1507
Genus list: https://npgsweb.ars-grin.gov/gringlobal/taxon/taxonomygenuslist?id=1507&type=subtribe
Genus record: https://npgsweb.ars-grin.gov/gringlobal/taxon/taxonomygenus?id=191 (Genus Adenodolichos Harms)
Species list: https://npgsweb.ars-grin.gov/gringlobal/taxon/taxonomyspecieslist?id=191&type=genus
Species record: https://npgsweb.ars-grin.gov/gringlobal/taxon/taxonomydetail?id=489203 ( Adenodolichos paniculatus)
]]
data.GRIN = {
citationArgs = {
website="[[Germplasm Resources Information Network]] (GRIN)",
publisher="[[Agricultural Research Service]] (ARS), [[United States Department of Agriculture]] (USDA)",
--postscript = 'none',
},
customArgs = { exclude = "id,authority,family,genus,species,1",
baseURL = "https://npgsweb.ars-grin.gov/gringlobal",
searchStr ="/taxon/taxonomydetail?", -- for species record
defaultSuffix = "",
defaultTitle = "GRIN-Global"
}
--id = function(id) return p.genericIdCitation (frame, title, url)
}
data.GRIN.id = function(id)
local title = data.GRIN.customArgs['defaultTitle'] .. ' ' .. id
local url = data.GRIN.customArgs['baseURL'] .. data.GRIN.customArgs['searchStr'] .. id
return title, url
end
--[[ USDA PLANTS
default search page: https://plants.sc.egov.usda.gov/
taxon: https://plants.sc.egov.usda.gov/plant-profile/RUID (Rubus idaeus L., American red raspberry)
]]
data.PLANTS = {
citationArgs = {
--last = "[[Natural Resources Conservation Service|NRCS]]",
website="PLANTS Database",
--publisher="[[United States Department of Agriculture]] (USDA)",
publisher="[[Natural Resources Conservation Service|USDA Natural Resources Conservation Service]]",
--postscript = 'none',
},
customArgs = { exclude = "id,1",
baseURL = "https://plants.sc.egov.usda.gov/",
searchStr ="plant-profile/", -- for species profile
defaultSuffix = "",
defaultTitle = "Plants Database"
}
--id = function(id) return p.genericIdCitation (frame, title, url)
}
data.PLANTS.id = function(id)
local title = data.PLANTS.customArgs['defaultTitle'] .. ' ' .. id
local url = data.PLANTS.customArgs['baseURL'] .. data.PLANTS.customArgs['searchStr'] .. id
return title, url
end
-- IPNI
--→ "Meconopsis Vig." International Plant Names Index (IPNI). Royal Botanic Gardens, Kew.
--- https://www.ipni.org/n/30149252-2
--- as {{IPNI |id=30149252-2 |taxon=((Meconopsis |authority=Vig.))}}
data.IPNI = {
citationArgs = {
website="[[International Plant Names Index]] (IPNI)",
publisher="Royal Botanic Gardens, Kew",
--postscript = 'none',
},
customArgs = { exclude = "id,authority,family,genus,species,1",
baseURL = "https://www.ipni.org",
searchStr ="/n/",
defaultSuffix = "",
defaultTitle = "IPNI"
}
--id = function(id) return p.genericIdCitation (frame, title, url)
}
data.IPNI.id = function(id)
local title = id
local url = data.IPNI.customArgs['baseURL'] .. data.IPNI.customArgs['searchStr'] .. id
return title, url
end
data.IPNI.species = function(genus, species) return data.IPNI.taxon(genus .. " " .. species, "TITLE_ITALICS") end
data.IPNI.genus = function(genus) return data.IPNI.taxon(genus, "TITLE_ITALICS") end
data.IPNI.taxon = function(taxon, italics)
local title = taxon
if italics then title = "''" .. title .. "''" end
title = addAuthority(title)
--[[ if templateArgs['authority'] then
title = title .. " " .. templateArgs['authority']
title = string.gsub( title, "(.*%.)$", "((%1))") -- if authority ends in "." enclose ((title)) to prevent removal
end ]]
local url = data.IPNI.customArgs['baseURL'] .. data.IPNI.customArgs['searchStr'] .. templateArgs['id']
return title, url
end
--[[World Flora Online
http://www.worldfloraonline.org/taxon/wfo-4000012284 -- id
]]
data.WFO = {
citationArgs = {
website="[[World Flora Online]]",
--publisher="Missouri Botanical Gardens",
--postscript = 'none',
},
customArgs = { exclude = "id,family,genus,species,authority,1",
baseURL = "http://www.worldfloraonline.org",
searchStr ="/taxon/wfo-", -- not strictly search string
defaultSuffix = "",
--defaultTitle = "World Flora Online"
defaultTitle = "An Online Flora of All Known Plants"
}
}
data.WFO.getValidID = function()
local id = templateArgs['id']
if id then
return string.gsub( id, "wfo%-", "") -- don't want this twice (must escape -)
end
mw.addWarning("Citations for WFO require a valid ID")
return ""
end
data.WFO.id = function(id)
--[[ http://www.worldfloraonline.org/taxon/wfo-4000012284
]]
id = data.WFO.getValidID()
local title = id
local url = data.WFO.customArgs['baseURL'] .. data.WFO.customArgs['searchStr'] .. id
return title, url
end
data.WFO.family = function(family)
local title = addAuthority(family)
local url = data.WFO.customArgs['baseURL'] .. data.WFO.customArgs['searchStr'] .. data.WFO.getValidID()
return title, url
end
data.WFO.genus = function(genus)
local title = addAuthority("''" .. genus .. "''")
local url = data.WFO.customArgs['baseURL'] .. data.WFO.customArgs['searchStr'] .. data.WFO.getValidID()
return title, url
end
data.WFO.species = function(genus,species)
local title = addAuthority("''" .. genus .. " " .. species .. "''")
local url = data.WFO.customArgs['baseURL'] .. data.WFO.customArgs['searchStr'] ..data.WFO.getValidID()
return title, url
end
data.WFO.error = function()
return "Requires id and title parameters"
end
data.Tropicos = {
citationArgs = {
website="[[Tropicos]]",
--publisher="Missouri Botanical Gardens",
--postscript = 'none',
},
customArgs = { exclude = "id,1",
baseURL = "http://legacy.tropicos.org/Name/",
searchStr ="",
defaultSuffix = "",
defaultTitle = "Tropicos"
}
}
data.Tropicos.id = function(id)
--[[ hhttp://legacy.tropicos.org/Name/100444532
]]
local title = id
local url = data.Tropicos.customArgs['baseURL'] .. data.Tropicos.customArgs['searchStr'] .. id
return title, url
end
data.Tropicos.error = function()
return "Requires id and title parameters"
end
data.FNA = {
citationArgs = {
website="[[Flora of North America]]",
--publisher="http://www.efloras.org",
--postscript = 'none',
},
customArgs = { exclude = "id,1",
baseURL = "http://www.efloras.org/florataxon.aspx",
searchStr ="?flora_id=1&taxon_id=",
defaultSuffix = "",
defaultTitle = "Flora of North America"
}
--id = function(id) return p.genericIdCitation (frame, title, url)
}
data.FNA.id = function(id)
--[[ http://www.efloras.org/florataxon.aspx?flora_id=1&taxon_id=125683
]]
local title = id
local url = data.FNA.customArgs['baseURL'] .. data.FNA.customArgs['searchStr'] .. id
return title, url
end
data.FNA.error = function()
return "Requires id and title parameters"
end
-- Australian Plant Name Index (APNI)
data.APNI = {
citationArgs = {
website="[[Australian Plant Name Index]]",
publisher="[[Centre for Australian National Biodiversity Research]]", -- IBIS database
--version = "Edition 8",
},
customArgs = { exclude = "name, qid, authority, genus, species,authority, id,1",
baseURL = "https://id.biodiversity.org.au/name/apni/",
searchURL = "https://biodiversity.org.au/nsl/services/search/names?product=APNI&tree.id=&name=",
defaultSuffix = "",
defaultTitle = "APNI"
}
--id = function(id) return p.genericIdCitation (frame, title, url)
}
data.APNI.id = function(id)
local title = addAuthority( templateArgs['taxon'] )
local url = data.APNI.customArgs['baseURL'] .. id
return title, url
end
data.APNI.taxon = function(taxon)
local title = addAuthority( taxon )
local url = data.APNI.customArgs['baseURL'] .. templateArgs['id']
return title, url
end
-- SEARCH
--https://biodiversity.org.au/nsl/services/search/names?product=APNI&tree.id=&name=ficus
--https://biodiversity.org.au/nsl/services/search/names?product=APNI&tree.id=&name=ficus&inc._scientific=&inc.scientific=on&inc._cultivar=&inc._other=&max=100&display=apni&search=true
data.APNI.search = function(taxon)
local title = addAuthority( taxon )
local url = data.APNI.customArgs['searchURL'] .. taxon:gsub(" ","+")
return title, url
end
-- ATRP: Australian Tropical Rainforest Plants
data.ATRP = {
citationArgs = {
website="[[Australian Tropical Rainforest Plants]]",
publisher="[[Commonwealth Scientific and Industrial Research Organisation]] (CSIRO)",
version = "Edition 8",
year = 2020,
--postscript = 'none',
last1= "Zich", first1="F. A.",
last2= "Hyland", first2= "B. P. M.", ['author2-link']="Bernard Hyland",
last3= "Whiffin", first3= "T.",
last4= "Kerrigan", first4= "R.A.",
--['display-authors']=3,
},
customArgs = { exclude = "genus, species,authority, id,1",
baseURL = "https://apps.lucidcentral.org/rainforest",
searchStr ="/text/entities/",
defaultSuffix = ".htm",
defaultTitle = "[[Australian Tropical Rainforest Plants]]"
}
--id = function(id) return p.genericIdCitation (frame, title, url)
}
data.ATRP.species = function(genus,species)
--[[ https://apps.lucidcentral.org/rainforest/text/entities/buckinghamia_celsissima.htm
]]
local title = addAuthority("''" .. genus .. " " .. species .. "''") --"''" .. genus .. " " .. species .. "''"
local url = data.ATRP.customArgs['baseURL'] .. data.ATRP.customArgs['searchStr'] .. genus .. "_" .. species .. data.ATRP.customArgs['defaultSuffix']
return title, url
end
data.ATRP.error = function()
return "Requires genus and species parameters"
end
--[[ ============================= Bryonames (Mosses etc) The Bryophyte Nomenclator =================================================
https://www.bryonames.org/nomenclator?group=Bryidae&group_id=35210272 (A Classification of the Bryidae)
https://www.bryonames.org/nomenclator?group=Hedwigiales (A Classification of the Hedwigiale)
https://www.bryonames.org/nomenclator?group=Rhacocarpus (A synopsis of Rhacocarpus)
--]]
data.bryonames = {
citationArgs = {
['editor1-first']="John C.", ['editor1-last']="Brinda",
['editor2-first']="John J.", ['editor2-last']="Atwood",
website="The Bryophyte Nomenclator"
--publisher="[[xxx]]"
},
customArgs = { exclude="family,genus,species,taxon,id,1",
baseURL = "https://www.bryonames.org/",
searchString = "nomenclator?group=",
defaultTitle="Classification of the Bryophyta"
}
}
data.bryonames.genus = function(genus) return data.bryonames.taxon(genus, "GENUS") end
data.bryonames.family = function(family) return data.bryonames.taxon(family, "FAMILY") end
data.bryonames.order = function(order) return data.bryonames.taxon(order, "ORDER") end
data.bryonames.taxon = function(taxon, rank)
taxon = firstToUpper(taxon)
local title = "A Classification of the " .. taxon -- default title for suprafamilia taxa
local url = data.bryonames.customArgs['baseURL'] .. data.bryonames.customArgs['searchString'] .. taxon -- url
if rank == "GENUS" then taxon = "''" .. taxon .. "''" end -- italicise genus
if rank == "GENUS" or rank == "FAMILY" then title = "A synopsis of " .. taxon end -- title for genus and familiees
return title, url
end
-- ============================= Mosses (Goffinet's site) =================================================
-- https://bryology.uconn.edu/classification/#Hypnanae
-- https://bryology.uconn.edu/classification/#Bryales
data.goffinet = {
citationArgs = {
first1="B.", last1="Goffinet",
first2="W.R.", last2="Buck",
website="Classification of extant moss genera"
--publisher="[[xxx]]"
},
customArgs = { exclude="family,genus,species,taxon,id,1",
baseURL = "https://bryology.uconn.edu/classification/",
searchString = "#",
searchSuffix = "",
defaultSuffix = "",
defaultTitle="Classification of the Bryophyta"
}
}
data.goffinet.genus = function(genus) return data.goffinet.taxon(genus, "GENUS") end
data.goffinet.family = function(family) return data.goffinet.taxon(family, "FAMILY") end
data.goffinet.order = function(order) return data.goffinet.taxon(order, "ORDER") end
data.goffinet.taxon = function(taxon, rank)
local title = firstToUpper(taxon)
if rank == "GENUS" then title = "''" .. title .. "''" end
if not (rank == "GENUS" or rank == "FAMILY") then -- upper case anchors for orders and above
if taxon ~= "Bryanae" and taxon ~= "Hypnanae" and taxon ~= "Bryales" and taxon ~= "Bryidae" then -- check for exceptions (inconsistencies at website)
taxon = taxon:upper()
end
end
local url = data.goffinet.customArgs['baseURL'] .. data.goffinet.customArgs['searchString'] .. taxon .. data.goffinet.customArgs['searchSuffix']
return title, url
end
--[[ AlgaeBase
(old) taxonomy browser url (Volvox) = https://www.algaebase.org/browse/taxonomy/?id=6898
taxonomy browser url (Volvox) = https://www.algaebase.org/browse/taxonomy/?#6898
genus article url (Volvox) = https://www.algaebase.org/search/genus/detail/?genus_id=43497 (different id)
genus article url (Torodinium)= https://www.algaebase.org/search/genus/detail/?genus_id=44698
Please cite this record as: M.D. Guiry in Guiry, M.D. & Guiry, G.M. 2020. AlgaeBase.
World-wide electronic publication, National University of Ireland, Galway.
http://www.algaebase.org; searched on 10 May 2020.
]]
data.AlgaeBase = {
citationArgs = {
website="[[AlgaeBase]]",
['editor1-last']="Guiry", ['editor1-first']="M.D.",
['editor2-last']="Guiry", ['editor2-first']="G.M.",
publisher="National University of Ireland, Galway",
},
customArgs = { exclude = "id,1,genus_id,species_id,spid,genid",
baseURL = "https://www.algaebase.org/",
--searchStr ="browse/taxonomy/?id=", (old)
searchStr ="browse/taxonomy/?#",
defaultSuffix = "",
defaultTitle = "AlgaeBase"
}
}
data.AlgaeBase.id = function(id)
--[[ https://www.algaebase.org/browse/taxonomy/?id=6898 (id for taxonomy page)
]]
local title = id
local url = data.AlgaeBase.customArgs['baseURL'] .. data.AlgaeBase.customArgs['searchStr'] .. id
return title, url
end
data.AlgaeBase.genid = function(genid)
--[[ https://www.algaebase.org/search/genus/detail/?genus_id=43497 (different id for genus page)
]]
local title = genid
local url = data.AlgaeBase.customArgs['baseURL'] .. "search/genus/detail/?genus_id=" .. genid
return title, url
end
data.AlgaeBase.spid = function(spid)
--[[ https://www.algaebase.org/search/species/detail/?species_id=52713 (id for species page)
]]
local title = spid
local url = data.AlgaeBase.customArgs['baseURL'] .. "search/species/detail/?species_id=" .. spid
return title, url
end
data.AlgaeBase.error = function()
return "Requires id and title parameters"
end
--[[================= Bacteria (LPSN) =========
-- LPSN - List of Prokaryotic names with Standing in Nomenclature
]]
data.lpsn = {
citationArgs = {
website="LPSN - List of Prokaryotic names with Standing in Nomenclature",
--['editor1-last']="xx", ['editor1-first']="xx",
--['editor2-last']="xx", ['editor2-first']="xx",
publisher="Leibniz Institute DSMZ",
},
customArgs = { exclude = "id,1,rank",
baseURL = "https://lpsn.dsmz.de/",
searchStr ="",
defaultSuffix = "",
defaultTitle = "LPSN - List of Prokaryotic names with Standing in Nomenclature"
}
}
data.lpsn.id = function(id)
-- https://lpsn.dsmz.de/taxon/25894
local title = "IPSN Record Number: " .. id
local url = data.lpsn.customArgs['baseURL'] .. 'taxon/' .. id
return title, url
end
data.lpsn.taxon = function(taxon)
--[[ general form: https://lpsn.dsmz.de/RANK/TAXON_NAME
e.g. https://lpsn.dsmz.de/phylum/cyanobacteriota (for phyla)
https://lpsn.dsmz.de/class/cyanophyceae (for classes)
use title and url parameters
]]
local title = taxon
local rank =templateArgs['rank']
local url
if rank then
url = data.lpsn.customArgs['baseURL'] .. rank .. '/' .. taxon
end
return title, url
end
--================= Viruses =========
data.ictv = {
citationArgs = {
website="ictv.global",
--['editor1-last']="xx", ['editor1-first']="xx",
--['editor2-last']="xx", ['editor2-first']="xx",
author="International Committee on Taxonomy of Viruses (ICTV)",
},
customArgs = { exclude = "id,1",
baseURL = "https://ictv.global/taxonomy/",
searchStr ="taxondetails?taxnode_id=",
defaultSuffix = "",
defaultTitle = "Taxonomy Browser"
}
}
data.ictv.id = function(id)
--[[ https://ictv.global/taxonomy/taxondetails?taxnode_id=202308917&taxon_name=Campanilevirus%20YC (for species Campanilevirus YC)
https://ictv.global/taxonomy/taxondetails?taxnode_id=202308917 (also works with just the id)
]]
local title = id
local url = data.ictv.customArgs['baseURL'] .. data.ictv.customArgs['searchStr'] .. id
return title, url
end
data.ictv.error = function()
return "Requires id and title parameters"
end
--############################## General Functions ########################################
local function getArgs (frame, args)
local parents = mw.getCurrentFrame():getParent()
for k,v in pairs(parents.args) do
--check content
if v and v ~= "" then
args[k]=v --parents.args[k]
end
end
for k,v in pairs(frame.args) do
--check content
if v and v ~= "" then
args[k]=v
end
end
end
local function initialise(frame, sourceDB)
target=sourceDB
templateArgs = sourceDB.citationArgs -- get custom arguments for target (fishbase, cof etc
getArgs(frame, templateArgs) -- get template arguments from parent frame and frane
local url = (target.customArgs['baseURL'] or "") .. (target.customArgs['defaultSuffix'] or "")
local title = target.customArgs['defaultTitle'] or ""
return title, url
end
-- moved up top for scope
local function firstToUpper2(str)
return (str:gsub("^%l", string.upper))
end
-- clear template arguments that won't be recognised by {{cite web}}
local function clearCustomArgs()
local excludeTable = { 'genus', 'species', 'subspecies', 'family', 'order', 'taxon',
'id', 'search' , 'citation', 1, 2, 3, 4 } -- add defaults ?
if target.customArgs['exclude'] then
local customTable = mw.text.split (target.customArgs['exclude'] , "%s*,%s*");
for k,v in pairs(customTable) do
table.insert (excludeTable, v )
end
end
for k,v in pairs(excludeTable) do
if tonumber (v) then
v = tonumber (v) --convert positional parameters (numbers as string) to a number
end
templateArgs[v]=nil --clear content
end
end
-- function handling the cite web template
p.citeWeb = function(frame, title, url)
-- set url and title if not provided (template parameters override above)
if not templateArgs['url'] and url then
templateArgs['url']= url
end
if not templateArgs['title'] and title then
templateArgs['title'] = title
end
clearCustomArgs()--blank template parameters not for cite web
local citeTemplate = 'cite web' -- use Template:Cite web unless specified
--if target.citeTemplate then citeTemplate = target.citeTemplate end
return frame:expandTemplate{ title = citeTemplate, args = templateArgs }
end
-- p.CiteBook
-- for reasons of consisitency within BioRef/FishRef the title parameter is the section-title of {{cite book}}
p.citeBook = function(frame, title, url, chapterParams) -- very much a msw3 function
--if (1==1) then return templateArgs['title'] end
-- set url and title if not provided (template parameters override above)
if not templateArgs['url'] and url then
templateArgs['url']= url
if target.GoogleBooks then
templateArgs['url'] = target.GoogleBooks['baseURL'] .. target.GoogleBooks['id']
.. (target.GoogleBooks['defaultPage'] or "&pg=PP1")
end
end
if not templateArgs['title'] and title then
-- templateArgs['title'] = title
end
if templateArgs['title'] ~= title or templateArgs['taxon-title'] then -- do we have a section title provided
templateArgs['section'] = templateArgs['title'] -- chapter/section title passed as title parameter
templateArgs['title'] = title -- the work is the book title given in the source data
if target.GoogleBooks then
templateArgs['section-url'] = target.GoogleBooks['baseURL'] .. target.GoogleBooks['id']
local pageSuffix = target.GoogleBooks['defaultPage'] or ""
if templateArgs['page'] or templateArgs['gb-page'] then
pageSuffix = "&pg=PT" .. (templateArgs['gb-page'] or templateArgs['page'] )
end
local searchStr = ""
-- quoted search {{#if:{{{text|{{{dq|}}}}}}|&dq={{urlencode:{{{text|{{{dq|}}}}}}}}}}
if templateArgs['q'] then searchStr = "&q=" .. mw.text.encode( templateArgs['q'] ) end
-- search #if:{{{keywords|{{{q|}}}}}}|&q={{urlencode:{{{keywords|{{{q|}}}}}}}}}}
if templateArgs['dq'] then searchStr = "&dq=" .. mw.text.encode( templateArgs['dq'] ) end
templateArgs['section-url'] = templateArgs['section-url'] .. pageSuffix .. searchStr
templateArgs['url'] = nil -- no need for second link to google books
end
-- if the chapter/section is linked, we can link the main book chapter differently
if target.customArgs['altTitle'] then -- if we are using a chapter/section, we can wikilink the book title
templateArgs['title'] = target.customArgs['altTitle'] -- alternative to allow wikilink
elseif target.customArgs['altURL'] then
templateArgs['url'] = target.customArgs['altURL']
end
end -- end if using supplied title for chapter/section
clearCustomArgs()--blank template parameters not for cite web
local citeTemplate = 'cite book' -- use Template:Cite web unless specified
--if target.citeTemplate then citeTemplate = target.citeTemplate end
return frame:expandTemplate{ title = citeTemplate, args = templateArgs }
end
-- common function for genus and species
local function getGenusSpecies()
--TODO standardise genus species handling
local genus, species, subspecies
if (templateArgs['genus'] or templateArgs[2] ) then
genus = templateArgs['genus'] or templateArgs[2]
genus = firstToUpper(mw.text.trim(genus))
end
if (templateArgs['species'] or templateArgs[3] ) then
species = templateArgs['species'] or templateArgs[3]
species = mw.text.trim(species)
end
if (templateArgs['subspecies'] or templateArgs[4] ) then
subspecies = templateArgs['subspecies'] or templateArgs[4]
subspecies = mw.text.trim(subspecies)
end
return genus, species, subspecies
end
--#################### MSW3 -- uses cite book
p.MSW3 = function(frame)
local msw = require('Module:FishRef/MSW')
initialise(frame, msw.MSW3)
return msw.MSW3.main(frame,templateArgs)
end
p.MSW3merged = function(frame)
local data = require('Module:FishRef/MSW')
return p._main(frame, data.MSW3)
end
p.MSW3_standalone = function(frame)
local data = require('Module:FishRef/MSW')
initialise(frame, data.MSW3)
local url = target.CustomArgs['baseURL']
if templateArgs['title'] and templateArgs['id'] then
templateArgs['chapter-url']= url .. target.CustomArgs['searchStr'] .. templateArgs['id']
templateArgs['chapter'] = templateArgs['title']
templateArgs['title'] = target.CustomArgs['bookTitle']
if templateArgs['page'] then
templateArgs['url'] = target.CustomArgs['googleBooksURL'] .. templateArgs['page']
else
--return "Page number for google books required"
end
elseif templateArgs['order'] then
templateArgs['chapter'] = "Order " .. templateArgs['order']
local chapter = target.chapters[templateArgs['order']]
for k,v in pairs(chapter) do -- add chapter specific parameters
templateArgs[k] = v
end
templateArgs['chapter-url']= url .. target.CustomArgs['searchStr'] .. templateArgs['id']
templateArgs['url']= target.CustomArgs['googleBooksURL'] .. templateArgs['page']
if templateArgs['pages'] and templateArgs['page'] then templateArgs['page'] = nil end
else -- default output
templateArgs['url']= target.CustomArgs['googleBooksURL'] .. "1" -- default to book
templateArgs['url']= url
end
-- using cite book
clearCustomArgs()--blank template parameters not for cite web
return frame:expandTemplate{ title = 'cite book', args = templateArgs }
end
--########################### Functions for access (using invoke) ##############################################
--================ Fishbase, Catalog of Fishes (cof) ================
p.fishbase = function(frame) return p._main(frame, data.fishbase) end
p.cof = function(frame) return p._main(frame, data.cof) end
p.fotw5 = function(frame) return p._main(frame, data.fotw5) end
--=================== ASW6, AmphibiaWeb, ReptileDB
p.reptileDB = function(frame) return p._main(frame, data.reptileDB) end
p.ASW6 = function(frame) return p._main(frame, data.ASW6) end
p.amphibiaweb = function(frame) return p._main(frame, data.amphibiaweb) end
--=========== Birds
p.HBWa = function(frame) return p._main(frame, data.HBWalive) end
p.HBWalive = function(frame) return p._main(frame, data.HBWalive) end
p.IOC = function(frame) return p._main(frame, data.IOC) end
p.BOW = function(frame) return p._main(frame, data.BOW) end
--======= Mammals
p.asm = function(frame) return p._main(frame, data.asm) end
--======= Plants
p.WFO = function(frame) return p._main(frame, data.WFO) end
p.POWO = function(frame) return p._main(frame, data.POWO) end
-- MSW3 has custom handling (see above)
--=========== Other
p.fossilworks = function(frame) return p._main(frame, data.fossilworks) end
p.worms = function(frame) return p._main(frame, data.WoRMS) end
p.WoRMS = function(frame) return p._main(frame, data.WoRMS) end
p.col = function(frame) return p._main(frame, data.col) end
--fallback = function() return "hello" end
--#########################################################
p.main = function(frame)
local source = mw.text.trim(frame.args[1])
--TODO force to lower case and use lower case for all functions above
if source == "MSW3" then return p.MSW3(frame) end
if source == "ref" or source == "reference" then source = "Reference" end -- aliases
if source == "Reference" then return p.Reference(frame) end
if source == "HBWa" then source = "HBWalive" end -- aliases
if source == "powo" then source = "POWO" end -- aliases
if source == "wfo" then source = "WFO" end -- aliases
if source == "IUCN" then source = "iucn" end -- aliases
if source == "MDD" then source = "asm" end -- aliases
if source == "mdd" then source = "asm" end -- aliases
if source == "PBDB" then source = "paleobiodb" end -- aliases
--return p[source]['test']
if source == "fishbase" -- unnecessary?
or source == "cof"
or source == "fotw5" or source == "Fotw5"
or source == "reptileDB"
or source == "amphibiaweb"
or source == "BOW"
or source == "ASW6"
or source == "asm"
or source == "HBWalive" or source == "HBWa"
or source == "fossilworks"
or source == "WoRMS" or source == "worms"
or source == "POWO" or source == "powo"
or source == "WFO" or source == "wfo"
or source == "AlgaeBase"
-- and so on
then return p._main(frame,data[source])
else
--
-- is there a point in the default if it needs the named object/table?
return p._main(frame,data[source])
end
end
p._main = function(frame, source)
--TODO in modular version source will be provided in frame arguments
--local source = mw.getCurrentFrame():getParent().args[1]
local chapterParams = {} -- used for cite book (only MSW3 at moment)
if not source then
return error_msg("Error: unrecognised taxonomy source. See [[Template:Cite taxon]] for supported sources.")
end
local title, url = initialise(frame, source)
--taxon related parameters
local genus, species, subspecies
if source.db ~= "col" then -- col legacy uses positional parameters differently
genus, species, subspecies = getGenusSpecies()
end
local family = templateArgs['family']
local order = templateArgs['order']
local taxon = templateArgs['taxon']
local id = templateArgs['id'] --id related parameters
local spid = templateArgs['spid'] or templateArgs['species_id']
local genid = templateArgs['genid'] or templateArgs['genus_id']
local citation = templateArgs['citation']
local collection = templateArgs['collection'] or templateArgs['collection_no']
local search = templateArgs['search']
local mode, value
-- the functions
if genus and species and source.species then
title, url = source.species(genus,species,subspecies)
else -- functions with just their own name as parameter
if taxon then mode = "taxon"; value = taxon
elseif order then mode = "order"; value = order
elseif family then mode = "family"; value = family
elseif genus then mode = "genus"; value = genus
elseif id then mode = "id"; value = id
elseif spid then mode = "spid"; value = spid
elseif genid then mode = "genid"; value = genid
elseif search then mode = "search"; value = search
elseif citation then mode = "citation"; value = citation
elseif collection then mode = "collection"; value = collection
else
-- no suitable parameter (use default page)
if source.default then
title, url, chapterParams = source.default(title, url)
end
end
end
if mode then
if source[mode] then
title, url, chapterParams = source[mode](value)
elseif data.default[mode] then
title, url, chapterParams = data.default[mode](value, source)
else
if source.error then return source.error() end -- custom error message
return error_msg("Error: parameter not supported for this source" .. " (" .. mode .. ")")
end
else
-- if no mode then use the default title and url set by initialize()
end
if source.citeTemplate == "Cite book" then
return p.citeBook(frame, title, url, chapterParams)
end
return p.citeWeb(frame, title, url)
end -- End the function.
p.Reference = function(frame)
local refs = require('Module:FishRef/refs')
getArgs(frame, templateArgs)
if templateArgs[2] then
local reference = mw.text.trim(templateArgs[2])
if reference ~= "" and refs[reference] then
if templateArgs['pages'] then
refs[reference] = refs[reference]:gsub("}}", "|pages="..templateArgs['pages'].."}}")
refs[reference] = refs[reference]:gsub("|pages=[^|{}%[%]]*(|[^|{}}%[%]]*|pages=)", "%1")
end
if templateArgs['reftags'] == "yes" then
refs[reference] = '<ref name=' .. templateArgs[2] ..'>' .. refs[reference] .. '</ref>'
end
if templateArgs['expand'] and templateArgs['expand']=='no' or templateArgs['raw'] then
return refs[reference]
else
return frame:preprocess(refs[reference])
end
else
return 'Reference not found: "' .. templateArgs[2] .. '"'
end
end
return "Reference parameter missing."
end -- End the function.
-- All modules end by returning the variable containing its functions to Wikipedia.
return p
mph26w738t77m0pten883f469eo2u8r
Seunaleuëk:Taxonomy/Plectorhinchinae
10
33900
159032
2026-10-10T17:12:18Z
Rachmat04
7338
Geupeugöt laman ngön asoë '{{Don't edit this line {{{machine code|}}} |rank=subfamilia |link=Plectorhinchinae |parent=Haemulidae |refs= {{Cof family | family = Haemulidae | access-date = 12 April 2021}} }}'
159032
wikitext
text/x-wiki
{{Don't edit this line {{{machine code|}}}
|rank=subfamilia
|link=Plectorhinchinae
|parent=Haemulidae
|refs= {{Cof family | family = Haemulidae | access-date = 12 April 2021}}
}}
r50083ca5296qfvgh8l68gqz9s6n8y5
Seunaleuëk:Taxonomy/Haemulidae
10
33901
159033
2026-10-10T17:12:42Z
Rachmat04
7338
Geupeugöt laman ngön asoë '{{Don't edit this line {{{machine code|}}} |rank=familia |link=Haemulidae |parent=Acanthuriformes |refs={{cite journal |title=Eschmeyer's Catalog of Fishes Classification - California Academy of Sciences |journal=www.calacademy.org |url=https://www.calacademy.org/scientists/catalog-of-fishes-classification/ |access-date=1 November 2024 |language=en}} }}'
159033
wikitext
text/x-wiki
{{Don't edit this line {{{machine code|}}}
|rank=familia
|link=Haemulidae
|parent=Acanthuriformes
|refs={{cite journal |title=Eschmeyer's Catalog of Fishes Classification - California Academy of Sciences |journal=www.calacademy.org |url=https://www.calacademy.org/scientists/catalog-of-fishes-classification/ |access-date=1 November 2024 |language=en}}
}}
cui5lw4bf9i8w464ily1qhqwl79j2v3
Seunaleuëk:Taxonomy/Acanthuriformes
10
33902
159034
2026-10-10T17:13:01Z
Rachmat04
7338
Geupeugöt laman ngön asoë '{{Don't edit this line {{{machine code|}}} |rank=ordo |link=Acanthuriformes |parent=Eupercaria |refs={{cite web |url=https://www.calacademy.org/scientists/catalog-of-fishes-classification/ |title=Eschmeyer's Catalog of Fishes Classification |access-date=25 October 2024 |work=Eschmeyer's Catalog of Fishes |publisher=[[California Academy of Sciences]]}} }}'
159034
wikitext
text/x-wiki
{{Don't edit this line {{{machine code|}}}
|rank=ordo
|link=Acanthuriformes
|parent=Eupercaria
|refs={{cite web |url=https://www.calacademy.org/scientists/catalog-of-fishes-classification/ |title=Eschmeyer's Catalog of Fishes Classification |access-date=25 October 2024 |work=Eschmeyer's Catalog of Fishes |publisher=[[California Academy of Sciences]]}}
}}
lw5tnm8hnflk6fi9wb549gstobkrk45
Seunaleuëk:Taxonomy/Eupercaria
10
33903
159035
2026-10-10T17:13:20Z
Rachmat04
7338
Geupeugöt laman ngön asoë '{{Don't edit this line {{{machine code|}}} |rank=clade |link=Eupercaria |parent=Percomorpha |refs= <!--Shown on this page only; don't include <ref> tags --> }}'
159035
wikitext
text/x-wiki
{{Don't edit this line {{{machine code|}}}
|rank=clade
|link=Eupercaria
|parent=Percomorpha
|refs= <!--Shown on this page only; don't include <ref> tags -->
}}
40bo7pcmbp8xemt6c6vry0htq5oq2uj
Seunaleuëk:Taxobox/taxonomy/ex1
10
33904
159036
2026-10-10T17:17:31Z
Rachmat04
7338
Geupeugöt laman ngön asoë '<noinclude><!-- -======================================================================= - Template:Taxobox/taxonomy/ex1: Show upper row set #1 of infobox taxons -======================================================================= -- --></noinclude>{{ #ifeq:<!--left brace: -->{|{{padleft:|1|{{taxonomy/{{taxonomy/{{taxonomy/{{taxonomy/{{taxonomy/{{taxonomy/{{taxonomy/{{taxonomy/{{taxonomy/{{taxonomy/{{{1|Acacia}}}|machine code=parent}}|machine code=parent}}...'
159036
wikitext
text/x-wiki
<noinclude><!--
-=======================================================================
- Template:Taxobox/taxonomy/ex1: Show upper row set #1 of infobox taxons
-=======================================================================
--
--></noinclude>{{
#ifeq:<!--left brace: -->{|{{padleft:|1|{{taxonomy/{{taxonomy/{{taxonomy/{{taxonomy/{{taxonomy/{{taxonomy/{{taxonomy/{{taxonomy/{{taxonomy/{{taxonomy/{{{1|Acacia}}}|machine code=parent}}|machine code=parent}}|machine code=parent}}|machine code=parent}}|machine code=parent}}|machine code=parent}}|machine code=parent}}|machine code=parent}}|machine code=parent}}|machine code=parent}} }}
|<!--then more would exceed top of tree; don't try higher name rows-->
|<!--else show higher names-->{{taxobox/taxonomy/ex2
|{{taxonomy/{{taxonomy/{{taxonomy/{{taxonomy/{{taxonomy/{{taxonomy/{{taxonomy/{{taxonomy/{{taxonomy/{{taxonomy/{{{1|Acacia}}}|machine code=parent}}|machine code=parent}}|machine code=parent}}|machine code=parent}}|machine code=parent}}|machine code=parent}}|machine code=parent}}|machine code=parent}}|machine code=parent}}|machine code=parent}}
|2={{{2|1}}} }}<!--endtaxobox/taxonomy/ex2 -->
}}<!--endifeq-else "{" error --><!--
The above uses {taxobox/taxonomy/ex2} to show even higher taxon rows.
The below creates the next 10 levels of lower taxonomy, after the
above levels (if any), on the request of the calling template.
------------------------------------------ Show rows of name levels -->
{{taxobox/showtaxon |LEVEL=10 |{{taxonomy/{{taxonomy/{{taxonomy/{{taxonomy/{{taxonomy/{{taxonomy/{{taxonomy/{{taxonomy/{{taxonomy/{{{1|Acacia}}}|machine code=parent}}|machine code=parent}}|machine code=parent}}|machine code=parent}}|machine code=parent}}|machine code=parent}}|machine code=parent}}|machine code=parent}}|machine code=parent}} |authority={{{authority|}}} |fc={{#ifexpr:{{{2|1}}}>18|true|}} }}
{{taxobox/showtaxon |LEVEL=9 |{{taxonomy/{{taxonomy/{{taxonomy/{{taxonomy/{{taxonomy/{{taxonomy/{{taxonomy/{{taxonomy/{{{1|Acacia}}}|machine code=parent}}|machine code=parent}}|machine code=parent}}|machine code=parent}}|machine code=parent}}|machine code=parent}}|machine code=parent}}|machine code=parent}}|authority={{{authority|}}} |fc={{#ifexpr:{{{2|1}}}>17|true|}} }}
{{taxobox/showtaxon |LEVEL=8 |{{taxonomy/{{taxonomy/{{taxonomy/{{taxonomy/{{taxonomy/{{taxonomy/{{taxonomy/{{{1|Acacia}}}|machine code=parent}}|machine code=parent}}|machine code=parent}}|machine code=parent}}|machine code=parent}}|machine code=parent}}|machine code=parent}}|authority={{{authority|}}} |fc={{#ifexpr:{{{2|1}}}>16|true|}} }}
{{taxobox/showtaxon |LEVEL=7 |{{taxonomy/{{taxonomy/{{taxonomy/{{taxonomy/{{taxonomy/{{taxonomy/{{{1|Acacia}}}|machine code=parent}}|machine code=parent}}|machine code=parent}}|machine code=parent}}|machine code=parent}}|machine code=parent}}|authority={{{authority|}}} |fc={{#ifexpr:{{{2|1}}}>15|true|}} }}
{{taxobox/showtaxon |LEVEL=6 |{{taxonomy/{{taxonomy/{{taxonomy/{{taxonomy/{{taxonomy/{{{1|Acacia}}}|machine code=parent}}|machine code=parent}}|machine code=parent}}|machine code=parent}}|machine code=parent}}|authority={{{authority|}}} |fc={{#ifexpr:{{{2|1}}}>14|true|}} }}
{{taxobox/showtaxon |LEVEL=5 |{{taxonomy/{{taxonomy/{{taxonomy/{{taxonomy/{{{1|Acacia}}}|machine code=parent}}|machine code=parent}}|machine code=parent}}|machine code=parent}}|authority={{{authority|}}} |fc={{#ifexpr:{{{2|1}}}>13|true|}} }}
{{taxobox/showtaxon |LEVEL=4 |{{taxonomy/{{taxonomy/{{taxonomy/{{{1|Acacia}}}|machine code=parent}}|machine code=parent}}|machine code=parent}}|authority={{{authority|}}}|fc={{#ifexpr:{{{2|1}}}>12|true|}} }}
{{taxobox/showtaxon |LEVEL=3 |{{taxonomy/{{taxonomy/{{{1|Acacia}}}|machine code=parent}}|machine code=parent}}|authority={{{grandparentauthority|}}}|fc={{#ifexpr:{{{2|1}}}>11|true|}} }}<!--
---------------------------- Parent taxon-->
{{taxobox/showtaxon |LEVEL=2 |{{taxonomy/{{{1|Acacia}}}|machine code=parent}}|authority={{{parentauthority|}}}|fc={{#ifexpr:{{{2|1}}}>10|true}} }}<!--
------------------------------------------- Show row of last taxon -->
{{taxobox/showtaxon |LEVEL=1 |{{ucfirst:{{{1|Acacia}}}}}|authority={{{authority|}}} |fc={{#ifexpr:{{{2|1}}}>9|true}} }}<noinclude>
{{documentation}}
</noinclude>
tgukk6ozew9j77kdtz8jvskm4b24ftt
Seunaleuëk:Taxobox/taxonomy/ex2
10
33905
159037
2026-10-10T17:18:22Z
Rachmat04
7338
Geupeugöt laman ngön asoë '<noinclude><!-- -======================================================================= - Template:Taxobox/taxonomy/ex2: Show extra infobox row set #2 taxons -======================================================================= -- --></noinclude>{{ #ifeq:<!--left brace: -->{|{{padleft:|1|{{taxonomy/{{taxonomy/{{taxonomy/{{taxonomy/{{taxonomy/{{taxonomy/{{taxonomy/{{taxonomy/{{taxonomy/{{taxonomy/{{{1|Ursa}}}|machine code=parent}}|machine code=parent}}|mach...'
159037
wikitext
text/x-wiki
<noinclude><!--
-=======================================================================
- Template:Taxobox/taxonomy/ex2: Show extra infobox row set #2 taxons
-=======================================================================
--
--></noinclude>{{
#ifeq:<!--left brace: -->{|{{padleft:|1|{{taxonomy/{{taxonomy/{{taxonomy/{{taxonomy/{{taxonomy/{{taxonomy/{{taxonomy/{{taxonomy/{{taxonomy/{{taxonomy/{{{1|Ursa}}}|machine code=parent}}|machine code=parent}}|machine code=parent}}|machine code=parent}}|machine code=parent}}|machine code=parent}}|machine code=parent}}|machine code=parent}}|machine code=parent}}|machine code=parent}} }}
|<!--then more would exceed top of tree; don't try higher name rows-->
|<!--else show higher names-->{{taxobox/taxonomy/ex3 |{{taxonomy/{{taxonomy/{{taxonomy/{{taxonomy/{{taxonomy/{{taxonomy/{{taxonomy/{{taxonomy/{{taxonomy/{{taxonomy/{{{1|Ursa}}}|machine code=parent}}|machine code=parent}}|machine code=parent}}|machine code=parent}}|machine code=parent}}|machine code=parent}}|machine code=parent}}|machine code=parent}}|machine code=parent}}|machine code=parent}}
|2={{{2|1}}} }}<!--endtaxobox/taxonomy/ex3 -->
}}<!--endifeq-else "{" error --><!--
The above uses {taxobox/taxonomy/ex3} to show even higher taxon rows.
The below creates the next 10 levels of lower taxonomy, after the
above levels (if any), on the request of the calling template.
------------------------------------------ Show rows of name levels -->
{{taxobox/showtaxon |LEVEL=10 |{{taxonomy/{{taxonomy/{{taxonomy/{{taxonomy/{{taxonomy/{{taxonomy/{{taxonomy/{{taxonomy/{{taxonomy/{{{1|Ursa}}}|machine code=parent}}|machine code=parent}}|machine code=parent}}|machine code=parent}}|machine code=parent}}|machine code=parent}}|machine code=parent}}|machine code=parent}}|machine code=parent}}|fc={{#ifexpr:{{{2|1}}}>28|true|}} }}
{{taxobox/showtaxon |LEVEL=9 |{{taxonomy/{{taxonomy/{{taxonomy/{{taxonomy/{{taxonomy/{{taxonomy/{{taxonomy/{{taxonomy/{{{1|Ursa}}}|machine code=parent}}|machine code=parent}}|machine code=parent}}|machine code=parent}}|machine code=parent}}|machine code=parent}}|machine code=parent}}|machine code=parent}}|fc={{#ifexpr:{{{2|1}}}>27|true|}} }}
{{taxobox/showtaxon |LEVEL=8 |{{taxonomy/{{taxonomy/{{taxonomy/{{taxonomy/{{taxonomy/{{taxonomy/{{taxonomy/{{{1|Ursa}}}|machine code=parent}}|machine code=parent}}|machine code=parent}}|machine code=parent}}|machine code=parent}}|machine code=parent}}|machine code=parent}}|fc={{#ifexpr:{{{2|1}}}>26|true|}} }}
{{taxobox/showtaxon |LEVEL=7 |{{taxonomy/{{taxonomy/{{taxonomy/{{taxonomy/{{taxonomy/{{taxonomy/{{{1|Ursa}}}|machine code=parent}}|machine code=parent}}|machine code=parent}}|machine code=parent}}|machine code=parent}}|machine code=parent}}|fc={{#ifexpr:{{{2|1}}}>25|true|}} }}
{{taxobox/showtaxon |LEVEL=6 |{{taxonomy/{{taxonomy/{{taxonomy/{{taxonomy/{{taxonomy/{{{1|Ursa}}}|machine code=parent}}|machine code=parent}}|machine code=parent}}|machine code=parent}}|machine code=parent}}|fc={{#ifexpr:{{{2|1}}}>24|true|}} }}
{{taxobox/showtaxon |LEVEL=5 |{{taxonomy/{{taxonomy/{{taxonomy/{{taxonomy/{{{1|Ursa}}}|machine code=parent}}|machine code=parent}}|machine code=parent}}|machine code=parent}}|authority={{{authority|}}}|fc={{#ifexpr:{{{2|1}}}>23|true|}} }}
{{taxobox/showtaxon |LEVEL=4 |{{taxonomy/{{taxonomy/{{taxonomy/{{{1|Ursa}}}|machine code=parent}}|machine code=parent}}|machine code=parent}}|authority={{{authority|}}}|fc={{#ifexpr:{{{2|1}}}>22|true|}} }}
{{taxobox/showtaxon |LEVEL=3 |{{taxonomy/{{taxonomy/{{{1|Ursa}}}|machine code=parent}}|machine code=parent}}|authority={{{authority|}}}|fc={{#ifexpr:{{{2|1}}}>21|true|}} }}<!--
------------------ Parent taxon-->
{{taxobox/showtaxon |LEVEL=2 |{{taxonomy/{{{1|Ursa}}}|machine code=parent}}|authority={{{authority|}}}|fc={{#ifexpr:{{{2|1}}}>20|true}} }}<!--
------------------------------------------- Show row of last taxon -->
{{taxobox/showtaxon |LEVEL=1 |{{ucfirst:{{{1|Ursa}}}}}|authority={{{authority|}}}|fc={{#ifexpr:{{{2|1}}}>19|true}} }}<noinclude>
{{documentation}}
</noinclude>
e1s1jgeucc6z0oc4hbicn6ja1a93dtu
Seunaleuëk:Taxobox/taxonomy/ex3
10
33906
159038
2026-10-10T17:18:53Z
Rachmat04
7338
Geupeugöt laman ngön asoë '<noinclude><!-- -======================================================================= - Template:Taxobox/taxonomy/ex3: Show extra infobox row set #3 taxons -======================================================================= -- --></noinclude> {{#switch: {{ucfirst:{{{1|Unikonta}}} }} | Eukaryota = {{taxobox/showtaxon |Eukaryota|fc={{#ifexpr:{{{2|1}}}>29|true}}}} | Unikonta = {{taxobox/showtaxon |Eukaryota|fc={{#ifexpr:{{{2|1}}}>30|true}}}} {{taxobox...'
159038
wikitext
text/x-wiki
<noinclude><!--
-=======================================================================
- Template:Taxobox/taxonomy/ex3: Show extra infobox row set #3 taxons
-=======================================================================
--
--></noinclude>
{{#switch: {{ucfirst:{{{1|Unikonta}}} }}
| Eukaryota =
{{taxobox/showtaxon |Eukaryota|fc={{#ifexpr:{{{2|1}}}>29|true}}}}
| Unikonta =
{{taxobox/showtaxon |Eukaryota|fc={{#ifexpr:{{{2|1}}}>30|true}}}}
{{taxobox/showtaxon |Unikonta| fc={{#ifexpr:{{{2|1}}}>29|true}}}}
| Opisthokonta =
{{taxobox/showtaxon |Eukaryota|fc={{#ifexpr:{{{2|1}}}>31|true}}}}
{{taxobox/showtaxon |Unikonta| fc={{#ifexpr:{{{2|1}}}>30|true}}}}
{{taxobox/showtaxon |Opisthokonta|fc={{#ifexpr:{{{2|1}}}>29|yes}}}}
| Holozoa =
{{taxobox/showtaxon |Eukaryota|fc={{#ifexpr:{{{2|1}}}>32|true}}}}
{{taxobox/showtaxon |Unikonta| fc={{#ifexpr:{{{2|1}}}>31|true}}}}
{{taxobox/showtaxon |Opisthokonta|fc={{#ifexpr:{{{2|1}}}>30|yes}}}}
{{taxobox/showtaxon |Holozoa| fc={{#ifexpr:{{{2|1}}}>29|true}}}}
| Filozoa =
{{taxobox/showtaxon |Eukaryota|fc={{#ifexpr:{{{2|1}}}>43|true}}}}
{{taxobox/showtaxon |Unikonta| fc={{#ifexpr:{{{2|1}}}>42|true}}}}
{{taxobox/showtaxon |Opisthokonta|fc={{#ifexpr:{{{2|1}}}>41|yes}}}}
{{taxobox/showtaxon |Holozoa| fc={{#ifexpr:{{{2|1}}}>40|true}}}}
{{taxobox/showtaxon |Filozoa| fc={{#ifexpr:{{{2|1}}}>39|true}}}}
| Animalia =
{{taxobox/showtaxon |Eukaryota|fc={{#ifexpr:{{{2|1}}}>34|true}}}}
{{taxobox/showtaxon |Unikonta| fc={{#ifexpr:{{{2|1}}}>33|true}}}}
{{taxobox/showtaxon |Opisthokonta|fc={{#ifexpr:{{{2|1}}}>32|yes}}}}
{{taxobox/showtaxon |Holozoa| fc={{#ifexpr:{{{2|1}}}>31|true}}}}
{{taxobox/showtaxon |Filozoa| fc={{#ifexpr:{{{2|1}}}>30|true}}}}
{{taxobox/showtaxon |Animalia| fc={{#ifexpr:{{{2|1}}}>29|true}}}}
| Eumetazoa =
{{taxobox/showtaxon |Eukaryota|fc={{#ifexpr:{{{2|1}}}>35|true}}}}
{{taxobox/showtaxon |Unikonta| fc={{#ifexpr:{{{2|1}}}>34|true}}}}
{{taxobox/showtaxon |Opisthokonta|fc={{#ifexpr:{{{2|1}}}>33|yes}}}}
{{taxobox/showtaxon |Holozoa| fc={{#ifexpr:{{{2|1}}}>32|true}}}}
{{taxobox/showtaxon |Filozoa| fc={{#ifexpr:{{{2|1}}}>31|true}}}}
{{taxobox/showtaxon |Animalia| fc={{#ifexpr:{{{2|1}}}>30|true}}}}
{{taxobox/showtaxon |Eumetazoa|fc={{#ifexpr:{{{2|1}}}>29|true}}}}
| Bilateria =
{{taxobox/showtaxon |Eukaryota|fc={{#ifexpr:{{{2|1}}}>36|true}}}}
{{taxobox/showtaxon |Unikonta| fc={{#ifexpr:{{{2|1}}}>35|true}}}}
{{taxobox/showtaxon |Opisthokonta|fc={{#ifexpr:{{{2|1}}}>34|yes}}}}
{{taxobox/showtaxon |Holozoa| fc={{#ifexpr:{{{2|1}}}>33|true}}}}
{{taxobox/showtaxon |Filozoa| fc={{#ifexpr:{{{2|1}}}>32|true}}}}
{{taxobox/showtaxon |Animalia| fc={{#ifexpr:{{{2|1}}}>31|true}}}}
{{taxobox/showtaxon |Eumetazoa|fc={{#ifexpr:{{{2|1}}}>30|true}}}}
{{taxobox/showtaxon |Bilateria|fc={{#ifexpr:{{{2|1}}}>29|true}}}}
| Nephrozoa =
{{taxobox/showtaxon |Eukaryota|fc={{#ifexpr:{{{2|1}}}>37|true}}}}
{{taxobox/showtaxon |Unikonta| fc={{#ifexpr:{{{2|1}}}>36|true}}}}
{{taxobox/showtaxon |Opisthokonta|fc={{#ifexpr:{{{2|1}}}>35|yes}}}}
{{taxobox/showtaxon |Holozoa| fc={{#ifexpr:{{{2|1}}}>34|true}}}}
{{taxobox/showtaxon |Filozoa| fc={{#ifexpr:{{{2|1}}}>33|true}}}}
{{taxobox/showtaxon |Animalia| fc={{#ifexpr:{{{2|1}}}>32|true}}}}
{{taxobox/showtaxon |Eumetazoa|fc={{#ifexpr:{{{2|1}}}>31|true}}}}
{{taxobox/showtaxon |Bilateria|fc={{#ifexpr:{{{2|1}}}>30|true}}}}
{{taxobox/showtaxon |Nephrozoa|fc={{#ifexpr:{{{2|1}}}>29|true}}}}
| Deuterostomia =
{{taxobox/showtaxon |Eukaryota|fc={{#ifexpr:{{{2|1}}}>38|true}}}}
{{taxobox/showtaxon |Unikonta| fc={{#ifexpr:{{{2|1}}}>37|true}}}}
{{taxobox/showtaxon |Opisthokonta|fc={{#ifexpr:{{{2|1}}}>36|yes}}}}
{{taxobox/showtaxon |Holozoa| fc={{#ifexpr:{{{2|1}}}>35|true}}}}
{{taxobox/showtaxon |Filozoa| fc={{#ifexpr:{{{2|1}}}>34|true}}}}
{{taxobox/showtaxon |Animalia| fc={{#ifexpr:{{{2|1}}}>33|true}}}}
{{taxobox/showtaxon |Eumetazoa|fc={{#ifexpr:{{{2|1}}}>32|true}}}}
{{taxobox/showtaxon |Bilateria|fc={{#ifexpr:{{{2|1}}}>31|true}}}}
{{taxobox/showtaxon |Nephrozoa|fc={{#ifexpr:{{{2|1}}}>30|true}}}}
{{taxobox/showtaxon |Deuterostomia|fc={{#ifexpr:{{{2|1}}}>29|true}}}}
| Chordata =
{{taxobox/showtaxon |Eukaryota|fc={{#ifexpr:{{{2|1}}}>39|true}}}}
{{taxobox/showtaxon |Unikonta| fc={{#ifexpr:{{{2|1}}}>38|true}}}}
{{taxobox/showtaxon |Opisthokonta|fc={{#ifexpr:{{{2|1}}}>37|yes}}}}
{{taxobox/showtaxon |Holozoa| fc={{#ifexpr:{{{2|1}}}>36|true}}}}
{{taxobox/showtaxon |Filozoa| fc={{#ifexpr:{{{2|1}}}>35|true}}}}
{{taxobox/showtaxon |Animalia| fc={{#ifexpr:{{{2|1}}}>34|true}}}}
{{taxobox/showtaxon |Eumetazoa|fc={{#ifexpr:{{{2|1}}}>33|true}}}}
{{taxobox/showtaxon |Bilateria|fc={{#ifexpr:{{{2|1}}}>32|true}}}}
{{taxobox/showtaxon |Nephrozoa|fc={{#ifexpr:{{{2|1}}}>31|true}}}}
{{taxobox/showtaxon |Deuterostomia|fc={{#ifexpr:{{{2|1}}}>30|true}}}}
{{taxobox/showtaxon |Chordata| fc={{#ifexpr:{{{2|1}}}>29|true}}}}
| Craniata =
{{taxobox/showtaxon |Eukaryota|fc={{#ifexpr:{{{2|1}}}>40|true}}}}
{{taxobox/showtaxon |Unikonta| fc={{#ifexpr:{{{2|1}}}>39|true}}}}
{{taxobox/showtaxon |Opisthokonta|fc={{#ifexpr:{{{2|1}}}>38|yes}}}}
{{taxobox/showtaxon |Holozoa| fc={{#ifexpr:{{{2|1}}}>37|true}}}}
{{taxobox/showtaxon |Filozoa| fc={{#ifexpr:{{{2|1}}}>36|true}}}}
{{taxobox/showtaxon |Animalia| fc={{#ifexpr:{{{2|1}}}>35|true}}}}
{{taxobox/showtaxon |Eumetazoa|fc={{#ifexpr:{{{2|1}}}>34|true}}}}
{{taxobox/showtaxon |Bilateria|fc={{#ifexpr:{{{2|1}}}>33|true}}}}
{{taxobox/showtaxon |Nephrozoa|fc={{#ifexpr:{{{2|1}}}>32|true}}}}
{{taxobox/showtaxon |Deuterostomia|fc={{#ifexpr:{{{2|1}}}>31|true}}}}
{{taxobox/showtaxon |Chordata| fc={{#ifexpr:{{{2|1}}}>30|true}}}}
{{taxobox/showtaxon |Craniata| fc={{#ifexpr:{{{2|1}}}>29|true}}}}
| Vertebrata =
{{taxobox/showtaxon |Eukaryota|fc={{#ifexpr:{{{2|1}}}>41|true}}}}
{{taxobox/showtaxon |Unikonta| fc={{#ifexpr:{{{2|1}}}>40|true}}}}
{{taxobox/showtaxon |Opisthokonta|fc={{#ifexpr:{{{2|1}}}>39|yes}}}}
{{taxobox/showtaxon |Holozoa| fc={{#ifexpr:{{{2|1}}}>38|true}}}}
{{taxobox/showtaxon |Filozoa| fc={{#ifexpr:{{{2|1}}}>37|true}}}}
{{taxobox/showtaxon |Animalia| fc={{#ifexpr:{{{2|1}}}>36|true}}}}
{{taxobox/showtaxon |Eumetazoa|fc={{#ifexpr:{{{2|1}}}>35|true}}}}
{{taxobox/showtaxon |Bilateria|fc={{#ifexpr:{{{2|1}}}>34|true}}}}
{{taxobox/showtaxon |Nephrozoa|fc={{#ifexpr:{{{2|1}}}>33|true}}}}
{{taxobox/showtaxon |Deuterostomia|fc={{#ifexpr:{{{2|1}}}>32|true}}}}
{{taxobox/showtaxon |Chordata| fc={{#ifexpr:{{{2|1}}}>31|true}}}}
{{taxobox/showtaxon |Craniata| fc={{#ifexpr:{{{2|1}}}>30|true}}}}
{{taxobox/showtaxon |Vertebrata|fc={{#ifexpr:{{{2|1}}}>29|true}}}}
| Life = <!--ignore-->
| #default = {{
#ifeq:<!--left brace: -->{|{{padleft:|1|{{taxonomy/{{taxonomy/{{taxonomy/{{taxonomy/{{taxonomy/{{taxonomy/{{taxonomy/{{taxonomy/{{taxonomy/{{taxonomy/{{{1|Ursa}}}|machine code=parent}}|machine code=parent}}|machine code=parent}}|machine code=parent}}|machine code=parent}}|machine code=parent}}|machine code=parent}}|machine code=parent}}|machine code=parent}}|machine code=parent}} }}
|<!--then more would exceed top of tree; don't try higher name rows -->
|<!--else show higher names-->{{taxobox/taxonomy/ex4
|{{taxonomy/{{taxonomy/{{taxonomy/{{taxonomy/{{taxonomy/{{taxonomy/{{taxonomy/{{taxonomy/{{taxonomy/{{taxonomy/{{{1|Ursa}}}|machine code=parent}}|machine code=parent}}|machine code=parent}}|machine code=parent}}|machine code=parent}}|machine code=parent}}|machine code=parent}}|machine code=parent}}|machine code=parent}}|machine code=parent}}
|2={{{2|1}}} }}<!--endtaxobox/taxonomy/ex4 -->
}}<!--endifeq-else "{" error --><!--
The above uses {taxobox/taxonomy/ex4} to show even higher taxon rows.
The below creates the next 10 levels of lower taxonomy, after the
above levels (if any), on the request of the calling template.
------------------------------------------- Show rows of name levels -->
{{taxobox/taxonomy cell/sandbox2|LEVEL=10 |{{taxonomy/{{taxonomy/{{taxonomy/{{taxonomy/{{taxonomy/{{taxonomy/{{taxonomy/{{taxonomy/{{taxonomy/{{{1|Ursa}}}|machine code=parent}}|machine code=parent}}|machine code=parent}}|machine code=parent}}|machine code=parent}}|machine code=parent}}|machine code=parent}}|machine code=parent}}|machine code=parent}}|fc={{#ifexpr:{{{2|1}}}>38|true|}} }}
{{taxobox/taxonomy cell/sandbox2|LEVEL=9 |{{taxonomy/{{taxonomy/{{taxonomy/{{taxonomy/{{taxonomy/{{taxonomy/{{taxonomy/{{taxonomy/{{{1|Ursa}}}|machine code=parent}}|machine code=parent}}|machine code=parent}}|machine code=parent}}|machine code=parent}}|machine code=parent}}|machine code=parent}}|machine code=parent}}|fc={{#ifexpr:{{{2|1}}}>37|true|}} }}
{{taxobox/taxonomy cell/sandbox2|LEVEL=8 |{{taxonomy/{{taxonomy/{{taxonomy/{{taxonomy/{{taxonomy/{{taxonomy/{{taxonomy/{{{1|Ursa}}}|machine code=parent}}|machine code=parent}}|machine code=parent}}|machine code=parent}}|machine code=parent}}|machine code=parent}}|machine code=parent}}|fc={{#ifexpr:{{{2|1}}}>36|true|}} }}
{{taxobox/taxonomy cell/sandbox2|LEVEL=7 |{{taxonomy/{{taxonomy/{{taxonomy/{{taxonomy/{{taxonomy/{{taxonomy/{{{1|Ursa}}}|machine code=parent}}|machine code=parent}}|machine code=parent}}|machine code=parent}}|machine code=parent}}|machine code=parent}}|fc={{#ifexpr:{{{2|1}}}>35|true|}} }}
{{taxobox/taxonomy cell/sandbox2|LEVEL=6 |{{taxonomy/{{taxonomy/{{taxonomy/{{taxonomy/{{taxonomy/{{{1|Ursa}}}|machine code=parent}}|machine code=parent}}|machine code=parent}}|machine code=parent}}|machine code=parent}}|fc={{#ifexpr:{{{2|1}}}>34|true|}} }}
{{taxobox/taxonomy cell/sandbox2|LEVEL=5 |{{taxonomy/{{taxonomy/{{taxonomy/{{taxonomy/{{{1|Ursa}}}|machine code=parent}}|machine code=parent}}|machine code=parent}}|machine code=parent}}|authority={{{authority|}}}|fc={{#ifexpr:{{{2|1}}}>33|true|}} }}
{{taxobox/taxonomy cell/sandbox2|LEVEL=4 |{{taxonomy/{{taxonomy/{{taxonomy/{{{1|Ursa}}}|machine code=parent}}|machine code=parent}}|machine code=parent}}|authority={{{authority|}}}|fc={{#ifexpr:{{{2|1}}}>32|true|}} }}
{{taxobox/taxonomy cell/sandbox2|LEVEL=3 |{{taxonomy/{{taxonomy/{{{1|Ursa}}}|machine code=parent}}|machine code=parent}}|authority={{{authority|}}}|fc={{#ifexpr:{{{2|1}}}>31|true|}} }}<!--
--------------------- Parent taxon-->
{{taxobox/taxonomy cell/sandbox2|LEVEL=2 |{{taxonomy/{{{1|Ursa}}}|machine code=parent}}|authority={{{authority|}}}|fc={{#ifexpr:{{{2|1}}}>30|true}} }}<!--
--------------------------------------------- Show row of last taxon -->
{{taxobox/taxonomy cell/sandbox2|LEVEL=1 |{{ucfirst:{{{1|Ursa}}}}}|authority={{{authority|}}}|fc={{#ifexpr:{{{2|1}}}>29|true}} }}
}}<noinclude><!--endswitch by taxon name
{{documentation|Template:Taxobox/taxonomy/doc}}
</noinclude>
kzvz3d32ctlk9s5lfjju4mcpqxgfefh
Seunaleuëk:Infrataxon()
10
33907
159039
2026-10-10T17:19:41Z
Rachmat04
7338
Geupeugöt laman ngön asoë '<!-- Remove "ichno" and "oo" and then check for a major taxon ("oordo" becomes "rdo"): -->{{#switch:{{#invoke:String|replace|{{#invoke:String|replace|{{Taxon info|{{{1|Acacia}}}|rank}}|ichno|}}|oo|}} |regnum|phylum|divisio|classis|ordo|rdo|familia|genus|species=|#default=true }}<noinclude>{{documentation}}</noinclude>'
159039
wikitext
text/x-wiki
<!--
Remove "ichno" and "oo" and then check for a major taxon ("oordo" becomes "rdo"):
-->{{#switch:{{#invoke:String|replace|{{#invoke:String|replace|{{Taxon info|{{{1|Acacia}}}|rank}}|ichno|}}|oo|}}
|regnum|phylum|divisio|classis|ordo|rdo|familia|genus|species=|#default=true
}}<noinclude>{{documentation}}</noinclude>
nknx0kbmjh6n4yllma2xnwpkc34cdy6