Jump to content
Toggle menu
  • 8 articles
  • 75 files
  • 7 users
  • 37.8K edits
Neodyland Wiki
Toggle preferences menu
Toggle personal menu
Not logged in
Your IP address will be publicly visible if you make any edits.

Module:Redirect: Difference between revisions

From Neodyland Wiki
better performing like this
m 34 revisions imported
 
(11 intermediate revisions by 4 users not shown)
Line 27: Line 27:
function p.getTargetFromText(text)
function p.getTargetFromText(text)
text = text or ''
text = text or ''
return text:match('#[Rr][Ee][Dd]...[Cc][Tt][%s:]*%[%[([^]|]-)%s*%]%]')
return text:match('^#[Rr][Ee][Dd][Ii][Rr][Ee][Cc][Tt][%s:]*%[%[[%s_:]*([^]|]-)[%s_]*%]%]')
end
end


Line 45: Line 45:
{{Seecat|target}}
{{Seecat|target}}
{{See cat|target}}
{{See cat|target}}
{{Endashcatredirect|target}}
{{Synonym taxon category redirect|target}}
{{Invalid taxon category redirect|target}}
{{Monotypic taxon category redirect|target}}
The `target` value may be prefixed by 'Category:' or not (implied). For the full list of aliases, see
The `target` value may be prefixed by 'Category:' or not (implied). For the full list of aliases, see
https://commons.wikimedia.org/w/index.php?title=Special:WhatLinksHere/Template:Category_redirect&hidetrans=1&hidelinks=1
https://commons.wikimedia.org/w/index.php?title=Special:WhatLinksHere/Template:Category_redirect&hidetrans=1&hidelinks=1
Line 51: Line 55:
-- Basic filtering: only in the relevant content shown on target page itself
-- Basic filtering: only in the relevant content shown on target page itself
content = (content or '')
content = (content or '')
:gsub('<!%-%-(.-)%-%->', '') -- discard HTML comments
:gsub('<!%-%-(.-)%-%->', '') -- Discard HTML comments.
:gsub('<includeonly%s*>(.-)</includeonly>', '') -- discard 'includeonly' sections and their content
:gsub('<includeonly%s*>(.-)</includeonly>', '') -- Discard 'includeonly' sections and their content.
:gsub('<includeonly%s*>(.-)$', '') -- discard unclosed 'includeonly' sections
:gsub('<includeonly%s*>(.-)$', '') -- Discard unclosed 'includeonly' sections.
:gsub('<[/]?onlyinclude>', '') -- discard 'onlyinclude' opening/closing tags
:gsub('<[/]?onlyinclude%s*>', '') -- Discard 'onlyinclude' opening/closing tags.
:gsub('<[/]?noinclude>', '') -- discard 'noinclude' opening/closing tags
:gsub('<[/]?noinclude%s*>', '') -- Discard 'noinclude' opening/closing tags.
:gsub('</?nowiki%s*/?>', '') -- discard nowiki opening/closing/selfclosed tags
:gsub('</?nowiki%s*/?>', '') -- Discard nowiki opening/closing/selfclosed tags.
-- Locate the template transclusion, keep their parameters only
-- Locate the template transclusion, keep their parameters only.
-- Note: there may potentially be several instances, this should not occur
-- Note: there may potentially be several instances, this should not occur.
content =
content =
content:match('{{[%s_]*[Cc]ategory*[%s_]*[Rr]edirect[%s_]*|(.-)}}') or
content:match('^#[Rr][Ee][Dd][Ii][Rr][Ee][Cc][Tt][%s:]*%[%[[%s_:]*([^]|]-)[%s_]*%]%]') or
content:match('{{[%s_]*[Cc]at[%s_]*[Rr]edirect[%s_]*|(.-)}}') or
content:match('{{[%s_]*[Cc]ategory*[%s_]*[Rr]edirect[%s_]*|[%s_:]*(.-)[%s_]*}}') or
content:match('{{[%s_]*[Cc]at-[Rr]edirect[%s_]*|(.-)}}') or
content:match('{{[%s_]*[Cc]at[%s_]*[Rr]edirect[%s_]*|[%s_:]*(.-)[%s_]*}}') or
content:match('{{[%s_]*[Cc]at[%s_]*[Rr]edir[%s_]*|(.-)}}') or
content:match('{{[%s_]*[Cc]at-[Rr]edirect[%s_]*|[%s_:]*(.-)[%s_]*}}') or
content:match('{{[%s_]*[Cc]at-red[%s_]*|(.-)}}') or
content:match('{{[%s_]*[Cc]at[%s_]*[Rr]edir[%s_]*|[%s_:]*(.-)[%s_]*}}') or
content:match('{{[%s_]*[Rr]edirect[%s_]*[Cc]ategory[%s_]*|(.-)}}') or
content:match('{{[%s_]*[Cc]at-red[%s_]*|[%s_:]*(.-)[%s_]*}}') or
content:match('{{[%s_]*[Rr]edirect[%s_]*[Cc]at[%s_]*|(.-)}}') or
content:match('{{[%s_]*[Rr]edirect[%s_]*[Cc]ategory[%s_]*|[%s_:]*(.-)[%s_]*}}') or
content:match('{{[%s_]*[Ss]ee[%s_]*[Cc]at[%s_]*|(.-)}}')
content:match('{{[%s_]*[Rr]edirect[%s_]*[Cc]at[%s_]*|[%s_:]*(.-)[%s_]*}}') or
content:match('{{[%s_]*[Ss]ee[%s_]*[Cc]at[%s_]*|[%s_:]*(.-)[%s_]*}}') or
content:match('{{[%s_]*[Ee]ndashcatredirect[%s_]*|[%s_:]*(.-)[%s_]*}}') or
content:match('{{[%s_]*[Ss]ynonym[%s_]*taxon[%s_]*category[%s_]*redirect[%s_]*|[%s_:]*(.-)[%s_]*}}') or
content:match('{{[%s_]*[Ii]nvalid[%s_]*taxon[%s_]*category[%s_]*redirect[%s_]*|[%s_:]*(.-)[%s_]*}}') or
content:match('{{[%s_]*[Mm]onotypic[%s_]*taxon[%s_]*category[%s_]*redirect[%s_]*|[%s_:]*(.-)[%s_]*}}')
if not content then
if not content then
return nil
return nil
end
end
do
do
-- Parse template parameters (they may be in arbitrary order)
-- Parse template parameters (they may be in arbitrary order).
local params, n = {}, 0
local params, n = {}, 0
for param in content:gmatch("([^|]+)") do
for param in content:gmatch('([^|]+)') do
local key
local key
local pos = param:find('=')
local pos = param:find('=')
Line 86: Line 95:
params[key] = param
params[key] = param
end
end
-- The target is in parameter ['1'] of the template transclusion
-- The target is in parameter ['1'] of the template transclusion.
content = params['1']
content = params['1']
end
end
-- Check there's an effective target parameter to the template
-- Check there's an effective target parameter to the template.
if not content then
if not content then
return nil
return nil
Line 95: Line 104:
content = content
content = content
-- The target parameter may contain some known character entities
-- The target parameter may contain some known character entities
-- (their validity in page names is not checked here, just parsed)
-- (their validity in page names is not checked here, just parsed).
:gsub('&([#%d%a]+);', function(entity)
:gsub('&([#%d%a]+);', function(entity)
if entity:sub(1,1) == '#' then
if entity:sub(1,1) == '#' then
Line 105: Line 114:
end
end
if codepoint and (
if codepoint and (
codepoint >= 0x0009 and codepoint <= 0x000D or -- accept some whitespace C0 controls
codepoint >= 0x0009 and codepoint <= 0x000D or -- Accept some whitespace C0 controls.
codepoint >= 0x0020 and codepoint <= 0x10FFFD -- normal range
codepoint >= 0x0020 and codepoint <= 0x10FFFD -- Normal range.
and (codepoint < 0x0080 or codepoint > 0x009F) -- exclude C1 controls
and (codepoint < 0x0080 or codepoint > 0x009F) -- Exclude C1 controls.
and (codepoint < 0xDC00 or codepoint > 0xDFFF) -- exclude surrogates
and (codepoint < 0xDC00 or codepoint > 0xDFFF) -- Exclude surrogates.
and (codepoint < 0xFDD0 or codepoint > 0xFDEF) -- exclude non-characters in BMP
and (codepoint < 0xFDD0 or codepoint > 0xFDEF) -- Exclude non-characters in BMP.
and codepoint % 0x10000 <= 0xFFFD -- exclude non-characters at end of planes
and codepoint % 0x10000 <= 0xFFFD -- Exclude non-characters at end of planes.
) then
) then
return char(codepoint)
return char(codepoint)
Line 122: Line 131:
return entity
return entity
end)
end)
-- Normalize spaces in the target according to Mediawiki pagename rules
-- Normalize spaces in the target according to Mediawiki pagename rules.
:gsub('[%s_]+', ' ')
:gsub('[%s_]+', ' ')
-- The target parameter should be trimmed by the template
-- The target parameter should be trimmed by the template.
:match('^ ?(.-) ?$')
:match('^ ?(.-) ?$')
-- The target should not be empty and not contain tag delimiters or other character forbidden in full page names
-- The target should not be empty and not contain tag delimiters or other character forbidden in full page names.
-- Note: templates used inside the target parameter of the soft redirect are not expanded (there should be none)
-- Note: templates used inside the target parameter of the soft redirect are not expanded (there should be none),
-- as this is costly or memory intensive and slow (would require invoking a full mediawiki parser).
-- as this is costly or memory intensive and slow (would require invoking a full mediawiki parser).
if content == '' or content:find('[<>%[%]{|}]') then
if content == '' or content:find('[<>%[%]{|}]') then
Line 140: Line 149:


