此模块的文档可以在模块:FilterDiv/doc创建

local p = {}
local mt = {__index=p, __tostring=function(this) return this:done() end}

local UID = require('Module:Random').UID
local Set = require('Module:Set')
local Util = require('Module:Util')

--[[数据结构说明:
	source = [
		{content, keys=[key, ...]},
		...
	],
	filters = [
		Set[key, ...],
		...
	],
	titles = [ [title,uid], ...],
]]

function p.new(...) -- 参数为各filter的title
	local argument = {...}
	if argument[2]==nil and type(argument[1])=='table' then --参数为单个数组
		argument = argument[1]
	end
	local titles = {}
	if argument[1] then --数组
		for i,v in ipairs(argument) do
			local uid = 'v'..i
			if type(v)=='table' then
				for _,title in ipairs(v) do
					table.insert(titles, {title, uid})
				end
			else
				table.insert(titles, {v, uid})
			end
		end			
	else --映射 用于跨行单选
		for k,v in pairs(argument) do
			table.insert(titles, {k, tostring(v)})
		end
	end
	return setmetatable({
		source = {},
		filters = Util.map(Util.range(#titles), function() return Set:new() end),
		titles = titles,
	}, mt)
end

function p:add(content, ...) --FilterDiv:add(content, key1, key2, ...)
	local keys = Util.map({...}, tostring)
	if #keys==0 then
		table.insert(self.source, {
        	content = tostring(content),
		})
		return
	end
	if #keys~=#self.titles then
		error('参数数量('..#keys..')与预设数量('..#self.titles..')不同')
    end
    local lazyload
    if type(content)=='table' and type(content.lazyload)=='string' then
        lazyload = content.lazyload
        content = content[1] or '加载中...'
    end
	table.insert(self.source, {
        content = tostring(content),
        lazyload = lazyload,
		keys = keys
	})
	for i,key in ipairs(keys) do
		self.filters[i]:add(key)
	end
end

function p:done(args)
	args = args or {}
	local itemId = UID()
	
	do
		if args.select==false or args.select==0 then
			args.select = function() return 0 end --全不选
		elseif type(args.select)=='table' then
			local t = args.select
			args.select = function(i) return t[i] or 1 end
		elseif type(args.select)~='function' then
			args.select = function() return 1 end --全选第一个
		end
	end

	local FilterBlock = mw.html.create('div')
		:addClass('filter-div')
		:attr('data-target', itemId)
	for i,filter in ipairs(self.filters) do
		local uid = self.titles[i][2]
		local group = mw.html.create('div'):addClass('filter-group')
		if args.class then group:addClass(args.class) end
		if args.style then group:cssText(args.style) end
		if args.center then group:css('justify-content', 'center') end
		if self.titles[i][1]~='' then --若为空字符串,则隐藏标签
			group:tag('div'):addClass('group-title'):wikitext(self.titles[i][1])
		end
		local ul = group:tag('ul'):addClass('filter-div--bgroup')
		local any = false
		for j,value in ipairs(filter.array) do
			if value~='' then
				any = true
				local btn = ul:tag('li')
					:addClass('filter-div--button')
					:attr('data-type', uid)
					:attr('data-'..uid, value)
					:wikitext(value)
				if j==args.select(i) then
					btn:addClass('selected')
				end
			end
		end
		if any then FilterBlock:node(group) end
	end

	local ItemBlock = mw.html.create('div')
		:attr('id', itemId)
		:addClass('filter-div--target')
	if args.height then
		if tonumber(args.height) then
			args.height = args.height..'px'
		end
		ItemBlock:css('height', args.height):css('overflow', 'auto')
	end
	if args.attr then
		if type(args.attr)=='table' then
			ItemBlock:attr(args.attr)
		elseif type(args.attr)=='function' then
			args.attr(ItemBlock)
		end
	end
	for _, data in ipairs(self.source) do
		local item = ItemBlock
			:tag('div')
            :wikitext(data.content)
		if data.lazyload then
			item:attr('data-lazyload', data.lazyload)
		end
        if data.keys then
        	item:addClass('filter-div--item')
			for i,key in ipairs(data.keys) do
				if key~='' then
					local uid = self.titles[i][2]
					item:attr('data-'..uid, key)
				end
			end
		end
	end

	return tostring(FilterBlock)..'\n'..tostring(ItemBlock)
end

function p.template(frame)
	local args = frame.args
	if not args.title1 then args = frame:getParent().args end
	local titles = {}
	for i=1,20 do
		titles[i] = args['title'..i]
		if not titles[i] then break end
	end
	local o = p:new(unpack(titles))
	for i=1,999 do
		local item = args['item'..i]
		local lazyload = args['lazyload'..i]
		if lazyload then 
			item = {
				[1] = item,
				lazyload = lazyload
			}
		end
		local keys = args['key'..i]
		if not item or not keys then break end
		keys = mw.text.split(keys, ';;', true)
		keys = Util.map(keys, function(s) return s~='' and s or nil end)
		o:add(item, unpack(keys))
	end
	if args.select then
		args.select = Util.map(mw.text.split(args.select, ';;'), function(s) return tonumber(s) end)
		if #args.select==1 then
			args.select = args.select[1]
		end
	end
	return o:done(args)
end

function p.test()
	local args = {
		title1='',
		title2='',
		item1='aaaa',
		key1='1;;2',
		item2='bbbb',
		key2='2;;2',
		center='1',
		noselect='1'
	}
	mw.log(p.template{args=args})
end

return p
avatar