Module:Citation/CS1: Difference between revisions

sync from sandbox;
(sync from sandbox;)
(sync from sandbox;)
Line 22: Line 22:
--[[--------------------------< P A G E  S C O P E  V A R I A B L E S >--------------------------------------
--[[--------------------------< P A G E  S C O P E  V A R I A B L E S >--------------------------------------


delare variables here that have page-wide scope that are not brought in from other modules; thatare created here
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 695: Line 694:
]]
]]


local function format_chapter_title (scriptchapter, script_chapter_source, chapter, transchapter, chapterurl, chapter_url_source, no_quotes, access)
local function format_chapter_title (script_chapter, script_chapter_source, chapter, chapter_source, trans_chapter, trans_chapter_source, chapter_url, chapter_url_source, no_quotes, access)
local chapter_error = '';
local chapter_error = '';


Line 713: Line 712:
end
end


chapter = script_concatenate (chapter, scriptchapter, script_chapter_source); -- <bdi> tags, lang atribute, categorization, etc; must be done after title is wrapped
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 (chapterurl) then
if is_set (chapter_url) then
chapter = external_link (chapterurl, chapter, chapter_url_source, access); -- adds bare_url_missing_title error if appropriate
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 .. '&nbsp;', 'ws link in chapter'); -- adds bare_url_missing_title error if appropriate; space char to move icon away from chap text; TODO: better way to do this?
chapter = external_link (ws_url, chapter .. '&nbsp;', 'ws link in chapter'); -- adds bare_url_missing_title error if appropriate; space char to move icon away from chap text; TODO: better way to do this?
Line 722: Line 721:
end
end


if is_set (transchapter) then
if is_set (trans_chapter) then
transchapter = wrap_style ('trans-quoted-title', transchapter);
trans_chapter = wrap_style ('trans-quoted-title', trans_chapter);
if is_set (chapter) then
if is_set (chapter) then
chapter = chapter ..  ' ' .. transchapter;
chapter = chapter ..  ' ' .. trans_chapter;
else -- here when transchapter without chapter or script-chapter
else -- here when trans_chapter without chapter or script-chapter
chapter = transchapter;
chapter = trans_chapter;
chapter_error = ' ' .. set_error ('trans_missing_title', {'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_source});
end
end
end
end
Line 882: 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 'none' == cfg.keywords_xlate[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
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 1,074: Line 1,073:
]]
]]


local function is_good_vanc_name (last, first)
local function is_good_vanc_name (last, first, suffix)
local first, suffix = first:match ('(.-),?%s*([%dJS][%drndth]+)%.?$') or first; -- if first has something that looks like a generational suffix, get it
if not suffix then
 
