Module:Delink: Difference between revisions

From Our World of Text Wiki
Jump to navigation Jump to search
(Created module.)
 
(Accidentally pasted in the contents of Wikipedia:Module:Clickable button instead of Wikipedia:Module:Delink.)
 
Line 1: Line 1:
-- This module implements {{clickable button 2}}.
-- This module de-links most wikitext.


local yesno = require('Module:Yesno')
require("strict")
local delink = require('Module:Delink')._delink


local p = {}
local p = {}


function p.main(frame)
local getArgs
local getArgs = require('Module:Arguments').getArgs
 
local args = getArgs(frame)
local function delinkReversePipeTrick(s)
return p._main(args)
if s:match("^%[%[|.*[|\n]") then -- Check for newlines or multiple pipes.
return s
end
return s:match("%[%[|(.*)%]%]")
 
end
end


function p._main(args)
local function delinkPipeTrick(s)
-- If first arg or a url is not provided,
-- We need to deal with colons, brackets, and commas, per [[Help:Pipe trick]].
-- but we have a second arg, make a button.
-- First, remove the text before the first colon, if any.
-- Otherwise, return nothing.
if s:match(":") then
args.originalInput = args[1]
s = s:match("%[%[.-:(.*)|%]%]")
args[1] = delink({args[1]})
-- If there are no colons, grab all of the text apart from the square brackets and the pipe.
if args[1] == "" then
else
args[1] = nil
s = s:match("%[%[(.*)|%]%]")
end
end
-- Next up, brackets and commas.
if s:match("%(.-%)$") then -- Brackets trump commas.
s = s:match("(.-) ?%(.-%)$")
elseif s:match(",") then -- If there are no brackets, display only the text before the first comma.
s = s:match("(.-),.*$")
end
return s
end


if not args[1] and not args.url then
-- Return wikilink target |wikilinks=target
if args[2] then
local function getDelinkedTarget(s)
p.nolink = true
local result = s
else
-- Deal with the reverse pipe trick.
return ''
if result:match("%[%[|") then
end
return delinkReversePipeTrick(result)
end
result = mw.uri.decode(result, "PATH") -- decode percent-encoded entities. Leave underscores and plus signs.
result = mw.text.decode(result, true) -- decode HTML entities.
-- Check for bad titles. To do this we need to find the
-- title area of the link, i.e. the part before any pipes.
local target_area
if result:match("|") then -- Find if we're dealing with a piped link.
target_area = result:match("^%[%[(.-)|.*%]%]")
else
target_area = result:match("^%[%[(.-)%]%]")
end
end


local data = p.makeLinkData(args)
-- Check for bad characters.
local link = p.renderLink(args.originalInput, data)
if mw.ustring.match(target_area, "[%[%]<>{}%%%c\n]") and mw.ustring.match(target_area, "[%[%]<>{}%%%c\n]") ~= "?" then
local trackingCategories = p.renderTrackingCategories(args)
return s
return link .. trackingCategories
end
return target_area
end
end


function p.makeLinkData(args)
local function getDelinkedLabel(s)
local data = {}
local result = s
-- Deal with the reverse pipe trick.
if result:match("%[%[|") then
return delinkReversePipeTrick(result)
end
 
result = mw.uri.decode(result, "PATH") -- decode percent-encoded entities. Leave underscores and plus signs.
result = mw.text.decode(result, true) -- decode HTML entities.


-- Get the link and display values,
-- Check for bad titles. To do this we need to find the
-- and find whether we are outputting
-- title area of the link, i.e. the part before any pipes.
-- a wikilink or a URL.
local target_area
if args.url then
if result:match("|") then -- Find if we're dealing with a piped link.
data.isUrl = true
target_area = result:match("^%[%[(.-)|.*%]%]")
data.link = args.url
if args[1] then
data.display = args[1]
elseif args[2] then
data.display = args[2]
else
data.display = args.url
p.urlisdisplay = true
end
else
else
data.isUrl = false
target_area = result:match("^%[%[(.-)%]%]")
p.urlisdisplay = false
end
data.link = args[1]
 
