Mòdul:Citation/CS1
Documentació del mòdul [ mostra ] [ modifica el codi ] [ mostra l'historial ] [ refresca ]
A continuació es mostra la documentació transclosa de la subpàgina /ús. [salta a la caixa de codi]
local z = { error_categories = {}; error_ids = {}; message_tail = {};}-- Include translation message hooks, ID and error handling configuration settings.local cfg = mw.loadData( 'Module:Citation/CS1/Configuration' );-- Contains a list of all recognized parameterslocal whitelist = mw.loadData( 'Module:Citation/CS1/Whitelist' );-- Whether variable is set or notfunction is_set( var ) return not (var == nil or var == '');end-- First set variable or nil if nonefunction first_set(...) local list = {...}; for _, var in pairs(list) do if is_set( var ) then return var; end endend-- Whether needle is in haystackfunction 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--[[Categorize and emit an error message when the citation contains one or more deprecated parameters. Because deprecated parameters (currently |day=, |month=,|coauthor=, and |coauthors=) aren't related to each other and because these parameters may be concatenated into the variables used by |date= and |author#= (and aliases)details of which parameter caused the error message are not provided. Only one error message is emitted regarless of the number of deprecated parameters in the citation.]]function deprecated_parameter()if true ~= Page_in_deprecated_cat then-- if we haven't been here before then set a Page_in_deprecated_cat=true;-- sticky flag so that if there are more than one deprecated parameter the category is added only oncetable.insert( z.message_tail, { seterror( 'deprecated_params', {error_message}, true ) } );-- add error messageendend-- Populates numbered arguments in a message string using an argument table.function substitute( msg, args ) return args and tostring( mw.message.newRawMessage( msg, args ) ) or msg;end-- Wraps a string using a message_list configuration taking one argumentfunction 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--[[Argument wrapper. This function provides support for argument mapping defined in the configuration file so that multiple namescan 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--[[Looks for a parameter's name in the whitelist.Parameters in the whitelist can have three valuse:true - active, supported parametersfalse - deprecated, supported parametersnil - unsupported parameters]]function validate( name )local name = tostring( name );local state = whitelist.basic_arguments[ name ];-- Normal argumentsif true == state then return true; end-- valid actively supported parameterif false == state thendeprecated_parameter ();-- parameter is deprecated but still supportedreturn true;end-- Arguments with numbers in themname = name:gsub( "%d+", "#" );-- replace digit(s) with # (last25 becomes last#state = whitelist.numbered_arguments[ name ];if true == state then return true; end-- valid actively supported parameterif false == state thendeprecated_parameter ();-- parameter is deprecated but still supportedreturn true;endreturn false;-- Not supported because not found or name is set to nilend-- Formats a comment for error trappingfunction 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 placementof 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-- Formats a wiki style external linkfunction externallinkid(options) local url_string = 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 linkfunction 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 checkingfunction 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 link to Amazonfunction amazon(id, domain) if not is_set(domain) then domain = "com" elseif ( "jp" == domain or "uk" == domain ) then domain = "co." .. domain end local handler = cfg.id_handlers['ASIN']; return externallinkid({link = handler.link, label=handler.label , prefix="//www.amazon."..domain.."/dp/",id=id, encode=handler.encode, separator = handler.separator})end--[[Determines if a PMC identifier's online version is embargoed. Compares the date in |embargo= against today's date. If embargo date isin the future, returns true; otherwse, returns false because the embargo has expired or |embargo= not set in this cite.]]function is_embargoed(embargo)if is_set(embargo) thenlocal lang = mw.getContentLanguage();local good1, embargo_date, good2, todays_date;good1, embargo_date = pcall( lang.formatDate, lang, 'U', embargo );good2, todays_date = pcall( lang.formatDate, lang, 'U' );if good1 and good2 and tonumber( embargo_date ) >= tonumber( todays_date ) then--is embargo date is in the future?return true;-- still embargoedendendreturn false;-- embargo expired or |embargo= not setend--[[Formats a PMC and checks for embargoed articles. The embargo parameter takes a date for a value. If the embargo date is in the futurethe PMC identifier will not be linked to the article. If the embargo specifies a date in the past, or if it is empty or omitted, thenthe PMC identifier is linked to the article through the link at cfg.id_handlers['PMC'].prefix.]]function pmc(id, embargo)local handler = cfg.id_handlers['PMC']; local text;if is_embargoed(embargo) thentext="[[" .. handler.link .. "|" .. handler.label .. "]]:" .. handler.separator .. id;--still embargoed so no external linkelsetext = externallinkid({link = handler.link, label = handler.label,--no embargo date, ok to link to articleprefix=handler.prefix,id=id,separator=handler.separator, encode=handler.encode})endreturn text;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) thenlocal inactive_year = inactive:match("%d%d%d%d") or '';-- try to get the year portion from the inactive datetext = "[[" .. handler.link .. "|" .. handler.label .. "]]:" .. id;if is_set(inactive_year) thentable.insert( z.error_categories, "Pages with DOIs inactive since " .. inactive_year );elsetable.insert( z.error_categories, "Pages with inactive DOIs" );-- when inactive doesn't contain a recognizable yearendinactive = " (" .. 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 = "" endif ( string.sub(id,1,3) ~= "10." ) then cat = seterror( 'bad_doi' );endreturn 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' ); endend--[[Validate and format an issn. This code fixes the case where an editor has included an ISSN in the citation but has separated the two groups of fourdigits with a space. When that condition occurred, the resulting link looked like this:|issn=0819 4327 gives: [http://www.worldcat.org/issn/0819 4327 0819 4327] -- can't have spaces in an external linkThis code now prevents that by inserting a hyphen at the issn midpoint. It also validates the issn for length and makes sure that the checkdigit agreeswith the calculated value. Incorrect length (8 digits), characters other than 0-9 and X, or checkdigit / calculated value mismatch will all cause a check issnerror message. The issn is always displayed with a hyphen, even if the issn was given as a single group of 8 digits.]]function issn(id)local issn_copy = id;-- save a copy of unadulterated issn; use this version for display if issn does not validatelocal handler = cfg.id_handlers['ISSN'];local text;local valid_issn = true;id=id:gsub( "[%s-–]", "" );-- strip spaces, hyphens, and ndashes from the issnif 8 ~= id:len() or nil == id:match( "^%d*X?$" ) then-- validate the issn: 8 didgits long, containing only 0-9 or X in the last positionvalid_issn=false;-- wrong length or improper characterelsevalid_issn=is_valid_isxn(id, 8);-- validate issnendif true == valid_issn thenid = string.sub( id, 1, 4 ) .. "-" .. string.sub( id, 5 );-- if valid, display correctly formatted versionelseid = issn_copy;-- if not valid, use the show the invalid issn with error messageendtext = externallinkid({link = handler.link, label = handler.label,prefix=handler.prefix,id=id,separator=handler.separator, encode=handler.encode}) if false == valid_issn thentext = text .. ' ' .. seterror( 'bad_issn' )-- add an error message if the issn is invalidend return textend--[[This function sets default title types (equivalent to the citation including |type=<default value>) for those citations that have defaults.Also handles the special case where it is desireable to omit the title type from the rendered citation (|type=none).]]function set_titletype(cite_class, title_type)if is_set(title_type) thenif "none" == title_type thentitle_type = "";-- if |type=none then type parameter not displayedendreturn title_type;-- if |type= has been set to any other value use that valueendif "pressrelease" == cite_class then-- if this citation is cite press releasereturn "Press release";-- display press release annotationelseif "speech" == cite_class then-- if this citation is cite speechreturn "Speech";-- display speech annotationelseif "techreport" == cite_class then-- if this citation is cite techreportreturn "Technical report";-- display techreport annotationelseif "thesis" == cite_class then-- if this citation is cite thesis (degree option handled after this function returns)return "Thesis";-- display simple thesis annotation (without |degree= modification)endend-- returns a number according to the month in a date: 1 for January, etc. If not a valid month, returns 0function get_month_number (month)local long_months = {['january']=1, ['february']=2, ['march']=3, ['april']=4, ['may']=5, ['june']=6, ['july']=7, ['august']=8, ['september']=9, ['october']=10, ['november']=11, ['december']=12};local short_months = {['jan']=1, ['feb']=2, ['mar']=3, ['apr']=4, ['may']=5, ['jun']=6, ['jul']=7, ['aug']=8, ['sep']=9, ['oct']=10, ['nov']=11, ['dec']=12};local temp;temp=long_months[month:lower()];if temp then return temp; end-- if month is the long-form nametemp=short_months[month:lower()];if temp then return temp; end-- if month is the short-form namereturn 0;-- misspelled or not a month nameend-- returns true if date has one of the five seasons. Else false.function is_valid_season (season)if inArray( season, {'winter', 'spring', 'summer', 'fall', 'autumn'} ) thenreturn true;endreturn false;end--[[Returns true if day is less than or equal to the number of days in month; else returns false.Assumes Julian calendar prior to year 1582 and Gregorian calendar thereafter. Accounts for Julian calendar leap years before 1582 and Gregorian leap years after 1582.Where the two calendars overlap (1582 to approximately 1923) dates are assumed to be Gregorian.]]function is_valid_date (year, month, day)local days_in_month = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};local month_length;if (2==month) then-- if Februarymonth_length = 28;-- then 28 days unlessif 1582 > tonumber(year) then-- Julian calendarif 0==(year%4) thenmonth_length = 29;endelse-- Gregorian calendarif (0==(year%4) and (0~=(year%100) or 0==(year%400))) then-- is a leap year?month_length = 29;-- if leap year then 29 days in Februaryendendelsemonth_length=days_in_month[month];endif tonumber (day) > month_length thenreturn false;endreturn true;end--Check a pair of months or seasons to see if both are valid members of a month or season pair.--TODO: Check order to make sure that the left month/season properly precedes the right month/seasonfunction is_valid_month_season_range(range_start, range_end)if 0 == get_month_number (range_start:lower()) then-- is this a month range?if true == is_valid_season (range_start:lower()) then-- not a month range, is this a season range?return is_valid_season (range_end:lower());-- range_start is season; return true if range_end also a season; else falseendreturn false;-- range_start is not a month or a seasonendif 0 == get_month_number (range_end:lower()) then-- range_start is a month; is range_end also a month?return false;-- not a month rangeendreturn true;end--[[Check date format to see that it is one of the formats approved by MOS:DATE: MMMM D, YYYY; D MMMM YYYY; MMMM YYYY; YYYY-MM-DD; YYYY.Additionally, check the date to see that it is a real date: no 31 in 30-day months; no 29 February when not a leap year. Months, both long-form and threecharacter abbreviations, and seasons must be spelled correctly.If the date fails the fomat tests, this function returns false but does not return values for anchor_year and COinS_date. When this happens, the date parameter isused in the COinS metadata and the CITEREF identifier gets its year from the year parameter if present.Inputs:date_string - date string from date-holding parameters (date, year, accessdate, embargo, archivedate, etc)Returns:false if date string is not a real date; elsetrue, anchor_year, COinS_dateanchor_year can be used in CITEREF anchorsCOinS_date is date_string without anchor_year disambiguator if any]]function check_date (date_string)local year;local month;local day;local anchor_year;local coins_date;if date_string:match("^%d%d%d%d%-%d%d%-%d%d$") then-- Year-initial numerical year month day formatcoins_date = date_string:match("%d%d%d%d%-%d%d%-%d%d");year, month, day=string.match(date_string, "(%d%d%d%d)%-(%d%d)%-(%d%d)");anchor_year = year;month=tonumber(month);if 12 < month or 1 > month then return false; endelseif date_string:match("^%a+%s*%d%d*%s*,%s*%d%d%d%d%a?$") then-- month-initial: month day, yearcoins_date = date_string:match("%a+%s*%d%d*%s*,%s*%d%d%d%d");month, day, anchor_year, year=string.match(date_string, "(%a+)%s*(%d%d*)%s*,%s*((%d%d%d%d)%a?)");month = get_month_number (month:lower());if 0 == month then return false; end-- return false if month text isn't one of the twelve monthselseif date_string:match("^%d%d*%s*%a+%s*%d%d%d%d%a?$") then-- date-initial: day month yearcoins_date = date_string:match("%d%d*%s*%a+%s*%d%d%d%d");day, month, anchor_year, year=string.match(date_string, "(%d%d*)%s*(%a+)%s*((%d%d%d%d)%a?)");month = get_month_number (month:lower());if 0 == month then return false; end-- return false if month text isn't one of the twelve monthselseif mw.ustring.match (date_string, "^%a+%s*[%s%-/–]%s*%a+%s*%d%d%d%d%a?$") then-- month/season range yearlocal month2coins_date = mw.ustring.match (date_string, "%a+%s*[%s%-/–]%s*%a+%s*%d%d%d%d");coins_date= mw.ustring.gsub( coins_date, "–", "-" );-- replace ndash with hyphenmonth, month2, anchor_year, year=mw.ustring.match (date_string, "(%a+)%s*[%s%-/–]%s*(%a+)%s*((%d%d%d%d)%a?)");day=0;-- mark day as not usedif false == is_valid_month_season_range(month, month2) thenreturn false;endelseif date_string:match("^%a+%s*%d%d%d%d%a?$") then-- month/season yearcoins_date = date_string:match("%a+%s*%d%d%d%d");month, anchor_year, year=string.match(date_string, "(%a+)%s*((%d%d%d%d)%a?)");day=0;-- mark day as not usedlocal season=month;-- copy month = get_month_number (month:lower());if month == 0 then-- if month text isn't one of the twelve months, might be a seasonif false == is_valid_season (season:lower()) thenreturn false;-- return false not a month or one of the five seasonsendendelseif date_string:match("^%d%d%d%d?%a?$") then-- year; here accept either YYY or YYYYcoins_date = date_string:match("^%d%d%d%d?");anchor_year, year=string.match(date_string, "((%d%d%d%d?)%a?)");month, day = 0, 0;-- mark day and month as not usedelsereturn false;-- date format not one of the MOS:DATE approved formatsendif 0~=month and 0~=day then-- check year month day dates for validityif false==is_valid_date(year,month,day) thenreturn false;-- date string is not a real date return false; unset anchor_year and coins_dateendendreturn true, anchor_year, coins_date;-- format is good and date string represents a real dateend--[[Cycle the date-holding parameters in passed table date_parameters_list through check_date() to check compliance with MOS:DATE. For all valid dates, check_date() returnstrue and values for anchor_year (used in CITEREF identifiers) and COinS_date (used in the COinS metadata). The |date= parameter test is unique. This function only accepts anchor_year and COinS_date results from the |date= parameter test and |date= is the only date-holding parameter that is allowed to contain the no-date keywords"n.d." or "nd" (without quotes).Unlike most error messages created in this module, only one error message is created by this function. Because all of the date holding parameters are processed serially,a single error message is created as the dates are tested.]]function dates(date_parameters_list)local anchor_year;-- will return as nil if the date being tested is not |date=local COinS_date;-- will return as nil if the date being tested is not |date=local error_message ="";local good_date=false;for k, v in pairs(date_parameters_list) do-- for each date-holding parameter in the listif is_set(v) then-- if the parameter has a valueif v:match("^c%.%s%d%d%d%d?%a?$") then-- special case for c. year or with or without CITEREF disambiguator - only |date= and |year=if 'date'==k thengood_date, anchor_year, COinS_date = true, v:match("((c%.%s%d%d%d%d?)%a?)");-- anchor year and COinS_date only from |date= parameterelseif 'year'==k thengood_date = true;endelseif 'year'==k then-- if the parameter is |year= (but not c. year)if v:match("^%d%d%d%d?%a?$") then-- year with or without CITEREF disambiguatorgood_date = true;endelseif 'date'==k then-- if the parameter is |date=if v:match("n%.d%.%a?") then-- if |date=n.d. with or without a CITEREF disambiguatorgood_date, anchor_year, COinS_date = true, v:match("((n%.d%.)%a?)");--"n.d."; no error when date parameter is set to no dateelseif v:match("nd%a?$") then-- if |date=nd with or without a CITEREF disambiguatorgood_date, anchor_year, COinS_date = true, v:match("((nd)%a?)");--"nd";no error when date parameter is set to no dateelsegood_date, anchor_year, COinS_date = check_date (v);-- go test the dateendelse-- any other date-holding parametergood_date = check_date (v);-- go test the dateendif false==good_date then-- assemble one error message so we don't add the tracking category multiple timesif is_set(error_message) then-- once we've added the first portion of the error message ...error_message=error_message .. ", ";-- ... add a comma space separatorenderror_message=error_message .. "|" .. k .. "=";-- add the failed parameterendendendif is_set(error_message) thentable.insert( z.message_tail, { seterror( 'bad_date', {error_message}, true ) } );-- add this error messageendreturn anchor_year, COinS_date;-- and doneend--[[Determines whether a URL string is validAt 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:BookSourcesfunction cleanisbn( isbn_str ) return isbn_str:gsub( "[^-0-9X]", "" );end--[[ISBN-10 and ISSN validator code calculates checksum across all isbn/issn digits including the check digit. ISBN-13 is checked in checkisbn().If the number is valid the result will be 0. Before calling this function, issbn/issn must be checked for length and stripped of dashes,spaces and other non-isxn characters.]]function is_valid_isxn (isxn_str, len)local temp = 0;isxn_str = { isxn_str:byte(1, len) };-- make a table of byteslen = len+1;-- adjust to be a loop counterfor i, v in ipairs( isxn_str ) do-- loop through all of the bytes and calculate the checksumif v == string.byte( "X" ) then-- if checkdigit is Xtemp = temp + 10*( len - i );-- it represents 10 decimalelsetemp = temp + tonumber( string.char(v) )*(len-i);endendreturn temp % 11 == 0;-- returns true if calculation result is zeroend-- Determines whether an ISBN string is validfunction checkisbn( isbn_str )if nil ~= isbn_str:match("[^%s-0-9X]") then return false; end-- fail if isbn_str contains anything but digits, hyphens, or the uppercase Xisbn_str = isbn_str:gsub( "-", "" ):gsub( " ", "" );-- remove hyphens and spaceslocal len = isbn_str:len(); if len ~= 10 and len ~= 13 thenreturn false;endif len == 10 thenif isbn_str:match( "^%d*X?$" ) == nil then return false; endreturn is_valid_isxn(isbn_str, 10);elselocal temp = 0;if isbn_str:match( "^97[89]%d*$" ) == nil then return false; end-- isbn13 begins with 978 or 979isbn_str = { isbn_str:byte(1, len) };for i, v in ipairs( isbn_str ) dotemp = temp + (3 - 2*(i % 2)) * tonumber( string.char(v) );endreturn temp % 10 == 0;endend-- Gets the display text for a wikilink like [[A|B]] or [[B]] gives Bfunction 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 descriptionsfunction safeforurl( str ) if str:match( "%[%[.-%]%]" ) ~= nil then table.insert( z.message_tail, { seterror( 'wikilink_in_url', {}, true ) } ); end return str:gsub( '[%[%]\n]', { ['['] = '[', [']'] = ']', ['\n'] = ' ' } );end-- Converts a hyphen to a dashfunction hyphentodash( str ) if not is_set(str) or str:match( "[%[%]{}<>]" ) ~= nil then return str; end return str:gsub( '-', '–' );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></span>" .. str; end if str:sub(-1,-1) == "'" then str = str .. "<span></span>"; end -- Remove newlines as they break italics. return str:gsub( '\n', ' ' ); endend--[[Joins a sequence of strings together while checking for duplicate separationcharacters.]]function safejoin( tbl, duplicate_char ) --[[ Note: we use string functions here, rather than ustring functions. This has considerably faster performance and should work correctly as long as the duplicate_char is strict ASCII. The strings in tbl may be ASCII or UTF8. ]] local str = ''; local comp = ''; local end_chr = ''; local trim; for _, value in ipairs( tbl ) do if value == nil then value = ''; end if str == '' then str = value; elseif value ~= '' then if value:sub(1,1) == '<' then -- Special case of values enclosed in spans and other markup. comp = value:gsub( "%b<>", "" ); else comp = value; end if comp:sub(1,1) == duplicate_char then trim = false; end_chr = str:sub(-1,-1); -- str = str .. "<HERE(enchr=" .. end_chr.. ")" if end_chr == duplicate_char then str = str:sub(1,-2); elseif end_chr == "'" then if str:sub(-3,-1) == duplicate_char .. "''" then str = str:sub(1, -4) .. "''"; elseif str:sub(-5,-1) == duplicate_char .. "]]''" then trim = true; elseif str:sub(-4,-1) == duplicate_char .. "]''" then trim = true; end elseif end_chr == "]" then if str:sub(-3,-1) == duplicate_char .. "]]" then trim = true; elseif str:sub(-2,-1) == duplicate_char .. "]" then trim = true; end elseif end_chr == " " then if str:sub(-2,-1) == duplicate_char .. " " then str = str:sub(1,-3); end end if trim then if value ~= comp then local dup2 = duplicate_char; if dup2:match( "%A" ) then dup2 = "%" .. dup2; end value = value:gsub( "(%b<>)" .. dup2, "%1", 1 ) else value = value:sub( 2, -1 ); end end end str = str .. value; end end return str;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 format = control.format local maximum = control.maximum local lastauthoramp = control.lastauthoramp; local text = {} local etal = false; if sep:sub(-1,-1) ~= " " then sep = sep .. " " end if maximum ~= nil and maximum < 1 then return "", 0; end for i,person in ipairs(people) do if is_set(person.last) then local mask = person.mask local one local sep_one = sep; if maximum ~= nil and i > maximum then etal = true; break; elseif (mask ~= nil) then local n = tonumber(mask) if (n ~= nil) then one = string.rep("—",n) else one = mask; sep_one = " "; end else one = person.last local first = person.first if is_set(first) then if ( "vanc" == format ) then first = reducetoinitials(first) end one = one .. namesep .. first end if is_set(person.link) then one = "[[" .. person.link .. "|" .. one .. "]]" end end table.insert( text, one ) table.insert( text, sep_one ) end end local count = #text / 2; if count > 0 then if count > 1 and is_set(lastauthoramp) and not etal then text[#text-2] = " & "; end text[#text] = nil; end local result = table.concat(text) -- construct list if etal then local etal_text = cfg.messages['et al']; result = result .. " " .. etal_text; end -- if necessary wrap result in <span> tag to format in Small Caps if ( "scap" == format ) then result = '<span class="smallcaps" style="font-variant:small-caps">' .. result .. '</span>'; end return result, countend-- Generates a CITEREF anchor ID.function anchorid( options ) return "CITEREF" .. table.concat( options );end-- Gets name list from the input argumentsfunction 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 -- just in case someone passed in an empty parameter break; end 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 ), mask = selectone( args, cfg.aliases[list_name .. '-Mask'], 'redundant_parameters', i ) }; i = i + 1; end return names;end-- Populates ID table from arguments using configuration settingsfunction 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 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 == 'ASIN' then table.insert( new_list, {handler.label, amazon( v, options.ASINTLD ) } ); elseif k == 'OL' then table.insert( new_list, {handler.label, openlibrary( v ) } ); elseif k == 'PMC' then table.insert( new_list, {handler.label, pmc( v, options.Embargo ) } ); elseif k == 'ISSN' then table.insert( new_list, {handler.label, issn( v ) } ); elseif k == 'ISBN' then local ISBN = internallinkid( handler ); if not checkisbn( v ) and not is_set(options.IgnoreISBN) then ISBN = ISBN .. seterror( 'bad_isbn', {}, false, " ", "" ); end table.insert( new_list, {handler.label, ISBN } ); else error( cfg.messages['unknown_manual_ID'] ); end end function comp( a, b )-- used in following table.sort() 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.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, 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, v ); else value = args[v]; selected = v; end end end if #error_list > 0 then local error_str = ""; for _, k in ipairs( error_list ) do if error_str ~= "" then error_str = error_str .. cfg.messages['parameter-separator'] end error_str = error_str .. wrap( 'parameter', k ); end if #error_list > 1 then error_str = error_str .. cfg.messages['parameter-final-separator']; else error_str = error_str .. cfg.messages['parameter-pair-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-- COinS metadata (see <http://ocoins.info/>) allows automated tools to parse-- the citation information.function COinS(data) if 'table' ~= type(data) or nil == next(data) then return ''; end local ctx_ver = "Z39.88-2004"; -- treat table strictly as an array with only set values. local OCinSoutput = setmetatable( {}, { __newindex = function(self, key, value) if is_set(value) then rawset( self, #self+1, table.concat{ key, '=', mw.uri.encode( removewikilink( value ) ) } ); end end }); if is_set(data.Chapter) then OCinSoutput.rft_val_fmt = "info:ofi/fmt:kev:mtx:book"; OCinSoutput["rft.genre"] = "bookitem"; OCinSoutput["rft.btitle"] = data.Chapter; OCinSoutput["rft.atitle"] = data.Title; elseif is_set(data.Periodical) then OCinSoutput.rft_val_fmt = "info:ofi/fmt:kev:mtx:journal"; OCinSoutput["rft.genre"] = "article"; OCinSoutput["rft.jtitle"] = data.Periodical; OCinSoutput["rft.atitle"] = data.Title; else OCinSoutput.rft_val_fmt = "info:ofi/fmt:kev:mtx:book"; OCinSoutput["rft.genre"] = "book" OCinSoutput["rft.btitle"] = data.Title; end OCinSoutput["rft.place"] = data.PublicationPlace; OCinSoutput["rft.date"] = data.Date; OCinSoutput["rft.series"] = data.Series; OCinSoutput["rft.volume"] = data.Volume; OCinSoutput["rft.issue"] = data.Issue; OCinSoutput["rft.pages"] = data.Pages; OCinSoutput["rft.edition"] = data.Edition; OCinSoutput["rft.pub"] = data.PublisherName; for k, v in pairs( data.ID_list ) do local id, value = cfg.id_handlers[k].COinS; if k == 'ISBN' then value = cleanisbn( v ); else value = v; end if string.sub( id or "", 1, 4 ) == 'info' then OCinSoutput["rft_id"] = table.concat{ id, "/", v }; else OCinSoutput[ id ] = value; end end local last, first; for k, v in ipairs( data.Authors ) do last, first = v.last, v.first; if k == 1 then if is_set(last) then OCinSoutput["rft.aulast"] = last; end if is_set(first) then OCinSoutput["rft.aufirst"] = first; end end if is_set(last) and is_set(first) then OCinSoutput["rft.au"] = table.concat{ last, ", ", first }; elseif is_set(last) then OCinSoutput["rft.au"] = last; end end OCinSoutput.rft_id = data.URL; OCinSoutput.rfr_id = table.concat{ "info:sid/", mw.site.server:match( "[^/]*$" ), ":", data.RawPage }; OCinSoutput = setmetatable( OCinSoutput, nil ); -- sort with version string always first, and combine. table.sort( OCinSoutput ); table.insert( OCinSoutput, 1, "ctx_ver=" .. ctx_ver ); -- such as "Z39.88-2004" return table.concat(OCinSoutput, "&");end--[[This is the main function doing the majority of the citationformatting.]]function citation0( config, args) --[[ Load Input Parameters The argment_wrapper facillitates the mapping of multiple aliases to single internal variable. ]] local A = argument_wrapper( args ); local i local PPrefix = A['PPrefix'] local PPPrefix = A['PPPrefix'] if is_set( A['NoPP'] ) then PPPrefix = "" PPrefix = "" end -- 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' ); local Year = A['Year']; local PublicationDate = A['PublicationDate']; local OrigYear = A['OrigYear']; local Date = A['Date']; local LayDate = A['LayDate']; ------------------------------------------------- Get title data local Title = A['Title']; local BookTitle = A['BookTitle']; local Conference = A['Conference']; 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 Degree = A['Degree']; local Docket = A['Docket']; 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 Periodical = A['Periodical'];--[[Parameter remapping for cite encyclopedia:When the citation has these parameters:|encyclopedia and |title then map |title to |article and |encyclopedia to |title|encyclopedia and |article then map |encyclopedia to |title|encyclopedia then map |encyclopedia to |title|trans_title maps to |trans_chapter when |title is re-mappedAll other combinations of |encyclopedia, |title, and |article are not modified]]if ( config.CitationClass == "encyclopaedia" ) thenif is_set(Periodical) then-- Periodical is set when |encyclopedia is setif is_set(Title) thenif not is_set(Chapter) thenChapter = Title;-- |encyclopedia and |title are set so map |title to |article and |encyclopedia to |titleTransChapter = TransTitle;Title = Periodical;Periodical = '';-- redundant so unsetTransTitle = '';-- redundant so unsetendelse-- |title not setTitle = Periodical;-- |encyclopedia set and |article set or not set so map |encyclopedia to |titlePeriodical = '';-- redundant so unsetendendendlocal Series = A['Series']; local Volume = A['Volume']; local Issue = A['Issue']; local Position = ''; local Page, Pages, At, page_type; Page = A['Page']; Pages = hyphentodash( A['Pages'] ); At = A['At']; if is_set(Page) then if is_set(Pages) or is_set(At) then Page = Page .. " " .. seterror('extra_pages'); Pages = ''; At = ''; end elseif is_set(Pages) then if is_set(At) then Pages = Pages .. " " .. seterror('extra_pages'); At = ''; end end local Edition = A['Edition']; local PublicationPlace = A['PublicationPlace'] local Place = A['Place']; if not is_set(PublicationPlace) and is_set(Place) then PublicationPlace = Place; end if PublicationPlace == Place then Place = ''; end local PublisherName = A['PublisherName']; local RegistrationRequired = A['RegistrationRequired']; 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'];-- Special case for cite techreport.local ID = A['ID'];if (config.CitationClass == "techreport") then-- special case for cite techreportif is_set(Issue) then-- cite techreport uses 'number', which other citations aliase to 'issue'if not is_set(ID) then-- can we use ID for the "number"?ID = Issue;-- yes, use itIssue = "";-- unset Issue so that "number" isn't duplicated in the rendered citation or COinS metadataelse-- can't use ID so emit error messageID = ID .. " " .. seterror('redundant_parameters', '<code>|id=</code> and <code>|number=</code>');endendend local ASINTLD = A['ASINTLD']; local IgnoreISBN = A['IgnoreISBN']; local Embargo = A['Embargo']; local ID_list = extractids( args ); local Quote = A['Quote']; local PostScript = A['PostScript']; local LayURL = A['LayURL']; local LaySource = A['LaySource']; local Transcript = A['Transcript']; local TranscriptURL = A['TranscriptURL'] local TranscriptURLorigin = A:ORIGIN('TranscriptURL'); local sepc = A['Separator']; local LastAuthorAmp = A['LastAuthorAmp']; local no_tracking_cats = A['NoTracking']; local use_lowercase = ( sepc ~= '.' ); local this_page = mw.title.getCurrentTitle(); --Also used for COinS and for language 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 endlocal anchor_year;-- used in the CITEREF identifierlocal COinS_date;-- used in the COinS metadata-- legacy: promote concatenation of |day=, |month=, and |year= to Date if Date not set; or, promote PublicationDate to Date if neither Date nor Year are set.if not is_set(Date) thenDate = Year;-- promote Year to DateYear = nil;-- make nil so Year as empty string isn't used for CITEREFif is_set(Date) thenlocal Month = A['Month'];if is_set(Month) thenDate = Month .. " " .. Date;local Day = A['Day']if is_set(Day) then Date = Day .. " " .. Date endendelseif is_set(PublicationDate) then-- use PublicationDate when |date= and |year= are not setDate = PublicationDate;-- promonte PublicationDate to DatePublicationDate = '';-- unset, no longer neededendendif PublicationDate == Date then PublicationDate = ''; end-- if PublicationDate is same as Date, don't display in rendered citation-- Go test all of the date-holding parameters for valid MOS:DATE format and make sure that dates are real dates.-- TODO: 2013-10-27: AirDate is nil when dates() is called because it hasn't been set yet. Move the call to dates() or set AirDate earlier.anchor_year, COinS_date = dates({['accessdate']=AccessDate, ['airdate']=AirDate, ['archivedate']=ArchiveDate, ['date']=Date, ['doi_brokendate']=DoiBroken,['embargo']=Embargo, ['laydate']=LayDate, ['publicationdate']=PublicationDate, ['year']=Year});-- At this point fields may be nil if they weren't specified in the template use. We can use that fact.--Account for the oddity that is {{cite journal}} with |pmc= set and |url= not setif config.CitationClass == "journal" and not is_set(URL) and is_set(ID_list['PMC']) thenif not is_embargoed(Embargo) thenURL=cfg.id_handlers['PMC'].prefix .. ID_list['PMC'];-- set url to be the same as the PMC external link if not embargoedendend -- Account for the oddity that is {{cite conference}}, before generation of COinS data. if is_set(BookTitle) then Chapter = Title; ChapterLink = TitleLink; TransChapter = TransTitle; Title = BookTitle; TitleLink = ''; TransTitle = ''; end -- Account for the oddity that is {{cite episode}}, before generation of COinS data. if config.CitationClass == "episode" then local AirDate = A['AirDate']; local SeriesLink = A['SeriesLink']; local Season = A['Season']; local SeriesNumber = A['SeriesNumber']; local Network = A['Network']; local Station = A['Station']; local s, n = {}, {}; local Sep = (first_set(A["SeriesSeparator"], A["Separator"]) or "") .. " "; if is_set(Issue) then table.insert(s, cfg.messages["episode"] .. " " .. Issue); Issue = ''; end if is_set(Season) then table.insert(s, cfg.messages["season"] .. " " .. Season); end if is_set(SeriesNumber) then table.insert(s, cfg.messages["series"] .. " " .. SeriesNumber); end if is_set(Network) then table.insert(n, Network); end if is_set(Station) then table.insert(n, Station); end Date = Date or AirDate; Chapter = Title; ChapterLink = TitleLink; TransChapter = TransTitle; Title = Series; TitleLink = SeriesLink; TransTitle = ''; Series = table.concat(s, Sep); ID = table.concat(n, Sep); end -- COinS metadata (see <http://ocoins.info/>) for -- automated parsing of citation information. local OCinSoutput = COinS{ ['Periodical'] = Periodical, ['Chapter'] = Chapter, ['Title'] = Title, ['PublicationPlace'] = PublicationPlace, ['Date'] = first_set(COinS_date, Date),-- COinS_date has correctly formatted date if Date is valid; any reason to keep Date here? Should we be including invalid dates in metadata? ['Series'] = Series, ['Volume'] = Volume, ['Issue'] = Issue, ['Pages'] = first_set(Page, Pages, At), ['Edition'] = Edition, ['PublisherName'] = PublisherName, ['URL'] = first_set( URL, ChapterURL ), ['Authors'] = a, ['ID_list'] = ID_list, ['RawPage'] = this_page.prefixedText, }; if is_set(Periodical) and not is_set(Chapter) and is_set(Title) then Chapter = Title; ChapterLink = TitleLink; TransChapter = TransTitle; Title = ''; TitleLink = ''; TransTitle = ''; end -- Now perform various field substitutions. -- We also add leading spaces and surrounding markup and punctuation to the -- various parts of the citation, but only when they are non-nil. if not is_set(Authors) then local Maximum = tonumber( A['DisplayAuthors'] ); -- Preserve old-style implicit et al. if not is_set(Maximum) and #a == 9 then Maximum = 8; table.insert( z.message_tail, { seterror('implict_etal_author', {}, true ) } ); elseif not is_set(Maximum) then Maximum = #a + 1; end local control = { sep = A["AuthorSeparator"] .. " ", namesep = (first_set(A["AuthorNameSeparator"], A["NameSeparator"]) or "") .. " ", format = A["AuthorFormat"], maximum = Maximum, lastauthoramp = LastAuthorAmp }; -- If the coauthor field is also used, prevent ampersand and et al. formatting. if is_set(Coauthors) then control.lastauthoramp = nil; control.maximum = #a + 1; end Authors = listpeople(control, a) endif not is_set(Authors) and is_set(Coauthors) then-- coauthors aren't displayed if one of authors=, authorn=, or lastn= isn't specifiedtable.insert( z.message_tail, { seterror('coauthors_missing_author', {}, true) } );-- emit error messageend local EditorCount if not is_set(Editors) then local Maximum = tonumber( A['DisplayEditors'] ); -- Preserve old-style implicit et al. if not is_set(Maximum) and #e == 4 then Maximum = 3; table.insert( z.message_tail, { seterror('implict_etal_editor', {}, true) } ); elseif not is_set(Maximum) then Maximum = #e + 1; end local control = { sep = A["EditorSeparator"] .. " ", namesep = (first_set(A["EditorNameSeparator"], A["NameSeparator"]) or "") .. " ", format = A['EditorFormat'], maximum = Maximum, lastauthoramp = LastAuthorAmp }; Editors, EditorCount = listpeople(control, e); else EditorCount = 1; end local Cartography = ""; local Scale = ""; if config.CitationClass == "map" then if not is_set( Authors ) and is_set( PublisherName ) then Authors = PublisherName; PublisherName = ""; end Cartography = A['Cartography']; if is_set( Cartography ) then Cartography = sepc .. " " .. wrap( 'cartography', Cartography, use_lowercase ); end Scale = A['Scale']; if is_set( Scale ) then Scale = sepc .. " " .. Scale; end end if not is_set(URL) and not is_set(ChapterURL) and not is_set(ArchiveURL) and not is_set(ConferenceURL) and not is_set(TranscriptURL) 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 Format = is_set(Format) and " (" .. Format .. ")" or ""; local OriginalURL = URL DeadURL = DeadURL:lower(); if is_set( ArchiveURL ) then if ( DeadURL ~= "no" ) then URL = ArchiveURL URLorigin = A:ORIGIN('ArchiveURL') end end -- Format chapter / article title if is_set(Chapter) and is_set(ChapterLink) then Chapter = "[[" .. ChapterLink .. "|" .. Chapter .. "]]"; end if is_set(Periodical) and is_set(Title) then Chapter = wrap( 'italic-title', Chapter ); TransChapter = wrap( 'trans-italic-title', TransChapter ); else Chapter = wrap( 'quoted-title', Chapter ); TransChapter = wrap( 'trans-quoted-title', TransChapter ); end local TransError = "" if is_set(TransChapter) then if not is_set(Chapter) then TransError = " " .. seterror( 'trans_missing_chapter' ); else TransChapter = " " .. TransChapter; end end Chapter = Chapter .. TransChapter; if is_set(Chapter) then if not is_set(ChapterLink) then if is_set(ChapterURL) then Chapter = externallink( ChapterURL, Chapter ) .. TransError; if not is_set(URL) then 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 = Chapter .. " " .. externallink( ChapterURL, nil, ChapterURLorigin ) .. TransError; else Chapter = Chapter .. TransError; end Chapter = Chapter .. sepc .. " " -- with end-space elseif is_set(ChapterURL) then Chapter = " " .. externallink( ChapterURL, nil, ChapterURLorigin ) .. sepc .. " "; end -- Format main title. if is_set(TitleLink) and is_set(Title) then Title = "[[" .. TitleLink .. "|" .. Title .. "]]" end if is_set(Periodical) then Title = wrap( 'quoted-title', Title ); TransTitle = wrap( 'trans-quoted-title', TransTitle ); elseif inArray(config.CitationClass, {"web","news","pressrelease","conference"}) and not is_set(Chapter) then Title = wrap( 'quoted-title', Title ); TransTitle = wrap( 'trans-quoted-title', TransTitle ); else Title = wrap( 'italic-title', Title ); TransTitle = wrap( 'trans-italic-title', TransTitle ); end TransError = ""; if is_set(TransTitle) then if not is_set(Title) then TransError = " " .. seterror( 'trans_missing_title' ); else TransTitle = " " .. TransTitle; end end Title = Title .. TransTitle; if is_set(Title) then if not is_set(TitleLink) and is_set(URL) then Title = externallink( URL, Title ) .. TransError .. Format URL = ""; Format = ""; else Title = Title .. TransError; end end if is_set(Place) then Place = " " .. wrap( 'written', Place, use_lowercase ) .. sepc .. " "; end if is_set(Conference) then if is_set(ConferenceURL) then Conference = externallink( ConferenceURL, Conference ); end Conference = sepc .. " " .. Conference elseif is_set(ConferenceURL) then Conference = sepc .. " " .. externallink( ConferenceURL, nil, ConferenceURLorigin ); end if not is_set(Position) then local Minutes = A['Minutes']; if is_set(Minutes) then Position = " " .. Minutes .. " " .. cfg.messages['minutes']; else local Time = A['Time']; if is_set(Time) then local TimeCaption = A['TimeCaption'] if not is_set(TimeCaption) then TimeCaption = cfg.messages['event']; if sepc ~= '.' then TimeCaption = TimeCaption:lower(); end end Position = " " .. TimeCaption .. " " .. Time; end end else Position = " " .. Position; At = ''; end if not is_set(Page) then if is_set(Pages) then if is_set(Periodical) and not inArray(config.CitationClass, {"encyclopaedia","web","book","news"}) then Pages = ": " .. Pages; elseif tonumber(Pages) ~= nil then Pages = sepc .." " .. PPrefix .. Pages; else Pages = sepc .." " .. PPPrefix .. Pages; end end else if is_set(Periodical) and not inArray(config.CitationClass, {"encyclopaedia","web","book","news"}) then Page = ": " .. Page; else Page = sepc .." " .. PPrefix .. Page; end end At = is_set(At) and (sepc .. " " .. At) or ""; Position = is_set(Position) and (sepc .. " " .. Position) or ""; if config.CitationClass == 'map' then local Section = A['Section']; local Inset = A['Inset']; if first_set( Pages, Page, At ) ~= nil or sepc ~= '.' then if is_set( Section ) then Section = ", " .. wrap( 'section', Section, true ); end if is_set( Inset ) then Inset = ", " .. wrap( 'inset', Inset, true ); end else if is_set( Section ) then Section = sepc .. " " .. wrap( 'section', Section, use_lowercase ); if is_set( Inset ) then Inset = ", " .. wrap( 'inset', Inset, true ); end elseif is_set( Inset ) then Inset = sepc .. " " .. wrap( 'inset', Inset, use_lowercase ); end end At = At .. Section .. Inset; end --[[Look in the list of iso639-1 language codes to see if the value provided in the language parameter matches one of them. If a match is found, use that value; if not, then use the value that was provided with the language parameter.Categories are assigned in a manner similar to the {{xx icon}} templates - categorizes only mainspace citations and only when the language code is not 'en' (English).]]if is_set (Language) thenlocal name = cfg.iso639_1[Language:lower()];-- get the language name if Language parameter has a valid iso 639-1 codeif nil == name thenLanguage=" " .. wrap( 'language', Language );-- no match, use parameter's valueelse--if 0 == this_page.namespace and 'ca' ~= Language:lower() then--found a match; is this page main / article space and English not the language?--Language=" " .. wrap( 'language', name .. '[[Category:Articles with ' .. name .. '-language external links]]' );-- in main space and not English: categorize--else--Language=" " .. wrap( 'language', name );--not in mainspace or language is English so don't categorize--endendelseLanguage="";-- language not specified so make sure this is an empty string;endOthers = is_set(Others) and (sepc .. " " .. Others) or "";-- handle type parameter for those CS1 citations that have default valuesif inArray(config.CitationClass, {"pressrelease","techreport","thesis", "speech"}) thenTitleType = set_titletype (config.CitationClass, TitleType);if is_set(Degree) and "Thesis" == TitleType then-- special case for cite thesisTitleType = Degree .. " thesis";endendif is_set(TitleType) then-- if type parameter is specifiedTitleType = " (" .. TitleType .. ")";-- display it in parenthesesendTitleNote = is_set(TitleNote) and (sepc .. " " .. TitleNote) or ""; Edition = is_set(Edition) and (" " .. wrap( 'edition', Edition )) or ""; Issue = is_set(Issue) and (" (" .. Issue .. ")") or ""; Series = is_set(Series) and (sepc .. " " .. Series) or ""; OrigYear = is_set(OrigYear) and (" [" .. OrigYear .. "]") or ""; Agency = is_set(Agency) and (sepc .. " " .. Agency) or ""; if is_set(Volume) then if ( mw.ustring.len(Volume) > 4 ) then Volume = sepc .." " .. Volume; else Volume = " <b>" .. hyphentodash(Volume) .. "</b>"; end end ------------------------------------ totally unrelated data --[[ Loosely mimic {{subscription required}} template; Via parameter identifies a delivery source that is not the publisher; these sources often, but not always, exist behind a registration or paywall. So here, we've chosen to decouple via from subscription (via has never been part of the registration required template). Subscription implies paywall; Registration does not. If both are used in a citation, the subscription required link note is displayed. There are no error messages for this condition. ]] if is_set(Via) then Via = " " .. wrap( 'via', Via ); endif is_set(SubscriptionRequired) then SubscriptionRequired = sepc .. " " .. cfg.messages['subscription']; --here when 'via' parameter not used but 'subscription' is elseif is_set(RegistrationRequired) then SubscriptionRequired = sepc .. " " .. cfg.messages['registration']; --here when 'via' and 'subscription' parameters not used but 'registration' is end if is_set(AccessDate) then local retrv_text = " " .. cfg.messages['retrieved'] if (sepc ~= ".") then retrv_text = retrv_text:lower() end AccessDate = '<span class="reference-accessdate">' .. sepc .. substitute( retrv_text, {AccessDate} ) .. '</span>' end if is_set(ID) then ID = sepc .." ".. ID; end if "thesis" == config.CitationClass and is_set(Docket) thenID = sepc .." Docket ".. Docket .. ID;end ID_list = buildidlist( ID_list, {DoiBroken = DoiBroken, ASINTLD = ASINTLD, IgnoreISBN = IgnoreISBN, Embargo=Embargo} ); if is_set(URL) then URL = " " .. externallink( URL, nil, URLorigin ); end if is_set(Quote) then if Quote:sub(1,1) == '"' and Quote:sub(-1,-1) == '"' then Quote = Quote:sub(2,-2); end Quote = sepc .." " .. wrap( 'quoted-text', Quote ); PostScript = ""; elseif PostScript:lower() == "none" then PostScript = ""; end local Archived if is_set(ArchiveURL) then if not is_set(ArchiveDate) then ArchiveDate = seterror('archive_missing_date'); end if "no" == DeadURL then local arch_text = cfg.messages['archived']; if sepc ~= "." then arch_text = arch_text:lower() end Archived = sepc .. " " .. substitute( cfg.messages['archived-not-dead'], { externallink( ArchiveURL, arch_text ), ArchiveDate } ); if not is_set(OriginalURL) then Archived = Archived .. " " .. seterror('archive_missing_url'); end elseif is_set(OriginalURL) then local arch_text = cfg.messages['archived-dead']; if sepc ~= "." then arch_text = arch_text:lower() end Archived = sepc .. " " .. substitute( arch_text, { externallink( OriginalURL, cfg.messages['original'] ), ArchiveDate } ); else local arch_text = cfg.messages['archived-missing']; if sepc ~= "." then arch_text = arch_text:lower() end Archived = sepc .. " " .. substitute( arch_text, { seterror('archive_missing_url'), ArchiveDate } ); end else Archived = "" end local Lay if is_set(LayURL) then if is_set(LayDate) then LayDate = " (" .. LayDate .. ")" end if is_set(LaySource) then LaySource = " – ''" .. safeforitalics(LaySource) .. "''"; else LaySource = ""; end if sepc == '.' then Lay = sepc .. " " .. externallink( LayURL, cfg.messages['lay summary'] ) .. LaySource .. LayDate else Lay = sepc .. " " .. externallink( LayURL, cfg.messages['lay summary']:lower() ) .. LaySource .. LayDate end else Lay = ""; end if is_set(Transcript) then if is_set(TranscriptURL) then Transcript = externallink( TranscriptURL, Transcript ); end elseif is_set(TranscriptURL) then Transcript = externallink( TranscriptURL, nil, TranscriptURLorigin ); end local Publisher; if is_set(Periodical) and not inArray(config.CitationClass, {"encyclopaedia","web","pressrelease"}) then if is_set(PublisherName) then if is_set(PublicationPlace) then Publisher = PublicationPlace .. ": " .. PublisherName; else Publisher = PublisherName; end elseif is_set(PublicationPlace) then Publisher= PublicationPlace; else Publisher = ""; end if is_set(PublicationDate) then if is_set(Publisher) then Publisher = Publisher .. ", " .. wrap( 'published', PublicationDate ); else Publisher = PublicationDate; end end if is_set(Publisher) then Publisher = " (" .. Publisher .. ")"; end else if is_set(PublicationDate) then PublicationDate = " (" .. wrap( 'published', PublicationDate ) .. ")"; end if is_set(PublisherName) then if is_set(PublicationPlace) then Publisher = sepc .. " " .. PublicationPlace .. ": " .. PublisherName .. PublicationDate; else Publisher = sepc .. " " .. PublisherName .. PublicationDate; end elseif is_set(PublicationPlace) then Publisher= sepc .. " " .. PublicationPlace .. PublicationDate; else Publisher = PublicationDate; end end -- Several of the above rely upon detecting this as nil, so do it last. if is_set(Periodical) then if is_set(Title) or is_set(TitleNote) then Periodical = sepc .. " " .. wrap( 'italic-title', Periodical ) else Periodical = wrap( 'italic-title', Periodical ) end end -- Piece all bits together at last. Here, all should be non-nil. -- We build things this way because it is more efficient in LUA -- not to keep reassigning to the same string variable over and over. local tcommon if inArray(config.CitationClass, {"journal","citation"}) and is_set(Periodical) then if is_set(Others) then Others = Others .. sepc .. " " end tcommon = safejoin( {Others, Title, TitleNote, Conference, Periodical, Format, TitleType, Scale, Series, Language, Cartography, Edition, Publisher, Agency, Volume, Issue}, sepc ); else tcommon = safejoin( {Title, TitleNote, Conference, Periodical, Format, TitleType, Scale, Series, Language, Volume, Issue, Others, Cartography, Edition, Publisher, Agency}, sepc ); end if #ID_list > 0 then ID_list = safejoin( { sepc .. " ", table.concat( ID_list, sepc .. " " ), ID }, sepc ); else ID_list = ID; end local idcommon = safejoin( { ID_list, URL, Archived, AccessDate, Via, SubscriptionRequired, Lay, Quote }, sepc ); local text; local pgtext = Position .. Page .. Pages .. At; if is_set(Authors) then if is_set(Coauthors) then Authors = Authors .. A['AuthorSeparator'] .. " " .. Coauthors end if is_set(Date) then Date = " ("..Date..")" .. OrigYear .. sepc .. " " elseif string.sub(Authors,-1,-1) == sepc then Authors = Authors .. " " else Authors = Authors .. sepc .. " " end if is_set(Editors) then local in_text = " "; local post_text = ""; if is_set(Chapter) then in_text = in_text .. cfg.messages['in'] .. " " else if EditorCount <= 1 then post_text = ", " .. cfg.messages['editor']; else post_text = ", " .. cfg.messages['editors']; end end if (sepc ~= '.') then in_text = in_text:lower() end Editors = in_text .. Editors .. post_text; if (string.sub(Editors,-1,-1) == sepc) then Editors = Editors .. " " else Editors = Editors .. sepc .. " " end end text = safejoin( {Authors, Date, Chapter, Place, Editors, tcommon }, sepc ); text = safejoin( {text, pgtext, idcommon}, sepc ); elseif is_set(Editors) then if is_set(Date) then if EditorCount <= 1 then Editors = Editors .. ", " .. cfg.messages['editor']; else Editors = Editors .. ", " .. cfg.messages['editors']; end Date = " (" .. Date ..")" .. OrigYear .. sepc .. " " else if EditorCount <= 1 then Editors = Editors .. " (" .. cfg.messages['editor'] .. ")" .. sepc .. " " else Editors = Editors .. " (" .. cfg.messages['editors'] .. ")" .. sepc .. " " end end text = safejoin( {Editors, Date, Chapter, Place, tcommon}, sepc ); text = safejoin( {text, pgtext, idcommon}, sepc ); else if is_set(Date) then if ( string.sub(tcommon,-1,-1) ~= sepc ) then Date = sepc .." " .. Date .. OrigYear else Date = " " .. Date .. OrigYear end end if config.CitationClass=="journal" and is_set(Periodical) then text = safejoin( {Chapter, Place, tcommon}, sepc ); text = safejoin( {text, pgtext, Date, idcommon}, sepc ); else text = safejoin( {Chapter, Place, tcommon, Date}, sepc ); text = safejoin( {text, pgtext, idcommon}, sepc ); end end if is_set(PostScript) and PostScript ~= sepc then text = safejoin( {text, sepc}, sepc ); --Deals with italics, spaces, etc. text = text:sub(1,-2); --Remove final seperator end text = safejoin( {text, PostScript}, sepc ); -- 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 is_set(Ref) and Ref:lower() ~= "none" then local id = Ref if ( "harv" == Ref ) then local names = {} --table of last names & year if #a > 0 then for i,v in ipairs(a) do names[i] = v.last if i == 4 then break end end elseif #e > 0 then for i,v in ipairs(e) do names[i] = v.last if i == 4 then break end end endnames[ #names + 1 ] = first_set(Year, anchor_year);-- Year first for legacy citations--names[ #names + 1 ] = Year or anchor_year;-- Year first for legacy citations id = anchorid(names) end options.id = id; 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(options.id) then text = '<span id="' .. mw.uri.anchorEncode(options.id) ..'" class="' .. mw.text.nowiki(options.class) .. '">' .. text .. "</span>"; else text = '<span class="' .. mw.text.nowiki(options.class) .. '">' .. text .. "</span>"; end local empty_span = '<span style="display:none;"> </span>'; -- Note: Using display: none on then COinS span breaks some clients. local OCinS = '<span title="' .. OCinSoutput .. '" class="Z3988">' .. empty_span .. '</span>'; text = text .. OCinS; 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 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 .. '[[Category:' .. v ..']]'; end end return textend-- 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 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 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( 'Module:Citation/CS1/Suggestions' ); 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 or (k == 'postscript') then args[k] = v; end end return citation0( config, args)endreturn z
🔥 Top keywords: PortadaEspecial:CercaLliga de Campions de la UEFAJosep Maria Terricabras i NoguerasSidonie-Gabrielle ColetteRuben Wagensberg RamonAtemptats de Londres del 7 de juliol de 2005Reial Madrid Club de FutbolXavlegbmaofffassssitimiwoamndutroabcwapwaeiippohfffXRadóBisbeEspecial:Canvis recentsViquipèdia:ContactePompeiaEleccions al Parlament de Catalunya de 2024Alex de MinaurBàcul pastoralJosep Guardiola i SalaMadridJude BellinghamFC Bayern de MúnicCarles Puigdemont i CasamajóBarqueta de Sant PereBàculDiada de Sant JordiSant JordiInstagramRafael Nadal i PareraTor (Alins)Bisbe (Església Catòlica)SportArsenal Football ClubComarques de CatalunyaRodrigo Hernández CascanteSoftcatalàAndrí LuninEl paradís de les senyoresManuel de Pedrolo i MolinaTaula periòdica