Module:Taxonbar

require('Module:No globals')

local conf = require( "Module:Taxonbar/conf" ) local TaxonItalics = require("Module:TaxonItalics") -- use a function from Module:TaxonItalics to italicize a taxon name

local function getIdsFromWikidata( item, property ) local ids = {} if not item.claims[property] then return ids end for _, statement in pairs( item.claims[property] ) do		if statement.mainsnak.datavalue then table.insert( ids, statement.mainsnak.datavalue.value ) end end return ids end

local function getLink( property, val ) local link, returnVal = "", {} returnVal.isError = false if mw.ustring.find( val, '//' ) then link = val else if type(property) == 'number' then local entityObject = mw.wikibase.getEntity('P'..property) local dataType if entityObject then dataType = entityObject.datatype else returnVal.isError = true end if dataType == "external-id" then local formatterURL = entityObject:getBestStatements('P1630')[1] if formatterURL then link = formatterURL.mainsnak.datavalue.value end elseif dataType == "url" then local subjectItem = entityObject:getBestStatements('P1629')[1] if subjectItem then local officialWebsite = mw.wikibase.getEntityObject(subjectItem.mainsnak.datavalue.value.id):getBestStatements('P856')[1] if officialWebsite then	link = officialWebsite.mainsnak.datavalue.value end end elseif dataType == "string" then local formatterURL = entityObject:getBestStatements('P1630')[1] if formatterURL then link = formatterURL.mainsnak.datavalue.value else local subjectItem = entityObject:getBestStatements('P1629')[1] if subjectItem then local officialWebsite = mw.wikibase.getEntityObject(subjectItem.mainsnak.datavalue.value.id):getBestStatements('P856')[1] if officialWebsite then	link = officialWebsite.mainsnak.datavalue.value end end end else returnVal.isError = true end elseif type(property) == 'string' then link = property end link = mw.ustring.gsub(link, '$1', val) end link = mw.ustring.gsub(link, '^[Hh][Tt][Tt][Pp]([Ss]?)&#58;//', 'http%1://') -- fix wikidata URL val = mw.ustring.match(val, '([^=/]*)/?$') -- get display name from end of URL if mw.ustring.find( link, '//' ) then returnVal.text = '['..link..' '..val..']' elseif link == "" then returnVal.text = val else returnVal.text = ' '..val..' ' end return returnVal end

local function createRow( id, label, rawValue, link, withUid ) if link then local outStr = '* ' .. label .. ' ' .. link .. ' \n' else return '* ' .. mw.text.tag('span', {class='error'}, 'The identifier ' .. id .. ' ' .. rawValue .. ' is not valid.') .. '\n' end end

local function copyTable(inTable) if type(inTable) ~= 'table' then return inTable end local outTable = setmetatable({}, getmetatable(inTable)) for key, value in pairs (inTable) do outTable[copyTable(key)] = copyTable(value) end return outTable end

local p = {}

function p.authorityControlTaxon( frame ) local resolve = require( "Module:ResolveEntityId" ) local parentArgs = copyTable(frame:getParent.args) local currentTitle = mw.title.getCurrentTitle local currentEntityId = mw.wikibase.getEntityIdForCurrentPage local stringArgs = false local fromTitleCount, firstRow, rowCount = 1, 0, 0 local outString, errors = "", "" local categories = { ,		,		,			}	--Cleanup args for k, v in pairs( frame:getParent.args ) do		if type(k) == 'string' then --make args case insensitive local lowerk = mw.ustring.lower(k) if not parentArgs[lowerk] or parentArgs[lowerk] == '' then parentArgs[k] = nil parentArgs[lowerk] = v			end --remap abc to abc1 if not mw.ustring.find(lowerk,"%d$") then --if no number at end of param if not parentArgs[lowerk..'1'] or parentArgs[lowerk..'1'] == '' then parentArgs[lowerk] = nil lowerk = lowerk..'1' parentArgs[lowerk] = v				end end if v and v ~= '' then --remap "for" to "title" if mw.ustring.sub(lowerk,1,3) == "for" then local forTitle = mw.ustring.gsub(lowerk,"^for","title",1) if parentArgs[forTitle] == '' or not parentArgs[forTitle] then parentArgs[lowerk] = nil lowerk = forTitle parentArgs[lowerk] = v					end end --find highest from or title param if mw.ustring.sub(lowerk,1,4) == "from" then local fromNumber = tonumber(mw.ustring.sub(lowerk,5,-1)) if fromNumber and fromNumber >= fromTitleCount then fromTitleCount = fromNumber end elseif mw.ustring.sub(lowerk,1,3) == "title" then local titleNumber = tonumber(mw.ustring.sub(lowerk,4,-1)) if titleNumber and titleNumber >= fromTitleCount then fromTitleCount = titleNumber end elseif mw.ustring.lower(v) ~= 'no' and lowerk ~= 'for' then stringArgs = true end end end end

