Module:Infobox: Difference between revisions

From Against the Storm Official Wiki
m (Fixing title)
(Updated doc; added generic range title; *maybe* fixed the extraneous separator issue)
 
(13 intermediate revisions by the same user not shown)
Line 1: Line 1:
---
---
--- Module to create an infobox for displaying on a workshop's wiki page.
--- Module of shortcuts and layout methods to standardize infoboxes on various
---
--- wiki pages. Supported modules should not use any mw.create or :tag methods,
--- Shows the facts from the data about the specified workshop in an easy-to-
--- but instead call the methods of this module with the facts and rely on
--- read table, with a large icon, information, categories, and the flavor
--- this module to build the content.
--- text.
---
--- This should be invoked from Template:Shopbox with the parameter of the
--- workshop whose infobox should be shown. See the template documentation for
--- more information about parameters and errors and to see examples.
---
---
--- @module Infobox
--- @module Infobox
Line 16: Line 11:


local GoodsData = require("Module:GoodsData")
local GoodsData = require("Module:GoodsData")
local StyleUtils = require("Module:StyleUtils")




Line 23: Line 19:
local RESOURCE_LINK_TEMPLATE = "rl"
local RESOURCE_LINK_TEMPLATE = "rl"
local RESOURCE_LINK_ICONSIZE = "med"
local RESOURCE_LINK_ICONSIZE = "med"
local CONSTRUCTION_TEMPLATE = "Construction"


local INDEX_REQ_STACK_SIZE= "stackSize"
local INDEX_REQ_STACK_SIZE= "stackSize"
local INDEX_REQ_GOOD_ID = "goodID"
local INDEX_REQ_GOOD_ID = "goodID"
local BOLD = "'''"


local PATTERN_FORMAT_TWO_DECIMALS = "%1.2f"
local PATTERN_FORMAT_TWO_DECIMALS = "%1.2f"
Line 38: Line 34:
--region Public constants
--region Public constants


-- Infobox header labels
Infobox.TITLE_ID = "ID"
Infobox.TITLE_ID = "ID"
Infobox.TITLE_CATEGORY = "Toolbar Category"
Infobox.TITLE_CATEGORY = "Category"
Infobox.TITLE_SIZE = "Building Size"
Infobox.TITLE_SIZE = "Size"
Infobox.TITLE_EATABLE = "Eatable"
Infobox.TITLE_EATABLE = "Eatable"
Infobox.TITLE_BURNABLE = "Burnable"
Infobox.TITLE_BURNABLE = "Burnable"
Infobox.TITLE_BURN_TIME = "Fuel burn time"
Infobox.TITLE_BURN_TIME = "Burn time"
Infobox.TITLE_MOVABLE = "Movable"
Infobox.TITLE_MOVABLE = "Movable"
Infobox.TITLE_ESSENTIAL = "Initially Essential"
Infobox.TITLE_ESSENTIAL = "Essential"
Infobox.TITLE_STORAGE_CAPACITY = "Storage Capacity"
Infobox.TITLE_STORAGE_CAPACITY = "Storage"
Infobox.TITLE_RANGE = "Range"
Infobox.TITLE_FARMING_AREA = "Farming Area"
Infobox.TITLE_FARMING_AREA = "Farming Area"
Infobox.TITLE_GATHERING_AREA = "Gathering Area"
Infobox.TITLE_GATHERING_AREA = "Gather Range"
Infobox.TITLE_CONSTRUCTION_TIME = "Construction Time"
Infobox.TITLE_CONSTRUCTION_TIME = "Build Time"
Infobox.TITLE_CONSTRUCTION_COST = "Construction Cost"
Infobox.TITLE_CONSTRUCTION_COST = "Build Cost"
Infobox.TITLE_SELL_VALUE = "Value when sold"
Infobox.TITLE_SELL_VALUE = "Sell value"
Infobox.TITLE_BUY_VALUE = "Price when bought"
Infobox.TITLE_BUY_VALUE = "Buy price"
Infobox.TITLE_WORKPLACES = "Workplaces"
Infobox.TITLE_WORKPLACES = "Workplaces"
Infobox.TITLE_RECIPES = "Recipes"
Infobox.TITLE_RECIPES = "Recipes"
Line 59: Line 55:
Infobox.ICONSIZE_MED = mw.getCurrentFrame():expandTemplate{ title="ImgM" }
Infobox.ICONSIZE_MED = mw.getCurrentFrame():expandTemplate{ title="ImgM" }


