Module:URL
--
 -- This module implements {{URL}}
 --
 -- See unit tests at [[Module:URL/testcases]]
 
 local p = {}
  
 local function safeUri(s)
 	local success, uri = pcall(function()
 		return mw.uri.new(s)
 	end)
 	if success then
 		return uri
 	end
 end
 
 local function extractUrl(args)
 	for name, val in pairs(args) do
 		if name ~= 2 and name ~= &quot;msg&quot; then
 			local url = name .. &quot;=&quot; .. val;
 			url = mw.ustring.gsub(url, '^[Hh][Tt][Tt][Pp]([Ss]?):(/?)([^/])', 'http%1://%3')
 			local uri = safeUri(url);
 			if uri and uri.host then
 				return url
 			end
 		end
 	end
 end
 
 function p._url(url, text, msg)
 	url = mw.text.trim(url or '')
 	text = mw.text.trim(text or '')
 	local nomsg = (msg or ''):sub(1,1):lower() == &quot;n&quot; or msg == 'false' -- boolean: true if msg is &quot;false&quot; or starts with n or N
 
 	if url == '' then
 		if text == '' then
 			if nomsg then
 				return nil
 			else
 				return mw.getCurrentFrame():expandTemplate{ title = 'tlx', args = { 'URL', &quot;''example.com''&quot;, &quot;''optional display text''&quot; } }
 			end
 		else
 			return text
 		end
 	end
 
 	-- If the URL contains any unencoded spaces, encode them, because MediaWiki will otherwise interpret a space as the end of the URL.
 	url = mw.ustring.gsub(url, '%s', function(s) return mw.uri.encode(s, 'PATH') end)
 
 	-- If there is an empty query string or fragment id, remove it as it will cause mw.uri.new to throw an error
 	url = mw.ustring.gsub(url, '#$', '')
 	url = mw.ustring.gsub(url, '%?$', '')
 
 	-- If it's an HTTP[S] URL without the double slash, fix it.
 	url = mw.ustring.gsub(url, '^[Hh][Tt][Tt][Pp]([Ss]?):(/?)([^/])', 'http%1://%3')
 
 	local uri = safeUri(url)
 
 	-- Handle URL's without a protocol and URL's that are protocol-relative, 
 	-- e.g. www.example.com/foo or www.example.com:8080/foo, and //www.example.com/foo
 	if uri and (not uri.protocol or (uri.protocol and not uri.host)) and url:sub(1, 2) ~= '//' then
 		url = 'http://' .. url
 		uri = safeUri(url)
 	end
 
 	if text == '' then
 		if uri then
 			if uri.path == '/' then uri.path = '' end
 
 			local port = ''
 			if uri.port then port = ':' .. uri.port end
 
 			text = mw.ustring.lower(uri.host or '') .. port .. (uri.relativePath or '')
 
 			-- Add &lt;wbr&gt; before _/.-# sequences
 			text = mw.ustring.gsub(text,&quot;(/+)&quot;,&quot;&lt;wbr/&gt;%1&quot;)      -- This entry MUST be the first. &quot;&lt;wbr/&gt;&quot; has a &quot;/&quot; in it, you know.
 			text = mw.ustring.gsub(text,&quot;(%.+)&quot;,&quot;&lt;wbr/&gt;%1&quot;)
 			-- text = mw.ustring.gsub(text,&quot;(%-+)&quot;,&quot;&lt;wbr/&gt;%1&quot;) 	-- DISABLED for now
 			text = mw.ustring.gsub(text,&quot;(%#+)&quot;,&quot;&lt;wbr/&gt;%1&quot;)
 			text = mw.ustring.gsub(text,&quot;(_+)&quot;,&quot;&lt;wbr/&gt;%1&quot;)
 		else -- URL is badly-formed, so just display whatever was passed in
 			text = url
 		end
 	end
 
 	return mw.ustring.format('&lt;span class=&quot;url&quot;&gt;[%s %s]&lt;/span&gt;', url, text)
 end
 
 --[[
 The main entry point for calling from Template:URL.
 --]]
 function p.url(frame)
 	local templateArgs = frame.args
 	local parentArgs = frame:getParent().args
 	local url = templateArgs[1] or parentArgs[1]
 	local text = templateArgs[2] or parentArgs[2] or ''
 	local msg = templateArgs.msg or parentArgs.msg or ''
 	url = url or extractUrl(templateArgs) or extractUrl(parentArgs) or ''
 	return p._url(url, text, msg)
 end
 
 --[[
 The entry point for calling from the forked Template:URL2.
 This function returns no message by default.
 It strips out wiki-link markup, html tags, and everything after a space.
 --]]
 function p.url2(frame)
 	local templateArgs = frame.args
 	local parentArgs = frame:getParent().args
 	local url = templateArgs[1] or parentArgs[1]
 	local text = templateArgs[2] or parentArgs[2] or ''
 	-- default to no message
 	local msg = templateArgs.msg or parentArgs.msg or 'no'
 	url = url or extractUrl(templateArgs) or extractUrl(parentArgs) or ''
 	-- if the url came from a Wikidata call, it might have a pen icon appended
 	-- we want to keep that and add it back at the end.
 	local u1, penicon = mw.ustring.match( url, &quot;(.*)(&amp;nbsp;&lt;span class='penicon.*)&quot; )
 	if penicon then url = u1 end
 	-- strip out html tags and [ ] from url
 	url = (url or ''):gsub(&quot;&lt;[^&gt;]*&gt;&quot;, &quot;&quot;):gsub(&quot;[%[%]]&quot;, &quot;&quot;)
 	-- truncate anything after a space
 	url = url:gsub(&quot;%%20&quot;, &quot; &quot;):gsub(&quot; .*&quot;, &quot;&quot;)
 	return (p._url(url, text, msg) or &quot;&quot;) .. (penicon or &quot;&quot;)
 end