Questa pagina è protetta dallo spostamento
Questa pagina è protetta

Modulo:Collegamenti esterni: differenze tra le versioni

Da Wikipedia, l'enciclopedia libera.
Vai alla navigazione Vai alla ricerca
Contenuto cancellato Contenuto aggiunto
supporto per vincolo multiplo. minuzie
Parametro per eventuali esclusioni. Solo categorie per link numerosi. Migliorie ai link multipli.
Riga 6: Riga 6:


local getArgs = require('Modulo:Arguments').getArgs
local getArgs = require('Modulo:Arguments').getArgs
local mDelink = require('Modulo:Delink')
local mWikidata = require('Modulo:Wikidata')
local mWikidata = require('Modulo:Wikidata')
local mCitazione = require('Modulo:Citazione')
local mCitazione = require('Modulo:Citazione')
Riga 16: Riga 15:
'Biografie', 'Letteratura', 'Biologia'
'Biografie', 'Letteratura', 'Biologia'
}
}
-- Soglie di attenzione sul numero elevato di collegamenti, per categorie di controllo
-- Numero di collegamenti esterni oltre il quale sono raggruppati
local THRESHOLD_GROUPED_LIST = 12
local MOLTI_LINK = 12
local MOLTI_LINK_2 = 15
-- Categorie di servizio
-- Categorie di servizio
local catLetta = ' letta da Wikidata'
local catLetta = ' letta da Wikidata'
local catMultiSenzaQual = ' multipla letta da Wikidata senza qualificatore'
local catMultiSenzaQual = ' multipla letta da Wikidata senza qualificatore'
local catGroupedList = 'Voci con template Collegamenti esterni e collegamenti raggruppati'
local catMoltiLink = 'Voci con template Collegamenti esterni e molti collegamenti'
local catMoltiLink2 = 'Voci con template Collegamenti esterni e molti collegamenti (soglia maggiore)'
local catEmpty = 'Voci con template Collegamenti esterni senza dati da Wikidata'
local catEmpty = 'Voci con template Collegamenti esterni senza dati da Wikidata'
local catUnknownQual = 'Voci con template Collegamenti esterni e qualificatori sconosciuti'
local catUnknownQual = 'Voci con template Collegamenti esterni e qualificatori sconosciuti'
Riga 148: Riga 149:
specifica = self.qualifier[i]
specifica = self.qualifier[i]
else
else
local ripetuto = false -- controllo se stesso titolo già usato
if titolo == self.title then
for j = 1, i - 1 do
if titolo == (self.extraConf.titolo[j] or self.title) then
ripetuto = true
break
end
end
if ripetuto then
specifica = 'altra versione'
specifica = 'altra versione'
else
else
Riga 160: Riga 168:
end
end
return tbl
return tbl
end

-- Restituisce il parametro posttitolo per il modulo Citazione.
--
-- @return {string}
function ExtLink:_getPostTitolo(groupedList)
local ret
if groupedList or not self.qualifier and #self.url > 1 then
local tbl = {}
for i = 2, #self.url do
table.insert(tbl, string.format('[%s %s]', self.url[i], i))
end
ret = string.format('(%s)', table.concat(tbl, ', '))
end
return ret
end

-- Restituisce la stringa da usare come "sito" per il modulo Citazione
-- o come label nel link creato come [url label].
--
-- @param {boolean} delink
-- @return {string}
function ExtLink:_getSito(delink)
local sito
if self.linkConf.sito then
sito = delink and mDelink._main({ self.linkConf.sito }) or self.linkConf.sito
else
sito = getDomain(self.url[1])
end
return sito
end
end


Riga 217: Riga 195:
end
end
return table.concat(formattedLinks, '\n')
return table.concat(formattedLinks, '\n')
end

-- Setta come necessaria la disambiguazione del link (più URL con lo stesso dominio nel gruppo),
-- se configurata tramite la chiave "sitodis" nella configurazione.
function ExtLink:needSitoDis()
self.sitodis = self.linkConf.sitodis
end
end


Riga 238: Riga 210:
titolo = self:_getTitolo(),
titolo = self:_getTitolo(),
altrilink = self:_getAltriLink(),
altrilink = self:_getAltriLink(),
sito = self.linkConf.opera and '' or self:_getSito(),
sito = self.linkConf.opera and '' or self.extraConf.sito,
opera = self.linkConf.opera,
opera = self.linkConf.opera,
editore = self.linkConf.editore,
editore = self.linkConf.editore,
Riga 252: Riga 224:
return self:_formatPropertyURL()
return self:_formatPropertyURL()
end
end
end

-- Formatta il collegamento esterno come elemento di un elenco puntato raggruppato.
--
-- @return {string}
function ExtLink:getGroupedListItem()
local ret = string.format('[%s %s]', self.url[1], self:_getSito(true))
return #self.url > 1 and (ret .. ' ' .. self:_getPostTitolo(true)) or ret
end
end


