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 ) if name:find( '^' .. prefixes.unwaxed .. ' ' ) then prefix = prefix .. prefixes.unwaxed .. ' ' name = name:sub( #prefixes.unwaxed + 1 ) end 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 ' .. class recipeAttribs = 'class="unsortable"|' end local header = table.concat( { ' {| class="wikitable collapsible ' .. 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