Module:PerksController: Difference between revisions
From Against the Storm Official Wiki
Now supports multiple names and descriptions criteria |
Added "search" parameter to search the same thing in both name and description |
||
| Line 22: | Line 22: | ||
local ARG_NAME_LIST = "name" | local ARG_NAME_LIST = "name" | ||
local ARG_DESCRIPTION_LIST = "description" | local ARG_DESCRIPTION_LIST = "description" | ||
local ARG_SEARCH_ALL_LIST = "search" | |||
local ARG_RARITY = "rarity" | local ARG_RARITY = "rarity" | ||
local ARG_SOURCE = "source" | local ARG_SOURCE = "source" | ||
| Line 117: | Line 118: | ||
---@param source string the source of cornerstones | ---@param source string the source of cornerstones | ||
---@param excludeList table list of ids | ---@param excludeList table list of ids | ||
function | local function loadIDs(selectList, searchNameList, searchDescriptionsList, rarity, source, excludeList) | ||
perkIDs = {} | perkIDs = {} | ||
| Line 474: | Line 475: | ||
local searchNameList = ControllerUtilities.expandCommaSeparatedStringsIntoTable(frame.args[ARG_NAME_LIST], false) | local searchNameList = ControllerUtilities.expandCommaSeparatedStringsIntoTable(frame.args[ARG_NAME_LIST], false) | ||
local searchDescriptionList = ControllerUtilities.expandCommaSeparatedStringsIntoTable(frame.args[ARG_DESCRIPTION_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 rarityFilter = PerksData.normalizeRarityText(frame.args[ARG_RARITY]) | ||
local sourceFilter = PerksData.normalizeSourceText(frame.args[ARG_SOURCE]) | 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 | -- Display parameters | ||
| Line 500: | Line 513: | ||
currentFrame = frame | currentFrame = frame | ||
loadIDs(selectList, searchNameList, searchDescriptionList, rarityFilter, sourceFilter, excludeList) | |||
if #perkIDs < 1 then | if #perkIDs < 1 then | ||
return "No matching Perks found." | return "No matching Perks found." | ||
Revision as of 01:33, 9 May 2024
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 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 ARGS_EXCLUDE_LIST = "exclude"
local ARG_CAPTION = "caption"
local ARG_SKIP_SOURCES = "skip_sources"
local ARG_SKIP_FLAG_VALUE = "skip"
local ARG_SHOW_ID = "show_id"
local ARG_SHOW_RARITY = "show_rarity"
local ARG_SHOW_DESCRIPTION = "show_description"
local ARG_SHOW_SOURCE_ALTAR = "show_source_altar"
local ARG_SHOW_SOURCE_CORNERSTONE = "show_source_cornerstone"
local ARG_SHOW_SOURCE_ORDER = "show_source_order"
local ARG_SHOW_SOURCE_RELIC = "show_source_relic"
local ARG_SHOW_SOURCE_TRADER = "show_source_trader"
local ARG_SHOW_PRICE = "show_price"
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_CAPTION = ARG_CAPTION
local TEMPLATE_PARAMETER_ID = ARG_ID_LIST
local TEMPLATE_PARAMETER_RARITY = ARG_RARITY
local TEMPLATE_PARAMETER_DESC = ARG_DESCRIPTION_LIST
local TEMPLATE_PARAMETER_SOURCE_ALTAR = "is_from_altar"
local TEMPLATE_PARAMETER_SOURCE_CORNERSTONE = "is_from_cornerstone"
local TEMPLATE_PARAMETER_SOURCE_ORDER = "is_from_order"
local TEMPLATE_PARAMETER_SOURCE_RELIC = "is_from_relic"
local TEMPLATE_PARAMETER_SOURCE_TRADER = "is_from_trader"
local TEMPLATE_PARAMETER_NUM_SOURCES = "num_sources_shown"
local TEMPLATE_PARAMETER_PRICE = "price"
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_TABLE_BASE = "PerksCornerstonesTable"
local TEMPLATE_TABLE_SUFFIX_ROW = "/row"
local TEMPLATE_TABLE_SUFFIX_END = "/end"
local TEMPLATE_TABLE_SKIP_SOURCES_VARIANT = "/SkipSources"
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] and not isIDAlreadyAdded[id] 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] = 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.
if not attemptedSearch then
local newIDs = PerksData.getAllPerkIDsFilteredByRarityAndSource(rarity, source)
loadPerkIDs(newIDs, rarity, source, excludeList)
attemptedSearch = true
end
-- Or, if no searching was even attempted (regardless of result), show them all.
if not attemptedSearch then
local newIDs = PerksData.getAllPerkIDs()
loadStormforgedIDs(newIDs, 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 cornerstone 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
---@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
---resolveTableStartTemplate
---@param isSkippingSources boolean true if skipping variant should be used
---@return string the full title of the template, for expandTemplate
local function resolveTableStartTemplate(isSkippingSources)
local suffixIfSkipping = (isSkippingSources and TEMPLATE_TABLE_SKIP_SOURCES_VARIANT) or ""
return TEMPLATE_TABLE_BASE .. suffixIfSkipping
end
---resolveTableRowTemplate
---@param isSkippingSources boolean true if skipping variant should be used
---@return string the full title of the template, for expandTemplate
local function resolveTableRowTemplate(isSkippingSources)
local suffixIfSkipping = (isSkippingSources and TEMPLATE_TABLE_SKIP_SOURCES_VARIANT) or ""
return TEMPLATE_TABLE_BASE .. TEMPLATE_TABLE_SUFFIX_ROW .. suffixIfSkipping
end
---resolveEndTemplate
---@return string the template name to use
local function resolveTableEndTemplate()
return TEMPLATE_TABLE_BASE .. TEMPLATE_TABLE_SUFFIX_END
end
--- Calls the view (other templates) to render the beginning of the table.
---
---@param desiredCaption string the caption for the table, if any
---@param isSkippingSources boolean true if skipping variant should be used
---@param argsForTableTemplate table a set of arguments ready to pass through to the called template
---@return string the wiki markup assembled by the view (other templates)
local function makeMarkupForTableStart(desiredCaption, isSkippingSources, argsForTableTemplate)
argsForTableTemplate[TEMPLATE_PARAMETER_CAPTION] = desiredCaption
-- Count how many source columns should be shown.
local sources = {
ARG_SHOW_SOURCE_ALTAR,
ARG_SHOW_SOURCE_CORNERSTONE,
ARG_SHOW_SOURCE_ORDER,
ARG_SHOW_SOURCE_RELIC,
ARG_SHOW_SOURCE_TRADER
}
local numSourcesShown = 0
for _, index in ipairs(sources) do
if ARG_SHOW_FLAG_VALUE == argsForTableTemplate[index] then
numSourcesShown = numSourcesShown + 1
end
end
argsForTableTemplate[TEMPLATE_PARAMETER_NUM_SOURCES] = numSourcesShown
return currentFrame:expandTemplate{ title = resolveTableStartTemplate(isSkippingSources), args = argsForTableTemplate }
end
--- Calls the view (other templates) 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 isSkippingSources boolean true if skipping variant should be used
---@param argsForTableTemplate table a set of arguments ready to pass through to the called template
---@return string the wiki markup assembled by the view (other templates)
local function makeMarkupPerRow(id, isSkippingSources, argsForTableTemplate)
argsForTableTemplate[TEMPLATE_PARAMETER_ID] = id
argsForTableTemplate[TEMPLATE_PARAMETER_RARITY] = PerksData.getRarityByID(id)
argsForTableTemplate[TEMPLATE_PARAMETER_DESC] = ControllerUtilities.findAndReplaceSpriteTagsWithFiles(PerksData.getDescriptionByID(id), currentFrame)
argsForTableTemplate[TEMPLATE_PARAMETER_PRICE] = PerksData.getPriceByID(id)
-- This is default, but adds a lot of extra template overhead if it's not needed, so only add it if necessary.
if not isSkippingSources then
argsForTableTemplate[TEMPLATE_PARAMETER_SOURCE_ALTAR] = PerksData.isFromAltarByID(id) and DISPLAY_YES
argsForTableTemplate[TEMPLATE_PARAMETER_SOURCE_CORNERSTONE] = PerksData.isFromCornerstoneByID(id) and DISPLAY_YES
argsForTableTemplate[TEMPLATE_PARAMETER_SOURCE_ORDER] = PerksData.isFromOrderByID(id) and DISPLAY_YES
argsForTableTemplate[TEMPLATE_PARAMETER_SOURCE_RELIC] = PerksData.isFromEventByID(id) and DISPLAY_YES
argsForTableTemplate[TEMPLATE_PARAMETER_SOURCE_TRADER] = PerksData.isFromTraderByID(id) and DISPLAY_YES
end
return currentFrame:expandTemplate{ title = resolveTableRowTemplate(isSkippingSources), args = argsForTableTemplate }
end
--- Handles assembling the rows for all of the IDs in the member variable list altarIDs.
---
---@param isSkippingSources boolean true if skipping sources columns
---@param argsForTableTemplate table a table of arguments to pass through to the view templates
---@return string the wiki markup assembled by the view (other templates)
local function makeMarkupForTableRows(isSkippingSources, argsForTableTemplate)
local markup = ""
for _, id in ipairs(perkIDs) do
markup = markup .. makeMarkupPerRow(id, isSkippingSources, argsForTableTemplate)
end
return markup
end
--- Calls the view (other templates) to render the end of the table.
---
---@return string the wiki markup assembled by the view (other templates)
local function makeMarkupForTableEnd()
return currentFrame:expandTemplate{ title = resolveTableEndTemplate(), args = {} }
end
---Calls the view (other templates) 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 isSkippingSources boolean true if skipping sources columns
---@param argsForTableTemplate table a table of arguments to pass through to the view templates
---@return string the wiki markup assembled by the view (other templates)
local function renderTable(desiredCaption, isSkippingSources, argsForTableTemplate)
local startMarkup = makeMarkupForTableStart(desiredCaption, isSkippingSources, argsForTableTemplate)
local rowsMarkup = makeMarkupForTableRows(isSkippingSources, argsForTableTemplate)
return startMarkup .. rowsMarkup .. makeMarkupForTableEnd()
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
local selectList = ControllerUtilities.expandCommaSeparatedStringsIntoTable(frame.args[ARG_ID_LIST], false)
local excludeList = ControllerUtilities.expandCommaSeparatedStringsIntoTable(frame.args[ARGS_EXCLUDE_LIST], 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]
local isSkippingSources = ARG_SKIP_FLAG_VALUE == frame.args[ARG_SKIP_SOURCES]
-- For clarity, copy each value instead of reusing the whole args table.
local argumentsToPassThroughToTable = {
[ARG_SKIP_SOURCES] = frame.args[ARG_SKIP_SOURCES],
[ARG_SHOW_ID] = frame.args[ARG_SHOW_ID],
[ARG_SHOW_RARITY] = frame.args[ARG_SHOW_RARITY],
[ARG_SHOW_DESCRIPTION] = frame.args[ARG_SHOW_DESCRIPTION],
[ARG_SHOW_SOURCE_ALTAR] = frame.args[ARG_SHOW_SOURCE_ALTAR],
[ARG_SHOW_SOURCE_CORNERSTONE] = frame.args[ARG_SHOW_SOURCE_CORNERSTONE],
[ARG_SHOW_SOURCE_ORDER] = frame.args[ARG_SHOW_SOURCE_ORDER],
[ARG_SHOW_SOURCE_RELIC] = frame.args[ARG_SHOW_SOURCE_RELIC],
[ARG_SHOW_SOURCE_TRADER] = frame.args[ARG_SHOW_SOURCE_TRADER],
[ARG_SHOW_PRICE] = frame.args[ARG_SHOW_PRICE]
}
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, isSkippingSources, argumentsToPassThroughToTable)
end
--endregion
return PerksController


