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|}}}|&dagger;|{{#ifeq:{{{status|}}}|EX|&dagger;|{{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|}}}|&dagger;|{{#ifeq:{{{status|}}}|EX|&dagger;|{{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 .. "&nbsp;" 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 .. '&nbsp;' .. 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 = '&dagger;' 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;">&nbsp;(?)</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;">&nbsp;(?)</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 == "&#123;&#123;&#123;coordinates&#125;&#125;&#125;" 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&params=1_2_N_3_4_W_ or //tools.wmflabs.org/geohack/geohack.php?pagename=Example&params=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 .. '&quot;' .. genus .. '+' .. species .. '&quot;' 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 = '&#32;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&#61;" .. id -- use entity &#61; 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 = "&#32;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