Module:Citation/CS1: Difference between revisions

sync from sandbox;
(sync from sandbox;)
(sync from sandbox;)
Line 534: Line 534:
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 first 3 non-space characters are script language prefix
if script_value:match('^%l%l%l?%s*:') then -- if first 3 or 4 non-space characters are script language prefix
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
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
Line 545: Line 543:
name = cfg.lang_code_remap[lang] or mw.language.fetchLanguageName( lang, cfg.this_wiki_code ); -- get language name so that we can use it to categorize
name = cfg.lang_code_remap[lang] or mw.language.fetchLanguageName( lang, cfg.this_wiki_code ); -- get language name so that we can use it to categorize
if 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%l%s*:%s*', ''); -- strip prefix from script
script_value = script_value:gsub ('^%l+%s*:%s*', ''); -- strip prefix from script
script_value = script_value:gsub ('^%l+%s*:%s*', ''); -- strip prefix from script
-- is prefix one of these language codes?
-- is prefix one of these language codes?
Line 617: Line 614:
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 624: Line 622:
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
'https://en.wikisource.org/wiki/', -- prefix
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 -- simple wikilink: [[Wikisource:ws article]]
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
'https://en.wikisource.org/wiki/', -- prefix
wikisource_prefix, -- prefix
str, -- article title
str, -- article title
});
});
Line 643: Line 641:
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
'https://en.wikisource.org/wiki/', -- prefix
wikisource_prefix, -- prefix
str, -- article title without namespace from link portion of wikilink
str, -- article title without namespace from link portion of wikilink
});
});
Line 651: Line 649:
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 anchor
ws_url = ws_url:gsub ('%%23', '#'); -- undo percent encoding of fragment marker
end
end


Line 660: Line 658:
--[[--------------------------< F O R M A T _ P E R I O D I C A L >--------------------------------------------
--[[--------------------------< F O R M A T _ P E R I O D I C A L >--------------------------------------------


Format the four periodical parameters: |script-<periodical>=, |<periodical>=, and |trans-<periodical>= into a single Periodical meta-
Format the three periodical parameters: |script-<periodical>=, |<periodical>=, and |trans-<periodical>= into a single Periodical meta-
parameter.
parameter.


Line 680: Line 678:
if is_set (periodical) then
if is_set (periodical) then
periodical = periodical ..  ' ' .. trans_periodical;
periodical = periodical ..  ' ' .. trans_periodical;
else -- here when transchapter without chapter or script-chapter
else -- here when trans-periodical without periodical or script-periodical
periodical = trans_periodical;
periodical = trans_periodical;
periodical_error = ' ' .. set_error ('trans_missing_title', {'periodical'});
periodical_error = ' ' .. set_error ('trans_missing_title', {'periodical'});
Line 733: Line 731:
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 843: Line 837:
-- 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 888: Line 883:
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 "none" == title_type then
 
if cfg.keywords_xlate[title_type] == 'none' then
title_type = ""; -- if |type=none then type parameter not displayed
title_type = ""; -- if |type=none then type parameter not displayed
end
end
Line 926: Line 922:
str = str:gsub ('&[nm]dash;', {['&ndash;'] = '–', ['&mdash;'] = '—'}); -- replace &mdash; and &ndash; entities  with their characters; semicolon mucks up the text.split
str = str:gsub ('&[nm]dash;', {['&ndash;'] = '–', ['&mdash;'] = '—'}); -- replace &mdash; and &ndash; entities  with their characters; semicolon mucks up the text.split
str = str:gsub ('&#45;', '-'); -- replace html numeric entity with hyphen character
str = str:gsub ('&#45;', '-'); -- replace html numeric entity with hyphen character
str = str:gsub ('&nbsp;', ' '); -- replace &nbsp; entity with generic keyboard space character
local out = {};
local out = {};
Line 1,082: Line 1,079:
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 ('suffix');
add_vanc_error (cfg.err_msg_supl.suffix);
return false; -- not a name with an appropriate suffix
return false; -- not a name with an appropriate suffix
end
end
Line 1,088: Line 1,085:
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 character');
add_vanc_error (cfg.err_msg_supl['non-Latin character']);
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,121: Line 1,118:
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 ('suffix'); -- one or two initials with invalid suffix so error message
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,129: Line 1,126:
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,208: Line 1,204:
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
table.insert( text, one )
if is_set (person.link) then
table.insert( text, sep_one )
one = make_wikilink (person.link, one); -- link author/editor
end
table.insert (text, one)
table.insert (text, sep_one)
end
end
end
end
Line 1,241: Line 1,237:


]]
]]
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,284: Line 1,281:


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,292: Line 1,307:
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 _, pattern;
local patterns = cfg.editor_markup_patterns; -- get patterns from configuration
local patterns = cfg.editor_markup_patterns; -- get patterns from configuration


