Jump to content

Module:Citation/CS1: Difference between revisions

Synch from sandbox;
m>Trappist the monk
(Synch from sandbox;)
m>Trappist the monk
(Synch from sandbox;)
Line 11: Line 11:
]]
]]
local dates, year_date_check -- functions in Module:Citation/CS1/Date_validation
local dates, year_date_check -- functions in Module:Citation/CS1/Date_validation
local cfg = {}; -- table of configuration tables that are defined in Module:Citation/CS1/Configuration
local whitelist = {}; -- talbe of tables listing valid template parameter names; defined in Module:Citation/CS1/Whitelist


--[[--------------------------< I S _ S E T >------------------------------------------------------------------
--[[--------------------------< I S _ S E T >------------------------------------------------------------------
Line 111: Line 114:
return error_comment( message, error_state.hidden );
return error_comment( message, error_state.hidden );
end
--[[--------------------------< A D D _ M A I N T _ C A T >------------------------------------------------------
Adds a category to z.maintenance_cats using names from the configuration file with additional text if any.
]]
local function add_maint_cat (key, arguments)
table.insert( z.maintenance_cats, substitute (cfg.maint_cats [key], arguments)); -- make name then add to table
end
--[[--------------------------< A D D _ P R O P _ C A T >--------------------------------------------------------
Adds a category to z.properties_cats using names from the configuration file with additional text if any.
]]
local function add_prop_cat (key, arguments)
table.insert( z.properties_cats, substitute (cfg.prop_cats [key], arguments)); -- make name then add to table
end
end


Line 302: Line 325:
-- is prefix one of these language codes?
-- is prefix one of these language codes?
if in_array (lang, {'ar', 'bg', 'bs', 'dv', 'el', 'fa', 'hy', 'ja', 'ka', 'ko', 'ku', 'he', 'ps', 'ru', 'sd', 'sr', 'th', 'uk', 'ug', 'yi', 'zh'}) then
if in_array (lang, {'ar', 'bg', 'bs', 'dv', 'el', 'fa', 'hy', 'ja', 'ka', 'ko', 'ku', 'he', 'ps', 'ru', 'sd', 'sr', 'th', 'uk', 'ug', 'yi', 'zh'}) then
table.insert( z.properties_cats, 'CS1 uses ' .. name .. '-language script ('..lang..')'); -- categorize in language-specific categories
add_prop_cat ('script_name', {name, lang})
else
else
table.insert( z.properties_cats, 'CS1 uses foreign language script'); -- use this category as a catchall until language-specific category is available
add_prop_cat ('script')
end
end
lang = ' lang="' .. lang .. '" '; -- convert prefix into a lang attribute
lang = ' lang="' .. lang .. '" '; -- convert prefix into a lang attribute
Line 354: Line 377:
end
end
end
end
--[[--------------------------< S E L E C T _ O N E >----------------------------------------------------------
--[[--------------------------< S E L E C T _ O N E >----------------------------------------------------------


Line 454: Line 478:
can be transparently aliased to single internal variable.
can be transparently aliased to single internal variable.
]]
]]
local function argument_wrapper( args )
local function argument_wrapper( args )
local origin = {};
local origin = {};
Line 504: Line 529:
nil - unsupported parameters
nil - unsupported parameters
]]
]]
local function validate( name )
local function validate( name )
local name = tostring( name );
local name = tostring( name );
Line 572: Line 598:
local function is_valid_isxn (isxn_str, len)
local function is_valid_isxn (isxn_str, len)
local temp = 0;
local temp = 0;
isxn_str = { isxn_str:byte(1, len) }; -- make a table of bytes
isxn_str = { isxn_str:byte(1, len) }; -- make a table of byte values '0' → 0x30 .. '9'  → 0x39, 'X' → 0x58
len = len+1; -- adjust to be a loop counter
len = len+1; -- adjust to be a loop counter
for i, v in ipairs( isxn_str ) do -- loop through all of the bytes and calculate the checksum
for i, v in ipairs( isxn_str ) do -- loop through all of the bytes and calculate the checksum
if v == string.byte( "X" ) then -- if checkdigit is X
if v == string.byte( "X" ) then -- if checkdigit is X (compares the byte value of 'X' which is 0x58)
temp = temp + 10*( len - i ); -- it represents 10 decimal
temp = temp + 10*( len - i ); -- it represents 10 decimal
else
else
Line 674: Line 700:
if id:match("^%d%d%d%d%d%d%d%d%d[%dX]$") then -- if 10-digit numeric (or 9 digits with terminal X)
if id:match("^%d%d%d%d%d%d%d%d%d[%dX]$") then -- if 10-digit numeric (or 9 digits with terminal X)
if check_isbn( id ) then -- see if asin value is isbn10
if check_isbn( id ) then -- see if asin value is isbn10
table.insert( z.maintenance_cats, 'CS1 maint: ASIN uses ISBN'); -- add to maint category
add_maint_cat ('ASIN');
elseif not is_set (err_cat) then
elseif not is_set (err_cat) then
err_cat =  ' ' .. set_error ('bad_asin'); -- asin is not isbn10
err_cat =  ' ' .. set_error ('bad_asin'); -- asin is not isbn10
Line 724: Line 750:
]]
]]


local function arxiv (id)
local function arxiv (id, class)
local handler = cfg.id_handlers['ARXIV'];
local handler = cfg.id_handlers['ARXIV'];
local year, month, version;
local year, month, version;
local err_cat = ""
local err_cat = '';
local text;
if id:match("^%a[%a%.%-]+/[90]%d[01]%d%d%d%d$") or id:match("^%a[%a%.%-]+/[90]%d[01]%d%d%d%dv%d+$") then -- test for the 9108-0703 format w/ & w/o version
if id:match("^%a[%a%.%-]+/[90]%d[01]%d%d%d%d$") or id:match("^%a[%a%.%-]+/[90]%d[01]%d%d%d%dv%d+$") then -- test for the 9108-0703 format w/ & w/o version
Line 756: Line 783:
end
end


return external_link_id({link = handler.link, label = handler.label,
text = external_link_id({link = handler.link, label = handler.label,
prefix=handler.prefix,id=id,separator=handler.separator, encode=handler.encode}) .. err_cat;
prefix=handler.prefix,id=id,separator=handler.separator, encode=handler.encode}) .. err_cat;
if is_set (class) then
class = ' [[' .. '//arxiv.org/archive/' .. class .. ' ' .. class .. ']]'; -- external link within square brackets, not wikilink
else
class = ''; -- empty string for concatenation
end
return text .. class;
end
end


--[[
--[[
Line 804: Line 838:


]]
]]
local function lccn(lccn)
local function lccn(lccn)
local handler = cfg.id_handlers['LCCN'];
local handler = cfg.id_handlers['LCCN'];
Line 850: Line 885:
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.
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.
]]
]]
local function pmid(id)
local function pmid(id)
local test_limit = 30000000; -- update this value as PMIDs approach
local test_limit = 30000000; -- update this value as PMIDs approach
Line 868: Line 904:
end
end


--[[
--[[--------------------------< I S _ E M B A R G O E D >------------------------------------------------------
 
Determines if a PMC identifier's online version is embargoed. Compares the date in |embargo= against today's date.  If embargo date is
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; otherwise, returns false because the embargo has expired or |embargo= not set in this cite.
in the future, returns the content of |embargo=; otherwise, returns and empty string because the embargo has expired or because
|embargo= was not set in this cite.
 
]]
]]
local function is_embargoed(embargo)
 
if is_set(embargo) then
local function is_embargoed (embargo)
if is_set (embargo) then
local lang = mw.getContentLanguage();
local lang = mw.getContentLanguage();
local good1, embargo_date, good2, todays_date;
local good1, embargo_date, good2, todays_date;
Line 879: Line 919:
good2, todays_date = pcall( lang.formatDate, lang, 'U' );
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?
if good1 and good2 then -- if embargo date and today's date are good dates
return true; -- still embargoed
if tonumber( embargo_date ) >= tonumber( todays_date ) then -- is embargo date is in the future?
return embargo; -- still embargoed
else
add_maint_cat ('embargo')
return ''; -- unset because embargo has expired
end
end
end
end
end
return false; -- embargo expired or |embargo= not set
return ''; -- |embargo= not set return empty string
end
end