Riga 285: Riga 249:
self.catColon = ''
self.catColon = ''
self.from = args.from
self.from = args.from
-- esclusioni ricevute come 'Xxx, yyy' e memorizzate come { 'Xxx'=true, 'Yyy'=true }
self.escludi = {}
local argescludi = args.escludi and mw.text.split(args.escludi, ',')
if argescludi then
for _, str in ipairs(argescludi) do
self.escludi[mw.getContentLanguage():ucfirst(mw.text.trim(str))] = true
end
end
-- la pagina dei test utilizza uno stub del modulo Wikidata
-- la pagina dei test utilizza uno stub del modulo Wikidata
if mw.title.getCurrentTitle().prefixedText ==
if mw.title.getCurrentTitle().prefixedText ==
Riga 317: Riga 289:
groupSites[groupName] = {}
groupSites[groupName] = {}
ret[groupName] = {}
ret[groupName] = {}
-- controlla se è un gruppo escluso manualmente dall'utente
if self.escludi[groupName] then
cfg[groupName] = {}
end
for _, linkConf in ipairs(cfg[groupName]) do -- Per ogni sito configurato
for _, linkConf in ipairs(cfg[groupName]) do -- Per ogni sito configurato
local valido = true
local valido = true
Riga 328: Riga 304:
end
end
end
end
-- controlla se è un sito escluso manualmente dall'utente
if self.escludi[linkConf.pid] or self.escludi[mw.getContentLanguage():ucfirst(linkConf.medium or 'web')] then
valido = false
end
-- Se il sito è abilitato, avviene la lettura da Wikidata
if valido then
if valido then
local url, qualifier, extraConf
local url, qualifier, extraConf
local Nqualtitoli = 0
local Nqualtitoli = 0
local claims = mWikidata._getClaims(linkConf.pid, { from = self.from, snaktype = 'value' })
local claims = mWikidata._getClaims(linkConf.pid, { from = self.from, snaktype = 'value' })
-- Qui, se ci sono valori, il sito viene aggiunto a quelli da mostrare
if claims and #claims > 0 then
if claims and #claims > 0 then
-- Qualificatori generali
-- Qualificatori generali
-- In caso di valori multipli, il titolo viene letto per tutti; gli altri qualificatori solo per il primo (altrimenti bisogna rivedere la formattazione dei valori multipli)
-- In caso di valori multipli, il titolo viene letto per tutti; gli altri qualificatori solo per il primo (altrimenti bisogna rivedere la formattazione dei valori multipli)
-- Ricordarsi di elencare i qual. generali anche in altriQualNoti
extraConf = {}
extraConf = {}
extraConf.autore = mWikidata._formatQualifiers(claims[1], 'P50') or mWikidata._formatQualifiers(claims[1], 'P2093') -- come item o stringa
extraConf.autore = mWikidata._formatQualifiers(claims[1], 'P50') or mWikidata._formatQualifiers(claims[1], 'P2093') -- come item o stringa
Riga 342: Riga 325:
extraConf.titolo = {}
extraConf.titolo = {}
for i, claim in ipairs(claims) do
for i, claim in ipairs(claims) do
extraConf.titolo[i] = mWikidata._formatQualifiers(claim, 'P1476') or mWikidata._formatQualifiers(claim, 'P1810') -- titolo o "indicato come"
extraConf.titolo[i] = mWikidata._formatQualifiers(claim, 'P1476') or mWikidata._formatQualifiers(claim, 'P1810') or mWikidata._formatQualifiers(claim, 'P742') -- titolo o "indicato come" o pseudonimo
if extraConf.titolo[i] then Nqualtitoli = Nqualtitoli + 1 end
if extraConf.titolo[i] then Nqualtitoli = Nqualtitoli + 1 end
end
end
Riga 364: Riga 347:
end
end
for _, v in ipairs(qualifierIds) do qualifierIds[v] = true end
for _, v in ipairs(qualifierIds) do qualifierIds[v] = true end
local altriQualNoti = {P407 = true, P50 = true, P2093 = true, P1476 = true, P1810 = true, P577 = true, P478 = true, P304 = true, P813 = true}
local altriQualNoti = {P407 = true, P50 = true, P2093 = true, P1476 = true, P1810 = true, P742 = true, P577 = true, P478 = true, P304 = true, P813 = true}
for qualifierId in pairs(claim.qualifiers) do
for qualifierId in pairs(claim.qualifiers) do
if qualifierIds[qualifierId] ~= true and altriQualNoti[qualifierId] ~= true then
if qualifierIds[qualifierId] ~= true and altriQualNoti[qualifierId] ~= true then
Riga 380: Riga 363:
table.insert(url, claim)
table.insert(url, claim)
end
end
-- nome sito, di default il dominio estratto dall'url
extraConf.sito = linkConf.sito or getDomain(linkConf.url)
-- Creazione dell'oggetto collegamento esterno, con l'url (o gli url) e gli altri dati raccolti
-- Creazione dell'oggetto collegamento esterno, con l'url (o gli url) e gli altri dati raccolti
table.insert(ret[groupName], ExtLink:new(url, qualifier, linkConf, extraConf, self.from))
table.insert(ret[groupName], ExtLink:new(url, qualifier, linkConf, extraConf, self.from))
Riga 387: Riga 372:
table.insert(self.categories, string.format('[[%sCategoria:%s%s]]', self.catColon, linkConf.pid, tail))
table.insert(self.categories, string.format('[[%sCategoria:%s%s]]', self.catColon, linkConf.pid, tail))
-- per verificare se un sito è ripetuto nel gruppo
-- per verificare se un sito è ripetuto nel gruppo
groupSites[groupName][extraConf.sito] = (groupSites[groupName][extraConf.sito] or 0) + 1
local sito = linkConf.sito and mDelink._main({ linkConf.sito }) or getDomain(linkConf.url)
-- conteggio complessivo dei collegamenti
groupSites[groupName][sito] = (groupSites[groupName][sito] or 0) + 1
self.numExtLinks = self.numExtLinks + 1
self.numExtLinks = self.numExtLinks + 1
end
end
Riga 397: Riga 382:
for _, groupName in ipairs(orderedGroupNames) do
for _, groupName in ipairs(orderedGroupNames) do
for _, extLink in ipairs(ret[groupName]) do
for _, extLink in ipairs(ret[groupName]) do
-- necessaria la disambiguazione (più URL con lo stesso dominio nel gruppo),
local linkConf = extLink.linkConf
-- se configurata tramite "sitodis" nella configurazione.
local sito = linkConf.sito and mDelink._main({ linkConf.sito }) or getDomain(linkConf.url)
if groupSites[groupName][sito] > 1 then
if groupSites[groupName][extLink.extraConf.sito] > 1 then
extLink:needSitoDis()
extLink.sitodis = extLink.linkConf.sitodis
end
end
end
end
end
end
-- categorie di servizio
-- categorie di servizio sul numero di link
local catnumero
if self.numExtLinks == 0 then
if self.numExtLinks == 0 then
catnumero = catEmpty
table.insert(self.categories, string.format('[[%sCategoria:%s]]', self.catColon, catEmpty))
elseif self.numExtLinks > THRESHOLD_GROUPED_LIST then
elseif self.numExtLinks > MOLTI_LINK then
if self.numExtLinks > MOLTI_LINK_2 then catnumero = catMoltiLink2
table.insert(self.categories, string.format('[[%sCategoria:%s]]', self.catColon, catGroupedList))
else catnumero = catMoltiLink end
end
if catnumero then
table.insert(self.categories, string.format('[[%sCategoria:%s]]', self.catColon, catnumero))
end
end