Line 1,307: Line 1,323:
end
end
end
end
return name; -- and done
end
end


Line 1,316: Line 1,331:
indicated if there is more than one comma and or semicolon.  If found, the function adds the multiple name
indicated if there is more than one comma and or semicolon.  If found, the function adds the multiple name
(author or editor) maintenance category.
(author or editor) maintenance category.
returns nothing


]]
]]


local function name_has_mult_names (name, list_name)
local function name_has_mult_names (name, list_name)
local count, _;
local _, count;
if is_set (name) then
if is_set (name) then
_, count = name:gsub ('[;,]', ''); -- count the number of separator-like characters
_, count = name:gsub ('[;,]', ''); -- count the number of separator-like characters
Line 1,328: Line 1,345:
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,343: Line 1,360:
last = last:match ('^%(%((.*)%)%)$'); -- strip parens
last = last:match ('^%(%((.*)%)%)$'); -- strip parens
else
else
last = name_has_mult_names (last, list_name); -- check for multiple names in the parameter (last only)
name_has_mult_names (last, list_name); -- check for multiple names in the parameter (last only)
last = name_has_ed_markup (last, list_name); -- check for extraneous 'editor' annotation
name_has_ed_markup (last, list_name); -- check for extraneous 'editor' annotation
name_is_numeric (last, list_name); -- check for names that are compsed of digits and punctuation
end
end
end
end
Line 1,351: Line 1,369:
first = first:match ('^%(%((.*)%)%)$'); -- strip parens
first = first:match ('^%(%((.*)%)%)$'); -- strip parens
else
else
first = name_has_ed_markup (first, list_name); -- check for extraneous 'editor' annotation
name_has_ed_markup (first, list_name); -- check for extraneous 'editor' annotation
name_is_numeric (first, list_name); -- check for names that are compsed of digits and punctuation
end
end
end
end
Line 1,385: Line 1,404:
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; -- selected parameter aliases used in error messaging
local last_alias, first_alias, link_alias; -- selected parameter aliases used in error messaging
while true do
while true do
last, last_alias = select_one( args, cfg.aliases[list_name .. '-Last'], 'redundant_parameters', i ); -- search through args for name components beginning at 1
last, last_alias = select_one( args, cfg.aliases[list_name .. '-Last'], 'redundant_parameters', i ); -- search through args for name components beginning at 1
first, first_alias = select_one( args, cfg.aliases[list_name .. '-First'], 'redundant_parameters', i );
first, first_alias = select_one( args, cfg.aliases[list_name .. '-First'], 'redundant_parameters', i );
link = select_one( args, cfg.aliases[list_name .. '-Link'], 'redundant_parameters', i );
link, link_alias = select_one( args, cfg.aliases[list_name .. '-Link'], 'redundant_parameters', i );
mask = select_one( args, cfg.aliases[list_name .. '-Mask'], 'redundant_parameters', i );
mask = select_one( args, cfg.aliases[list_name .. '-Mask'], 'redundant_parameters', i );


