Módulo:Citas: Diferenzas entre revisións

Contido eliminado Contido engadido
copiado de en.wiki
 
substitúo todo o contido polo contido actual presente en en.wp
Liña 6:
 
-- Include translation message hooks, ID and error handling configuration settings.
--local cfg = mw.loadData( 'Module:Citation/CS1/Configuration/sandbox' );
 
-- Contains a list of all recognized parameters
--local whitelist = mw.loadData( 'Module:Citation/CS1/Whitelist/sandbox' );
 
--local dates = require('Module:Citation/CS1/Date_validation/sandbox').dates -- location of date validation code
 
-- Whether variable is set or not
Liña 39 ⟶ 41:
end
 
--[[
-- Add this page to the deprecated parameter tracking category
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 once
-- table.insert( z.error_categoriesmessage_tail, "Páxinas{ queseterror( conteñen'deprecated_params', modelos{error_message}, detrue cita) con parámetros obsoletos"} ); -- add page toerror categorymessage
table.insert( z.message_tail, { seterror( 'deprecated_params', {}, true ) } ); -- add error message
end
end
Liña 49 ⟶ 56:
-- 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;
return args and mw.message.newRawMessage( msg, args ):plain() or msg;
end
 
--[[
Apply kerning to open the space between the quote mark provided by the Module and a leading or trailing quote mark contained in a |title= or |chapter= parameter's value.
This function will positive kern either single or double quotes:
"'Unkerned title with leading and trailing single quote marks'"
" 'Kerned title with leading and trailing single quote marks' " (in real life the kerning isn't as wide as this example)
]]
function kern_quotes (str)
local left='<span style="padding-left:0.2em;">%1</span>'; -- spacing to use when title contains leading single or double quote mark
local right='<span style="padding-right:0.2em;">%1</span>'; -- spacing to use when title contains trailing single or double quote mark
if str:match ("^[\"\'][^\']") then
str = string.gsub( str, "^[\"\']", left, 1 ); -- replace (captured) leading single or double quote with left-side <span>
end
if str:match ("[^\'][\"\']$") then
str = string.gsub( str, "[\"\']$", right, 1 ); -- replace (captured) trailing single or double quote with right-side <span>
end
return str;
end
 
Liña 113 ⟶ 140:
end
 
--[[
-- Checks that parameter name is valid using the whitelist
Looks for a parameter's name in the whitelist.
 
Parameters in the whitelist can have three values:
true - active, supported parameters
false - deprecated, supported parameters
nil - unsupported parameters
]]
function validate( name )
local name = tostring( name );
local state = whitelist.basic_arguments[ name ];
-- Normal arguments
-- Normal arguments
if whitelist.basic_arguments[ name ] then
if true == state then return true; end -- valid actively supported parameter
if false == state then
end
deprecated_parameter (); -- parameter is deprecated but still supported
return true;
-- Arguments with numbers in them
end
name = name:gsub( "%d+", "#" );
if whitelist.numbered_arguments[ name ] then
-- Arguments with numbers in them
return true;
name = name:gsub( "%d+", "#" ); -- replace digit(s) with # (last25 becomes last#
end
state = whitelist.numbered_arguments[ name ];
if true == state --then Notreturn found,true; argumentend -- notvalid actively supported. parameter
if false == state then
return false
deprecated_parameter (); -- parameter is deprecated but still supported
return true;
end
return false; -- Not supported because not found or name is set to nil
end
 
Liña 227 ⟶ 266:
 
--[[
Format LCCN link and do simple error checking. LCCN is a character string 8-12 characters long. The length of the LCCN dictates the character type of the first 1-3 characters; the
Formats a PMC and checks for embargoed articles. The embargo parameter takes a date for a value. If the embargo date is in the futue
rightmost eight are always digits. http://info-uri.info/registry/OAIHandler?verb=GetRecord&metadataPrefix=reg&identifier=info:lccn/
the 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, then
 
the PMC identifier is linked to the article through the link at cfg.id_handlers['PMC'].link.
length = 8 then all digits
length = 9 then lccn[1] is alpha
length = 10 then lccn[1] and lccn[2] are both alpha or both digits
length = 11 then lccn[1] is alpha, lccn[2] and lccn[3] are both alpha or both digits
length = 12 then lccn[1] and lccn[2] are both alpha
 
The {{citation/core}} version of {{cite journal}} links the citation title (if url parameter is empty) when embargo date is in the past
or when embargo parameter is missing or empty. That behavior is inconsistent with the behavior of other identifiers used in CS1 and is
not supported here.
]]
function pmclccn(id, embargo)
local handler = cfg.id_handlers['PMCLCCN'];
local err_cat = ''; -- presume that LCCN is valid
 
local text;
local len = id:len(); -- get the length of the lccn
 
if 8 == len then
if id:match("[^%d]") then -- if LCCN has anything but digits (nil if only digits)
err_cat = ' ' .. seterror( 'bad_lccn' ); -- set an error message
end
elseif 9 == len then -- LCCN should be adddddddd
if nil == id:match("%a%d%d%d%d%d%d%d%d") then -- does it match our pattern?
err_cat = ' ' .. seterror( 'bad_lccn' ); -- set an error message
end
elseif 10 == len then -- LCCN should be aadddddddd or dddddddddd
if id:match("[^%d]") then -- if LCCN has anything but digits (nil if only digits) ...
if nil == id:match("^%a%a%d%d%d%d%d%d%d%d") then -- ... see if it matches our pattern
err_cat = ' ' .. seterror( 'bad_lccn' ); -- no match, set an error message
end
end
elseif 11 == len then -- LCCN should be aaadddddddd or adddddddddd
if not (id:match("^%a%a%a%d%d%d%d%d%d%d%d") or id:match("^%a%d%d%d%d%d%d%d%d%d%d")) then -- see if it matches one of our patterns
err_cat = ' ' .. seterror( 'bad_lccn' ); -- no match, set an error message
end
elseif 12 == len then -- LCCN should be aadddddddddd
if not id:match("^%a%a%d%d%d%d%d%d%d%d%d%d") then -- see if it matches our pattern
err_cat = ' ' .. seterror( 'bad_lccn' ); -- no match, set an error message
end
else
err_cat = ' ' .. seterror( 'bad_lccn' ); -- wrong length, set an error message
end
 
return externallinkid({link = handler.link, label = handler.label,
prefix=handler.prefix,id=id,separator=handler.separator, encode=handler.encode}) .. err_cat;
end
 
--[[
Format PMID and do simple error checking. PMIDs are sequential numbers beginning at 1 and counting up. This code checks the PMID to see that it
contains only digits and is less than test_limit; the value in local variable test_limit will need to be updated periodically as more PMIDs are issued.
]]
function pmid(id)
local test_limit = 30000000; -- update this value as PMIDs approach
local handler = cfg.id_handlers['PMID'];
local err_cat = ''; -- presume that PMID is valid
if id:match("[^%d]") then -- if PMID has anything but digits
err_cat = ' ' .. seterror( 'bad_pmid' ); -- set an error message
else -- PMID is only digits
local id_num = tonumber(id); -- convert id to a number for range testing
if 1 > id_num or test_limit < id_num then -- if PMID is outside test limit boundaries
err_cat = ' ' .. seterror( 'bad_pmid' ); -- set an error message
end
end
return externallinkid({link = handler.link, label = handler.label,
prefix=handler.prefix,id=id,separator=handler.separator, encode=handler.encode}) .. err_cat;
end
 
--[[
Determines if a PMC identifier's online version is embargoed. Compares the date in |embargo= against today's date. If embargo date is
in 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) then
local lang = mw.getContentLanguage();
Liña 245 ⟶ 344:
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 embargoed
end
end
return false; -- embargo expired or |embargo= not set
end
 
--[[
if good1 and good2 and tonumber( embargo_date ) < tonumber( todays_date ) then --if embargo date is in the past then
Format a PMC, do simple error checking, and check for embargoed articles.
text = externallinkid({link = handler.link, label = handler.label, --ok to link to article
 
prefix=handler.prefix,id=id,separator=handler.separator, encode=handler.encode})
The embargo parameter takes a date for a value. If the embargo date is in the future
else
the 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, then
text="[[" .. handler.link .. "|" .. handler.label .. "]]:" .. handler.separator .. id; --still embargoed so no external link
the PMC identifier is linked to the article through the link at cfg.id_handlers['PMC'].prefix.
 
PMCs are sequential numbers beginning at 1 and counting up. This code checks the PMC to see that it contains only digits and is less
than test_limit; the value in local variable test_limit will need to be updated periodically as more PMCs are issued.
]]
function pmc(id, embargo)
local test_limit = 5000000; -- update this value as PMCs approach
local handler = cfg.id_handlers['PMC'];
local err_cat = ''; -- presume that PMC is valid
local text;
 
if id:match("[^%d]") then -- if PMC has anything but digits
err_cat = ' ' .. seterror( 'bad_pmc' ); -- set an error message
else -- PMC is only digits
local id_num = tonumber(id); -- convert id to a number for range testing
if 1 > id_num or test_limit < id_num then -- if PMC is outside test limit boundaries
err_cat = ' ' .. seterror( 'bad_pmc' ); -- set an error message
end
end
if is_embargoed(embargo) then
text="[[" .. handler.link .. "|" .. handler.label .. "]]:" .. handler.separator .. id .. err_cat; --still embargoed so no external link
else
text = externallinkid({link = handler.link, label = handler.label, --no embargo date, ok to link to article
prefix=handler.prefix,id=id,separator=handler.separator, encode=handler.encode}) .. err_cat;
end
return text;
end
 
-- Formats a DOI and checks for DOI errors.
 
-- DOI names contain two parts: prefix and suffix separated by a forward slash.
-- Prefix: directory indicator '10.' followed by a registrant code
-- Suffix: character string of any length chosen by the registrant
 
-- This function checks a DOI name for: prefix/suffix. If the doi name contains spaces or endashes,
-- or, if it ends with a period or a comma, this function will emit a bad_doi error message.
 
-- DOI names are case-insensitive and can incorporate any printable Unicode characters so the test for spaces, endash,
-- and terminal punctuation may not be technically correct but it appears, that in practice these characters are rarely if ever used in doi names.
 
function doi(id, inactive)
local cat = ""
Liña 265 ⟶ 404:
local text;
if is_set(inactive) then
local inactive_year = inactive:match("%d%d%d%d") or ''; -- try to get the year portion from the inactive date
text = "[[" .. handler.link .. "|" .. handler.label .. "]]:" .. id;
text = "[[" .. handler.link .. "|" .. handler.label .. "]]:" .. id;
table.insert( z.error_categories, "Páxinas con DOIs inactivos dende " .. selectyear(inactive) );
if is_set(inactive_year) then
inactive = " (" .. cfg.messages['inactive'] .. " " .. inactivo .. ")"
table.insert( z.error_categories, "Pages with DOIs inactive since " .. inactive_year );
else
else
text = externallinkid({link = handler.link, label = handler.label,
table.insert( z.error_categories, "Pages with inactive DOIs" ); -- when inactive doesn't contain a recognizable year
prefix=handler.prefix,id=id,separator=handler.separator, encode=handler.encode})
end
inactive = ""
inactive = " (" .. cfg.messages['inactive'] .. " " .. inactive .. ")"
end
else
if ( string.sub(id,1,3) ~= "10." ) then
text = externallinkid({link = handler.link, label = handler.label,
cat = seterror( 'bad_doi' );
prefix=handler.prefix,id=id,separator=handler.separator, encode=handler.encode})
end
return text .. inactive ..= cat""
end
 
if nil == id:match("^10%.[^%s–]-/[^%s–]-[^%.,]$") then -- doi must begin with '10.', must contain a fwd slash, must not contain spaces or endashes, and must not end with period or comma
cat = ' ' .. seterror( 'bad_doi' );
end
return text .. inactive .. cat
end
 
Liña 342 ⟶ 487:
return text
end
 
-- returns a number according to the month in a date 1 for January, etc. If not a valid month, returns 0
function get_month_number (month)
local long_months = {['xaneiro']=1, ['febreiro']=2, ['marzo']=3, ['abril']=4, ['maio']=5, ['xuño']=6, ['xullo']=7, ['agosto']=8, ['setembro']=9, ['outubro']=10, ['novembro']=11, ['decembro']=12};
local short_months = {['xan']=1, ['feb']=2, ['mar']=3, ['abr']=4, ['mai']=5, ['xuñ']=6, ['xul']=7, ['ago']=8, ['set']=9, ['out']=10, ['nov']=11, ['dec']=12};
local temp;
temp=long_months[month:lower()];
if temp then return temp; end -- if month is the long-form name
temp=short_months[month:lower()];
if temp then return temp; end -- if month is the short-form name
return 0; -- misspelled or not a month name
end
 
-- returns true if date has one of the five seasons. Else false.
function is_valid_season (season)
if inArray( season, {'inverno', 'primavera', 'verán', 'outono'} ) then
return true;
end
return false;
end
 
--[[
This function sets default title types (equivalent to the citation including |type=<default value>) for those citations that have defaults.
Returns true if day is less than or equal to the number of days in month; else returns false.
Also handles the special case where it is desireable to omit the title type from the rendered citation (|type=none).
 
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 set_titletype(year, monthcite_class, daytitle_type)
if is_set(title_type) then
local days_in_month = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
if "none" == title_type then
local month_length;
title_type = ""; -- if |type=none then type parameter not displayed
if (2==month) then -- if February
month_length = 28; -- then 28 days unless
if 1582 > tonumber(year) then -- Julian calendar
if 0==(year%4) then
month_length = 29;
end
else -- Gregorian calendar
if (0==(year%4) and (0~=(year%100) or 0==(year%400))) then -- date specifies a leap year
month_length = 29; -- if leap year then 29 days in February
end
end
return title_type; -- if |type= has been set to any other value use that value
else
month_length=days_in_month[month];
end
 
if "AV media notes" == cite_class or "DVD notes" == cite_class then -- if this citation is cite AV media notes or cite DVD notes
if tonumber (day) > month_length then
return "Media notes"; -- display AV media notes / DVD media notes annotation
return false;
end
return true;
end
 
elseif "podcast" == cite_class then -- if this citation is cite podcast
--Check a pair of months or seasons to see if both are valid members of a month or season pair.
return "Podcast"; -- display podcast annotation
 
elseif "pressrelease" == cite_class then -- if this citation is cite press release
function is_valid_month_season_range(range_start, range_end)
return "Press release"; -- display press release annotation
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 false
end
return false; -- range_start is not a month or a season
end
if 0 == get_month_number (range_end:lower()) then -- range_start is a month; is range_end also a month?
return false; -- not a month range
end
return true;
end
 
elseif "techreport" == cite_class then -- if this citation is cite techreport
 
return "Technical report"; -- display techreport annotation
--[[
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 three
character 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 is
used 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; else
true, anchor_year, COinS_date
anchor_year can be used in CITEREF anchors
COinS_date is date_string without anchor_year disambiguators 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 format
coins_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; end
 
elseif date_string:match("^%a+%s*%d%d*%s*,%s*%d%d%d%d%a?$") then -- month-initial: month day, year
coins_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 months
elseif date_string:match("^%d%d*%s*%a+%s*%d%d%d%d%a?$") then -- date-initial: day month year
coins_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 months
 
elseif mw.ustring.match (date_string, "^%a+%s*[%s%-/–]%s*%a+%s*%d%d%d%d%a?$") then -- month/season range year
local month2
coins_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 hyphen
month, 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 used
if false == is_valid_month_season_range(month, month2) then
return false;
end
elseif date_string:match("^%a+%s*%d%d%d%d%a?$") then -- month/season year
coins_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 used
local 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 season
if false == is_valid_season (season:lower()) then
return false; -- return false not a month or one of the five seasons
end
end
 
elseif date_string:match("^%d%d%d%d?%a?$") then -- year; here accept either YYY or YYYY
coins_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 used
else
return false; -- date format not one of the MOS:DATE approved formats
end
 
if 0~=month and 0~=day then -- check year month day dates for validity
if false==is_valid_date(year,month,day) then
return false; -- date string is not a real date return false; unset anchor_year and coins_date
end
end
elseif "thesis" == cite_class then -- if this citation is cite thesis (degree option handled after this function returns)
return true, anchor_year, coins_date; -- format is good and date string represents a real date
return "Thesis"; -- display simple thesis annotation (without |degree= modification)
end
 
--[[
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() returns
true 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 list
if is_set(v) then -- if the parameter has a value
if 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 then
good_date, anchor_year, COinS_date = true, v:match("((c%.%s%d%d%d%d?)%a?)"); -- anchor year and COinS_date only from |date= parameter
elseif 'year'==k then
good_date = true;
end
elseif '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 disambiguator
good_date = true;
end
elseif 'date'==k then -- if the parameter is |date=
if v:match("n%.d%.%a?") then -- if |date=n.d. with or without a CITEREF disambiguator
good_date, anchor_year, COinS_date = true, v:match("((n%.d%.)%a?)"); --"n.d."; -- no error when date parameter is set to no date
elseif v:match("nd%a?$") then -- if |date=nd with or without a CITEREF disambiguator
good_date, anchor_year, COinS_date = true, v:match("((nd)%a?)"); --"nd"; -- no error when date parameter is set to no date
else
good_date, anchor_year, COinS_date = check_date (v); -- go test the date
end
else -- any other date-holding parameter
good_date = check_date (v); -- go test the date
end
if false==good_date then -- assemble one error message so we don't add the tracking category multiple times
if is_set(error_message) then -- once we've added the first portion of the error message ...
error_message=error_message .. ", "; -- ... add a comma space separator
end
error_message=error_message .. "&#124;" .. k .. "="; -- add the failed parameter
end
end
end
if is_set(error_message) then
table.insert( z.message_tail, { seterror( 'bad_date', {error_message}, true ) } ); -- add this error message
end
 
return anchor_year, COinS_date; -- and done
end
 
--[[
Determines whether ana URL string is valid
 
At present the only check is whether the string appears to
Liña 563 ⟶ 535:
function cleanisbn( isbn_str )
return isbn_str:gsub( "[^-0-9X]", "" );
end
 
-- Extract page numbers from external wikilinks in any of the |page=, |pages=, or |at= parameters for use in COinS.
function get_coins_pages (pages)
if not is_set (pages) then return pages; end -- if no page numbers then we're done
while true do
pattern = pages:match("%[([%w/:\.]+%s+)[%w%d].*%]"); -- pattern is the opening bracket, the url and following space(s): "[url "
if nil == pattern then break; end -- no more urls
pages = pages:gsub(pattern, ""); -- remove as many instances of pattern as possible
end
pages = pages:gsub("[%[%]]", ""); -- remove the brackets
pages = pages:gsub("–", "-" ); -- replace endashes with hyphens
pages = pages:gsub("&%w+;", "-" ); -- and replace html entities (&ndash; etc) with hyphens; do we need to replace numerical entities like &#32; and the like?
return pages;
end
 
--[[
ISBN-10 and ISSN validator code calculates checksum across all isbn/issn digits including the check digit. If the numberISBN-13 is valid the result willchecked bein 0checkisbn().
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)
Liña 573 ⟶ 561:
isxn_str = { isxn_str:byte(1, len) }; -- make a table of bytes
len = len+1; -- adjust to be a loop counter
for i, v in ipairs( isxn_str ) do -- loop through all of the bytebytes anand calculate the checksum
if v == string.byte( "X" ) then -- if checkdigit is X
temp = temp + 10*( len - i ); -- it represents 10 decimal
Liña 585 ⟶ 573:
-- Determines whether an ISBN string is valid
function 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 X
isbn_str = cleanisbn( isbn_str ):gsub( "-", "" );
isbn_str = isbn_str:gsub( "-", "" ):gsub( " ", "" ); -- remove hyphens and spaces
local len = isbn_str:len();
local len = isbn_str:len();
if len ~= 10 and len ~= 13 then
return false;
end
 
if len == 10 then
if isbn_str:match( "^%d*X?$" ) == nil then return false; end
return is_valid_isxn(isbn_str, 10);
else
local temp = 0;
if isbn_str:match( "^97[89]%d*$" ) == nil then return false; end -- isbn13 begins with 978 or 979
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
 
Liña 723 ⟶ 712:
return str;
end
 
--[[
Return the year portion of a date string, if possible.
Returns empty string if the argument can not be interpreted
as a year.
 
BUG: If editors set |date=n.d or |date=n.da then selectyear() returns the current year for use in CITEREF. These "dates" are caught by dates().
]]
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; end -- if good
end
end
 
-- Attempts to convert names to initials.
Liña 791 ⟶ 759:
end
if is_set(person.link) then one = "[[" .. person.link .. "|" .. one .. "]]" end
if is_set(person.link) and nil ~= person.link:find("//") then one = one .. " " .. seterror( 'bad_authorlink' ) end -- check for url in author link;
end
table.insert( text, one )
Liña 876 ⟶ 845:
elseif k == 'ASIN' then
table.insert( new_list, {handler.label, amazon( v, options.ASINTLD ) } );
elseif k == 'LCCN' then
table.insert( new_list, {handler.label, lccn( v ) } );
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 == 'PMID' then
table.insert( new_list, {handler.label, pmid( v ) } );
elseif k == 'ISSN' then
table.insert( new_list, {handler.label, issn( v ) } );
Liña 893 ⟶ 866:
end
function comp( a, b ) -- used in following table.sort()
return a[1] < b[1];
end
Liña 1.043 ⟶ 1.016:
 
--[[
This is the main function foingdoing the majority of the citation
formatting.
]]
Liña 1.095 ⟶ 1.068:
local ConferenceURLorigin = A:ORIGIN('ConferenceURL');
local Periodical = A['Periodical'];
if ( config.CitationClass == "encyclopaedia" ) then
if not is_set(Chapter) then
if not is_set(Title) then
Title = Periodical;
Periodical = '';
else
Chapter = Title
TransChapter = TransTitle
Title = '';
TransTitle = '';
end
end
end
 
local Series = A['Series'];
local Volume = A['Volume'];
local Issue = A['Issue'];
local Position = '';
local Page, Pages,= At, page_typeA['Page'];
local Pages = hyphentodash( A['Pages'] );
Pagelocal At = A['PageAt'];
 
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'];
Liña 1.154 ⟶ 1.092:
local Format = A['Format'];
local Ref = A['Ref'];
local DoiBroken = A['DoiBroken'];
local DoiBroken = A['DoiBroken'];
-- Special case for cite techreport.
local ID = A['ID'];
if (config.CitationClass == "techreport") then -- special case for cite techreport
if is_set(Issue) then -- cite techreport uses 'number', which everything else aliases to 'issue'
if not is_set(ID) then -- can we use ID for the "number"?
ID = Issue; -- yes, use it
Issue = ""; -- unset Issue so that "number" isn't duplicated in the rendered citation or COinS metadata
else -- can't use ID so emit error message
ID = ID .. " " .. seterror('redundant_parameters', '<code>&#124;id=</code> and <code>&#124;number=</code>');
end
end
end
local ASINTLD = A['ASINTLD'];
local IgnoreISBN = A['IgnoreISBN'];
Liña 1.178 ⟶ 1.102:
local Quote = A['Quote'];
local PostScript = A['PostScript'];
 
local LayURL = A['LayURL'];
local LaySource = A['LaySource'];
Liña 1.184 ⟶ 1.109:
local TranscriptURLorigin = A:ORIGIN('TranscriptURL');
local sepc = A['Separator'];
 
local LastAuthorAmp = A['LastAuthorAmp'];
local no_tracking_cats = A['NoTracking'];
 
--these are used by cite interview
local Callsign = A['Callsign'];
local City = A['City'];
local Cointerviewers = A['Cointerviewers']; -- deprecated
local Interviewer = A['Interviewer']; -- deprecated
local Program = A['Program'];
 
--local variables that are not cs1 parameters
local page_type; -- is this needed? Doesn't appear to be used anywhere;
local use_lowercase = ( sepc ~= '.' );
local this_page = mw.title.getCurrentTitle(); --Also used for COinS and for language
local anchor_year; -- used in the CITEREF identifier
local COinS_date; -- used in the COinS metadata
if not is_set(no_tracking_cats) then
 
for k, v in pairs( cfg.uncategorized_namespaces ) do
-- Set postscript default.
if this_page.nsText == v then
if not is_set (PostScript) then -- if |postscript= has not been set (Postscript is nil which is the default for {{citation}}) and
no_tracking_cats = "true";
if (config.CitationClass ~= "citation") then -- this template is not a citation template
break;
PostScript = '.'; -- must be a cite xxx template so set postscript to default (period)
end
else
if PostScript:lower() == 'none' then -- if |postscript=none then
PostScript = ''; -- no postscript
end
end
 
--check this page to see if it is in one of the namespaces that cs1 is not supposed to add to the error categories.
if not is_set(no_tracking_cats) then -- ignore if we are already not going to categorize this page
for k, v in pairs( cfg.uncategorized_namespaces ) do -- otherwise, spin through the list of namespaces we don't include in error categories
if this_page.nsText == v then -- if we find one
no_tracking_cats = "true"; -- set no_trackin_cats
break; -- and we're done
end
end
end
 
-- check for extra |page=, |pages= or |at= parameters.
local anchor_year; -- used in the CITEREF identifier
if is_set(Page) then
local COinS_date; -- used in the COinS metadata
if is_set(Pages) or is_set(At) then
Page = Page .. " " .. seterror('extra_pages'); -- add error message
Pages = ''; -- unset the others
At = '';
end
elseif is_set(Pages) then
if is_set(At) then
Pages = Pages .. " " .. seterror('extra_pages'); -- add error messages
At = ''; -- unset
end
end
 
-- both |publication-place= and |place= (|location=) allowed if different
-- Go test all of the date-holding parameters for valid MOS:DATE format and make sure that dates are real dates.
if not is_set(PublicationPlace) and is_set(Place) then
-- 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.
PublicationPlace = Place; -- promote |place= (|location=) to |publication-place
anchor_year, COinS_date = dates({['accessdate']=AccessDate, ['airdate']=AirDate, ['archivedate']=ArchiveDate, ['date']=Date, ['doi_brokendate']=DoiBroken,
end
['embargo']=Embargo, ['laydate']=LayDate, ['publicationdate']=PublicationDate, ['year']=Year});
if PublicationPlace == Place then Place = ''; end -- don't need both if they are the same
--[[
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-mapped
if not is_set(Year) then -- prevent Year from being set from DateIn TODO: eliminate the need for this?
 
if is_set(anchor_year) then
All other combinations of |encyclopedia, |title, and |article are not modified
Year = anchor_year;
]]
if ( config.CitationClass == "encyclopaedia" ) then
if is_set(Periodical) then -- Periodical is set when |encyclopedia is set
if is_set(Title) then
if not is_set(Chapter) then
Chapter = Title; -- |encyclopedia and |title are set so map |title to |article and |encyclopedia to |title
TransChapter = TransTitle;
Title = Periodical;
Periodical = ''; -- redundant so unset
TransTitle = ''; -- redundant so unset
end
else -- |title not set
Title = Periodical; -- |encyclopedia set and |article set or not set so map |encyclopedia to |title
Periodical = ''; -- redundant so unset
end
end
end
 
--special cases for citation.
if (config.CitationClass == "citation") then -- for citation templates
if not is_set (Ref) then -- if |ref= is not set
Ref = "harv"; -- set default |ref=harv
end
if not is_set (sepc) then -- if |separator= is not set
sepc = ','; -- set citation separator to its default (comma)
end
else -- not a citation template
if not is_set (sepc) then -- if |separator= has not been set
sepc = '.'; -- set cite xxx separator to its default (period)
end
end
 
-- check for specital case where |separator=none
if 'none' == sepc:lower() then -- if |separator=none
sepc = ''; -- then set it to a empty string
end
 
-- Special case for cite techreport.
if (config.CitationClass == "techreport") then -- special case for cite techreport
if 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 it
Issue = ""; -- unset Issue so that "number" isn't duplicated in the rendered citation or COinS metadata
else -- can't use ID so emit error message
ID = ID .. " " .. seterror('redundant_parameters', '<code>&#124;id=</code> and <code>&#124;number=</code>');
end
end
end
 
-- special case for cite interview
if (config.CitationClass == "interview") then
if is_set(Program) then
ID = ' ' .. Program;
end
if is_set(Callsign) then
if is_set(ID) then
ID = ID .. sepc .. ' ' .. Callsign;
else
ID = ' ' .. Callsign;
end
end
if is_set(City) then
if is_set(ID) then
ID = ID .. sepc .. ' ' .. City;
else
ID = ' ' .. City;
end
end
 
if is_set(Interviewer) then
if is_set(TitleType) then
Others = ' ' .. TitleType .. ' with ' .. Interviewer;
TitleType = '';
else
Others = ' ' .. 'Interview with ' .. Interviewer;
end
if is_set(Cointerviewers) then
Others = Others .. sepc .. ' ' .. Cointerviewers;
end
else
Others = '(Interview)';
end
end
 
--Account for the oddity that is {{cite journal}} with |pmc= set and |url= not set
if config.CitationClass == "journal" and not is_set(URL) and is_set(ID_list['PMC']) then
if not is_embargoed(Embargo) then
URL=cfg.id_handlers['PMC'].prefix .. ID_list['PMC']; -- set url to be the same as the PMC external link if not embargoed
URLorigin = cfg.id_handlers['PMC'].parameters[1]; -- set URLorigin to parameter name for use in error message if citation is missing a |title=
end
end
 
-- Account for the oddity that is {{cite conference}}, before generation of COinS data.
--TODO: if this is only for {{cite conference}}, shouldn't we be checking? (if config.CitationClass=='conference' then ...)
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.
--[[ -- {{cite episode}} is not currently supported by this module
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
-- end of {{cite episode}} stuff]]
 
-- 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) then
Date = Year; -- promote Year to Date
Year = nil; -- make nil so Year as empty string isn't used for CITEREF
if is_set(Date) then
local Month = A['Month'];
if is_set(Month) then
Date = Month .. " " .. Date;
local Day = A['Day']
if is_set(Day) then Date = Day .. " " .. Date end
end
elseif is_set(PublicationDate) then -- use PublicationDate when |date= and |year= are not set
Date = PublicationDate; -- promonte PublicationDate to Date
PublicationDate = ''; -- unset, no longer needed
end
end
 
if 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. This must be done before we do COinS because here is where
we get the date used in the metadata.
 
Date validation supporting code is in Module:Citation/CS1/Date_validation
]]
anchor_year, COinS_date, error_message = dates({['accessdate']=AccessDate, ['airdate']=AirDate, ['archivedate']=ArchiveDate, ['date']=Date, ['doi_brokendate']=DoiBroken,
['embargo']=Embargo, ['laydate']=LayDate, ['publicationdate']=PublicationDate, ['year']=Year});
if is_set(error_message) then
table.insert( z.message_tail, { seterror( 'bad_date', {error_message}, true ) } ); -- add this error message
end
 
-- 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 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.
Liña 1.260 ⟶ 1.354:
['Title'] = Title,
['PublicationPlace'] = PublicationPlace,
['Date'] = first_set(COinS_date, Date), -- Year,COinS_date PublicationDate),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'] = get_coins_pages (first_set(Page, Pages, At)), -- pages stripped of external links
['Edition'] = Edition,
['PublisherName'] = PublisherName,
Liña 1.308 ⟶ 1.402:
control.lastauthoramp = nil;
control.maximum = #a + 1;
deprecated_parameter(); -- |coauthor= and |coathors= are deprecated; add this page to deprecated parameter category
end
Liña 1.316 ⟶ 1.409:
if not is_set(Authors) and is_set(Coauthors) then -- coauthors aren't displayed if one of authors=, authorn=, or lastn= isn't specified
table.insert( z.message_tail, { seterror('coauthors_missing_author', {}, true) } ); -- emit error message
deprecated_parameter(); -- |coauthor= and |coathors= are deprecated; add this page to deprecated parameter category
end
 
Liña 1.359 ⟶ 1.451:
end
end
if not is_set(Date) then
Date = Year;
if is_set(Date) then
local Month = A['Month'];
if is_set(Month) then
deprecated_parameter(); -- |month= (and also |day=) is deprecated; add this page to deprecated parameter category
Date = Month .. " " .. Date;
local Day = A['Day']
if is_set(Day) then Date = Day .. " " .. Date end
end
end
end
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
Liña 1.388 ⟶ 1.458:
not is_set(TranscriptURL) then
-- Test if cite web isor calledcite podcast |url= is withoutmissing givingor aempty URL
if inArray( config.CitationClass, == {"web" ,"podcast"}) then
table.insert( z.message_tail, { seterror( 'cite_web_url', {}, true ) } );
end
-- Test if accessdate is given without giving a URL
Liña 1.434 ⟶ 1.504:
TransChapter = wrap( 'trans-italic-title', TransChapter );
else
Chapter = kern_quotes (Chapter); -- if necessary, separate chapter title's leading and trailing quote marks from Module provided quote marks
Chapter = wrap( 'quoted-title', Chapter );
TransChapter = wrap( 'trans-quoted-title', TransChapter );
Liña 1.481 ⟶ 1.552:
if is_set(Periodical) then
Title = kern_quotes (Title); -- if necessary, separate title's leading and trailing quote marks from Module provided quote marks
Title = wrap( 'quoted-title', Title );
TransTitle = wrap( 'trans-quoted-title', TransTitle );
elseif inArray(config.CitationClass, {"web","news","pressrelease","conference","podcast"}) and
not is_set(Chapter) then
Title = kern_quotes (Title); -- if necessary, separate title's leading and trailing quote marks from Module provided quote marks
Title = wrap( 'quoted-title', Title );
TransTitle = wrap( 'trans-quoted-title', TransTitle );
Liña 1.551 ⟶ 1.624:
if is_set(Pages) then
if is_set(Periodical) and
not inArray(config.CitationClass, {"encyclopaedia","web","book","news","podcast"}) then
Pages = ": " .. Pages;
elseif tonumber(Pages) ~= nil then
Liña 1.561 ⟶ 1.634:
else
if is_set(Periodical) and
not inArray(config.CitationClass, {"encyclopaedia","web","book","news","podcast"}) then
Page = ": " .. Page;
else
Liña 1.599 ⟶ 1.672:
]]
if is_set (Language) then
-- local name = mw.language.fetchLanguageName( Language:lower(), "en" ); -- experiment: this seems to return correct ISO 639-1 language names
local name = cfg.iso639_1[Language:lower()]; -- get the language name if Language parameter has a valid iso 639-1 code
if nil == name then
Liña 1.617 ⟶ 1.691:
-- handle type parameter for those CS1 citations that have default values
 
if "pressrelease" == inArray(config.CitationClass, then --{"AV ifmedia thisnotes", citation"DVD isnotes", cite"podcast", press"pressrelease", release"techreport", "thesis"}) then
ifTitleType not= is_setset_titletype (config.CitationClass, TitleType) then;
if is_set(Degree) and "Thesis" == TitleType then -- special case for cite thesis
TitleType = "Press release"; -- if type not specified, display the press release annotation
TitleType = Degree .. " thesis";
else
if "none" == TitleType then TitleType = ""; end -- if |type=none then type parameter not displayed
end
end
 
elseif "techreport" == config.CitationClass then -- if this citation is cite techreport
if not is_set (TitleType) then
TitleType = "Technical report"; -- if type not specified, display the techreport annotation
else
if "none" == TitleType then TitleType = ""; end -- if |type=none then type parameter not displayed; |number=, if set, will be displayed
end
elseif "thesis" == config.CitationClass then -- if this citation is cite thesis
if not is_set (TitleType) then
if is_set(Degree) then -- if type not specified, display one of the thesis annotations
TitleType = Degree .. " thesis"; -- if a degree (masters, PhD, ...) is specified include it in the display
else
TitleType = "Thesis"; -- otherwise display the simple thesis annotation
end
else
if "none" == TitleType then TitleType = ""; end -- if |type=none then type parameter not displayed
end
end
if is_set(TitleType) then -- if type parameter is specified
TitleType = " (" .. TitleType .. ")"; -- display it in parentheses
Liña 1.652 ⟶ 1.708:
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 )
Liña 1.659 ⟶ 1.715:
end
end
 
--[[ This code commented out while discussion continues until after week of 2014-03-23 live module update;
if is_set(Volume) then
if ( mw.ustring.len(Volume) > 4 )
then Volume = sepc .. " " .. Volume;
else
Volume = " <b>" .. hyphentodash(Volume) .. "</b>";
if is_set(Series) then Volume = sepc .. Volume;
end
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
Liña 1.700 ⟶ 1.767:
end
Quote = sepc .." " .. wrap( 'quoted-text', Quote );
PostScript = ""; -- CS1 does not supply terminal punctuation when |quote= is set
elseif PostScript:lower() == "none" then
PostScript = "";
end
Liña 1.758 ⟶ 1.823:
local Publisher;
if is_set(Periodical) and
not inArray(config.CitationClass, {"encyclopaedia","web","pressrelease","podcast"}) then
if is_set(PublisherName) then
if is_set(PublicationPlace) then
Liña 1.805 ⟶ 1.870:
end
end
 
--[[
Handle the oddity that is cite speech. This code overrides whatever may be the value assigned to TitleNote (through |department=) and forces it to be " (Speech)" so that
the annotation directly follows the |title= parameter value in the citation rather than the |event= parameter value (if provided).
]]
if "speech" == config.CitationClass then -- cite speech only
TitleNote = " (Speech)"; -- annotate the citation
if is_set (Periodical) then -- if Periodical, perhaps because of an included |website= or |journal= parameter
if is_set (Conference) then -- and if |event= is set
Conference = Conference .. sepc .. " "; -- then add appropriate punctuation to the end of the Conference variable before rendering
end
end
end
 
-- Piece all bits together at last. Here, all should be non-nil.
Liña 1.895 ⟶ 1.973:
end
if is_set(PostScript) and PostScript ~= sepc then
text = safejoin( {text, sepc}, sepc ); --Deals with italics, spaces, etc.
text = text:sub(1,-2sepc:len()-1); --Remove final seperator
-- text = text:sub(1,-2); --Remove final separator (assumes that sepc is only one character)
end
end
text = safejoin( {text, PostScript}, sepc );
 
-- Now enclose the whole thing in a <span/> element
if not is_set(Year) then
if is_set(DateIn) then
Year = selectyear( DateIn );
elseif is_set(PublicationDate) then
Year = selectyear( PublicationDate );
end
end
local options = {};
Liña 1.934 ⟶ 2.005:
end
end
names[ #names + 1 ] = first_set(Year or, anchor_year); -- Year first for legacy citations
id = anchorid(names)
end
Liña 1.985 ⟶ 2.056:
local pframe = frame:getParent()
if nil ~= string.find( frame:getTitle(), 'sandbox', 1, true ) then -- did the {{#invoke:}} use sandbox version?
cfg = mw.loadData( 'Module:Citation/CS1/Configuration/sandbox' ); -- load sandbox versions of Configuration and Whitelist and ...
whitelist = mw.loadData( 'Module:Citation/CS1/Whitelist/sandbox' );
dates = require('Module:Citation/CS1/Date_validation/sandbox').dates -- ... sandbox version of date validation code
else -- otherwise
cfg = mw.loadData( 'Module:Citation/CS1/Configuration' ); -- load live versions of Configuration and Whitelist and ...
whitelist = mw.loadData( 'Module:Citation/CS1/Whitelist' );
dates = require('Module:Citation/CS1/Date_validation').dates -- ... live version of date validation code
end
local args = {};
local suggestions = {};