Module:RenderRecipe: Difference between revisions
From Against the Storm Official Wiki
added back building cell to output table |
changed renderTable inner funcion to just make a row of a table; now the result is one table in all cases--some will have multiple rows |
||
| Line 48: | Line 48: | ||
local argProductName = frame.args.product | local argProductName = frame.args.product | ||
local argBuildingName = frame.args.building | local argBuildingName = frame.args.building | ||
-- build the table header | |||
local wikiTable = mw.html.create('table'):addClass(CSS_CLASS_WIKITABLE_SORTABLE) | |||
wikiTable:tag('tr') | |||
:tag('th'):wikitext("Building"):done() | |||
:tag('th'):wikitext("Ingredient #1"):done() | |||
:tag('th'):wikitext("Ingredient #2"):done() | |||
:tag('th'):wikitext("Ingredient #3"):done() | |||
:tag('th'):wikitext("Product") | |||
-- both product and building are specified | -- both product and building are specified | ||
| Line 58: | Line 67: | ||
end | end | ||
-- only one to render | -- only one to render; renderTableRow returns the wikiTable passed to it | ||
-- | -- renderTableRow will use just the first place in the recipe, which is perfect for this version with only one place | ||
wikiTable = RenderRecipe.renderTableRow(recipe, wikiTable) | |||
-- only product is specified | -- only product is specified | ||
| Line 70: | Line 79: | ||
return "Render_Recipe Error: no recipe found with product=" .. argProductName .. "." | return "Render_Recipe Error: no recipe found with product=" .. argProductName .. "." | ||
end | end | ||
-- go through each place and send a simplified (one place) version of tRecipe to the table renderer | -- go through each place and send a simplified (one place) version of tRecipe to the table renderer | ||
| Line 78: | Line 85: | ||
local tempRecipe = { product=argProductName, pattern=tRecipe.pattern, places={place} } | local tempRecipe = { product=argProductName, pattern=tRecipe.pattern, places={place} } | ||
-- each call to renderTableRow adds a new row to the passed table | |||
wikiTable = RenderRecipe.renderTableRow(tempRecipe, wikiTable) | |||
end | end | ||
-- only building is specified | -- only building is specified | ||
| Line 105: | Line 106: | ||
end | end | ||
-- | -- each call to renderTableRow adds a new row to the passed table | ||
wikiTable = RenderRecipe.renderTableRow(recipe, wikiTable) | |||
end | end | ||
-- something was bad about the arguments; can't print them since they may be nil | -- something was bad about the arguments; can't print them since they may be nil | ||
| Line 116: | Line 115: | ||
end | end | ||
return mw.allToString(wikiTable) | |||
end | end | ||
| Line 123: | Line 122: | ||
-- writes the wiki table markup to represent a recipe | -- writes the wiki table markup to represent a recipe | ||
-- takes a recipe table (pattern and place), and uses only the first place | -- takes a recipe table (pattern and place), and uses only the first place | ||
function RenderRecipe. | function RenderRecipe.renderTableRow(tRecipe, wikiTable) | ||
if not tRecipe then | if not tRecipe then | ||
| Line 165: | Line 164: | ||
end | end | ||
-- write the first cell with the building | -- write the first cell with the building | ||
local wikiTableDataRow = wikiTable:tag('tr') | local wikiTableDataRow = wikiTable:tag('tr') | ||
:tag('td'):wikitext(RenderRecipe.blTemplate(building) .. BR .. RenderRecipe.starTemplate(stars) .. BR .. speed) | :tag('td'):wikitext(RenderRecipe.blTemplate(building) .. BR .. RenderRecipe.starTemplate(stars) .. BR .. speed) | ||
-- first fill in empty cells like in the recipe book, one for the blank ingredient with a border, then a space for a missing plus sign | -- first fill in empty cells like in the recipe book, one for the blank ingredient with a border, then a space for a missing plus sign | ||
| Line 185: | Line 173: | ||
wikiTableDataRow:tag('td'):addClass(CSS_CLASS_EMPTY_INGREDIENT) | wikiTableDataRow:tag('td'):addClass(CSS_CLASS_EMPTY_INGREDIENT) | ||
end | end | ||
| Line 193: | Line 180: | ||
for i, group in ipairs(ingredients) do | for i, group in ipairs(ingredients) do | ||
local groupOfQuantities = quantities[i] | local groupOfQuantities = quantities[i] | ||
local wikiTableDataRowDataCell = wikiTableDataRow:tag('td') | local wikiTableDataRowDataCell = wikiTableDataRow:tag('td') | ||
| Line 205: | Line 187: | ||
if 1 == #group then | if 1 == #group then | ||
wikiTableDataRowDataCell:addClass(CSS_CLASS_REQUIRED_INGREDIENT) | wikiTableDataRowDataCell:addClass(CSS_CLASS_REQUIRED_INGREDIENT) | ||
else | else | ||
wikiTableDataRowDataCell:addClass(CSS_CLASS_SWAPPABLE_INGREDIENT) | wikiTableDataRowDataCell:addClass(CSS_CLASS_SWAPPABLE_INGREDIENT) | ||
end | end | ||
| Line 220: | Line 198: | ||
if j > 1 then | if j > 1 then | ||
wikiTableDataRowDataCell:wikitext(BR) | wikiTableDataRowDataCell:wikitext(BR) | ||
end | end | ||
wikiTableDataRowDataCell:wikitext(quant .. " " .. RenderRecipe.rlTemplate(alt)) | wikiTableDataRowDataCell:wikitext(quant .. " " .. RenderRecipe.rlTemplate(alt)) | ||
end | end | ||
end | end | ||
-- close up the table with the product | -- close up the table row with the product | ||
wikiTableDataRow:tag('td'):wikitext(number .. " " .. RenderRecipe.rlTemplate(product,"large")) | wikiTableDataRow:tag('td'):wikitext(number .. " " .. RenderRecipe.rlTemplate(product,"large")) | ||
-- | -- pass the table back in case more rows need to be added | ||
return wikiTable | |||
return | |||
end | end | ||
Revision as of 14:45, 10 February 2023
Documentation for this module may be created at Module:RenderRecipe/doc
-------------------------------------------------------------------------------
-- Renders the {{recipe}} template
--
-- Takes at least one argument. The first, requried, is the name of the
-- resource for which the recipes are needed. Optionally, the second argument
-- is the name of the building.
-- This module renders small wikimarkup tables to represent one or more
-- recipes: one table if the building was specified. several tables
-- corresponding to all the buildings in which the resource can be produced.
-------------------------------------------------------------------------------
local RenderRecipe = {}
local RecipeData = require("Module:RecipeData") -- lookup table for recipes
-------------------------------------------------------------------------------
-- Constants
-------------------------------------------------------------------------------
local CSS_CLASS_WIKITABLE_SORTABLE = "wikitable sortable"
local CSS_CLASS_RECIPE_TABLE = "ATSrecipe"
local CSS_CLASS_RECIPE_CAPTION = "ATSrecipecaption"
local CSS_CLASS_REQUIRED_INGREDIENT = "ATSrequired"
local CSS_CLASS_SWAPPABLE_INGREDIENT = "ATSswappable"
local CSS_CLASS_EMPTY_INGREDIENT = "ATSempty"
local TEMPLATE_BUILDING_LINK = "Building_link"
local TEMPLATE_RESOURCE_LINK = "Resource_link"
local TEMPLATE_STAR_SUFFIX = "Star"
local BR = "<br />"
local NL = "\n\n"
-------------------------------------------------------------------------------
-- Main rendering function
-- uses ResourceData lookup function, parses the result and handles errors
-- with default values, then assembles a final string to return to the wiki
-------------------------------------------------------------------------------
-- need this in whole-class scope, sorry
local thisFrame = {}
function RenderRecipe.renderRecipe(frame)
-- need to set the class variable so expandTemplate can work later
thisFrame = frame
local argProductName = frame.args.product
local argBuildingName = frame.args.building
-- build the table header
local wikiTable = mw.html.create('table'):addClass(CSS_CLASS_WIKITABLE_SORTABLE)
wikiTable:tag('tr')
:tag('th'):wikitext("Building"):done()
:tag('th'):wikitext("Ingredient #1"):done()
:tag('th'):wikitext("Ingredient #2"):done()
:tag('th'):wikitext("Ingredient #3"):done()
:tag('th'):wikitext("Product")
-- both product and building are specified
if argProductName and argProductName ~= "" and argBuildingName and argBuildingName ~= "" then
-- returns exactly one recipe with one place
local recipe = RecipeData.getRecipeAtBuilding(argProductName, argBuildingName)
if not recipe then
return "Render_Recipe Error: no recipe found with product=" .. argProductName .. " and building=" .. argBuildingName .. "."
end
-- only one to render; renderTableRow returns the wikiTable passed to it
-- renderTableRow will use just the first place in the recipe, which is perfect for this version with only one place
wikiTable = RenderRecipe.renderTableRow(recipe, wikiTable)
-- only product is specified
elseif argProductName and argProductName ~= "" then
-- gets a whole product's recipe stack, which may be any number of places (1-6)
local tRecipe = RecipeData.getRecipeForProduct(argProductName)
if not tRecipe then
return "Render_Recipe Error: no recipe found with product=" .. argProductName .. "."
end
-- go through each place and send a simplified (one place) version of tRecipe to the table renderer
for i, place in ipairs(tRecipe.places) do
local tempRecipe = { product=argProductName, pattern=tRecipe.pattern, places={place} }
-- each call to renderTableRow adds a new row to the passed table
wikiTable = RenderRecipe.renderTableRow(tempRecipe, wikiTable)
end
-- only building is specified
elseif argBuildingName and argBuildingName ~= "" then
-- gets a table of recipes for different products, each one has exactly one place
local tableOfRecipes = RecipeData.getBuildingsRecipes(argBuildingName)
if not tableOfRecipes then
return "Render_Recipe Error: no recipes found at building=" .. argBuildingName .. "."
end
local strToReturn = ""
-- go through each recipe and just send it straight to the table renderer, since the place already matches
for j, recipe in ipairs(tableOfRecipes) do
if j > 1 then
strToReturn = strToReturn .. NL -- separate tables with new lines
end
-- each call to renderTableRow adds a new row to the passed table
wikiTable = RenderRecipe.renderTableRow(recipe, wikiTable)
end
-- something was bad about the arguments; can't print them since they may be nil
else
return "Render_Recipe Error: invalid template parameters. at least a product or building is required"
end
return mw.allToString(wikiTable)
end
-- writes the wiki table markup to represent a recipe
-- takes a recipe table (pattern and place), and uses only the first place
function RenderRecipe.renderTableRow(tRecipe, wikiTable)
if not tRecipe then
return nil
end
-- call the helper functions to extract the data, make sure we have something usable,
-- then get only the first values since we're assuming that there's only one top-level record in tRecipe
local building, stars = RecipeData.getBuildingsAndStarsLists(tRecipe)
if building and stars then
building, stars = building[1], stars[1]
else
return "Render_Recipe Error: did not find building or stars in recipe."
end
local speed = RecipeData.getProductionSpeed(tRecipe)
if speed then
speed = speed[1]
else
return "Render_Recipe Error: did not find production speed in recipe."
end
local product, number = RecipeData.getProductAndNumbers(tRecipe)
if product and number then
number = number[1]
else
return "Render_Recipe Error: did not find product or output numbers in recipe."
end
-- need separate error checking, because ingredients is the same structure as EACH
-- of the top-level elements of quantities
local ingredients, quantities = RecipeData.getIngredientsAndQuantities(tRecipe)
if not ingredients or 0 == #ingredients then
return "Render_Recipe Error: did not find ingredients in recipe."
end
-- just want the first values since we're assuming there's only one top-level record in tRecipe
if quantities then
quantities = quantities[1] -- now ingredients and quantities have the same structure
else
return "Render_Recipe Error: did not find quantities in recipe."
end
-- write the first cell with the building
local wikiTableDataRow = wikiTable:tag('tr')
:tag('td'):wikitext(RenderRecipe.blTemplate(building) .. BR .. RenderRecipe.starTemplate(stars) .. BR .. speed)
-- first fill in empty cells like in the recipe book, one for the blank ingredient with a border, then a space for a missing plus sign
local blanks = 3 - #ingredients
for h = 1,blanks do
wikiTableDataRow:tag('td'):addClass(CSS_CLASS_EMPTY_INGREDIENT)
end
-- looping over groups of alternative ingredients and quantities simultaneously,
-- so use local group and groupOfQuantities for each i
for i, group in ipairs(ingredients) do
local groupOfQuantities = quantities[i]
local wikiTableDataRowDataCell = wikiTableDataRow:tag('td')
-- add a class to the table cell based on whether there's only one (required) or more (swappable) ingredients
-- in the group
if 1 == #group then
wikiTableDataRowDataCell:addClass(CSS_CLASS_REQUIRED_INGREDIENT)
else
wikiTableDataRowDataCell:addClass(CSS_CLASS_SWAPPABLE_INGREDIENT)
end
-- for every group, list out the required or alternatives within that group
for j, alt in ipairs(group) do
local quant = groupOfQuantities[j]
-- need to add breaks only between the first and any subsequent options
if j > 1 then
wikiTableDataRowDataCell:wikitext(BR)
end
wikiTableDataRowDataCell:wikitext(quant .. " " .. RenderRecipe.rlTemplate(alt))
end
end
-- close up the table row with the product
wikiTableDataRow:tag('td'):wikitext(number .. " " .. RenderRecipe.rlTemplate(product,"large"))
-- pass the table back in case more rows need to be added
return wikiTable
end
-- redirect a rendering request to the recipe data and create appropriate
-- templates for the list. The caller can decide how to output the list
function RenderRecipe.getBuildingsAndStarsForProduct(frame)
local argProductName = frame.args.product
-- make sure there's an argument to work with
if not tableRecipe then
return "Render_Recipe Error: no product given."
end
-- get the associated recipe data, including all buildings
local tableRecipe = RecipeData.getAllRecipes(argProductName)
-- make sure what's returned is valid before we loop through it
if not tableRecipe or not tableRecipe.places or #tableRecipe.places < 1 then
return "Render_Recipe Error: no recipes found"
end
local listOfTemplates = {}
local buildings, stars = RecipeData.getBuildingsAndStarsLists(tRecipe)
-- loop through the buildings and stars and build the templates
for i, building in pairs(buildings) do
listOfTemplates[i] = RenderRecipe.blTemplate(building) .. " " .. RenderRecipe.pstarTemplate(stars[i])
end
return listOfTemplates
end
-------------------------------------------------------------------------------
-- Helper rendering functions
-- these do not call member functions, but write out the actual templates
-- (which will in turn invoke the code. this is to protect variations in the
-- modules, but we may decide later it should be different)
-------------------------------------------------------------------------------
--use large size for recipes unless speified
function RenderRecipe.blTemplate(strBuilding,strSize)
if not strSize then
strSize = "large"
end
--return "{{" .. TEMPLATE_BUILDING_LINK .. "|" .. strBuilding .. "|" .. strSize .. "}}"
return thisFrame:expandTemplate{ title=TEMPLATE_BUILDING_LINK, args={ strBuilding, strSize } }
end
-- use recipe-sized icons, "med", unless specified
function RenderRecipe.rlTemplate(strResource,strSize)
if not strSize then
strSize = "med"
end
--return "{{" .. TEMPLATE_RESOURCE_LINK .. "|" .. strResource .. "|" .. strSize .. "}}"
return thisFrame:expandTemplate{ title=TEMPLATE_RESOURCE_LINK, args={ strResource, strSize } }
end
-- use the parentheses version, with "P"
function RenderRecipe.pstarTemplate(intStars)
--return "{{P" .. intStars .. "star}}"
return thisFrame:expandTemplate{ title= "P" .. intStars .. TEMPLATE_STAR_SUFFIX}
end
-- no parens version
function RenderRecipe.starTemplate(intStars)
--return "{{" .. intStars .. "star}}"
return thisFrame:expandTemplate{ title= intStars .. TEMPLATE_STAR_SUFFIX}
end
-------------------------------------------------------------------------------
-- Return when required into another Module.
-------------------------------------------------------------------------------
return RenderRecipe