Line 1,404: Line 1,423:
end
end
else -- we have last with or without a first
else -- we have last with or without a first
link_title_ok (link, list_name:match ("(%w+)List"):lower() .. '-link' .. i, last, list_name:match ("(%w+)List"):lower() .. '-last' .. i); -- check for improper wikimarkup
link_title_ok (link, link_alias, last, last_alias); -- check for improper wikimarkup
if first then
link_title_ok (link, link_alias, first, first_alias); -- check for improper wikimarkup
end


names[n] = {last = last, first = first, link = link, mask = mask, corporate=false}; -- add this name to our names list (corporate for |vauthors= only)
names[n] = {last = last, first = first, link = link, mask = mask, corporate=false}; -- add this name to our names list (corporate for |vauthors= only)
Line 1,483: Line 1,505:


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 bit code 'ara' is not.
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,508: Line 1,530:
end
end
else
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:gsub ('^(%a%a%a?)%-.*', '%1'); -- strip any ietf-like tags from code
lang = lang:match ('(%a%a)%-') -- keep only 639-1 code portion to lang; TODO: do something with 3166 alpha 2 country code?
end
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(), cfg.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
Line 1,546: Line 1,566:
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, ', '); -- and concatenate with '<comma><space>' separators
name = table.concat (language_list, cfg.messages['parameter-separator'], 1, code-1); -- concatenate all but last
name = name:gsub (', ([^,]+)$', cfg.messages['parameter-final-separator'] .. '%1'); -- replace last '<comma><space>' separator with '<comma><space>and<space>' separator
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,569: Line 1,589:


local function set_cs1_style (ps)
local function set_cs1_style (ps)
if not is_set (ps) then -- unless explicitely set to something
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,631: Line 1,651:
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,820: Line 1,841:
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 ('punctuation');
add_vanc_error (cfg.err_msg_supl.punctuation);
end
end
local lastfirstTable = {}
local lastfirstTable = {}
Line 1,831: Line 1,852:
last = table.concat(lastfirstTable, " ") -- returns a string that is the concatenation of all other names that are not initials
last = table.concat(lastfirstTable, " ") -- returns a string that is the concatenation of all other names that are not initials
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'); -- matches last II last; the case when a comma is missing
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 ('name'); -- matches a space between two intiials
add_vanc_error (cfg.err_msg_supl.name); -- matches a space between two intiials
end
end
else
else
Line 1,843: Line 1,864:
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 ('initials'); -- too many initials; mixed case initials (which may be ok Romanization); hyphenated initials
add_vanc_error (cfg.err_msg_supl.initials); -- too many initials; mixed case initials (which may be ok Romanization); hyphenated initials
end
end
is_good_vanc_name (last, first); -- check first and last before restoring the suffix which may have a non-Latin digit
is_good_vanc_name (last, first); -- check first and last before restoring the suffix which may have a non-Latin digit
Line 1,883: Line 1,904:


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 2,105: Line 2,126:
return page, pages, at, coins_pages;
return page, pages, at, coins_pages;
end
end




Line 2,150: Line 2,170:


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 = 'save command';
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 = 'liveweb';
err_msg = cfg.err_msg_supl.liveweb;
else
else
path, timestamp, flag = url:match('//web%.archive%.org/([^%d]*)(%d+)([^/]*)/'); -- split out some of the url parts for evaluation
path, timestamp, flag = url:match('//web%.archive%.org/([^%d]*)(%d+)([^/]*)/'); -- split out some of the url parts for evaluation
if not is_set(timestamp) or 14 ~= timestamp:len() then -- path and flag optional, must have 14-digit timestamp here
if not is_set(timestamp) or 14 ~= timestamp:len() then -- path and flag optional, must have 14-digit timestamp here
err_msg = 'timestamp';
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 = 'path';
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 = 'flag';
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 = 'flag';
err_msg = cfg.err_msg_supl.flag;
else
else
return url, date; -- return archiveURL and ArchiveDate
return url, date; -- return ArchiveURL and ArchiveDate
end
end
end
end
Line 2,175: Line 2,195:
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 archiveURL and ArchiveDate
return '', ''; -- return empty strings for ArchiveURL and ArchiveDate
else
else
return url, date; -- preview mode so return archiveURL and ArchiveDate
return url, date; -- preview mode so return ArchiveURL and ArchiveDate
end
end
end
end
Line 2,192: Line 2,212:


