Module:DatatableBuilder

From Sekaipedia

local yesno = require('Module:Yesno')

local DatatableBuilder = {}
DatatableBuilder.__index = DatatableBuilder
DatatableBuilder.__tostring = DatatableBuilder.tostring

function DatatableBuilder.new()
	local obj = setmetatable({
		caption = nil,
		headers = {},
		columns = {},
		columnOrder = {},
		tbl = nil,
		data = {},
	}, DatatableBuilder)
	
	return obj
end

function DatatableBuilder:setCaption(caption)
	if caption == nil or caption == '' then
		error('Caption must not be nil or empty')
	end
	
	self.caption = caption
	
	return self
end

function DatatableBuilder:setColumnVisibility(columnName, visibility)
	if columnName == nil or columnName == '' then
		error('Column name must not be nil or empty')
	end
	if self.columns[columnName] == nil then
		error('Column must have an associated column in the table')
	end
	
	self.columns[columnName].visible = visibility
	
	return self
end

function DatatableBuilder:setHeaders(headers)
	for i,header in ipairs(headers) do
		if header == nil or header == '' then
			error('Header must not be nil or empty')
		end
		if self.columns[header] == nil then
			error('Header must have an associated column')
		end
		
		table.insert(self.headers, header)
	end
	
	return self
end

function DatatableBuilder:setColumns(...)
	for _, col in ipairs(...) do
		local columnName = col.name
		
		if columnName == nil or columnName == '' then
			error('Column name must not be nil or empty.')
		end
		if self.columns[columnName] then
			error('Columns cannot have duplicate names.')
		end
		
		local visible = yesno(col.visible, true)
		if visible == nil then
			visible = true
		end
		
		self.columns[columnName] = {
			['type'] = type(col.func or col.fn),
			header = col.header,
			dataFields = col.dataFields,
			fn = col.func or col.fn,
			default = col.default,
			css = col.css,
			sortable = col.sortable,
			visible = visible
		}
		
		table.insert(self.columnOrder, columnName)
	end
	
	return self
end

function DatatableBuilder:setData(data)
	self.data = data
	
	return self
end

function DatatableBuilder:getContent(columnName, rowValues)
	if columnName == nil or columnName == '' then
		error('Column must not be nil or empty')
	end
	
	local content = nil
	local currentCol = self.columns[columnName]
	
	if currentCol == nil then
		error(string.format('No such column with name: %s', columnName))
	end
	
	local rawCellValues = {}
	for _, field in ipairs(currentCol.dataFields) do
		table.insert(rawCellValues, rowValues[field])
	end
	
	if currentCol['type'] == 'function' then
		content = currentCol.fn(unpack(rawCellValues))
	else
		content = table.concat(rawCellValues, ' ')
	end
	
	if content == nil or content == '' then
		return currentCol.default or '?'
	end
	return content
end

function DatatableBuilder:getCSS(columnName)
	local currentCol = self.columns[columnName]
	
	return currentCol.css or {}
end

function DatatableBuilder:renderHeader()
	local header = mw.html.create('tr')
	for _, name in ipairs(self.columnOrder) do
		local currentColumn = self.columns[name]
		
		if currentColumn.visible == true then
			local cell = header:tag('th')
				:wikitext(currentColumn.header)
		
			if currentColumn.sortable == false then
				cell:addClass('unsortable')
			end
		end
	end
	
	return header
end

function DatatableBuilder:renderRow(val)
	local row = mw.html.create('tr')
			
	for _, name in ipairs(self.columnOrder) do
		if self.columns[name].visible == true then
			row:tag('td')
				:css(self:getCSS(name))
				:wikitext(self:getContent(name, val))
				:done()
		end
	end
	
	return row
end

function DatatableBuilder:generateTable()
	self.tbl = mw.html.create('table')
		:addClass('wikitable')
		:addClass('sortable')
	
	if self.caption then
		local caption = mw.html.create('caption')
			:wikitext(self.caption)
			
		self.tbl:node(caption)
	end
	
	local header = self:renderHeader()
	self.tbl:node(header)
	
	if #self.data > 0 then
		for _, val in ipairs(self.data) do
			local row = self:renderRow(val)
			self.tbl:node(row)
		end
	else
		self.tbl:tag('tr')
			:tag('td')
				:attr('colspan', #self.columnOrder)
				:css({
					['text-align'] = 'center'
				})
				:wikitext("''No data''")
				:done()
			:done()
		:done()
	end

end

function DatatableBuilder:tostring()
	if self.tbl == nil then
		self:generateTable()
	end
	
	return tostring(self.tbl)
end

return DatatableBuilder
Cookies help us deliver our services. By using our services, you agree to our use of cookies.