return ret
return ret
end
end
Riga 426: Riga 415:
end
end
return table.concat(formattedLinks, '\n')
return table.concat(formattedLinks, '\n')
end

-- Formatta i collegamenti esterni come elenco puntato, raggruppandoli.
--
-- @param {table} [groupNames]
-- @return {string}
function LinksManager:_formatGroupedList(groupNames)
local formattedGroups = {}
for _, groupName in ipairs(groupNames) do
local formattedLinks = {}
for _, extLink in ipairs(self.extLinks[groupName]) do
table.insert(formattedLinks, extLink:getGroupedListItem())
end
if #formattedLinks > 0 then
local groupTitle = groupName == 'Enciclopedie' and
groupName or 'Banche dati ' .. mw.ustring.lower(groupName)
table.insert(formattedGroups, string.format("* %s: %s%s", groupTitle,
table.concat(formattedLinks, '<span style="font-weight:bold;">&nbsp;·</span> '),
mEditAtWikidata._showMessage({ sezione = 'identifiers', qid = self.from })))
end
end
return table.concat(formattedGroups, '\n')
end
end


-- Restituisce tutti i collegamenti esterni formattandoli come elenco puntato
-- Restituisce tutti i collegamenti esterni formattandoli come elenco puntato
-- e raggruppandoli quando sono più di THRESHOLD_GROUPED_LIST.
--
--
-- @return {string}
-- @return {string}
function LinksManager:getList()
function LinksManager:getList()
local categories, groupNames, olinks, links
local categories, links
-- categorie di servizio