-- Infobox styling
-- *DEPRECATED* Infobox styling.
Infobox.CSS_MAIN = {
Infobox.CSS_MAIN = {
["float"] = "right",
["float"] = "right",
Line 69: Line 65:
["margin"] = "0.5em 0 0.5em 1em"
["margin"] = "0.5em 0 0.5em 1em"
}
}
Infobox.CSS_INNER_TABLE = {
Infobox.CSS_INNER_TABLE = {
["border-collapse"] = "collapse"
["border-collapse"] = "collapse"
}
}
Infobox.CSS_TR_BORDER_BOT = {
Infobox.CSS_TR_BORDER_BOT = {
["border-bottom"] = "1px solid #a2a9b1"
["border-bottom"] = "1px solid #a2a9b1"
}
}
Infobox.CSS_TR_BORDER_TOP = {
Infobox.CSS_TR_BORDER_TOP = {
["border-top"] = "1px solid #a2a9b1"
["border-top"] = "1px solid #a2a9b1"
Line 97: Line 90:
["Trade Goods"] = "Icon_UI_CategoryTrade.png"
["Trade Goods"] = "Icon_UI_CategoryTrade.png"
}
}
--endregion
--region Private methods
---
--- Adds a separator if needed.
---
---@param row table html table row we're building
---@param needsSeparator boolean whether we need a separator
---@return boolean whether we still need a separator
local function trySeparator(row, needsSeparator)
if needsSeparator then
StyleUtils.styleInfoboxSeparator(row)
return false
end
return true
end
---
--- Shortcut method to populate the provided row with a header and a value.
---
---@param htmlRow table the html table row we're populating
---@param header string header text
---@param value string value text
---@return table the same htmlTable
local function populateStandardRow(htmlRow, header, value)
htmlRow:tag("th"):wikitext(header):done()
  :tag("td"):wikitext(value):done()
  :done():newline()
return htmlRow
end


--endregion
--endregion
Line 151: Line 184:


