模块:List:修订间差异

来自Rizline中文维基
(创建页面,内容为“-- 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 mTableTools = require('Module:TableTools') local p = {} local listTypes = { ['bulleted'] = true, ['unbulleted'] = true, ['horizontal'] = true, ['ordered'] = true, ['horizontal_ordered'] = true } function p.makeListData(li…”)
 
无编辑摘要
 
第2行: 第2行:
-- unbulleted, horizontal, ordered, and horizontal ordered lists are supported.
-- unbulleted, horizontal, ordered, and horizontal ordered lists are supported.


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


local p = {}
local p = {}
第13行: 第13行:
['horizontal'] = true,
['horizontal'] = true,
['ordered'] = true,
['ordered'] = true,
['horizontal_ordered'] = true
['horizontal_ordered'] = true,
concat = true,
list_to_text = true
}
}


第23行: 第25行:
data.classes = {}
data.classes = {}
if listType == 'horizontal' or listType == 'horizontal_ordered' then
if listType == 'horizontal' or listType == 'horizontal_ordered' then
table.insert(data.classes, 'hlist')
data.classes[#data.classes + 1] = 'hlist'
elseif listType == 'unbulleted' then
elseif listType == 'unbulleted' then
table.insert(data.classes, 'plainlist')
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
end
table.insert(data.classes, args.class)
-- Main div style
data.style = args.style


-- Indent for horizontal lists
-- Indent for horizontal lists
第46行: 第51行:
-- property.
-- property.
if listType == 'ordered' or listType == 'horizontal_ordered' then  
if listType == 'ordered' or listType == 'horizontal_ordered' then  
data.listStyleType = args.list_style_type or args['list-style-type']
data.listStyleType = args.liststyletype
data.type = args['type']
data.type = args['type']


第63行: 第68行:
if listType == 'ordered' or listType == 'horizontal_ordered' then
if listType == 'ordered' or listType == 'horizontal_ordered' then
data.listTag = 'ol'
data.listTag = 'ol'
elseif listType == 'concat' or listType == 'list_to_text' then
data.listTag = false
else
else
data.listTag = 'ul'
data.listTag = 'ul'
第80行: 第87行:
-- ul_style and ol_style are included for backwards compatibility. No
-- ul_style and ol_style are included for backwards compatibility. No
-- distinction is made for ordered or unordered lists.
-- distinction is made for ordered or unordered lists.
data.listStyle = args.list_style
data.listStyle = args.liststyle or args.style


-- List items
-- List items
-- li_style is included for backwards compatibility. item_style was included
-- li_style is included for backwards compatibility. item_style was included
-- to be easier to understand for non-coders.
-- to be easier to understand for non-coders.
data.itemStyle = args.item_style or args.li_style
data.itemStyle = args.itemstyle
data.items = {}
data.items = {}
for i, num in ipairs(mTableTools.numKeys(args)) do
if #args == 0 then
local item = {}
args[1] = default
item.content = args[num]
end
item.style = args['item' .. tostring(num) .. '_style']
local trim = data.trim
or args['item_style' .. tostring(num)]
for num, v in TableTools.sparseIpairs(args) do
or args['li_style' .. tostring(num)]
if trim then
item.value = args['item' .. tostring(num) .. '_value']
v = mw.text.trim(v)
or args['item_value' .. tostring(num)]
end
or args['li_value' .. tostring(num)]
if (not trim) or v~='' then
table.insert(data.items, item)
-- 实际上相当于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
end
第111行: 第199行:
-- Render the main div tag.
-- Render the main div tag.
local root = mw.html.create('div')
-- 这里简化代码,不这样渲染
 
-- Render the list tag.
local list = mw.html.create(data.listTag or 'ul')
for i, class in ipairs(data.classes or {}) do
for i, class in ipairs(data.classes or {}) do
root:addClass(class)
list:addClass(class)
end
root:css{['margin-left'] = data.marginLeft}
if data.style then
root:cssText(data.style)
end
end
-- Render the list tag.
local list = root:tag(data.listTag or 'ul')
list
list
:attr{start = data.start, type = data.type}
:attr{start = data.start, type = data.type}
:css{
:css{
['counter-reset'] = data.counterReset,
['counter-reset'] = data.counterReset,
['list-style-type'] = data.listStyleType
['list-style-type'] = data.listStyleType,
['margin-left'] = data.marginLeft
}
}
if data.listStyle then
if data.listStyle then
list:cssText(data.listStyle)
list:cssText(data.listStyle)
end
end
 
local modify = type(data.modify) == 'function' and data.modify or nil
-- Render the list items
-- Render the list items
for i, t in ipairs(data.items or {}) do
for i, t in ipairs(data.items or {}) do
local item = list:tag('li')
local item = list:tag('li')
local content
if modify then
content = modify(t.content)
else
content = t.content
end
if data.itemStyle then
if data.itemStyle then
item:cssText(data.itemStyle)
item:cssText(data.itemStyle)
第143行: 第236行:
item
item
:attr{value = t.value}
:attr{value = t.value}
:wikitext(t.content)
:wikitext(content)
end
end
 
return tostring(root)
return tostring(list)
end
end


function p.renderTrackingCategories(args)
function p.renderList2(data, listType, separation, conjunction)
local isDeprecated = false -- Tracks deprecated parameters.
local list = {}
for k, v in pairs(args) do
local modify = type(data.modify) == 'function' and data.modify or nil
k = tostring(k)
for i, t in ipairs(data.items or {}) do
if k:find('^item_style%d+$') or k:find('^item_value%d+$') then
local item
isDeprecated = true
local content
break
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
end
end
local ret = ''
if listType=='concat' then
if isDeprecated then
if separation and conjunction then
ret = ret .. '[[Category:含有过期参数的列表模板]]'
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
return ret
end
end


function p.makeList(listType, args)
function p.makeList(listType, args)
-- 如果未指定listType或listType指定不正确,取默认值bulleted
if not listType or not listTypes[listType] then
if not listType or not listTypes[listType] then
error(string.format(
listType = 'bulleted'
"bad argument #1 to 'makeList' ('%s'不是合适的列表类型)",
tostring(listType)
), 2)
end
end
checkType('makeList', 2, args, 'table')
-- checkType('makeList', 2, args, 'table')
local data = p.makeListData(listType, args)
local data = p.makeListData(listType, args)
local list = p.renderList(data)
if listType == 'concat' or listType == 'list_to_text' then
local trackingCategories = p.renderTrackingCategories(args)
return p.renderList2(data,listType,args.separation or args.sep,args.conjunction or args.conj)
return list .. trackingCategories
else
return p.renderList(data)
end
end
end


for listType in pairs(listTypes) do
for listType in pairs(listTypes) do
p[listType] = function (frame)
p[listType] = function (frame)
local mArguments = require('Module:Arguments')
-- local mArguments = require('Module:Arguments')
local origArgs = mArguments.getArgs(frame)
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.
-- Copy all the arguments to a new table, for faster indexing.
local args = {}
local args = {}
for k, v in pairs(origArgs) do
if arguments=='self' or arguments=='both' or arguments=='template' then
args[k] = v
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
end
return p.makeList(listType, args)
return p.makeList(listType, args)

2024年4月16日 (二) 23:56的最新版本

可在模块:List/doc创建此模块的帮助文档

-- 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