-- categorie
categories = (mw.title.getCurrentTitle().namespace == 0 or self.debug) and
categories = (mw.title.getCurrentTitle().namespace == 0 or self.debug) and
table.concat(self.categories) or ''
table.concat(self.categories) or ''
-- collegamenti
-- i siti web ufficiali sono sempre visualizzati uno per riga
olinks = self:_formatList({ 'Ufficiali' })
links = self:_formatList(orderedGroupNames)
return links .. categories
-- tutti gli altri collegamenti
groupNames = { unpack(orderedGroupNames, 2) }
links = self.numExtLinks <= THRESHOLD_GROUPED_LIST and
self:_formatList(groupNames) or
self:_formatGroupedList(groupNames)

return olinks .. ((links ~= '' and olinks ~= '') and '\n' or '') .. links .. categories
end
end


Riga 477: Riga 436:
local p = {}
local p = {}


-- Funzione di utilità per il manuale, restituisce la soglia THRESHOLD_GROUPED_LIST.
-- Funzioni di utilità per il manuale, danno la soglia di attenzione sul n° di link.
function p.threshold(frame)
function p.threshold(frame)
return THRESHOLD_GROUPED_LIST
return MOLTI_LINK
end
function p.threshold2(frame)
return MOLTI_LINK_2
end
end



Versione delle 23:28, 13 apr 2019

Modulo che implementa il template {{Collegamenti esterni}}.

Ha una sottopagina di configurazione per ciascun gruppo di collegamenti esterni: Errore Lua in package.lua alla linea 80: module 'Modulo:No globals' not found.

Tipo di proprietà

Quasi tutti i collegamenti si basano su proprietà di tipo "identificativo esterno", quindi per ciascuno bisognerà inserire, nel relativo gruppo della sottopagina di configurazione, almeno l'ID della proprietà Wikidata ("pid") e l'URL di formattazione ("url"). Per i rari casi di utilizzo di proprietà di tipo "URL", al posto dell'URL di formattazione va specificato il titolo del collegamento ("titolo").

Ordine collegamenti

All'interno di ciascun gruppo i collegamenti sono visualizzati nell'ordine in cui sono stati inseriti nella pagina di configurazione (ovviamente se è presente la relativa proprietà Wikidata). Per cambiare l'ordine è quindi sufficiente cambiare l'ordine dei collegamenti nelle sottopagine di configurazione.

Disambiguare i collegamenti relativi allo stesso sito web

Quando più proprietà Wikidata si riferiscono allo stesso sito web (esempio per le diverse schede di un calciatore, allenatore, dirigente, ...) e possono essere usate contemporaneamente in uno stesso elemento Wikidata, ci sono tre modi per disambiguare i collegamenti generati:

  1. differenziarli con "tipo", esempio nel primo tipo = 'calciatore' e nel secondo tipo = 'allenatore'. La disambiguazione apparirà però sempre, anche quando presente una sola proprietà nell'elemento.
  2. differenziarli con "titolo", esempio nel primo titolo = 'Scheda giocatore di $1' e nel secondo titolo = 'Scheda allenatore di $1'. La disambiguazione apparirà però sempre, anche quando presente una sola proprietà nell'elemento, inoltre la frase apparirà in corsivo anche se non fosse effettivamente il titolo della pagina.
  3. differenziarli con "sitodis", esempio nel primo sitodis = 'giocatore' e nel secondo sitodis = 'allenatore'. In questo modo, rispetto ai due metodi precedenti: (1) la disambiguazione apparirà automaticamente solo quando è presente più di una proprietà che utilizza lo stesso sito web e (2) si potranno omettere titolo e sito, lasciandoli al loro valore predefinito, ossia il titolo della pagina e il dominio dell'URL.
Controllo duplicati

Verifica automatica di proprietà duplicate: Errore Lua in package.lua alla linea 80: module 'Modulo:No globals' not found..


--[[
* Modulo che implementa il template Collegamenti esterni.
]]--

require('Modulo:No globals')

local getArgs = require('Modulo:Arguments').getArgs
local mWikidata = require('Modulo:Wikidata')
local mCitazione = require('Modulo:Citazione')
local mEditAtWikidata = require('Modulo:Modifica su Wikidata')
-- Permette di definire l'ordine di visualizzazione dei vari gruppi
local orderedGroupNames = {
	'Ufficiali', 'Enciclopedie', 'Politica', 'Calcio', 'Sport', 'Software', 'Videogiochi',
	'Fumetti', 'Cinema', 'Musica', 'MAB', 'Architettura', 'Geografia',
	'Biografie', 'Letteratura', 'Biologia'
}
-- Soglie di attenzione sul numero elevato di collegamenti, per categorie di controllo
local MOLTI_LINK = 12
local MOLTI_LINK_2 = 15
-- Categorie di servizio
local catLetta = ' letta da Wikidata'
local catMultiSenzaQual = ' multipla letta da Wikidata senza qualificatore'
local catMoltiLink = 'Voci con template Collegamenti esterni e molti collegamenti'
local catMoltiLink2 = 'Voci con template Collegamenti esterni e molti collegamenti (soglia maggiore)'
local catEmpty = 'Voci con template Collegamenti esterni senza dati da Wikidata'
local catUnknownQual = 'Voci con template Collegamenti esterni e qualificatori sconosciuti'

