Module:Citation/CS1: Difference between revisions

imported>Trappist the monk
sync from sandbox;
m 1 revision imported: template update
 
(One intermediate revision by one other user not shown)
Line 1: Line 1:
require('strict');
require ('strict');


--[[--------------------------< F O R W A R D  D E C L A R A T I O N S >--------------------------------------
--[[--------------------------< F O R W A R D  D E C L A R A T I O N S >--------------------------------------
Line 28: Line 28:
local added_vanc_errs; -- Boolean flag so we only emit one Vancouver error / category
local added_vanc_errs; -- Boolean flag so we only emit one Vancouver error / category
local added_generic_name_errs; -- Boolean flag so we only emit one generic name error / category and stop testing names once an error is encountered
local added_generic_name_errs; -- Boolean flag so we only emit one generic name error / category and stop testing names once an error is encountered
local added_numeric_name_errs; -- Boolean flag so we only emit one numeric name error / category and stop testing names once an error is encountered
local added_numeric_name_maint; -- Boolean flag so we only emit one numeric name maint category and stop testing names once a category has been emitted
local Frame; -- holds the module's frame table
local Frame; -- holds the module's frame table
local is_preview_mode; -- true when article is in preview mode; false when using 'Preview page with this template' (previewing the module)
local is_preview_mode; -- true when article is in preview mode; false when using 'Preview page with this template' (previewing the module)
Line 533: Line 535:
end
end
-- if we get this far we have prefix and script
-- if we get this far we have prefix and script
name = cfg.lang_code_remap[lang] or mw.language.fetchLanguageName( lang, cfg.this_wiki_code ); -- get language name so that we can use it to categorize
name = cfg.lang_tag_remap[lang] or mw.language.fetchLanguageName( lang, cfg.this_wiki_code ); -- get language name so that we can use it to categorize
if utilities.is_set (name) then -- is prefix a proper ISO 639-1 language code?
if utilities.is_set (name) then -- is prefix a proper ISO 639-1 language code?
script_value = script_value:gsub ('^%l+%s*:%s*', ''); -- strip prefix from script
script_value = script_value:gsub ('^%l+%s*:%s*', ''); -- strip prefix from script
Line 1,037: Line 1,039:
end
end
end
end
if nil == mw.ustring.find (last, "^[A-Za-z\195\128-\195\150\195\152-\195\182\195\184-\198\191\199\132-\201\143%-%s%']*$") or
if nil == mw.ustring.find (last, "^[A-Za-z\195\128-\195\150\195\152-\195\182\195\184-\198\191\199\132-\201\143\225\184\128-\225\187\191%-%s%']*$") or
nil == mw.ustring.find (first, "^[A-Za-z\195\128-\195\150\195\152-\195\182\195\184-\198\191\199\132-\201\143%-%s%'%.]*$") then
nil == mw.ustring.find (first, "^[A-Za-z\195\128-\195\150\195\152-\195\182\195\184-\198\191\199\132-\201\143\225\184\128-\225\187\191%-%s%'%.]*$") then
add_vanc_error (cfg.err_msg_supl['non-Latin char'], position);
add_vanc_error (cfg.err_msg_supl['non-Latin char'], position);
return false; -- not a string of Latin characters; Vancouver requires Romanization
return false; -- not a string of Latin characters; Vancouver requires Romanization
Line 1,063: Line 1,065:
]]
]]


local function reduce_to_initials(first, position)
local function reduce_to_initials (first, position)
local name, suffix = mw.ustring.match(first, "^(%u+) ([%dJS][%drndth]+)$");
if first:find (',', 1, true) then
return first; -- commas not allowed; abandon
end
 
local name, suffix = mw.ustring.match (first, "^(%u+) ([%dJS][%drndth]+)$");


if not name then -- if not initials and a suffix
if not name then -- if not initials and a suffix
name = mw.ustring.match(first, "^(%u+)$"); -- is it just initials?
name = mw.ustring.match (first, "^(%u+)$"); -- is it just initials?
end
end


Line 1,085: Line 1,091:
end -- if here then name has 3 or more uppercase letters so treat them as a word
end -- if here then name has 3 or more uppercase letters so treat them as a word


local initials, names = {}, {}; -- tables to hold name parts and initials
local initials_t, names_t = {}, {}; -- tables to hold name parts and initials
local i = 1; -- counter for number of initials
local i = 1; -- counter for number of initials


names = mw.text.split (first, '[%s,]+'); -- split into a table of names and possible suffix
names_t = mw.text.split (first, '[%s%-]+'); -- split into a sequence of names and possible suffix


while names[i] do -- loop through the table
while names_t[i] do -- loop through the sequence
if 1 < i and names[i]:match ('[%dJS][%drndth]+%.?$') then -- if not the first name, and looks like a suffix (may have trailing dot)
if 1 < i and names_t[i]:match ('[%dJS][%drndth]+%.?$') then -- if not the first name, and looks like a suffix (may have trailing dot)
names[i] = names[i]:gsub ('%.', ''); -- remove terminal dot if present
names_t[i] = names_t[i]:gsub ('%.', ''); -- remove terminal dot if present
if is_suffix (names[i]) then -- if a legitimate suffix
if is_suffix (names_t[i]) then -- if a legitimate suffix
table.insert (initials, ' ' .. names[i]); -- add a separator space, insert at end of initials table
table.insert (initials_t, ' ' .. names_t[i]); -- add a separator space, insert at end of initials sequence
break; -- and done because suffix must fall at the end of a name
break; -- and done because suffix must fall at the end of a name
end -- no error message if not a suffix; possibly because of Romanization
end -- no error message if not a suffix; possibly because of Romanization
end
end
if 3 > i then
if 3 > i then
table.insert (initials, mw.ustring.sub(names[i], 1, 1)); -- insert the initial at end of initials table
table.insert (initials_t, mw.ustring.sub (names_t[i], 1, 1)); -- insert the initial at end of initials sequence
end
end
i = i + 1; -- bump the counter
i = i + 1; -- bump the counter
end
end
return table.concat(initials) -- Vancouver format does not include spaces.
return table.concat (initials_t); -- Vancouver format does not include spaces.
end
end


Line 1,245: Line 1,251:
if one then -- if <one> has a value (name, mdash replacement, or mask text replacement)
if one then -- if <one> has a value (name, mdash replacement, or mask text replacement)
local proj, tag = interwiki_prefixen_get (one, true); -- get the interwiki prefixen if present
local proj, tag = interwiki_prefixen_get (one, true); -- get the interwiki prefixen if present
if 'w' == proj and ('Wikipedia' == mw.site.namespaces.Project['name']) then
if 'w' == proj and ('Wikipedia' == mw.site.namespaces.Project['name']) then
proj = nil; -- for stuff like :w:de:<article>, :w is unnecessary TODO: maint cat?
proj = nil; -- for stuff like :w:de:<article>, :w is unnecessary TODO: maint cat?
end
end
if proj then
if proj then
proj = ({['d'] = 'Wikidata', ['s'] = 'Wikisource', ['w'] = 'Wikipedia'})[proj]; -- :w (wikipedia) for linking from a non-wikipedia project
local proj_name = ({['d'] = 'Wikidata', ['s'] = 'Wikisource', ['w'] = 'Wikipedia'})[proj]; -- :w (wikipedia) for linking from a non-wikipedia project
if proj then  
if proj_name then  
one = one .. utilities.wrap_style ('interproj', proj); -- add resized leading space, brackets, static text, language name
one = one .. utilities.wrap_style ('interproj', proj_name); -- add resized leading space, brackets, static text, language name
utilities.add_prop_cat ('interproj-linked-name', proj); -- categorize it; <proj> is sort key
tag = nil; -- unset; don't do both project and language
tag = nil; -- unset; don't do both project and language
end
end
Line 1,260: Line 1,266:
end
end
if tag then
if tag then
local lang = cfg.lang_code_remap[tag] or cfg.mw_languages_by_tag_t[tag];
local lang = cfg.lang_tag_remap[tag] or cfg.mw_languages_by_tag_t[tag];
if lang then -- error messaging done in extract_names() where we know parameter names
if lang then -- error messaging done in extract_names() where we know parameter names
one = one .. utilities.wrap_style ('interwiki', lang); -- add resized leading space, brackets, static text, language name
one = one .. utilities.wrap_style ('interwiki', lang); -- add resized leading space, brackets, static text, language name
utilities.add_prop_cat ('interwiki-linked-name', tag); -- categorize it; <tag> is sort key
end
end
end
end
Line 1,290: Line 1,297:
local result = table.concat (name_list); -- construct list
local result = table.concat (name_list); -- construct list
if etal and utilities.is_set (result) then -- etal may be set by |display-authors=etal but we might not have a last-first list
if etal and utilities.is_set (result) then -- etal may be set by |display-authors=etal but we might not have a last-first list
result = result .. sep .. ' ' .. cfg.messages['et al']; -- we've got a last-first list and etal so add et al.
result = result .. sep .. cfg.messages['et al']; -- we've got a last-first list and etal so add et al.
end
end
Line 1,383: Line 1,390:
--[[---------------------< N A M E _ I S _ N U M E R I C >----------------------
--[[---------------------< N A M E _ I S _ N U M E R I C >----------------------


Add maint cat when name parameter value does not contain letters.  Does not catch
Add an error message and category when <name> parameter value does not contain letters.   
mixed alphanumeric names so |last=A. Green (1922-1987) does not get caught in the
 
current version of this test but |first=(1888) is caught.
Add a maintenance category when <name> parameter value has numeric characters mixed with characters that are
not numeric characters; could be letters and/or punctuation characters.
 
This function will only emit one error and one maint message for the current template. Does not emit both error
and maint messages/categories for the same parameter value.


returns nothing
returns nothing
Line 1,391: Line 1,402:
]]
]]


