Modulo:Cronologia valutazioni: differenze tra le versioni

Da Wikipedia, l'enciclopedia libera.
Vai alla navigazione Vai alla ricerca
Contenuto cancellato Contenuto aggiunto
m +width
icona per quando le proposte per la rubrica sono state respinte (vedi discussione)
Riga 470: Riga 470:
else
else
ret[#ret+1] = " è stata proposta per la rubrica ''[[Wikipedia:Lo sapevi che|Lo sapevi che]]'', ma è stata respinta"
ret[#ret+1] = " è stata proposta per la rubrica ''[[Wikipedia:Lo sapevi che|Lo sapevi che]]'', ma è stata respinta"
icon = 'LoSapeviCheEsclusa'
end
end
incipit_done = true
incipit_done = true

Versione delle 13:49, 2 apr 2017

Modulo che implementa il template {{Cronologia valutazioni}}.

Ha una sottopagina di configurazione: Modulo:Cronologia valutazioni/Configurazione.


-- Modulo per implementare il template Cronologia valutazioni
-- copiato senza vergogna da modulo:Navbox

-- Configurazione
local cfg = mw.loadData("Modulo:Cronologia valutazioni/Configurazione")

local Date = require('Modulo:Data').Date
local errors = {}
local we_got_error = false

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

local function dump(t, ...)
	local args = {...}
	for _, s in ipairs(args) do
		table.insert(t, s)
	end
end

-- Controlla se il nome dell'argomento è valido, altrimenti restituisce errore
local function ValidArg(name)
	local ret = cfg.HistoryBoxArgs[name]
	if not ret then
		local _, _, base_name, id = mw.ustring.find(name, "^(%a+)(%d+)$")
		if cfg.HistoryBoxNumberedArgs[base_name] and id then
			ret = cfg.HistoryBoxNumberedArgs[base_name]..id
		else
			dump(errors, "Argomento non riconosciuto: '" .. name .. "'")
		end
	end
	return ret
end

-- Ritorna gli argomenti passati al modulo, scartando quelli senza nome,
-- quelli contenenti stringhe vuote e i non riconosciuti.
local function getArgs(frame, isSubgroup)
	local ret = {}
	for k, v in pairs(frame:getParent().args) do
		if type(k) == "string" and v ~= "" then
			k = ValidArg(k)
			if k then
				ret[k] = v
			end
		end
	end
	return ret
end

-- Ritorna gli ID degli argomenti azioneN presenti
local function getListIds(args)
	local ret = {}

	for k, v in pairs(args) do
		local id = k:match("^azione(%d+)$")
		if id then table.insert(ret, tonumber(id)) end
	end
	table.sort(ret)
	return ret
end

-- Verica se si verifica una condizione di errore
-- errors_check: lista di array con le condizioni da controllare, questi hanno la struttura:
----- condition: il valore (vero o falso) da controllare
----- checks: lista di stati da controllare
----- msg: messaggio di errore se gli stati hanno tutti il valore uguale a condition
-- restituisce nil se non ci sono errori, altrimenti una stringa con un errore per riga
local function checkErrors(errors_check, status, errors_msg)
	if errors_check == nil then return end
	for _, check in ipairs(errors_check) do
		local check_result = true
		for _, par_to_test in ipairs(check.checks) do
			check_result = check_result and (status[par_to_test] == check.condition)
		end
		if check_result then errors_msg[#errors_msg+1] = check.msg  end
	end
end

local function wrap_errors(errors_msg)
	if  #errors_msg > 0 then
		for i, e in ipairs(errors_msg) do
			errors_msg[i] =  '<div class="error">' .. e .. '</div>'
		end
		we_got_error = true
		return table.concat(errors_msg)
	else
		return ''
	end
end

-------------------------------------------------------------------------------
--							 Classe HistoryBox
-------------------------------------------------------------------------------

local HistoryBox = {}

function HistoryBox:new(args)
	local self = {}
	setmetatable(self, { __index = HistoryBox,
						 __tostring = function(t) return self:__tostring() end })
	self.args = args
	-- costruzione table
	self.status = {}
	self.actions = {}
	self.counters = {}
	self.categories = {}
	self.manca_data = false
	self.manca_codice = false
	for k,v in pairs(cfg.status_toggle) do
		self.status[k] = v
	end
	self.current_title = mw.title.getCurrentTitle()
	if self.current_title.namespace ~= 1 then
		self.page = 'pagina'
		self.name = self.args['debug_name'] or self.current_title.subjectNsText..':'..self.current_title.text
	else
		self.page = 'voce'
		self.name = self.args['debug_name'] or self.current_title.text
	end
	self.processedArgs = {}
	self.listIds = getListIds(self.args)
	self:__PreprocessArgs()
	self:__SetupBaseNode()
	self:__infoDiv()
	if #self.listIds == 0 then
		errors[#errors+1] = 'Template Cronologia valutazioni vuoto.'
	elseif #self.listIds ~= 1 then
		self:__RowContent() 
	end
	if  self.current_title.namespace == 1 then
		self:__SetCategories()
	end
	return self
end

function HistoryBox:__tostring()
	local categorie = table.concat(self.categories)
	if debug and categorie ~= '' and self.current_title.namespace ~= 1 then
		categorie = '<br>Categorie: ' .. table.concat(self.categories, ", ") 
	end
	local ret = tostring(self.BaseNode) .. wrap_errors(errors) .. categorie
	if we_got_error and not(self.args['no_categoria_errore']) then
		ret = ret .. '[[Categoria:Errori di compilazione del template Cronologia valutazioni]]'
	end
	return ret
end

function HistoryBox:__PreprocessArgs()
	local currentTitle = mw.title.getCurrentTitle()
	for _, Id in ipairs(self.listIds) do
		local row = { }
		local action = mw.ustring.upper(self.args['azione' .. Id] or '')
		action = cfg.action_alias[action] or action
		local row_action = cfg.actions[action]
		if row_action == nil then
			dump(errors, "Non riconosciuta 'azione" .. Id .. " = " .. action .. "'")
		else
			-- leggo i dati della riga
			local date = self.args['data' .. Id]
			date = date and Date:newDMY(date)
			local collegamento = self.args['collegamento' .. Id]
			local codice = self.args['codice' .. Id]
			local name = self.args['nome' .. Id] or self.name
			local commento = self.args['commento' .. Id]
			if commento then
				row['comment'] = "'''commento''': ''" .. commento .. "''" 
			end
			local errors_msg = {}
			checkErrors(row_action['check_errors'], self.status, errors_msg)
			local msg, link_label
			-- verifico che l'esito esista e lo gestisco
			local result = mw.ustring.upper(self.args['esito' .. Id] or '')
			if result == '' and row_action['default_result'] then
				result = row_action['default_result']
			elseif row_action['result_alias'] then
				result = row_action.result_alias[result] or result
			end
			local row_result = row_action.valid_result[result]
			if row_result then
				-- controllo se le condizioni sono tutte soddisfatte
				checkErrors(row_result['check_errors'], self.status, errors_msg)
				-- setto le variabili relative all'azione
				if row_result['set'] then
					for _,to_set in ipairs(row_result.set) do
						self.status[to_set[2]] = to_set[1]
					end
				end
				msg = row_result['msg']
				link_label = row_result['link_label']
				row['icon'] = row_result['icon']
			else
				if not(row_action['no_result']) then
					local default_result = row_action['default_result'] or 'xxx'
					local list_result = {}
					for kr,vr in pairs(row_action.valid_result) do
						if kr == default_result then
							list_result[#list_result+1] = "<b>" .. mw.ustring.lower(kr) .. "</b>"
						else
							list_result[#list_result+1] = mw.ustring.lower(kr)
						end
					end
					dump(errors, "Esito '" .. result .. "' non riconosciuto, esiti validi: " .. table.concat(list_result, "/"))
				end
				row['result'] = '-'
			end
			msg = msg or row_action['msg']
			link_label = link_label or row_action['link_label']
			row['icon'] = row['icon'] or row_action['icon']
			
			-- analizzo casi specifici
			
			-- per le rimozioni da riconoscimento qualità è necessario indagare quale fosse il riconoscimento per cambiare i giusti "status"
			if action == "RRQ" then
				if result == "RIMOSSA" then
					if self.status.is_vetrina then
						self.status.is_vetrina = false
						self.status.removed_vetrina = true
						row['icon'] = 'VetrinaEsclusa'
					elseif self.status.is_vdq then
						self.status.is_vdq = false
						self.status.removed_vdq = true
						row['icon'] = 'VdqEsclusa'
					end
				elseif result == "MANTENUTA" or result == "ANNULLATA" then
					if self.status.is_vetrina then
						row['icon'] = 'Vetrina'
					elseif self.status.is_vdq then
						row['icon'] = 'Vdq'
					end
				end
			end
			-- per le valutazioni VdQ scadute generalmente non c'è pagina a cui linkare
			if action == "OLDVDQ" and result == "SCADUTA" then
				collegamento = collegamento or "no"
			end
			-- per le procedure di cancellazione aggiungo in automatico dettagli sul tipo di procedura
			if action == "PDC" and (result == "MANTENUTA" or result == "CANCELLATA") then
				-- per le primissime procedure si applicava il veto
				if date and date < Date:new('2004/10/01') then
					if result == 'CANCELLATA' then
						msg = msg..' in seguito a decisione consensuale.'
					else
						msg = msg..' in seguito al veto di uno o più utenti.'
					end
				else
					local yes = tonumber(self.args['si' .. Id])
					local no = tonumber(self.args['no' .. Id])
					if yes and no then
						msg = msg..' in seguito a voto della comunità con risultato <span style="color:red;">' .. yes .. '</span> a <span style="color:green;">' .. no .. '</span>.'
						link_label = "votazione"
						if date then
							local cambio_quorum1 = Date:new('2005/12/30')
							local cambio_quorum2 = Date:new('2015/04/27')
							if result == "MANTENUTA" and yes >= no*2 and yes+no >= 5 and (yes >= 7 or date < cambio_quorum1) and (yes+no >= 10 or date >= cambio_quorum2 or date < cambio_quorum1) then
								errors_msg[#errors_msg+1] = "Risultato della PDC discorde con i voti dati: la voce avrebbe dovuto essere cancellata."
							elseif result == "CANCELLATA" and (yes < no*2 or (yes < 7 and date >= cambio_quorum2)) then
								-- il quorum per le procedure precedenti al 2015 non è considerato: comprendeva anche gli astenuti
								errors_msg[#errors_msg+1] = "Risultato della PDC discorde con i voti dati: la voce avrebbe dovuto essere mantenuta."
							end
						end
					else
						msg = msg..' in seguito a decisione consensuale.'
					end
				end
				-- messaggio che avvisa di non proporre nuovamente la voce per la cancellazione nel caso ne sia stata deciso recentemente il mantenimento
				if result == "MANTENUTA" and date then
					local scadenza = date:addDays(90)
					if Date:new() < scadenza then
						msg = msg .. ' Non può essere riproposta in cancellazione fino al ' .. scadenza:getDateString() ..
							  ', a meno di motivazioni radicalmente diverse o rilevanti novità.'
					end
				end
			end
			if action == 'PDC' and date and date < Date:new('2005/04/19') and not collegamento then
				collegamento = 'no'
			end
			-- per le vecchie valutazioni per la vetrina si distinguono le votazioni dalle valutazioni in base alla data
			if (action == "OLDSRQ" or action == "OLDRRQ") and date then
				if date <= Date:new('2009/02/01') then
					link_label = "votazione"
				end
			end
			
			-- genero i dati di output rimanenti
			
			-- link alla versione
			if codice and codice ~= "no" then
				local etichetta
				if date then
					etichetta = date:getDateString()
				else
					self.manca_data = true
					etichetta = "versione "..codice
				end
				row['date'] = '[' .. tostring(mw.uri.fullUrl( name, {oldid=codice} )) .. " " .. etichetta .. "]"
			elseif codice == 'no' and date then
				row['date'] = '<abbr title="Nella cronologia della voce non è reperibile la versione relativa a questa procedura">' .. date:getDateString() .. '</abbr>'
			elseif date then
				self.manca_codice = true
				row['date'] = date:getDateString()
			else
				self.manca_data = true
				row['date'] = "-"
			end
			-- aggiorno il counter associato all'azione
			if collegamento ~= "no" then
				if self.counters[row_action.counter] then
					self.counters[row_action.counter] = self.counters[row_action.counter] + 1
				else
					self.counters[row_action.counter] = 1
				end
			end
			-- Tenta di generare il link di default se collegamento non è definito 
			if collegamento == nil then
				if row_action['default_position'] then
					if row_action['use_date_for_position'] then
						if date and action == "LSC" then
							if date >= Date:new('2012/01/01') then
								local month, year = string.match(self.args['data' .. Id], "(%a+) (%d+)")
								month = month and mw.language.getContentLanguage():ucfirst(month) or nil
								collegamento = mw.message.newRawMessage( row_action.default_position,
																		 {name, month, year} ):plain()
							else
								local link_crono
								if date >= Date:new('2010/03/04') then
									link_crono = 'Lo_sapevi_che/Valutazione'
								else
									link_crono = 'Lo_sapevi_che'
								end
						 		row['consiglio']= "Le procedure prima del 2012 non venivano archiviate, perciò possono essere trovate solo nella [http://it.wikipedia.org/w/index.php?title=Wikipedia:" .. link_crono .. "&action=history cronologia] della pagina di valutazione."
							end
						-- per le valutazioni LSC non c'è collegamento automatico senza data, perciò il template aiuta l'utente a trovare la valutazione manualmente
						elseif action == "LSC" then
						 	row['consiglio']= "La procedura si può trovare nell'[[Wikipedia:Lo sapevi che/Valutazione/Archivio|archivio]], oppure nella [http://it.wikipedia.org/w/index.php?title=Wikipedia:Lo_sapevi_che/Valutazione&action=history cronologia] della pagina di valutazione."
						end
					else
						if self.counters[row_action.counter] == 1 then
							collegamento = mw.message.newRawMessage( row_action.default_position[1], {name} ):plain()
						else
							collegamento = mw.message.newRawMessage( row_action.default_position[2],
																	 {name, self.counters[row_action.counter]} ):plain()
						end
					end
				end
			elseif collegamento == "no" then
				collegamento = nil
			end
			row['msg'] = msg
			row['collegamento'] = collegamento
			link_label = link_label or "discussione"
			row['label'] = link_label
			row['errors_msg'] = errors_msg
			table.insert(self.processedArgs, row)
		end
	end
end

function HistoryBox:__SetupBaseNode()
	self.BaseNode = mw.html.create("h2")
		:cssText("border: none; margin-left: 8%; margin-bottom: 0.4em")
		:done()
	:tag("table")
		:addClass("cronoval")
		:addClass("noprint") -- serve a qualcosa? tanto va nelle discussioni
		:cssText("margin: 5px 10%; width: 80%; border: thin solid #a7d7f9; background-color: #EAF7ED;")
	if #self.listIds ~= 1 then
		self.BaseNode:addClass("mw-collapsible mw-collapsed") 
	end
end

function HistoryBox:__infoDiv()
	local stato_descriptor, commento, consiglio, icon = self:__getSummaryInfo()
	self.BaseNode:tag("tr")
		:addClass("cronoval_h")
		:tag("td")
			:cssText("width:52px")
			:css("text-align", "center")
			:wikitext("[[File:" .. (cfg.icons[icon] or cfg.icons['default']) .. "|40px]]")
			:done()
		:tag("td")
			:wikitext(stato_descriptor)
			:tag ("div")
				:cssText ("font-size: 90%;")
				:wikitext (commento)
				:done ()
			:tag ("div")
			   	:wikitext (consiglio)
end

function HistoryBox:__getSummaryInfo()
	local ret = {}
	if #self.processedArgs == 1 then
		local row = self.processedArgs[1]
		for _, e in ipairs(row['errors_msg']) do
			errors[#errors+1] = e
		end
		if row['date'] ~= "-" then
			ret = {'In data <span class="plainlinks">'..row['date'].."</span>"}
		end
		ret[#ret + 1] = mw.message.newRawMessage (row['msg'], {"la "..self.page.." <b>"..self.name.."</b>"}):plain()
		local ret_consiglio= ""
		if row['collegamento'] then
			ret_consiglio= "Consulta la '''[["..row['collegamento'].."|pagina della "..row['label'].."]]''' per eventuali pareri e suggerimenti."
		elseif row['consiglio'] then
			ret_consiglio= row['consiglio'] 
		end
		return table.concat(ret, " "), row['comment'], ret_consiglio, row['icon']
	else
		local s = self.status
		local c = self.counters
		c['Vetrina'] = (c['OLDSRQ'] or 0) + (c['Vetrina'] or 0)
		local incipit_done = true
		local icon
		ret[1] = '<b>$1</b>'
		if s.is_vetrina then
			ret[#ret+1] = ' è una [[Wikipedia:Vetrina|voce in vetrina]]'
			icon = 'Vetrina'
		elseif s.is_vdq then
			ret[#ret+1] = ' è una [[Wikipedia:Voci di qualità|voce di qualità]]'
			icon = 'Vdq'
			if s.removed_vetrina then
				 ret[#ret+1] = ', in precedenza è stata in vetrina'
			end
		elseif s.removed_vetrina then
			ret[#ret+1] = ' è  stata una [[Wikipedia:Vetrina|voce in vetrina]]'
			icon = 'VetrinaEsclusa'
		elseif s.removed_vdq then
			ret[#ret+1] = ' è  stata una [[Wikipedia:Voci di qualità|voce di qualità]]'
			icon = 'VdqEsclusa'
		elseif c['SRQ'] then
			ret[#ret+1] = ' è stata segnalata per un [[Wikipedia:Riconoscimenti di qualità/Segnalazioni|riconoscimento di qualità]]'
			if c['SRQ'] + c['Vetrina'] + (c['Vdq'] or 0) == 1 then
				ret[#ret+1] = ', ma non ha superato la valutazione'
			else
				ret[#ret+1] = ', ma non ha superato le valutazioni'
			end
			icon = 'QualitaEsclusa'
		elseif c['Vetrina'] >= 1 and c['Vdq'] then
			ret[#ret+1] = ' non ha superato le valutazioni per essere giudicata una [[Wikipedia:Vetrina|voce in vetrina]] o [[Wikipedia:Vetrina|di qualità]]'
			icon = 'QualitaEsclusa'
		elseif c['Vetrina'] >= 1 then
			ret[#ret+1] = ' non ha superato la valutazione per essere inserita in [[Wikipedia:Vetrina|vetrina]]'
			icon = 'VetrinaEsclusa'
		elseif c['Vdq'] then
			ret[#ret+1] = ' non ha superato la valutazione per essere giudicata una [[Wikipedia:Vetrina|voce di qualità]]'
			icon = 'VdqEsclusa'
		else
			incipit_done = false
		end
		if c['Vaglio'] then
			if incipit_done then
				ret[#ret+1] = '. La voce'
			end
			ret[#ret+1] = ' è stata sottoposta a '
			if c['Vaglio'] > 1 then
				ret[#ret+1] = 'più procedure di [[Wikipedia:Vaglio|vaglio]]'
			else
				ret[#ret+1] = 'una procedura di [[Wikipedia:Vaglio|vaglio]]'
			end
			incipit_done = true
		end
		if c['Lo sapevi che'] then
			if incipit_done then
				ret[#ret+1] = '. La voce'
			end
			if s.was_LSC then
				ret[#ret+1] = " è comparsa nella rubrica ''[[Wikipedia:Lo sapevi che|Lo sapevi che]]''"
				icon = icon or "LoSapeviChe"
			else
				ret[#ret+1] = " è stata proposta per la rubrica ''[[Wikipedia:Lo sapevi che|Lo sapevi che]]'', ma è stata respinta"
				icon = 'LoSapeviCheEsclusa'
			end
			incipit_done = true
		end
		local ret_avviso = ""
		if c['Cancellazione'] then
			if incipit_done then
				ret[#ret+1] = '. La '..self.page
			end
			ret[#ret+1] = ' è stata sottoposta a'
			if c['Cancellazione'] > 1 then
				ret[#ret+1] = ' più procedure di [[Wikipedia:Pagine da cancellare|cancellazione]]'
			else
				ret[#ret+1] = ' una procedura di [[Wikipedia:Pagine da cancellare|cancellazione]]'
			end
			if s.was_deleted and not s.is_deleted then
				ret[#ret+1] = ', ma successivamente è stata ripristinata'
			elseif not s.is_deleted then
				if c['Cancellazione'] > 1 then
					ret[#ret+1] = ', che non sono state accolte'
				else
					ret[#ret+1] = ', che non è stata accolta'
				end
			end
			incipit_done = true
		end
		if incipit_done then
			ret[#ret+1] = '.'
			return mw.message.newRawMessage(table.concat(ret), {self.name}):plain(), nil,
					"Consulta le varie procedure di valutazione per eventuali pareri e suggerimenti.", (icon or "default")
		end
		return ''
	end
end

function HistoryBox:__RowContent()
	local listIds, altStyle
	-- crea la tabella che contiene i dati collassati
	local dataTableContent =
		self.BaseNode:tag("tr")
			:tag("td")
				:attr("colspan", "2")
				:tag("table")
					:addClass("cronoval_elenco")
					:cssText("clear: both; width: 100% !important; border-collapse: collapse;") -- l'important è per la versione mobile
	for row_number, row in ipairs(self.processedArgs) do
		local row_element = dataTableContent:tag("tr")
			:cssText("background-color: white; border: thin solid #D8D8D8;")
		local icon = ''
		if row['icon'] then
			icon = '[[File:' .. cfg.icons[row.icon] .. "|20px]]"end
		local conclusione= ""
		if row.collegamento then
			conclusione= " '''[[" .. row.collegamento .. "|Vedi " .. row.label .. "]]'''"
		elseif row.consiglio then
			conclusione= " " .. row.consiglio end
		local data_element = row_element
		:tag("td")
			:cssText("width: 22px; padding:0 2px;")
			:wikitext(icon)
			:done()
		:tag("td")
			:addClass("plainlinks")
			:cssText("text-align: right; padding-right: 0.3em; width: 10em; vertical-align: top;")
			:wikitext(row.date..":")
			:done()
		:tag("td")
			:wikitext(mw.message.newRawMessage (row.msg, {"la "..self.page}):plain() .. conclusione)
		if row['comment'] then
			data_element
				:tag('div')
				:cssText("font-size: 90%;")
				:wikitext(row.comment)
		end
		if row['errors_msg'] then
			data_element:tag("div"):wikitext(wrap_errors(row['errors_msg']))
		end
	end
end

function HistoryBox:__SetCategories()
	-- Aggiunge le categorie per la pagina secondo il suo stato
	if self.status.tried_qualita then
		self.categories[#self.categories+1] = '[[Categoria:Voci escluse da un riconoscimento di qualità]]'
	end
	if self.status.tried_vetrina then
		self.categories[#self.categories+1] = '[[Categoria:Voci escluse dalla vetrina]]'
	end
	if self.status.tried_vdq then
	   self.categories[#self.categories+1] = '[[Categoria:Voci escluse dalle voci di qualità]]'
	end
	if self.status.tried_LSC then
		self.categories[#self.categories+1] = '[[Categoria:Voci scartate nella rubrica Lo sapevi che]]'
	end
	if self.status.removed_vetrina then
		self.categories[#self.categories+1] = '[[Categoria:Voci rimosse dalla vetrina]]'
	end
	if self.status.removed_vdq then
		self.categories[#self.categories+1] = '[[Categoria:Voci rimosse dalle voci di qualità]]'
	end 
	if self.status.scaduta_vdq then
	   self.categories[#self.categories+1] = '[[Categoria:Segnalazioni voci di qualità scadute]]'
	end
	if self.counters['Vaglio'] then
		self.categories[#self.categories+1] = '[[Categoria:Voci vagliate]]'
	end
	if self.status.was_LSC then
		self.categories[#self.categories+1] = '[[Categoria:Voci pubblicate nella rubrica Lo sapevi che]]'
	end
	if self.manca_data and not self.args['no_categoria_errore'] then
		self.categories[#self.categories+1] = '[[Categoria:Template Cronologia valutazioni con parametro data non compilato]]'
	end
	if self.manca_codice and not self.args['no_categoria_errore'] then
		self.categories[#self.categories+1] = '[[Categoria:Template Cronologia valutazioni con parametro codice non compilato]]'
	end
end

-------------------------------------------------------------------------------
--								  API
-------------------------------------------------------------------------------
local p = {}

-- Entry-point per {{HistoryBox}}
function p.historybox(frame)
	return tostring(HistoryBox:new(getArgs(frame)))
end

-- Ritorna la tabella di configurazione
function p.actiontable(frame)
	local tableNode = mw.html.create("table")
		:addClass('wikitable')
		:addClass('sortable')
	tableNode:tag('tr')
		:tag('th'):wikitext('Azione'):done()
		:tag('th'):wikitext('Alias azione'):done()
		:tag('th'):wikitext('Descrizione'):done()
		:tag('th'):wikitext("Esiti<br /><small>In grassetto l'esito di default</small><br /><small>Tra parentesi gli alias</small>"):done()
		:tag('th'):wikitext("Collegamento di default")
	for kaction, vaction in pairs(cfg.actions) do
		local table_row = tableNode:tag('tr')
		table_row:tag('td')
			:wikitext(kaction)
		local alias_action = {}
		for k, v in pairs(cfg.action_alias) do
			if v == kaction then
				alias_action[#alias_action+1] = mw.ustring.lower(k)
			end
		end
		table_row:tag('td')
			:wikitext(table.concat(alias_action, ',<br />'))
		table_row:tag('td')
			:wikitext(vaction['description'] or '&nbsp;')
		local default_result = vaction['default_result'] or 'xxx'
		local td_result = table_row:tag('td')
		if vaction.valid_result then
			local first_result = true
			for kr,vr in pairs(vaction.valid_result) do
				if first_result then
					first_result = false
				else
					td_result:tag('br'):done()
				end
				if kr == default_result then
					td_result:tag("b"):wikitext(mw.ustring.lower(kr))
				else
					td_result:wikitext(mw.ustring.lower(kr))
				end
				if vaction['result_alias'] then
					local result_alias = {}
					for ka, va in pairs(vaction.result_alias) do
						if va == kr then result_alias[#result_alias+1] = mw.ustring.lower(ka) end
					end
					if #result_alias > 0 then td_result:wikitext(" (" .. table.concat(result_alias, ", ") .. ")" ) end
				end
				td_result:wikitext(' --> ' .. (vr['msg'] or '???') )
			end
		else
			td_result = table_row:wikitext("-")
		end
		local default_position = '&nbsp;'
		if vaction['default_position'] then
			if vaction['use_date_for_position'] then
				default_position = mw.message.newRawMessage( vaction.default_position, { '<nome>', '<mese>', '<anno>'}):plain()
			else
				default_position = mw.message.newRawMessage( vaction.default_position[1] .. '<br />' .. vaction.default_position[2],
															 { '<name>', '<n>'} ):plain()
			end
		end
		table_row:tag('td'):wikitext(default_position)
	end
	return tostring(tableNode)
end

return p