local function place_check (param_val)
local function place_check (param_val)
if not is_set (param_val) then -- parameter empty or omitted
if not is_set (param_val) then -- parameter empty or omitted
return param_val; -- return that empty state
return param_val; -- return that empty state
end
end
Line 2,280: Line 2,300:
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 Contribution = A['Contribution']; -- TODO: move to after chapter use if A:ORIGIN ('Chapter') ... to set Contribution; this to remove duplicate in aliases list
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,322: Line 2,342:
link_title_ok (TitleLink, A:ORIGIN ('TitleLink'), Title, 'title'); -- check for wikimarkup in |title-link= or wikimarkup in |title= when |title-link= is set
link_title_ok (TitleLink, A:ORIGIN ('TitleLink'), Title, 'title'); -- check for wikimarkup in |title-link= or wikimarkup in |title= when |title-link= is set


local Chapter = A['Chapter'];
local Chapter = A['Chapter']; -- TODO: insert test, assignment, and then unset Chapter when |section= in cite map; test is at c. line 3220
local ScriptChapter = A['ScriptChapter'];
local ScriptChapter = A['ScriptChapter'];
local ScriptChapterOrigin = A:ORIGIN ('ScriptChapter');
local ScriptChapterOrigin = A:ORIGIN ('ScriptChapter');
Line 2,347: Line 2,367:
local ConferenceURL = A['ConferenceURL'];
local ConferenceURL = A['ConferenceURL'];
local ConferenceURLorigin = A:ORIGIN('ConferenceURL'); -- get name of parameter that holds ConferenceURL
local ConferenceURLorigin = A:ORIGIN('ConferenceURL'); -- get name of parameter that holds ConferenceURL
local Periodical = A['Periodical'];
 
-- TODO: mailinglist should be removed from Periodical alias list; Periodical should be assigned value from |mailinglist= here wh
local Periodical = A['Periodical']; -- cite mailinglist or citation and |mailinglist=; error check for duplicate work params (Periodical already set)
local Periodical_origin = '';
local Periodical_origin = '';
if is_set (Periodical) then
if is_set (Periodical) then
Line 2,357: Line 2,379:
end
end
end
end
 
-- TODO: mailinglist assignment here? iff Periodical not set; err msg else; see TODO c. line 2607
local ScriptPeriodical = A['ScriptPeriodical'];
local ScriptPeriodical = A['ScriptPeriodical'];
local ScriptPeriodical_origin = A:ORIGIN('ScriptPeriodical');
local ScriptPeriodical_origin = A:ORIGIN('ScriptPeriodical');
Line 2,363: Line 2,385:
-- Wikipedia:Administrators%27_noticeboard#Is_there_a_semi-automated_tool_that_could_fix_these_annoying_"Cite_Web"_errors?
-- Wikipedia:Administrators%27_noticeboard#Is_there_a_semi-automated_tool_that_could_fix_these_annoying_"Cite_Web"_errors?
if not (is_set (Periodical) or is_set (ScriptPeriodical)) then -- 'periodical' templates require periodical parameter
if not (is_set (Periodical) or is_set (ScriptPeriodical)) then -- 'periodical' templates require periodical parameter
-- local p = {['journal'] = 'journal', ['magazine'] = 'magazine', ['news'] = 'newspaper', ['web'] = 'website'}; -- for error message
-- local p = {['journal'] = 'journal', ['magazine'] = 'magazine', ['news'] = 'newspaper', ['web'] = 'website'}; -- for error message
local p = {['journal'] = 'journal', ['magazine'] = 'magazine'}; -- for error message
local p = {['journal'] = 'journal', ['magazine'] = 'magazine'}; -- for error message
if p[config.CitationClass]  then
if p[config.CitationClass]  then
Line 2,428: Line 2,450:
end
end
end
end
local Newsgroup = A['Newsgroup']; -- TODO: strip apostrophe markup?
local Newsgroup_origin = A:ORIGIN('Newsgroup');
if 'newsgroup' == config.CitationClass then
if is_set (PublisherName) then -- general use parmeter |publisher= not allowed in cite newsgroup
local error_text = set_error ('parameter_ignored', {PublisherName_origin}, true);
if is_set (error_text) then
table.insert( z.message_tail, {error_text, error_state} );
end
end
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);
local UrlAccess = is_valid_parameter_value (A['UrlAccess'], A:ORIGIN('UrlAccess'), cfg.keywords_lists['url-access'], nil);
Line 2,494: Line 2,530:
local sepc; -- separator between citation elements for CS1 a period, for CS2, a comma
local sepc; -- separator between citation elements for CS1 a period, for CS2, a comma
local PostScript;
local PostScript;
local Ref;
local Ref = A['Ref'];
sepc, PostScript, Ref = set_style (Mode:lower(), A['PostScript'], A['Ref'], config.CitationClass);
if 'harv' == Ref then
add_maint_cat ('ref_harv'); -- add maint cat to identify templates that have this now-extraneous param value
elseif not is_set (Ref) then
Ref = 'harv'; -- set as default when not set externally
end
sepc, PostScript, Ref = set_style (Mode:lower(), A['PostScript'], Ref, config.CitationClass);
use_lowercase = ( sepc == ',' ); -- used to control capitalization for certain static text
use_lowercase = ( sepc == ',' ); -- used to control capitalization for certain static text


