Hopp til innhald

Modul:WikidataListe

Frå Wikipedia – det frie oppslagsverket

Dokumentasjon for modulen kan opprettast på Modul:WikidataListe/dok


local WikidataDato = require( 'Module:WikidataDato' )
--local refs = require 'Module:Reference score'
local p = {}

-- The value given to the properties in the table are not significant, they just need to exist
local useReferences = {
	["P19"] = "fødestad",     -- fødested
	["P20"] = "dødsstad",     -- dødssted
	["P69"] = "utdanna ved",     -- utdannet ved
	["P84"] = "arkitekt",     -- arkitekt
	["P102"] = "medlem av politisk parti",     -- medlem av politisk parti
	["P106"] = "sysselsetjing",    -- beskjeftigelse
	["P166"] = "utmerking"    -- utmerkelse
}

local linktext = 'Rediger på Wikidata'
local linktarget = 'https://www.wikidata.org/wiki/%s?uselang=%s#%s'

-- filter(function, table)
function filter(func, tbl)
	local newtbl= {}
	for i, v in pairs(tbl) do
		if func(v) then
			table.insert(newtbl, v)
		end
	end
	return newtbl
 end

-- Returns an array of non-deprecated claims for the given property.
-- If there's no Wikidata entity or no claims, an empty array is returned.
function getNonDeprecatedClaims( property )
	assert( property )

	local entity = mw.wikibase.getEntity()
	if not entity then
		return {}
	end

	local propertyId =  mw.wikibase.resolvePropertyId( property ) or 'none'
	local claims = ( entity.claims or {} )[propertyId] or {}

	claims = filter( function( claim ) return claim.mainsnak end, claims )
	claims = filter( function( claim ) return claim.rank ~= 'deprecated' end, claims )

	return claims
end

function hasQualifer( claim, qualifier )
	assert( claim )
	assert( qualifier )

	local qualifiers = claim.qualifiers or {}
	local snaks = qualifiers[qualifier] or {}
	
	return not not snaks[1]
end

function isStrange( snak )
	if not snak then
		return nil
	end

	return snak.snaktype == 'novalue'
		or snak.snaktype == 'somevalue'
		or nil
end

function getStrange( snak )
	return (snak.snaktype == 'novalue' and 'ingen')
		or (snak.snaktype == 'somevalue' and 'ukjend')
		or nil
end

function getQualifier( claim, qualifier, strip )
	if not claim.qualifiers then
		return nil
	end
	
	local qualifiers = claim.qualifiers or {}
	if not qualifiers[qualifier] then
		return nil
	end
	
	local snaks = qualifiers[qualifier] or {}
	if not snaks[1] then
		return nil
	end
	
	local snak = snaks[1] or {}
	if isStrange( snak ) then
		return getStrange( snak )
	end
	
	if not strip then
		return mw.wikibase.formatValue( snak )
	end
	
	-- this is to simple for more complex cases
	return tostring( mw.wikibase.formatValue( snak ) ):gsub("%b<>", "")
end

function formatYearQualifier(claim, qualifier)
	assert( claim )
	assert( qualifier )

	local snaks = ( claim.qualifiers or {} )[qualifier] or {}
	if not snaks[1] then
		return nil
	end

	local snak = snaks[1] or {}
	if isStrange( snak ) then
		return getStrange( snak )
	end

	return WikidataDato.aarFraClaim( snak )
end

-- Returns either "ingen", "ukjent", "" or "Qxxxxxx"
function getValue(claim)
	assert( claim )

	local mainsnak = claim.mainsnak or {}
	if isStrange( mainsnak ) then
		return getStrange( mainsnak )
	end

	-- check datatype
	if mainsnak.datatype ~= 'wikibase-item' then
		return nil
	end
	
	local datavalue = mainsnak.datavalue or {}
	if datavalue.type ~= 'wikibase-entityid' then
		return nil
	end
	
	local value = datavalue.value or {}
	if value['entity-type'] ~= 'item' then
		return nil
	end

	-- at this point there should be an ordinary value, but be safe
	return 'Q' .. ( value["numeric-id"] or 'xxxx')
end

function formatValue(value, first, link)
	assert( value )
	--assert( first )
	
	-- setter link til true som default hvis ingen verdi er angitt
	link = ( type( link ) == 'boolean' ) and link or true

	if string.sub(value, 1, 1) ~= "Q" then
		-- Verdien er enten "ukjend" eller "ingen"
		return string.format("''%s''", value)
	end

	local label = mw.wikibase.label( value )
	local sitelink = mw.wikibase.sitelink( value )
	if first and label then
		local lang = mw.language.getContentLanguage()
		label = lang:ucfirst( label )
	end

	if not link then
		-- Vi ønsker kun tekst, ikke wikilenke
		if label then
			return label
		end
		return ''
	end

	if label and sitelink then
		return '[[' .. sitelink .. '|' .. label .. ']]'
	end
	if label and not sitelink then
		return label
	end
	if sitelink and not label then
		return '[[' .. sitelink .. ']]'
	end

	return ''
