Module:RecipeView: Difference between revisions

From Against the Storm Official Wiki
(Created to replace Recipe module in combination with the more RecipeController; more powerful and capable of showing more data more flexibly.)
 
(Temporarily making methods public for debugging. also had to make table indexed on strings instead of numbers apparently)
Line 15: Line 15:


local stars = {
local stars = {
[0] = mw.getCurrentFrame():expandTemplate{ title = "0Star" },
["0"] = mw.getCurrentFrame():expandTemplate{ title = "0Star" },
[1] = mw.getCurrentFrame():expandTemplate{ title = "1Star" },
["1"] = mw.getCurrentFrame():expandTemplate{ title = "1Star" },
[2] = mw.getCurrentFrame():expandTemplate{ title = "2Star" },
["2"] = mw.getCurrentFrame():expandTemplate{ title = "2Star" },
[3] = mw.getCurrentFrame():expandTemplate{ title = "3Star" }
["3"] = mw.getCurrentFrame():expandTemplate{ title = "3Star" }
}
}


Line 150: Line 150:
---
---
---@return table invisible MediaWiki HTML table entity
---@return table invisible MediaWiki HTML table entity
local function startNewInvisibleTable()
function RecipeView.startNewInvisibleTable()


return mw.html.create("table"):newline()
return mw.html.create("table"):newline()
Line 164: Line 164:
---@param buildingName string the name of the building
---@param buildingName string the name of the building
---@param buildingIcon string the filename for the icon
---@param buildingIcon string the filename for the icon
local function makeBuildingColumn(htmlTableRow, buildingName, buildingIcon)
function RecipeView.makeBuildingColumn(htmlTableRow, buildingName, buildingIcon)


htmlTableRow:tag("td"):wikitext(buildingLink(buildingName, buildingIcon, imgL)):done():newline()
htmlTableRow:tag("td"):wikitext(buildingLink(buildingName, buildingIcon, imgL)):done():newline()
Line 178: Line 178:
---@param gradeStars number the stars of efficiency
---@param gradeStars number the stars of efficiency
---@param productionTime string the formatted for display time
---@param productionTime string the formatted for display time
local function makeEfficiencyColumn(htmlTableRow, gradeStars, productionTime)
function RecipeView.makeEfficiencyColumn(htmlTableRow, gradeStars, productionTime)


htmlTableRow:tag("td"):wikitext(stars[gradeStars] .. BR .. productionTime):done():newline()
htmlTableRow:tag("td"):wikitext(stars[gradeStars] .. BR .. productionTime):done():newline()
Line 198: Line 198:
---@param htmlTable table MediaWiki HTML table entity
---@param htmlTable table MediaWiki HTML table entity
---@param optionTable table of one good's option data: stack size, name, icon
---@param optionTable table of one good's option data: stack size, name, icon
local function makeOptionRow(htmlTable, optionTable)
function RecipeView.RecipeView.makeOptionRow(htmlTable, optionTable)


local row = htmlTable:tag("tr")
local row = htmlTable:tag("tr")
Line 216: Line 216:
---@param resultIcon string the filename of the result's icon
---@param resultIcon string the filename of the result's icon
---@param resultName string the display name of the result
---@param resultName string the display name of the result
local function makeResultColumn(htmlTableRow, resultStackSize, resultIcon, resultName)
function RecipeView.makeResultColumn(htmlTableRow, resultStackSize, resultIcon, resultName)


local stackSizePart = BOLD .. resultStackSize .. BOLD
local stackSizePart = BOLD .. resultStackSize .. BOLD
Line 314: Line 314:
-- Table version.
-- Table version.
newNode = mw.html.create("tr"):newline()
newNode = mw.html.create("tr"):newline()
makeBuildingColumn(newNode, buildingName, buildingIcon)
RecipeView.makeBuildingColumn(newNode, buildingName, buildingIcon)
makeEfficiencyColumn(newNode, gradeStars, productionTime)
RecipeView.makeEfficiencyColumn(newNode, gradeStars, productionTime)


for _, iList in ipairs(ingredientsList) do
for _, iList in ipairs(ingredientsList) do