---
---
--- A shortcut method for looking up an icon and assigning its wiki markup.
---
---@param category string the category of the icon to make
---@return string the wiki markup for the icon
function Infobox.makeCategoryIcon(category, isGoodsCategory)
local classStr = ""
if isGoodsCategory then
classStr = StyleUtils.CLASS_GOODS_CATEGORY_ICON
else
classStr = StyleUtils.CLASS_CATEGORY_ICON
end
return "[[File:" .. Infobox.ICON_FILENAMES_CATEGORIES[category] ..
"|" .. Infobox.ICONSIZE_MED .. "|alt=" .. category ..
"|class=" .. classStr .. "]]"
end
---
--- A shortcut method for making a standard title.
---
---@param parentNode table the html node to add to
---@param title string the title to write
---@return table the title node added
function Infobox.makeTitle(parentNode, title)
local p = parentNode:tag("p")
StyleUtils.styleInfoboxTitle(p)
p:wikitext(title):done():newline()
return p
end
---
--- A shortcut method for adding a description as flavor text.
---
---@param parentNode table the html node to add to
---@param description string the description to write out
---@return table the title node added
function Infobox.makeFlavorText(parentNode, description)
local p = parentNode:tag("p")
StyleUtils.styleInfoboxFlavorText(p)
p:wikitext(description):done():newline()
return p
end
---
--- A shortcut method for adding a large icon to the header.
---
---@param parentNode table the html node to add to
---@param iconFilename string the icon to use
---@return table the title node added
function Infobox.makeTitleIcon(parentNode, iconFilename)
local div = parentNode:tag("div")
StyleUtils.styleInfoboxTitleIcon(div)
div:wikitext("[[File:" .. iconFilename .. "]]"):done():newline()
return div
end
---
--- A shortcut method to make a table row based on the provided check, also
--- checks to see whether it needs to add a separator.
---
---@param parentNode table the html node to add to
---@param check boolean whether the row can be added
---@param needsSeparator boolean whether the row needs a separator before it
---@param header string the header of the row
---@param value string the value of the row
---@return boolean whether the next row still needs a separator before it
function Infobox.makeInnerRow(parentNode, check, needsSeparator, header, value)
local row
local nowNeedsSeparator = needsSeparator
if check ~= nil and check ~= "" then
row = parentNode:tag("tr")
nowNeedsSeparator = trySeparator(row, needsSeparator)
populateStandardRow(row, header, value)
end
return nowNeedsSeparator
end
--- *DEPRECATED* TODO DELETE THIS because we're not doing inline css anymore
--- Shortcut method to build a standard row with a header and a value.
--- Shortcut method to build a standard row with a header and a value.
---
---
Line 157: Line 292:
---@param header string header text
---@param header string header text
---@param value string value text
---@param value string value text
---@return table the same htmlTable
function Infobox.buildStandardRow(htmlNode, cssInline, header, value)
function Infobox.buildStandardRow(htmlNode, cssInline, header, value)


Line 181: Line 317:
end
end


local requiredGoodsRows = mw.html.create("table")
local templateArgs = {}
requiredGoodsRows:newline()
 
for _, requiredGroup in ipairs(requiredGoods) do
for _, requiredGroup in ipairs(requiredGoods) do


local stackSize = requiredGroup[INDEX_REQ_STACK_SIZE]
local stackSize = requiredGroup[INDEX_REQ_STACK_SIZE]
local goodID = requiredGroup[INDEX_REQ_GOOD_ID]
local goodName = GoodsData.getGoodNameByID(requiredGroup[INDEX_REQ_GOOD_ID])


requiredGoodsRows:tag("tr")
templateArgs[goodName] = stackSize
:tag("td"):wikitext(BOLD .. stackSize .. BOLD):done()
:tag("td"):wikitext(Infobox.resourceLink(goodID)):done()
:done():newline()
end
end


return requiredGoodsRows
return mw.getCurrentFrame():expandTemplate{ title = CONSTRUCTION_TEMPLATE,
args = templateArgs }
end
 
 
 
---
--- Starts off a new infobox.
---
--- @return table the html node created
function Infobox.startNewInfobox()
 
local wikiInfobox = mw.html.create("div")
StyleUtils.styleInfobox(wikiInfobox)
 
wikiInfobox:newline()
 
return wikiInfobox
end
 
 
 
---
--- Creates a standard way of displaying the top content of the infobox and
--- returns the HTML node. Styles consistently.
---
---@param wikiInfobox table the overall context this is added to
---@return table the html node created
function Infobox.startNewHeader(wikiInfobox)
 
local header = wikiInfobox:tag("div")
StyleUtils.styleInfoboxHeader(header)
 
header:newline()
 
return header
end
 
 
 
---
--- Finalizes the standard top content
---
---@param wikiInfobox table the overall context
---@param header table the header content to add to the outer context
function Infobox.endInnerTable(wikiInfobox, header)
 
header:done():newline()
 
return wikiInfobox
end
 
 
 
---
--- Creates a standard way of displaying rows of headers and values and
--- returns the HTML node. Styles consistently.
---
---@param wikiInfobox table the overall context this is added to
---@return table the html node created
function Infobox.startNewInnerTable(wikiInfobox)
 
local innerTable = wikiInfobox:tag("table")
innerTable = StyleUtils.styleInfoboxInnerTable(innerTable)
 
