<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://salisford.net/index.php?action=history&amp;feed=atom&amp;title=Module%3AAnnotated_link</id>
	<title>Module:Annotated link - Revision history</title>
	<link rel="self" type="application/atom+xml" href="https://salisford.net/index.php?action=history&amp;feed=atom&amp;title=Module%3AAnnotated_link"/>
	<link rel="alternate" type="text/html" href="https://salisford.net/index.php?title=Module:Annotated_link&amp;action=history"/>
	<updated>2026-06-15T19:28:33Z</updated>
	<subtitle>Revision history for this page on the wiki</subtitle>
	<generator>MediaWiki 1.36.1</generator>
	<entry>
		<id>https://salisford.net/index.php?title=Module:Annotated_link&amp;diff=862&amp;oldid=prev</id>
		<title>Cascadia: 1 revision imported</title>
		<link rel="alternate" type="text/html" href="https://salisford.net/index.php?title=Module:Annotated_link&amp;diff=862&amp;oldid=prev"/>
		<updated>2023-04-05T14:40:16Z</updated>

		<summary type="html">&lt;p&gt;1 revision imported&lt;/p&gt;
&lt;table style=&quot;background-color: #fff; color: #202122;&quot; data-mw=&quot;interface&quot;&gt;
				&lt;tr class=&quot;diff-title&quot; lang=&quot;en&quot;&gt;
				&lt;td colspan=&quot;1&quot; style=&quot;background-color: #fff; color: #202122; text-align: center;&quot;&gt;← Older revision&lt;/td&gt;
				&lt;td colspan=&quot;1&quot; style=&quot;background-color: #fff; color: #202122; text-align: center;&quot;&gt;Revision as of 14:40, 5 April 2023&lt;/td&gt;
				&lt;/tr&gt;&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-notice&quot; lang=&quot;en&quot;&gt;&lt;div class=&quot;mw-diff-empty&quot;&gt;(No difference)&lt;/div&gt;
&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;</summary>
		<author><name>Cascadia</name></author>
	</entry>
	<entry>
		<id>https://salisford.net/index.php?title=Module:Annotated_link&amp;diff=861&amp;oldid=prev</id>
		<title>wp&gt;Fred Gandt: applied coding conventions now I have to look at it less often</title>
		<link rel="alternate" type="text/html" href="https://salisford.net/index.php?title=Module:Annotated_link&amp;diff=861&amp;oldid=prev"/>
		<updated>2023-02-15T20:13:45Z</updated>

		<summary type="html">&lt;p&gt;applied coding conventions now I have to look at it less often&lt;/p&gt;
&lt;p&gt;&lt;b&gt;New page&lt;/b&gt;&lt;/p&gt;&lt;div&gt;&lt;br /&gt;
local function pipedLink(name, display) return '[[:'..name..'|'..display..']]' end&lt;br /&gt;
&lt;br /&gt;
local function isEmpty(value) return value == nil or value == '' end&lt;br /&gt;
&lt;br /&gt;
local function notEmpty(value) return not isEmpty(value) end&lt;br /&gt;
&lt;br /&gt;
-- Unescape functionality grabbed from https://stackoverflow.com/a/14899740/1832568&lt;br /&gt;
local function unescape(str)&lt;br /&gt;
	str = string.gsub(str, '&amp;amp;#(%d+);', string.char)&lt;br /&gt;
	str = string.gsub(str, '&amp;amp;#x(%d+);', function(d) return string.char(tonumber(d, 16)) end)&lt;br /&gt;
	return str&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function hashDelimitedList(list_string) return mw.text.gsplit(unescape(list_string), '%s*#%s*') end&lt;br /&gt;
&lt;br /&gt;
local function alarmingMessage(message)&lt;br /&gt;
	return '&amp;lt;span style=&amp;quot;color:#d33&amp;quot;&amp;gt;[[Module:Annotated link]] '..message..'.&amp;lt;/span&amp;gt;'..&lt;br /&gt;
		'[[Category:Pages displaying alarming messages about Module:Annotated link]]'&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function optionallyVisibleCategory(class, category)&lt;br /&gt;
	return '&amp;lt;span style=&amp;quot;display:none&amp;quot; class=&amp;quot;'..class..'&amp;quot;&amp;gt;'..category..&lt;br /&gt;
		'&amp;lt;/span&amp;gt;[[Category:'..category..' via Module:Annotated link]]'&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function handleFirstLetterCase(short_description, case)&lt;br /&gt;
	return mw.ustring.gsub(short_description, '^([^%d])', function(first_char)&lt;br /&gt;
		if case == 'upper' then&lt;br /&gt;
			return mw.ustring.upper(first_char)&lt;br /&gt;
		end&lt;br /&gt;
		return mw.ustring.lower(first_char) end&lt;br /&gt;
	)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local mLang = require('Module:Lang')&lt;br /&gt;
