Module:PerksController
From Against the Storm Official Wiki
Documentation for this module may be created at Module:PerksController/doc
---
--- Serves the Perks searching template by capturing input and using it to control the display of data.
---
---@module PerksController
local PerksController = {}
--region Dependencies
local PerksData = require("Module:PerksData")
local PerksView = require("Module:PerksView")
local ControllerUtilities = require("Module:ControllerUtilities")
--endregion
--region Private constants
local ARG_ID_LIST = "id"
local ARG_NAME_LIST = "name"
local ARG_DESCRIPTION_LIST = "description"
local ARG_SEARCH_ALL_LIST = "search"
local ARG_RARITY = "rarity"
local ARG_SOURCE = "source"
local ARG_EXCLUDE_LIST = "exclude"
local ARG_CAPTION = "caption"
local ARG_SHOW_ID = "show_id"
local ARG_SHOW_FLAG_VALUE = "show"
local ARG_DISPLAY_OVERRIDE = "display"
local ARG_DISPLAY_OVERRIDE_OPTION_LIST = "list"
local ARG_DISPLAY_OVERRIDE_OPTION_INLINE = "inline"
local ARG_LIST_TYPE = "list_type"
local TEMPLATE_PARAMETER_ID = ARG_ID_LIST
local TEMPLATE_PARAMETER_SHOW_ID = ARG_SHOW_ID
local TEMPLATE_PARAMETER_LIST_TYPE = ARG_LIST_TYPE
local TEMPLATE_PARAMETER_ICON_SIZE = "icon_size"
local TEMPLATE_PARAMETER_ICON_SIZE_DEFAULT = "none"
local TEMPLATE_LIST_ITEM = "PerksCornerstonesList/item"
local TEMPLATE_INLINE_LINK = "pl"
local DISPLAY_YES = "true"
--endregion
--region Private member variables
local currentFrame = {}
local perkIDs = {}
local isIDAlreadyAdded = {}
--endregion
--region Private methods
--- Takes a list of possible IDs and only loads the valid ones of the specified rarity or source to the member variable perkIDs. Skips all ids present in the exclude list.
---
---@param newIDs table an array of possible IDs to check before adding
---@param rarityToCheck string a rarity to filter to, needs to be normalized
---@param sourceToCheck string a source to filter to, needs to be normalized
---@param excludeList table an array of IDs that should not be added
local function loadPerkIDs(newIDs, rarityToCheck, sourceToCheck, excludeList)
for _, id in ipairs(newIDs) do
if PerksData.isPerkIDValid(id) and not excludeList[id:lower()] and not isIDAlreadyAdded[id:lower()] then
-- In this situation, nil values mean to skip the filter.
local isRarityMatch = not rarityToCheck or "" == rarityToCheck or PerksData.isRarityMatchByID(id, rarityToCheck)
local isSourceMatch = not sourceToCheck or "" == sourceToCheck or PerksData.isAnySource(id, sourceToCheck)
if isRarityMatch and isSourceMatch then
table.insert(perkIDs, id)
isIDAlreadyAdded[id:lower()] = true
end
end
end
end
--- Requests the desired lists of IDs from Perks data models, applies some post-processing, and stores them in the member variable perkIDs.
---
---@param selectList table array of ids of the cornerstone to include
---@param searchNameList table array of search criteria for names
---@param searchDescriptionsList table array of search criteria for descriptions
---@param rarity string the rarity of the cornerstones
---@param source string the source of cornerstones
---@param excludeList table list of ids
local function loadIDs(selectList, searchNameList, searchDescriptionsList, rarity, source, excludeList)
perkIDs = {}
isIDAlreadyAdded = {}
local attemptedSearch = false
-- Load the selected IDs
if selectList then
loadPerkIDs(selectList, rarity, source, excludeList)
-- It should always be true, but it can be blank.
if #selectList > 0 then
attemptedSearch = true
end
end
-- Add any name matches
if searchNameList and #searchNameList > 0 then
for _, searchName in ipairs(searchNameList) do
local newIDs = PerksData.getAllPerkIDsWhereName(searchName)
loadPerkIDs(newIDs, rarity, source, excludeList)
attemptedSearch = true
end
end
-- Add any description matches
if searchDescriptionsList and #searchDescriptionsList > 0 then
for _, searchDescription in ipairs(searchDescriptionsList) do
local newIDs = PerksData.getAllPerkIDsWhereDescription(searchDescription)
loadPerkIDs(newIDs, rarity, source, excludeList)
attemptedSearch = true
end
end
-- Or, if no searching was attempted (regardless of result), show all from the selected rarities and sources. No need to do this more expensive call unless it's the only filtering, because loadPerkIDs already filters out by rarity and source while looping.
if not attemptedSearch then
if (rarityFilter and "" ~= rarityFilter) or (sourceFilter and "" ~= sourceFilter) then
local newIDs = PerksData.getAllPerkIDsFilteredByRarityAndSource(rarity, source)
loadPerkIDs(newIDs, rarity, source, excludeList)
attemptedSearch = true
end
end
-- Or, if no searching was even attempted (regardless of result), show them all.
if not attemptedSearch then
local newIDs = PerksData.getAllPerkIDs()
loadPerkIDs(newIDs, rarity, source, excludeList)
end
if #perkIDs > 0 then
-- Alphabetize by name.
table.sort(perkIDs, PerksData.compareNames)
end
return perkIDs
end
--- Ensures that if a caption is not defined, there is a suitable fallback in case the author has specified an id, name, or search term to use, so readers know what they're looking at.
---
--- If no caption was specified and also none of those filtering parameters, then leave it up to the template by returning a blank caption.
---
---@param desiredCaption string the caption requested, if any
---@param selectList table array of ids of the perks to include
---@param searchNameList table array of search criteria for names
---@param searchDescriptionList table array of search criteria for descriptions
---@param rarity string the rarity of the cornerstones
---@param source string the source of cornerstones
---@param excludeList table array of ids that were excluded
---@return string an appropriate caption, or blank if it should be default
local function resolveCaption(desiredCaption, selectList, searchNameList, searchDescriptionList, rarity, source, excludeList)
-- No matter what, if the author provided a caption, use that.
if desiredCaption and desiredCaption ~= "" then
return desiredCaption
end
-- If no selection, delegate to template.
local addedToText = false
desiredCaption = "" .. #perkIDs
if rarity and rarity ~= "" then
desiredCaption = desiredCaption .. " " .. rarity .. " Perk"
addedToText = true
else
desiredCaption = desiredCaption .. " Perk"
-- did not addedToText, this is just default
end
if #perkIDs > 1 then
desiredCaption = desiredCaption .. "s"
end
if source and source ~= "" then
desiredCaption = desiredCaption .. " from " .. source .. "s"
addedToText = true
end
if selectList and #selectList > 0 then
if #selectList == 1 then
desiredCaption = desiredCaption .. " with ID '" .. selectList[1] .. "'"
else
desiredCaption = desiredCaption .. " with selected IDs"
end
addedToText = true
end
if searchNameList and #searchNameList > 0 then
if addedToText then
desiredCaption = desiredCaption .. " and"
end
if #searchNameList == 1 and searchNameList[1] then
desiredCaption = desiredCaption .. " named '" .. searchNameList[1] .. "'"
else
desiredCaption = desiredCaption .. " with specific names"
end
addedToText = true
end
if searchDescriptionList and #searchDescriptionList > 0 then
if addedToText then
desiredCaption = desiredCaption .. " and"
end
if #searchDescriptionList == 1 and searchDescriptionList[1] then
desiredCaption = desiredCaption .. " mentioning '" .. searchDescriptionList[1] .. "'"
else
desiredCaption = desiredCaption .. " by searching descriptions"
end
addedToText = true
end
if excludeList and #excludeList > 0 then
desiredCaption = desiredCaption .. " (with exclusions)"
addedToText = true
end
if addedToText then
return desiredCaption
else
-- Delegate to the template for the default
return ""
end
end
--- Calls the view to render the beginning of the table.
---
---@param desiredCaption string the caption for the table, if any
---@param viewParameters table a table of parameters made by and for PerksView
---@return string the wiki markup assembled so far by the view module
local function makeMarkupForTableStart(desiredCaption, viewParameters)
return PerksView.startTable(desiredCaption, viewParameters)
end
--- Calls the view to render a single row of the table with data based on the provided identifier.
---
---@param id string the unique identifier of a Perk or Cornerstone to use to add data to a new table row
---@param viewParameters table a table of parameters made by and for PerksView
---@return string the wiki markup assembled so far by the view module
local function makeMarkupPerRow(id, viewParameters)
local name = PerksData.getNameByID(id)
local rarity = PerksData.getRarityByID(id)
local description = ControllerUtilities.removeEnclosingDoubleQuotes(ControllerUtilities.findAndReplaceSpriteTagsWithFiles(PerksData.getDescriptionByID(id), currentFrame))
local isSourceAltar = PerksData.isFromAltarByID(id) and DISPLAY_YES
local isSourceCornerstone = PerksData.isFromCornerstoneByID(id) and DISPLAY_YES
local isSourceOrder = PerksData.isFromOrderByID(id) and DISPLAY_YES
local isSourceRelic = PerksData.isFromEventByID(id) and DISPLAY_YES
local isSourceTrader = PerksData.isFromTraderByID(id) and DISPLAY_YES
local isSourceDecoration = PerksData.isFromDecorationByID(id) and DISPLAY_YES
local isSourcePort = PerksData.isFromPortByID(id) and DISPLAY_YES
local isSourceRacial = PerksData.isFromRacialByID(id) and DISPLAY_YES
local isSourceInstitution = PerksData.isFromInstitutionByID(id) and DISPLAY_YES
local isSourceBiome = PerksData.isFromBiomeByID(id) and DISPLAY_YES
local price = PerksData.getPriceByID(id)
return PerksView.addRow(id, name, rarity, description, isSourceAltar, isSourceCornerstone, isSourceOrder, isSourceRelic, isSourceTrader, isSourceDecoration, isSourcePort, isSourceRacial, isSourceInstitution, isSourceBiome, price, viewParameters)
end
--- Handles assembling the rows for all of the IDs in the member variable list altarIDs.
---
---@param viewParameters table a table of parameters made by and for PerksView
---@return string the wiki markup assembled by the view (other templates)
local function makeMarkupForTableRows(viewParameters)
for _, id in ipairs(perkIDs) do
makeMarkupPerRow(id, viewParameters)
end
end
---Calls the view to render the content and appends it to the wiki markup string that will replace this controller's template.
-----
----- Calls several methods to build pieces of the table's markup based on the author's requests.
---
---@param desiredCaption string the caption for the table
---@param viewParameters table a table of parameters made by and for PerksView
---@return string the wiki markup assembled by the view (other templates)
local function renderTable(desiredCaption, viewParameters)
makeMarkupForTableStart(desiredCaption, viewParameters)
makeMarkupForTableRows(viewParameters)
return PerksView.finalize()
end
---makeMarkupPerListItem
---@param id string the id of the cornerstone to display
---@param listType string the type of list to create
---@param isShowingID boolean true when needing to show the ID column
---@return string the wiki markup assembled by the view (other templates)
local function makeMarkupPerListItem(id, listType, isShowingID)
local templateParameters = {
[TEMPLATE_PARAMETER_ID] = id,
[TEMPLATE_PARAMETER_LIST_TYPE] = listType,
[TEMPLATE_PARAMETER_SHOW_ID] = isShowingID and ARG_SHOW_FLAG_VALUE
}
return currentFrame:expandTemplate{ title = TEMPLATE_LIST_ITEM, args = templateParameters }
end
---makeMarkupForListItems
---@param listType string the type of list to create
---@param isShowingID boolean true when needing to show the ID column
---@return string the wiki markup assembled by the view (other templates)
local function makeMarkupForListItems(listType, isShowingID)
local markup = ""
for _, id in ipairs(perkIDs) do
markup = markup .. makeMarkupPerListItem(id, listType, isShowingID)
end
return markup
end
---renderList
---@param listType string the type of list to create
---@param isShowingID boolean true when needing to show the ID column
---@return string the wiki markup assembled by the view (other templates
local function renderList(listType, isShowingID)
return makeMarkupForListItems(listType, isShowingID)
end
---makeMarkupPerLink
---@param id string the id of the cornerstone to display
---@param isShowingID boolean true when needing to show the ID column
---@return string the wiki markup assembled by the view (other templates)
local function makeMarkupPerLink(id, isShowingID)
local templateParameters = {
[TEMPLATE_PARAMETER_ID] = id,
[TEMPLATE_PARAMETER_ICON_SIZE] = TEMPLATE_PARAMETER_ICON_SIZE_DEFAULT,
}
local link = currentFrame:expandTemplate{ title = TEMPLATE_INLINE_LINK, args = templateParameters }
if isShowingID then
return link .. " ('" .. id .. "')"
else
return link
end
end
---makeMarkupForInlineLinks
---@param isShowingID boolean true when needing to show the ID column
---@return string the wiki markup assembled by the view (other templates)
local function makeMarkupForInlineLinks(isShowingID)
local markup = ""
for i, id in ipairs(perkIDs) do
if i > 1 then
markup = markup .. ", "
end
markup = markup .. makeMarkupPerLink(id, isShowingID)
end
return markup
end
---renderInline
---@param isShowingID boolean true when needing to show the ID column
---@return string the wiki markup assembled by the view (other templates)
local function renderInlineLinks(isShowingID)
return makeMarkupForInlineLinks(isShowingID)
end
--endregion
--region Public methods
function PerksController.main(frame)
-- Selection parameters, normalized for exclude list
local selectList = ControllerUtilities.expandCommaSeparatedStringsIntoTable(frame.args[ARG_ID_LIST], false)
local excludeList = ControllerUtilities.expandCommaSeparatedStringsIntoTable(frame.args[ARG_EXCLUDE_LIST], true, true)
local searchNameList = ControllerUtilities.expandCommaSeparatedStringsIntoTable(frame.args[ARG_NAME_LIST], false)
local searchDescriptionList = ControllerUtilities.expandCommaSeparatedStringsIntoTable(frame.args[ARG_DESCRIPTION_LIST], false)
local searchAllList = ControllerUtilities.expandCommaSeparatedStringsIntoTable(frame.args[ARG_SEARCH_ALL_LIST], false)
local rarityFilter = PerksData.normalizeRarityText(frame.args[ARG_RARITY])
local sourceFilter = PerksData.normalizeSourceText(frame.args[ARG_SOURCE])
-- Substitute the search all terms for name or description, if they weren't provided but search-all was.
if searchAllList and #searchAllList > 0 then
if #searchNameList < 1 then
searchNameList = searchAllList
end
if #searchDescriptionList < 1 then
searchDescriptionList = searchAllList
end
end
-- Display parameters
local desiredCaption = frame.args[ARG_CAPTION]
local displayOverride = frame.args[ARG_DISPLAY_OVERRIDE]
local listType = frame.args[ARG_LIST_TYPE]
local isShowingID = ARG_SHOW_FLAG_VALUE == frame.args[ARG_SHOW_ID]
-- Let the View module itself determine how to use the template parameters relating to the view.
local viewParameters = PerksView.constructViewParametersFromTemplateFrame(frame)
currentFrame = frame
loadIDs(selectList, searchNameList, searchDescriptionList, rarityFilter, sourceFilter, excludeList)
if #perkIDs < 1 then
return "No matching Perks found."
end
if displayOverride == ARG_DISPLAY_OVERRIDE_OPTION_LIST then
return renderList(listType, isShowingID)
end
if displayOverride == ARG_DISPLAY_OVERRIDE_OPTION_INLINE then
return renderInlineLinks(isShowingID)
end
-- Default display is table.
desiredCaption = resolveCaption(desiredCaption, selectList, searchNameList, searchDescriptionList, rarityFilter, sourceFilter, excludeList)
return renderTable(desiredCaption, viewParameters)
end
--endregion
return PerksController


