-- Variabile in cui vengono memorizzate le condizioni di errore registrate durante l'esecusione -- delle funzioni del modulo local z = { error_categories = {}; error_ids = {}; message_tail = {}; } -- Include translation message hooks, ID and error handling configuration settings. local cfg = mw.loadData( 'Modulo:Citazione/Configurazione' ); -- Contains a list of all recognized parameters local whitelist = mw.loadData( 'Modulo:Citazione/Whitelist' ); -- Whether variable is set or not function is_set( var ) return not (var == nil or var == ''); end -- First set variable or nil if none function first_set(...) local list = {...}; for _, var in pairs(list) do if is_set( var ) then return var; end end end -- If needle is in haystack return the index position function inArray( 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 -- Populates numbered arguments in a message string using an argument table. function substitute( msg, args ) return args and mw.message.newRawMessage( msg, args ):plain() or msg; end -- Wraps a string using a message_list configuration taking one argument function wrap( key, str, lower ) if not is_set( str ) then return ""; elseif inArray( key, { 'italic-title', 'trans-italic-title' } ) then str = safeforitalics( str ); end if lower == true then return substitute( cfg.messages[key]:lower(), {str} ); else return substitute( cfg.messages[key], {str} ); end end function debug_msg(msg) table.insert( z.message_tail, { seterror( 'debug_txt', {msg}, true ) } ); end function debug_value(name, value) if not value then value='nil' end debug_msg(name .. '="'.. value .. '"') end --[[ Argument wrapper. This function provides support for argument mapping defined in the configuration file so that multiple names can be transparently aliased to single internal variable. ]] 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] = selectone( 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 -- Checks that parameter name is valid using the whitelist 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 -- Formats a comment for error trapping function errorcomment( content, hidden ) return wrap( hidden and 'hidden-error' or 'visible-error', content ); end --[[ Sets an error condition and returns the appropriate error message. The actual placement of the error message in the output is the responsibility of the calling function. ]] function seterror( 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 = message .. " ([[" .. cfg.messages['help page link'] .. "#" .. error_state.anchor .. "|" .. cfg.messages['help page label'] .. "]])"; z.error_ids[ error_id ] = true; if inArray( 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 errorcomment( message, error_state.hidden ); end ----------------------------------------------------------------------------------------- -- Oggetto per memorizzare gli elementi di una citazione ----------------------------------------------------------------------------------------- local Fragment = {} Fragment.priority = {} Fragment_mt = { __index = Fragment } Fragment.new = function(texts, sep_key) if type(texts) == "string" then texts = { texts } end local fpriority = Fragment.priority if not fpriority[sep_key] then sep_key = "" end local separator = fpriority[sep_key] 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] = fpriority[tx.sep_key].sep end end if #tx > 1 then tx.last_priority = fpriority[tx.sep_key].order else tx[1] = "" end setmetatable(tx, Fragment_mt) return tx end function Fragment:start(sep_key) if #self == 0 then return self end local separator = Fragment.priority[sep_key] or Fragment.priority[""] self[1] = separator.sep self.first_priority = separator.order return self end function Fragment:last(sep_key) if #self == 0 then return self end local separator = Fragment.priority[sep_key] or Fragment.priority[""] self[#self] = separator.sep self.last_priority = separator.order return self end function Fragment:empty() return #self==0 end 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 function Fragment:appends(fragments) for _,f in ipairs(fragments) do self:append(f) end return self end Fragment_mt.__tostring = function(tx) -- Collassa i componenti in una stringa e la restituisce return table.concat(tx, '') end -- Formats a wiki style external link function externallinkid(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 return mw.ustring.format( '[[%s|%s]]%s[%s%s%s %s]', options.link, options.label, options.separator or " ", options.prefix, url_string, options.suffix or "", mw.text.nowiki(options.id) ); end -- Formats a wiki style internal link function internallinkid(options) return mw.ustring.format( '[[%s|%s]]%s[[%s%s%s|%s]]', options.link, options.label, options.separator or " ", options.prefix, options.id, options.suffix or "", mw.text.nowiki(options.id) ); end -- Format an external link with error checking function externallink( URL, label, source ) local error_str = ""; if not is_set( label ) then label = URL; if is_set( source ) then error_str = seterror( 'bare_url_missing_title', { wrap( 'parameter', source ) }, false, " " ); else error( cfg.messages["bare_url_no_origin"] ); end end if not checkurl( URL ) then error_str = seterror( 'bad_url', {}, false, " " ) .. error_str; end return table.concat({ "[", URL, " ", safeforurl( label ), "]", error_str }); end -- Formats a DOI and checks for DOI errors. function doi(id, inactive) local cat = "" local handler = cfg.id_handlers['DOI']; local text; if is_set(inactive) then text = "[[" .. handler.link .. "|" .. handler.label .. "]]:" .. id; table.insert( z.error_categories, "Pagine con DOI inattivo dal " .. selectyear(inactive) ); inactive = " (" .. cfg.messages['inactive'] .. " " .. inactive .. ")" else text = externallinkid({link = handler.link, label = handler.label, prefix=handler.prefix,id=id,separator=handler.separator, encode=handler.encode}) inactive = "" end if ( string.sub(id,1,3) ~= "10." ) then cat = seterror( 'bad_doi' ); end return text .. inactive .. cat end -- Formats an OpenLibrary link, and checks for associated errors. function openlibrary(id) local code = id:sub(-1,-1) local handler = cfg.id_handlers['OL']; if ( code == "A" ) then return externallinkid({link=handler.link, label=handler.label, prefix="http://openlibrary.org/authors/OL",id=id, separator=handler.separator, encode = handler.encode}) elseif ( code == "M" ) then return externallinkid({link=handler.link, label=handler.label, prefix="http://openlibrary.org/books/OL",id=id, separator=handler.separator, encode = handler.encode}) elseif ( code == "W" ) then return externallinkid({link=handler.link, label=handler.label, prefix= "http://openlibrary.org/works/OL",id=id, separator=handler.separator, encode = handler.encode}) else return externallinkid({link=handler.link, label=handler.label, prefix= "http://openlibrary.org/OL",id=id, separator=handler.separator, encode = handler.encode}) .. ' ' .. seterror( 'bad_ol' ); end end -- Formats a sbn link 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 externallinkid({link=handler.link, label=handler.label, prefix='http://opac.sbn.it/bid/', id = id, code_id=cd1 .. cd2, encode =handler.encode}) else return externallinkid({link=handler.link, label=handler.label, prefix='http://opac.sbn.it/bid/', id = id, encode =handler.encode}) .. ' ' .. seterror('bad_sbn') end end --[[ Determines whether an URL string is valid At present the only check is whether the string appears to be prefixed with a URI scheme. It is not determined whether the URI scheme is valid or whether the URL is otherwise well formed. ]] function checkurl( url_str ) -- Protocol-relative or URL scheme return url_str:sub(1,2) == "//" or url_str:match( "^[^/]*:" ) ~= nil; end -- Removes irrelevant text and dashes from ISBN number -- Similar to that used for Special:BookSources function cleanisbn( isbn_str ) return isbn_str:gsub( "[^-0-9X]", "" ); end -- Determines whether an ISBN string is valid function checkisbn( isbn_str ) isbn_str = cleanisbn( 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 -- Gets the display text for a wikilink like [[A|B]] or [[B]] gives B function removewikilink( str ) return (str:gsub( "%[%[([^%[%]]*)%]%]", function(l) return l:gsub( "^[^|]*|(.*)$", "%1" ):gsub("^%s*(.-)%s*$", "%1"); end)); end -- Escape sequences for content that will be used for URL descriptions function safeforurl( str ) if str:match( "%[%[.-%]%]" ) ~= nil then table.insert( z.message_tail, { seterror( 'wikilink_in_url', {}, true ) } ); end return str:gsub( '[%[%]\n]', { ['['] = '[', [']'] = ']', ['\n'] = ' ' } ); end -- Protects a string that will be wrapped in wiki italic markup '' ... '' function safeforitalics( str ) --[[ Note: We can not use <i> for italics, as the expected behavior for italics specified by ''...'' in the title is that they will be inverted (i.e. unitalicized) in the resulting references. In addition, <i> and '' tend to interact poorly under Mediawiki's HTML tidy. ]] if not is_set(str) then return str; else if str:sub(1,1) == "'" then str = "<span />" .. str; end if str:sub(-1,-1) == "'" then str = str .. "<span />"; end -- Remove newlines as they break italics. return str:gsub( '\n', ' ' ); end end --[[ Return the year portion of a date string, if possible. Returns empty string if the argument can not be interpreted as a year. ]] function selectyear( str ) -- Is the input a simple number? local num = tonumber( str ); if num ~= nil and num > 0 and num < 2100 and num == math.floor(num) then return str; else -- Use formatDate to interpret more complicated formats local lang = mw.getContentLanguage(); local good, result; good, result = pcall( lang.formatDate, lang, 'Y', str ) if good then return result; else -- Can't make sense of this input, return blank. return ""; end end end --[[ Return a string formed joining Day, Month and Year. Month is checked only if Year is defined and Day is checked only if Month is defined If Month is a number try to convert in the corresponding name (1->gennaio, 2->febbraio...) otherwise dont change it ]] function Get_date(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 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 function article_date(date) local start = mw.ustring.sub(date,1,2) if inArray( start, {'08', '8 ', '8-', '8/', '11'} ) then return "l'" end return "il " end -- Controlla che il parametro tempo sia in un formato ammesso -- in caso contrario ritorna il codice di erore function check_time(Time) local h,m,s = string.match(Time, '^(%d+):(%d+):(%d+)$') if not(h) then h,m,s = string.match(Time, '^(%d+) h (%d+) min (%d+) s$') end if not(m) then m,s = string.match(Time, '^(%d+) min (%d+) s$') end if not(m) then m,s = string.match(Time, '^(%d+):(%d+)$') end if not(m) then m = string.match(Time, '^(%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 -- Attempts to convert names to initials. function reducetoinitials(first) local initials = {} for word in string.gmatch(first, "%S+") do table.insert(initials, string.sub(word,1,1)) -- Vancouver format does not include full stops. end return table.concat(initials) -- Vancouver format does not include spaces. end -- Formats a list of people (e.g. authors / editors) function listpeople(control, people) local sep = control.sep; local namesep = control.namesep 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}, namesep) 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 -- Generates a CITEREF anchor ID. function anchorid( options ) return "CITEREF" .. table.concat( options ); end -- Gets name list from the input arguments function extractnames(args, list_name) local names = {}; local i = 1; local last; while true do last = selectone( args, cfg.aliases[list_name .. '-Last'], 'redundant_parameters', i ); if not is_set(last) then first = selectone( args, cfg.aliases[list_name .. '-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 = selectone( args, cfg.aliases[list_name .. '-Link'], 'redundant_parameters', i ), } end else names[i] = { last = last, first = selectone( args, cfg.aliases[list_name .. '-First'], 'redundant_parameters', i ), link = selectone( args, cfg.aliases[list_name .. '-Link'], 'redundant_parameters', i ), }; end i = i + 1; end return names; end -- Populates ID table from arguments using configuration settings function extractids( args ) local id_list = {}; for k, v in pairs( cfg.id_handlers ) do v = selectone( 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 -- Takes a table of IDs and turns it into a table of formatted ID outputs. function buildidlist( id_list, options ) local new_list, handler = {}; function fallback(k) return { __index = function(t,i) return cfg.id_handlers[k][i] end } end; for k, v in pairs( id_list ) do -- fallback to read-only cfg handler = setmetatable( { ['id'] = v }, fallback(k) ); if handler.mode == 'external' then table.insert( new_list, {handler.label, externallinkid( handler ) } ); elseif handler.mode == 'internal' then table.insert( new_list, {handler.label, internallinkid( handler ) } ); elseif handler.mode ~= 'manual' then error( cfg.messages['unknown_ID_mode'] ); elseif k == 'DOI' then table.insert( new_list, {handler.label, doi( v, options.DoiBroken ) } ); elseif k == 'OL' then table.insert( new_list, {handler.label, openlibrary( v ) } ); elseif k == 'SBN' then table.insert (new_list, {handler.label, sbn(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 = internallinkid( handler ); if not checkisbn( v ) and not is_set(options.IgnoreISBN) then ISBN = ISBN .. seterror( 'bad_isbn', {}, false, "<sup>", "</sup>" ); end end table.insert( new_list, {handler.label, ISBN } ); else error( cfg.messages['unknown_manual_ID'] ); end end function comp( a, b ) return a[1] < b[1]; end table.sort( new_list, comp ); for k, v in ipairs( new_list ) do new_list[k] = v[2]; end return new_list; end -- Chooses one matching parameter from a list of parameters to consider -- Generates an error if more than one match is present. -- Return a pair value, selected where value is the value found and -- selected the key associated function selectone( 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, { seterror( error_condition, {error_str}, true ) } ); end return value, selected; end function citation0( config, args) --[[ Load Input Parameters The argment_wrapper facilitates the mapping of multiple aliases to single internal variable. ]] 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 Fragment.priority = Style.separator_priority -- 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 = extractnames( args, 'AuthorList' ); local Coauthors = A['Coauthors']; local Others = A['Others']; local Editors = A['Editors']; local e = extractnames( args, 'EditorList' ); ------------------------------------------------- Get date data local Year = A['Year']; local PublicationDate = A['PublicationDate']; local OrigDate = A['OrigDate']; local Date = A['Date']; local LayDate = A['LayDate']; ------------------------------------------------- Get title data local Title = A['Title']; local Conference = A['Conference']; local Organization = A['Organization'] local TransTitle = A['TransTitle']; -- 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 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 if config.CitationClass == "libro" and PositionOrigin=="pagine" 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") and PositionOrigin=="pagine" then if tonumber(Position) then Position = PPrefix .. Position else Position = PPPrefix .. Position end elseif PositionOrigin == "pagina" then Position = PPrefix .. Position else Position = PPPrefix .. Position end end end if inArray(config.CitationClass, { "video", "tv", "audio" } ) then local Hour = A['Hour'] local Minutes = A['Minutes'] local Seconds = A['Seconds'] local Time = A['Time'] local ComposeTime = {} local TimeError = {} if is_set(Hour) then if not is_set(Minutes) then TimeError[#TimeError+1] = seterror('need_minutes' , {'ora'}) end if not tonumber(Hour) then TimeError[#TimeError+1] = seterror('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] = seterror('timepar_must_be_integer', {'minuto'}) elseif check_error > 60 then TimeError[#TimeError+1] = seterror('minutes_wrong') end ComposeTime[#ComposeTime+1] = Minutes .. ' min' end if is_set(Seconds) then if not is_set(Minutes) then TimeError[#TimeError+1] = seterror('need_minutes', {'secondo'}) end local check_error = tonumber(Seconds) if not check_error then TimeError[#TimeError+1] = seterror('timepar_must_be_integer', {'ora'}) elseif check_error > 60 then TimeError[#TimeError+1] = seterror('seconds_wrong') end ComposeTime[#ComposeTime+1] = Seconds .. ' s' end if #ComposeTime > 1 then if is_set(Position) then TimeError[#TimeError+1] = seterror('time_parameter_conflict') end Position = 'a ' .. table.concat(ComposeTime, ' ') end if is_set(Time) then if is_set(Position) then TimeError[#TimeError+1] = seterror('time_parameter_conflict') end local check_error = check_time(Time) if check_error then TimeError[#TimeError+1] = seterror(check_error) end Position = 'a ' .. Time end if #TimeError > 0 then Position = Position .. " " .. table.concat(TimeError, ", ") 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 if is_set(Volume) then if tonumber(Volume) or A:ORIGIN('Volume') == "vol" then Volume = "vol. " .. Volume end end if is_set(Issue) then if tonumber(Issue) 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 AccessDate = A['AccessDate']; local ArchiveDate = A['ArchiveDate']; -- 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 = extractids( args ); if ( isPubblicazione ) then if not is_set(URL) and 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 = "http://www.ncbi.nlm.nih.gov/pmc/articles/PMC" .. ID_list['PMC']; URLorigin = cfg.id_handlers['PMC'].parameters[1]; end else URL = "http://www.ncbi.nlm.nih.gov/pmc/articles/PMC" .. ID_list['PMC']; URLorigin = cfg.id_handlers['PMC'].parameters[1]; end end end ID_list = buildidlist( 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 local SeriesLink = A['SeriesLink']; Chapter = Title; ChapterLink = TitleLink; TransChapter = TransTitle; Title = Series; TitleLink = SeriesLink; TransTitle = ''; Series = ''; 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 ------------------------------------------------------------------------------ -- Recupero e formatto lista autori ------------------------------------------------------------------------------ local AuthorSeparator = Style.peoplesep local control = { sep = AuthorSeparator, namesep = Style.namesep, maximum = Style.maximum_authors, lastsep = Style.lastsepauthor, invertorder = Style.invertorder, etal = false, coauthors = false, }; Etal = A['Etal'] -- If the coauthor field is also used, prevent adding ''et al.'' if is_set(Coauthors) then control.coauthors = true elseif is_set(Etal) then control.etal = true end Authors = listpeople(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 EditorCount, msg_editors local CuratoriEtal = A['Etalcuratori'] control.coauthors = false if is_set(CuratoriEtal) then control.etal = true else control.etal = false end if is_set(Editors) then msg_editors = 'editors' else Editors, EditorCount = listpeople(control, e) if is_set(Editors) then if EditorCount <= 1 then msg_editors = 'editor' else msg_editors = 'editors' end end end ------------------------------------------------------------------------------ -- Se non sono definiti autori sostituisco con curatori ------------------------------------------------------------------------------ if not is_set(Authors) and is_set(Editors) then Authors = Editors Editors = "" 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 ------------------------------------------------------------------------------ if not is_set(Date) then Date=Get_date(Year, A['Month'], A['Day']) end if not is_set(OrigDate) then OrigDate=Get_date(A['OrigYear'], A['OrigMonth'], A['OrigDay']) end if not is_set(AccessDate) then AccessDate=Get_date(A['AccessYear'], A['AccessMonth'], A['AccessDay']) end if is_set(OrigDate) and not is_set(Date) then Date = OrigDate OrigDate = "" end OrigDate = is_set(OrigDate) and (" " .. wrap( 'origdate', OrigDate)) or ""; if inArray(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 -- Test if cite web is called without giving a URL if ( config.CitationClass == "web" ) then table.insert( z.message_tail, { seterror( 'cite_web_url', {}, true ) } ); end -- Test if accessdate is given without giving a URL if is_set(AccessDate) then table.insert( z.message_tail, { seterror( 'accessdate_missing_url', {}, true ) } ); AccessDate = ''; end -- Test if format is given without giving a URL if is_set(Format) then Format = Format .. seterror( '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, { seterror( 'citation_missing_title', {}, true ) } ); end -- Se il formato esterno è tra quelli previsti imita lo stile dei template {{PDF}} o {{doc}} if is_set(Format) then local f = cfg.external_link_type[Format:lower()] if f then Format = table.concat({' (<span style="font-weight: bolder; font-size: smaller;">[[', f.link, '|', f.label, ']]</span>)'}) else Format = table.concat({' (', Format, ')'}) end else Format = "" end local OriginalURL = URL DeadURL = DeadURL:lower(); if is_set( ArchiveURL ) then if ( DeadURL ~= "no" ) 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 = externallink( ChapterURL, 'abstract' ) ChapterURL = "" if not is_set(URL) then Format = "" end elseif is_set(URL) then TitleType = externallink( 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 = " " .. seterror( 'trans_missing_chapter' ) Chapter = TransChapter TransChapter = "" else TransChapter = wrap( 'trans-italic-title', TransChapter ) end end Chapter = wrap( 'italic-title', 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 = externallink( 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 = externallink( URL, Chapter ) .. TransError .. Format; URL = ""; Format = ""; else Chapter = Chapter .. TransError; end elseif is_set(ChapterURL) then Chapter = externallink( ChapterURL, nil, ChapterURLorigin ) .. TransError end --------------------------------------------------------------- -- Format main title --------------------------------------------------------------- TransError = ""; if is_set(TransTitle) then if not is_set(Title) then TransError = " " .. seterror( 'trans_missing_title' ) Title = TransTitle TransTitle = "" else TransTitle = wrap( 'trans-italic-title', TransTitle ) end end Title = wrap('italic-title', 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 = externallink( URL, Title ) .. TransError .. 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 = externallink( ConferenceURL, Conference ); end elseif is_set(ConferenceURL) then Conference = externallink( ConferenceURL, nil, ConferenceURLorigin ); end --------------------------------------------------------------- -- Compone la stringa del linguaggio --------------------------------------------------------------- local Language_code = "" if is_set(Language) then if Language:sub(1,1) == "(" then Language_code = Language else local frame = {return_error='true', usacodice='sì'} for lingua in mw.ustring.gmatch(Language, "%S+") do frame[#frame+1] = lingua end if #frame > 1 or (#frame==1 and frame[1]:lower()~="it") then local lg_error local lg = require( "Modulo:Linguaggi" ); Language_code, lg_error = lg.lingue(frame) if lg_error and #lg_error > 0 then local error_string = mw.text.listToText(lg_error, ", ", " e " ) table.insert( z.message_tail, { seterror('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 -- se URL non è stato consumato da un capitolo/titolo emette errore if is_set(URL) then URL = " " .. externallink( 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 if not is_set(ArchiveDate) then ArchiveDate = seterror('archive_missing_date'); end ArchiveURL2 = A['ArchiveURL2'] if is_set(ArchiveURL2) then ArchiveDate2 = A['ArchiveDate2'] if not is_set(ArchiveDate2) then ArchiveDate2 = seterror('archive_missing_date2'); end end if DeadURL=="no" then Archived = substitute( cfg.messages['archived-not-dead'], { externallink( ArchiveURL, cfg.messages['archived'] ), ArchiveDate, article_date(ArchiveDate) } ); if not is_set(OriginalURL) then Archived = Archived .. " " .. seterror('archive_missing_url'); end elseif is_set(OriginalURL) then Archived = substitute( cfg.messages['archived-dead'], { OriginalURL, ArchiveDate, article_date(ArchiveDate) } ); else Archived = substitute( cfg.messages['archived-missing'], { seterror('archive_missing_url'), ArchiveDate, article_date(ArchiveDate) } ); end if is_set(ArchiveURL2) then Archived = Archived .. ". " .. substitute(cfg.messages['archived-second-copy'], { externallink( ArchiveURL2, cfg.messages['archived2']), ArchiveDate2, article_date(ArchiveDate2)}); end else Archived = "" end --------------------------------------------------------------- -- Data originale se presente (in ordine di preferenza -- dopo l'editore, il luogo di pubblicazione, la data di pubblicazione) --------------------------------------------------------------- if is_set(OrigDate) then if is_set(PublisherName) then PublisherName = PublisherName .. " " .. OrigDate elseif is_set(Place) then Place = Place .. " " .. OrigDate else Date = Date .. " " .. OrigDate end end -- Several of the above rely upon detecting this as nil, so do it last. if is_set(Periodical) then Periodical = wrap( 'italic-title', Periodical ) end if config.CitationClass=="news" and is_set(Place) then if is_set(Periodical) then Periodical = table.concat({Periodical, ' (', Place, ')'}) Place = "" elseif is_set(Title) then Title = table.concat({Title, ' (', Place, ')'}) Place = "" end end --------------------------------------------------------------- -- Combino insieme i vari componenti della citazione --------------------------------------------------------------- local Fragment_Title if is_set(Title) then fragment_Title = Fragment.new({Title, Format, TitleType}, ' '):last(",") else fragment_Title = Fragment.new({}) if is_set(Chapter) then Chapter = tostring(Fragment.new({Chapter, Format, TitleType}, ' ')) 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(Authors) and is_set(Editors) and is_set(Title) and not is_set(Chapter) then Editors = 'a cura di ' .. Editors fragment_citation = Fragment.new({Authors}, sepc) fragment_citation:appends({fragment_Title, Editors}) else if is_set(msg_editors) then if is_set(Editors) then Editors = wrap(msg_editors, Editors) else Authors = wrap(msg_editors, Authors) end end fragment_citation = Fragment.new({Authors, Chapter}, sepc) if Chapter ~= "" or Editors ~= "" then if A:ORIGIN('Periodical') == 'sito' then -- antepone "su" anzichè "in" per i siti web fragment_citation:last("su") else fragment_citation:last("in") end end fragment_citation:appends({Editors, fragment_Title}) end end fragment_citation:appends({Conference, Periodical, Others, Series, Volume, Issue, Edition, 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_Abstract =Fragment.new(Abstract):start(".") local fragment_AccessInfo = Fragment.new({AccessDate, Via, Archived}, " "):start(".") local fragment_Quote = Fragment.new({Quote}):start(".") fragment_citation:appends({fragment_ID_list, fragment_URL, fragment_AccessInfo, fragment_Quote}) if PostScript == 'nessuno' then fragment_citation:last("nothing") else fragment_citation:last("..") end fragment_citation:start(" ") local text = Language_code .. tostring(fragment_citation) --aggiungo l'icona per cita video 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 = seterror('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 .. errorcomment( v[1], v[2] ); else text = text .. errorcomment( 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 inArray(no_tracking_cats, {"", "no", "false", "n"}) then for _, v in ipairs( z.error_categories ) do text = text .. '[[Categoria:' .. v ..']]'; end end return text end -- This is used by templates such as {{cite book}} to create the actual citation text. 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 -- copy unnamed parameter to named parameter local lastunnamed = 0 if 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 = seterror( 'text_ignored', {v}, true ); end elseif validate( k:lower() ) then error_text, error_state = seterror( 'parameter_ignored_suggest', {k, k:lower()}, true ); else if #suggestions == 0 then suggestions = mw.loadData( 'Modulo:Citazione/Suggerimenti' ); end if suggestions[ k:lower() ] ~= nil then error_text, error_state = seterror( 'parameter_ignored_suggest', {k, suggestions[ k:lower() ]}, true ); else error_text, error_state = seterror( '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 inArray(config.CitationClass, {"googlebooks", "video"}) then args.id = nil end end return citation0( config, args) end -- Elenco i formati di documenti gestiti function z.list_external_links(frame) local rows = {'{| class = "wikitable sortable"\n!codice!!collegamento!!visualizzato come'} 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] = '|-\n|' .. key .. '|| [[' .. cfg.external_link_type[key].link .. ']] || (<span style="font-weight: bolder; font-size: smaller;">' .. cfg.external_link_type[key].label .. '</span>)' end rows[#rows+1] = "|}" return table.concat(rows, '\n') end return z -- Parametri rimossi: Cite map e relativi parametri esclusivi cartography, scale, inset, section -- Revision history -- 13/6/2013 importato dalla revisione 555909894 del 20/5/2013 da [[:en:Module:Citation/CS1]] -- 20/6/2013 inserito gestione stili per la citazione liste di persone, pulizia o rimozione con -- commento di codice non necessario per it.wikipedia, aggiunta riconoscimento codici -- lingue, aggiunto gestione parametri posizionali, hack per il parametro cid di cita web/video