Module:Data Table

local p = {} local h = {}

local Franchise = require("Module:Franchise") local Sequences = require("Module:Sequences") local Term = require("Module:Term") local TermList = require("Module:Term List") local utilsArg = require("Module:UtilsArg") local utilsLayout = require("Module:UtilsLayout") local utilsMarkup = require("Module:UtilsMarkup") local utilsString = require("Module:UtilsString") local utilsTable = require("Module:UtilsTable")

local CATEGORY_INVALID_ARGS = require("Module:Constants/category/invalidArgs")

function p.Main(frame) local args, err = utilsArg.parse(frame:getParent.args, p.Templates["Data Table"]) local categories = err and err.categoryText or "" local columnHeaders, columnTags = h.extractColumnTags(args.columns) local tableId = args.storeAs and utilsString.kebabCase(args.storeAs) local unsortableColumns = {} local dataRows = {} local currentRow = { cells = {} }	local columnIndex = 1 for i, cell in ipairs(args.cells) do		if cell[1] == "-" and i ~= 1 then currentRow.id = tableId and tableId.."-"..(#dataRows+1) table.insert(dataRows, currentRow) currentRow = { cells = {} }			columnIndex = 1 elseif cell[1] ~= "-" then local cell, sortable = h.formatCell(args.game, columnTags[columnIndex], cell) table.insert(currentRow.cells, cell) if not sortable then unsortableColumns[columnIndex] = true end columnIndex = columnIndex + 1 end end currentRow.id = tableId and tableId.."-"..(#dataRows+1) table.insert(dataRows, currentRow) local sortableColumns = {} for i = 1, #columnHeaders do		if not unsortableColumns[i] then table.insert(sortableColumns, i)		end end

local desktopTable = h.desktopTable(columnHeaders, dataRows, sortableColumns) local mobileTable = h.mobileTable(columnHeaders, dataRows) return desktopTable..mobileTable, categories end

function h.extractColumnTags(columns) local columnHeaders = {} local columnTags = {} for i, column in ipairs(columns) do		columnHeaders[i] = string.gsub(column, "%s*%[(%w+)%]$", function(tag)			columnTags[i] = tag			return ""		end) end return columnHeaders, columnTags end

function h.formatCell(game, tag, cellData) local frame = mw.getCurrentFrame local cell = {} sortable = tag ~= nil and #cellData == 1 if tag == "Amount" or tag == "Amounts" then cell.class = "data-table__cell data-table__cell--amounts" sortable = false local amounts = utilsTable.map(cellData, function(itemAmount)			local amountStart, amountEnd, amount = string.find(itemAmount, "^(%d+)%s")			local item = string.sub(itemAmount, amountEnd+1)				return frame:expandTemplate({ title = "Item Amount", args = {game, amount, item} })			end) cell.content = h.list(amounts) elseif tag == "Rupees" then cell.class = "data-table__cell data-table__cell--amounts" if #cellData == 1 then cell.sortValue = cellData[1] end local amounts = utilsTable.map(cellData, function(amount)			return frame:expandTemplate({ title = "Rupee", args = {game, amount} })		end) cell.content = h.list(amounts) elseif tag == "SortValue" then cell.class = "data-table__cell data-table__cell--terms" cell.sortValue = Sequences.sortValue(game, nil, cellData[1]) cell.content = Term.link(cellData[1], game) if #cellData > 1 then local utilsError = require("Module:UtilsError") utilsError.warn(string.format("Tag  cannot be used on cells containing multiple values:  ", table.concat(cellData, ", "))) cell.content = cell.content.."" end elseif tag == "Term" or tag == "Terms" then cell.class = "data-table__cell data-table__cell--terms" local termLinks = TermList.termList(game, cellData, { link = true }) cell.content = h.list(termLinks) else cell.class = "data-table__cell" cell.content = cellData[1] end return cell, sortable end

function h.list(items) return #items > 1 and utilsMarkup.list(items) or items[1] end

function h.desktopTable(headerRows, dataRows, sortableColumns) local wikitable = utilsLayout.table({		sortable = sortableColumns,		headers = headerRows,		rows = dataRows,	}) local html = mw.html.create("div") :addClass("data-table data-table--desktop size-large-up") :wikitext(wikitable) return tostring(html) end

function h.mobileTable(headerRows, dataRows) local html = mw.html.create("div") :addClass("data-table data-table--mobile size-medium-down") :tag("table") :addClass("wikitable") for i, row in ipairs(dataRows) do		html:tag("tr") :tag("th") :attr("colspan", 2) :wikitext(row.cells[1].content) for j = 2, #headerRows do			html:tag("tr") :tag("th") :wikitext(headerRows[j]) :done :tag("td") :addClass(row.cells[j].class) :wikitext(row.cells[j].content) :done end end return tostring(html:allDone) end

p.Templates = { ["Data Table"] = { wip = true, format = "block", purpose = " Displays tabular data in a way that is mobile-friendly. Minimizes the amount of boilerplate wikitext that most tables require. Automatically center-aligns columns and applies templates such as, , , etc.  The table data can be stored in Cargo so that the table (or a subset of its rows) can be displayed on other relevant pages using .", boilerplate = { separateRequiredParams = false, },		paramOrder = {"storeAs", "game", "columns", "..."}, params = { storeAs = { type = "string", suggested = true, desc = "If present, the data will be stored in the DataTables Cargo table so that it can be retrieved on other pages using .", },			game = { type = "string", required = true, enum = Franchise.enum, desc = "A game code. Used to automatically apply game-based templates (e.g., , ) to table cells.", },			columns = { type = "content", required = true, desc = "Comma-separated list of column headers. One tag can be appended to each column to indicate how the template should handle data in that column. See below.", trim = true, nilIfEmpty= true, split = true, },			["..."] = {				name = "cells", placeholder = "cell", required = true, type = "content", desc = "Cell values. Type  to separate rows, as shown in the examples below.", trim = true, split = true, }		}	} }

return p