Module:Citation/CS1: Difference between revisions
don't evaluate positional parameters for invisible chars;
m (1 revision imported) |
(don't evaluate positional parameters for invisible chars;) |
||
Line 22: | Line 22: | ||
--[[--------------------------< P A G E S C O P E V A R I A B L E S >-------------------------------------- | --[[--------------------------< P A G E S C O P E V A R I A B L E S >-------------------------------------- | ||
declare variables here that have page-wide scope that are not brought in from other modules; that are created here and used here | |||
and used here | |||
]] | ]] | ||
Line 70: | Line 69: | ||
if not added_prop_cats [key] then | if not added_prop_cats [key] then | ||
added_prop_cats [key] = true; -- note that we've added this category | added_prop_cats [key] = true; -- note that we've added this category | ||
key = key:gsub ('(foreign_lang_source_?2?)%a%a%a?', '%1'); | key = key:gsub ('(foreign_lang_source_?2?)%a%a%a?[%a%-]*', '%1'); -- strip lang code from keyname | ||
table.insert( z.properties_cats, substitute (cfg.prop_cats [key], arguments)); -- make name then add to table | table.insert( z.properties_cats, substitute (cfg.prop_cats [key], arguments)); -- make name then add to table | ||
end | end | ||
Line 534: | Line 533: | ||
local lang=''; -- initialize to empty string | local lang=''; -- initialize to empty string | ||
local name; | local name; | ||
if script_value:match('^%l%l%s*:') then | if script_value:match('^%l%l%l?%s*:') then -- if first 3 or 4 non-space characters are script language prefix | ||
lang = script_value:match('^(%l%l)%s*:%s*%S.*'); -- get the language prefix or nil if there is no script | lang = script_value:match('^(%l%l%l?)%s*:%s*%S.*'); -- get the language prefix or nil if there is no script | ||
if not is_set (lang) then | if not is_set (lang) then | ||
table.insert( z.message_tail, { set_error( 'script_parameter', {script_param, 'missing title part'}, true ) } ); -- prefix without 'title'; add error message | table.insert( z.message_tail, { set_error( 'script_parameter', {script_param, 'missing title part'}, true ) } ); -- prefix without 'title'; add error message | ||
Line 541: | Line 540: | ||
end | end | ||
-- if we get this far we have prefix and script | -- if we get this far we have prefix and script | ||
name = cfg.lang_code_remap[lang] or mw.language.fetchLanguageName( lang, | 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 is_set (name) then -- is prefix a proper ISO 639-1 language code? | if is_set (name) then -- is prefix a proper ISO 639-1 language code? | ||
script_value = script_value:gsub ('^%l | 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? | ||
if in_array (lang, cfg.script_lang_codes) then | if in_array (lang, cfg.script_lang_codes) then | ||
Line 614: | Line 613: | ||
local wl_type, D, L; | local wl_type, D, L; | ||
local ws_url, ws_label; | local ws_url, ws_label; | ||
local wikisource_prefix = table.concat ({'https://', cfg.this_wiki_code, '.wikisource.org/wiki/'}); | |||
wl_type, D, L = is_wikilink (str); -- wl_type is 0 (not a wikilink), 1 (simple wikilink), 2 (complex wikilink) | wl_type, D, L = is_wikilink (str); -- wl_type is 0 (not a wikilink), 1 (simple wikilink), 2 (complex wikilink) | ||
Line 621: | Line 621: | ||
if is_set (str) then | if is_set (str) then | ||
ws_url = table.concat ({ -- build a wikisource url | ws_url = table.concat ({ -- build a wikisource url | ||
wikisource_prefix, -- prefix | |||
str, -- article title | str, -- article title | ||
}); | }); | ||
ws_label = str; -- label for the url | ws_label = str; -- label for the url | ||
end | end | ||
elseif 1 == wl_type then | elseif 1 == wl_type then -- simple wikilink: [[Wikisource:ws article]] | ||
str = D:match ('^[Ww]ikisource:(.+)') or D:match ('^[Ss]:(.+)'); -- article title from interwiki link with long-form or short-form namespace | str = D:match ('^[Ww]ikisource:(.+)') or D:match ('^[Ss]:(.+)'); -- article title from interwiki link with long-form or short-form namespace | ||
if is_set (str) then | if is_set (str) then | ||
ws_url = table.concat ({ -- build a wikisource url | ws_url = table.concat ({ -- build a wikisource url | ||
wikisource_prefix, -- prefix | |||
str, -- article title | str, -- article title | ||
}); | }); | ||
Line 640: | Line 640: | ||
ws_label = D; -- get ws article name from display portion of interwiki link | ws_label = D; -- get ws article name from display portion of interwiki link | ||
ws_url = table.concat ({ -- build a wikisource url | ws_url = table.concat ({ -- build a wikisource url | ||
wikisource_prefix, -- prefix | |||
str, -- article title without namespace from link portion of wikilink | str, -- article title without namespace from link portion of wikilink | ||
}); | }); | ||
Line 648: | Line 648: | ||
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 encoding of | ws_url = ws_url:gsub ('%%23', '#'); -- undo percent encoding of fragment marker | ||
end | end | ||
Line 657: | Line 657: | ||
--[[--------------------------< 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 | Format the three periodical parameters: |script-<periodical>=, |<periodical>=, and |trans-<periodical>= into a single Periodical meta- | ||
parameter. | parameter. | ||
Line 677: | Line 677: | ||
if is_set (periodical) then | if is_set (periodical) then | ||
periodical = periodical .. ' ' .. trans_periodical; | periodical = periodical .. ' ' .. trans_periodical; | ||
else -- here when | else -- here when trans-periodical without periodical or script-periodical | ||
periodical = trans_periodical; | periodical = trans_periodical; | ||
periodical_error = ' ' .. set_error ('trans_missing_title', {'periodical'}); | periodical_error = ' ' .. set_error ('trans_missing_title', {'periodical'}); | ||
Line 694: | Line 694: | ||
]] | ]] | ||
local function format_chapter_title ( | local function format_chapter_title (script_chapter, script_chapter_source, chapter, chapter_source, trans_chapter, trans_chapter_source, chapter_url, chapter_url_source, no_quotes, access) | ||
local chapter_error = ''; | local chapter_error = ''; | ||
Line 712: | Line 712: | ||
end | end | ||
chapter = script_concatenate (chapter, | chapter = script_concatenate (chapter, script_chapter, script_chapter_source); -- <bdi> tags, lang atribute, categorization, etc; must be done after title is wrapped | ||
if is_set ( | if is_set (chapter_url) then | ||
chapter = external_link ( | chapter = external_link (chapter_url, chapter, chapter_url_source, access); -- adds bare_url_missing_title error if appropriate | ||
elseif ws_url then | elseif ws_url then | ||
chapter = external_link (ws_url, chapter .. ' ', 'ws link in chapter'); -- adds bare_url_missing_title error if appropriate; space char to move icon away from chap text; TODO: better way to do this? | chapter = external_link (ws_url, chapter .. ' ', 'ws link in chapter'); -- adds bare_url_missing_title error if appropriate; space char to move icon away from chap text; TODO: better way to do this? | ||
Line 721: | Line 721: | ||
end | end | ||
if is_set ( | if is_set (trans_chapter) then | ||
trans_chapter = wrap_style ('trans-quoted-title', trans_chapter); | |||
if is_set (chapter) then | if is_set (chapter) then | ||
chapter = chapter .. ' ' .. | chapter = chapter .. ' ' .. trans_chapter; | ||
else -- here when | else -- here when trans_chapter without chapter or script-chapter | ||
chapter = | chapter = trans_chapter; | ||
chapter_error = ' ' .. set_error ('trans_missing_title', { | chapter_source = trans_chapter_source:match ('trans%-?(.+)'); -- when no chapter, get matching name from trans-<param> | ||
chapter_error = ' ' .. set_error ('trans_missing_title', {chapter_source}); | |||
end | end | ||
end | end | ||
return chapter .. chapter_error; | return chapter .. chapter_error; | ||
Line 840: | Line 837: | ||
-- Empty strings, not nil; | -- Empty strings, not nil; | ||
if v == nil then | if v == nil then | ||
-- v = cfg.defaults[k] or ''; | |||
v = ''; | |||
origin[k] = ''; | origin[k] = ''; | ||
end | end | ||
Line 884: | Line 882: | ||
local function set_titletype (cite_class, title_type) | local function set_titletype (cite_class, title_type) | ||
if is_set(title_type) then | if is_set (title_type) then | ||
if | if 'none' == cfg.keywords_xlate[title_type] then | ||
title_type = | title_type = ''; -- if |type=none then type parameter not displayed | ||
end | end | ||
return title_type; -- if |type= has been set to any other value use that value | return title_type; -- if |type= has been set to any other value use that value | ||
Line 922: | Line 920: | ||
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 entity with generic keyboard space character | |||
local out = {}; | local out = {}; | ||
Line 928: | Line 928: | ||
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 mw.ustring.match (item, '^%w*[%.%-]?%w+%s*[%-–—]%s*%w*[%.%-]?%w+$') then -- if a hyphenated range or has endash or emdash separators | ||
if item:match ('%a+[%.%-]?%d+%s*%-%s*%a+[%.%-]?%d+') or | 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) | ||
item:match ('%d+[%.%-]%d+%s*%-%s*%d+[%.%-]%d+') or | item:match ('^%d+[%.%-]%d+%s*%-%s*%d+[%.%-]%d+$') or -- digit separator digit hyphen digit separator digit | ||
item:match ('%d+%s*%-%s*%d+') or -- digit hyphen digit | item:match ('^%d+%s*%-%s*%d+$') or -- digit hyphen digit | ||
item:match ('%a+%s*%-%s*%a+') then | item:match ('^%a+%s*%-%s*%a+$') then -- letter hyphen letter | ||
item = item:gsub ('(%w*[%.%-]?%w+)%s*%-%s*(%w*[%.%-]?%w+)', '%1–%2'); -- replace hyphen, remove extraneous space characters | item = item:gsub ('(%w*[%.%-]?%w+)%s*%-%s*(%w*[%.%-]?%w+)', '%1–%2'); -- replace hyphen, remove extraneous space characters | ||
else | else | ||
Line 1,073: | Line 1,073: | ||
]] | ]] | ||
local function is_good_vanc_name (last, first) | local function is_good_vanc_name (last, first, suffix) | ||
if not suffix then | |||
if first:find ('[,%s]') then -- when there is a space or comma, might be first name/initials + generational suffix | |||
first = first:match ('(.-)[,%s]+'); -- get name/initials | |||
suffix = first:match ('[,%s]+(.+)$'); -- get generational suffix | |||
end | |||
end | |||
if is_set (suffix) then | if is_set (suffix) then | ||
if not is_suffix (suffix) then | if not is_suffix (suffix) then | ||
add_vanc_error ( | 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,084: | Line 1,088: | ||
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 ('non-Latin | 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,117: | Line 1,121: | ||
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 ( | 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,125: | Line 1,129: | ||
end | end | ||
end -- if here then name has 3 or more uppercase letters so treat them as a word | end -- if here then name has 3 or more uppercase letters so treat them as a word | ||
local initials, names = {}, {}; -- tables to hold name parts and initials | local initials, names = {}, {}; -- tables to hold name parts and initials | ||
Line 1,167: | Line 1,170: | ||
sep = cfg.presentation['sep_nl_vanc']; -- name-list separator between authors is a comma | sep = cfg.presentation['sep_nl_vanc']; -- name-list separator between authors 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; -- unset because isn't used by Vancouver style | |||
else | else | ||
sep = cfg.presentation['sep_nl']; -- name-list separator between authors is a semicolon | sep = cfg.presentation['sep_nl']; -- name-list separator between authors is a semicolon | ||
Line 1,203: | Line 1,207: | ||
one = one .. namesep .. first; | one = one .. namesep .. first; | ||
end | end | ||
end | end | ||
table.insert( text, one ) | if is_set (person.link) then | ||
table.insert( text, sep_one ) | one = make_wikilink (person.link, one); -- link author/editor | ||
end | |||
table.insert (text, one) | |||
table.insert (text, sep_one) | |||
end | end | ||
end | end | ||
Line 1,236: | Line 1,240: | ||
]] | ]] | ||
local function anchor_id (namelist, year) | local function anchor_id (namelist, year) | ||
local names={}; -- a table for the one to four names and year | local names={}; -- a table for the one to four names and year | ||
Line 1,279: | Line 1,284: | ||
return name, etal; -- | return name, etal; -- | ||
end | |||
--[[--------------------------< 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 mixed alphanumeric names so | |||
|last=A. Green (1922-1987) does not get caught in the current version of this test but |first=(1888) is caught. | |||
returns nothing | |||
]] | |||
local function name_is_numeric (name, list_name) | |||
if is_set (name) then | |||
if mw.ustring.match (name, '^[%A]+$') then -- when name does not contain any letters | |||
add_maint_cat ('numeric_names', cfg.special_case_translation [list_name]); -- add a maint cat for this template | |||
end | |||
end | |||
end | end | ||
Line 1,287: | Line 1,310: | ||
These annotation do not belong in author parameters and are redundant in editor parameters. If found, the function | These annotation do not belong in author parameters and are redundant in editor parameters. If found, the function | ||
adds the editor markup maintenance category. | adds the editor markup maintenance category. | ||
returns nothing | |||
]] | ]] | ||
local function name_has_ed_markup (name, list_name) | local function name_has_ed_markup (name, list_name) | ||
local patterns = cfg.editor_markup_patterns; -- get patterns from configuration | local patterns = cfg.editor_markup_patterns; -- get patterns from configuration | ||
Line 1,302: | Line 1,326: | ||
end | end | ||
end | end | ||
end | end | ||
Line 1,311: | Line 1,334: | ||
indicated if there is more than one comma and or semicolon. If found, the function adds the multiple name | indicated if there is more than one comma and or semicolon. If found, the function adds the multiple name | ||
(author or editor) maintenance category. | (author or editor) maintenance category. | ||
returns nothing | |||
]] | ]] | ||
local function name_has_mult_names (name, list_name) | local function name_has_mult_names (name, list_name) | ||
local count | local _, count; | ||
if is_set (name) then | if is_set (name) then | ||
_, count = name:gsub ('[;,]', ''); -- count the number of separator-like characters | _, count = name:gsub ('[;,]', ''); -- count the number of separator-like characters | ||
Line 1,323: | Line 1,348: | ||
end | end | ||
end | end | ||
end | end | ||
--[[--------------------------< 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 of the various name-holding | This function calls various name checking functions used to validate the content of the various name-holding | ||
parameters. | parameters. | ||
Line 1,338: | Line 1,363: | ||
last = last:match ('^%(%((.*)%)%)$'); -- strip parens | last = last:match ('^%(%((.*)%)%)$'); -- strip parens | ||
else | else | ||
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_is_numeric (last, list_name); -- check for names that are compsed of digits and punctuation | |||
end | end | ||
end | end | ||
Line 1,346: | Line 1,372: | ||
first = first:match ('^%(%((.*)%)%)$'); -- strip parens | first = first:match ('^%(%((.*)%)%)$'); -- strip parens | ||
else | else | ||
name_has_ed_markup (first, list_name); -- check for extraneous 'editor' annotation | |||
name_is_numeric (first, list_name); -- check for names that are compsed of digits and punctuation | |||
end | end | ||
end | end | ||
Line 1,380: | Line 1,407: | ||
local etal=false; -- return value set to true when we find some form of et al. in an author parameter | local etal=false; -- return value set to true when we find some form of et al. in an author parameter | ||
local last_alias, first_alias; | local last_alias, first_alias, link_alias; -- selected parameter aliases used in error messaging | ||
while true do | while true do | ||
last, last_alias = select_one( args, cfg.aliases[list_name .. '-Last'], 'redundant_parameters', i ); -- search through args for name components beginning at 1 | last, last_alias = select_one( args, cfg.aliases[list_name .. '-Last'], 'redundant_parameters', i ); -- search through args for name components beginning at 1 | ||
first, first_alias = select_one( args, cfg.aliases[list_name .. '-First'], 'redundant_parameters', i ); | first, first_alias = select_one( args, cfg.aliases[list_name .. '-First'], 'redundant_parameters', i ); | ||
link = select_one( args, cfg.aliases[list_name .. '-Link'], 'redundant_parameters', i ); | link, link_alias = select_one( args, cfg.aliases[list_name .. '-Link'], 'redundant_parameters', i ); | ||
mask = select_one( args, cfg.aliases[list_name .. '-Mask'], 'redundant_parameters', i ); | mask = select_one( args, cfg.aliases[list_name .. '-Mask'], 'redundant_parameters', i ); | ||
Line 1,399: | Line 1,426: | ||
end | end | ||
else -- we have last with or without a first | else -- we have last with or without a first | ||
link_title_ok (link, | link_title_ok (link, link_alias, last, last_alias); -- check for improper wikimarkup | ||
if first then | |||
link_title_ok (link, link_alias, first, first_alias); -- check for improper wikimarkup | |||
end | |||
names[n] = {last = last, first = first, link = link, mask = mask, corporate=false}; -- add this name to our names list (corporate for |vauthors= only) | names[n] = {last = last, first = first, link = link, mask = mask, corporate=false}; -- add this name to our names list (corporate for |vauthors= only) | ||
Line 1,478: | Line 1,508: | ||
Languages that are the same as the local wiki are not categorized. MediaWiki does not recognize three-character | Languages that are the same as the local wiki are not categorized. MediaWiki does not recognize three-character | ||
equivalents of two-character codes: code 'ar' is recognized | equivalents of two-character codes: code 'ar' is recognized but code 'ara' is not. | ||
This function supports multiple languages in the form |language=nb, French, th where the language names or codes are | This function supports multiple languages in the form |language=nb, French, th where the language names or codes are | ||
separated from each other by commas. | separated from each other by commas with optional space characters. | ||
]] | ]] | ||
Line 1,491: | Line 1,521: | ||
local names_table = {}; -- table made from the value assigned to |language= | local names_table = {}; -- table made from the value assigned to |language= | ||
local this_wiki_name = mw.language.fetchLanguageName(cfg.this_wiki_code, cfg.this_wiki_code); -- get this wiki's language name | |||
local this_wiki_name = mw.language.fetchLanguageName(this_wiki_code, this_wiki_code); -- get this wiki's language name | |||
names_table = mw.text.split (lang, '%s*,%s*'); -- names should be a comma separated list | names_table = mw.text.split (lang, '%s*,%s*'); -- names should be a comma separated list | ||
Line 1,501: | Line 1,529: | ||
if name then -- there was a remapped code so | if name then -- there was a remapped code so | ||
lang = lang:gsub ('^(%a%a%a?)%-.*', '%1'); | if not lang:match ('^%a%a%a?%-x%-%a+$') then -- if not a private ietf tag | ||
lang = lang:gsub ('^(%a%a%a?)%-.*', '%1'); -- strip ietf tags from code | |||
end | |||
else | else | ||
lang = lang:gsub ('^(%a%a%a?)%-.*', '%1'); -- strip any ietf-like tags from code | |||
if 2 == lang:len() or 3 == lang:len() then -- if two-or three-character code | if 2 == lang:len() or 3 == lang:len() then -- if two-or three-character code | ||
name = mw.language.fetchLanguageName (lang:lower(), this_wiki_code); -- get language name if |language= is a proper code | name = mw.language.fetchLanguageName (lang:lower(), cfg.this_wiki_code); -- get language name if |language= is a proper code | ||
end | end | ||
end | end | ||
Line 1,514: | Line 1,542: | ||
code = lang:lower(); -- save it | code = lang:lower(); -- save it | ||
else | else | ||
name, code = get_iso639_code (lang, this_wiki_code); -- attempt to get code from name (assign name here so that we are sure of proper capitalization) | name, code = get_iso639_code (lang, cfg.this_wiki_code); -- attempt to get code from name (assign name here so that we are sure of proper capitalization) | ||
end | end | ||
Line 1,520: | Line 1,548: | ||
name = cfg.lang_code_remap[code] or name; -- override wikimedia when they misuse language codes/names | name = cfg.lang_code_remap[code] or name; -- override wikimedia when they misuse language codes/names | ||
if this_wiki_code ~= code then | if cfg.this_wiki_code ~= code then -- when the language is not the same as this wiki's language | ||
if 2 == code:len() then -- and is a two-character code | if 2 == code:len() then -- and is a two-character code | ||
add_prop_cat ('foreign_lang_source' .. code, {name, code}) -- categorize it | add_prop_cat ('foreign_lang_source' .. code, {name, code}); -- categorize it; code appended to allow for multiple language categorization | ||
else -- or is a recognized language (but has a three-character code) | else -- or is a recognized language (but has a three-character code) | ||
add_prop_cat ('foreign_lang_source_2' .. code, {code}) -- categorize it differently TODO: support | add_prop_cat ('foreign_lang_source_2' .. code, {code}); -- categorize it differently TODO: support multiple three-character code categories per cs1|2 template | ||
end | end | ||
elseif cfg.local_lang_cat_enable then -- when the language and this wiki's language are the same and categorization is enabled | |||
add_prop_cat ('local_lang_source', {name, code}); -- categorize it | |||
end | end | ||
else | else | ||
Line 1,539: | Line 1,569: | ||
name = table.concat (language_list, cfg.messages['parameter-pair-separator']) -- insert '<space>and<space>' between two language names | name = table.concat (language_list, cfg.messages['parameter-pair-separator']) -- insert '<space>and<space>' between two language names | ||
elseif 2 < code then | elseif 2 < code then | ||
name = table.concat (language_list, ', | name = table.concat (language_list, cfg.messages['parameter-separator'], 1, code-1); -- concatenate all but last | ||
name = name | name = table.concat ({name, language_list[code]}, cfg.messages['parameter-final-separator']); -- concatenate last with final separator | ||
end | end | ||
if this_wiki_name == name then | if this_wiki_name == name then | ||
Line 1,562: | Line 1,592: | ||
local function set_cs1_style (ps) | local function set_cs1_style (ps) | ||
if not is_set (ps) then -- unless | if not is_set (ps) then -- unless explicitly set to something | ||
ps = cfg.presentation['ps_cs1']; -- terminate the rendered citation | ps = cfg.presentation['ps_cs1']; -- terminate the rendered citation | ||
end | end | ||
Line 1,624: | Line 1,654: | ||
sep, ps, ref = get_settings_from_cite_class (ps, ref, cite_class); -- get settings based on the template's CitationClass | sep, ps, ref = get_settings_from_cite_class (ps, ref, cite_class); -- get settings based on the template's CitationClass | ||
end | end | ||
if | |||
if cfg.keywords_xlate[ps:lower()] == 'none' then -- if assigned value is 'none' then | |||
ps = ''; -- set to empty string | ps = ''; -- set to empty string | ||
end | end | ||
Line 1,807: | Line 1,838: | ||
for i, v_name in ipairs(v_name_table) do | for i, v_name in ipairs(v_name_table) do | ||
first = ''; -- set to empty string for concatenation and because it may have been set for previous author/editor | |||
if v_name:match ('^%(%(.+%)%)$') then -- corporate authors are wrapped in doubled parentheses to supress vanc formatting and error detection | if v_name:match ('^%(%(.+%)%)$') then -- corporate authors are wrapped in doubled parentheses to supress vanc formatting and error detection | ||
last = v_name:match ('^%(%((.+)%)%)$') -- remove doubled parntheses | last = v_name:match ('^%(%((.+)%)%)$') -- remove doubled parntheses | ||
corporate = true; -- flag used in list_people() | corporate = true; -- flag used in list_people() | ||
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 ( | add_vanc_error (cfg.err_msg_supl.punctuation); | ||
end | end | ||
local lastfirstTable = {} | local lastfirstTable = {} | ||
lastfirstTable = mw.text.split(v_name, "%s") | lastfirstTable = mw.text.split(v_name, "%s+") | ||
first = table.remove(lastfirstTable); -- removes and returns value of last element in table which should be | first = table.remove(lastfirstTable); -- removes and returns value of last element in table which should be intials or generational suffix | ||
if | |||
suffix = first -- | if not mw.ustring.match (first, '^%u+$') then -- mw.ustring here so that later we will catch non-latin characters | ||
suffix = first; -- not initials so assume that whatever we got is a generational suffix | |||
first = table.remove(lastfirstTable); -- get what should be the initials from the table | first = table.remove(lastfirstTable); -- get what should be the initials from the table | ||
end | end | ||
last = table.concat(lastfirstTable, | last = table.concat(lastfirstTable, ' ') -- returns a string that is the concatenation of all other names that are not initials and generational suffix | ||
if not is_set (last) then | |||
first = ''; -- unset | |||
last = v_name; -- last empty because something wrong with first | |||
add_vanc_error (cfg.err_msg_supl.name); | |||
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 ('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 ( | add_vanc_error (cfg.err_msg_supl.name); -- matches a space between two intiials | ||
end | end | ||
else | else | ||
last = v_name; -- last name or single corporate name? Doesn't support multiword corporate names? do we need this? | last = v_name; -- last name or single corporate name? Doesn't support multiword corporate names? do we need this? | ||
end | end | ||
Line 1,836: | Line 1,872: | ||
if is_set (first) then | if 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 ( | 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); | is_good_vanc_name (last, first, suffix); -- check first and last before restoring the suffix which may have a non-Latin digit | ||
if is_set (suffix) then | if 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,876: | Line 1,912: | ||
local function select_author_editor_source (vxxxxors, xxxxors, args, list_name) | local function select_author_editor_source (vxxxxors, xxxxors, args, list_name) | ||
local lastfirst = false; | local lastfirst = false; | ||
if select_one( args, cfg.aliases[list_name .. '-Last'], 'none', 1 ) or -- do this twice incase we have a |first1= without a |last1=; this ... | if select_one( args, cfg.aliases[list_name .. '-Last'], 'none', 1 ) or -- do this twice incase we have a |first1= without a |last1=; this ... | ||
select_one( args, cfg.aliases[list_name .. '-First'], 'none', 1 ) or -- ... also catches the case where |first= is used with |vauthors= | select_one( args, cfg.aliases[list_name .. '-First'], 'none', 1 ) or -- ... also catches the case where |first= is used with |vauthors= | ||
Line 1,907: | Line 1,943: | ||
This function is used to validate a parameter's assigned value for those parameters that have only a limited number | This function is used to validate a parameter's assigned value for those parameters that have only a limited number | ||
of allowable values (yes, y, true, | of allowable values (yes, y, true, live, dead, etc). When the parameter value has not been assigned a value (missing | ||
in the source template) the function returns | or empty in the source template) the function returns the value specified by ret_val. If the parameter value is one | ||
of the list of allowed values returns the translated value; else, emits an error message and returns the value | |||
specified by ret_val. | |||
]] | ]] | ||
local function is_valid_parameter_value (value, name, possible) | local function is_valid_parameter_value (value, name, possible, ret_val) | ||
if not is_set (value) then | if not is_set (value) then | ||
return | return ret_val; -- an empty parameter is ok | ||
elseif in_array (value, possible) then | elseif in_array (value, possible) then | ||
return | return cfg.keywords_xlate[value]; -- return translation of parameter keyword | ||
else | else | ||
table.insert( z.message_tail, { set_error( 'invalid_param_val', {name, value}, true ) } ); -- not an allowed value so add error message | table.insert( z.message_tail, { set_error( 'invalid_param_val', {name, value}, true ) } ); -- not an allowed value so add error message | ||
return | return ret_val; | ||
end | end | ||
end | end | ||
Line 1,965: | Line 2,002: | ||
return wrap_msg ('issue', {sepc, issue}, lower); | return wrap_msg ('issue', {sepc, issue}, lower); | ||
end | end | ||
end | |||
if 'podcast' == cite_class and is_set (issue) then | |||
return wrap_msg ('issue', {sepc, issue}, lower); | |||
end | end | ||
Line 2,093: | Line 2,134: | ||
return page, pages, at, coins_pages; | return page, pages, at, coins_pages; | ||
end | end | ||
Line 2,138: | Line 2,178: | ||
if url:match('//web%.archive%.org/save/') then -- if a save command url, we don't want to allow saving of the target page | if url:match('//web%.archive%.org/save/') then -- if a save command url, we don't want to allow saving of the target page | ||
err_msg = | err_msg = cfg.err_msg_supl.save; | ||
url = url:gsub ('(//web%.archive%.org)/save/', '%1/*/', 1); -- for preview mode: modify ArchiveURL | url = url:gsub ('(//web%.archive%.org)/save/', '%1/*/', 1); -- for preview mode: modify ArchiveURL | ||
elseif url:match('//liveweb%.archive%.org/') then | elseif url:match('//liveweb%.archive%.org/') then | ||
err_msg = | err_msg = cfg.err_msg_supl.liveweb; | ||
else | else | ||
path, timestamp, flag = url:match('//web%.archive%.org/([^%d]*)(%d+)([^/]*)/'); -- split out some of the url parts for evaluation | path, timestamp, flag = url:match('//web%.archive%.org/([^%d]*)(%d+)([^/]*)/'); -- split out some of the url parts for evaluation | ||
if not is_set(timestamp) or 14 ~= timestamp:len() then -- path and flag optional, must have 14-digit timestamp here | if not is_set(timestamp) or 14 ~= timestamp:len() then -- path and flag optional, must have 14-digit timestamp here | ||
err_msg = | err_msg = cfg.err_msg_supl.timestamp; | ||
if '*' ~= flag then | if '*' ~= flag then | ||
url=url:gsub ('(//web%.archive%.org/[^%d]*%d?%d?%d?%d?%d?%d?)[^/]*', '%1*', 1) -- for preview, modify ts to be yearmo* max (0-6 digits plus splat) | url=url:gsub ('(//web%.archive%.org/[^%d]*%d?%d?%d?%d?%d?%d?)[^/]*', '%1*', 1) -- for preview, modify ts to be yearmo* max (0-6 digits plus splat) | ||
end | end | ||
elseif is_set(path) and 'web/' ~= path then -- older archive urls do not have the extra 'web/' path element | elseif is_set(path) and 'web/' ~= path then -- older archive urls do not have the extra 'web/' path element | ||
err_msg = | err_msg = cfg.err_msg_supl.path; | ||
elseif is_set (flag) and not is_set (path) then -- flag not allowed with the old form url (without the 'web/' path element) | elseif is_set (flag) and not is_set (path) then -- flag not allowed with the old form url (without the 'web/' path element) | ||
err_msg = | err_msg = cfg.err_msg_supl.flag; | ||
elseif is_set (flag) and not flag:match ('%a%a_') then -- flag if present must be two alpha characters and underscore (requires 'web/' path element) | elseif is_set (flag) and not flag:match ('%a%a_') then -- flag if present must be two alpha characters and underscore (requires 'web/' path element) | ||
err_msg = | err_msg = cfg.err_msg_supl.flag; | ||
else | else | ||
return url, date; -- return | return url, date; -- return ArchiveURL and ArchiveDate | ||
end | end | ||
end | end | ||
Line 2,163: | Line 2,203: | ||
table.insert( z.message_tail, { set_error( 'archive_url', {err_msg}, true ) } ); -- add error message and | table.insert( z.message_tail, { set_error( 'archive_url', {err_msg}, true ) } ); -- add error message and | ||
if is_set (Frame:preprocess('{{REVISIONID}}')) then | if is_set (Frame:preprocess('{{REVISIONID}}')) then | ||
return '', ''; -- return empty strings for | return '', ''; -- return empty strings for ArchiveURL and ArchiveDate | ||
else | else | ||
return url, date; -- preview mode so return | return url, date; -- preview mode so return ArchiveURL and ArchiveDate | ||
end | end | ||
end | end | ||
--[[--------------------------< C | --[[--------------------------< P L A C E _ C H E C K >-------------------------------------------------------- | ||
check |place=, |publication-place=, |location= to see if these params include digits. This function added because | |||
many editors mis-use location to specify the in-source location (|page(s)= and |at= are supposed to do that) | |||
returns the original parameter value without modification; added maint cat when parameter value contains digits | |||
]] | ]] | ||
local function citation0( config, args) | local function place_check (param_val) | ||
if not is_set (param_val) then -- parameter empty or omitted | |||
return param_val; -- return that empty state | |||
end | |||
if mw.ustring.find (param_val, '%d') then -- not empty, are there digits in the parameter value | |||
add_maint_cat ('location'); -- yep, add maint cat | |||
end | |||
return param_val; -- and done | |||
end | |||
--[[--------------------------< C I T A T I O N 0 >------------------------------------------------------------ | |||
This is the main function doing the majority of the citation formatting. | |||
]] | |||
local function citation0( config, args) | |||
--[[ | --[[ | ||
Load Input Parameters | Load Input Parameters | ||
Line 2,187: | Line 2,249: | ||
-- 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 Mode = A['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 NameListFormat = A['NameListFormat']; | |||
local NameListFormat = is_valid_parameter_value (A['NameListFormat'], A:ORIGIN('NameListFormat'), cfg.keywords_lists['name-list-format'], ''); | |||
local Collaboration = A['Collaboration']; | local Collaboration = A['Collaboration']; | ||
Line 2,249: | Line 2,308: | ||
local c = {}; -- contributors list from |contributor-lastn= / contributor-firstn= pairs | local c = {}; -- contributors list from |contributor-lastn= / contributor-firstn= pairs | ||
local Contributors; -- assembled contributors name list | local Contributors; -- assembled contributors name list | ||
local Contribution = A[' | |||
local Chapter = A['Chapter']; -- done here so that we have access to |contribution= from |chapter= aliases | |||
local Chapter_origin = A:ORIGIN ('Chapter'); | |||
local Contribution; -- because contribution is required for contributor(s) | |||
if 'contribution' == A:ORIGIN ('Chapter') then | |||
Contribution = A['Chapter']; -- get the name of the contribution | |||
end | |||
if in_array(config.CitationClass, {"book","citation"}) and not is_set(A['Periodical']) then -- |contributor= and |contribution= only supported in book cites | if in_array(config.CitationClass, {"book","citation"}) and not 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,268: | Line 2,334: | ||
end | end | ||
Contribution = nil; -- unset | Contribution = nil; -- unset | ||
end | end | ||
Line 2,291: | Line 2,353: | ||
local Conference = A['Conference']; | local Conference = A['Conference']; | ||
local TransTitle = A['TransTitle']; | local TransTitle = A['TransTitle']; | ||
local TransTitle_origin = A:ORIGIN ('TransTitle'); | |||
local TitleNote = A['TitleNote']; | local TitleNote = A['TitleNote']; | ||
local TitleLink = A['TitleLink']; | local TitleLink = A['TitleLink']; | ||
link_title_ok (TitleLink, A:ORIGIN ('TitleLink'), Title, 'title'); -- check for wikimarkup in |title-link= or wikimarkup in |title= when |title-link= is set | link_title_ok (TitleLink, A:ORIGIN ('TitleLink'), Title, 'title'); -- check for wikimarkup in |title-link= or wikimarkup in |title= when |title-link= is set | ||
local Chapter = A['Chapter']; | local Section = ''; -- {{cite map}} only; preset to empty string for concatnation 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 ScriptChapter = A['ScriptChapter']; | local ScriptChapter = A['ScriptChapter']; | ||
local | local ScriptChapter_origin = A:ORIGIN ('ScriptChapter'); | ||
local ChapterLink -- = A['ChapterLink']; -- deprecated as a parameter but still used internally by cite episode | local ChapterLink -- = A['ChapterLink']; -- deprecated as a parameter but still used internally by cite episode | ||
local TransChapter = A['TransChapter']; | local TransChapter = A['TransChapter']; | ||
local TransChapter_origin = A:ORIGIN ('TransChapter'); | |||
local TitleType = A['TitleType']; | local TitleType = A['TitleType']; | ||
local Degree = A['Degree']; | local Degree = A['Degree']; | ||
Line 2,310: | Line 2,379: | ||
ArchiveURL, ArchiveDate = archive_url_check (A['ArchiveURL'], A['ArchiveDate']) | ArchiveURL, ArchiveDate = archive_url_check (A['ArchiveURL'], A['ArchiveDate']) | ||
local UrlStatus = A['UrlStatus'] | local UrlStatus = is_valid_parameter_value (A['UrlStatus'], A:ORIGIN('UrlStatus'), cfg.keywords_lists['url-status'], ''); | ||
local URL = A['URL'] | local URL = A['URL'] | ||
local | local URL_origin = A:ORIGIN('URL'); -- get name of parameter that holds URL | ||
local ChapterURL = A['ChapterURL']; | local ChapterURL = A['ChapterURL']; | ||
local | local ChapterURL_origin = A:ORIGIN('ChapterURL'); -- get name of parameter that holds ChapterURL | ||
local ConferenceFormat = A['ConferenceFormat']; | local ConferenceFormat = A['ConferenceFormat']; | ||
local ConferenceURL = A['ConferenceURL']; | local ConferenceURL = A['ConferenceURL']; | ||
local | local ConferenceURL_origin = A:ORIGIN('ConferenceURL'); -- get name of parameter that holds ConferenceURL | ||
local Periodical = A['Periodical']; | local Periodical = A['Periodical']; | ||
local Periodical_origin = ''; | local Periodical_origin = ''; | ||
Line 2,345: | Line 2,401: | ||
end | end | ||
if 'mailinglist' == config.CitationClass then -- special case for {{cite mailing list}} | |||
if is_set (Periodical) and is_set (A ['MailingList']) then -- both set emit an error | |||
table.insert( z.message_tail, { set_error('redundant_parameters', {wrap_style ('parameter', Periodical_origin) .. ' and ' .. wrap_style ('parameter', 'mailinglist')}, true )}); | |||
end | |||
Periodical = A ['MailingList']; -- error or no, set Periodical to |mailinglist= value because this template is {{cite mailing list}} | |||
Periodical_origin = A:ORIGIN('MailingList'); | |||
end | |||
local ScriptPeriodical = A['ScriptPeriodical']; | local ScriptPeriodical = A['ScriptPeriodical']; | ||
local ScriptPeriodical_origin = A:ORIGIN('ScriptPeriodical'); | local ScriptPeriodical_origin = A:ORIGIN('ScriptPeriodical'); | ||
Line 2,350: | Line 2,418: | ||
-- Wikipedia:Administrators%27_noticeboard#Is_there_a_semi-automated_tool_that_could_fix_these_annoying_"Cite_Web"_errors? | -- Wikipedia:Administrators%27_noticeboard#Is_there_a_semi-automated_tool_that_could_fix_these_annoying_"Cite_Web"_errors? | ||
if not (is_set (Periodical) or is_set (ScriptPeriodical)) then -- 'periodical' templates require periodical parameter | if not (is_set (Periodical) or is_set (ScriptPeriodical)) then -- 'periodical' templates require periodical parameter | ||
-- | -- local p = {['journal'] = 'journal', ['magazine'] = 'magazine', ['news'] = 'newspaper', ['web'] = 'website'}; -- for error message | ||
local p = {['journal'] = 'journal', ['magazine'] = 'magazine'}; -- for error message | local p = {['journal'] = 'journal', ['magazine'] = 'magazine'}; -- for error message | ||
if p[config.CitationClass] then | if p[config.CitationClass] then | ||
Line 2,358: | Line 2,426: | ||
local TransPeriodical = A['TransPeriodical']; | local TransPeriodical = A['TransPeriodical']; | ||
local TransPeriodical_origin = A:ORIGIN ('TransPeriodical'); | |||
local Series = A['Series']; | local Series = A['Series']; | ||
Line 2,402: | Line 2,471: | ||
local Edition = A['Edition']; | local Edition = A['Edition']; | ||
local PublicationPlace = A['PublicationPlace'] | local PublicationPlace = place_check (A['PublicationPlace'], A:ORIGIN('PublicationPlace')); | ||
local Place = A['Place']; | local Place = place_check (A['Place'], A:ORIGIN('Place')); | ||
local PublisherName = A['PublisherName']; | local PublisherName = A['PublisherName']; | ||
Line 2,416: | Line 2,485: | ||
end | end | ||
local | local Newsgroup = A['Newsgroup']; -- TODO: strip apostrophe markup? | ||
if not | local Newsgroup_origin = A:ORIGIN('Newsgroup'); | ||
if 'newsgroup' == config.CitationClass then | |||
if is_set (PublisherName) then -- general use parmeter |publisher= not allowed in cite newsgroup | |||
local error_text = set_error ('parameter_ignored', {PublisherName_origin}, true); | |||
if is_set (error_text) then | |||
table.insert( z.message_tail, {error_text, error_state} ); | |||
end | |||
end | end | ||
PublisherName = nil; -- ensure that this parameter is unset for the time being; will be used again after COinS | |||
end | |||
local UrlAccess = A['UrlAccess'] | local UrlAccess = is_valid_parameter_value (A['UrlAccess'], A:ORIGIN('UrlAccess'), cfg.keywords_lists['url-access'], nil); | ||
if not is_set(URL) and is_set(UrlAccess) then | if not is_set(URL) and is_set(UrlAccess) then | ||
UrlAccess = nil; | UrlAccess = nil; | ||
Line 2,435: | Line 2,505: | ||
end | end | ||
local ChapterUrlAccess = is_valid_parameter_value (A['ChapterUrlAccess'], A:ORIGIN('ChapterUrlAccess'), cfg.keywords_lists['url-access'], nil); | |||
local ChapterUrlAccess = A['ChapterUrlAccess'] | |||
if not is_set(ChapterURL) and is_set(ChapterUrlAccess) then | if not is_set(ChapterURL) and is_set(ChapterUrlAccess) then | ||
ChapterUrlAccess = nil; | ChapterUrlAccess = nil; | ||
Line 2,453: | Line 2,511: | ||
end | end | ||
local MapUrlAccess = A['MapUrlAccess'] | local MapUrlAccess = is_valid_parameter_value (A['MapUrlAccess'], A:ORIGIN('MapUrlAccess'), cfg.keywords_lists['url-access'], nil); | ||
if not is_set(A['MapURL']) and is_set(MapUrlAccess) then | if not is_set(A['MapURL']) and is_set(MapUrlAccess) then | ||
MapUrlAccess = nil; | MapUrlAccess = nil; | ||
Line 2,472: | Line 2,527: | ||
local ID = A['ID']; | local ID = A['ID']; | ||
local ASINTLD = A['ASINTLD']; | local ASINTLD = A['ASINTLD']; | ||
local IgnoreISBN = A['IgnoreISBN'] | local IgnoreISBN = is_valid_parameter_value (A['IgnoreISBN'], A:ORIGIN('IgnoreISBN'), cfg.keywords_lists['yes_true_y'], nil); | ||
local Embargo = A['Embargo']; | local Embargo = A['Embargo']; | ||
local Class = A['Class']; -- arxiv class identifier | local Class = A['Class']; -- arxiv class identifier | ||
Line 2,493: | Line 2,545: | ||
local TranscriptFormat = A['TranscriptFormat']; | local TranscriptFormat = A['TranscriptFormat']; | ||
local TranscriptURL = A['TranscriptURL'] | local TranscriptURL = A['TranscriptURL'] | ||
local | local TranscriptURL_origin = A:ORIGIN('TranscriptURL'); -- get name of parameter that holds TranscriptURL | ||
local LastAuthorAmp = A['LastAuthorAmp'] | local LastAuthorAmp = is_valid_parameter_value (A['LastAuthorAmp'], A:ORIGIN('LastAuthorAmp'), cfg.keywords_lists['yes_true_y'], nil); | ||
local no_tracking_cats = A['NoTracking'] | local no_tracking_cats = is_valid_parameter_value (A['NoTracking'], A:ORIGIN('NoTracking'), cfg.keywords_lists['yes_true_y'], nil); | ||
--local variables that are not cs1 parameters | --local variables that are not cs1 parameters | ||
Line 2,511: | Line 2,557: | ||
local COinS_date = {}; -- holds date info extracted from |date= for the COinS metadata by Module:Date verification | local COinS_date = {}; -- holds date info extracted from |date= for the COinS metadata by Module:Date verification | ||
local DF = A['DF'] | local DF = is_valid_parameter_value (A['DF'], A:ORIGIN('DF'), cfg.keywords_lists['df'], ''); | ||
if not is_set (DF) then | if not is_set (DF) then | ||
DF = cfg.global_df; | DF = cfg.global_df; -- local df if present overrides global df set by {{use xxx date}} template | ||
end | end | ||
local sepc; -- separator between citation elements for CS1 a period, for CS2, a comma | local sepc; -- separator between citation elements for CS1 a period, for CS2, a comma | ||
local PostScript; | local PostScript; | ||
local Ref; | local Ref = A['Ref']; | ||
sepc, PostScript, Ref = set_style (Mode:lower(), A['PostScript'], | if 'harv' == Ref then | ||
add_maint_cat ('ref_harv'); -- add maint cat to identify templates that have this now-extraneous param value | |||
elseif not 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 | use_lowercase = ( sepc == ',' ); -- used to control capitalization for certain static text | ||
Line 2,537: | Line 2,586: | ||
end | end | ||
end | end | ||
-- check for extra |page=, |pages= or |at= parameters. (also sheet and sheets while we're at it) | |||
select_one (args, {'page', 'p', 'pp', 'pages', 'at', 'sheet', 'sheets'}, 'redundant_parameters'); -- this is a dummy call simply to get the error message and category | |||
select_one( args, {'page', 'p', 'pp', 'pages', 'at', 'sheet', 'sheets'}, 'redundant_parameters' ); -- this is a dummy call simply to get the error message and category | |||
local coins_pages; | local coins_pages; | ||
Line 2,545: | Line 2,593: | ||
Page, Pages, At, coins_pages = insource_loc_get (Page, Pages, At); | Page, Pages, At, coins_pages = insource_loc_get (Page, Pages, At); | ||
local NoPP = A['NoPP'] | local NoPP = is_valid_parameter_value (A['NoPP'], A:ORIGIN('NoPP'), cfg.keywords_lists['yes_true_y'], nil); | ||
if | if is_set (PublicationPlace) and is_set (Place) then -- both |publication-place= and |place= (|location=) allowed if different | ||
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 is_set (PublicationPlace) and is_set (Place) then -- when only |place= (|location=) is set ... | |||
PublicationPlace = Place; -- promote |place= (|location=) to |publication-place | PublicationPlace = Place; -- promote |place= (|location=) to |publication-place | ||
end | end | ||
if PublicationPlace == Place then Place = ''; end -- don't need both if they are the same | if PublicationPlace == Place then Place = ''; end -- don't need both if they are the same | ||
Line 2,571: | Line 2,619: | ||
]] | ]] | ||
local Encyclopedia = A['Encyclopedia']; | local Encyclopedia = A['Encyclopedia']; -- used as a flag by this module and by ~/COinS | ||
if is_set (Encyclopedia) then -- emit error message when Encyclopedia set but template is other than {{cite encyclopedia}} or {{citation}} | |||
if 'encyclopaedia' ~= config.CitationClass and 'citation' ~= config.CitationClass then | |||
table.insert (z.message_tail, {set_error ('parameter_ignored', {A:ORIGIN ('Encyclopedia')}, true)}); | |||
Encyclopedia = nil; -- unset because not supported by this template | |||
end | |||
end | |||
if ('encyclopaedia' == config.CitationClass) or ('citation' == config.CitationClass and is_set (Encyclopedia)) then | |||
if is_set (Periodical) and is_set (Encyclopedia) then -- when both set emit an error | |||
table.insert (z.message_tail, {set_error('redundant_parameters', {wrap_style ('parameter', A:ORIGIN ('Encyclopedia')) .. ' and ' .. wrap_style ('parameter', Periodical_origin)}, true )}); | |||
end | |||
if is_set (Encyclopedia) then | |||
Periodical = Encyclopedia; -- error or no, set Periodical to Encyclopedia; allow periodical without encyclopedia | |||
Periodical_origin = A:ORIGIN ('Encyclopedia'); | |||
end | |||
if is_set (Periodical) then -- Periodical is set when |encyclopedia is set | if is_set (Periodical) then -- Periodical is set when |encyclopedia is set | ||
if is_set(Title) or is_set (ScriptTitle) then | if is_set(Title) or is_set (ScriptTitle) then | ||
Line 2,579: | Line 2,643: | ||
Chapter = Title; -- |encyclopedia and |title are set so map |title to |article and |encyclopedia to |title | Chapter = Title; -- |encyclopedia and |title are set so map |title to |article and |encyclopedia to |title | ||
ScriptChapter = ScriptTitle; | ScriptChapter = ScriptTitle; | ||
ScriptChapter_origin = A:ORIGIN('ScriptTitle') | |||
TransChapter = TransTitle; | TransChapter = TransTitle; | ||
ChapterURL = URL; | ChapterURL = URL; | ||
ChapterURL_origin = A:ORIGIN('URL') | |||
ChapterUrlAccess = UrlAccess; | ChapterUrlAccess = UrlAccess; | ||
Line 2,612: | Line 2,678: | ||
end | end | ||
end | end | ||
end | end | ||
Line 2,625: | Line 2,684: | ||
if is_set(BookTitle) then | if is_set(BookTitle) then | ||
Chapter = Title; | Chapter = Title; | ||
-- | Chapter_origin = 'title'; | ||
-- ChapterLink = TitleLink; -- |chapterlink= is deprecated | |||
ChapterURL = URL; | ChapterURL = URL; | ||
ChapterUrlAccess = UrlAccess; | ChapterUrlAccess = UrlAccess; | ||
ChapterURL_origin = URL_origin; | |||
URL_origin = ''; | |||
ChapterFormat = Format; | ChapterFormat = Format; | ||
TransChapter = TransTitle; | TransChapter = TransTitle; | ||
TransChapter_origin = TransTitle_origin; | |||
Title = BookTitle; | Title = BookTitle; | ||
Format = ''; | Format = ''; | ||
-- | -- TitleLink = ''; | ||
TransTitle = ''; | TransTitle = ''; | ||
URL = ''; | URL = ''; | ||
Line 2,648: | Line 2,709: | ||
local Sheets = A['Sheets'] or ''; | local Sheets = A['Sheets'] or ''; | ||
if config.CitationClass == "map" then | if config.CitationClass == "map" then | ||
if is_set (Chapter) then | |||
table.insert( z.message_tail, { set_error( 'redundant_parameters', {wrap_style ('parameter', 'map') .. ' and ' .. wrap_style ('parameter', Chapter_origin)}, true ) } ); -- add error message | |||
end | |||
Chapter = A['Map']; | Chapter = A['Map']; | ||
Chapter_origin = A:ORIGIN('Map'); | |||
ChapterURL = A['MapURL']; | ChapterURL = A['MapURL']; | ||
ChapterURL_origin = A:ORIGIN('MapURL'); | |||
TransChapter = A['TransMap']; | |||
ScriptChapter = A['ScriptMap'] | |||
ScriptChapter_origin = A:ORIGIN('ScriptMap') | |||
ChapterUrlAccess = MapUrlAccess; | ChapterUrlAccess = MapUrlAccess; | ||
ChapterFormat = A['MapFormat']; | ChapterFormat = A['MapFormat']; | ||
Cartography = A['Cartography']; | Cartography = A['Cartography']; | ||
if is_set( Cartography ) then | if is_set( Cartography ) then | ||
Line 2,667: | Line 2,735: | ||
-- 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,680: | Line 2,747: | ||
ID = table.concat(n, sepc .. ' '); | ID = table.concat(n, sepc .. ' '); | ||
if 'episode' == config.CitationClass then -- handle the oddities that are strictly {{cite episode}} | if 'episode' == config.CitationClass then -- handle the oddities that are strictly {{cite episode}} | ||
local Season = A['Season']; | local Season = A['Season']; | ||
Line 2,700: | Line 2,763: | ||
Chapter = Title; -- promote title parameters to chapter | Chapter = Title; -- promote title parameters to chapter | ||
ScriptChapter = ScriptTitle; | ScriptChapter = ScriptTitle; | ||
ScriptChapter_origin = A:ORIGIN('ScriptTitle'); | |||
ChapterLink = TitleLink; -- alias episodelink | ChapterLink = TitleLink; -- alias episodelink | ||
TransChapter = TransTitle; | TransChapter = TransTitle; | ||
ChapterURL = URL; | ChapterURL = URL; | ||
ChapterUrlAccess = UrlAccess; | ChapterUrlAccess = UrlAccess; | ||
ChapterURL_origin = A:ORIGIN('URL'); | |||
Title = Series; -- promote series to title | Title = Series; -- promote series to title | ||
Line 2,733: | Line 2,796: | ||
-- 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. | ||
do | do | ||
if in_array (config.CitationClass, | if in_array (config.CitationClass, whitelist.preprint_template_list) then | ||
if not is_set (ID_list[config.CitationClass:upper()]) then -- |arxiv= or |eprint= required for cite arxiv; |biorxiv= & |citeseerx= required for their templates | if not is_set (ID_list[config.CitationClass:upper()]) then -- |arxiv= or |eprint= required for cite arxiv; |biorxiv= & |citeseerx= required for their templates | ||
table.insert( z.message_tail, { set_error( config.CitationClass .. '_missing', {}, true ) } ); -- add error message | table.insert( z.message_tail, { set_error( config.CitationClass .. '_missing', {}, true ) } ); -- add error message | ||
end | end | ||
Periodical = ({['arxiv'] = 'arXiv', ['biorxiv'] = bioRxiv, ['citeseerx'] = 'CiteSeerX', ['ssrn'] = 'Social Science Research Network'})[config.CitationClass]; | Periodical = ({['arxiv'] = 'arXiv', ['biorxiv'] = 'bioRxiv', ['citeseerx'] = 'CiteSeerX', ['ssrn'] = 'Social Science Research Network'})[config.CitationClass]; | ||
end | end | ||
end | end | ||
Line 2,828: | Line 2,891: | ||
-- uncomment these three lines. Not supported by en.wiki (for obvious reasons) | -- uncomment these three lines. Not supported by en.wiki (for obvious reasons) | ||
-- set date_name_xlate() second argument to true to translate English digits to local digits (will translate ymd dates) | -- set date_name_xlate() second argument to true to translate English digits to local digits (will translate ymd dates) | ||
-- | -- if date_name_xlate (date_parameters_list, false) then | ||
-- | -- modified = true; | ||
-- | -- end | ||
if modified then -- if the date_parameters_list values were modified | if modified then -- if the date_parameters_list values were modified | ||
Line 2,845: | Line 2,908: | ||
end -- end of do | end -- end of do | ||
-- | -- Link the title of the work if no |url= was provided, but we have a |pmc= or a |doi= with |doi-access=free | ||
-- Here we unset Embargo if PMC not embargoed (|embargo= not set in the citation) or if the embargo time has expired. Otherwise, holds embargo date | -- Here we unset Embargo if PMC not embargoed (|embargo= not set in the citation) or if the embargo time has expired. Otherwise, holds embargo date | ||
Embargo = is_embargoed (Embargo); | Embargo = is_embargoed (Embargo); | ||
if config.CitationClass == "journal" and not is_set(URL) and is_set(ID_list['PMC']) | if config.CitationClass == "journal" and not is_set(URL) and not is_set(TitleLink) then | ||
if is_set(ID_list['PMC']) and not is_set (Embargo) then -- if not embargoed or embargo has expired | |||
URL=cfg.id_handlers['PMC'].prefix .. ID_list['PMC']; -- set url to be the same as the PMC external link if not embargoed | URL=cfg.id_handlers['PMC'].prefix .. ID_list['PMC']; -- set url to be the same as the PMC external link if not embargoed | ||
URL_origin = cfg.id_handlers['PMC'].parameters[1]; -- set URL_origin to parameter name for use in error message if citation is missing a |title= | |||
if is_set(AccessDate) then | elseif is_set(ID_list['DOI']) and ID_access_levels['DOI'] == "free" then | ||
URL=cfg.id_handlers['DOI'].prefix .. ID_list['DOI']; | |||
URL_origin = cfg.id_handlers['DOI'].parameters[1]; | |||
end | |||
if is_set(URL) and is_set(AccessDate) then -- access date requires |url=; pmc or doi created url is not |url= | |||
table.insert( z.message_tail, { set_error( 'accessdate_missing_url', {}, true ) } ); | |||
AccessDate = ''; -- unset | |||
end | end | ||
end | end | ||
Line 2,863: | Line 2,928: | ||
-- At this point fields may be nil if they weren't specified in the template use. We can use that fact. | -- At this point fields may be nil if they weren't specified in the template use. We can use that fact. | ||
-- Test if citation has no title | -- Test if citation has no title | ||
if not is_set(Title) and | if not is_set(Title) and not is_set(TransTitle) and not is_set(ScriptTitle) then -- has special case for cite episode | ||
table.insert( z.message_tail, { set_error( 'citation_missing_title', {'episode' == config.CitationClass and 'series' or 'title'}, true ) } ); | |||
end | end | ||
if 'none' | if cfg.keywords_xlate[Title] == 'none' and | ||
in_array (config.CitationClass, {'journal', 'citation'}) and | in_array (config.CitationClass, {'journal', 'citation'}) and | ||
(is_set (Periodical) or is_set (ScriptPeriodical)) and | (is_set (Periodical) or is_set (ScriptPeriodical)) and | ||
Line 2,905: | Line 2,964: | ||
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 = COinS({ | local OCinSoutput = COinS({ | ||
['Periodical'] = strip_apostrophe_markup (Periodical), -- no markup in the metadata | ['Periodical'] = strip_apostrophe_markup (Periodical), -- no markup in the metadata | ||
['Encyclopedia'] = | ['Encyclopedia'] = Encyclopedia, -- just a flag; content ignored by ~/COinS | ||
['Chapter'] = make_coins_title (coins_chapter, ScriptChapter), -- Chapter and ScriptChapter stripped of bold / italic wikimarkup | ['Chapter'] = make_coins_title (coins_chapter, ScriptChapter), -- Chapter and ScriptChapter stripped of bold / italic wikimarkup | ||
['Degree'] = Degree; -- cite thesis only | ['Degree'] = Degree; -- cite thesis only | ||
Line 2,916: | Line 2,975: | ||
['Date'] = COinS_date.rftdate, -- COinS_date has correctly formatted date if Date is valid; | ['Date'] = COinS_date.rftdate, -- COinS_date has correctly formatted date if Date is valid; | ||
['Season'] = COinS_date.rftssn, | ['Season'] = COinS_date.rftssn, | ||
['Quarter'] = COinS_date.rftquarter, | |||
['Chron'] = COinS_date.rftchron or (not COinS_date.rftdate and Date) or '', -- chron but if not set and invalid date format use Date; keep this last bit? | ['Chron'] = COinS_date.rftchron or (not COinS_date.rftdate and Date) or '', -- chron but if not set and invalid date format use Date; keep this last bit? | ||
['Series'] = Series, | ['Series'] = Series, | ||
Line 2,922: | Line 2,982: | ||
['Pages'] = coins_pages or get_coins_pages (first_set ({Sheet, Sheets, Page, Pages, At}, 5)), -- pages stripped of external links | ['Pages'] = coins_pages or get_coins_pages (first_set ({Sheet, Sheets, Page, Pages, At}, 5)), -- pages stripped of external links | ||
['Edition'] = Edition, | ['Edition'] = Edition, | ||
['PublisherName'] = PublisherName, | ['PublisherName'] = PublisherName or Newsgroup, -- any apostrophe markup already removed from PublisherName | ||
['URL'] = first_set ({ChapterURL, URL}, 2), | ['URL'] = first_set ({ChapterURL, URL}, 2), | ||
['Authors'] = coins_author, | ['Authors'] = coins_author, | ||
Line 2,930: | Line 2,990: | ||
-- Account for the oddities that are {{cite arxiv}}, {{cite biorxiv}}, {{cite citeseerx}}, and {{cite ssrn}} AFTER generation of COinS data. | -- Account for the oddities that are {{cite arxiv}}, {{cite biorxiv}}, {{cite citeseerx}}, and {{cite ssrn}} AFTER generation of COinS data. | ||
if in_array (config.CitationClass, | if in_array (config.CitationClass, whitelist.preprint_template_list) then -- we have set rft.jtitle in COinS to arXiv, bioRxiv, CiteSeerX, or ssrn now unset so it isn't displayed | ||
Periodical = ''; -- periodical not allowed in these templates; if article has been published, use cite journal | Periodical = ''; -- periodical not allowed in these templates; if article has been published, use cite journal | ||
end | end | ||
-- special case for cite newsgroup. Do this after COinS because we are modifying Publishername to include some static text | -- special case for cite newsgroup. Do this after COinS because we are modifying Publishername to include some static text | ||
if 'newsgroup' == config.CitationClass | if 'newsgroup' == config.CitationClass and is_set (Newsgroup) then | ||
PublisherName = substitute (cfg.messages['newsgroup'], external_link( 'news:' .. Newsgroup, Newsgroup, Newsgroup_origin, nil )); | |||
end | end | ||
Line 2,951: | Line 3,009: | ||
maximum = nil, -- as if display-authors or display-editors not set | maximum = nil, -- as if display-authors or display-editors not set | ||
lastauthoramp = LastAuthorAmp, | lastauthoramp = LastAuthorAmp, | ||
mode = Mode | mode = Mode | ||
}; | }; | ||
Line 2,963: | Line 3,020: | ||
if editor_etal then | if editor_etal then | ||
Editors = Editors .. ' ' .. cfg.messages['et al']; -- add et al. to editors parameter beause |display-editors=etal | Editors = Editors .. ' ' .. cfg.messages['et al']; -- add et al. to editors parameter beause |display-editors=etal | ||
end | end | ||
EditorCount = 2; -- we don't know but assume |editors= is multiple names; spoof to display (eds.) annotation | |||
else | else | ||
Editors = last_first_list; -- either an author name list or an empty string | Editors = last_first_list; -- either an author name list or an empty string | ||
Line 3,035: | Line 3,090: | ||
end | end | ||
local OriginalURL, | 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 is_set( ArchiveURL ) then | if is_set( ArchiveURL ) then | ||
if is_set (ChapterURL) then -- if chapter-url is set apply archive url to it | if is_set (ChapterURL) then -- if chapter-url is set apply archive url to it | ||
OriginalURL = ChapterURL; -- save copy of source chapter's url for archive text | OriginalURL = ChapterURL; -- save copy of source chapter's url for archive text | ||
OriginalURL_origin = ChapterURL_origin; -- name of chapter-url parameter for error messages | |||
OriginalFormat = ChapterFormat; -- and original |chapter-format= | OriginalFormat = ChapterFormat; -- and original |chapter-format= | ||
if 'live' ~= UrlStatus then | if 'live' ~= UrlStatus then | ||
ChapterURL = ArchiveURL -- swap-in the archive's url | ChapterURL = ArchiveURL -- swap-in the archive's url | ||
ChapterURL_origin = A:ORIGIN('ArchiveURL') -- name of archive-url parameter for error messages | |||
ChapterFormat = ArchiveFormat or ''; -- swap in archive's format | ChapterFormat = ArchiveFormat or ''; -- swap in archive's format | ||
ChapterUrlAccess = nil; -- restricted access levels do not make sense for archived urls | ChapterUrlAccess = nil; -- restricted access levels do not make sense for archived urls | ||
Line 3,052: | Line 3,106: | ||
elseif is_set (URL) then | elseif is_set (URL) then | ||
OriginalURL = URL; -- save copy of original source URL | OriginalURL = URL; -- save copy of original source URL | ||
OriginalURL_origin = URL_origin; -- name of url parameter for error messages | |||
OriginalFormat = Format; -- and original |format= | OriginalFormat = Format; -- and original |format= | ||
OriginalAccess = UrlAccess; | OriginalAccess = UrlAccess; | ||
if 'live' ~= UrlStatus then -- if URL set then archive-url applies to it | if 'live' ~= UrlStatus then -- if URL set then archive-url applies to it | ||
URL = ArchiveURL -- swap-in the archive's url | URL = ArchiveURL -- swap-in the archive's url | ||
URL_origin = A:ORIGIN('ArchiveURL') -- name of archive url parameter for error messages | |||
Format = ArchiveFormat or ''; -- swap in archive's format | Format = ArchiveFormat or ''; -- swap in archive's format | ||
UrlAccess = nil; -- restricted access levels do not make sense for archived urls | UrlAccess = nil; -- restricted access levels do not make sense for archived urls | ||
Line 3,075: | Line 3,129: | ||
chap_param = A:ORIGIN ('ChapterURL') | chap_param = A:ORIGIN ('ChapterURL') | ||
elseif is_set (ScriptChapter) then | elseif is_set (ScriptChapter) then | ||
chap_param = | chap_param = ScriptChapter_origin; | ||
else is_set (ChapterFormat) | else is_set (ChapterFormat) | ||
chap_param = A:ORIGIN ('ChapterFormat') | chap_param = A:ORIGIN ('ChapterFormat') | ||
Line 3,091: | Line 3,145: | ||
local no_quotes = false; -- default assume that we will be quoting the chapter parameter value | local no_quotes = false; -- default assume that we will be quoting the chapter parameter value | ||
if is_set (Contribution) and 0 < #c then -- if this is a contribution with contributor(s) | if is_set (Contribution) and 0 < #c then -- if this is a contribution with contributor(s) | ||
if in_array (Contribution:lower(), cfg. | if in_array (Contribution:lower(), cfg.keywords_lists.contribution) then -- and a generic contribution title | ||
no_quotes = true; -- then render it unquoted | no_quotes = true; -- then render it unquoted | ||
end | end | ||
end | end | ||
Chapter = format_chapter_title (ScriptChapter, | Chapter = format_chapter_title (ScriptChapter, ScriptChapter_origin, Chapter, Chapter_origin, TransChapter, TransChapter_origin, ChapterURL, ChapterURL_origin, no_quotes, ChapterUrlAccess); -- Contribution is also in Chapter | ||
if is_set (Chapter) then | if is_set (Chapter) then | ||
Chapter = Chapter .. ChapterFormat ; | Chapter = Chapter .. ChapterFormat ; | ||
Line 3,108: | Line 3,162: | ||
end | end | ||
-- Format main title | -- Format main title | ||
if is_set (ArchiveURL) and mw.ustring.match (mw.ustring.lower(Title), cfg.special_case_translation | if is_set (ArchiveURL) and | ||
add_maint_cat ('archived_copy'); | (mw.ustring.match (mw.ustring.lower(Title), cfg.special_case_translation.archived_copy.en) or -- if title is 'Archived copy' (place holder added by bots that can't find proper title) | ||
mw.ustring.match (mw.ustring.lower(Title), cfg.special_case_translation.archived_copy['local'])) then -- local-wiki's form | |||
add_maint_cat ('archived_copy'); -- add maintenance category before we modify the content of Title | |||
end | end | ||
Line 3,123: | Line 3,179: | ||
end | end | ||
end | end | ||
if in_array(config.CitationClass, {'web', 'news', 'journal', 'magazine', 'pressrelease', 'podcast', 'newsgroup', 'mailinglist', 'interview', 'arxiv', 'biorxiv', 'citeseerx', 'ssrn'}) or | if in_array(config.CitationClass, {'web', 'news', 'journal', 'magazine', 'pressrelease', 'podcast', 'newsgroup', 'mailinglist', 'interview', 'arxiv', 'biorxiv', 'citeseerx', 'ssrn'}) or | ||
('citation' == config.CitationClass and (is_set (Periodical) or is_set (ScriptPeriodical)) and not is_set (Encyclopedia)) or | ('citation' == config.CitationClass and (is_set (Periodical) or is_set (ScriptPeriodical)) and not is_set (Encyclopedia)) or | ||
Line 3,149: | Line 3,205: | ||
end | end | ||
if is_set(Title) then | if is_set (Title) then -- TODO: is this the right place to be making wikisource urls? | ||
if is_set (TitleLink) and is_set (URL) then | |||
table.insert( z.message_tail, { set_error( 'wikilink_in_url', {}, true ) } ); -- set an error message because we can't have both | |||
TitleLink = ''; -- unset | |||
end | |||
if not is_set (TitleLink) and is_set (URL) then | if not is_set (TitleLink) and is_set (URL) then | ||
Title = external_link (URL, Title, | Title = external_link (URL, Title, URL_origin, UrlAccess) .. TransTitle .. TransError .. Format; | ||
URL = ''; -- unset these because no longer needed | URL = ''; -- unset these because no longer needed | ||
Format = ""; | Format = ""; | ||
Line 3,165: | Line 3,226: | ||
end | end | ||
else | else | ||
local ws_url, ws_label; | local ws_url, ws_label; -- 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); | 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 tool tip 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,186: | Line 3,247: | ||
if is_set (Conference) then | if is_set (Conference) then | ||
if is_set (ConferenceURL) then | if is_set (ConferenceURL) then | ||
Conference = external_link( ConferenceURL, Conference, | Conference = external_link( ConferenceURL, Conference, ConferenceURL_origin, nil ); | ||
end | end | ||
Conference = sepc .. " " .. Conference .. ConferenceFormat; | Conference = sepc .. " " .. Conference .. ConferenceFormat; | ||
elseif is_set(ConferenceURL) then | elseif is_set(ConferenceURL) then | ||
Conference = sepc .. " " .. external_link( ConferenceURL, nil, | Conference = sepc .. " " .. external_link( ConferenceURL, nil, ConferenceURL_origin, nil ); | ||
end | end | ||
Line 3,224: | Line 3,285: | ||
Position = is_set(Position) and (sepc .. " " .. Position) or ""; | Position = is_set(Position) and (sepc .. " " .. Position) or ""; | ||
if config.CitationClass == 'map' then | if config.CitationClass == 'map' then | ||
local Sections = A['Sections']; -- Section (singular) is an alias of Chapter so set earlier | |||
local Sections = A['Sections']; | |||
local Inset = A['Inset']; | local Inset = A['Inset']; | ||
Line 3,275: | Line 3,335: | ||
------------------------------------ totally unrelated data | ------------------------------------ totally unrelated data | ||
Via = is_set (Via) and wrap_msg ('via', Via) or ''; | Via = is_set (Via) and wrap_msg ('via', Via) or ''; | ||
if is_set(AccessDate) then | if is_set(AccessDate) then | ||
Line 3,310: | Line 3,357: | ||
if is_set(URL) then | if is_set(URL) then | ||
URL = " " .. external_link( URL, nil, | URL = " " .. external_link( URL, nil, URL_origin, UrlAccess ); | ||
end | end | ||
Line 3,323: | Line 3,370: | ||
local Archived | local Archived | ||
if is_set(ArchiveURL) then | if is_set(ArchiveURL) then | ||
local arch_text; | |||
if not is_set(ArchiveDate) then | if not is_set(ArchiveDate) then | ||
ArchiveDate = set_error('archive_missing_date'); | ArchiveDate = set_error('archive_missing_date'); | ||
end | end | ||
if "live" == UrlStatus then | if "live" == UrlStatus then | ||
arch_text = cfg.messages['archived']; | |||
if sepc ~= "." then arch_text = arch_text:lower() end | if sepc ~= "." then arch_text = arch_text:lower() end | ||
Archived = sepc .. " " .. substitute( cfg.messages['archived-live'], | Archived = sepc .. " " .. substitute( cfg.messages['archived-live'], | ||
{ external_link( ArchiveURL, arch_text, A:ORIGIN('ArchiveURL'), nil ) .. ArchiveFormat, ArchiveDate } ); | { external_link( ArchiveURL, arch_text, A:ORIGIN('ArchiveURL'), nil ) .. ArchiveFormat, ArchiveDate } ); | ||
if not is_set(OriginalURL) then | if not is_set (OriginalURL) then | ||
Archived = Archived .. " " .. set_error('archive_missing_url'); | Archived = Archived .. " " .. set_error('archive_missing_url'); | ||
end | end | ||
elseif is_set(OriginalURL) then -- UrlStatus is empty, 'dead', 'unfit', 'usurped', 'bot: unknown' | elseif is_set(OriginalURL) then -- UrlStatus is empty, 'dead', 'unfit', 'usurped', 'bot: unknown' | ||
if in_array (UrlStatus, {'unfit', 'usurped', 'bot: unknown'}) then | if in_array (UrlStatus, {'unfit', 'usurped', 'bot: unknown'}) then | ||
Archived = sepc .. " " .. | arch_text = cfg.messages['archived-unfit']; | ||
if sepc ~= "." then arch_text = arch_text:lower() end | |||
Archived = sepc .. " " .. arch_text .. ArchiveDate; -- format already styled | |||
if 'bot: unknown' == UrlStatus then | if 'bot: unknown' == UrlStatus then | ||
add_maint_cat ('bot:_unknown'); -- and add a category if not already added | add_maint_cat ('bot:_unknown'); -- and add a category if not already added | ||
Line 3,345: | Line 3,393: | ||
end | end | ||
else -- UrlStatus is empty, 'dead' | else -- UrlStatus is empty, 'dead' | ||
arch_text = cfg.messages['archived-dead']; | |||
if sepc ~= "." then arch_text = arch_text:lower() end | |||
Archived = sepc .. " " .. substitute( arch_text, | Archived = sepc .. " " .. substitute( arch_text, | ||
{ external_link( OriginalURL, cfg.messages['original'], | { external_link( OriginalURL, cfg.messages['original'], OriginalURL_origin, OriginalAccess ) .. OriginalFormat, ArchiveDate } ); -- format already styled | ||
end | end | ||
else | else -- OriginalUrl not set | ||
arch_text = cfg.messages['archived-missing']; | |||
if sepc ~= "." then arch_text = arch_text:lower() end | if sepc ~= "." then arch_text = arch_text:lower() end | ||
Archived = sepc .. " " .. substitute( arch_text, | Archived = sepc .. " " .. substitute( arch_text, | ||
Line 3,379: | Line 3,429: | ||
if is_set(Transcript) then | if is_set(Transcript) then | ||
if is_set(TranscriptURL) then | if is_set(TranscriptURL) then | ||
Transcript = external_link( TranscriptURL, Transcript, | Transcript = external_link( TranscriptURL, Transcript, TranscriptURL_origin, nil ); | ||
end | end | ||
Transcript = sepc .. ' ' .. Transcript .. TranscriptFormat; | Transcript = sepc .. ' ' .. Transcript .. TranscriptFormat; | ||
elseif is_set(TranscriptURL) then | elseif is_set(TranscriptURL) then | ||
Transcript = external_link( TranscriptURL, nil, | Transcript = external_link( TranscriptURL, nil, TranscriptURL_origin, nil ); | ||
end | end | ||
Line 3,405: | Line 3,455: | ||
if (is_set (Periodical) or is_set (ScriptPeriodical) or is_set (TransPeriodical)) then | if (is_set (Periodical) or is_set (ScriptPeriodical) or is_set (TransPeriodical)) then | ||
if is_set(Title) or is_set(TitleNote) then | if is_set(Title) or is_set(TitleNote) then | ||
Periodical = sepc .. " " .. format_periodical (ScriptPeriodical, ScriptPeriodical_origin, Periodical, TransPeriodical); | Periodical = sepc .. " " .. format_periodical (ScriptPeriodical, ScriptPeriodical_origin, Periodical, TransPeriodical, TransPeriodical_origin); | ||
else | else | ||
Periodical = format_periodical (ScriptPeriodical, ScriptPeriodical_origin, Periodical, TransPeriodical); | Periodical = format_periodical (ScriptPeriodical, ScriptPeriodical_origin, Periodical, TransPeriodical, TransPeriodical_origin); | ||
end | end | ||
end | end | ||
Line 3,467: | Line 3,517: | ||
local idcommon; | local idcommon; | ||
if 'audio-visual' == config.CitationClass or 'episode' == config.CitationClass then -- special case for cite AV media & cite episode position transcript | if 'audio-visual' == config.CitationClass or 'episode' == config.CitationClass then -- special case for cite AV media & cite episode position transcript | ||
idcommon = safe_join( { ID_list, URL, Archived, Transcript, AccessDate, Via | idcommon = safe_join( { ID_list, URL, Archived, Transcript, AccessDate, Via, Lay, Quote }, sepc ); | ||
else | else | ||
idcommon = safe_join( { ID_list, URL, Archived, AccessDate, Via | idcommon = safe_join( { ID_list, URL, Archived, AccessDate, Via, Lay, Quote }, sepc ); | ||
end | end | ||
Line 3,554: | Line 3,604: | ||
if is_set(config.CitationClass) and config.CitationClass ~= "citation" then | if is_set(config.CitationClass) and config.CitationClass ~= "citation" then | ||
options.class = | options.class = string.format ('%s %s %s', 'citation', config.CitationClass, is_set (Mode) and Mode or 'cs1'); -- class=citation required for blue highlight when used with |ref= | ||
else | else | ||
options.class = | options.class = string.format ('%s %s', 'citation', is_set (Mode) and Mode or 'cs2'); | ||
end | end | ||
if is_set(Ref) and Ref:lower() | if is_set(Ref) and 'none' ~= cfg.keywords_xlate[Ref:lower()] then | ||
local id = Ref | local id = Ref | ||
if ('harv' == Ref ) then | if ('harv' == Ref ) then | ||
Line 3,624: | Line 3,673: | ||
end | end | ||
if not no_tracking_cats then | |||
if | |||
for _, v in ipairs( z.error_categories ) do | for _, v in ipairs( z.error_categories ) do | ||
table.insert (render, make_wikilink ('Category:' .. v)); | table.insert (render, make_wikilink ('Category:' .. v)); | ||
Line 3,655: | Line 3,703: | ||
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 | |||
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 | ||
Line 3,663: | Line 3,709: | ||
return true; | return true; | ||
end | end | ||
return nil; | |||
end | |||
state = whitelist[cite_class | if name:find ('#') then -- # is a cs1|2 reserved character so parameters with # not permitted | ||
return nil; | |||
end | |||
if in_array (cite_class, whitelist.preprint_template_list ) then -- limited parameter sets allowed for these templates | |||
state = whitelist.limited_basic_arguments[name]; | |||
if true == state_test (state, name) then return true; end | |||
state = whitelist.preprint_arguments[cite_class][name]; -- look in the parameter-list for the template identified by cite_class | |||
if true == state_test (state, name) then return true; end | |||
-- 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) | name = name:gsub("%d+", "#" ); -- replace digit(s) with # (last25 becomes last#) (mw.ustring because non-Western 'local' digits) | ||
state = whitelist.limited_numbered_arguments[name]; | state = whitelist.limited_numbered_arguments[name]; | ||
if true == state | if true == state_test (state, name) then return true; end | ||
return false; -- not supported because not found or name is set to nil | return false; -- not supported because not found or name is set to nil | ||
end -- end limited parameter-set templates | end -- end limited parameter-set templates | ||
if in_array (cite_class, whitelist.unique_param_template_list) then -- experiment for template-specific parameters for templates that accept parameters from the basic argument list | |||
state = whitelist.unique_arguments[cite_class][name]; -- look in the template-specific parameter-lists for the template identified by cite_class | |||
if true == state_test (state, name) then return true; end | |||
end -- if here, fall into general validation | |||
state = whitelist.basic_arguments[name]; -- all other templates; all normal parameters allowed | state = whitelist.basic_arguments[name]; -- all other templates; all normal parameters allowed | ||
if true == state_test (state, name) then return true; end | |||
if true == state then return true; end | |||
-- 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) | name = name:gsub("%d+", "#" ); -- replace digit(s) with # (last25 becomes last#) (mw.ustring because non-Western 'local' digits) | ||
state = whitelist.numbered_arguments[name]; | state = whitelist.numbered_arguments[name]; | ||
if true == state_test (state, name) then return true; end | |||
return false; -- not supported because not found or name is set to nil | return false; -- not supported because not found or name is set to nil | ||
end | end | ||
Line 3,708: | Line 3,752: | ||
Look at the contents of a parameter. If the content has a string of characters and digits followed by an equal | Look at the contents of a parameter. If the content has a string of characters and digits followed by an equal | ||
sign, compare the alphanumeric string to the list of cs1|2 parameters. If found, then the string is possibly a | sign, compare the alphanumeric string to the list of cs1|2 parameters. If found, then the string is possibly a | ||
parameter that is missing its pipe: | parameter that is missing its pipe. There are two tests made: | ||
{{cite ... |title=Title access-date=2016-03-17}} | {{cite ... |title=Title access-date=2016-03-17}} -- the first parameter has a value and whitespace separates that value from the missing pipe parameter name | ||
{{cite ... |title=access-date=2016-03-17}} -- the first parameter has no value (whitespace after the first = is trimmed by mediawiki) | |||
cs1|2 shares some parameter names with xml/html atributes: class=, title=, etc. To prevent false positives xml/html | cs1|2 shares some parameter names with xml/html atributes: class=, title=, etc. To prevent false positives xml/html | ||
tags are removed before the search. | tags are removed before the search. | ||
Line 3,723: | Line 3,767: | ||
capture = value:match ('%s+(%a[%w%-]+)%s*=') or value:match ('^(%a[%w%-]+)%s*='); -- find and categorize parameters with possible missing pipes | capture = value:match ('%s+(%a[%w%-]+)%s*=') or value:match ('^(%a[%w%-]+)%s*='); -- find and categorize parameters with possible missing pipes | ||
if capture and validate (capture) then | if capture and validate (capture) then -- if the capture is a valid parameter name | ||
table.insert( z.message_tail, {set_error ('missing_pipe',parameter)}); | table.insert( z.message_tail, {set_error ('missing_pipe', parameter)}); | ||
end | end | ||
end | end | ||
Line 3,736: | Line 3,780: | ||
local function has_extraneous_punc (param, value) | local function has_extraneous_punc (param, value) | ||
if 'number' == type (param) then | |||
return; | |||
end | |||
param = param:gsub ('%d+', '#'); -- enumerated name-list mask params allow terminal punct; normalize | |||
if cfg.punct_skip[param] then | if cfg.punct_skip[param] then | ||
return; -- parameter name found in the skip table so done | return; -- parameter name found in the skip table so done | ||
Line 3,817: | Line 3,866: | ||
local config = {}; -- table to store parameters from the module {{#invoke:}} | local config = {}; -- table to store parameters from the module {{#invoke:}} | ||
for k, v in pairs( frame.args ) do | for k, v in pairs( frame.args ) do -- get parameters from the {{#invoke}} frame | ||
config[k] = v; | config[k] = v; | ||
-- | -- args[k] = v; -- crude debug support that allows us to render a citation from module {{#invoke:}}; skips parameter validation; TODO: keep? | ||
end | end | ||
local capture; -- the single supported capture when matching unknown parameters using patterns | local capture; -- the single supported capture when matching unknown parameters using patterns | ||
for k, v in pairs( pframe.args ) do | for k, v in pairs( pframe.args ) do -- get parameters from the parent (template) frame | ||
if v ~= '' then | if v ~= '' then | ||
if ('string' == type (k)) then | if ('string' == type (k)) then | ||
Line 3,853: | Line 3,902: | ||
else | else | ||
error_text, error_state = set_error( 'parameter_ignored', {param}, true ); -- suggested param not supported by this template | error_text, error_state = set_error( 'parameter_ignored', {param}, true ); -- suggested param not supported by this template | ||
v = ''; -- unset | |||
end | end | ||
end | end | ||
Line 3,869: | Line 3,919: | ||
end | end | ||
end | end | ||
-- TODO: | args[k] = v; -- save this parameter and its value | ||
-- crude debug support that allows us to render a citation from module {{#invoke:}} TODO: keep? | |||
-- elseif args[k] ~= nil or (k == 'postscript') then -- when args[k] has a value from {{#invoke}} frame (we don't normally do that) | |||
end | -- args[k] = v; -- overwrite args[k] with empty string from pframe.args[k] (template frame); v is empty string here | ||
end -- not sure about the postscript bit; that gets handled in parameter validation; historical artifact? | |||
end | end | ||
for k, v in pairs( args ) do | for k, v in pairs( args ) do | ||
if 'string' == type (k) then -- don't evaluate positional parameters | if 'string' == type (k) then -- don't evaluate positional parameters | ||
has_invisible_chars | has_invisible_chars (k, v); -- look for invisible characters | ||
end | end | ||
has_extraneous_punc (k, v); -- look for extraneous terminal punctuation in parameter values | |||
missing_pipe_check (k, v); -- do we think that there is a parameter that is missing a pipe? | |||
end | end | ||
return table.concat ({citation0( config, args), frame:extensionTag ('templatestyles', '', {src=styles})}); | return table.concat ({citation0( config, args), frame:extensionTag ('templatestyles', '', {src=styles})}); | ||
end | end |