Modul:Collegamenti esterni

Izvor: Wikipedija
Prijeđi na navigaciju Prijeđi na pretragu

Dokumentaciju za ovaj modul možete napraviti na stranici Modul:Collegamenti esterni/dok

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

require('Modul:No globals')

local getArgs = require('Modul:Arguments').getArgs
local mDelink = require('Modul:Delink')
local mWikidata = require('Modul:Wikidata')
local mCitazione = require('Modul:Citazione')
local mEditAtWikidata = require('Modul:Modifica su Wikidata')
-- Permette di definire l'ordine di visualizzazione dei vari gruppi
local orderedGroupNames = {
	'Ufficiali', 'Politica', 'Calcio', 'Sport', 'Software',
	'Videogiochi', 'Fumetti', 'Cinema', 'Musica', 'Biografie', 'Letteratura'
}
-- Tabella per contenere la configurazione delle varie sottopagine
local cfg = {}
-- Numero di collegamenti esterni oltre il quale sono raggruppati
local THRESHOLD_GROUPED_LIST = 12
-- Categorie di servizio
local catGroupedList = 'Voci con template Collegamenti esterni e collegamenti raggruppati'
local catEmpty = 'Voci con template Collegamenti esterni senza dati da Wikidata'

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

-- Legge la configurazione delle sottopagine.
local function readConfig()
	for _, groupName in ipairs(orderedGroupNames) do
		cfg[groupName] = mw.loadData('Modul:Collegamenti esterni/' .. groupName)
	end
end

-- Restituisce il titolo della pagina corrente.
--
-- @param {string} from
-- @return {string}
local function getCurrentTitle(from)
	-- utilizza l'etichetta dell'elemento Wikidata invece di mw.title
	-- perché le parentesi possono far parte del titolo.
	return mw.wikibase.label(from)
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à istanza di (P31) uno degli elementi specificati.
--
-- @param {table} [entityIds]
-- @param {string} from
-- @return {boolean}
local function checkInstance(entityIds, from)
	local args = { from = from }
	for _, entityId in ipairs(entityIds) do
		table.insert(args, entityId)
	end
	return mWikidata._instanceOf(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} linkConf - la configurazione per questo collegamento esterno
-- @param {string} from - entityId se diverso da quello collegato alla pagina corrente
-- @return {table} un nuovo oggetto ExtLink
function ExtLink:new(url, linkConf, from)
	local self = {}
	setmetatable(self, { __index = ExtLink })

	self.url = url
	self.linkConf = linkConf
	self.from = from

	return self
end

-- Restituisce il parametro titolo per citaweb.
--
-- @return {string}
function ExtLink:_getTitolo()
	local currTitle = getCurrentTitle()
	return self.from and mw.wikibase.label(self.from) or 
		   (self.linkConf.titolo and self.linkConf.titolo:gsub('$1', currTitle) or currTitle)
end

-- Restituisce il parametro posttitolo per citaweb.
--
-- @return {string}
function ExtLink:_getPostTitolo()
	local ret
	if #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 citaweb
-- 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
	-- aggiunge la disambiguazione se c'è più di un collegamento esterno con la stesso sito
	return self.sitodis and string.format('%s (%s)', sito, self.sitodis) or sito
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.citaweb({
				url = mWikidata._formatStatement(claim),
				titolo = self.linkConf.titolo:gsub('$1', currTitle),
				lingua = table.concat(langs, ' ')
			})
		table.insert(formattedLinks, '* ' .. formattedLink ..
					 mEditAtWikidata._showMessage({ pid = self.linkConf.pid, qid = self.from }))
	end
	return table.concat(formattedLinks, '\n')
end