Line 2,510: Line 2,552:
end
end
end
end
 
-- check for extra |page=, |pages= or |at= parameters. (also sheet and sheets while we're at it)
-- check for extra |page=, |pages= or |at= parameters. (also sheet and sheets while we're at it)
select_one (args, {'page', 'p', 'pp', 'pages', 'at', 'sheet', 'sheets'}, 'redundant_parameters'); -- this is a dummy call simply to get the error message and category
select_one( args, {'page', 'p', 'pp', 'pages', 'at', 'sheet', 'sheets'}, 'redundant_parameters' ); -- this is a dummy call simply to get the error message and category


local coins_pages;
local coins_pages;
Line 2,529: Line 2,570:
end
end


-- if not is_set(PublicationPlace) and is_set(Place) then -- both |publication-place= and |place= (|location=) allowed if different
-- PublicationPlace = Place; -- promote |place= (|location=) to |publication-place
-- 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,548: Line 2,585:
]]
]]


local Encyclopedia = A['Encyclopedia'];
local Encyclopedia = A['Encyclopedia'];


if ( config.CitationClass == "encyclopaedia" ) or ( config.CitationClass == "citation" and is_set (Encyclopedia)) then -- test code for citation
if ( config.CitationClass == "encyclopaedia" ) or ( config.CitationClass == "citation" and is_set (Encyclopedia)) then -- test code for citation
Line 2,559: Line 2,596:
TransChapter = TransTitle;
TransChapter = TransTitle;
ChapterURL = URL;
ChapterURL = URL;
ChapterURLorigin = A:ORIGIN('URL')
ChapterUrlAccess = UrlAccess;
ChapterUrlAccess = UrlAccess;


Line 2,592: Line 2,631:


