Community Central

The Admin Code of Conduct is now live! This new policy outlines clear expectations for wiki admins. Check out the announcement blog!

READ MORE

Community Central
Community Central

This module is called Module:ItemRecipes on the Rend wiki, but is commented here extensively. It's an example of printing a table based on a Cargo query. The table it queries can be found here.

local lang = mw.getLanguage('en') -- this is a constant available to every function, and will be used to lowercase a variable below.
local p = {}
function p.main(frame) -- this is the function that's called from the page itself
	local args = require('Module:ProcessArgs').merge(true)

	-- everything above here lets us call this module either from a page via #invoke, or from another module, and have the arguments fed to the template be available in a table called args
	-- you should copy Module:ProcessArgs to your wiki to use it, if it's not already there
	
	
	local item = args[1] or mw.title.getCurrentTitle().text
	local result = p.doQuery(item) -- first thing is to do the cargo query, which is done in its own function; see comments on that function for more info
	if not result then -- if there was no result then return
		return '<span style="color:#ccc">\'\'No crafting recipes found.\'\'</span>'
	end
	
	-- now we format all of the data that we got from our result to prepare it for output
	local formatted = p.formatResult(result)
	
	-- now we return a table that prints all the formatted data
	return p.makeTable(formatted)
end

-----------------------------------
-- cargo
-----------------------------------
-- the code to do the query is broken up into a bunch of functions
-- just so that it's easier to see what each piece does
-- this is the outer function, which actually does the query
-- and returns the result to the main function, or returns nil if there is no result
-- the query itself will return {} (an empty table) if there is no result to the query
function p.doQuery(item)
	-- [[the query takes 3 arguments:
	1) a list of tables (it expects a comma-separated list as a string)
	2) a list of fields to return (again, a comma separated list)
	3) a table with a bunch of optional values. in this case we give a "where" condition and an "orderBy."
	   Mostly these parameters are the same as the ones available in a normal mediawiki Cargo query,
	   but there are some differences in what they're called so that they are just 1 single word in Lua
	   and can be written more clearly as the keys in a table]]
	local result = mw.ext.cargo.query('Recipes',
		p.cargoFields(),
		-- the fields that we want in this example is actually kind of long and annoying to construct,
		-- so it's done in its own function.
		-- all you need to know is that a string is returned that contains a list of fields
		{
			where = p.cargoWhere(item), -- again, constructing the 'where' is kind of annoying so it's done in its own function. all you need to know is that it returns a string.
			orderBy = 'tool'
		}
	)
	if #result == 0 then
		-- this just checks if the table is non-empty
		-- the following code: 
		--   if result == {}
		-- will NOT work because Lua == when used on two tables only returns true if you are comparing
		-- one table to literally itself, and NOT another table that has the same structure & values as it
		-- however consider the following code:
		-- a = {}
		-- b = a
		-- in this case, a does equal b
		return nil
	else
		return result
	end
end

-- don't worry too much about the specifics of this function,
-- just know it returns a string with a list of fields we want to query
-- if we wanted to alias a field name,
-- we could do for example "result=result_alias" instead of just "result"
-- and then that would be returned to us as row.result_alias instead of row.result
-- when we do our for k, row in ipairs.... loop later on
function p.cargoFields()
	-- we'll first make a table with all of the fields in it
	local fields = {
		'result','resultAmount','tool'
	}
	-- there are a bunch of items & amounts and i don't want to type them all out so do a loop for the rest
	for i = 1,12 do
		fields[#fields+1] = 'item' .. i
		fields[#fields+1] = 'amount' .. i
	end
	return table.concat(fields,',') -- then concat the table into a comma-separated string and return it to the main function
end

-- also don't worry too much about the specifics of this function, just know it returns a where condition as a string
function p.cargoWhere(item)
	local where = {}
	for i = 1,12 do
		where[#where+1] = string.format('item%s="%s"', i, item)
	end
	return table.concat(where,' OR ')
end

--------------------------------------------------
-- process data for output
--------------------------------------------------
-- in the end we want to print a table with three columns.
-- the function that does the actual printing should only need to print data to the page,
-- and not need to do any kind of processing on it anymore,
-- so we are doing the processing / formatting here, 
-- saving it into a table called "formatted",
-- and then returning it to the main function where it will then be printed.
function p.formatResult(result)
	local formatted = {}
	-- this loop structure is pretty much always how you will process cargo data.
	-- you will loop over the ipairs iterator of the results table and apply a bunch of processing to the row, and save it.
	-- once it's been processed you will then print it.
	for k, row in ipairs(result) do
		formatted[k] = {
			-- each of these pieces of formatting is done in its own function for ease of reading.
			-- it's not too important to read them individually, just know how string.format works
			p.formatLinkAndImage(row.result, row.resultAmount),
			p.makeIngredientsTable(row),
			p.formatTool(row.tool)
		}
	end
	return formatted
end

function p.formatLinkAndImage(result, amount)
	return string.format("[[File:%s.png|40px|link=%s]] [[%s]] (%s)",
		result or '',
		result or '',
		result or '',
		amount or ''
	)
end

function p.makeIngredientsTable(row)
	local tbl = mw.html.create('table'):css({
		margin='-1px',
		width = 'calc(100% + 2px)',
		['border-collapse'] = 'collapse'
	})
	for i = 1, 12 do
		if row['item' .. i] ~= '' then
			tbl:tag('tr'):tag('td'):wikitext(p.formatLinkAndImage(row['item' .. i], row['amount' .. i]))
		end
	end
	return tostring(tbl)
end

function p.formatTool(tool)
	if lang:lc(tool) == 'by hand' then
		return '[[By Hand]]'
	else
		return string.format('[[File:%s.png|40px|link=%s]] %s',
			tool or '',
			tool or '',
			tool or ''
		)
	end
end

----------------------------------------------------
-- make table for output
----------------------------------------------------
-- since we did all our processing above, literally all that's left to do is to make the table for output.
-- this is done using the mw.html library.
function p.makeTable(formatted)
	-- this table of styles corresponds to each of the columns
	local styles = {
		'', -- first column has no style
		{ padding = '0!important', }, -- second column has no padding
		'' -- third column has no style
	}
	local tbl = mw.html.create('table'):addClass('wikitable') -- create a wikitable html class
	tbl:tag('tr') -- and make its header row
		:tag('th'):wikitext('Result'):done()
		:tag('th'):wikitext('Ingredients'):done()
		:tag('th'):wikitext('Crafting Station'):done()
	for _, row in ipairs(formatted) do -- now iterate over the formatted data
		tr = tbl:tag('tr') -- create a row
		for k, v in ipairs(row) do
			-- create each of the columns within the row,
			-- with the style we defined above and the wikitext as the row value we made in the earlier function
			tr:tag('td'):css(styles[k]):wikitext(v)
		end
	end
	return tbl -- done!
end

return p