if first:find ('[,%s]') then -- when there is a space or comma, might be first name/initials + generational suffix
first = first:match ('(.-)[,%s]+'); -- get name/initials
suffix = first:match ('[,%s]+(.+)$'); -- get generational suffix
end
end
if is_set (suffix) then
if is_set (suffix) then
if not is_suffix (suffix) then
if not is_suffix (suffix) then
Line 1,085: 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 (cfg.err_msg_supl['non-Latin character']);
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,118: 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 (cfg.err_msg_supl.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,549: Line 1,552:
add_prop_cat ('foreign_lang_source' .. code, {name, code}); -- categorize it; code appended to allow for multiple language categorization
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 mutliple three-character code categories per cs1|2 template
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
elseif cfg.local_lang_cat_enable then -- when the language and this wiki's language are the same and categorization is enabled
Line 1,835: Line 1,838:


for i, v_name in ipairs(v_name_table) do
for i, v_name in ipairs(v_name_table) do
first = ''; -- set to empty string for concatenation and because it may have been set for previous author/editor
if v_name:match ('^%(%(.+%)%)$') then -- corporate authors are wrapped in doubled parentheses to supress vanc formatting and error detection
if v_name:match ('^%(%(.+%)%)$') then -- corporate authors are wrapped in doubled parentheses to supress vanc formatting and error detection
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()
Line 1,844: Line 1,847:
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 author intials
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
 
suffix = first -- save it as a suffix and
if not mw.ustring.match (first, '^%u+$') then -- mw.ustring here so that later we will catch non-latin characters
suffix = first; -- not initials so assume that whatever we got is a generational suffix
first = table.remove(lastfirstTable); -- get what should be the initials from the table
first = table.remove(lastfirstTable); -- get what should be the initials from the table
end -- no suffix error message here because letter combination may be result of Romanization; check for digits?
end
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 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 (cfg.err_msg_supl['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 (cfg.err_msg_supl.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
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,864: 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 (cfg.err_msg_supl.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, 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 2,300: Line 2,308:
local c = {}; -- contributors list from |contributor-lastn= / contributor-firstn= pairs
local c = {}; -- contributors list from |contributor-lastn= / contributor-firstn= pairs
local Contributors; -- assembled contributors name list
local Contributors; -- assembled contributors name list
local Contribution = A['Contribution']; -- TODO: move to after chapter use if A:ORIGIN ('Chapter') ... to set Contribution; this to remove duplicate in aliases list
 
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,338: Line 2,353:
local Conference = A['Conference'];
local Conference = A['Conference'];
local TransTitle = A['TransTitle'];
local TransTitle = A['TransTitle'];
local TransTitle_origin = A:ORIGIN ('TransTitle');
local TitleNote = A['TitleNote'];
local TitleNote = A['TitleNote'];
local TitleLink = A['TitleLink'];
local TitleLink = A['TitleLink'];
link_title_ok (TitleLink, A:ORIGIN ('TitleLink'), Title, 'title'); -- check for wikimarkup in |title-link= or wikimarkup in |title= when |title-link= is set
link_title_ok (TitleLink, A:ORIGIN ('TitleLink'), Title, 'title'); -- check for wikimarkup in |title-link= or wikimarkup in |title= when |title-link= is set


local Chapter = A['Chapter']; -- TODO: insert test, assignment, and then unset Chapter when |section= in cite map; test is at c. line 3220
local Section = ''; -- {{cite map}} only; preset to empty string for concatnation if not used
if 'map' == config.CitationClass and 'section' == A:ORIGIN ('Chapter') then
Section = A['Chapter']; -- get |section= from |chapter= alias list; |chapter= and the other aliases not supported in {{cite map}}
Chapter = ''; -- unset for now; will be reset later from |map= if present
end
 
local ScriptChapter = A['ScriptChapter'];
local ScriptChapter = A['ScriptChapter'];
local ScriptChapterOrigin = A:ORIGIN ('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,361: Line 2,383:


local URL = A['URL']
local URL = A['URL']
local URLorigin = A:ORIGIN('URL'); -- get name of parameter that holds URL
local URL_origin = A:ORIGIN('URL'); -- get name of parameter that holds URL
local ChapterURL = A['ChapterURL'];
local ChapterURL = A['ChapterURL'];
local ChapterURLorigin = A:ORIGIN('ChapterURL'); -- get name of parameter that holds ChapterURL
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 ConferenceURLorigin = A:ORIGIN('ConferenceURL'); -- get name of parameter that holds ConferenceURL
local ConferenceURL_origin = A:ORIGIN('ConferenceURL'); -- get name of parameter that holds ConferenceURL


-- TODO: mailinglist should be removed from Periodical alias list; Periodical should be assigned value from |mailinglist= here wh
local Periodical = A['Periodical'];
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,379: Line 2,400:
end
end
end
end
-- TODO: mailinglist assignment here? iff Periodical not set; err msg else; see TODO c. line 2607
 
if 'mailinglist' == config.CitationClass then -- special case for {{cite mailing list}}
if is_set (Periodical) and is_set (A ['MailingList']) then -- both set emit an error
table.insert( z.message_tail, { set_error('redundant_parameters', {wrap_style ('parameter', Periodical_origin) .. ' and ' .. wrap_style ('parameter', 'mailinglist')}, true )});
end
 
Periodical = A ['MailingList']; -- error or no, set Periodical to |mailinglist= value because this template is {{cite mailing list}}
Periodical_origin = A:ORIGIN('MailingList');
end
 
 
 
local ScriptPeriodical = A['ScriptPeriodical'];
local ScriptPeriodical = A['ScriptPeriodical'];
local ScriptPeriodical_origin = A:ORIGIN('ScriptPeriodical');
local ScriptPeriodical_origin = A:ORIGIN('ScriptPeriodical');
Line 2,393: Line 2,426:


local TransPeriodical =  A['TransPeriodical'];
local TransPeriodical =  A['TransPeriodical'];
local TransPeriodical_origin =  A:ORIGIN ('TransPeriodical');


local Series = A['Series'];
local Series = A['Series'];
Line 2,511: Line 2,545:
local TranscriptFormat = A['TranscriptFormat'];
local TranscriptFormat = A['TranscriptFormat'];
local TranscriptURL = A['TranscriptURL']  
local TranscriptURL = A['TranscriptURL']  
local TranscriptURLorigin = A:ORIGIN('TranscriptURL'); -- get name of parameter that holds TranscriptURL
local TranscriptURL_origin = A:ORIGIN('TranscriptURL'); -- get name of parameter that holds TranscriptURL


local LastAuthorAmp = is_valid_parameter_value (A['LastAuthorAmp'], A:ORIGIN('LastAuthorAmp'), cfg.keywords_lists['yes_true_y'], nil);
local LastAuthorAmp = is_valid_parameter_value (A['LastAuthorAmp'], A:ORIGIN('LastAuthorAmp'), cfg.keywords_lists['yes_true_y'], nil);
Line 2,585: Line 2,619:
]]
]]


local Encyclopedia = A['Encyclopedia'];
local Encyclopedia = A['Encyclopedia']; -- used as a flag by this module and by ~/COinS
 
if is_set (Encyclopedia) then -- emit error message when Encyclopedia set but template is other than {{cite encyclopedia}} or {{citation}}
if 'encyclopaedia' ~= config.CitationClass and 'citation' ~= config.CitationClass then
table.insert (z.message_tail, {set_error ('parameter_ignored', {A:ORIGIN ('Encyclopedia')}, true)});
Encyclopedia = nil; -- unset because not supported by this template
end
end
 
if ('encyclopaedia' == config.CitationClass) or ('citation' == config.CitationClass and is_set (Encyclopedia)) then
if is_set (Periodical) and is_set (Encyclopedia) then -- when both set emit an error
table.insert (z.message_tail, {set_error('redundant_parameters', {wrap_style ('parameter', A:ORIGIN ('Encyclopedia')) .. ' and ' .. wrap_style ('parameter', Periodical_origin)}, true )});
end
 
if is_set (Encyclopedia) then
Periodical = Encyclopedia; -- error or no, set Periodical to Encyclopedia; allow periodical without encyclopedia
Periodical_origin = A:ORIGIN ('Encyclopedia');
end


if ( config.CitationClass == "encyclopaedia" ) or ( config.CitationClass == "citation" and is_set (Encyclopedia)) then -- test code for citation
if is_set (Periodical) then -- Periodical is set when |encyclopedia is set
if is_set (Periodical) then -- Periodical is set when |encyclopedia is set
if is_set(Title) or is_set (ScriptTitle) then
if is_set(Title) or is_set (ScriptTitle) then
Line 2,593: Line 2,643:
Chapter = Title; -- |encyclopedia and |title are set so map |title to |article and |encyclopedia to |title
Chapter = Title; -- |encyclopedia and |title are set so map |title to |article and |encyclopedia to |title
ScriptChapter = ScriptTitle;
ScriptChapter = ScriptTitle;
ScriptChapterOrigin = A:ORIGIN('ScriptTitle')
ScriptChapter_origin = A:ORIGIN('ScriptTitle')
TransChapter = TransTitle;
TransChapter = TransTitle;
ChapterURL = URL;
ChapterURL = URL;
ChapterURLorigin = A:ORIGIN('URL')
ChapterURL_origin = A:ORIGIN('URL')


ChapterUrlAccess = UrlAccess;
ChapterUrlAccess = UrlAccess;
Line 2,628: Line 2,678:
end
end
end
end
end
-- special case for cite mailing list
if (config.CitationClass == "mailinglist") then -- TODO: move this to Periodical assignment; see TODOs at c. line 2360
Periodical = A ['MailingList'];
elseif 'mailinglist' == Periodical_origin then
Periodical = ''; -- unset because mailing list is only used for cite mailing list
end
end


Line 2,641: 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;
ChapterURLorigin = URLorigin;
ChapterURL_origin = URL_origin;
URLorigin = '';
URL_origin = '';
ChapterFormat = Format;
ChapterFormat = Format;
TransChapter = TransTitle;
TransChapter = TransTitle;
TransChapter_origin = TransTitle_origin;
Title = BookTitle;
Title = BookTitle;
Format = '';
Format = '';
Line 2,664: 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'];
ChapterURLorigin = A:ORIGIN('MapURL');
ChapterURL_origin = A:ORIGIN('MapURL');
TransChapter = A['TransMap'];
TransChapter = A['TransMap'];
ScriptChapter = A['ScriptMap']
ScriptChapter = A['ScriptMap']
ScriptChapterOrigin = A:ORIGIN('ScriptMap')
ScriptChapter_origin = A:ORIGIN('ScriptMap')


ChapterUrlAccess = MapUrlAccess;
ChapterUrlAccess = MapUrlAccess;
Line 2,714: Line 2,763:
Chapter = Title; -- promote title parameters to chapter
Chapter = Title; -- promote title parameters to chapter
ScriptChapter = ScriptTitle;
ScriptChapter = ScriptTitle;
ScriptChapterOrigin = A:ORIGIN('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;
ChapterURLorigin = A:ORIGIN('URL');
ChapterURL_origin = A:ORIGIN('URL');
Title = Series; -- promote series to title
Title = Series; -- promote series to title
Line 2,859: Line 2,908:
end -- end of do
end -- end of do


-- Account for the oddity that is {{cite journal}} with |pmc= set and |url= not set.  Do this after date check but before COInS.
-- Link the title of the work if no |url= was provided, but we have a |pmc= or a |doi= with |doi-access=free
-- Here we unset Embargo if PMC not embargoed (|embargo= not set in the citation) or if the embargo time has expired. Otherwise, holds embargo date
-- Here we unset Embargo if PMC not embargoed (|embargo= not set in the citation) or if the embargo time has expired. Otherwise, holds embargo date
Embargo = is_embargoed (Embargo);
Embargo = is_embargoed (Embargo);
 
if config.CitationClass == "journal" and not is_set(URL) and is_set(ID_list['PMC']) then
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
URLorigin = cfg.id_handlers['PMC'].parameters[1]; -- set URLorigin to parameter name for use in error message if citation is missing a |title=
URL_origin = cfg.id_handlers['PMC'].parameters[1]; -- set URL_origin to parameter name for use in error message if citation is missing a |title=
if is_set(AccessDate) then -- access date requires |url=; pmc created url is not |url=
elseif is_set(ID_list['DOI']) and ID_access_levels['DOI'] == "free" then
table.insert( z.message_tail, { set_error( 'accessdate_missing_url', {}, true ) } );
URL=cfg.id_handlers['DOI'].prefix .. ID_list['DOI'];
AccessDate = ''; -- unset
URL_origin = cfg.id_handlers['DOI'].parameters[1];
end
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,877: 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
not is_set(TransTitle) and
table.insert( z.message_tail, { set_error( 'citation_missing_title', {'episode' == config.CitationClass and 'series' or 'title'}, true ) } );
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


Line 2,923: Line 2,968:
local OCinSoutput = COinS({
local OCinSoutput = COinS({
['Periodical'] = strip_apostrophe_markup (Periodical), -- no markup in the metadata
['Periodical'] = strip_apostrophe_markup (Periodical), -- no markup in the metadata
['Encyclopedia'] = strip_apostrophe_markup (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,930: Line 2,975:
['Date'] = COinS_date.rftdate, -- COinS_date has correctly formatted date if Date is valid;
['Date'] = COinS_date.rftdate, -- COinS_date has correctly formatted date if Date is valid;
['Season'] = COinS_date.rftssn,
['Season'] = COinS_date.rftssn,
['Quarter'] = COinS_date.rftquarter,
['Chron'] =  COinS_date.rftchron or (not COinS_date.rftdate and Date) or '', -- chron but if not set and invalid date format use Date; keep this last bit?
['Chron'] =  COinS_date.rftchron or (not COinS_date.rftdate and Date) or '', -- chron but if not set and invalid date format use Date; keep this last bit?
['Series'] = Series,
['Series'] = Series,
Line 3,044: Line 3,090:
end
end


local OriginalURL, OriginalURLorigin, OriginalFormat, OriginalAccess;
local OriginalURL, OriginalURL_origin, OriginalFormat, OriginalAccess;
UrlStatus = UrlStatus:lower(); -- used later when assembling archived text
UrlStatus = UrlStatus:lower(); -- used later when assembling archived text
if is_set( ArchiveURL ) then
if is_set( ArchiveURL ) then
if is_set (ChapterURL) then -- if chapter-url is set apply archive url to it
if is_set (ChapterURL) then -- if chapter-url is set apply archive url to it
OriginalURL = ChapterURL; -- save copy of source chapter's url for archive text
OriginalURL = ChapterURL; -- save copy of source chapter's url for archive text
OriginalURLorigin = ChapterURLorigin; -- name of chapter-url parameter for error messages
OriginalURL_origin = ChapterURL_origin; -- name of chapter-url parameter for error messages
OriginalFormat = ChapterFormat; -- and original |chapter-format=
OriginalFormat = ChapterFormat; -- and original |chapter-format=


if 'live' ~= UrlStatus then
if 'live' ~= UrlStatus then
ChapterURL = ArchiveURL -- swap-in the archive's url
ChapterURL = ArchiveURL -- swap-in the archive's url
ChapterURLorigin = A:ORIGIN('ArchiveURL') -- name of archive-url parameter for error messages
ChapterURL_origin = A:ORIGIN('ArchiveURL') -- name of archive-url parameter for error messages
ChapterFormat = ArchiveFormat or ''; -- swap in archive's format
ChapterFormat = ArchiveFormat or ''; -- swap in archive's format
ChapterUrlAccess = nil; -- restricted access levels do not make sense for archived urls
ChapterUrlAccess = nil; -- restricted access levels do not make sense for archived urls
Line 3,060: 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
OriginalURLorigin = URLorigin; -- name of url parameter for error messages
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;
Line 3,066: Line 3,112:
if 'live' ~= UrlStatus then -- if URL set then archive-url applies to it
if 'live' ~= UrlStatus then -- if URL set then archive-url applies to it
URL = ArchiveURL -- swap-in the archive's url
URL = ArchiveURL -- swap-in the archive's url
URLorigin = A:ORIGIN('ArchiveURL') -- name of archive url parameter for error messages
URL_origin = A:ORIGIN('ArchiveURL') -- name of archive url parameter for error messages
Format = ArchiveFormat or ''; -- swap in archive's format
Format = ArchiveFormat or ''; -- swap in archive's format
UrlAccess = nil; -- restricted access levels do not make sense for archived urls
UrlAccess = nil; -- restricted access levels do not make sense for archived urls
Line 3,083: 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 = ScriptChapterOrigin;
chap_param = ScriptChapter_origin;
else is_set (ChapterFormat)
else is_set (ChapterFormat)
chap_param = A:ORIGIN ('ChapterFormat')
chap_param = A:ORIGIN ('ChapterFormat')
Line 3,104: Line 3,150:
end
end


Chapter = format_chapter_title (ScriptChapter, ScriptChapterOrigin, Chapter, TransChapter, ChapterURL, ChapterURLorigin, no_quotes, ChapterUrlAccess); -- Contribution is also in Chapter
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,116: Line 3,162:
end
end


-- Format main title. TODO: add support for non-English versions of 'Archived copy' when used on other-language wikis
-- 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.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.en) or -- if title is 'Archived copy' (place holder added by bots that can't find proper title)
Line 3,160: Line 3,206:


if is_set (Title) then -- TODO: is this the right place to be making wikisource urls?
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, URLorigin, UrlAccess) .. TransTitle .. TransError .. Format;
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,196: 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, ConferenceURLorigin, nil );
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, ConferenceURLorigin, nil );
Conference = sepc .. " " .. external_link( ConferenceURL, nil, ConferenceURL_origin, nil );
end
end


Line 3,233: Line 3,284:
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 -- TODO copy this line and
if config.CitationClass == 'map' then
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']; -- Section (singular) is an alias of Chapter so set earlier
local Sections = A['Sections'];
local Inset = A['Inset'];
local Inset = A['Inset'];
Line 3,307: Line 3,357:


if is_set(URL) then
if is_set(URL) then
URL = " " .. external_link( URL, nil, URLorigin, UrlAccess );
URL = " " .. external_link( URL, nil, URL_origin, UrlAccess );
end
end


Line 3,346: Line 3,396:
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,
{ external_link( OriginalURL, cfg.messages['original'], OriginalURLorigin, OriginalAccess ) .. OriginalFormat, ArchiveDate } ); -- format already styled
{ external_link( OriginalURL, cfg.messages['original'], OriginalURL_origin, OriginalAccess ) .. OriginalFormat, ArchiveDate } ); -- format already styled
end
end
else -- OriginalUrl not set
else -- OriginalUrl not set
Line 3,379: Line 3,429:
if is_set(Transcript) then
if is_set(Transcript) then
if is_set(TranscriptURL) then
if is_set(TranscriptURL) then
Transcript = external_link( TranscriptURL, Transcript, TranscriptURLorigin, nil );
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, TranscriptURLorigin, nil );
Transcript = external_link( TranscriptURL, nil, TranscriptURL_origin, nil );
end
end


Line 3,405: Line 3,455:
if (is_set (Periodical) or is_set (ScriptPeriodical) or is_set (TransPeriodical)) then
if (is_set (Periodical) or is_set (ScriptPeriodical) or is_set (TransPeriodical)) then
if is_set(Title) or is_set(TitleNote) then  
if is_set(Title) or is_set(TitleNote) then  
Periodical = sepc .. " " .. format_periodical (ScriptPeriodical, ScriptPeriodical_origin, Periodical, TransPeriodical);
Periodical = sepc .. " " .. format_periodical (ScriptPeriodical, ScriptPeriodical_origin, Periodical, TransPeriodical, TransPeriodical_origin);
else  
else  
Periodical = format_periodical (ScriptPeriodical, ScriptPeriodical_origin, Periodical, TransPeriodical);
Periodical = format_periodical (ScriptPeriodical, ScriptPeriodical_origin, Periodical, TransPeriodical, TransPeriodical_origin);
end
end
end
end
Line 3,554: Line 3,604:
if is_set(config.CitationClass) and config.CitationClass ~= "citation" then
if is_set(config.CitationClass) and config.CitationClass ~= "citation" then
options.class = 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 = "citation";
options.class = string.format ('%s %s', 'citation', is_set (Mode) and Mode or 'cs2');
end
end
Line 3,703: 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,718: Line 3,767:


capture = value:match ('%s+(%a[%w%-]+)%s*=') or value:match ('^(%a[%w%-]+)%s*='); -- find and categorize parameters with possible missing pipes
capture = value:match ('%s+(%a[%w%-]+)%s*=') or value:match ('^(%a[%w%-]+)%s*='); -- find and categorize parameters with possible missing pipes
if capture and validate (capture) then -- if 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)});
table.insert( z.message_tail, {set_error ('missing_pipe', parameter)});
end
end
end
end
Line 3,731: Line 3,780:


