MediaWiki:Common.js: Difference between revisions
Appearance
Replaced content with "if ( !thead || !thead.rows.length || !tbody ) { return; }" Tag: Replaced |
No edit summary |
||
| Line 1: | Line 1: | ||
if ( !thead | | /* Any JavaScript here will be loaded for all users on every page load. */ | ||
} | /* Platform filter for the PC and Console Games table. | ||
Runs AFTER MediaWiki's table sorter so the two do not conflict, | |||
then adds a combo box in the header under the Platform column. | |||
"Contains" matching means multi-platform games appear under | |||
every platform they support. */ | |||
( function () { | |||
var counter = 0; | |||
function setup( table ) { | |||
if ( table.dataset.platformFilterReady ) { | |||
return; | |||
} | |||
// Find the header row: the first row that contains a <th>. | |||
var headerRow = null; | |||
var allRows = table.rows; | |||
for ( var i = 0; i < allRows.length; i++ ) { | |||
if ( allRows[ i ].getElementsByTagName( 'th' ).length ) { | |||
headerRow = allRows[ i ]; | |||
break; | |||
} | |||
} | |||
if ( !headerRow ) { | |||
return; | |||
} | |||
// Find the Platform column by its header text. | |||
var headerCells = headerRow.cells; | |||
var platformCol = -1; | |||
for ( var j = 0; j < headerCells.length; j++ ) { | |||
if ( /platform/i.test( headerCells[ j ].textContent ) ) { | |||
platformCol = j; | |||
break; | |||
} | |||
} | |||
if ( platformCol === -1 ) { | |||
return; | |||
} | |||
table.dataset.platformFilterReady = '1'; | |||
// Use the thead the sorter created; create one only if absent. | |||
var thead = table.tHead; | |||
if ( !thead ) { | |||
thead = document.createElement( 'thead' ); | |||
table.insertBefore( thead, table.firstChild ); | |||
} | |||
if ( headerRow.parentNode !== thead ) { | |||
thead.appendChild( headerRow ); | |||
} | |||
// Platform options. Edit this list to add or rename platforms. | |||
var platforms = [ | |||
{ label: 'Windows', match: /windows/i }, | |||
{ label: 'PlayStation', match: /playstation/i }, | |||
{ label: 'Xbox / Game Pass', match: /xbox|game ?pass/i }, | |||
{ label: 'Nintendo Switch', match: /switch/i }, | |||
{ label: 'iOS', match: /\bios\b/i }, | |||
{ label: 'Android', match: /android/i }, | |||
{ label: 'Web', match: /\bweb\b/i }, | |||
{ label: 'Linux', match: /linux/i } | |||
]; | |||
var selectId = 'platform-filter-select-' + ( counter++ ); | |||
// Status line, announced to screen readers on change. | |||
var status = document.createElement( 'div' ); | |||
status.className = 'platform-filter-status'; | |||
status.setAttribute( 'role', 'status' ); | |||
status.setAttribute( 'aria-live', 'polite' ); | |||
table.parentNode.insertBefore( status, table ); | |||
// Build the filter row and place it in the thead, after the | |||
// header row. The sorter already bound its click handlers to | |||
// the header cells, so these extra cells do not affect sorting. | |||
var filterRow = thead.insertRow( -1 ); | |||
if ( platformCol > 0 ) { | |||
var lead = document.createElement( 'td' ); | |||
lead.colSpan = platformCol; | |||
filterRow.appendChild( lead ); | |||
} | |||
var pcell = document.createElement( 'td' ); | |||
var label = document.createElement( 'label' ); | |||
label.setAttribute( 'for', selectId ); | |||
label.textContent = 'Filter by platform: '; | |||
var select = document.createElement( 'select' ); | |||
select.id = selectId; | |||
var optAll = document.createElement( 'option' ); | |||
optAll.value = ''; | |||
optAll.textContent = 'All platforms'; | |||
select.appendChild( optAll ); | |||
platforms.forEach( function ( p, idx ) { | |||
var opt = document.createElement( 'option' ); | |||
opt.value = String( idx ); | |||
opt.textContent = p.label; | |||
select.appendChild( opt ); | |||
} ); | |||
select.addEventListener( 'click', function ( e ) { | |||
e.stopPropagation(); | |||
} ); | |||
select.addEventListener( 'change', function () { | |||
applyFilter( this.value ); | |||
} ); | |||
pcell.appendChild( label ); | |||
pcell.appendChild( select ); | |||
filterRow.appendChild( pcell ); | |||
var trailing = headerCells.length - platformCol - 1; | |||
if ( trailing > 0 ) { | |||
var tail = document.createElement( 'td' ); | |||
tail.colSpan = trailing; | |||
filterRow.appendChild( tail ); | |||
} | |||
function applyFilter( value ) { | |||
var body = table.tBodies[ 0 ]; | |||
if ( !body ) { | |||
return; | |||
} | |||
var rows = body.rows; | |||
var total = rows.length; | |||
var shown = 0; | |||
var test = ( value === '' ) ? null : platforms[ Number( value ) ].match; | |||
for ( var r = 0; r < total; r++ ) { | |||
var row = rows[ r ]; | |||
var pc = row.cells[ platformCol ]; | |||
var textVal = pc ? pc.textContent : ''; | |||
if ( !test || test.test( textVal ) ) { | |||
row.style.display = ''; | |||
shown++; | |||
} else { | |||
row.style.display = 'none'; | |||
} | |||
} | |||
if ( !test ) { | |||
status.textContent = 'Showing all ' + total + ' games.'; | |||
} else { | |||
status.textContent = 'Showing ' + shown + ' of ' + total + | |||
' games available on ' + platforms[ Number( value ) ].label + '.'; | |||
} | |||
} | |||
// Initial confirmation, findable by navigating just before | |||
// the table even though it will not auto-announce at load. | |||
var body = table.tBodies[ 0 ]; | |||
var count = body ? body.rows.length : 0; | |||
status.textContent = 'Platform filter ready. Showing all ' + count + ' games.'; | |||
} | |||
mw.hook( 'wikipage.content' ).add( function ( $content ) { | |||
// Defer one tick so the table sorter finishes first, then we | |||
// attach to the header it built instead of racing it. | |||
setTimeout( function () { | |||
$content.find( 'table.platform-filter' ).each( function () { | |||
setup( this ); | |||
} ); | |||
}, 0 ); | |||
} ); | |||
}() ); | |||
Latest revision as of 16:07, 7 July 2026
/* Any JavaScript here will be loaded for all users on every page load. */
/* Platform filter for the PC and Console Games table.
Runs AFTER MediaWiki's table sorter so the two do not conflict,
then adds a combo box in the header under the Platform column.
"Contains" matching means multi-platform games appear under
every platform they support. */
( function () {
var counter = 0;
function setup( table ) {
if ( table.dataset.platformFilterReady ) {
return;
}
// Find the header row: the first row that contains a <th>.
var headerRow = null;
var allRows = table.rows;
for ( var i = 0; i < allRows.length; i++ ) {
if ( allRows[ i ].getElementsByTagName( 'th' ).length ) {
headerRow = allRows[ i ];
break;
}
}
if ( !headerRow ) {
return;
}
// Find the Platform column by its header text.
var headerCells = headerRow.cells;
var platformCol = -1;
for ( var j = 0; j < headerCells.length; j++ ) {
if ( /platform/i.test( headerCells[ j ].textContent ) ) {
platformCol = j;
break;
}
}
if ( platformCol === -1 ) {
return;
}
table.dataset.platformFilterReady = '1';
// Use the thead the sorter created; create one only if absent.
var thead = table.tHead;
if ( !thead ) {
thead = document.createElement( 'thead' );
table.insertBefore( thead, table.firstChild );
}
if ( headerRow.parentNode !== thead ) {
thead.appendChild( headerRow );
}
// Platform options. Edit this list to add or rename platforms.
var platforms = [
{ label: 'Windows', match: /windows/i },
{ label: 'PlayStation', match: /playstation/i },
{ label: 'Xbox / Game Pass', match: /xbox|game ?pass/i },
{ label: 'Nintendo Switch', match: /switch/i },
{ label: 'iOS', match: /\bios\b/i },
{ label: 'Android', match: /android/i },
{ label: 'Web', match: /\bweb\b/i },
{ label: 'Linux', match: /linux/i }
];
var selectId = 'platform-filter-select-' + ( counter++ );
// Status line, announced to screen readers on change.
var status = document.createElement( 'div' );
status.className = 'platform-filter-status';
status.setAttribute( 'role', 'status' );
status.setAttribute( 'aria-live', 'polite' );
table.parentNode.insertBefore( status, table );
// Build the filter row and place it in the thead, after the
// header row. The sorter already bound its click handlers to
// the header cells, so these extra cells do not affect sorting.
var filterRow = thead.insertRow( -1 );
if ( platformCol > 0 ) {
var lead = document.createElement( 'td' );
lead.colSpan = platformCol;
filterRow.appendChild( lead );
}
var pcell = document.createElement( 'td' );
var label = document.createElement( 'label' );
label.setAttribute( 'for', selectId );
label.textContent = 'Filter by platform: ';
var select = document.createElement( 'select' );
select.id = selectId;
var optAll = document.createElement( 'option' );
optAll.value = '';
optAll.textContent = 'All platforms';
select.appendChild( optAll );
platforms.forEach( function ( p, idx ) {
var opt = document.createElement( 'option' );
opt.value = String( idx );
opt.textContent = p.label;
select.appendChild( opt );
} );
select.addEventListener( 'click', function ( e ) {
e.stopPropagation();
} );
select.addEventListener( 'change', function () {
applyFilter( this.value );
} );
pcell.appendChild( label );
pcell.appendChild( select );
filterRow.appendChild( pcell );
var trailing = headerCells.length - platformCol - 1;
if ( trailing > 0 ) {
var tail = document.createElement( 'td' );
tail.colSpan = trailing;
filterRow.appendChild( tail );
}
function applyFilter( value ) {
var body = table.tBodies[ 0 ];
if ( !body ) {
return;
}
var rows = body.rows;
var total = rows.length;
var shown = 0;
var test = ( value === '' ) ? null : platforms[ Number( value ) ].match;
for ( var r = 0; r < total; r++ ) {
var row = rows[ r ];
var pc = row.cells[ platformCol ];
var textVal = pc ? pc.textContent : '';
if ( !test || test.test( textVal ) ) {
row.style.display = '';
shown++;
} else {
row.style.display = 'none';
}
}
if ( !test ) {
status.textContent = 'Showing all ' + total + ' games.';
} else {
status.textContent = 'Showing ' + shown + ' of ' + total +
' games available on ' + platforms[ Number( value ) ].label + '.';
}
}
// Initial confirmation, findable by navigating just before
// the table even though it will not auto-announce at load.
var body = table.tBodies[ 0 ];
var count = body ? body.rows.length : 0;
status.textContent = 'Platform filter ready. Showing all ' + count + ' games.';
}
mw.hook( 'wikipage.content' ).add( function ( $content ) {
// Defer one tick so the table sorter finishes first, then we
// attach to the header it built instead of racing it.
setTimeout( function () {
$content.find( 'table.platform-filter' ).each( function () {
setup( this );
} );
}, 0 );
} );
}() );