local optionsGrid = startNewInvisibleTable()
local optionsGrid = RecipeView.startNewInvisibleTable()
for _, option in ipairs(iList) do
for _, option in ipairs(iList) do
makeOptionRow(optionsGrid, option)
RecipeView.makeOptionRow(optionsGrid, option)
end
end


Line 328: Line 328:
end
end


makeResultColumn(newNode, productStackSize, productIcon, productName)
RecipeView.makeResultColumn(newNode, productStackSize, productIcon, productName)
end
end



Revision as of 02:44, 26 November 2023

Documentation for this module may be created at Module:RecipeView/doc

--- @module RecipeView
local RecipeView = {}



--region Private member variables

beginning = ""
middle = ""
ending = ""

local imgS = mw.getCurrentFrame():expandTemplate{ title = "ImgS" }
local imgM = mw.getCurrentFrame():expandTemplate{ title = "ImgM" }
local imgL = mw.getCurrentFrame():expandTemplate{ title = "ImgL" }

local stars = {
	["0"] = mw.getCurrentFrame():expandTemplate{ title = "0Star" },
	["1"] = mw.getCurrentFrame():expandTemplate{ title = "1Star" },
	["2"] = mw.getCurrentFrame():expandTemplate{ title = "2Star" },
	["3"] = mw.getCurrentFrame():expandTemplate{ title = "3Star" }
}

--endregion



--region Private constants

local INDEX_OPTION_STACK_SIZE = "stackSize"
local INDEX_OPTION_GOOD_NAME = "name"
local INDEX_OPTION_GOOD_ICON = "icon"

local PARAMETER_DISPLAY_OVERRIDE_LIST = "list"

local MAX_INGREDIENTS = 3
local DEFAULT_RESULT_HEADER = "Result"

-- wikitable classes for tables
local CLASS_WIKITABLE_SORTABLE_COLLAPSIBLE = "wikitable sortable mw-collapsible"

-- Shortcut markup that's easier for Lua string concatenations
local BR = "<br />"
local NBSP = "&nbsp;"
local BOLD = "'''"

--endregion



--region Private methods

---
--- Formats a standard link to a building. Does not invoke the template, but it
--- could be modified to do so in the future.
---
---@param buildingName string the display name of the building
---@param buildingIcon string the filename for the icon
---@param iconSize string representing the desired size of the icon
---@return string an assembled link, with icon (if large enough) and text link to page
local function buildingLink(buildingName, buildingIcon, iconSize)

	if not buildingIcon or not iconSize or not buildingName then
		error("Building parameters cannot be nil.")
	end

	-- Skip the smallest icons for the building links.
	local iconPart = ""
	if iconSize > imgS then
		iconPart = "[[File:" .. buildingIcon .. "|" .. iconSize ..
				"|alt=" .. buildingName .."|link=" .. buildingName .. "]]" ..
				NBSP
	end

	local linkPart = "[[" .. buildingName .. "]]"

	return iconPart .. linkPart
end



---
--- Formats a standard link to a resource. Does not invoke the template, but it
--- could be modified to do so in the future.
---
---@param resourceName string the display name of the good
---@param resourceIcon string the filename for the icon
---@param iconSize string representing the desired size of the icon
---@return string an assembled link, with icon and text link to page
local function resourceLink(resourceName, resourceIcon, iconSize)

	if not resourceName or not resourceIcon or not iconSize then
		error("Resource parameters cannot be nil.")
	end

	local iconPart = "[[File:" .. resourceIcon .. "|" .. iconSize .. "|alt=" .. resourceName .."|link=" .. resourceName .. "]]"
	local linkPart = "[[" .. resourceName .. "]]"

	return iconPart .. NBSP .. linkPart
end



