Type a search term to find related articles by LIMS subject matter experts gathered from the most trusted and dynamic collaboration tools in the laboratory informatics industry.
Modulo Lua per la riproduzione delle funzioni dei vari template {{Cita libro}}, {{Cita web}}, {{Cita news}}, {{Cita pubblicazione}}, {{Cita conferenza}} e {{Cita video}}.
Quelle che seguono sono note tecniche sul funzionamento del modulo. Per le istruzioni su come usarlo per inserire citazioni nelle voci vedi il manuale di {{Cita testo}}.
Nel seguito per settata si intende una variabile diversa da nil e da stringa nulla
mw.message.newRawMessage
, non granchè documentata, apparentemente nella stringa i $n
vengono sostituiti dal valore in posizione ennesima in args. Se args è nil ritorna nilA=argument_wrapper(args)
la chiamata A[key]
il valore args[first_set(citation_config.aliases[key])]
. Questo permette la localizzazione dei parametri e la creazione di alias per lo stesso valore. Per esempio se citation_config.aliases['Chapter'] = {'capitolo', 'contributo', 'voce', 'articolo', 'sezione' }
la chiamata A['Chapter']
resituirà uno dei valori settati tra args['capitolo']
, args['contributo']
, args['voce']
, args['articolo']
, args['sezione']
. Aggiunge inoltre il metodo A:ORIGIN che restituisce l'alias con il quale è stato trovato un valore. I valori trovati vengono bufferizzati in una tabella interna.true
se name non è nil ed è il nome di un parametro accettato, false
in caso contrariotrue
il codice sarà inserito ma non visibile salvo analizzare il codice html della pagina, altrimenti sarà formattato come da settaggio delle classi "error" e "citation-comment" nel css (normalmente una scritta in rosso)true
il messaggio viene ritornato senza essere passato prima per errorcomment.Per gestire l'unione dei pezzi di citazione, viene definito un "oggetto" Lua (in realtà una tabella con una metatable che definisce alcuni metodi aggiuntivi). Un fragment è composto da un array il cui primo elemento è un stringa da inserire all'inizio della sequenza, seguito da uno o più stringhe e terminati da una stringa da inserire al termine della sequenza. Quando due frammenti f1 e f2 vengono uniti (vedi fragment.append e fragment.appends) viene valutata la priorità dell'ultimo separatore di f1 e quella del primo di f2 e conservato solo quello con priorità maggiore. Il nuovo frammento avrà il separatore iniziale di f1 e quello finale di f2.
[""] = { order=0, sep = ""},
[" "] = { order=1, sep = " "},
[","] = { order=2, sep = ", "},
["."] = { order=3, sep = ". "},
["in"] = {order=4, sep = " in "},
[" "] = { order=5, sep = " "},
spazio semplice che però prevale su altri separatori["nothing"] = {order=6, sep="" }
stringa nulla che prevale su tutto (per forzare nessun separatore a inizio citazione)true
se fragment è un frammento vuoto (contiene un array di stringhe vuoto)-- Modulo per la gestione delle citazioni, originariamente importato dalla
-- revisione 555909894 del 20/5/2013 da [[:en:Module:Citation/CS1]]
--[[ ===============================================================================
Variabile in cui vengono memorizzate le condizioni di errore registrate durante l'esecuzione
delle funzioni del modulo.
===============================================================================]]
local z = {
error_categories = {}; -- lista delle categorie di errore
error_ids = {}; -- lista dei codici di errore
message_tail = {}; -- messaggi di errore da visualizzare in coda alla citazione
}
--[[ ===============================================================================
Carica la tabella di configurazione, correggendo il nome se caricato da sandbox
-- nota: non ancora attiva per qualche motivo non funziona
===============================================================================]]
local function load_configuration_table(name)
local frame = mw.getCurrentFrame()
local real_name = name
if nil ~= string.find (frame:getTitle(), 'sandbox', 1, true) then
real_name = real_name .. '/sandbox'
end
return mw.loadData(real_name)
end
--[[ ===============================================================================
Caricamento delle tabelle di configurazione del modulo.
===============================================================================]]
local cfg = mw.loadData('Module:Citazione/Configurazione')
--local cfg = load_configuration_table('Module:Citazione/Configurazione')
--[[ ===============================================================================
Lista di tutti i parametri riconosciuti.
===============================================================================]]
local whitelist = mw.loadData('Module:Citazione/Whitelist')
--local whitelist = load_configuration_table('Module:Citazione/Whitelist')
--[[ ===============================================================================
Ritorna true se una variabile è settata (diversa da nil e da stringa vuota)
===============================================================================]]
local function is_set( var )
return not (var == nil or var == '');
end
-- Ritorna il nostro {{Collegamento interrotto}}
local function interrupted_url()
return mw.getCurrentFrame():expandTemplate{ title = 'Collegamento interrotto' }
end
--[[ ===============================================================================
Ritorna la prima variabile settata di quelle passate alla funzione
===============================================================================]]
local function first_set(...)
local list = {...};
for _, var in pairs(list) do
if is_set( var ) then
return var;
end
end
end
--[[ ===============================================================================
Ritorna la posizione di needle nella lista haystack, altrimenti ritorna false
===============================================================================]]
local function in_array( needle, haystack )
if needle == nil then return false; end
for n,v in ipairs( haystack ) do
if v == needle then return n; end
end
return false;
end
--[[ ===============================================================================
Popola gli argomenti numerati nella stringa msg usando la tabella di argomenti args
===============================================================================]]
local function substitute( msg, args )
return args and mw.message.newRawMessage( msg, args ):plain() or msg;
end
--[[ ===============================================================================
Rende la stringa sicura per il markup corsivo '' ... ''
Nota: non si può usare <i> per il corsivo poichè il comportamento atteso se lo si
specifica per i titoli è di renderli non corsivi. Inoltre <i> e '' interagiscono
male con la funzione HTML tidy di Mediawiki
===============================================================================]]
local function safe_for_italics( str )
if not is_set(str) then
return str;
else
if str:sub(1,1) == "'" then str = "<span></span>" .. str; end
if str:sub(-1,-1) == "'" then str = str .. "<span></span>"; end
-- Rimuove le andate a capo perché rompono il corsivo.
return str:gsub( '\n', ' ' );
end
end
--[[ ===============================================================================
Ritorna true/false a seconda che la stringa si possa scrivere in corsivo
===============================================================================]]
local function is_italicizable( str )
return require('Modulo:Valido in corsivo')._main({ str })
end
--[[ ===============================================================================
Restituisce un messaggio dalla tabella cfg.messages in cui viene inserita una stringa
- key: codice del messaggio da visualizzare in cfg.messages
- str: una stringa da inserire nel messaggio, se non è definita o uguale a stringa
vuota la funzione ritorna una stringa vuota
===============================================================================]]
local function wrap( key, str )
if not is_set( str ) then
return "";
elseif in_array( key, { 'italic-title', 'trans-italic-title' } ) then
str = safe_for_italics( str );
end
return substitute( cfg.messages[key], {str} );
end
--[[ ===============================================================================
Inserisce un messaggio di debug da visualizzare in coda alla citazione
===============================================================================]]
local function debug_msg(msg)
table.insert( z.message_tail, { set_error( 'debug_txt', {msg}, true ) } );
end
--[[ ===============================================================================
A scopo di debug, aggiunge la stringa 'name=<value>' in coda alla citazione
===============================================================================]]
local function debug_value(name, value)
if not value then value='nil' end
debug_msg(name .. '="'.. value .. '"')
end
--[[ ===============================================================================
Formatta un commento per identificare gli errori, aggiungendo la classe css per
renderlo visibile o meno
===============================================================================]]
local function error_comment( content, hidden )
return wrap( hidden and 'hidden-error' or 'visible-error', content );
end
--[[ ===============================================================================
Imposta un condizione di errore e ritorna un messaggio appropriato. L'inserimento
del messaggio nell'output è di responsabilità della funzione chiamante
-- -- error_id: codice dell'errore (una chiave valida per cfg.error_conditions)
-- -- arguments: una lista di argomenti opzionali per la formattazione del messaggio
-- -- raw: ritorna una coppia: {messaggio di errore, visibilità} invece del messaggio
-- di errore formattato
-- -- prefix: stringa da aggiungere in testa al messaggio
-- -- suffix: stringa da aggiungere in coda al messaggio
===============================================================================]]
local function set_error( error_id, arguments, raw, prefix, suffix )
local error_state = cfg.error_conditions[ error_id ];
prefix = prefix or "";
suffix = suffix or "";
if error_state == nil then
error( cfg.messages['undefined_error'] );
elseif is_set( error_state.category ) then
table.insert( z.error_categories, error_state.category );
end
local message = substitute( error_state.message, arguments );
message = mw.ustring.format(
'%s ([[%s#%s|%s]])',
message, cfg.messages['help page link'], error_state.anchor,
cfg.messages['help page label']
)
z.error_ids[ error_id ] = true;
if in_array( error_id, { 'bare_url_missing_title', 'trans_missing_title' } )
and z.error_ids['citation_missing_title'] then
return '', false;
end
message = table.concat({ prefix, message, suffix });
if raw == true then return message, error_state.hidden end
return error_comment( message, error_state.hidden );
end
--[[ ===============================================================================
Cerca il primo parametro settato da una lista di parametri e genera un errore se
più di un parametro è settato.
Ritorna la coppia (value, selected) dove value è il valore del parametro trovato e
selected il nome del parametro trovato
===============================================================================]]
local function select_one( args, possible, error_condition, index )
local value = nil;
local selected = '';
local error_list = {};
if index ~= nil then index = tostring(index); end
-- Handle special case of "#" replaced by empty string
if index == '1' then
for _, v in ipairs( possible ) do
v = v:gsub( "#", "" );
if is_set(args[v]) then
if value ~= nil and selected ~= v then
table.insert( error_list, wrap( 'parameter', v ) );
else
value = args[v];
selected = v;
end
end
end
end
for _, v in ipairs( possible ) do
if index ~= nil then
v = v:gsub( "#", index );
end
if is_set(args[v]) then
if value ~= nil and selected ~= v then
table.insert( error_list, wrap( 'parameter', v ));
else
value = args[v];
selected = v;
end
end
end
if #error_list > 0 then
-- genera il messaggio di errore concatenando i parametri duplicati
local error_str = "";
if #error_list == 1 then
error_str = error_list[1] .. cfg.messages['parameter-pair-separator'];
else
error_str = table.concat(error_list, cfg.messages['parameter-separator']) .. cfg.messages['parameter-final-separator'];
end
error_str = error_str .. wrap( 'parameter', selected );
table.insert( z.message_tail, { set_error( error_condition, {error_str}, true ) } );
end
return value, selected;
end
--[[ ===============================================================================
Funzione di supporto per la mappatura degli argomenti del file di configurazione,
così che nomi multipli possono essere assegnati ad una singola variabile interna
===============================================================================]]
local function argument_wrapper( args )
local origin = {};
return setmetatable({
ORIGIN = function( self, k )
local dummy = self[k]; --force the variable to be loaded.
return origin[k];
end
},
{
__index = function ( tbl, k )
if origin[k] ~= nil then
return nil;
end
local args, list, v = args, cfg.aliases[k];
if type( list ) == 'table' then
v, origin[k] = select_one( args, list, 'redundant_parameters' );
if origin[k] == nil then
origin[k] = ''; -- Empty string, not nil
end
elseif list ~= nil then
v, origin[k] = args[list], list;
else
-- maybe let through instead of raising an error?
-- v, origin[k] = args[k], k;
error( cfg.messages['unknown_argument_map'] );
end
-- Empty strings, not nil;
if v == nil then
v = cfg.defaults[k] or '';
origin[k] = '';
end
tbl = rawset( tbl, k, v );
return v;
end,
});
end
--[[ ===============================================================================
Controlla che il nome di un parametro sia valido usando la whitelist
===============================================================================]]
local function validate( name )
name = tostring( name );
-- Normal arguments
if whitelist.basic_arguments[ name ] then return true end
-- Arguments with numbers in them
name = name:gsub( "%d+", "#" );
if whitelist.numbered_arguments[ name ] then return true end
-- Not found, argument not supported.
return false
end
--[[ ===============================================================================
Oggetto per memorizzare gli elementi di una citazione. Un frammento di citazione è
formato dai seguenti elementi:
- self[n]: n-esimo elemento da unire, è una lista di stringhe inframezzata dai
separatori da usare per unirle.
- self.last_priority: priorità del separatore di chiusura
- self.first_priority: priorità del separatore di apertura
- self.sep_key: codice del carattere separatore di default da usare
se unita a un altro frammento
===============================================================================]]
local Fragment = {}
Fragment.precedence = cfg.style.separator_priority
local Fragment_mt = { __index = Fragment }
Fragment.new = function(texts, sep_key)
if type(texts) == "string" then texts = { texts } end
if not Fragment.precedence[sep_key] then sep_key = "" end
local tx = { }
tx.last_priority = 0
tx.first_priority = 0
tx.sep_key = sep_key
tx[1] = ""
for _, el in ipairs(texts) do
if el ~= "" then
tx[#tx+1] = el
tx[#tx+1] = Fragment.precedence[tx.sep_key].sep
end
end
if #tx > 1 then
tx.last_priority = Fragment.precedence[tx.sep_key].order
else
tx[1] = ""
end
setmetatable(tx, Fragment_mt)
return tx
end
--- cambia il separatore iniziale di un frammento di citazione
function Fragment:start(sep_key)
if #self == 0 then return self end
local separator = Fragment.precedence[sep_key] or Fragment.precedence[""]
self[1] = separator.sep
self.first_priority = separator.order
return self
end
-- cambia il separatore finale di un frammento di citazione
function Fragment:last(sep_key)
if #self == 0 then return self end
local separator = Fragment.precedence[sep_key] or Fragment.precedence[""]
self[#self] = separator.sep
self.last_priority = separator.order
return self
end
-- ritorna un frammento di citazione vuoto
function Fragment:empty()
return #self==0
end
-- appende una stringa o un frammento di citazione in coda
function Fragment:append(txr)
if txr == nil then return self end
if type(txr) == "string" then txr = Fragment.new(txr, self.sep_key) end
if #txr == 0 then return self end
if #self == 0 then self[1] = txr[1] end
self.last_priority = self.last_priority or 0
if self.last_priority < txr.first_priority then
self[#self] = txr[1]
end
for i, el in ipairs(txr) do
if i>1 then self[#self+1] = el end
end
self.last_priority = txr.last_priority
--self.sep_key = txr.sep_key
return self
end
-- appende una lista di stringhe o frammenti di citazione
function Fragment:appends(fragments)
for _,f in ipairs(fragments) do
self:append(f)
end
return self
end
-- collassa il frammento in una stringa e la restituisce
Fragment_mt.__tostring = function(tx)
return table.concat(tx, '')
end
-- =====================================================================
-- Fine definizione oggetto Fragment
-- =====================================================================
--[[ ===============================================================================
Formatta un wikilink interno o un link esterno a un documento
- options.code_id: codice per il link esterno
- options.id: etichetta del link esterno o id del documento
- options.encode: se true o nil l'url viene codificato (en:Percent-encoding)
- options.link: link alla voce wiki sul codice documento
- options.label: etichetta del link alla voce wiki sul codice documento
- options.separator: separatore tra codice e link (di default uno spazio unificatore)
- options.pattern: pattern del link in cui "$1" è l'id normale e "$2" l'id nell'url esterno
===============================================================================]]
local function link_id(options)
local url_string = options.code_id or options.id;
if options.encode == true or options.encode == nil then
url_string = mw.uri.encode( url_string );
end
for w in mw.ustring.gmatch( options.pattern, '$1' ) do
options.pattern = mw.ustring.gsub( options.pattern, '^(%[[^%[]%S+)$1(.-%])', '%1$2%2' );
options.pattern = mw.ustring.gsub( options.pattern, '([^%[]%[[^%[]%S+)$1(.-%])', '%1$2%2' );
end
return mw.ustring.format( '[[%s|%s]]%s%s',
options.link, options.label, options.separator or " ",
substitute( options.pattern, {mw.text.nowiki(options.id), url_string} )
);
end
--[[ ===============================================================================
Determina se un URL è corretto. Al momento controlla solo la stringa inizia con
prefisso URI valido e che non contenga spazi
TODO: aggiungere controlli più stringenti (vedi en.wiki)
===============================================================================]]
local function check_url( url_str )
-- se contiene spazi non può essere un url corretto
if nil == url_str:match ("^%S+$") then
return false;
end
-- Protocol-relative or URL scheme
return url_str:sub(1,2) == "//" or url_str:match( "^[^/]*:" ) ~= nil;
end
--[[ ===============================================================================
Rende una stringa sicura per essere usata come descrizione di un url
===============================================================================]]
local function safe_for_url( str )
if str:match( "%[%[.-%]%]" ) ~= nil then
table.insert( z.message_tail, { set_error( 'wikilink_in_url', {}, true ) } );
end
return str:gsub( '[%[%]\n]', {
['['] = '[',
[']'] = ']',
['\n'] = ' ' } );
end
--[[ ===============================================================================
Formatta un collegamento esterno con controllo degli errori
- URL: url del link esterno
- label: etichetta del link esterno (se non inserita viene usato
URL come etichetta e segnalato l'errore)
- source: parametro in cui è contenuto l'url
===============================================================================]]
local function external_link( URL, label, source )
local error_str = "";
if not is_set( label ) then
label = URL;
if is_set( source ) then
error_str = set_error( 'bare_url_missing_title', { wrap( 'parameter', source ) }, false, " " );
else
error( cfg.messages["bare_url_no_origin"] );
end
end
if not check_url( URL ) then
error_str = set_error( 'bad_url', {}, false, " " ) .. error_str;
end
return table.concat({ "[", URL, " ", safe_for_url( label ), "]", error_str });
end
--[[ ===============================================================================
Aggiunta collegamenti multipli, per ora usati solo dal modulo Collegamenti esterni
===============================================================================]]
local function append_links(value, links)
if type(links) == 'table' then
for _, t in ipairs(links) do
t[2] = is_italicizable( t[2] ) and wrap( 'italic-title', t[2] ) or t[2]
value = value .. ' / ' .. external_link( t[1], t[2] )
end
end
return value
end
--[[ ===============================================================================
Formatta un DOI e controlla per errori
===============================================================================]]
local function doi(id, inactive)
local cat = ""
local handler = cfg.id_handlers['DOI'];
local text;
if is_set(inactive) then
local inactive_year = inactive:match("%d%d%d%d") or ''
--text = "[[" .. handler.link .. "|" .. handler.label .. "]]:" .. id;
if is_set(inactive_year) then
table.insert( z.error_categories, "Pagine con DOI inattivo dal " .. inactive_year );
else
table.insert( z.error_categories, "Pagine con DOI inattivo" ); -- when inactive doesn't contain a recognizable year
end
inactive = " (" .. cfg.messages['inactive'] .. " " .. inactive .. ")"
end
text = link_id({link = handler.link, label = handler.label,
pattern=handler.pattern,id=id,separator=handler.separator, encode=handler.encode}) .. (inactive or '')
if nil == id:match("^10%.[^%s–]-/[^%s–]-[^%.,]$") then -- doi must begin with '10.', must contain a fwd slash, must not contain spaces or endashes, and must not end with period or comma
cat = set_error( 'bad_doi' );
end
return text .. cat
end
--[[ ===============================================================================
Formatta un link a Open library e controlla per errori
===============================================================================]]
local function open_library(id)
local code = id:sub(-1,-1)
local handler = cfg.id_handlers['OL'];
if ( code == "A" ) then
return link_id({link=handler.link, label=handler.label,
pattern="[[openlibrary:authors/OL$1|$1]]",id=id, separator=handler.separator,
encode = handler.encode})
elseif ( code == "M" ) then
return link_id({link=handler.link, label=handler.label,
pattern="[[openlibrary:books/OL$1|$1]]",id=id, separator=handler.separator,
encode = handler.encode})
elseif ( code == "W" ) then
return link_id({link=handler.link, label=handler.label,
pattern= "[[openlibrary:works/OL$1|$1]]",id=id, separator=handler.separator,
encode = handler.encode})
else
return link_id({link=handler.link, label=handler.label,
pattern= "[[openlibrary:OL$1|$1]]",id=id, separator=handler.separator,
encode = handler.encode}) ..
' ' .. set_error( 'bad_ol' );
end
end
--[[ ===============================================================================
Formatta un link alla libreria Opac mediante SBN e controlla per errori
===============================================================================]]
local function sbn(id)
local handler = cfg.id_handlers['SBN']
local start_match, end_match, cd1, cd2 = string.find(id, '^IT\\ICCU\\(...)\\(%d+)')
if not(cd1 and cd2) then
start_match, end_match, cd1, cd2 = string.find(id, '^IT\\ICCU\\(....)\\(%d+)')
end
if cd1 and cd2 then
return link_id({link=handler.link, label=handler.label,
pattern='[http://opac.sbn.it/bid/$1 $1]', id = id, code_id=cd1 .. cd2,
encode =handler.encode})
else
return link_id({link=handler.link, label=handler.label,
pattern='[http://opac.sbn.it/bid/$1 $1]', id = id,
encode =handler.encode}) .. ' ' .. set_error('bad_sbn')
end
end
--[[ ===============================================================================
Nice Opaque Identifiern utilisé par les formats Ark pour générer une clé
adattato da fr:Module:Biblio/Références
===============================================================================]]
local function ark_id( base )
base = tostring( base )
if base then
local xdigits = '0123456789bcdfghjkmnpqrstvwxz'
local sum = 0
local position
for i = 1, base:len() do
position = xdigits:find( base:sub( i, i ), 1, true ) or 1
sum = sum + i * ( position - 1 )
end
local index = sum % 29 + 1
return xdigits:sub( index, index )
end
end
--[[ ===============================================================================
Formatta un link alla Bibliothèque Nationale de France e controlla per errori
adattato da fr:Module:Biblio/Références
===============================================================================]]
local function bnf(id)
local handler = cfg.id_handlers['BNF']
if id then
local txt = id
local error_code = ''
local bnf_id = id:upper():match( 'BNF(%d+%w)' ) or id:lower():match( 'cb(%d+%w)' ) or id:match( '^%d+%w' )
if bnf_id then
-- bnf contient une suite de chiffres qui peut être un ark valide
local base = bnf_id:sub( 1, 8 )
if bnf_id:len() == 8 then
-- il manque la clé, on l'ajoute
id = base .. ark_id( 'cb' .. base )
txt = base
elseif bnf_id:len() > 8 and bnf_id:sub( 9, 9 ) == ark_id( 'cb' .. base ) then
-- ark valide
id = bnf_id:sub( 1, 9 )
txt = base
else
-- ark qui semble non valide
id = bnf_id
txt = bnf_id
error_code = set_error('bad_bnf')
end
else
-- le paramètre ne semble pas un ark valide
error_code = set_error('bad_bnf')
end
-- dans tous les cas on renvoie l'adresse, on catégorise juste pour vérifier ce qui ne va pas
return link_id( {
link=handler.link,
label=handler.label,
pattern=handler.pattern,
id=txt,
code_id=bnf_id,
separator=handler.separator
} ) .. ' ' .. error_code
end
end
--[[ ===============================================================================
Rimuove text e trattini irrilevanti da un numero isbn
===============================================================================]]
local function clean_isbn( isbn_str )
return isbn_str:gsub( "[^-0-9X]", "" );
end
--[[ ===============================================================================
Determina se una stringa ISBN è valida
===============================================================================]]
local function check_isbn( isbn_str )
isbn_str = clean_isbn( isbn_str ):gsub( "-", "" );
local len = isbn_str:len();
if len ~= 10 and len ~= 13 then
return false;
end
local temp = 0;
if len == 10 then
if isbn_str:match( "^%d*X?$" ) == nil then return false; end
isbn_str = { isbn_str:byte(1, len) };
for i, v in ipairs( isbn_str ) do
if v == string.byte( "X" ) then
temp = temp + 10*( 11 - i );
else
temp = temp + tonumber( string.char(v) )*(11-i);
end
end
return temp % 11 == 0;
else
if isbn_str:match( "^%d*$" ) == nil then return false; end
isbn_str = { isbn_str:byte(1, len) };
for i, v in ipairs( isbn_str ) do
temp = temp + (3 - 2*(i % 2)) * tonumber( string.char(v) );
end
return temp % 10 == 0;
end
end
--[[ ===============================================================================
Ritorna la sola etichetta visibile di un wikilink
===============================================================================]]
local function remove_wikilink( str )
-- Sia [[A|B]] che [[B]] ritornano B
return (str:gsub( "%[%[([^%[%]]*)%]%]", function(l)
return l:gsub( "^[^|]*|(.*)$", "%1" ):gsub("^%s*(.-)%s*$", "%1");
end));
end
--[[ ===============================================================================
Riconosce le date nel formato ISO yyyy-mm-dd e le riformatta in dmy. Si assicura
che 01 e 1 siano resi come 1º qualora indichino il giorno.
===============================================================================]]
local function get_date(str)
if is_set(str) then
local try_year, try_month, try_day = string.match(str, '^(%d%d%d%d)-(%d%d)-(%d%d)$')
if try_day then
local Month = cfg.months[tonumber(try_month)]
if Month then
try_day = try_day == '01' and '1º' or tonumber(try_day)
return string.format("%s %s %s", try_day, Month, try_year)
end
end
try_day, try_month, try_year = string.match(str, '^(%d%d?) (%a+) (%d%d%d%d)$')
if try_day then
try_day = (try_day == '1' or try_day == '01') and '1º' or tonumber(try_day)
return string.format("%s %s %s", try_day, try_month, try_year)
end
end
return str
end
--[[ ===============================================================================
Unisce year, day e month ritornando la data come un'unica stringa.
month è controllato solo se year è definito, e day è controllato solo se month è definito.
Se month è un numero tenta di convertilo nel nome corrispondente (1->gennaio, 2->febbraio...),
altrimenti non lo modifica
===============================================================================]]
local function get_date_yyyy_mm_dd(year, month, day)
local date = year
if is_set(date) then
if is_set(month) then
local month = cfg.months[tonumber(month)] or month
date = month .. " " .. year
if is_set(day) then
if day == "01" or day=="1" then day="1º" end
date = day .. " " .. date
end
end
return date
end
return ""
end
--[[ ===============================================================================
Suppone che str sia una data ben formata (una delle varianti "gg mm aaaa",
"gg/mm/aaaa" o "gg-mm-aaaa") e restituisce l'articolo da anteporre per citarla
come data di accesso/archivio
===============================================================================]]
local function article_date(str)
local start = mw.ustring.sub(str, 1, 2)
if in_array( start, {'08', '8 ', '8-', '8/', '11'} ) then
return " l'"
elseif mw.ustring.find(str, '^pre ') then -- per i valori "pre x/x/x" inseriti da ArchiveBot
return ' in data '
end
return str ~= '' and " il " or ''
end
--[[ ===============================================================================
Controlla che la stringa passata sia in un formato ammesso in caso contrario
ritorna il codice di errore
===============================================================================]]
local function check_time(str)
local h,m,s = string.match(str, '^(%d+):(%d+):(%d+)$')
if not(h) then h,m,s = string.match(str, '^(%d+) h (%d+) min (%d+) s$') end
if not(m) then m,s = string.match(str, '^(%d+) min (%d+) s$') end
if not(m) then m,s = string.match(str, '^(%d+):(%d+)$') end
if not(m) then m = string.match(str, '^(%d+) min$') end
if not(m) then return 'time_not_valid' end
if tonumber(m) >= 60 then return 'minutes_wrong' end
if s and tonumber(s) >= 60 then return 'seconds_wrong' end
if h and not(tonumber(s)) then return 'hour_wrong' end
return nil
end
--[[ ===============================================================================
Formatta una lista di persone (autori o editori)
===============================================================================]]
local function list_people(control, people)
local sep = control.sep;
local lastsep = control.lastsep
local text = {}
local etal = control.etal
local coauthors = control.coauthors
local person_list = {}
for i,person in ipairs(people) do
local last = person.last
if is_set(last) then
local fullname = ""
local first = person.first
if is_set(first) then
if invertorder then first, last = last, first end
fullname = table.concat({first, person.last}, ' ')
else
fullname = person.last
end
if is_set(person.link) then fullname = table.concat({"[[", person.link, "|", fullname, "]]"}) end
table.insert( person_list, fullname )
end
if etal then
break
end
end
local count = #person_list
local result = ""
if count > 0 then
if coauthors then
result = table.concat(person_list, sep)
elseif etal then
result = person_list[1] .. cfg.messages['et al']
else
result = mw.text.listToText(person_list, sep, lastsep)
end
end
return result, count
end
--[[ ===============================================================================
Genera un id per un ancora CITEREF
===============================================================================]]
local function anchor_id( options )
return "CITEREF" .. table.concat( options );
end
--[[ ===============================================================================
Estrae una lista di nomi (autori o editori) dalla lista argomenti
===============================================================================]]
local function extract_names(args, list_name, parent_name)
local names = {};
local i = 1;
local last;
local parameters = {
first = cfg.aliases[list_name .. '-First'],
last = cfg.aliases[list_name .. '-Last'],
link = cfg.aliases[list_name .. '-Link'],
}
if parent_name then
for k, t in pairs(parameters) do
local new_values = {}
for _, v in ipairs(t) do
table.insert( new_values, substitute(v, parent_name) )
end
parameters[k] = new_values
end
end
while true do
last = select_one( args, parameters.last, 'redundant_parameters', i );
if not is_set(last) then
local first = select_one( args, parameters.first, 'redundant_parameters', i )
if not is_set(first) then
break;
else -- nel caso sia definito "nome" ma non "cognome"
names[i] = {
last = first,
first = '',
link = select_one( args, parameters.link, 'redundant_parameters', i ),
}
end
else
names[i] = {
last = last,
first = select_one( args, parameters.first, 'redundant_parameters', i ),
link = select_one( args, parameters.link, 'redundant_parameters', i ),
};
end
i = i + 1;
end
return names;
end
--[[ ===============================================================================
Estrae dagli argomenti i codici bibliografici riconosciuti usando la
tabella cfg.id_handlers
===============================================================================]]
local function extract_ids( args )
local id_list = {};
for k, v in pairs( cfg.id_handlers ) do
v = select_one( args, v.parameters, 'redundant_parameters' );
if is_set(v) then
if k == 'ISBN' then v = string.gsub(v, '^ISBN%s*', '') end -- hack per eliminare l'ISBN ripetuto
id_list[k] = v;
end
end
return id_list;
end
--[[ ===============================================================================
Formatta gli id bibliografici presenti nella tabella id_list
===============================================================================]]
local function build_id_list( id_list, options )
local new_list, handler = {};
local function fallback(k)
return { __index = function(t,i) return cfg.id_handlers[k][i] end }
end;
local function comp( a, b )
return a[1] < b[1];
end
for k, v in pairs( id_list ) do
-- fallback to read-only cfg
local handler = setmetatable( { ['id'] = v }, fallback(k) );
if k == 'DOI' then
table.insert( new_list, {handler.label, doi( v, options.DoiBroken ) } );
elseif k == 'OL' then
table.insert( new_list, {handler.label, open_library( v ) } );
elseif k == 'SBN' then
table.insert (new_list, {handler.label, sbn(v) } );
elseif k == 'BNF' then
table.insert (new_list, {handler.label, bnf(v) } );
elseif k == 'ISBN' then
local ISBN
if v == 'non esistente' or v == 'no' then --la forma lunga per intercettare il valore ritornato dal template NoIsbn
ISBN = 'ISBN non esistente'
else
ISBN = link_id( handler );
if not check_isbn( v ) and not is_set(options.IgnoreISBN) then
ISBN = ISBN .. set_error( 'bad_isbn', {}, false, "<sup>", "</sup>" );
end
end
table.insert( new_list, {handler.label, ISBN } );
else
table.insert( new_list, {handler.label, link_id( handler ) } );
end
end
table.sort( new_list, comp );
for k, v in ipairs( new_list ) do
new_list[k] = v[2];
end
return new_list;
end
--[[ ===============================================================================
Genera la stringa per il formato, se format non è definita tenta di ricavarlo dall'url
===============================================================================]]
local function get_format(format, url)
if format:lower() == 'html' then
return ''
elseif not is_set(format) then
format = mw.ustring.match(url, "^.*%.(.+)$" ) or ''
if not cfg.external_link_type[format:lower()] then
format = mw.ustring.match(format, "^(.+)#.+$") or ''
if not cfg.external_link_type[format:lower()] then
return ''
end
end
end
-- Se il formato esterno è tra quelli previsti imita lo stile dei template {{PDF}} o {{doc}}
local f = cfg.external_link_type[format:lower()]
if f then
return mw.ustring.format(' (<span style="font-weight: bolder; font-size:80%%"><abbr title="%s">%s</abbr></span>)', f.text, f.label)
else
table.insert( z.message_tail, { set_error('unknown_format', format, true) } );
return mw.ustring.format(' (%s)', format)
end
end
--[[ ===============================================================================
Genera la citazione
===============================================================================]]
local function citation0( config, args )
local A = argument_wrapper( args );
local i
local Stylename = A['Style']
local Style = cfg.style
local PPPrefix = (is_set( A['NoPP'] ) and "") or Style.ppprefix
local PPrefix = (is_set( A['NoPP'] ) and "") or Style.pprefix
-- Pick out the relevant fields from the arguments. Different citation templates
-- define different field names for the same underlying things.
-- local Authors = A['Authors'];
local a = extract_names( args, 'AuthorList' );
local Coauthors = A['Coauthors'];
local Others = A['Others'];
local Editors = A['Editors'];
local e = extract_names( args, 'EditorList' );
------------------------------------------------- Get date data
local PublicationDate = A['PublicationDate'];
local LayDate = A['LayDate'];
------------------------------------------------- Get title data
local Title = A['Title'];
local Conference = A['Conference'];
local Organization = A['Organization']
local TransTitle = A['TransTitle'];
local OriginalTitle = A['OriginalTitle']
-- local TitleNote = A['TitleNote'];
local TitleLink = A['TitleLink'];
local Chapter = A['Chapter'];
local ChapterLink = A['ChapterLink'];
local TransChapter = A['TransChapter'];
local TitleType = A['TitleType'];
local ArchiveURL = A['ArchiveURL'];
local URL = A['URL']
local URLorigin = A:ORIGIN('URL');
local ChapterURL = A['ChapterURL'];
local ChapterURLorigin = A:ORIGIN('ChapterURL');
local ConferenceURL = A['ConferenceURL'];
local ConferenceURLorigin = A:ORIGIN('ConferenceURL');
local Abstract = A['Abstract']
local Periodical = A['Periodical'];
local Illustrator = A['Illustrator'];
local Translator = A['Translator'];
local Institution = A['Institution'];
local Collection = A['Collection'];
local SupplementOf = A['SupplementOf'];
if is_set(OriginalTitle) and not is_set(TransTitle) then
TransTitle = OriginalTitle
end
local isPubblicazione = (config.CitationClass == 'pubblicazione') or
(config.CitationClass=='testo' and is_set(Periodical))
------------------------------------------------------------------------------
-- Formattazione di Position - contiene la pagina/posizione o punto del video
-- a cui fa riferimento la fonte
------------------------------------------------------------------------------
local Position = A['Position'];
local PositionOrigin=A:ORIGIN('Position')
if is_set(Position) then
if PositionOrigin == "p" then
Position = PPrefix .. Position
elseif PositionOrigin == "pp" then
Position = PPPrefix .. Position
elseif PositionOrigin ~= "posizione" then
table.insert( z.error_categories, 'Voci con modulo citazione e parametro ' .. PositionOrigin )
if PositionOrigin == "pagine" then
if config.CitationClass == "libro" then
if tonumber(Position) then
Position = PPrefix .. Position
elseif string.find(Position, '^%d') then
Position = PPPrefix .. Position
end
elseif config.CitationClass=="conferenza" or config.CitationClass== "pubblicazione" then
Position = (tonumber(Position) and PPrefix or PPPrefix) .. Position
end
elseif PositionOrigin == "pagina" then
Position = PPrefix .. Position
else
Position = PPPrefix .. Position
end
end
end
local Hour = A['Hour']
local Minutes = A['Minutes']
local Seconds = A['Seconds']
local Time = A['Time']
if in_array(config.CitationClass, { "video", "tv", "audio" } ) then
local ComposeTime = {}
local TimeError = {}
if is_set(Hour) then
if not is_set(Minutes) then TimeError[#TimeError+1] = set_error('need_minutes' , {'ora'}) end
if not tonumber(Hour) then TimeError[#TimeError+1] = set_error('timepar_must_be_integer', {'ora'}) end
ComposeTime[#ComposeTime+1] = Hour .. ' h'
end
if is_set(Minutes) then
local check_error = tonumber(Minutes)
if not check_error then
TimeError[#TimeError+1] = set_error('timepar_must_be_integer', {'minuto'})
elseif check_error > 60 then
TimeError[#TimeError+1] = set_error('minutes_wrong')
end
ComposeTime[#ComposeTime+1] = Minutes .. ' min'
end
if is_set(Seconds) then
if not is_set(Minutes) then TimeError[#TimeError+1] = set_error('need_minutes', {'secondo'}) end
local check_error = tonumber(Seconds)
if not check_error then
TimeError[#TimeError+1] = set_error('timepar_must_be_integer', {'ora'})
elseif check_error > 60 then
TimeError[#TimeError+1] = set_error('seconds_wrong')
end
ComposeTime[#ComposeTime+1] = Seconds .. ' s'
end
if #ComposeTime > 1 then
if is_set(Position) then TimeError[#TimeError+1] = set_error('time_parameter_conflict') end
Position = 'a ' .. table.concat(ComposeTime, ' ')
end
if is_set(Time) then
if is_set(Position) then TimeError[#TimeError+1] = set_error('time_parameter_conflict') end
local check_error = check_time(Time)
if check_error then TimeError[#TimeError+1] = set_error(check_error) end
Position = 'a ' .. Time
end
if #TimeError > 0 then Position = Position .. " " .. table.concat(TimeError, ", ") end
else
if is_set(Hour) or is_set(Minutes) or is_set(Seconds) or is_set(Time) then
table.insert( z.message_tail, { set_error( 'not_video_citation', {}, true ) } );
end
end
if is_set(Position) then Position = ' ' .. Position end
------------------------------------------------------------------------------
-- Formattazione di volume/numero/serie/episodio
------------------------------------------------------------------------------
local Series = A['Series'];
local Volume = A['Volume'];
local Issue = A['Issue'];
if config.CitationClass == "tv" then
if is_set(Issue) then
if is_set(Volume) then
Issue = substitute(cfg.messages['season_episode'], {Volume, Issue} )
Volume = ''
else
Issue = substitute(cfg.messages['episode'], {Issue})
end
end
else
-- formatta Volume e Issue considerando numeri anche le stringhe del tipo n-n o n/n
if is_set(Volume) then
if tonumber(Volume:gsub('[-/]', ''), 10) or A:ORIGIN('Volume') == "vol" then
Volume = "vol. " .. Volume
end
end
if is_set(Issue) then
if tonumber(Issue:gsub('[-/]', ''), 10) then
Issue = "n. " .. Issue
end
end
end
local Edition = A['Edition'];
local Place = A['Place']
local PublisherName = A['PublisherName'];
local SubscriptionRequired = A['SubscriptionRequired'];
local Via = A['Via'];
-- local Agency = A['Agency'];
local DeadURL = A['DeadURL'];
local Language = A['Language'];
local Format = A['Format'];
local Ref = A['Ref'];
local DoiBroken = A['DoiBroken'];
local ID = A['ID'];
local IgnoreISBN = A['IgnoreISBN'];
local Quote = A['Quote'];
local sepc = Style.sep
local sepcspace = sepc .. " "
local PostScript = first_set(A['PostScript'], Style['postscript']);
local no_tracking_cats = A['NoTracking'];
local use_lowercase = ( sepc ~= '.' );
local this_page = mw.title.getCurrentTitle(); --Also used for COinS
local ID_list = extract_ids( args );
if ( isPubblicazione ) then
if not is_set(URL) and not is_set(TitleLink) then
if is_set(ID_list['PMC']) then
local Embargo = A['Embargo'];
if is_set(Embargo) then
local lang = mw.getContentLanguage();
local good1, result1, good2, result2;
good1, result1 = pcall( lang.formatDate, lang, 'U', Embargo );
good2, result2 = pcall( lang.formatDate, lang, 'U' );
if good1 and good2 and tonumber( result1 ) < tonumber( result2 ) then
URL = "https://www.ncbi.nlm.nih.gov/pmc/articles/PMC" .. ID_list['PMC'];
URLorigin = cfg.id_handlers['PMC'].parameters[1];
end
else
URL = "https://www.ncbi.nlm.nih.gov/pmc/articles/PMC" .. ID_list['PMC'];
URLorigin = cfg.id_handlers['PMC'].parameters[1];
end
elseif is_set(ID_list['DOI']) then
URL = "https://oadoi.org/" .. ID_list['DOI'];
URLorigin = cfg.id_handlers['DOI'].parameters[1];
end
end
end
ID_list = build_id_list( ID_list, {DoiBroken = DoiBroken, IgnoreISBN = IgnoreISBN} );
local Station = A['Station'];
if is_set(Station) then
local wkStation = A['StationLink']
if is_set(wkStation) then
Station = '[[' .. wkStation .. '|' .. Station .. ']]'
end
end
if config.CitationClass == "tv" then
Chapter = Title;
ChapterLink = TitleLink;
TransChapter = TransTitle;
Title = Series;
TitleLink = A['SeriesLink'];
TransTitle = '';
Series = '';
end
------------------------------------------------------------------------------
-- Se url è in realtà un url archiviato, lo tratta come tale
-- (per ora riconosce solo Internet Archive)
------------------------------------------------------------------------------
local formatoIA = '^https?://web%.archive%.org/w?e?b?/?%d+/'
if is_set(URL) and is_set(Title) and URL:match(formatoIA) and not is_set(ArchiveURL) then
ArchiveURL = URL
URL = URL:gsub(formatoIA,'')
if not URL:match('://') then
URL = 'http://' .. URL
end
end
------------------------------------------------------------------------------
-- Se opera/sito non è specificata, nel caso dei siti usa il dominio dell'URL
------------------------------------------------------------------------------
local auto_Periodical = false
if in_array(config.CitationClass, {'web'}) and not is_set(Periodical) and is_set(URL) then
Periodical = mw.ustring.match(URL, "//([^/#%?]*)") or ''
-- tolgo anche eventuale www.
if string.find(Periodical, "^[Ww][Ww][Ww]%.") then
Periodical = mw.ustring.sub(Periodical, 5)
end
-- evito ripetizione se il dominio è stato usato come titolo o editore
if is_set(Periodical) then
if mw.ustring.lower(Title) == mw.ustring.lower(Periodical) then
Periodical = ''
end
if mw.ustring.lower(PublisherName) == mw.ustring.lower(Periodical) then
PublisherName = ''
end
end
auto_Periodical = true
end
------------------------------------------------------------------------------
-- Se compare uno dei parametri legati a una pubblicazione periodica (opera, rivista, ec...)
-- e non è definito capitolo, ma solo titolo sposto titolo a capitolo
------------------------------------------------------------------------------
if is_set(Periodical) and not is_set(Chapter) and is_set(Title) then
Chapter = Title;
ChapterLink = TitleLink;
TransChapter = TransTitle;
Title = '';
TitleLink = '';
TransTitle = '';
end
---------------------------------------------------------------
-- Compone la stringa della lingua
---------------------------------------------------------------
local Language_code = ""
local first_language = ""
if is_set(Language) then
if Language:sub(1,1) == "(" then
Language_code = Language
else
local frame_lingue = {return_error='true'}
for lingua in mw.text.gsplit(Language, ',', true) do
lingua = mw.text.trim(lingua)
if lingua ~= '' then
frame_lingue[#frame_lingue+1] = lingua
end
end
if #frame_lingue > 1 or (#frame_lingue==1 and frame_lingue[1]:lower()~="it" and frame_lingue[1]:lower()~="it-it") then
first_language = frame_lingue[1]:lower();
local lg_error;
Language_code, lg_error = require("Modulo:Lingue").lingue(frame_lingue)
if lg_error and #lg_error > 0 then
local error_string = mw.text.listToText(lg_error, ", ", " e " )
table.insert( z.message_tail, { set_error('unknown_language', {error_string}, true) } );
end
end
end
end
if is_set(Edition) then
if A:ORIGIN('Edition') == "ed" or tonumber(Edition) then
Edition = Edition .. "ª ed."
end
end
------------------------------------------------------------------------------
-- Aggiunge il wikilink a Wikisource
------------------------------------------------------------------------------
if is_set(A['Source']) and not in_array(config.CitationClass, { "web", "video", "tv", "audio" } ) then
local source = A['Source']
-- se s=1 usa lo stesso valore di titolo/capitolo
if source == "1" then
source = Title .. (is_set(Chapter) and ("/" .. Chapter) or "")
end
source = "s:" .. (is_set(first_language) and (first_language .. ":") or "") .. source
if is_set(Chapter) then ChapterLink = source
else TitleLink = source end
end
------------------------------------------------------------------------------
-- Recupero e formatto lista autori
------------------------------------------------------------------------------
local AuthorSeparator = Style.peoplesep
local control = {
sep = AuthorSeparator,
maximum = Style.maximum_authors,
lastsep = Style.lastsepauthor,
invertorder = Style.invertorder,
etal = false,
coauthors = false,
};
local Etal = A['Etal']
-- If the coauthor field is also used, prevent adding ''et al.''
if is_set(Coauthors) then
table.insert( z.error_categories, 'Voci con modulo citazione e parametro ' .. A:ORIGIN('Coauthors') )
control.coauthors = true
elseif is_set(Etal) then
control.etal = true
end
local Authors = list_people(control, a)
if not is_set(Authors) and is_set(Coauthors) then -- se non sono stati compilati campi autore, ma solo coautori
Authors = Coauthors
Coauthors = ""
elseif is_set(Coauthors) then
Authors = table.concat({Authors, AuthorSeparator, Coauthors})
end
------------------------------------------------------------------------------
-- Recupero e formatto lista curatori
------------------------------------------------------------------------------
local msg_editors
local CuratoriEtal = A['Etalcuratori']
control.coauthors = false
control.etal = is_set(CuratoriEtal)
if is_set(Editors) then
msg_editors = 'editors'
else
local EditorCount
Editors, EditorCount = list_people(control, e)
if is_set(Editors) then
msg_editors = EditorCount <= 1 and 'editor' or 'editors'
end
end
------------------------------------------------------------------------------
-- Recupero e formatto lista autori e curatori di un singolo capitolo dell'opera citata
------------------------------------------------------------------------------
local msg_chapter_editors
local Contributors, ChapterEditors = "", ""
if is_set(Chapter) then
local ChapterEditorCount
control.etal = false
Contributors = list_people(control,
extract_names( args, 'ContributorList', A:ORIGIN('Chapter') ))
ChapterEditors, ChapterEditorCount = list_people(control,
extract_names( args, 'ChapterEditorList', A:ORIGIN('Chapter') ))
if is_set(ChapterEditors) then
msg_chapter_editors = ChapterEditorCount <= 1 and 'editor' or 'editors'
end
end
------------------------------------------------------------------------------
-- Se conferenza aggiungo il campo Organizzazione
------------------------------------------------------------------------------
if config.CitationClass == 'conferenza' then
if is_set (Authors) and is_set(Organization) then
Authors = table.concat({Authors, ', ', Organization})
elseif is_set(Organization) then
Authors = Organization
end
Organization = ""
end
------------------------------------------------------------------------------
-- Formatto la data
------------------------------------------------------------------------------
local Date = get_date(A['Date'])
local Year = A['Year']
if not is_set(Date) then Date=get_date_yyyy_mm_dd(Year, A['Month'], A['Day']) end
local OrigDate = get_date(A['OrigDate'])
if not is_set(OrigDate) then OrigDate=get_date_yyyy_mm_dd(A['OrigYear'], A['OrigMonth'], A['OrigDay']) end
local AccessDate = get_date(A['AccessDate'])
if not is_set(AccessDate) then AccessDate=get_date_yyyy_mm_dd(A['AccessYear'], A['AccessMonth'], A['AccessDay']) end
local ArchiveDate = get_date(A['ArchiveDate']);
if is_set(OrigDate) and not is_set(Date) then
Date = OrigDate
OrigDate = ""
end
OrigDate = is_set(OrigDate) and (" " .. wrap( 'origdate', OrigDate)) or "";
if in_array(PublicationDate, {Date, Year}) then PublicationDate = '' end
if not is_set(Date) and is_set(PublicationDate) then
Date = PublicationDate;
PublicationDate = '';
end
-- Captures the value for Date prior to adding parens or other textual transformations
local DateIn = Date;
if not is_set(URL) and
not is_set(ChapterURL) and
not is_set(ArchiveURL) and
not is_set(ConferenceURL) then
-- Controlla se Cita web viene chiamato senza URL
if in_array(config.CitationClass, {'web'}) then
table.insert( z.message_tail, { set_error( 'cite_web_url', {}, true ) } );
end
-- Test if accessdate is given without giving a URL
if is_set(AccessDate) then
table.insert( z.message_tail, { set_error( 'accessdate_missing_url', {}, true ) } );
AccessDate = '';
end
-- Test if format is given without giving a URL
if is_set(Format) then
Format = Format .. set_error( 'format_missing_url' );
end
end
-- Test if citation has no title
if not is_set(Chapter) and
not is_set(Title) and
not is_set(Periodical) and
not is_set(Conference) and
not is_set(TransTitle) and
not is_set(TransChapter) then
table.insert( z.message_tail, { set_error( 'citation_missing_title', {}, true ) } );
end
-- genera la stringa per il formato
Format = get_format(Format, (is_set(URL) and URL) or ChapterURL )
-- In maniera predefinita l'URL non è dichiarato morto
if is_set(DeadURL) then
DeadURL = DeadURL:lower() ~= 'no'
else
-- A meno che l'archivio non sia specificato
DeadURL = is_set(ArchiveURL)
end
local OriginalURL = URL
if is_set( ArchiveURL ) then
if DeadURL then
URL = ArchiveURL
URLorigin = A:ORIGIN('ArchiveURL')
end
end
---------------------------------------------------------------
-- se pubblicazione controlla per i parametro abstract
--------------------------------------------------------------
if is_set(Abstract) then
if isPubblicazione then
if is_set(ChapterURL) then
TitleType = external_link( ChapterURL, 'abstract' )
ChapterURL = ""
if not is_set(URL) then Format = "" end
elseif is_set(URL) then
TitleType = external_link( URL, 'abstract' )
URL = ""
else
Abstract = ''
end
else
Abstract = ""
end
else
Abstract = ""
end
TitleType = is_set(TitleType) and ("(" .. TitleType .. ")") or "";
---------------------------------------------------------------
-- Format chapter / article title
---------------------------------------------------------------
local TransError = ""
if is_set(TransChapter) then
if not is_set(Chapter) then
TransError = " " .. set_error( 'trans_missing_chapter' )
Chapter = TransChapter
TransChapter = ""
else
TransChapter = wrap( is_italicizable(TransChapter) and 'trans-italic-title' or 'trans-quoted-title', TransChapter )
end
end
Chapter = is_italicizable( Chapter ) and wrap( 'italic-title', Chapter ) or Chapter;
if is_set(TransChapter) then Chapter = Chapter .. " " .. TransChapter end
if is_set(Chapter) then
if is_set(ChapterLink) then
Chapter = table.concat({"[[", ChapterLink, "|", Chapter, "]]"})
elseif is_set(ChapterURL) then
Chapter = external_link( ChapterURL, Chapter ) .. TransError;
if not is_set(URL) then --se è settato URL conservo Format per inserirlo dopo questo
Chapter = Chapter .. Format;
Format = "";
end
elseif is_set(URL) then
Chapter = external_link( URL, Chapter ) .. TransError;
Chapter = append_links(Chapter, args.altrilink)
Chapter = Chapter .. Format;
URL = "";
Format = "";
else
Chapter = Chapter .. TransError;
end
elseif is_set(ChapterURL) then
Chapter = external_link( ChapterURL, nil, ChapterURLorigin ) .. TransError
end
---------------------------------------------------------------
-- Format main title
---------------------------------------------------------------
TransError = "";
if is_set(TransTitle) then
if not is_set(Title) then
TransError = " " .. set_error( 'trans_missing_title' )
Title = TransTitle
TransTitle = ""
else
TransTitle = wrap( is_italicizable(TransTitle) and 'trans-italic-title' or 'trans-quoted-title', TransTitle )
end
end
Title = is_italicizable( Title ) and wrap('italic-title', Title ) or Title;
if is_set(TransTitle) then Title = Title .. " " .. TransTitle end
if is_set(Title) then
if is_set(TitleLink) then
Title = "[[" .. TitleLink .. "|" .. Title .. "]]"
elseif is_set(URL) then
Title = external_link( URL, Title ) .. TransError
Title = append_links(Title, args.altrilink)
Title = Title .. Format
URL = "";
Format = "";
else
Title = Title .. TransError;
end
end
---------------------------------------------------------------
-- Format Conference
---------------------------------------------------------------
if is_set(Conference) then
Conference = wrap('italic-title', Conference )
if is_set(ConferenceURL) then
Conference = external_link( ConferenceURL, Conference );
end
elseif is_set(ConferenceURL) then
Conference = external_link( ConferenceURL, nil, ConferenceURLorigin );
end
-- se URL non è stato consumato da un capitolo/titolo emette errore
if is_set(URL) then
URL = " " .. external_link( URL, nil, URLorigin );
end
--Aggiungo le virgolette alla citazione-
if is_set(Quote) then
Quote = wrap( 'quoted-text', Quote );
end
---------------------------------------------------------------
-- Parametro via e subscription
---------------------------------------------------------------
if is_set(Via) then
if is_set(SubscriptionRequired) then
Via = wrap( 'viasubscription', Via );
else
Via = wrap('via', Via);
end
elseif is_set(SubscriptionRequired) then
Via = wrap('subscription')
end
---------------------------------------------------------------
-- Formattazione dati di accesso/url di archivio
---------------------------------------------------------------
if is_set(AccessDate) then
AccessDate = substitute( cfg.messages['retrieved'], {AccessDate, article_date(AccessDate)} )
end
local Archived
if is_set(ArchiveURL) then
local decodeArchiveDate = require('Modulo:Webarchive').decodeArchiveDate
local ArchiveURLDate = decodeArchiveDate(ArchiveURL)
local ArchiveError, ArchiveOutput = ''
if not is_set(ArchiveDate) then
ArchiveDate = ArchiveURLDate or ''
if not ArchiveURLDate then
ArchiveError = set_error('archive_missing_date', {}, false, ' ')
end
elseif ArchiveURLDate and ArchiveURLDate ~= ArchiveDate then
ArchiveError = set_error('date_mismatch', {ArchiveURLDate}, false, ' ')
end
ArchiveOutput = ArchiveDate .. ArchiveError
local ArchiveURL2 = A['ArchiveURL2']
local ArchiveDate2 = get_date(A['ArchiveDate2'])
if is_set(ArchiveURL2) then
local ArchiveURLDate2 = decodeArchiveDate(ArchiveURL2)
local ArchiveError2, ArchiveOutput2 = ''
if not is_set(ArchiveDate2) then
ArchiveDate2 = ArchiveURLDate2 or ''
if not ArchiveURLDate2 then
ArchiveError2 = set_error('archive_missing_date2', {}, false, ' ')
end
elseif ArchiveURLDate2 and ArchiveURLDate2 ~= ArchiveDate2 then
ArchiveError2 = set_error('date2_mismatch', {ArchiveURLDate2}, false, ' ')
end
ArchiveOutput2 = ArchiveDate2 .. ArchiveError2
ArchiveURL2 = substitute(cfg.messages['archived-second-copy'],
{ external_link( ArchiveURL2, cfg.messages['archived2']), ArchiveOutput2, article_date(ArchiveDate2) } );
end
if not DeadURL then
Archived = substitute( cfg.messages['archived-not-dead'],
{ external_link( ArchiveURL, cfg.messages['archived'] ), ArchiveOutput, article_date(ArchiveDate), ArchiveURL2} );
if not is_set(OriginalURL) then
Archived = Archived .. set_error('archive_missing_url', {}, false, ' ');
end
elseif is_set(OriginalURL) then
Archived = substitute( cfg.messages['archived-dead'],
{ OriginalURL, ArchiveOutput, article_date(ArchiveDate), ArchiveURL2 } );
else
Archived = substitute( cfg.messages['archived-missing'],
{ set_error('archive_missing_url'), ArchiveOutput, article_date(ArchiveDate), ArchiveURL2 } );
end
else
Archived = ""
end
---------------------------------------------------------------
-- Data originale se presente (in ordine di preferenza dopo
-- la data di pubblicazione, quindi l'editore, il luogo di pubblicazione, )
---------------------------------------------------------------
if is_set(OrigDate) then
if is_set(Date) then
Date = Date .. " " .. OrigDate
elseif is_set(PublisherName) then
PublisherName = PublisherName .. " " .. OrigDate
elseif is_set(Place) then
Place = Place .. " " .. OrigDate
else
Date = OrigDate
end
end
-- sopra si controlla se è vuoto, perciò bisogna formattarlo alla fine.
if is_set(Periodical) then Periodical = wrap( 'italic-title', Periodical ) end
if is_set(SupplementOf) then
if not mw.ustring.find(SupplementOf, "^.+''.+''") then
SupplementOf = 'supplemento di ' .. wrap( 'italic-title', SupplementOf )
end
end
if is_set(Collection) then Collection = 'collana ' .. wrap( 'italic-title', Collection ) end
if is_set(Translator) then Translator = wrap('translator', Translator) end
if is_set(Illustrator) then Illustrator = wrap('illustrator', Illustrator) end
---------------------------------------------------------------
-- Combino insieme i vari componenti della citazione
---------------------------------------------------------------
local fragment_Title
local PostTitle = A['PostTitle']
if is_set(Title) then
if DeadURL and not is_set( ArchiveURL ) then
-- Report a dead URL without an archived URL
Title = Title .. interrupted_url()
end
fragment_Title = Fragment.new({Title, Format, TitleType, PostTitle}, ' '):last(",")
else
fragment_Title = Fragment.new({ })
if is_set(Chapter) then
Chapter = DeadURL and not is_set( ArchiveURL )
and tostring(Fragment.new({Chapter, interrupted_url(), Format, TitleType, PostTitle}, ' '):last(""))
or tostring(Fragment.new({Chapter, Format, TitleType, PostTitle}, ' '):last(""))
end
end
local fragment_citation
if config.CitationClass == "tv" then
if is_set(Chapter) then
fragment_Title:last(":"):append(Fragment.new({Issue, Chapter}, sepc))
Issue = ""
end
fragment_citation=Fragment.new({Authors}, sepc)
fragment_citation:append(fragment_Title)
else
if is_set(ChapterEditors) and (is_set(Contributors) or args["anteposizione-curatore"] == "no") then
ChapterEditors = 'a cura di ' .. ChapterEditors
fragment_citation = Fragment.new({Contributors, Chapter, ChapterEditors}, sepc)
else
if is_set(ChapterEditors) then
ChapterEditors = wrap(msg_chapter_editors, ChapterEditors)
end
if is_set(Chapter) and not (is_set(Contributors) or is_set(ChapterEditors)) then
if is_set(Authors) then
Contributors, Authors = Authors, ""
elseif is_set(Editors) and args["anteposizione-curatore"] ~= "no" then
ChapterEditors, Editors = wrap(msg_editors, Editors), ""
end
end
fragment_citation = Fragment.new({is_set(Contributors) and Contributors or ChapterEditors, Chapter}, sepc)
end
if is_set(Chapter) then
-- antepone "su" anzichè "in" per i siti web
if A:ORIGIN('Periodical') == 'sito' or auto_Periodical then
fragment_citation:last("su")
else
fragment_citation:last("in")
end
end
if is_set(Editors) and (is_set(Authors) or args["anteposizione-curatore"] == "no" and not is_set(Chapter)) then
Editors = 'a cura di ' .. Editors
fragment_citation:appends({Authors, fragment_Title, Editors})
else
if is_set(Editors) then
Editors = wrap(msg_editors, Editors)
end
fragment_citation:appends({is_set(Authors) and Authors or Editors, fragment_Title})
end
end
fragment_citation:appends( { Conference, Periodical, SupplementOf, Collection, Translator, Illustrator, Others, Series,
Volume, Issue, Edition, Institution, Place, PublisherName, Station, Date, Position } )
local fragment_ID_list = Fragment.new(ID_list, sepc):append(ID):start(",")
local fragment_URL = Fragment.new(URL):start(",")
local fragment_AccessDate = Fragment.new(AccessDate):start('.')
local fragment_Archived = Fragment.new(Archived):start(' ')
local fragment_Via = Fragment.new(Via):start(".")
local fragment_Quote = Fragment.new({Quote}):start(".")
fragment_citation:appends({fragment_ID_list, fragment_URL, fragment_AccessDate, fragment_Archived, fragment_Via})
if PostScript == 'nessuno' then
fragment_citation:last("nothing")
else
fragment_citation:last("..")
end
fragment_citation:appends({fragment_Quote})
fragment_citation:start(" ")
local text = Language_code .. tostring(fragment_citation)
-- aggiungo l'icona per video/audio
if config.CitationClass == "video" then text = cfg.messages['icon_video'] .. ' ' .. text end
if config.CitationClass == "audio" then text = cfg.messages['icon_audio'] .. ' ' .. text end
-- Now enclose the whole thing in a <span/> element
local options = {};
if is_set(config.CitationClass) and config.CitationClass ~= "citation" then
options.class = "citation " .. config.CitationClass;
else
options.class = "citation";
end
-- if string.len(text:gsub("<span[^>/]*>.-</span>", ""):gsub("%b<>","")) <= 2 then
-- z.error_categories = {};
-- text = set_error('empty_citation');
-- z.message_tail = {};
-- end
if is_set(Ref) then
text = table.concat({ '<cite id="CITEREF', Ref, --mw.uri.anchorEncode('CITEREF' .. Ref),
'" class="', mw.text.nowiki(options.class), '" style="font-style:normal">', text, "</cite>"})
else
text = table.concat({ '<cite class="', mw.text.nowiki(options.class), '" style="font-style:normal">', text, "</cite>"})
end
local empty_span = '<span style="display:none;"> </span>';
if #z.message_tail ~= 0 then
text = text .. " ";
for i,v in ipairs( z.message_tail ) do
if is_set(v[1]) then
if i== #z.message_tail then
text = text .. error_comment( v[1], v[2] );
else
text = text .. error_comment( v[1] .. "; ", v[2] );
end
end
end
end
-- Chek to insert category error
if not is_set(no_tracking_cats) then
for k, v in pairs( cfg.uncategorized_namespaces ) do
if this_page.nsText == v then
no_tracking_cats = "true";
break;
end
end
end
no_tracking_cats = no_tracking_cats:lower();
if in_array(no_tracking_cats, {"", "no", "false", "n"}) then
for _, v in ipairs( z.error_categories ) do
text = text .. '[[Categoria:' .. v ..']]';
end
end
return text
end
--[[ ===============================================================================
Funzione di interfaccia per la generazione della citazione, usata dai vari template
cita libro, cita news, ecc...
===============================================================================]]
function z.citation(frame)
local pframe = frame:getParent()
local args = {};
local suggestions = {};
local error_text, error_state;
local config = {};
for k, v in pairs( frame.args ) do
config[k] = v;
args[k] = v;
end
if config['ignore_parent'] == 's' then
pframe.args = {}
end
local ignore_unnamed = (config['ignore_unnamed'] == 's') or false
-- copy unnamed parameter to named parameter
local lastunnamed = 0
if not(ignore_unnamed) and cfg.unnamed_parameter[config.CitationClass] then
for i, v in ipairs(cfg.unnamed_parameter[config.CitationClass]) do
if pframe.args[i] then
local args_value = mw.text.trim(pframe.args[i])
if args_value ~= "" then
args[v] = args_value
end
lastunnamed = i
else
break
end
end
end
for k, v in pairs( pframe.args ) do
if v ~= '' then
if not validate( k ) then
error_text = "";
if type( k ) ~= 'string' then
-- Exclude empty numbered parameters
if v:match("%S+") ~= nil and tonumber(k) > lastunnamed and lastunnamed > 0 then
error_text, error_state = set_error( 'text_ignored', {v}, true );
end
elseif validate( k:lower() ) then
error_text, error_state = set_error( 'parameter_ignored_suggest', {k, k:lower()}, true );
else
if #suggestions == 0 then
suggestions = mw.loadData('Modulo:Citazione/Suggerimenti');
--suggestions = load_configuration_table( 'Modulo:Citazione/Suggerimenti');
end
if suggestions[ k:lower() ] ~= nil then
error_text, error_state = set_error( 'parameter_ignored_suggest', {k, suggestions[ k:lower() ]}, true );
else
error_text, error_state = set_error( 'parameter_ignored', {k}, true );
end
end
if error_text ~= '' then
table.insert( z.message_tail, {error_text, error_state} );
end
end
args[k] = v;
elseif args[k] ~= nil then
args[k] = v;
end
end
-- hack per l'uso che fanno cita google books e youtube del parametro id
if args.id and args.id~='' then
if in_array(config.CitationClass, {"googlebooks", "video"}) then
args.id = nil
end
end
return citation0( config, args )
end
-- Funzione per generare direttamente una citazione da un altro modulo
function z.cita_da_modulo(classe, args)
-- mi assicuro che le code messaggi di errore siano vuote per evitare problemi in caso
-- per citazioni multiple dall'interno dello stesso modulo
z.error_categories = {}; -- lista delle categorie di errore
z.error_ids = {}; -- lista dei codici di errore
z.message_tail = {}; -- messaggi di errore da visualizzare in coda alla citazione
return citation0( {CitationClass = classe}, args )
end
-- Elenco i formati di documenti gestiti
function z.list_external_links(frame)
local rows = {'{| class = "wikitable sortable"\n!codice!!Testo popup'}
local keys = {}
for key, _ in pairs(cfg.external_link_type) do
keys[#keys+1] = key
end
table.sort(keys)
for _,key in ipairs(keys) do
rows[#rows+1] = mw.ustring.format('|-\n|%s||%s', key, cfg.external_link_type[key].text)
end
rows[#rows+1] = "|}"
return table.concat(rows, '\n')
end
-- per formati esterni da altri template
function z.format(frame)
local getArgs = require('Module:Arguments').getArgs
local args = getArgs(frame, {frameOnly = true})
return get_format(args[1])
end
return z