-- special case for cite mailing list
-- special case for cite mailing list
if (config.CitationClass == "mailinglist") then
if (config.CitationClass == "mailinglist") then -- TODO: move this to Periodical assignment; see TODOs at c. line 2360
Periodical = A ['MailingList'];
Periodical = A ['MailingList'];
elseif 'mailinglist' == Periodical_origin then
elseif 'mailinglist' == Periodical_origin then
Line 2,602: Line 2,641:
if is_set(BookTitle) then
if is_set(BookTitle) then
Chapter = Title;
Chapter = Title;
-- ChapterLink = TitleLink; -- |chapterlink= is deprecated
-- ChapterLink = TitleLink; -- |chapterlink= is deprecated
ChapterURL = URL;
ChapterURL = URL;
ChapterUrlAccess = UrlAccess;
ChapterUrlAccess = UrlAccess;
Line 2,611: Line 2,650:
Title = BookTitle;
Title = BookTitle;
Format = '';
Format = '';
-- TitleLink = '';
-- TitleLink = '';
TransTitle = '';
TransTitle = '';
URL = '';
URL = '';
Line 2,647: Line 2,686:
-- 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,660: Line 2,698:
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,680: Line 2,714:
Chapter = Title; -- promote title parameters to chapter
Chapter = Title; -- promote title parameters to chapter
ScriptChapter = ScriptTitle;
ScriptChapter = ScriptTitle;
-- ScriptChapterOrigin = 'title';
ScriptChapterOrigin = A:ORIGIN('ScriptTitle');
ScriptChapterOrigin = A:ORIGIN('ScriptTitle');
ChapterLink = TitleLink; -- alias episodelink
ChapterLink = TitleLink; -- alias episodelink
Line 2,714: Line 2,747:
-- Account for the oddities that are {{cite arxiv}}, {{cite biorxiv}}, {{cite citeseerx}}, {{cite ssrn}}, before generation of COinS data.
-- Account for the oddities that are {{cite arxiv}}, {{cite biorxiv}}, {{cite citeseerx}}, {{cite ssrn}}, before generation of COinS data.
do
do
if in_array (config.CitationClass, {'arxiv', 'biorxiv', 'citeseerx', 'ssrn'}) then
if in_array (config.CitationClass, whitelist.preprint_template_list) then
if not is_set (ID_list[config.CitationClass:upper()]) then -- |arxiv= or |eprint= required for cite arxiv; |biorxiv= & |citeseerx= required for their templates
if not is_set (ID_list[config.CitationClass:upper()]) then -- |arxiv= or |eprint= required for cite arxiv; |biorxiv= & |citeseerx= required for their templates
table.insert( z.message_tail, { set_error( config.CitationClass .. '_missing', {}, true ) } ); -- add error message
table.insert( z.message_tail, { set_error( config.CitationClass .. '_missing', {}, true ) } ); -- add error message
Line 2,809: Line 2,842:
-- 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
-- if date_name_xlate (date_parameters_list, false) then
-- modified = true;
-- modified = true;
-- end
-- 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,854: Line 2,887:
end
end


if 'none' == Title and
if cfg.keywords_xlate[Title] == 'none' and
in_array (config.CitationClass, {'journal', 'citation'}) and
in_array (config.CitationClass, {'journal', 'citation'}) and
(is_set (Periodical) or is_set (ScriptPeriodical)) and
(is_set (Periodical) or is_set (ScriptPeriodical)) and
Line 2,886: Line 2,919:
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({
Line 2,903: Line 2,936:
['Pages'] = coins_pages or get_coins_pages (first_set ({Sheet, Sheets, Page, Pages, At}, 5)), -- pages stripped of external links
['Pages'] = coins_pages or get_coins_pages (first_set ({Sheet, Sheets, Page, Pages, At}, 5)), -- pages stripped of external links
['Edition'] = Edition,
['Edition'] = Edition,
['PublisherName'] = PublisherName, -- any apostrophe markup already removed
['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,911: Line 2,944:


-- Account for the oddities that are {{cite arxiv}}, {{cite biorxiv}}, {{cite citeseerx}}, and {{cite ssrn}} AFTER generation of COinS data.
-- Account for the oddities that are {{cite arxiv}}, {{cite biorxiv}}, {{cite citeseerx}}, and {{cite ssrn}} AFTER generation of COinS data.
if in_array (config.CitationClass, {'arxiv', 'biorxiv', 'citeseerx', 'ssrn'}) then -- we have set rft.jtitle in COinS to arXiv, bioRxiv, CiteSeerX, or ssrn now unset so it isn't displayed
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
if is_set (PublisherName) then
PublisherName = substitute (cfg.messages['newsgroup'], external_link( 'news:' .. Newsgroup, Newsgroup, Newsgroup_origin, nil ));
PublisherName = substitute (cfg.messages['newsgroup'], external_link( 'news:' .. PublisherName, PublisherName, PublisherName_origin, nil ));
end
end
end


Line 2,932: Line 2,963:
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
};
};
Line 2,944: Line 2,974:
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 3,088: Line 3,116:
end
end


-- Format main title.
-- Format main title. TODO: add support for non-English versions of 'Archived copy' when used on other-language wikis
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)
if is_set (ArchiveURL) and  
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.en) or -- if title is 'Archived copy' (place holder added by bots that can't find proper title)
mw.ustring.match (mw.ustring.lower(Title), cfg.special_case_translation.archived_copy['local'])) then -- local-wiki's form
add_maint_cat ('archived_copy'); -- add maintenance category before we modify the content of Title
end
end