-- =============================================================================
--                            Funzioni di utilità
-- =============================================================================

-- Restituisce la configurazione delle sottopagine.
--
-- @return {table}
local function readConfig()
	local ret = {}
	for _, groupName in ipairs(orderedGroupNames) do
		ret[groupName] = mw.loadData('Modulo:Collegamenti esterni/' .. groupName)
	end
	return ret
end

-- Restituisce il titolo della pagina corrente rimuovendo eventuale testo tra parentesi.
-- Se l'etichetta dell'elemento Wikidata contiene delle parentesi,
-- non le rimuove perché significa che fanno parte del titolo.
-- Con il parametro "from" (elemento Wikidata arbitrario) usa sempre l'etichetta.
--
-- @param {string} from
-- @return {string}
local function getCurrentTitle(from)
	local ret
	local label = mWikidata._getLabel({ from })
	if from then
		ret = label
	else
		ret = mw.title.getCurrentTitle().text
		if not (label and string.find(label, ' %(')) then
			ret = mw.text.split(ret, ' %(')[1]
		end
	end
	return ret
end

-- Restituisce il dominio dell'URL specificato.
--
-- @param {string} url
-- @return {string}
local function getDomain(url)
	return mw.uri.new(url).host:gsub('^www.', '')
end

-- Restituisce true se l'elemento collegato alla pagina o quello specificato in from
-- ha tra i valori della proprietà indicata uno degli elementi specificati.
-- @param {string} prop - codice della proprietà 'Pxxx'
-- @param {table} [entityIds] - array dei valori (strighe 'Qxxx') che può avere
-- @param {string} from
-- @return {boolean}
local function checkEntity(prop, entityIds, from)
	local args = { from = from }
	for _, entityId in ipairs(entityIds) do
		table.insert(args, entityId)
	end
	return mWikidata._propertyHasEntity(prop, args)
end

-- =============================================================================
--                            Classe ExtLink
-- =============================================================================

-- La classe ExtLink rappresenta un singolo collegamento esterno.
-- Al suo interno ha un riferimento alla propria configurazione (linkConf)
-- e nel caso la proprietà Wikidata abbia più valori li raccoglie tutti.

local ExtLink = {}

-- Costruttore della classe ExtLink.
--
-- @param {table} [url] - uno o più URL, quanti sono i valori della proprietà Wikidata
-- @param {table} [qualifier] - eventuali qualificatori da annettere al titolo per ciascun URL
-- @param {table} linkConf - la configurazione fissa per questo collegamento esterno
-- @param {table} extraConf - altri elementi di configurazione ricavati dall'item
-- @param {string} from - entityId se diverso da quello collegato alla pagina corrente
-- @return {table} un nuovo oggetto ExtLink
function ExtLink:new(url, qualifier, linkConf, extraConf, from)
	local self = {}
	setmetatable(self, { __index = ExtLink })

	-- sostituisce eventuali spazi con %20
	for i = 1, #url do
		url[i] = url[i]:gsub(' ', '%%20')
	end
	self.url = url
	self.qualifier = #url > 1 and qualifier
	self.linkConf = linkConf
	self.extraConf = extraConf
	self.from = from
	self.title = getCurrentTitle()
	self.title = self.from and mWikidata._getLabel({ self.from }) or
			(self.linkConf.titolo and
			self.linkConf.titolo:gsub('$1', self.title) or
			self.title)
	self.extraConf.medium = self.linkConf.medium or 'web'
	
	return self
end

-- Restituisce il parametro titolo per il modulo Citazione.
--
-- @return {string}
function ExtLink:_getTitolo()
	local titolo = self.extraConf.titolo[1] or self.title
	if self.qualifier and self.qualifier[1] ~= nil then
		return string.format('%s (%s)', titolo, self.qualifier[1])
	else
		return titolo
	end
end

-- Restituisce il parametro altrilink per il modulo Citazione.
-- Nel caso di valori multipli, genera quelli successivi al primo.
--
-- @return {table}
function ExtLink:_getAltriLink()
	local tbl = {}
	local titolo, specifica
	for i = 2, #self.url do
		titolo = self.extraConf.titolo[i] or self.title
		if self.qualifier and self.qualifier[i] ~= nil then
			specifica = self.qualifier[i]
		else
			local ripetuto = false -- controllo se stesso titolo già usato
			for j = 1, i - 1 do
				if titolo == (self.extraConf.titolo[j] or self.title) then 
					ripetuto = true
					break
				end
			end
			if ripetuto then
				specifica = 'altra versione'
			else
				specifica = nil -- se titoli diversi, va bene anche senza specificazione
			end
		end
		if specifica then
			titolo = string.format('%s (%s)', titolo, specifica)
		end
		table.insert(tbl, { self.url[i], titolo })
	end
	return tbl
