「モジュール:Citation/CS1/Utilities」の版間の差分
ナビゲーションに移動
検索に移動
update per RfC;
細 (1版 をインポートしました) |
bsd>Trappist the monk (update per RfC;) |
||
1行目: | 1行目: | ||
local z = { | local z = { | ||
error_cats_t = {}; -- 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_msgs_t = {}; -- sequence table of error messages | |||
maint_cats_t = {}; -- 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 | |||
prop_keys_t = {}; -- for adding classes to the citation's <cite> tag | |||
}; | }; | ||
13行目: | 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 | |||
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 | 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 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 | ||
37行目: | 72行目: | ||
--[[--------------------------< | --[[--------------------------< S U B S T I T U T E >---------------------------------------------------------- | ||
Populates numbered arguments in a message string using an argument table. <args> may be a single string or a | |||
sequence table of multiple strings. | |||
]] | ]] | ||
local function | local function substitute (msg, args) | ||
return | return args and mw.message.newRawMessage (msg, args):plain() or msg; | ||
end | end | ||
--[[--------------------------< | --[[--------------------------< E R R O R _ C O M M E N T >---------------------------------------------------- | ||
Wraps error messages with CSS markup according to the state of hidden. <content> may be a single string or a | |||
sequence table of multiple strings. | |||
]] | ]] | ||
local function | local function error_comment (content, hidden) | ||
return substitute (hidden and cfg.presentation['hidden-error'] or cfg.presentation['visible-error'], content); | |||
end | end | ||
--[[--------------------------< S | --[[--------------------------< H Y P H E N _ T O _ D A S H >-------------------------------------------------- | ||
Converts a hyphen to a dash under certain conditions. The hyphen must separate | |||
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 | local function hyphen_to_dash (str) | ||
if not is_set (str) then | |||
end | return str; | ||
end | |||
local accept; -- boolean | |||
- | 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 | |||
item, accept = has_accept_as_written (item); -- remove accept-this-as-written markup when it wraps all of item | |||
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 | |||
return | 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 | ||
92行目: | 159行目: | ||
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, 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 | ||
112行目: | 177行目: | ||
--[[--------------------------< S E T _ M E S S A G E >---------------------------------------------------------- | --[[--------------------------< S E T _ M E S S A G E >---------------------------------------------------------- | ||
Sets an | Sets an error message using the ~/Configuration error_conditions{} table along with arguments supplied in the function | ||
the | call, inserts the resulting message in z.error_msgs_t{} sequence table, and returns the error message. | ||
TODO: change z. | <error_id> – key value for appropriate error handler in ~/Configuration error_conditions{} table | ||
<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. | |||
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. | table.insert (z.error_cats_t, 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. | table.insert (z.maint_cats_t, 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 | ||
141行目: | 218行目: | ||
end | end | ||
local message = substitute( error_state.message, arguments ); | local message = substitute (error_state.message, arguments); | ||
message = table.concat ( | message = table.concat ( | ||
158行目: | 235行目: | ||
}); | }); | ||
z. | z.error_ids_t[error_id] = true; | ||
if z. | if z.error_ids_t['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 | if true == raw then | ||
return message, error_state.hidden; | return message, error_state.hidden; -- return message not wrapped in visible-error, hidden-error span tag | ||
end | end | ||
message = error_comment (message, error_state.hidden); -- wrap message in visible-error, hidden-error span tag | |||
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 | ||
201行目: | 280行目: | ||
end | end | ||
if is_set(args[alias]) then | 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; | ||
211行目: | 290行目: | ||
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 | ||
224行目: | 303行目: | ||
--[[--------------------------< 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. | Adds a category to z.maint_cats_t 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. | To prevent duplication, the added_maint_cats table lists the categories by key that have been added to z.maint_cats_t. | ||
]] | ]] | ||
232行目: | 311行目: | ||
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. | table.insert (z.maint_cats_t, substitute (cfg.maint_cats [key], arguments)); -- make name then add to table | ||
end | end | ||
end | end | ||
239行目: | 318行目: | ||
--[[--------------------------< 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. | Adds a category to z.prop_cats_t 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 | ||
248行目: | 327行目: | ||
]] | ]] | ||
local added_prop_cats = {}; -- list of property categories that have been added to z. | local added_prop_cats = {}; -- list of property categories that have been added to z.prop_cats_t | ||
local function add_prop_cat (key, arguments) | local function add_prop_cat (key, arguments, key_modifier) | ||
if not added_prop_cats [ | local key_modified = key .. ((key_modifier and key_modifier) or ''); -- modify <key> with <key_modifier> if present and not nil | ||
added_prop_cats [ | |||
if not added_prop_cats [key_modified] then | |||
table.insert( z. | added_prop_cats [key_modified] = true; -- note that we've added this category | ||
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 | ||
269行目: | 350行目: | ||
]] | ]] | ||
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 | |||
return str:gsub ('\n', ' '); -- Remove newlines as they break italics. | |||
end | end | ||
291行目: | 369行目: | ||
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 | ||
325行目: | 403行目: | ||
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 | ||
353行目: | 431行目: | ||
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 | ||
360行目: | 438行目: | ||
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 | ||
369行目: | 447行目: | ||
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)}); | |||
end | end | ||
389行目: | 467行目: | ||
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 | ||
453行目: | 531行目: | ||
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("%'%'%'%'%'", ""); | argument, flag = argument:gsub ("%'%'%'%'%'", ""); -- remove all instances of it | ||
elseif argument:find ( "''''", 1, true ) then | 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 | 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; | ||
490行目: | 568行目: | ||
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, |