]]
local dates, year_date_check, reformat_dates, date_hyphen_to_dash , -- functions in Module:Citation/CS1/Date_validation date_name_xlate
local is_set, in_array, substitute, error_comment, set_error, select_one, -- functions in Module:Citation/CS1/Utilities
add_maint_cat, wrap_style, safe_for_italics, remove_wiki_linkis_wikilink, make_wikilink;
local z ={}; -- tables in Module:Citation/CS1/Utilities
end
end
--[[--------------------------< A D D _ P R O P _ C A T >--------------------------------------------------------
Adds a category to z.properties_cats using names from the configuration file with additional text if any.
foreign_lang_source and foreign_lang_source_2 keys have a language code appended to them so that multiple languages
may be categorized but multiples of the same language are not categorized.
added_prop_cats is a table declared in page scope variables above
if not added_prop_cats [key] then
added_prop_cats [key] = true; -- note that we've added this category
key = key:gsub ('(foreign_lang_source_?2?)%a%a%a?', '%1'); -- strip lang code from keyname
table.insert( z.properties_cats, substitute (cfg.prop_cats [key], arguments)); -- make name then add to table
end
end
--[[--------------------------< A D D _ V A N C _ E R R O R >----------------------------------------------------
the first character of the whole domain name including subdomains must be a letter or a digit
internationalized domain name (ascii characters with .xn-- ASCII Compatible Encoding (ACE) prefix xn-- in the tld) see https://tools.ietf.org/html/rfc3490
single-letter/digit second-level domains in the .org TLDand .cash TLDs
q, x, and z SL domains in the .com TLD
i and q SL domains in the .net TLD
elseif domain:match ('%f[%a%d][%a%d][%a%d%-]+[%a%d]%.xn%-%-[%a%d]+$') then -- internationalized domain name with ACE prefix
return true;
elseif domain:match ('%f[%a%d][%a%d]%.cash$') then -- one character/digit .cash hostname return true; elseif domain:match ('%f[%a%d][%a%d]%.org$') then -- one character /digit .org hostname
return true;
elseif domain:match ('%f[%a][qxz]%.com$') then -- assigned one character .com hostname (x.com times out 2015-12-10)
return not is_url (scheme, domain); -- return true if value DOES NOT appear to be a valid url
end
--[[--------------------------< L I N K _ T I T L E _ O K >---------------------------------------------------
['\n'] = ' ' } );
end
--[[--------------------------< E X T E R N A L _ L I N K >----------------------------------------------------
if is_set (access) then -- access level (subscription, registration, limited)
local label_head label = ''safe_for_url (label); local label_tail; local markup = ''; -- can't start a span inside italic markup replace square brackets and end it outside the italic markupnewlines
label base_url = safe_for_url (label); -- replace square brackets and newlines (is this necessary? already done above?) if label:match ("(table.*)%s+concat (.+)('''?)$") then -- for italicized titles (cite book, etc) label_head, label_tail, markup = label:match ("(.*)%s+(.+)('''?)$"); -- split the label at the right-most space; separate the markup elseif label:match ("(.*)%s+(.+)$") then -- for upright titles (journal, news, magazine, etc) label_head, label_tail = label:match ("(.*)%s+(.+)$"); -- split the label at the right-most space; no markup elseif label:match ("(.+)('''?)$") then -- single word label assemble external link with markup label_tail, markup = label:match ("(.+)('''?)$"); -- save label text as label tail; separate the markup else label_tail = label; end base_url = table.concat (access signal
{
'<span class="plainlinks">[', -- opening cssand url markup
URL, -- the url
' ', -- the required space
label_head, -- all but the last word of the label ' <span class="nowrap">', -- nowrap css for the last word and the signal icon label_tail, -- last (or only) word of the label inside the span
'<span style="padding-left:0.15em">', -- signal spacing css
cfg.presentation[access], -- the appropriate icon
'</span></span>', -- close signal spacing and nowrap spans markup, -- insert italic markup if anyspan ']</span>' -- close the url markup and plain links span
});
else
end
--[[--------------------------< K E R N _ Q U O T E S >--------------------------------------------------------
--[=[-------------------------< K E R N _ Q U O T E S >-------------------------------------------------------- Apply kerning to open the space between the quote mark provided by the Module and a leading or trailing quote mark contained in a |title= or |chapter= parameter's value.
This function will positive kern either single or double quotes:
"'Unkerned title with leading and trailing single quote marks'"
Double single quotes (italic or bold wikimarkup) are not kerned.
Replaces unicode quotemarks in plain text or in the label portion of a [[L|D]] style wikilink with typewriter quote marks regardless of the need for kerning. Unicode quote marks are not replaced in simple [[D]] wikilinks.
Call this function for chapter titles, for website titles, etc; not for book titles.
]=]
local function kern_quotes (str)
local cap='';
local cap2='';
-- TODO: move this elswhere so that all title-holding elements get these quote marks replaced? local wl_type, label, link; strwl_type, label, link = mw.ustring.gsub is_wikilink (str, '[“”]', '\"'); -- replace “” wl_type is: 0, no wl (U+201C & U+201Dtext in label variable) with " (typewriter double quote mark) str= mw.ustring.gsub (str; 1, '[‘’[D]']; 2, '\''); -- replace ‘’ (U+2018 & U+2019) with ' (typewriter single quote mark)[[L|D]]
cap, cap2 if 1 = str:= wl_type then -- [[D]] simple wikilink with or without quote marks if mw.ustring.match (str, '%[%[[\"^(“”\'‘’].+[\"“”\'‘’]%]%]')then -- leading and trailing quote marks str = substitute (cfg.presentation['kern-wl-both'], str); elseif mw.ustring.match (str, '%[%[[^\"“”\'‘’].+%]%]')"); then -- match leading double or single quote but not double single quotesmarks if is_set str = substitute (capcfg.presentation['kern-wl-left'], str) then; elseif mw.ustring.match (str, '%[%[.+[\"“”\'‘’]%]%]') then -- trailing quote marks str = substitute (cfg.presentation['kern-leftwl-right'], {cap, cap2}str); end
else -- plain text or [[L|D]]; text in label variable label= mw.ustring.gsub (label, '[“”]', '\"'); -- replace “” (U+201C & U+201D) with " (typewriter double quote mark) label= mw.ustring.gsub (label, '[‘’]', '\''); -- replace ‘’ (U+2018 & U+2019) with ' (typewriter single quote mark) cap, cap2 = str:mw.ustring.match (label, "^([\"\'])([^\'].+)"); -- match leading double or single quote but not doubled single quotes (italic markup) if is_set (cap) then label = substitute (cfg.presentation['kern-left'], {cap, cap2}); end cap, cap2 = mw.ustring.match (label, "^(.+[^\'])([\"\'])$") -- match trailing double or single quote but not doubled single quotes (italic markup) if is_set (cap) then str label = substitute (cfg.presentation['kern-right'], {cap, cap2}); end if 2 == wl_type then str = make_wikilink (link, label); -- reassemble the wikilink else str = label; end
end
return str;
end
--[[--------------------------< F O R M A T _ S C R I P T _ V A L U E >----------------------------------------
return script_value;
end
--[[--------------------------< S C R I P T _ C O N C A T E N A T E >------------------------------------------
]]
local function format_chapter_title (scriptchapter, chapter, transchapter, chapterurl, chapter_url_source, no_quotes, access)
local chapter_error = '';
else
if false == no_quotes then
chapter = kern_quotes (chapter); -- if necessary, separate chapter title's leading and trailing quote marks from Module provided quote marks
chapter = wrap_style ('quoted-title', chapter);
end
if is_set (chapterurl) then
chapter = external_link (chapterurl, chapter, chapter_url_source, nilaccess); -- adds bare_url_missing_title error if appropriate
end
return chapter .. chapter_error;
end
--[[--------------------------< H A S _ I N V I S I B L E _ C H A R S >----------------------------------------
local pattern=cfg.invisible_chars[i][2] -- the pattern used to find it
position, dummy, capture = mw.ustring.find (v, pattern) -- see if the parameter value contains characters that match the pattern
if position and (char == 'zero width joiner') then -- if we found a zero width joiner character
if mw.ustring.find (v, cfg.indic_script) then -- its ok if one of the indic scripts
position = nil; -- unset position
end
end
if position then
});
end
--[[--------------------------< V A L I D A T E >--------------------------------------------------------------
]]
--local function validate( name )
local function validate( name, cite_class )
local name = tostring( name );
local state;
if in_array (cite_class, {'arxiv', 'biorxiv', 'citeseerx'}) then -- limited parameter sets allowed for these templates
state = whitelist.limited_basic_arguments[ name ];
if true == state then return true; end -- valid actively supported parameter
return date;
end
--[[--------------------------< S E T _ T I T L E T Y P E >----------------------------------------------------
elseif end_chr == "]" then -- if it might be wikimarkup
if str:sub(-3,-1) == duplicate_char .. "]]" then -- if last three chars of str are sepc]] wikilink
trim = true;
elseif str:sub(-3,-1) == duplicate_char .. '"]' then -- if last three chars of str are sepc"] quoted external link
trim = true;
elseif str:sub(-2,-1) == duplicate_char .. "]" then -- if last two chars of str are sepc] external link
return false;
end
--[[--------------------------< I S _ G O O D _ V A N C _ N A M E >--------------------------------------------
return true;
end
--[[--------------------------< R E D U C E _ T O _ I N I T I A L S >------------------------------------------
return table.concat(initials) -- Vancouver format does not include spaces.
end
--[[--------------------------< L I S T _ P E O P L E >-------------------------------------------------------
sep = ','; -- name-list separator between authors is a comma
namesep = ' '; -- last/first separator is a space
elseif 'mla' == control.mode then
sep = ','; -- name-list separator between authors is a comma
namesep = ', ' -- last/first separator is <comma><space>
else
sep = ';' -- name-list separator between authors is a semicolon
local first = person.first
if is_set(first) then
if 'mla' ( "vanc" == control.mode format ) then if i == 1 then -- for mlaif vancouver format one = one :gsub ('%.', ''); -- remove periods from surnames (http://www. namesep ncbi.nlm. nih.gov/books/NBK7271/box/A35029/) if not person.corporate and is_good_vanc_name (one, first; ) then -- first and name last, first else -- is all other namesLatin characters; corporate authors not tested one first = reduce_to_initials(first .. ' ' .. one; ) -- attempt to convert first lastname(s) to initials
end
else
if ( "vanc" == format ) then -- if vancouver format
one = one:gsub ('%.', ''); -- remove periods from surnames (http://www.ncbi.nlm.nih.gov/books/NBK7271/box/A35029/)
if not person.corporate and is_good_vanc_name (one, first) then -- and name is all Latin characters; corporate authors not tested
first = reduce_to_initials(first) -- attempt to convert first name(s) to initials
end
end
one = one .. namesep .. first;
end
one = one .. namesep .. first;
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
if count > 0 then
if count > 1 and is_set(lastauthoramp) and not etal then
if 'mla' == control.mode then text[#text-2] = ", and "; -- replace last separator with ', and ' text else text[#text-2] = " & "; -- replace last separator with ampersand text end
end
text[#text] = nil; -- erase the last separator
return result, count
end
--[[--------------------------< A N C H O R _ I D >------------------------------------------------------------
'^[%(%[]?%s*[Ee][Dd][Ii][Tt][Oo][Rr][Ss]?%A', -- (editor or (editors: also sq brackets, case insensitive, optional brackets, 's'
'^[%(%[]?%s*[Ee][Dd][Ii][Tt][Ee][Dd]%A', -- (edited: also sq brackets, case insensitive, optional brackets
}
return names, etal; -- all done, return our list of names
end
--[[--------------------------< G E T _ I S O 6 3 9 _ C O D E >------------------------------------------------
return the original language name string.
mw.language.fetchLanguageNames(<local wiki language>, 'all') return returns a list of languages that in some cases may include
extensions. For example, code 'cbk-zam' and its associated name 'Chavacano de Zamboanga' (MediaWiki does not support
code 'cbk' or name 'Chavacano'. Most (all?) of these languages are not used a 'language' codes per se, rather theyare used as sub-domain names: cbk-zam.wikipedia.org. These names can be found (for the time being) athttps://phabricator.wikimedia.org/diffusion/ECLD/browse/master/LocalNames/LocalNamesEn.php
Names but that are included in the list will be found if that name is provided in the |language= parameter. For example,
local function get_iso639_code (lang, this_wiki_code)
if local remap = { ['bangla' ] == lang:lower() then {'Bengali', 'bn'}, -- special case related to Wikimedia MediaWiki returns Bangla (the endonym) but we want Bengali (the exonym); here we remap of code ['bengali'] = {'Bengali', 'bn' at mw:Extension:CLDR}, -- MediaWiki doesn't use exonym so here we provide correct language name and 639-1 code return ['Bengalibihari'] = {'Bihari', 'bnbh'}, -- MediaWiki replace 'Bihari' with 'Bhojpuri' so 'Bihari' cannot be found ['bhojpuri'] = {'Bhojpuri', 'bho'}, -- MediaWiki uses 'bh' as a subdomain name for Bhojpuri wWikipedia: bh.wikipedia.org } if remap[lang:lower()] then return remap[lang:lower()][1], remap[lang:lower()][2]; -- make sure rendered version is properly capitalizedfor this language 'name', return a possibly new name and appropriate code
end
local this_wiki_code = this_wiki:getCode() -- get this wiki's language code
local this_wiki_name = mw.language.fetchLanguageName(this_wiki_code, this_wiki_code); -- get this wiki's language name
local remap = {
['bh'] = 'Bihari', -- MediaWiki uses 'bh' as a subdomain name for Bhojpuri wWikipedia: bh.wikipedia.org
['bn'] = 'Bengali', -- MediaWiki returns Bangla
}
names_table = mw.text.split (lang, '%s*,%s*'); -- names should be a comma separated list
if is_set (code) then -- only 2- or 3-character codes
if 'bn' =name = remap[code then ] or name = 'Bengali' end; -- override wikimedia when code is 'bn'they misuse language codes/names
if this_wiki_code ~= code then -- when the language is not the same as this wiki's language
if 2 == code:len() then -- and is a two-character code
add_prop_cat ('foreign_lang_source'.. code, {name, code}) -- categorize it
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
end
end
]]
end
--[[--------------------------< S E T _ C S 1 _ S T Y L E >----------------------------------------------------
return '.', ps; -- separator is a full stop
end
--[[--------------------------< S E T _ C S 2 _ S T Y L E >----------------------------------------------------
return ',', ps, ref; -- separator is a comma
end
--[[--------------------------< G E T _ S E T T I N G S _ F R O M _ C I T E _ C L A S S >----------------------
return sep, ps, ref -- return them all
end
--[[--------------------------< S E T _ S T Y L E >------------------------------------------------------------
sep, ps, ref = set_cs2_style (ps, ref);
elseif 'cs1' == mode then -- if this template is to be rendered in CS1 (cite xxx) style
sep, ps = set_cs1_style (ps);
elseif 'mla' == mode then -- if this template is to be rendered in mla style use cs1 for bot cs1 & cs2 templates
sep, ps = set_cs1_style (ps);
else -- anything but cs1 or cs2
return sep, ps, ref
end
--[=[-------------------------< I S _ P D F >------------------------------------------------------------------
applying the pdf icon to external links.
returns true if file extension is one of the recognized extensionextensions, else false
]=]
local function is_pdf (url)
return url:match ('%.pdf$') or url:match ('%.PDF$') or url:match ('%.pdf[%?#]?') or url:match ('%.PDF[%?#]?');
end
--[[--------------------------< S T Y L E _ F O R M A T >------------------------------------------------------
local function style_format (format, url, fmt_param, url_param)
if is_set (format) then
format = wrap_style ('format', format); -- add leading space, parenthasesparentheses, resize
if not is_set (url) then
format = format .. set_error( 'format_missing_url', {fmt_param, url_param} ); -- add an error message
return format;
end
--[[--------------------------< G E T _ D I S P L A Y _ A U T H O R S _ E D I T O R S >------------------------
return max, etal;
end
--[[--------------------------< E X T R A _ T E X T _ I N _ P A G E _ C H E C K >------------------------------
local function extra_text_in_page_check (page)
-- local good_pattern = '^P[^%.P%l]';
local good_pattern = '^P[^%.Pp]'; -- ok to begin with uppercase P: P7 (pg 7 of section P) but not p123 (page 123) TODO: add Gg for PG or Pg?
-- local bad_pattern = '^[Pp][Pp]';
local bad_pattern = '^[Pp]?[Pp]%.?[ %d]';
add_maint_cat ('extra_text');
end
-- if Page:match ('^[Pp]?[Pp]%.?[ %d]') or Page:match ('^[Pp]ages?[ %d]') or
-- Pages:match ('^[Pp]?[Pp]%.?[ %d]') or Pages:match ('^[Pp]ages?[ %d]') then
-- add_maint_cat ('extra_text');
-- end
end
--[[--------------------------< G E T _ V _ N A M E _ T A B L E >----------------------------------------------
--[=[-------------------------< G E T _ V _ N A M E _ T A B L E >---------------------------------------------- split apart a |vautthorsvauthors= or |veditors= parameter. This function allows for corporate names, wrapped in doubled
parentheses to also have commas; in the old version of the code, the doubled parnetheses were included in the
rendered citation and in the metadata. Individual author names may be wikilinked
|vauthors=Jones AB, [[E. B. White|White EB]], ((Black, Brown, and Co.))
This code is experimental and may not be retained.]=]
]]local function get_v_name_table (vparam, output_table, output_link_table)
local name_table = mw.text.split(vparam, "%s*,%s*"); -- names are separated by commas
local wl_type, label, link; -- wl_type not used here; just a place holder
local i = 1;
end
table.insert (output_table, name); -- and add corporate name to the output table
table.insert (output_link_table, ''); -- no wikilink
else
wl_type, label, link = is_wikilink (name_table[i]); -- wl_type is: 0, no wl (text in label variable); 1, [[D]]; 2, [[L|D]] table.insert (output_table, name_tablelabel); -- add this name if 1 == wl_type then table.insert (output_link_table, label); -- simple wikilink [i[D]] else table.insert (output_link_table, link); -- no wikilink or [[L|D]]; add this name link if there is one, else empty string end
end
i = i+1;
return output_table;
end
--[[--------------------------< P A R S E _ V A U T H O R S _ V E D I T O R S >--------------------------------
local names = {}; -- table of names assembled from |vauthors=, |author-maskn=, |author-linkn=
local v_name_table = {};
local v_link_table = {}; -- when name is wikilinked, targets go in this table
local etal = false; -- return value set to true when we find some form of et al. vauthors parameter
local last, first, link, mask, suffix;
vparam, etal = name_has_etal (vparam, etal, true); -- find and remove variations on et al. do not categorize (do it here because et al. might have a period)
if vparam:find ('%[%[') or vparam:find ('%]%]') then -- no wikilinking vauthors names add_vanc_error ('wikilink'); end v_name_table = get_v_name_table (vparam, v_name_table, v_link_table); -- names are separated by commas
for i, v_name in ipairs(v_name_table) do
end
end
-- this from extract_names () link = select_one( args, cfg.aliases[list_name .. '-Link'], 'redundant_parameters', i )or v_link_table[i];
mask = select_one( args, cfg.aliases[list_name .. '-Mask'], 'redundant_parameters', i );
names[i] = {last = last, first = first, link = link, mask = mask, corporate=corporate}; -- add this assembled name to our names list
This function is used to validate a parameter's assigned value for those parameters that have only a limited number
of allowable values (yes, y, true, no, etc). When the parameter value has not been assigned a value (missing or empty
in the source template) the function refurns returns true. If the parameter value is one of the list of allowed values returns
true; else, emits an error message and returns false.
]]
local function is_valid_parameter_value (value, name, possible, cite_class)-- begin hack to limit |mode=mla to a specific set of templates if ('mode' == name) and ('mla' == value) and not in_array (cite_class, {'book', 'journal', 'news'}) then table.insert( z.message_tail, { set_error( 'invalid_param_val', {name, value}, true ) } ); -- not an allowed value so add error message return false end-- end hack
if not is_set (value) then
return true; -- an empty parameter is ok
]]
local function format_volume_issue (volume, issue, cite_class, origin, sepc, lower, mode)
if not is_set (volume) and not is_set (issue) then
return '';
end
if ('mla' == mode) and ('journal' == cite_class) then -- same as cs1 for magazines
lower = true; -- mla 8th edition; force these to lower case
if is_set (volume) and is_set (issue) then
return wrap_msg ('vol-no', {sepc, volume, issue}, lower);
elseif is_set (volume) then
return wrap_msg ('vol', {sepc, volume}, lower);
else
return '';
end
end
if 'magazine' == cite_class or (in_array (cite_class, {'citation', 'map'}) and 'magazine' == origin) then
if is_set (volume) and is_set (issue) then
return vol;
end
--[[-------------------------< N O R M A L I Z E _ P A G E _ L I S T >-----------------------------------------
not currently used
normalizes a comma, ampersand, and/or space separated list to be '<value>, <value>, ..., <value>'
returns list unchanged if there are no commas else strips whitespace and then reformats the list
]]
--[[
local function normalize_page_list (list)
if not list:find ('[,& ]') then return list end -- if list is not delimited with commas, ampersands, or spaces; done
list = mw.text.split (list, '[,&%s]+'); -- make a table of values
list = table.concat (list, ', '); -- and now make a normalized list
return list;
end
]]
]]
local function format_pages_sheets (page, pages, sheet, sheets, cite_class, origin, sepc, nopp, lower, mode)
if 'map' == cite_class then -- only cite map supports sheet(s) as in-source locators
if is_set (sheet) then
local is_journal = 'journal' == cite_class or (in_array (cite_class, {'citation', 'map'}) and 'journal' == origin);
if is_journal and 'mla' == mode then
is_journal = false; -- mla always uses p & pp
end
if is_set (page) then
if is_journal then
-- define different field names for the same underlying things.
-- set default parameter values defined by |mode= parameter. If |mode= is empty or omitted, use CitationClass to set these values
local Mode = A['Mode'];
if not is_valid_parameter_value (Mode, 'mode', cfg.keywords['mode'], config.CitationClass) then
Mode = '';
end
local Translators; -- assembled translators name list
t = extract_names (args, 'TranslatorList'); -- fetch translator list from |translatorn= / |translator-lastn=, -firstn=, -linkn=, -maskn=
local interviewers_list = {};
local Pages;
local At;
-- previously conference books did not support volume-- if in_array (config.CitationClass, cfg.templates_using_volume) and not ('conference' == config.CitationClass and not is_set (Periodical)) then
if in_array (config.CitationClass, cfg.templates_using_volume) then
Volume = A['Volume'];
RegistrationRequired=nil;
end
local SubscriptionRequired = A['SubscriptionRequired'];
if not is_valid_parameter_value (SubscriptionRequired, 'subscription', cfg.keywords ['yes_true_y']) then
SubscriptionRequired=nil;
end
local UrlAccess = A['UrlAccess'];
if not is_valid_parameter_value (UrlAccess, 'url-access', cfg.keywords ['url-access']) then
end
local ChapterUrlAccess = A['ChapterUrlAccess'];
if not is_valid_parameter_value (ChapterUrlAccess, 'chapter-url-access', cfg.keywords ['url-access']) then -- same as url-access
ChapterUrlAccess = nil;
end
if not is_set(ChapterURL) and is_set(ChapterUrlAccess) then
ChapterUrlAccess = nil;
table.insert( z.message_tail, { set_error( 'param_access_requires_param', {'chapter-url'}, true ) } );
end
local Via = A['Via'];
LastAuthorAmp = nil; -- set to empty string
end
if 'mla' == Mode then LastAuthorAmp = 'yes'; -- replaces last author/editor separator with ' and ' text end
local no_tracking_cats = A['NoTracking'];
if not is_valid_parameter_value (no_tracking_cats, 'no-tracking', cfg.keywords ['yes_true_y']) then
end
--local variables that are not cs1 parameters
local use_lowercase; -- controls capitalization of certain static text
local this_page = mw.title.getCurrentTitle(); -- also used for COinS and for language
use_lowercase = ( sepc == ',' ); -- used to control capitalization for certain static text
--check this page to see if it is in one of the namespaces that cs1 is not supposed to add to the error categories
if not is_set (no_tracking_cats) then -- ignore if we are already not going to categorize this page
if in_array (this_page.nsText, cfg.uncategorized_namespaces) then
end
-- check for extra |page=, |pages= or |at= parameters. (also sheet and sheets while we're at it)
select_one( args, {'page', 'p', 'pp', 'pages', 'at', 'sheet', 'sheets'}, 'redundant_parameters' ); -- this is a dummy call simply to get the error message and category
end
-- both |publication-place= and |place= (|location=) allowed if different
if not is_set(PublicationPlace) and is_set(Place) then
PublicationPlace = Place; -- promote |place= (|location=) to |publication-place
if PublicationPlace == Place then Place = ''; end -- don't need both if they are the same
--[[ Parameter remapping for cite encyclopedia: When the citation has these parameters: |encyclopedia and |title then map |title to |article and |encyclopedia to |title |encyclopedia and |article then map |encyclopedia to |title |encyclopedia then map |encyclopedia to |title |trans_title trans-title maps to |trans_chapter trans-chapter when |title is re-mapped |url maps to |chapterurl when |title is remapped All other combinations of |encyclopedia, |title, and |article are not modified ]]
local Encyclopedia = A['Encyclopedia'];
TransChapter = TransTitle;
ChapterURL = URL;
ChapterUrlAccess = UrlAccess;
if not is_set (ChapterURL) and is_set (TitleLink) then
Chapter= '[[' .. make_wikilink (TitleLink .. '|' .. , Chapter .. ']]');
end
Title = Periodical;
end
-- Special case for cite techreport.
if (config.CitationClass == "techreport") then -- special case for cite techreport
if is_set(A['Number']) then -- cite techreport uses 'number', which other citations alias to 'issue'
end
-- special case for cite mailing list
if (config.CitationClass == "mailinglist") then
Periodical = A ['MailingList'];
end
-- Account for the oddity that is {{cite conference}}, before generation of COinS data.
if 'conference' == config.CitationClass then
if is_set(BookTitle) then
-- ChapterLink = TitleLink; -- |chapterlink= is deprecated
ChapterURL = URL;
ChapterUrlAccess = UrlAccess;
ChapterURLorigin = URLorigin;
URLorigin = '';
end
-- cite map oddities
local Cartography = "";
local Scale = "";
Chapter = A['Map'];
ChapterURL = A['MapURL'];
ChapterUrlAccess = UrlAccess;
TransChapter = A['TransMap'];
ChapterURLorigin = A:ORIGIN('MapURL');
end
-- 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
local AirDate = A['AirDate'];
TransChapter = TransTitle;
ChapterURL = URL;
ChapterUrlAccess = UrlAccess;
ChapterURLorigin = A:ORIGIN('URL');
if is_set (ChapterLink) and not is_set (ChapterURL) then -- link but not URL
Chapter = '[[' .. make_wikilink (ChapterLink .. '|' .. , Chapter .. ']]'); -- ok to wikilink
elseif is_set (ChapterLink) and is_set (ChapterURL) then -- if both are set, URL links episode;
Series = '[[' .. make_wikilink (ChapterLink .. '|' .. , Series .. ']]'); -- series links with ChapterLink (episodelink -> TitleLink -> ChapterLink) ugly
end
URL = ''; -- unset
Chapter = A['Episode']; -- TODO: make |episode= available to cite episode someday?
if is_set (Series) and is_set (SeriesLink) then
Series = '[[' .. make_wikilink (SeriesLink .. '|' .. , Series .. ']]');
end
Series = wrap_style ('italic-title', Series); -- series is italicized
end
end
-- end of {{cite episode}} stuff
-- Account for the oddities that are {{cite arxiv}}, {{cite biorxiv}}, {{cite citeseerx}}, before generation of COinS data.
do
if in_array (config.CitationClass, {'arxiv', 'biorxiv', 'citeseerx'}) then
Periodical = 'arXiv'; -- set to arXiv for COinS; after that, must be set to empty string
end
if 'biorxiv' == config.CitationClass then
Periodical = 'bioRxiv'; -- set to bioRxiv for COinS; after that, must be set to empty string
end
if 'citeseerx' == config.CitationClass then
Periodical = 'CiteSeerX'; -- set to CiteSeerX for COinS; after that, must be set to empty string
end
-- handle type parameter for those CS1 citations that have default values
if in_array(config.CitationClass, {"AV-media-notes", "interview", "mailinglist", "map", "podcast", "pressrelease", "report", "techreport", "thesis"}) then
TitleType = set_titletype (config.CitationClass, TitleType);
end
-- legacy: promote PublicationDate to Date if neither Date nor Year are set.
if not is_set (Date) then
Date = Year; -- promote Year to Date
if PublicationDate == Date then PublicationDate = ''; end -- if PublicationDate is same as Date, don't display in rendered citation
--[[ Go test all of the date-holding parameters for valid MOS:DATE format and make sure that dates are real dates. This must be done before we do COinS because here is where we get the date used in the metadata. Date validation supporting code is in Module:Citation/CS1/Date_validation ]]
do -- create defined block to contain local variables error_message, date_parameters_list, mismatch
local error_message = '';
anchor_year, Embargo, error_message = dates(date_parameters_list, COinS_date);
-- start temporary Julian / Gregorian calendar uncertainty categorization
if COinS_date.inter_cal_cat then
add_prop_cat ('jul_greg_uncertainty');
end
-- end temporary Julian / Gregorian calendar uncertainty categorization
if is_set (Year) and is_set (Date) then -- both |date= and |year= not normally needed;
if not is_set(error_message) then -- error free dates only
local modified = false; -- flag
if is_set (DF) then -- if we need to reformat dates
modified = reformat_dates (date_parameters_list, DF, false); -- reformat to DF format, use long month names if appropriate
end
if true == date_hyphen_to_dash (date_parameters_list) then -- convert hyphens to dashes where appropriate
modified = true;
add_maint_cat ('date_format'); -- hyphens were converted so add maint category
end
-- for those wikis that can and want to have English date names translated to the local language,
-- uncomment these three lines. Not supported by en.wiki (for obvious reasons)
-- if date_name_xlate (date_parameters_list) then
-- modified = true;
-- end
if modified then -- if the date_parameters_list values were modified
AccessDate = date_parameters_list['access-date']; -- overwrite date holding parameters with modified values
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. -- 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); --
if config.CitationClass == "journal" and not is_set(URL) and is_set(ID_list['PMC']) then
end
-- 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
if not is_set(Title) and
}, config.CitationClass);
-- Account for the oddities that are {{cite arxiv}}, {{cite biorxiv}}, and {{cite citeseerx}} AFTER generation of COinS data.-- if 'arxiv' == config.CitationClass then -- we have set rft.jtitle in COinS to arXiv, now unset so it isn't displayed
if in_array (config.CitationClass, {'arxiv', 'biorxiv', 'citeseerx'}) then -- we have set rft.jtitle in COinS to arXiv, bioRxiv, or CiteSeerX now unset so it isn't displayed
Periodical = ''; -- periodical not allowed in these templates; if article has been published, use cite journal
end
-- 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 is_set (PublisherName) then
end
-- apply |[xx-]format= styling; at the end, these parameters hold correctly styled format annotation, -- an error message if the associated url is not set, or an empty string for concatenation
ArchiveFormat = style_format (ArchiveFormat, ArchiveURL, 'archive-format', 'archive-url');
ConferenceFormat = style_format (ConferenceFormat, ConferenceURL, 'conference-format', 'conference-url');
TranscriptFormat = style_format (TranscriptFormat, TranscriptURL, 'transcript-format', 'transcripturl');
-- special case for chapter format so no error message or cat when chapter not supported
if not (in_array(config.CitationClass, {'web', 'news', 'journal', 'magazine', 'pressrelease', 'podcast', 'newsgroup', 'arxiv', 'biorxiv', 'citeseerx'}) or
('citation' == config.CitationClass and is_set (Periodical) and not is_set (Encyclopedia))) then
end
Chapter = format_chapter_title (ScriptChapter, Chapter, TransChapter, ChapterURL, ChapterURLorigin, no_quotes, ChapterUrlAccess); -- Contribution is also in Chapter
if is_set (Chapter) then
Chapter = Chapter .. ChapterFormat ;
-- Format main title.
if '...' == Title:sub (-3) then -- if elipsis is the last three characters of |title=
Title = mw.ustring.gsub (Title, '(%.%.%.)%.+$', '%1'); -- limit the number of dots to three
elseif not mw.ustring.find (Title, '%.%s*%a%.') then -- end of title is not a 'dot-(optional space-)letter-dot' initialism
Title = mw.ustring.gsub(Title, '%'..sepc..'$', ''); -- remove any trailing separator character
end
if is_set(TitleLink) and is_set(Title) then
Title = "[[" .. make_wikilink (TitleLink .. "|" .. , Title .. "]]");
end
Title = external_link( URL, Title, URLorigin, UrlAccess ) .. TransTitle .. TransError .. Format;
-- this experiment hidden 2016-04-10; see Help_talk:Citation_Style_1#Recycled_urls
-- local temp_title = external_link( URL, Title, URLorigin ) .. TransError .. Format; -- do this so we get error message even if url is usurped no archive
-- if in_array (DeadURL, {'unfit no archive', 'usurped no archive'}) then -- when url links to inappropriate location and there is no archive of original source available
-- local err_msg
-- if temp_title:match ('%[%S+%s+(.+)%](<.+)') then -- if there is an error message
-- Title, err_msg = temp_title:match ('%[%S+%s+(.+)%](<.+)'); -- strip off external link; TODO: find a better to do this
-- Title = Title .. (err_msg or '');
-- end
-- else
-- Title = temp_title;
-- end
URL = ''; -- unset these because no longer needed
Format = "";
Title = Title .. TransTitle .. TransError;
end
else
Title = TransTitle .. TransError;
end
end
Page, Pages, Sheet, Sheets = format_pages_sheets (Page, Pages, Sheet, Sheets, config.CitationClass, Periodical_origin, sepc, NoPP, use_lowercase, Mode);
At = is_set(At) and (sepc .. " " .. At) or "";
if is_set (Translators) then
if 'mla' == Mode then Others = sepc .. ' Trans. ' .. Translators .. Others; else Others = sepc .. ' ' .. wrap_msg ('translated', Translators, use_lowercase) .. Others; end
end
if is_set (Interviewers) then
add_maint_cat ('extra_text', 'edition');
end
if 'mla' == Mode then Edition = '. ' .. Edition .. ' ed.'; else Edition = " " .. wrap_msg ('edition', Edition); end
else
Edition = '';
Series = is_set(Series) and (sepc .. " " .. Series) or "";
if 'mla' == Mode then -- not in brackets for mla OrigYear = is_set(OrigYear) and (". " .. OrigYear) or ""; else OrigYear = is_set(OrigYear) and (" [" .. OrigYear .. "]") or ""; -- TODO: presentation end
Agency = is_set(Agency) and (sepc .. " " .. Agency) or "";
Volume = format_volume_issue (Volume, Issue, config.CitationClass, Periodical_origin, sepc, use_lowercase, Mode);
------------------------------------ totally unrelated data
end
--[[ Subscription implies paywall; Registration does not. If both are used in a citation, the subscription required link note is displayed. There are no error messages for this condition. ]]
if is_set (SubscriptionRequired) then
SubscriptionRequired = sepc .. " " .. cfg.messages['subscription']; -- subscription required message
AccessDate = nowrap_date (AccessDate); -- wrap in nowrap span if date in appropriate format
if 'mla' == Mode then -- retrieved text not used in mla AccessDate = ' ' .. AccessDate; else if (sepc ~= ".") then retrv_text = retrv_text:lower() end -- if mode is cs2, lower case AccessDate = substitute (retrv_text, AccessDate); -- add retrieved text end
AccessDate = substitute (cfg.presentation['accessdate'], {sepc, AccessDate}); -- allow editors to hide accessdates
end
end
--[[ Handle the oddity that is cite speech. This code overrides whatever may be the value assigned to TitleNote (through |department=) and forces it to be " (Speech)" so that the annotation directly follows the |title= parameter value in the citation rather than the |event= parameter value (if provided). ]]
if "speech" == config.CitationClass then -- cite speech only
TitleNote = " (Speech)"; -- annotate the citation
if in_array(config.CitationClass, {"journal","citation"}) and is_set(Periodical) then
if is_set(Others) then Others = Others .. sepc .. " " end
if 'mla' == Mode then tcommon = safe_join( {Conference, Periodical, Format, TitleType, Series, Language, Edition, Publisher, Agency, Volume}, sepc ); else tcommon = safe_join( {Others, Title, TitleNote, Conference, Periodical, Format, TitleType, Series, Language, Edition, Publisher, Agency, Volume}, sepc ); end
elseif in_array(config.CitationClass, {"book","citation"}) and not is_set(Periodical) then -- special cases for book cites
if is_set (Contributors) then -- when we are citing foreword, preface, introduction, etc
tcommon = safe_join( {Title, TitleNote}, sepc ); -- author and other stuff will come after this and before tcommon2
if 'mla' == Mode then tcommon2 = safe_join( {Conference, Periodical, Format, TitleType, Series, Language, Volume, Edition, Publisher, Agency}, sepc ); else tcommon2 = safe_join( {Conference, Periodical, Format, TitleType, Series, Language, Volume, Others, Edition, Publisher, Agency}, sepc ); end elseif 'mla' == Mode then tcommon = safe_join( {TitleNote, Conference, Periodical, Format, TitleType, Series, Language, Volume, Publisher, Agency}, sepc );
else
tcommon = safe_join( {Title, TitleNote, Conference, Periodical, Format, TitleType, Series, Language, Volume, Others, Edition, Publisher, Agency}, sepc );
elseif 'episode' == config.CitationClass then -- special case for cite episode
tcommon = safe_join( {Title, TitleNote, TitleType, Series, Transcript, Language, Edition, Publisher}, sepc );
elseif ('news' == config.CitationClass) and ('mla' == Mode) then -- special case for cite news in MLA mode
tcommon = safe_join( {Periodical, Format, TitleType, Series, Language, Edition, Agency}, sepc );
elseif ('web' == config.CitationClass) and ('mla' == Mode) then -- special case for cite web in MLA mode
tcommon = safe_join( {Periodical, Format, TitleType, Series, Language,
Edition, Publisher, Agency}, sepc );
else -- all other CS1 templates
if is_set(Date) then
if ('mla' == Mode) then if in_array (config.CitationClass, {'book', 'news', 'web'}) then Date = ', ' .. Date; -- origyear follows title in mla elseif 'journal' == config.CitationClass then Date = ', (' .. Date .. ')'; end elseif is_set (Authors) or is_set (Editors) then -- date follows authors or editors when authors not set
Date = " (" .. Date ..")" .. OrigYear .. sepc .. " "; -- in paranetheses
else -- neither of authors and editors set
end
if is_set(Authors) then
if (not is_set (Date)) or ('mla' == Mode) then -- when date is set it's in parentheses; no Authors termination
Authors = terminate_name_list (Authors, sepc); -- when no date, terminate with 0 or 1 sepc and a space
end
local in_text = " ";
local post_text = "";
if is_set(Chapter) and 0 == #c and 'mla' ~= Mode then
in_text = in_text .. cfg.messages['in'] .. " "
if (sepc ~= '.') then in_text = in_text:lower() end -- lowercase for cs2 elseif is_set(Chapter) and 'mla' == Mode then if EditorCount <= 1 then in_text = '. Ed. '; else in_text = '. Eds. '; end
else
if EditorCount <= 1 then
if (sepc ~= '.') then by_text = by_text:lower() end -- lowercase for cs2
Authors = by_text .. Authors; -- author follows title so tweak it here
if is_set (Editors) and is_set (Date) and ('mla' ~= Mode) then -- when Editors make sure that Authors gets terminated
Authors = terminate_name_list (Authors, sepc); -- terminate with 0 or 1 sepc and a space
end
if (not is_set (Date)) or ('mla' == Mode) then -- when date is set it's in parentheses; no Contributors termination
Contributors = terminate_name_list (Contributors, sepc); -- terminate with 0 or 1 sepc and a space
end
if 'mla' == Mode then text = safe_join( {Contributors, Chapter, tcommon, OrigYear, Authors, Place, Others, Editors, tcommon2, Date, pgtext, idcommon }, sepc ); else text = safe_join( {Contributors, Date, Chapter, tcommon, Authors, Place, Editors, tcommon2, pgtext, idcommon }, sepc ); end elseif 'mla' == Mode then tcommon = tcommon .. Date; -- hack to avoid duplicate separators text = safe_join( {Authors, Chapter, Title, OrigYear, Others, Editors, Edition, Place, tcommon, pgtext, idcommon }, sepc );
else
text = safe_join( {Authors, Date, Chapter, Place, Editors, tcommon, pgtext, idcommon }, sepc );
end
end
if 'mla' == Mode then if in_array(config.CitationClass, {'journal', 'news', 'web'}) and is_set(Periodical) then text = safe_join( {Editors, Title, Place, tcommon, pgtext, Date, idcommon}, sepc ); else text = safe_join( {Editors, Chapter, Title, Place, tcommon, Date, pgtext, idcommon}, sepc ); end else text = safe_join( {Editors, Date, Chapter, Place, tcommon, pgtext, idcommon}, sepc ); end elseif 'mla' == Mode then if in_array(config.CitationClass, {'journal', 'news', 'web'}) and is_set(Periodical) then text = safe_join( {Title, Place, tcommon, pgtext, Date, idcommon}, sepc ); else text = safe_join( {Chapter, Title, Place, tcommon, Date, pgtext, idcommon}, sepc ); end
else
if in_array(config.CitationClass, {"journal","citation"}) and is_set(Periodical) then
end
local render = {}; -- here we collect the final bits for concatenation into the rendered citation
if is_set(options.id) then -- here we wrap the rendered citation in <cite ...>...</cite> tags
text = table.insert (render, substitute (cfg.presentation['cite-id'], {mw.uri.anchorEncode(options.id), mw.text.nowiki(options.class), text})); -- when |ref= is set
else
text = table.insert (render, substitute (cfg.presentation['cite'], {mw.text.nowiki(options.class), text})); -- all other cases
end
text = text .table. insert (render, substitute (cfg.presentation['ocins'], {OCinSoutput})); -- append metadata to the citation
if #z.message_tail ~= 0 then
text = text table.. " "insert (render, ' ');
for i,v in ipairs( z.message_tail ) do
if is_set(v[1]) then
if i == #z.message_tail then
text = text .table. insert (render, error_comment( v[1], v[2] ));
else
text = text .table. insert (render, error_comment( v[1] .. "; ", v[2] ));
end
end
if #z.maintenance_cats ~= 0 then
text = text .table. insert (render, '<span class="citation-comment" style="display:none; color:#33aa33; margin-left:0.3em">');
for _, v in ipairs( z.maintenance_cats ) do -- append maintenance categories
text = text .table. insert (render, v ); table.. insert (render, ' ([['); table.insert (render, make_wikilink (':Category:' .. v .., '|link]]')); table.insert (render, ') ');
end
text = text .table. insert (render, '</span>'); -- maintenance mesages (realy just the names of the categories for now)
end
if in_array(no_tracking_cats, {"", "no", "false", "n"}) then
for _, v in ipairs( z.error_categories ) do
text = text .table. insert (render, make_wikilink ('[[Category:' .. v ..']]'));
end
for _, v in ipairs( z.maintenance_cats ) do -- append maintenance categories
text = text .table. insert (render, make_wikilink ('[[Category:' .. v ..']]'));
end
for _, v in ipairs( z.properties_cats ) do -- append maintenance properties categories text = text .table. insert (render, make_wikilink ('[[Category:' .. v ..']]'));
end
end
return texttable.concat (render);
end
utilities.set_selected_modules (cfg); -- so that functions in Utilities can see the cfg tables
identifiers.set_selected_modules (cfg, utilities); -- so that functions in Identifiers can see the selected cfg tables and selected Utilities module
validation.set_selected_modules (cfg, utilities); -- so that functions in Date validataion can see selected cfg tables and the selected Utilities module
metadata.set_selected_modules (cfg, utilities); -- so that functions in COinS can see the selected cfg tables and selected Utilities module
reformat_dates = validation.reformat_dates;
date_hyphen_to_dash = validation.date_hyphen_to_dash;
date_name_xlate = validation.date_name_xlate;
is_set = utilities.is_set; -- imported functions from Module:Citation/CS1/Utilities
in_array = utilities.in_array;
wrap_style = utilities.wrap_style;
safe_for_italics = utilities.safe_for_italics;
remove_wiki_link is_wikilink = utilities.remove_wiki_linkis_wikilink; make_wikilink = utilities.make_wikilink;
z = utilities.z; -- table of error and category tables in Module:Citation/CS1/Utilities