Module:Recipes by category table

From Coral Island Wiki
Jump to navigation Jump to search

Documentation for this module may be created at Module:Recipes by category table/doc

local p = {}
local lib = require('Module:Feature')
local Icon = require('Module:Icon')._main
local Icon_list = require('Module:Icon list')._main
local Parse = require('Module:Parser').getTemplateArgs
local LL = require('Module:Link label')._main
local show_time = false

function p.main(frame)
	local args = require('Module:Arguments').getArgs(frame)
	if lib.isEmpty(frame.args.pages) then
		local result = args.noresult or ''
		if result ~= '' then return result
		elseif args[1] then
			local array = lib.split(string.lower(args[1]), ';')
			local link = (args.noresultlink and args.noresultlink) or 'crafting recipe'
			if #array == 0 then result = 'No page matches category selection.'
			elseif #array == 1 then result = 'No ' .. link .. ' needs ' .. array[1] .. '.'
			elseif #array == 2 then result = 'No ' .. link .. ' needs ' .. array[1] .. ' or ' .. array[2] .. '.'
			else
				local last = table.remove(array, #array)
				result = 'No ' .. link .. ' needs any of the following: ' .. table.concat(array, ', ') .. ', or ' .. last .. '.'
			end
		else 
			result = 'No page matches category selection.'
		end
		result = result  .. require('Module:Namespace detect').main{main='[[Category:Pages with empty template results|Recipes by category table]]'}
		return result
	else
		args.pages = frame.args.pages
		local mustHave = {
			ingredient = {},
			medium = {}
		}
		if args[1] then
			for item in lib.gsplit(args[1], ';') do
				mustHave.ingredient[string.lower(item)] = true
			end
		end
		if args.medium then
			for item in lib.gsplit(args.medium, ';') do
				mustHave.medium[string.lower(item)] = true
			end
		end
		local Recipes = p.parsePages(args, mustHave)
		-- mw.logObject(Recipes) --debug
		if args.col1 then
			local i = '1'
			local cols = {}
			while lib.isNotEmpty(args['col'..i]) do
				local col = {}
				col.name = args['col'..i .. '_name'] or ('Info ' .. i)
				col.form = args['col'..i .. '_format'] ~= nil and lib.split((args['col'..i .. '_format']:gsub('²{', '{{'):gsub('}²', '}}'):gsub('¦', '|'):gsub('«(.-)»', '<%1>')), ',', {noTrim=true}) or nil
				col.params = {}
				for group in lib.gsplit(args['col'..i], ',') do
					local template, params = string.match(group, '^{(.+)}:(.+)$')
					for param in lib.gsplit(params, ':') do
						table.insert(col.params, {
							template = template,
							param = param
						})
					end
				end
				table.insert(cols, col)
				i = tostring(tonumber(i)+1)
			end
			args.CUSTOM_COLUMNS = cols
		end
		return p._main(Recipes, args, frame)
	end
end

function p._main(Recipes, args, frame)
	local out  = mw.html.create('table'):addClass('fandom-table article-table sortable ' .. (args.class or ''))
	
	--header
	local tr = out:tag('tr')
	tr:tag('th'):wikitext('Product')
	tr:tag('th'):wikitext('Ingredients')
	if not args.nomedium and (not args.medium or args.medium:find(';')) then tr:tag('th'):wikitext('Crafting<br />medium') end
	if show_time and not args.notime then tr:tag('th'):wikitext('Time') end
	if args.CUSTOM_COLUMNS and type(args.CUSTOM_COLUMNS) == 'table' and  #args.CUSTOM_COLUMNS > 0 then
		for col_num, col_data in ipairs(args.CUSTOM_COLUMNS) do
			tr:tag('th'):wikitext(col_data.name)
		end
	end
	
	--recipes
	for _, recipe  in ipairs(Recipes) do
		local tr = out:tag('tr')
		recipe[1] = recipe.items or recipe[1]
		recipe.amount = '1'
		tr:tag('td')
			:node(Icon{
				(recipe.product or recipe.PAGENAME),
				(recipe['yield'] or '1'),
				size = 60,
			})
		tr:tag('td'):node(Icon_list(recipe))
		if not args.nomedium and (not args.medium or args.medium:find(';')) then
			if recipe.medium and recipe.medium ~= 'Menu' then
				tr:tag('td')
					:node(Icon{
						recipe.medium,
						size = 60
					})
			else
				tr:tag('td'):wikitext('[[Crafting|In-menu<br />crafting]]')
			end
		end
		if show_time and not args.notime then tr:tag('td'):wikitext(recipe['time'] or '') end
		if args.CUSTOM_COLUMNS and type(args.CUSTOM_COLUMNS) == 'table' and  #args.CUSTOM_COLUMNS > 0 then
			local Pdata = recipe.PAGEDATA
			for col_num, col_data in ipairs(args.CUSTOM_COLUMNS) do
				local td = tr:tag('td')
				local ret = mw.html.create()
				if col_data.form ~= nil then
					for part, str in ipairs(col_data.form) do
						ret:wikitext(str)
						local pair = col_data.params[part]
						if pair then
							if pair.param == '%PAGE%' then
								ret:wikitext(recipe.PAGENAME)
							elseif Pdata[pair.template] and Pdata[pair.template][pair.param] then
								ret:wikitext(Pdata[pair.template][pair.param])
							end
						end
					end
				else
					for _, pair in ipairs(col_data.params) do
						if pair.param == '%PAGE%' then
							ret:wikitext(recipe.PAGENAME)
						elseif Pdata[pair.template] and Pdata[pair.template][pair.param] then
							ret:wikitext(Pdata[pair.template][pair.param])
						end
					end
				end
				td:wikitext(frame:preprocess(tostring(ret)))
			end
		end
	end
	
	return out
end

function p.parsePages(args, mustHave)
	local Recipes = {}
	local defaults = {
		delim = ';',
		delim_amount = '*',
		delim_quality = '/'
	}
	local function inString(data)
		for str in lib.gsplit(data.items, data.delim) do
			for item in lib.gsplit(str, '//') do
				local pre, quality = string.match(item, data.quality)
				if not pre then
					pre = item
				end
				local name, amount = string.match(pre, data.amount)
				if not name then
					name = pre
					amount = '1'
				end
				-- mw.logObject(string.lower(name), 'name')
				-- mw.logObject(mustHave, 'mustHave')
				
				if (next(mustHave.ingredient) ~= nil and next(mustHave.medium) ~= nil and mustHave.ingredient[string.lower(name)] and mustHave.medium[string.lower(data.medium or 'menu')]) then
					return true
				elseif (next(mustHave.ingredient) ~= nil and next(mustHave.medium) == nil and mustHave.ingredient[string.lower(name)]) then
					return true
				elseif (next(mustHave.ingredient) == nil and next(mustHave.medium) ~= nil and mustHave.medium[string.lower(data.medium or 'crafting menu')]) then
					return true
				end
			end
		end
		return false
	end
	for page in lib.gsplit(args.pages, ';;;') do
		local page_data = Parse(page)
		if page_data.Recipe then
			if next(mustHave.ingredient) ~= nil or next(mustHave.medium) ~= nil then
				if type(page_data.Recipe[1]) == 'table' then
					for _, call in ipairs(page_data.Recipe) do
						local data = {
							items = call.items or call[1],
							medium = call.medium or 'crafting menu',
							delim = call.delim or defaults.delim,
							quality = '^(.-)' .. (call.delim_quality or defaults.delim_quality) .. '(.*)$',
							amount = '^(.-)' .. (call.delim_amount or defaults.delim_amount) .. '(.*)$'
						}
						if inString(data) then
							if not show_time and lib.isNotEmpty(call['time']) then show_time = true end
							call.PAGENAME = page
							call.PAGEDATA = page_data
							table.insert(Recipes, call)
						end
					end
				else
					local data = {
						items = page_data.Recipe.items or page_data.Recipe[1],
						delim = page_data.Recipe.delim or defaults.delim,
						medium = page_data.Recipe.medium or 'crafting menu',
						amount = '^(.-)' .. (page_data.Recipe.delim_amount or defaults.delim_amount) .. '(.*)$',
						quality = '^(.-)' .. (page_data.Recipe.delim_quality or defaults.delim_quality) .. '(.*)$'
					}
					if inString(data) then
						if not show_time and lib.isNotEmpty(page_data.Recipe['time']) then show_time = true end
						page_data.Recipe.PAGENAME = page
						page_data.Recipe.PAGEDATA = page_data
						table.insert(Recipes, page_data.Recipe)
					end
				end
			else
				if page_data.Recipe[1] and type(page_data.Recipe[1]) == 'table' then
					for _, call in ipairs(page_data.Recipe) do
						if not show_time and lib.isNotEmpty(call['time']) then show_time = true end
						call.PAGENAME = page
						call.PAGEDATA = page_data
						table.insert(Recipes, call)
					end
				else
					if not show_time and lib.isNotEmpty(page_data.Recipe['time']) then show_time = true end
					page_data.Recipe.PAGENAME = page
					page_data.Recipe.PAGEDATA = page_data
					table.insert(Recipes, page_data.Recipe)
				end
			end
		end
	end
	return Recipes
end

return p