Module:Card List

Revision as of 20:38, 29 August 2025 by Raven.Familiar (talk | contribs) (Created page with "local p = {} local lib = require('Module:Feature') local Card = require('Module:Card') function p.main(frame) local args = require('Module:Arguments').getArgs(frame, { parentFirst = true, removeBlanks = false, wrapper = { 'Template:Card List' } }) return p._main(args) end function p.splitNote(entry, notePattern) if notePattern then item, note = entry:match(notePattern) if item == nil then -- will be nil if note is not present return entry end retur...")
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
This Lua module is used primarily on pages in the Main namespace. It can be found on pages, or on about Expression error: Unexpected / operator.% of those pages.
Edits to this Lua module will be widely noticed. To avoid large-scale disruption and unnecessary server load, any changes to this Lua module should be tested in its sandbox or testcases subpages. The tested changes can then be added to this page in one single edit by an administrator or a content moderator.
Please consider discussing any changes in the wiki's Discord.

This module implements {{Card List}}.


local p = {}
local lib = require('Module:Feature')
local Card = require('Module:Card')

function p.main(frame)
	local args = require('Module:Arguments').getArgs(frame, {
		parentFirst = true,
		removeBlanks = false,
		wrapper = { 'Template:Card List' }
	})
	return p._main(args)
end

function p.splitNote(entry, notePattern)
	if notePattern then
		item, note = entry:match(notePattern)
		if item == nil then -- will be nil if note is not present
			return entry
		end
		return item, note
	end
	return entry
end

function p.splitParams(entry, paramDelim)
	if entry:find('{.-}') then
		local params = string.match(entry, '{(.-)}')
		entry = entry:gsub('{.-}', '')
		params = lib.split(params, paramDelim)
		local returns = {}
		for i, param in ipairs(params) do
			local name, val = string.match(param, '^%s*(.-)%s*=%s*(.-)%s*$')
			if name ~= nil and name ~= '' and val ~= nil then --named params
				returns[name] = val
			elseif param ~= nil and param ~= '' then --unnamed params
				table.insert(returns, param)
			end
		end
		return entry, returns
	end
	return entry, {}
end

function p.sortPairs(dataPairs)
	local overrideData = mw.loadData('Module:Card List/SortOverrides')
	
	table.sort(dataPairs, function(pair0, pair1)
		local item0, item1 = pair0[2] or pair0, pair1[2] or pair1
		
		local override0, override1 = overrideData[item0.id], overrideData[item1.id]
		local rarity0 = math.min(tonumber(item0.rarity) or tonumber(pair0[1] and pair0[1].rarity) or 3, 5)
		local rarity1 = math.min(tonumber(item1.rarity) or tonumber(pair1[1] and pair1[1].rarity) or 3, 5)
		
		-- in-game, item lists are sorted based on three criteria:
		-- 1) ItemDisplaySort position overrides, ascending
		-- 2) rarity, descending
		-- 3) item id, ascending
		-- these variables condense this criteria into a single number for comparison
		local key0 = override0 or (((6 - rarity0) * 10000000) + (tonumber(item0.id) or 9999999))
		local key1 = override1 or (((6 - rarity1) * 10000000) + (tonumber(item1.id) or 9999999))
		
		return key0 < key1
	end)
end

-- all the non-boolean params except note_delim
local PARAMS_NOT_SUPPORTING_BLANKS = {"caption", "text", "amount", "delim", "amount_delim", "type", "caption_width"}

function p._main(args)
	local input = args[1] or ''
	local itemDelim = args.delim ~= '' and args.delim or ','
	local countDelim = args.amount_delim or '*'
	local noteDelim = args.note_delim or '/'
	local paramDelim = args.param_delim or '$'
	
	--= handle blanks for non-boolean params
	for _, paramName in ipairs(PARAMS_NOT_SUPPORTING_BLANKS) do
		local value = args[paramName]
		if value == "" then
			args[paramName] = nil
		end
	end
	
	-- put all text after the first noteDelim into the second capture
	local notePattern
	if lib.isNotEmpty(noteDelim) then
		notePattern = "^(.-)" .. noteDelim .. "(.*)$"
	end
	
	local containerClass = "card-list-container "
	if args.mobile_list then
		containerClass = containerClass .. "card-mobile-list "
	end
	if lib.isNotEmpty(args.class) then
		containerClass = containerClass .. args.class
	end
	
	local result = mw.html.create():tag("span"):addClass(containerClass)
	local categories = mw.html.create()
	local splitSett = {
		noTrim      = lib.ternary(args.notrim, false, true),
		removeEmpty = true
	}
	
	local cardPairs = {}
	
	for entry in lib.gsplit(input, itemDelim, splitSett) do
		local entry, cardArgs = p.splitParams(entry, paramDelim) --check for entry-specific params
		
		local item, note = p.splitNote(entry, notePattern) --check for entry-specific note
		
		local item_parts = lib.split(item, countDelim) --check for entry-specific amount
		local name = item_parts[1]
		local amount = item_parts[2]
		if args.ts and tonumber(amount) ~= nil then amount = lib.thousandsSeparator(amount) end
		
		--set card arguments without replacing those set by entry-specific params
		cardArgs.name			= cardArgs[1]				or cardArgs.name			 or name
		cardArgs.text			= cardArgs[2]				or cardArgs.text			 or amount or args.text or args.amount
		cardArgs.caption		= cardArgs.caption			or args.caption
		cardArgs.show_caption	= cardArgs.show_caption		or args.show_caption
		cardArgs.caption_width	= cardArgs.caption_width	or args.caption_width
		cardArgs.note			= cardArgs.note				or note
		cardArgs.stars			= cardArgs.stars			or args.stars
		cardArgs.type			= cardArgs.type				or args.type
		cardArgs.set			= cardArgs.set				or args.set
		cardArgs.mini			= cardArgs.mini				or args.mini
		cardArgs.element		= cardArgs.element			or args.element
		cardArgs.link	    	= cardArgs.link				or args.link
		cardArgs.nolink	    	= cardArgs.nolink			or args.nolink
		cardArgs['path']		= cardArgs['path']			or args['path']
		cardArgs.mobile_list	= cardArgs.mobile_list		or args.mobile_list
		cardArgs.icon_type		= cardArgs.icon_type		or args.icon_type
		cardArgs.icon_size		= cardArgs.icon_size		or args.icon_size
		cardArgs.icon_suffix	= cardArgs.icon_suffix		or args.icon_suffix
		cardArgs.multiline_text	= cardArgs.multiline_text	or args.multiline_text
		cardArgs.suffix			= cardArgs.suffix			or args.suffix
		cardArgs.notext			= cardArgs.notext			or args.notext
		cardArgs.minitext		= cardArgs.minitext			or args.minitext
		cardArgs.rarity			= cardArgs.rarity			or args.rarity
		-- mw.logObject(cardArgs)
		
		if (args.autosort) then
			local processedArgs, itemData = Card._processArgs(cardArgs)
			table.insert(cardPairs, {processedArgs, itemData})
		else
			result:node(Card._main(cardArgs))
		end

		if (args.category ~= nil) then
			if type(args.category) ~= 'table' then args.category = {args.category} end
			for _, catForm in ipairs(args.category) do
				categories:wikitext('[[Category:', catForm:gsub('{item}', cardArgs.name), ']]')
			end
		end
	end
	
	if (args.autosort) then
		p.sortPairs(cardPairs)
		for _, pair in ipairs(cardPairs) do
			result:node(Card._createCard(pair[1]))
		end
	end
	
	if (itemDelim == ',' and input:find(',')) then
		result:wikitext('[[Category:Pages Using Comma as Delimiter]]')	
	end
	
	if (args.category ~= nil) then
		result:node(require('Module:Namespace detect')._main({ main = categories }))
	end
	
	return result