local function name_is_numeric (name, list_name)
local function name_is_numeric (name, name_alias, list_name)
if utilities.is_set (name) then
local patterns = {
if mw.ustring.match (name, '^[%A]+$') then -- when name does not contain any letters
'^%D+%d', -- <name> must have digits preceded by other characters
utilities.set_message ('maint_numeric_names', cfg.special_case_translation [list_name]); -- add a maint cat for this template
'^%D*%d+%D+', -- <name> must have digits followed by other characters
}
 
if not added_numeric_name_errs and mw.ustring.match (name, '^[%A]+$') then -- if we have not already set an error message and <name> does not have any alpha characters
utilities.set_message ('err_numeric_names', name_alias); -- add an error message
added_numeric_name_errs = true; -- set the flag so we emit only one error message
return; -- when here no point in further testing; abandon
end
 
if not added_numeric_name_maint then -- if we have already set a maint message
for _, pattern in ipairs (patterns) do -- spin through list of patterns
if mw.ustring.match (name, pattern) then -- digits preceded or followed by anything but digits; %D+ includes punctuation
utilities.set_message ('maint_numeric_names', cfg.special_case_translation [list_name]); -- add a maint cat for this template
added_numeric_name_maint = true; -- set the flag so we emit only one maint message
return; -- when here no point in further testing; abandon
end
end
end
end
end
Line 1,406: Line 1,432:
semicolons. Escaped semicolons are ones used as part of selected HTML entities.
semicolons. Escaped semicolons are ones used as part of selected HTML entities.
If the condition is met, the function adds the multiple name maintenance category.
If the condition is met, the function adds the multiple name maintenance category.
Same test for first except that commas should not appear in given names (MOS:JR says
that the generational suffix does not take a separator character).  Titles, degrees,
postnominals, affiliations, all normally comma separated don't belong in a citation.
<name> – name parameter value
<list_name> – AuthorList, EditorList, etc
<limit> – number of allowed commas; 1 (default) for surnames; 0 for given names


returns nothing
returns nothing
Line 1,411: Line 1,445:
]]
]]


local function name_has_mult_names (name, list_name)
local function name_has_mult_names (name, list_name, limit)
local _, commas, semicolons, nbsps;
local _, commas, semicolons, nbsps;
limit = limit and limit or 1;
if utilities.is_set (name) then
if utilities.is_set (name) then
_, commas = name:gsub (',', ''); -- count the number of commas
_, commas = name:gsub (',', ''); -- count the number of commas
Line 1,426: Line 1,461:
-- from semicolons to 'escape' them. If additional entities are added,
-- from semicolons to 'escape' them. If additional entities are added,
-- they also can be subtracted.
-- they also can be subtracted.
if 1 < commas or 0 < (semicolons - nbsps) then
if limit < commas or 0 < (semicolons - nbsps) then
utilities.set_message ('maint_mult_names', cfg.special_case_translation [list_name]); -- add a maint message
utilities.set_message ('maint_mult_names', cfg.special_case_translation [list_name]); -- add a maint message
end
end
Line 1,521: Line 1,556:


if not accept_name then -- <last> not wrapped in accept-as-written markup
if not accept_name then -- <last> not wrapped in accept-as-written markup
name_has_mult_names (last, list_name); -- check for multiple names in the parameter (last only)
name_has_mult_names (last, list_name); -- check for multiple names in the parameter
name_is_numeric (last, list_name); -- check for names that are composed of digits and punctuation
name_is_numeric (last, last_alias, list_name); -- check for names that have no letters or are a mix of digits and other characters
name_is_generic (last, last_alias); -- check for names found in the generic names list
name_is_generic (last, last_alias); -- check for names found in the generic names list
end
end
Line 1,531: Line 1,566:


if not accept_name then -- <first> not wrapped in accept-as-written markup
if not accept_name then -- <first> not wrapped in accept-as-written markup
name_is_numeric (first, list_name); -- check for names that are composed of digits and punctuation
name_has_mult_names (first, list_name, 0); -- check for multiple names in the parameter; 0 is number of allowed commas in a given name
name_is_numeric (first, first_alias, list_name); -- check for names that have no letters or are a mix of digits and other characters
name_is_generic (first, first_alias); -- check for names found in the generic names list
name_is_generic (first, first_alias); -- check for names found in the generic names list
end
end
Line 1,644: Line 1,680:


This function looks for:
This function looks for:
<lang_param> as a tag in cfg.lang_code_remap{}
<lang_param> as a tag in cfg.lang_tag_remap{}
<lang_param> as a name in cfg.lang_name_remap{}
<lang_param> as a name in cfg.lang_name_remap{}
Line 1,662: Line 1,698:
local tag;
local tag;


name = cfg.lang_code_remap[lang_param_lc]; -- assume <lang_param_lc> is a tag; attempt to get remapped language name  
name = cfg.lang_tag_remap[lang_param_lc]; -- assume <lang_param_lc> is a tag; attempt to get remapped language name  
if name then -- when <name>, <lang_param> is a tag for a remapped language name
if name then -- when <name>, <lang_param> is a tag for a remapped language name
if cfg.lang_name_remap[name:lower()][2] ~= lang_param_lc then
utilities.set_message ('maint_unknown_lang'); -- add maint category if not already added
return name, cfg.lang_name_remap[name:lower()][2]; -- so return name and tag from lang_name_remap[name]; special case to xlate sr-ec and sr-el to sr-cyrl and sr-latn
end
return name, lang_param_lc; -- so return <name> from remap and <lang_param_lc>
return name, lang_param_lc; -- so return <name> from remap and <lang_param_lc>
end
end


tag = lang_param_lc:match ('^(%a%a%a?)%-.*'); -- still assuming that <lang_param_lc> is a tag; strip script, region, variant subtags
tag = lang_param_lc:match ('^(%a%a%a?)%-.*'); -- still assuming that <lang_param_lc> is a tag; strip script, region, variant subtags
name = cfg.lang_code_remap[tag]; -- attempt to get remapped language name with language subtag only
name = cfg.lang_tag_remap[tag]; -- attempt to get remapped language name with language subtag only
if name then -- when <name>, <tag> is a tag for a remapped language name
if name then -- when <name>, <tag> is a tag for a remapped language name
return name, tag; -- so return <name> from remap and <tag>
return name, tag; -- so return <name> from remap and <tag>
end
end


if cfg.lang_name_remap[lang_param_lc] then -- not a tag, assume <lang_param_lc> is a name; attempt to get remapped language tag  
if cfg.lang_name_remap[lang_param_lc] then -- not a remapped tag, assume <lang_param_lc> is a name; attempt to get remapped language tag  
return cfg.lang_name_remap[lang_param_lc][1], cfg.lang_name_remap[lang_param_lc][2]; -- for this <lang_param_lc>, return a (possibly) new name and appropriate tag
return cfg.lang_name_remap[lang_param_lc][1], cfg.lang_name_remap[lang_param_lc][2]; -- for this <lang_param_lc>, return a (possibly) new name and appropriate tag
end
end


name = cfg.mw_languages_by_tag_t[lang_param_lc]; -- assume that <lang_param_lc> is a tag; attempt to get its matching language name
if name then
return name, lang_param_lc; -- <lang_param_lc> is a tag so return it and <name>
end
tag = cfg.mw_languages_by_name_t[lang_param_lc]; -- assume that <lang_param_lc> is a language name; attempt to get its matching tag
tag = cfg.mw_languages_by_name_t[lang_param_lc]; -- assume that <lang_param_lc> is a language name; attempt to get its matching tag
Line 1,683: Line 1,729:
end
end


name = cfg.mw_languages_by_tag_t[lang_param_lc]; -- assume that <lang_param_lc> is a tag; attempt to get its matching language name
if name then
return name, lang_param_lc; -- <lang_param_lc> is a tag so return it and <name>
end
tag = lang_param_lc:match ('^(%a%a%a?)%-.*'); -- is <lang_param_lc> an IETF-like tag that MediaWiki doesn't recognize? <tag> gets the language subtag; nil else
tag = lang_param_lc:match ('^(%a%a%a?)%-.*'); -- is <lang_param_lc> an IETF-like tag that MediaWiki doesn't recognize? <tag> gets the language subtag; nil else


Line 1,812: Line 1,852:
-- emit a maintenance message if user postscript is the default cs2 postscript
-- emit a maintenance message if user postscript is the default cs2 postscript
-- we catch the opposite case for cs1 in set_cs_style
-- we catch the opposite case for cs1 in set_cs_style
if 'cs2' == mode or 'citation' == cite_class then
if 'cs2' == mode or ('cs1' ~= mode and 'citation' == cite_class) then -- {{citation |title=Title |mode=cs1 |postscript=none}} should not emit maint message
utilities.set_message ('maint_postscript');
utilities.set_message ('maint_postscript');
end
end
Line 1,879: Line 1,919:


