Module:UtilsMarkup/Link

From Zelda Wiki, the Zelda encyclopedia
Jump to: navigation, search

This submodule provides utility functions for formatting text with wiki markup.

This module exports the following functions.

link

link(page, [display], [noBacklink])

Parameters
  • page
    The link target. Can be the name of a page on the wiki or an external URL.
  • [display=page]
    The text to display for the link.
  • [noBacklink]
    When true, renders an internal link such that it does not register on the Special:WhatLinksHere of the target page.

    Use only when certain that the page exists. This method cannot render red-links (i.e. distinguish non-existent pages).

Returns
  • A string of wikitext that evaluates to a link. Will display a red link if the target is an internal link to a page that doesn't exist.
Examples
InputOutputResultStatus
Internal link
link("Princess Zelda")
"[[Princess Zelda]]"
Princess Zelda
Green check.svg
Link to page that doesn't exist
link("Flippityfloppityfloo")
"[[Flippityfloppityfloo]]"
Flippityfloppityfloo
Green check.svg
Piped link
link("Princess Zelda", "Zelda")
"[[Princess Zelda|Zelda]]"
Zelda
Green check.svg
Category link
link("Category:Items")
"[[:Category:Items]]"
Category:Items
Green check.svg
Category link without prefix
link("Category:Items", "")
"[[:Category:Items|Items]]"
Items
Green check.svg
Category link with display text
link(
  "Category:Items in Breath of the Wild",
  "Items in ''Breath of the Wild''"
)
"[[:Category:Items in Breath of the Wild|Items in ''Breath of the Wild'']]"
Items in Breath of the Wild
Green check.svg
File link (to file description)
link("File:MM Deku Butler Artwork.png")
"[[:File:MM Deku Butler Artwork.png]]"
File:MM Deku Butler Artwork.png
Green check.svg
External link
link("https://www.mariowiki.com/Thwomp", "Thwomp")
"[https://www.mariowiki.com/Thwomp Thwomp]"
Thwomp
Green check.svg
Looks like an internal link, but it's actually an external link. This is to avoid Special:WhatLinksHere
link("Princess Zelda", "Zelda", true)
Expected
'<span class="plainlinks">[https://zelda.gamepedia.com/Princess_Zelda Zelda]</span>'
Actual
'<span class="plainlinks">[https://zelda.fandom.com/Princess_Zelda Zelda]</span>'
Zelda
TFH Red Link desperate.png
When noBacklink is set to true, red links are not rendered for pages which do not exist.
link("Flippityfloppityfloo", nil, true)
Expected
'<span class="plainlinks">[https://zelda.gamepedia.com/Flippityfloppityfloo Flippityfloppityfloo]</span>'
Actual
'<span class="plainlinks">[https://zelda.fandom.com/Flippityfloppityfloo Flippityfloppityfloo]</span>'
Flippityfloppityfloo
TFH Red Link desperate.png

sectionLink

sectionLink(page, [section], [display])

Parameters
Returns
  • A string of wikitext rendering a section link.
Examples
InputOutputResultStatus
sectionLink("Link", "Ocarina of Time", "Hero of Time")
"[[Link#Ocarina of Time|Hero of Time]]"
Hero of Time
Green check.svg
sectionLink("Link", nil, "Hero of Time")
"[[Link|Hero of Time]]"
Hero of Time
Green check.svg
sectionLink("Link", "")
"[[Link#]]"
Link#
Green check.svg

file

file(name, [options])

Parameters
Returns
  • A string of wikitext that renders a thumbnail for the file.
