Module:Annotated link: Difference between revisions

Content deleted Content added
adding filtering option against wikidata descriptions containing specified terms
disable wikidata short descriptions, per RFC and multiple talk page discussions. Please report any bugs on the template talk page
 
(12 intermediate revisions by 3 users not shown)
Line 1:
local getShortDescription = require( 'Module:GetShortDescription' ).main
local getArgs = require( 'Module:Arguments' ).getArgs
local mLang = require( 'Module:Lang' )
 
local function pipedLink( name, display ) return '[[:' .. name .. '|' .. display .. ']]' end
 
local function isEmpty( value ) return value == nil or value == '' end
 
local function notEmpty( value ) return not isEmpty( value ) end
 
-- Unescape functionality grabbed from https://stackoverflow.com/a/14899740/1832568
local function unescape( str )
str = string.gsub( str, '&#(%d+);', string.char )
str = string.gsub( str, '&#x(%d+);', function( d ) return string.char( tonumber( d, 16 ) ) end )
return str
end
 
local function hashDelimitedList( list_string ) return mw.text.gsplit( unescape( list_string ), '%s*#%s*' ) end
 
local function alarmingMessage( message )
return '<span style="color:#d33">[[Module:Annotated link]] ' .. message .. '.</span>'..
.. '[[Category:Pages displaying alarming messages about Module:AnnotatedLinkAnnotated link]]'
end
 
local function optionallyVisibleCategory( class, category )
return '<span style="display:none" class="' .. class .. '">' .. category ..
'</span>[[Category:' .. category ..' 'via Module:Annotated link]]'
end
 
local function handleFirstLetterCase( short_description, case )
return mw.ustring.gsub( short_description, '^([^%d])', function( first_char )
if case == 'upper' then
return mw.ustring.upper( first_char )
end
return mw.ustring.lower( first_char ) end
)
end
 
