Module:Citation/CS1: Difference between revisions
sync from sandbox;
(sync from sandbox;) |
(sync from sandbox;) |
||
Line 3: | Line 3: | ||
--[[--------------------------< 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 >-------------------------------------- | ||
each of these counts against the Lua upvalue limit | each of these counts against the Lua upvalue limit | ||
]] | ]] | ||
Line 18: | Line 16: | ||
local whitelist = {}; -- table of tables listing valid template parameter names; defined in Module:Citation/CS1/Whitelist | local whitelist = {}; -- table of tables listing valid template parameter names; defined in Module:Citation/CS1/Whitelist | ||
--[[------------------< P A G E S C O P E V A R I A B L E S >--------------- | |||
--[[ | declare variables here that have page-wide scope that are not brought in from | ||
other modules; that are created here and used here | |||
declare variables here that have page-wide scope that are not brought in from other modules; that are created here and used here | |||
]] | ]] | ||
local added_deprecated_cat; -- Boolean flag so that the category is added only once | local added_deprecated_cat; -- Boolean flag so that the category is added only once | ||
local added_discouraged_cat; -- Boolean flag so that the category is added only once | |||
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 Frame; -- holds the module's frame table | local Frame; -- holds the module's frame table | ||
--[[--------------------------< F I R S T _ S E T >------------------------------------------------------------ | --[[--------------------------< F I R S T _ S E T >------------------------------------------------------------ | ||
Line 62: | Line 56: | ||
]] | ]] | ||
local function add_vanc_error (source) | local function add_vanc_error (source, position) | ||
if | if added_vanc_errs then return end | ||
added_vanc_errs = true; | |||
added_vanc_errs = true; -- note that we've added this category | |||
table.insert( z.message_tail, { utilities.set_message ( 'err_vancouver', {source, position}, true ) } ); | |||
end | end | ||
Line 415: | Line 409: | ||
domain, path = URL:match ('^([/%.%-%+:%a%d]+)([/%?#].*)$'); -- split the URL into scheme plus domain and path | domain, path = URL:match ('^([/%.%-%+:%a%d]+)([/%?#].*)$'); -- split the URL into scheme plus domain and path | ||
if path then -- if there is a path portion | if path then -- if there is a path portion | ||
path = path:gsub ('[%[%]]', {['['] = '%5b', [']'] = '%5d'}); | path = path:gsub ('[%[%]]', {['['] = '%5b', [']'] = '%5d'}); -- replace '[' and ']' with their percent-encoded values | ||
URL = table.concat ({domain, path}); -- and reassemble | URL = table.concat ({domain, path}); -- and reassemble | ||
end | end | ||
Line 443: | Line 437: | ||
added_deprecated_cat = true; -- note that we've added this category | added_deprecated_cat = true; -- note that we've added this category | ||
table.insert( z.message_tail, { utilities.set_message ( 'err_deprecated_params', {name}, true ) } ); -- add error message | table.insert( z.message_tail, { utilities.set_message ( 'err_deprecated_params', {name}, true ) } ); -- add error message | ||
end | |||
end | |||
--[[--------------------------< D I S C O U R A G E D _ P A R A M E T E R >------------------------------------ | |||
Categorize and emit an maintenance message when the citation contains one or more discouraged parameters. Only | |||
one error message is emitted regardless of the number of discouraged parameters in the citation. | |||
added_discouraged_cat is a Boolean declared in page scope variables above | |||
]] | |||
local function discouraged_parameter(name) | |||
if not added_discouraged_cat then | |||
added_discouraged_cat = true; -- note that we've added this category | |||
table.insert( z.message_tail, { utilities.set_message ( 'maint_discouraged', {name}, true ) } ); -- add maint message | |||
end | end | ||
end | end | ||
Line 539: | Line 550: | ||
-- 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_code_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 | 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 | ||
-- is prefix one of these language codes? | -- is prefix one of these language codes? | ||
Line 755: | Line 766: | ||
local function has_invisible_chars (param, v) | local function has_invisible_chars (param, v) | ||
local position = ''; -- position of invisible char or starting position of stripmarker | local position = ''; -- position of invisible char or starting position of stripmarker | ||
local capture; -- used by stripmarker detection to hold name of the stripmarker | local capture; -- used by stripmarker detection to hold name of the stripmarker | ||
local | local stripmarker; -- boolean set true when a stripmarker is found | ||
capture = string.match (v, '[%w%p ]*'); -- test for values that are simple ASCII text and bypass other tests if true | capture = string.match (v, '[%w%p ]*'); -- test for values that are simple ASCII text and bypass other tests if true | ||
if capture == v then -- if same there are no Unicode characters | if capture == v then -- if same there are no Unicode characters | ||
Line 765: | Line 774: | ||
end | end | ||
for _, invisible_char in ipairs (cfg.invisible_chars) do | |||
local | local char_name = invisible_char[1]; -- the character or group name | ||
local pattern = | local pattern = invisible_char[2]; -- the pattern used to find it | ||
position, | position, _, capture = mw.ustring.find (v, pattern); -- see if the parameter value contains characters that match the pattern | ||
if position and ( | if position and (cfg.invisible_defs.zwj == capture) then -- if we found a zero-width joiner character | ||
if mw.ustring.find (v, cfg.indic_script) then -- it's ok if one of the Indic scripts | if mw.ustring.find (v, cfg.indic_script) then -- it's ok if one of the Indic scripts | ||
position = nil; -- unset position | |||
elseif cfg.emoji[mw.ustring.codepoint (v, position+1)] then -- is zwj followed by a character listed in emoji{}? | |||
position = nil; -- unset position | position = nil; -- unset position | ||
end | end | ||
Line 780: | Line 791: | ||
('templatestyles' == capture and utilities.in_array (param, {'id', 'quote'})) then -- templatestyles stripmarker allowed in these parameters | ('templatestyles' == capture and utilities.in_array (param, {'id', 'quote'})) then -- templatestyles stripmarker allowed in these parameters | ||
stripmarker = true; -- set a flag | stripmarker = true; -- set a flag | ||
elseif true == stripmarker and | elseif true == stripmarker and cfg.invisible_defs.del == capture then -- because stripmakers begin and end with the delete char, assume that we've found one end of a stripmarker | ||
position = nil; -- unset | position = nil; -- unset | ||
else | else | ||
local err_msg; | local err_msg; | ||
if capture then | if capture and not (cfg.invisible_defs.del == capture or cfg.invisible_defs.zwj == capture) then | ||
err_msg = capture .. ' ' .. | err_msg = capture .. ' ' .. char_name; | ||
else | else | ||
err_msg = | err_msg = char_name .. ' ' .. 'character'; | ||
end | end | ||
table.insert( z.message_tail, { utilities.set_message ( 'err_invisible_char', {err_msg, utilities.wrap_style ('parameter', param), position}, true ) } ); -- add error message | table.insert (z.message_tail, {utilities.set_message ('err_invisible_char', {err_msg, utilities.wrap_style ('parameter', param), position}, true)}); -- add error message | ||
return; -- and done with this parameter | return; -- and done with this parameter | ||
end | end | ||
end | end | ||
end | end | ||
end | end | ||
Line 812: | Line 822: | ||
return setmetatable({ | return setmetatable({ | ||
ORIGIN = function ( self, k ) | ORIGIN = function ( self, k ) | ||
local dummy = self[k]; -- force the variable to be loaded. | local dummy = self[k]; -- force the variable to be loaded. | ||
return origin[k]; | return origin[k]; | ||
end | end | ||
Line 827: | Line 837: | ||
v, origin[k] = utilities.select_one ( args, list, 'err_redundant_parameters' ); | v, origin[k] = utilities.select_one ( args, list, 'err_redundant_parameters' ); | ||
if origin[k] == nil then | if origin[k] == nil then | ||
origin[k] = ''; -- Empty string, not nil | origin[k] = ''; -- Empty string, not nil | ||
end | end | ||
elseif list ~= nil then | elseif list ~= nil then | ||
Line 924: | Line 934: | ||
str = str:gsub ('&[nm]dash;', {['–'] = '–', ['—'] = '—'}); -- replace — and – entities with their characters; semicolon mucks up the text.split | str = str:gsub ('&[nm]dash;', {['–'] = '–', ['—'] = '—'}); -- replace — and – entities with their characters; semicolon mucks up the text.split | ||
str = str:gsub ('-', '-'); -- replace HTML numeric entity with hyphen character | str = str:gsub ('-', '-'); -- replace HTML numeric entity with hyphen character | ||
str = str:gsub (' ', ' '); -- replace entity with generic keyboard space character | str = str:gsub (' ', ' '); -- replace entity with generic keyboard space character | ||
Line 933: | Line 941: | ||
for _, item in ipairs (list) do -- for each item in the list | for _, item in ipairs (list) do -- for each item in the list | ||
item, accept = utilities.has_accept_as_written (item); -- remove accept-this-as-written markup when it wraps all of item | item, accept = utilities.has_accept_as_written (item); -- remove accept-this-as-written markup when it wraps all of item | ||
if not accept and mw.ustring.match (item, '^%w*[%.%-]?%w+%s*[%-–—]%s*%w*[%.%-]?%w+$') then -- if a hyphenated range or has endash or emdash separators | if not accept and mw.ustring.match (item, '^%w*[%.%-]?%w+%s*[%-–—]%s*%w*[%.%-]?%w+$') then -- if a hyphenated range or has endash or emdash separators | ||
if item:match ('^%a+[%.%-]?%d+%s*%-%s*%a+[%.%-]?%d+$') or -- letterdigit hyphen letterdigit (optional separator between letter and digit) | if item:match ('^%a+[%.%-]?%d+%s*%-%s*%a+[%.%-]?%d+$') or -- letterdigit hyphen letterdigit (optional separator between letter and digit) | ||
Line 951: | Line 959: | ||
temp_str, accept = utilities.has_accept_as_written (table.concat (out, ', ')); -- remove accept-this-as-written markup when it wraps all of concatenated out | temp_str, accept = utilities.has_accept_as_written (table.concat (out, ', ')); -- remove accept-this-as-written markup when it wraps all of concatenated out | ||
if accept then | if accept then | ||
return utilities.has_accept_as_written (str); -- when global markup removed, return original str | return utilities.has_accept_as_written (str); -- when global markup removed, return original str | ||
else | else | ||
return temp_str; -- else, return assembled temp_str | return temp_str; -- else, return assembled temp_str | ||
Line 996: | Line 1,004: | ||
trim = false; | trim = false; | ||
end_chr = f.sub(str, -1, -1); -- get the last character of the output string | end_chr = f.sub(str, -1, -1); -- get the last character of the output string | ||
-- str = str .. "<HERE(enchr=" .. end_chr .. ")" | -- str = str .. "<HERE(enchr=" .. end_chr .. ")" -- debug stuff? | ||
if end_chr == duplicate_char then -- if same as separator | if end_chr == duplicate_char then -- if same as separator | ||
str = f.sub(str, 1, -2); | str = f.sub(str, 1, -2); -- remove it | ||
elseif end_chr == "'" then -- if it might be wiki-markup | elseif end_chr == "'" then -- if it might be wiki-markup | ||
if f.sub(str, -3, -1) == duplicate_char .. "''" then | if f.sub(str, -3, -1) == duplicate_char .. "''" then -- if last three chars of str are sepc'' | ||
str = f.sub(str, 1, -4) .. "''"; -- remove them and add back '' | str = f.sub(str, 1, -4) .. "''"; -- remove them and add back '' | ||
elseif f.sub(str, -5, -1) == duplicate_char .. "]]''" then -- if last five chars of str are sepc]]'' | elseif f.sub(str, -5, -1) == duplicate_char .. "]]''" then -- if last five chars of str are sepc]]'' | ||
Line 1,008: | Line 1,016: | ||
end | end | ||
elseif end_chr == "]" then -- if it might be wiki-markup | elseif end_chr == "]" then -- if it might be wiki-markup | ||
if f.sub(str, -3, -1) == duplicate_char .. "]]" then | if f.sub(str, -3, -1) == duplicate_char .. "]]" then -- if last three chars of str are sepc]] wikilink | ||
trim = true; | trim = true; | ||
elseif f.sub(str, -3, -1) == duplicate_char .. '"]' then | elseif f.sub(str, -3, -1) == duplicate_char .. '"]' then -- if last three chars of str are sepc"] quoted external link | ||
trim = true; | trim = true; | ||
elseif f.sub(str, -2, -1) == duplicate_char .. "]" then | elseif f.sub(str, -2, -1) == duplicate_char .. "]" then -- if last two chars of str are sepc] external link | ||
trim = true; | trim = true; | ||
elseif f.sub(str, -4, -1) == duplicate_char .. "'']" then -- normal case when |url=something & |title=Title. | elseif f.sub(str, -4, -1) == duplicate_char .. "'']" then -- normal case when |url=something & |title=Title. | ||
Line 1,019: | Line 1,027: | ||
elseif end_chr == " " then -- if last char of output string is a space | elseif end_chr == " " then -- if last char of output string is a space | ||
if f.sub(str, -2, -1) == duplicate_char .. " " then -- if last two chars of str are <sepc><space> | if f.sub(str, -2, -1) == duplicate_char .. " " then -- if last two chars of str are <sepc><space> | ||
str = f.sub(str, 1, -3); | str = f.sub(str, 1, -3); -- remove them both | ||
end | end | ||
end | end | ||
Line 1,034: | Line 1,042: | ||
end | end | ||
end | end | ||
str = str .. value; | str = str .. value; -- add it to the output string | ||
end | end | ||
end | end | ||
Line 1,059: | Line 1,067: | ||
For Vancouver style, author/editor names are supposed to be rendered in Latin | For Vancouver style, author/editor names are supposed to be rendered in Latin | ||
(read ASCII) characters. When a name uses characters that contain diacritical marks, | (read ASCII) characters. When a name uses characters that contain diacritical | ||
those characters are to converted to the corresponding Latin character. When a name | marks, those characters are to be converted to the corresponding Latin | ||
is written using a non-Latin alphabet or logogram, that name is to be transliterated | character. When a name is written using a non-Latin alphabet or logogram, that | ||
into Latin characters. The module doesn't do this so editors may/must. | name is to be transliterated into Latin characters. The module doesn't do this | ||
so editors may/must. | |||
This test allows |first= and |last= names to contain any of the letters defined | This test allows |first= and |last= names to contain any of the letters defined | ||
Line 1,091: | Line 1,100: | ||
]] | ]] | ||
local function is_good_vanc_name (last, first, suffix) | local function is_good_vanc_name (last, first, suffix, position) | ||
if not suffix then | if not suffix then | ||
if first:find ('[,%s]') then -- when there is a space or comma, might be first name/initials + generational suffix | if first:find ('[,%s]') then -- when there is a space or comma, might be first name/initials + generational suffix | ||
Line 1,100: | Line 1,109: | ||
if utilities.is_set (suffix) then | if utilities.is_set (suffix) then | ||
if not is_suffix (suffix) then | if not is_suffix (suffix) then | ||
add_vanc_error (cfg.err_msg_supl.suffix); | add_vanc_error (cfg.err_msg_supl.suffix, position); | ||
return false; -- not a name with an appropriate suffix | return false; -- not a name with an appropriate suffix | ||
end | end | ||
Line 1,106: | Line 1,115: | ||
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%-%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%-%s%'%.]*$") then | ||
add_vanc_error (cfg.err_msg_supl['non-Latin char']); | 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 | ||
end; | end; | ||
Line 1,130: | Line 1,139: | ||
]] | ]] | ||
local function reduce_to_initials(first) | local function reduce_to_initials(first, position) | ||
local name, suffix = mw.ustring.match(first, "^(%u+) ([%dJS][%drndth]+)$"); | local name, suffix = mw.ustring.match(first, "^(%u+) ([%dJS][%drndth]+)$"); | ||
Line 1,143: | Line 1,152: | ||
return first; -- one or two initials and a valid suffix so nothing to do | return first; -- one or two initials and a valid suffix so nothing to do | ||
else | else | ||
add_vanc_error (cfg.err_msg_supl.suffix); | add_vanc_error (cfg.err_msg_supl.suffix, position); -- one or two initials with invalid suffix so error message | ||
return first; -- and return first unmolested | return first; -- and return first unmolested | ||
end | end | ||
Line 1,166: | Line 1,175: | ||
end | end | ||
if 3 > i then | if 3 > i then | ||
table.insert (initials, mw.ustring.sub(names[i], 1, 1)); | table.insert (initials, mw.ustring.sub(names[i], 1, 1)); -- insert the initial at end of initials table | ||
end | end | ||
i = i + 1; -- bump the counter | i = i + 1; -- bump the counter | ||
Line 1,232: | Line 1,241: | ||
if ("vanc" == format) then -- if Vancouver format | if ("vanc" == format) then -- if Vancouver format | ||
one = one:gsub ('%.', ''); -- remove periods from surnames (http://www.ncbi.nlm.nih.gov/books/NBK7271/box/A35029/) | one = one:gsub ('%.', ''); -- remove periods from surnames (http://www.ncbi.nlm.nih.gov/books/NBK7271/box/A35029/) | ||
if not person.corporate and is_good_vanc_name (one, first) then -- and name is all Latin characters; corporate authors not tested | if not person.corporate and is_good_vanc_name (one, first, nil, i) then -- and name is all Latin characters; corporate authors not tested | ||
first = reduce_to_initials (first); | first = reduce_to_initials (first, i); -- attempt to convert first name(s) to initials | ||
end | end | ||
end | end | ||
Line 1,273: | Line 1,282: | ||
end | end | ||
--[[--------------------< M A K E _ C I T E R E F _ I D >----------------------- | |||
--[[ | |||
Generates a CITEREF anchor ID if we have at least one name or a date. Otherwise | Generates a CITEREF anchor ID if we have at least one name or a date. Otherwise | ||
Line 1,284: | Line 1,292: | ||
]] | ]] | ||
local function | local function make_citeref_id (namelist, year) | ||
local names={}; | local names={}; -- a table for the one to four names and year | ||
for i,v in ipairs (namelist) do | for i,v in ipairs (namelist) do -- loop through the list and take up to the first four last names | ||
names[i] = v.last | names[i] = v.last | ||
if i == 4 then break end | if i == 4 then break end -- if four then done | ||
end | end | ||
table.insert (names, year); | table.insert (names, year); -- add the year at the end | ||
local id = table.concat(names); | local id = table.concat(names); -- concatenate names and year for CITEREF id | ||
if utilities.is_set (id) then | if utilities.is_set (id) then -- if concatenation is not an empty string | ||
return "CITEREF" .. id; | return "CITEREF" .. id; -- add the CITEREF portion | ||
else | else | ||
return ''; | return ''; -- return an empty string; no reason to include CITEREF id in this citation | ||
end | end | ||
end | end | ||
Line 1,432: | Line 1,440: | ||
first, accept_name = utilities.has_accept_as_written (first); -- remove accept-this-as-written markup when it wraps all of <first> | first, accept_name = utilities.has_accept_as_written (first); -- remove accept-this-as-written markup when it wraps all of <first> | ||
if not accept_name then | if not accept_name then -- <first> not wrapped in accept-as-written markup | ||
name_has_ed_markup (first, list_name); -- check for extraneous 'editor' annotation | name_has_ed_markup (first, list_name); -- check for extraneous 'editor' annotation | ||
name_is_numeric (first, list_name); -- check for names that are composed of digits and punctuation | name_is_numeric (first, list_name); -- check for names that are composed of digits and punctuation | ||
Line 1,517: | Line 1,525: | ||
--[[ | --[[---------------------< G E T _ I S O 6 3 9 _ C O D E >---------------------- | ||
Validates language names provided in |language= parameter if not an ISO639-1 or 639-2 code. | Validates language names provided in |language= parameter if not an ISO639-1 or 639-2 code. | ||
Line 1,655: | Line 1,663: | ||
end | end | ||
--[[-----------------------< S E T _ C S _ S T Y L E >-------------------------- | |||
--[[----------------------< S E T _ C S | Gets the default CS style configuration for the given mode. | ||
Returns default separator and either postscript as passed in or the default. | |||
In CS1, the default postscript and separator are '.'. | |||
In CS2, the default postscript is the empty string and the default separator is ','. | |||
]] | ]] | ||
local function set_cs_style (postscript, mode) | |||
local function | if utilities.is_set(postscript) then | ||
if | -- emit a maintenance message if user postscript is the default cs1 postscript | ||
-- we catch the opposite case for cs2 in set_style | |||
if mode == 'cs1' and postscript == cfg.presentation['ps_' .. mode] then | |||
utilities.set_message ('maint_postscript'); | |||
end | |||
else | |||
postscript = cfg.presentation['ps_' .. mode]; | |||
end | end | ||
return cfg.presentation[' | return cfg.presentation['sep_' .. mode], postscript; | ||
end | end | ||
--[[--------------------------< S E T _ S T Y L E >----------------------------- | |||
--[[-----------------------< S E T | Sets the separator and postscript styles. Checks the |mode= first and the | ||
#invoke CitationClass second. Removes the postscript if postscript == none. | |||
]] | ]] | ||
local function set_style (mode, postscript, cite_class) | |||
local sep; | |||
if 'cs2' == mode then | |||
sep, postscript = set_cs_style (postscript, 'cs2'); | |||
elseif 'cs1' == mode then | |||
sep, postscript = set_cs_style (postscript, 'cs1'); | |||
elseif 'citation' == cite_class then | |||
sep, postscript = set_cs_style (postscript, 'cs2'); | |||
else | |||
sep, postscript = set_cs_style (postscript, 'cs1'); | |||
end | |||
if cfg.keywords_xlate[postscript:lower()] == 'none' then | |||
if | -- emit a maintenance message if user postscript is the default cs2 postscript | ||
-- we catch the opposite case for cs1 in set_cs_style | |||
if 'cs2' == mode or 'citation' == cite_class then | |||
utilities.set_message ('maint_postscript'); | |||
end | |||
postscript = ''; | |||
end | end | ||
return sep, postscript | |||
return | |||
end | end | ||
--[=[-------------------------< I S _ P D F >----------------------------------- | |||
Determines if a URL has the file extension that is one of the PDF file extensions | |||
Determines if a URL has the file extension that is one of the PDF file extensions | |||
used by [[MediaWiki:Common.css]] when applying the PDF icon to external links. | used by [[MediaWiki:Common.css]] when applying the PDF icon to external links. | ||
Line 1,801: | Line 1,774: | ||
]] | ]] | ||
local function get_display_names (max, count, list_name, etal) | local function get_display_names (max, count, list_name, etal, param) | ||
if utilities.is_set (max) then | if utilities.is_set (max) then | ||
if 'etal' == max:lower():gsub("[ '%.]", '') then -- the :gsub() portion makes 'etal' from a variety of 'et al.' spellings and stylings | if 'etal' == max:lower():gsub("[ '%.]", '') then -- the :gsub() portion makes 'etal' from a variety of 'et al.' spellings and stylings | ||
Line 1,809: | Line 1,782: | ||
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 then -- if |display-xxxxors= value greater than or equal to number of authors/editors | ||
table.insert( z.message_tail, {utilities.set_message ('err_disp_name', { | table.insert( z.message_tail, {utilities.set_message ('err_disp_name', {param, max}, true)}); -- add error message | ||
max = nil; | max = nil; | ||
end | end | ||
else -- not a valid keyword or number | else -- not a valid keyword or number | ||
table.insert( z.message_tail, {utilities.set_message ('err_disp_name', { | table.insert( z.message_tail, {utilities.set_message ('err_disp_name', {param, max}, true)}); -- 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,834: | Line 1,807: | ||
]] | ]] | ||
local function extra_text_in_page_check ( | local function extra_text_in_page_check (val, name) | ||
if not val:match (cfg.vol_iss_pg_patterns.good_ppattern) then | |||
for _, pattern in ipairs (cfg.vol_iss_pg_patterns.bad_ppatterns) do -- spin through the selected sequence table of patterns | |||
if val:match (pattern) then -- when a match, error so | |||
table.insert (z.message_tail, {utilities.set_message ('err_extra_text_pages', {name}, true)}); -- add error message | |||
return; -- and done | |||
end | end | ||
end | |||
end | |||
end | end | ||
--[ | --[[--------------------------< 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. | |||
For |volume=: | |||
'V.', or 'Vol.' (with or without the dot) abbreviations or 'Volume' in the first characters of the parameter | |||
content (all case insensitive). 'V' and 'v' (without the dot) are presumed to be roman numerals so | |||
are allowed. | |||
For |issue=: | |||
'No.', 'I.', 'Iss.' (with or without the dot) abbreviations, or 'Issue' in the first characters of the | |||
parameter content (all case insensitive). | |||
local i = 1; | Single character values ('v', 'i', 'n') allowed when not followed by separator character ('.', ':', '=', or | ||
whitespace character) – param values are trimmed of whitespace by MediaWiki before delivered to the module. | |||
<val> is |volume= or |issue= parameter value | |||
<name> is |volume= or |issue= parameter name for error message | |||
<selector> is 'v' for |volume=, 'i' for |issue= | |||
sets error message on failure; returns nothing | |||
]] | |||
local function extra_text_in_vol_iss_check (val, name, selector) | |||
if not utilities.is_set (val) then | |||
return; | |||
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'; | |||
val = val:lower(); -- force parameter value to lower case | |||
for _, pattern in ipairs (patterns) do -- spin through the selected sequence table of patterns | |||
if val:match (pattern) then -- when a match, error so | |||
table.insert (z.message_tail, {utilities.set_message (handler, {name}, true)}); -- add error message | |||
return; -- and done | |||
end | |||
end | |||
end | |||
--[=[-------------------------< G E T _ V _ N A M E _ T A B L E >---------------------------------------------- | |||
split apart a |vauthors= or |veditors= parameter. This function allows for corporate names, wrapped in doubled | |||
parentheses to also have commas; in the old version of the code, the doubled parentheses were included in the | |||
rendered citation and in the metadata. Individual author names may be wikilinked | |||
|vauthors=Jones AB, [[E. B. White|White EB]], ((Black, Brown, and Co.)) | |||
]=] | |||
local function get_v_name_table (vparam, output_table, output_link_table) | |||
local name_table = mw.text.split(vparam, "%s*,%s*"); -- names are separated by commas | |||
local wl_type, label, link; -- wl_type not used here; just a placeholder | |||
local i = 1; | |||
while name_table[i] do | while name_table[i] do | ||
if name_table[i]:match ('^%(%(.*[^%)][^%)]$') then -- first segment of corporate with one or more commas; this segment has the opening doubled parentheses | if name_table[i]:match ('^%(%(.*[^%)][^%)]$') then -- first segment of corporate with one or more commas; this segment has the opening doubled parentheses | ||
local name = name_table[i]; | local name = name_table[i]; | ||
i = i + 1; | i = i + 1; -- bump indexer to next segment | ||
while name_table[i] do | while name_table[i] do | ||
name = name .. ', ' .. name_table[i]; -- concatenate with previous segments | name = name .. ', ' .. name_table[i]; -- concatenate with previous segments | ||
Line 1,919: | Line 1,936: | ||
v_name, accept_name = utilities.has_accept_as_written (v_name); -- remove accept-this-as-written markup when it wraps all of <v_name> | v_name, accept_name = utilities.has_accept_as_written (v_name); -- remove accept-this-as-written markup when it wraps all of <v_name> | ||
if accept_name then | if accept_name then | ||
last = v_name; | last = v_name; | ||
Line 1,926: | Line 1,941: | ||
elseif string.find(v_name, "%s") then | elseif string.find(v_name, "%s") then | ||
if v_name:find('[;%.]') then -- look for commonly occurring punctuation characters; | if v_name:find('[;%.]') then -- look for commonly occurring punctuation characters; | ||
add_vanc_error (cfg.err_msg_supl.punctuation); | add_vanc_error (cfg.err_msg_supl.punctuation, i); | ||
end | end | ||
local lastfirstTable = {} | local lastfirstTable = {} | ||
Line 1,940: | Line 1,955: | ||
first = ''; -- unset | first = ''; -- unset | ||
last = v_name; -- last empty because something wrong with first | last = v_name; -- last empty because something wrong with first | ||
add_vanc_error (cfg.err_msg_supl.name); | add_vanc_error (cfg.err_msg_supl.name, i); | ||
end | end | ||
if mw.ustring.match (last, '%a+%s+%u+%s+%a+') then | if mw.ustring.match (last, '%a+%s+%u+%s+%a+') then | ||
add_vanc_error (cfg.err_msg_supl['missing comma']); | add_vanc_error (cfg.err_msg_supl['missing comma'], i); -- matches last II last; the case when a comma is missing | ||
end | end | ||
if mw.ustring.match (v_name, ' %u %u$') then -- this test is in the wrong place TODO: move or replace with a more appropriate test | if mw.ustring.match (v_name, ' %u %u$') then -- this test is in the wrong place TODO: move or replace with a more appropriate test | ||
add_vanc_error (cfg.err_msg_supl. | add_vanc_error (cfg.err_msg_supl.initials, i); -- matches a space between two initials | ||
end | end | ||
else | else | ||
Line 1,954: | Line 1,969: | ||
if utilities.is_set (first) then | if utilities.is_set (first) then | ||
if not mw.ustring.match (first, "^%u?%u$") then -- first shall contain one or two upper-case letters, nothing else | if not mw.ustring.match (first, "^%u?%u$") then -- first shall contain one or two upper-case letters, nothing else | ||
add_vanc_error (cfg.err_msg_supl.initials); | add_vanc_error (cfg.err_msg_supl.initials, i); -- too many initials; mixed case initials (which may be ok Romanization); hyphenated initials | ||
end | end | ||
is_good_vanc_name (last, first, suffix); -- check first and last before restoring the suffix which may have a non-Latin digit | is_good_vanc_name (last, first, suffix, i); -- check first and last before restoring the suffix which may have a non-Latin digit | ||
if utilities.is_set (suffix) then | if utilities.is_set (suffix) then | ||
first = first .. ' ' .. suffix; -- if there was a suffix concatenate with the initials | first = first .. ' ' .. suffix; -- if there was a suffix concatenate with the initials | ||
Line 1,963: | Line 1,978: | ||
else | else | ||
if not corporate then | if not corporate then | ||
is_good_vanc_name (last, ''); | is_good_vanc_name (last, '', nil, i); | ||
end | end | ||
end | end | ||
Line 2,177: | Line 2,192: | ||
]] | ]] | ||
local function insource_loc_get (page, pages, at) | local function insource_loc_get (page, page_orig, pages, pages_orig, at) | ||
local ws_url, ws_label, coins_pages, L; -- for Wikisource interwiki-links; TODO: this corrupts page metadata (span remains in place after cleanup; fix there?) | local ws_url, ws_label, coins_pages, L; -- for Wikisource interwiki-links; TODO: this corrupts page metadata (span remains in place after cleanup; fix there?) | ||
Line 2,185: | Line 2,200: | ||
at = ''; | at = ''; | ||
end | end | ||
extra_text_in_page_check (page); | extra_text_in_page_check (page, page_orig); -- emit error message when |page= value begins with what looks like p., pp., etc. | ||
ws_url, ws_label, L = wikisource_url_make (page); -- make ws URL from |page= interwiki link; link portion L becomes tooltip label | ws_url, ws_label, L = wikisource_url_make (page); -- make ws URL from |page= interwiki link; link portion L becomes tooltip label | ||
Line 2,197: | Line 2,212: | ||
at = ''; -- unset | at = ''; -- unset | ||
end | end | ||
extra_text_in_page_check (pages); | extra_text_in_page_check (pages, pages_orig); -- emit error message when |page= value begins with what looks like p., pp., etc. | ||
ws_url, ws_label, L = wikisource_url_make (pages); -- make ws URL from |pages= interwiki link; link portion L becomes tooltip label | ws_url, ws_label, L = wikisource_url_make (pages); -- make ws URL from |pages= interwiki link; link portion L becomes tooltip label | ||
Line 2,215: | Line 2,230: | ||
return page, pages, at, coins_pages; | return page, pages, at, coins_pages; | ||
end | |||
--[[--------------------------< I S _ U N I Q U E _ A R C H I V E _ U R L >------------------------------------ | |||
add error message when |archive-url= value is same as |url= or chapter-url= (or alias...) value | |||
]] | |||
local function is_unique_archive_url (archive, url, c_url, source, date) | |||
if utilities.is_set (archive) then | |||
if archive == url or archive == c_url then | |||
table.insert (z.message_tail, {utilities.set_message ('err_bad_url', {utilities.wrap_style ('parameter', source)}, true)}); -- add error message | |||
return '', ''; -- unset |archive-url= and |archive-date= because same as |url= or |chapter-url= | |||
end | |||
end | |||
return archive, date; | |||
end | end | ||
Line 2,364: | Line 2,396: | ||
]] | ]] | ||
local function citation0( config, args) | local function citation0( config, args ) | ||
--[[ | --[[ | ||
Load Input Parameters | Load Input Parameters | ||
Line 2,374: | Line 2,406: | ||
-- Pick out the relevant fields from the arguments. Different citation templates | -- Pick out the relevant fields from the arguments. Different citation templates | ||
-- define different field names for the same underlying things. | -- define different field names for the same underlying things. | ||
local author_etal; | local author_etal; | ||
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 = is_valid_parameter_value (A['NameListStyle'], A:ORIGIN('NameListStyle'), cfg.keywords_lists['name-list-style'], ''); | ||
local Collaboration = A['Collaboration']; | local Collaboration = A['Collaboration']; | ||
Line 2,389: | Line 2,418: | ||
a, author_etal = extract_names (args, 'AuthorList'); -- fetch author list from |authorn= / |lastn= / |firstn=, |author-linkn=, and |author-maskn= | a, author_etal = extract_names (args, 'AuthorList'); -- fetch author list from |authorn= / |lastn= / |firstn=, |author-linkn=, and |author-maskn= | ||
elseif 2 == selected then | elseif 2 == selected then | ||
NameListStyle = 'vanc'; | 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, args.vauthors, 'AuthorList'); -- fetch author list from |vauthors=, |author-linkn=, and |author-maskn= | ||
elseif 3 == selected then | elseif 3 == selected then | ||
Line 2,401: | Line 2,430: | ||
end | end | ||
end | end | ||
local editor_etal; | local editor_etal; | ||
local e = {}; -- editors list from |editor-lastn= / |editor-firstn= pairs or |veditors= | local e = {}; -- editors list from |editor-lastn= / |editor-firstn= pairs or |veditors= | ||
do -- to limit scope of selected | do -- to limit scope of selected | ||
Line 2,417: | Line 2,443: | ||
end | end | ||
end | end | ||
local Chapter = A['Chapter']; -- done here so that we have access to |contribution= from |chapter= aliases | local Chapter = A['Chapter']; -- done here so that we have access to |contribution= from |chapter= aliases | ||
local Chapter_origin = A:ORIGIN ('Chapter'); | local Chapter_origin = A:ORIGIN ('Chapter'); | ||
local Contribution; -- because contribution is required for contributor(s) | local Contribution; -- because contribution is required for contributor(s) | ||
if 'contribution' == | if 'contribution' == Chapter_origin then | ||
Contribution = | Contribution = Chapter; -- get the name of the contribution | ||
end | end | ||
local c = {}; -- contributors list from |contributor-lastn= / contributor-firstn= pairs | |||
if utilities.in_array (config.CitationClass, {"book", "citation"}) and not utilities.is_set (A['Periodical']) then -- |contributor= and |contribution= only supported in book cites | if utilities.in_array (config.CitationClass, {"book", "citation"}) and not utilities.is_set (A['Periodical']) then -- |contributor= and |contribution= only supported in book cites | ||
c = extract_names (args, 'ContributorList'); -- fetch contributor list from |contributorn= / |contributor-lastn=, -firstn=, -linkn=, -maskn= | c = extract_names (args, 'ContributorList'); -- fetch contributor list from |contributorn= / |contributor-lastn=, -firstn=, -linkn=, -maskn= | ||
Line 2,459: | Line 2,472: | ||
end | end | ||
local Title = A['Title']; | local Title = A['Title']; | ||
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 | ||
if (not accept_link) and utilities.in_array (TitleLink, {'none', 'pmc', 'doi'}) then -- check for special keywords | if (not accept_link) and utilities.in_array (TitleLink, {'none', 'pmc', 'doi'}) then -- check for special keywords | ||
auto_select = TitleLink; -- remember selection for later | auto_select = TitleLink; -- remember selection for later | ||
TitleLink = ''; -- treat as if |title-link= would have been empty | TitleLink = ''; -- treat as if |title-link= would have been empty | ||
end | end | ||
Line 2,491: | Line 2,486: | ||
local Section = ''; -- {{cite map}} only; preset to empty string for concatenation if not used | local Section = ''; -- {{cite map}} only; preset to empty string for concatenation if not used | ||
if 'map' == config.CitationClass and 'section' == Chapter_origin then | |||
Section = A['Chapter']; -- get |section= from |chapter= alias list; |chapter= and the other aliases not supported in {{cite map}} | |||
Chapter = ''; -- unset for now; will be reset later from |map= if present | |||
end | |||
local Periodical = A['Periodical']; | |||
local Periodical_origin = ''; | |||
local Periodical = A['Periodical']; | |||
local Periodical_origin = ''; | |||
if utilities.is_set (Periodical) then | if utilities.is_set (Periodical) then | ||
Periodical_origin = A:ORIGIN('Periodical'); -- get the name of the periodical parameter | Periodical_origin = A:ORIGIN('Periodical'); -- get the name of the periodical parameter | ||
Line 2,542: | Line 2,512: | ||
local ScriptPeriodical = A['ScriptPeriodical']; | local ScriptPeriodical = A['ScriptPeriodical']; | ||
-- web and news not tested for now because of | -- web and news not tested for now because of | ||
Line 2,553: | Line 2,522: | ||
end | end | ||
end | end | ||
local Volume; | local Volume; | ||
local | 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,580: | Line 2,540: | ||
Volume = A['Volume']; | Volume = A['Volume']; | ||
end | end | ||
extra_text_in_vol_iss_check (Volume, A:ORIGIN ('Volume'), 'v'); | |||
local Issue; | |||
if 'citation' == config.CitationClass then | if 'citation' == config.CitationClass then | ||
if utilities.is_set (Periodical) and utilities.in_array (Periodical_origin, {'journal', 'magazine', 'newspaper', 'periodical', 'work'}) or -- {{citation}} renders issue for these 'periodicals' | if utilities.is_set (Periodical) and utilities.in_array (Periodical_origin, {'journal', 'magazine', 'newspaper', 'periodical', 'work'}) or -- {{citation}} renders issue for these 'periodicals' | ||
Line 2,591: | Line 2,553: | ||
end | end | ||
end | end | ||
extra_text_in_vol_iss_check (Issue, A:ORIGIN ('Issue'), 'i'); | |||
local | local Page; | ||
local Pages; | |||
local At; | |||
if not utilities.in_array (config.CitationClass, cfg.templates_not_using_page) then | if not utilities.in_array (config.CitationClass, cfg.templates_not_using_page) then | ||
Page = A['Page']; | Page = A['Page']; | ||
Line 2,598: | Line 2,563: | ||
At = A['At']; | At = A['At']; | ||
end | end | ||
local Edition = A['Edition']; | local Edition = A['Edition']; | ||
Line 2,629: | Line 2,592: | ||
end | end | ||
local URL = A['URL'] | |||
local UrlAccess = is_valid_parameter_value (A['UrlAccess'], A:ORIGIN('UrlAccess'), cfg.keywords_lists['url-access'], nil); | local UrlAccess = is_valid_parameter_value (A['UrlAccess'], A:ORIGIN('UrlAccess'), cfg.keywords_lists['url-access'], nil); | ||
if not utilities.is_set (URL) and utilities.is_set (UrlAccess) then | |||
UrlAccess = nil; | |||
table.insert( z.message_tail, { utilities.set_message ( 'err_param_access_requires_param', {'url'}, true ) } ); | |||
end | |||
local ChapterURL = A['ChapterURL']; | |||
local ChapterUrlAccess = is_valid_parameter_value (A['ChapterUrlAccess'], A:ORIGIN('ChapterUrlAccess'), cfg.keywords_lists['url-access'], nil); | local ChapterUrlAccess = is_valid_parameter_value (A['ChapterUrlAccess'], A:ORIGIN('ChapterUrlAccess'), cfg.keywords_lists['url-access'], nil); | ||
if not utilities.is_set (ChapterURL) and utilities.is_set (ChapterUrlAccess) then | if not utilities.is_set (ChapterURL) and utilities.is_set (ChapterUrlAccess) then | ||
Line 2,647: | Line 2,613: | ||
end | end | ||
local | local this_page = mw.title.getCurrentTitle(); -- also used for COinS and for language | ||
local no_tracking_cats = is_valid_parameter_value (A['NoTracking'], A:ORIGIN('NoTracking'), cfg.keywords_lists['yes_true_y'], nil); | local no_tracking_cats = is_valid_parameter_value (A['NoTracking'], A:ORIGIN('NoTracking'), cfg.keywords_lists['yes_true_y'], nil); | ||
-- 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 utilities.is_set (no_tracking_cats) then -- ignore if we are already not going to categorize this page | |||
if utilities.in_array (this_page.nsText, cfg.uncategorized_namespaces) then | |||
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 | |||
-- 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 utilities.is_set (no_tracking_cats) then -- ignore if we are already not going to categorize this page | |||
if utilities.in_array (this_page.nsText, cfg.uncategorized_namespaces) then | |||
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 | no_tracking_cats = "true"; -- set no_tracking_cats | ||
break; -- bail out if one is found | break; -- bail out if one is found | ||
Line 2,713: | Line 2,633: | ||
local coins_pages; | local coins_pages; | ||
Page, Pages, At, coins_pages = insource_loc_get (Page, Pages, At); | Page, Pages, At, coins_pages = insource_loc_get (Page, A:ORIGIN('Page'), Pages, A:ORIGIN('Pages'), At); | ||
local NoPP = is_valid_parameter_value (A['NoPP'], A:ORIGIN('NoPP'), cfg.keywords_lists['yes_true_y'], nil); | local NoPP = is_valid_parameter_value (A['NoPP'], A:ORIGIN('NoPP'), cfg.keywords_lists['yes_true_y'], nil); | ||
Line 2,727: | Line 2,647: | ||
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 ChapterURL_origin = A:ORIGIN('ChapterURL'); -- get name of parameter that holds ChapterURL | |||
local ScriptChapter = A['ScriptChapter']; | |||
local ScriptChapter_origin = A:ORIGIN ('ScriptChapter'); | |||
local Format = A['Format']; | |||
local ChapterFormat = A['ChapterFormat']; | |||
local TransChapter = A['TransChapter']; | |||
local TransChapter_origin = A:ORIGIN ('TransChapter'); | |||
local TransTitle = A['TransTitle']; | |||
local ScriptTitle = A['ScriptTitle']; | |||
--[[ | --[[ | ||
Line 2,768: | Line 2,699: | ||
TransChapter = TransTitle; | TransChapter = TransTitle; | ||
ChapterURL = URL; | ChapterURL = URL; | ||
ChapterURL_origin = | ChapterURL_origin = URL_origin; | ||
ChapterUrlAccess = UrlAccess; | ChapterUrlAccess = UrlAccess; | ||
Line 2,792: | Line 2,723: | ||
-- special case for cite techreport. | -- special case for cite techreport. | ||
local ID = A['ID']; | |||
if (config.CitationClass == "techreport") then -- special case for cite techreport | if (config.CitationClass == "techreport") then -- special case for cite techreport | ||
if utilities.is_set (A['Number']) then -- cite techreport uses 'number', which other citations alias to 'issue' | if utilities.is_set (A['Number']) then -- cite techreport uses 'number', which other citations alias to 'issue' | ||
Line 2,803: | Line 2,735: | ||
-- Account for the oddity that is {{cite conference}}, before generation of COinS data. | -- Account for the oddity that is {{cite conference}}, before generation of COinS data. | ||
local ChapterLink -- = A['ChapterLink']; -- deprecated as a parameter but still used internally by cite episode | |||
local Conference = A['Conference']; | |||
local BookTitle = A['BookTitle']; | |||
local TransTitle_origin = A:ORIGIN ('TransTitle'); | |||
if 'conference' == config.CitationClass then | if 'conference' == config.CitationClass then | ||
if utilities.is_set (BookTitle) then | if utilities.is_set (BookTitle) then | ||
Line 2,824: | Line 2,760: | ||
Conference = ''; -- not cite conference or cite speech so make sure this is empty string | Conference = ''; -- not cite conference or cite speech so make sure this is empty string | ||
end | end | ||
-- CS1/2 mode | |||
local Mode = is_valid_parameter_value (A['Mode'], A:ORIGIN('Mode'), cfg.keywords_lists['mode'], ''); | |||
-- separator character and postscript | |||
local sepc, PostScript = set_style (Mode:lower(), A['PostScript'], config.CitationClass); | |||
-- controls capitalization of certain static text | |||
local use_lowercase = ( sepc == ',' ); | |||
-- cite map oddities | -- cite map oddities | ||
local Cartography = ""; | local Cartography = ""; | ||
Line 2,856: | Line 2,799: | ||
-- Account for the oddities that are {{cite episode}} and {{cite serial}}, before generation of COinS data. | -- Account for the oddities that are {{cite episode}} and {{cite serial}}, before generation of COinS data. | ||
local Series = A['Series']; | |||
if 'episode' == config.CitationClass or 'serial' == config.CitationClass then | if 'episode' == config.CitationClass or 'serial' == config.CitationClass then | ||
local SeriesLink = A['SeriesLink']; | local SeriesLink = A['SeriesLink']; | ||
Line 2,890: | Line 2,834: | ||
ChapterURL = URL; | ChapterURL = URL; | ||
ChapterUrlAccess = UrlAccess; | ChapterUrlAccess = UrlAccess; | ||
ChapterURL_origin = | ChapterURL_origin = URL_origin; | ||
Title = Series; -- promote series to title | Title = Series; -- promote series to title | ||
Line 2,917: | Line 2,861: | ||
-- handle type parameter for those CS1 citations that have default values | -- handle type parameter for those CS1 citations that have default values | ||
local TitleType = A['TitleType']; | |||
local Degree = A['Degree']; | |||
if utilities.in_array (config.CitationClass, {"AV-media-notes", "interview", "mailinglist", "map", "podcast", "pressrelease", "report", "techreport", "thesis"}) then | if utilities.in_array (config.CitationClass, {"AV-media-notes", "interview", "mailinglist", "map", "podcast", "pressrelease", "report", "techreport", "thesis"}) then | ||
TitleType = set_titletype (config.CitationClass, TitleType); | TitleType = set_titletype (config.CitationClass, TitleType); | ||
Line 2,930: | Line 2,876: | ||
-- legacy: promote PublicationDate to Date if neither Date nor Year are set. | -- legacy: promote PublicationDate to Date if neither Date nor Year are set. | ||
local Date = A['Date']; | |||
local Date_origin; -- to hold the name of parameter promoted to Date; required for date error messaging | local Date_origin; -- to hold the name of parameter promoted to Date; required for date error messaging | ||
local PublicationDate = A['PublicationDate']; | |||
local Year = A['Year']; | |||
if not utilities.is_set (Date) then | if not utilities.is_set (Date) then | ||
Line 2,954: | Line 2,903: | ||
Date validation supporting code is in Module:Citation/CS1/Date_validation | Date validation supporting code is in Module:Citation/CS1/Date_validation | ||
]] | ]] | ||
local DF = is_valid_parameter_value (A['DF'], A:ORIGIN('DF'), cfg.keywords_lists['df'], ''); | |||
if not utilities.is_set (DF) then | |||
DF = cfg.global_df; -- local |df= if present overrides global df set by {{use xxx date}} template | |||
end | |||
local ArchiveURL; | |||
local ArchiveDate; | |||
local ArchiveFormat = A['ArchiveFormat']; | |||
ArchiveURL, ArchiveDate = archive_url_check (A['ArchiveURL'], A['ArchiveDate']) | |||
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 | |||
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 DoiBroken = A['DoiBroken']; | |||
local Embargo = A['Embargo']; | |||
local anchor_year; -- used in the CITEREF identifier | |||
do -- create defined block to contain local variables error_message, date_parameters_list, mismatch | do -- create defined block to contain local variables error_message, date_parameters_list, mismatch | ||
local error_message = ''; | local error_message = ''; | ||
Line 2,978: | Line 2,949: | ||
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); | |||
end | end | ||
Line 2,989: | Line 2,955: | ||
local modified = false; -- flag | local modified = false; -- flag | ||
if validation.edtf_transform (date_parameters_list) then -- edtf dates to MOS compliant format | |||
modified = true; | |||
end | |||
if utilities.is_set (DF) then -- if we need to reformat dates | if utilities.is_set (DF) then -- if we need to reformat dates | ||
modified = validation.reformat_dates (date_parameters_list, DF); -- reformat to DF format, use long month names if appropriate | modified = validation.reformat_dates (date_parameters_list, DF); -- reformat to DF format, use long month names if appropriate | ||
Line 3,020: | Line 2,990: | ||
local ID_list = {}; -- sequence table of rendered identifiers | local ID_list = {}; -- sequence table of rendered identifiers | ||
local ID_list_coins = {}; -- table of identifiers and their values from args; key is same as cfg.id_handlers's key | local ID_list_coins = {}; -- table of identifiers and their values from args; key is same as cfg.id_handlers's key | ||
local Class = A['Class']; -- arxiv class identifier | |||
local ID_support = { | |||
{A['ASINTLD'], 'ASIN', 'err_asintld_missing_asin', A:ORIGIN ('ASINTLD')}, | |||
{DoiBroken, 'DOI', 'err_doibroken_missing_doi', A:ORIGIN ('DoiBroken')}, | |||
{Embargo, 'PMC', 'err_embargo_missing_pmc', A:ORIGIN ('Embargo')}, | |||
} | |||
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 ssrn}}, before generation of COinS data. | ||
Line 3,038: | Line 3,012: | ||
if config.CitationClass == "journal" and not utilities.is_set (URL) and not utilities.is_set (TitleLink) and not utilities.in_array (cfg.keywords_xlate[Title], {'off', 'none'}) then -- TODO: remove 'none' once existing citations have been switched to 'off', so 'none' can be used as token for "no title" instead | if config.CitationClass == "journal" and not utilities.is_set (URL) and not utilities.is_set (TitleLink) and not utilities.in_array (cfg.keywords_xlate[Title], {'off', 'none'}) then -- TODO: remove 'none' once existing citations have been switched to 'off', so 'none' can be used as token for "no title" instead | ||
if 'none' ~= cfg.keywords_xlate[auto_select] then -- if auto-linking not disabled | |||
if identifiers.auto_link_urls[auto_select] then -- manual selection | if identifiers.auto_link_urls[auto_select] then -- manual selection | ||
URL = identifiers.auto_link_urls[auto_select]; -- set URL to be the same as identifier's external link | URL = identifiers.auto_link_urls[auto_select]; -- set URL to be the same as identifier's external link | ||
URL_origin = cfg.id_handlers[auto_select:upper()].parameters[1]; -- set URL_origin to parameter name for use in error message if citation is missing a |title= | URL_origin = cfg.id_handlers[auto_select:upper()].parameters[1]; -- set URL_origin to parameter name for use in error message if citation is missing a |title= | ||
elseif identifiers.auto_link_urls['pmc'] then -- auto-select PMC | elseif identifiers.auto_link_urls['pmc'] then -- auto-select PMC | ||
URL = identifiers.auto_link_urls['pmc']; -- set URL to be the same as the PMC external link if not embargoed | URL = identifiers.auto_link_urls['pmc']; -- set URL to be the same as the PMC external link if not embargoed | ||
URL_origin = cfg.id_handlers['PMC'].parameters[1]; -- set URL_origin to parameter name for use in error message if citation is missing a |title= | URL_origin = cfg.id_handlers['PMC'].parameters[1]; -- set URL_origin to parameter name for use in error message if citation is missing a |title= | ||
elseif identifiers.auto_link_urls['doi'] then -- auto-select DOI | elseif identifiers.auto_link_urls['doi'] then -- auto-select DOI | ||
URL = identifiers.auto_link_urls['doi']; | URL = identifiers.auto_link_urls['doi']; | ||
URL_origin = cfg.id_handlers['DOI'].parameters[1]; | URL_origin = cfg.id_handlers['DOI'].parameters[1]; | ||
Line 3,095: | Line 3,069: | ||
coins_author = c; -- use that instead | coins_author = c; -- use that instead | ||
end | end | ||
local QuotePage = A['QuotePage']; | |||
local QuotePages = hyphen_to_dash (A['QuotePages']); | |||
-- this is the function call to COinS() | -- this is the function call to COinS() | ||
Line 3,130: | Line 3,107: | ||
end | end | ||
local Editors; | |||
local EditorCount; -- used only for choosing {ed.) or (eds.) annotation at end of editor name-list | |||
local Contributors; -- assembled contributors name list | |||
local contributor_etal; | |||
local Translators; -- assembled translators name list | |||
local translator_etal; | |||
local t = {}; -- translators list from |translator-lastn= / translator-firstn= pairs | |||
t = extract_names (args, 'TranslatorList'); -- fetch translator list from |translatorn= / |translator-lastn=, -firstn=, -linkn=, -maskn= | |||
local Interviewers; | |||
local interviewers_list = {}; | |||
interviewers_list = extract_names (args, 'InterviewerList'); -- process preferred interviewers parameters | |||
local interviewer_etal; | |||
-- Now perform various field substitutions. | -- Now perform various field substitutions. | ||
-- 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. | ||
do | do | ||
local last_first_list; | local last_first_list; | ||
Line 3,143: | Line 3,132: | ||
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); | control.maximum , editor_etal = get_display_names (A['DisplayEditors'], #e, 'editors', editor_etal, A:ORIGIN ('DisplayEditors')); | ||
Editors, EditorCount = list_people (control, e, editor_etal); | Editors, EditorCount = list_people (control, e, editor_etal); | ||
Line 3,151: | Line 3,140: | ||
end | end | ||
do -- now do interviewers | do -- now do interviewers | ||
control.maximum , interviewer_etal = get_display_names (A['DisplayInterviewers'], #interviewers_list, 'interviewers', interviewer_etal); | control.maximum, interviewer_etal = get_display_names (A['DisplayInterviewers'], #interviewers_list, 'interviewers', interviewer_etal, A:ORIGIN ('DisplayInterviewers')); | ||
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); | control.maximum, translator_etal = get_display_names (A['DisplayTranslators'], #t, 'translators', translator_etal, A:ORIGIN ('DisplayTranslators')); | ||
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); | control.maximum, contributor_etal = get_display_names (A['DisplayContributors'], #c, 'contributors', contributor_etal, A:ORIGIN ('DisplayContributors')); | ||
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); | control.maximum, author_etal = get_display_names (A['DisplayAuthors'], #a, 'authors', author_etal, A:ORIGIN ('DisplayAuthors')); | ||
last_first_list = list_people(control, a, author_etal); | last_first_list = list_people (control, a, author_etal); | ||
if utilities.is_set (Authors) then | if utilities.is_set (Authors) then | ||
Line 3,183: | Line 3,172: | ||
end | end | ||
local ConferenceFormat = A['ConferenceFormat']; | |||
local ConferenceURL = A['ConferenceURL']; | |||
ConferenceFormat = style_format (ConferenceFormat, ConferenceURL, 'conference-format', 'conference-url'); | ConferenceFormat = style_format (ConferenceFormat, ConferenceURL, 'conference-format', 'conference-url'); | ||
Format = style_format (Format, URL, 'format', 'url'); | Format = style_format (Format, URL, 'format', 'url'); | ||
-- 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 | ||
Line 3,210: | Line 3,196: | ||
end | end | ||
local OriginalURL | local UrlStatus = is_valid_parameter_value (A['UrlStatus'], A:ORIGIN('UrlStatus'), cfg.keywords_lists['url-status'], ''); | ||
local OriginalURL | |||
local OriginalURL_origin | |||
local OriginalFormat | |||
local OriginalAccess; | |||
UrlStatus = UrlStatus:lower(); -- used later when assembling archived text | UrlStatus = UrlStatus:lower(); -- used later when assembling archived text | ||
if utilities.is_set ( ArchiveURL ) then | if utilities.is_set ( ArchiveURL ) then | ||
Line 3,377: | Line 3,367: | ||
end | end | ||
local ConferenceURL_origin = A:ORIGIN('ConferenceURL'); -- get name of parameter that holds ConferenceURL | |||
if utilities.is_set (Conference) then | if utilities.is_set (Conference) then | ||
if utilities.is_set (ConferenceURL) then | if utilities.is_set (ConferenceURL) then | ||
Line 3,386: | Line 3,377: | ||
end | end | ||
local Position = ''; | |||
if not utilities.is_set (Position) then | if not utilities.is_set (Position) then | ||
local Minutes = A['Minutes']; | local Minutes = A['Minutes']; | ||
Line 3,432: | Line 3,424: | ||
end | end | ||
if utilities.is_set ( | local Others = A['Others']; | ||
if utilities.is_set (Others) and 0 == #a and 0 == #e then -- add maint cat when |others= has value and used without |author=, |editor= | |||
if config.CitationClass == "AV-media-notes" | |||
or config.CitationClass == "audio-visual" then -- special maint for AV/M which has a lot of 'false' positives right now | |||
utilities.set_message ('maint_others_avm') | |||
else | |||
utilities.set_message ('maint_others'); | |||
end | |||
end | end | ||
Others = utilities.is_set (Others) and (sepc .. " " .. Others) or ""; | Others = utilities.is_set (Others) and (sepc .. " " .. Others) or ""; | ||
Line 3,450: | Line 3,442: | ||
end | end | ||
local TitleNote = A['TitleNote']; | |||
TitleNote = utilities.is_set (TitleNote) and (sepc .. " " .. TitleNote) or ""; | TitleNote = utilities.is_set (TitleNote) and (sepc .. " " .. TitleNote) or ""; | ||
if utilities.is_set (Edition) then | if utilities.is_set (Edition) then | ||
Line 3,461: | Line 3,454: | ||
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']; | |||
Agency = utilities.is_set (Agency) and wrap_msg ('agency', {sepc, Agency}) or ""; | Agency = utilities.is_set (Agency) and wrap_msg ('agency', {sepc, Agency}) or ""; | ||
Volume = format_volume_issue (Volume, Issue, config.CitationClass, Periodical_origin, sepc, use_lowercase); | Volume = format_volume_issue (Volume, Issue, config.CitationClass, Periodical_origin, sepc, use_lowercase); | ||
if utilities.is_set (AccessDate) then | if utilities.is_set (AccessDate) then | ||
Line 3,479: | Line 3,469: | ||
if utilities.is_set (ID) then ID = sepc .. " " .. ID; end | if utilities.is_set (ID) then ID = sepc .. " " .. ID; end | ||
local Docket = A['Docket']; | |||
if "thesis" == config.CitationClass and utilities.is_set (Docket) then | if "thesis" == config.CitationClass and utilities.is_set (Docket) then | ||
ID = sepc .. " Docket " .. Docket .. ID; | ID = sepc .. " Docket " .. Docket .. ID; | ||
Line 3,490: | Line 3,482: | ||
end | end | ||
local Quote = A['Quote']; | |||
local TransQuote = A['TransQuote']; | |||
local ScriptQuote = A['ScriptQuote']; | |||
if utilities.is_set (Quote) or utilities.is_set (TransQuote) or utilities.is_set (ScriptQuote) then | if utilities.is_set (Quote) or utilities.is_set (TransQuote) or utilities.is_set (ScriptQuote) then | ||
Line 3,498: | Line 3,493: | ||
end | end | ||
Quote = utilities.wrap_style ('quoted-text', Quote ); | Quote = utilities.wrap_style ('quoted-text', Quote ); -- wrap in <q>...</q> tags | ||
if utilities.is_set (ScriptQuote) then | if utilities.is_set (ScriptQuote) then | ||
Quote = script_concatenate (Quote, ScriptQuote, 'script-quote'); -- <bdi> tags, lang attribute, categorization, etc.; must be done after quote is wrapped | Quote = script_concatenate (Quote, ScriptQuote, 'script-quote'); -- <bdi> tags, lang attribute, categorization, etc.; must be done after quote is wrapped | ||
end | end | ||
Line 3,511: | Line 3,506: | ||
end | end | ||
if utilities.is_set (QuotePage) or utilities.is_set (QuotePages) then -- add page prefix | |||
if utilities.is_set (QuotePage) or utilities.is_set (QuotePages) then | |||
local quote_prefix = ''; | local quote_prefix = ''; | ||
if utilities.is_set (QuotePage) then | if utilities.is_set (QuotePage) then | ||
extra_text_in_page_check (QuotePage); -- add to maint cat if |quote-page= value begins with what looks like p., pp., etc. | extra_text_in_page_check (QuotePage, 'quote-page'); -- add to maint cat if |quote-page= value begins with what looks like p., pp., etc. | ||
if not NoPP then | if not NoPP then | ||
quote_prefix = utilities.substitute (cfg.messages['p-prefix'], {sepc, QuotePage}), '', '', ''; | quote_prefix = utilities.substitute (cfg.messages['p-prefix'], {sepc, QuotePage}), '', '', ''; | ||
Line 3,522: | Line 3,516: | ||
end | end | ||
elseif utilities.is_set (QuotePages) then | elseif utilities.is_set (QuotePages) then | ||
extra_text_in_page_check (QuotePages); -- add to maint cat if |quote-pages= value begins with what looks like p., pp., etc. | extra_text_in_page_check (QuotePages, 'quote-pages'); -- add to maint cat if |quote-pages= value begins with what looks like p., pp., etc. | ||
if tonumber(QuotePages) ~= nil and not NoPP then -- if only digits, assume single page | if tonumber(QuotePages) ~= nil and not NoPP then -- if only digits, assume single page | ||
quote_prefix = utilities.substitute (cfg.messages['p-prefix'], {sepc, QuotePages}), '', ''; | quote_prefix = utilities.substitute (cfg.messages['p-prefix'], {sepc, QuotePages}), '', ''; | ||
Line 3,538: | Line 3,532: | ||
PostScript = ""; -- cs1|2 does not supply terminal punctuation when |quote= is set | PostScript = ""; -- cs1|2 does not supply terminal punctuation when |quote= is set | ||
end | |||
-- We check length of PostScript here because it will have been nuked by | |||
-- the quote parameters. We'd otherwise emit a message even if there wasn't | |||
-- a displayed postscript. | |||
-- TODO: Should the max size (1) be configurable? | |||
-- TODO: Should we check a specific pattern? | |||
if utilities.is_set(PostScript) and mw.ustring.len(PostScript) > 1 then | |||
utilities.set_message('maint_postscript') | |||
end | end | ||
Line 3,583: | Line 3,586: | ||
local Lay = ''; | 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 (LayURL) then | ||
if utilities.is_set (LayDate) then LayDate = " (" .. LayDate .. ")" end | if utilities.is_set (LayDate) then LayDate = " (" .. LayDate .. ")" end | ||
Line 3,599: | Line 3,606: | ||
end | end | ||
local TranscriptURL = A['TranscriptURL'] | |||
local TranscriptFormat = A['TranscriptFormat']; | |||
TranscriptFormat = style_format (TranscriptFormat, TranscriptURL, 'transcript-format', 'transcripturl'); | |||
local Transcript = A['Transcript']; | |||
local TranscriptURL_origin = A:ORIGIN('TranscriptURL'); -- get name of parameter that holds TranscriptURL | |||
if utilities.is_set (Transcript) then | if utilities.is_set (Transcript) then | ||
if utilities.is_set (TranscriptURL) then | if utilities.is_set (TranscriptURL) then | ||
Line 3,624: | Line 3,636: | ||
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,631: | Line 3,645: | ||
Periodical = format_periodical (ScriptPeriodical, ScriptPeriodical_origin, Periodical, TransPeriodical, TransPeriodical_origin); | Periodical = format_periodical (ScriptPeriodical, ScriptPeriodical_origin, Periodical, TransPeriodical, TransPeriodical_origin); | ||
end | end | ||
end | |||
local Language = A['Language']; | |||
if utilities.is_set (Language) then | |||
Language = language_parameter (Language); -- format, categories, name from ISO639-1, etc. | |||
else | |||
Language=''; -- language not specified so make sure this is an empty string; | |||
--[[ TODO: need to extract the wrap_msg from language_parameter | |||
so that we can solve parentheses bunching problem with Format/Language/TitleType | |||
]] | |||
end | end | ||
Line 3,687: | Line 3,711: | ||
end | end | ||
local Via = A['Via']; | |||
Via = utilities.is_set (Via) and wrap_msg ('via', Via) or ''; | |||
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 | ||
Line 3,697: | Line 3,723: | ||
local pgtext = Position .. Sheet .. Sheets .. Page .. Pages .. At; | local pgtext = Position .. Sheet .. Sheets .. Page .. Pages .. At; | ||
local OrigDate = A['OrigDate']; | |||
OrigDate = utilities.is_set (OrigDate) and wrap_msg ('origdate', OrigDate) or ''; | |||
if utilities.is_set (Date) then | if utilities.is_set (Date) then | ||
if utilities.is_set (Authors) or utilities.is_set (Editors) then -- date follows authors or editors when authors not set | if utilities.is_set (Authors) or utilities.is_set (Editors) then -- date follows authors or editors when authors not set | ||
Line 3,772: | Line 3,800: | ||
text = safe_join( {text, PostScript}, sepc ); | text = safe_join( {text, PostScript}, sepc ); | ||
-- Now enclose the whole thing in a <cite | -- Now enclose the whole thing in a <cite> element | ||
local options = {}; | local options = {}; | ||
Line 3,780: | Line 3,808: | ||
options.class = string.format ('%s %s', 'citation', utilities.is_set (Mode) and Mode or 'cs2'); | options.class = string.format ('%s %s', 'citation', utilities.is_set (Mode) and Mode or 'cs2'); | ||
end | end | ||
if utilities.is_set (Ref) | local Ref = A['Ref']; | ||
if 'harv' == Ref then -- need to check this before setting to default | |||
utilities.set_message ('maint_ref_harv'); -- add maint cat to identify templates that have this now-extraneous param value | |||
elseif not utilities.is_set (Ref) then | |||
Ref = 'harv'; -- set as default when not set externally | |||
end | |||
if 'none' ~= cfg.keywords_xlate[Ref:lower()] then | |||
local id = Ref | local id = Ref | ||
local namelist = {}; -- holds selected contributor, author, editor name list | |||
local year = first_set ({Year, anchor_year}, 2); -- Year first for legacy citations and for YMD dates that require disambiguation | |||
if #c > 0 then -- if there is a contributor list | |||
namelist = c; -- select it | |||
elseif #a > 0 then -- or an author list | |||
namelist = a; | |||
elseif #e > 0 then -- or an editor list | |||
namelist = e; | |||
end | |||
local citeref_id | |||
if #namelist > 0 then -- if there are names in namelist | |||
citeref_id = make_citeref_id (namelist, year); -- go make the CITEREF anchor | |||
else | |||
end | citeref_id = ''; -- unset | ||
end | |||
if citeref_id == Ref then | |||
utilities.set_message ('maint_ref_duplicates_default'); | |||
end | |||
if 'harv' == Ref then | |||
id = citeref_id | |||
end | end | ||
options.id = id; | options.id = id; | ||
Line 3,879: | Line 3,918: | ||
if true == state then return true; end -- valid actively supported parameter | if true == state then return true; end -- valid actively supported parameter | ||
if false == state then | if false == state then | ||
if empty then return nil; end -- deprecated | if empty then return nil; end -- empty deprecated parameters are treated as unknowns | ||
deprecated_parameter (name); -- parameter is deprecated but still supported | deprecated_parameter (name); -- parameter is deprecated but still supported | ||
return true; | |||
end | |||
if 'discouraged' == state then | |||
discouraged_parameter (name); -- parameter is discouraged but still supported | |||
return true; | return true; | ||
end | end | ||
Line 4,071: | Line 4,114: | ||
error_text, error_state = utilities.set_message ('err_parameter_ignored_suggest', {k, param}, true); -- set the suggestion error message | error_text, error_state = utilities.set_message ('err_parameter_ignored_suggest', {k, param}, true); -- set the suggestion error message | ||
else | else | ||
error_text, error_state = utilities.set_message ( 'err_parameter_ignored', { | error_text, error_state = utilities.set_message ( 'err_parameter_ignored', {k}, true ); -- suggested param not supported by this template | ||
v = ''; -- unset | v = ''; -- unset | ||
end | end | ||
end | end | ||
end | end | ||
if not utilities.is_set (error_text) then -- couldn't match with a pattern, is there an explicit suggestion? | if not utilities.is_set (error_text) then -- couldn't match with a pattern, is there an explicit suggestion? | ||
if suggestions.suggestions[ k:lower() ] ~= nil then | if (suggestions.suggestions[ k:lower() ] ~= nil) and validate (suggestions.suggestions[ k:lower() ], config.CitationClass) then | ||
error_text, error_state = utilities.set_message ( 'err_parameter_ignored_suggest', {k, suggestions.suggestions[ k:lower() ]}, true ); | error_text, error_state = utilities.set_message ( 'err_parameter_ignored_suggest', {k, suggestions.suggestions[ k:lower() ]}, true ); | ||
else | else |