Module:Recipe table

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, , 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 .. ' ' ) end return table.concat( links, i18n.separator .. ' ' ) 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, upcoming ) local cell = {} if name then cell[1] = name else cell[1] = m.makeItemLinks( m.makeItemSets( outputArgs, parsedRecipeArgs ), true ) end if upcoming then if upcoming:find( '%[%[' ) then cell[2] = '(' .. upcoming .. ')' else cell[2] = '(' .. upcoming .. ')' end end return table.concat( cell, ' ' ) 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, args.upcoming ) 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