442
edits
m>Trappist the monk (synch from sandbox;) |
m (7 revisions imported from wikipedia:Module:Citation/CS1/Utilities: see Topic:Vtixlm0q28eo6jtf) |
||
(9 intermediate revisions by 3 users not shown) | |||
Line 1: | Line 1: | ||
local z = { | local z = { | ||
Line 14: | 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 | ||
--[[--------------------------< 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 | |||
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. | |||
After further 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 count; | |||
if true == allow_empty then | |||
str, count = str:gsub ('^%(%((.*)%)%)$', '%1'); -- allows (()) to be an empty set | |||
else | |||
str, count = str:gsub ('^%(%((.+)%)%)$', '%1'); | |||
end | |||
return str, 0 ~= count; | |||
end | |||
Line 22: | Line 43: | ||
]] | ]] | ||
local function is_set( var ) | local function is_set (var) | ||
return not (var == nil or var == ''); | return not (var == nil or var == ''); | ||
end | end | ||
Line 33: | Line 54: | ||
]] | ]] | ||
local function in_array( needle, haystack ) | local function in_array (needle, haystack) | ||
if needle == nil then | if needle == nil then | ||
return false; | return false; | ||
end | end | ||
for n,v in ipairs( haystack ) do | for n, v in ipairs (haystack) do | ||
if v == needle then | if v == needle then | ||
return n; | return n; | ||
Line 52: | Line 73: | ||
]] | ]] | ||
local function substitute( msg, args ) | local function substitute (msg, args) | ||
return args and mw.message.newRawMessage( msg, args ):plain() or msg; | return args and mw.message.newRawMessage (msg, args):plain() or msg; | ||
end | end | ||
Line 59: | Line 80: | ||
--[[--------------------------< E R R O R _ C O M M E N T >---------------------------------------------------- | --[[--------------------------< E R R O R _ C O M M E N T >---------------------------------------------------- | ||
Wraps error messages with | Wraps error messages with CSS markup according to the state of hidden. | ||
]] | ]] | ||
local function error_comment( content, hidden ) | local function error_comment (content, hidden) | ||
return substitute( hidden and cfg.presentation['hidden-error'] or cfg.presentation['visible-error'], content ); | return substitute (hidden and cfg.presentation['hidden-error'] or cfg.presentation['visible-error'], content); | ||
end | end | ||
Line 70: | Line 91: | ||
--[=[-------------------------< M A K E _ W I K I L I N K >---------------------------------------------------- | --[=[-------------------------< M A K E _ W I K I L I N K >---------------------------------------------------- | ||
Makes a wikilink; when | Makes a wikilink; when both link and display text is provided, returns a wikilink in the form [[L|D]]; if only | ||
link is provided, returns a wikilink in the form [[L]]; if neither are provided or link is omitted, returns an | link is provided (or link and display are the same), returns a wikilink in the form [[L]]; if neither are | ||
empty string. | provided or link is omitted, returns an empty string. | ||
]=] | ]=] | ||
local function make_wikilink (link, display) | local function make_wikilink (link, display) | ||
if is_set (link) then | if not is_set (link) then return '' end | ||
if is_set (display) and link ~= display then | |||
return table.concat ({'[[', link, '|', display, ']]'}); | |||
else | else | ||
return ''; | return table.concat ({'[[', link, ']]'}); | ||
end | end | ||
end | end | ||
--[[--------------------------< S E T _ E | --[[--------------------------< S E T _ M E S S A G E >---------------------------------------------------------- | ||
Sets an error condition and returns the appropriate error message. The actual placement of the error message in the output is | Sets an error condition and returns the appropriate error message. The actual placement of the error message in the output is | ||
the responsibility of the calling function. | the responsibility of the calling function. | ||
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 | |||
]] | ]] | ||
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 function | 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 (cfg.messages['undefined_error'] .. ': ' .. error_id); -- because missing error handler in Module:Citation/CS1/Configuration | ||
elseif is_set( error_state.category ) then | |||
table.insert( z.error_categories, error_state.category ); | elseif is_set (error_state.category) then | ||
if error_state.message then -- when error_state.message defined, this is an error message | |||
table.insert (z.error_categories, error_state.category); | |||
else | |||
if not added_maint_cats[error_id] then | |||
added_maint_cats[error_id] = true; -- note that we've added this category | |||
table.insert (z.maintenance_cats, substitute (error_state.category, arguments)); -- make cat name then add to table | |||
end | |||
return; -- because no message, nothing more to do | |||
end | |||
end | end | ||
local message = substitute( error_state.message, arguments ); | local message = substitute (error_state.message, arguments); | ||
message = table.concat ( | message = table.concat ( | ||
Line 125: | Line 156: | ||
}); | }); | ||
z.error_ids[error_id] = true; | |||
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 | |||
-- | 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 raw == true then | if raw == true then | ||
return message, error_state.hidden; | return message, error_state.hidden; | ||
end | end | ||
return error_comment( message, error_state.hidden ); | return error_comment (message, error_state.hidden); | ||
end | end | ||
Line 156: | Line 181: | ||
alias – one of the list of possible aliases in the aliases lists from Module:Citation/CS1/Configuration | alias – one of the list of possible aliases in the aliases lists from Module:Citation/CS1/Configuration | ||
index – for enumerated parameters, identifies which one | index – for enumerated parameters, identifies which one | ||
enumerated – true/false flag used choose how enumerated aliases are examined | enumerated – true/false flag used to choose how enumerated aliases are examined | ||
value – value associated with an alias that has previously been selected; nil if not yet selected | value – value associated with an alias that has previously been selected; nil if not yet selected | ||
selected – the alias that has previously been selected; nil if not yet selected | selected – the alias that has previously been selected; nil if not yet selected | ||
Line 174: | Line 199: | ||
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 184: | Line 209: | ||
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 202: | Line 227: | ||
]] | ]] | ||
local function add_maint_cat (key, arguments) | local function add_maint_cat (key, arguments) | ||
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.maintenance_cats, 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 | |||
--[[--------------------------< 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 | |||
]] | |||
local added_prop_cats = {}; -- list of property categories that have been added to z.properties_cats | |||
local function add_prop_cat (key, arguments) | |||
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?[%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 | ||
end | end | ||
Line 221: | Line 267: | ||
]] | ]] | ||
local function safe_for_italics( str ) | local function safe_for_italics (str) | ||
if not is_set(str) then | if not is_set (str) then return str end | ||
if str:sub (1, 1) == "'" then str = "<span></span>" .. str; end | |||
if str:sub (-1, -1) == "'" then str = str .. "<span></span>"; end | |||
-- Remove newlines as they break italics. | |||
return str:gsub ('\n', ' '); | |||
end | end | ||
Line 243: | Line 288: | ||
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 | |||
--[[--------------------------< M A K E _ S E P _ L I S T >------------------------------------------------------------ | |||
make a separated list of items using provided separators. | |||
<sep_list> - typically '<comma><space>' | |||
<sep_list_pair> - typically '<space>and<space>' | |||
<sep_list_end> - typically '<comma><space>and<space>' or '<comma><space>&<space>' | |||
defaults to cfg.presentation['sep_list'], cfg.presentation['sep_list_pair'], and cfg.presentation['sep_list_end'] | |||
if <sep_list_end> is specified, <sep_list> and <sep_list_pair> must also be supplied | |||
]] | |||
local function make_sep_list (count, list_seq, sep_list, sep_list_pair, sep_list_end) | |||
local list = ''; | |||
if not sep_list then -- set the defaults | |||
sep_list = cfg.presentation['sep_list']; | |||
sep_list_pair = cfg.presentation['sep_list_pair']; | |||
sep_list_end = cfg.presentation['sep_list_end']; | |||
end | |||
if 2 >= count then | |||
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 | |||
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 | |||
end | |||
return list; | |||
end | end | ||
Line 266: | Line 343: | ||
]] | ]] | ||
local function select_one( args, aliases_list, error_condition, index ) | local function select_one (args, aliases_list, error_condition, index) | ||
local value = nil; -- the value assigned to the selected parameter | local value = nil; -- the value assigned to the selected parameter | ||
local selected = ''; -- the name of the parameter we have chosen | local selected = ''; -- the name of the parameter we have chosen | ||
Line 273: | Line 350: | ||
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 | ||
value, selected = is_alias_used (args, alias, index, false, value, selected, error_list); -- first test for non-enumerated alias | value, selected = is_alias_used (args, alias, index, false, value, selected, error_list); -- first test for non-enumerated alias | ||
end | end | ||
value, selected = is_alias_used (args, alias, index, true, value, selected, error_list); | 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); | value, selected = is_alias_used (args, alias, index, false, value, selected, error_list); -- test for non-enumerated alias | ||
end | end | ||
end | end | ||
if #error_list > 0 and 'none' ~= error_condition then -- for cases where this code is used outside of extract_names() | if #error_list > 0 and 'none' ~= error_condition then -- for cases where this code is used outside of extract_names() | ||
for i, v in ipairs (error_list) do | |||
for | error_list[i] = wrap_style ('parameter', v); | ||
end | end | ||
table.insert (error_list, wrap_style ('parameter', selected)); | |||
table.insert( z.message_tail, { | table.insert (z.message_tail, {set_message (error_condition, {make_sep_list (#error_list, error_list)}, true)}); | ||
end | end | ||
Line 309: | Line 379: | ||
The str:gsub() returns either A|B froma [[A|B]] or B from [[B]] or B from B (no wikilink markup). | The str:gsub() returns either A|B froma [[A|B]] or B from [[B]] or B from B (no wikilink markup). | ||
In l(), l:gsub() removes the link and pipe (if they exist); the second :gsub() trims | In l(), l:gsub() removes the link and pipe (if they exist); the second :gsub() trims whitespace from the label | ||
if str was wrapped in wikilink markup. Presumably, this is because without wikimarkup in str, there is no match | if str was wrapped in wikilink markup. Presumably, this is because without wikimarkup in str, there is no match | ||
in the initial gsub, the replacement function l() doesn't get called. | in the initial gsub, the replacement function l() doesn't get called. | ||
Line 316: | Line 386: | ||
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 324: | Line 394: | ||
--[=[-------------------------< I S _ W I K I L I N K >-------------------------------------------------------- | --[=[-------------------------< I S _ W I K I L I N K >-------------------------------------------------------- | ||
Determines if str is a wikilink, extracts, and returns | Determines if str is a wikilink, extracts, and returns the wikilink type, link text, and display text parts. | ||
If str is a complex wikilink ([[L|D]]): | If str is a complex wikilink ([[L|D]]): | ||
returns wl_type 2 and D and L from [[L|D]]; | returns wl_type 2 and D and L from [[L|D]]; | ||
Line 332: | Line 402: | ||
returns wl_type 0, str as D, and L as empty string. | returns wl_type 0, str as D, and L as empty string. | ||
trims leading and trailing | trims leading and trailing whitespace and pipes from L and D ([[L|]] and [[|D]] are accepted by MediaWiki and | ||
treated like [[D]]; while [[|D|]] is not accepted by MediaWiki, here, we accept it and return D without the pipes). | treated like [[D]]; while [[|D|]] is not accepted by MediaWiki, here, we accept it and return D without the pipes). | ||
Line 341: | Line 411: | ||
local wl_type = 2; -- assume that str is a complex wikilink [[L|D]] | local wl_type = 2; -- assume that str is a complex wikilink [[L|D]] | ||
L, D = str:match ('%[%[([^|]+)|([^%]]+)%]%]'); | if not str:match ('^%[%[[^%]]+%]%]$') then -- is str some sort of a wikilink (must have some sort of content) | ||
return 0, str, ''; -- not a wikilink; return wl_type as 0, str as D, and empty string as L | |||
end | |||
L, D = str:match ('^%[%[([^|]+)|([^%]]+)%]%]$'); -- get L and D from [[L|D]] | |||
if not is_set (D) then -- if no separate | if not is_set (D) then -- if no separate display | ||
D = str:match ('%[%[([^%]]*)|*%]%]'); -- get D from [[D]] | D = str:match ('^%[%[([^%]]*)|*%]%]$'); -- get D from [[D]] or [[D|]] | ||
wl_type = 1; | wl_type = 1; | ||
end | end | ||
D = mw.text.trim (D, '%s|'); -- trim white space and pipe characters | D = mw.text.trim (D, '%s|'); -- trim white space and pipe characters | ||
return wl_type, D, L or ''; | return wl_type, D, L or ''; | ||
end | |||
--[[--------------------------< S T R I P _ A P O S T R O P H E _ M A R K U P >-------------------------------- | |||
Strip wiki italic and bold markup from argument so that it doesn't contaminate COinS metadata. | |||
This function strips common patterns of apostrophe markup. We presume that editors who have taken the time to | |||
markup a title have, as a result, provided valid markup. When they don't, some single apostrophes are left behind. | |||
Returns the argument without wiki markup and a number; the number is more-or-less meaningless except as a flag | |||
to indicate that markup was replaced; do not rely on it as an indicator of how many of any kind of markup was | |||
removed; returns the argument and nil when no markup removed | |||
]] | |||
local function strip_apostrophe_markup (argument) | |||
if not is_set (argument) then | |||
return argument, nil; -- no argument, nothing to do | |||
end | |||
if nil == argument:find ( "''", 1, true ) then -- Is there at least one double apostrophe? If not, exit. | |||
return argument, nil; | |||
end | |||
local flag; | |||
while true do | |||
if argument:find ("'''''", 1, true) then -- bold italic (5) | |||
argument, flag = argument:gsub ("%'%'%'%'%'", ""); -- remove all instances of it | |||
elseif argument:find ("''''", 1, true) then -- italic start and end without content (4) | |||
argument, flag=argument:gsub ("%'%'%'%'", ""); | |||
elseif argument:find ("'''", 1, true) then -- bold (3) | |||
argument, flag=argument:gsub ("%'%'%'", ""); | |||
elseif argument:find ("''", 1, true) then -- italic (2) | |||
argument, flag = argument:gsub ("%'%'", ""); | |||
else | |||
break; | |||
end | |||
end | |||
return argument, flag; -- done | |||
end | end | ||
Line 372: | Line 479: | ||
--[[--------------------------< E X P O R T S >---------------------------------------------------------------- | |||
]] | |||
return { | return { | ||
add_maint_cat = add_maint_cat, -- exported functions | |||
add_prop_cat = add_prop_cat, | |||
error_comment = error_comment, | |||
has_accept_as_written = has_accept_as_written, | |||
in_array = in_array, | |||
is_set = is_set, | is_set = is_set, | ||
is_wikilink = is_wikilink, | is_wikilink = is_wikilink, | ||
make_sep_list = make_sep_list, | |||
make_wikilink = make_wikilink, | make_wikilink = make_wikilink, | ||
remove_wiki_link = remove_wiki_link, | |||
safe_for_italics = safe_for_italics, | |||
select_one = select_one, | |||
set_message = set_message, | |||
set_selected_modules = set_selected_modules, | set_selected_modules = set_selected_modules, | ||
z = z, | strip_apostrophe_markup = strip_apostrophe_markup, | ||
substitute = substitute, | |||
wrap_style = wrap_style, | |||
z = z, -- exported table | |||
} | } |