-- Setta come necessaria la disambiguazione del sito (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

-- Formatta il collegamento esterno come elemento di un elenco puntato.
--
-- @return {string}
function ExtLink:getListItem()
	local icon = self.linkConf.icona == 'video' and
			'[[File:35mm film frames.svg|16px|link=|alt=Filmato]]' or ''
	-- se è specificato l'URL di formattazione è una
	-- proprietà di tipo "identificativo esterno" altrimenti di tipo URL
	if self.linkConf.url then
		return '* ' .. icon .. mCitazione.citaweb({
				url = self.url[1],
				titolo = self:_getTitolo(),
				posttitolo = self:_getPostTitolo(),
				sito = self:_getSito(),
				editore = self.linkConf.editore,
				lingua = self.linkConf.lingua
			}) .. mEditAtWikidata._showMessage({ pid = self.linkConf.pid, qid = self.from })
	else
		return self:_formatPropertyURL()
	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()) or ret
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 })

	readConfig()
	self.numExtLinks = 0
	self.categories = {}
	self.catColon = ''
	-- la pagina dei test utilizza uno stub del modulo Wikidata
	if mw.title.getCurrentTitle().prefixedText ==
	   'Razgovor o modulu:Collegamenti esterni/test' then
		self:_setStubWikidata(args.stubwd)
	end
	self.extLinks = self:_getExtLinks(args.from)

	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.
--
-- @param {string} from
-- @return {table}
function LinksManager:_getExtLinks(from)
	local ret, groupSites = {}, {}
	for _, groupName in ipairs(orderedGroupNames) do
		groupSites[groupName] = {}
		ret[groupName] = {}
		for _, linkConf in ipairs(cfg[groupName]) do
			if not linkConf.istanza or checkInstance(linkConf.istanza, from) then
				local url = mWikidata._getProperty({ linkConf.pid, from = from, pattern = linkConf.url }, true)
				if url then
					table.insert(ret[groupName], ExtLink:new(url, linkConf, from))
					-- categorie
					table.insert(self.categories, string.format('[[%sKategorija:%s letta da Wikidata]]',
								 self.catColon, linkConf.pid))
					-- per verificare se un sito è ripetuto nel gruppo
					local sito = linkConf.sito and mDelink._main({ linkConf.sito }) or getDomain(linkConf.url)
					groupSites[groupName][sito] = (groupSites[groupName][sito] or 0) + 1
					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
			local linkConf = extLink.linkConf
			local sito = linkConf.sito and mDelink._main({ linkConf.sito }) or getDomain(linkConf.url)
			if groupSites[groupName][sito] > 1 then
				extLink:needSitoDis()
			end
		end
	end
	-- categorie di servizio
	if self.numExtLinks == 0 then
		table.insert(self.categories, string.format('[[%sKategorija:%s]]', self.catColon, catEmpty))
	elseif self.numExtLinks > THRESHOLD_GROUPED_LIST then
		table.insert(self.categories, string.format('[[%sKategorija:%s]]', self.catColon, catGroupedList))
	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

-- 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
			table.insert(formattedGroups, string.format("* ''Banche dati %s'': %s",
				mw.ustring.lower(groupName),
				table.concat(formattedLinks, '<span style="font-weight:bold;">&nbsp;·</span> ')))
		end
	end
	return table.concat(formattedGroups, '\n')
end

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

	-- categorie
	categories = (mw.title.getCurrentTitle().namespace == 0 or self.debug) and
				 table.concat(self.categories) or ''
	-- i siti web ufficiali sono sempre visualizzati uno per riga
	olinks = self:_formatList({ 'Ufficiali' })
	-- 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

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

local p = {}

-- Funzione di utilità per il manuale, restituisce la soglia THRESHOLD_GROUPED_LIST.
function p.threshold(frame)
	return THRESHOLD_GROUPED_LIST
end

-- Funzione di utilità per il manuale, restituisce un elenco
-- delle proprietà supportate, divise per gruppo.
function p.properties(frame)
	local res = {}
	readConfig()
	table.sort(orderedGroupNames)
	for _, groupName in ipairs(orderedGroupNames) do
		local wdLinks = {}
		for _, linkConf in ipairs(cfg[groupName]) do
			local wdLink = string.format('* [[d:Property:%s|%s (%s)]]',
				linkConf.pid, mw.wikibase.label(linkConf.pid), linkConf.pid)
			table.insert(wdLinks, wdLink) 
		end
		local group = frame.args[1] == 'modulo' and
			string.format('* [[Modul:Collegamenti esterni/%s]] (%s)', groupName, #wdLinks) or
			mw.getCurrentFrame():expandTemplate {
				title = 'Cassetto',
				args = {
					titolo = string.format('%s (%s)', groupName, #wdLinks),
					testo = table.concat(wdLinks, '\n')
				}
			}
		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 = {}, {}
	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