local function langify(args)&lt;br /&gt;
	local lang = args.lang&lt;br /&gt;
	local text = args.text&lt;br /&gt;
	if isEmpty(lang) or lang == 'en' then&lt;br /&gt;
		return text&lt;br /&gt;
	end&lt;br /&gt;
	return mLang._lang {&lt;br /&gt;
		lang,&lt;br /&gt;
		text,&lt;br /&gt;
		italic = args.italic,&lt;br /&gt;
		nocat = args.nocat,&lt;br /&gt;
		size = args.size,&lt;br /&gt;
		cat = args.cat,&lt;br /&gt;
		rtl = args.rtl&lt;br /&gt;
	}&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function formatResult(result, dash, description)&lt;br /&gt;
	if notEmpty(description) then&lt;br /&gt;
		return result..dash..' '..description&lt;br /&gt;
	end&lt;br /&gt;
	return result&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function annotatedLink(args)&lt;br /&gt;
	local name = args.name&lt;br /&gt;
	if isEmpty(name) then&lt;br /&gt;
		return alarmingMessage('requires a page name (including namespace)')&lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	-- In order to handle an attempt to annotate a template link&lt;br /&gt;
	-- already formatted with the likes of {{tl|&amp;lt;template name&amp;gt;}};&lt;br /&gt;
	-- unescape name to make sense of braces in lua patern matching.&lt;br /&gt;
	name = unescape(name)&lt;br /&gt;
	&lt;br /&gt;
	if name:match('^{%b{}}$') then&lt;br /&gt;
		-- The possibility to extract useful data exists here: e.g. {{tl*|Template}}.&lt;br /&gt;
		return alarmingMessage(&lt;br /&gt;
			'requires only a page name (including namespace) without markup. '..&lt;br /&gt;
			'If an attempt is being made to annotate a link to a template, '..&lt;br /&gt;
			'provide only the template name with namespace e.g. &amp;quot;Template:Example&amp;quot;')&lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	-- If a literal link was provided as name;&lt;br /&gt;
	-- extract the content and apply it to name and display as appropriate.&lt;br /&gt;
	local wikilink = mw.ustring.match(name, '^%[%[%s*:*%s*(.-)%s*%]%]$')&lt;br /&gt;
	if wikilink then&lt;br /&gt;
		local link_name, link_display = unpack(mw.text.split(wikilink, '%s*|%s*'))&lt;br /&gt;
		if link_name then&lt;br /&gt;
			name = link_name&lt;br /&gt;
		end&lt;br /&gt;
		if link_display and isEmpty(args.display) then&lt;br /&gt;
			args.display = link_display&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	-- Prepare to concatenate.&lt;br /&gt;
	local result&lt;br /&gt;
	&lt;br /&gt;
	local is_template = name:match('^Template:(.+)$')&lt;br /&gt;
	local template_link = args.template_link&lt;br /&gt;
	if is_template and template_link ~= 'no' then&lt;br /&gt;
		result = '{{'..pipedLink(name, is_template)..'}}'&lt;br /&gt;
		if template_link == 'code' then&lt;br /&gt;
			result = '&amp;lt;code&amp;gt;'..result..'&amp;lt;/code&amp;gt;'&lt;br /&gt;
		end&lt;br /&gt;
	else&lt;br /&gt;
		local display = args.display&lt;br /&gt;
		if isEmpty(display) then&lt;br /&gt;
			display = name&lt;br /&gt;
		end&lt;br /&gt;
		result = langify({&lt;br /&gt;
			lang = args.link_lang,&lt;br /&gt;
			text = pipedLink(name, display),&lt;br /&gt;
			italic = args.link_lang_italic,&lt;br /&gt;
			nocat = args.link_lang_nocat,&lt;br /&gt;
			size = args.link_lang_size,&lt;br /&gt;
			cat = args.link_lang_cat,&lt;br /&gt;
			rtl = args.link_lang_rtl&lt;br /&gt;
		})&lt;br /&gt;
		&lt;br /&gt;
		if notEmpty(args.quote) then&lt;br /&gt;
			result = '&amp;quot;'..result..'&amp;quot;'&lt;br /&gt;
		end&lt;br /&gt;
		&lt;br /&gt;
		local abbr = args.abbr&lt;br /&gt;
		if notEmpty(abbr) then&lt;br /&gt;
			result = result..' (&amp;lt;abbr'&lt;br /&gt;
			local abbr_title = args.abbr_title&lt;br /&gt;
			if notEmpty(abbr_title) then&lt;br /&gt;
				result = result..' title=&amp;quot;'..abbr_title..'&amp;quot;'&lt;br /&gt;
			end&lt;br /&gt;
			result = result..'&amp;gt;'..abbr..'&amp;lt;/abbr&amp;gt;)'&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	if isEmpty(result) then&lt;br /&gt;
		return alarmingMessage('could not create a link for &amp;quot;'..name..'&amp;quot;')&lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	local aka = args.aka&lt;br /&gt;
	if notEmpty(aka) then&lt;br /&gt;
		result = result..', also known as '..langify({&lt;br /&gt;
			lang = args.aka_lang,&lt;br /&gt;
			text = aka,&lt;br /&gt;
			italic = args.aka_lang_italic,&lt;br /&gt;
			nocat = args.aka_lang_nocat,&lt;br /&gt;
			size = args.aka_lang_size,&lt;br /&gt;
			cat = args.aka_lang_cat,&lt;br /&gt;
			rtl = args.aka_lang_rtl&lt;br /&gt;
		})&lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	local wedge = args.wedge&lt;br /&gt;
	if notEmpty(wedge) then&lt;br /&gt;
		result = result..', '..langify({&lt;br /&gt;
			lang = args.wedge_lang,&lt;br /&gt;
			text = wedge,&lt;br /&gt;
			italic = args.wedge_lang_italic,&lt;br /&gt;
			nocat = args.wedge_lang_nocat,&lt;br /&gt;
			size = args.wedge_lang_size,&lt;br /&gt;
			cat = args.wedge_lang_cat,&lt;br /&gt;
			rtl = args.wedge_lang_rtl&lt;br /&gt;
		})&lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	-- Exclude wikidata fallback for any specified list of link titles,&lt;br /&gt;
	-- unless explicity instructed that it's okay.&lt;br /&gt;
	local not_wikidata_for_links_starting_with = args.not_wikidata_for_links_starting_with&lt;br /&gt;
	if isEmpty(args.wikidata) and notEmpty(not_wikidata_for_links_starting_with) then&lt;br /&gt;
		for only_explicit in hashDelimitedList(not_wikidata_for_links_starting_with) do&lt;br /&gt;
			if name:match('^'..only_explicit) then&lt;br /&gt;
				args.only = 'explicit'&lt;br /&gt;
				break&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	-- Get the short description from Module:GetShortDescription.&lt;br /&gt;
	local short_description = require('Module:GetShortDescription').main({&lt;br /&gt;
		none_is_valid = args.none_is_valid,&lt;br /&gt;
		none_is_nil = args.none_is_nil,&lt;br /&gt;
		lang_italic = args.desc_lang_italic,&lt;br /&gt;
		lang_nocat = args.desc_lang_nocat,&lt;br /&gt;
		lang_size = args.desc_lang_size,&lt;br /&gt;
		lang_cat = args.desc_lang_cat,&lt;br /&gt;
		lang_rtl = args.desc_lang_rtl,&lt;br /&gt;
		lang_no = args.desc_lang_no,&lt;br /&gt;
		prefer = args.prefer,&lt;br /&gt;
		only = args.only,&lt;br /&gt;
		name = name&lt;br /&gt;
	})&lt;br /&gt;
	&lt;br /&gt;
	local dash = args.dash&lt;br /&gt;
	if isEmpty(dash) then&lt;br /&gt;
		dash = '&amp;amp;nbsp;–'&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local fallback = args.fallback&lt;br /&gt;
