Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 53 additions & 0 deletions src/XtremeIdiots.Portal.Web/Styles/features/_chatlog.scss
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,63 @@
flex: 0 1 240px;
}

// Page jump controls
.datatable-page-jump {
display: inline-flex;
align-items: center;
gap: $spacing-xs;
margin-right: $spacing-md;
padding: $spacing-xs 0;

.page-jump-label {
font-size: $font-size-sm;
color: $xi-text-muted;
white-space: nowrap;
}

.page-jump-input {
width: 60px;
padding: 0.25rem 0.5rem;
font-size: $font-size-sm;
line-height: 1.5;
color: $xi-text;
background-color: $white-bg;
border: 1px solid $border-color;
border-radius: 3px;
text-align: center;
transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;

&:focus {
outline: 0;
border-color: $xi-primary;
box-shadow: 0 0 0 0.15rem rgba($xi-primary, 0.25);
}

&::-webkit-inner-spin-button,
&::-webkit-outer-spin-button {
opacity: 1;
}
}

.page-jump-total {
font-size: $font-size-sm;
color: $xi-text-muted;
white-space: nowrap;
}
}

@include media-max-md {
#chatLogFilters .filter-group.locked-filter-group {
padding-top: 0.4rem;
}

.datatable-page-jump {
display: flex;
margin-right: 0;
margin-bottom: $spacing-xs;
width: 100%;
justify-content: center;
}
}

@include media-lg {
Expand Down
81 changes: 80 additions & 1 deletion src/XtremeIdiots.Portal.Web/wwwroot/js/chatlog-index.js
Original file line number Diff line number Diff line change
Expand Up @@ -169,10 +169,89 @@
}
}

function addPageJump() {
try {
const paginateDiv = document.querySelector('#dataTable_paginate');
if (!paginateDiv) {
console.warn('[ChatLog] addPageJump: paginate div not found');
return;
}

// Don't add if already exists
if (document.getElementById('pageJumpContainer')) {
return;
}

const pageInfo = table.page.info();
const totalPages = pageInfo.pages;

// Create the page jump container
const jumpContainer = document.createElement('div');
jumpContainer.id = 'pageJumpContainer';
jumpContainer.className = 'datatable-page-jump';
jumpContainer.innerHTML = `
<span class="page-jump-label">Go to page:</span>
<input type="number" id="pageJumpInput" class="page-jump-input" min="1" max="${totalPages}" value="${pageInfo.page + 1}" />
<span class="page-jump-total">of ${totalPages}</span>
Comment on lines +193 to +195
Copy link

Copilot AI Feb 16, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The page-jump input doesn’t have an associated label (a isn’t announced as a label by many screen readers). Consider using a … or adding an aria-label/aria-labelledby/aria-describedby so the control is accessible.

Suggested change
<span class="page-jump-label">Go to page:</span>
<input type="number" id="pageJumpInput" class="page-jump-input" min="1" max="${totalPages}" value="${pageInfo.page + 1}" />
<span class="page-jump-total">of ${totalPages}</span>
<label for="pageJumpInput" class="page-jump-label">Go to page:</label>
<input type="number" id="pageJumpInput" class="page-jump-input" min="1" max="${totalPages}" value="${pageInfo.page + 1}" aria-describedby="pageJumpTotal" />
<span id="pageJumpTotal" class="page-jump-total">of ${totalPages}</span>

Copilot uses AI. Check for mistakes.
`;
Comment on lines +192 to +196

Check warning

Code scanning / ESLint

Assignments to [innerHTML](https://developer.mozilla.org/en-US/docs/Web/API/Element/innerHTML)/[outerHTML](https://developer.mozilla.org/en-US/docs/Web/API/Element/outerHTML) properties or calls to [insertAdjacentHTML](https://developer.mozilla.org/en-US/docs/Web/API/Element/insertAdjacentHTML) method manipulate DOM directly without any sanitization and should be avoided. Use document.createElement() or similar methods instead. Warning

Do not write to DOM directly using innerHTML/outerHTML property

// Insert before the pagination controls
paginateDiv.parentNode.insertBefore(jumpContainer, paginateDiv);

// Helper function for page navigation
function navigateToPage(inputElement) {
const pageInfo = table.page.info();
const pageNum = parseInt(inputElement.value, 10);

// Check for valid number and range
if (!isNaN(pageNum) && pageNum >= 1 && pageNum <= pageInfo.pages) {
table.page(pageNum - 1).draw(false);
} else {
// Reset to current page if invalid or out of range
inputElement.value = pageInfo.page + 1;
}
}

// Add event handler for the input
const pageInput = document.getElementById('pageJumpInput');
if (pageInput) {
pageInput.addEventListener('keypress', function(e) {
if (e.key === 'Enter') {
Comment on lines +218 to +219
Copy link

Copilot AI Feb 16, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

keypress is deprecated and can behave inconsistently across browsers for non-printing keys like Enter. Prefer keydown/keyup (and optionally e.preventDefault() on Enter) for more reliable handling.

Suggested change
pageInput.addEventListener('keypress', function(e) {
if (e.key === 'Enter') {
pageInput.addEventListener('keydown', function(e) {
if (e.key === 'Enter') {
e.preventDefault();

Copilot uses AI. Check for mistakes.
navigateToPage(this);
}
});

pageInput.addEventListener('blur', function() {
navigateToPage(this);
});

// Update page jump on table redraw
table.on('draw.dt', function() {
const pageInfo = table.page.info();
pageInput.value = pageInfo.page + 1;
pageInput.max = pageInfo.pages;

const totalSpan = document.querySelector('.page-jump-total');
Copy link

Copilot AI Feb 16, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the draw.dt handler, document.querySelector('.page-jump-total') searches the whole document. It would be more robust to scope this lookup to the page-jump container (or otherwise keep a reference) to avoid accidentally updating the wrong element if another .page-jump-total exists on the page.

Suggested change
const totalSpan = document.querySelector('.page-jump-total');
const totalSpan = jumpContainer.querySelector('.page-jump-total');

Copilot uses AI. Check for mistakes.
if (totalSpan) {
totalSpan.textContent = `of ${pageInfo.pages}`;
}
});
}

console.log('[ChatLog] addPageJump complete');
} catch (e) {
console.warn('[ChatLog] addPageJump error', e);
}
}

// Run after DataTables initialization to avoid timing issues
table.on('init.dt', function () { relocateSearch(); });
table.on('init.dt', function () {
relocateSearch();
addPageJump();
});
// Fallback in case init event missed (safety timeout)
setTimeout(relocateSearch, 1200);
setTimeout(addPageJump, 1200);

if (lockedSel) lockedSel.addEventListener('change', function () { table.ajax.reload(null, false); });
if (gameTypeSel) gameTypeSel.addEventListener('change', function () {
Expand Down
Loading