Module:Citation/CS1: Difference between revisions
Content added Content deleted
m (1 revision imported) |
(don't evaluate positional parameters for invisible chars;) |
||
Line 1: | Line 1: | ||
local cs1 ={}; |
|||
--[[--------------------------< F O R W A R D D E C L A R A T I O N S >-------------------------------------- |
--[[--------------------------< F O R W A R D D E C L A R A T I O N S >-------------------------------------- |
||
Line 9: | Line 7: | ||
local is_set, in_array, substitute, error_comment, set_error, select_one, -- functions in Module:Citation/CS1/Utilities |
local is_set, in_array, substitute, error_comment, set_error, select_one, -- functions in Module:Citation/CS1/Utilities |
||
add_maint_cat, wrap_style, safe_for_italics, is_wikilink, make_wikilink |
add_maint_cat, wrap_style, safe_for_italics, is_wikilink, make_wikilink, |
||
strip_apostrophe_markup; |
|||
local z ={}; -- tables in Module:Citation/CS1/Utilities |
local z ={}; -- tables in Module:Citation/CS1/Utilities |
||
Line 23: | 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 71: | 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)); |
table.insert( z.properties_cats, substitute (cfg.prop_cats [key], arguments)); -- make name then add to table |
||
end |
end |
||
end |
end |
||
Line 133: | Line 131: | ||
the first character of the whole domain name including subdomains must be a letter or a digit |
the first character of the whole domain name including subdomains must be a letter or a digit |
||
internationalized domain name (ascii characters with .xn-- ASCII Compatible Encoding (ACE) prefix xn-- in the tld) see https://tools.ietf.org/html/rfc3490 |
internationalized domain name (ascii characters with .xn-- ASCII Compatible Encoding (ACE) prefix xn-- in the tld) see https://tools.ietf.org/html/rfc3490 |
||
single-letter/digit second-level domains in the .org and . |
single-letter/digit second-level domains in the .org, .cash, and .today TLDs |
||
q, x, and z SL domains in the .com TLD |
q, x, and z SL domains in the .com TLD |
||
i and q SL domains in the .net TLD |
i and q SL domains in the .net TLD |
||
Line 152: | Line 150: | ||
domain = domain:gsub ('^//', ''); -- strip '//' from domain name if present; done here so we only have to do it once |
domain = domain:gsub ('^//', ''); -- strip '//' from domain name if present; done here so we only have to do it once |
||
if not domain:match ('^[% |
if not domain:match ('^[%w]') then -- first character must be letter or digit |
||
return false; |
return false; |
||
end |
end |
||
Line 159: | Line 157: | ||
return false; |
return false; |
||
end |
end |
||
-- Do most common case first |
|||
local patterns = { -- patterns that look like urls |
|||
if domain:match ('%f[%a%d][%a%d][%a%d%-]+[%a%d]%.%a%a+$') then -- three or more character hostname.hostname or hostname.tld |
|||
'%f[%w][%w][%w%-]+[%w]%.%a%a+$', -- three or more character hostname.hostname or hostname.tld |
|||
return true; |
|||
'%f[%w][%w][%w%-]+[%w]%.xn%-%-[%w]+$', -- internationalized domain name with ACE prefix |
|||
'%f[%a][qxz]%.com$', -- assigned one character .com hostname (x.com times out 2015-12-10) |
|||
return true; |
|||
'%f[%a][iq]%.net$', -- assigned one character .net hostname (q.net registered but not active 2015-12-10) |
|||
'%f[%w][%w]%.%a%a$', -- one character hostname and cctld (2 chars) |
|||
return true; |
|||
'%f[%w][%w][%w]%.%a%a+$', -- two character hostname and tld |
|||
'^%d%d?%d?%.%d%d?%d?%.%d%d?%d?%.%d%d?%d?', -- IPv4 address |
|||
return true; |
|||
} |
|||
elseif domain:match ('%f[%a][qxz]%.com$') then -- assigned one character .com hostname (x.com times out 2015-12-10) |
|||
return true; |
|||
for _, pattern in ipairs (patterns) do -- loop through the patterns list |
|||
elseif domain:match ('%f[%a][iq]%.net$') then -- assigned one character .net hostname (q.net registered but not active 2015-12-10) |
|||
if domain:match (pattern) then |
|||
return true; |
|||
return true; -- if a match then we think that this thing that purports to be a url is a url |
|||
elseif domain:match ('%f[%a%d][%a%d]%.%a%a$') then -- one character hostname and cctld (2 chars) |
|||
end |
|||
return true; |
|||
end |
|||
elseif domain:match ('%f[%a%d][%a%d][%a%d]%.%a%a+$') then -- two character hostname and tld |
|||
return true; |
|||
for _, d in ipairs ({'cash', 'company', 'today', 'org'}) do -- look for single letter second level domain names for these top level domains |
|||
elseif domain:match ('^%d%d?%d?%.%d%d?%d?%.%d%d?%d?%.%d%d?%d?') then -- IPv4 address |
|||
if domain:match ('%f[%w][%w]%.' .. d) then |
|||
return true; |
|||
return true |
|||
else |
|||
end |
|||
return false; |
|||
end |
end |
||
return false; -- no matches, we don't know what this thing is |
|||
end |
end |
||
Line 445: | Line 444: | ||
if not added_deprecated_cat then |
if not added_deprecated_cat then |
||
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, { set_error( 'deprecated_params', {name}, true ) } ); |
table.insert( z.message_tail, { set_error( 'deprecated_params', {name}, true ) } ); -- add error message |
||
end |
end |
||
end |
end |
||
Line 527: | Line 526: | ||
is not added. At this time there is no error message for this condition. |
is not added. At this time there is no error message for this condition. |
||
Supports |script-title= |
Supports |script-title=, |script-chapter=, |script-<periodical>= |
||
TODO: error messages when prefix is invalid ISO639-1 code; when script_value has prefix but no script; |
|||
]] |
]] |
||
local function format_script_value (script_value) |
local function format_script_value (script_value, script_param) |
||
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 |
|||
return ''; -- script_value was just the prefix so return empty string |
return ''; -- script_value was just the prefix so return empty string |
||
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 |
||
add_prop_cat ('script_with_name', {name, lang}) |
add_prop_cat ('script_with_name', {name, lang}) |
||
else |
else |
||
table.insert( z.message_tail, { set_error( 'script_parameter', {script_param, 'unknown language code'}, true ) } ); -- unknown script-language; add error message |
|||
add_prop_cat ('script') |
|||
end |
end |
||
lang = ' lang="' .. lang .. '" '; -- convert prefix into a lang attribute |
lang = ' lang="' .. lang .. '" '; -- convert prefix into a lang attribute |
||
else |
else |
||
table.insert( z.message_tail, { set_error( 'script_parameter', {script_param, 'invalid language code'}, true ) } ); -- invalid language code; add error message |
|||
lang = ''; -- invalid so set lang to empty string |
lang = ''; -- invalid so set lang to empty string |
||
end |
end |
||
else |
|||
table.insert( z.message_tail, { set_error( 'script_parameter', {script_param, 'missing prefix'}, true ) } ); -- no language code prefix; add error message |
|||
end |
end |
||
script_value = substitute (cfg.presentation['bdi'], {lang, script_value}); -- isolate in case script is rtl |
script_value = substitute (cfg.presentation['bdi'], {lang, script_value}); -- isolate in case script is rtl |
||
Line 567: | Line 569: | ||
]] |
]] |
||
local function script_concatenate (title, script) |
local function script_concatenate (title, script, script_param) |
||
if is_set (script) then |
if is_set (script) then |
||
script = format_script_value (script); |
script = format_script_value (script, script_param); -- <bdi> tags, lang atribute, categorization, etc; returns empty string on error |
||
if is_set (script) then |
if is_set (script) then |
||
title = title .. ' ' .. script; -- concatenate title and script title |
title = title .. ' ' .. script; -- concatenate title and script title |
||
Line 593: | Line 595: | ||
local msg; |
local msg; |
||
msg = cfg.messages[key]:lower(); -- set the message to lower case before |
msg = cfg.messages[key]:lower(); -- set the message to lower case before |
||
return substitute( msg, str ); -- including template text |
return substitute( msg, str ); -- including template text |
||
else |
else |
||
return substitute( cfg.messages[key], str ); |
return substitute( cfg.messages[key], str ); |
||
Line 611: | 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 618: | 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 637: | 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 645: | 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 |
||
return ws_url, ws_label, L or D; |
return ws_url, ws_label, L or D; -- return proper url or nil and a label or nil |
||
end |
|||
--[[--------------------------< F O R M A T _ P E R I O D I C A L >-------------------------------------------- |
|||
Format the three periodical parameters: |script-<periodical>=, |<periodical>=, and |trans-<periodical>= into a single Periodical meta- |
|||
parameter. |
|||
]] |
|||
local function format_periodical (script_periodical, script_periodical_source, periodical, trans_periodical) |
|||
local periodical_error = ''; |
|||
if not is_set (periodical) then |
|||
periodical = ''; -- to be safe for concatenation |
|||
else |
|||
periodical = wrap_style ('italic-title', periodical); -- style |
|||
end |
|||
periodical = script_concatenate (periodical, script_periodical, script_periodical_source); -- <bdi> tags, lang atribute, categorization, etc; must be done after title is wrapped |
|||
if is_set (trans_periodical) then |
|||
trans_periodical = wrap_style ('trans-italic-title', trans_periodical); |
|||
if is_set (periodical) then |
|||
periodical = periodical .. ' ' .. trans_periodical; |
|||
else -- here when trans-periodical without periodical or script-periodical |
|||
periodical = trans_periodical; |
|||
periodical_error = ' ' .. set_error ('trans_missing_title', {'periodical'}); |
|||
end |
|||
end |
|||
return periodical .. periodical_error; |
|||
end |
end |
||
Line 659: | 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 = ''; |
||
local ws_url, ws_label, L = wikisource_url_make (chapter); |
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 ('_', ''); -- replace underscore separaters with space characters |
ws_label = ws_label:gsub ('_', ''); -- replace underscore separaters with space characters |
||
Line 677: | 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'); |
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 = substitute (cfg.presentation['interwiki-icon'], {cfg.presentation['class-wikisource'], L, chapter}); |
chapter = substitute (cfg.presentation['interwiki-icon'], {cfg.presentation['class-wikisource'], L, chapter}); |
||
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_source = trans_chapter_source:match ('trans%-?(.+)'); -- when no chapter, get matching name from trans-<param> |
|||
chapter_error = ' ' .. set_error ('trans_missing_title', {'chapter'}); |
|||
chapter_error = ' ' .. set_error ('trans_missing_title', {chapter_source}); |
|||
end |
end |
||
end |
end |
||
-- if is_set (chapterurl) then |
|||
-- chapter = external_link (chapterurl, chapter, chapter_url_source, access); -- adds bare_url_missing_title error if appropriate |
|||
-- end |
|||
return chapter .. chapter_error; |
return chapter .. chapter_error; |
||
Line 713: | Line 745: | ||
Detects but ignores nowiki and math stripmarkers. Also detects other named stripmarkers (gallery, math, pre, ref) |
Detects but ignores nowiki and math stripmarkers. Also detects other named stripmarkers (gallery, math, pre, ref) |
||
and identifies them with a slightly different error message. See also coins_cleanup(). |
and identifies them with a slightly different error message. See also coins_cleanup(). |
||
Detects but ignores the character pattern that results from the transclusion of {{'}} templates. |
|||
Output of this function is an error message that identifies the character or the Unicode group, or the stripmarker |
Output of this function is an error message that identifies the character or the Unicode group, or the stripmarker |
||
Line 802: | Line 832: | ||
-- maybe let through instead of raising an error? |
-- maybe let through instead of raising an error? |
||
-- v, origin[k] = args[k], k; |
-- v, origin[k] = args[k], k; |
||
error( cfg.messages['unknown_argument_map'] ); |
error( cfg.messages['unknown_argument_map'] .. ': ' .. k); |
||
end |
end |
||
-- Empty strings, not nil; |
-- Empty strings, not nil; |
||
if v == nil then |
if v == nil then |
||
v = cfg.defaults[k] or ''; |
-- v = cfg.defaults[k] or ''; |
||
v = ''; |
|||
origin[k] = ''; |
origin[k] = ''; |
||
end |
end |
||
Line 851: | 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 889: | 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 895: | 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,040: | Line 1,073: | ||
]] |
]] |
||
local function is_good_vanc_name (last, first) |
local function is_good_vanc_name (last, first, suffix) |
||
if not suffix then |
|||
local first, suffix = first:match ('(.-),?%s*([%dJS][%drndth]+)%.?$') or first; -- if first has something that looks like a generational suffix, get it |
|||
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,051: | 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,084: | 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,092: | 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,134: | 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,170: | Line 1,207: | ||
one = one .. namesep .. first; |
one = one .. namesep .. first; |
||
end |
end |
||
if is_set(person.link) and person.link ~= control.page_name then |
|||
one = make_wikilink (person.link, one); -- link author/editor if this page is not the author's/editor's page |
|||
end |
|||
end |
end |
||
if is_set (person.link) then |
|||
table.insert( text, one ) |
|||
one = make_wikilink (person.link, one); -- link author/editor |
|||
table.insert( text, sep_one ) |
|||
end |
|||
table.insert (text, one) |
|||
table.insert (text, sep_one) |
|||
end |
end |
||
end |
end |
||
Line 1,203: | 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,221: | Line 1,259: | ||
--[[--------------------------< 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 |
Evaluates the content of name parameters (author, editor, etc) for variations on the theme of et al. If found, |
||
the et al. is removed, a flag is set to true and the function returns the modified name and the flag. |
the et al. is removed, a flag is set to true and the function returns the modified name and the flag. |
||
This function never sets the flag to false but returns it's previous state because it may have been set by |
This function never sets the flag to false but returns it's previous state because it may have been set by |
||
previous passes through this function or by the |
previous passes through this function or by the associated |display-<names>=etal parameter |
||
]] |
]] |
||
local function name_has_etal (name, etal, nocat) |
local function name_has_etal (name, etal, nocat, param) |
||
if is_set (name) then -- name can be nil in which case just return |
if is_set (name) then -- name can be nil in which case just return |
||
local patterns = cfg.et_al_patterns; --get patterns from configuration |
|||
local etal_pattern = "[;,]? *[\"']*%f[%a][Ee][Tt] *[Aa][Ll][%.\"']*$" -- variations on the 'et al' theme |
|||
local others_pattern = "[;,]? *%f[%a]and [Oo]thers"; -- and alternate to et al. |
|||
for _, pattern in ipairs (patterns) do -- loop through all of the patterns |
|||
if name:match (pattern) then -- if this 'et al' pattern is found in name |
|||
name = name:gsub (pattern, ''); -- remove the offending text |
|||
etal = true; -- set flag (may have been set previously here or by |display-authors=etal) |
|||
etal = true; -- set flag (may have been set previously here or by |display-<names>=etal) |
|||
if not nocat then -- no categorization for |vauthors= |
|||
table.insert( z.message_tail, {set_error ('etal', {param})}); -- and set an error if not added |
|||
end |
|||
end |
|||
elseif name:match (others_pattern) then -- if not 'et al.', then 'and others'? |
|||
name = name:gsub (others_pattern, ''); -- if found, remove |
|||
etal = true; -- set flag (may have been set previously here or by |display-authors=etal) |
|||
if not nocat then -- no categorization for |vauthors= |
|||
add_maint_cat ('etal'); -- and add a category if not already added |
|||
end |
end |
||
end |
end |
||
end |
end |
||
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,258: | 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 _, pattern; |
|||
local patterns = { -- these patterns match annotations at end of name |
|||
'%f[%(%[][%(%[]%s*[Ee][Dd][Ss]?%.?%s*[%)%]]?$', -- (ed) or (eds): leading '(', case insensitive 'ed', optional 's', '.' and/or ')' |
|||
'[,%.%s]%f[e]eds?%.?$', -- ed or eds: without '('or ')'; case sensitive (ED could be initials Ed could be name) |
|||
'%f[%(%[][%(%[]%s*[Ee][Dd][Ii][Tt][Oo][Rr][Ss]?%.?%s*[%)%]]?$', -- (editor) or (editors): leading '(', case insensitive, optional '.' and/or ')' |
|||
'[,%.%s]%f[Ee][Ee][Dd][Ii][Tt][Oo][Rr][Ss]?%.?$', -- editor or editors: without '('or ')'; case insensitive |
|||
-- these patterns match annotations at beginning of name |
|||
'^eds?[%.,;]', -- ed. or eds.: lower case only, optional 's', requires '.' |
|||
'^[%(%[]%s*[Ee][Dd][Ss]?%.?%s*[%)%]]', -- (ed) or (eds): also sqare brackets, case insensitive, optional 's', '.' |
|||
'^[%(%[]?%s*[Ee][Dd][Ii][Tt][Oo][Rr][Ss]?%A', -- (editor or (editors: also sq brackets, case insensitive, optional brackets, 's' |
|||
'^[%(%[]?%s*[Ee][Dd][Ii][Tt][Ee][Dd]%A', -- (edited: also sq brackets, case insensitive, optional brackets |
|||
} |
|||
if is_set (name) then |
if is_set (name) then |
||
Line 1,284: | Line 1,326: | ||
end |
end |
||
end |
end |
||
return name; -- and done |
|||
end |
end |
||
Line 1,293: | 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 |
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,305: | Line 1,348: | ||
end |
end |
||
end |
end |
||
return name; -- and done |
|||
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,320: | 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,328: | 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,362: | 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, link_alias; -- selected parameter aliases used in error messaging |
|||
local err_msg_list_name = list_name:match ("(%w+)List") .. 's list'; -- modify AuthorList or EditorList for use in error messages if necessary |
|||
while true do |
while true do |
||
last = 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 = 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 ); |
||
last, etal = name_has_etal (last, etal, false); |
last, etal = name_has_etal (last, etal, false, last_alias); -- find and remove variations on et al. |
||
first, etal = name_has_etal (first, etal, false); |
first, etal = name_has_etal (first, etal, false, first_alias); -- find and remove variations on et al. |
||
last, first= name_checks (last, first, list_name); -- multiple names, extraneous annotation, etc checks |
last, first= name_checks (last, first, list_name); -- multiple names, extraneous annotation, etc checks |
||
if first and not last then -- if there is a firstn without a matching lastn |
if first and not last then -- if there is a firstn without a matching lastn |
||
table.insert( z.message_tail, { set_error( 'first_missing_last', { |
table.insert( z.message_tail, { set_error( 'first_missing_last', {first_alias, first_alias:gsub('first', 'last')}, true ) } ); -- add this error message |
||
elseif not first and not last then -- if both firstn and lastn aren't found, are we done? |
elseif not first and not last then -- if both firstn and lastn aren't found, are we done? |
||
count = count + 1; -- number of times we haven't found last and first |
count = count + 1; -- number of times we haven't found last and first |
||
Line 1,381: | 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) |
||
n = n + 1; -- point to next location in the names table |
n = n + 1; -- point to next location in the names table |
||
if 1 == count then -- if the previous name was missing |
if 1 == count then -- if the previous name was missing |
||
table.insert( z.message_tail, { set_error( 'missing_name', { |
table.insert( z.message_tail, { set_error( 'missing_name', {list_name:match ("(%w+)List"):lower(), i-1}, true ) } ); -- add this error message |
||
end |
end |
||
count = 0; -- reset the counter, we're looking for two consecutive missing names |
count = 0; -- reset the counter, we're looking for two consecutive missing names |
||
Line 1,460: | 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,473: | 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 |
local this_wiki_name = mw.language.fetchLanguageName(cfg.this_wiki_code, cfg.this_wiki_code); -- get this wiki's language name |
||
local this_wiki_code = this_wiki:getCode() -- get this wiki's language code |
|||
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,483: | Line 1,529: | ||
if name then -- there was a remapped code so |
if name then -- there was a remapped code so |
||
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 |
|||
else |
|||
if lang:match ('^%a%a%-') then -- strip ietf tags from code; TODO: is there a need to support 3-char with tag? |
|||
lang = lang:match ('(%a%a)%-') -- keep only 639-1 code portion to lang; TODO: do something with 3166 alpha 2 country code? |
|||
end |
end |
||
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,496: | 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,502: | 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,521: | 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 = 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,544: | 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,606: | 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 'none' == ps:lower() then -- if assigned value is 'none' then |
|||
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,624: | Line 1,673: | ||
local function is_pdf (url) |
local function is_pdf (url) |
||
return url:match ('%.pdf$') or url:match ('%.PDF$') or |
return url:match ('%.pdf$') or url:match ('%.PDF$') or |
||
url:match ('%.pdf[%?#]') or url:match ('%.PDF[%?#]') or |
|||
url:match ('%.PDF#') or url:match ('%.pdf#'); |
|||
end |
end |
||
Line 1,652: | Line 1,703: | ||
--[[--------------------------< G E T _ D I S P L A Y _ A |
--[[--------------------------< 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 name lists and a boolean flag |
Returns a number that defines the number of names displayed for author and editor name lists and a boolean flag |
||
Line 1,675: | Line 1,726: | ||
]] |
]] |
||
local function |
local function get_display_names (max, count, list_name, etal) |
||
if is_set (max) then |
if is_set (max) then |
||
if 'etal' == max:lower():gsub("[ '%.]", '') then -- the :gsub() portion makes 'etal' from a variety of 'et al.' spellings and stylings |
if 'etal' == max:lower():gsub("[ '%.]", '') then -- the :gsub() portion makes 'etal' from a variety of 'et al.' spellings and stylings |
||
Line 1,683: | Line 1,734: | ||
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 |
||
add_maint_cat (' |
add_maint_cat ('disp_name', cfg.special_case_translation [list_name]); |
||
end |
end |
||
else -- not a valid keyword or number |
else -- not a valid keyword or number |
||
Line 1,784: | Line 1,835: | ||
vparam, etal = name_has_etal (vparam, etal, true); -- find and remove variations on et al. do not categorize (do it here because et al. might have a period) |
vparam, etal = name_has_etal (vparam, etal, true); -- find and remove variations on et al. do not categorize (do it here because et al. might have a period) |
||
v_name_table = get_v_name_table (vparam, v_name_table, v_link_table); |
v_name_table = get_v_name_table (vparam, v_name_table, v_link_table); -- names are separated by commas |
||
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 |
||
first = ''; -- set to empty string for concatenation and because it may have been set for previous author/editor |
|||
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 is_suffix (first) then -- if a valid suffix |
|||
if not mw.ustring.match (first, '^%u+$') then -- mw.ustring here so that later we will catch non-latin characters |
|||
suffix = first -- save it as a suffix and |
|||
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 -- no suffix error message here because letter combination may be result of Romanization; check for digits? |
|||
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 |
||
first = ''; -- set to empty string for concatenation and because it may have been set for previous author/editor |
|||
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,816: | 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,856: | 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,887: | 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 |
elseif in_array (value, possible) then |
||
return cfg.keywords_xlate[value]; -- return translation of parameter keyword |
|||
return true; |
|||
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,945: | 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,006: | Line 2,067: | ||
if is_journal then |
if is_journal then |
||
return substitute (cfg.messages['j-page(s)'], pages), '', '', ''; |
return substitute (cfg.messages['j-page(s)'], pages), '', '', ''; |
||
elseif tonumber(pages) ~= nil and not nopp then |
elseif tonumber(pages) ~= nil and not nopp then -- if pages is only digits, assume a single page number |
||
return '', substitute (cfg.messages['p-prefix'], {sepc, pages}), '', ''; |
return '', substitute (cfg.messages['p-prefix'], {sepc, pages}), '', ''; |
||
elseif not nopp then |
elseif not nopp then |
||
Line 2,073: | Line 2,134: | ||
return page, pages, at, coins_pages; |
return page, pages, at, coins_pages; |
||
end |
end |
||
Line 2,118: | 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+)([^/]*)/'); |
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,143: | 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 |
|||
--[[--------------------------< 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 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 |
end |
||
Line 2,167: | 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'], ''); |
|||
-- set default parameter values defined by |mode= parameter. |
|||
local Mode = A['Mode']; |
|||
if not is_valid_parameter_value (Mode, 'mode', cfg.keywords['mode']) then |
|||
Mode = ''; |
|||
end |
|||
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,216: | Line 2,295: | ||
end |
end |
||
local translator_etal; |
|||
local t = {}; -- translators list from |translator-lastn= / translator-firstn= pairs |
local t = {}; -- translators list from |translator-lastn= / translator-firstn= pairs |
||
local Translators; -- assembled translators name list |
local Translators; -- assembled translators name list |
||
t = extract_names (args, 'TranslatorList'); -- fetch translator list from |translatorn= / |translator-lastn=, -firstn=, -linkn=, -maskn= |
t = extract_names (args, 'TranslatorList'); -- fetch translator list from |translatorn= / |translator-lastn=, -firstn=, -linkn=, -maskn= |
||
local interviewer_etal; |
|||
local interviewers_list = {}; |
local interviewers_list = {}; |
||
local Interviewers; -- used later |
local Interviewers; -- used later |
||
interviewers_list = extract_names (args, 'InterviewerList'); -- process preferred interviewers parameters |
interviewers_list = extract_names (args, 'InterviewerList'); -- process preferred interviewers parameters |
||
local contributor_etal; |
|||
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['Contribution']; |
|||
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,247: | Line 2,336: | ||
end |
end |
||
if is_set (Others) then |
|||
if not is_valid_parameter_value (NameListFormat, 'name-list-format', cfg.keywords['name-list-format']) then -- only accepted value for this parameter is 'vanc' |
|||
if 0 == #a and 0 == #e then -- add maint cat when |others= has value and used without |author=, |editor= |
|||
NameListFormat = ''; -- anything else, set to empty string |
|||
add_maint_cat ('others'); |
|||
end |
|||
end |
end |
||
Line 2,262: | 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 Section = ''; -- {{cite map}} only; preset to empty string for concatnation if not used |
|||
local Chapter = A['Chapter']; |
|||
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 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,280: | Line 2,379: | ||
ArchiveURL, ArchiveDate = archive_url_check (A['ArchiveURL'], A['ArchiveDate']) |
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 DeadURL = A['DeadURL'] |
|||
if not is_valid_parameter_value (DeadURL, 'dead-url', cfg.keywords ['deadurl']) then -- set in config.defaults to 'yes' |
|||
DeadURL = ''; -- anything else, set to empty string |
|||
end |
|||
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 = ''; |
||
if is_set (Periodical) then |
|||
Periodical_origin = A:ORIGIN('Periodical'); -- get the name of the periodical parameter |
|||
local i; |
|||
Periodical, i = strip_apostrophe_markup (Periodical); -- strip appostrophe markup so that metadata isn't contaminated |
|||
if i then -- non-zero when markup was stripped so emit an error message |
|||
table.insert( z.message_tail, {set_error ('apostrophe_markup', {Periodical_origin}, true)}); |
|||
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_origin = A:ORIGIN('ScriptPeriodical'); |
|||
-- web and news not tested for now because of |
|||
-- 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 |
|||
-- local p = {['journal'] = 'journal', ['magazine'] = 'magazine', ['news'] = 'newspaper', ['web'] = 'website'}; -- for error message |
|||
local p = {['journal'] = 'journal', ['magazine'] = 'magazine'}; -- for error message |
|||
if p[config.CitationClass] then |
|||
table.insert( z.message_tail, {set_error ('missing_periodical', {config.CitationClass, p[config.CitationClass]}, true)}); |
|||
end |
|||
end |
|||
local TransPeriodical = A['TransPeriodical']; |
|||
local TransPeriodical_origin = A:ORIGIN ('TransPeriodical'); |
|||
local Series = A['Series']; |
local Series = A['Series']; |
||
Line 2,303: | Line 2,436: | ||
local At; |
local At; |
||
if |
if 'citation' == config.CitationClass then |
||
if is_set (Periodical) then |
|||
if not in_array (Periodical_origin, {'website', 'mailinglist'}) then -- {{citation}} does not render volume for these 'periodicals' |
|||
Volume = A['Volume']; -- but does for all other 'periodicals' |
|||
end |
|||
elseif is_set (ScriptPeriodical) then |
|||
if 'script-website' ~= ScriptPeriodical_origin then -- {{citation}} does not render volume for |script-website= |
|||
Volume = A['Volume']; -- but does for all other 'periodicals' |
|||
end |
|||
else |
|||
Volume = A['Volume']; -- and does for non-'periodical' cites |
|||
end |
|||
elseif in_array (config.CitationClass, cfg.templates_using_volume) then -- render |volume= for cs1 according to the configuration settings |
|||
Volume = A['Volume']; |
Volume = A['Volume']; |
||
end |
|||
if 'citation' == config.CitationClass then |
|||
if is_set (Periodical) and in_array (Periodical_origin, {'journal', 'magazine', 'newspaper', 'periodical', 'work'}) or -- {{citation}} renders issue for these 'periodicals' |
|||
is_set (ScriptPeriodical) and in_array (ScriptPeriodical_origin, {'script-journal', 'script-magazine', 'script-newspaper', 'script-periodical', 'script-work'}) then -- and these 'script-periodicals' |
|||
Issue = hyphen_to_dash (A['Issue']); |
|||
end |
|||
elseif in_array (config.CitationClass, cfg.templates_using_issue) then -- conference & map books do not support issue; {{citation}} listed here because included in settings table |
|||
if not (in_array (config.CitationClass, {'conference', 'map', 'citation'}) and not (is_set (Periodical) or is_set (ScriptPeriodical))) then |
|||
Issue = hyphen_to_dash (A['Issue']); |
|||
end |
|||
end |
end |
||
-- conference & map books do not support issue |
|||
if in_array (config.CitationClass, cfg.templates_using_issue) and not (in_array (config.CitationClass, {'conference', 'map'}) and not is_set (Periodical))then |
|||
Issue = hyphen_to_dash (A['Issue']); |
|||
end |
|||
local Position = ''; |
local Position = ''; |
||
if not in_array (config.CitationClass, cfg.templates_not_using_page) then |
if not in_array (config.CitationClass, cfg.templates_not_using_page) then |
||
Line 2,318: | 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']; |
||
local |
local PublisherName_origin = A:ORIGIN('PublisherName'); |
||
if is_set (PublisherName) then |
|||
if not is_valid_parameter_value (RegistrationRequired, 'registration', cfg.keywords ['yes_true_y']) then |
|||
local i=0; |
|||
RegistrationRequired=nil; |
|||
PublisherName, i = strip_apostrophe_markup (PublisherName); -- strip appostrophe markup so that metadata isn't contaminated; publisher is never italicized |
|||
end |
|||
if i then -- non-zero when markup was stripped so emit an error message |
|||
local SubscriptionRequired = A['SubscriptionRequired']; |
|||
table.insert( z.message_tail, {set_error ('apostrophe_markup', {PublisherName_origin}, true)}); |
|||
if not is_valid_parameter_value (SubscriptionRequired, 'subscription', cfg.keywords ['yes_true_y']) then |
|||
end |
|||
SubscriptionRequired=nil; |
|||
end |
end |
||
local |
local Newsgroup = A['Newsgroup']; -- TODO: strip apostrophe markup? |
||
local Newsgroup_origin = A:ORIGIN('Newsgroup'); |
|||
if not is_valid_parameter_value (UrlAccess, 'url-access', cfg.keywords ['url-access']) then |
|||
UrlAccess = nil; |
|||
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 = 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; |
||
table.insert( z.message_tail, { set_error( 'param_access_requires_param', {'url'}, true ) } ); |
table.insert( z.message_tail, { set_error( 'param_access_requires_param', {'url'}, true ) } ); |
||
end |
end |
||
local ChapterUrlAccess = is_valid_parameter_value (A['ChapterUrlAccess'], A:ORIGIN('ChapterUrlAccess'), cfg.keywords_lists['url-access'], nil); |
|||
if is_set (UrlAccess) and is_set (SubscriptionRequired) then -- while not aliases, these are much the same so if both are set |
|||
table.insert( z.message_tail, { set_error( 'redundant_parameters', {wrap_style ('parameter', 'url-access') .. ' and ' .. wrap_style ('parameter', 'subscription')}, true ) } ); -- add error message |
|||
SubscriptionRequired = nil; -- unset; prefer |access= over |subscription= |
|||
end |
|||
if is_set (UrlAccess) and is_set (RegistrationRequired) then -- these are not the same but contradictory so if both are set |
|||
table.insert( z.message_tail, { set_error( 'redundant_parameters', {wrap_style ('parameter', 'url-access') .. ' and ' .. wrap_style ('parameter', 'registration')}, true ) } ); -- add error message |
|||
RegistrationRequired = nil; -- unset; prefer |access= over |registration= |
|||
end |
|||
local ChapterUrlAccess = A['ChapterUrlAccess']; |
|||
if not is_valid_parameter_value (ChapterUrlAccess, 'chapter-url-access', cfg.keywords ['url-access']) then -- same as url-access |
|||
ChapterUrlAccess = nil; |
|||
end |
|||
if not is_set(ChapterURL) and is_set(ChapterUrlAccess) then |
if not is_set(ChapterURL) and is_set(ChapterUrlAccess) then |
||
ChapterUrlAccess = nil; |
ChapterUrlAccess = nil; |
||
table.insert( z.message_tail, { set_error( 'param_access_requires_param', {' |
table.insert( z.message_tail, { set_error( 'param_access_requires_param', {A:ORIGIN('ChapterUrlAccess'):gsub ('%-access', '')}, true ) } ); |
||
end |
|||
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 |
|||
MapUrlAccess = nil; |
|||
table.insert( z.message_tail, { set_error( 'param_access_requires_param', {'map-url'}, true ) } ); |
|||
end |
end |
||
Line 2,369: | 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); |
||
if not is_valid_parameter_value (IgnoreISBN, 'ignore-isbn-error', cfg.keywords ['yes_true_y']) then |
|||
IgnoreISBN = nil; -- anything else, set to empty string |
|||
end |
|||
local Embargo = A['Embargo']; |
local Embargo = A['Embargo']; |
||
local Class = A['Class']; -- arxiv class identifier |
local Class = A['Class']; -- arxiv class identifier |
||
local ID_list = extract_ids( args ); |
local ID_list = extract_ids( args ); |
||
if is_set (DoiBroken) and not ID_list['DOI'] then |
|||
table.insert( z.message_tail, { set_error( 'doibroken_missing_doi', A:ORIGIN('DoiBroken'))}); |
|||
end |
|||
local ID_access_levels = extract_id_access_levels( args, ID_list ); |
local ID_access_levels = extract_id_access_levels( args, ID_list ); |
||
Line 2,387: | 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); |
||
if not is_valid_parameter_value (LastAuthorAmp, 'last-author-amp', cfg.keywords ['yes_true_y']) then |
|||
LastAuthorAmp = nil; -- set to empty string |
|||
end |
|||
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); |
||
if not is_valid_parameter_value (no_tracking_cats, 'no-tracking', cfg.keywords ['yes_true_y']) then |
|||
no_tracking_cats = nil; -- set to empty string |
|||
end |
|||
--local variables that are not cs1 parameters |
--local variables that are not cs1 parameters |
||
Line 2,405: | 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 = is_valid_parameter_value (A['DF'], A:ORIGIN('DF'), cfg.keywords_lists['df'], ''); |
|||
local DF = A['DF']; -- date format set in cs1|2 template |
|||
if not is_set (DF) then |
|||
if not is_valid_parameter_value (DF, 'df', cfg.keywords['date-format']) then -- validate reformatting keyword |
|||
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']; |
||
if 'harv' == Ref then |
|||
sepc, PostScript, Ref = set_style (Mode:lower(), A['PostScript'], A['Ref'], config.CitationClass); |
|||
add_maint_cat ('ref_harv'); -- add maint cat to identify templates that have this now-extraneous param value |
|||
use_lowercase = ( sepc == ',' ); -- used to control capitalization for certain static text |
|||
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 |
|||
--check this page to see if it is in one of the namespaces that cs1 is not supposed to add to the error categories |
--check this page to see if it is in one of the namespaces that cs1 is not supposed to add to the error categories |
||
Line 2,428: | 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 |
|||
-- 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 |
|||
local coins_pages; |
local coins_pages; |
||
Line 2,436: | 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 is_set (NoPP) and is_valid_parameter_value (NoPP, 'nopp', cfg.keywords ['yes_true_y']) then |
|||
NoPP = true; |
|||
else |
|||
NoPP = nil; -- unset, used as a flag later |
|||
end |
|||
-- both |publication-place= and |place= (|location=) allowed if different |
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 not is_set(PublicationPlace) and is_set(Place) then |
|||
PublicationPlace = Place |
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 |
|||
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,455: | Line 2,611: | ||
|encyclopedia and |title then map |title to |article and |encyclopedia to |title |
|encyclopedia and |title then map |title to |article and |encyclopedia to |title |
||
|encyclopedia and |article then map |encyclopedia to |title |
|encyclopedia and |article then map |encyclopedia to |title |
||
|encyclopedia then map |encyclopedia to |title |
|||
|trans-title maps to |trans-chapter when |title is re-mapped |
|trans-title maps to |trans-chapter when |title is re-mapped |
||
|url maps to |chapterurl when |title is remapped |
|url maps to |chapterurl when |title is remapped |
||
Line 2,464: | 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 ( config.CitationClass == "encyclopaedia" ) or ( config.CitationClass == "citation" and is_set (Encyclopedia)) then -- test code for citation |
|||
if 'encyclopaedia' ~= config.CitationClass and 'citation' ~= config.CitationClass then |
|||
if is_set(Periodical) then -- Periodical is set when |encyclopedia is set |
|||
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(Title) or is_set (ScriptTitle) then |
if is_set(Title) or is_set (ScriptTitle) then |
||
if not is_set(Chapter) then |
if not is_set(Chapter) then |
||
Chapter = Title; -- |encyclopedia and |title are set so map |title to |article and |encyclopedia to |title |
Chapter = Title; -- |encyclopedia and |title are set so map |title 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,488: | Line 2,662: | ||
ScriptTitle = ''; |
ScriptTitle = ''; |
||
end |
end |
||
elseif is_set (Chapter) then -- |title not set |
|||
Title = Periodical; -- |encyclopedia set and |article |
Title = Periodical; -- |encyclopedia set and |article set so map |encyclopedia to |title |
||
Periodical = ''; -- redundant so unset |
Periodical = ''; -- redundant so unset |
||
end |
end |
||
Line 2,504: | Line 2,678: | ||
end |
end |
||
end |
end |
||
end |
|||
-- special case for cite mailing list |
|||
if (config.CitationClass == "mailinglist") then |
|||
Periodical = A ['MailingList']; |
|||
elseif 'mailinglist' == A:ORIGIN('Periodical') then |
|||
Periodical = ''; -- unset because mailing list is only used for cite mailing list |
|||
end |
end |
||
Line 2,517: | 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 |
|||
-- 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,540: | 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'); |
|||
ChapterUrlAccess = UrlAccess; |
|||
TransChapter = A['TransMap']; |
TransChapter = A['TransMap']; |
||
ScriptChapter = A['ScriptMap'] |
|||
ChapterURLorigin = A:ORIGIN('MapURL'); |
|||
ScriptChapter_origin = A:ORIGIN('ScriptMap') |
|||
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,559: | 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 AirDate = A['AirDate']; |
|||
local SeriesLink = A['SeriesLink']; |
local SeriesLink = A['SeriesLink']; |
||
Line 2,572: | Line 2,747: | ||
ID = table.concat(n, sepc .. ' '); |
ID = table.concat(n, sepc .. ' '); |
||
if not is_set (Date) and is_set (AirDate) then -- promote airdate to date |
|||
Date = AirDate; |
|||
end |
|||
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,586: | Line 2,757: | ||
-- assemble a table of parts concatenated later into Series |
-- assemble a table of parts concatenated later into Series |
||
if is_set(Season) then table.insert(s, wrap_msg ('season', Season, use_lowercase)); end |
if is_set(Season) then table.insert(s, wrap_msg ('season', Season, use_lowercase)); end |
||
if is_set(SeriesNumber) then table.insert(s, wrap_msg (' |
if is_set(SeriesNumber) then table.insert(s, wrap_msg ('seriesnum', SeriesNumber, use_lowercase)); end |
||
if is_set(Issue) then table.insert(s, wrap_msg ('episode', Issue, use_lowercase)); end |
if is_set(Issue) then table.insert(s, wrap_msg ('episode', Issue, use_lowercase)); end |
||
Issue = ''; -- unset because this is not a unique parameter |
Issue = ''; -- unset because this is not a unique parameter |
||
Line 2,592: | 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,622: | Line 2,794: | ||
-- end of {{cite episode}} stuff |
-- end of {{cite episode}} stuff |
||
-- Account for the oddities that are {{cite arxiv}}, {{cite biorxiv}}, {{cite citeseerx}}, 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 ) } ); |
table.insert( z.message_tail, { set_error( config.CitationClass .. '_missing', {}, true ) } ); -- add error message |
||
end |
|||
if 'arxiv' == config.CitationClass then |
|||
Periodical = 'arXiv'; -- set to arXiv for COinS; after that, must be set to empty string |
|||
end |
end |
||
Periodical = ({['arxiv'] = 'arXiv', ['biorxiv'] = 'bioRxiv', ['citeseerx'] = 'CiteSeerX', ['ssrn'] = 'Social Science Research Network'})[config.CitationClass]; |
|||
Periodical = 'bioRxiv'; -- set to bioRxiv for COinS; after that, must be set to empty string |
|||
end |
|||
if 'citeseerx' == config.CitationClass then |
|||
Periodical = 'CiteSeerX'; -- set to CiteSeerX for COinS; after that, must be set to empty string |
|||
end |
|||
end |
end |
||
end |
end |
||
Line 2,729: | 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,746: | 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( |
if config.CitationClass == "journal" and not is_set(URL) and not is_set(TitleLink) then |
||
if not is_set (Embargo) then -- if not embargoed or embargo has expired |
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= |
|||
elseif is_set(ID_list['DOI']) and ID_access_levels['DOI'] == "free" then |
|||
if is_set(AccessDate) then -- access date requires |url=; pmc created url is not |url= |
|||
URL=cfg.id_handlers['DOI'].prefix .. ID_list['DOI']; |
|||
table.insert( z.message_tail, { set_error( 'accessdate_missing_url', {}, true ) } ); |
|||
URL_origin = cfg.id_handlers['DOI'].parameters[1]; |
|||
AccessDate = ''; -- unset |
|||
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,764: | 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 ) } ); |
|||
not is_set(TransTitle) and |
|||
not is_set(ScriptTitle) then |
|||
if 'episode' == config.CitationClass then -- special case for cite episode; TODO: is there a better way to do this? |
|||
table.insert( z.message_tail, { set_error( 'citation_missing_title', {'series'}, true ) } ); |
|||
else |
|||
table.insert( z.message_tail, { set_error( 'citation_missing_title', {'title'}, true ) } ); |
|||
end |
|||
end |
end |
||
if cfg.keywords_xlate[Title] == 'none' and |
|||
if 'none' == Title and in_array (config.CitationClass, {'journal', 'citation'}) and is_set (Periodical) and 'journal' == A:ORIGIN('Periodical') then -- special case for journal cites |
|||
in_array (config.CitationClass, {'journal', 'citation'}) and |
|||
Title = ''; -- set title to empty string |
|||
(is_set (Periodical) or is_set (ScriptPeriodical)) and |
|||
add_maint_cat ('untitled'); |
|||
('journal' == Periodical_origin or 'script-journal' == ScriptPeriodical_origin) then -- special case for journal cites |
|||
Title = ''; -- set title to empty string |
|||
add_maint_cat ('untitled'); |
|||
end |
end |
||
check_for_url ({ -- add error message when any of these parameters |
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, |
||
[ |
[PublisherName_origin] = PublisherName |
||
}); |
}); |
||
Line 2,803: | 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'] = Periodical, |
['Periodical'] = strip_apostrophe_markup (Periodical), -- no markup in the metadata |
||
['Encyclopedia'] = 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,814: | 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, |
||
['Volume'] = Volume, |
['Volume'] = Volume, |
||
['Issue'] = Issue, |
['Issue'] = Issue, |
||
['Pages'] = coins_pages or get_coins_pages (first_set ({Sheet, Sheets, Page, Pages, At}, 5)), |
['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,827: | Line 2,989: | ||
}, config.CitationClass); |
}, config.CitationClass); |
||
-- Account for the oddities that are {{cite arxiv}}, {{cite biorxiv}}, and {{cite |
-- 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 then |
if 'newsgroup' == config.CitationClass and is_set (Newsgroup) then |
||
PublisherName = substitute (cfg.messages['newsgroup'], external_link( 'news:' .. Newsgroup, Newsgroup, Newsgroup_origin, nil )); |
|||
if is_set (PublisherName) then |
|||
PublisherName = substitute (cfg.messages['newsgroup'], external_link( 'news:' .. PublisherName, PublisherName, A:ORIGIN('PublisherName'), nil )); |
|||
end |
|||
end |
end |
||
-- Now perform various field substitutions. |
-- Now perform various field substitutions. |
||
Line 2,851: | 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, |
||
page_name = this_page.text, -- get current page name so that we don't wikilink to it via editorlinkn |
|||
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 = |
control.maximum , editor_etal = get_display_names (A['DisplayEditors'], #e, 'editors', editor_etal); |
||
last_first_list, EditorCount = list_people(control, e, editor_etal); |
last_first_list, EditorCount = list_people(control, e, editor_etal); |
||
if is_set (Editors) then |
if 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 |
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 |
||
EditorCount = 2; -- with et al., |editors= is multiple names; spoof to display (eds.) annotation |
|||
else |
|||
EditorCount = 2; -- we don't know but assume |editors= is multiple names; spoof to display (eds.) annotation |
|||
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 2,875: | Line 3,031: | ||
end |
end |
||
do -- now do interviewers |
do -- now do interviewers |
||
control.maximum = #interviewers_list |
control.maximum , interviewer_etal = get_display_names (A['DisplayInterviewers'], #interviewers_list, 'interviewers', interviewer_etal); |
||
Interviewers = list_people(control, interviewers_list, |
Interviewers = list_people (control, interviewers_list, interviewer_etal); |
||
end |
end |
||
do -- now do translators |
do -- now do translators |
||
control.maximum = #t |
control.maximum , translator_etal = get_display_names (A['DisplayTranslators'], #t, 'translators', translator_etal); |
||
Translators = list_people(control, t, |
Translators = list_people (control, t, translator_etal); |
||
end |
end |
||
do -- now do contributors |
do -- now do contributors |
||
control.maximum = #c |
control.maximum , contributor_etal = get_display_names (A['DisplayContributors'], #c, 'contributors', contributor_etal); |
||
Contributors = list_people(control, c, |
Contributors = list_people (control, c, contributor_etal); |
||
end |
end |
||
do -- now do authors |
do -- now do authors |
||
control.maximum , 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 is_set (Authors) then |
if is_set (Authors) then |
||
Authors, author_etal = name_has_etal (Authors, author_etal, false); -- find and remove variations on et al. |
Authors, author_etal = name_has_etal (Authors, author_etal, false, 'authors'); -- find and remove variations on et al. |
||
if author_etal then |
if author_etal then |
||
Authors = Authors .. ' ' .. cfg.messages['et al']; -- add et al. to authors parameter |
Authors = Authors .. ' ' .. cfg.messages['et al']; -- add et al. to authors parameter |
||
Line 2,916: | Line 3,072: | ||
-- special case for chapter format so no error message or cat when chapter not supported |
-- special case for chapter format so no error message or cat when chapter not supported |
||
if not (in_array(config.CitationClass, {'web', 'news', 'journal', 'magazine', 'pressrelease', 'podcast', 'newsgroup', 'arxiv', 'biorxiv', 'citeseerx'}) or |
if not (in_array(config.CitationClass, {'web', 'news', 'journal', 'magazine', 'pressrelease', 'podcast', 'newsgroup', 'arxiv', 'biorxiv', 'citeseerx', 'ssrn'}) or |
||
('citation' == config.CitationClass and is_set (Periodical) and not is_set (Encyclopedia))) then |
('citation' == config.CitationClass and (is_set (Periodical) or is_set (ScriptPeriodical)) and not is_set (Encyclopedia))) then |
||
ChapterFormat = style_format (ChapterFormat, ChapterURL, 'chapter-format', 'chapter-url'); |
ChapterFormat = style_format (ChapterFormat, ChapterURL, 'chapter-format', 'chapter-url'); |
||
end |
end |
||
if not is_set(URL) then |
if not is_set(URL) then |
||
if in_array(config.CitationClass, {"web","podcast", "mailinglist"}) |
if in_array(config.CitationClass, {"web","podcast", "mailinglist"}) or -- |url= required for cite web, cite podcast, and cite mailinglist |
||
('citation' == config.CitationClass and ('website' == Periodical_origin or 'script-website' == ScriptPeriodical_origin)) then -- and required for {{citation}} with |website= or |script-website= |
|||
table.insert( z.message_tail, { set_error( 'cite_web_url', {}, true ) } ); |
|||
table.insert( z.message_tail, { set_error( 'cite_web_url', {}, true ) } ); |
|||
end |
end |
||
Line 2,933: | Line 3,090: | ||
end |
end |
||
local OriginalURL, |
local OriginalURL, OriginalURL_origin, OriginalFormat, OriginalAccess; |
||
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 'no' ~= DeadURL 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 2,948: | 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 'no' ~= DeadURL 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 2,960: | Line 3,119: | ||
end |
end |
||
if in_array(config.CitationClass, {'web','news','journal', 'magazine', 'pressrelease', 'podcast', 'newsgroup', 'arxiv', 'biorxiv', 'citeseerx'}) or -- if any of the 'periodical' cites except encyclopedia |
if in_array(config.CitationClass, {'web','news','journal', 'magazine', 'pressrelease', 'podcast', 'newsgroup', 'arxiv', 'biorxiv', 'citeseerx', 'ssrn'}) or -- if any of the 'periodical' cites except encyclopedia |
||
('citation' == config.CitationClass and is_set (Periodical) and not is_set (Encyclopedia)) then |
('citation' == config.CitationClass and (is_set (Periodical) or is_set (ScriptPeriodical)) and not is_set (Encyclopedia)) then |
||
local chap_param; |
local chap_param; |
||
if is_set (Chapter) then -- get a parameter name from one of these chapter related meta-parameters |
if is_set (Chapter) then -- get a parameter name from one of these chapter related meta-parameters |
||
Line 2,970: | 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 2,986: | 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, TransChapter, ChapterURL, |
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,003: | Line 3,162: | ||
end |
end |
||
-- Format main title |
-- Format main title |
||
if is_set (ArchiveURL) and |
|||
if is_set (ArchiveURL) and mw.ustring.match (mw.ustring.lower(Title), cfg.special_case_translation['archived_copy']) then -- 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.en) or -- if title is 'Archived copy' (place holder added by bots that can't find proper title) |
|||
add_maint_cat ('archived_copy'); -- add maintenance category before we modify the content of 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,018: | Line 3,179: | ||
end |
end |
||
end |
end |
||
if in_array(config.CitationClass, {'web', 'news', 'journal', 'magazine', 'pressrelease', 'podcast', 'newsgroup', 'mailinglist', 'interview', 'arxiv', 'biorxiv', 'citeseerx'}) 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) and not is_set (Encyclopedia)) or |
('citation' == config.CitationClass and (is_set (Periodical) or is_set (ScriptPeriodical)) and not is_set (Encyclopedia)) or |
||
('map' == config.CitationClass and is_set (Periodical)) then |
('map' == config.CitationClass and (is_set (Periodical) or is_set (ScriptPeriodical))) then -- special case for cite map when the map is in a periodical treat as an article |
||
Title = kern_quotes (Title); -- if necessary, separate title's leading and trailing quote marks from Module provided quote marks |
Title = kern_quotes (Title); -- if necessary, separate title's leading and trailing quote marks from Module provided quote marks |
||
Title = wrap_style ('quoted-title', Title); |
Title = wrap_style ('quoted-title', Title); |
||
Title = script_concatenate (Title, ScriptTitle); |
Title = script_concatenate (Title, ScriptTitle, 'script-title'); -- <bdi> tags, lang atribute, categorization, etc; must be done after title is wrapped |
||
TransTitle= wrap_style ('trans-quoted-title', TransTitle ); |
TransTitle= wrap_style ('trans-quoted-title', TransTitle ); |
||
elseif 'report' == config.CitationClass then -- no styling for cite report |
elseif 'report' == config.CitationClass then -- no styling for cite report |
||
Title = script_concatenate (Title, ScriptTitle); |
Title = script_concatenate (Title, ScriptTitle, 'script-title'); -- <bdi> tags, lang atribute, categorization, etc; must be done after title is wrapped |
||
TransTitle= wrap_style ('trans-quoted-title', TransTitle ); -- for cite report, use this form for trans-title |
TransTitle= wrap_style ('trans-quoted-title', TransTitle ); -- for cite report, use this form for trans-title |
||
else |
else |
||
Title = wrap_style ('italic-title', Title); |
Title = wrap_style ('italic-title', Title); |
||
Title = script_concatenate (Title, ScriptTitle); |
Title = script_concatenate (Title, ScriptTitle, 'script-title'); -- <bdi> tags, lang atribute, categorization, etc; must be done after title is wrapped |
||
TransTitle = wrap_style ('trans-italic-title', TransTitle); |
TransTitle = wrap_style ('trans-italic-title', TransTitle); |
||
end |
end |
||
Line 3,044: | 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,060: | Line 3,226: | ||
end |
end |
||
else |
else |
||
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) |
|||
local ws_url, ws_label; |
|||
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,081: | 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,119: | 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 Section = A['Section']; |
|||
local Sections = A['Sections']; |
|||
local Inset = A['Inset']; |
local Inset = A['Inset']; |
||
Line 3,163: | Line 3,328: | ||
end |
end |
||
Series = is_set(Series) and (sepc |
Series = is_set (Series) and wrap_msg ('series', {sepc, Series}) or ""; -- not the same as SeriesNum |
||
OrigYear = is_set (OrigYear) and wrap_msg ('origyear', OrigYear) or ''; |
|||
Agency = is_set (Agency) and wrap_msg ('agency', {sepc, Agency}) or ""; |
|||
Agency = is_set(Agency) and (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 |
------------------------------------ totally unrelated data |
||
Via = is_set (Via) and wrap_msg ('via', Via) or ''; |
|||
Via = " " .. wrap_msg ('via', Via); |
|||
end |
|||
--[[ |
|||
Subscription implies paywall; Registration does not. If both are used in a citation, the subscription required link |
|||
note is displayed. There are no error messages for this condition. |
|||
]] |
|||
if is_set (SubscriptionRequired) then |
|||
SubscriptionRequired = sepc .. " " .. cfg.messages['subscription']; -- subscription required message |
|||
elseif is_set (RegistrationRequired) then |
|||
SubscriptionRequired = sepc .. " " .. cfg.messages['registration']; -- registration required message |
|||
else |
|||
SubscriptionRequired = ''; -- either or both might be set to something other than yes true y |
|||
end |
|||
if is_set(AccessDate) then |
if is_set(AccessDate) then |
||
Line 3,209: | 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,222: | 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 " |
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- |
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 -- |
elseif is_set(OriginalURL) then -- UrlStatus is empty, 'dead', 'unfit', 'usurped', 'bot: unknown' |
||
if in_array (UrlStatus, {'unfit', 'usurped', 'bot: unknown'}) then |
|||
local arch_text = cfg.messages['archived-dead']; |
|||
arch_text = cfg.messages['archived-unfit']; |
|||
if sepc ~= "." then arch_text = arch_text:lower() end |
|||
if sepc ~= "." then arch_text = arch_text:lower() end |
|||
if in_array (DeadURL, {'unfit', 'usurped', 'bot: unknown'}) then |
|||
Archived = sepc .. " " .. |
Archived = sepc .. " " .. arch_text .. ArchiveDate; -- format already styled |
||
if 'bot: unknown' == |
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 |
||
else |
else |
||
add_maint_cat ('unfit'); -- and add a category if not already added |
add_maint_cat ('unfit'); -- and add a category if not already added |
||
end |
end |
||
else -- |
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 -- OriginalUrl not set |
|||
else |
|||
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,278: | 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,302: | Line 3,453: | ||
-- 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 is_set(Periodical) 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 .. " " .. |
Periodical = sepc .. " " .. format_periodical (ScriptPeriodical, ScriptPeriodical_origin, Periodical, TransPeriodical, TransPeriodical_origin); |
||
else |
else |
||
Periodical = |
Periodical = format_periodical (ScriptPeriodical, ScriptPeriodical_origin, Periodical, TransPeriodical, TransPeriodical_origin); |
||
end |
end |
||
end |
end |
||
Line 3,314: | Line 3,465: | ||
the annotation directly follows the |title= parameter value in the citation rather than the |event= parameter value (if provided). |
the annotation directly follows the |title= parameter value in the citation rather than the |event= parameter value (if provided). |
||
]] |
]] |
||
if "speech" == config.CitationClass then -- cite speech only |
if "speech" == config.CitationClass then -- cite speech only |
||
TitleNote = " (Speech)"; -- annotate the citation |
TitleNote = " (Speech)"; -- annotate the citation |
||
if is_set (Periodical) then -- if Periodical, perhaps because of an included |website= or |journal= parameter |
if is_set (Periodical) then -- if Periodical, perhaps because of an included |website= or |journal= parameter |
||
if is_set (Conference) then -- and if |event= is set |
if is_set (Conference) then -- and if |event= is set |
||
Conference = Conference .. sepc .. " "; -- then add appropriate punctuation to the end of the Conference variable before rendering |
Conference = Conference .. sepc .. " "; -- then add appropriate punctuation to the end of the Conference variable before rendering |
||
end |
end |
||
end |
end |
||
Line 3,351: | Line 3,502: | ||
elseif 'episode' == config.CitationClass then -- special case for cite episode |
elseif 'episode' == config.CitationClass then -- special case for cite episode |
||
tcommon = safe_join( {Title, TitleNote, TitleType, Series |
tcommon = safe_join( {Title, TitleNote, TitleType, Series, Language, Edition, Publisher}, sepc ); |
||
else -- all other CS1 templates |
else -- all other CS1 templates |
||
Line 3,364: | Line 3,515: | ||
end |
end |
||
local idcommon; |
|||
local idcommon = safe_join( { ID_list, URL, Archived, AccessDate, Via, SubscriptionRequired, Lay, Quote }, sepc ); |
|||
if 'audio-visual' == config.CitationClass or 'episode' == config.CitationClass then -- special case for cite AV media & cite episode position transcript |
|||
idcommon = safe_join( { ID_list, URL, Archived, Transcript, AccessDate, Via, Lay, Quote }, sepc ); |
|||
else |
|||
idcommon = safe_join( { ID_list, URL, Archived, AccessDate, Via, Lay, Quote }, sepc ); |
|||
end |
|||
local text; |
local text; |
||
local pgtext = Position .. Sheet .. Sheets .. Page .. Pages .. At; |
local pgtext = Position .. Sheet .. Sheets .. Page .. Pages .. At; |
||
Line 3,390: | Line 3,547: | ||
if (sepc ~= '.') then |
if (sepc ~= '.') then |
||
in_text = in_text:lower() -- lowercase for cs2 |
in_text = in_text:lower() -- lowercase for cs2 |
||
end |
|||
else |
|||
if EditorCount <= 1 then |
|||
post_text = ", " .. cfg.messages['editor']; |
|||
else |
|||
post_text = ", " .. cfg.messages['editors']; |
|||
end |
end |
||
end |
end |
||
if EditorCount <= 1 then |
|||
post_text = " (" .. cfg.messages['editor'] .. ")"; -- be consistent with no-author, no-date case |
|||
else |
|||
post_text = " (" .. cfg.messages['editors'] .. ")"; |
|||
end |
|||
Editors = terminate_name_list (in_text .. Editors .. post_text, sepc); -- terminate with 0 or 1 sepc and a space |
Editors = terminate_name_list (in_text .. Editors .. post_text, sepc); -- terminate with 0 or 1 sepc and a space |
||
end |
end |
||
Line 3,438: | Line 3,594: | ||
if is_set(PostScript) and PostScript ~= sepc then |
if is_set(PostScript) and PostScript ~= sepc then |
||
text = safe_join( {text, sepc}, sepc ); |
text = safe_join( {text, sepc}, sepc ); --Deals with italics, spaces, etc. |
||
text = text:sub(1,-sepc:len()-1); |
text = text:sub(1,-sepc:len()-1); |
||
end |
end |
||
Line 3,448: | 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 = config.CitationClass; |
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= |
||
options.class = "citation " .. config.CitationClass; -- 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,490: | Line 3,645: | ||
end |
end |
||
table.insert (render, substitute (cfg.presentation['ocins'], {OCinSoutput})); |
table.insert (render, substitute (cfg.presentation['ocins'], {OCinSoutput})); -- append metadata to the citation |
||
if 0 ~= #z.message_tail then |
if 0 ~= #z.message_tail then |
||
Line 3,518: | Line 3,673: | ||
end |
end |
||
if not no_tracking_cats then |
|||
if in_array(no_tracking_cats, {"", "no", "false", "n"}) then |
|||
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,549: | 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 in_array (cite_class, {'arxiv', 'biorxiv', 'citeseerx'}) then -- limited parameter sets allowed for these templates |
|||
state = whitelist.limited_basic_arguments[name]; |
|||
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,557: | Line 3,709: | ||
return true; |
return true; |
||
end |
end |
||
return nil; |
|||
end |
|||
if name:find ('#') then -- # is a cs1|2 reserved character so parameters with # not permitted |
|||
state = whitelist[cite_class .. '_basic_arguments'][name]; -- look in the parameter-list for the template identified by cite_class |
|||
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 |
|||
if true == state then return true; end -- valid actively supported parameter |
|||
if false == state then |
|||
deprecated_parameter (name); -- parameter is deprecated but still supported |
|||
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 then return true; end |
if true == state_test (state, name) then return true; end |
||
if false == state then |
|||
deprecated_parameter (name); -- parameter is deprecated but still supported |
|||
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 -- valid actively supported parameter |
|||
if false == state then |
|||
deprecated_parameter (name); -- parameter is deprecated but still supported |
|||
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 |
|||
if true == state then return true; end -- valid actively supported parameter |
|||
if false == state then |
|||
deprecated_parameter (name); -- parameter is deprecated but still supported |
|||
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,602: | 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,612: | Line 3,762: | ||
]] |
]] |
||
local function missing_pipe_check (value) |
local function missing_pipe_check (parameter, value) |
||
local capture; |
local capture; |
||
value = value:gsub ('%b<>', ''); -- remove xml/html tags because attributes: class=, title=, etc |
value = value:gsub ('%b<>', ''); -- remove xml/html tags because attributes: class=, title=, etc |
||
capture = value:match ('%s+(%a[% |
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 the capture is a valid parameter name |
if capture and validate (capture) then -- if the capture is a valid parameter name |
||
table.insert( z.message_tail, {set_error ('missing_pipe', parameter)}); |
|||
end |
end |
||
end |
end |
||
--[[--------------------------< |
--[[--------------------------< H A S _ E X T R A N E O U S _ P U N C T >-------------------------------------- |
||
look for extraneous terminal punctuation in most parameter values; parameters listed in skip table are not checked |
|||
]] |
|||
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 |
|||
return; -- parameter name found in the skip table so done |
|||
end |
|||
if value:match ('[,;:]$') then |
|||
add_maint_cat ('extra_punct'); -- has extraneous punctuation; add maint cat |
|||
end |
|||
end |
|||
--[[--------------------------< C I T A T I O N >-------------------------------------------------------------- |
|||
This is used by templates such as {{cite book}} to create the actual citation text. |
This is used by templates such as {{cite book}} to create the actual citation text. |
||
Line 3,629: | Line 3,801: | ||
]] |
]] |
||
function |
local function citation(frame) |
||
Frame = frame; -- save a copy incase we need to display an error message in preview mode |
Frame = frame; -- save a copy incase we need to display an error message in preview mode |
||
local pframe = frame:getParent() |
local pframe = frame:getParent() |
||
Line 3,676: | Line 3,848: | ||
is_wikilink = utilities.is_wikilink; |
is_wikilink = utilities.is_wikilink; |
||
make_wikilink = utilities.make_wikilink; |
make_wikilink = utilities.make_wikilink; |
||
strip_apostrophe_markup = utilities.strip_apostrophe_markup; |
|||
z = utilities.z; -- table of error and category tables in Module:Citation/CS1/Utilities |
z = utilities.z; -- table of error and category tables in Module:Citation/CS1/Utilities |
||
Line 3,693: | 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,729: | 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,745: | Line 3,919: | ||
end |
end |
||
end |
end |
||
missing_pipe_check (v); -- do we think that there is a parameter that is missing a pipe? |
|||
args[k] = v; -- save this parameter and its value |
|||
args[k] = v; |
|||
-- crude debug support that allows us to render a citation from module {{#invoke:}} TODO: keep? |
|||
elseif args[k] ~= nil or (k == 'postscript') then -- here when v is empty string |
|||
-- elseif args[k] ~= nil or (k == 'postscript') then -- when args[k] has a value from {{#invoke}} frame (we don't normally do that) |
|||
-- args[k] = v; -- overwrite args[k] with empty string from pframe.args[k] (template frame); v is empty string here |
|||
end |
|||
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 (k, v); |
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 |
||
--[[--------------------------< E X P O R T E D F U N C T I O N S >------------------------------------------ |
|||
return cs1; |
|||
]] |
|||
return {citation = citation}; |