innerTable:newline()
 
return innerTable
end
 
 
---
--- Finalizes the standard inner display of headers and values.
---
---@param wikiInfobox table the overall context
---@param innerTable table the inner content to add to the outer context
function Infobox.endInnerTable(wikiInfobox, innerTable)
 
innerTable:done():newline()
 
return wikiInfobox
end
end



Latest revision as of 15:43, 24 December 2023

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

---
--- Module of shortcuts and layout methods to standardize infoboxes on various
--- wiki pages. Supported modules should not use any mw.create or :tag methods,
--- but instead call the methods of this module with the facts and rely on
--- this module to build the content.
---
--- @module Infobox
local Infobox = {}



local GoodsData = require("Module:GoodsData")
local StyleUtils = require("Module:StyleUtils")



--region Private constants

local RESOURCE_LINK_TEMPLATE = "rl"
local RESOURCE_LINK_ICONSIZE = "med"

local CONSTRUCTION_TEMPLATE = "Construction"

local INDEX_REQ_STACK_SIZE= "stackSize"
local INDEX_REQ_GOOD_ID = "goodID"

local PATTERN_FORMAT_TWO_DECIMALS = "%1.2f"
local PATTERN_CAPTURE_FIRST_LETTER_IN_WORD = "(%a)([%w]*)"

--endregion



--region Public constants

Infobox.TITLE_ID = "ID"
Infobox.TITLE_CATEGORY = "Category"
Infobox.TITLE_SIZE = "Size"
Infobox.TITLE_EATABLE = "Eatable"
Infobox.TITLE_BURNABLE = "Burnable"
Infobox.TITLE_BURN_TIME = "Burn time"
Infobox.TITLE_MOVABLE = "Movable"
Infobox.TITLE_ESSENTIAL = "Essential"
Infobox.TITLE_STORAGE_CAPACITY = "Storage"
Infobox.TITLE_RANGE = "Range"
Infobox.TITLE_FARMING_AREA = "Farming Area"
Infobox.TITLE_GATHERING_AREA = "Gather Range"
Infobox.TITLE_CONSTRUCTION_TIME = "Build Time"
Infobox.TITLE_CONSTRUCTION_COST = "Build Cost"
Infobox.TITLE_SELL_VALUE = "Sell value"
Infobox.TITLE_BUY_VALUE = "Buy price"
Infobox.TITLE_WORKPLACES = "Workplaces"
Infobox.TITLE_RECIPES = "Recipes"

Infobox.ICONSIZE_MED = mw.getCurrentFrame():expandTemplate{ title="ImgM" }

-- *DEPRECATED* Infobox styling.
Infobox.CSS_MAIN = {
	["float"] = "right",
	["clear"] = "right",
	["width"] = "256px",
	["border"] = "1px solid #a2a9b1",
	["border-spacing"] = "3px",
	["border-collapse"] = "collapse",
	["margin"] = "0.5em 0 0.5em 1em"
}
Infobox.CSS_INNER_TABLE = {
	["border-collapse"] = "collapse"
}
Infobox.CSS_TR_BORDER_BOT = {
	["border-bottom"] = "1px solid #a2a9b1"
}
Infobox.CSS_TR_BORDER_TOP = {
	["border-top"] = "1px solid #a2a9b1"
}

-- Infobox icons
Infobox.ICON_FILENAMES_CATEGORIES = {
	-- Buildings
	["Camps"] = "Construct Camps.png",
	["City Buildings"] = "Construct City Buildings.png",
	["Food Production"] = "Construct Food Production.png",
	["Industry"] = "Construct Industry.png",
	-- Goods
	["Building Materials"]	= "Icon_UI_CategoryBuilding.png",
	["Consumable Items"]	= "Icon_UI_CategoryConsumable.png",
	["Crafting Resources"]	= "Icon_UI_CategoryCrafting.png",
	["Food"]				= "Icon UI CategoryFood.png",
	["Fuel & Exploration"]	= "Icon_UI_CategoryFuel.png",
	["Trade Goods"]			= "Icon_UI_CategoryTrade.png"
}