Examples
InputOutputResultStatus
file("File:ALttP Ganon Sprite.png")
"[[File:ALttP Ganon Sprite.png]]"
ALttP Ganon Sprite.png
Green check.svg
file(
  "ALttP Ganon Sprite.png",
  {
    caption = "Ganon",
    link = "",
  }
)
"[[File:ALttP Ganon Sprite.png|link=|Ganon]]"
Ganon
Green check.svg
file(
  "File:TWW Great Fairy Figurine Model.png",
  {
    size = "100px",
    link = "Great Fairy",
  }
)
"[[File:TWW Great Fairy Figurine Model.png|100px|link=Great Fairy]]"
TWW Great Fairy Figurine Model.png
Green check.svg
file(
  "File:TWW Great Fairy Figurine Model.png",
  {
    noBacklink = true,
    size = "100px",
    link = "Great Fairy",
  }
)
Expected
"[[File:TWW Great Fairy Figurine Model.png|100px|link=https://zelda.gamepedia.com/Great_Fairy]]"
Actual
"[[File:TWW Great Fairy Figurine Model.png|100px|link=https://zelda.fandom.com/wiki/Great_Fairy]]"
TWW Great Fairy Figurine Model.png
TFH Red Link desperate.png

category

category(name, [sortKey])

Parameters
  • name
    The name of the category to link to (with or without namespace prefix).
  • [sortKey]
    A custom sort key for the category entry.
Returns
  • A category link—the kind that adds a category to a page. For the other kind that links to the actual category page, use link.
Examples
InputOutputStatus
Category link from category name
category("Items")
"[[Category:Items]]"
Green check.svg
Category link from category name with namespace prefix
category("Category:Items")
"[[Category:Items]]"
Green check.svg
Category link with sort key
category("Items", "*")
"[[Category:Items|*]]"
Green check.svg

categories

categories(names)

Parameters
  • names
    An array of category names, with or without the namespace prefix.
Returns
  • A concatenated string of category links.
Examples
InputOutputStatus
categories({"Link", "Category:Zelda", "Category:Ganon"})
"[[Category:Link]][[Category:Zelda]][[Category:Ganon]]"
Green check.svg
categories({})
""
Green check.svg

containsLink

containsLink(wikitext)

Returns
  • Given a string of wikitext, returns true if it contains a link, false otherwise.
Examples
InputOutputStatus
containsLink("There is a [[Link]]")
true
Green check.svg
containsLink("[Link] is not a link but rather an idication of replaced words in a quote.")
false
Green check.svg

killBacklinks

killBacklinks(wikitext)

Parameters
Returns
  • The same wikitext but with all the internal links formatted as external links, to avoid additions to Special:WhatLinksHere.
Examples
InputOutputResultStatus
Escapes both normal links and red links
killBacklinks("[[Link]], [[Princess Zelda|Zelda]], and [[Jean-Guy Rubber Boots]]")
Expected
'<span class="plainlinks">[https://zelda.gamepedia.com/Link Link]</span>, <span class="plainlinks">[https://zelda.gamepedia.com/Princess_Zelda Zelda]</span>, and <span class="plainlinks new">[https://zelda.gamepedia.com/Jean-Guy_Rubber_Boots?action=edit&redlink=1 Jean-Guy Rubber Boots]</span>'
Actual
'<span class="plainlinks">[https://zelda.fandom.com/Link Link]</span>, <span class="plainlinks">[https://zelda.fandom.com/Princess_Zelda Zelda]</span>, and <span class="plainlinks">[https://zelda.fandom.com/Jean-Guy_Rubber_Boots Jean-Guy Rubber Boots]</span>'
Link, Zelda, and Jean-Guy Rubber Boots
TFH Red Link desperate.png
Does not escape file links or category links
killBacklinks("[[Category:Link]] and [[File:SS Blessed Butterfly Icon.png]]")
"[[Category:Link]] and [[File:SS Blessed Butterfly Icon.png]]"
and SS Blessed Butterfly Icon.png
Green check.svg
Escapes visible file and category links
killBacklinks("[[:Category:Link]], [[:Category:Princess Zelda|Zelda]], and [[:File:SS Blessed Butterfly Icon.png]]")
Expected
'<span class="plainlinks">[https://zelda.gamepedia.com/Category:Link Category:Link]</span>, <span class="plainlinks">[https://zelda.gamepedia.com/Category:Princess_Zelda Zelda]</span>, and <span class="plainlinks">[https://zelda.gamepedia.com/File:SS_Blessed_Butterfly_Icon.png File:SS Blessed Butterfly Icon.png]</span>'
Actual
'<span class="plainlinks">[https://zelda.fandom.com/Category:Link Category:Link]</span>, <span class="plainlinks">[https://zelda.fandom.com/Category:Princess_Zelda Zelda]</span>, and <span class="plainlinks">[https://zelda.fandom.com/File:SS_Blessed_Butterfly_Icon.png File:SS Blessed Butterfly Icon.png]</span>'
Category:Link, Zelda, and File:SS Blessed Butterfly Icon.png
TFH Red Link desperate.png
Does not affect interwiki links
killBacklinks("[[metroidwiki:Chozo|Chozo]]")
"[[metroidwiki:Chozo|Chozo]]"
Chozo
Green check.svg

