Jump to content
Main menu
Main menu
move to sidebar
hide
Navigation
Main page
Recent changes
Random page
MediaWiki help
Creopedia
Search
Search
Appearance
Log in
Personal tools
Log in
View source for Module:TableLua
Module
Discussion
English
Read
View source
View history
Tools
Tools
move to sidebar
hide
Actions
Read
View source
View history
General
What links here
Related changes
Special pages
Page information
Appearance
move to sidebar
hide
←
Module:TableLua
require( 'strict' ) --- Simplified Lua interface for building a table. --- Using similar approach to the Codex Table component. --- @class TableProps --- @field caption string --- @field hideCaption? boolean @default false --- @field columns? TableColumn[] @default {} --- @field data? TableRow[] @default {} --- @field sort? TableSort @default {} --- @field class? string @default '' --- @field emptyState? string @default 'No data' --- @class TableColumn --- @field id string --- @field label? string --- @field textAlign? 'start'|'center'|'end'|'number' @default 'start' --- @field width? string --- @field minWidth? string --- @field allowSort? boolean --- A cell that sorts on something other than what it shows. --- --- A sortable column is otherwise ordered by the text of its cells, which is --- wrong wherever the text is a label for a scale: a rarity column sorted on --- its badges runs Ascendant, Common, Mega Prime. Such a cell states the value --- it should be compared on, which both this module's own sort and the --- browser's read in preference to the cell's text. --- --- @class TableCellProps --- @field value string --- @field sortValue? string|number --- @alias TableCell string|TableCellProps --- @alias TableRow TableCell[] --- @alias TableSort table<string, TableSortOption> --- @alias TableSortOption 'none'|'asc'|'desc' local p = {} ---@param props TableProps ---@return TableProps local function normalizeProps( props ) props.columns = props.columns or {} props.data = props.data or {} props.sort = props.sort or {} props.emptyState = props.emptyState or 'There is no data available' return props end --- @return TableRow[] local function getEmptyStateData( emptyState ) return { { emptyState } } end ---@param root mw.html ---@param props TableProps local function renderCaption( root, props ) if not props.hideCaption then root :tag( 'caption' ) :wikitext( props.caption ) end end ---@param root mw.html ---@param props TableProps local function renderHeader( root, props ) local headerRow = root:tag( 'tr' ) for _, column in ipairs( props.columns ) do local th = headerRow:tag( 'th' ) th:attr( 'scope', 'col' ) if column.textAlign then th:addClass( 't-table__cell--align-' .. column.textAlign ) end if column.minWidth then th:css( 'min-width', column.minWidth ) end if column.width then th:css( 'width', column.width ) end if column.allowSort == false then th:addClass( 'unsortable' ) end th:wikitext( column.label or '' ) end end ---@param root mw.html ---@param props TableProps local function renderBody( root, props ) for _, row in ipairs( props.data ) do local tr = root:tag( 'tr' ) for i, cell in ipairs( row ) do local td = tr:tag( 'td' ) local column = props.columns[i] if column and column.textAlign then td:addClass( 't-table__cell--align-' .. column.textAlign ) end if type( cell ) == 'table' then if cell.sortValue ~= nil then td:attr( 'data-sort-value', cell.sortValue ) end td:wikitext( cell.value ) else td:wikitext( cell ) end end end end --- What a cell is compared on. --- --- @param cell TableCell --- @return any local function getSortable( cell ) if type( cell ) ~= 'table' then return cell end if cell.sortValue ~= nil then return cell.sortValue end return cell.value end --- Reduce a cell to the text it will end up displaying, so that sorting --- compares content rather than markup. --- --- Cells built from other modules carry parser strip markers: opaque --- \127-delimited placeholders standing in for extension tags such as the --- templatestyles an icon link emits. Left in place they sort as their --- sequence number, which silently orders the column by insertion instead. --- --- @param value string --- @return string local function cleanValue( value ) return ( value :gsub( '\127[^\127]*\127', '' ) :gsub( '<[^>]+>', '' ) ) end --- Sort the data according to TableSort --- MW does not sort tables by default, so we need to sort them manually. --- ---@param props TableProps local function sortData( props ) local colMap = {} for i, column in ipairs( props.columns ) do colMap[column.id] = i end local sortKeys = {} for k in pairs( props.sort ) do table.insert( sortKeys, k ) end table.sort( sortKeys ) local function compare( valA, valB ) if valA == valB then return 0 end if valA == nil then return -1 end if valB == nil then return 1 end local typeA, typeB = type( valA ), type( valB ) if typeA == 'number' and typeB == 'number' then return valA < valB and -1 or 1 end if typeA == 'string' and typeB == 'string' then -- Attempt to sort numerically if the string contains a number, -- even if it's wrapped in HTML. local cleanA = cleanValue( valA ) local cleanB = cleanValue( valB ) -- Try to extract numbers for sorting. local matchA = cleanA:match( '(-?%d+%.?%d*)' ) local matchB = cleanB:match( '(-?%d+%.?%d*)' ) if matchA and matchB then local numA = tonumber( matchA ) local numB = tonumber( matchB ) -- Only use numeric sort if both are valid numbers and not equal. if numA and numB and numA ~= numB then return numA < numB and -1 or 1 end end -- Fallback to alphanumeric sort on cleaned text if cleanA == cleanB then return 0 end return cleanA < cleanB and -1 or 1 end if typeA ~= typeB then valA, valB = tostring( valA ), tostring( valB ) end return valA < valB and -1 or 1 end table.sort( props.data, function ( a, b ) if a == b then return false end if b == nil then return true end if a == nil then return false end for _, colId in ipairs( sortKeys ) do local order = props.sort[colId] if order and order ~= 'none' then local colIndex = colMap[colId] if colIndex then local result = compare( getSortable( a[colIndex] ), getSortable( b[colIndex] ) ) if result ~= 0 then return (order == 'asc' and result == -1) or (order == 'desc' and result == 1) end end end end return false end ) end --- @param props TableProps --- @return string function p.render( props ) props = normalizeProps( props ) if props.data == {} then props.data = getEmptyStateData( props.emptyState ) end local root = mw.html.create( 'table' ) root :addClass( 't-table' ) :addClass( 'wikitable' ) :addClass( props.class ) if next( props.sort ) then root:addClass( 'sortable' ) sortData( props ) end renderCaption( root, props ) renderHeader( root, props ) renderBody( root, props ) return mw.getCurrentFrame():extensionTag { name = 'templatestyles', args = { src = 'Module:TableLua/styles.css' } } .. tostring( root ) end return p
Templates used on this page:
Template:Documentation
(
view source
)
Module:TableLua/doc
(
view source
)
Return to
Module:TableLua
.