Module:template link: difference between revisions
Jump to navigation
Jump to search
Content deleted Content added
Theknightwho (talk | contribs) mNo edit summary |
Theknightwho (talk | contribs) Display self-links as links with the #top anchor, and clarify some comments. |
||
Line 12: | Line 12: | ||
local is_substing = mw.isSubsting |
local is_substing = mw.isSubsting |
||
local lower = string.lower |
local lower = string.lower |
||
local make_title = mw.title.makeTitle -- |
local make_title = mw.title.makeTitle -- unconditionally adds the specified namespace prefix |
||
local new_title = mw.title.new -- namespace |
local new_title = mw.title.new -- specified namespace prefix is only added if the input doesn't contain one |
||
local parse_template_name = require("Module:template parser").parseTemplateName |
local parse_template_name = require("Module:template parser").parseTemplateName |
||
local php_trim = m_str_utils.php_trim |
local php_trim = m_str_utils.php_trim |
||
Line 31: | Line 31: | ||
do |
do |
||
-- pf_arg0 or arg1 may need to be linked if a given parser function treats |
-- pf_arg0 or arg1 may need to be linked if a given parser function treats |
||
-- them as a |
-- them as a pagename. If a key exists in `namespace`, the value is the |
||
-- namespace for the page |
-- namespace for the page: if not 0, then the namespace prefix will always |
||
-- |
-- be added to the input (e.g. {{#invoke}} can only target the Module: |
||
-- namespace, so inputting "Template:foo" gives "Module:Template:foo", and |
|||
-- the value is 0, the link is to mainspace unless the page contains a |
|||
-- "Module:foo" gives "Module:Module:foo"). However, this isn't possible |
|||
⚫ | |||
-- with mainspace (namespace 0), so prefixes are respected. make_title |
|||
⚫ | |||
local function link_page(page, namespace) |
local function link_page(page, namespace) |
||
if not namespace then |
if not namespace then |
||
Line 45: | Line 47: | ||
end |
end |
||
return format( |
return format( |
||
"[[:%s|%s]]", |
"[[:%s#top|%s]]", |
||
encode_uri(title.prefixedText, "WIKI"), |
encode_uri(title.prefixedText, "WIKI"), |
||
page |
page |
||
Line 68: | Line 70: | ||
local chunk = chunks[chunks_len] |
local chunk = chunks[chunks_len] |
||
local link = magic_words[chunk] |
local link = magic_words[chunk] |
||
-- If the name is not listed in magic_words, it must be a template. |
|||
-- Template. |
|||
-- Use new_title and set the default namespace to 10 (Template:), as |
|||
-- this mimics template behaviour. |
|||
if not link then |
if not link then |
||
chunks[chunks_len] = format( |
chunks[chunks_len] = format( |
||
"[[:%s|%s]]", |
"[[:%s#top|%s]]", |
||
encode_uri(new_title(chunk, 10).prefixedText, "WIKI"), |
encode_uri(new_title(chunk, 10).prefixedText, "WIKI"), |
||
concat(rawchunks, ":", chunks_len) |
concat(rawchunks, ":", chunks_len) |
||
) |
) |
||
return concat(chunks, ":") |
return concat(chunks, ":") |
||
-- Otherwise, it's a magic word. Some magic words have different links |
-- Otherwise, it's a magic word. Some magic words have different links, |
||
-- depending on whether argument 1 is specified ( |
-- depending on whether argument 1 is specified (e.g. "baz" in |
||
-- {{foo:bar|baz}}). |
-- {{foo:bar|baz}}). |
||
elseif type(link) == "table" then |
elseif type(link) == "table" then |
Revision as of 13:09, 8 May 2024
- The following documentation is located at Module:template link/documentation. [edit]
- Useful links: subpage list • links • transclusions • testcases • sandbox
This module implements {{temp}}
and {{tempn}}
.
local export = {}
local m_str_utils = require("Module:string utilities")
local m_table = require("Module:table")
local string = string
local table = table
local concat = table.concat
local encode_uri = mw.uri.encode
local format = string.format
local format_link -- defined as export.format_link below
local is_substing = mw.isSubsting
local lower = string.lower
local make_title = mw.title.makeTitle -- unconditionally adds the specified namespace prefix
local new_title = mw.title.new -- specified namespace prefix is only added if the input doesn't contain one
local parse_template_name = require("Module:template parser").parseTemplateName
local php_trim = m_str_utils.php_trim
local process_params = require("Module:parameters").process
local shallowcopy = m_table.shallowcopy
local sorted_pairs = m_table.sortedPairs
local split = m_str_utils.split
local insert = table.insert
local type = type
local data = mw.loadData("Module:template link/data")
local magic_words = data.magic_words
local link_parameter_0 = data.link_parameter_0
local link_parameter_1 = data.link_parameter_1
local parser_extension_tags = mw.loadData("Module:data/parser extension tags")
do
-- pf_arg0 or arg1 may need to be linked if a given parser function treats
-- them as a pagename. If a key exists in `namespace`, the value is the
-- namespace for the page: if not 0, then the namespace prefix will always
-- be added to the input (e.g. {{#invoke}} can only target the Module:
-- namespace, so inputting "Template:foo" gives "Module:Template:foo", and
-- "Module:foo" gives "Module:Module:foo"). However, this isn't possible
-- with mainspace (namespace 0), so prefixes are respected. make_title
-- handles all of this automatically.
local function link_page(page, namespace)
if not namespace then
return page
end
local title = make_title(namespace, page)
if not title then
return page
end
return format(
"[[:%s#top|%s]]",
encode_uri(title.prefixedText, "WIKI"),
page
)
end
local function render_title(name, args)
local arg1 = args and args[1] or nil
local chunks, pf_arg0 = parse_template_name(name, arg1)
if chunks == nil then
return name
end
local chunks_len = #chunks
local rawchunks = split(name, ":")
for i = 1, chunks_len - 1 do
chunks[i] = format(
"[[%s|%s]]",
encode_uri(magic_words[chunks[i]], "WIKI"),
rawchunks[i]
)
end
local chunk = chunks[chunks_len]
local link = magic_words[chunk]
-- If the name is not listed in magic_words, it must be a template.
-- Use new_title and set the default namespace to 10 (Template:), as
-- this mimics template behaviour.
if not link then
chunks[chunks_len] = format(
"[[:%s#top|%s]]",
encode_uri(new_title(chunk, 10).prefixedText, "WIKI"),
concat(rawchunks, ":", chunks_len)
)
return concat(chunks, ":")
-- Otherwise, it's a magic word. Some magic words have different links,
-- depending on whether argument 1 is specified (e.g. "baz" in
-- {{foo:bar|baz}}).
elseif type(link) == "table" then
link = arg1 and link[1] or link[0]
end
chunks[chunks_len] = format(
"[[%s|%s]]",
encode_uri(link, "WIKI"),
rawchunks[chunks_len]
)
-- If we don't have pf_arg0, it must be a parser variable, so return.
if not pf_arg0 then
return concat(chunks, ":")
-- #TAG: has special handling, because documentation links for parser
-- extension tags come from [[Module:data/parser extension tags]].
elseif chunk == "#TAG:" then
local tag = parser_extension_tags[lower(php_trim(pf_arg0))]
if tag then
pf_arg0 = format(
"[[%s|%s]]",
encode_uri(tag, "WIKI"),
pf_arg0
)
end
-- Otherwise, finalize pf_arg0 and add it to `chunks`.
else
pf_arg0 = link_page(pf_arg0, link_parameter_0[chunk])
end
chunks[chunks_len + 1] = pf_arg0
-- Finalize arg1 (if applicable) then return.
if arg1 then
args[1] = link_page(arg1, link_parameter_1[chunk])
end
return concat(chunks, ":")
end
function export.format_link(title, args, nested)
local output = {render_title(title, args)}
-- Iterate over numbered arguments, adding them as implicit parameters
-- (i.e. with no key) until we hit nil. Any remaining parameters are
-- given with explicit keys (including any non-sequential numbered
-- parameters).
if args then
local iter = sorted_pairs(args)
local i, k, v = 1, iter()
while k == i do
insert(output, v)
k, v = iter()
i = i + 1
end
if k ~= nil then
repeat
insert(output, k .. "=" .. v)
k, v = iter()
until k == nil
end
end
-- Add opening/closing braces and delimiting pipes.
output = "{{" .. concat(output, "|") .. "}}"
-- Return, enclosing in <code> tags if the `nested` flag hasn't been
-- set.
return nested and output or "<code>" .. output .. "</code>"
end
format_link = export.format_link
end
function export.show(frame)
if is_substing() then
return require("Module:unsubst").unsubst_template("format_link")
end
local iargs = process_params(frame.args, {
["annotate"] = {},
["nested"] = {type = "boolean"}
})
-- iargs.annotate allows a template to specify the title, so the input
-- arguments will match the output. Otherwise, we treat parameter 1 as the
-- template name and offset any implicit arguments.
local title = iargs.annotate
if title then
return format_link(title, shallowcopy(frame:getParent().args), iargs.nested)
end
-- Process parameters with the return_unknown flag set. `title` contains
-- the title at key 1; everything else goes in `args`.
local args
title, args = process_params(frame:getParent().args, {
[1] = {required = true, allow_empty = true, allow_whitespace = true}
}, true)
title = title[1]
-- Shift all implicit arguments down by 1. Non-sequential numbered
-- parameters don't get shifted; however, this offset means that if the
-- input contains (e.g.) {{tl|l|en|3=alt}}, representing {{l|en|3=alt}},
-- the parameter at 3= is instead treated as sequential by this module,
-- because it's indistinguishable from {{tl|l|en|alt}}, which represents
-- {{l|en|alt}}. On the other hand, {{tl|l|en|4=tr}} is handled correctly,
-- because there's still a gap before 4=.
-- Unfortunately, there's no way to know the original input, so
-- there's no clear way to fix this; the only difference is that explicit
-- parameters have whitespace trimmed from their values while implicit ones
-- don't, but we can't assume that every input with no whitespace was given
-- with explicit numbering.
-- This also causes bigger problems for any parser functions which treat
-- their inputs as arrays, or in some other nonstandard way (e.g.
-- {{#IF:foo|bar=baz|qux}} treats "bar=baz" as parameter 1). Without
-- knowing the original input, these can't be reconstructed accurately.
-- The way around this is to use <nowiki> tags in the input, since this
-- module won't unstrip them by design.
local i = 2
repeat
local arg = args[i]
args[i - 1] = arg
i = i + 1
until arg == nil
return format_link(title, args, iargs.nested)
end
return export