stripCategories

stripCategories(wikitext)

Parameters
Returns
  • The string of wiki markup with all the category links removed (not including visual links to category description pages).
  • A table array of direct links to the removed categories.
Examples
InputOutputStatus
Basic use case
stripCategories("<[[Category:Link]][[Category:Princess Zelda]][[Category:Link]]>")
"<>"
Green check.svg
{
  "[[:Category:Link]]",
  "[[:Category:Princess Zelda]]",
}
Green check.svg
Does not affect visual links to category description pages
stripCategories("[[:Category:Link]] and [[:Category:Princess Zelda]]")
"[[:Category:Link]] and [[:Category:Princess Zelda]]"
Green check.svg
{}
Green check.svg

local p = {}
local h = {}

local utilsMarkup = require("Module:UtilsMarkup/Format")
local utilsPage = require("Module:UtilsPage")
local utilsString = require("Module:UtilsString")
local utilsTable = require("Module:UtilsTable")

-- If backlink == false then this print an external link that looks like an internal one 
-- (useful for creating links that do not appear in Special:WhatLinksHere)
function p.link(link, text, noBacklink)
	if not link then
		return ""
	end
	link = mw.text.trim(link)
	if link:find('http') then
		return h.externalLink(link, text)
	end
	if noBacklink then
		local url = utilsPage.fullUrl(link)
		local externalLink = h.externalLink(url, text or link)
		local formattedLink = utilsMarkup.class("plainlinks", externalLink)
		return formattedLink
	end
	local title = mw.title.new(link) or link
	if title.nsText == "File" or title.nsText == "Category" then
		link = ":" .. link
		if text == "" then
			text = title.text
		end
	end
	return h.internalLink(link, text)
end

function p.sectionLink(page, section, display)
	local target = page
	if section then
		target = target .. "#" .. section
	end
	return p.link(target, display)
end

function h.internalLink(page, display)
	if not page then
		return ""
	end
	if not display then
		return ("[[%s]]"):format(page)
	end
	return ('[[%s|%s]]'):format(page, display)
end

function h.externalLink(page, display)
	if not page then
		return ""
	end
	if not display then
		return page
	end
	return ('[%s %s]'):format(page, display)
end

function p.file(name, options)
	options = options or {}
	local size = options.size
	local link = options.link
	local caption = options.caption
	local noBacklink = options.noBacklink
	
	if not utilsString.startsWith(name, "File:") then
		name = "File:" .. name
	end
	if link and noBacklink then
		link = tostring(mw.uri.fullUrl(link))
	end
	local linkParts = utilsTable.compact({
		name,
		size,
		link and "link="..link,
		caption,
	})
	local fileLink = "[[" .. table.concat(linkParts, "|") .. "]]"
	return fileLink
end

function p.category(name, sortKey)
	if not utilsString.startsWith(name, "Category:") then
		name = "Category:" .. name
	end
	return h.internalLink(name, sortKey)
end

function p.categories(categoryNames)
	local categoryLinks = utilsTable.map(categoryNames, p.category)
	return table.concat(categoryLinks)
end

function p.containsLink(wikitext, external)
	return not not wikitext:find("%[%[.*%]%]")
