Moduldokumentasjon

Statements er en eksperimentell modul for å sette inn verdier fra utsagn i eksisterende infobokser, og er et alternativ til parserfunksjonen {{#statements}}. Modulen gjør nesten det samme, men kan også vise kvalifikatorer og referanser. Den har to former; text som gir ren tekst og html som gir html.

Bruk rediger

Selv om det er mulig å kalle funksjoner direkte fra andre moduler, så er formålet at modulens funksjoner skal kalles direkte fra maler.

Metoder rediger

text
Forenklet utlegg, men tilstrekkelig for testing av eksistens av verdier. Vil ikke vise kvalifikatorer og referanser.
html
Fullt utlegg, med lenking, kvalifikatorer og referanser.

Parametre rediger

anonyme
Tittel eller P-id for angivelse av egenskapen som skal brukes.
from
Tittel eller P-id for angivelse av egenskapen som skal brukes. Hvis parameteren mangler eller er tom så vil det koblede elementet brukes.

Eksempler rediger

Kode Utlegg
; [[Marokko]]s {{P|31}}
: tekst: {{#invoke:Statements|text|P31|from=Q1028}}
: html: {{#invoke:Statements|html|P31|from=Q1028}}
; Referanser
<references />
Marokkos forekomst av (P31)
tekst: konstitusjonelt monarki, uavhengig stat, middelhavsland, og land
html: konstitusjonelt monarki, uavhengig stat, middelhavsland, og land
Referanser
; [[Marokko]]s {{P|1082}}
: tekst: {{#invoke:Statements|text|P1082|from=Q1028}}
: html: {{#invoke:Statements|html|P1082|from=Q1028}}
; Referanser
<references />
Marokkos folketall (P1082)
tekst: 37 076 584
html: Lua-feil i Modul:Reference_score, linje 40: attempt to call global 'splitTimestamp' (a nil value).
Referanser
; [[Marokko]]s {{P|2046}}
: tekst: {{#invoke:Statements|text|P2046|from=Q1028}}
: html: {{#invoke:Statements|html|P2046|from=Q1028}}
; Referanser
<references />
Marokkos areal (P2046)
tekst: 446 550 km²
html: 446 550 km² (Vest-Sahara) [1]
Referanser
  1. ^ World Development Indicators, «Country Profile»[Hentet fra Wikidata]
; [[Knut Hamsun]]s {{P|26}}
: tekst: {{#invoke:Statements|text|P26|from=Q40826}}
: html: {{#invoke:Statements|html|P26|from=Q40826}}
; Referanser
<references />
Knut Hamsuns ektefelle (P26)
tekst: Marie Hamsun og Bergljot Bech
html: Marie Hamsun (1909, personens død, 19. feb. 1952) og Bergljot Bech (13. mai 1898, skilsmisse, 1906)
Referanser
; [[Knut Hamsun]]s {{P|40}}
: tekst: {{#invoke:Statements|text|P40|from=Q40826}}
: html: {{#invoke:Statements|html|P40|from=Q40826}}
; Referanser
<references />
Knut Hamsuns barn (P40)
tekst: Arild Hamsun, Ellinor Hamsun, Tore Hamsun, og Victoria Hamsun Charlesson
html: Arild Hamsun, Ellinor Hamsun, Tore Hamsun, og Victoria Hamsun Charlesson
Referanser
; [[Arne E. Holm]]s {{P|40}}
: tekst: {{#invoke:Statements|text|P40|from=Q11959015}}
: html: {{#invoke:Statements|html|P40|from=Q11959015}}
; Referanser
<references />
Arne E. Holms barn (P40)
tekst: Bentine Holm
html: Bentine Holm
Referanser

Pågående arbeid rediger

Det er noen forhold som trenger ytterligere avklaring, ikke minst om brukere har andre ønsker.

1. Seriekomma og konjunksjon
Lister bruker seriekomma og konjunksjonen «og» («and»). Det er ikke alltid dette er riktig, men i norsk språk brukes konjunksjonene «og» («and») og «eller» («or») litt om hverandre. Nettsamfunnet har divergerende meninger om hva som er rett, se Wikipedia:Torget/Arkiv/2019/januar#Opplistinger.
2. Formatering av tall
Tall bruker standard formatering,det vil si med mellomrom, slik det genereres av funksjonen mw.message.numParam(). Fordi standard formatering ikke bruker w:non-breaking space så kan vi få linjebrekk inne i tall. Det optimale ville vært å bruke narrow non-breaking space, men da vil utlegget bli forskjellig for tall i infoboksen og brødteksten.
3. Overstyring av navn på enheter
Enhetens etikett (label), eller lang form, kan hentes effektivt. Enhetens kortform er derimot lastmessig kostbart å hente, her må hele elementet hentes inn, og derfor er det mulig å predefinere disse. Dette er mest aktuelt for SI-enheter. Eksempelet med areal er litt uheldig da «km²» ikke er en korrekt SI-enhet.
4. Forenkling av parentes
Kvalifikatorer bruker en standardform, men de burde forenkles på samme vis som i brødtekst. Typisk forenkles startdatoen på et ekteskap til året, og navnet på et barn er kun fornavnet. Dette skaper imidlertid tvetydighet. Hvis to ekteskap treffer på samme året så må presisjonen økes med måned eller full dato. Tilsvarende for barn, har de forskjellig etternavn må dette angis. Vi kan unngå problemet ved å plassere fullform i en hoverboble, men det fungerer kun for html-formatet.
5. Angivelse av perioder
Perioder angis normalt som «startdatosluttdato», men det får vi ikke til med standardformatet. Dette er et eksempel på et unntak fra normalt utlegg, og egenskapene skal tas ut av datasettet og håndteres spesielt.
6. Ingen verdi og ukjent verdi
Oppføringer med «ingen verdi» og «ukjent verdi» kan tilpasses egenskapen, slik at navnene blir mer naturlige. Hvis oppføringen for barn (P40) har «ukjent verdi» så blir det isteden vist «ukjent barn» i siste eksempelet.

Notater rediger

Typisk kall i wikikode

{{#invoke:Statements|text|P40|from=Q11959015}}

Typisk testkall i consol

=mw.dumpObject(p.getFormattedValues(mw.getCurrentFrame(),'P2046', 'areal',true,'Q1028'))

Formatering av store tall

=mw.message.newRawMessage('Format: $1'):numParams(mw.wikibase.getBestStatements('Q4115189','P2067')[1].mainsnak.datavalue.value.amount):plain()

--- Statements…

-- @table local library variable
local libUtil = require 'libraryUtil'

local libRefs = require 'Module:Reference score'

local i18n = mw.loadData( 'Module:Statements/i18n' )

local h = {}

function h.findUnit( unit )
	-- is this a simple countable
	if unit == '1' then
		return nil
	end
	-- this is not well-defined
	local uri = mw.uri.new( unit )
	if not uri then
		return unit
	end
	local entityId = string.match( uri.path, 'Q%d+$')
	if not entityId then
		return unit
	end
	local label = mw.wikibase.getLabel( entityId )
	local pKey = string.format( '%s-%s', 'statements-unit', string.lower( entityId ) )
	local raw = i18n[pKey]
	if raw then
		local msg = mw.message.newRawMessage( raw )
		if msg:exists() then
			return label, msg:plain()
		end
	end
	return label
end

function h.findMessage( key, property )
	if not property then
		local raw = i18n[key] or mw.ustring.format( '[%s]', key )
		return mw.message.newRawMessage( raw )
	end
	local propertyId = mw.wikibase.resolvePropertyId( property )
	if not propertyId then
		local raw = i18n[key] or mw.ustring.format( '[%s]', key )
		return mw.message.newRawMessage( raw )
	end
	local pKey = string.format( '%s-%s', key, string.lower( propertyId ) )
	local raw = i18n[pKey] or i18n[key] or mw.ustring.format( '[%s]', key )
	return mw.message.newRawMessage( raw )
end
	
function h.exists( handler, type )
	if not handler then
		return nil, mw.html.create( 'span' )
			:addClass( 'warning' )
			:wikitext( mw.message.newRawMessage( i18n['statements-not-implemented'], type ):plain() )
		end
	return handler
end

-- @field datatypes holds handlers for mainsnaks
h.snaktypes = {}

h.snaktypes['somevalue'] = {
	text = function( snak )
		return h.findMessage( 'statements-somevalue', snak.property ):plain()
	end,

	html = function( snak )
		return mw.html.create( 'span' )
			:wikitext( h.findMessage( 'statements-somevalue', snak.property ):plain() )
	end,
}

h.snaktypes['novalue'] = {
	text = function( snak )
		return h.findMessage( 'statements-novalue', snak.property ):plain()
	end,

	html = function( snak )
		return mw.html.create( 'span' )
			:wikitext( h.findMessage( 'statements-somevalue', snak.property ):plain() )
	end,
}

h.snaktypes['value'] = {
	text = function( snak, property )
		local handler = h.datatypes[snak.datatype]
		if not handler then
			return ''
		end
		return handler.text( snak.datavalue, snak.property )
	end,

	html = function( snak, property )
		local handler, err = h.exists( h.datatypes[snak.datatype], snak.datatype )
		if not handler then
			return err
		end
		return mw.html.create( 'span' )
			:node( handler.html( snak.datavalue, snak.property ) )
	end,
}

-- @field datatypes holds handlers for datavalues
h.datatypes = {}

h.datatypes['wikibase-item'] = {
	text = function( datavalue, property )
		local handler = h.valuetypes[datavalue.type]
		if not handler then
			return ''
		end
		return handler.text( datavalue.value, property )
	end,

	html = function( datavalue, property )
		local handler, err = h.exists( h.valuetypes[datavalue.type], datavalue.type )
		if not handler then
			return err
		end
		return handler.html( datavalue.value, property )
	end
}

h.datatypes['quantity'] = {
	text = function( datavalue, property )
		local handler = h.valuetypes[datavalue.type]
		if not handler then
			return ''
		end
		return handler.text( datavalue.value, property )
	end,

	html = function( datavalue, property )
		local handler, err = h.exists( h.valuetypes[datavalue.type], datavalue.type )
		if not handler then
			return err
		end
		return handler.html( datavalue.value, property )
	end
}

-- @field datatypes holds handlers for values
h.valuetypes = {}

h.valuetypes['wikibase-entityid'] =  {
	-- @field text handler for generating a plain text layout
	text = function( value, property )
		local label = mw.wikibase.getLabel( value.id )
		return label or value.id
	end,

	-- @field html handler for generating a fancy html layout
	html = function( value, property )
		local label = mw.wikibase.getLabel( value.id )
		local sitelink = mw.wikibase.getSitelink( value.id )
		local html = mw.html.create( 'span' )
			:addClass( 'mw-wikibase-entityid' )
		if sitelink then
			html:addClass( 'extiw' )
		end
		return html:wikitext( mw.ustring.format( '[[%s|%s]]',
			sitelink or mw.ustring.format( 'd:%s', value.id ),
			label or value.id ) )
	end
}

h.valuetypes['quantity'] =  {
	-- @field text handler for generating a plain text layout
	text = function( value )
		local long, short = h.findUnit( value.unit )
		local msg = mw.message.newRawMessage( i18n['statements-format-quantity-scalar'] )
			:numParams( tonumber( value.amount ) )
			:params( short or long or '' )
		return msg:plain()
	end,

	-- @field html handler for generating a fancy html layout
	html = function( value )
		local long, short = h.findUnit( value.unit )
		local msg = nil
		if value.amount then
			msg = h.findMessage( 'statements-format-quantity-scalar', property )
				:numParams( tonumber( value.amount ) )
				:params( short or long or '' )
		elseif value.lowerBound or value.upperBound then
			local lower = value.lowerBound and h.findMessage( 'statements-format-quantity-range-lower-bound', property )
					:numParams( tonumber( value.lowerBound ) )
				or h.findMessage( 'statements-format-quantity-range-lower-open', property )
			local upper = value.upperBound and h.findMessage( 'statements-format-quantity-range-upper-bound', property )
					:numParams( tonumber( value.upperBound ) )
				or h.findMessage( 'statements-format-quantity-range-upper-open', property )
			msg = h.findMessage( 'statements-format-quantity-range', property )
				:params( lower, upper, short or long )
		else
			msg = h.findMessage( 'statements-format-quantity-empty', property )
		end
		return mw.html.create( 'span' )
			:addClass( 'mw-wikibase-quantity' )
			:wikitext( msg:plain() )
	end
}

--- Get entity.
-- This convenience function encapsulates base functionality,
-- and makes it possible to use both Q-ids and titles to reference
-- entities.
-- @throw on wrong argument.
-- @tparam nil|string entityIdOrTitle a string that can be both a Q-id and title
-- @treturn entity
function h.getEntity( entityIdOrTitle )
	libUtil.checkType( 'Statements:getEntity', 1, entityIdOrTitle, 'string', true )
	local entity = nil
	if entityIdOrTitle then
		if mw.ustring.match( entityIdOrTitle, '^Q%d+$' ) then
			entity = mw.wikibase.getEntity( entityIdOrTitle )
		elseif mw.ustring.match( entityIdOrTitle, '^.$' ) then
			entity = mw.wikibase.getEntityIdForTitle( entityIdOrTitle )
		end
	end

	if not entity then
		entity = mw.wikibase.getEntityIdForCurrentPage()
	end

	return entity
end

--- Render plain text form.
-- This is an access point for use in a template.
-- Will not generate visible warnings.
-- @throw on wrong argument.
-- @tparam nil|table frame
-- @treturn wikitext
function h.text( frame )
	libUtil.checkType( 'Statements:text', 1, frame, 'table', true )
	frame = mw.getCurrentFrame()
	local entity = h.getEntity( frame.args['from'] )
	if not entity then
		return 'no entity'
	end

	local statements = entity:getBestStatements( frame.args[1] )
	if not statements then
		return 'no statements'
	end

	local t = {}
	for k,v in ipairs( statements ) do
		if v.type == 'statement' then
			local handler = h.snaktypes[k..':'..v.mainsnak.snaktype] or h.snaktypes[v.mainsnak.snaktype]
			if handler then
				local item = handler.text( v.mainsnak )
				if item then
					table.insert( t, item )
				end
				local refs = ''
			end
		end
	end

	if #t == 0 then
		return '#t == 0'
	elseif #t == 1 then
		return t[1]
	elseif #t == 2 then
		return mw.ustring.format( '%s %s %s', t[1], mw.message.newRawMessage( i18n['statements-combiner'] ):plain(), t[2] )
	end

	local punctuation = mw.message.newRawMessage( i18n['statements-punctuation'] ):plain()
	punctuation = punctuation .. ' '
	local last = table.remove( t )
	local first = table.concat( t, punctuation )
	return mw.ustring.format( '%s, %s %s', first, mw.message.newRawMessage( i18n['statements-combiner'] ):plain(), last )
end

function h.qualifiers( snaks )
	local keys = {}
	for k,_ in pairs( snaks or {} ) do
		table.insert( keys, k )
	end
	if #keys == 0 then
		return ''
	end
	local t = {}
	for _,k in pairs( mw.wikibase.orderProperties( keys ) ) do
		-- lua keeps injection order
		t[k] = snaks[k]
	end
	local wiki = mw.wikibase.formatValues( t )
	if not wiki or wiki == '' then
		return ''
	end
	local html = mw.html.create( 'span' )
		:addClass( 'qualifiers' )
		:wikitext( ' (', wiki, ') ' )
	return html
end

--- Render fancy html form.
-- This is an access point for use in a template.
-- Generates visible warnings.
-- @throw on wrong argument.
-- @tparam nil|table frame
-- @treturn wikitext
function h.html( frame )
	frame = mw.getCurrentFrame()
	local entity = h.getEntity( frame.args['from'] )
	if not entity then
		return mw.html.create( 'span' )
			:addClass( 'warning' )
			:wikitext( mw.message.newRawMessage( i18n['statements-no-entity'] ):plain() )
	end

	local statements = entity:getBestStatements( frame.args[1] )
	if not statements then
		return mw.html.create( 'span' )
			:addClass( 'warning' )
			:wikitext( mw.message.newRawMessage( i18n['statements-no-statements'] ):plain() )
	end

	local t = {}
	for _,v in ipairs( statements ) do
		if v.type == 'statement' then
			local handler = h.snaktypes[v.mainsnak.snaktype]
			if handler then
				local item = handler.html( v.mainsnak )
				if item then
					item:node( h.qualifiers( v.qualifiers ) )
					item:wikitext( libRefs.render( frame, v.references ) )
					table.insert( t, item )
				end
			end
		end
	end
	local html = mw.html.create( 'span' )
		:addClass( 'mw-statement' )
	if #t == 0 then
		return html
	elseif #t == 1 then
		return html:node( t[1] )
	elseif #t == 2 then
		return html:node( t[1] ):wikitext( ' ', mw.message.newRawMessage( i18n['statements-combiner'] ):plain(), ' ' ):node( t[2] )
	end

	local last = table.remove( t )
	local punctuation = mw.message.newRawMessage( i18n['statements-punctuation'] ):plain()
	for _,v in ipairs( t ) do
		html:node( v ):wikitext( punctuation, ' ' )
	end
	html:wikitext( ' ', mw.message.newRawMessage( i18n['statements-combiner'] ):plain(), ' ' ):node( last )
	return html
end

return h