Modul:Taxonbar

Iz Wikipedije, proste enciklopedije
Jump to navigation Jump to search
Documentation icon Dokumentacija modula[predogled] [uredi] [zgodovina] [osveži]

Predloga:Taxonbar (uredi|pogovor|zgodovina|povezave|/dok|/podstr|/pesk|/pesk razlika|/testp)

Glavni članek: Predloga:Taxonbar.

This module contains the code of {{Taxonbar}}. To use Taxonbar, follow instructions at Predloga:Taxonbar/dok.

Konfiguracija[uredi kodo]

Parameters and databases are set by Modul:Taxonbar/conf.

Identifikatorji taksona[uredi kodo]

Testni primeri[uredi kodo]

Glej tudi: Predloga:Taxonbar/testniprimeri in Modul:Taxonbar/peskovnik

For testcases use: {{Taxonbar | from=QID}}

Počisti predpomnilnik

Rhododendron maximum

Asclepias syriaca

Peach (Prunus persica)

Puma (genus)

Dog (Canis lupus familiaris)

Eastern bluebird (Sialia sialis)

Honey bee (Apis)

Western honey bee (Apis mellifera)

Clipper butterfly (Parthenos sylvia)

Turkey tail (Trametes versicolor)

Button/portobello mushroom (Agaricus bisporus)

Glej tudi[uredi kodo]


require('Module:No globals')