end

-- Formatta il collegamento esterno quando la proprietà è di tipo URL.
--
-- @return {string}
function ExtLink:_formatPropertyURL()
	local formattedLinks = {}
	local currTitle = getCurrentTitle(self.from)
	local claims = mWikidata._getClaims(self.linkConf.pid, { from = self.from }) or {}
	for idx, claim in ipairs(claims) do
		local langs = mWikidata._formatQualifiers(claim, 'P407', { formatting = 'raw' }, true)
		langs = (#langs == 1 and langs[1] == 'Q652') and {} or langs
		for i, lang in ipairs(langs) do
			langs[i] = mWikidata._getLabel({ lang })
		end
		local formattedLink = mCitazione.cita_da_modulo(
			self.extraConf.medium,
			{
				url = mWikidata._formatStatement(claim),
				titolo = self.linkConf.titolo:gsub('$1', currTitle),
				lingua = table.concat(langs, ','),
				cid = self.linkConf.cid
			})
		table.insert(formattedLinks, '* ' .. formattedLink ..
					 mEditAtWikidata._showMessage({ pid = self.linkConf.pid, qid = self.from }))
	end
	return table.concat(formattedLinks, '\n')
end

-- Formatta il collegamento esterno come elemento di un elenco puntato.
--
-- @return {string}
function ExtLink:getListItem()
	-- se è specificato l'URL di formattazione è una
	-- proprietà di tipo "identificativo esterno" altrimenti di tipo URL
	if self.linkConf.url then
		return '* ' .. mCitazione.cita_da_modulo(
			self.extraConf.medium,
			{
				url = self.url[1],
				titolo = self:_getTitolo(),
				altrilink = self:_getAltriLink(),
				sito = self.linkConf.opera and '' or self.extraConf.sito,
				opera = self.linkConf.opera,
				editore = self.linkConf.editore,
				lingua = self.linkConf.lingua,
				cid = self.linkConf.cid,
				autore = self.linkConf.autore or self.extraConf.autore,
				volume = self.extraConf.volume,
				p = self.extraConf.pagina,
				data = self.linkConf.data or self.extraConf.data,
				tipo = self.linkConf.tipo or self.sitodis
			}) .. mEditAtWikidata._showMessage({ pid = self.linkConf.pid, qid = self.from })
	else
		return self:_formatPropertyURL()
	end
end

-- =============================================================================
--                            Classe LinksManager
-- =============================================================================

-- La classe LinksManager è la classe principale del modulo.
-- Al suo interno ha un riferimento a tutti collegamenti esterni (extLinks)
-- presenti in un dato elemento Wikidata e li può restituire tutti formattati 
-- nel modo più appropriato.

local LinksManager = {}

-- Costruttore della classe LinksManager.
--
-- @param {table} args
-- @return {table} un nuovo oggetto LinksManager
function LinksManager:new(args)
	local self = {}
	setmetatable(self, { __index = LinksManager })

	self.numExtLinks = 0
	self.categories = {}
	self.catColon = ''
	self.from = args.from
	-- esclusioni ricevute come 'Xxx, yyy' e memorizzate come { 'Xxx'=true, 'Yyy'=true }
	self.escludi = {}
	local argescludi = args.escludi and mw.text.split(args.escludi, ',')
	if argescludi then
		for _, str in ipairs(argescludi) do
			self.escludi[mw.getContentLanguage():ucfirst(mw.text.trim(str))] = true
		end
	end
	-- la pagina dei test utilizza uno stub del modulo Wikidata
	if mw.title.getCurrentTitle().prefixedText ==
	   'Discussioni modulo:Collegamenti esterni/test' then
		self:_setStubWikidata(args.stubwd)
	end
	self.extLinks = self:_getExtLinks()

	return self
end

-- Permette di specificare uno stub del modulo Wikidata
-- in modo da ottenere i valori delle proprietà in modo deterministico,
-- non dipendenti da modifiche utente a un elemento Wikidata.
--
-- @param {table} stubwd
function LinksManager:_setStubWikidata(stubwd)
	mEditAtWikidata = { _showMessage = function(frame) return '' end }
	mWikidata = stubwd
	self.catColon = ':'
	self.debug = true
end

-- Ottiene tutti i collegamenti esterni (configurati) presenti in un dato elemento Wikidata
-- suddivisi per gruppo.
--
-- @return {table}
function LinksManager:_getExtLinks()
	local ret, groupSites = {}, {}
	local cfg = readConfig()
	for _, groupName in ipairs(orderedGroupNames) do -- Per ogni gruppo tematico
		groupSites[groupName] = {}
		ret[groupName] = {}
		-- controlla se è un gruppo escluso manualmente dall'utente
		if self.escludi[groupName] then
			cfg[groupName] = {}
		end
		for _, linkConf in ipairs(cfg[groupName]) do -- Per ogni sito configurato
			local valido = true
			-- controlla se è un sito da escludere per soggetto non pertinente
			if type(linkConf.vincolo) == 'table' then
				valido = false
				local Nvincoli = 0
				for _, _ in ipairs(linkConf.vincolo) do Nvincoli = Nvincoli + 1 end
				for i = 2, Nvincoli, 2 do -- Per ogni coppia 'proprietà', {valori}
					valido = valido or checkEntity(linkConf.vincolo[i - 1], linkConf.vincolo[i], self.from)
				end
			end
			-- controlla se è un sito escluso manualmente dall'utente
			if self.escludi[linkConf.pid] or self.escludi[mw.getContentLanguage():ucfirst(linkConf.medium or 'web')] then
				valido = false
			end
			-- Se il sito è abilitato, avviene la lettura da Wikidata
			if valido then
				local url, qualifier, extraConf
				local Nqualtitoli = 0
				local claims = mWikidata._getClaims(linkConf.pid, { from = self.from, snaktype = 'value' })
				-- Qui, se ci sono valori, il sito viene aggiunto a quelli da mostrare
				if claims and #claims > 0 then
					-- Qualificatori generali
					-- In caso di valori multipli, il titolo viene letto per tutti; gli altri qualificatori solo per il primo (altrimenti bisogna rivedere la formattazione dei valori multipli)
					-- Ricordarsi di elencare i qual. generali anche in altriQualNoti
					extraConf = {}
					extraConf.autore = mWikidata._formatQualifiers(claims[1], 'P50') or mWikidata._formatQualifiers(claims[1], 'P2093') -- come item o stringa
					extraConf.volume = mWikidata._formatQualifiers(claims[1], 'P478')
					extraConf.pagina = mWikidata._formatQualifiers(claims[1], 'P304')
					extraConf.data = mWikidata._formatQualifiers(claims[1], 'P577')
					extraConf.titolo = {}
					for i, claim in ipairs(claims) do
						extraConf.titolo[i] = mWikidata._formatQualifiers(claim, 'P1476') or mWikidata._formatQualifiers(claim, 'P1810') or mWikidata._formatQualifiers(claim, 'P742') -- titolo o "indicato come" o pseudonimo
						if extraConf.titolo[i] then Nqualtitoli = Nqualtitoli + 1 end
					end
					-- Uno o più url ed eventuali qualificatori per distinguerli
					url = {}
					for i, claim in ipairs(claims) do
						if claim.qualifiers then
							local qualifierIds = {}
							if linkConf.multi then
								qualifierIds = mw.text.split(linkConf.multi:gsub('%s', ''), ',')
								for _, qualifierId in ipairs(qualifierIds) do
									if claim.qualifiers[qualifierId] then
										local formattedQualifier = mWikidata._formatQualifiers(claim, qualifierId, { nq = '1', formatting = 'raw' })
										if formattedQualifier then
											if not qualifier then qualifier = {} end
											qualifier[i] = mw.wikibase.getLabel(formattedQualifier)
											break
										end
									end
								end
							end
							for _, v in ipairs(qualifierIds) do qualifierIds[v] = true end
							local altriQualNoti = {P407 = true, P50 = true, P2093 = true, P1476 = true, P1810 = true, P742 = true, P577 = true, P478 = true, P304 = true, P813 = true}
							for qualifierId in pairs(claim.qualifiers) do
								if qualifierIds[qualifierId] ~= true and altriQualNoti[qualifierId] ~= true then
									table.insert(self.categories, string.format('[[%sCategoria:%s]]', self.catColon, catUnknownQual))
									break
								end
							end
						end
						-- crea l'url
						claim = mWikidata._formatStatement(claim)
						if linkConf.url then
							-- se proprietà di tipo id, il valore viene sotituito a "$1"
							claim = mw.message.newRawMessage(linkConf.url, claim):plain()
						end
						table.insert(url, claim)
					end
					-- nome sito, di default il dominio estratto dall'url
					extraConf.sito = linkConf.sito or getDomain(linkConf.url)
					-- Creazione dell'oggetto collegamento esterno, con l'url (o gli url) e gli altri dati raccolti
					table.insert(ret[groupName], ExtLink:new(url, qualifier, linkConf, extraConf, self.from))
					-- categoria per proprietà letta; se multipla e indistinguibile, usa categoria di avviso
					local tail = #url > 1 and linkConf.url and (qualifier == nil or #qualifier ~= #url) and (Nqualtitoli < #url - 1) and
							catMultiSenzaQual or catLetta
					table.insert(self.categories, string.format('[[%sCategoria:%s%s]]', self.catColon, linkConf.pid, tail))
					-- per verificare se un sito è ripetuto nel gruppo
					groupSites[groupName][extraConf.sito] = (groupSites[groupName][extraConf.sito] or 0) + 1
					-- conteggio complessivo dei collegamenti
					self.numExtLinks = self.numExtLinks + 1
				end
			end
		end
	end
	-- verifica se un sito è ripetuto nel gruppo
	for _, groupName in ipairs(orderedGroupNames) do
		for _, extLink in ipairs(ret[groupName]) do
			-- necessaria la disambiguazione (più URL con lo stesso dominio nel gruppo),
			-- se configurata tramite "sitodis" nella configurazione.
			if groupSites[groupName][extLink.extraConf.sito] > 1 then
				extLink.sitodis = extLink.linkConf.sitodis
			end
		end
	end
	-- categorie di servizio sul numero di link
	local catnumero
	if self.numExtLinks == 0 then
		catnumero = catEmpty
	elseif self.numExtLinks > MOLTI_LINK then
		if self.numExtLinks > MOLTI_LINK_2 then catnumero = catMoltiLink2
		else catnumero = catMoltiLink end
	end
	if catnumero then
		table.insert(self.categories, string.format('[[%sCategoria:%s]]', self.catColon, catnumero))
	end
	return ret
end

-- Formatta i collegamenti esterni come elenco puntato.
--
-- @param {table} [groupNames]
-- @return {string}
function LinksManager:_formatList(groupNames)
	local formattedLinks = {}
	for _, groupName in ipairs(groupNames) do
		for _, extLink in ipairs(self.extLinks[groupName]) do
			table.insert(formattedLinks, extLink:getListItem())
		end
	end
	return table.concat(formattedLinks, '\n')
end

-- Restituisce tutti i collegamenti esterni formattandoli come elenco puntato
--
-- @return {string}
function LinksManager:getList()
	local categories, links
	-- categorie di servizio
	categories = (mw.title.getCurrentTitle().namespace == 0 or self.debug) and
				 table.concat(self.categories) or ''
	-- collegamenti
	links = self:_formatList(orderedGroupNames)
	return links .. categories
end

-- =============================================================================
--                            Funzioni esportate
-- =============================================================================

local p = {}

-- Funzioni di utilità per il manuale, danno la soglia di attenzione sul n° di link.
function p.threshold(frame)
	return MOLTI_LINK
end
function p.threshold2(frame)
	return MOLTI_LINK_2
end

-- Funzione di utilità per il manuale, restituisce un elenco
-- delle proprietà supportate, divise per gruppo.
function p.properties(frame)
	local res = {}
	local cfg = readConfig()
	table.sort(orderedGroupNames)
	for _, groupName in ipairs(orderedGroupNames) do
		local wdLinks = {}
		for _, linkConf in ipairs(cfg[groupName]) do
			local wdLink = string.format('<tr><td>[[d:Property:%s|%s (%s)]]</td><td>%s</td><td>%s</td></tr>',
				linkConf.pid, mWikidata._getLabel({ linkConf.pid }), linkConf.pid, linkConf.url or '', linkConf.cid or '')
			table.insert(wdLinks, wdLink) 
		end
		local group = frame.args[1] == 'modulo' and
			string.format('* [[Modulo:Collegamenti esterni/%s]] (%s)', groupName, #wdLinks) or
			mw.getCurrentFrame():expandTemplate {
				title = 'Cassetto',
				args = {
					titolo = string.format('[[Modulo:Collegamenti esterni/%s|%s]] (%s)', groupName, groupName, #wdLinks),
					testo = '<table class="wikitable sortable plainlinks"><tr><th>Proprietà</th><th>Formato URL</th><th>cid</th></tr>' .. table.concat(wdLinks, '') .. '</table>'
				}
			}
		table.insert(res, group)
	end
	return table.concat(res, '\n')
end

-- Funzione di utilità per il manuale, verifica l'assenza di proprietà duplicate.
function p.checkdup(frame)
	local ids, res = {}, {}
	local cfg = readConfig()
	for _, groupName in ipairs(orderedGroupNames) do
		for _, linkConf in ipairs(cfg[groupName]) do
			if ids[linkConf.pid] then
				table.insert(res, linkConf.pid)
			else
				ids[linkConf.pid] = true
			end
		end
	end
	return #res == 0 and 'nessun duplicato' or
		string.format('<span class="error">%s</span>', table.concat(res, ', ')) 
end

-- Funzione per l'utilizzo da un altro modulo.
function p._main(args)
	return LinksManager:new(args):getList()
end

-- Funzione per il template {{Collegamenti esterni}}.
function p.main(frame)
	return p._main(getArgs(frame, { parentOnly = true }))
end

return p