Module:TScope
This Lua module is used on 100,000+ pages. To avoid major disruption and server load, any changes should be tested in the module's /sandbox or /testcases subpages, or in your own module sandbox. The tested changes can be added to this page in a single edit. Consider discussing changes on the talk page before implementing them. |
This module provides several functions to facilitate programming with wiki templates. The common theme is that they deal with template scope, the rules of what information is available where in templates.
All of these functions must be invoked directly by the template they are providing their service to: they cannot serve their purpose from inside a wrapper template. This is because they exploit a feature of Scribunto allowing a module to access the template parameters to (and name of) the immediate template in which the module is invoked.
Call functions
Each of these functions calls another template with a set of parameters formed by merging the set of parameters to the surrounding template with the set of parameters to the module invocation. This is useful if the surrounding template is meant to be a shell providing a modified form of the services of another, underlying template. The shell template doesn't have to explicitly pass along every parameter to the underlying template; in fact, the shell doesn't even have to know what all the parameters to the underlying template are, just the particular parameters that matter to the way it modifies the services. If the underlying template is later changed by, say, adding parameters, the implementation of the shell doesn't have to be touched unless the new parameters actually matter to the way the shell modifies the services (although the documentation of the shell might need to be changed if it duplicates explanations of parameters from the underlying template). See for example {{dialog/view}}.
The first unnamed parameter to the invocation names the template to call.
Named parameters to the invocation are passed into the call. Each named parameter to the surrounding template is passed into the call unless overridden by a same-named invocation parameter.
The functions differ from each other in how they handle unnamed parameters.
override
This function handles additional unnamed parameters to the invocation, after the first naming the template to call, in the same way as named parameters: each unnamed invocation parameter is passed into the call in its corresponding position (the first additional parameter becomes unnamed-parameter-1 to the call, etc.), while each unnamed parameter to the surrounding template is passed into the call unless overridden by an invocation parameter in corresponding position.
For example, if page Template:Foo contains invocation
{{#invoke:TScope|override|bar|inner|quux=inner}}
and foo is called elsewhere by {{foo|outer|baz=outer|quux=outer}}
, then the invocation would call Template:Bar with parameters 1=inner
, quux=inner
, and baz=outer
.
The first additional unnamed invocation parameter, after the name of the template to call, is passed into the call with index 1, the second additional unnamed invocation parameter is passed into the call with index 2, and so on. This means, however, that if the unnamed invocation parameters were passed explicitly by their integer names, the integer names specified to the invocation would be one more than the parameter numbers received by the called template. That is,
{{#invoke:TScope|override|bar|baz|5=quux}}
which is equivalent to
{{#invoke:TScope|override|1=bar|2=baz|5=quux}}
would call Template:Bar with parameters 1=baz
and 4=quux
.
prepend
This function handles unnamed parameters by passing them all into the call, first all additional unnamed parameters to the invocation and then all unnamed parameters to the surrounding template. The indices of unnamed surrounding-template parameters are increased by the largest call-index of any of the additional unnamed invocation parameters. For example, if page Template:Foo contains invocation
{{#invoke:TScope|prepend|bar|quux|baz}}
and foo is called elsewhere by {{foo|fnord}}
, then the invocation would call Template:Bar with parameters 1=quux
, 2=baz
, and 3=fnord
.
Each set of unnamed parameters (invocation parameters, and surrounding-template parameters) is treated as a solid block of indices starting with 1, even if some slots within the block (even at the start of the block) are unoccupied. Recalling the note under function override regarding the off-by-one discrepancy between invocation-indices and call-indices, if page Template:Foo contains invocation
{{#invoke:TScope|prepend|bar|5=quux|3=baz}}
and foo is called elsewhere by {{foo|3=fnord}}
, then the invocation would call Template:Bar with parameters 2=baz
, 4=quux
, and 7=fnord
.
append
As function prepend, except that rather than unnamed parameters to the surrounding template having their indices increased, instead unnamed parameters to the module invocation have their indices increased, by the largest index of any unnamed parameter to the surrounding template. For example, if Template:Foo contains invocation
{{#invoke:TScope|append|bar|quux|baz}}
and foo is called elsewhere by {{foo|fnord}}
, then the invocation would call Template:Bar with parameters 1=fnord
, 2=quux
, and 3=baz
.
drop
As function override, except that only named parameters of the surrounding template are passed on to the called template; unnamed parameters are passed only if specified directly to the module invocation.
shiftLeft
Similar to function override, but the first unnamed parameter to the invocation after the name of the template to call is not a parameter to pass into the call, but instead is an integer by which to decrement the indices of unnamed parameters to the surrounding template, dropping any that decrease below 1. For example, if Template:Foo contains invocation
{{#invoke:TScope|shiftLeft|bar|1}}
and foo is called elsewhere by {{foo|baz|quux|fnord}}
, then the invocation would call Template:Bar with parameters 1=quux
and 2=fnord
; while invocation
{{#invoke:TScope|shiftLeft|bar|-2|inner}}
would call Template:Bar with parameters 1=inner
, 3=baz
, 4=quux
, and 5=fnord
.
map
This function calls a named template multiple times, using an interface somewhat similar to function override. As usual, the first unnamed parameter to the invocation names the template to call. If that is the only parameter to the invocation, the target template is called once for each unnamed parameter to the surrounding template, passing in that unnamed parameter as the first unnamed parameter to the call, and passing in all named parameters from the surrounding template; the results are concatenated in increasing order of the indices of the unnamed parameters. For example, if Template:Foo contains invocation
{{#invoke:TScope|map|bar}}
and foo is called elsewhere by {{foo|baz|quux|fnord}}
, then the invocation would call Template:Bar three times, with respectively parameter 1=baz
, 1=quux
, and 1=fnord
.
Named parameters to the invocation override same-named parameters to the surrounding template. The optional second unnamed parameter to the invocation must be a non-negative integer indicating so many leading unnamed parameters to the surrounding template should be passed as later unnamed parameters to each call instead of being featured as first-unnamed to a call. For example, if Template:Foo contains invocation
{{#invoke:TScope|map|bar|2|quux=inner}}
and foo is called elsewhere by {{foo|one|two|three|four|five|baz=outer|quux=outer|fnord=outer}}
, then the invocation would call Template:Bar three times, with respectively 1=three
, 1=four
, 1=five
, and each call would get 2=one
, 3=two
, baz=outer
, quux=inner
, fnord=outer
. Additional unnamed parameters to the invocation are also passed to each call, overriding any passed through from the surrounding template; thus, in the immediately preceding example, if the invocation were instead
{{#invoke:TScope|map|bar|2|inner|quux=inner}}
the calls would be the same except with 2=inner
instead of 2=one
.
static
This function returns the name of the template containing the invocation of the module; in contrast to magic word {{PAGENAME}}, which returns the name of the page being displayed. For example, if page Quux is viewed, and contains a call to Template:Bar, which contains a call to Template:Foo, which invokes this function and also calls magic word {{PAGENAME}}, the call to the magic word returns Quux
while the invocation returns Template:Foo
.
echo
This function returns, in general, two wikitables giving first the names and values of all parameters passed to the invocation of the module, then the names and values of all parameters passed to the template containing the invocation of the module. If the invocation is given no parameters beyond the name of the function, that wikitable is omitted.
local export = {}
export.override = function( frame )
local title = frame.args[1]
local args = {}
for v, k in pairs( frame:getParent().args ) do
args[v] = k
end
for v, k in pairs( frame.args ) do
if type( v ) == "number" then
if v ~= 1 then
args[ v - 1 ] = k
end
else
args[v] = k
end
end
return frame:expandTemplate{ title = title, args = args }
end
export.prepend = function( frame )
local title = frame.args[1]
local args = {}
local displace = 0;
for v, k in pairs( frame.args ) do
if (type( v ) == "number") and (v ~= 1) then
args[ v - 1 ] = k
displace = math.max( displace, (v - 1) )
end
end
for v, k in pairs( frame:getParent().args ) do
if type( v ) == "number" then
args[ displace + v ] = k
else
args[v] = k
end
end
for v, k in pairs( frame.args ) do
if type( v ) ~= "number" then
args[v] = k
end
end
return frame:expandTemplate{ title = title, args = args }
end
export.append = function( frame )
local title = frame.args[1]
local args = {}
local displace = 0;
for v, k in pairs( frame:getParent().args ) do
if type( v ) == "number" then
displace = math.max( displace, v )
end
args[v] = k
end
for v, k in pairs( frame.args ) do
if type( v ) == "number" then
if v ~= 1 then
args[ displace + v - 1 ] = k
end
else
args[v] = k
end
end
return frame:expandTemplate{ title = title, args = args }
end
export.drop = function( frame )
local title = frame.args[1]
local args = {}
for v, k in pairs( frame:getParent().args ) do
if type( v ) ~= "number" then
args[v] = k
end
end
for v, k in pairs( frame.args ) do
if type( v ) == "number" then
if v ~= 1 then
args[ v - 1 ] = k
end
else
args[v] = k
end
end
return frame:expandTemplate{ title = title, args = args }
end
export.shiftLeft = function( frame )
local title = frame.args[1]
local args = {}
local displace = tonumber( frame.args[2] )
if displace == nil then displace = 0 end
for v, k in pairs( frame:getParent().args ) do
if type( v ) == "number" then
if v >= displace then
args[ v - displace ] = k
end
else
args[v] = k
end
end
for v, k in pairs( frame.args ) do
if type( v ) == "number" then
if v > 2 then
args[ v - 2 ] = k
end
else
args[v] = k
end
end
return frame:expandTemplate{ title = title, args = args }
end
export.map = function( frame )
local title = frame.args[1]
local displace = frame.args[2]
if displace == nil then
displace = 0
else
displace = tonumber( displace )
end
local args = {}
local data = {}
local maxv = 0
for v, k in pairs( frame:getParent().args ) do
if (type( v ) ~= "number") then
args[v] = k
elseif v <= displace then
args[v + 1] = k
else
data[v] = k
maxv = math.max( v, maxv )
end
end
for v, k in pairs( frame.args ) do
if type( v ) ~= "number" then
args[v] = k
elseif v > 2 then
args[v - 1] = k
end
end
local result = ""
for v = 1, maxv do
if data[v] ~= nil then
args[1] = data[v]
result = result .. frame:expandTemplate{ title = title, args = args }
end
end
return result
end
export.static = function( frame )
return frame:getParent():getTitle()
end
local function tabulate( args )
local s = ''
for k, v in pairs( args ) do
s = s .. '|-\n| ' .. k .. '\n| <code>' .. v .. '</code>\n'
end
if s ~= '' then
s = '{| class="wikitable"\n|-\n! key\n! value\n' .. s .. '|}'
end
return s
end
export.echo = function( frame )
local mp = tabulate( frame.args )
local cp = tabulate( frame:getParent().args )
if mp ~= '' then
mp = 'module parameters:\n' .. mp .. '\n'
end
if cp ~= '' then
cp = 'context parameters:\n' .. cp .. '\n'
else
cp = 'no context parameters.\n'
end
return mp .. cp
end
return export