---
--- Creates a header row under the provided MediaWiki HTML table entity.
---
---@param tableNode table MediaWiki HTML table entity
---@param numIngredients number of ingredient columns
---@param finalColumnName string the title for the final/result column.
local function makeStandardRecipeTableHeaderRow(tableNode, numIngredients, finalColumnName)

	-- Use generic defaults if they are not provided.
	if not numIngredients then
		numIngredients = MAX_INGREDIENTS
	end
	if not finalColumnName then
		finalColumnName = DEFAULT_RESULT_HEADER
	end

	local row = tableNode:tag("tr")

	row:tag("th"):wikitext("Building"):done()
	row:tag("th"):wikitext("Efficiency"):done()

	for i = 1, math.min(numIngredients, MAX_INGREDIENTS) do
		row:tag("th"):wikitext("Ingredient #" .. i .. "options"):done()
	end

	row:tag("th"):wikitext(finalColumnName):done()

	row:done():newline()
end



---
--- Returns a standard MediaWiki HTML table entity created with standard
--- display and interactivity classes.
---
---@return table standard MediaWiki HTML table entity
local function startNewWikiTable()

	return mw.html.create("table"):addClass(CLASS_WIKITABLE_SORTABLE_COLLAPSIBLE):newline()
end



---
--- Returns a standard MediaWiki HTML table entity created with no classes or
--- interactivity, making it invisible, for layout purposes only.
---
---@return table invisible MediaWiki HTML table entity
function RecipeView.startNewInvisibleTable()

	return mw.html.create("table"):newline()
end



---
--- Makes the content of the building column under the provided HTML table row
--- entity.
---
---@param htmlTableRow table MediaWiki HTML table row entity
---@param buildingName string the name of the building
---@param buildingIcon string the filename for the icon
function RecipeView.makeBuildingColumn(htmlTableRow, buildingName, buildingIcon)

	htmlTableRow:tag("td"):wikitext(buildingLink(buildingName, buildingIcon, imgL)):done():newline()
end



---
--- Makes the content of the recipe efficiency column under the provided HTML
--- table row entity.
---
---@param htmlTableRow table MediaWiki HTML table row entity
---@param gradeStars number the stars of efficiency
---@param productionTime string the formatted for display time
function RecipeView.makeEfficiencyColumn(htmlTableRow, gradeStars, productionTime)

	htmlTableRow:tag("td"):wikitext(stars[gradeStars] .. BR .. productionTime):done():newline()
end



---
--- Makes the row and fills it with content. Puts the row into the provided
--- HTML table entity.
---
--- Needs option information structured in a table, like this:
--- optionTable = {
--- 	[INDEX_OPTION_STACK_SIZE] = 9,
--- 	[INDEX_OPTION_GOOD_NAME] = "Display Name",
--- 	[INDEX_OPTION_GOOD_ICON] = "Icon_filename.png"
--- }
---
---@param htmlTable table MediaWiki HTML table entity
---@param optionTable table of one good's option data: stack size, name, icon
function RecipeView.RecipeView.makeOptionRow(htmlTable, optionTable)

	local row = htmlTable:tag("tr")
	row:tag("td"):wikitext(BOLD .. optionTable[INDEX_OPTION_STACK_SIZE] .. BOLD):done()
	row:tag("td"):wikitext(resourceLink(optionTable[INDEX_OPTION_GOOD_NAME], optionTable[INDEX_OPTION_GOOD_ICON], imgM)):done()
	row:done():newline()
end



---
--- Makes the content of the result column under the provided HTML table row
--- entity. Agnostic of whether the result is a product or a service.
---
---@param htmlTableRow table MediaWiki HTML table row entity
---@param resultStackSize number of results provided by the recipe
---@param resultIcon string the filename of the result's icon
---@param resultName string the display name of the result
function RecipeView.makeResultColumn(htmlTableRow, resultStackSize, resultIcon, resultName)

	local stackSizePart = BOLD .. resultStackSize .. BOLD
	local iconAndLinkPart = resourceLink(resultName, resultIcon, imgL)

	htmlTableRow:tag("td"):wikitext(stackSizePart .. NBSP .. iconAndLinkPart):done():newline()
end

--endregion



--region Public methods