-- Get page name that a redirect leads to, or nil if it isn't a redirect.
-- Get page name that a redirect leads to, or nil if it isn't a redirect.
function p.getTargetFrom(obj)
-- fulltext is an optional option: when set, it indicates if we want the `.fullText`, otherwise we get the `.prefixedText`.
function p.getTargetFrom(obj, fulltext)
--[[
--[[
obj:getContent() is intensive for large pages, but obj.redirectTarget returns directly
obj:getContent() is intensive for large pages, but obj.redirectTarget returns directly
Line 158: Line 168:
if r then
if r then
local obj2 = getTitle(r)
local obj2 = getTitle(r)
if obj2 then -- getTitle may fail
if obj2 then -- Detect when getTitle fails.
obj = obj2 -- true replacement withe the target
obj = obj2 -- True replacement with the target.
-- special: the replacement may also be a hard redirect
-- Special: the replacement may also be a hard redirect.
r = obj.isRedirect and obj.redirectTarget
r = obj.isRedirect and obj.redirectTarget
-- not done here: second soft redirect detection
-- Not done here: second soft redirect detection.
end
end
end
end
Line 168: Line 178:
if not r and obj.isRedirect then
if not r and obj.isRedirect then
-- The page is a redirect, but matching failed, which may be a bug
-- The page is a redirect, but matching failed, which may be a bug
-- in redirect matching pattern, so throw an error.
-- in the redirect matching pattern, so throw an error.
error(string.format(
error(string.format(
'could not parse redirect on page "%s"',
'could not parse redirect on page "%s"',
Line 174: Line 184:
))
))
end
end
r = obj.fulltext and obj.fullText or obj.prefixedText
r = fulltext and obj.fullText or obj.prefixedText
end
end
return r
return r
Line 186: Line 196:
titleObj = target
titleObj = target
else
else
error(string.format("bad argument #1 to 'fmtTitle' " ..
error(string.format(
"(string, number, or title object expected, got %s)",
'bad argument #1 to "fmtTitle": string, number, or title object expected, got %s',
type(target)
type(target)
), 2)
), 2)
Line 209: Line 219:
titleObj = page
titleObj = page
else
else
error(string.format("bad argument #1 to 'getTarget' " ..
error(string.format(
"(string, number, or title object expected, got %s)",
'bad argument #1 to "getTarget": string, number, or title object expected, got %s',
type(page)
type(page)
), 2)
), 2)
end
end
if titleObj and titleObj.exists and
if titleObj and titleObj.exists and
(titleObj.isRedirect or titleObj:inNamespace("Category"))
(titleObj.isRedirect or titleObj:inNamespace('Category'))
then
then
-- Find the target by using string matching on the page content.
-- Find the target by using string matching on the page content.
return fmtTitle(p.getTargetFrom(titleObj), fulltext, ensureTitleExists)
return fmtTitle(p.getTargetFrom(titleObj, fulltext), fulltext, ensureTitleExists)
end
end
end
end
Line 232: Line 242:
--]]
--]]
function p.luaMain(rname, bracket, fulltext, ensureTitleExists)
function p.luaMain(rname, bracket, fulltext, ensureTitleExists)
if type(rname) ~= "string" or not rname:find("%S") then
if type(rname) ~= 'string' or not rname:find('%S') then
return nil
return nil
end
end
rname = rname:match("%[%[%s*([%]|]-)%s*%]%]") or rname
rname = rname:match('%[%[[%s_:]*([^%]|]-)[%s_]*%]%]')
or rname:match('^[%s_:]*([%]|]-)[^%s_]*$')
or rname
local ret = p.getTarget(rname, fulltext, ensureTitleExists) or
local ret = p.getTarget(rname, fulltext, ensureTitleExists) or
fmtTitle(rname, fulltext, ensureTitleExists)
fmtTitle(rname, fulltext, ensureTitleExists)
link = bracket and (ret == rname and "[[:%s]]" or "[[:%s|%s]]") or "%s"
local link = bracket and (ret == rname and '[[:%s]]' or '[[:%s|%s]]') or '%s'
return ret and link:format(ret, rname)
return ret and link:format(ret, rname)
end
end
Cookies help us deliver our services. By using our services, you agree to our use of cookies.