Line 1:
Line 1:
+
local z = {
local z = {
−
error_cats_t = {}; -- for categorizing citations that contain errors
+
error_categories = {}; -- for categorizing citations that contain errors
−
error_ids_t = {}; -- list of error identifiers; used to prevent duplication of certain errors; local to this module
+
error_ids = {};
−
error_msgs_t = {}; -- sequence table of error messages
+
message_tail = {};
−
maint_cats_t = {}; -- for categorizing citations that aren't erroneous per se, but could use a little work
+
maintenance_cats = {}; -- for categorizing citations that aren't erroneous per se, but could use a little work
−
prop_cats_t = {}; -- for categorizing citations based on certain properties, language of source for instance
+
properties_cats = {}; -- for categorizing citations based on certain properties, language of source for instance
−
prop_keys_t = {}; -- for adding classes to the citation's <cite> tag
};
};
Line 13:
Line 13:
local cfg; -- table of tables imported from selected Module:Citation/CS1/Configuration
local cfg; -- table of tables imported from selected Module:Citation/CS1/Configuration
−
−
−
--[[--------------------------< I S _ S E T >------------------------------------------------------------------
−
−
Returns true if argument is set; false otherwise. Argument is 'set' when it exists (not nil) or when it is not an empty string.
−
−
]]
−
−
local function is_set (var)
−
return not (var == nil or var == '');
−
end
−
−
−
--[[--------------------------< I N _ A R R A Y >--------------------------------------------------------------
−
−
Whether needle is in haystack
−
−
]]
−
−
local function in_array (needle, haystack)
−
if needle == nil then
−
return false;
−
end
−
for n, v in ipairs (haystack) do
−
if v == needle then
−
return n;
−
end
−
end
−
return false;
−
end
--[[--------------------------< H A S _ A C C E P T _ A S _ W R I T T E N >------------------------------------
--[[--------------------------< H A S _ A C C E P T _ A S _ W R I T T E N >------------------------------------
−
When <str> is wholly wrapped in accept-as-written markup, return <str> without markup and true; return <str> and false else
+
when <str> is wholly wrapped in accept-as-written markup, return <str> without markup and true; return <str> and false else
with allow_empty = false, <str> must have at least one character inside the markup
with allow_empty = false, <str> must have at least one character inside the markup
with allow_empty = true, <str> the markup frame can be empty like (()) to distinguish an empty template parameter from the specific condition "has no applicable value" in citation-context.
with allow_empty = true, <str> the markup frame can be empty like (()) to distinguish an empty template parameter from the specific condition "has no applicable value" in citation-context.
−
After further evaluation the two cases might be merged at a later stage, but should be kept separated for now.
+
After futher evaluation the two cases might be merged at a later stage, but should be kept separated for now.
]]
]]
local function has_accept_as_written (str, allow_empty)
local function has_accept_as_written (str, allow_empty)
−
if not is_set (str) then
−
return str, false;
−
end
−
local count;
local count;
−
if true == allow_empty then
if true == allow_empty then
str, count = str:gsub ('^%(%((.*)%)%)$', '%1'); -- allows (()) to be an empty set
str, count = str:gsub ('^%(%((.*)%)%)$', '%1'); -- allows (()) to be an empty set
Line 72:
Line 37:
−
--[[--------------------------< S U B S T I T U T E >----------------------------------------------------------
+
--[[--------------------------< I S _ S E T >------------------------------------------------------------------
−
Populates numbered arguments in a message string using an argument table. <args> may be a single string or a
+
Returns true if argument is set; false otherwise. Argument is 'set' when it exists (not nil) or when it is not an empty string.
−
sequence table of multiple strings.
]]
]]
−
local function substitute (msg, args)
+
local function is_set( var )
−
return args and mw.message.newRawMessage (msg, args):plain() or msg;
+
return not (var == nil or var == '');
end
end
−
--[[--------------------------< E R R O R _ C O M M E N T >----------------------------------------------------
+
--[[--------------------------< I N _ A R R A Y >--------------------------------------------------------------
−
Wraps error messages with CSS markup according to the state of hidden. <content> may be a single string or a
+
Whether needle is in haystack
−
sequence table of multiple strings.
]]
]]
−
local function error_comment (content, hidden)
+
local function in_array( needle, haystack )
−
return substitute (hidden and cfg.presentation['hidden-error'] or cfg.presentation['visible-error'], content);
+
if needle == nil then
+
return false;
+
end
+
for n,v in ipairs( haystack ) do
+
if v == needle then
+
return n;
+
end
+
end
+
return false;
end
end
−
--[[--------------------------< H Y P H E N _ T O _ D A S H >--------------------------------------------------
+
--[[--------------------------< S U B S T I T U T E >----------------------------------------------------------
−
Converts a hyphen to a dash under certain conditions. The hyphen must separate
+
Populates numbered arguments in a message string using an argument table.
−
like items; unlike items are returned unmodified. These forms are modified:
−
letter - letter (A - B)
−
digit - digit (4-5)
−
digit separator digit - digit separator digit (4.1-4.5 or 4-1-4-5)
−
letterdigit - letterdigit (A1-A5) (an optional separator between letter and
−
digit is supported – a.1-a.5 or a-1-a-5)
−
digitletter - digitletter (5a - 5d) (an optional separator between letter and
−
digit is supported – 5.a-5.d or 5-a-5-d)
−
any other forms are returned unmodified.
+
]]
−
str may be a comma- or semicolon-separated list
+
local function substitute( msg, args )
+
return args and mw.message.newRawMessage( msg, args ):plain() or msg;
+
end
−
]]
−
local function hyphen_to_dash (str)
+
--[[--------------------------< E R R O R _ C O M M E N T >----------------------------------------------------
−
if not is_set (str) then
−
return str;
−
end
−
local accept; -- boolean
+
Wraps error messages with CSS markup according to the state of hidden.
−
str = str:gsub ("(%(%(.-%)%))", function(m) return m:gsub(",", ","):gsub(";", ";") end) -- replace commas and semicolons in accept-as-written markup with similar unicode characters so they'll be ignored during the split
+
]]
−
str = str:gsub ('&[nm]dash;', {['–'] = '–', ['—'] = '—'}); -- replace — and – entities with their characters; semicolon mucks up the text.split
−
str = str:gsub ('-', '-'); -- replace HTML numeric entity with hyphen character
−
str = str:gsub (' ', ' '); -- replace entity with generic keyboard space character
−
−
local out = {};
−
local list = mw.text.split (str, '%s*[,;]%s*'); -- split str at comma or semicolon separators if there are any
−
for _, item in ipairs (list) do -- for each item in the list
+
local function error_comment( content, hidden )
−
item, accept = has_accept_as_written (item); -- remove accept-this-as-written markup when it wraps all of item
+
return substitute( hidden and cfg.presentation['hidden-error'] or cfg.presentation['visible-error'], content );
−
if not accept and mw.ustring.match (item, '^%w*[%.%-]?%w+%s*[%-–—]%s*%w*[%.%-]?%w+$') then -- if a hyphenated range or has endash or emdash separators
−
if item:match ('^%a+[%.%-]?%d+%s*%-%s*%a+[%.%-]?%d+$') or -- letterdigit hyphen letterdigit (optional separator between letter and digit)
−
item:match ('^%d+[%.%-]?%a+%s*%-%s*%d+[%.%-]?%a+$') or -- digitletter hyphen digitletter (optional separator between digit and letter)
−
item:match ('^%d+[%.%-]%d+%s*%-%s*%d+[%.%-]%d+$') or -- digit separator digit hyphen digit separator digit
−
item:match ('^%d+%s*%-%s*%d+$') or -- digit hyphen digit
−
item:match ('^%a+%s*%-%s*%a+$') then -- letter hyphen letter
−
item = item:gsub ('(%w*[%.%-]?%w+)%s*%-%s*(%w*[%.%-]?%w+)', '%1–%2'); -- replace hyphen, remove extraneous space characters
−
else
−
item = mw.ustring.gsub (item, '%s*[–—]%s*', '–'); -- for endash or emdash separated ranges, replace em with en, remove extraneous whitespace
−
end
−
end
−
table.insert (out, item); -- add the (possibly modified) item to the output table
−
end
−
−
local temp_str = ''; -- concatenate the output table into a comma separated string
−
temp_str, accept = has_accept_as_written (table.concat (out, ', ')); -- remove accept-this-as-written markup when it wraps all of concatenated out
−
if accept then
−
temp_str = has_accept_as_written (str); -- when global markup removed, return original str; do it this way to suppress boolean second return value
−
return temp_str:gsub(",", ","):gsub(";", ";");
−
else
−
return temp_str:gsub(",", ","):gsub(";", ";"); -- else, return assembled temp_str
−
end
end
end
Line 159:
Line 92:
Makes a wikilink; when both link and display text is provided, returns a wikilink in the form [[L|D]]; if only
Makes a wikilink; when both link and display text is provided, returns a wikilink in the form [[L|D]]; if only
−
link is provided (or link and display are the same), returns a wikilink in the form [[L]]; if neither are
+
link is provided, returns a wikilink in the form [[L]]; if neither are provided or link is omitted, returns an
−
provided or link is omitted, returns an empty string.
+
empty string.
]=]
]=]
local function make_wikilink (link, display)
local function make_wikilink (link, display)
−
if not is_set (link) then return '' end
+
if is_set (link) then
−
+
if is_set (display) then
−
if is_set (display) and link ~= display then
+
return table.concat ({'[[', link, '|', display, ']]'});
−
return table.concat ({'[[', link, '|', display, ']]'});
+
else
+
return table.concat ({'[[', link, ']]'});
+
end
else
else
−
return table.concat ({'[[', link, ']]'});
+
return '';
end
end
end
end
Line 177:
Line 112:
--[[--------------------------< S E T _ M E S S A G E >----------------------------------------------------------
--[[--------------------------< S E T _ M E S S A G E >----------------------------------------------------------
−
Sets an error message using the ~/Configuration error_conditions{} table along with arguments supplied in the function
+
Sets an error condition and returns the appropriate error message. The actual placement of the error message in the output is
−
call, inserts the resulting message in z.error_msgs_t{} sequence table, and returns the error message.
+
the responsibility of the calling function.
−
<error_id> – key value for appropriate error handler in ~/Configuration error_conditions{} table
+
TODO: change z.error_categories and z.maintenance_cats to have the form cat_name = true; to avoid dups without having to have an extra cat
−
<arguments> – may be a single string or a sequence table of multiple strings to be subsititued into error_conditions[error_id].message
−
<raw> – boolean
−
true – causes this function to return the error message not wrapped in visible-error, hidden-error span tag;
−
returns error_conditions[error_id].hidden as a second return value
−
does not add message to z.error_msgs_t sequence table
−
false, nil – adds message wrapped in visible-error, hidden-error span tag to z.error_msgs_t
−
returns the error message wrapped in visible-error, hidden-error span tag; there is no second return value
−
<prefix> – string to be prepended to <message> -- TODO: remove support for these unused(?) arguments?
−
<suffix> – string to be appended to <message>
−
−
TODO: change z.error_cats_t and z.maint_cats_t to have the form cat_name = true? this to avoid dups without having to have an extra table
]]
]]
−
+
local added_maint_cats = {} -- list of maintenance categories that have been added to z.maintenance_cats; TODO: figure out how to delete this table
−
local added_maint_cats = {} -- list of maintenance categories that have been added to z.maint_cats_t; TODO: figure out how to delete this table
local function set_message (error_id, arguments, raw, prefix, suffix)
local function set_message (error_id, arguments, raw, prefix, suffix)
local error_state = cfg.error_conditions[error_id];
local error_state = cfg.error_conditions[error_id];
−
prefix = prefix or '';
+
prefix = prefix or "";
−
suffix = suffix or '';
+
suffix = suffix or "";
if error_state == nil then
if error_state == nil then
−
error (cfg.messages['undefined_error'] .. ': ' .. error_id); -- because missing error handler in Module:Citation/CS1/Configuration
+
error( cfg.messages['undefined_error'] .. ': ' .. error_id ); -- because missing error handler in Module:Citation/CS1/Configuration
elseif is_set (error_state.category) then
elseif is_set (error_state.category) then
if error_state.message then -- when error_state.message defined, this is an error message
if error_state.message then -- when error_state.message defined, this is an error message
−
table.insert (z.error_cats_t, error_state.category);
+
table.insert( z.error_categories, error_state.category );
else
else
if not added_maint_cats[error_id] then
if not added_maint_cats[error_id] then
added_maint_cats[error_id] = true; -- note that we've added this category
added_maint_cats[error_id] = true; -- note that we've added this category
−
table.insert (z.maint_cats_t, substitute (error_state.category, arguments)); -- make cat name then add to table
+
table.insert (z.maintenance_cats, substitute (error_state.category, arguments)); -- make cat name then add to table
end
end
return; -- because no message, nothing more to do
return; -- because no message, nothing more to do
Line 218:
Line 141:
end
end
−
local message = substitute (error_state.message, arguments);
+
local message = substitute( error_state.message, arguments );
message = table.concat (
message = table.concat (
Line 235:
Line 158:
});
});
−
z.error_ids_t[error_id] = true;
+
z.error_ids[error_id] = true;
−
if z.error_ids_t['err_citation_missing_title'] and -- if missing-title error already noted
+
if z.error_ids['err_citation_missing_title'] and -- if missing-title error already noted
in_array (error_id, {'err_bare_url_missing_title', 'err_trans_missing_title'}) then -- and this error is one of these
in_array (error_id, {'err_bare_url_missing_title', 'err_trans_missing_title'}) then -- and this error is one of these
return '', false; -- don't bother because one flavor of missing title is sufficient
return '', false; -- don't bother because one flavor of missing title is sufficient
end
end
−
message = table.concat ({prefix, message, suffix});
+
message = table.concat ({ prefix, message, suffix });
−
if true == raw then
+
if raw == true then
−
return message, error_state.hidden; -- return message not wrapped in visible-error, hidden-error span tag
+
return message, error_state.hidden;
end
end
−
message = error_comment (message, error_state.hidden); -- wrap message in visible-error, hidden-error span tag
+
return error_comment (message, error_state.hidden);
−
table.insert (z.error_msgs_t, message); -- add it to the messages sequence table
−
return message; -- and done; return value generally not used but is used as a flag in various functions of ~/Identifiers
end
end
Line 280:
Line 201:
end
end
−
if is_set (args[alias]) then -- alias is in the template's argument list
+
if is_set(args[alias]) then -- alias is in the template's argument list
if value ~= nil and selected ~= alias then -- if we have already selected one of the aliases
if value ~= nil and selected ~= alias then -- if we have already selected one of the aliases
local skip;
local skip;
−
for _, v in ipairs (error_list) do -- spin through the error list to see if we've added this alias
+
for _, v in ipairs(error_list) do -- spin through the error list to see if we've added this alias
if v == alias then
if v == alias then
skip = true;
skip = true;
Line 290:
Line 211:
end
end
if not skip then -- has not been added so
if not skip then -- has not been added so
−
table.insert (error_list, alias); -- add error alias to the error list
+
table.insert( error_list, alias ); -- add error alias to the error list
end
end
else
else
Line 303:
Line 224:
--[[--------------------------< A D D _ M A I N T _ C A T >------------------------------------------------------
--[[--------------------------< A D D _ M A I N T _ C A T >------------------------------------------------------
−
Adds a category to z.maint_cats_t using names from the configuration file with additional text if any.
+
Adds a category to z.maintenance_cats using names from the configuration file with additional text if any.
−
To prevent duplication, the added_maint_cats table lists the categories by key that have been added to z.maint_cats_t.
+
To prevent duplication, the added_maint_cats table lists the categories by key that have been added to z.maintenance_cats.
]]
]]
Line 311:
Line 232:
if not added_maint_cats [key] then
if not added_maint_cats [key] then
added_maint_cats [key] = true; -- note that we've added this category
added_maint_cats [key] = true; -- note that we've added this category
−
table.insert (z.maint_cats_t, substitute (cfg.maint_cats [key], arguments)); -- make name then add to table
+
table.insert( z.maintenance_cats, substitute (cfg.maint_cats [key], arguments)); -- make name then add to table
end
end
end
end
Line 318:
Line 239:
--[[--------------------------< A D D _ P R O P _ C A T >--------------------------------------------------------
--[[--------------------------< A D D _ P R O P _ C A T >--------------------------------------------------------
−
Adds a category to z.prop_cats_t using names from the configuration file with additional text if any.
+
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
foreign_lang_source and foreign_lang_source_2 keys have a language code appended to them so that multiple languages
Line 327:
Line 248:
]]
]]
−
local added_prop_cats = {}; -- list of property categories that have been added to z.prop_cats_t
+
local added_prop_cats = {}; -- list of property categories that have been added to z.properties_cats
−
local function add_prop_cat (key, arguments, key_modifier)
+
local function add_prop_cat (key, arguments)
−
local key_modified = key .. ((key_modifier and key_modifier) or ''); -- modify <key> with <key_modifier> if present and not nil
+
if not added_prop_cats [key] then
−
+
added_prop_cats [key] = true; -- note that we've added this category
−
if not added_prop_cats [key_modified] then
+
key = key:gsub ('(foreign_lang_source_?2?)%a%a%a?[%a%-]*', '%1'); -- strip lang code from keyname
−
added_prop_cats [key_modified] = true; -- note that we've added this category
+
table.insert( z.properties_cats, substitute (cfg.prop_cats [key], arguments)); -- make name then add to table
−
table.insert (z.prop_cats_t, substitute (cfg.prop_cats [key], arguments)); -- make name then add to table
−
table.insert (z.prop_keys_t, 'cs1-prop-' .. key); -- convert key to class for use in the citation's <cite> tag
end
end
end
end
Line 350:
Line 269:
]]
]]
−
local function safe_for_italics (str)
+
local function safe_for_italics( str )
−
if not is_set (str) then return str end
+
if not is_set(str) then
−
+
return str;
−
if str:sub (1, 1) == "'" then str = "<span></span>" .. str; end
+
else
−
if str:sub (-1, -1) == "'" then str = str .. "<span></span>"; end
+
if str:sub(1,1) == "'" then str = "<span></span>" .. str; end
−
+
if str:sub(-1,-1) == "'" then str = str .. "<span></span>"; end
−
return str:gsub ('\n', ' '); -- Remove newlines as they break italics.
+
+
-- Remove newlines as they break italics.
+
return str:gsub( '\n', ' ' );
+
end
end
end
Line 369:
Line 291:
local function wrap_style (key, str)
local function wrap_style (key, str)
−
if not is_set (str) then
+
if not is_set( str ) then
return "";
return "";
−
elseif in_array (key, {'italic-title', 'trans-italic-title'}) then
+
elseif in_array( key, { 'italic-title', 'trans-italic-title' } ) then
−
str = safe_for_italics (str);
+
str = safe_for_italics( str );
end
end
−
return substitute (cfg.presentation[key], {str});
+
return substitute( cfg.presentation[key], {str} );
end
end
Line 403:
Line 325:
list = table.concat (list_seq, sep_list_pair); -- insert separator between two items; returns list_seq[1] then only one item
list = table.concat (list_seq, sep_list_pair); -- insert separator between two items; returns list_seq[1] then only one item
elseif 2 < count then
elseif 2 < count then
−
list = table.concat (list_seq, sep_list, 1, count - 1); -- concatenate all but last item with plain list separator
+
list = table.concat (list_seq, sep_list, 1, count-1); -- concatenate all but last item with plain list separator
list = table.concat ({list, list_seq[count]}, sep_list_end); -- concatenate last item onto end of <list> with final separator
list = table.concat ({list, list_seq[count]}, sep_list_end); -- concatenate last item onto end of <list> with final separator
end
end
Line 431:
Line 353:
if index ~= nil then index = tostring(index); end
if index ~= nil then index = tostring(index); end
−
for _, alias in ipairs (aliases_list) do -- for each alias in the aliases list
+
for _, alias in ipairs( aliases_list ) do -- for each alias in the aliases list
if alias:match ('#') then -- if this alias can be enumerated
if alias:match ('#') then -- if this alias can be enumerated
if '1' == index then -- when index is 1 test for enumerated and non-enumerated aliases
if '1' == index then -- when index is 1 test for enumerated and non-enumerated aliases
Line 438:
Line 360:
value, selected = is_alias_used (args, alias, index, true, value, selected, error_list); -- test for enumerated alias
value, selected = is_alias_used (args, alias, index, true, value, selected, error_list); -- test for enumerated alias
else
else
−
value, selected = is_alias_used (args, alias, index, false, value, selected, error_list); -- test for non-enumerated alias
+
value, selected = is_alias_used (args, alias, index, false, value, selected, error_list); --test for non-enumerated alias
end
end
end
end
Line 447:
Line 369:
end
end
table.insert (error_list, wrap_style ('parameter', selected));
table.insert (error_list, wrap_style ('parameter', selected));
−
set_message (error_condition, {make_sep_list (#error_list, error_list)});
+
table.insert (z.message_tail, {set_message (error_condition, {make_sep_list (#error_list, error_list)}, true)});
end
end
Line 467:
Line 389:
local function remove_wiki_link (str)
local function remove_wiki_link (str)
−
return (str:gsub ("%[%[([^%[%]]*)%]%]", function(l)
+
return (str:gsub( "%[%[([^%[%]]*)%]%]", function(l)
−
return l:gsub ("^[^|]*|(.*)$", "%1" ):gsub ("^%s*(.-)%s*$", "%1");
+
return l:gsub( "^[^|]*|(.*)$", "%1" ):gsub("^%s*(.-)%s*$", "%1");
end));
end));
end
end
Line 531:
Line 453:
local flag;
local flag;
while true do
while true do
−
if argument:find ("'''''", 1, true) then -- bold italic (5)
+
if argument:find ( "'''''", 1, true ) then -- bold italic (5)
−
argument, flag = argument:gsub ("%'%'%'%'%'", ""); -- remove all instances of it
+
argument, flag=argument:gsub("%'%'%'%'%'", ""); -- remove all instances of it
−
elseif argument:find ("''''", 1, true) then -- italic start and end without content (4)
+
elseif argument:find ( "''''", 1, true ) then -- italic start and end without content (4)
−
argument, flag=argument:gsub ("%'%'%'%'", "");
+
argument, flag=argument:gsub("%'%'%'%'", "");
−
elseif argument:find ("'''", 1, true) then -- bold (3)
+
elseif argument:find ( "'''", 1, true ) then -- bold (3)
−
argument, flag=argument:gsub ("%'%'%'", "");
+
argument, flag=argument:gsub("%'%'%'", "");
−
elseif argument:find ("''", 1, true) then -- italic (2)
+
elseif argument:find ( "''", 1, true ) then -- italic (2)
−
argument, flag = argument:gsub ("%'%'", "");
+
argument, flag=argument:gsub("%'%'", "");
else
else
break;
break;
Line 568:
Line 490:
error_comment = error_comment,
error_comment = error_comment,
has_accept_as_written = has_accept_as_written,
has_accept_as_written = has_accept_as_written,
−
hyphen_to_dash = hyphen_to_dash,
in_array = in_array,
in_array = in_array,
is_set = is_set,
is_set = is_set,