---
--- Initializes the table, populates the caption, and writes and header row,
--- all appropriate for a table focusing on ingredients.
---
--- The default is a wikitable output. With the displayOverride flag, this
--- method will instead make a list.
---
---@param ingredientName string the name of the ingredient this table is based on
---@param displayOverride string a flag for the output type if not the default
---@param numRecipes number of recipes that will be in this table, if it's known
---@param numIngredients number of columns that will be written to this table, if known
---@param finalColumnName string the header label of the last column
function RecipeView.startViewForIngredient(ingredientName, displayOverride, numRecipes, numIngredients, finalColumnName)

	-- These should never be nil at runtime.
	if not ingredientName then
		error("Parameter is invalid for ingredient name.")
	end
	-- Use generic defaults if they are not provided.
	if not numRecipes then
		numRecipes = "All"
	end

	local newNode
	if displayOverride == PARAMETER_DISPLAY_OVERRIDE_LIST then
		newNode = mw.html.create("ul")
	else
		newNode = startNewWikiTable()
		newNode:tag("caption"):wikitext(numRecipes .. " recipes that require " .. ingredientName):done():newline()

		makeStandardRecipeTableHeaderRow(newNode, numIngredients, finalColumnName)
	end

	beginning = newNode
	-- Return value is not used by the Controller, but for debugging.
	return newNode
end



---
--- Adds a new row to the content being built. This is typically called from a
--- Controller that knows how many rows to add. RecipeView maintains the output
--- in-progress while rows are added, so that layout and formatting can be
--- owned by this module instead of the Controller.
---
--- Expects a table-of-tables for ingredients information, like this:
--- ingredientsList = {
--- 	[1] = {
--- 		[1] = {
--- 			[INDEX_OPTION_STACK_SIZE] = 9,
--- 			[INDEX_OPTION_GOOD_NAME] = "Display Name",
--- 			[INDEX_OPTION_GOOD_ICON] = "Icon_filename.png"
--- 		},
--- 		[2] = { ... },
--- 		[3] = { ... },
--- 		... -- or fewer or up to six options
--- 	},
--- 	[2] = {
--- 		[1] = { ... },
--- 		[2] = { ... },
--- 		... -- or fewer or up to six options
--- 	},
--- 	[3] = { ... } -- or fewer ingredient option groups
--- }
---
---@param displayOverride string a flag for the output type if not the default
---@param buildingName string the name of the building of this recipe
---@param buildingIcon string the icon of the building
---@param gradeStars number of stars of efficiency of this recipe
---@param productionTime string formatted time to produce
---@param ingredientsList table of ingredient subtables of options
---@param productStackSize number how many of the products are produced by this recipe
---@param productName string the display name of the product
---@param productIcon string the icon of the product
function RecipeView.addRowForRecipe(displayOverride, buildingName, buildingIcon, gradeStars, productionTime, ingredientsList, productStackSize, productIcon, productName)

	local newNode
	if displayOverride == PARAMETER_DISPLAY_OVERRIDE_LIST then
		--List version.
		newNode = mw.html.create("li"):wikitext(buildingLink(buildingName, buildingIcon, imgS))
	else
		-- Table version.
		newNode = mw.html.create("tr"):newline()
		RecipeView.makeBuildingColumn(newNode, buildingName, buildingIcon)
		RecipeView.makeEfficiencyColumn(newNode, gradeStars, productionTime)

		for _, iList in ipairs(ingredientsList) do

			local optionsGrid = RecipeView.startNewInvisibleTable()
			for _, option in ipairs(iList) do
				RecipeView.makeOptionRow(optionsGrid, option)
			end

			optionsGrid:done()
			newNode:tag("td"):node(optionsGrid):done():newline()
		end

		RecipeView.makeResultColumn(newNode, productStackSize, productIcon, productName)
	end

	newNode:done()
	middle = middle .. tostring(newNode)

	return newNode
end



---
--- Wraps up anything outstanding for the view based on ingredients, then
--- returns the entire MediaWiki entity originally started in the method
--- startViewForIngredient.
---
---@return string the HTML markup of the completed view
function RecipeView.endViewForIngredient()

	beginning:node(middle)
	beginning:done()

	return beginning
end

--endregion

return RecipeView