Editing Module:Citation/CS1
The edit can be undone. Please check the comparison below to verify that this is what you want to do, and then publish the changes below to finish undoing the edit.
Latest revision | Your text | ||
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 16: | Line 18: | ||
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 | --[[--------------------------< P A G E S C O P E V A R I A B L E S >-------------------------------------- | ||
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_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 56: | Line 62: | ||
]] | ]] | ||
local function add_vanc_error (source | local function add_vanc_error (source) | ||
if added_vanc_errs then | if not added_vanc_errs then | ||
added_vanc_errs = true; -- note that we've added this category | |||
table.insert( z.message_tail, { utilities.set_message ( 'err_vancouver', {source}, true ) } ); | |||
end | |||
end | end | ||
Line 409: | Line 415: | ||
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 437: | Line 443: | ||
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 | ||
end | end | ||
Line 550: | Line 539: | ||
-- 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 611: | Line 600: | ||
--[[----------------< W I K I S O U R C E _ U R L _ M A K E >------------------- | --[[--------------------------< W I K I S O U R C E _ U R L _ M A K E >---------------------------------------- | ||
Makes a Wikisource URL from Wikisource interwiki-link. Returns the URL and appropriate | Makes a Wikisource URL from Wikisource interwiki-link. Returns the URL and appropriate label; nil else. | ||
label; nil else. | |||
str is the value assigned to |chapter= (or aliases) or |title= or |title-link= | str is the value assigned to |chapter= (or aliases) or |title= or |title-link= | ||
Line 655: | Line 643: | ||
end | end | ||
end | end | ||
if ws_url then | if ws_url then | ||
ws_url = mw.uri.encode (ws_url, 'WIKI'); -- make a usable URL | ws_url = mw.uri.encode (ws_url, 'WIKI'); -- make a usable URL | ||
ws_url = ws_url:gsub ('%%23', '#'); -- undo percent | ws_url = ws_url:gsub ('%%23', '#'); -- undo percent encoding of fragment marker | ||
end | end | ||
Line 665: | Line 653: | ||
--[[----------------< F O R M A T _ P E R I O D I C A L >----------------------- | --[[--------------------------< F O R M A T _ P E R I O D I C A L >-------------------------------------------- | ||
Format the three periodical parameters: |script-<periodical>=, |<periodical>=, | Format the three periodical parameters: |script-<periodical>=, |<periodical>=, and |trans-<periodical>= into a single Periodical meta- | ||
and |trans-<periodical>= into a single Periodical meta-parameter. | parameter. | ||
]] | ]] | ||
Line 697: | Line 685: | ||
--[[------------------< F O R M A T _ C H A P T E R _ T I T L E >--------------- | --[[--------------------------< F O R M A T _ C H A P T E R _ T I T L E >-------------------------------------- | ||
Format the four chapter parameters: |script-chapter=, |chapter=, |trans-chapter=, | Format the four chapter parameters: |script-chapter=, |chapter=, |trans-chapter=, and |chapter-url= into a single chapter meta- | ||
and |chapter-url= into a single chapter meta- parameter (chapter_url_source used | parameter (chapter_url_source used for error messages). | ||
for error messages). | |||
]] | ]] | ||
Line 710: | Line 697: | ||
local ws_url, ws_label, L = wikisource_url_make (chapter); -- make a wikisource URL and label from a wikisource interwiki link | local ws_url, ws_label, L = wikisource_url_make (chapter); -- make a wikisource URL and label from a wikisource interwiki link | ||
if ws_url then | if ws_url then | ||
ws_label = ws_label:gsub ('_', ' '); | ws_label = ws_label:gsub ('_', ''); -- replace underscore separaters with space characters | ||
chapter = ws_label; | chapter = ws_label; | ||
end | end | ||
Line 747: | Line 734: | ||
--[[----------------< H A S _ I N V I S I B L E _ C H A R S >------------------- | --[[--------------------------< H A S _ I N V I S I B L E _ C H A R S >---------------------------------------- | ||
This function searches a parameter's value for non-printable or invisible characters. | This function searches a parameter's value for non-printable or invisible characters. The search stops at the | ||
The search stops at the first match. | first match. | ||
This function will detect the visible replacement character when it is part of the Wikisource. | This function will detect the visible replacement character when it is part of the Wikisource. | ||
Detects but ignores nowiki and math stripmarkers. Also detects other named stripmarkers | Detects but ignores nowiki and math stripmarkers. Also detects other named stripmarkers (gallery, math, pre, ref) | ||
(gallery, math, pre, ref) and identifies them with a slightly different error message. | and identifies them with a slightly different error message. See also coins_cleanup(). | ||
See also coins_cleanup(). | |||
Output of this function is an error message that identifies the character or the | Output of this function is an error message that identifies the character or the Unicode group, or the stripmarker | ||
Unicode group, or the stripmarker that was detected along with its position (or, | that was detected along with its position (or, for multi-byte characters, the position of its first byte) in the | ||
for multi-byte characters, the position of its first byte) in the parameter value. | parameter value. | ||
]] | ]] | ||
Line 766: | Line 752: | ||
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 dummy; -- end of matching string; not used but required to hold end position when a capture is returned | |||
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 stripmarker; | local i = 1; | ||
local stripmarker, apostrophe; | |||
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 774: | Line 762: | ||
end | end | ||
while cfg.invisible_chars[i] do | |||
local | local char = cfg.invisible_chars[i][1] -- the character or group name | ||
local pattern = | local pattern = cfg.invisible_chars[i][2] -- the pattern used to find it | ||
position, | position, dummy, capture = mw.ustring.find (v, pattern) -- see if the parameter value contains characters that match the pattern | ||
if position and ( | if position and (char == 'zero width joiner') 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 | position = nil; -- unset position | ||
end | end | ||
Line 791: | Line 777: | ||
('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 'delete' == char 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 | if capture then | ||
err_msg = capture .. ' ' .. | err_msg = capture .. ' ' .. char; | ||
else | else | ||
err_msg = | err_msg = char .. ' ' .. '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 | ||
i = i+1; -- bump our index | |||
end | end | ||
end | end | ||
--[[-------------------< A R G U M E N T _ W R A P P E R >---------------------- | --[[--------------------------< A R G U M E N T _ W R A P P E R >---------------------------------------------- | ||
Argument wrapper. This function provides support for argument mapping defined | Argument wrapper. This function provides support for argument mapping defined in the configuration file so that | ||
in the configuration file so that multiple names can be transparently aliased to | multiple names can be transparently aliased to single internal variable. | ||
single internal variable. | |||
]] | ]] | ||
Line 822: | Line 808: | ||
return setmetatable({ | return setmetatable({ | ||
ORIGIN = function ( self, k ) | ORIGIN = function ( self, k ) | ||
local dummy = self[k]; | local dummy = self[k]; --force the variable to be loaded. | ||
return origin[k]; | return origin[k]; | ||
end | end | ||
Line 837: | Line 823: | ||
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] = ''; | origin[k] = ''; -- Empty string, not nil | ||
end | end | ||
elseif list ~= nil then | elseif list ~= nil then | ||
Line 860: | Line 846: | ||
--[[--------------------------< N O W R A P _ D A T E >------------------------- | --[[--------------------------< N O W R A P _ D A T E >-------------------------------------------------------- | ||
When date is YYYY-MM-DD format wrap in nowrap span: <span ...>YYYY-MM-DD</span>. | When date is YYYY-MM-DD format wrap in nowrap span: <span ...>YYYY-MM-DD</span>. When date is DD MMMM YYYY or is | ||
When date is DD MMMM YYYY or is MMMM DD, YYYY then wrap in nowrap span: | MMMM DD, YYYY then wrap in nowrap span: <span ...>DD MMMM</span> YYYY or <span ...>MMMM DD,</span> YYYY | ||
<span ...>DD MMMM</span> YYYY or <span ...>MMMM DD,</span> YYYY | |||
DOES NOT yet support MMMM YYYY or any of the date ranges. | DOES NOT yet support MMMM YYYY or any of the date ranges. | ||
Line 886: | Line 871: | ||
--[[--------------------------< S E T _ T I T L E T Y P E >--------------------- | --[[--------------------------< S E T _ T I T L E T Y P E >---------------------------------------------------- | ||
This function sets default title types (equivalent to the citation including | This function sets default title types (equivalent to the citation including |type=<default value>) for those templates that have defaults. | ||
|type=<default value>) for those templates that have defaults. Also handles the | Also handles the special case where it is desirable to omit the title type from the rendered citation (|type=none). | ||
special case where it is desirable to omit the title type from the rendered citation | |||
(|type=none). | |||
]] | ]] | ||
Line 909: | Line 892: | ||
--[[--------------------------< H Y P H E N _ T O _ D A S H >-------------------------------------------------- | --[[--------------------------< H Y P H E N _ T O _ D A S H >-------------------------------------------------- | ||
Converts a hyphen to a dash under certain conditions. The hyphen must separate | Converts a hyphen to a dash under certain conditions. The hyphen must separate like items; unlike items are | ||
like items; unlike items are returned unmodified. These forms are modified: | returned unmodified. These forms are modified: | ||
letter - letter (A - B) | letter - letter (A - B) | ||
digit - digit (4-5) | digit - digit (4-5) | ||
digit separator digit - digit separator digit (4.1-4.5 or 4-1-4-5) | digit separator digit - digit separator digit (4.1-4.5 or 4-1-4-5) | ||
letterdigit - letterdigit (A1-A5) (an optional separator between letter and | letterdigit - letterdigit (A1-A5) (an optional separator between letter and digit is supported – a.1-a.5 or a-1-a-5) | ||
digitletter - digitletter (5a - 5d) (an optional separator between letter and digit is supported – 5.a-5.d or 5-a-5-d) | |||
digitletter - digitletter (5a - 5d) (an optional separator between letter and | |||
any other forms are returned unmodified. | any other forms are returned unmodified. | ||
Line 930: | Line 911: | ||
end | end | ||
local accept; -- Boolean | local accept; -- Boolean | ||
str, accept = utilities.has_accept_as_written (str); -- remove accept-this-as-written markup when it wraps all of str | |||
if accept then | |||
return str; -- when markup removed, nothing to do, we're done | |||
end | |||
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 | |||
local out = {}; | local out = {}; | ||
Line 941: | Line 925: | ||
for _, item in ipairs (list) do -- for each item in the list | for _, item in ipairs (list) do -- for each item in the list | ||
if mw.ustring.match (item, '^%w*[%.%-]?%w+%s*[%-–—]%s*%w*[%.%-]?%w+$') then -- if a hyphenated range or has endash or emdash separators | |||
if | |||
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) | ||
item:match ('^%d+[%.%-]?%a+%s*%-%s*%d+[%.%-]?%a+$') or -- digitletter hyphen digitletter (optional separator between digit and letter) | item:match ('^%d+[%.%-]?%a+%s*%-%s*%d+[%.%-]?%a+$') or -- digitletter hyphen digitletter (optional separator between digit and letter) | ||
Line 953: | Line 936: | ||
end | end | ||
end | end | ||
item = utilities.has_accept_as_written (item); -- remove accept-this-as-written markup when it wraps all of str | |||
table.insert (out, item); -- add the (possibly modified) item to the output table | table.insert (out, item); -- add the (possibly modified) item to the output table | ||
end | end | ||
return table.concat (out, ', '); -- concatenate the output table into a comma separated string | |||
end | end | ||
--[[--------------------------< S A F E _ J O I N >----------------------------- | --[[--------------------------< S A F E _ J O I N >------------------------------------------------------------ | ||
Joins a sequence of strings together while checking for duplicate separation characters. | Joins a sequence of strings together while checking for duplicate separation characters. | ||
Line 1,006: | Line 983: | ||
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,018: | Line 995: | ||
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 -- if last three chars of str are sepc"] quoted external link | 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 -- if last two chars of str are sepc] external link | 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,029: | Line 1,006: | ||
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,044: | Line 1,021: | ||
end | end | ||
end | end | ||
str = str .. value; -- add it to the output string | str = str .. value; --add it to the output string | ||
end | end | ||
end | end | ||
Line 1,051: | Line 1,028: | ||
--[[--------------------------< I S _ S U F F I X >----------------------------- | --[[--------------------------< I S _ S U F F I X >------------------------------------------------------------ | ||
returns true is suffix is properly formed Jr, Sr, or ordinal in the range 1–9. | returns true is suffix is properly formed Jr, Sr, or ordinal in the range 1–9. Puncutation not allowed. | ||
Puncutation not allowed. | |||
]] | ]] | ||
Line 1,066: | Line 1,042: | ||
--[[--------------------< I S _ G O O D _ V A N C _ N A M E >------------------- | --[[--------------------------< I S _ G O O D _ V A N C _ N A M E >-------------------------------------------- | ||
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 | ||
(read ASCII) characters. When a name uses characters that contain diacritical | uses characters that contain diacritical marks, those characters are to converted to the corresponding Latin character. | ||
marks, those characters are to | When a name is written using a non-Latin alphabet or logogram, that name is to be transliterated into Latin characters. | ||
character. When a name is written using a non-Latin alphabet or logogram, that | These things are not currently possible in this module so are left to the editor to do. | ||
name is to be transliterated into Latin characters. | |||
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 in the four Unicode Latin character sets | ||
in the four Unicode Latin character sets | |||
[http://www.unicode.org/charts/PDF/U0000.pdf C0 Controls and Basic Latin] 0041–005A, 0061–007A | [http://www.unicode.org/charts/PDF/U0000.pdf C0 Controls and Basic Latin] 0041–005A, 0061–007A | ||
[http://www.unicode.org/charts/PDF/U0080.pdf C1 Controls and Latin-1 Supplement] 00C0–00D6, 00D8–00F6, 00F8–00FF | [http://www.unicode.org/charts/PDF/U0080.pdf C1 Controls and Latin-1 Supplement] 00C0–00D6, 00D8–00F6, 00F8–00FF | ||
Line 1,082: | Line 1,055: | ||
[http://www.unicode.org/charts/PDF/U0180.pdf Latin Extended-B] 0180–01BF, 01C4–024F | [http://www.unicode.org/charts/PDF/U0180.pdf Latin Extended-B] 0180–01BF, 01C4–024F | ||
|lastn= also allowed to contain hyphens, spaces, and apostrophes. | |lastn= also allowed to contain hyphens, spaces, and apostrophes. (http://www.ncbi.nlm.nih.gov/books/NBK7271/box/A35029/) | ||
|firstn= also allowed to contain hyphens, spaces, apostrophes, and periods | |firstn= also allowed to contain hyphens, spaces, apostrophes, and periods | ||
This original test: | This original test: | ||
if nil == mw.ustring.find (last, "^[A-Za-zÀ-ÖØ-öø-ƿDŽ-ɏ%-%s%']*$") | if nil == mw.ustring.find (last, "^[A-Za-zÀ-ÖØ-öø-ƿDŽ-ɏ%-%s%']*$") or nil == mw.ustring.find (first, "^[A-Za-zÀ-ÖØ-öø-ƿDŽ-ɏ%-%s%'%.]+[2-6%a]*$") then | ||
was written outside of the code editor and pasted here because the code editor gets confused between character insertion point and cursor position. | |||
was written outside of the code editor and pasted here because the code editor | The test has been rewritten to use decimal character escape sequence for the individual bytes of the Unicode characters so that it is not necessary | ||
gets confused between character insertion point and cursor position. The test has | to use an external editor to maintain this code. | ||
been rewritten to use decimal character escape sequence for the individual bytes | |||
of the Unicode characters so that it is not necessary to use an external editor | |||
to maintain this code. | |||
\195\128-\195\150 – À-Ö (U+00C0–U+00D6 – C0 controls) | \195\128-\195\150 – À-Ö (U+00C0–U+00D6 – C0 controls) | ||
Line 1,102: | Line 1,071: | ||
]] | ]] | ||
local function is_good_vanc_name (last, first, suffix | local function is_good_vanc_name (last, first, suffix) | ||
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,111: | Line 1,080: | ||
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); | ||
return false; -- not a name with an appropriate suffix | return false; -- not a name with an appropriate suffix | ||
end | end | ||
Line 1,117: | Line 1,086: | ||
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']); | ||
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,128: | Line 1,097: | ||
Attempts to convert names to initials in support of |name-list-style=vanc. | Attempts to convert names to initials in support of |name-list-style=vanc. | ||
Names in |firstn= may be separated by spaces or hyphens, or for initials, a period. | Names in |firstn= may be separated by spaces or hyphens, or for initials, a period. See http://www.ncbi.nlm.nih.gov/books/NBK7271/box/A35062/. | ||
See http://www.ncbi.nlm.nih.gov/books/NBK7271/box/A35062/. | |||
Vancouver style requires family rank designations (Jr, II, III, etc.) to be rendered | Vancouver style requires family rank designations (Jr, II, III, etc.) to be rendered as Jr, 2nd, 3rd, etc. See http://www.ncbi.nlm.nih.gov/books/NBK7271/box/A35085/. | ||
as Jr, 2nd, 3rd, etc. See http://www.ncbi.nlm.nih.gov/books/NBK7271/box/A35085/. | This code only accepts and understands generational suffix in the Vancouver format because Roman numerals look like, and can be mistaken for, initials. | ||
This code only accepts and understands generational suffix in the Vancouver format | |||
because Roman numerals look like, and can be mistaken for, initials. | |||
This function uses ustring functions because firstname initials may be any of the | This function uses ustring functions because firstname initials may be any of the Unicode Latin characters accepted by is_good_vanc_name (). | ||
Unicode Latin characters accepted by is_good_vanc_name (). | |||
]] | ]] | ||
local function reduce_to_initials(first | local function reduce_to_initials(first) | ||
local name, suffix = mw.ustring.match(first, "^(%u+) ([%dJS][%drndth]+)$"); | local name, suffix = mw.ustring.match(first, "^(%u+) ([%dJS][%drndth]+)$"); | ||
Line 1,154: | Line 1,119: | ||
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); -- 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,177: | Line 1,142: | ||
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 | ||
end | end | ||
Line 1,186: | Line 1,151: | ||
--[[--------------------------< L I S T _ P E O P L E >-------------------------- | --[[--------------------------< L I S T _ P E O P L E >------------------------------------------------------- | ||
Formats a list of people (authors, contributors, editors, interviewers, translators) | Formats a list of people (e.g. authors, contributors, editors, interviewers, translators) | ||
names in the list will be linked when | names in the list will be linked when | ||
|<name>-link= has a value | |<name>-link= has a value | ||
|<name>-mask- does NOT have a value; masked names are presumed to have been | |<name>-mask- does NOT have a value; masked names are presumed to have been rendered previously so should have been linked there | ||
when |<name>-mask=0, the associated name is not rendered | when |<name>-mask=0, the associated name is not rendered | ||
Line 1,204: | Line 1,168: | ||
local format = control.format; | local format = control.format; | ||
local maximum = control.maximum; | local maximum = control.maximum; | ||
local lastauthoramp = control.lastauthoramp; -- TODO: delete after deprecation | |||
local name_list = {}; | local name_list = {}; | ||
Line 1,209: | Line 1,174: | ||
sep = cfg.presentation['sep_nl_vanc']; -- name-list separator between names is a comma | sep = cfg.presentation['sep_nl_vanc']; -- name-list separator between names is a comma | ||
namesep = cfg.presentation['sep_name_vanc']; -- last/first separator is a space | namesep = cfg.presentation['sep_name_vanc']; -- last/first separator is a space | ||
lastauthoramp = nil; -- TODO: delete after deprecation -- unset because isn't used by Vancouver style | |||
else | else | ||
sep = cfg.presentation['sep_nl']; -- name-list separator between names is a semicolon | sep = cfg.presentation['sep_nl']; -- name-list separator between names is a semicolon | ||
Line 1,231: | Line 1,197: | ||
local n = tonumber (mask); -- convert to a number if it can be converted; nil else | local n = tonumber (mask); -- convert to a number if it can be converted; nil else | ||
if n then | if n then | ||
one = 0 ~= n and string.rep("—", n) or nil; -- make a string of (n > 0) mdashes, nil else, to replace name | one = 0 ~= n and string.rep("—",n) or nil; -- make a string of (n > 0) mdashes, nil else, to replace name | ||
person.link = nil; -- don't create link to name if name is replaces with mdash string or has been set nil | person.link = nil; -- don't create link to name if name is replaces with mdash string or has been set nil | ||
else | else | ||
Line 1,243: | Line 1,209: | ||
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 | if not person.corporate and is_good_vanc_name (one, first) then -- and name is all Latin characters; corporate authors not tested | ||
first = reduce_to_initials (first | first = reduce_to_initials (first); -- attempt to convert first name(s) to initials | ||
end | end | ||
end | end | ||
Line 1,263: | Line 1,229: | ||
if 0 < count then | if 0 < count then | ||
if 1 < count and not etal then | if 1 < count and not etal then | ||
if 'amp' == format then | if 'amp' == format or utilities.is_set (lastauthoramp) then -- TODO: delete lastauthoramp after deprecation | ||
name_list[#name_list-2] = " & "; -- replace last separator with ampersand text | name_list[#name_list-2] = " & "; -- replace last separator with ampersand text | ||
elseif 'and' == format then | elseif 'and' == format then | ||
Line 1,284: | Line 1,250: | ||
end | end | ||
--[[--------------------------< A N C H O R _ I D >------------------------------------------------------------ | |||
namelist is one of the contributor-, author-, or editor-name lists chosen in that | Generates a CITEREF anchor ID if we have at least one name or a date. Otherwise returns an empty string. | ||
order. year is Year or anchor_year. | |||
namelist is one of the contributor-, author-, or editor-name lists chosen in that order. year is Year or anchor_year. | |||
]] | ]] | ||
local function | local function anchor_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 | ||
--[[---------------------< N A M E _ H A S _ E T A L >-------------------------- | --[[--------------------------< N A M E _ H A S _ E T A L >---------------------------------------------------- | ||
Evaluates the content of name parameters (author, editor, etc.) for variations on | Evaluates the content of name parameters (author, editor, etc.) for variations on the theme of et al. If found, | ||
the theme of et al. If found, the et al. is removed, a flag is set to true and | the et al. is removed, a flag is set to true and the function returns the modified name and the flag. | ||
the function returns the modified name and the flag. | |||
This function never sets the flag to false but returns | This function never sets the flag to false but returns it's previous state because it may have been set by | ||
it may have been set by previous passes through this function or by the associated | previous passes through this function or by the associated |display-<names>=etal parameter | ||
|display-<names>=etal parameter | |||
]] | ]] | ||
Line 1,325: | Line 1,288: | ||
if utilities.is_set (name) then -- name can be nil in which case just return | if utilities.is_set (name) then -- name can be nil in which case just return | ||
local patterns = cfg.et_al_patterns; | local patterns = cfg.et_al_patterns; --get patterns from configuration | ||
for _, pattern in ipairs (patterns) do -- loop through all of the patterns | for _, pattern in ipairs (patterns) do -- loop through all of the patterns | ||
Line 1,342: | Line 1,305: | ||
--[[---------------------< 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 maint cat when name parameter value does not contain letters. Does not catch mixed alphanumeric names so | ||
mixed alphanumeric names so |last=A. Green (1922-1987) does not get caught in the | |last=A. Green (1922-1987) does not get caught in the current version of this test but |first=(1888) is caught. | ||
current version of this test but |first=(1888) is caught. | |||
returns nothing | returns nothing | ||
Line 1,361: | Line 1,323: | ||
--[[-------------------< N A M E _ H A S _ E D _ M A R K U P >------------------ | --[[--------------------------< N A M E _ H A S _ E D _ M A R K U P >------------------------------------------ | ||
Evaluates the content of author and editor parameters for extraneous editor annotations: | Evaluates the content of author and editor parameters for extraneous editor annotations: ed, ed., eds, (Ed.), etc. | ||
ed, ed., eds, (Ed.), etc. These | These annotation do not belong in author parameters and are redundant in editor parameters. If found, the function | ||
are redundant in editor parameters. If found, the function adds the editor markup | adds the editor markup maintenance category. | ||
maintenance category. | |||
returns nothing | returns nothing | ||
Line 1,386: | Line 1,347: | ||
--[[-----------------< N A M E _ H A S _ M U L T _ N A M E S >------------------ | --[[--------------------------< N A M E _ H A S _ M U L T _ N A M E S >---------------------------------------- | ||
Evaluates the content of last/surname (authors etc.) parameters for multiple names. | Evaluates the content of last/surname (authors etc.) parameters for multiple names. Multiple names are indicated | ||
Multiple names are indicated if there is more than one comma or any | if there is more than one comma or any semicolons. If found, the function adds the multiple name maintenance category. | ||
If | |||
returns nothing | returns nothing | ||
Line 1,398: | Line 1,357: | ||
local function name_has_mult_names (name, list_name) | local function name_has_mult_names (name, list_name) | ||
local _, commas, semicolons | local _, commas, semicolons; | ||
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 | ||
_, semicolons = name:gsub (';', ''); -- count the number of semicolons | _, semicolons = name:gsub (';', ''); -- count the number of semicolons | ||
if 1 < commas or 0 < semicolons then | |||
if 1 < commas or 0 < | |||
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,419: | Line 1,369: | ||
--[[------------------------< N A M E _ C H E C K S >--------------------------- | --[[--------------------------< N A M E _ C H E C K S >-------------------------------------------------------- | ||
This function calls various name checking functions used to validate the content | This function calls various name checking functions used to validate the content of the various name-holding | ||
of the various name-holding parameters. | parameters. | ||
]] | ]] | ||
Line 1,435: | Line 1,385: | ||
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 (last only) | ||
name_has_ed_markup (last, list_name); -- check for extraneous 'editor' annotation | name_has_ed_markup (last, list_name); -- check for extraneous 'editor' annotation | ||
name_is_numeric (last, list_name); -- check for names that are | name_is_numeric (last, list_name); -- check for names that are compsed of digits and punctuation | ||
end | end | ||
end | end | ||
Line 1,442: | Line 1,392: | ||
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 | name_is_numeric (first, list_name); -- check for names that are compsed of digits and punctuation | ||
end | end | ||
end | end | ||
Line 1,452: | Line 1,402: | ||
--[[----------------------< E X T R A C T _ N A M E S >------------------------- | --[[--------------------------< E X T R A C T _ N A M E S >---------------------------------------------------- | ||
Gets name list from the input arguments | Gets name list from the input arguments | ||
Searches through args in sequential order to find |lastn= and |firstn= parameters | Searches through args in sequential order to find |lastn= and |firstn= parameters (or their aliases), and their matching link and mask parameters. | ||
(or their aliases), and their matching link and mask parameters. Stops searching | Stops searching when both |lastn= and |firstn= are not found in args after two sequential attempts: found |last1=, |last2=, and |last3= but doesn't | ||
when both |lastn= and |firstn= are not found in args after two sequential attempts: | find |last4= and |last5= then the search is done. | ||
found |last1=, |last2=, and |last3= but doesn't find |last4= and |last5= then the | |||
search is done. | |||
This function emits an error message when there is a |firstn= without a matching | This function emits an error message when there is a |firstn= without a matching |lastn=. When there are 'holes' in the list of last names, |last1= and |last3= | ||
|lastn=. When there are 'holes' in the list of last names, |last1= and |last3= | are present but |last2= is missing, an error message is emitted. |lastn= is not required to have a matching |firstn=. | ||
are present but |last2= is missing, an error message is emitted. |lastn= is not | |||
required to have a matching |firstn=. | |||
When an author or editor parameter contains some form of 'et al.', the 'et al.' | When an author or editor parameter contains some form of 'et al.', the 'et al.' is stripped from the parameter and a flag (etal) returned | ||
is stripped from the parameter and a flag (etal) returned that will cause list_people() | that will cause list_people() to add the static 'et al.' text from Module:Citation/CS1/Configuration. This keeps 'et al.' out of the | ||
to add the static 'et al.' text from Module:Citation/CS1/Configuration. This keeps | template's metadata. When this occurs, the page is added to a maintenance category. | ||
'et al.' out of the template's metadata. When this occurs, | |||
]] | ]] | ||
Line 1,527: | Line 1,472: | ||
--[[---------------------< G E T _ I S O 6 3 9 _ C O D E >---------------------- | --[[--------------------------< 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. | ||
Returns the language name and associated two- or three-character code. Because | Returns the language name and associated two- or three-character code. Because case of the source may be incorrect | ||
case of the source may be incorrect or different from the case that WikiMedia uses, | or different from the case that WikiMedia uses, the name comparisons are done in lower case and when a match is | ||
the name comparisons are done in lower case and when a match is found, the Wikimedia | found, the Wikimedia version (assumed to be correct) is returned along with the code. When there is no match, we | ||
version (assumed to be correct) is returned along with the code. When there is no | return the original language name string. | ||
match, we return the original language name string. | |||
mw.language.fetchLanguageNames(<local wiki language>, 'all') returns a list of | mw.language.fetchLanguageNames(<local wiki language>, 'all') returns a list of languages that in some cases may include | ||
languages that in some cases may include extensions. For example, code 'cbk-zam' | extensions. For example, code 'cbk-zam' and its associated name 'Chavacano de Zamboanga' (MediaWiki does not support | ||
and its associated name 'Chavacano de Zamboanga' (MediaWiki does not support | code 'cbk' or name 'Chavacano'. Most (all?) of these languages are not used a 'language' codes per se, rather they | ||
code 'cbk' or name 'Chavacano'. Most (all?) of these languages are not used a | are used as sub-domain names: cbk-zam.wikipedia.org. A list of language names and codes supported by fetchLanguageNames() | ||
'language' codes per se, rather they are used as sub-domain names: cbk-zam.wikipedia.org. | can be found at Template:Citation Style documentation/language/doc | ||
A list of language names and codes supported by fetchLanguageNames() can be found | |||
at Template:Citation Style documentation/language/doc | |||
Names that are included in the list will be found if that name is provided in the | Names that are included in the list will be found if that name is provided in the |language= parameter. For example, | ||
|language= parameter. For example, if |language=Chavacano de Zamboanga, that name | if |language=Chavacano de Zamboanga, that name will be found with the associated code 'cbk-zam'. When names are found | ||
will be found with the associated code 'cbk-zam'. When names are found and the | and the associated code is not two or three characters, this function returns only the WikiMedia language name. | ||
associated code is not two or three characters, this function returns only the | |||
WikiMedia language name. | |||
Some language names have multiple entries under different codes: | Some language names have multiple entries under different codes: | ||
Line 1,583: | Line 1,523: | ||
--[[-------------------< L A N G U A G E _ P A R A M E T E R >------------------ | --[[--------------------------< L A N G U A G E _ P A R A M E T E R >------------------------------------------ | ||
Gets language name from a provided two- or three-character ISO 639 code. If a code | Gets language name from a provided two- or three-character ISO 639 code. If a code is recognized by MediaWiki, | ||
is recognized by MediaWiki, use the returned name; if not, then use the value that | use the returned name; if not, then use the value that was provided with the language parameter. | ||
was provided with the language parameter. | |||
When |language= contains a recognized language (either code or name), the page is | When |language= contains a recognized language (either code or name), the page is assigned to the category for | ||
assigned to the category for that code: Category:Norwegian-language sources (no). | that code: Category:Norwegian-language sources (no). For valid three-character code languages, the page is assigned | ||
For valid three-character code languages, the page is assigned to the single category | to the single category for '639-2' codes: Category:CS1 ISO 639-2 language sources. | ||
for '639-2' codes: Category:CS1 ISO 639-2 language sources. | |||
Languages that are the same as the local wiki are not categorized. MediaWiki does | Languages that are the same as the local wiki are not categorized. MediaWiki does not recognize three-character | ||
not recognize three-character equivalents of two-character codes: code 'ar' is | equivalents of two-character codes: code 'ar' is recognized but code 'ara' is not. | ||
recognized but code 'ara' is not. | |||
This function supports multiple languages in the form |language=nb, French, th | This function supports multiple languages in the form |language=nb, French, th where the language names or codes are | ||
where the language names or codes are separated from each other by commas with | separated from each other by commas with optional space characters. | ||
optional space characters. | |||
]] | ]] | ||
Line 1,665: | Line 1,601: | ||
end | end | ||
--[[-----------------------< S E T _ C S _ S T Y L E >-------------------------- | |||
--[[--------------------------< S E T _ C S 1 _ S T Y L E >---------------------------------------------------- | |||
Returns | |||
Set style settings for CS1 citation templates. Returns separator and postscript settings | |||
At en.wiki, for cs1: | |||
ps gets: '.' | |||
sep gets: '.' | |||
]] | ]] | ||
local function | |||
if utilities.is_set( | local function set_cs1_style (ps) | ||
if not utilities.is_set (ps) then -- unless explicitly set to something | |||
ps = cfg.presentation['ps_cs1']; -- terminate the rendered citation | |||
end | end | ||
return cfg.presentation[' | return cfg.presentation['sep_cs1'], ps; -- element separator | ||
end | end | ||
--[[--------------------------< S E T _ S T Y L E >----------------------------- | |||
--[[--------------------------< S E T _ C S 2 _ S T Y L E >---------------------------------------------------- | |||
]] | Set style settings for CS2 citation templates. Returns separator, postscript, ref settings | ||
local function set_style (mode, | At en.wiki, for cs2: | ||
ps gets: '' (empty string - no terminal punctuation) | |||
sep gets: ',' | |||
]] | |||
local function set_cs2_style (ps, ref) | |||
if not utilities.is_set (ps) then -- if |postscript= has not been set, set cs2 default | |||
ps = cfg.presentation['ps_cs2']; -- terminate the rendered citation | |||
end | |||
if not utilities.is_set (ref) then -- if |ref= is not set | |||
ref = "harv"; -- set default |ref=harv | |||
end | |||
return cfg.presentation['sep_cs2'], ps, ref; -- element separator | |||
end | |||
--[[--------------------------< G E T _ S E T T I N G S _ F R O M _ C I T E _ C L A S S >---------------------- | |||
When |mode= is not set or when its value is invalid, use config.CitationClass and parameter values to establish | |||
rendered style. | |||
]] | |||
local function get_settings_from_cite_class (ps, ref, cite_class) | |||
local sep; | |||
if (cite_class == "citation") then -- for citation templates (CS2) | |||
sep, ps, ref = set_cs2_style (ps, ref); | |||
else -- not a citation template so CS1 | |||
sep, ps = set_cs1_style (ps); | |||
end | |||
return sep, ps, ref -- return them all | |||
end | |||
--[[--------------------------< S E T _ S T Y L E >------------------------------------------------------------ | |||
Establish basic style settings to be used when rendering the citation. Uses |mode= if set and valid or uses | |||
config.CitationClass from the template's #invoke: to establish style. | |||
]] | |||
local function set_style (mode, ps, ref, cite_class) | |||
local sep; | local sep; | ||
if 'cs2' == mode then | if 'cs2' == mode then -- if this template is to be rendered in CS2 (citation) style | ||
sep, | sep, ps, ref = set_cs2_style (ps, ref); | ||
elseif 'cs1' == mode then | elseif 'cs1' == mode then -- if this template is to be rendered in CS1 (cite xxx) style | ||
sep, ps = set_cs1_style (ps); | |||
else -- anything but cs1 or cs2 | |||
sep, | sep, ps, ref = get_settings_from_cite_class (ps, ref, cite_class); -- get settings based on the template's CitationClass | ||
else | |||
sep, | |||
end | end | ||
if cfg.keywords_xlate[ | if cfg.keywords_xlate[ps:lower()] == 'none' then -- if assigned value is 'none' then | ||
ps = ''; -- set to empty string | |||
end | end | ||
return sep, | return sep, ps, ref | ||
end | end | ||
Determines if a URL has the file extension that is one of the PDF file extensions | --[=[-------------------------< I S _ P D F >------------------------------------------------------------------ | ||
used by [[MediaWiki:Common.css]] when applying the PDF icon to external links. | |||
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. | |||
returns true if file extension is one of the recognized extensions, else false | returns true if file extension is one of the recognized extensions, else false | ||
Line 1,728: | Line 1,699: | ||
--[[--------------------------< S T Y L E _ F O R M A T >----------------------- | --[[--------------------------< S T Y L E _ F O R M A T >------------------------------------------------------ | ||
Applies CSS style to |format=, |chapter-format=, etc. Also emits an error message | Applies CSS style to |format=, |chapter-format=, etc. Also emits an error message if the format parameter does | ||
if the format parameter does not have a matching URL parameter. If the format parameter | not have a matching URL parameter. If the format parameter is not set and the URL contains a file extension that | ||
is not set and the URL contains a file extension that is recognized as a PDF document | is recognized as a PDF document by MediaWiki's commons.css, this code will set the format parameter to (PDF) with | ||
by MediaWiki's commons.css, this code will set the format parameter to (PDF) with | |||
the appropriate styling. | the appropriate styling. | ||
Line 1,753: | Line 1,723: | ||
--[[---------------------< G E T _ D I S P L A Y _ N A M E S >------------------ | --[[--------------------------< G E T _ D I S P L A Y _ N A M E S >-------------------------------------------- | ||
Returns a number that defines the number of names displayed for author and editor | Returns a number that defines the number of names displayed for author and editor name lists and a Boolean flag | ||
name lists and a Boolean flag to indicate when et al. should be appended to the name list. | to indicate when et al. should be appended to the name list. | ||
When the value assigned to |display-xxxxors= is a number greater than or equal to zero, | When the value assigned to |display-xxxxors= is a number greater than or equal to zero, return the number and | ||
return the number and the previous state of the 'etal' flag (false by default | the previous state of the 'etal' flag (false by default but may have been set to true if the name list contains | ||
but may have been set to true if the name list contains some variant of the text 'et al.'). | some variant of the text 'et al.'). | ||
When the value assigned to |display-xxxxors= is the keyword 'etal', return a number | When the value assigned to |display-xxxxors= is the keyword 'etal', return a number that is one greater than the | ||
that is one greater than the number of authors in the list and set the 'etal' flag true. | number of authors in the list and set the 'etal' flag true. This will cause the list_people() to display all of | ||
This will cause the list_people() to display all of the names in the name list followed by 'et al.' | the names in the name list followed by 'et al.' | ||
In all other cases, returns nil and the previous state of the 'etal' flag. | In all other cases, returns nil and the previous state of the 'etal' flag. | ||
Line 1,776: | Line 1,746: | ||
]] | ]] | ||
local function get_display_names (max, count, list_name, etal | local function get_display_names (max, count, list_name, etal) | ||
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,784: | Line 1,754: | ||
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', {cfg.special_case_translation [list_name], 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', {cfg.special_case_translation [list_name], 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,797: | Line 1,767: | ||
--[[----------< E X T R A _ T E X T _ I N _ P A G E _ C H E C K >--------------- | --[[--------------------------< E X T R A _ T E X T _ I N _ P A G E _ C H E C K >------------------------------ | ||
Adds | Adds page to Category:CS1 maint: extra text if |page= or |pages= has what appears to be some form of p. or pp. | ||
some form of p. or pp. abbreviation in the first characters of the parameter content. | abbreviation in the first characters of the parameter content. | ||
check | check Page and Pages for extraneous p, p., pp, and pp. at start of parameter value: | ||
good pattern: '^P[^%.P%l]' matches when page begins PX or P# but not Px | good pattern: '^P[^%.P%l]' matches when |page(s)= begins PX or P# but not Px where x and X are letters and # is a dgiit | ||
bad pattern: '^[Pp][Pp]' matches matches when |page(s)= begins pp or pP or Pp or PP | |||
bad pattern: | |||
]] | ]] | ||
local function extra_text_in_page_check ( | local function extra_text_in_page_check (page) | ||
if not | local good_pattern = '^P[^%.Pp]'; -- ok to begin with uppercase P: P7 (pg 7 of section P) but not p123 (page 123) TODO: add Gg for PG or Pg? | ||
local bad_pattern = '^[Pp]?[Pp]%.?[ %d]'; | |||
if not page:match (good_pattern) and (page:match (bad_pattern) or page:match ('^[Pp]ages?')) then | |||
utilities.set_message ('maint_extra_text'); -- add maint cat; | |||
end | |||
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 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 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 | local wl_type, label, link; -- wl_type not used here; just a place holder | ||
local i = 1; | local i = 1; | ||
Line 1,882: | Line 1,807: | ||
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,938: | Line 1,863: | ||
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 v_name:match ('^%(%(.+%)%)$') then -- corporate authors are wrapped in doubled parentheses to suppress vanc formatting and error detection | |||
-- last = v_name:match ('^%(%((.+)%)%)$') -- remove doubled parentheses | |||
if accept_name then | if accept_name then | ||
last = v_name; | last = v_name; | ||
Line 1,943: | Line 1,870: | ||
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); | ||
end | end | ||
local lastfirstTable = {} | local lastfirstTable = {} | ||
Line 1,957: | Line 1,884: | ||
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); | ||
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']); -- 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.name); -- matches a space between two initials | ||
end | end | ||
else | else | ||
Line 1,971: | Line 1,898: | ||
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); -- too many initials; mixed case initials (which may be ok Romanization); hyphenated initials | ||
end | end | ||
is_good_vanc_name (last, first, suffix | is_good_vanc_name (last, first, suffix); -- 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,980: | Line 1,907: | ||
else | else | ||
if not corporate then | if not corporate then | ||
is_good_vanc_name (last, '' | is_good_vanc_name (last, ''); | ||
end | end | ||
end | end | ||
Line 1,995: | Line 1,922: | ||
Select one of |authors=, |authorn= / |lastn / firstn=, or |vauthors= as the source of the author name list or | Select one of |authors=, |authorn= / |lastn / firstn=, or |vauthors= as the source of the author name list or | ||
select one of |editorn= / editor-lastn= / |editor-firstn= or |veditors= as the source of the editor name list. | select one of |editors=, |editorn= / editor-lastn= / |editor-firstn= or |veditors= as the source of the editor name list. | ||
Only one of these appropriate three will be used. The hierarchy is: |authorn= (and aliases) highest and |authors= lowest | Only one of these appropriate three will be used. The hierarchy is: |authorn= (and aliases) highest and |authors= lowest and | ||
|editorn= (and aliases) highest and | | similarly, |editorn= (and aliases) highest and |editors= lowest | ||
When looking for |authorn= / |editorn= parameters, test |xxxxor1= and |xxxxor2= (and all of their aliases); stops after the second | When looking for |authorn= / |editorn= parameters, test |xxxxor1= and |xxxxor2= (and all of their aliases); stops after the second | ||
Line 2,006: | Line 1,933: | ||
Emits an error message when more than one xxxxor name source is provided. | Emits an error message when more than one xxxxor name source is provided. | ||
In this function, vxxxxors = vauthors or veditors; xxxxors = authors as appropriate. | In this function, vxxxxors = vauthors or veditors; xxxxors = authors or editors as appropriate. | ||
]] | ]] | ||
Line 2,095: | Line 2,022: | ||
if 'magazine' == cite_class or (utilities.in_array (cite_class, {'citation', 'map'}) and 'magazine' == origin) then | if 'magazine' == cite_class or (utilities.in_array (cite_class, {'citation', 'map'}) and 'magazine' == origin) then | ||
if utilities.is_set (volume) and utilities.is_set (issue) then | if utilities.is_set (volume) and utilities.is_set (issue) then | ||
return wrap_msg ('vol-no', {sepc, | return wrap_msg ('vol-no', {sepc, volume, issue}, lower); | ||
elseif utilities.is_set (volume) then | elseif utilities.is_set (volume) then | ||
return wrap_msg ('vol', {sepc, | return wrap_msg ('vol', {sepc, volume}, lower); | ||
else | else | ||
return wrap_msg ('issue', {sepc, issue}, lower); | return wrap_msg ('issue', {sepc, issue}, lower); | ||
Line 2,111: | Line 2,038: | ||
if utilities.is_set (volume) then | if utilities.is_set (volume) then | ||
if volume:match ('^[MDCLXVI]+$') or volume:match ('^%d+$') then -- volume value is all digits or all uppercase Roman numerals | if volume:match ('^[MDCLXVI]+$') or volume:match ('^%d+$') then -- volume value is all digits or all uppercase Roman numerals | ||
vol = utilities.substitute (cfg.presentation['vol-bold'], {sepc, volume}); -- render in bold face | vol = utilities.substitute (cfg.presentation['vol-bold'], {sepc, hyphen_to_dash(volume)}); -- render in bold face | ||
elseif (4 < mw.ustring.len(volume)) then -- not all digits or Roman numerals and longer than 4 characters | elseif (4 < mw.ustring.len(volume)) then -- not all digits or Roman numerals and longer than 4 characters | ||
vol = utilities.substitute (cfg.messages['j-vol'], {sepc, | vol = utilities.substitute (cfg.messages['j-vol'], {sepc, volume}); -- not bold | ||
utilities.add_prop_cat ('long_vol'); | utilities.add_prop_cat ('long_vol'); | ||
else -- four or less characters | else -- four or less characters | ||
vol = utilities.substitute (cfg.presentation['vol-bold'], {sepc, hyphen_to_dash (volume)}); -- bold | vol = utilities.substitute (cfg.presentation['vol-bold'], {sepc, hyphen_to_dash(volume)}); -- bold | ||
end | end | ||
end | end | ||
Line 2,184: | Line 2,111: | ||
If any of these are interwiki links to Wikisource, returns the label portion of the interwiki-link as plain text | If any of these are interwiki links to Wikisource, returns the label portion of the interwiki-link as plain text | ||
for use in COinS. This COinS thing is done because here we convert an interwiki-link to | for use in COinS. This COinS thing is done because here we convert an interwiki-link to and external link and | ||
add an icon span around that; get_coins_pages() doesn't know about the span. TODO: should it? | add an icon span around that; get_coins_pages() doesn't know about the span. TODO: should it? | ||
Line 2,194: | Line 2,121: | ||
]] | ]] | ||
local function insource_loc_get (page | local function insource_loc_get (page, pages, 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,202: | Line 2,129: | ||
at = ''; | at = ''; | ||
end | end | ||
extra_text_in_page_check (page | extra_text_in_page_check (page); -- add this page to maint cat if |page= value begins with what looks like p. or pp. | ||
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,214: | Line 2,141: | ||
at = ''; -- unset | at = ''; -- unset | ||
end | end | ||
extra_text_in_page_check (pages | extra_text_in_page_check (pages); -- add this page to maint cat if |pages= value begins with what looks like p. or pp. | ||
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,232: | Line 2,159: | ||
return page, pages, at, coins_pages; | return page, pages, at, coins_pages; | ||
end | end | ||
Line 2,362: | Line 2,272: | ||
local function is_generic_title (title) | local function is_generic_title (title) | ||
title = mw.ustring.lower(title); -- switch title to lower case | title = mw.ustring.lower(title); -- switch title to lower case | ||
for _, generic_title in ipairs (cfg.special_case_translation['generic_titles']) do | for _, generic_title in ipairs (cfg.special_case_translation['generic_titles']) do --spin through the list of known generic title fragments | ||
if title:find (generic_title['en'][1], 1, generic_title['en'][2]) then | if title:find (generic_title['en'][1], 1, generic_title['en'][2]) then | ||
return true; -- found English generic title so done | return true; -- found English generic title so done | ||
Line 2,376: | Line 2,286: | ||
--[[--------------------------< I S _ A R C H I V E D _ C O P Y >---------------------------------------------- | --[[--------------------------< I S _ A R C H I V E D _ C O P Y >---------------------------------------------- | ||
compares |title= to 'Archived copy' ( | compares |title= to 'Archived copy' (place holder added by bots that can't find proper title); if matches, return true; nil else | ||
]] | ]] | ||
Line 2,398: | Line 2,308: | ||
]] | ]] | ||
local function citation0( config, args ) | local function citation0( config, args) | ||
--[[ | --[[ | ||
Load Input Parameters | Load Input Parameters | ||
Line 2,408: | Line 2,318: | ||
-- 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 Mode = is_valid_parameter_value (A['Mode'], A:ORIGIN('Mode'), cfg.keywords_lists['mode'], ''); | |||
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,420: | Line 2,333: | ||
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,432: | Line 2,345: | ||
end | end | ||
end | end | ||
local Others = A['Others']; | |||
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= | ||
local Editors; | |||
do -- to limit scope of selected | do -- to limit scope of selected | ||
local selected = select_author_editor_source (A['Veditors'], | local selected = select_author_editor_source (A['Veditors'], A['Editors'], args, 'EditorList'); | ||
if 1 == selected then | if 1 == selected then | ||
e, editor_etal = extract_names (args, 'EditorList'); -- fetch editor list from |editorn= / |editor-lastn= / |editor-firstn=, |editor-linkn=, and |editor-maskn= | e, editor_etal = extract_names (args, 'EditorList'); -- fetch editor list from |editorn= / |editor-lastn= / |editor-firstn=, |editor-linkn=, and |editor-maskn= | ||
elseif 2 == selected then | elseif 2 == selected then | ||
NameListStyle = 'vanc'; | NameListStyle = 'vanc'; -- override whatever |name-list-style= might be | ||
e, editor_etal = parse_vauthors_veditors (args, args.veditors, 'EditorList'); -- fetch editor list from |veditors=, |editor-linkn=, and |editor-maskn= | e, editor_etal = parse_vauthors_veditors (args, args.veditors, 'EditorList'); -- fetch editor list from |veditors=, |editor-linkn=, and |editor-maskn= | ||
elseif 3 == selected then | |||
Editors = A['Editors']; -- use content of |editors= | |||
end | end | ||
end | end | ||
local translator_etal; | |||
local t = {}; -- translators list from |translator-lastn= / translator-firstn= pairs | |||
local Translators; -- assembled translators name list | |||
t = extract_names (args, 'TranslatorList'); -- fetch translator list from |translatorn= / |translator-lastn=, -firstn=, -linkn=, -maskn= | |||
local interviewer_etal; | |||
local interviewers_list = {}; | |||
local Interviewers; -- used later | |||
interviewers_list = extract_names (args, 'InterviewerList'); -- process preferred interviewers parameters | |||
local contributor_etal; | |||
local c = {}; -- contributors list from |contributor-lastn= / contributor-firstn= pairs | |||
local Contributors; -- assembled contributors name list | |||
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' == A:ORIGIN ('Chapter') then | ||
Contribution = Chapter; | Contribution = A['Chapter']; -- get the name of the contribution | ||
end | end | ||
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,474: | Line 2,405: | ||
end | end | ||
if utilities.is_set (Others) then | |||
if 0 == #a and 0 == #e then -- add maint cat when |others= has value and used without |author=, |editor= | |||
utilities.set_message ('maint_others'); | |||
end | |||
end | |||
local Year = A['Year']; | |||
local PublicationDate = A['PublicationDate']; | |||
local OrigDate = A['OrigDate']; | |||
local Date = A['Date']; | |||
local LayDate = A['LayDate']; | |||
------------------------------------------------- Get title data | |||
local Title = A['Title']; | local Title = A['Title']; | ||
local ScriptTitle = A['ScriptTitle']; | |||
local BookTitle = A['BookTitle']; | |||
local Conference = A['Conference']; | |||
local TransTitle = A['TransTitle']; | |||
local TransTitle_origin = A:ORIGIN ('TransTitle'); | |||
local TitleNote = A['TitleNote']; | |||
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; | auto_select = TitleLink; -- remember selection for later | ||
TitleLink = ''; | TitleLink = ''; -- treat as if |title-link= would have been empty | ||
end | end | ||
Line 2,488: | Line 2,437: | ||
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' == A:ORIGIN ('Chapter') 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 ScriptChapter = A['ScriptChapter']; | ||
local Periodical_origin = ''; | local ScriptChapter_origin = A:ORIGIN ('ScriptChapter'); | ||
if utilities.is_set (Periodical) then | local ChapterLink -- = A['ChapterLink']; -- deprecated as a parameter but still used internally by cite episode | ||
Periodical_origin = A:ORIGIN('Periodical'); -- get the name of the periodical parameter | local TransChapter = A['TransChapter']; | ||
local TransChapter_origin = A:ORIGIN ('TransChapter'); | |||
local TitleType = A['TitleType']; | |||
local Degree = A['Degree']; | |||
local Docket = A['Docket']; | |||
local ArchiveFormat = A['ArchiveFormat']; | |||
local ArchiveDate; | |||
local ArchiveURL; | |||
ArchiveURL, ArchiveDate = archive_url_check (A['ArchiveURL'], A['ArchiveDate']) | |||
local UrlStatus = is_valid_parameter_value (A['UrlStatus'], A:ORIGIN('UrlStatus'), cfg.keywords_lists['url-status'], ''); | |||
local URL = A['URL'] | |||
local URL_origin = A:ORIGIN('URL'); -- get name of parameter that holds URL | |||
local ChapterURL = A['ChapterURL']; | |||
local ChapterURL_origin = A:ORIGIN('ChapterURL'); -- get name of parameter that holds ChapterURL | |||
local ConferenceFormat = A['ConferenceFormat']; | |||
local ConferenceURL = A['ConferenceURL']; | |||
local ConferenceURL_origin = A:ORIGIN('ConferenceURL'); -- get name of parameter that holds ConferenceURL | |||
local Periodical = A['Periodical']; | |||
local Periodical_origin = ''; | |||
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,514: | Line 2,488: | ||
local ScriptPeriodical = A['ScriptPeriodical']; | local ScriptPeriodical = A['ScriptPeriodical']; | ||
local ScriptPeriodical_origin = A:ORIGIN('ScriptPeriodical'); | |||
-- web and news not tested for now because of | -- web and news not tested for now because of | ||
Line 2,524: | Line 2,499: | ||
end | end | ||
end | end | ||
local TransPeriodical = A['TransPeriodical']; | |||
local TransPeriodical_origin = A:ORIGIN ('TransPeriodical'); | |||
local Series = A['Series']; | |||
local Volume; | local Volume; | ||
local | local Issue; | ||
local Page; | |||
local Pages; | |||
local At; | |||
if 'citation' == config.CitationClass then | if 'citation' == config.CitationClass then | ||
if utilities.is_set (Periodical) then | if utilities.is_set (Periodical) then | ||
Line 2,542: | Line 2,526: | ||
Volume = A['Volume']; | Volume = A['Volume']; | ||
end | end | ||
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,555: | Line 2,537: | ||
end | end | ||
end | end | ||
local | local Position = ''; | ||
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,594: | Line 2,573: | ||
end | end | ||
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 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,615: | Line 2,591: | ||
end | end | ||
local | local Via = A['Via']; | ||
local | local AccessDate = A['AccessDate']; | ||
local Agency = A['Agency']; | |||
local Language = A['Language']; | |||
local Format = A['Format']; | |||
local ChapterFormat = A['ChapterFormat']; | |||
local DoiBroken = A['DoiBroken']; | |||
local ID = A['ID']; | |||
local ASINTLD = A['ASINTLD']; | |||
local IgnoreISBN = is_valid_parameter_value (A['IgnoreISBN'], A:ORIGIN('IgnoreISBN'), cfg.keywords_lists['yes_true_y'], nil); | |||
local Embargo = A['Embargo']; | |||
local Class = A['Class']; -- arxiv class identifier | |||
local | local Quote = A['Quote']; | ||
local QuotePage = A['QuotePage']; | |||
local QuotePages = A['QuotePages']; | |||
local ScriptQuote = A['ScriptQuote']; | |||
local TransQuote = A['TransQuote']; | |||
local LayFormat = A['LayFormat']; | |||
local LayURL = A['LayURL']; | |||
local LaySource = A['LaySource']; | |||
local Transcript = A['Transcript']; | |||
local TranscriptFormat = A['TranscriptFormat']; | |||
local TranscriptURL = A['TranscriptURL'] | |||
local TranscriptURL_origin = A:ORIGIN('TranscriptURL'); -- get name of parameter that holds TranscriptURL | |||
local | local LastAuthorAmp = is_valid_parameter_value (A['LastAuthorAmp'], A:ORIGIN('LastAuthorAmp'), 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); | |||
if 'nocat' == A:ORIGIN('NoTracking') then | |||
utilities.set_message ('maint_nocat'); -- this one so that we get the message; see main categorization at end of citation0() | |||
end | |||
--local variables that are not cs1 parameters | |||
local use_lowercase; -- controls capitalization of certain static text | |||
local this_page = mw.title.getCurrentTitle(); -- also used for COinS and for language | |||
local anchor_year; -- used in the CITEREF identifier | |||
local COinS_date = {}; -- holds date info extracted from |date= for the COinS metadata by Module:Date verification | |||
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 | end | ||
if | local sepc; -- separator between citation elements for CS1 a period, for CS2, a comma | ||
local PostScript; | |||
local Ref = A['Ref']; | |||
if 'harv' == Ref then | |||
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 | |||
sepc, PostScript, Ref = set_style (Mode:lower(), A['PostScript'], Ref, config.CitationClass); | |||
use_lowercase = ( sepc == ',' ); -- used to control capitalization for certain static text | |||
-- check this page to see if it is in one of the namespaces that cs1 is not supposed to add to the error categories | |||
local | if not utilities.is_set (no_tracking_cats) then -- ignore if we are already not going to categorize this page | ||
local | 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 | |||
break; -- bail out if one is found | |||
end | |||
end | |||
end | |||
-- check for extra |page=, |pages= or |at= parameters. (also sheet and sheets while we're at it) | |||
utilities.select_one (args, {'page', 'p', 'pp', 'pages', 'at', 'sheet', 'sheets'}, 'err_redundant_parameters'); -- this is a dummy call simply to get the error message and category | |||
local coins_pages; | |||
Page, Pages, At, coins_pages = insource_loc_get (Page, Pages, At); | |||
local NoPP = is_valid_parameter_value (A['NoPP'], A:ORIGIN('NoPP'), cfg.keywords_lists['yes_true_y'], nil); | |||
if utilities.is_set (PublicationPlace) and utilities.is_set (Place) then -- both |publication-place= and |place= (|location=) allowed if different | |||
utilities.add_prop_cat ('location test'); -- add property cat to evaluate how often PublicationPlace and Place are used together | |||
if PublicationPlace == Place then | |||
Place = ''; -- unset; don't need both if they are the same | |||
end | |||
elseif not utilities.is_set (PublicationPlace) and utilities.is_set (Place) then -- when only |place= (|location=) is set ... | |||
PublicationPlace = Place; -- promote |place= (|location=) to |publication-place | |||
end | |||
if PublicationPlace == Place then Place = ''; end -- don't need both if they are the same | |||
--[[ | --[[ | ||
Line 2,701: | Line 2,721: | ||
TransChapter = TransTitle; | TransChapter = TransTitle; | ||
ChapterURL = URL; | ChapterURL = URL; | ||
ChapterURL_origin = | ChapterURL_origin = A:ORIGIN('URL') | ||
ChapterUrlAccess = UrlAccess; | ChapterUrlAccess = UrlAccess; | ||
Line 2,725: | Line 2,745: | ||
-- special case for cite techreport. | -- special case for cite techreport. | ||
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,737: | Line 2,756: | ||
-- 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. | ||
if 'conference' == config.CitationClass then | if 'conference' == config.CitationClass then | ||
if utilities.is_set (BookTitle) then | if utilities.is_set (BookTitle) then | ||
Line 2,762: | Line 2,777: | ||
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 | ||
-- cite map oddities | -- cite map oddities | ||
local Cartography = ""; | local Cartography = ""; | ||
Line 2,801: | Line 2,809: | ||
-- 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. | ||
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,836: | Line 2,843: | ||
ChapterURL = URL; | ChapterURL = URL; | ||
ChapterUrlAccess = UrlAccess; | ChapterUrlAccess = UrlAccess; | ||
ChapterURL_origin = | ChapterURL_origin = A:ORIGIN('URL'); | ||
Title = Series; -- promote series to title | Title = Series; -- promote series to title | ||
Line 2,863: | Line 2,870: | ||
-- handle type parameter for those CS1 citations that have default values | -- handle type parameter for those CS1 citations that have default values | ||
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,878: | Line 2,883: | ||
-- 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_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 | ||
if not utilities.is_set (Date) then | if not utilities.is_set (Date) then | ||
Line 2,905: | Line 2,907: | ||
Date validation supporting code is in Module:Citation/CS1/Date_validation | Date validation supporting code is in Module:Citation/CS1/Date_validation | ||
]] | ]] | ||
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,951: | Line 2,931: | ||
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, | local mismatch = validation.year_date_check (Year, Date); | ||
if 0 == mismatch then -- |year= does not match a year-value in |date= | |||
table.insert (error_list, '<code class="cs1-code">|year= / |date= mismatch</code>'); | |||
elseif 1 == mismatch then -- |year= matches year-value in |date= | |||
utilities.set_message ('maint_date_year'); -- add a maint cat | |||
end | |||
end | end | ||
Line 2,957: | Line 2,942: | ||
local modified = false; -- flag | local modified = false; -- flag | ||
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 2,990: | Line 2,971: | ||
end -- end of do | end -- end of do | ||
local | local ID_list_coins = identifiers.extract_ids (args); -- gets identifiers and their values from args; this list used for COinS and source for build_id_list() | ||
if utilities.is_set (DoiBroken) and not ID_list_coins['DOI'] then | |||
local Class = | table.insert (z.message_tail, {utilities.set_message ('err_doibroken_missing_doi', A:ORIGIN('DoiBroken'))}); | ||
end | |||
local ID_access_levels = identifiers.extract_id_access_levels (args, ID_list_coins); | |||
local ID_list = identifiers.build_id_list (ID_list_coins, {IdAccessLevels = ID_access_levels, DoiBroken = DoiBroken, ASINTLD = ASINTLD, IgnoreISBN = IgnoreISBN, Embargo = Embargo, Class = Class}); -- render identifiers | |||
-- 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. | ||
if utilities.in_array (config.CitationClass, whitelist.preprint_template_list) then | if utilities.in_array (config.CitationClass, whitelist.preprint_template_list) then | ||
Line 3,014: | Line 2,990: | ||
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 | if identifiers.auto_link_urls[auto_select] then -- manual selection | ||
URL = identifiers.auto_link_urls[auto_select]; | 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 | elseif identifiers.auto_link_urls['pmc'] then -- auto-select PMC | ||
URL = identifiers.auto_link_urls['pmc']; | 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]; | 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 | 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,048: | Line 3,024: | ||
check_for_url ({ -- add error message when any of these parameters hold a URL | check_for_url ({ -- add error message when any of these parameters hold a URL | ||
['title'] = Title, | ['title']=Title, | ||
[A:ORIGIN('Chapter')] = Chapter, | [A:ORIGIN('Chapter')]=Chapter, | ||
[Periodical_origin] = Periodical, | [Periodical_origin] = Periodical, | ||
[PublisherName_origin] = PublisherName | [PublisherName_origin] = PublisherName | ||
Line 3,071: | Line 3,047: | ||
coins_author = c; -- use that instead | coins_author = c; -- use that instead | ||
end | end | ||
-- this is the function call to COinS() | -- this is the function call to COinS() | ||
local OCinSoutput = metadata.COinS({ | local OCinSoutput = metadata.COinS({ | ||
Line 3,090: | Line 3,063: | ||
['Volume'] = Volume, | ['Volume'] = Volume, | ||
['Issue'] = Issue, | ['Issue'] = Issue, | ||
['Pages'] = coins_pages or metadata.get_coins_pages (first_set ({Sheet, Sheets, Page, Pages, At | ['Pages'] = coins_pages or metadata.get_coins_pages (first_set ({Sheet, Sheets, Page, Pages, At}, 5)), -- pages stripped of external links | ||
['Edition'] = Edition, | ['Edition'] = Edition, | ||
['PublisherName'] = PublisherName or Newsgroup, -- any apostrophe markup already removed from PublisherName | ['PublisherName'] = PublisherName or Newsgroup, -- any apostrophe markup already removed from PublisherName | ||
Line 3,109: | Line 3,082: | ||
end | end | ||
-- 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. | ||
local EditorCount; -- used only for choosing {ed.) or (eds.) annotation at end of editor name-list | |||
do | do | ||
local last_first_list; | local last_first_list; | ||
local control = { | local control = { | ||
format = NameListStyle, | format = NameListStyle, -- empty string or 'vanc' | ||
maximum = nil, -- as if display-authors or display-editors not set | maximum = nil, -- as if display-authors or display-editors not set | ||
lastauthoramp = LastAuthorAmp, | |||
mode = Mode | mode = Mode | ||
}; | }; | ||
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); | ||
last_first_list, EditorCount = list_people(control, e, editor_etal); | |||
if utilities.is_set (Editors) then | |||
Editors, editor_etal = name_has_etal (Editors, editor_etal, false, 'editors'); -- find and remove variations on et al. | |||
if editor_etal then | |||
Editors = Editors .. ' ' .. cfg.messages['et al']; -- add et al. to editors parameter beause |display-editors=etal | |||
end | |||
EditorCount = 2; -- we don't know but assume |editors= is multiple names; spoof to display (eds.) annotation | |||
else | |||
Editors = last_first_list; -- either an author name list or an empty string | |||
end | |||
if 1 == EditorCount and (true == editor_etal or 1 < #e) then -- only one editor displayed but includes etal then | if 1 == EditorCount and (true == editor_etal or 1 < #e) then -- only one editor displayed but includes etal then | ||
Line 3,142: | Line 3,114: | ||
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); | ||
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); | ||
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); | ||
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); | ||
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,174: | Line 3,146: | ||
end | end | ||
-- apply |[xx-]format= styling; at the end, these parameters hold correctly styled format annotation, | |||
-- an error message if the associated URL is not set, or an empty string for concatenation | |||
ArchiveFormat = style_format (ArchiveFormat, ArchiveURL, 'archive-format', 'archive-url'); | |||
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'); | ||
LayFormat = style_format (LayFormat, LayURL, 'lay-format', 'lay-url'); | |||
TranscriptFormat = style_format (TranscriptFormat, TranscriptURL, 'transcript-format', 'transcripturl'); | |||
-- 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,198: | Line 3,173: | ||
end | end | ||
local | local OriginalURL, OriginalURL_origin, OriginalFormat, 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,334: | Line 3,305: | ||
TitleLink = ''; -- unset | TitleLink = ''; -- unset | ||
end | end | ||
if not utilities.is_set (TitleLink) and utilities.is_set (URL) then | if not utilities.is_set (TitleLink) and utilities.is_set (URL) then | ||
Title = external_link (URL, Title, URL_origin, UrlAccess) .. TransTitle .. TransError .. Format; | Title = external_link (URL, Title, URL_origin, UrlAccess) .. TransTitle .. TransError .. Format; | ||
Line 3,351: | Line 3,322: | ||
else | else | ||
local ws_url, ws_label, L; -- Title has italic or quote markup by the time we get here which causes is_wikilink() to return 0 (not a wikilink) | local ws_url, ws_label, L; -- Title has italic or quote markup by the time we get here which causes is_wikilink() to return 0 (not a wikilink) | ||
ws_url, ws_label, L = wikisource_url_make (Title:gsub(' | ws_url, ws_label, L = wikisource_url_make (Title:gsub('[\'"](.-)[\'"]', '%1')); -- make ws URL from |title= interwiki link (strip italic or quote markup); link portion L becomes tooltip label | ||
if ws_url then | if ws_url then | ||
Title = Title:gsub ('%b[]', ws_label); -- replace interwiki link with ws_label to retain markup | Title = Title:gsub ('%b[]', ws_label); -- replace interwiki link with ws_label to retain markup | ||
Line 3,369: | Line 3,340: | ||
end | end | ||
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,379: | Line 3,349: | ||
end | end | ||
if not utilities.is_set (Position) then | if not utilities.is_set (Position) then | ||
local Minutes = A['Minutes']; | local Minutes = A['Minutes']; | ||
Line 3,426: | Line 3,395: | ||
end | end | ||
if utilities.is_set (Language) then | |||
if utilities.is_set ( | 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 | ||
Others = utilities.is_set (Others) and (sepc .. " " .. Others) or ""; | Others = utilities.is_set (Others) and (sepc .. " " .. Others) or ""; | ||
Line 3,444: | Line 3,413: | ||
end | end | ||
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 | ||
if Edition:match ('%f[%a][Ee]d | if Edition:match ('%f[%a][Ee]d%.?$') or Edition:match ('%f[%a][Ee]dition$') then | ||
utilities.set_message ('maint_extra_text', 'edition'); -- add maint cat | |||
end | end | ||
Edition = " " .. wrap_msg ('edition', Edition); | Edition = " " .. wrap_msg ('edition', Edition); | ||
Line 3,456: | Line 3,424: | ||
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 | ||
OrigDate = utilities.is_set (OrigDate) and wrap_msg ('origdate', OrigDate) or ''; | |||
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); | ||
------------------------------------ totally unrelated data | |||
Via = utilities.is_set (Via) and wrap_msg ('via', Via) or ''; | |||
if utilities.is_set (AccessDate) then | if utilities.is_set (AccessDate) then | ||
Line 3,471: | Line 3,442: | ||
if utilities.is_set (ID) then ID = sepc .. " " .. ID; end | if utilities.is_set (ID) then ID = sepc .. " " .. ID; end | ||
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,484: | Line 3,453: | ||
end | end | ||
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,495: | Line 3,461: | ||
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,477: | ||
local quote_prefix = ''; | local quote_prefix = ''; | ||
if utilities.is_set (QuotePage) then | if utilities.is_set (QuotePage) then | ||
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,518: | Line 3,483: | ||
end | end | ||
elseif utilities.is_set (QuotePages) then | elseif utilities.is_set (QuotePages) then | ||
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,534: | Line 3,498: | ||
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 | end | ||
Line 3,588: | Line 3,543: | ||
local Lay = ''; | local Lay = ''; | ||
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,608: | Line 3,559: | ||
end | end | ||
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,638: | Line 3,584: | ||
end | end | ||
-- 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,647: | Line 3,591: | ||
Periodical = format_periodical (ScriptPeriodical, ScriptPeriodical_origin, Periodical, TransPeriodical, TransPeriodical_origin); | Periodical = format_periodical (ScriptPeriodical, ScriptPeriodical_origin, Periodical, TransPeriodical, TransPeriodical_origin); | ||
end | end | ||
end | end | ||
Line 3,713: | Line 3,647: | ||
end | end | ||
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,725: | Line 3,657: | ||
local pgtext = Position .. Sheet .. Sheets .. Page .. Pages .. At; | local pgtext = Position .. Sheet .. Sheets .. Page .. Pages .. At; | ||
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,781: | Line 3,711: | ||
else | else | ||
if EditorCount <= 1 then | if EditorCount <= 1 then | ||
Editors = Editors .. " (" .. cfg.messages['editor'] .. ")" .. sepc .. " " | Editors = Editors .. " (" .. cfg.messages['editor'] .. ")" .. sepc .. " " | ||
else | |||
Editors = Editors .. " (" .. cfg.messages['editors'] .. ")" .. sepc .. " " | |||
end | |||
end | |||
text = safe_join( {Editors, Date, Chapter, Place, tcommon, pgtext, idcommon}, sepc ); | |||
else | |||
if utilities.in_array (config.CitationClass, {"journal", "citation"}) and utilities.is_set (Periodical) then | |||
text = safe_join( {Chapter, Place, tcommon, pgtext, Date, idcommon}, sepc ); | |||
else | |||
text = safe_join( {Chapter, Place, tcommon, Date, pgtext, idcommon}, sepc ); | |||
end | |||
end | |||
if utilities.is_set (PostScript) and PostScript ~= sepc then | |||
text = safe_join( {text, sepc}, sepc ); --Deals with italics, spaces, etc. | |||
text = text:sub(1, -sepc:len() - 1); | |||
end | |||
text = safe_join( {text, PostScript}, sepc ); | |||
-- Now enclose the whole thing in a <cite/> element | |||
local options = {}; | |||
if utilities.is_set (config.CitationClass) and config.CitationClass ~= "citation" then | |||
options.class = string.format ('%s %s %s', 'citation', config.CitationClass, utilities.is_set (Mode) and Mode or 'cs1'); -- class=citation required for blue highlight when used with |ref= | |||
else | |||
options.class = string.format ('%s %s', 'citation', utilities.is_set (Mode) and Mode or 'cs2'); | |||
end | |||
if utilities.is_set (Ref) and 'none' ~= cfg.keywords_xlate[Ref:lower()] then | |||
local id = Ref | |||
if ('harv' == Ref ) then | |||
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 | |||
if #namelist > 0 then -- if there are names in namelist | |||
id = anchor_id (namelist, year); -- go make the CITEREF anchor | |||
else | else | ||
id = ''; -- unset | |||
end | end | ||
end | end | ||
options.id = id; | options.id = id; | ||
Line 3,879: | Line 3,798: | ||
table.insert (maint, v); -- maint msg is the category name | table.insert (maint, v); -- maint msg is the category name | ||
table.insert (maint, ' ('); -- open the link text | table.insert (maint, ' ('); -- open the link text | ||
table.insert (maint, utilities. | table.insert (maint, utilities.make_wikilink (':Category:' .. v, 'link')); -- add the link | ||
table.insert (maint, ')'); -- and close it | table.insert (maint, ')'); -- and close it | ||
table.insert (maint_msgs, table.concat (maint)); -- assemble new maint message and add it to the maint_msgs table | table.insert (maint_msgs, table.concat (maint)); -- assemble new maint message and add it to the maint_msgs table | ||
Line 3,887: | Line 3,806: | ||
if not no_tracking_cats then | if not no_tracking_cats then | ||
for _, v in ipairs( z.error_categories ) do | for _, v in ipairs( z.error_categories ) do | ||
table.insert (render, utilities. | table.insert (render, utilities.make_wikilink ('Category:' .. v)); | ||
end | end | ||
for _, v in ipairs( z.maintenance_cats ) do -- append maintenance categories | for _, v in ipairs( z.maintenance_cats ) do -- append maintenance categories | ||
table.insert (render, utilities. | table.insert (render, utilities.make_wikilink ('Category:' .. v)); | ||
end | end | ||
for _, v in ipairs( z.properties_cats ) do -- append properties categories | for _, v in ipairs( z.properties_cats ) do -- append properties categories | ||
table.insert (render, utilities. | table.insert (render, utilities.make_wikilink ('Category:' .. v)); | ||
end | end | ||
elseif 'nocat' == A:ORIGIN('NoTracking') then -- peculiar special case; can't track nocat without tracking nocat | |||
table.insert (render, utilities.make_wikilink ('Category:CS1 maint: nocat')); -- hand-set this category because it is supposed to be temporary | |||
end | end | ||
Line 3,915: | Line 3,836: | ||
local function validate (name, cite_class, empty) | local function validate (name, cite_class, empty) | ||
local name = tostring (name); | local name = tostring (name); | ||
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 | ||
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 -- empty | if empty then return nil; end -- deprecated empty 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; | return true; | ||
end | end | ||
Line 3,943: | Line 3,859: | ||
-- limited enumerated parameters list | -- limited enumerated parameters list | ||
name = name:gsub("%d+", "#" ); -- replace digit(s) with # (last25 becomes last#) (mw.ustring because non-Western 'local' digits) | |||
state = whitelist.limited_numbered_arguments[ | state = whitelist.limited_numbered_arguments[name]; | ||
if true == state_test (state, name) then return true; end | if true == state_test (state, name) then return true; end | ||
Line 3,959: | Line 3,875: | ||
-- all enumerated parameters allowed | -- all enumerated parameters allowed | ||
name = name:gsub("%d+", "#" ); -- replace digit(s) with # (last25 becomes last#) (mw.ustring because non-Western 'local' digits) | |||
state = whitelist.numbered_arguments[ | state = whitelist.numbered_arguments[name]; | ||
if true == state_test (state, name) then return true; end | if true == state_test (state, name) then return true; end | ||
Line 4,116: | Line 4,032: | ||
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', {param}, 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 | if not utilities.is_set (error_text) then -- couldn't match with a pattern, is there an expicit suggestion? | ||
if | if suggestions.suggestions[ k:lower() ] ~= nil 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 | ||
Line 4,139: | Line 4,055: | ||
elseif not utilities.is_set (v) then -- for empty parameters | elseif not utilities.is_set (v) then -- for empty parameters | ||
if not validate (k, config.CitationClass, true) then -- is this empty parameter a valid parameter | if not validate (k, config.CitationClass, true) then -- is this empty parameter a valid parameter | ||
k = ('' | k = k:gsub ('^$', '(empty string)'); -- when k is empty string (or was space(s) trimmed to empty string), replace with descriptive text | ||
table.insert (empty_unknowns, utilities.wrap_style ('parameter', k)); -- format for error message and add to the list | table.insert (empty_unknowns, utilities.wrap_style ('parameter', k)); -- format for error message and add to the list | ||
end | end | ||
Line 4,164: | Line 4,080: | ||
end | end | ||
return table.concat ({ | return table.concat ({citation0( config, args), frame:extensionTag ('templatestyles', '', {src=styles})}); | ||
end | end | ||