local function has_extraneous_punc (param, value)
local function has_extraneous_punc (param, value)
if 'number' == type (param) then
return;
end
param = param:gsub ('%d+', '#'); -- enumerated name-list mask params allow terminal punct; normalize
if cfg.punct_skip[param] then
if cfg.punct_skip[param] then
return; -- parameter name found in the skip table so done
return; -- parameter name found in the skip table so done
Line 3,812: 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; -- debug tool that allows us to render a citation from module {{#invoke:}}
-- 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,865: Line 3,919:
end
end
end
end
missing_pipe_check (k, v); -- do we think that there is a parameter that is missing a pipe?
 
-- TODO: is this the best place for this translation?
args[k] = v; -- save this parameter and its value
args[k] = v;
 
elseif args[k] ~= nil or (k == 'postscript') then -- here when v is empty string
-- crude debug support that allows us to render a citation from module {{#invoke:}} TODO: keep?
args[k] = v; -- why do we do this?  we don't support 'empty' parameters
-- elseif args[k] ~= nil or (k == 'postscript') then -- when args[k] has a value from {{#invoke}} frame (we don't normally do that)
end
-- args[k] = v; -- overwrite args[k] with empty string from pframe.args[k] (template frame); v is empty string here
end -- not sure about the postscript bit; that gets handled in parameter validation; historical artifact?
end
end


for k, v in pairs( args ) do
for k, v in pairs( args ) do
if 'string' == type (k) then -- don't evaluate positional parameters
has_invisible_chars (k, v); -- look for invisible characters
has_invisible_chars (k, v);
has_extraneous_punc (k, v); -- look for extraneous terminal punctuation in parameter values
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
end