end

function formatTimePeriod( claim, first, second )
	local startYear = formatYearQualifier(claim, first)  -- fra dato
			or formatYearQualifier(claim, 'P1319') -- tidligste dato
			or '' -- all fail
	--do return mw.dumpObject(claim.qualifiers['P1326']) end
	local startTitle = (hasQualifer(claim, first) and getQualifier(claim, first, true))
			or (hasQualifer(claim, 'P1319') and getQualifier(claim, 'P1319', true))
			or nil
	local endYear = formatYearQualifier(claim, second)  -- til dato
			or formatYearQualifier(claim, 'P1326') -- seneste dato
			or '' -- all fail
	local endTitle = (hasQualifer(claim, second) and getQualifier(claim, second, true))
			or (hasQualifer(claim, 'P1326') and getQualifier(claim, 'P1326', true))
			or nil
	local asterix = mw.html.create( 'sup' ):wikitext( '*' )
	if startTitle then
		local useFallback = (first == 'P1319') or not hasQualifer(claim, first)
		startYear = mw.html.create( 'span' )
			:attr( 'title', string.format("%s: %s", mw.wikibase.getLabel( useFallback and 'P1319' or first ), startTitle ))
			:wikitext( startYear .. (useFallback and tostring( asterix ) or ''))
	end
	if endTitle then
		local useFallback = (second == 'P1326') or not hasQualifer(claim, second)
		endYear = mw.html.create( 'span' )
			:attr( 'title', string.format("%s: %s", mw.wikibase.getLabel( useFallback and 'P1326' or second ), endTitle ))
			:wikitext( endYear .. (useFallback and tostring( asterix ) or ''))
	end
	return string.format("(%s–%s)", tostring(startYear), tostring(endYear))
end

function formatTimePoint( claim )
	local pointYear = formatYearQualifier(claim, 'P585')
			or '' -- all fail
	local pointTitle = (hasQualifer(claim, 'P585') and getQualifier(claim, 'P585', true))
			or nil
	if pointTitle then
		pointYear = mw.html.create( 'span' )
			:attr( 'title', string.format("%s: %s", mw.wikibase.getLabel( 'P585' ), pointTitle ))
			:wikitext( pointYear )
	end
	return string.format("(%s)", tostring(pointYear))
end

function formatEdit( qid, langCode, prop )
	if not qid then
		return ''
	end

	local link = mw.ustring.format( linktarget, qid, langCode, prop )

	local text = '[[File:OOjs UI icon edit-ltr-progressive.svg'
		.. '|frameless|text-top|10px'
		.. '|alt=' .. mw.text.nowiki( linktext )
		.. '|link=' .. mw.text.nowiki( link )
		.. '|' .. mw.text.nowiki( linktext )
		.. ']]'

	local html = mw.html.create( 'span' )
		:addClass( 'wb-edithandle' )
		-- @todo this must be adjusted
		-- :attr( 'data-bridge-edit-flow', 'single-best-value' )
		:wikitext( text )

	return tostring( html )
end