--[[
--[[--------------------------< P M C >------------------------------------------------------------------------
 
Format a PMC, do simple error checking, and check for embargoed articles.
Format a PMC, do simple error checking, and check for embargoed articles.


The embargo parameter takes a date for a value. If the embargo date is in the future
The embargo parameter takes a date for a value. If the embargo date is in the future the PMC identifier will not
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
be linked to the article.  If the embargo date is today or in the past, or if it is empty or omitted, then the
the PMC identifier is linked to the article through the link at cfg.id_handlers['PMC'].prefix.
PMC identifier is linked to the article through the link at cfg.id_handlers['PMC'].prefix.
 
PMC embargo date testing is done in function is_embargoed () which is called earlier because when the citation
has |pmc=<value> but does not have a |url= then |title= is linked with the PMC link.  Function is_embargoed ()
returns the embargo date if the PMC article is still embargoed, otherwise it returns an empty string.


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
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.
than test_limit; the value in local variable test_limit will need to be updated periodically as more PMCs are issued.
]]
]]
local function pmc(id, embargo)
local function pmc(id, embargo)
local test_limit = 5000000; -- update this value as PMCs approach
local test_limit = 5000000; -- update this value as PMCs approach
Line 912: Line 964:
end
end
if is_embargoed(embargo) then
if is_set (embargo) then -- is PMC is still embargoed?
text="[[" .. handler.link .. "|" .. handler.label .. "]]:" .. handler.separator .. id .. err_cat; --still embargoed so no external link
text="[[" .. handler.link .. "|" .. handler.label .. "]]:" .. handler.separator .. id .. err_cat; -- still embargoed so no external link
else
else
text = external_link_id({link = handler.link, label = handler.label, --no embargo date, ok to link to article
text = external_link_id({link = handler.link, label = handler.label, -- no embargo date or embargo has expired, ok to link to article
prefix=handler.prefix,id=id,separator=handler.separator, encode=handler.encode}) .. err_cat;
prefix=handler.prefix,id=id,separator=handler.separator, encode=handler.encode}) .. err_cat;
end
end
Line 1,004: Line 1,056:
return text
return text
end
end


--[[--------------------------< S E T _ T I T L E T Y P E >----------------------------------------------------
--[[--------------------------< S E T _ T I T L E T Y P E >----------------------------------------------------


This function sets default title types (equivalent to the citation including |type=<default value>) for those citations that have defaults.
This function sets default title types (equivalent to the citation including |type=<default value>) for those templates that have defaults.
Also handles the special case where it is desirable to omit the title type from the rendered citation (|type=none).
Also handles the special case where it is desirable to omit the title type from the rendered citation (|type=none).


]]
]]
local function set_titletype(cite_class, title_type)
 
local function set_titletype (cite_class, title_type)
if is_set(title_type) then
if is_set(title_type) then
if "none" == title_type then
if "none" == title_type then
title_type = ""; -- if |type=none then type parameter not displayed
title_type = ""; -- if |type=none then type parameter not displayed
end
end
return title_type; -- if |type= has been set to any other value use that value
return title_type; -- if |type= has been set to any other value use that value
end
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
return cfg.title_types [cite_class] or ''; -- set template's default title type; else empty string for concatenation
return "Media notes"; -- display AV media notes / DVD media notes annotation
end


elseif "mailinglist" == cite_class then -- if this citation is cite mailing list
--[[--------------------------< C L E A N _ I S B N >----------------------------------------------------------
return "Mailing list"; -- display mailing list annotation


elseif "map" == cite_class then -- if this citation is cite map
Removes irrelevant text and dashes from ISBN number
return "Map"; -- display map annotation
Similar to that used for Special:BookSources


elseif "podcast" == cite_class then -- if this citation is cite podcast
]]
return "Podcast"; -- display podcast annotation


