Module:List

zhwiki>Xiplus-abot2024年11月3日 (日) 20:50的版本 (已更改“Module:List”的保护设置:​高風險模板:100025引用<!-- 機器人3 -->([编辑=仅允许管理员](无限期)[移动=仅允许管理员](无限期)))
(差异) ←上一版本 | 最后版本 (差异) | 下一版本→ (差异)

本模块可以输出各种类型的列表。目前,它支持带点的无序列表、不带点的无序列表、水平列表、有序列表(数字的或字母的)、水平有序列表、直接连接列表和用自然语言连成的列表。它允许对各个列表项目进行单独的css样式。

用法

快速使用

模板链接:{{#invoke:list|函数|第一项|第二项|第三项|…}}

所有参数

位次参数
列表的内容
start
有序列表的开始数字
type
有序列表的标序类别
liststyletype或list-style-type
有序列表标记的类型(使用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
列表每一项的后缀
trim
是否移除各参数的两侧空格并忽略空白参数。

从上级模板传递下来的参数

模板链接:{{#invoke:list|函数}}

函数

函数名称 产生 示例输出
bulleted 带点的无序列表
  • 第一项
  • 第二项
  • 第三项
unbulleted 不带点的无序列表
  • 第一项
  • 第二项
  • 第三项
horizontal 水平无序列表
  • 第一项
  • 第二项
  • 第三项
ordered 有序列表(数字标识和字母标识)
  1. 第一项
  2. 第二项
  3. 第三项
horizontal_ordered 水平有序列表
  1. 第一项
  2. 第二项
  3. 第三项
concat 直接连接(本站特有) 脚本错误:函数“concat”不存在。
list_to_text 使用自然语言连接(本站特有) 脚本错误:函数“list_to_text”不存在。

参数

基本参数

  • 位次参数(positional parameters)(1、2、3……)——这些是列表项。如果没有列表项,模块不输出任何值。
  • start——设置有序列表的开始。可以是数字序列列表的开始数字,也可以是字母列表的开始字母。水平有序列表只支持数字。
  • type——有序列表使用的标识类别。比如,数字“1”(默认)、大写字母“A”、小写字母“a”、大写希腊字母“I”、小写希腊字母“i”。水平有序列表不支持。参考liststyletype参数。
  • liststyletype或list-style-type——有序列表标识的类别,使用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优先。默认为both。
  • separation或sep——在类型为code或list_to_text时,将各项连接起来。
  • conjunction或conj——在类型为list_to_text时,最后一项与倒数第二项的连接。

修改列表各项内容

本模块支持对列表各项内容进行统一的修改。共有以下几种修改方法。注意以下这些修改方法只能选择一种,或者全都不选。

为了表述方便,我们将模板参数中输入的每一项内容称为原始内容,修改后的每一项的内容称为修改后内容,这个用于修改的函数(如有)称为修改函数。

调用模块

可以对每一项调用特定的模块进行修改。其参数用法为:

  • modification = 要调用的模块的页面名称。当这个页面不存在时无效。当这个页面未指定而function指定了时,这个模块名称默认为Module:List/preset functions
  • function = 要调用的模块中的函数名称。如果这个值指定了,则将整个模块作为一个表,取其相应的域作为修改函数。如果这个值没有指定,则将整个模块作为修改函数。

比如,如果modification=Module:a,而function是b,则这个修改函数(记为modify)可以理解为:

modify = require 'Module:a'.b

如果modification=Module:a,而function没有指定,则这个修改函数可以理解为:

modify = require 'Module:a'

调用模板

我们可以将原始内容作为模板的参数,同时加入其它参数,将模板展开后的结果作为修改后内容。

其参数用法为:

  • 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=,}}
您所看到的

脚本错误:函数“concat”不存在。

注意,前后缀可以同时都有,但是不能设置像|prefix={{|suffix=}}或|prefix=[[|suffix=]]这样的参数,因为这会直接影响维基文本的解析;即使加了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|第一项|第二项|第三项}}

您所看到的
  1. 第一项
  2. 第二项
  3. 第三项
您所输入的

模板链接:{{#invoke:list|ordered|第一项|第二项|第三项|start=3}}

您所看到的
  1. 第一项
  2. 第二项
  3. 第三项
您所输入的

模板链接:{{#invoke:list|ordered|第一项|第二项|第三项|type=i}}

您所看到的
  1. 第一项
  2. 第二项
  3. 第三项
您所输入的

模板链接:{{#invoke:list|ordered|第一项|第二项|第三项|liststyletype=lower-greek}}

您所看到的
  1. 第一项
  2. 第二项
  3. 第三项

水平有序列表

您所输入的

模板链接:{{#invoke:list|horizontal_ordered|第一项|第二项|第三项}}

您所看到的
  1. 第一项
  2. 第二项
  3. 第三项
您所输入的

模板链接:{{#invoke:list|horizontal_ordered|第一项|第二项|第三项|start=3}}

您所看到的
  1. 第一项
  2. 第二项
  3. 第三项
您所输入的

模板链接:{{#invoke:list|horizontal_ordered|第一项|第二项|第三项|indent=2}}

您所看到的
  1. 第一项
  2. 第二项
  3. 第三项

直接连接

您所输入的

模板链接:{{#invoke:list|concat|第一项|第二项|第三项}}

您所看到的

脚本错误:函数“concat”不存在。

您所输入的

模板链接:{{#invoke:list|concat|第一项|第二项|第三项|sep=/}}

您所看到的

脚本错误:函数“concat”不存在。

您所输入的

模板链接:{{#invoke:list|concat|第一项|第二项|第三项|conj=及|sep=、}}

您所看到的

脚本错误:函数“concat”不存在。

注:separation和sep等价,conjunction和conj等价。

用自然语言连接

您所输入的

模板链接:{{#invoke:list|list_to_text|第一项|第二项|第三项}}

您所看到的

脚本错误:函数“list_to_text”不存在。

您所输入的

模板链接:{{#invoke:list|list_to_text|第一项|第二项|第三项|sep=,}}

您所看到的

脚本错误:函数“list_to_text”不存在。

您所输入的

模板链接:{{#invoke:list|list_to_text|第一项|第二项|第三项|conj=或}}

您所看到的

脚本错误:函数“list_to_text”不存在。


local libUtil = require('libraryUtil')
local checkType = libUtil.checkType
local mTableTools = require('Module:TableTools')

local p = {}

local listTypes = {
	['bulleted'] = true,
	['unbulleted'] = true,
	['horizontal'] = true,
	['ordered'] = true,
	['horizontal_ordered'] = true
}

function p.makeListData(listType, args)
	-- Constructs a data table to be passed to p.renderList.
	local data = {}

	-- Classes and TemplateStyles
	data.classes = {}
	data.templatestyles = ''
	if listType == 'horizontal' or listType == 'horizontal_ordered' then
		table.insert(data.classes, 'hlist')
		data.templatestyles = mw.getCurrentFrame():extensionTag{
			name = 'templatestyles', args = { src = 'Hlist/styles.css' }
		}
	elseif listType == 'unbulleted' then
		table.insert(data.classes, 'plainlist')
		data.templatestyles = mw.getCurrentFrame():extensionTag{
			name = 'templatestyles', args = { src = 'Plainlist/styles.css' }
		}
	end
	table.insert(data.classes, args.class)

	-- Main div style
	data.style = args.style

	-- 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.list_style_type or args['list-style-type']
		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'
	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.list_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.item_style or args.li_style
	data.items = {}
	for _, num in ipairs(mTableTools.numKeys(args)) do
		local item = {}
		item.content = args[num]
		item.style = args['item' .. tostring(num) .. '_style']
			or args['item_style' .. tostring(num)]
			or args['li_style' .. tostring(num)]
		item.value = args['item' .. tostring(num) .. '_value']
			or args['item_value' .. tostring(num)]
			or args['li_value' .. tostring(num)]
		table.insert(data.items, item)
	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.
	local root = mw.html.create('div')
	for _, class in ipairs(data.classes or {}) do
		root:addClass(class)
	end
	root:css{['margin-left'] = data.marginLeft}
	if data.style then
		root:cssText(data.style)
	end

	-- Render the list tag.
	local list = root:tag(data.listTag or 'ul')
	list
		:attr{start = data.start, type = data.type}
		:css{
			['counter-reset'] = data.counterReset,
			['list-style-type'] = data.listStyleType
		}
	if data.listStyle then
		list:cssText(data.listStyle)
	end

	-- Render the list items
	for _, t in ipairs(data.items or {}) do
		local item = list:tag('li')
		if data.itemStyle then
			item:cssText(data.itemStyle)
		end
		if t.style then
			item:cssText(t.style)
		end
		item
			:attr{value = t.value}
			:wikitext(t.content)
	end

	return data.templatestyles .. tostring(root)
end

function p.renderTrackingCategories(args)
	local isDeprecated = false -- Tracks deprecated parameters.
	for k, v in pairs(args) do
		k = tostring(k)
		if k:find('^item_style%d+$') or k:find('^item_value%d+$') then
			isDeprecated = true
			break
		end
	end
	local ret = ''
	if isDeprecated then
		ret = ret .. '[[Category:含有过期参数的列表模板]]'
	end
	return ret
end

function p.makeList(listType, args)
	if not listType or not listTypes[listType] then
		error(string.format(
			"bad argument #1 to 'makeList' ('%s'不是合适的列表类型)",
			tostring(listType)
		), 2)
	end
	checkType('makeList', 2, args, 'table')
	local data = p.makeListData(listType, args)
	local list = p.renderList(data)
	local trackingCategories = p.renderTrackingCategories(args)
	return list .. trackingCategories
end

for listType in pairs(listTypes) do
	p[listType] = function (frame)
		local mArguments = require('Module:Arguments')
		local origArgs = mArguments.getArgs(frame, {
			frameOnly = ((frame and frame.args and frame.args.frameonly or '') ~= ''),
			valueFunc = function (key, value)
			if not value or not mw.ustring.find(value, '%S') then return nil end
			if mw.ustring.find(value, '^%s*[%*#;:]') then
				return value
			else
				return value:match('^%s*(.-)%s*$')
			end
			return nil
		end
		})
		-- Copy all the arguments to a new table, for faster indexing.
		local args = {}
		for k, v in pairs(origArgs) do
			args[k] = v
		end
		return p.makeList(listType, args)
	end
end

return p