-- Returns all values from Wikidata for the given property
-- If no values are found, an empty string is returned.
function getFormattedValues(frame, prop, param, link)
	local claims = getNonDeprecatedClaims(prop)

	local i = 0
	local manglerOversettelse = false
	local formattedValues = {}
	
	for i, claim in ipairs(claims) do
		local value = getValue(claim)
		if value then
			local formattedValue = formatValue(value, i == 1, link)

			if formattedValue == '' then
				-- Målet har ikke en etikett på norsk bokmål, ei heller en artikkel på nowiki.
				-- Vi skriver ut en lenke til Wikidata for å gjøre det enkelt å legge til en etikett.
				-- For vanlige lesere kan det imidlertid være forvirrende med en Wikidata-lenke,
				-- så det er ikke helt optimalt. Vi marker derfor også at artikkelen skal legges til
				--  i en vedlikeholdskategori.
				manglerOversettelse = true
				formattedValue = "[[d:" .. value .. '|' .. value .. ']]'
			end

			-- Dette er egentlig valg av en algoritme, dvs det burde skrives som et pattern
			if hasQualifer(claim, 'P523') or hasQualifer(claim, 'P524') then
				formattedValue = formattedValue .. ' ' .. formatTimePeriod( claim, 'P523', 'P524' )
			elseif hasQualifer(claim, 'P580') or hasQualifer(claim, 'P582') then
				formattedValue = formattedValue .. ' ' .. formatTimePeriod( claim, 'P580', 'P582' )
			elseif hasQualifer(claim, 'P729') or hasQualifer(claim, 'P730') then
				formattedValue = formattedValue .. ' ' .. formatTimePeriod( claim, 'P729', 'P730' )
			elseif hasQualifer(claim, 'P2031') or hasQualifer(claim, 'P2032') then
				formattedValue = formattedValue .. ' ' .. formatTimePeriod( claim, 'P2031', 'P2032' )
			elseif hasQualifer(claim, 'P3415') or hasQualifer(claim, 'P3416') then
				formattedValue = formattedValue .. ' ' .. formatTimePeriod( claim, 'P3415', 'P3416' )
			elseif hasQualifer(claim, 'P575') then
				formattedValue = formattedValue .. ' ' .. formatTimePoint( claim, 'P575' )
			elseif hasQualifer(claim, 'P585') then
				formattedValue = formattedValue .. ' ' .. formatTimePoint( claim, 'P585' )
			elseif hasQualifer(claim, 'P606') then
				formattedValue = formattedValue .. ' ' .. formatTimePoint( claim, 'P606' )
			elseif hasQualifer(claim, 'P813') then
				formattedValue = formattedValue .. ' ' .. formatTimePoint( claim, 'P813' )
			elseif hasQualifer(claim, 'P1191') then
				formattedValue = formattedValue .. ' ' .. formatTimePoint( claim, 'P1191' )
			elseif hasQualifer(claim, 'P1249') then
				formattedValue = formattedValue .. ' ' .. formatTimePoint( claim, 'P1249' )
			elseif hasQualifer(claim, 'P3999') then
				formattedValue = formattedValue .. ' ' .. formatTimePoint( claim, 'P3999' )
			elseif hasQualifer(claim, 'P1319') or hasQualifer(claim, 'P1326') then
				formattedValue = formattedValue .. ' ' .. formatTimePeriod( claim, 'P1319', 'P1326' )
			end

			if formattedValue ~= '' then
				local tmp = nil
				if  useReferences[prop]
				then
					-- tmp = refs.render(frame, claim.references)
				end
				--table.insert(formattedValues, formattedValue..(tmp or ''))
			end
			
		end
	end

	local resultat = table.concat(formattedValues, ", ")

	local qid = mw.wikibase.getEntityIdForCurrentPage()
	local langCode = mw.language.getContentLanguage():getCode()

	if #formattedValues > 0 then
		resultat = resultat .. formatEdit( qid, langCode, prop )
	end

	-- use of # to get count will fail in the future
	if #formattedValues > 5 then
		resultat = string.format([[
			<div class="mw-collapsible mw-collapsed">
				<div class="sentrert">%s oppføringar</div>
				<div class="mw-collapsible-content">%s</div>
			</div>
		]], #formattedValues, resultat)
	end

	if manglerOversettelse then
		resultat = resultat .. "[[Kategori:Artiklar dr " .. param .. " manglar omsetjing]]"
	end

	return resultat
end

function getFrameValue(frame, params)
	local args = frame.args
	if args[1] == nil then
		local pFrame = frame:getParent();
		args = pFrame.args;
		for k,v in pairs( frame.args ) do
			args[k] = v;
		end
	end
	
	-- params kan være én enkelt verdi eller flere verdier adskilt med komma.
	-- F.eks. vil "religion,livssyn" sjekke både "religion" og "livssyn".
	for param in mw.text.gsplit( params, ',', true ) do
		 if args[param] then
			return mw.text.trim( args[param] )
		 end
	end
	return ""
end

function p.grenserTil(frame)
	assert( frame )
	return getFormattedValues(frame,'P47',"grensar til")
end

function p.yrker(frame)
	assert( frame )
	return getFormattedValues(frame,'P106',"sysselsetjing", false)
end

function _strip( str )
	return string.sub( str, 2 , string.len( str )-1 )
end

function strip( str )
	local lang = mw.language.getContentLanguage()
	-- Fjern mest mulig formatering fra den lokale verdien
	local stripped = str:gsub("%[%[([^%[%]%{%}%|]+)%|([^%[%]%{%}%|]+)%]%]", "%2")
	stripped = stripped:gsub("%b<>", "")
	local last = nil
	repeat
		last = stripped
		stripped = stripped:gsub( "(%b[])", _strip )
				:gsub( "(%b{})", _strip ) -- not sure if this should be escaped
				:gsub( "(%b())", _strip )
	until ( last == stripped )
	stripped = stripped:gsub("''+", "")
	stripped = lang:uc(stripped)
	return stripped
end

function velg(frame, prop, param, link)
	local verdiFraFrame = getFrameValue(frame, param)
	if verdiFraFrame == "uten" then
		-- Hvis malargumentet er satt til "uten" betyr det at det ikke er ønskelig
		-- at feltet vises, selv om det finnes data på Wikidata.
		return "[[Kategori:Artiklar derr " .. param .. " spesifisert som utan]]"
	end

	local verdiFraWikidata = getFormattedValues(frame, prop, param, link)
	if verdiFraWikidata == "" then
		-- No value at Wikidata.
		if verdiFraFrame == "" then
			return ""
		end
		return verdiFraFrame .. "[[Kategori:Artiklar der " .. param .. " manglar på Wikidata]]"
	end

	if verdiFraFrame == "" then
		if verdiFraWikidata == "" then
			return ""
		end
		return verdiFraWikidata .. "[[Kategori:Artiklar der " .. param .. " er henta frå Wikidata]]"
	end
	

	if strip(verdiFraFrame) == strip(verdiFraWikidata) then
		-- Den lokale verdien er helt lik Wikidata-verdien
		return verdiFraFrame .. "[[Kategori:Artiklar der " .. param .. " same som på Wikidata]]"
	end

	-- Den lokale verdien er ikke *helt* lik Wikidata-verdien, men vi vet ikke om det er
	-- snakk om betydningsforskjeller.
	return verdiFraFrame .. "[[Kategori:Artiklar der " .. param .. " forskjellig fra Wikidata]]"
end

function rad( frame, prop, param, link, displayName )
	assert( frame )
	local lang = mw.language.getContentLanguage()
	local verdiFraFrame = getFrameValue( frame, param )
	local value = velg( frame, prop, param, link )
	displayName = displayName or lang:ucfirst(param)
	if verdiFraFrame == "uten" then
		-- I dette tilfellet har velg() returnert en kategori av typen
		-- [[Kategori:Artikler hvor {param} spesifisert som uten]].
		-- Vi sender denne videre.
		return value
	end
	if value == "" then
		return ""
	end
	return string.format([[
		<tr class="rad" valign="top">
			<th colspan="2" class="nowrap">%s</th>
			<td colspan="2">%s</td>
		</tr>
	]], displayName, value)
end

function p.radYrke(frame)
	assert( frame )
	return rad(frame,'P106','sysselsetjing', false)
end

function p.velgYrke(frame)
	assert( frame )
	return velg(frame,'P106','sysselsetjing', false)
end

function p.velgIdrettsgren(frame)
	assert( frame )
	return velg(frame,'P641','idrettsgrein', false)
end

function p.velgKlubb(frame)
	assert( frame )
	return velg(frame,'P54','medlem av idrettslag', false)
end

function p.velgKonkurranseklasse(frame)
	assert( frame )
	return velg(frame,'P2094','konkurranseklasse', false)
end

function p.radRekord(frame)
	assert( frame )
	return rad(frame,'P2415','personleg rekord')
end

function p.radUtdannet_ved(frame)
	assert( frame )
	return rad(frame,'P69','utdanna ved')
end
function p.radUtdannelse(frame)
	assert( frame )
	return rad(frame,'P512','akademisk grad')
end
function p.radDoktorgradsveileder(frame)
	assert( frame )
	return rad(frame,'P184','doktorgradsveileder',true,'Doktorgrads-<br />veileder')
end
function p.radEktefelle(frame)
	assert( frame )
	return rad(frame,'P26','ektefelle', true)
end
function p.radMor(frame)
	assert( frame )
	return rad(frame,'P25','mor')
end
function p.radFar(frame)
	assert( frame )
	return rad(frame,'P22','far')
end
function p.radBarn(frame)
	assert( frame )
	return rad(frame,'P40','barn')
end
function p.radSoesken(frame)
	assert( frame )
	return rad(frame,'P3373','sysken')
end
function p.radParti(frame)
	assert( frame )
	return rad(frame,'P102','parti')
end
function p.rad(frame)
	assert( frame )
	return rad(frame, frame.args['wdp'], frame.args['param'], nil, frame.args['tekst'])
end
function p.values(frame)
	assert( frame )
	return getFormattedValues(frame, frame.args['wdp'], frame.args['param'], true)
end

return p