Jump to content

Module:Citation/CS1: Difference between revisions

sync from sandbox;
(synch from sandbox;)
(sync from sandbox;)
Line 1: Line 1:
local cs1 ={};


--[[--------------------------< F O R W A R D  D E C L A R A T I O N S >--------------------------------------
--[[--------------------------< F O R W A R D  D E C L A R A T I O N S >--------------------------------------
Line 133: Line 131:
the first character of the whole domain name including subdomains must be a letter or a digit
the first character of the whole domain name including subdomains must be a letter or a digit
internationalized domain name (ascii characters with .xn-- ASCII Compatible Encoding (ACE) prefix xn-- in the tld) see https://tools.ietf.org/html/rfc3490
internationalized domain name (ascii characters with .xn-- ASCII Compatible Encoding (ACE) prefix xn-- in the tld) see https://tools.ietf.org/html/rfc3490
single-letter/digit second-level domains in the .org and .cash TLDs
single-letter/digit second-level domains in the .org, .cash, and .today TLDs
q, x, and z SL domains in the .com TLD
q, x, and z SL domains in the .com TLD
i and q SL domains in the .net TLD
i and q SL domains in the .net TLD
Line 165: Line 163:
return true;
return true;
elseif domain:match ('%f[%a%d][%a%d]%.cash$') then -- one character/digit .cash hostname
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]%.today') then -- one character/digit .today hostname
return true;
return true;
elseif domain:match ('%f[%a%d][%a%d]%.org$') then -- one character/digit .org hostname
elseif domain:match ('%f[%a%d][%a%d]%.org$') then -- one character/digit .org hostname
Line 713: Line 713:
Detects but ignores nowiki and math stripmarkers.  Also detects other named stripmarkers (gallery, math, pre, ref)
Detects but ignores nowiki and math stripmarkers.  Also detects other named stripmarkers (gallery, math, pre, ref)
and identifies them with a slightly different error message.  See also coins_cleanup().
and identifies them with a slightly different error message.  See also coins_cleanup().
Detects but ignores the character pattern that results from the transclusion of {{'}} templates.


Output of this function is an error message that identifies the character or the Unicode group, or the stripmarker
Output of this function is an error message that identifies the character or the Unicode group, or the stripmarker
Line 1,221: Line 1,219:
--[[--------------------------< N A M E _ H A S _ E T A L >----------------------------------------------------
--[[--------------------------< N A M E _ H A S _ E T A L >----------------------------------------------------


Evaluates the content of author and editor name parameters for variations on the theme of et al.  If found,
Evaluates the content of name parameters (author, editor, etc) for variations on the theme of et al.  If found,
the et al. is removed, a flag is set to true and the function returns the modified name and the flag.
the et al. is removed, a flag is set to true and the function returns the modified name and the flag.


This function never sets the flag to false but returns it's previous state because it may have been set by
This function never sets the flag to false but returns it's previous state because it may have been set by
previous passes through this function or by the parameters |display-authors=etal or |display-editors=etal
previous passes through this function or by the associated |display-<names>=etal parameter


]]
]]


local function name_has_etal (name, etal, nocat)
local function name_has_etal (name, etal, nocat, param)


if is_set (name) then -- name can be nil in which case just return
if is_set (name) then -- name can be nil in which case just return
local etal_pattern = "[;,]? *[\"']*%f[%a][Ee][Tt] *[Aa][Ll][%.\"']*$" -- variations on the 'et al' theme
local patterns = cfg.et_al_patterns; --get patterns from configuration
local others_pattern = "[;,]? *%f[%a]and [Oo]thers"; -- and alternate to et al.
if name:match (etal_pattern) then -- variants on et al.
for _, pattern in ipairs (patterns) do -- loop through all of the patterns
name = name:gsub (etal_pattern, ''); -- if found, remove
if name:match (pattern) then -- if this 'et al' pattern is found in name
etal = true; -- set flag (may have been set previously here or by |display-authors=etal)
name = name:gsub (pattern, ''); -- remove the offending text
if not nocat then -- no categorization for |vauthors=
etal = true; -- set flag (may have been set previously here or by |display-<names>=etal)
add_maint_cat ('etal'); -- and add a category if not already added
if not nocat then -- no categorization for |vauthors=
end
table.insert( z.message_tail, {set_error ('etal', {param})}); -- and set an error if not added
elseif name:match (others_pattern) then -- if not 'et al.', then 'and others'?
end
name = name:gsub (others_pattern, ''); -- if found, remove
etal = true; -- set flag (may have been set previously here or by |display-authors=etal)
if not nocat then -- no categorization for |vauthors=
add_maint_cat ('etal'); -- and add a category if not already added
end
end
end
end
end
end
return name, etal; --  
return name, etal; --  
end
end
Line 1,263: Line 1,257:
local function name_has_ed_markup (name, list_name)
local function name_has_ed_markup (name, list_name)
local _, pattern;
local _, pattern;
local patterns = { -- these patterns match annotations at end of name
local patterns = cfg.editor_markup_patterns; -- get patterns from configuration
'%f[%(%[][%(%[]%s*[Ee][Dd][Ss]?%.?%s*[%)%]]?$', -- (ed) or (eds): leading '(', case insensitive 'ed', optional 's', '.' and/or ')'
'[,%.%s]%f[e]eds?%.?$', -- ed or eds: without '('or ')'; case sensitive (ED could be initials Ed could be name)
'%f[%(%[][%(%[]%s*[Ee][Dd][Ii][Tt][Oo][Rr][Ss]?%.?%s*[%)%]]?$', -- (editor) or (editors): leading '(', case insensitive, optional '.' and/or ')'
'[,%.%s]%f[Ee][Ee][Dd][Ii][Tt][Oo][Rr][Ss]?%.?$', -- editor or editors: without '('or ')'; case insensitive
-- these patterns match annotations at beginning of name
'^eds?[%.,;]', -- ed. or eds.: lower case only, optional 's', requires '.'
'^[%(%[]%s*[Ee][Dd][Ss]?%.?%s*[%)%]]', -- (ed) or (eds): also sqare brackets, case insensitive, optional 's', '.'
'^[%(%[]?%s*[Ee][Dd][Ii][Tt][Oo][Rr][Ss]?%A', -- (editor or (editors: also sq brackets, case insensitive, optional brackets, 's'
'^[%(%[]?%s*[Ee][Dd][Ii][Tt][Ee][Dd]%A', -- (edited: also sq brackets, case insensitive, optional brackets
}


if is_set (name) then
if is_set (name) then
Line 1,362: Line 1,345:
local etal=false; -- return value set to true when we find some form of et al. in an author parameter
local etal=false; -- return value set to true when we find some form of et al. in an author parameter


local err_msg_list_name = list_name:match ("(%w+)List") .. 's list'; -- modify AuthorList or EditorList for use in error messages if necessary
local last_alias, first_alias; -- selected parameter aliases used in error messaging
while true do
while true do
last = select_one( args, cfg.aliases[list_name .. '-Last'], 'redundant_parameters', i ); -- search through args for name components beginning at 1
last, last_alias = select_one( args, cfg.aliases[list_name .. '-Last'], 'redundant_parameters', i ); -- search through args for name components beginning at 1
first = select_one( args, cfg.aliases[list_name .. '-First'], 'redundant_parameters', i );
first, first_alias = select_one( args, cfg.aliases[list_name .. '-First'], 'redundant_parameters', i );
link = select_one( args, cfg.aliases[list_name .. '-Link'], 'redundant_parameters', i );
link = select_one( args, cfg.aliases[list_name .. '-Link'], 'redundant_parameters', i );
mask = select_one( args, cfg.aliases[list_name .. '-Mask'], 'redundant_parameters', i );
mask = select_one( args, cfg.aliases[list_name .. '-Mask'], 'redundant_parameters', i );


last, etal = name_has_etal (last, etal, false); -- 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); -- find and remove variations on et al.
first, etal = name_has_etal (first, etal, false, first_alias); -- find and remove variations on et al.
last, first= name_checks (last, first, list_name); -- multiple names, extraneous annotation, etc checks
last, first= name_checks (last, first, list_name); -- multiple names, extraneous annotation, etc checks
if first and not last then -- if there is a firstn without a matching lastn
if first and not last then -- if there is a firstn without a matching lastn
table.insert( z.message_tail, { set_error( 'first_missing_last', {err_msg_list_name, i}, true ) } ); -- add this error message
table.insert( z.message_tail, { set_error( 'first_missing_last', {first_alias, first_alias:gsub('first', 'last')}, true ) } ); -- add this error message
elseif not first and not last then -- if both firstn and lastn aren't found, are we done?
elseif not first and not last then -- if both firstn and lastn aren't found, are we done?
count = count + 1; -- number of times we haven't found last and first
count = count + 1; -- number of times we haven't found last and first
Line 1,386: Line 1,369:
n = n + 1; -- point to next location in the names table
n = n + 1; -- point to next location in the names table
if 1 == count then -- if the previous name was missing
if 1 == count then -- if the previous name was missing
table.insert( z.message_tail, { set_error( 'missing_name', {err_msg_list_name, i-1}, true ) } ); -- add this error message
table.insert( z.message_tail, { set_error( 'missing_name', {list_name:match ("(%w+)List"):lower(), i-1}, true ) } ); -- add this error message
end
end
count = 0; -- reset the counter, we're looking for two consecutive missing names
count = 0; -- reset the counter, we're looking for two consecutive missing names
Line 1,624: Line 1,607:


local function is_pdf (url)
local function is_pdf (url)
return url:match ('%.pdf$') or url:match ('%.PDF$') or url:match ('%.pdf[%?#]') or url:match ('%.PDF[%?#]');
return url:match ('%.pdf$') or url:match ('%.PDF$') or
url:match ('%.pdf[%?#]') or url:match ('%.PDF[%?#]') or
url:match ('%.PDF&#035') or url:match ('%.pdf&#035');
end
end


Line 1,652: Line 1,637:




--[[--------------------------< G E T _ D I S P L A Y _ A U T H O R S _ E D I T O R S >------------------------
--[[--------------------------< G E T _ D I S P L A Y _ N A M E S >--------------------------------------------


Returns a number that defines the number of names displayed for author and editor name lists and a boolean flag
Returns a number that defines the number of names displayed for author and editor name lists and a boolean flag
Line 1,675: Line 1,660:
]]
]]


local function get_display_authors_editors (max, count, list_name, etal)
local function get_display_names (max, count, list_name, etal)
if is_set (max) then
if is_set (max) then
if 'etal' == max:lower():gsub("[ '%.]", '') then -- the :gsub() portion makes 'etal' from a variety of 'et al.' spellings and stylings
if 'etal' == max:lower():gsub("[ '%.]", '') then -- the :gsub() portion makes 'etal' from a variety of 'et al.' spellings and stylings
Line 1,683: Line 1,668:
max = tonumber (max); -- make it a number
max = tonumber (max); -- make it a number
if max >= count then -- if |display-xxxxors= value greater than or equal to number of authors/editors
if max >= count then -- if |display-xxxxors= value greater than or equal to number of authors/editors
add_maint_cat ('disp_auth_ed', cfg.special_case_translation [list_name]);
add_maint_cat ('disp_name', cfg.special_case_translation [list_name]);
end
end
else -- not a valid keyword or number
else -- not a valid keyword or number
Line 1,784: Line 1,769:


vparam, etal = name_has_etal (vparam, etal, true); -- find and remove variations on et al. do not categorize (do it here because et al. might have a period)
vparam, etal = name_has_etal (vparam, etal, true); -- find and remove variations on et al. do not categorize (do it here because et al. might have a period)
v_name_table = get_v_name_table (vparam, v_name_table, v_link_table); -- names are separated by commas
v_name_table = get_v_name_table (vparam, v_name_table, v_link_table); -- names are separated by commas


for i, v_name in ipairs(v_name_table) do
for i, v_name in ipairs(v_name_table) do
Line 2,216: Line 2,201:
end
end


local translator_etal;
local t = {}; -- translators list from |translator-lastn= / translator-firstn= pairs
local t = {}; -- translators list from |translator-lastn= / translator-firstn= pairs
local Translators; -- assembled translators name list
local Translators; -- assembled translators name list
t = extract_names (args, 'TranslatorList'); -- fetch translator list from |translatorn= / |translator-lastn=, -firstn=, -linkn=, -maskn=
t = extract_names (args, 'TranslatorList'); -- fetch translator list from |translatorn= / |translator-lastn=, -firstn=, -linkn=, -maskn=


local interviewer_etal;
local interviewers_list = {};
local interviewers_list = {};
local Interviewers; -- used later
local Interviewers; -- used later
interviewers_list = extract_names (args, 'InterviewerList'); -- process preferred interviewers parameters
interviewers_list = extract_names (args, 'InterviewerList'); -- process preferred interviewers parameters


local contributor_etal;
local c = {}; -- contributors list from |contributor-lastn= / contributor-firstn= pairs
local c = {}; -- contributors list from |contributor-lastn= / contributor-firstn= pairs
local Contributors; -- assembled contributors name list
local Contributors; -- assembled contributors name list
Line 2,250: Line 2,238:
NameListFormat = ''; -- anything else, set to empty string
NameListFormat = ''; -- anything else, set to empty string
end
end
if is_set (Others) then
if 0 == #a and 0 == #e then -- add maint cat when |others= has value and used without |author=, |editor=
add_maint_cat ('others');
end
end


local Year = A['Year'];
local Year = A['Year'];
Line 2,408: Line 2,402:
if not is_valid_parameter_value (DF, 'df', cfg.keywords['date-format']) then -- validate reformatting keyword
if not is_valid_parameter_value (DF, 'df', cfg.keywords['date-format']) then -- validate reformatting keyword
DF = ''; -- not valid, set to empty string
DF = ''; -- not valid, set to empty string
end
if not is_set (DF) then
DF = cfg.global_df;
end
end


Line 2,856: Line 2,853:


do -- do editor name list first because the now unsupported coauthors used to modify control table
do -- do editor name list first because the now unsupported coauthors used to modify control table
control.maximum , editor_etal = get_display_authors_editors (A['DisplayEditors'], #e, 'editors', editor_etal);
control.maximum , editor_etal = get_display_names (A['DisplayEditors'], #e, 'editors', editor_etal);
last_first_list, EditorCount = list_people(control, e, editor_etal);
last_first_list, EditorCount = list_people(control, e, editor_etal);


if is_set (Editors) then
if is_set (Editors) then
Editors, editor_etal = name_has_etal (Editors, editor_etal, false, 'editors'); -- find and remove variations on et al.
if editor_etal then
if editor_etal then
Editors = Editors .. ' ' .. cfg.messages['et al']; -- add et al. to editors parameter beause |display-editors=etal
Editors = Editors .. ' ' .. cfg.messages['et al']; -- add et al. to editors parameter beause |display-editors=etal
Line 2,875: Line 2,873:
end
end
do -- now do interviewers
do -- now do interviewers
control.maximum = #interviewers_list; -- number of interviewerss
control.maximum , interviewer_etal = get_display_names (A['DisplayInterviewers'], #interviewers_list, 'interviewers', interviewer_etal);
Interviewers = list_people(control, interviewers_list, false); -- et al not currently supported
Interviewers = list_people (control, interviewers_list, interviewer_etal);
end
end
do -- now do translators
do -- now do translators
control.maximum = #t; -- number of translators
control.maximum , translator_etal = get_display_names (A['DisplayTranslators'], #t, 'translators', translator_etal);
Translators = list_people(control, t, false); -- et al not currently supported
Translators = list_people (control, t, translator_etal);
end
end
do -- now do contributors
do -- now do contributors
control.maximum = #c; -- number of contributors
control.maximum , contributor_etal = get_display_names (A['DisplayContributors'], #c, 'contributors', contributor_etal);
Contributors = list_people(control, c, false); -- et al not currently supported
Contributors = list_people (control, c, contributor_etal);
-- control.maximum = #c; -- number of contributors
-- Contributors = list_people(control, c, false); -- et al not currently supported
end
end
do -- now do authors
do -- now do authors
control.maximum , author_etal = get_display_authors_editors (A['DisplayAuthors'], #a, 'authors', author_etal);
control.maximum , author_etal = get_display_names (A['DisplayAuthors'], #a, 'authors', author_etal);


last_first_list = list_people(control, a, author_etal);
last_first_list = list_people(control, a, author_etal);


if is_set (Authors) then
if is_set (Authors) then
Authors, author_etal = name_has_etal (Authors, author_etal, false); -- find and remove variations on et al.
Authors, author_etal = name_has_etal (Authors, author_etal, false, 'authors'); -- find and remove variations on et al.
if author_etal then
if author_etal then
Authors = Authors .. ' ' .. cfg.messages['et al']; -- add et al. to authors parameter
Authors = Authors .. ' ' .. cfg.messages['et al']; -- add et al. to authors parameter
Line 3,351: Line 3,351:
elseif 'episode' == config.CitationClass then -- special case for cite episode
elseif 'episode' == config.CitationClass then -- special case for cite episode
tcommon = safe_join( {Title, TitleNote, TitleType, Series, Transcript, Language, Edition, Publisher}, sepc );
tcommon = safe_join( {Title, TitleNote, TitleType, Series, Language, Edition, Publisher}, sepc );


else -- all other CS1 templates
else -- all other CS1 templates
Line 3,364: Line 3,364:
end
end
local idcommon = safe_join( { ID_list, URL, Archived, AccessDate, Via, SubscriptionRequired, Lay, Quote }, sepc );
local idcommon;
if 'audio-visual' == config.CitationClass or 'episode' == config.CitationClass then -- special case for cite AV media & cite episode position transcript
idcommon = safe_join( { ID_list, URL, Archived, Transcript, AccessDate, Via, SubscriptionRequired, Lay, Quote }, sepc );
else
idcommon = safe_join( { ID_list, URL, Archived, AccessDate, Via, SubscriptionRequired, Lay, Quote }, sepc );
end
local text;
local text;
local pgtext = Position .. Sheet .. Sheets .. Page .. Pages .. At;
local pgtext = Position .. Sheet .. Sheets .. Page .. Pages .. At;
Line 3,390: Line 3,396:
if (sepc ~= '.') then
if (sepc ~= '.') then
in_text = in_text:lower() -- lowercase for cs2
in_text = in_text:lower() -- lowercase for cs2
end
end
end
if EditorCount <= 1 then
post_text = " (" .. cfg.messages['editor'] .. ")"; -- be consistent with no-author, no-date case
else
else
if EditorCount <= 1 then
post_text = " (" .. cfg.messages['editors'] .. ")";
post_text = ", " .. cfg.messages['editor'];
end
else
post_text = ", " .. cfg.messages['editors'];
end
end  
Editors = terminate_name_list (in_text .. Editors .. post_text, sepc); -- terminate with 0 or 1 sepc and a space
Editors = terminate_name_list (in_text .. Editors .. post_text, sepc); -- terminate with 0 or 1 sepc and a space
end
end
Line 3,612: Line 3,617:
]]
]]


local function missing_pipe_check (value)
local function missing_pipe_check (parameter, value)
local capture;
local capture;
value = value:gsub ('%b<>', ''); -- remove xml/html tags because attributes: class=, title=, etc  
value = value:gsub ('%b<>', ''); -- remove xml/html tags because attributes: class=, title=, etc  
Line 3,618: Line 3,623:
capture = value:match ('%s+(%a[%a%d]+)%s*=') or value:match ('^(%a[%a%d]+)%s*='); -- find and categorize parameters with possible missing pipes
capture = value:match ('%s+(%a[%a%d]+)%s*=') or value:match ('^(%a[%a%d]+)%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
add_maint_cat ('missing_pipe');
table.insert( z.message_tail, {set_error ('missing_pipe',parameter)});
end
end
end
end
Line 3,629: Line 3,634:
]]
]]


function cs1.citation(frame)
local function citation(frame)
Frame = frame; -- save a copy incase we need to display an error message in preview mode
Frame = frame; -- save a copy incase we need to display an error message in preview mode
local pframe = frame:getParent()
local pframe = frame:getParent()
Line 3,745: Line 3,750:
end
end
end
end
missing_pipe_check (v); -- do we think that there is a parameter that is missing a pipe?
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?
-- TODO: is this the best place for this translation?
args[k] = v;
args[k] = v;
Line 3,761: Line 3,766:
end
end


return cs1;
--[[--------------------------< E X P O R T E D  F U N C T I O N S >------------------------------------------
]]
 
return {citation = citation};
Cookies help us deliver our services. By using our services, you agree to our use of cookies.