end

function p.killBacklinks(wikitext)
	local link = string.match(wikitext, "%[%[[^%]]*%]%]")
	if not link then
		return wikitext
	end
	local startPos, endPos = string.find(wikitext, link, 1, true)
	local before = string.sub(wikitext, 1, startPos -1)
	local after = string.sub(wikitext, endPos + 1)
	local externalLink = p.killBacklink(link)
	return before .. externalLink .. p.killBacklinks(after)
end

function p.killBacklink(link)
	local linkParts = utilsString.trim(link, "][")
	local pipe = string.find(linkParts, "|")
	local page = string.sub(linkParts, 1, pipe and pipe - 1)
	local display = pipe and string.sub(linkParts, pipe + 1)
	local startsWithColon = utilsString.startsWith(page, ":")
	page = string.gsub(page, "^:", "")
	local title = mw.title.new(page)
	if not title or title.interwiki ~= "" or not startsWithColon and (title.nsText == "Category" or title.nsText == "File") then
		return link
	end
	return p.link(page, display or page, true)
end

local categoryPattern = "%[%[Category:[^%]]*%]%]"
function p.stripCategories(wikitext)
	local categories = {}
	for category in string.gmatch(wikitext, categoryPattern) do
		local categoryWithoutSortKey = string.gsub(category, "|[^%]]*%]%]", "]]")
		local categoryLink = string.gsub(categoryWithoutSortKey, "Category", ":Category")
		if not utilsTable.keyOf(categories, categoryLink) then
			table.insert(categories, categoryLink)
		end
	end
	return string.gsub(wikitext, categoryPattern, ""), categories
end

p.Schemas = {
	link = {
		page = {
			type = "string",
			required = true,
			desc = "The link target. Can be the name of a page on the wiki or an external URL.",
		},
		display = {
			type = "string",
			default = "page",
			desc = "The text to display for the link.",
		},
		noBacklink = {
			type = "boolean",
			desc = [[
				When <code>true</code>, renders an internal link such that it does not register on the]] .. " [[Special:WhatLinksHere]] " .. [[of the target page.
				
				'''Use only when certain that the page exists'''.  This method cannot render red-links (i.e. distinguish non-existent pages).
			]],
		},
	},
	sectionLink = {
		page = {
			type = "string",
			required = true,
			desc = "The name of a wiki page to target.",
		},
		section = {
			type = "string",
			desc = "The name of the page section to target.",
		},
		display = {
			type = "string",
			default = "page",
			desc = "The text to display for the link.",
		},
	},
	file = {
		name = {
			type = "string",
			required = true,
			desc = "A file name, with or without the <code>File:</code> prefix.",
		},
		options = {
			type = "record",
			properties = {
				{
					name = "size",
					type = "string",
					desc = "Image size in pixels.",
				},
				{
					name = "link",
					type = "string",
					desc = "Name of a page on the wiki or an external URL for the image thumbnail to link to.",
				},
				{
					name = "caption",
					type = "string",
					desc = "[https://developer.mozilla.org/en-US/docs/Web/HTML/Element/img Alt text] for the image.",
				},
				{
					name = "noBacklink",
					type = "boolean",
					desc = "When <code>true</code>, the <code>link</code> property is rendered such that it does not register on the [[Special:WhatLinksHere]] of the target page. " 
						 .. "It also does not register on [[Special:WantedPages]] if the page doesn't exist.",
				}
			}
		},
	},
	category = {
		name = {
			type = "string",
			required = true,
			desc = "The name of the category to link to (with or without namespace prefix).",
		},
		sortKey = {
			type = "string",
			desc = "A custom {{mediawiki|Help:Categories#Sort_key|sort key}} for the category entry.",
		}
	},
	categories = {
		names = {
			type = "array",
			required = true,
			items = { type = "string" },
			desc = "An array of category names, with or without the namespace prefix.",
		}
	},
	killBacklinks = {
		wikitext = {
			type = "string",
			required = true,
			desc = "A string of wiki markup.",
		},
	},
	stripCategories = {
		wikitext = {
			type = "string",
			required = true,
			desc = "A string of wiki markup.",
		},
	}
}

