Module:Data Table/Tags: Difference between revisions

From Zelda Wiki, the Zelda encyclopedia
Jump to navigation Jump to search
(checkExists = false to fix too many expensive parser function calls on Material)
No edit summary
 
(10 intermediate revisions by 2 users not shown)
Line 39: Line 39:
local format = tagArgs[2]
local format = tagArgs[2]
local cellSize = 0
local cellSize = 0
local sortValue
local sortValue
values = utilsTable.map(values, function(value)
local text
local value, info = utilsMarkup.separateMarkup(value)
if #values == 1 then
if #values == 1 then
local value, info = utilsMarkup.separateMarkup(values[1])
sortValue = value:gsub(",", "")
sortValue = value:gsub(",", "")
if value == "" then
text = info
end
end
cellSize = math.max(cellSize, value:len())
end
local args = {value, format}
if not text then
if hasGameParam then
values = utilsTable.map(values, function(value)
table.insert(args, 1, amountGame)
local value, info = utilsMarkup.separateMarkup(value)
end
if #values == 1 then
local text = frame:expandTemplate({
sortValue = value:gsub(",", "")
title = templateName,
end
args = args,
cellSize = math.max(cellSize, value:len())
})
local args = {value, format}
return text..info
if hasGameParam then
end)
table.insert(args, 1, amountGame)
local valuesList = list(values, "plain")
end
local text = frame:expandTemplate({
title = templateName,
args = args,
})
return text..info
end)
text = list(values, "plain")
end
return {
return {
text = valuesList,
text = text,
size = cell:len(),
size = cell:len(),
sortValue = sortValue
sortValue = sortValue
Line 66: Line 77:
end
end


local function terms(tagName, plural)
local function links(tagName)
return {
return {
formatter = function(cell, tableArgs, tagArgs)
formatter = function(cell, tableArgs, tagArgs)
Line 80: Line 91:
local entries = utilsTable.map(pages, function(page)
local entries = utilsTable.map(pages, function(page)
return GalleryList.entry(game, "", page, {
-- We use GalleryList here because we have to be aware of any GalleryList syntax that could be present in the cell,
plural = plural,
-- which may be the case if the [Image] tag is also applied to the column
link = true
return GalleryList.parseEntry(page, game, "", {
plural = tagName == "Plural" or tagName == "PluralList",
link = true,
useTerms = tagName ~= "LinkList",
})
})
end)
end)
Line 92: Line 106:
end
end
local isBulletList = tagName == "TermList" or tagName == "PluralList"
local isBulletList = tagName == "TermList" or tagName == "PluralList" or tagName == "LinkList"
local links = utilsTable.map(entries, "link")
local links = utilsTable.map(entries, function(entry)
local list = list(links, isBulletList and "*" or "plain")
return entry.link..entry.info
end)
local text
if #entries == 1 and entries[1].link == "[[]]" then
text = entries[1].info
else
text = list(links, isBulletList and "*" or "plain")
end
local sortValue
local sortValue
Line 101: Line 123:
end
end
return {
return {
text = list,
text = text,
sortValue = sortValue,
sortValue = sortValue,
size = cellSize
size = cellSize
Line 118: Line 140:
local spanningCell = spanningCellsByColumn[columnIndex]
local spanningCell = spanningCellsByColumn[columnIndex]
local spanCount = spanCountsByColumn[columnIndex]
local spanCount = spanCountsByColumn[columnIndex]
local na = string.find(tostring(cell.content), "Not Applicable")
if not spanningCell then
if not spanningCell then
spanningCell = cell
spanningCell = cell
spanCount = 1
spanCount = 1
elseif tostring(cell.content) == tostring(spanningCell.content) then
elseif tostring(cell.content) == tostring(spanningCell.content) and not na then
cell.skip = true
cell.skip = true
spanCount = spanCount + 1
spanCount = spanCount + 1
Line 203: Line 226:
local subject, info = utilsMarkup.separateMarkup(item)
local subject, info = utilsMarkup.separateMarkup(item)
cellSize = math.max(cellSize, subject:len())
cellSize = math.max(cellSize, subject:len())
if #amounts == 1 and subject == "" then
text = info
end
end
end
Line 269: Line 295:
cell = string.gsub(cell, "%[Player Name%]", "Link")
cell = string.gsub(cell, "%[Player Name%]", "Link")
local fileType = tagArgs[1] or Franchise.graphics(tableArgs.game) == "2D" and "Sprite" or "Icon"
local fileType = tagArgs[1] or Franchise.graphics(tableArgs.game) == "2D" and "Sprite" or "Icon"
local entry = GalleryList.entry(tableArgs.game, fileType, cell, {
local entry = GalleryList.parseEntry(cell, tableArgs.game, fileType, {
useTerms = false,
useTerms = false,
})
})
Line 283: Line 309:
end,
end,
},
},
["Link"] = {
formatter = function(cell, tableArgs, tagArgs)
local cellSize = cell:len()
-- We use GalleryList here because we have to be aware of any GalleryList syntax that could be present in the cell,
-- which may be the case if the [Image] tag is also applied to the column
-- We have to escape the brackets in [Player Name] so that GalleryList doesn't parse it as a variant
local entry = GalleryList.parseEntry(cell, "", "", {
useTerms = false
})
local text
if entry.subject ~= "" then
text = "[["..entry.subject.."]]"..entry.info
else
text = entry.info
end
return {
text = text,
sortValue = entry.subject
}
end,
},
["LinkList"] = links("LinkList"),
["List"] = {
["List"] = {
formatter = function(cell, tableArgs, tagArgs)
formatter = function(cell, tableArgs, tagArgs)
Line 301: Line 351:
formatter = function(cell, tableArgs, tagArgs)
formatter = function(cell, tableArgs, tagArgs)
local cellSize = cell:len()
local cellSize = cell:len()
local text = string.gsub(cell, "%[Player Name%]", playerName())
-- We use GalleryList here because we have to be aware of any GalleryList syntax that could be present in the cell,
local text = GalleryList.parseVariant(text)
-- which may be the case if the [Image] tag is also applied to the column
-- We have to escape the brackets in [Player Name] so that GalleryList doesn't parse it as a variant
local text = string.gsub(cell, "%[Player Name%]", "{Player Name}")
local entry = GalleryList.parseEntry(text, "", "", {
useTerms = false
})
local text = string.gsub(entry.subject, "{Player Name}", playerName())..entry.info
return {
return {
text = text,
text = text,
sortValue = text,
}
}
end,
end,
},
},
["Plural"] = terms("Plural", true),
["Plural"] = links("Plural"),
["PluralList"] = terms("PluralList", true),
["PluralList"] = links("PluralList"),
["Rupees"] = value("Rupee", true),
["Rupees"] = value("Rupee", true),
["SortValue"] = {
["SortValue"] = {
Line 340: Line 397:
end,
end,
},
},
["Term"] = terms("Term"),
["Term"] = links("Term"),
["Terms"] = terms("Terms"),
["Terms"] = links("Terms"),
["TermList"] = terms("TermList"),
["TermList"] = links("TermList"),
["Transcript"] = {
["Transcript"] = {
formatter = function(cell, tableArgs, tagArgs)
formatter = function(cell, tableArgs, tagArgs)
Line 358: Line 415:
["ID"] = {
["ID"] = {
formatter = function(cell, tableArgs, tagArgs)
formatter = function(cell, tableArgs, tagArgs)
cell.id = string.gsub(cell.raw, "%[Player Name%]", "Link")
local id = string.gsub(cell.raw, "%[Player Name%]", "Link")
id = utilsMarkup.separateMarkup(id)
cell.id = id
cell.content:addClass("data-table__cell-content--id")
end,
end,
},
},

Latest revision as of 12:42, 6 November 2023


local File = require("Module:File")
local Franchise = require("Module:Franchise")
local GalleryList = require("Module:Gallery List")
local Sequences = require("Module:Sequences")
local Term = require("Module:Term")
local TermList = require("Module:Term List")
local utilsMarkup = require("Module:UtilsMarkup")
local utilsString = require("Module:UtilsString")
local utilsTable = require("Module:UtilsTable")

local frame = mw.getCurrentFrame()

local playerNameOutput
local function playerName()
	return playerNameOutput or frame:expandTemplate({
		title = "Player Name"
	})
end

local function list(items, listType)
	if listType == "*" then
		return utilsMarkup.bulletList(items)
	elseif listType == "#" then
		return utilsMarkup.numberList(items)
	elseif listType == "plain" then
		return utilsMarkup.list(items)
	elseif #items > 1 then
		return utilsMarkup.list(items)
	else
		return items[1]
	end
end

local function value(templateName, hasGameParam)
	return {
		formatter = function(cell, tableArgs, tagArgs)
			local values = utilsString.split(cell, '%s*,[%D+|%s*]')
			local amountGame = tableArgs.game or tagArgs[1]
			local format = tagArgs[2]
			local cellSize = 0
			
			local sortValue
			local text
			if #values == 1 then
				local value, info = utilsMarkup.separateMarkup(values[1])
				sortValue = value:gsub(",", "")
				if value == "" then
					text = info
				end
			end
			if not text then
				values = utilsTable.map(values, function(value)
					local value, info = utilsMarkup.separateMarkup(value)
					if #values == 1 then
						sortValue = value:gsub(",", "")
					end
					cellSize = math.max(cellSize, value:len())
					local args = {value, format}
					if hasGameParam then
						table.insert(args, 1, amountGame)
					end
					local text = frame:expandTemplate({
						title = templateName,
						args = args,
					})
					return text..info
				end)
				text = list(values, "plain")
			end
			return {
				text = text,
				size = cell:len(),
				sortValue = sortValue
			}
		end
	}
end

local function links(tagName)
	return {
		formatter = function(cell, tableArgs, tagArgs)
			local game = tagArgs[1] or tableArgs.game
		
			cell = string.gsub(cell, "%[Player Name%]", "Link")
			local pages
			if tagName == "Term" or tagName == "Plural" then
				pages = {cell}
			else
				pages = utilsString.split(cell)
			end
		
			local entries = utilsTable.map(pages, function(page)
				-- We use GalleryList here because we have to be aware of any GalleryList syntax that could be present in the cell, 
				-- which may be the case if the [Image] tag is also applied to the column
				return GalleryList.parseEntry(page, game, "", {
					plural = tagName == "Plural" or tagName == "PluralList",
					link = true,
					useTerms = tagName ~= "LinkList",
				})
			end)
	
			local cellSize = 0
			for i, entry in ipairs(entries) do
				local term = entry.term or ""
				cellSize = math.max(term:len(), cellSize)
			end
		
			local isBulletList = tagName == "TermList" or tagName == "PluralList" or tagName == "LinkList"
			local links = utilsTable.map(entries, function(entry)
				return entry.link..entry.info
			end)
			
			local text
			if #entries == 1 and entries[1].link == "[[]]" then
				text = entries[1].info
			else
				text = list(links, isBulletList and "*" or "plain")
			end
		
			local sortValue
			if #entries == 1 then
				sortValue = entries[1].term
			end
			return {
				text = text,
				sortValue = sortValue,
				size = cellSize
			}
		end
	}
end

local spanningCellsByColumn = {}
local spanCountsByColumn = {}
function computeRowspan(cell)
	local columnIndex = cell.columnIndex
	if not columnIndex then
		return
	end
	local spanningCell = spanningCellsByColumn[columnIndex]
	local spanCount = spanCountsByColumn[columnIndex]
	local na = string.find(tostring(cell.content), "Not Applicable")
	if not spanningCell then
		spanningCell = cell
		spanCount = 1
	elseif tostring(cell.content) == tostring(spanningCell.content) and not na then
		cell.skip = true
		spanCount = spanCount + 1
	else
		spanningCell.rowspan = spanCount
		spanningCell = cell
		spanCount = 1
	end
	if cell.isLastRow then
		spanningCell.rowspan = spanCount
	end
	spanCountsByColumn[columnIndex] = spanCount
	spanningCellsByColumn[columnIndex] = spanningCell
end

-- So that the template is evaluated at most once per page
local NA
function notApplicable()
	NA = NA or mw.getCurrentFrame():expandTemplate({ title = "NA" })
	return NA
end

local p = {
	-- formatter (required): a function that returns an object with the following properties:
	-- - text (required): the text to display in the cell
	-- - size (optional): an estimation of the cell's width in characters
	-- - sortValue (optional): a column sort value — column is unsortable if false, sorted by its content if nil

	-- noCopy (optional): if set to true, the tag will not be automatically carried over to copies of the table 
	contentTags = {
		[""] = {
			formatter = function(cell) -- default: no tags
				local text = string.gsub(cell, "%[Player Name%]", playerName())
				local sortValue
				local markupStripped = string.gsub(text, "'", "") -- strip any bold or italics formatting
				local leadingNumber = string.match(markupStripped, "^(%d[%d,]*)")
				if leadingNumber then
					leadingNumber = string.gsub(leadingNumber, ",", "")
					leadingNumber = tonumber(leadingNumber)
					sortValue = leadingNumber
				end
				return {
					text = cell,
					size = cell:len(),
					sortValue = sortValue,
				}
			end,
		},
		["EmptyCell"] = {
			formatter = function(cell) -- special case: empty cell
				return {
					text = " ",
					sortValue = "",
					size = 0,
				}
			end,
		},
		["NotApplicable"] = {
			formatter = function(cell) -- special case: cell starts with N/A
				local text, info = utilsMarkup.separateMarkup(cell)
				text = text:gsub("N/A", notApplicable())
				return {
					text = text..info,
					sortValue = text,
					size = cell:len(),
				}
			end,
		},

		["Amounts"] = {
			formatter = function(cell, tableArgs, tagArgs)
				local text = frame:expandTemplate({
					title = "Amounts",
					args = {tableArgs.game, cell}
				})
	
				local cellSize = 0
				local amounts = utilsString.split(cell, '%s*,[%D+|%s*]')
				for i, amount in ipairs(amounts) do
					local item = string.gsub(amount, "$[%d,]+ ", "")
					local subject, info = utilsMarkup.separateMarkup(item)
					cellSize = math.max(cellSize, subject:len())
					if #amounts == 1 and subject == "" then
						text = info
					end
				end
	
				return {
					text = text,
					size = cellSize,
					sortValue = false,
				}
			end,
		},
		["Code"] = {
			formatter = function(cell, tableArgs, tagArgs)
				local value, info = utilsMarkup.separateMarkup(cell)
				return {
					text = "<code>"..value.."</code>"..info,
					size = value:len(),
				}
			end,
		},
		["Defense"] = value("Defense", true),
		["Description"] = {
			formatter = function(cell, tableArgs, tagArgs)
				local text = string.gsub(cell, "%[Player Name%]", playerName())
				text = "\n"..text.."\n" -- bullet lists don't work without the newlines
				return {
					text = text,
					size = cell:len(),
					sortValue = false,
				}
			end,
		},
		["Effect"] = value("Effect", false),
		["HeartAmount"] = {
			formatter = function(cell, tableArgs, tagArgs)
				local text = frame:expandTemplate({
					title = "HeartAmount",
					args = {cell, "true"}
				})
				return {
					text = text,
					size = 12,
					sortValue = cell
				}
			end,
		},
		["IconList"] = {
			formatter = function(cell, tableArgs, tagArgs)
				local cellSize = 0
				local listItems = utilsString.split(cell)
				for i, listItem in ipairs(listItems) do
					cellSize = math.max(listItem:len(), cellSize)
				end
				local iconList = frame:expandTemplate({
					title = "Icon List",
					args = {tableArgs.game, cell}
				})
				return {
					text = iconList,
					size = cellSize,
					sortValue = false,
				}
			end,
		},
		["Image"] = {
			formatter = function(cell, tableArgs, tagArgs)
				cell = string.gsub(cell, "%[Player Name%]", "Link")
				local fileType = tagArgs[1] or Franchise.graphics(tableArgs.game) == "2D" and "Sprite" or "Icon"
				local entry = GalleryList.parseEntry(cell, tableArgs.game, fileType, {
					useTerms = false,
				})
				local image = File.image(entry.file, {
					size = tagArgs[2] or "64x64px",
					checkExists = false,
				})
				return {
					text = image,
					size = 20,
					sortValue = false,
				}
			end,
		},
		["Link"] = {
			formatter = function(cell, tableArgs, tagArgs)
				local cellSize = cell:len()
				-- We use GalleryList here because we have to be aware of any GalleryList syntax that could be present in the cell, 
				-- which may be the case if the [Image] tag is also applied to the column
				-- We have to escape the brackets in [Player Name] so that GalleryList doesn't parse it as a variant
				local entry = GalleryList.parseEntry(cell, "", "", {
					useTerms = false
				})

				local text
				if entry.subject ~= "" then
					text = "[["..entry.subject.."]]"..entry.info
				else
					text = entry.info
				end

				return {
					text = text,
					sortValue = entry.subject
				}
			end,
		},
		["LinkList"] = links("LinkList"),
		["List"] = {
			formatter = function(cell, tableArgs, tagArgs)
				local listItems = utilsString.split(cell, '%s*,[%D+|%s*]')
				local cellSize = 0
				for i, listItem in ipairs(listItems) do
					cellSize = math.max(cellSize, listItem:len())
				end
				local list = list(listItems, tagArgs[1] or "*")
				return {
					text = list,
					sortValue = false,
				}
			end,
		},
		["Mon"] = value("Mon", false),
		["Name"] = {
			formatter = function(cell, tableArgs, tagArgs)
				local cellSize = cell:len()
				-- We use GalleryList here because we have to be aware of any GalleryList syntax that could be present in the cell, 
				-- which may be the case if the [Image] tag is also applied to the column
				-- We have to escape the brackets in [Player Name] so that GalleryList doesn't parse it as a variant
				local text = string.gsub(cell, "%[Player Name%]", "{Player Name}") 
				local entry = GalleryList.parseEntry(text, "", "", {
					useTerms = false
				})
				local text = string.gsub(entry.subject, "{Player Name}", playerName())..entry.info
				return {
					text = text,
					sortValue = text,
				}
			end,
		},
		["Plural"] = links("Plural"),
		["PluralList"] = links("PluralList"),
		["Rupees"] = value("Rupee", true),
		["SortValue"] = {
			formatter = function(cell, tableArgs, tagArgs)
				cell = string.gsub(cell, "%[Player Name%]", "Link")
				local sortValue = Sequences.sortValue(tableArgs.game, nil, cell)
				local termLink = Term.link(cell, tableArgs.game)
				return {
					size = cell:len(),
					text = termLink,
					sortValue = sortValue,
				}
			end,
		},
		["SyntaxHighlight"] = {
			formatter = function(cell, tableArgs, tagArgs)
				local text, notes = utilsMarkup.separateMarkup(cell)
				local codeBlock = frame:extensionTag({
					name = "syntaxhighlight",
					args = {
						inline = true,
						lang = tagArgs[1] or "lua"
					},
					content = text
				})
				return {
					text = codeBlock..notes,
					size = text:len(),
				}
			end,
		},
		["Term"] = links("Term"),
		["Terms"] = links("Terms"),
		["TermList"] = links("TermList"),
		["Transcript"] = {
			formatter = function(cell, tableArgs, tagArgs)
				local text = string.gsub(cell, "%[Player Name%]", playerName())
				text = "\n"..text.."\n" -- bullet lists don't work without the newlines
				return {
					text = text,
					size = cell:len(),
					sortValue = false,
				}
			end,
		},
	},
	attributeTags = {
		["ID"] = {
			formatter = function(cell, tableArgs, tagArgs)
				local id = string.gsub(cell.raw, "%[Player Name%]", "Link")
				id = utilsMarkup.separateMarkup(id)
				cell.id = id
				cell.content:addClass("data-table__cell-content--id")
			end,
		},
		["Nowrap"] = {
			formatter = function(cell, tableArgs, tagArgs)
				cell.content:addClass("data-table__cell-content--nowrap")
			end,
		},
		["Rowspan"] = {
			formatter = function(cell, tableArgs, tagArgs)
				computeRowspan(cell)
			end,
		},
		["Unsortable"] = {
			formatter = function(cell, tableArgs, tagArgs)
				cell.sortValue = false
			end,
		},
		["Width"] = {
			noCopy = true,
			formatter = function(cell, tableArgs, tagArgs)
				cell.styles = cell.styles or {}
				cell.styles["width"] = tagArgs[1]
			end,
		},
	}
}

return p