Common.js: Difference between revisions
From SUALEX
No edit summary |
No edit summary |
||
| Line 45: | Line 45: | ||
// Pager UI (placed above the table) | // Pager UI (placed above the table) | ||
var $pager = $('<div class="table-pager" style="margin:0. | var $pager = $('<div class="table-pager" style="margin:0.5em 0; display:flex; align-items:center; gap:0.5em;">'); | ||
var $prev = $('<button type="button" class="pager-prev">◀</button>'); | var $prev = $('<button type="button" class="pager-prev">◀</button>'); | ||
var $next = $('<button type="button" class="pager-next">▶</button>'); | var $next = $('<button type="button" class="pager-next">▶</button>'); | ||
| Line 51: | Line 51: | ||
var $status = $('<span class="pager-status">'); | var $status = $('<span class="pager-status">'); | ||
$pager.append($prev, $next, $pageInfo, $status); | $pager.append($prev, $next, $pageInfo, $status); | ||
$table. | $table.after($pager); | ||
// Page size fixed | // Page size fixed | ||
var pageSize = 100; | var pageSize = 100; | ||
var currentPage = 1; | var currentPage = 1; | ||
| Line 61: | Line 61: | ||
var $rows = $table.find('tbody tr'); | var $rows = $table.find('tbody tr'); | ||
if ($rows.length === 0) { | if ($rows.length === 0) { | ||
$rows = $table.find('tr').not($thead.find('tr')); | $rows = $table.find('tr').not($thead.find('tr')); | ||
} | } | ||
Revision as of 00:21, 31 January 2026
/* Any JavaScript here will be loaded for all users on every page load. */
mw.loader.using(['jquery'], function () {
// Debounce helper to avoid too-frequent re-evaluations while typing
function debounce(fn, wait) {
var timeout;
return function () {
var context = this, args = arguments;
clearTimeout(timeout);
timeout = setTimeout(function () {
fn.apply(context, args);
}, wait);
};
}
function initColumnSearchAndPager($table) {
var $thead = $table.find('thead');
// Ensure a thead exists (clone first row into thead if necessary)
if ($thead.length === 0) {
var $firstRow = $table.find('tr').first();
$thead = $('<thead>').append($firstRow.clone());
$firstRow.remove();
$table.prepend($thead);
}
var $headerRow = $thead.find('tr').last();
var $filterRow = $('<tr class="searchable-row">');
var colCount = $headerRow.find('th').length;
for (var colIndex = 0; colIndex < colCount; colIndex++) {
var $input = $('<input>', {
type: 'search',
placeholder: 'Search…',
'data-col-index': colIndex
}).css({
width: '95%',
boxSizing: 'border-box'
});
$filterRow.append($('<th>').append($input));
}
$headerRow.before($filterRow);
// Pager UI (placed above the table)
var $pager = $('<div class="table-pager" style="margin:0.5em 0; display:flex; align-items:center; gap:0.5em;">');
var $prev = $('<button type="button" class="pager-prev">◀</button>');
var $next = $('<button type="button" class="pager-next">▶</button>');
var $pageInfo = $('<span class="pager-pageinfo">');
var $status = $('<span class="pager-status">');
$pager.append($prev, $next, $pageInfo, $status);
$table.after($pager);
// Page size fixed
var pageSize = 100;
var currentPage = 1;
// Helper to fetch current candidate rows (recomputed when needed)
function getAllRows() {
var $rows = $table.find('tbody tr');
if ($rows.length === 0) {
$rows = $table.find('tr').not($thead.find('tr'));
}
return $rows;
}
// Initialize matched flag
var $allRows = getAllRows();
$allRows.each(function () { $(this).data('matched', true); });
function updatePagerUI(totalMatches) {
var totalPages = Math.max(1, Math.ceil(totalMatches / pageSize));
// compute shown range
var start = (totalMatches === 0) ? 0 : (currentPage - 1) * pageSize + 1;
var end = Math.min(currentPage * pageSize, totalMatches);
$pageInfo.text('Page ' + currentPage + ' of ' + totalPages);
if (totalMatches === 0) {
$status.text('Showing 0 entries');
} else {
$status.text('Showing ' + start + '–' + end + ' of ' + totalMatches + ' entries');
}
$prev.prop('disabled', currentPage <= 1);
$next.prop('disabled', currentPage >= totalPages);
}
function renderPage() {
// Recompute rows set (in case table changed)
$allRows = getAllRows();
// Hide everything first
$allRows.hide();
// Filtered rows (preserve order)
var $matched = $allRows.filter(function () { return $(this).data('matched') === true; });
var totalMatches = $matched.length;
var totalPages = Math.max(1, Math.ceil(totalMatches / pageSize));
if (currentPage > totalPages) currentPage = totalPages;
var startIndex = (currentPage - 1) * pageSize;
var endIndex = startIndex + pageSize;
$matched.slice(startIndex, endIndex).show();
updatePagerUI(totalMatches);
}
// Prev / Next handlers
$prev.on('click', function () {
if (currentPage > 1) {
currentPage--;
renderPage();
}
});
$next.on('click', function () {
var totalMatches = $allRows.filter(function () { return $(this).data('matched') === true; }).length;
var totalPages = Math.max(1, Math.ceil(totalMatches / pageSize));
if (currentPage < totalPages) {
currentPage++;
renderPage();
}
});
// Filtering logic (applies across all rows)
function applyFilters() {
var filters = [];
$filterRow.find('input').each(function () {
filters.push($(this).val().toLowerCase());
});
// Recompute rows set
$allRows = getAllRows();
$allRows.each(function () {
var $cells = $(this).find('td');
var visible = true;
for (var i = 0; i < filters.length; i++) {
var text = filters[i];
if (!text) continue;
var cell = $cells.eq(i);
var cellText = cell.length ? cell.text().toLowerCase() : '';
if (cellText.indexOf(text) === -1) {
visible = false;
break;
}
}
$(this).data('matched', visible);
});
// Reset to first page when filters change
currentPage = 1;
renderPage();
}
// Debounce input handler for better UX on large tables
var debouncedApply = debounce(applyFilters, 150);
$filterRow.find('input').on('input', debouncedApply);
// Expose a reapply function for external code that mutates or sorts the table
$table.data('reapplySearchAndPaging', function () {
applyFilters();
});
// Initial render
renderPage();
}
// Initialize every matching table on DOM ready
$(function () {
$('table.searchable.sortable').each(function () {
initColumnSearchAndPager($(this));
});
});
});