Changes

7,329 bytes added ,  14:43, 14 January 2023
sync from sandbox;
Line 1: Line 1: −
require ('Module:No globals');
+
require('strict');
    
--[[--------------------------< 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 10: Line 10:     
local utilities; -- functions in Module:Citation/CS1/Utilities
 
local utilities; -- functions in Module:Citation/CS1/Utilities
local z ={}; -- table of tables in Module:Citation/CS1/Utilities
+
local z = {}; -- table of tables in Module:Citation/CS1/Utilities
    
local identifiers; -- functions and tables in Module:Citation/CS1/Identifiers
 
local identifiers; -- functions and tables in Module:Citation/CS1/Identifiers
Line 154: Line 154:  
end
 
end
   −
for _, d in ipairs ({'cash', 'company', 'today', 'org'}) do -- look for single letter second level domain names for these top level domains
+
for _, d in ipairs (cfg.single_letter_2nd_lvl_domains_t) do -- look for single letter second level domain names for these top level domains
 
if domain:match ('%f[%w][%w]%.' .. d) then
 
if domain:match ('%f[%w][%w]%.' .. d) then
 
return true
 
return true
Line 265: Line 265:     
local function link_title_ok (link, lorig, title, torig)
 
local function link_title_ok (link, lorig, title, torig)
local orig;
+
local orig;
 
if utilities.is_set (link) then -- don't bother if <param>-link doesn't have a value
 
if utilities.is_set (link) then -- don't bother if <param>-link doesn't have a value
 
if not link_param_ok (link) then -- check |<param>-link= markup
 
if not link_param_ok (link) then -- check |<param>-link= markup
Line 401: Line 401:  
utilities.set_message ('err_bare_url_missing_title', {utilities.wrap_style ('parameter', source)});
 
utilities.set_message ('err_bare_url_missing_title', {utilities.wrap_style ('parameter', source)});
 
else
 
else
error (cfg.messages["bare_url_no_origin"]);
+
error (cfg.messages["bare_url_no_origin"]); -- programmer error; valid parameter name does not have matching meta-parameter
 
end
 
end
 
end
 
end
Line 764: Line 764:  
if mw.ustring.find (v, cfg.indic_script) then -- it's ok if one of the Indic scripts
 
if mw.ustring.find (v, cfg.indic_script) then -- it's ok if one of the Indic scripts
 
position = nil; -- unset position
 
position = nil; -- unset position
elseif cfg.emoji[mw.ustring.codepoint (v, position+1)] then -- is zwj followed by a character listed in emoji{}?
+
elseif cfg.emoji_t[mw.ustring.codepoint (v, position+1)] then -- is zwj followed by a character listed in emoji{}?
 
position = nil; -- unset position
 
position = nil; -- unset position
 
end
 
end
Line 1,105: Line 1,105:  
 
 
return table.concat(initials) -- Vancouver format does not include spaces.
 
return table.concat(initials) -- Vancouver format does not include spaces.
 +
end
 +
 +
 +
--[[--------------------------< I N T E R W I K I _ P R E F I X E N _ G E T >----------------------------------
 +
 +
extract interwiki prefixen from <value>.  Returns two one or two values:
 +
false – no prefixen
 +
nil – prefix exists but not recognized
 +
project prefix, language prefix – when value has either of:
 +
:<project>:<language>:<article>
 +
:<language>:<project>:<article>
 +
project prefix, nil – when <value> has only a known single-letter prefix
 +
nil, language prefix – when <value> has only a known language prefix
 +
 +
accepts single-letter project prefixen: 'd' (wikidata), 's' (wikisource), and 'w' (wikipedia) prefixes; at this
 +
writing, the other single-letter prefixen (b (wikibook), c (commons), m (meta), n (wikinews), q (wikiquote), and
 +
v (wikiversity)) are not supported.
 +
 +
]]
 +
 +
local function interwiki_prefixen_get (value, is_link)
 +
if not value:find (':%l+:') then -- if no prefix
 +
return false; -- abandon; boolean here to distinguish from nil fail returns later
 +
end
 +
 +
local prefix_patterns_linked_t = { -- sequence of valid interwiki and inter project prefixen
 +
'^%[%[:([dsw]):(%l%l+):', -- wikilinked; project and language prefixes
 +
'^%[%[:(%l%l+):([dsw]):', -- wikilinked; language and project prefixes
 +
'^%[%[:([dsw]):', -- wikilinked; project prefix
 +
'^%[%[:(%l%l+):', -- wikilinked; language prefix
 +
}
 +
 +
local prefix_patterns_unlinked_t = { -- sequence of valid interwiki and inter project prefixen
 +
'^:([dsw]):(%l%l+):', -- project and language prefixes
 +
'^:(%l%l+):([dsw]):', -- language and project prefixes
 +
'^:([dsw]):', -- project prefix
 +
'^:(%l%l+):', -- language prefix
 +
}
 +
 +
local cap1, cap2;
 +
for _, pattern in ipairs ((is_link and prefix_patterns_linked_t) or prefix_patterns_unlinked_t) do
 +
cap1, cap2 = value:match (pattern);
 +
if cap1 then
 +
break; -- found a match so stop looking
 +
end
 +
end
 +
 +
if cap1 and cap2 then -- when both then :project:language: or :language:project: (both forms allowed)
 +
if 1 == #cap1 then -- length == 1 then :project:language:
 +
if cfg.inter_wiki_map[cap2] then -- is language prefix in the interwiki map?
 +
return cap1, cap2; -- return interwiki project and interwiki language
 +
end
 +
else -- here when :language:project:
 +
if cfg.inter_wiki_map[cap1] then -- is language prefix in the interwiki map?
 +
return cap2, cap1; -- return interwiki project and interwiki language
 +
end
 +
end
 +
return nil; -- unknown interwiki language
 +
elseif not (cap1 or cap2) then -- both are nil?
 +
return nil; -- we got something that looks like a project prefix but isn't; return fail
 +
elseif 1 == #cap1 then -- here when one capture
 +
return cap1, nil; -- length is 1 so return project, nil language
 +
else -- here when one capture and its length it more than 1
 +
if cfg.inter_wiki_map[cap1] then -- is language prefix in the interwiki map?
 +
return nil, cap1; -- return nil project, language
 +
end
 +
end
 
end
 
end
   Line 1,175: Line 1,242:  
one = utilities.make_wikilink (person.link, one); -- link author/editor
 
one = utilities.make_wikilink (person.link, one); -- link author/editor
 
end
 
end
 +
 
if one then -- if <one> has a value (name, mdash replacement, or mask text replacement)
 
if one then -- if <one> has a value (name, mdash replacement, or mask text replacement)
 +
local proj, tag = interwiki_prefixen_get (one, true); -- get the interwiki prefixen if present
 +
 +
if 'w' == proj and ('Wikipedia' == mw.site.namespaces.Project['name']) then
 +
proj = nil; -- for stuff like :w:de:<article>, :w is unnecessary TODO: maint cat?
 +
end
 +
if proj then
 +
proj = ({['d'] = 'Wikidata', ['s'] = 'Wikisource', ['w'] = 'Wikipedia'})[proj]; -- :w (wikipedia) for linking from a non-wikipedia project
 +
if proj then
 +
one = one .. utilities.wrap_style ('interproj', proj); -- add resized leading space, brackets, static text, language name
 +
tag = nil; -- unset; don't do both project and language
 +
end
 +
end
 +
if tag == cfg.this_wiki_code then
 +
tag = nil; -- stuff like :en:<article> at en.wiki is pointless TODO: maint cat?
 +
end
 +
if tag then
 +
local lang = cfg.lang_code_remap[tag] or cfg.mw_languages_by_tag_t[tag];
 +
if lang then -- error messaging done in extract_names() where we know parameter names
 +
one = one .. utilities.wrap_style ('interwiki', lang); -- add resized leading space, brackets, static text, language name
 +
end
 +
end
 +
 
table.insert (name_list, one); -- add it to the list of names
 
table.insert (name_list, one); -- add it to the list of names
 
table.insert (name_list, sep_one); -- add the proper name-list separator
 
table.insert (name_list, sep_one); -- add the proper name-list separator
Line 1,494: Line 1,584:  
link, link_alias = utilities.select_one ( args, cfg.aliases[list_name .. '-Link'], 'err_redundant_parameters', i );
 
link, link_alias = utilities.select_one ( args, cfg.aliases[list_name .. '-Link'], 'err_redundant_parameters', i );
 
mask = utilities.select_one ( args, cfg.aliases[list_name .. '-Mask'], 'err_redundant_parameters', i );
 
mask = utilities.select_one ( args, cfg.aliases[list_name .. '-Mask'], 'err_redundant_parameters', i );
 
+
 +
if last then -- error check |lastn= alias for unknown interwiki link prefix; done here because this is where we have the parameter name
 +
local project, language = interwiki_prefixen_get (last, true); -- true because we expect interwiki links in |lastn= to be wikilinked
 +
if nil == project and nil == language then -- when both are nil
 +
utilities.set_message ('err_bad_paramlink', last_alias); -- not known, emit an error message -- TODO: err_bad_interwiki?
 +
last = utilities.remove_wiki_link (last); -- remove wikilink markup; show display value only
 +
end
 +
end
 +
 +
if link then -- error check |linkn= alias for unknown interwiki link prefix
 +
local project, language = interwiki_prefixen_get (link, false); -- false because wiki links in |author-linkn= is an error
 +
if nil == project and nil == language then -- when both are nil
 +
utilities.set_message ('err_bad_paramlink', link_alias); -- not known, emit an error message -- TODO: err_bad_interwiki?
 +
link = nil; -- unset so we don't link
 +
link_alias = nil;
 +
end
 +
end
 +
 
last, etal = name_has_etal (last, etal, false, last_alias); -- find and remove variations on et al.
 
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_alias); -- find and remove variations on et al.
 
first, etal = name_has_etal (first, etal, false, first_alias); -- find and remove variations on et al.
Line 1,633: Line 1,740:  
if cfg.this_wiki_code ~= lang_subtag then -- when the language is not the same as this wiki's language
 
if cfg.this_wiki_code ~= lang_subtag then -- when the language is not the same as this wiki's language
 
if 2 == lang_subtag:len() then -- and is a two-character tag
 
if 2 == lang_subtag:len() then -- and is a two-character tag
-- utilities.add_prop_cat ('foreign-lang-source', {name, lang_subtag}, lang_subtag); -- categorize it; tag appended to allow for multiple language categorization
   
utilities.add_prop_cat ('foreign-lang-source', {name, tag}, lang_subtag); -- categorize it; tag appended to allow for multiple language categorization
 
utilities.add_prop_cat ('foreign-lang-source', {name, tag}, lang_subtag); -- categorize it; tag appended to allow for multiple language categorization
 
else -- or is a recognized language (but has a three-character tag)
 
else -- or is a recognized language (but has a three-character tag)
Line 1,682: Line 1,788:  
return cfg.presentation['sep_' .. mode], postscript;
 
return cfg.presentation['sep_' .. mode], postscript;
 
end
 
end
 +
    
--[[--------------------------< S E T _ S T Y L E >-----------------------------
 
--[[--------------------------< S E T _ S T Y L E >-----------------------------
Line 2,089: Line 2,196:       −
--[[-------------------------< F O R M A T _ V O L U M E _ I S S U E >----------------------------------------
+
--[[-------------------------< F O R M A T _ V O L U M E _ I S S U E >-----------------------------------------
   −
returns the concatenation of the formatted volume and issue parameters as a single string; or formatted volume
+
returns the concatenation of the formatted volume and issue (or journal article number) parameters as a single
or formatted issue, or an empty string if neither are set.
+
string; or formatted volume or formatted issue, or an empty string if neither are set.
    
]]
 
]]
 
 
local function format_volume_issue (volume, issue, cite_class, origin, sepc, lower)
+
local function format_volume_issue (volume, issue, article, cite_class, origin, sepc, lower)
if not utilities.is_set (volume) and not utilities.is_set (issue) then
+
if not utilities.is_set (volume) and not utilities.is_set (issue) and not utilities.is_set (article) then
 
return '';
 
return '';
 
end
 
end
Line 2,113: Line 2,220:  
if is_journal then -- journal-style formatting
 
if is_journal then -- journal-style formatting
 
local vol = '';
 
local vol = '';
+
 
 
if utilities.is_set (volume) then
 
if utilities.is_set (volume) then
 
if is_numeric_vol then -- |volume= value all digits or all uppercase Roman numerals?
 
if is_numeric_vol then -- |volume= value all digits or all uppercase Roman numerals?
Line 2,123: Line 2,230:  
end
 
end
 
end
 
end
if utilities.is_set (issue) then
+
vol = vol .. (utilities.is_set (issue) and utilities.substitute (cfg.messages['j-issue'], issue) or '')
return vol .. utilities.substitute (cfg.messages['j-issue'], issue);
+
vol = vol .. (utilities.is_set (article) and utilities.substitute (cfg.messages['j-article-num'], article) or '')
end
   
return vol;
 
return vol;
 
end
 
end
Line 2,131: Line 2,237:  
if 'podcast' == cite_class and utilities.is_set (issue) then
 
if 'podcast' == cite_class and utilities.is_set (issue) then
 
return wrap_msg ('issue', {sepc, issue}, lower);
 
return wrap_msg ('issue', {sepc, issue}, lower);
 +
end
 +
 +
if 'conference' == cite_class and utilities.is_set (article) then -- |article-number= supported only in journal and conference cites
 +
if utilities.is_set (volume) and utilities.is_set (article) then -- both volume and article number
 +
return wrap_msg ('vol-art', {sepc, utilities.hyphen_to_dash (volume), article}, lower);
 +
elseif utilities.is_set (article) then -- article number alone; when volume alone, handled below
 +
return wrap_msg ('art', {sepc, article}, lower);
 +
end
 
end
 
end
   Line 2,504: Line 2,618:  
if 'mailinglist' == config.CitationClass then -- special case for {{cite mailing list}}
 
if 'mailinglist' == config.CitationClass then -- special case for {{cite mailing list}}
 
if utilities.is_set (Periodical) and utilities.is_set (A ['MailingList']) then -- both set emit an error TODO: make a function for this and similar?
 
if utilities.is_set (Periodical) and utilities.is_set (A ['MailingList']) then -- both set emit an error TODO: make a function for this and similar?
utilities.set_message ('err_redundant_parameters', {utilities.wrap_style ('parameter', Periodical_origin) .. ' and ' .. utilities.wrap_style ('parameter', 'mailinglist')});
+
utilities.set_message ('err_redundant_parameters', {utilities.wrap_style ('parameter', Periodical_origin) .. cfg.presentation['sep_list_pair'] .. utilities.wrap_style ('parameter', 'mailinglist')});
 
end
 
end
   Line 2,552: Line 2,666:  
end
 
end
 
end
 
end
 +
 +
local ArticleNumber;
 +
 +
if utilities.in_array (config.CitationClass, {'journal', 'conference'}) or ('citation' == config.CitationClass and utilities.is_set (Periodical) and 'journal' == Periodical_origin) then
 +
ArticleNumber = A['ArticleNumber'];
 +
end
 +
 
extra_text_in_vol_iss_check (Issue, A:ORIGIN ('Issue'), 'i');
 
extra_text_in_vol_iss_check (Issue, A:ORIGIN ('Issue'), 'i');
   Line 2,557: Line 2,678:  
local Pages;
 
local Pages;
 
local At;
 
local At;
if not utilities.in_array (config.CitationClass, cfg.templates_not_using_page) then
+
local QuotePage;
 +
local QuotePages;
 +
if not utilities.in_array (config.CitationClass, cfg.templates_not_using_page) then -- TODO: rewrite to emit ignored parameter error message?
 
Page = A['Page'];
 
Page = A['Page'];
 
Pages = utilities.hyphen_to_dash (A['Pages']);
 
Pages = utilities.hyphen_to_dash (A['Pages']);
 
At = A['At'];
 
At = A['At'];
 +
QuotePage = A['QuotePage'];
 +
QuotePages = utilities.hyphen_to_dash (A['QuotePages']);
 
end
 
end
   Line 2,614: Line 2,739:  
-- 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
 
if not utilities.is_set (no_tracking_cats) then -- ignore if we are already not going to categorize this page
 
if not utilities.is_set (no_tracking_cats) then -- ignore if we are already not going to categorize this page
if utilities.in_array (this_page.nsText, cfg.uncategorized_namespaces) then
+
if cfg.uncategorized_namespaces[this_page.namespace] then -- is this page's namespace id one of the uncategorized namespace ids?
 
no_tracking_cats = "true"; -- set no_tracking_cats
 
no_tracking_cats = "true"; -- set no_tracking_cats
 
end
 
end
Line 2,679: Line 2,804:  
if ('encyclopaedia' == config.CitationClass) or ('citation' == config.CitationClass and utilities.is_set (Encyclopedia)) then
 
if ('encyclopaedia' == config.CitationClass) or ('citation' == config.CitationClass and utilities.is_set (Encyclopedia)) then
 
if utilities.is_set (Periodical) and utilities.is_set (Encyclopedia) then -- when both set emit an error TODO: make a function for this and similar?
 
if utilities.is_set (Periodical) and utilities.is_set (Encyclopedia) then -- when both set emit an error TODO: make a function for this and similar?
utilities.set_message ('err_redundant_parameters', {utilities.wrap_style ('parameter', A:ORIGIN ('Encyclopedia')) .. ' and ' .. utilities.wrap_style ('parameter', Periodical_origin)});
+
utilities.set_message ('err_redundant_parameters', {utilities.wrap_style ('parameter', A:ORIGIN ('Encyclopedia')) .. cfg.presentation['sep_list_pair'] .. utilities.wrap_style ('parameter', Periodical_origin)});
 
end
 
end
   Line 2,725: Line 2,850:  
ID = A['Number']; -- yes, use it
 
ID = A['Number']; -- yes, use it
 
else -- ID has a value so emit error message
 
else -- ID has a value so emit error message
utilities.set_message ('err_redundant_parameters', {utilities.wrap_style ('parameter', 'id') .. ' and ' .. utilities.wrap_style ('parameter', 'number')});
+
utilities.set_message ('err_redundant_parameters', {utilities.wrap_style ('parameter', 'id') .. cfg.presentation['sep_list_pair'] .. utilities.wrap_style ('parameter', 'number')});
 
end
 
end
 
end
 
end
Line 2,771: Line 2,896:  
if config.CitationClass == "map" then
 
if config.CitationClass == "map" then
 
if utilities.is_set (Chapter) then --TODO: make a function for this and similar?
 
if utilities.is_set (Chapter) then --TODO: make a function for this and similar?
utilities.set_message ('err_redundant_parameters', {utilities.wrap_style ('parameter', 'map') .. ' and ' .. utilities.wrap_style ('parameter', Chapter_origin)}); -- add error message
+
utilities.set_message ('err_redundant_parameters', {utilities.wrap_style ('parameter', 'map') .. cfg.presentation['sep_list_pair'] .. utilities.wrap_style ('parameter', Chapter_origin)}); -- add error message
 
end
 
end
 
Chapter = A['Map'];
 
Chapter = A['Map'];
Line 2,814: Line 2,939:     
if utilities.is_set (Season) and utilities.is_set (SeriesNumber) then -- these are mutually exclusive so if both are set TODO: make a function for this and similar?
 
if utilities.is_set (Season) and utilities.is_set (SeriesNumber) then -- these are mutually exclusive so if both are set TODO: make a function for this and similar?
utilities.set_message ('err_redundant_parameters', {utilities.wrap_style ('parameter', 'season') .. ' and ' .. utilities.wrap_style ('parameter', 'seriesno')}); -- add error message
+
utilities.set_message ('err_redundant_parameters', {utilities.wrap_style ('parameter', 'season') .. cfg.presentation['sep_list_pair'] .. utilities.wrap_style ('parameter', 'seriesno')}); -- add error message
 
SeriesNumber = ''; -- unset; prefer |season= over |seriesno=
 
SeriesNumber = ''; -- unset; prefer |season= over |seriesno=
 
end
 
end
Line 2,994: Line 3,119:     
-- Account for the oddities that are {{cite arxiv}}, {{cite biorxiv}}, {{cite citeseerx}}, {{cite ssrn}}, before generation of COinS data.
 
-- Account for the oddities that are {{cite arxiv}}, {{cite biorxiv}}, {{cite citeseerx}}, {{cite ssrn}}, before generation of COinS data.
if utilities.in_array (config.CitationClass, whitelist.preprint_template_list) then
+
if utilities.in_array (config.CitationClass, whitelist.preprint_template_list) then -- |arxiv= or |eprint= required for cite arxiv; |biorxiv=, |citeseerx=, |ssrn= required for their templates
if not utilities.is_set (ID_list_coins[config.CitationClass:upper()]) then -- |arxiv= or |eprint= required for cite arxiv; |biorxiv= & |citeseerx= required for their templates
+
if not (args[cfg.id_handlers[config.CitationClass:upper()].parameters[1]] or -- can't use ID_list_coins k/v table here because invalid parameters omitted
utilities.set_message ('err_' .. config.CitationClass .. '_missing'); -- add error message
+
args[cfg.id_handlers[config.CitationClass:upper()].parameters[2]]) then -- which causes unexpected parameter missing error message
 +
utilities.set_message ('err_' .. config.CitationClass .. '_missing'); -- add error message
 
end
 
end
   Line 3,063: Line 3,189:  
end
 
end
 
 
local QuotePage = A['QuotePage'];
  −
local QuotePages = utilities.hyphen_to_dash (A['QuotePages']);
  −
   
-- this is the function call to COinS()
 
-- this is the function call to COinS()
 
local OCinSoutput = metadata.COinS({
 
local OCinSoutput = metadata.COinS({
Line 3,081: Line 3,204:  
['Volume'] = Volume,
 
['Volume'] = Volume,
 
['Issue'] = Issue,
 
['Issue'] = Issue,
 +
['ArticleNumber'] = ArticleNumber,
 
['Pages'] = coins_pages or metadata.get_coins_pages (first_set ({Sheet, Sheets, Page, Pages, At, QuotePage, QuotePages}, 7)), -- pages stripped of external links
 
['Pages'] = coins_pages or metadata.get_coins_pages (first_set ({Sheet, Sheets, Page, Pages, At, QuotePage, QuotePages}, 7)), -- pages stripped of external links
 
['Edition'] = Edition,
 
['Edition'] = Edition,
Line 3,378: Line 3,502:  
if utilities.is_set (Minutes) then
 
if utilities.is_set (Minutes) then
 
if utilities.is_set (Time) then --TODO: make a function for this and similar?
 
if utilities.is_set (Time) then --TODO: make a function for this and similar?
utilities.set_message ('err_redundant_parameters', {utilities.wrap_style ('parameter', 'minutes') .. ' and ' .. utilities.wrap_style ('parameter', 'time')});
+
utilities.set_message ('err_redundant_parameters', {utilities.wrap_style ('parameter', 'minutes') .. cfg.presentation['sep_list_pair'] .. utilities.wrap_style ('parameter', 'time')});
 
end
 
end
 
Position = " " .. Minutes .. " " .. cfg.messages['minutes'];
 
Position = " " .. Minutes .. " " .. cfg.messages['minutes'];
Line 3,450: Line 3,574:  
local Agency = A['Agency'];
 
local Agency = A['Agency'];
 
Agency = utilities.is_set (Agency) and wrap_msg ('agency', {sepc, Agency}) or "";
 
Agency = utilities.is_set (Agency) and wrap_msg ('agency', {sepc, Agency}) or "";
Volume = format_volume_issue (Volume, Issue, config.CitationClass, Periodical_origin, sepc, use_lowercase);
+
Volume = format_volume_issue (Volume, Issue, ArticleNumber, config.CitationClass, Periodical_origin, sepc, use_lowercase);
    
if utilities.is_set (AccessDate) then
 
if utilities.is_set (AccessDate) then
Line 3,486: Line 3,610:  
end
 
end
 
end
 
end
 
+
 +
Quote = kern_quotes (Quote); -- kern if needed
 
Quote = utilities.wrap_style ('quoted-text', Quote ); -- wrap in <q>...</q> tags
 
Quote = utilities.wrap_style ('quoted-text', Quote ); -- wrap in <q>...</q> tags
 
 
Line 3,684: Line 3,809:  
 
 
if utilities.in_array (config.CitationClass, {"journal", "citation"}) and utilities.is_set (Periodical) then
 
if utilities.in_array (config.CitationClass, {"journal", "citation"}) and utilities.is_set (Periodical) then
 +
if not (utilities.is_set (Authors) or utilities.is_set (Editors)) then
 +
Others = Others:gsub ('^' .. sepc .. ' ', ''); -- when no authors and no editors, strip leading sepc and space
 +
end
 
if utilities.is_set (Others) then Others = safe_join ({Others, sepc .. " "}, sepc) end -- add terminal punctuation & space; check for dup sepc; TODO why do we need to do this here?
 
if utilities.is_set (Others) then Others = safe_join ({Others, sepc .. " "}, sepc) end -- add terminal punctuation & space; check for dup sepc; TODO why do we need to do this here?
 
tcommon = safe_join( {Others, Title, TitleNote, Conference, Periodical, Format, TitleType, Series, Language, Edition, Publisher, Agency, Volume}, sepc );
 
tcommon = safe_join( {Others, Title, TitleNote, Conference, Periodical, Format, TitleType, Series, Language, Edition, Publisher, Agency, Volume}, sepc );
Line 3,779: Line 3,907:  
if utilities.is_set (Date) then
 
if utilities.is_set (Date) then
 
if EditorCount <= 1 then
 
if EditorCount <= 1 then
Editors = Editors .. ", " .. cfg.messages['editor'];
+
Editors = Editors .. cfg.presentation['sep_name'] .. cfg.messages['editor'];
 
else
 
else
Editors = Editors .. ", " .. cfg.messages['editors'];
+
Editors = Editors .. cfg.presentation['sep_name'] .. cfg.messages['editors'];
 
end
 
end
 
else
 
else
Line 4,076: Line 4,204:  
local function citation(frame)
 
local function citation(frame)
 
Frame = frame; -- save a copy in case we need to display an error message in preview mode
 
Frame = frame; -- save a copy in case we need to display an error message in preview mode
local sandbox = '/sandbox' -- i18n: replace this rvalue with the name that your wiki uses to identify sandbox subpages
+
 
 +
local config = {}; -- table to store parameters from the module {{#invoke:}}
 +
for k, v in pairs( frame.args ) do -- get parameters from the {{#invoke}} frame
 +
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
 +
-- i18n: set the name that your wiki uses to identify sandbox subpages from sandbox template invoke (or can be set here)
 +
local sandbox = ((config.SandboxPath and '' ~= config.SandboxPath) and config.SandboxPath) or '/sandbox'; -- sandbox path from {{#invoke:Citation/CS1/sandbox|citation|SandboxPath=/...}}
 
is_sandbox = nil ~= string.find (frame:getTitle(), sandbox, 1, true); -- is this invoke the sandbox module?
 
is_sandbox = nil ~= string.find (frame:getTitle(), sandbox, 1, true); -- is this invoke the sandbox module?
 
sandbox = is_sandbox and sandbox or ''; -- use i18n sandbox to load sandbox modules when this module is the sandox; live modules else
 
sandbox = is_sandbox and sandbox or ''; -- use i18n sandbox to load sandbox modules when this module is the sandox; live modules else
Line 4,103: Line 4,238:  
local suggestions = {}; -- table where we store suggestions if we need to loadData them
 
local suggestions = {}; -- table where we store suggestions if we need to loadData them
 
local error_text; -- used as a flag
 
local error_text; -- used as a flag
  −
local config = {}; -- table to store parameters from the module {{#invoke:}}
  −
for k, v in pairs( frame.args ) do -- get parameters from the {{#invoke}} frame
  −
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
      
local capture; -- the single supported capture when matching unknown parameters using patterns
 
local capture; -- the single supported capture when matching unknown parameters using patterns
Line 4,127: Line 4,256:  
else
 
else
 
if nil == suggestions.suggestions then -- if this table is nil then we need to load it
 
if nil == suggestions.suggestions then -- if this table is nil then we need to load it
if is_sandbox then -- did the {{#invoke:}} use sandbox version?
+
suggestions = mw.loadData ('Module:Citation/CS1/Suggestions' .. sandbox); --load sandbox version of suggestion module when {{#invoke:Citation/CS1/sandbox|...}}; live module else
suggestions = mw.loadData( 'Module:Citation/CS1/Suggestions/sandbox' ); -- use the sandbox version
  −
else
  −
suggestions = mw.loadData( 'Module:Citation/CS1/Suggestions' ); -- use the live version
  −
end
   
end
 
end
 
for pattern, param in pairs (suggestions.patterns) do -- loop through the patterns to see if we can suggest a proper parameter
 
for pattern, param in pairs (suggestions.patterns) do -- loop through the patterns to see if we can suggest a proper parameter