--endregion



--region Private methods

---
--- Adds a separator if needed.
---
---@param row table html table row we're building
---@param needsSeparator boolean whether we need a separator
---@return boolean whether we still need a separator
local function trySeparator(row, needsSeparator)

	if needsSeparator then
		StyleUtils.styleInfoboxSeparator(row)
		return false
	end

	return true
end



---
--- Shortcut method to populate the provided row with a header and a value.
---
---@param htmlRow table the html table row we're populating
---@param header string header text
---@param value string value text
---@return table the same htmlTable
local function populateStandardRow(htmlRow, header, value)

	htmlRow:tag("th"):wikitext(header):done()
		   :tag("td"):wikitext(value):done()
		   :done():newline()

	return htmlRow
end

--endregion



--region Public methods

---
--- Shortcut string to reformat numbers with two decimals.
---
---@param value number whole or with a fractional part
---@return string reformatted to force two decimal places
function Infobox.toTwoDecimalPlaces(value)

	return string.format(PATTERN_FORMAT_TWO_DECIMALS, value)
end



---
--- Capitalizes the first character of each word to "Make It Title Case." Also
--- converts any underscores to spaces.
---
--- @param title string to capitalize
--- @return string capitalized with title case
function Infobox.toTitleCase(title)

	title = title:gsub("_", " ")

	local newTitle = title:gsub(PATTERN_CAPTURE_FIRST_LETTER_IN_WORD, function(firstLetter, rest)
		return firstLetter:upper() .. rest:lower()
	end)

	return newTitle
end



---
--- A shortcut method for making resource links.
---
---@param goodID string the ID of the good to link to
---@return string wikimarkup representing an icon and link
function Infobox.resourceLink(goodID)

	local goodName = GoodsData.getGoodNameByID(goodID)

	return mw.getCurrentFrame():expandTemplate{ title=RESOURCE_LINK_TEMPLATE, args={
		resource=goodName, iconsize= RESOURCE_LINK_ICONSIZE } }
end



---
--- A shortcut method for looking up an icon and assigning its wiki markup.
---
---@param category string the category of the icon to make
---@return string the wiki markup for the icon
function Infobox.makeCategoryIcon(category, isGoodsCategory)

	local classStr = ""
	if isGoodsCategory then
		classStr = StyleUtils.CLASS_GOODS_CATEGORY_ICON
	else
		classStr = StyleUtils.CLASS_CATEGORY_ICON
	end

	return "[[File:" .. Infobox.ICON_FILENAMES_CATEGORIES[category] ..
			"|" .. Infobox.ICONSIZE_MED .. "|alt=" .. category ..
			"|class=" .. classStr .. "]]"
end



---
--- A shortcut method for making a standard title.
---
---@param parentNode table the html node to add to
---@param title string the title to write
---@return table the title node added
function Infobox.makeTitle(parentNode, title)

	local p = parentNode:tag("p")
	StyleUtils.styleInfoboxTitle(p)

	p:wikitext(title):done():newline()

	return p
end



---
--- A shortcut method for adding a description as flavor text.
---
---@param parentNode table the html node to add to
---@param description string the description to write out
---@return table the title node added
function Infobox.makeFlavorText(parentNode, description)

	local p = parentNode:tag("p")
	StyleUtils.styleInfoboxFlavorText(p)

	p:wikitext(description):done():newline()

	return p
end



---
--- A shortcut method for adding a large icon to the header.
---
---@param parentNode table the html node to add to
---@param iconFilename string the icon to use
---@return table the title node added
function Infobox.makeTitleIcon(parentNode, iconFilename)

	local div = parentNode:tag("div")
	StyleUtils.styleInfoboxTitleIcon(div)

	div:wikitext("[[File:" .. iconFilename .. "]]"):done():newline()

	return div