&lt;br /&gt;
	if isEmpty(short_description) or short_description.redlink then&lt;br /&gt;
		return formatResult(result, dash, fallback)&lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	if short_description.alarm then&lt;br /&gt;
		return short_description.alarm&lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	local maintenance = ''&lt;br /&gt;
	&lt;br /&gt;
	if short_description.redirected then&lt;br /&gt;
		maintenance = optionallyVisibleCategory(&lt;br /&gt;
			'category-annotation-with-redirected-description',&lt;br /&gt;
			'Pages displaying short descriptions of redirect targets')&lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	local fellback&lt;br /&gt;
	&lt;br /&gt;
	if short_description.wikidata then&lt;br /&gt;
		if short_description.fellback then&lt;br /&gt;
			fellback = true&lt;br /&gt;
			maintenance = maintenance..optionallyVisibleCategory(&lt;br /&gt;
				'category-wikidata-fallback-annotation',&lt;br /&gt;
				'Pages displaying wikidata descriptions as a fallback')&lt;br /&gt;
		end&lt;br /&gt;
		short_description = short_description.wikidata&lt;br /&gt;
		-- Filter against likely rubbish wikidata descriptions.&lt;br /&gt;
		local not_wikidata_descriptions_including = args.not_wikidata_descriptions_including&lt;br /&gt;
		if notEmpty(not_wikidata_descriptions_including) then&lt;br /&gt;
			-- Case insentive matching.&lt;br /&gt;
			local lower_case_short_description = short_description:lower()&lt;br /&gt;
			for exclusion in hashDelimitedList(not_wikidata_descriptions_including:lower()) do&lt;br /&gt;
				if lower_case_short_description:match(exclusion) then&lt;br /&gt;
					short_description = ''&lt;br /&gt;
					break&lt;br /&gt;
				end&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
		if isEmpty(short_description) then&lt;br /&gt;
			return formatResult(result, dash, fallback)&lt;br /&gt;
		end&lt;br /&gt;
	else&lt;br /&gt;
		short_description = short_description.explicit&lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	local lower_case_name = name:lower()&lt;br /&gt;
	&lt;br /&gt;
	if notEmpty(short_description) and not short_description:match(' ') then&lt;br /&gt;
		-- Filter against likely rubbish single word descriptions.&lt;br /&gt;
		local lower_case_short_description = short_description:lower()&lt;br /&gt;
		local not_single_word = args.not_single_word&lt;br /&gt;
		if notEmpty(not_single_word) then&lt;br /&gt;
			-- Case insentive matching.&lt;br /&gt;
			for single_word in hashDelimitedList(not_single_word:lower()) do&lt;br /&gt;
				if single_word == lower_case_short_description then&lt;br /&gt;
					short_description = ''&lt;br /&gt;
					break&lt;br /&gt;
				end&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
		if isEmpty(short_description) or lower_case_name:match(lower_case_short_description) then&lt;br /&gt;
			return formatResult(result, dash, fallback)&lt;br /&gt;
		end&lt;br /&gt;
		if isEmpty(args.space_cat) then&lt;br /&gt;
			maintenance = maintenance..optionallyVisibleCategory(&lt;br /&gt;
				'category-spaceless-annotation',&lt;br /&gt;
				'Pages displaying short descriptions with no spaces')&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	if lower_case_name == short_description:lower() then&lt;br /&gt;
		if fellback then&lt;br /&gt;
			return formatResult(result, dash, fallback)&lt;br /&gt;
		end&lt;br /&gt;
		maintenance = maintenance..optionallyVisibleCategory(&lt;br /&gt;
			'category-annotation-matches-name',&lt;br /&gt;
			'Pages displaying short descriptions matching their page name')&lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