p.Documentation = {
	link = {
		params = {"page", "display", "noBacklink"},
		returns = "A string of wikitext that evaluates to a link. Will display a red link if the target is an internal link to a page that doesn't exist.",
		cases = {
			{
				desc = "Internal link",
				args = { "Princess Zelda" },
				expect = "[[Princess Zelda]]",
			},
			{
				desc = "Link to page that doesn't exist",
				args = {"Flippityfloppityfloo"},
				expect = "[[Flippityfloppityfloo]]"
			},
			{
				desc = "Piped link",
				args = { "Princess Zelda", "Zelda" },
				expect = "[[Princess Zelda|Zelda]]",
			},
			{
				desc = "Category link",
				args = { "Category:Items" },
				expect = "[[:Category:Items]]",
			},
			{
				desc = "Category link without prefix",
				args = { "Category:Items", "" },
				expect = "[[:Category:Items|Items]]",
			},
			{
				desc = "Category link with display text",
				args = { "Category:Items in Breath of the Wild", "Items in ''Breath of the Wild''" },
				expect = "[[:Category:Items in Breath of the Wild|Items in ''Breath of the Wild'']]",
			},
			{
				desc = "File link (to file description)",
				args = { "File:MM Deku Butler Artwork.png" },
				expect = "[[:File:MM Deku Butler Artwork.png]]",
			},
			{
				desc = "External link",
				args = { "https://www.mariowiki.com/Thwomp", "Thwomp" },
				expect = "[https://www.mariowiki.com/Thwomp Thwomp]",
			},
			{
				desc = "Looks like an internal link, but it's actually an external link. This is to avoid [[Special:WhatLinksHere]]",
				args = { "Princess Zelda", "Zelda", true },
				expect = [[<span class="plainlinks">[https://zelda.gamepedia.com/Princess_Zelda Zelda]</span>]],
			},
			{
				desc = "When <code>noBacklink</code> is set to <code>true</code>, red links are not rendered for pages which do not exist.",
				args = { "Flippityfloppityfloo", nil, true },
				expect = [[<span class="plainlinks">[https://zelda.gamepedia.com/Flippityfloppityfloo Flippityfloppityfloo]</span>]],
			},
		},
	},
	sectionLink = {
		params = {"page", "section", "display"},
		returns = "A string of wikitext rendering a section link.",
		cases = {
			{
				args = {"Link", "Ocarina of Time", "Hero of Time"},
				expect = "[[Link#Ocarina of Time|Hero of Time]]",
			},
			{
				args = {"Link", nil, "Hero of Time"},
				expect = "[[Link|Hero of Time]]",
			},
			{
				args = {"Link", ""},
				expect = "[[Link#]]",
			},
		},
	},
	file = {
		params = {"name", "options"},
		returns = "A <code>string</code> of wikitext that renders a thumbnail for the file.",
		cases = {
			{
				args = { "File:ALttP Ganon Sprite.png" },
				expect = "[[File:ALttP Ganon Sprite.png]]",
			},
			{
				args = { "ALttP Ganon Sprite.png", {
					link = "",
					caption = "Ganon"
				}},
				expect = "[[File:ALttP Ganon Sprite.png|link=|Ganon]]",
			},
			{
				args = { "File:TWW Great Fairy Figurine Model.png", {
					link = "Great Fairy",
					size = "100px",
				}},
				expect = "[[File:TWW Great Fairy Figurine Model.png|100px|link=Great Fairy]]",
			},
			{
				args = { "File:TWW Great Fairy Figurine Model.png", {
					link = "Great Fairy",
					size = "100px",
					noBacklink = true,
				}},
				expect = "[[File:TWW Great Fairy Figurine Model.png|100px|link=https://zelda.gamepedia.com/Great_Fairy]]",
			},
		},
	},
	category = {
		params = {"name", "sortKey"},
		returns = "A category link—the kind that adds a category to a page. For the other kind that links to the actual category page, use <code>link</code>.",
		cases = {
			outputOnly = true,
			{
				desc = "Category link from category name",
				args = { "Items" },
				expect = "[[Category:Items]]"
			},
			{
				desc = "Category link from category name with namespace prefix",
				args = { "Category:Items" },
				expect = "[[Category:Items]]",
			},
			{
				desc = "Category link with sort key",
				args = { "Items", "*" },
				expect = "[[Category:Items|*]]",
			},
		},
	},
	categories = {
		params = {"names"},
		returns = "A concatenated string of category links.",
		cases = {
			outputOnly = true,
			{
				args = { {"Link", "Category:Zelda", "Category:Ganon"} },
				expect = "[[Category:Link]][[Category:Zelda]][[Category:Ganon]]"
			},
			{
				args = { {} },
				expect = ""
			},
		},
	},
	containsLink = {
		params = {"wikitext"},
		returns = "Given a string of wikitext, returns <code>true</code> if it contains a link, false otherwise.",
		cases = {
			{
				args = {"There is a [[Link]]"},
				expect = true,
			},
			{
				args = {"[Link] is not a link but rather an idication of replaced words in a quote."},
				expect = false,
			},
		},
	},
	killBacklinks = {
		params = {"wikitext"},
		returns = "The same wikitext but with all the internal links formatted as external links, to avoid additions to [[Special:WhatLinksHere]].",
		cases = {
			{
				desc = "Escapes both normal links and red links",
				args = { "[[Link]], [[Princess Zelda|Zelda]], and [[Jean-Guy Rubber Boots]]" },
				expect = '<span class="plainlinks">[https://zelda.gamepedia.com/Link Link]</span>, <span class="plainlinks">[https://zelda.gamepedia.com/Princess_Zelda Zelda]</span>, and <span class="plainlinks new">[https://zelda.gamepedia.com/Jean-Guy_Rubber_Boots?action=edit&redlink=1 Jean-Guy Rubber Boots]</span>'
			},
			{
				desc = "Does not escape file links or category links",
				args = { "[[Category:Link]] and [[File:SS Blessed Butterfly Icon.png]]"},
				expect = "[[Category:Link]] and [[File:SS Blessed Butterfly Icon.png]]"
			},
			{
				desc = "Escapes visible file and category links",
				args = { "[[:Category:Link]], [[:Category:Princess Zelda|Zelda]], and [[:File:SS Blessed Butterfly Icon.png]]"},
				expect = 
					'<span class="plainlinks">[https://zelda.gamepedia.com/Category:Link Category:Link]</span>, '
					.. '<span class="plainlinks">[https://zelda.gamepedia.com/Category:Princess_Zelda Zelda]</span>, '
					.. 'and <span class="plainlinks">[https://zelda.gamepedia.com/File:SS_Blessed_Butterfly_Icon.png File:SS Blessed Butterfly Icon.png]</span>'
			},
			{
				desc = "Does not affect interwiki links",
				args = { "[[metroidwiki:Chozo|Chozo]]" },
				expect = "[[metroidwiki:Chozo|Chozo]]"
			}
		},
	},
	stripCategories = {
		params = {"wikitext"},
		returns = {
			 "The string of wiki markup with all the category links removed (not including visual links to category description pages).",
			 "A <code>table</code> array of direct links to the removed categories.",
		},
		cases = {
			outputOnly = true,
			{
				desc = "Basic use case",
				args = {"<[[Category:Link]][[Category:Princess Zelda]][[Category:Link]]>"},
				expect = {
					"<>",
					{"[[:Category:Link]]", "[[:Category:Princess Zelda]]"},
				},
			},
			{
				desc = "Does not affect visual links to category description pages",
				args = {"[[:Category:Link]] and [[:Category:Princess Zelda]]"},
				expect = {
					"[[:Category:Link]] and [[:Category:Princess Zelda]]",
					{},
				}
			}
		}
	}
}

return p