local conf = require( "Modul:Taxonbar/conf" ) -- configuration module
local TaxonItalics = require("Modul: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' and property > 0 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.getEntity(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.getEntity(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
		
		local valurl = val
		if mw.ustring.find( link, 'antweb.org' ) then valurl = mw.ustring.gsub(valurl, " ", "%%20") end
		valurl = mw.ustring.gsub(valurl,"%%","%%%%")
		link = mw.ustring.gsub(link, '$1', valurl)
	end
	
	link = mw.ustring.gsub(link, '^[Hh][Tt][Tt][Pp]([Ss]?)://', '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..' '..mw.text.encode(mw.uri.decode(val, "PATH"),'%[%]')..']'
	elseif link == "" then
		returnVal.text = val
	else
		returnVal.text = '<span class="external">[['..link..'|'..val..']]</span>'
	end
	return returnVal
end

local function createRow( id, label, rawValue, link, withUid )
	if link then
		local outStr = '*<span style="white-space:nowrap;">' .. label .. ' <span'
		if withUid then outStr = outStr..' class="uid"' end
		return outStr..'>' .. link .. '</span></span>\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 tfroms = {} --non-sequential table of unique froms
	local ifroms = 0 --integer size of tfroms, b/c Lua
	local categories = {
		'[[Kategorija:Taxonbar brez parametra from]]',
		'[[Kategorija:Taxonbar, odklopljen od Wikipodatkov]]',
		'', -- [3] placeholder for [[Category:Taxonbars using multiple manual Wikidata items]]
		'', -- [4] placeholder for [[Category:Taxonbars with invalid from parameters]]
		'', -- [5] placeholder for [[Category:Taxonbars using manual taxon IDs]]
		'', -- [6] placeholder for [[Category:Taxonbar pages requiring a Wikidata item]]
		'', -- [7] placeholder for [[Category:Taxonbar pages without Wikidata taxon IDs]]
		'', -- [8] placeholder for [[Category:Taxonbars with duplicate from parameters]]
		'', -- [9] placeholder for [[Category:Taxonbars with manual taxon IDs differing from Wikidata]]
		'', --[10] placeholder for [[Category:Taxonbars with manual taxon IDs identical to Wikidata]]
		'', --[11] placeholder for [[Category:Taxonbars on possible non-taxon pages]]
		'', --[12] placeholder for [[Category:Taxonbars with 20+ taxon IDs]]
		'', --[13] placeholder for [[Category:Taxonbars with 25+ taxon IDs]]
		'', --[14] placeholder for [[Category:Taxonbars with automatically added basionyms]]
	}
	
	--Assess the page's relationship with Wikidata
	local currentItem = nil
	if currentTitle.namespace == 10 then --i.e. Module:Taxonbar/sandbox, Template:Taxonbar/doc, etc.
		if resolve._entityid(frame, parentArgs['from']) then
			currentItem = mw.wikibase.getEntity(parentArgs['from'])
		end
		if currentItem == nil then
			if resolve._entityid(frame, parentArgs['from1']) then
				currentItem = mw.wikibase.getEntity(parentArgs['from1'])
			end
		end
	elseif resolve._entityid(frame, currentEntityId) then
		currentItem = mw.wikibase.getEntity(currentEntityId)
	else --currentEntityId == nil
		categories[6] = '[[Kategorija:Strani s Taxonbar, ki potrebujejo objekt v Wikipodatkih]]'
	end
	if currentItem then
		local acceptable = {
		   ['Q16521'] = 'takson',
		   ['Q23038290'] = 'fosilni takson',
		   ['Q310890'] = 'monotipski takson',
		   ['Q47487597'] = 'monotipski fosilni takson',
		   ['Q2568288'] = 'ihnotakson',
		   ['Q713623'] = 'klad',
		   ['Q42621'] = 'hibrid',
		   ['Q848328'] = 'serotip',
		   ['Q17487588'] = 'unavailable combination',
		   ['Q235536'] = 'incertae sedis',
		}
		categories[11] = '[[Kategorija:Taxonbar na straneh, ki morda ne opisujejo taksonov]]' --unset if acceptable found
		for _, instanceState in pairs ( currentItem:getBestStatements('P31') ) do --instance of
			local instanceOf = instanceState.mainsnak.datavalue.value.id
			if acceptable[instanceOf] then
				categories[11] = ''
				break
			end
		end
	end
	
	--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
					--look for duplicate froms while we're here
					if mw.ustring.find(v, "^Q%d") then
						if tfroms[v] then
							categories[8] = '[[Kategorija:Taxonbar s podvojenimi parametri from]]'
							tfroms[v] = tfroms[v] + 1
						else
							ifroms = ifroms + 1
							tfroms[v] = 1
						end
						if ifroms > 1 then
							categories[3] = '[[Kategorija:Taxonbar z več ročnimi objekti v Wikipodatkih]]'
						end
					end
				elseif mw.ustring.sub(lowerk,1,5) == "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' then
					stringArgs = true
					categories[5] = '[[Kategorija:Taxonbar z ročno dodanimi ID-ji za taksone]]'
				end
			end
		end
	end
	
	--Append basionym to arg list if not already provided
	if currentItem then
		local currentBasState = currentItem:getBestStatements('P566')[1] --basionym
		if currentBasState then
			local basionymId = currentBasState.mainsnak.datavalue.value.id
			if basionymId and resolve._entityid(frame, basionymId) and tfroms[basionymId] == nil then
				--check that basionym is a strict instance of taxon
				local basionymItem = mw.wikibase.getEntity(basionymId)
				if basionymItem then
					local acceptable = {
					   ['Q16521'] = 'takson',
					   ['Q23038290'] = 'fosilni takson',
					   ['Q310890'] = 'monotipski takson',
					   ['Q47487597'] = 'monotipski fosilni takson',
					   ['Q2568288'] = 'ihnotakson',
					}
					for _, instanceState in pairs ( basionymItem:getBestStatements('P31') ) do --instance of
						local instanceOf = instanceState.mainsnak.datavalue.value.id
						if acceptable[instanceOf] then
							fromTitleCount = fromTitleCount + 1
							parentArgs['from'..fromTitleCount] = basionymId
							categories[14] = '[[Kategorija:Taxonbar s samodejno dodanimi bazionimi]]'
							break
						end
					end
				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] --taxon name
			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] = '[[Kategorija:Taxonbar z neveljavnimi parametri from]]'
				errors = errors .. mw.text.tag('strong', {class='error'}, 'Napaka: "' .. parentArgs['from'..f] .. '" ni veljaven ID za entiteto v Wikipodatkih.<br />')				
			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
				local sourceCount = 0
				for _, params in pairs( conf.databases ) do
					params[1] = mw.ustring.lower(params[1])
					local propId = params[3]
					--Wikidata fallback if requested
					if (item ~= nil and item.claims ~= nil) and
					   (type(propId) == 'string' or (type(propId) == 'number' and propId > 0)) then
						local wikidataIds = getIdsFromWikidata( item, 'P' .. propId )
						local v = parentArgs[params[1]..f]
						if wikidataIds[1] then
							if (not v or v == '') then
								parentArgs[params[1]..f] = wikidataIds[1]
							else
								if v and v ~= 'no' and v ~= wikidataIds[1] then
									categories[9] = '[[Kategorija:Taxonbar z ročnim ID-jem taksona, različnim od tistega v Wikipodatkih]]'
								elseif v and v == wikidataIds[1] then
									categories[10] = '[[Kategorija:Taxonbar z ročnim ID-jem taksona, enakim kot v Wikipodatkih]]'
								end
							end
						end
					end
					local val = parentArgs[params[1]..f]
					if val and val ~= '' and mw.ustring.lower(val) ~= 'no' then
						if type(propId) == 'number' then
							if propId < 0 then propId = -propId end --allow link
							if propId > 0 then --link
								table.insert( elements, createRow( params[1], params[2] .. ':', val, getLink( propId, val ).text, true ) )
							else --propId == 0; no link
								table.insert( elements, createRow( params[1], params[2] .. ':', val, val, true ) )
							end
						else
							table.insert( elements, createRow( params[1], params[2] .. ':', val, getLink( propId, val ).text, true ) )
						end
						if params[1] ~= 'wikidata' then
							sourcesFound = true 
							sourceCount = sourceCount + 1
						end
					end
				end
				
				if sourceCount >= 20 then categories[12] = '[[Kategorija:Taxonbar z 20+ ID-ji]]' end
				if sourceCount >= 25 then categories[13] = '[[Kategorija:Taxonbar s 25+ ID-ji]]' 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 )
				elseif currentEntityId then
					categories[7] = '[[Kategorija:Strani s Taxonbar brez ID-jev v Wikipodatkih]]'
				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
			--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'] = "Identifikatorji taksona"
			if rowCount > 2 then
				navboxParams['navbar'] = 'plain'
			else
				navboxParams['state'] = 'off'
				navboxParams['navbar'] = 'off'
			end
		elseif parentArgs['noTitle'..firstRow] then
			navboxParams['group'..firstRow] = 'Identifikatorji taksona'
		else
			navboxParams['group'..firstRow] = 'Identifikatorji taksona<br />' .. 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)) .. '<br />'
	elseif currentTitle.namespace == 0 then
		outString = outString .. table.concat(categories)
	end
	
	return outString .. errors
end

return p