local functionmLang langify= require( args 'Module:Lang')
local function langify(args)
local lang = args.lang
local text = args.text
if isEmpty( lang ) or lang == 'en' then
return text
end
return mLang._lang {
lang,
Line 49 ⟶ 52:
end
 
local function annotatedLinkformatResult(result, argsdash, description, prefix_parentheses)
if notEmpty(description) then
if prefix_parentheses then
local startIdx = description:find("%(")
if startIdx then
local beforeParens = description:sub(1, startIdx - 2)
local insideParens = description:sub(startIdx, -1)
return result..' '..insideParens..dash..' '..beforeParens
end
end
return result..dash..' '..description
end
return result
end
 
local function annotatedLink(args)
local name = args.name
if isEmpty( name ) then
return alarmingMessage( 'requires a page name (including namespace)' )
end
-- In order to handle an attempt to annotate a template link,
-- already formatted with the likes of {{tl|<template name>}};
-- unescape name to make sense of braces in lua patern matching.
name = unescape( name )
if name:match( '^{%b{}}$' ) then
-- The possibility to extract useful data exists here: e.g. {{tl*|Template}}.
return alarmingMessage(
'requires only a page name (including namespace) without markup. ' ..
'If an attempt is being made to annotate a link to a template, '..
'provide only the template name with namespace e.g. "Template:Example"')
)
end
-- If a literal link was provided as name;
-- extract the content and apply it to name and display as appropriate.
local wikilink = mw.ustring.match( name, '^%[%[%s*:*%s*(.-)%s*%]%]$' )
if wikilink then
local link_name, link_display = unpack( mw.text.split( wikilink, '%s*|%s*' ) )
if link_name then
name = link_name end
if link_display and not args.display then args.display = link_display end
end
-- Exclude wikidata fallback for any specified list of link titles, unless explicity instructed that it's okay.
local not_wikidata_for_links_starting_with = args.not_wikidata_for_links_starting_with
if isEmpty( args.wikidata ) and notEmpty( not_wikidata_for_links_starting_with ) then
for only_explicit in hashDelimitedList( not_wikidata_for_links_starting_with ) do
if name:match( '^' .. only_explicit ) then args.only = 'explicit' break end
end
if link_display and isEmpty(args.display) then
end
args.display = link_display
-- Get the short description from Module:GetShortDescription.
local short_description = getShortDescription( {
objectify_alarm = true,
report_redlinks = true,
lang_italic = args.desc_lang_italic,
lang_nocat = args.desc_lang_nocat,
lang_size = args.desc_lang_size,
lang_cat = args.desc_lang_cat,
lang_rtl = args.desc_lang_rtl,
lang_no = args.desc_lang_no,
fallback = args.fallback,
prefer = args.prefer,
only = args.only,
name = name
} )
local redlink
local wikidata
if type( short_description ) == 'table' then
if short_description.alarm then return short_description.alarm end
redlink = short_description.redlink
wikidata = short_description.wikidata
if wikidata then
short_description = wikidata
local not_wikidata_descriptions_including = args.not_wikidata_descriptions_including
if notEmpty( not_wikidata_descriptions_including ) then
-- Case insentive matching of terms to filter
local upper_case_short_description = short_description:upper()
for exclusion in hashDelimitedList( not_wikidata_descriptions_including:upper() ) do
if upper_case_short_description:match( exclusion ) then short_description = '' break end
end
end
end
end
-- Prepare to concatenate.
local result
local is_template = name:match( '^Template:(.+)$' )
local template_link = args.template_link
if is_template and template_link ~= 'no' then
result = '{{' .. pipedLink( name, is_template ) .. '}}'
if template_link == 'code' then
result = '<code>' .. result .. '</code>'
end
else
local display = args.display
if isEmpty( display ) then
display = name
end
result = langify({
result = langify( {
lang = args.link_lang,
text = pipedLink( name, display ),
italic = args.link_lang_italic,
nocat = args.link_lang_nocat,
Line 137 ⟶ 122:
cat = args.link_lang_cat,
rtl = args.link_lang_rtl
} )
if notEmpty( args.quote ) then
result = '"' .. result .. '"'
end
local abbr = args.abbr
if notEmpty( abbr ) then
result = result .. ' (<abbr'
local abbr_title = args.abbr_title
if notEmpty( abbr_title ) then
result = result .. ' title="' .. abbr_title .. '"' end
end
result = result .. '>' .. abbr .. '</abbr>)'
result = result..'>'..abbr..'</abbr>)'
end
end
if isEmpty( result ) then
return alarmingMessage( 'could not create a link for "' .. name .. '"' )
end
local aka = args.aka
if notEmpty( aka ) then
result = result .. ', also known as ' .. langify( {
lang = args.aka_lang,
text = aka,
Line 162 ⟶ 153:
cat = args.aka_lang_cat,
rtl = args.aka_lang_rtl
} )
end
local wedge = args.wedge
if notEmpty( wedge ) then
result = result .. ', ' .. langify( {
lang = args.wedge_lang,
text = wedge,
Line 175 ⟶ 166:
cat = args.wedge_lang_cat,
rtl = args.wedge_lang_rtl
} )
end
-- Exclude wikidata fallback for any specified list of link titles,
-- unless explicity instructed that it's okay.
local not_wikidata_for_links_starting_with = args.not_wikidata_for_links_starting_with
if isEmpty(args.wikidata) and notEmpty(not_wikidata_for_links_starting_with) then
for only_explicit in hashDelimitedList(not_wikidata_for_links_starting_with) do
if name:match('^'..only_explicit) then
args.only = 'explicit'
break
end
end
end
-- Get the short description from Module:GetShortDescription.
local short_description = require('Module:GetShortDescription').main({
none_is_valid = args.none_is_valid,
none_is_nil = args.none_is_nil,
lang_italic = args.desc_lang_italic,
lang_nocat = args.desc_lang_nocat,
lang_size = args.desc_lang_size,
lang_cat = args.desc_lang_cat,
lang_rtl = args.desc_lang_rtl,
lang_no = args.desc_lang_no,
prefer = args.prefer,
only = args.only,
name = name
})
local dash = args.dash
if isEmpty(dash) then
dash = '&nbsp;–'
end
 
local fallback = args.fallback
if isEmpty( short_description ) then return result end
 
if isEmpty(short_description) or short_description.redlink then
return formatResult(result, dash, fallback, args.prefix_parentheses)
end
if short_description.alarm then
-- If Module:GetShortDescription indicates that name is for a nonexistent page; redlink will be true and there will be no short_description.
return short_description.alarm
if redlink then
end
-- red_cat_no may be provided as a '#' delimited list of titles to not categorise;
local maintenance = ''
-- the titles may be incomplete prefixes e.g. 'List of'.
local red_cat_no = args.red_cat_no
if short_description.redirected then
local current_title = mw.title.getCurrentTitle().prefixedText
maintenance = optionallyVisibleCategory(
-- If instructed to not categorise pages matching the current title:
'category-annotation-with-redirected-description',
if current_title and notEmpty( red_cat_no ) then
'Pages displaying short descriptions of redirect targets')
for no_cat in hashDelimitedList( red_cat_no ) do
end
if current_title:match( '^' .. no_cat ) then args.red_cat = 'no' break end
local fellback
if short_description.wikidata then
-- if short_description.fellback then
-- fellback = true
-- maintenance = maintenance..optionallyVisibleCategory(
-- 'category-wikidata-fallback-annotation',
-- 'Pages displaying wikidata descriptions as a fallback')
-- end
-- short_description = short_description.wikidata
-- Filter against likely rubbish wikidata descriptions.
-- local not_wikidata_descriptions_including = args.not_wikidata_descriptions_including
-- if notEmpty(not_wikidata_descriptions_including) then
-- Case insentive matching.
-- local lower_case_short_description = short_description:lower()
-- for exclusion in hashDelimitedList(not_wikidata_descriptions_including:lower()) do
-- if lower_case_short_description:match(exclusion) then
short_description = ''
-- break
-- end
-- end
-- end
if isEmpty(short_description) then
return formatResult(result, dash, fallback, args.prefix_parentheses)
end
else
short_description = short_description.explicit
end
local lower_case_name = name:lower()
if notEmpty(short_description) and not short_description:match(' ') then
-- Filter against likely rubbish single word descriptions.
local lower_case_short_description = short_description:lower()
local not_single_word = args.not_single_word
if notEmpty(not_single_word) then
-- Case insentive matching.
for single_word in hashDelimitedList(not_single_word:lower()) do
if single_word == lower_case_short_description then
short_description = ''
break
end
end
end
if isEmpty(short_description) or lower_case_name:match(lower_case_short_description) then
return formatResult(result, dash, fallback, args.prefix_parentheses)
-- If the invocation has not stated a value for red_cat; return the annotation we have thusfar with an appended maintenance category.
if isEmpty( args.red_cat ) then
return result .. optionallyVisibleCategory( 'category-annotated-redlinks', 'Pages displaying redlinks processed by Module:AnnotatedLink' )
end
if isEmpty(args.space_cat) then
return result
maintenance = maintenance..optionallyVisibleCategory(
'category-spaceless-annotation',
'Pages displaying short descriptions with no spaces')
end
end
if lower_case_name == short_description:lower() then
if fellback then
return formatResult(result, dash, fallback, args.prefix_parentheses)
end
maintenance = maintenance..optionallyVisibleCategory(
'category-annotation-matches-name',
'Pages displaying short descriptions matching their page name')
end
Line 209 ⟶ 289:
local desc_first_letter_case = args.desc_first_letter_case
if desc_first_letter_case == 'upper' or desc_first_letter_case == 'lower' then
short_description = handleFirstLetterCase( short_description, desc_first_letter_case )
end
return formatResult(result, dash, (short_description or fallback)..maintenance, args.prefix_parentheses)
if isEmpty( args.space_cat ) and not short_description:match( ' ' ) then
short_description = short_description .. '[[Category:Pages displaying short descriptions with no spaces via Module:AnnotatedLink]]'
end
if wikidata then
short_description = short_description .. optionallyVisibleCategory(
'category-wikidata-fallback-annotation', 'Pages displaying wikidata descriptions as a fallback via Module:Annotated link'
)
end
local dash = args.dash
if isEmpty( dash ) then dash = '&nbsp;–' end
return result .. dash .. ' ' .. short_description
end
 
local p = {}
 
function p.main( frame )
local args = getArgsrequire('Module:Arguments' ).getArgs(frame )
if isEmpty( args ) then
return alarmingMessage( 'could not getArgs' ) end -- This really would be alarming.
end
return annotatedLink( args )
return annotatedLink(args)
end