--Setup navbox local navboxParams = { name = 'Taxonbar', bodyclass = 'hlist', listclass = '', groupstyle = 'text-align: left;', }	for f = 1,fromTitleCount,1 do local elements, title = {}, nil --cleanup parameters if parentArgs['from'..f] == '' then parentArgs['from'..f] = nil end if parentArgs['title'..f] == '' then parentArgs['title'..f] = nil end --remap aliases for _, a in pairs( conf.aliases ) do			local alias, name = mw.ustring.lower(a[1]), mw.ustring.lower(a[2]) if parentArgs[alias..f] and not parentArgs[name..f] then parentArgs[name..f] = parentArgs[alias..f]				parentArgs[alias..f] = nil end end --Fetch Wikidata item local from = resolve._entityid(frame, parentArgs['from'..f]) local item = mw.wikibase.getEntity(from) local label = nil if type(item) == 'table' then local statements = item:getBestStatements('P225')[1] if statements then local datavalue = statements.mainsnak.datavalue if datavalue then label = datavalue.value end end label = label or item:getLabel else if parentArgs['from'..f] then categories[1] = '' categories[4] = '' errors = errors .. mw.text.tag('strong', {class='error'}, 'Error: "' .. parentArgs['from'..f] .. '" is not a valid Wikidata entity ID. ') end end if label and label ~= '' then title = mw.title.new(label) end if not title and parentArgs['title'..f] then title = mw.title.new(parentArgs['title'..f]) end if not title and f == 1 then title = currentTitle end

if title then if (not parentArgs['wikidata'..f] or parentArgs['wikidata'..f] == '') and (title.namespace == 0) then if parentArgs['from'..f] then parentArgs['wikidata'..f] = parentArgs['from'..f] elseif item then parentArgs['wikidata'..f] = item.id end end if title.namespace == 0 or stringArgs then --Only in the main namespace or if there are manual overrides local sourcesFound = false for _, params in pairs( conf.databases ) do					params[1] = mw.ustring.lower(params[1]) --Wikidata fallback if requested if (item ~= nil and item.claims ~= nil) and params[3] ~= 0 and (not parentArgs[params[1]..f] or parentArgs[params[1]..f] == '') then local wikidataIds = getIdsFromWikidata( item, 'P' .. params[3] ) if wikidataIds[1] then parentArgs[params[1]..f] = wikidataIds[1] end end local val = parentArgs[params[1]..f]					if val and val ~= '' and mw.ustring.lower(val) ~= 'no' and params[3] ~= 0 then table.insert( elements, createRow( params[1], params[2] .. ':', val, getLink( params[3], val ).text, true ) ) if params[1] ~= 'wikidata' then sourcesFound = true end end end

--Generate navbox title if sourcesFound then rowCount = rowCount + 1 if firstRow == 0 then firstRow = f end --set title from wikidata if it doesn't exist if parentArgs['title'..f] == '' or not parentArgs['title'..f] then parentArgs['noTitle'..f] = true parentArgs['title'..f] = title.text end --if it exists now, set row heading to title if parentArgs['title'..f] and parentArgs['title'..f] ~= '' then navboxParams['group'..f] = TaxonItalics.italicizeTaxonName(parentArgs['title'..f], false) else navboxParams['group'..f] = "" end navboxParams['list'..f] = table.concat( elements ) end --Categorize if parentArgs['from'..f] and parentArgs['from'..f] ~= '' then --blank "missing from" if 'from' exists categories[1] = '' --blank "desynced" if 'from' matches current page if parentArgs['from'..f] == currentEntityId then categories[2] = '' end end --cannot be "desynced" if no 'from' params if categories[1] ~=  then categories[2] =  end end end end

if rowCount > 0 then local Navbox = require('Module:Navbox') if rowCount > 1 then categories[3] = '' --remove duplicates and move page title to top local rowIDs = {} for f = 1,fromTitleCount,1 do if parentArgs['title'..f] and parentArgs['title'..f] ~= '' then if rowIDs[parentArgs['wikidata'..f]] then --remove duplicate navboxParams['group'..f] = nil navboxParams['list'..f] = nil else rowIDs[parentArgs['wikidata'..f]] = true if f > firstRow and (parentArgs['title'..f] == currentTitle.text or parentArgs['wikidata'..f] == currentEntityId) then --move item linked to page to top if navboxParams['group'..f] and navboxParams['group'..f] ~=  and navboxParams['list'..f] and navboxParams['list'..f] ~=  then local tempGroup, tempList = navboxParams['group'..f], navboxParams['list'..f]								navboxParams['group'..f], navboxParams['list'..f] = navboxParams['group'..firstRow], navboxParams['list'..firstRow] navboxParams['group'..firstRow], navboxParams['list'..firstRow] = tempGroup, tempList end end end end end --adjust navbox for number of rows navboxParams['title'] = "Taxon identifiers" if rowCount > 2 then navboxParams['navbar'] = 'plain' else navboxParams['state'] = 'off' navboxParams['navbar'] = 'off' end elseif parentArgs['noTitle'..firstRow] then navboxParams['group'..firstRow] = 'Taxon identifiers' else navboxParams['group'..firstRow] = 'Taxon identifiers ' .. navboxParams['group'..firstRow] end --return navbox outString = Navbox._navbox(navboxParams) end --add categories if string.sub(currentTitle.subpageText,1,9) == 'testcases' then parentArgs['demo'] = true end if parentArgs['demo'] and parentArgs['demo'] ~= '' then outString = outString .. mw.text.nowiki(table.concat(categories)) .. ' '	elseif currentTitle.namespace == 0 then outString = outString .. table.concat(categories) end return outString .. errors end

return p