if args[2] then
-- Check for bad characters.
data.display = args[2]
if mw.ustring.match(target_area, "[%[%]<>{}%%%c\n]") and mw.ustring.match(target_area, "[%[%]<>{}%%%c\n]") ~= "?" then
else
return s
data.display = args[1]
end
end
 
if args[1] and args[1]:find('http') then
-- Check for categories, interwikis, and files.
data.isUrl = true
local colon_prefix = result:match("%[%[(.-):.*%]%]") or "" -- Get the text before the first colon.
end
local ns = mw.site.namespaces[colon_prefix] -- see if this is a known namespace
if mw.language.isKnownLanguageTag(colon_prefix) or (ns and (ns.canonicalName == "File" or ns.canonicalName == "Category")) then
return ""
end
 
-- Remove the colon if the link is using the [[Help:Colon trick]].
if result:match("%[%[:") then
result = "[[" .. result:match("%[%[:(.*%]%])")
end
 
-- Deal with links using the [[Help:Pipe trick]].
if mw.ustring.match(result, "^%[%[[^|]*|%]%]") then
return delinkPipeTrick(result)
end
end
if yesno(args.link) == false then
-- Find the display area of the wikilink
p.nolink = true
if result:match("|") then -- Find if we're dealing with a piped link.
result = result:match("^%[%[.-|(.+)%]%]")
-- Remove new lines from the display of multiline piped links,
-- where the pipe is before the first new line.
result = result:gsub("\n", "")
else
result = result:match("^%[%[(.-)%]%]")
end
end


-- Colours
return result
-- For the merge with {{clickable button}}
end
local colour = args.color and args.color:lower()