-- Short descriptions on en Wikipedia should be formatted with an uppercase first letter, but&lt;br /&gt;
-- the typical application of this module will require the first character to be lowercase, but&lt;br /&gt;
-- some descriptions may start with proper names and should start with an uppercase letter even if used in an annotaion.&lt;br /&gt;
-- By default; this module will not affect the first letter case of descriptions retrieved by Module:GetShortDescription, but&lt;br /&gt;
-- the first letter case may be transformed explicitly if required.&lt;br /&gt;
	local desc_first_letter_case = args.desc_first_letter_case&lt;br /&gt;
	if desc_first_letter_case == 'upper' or desc_first_letter_case == 'lower' then&lt;br /&gt;
		short_description = handleFirstLetterCase(short_description, desc_first_letter_case)&lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	return formatResult(result, dash, (short_description or fallback)..maintenance)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local p = {}&lt;br /&gt;
&lt;br /&gt;
function p.main(frame)&lt;br /&gt;
	local args = require('Module:Arguments' ).getArgs(frame)&lt;br /&gt;
	if isEmpty(args) then&lt;br /&gt;
		return alarmingMessage('could not getArgs') -- This really would be alarming.&lt;br /&gt;
	end&lt;br /&gt;
	return annotatedLink(args)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
return p&lt;/div&gt;</summary>
		<author><name>wp&gt;Fred Gandt</name></author>
	</entry>
</feed>