|
|
Line 1: |
Line 1: |
| | <includeonly>{{ {{{|safesubst:}}}#invoke:Annotated link | main |
|
| |
|
| local function pipedLink(name, display) return '[[:'..name..'|'..display..']]' end
| | | wikidata = {{{ wikidata |}}} |
| | | not_wikidata_for_links_starting_with = List of # Index of # Glossary of # Outline of # Timeline of # History of |
| | | not_wikidata_descriptions_including = wikimedia # mediawiki # wikipedia # list # index # glossary # outline # overview |
|
| |
|
| local function isEmpty(value) return value == nil or value == '' end
| | | space_cat = {{{ space_cat | {{{ space-cat |}}} }}} |
| | | not_single_word = organization # organisation # term |
|
| |
|
| local function notEmpty(value) return not isEmpty(value) end
| | | none_is_valid = yes |
| | | none_is_nil = yes |
|
| |
|
| -- Unescape functionality grabbed from https://stackoverflow.com/a/14899740/1832568
| | | name = {{{ 1 | {{{ name | {{{ title |}}} }}} }}} |
| local function unescape(str)
| | | display = {{{ 2 | {{{ display | {{{ disp |}}} }}} }}} |
| str = string.gsub(str, '&#(%d+);', string.char)
| | | dash = {{{ 3 | {{{ dash | {{{ comma |}}} }}} }}} |
| 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
| | | template_link = {{{ template_link | {{{ template-link | {{{ tl |}}} }}} }}} |
|
| |
|
| local function alarmingMessage(message)
| | | link_lang = {{{ link_lang | {{{ link-lang | {{{ ll |}}} }}} }}} |
| return '<span style="color:#d33">[[Module:Annotated link]] '..message..'.</span>'..
| | | link_lang_italic = {{{ link_lang_italic | {{{ link-lang-italic | {{{ lli |}}} }}} }}} |
| '[[Category:Pages displaying alarming messages about Module:Annotated link]]'
| | | link_lang_nocat = {{{ link_lang_nocat | {{{ link-lang-nocat | {{{ llnc |}}} }}} }}} |
| end
| | | link_lang_size = {{{ link_lang_size | {{{ link-lang-size | {{{ lls |}}} }}} }}} |
| | | link_lang_cat = {{{ link_lang_cat | {{{ link-lang-cat | {{{ llc |}}} }}} }}} |
| | | link_lang_rtl = {{{ link_lang_rtl | {{{ link-lang-rtl | {{{ llr |}}} }}} }}} |
|
| |
|
| local function optionallyVisibleCategory(class, category)
| | | quote = {{{ quote | {{{ quote_link | {{{ quote-link | {{{ ql |}}} }}} }}} }}} |
| return '<span style="display:none" class="'..class..'">'..category..
| |
| '</span>[[Category:'..category..' via Module:Annotated link]]'
| |
| end
| |
|
| |
|
| local function handleFirstLetterCase(short_description, case)
| | | abbr = {{{ abbr | {{{ abbreviation |}}} }}} |
| return mw.ustring.gsub(short_description, '^([^%d])', function(first_char)
| | | abbr_title = {{{ abbr_title | {{{ abbr-title | {{{ abbreviation_title | {{{ abbreviation-title | {{{ at |}}} }}} }}} }}} }}} |
| if case == 'upper' then
| |
| return mw.ustring.upper(first_char)
| |
| end
| |
| return mw.ustring.lower(first_char) end
| |
| )
| |
| end
| |
|
| |
|
| local mLang = require('Module:Lang')
| | | aka = {{{ aka |}}} |
| local function langify(args)
| | | aka_lang = {{{ aka_lang | {{{ aka-lang | {{{ al |}}} }}} }}} |
| local lang = args.lang
| | | aka_lang_italic = {{{ aka_lang_italic | {{{ aka-lang-italic | {{{ ali |}}} }}} }}} |
| local text = args.text
| | | aka_lang_nocat = {{{ aka_lang_nocat | {{{ aka-lang-nocat | {{{ alnc |}}} }}} }}} |
| if isEmpty(lang) or lang == 'en' then
| | | aka_lang_size = {{{ aka_lang_size | {{{ aka-lang-size | {{{ als |}}} }}} }}} |
| return text
| | | aka_lang_cat = {{{ aka_lang_cat | {{{ aka-lang-cat | {{{ alc |}}} }}} }}} |
| end
| | | aka_lang_rtl = {{{ aka_lang_rtl | {{{ aka-lang-rtl | {{{ alr |}}} }}} }}} |
| return mLang._lang {
| |
| lang,
| |
| text,
| |
| italic = args.italic,
| |
| nocat = args.nocat,
| |
| size = args.size,
| |
| cat = args.cat,
| |
| rtl = args.rtl
| |
| }
| |
| end
| |
|
| |
|
| local function formatResult(result, dash, description, prefix_parentheses)
| | | wedge = {{{ wedge | {{{ insert | {{{ extra |}}} }}} }}} |
| if notEmpty(description) then
| | | wedge_lang = {{{ wedge_lang | {{{ wedge-lang | {{{ insert_lang | {{{ insert-lang | {{{ extra_lang | {{{ extra-lang | {{{ wl |}}} }}} }}} }}} }}} }}} }}} |
| if prefix_parentheses then
| | | wedge_lang_italic = {{{ wedge_lang_italic | {{{ wedge-lang-italic | {{{ insert_lang_italic | {{{ insert-lang-italic | {{{ extra_lang_italic | {{{ extra-lang-italic | {{{ wli |}}} }}} }}} }}} }}} }}} }}} |
| local startIdx = description:find("%(")
| | | wedge_lang_nocat = {{{ wedge_lang_nocat | {{{ wedge-lang_nocat | {{{ insert_lang_nocat | {{{ insert-lang-nocat | {{{ extra_lang_nocat | {{{ extra-lang-nocat | {{{ wlnc |}}} }}} }}} }}} }}} }}} }}} |
| if startIdx then
| | | wedge_lang_size = {{{ wedge_lang_size | {{{ wedge-lang-size | {{{ insert_lang_size | {{{ insert-lang-size | {{{ extra_lang_size | {{{ extra-lang-size | {{{ wls |}}} }}} }}} }}} }}} }}} }}} |
| local beforeParens = description:sub(1, startIdx - 2)
| | | wedge_lang_cat = {{{ wedge_lang_cat | {{{ wedge-lang-cat | {{{ insert_lang_cat | {{{ insert-lang-cat | {{{ extra_lang_cat | {{{ extra-lang-cat | {{{ wlc |}}} }}} }}} }}} }}} }}} }}} |
| local insideParens = description:sub(startIdx, -1)
| | | wedge_lang_rtl = {{{ wedge_lang_rtl | {{{ wedge-lang-rtl | {{{ insert_lang_rtl | {{{ insert-lang-rtl | {{{ extra_lang_rtl | {{{ extra-lang-rtl | {{{ wlr |}}} }}} }}} }}} }}} }}} }}} |
| return result..' '..insideParens..dash..' '..beforeParens
| |
| end
| |
| end
| |
| return result..dash..' '..description
| |
| end
| |
| return result
| |
| end
| |
|
| |
|
| local function annotatedLink(args)
| | | desc_first_letter_case = {{{ desc_first_letter_case | {{{ desc-first-letter-case | {{{ desc_case | {{{ desc-case | {{{ case | {{{ dflc |}}} }}} }}} }}} }}} }}} |
| 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 isEmpty(args.display) then
| |
| args.display = link_display
| |
| 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({
| |
| lang = args.link_lang,
| |
| text = pipedLink(name, display),
| |
| italic = args.link_lang_italic,
| |
| nocat = args.link_lang_nocat,
| |
| size = args.link_lang_size,
| |
| 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
| |
| 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,
| |
| italic = args.aka_lang_italic,
| |
| nocat = args.aka_lang_nocat,
| |
| size = args.aka_lang_size,
| |
| 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,
| |
| italic = args.wedge_lang_italic,
| |
| nocat = args.wedge_lang_nocat,
| |
| size = args.wedge_lang_size,
| |
| 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 = ' –'
| |
| end
| |
|
| |
|
| local fallback = args.fallback
| | | only = {{{ only |}}} |
| | | prefer = {{{ prefer |}}} |
| | | fallback = {{{ fallback |}}} |
|
| |
|
| if isEmpty(short_description) or short_description.redlink then
| | | desc_lang_italic = {{{ desc_lang_italic | {{{ desc-lang-italic | {{{ dli |}}} }}} }}} |
| return formatResult(result, dash, fallback, args.prefix_parentheses)
| | | desc_lang_nocat = {{{ desc_lang_nocat | {{{ desc-lang-nocat | {{{ dlnc |}}} }}} }}} |
| end
| | | desc_lang_size = {{{ desc_lang_size | {{{ desc-lang-size | {{{ dls |}}} }}} }}} |
|
| | | desc_lang_cat = {{{ desc_lang_cat | {{{ desc-lang-cat | {{{ dlc |}}} }}} }}} |
| if short_description.alarm then
| | | desc_lang_rtl = {{{ desc_lang_rtl | {{{ desc-lang-rtl | {{{ dlr |}}} }}} }}} |
| return short_description.alarm
| | | desc_lang_no = {{{ desc_lang_no | {{{ desc-lang-no | {{{ dlno |}}} }}} }}} |
| end
| |
|
| |
| local maintenance = ''
| |
|
| |
| if short_description.redirected then
| |
| maintenance = optionallyVisibleCategory(
| |
| 'category-annotation-with-redirected-description',
| |
| 'Pages displaying short descriptions of redirect targets')
| |
| 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)
| |
| end
| |
| if isEmpty(args.space_cat) then
| |
| 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
| |
|
| |
| -- Short descriptions on en Wikipedia should be formatted with an uppercase first letter, but
| |
| -- the typical application of this module will require the first character to be lowercase, but
| |
| -- some descriptions may start with proper names and should start with an uppercase letter even if used in an annotaion.
| |
| -- By default; this module will not affect the first letter case of descriptions retrieved by Module:GetShortDescription, but
| |
| -- the first letter case may be transformed explicitly if required.
| |
| 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)
| |
| end
| |
|
| |
|
| local p = {}
| | }}</includeonly><noinclude>{{documentation}}</noinclude> |
| | |
| function p.main(frame)
| |
| local args = require('Module:Arguments' ).getArgs(frame)
| |
| if isEmpty(args) then
| |
| return alarmingMessage('could not getArgs') -- This really would be alarming.
| |
| end
| |
| return annotatedLink(args)
| |
| end
| |
| | |
| return p
| |