end

function p.list(args)
	args = args or {}
	
	--= handle blanks for non-boolean params
	for _, paramName in ipairs(PARAMS_NOT_SUPPORTING_BLANKS) do
		local value = args[paramName]
		if value == "" then
			args[paramName] = nil
		end
	end

	local containerClass = "card-list-container"
	if args.mobile_list then
		containerClass = containerClass .. " card-mobile-list"
	end
	
	local result = mw.html.create():tag("span"):addClass(containerClass)
	local categories = mw.html.create()
	
	local cardPairs = {}
	
	for i, cardArgs in ipairs(args) do
		if not lib.isEmpty(cardArgs) then
			if type(cardArgs) == 'string' then
				cardArgs = {
					name			= cardArgs,
					text			= args.text				or args.amount,
					caption			= args.caption,
					show_caption	= args.show_caption,
					caption_width	= args.caption_width,
					note			= args.note,
					stars			= args.stars,
					type			= args.type,
					set				= args.set,
					mini			= args.mini,
					mobile_list		= args.mobile_list
				}
			elseif type(cardArgs) == 'table' then
				--set card arguments without replacing those set by entry-specific params
				cardArgs.name			= cardArgs[1]				or cardArgs.name			 or name
				cardArgs.text			= cardArgs[2]				or cardArgs.text			 or amount or args.text or args.amount
				cardArgs.caption		= cardArgs.caption			or args.caption
				cardArgs.show_caption	= cardArgs.show_caption		or args.show_caption
				cardArgs.caption_width	= cardArgs.caption_width	or args.caption_width
				cardArgs.note			= cardArgs.note				or note
				cardArgs.stars			= cardArgs.stars			or args.stars
				cardArgs.type			= cardArgs.type				or args.type
				cardArgs.set			= cardArgs.set				or args.set
				cardArgs.mini			= cardArgs.mini				or args.mini
				cardArgs.element		= cardArgs.element			or args.element
				cardArgs.link	    	= cardArgs.link				or args.link
				cardArgs.nolink	    	= cardArgs.nolink			or args.nolink
				cardArgs['path']		= cardArgs['path']			or args['path']
				cardArgs.mobile_list	= cardArgs.mobile_list		or args.mobile_list
				cardArgs.icon_type		= cardArgs.icon_type		or args.icon_type
				cardArgs.icon_size		= cardArgs.icon_size		or args.icon_size
				cardArgs.icon_suffix	= cardArgs.icon_suffix		or args.icon_suffix
				cardArgs.multiline_text	= cardArgs.multiline_text	or args.multiline_text
				cardArgs.suffix			= cardArgs.suffix			or args.suffix
				cardArgs.notext			= cardArgs.notext			or args.notext
				cardArgs.minitext		= cardArgs.minitext			or args.minitext
				
				if (args.category ~= nil) then
					if type(args.category) ~= 'table' then args.category = {args.category} end
					for _, catForm in ipairs(args.category) do
						categories:wikitext('[[Category:', catForm:gsub('{item}', cardArgs.name), ']]')
					end
				end
			end
			
			if (args.autosort) then
				local processedArgs, itemData = Card._processArgs(cardArgs)
				table.insert(cardPairs, {processedArgs, itemData})
			else
				result:node(Card._main(cardArgs))
			end
		end
	end
	
	if (args.autosort) then
		p.sortPairs(cardPairs)
		for _, pair in ipairs(cardPairs) do
			result:node(Card._createCard(pair[1]))
		end
	end
	
	if (args.category ~= nil) then
		result:node(require('Module:Namespace detect')._main({ main = categories }))
	end
	
	return result
end
	
return p