inputs:
inputs:
max: A['DisplayAuthors'] or A['DisplayEditors']; a number or some flavor of etal
max: A['DisplayAuthors'] or A['DisplayEditors'], etc; a number or some flavor of etal
count: #a or #e
count: #a or #e
list_name: 'authors' or 'editors'
list_name: 'authors' or 'editors'
etal: author_etal or editor_etal
etal: author_etal or editor_etal
This function sets an error message when |display-xxxxors= value greater than or equal to number of names but
not when <max> comes from {{cs1 config}} global settings.  When using global settings, <param> is set to the
keyword 'cs1 config' which is used to supress the normal error.  Error is suppressed because it is to be expected
that some citations in an article will have the same or fewer names that the limit specified in {{cs1 config}}.


]]
]]
Line 1,893: Line 1,938:
elseif max:match ('^%d+$') then -- if is a string of numbers
elseif max:match ('^%d+$') then -- if is a string of numbers
max = tonumber (max); -- make it a number
max = tonumber (max); -- make it a number
if max >= count then -- if |display-xxxxors= value greater than or equal to number of authors/editors
if (max >= count) and ('cs1 config' ~= param) then -- error when local |display-xxxxors= value greater than or equal to number of names; not an error when using global setting
utilities.set_message ('err_disp_name', {param, max}); -- add error message
utilities.set_message ('err_disp_name', {param, max}); -- add error message
max = nil;
max = nil;
end
end
else -- not a valid keyword or number
else -- not a valid keyword or number
utilities.set_message ('err_disp_name', {param, max}); -- add error message
utilities.set_message ('err_disp_name', {param, max}); -- add error message
max = nil; -- unset; as if |display-xxxxors= had not been set
max = nil; -- unset; as if |display-xxxxors= had not been set
end
end
Line 1,933: Line 1,978:
--[[--------------------------< E X T R A _ T E X T _ I N _ V O L _ I S S _ C H E C K >------------------------
--[[--------------------------< E X T R A _ T E X T _ I N _ V O L _ I S S _ C H E C K >------------------------


Adds error if |volume= or |issue= has what appears to be some form of redundant 'type' indicator.
Adds error if |volume= or |issue= has what appears to be some form of redundant 'type' indicator.  Applies to
both; this function looks for issue text in both |issue= and |volume= and looks for volume-like text in |voluem=
and |issue=.


For |volume=:
For |volume=:
Line 1,942: Line 1,989:
For |issue=:
For |issue=:
'No.', 'I.', 'Iss.' (with or without the dot) abbreviations, or 'Issue' in the first characters of the
'No.', 'I.', 'Iss.' (with or without the dot) abbreviations, or 'Issue' in the first characters of the
parameter content (all case insensitive).
parameter content (all case insensitive); numero styling: 'n°' with degree sign U+00B0, and № precomposed
numero sign U+2116.
Single character values ('v', 'i', 'n') allowed when not followed by separator character ('.', ':', '=', or
Single character values ('v', 'i', 'n') allowed when not followed by separator character ('.', ':', '=', or
Line 1,960: Line 2,008:
end
end
local patterns = 'v' == selector and cfg.vol_iss_pg_patterns.vpatterns or cfg.vol_iss_pg_patterns.ipatterns;
local handler = 'v' == selector and 'err_extra_text_volume' or 'err_extra_text_issue';
local handler = 'v' == selector and 'err_extra_text_volume' or 'err_extra_text_issue';
val = val:lower(); -- force parameter value to lower case
val = val:lower(); -- force parameter value to lower case
for _, pattern in ipairs (patterns) do -- spin through the selected sequence table of patterns
 
for _, pattern in ipairs (cfg.vol_iss_pg_patterns.vi_patterns_t) do -- spin through the sequence table of patterns
if val:match (pattern) then -- when a match, error so
if val:match (pattern) then -- when a match, error so
utilities.set_message (handler, name); -- add error message
utilities.set_message (handler, name); -- add error message
Line 2,414: Line 2,461:
for timestamp errors when the timestamp has a wildcard, return the URL unmodified
for timestamp errors when the timestamp has a wildcard, return the URL unmodified
for timestamp errors when the timestamp does not have a wildcard, return with timestamp limited to six digits plus wildcard (/yyyymm*/)
for timestamp errors when the timestamp does not have a wildcard, return with timestamp limited to six digits plus wildcard (/yyyymm*/)
A secondary function is to return an archive-url timestamp from those urls that have them (archive.org and
archive.today).  The timestamp is used by validation.archive_date_check() to see if the value in |archive-date=
matches the timestamp in the archive url.


]=]
]=]
Line 2,421: Line 2,472:
local path, timestamp, flag; -- portions of the archive.org URL
local path, timestamp, flag; -- portions of the archive.org URL
timestamp = url:match ('//archive.today/(%d%d%d%d%d%d%d%d%d%d%d%d%d%d)/') or -- get timestamp from archive.today urls
url:match ('//archive.today/(%d%d%d%d%.%d%d%.%d%d%-%d%d%d%d%d%d)/'); -- this timestamp needs cleanup
if timestamp then -- if this was an archive.today url ...
return url, date, timestamp:gsub ('[%.%-]', ''); -- return ArchiveURL, ArchiveDate, and timestamp (dots and dashes removed) from |archive-url=, and done
end
-- here for archive.org urls
if (not url:match('//web%.archive%.org/')) and (not url:match('//liveweb%.archive%.org/')) then -- also deprecated liveweb Wayback machine URL
if (not url:match('//web%.archive%.org/')) and (not url:match('//liveweb%.archive%.org/')) then -- also deprecated liveweb Wayback machine URL
return url, date; -- not an archive.org archive, return ArchiveURL and ArchiveDate
return url, date; -- not an archive.org archive, return ArchiveURL and ArchiveDate
Line 2,450: Line 2,507:
err_msg = cfg.err_msg_supl.flag;
err_msg = cfg.err_msg_supl.flag;
else
else
return url, date; -- return ArchiveURL and ArchiveDate
return url, date, timestamp; -- return ArchiveURL, ArchiveDate, and timestamp from |archive-url=
end
end
end
end
Line 2,457: Line 2,514:


if is_preview_mode then
if is_preview_mode then
return url, date; -- preview mode so return ArchiveURL and ArchiveDate
return url, date, timestamp; -- preview mode so return ArchiveURL, ArchiveDate, and timestamp from |archive-url=
else
else
return '', ''; -- return empty strings for ArchiveURL and ArchiveDate
return '', ''; -- return empty strings for ArchiveURL and ArchiveDate
Line 2,504: Line 2,561:




--[[--------------------------< C I T A T I O N 0 >------------------------------------------------------------
--[[--------------------------< D I S P L A Y _ N A M E S _ S E L E C T >--------------------------------------
 
for any of the |display-authors=, |display-editors=, etc parameters, select either the local or global setting.
When both are present, look at <local_display_names> value.  When the value is some sort of 'et al.'string,
special handling is required.
 
When {{cs1 config}} has |display-<namelist>= AND this template has |display-<namelist>=etal AND:
the number of names specified by <number_of_names> is:
greater than the number specified in the global |display-<namelist>= parameter (<global_display_names>)
use global |display-<namelist>= parameter value
set overridden maint category
less than or equal to the number specified in the global |display-<namelist>=  parameter
use local |display-<namelist>= parameter value


This is the main function doing the majority of the citation formatting.
The purpose of this function is to prevent categorizing a template that has fewer names than the global setting
to keep the etal annotation specified by <local_display_names>.


]]
]]


local function citation0( config, args )
local function display_names_select (global_display_names, local_display_names, param_name, number_of_names, test)
--[[  
if global_display_names and utilities.is_set (local_display_names) then -- when both
if 'etal' == local_display_names:lower():gsub("[ '%.]", '') then -- the :gsub() portion makes 'etal' from a variety of 'et al.' spellings and stylings
number_of_names = tonumber (number_of_names); -- convert these to numbers for comparison
local global_display_names_num = tonumber (global_display_names); -- <global_display_names> not set when parameter value is not digits
 
if number_of_names > global_display_names_num then -- template has more names than global config allows to be displayed?
utilities.set_message ('maint_overridden_setting'); -- set a maint message because global is overriding local |display-<namelist>=etal
return global_display_names, 'cs1 config'; -- return global with spoof parameter name (for get_display_names())
else
return local_display_names, param_name; -- return local because fewer names so let <local_display_names> control
end
end
-- here when <global_display_names> and <local_display_names> both numbers; <global_display_names> controls
utilities.set_message ('maint_overridden_setting'); -- set a maint message
return global_display_names, 'cs1 config'; -- return global with spoof parameter name (for get_display_names())
end
-- here when only one of <global_display_names> or <local_display_names> set
if global_display_names then
return global_display_names, 'cs1 config'; -- return global with spoof parameter name (for get_display_names())
else
return local_display_names, param_name; -- return local
end
end
 
 
--[[--------------------------< C I T A T I O N 0 >------------------------------------------------------------
 
This is the main function doing the majority of the citation formatting.
 
]]
 
local function citation0( config, args )
--[[  
Load Input Parameters
Load Input Parameters
The argument_wrapper facilitates the mapping of multiple aliases to single internal variable.
The argument_wrapper facilitates the mapping of multiple aliases to single internal variable.
Line 2,524: Line 2,626:
local a = {}; -- authors list from |lastn= / |firstn= pairs or |vauthors=
local a = {}; -- authors list from |lastn= / |firstn= pairs or |vauthors=
local Authors;
local Authors;
local NameListStyle = is_valid_parameter_value (A['NameListStyle'], A:ORIGIN('NameListStyle'), cfg.keywords_lists['name-list-style'], '');
local NameListStyle;
if cfg.global_cs1_config_t['NameListStyle'] then -- global setting in {{cs1 config}} overrides local |name-list-style= parameter value; nil when empty or assigned value invalid
NameListStyle = is_valid_parameter_value (cfg.global_cs1_config_t['NameListStyle'], 'cs1 config: name-list-style', cfg.keywords_lists['name-list-style'], ''); -- error messaging 'param' here is a hoax
else
NameListStyle = is_valid_parameter_value (A['NameListStyle'], A:ORIGIN('NameListStyle'), cfg.keywords_lists['name-list-style'], '');
end
 
if cfg.global_cs1_config_t['NameListStyle'] and utilities.is_set (A['NameListStyle']) then -- when template has |name-list-style=<something> which global setting has overridden
utilities.set_message ('maint_overridden_setting'); -- set a maint message
end
 
local Collaboration = A['Collaboration'];
local Collaboration = A['Collaboration'];


Line 2,533: Line 2,645:
elseif 2 == selected then
elseif 2 == selected then
NameListStyle = 'vanc'; -- override whatever |name-list-style= might be
NameListStyle = 'vanc'; -- override whatever |name-list-style= might be
a, author_etal = parse_vauthors_veditors (args, args.vauthors, 'AuthorList'); -- fetch author list from |vauthors=, |author-linkn=, and |author-maskn=
a, author_etal = parse_vauthors_veditors (args, A['Vauthors'], 'AuthorList'); -- fetch author list from |vauthors=, |author-linkn=, and |author-maskn=
elseif 3 == selected then
elseif 3 == selected then
Authors = A['Authors']; -- use content of |authors=
Authors = A['Authors']; -- use content of |people= or |credits=; |authors= is deprecated; TODO: constrain |people= and |credits= to cite av media, episode, serial?
if 'authors' == A:ORIGIN('Authors') then -- but add a maint cat if the parameter is |authors=
utilities.set_message ('maint_authors'); -- because use of this parameter is discouraged; what to do about the aliases is a TODO:
end
end
end
if utilities.is_set (Collaboration) then
if utilities.is_set (Collaboration) then
Line 2,589: Line 2,698:
local TitleLink = A['TitleLink'];
local TitleLink = A['TitleLink'];


local auto_select = ''; -- default is auto
local auto_select = ''; -- default is auto
local accept_link;
local accept_link;
TitleLink, accept_link = utilities.has_accept_as_written (TitleLink, true); -- test for accept-this-as-written markup
TitleLink, accept_link = utilities.has_accept_as_written (TitleLink, true); -- test for accept-this-as-written markup
Line 2,606: Line 2,715:


local Periodical = A['Periodical'];
local Periodical = A['Periodical'];
local Periodical_origin = '';
local Periodical_origin = A:ORIGIN('Periodical');
local ScriptPeriodical = A['ScriptPeriodical'];
local ScriptPeriodical_origin = A:ORIGIN('ScriptPeriodical');
local TransPeriodical =  A['TransPeriodical'];
local TransPeriodical_origin =  A:ORIGIN ('TransPeriodical');
if (utilities.in_array (config.CitationClass, {'book', 'encyclopaedia'}) and (utilities.is_set (Periodical) or utilities.is_set (ScriptPeriodical) or utilities.is_set (TransPeriodical))) then
local param;
if utilities.is_set (Periodical) then -- get a parameter name from one of these periodical related meta-parameters
Periodical = ''; -- unset because not valid {{cite book}} or {{cite encyclopedia}} parameters
param = Periodical_origin -- get parameter name for error messaging
elseif utilities.is_set (TransPeriodical) then
TransPeriodical = ''; -- unset because not valid {{cite book}} or {{cite encyclopedia}} parameters
param = TransPeriodical_origin; -- get parameter name for error messaging
elseif utilities.is_set (ScriptPeriodical) then
ScriptPeriodical = ''; -- unset because not valid {{cite book}} or {{cite encyclopedia}} parameters
param = ScriptPeriodical_origin; -- get parameter name for error messaging
end
 
if utilities.is_set (param) then -- if we found one
utilities.set_message ('err_periodical_ignored', {param}); -- emit an error message
end
end
 
if utilities.is_set (Periodical) then
if utilities.is_set (Periodical) then
Periodical_origin = A:ORIGIN('Periodical'); -- get the name of the periodical parameter
local i;
local i;
Periodical, i = utilities.strip_apostrophe_markup (Periodical); -- strip apostrophe markup so that metadata isn't contaminated  
Periodical, i = utilities.strip_apostrophe_markup (Periodical); -- strip apostrophe markup so that metadata isn't contaminated  
Line 2,624: Line 2,755:
Periodical_origin = A:ORIGIN('MailingList');
Periodical_origin = A:ORIGIN('MailingList');
end
end
local ScriptPeriodical = A['ScriptPeriodical'];


-- web and news not tested for now because of  
-- web and news not tested for now because of  
Line 2,638: Line 2,767:
local Volume;
local Volume;
local ScriptPeriodical_origin = A:ORIGIN('ScriptPeriodical');
if 'citation' == config.CitationClass then
if 'citation' == config.CitationClass then
if utilities.is_set (Periodical) then
if utilities.is_set (Periodical) then
Line 2,694: Line 2,822:
local PublisherName = A['PublisherName'];
local PublisherName = A['PublisherName'];
local PublisherName_origin = A:ORIGIN('PublisherName');
local PublisherName_origin = A:ORIGIN('PublisherName');
if utilities.is_set (PublisherName) then
if utilities.is_set (PublisherName) and (cfg.keywords_xlate['none'] ~= PublisherName) then
local i = 0;
local i = 0;
PublisherName, i = utilities.strip_apostrophe_markup (PublisherName); -- strip apostrophe markup so that metadata isn't contaminated; publisher is never italicized
PublisherName, i = utilities.strip_apostrophe_markup (PublisherName); -- strip apostrophe markup so that metadata isn't contaminated; publisher is never italicized
if i then -- non-zero when markup was stripped so emit an error message
if i and (0 < i) then -- non-zero when markup was stripped so emit an error message
utilities.set_message ('err_apostrophe_markup', {PublisherName_origin});
utilities.set_message ('err_apostrophe_markup', {PublisherName_origin});
end
end
end
if ('document' == config.CitationClass) and not utilities.is_set (PublisherName) then
utilities.set_message ('err_missing_publisher', {config.CitationClass, 'publisher'});
end
end


Line 2,706: Line 2,838:


if 'newsgroup' == config.CitationClass then
if 'newsgroup' == config.CitationClass then
if utilities.is_set (PublisherName) then -- general use parameter |publisher= not allowed in cite newsgroup
if utilities.is_set (PublisherName) and (cfg.keywords_xlate['none'] ~= PublisherName) then -- general use parameter |publisher= not allowed in cite newsgroup
utilities.set_message ('err_parameter_ignored', {PublisherName_origin});
utilities.set_message ('err_parameter_ignored', {PublisherName_origin});
end
end
Line 2,768: Line 2,900:


if PublicationPlace == Place then Place = ''; end -- don't need both if they are the same
if PublicationPlace == Place then Place = ''; end -- don't need both if they are the same
 
local URL_origin = A:ORIGIN('URL'); -- get name of parameter that holds URL
local URL_origin = A:ORIGIN('URL'); -- get name of parameter that holds URL
local ChapterURL_origin = A:ORIGIN('ChapterURL'); -- get name of parameter that holds ChapterURL
local ChapterURL_origin = A:ORIGIN('ChapterURL'); -- get name of parameter that holds ChapterURL
Line 2,783: Line 2,915:
Parameter remapping for cite encyclopedia:
Parameter remapping for cite encyclopedia:
When the citation has these parameters:
When the citation has these parameters:
|encyclopedia= and |title= then map |title= to |article= and |encyclopedia= to |title=
|encyclopedia= and |title= then map |title= to |article= and |encyclopedia= to |title= for rendering
|encyclopedia= and |article= then map |encyclopedia= to |title=
|encyclopedia= and |article= then map |encyclopedia= to |title= for rendering


|trans-title= maps to |trans-chapter= when |title= is re-mapped
|trans-title= maps to |trans-chapter= when |title= is re-mapped
Line 2,794: Line 2,926:


local Encyclopedia = A['Encyclopedia']; -- used as a flag by this module and by ~/COinS
local Encyclopedia = A['Encyclopedia']; -- used as a flag by this module and by ~/COinS
local ScriptEncyclopedia = A['ScriptEncyclopedia'];
local TransEncyclopedia = A['TransEncyclopedia'];


if utilities.is_set (Encyclopedia) then -- emit error message when Encyclopedia set but template is other than {{cite encyclopedia}} or {{citation}}
if utilities.is_set (Encyclopedia) or utilities.is_set (ScriptEncyclopedia) then -- emit error message when Encyclopedia set but template is other than {{cite encyclopedia}} or {{citation}}
if 'encyclopaedia' ~= config.CitationClass and 'citation' ~= config.CitationClass then
if 'encyclopaedia' ~= config.CitationClass and 'citation' ~= config.CitationClass then
utilities.set_message ('err_parameter_ignored', {A:ORIGIN ('Encyclopedia')});
if utilities.is_set (Encyclopedia) then
Encyclopedia = nil; -- unset because not supported by this template
utilities.set_message ('err_parameter_ignored', {A:ORIGIN ('Encyclopedia')});
else
utilities.set_message ('err_parameter_ignored', {A:ORIGIN ('ScriptEncyclopedia')});
end
Encyclopedia = nil; -- unset these because not supported by this template
ScriptEncyclopedia = nil;
TransEncyclopedia = nil;
end
end
elseif utilities.is_set (TransEncyclopedia) then
utilities.set_message ('err_trans_missing_title', {'encyclopedia'});
end
end


if ('encyclopaedia' == config.CitationClass) or ('citation' == config.CitationClass and utilities.is_set (Encyclopedia)) then
if ('encyclopaedia' == config.CitationClass) or ('citation' == config.CitationClass and utilities.is_set (Encyclopedia)) then
if utilities.is_set (Periodical) and utilities.is_set (Encyclopedia) then -- when both set emit an error TODO: make a function for this and similar?
if utilities.is_set (Periodical) and utilities.is_set (Encyclopedia) then -- when both parameters set emit an error message; {{citation}} only; Periodical not allowed in {{cite encyclopedia}}
utilities.set_message ('err_redundant_parameters', {utilities.wrap_style ('parameter', A:ORIGIN ('Encyclopedia')) .. cfg.presentation['sep_list_pair'] .. utilities.wrap_style ('parameter', Periodical_origin)});
utilities.set_message ('err_periodical_ignored', {Periodical_origin});
end
end


if utilities.is_set (Encyclopedia) then
if utilities.is_set (Encyclopedia) or utilities.is_set (ScriptEncyclopedia) then
Periodical = Encyclopedia; -- error or no, set Periodical to Encyclopedia; allow periodical without encyclopedia
Periodical = Encyclopedia; -- error or no, set Periodical to Encyclopedia for rendering; {{citation}} could (not legitimately) have both; use Encyclopedia
Periodical_origin = A:ORIGIN ('Encyclopedia');
Periodical_origin = A:ORIGIN ('Encyclopedia');
end
ScriptPeriodical = ScriptEncyclopedia;
ScriptPeriodical_origin = A:ORIGIN ('ScriptEncyclopedia');


if utilities.is_set (Periodical) then -- Periodical is set when |encyclopedia= is set
if utilities.is_set (Title) or utilities.is_set (ScriptTitle) then
if utilities.is_set (Title) or utilities.is_set (ScriptTitle) then
if not utilities.is_set (Chapter) then
if not utilities.is_set (Chapter) then
Chapter = Title; -- |encyclopedia= and |title= are set so map |title= to |article= and |encyclopedia= to |title=
Chapter = Title; -- |encyclopedia= and |title= are set so map |title= params to |article= params for rendering
ScriptChapter = ScriptTitle;
ScriptChapter = ScriptTitle;
ScriptChapter_origin = A:ORIGIN('ScriptTitle')
ScriptChapter_origin = A:ORIGIN('ScriptTitle')
Line 2,821: Line 2,963:
ChapterURL = URL;
ChapterURL = URL;
ChapterURL_origin = URL_origin;
ChapterURL_origin = URL_origin;
ChapterUrlAccess = UrlAccess;
ChapterUrlAccess = UrlAccess;
ChapterFormat = Format;


if not utilities.is_set (ChapterURL) and utilities.is_set (TitleLink) then
if not utilities.is_set (ChapterURL) and utilities.is_set (TitleLink) then
Chapter = utilities.make_wikilink (TitleLink, Chapter);
Chapter = utilities.make_wikilink (TitleLink, Chapter);
end
end
Title = Periodical;
Title = Periodical; -- now map |encyclopedia= params to |title= params for rendering
ChapterFormat = Format;
ScriptTitle = ScriptPeriodical or '';
TransTitle = TransEncyclopedia or '';
Periodical = ''; -- redundant so unset
Periodical = ''; -- redundant so unset
TransTitle = '';
ScriptPeriodical = '';
URL = '';
URL = '';
Format = '';
Format = '';
TitleLink = '';
TitleLink = '';
ScriptTitle = '';
end
end
elseif utilities.is_set (Chapter) or utilities.is_set (ScriptChapter) then -- |title= not set
elseif utilities.is_set (Chapter) or utilities.is_set (ScriptChapter) then -- |title= not set
Title = Periodical; -- |encyclopedia= set and |article= set so map |encyclopedia= to |title=
Title = Periodical; -- |encyclopedia= set and |article= set so map |encyclopedia= to |title= for rendering
ScriptTitle = ScriptPeriodical or '';
TransTitle = TransEncyclopedia or '';
Periodical = ''; -- redundant so unset
Periodical = ''; -- redundant so unset
ScriptPeriodical = '';
end
end
end
end
Line 2,883: Line 3,028:
-- CS1/2 mode
-- CS1/2 mode
local Mode = is_valid_parameter_value (A['Mode'], A:ORIGIN('Mode'), cfg.keywords_lists['mode'], '');
local Mode;
if cfg.global_cs1_config_t['Mode'] then -- global setting in {{cs1 config}} overrides local |mode= parameter value; nil when empty or assigned value invalid
Mode = is_valid_parameter_value (cfg.global_cs1_config_t['Mode'], 'cs1 config: mode', cfg.keywords_lists['mode'], ''); -- error messaging 'param' here is a hoax
else
Mode = is_valid_parameter_value (A['Mode'], A:ORIGIN('Mode'), cfg.keywords_lists['mode'], '');
end
 
if cfg.global_cs1_config_t['Mode'] and utilities.is_set (A['Mode']) then -- when template has |mode=<something> which global setting has overridden
utilities.set_message ('maint_overridden_setting'); -- set a maint message
end
 
-- separator character and postscript
-- separator character and postscript
local sepc, PostScript = set_style (Mode:lower(), A['PostScript'], config.CitationClass);
local sepc, PostScript = set_style (Mode:lower(), A['PostScript'], config.CitationClass);
Line 2,986: Line 3,141:
local TitleType = A['TitleType'];
local TitleType = A['TitleType'];
local Degree = A['Degree'];
local Degree = A['Degree'];
if utilities.in_array (config.CitationClass, {'AV-media-notes', 'interview', 'mailinglist', 'map', 'podcast', 'pressrelease', 'report', 'speech', 'techreport', 'thesis'}) then
if utilities.in_array (config.CitationClass, {'AV-media-notes', 'document', 'interview', 'mailinglist', 'map', 'podcast', 'pressrelease', 'report', 'speech', 'techreport', 'thesis'}) then
TitleType = set_titletype (config.CitationClass, TitleType);
TitleType = set_titletype (config.CitationClass, TitleType);
if utilities.is_set (Degree) and "Thesis" == TitleType then -- special case for cite thesis
if utilities.is_set (Degree) and "Thesis" == TitleType then -- special case for cite thesis
Line 3,004: Line 3,159:
local Year = A['Year'];
local Year = A['Year'];


if utilities.is_set (Year) then
validation.year_check (Year); -- returns nothing; emits maint message when |year= doesn't hold a 'year' value
end
if not utilities.is_set (Date) then
if not utilities.is_set (Date) then
Date = Year; -- promote Year to Date
Date = Year; -- promote Year to Date
Line 3,035: Line 3,194:
local ArchiveDate;
local ArchiveDate;
local ArchiveFormat = A['ArchiveFormat'];
local ArchiveFormat = A['ArchiveFormat'];
 
local archive_url_timestamp; -- timestamp from wayback machine url
ArchiveURL, ArchiveDate = archive_url_check (A['ArchiveURL'], A['ArchiveDate'])
ArchiveURL, ArchiveDate, archive_url_timestamp = archive_url_check (A['ArchiveURL'], A['ArchiveDate'])
ArchiveFormat = style_format (ArchiveFormat, ArchiveURL, 'archive-format', 'archive-url');
ArchiveFormat = style_format (ArchiveFormat, ArchiveURL, 'archive-format', 'archive-url');
ArchiveURL, ArchiveDate = is_unique_archive_url (ArchiveURL, URL, ChapterURL, A:ORIGIN('ArchiveURL'), ArchiveDate); -- add error message when URL or ChapterURL == ArchiveURL
ArchiveURL, ArchiveDate = is_unique_archive_url (ArchiveURL, URL, ChapterURL, A:ORIGIN('ArchiveURL'), ArchiveDate); -- add error message when URL or ChapterURL == ArchiveURL


local AccessDate = A['AccessDate'];
local AccessDate = A['AccessDate'];
local LayDate = A['LayDate'];
local COinS_date = {}; -- holds date info extracted from |date= for the COinS metadata by Module:Date verification
local COinS_date = {}; -- holds date info extracted from |date= for the COinS metadata by Module:Date verification
local DoiBroken = A['DoiBroken'];
local DoiBroken = A['DoiBroken'];
Line 3,057: Line 3,215:
['doi-broken-date'] = {val = DoiBroken, name = A:ORIGIN ('DoiBroken')},
['doi-broken-date'] = {val = DoiBroken, name = A:ORIGIN ('DoiBroken')},
['pmc-embargo-date'] = {val = Embargo, name = A:ORIGIN ('Embargo')},
['pmc-embargo-date'] = {val = Embargo, name = A:ORIGIN ('Embargo')},
['lay-date'] = {val = LayDate, name = A:ORIGIN ('LayDate')},
['publication-date'] = {val = PublicationDate, name = A:ORIGIN ('PublicationDate')},
['publication-date'] = {val = PublicationDate, name = A:ORIGIN ('PublicationDate')},
['year'] = {val = Year, name = A:ORIGIN ('Year')},
['year'] = {val = Year, name = A:ORIGIN ('Year')},
Line 3,064: Line 3,221:
local error_list = {};
local error_list = {};
anchor_year, Embargo = validation.dates(date_parameters_list, COinS_date, error_list);
anchor_year, Embargo = validation.dates(date_parameters_list, COinS_date, error_list);
-- start temporary Julian / Gregorian calendar uncertainty categorization
if COinS_date.inter_cal_cat then
utilities.add_prop_cat ('jul-greg-uncertainty');
end
-- end temporary Julian / Gregorian calendar uncertainty categorization


if utilities.is_set (Year) and utilities.is_set (Date) then -- both |date= and |year= not normally needed;  
if utilities.is_set (Year) and utilities.is_set (Date) then -- both |date= and |year= not normally needed;  
validation.year_date_check (Year, A:ORIGIN ('Year'), Date, A:ORIGIN ('Date'), error_list);
validation.year_date_check (Year, A:ORIGIN ('Year'), Date, A:ORIGIN ('Date'), error_list);
end
end
 
if 0 == #error_list then -- error free dates only; 0 when error_list is empty
if 0 == #error_list then -- error free dates only; 0 when error_list is empty
local modified = false; -- flag
local modified = false; -- flag
Line 3,098: Line 3,249:
Date = date_parameters_list['date'].val;
Date = date_parameters_list['date'].val;
DoiBroken = date_parameters_list['doi-broken-date'].val;
DoiBroken = date_parameters_list['doi-broken-date'].val;
LayDate = date_parameters_list['lay-date'].val;
PublicationDate = date_parameters_list['publication-date'].val;
PublicationDate = date_parameters_list['publication-date'].val;
end
if archive_url_timestamp and utilities.is_set (ArchiveDate) then
validation.archive_date_check (ArchiveDate, archive_url_timestamp, DF); -- does YYYYMMDD in archive_url_timestamp match date in ArchiveDate
end
end
else
else
Line 3,105: Line 3,259:
end
end
end -- end of do
end -- end of do
if utilities.in_array (config.CitationClass, {'book', 'encyclopaedia'}) or -- {{cite book}}, {{cite encyclopedia}}; TODO: {{cite conference}} and others?
('citation' == config.CitationClass and utilities.is_set (Encyclopedia)) or -- {{citation}} as an encylopedia citation
('citation' == config.CitationClass and not utilities.is_set (Periodical)) then -- {{citation}} as a book citation
if utilities.is_set (PublicationPlace) then
if not utilities.is_set (PublisherName) then
local date = COinS_date.rftdate and tonumber (COinS_date.rftdate:match ('%d%d%d%d')); -- get year portion of COinS date (because in Arabic numerals); convert string to number
if date and (1850 <= date) then -- location has no publisher; if date is 1850 or later
utilities.set_message ('maint_location_no_publisher'); -- add maint cat
end
else -- PublisherName has a value
if cfg.keywords_xlate['none'] == PublisherName then -- if that value is 'none' (only for book and encyclopedia citations)
PublisherName = ''; -- unset
end
end
end
end


local ID_list = {}; -- sequence table of rendered identifiers
local ID_list = {}; -- sequence table of rendered identifiers
Line 3,118: Line 3,289:
ID_list, ID_list_coins = identifiers.identifier_lists_get (args, {DoiBroken = DoiBroken, ASINTLD = A['ASINTLD'], Embargo = Embargo, Class = Class}, ID_support);
ID_list, ID_list_coins = identifiers.identifier_lists_get (args, {DoiBroken = DoiBroken, ASINTLD = A['ASINTLD'], Embargo = Embargo, Class = Class}, ID_support);


-- Account for the oddities that are {{cite arxiv}}, {{cite biorxiv}}, {{cite citeseerx}}, {{cite ssrn}}, before generation of COinS data.
-- Account for the oddities that are {{cite arxiv}}, {{cite biorxiv}}, {{cite citeseerx}}, {{cite medrxiv}}, {{cite ssrn}}, before generation of COinS data.
if utilities.in_array (config.CitationClass, whitelist.preprint_template_list) then -- |arxiv= or |eprint= required for cite arxiv; |biorxiv=, |citeseerx=, |ssrn= required for their templates
if utilities.in_array (config.CitationClass, whitelist.preprint_template_list_t) then -- |arxiv= or |eprint= required for cite arxiv; |biorxiv=, |citeseerx=, |medrxiv=, |ssrn= required for their templates
if not (args[cfg.id_handlers[config.CitationClass:upper()].parameters[1]] or -- can't use ID_list_coins k/v table here because invalid parameters omitted
if not (args[cfg.id_handlers[config.CitationClass:upper()].parameters[1]] or -- can't use ID_list_coins k/v table here because invalid parameters omitted
args[cfg.id_handlers[config.CitationClass:upper()].parameters[2]]) then -- which causes unexpected parameter missing error message
args[cfg.id_handlers[config.CitationClass:upper()].parameters[2]]) then -- which causes unexpected parameter missing error message
utilities.set_message ('err_' .. config.CitationClass .. '_missing'); -- add error message
utilities.set_message ('err_' .. config.CitationClass .. '_missing'); -- add error message
end
end


Periodical = ({['arxiv'] = 'arXiv', ['biorxiv'] = 'bioRxiv', ['citeseerx'] = 'CiteSeerX', ['ssrn'] = 'Social Science Research Network'})[config.CitationClass];
Periodical = ({['arxiv'] = 'arXiv', ['biorxiv'] = 'bioRxiv', ['citeseerx'] = 'CiteSeerX', ['medrxiv'] = 'medRxiv', ['ssrn'] = 'Social Science Research Network'})[config.CitationClass];
end
end


Line 3,197: Line 3,368:
['Title'] = metadata.make_coins_title (coins_title, ScriptTitle), -- Title and ScriptTitle stripped of bold / italic / accept-as-written markup
['Title'] = metadata.make_coins_title (coins_title, ScriptTitle), -- Title and ScriptTitle stripped of bold / italic / accept-as-written markup
['PublicationPlace'] = PublicationPlace,
['PublicationPlace'] = PublicationPlace,
['Date'] = COinS_date.rftdate, -- COinS_date has correctly formatted date if Date is valid;
['Date'] = COinS_date.rftdate, -- COinS_date.* has correctly formatted date values if Date is valid;
['Season'] = COinS_date.rftssn,
['Season'] = COinS_date.rftssn,
['Quarter'] = COinS_date.rftquarter,
['Quarter'] = COinS_date.rftquarter,
['Chron'] =  COinS_date.rftchron or (not COinS_date.rftdate and Date) or '', -- chron but if not set and invalid date format use Date; keep this last bit?
['Chron'] =  COinS_date.rftchron,
['Series'] = Series,
['Series'] = Series,
['Volume'] = Volume,
['Volume'] = Volume,
Line 3,214: Line 3,385:
}, config.CitationClass);
}, config.CitationClass);


-- Account for the oddities that are {{cite arxiv}}, {{cite biorxiv}}, {{cite citeseerx}}, and {{cite ssrn}} AFTER generation of COinS data.
-- Account for the oddities that are {{cite arxiv}}, {{cite biorxiv}}, {{cite citeseerx}}, {{cite medrxiv}}, and {{cite ssrn}} AFTER generation of COinS data.
if utilities.in_array (config.CitationClass, whitelist.preprint_template_list) then -- we have set rft.jtitle in COinS to arXiv, bioRxiv, CiteSeerX, or ssrn now unset so it isn't displayed
if utilities.in_array (config.CitationClass, whitelist.preprint_template_list_t) then -- we have set rft.jtitle in COinS to arXiv, bioRxiv, CiteSeerX, medRxiv, or ssrn now unset so it isn't displayed
Periodical = ''; -- periodical not allowed in these templates; if article has been published, use cite journal
Periodical = ''; -- periodical not allowed in these templates; if article has been published, use cite journal
end
end
Line 3,243: Line 3,414:
local last_first_list;
local last_first_list;
local control = {  
local control = {  
format = NameListStyle, -- empty string or 'vanc'
format = NameListStyle, -- empty string, '&', 'amp', 'and', or 'vanc'
maximum = nil, -- as if display-authors or display-editors not set
maximum = nil, -- as if display-authors or display-editors not set
mode = Mode
mode = Mode
Line 3,249: Line 3,420:


do -- do editor name list first because the now unsupported coauthors used to modify control table
do -- do editor name list first because the now unsupported coauthors used to modify control table
control.maximum , editor_etal = get_display_names (A['DisplayEditors'], #e, 'editors', editor_etal, A:ORIGIN ('DisplayEditors'));
local display_names, param = display_names_select (cfg.global_cs1_config_t['DisplayEditors'], A['DisplayEditors'], A:ORIGIN ('DisplayEditors'), #e);
control.maximum, editor_etal = get_display_names (display_names, #e, 'editors', editor_etal, param);
 
Editors, EditorCount = list_people (control, e, editor_etal);
Editors, EditorCount = list_people (control, e, editor_etal);


Line 3,257: Line 3,430:
end
end
do -- now do interviewers
do -- now do interviewers
control.maximum, interviewer_etal = get_display_names (A['DisplayInterviewers'], #interviewers_list, 'interviewers', interviewer_etal, A:ORIGIN ('DisplayInterviewers'));
local display_names, param = display_names_select (cfg.global_cs1_config_t['DisplayInterviewers'], A['DisplayInterviewers'], A:ORIGIN ('DisplayInterviewers'), #interviewers_list);
control.maximum, interviewer_etal = get_display_names (display_names, #interviewers_list, 'interviewers', interviewer_etal, param);
 
Interviewers = list_people (control, interviewers_list, interviewer_etal);
Interviewers = list_people (control, interviewers_list, interviewer_etal);
end
end
do -- now do translators
do -- now do translators
control.maximum, translator_etal = get_display_names (A['DisplayTranslators'], #t, 'translators', translator_etal, A:ORIGIN ('DisplayTranslators'));
local display_names, param = display_names_select (cfg.global_cs1_config_t['DisplayTranslators'], A['DisplayTranslators'], A:ORIGIN ('DisplayTranslators'), #t);
control.maximum, translator_etal = get_display_names (display_names, #t, 'translators', translator_etal, param);
 
Translators = list_people (control, t, translator_etal);
Translators = list_people (control, t, translator_etal);
end
end
do -- now do contributors
do -- now do contributors
control.maximum, contributor_etal = get_display_names (A['DisplayContributors'], #c, 'contributors', contributor_etal, A:ORIGIN ('DisplayContributors'));
local display_names, param = display_names_select (cfg.global_cs1_config_t['DisplayContributors'], A['DisplayContributors'], A:ORIGIN ('DisplayContributors'), #c);
control.maximum, contributor_etal = get_display_names (display_names, #c, 'contributors', contributor_etal, param);
 
Contributors = list_people (control, c, contributor_etal);
Contributors = list_people (control, c, contributor_etal);
end
end
do -- now do authors
do -- now do authors
control.maximum, author_etal = get_display_names (A['DisplayAuthors'], #a, 'authors', author_etal, A:ORIGIN ('DisplayAuthors'));
local display_names, param = display_names_select (cfg.global_cs1_config_t['DisplayAuthors'], A['DisplayAuthors'], A:ORIGIN ('DisplayAuthors'), #a, author_etal);
control.maximum, author_etal = get_display_names (display_names, #a, 'authors', author_etal, param);


last_first_list = list_people (control, a, author_etal);
last_first_list = list_people (control, a, author_etal);
Line 3,295: Line 3,475:


-- special case for chapter format so no error message or cat when chapter not supported
-- special case for chapter format so no error message or cat when chapter not supported
if not (utilities.in_array (config.CitationClass, {'web', 'news', 'journal', 'magazine', 'pressrelease', 'podcast', 'newsgroup', 'arxiv', 'biorxiv', 'citeseerx', 'ssrn'}) or
if not (utilities.in_array (config.CitationClass, {'web', 'news', 'journal', 'magazine', 'pressrelease', 'podcast', 'newsgroup', 'arxiv', 'biorxiv', 'citeseerx', 'medrxiv', 'ssrn'}) or
('citation' == config.CitationClass and (utilities.is_set (Periodical) or utilities.is_set (ScriptPeriodical)) and not utilities.is_set (Encyclopedia))) then
('citation' == config.CitationClass and (utilities.is_set (Periodical) or utilities.is_set (ScriptPeriodical)) and not utilities.is_set (Encyclopedia))) then
ChapterFormat = style_format (ChapterFormat, ChapterURL, 'chapter-format', 'chapter-url');
ChapterFormat = style_format (ChapterFormat, ChapterURL, 'chapter-format', 'chapter-url');
Line 3,348: Line 3,528:
end
end


if utilities.in_array (config.CitationClass, {'web', 'news', 'journal', 'magazine', 'pressrelease', 'podcast', 'newsgroup', 'arxiv', 'biorxiv', 'citeseerx', 'ssrn'}) or -- if any of the 'periodical' cites except encyclopedia
if utilities.in_array (config.CitationClass, {'web', 'news', 'journal', 'magazine', 'pressrelease', 'podcast', 'newsgroup', 'arxiv', 'biorxiv', 'citeseerx', 'medrxiv', 'ssrn'}) or -- if any of the 'periodical' cites except encyclopedia
('citation' == config.CitationClass and (utilities.is_set (Periodical) or utilities.is_set (ScriptPeriodical)) and not utilities.is_set (Encyclopedia)) then
('citation' == config.CitationClass and (utilities.is_set (Periodical) or utilities.is_set (ScriptPeriodical)) and not utilities.is_set (Encyclopedia)) then
local chap_param;
local chap_param;
Line 3,421: Line 3,601:
end
end


if (not plain_title) and (utilities.in_array (config.CitationClass, {'web', 'news', 'journal', 'magazine', 'pressrelease', 'podcast', 'newsgroup', 'mailinglist', 'interview', 'arxiv', 'biorxiv', 'citeseerx', 'ssrn'}) or
if (not plain_title) and (utilities.in_array (config.CitationClass, {'web', 'news', 'journal', 'magazine', 'document', 'pressrelease', 'podcast', 'newsgroup', 'mailinglist', 'interview', 'arxiv', 'biorxiv', 'citeseerx', 'medrxiv', 'ssrn'}) or
('citation' == config.CitationClass and (utilities.is_set (Periodical) or utilities.is_set (ScriptPeriodical)) and not utilities.is_set (Encyclopedia)) or
('citation' == config.CitationClass and (utilities.is_set (Periodical) or utilities.is_set (ScriptPeriodical)) and not utilities.is_set (Encyclopedia)) or
('map' == config.CitationClass and (utilities.is_set (Periodical) or utilities.is_set (ScriptPeriodical)))) then -- special case for cite map when the map is in a periodical treat as an article
('map' == config.CitationClass and (utilities.is_set (Periodical) or utilities.is_set (ScriptPeriodical)))) then -- special case for cite map when the map is in a periodical treat as an article
Line 3,572: Line 3,752:


Series = utilities.is_set (Series) and wrap_msg ('series', {sepc, Series}) or ""; -- not the same as SeriesNum
Series = utilities.is_set (Series) and wrap_msg ('series', {sepc, Series}) or ""; -- not the same as SeriesNum
local Agency = A['Agency'];
local Agency = A['Agency'] or ''; -- |agency= is supported by {{cite magazine}}, {{cite news}}, {{cite press release}}, {{cite web}}, and certain {{citation}} templates
Agency = utilities.is_set (Agency) and wrap_msg ('agency', {sepc, Agency}) or "";
if utilities.is_set (Agency) then -- this testing done here because {{citation}} supports 'news' citations
if utilities.in_array (config.CitationClass, {'magazine', 'news', 'pressrelease', 'web'}) or ('citation' == config.CitationClass and utilities.in_array (Periodical_origin, {"magazine", "newspaper", "work"})) then
Agency = wrap_msg ('agency', {sepc, Agency}); -- format for rendering
else
Agency = ''; -- unset; not supported
utilities.set_message ('err_parameter_ignored', {'agency'}); -- add error message
end
end
Volume = format_volume_issue (Volume, Issue, ArticleNumber, config.CitationClass, Periodical_origin, sepc, use_lowercase);
Volume = format_volume_issue (Volume, Issue, ArticleNumber, config.CitationClass, Periodical_origin, sepc, use_lowercase);


Line 3,664: Line 3,852:
local Archived;
local Archived;
if utilities.is_set (ArchiveURL) then
if utilities.is_set (ArchiveURL) then
local arch_text;
if not utilities.is_set (ArchiveDate) then -- ArchiveURL set but ArchiveDate not set
if not utilities.is_set (ArchiveDate) then
utilities.set_message ('err_archive_missing_date'); -- emit an error message
utilities.set_message ('err_archive_missing_date');
ArchiveURL = ''; -- empty string for concatenation
ArchiveDate = ''; -- empty string for concatenation
end
else
if utilities.is_set (ArchiveDate) then -- ArchiveURL not set but ArchiveDate is set
utilities.set_message ('err_archive_date_missing_url'); -- emit an error message
ArchiveURL = ''; -- empty string for concatenation
ArchiveDate = ''; -- empty string for concatenation
ArchiveDate = ''; -- empty string for concatenation
end
end
end
if utilities.is_set (ArchiveURL) then
local arch_text;
if "live" == UrlStatus then
if "live" == UrlStatus then
arch_text = cfg.messages['archived'];
arch_text = cfg.messages['archived'];
Line 3,703: Line 3,901:
end
end
else -- OriginalUrl not set
else -- OriginalUrl not set
arch_text = cfg.messages['archived-missing'];
if sepc ~= "." then arch_text = arch_text:lower() end
utilities.set_message ('err_archive_missing_url');
utilities.set_message ('err_archive_missing_url');
Archived = ''; -- empty string for concatenation
Archived = ''; -- empty string for concatenation
Line 3,714: Line 3,910:
end
end
local Lay = '';
local LaySource = A['LaySource'];
local LayURL = A['LayURL'];
local LayFormat = A['LayFormat'];
LayFormat = style_format (LayFormat, LayURL, 'lay-format', 'lay-url');
if utilities.is_set (LayURL) then
if utilities.is_set (LayDate) then LayDate = " (" .. LayDate .. ")" end
if utilities.is_set (LaySource) then
LaySource = " &ndash; ''" .. utilities.safe_for_italics (LaySource) .. "''";
else
LaySource = "";
end
if sepc == '.' then
Lay = sepc .. " " .. external_link( LayURL, cfg.messages['lay summary'], A:ORIGIN('LayURL'), nil ) .. LayFormat .. LaySource .. LayDate
else
Lay = sepc .. " " .. external_link( LayURL, cfg.messages['lay summary']:lower(), A:ORIGIN('LayURL'), nil ) .. LayFormat .. LaySource .. LayDate
end
elseif utilities.is_set (LayFormat) then -- Test if |lay-format= is given without giving a |lay-url=
Lay = sepc .. LayFormat; -- if set and LayURL not set, then LayFormat has error message
end
local TranscriptURL = A['TranscriptURL']
local TranscriptURL = A['TranscriptURL']
local TranscriptFormat = A['TranscriptFormat'];
local TranscriptFormat = A['TranscriptFormat'];
Line 3,765: Line 3,940:
end
end
local TransPeriodical =  A['TransPeriodical'];
local TransPeriodical_origin =  A:ORIGIN ('TransPeriodical');
-- Several of the above rely upon detecting this as nil, so do it last.
-- Several of the above rely upon detecting this as nil, so do it last.
if (utilities.is_set (Periodical) or utilities.is_set (ScriptPeriodical) or utilities.is_set (TransPeriodical)) then
if (utilities.is_set (Periodical) or utilities.is_set (ScriptPeriodical) or utilities.is_set (TransPeriodical)) then
Line 3,808: Line 3,981:
local tcommon2; -- used for book cite when |contributor= is set
local tcommon2; -- used for book cite when |contributor= is set
if utilities.in_array (config.CitationClass, {"journal", "citation"}) and utilities.is_set (Periodical) then
if utilities.in_array (config.CitationClass, {"book", "citation"}) and not utilities.is_set (Periodical) then -- special cases for book cites
if not (utilities.is_set (Authors) or utilities.is_set (Editors)) then
Others = Others:gsub ('^' .. sepc .. ' ', ''); -- when no authors and no editors, strip leading sepc and space
end
if utilities.is_set (Others) then Others = safe_join ({Others, sepc .. " "}, sepc) end -- add terminal punctuation & space; check for dup sepc; TODO why do we need to do this here?
tcommon = safe_join( {Others, Title, TitleNote, Conference, Periodical, Format, TitleType, Series, Language, Edition, Publisher, Agency, Volume}, sepc );
elseif utilities.in_array (config.CitationClass, {"book", "citation"}) and not utilities.is_set (Periodical) then -- special cases for book cites
if utilities.is_set (Contributors) then -- when we are citing foreword, preface, introduction, etc.
if utilities.is_set (Contributors) then -- when we are citing foreword, preface, introduction, etc.
tcommon = safe_join( {Title, TitleNote}, sepc ); -- author and other stuff will come after this and before tcommon2
tcommon = safe_join ({Title, TitleNote}, sepc); -- author and other stuff will come after this and before tcommon2
tcommon2 = safe_join( {Conference, Periodical, Format, TitleType, Series, Language, Volume, Others, Edition, Publisher, Agency}, sepc );
tcommon2 = safe_join ({TitleType, Series, Language, Volume, Others, Edition, Publisher}, sepc);
else
else
tcommon = safe_join( {Title, TitleNote, Conference, Periodical, Format, TitleType, Series, Language, Volume, Others, Edition, Publisher, Agency}, sepc );
tcommon = safe_join ({Title, TitleNote, TitleType, Series, Language, Volume, Others, Edition, Publisher}, sepc);
end
end


elseif 'map' == config.CitationClass then -- special cases for cite map
elseif 'map' == config.CitationClass then -- special cases for cite map
if utilities.is_set (Chapter) then -- map in a book; TitleType is part of Chapter
if utilities.is_set (Chapter) then -- map in a book; TitleType is part of Chapter
tcommon = safe_join( {Title, Format, Edition, Scale, Series, Language, Cartography, Others, Publisher, Volume}, sepc );
tcommon = safe_join ({Title, Edition, Scale, Series, Language, Cartography, Others, Publisher, Volume}, sepc);
elseif utilities.is_set (Periodical) then -- map in a periodical
elseif utilities.is_set (Periodical) then -- map in a periodical
tcommon = safe_join( {Title, TitleType, Format, Periodical, Scale, Series, Language, Cartography, Others, Publisher, Volume}, sepc );
tcommon = safe_join ({Title, TitleType, Periodical, Scale, Series, Language, Cartography, Others, Publisher, Volume}, sepc);
else -- a sheet or stand-alone map
else -- a sheet or stand-alone map
tcommon = safe_join( {Title, TitleType, Format, Edition, Scale, Series, Language, Cartography, Others, Publisher}, sepc );
tcommon = safe_join ({Title, TitleType, Edition, Scale, Series, Language, Cartography, Others, Publisher}, sepc);
end
end
elseif 'episode' == config.CitationClass then -- special case for cite episode
elseif 'episode' == config.CitationClass then -- special case for cite episode
tcommon = safe_join( {Title, TitleNote, TitleType, Series, Language, Edition, Publisher}, sepc );
tcommon = safe_join ({Title, TitleNote, TitleType, Series, 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, TitleType, Series, Language, Volume, Others, Edition, Publisher, Agency}, sepc);
Volume, Others, Edition, Publisher, Agency}, sepc );
end
end
Line 3,849: Line 4,015:
local idcommon;
local idcommon;
if 'audio-visual' == config.CitationClass or 'episode' == config.CitationClass then -- special case for cite AV media & cite episode position transcript
if 'audio-visual' == config.CitationClass or 'episode' == config.CitationClass then -- special case for cite AV media & cite episode position transcript
idcommon = safe_join( { ID_list, URL, Archived, Transcript, AccessDate, Via, Lay, Quote }, sepc );
idcommon = safe_join( { ID_list, URL, Archived, Transcript, AccessDate, Via, Quote }, sepc );
else
else
idcommon = safe_join( { ID_list, URL, Archived, AccessDate, Via, Lay, Quote }, sepc );
idcommon = safe_join( { ID_list, URL, Archived, AccessDate, Via, Quote }, sepc );
end
end
Line 3,875: Line 4,041:
end
end
if utilities.is_set (Editors) then
if utilities.is_set (Editors) then
local in_text = " ";
local in_text = '';
local post_text = "";
local post_text = '';
if utilities.is_set (Chapter) and 0 == #c then
if utilities.is_set (Chapter) and 0 == #c then
in_text = in_text .. cfg.messages['in'] .. " "
in_text = cfg.messages['in'] .. ' ';
if (sepc ~= '.') then
if (sepc ~= '.') then
in_text = in_text:lower() -- lowercase for cs2
in_text = in_text:lower(); -- lowercase for cs2
end
end
end
end
if EditorCount <= 1 then
if EditorCount <= 1 then
post_text = " (" .. cfg.messages['editor'] .. ")"; -- be consistent with no-author, no-date case
post_text = ' (' .. cfg.messages['editor'] .. ')'; -- be consistent with no-author, no-date case
else
else
post_text = " (" .. cfg.messages['editors'] .. ")";
post_text = ' (' .. cfg.messages['editors'] .. ')';
end
end
Editors = terminate_name_list (in_text .. Editors .. post_text, sepc); -- terminate with 0 or 1 sepc and a space
Editors = terminate_name_list (in_text .. Editors .. post_text, sepc); -- terminate with 0 or 1 sepc and a space
Line 3,926: Line 4,092:
end
end
end
end
 
if utilities.is_set (PostScript) and PostScript ~= sepc then
if utilities.is_set (PostScript) and PostScript ~= sepc then
text = safe_join( {text, sepc}, sepc ); -- Deals with italics, spaces, etc.
text = safe_join( {text, sepc}, sepc ); -- Deals with italics, spaces, etc.
text = text:sub(1, -sepc:len() - 1);
if '.' == sepc then -- remove final seperator if present
text = text:gsub ('%' .. sepc .. '$', ''); -- dot must be escaped here
else
text = mw.ustring.gsub (text, sepc .. '$', ''); -- using ustring for non-dot sepc (likely a non-Latin character)
end
end
end
Line 4,025: Line 4,195:


if not no_tracking_cats then
if not no_tracking_cats then
local sort_key;
local cat_wikilink = 'cat wikilink';
if cfg.enable_sort_keys then -- when namespace sort keys enabled
local namespace_number = mw.title.getCurrentTitle().namespace; -- get namespace number for this wikitext
sort_key = (0 ~= namespace_number and (cfg.name_space_sort_keys[namespace_number] or cfg.name_space_sort_keys.other)) or nil; -- get sort key character; nil for mainspace
cat_wikilink = (not sort_key and 'cat wikilink') or 'cat wikilink sk'; -- make <cfg.messages> key
end
for _, v in ipairs (z.error_cats_t) do -- append error categories
for _, v in ipairs (z.error_cats_t) do -- append error categories
table.insert (render_t, utilities.substitute (cfg.messages['cat wikilink'], v));
table.insert (render_t, utilities.substitute (cfg.messages[cat_wikilink], {v, sort_key}));
end
end
for _, v in ipairs (z.maint_cats_t) do -- append maintenance categories
for _, v in ipairs (z.maint_cats_t) do -- append maintenance categories
table.insert (render_t, utilities.substitute (cfg.messages['cat wikilink'], v));
table.insert (render_t, utilities.substitute (cfg.messages[cat_wikilink], {v, sort_key}));
end
end
for _, v in ipairs (z.prop_cats_t) do -- append properties categories
for _, v in ipairs (z.prop_cats_t) do -- append properties categories
table.insert (render_t, utilities.substitute (cfg.messages['cat wikilink'], v));
table.insert (render_t, utilities.substitute (cfg.messages['cat wikilink'], v)); -- no sort keys
end
end
end
end
Line 4,053: Line 4,232:
local function validate (name, cite_class, empty)
local function validate (name, cite_class, empty)
local name = tostring (name);
local name = tostring (name);
local enum_name; -- for enumerated parameters, is name with enumerator replaced with '#'
local enum_name; -- parameter name with enumerator (if any) replaced with '#'
local state;
local state;
local function state_test (state, name) -- local function to do testing of state values
local function state_test (state, name) -- local function to do testing of state values
Line 4,073: Line 4,252:
return nil;
return nil;
end
end
-- replace enumerator digit(s) with # (|last25= becomes |last#=) (mw.ustring because non-Western 'local' digits)
enum_name = mw.ustring.gsub (name, '%d+$', '#'); -- where enumerator is last charaters in parameter name (these to protect |s2cid=)
enum_name = mw.ustring.gsub (enum_name, '%d+([%-l])', '#%1'); -- where enumerator is in the middle of the parameter name; |author#link= is the oddity


if utilities.in_array (cite_class, whitelist.preprint_template_list ) then -- limited parameter sets allowed for these templates
if 'document' == cite_class then -- special case for {{cite document}}
state = whitelist.limited_basic_arguments[name];
state = whitelist.document_parameters_t[enum_name]; -- this list holds enumerated and nonenumerated parameters
if true == state_test (state, name) then return true; end
if true == state_test (state, name) then return true; end
return false;
end


state = whitelist.preprint_arguments[cite_class][name]; -- look in the parameter-list for the template identified by cite_class
if utilities.in_array (cite_class, whitelist.preprint_template_list_t) then -- limited parameter sets allowed for these templates
state = whitelist.limited_parameters_t[enum_name]; -- this list holds enumerated and nonenumerated parameters
if true == state_test (state, name) then return true; end
if true == state_test (state, name) then return true; end


-- limited enumerated parameters list
state = whitelist.preprint_arguments_t[cite_class][name]; -- look in the parameter-list for the template identified by cite_class
enum_name = name:gsub("%d+", "#" ); -- replace digit(s) with # (last25 becomes last#) (mw.ustring because non-Western 'local' digits)
state = whitelist.limited_numbered_arguments[enum_name];
if true == state_test (state, name) then return true; end
if true == state_test (state, name) then return true; end


Line 4,089: Line 4,273:
end -- end limited parameter-set templates
end -- end limited parameter-set templates


if utilities.in_array (cite_class, whitelist.unique_param_template_list) then -- experiment for template-specific parameters for templates that accept parameters from the basic argument list
if utilities.in_array (cite_class, whitelist.unique_param_template_list_t) then -- template-specific parameters for templates that accept parameters from the basic argument list
state = whitelist.unique_arguments[cite_class][name]; -- look in the template-specific parameter-lists for the template identified by cite_class
state = whitelist.unique_arguments_t[cite_class][name]; -- look in the template-specific parameter-lists for the template identified by cite_class
if true == state_test (state, name) then return true; end
if true == state_test (state, name) then return true; end
end -- if here, fall into general validation
end -- if here, fall into general validation
state = whitelist.basic_arguments[name]; -- all other templates; all normal parameters allowed
if true == state_test (state, name) then return true; end


-- all enumerated parameters allowed
state = whitelist.common_parameters_t[enum_name]; -- all other templates; all normal parameters allowed; this list holds enumerated and nonenumerated parameters
enum_name = name:gsub("%d+", "#" ); -- replace digit(s) with # (last25 becomes last#) (mw.ustring because non-Western 'local' digits)
state = whitelist.numbered_arguments[enum_name];
if true == state_test (state, name) then return true; end
if true == state_test (state, name) then return true; end