Module:List
- 不再使用模块:Arguments以自动控制参数,取而代之的是通过arguments参数来选择参数的来源。
- 生成的列表不再被div标签包围。本wiki支持直接对列表标签给予hlist类。
- 支持对列表各项进行统一修改。
- 支持使用直接连接和用自然语言连接列表。
本模块可以输出各种类型的列表。目前,它支持带点的无序列表、不带点的无序列表、水平列表、有序列表(数字的或字母的)、水平有序列表、直接连接列表和用自然语言连成的列表。它允许对各个列表项目进行单独的css样式。
用法[编辑源代码]
快速使用[编辑源代码]
{{#invoke:list|函数|第一项|第二项|第三项|…}}
所有参数[编辑源代码]
- 位次参数
- 列表的内容
- start
- 有序列表的开始数字
- type
- 有序列表的标序类别
- liststyletype
- 有序列表标记的类型(使用CSS)
- class
- 类
- style
- 样式
- liststyle
- 列表的样式
- itemstyle
- 列表项的样式
- item1style、item2style、item3style
- 第1项的样式、第2项的样式、第3项的样式
- item1value、item2value、item3value
- 第1项的值、第2项的值、第3项的值
- indent
- 水平列表的缩进
以下参数为本站特有:
- arguments
- 指定参数的来源
- modification
- 指定一个模块对各项进行修改
- function
- 将模块作为一个表,指定其内函数进行修改
- call
- 对每个参数调用一个模板,其模板名称即为这个值
- content_as
- 调用模板时,将列表项的原始内容作为值,其对应的键即为这个content_as的值(可以是数字或字符串),默认为1
- para_参数名称
- 调用模板时的参数
- replacement
- 列表的每一项为将这个值中的%s替换为原始内容之后的值
- prefix
- 列表每一项的前缀
- suffix
- 列表每一项的后缀
从上级模板传递下来的参数[编辑源代码]
{{#invoke:list|函数}}
函数[编辑源代码]
函数名称 | 产生 | 示例输出 |
---|---|---|
bulleted
|
带点的无序列表 |
|
unbulleted
|
不带点的无序列表 |
|
horizontal
|
水平无序列表 |
|
ordered
|
有序列表(数字标识和字母标识) |
|
horizontal_ordered
|
水平有序列表 |
|
concat
|
直接连接(本站特有) | 第一项第二项第三项 |
list_to_text
|
使用自然语言连接(本站特有) | 第一项、第二项和第三项 |
参数[编辑源代码]
基本参数[编辑源代码]
- 位次参数(positional parameters)(
1
、2
、3
……)——这些是列表项。如果没有列表项,模块不输出任何值。 start
——设置有序列表的开始。可以是数字序列列表的开始数字,也可以是字母列表的开始字母。水平有序列表只支持数字。type
——有序列表使用的标识类别。比如,数字“1”(默认)、大写字母“A”、小写字母“a”、大写希腊字母“I”、小写希腊字母“i”。水平有序列表不支持。参考liststyletype
参数。liststyletype
——有序列表标识的类别,使用CSS样式,并且使用html标记比type
参数拥有更多的可行类型。可用的值都列举在MDN的list-style-type页面。不同浏览器可能支持性不同。class
——列表标签的自定义类。本模块不使用div标签。style
——列表标签的自定义css样式,例如,font-size: 90%;
。liststyle
——同style
参数。itemstyle
——对于所有列表项的自动css样式。格式同style
参数。item1style
、item2style
、item3style
……——为每个列表项的自定义css样式。格式同style
参数。item1value
、item2value
、item3value
……对给定列表项的自定义值。给定一个,后面的值会从这个指定的值开始增加。这个值应该是正整数。(仅对有序列表有效。)indent
——缩进列表,仅适用于水平列表和水平有序列表。值必须是一个数字,比如2
。缩进成倍计算,是指定值的1.6倍。未指定时为零。arguments
——参数的来源。self
表示只接受通过#invoke调用模块时的参数,parent
表示使用调用了此模块的模板时传入的参数,template
表示位次参数视为parent,赋名参数为self,both
表示同时考虑二者,且parent优先。默认为self
。separation
或sep
——在类型为code或list_to_text时,将各项连接起来。conjunction
或conj
——在类型为list_to_text时,最后一项与倒数第二项的连接。
修改列表各项内容[编辑源代码]
本模块支持对列表各项内容进行统一的修改。共有以下几种修改方法。注意以下这些修改方法只能选择一种,或者全都不选。
为了表述方便,我们将模板参数中输入的每一项内容称为原始内容,修改后的每一项的内容称为修改后内容,这个用于修改的函数(如有)称为修改函数。
调用模块[编辑源代码]
可以对每一项调用特定的模块进行修改。其参数用法为:
modification
= 要调用的模块的页面名称。当这个页面不存在时无效。当这个页面未指定而function
指定了时,这个模块名称默认为Module:List/preset functionsfunction
= 要调用的模块中的函数名称。如果这个值指定了,则将整个模块作为一个表,取其相应的域作为修改函数。如果这个值没有指定,则将整个模块作为修改函数。
比如,如果modification
=Module:a,而function
是b,则这个修改函数(记为modify)可以理解为:
modify = require 'Module:a'.b
如果modification
=Module:a,而function
没有指定,则这个修改函数可以理解为:
modify = require 'Module:a'
本站预置了几个常用于此模块的修改函数,参见Module:List/preset functions。我们以其中的函数sectionLink为例,该函数可以用于生成内链,并同时将“#”替换为“§”。这种情况下,modification
未指定,而function
=sectionLink,因此这个修改函数可以理解为:
modify = require 'Module:List/preset functions'.sectionLink
print(modify('a')) -- 会输出[[a]]
print(modify('a#b')) -- 会输出[[a#b|a§b]]
初步理解了这个函数之后,我们可以将它直接使用:
代码 | 结果 |
---|---|
{{#invoke:list|bulleted|第一项|第二项|第三项#段落名称 |function=sectionLink}} |
|
{{#invoke:list|list_to_text|第一项|第二项|第三项#段落名称 |function=sectionLink}} |
第一项、第二项和第三项 § 段落名称 |
调用模板[编辑源代码]
我们可以将原始内容作为模板的参数,同时加入其它参数,将模板展开后的结果作为修改后内容。
其参数用法为:
call
= 要调用的模板名称,可以省略命名空间前缀。content_as
= 要将原始内容作为调用的模板的哪个参数,默认为要调用的模板的第一个参数,即默认值为1。para_参数名称
= 指定调用模板时加入的其他参数。
为了更好地理解,我们将各个代码的用法和等价效果进行比较。
代码 | 等价效果 |
---|---|
{{#invoke:list|list_to_text|第一项|第二项|第三项 |call=a}} |
{{a|第一项}}、{{a|第二项}}和{{a|第三项}} |
{{#invoke:list|list_to_text|第一项|第二项|第三项 |call=a|content_as=b}} |
{{a|b=第一项}}、{{a|b=第二项}}和{{a|b=第三项}} |
{{#invoke:list|list_to_text|第一项|第二项|第三项 |call=a|content_as=b|para_c=d}} |
{{a|b=第一项|c=d}}、{{a|b=第二项|c=d}}和{{a|b=第三项|c=d}} |
{{#invoke:list|list_to_text|第一项|第二项|第三项 |call=a|para_2=d}} |
{{a|第一项|d}}、{{a|第二项|d}}和{{a|第三项|d}} 或: {{a|1=第一项|2=d}}、{{a|1=第二项|2=d}}和{{a|1=第三项|2=d}} |
请注意这种修改方法比较占开销,因此这种方法能避免就避免。
替换格式[编辑源代码]
你可以指定一个被替换文本,将被替换文本中的“%s”替换为原始内容之后即为修改后内容。这有点类似于string.format函数,但是可以替换可以多次,且不支持%a、%d等特殊用法。
代码 | 结果 |
---|---|
{{#invoke:list|bulleted|第一项|第二项|第三项 |replacement=这个%s和那个%s}} |
|
{{#invoke:list|bulleted|第一项|第二项|第三项 |replacement=[[User:%s|%s]]}} |
前后缀[编辑源代码]
你可以直接给原始内容加入前缀和后缀。这个当然也可以通过替换文字来实现,不过直接加前后缀显然更加简便。
代码 | 结果 |
---|---|
{{#invoke:list|bulleted|第一项|第二项|第三项 |prefix=这是}} |
|
{{#invoke:list|concat|第一项|第二项|第三项 |suffix=平安|sep=,}} |
第一项平安,第二项平安,第三项平安 |
注意,前后缀可以同时都有,但是不能设置像|prefix={{|suffix=}}
或|prefix=[[|suffix=]]
这样的参数,因为这会直接影响维基文本的解析;即使加了nowiki也不行,因为这会直接导致文本不解析。虽然模块可以剥离nowiki并反转义,但谁愿意那样做呢?
示例[编辑源代码]
带点的有序列表[编辑源代码]
代码 | 结果 |
---|---|
{{#invoke:list|bulleted|第一项|第二项|第三项}}
|
|
{{#invoke:list|bulleted|第一项|第二项|第三项|itemstyle=color:blue;}}
|
|
{{#invoke:list|bulleted|第一项|第二项|第三项|item1style=background-color:yellow;|item2style=background-color:silver;}}
|
|
不带点的无序列表[编辑源代码]
代码 | 结果 |
---|---|
{{#invoke:list|unbulleted|第一项|第二项|第三项}}
|
|
{{#invoke:list|unbulleted|第一项|第二项|第三项|itemstyle=color:blue;}}
|
|
{{#invoke:list|unbulleted|第一项|第二项|第三项|item1style=background-color:yellow;|item2style=background-color:silver;}}
|
|
水平列表[编辑源代码]
代码 | 结果 |
---|---|
{{#invoke:list|horizontal|第一项|第二项|第三项}}
|
|
{{#invoke:list|horizontal|第一项|第二项|第三项|indent=2}}
|
|
有序列表[编辑源代码]
代码 | 结果 |
---|---|
{{#invoke:list|ordered|第一项|第二项|第三项}}
|
|
{{#invoke:list|ordered|第一项|第二项|第三项|start=3}}
|
|
{{#invoke:list|ordered|第一项|第二项|第三项|type=i}}
|
|
{{#invoke:list|ordered|第一项|第二项|第三项|liststyletype=lower-greek}}
|
|
水平有序列表[编辑源代码]
代码 | 结果 |
---|---|
{{#invoke:list|horizontal_ordered|第一项|第二项|第三项}}
|
|
{{#invoke:list|horizontal_ordered|第一项|第二项|第三项|start=3}}
|
|
{{#invoke:list|horizontal_ordered|第一项|第二项|第三项|indent=2}}
|
|
直接连接[编辑源代码]
代码 | 结果 |
---|---|
{{#invoke:list|concat|第一项|第二项|第三项}}
|
第一项第二项第三项 |
{{#invoke:list|concat|第一项|第二项|第三项|sep= / }}
|
第一项/第二项/第三项 |
{{#invoke:list|concat|第一项|第二项|第三项|sep=、|conj=及}}
|
第一项、第二项及第三项 |
注:separation
和sep
等价,conjunction
和conj
等价。
用自然语言连接[编辑源代码]
代码 | 结果 |
---|---|
{{#invoke:list|list_to_text|第一项|第二项|第三项}}
|
第一项、第二项和第三项 |
{{#invoke:list|list_to_text|第一项|第二项|第三项|sep=,}}
|
第一项,第二项和第三项 |
{{#invoke:list|list_to_text|第一项|第二项|第三项|conj=或}}
|
第一项、第二项或第三项 |
-- This module outputs different kinds of lists. At the moment, bulleted,
-- unbulleted, horizontal, ordered, and horizontal ordered lists are supported.
-- local libUtil = require('libraryUtil')
-- local checkType = libUtil.checkType
local TableTools = require('Module:TableTools')
local p = {}
local listTypes = {
['bulleted'] = true,
['unbulleted'] = true,
['horizontal'] = true,
['ordered'] = true,
['horizontal_ordered'] = true,
concat = true,
list_to_text = true
}
function p.makeListData(listType, args)
-- Constructs a data table to be passed to p.renderList.
local data = {}
-- Classes
data.classes = {}
if listType == 'horizontal' or listType == 'horizontal_ordered' then
data.classes[#data.classes + 1] = 'hlist'
elseif listType == 'unbulleted' then
data.classes[#data.classes + 1] = 'plainlist'
end
data.classes[#data.classes + 1] = args.class
-- 设置trim是否为true
do
local trim = args.trim
data.trim = not(trim=='0' or trim==false)
end
-- Indent for horizontal lists
if listType == 'horizontal' or listType == 'horizontal_ordered' then
local indent = tonumber(args.indent)
indent = indent and indent * 1.6 or 0
if indent > 0 then
data.marginLeft = indent .. 'em'
end
end
-- List style types for ordered lists
-- This could be "1, 2, 3", "a, b, c", or a number of others. The list style
-- type is either set by the "type" attribute or the "list-style-type" CSS
-- property.
if listType == 'ordered' or listType == 'horizontal_ordered' then
data.listStyleType = args.liststyletype
data.type = args['type']
-- Detect invalid type attributes and attempt to convert them to
-- list-style-type CSS properties.
if data.type
and not data.listStyleType
and not tostring(data.type):find('^%s*[1AaIi]%s*$')
then
data.listStyleType = data.type
data.type = nil
end
end
-- List tag type
if listType == 'ordered' or listType == 'horizontal_ordered' then
data.listTag = 'ol'
elseif listType == 'concat' or listType == 'list_to_text' then
data.listTag = false
else
data.listTag = 'ul'
end
-- Start number for ordered lists
data.start = args.start
if listType == 'horizontal_ordered' then
-- Apply fix to get start numbers working with horizontal ordered lists.
local startNum = tonumber(data.start)
if startNum then
data.counterReset = 'listitem ' .. tostring(startNum - 1)
end
end
-- List style
-- ul_style and ol_style are included for backwards compatibility. No
-- distinction is made for ordered or unordered lists.
data.listStyle = args.liststyle or args.style
-- List items
-- li_style is included for backwards compatibility. item_style was included
-- to be easier to understand for non-coders.
data.itemStyle = args.itemstyle
data.items = {}
if #args == 0 then
args[1] = default
end
local trim = data.trim
for num, v in TableTools.sparseIpairs(args) do
if trim then
v = mw.text.trim(v)
end
if (not trim) or v~='' then
-- 实际上相当于if trim and v=='' then continue end,
-- 但是Lua没有continue语法。
local item = {}
item.content = v
item.style = args['item' .. tostring(num) .. 'style']
item.value = args['item' .. tostring(num) .. 'value']
data.items [#data.items + 1] = item
end
end
-- 列表修饰函数。修饰函数在渲染列表时才调用。
data.modify = false --初始化
if args.modification or args['function'] then
-- 指定调用一个模块对参数进行修改。
-- 如果没有指定函数名称,则将整个模块作为函数。
-- 如果指定了函数但是没有指定模块名称,
-- 则模块名称默认为Module:List/preset functions
local module_name = args.modification or 'Module:List/preset functions'
local function_name = args['function']
local success, target_module=pcall(require, module_name)
if success then
if function_name and type(target_module)=='table' then
data.modify = target_module[function_name]
elseif type(target_module)=='function'
or (getmetatable(target_module) or {}).__call then
data.modify = target_module
end
end
end
if args.call then
-- 指定一个模板,并且调用它。并且调用模板时,以列表项内容为参数。
-- 如果有第二个参数,取para作为第二个参数。
local template_name = args.call
local frame = frame or mw.getCurrentFrame()
local para = args.para
local call_args = {}
local content_key = args.content_as or 1
for k,v in pairs(args) do
-- 修复于 2023-6-15:数字键会导致此处出错
local key = type(k) == 'string' and k:match('^para_(.+)')
if key then call_args[key]=v end
end
function data.modify(content)
-- 修复于 2023-6-15:错误处理了content参数
if content_key then
call_args[content_key] = content
end
return frame:expandTemplate{
title = template_name,
args = call_args
}
end
end
--[[
if args.format then
-- 指定一个格式,并将其应用。
-- 注意:一个格式标记只能使用一次!
-- 由于使用多余一次会导致错误,故该函数暂时禁用。
function data.modify(content)
return string.format(args.format, content)
end
end
]]
if args.replacement then
-- 指定一串文本,将其%s替换为其内容。
-- 可以替换多次。
function data.modify(content)
return args.replacement:gsub('%%s',content)
end
end
if args.prefix or args.suffix then
-- 指定前缀和后缀,将其应用。
local prefix = args.prefix or ''
local suffix = args.suffix or ''
function data.modify(content)
return prefix .. content .. suffix
end
end
return data
end
function p.renderList(data)
-- Renders the list HTML.
-- Return the blank string if there are no list items.
if type(data.items) ~= 'table' or #data.items < 1 then
return ''
end
-- Render the main div tag.
-- 这里简化代码,不这样渲染
-- Render the list tag.
local list = mw.html.create(data.listTag or 'ul')
for i, class in ipairs(data.classes or {}) do
list:addClass(class)
end
list
:attr{start = data.start, type = data.type}
:css{
['counter-reset'] = data.counterReset,
['list-style-type'] = data.listStyleType,
['margin-left'] = data.marginLeft
}
if data.listStyle then
list:cssText(data.listStyle)
end
local modify = type(data.modify) == 'function' and data.modify or nil
-- Render the list items
for i, t in ipairs(data.items or {}) do
local item = list:tag('li')
local content
if modify then
content = modify(t.content)
else
content = t.content
end
if data.itemStyle then
item:cssText(data.itemStyle)
end
if t.style then
item:cssText(t.style)
end
item
:attr{value = t.value}
:wikitext(content)
end
return tostring(list)
end
function p.renderList2(data, listType, separation, conjunction)
local list = {}
local modify = type(data.modify) == 'function' and data.modify or nil
for i, t in ipairs(data.items or {}) do
local item
local content
if modify then
content = modify(t.content)
else
content = t.content
end
if data.itemStyle or t.style then -- 这一项定义了样式
item = mw.html.create'span'
:wikitext(content)
:cssText(data.itemStyle)
:cssText(t.style)
list[#list + 1] = tostring(item)
else -- 这一项没有定义任何样式
list[#list + 1] = content
end
end
if listType=='concat' then
if separation and conjunction then
return mw.text.listToText(list, separation, conjunction)
else
return table.concat(list, separation)
end
elseif listType=='list_to_text' then
return mw.text.listToText(list, separation, conjunction)
end
end
function p.makeList(listType, args)
-- 如果未指定listType或listType指定不正确,取默认值bulleted
if not listType or not listTypes[listType] then
listType = 'bulleted'
end
-- checkType('makeList', 2, args, 'table')
local data = p.makeListData(listType, args)
if listType == 'concat' or listType == 'list_to_text' then
return p.renderList2(data,listType,args.separation or args.sep,args.conjunction or args.conj)
else
return p.renderList(data)
end
end
for listType in pairs(listTypes) do
p[listType] = function (frame)
-- local mArguments = require('Module:Arguments')
local origArgs = frame.args
local parentFrame = frame:getParent()
local parentArgs = type(parentFrame)=='table'
and parentFrame.args or nil
local arguments = origArgs.arguments or 'self'
-- 关于此参数的说明:
-- self(默认):只考虑通过#invoke调用的模块自身的参数
-- parent:使用调用了此模块的模板时传入的参数
-- template:数字参数为parent,其他参数为self
-- both:同时考虑二者,且模板参数优先,相当于parentFirst
-- Copy all the arguments to a new table, for faster indexing.
local args = {}
if arguments=='self' or arguments=='both' or arguments=='template' then
for k, v in pairs(origArgs) do
if arguments~='template' or type(k)~='number' then
v = type(k)=='number' and v or mw.text.trim(v)
args[k] = v~='' and v or nil
end
end
end
if arguments=='parent' or arguments=='both' or arguments=='template' then
for k,v in pairs(parentArgs) do
if arguments~='template' or type(k)=='number' then
v = type(k)=='number' and v or mw.text.trim(v)
args[k] = v~='' and v or nil
end
end
end
return p.makeList(listType, args)
end
end
return p