Module:PerksView: Difference between revisions
From Against the Storm Official Wiki
(Created to replace the table templates that are way too slow) |
(hiding all sources should work now) |
||
(5 intermediate revisions by the same user not shown) | |||
Line 12: | Line 12: | ||
--region Private constants | --region Private constants | ||
local DEFAULT_CAPTION = "Perks and Cornerstones" | local DEFAULT_CAPTION = "Perks and Cornerstones" | ||
Line 32: | Line 18: | ||
local CLASS_UNSORTABLE = "unsortable" | local CLASS_UNSORTABLE = "unsortable" | ||
local | local PERK_LINK_ICON_SIZE = "large" | ||
local HEADER_ID = "ID" | local HEADER_ID = "ID" | ||
Line 105: | Line 91: | ||
function PerksView.ViewParameters.isShowingPrice(self) | function PerksView.ViewParameters.isShowingPrice(self) | ||
return ARG_SHOW_FLAG_VALUE == self[ARG_SHOW_PRICE] | return ARG_SHOW_FLAG_VALUE == self[ARG_SHOW_PRICE] | ||
end | |||
function PerksView.ViewParameters.countShownSourceColumns(self) | |||
local count = 0 | |||
if self:isShowingSourceAltar() then | |||
count = count + 1 | |||
end | |||
if self:isShowingSourceCornerstone() then | |||
count = count + 1 | |||
end | |||
if self:isShowingSourceOrder() then | |||
count = count + 1 | |||
end | |||
if self:isShowingSourceRelic() then | |||
count = count + 1 | |||
end | |||
if self:isShowingSourceTrader() then | |||
count = count + 1 | |||
end | |||
-- No matter what, one column. | |||
if 0 == count then | |||
return 1 | |||
else | |||
return count | |||
end | |||
end | end | ||
Line 133: | Line 146: | ||
function PerksView.constructViewParametersFromTemplateFrame(frame) | function PerksView.constructViewParametersFromTemplateFrame(frame) | ||
local newInstance = {} | local newInstance = {} | ||
newInstance[ARG_SKIP_SOURCES] = frame.args[ARG_SKIP_SOURCES] or | newInstance[ARG_SKIP_SOURCES] = frame.args[ARG_SKIP_SOURCES] or "not by default" | ||
newInstance[ARG_SHOW_ID] = frame.args[ARG_SHOW_ID] or | newInstance[ARG_SHOW_ID] = frame.args[ARG_SHOW_ID] or "not by default" | ||
newInstance[ARG_SHOW_RARITY] = frame.args[ARG_SHOW_RARITY] or ARG_SHOW_FLAG_VALUE | newInstance[ARG_SHOW_RARITY] = frame.args[ARG_SHOW_RARITY] or ARG_SHOW_FLAG_VALUE | ||
newInstance[ARG_SHOW_DESCRIPTION] = frame.args[ARG_SHOW_DESCRIPTION] or ARG_SHOW_FLAG_VALUE | newInstance[ARG_SHOW_DESCRIPTION] = frame.args[ARG_SHOW_DESCRIPTION] or ARG_SHOW_FLAG_VALUE | ||
Line 202: | Line 215: | ||
-- Assign the methods so they can be chained | -- Assign the methods so they can be chained | ||
cell.spanTwoRows = function(self) | cell.spanTwoRows = function(self) | ||
self:attr( | self:attr({ rowspan="2" }) | ||
return self | return self | ||
end | end | ||
Line 209: | Line 222: | ||
return self | return self | ||
end | end | ||
cell.spanMultipleColumns = function(self, columnsToSpan) | |||
self:attr({ colspan=columnsToSpan }) | |||
return self | |||
end | |||
return cell | return cell | ||
Line 247: | Line 265: | ||
{ label = HEADER_RARITY, cell = createHeaderCell(HEADER_RARITY):spanTwoRows() }, | { label = HEADER_RARITY, cell = createHeaderCell(HEADER_RARITY):spanTwoRows() }, | ||
{ label = HEADER_DESCRIPTION, cell = createHeaderCell(HEADER_DESCRIPTION):spanTwoRows():makeUnsortable() }, | { label = HEADER_DESCRIPTION, cell = createHeaderCell(HEADER_DESCRIPTION):spanTwoRows():makeUnsortable() }, | ||
{ label = HEADER_SOURCES, cell = createHeaderCell(HEADER_SOURCES) }, | { label = HEADER_SOURCES, cell = createHeaderCell(HEADER_SOURCES):spanMultipleColumns(viewParameters:countShownSourceColumns()) }, | ||
{ label = HEADER_PRICE, cell = createHeaderCell(HEADER_PRICE):spanTwoRows() } | { label = HEADER_PRICE, cell = createHeaderCell(HEADER_PRICE):spanTwoRows() } | ||
} | } | ||
Line 303: | Line 321: | ||
-- Configure the table; we'll figure out which to actually show in a moment. Separating the setup from the logic makes this significantly easier to read and understand. These cannot be key-value pairs, like [label] = cell, because we have to use numerical indexes to preserve their order. | -- Configure the table; we'll figure out which to actually show in a moment. Separating the setup from the logic makes this significantly easier to read and understand. These cannot be key-value pairs, like [label] = cell, because we have to use numerical indexes to preserve their order. | ||
local | local cellsInOrderWithoutSources = { | ||
{ label = HEADER_ID, cell = createDataCell(data[HEADER_ID] or "—") }, | |||
{ label = HEADER_NAME, cell = createDataCell(data[HEADER_NAME] or "—") }, | |||
{ label = HEADER_RARITY, cell = createDataCell(data[HEADER_RARITY] or "—") }, | |||
{ label = HEADER_DESCRIPTION, cell = createDataCell(data[HEADER_DESCRIPTION] or "—") }, | |||
{ label = HEADER_PRICE, cell = createDataCell(data[HEADER_PRICE] or "—") } | |||
} | |||
local cellsInOrderWithSources = { | |||
{ label = HEADER_ID, cell = createDataCell(data[HEADER_ID] or "—") }, | { label = HEADER_ID, cell = createDataCell(data[HEADER_ID] or "—") }, | ||
{ label = HEADER_NAME, cell = createDataCell(data[HEADER_NAME] or "—") }, | { label = HEADER_NAME, cell = createDataCell(data[HEADER_NAME] or "—") }, | ||
Line 316: | Line 341: | ||
} | } | ||
local dataRow = mw.html.create("tr") | -- If skipping the sources altogether overrides individual column visibility. | ||
dataRow:newline() | if viewParameters:isShowingSources() then | ||
local dataRow = mw.html.create("tr") | |||
dataRow:newline() | |||
addAllCellsThatShouldBeShowing(dataRow, cellsInOrderWithSources, viewParameters) | |||
htmlTable:node(dataRow):newline() | |||
return dataRow | |||
else | |||
local dataRow = mw.html.create("tr") | |||
dataRow:newline() | |||
addAllCellsThatShouldBeShowing(dataRow, cellsInOrderWithoutSources, viewParameters) | |||
htmlTable:node(dataRow):newline() | |||
return dataRow | |||
end | |||
end | end | ||
Line 363: | Line 402: | ||
end | end | ||
end | end | ||
end | |||
local function createPerkLink(id) | |||
return mw.getCurrentFrame():expandTemplate{ | |||
title = "pl", | |||
args = { ["id"] = id, ["iconsize"] = PERK_LINK_ICON_SIZE } | |||
} | |||
end | end | ||
Line 372: | Line 419: | ||
---startTable | ---startTable | ||
---@param caption | ---@param caption string the desired caption | ||
---@param viewParameters table | ---@param viewParameters table a ViewParameters initialized with its constructor | ||
---@return table | ---@return table an html node, the htmlTable member variable | ||
function PerksView.startTable(caption, viewParameters) | function PerksView.startTable(caption, viewParameters) | ||
Line 384: | Line 431: | ||
---addRow | ---addRow | ||
---@param id | ---@param id string the ID of the perk | ||
---@param name | ---@param _ string the name of the perk is not actually used, but asked for because the Controller doesn't need to know | ||
---@param rarity | ---@param rarity string the rarity of the perk expressed as a string | ||
---@param description | ---@param description string the description of the perk | ||
---@param isSourceAltar | ---@param isSourceAltar boolean whether the perk is acquired at the altar | ||
---@param isSourceCornerstone | ---@param isSourceCornerstone boolean whether the perk is acquired as a cornerstone | ||
---@param isSourceOrder | ---@param isSourceOrder boolean whether the perk is acquired from orders | ||
---@param isSourceRelic | ---@param isSourceRelic boolean whether the perk is acquired from relics | ||
---@param isSourceTrader | ---@param isSourceTrader boolean whether the perk is acquired from traders | ||
---@param price | ---@param price number the purchase price at a trader | ||
---@param viewParameters table | ---@param viewParameters table a ViewParameters initialized with its constructor | ||
---@return table | ---@return table an html node, the htmlTable member variable | ||
function PerksView.addRow(id, | function PerksView.addRow(id, _, rarity, description, isSourceAltar, isSourceCornerstone, isSourceOrder, isSourceRelic, isSourceTrader, price, viewParameters) | ||
local data = { | local data = { | ||
[HEADER_ID] = validateStringData(id), | [HEADER_ID] = validateStringData(id), | ||
[HEADER_NAME] = validateStringData( | [HEADER_NAME] = createPerkLink(validateStringData(id)), | ||
[HEADER_RARITY] = validateStringData(rarity), | [HEADER_RARITY] = validateStringData(rarity), | ||
[HEADER_DESCRIPTION] = validateStringData(description), | [HEADER_DESCRIPTION] = validateStringData(description), | ||
Line 412: | Line 459: | ||
addDataRow(data, viewParameters) | addDataRow(data, viewParameters) | ||
return htmlTable | |||
end | |||
---finalize | |||
---@return table the complete html table node, fully rendered | |||
function PerksView.finalize() | |||
return htmlTable | return htmlTable |
Latest revision as of 01:14, 24 June 2024
Documentation for this module may be created at Module:PerksView/doc
--- --- Serves the Perks searching template by capturing input and using it to control the display of data. --- ---@module PerksView local PerksView = {} --region Dependencies --endregion --region Private constants local DEFAULT_CAPTION = "Perks and Cornerstones" local CLASS_PERKS_TABLE = "wikitable sortable mw-collapsible" local CLASS_UNSORTABLE = "unsortable" local PERK_LINK_ICON_SIZE = "large" local HEADER_ID = "ID" local HEADER_NAME = "Name" local HEADER_RARITY = "Rarity" local HEADER_DESCRIPTION = "Description" local HEADER_SOURCES = "Sources" local HEADER_PRICE = "Price" local HEADER_ABBR_ALTAR = tostring(mw.html.create("abbr"):attr({ title="Altar (Stormforged Cornerstone)" }):wikitext("Alt")) local HEADER_ABBR_CORNERSTONE = tostring(mw.html.create("abbr"):attr({ title="Cornerstone" }):wikitext("Cor")) local HEADER_ABBR_ORDER = tostring(mw.html.create("abbr"):attr({ title="Order"}):wikitext("Ord")) local HEADER_ABBR_RELIC = tostring(mw.html.create("abbr"):attr({ title="Relic (Glade Event)" }):wikitext("Rel")) local HEADER_ABBR_TRADER = tostring(mw.html.create("abbr"):attr({ title="Trader" }):wikitext("Tra")) local RED_X = mw.getCurrentFrame():expandTemplate{ title = "c", args = { [1] = "Red", [2] = "x" } } --endregion --region Public sub-class --- This subclass should never be created directly, but only via the constructFromTemplateFrame method, to ensure data integrity and minimize chance for errors. PerksView.ViewParameters = {} -- Indexes local ARG_SKIP_SOURCES = "skip_sources" 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" -- Flags local ARG_SKIP_FLAG_VALUE = "skip" local ARG_SHOW_FLAG_VALUE = "show" function PerksView.ViewParameters.isShowingID(self) return ARG_SHOW_FLAG_VALUE == self[ARG_SHOW_ID] end function PerksView.ViewParameters.isShowingName() return true end function PerksView.ViewParameters.isShowingRarity(self) return ARG_SHOW_FLAG_VALUE == self[ARG_SHOW_RARITY] end function PerksView.ViewParameters.isShowingDescription(self) return ARG_SHOW_FLAG_VALUE == self[ARG_SHOW_DESCRIPTION] end function PerksView.ViewParameters.isShowingSources(self) return ARG_SKIP_FLAG_VALUE ~= self[ARG_SKIP_SOURCES] end function PerksView.ViewParameters.isShowingSourceAltar(self) return ARG_SHOW_FLAG_VALUE == self[ARG_SHOW_SOURCE_ALTAR] end function PerksView.ViewParameters.isShowingSourceCornerstone(self) return ARG_SHOW_FLAG_VALUE == self[ARG_SHOW_SOURCE_CORNERSTONE] end function PerksView.ViewParameters.isShowingSourceOrder(self) return ARG_SHOW_FLAG_VALUE == self[ARG_SHOW_SOURCE_ORDER] end function PerksView.ViewParameters.isShowingSourceRelic(self) return ARG_SHOW_FLAG_VALUE == self[ARG_SHOW_SOURCE_RELIC] end function PerksView.ViewParameters.isShowingSourceTrader(self) return ARG_SHOW_FLAG_VALUE == self[ARG_SHOW_SOURCE_TRADER] end function PerksView.ViewParameters.isShowingPrice(self) return ARG_SHOW_FLAG_VALUE == self[ARG_SHOW_PRICE] end function PerksView.ViewParameters.countShownSourceColumns(self) local count = 0 if self:isShowingSourceAltar() then count = count + 1 end if self:isShowingSourceCornerstone() then count = count + 1 end if self:isShowingSourceOrder() then count = count + 1 end if self:isShowingSourceRelic() then count = count + 1 end if self:isShowingSourceTrader() then count = count + 1 end -- No matter what, one column. if 0 == count then return 1 else return count end end local checkerSwitch = { [HEADER_ID] = PerksView.ViewParameters.isShowingID, [HEADER_NAME] = PerksView.ViewParameters.isShowingName, [HEADER_RARITY] = PerksView.ViewParameters.isShowingRarity, [HEADER_DESCRIPTION] = PerksView.ViewParameters.isShowingDescription, [HEADER_SOURCES] = PerksView.ViewParameters.isShowingSources, [HEADER_PRICE] = PerksView.ViewParameters.isShowingPrice, [HEADER_ABBR_ALTAR] = PerksView.ViewParameters.isShowingSourceAltar, [HEADER_ABBR_CORNERSTONE] = PerksView.ViewParameters.isShowingSourceCornerstone, [HEADER_ABBR_ORDER] = PerksView.ViewParameters.isShowingSourceOrder, [HEADER_ABBR_RELIC] = PerksView.ViewParameters.isShowingSourceRelic, [HEADER_ABBR_TRADER] = PerksView.ViewParameters.isShowingSourceTrader } ---getCheckerMethod ---@param headerLabel string the label displayed on the table ---@return function the function to call to see whether that column should be shown function PerksView.ViewParameters.getCheckerMethod(headerLabel) return checkerSwitch[headerLabel] end ---constructViewParametersFromTemplateFrame ---@param frame table the mediawiki template's calling frame ---@return table an instance of the ViewParameters class function PerksView.constructViewParametersFromTemplateFrame(frame) local newInstance = {} newInstance[ARG_SKIP_SOURCES] = frame.args[ARG_SKIP_SOURCES] or "not by default" newInstance[ARG_SHOW_ID] = frame.args[ARG_SHOW_ID] or "not by default" newInstance[ARG_SHOW_RARITY] = frame.args[ARG_SHOW_RARITY] or ARG_SHOW_FLAG_VALUE newInstance[ARG_SHOW_DESCRIPTION] = frame.args[ARG_SHOW_DESCRIPTION] or ARG_SHOW_FLAG_VALUE newInstance[ARG_SHOW_SOURCE_ALTAR] = frame.args[ARG_SHOW_SOURCE_ALTAR] or ARG_SHOW_FLAG_VALUE newInstance[ARG_SHOW_SOURCE_CORNERSTONE] = frame.args[ARG_SHOW_SOURCE_CORNERSTONE] or ARG_SHOW_FLAG_VALUE newInstance[ARG_SHOW_SOURCE_ORDER] = frame.args[ARG_SHOW_SOURCE_ORDER] or ARG_SHOW_FLAG_VALUE newInstance[ARG_SHOW_SOURCE_RELIC] = frame.args[ARG_SHOW_SOURCE_RELIC] or ARG_SHOW_FLAG_VALUE newInstance[ARG_SHOW_SOURCE_TRADER] = frame.args[ARG_SHOW_SOURCE_TRADER] or ARG_SHOW_FLAG_VALUE newInstance[ARG_SHOW_PRICE] = frame.args[ARG_SHOW_PRICE] or ARG_SHOW_FLAG_VALUE -- Attach methods to the instance setmetatable(newInstance, { __index = PerksView.ViewParameters }) return newInstance end --endregion --region Private member variables local htmlTable --endregion --region Private methods ---createCaptionNode ---@param captionText string the desired caption ---@return table the html node of the caption tags local function createCaptionNode(captionText) captionNode = mw.html.create("caption") if null == captionText or "" == captionText then captionNode:wikitext(DEFAULT_CAPTION) else captionNode:wikitext(captionText) end return captionNode end ---openTable ---@param caption string the desired caption ---@return table the complete html node, htmlTable, the class variable local function openTable(caption) htmlTable = mw.html.create("table") htmlTable:addClass(CLASS_PERKS_TABLE):newline() htmlTable:node(createCaptionNode(caption)):newline() return htmlTable end ---createHeaderCell ---@param label string the label to put in the header cell ---@return table a new html table header cell local function createHeaderCell(label) local cell = mw.html.create("th") cell:wikitext(label) -- Assign the methods so they can be chained cell.spanTwoRows = function(self) self:attr({ rowspan="2" }) return self end cell.makeUnsortable = function(self) self:addClass(CLASS_UNSORTABLE) return self end cell.spanMultipleColumns = function(self, columnsToSpan) self:attr({ colspan=columnsToSpan }) return self end return cell end ---loopThroughHeaderCells ---@param row table the html table row node to use ---@param preconfiguredRowToUse table the row already setup to choose from ---@param viewParameters table the ViewParameters specified by the author ---@return table the same row, now with more stuff in it local function addAllCellsThatShouldBeShowing(row, preconfiguredRowToUse, viewParameters) for _, rowItem in ipairs(preconfiguredRowToUse) do local isShowingIn = PerksView.ViewParameters.getCheckerMethod(rowItem.label) if isShowingIn(viewParameters) then row:node(rowItem.cell):newline() end end end ---addHeaderRow adds header rows to the member variable htmlTable and returns what was added. --- ---@param viewParameters table a ViewParameters initialized with its constructor ---@return table, table the header row added, sometimes a second sub-header row local function addHeaderRow(viewParameters) -- Configure the options; we'll figure out which to create in a moment. Separating the setup from the logic makes this significantly easier to read and understand. These cannot be key-value pairs, like [label] = cell, because we have to use numerical indexes to preserve their order. local headersInOrderWithoutSources = { { label = HEADER_ID, cell = createHeaderCell(HEADER_ID) }, { label = HEADER_NAME, cell = createHeaderCell(HEADER_NAME) }, { label = HEADER_RARITY, cell = createHeaderCell(HEADER_RARITY) }, { label = HEADER_DESCRIPTION, cell = createHeaderCell(HEADER_DESCRIPTION):makeUnsortable() }, { label = HEADER_PRICE, cell = createHeaderCell(HEADER_PRICE) } } local headersInOrderWithSources = { { label = HEADER_ID, cell = createHeaderCell(HEADER_ID):spanTwoRows() }, { label = HEADER_NAME, cell = createHeaderCell(HEADER_NAME):spanTwoRows() }, { label = HEADER_RARITY, cell = createHeaderCell(HEADER_RARITY):spanTwoRows() }, { label = HEADER_DESCRIPTION, cell = createHeaderCell(HEADER_DESCRIPTION):spanTwoRows():makeUnsortable() }, { label = HEADER_SOURCES, cell = createHeaderCell(HEADER_SOURCES):spanMultipleColumns(viewParameters:countShownSourceColumns()) }, { label = HEADER_PRICE, cell = createHeaderCell(HEADER_PRICE):spanTwoRows() } } local subheadersInOrderUnderSources = { { label = HEADER_ABBR_ALTAR, cell = createHeaderCell(HEADER_ABBR_ALTAR) }, { label = HEADER_ABBR_CORNERSTONE, cell = createHeaderCell(HEADER_ABBR_CORNERSTONE) }, { label = HEADER_ABBR_ORDER, cell = createHeaderCell(HEADER_ABBR_ORDER) }, { label = HEADER_ABBR_RELIC, cell = createHeaderCell(HEADER_ABBR_RELIC) }, { label = HEADER_ABBR_TRADER, cell = createHeaderCell(HEADER_ABBR_TRADER) } } -- If there are subheaders, populate two rows then add them to the main htmlTable if viewParameters:isShowingSources() then local headerRow = mw.html.create("tr") headerRow:newline() addAllCellsThatShouldBeShowing(headerRow, headersInOrderWithSources, viewParameters) local subheaderRow = mw.html.create("tr") subheaderRow:newline() addAllCellsThatShouldBeShowing(subheaderRow, subheadersInOrderUnderSources, viewParameters) htmlTable:node(headerRow):newline() htmlTable:node(subheaderRow):newline() return headerRow, subheaderRow else -- No subheaders, just populate one row then add it to the main htmlTable. local headerRow = mw.html.create("tr") headerRow:newline() addAllCellsThatShouldBeShowing(headerRow, headersInOrderWithoutSources, viewParameters) htmlTable:node(headerRow):newline() return headerRow end end ---createDataCell ---@param label string the label to put in the cell ---@return table a new html table data cell local function createDataCell(label) local cell = mw.html.create("td") cell:wikitext(label) return cell end ---addDataRow ---@param data table a table of data configured with keys to match the labels in cellsInOrder in this method ---@param viewParameters table a ViewParameters initialized with its constructor ---@return table the data row added, sometimes a second sub-header row local function addDataRow(data, viewParameters) -- Configure the table; we'll figure out which to actually show in a moment. Separating the setup from the logic makes this significantly easier to read and understand. These cannot be key-value pairs, like [label] = cell, because we have to use numerical indexes to preserve their order. local cellsInOrderWithoutSources = { { label = HEADER_ID, cell = createDataCell(data[HEADER_ID] or "—") }, { label = HEADER_NAME, cell = createDataCell(data[HEADER_NAME] or "—") }, { label = HEADER_RARITY, cell = createDataCell(data[HEADER_RARITY] or "—") }, { label = HEADER_DESCRIPTION, cell = createDataCell(data[HEADER_DESCRIPTION] or "—") }, { label = HEADER_PRICE, cell = createDataCell(data[HEADER_PRICE] or "—") } } local cellsInOrderWithSources = { { label = HEADER_ID, cell = createDataCell(data[HEADER_ID] or "—") }, { label = HEADER_NAME, cell = createDataCell(data[HEADER_NAME] or "—") }, { label = HEADER_RARITY, cell = createDataCell(data[HEADER_RARITY] or "—") }, { label = HEADER_DESCRIPTION, cell = createDataCell(data[HEADER_DESCRIPTION] or "—") }, { label = HEADER_ABBR_ALTAR, cell = createDataCell(data[HEADER_ABBR_ALTAR] and HEADER_ABBR_ALTAR or RED_X) }, { label = HEADER_ABBR_CORNERSTONE, cell = createDataCell(data[HEADER_ABBR_CORNERSTONE] and HEADER_ABBR_CORNERSTONE or RED_X) }, { label = HEADER_ABBR_ORDER, cell = createDataCell(data[HEADER_ABBR_ORDER] and HEADER_ABBR_ORDER or RED_X) }, { label = HEADER_ABBR_RELIC, cell = createDataCell(data[HEADER_ABBR_RELIC] and HEADER_ABBR_RELIC or RED_X) }, { label = HEADER_ABBR_TRADER, cell = createDataCell(data[HEADER_ABBR_TRADER] and HEADER_ABBR_TRADER or RED_X) }, { label = HEADER_PRICE, cell = createDataCell(data[HEADER_PRICE] or "—") } } -- If skipping the sources altogether overrides individual column visibility. if viewParameters:isShowingSources() then local dataRow = mw.html.create("tr") dataRow:newline() addAllCellsThatShouldBeShowing(dataRow, cellsInOrderWithSources, viewParameters) htmlTable:node(dataRow):newline() return dataRow else local dataRow = mw.html.create("tr") dataRow:newline() addAllCellsThatShouldBeShowing(dataRow, cellsInOrderWithoutSources, viewParameters) htmlTable:node(dataRow):newline() return dataRow end end ---validateStringData ---@param stringData string a string to display ---@return string the same string, or nil if it's empty local function validateStringData(stringData) if "" == stringData or " " == stringData then return nil else return stringData end end ---validateBooleanData ---@param booleanData boolean a boolean to display ---@return boolean the same boolean, or false if it's anything besides a true value local function validateBooleanData(booleanData) if true == booleanData or "true" == booleanData then return true else return nil end end ---validateNumberData ---@param numberData number a number to display ---@return number the same number, or nil if it was invalid or 0 local function validateNumberData(numberData) if type(numberData) ~= "number" then return tonumber(numberData) else if 0 > numberData then return nil else return numberData end end end local function createPerkLink(id) return mw.getCurrentFrame():expandTemplate{ title = "pl", args = { ["id"] = id, ["iconsize"] = PERK_LINK_ICON_SIZE } } end --endregion --region Public methods ---startTable ---@param caption string the desired caption ---@param viewParameters table a ViewParameters initialized with its constructor ---@return table an html node, the htmlTable member variable function PerksView.startTable(caption, viewParameters) openTable(caption) addHeaderRow(viewParameters) return htmlTable end ---addRow ---@param id string the ID of the perk ---@param _ string the name of the perk is not actually used, but asked for because the Controller doesn't need to know ---@param rarity string the rarity of the perk expressed as a string ---@param description string the description of the perk ---@param isSourceAltar boolean whether the perk is acquired at the altar ---@param isSourceCornerstone boolean whether the perk is acquired as a cornerstone ---@param isSourceOrder boolean whether the perk is acquired from orders ---@param isSourceRelic boolean whether the perk is acquired from relics ---@param isSourceTrader boolean whether the perk is acquired from traders ---@param price number the purchase price at a trader ---@param viewParameters table a ViewParameters initialized with its constructor ---@return table an html node, the htmlTable member variable function PerksView.addRow(id, _, rarity, description, isSourceAltar, isSourceCornerstone, isSourceOrder, isSourceRelic, isSourceTrader, price, viewParameters) local data = { [HEADER_ID] = validateStringData(id), [HEADER_NAME] = createPerkLink(validateStringData(id)), [HEADER_RARITY] = validateStringData(rarity), [HEADER_DESCRIPTION] = validateStringData(description), [HEADER_ABBR_ALTAR] = validateBooleanData(isSourceAltar), [HEADER_ABBR_CORNERSTONE] = validateBooleanData(isSourceCornerstone), [HEADER_ABBR_ORDER] = validateBooleanData(isSourceOrder), [HEADER_ABBR_RELIC] = validateBooleanData(isSourceRelic), [HEADER_ABBR_TRADER] = validateBooleanData(isSourceTrader), [HEADER_PRICE] = validateNumberData(price) } addDataRow(data, viewParameters) return htmlTable end ---finalize ---@return table the complete html table node, fully rendered function PerksView.finalize() return htmlTable end --endregion return PerksView