end



---
--- A shortcut method to make a table row based on the provided check, also
--- checks to see whether it needs to add a separator.
---
---@param parentNode table the html node to add to
---@param check boolean whether the row can be added
---@param needsSeparator boolean whether the row needs a separator before it
---@param header string the header of the row
---@param value string the value of the row
---@return boolean whether the next row still needs a separator before it
function Infobox.makeInnerRow(parentNode, check, needsSeparator, header, value)

	local row
	local nowNeedsSeparator = needsSeparator
	if check ~= nil and check ~= "" then

		row = parentNode:tag("tr")
		nowNeedsSeparator = trySeparator(row, needsSeparator)

		populateStandardRow(row, header, value)
	end

	return nowNeedsSeparator
end



--- *DEPRECATED* TODO DELETE THIS because we're not doing inline css anymore
--- Shortcut method to build a standard row with a header and a value.
---
---@param htmlNode table the MediaWiki HTML entity to build on
---@param cssInline string inline style to apply
---@param header string header text
---@param value string value text
---@return table the same htmlTable
function Infobox.buildStandardRow(htmlNode, cssInline, header, value)

	htmlNode:tag("tr"):css(cssInline)
			  :tag("th"):wikitext(header):done()
			  :tag("td"):wikitext(value):done()
			  :done():newline()

	return htmlNode
end



---
--- Lays out an inner, no-styling table to display construction goods with
--- their stack sizes.
---
--- @param requiredGoods table of required goods, with stack sizes and IDs
--- @return string wikimarkup for a table of required goods to insert in other markup
function Infobox.writeRequiredGoodsRows(requiredGoods)

	if not requiredGoods or #requiredGoods == 0 then
		error("Cannot write content with provided table of required goods.")
	end

	local templateArgs = {}
	for _, requiredGroup in ipairs(requiredGoods) do

		local stackSize = requiredGroup[INDEX_REQ_STACK_SIZE]
		local goodName = GoodsData.getGoodNameByID(requiredGroup[INDEX_REQ_GOOD_ID])

		templateArgs[goodName] = stackSize
	end

	return mw.getCurrentFrame():expandTemplate{ title = CONSTRUCTION_TEMPLATE,
			args = templateArgs }
end



---
--- Starts off a new infobox.
---
--- @return table the html node created
function Infobox.startNewInfobox()

	local wikiInfobox = mw.html.create("div")
	StyleUtils.styleInfobox(wikiInfobox)

	wikiInfobox:newline()

	return wikiInfobox
end



---
--- Creates a standard way of displaying the top content of the infobox and
--- returns the HTML node. Styles consistently.
---
---@param wikiInfobox table the overall context this is added to
---@return table the html node created
function Infobox.startNewHeader(wikiInfobox)

	local header = wikiInfobox:tag("div")
	StyleUtils.styleInfoboxHeader(header)

	header:newline()

	return header
end



---
--- Finalizes the standard top content
---
---@param wikiInfobox table the overall context
---@param header table the header content to add to the outer context
function Infobox.endInnerTable(wikiInfobox, header)

	header:done():newline()

	return wikiInfobox
end



---
--- Creates a standard way of displaying rows of headers and values and
--- returns the HTML node. Styles consistently.
---
---@param wikiInfobox table the overall context this is added to
---@return table the html node created
function Infobox.startNewInnerTable(wikiInfobox)

	local innerTable = wikiInfobox:tag("table")
	innerTable = StyleUtils.styleInfoboxInnerTable(innerTable)

	innerTable:newline()

	return innerTable
end


---
--- Finalizes the standard inner display of headers and values.
---
---@param wikiInfobox table the overall context
---@param innerTable table the inner content to add to the outer context
function Infobox.endInnerTable(wikiInfobox, innerTable)

	innerTable:done():newline()

	return wikiInfobox
end

--endregion

return Infobox