elseif "pressrelease" == cite_class then -- if this citation is cite press release
return "Press release"; -- display press release annotation
elseif "report" == cite_class then -- if this citation is cite report
return "Report"; -- display report annotation
elseif "techreport" == cite_class then -- if this citation is cite techreport
return "Technical report"; -- display techreport annotation
elseif "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)
end
end
-- Removes irrelevant text and dashes from ISBN number
-- Similar to that used for Special:BookSources
local function clean_isbn( isbn_str )
local function clean_isbn( isbn_str )
return isbn_str:gsub( "[^-0-9X]", "" );
return isbn_str:gsub( "[^-0-9X]", "" );
Line 1,071: Line 1,104:


]]
]]
local function strip_apostrophe_markup (argument)
local function strip_apostrophe_markup (argument)
if not is_set (argument) then return argument; end
if not is_set (argument) then return argument; end
Line 1,121: Line 1,155:


]]
]]
local function get_coins_pages (pages)
local function get_coins_pages (pages)
local pattern;
local pattern;
Line 1,157: Line 1,192:


]]
]]
local function safe_join( tbl, duplicate_char )
local function safe_join( tbl, duplicate_char )
--[[
--[[
Line 1,228: Line 1,264:
return str;
return str;
end   
end   


--[[--------------------------< I S _ G O O D _ V A N C _ N A M E >--------------------------------------------
--[[--------------------------< I S _ G O O D _ V A N C _ N A M E >--------------------------------------------
Line 1,235: Line 1,270:
uses characters that contain diacritical marks, those characters are to converted to the corresponding Latin character.
uses characters that contain diacritical marks, those characters are to converted to the corresponding Latin character.
When a name is written using a non-Latin alphabet or logogram, that name is to be transliterated into Latin characters.
When a name is written using a non-Latin alphabet or logogram, that name is to be transliterated into Latin characters.
These things are not currently possible in this module so are left to the editor to do. This module can, however, check
These things are not currently possible in this module so are left to the editor to do.
the content of |lastn= and |firstn= to see if the names contain non-Latin (non-ASCII) characters and emit an error message
 
when such characters are located.
This test allows |first= and |last= names to contain any of the letters defined in the four Unicode Latin character sets
[http://www.unicode.org/charts/PDF/U0000.pdf C0 Controls and Basic Latin] 0041–005A, 0061–007A
[http://www.unicode.org/charts/PDF/U0080.pdf C1 Controls and Latin-1 Supplement] 00C0–00D6, 00D8–00F6, 00F8–00FF
[http://www.unicode.org/charts/PDF/U0100.pdf Latin Extended-A] 0100–017F
[http://www.unicode.org/charts/PDF/U0180.pdf Latin Extended-B] 0180–01BF, 01C4–024F
 
|lastn= also allowed to contain hyphens, spaces, and apostrophes. (http://www.ncbi.nlm.nih.gov/books/NBK7271/box/A35029/)
|firstn= also allowed to contain hyphens, spaces, apostrophes, and periods
 
At the time of this writing, I had to write the 'if nil == mw.ustring.find ...' test ouside of the code editor and past it here
because the code editor gets confused between character insertion point and cursor position.


Allow |lastn= to contain ASCII characters, hyphens, spaces, and apostrophes. (http://www.ncbi.nlm.nih.gov/books/NBK7271/box/A35029/)
Allow |firstn= to contain ASCII characters, hyphens, spaces, apostrophes, and periods
]]
]]


local function is_good_vanc_name (last, first)
local function is_good_vanc_name (last, first)
if last:find ("[^%a%-%'%s]") or first:find ("[^%a%-%'%s%.]") then
if nil == mw.ustring.find (last, "^[A-Za-zÀ-ÖØ-öø-ƿDŽ-ɏ%-%s%']*$") or nil == mw.ustring.find (first, "^[A-Za-zÀ-ÖØ-öø-ƿDŽ-ɏ%-%s%'%.]*$") then
if true ~= Page_in_vanc_error_cat then -- if we haven't been here before then set a sticky flag
if true ~= Page_in_vanc_error_cat then -- if we haven't been here before then set a sticky flag
Page_in_vanc_error_cat=true; -- so that if there are more than one error the category is added only once
Page_in_vanc_error_cat=true; -- so that if there are more than one error the category is added only once
Line 1,253: Line 1,296:
return true;
return true;
end
end


--[[--------------------------< R E D U C E _ T O _ I N I T I A L S >------------------------------------------
--[[--------------------------< R E D U C E _ T O _ I N I T I A L S >------------------------------------------
Line 1,263: Line 1,305:
Vancouver style requires family rank designations (Jr, II, III, etc) to be rendered as Jr, 2nd, 3rd, etc.  This form is not
Vancouver style requires family rank designations (Jr, II, III, etc) to be rendered as Jr, 2nd, 3rd, etc.  This form is not
currently supported by this code so correctly formed names like Smith JL 2nd are converted to Smith J2. See http://www.ncbi.nlm.nih.gov/books/NBK7271/box/A35085/.
currently supported by this code so correctly formed names like Smith JL 2nd are converted to Smith J2. See http://www.ncbi.nlm.nih.gov/books/NBK7271/box/A35085/.
This function uses ustring functions because firstname initials may be any of the unicode Latin characters accepted by is_good_vanc_name ().


]]
]]


local function reduce_to_initials(first)
local function reduce_to_initials(first)
if first:match("^%u%u$") then return first end; -- when first contains just two upper-case letters, nothing to do
if mw.ustring.match(first, "^%u%u$") then return first end; -- when first contains just two upper-case letters, nothing to do
local initials = {}
local initials = {}
local i = 0; -- counter for number of initials
local i = 0; -- counter for number of initials
for word in string.gmatch(first, "[^%s%.%-]+") do -- names separated by spaces, hyphens, or periods
for word in mw.ustring.gmatch(first, "[^%s%.%-]+") do -- names separated by spaces, hyphens, or periods
table.insert(initials, string.sub(word,1,1)) -- Vancouver format does not include full stops.
table.insert(initials, mw.ustring.sub(word,1,1)) -- Vancouver format does not include full stops.
i = i + 1; -- bump the counter  
i = i + 1; -- bump the counter  
if 2 <= i then break; end -- only two initials allowed in Vancouver system; if 2, quit
if 2 <= i then break; end -- only two initials allowed in Vancouver system; if 2, quit
Line 1,279: Line 1,323:


--[[--------------------------< L I S T  _ P E O P L E >-------------------------------------------------------
--[[--------------------------< L I S T  _ P E O P L E >-------------------------------------------------------
Formats a list of people (e.g. authors / editors)  
Formats a list of people (e.g. authors / editors)  
]]
]]
local function list_people(control, people, etal)
local function list_people(control, people, etal)
local sep;
local sep;
Line 1,298: Line 1,345:
if sep:sub(-1,-1) ~= " " then sep = sep .. " " end
if sep:sub(-1,-1) ~= " " then sep = sep .. " " end
if maximum ~= nil and maximum < 1 then return "", 0; end
if is_set (maximum) and maximum < 1 then return "", 0; end -- returned 0 is for EditorCount; not used for authors
for i,person in ipairs(people) do
for i,person in ipairs(people) do
Line 1,305: Line 1,352:
local one
local one
local sep_one = sep;
local sep_one = sep;
if maximum ~= nil and i > maximum then
if is_set (maximum) and i > maximum then
etal = true;
etal = true;
break;
break;
Line 1,358: Line 1,405:


--[[--------------------------< A N C H O R _ I D >------------------------------------------------------------
--[[--------------------------< A N C H O R _ I D >------------------------------------------------------------
Generates a CITEREF anchor ID if we have at least one name or a date.  Otherwise returns an empty string.
Generates a CITEREF anchor ID if we have at least one name or a date.  Otherwise returns an empty string.


Line 1,437: Line 1,485:
if true == etal then
if true == etal then
table.insert( z.maintenance_cats, 'CS1 maint: Explicit use of et al.'); -- add to maint category
add_maint_cat ('etal');
end
end
return names, etal; -- all done, return our list of names
return names, etal; -- all done, return our list of names
Line 1,453: Line 1,501:


--[[--------------------------< B U I L D _ I D _ L I S T >--------------------------------------------------------
--[[--------------------------< B U I L D _ I D _ L I S T >--------------------------------------------------------
Takes a table of IDs and turns it into a table of formatted ID outputs.
Takes a table of IDs and turns it into a table of formatted ID outputs.


]]
]]
local function build_id_list( id_list, options )
local function build_id_list( id_list, options )
local new_list, handler = {};
local new_list, handler = {};
Line 1,474: Line 1,524:
table.insert( new_list, {handler.label, doi( v, options.DoiBroken ) } );
table.insert( new_list, {handler.label, doi( v, options.DoiBroken ) } );
elseif k == 'ARXIV' then
elseif k == 'ARXIV' then
table.insert( new_list, {handler.label, arxiv( v ) } );  
table.insert( new_list, {handler.label, arxiv( v, options.Class ) } );  
elseif k == 'ASIN' then
elseif k == 'ASIN' then
table.insert( new_list, {handler.label, amazon( v, options.ASINTLD ) } );  
table.insert( new_list, {handler.label, amazon( v, options.ASINTLD ) } );  
Line 1,515: Line 1,565:
-- COinS metadata (see <http://ocoins.info/>) allows automated tools to parse
-- COinS metadata (see <http://ocoins.info/>) allows automated tools to parse
-- the citation information.
-- the citation information.
local function COinS(data)
local function COinS(data, class)
if 'table' ~= type(data) or nil == next(data) then
if 'table' ~= type(data) or nil == next(data) then
return '';
return '';
Line 1,538: Line 1,588:
elseif is_set(data.Periodical) then
elseif is_set(data.Periodical) then
OCinSoutput.rft_val_fmt = "info:ofi/fmt:kev:mtx:journal";
OCinSoutput.rft_val_fmt = "info:ofi/fmt:kev:mtx:journal";
OCinSoutput["rft.genre"] = "article";
if 'arxiv' == class then
OCinSoutput["rft.genre"] = "preprint"; -- cite arxiv
else
OCinSoutput["rft.genre"] = "article";
end
OCinSoutput["rft.jtitle"] = data.Periodical;
OCinSoutput["rft.jtitle"] = data.Periodical;
OCinSoutput["rft.atitle"] = data.Title;
OCinSoutput["rft.atitle"] = data.Title;
Line 1,610: Line 1,664:


Adapted from code taken from Module:Check ISO 639-1.
Adapted from code taken from Module:Check ISO 639-1.
]]
]]


Line 1,647: Line 1,702:
When |language= contains a valid ISO639-1 code, the page is assigned to the category for that code: Category:Norwegian-language sources (no) if
When |language= contains a valid ISO639-1 code, the page is assigned to the category for that code: Category:Norwegian-language sources (no) if
the page is a mainspace page and the ISO639-1 code is not 'en'.  Similarly, if the  parameter is |language=Norwegian, it will be categorized in the same way.
the page is a mainspace page and the ISO639-1 code is not 'en'.  Similarly, if the  parameter is |language=Norwegian, it will be categorized in the same way.
This function supports multiple languages in the form |language=nb, French, th where the language names or codes are separated from each other by commas.


]]
]]


local function language_parameter (lang, namespace)
local function language_parameter (lang, namespace)
local code; -- the ISO639-1 two character code
local code; -- the ISO639-1 two character code
local name; -- the language name
local name; -- the language name
local test='';
local language_list = {}; -- table of language names to be rendered
local names_table = {}; -- table made from the value assigned to |language=
local unrec_cat = false -- flag so that we only add unrecognized category once
names_table = mw.text.split (lang, '%s*,%s*'); -- names should be a comma separated list
for _, lang in ipairs (names_table) do -- reuse lang
if 0 == namespace and (('en' == lang:lower()) or ('english' == lang:lower())) then
add_maint_cat ('english');
end
if 2 == lang:len() then -- ISO639-1 language code are 2 characters (fetchLanguageName also supports 3 character codes)
name = mw.language.fetchLanguageName( lang:lower(), "en" ); -- get ISO 639-1 language name if Language is a proper code
end
if is_set (name) then -- if Language specified a valid ISO639-1 code
code = lang:lower(); -- save it
else
name, code = get_iso639_code (lang); -- attempt to get code from name (assign name here so that we are sure of proper capitalization)
end
if is_set (code) then
if 'no' == code then name = 'Norwegian' end; -- override wikimedia when code is 'no'
if 0 == namespace and 'en' ~= code then -- is this page main / article space and English not the language?
add_prop_cat ('foreign_lang_source', {name, code})
end
elseif false == unrec_cat then
unrec_cat = true; -- only add this category once
add_maint_cat (unknown_lang);
end
if 0 == namespace and (('en' == lang:lower()) or ('english' == lang:lower())) then
table.insert (language_list, name);
table.insert (z.maintenance_cats, 'CS1 maint: English language specified'); -- add maintenance category if |language=English or |language=en in article space
name = ''; -- so we can reuse it
end
code = #language_list -- reuse code as number of languages in the list
if 2 >= code then
name = table.concat (language_list, ' and ') -- insert '<space>and<space>' between two language names
elseif 2 < code then
language_list[code] = 'and ' .. language_list[code]; -- prepend last name with 'and<space>'
name = table.concat (language_list, ', ') -- and concatenate with '<comma><space>' separators
end
end
return (" " .. wrap_msg ('language', name)); -- wrap with '(in ...)'
end
--[[--------------------------< S E T _ C S 1 _ S T Y L E >----------------------------------------------------
Set style settings for CS1 citation templates. Returns separator and postscript settings
]]


if 2 == lang:len() then -- ISO639-1 language code are 2 characters (fetchLanguageName also supports 3 character codes)
local function set_cs1_style (ps)
name = mw.language.fetchLanguageName( lang:lower(), "en" ); -- get ISO 639-1 language name if Language is a proper code
if not is_set (ps) then -- unless explicitely set to something
ps = '.'; -- terminate the rendered citation with a period
end
end
return '.', ps; -- separator is a full stop
end


if is_set (name) then -- if Language specified a valid ISO639-1 code
--[[--------------------------< S E T _ C S 2 _ S T Y L E >----------------------------------------------------
code = lang:lower(); -- save it
 
else
Set style settings for CS2 citation templates. Returns separator, postscript, ref settings
name, code = get_iso639_code (lang); -- attempt to get code from name (assign name here so that we are sure of proper capitalization)
 
]]
 
local function set_cs2_style (ps, ref)
if not is_set (ps) then -- if |postscript= has not been set, set cs2 default
ps = ''; -- make sure it isn't nil
end
end
 
if not is_set (ref) then -- if |ref= is not set
if is_set (code) then
ref = "harv"; -- set default |ref=harv
if 'no' == code then name = 'Norwegian' end; -- override wikimedia when code is 'no'
if 0 == namespace and 'en' ~= code then -- is this page main / article space and English not the language?
table.insert( z.properties_cats, 'CS1 ' .. name .. '-language sources (' .. code .. ')'); -- in main space and not English: categorize
end
else
table.insert (z.maintenance_cats, 'CS1 maint: Unrecognized language'); -- add maintenance category when |language= does not appear to be ISO 639-1 language
end
end
return (" " .. wrap_msg ('language', name)); -- wrap with '(in ...)'
return ',', ps, ref; -- separator is a comma
end
end


--[[--------------------------< G E T _ S E T T I N G S _ F R O M _ C I T E _ C L A S S >----------------------
--[[--------------------------< G E T _ S E T T I N G S _ F R O M _ C I T E _ C L A S S >----------------------
When |mode= is not set or when its value is invalid, use config.CitationClass and parameter values to establish
When |mode= is not set or when its value is invalid, use config.CitationClass and parameter values to establish
rendered style.
rendered style.
Line 1,687: Line 1,792:


local function get_settings_from_cite_class (ps, ref, cite_class)
local function get_settings_from_cite_class (ps, ref, cite_class)
local sep;
local sep;
if (cite_class == "citation") then -- for citation templates (CS2)
if (cite_class == "citation") then -- for citation templates (CS2)
sep = ','; -- set citation separator to its default (comma)
sep, ps, ref = set_cs2_style (ps, ref);
if not is_set (ps) then -- if |postscript= has not been set, set cs2 default
ps = ''; -- make sure it isn't nil
end
if not is_set (ref) then -- if |ref= is not set
ref = "harv"; -- set default |ref=harv
end
else -- not a citation template so CS1
else -- not a citation template so CS1
sep = '.'; -- set cite xxx separator to its default (period)
sep, ps = set_cs1_style (ps);
if not is_set (ps) then -- if |postscript= has not been set
ps = '.'; -- set cs1 default
end
end
end


Line 1,714: Line 1,810:


local function set_style (mode, ps, ref, cite_class)
local function set_style (mode, ps, ref, cite_class)
local sep;
local sep;
if is_set (mode) then
if 'cs2' == mode then -- if this template is to be rendered in CS2 (citation) style
if 'cs2' == mode then -- if this template is to be rendered in CS2 (citation) style
sep, ps, ref = set_cs2_style (ps, ref);
sep = ','; -- separate elements with a comma
elseif 'cs1' == mode then -- if this template is to be rendered in CS1 (cite xxx) style
if not is_set (ps) then -- unless explicitely set to something
sep, ps = set_cs1_style (ps);
ps = ''; -- make sure it isn't nil
else -- anything but cs1 or cs2
end
if is_set (mode) then
if not is_set (ref) then -- unless explicitely set to something
ref = 'harv'; -- set so this template renders with CITEREF anchor id
end
elseif 'cs1' == mode then -- if this template is to be rendered in CS1 (cite xxx) style
sep = '.'; -- separate elements with a period
if not is_set (ps) then -- unless explicitely set to something
ps = '.'; -- terminate the rendered citation with a period
end
else -- anything but cs1 or cs2
table.insert( z.message_tail, { set_error( 'invalid_param_val', {'mode', mode}, true ) } ); -- add error message
table.insert( z.message_tail, { set_error( 'invalid_param_val', {'mode', mode}, true ) } ); -- add error message
sep, ps, ref = get_settings_from_cite_class (ps, ref, cite_class); -- get settings based on the template's CitationClass
end
end
else -- when |mode= empty or omitted
sep, ps, ref = get_settings_from_cite_class (ps, ref, cite_class); -- get settings based on the template's CitationClass
sep, ps, ref = get_settings_from_cite_class (ps, ref, cite_class); -- get settings based on the template's CitationClass
end
end
Line 1,743: Line 1,828:
end
end


--[=[-------------------------< I S _ P D F >------------------------------------------------------------------
Determines if a url has the file extension is one of the pdf file extensions used by [[MediaWiki:Common.css]] when
applying the pdf icon to external links.
returns true if file extension is one of the recognized extension, else false
]=]
local function is_pdf (url)
return url:match ('%.pdf[%?#]?') or url:match ('%.PDF[%?#]?');
end
--[[--------------------------< S T Y L E _ F O R M A T >------------------------------------------------------
Applies css style to |format=, |chapter-format=, etc.  Also emits an error message if the format parameter does
not have a matching url parameter.  If the format parameter is not set and the url contains a file extension that
is recognized as a pdf document by MediaWiki's commons.css, this code will set the format parameter to (PDF) with
the appropriate styling.
]]
local function style_format (format, url, fmt_param, url_param)
if is_set (format) then
format = wrap_style ('format', format:upper()); -- force upper case, add leading space, parenthases, resize
if not is_set (url) then
format = format .. set_error( 'format_missing_url', {fmt_param, url_param} ); -- add an error message
end
elseif is_pdf (url) then -- format is not set so if url is a pdf file then
format = wrap_style ('format', 'PDF'); -- set format to pdf
else
format = ''; -- empty string for concatenation
end
return format;
end
--[[--------------------------< G E T _ D I S P L A Y _ A U T H O R S _ E D I T O R S >------------------------
Returns a number that may or may not limit the length of the author or editor name lists.
When the value assigned to |display-authors= is a number greater than or equal to zero, return the number and
the previous state of the 'etal' flag (false by default but may have been set to true if the name list contains
some variant of the text 'et al.').
When the value assigned to |display-authors= is the keyword 'etal', return a number that is one greater than the
number of authors in the list and set the 'etal' flag true.  This will cause the list_people() to display all of
the names in the name list followed by 'et al.'
In all other cases, returns nil and the previous state of the 'etal' flag.
]]
local function get_display_authors_editors (max, count, list_name, etal)
if is_set (max) then
if 'etal' == max:lower():gsub("[ '%.]", '') then -- the :gsub() portion makes 'etal' from a variety of 'et al.' spellings and stylings
max = count + 1; -- number of authors + 1 so display all author name plus et al.
etal = true; -- overrides value set by extract_names()
elseif max:match ('^%d+$') then -- if is a string of numbers
max = tonumber (max); -- make it a number
if max >= count and 'authors' == list_name then -- AUTHORS ONLY -- if |display-xxxxors= value greater than or equal to number of authors/editors
add_maint_cat ('disp_auth_ed', list_name);
end
else -- not a valid keyword or number
table.insert( z.message_tail, { set_error( 'invalid_param_val', {'display-' .. list_name, max}, true ) } ); -- add error message
max = nil; -- unset
end
elseif 'authors' == list_name then -- AUTHORS ONLY need to clear implicit et al category
max = count + 1; -- number of authors + 1
end
return max, etal;
end


--[[--------------------------< C I T A T I O N 0 >------------------------------------------------------------
--[[--------------------------< C I T A T I O N 0 >------------------------------------------------------------
This is the main function doing the majority of the citation
This is the main function doing the majority of the citation
formatting.
formatting.
]]
]]
local function citation0( config, args)
local function citation0( config, args)
--[[  
--[[  
Line 1,798: Line 1,958:
local Degree = A['Degree'];
local Degree = A['Degree'];
local Docket = A['Docket'];
local Docket = A['Docket'];
local ArchiveFormat = A['ArchiveFormat'];
local ArchiveURL = A['ArchiveURL'];
local ArchiveURL = A['ArchiveURL'];
local URL = A['URL']
local URL = A['URL']
Line 1,803: Line 1,964:
local ChapterURL = A['ChapterURL'];
local ChapterURL = A['ChapterURL'];
local ChapterURLorigin = A:ORIGIN('ChapterURL'); -- get name of parameter that holds ChapterURL
local ChapterURLorigin = A:ORIGIN('ChapterURL'); -- get name of parameter that holds ChapterURL
local ConferenceFormat = A['ConferenceFormat'];
local ConferenceURL = A['ConferenceURL'];
local ConferenceURL = A['ConferenceURL'];
local ConferenceURLorigin = A:ORIGIN('ConferenceURL'); -- get name of parameter that holds ConferenceURL
local ConferenceURLorigin = A:ORIGIN('ConferenceURL'); -- get name of parameter that holds ConferenceURL
Line 1,835: Line 1,997:
local IgnoreISBN = A['IgnoreISBN'];
local IgnoreISBN = A['IgnoreISBN'];
local Embargo = A['Embargo'];
local Embargo = A['Embargo'];
local Class = A['Class']; -- arxiv class identifier


local ID_list = extract_ids( args );
local ID_list = extract_ids( args );
Line 1,840: Line 2,003:
local Quote = A['Quote'];
local Quote = A['Quote'];


local LayFormat = A['LayFormat'];
local LayURL = A['LayURL'];
local LayURL = A['LayURL'];
local LaySource = A['LaySource'];
local LaySource = A['LaySource'];
local Transcript = A['Transcript'];
local Transcript = A['Transcript'];
local TranscriptFormat = A['TranscriptFormat'];
local TranscriptURL = A['TranscriptURL']  
local TranscriptURL = A['TranscriptURL']  
local TranscriptURLorigin = A:ORIGIN('TranscriptURL'); -- get name of parameter that holds TranscriptURL
local TranscriptURLorigin = A:ORIGIN('TranscriptURL'); -- get name of parameter that holds TranscriptURL
Line 1,867: Line 2,032:
use_lowercase = ( sepc == ',' ); -- used to control capitalization for certain static text
use_lowercase = ( sepc == ',' ); -- used to control capitalization for certain static text


--check this page to see if it is in one of the namespaces that cs1 is not supposed to add to the error categories.
--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
if not is_set (no_tracking_cats) then -- ignore if we are already not going to categorize this page
if in_array (this_page.nsText, cfg.uncategorized_namespaces) then
if in_array (this_page.nsText, cfg.uncategorized_namespaces) then
no_tracking_cats = "true"; -- set no_tracking_cats
no_tracking_cats = "true"; -- set no_tracking_cats
end
for _,v in ipairs (cfg.uncategorized_subpages) do -- cycle through page name patterns
if this_page.text:match (v) then -- test page name against each pattern
no_tracking_cats = "true"; -- set no_tracking_cats
break; -- bail out if one is found
end
end
end
end
end
Line 1,979: Line 2,150:
if (config.CitationClass == "mailinglist") then
if (config.CitationClass == "mailinglist") then
Periodical = A ['MailingList'];
Periodical = A ['MailingList'];
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
end


Line 2,005: Line 2,168:
URL = '';
URL = '';
end
end
else
elseif 'speech' ~= config.CitationClass then
Conference = ''; -- not cite conference so make sure this is empty string
Conference = ''; -- not cite conference or cite speech so make sure this is empty string
end
 
-- cite map oddities
local Cartography = "";
local Scale = "";
local Sheet = A['Sheet'] or '';
local Sheets = A['Sheets'] or '';
if config.CitationClass == "map" then
Chapter = A['Map'];
ChapterURL = A['MapURL'];
TransChapter = A['TransMap'];
ChapterURLorigin = A:ORIGIN('MapURL');
ChapterFormat = A['MapFormat'];
Cartography = A['Cartography'];
if is_set( Cartography ) then
Cartography = sepc .. " " .. wrap_msg ('cartography', Cartography, use_lowercase);
end
Scale = A['Scale'];
if is_set( Scale ) then
Scale = sepc .. " " .. Scale;
end
end
end


-- Account for the oddity that is {{cite episode}}, before generation of COinS data.
-- Account for the oddities that are {{cite episode}} and {{cite serial}}, before generation of COinS data.
--[[ -- {{cite episode}} is not currently supported by this module
if 'episode' == config.CitationClass or 'serial' == config.CitationClass then
if config.CitationClass == "episode" then
local AirDate = A['AirDate'];
local AirDate = A['AirDate'];
local Began = A['Began']; -- these two are deprecated because the module understands date ranges
local Ended = A['Ended'];
local SeriesLink = A['SeriesLink'];
local SeriesLink = A['SeriesLink'];
local Season = A['Season'];
local SeriesNumber = A['SeriesNumber'];
local Network = A['Network'];
local Network = A['Network'];
local Station = A['Station'];
local Station = A['Station'];
local s, n = {}, {};
local s, n = {}, {};
local Sep = (first_set(A["SeriesSeparator"], A["Separator"]) or "") .. " ";
 
-- do common parameters first
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(Network) then table.insert(n, Network); end
if is_set(Station) then table.insert(n, Station); end
if is_set(Station) then table.insert(n, Station); end
ID = table.concat(n, sepc .. ' ');
Date = Date or AirDate;
if not is_set (Date) then -- promote airdate or Began/Ended to date
Chapter = Title;
if is_set (AirDate) then
ChapterLink = TitleLink;
Date = AirDate;
TransChapter = TransTitle;
elseif is_set (Began) then -- deprecated
Title = Series;
if Began:match('%s') or Ended:match('%s') then -- so we don't create errors: if either has spaces then
TitleLink = SeriesLink;
Date = Began .. ' – ' .. Ended; -- use spaced ndash as separator
TransTitle = '';
else
Date = Began .. '' .. Ended; -- elsewise no spaces
Series = table.concat(s, Sep);
end
ID = table.concat(n, Sep);
end
end
end
-- end of {{cite episode}} stuff]]
 
if 'episode' == config.CitationClass then -- handle the oddities that are strictly {{cite episode}}
local Season = A['Season'];
local SeriesNumber = A['SeriesNumber'];


-- legacy: promote concatenation of |month=, and |year= to Date if Date not set; or, promote PublicationDate to Date if neither Date nor Year are set.
if is_set (Season) and is_set (SeriesNumber) then -- these are mutually exclusive so if both are set
table.insert( z.message_tail, { set_error( 'redundant_parameters', {wrap_style ('parameter', 'season') .. ' and ' .. wrap_style ('parameter', 'seriesno')}, true ) } ); -- add error message
SeriesNumber = ''; -- unset; prefer |season= over |seriesno=
end
-- assemble a table of parts concatenated later into Series
if is_set(Season) then table.insert(s, wrap_msg ('season', Season, use_lowercase)); end
if is_set(SeriesNumber) then table.insert(s, wrap_msg ('series', SeriesNumber, use_lowercase)); end
if is_set(Issue) then table.insert(s, wrap_msg ('episode', Issue, use_lowercase)); end
Issue = ''; -- unset because this is not a unique parameter
Chapter = Title; -- promote title parameters to chapter
ChapterLink = TitleLink; -- alias episodelink
TransChapter = TransTitle;
ChapterURL = URL;
ChapterURLorigin = A:ORIGIN('URL');
Title = Series; -- promote series to title
TitleLink = SeriesLink;
Series = table.concat(s, sepc .. ' '); -- this is concatenation of season, seriesno, episode number
 
if is_set (ChapterLink) and not is_set (ChapterURL) then -- link but not URL
Chapter = '[[' .. ChapterLink .. '|' .. Chapter .. ']]'; -- ok to wikilink
elseif is_set (ChapterLink) and is_set (ChapterURL) then -- if both are set, URL links episode;
Series = '[[' .. ChapterLink .. '|' .. Series .. ']]'; -- series links with ChapterLink (episodelink -> TitleLink -> ChapterLink) ugly
end
URL = ''; -- unset
TransTitle = ''; -- unset
else -- now oddities that are cite serial
Issue = ''; -- unset because this parameter no longer supported by the citation/core version of cite serial
Chapter = A['Episode']; -- TODO: make |episode= available to cite episode someday?
if is_set (Series) and is_set (SeriesLink) then
Series = '[[' .. SeriesLink .. '|' .. Series .. ']]';
end
Series = wrap_style ('italic-title', Series); -- series is italicized
end
end
-- end of {{cite episode}} stuff
 
-- Account for the oddities that are {{cite arxiv}}, before generation of COinS data.
if 'arxiv' == config.CitationClass then
if not is_set (ID_list['ARXIV']) then -- |arxiv= or |eprint= required for cite arxiv
table.insert( z.message_tail, { set_error( 'arxiv_missing', {}, true ) } ); -- add error message
end
if first_set (AccessDate, At, Chapter, Format, Page, Pages, Periodical, PublisherName, URL, -- a crude list of parameters that are not supported by cite arxiv
ID_list['ASIN'], ID_list['BIBCODE'], ID_list['DOI'], ID_list['ISBN'], ID_list['ISSN'],
ID_list['JFM'], ID_list['JSTOR'], ID_list['LCCN'], ID_list['MR'], ID_list['OCLC'], ID_list['OL'],
ID_list['OSTI'], ID_list['PMC'], ID_list['PMID'], ID_list['RFC'], ID_list['SSRN'], ID_list['USENETID'], ID_list['ZBL']) then
table.insert( z.message_tail, { set_error( 'arxiv_params_not_supported', {}, true ) } ); -- add error message
 
AccessDate= ''; -- set these to empty string; not supported in cite arXiv
PublisherName = ''; -- (if the article has been published, use cite journal, or other)
Chapter = '';
URL = '';
Format = '';
Page = ''; Pages = ''; At = '';
end
Periodical = 'arXiv'; -- set to arXiv for COinS; after that, must be set to empty string
end
 
-- handle type parameter for those CS1 citations that have default values
 
if in_array(config.CitationClass, {"AV-media-notes", "DVD-notes", "mailinglist", "map", "podcast", "pressrelease", "report", "techreport", "thesis"}) then
TitleType = set_titletype (config.CitationClass, TitleType);
if is_set(Degree) and "Thesis" == TitleType then -- special case for cite thesis
TitleType = Degree .. " thesis";
end
end
 
if is_set(TitleType) then -- if type parameter is specified
TitleType = " (" .. TitleType .. ")"; -- display it in parentheses
end
 
-- legacy: promote concatenation of |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
if not is_set (Date) then
Date = Year; -- promote Year to Date
Date = Year; -- promote Year to Date
Line 2,065: Line 2,323:
do -- create defined block to contain local variables error_message and mismatch
do -- create defined block to contain local variables error_message and mismatch
local error_message = '';
local error_message = '';
 
-- AirDate has been promoted to Date so not necessary to check it
anchor_year, COinS_date, error_message = dates({['accessdate']=AccessDate, ['airdate']=AirDate, ['archivedate']=ArchiveDate, ['date']=Date, ['doi_brokendate']=DoiBroken,
anchor_year, COinS_date, error_message = dates({['accessdate']=AccessDate, ['archivedate']=ArchiveDate, ['date']=Date, ['doi_brokendate']=DoiBroken,
['embargo']=Embargo, ['laydate']=LayDate, ['publicationdate']=PublicationDate, ['year']=Year});
['embargo']=Embargo, ['laydate']=LayDate, ['publicationdate']=PublicationDate, ['year']=Year});


Line 2,077: Line 2,335:
error_message = error_message .. '&#124;year= / &#124;date= mismatch';
error_message = error_message .. '&#124;year= / &#124;date= mismatch';
elseif 1 == mismatch then -- |year= matches year-value in |date=
elseif 1 == mismatch then -- |year= matches year-value in |date=
table.insert( z.maintenance_cats, 'CS1 maint: Date and year'); -- add to maint category
add_maint_cat ('date_year');
end
end
end
end
Line 2,085: Line 2,343:
end
end
end -- end of do
end -- end of do
-- Account for the oddity that is {{cite journal}} with |pmc= set and |url= not set.  Do this after date check but before COInS.
-- Here we unset Embargo if PMC not embargoed (|embargo= not set in the citation) or if the embargo time has expired. Otherwise, holds embargo date
Embargo = is_embargoed (Embargo); --
if config.CitationClass == "journal" and not is_set(URL) and is_set(ID_list['PMC']) then
if not is_set (Embargo) then -- if not embargoed or embargo has expired
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


-- At this point fields may be nil if they weren't specified in the template use.  We can use that fact.
-- At this point fields may be nil if they weren't specified in the template use.  We can use that fact.
Line 2,096: Line 2,365:
if 'none' == Title and is_set(Periodical) and not (( config.CitationClass == "encyclopaedia" ) or ( config.CitationClass == "citation" and is_set (Encyclopedia))) then -- special case
if 'none' == Title and is_set(Periodical) and not (( config.CitationClass == "encyclopaedia" ) or ( config.CitationClass == "citation" and is_set (Encyclopedia))) then -- special case
Title = ''; -- set title to empty string
Title = ''; -- set title to empty string
table.insert( z.maintenance_cats, 'CS1 maint: Untitled periodical'); -- add to maint category
add_maint_cat ('untitled');
end
end


Line 2,114: Line 2,383:
-- this is the function call to COinS()
-- this is the function call to COinS()
local OCinSoutput = COinS{
local OCinSoutput = COinS({
['Periodical'] = Periodical,
['Periodical'] = Periodical,
['Chapter'] = strip_apostrophe_markup (coins_chapter), -- Chapter stripped of bold / italic wikimarkup
['Chapter'] = strip_apostrophe_markup (coins_chapter), -- Chapter stripped of bold / italic wikimarkup
Line 2,123: Line 2,392:
['Volume'] = Volume,
['Volume'] = Volume,
['Issue'] = Issue,
['Issue'] = Issue,
['Pages'] = get_coins_pages (first_set(Page, Pages, At)), -- pages stripped of external links
['Pages'] = get_coins_pages (first_set(Sheet, Sheets, Page, Pages, At)), -- pages stripped of external links
['Edition'] = Edition,
['Edition'] = Edition,
['PublisherName'] = PublisherName,
['PublisherName'] = PublisherName,
Line 2,130: Line 2,399:
['ID_list'] = ID_list,
['ID_list'] = ID_list,
['RawPage'] = this_page.prefixedText,
['RawPage'] = this_page.prefixedText,
};
}, config.CitationClass);
 
-- Account for the oddities that are {{cite arxiv}}, AFTER generation of COinS data.
if 'arxiv' == config.CitationClass then -- we have set rft.jtitle in COinS to arXiv, now unset so it isn't displayed
Periodical = ''; -- periodical not allowed in cite arxiv; if article has been published, use cite journal
end


-- special case for cite newsgroup.  Do this after COinS because we are modifying Publishername to include some static text
-- special case for cite newsgroup.  Do this after COinS because we are modifying Publishername to include some static text
Line 2,144: Line 2,418:
-- We also add leading spaces and surrounding markup and punctuation to the
-- We also add leading spaces and surrounding markup and punctuation to the
-- various parts of the citation, but only when they are non-nil.
-- various parts of the citation, but only when they are non-nil.
if not is_set(Authors) then
do -- do-block to limit scope of LastFirstAuthors
local Maximum = tonumber( A['DisplayAuthors'] );
local LastFirstAuthors;
local Maximum = A['DisplayAuthors'];


if is_set (Maximum) then
Maximum , author_etal = get_display_authors_editors (Maximum, #a, 'authors', author_etal);
if Maximum >= #a then -- if display-authors value greater than or equal to number of authors
table.insert( z.maintenance_cats, 'CS1 maint: display-authors'); -- add maintenance category because display-authors parameter may be removed
end
else
Maximum = #a + 1; -- number of authors + 1
end


local control = {  
local control = {  
Line 2,168: Line 2,437:
end
end
Authors = list_people(control, a, author_etal)  
LastFirstAuthors = list_people(control, a, author_etal);
end
 
if is_set (Authors) then
if is_set (LastFirstAuthors) then -- if both author name styles
table.insert( z.message_tail, { set_error( 'redundant_parameters', {wrap_style ('parameter', 'authors') .. ' and ' .. wrap_style ('parameter', 'last')}, true ) } ); -- add error message
Authors = LastFirstAuthors; -- TODO: is this correct or should we use |authors= instead?
end
else
Authors = LastFirstAuthors; -- either an author name list or an empty string
end
end -- end of do


if not is_set(Authors) and is_set(Coauthors) then -- coauthors aren't displayed if one of authors=, authorn=, or lastn= isn't specified
if not is_set(Authors) and is_set(Coauthors) then -- coauthors aren't displayed if one of authors=, authorn=, or lastn= isn't specified
Line 2,175: Line 2,453:
end
end


local EditorCount
local EditorCount; -- used only for choosing {ed.) or (eds.) annotation at end of editor name-list
if not is_set(Editors) then
if not is_set(Editors) then
local Maximum = tonumber( A['DisplayEditors'] );
local Maximum = A['DisplayEditors'];
 
Maximum , editor_etal = get_display_authors_editors (Maximum, #e, 'editors', editor_etal);
-- Preserve old-style implicit et al.
-- Preserve old-style implicit et al.
if not is_set(Maximum) and #e == 4 then  
if not is_set(Maximum) and #e == 4 then  
Maximum = 3;
Maximum = 3;
table.insert( z.message_tail, { set_error('implict_etal_editor', {}, true) } );
table.insert( z.message_tail, { set_error('implict_etal_editor', {}, true) } );
elseif not is_set(Maximum) then
Maximum = #e + 1;
end
end


Line 2,194: Line 2,472:


Editors, EditorCount = list_people(control, e, editor_etal);
Editors, EditorCount = list_people(control, e, editor_etal);
if 1 == EditorCount and (true == editor_etal or 1 < #e) then -- only one editor displayed but includes etal then
EditorCount = 2; -- spoof to display (eds.) annotation
end
else
else
EditorCount = 1;
EditorCount = 1;
end
end


-- cite map oddities
-- apply |[xx-]format= styling; at the end, these parameters hold correctly styled format annotation,
local Cartography = "";
-- an error message if the associated url is not set, or an empty string for concatenation
local Scale = "";
ArchiveFormat = style_format (ArchiveFormat, ArchiveURL, 'archive-format', 'archive-url');
if config.CitationClass == "map" then
ChapterFormat = style_format (ChapterFormat, ChapterURL, 'chapter-format', 'chapter-url');
Chapter = A['Map'];
ConferenceFormat = style_format (ConferenceFormat, ConferenceURL, 'conference-format', 'conference-url');
ChapterURL = A['MapURL'];
Format = style_format (Format, URL, 'format', 'url');
ChapterURLorigin = A:ORIGIN('MapURL');
LayFormat = style_format (LayFormat, LayURL, 'lay-format', 'lay-url');
ChapterFormat = A['MapFormat'];
TranscriptFormat = style_format (TranscriptFormat, TranscriptURL, 'transcript-format', 'transcripturl');
Cartography = A['Cartography'];
if is_set( Cartography ) then
Cartography = sepc .. " " .. wrap_msg ('cartography', Cartography, use_lowercase);
end
Scale = A['Scale'];
if is_set( Scale ) then
Scale = sepc .. " " .. Scale;
end
end
Format = is_set(Format) and " (" .. Format .. ")" or "";


if  not is_set(URL) and
if  not is_set(URL) then --and
not is_set(ArchiveURL) and
-- not is_set(ArchiveURL) then --and -- prevents format_missing_url error from registering
not is_set(ConferenceURL) and -- TODO: keep this here? conference as part of cite web or cite podcast?
-- not is_set(ConferenceURL) and -- TODO: keep this here? conference as part of cite web or cite podcast?
not is_set(TranscriptURL) then
-- not is_set(TranscriptURL) then -- TODO: remove? |transcript-url= and |transcript= has separate test
-- Test if cite web or cite podcast |url= is missing or empty  
-- Test if cite web or cite podcast |url= is missing or empty  
Line 2,233: Line 2,502:
table.insert( z.message_tail, { set_error( 'accessdate_missing_url', {}, true ) } );
table.insert( z.message_tail, { set_error( 'accessdate_missing_url', {}, true ) } );
AccessDate = '';
AccessDate = '';
end
-- Test if format is given without giving a URL
if is_set(Format) then
Format = Format .. set_error( 'format_missing_url', {'format', 'url'} );
end
end
end
end


local OriginalURL;
local OriginalURL, OriginalFormat; -- TODO: swap chapter and title here so that archive applies to most specific if both are set?
DeadURL = DeadURL:lower(); -- used later when assembling archived text
DeadURL = DeadURL:lower(); -- used later when assembling archived text
if is_set( ArchiveURL ) then
if is_set( ArchiveURL ) then
if is_set (URL) then
if is_set (URL) then
OriginalURL = URL; -- save copy of original source URL
OriginalURL = URL; -- save copy of original source URL
OriginalFormat = Format; -- and original |format=
if 'no' ~= DeadURL then -- if URL set then archive-url applies to it
if 'no' ~= DeadURL then -- if URL set then archive-url applies to it
URL = ArchiveURL -- swap-in the archive's url
URL = ArchiveURL -- swap-in the archive's url
URLorigin = A:ORIGIN('ArchiveURL') -- name of archive url parameter for error messages
URLorigin = A:ORIGIN('ArchiveURL') -- name of archive url parameter for error messages
Format = ArchiveFormat or ''; -- swap in archive's format
end
end
elseif is_set (ChapterURL) then -- URL not set so if chapter-url is set apply archive url to it
elseif is_set (ChapterURL) then -- URL not set so if chapter-url is set apply archive url to it
OriginalURL = ChapterURL; -- save copy of source chapter's url for archive text
OriginalURL = ChapterURL; -- save copy of source chapter's url for archive text
OriginalFormat = ChapterFormat; -- and original |format=
if 'no' ~= DeadURL then
if 'no' ~= DeadURL then
ChapterURL = ArchiveURL -- swap-in the archive's url
ChapterURL = ArchiveURL -- swap-in the archive's url
URLorigin = A:ORIGIN('ArchiveURL') -- name of archive url parameter for error messages
URLorigin = A:ORIGIN('ArchiveURL') -- name of archive url parameter for error messages
ChapterFormat = ArchiveFormat or ''; -- swap in archive's format
end
end
end
end
end
end


if in_array(config.CitationClass, {"web","news","journal","pressrelease","podcast", "newsgroup"}) or
if in_array(config.CitationClass, {"web","news","journal","pressrelease","podcast", "newsgroup", 'arxiv'}) or
('citation' == config.CitationClass and is_set (Periodical) and not is_set (Encyclopedia)) then
('citation' == config.CitationClass and is_set (Periodical) and not is_set (Encyclopedia)) then
if is_set (Chapter) or is_set (TransChapter) or is_set (ChapterURL)then -- chapter parameters not supported for these citation types
if is_set (Chapter) or is_set (TransChapter) or is_set (ChapterURL)then -- chapter parameters not supported for these citation types
Line 2,270: Line 2,538:
Chapter = format_chapter_title (Chapter, TransChapter, ChapterURL, ChapterURLorigin);
Chapter = format_chapter_title (Chapter, TransChapter, ChapterURL, ChapterURLorigin);
if is_set (Chapter) then
if is_set (Chapter) then
ChapterFormat = is_set(ChapterFormat) and " (" .. ChapterFormat .. ")" or "";
if is_set(ChapterFormat) and not is_set (ChapterURL) then -- Test if |chapter-format= is given without giving a |chapter-url=
ChapterFormat = ChapterFormat .. set_error( 'format_missing_url', {'chapter-format', 'chapter-url'} );
end
if 'map' == config.CitationClass and is_set (TitleType) then
if 'map' == config.CitationClass and is_set (TitleType) then
Chapter = Chapter .. ' (' .. TitleType .. ')';
Chapter = Chapter .. ' ' .. TitleType;
end
end
Chapter = Chapter .. ChapterFormat .. sepc .. ' ';
Chapter = Chapter .. ChapterFormat .. sepc .. ' ';
Line 2,286: Line 2,550:
end
end


if in_array(config.CitationClass, {"web","news","journal","pressrelease","podcast", "newsgroup", "mailinglist"}) or
if in_array(config.CitationClass, {"web","news","journal","pressrelease","podcast", "newsgroup", "mailinglist", 'arxiv'}) or
('citation' == config.CitationClass and is_set (Periodical) and not is_set (Encyclopedia)) or
('citation' == config.CitationClass and is_set (Periodical) and not is_set (Encyclopedia)) or
('map' == config.CitationClass and is_set (Periodical)) then -- special case for cite map when the map is in a periodical treat as an article
('map' == config.CitationClass and is_set (Periodical)) then -- special case for cite map when the map is in a periodical treat as an article
Line 2,316: Line 2,580:
if is_set(Title) then
if is_set(Title) then
if not is_set(TitleLink) and is_set(URL) then  
if not is_set(TitleLink) and is_set(URL) then  
Title = external_link( URL, Title ) .. TransError .. Format  
Title = external_link( URL, Title ) .. TransError .. Format;
URL = "";
URL = "";
Format = "";
Format = "";
Line 2,327: Line 2,591:
Place = " " .. wrap_msg ('written', Place, use_lowercase) .. sepc .. " ";
Place = " " .. wrap_msg ('written', Place, use_lowercase) .. sepc .. " ";
end
end
 
if is_set(Conference) then
if is_set (Conference) then
if is_set(ConferenceURL) then
if is_set (ConferenceURL) then
Conference = external_link( ConferenceURL, Conference );
Conference = external_link( ConferenceURL, Conference );
end
end
Conference = sepc .. " " .. Conference
Conference = sepc .. " " .. Conference .. ConferenceFormat;
elseif is_set(ConferenceURL) then
elseif is_set(ConferenceURL) then
Conference = sepc .. " " .. external_link( ConferenceURL, nil, ConferenceURLorigin );
Conference = sepc .. " " .. external_link( ConferenceURL, nil, ConferenceURLorigin );
end
end
 
if not is_set(Position) then
if not is_set(Position) then
local Minutes = A['Minutes'];
local Minutes = A['Minutes'];
Line 2,378: Line 2,642:
end
end
end
end
 
if 'map' == config.CitationClass then -- cite map oddity done after COinS call (and with other in-source locators)
if is_set (Sheet) or is_set (Sheets) then
local err_msg1 = 'sheet=, &#124;sheets'; -- default error message in case any of page pages or at are set
local err_msg2;
if is_set (Page) or is_set (Pages) or is_set (At) then -- are any set?
err_msg2 = 'page=, &#124;pages=, &#124;at'; -- a generic error message
Page = ''; Pages = ''; At = '';
elseif is_set (Sheet) and is_set (Sheets) then -- if both are set make error message
err_msg1 = 'sheet';
err_msg2 = 'sheets';
end
if is_set (err_msg2) then
table.insert( z.message_tail, { set_error( 'redundant_parameters', {wrap_style ('parameter', err_msg1) .. ' and ' .. wrap_style ('parameter', err_msg2)}, true ) } ); -- add error message
end
if not is_set (Sheet) then -- do sheet static text and formatting; Sheet has priority over Sheets if both provided
if is_set (Sheets) then
if is_set (Periodical) then
Sheet = ": Sheets " .. Sheets; -- because Sheet has priority, no need to support both later on
else
Sheet = sepc .. " Sheets " .. Sheets;
end
end
else
if is_set (Periodical) then
Sheet = ": Sheet " .. Sheet;
else
Sheet = sepc .. " Sheet " .. Sheet;
end
end
end
end
 
At = is_set(At) and (sepc .. " " .. At) or "";
At = is_set(At) and (sepc .. " " .. At) or "";
Position = is_set(Position) and (sepc .. " " .. Position) or "";
Position = is_set(Position) and (sepc .. " " .. Position) or "";
Line 2,405: Line 2,701:


Others = is_set(Others) and (sepc .. " " .. Others) or "";
Others = is_set(Others) and (sepc .. " " .. Others) or "";
-- handle type parameter for those CS1 citations that have default values
if in_array(config.CitationClass, {"AV-media-notes", "DVD-notes", "mailinglist", "map", "podcast", "pressrelease", "report", "techreport", "thesis"}) then
TitleType = set_titletype (config.CitationClass, TitleType);
if is_set(Degree) and "Thesis" == TitleType then -- special case for cite thesis
TitleType = Degree .. " thesis";
end
end
if is_set(TitleType) then -- if type parameter is specified
TitleType = " (" .. TitleType .. ")"; -- display it in parentheses
end


TitleNote = is_set(TitleNote) and (sepc .. " " .. TitleNote) or "";
TitleNote = is_set(TitleNote) and (sepc .. " " .. TitleNote) or "";
Line 2,469: Line 2,752:
end
end


ID_list = build_id_list( ID_list, {DoiBroken = DoiBroken, ASINTLD = ASINTLD, IgnoreISBN = IgnoreISBN, Embargo=Embargo} );
ID_list = build_id_list( ID_list, {DoiBroken = DoiBroken, ASINTLD = ASINTLD, IgnoreISBN = IgnoreISBN, Embargo=Embargo, Class = Class} );


if is_set(URL) then
if is_set(URL) then
Line 2,492: Line 2,775:
if sepc ~= "." then arch_text = arch_text:lower() end
if sepc ~= "." then arch_text = arch_text:lower() end
Archived = sepc .. " " .. substitute( cfg.messages['archived-not-dead'],
Archived = sepc .. " " .. substitute( cfg.messages['archived-not-dead'],
{ external_link( ArchiveURL, arch_text ), ArchiveDate } );
{ external_link( ArchiveURL, arch_text ) .. ArchiveFormat, ArchiveDate } );
if not is_set(OriginalURL) then
if not is_set(OriginalURL) then
Archived = Archived .. " " .. set_error('archive_missing_url');    
Archived = Archived .. " " .. set_error('archive_missing_url');    
Line 2,500: Line 2,783:
if sepc ~= "." then arch_text = arch_text:lower() end
if sepc ~= "." then arch_text = arch_text:lower() end
Archived = sepc .. " " .. substitute( arch_text,
Archived = sepc .. " " .. substitute( arch_text,
{ external_link( OriginalURL, cfg.messages['original'] ), ArchiveDate } );
{ external_link( OriginalURL, cfg.messages['original'] ) .. OriginalFormat, ArchiveDate } ); -- format already styled
else
else
local arch_text = cfg.messages['archived-missing'];
local arch_text = cfg.messages['archived-missing'];
Line 2,507: Line 2,790:
{ set_error('archive_missing_url'), ArchiveDate } );
{ set_error('archive_missing_url'), ArchiveDate } );
end
end
elseif is_set (ArchiveFormat) then
Archived = ArchiveFormat; -- if set and ArchiveURL not set ArchiveFormat has error message
else
else
Archived = ""
Archived = ""
end
end
local Lay
local Lay = '';
if is_set(LayURL) then
if is_set(LayURL) then
if is_set(LayDate) then LayDate = " (" .. LayDate .. ")" end
if is_set(LayDate) then LayDate = " (" .. LayDate .. ")" end
Line 2,520: Line 2,805:
end
end
if sepc == '.' then
if sepc == '.' then
Lay = sepc .. " " .. external_link( LayURL, cfg.messages['lay summary'] ) .. LaySource .. LayDate
Lay = sepc .. " " .. external_link( LayURL, cfg.messages['lay summary'] ) .. LayFormat .. LaySource .. LayDate
else
else
Lay = sepc .. " " .. external_link( LayURL, cfg.messages['lay summary']:lower() ) .. LaySource .. LayDate
Lay = sepc .. " " .. external_link( LayURL, cfg.messages['lay summary']:lower() ) .. LayFormat .. LaySource .. LayDate
end
end
else
elseif is_set (LayFormat) then -- Test if |lay-format= is given without giving a |lay-url=
Lay = "";
Lay = sepc .. LayFormat; -- if set and LayURL not set, then LayFormat has error message
end
end
 
if is_set(Transcript) then
if is_set(Transcript) then
if is_set(TranscriptURL) then Transcript = external_link( TranscriptURL, Transcript ); end
if is_set(TranscriptURL) then
Transcript = external_link( TranscriptURL, Transcript );
end
Transcript = sepc .. ' ' .. Transcript .. TranscriptFormat;
elseif is_set(TranscriptURL) then
elseif is_set(TranscriptURL) then
Transcript = external_link( TranscriptURL, nil, TranscriptURLorigin );
Transcript = external_link( TranscriptURL, nil, TranscriptURLorigin );
end
end
 
local Publisher;
local Publisher;
if is_set(Periodical) and
if is_set(Periodical) and
Line 2,616: Line 2,904:
end
end
elseif 'episode' == config.CitationClass then -- special case for cite episode
tcommon = safe_join( {Title, TitleNote, TitleType, Series, Transcript, Language, Edition, Publisher}, sepc );
else -- all other CS1 templates
else -- all other CS1 templates
tcommon = safe_join( {Title, TitleNote, Conference, Periodical, Format, TitleType, Series, Language,  
tcommon = safe_join( {Title, TitleNote, Conference, Periodical, Format, TitleType, Series, Language,  
Line 2,629: Line 2,919:
local idcommon = safe_join( { ID_list, URL, Archived, AccessDate, Via, SubscriptionRequired, Lay, Quote }, sepc );
local idcommon = safe_join( { ID_list, URL, Archived, AccessDate, Via, SubscriptionRequired, Lay, Quote }, sepc );
local text;
local text;
local pgtext = Position .. Page .. Pages .. At;
local pgtext = Position .. Sheet .. Page .. Pages .. At;
if is_set(Authors) then
if is_set(Authors) then
Line 2,660: Line 2,950:
if (sepc ~= '.') then in_text = in_text:lower() end
if (sepc ~= '.') then in_text = in_text:lower() end
Editors = in_text .. Editors .. post_text;
Editors = in_text .. Editors .. post_text;
if (string.sub(Editors,-1,-1) == sepc)
if (string.sub(Editors,-1,-1) == sepc) or (string.sub(Editors,-3,-1) == sepc .. ']]') then -- if last editor name ends with sepc char
then Editors = Editors .. " "
Editors = Editors .. " "; -- don't add another
else Editors = Editors .. sepc .. " "
else
Editors = Editors .. sepc .. " " -- otherwise terninate the editor list
end
end
end
end
Anonymous user
Cookies help us deliver our services. By using our services, you agree to our use of cookies.