From e0dfe835fe2c190887ac5be60643b16e3ead2e32 Mon Sep 17 00:00:00 2001 From: Eetu Rantanen Date: Mon, 2 Mar 2026 10:04:15 +0200 Subject: [PATCH 01/11] table2-striping --- javascript/Main.js | 1 + javascript/commons/Table2.js | 69 +++++++++++++++++++ lua/wikis/commons/Widget/Contexts/Table2.lua | 1 - lua/wikis/commons/Widget/Table2/Row.lua | 29 +++++--- lua/wikis/commons/Widget/Table2/TableBody.lua | 68 +----------------- stylesheets/commons/Table2.scss | 10 --- 6 files changed, 89 insertions(+), 89 deletions(-) create mode 100644 javascript/commons/Table2.js diff --git a/javascript/Main.js b/javascript/Main.js index 5f5c0853d8d..e8f8ab7b52f 100644 --- a/javascript/Main.js +++ b/javascript/Main.js @@ -28,6 +28,7 @@ const jsModules = [ 'Selectall', 'Slider', 'SwitchButtons', + 'Table2', 'Tabs' ]; diff --git a/javascript/commons/Table2.js b/javascript/commons/Table2.js new file mode 100644 index 00000000000..1a909511703 --- /dev/null +++ b/javascript/commons/Table2.js @@ -0,0 +1,69 @@ +/******************************************************************************* + * Description: Handles dynamic striping for Table2 widgets, + * applying odd/even classes with rowspan grouping support. + ******************************************************************************/ + +const TABLE2_CONFIG = { + SELECTORS: { + TABLE: '.table2__table', + BODY_ROW: 'tbody tr.table2__row--body' + }, + CLASSES: { + ODD: 'table2__row--odd', + EVEN: 'table2__row--even' + } +}; + +class Table2Striper { + constructor( table ) { + this.table = table; + this.isSortable = table.classList.contains( 'sortable' ); + } + + init() { + this.restripe(); + + if ( this.isSortable ) { + this.setupSortListener(); + } + } + + setupSortListener() { + mw.loader.using( 'jquery.tablesorter' ).then( () => { + $( this.table ).on( 'sortEnd.tablesorter', () => this.restripe() ); + } ); + } + + restripe() { + const rows = this.table.querySelectorAll( TABLE2_CONFIG.SELECTORS.BODY_ROW ); + let stripe = 'even'; + let groupRemaining = 0; + + rows.forEach( ( row ) => { + if ( groupRemaining === 0 ) { + stripe = ( stripe === 'even' ) ? 'odd' : 'even'; + } + + const rowspanCount = parseInt( row.dataset.rowspanCount, 10 ) || 1; + groupRemaining = Math.max( groupRemaining, rowspanCount ); + + row.classList.remove( TABLE2_CONFIG.CLASSES.ODD, TABLE2_CONFIG.CLASSES.EVEN ); + row.classList.add( `table2__row--${ stripe }` ); + + groupRemaining--; + } ); + } +} + +class Table2Module { + init() { + const tables = document.querySelectorAll( TABLE2_CONFIG.SELECTORS.TABLE ); + + tables.forEach( ( table ) => { + new Table2Striper( table ).init(); + } ); + } +} + +liquipedia.table2 = new Table2Module(); +liquipedia.core.modules.push( 'table2' ); diff --git a/lua/wikis/commons/Widget/Contexts/Table2.lua b/lua/wikis/commons/Widget/Contexts/Table2.lua index f4a63f1535b..22489f96f6f 100644 --- a/lua/wikis/commons/Widget/Contexts/Table2.lua +++ b/lua/wikis/commons/Widget/Contexts/Table2.lua @@ -11,7 +11,6 @@ local Class = Lua.import('Module:Class') local Context = Lua.import('Module:Widget/Context') return { - BodyStripe = Class.new(Context), ColumnContext = Class.new(Context), HeaderRowKind = Class.new(Context), Section = Class.new(Context), diff --git a/lua/wikis/commons/Widget/Table2/Row.lua b/lua/wikis/commons/Widget/Table2/Row.lua index d3521447da8..d8b93974e51 100644 --- a/lua/wikis/commons/Widget/Table2/Row.lua +++ b/lua/wikis/commons/Widget/Table2/Row.lua @@ -32,12 +32,24 @@ local HtmlWidgets = Lua.import('Module:Widget/Html/All') ---@field props Table2RowProps local Table2Row = Class.new(Widget) +---@param rowChildren (Widget|Html|string|number|nil)[] +---@return integer +local function getMaxRowspan(rowChildren) + return Array.reduce(rowChildren, function(maxRowspan, child) + if Class.instanceOf(child, Table2Cell) or Class.instanceOf(child, Table2CellHeader) then + local cellChild = child --[[@as Table2Cell|Table2CellHeader]] + local rowspan = MathUtil.toInteger(cellChild.props.rowspan) or 1 + return math.max(maxRowspan, math.max(rowspan, 1)) + end + return maxRowspan + end, 1) +end + ---@return Widget function Table2Row:render() local props = self.props local section = props.section or self:useContext(Table2Contexts.Section) local headerRowKind = self:useContext(Table2Contexts.HeaderRowKind) - local bodyStripe = self:useContext(Table2Contexts.BodyStripe) local sectionClass = 'table2__row--body' if section == 'head' or section == 'subhead' then @@ -53,15 +65,6 @@ function Table2Row:render() end end - local stripeClass - if section == 'body' then - if bodyStripe == 'odd' then - stripeClass = 'table2__row--odd' - elseif bodyStripe == 'even' then - stripeClass = 'table2__row--even' - end - end - local highlightClass if section == 'body' and Logic.readBool(props.highlighted) then highlightClass = 'table2__row--highlighted' @@ -109,10 +112,14 @@ function Table2Row:render() end return child end) + local attributes = props.attributes or {} + if section == 'body' then + local maxRowspan = getMaxRowspan(children) + attributes['data-rowspan-count'] = maxRowspan end return HtmlWidgets.Tr{ - classes = WidgetUtil.collect(sectionClass, kindClass, stripeClass, highlightClass, props.classes), + classes = WidgetUtil.collect(sectionClass, kindClass, highlightClass, props.classes), css = props.css, attributes = props.attributes, children = trChildren, diff --git a/lua/wikis/commons/Widget/Table2/TableBody.lua b/lua/wikis/commons/Widget/Table2/TableBody.lua index f1ff55f8c23..f454094c624 100644 --- a/lua/wikis/commons/Widget/Table2/TableBody.lua +++ b/lua/wikis/commons/Widget/Table2/TableBody.lua @@ -7,15 +7,10 @@ local Lua = require('Module:Lua') -local Array = Lua.import('Module:Array') local Class = Lua.import('Module:Class') -local MathUtil = Lua.import('Module:MathUtil') local Widget = Lua.import('Module:Widget') local Table2Contexts = Lua.import('Module:Widget/Contexts/Table2') -local Table2Cell = Lua.import('Module:Widget/Table2/Cell') -local Table2CellHeader = Lua.import('Module:Widget/Table2/CellHeader') -local Table2Row = Lua.import('Module:Widget/Table2/Row') ---@class Table2BodyProps ---@field children Renderable[]? @@ -27,70 +22,9 @@ local Table2Body = Class.new(Widget) ---@return Widget function Table2Body:render() - local props = self.props - local children = props.children or {} - - local stripeEnabled = self:useContext(Table2Contexts.BodyStripe) - if stripeEnabled == nil then - return Table2Contexts.Section{ - value = 'body', - children = children, - } - end - - local stripedChildren = {} - local stripe = 'even' - local groupRemaining = 0 - - local function toggleStripe() - stripe = stripe == 'even' and 'odd' or 'even' - end - - local function getRowMaxRowspan(row) - if row and row._cachedMaxRowspan then - return row._cachedMaxRowspan - end - - local rowChildren = (row and row.props and row.props.children) or {} - local maxRowspan = 1 - Array.forEach(rowChildren, function(child) - if Class.instanceOf(child, Table2Cell) or Class.instanceOf(child, Table2CellHeader) then - local rowspan = MathUtil.toInteger(child.props.rowspan) or 1 - rowspan = math.max(rowspan, 1) - maxRowspan = math.max(maxRowspan, rowspan) - end - end) - - if row then - row._cachedMaxRowspan = maxRowspan - end - - return maxRowspan - end - - Array.forEach(children, function(child) - if Class.instanceOf(child, Table2Row) then - if groupRemaining == 0 then - toggleStripe() - end - - local maxRowspan = getRowMaxRowspan(child) - groupRemaining = math.max(groupRemaining, maxRowspan) - - table.insert(stripedChildren, Table2Contexts.BodyStripe{ - value = stripe, - children = {child}, - }) - - groupRemaining = groupRemaining - 1 - else - table.insert(stripedChildren, child) - end - end) - return Table2Contexts.Section{ value = 'body', - children = stripedChildren, + children = self.props.children or {}, } end diff --git a/stylesheets/commons/Table2.scss b/stylesheets/commons/Table2.scss index 993055369a6..8d59823e68f 100644 --- a/stylesheets/commons/Table2.scss +++ b/stylesheets/commons/Table2.scss @@ -250,16 +250,6 @@ $table2-cell-padding-x: 0.75rem; @include table2-surface-colors(); - tbody tr:not( :has( th ):not( :has( td ) ) ):nth-child( odd ) { - .theme--light & { - background-color: var( --clr-on-surface-light-primary-4 ); - } - - .theme--dark & { - background-color: var( --clr-on-surface-dark-primary-4 ); - } - } - tbody tr:not( :has( th ):not( :has( td ) ) ):hover { .theme--light & { background-color: var( --clr-on-surface-light-primary-8 ); From c868004249d1a403674488774e78bdb846e44ab1 Mon Sep 17 00:00:00 2001 From: Eetu Rantanen Date: Wed, 4 Mar 2026 15:29:05 +0200 Subject: [PATCH 02/11] dont add odd as it doesn need class --- javascript/commons/Table2.js | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/javascript/commons/Table2.js b/javascript/commons/Table2.js index 1a909511703..31f0dfcda5b 100644 --- a/javascript/commons/Table2.js +++ b/javascript/commons/Table2.js @@ -9,7 +9,6 @@ const TABLE2_CONFIG = { BODY_ROW: 'tbody tr.table2__row--body' }, CLASSES: { - ODD: 'table2__row--odd', EVEN: 'table2__row--even' } }; @@ -36,19 +35,18 @@ class Table2Striper { restripe() { const rows = this.table.querySelectorAll( TABLE2_CONFIG.SELECTORS.BODY_ROW ); - let stripe = 'even'; + let isEven = false; let groupRemaining = 0; rows.forEach( ( row ) => { if ( groupRemaining === 0 ) { - stripe = ( stripe === 'even' ) ? 'odd' : 'even'; + isEven = !isEven; } const rowspanCount = parseInt( row.dataset.rowspanCount, 10 ) || 1; groupRemaining = Math.max( groupRemaining, rowspanCount ); - row.classList.remove( TABLE2_CONFIG.CLASSES.ODD, TABLE2_CONFIG.CLASSES.EVEN ); - row.classList.add( `table2__row--${ stripe }` ); + row.classList.toggle( TABLE2_CONFIG.CLASSES.EVEN, isEven ); groupRemaining--; } ); From f03a6e6798fe20f76fb81011301859c850d68176 Mon Sep 17 00:00:00 2001 From: Eetu Rantanen Date: Wed, 4 Mar 2026 16:16:06 +0200 Subject: [PATCH 03/11] update --- javascript/commons/Table2.js | 9 ++++++--- lua/wikis/commons/Widget/Table2/Table.lua | 10 ++++------ 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/javascript/commons/Table2.js b/javascript/commons/Table2.js index 31f0dfcda5b..a7aa0325718 100644 --- a/javascript/commons/Table2.js +++ b/javascript/commons/Table2.js @@ -17,13 +17,16 @@ class Table2Striper { constructor( table ) { this.table = table; this.isSortable = table.classList.contains( 'sortable' ); + this.shouldStripe = table.getAttribute( 'data-striped' ) !== 'false'; } init() { - this.restripe(); + if ( this.shouldStripe ) { + this.restripe(); - if ( this.isSortable ) { - this.setupSortListener(); + if ( this.isSortable ) { + this.setupSortListener(); + } } } diff --git a/lua/wikis/commons/Widget/Table2/Table.lua b/lua/wikis/commons/Widget/Table2/Table.lua index d05bdce3e26..8178581cfc0 100644 --- a/lua/wikis/commons/Widget/Table2/Table.lua +++ b/lua/wikis/commons/Widget/Table2/Table.lua @@ -95,15 +95,13 @@ function Table2:render() }} end - if Logic.readBool(props.striped) then - tableChildren = {Table2Contexts.BodyStripe{ - value = true, - children = tableChildren, - }} + local tableAttributes = props.tableAttributes or {} + if not Logic.readBool(props.striped) then + tableAttributes['data-striped'] = 'false' end local tableNode = HtmlWidgets.Table{ - attributes = props.tableAttributes, + attributes = tableAttributes, classes = tableClasses, children = tableChildren, } From a74bda668ec902174c172c67820dcdb045e33f2e Mon Sep 17 00:00:00 2001 From: Eetu Rantanen Date: Wed, 4 Mar 2026 16:20:43 +0200 Subject: [PATCH 04/11] fix it --- lua/wikis/commons/Widget/Table2/Row.lua | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lua/wikis/commons/Widget/Table2/Row.lua b/lua/wikis/commons/Widget/Table2/Row.lua index d8b93974e51..0a43f6ddb50 100644 --- a/lua/wikis/commons/Widget/Table2/Row.lua +++ b/lua/wikis/commons/Widget/Table2/Row.lua @@ -112,6 +112,8 @@ function Table2Row:render() end return child end) + end + local attributes = props.attributes or {} if section == 'body' then local maxRowspan = getMaxRowspan(children) @@ -121,7 +123,7 @@ function Table2Row:render() return HtmlWidgets.Tr{ classes = WidgetUtil.collect(sectionClass, kindClass, highlightClass, props.classes), css = props.css, - attributes = props.attributes, + attributes = attributes, children = trChildren, } end From 721f74179c07949f8c38d62b9f6776569ddc56c0 Mon Sep 17 00:00:00 2001 From: Eetu Rantanen Date: Wed, 4 Mar 2026 16:41:42 +0200 Subject: [PATCH 05/11] consider subheaders --- javascript/commons/Table2.js | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/javascript/commons/Table2.js b/javascript/commons/Table2.js index a7aa0325718..b2d34a66a83 100644 --- a/javascript/commons/Table2.js +++ b/javascript/commons/Table2.js @@ -6,10 +6,12 @@ const TABLE2_CONFIG = { SELECTORS: { TABLE: '.table2__table', - BODY_ROW: 'tbody tr.table2__row--body' + BODY_ROW: 'tbody tr.table2__row--body', + ALL_ROWS: 'tbody tr' }, CLASSES: { - EVEN: 'table2__row--even' + EVEN: 'table2__row--even', + HEAD: 'table2__row--head' } }; @@ -37,11 +39,24 @@ class Table2Striper { } restripe() { - const rows = this.table.querySelectorAll( TABLE2_CONFIG.SELECTORS.BODY_ROW ); - let isEven = false; + const rows = this.table.querySelectorAll( TABLE2_CONFIG.SELECTORS.ALL_ROWS ); + let isEven = true; let groupRemaining = 0; rows.forEach( ( row ) => { + const isBodyRow = row.classList.contains( 'table2__row--body' ); + const isSubheader = row.classList.contains( TABLE2_CONFIG.CLASSES.HEAD ); + + if ( isSubheader ) { + isEven = true; + groupRemaining = 0; + return; + } + + if ( !isBodyRow || row.style.display === 'none' ) { + return; + } + if ( groupRemaining === 0 ) { isEven = !isEven; } From 9195b0575092c5e7876021a1d5c181f5db83d522 Mon Sep 17 00:00:00 2001 From: Eetu Rantanen Date: Thu, 5 Mar 2026 09:36:26 +0200 Subject: [PATCH 06/11] only set attribute to rowspans --- lua/wikis/commons/Widget/Table2/Row.lua | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/lua/wikis/commons/Widget/Table2/Row.lua b/lua/wikis/commons/Widget/Table2/Row.lua index 0a43f6ddb50..094269a92df 100644 --- a/lua/wikis/commons/Widget/Table2/Row.lua +++ b/lua/wikis/commons/Widget/Table2/Row.lua @@ -33,16 +33,17 @@ local HtmlWidgets = Lua.import('Module:Widget/Html/All') local Table2Row = Class.new(Widget) ---@param rowChildren (Widget|Html|string|number|nil)[] ----@return integer +---@return integer|nil local function getMaxRowspan(rowChildren) - return Array.reduce(rowChildren, function(maxRowspan, child) + local maxRowspan = Array.reduce(rowChildren, function(max, child) if Class.instanceOf(child, Table2Cell) or Class.instanceOf(child, Table2CellHeader) then local cellChild = child --[[@as Table2Cell|Table2CellHeader]] local rowspan = MathUtil.toInteger(cellChild.props.rowspan) or 1 - return math.max(maxRowspan, math.max(rowspan, 1)) + return math.max(max, math.max(rowspan, 1)) end - return maxRowspan + return max end, 1) + return maxRowspan > 1 and maxRowspan or nil end ---@return Widget @@ -117,7 +118,9 @@ function Table2Row:render() local attributes = props.attributes or {} if section == 'body' then local maxRowspan = getMaxRowspan(children) - attributes['data-rowspan-count'] = maxRowspan + if maxRowspan then + attributes['data-rowspan-count'] = maxRowspan + end end return HtmlWidgets.Tr{ From bbac2168d1e0be540f784a5c2d6de0d16dea2323 Mon Sep 17 00:00:00 2001 From: Eetu Rantanen Date: Thu, 5 Mar 2026 10:25:24 +0200 Subject: [PATCH 07/11] make hovering on rowspan rows work --- javascript/commons/Table2.js | 49 +++++++++++++++++++++++++++++++++ stylesheets/commons/Table2.scss | 10 +++++++ 2 files changed, 59 insertions(+) diff --git a/javascript/commons/Table2.js b/javascript/commons/Table2.js index b2d34a66a83..0aedbe01b47 100644 --- a/javascript/commons/Table2.js +++ b/javascript/commons/Table2.js @@ -20,6 +20,7 @@ class Table2Striper { this.table = table; this.isSortable = table.classList.contains( 'sortable' ); this.shouldStripe = table.getAttribute( 'data-striped' ) !== 'false'; + this.groupCounter = 0; } init() { @@ -30,6 +31,7 @@ class Table2Striper { this.setupSortListener(); } } + this.setupHoverListeners(); } setupSortListener() { @@ -42,6 +44,7 @@ class Table2Striper { const rows = this.table.querySelectorAll( TABLE2_CONFIG.SELECTORS.ALL_ROWS ); let isEven = true; let groupRemaining = 0; + this.groupCounter = 0; rows.forEach( ( row ) => { const isBodyRow = row.classList.contains( 'table2__row--body' ); @@ -50,6 +53,7 @@ class Table2Striper { if ( isSubheader ) { isEven = true; groupRemaining = 0; + row.removeAttribute( 'data-group-id' ); return; } @@ -59,16 +63,61 @@ class Table2Striper { if ( groupRemaining === 0 ) { isEven = !isEven; + this.groupCounter++; } const rowspanCount = parseInt( row.dataset.rowspanCount, 10 ) || 1; groupRemaining = Math.max( groupRemaining, rowspanCount ); row.classList.toggle( TABLE2_CONFIG.CLASSES.EVEN, isEven ); + row.setAttribute( 'data-group-id', this.groupCounter ); groupRemaining--; } ); } + + setupHoverListeners() { + const bodyRows = this.table.querySelectorAll( TABLE2_CONFIG.SELECTORS.BODY_ROW ); + + bodyRows.forEach( ( row ) => { + row.addEventListener( 'mouseenter', ( e ) => this.onRowHoverEnter( e ) ); + row.addEventListener( 'mouseleave', ( e ) => this.onRowHoverLeave( e ) ); + } ); + } + + onRowHoverEnter( event ) { + const row = event.target.closest( TABLE2_CONFIG.SELECTORS.BODY_ROW ); + if ( !row ) { + return; + } + + const groupId = row.getAttribute( 'data-group-id' ); + if ( !groupId ) { + return; + } + + const groupRows = this.table.querySelectorAll( + `${ TABLE2_CONFIG.SELECTORS.BODY_ROW }[data-group-id="${ groupId }"]` + ); + groupRows.forEach( ( r ) => r.classList.add( 'table2__row--group-hover' ) ); + } + + onRowHoverLeave( event ) { + const row = event.target.closest( TABLE2_CONFIG.SELECTORS.BODY_ROW ); + if ( !row ) { + return; + } + + const groupId = row.getAttribute( 'data-group-id' ); + if ( !groupId ) { + return; + } + + const groupRows = this.table.querySelectorAll( + `${ TABLE2_CONFIG.SELECTORS.BODY_ROW }[data-group-id="${ groupId }"]` + ); + groupRows.forEach( ( r ) => r.classList.remove( 'table2__row--group-hover' ) ); + } } class Table2Module { diff --git a/stylesheets/commons/Table2.scss b/stylesheets/commons/Table2.scss index 8d59823e68f..dbd4ea7b61d 100644 --- a/stylesheets/commons/Table2.scss +++ b/stylesheets/commons/Table2.scss @@ -158,6 +158,16 @@ $table2-cell-padding-x: 0.75rem; } } + &.table2__row--group-hover { + .theme--light & { + background-color: var( --clr-on-surface-light-primary-8 ); + } + + .theme--dark & { + background-color: var( --clr-on-surface-dark-primary-8 ); + } + } + &.table2__row--highlighted:hover { .theme--light & { background-color: var( --clr-semantic-gold-85 ); From cb62198d097184424b3f691cbee7e61e13697742 Mon Sep 17 00:00:00 2001 From: Eetu Rantanen Date: Thu, 5 Mar 2026 14:15:37 +0200 Subject: [PATCH 08/11] remove standalone table hover rules as js handles that --- stylesheets/commons/Table2.scss | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/stylesheets/commons/Table2.scss b/stylesheets/commons/Table2.scss index dbd4ea7b61d..bf2d716c7e0 100644 --- a/stylesheets/commons/Table2.scss +++ b/stylesheets/commons/Table2.scss @@ -259,14 +259,4 @@ $table2-cell-padding-x: 0.75rem; overflow: hidden; @include table2-surface-colors(); - - tbody tr:not( :has( th ):not( :has( td ) ) ):hover { - .theme--light & { - background-color: var( --clr-on-surface-light-primary-8 ); - } - - .theme--dark & { - background-color: var( --clr-on-surface-dark-primary-8 ); - } - } } From 5ada54d4fe060eec7599c8b96e2d6c10d4561563 Mon Sep 17 00:00:00 2001 From: Eetu Rantanen Date: Thu, 5 Mar 2026 14:26:30 +0200 Subject: [PATCH 09/11] bring back striping for mediawiki tables --- stylesheets/commons/Table2.scss | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/stylesheets/commons/Table2.scss b/stylesheets/commons/Table2.scss index bf2d716c7e0..6a9d4556ce4 100644 --- a/stylesheets/commons/Table2.scss +++ b/stylesheets/commons/Table2.scss @@ -259,4 +259,24 @@ $table2-cell-padding-x: 0.75rem; overflow: hidden; @include table2-surface-colors(); + + tbody tr:not( :has( th ):not( :has( td ) ) ):nth-child( odd ) { + .theme--light & { + background-color: var( --clr-on-surface-light-primary-4 ); + } + + .theme--dark & { + background-color: var( --clr-on-surface-dark-primary-4 ); + } + } + + tbody tr:not( :has( th ):not( :has( td ) ) ):hover { + .theme--light & { + background-color: var( --clr-on-surface-light-primary-8 ); + } + + .theme--dark & { + background-color: var( --clr-on-surface-dark-primary-8 ); + } + } } From 902503a0ae08f474d0861325c04a602f2b1c388c Mon Sep 17 00:00:00 2001 From: Eetu Rantanen Date: Thu, 5 Mar 2026 14:48:21 +0200 Subject: [PATCH 10/11] js spesific to widget based tables. make sure grouped highlight rows hover works --- javascript/commons/Table2.js | 2 +- stylesheets/commons/Table2.scss | 12 +++++++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/javascript/commons/Table2.js b/javascript/commons/Table2.js index 0aedbe01b47..baaded6e323 100644 --- a/javascript/commons/Table2.js +++ b/javascript/commons/Table2.js @@ -5,7 +5,7 @@ const TABLE2_CONFIG = { SELECTORS: { - TABLE: '.table2__table', + TABLE: '.table2 .table2__table', BODY_ROW: 'tbody tr.table2__row--body', ALL_ROWS: 'tbody tr' }, diff --git a/stylesheets/commons/Table2.scss b/stylesheets/commons/Table2.scss index 6a9d4556ce4..b269db89133 100644 --- a/stylesheets/commons/Table2.scss +++ b/stylesheets/commons/Table2.scss @@ -158,6 +158,16 @@ $table2-cell-padding-x: 0.75rem; } } + &.table2__row--highlighted:hover { + .theme--light & { + background-color: var( --clr-semantic-gold-85 ); + } + + .theme--dark & { + background-color: var( --clr-semantic-gold-18 ); + } + } + &.table2__row--group-hover { .theme--light & { background-color: var( --clr-on-surface-light-primary-8 ); @@ -168,7 +178,7 @@ $table2-cell-padding-x: 0.75rem; } } - &.table2__row--highlighted:hover { + &.table2__row--highlighted.table2__row--group-hover { .theme--light & { background-color: var( --clr-semantic-gold-85 ); } From 78ebebdc0fb5c7b7509f9ba15e35d9decb94e97e Mon Sep 17 00:00:00 2001 From: Eetu Rantanen Date: Thu, 5 Mar 2026 14:57:40 +0200 Subject: [PATCH 11/11] add basic tests --- javascript/tests/Table2.test.js | 98 +++++++++++++++++++++++++++++++++ 1 file changed, 98 insertions(+) create mode 100644 javascript/tests/Table2.test.js diff --git a/javascript/tests/Table2.test.js b/javascript/tests/Table2.test.js new file mode 100644 index 00000000000..893adb02db2 --- /dev/null +++ b/javascript/tests/Table2.test.js @@ -0,0 +1,98 @@ +/** + * @jest-environment jsdom + */ +/* global jest */ + +const { test, expect, beforeAll, describe } = require( '@jest/globals' ); + +describe( 'Table2 module', () => { + beforeAll( () => { + globalThis.liquipedia = { + core: { + modules: [] + } + }; + + globalThis.mw = { + loader: { + using: jest.fn( () => Promise.resolve() ) + } + }; + + require( '../commons/Table2.js' ); + } ); + + test( 'should register itself as a module', () => { + expect( globalThis.liquipedia.core.modules ).toContain( 'table2' ); + } ); + + test( 'should initialize table2 instance', () => { + expect( globalThis.liquipedia.table2 ).toBeTruthy(); + } ); + + test( 'should have init method', () => { + expect( typeof globalThis.liquipedia.table2.init ).toBe( 'function' ); + } ); + + test( 'should assign data-group-id to body rows during striping', () => { + document.body.innerHTML = ` +
+ + + + + + +
+
+ `; + + globalThis.liquipedia.table2.init(); + + const rows = document.querySelectorAll( '.table2 .table2__table tbody tr.table2__row--body' ); + expect( rows.length ).toBe( 3 ); + + rows.forEach( ( row ) => { + expect( row.getAttribute( 'data-group-id' ) ).toBeTruthy(); + } ); + } ); + + test( 'should apply even class to alternating rows', () => { + document.body.innerHTML = ` +
+ + + + + + + +
+
+ `; + + globalThis.liquipedia.table2.init(); + + const rows = document.querySelectorAll( '.table2 .table2__table tbody tr.table2__row--body' ); + + expect( rows[ 0 ].classList.contains( 'table2__row--even' ) ).toBe( false ); + expect( rows[ 1 ].classList.contains( 'table2__row--even' ) ).toBe( true ); + expect( rows[ 2 ].classList.contains( 'table2__row--even' ) ).toBe( false ); + expect( rows[ 3 ].classList.contains( 'table2__row--even' ) ).toBe( true ); + } ); + + test( 'should ignore standalone tables without .table2 wrapper', () => { + document.body.innerHTML = ` + + + + +
Standalone table row
+ `; + + globalThis.liquipedia.table2.init(); + + const row = document.querySelector( '.table2__table tbody tr' ); + expect( row.getAttribute( 'data-group-id' ) ).toBeNull(); + } ); +} );