Module:Recipe table
Documentation for this module may be created at Module:Recipe table/doc
local m = {}
local i18n = {
headingDescription = 'Description',
headingIngredients = 'Ingredients',
headingName = 'Name',
headingRecipe = '[[$1]] recipe',
moduleSlot = [[Module:Inventory slot]],
moduleUi = [[Module:UI]],
separator = ' +',
setSeparator = ' or',
tableDescription = '$1 recipes',
}
local slot = require( i18n.moduleSlot )
local prefixes = slot.i18n.prefixes
--[[Merges a list, or inserts a string
or table into a table
--]]
local function mergeList( parentTable, content )
local i = #parentTable + 1
if content[1] then
-- Merge list into table
for _, v in ipairs( content ) do
parentTable[i] = v
i = i + 1
end
else
-- Add strings or tables to table
parentTable[i] = content
end
end
--[[Loops through the input and output args and parses them into a single table,
with alias reference data
Identical slots reuse the same table, to allow them to be compared like strings
--]]
local function parseRecipeArgs( args, ingredientArgVals, outputArgs )
local recipeArgs = {}
for _, arg in pairs( ingredientArgVals ) do
recipeArgs[arg] = args[arg]
end
for _, arg in pairs( outputArgs ) do
recipeArgs[arg] = args[arg]
end
local parsedFrameText = {}
local parsedRecipeArgs = {}
for arg, frameText in pairs( recipeArgs ) do
if frameText then
local randomise
for _, oArg in pairs( outputArgs ) do
if arg == oArg then
randomise = 'never'
break
end
end
local frames = not randomise and parsedFrameText[frameText]
if not frames then
frames = slot.parseFrameText( frameText, randomise, true )
parsedFrameText[frameText] = frames
end
parsedRecipeArgs[arg] = frames
end
end
return parsedRecipeArgs
end
--[[Creates a link (with mod name if specified) with
any prefix moved outside
--]]
function m.prefixedLink( name, mod )
local prefix = ''
for _, thisPrefix in pairs( prefixes ) do
if name:find( '^' .. thisPrefix .. ' ' ) then
prefix = thisPrefix .. ' '
name = name:sub( #prefix + 1 )
break
end
end
local page = name
if mod then
page = slot.i18n.modLink:gsub( '%$1', mod ):gsub( '%$2', name )
end
return table.concat{ prefix, '[[', page, '|', name, ']]' }
end
--[[Creates sets of unique items from a set of slots, using the
original alias name if available
Each set of items are the frames of that slot
--]]
function m.makeItemSets( argVals, parsedArgs )
local usedItems = {}
local function addItem( items, arg, frame, alias )
if alias then
frame = alias.frame
end
local uniqName = ( frame.mod or '' ) .. ':' .. frame.name
if not usedItems[uniqName] then
usedItems[uniqName] = true
items[#items + 1] = frame
end
return alias and alias.length or 1
end
local itemSets = {}
local i = 1
for _, arg in ipairs( argVals ) do
local frames = parsedArgs[arg]
if frames then
local items = {}
local frameNum = 1
while frameNum <= #frames do
local frame = frames[frameNum]
if frame[1] then
local subframeNum = 1
while subframeNum <= #frame do
local subframe = frame[subframeNum]
if subframe.name ~= '' then
local alias = frame.aliasReference and frame.aliasReference[subframeNum]
subframeNum = subframeNum + addItem( items, arg, subframe, alias )
else
subframeNum = subframeNum + 1
end
end
frameNum = frameNum + 1
elseif frame.name ~= '' then
local alias = frames.aliasReference and frames.aliasReference[frameNum]
frameNum = frameNum + addItem( items, arg, frame, alias )
else
frameNum = frameNum + 1
end
end
if #items > 0 then
itemSets[i] = items
i = i + 1
end
end
end
return itemSets
end
--[[Creates links for the name/ingredients columns out of
item sets, with the appropriate separators, and optionally
"Any" and "Matching" prefixes removed.
--]]
function m.makeItemLinks( itemSets, removePrefixes )
local links = {}
for i, itemSet in ipairs( itemSets ) do
local linkSet = {}
for i2, item in ipairs( itemSet ) do
local name = item.name
if removePrefixes then
-- Remove prefixes and uppercase first letter
name = name
:gsub( '^' .. prefixes.any .. ' ', '' )
:gsub( '^' .. prefixes.matching .. ' ', '' )
:gsub( '^%l', string.upper )
end
local disjunctionA, disjunctionB = name:match("(.-) or (.+)") -- hardcoding "A or B" names in English
if disjunctionA then
linkSet[i2] = m.prefixedLink( disjunctionA, item.mod )
.. ' or '
.. m.prefixedLink( disjunctionB, item.mod )
else
linkSet[i2] = m.prefixedLink( name, item.mod )
end
end
links[i] = table.concat( linkSet, i18n.setSeparator .. '<br>' )
end
return table.concat( links, i18n.separator .. '<br>' )
end
-- Creates the table header
function m.makeHeader( recipeType, class, showName, showDescription, multirow )
class = class or ''
local nameCell = ''
if showName then
nameCell = i18n.headingName .. '!!'
end
local descriptionCell = ''
if showDescription then
descriptionCell = '!!class="unsortable"|' .. i18n.headingDescription
end
local recipeAttribs = ''
if multirow then
class = 'sortable collapsible ' .. class
recipeAttribs = 'class="unsortable"|'
end
local header = table.concat( {
' {| class="wikitable ' .. class .. '" data-description="' .. i18n.tableDescription:gsub( '%$1', recipeType ) .. '"',
'!' .. nameCell ..
i18n.headingIngredients .. '!!' ..
recipeAttribs .. i18n.headingRecipe:gsub( '%$1', recipeType ) ..
descriptionCell
}, '\n' )
return header
end
-- Create the contents for the name cell
function m.makeNameCell( name, outputArgs, parsedRecipeArgs )
local cell = {}
if name then
cell[1] = name
else
cell[1] = m.makeItemLinks( m.makeItemSets( outputArgs, parsedRecipeArgs ), true )
end
return table.concat( cell, '<br>' )
end
-- Create the contents for the ingredients cell
function m.makeIngredientsCell( ingredients, itemSets )
return ingredients or m.makeItemLinks( itemSets )
end
--[[Main entry point, creates the table with the relevant DPL vars
to allow multiple table rows from separate template calls
Also returns the unique ingredients, for categorisation purposes in
Module:Crafting
--]]
function m.table( args, settings )
local f = mw.getCurrentFrame()
local multirow = f:callParserFunction( '#dplvar', 'recipetable-multirow' )
if multirow == '' then
multirow = nil
end
local showHead = args.head
local showFoot = args.foot
if multirow then
showHead = nil
elseif showHead and not showFoot then
multirow = true
f:callParserFunction( '#dplvar:set', 'recipetable-multirow', '1' )
else
showHead = true
showFoot = true
end
local showName = args.showname
local showDescription = args.showdescription
if multirow then
if showHead then
showName = args.showname or '1'
f:callParserFunction( '#dplvar:set', 'recipetable-name', showName, 'recipetable-description', showDescription )
else
showName = f:callParserFunction( '#dplvar', 'recipetable-name' )
showDescription = f:callParserFunction( '#dplvar', 'recipetable-description' )
end
end
if showName ~= '1' then
showName = nil
end
if showDescription == '' then
showDescription = nil
end
local out = {}
if showHead then
out[1] = m.makeHeader( settings.type, args.class, showName, showDescription, multirow )
end
local ingredientArgVals = settings.ingredientArgs
local outputArgs = settings.outputArgs
local parsedRecipeArgs = args
if not args.parsed then
parsedRecipeArgs = parseRecipeArgs( args, ingredientArgVals, outputArgs )
end
local cells = {}
if showName then
cells[1] = '!' .. m.makeNameCell( args.name, outputArgs, parsedRecipeArgs )
end
local ingredientsItemSets = m.makeItemSets( ingredientArgVals, parsedRecipeArgs )
cells[#cells + 1] = '|' .. m.makeIngredientsCell( args.ingredients, ingredientsItemSets )
cells[#cells + 1] = '|style="padding:1px;text-align:center"|' .. require( i18n.moduleUi )[settings.uiFunc]( args )
if showDescription then
cells[#cells + 1] = '|' .. ( args.description or '' )
end
out[#out + 1] = table.concat( cells, '\n' )
out[#out + 1] = showFoot and '|}' or ''
if showFoot then
f:callParserFunction( '#dplvar:set',
'recipetable-multirow', '',
'recipetable-name', '',
'recipetable-description', ''
)
end
return table.concat( out, '\n|-\n' ), ingredientsItemSets
end
return m