Line 3,103: Line 3,133:
end
end
end
end
 
if in_array(config.CitationClass, {'web', 'news', 'journal', 'magazine', 'pressrelease', 'podcast', 'newsgroup', 'mailinglist', 'interview', 'arxiv', 'biorxiv', 'citeseerx', 'ssrn'}) or
if in_array(config.CitationClass, {'web', 'news', 'journal', 'magazine', 'pressrelease', 'podcast', 'newsgroup', 'mailinglist', 'interview', 'arxiv', 'biorxiv', 'citeseerx', 'ssrn'}) or
('citation' == config.CitationClass and (is_set (Periodical) or is_set (ScriptPeriodical)) and not is_set (Encyclopedia)) or
('citation' == config.CitationClass and (is_set (Periodical) or is_set (ScriptPeriodical)) and not is_set (Encyclopedia)) or
Line 3,129: Line 3,159:
end
end


if is_set(Title) then
if is_set (Title) then -- TODO: is this the right place to be making wikisource urls?
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, URLorigin, UrlAccess) .. TransTitle .. TransError .. Format;
Title = external_link (URL, Title, URLorigin, UrlAccess) .. TransTitle .. TransError .. Format;
Line 3,145: Line 3,175:
end
end
else
else
local ws_url, ws_label;
local ws_url, ws_label; -- Title has italic or quote markup by the time we get here which causes is_wikilink() to return 0 (not a wikilink)
ws_url, ws_label, L = wikisource_url_make (Title); -- make ws url from |title= interwiki link; link portion L becomes tool tip label
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,203: Line 3,233:
At = is_set(At) and (sepc .. " " .. At) or "";
At = is_set(At) and (sepc .. " " .. At) or "";
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 -- TODO copy this line and
local Section = A['Section'];
local Section = A['Section']; -- TODO move this line to c. line 2337 so that separate Sections in aliases{} not required? then unset Chapter?
local Sections = A['Sections'];
local Sections = A['Sections'];
local Inset = A['Inset'];
local Inset = A['Inset'];
Line 3,530: Line 3,560:
end
end
if is_set(Ref) and Ref:lower() ~= "none" then -- set reference anchor if appropriate
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,594: Line 3,624:
end
end
-- no_tracking_cats = no_tracking_cats:lower();
-- if in_array(no_tracking_cats, {"", "no", "false", "n"}) then
if not no_tracking_cats then
if not no_tracking_cats then
for _, v in ipairs( z.error_categories ) do
for _, v in ipairs( z.error_categories ) do
Line 3,626: Line 3,654:
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', 'ssrn'}) 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,634: Line 3,660:
return true;
return true;
end
end
return nil;
end


state = whitelist[cite_class .. '_basic_arguments'][name]; -- look in the parameter-list for the template identified by cite_class
if name:find ('#') then -- # is a cs1|2 reserved character so parameters with # not permitted
return nil;
end
 
if in_array (cite_class, whitelist.preprint_template_list ) then -- limited parameter sets allowed for these templates
state = whitelist.limited_basic_arguments[name];
if true == state_test (state, name) then return true; end
 
state = whitelist.preprint_arguments[cite_class][name]; -- look in the parameter-list for the template identified by cite_class
if true == state_test (state, name) then return true; end


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 -- valid actively supported parameter
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