-- Classes
local function delinkURL(s)
local class = args.class and args.class:lower()
-- Assume we have already delinked internal wikilinks, and that
data.classes = {}
-- we have been passed some text between two square brackets [foo].
if class == 'ui-button-green'
or class == 'ui-button-blue'
-- If the text contains a line break it is not formatted as a URL, regardless of other content.
or class == 'ui-button-red'
if s:match("\n") then
then
return s
table.insert(
data.classes,
'submit ui-button ui-widget ui-state-default ui-corner-all'
.. ' ui-button-text-only ui-button-text'
)
else
table.insert(data.classes, 'mw-ui-button')
end
end
--If class is unset,
-- Check if the text has a valid URL prefix and at least one valid URL character.
--then let color determine class
local valid_url_prefixes = {"//", "http://", "https://", "ftp://", "gopher://", "mailto:", "news:", "irc://"}
if not class then
local url_prefix
if colour == 'blue' then
for _ ,v in ipairs(valid_url_prefixes) do
class = 'mw-ui-progressive'
if mw.ustring.match(s, '^%[' .. v ..'[^"%s].*%]' ) then
elseif colour == 'red' then
url_prefix = v
class = 'mw-ui-destructive'
break
elseif colour == 'green' then
class = 'mw-ui-constructive'
end
end
end
end
if class then
-- Get display text
table.insert(data.classes, class)
if not url_prefix then
return s
end
s = s:match("^%[" .. url_prefix .. "(.*)%]") -- Grab all of the text after the URL prefix and before the final square bracket.
s = s:match('^.-(["<> ].*)') or "" -- Grab all of the text after the first URL separator character ("<> ).
s = mw.ustring.match(s, "^%s*(%S.*)$") or "" -- If the separating character was a space, trim it off.
local s_decoded = mw.text.decode(s, true)
if mw.ustring.match(s_decoded, "%c") then
return s
end
end


-- Styles
return s_decoded
do
 
--[[
end
-- Check whether we are on the same page as we have specified in
 
-- args[1], but not if we are using a URL link, as then args[1] is only
local function delinkLinkClass(text, pattern, delinkFunction)
-- a display value. If we are currently on the page specified in
if type(text) ~= "string" then
-- args[1] make the button colour darker so that it stands out from
error("Attempt to de-link non-string input.", 2)
-- other buttons on the page.
end
--]]
if type(pattern) ~= "string" or mw.ustring.sub(pattern, 1, 1) ~= "^" then
local success, linkTitle, currentTitle
error('Invalid pattern detected. Patterns must begin with "^".', 2)
if not data.isUrl then
end
currentTitle = mw.title.getCurrentTitle()
-- Iterate over the text string, and replace any matched text. using the
success, linkTitle = pcall(mw.title.new, args[1])
-- delink function. We need to iterate character by character rather
elseif p.urlisdisplay then
-- than just use gsub, otherwise nested links aren't detected properly.
currentTitle = mw.title.getCurrentTitle()
local result = ""
end
while text ~= "" do
if success
-- Replace text using one iteration of gsub.
and linkTitle
text = mw.ustring.gsub(text, pattern, delinkFunction, 1)
and mw.title.equals(currentTitle, linkTitle)
-- Append the left-most character to the result string.
and not p.urlisdisplay
result = result .. mw.ustring.sub(text, 1, 1)
then
text = mw.ustring.sub(text, 2, -1)
if class == 'ui-button-blue'
or class == 'mw-ui-progressive'
or class == 'mw-ui-constructive'
then
data.backgroundColor = '#2962CB'
data.color = '#fff'
elseif class == 'ui-button-green' then
data.backgroundColor = '#008B6D'
elseif class == 'ui-button-red' or class == 'mw-ui-destructive' then
data.backgroundColor = '#A6170F'
else
data.backgroundColor = '#CCC'
data.color = '#666'
end
elseif p.urlisdisplay then
data.dummyLink = tostring(currentTitle)
end
-- Add user-specified styles.
data.style = args.style
end
end
return data
return result
end
end


function p.renderLink(originalInput, data)
function p._delink(args)
-- Render the display span tag.
local text = args[1] or ""
local display
if args.refs == "yes" then
do
-- Remove any [[Help:Strip markers]] representing ref tags. In most situations
local displaySpan = mw.html.create('span')
-- this is not a good idea - only use it if you know what you are doing!
for i, class in ipairs(data.classes or {}) do
text = mw.ustring.gsub(text, "UNIQ%w*%-ref%-%d*%-QINU", "")
displaySpan:addClass(class)
end
end
if args.comments ~= "no" then
text = text:gsub("<!%-%-.-%-%->", "") -- Remove html comments.
end


displaySpan
if args.wikilinks ~= "no" and args.wikilinks ~= "target" then
:css{
-- De-link wikilinks and return the label portion of the wikilink.
['background-color'] = data.backgroundColor,
text = delinkLinkClass(text, "^%[%[.-%]%]", getDelinkedLabel)
color = data.color
elseif args.wikilinks == "target" then
}
-- De-link wikilinks and return the target portions of the wikilink.
if data.style then
text = delinkLinkClass(text, "^%[%[.-%]%]", getDelinkedTarget)
displaySpan:cssText(data.style)
end
end
if args.urls ~= "no" then
displaySpan:wikitext(data.display)
text = delinkLinkClass(text, "^%[.-%]", delinkURL) -- De-link URLs.
display = tostring(displaySpan)
end
end
 
if args.whitespace ~= "no" then
-- Render the link
-- Replace single new lines with a single space, but leave double new lines
local link
-- and new lines only containing spaces or tabs before a second new line.
if originalInput and originalInput:find('|') then
text = mw.ustring.gsub(text, "([^\n \t][ \t]*)\n([ \t]*[^\n \t])", "%1 %2")
link = string.format('[[%s|%s]]', delink({originalInput, wikilinks = 'target'}), display)
text = text:gsub("[ \t]+", " ") -- Remove extra tabs and spaces.
elseif p.nolink then
if p.urlisdisplay then
link = string.format('[[%s|%s]]', data.dummyLink, display)
else
link = string.format('%s', display)
end
else
if data.isUrl then
link = string.format('[%s %s]', data.link, display)
else
link = string.format('[[%s |%s]]', data.link, display)
end
end
end
 
return text
return string.format('<span class="plainlinks clickbutton">%s</span>', link)
end
end


function p.renderTrackingCategories(args)
function p.delink(frame)
if yesno(args.category) == false then
if not getArgs then
return ''
getArgs = require('Module:Arguments').getArgs
end
local class = args.class and args.class:lower()
if class == 'ui-button-green'
or class == 'ui-button-blue'
or class == 'ui-button-red'
then
return '[[Category:Pages using old style ui-button-color]]'
else
return ''
end
end
return p._delink(getArgs(frame, {wrappers = 'Template:Delink'}))
end
end


return p
return p

Latest revision as of 12:59, 9 December 2024

Documentation for this module may be created at Module:Delink/doc

-- This module de-links most wikitext.

require("strict")

local p = {}

local getArgs

local function delinkReversePipeTrick(s)
	if s:match("^%[%[|.*[|\n]") then -- Check for newlines or multiple pipes.
		return s
	end
	return s:match("%[%[|(.*)%]%]")

end

local function delinkPipeTrick(s)
	-- We need to deal with colons, brackets, and commas, per [[Help:Pipe trick]].
	-- First, remove the text before the first colon, if any.
	if s:match(":") then
		s = s:match("%[%[.-:(.*)|%]%]")
	-- If there are no colons, grab all of the text apart from the square brackets and the pipe.
	else
		s = s:match("%[%[(.*)|%]%]")
	end
	
	-- Next up, brackets and commas.
	if s:match("%(.-%)$") then -- Brackets trump commas.
		s = s:match("(.-) ?%(.-%)$")
	elseif s:match(",") then -- If there are no brackets, display only the text before the first comma.
		s = s:match("(.-),.*$")
	end
	return s
end

-- Return wikilink target |wikilinks=target
local function getDelinkedTarget(s)
	local result = s
	-- Deal with the reverse pipe trick.
	if result:match("%[%[|") then
		return delinkReversePipeTrick(result)
	end
	
	result = mw.uri.decode(result, "PATH") -- decode percent-encoded entities. Leave underscores and plus signs.
	result = mw.text.decode(result, true) -- decode HTML entities.
	
	-- Check for bad titles. To do this we need to find the
	-- title area of the link, i.e. the part before any pipes.
	local target_area
	if result:match("|") then -- Find if we're dealing with a piped link.
		target_area = result:match("^%[%[(.-)|.*%]%]")
	else
		target_area = result:match("^%[%[(.-)%]%]")
	end

	-- Check for bad characters.
	if mw.ustring.match(target_area, "[%[%]<>{}%%%c\n]") and mw.ustring.match(target_area, "[%[%]<>{}%%%c\n]") ~= "?" then
		return s
	end
	
	return target_area
end

local function getDelinkedLabel(s)
	local result = s
	-- Deal with the reverse pipe trick.
	if result:match("%[%[|") then
		return delinkReversePipeTrick(result)
	end

	result = mw.uri.decode(result, "PATH") -- decode percent-encoded entities. Leave underscores and plus signs.
	result = mw.text.decode(result, true) -- decode HTML entities.

	-- Check for bad titles. To do this we need to find the
	-- title area of the link, i.e. the part before any pipes.
	local target_area
	if result:match("|") then -- Find if we're dealing with a piped link.
		target_area = result:match("^%[%[(.-)|.*%]%]")
	else
		target_area = result:match("^%[%[(.-)%]%]")
	end

	-- Check for bad characters.
	if mw.ustring.match(target_area, "[%[%]<>{}%%%c\n]") and mw.ustring.match(target_area, "[%[%]<>{}%%%c\n]") ~= "?" then
		return s
	end

	-- Check for categories, interwikis, and files.
	local colon_prefix = result:match("%[%[(.-):.*%]%]") or "" -- Get the text before the first colon.
	local ns = mw.site.namespaces[colon_prefix] -- see if this is a known namespace
	if mw.language.isKnownLanguageTag(colon_prefix) or (ns and (ns.canonicalName == "File" or ns.canonicalName == "Category")) then
		return ""
	end

	-- Remove the colon if the link is using the [[Help:Colon trick]].
	if result:match("%[%[:") then
		result = "[[" .. result:match("%[%[:(.*%]%])")
	end

	-- Deal with links using the [[Help:Pipe trick]].
	if mw.ustring.match(result, "^%[%[[^|]*|%]%]") then
		return delinkPipeTrick(result)
	end
	
	-- Find the display area of the wikilink
	if result:match("|") then -- Find if we're dealing with a piped link.
		result = result:match("^%[%[.-|(.+)%]%]")
		-- Remove new lines from the display of multiline piped links,
		-- where the pipe is before the first new line.
		result = result:gsub("\n", "")
	else
		result = result:match("^%[%[(.-)%]%]")
	end

	return result
end

local function delinkURL(s)
	-- Assume we have already delinked internal wikilinks, and that
	-- we have been passed some text between two square brackets [foo].
	
	-- If the text contains a line break it is not formatted as a URL, regardless of other content.
	if s:match("\n") then
		return s
	end
	
	-- Check if the text has a valid URL prefix and at least one valid URL character.
	local valid_url_prefixes = {"//", "http://", "https://", "ftp://", "gopher://", "mailto:", "news:", "irc://"} 
	local url_prefix
	for _ ,v in ipairs(valid_url_prefixes) do
		if mw.ustring.match(s, '^%[' .. v ..'[^"%s].*%]' ) then
			url_prefix = v
			break
		end
	end
	
	-- Get display text
	if not url_prefix then
		return s
	end
	s = s:match("^%[" .. url_prefix .. "(.*)%]") -- Grab all of the text after the URL prefix and before the final square bracket.
	s = s:match('^.-(["<> ].*)') or "" -- Grab all of the text after the first URL separator character ("<> ).
	s = mw.ustring.match(s, "^%s*(%S.*)$") or "" -- If the separating character was a space, trim it off.
	
	local s_decoded = mw.text.decode(s, true)
	if mw.ustring.match(s_decoded, "%c") then
		return s
	end

	return s_decoded

end

local function delinkLinkClass(text, pattern, delinkFunction)
	if type(text) ~= "string" then
		error("Attempt to de-link non-string input.", 2)
	end
	if type(pattern) ~= "string" or mw.ustring.sub(pattern, 1, 1) ~= "^" then
		error('Invalid pattern detected. Patterns must begin with "^".', 2)
	end
	-- Iterate over the text string, and replace any matched text. using the 
	-- delink function. We need to iterate character by character rather 
	-- than just use gsub, otherwise nested links aren't detected properly.
	local result = ""
	while text ~= "" do
		-- Replace text using one iteration of gsub.
		text = mw.ustring.gsub(text, pattern, delinkFunction, 1)
		-- Append the left-most character to the result string.
		result = result .. mw.ustring.sub(text, 1, 1)
		text = mw.ustring.sub(text, 2, -1)
	end
	return result
end

function p._delink(args)
	local text = args[1] or ""
	if args.refs == "yes" then
		-- Remove any [[Help:Strip markers]] representing ref tags. In most situations 
		-- this is not a good idea - only use it if you know what you are doing!
		text = mw.ustring.gsub(text, "UNIQ%w*%-ref%-%d*%-QINU", "")
	end
	if args.comments ~= "no" then
		text = text:gsub("<!%-%-.-%-%->", "") -- Remove html comments.
	end

	if args.wikilinks ~= "no" and args.wikilinks ~= "target" then
		-- De-link wikilinks and return the label portion of the wikilink.
		text = delinkLinkClass(text, "^%[%[.-%]%]", getDelinkedLabel)
	elseif args.wikilinks == "target" then
		-- De-link wikilinks and return the target portions of the wikilink.
		text = delinkLinkClass(text, "^%[%[.-%]%]", getDelinkedTarget)
	end
	if args.urls ~= "no" then
		text = delinkLinkClass(text, "^%[.-%]", delinkURL) -- De-link URLs.
	end
	if args.whitespace ~= "no" then
		-- Replace single new lines with a single space, but leave double new lines
		-- and new lines only containing spaces or tabs before a second new line.
		text = mw.ustring.gsub(text, "([^\n \t][ \t]*)\n([ \t]*[^\n \t])", "%1 %2")
		text = text:gsub("[ \t]+", " ") -- Remove extra tabs and spaces.
	end
	return text
end

function p.delink(frame)
	if not getArgs then
		getArgs = require('Module:Arguments').getArgs
	end
	return p._delink(getArgs(frame, {wrappers = 'Template:Delink'}))
end

return p