fix(ui): queue columns fit the window on resize (fullscreen → windowed)

Saved column widths were applied as fixed pixels, so switching from fullscreen
to windowed mode left the column sum wider than the viewport and the user had to
manually drag the window wider just to see the rightmost columns.

Now: a separate _idealColumnWidths map holds the user's preferred widths
(persisted), and _applyFittedColumnWidths reshapes the displayed widths to fit
the current container width. When sum(ideals) > container.clientWidth, every
column is scaled by the same factor so the row exactly fits (and a hidden
column becomes visible again).

- Two-tier widths: ideals are only updated by an explicit drag, not by a
  resize-driven refit. So dragging while the window is narrow no longer
  permanently shrinks every other column.
- saveDraggedColumnWidth(col, w) saves a single column's new ideal.
- Window-resize listener refits with a 60ms debounce.

Lint clean, full suite 200/200.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
Administrator 2026-06-02 05:39:28 +02:00
parent 72d3fe1e4e
commit b5ff9b1a0b

View File

@ -4120,31 +4120,79 @@ function loadAutoCheckPreference() {
} }
// --- Queue table column resizing (JDownloader-style) --- // --- Queue table column resizing (JDownloader-style) ---
// Two-tier widths: _idealColumnWidths is what the user set (persisted); the
// displayed widths are scaled proportionally if the window is too narrow to fit
// all ideals (fullscreen → windowed). We never overwrite ideals just because
// the window shrunk — only an explicit drag updates the ideal for that column.
const _idealColumnWidths = {};
function restoreQueueColumnWidths() { function restoreQueueColumnWidths() {
try { try {
const raw = localStorage.getItem(QUEUE_COL_WIDTHS_KEY); const raw = localStorage.getItem(QUEUE_COL_WIDTHS_KEY);
if (!raw) return; if (raw) {
const widths = JSON.parse(raw); const widths = JSON.parse(raw);
if (!widths || typeof widths !== 'object') return; if (widths && typeof widths === 'object') {
for (const [col, px] of Object.entries(widths)) { for (const [col, px] of Object.entries(widths)) {
const th = document.querySelector(`#queueTable th[data-col="${col}"]`); if (typeof px === 'number' && px > 20) _idealColumnWidths[col] = px;
if (th && typeof px === 'number' && px > 20) { }
th.style.width = px + 'px';
} }
} }
_applyFittedColumnWidths();
} catch {} } catch {}
} }
function saveQueueColumnWidths() { function saveDraggedColumnWidth(col, width) {
try { // Called from the resizer onUp: the dragged column's new width becomes its
const widths = {}; // new ideal. Other columns keep their saved ideals untouched (so a drag
document.querySelectorAll('#queueTable th[data-col]').forEach(th => { // while the window is small doesn't bake the scaled values in).
widths[th.dataset.col] = th.getBoundingClientRect().width; if (!col || typeof width !== 'number' || width < 40) return;
}); _idealColumnWidths[col] = width;
localStorage.setItem(QUEUE_COL_WIDTHS_KEY, JSON.stringify(widths)); try { localStorage.setItem(QUEUE_COL_WIDTHS_KEY, JSON.stringify(_idealColumnWidths)); } catch {}
} catch {} _applyFittedColumnWidths();
} }
function _applyFittedColumnWidths() {
const container = document.getElementById('queueContainer');
if (!container) return;
const ths = document.querySelectorAll('#queueTable th[data-col]');
if (!ths.length) return;
const entries = [];
let total = 0;
ths.forEach(th => {
// Fall back to the column's currently-measured width if no ideal exists
// yet (first render before the user ever dragged).
const ideal = _idealColumnWidths[th.dataset.col] || th.getBoundingClientRect().width || 0;
entries.push({ th, ideal });
total += ideal;
});
if (total <= 0) return;
const available = container.clientWidth;
if (available <= 0) return;
const MIN = 40;
if (total <= available) {
entries.forEach(({ th, ideal }) => { th.style.width = ideal + 'px'; });
return;
}
// Scale all columns proportionally so they exactly fit the available width.
const scale = available / total;
entries.forEach(({ th, ideal }) => {
th.style.width = Math.max(MIN, Math.round(ideal * scale)) + 'px';
});
}
// Debounced window-resize refit. Fires on every window size change — fullscreen
// → windowed, dragging the window edge, monitor unplug — and reshapes columns
// to the new viewport so the user never has to drag the window wider just to
// see a hidden column.
let _columnRefitTimer = null;
window.addEventListener('resize', () => {
clearTimeout(_columnRefitTimer);
_columnRefitTimer = setTimeout(_applyFittedColumnWidths, 60);
});
function setupColumnResizing() { function setupColumnResizing() {
const headers = document.querySelectorAll('#queueTable th[data-col]'); const headers = document.querySelectorAll('#queueTable th[data-col]');
headers.forEach(th => { headers.forEach(th => {
@ -4171,7 +4219,10 @@ function setupColumnResizing() {
document.removeEventListener('mouseup', onUp); document.removeEventListener('mouseup', onUp);
resizer.classList.remove('dragging'); resizer.classList.remove('dragging');
document.body.classList.remove('col-resizing'); document.body.classList.remove('col-resizing');
saveQueueColumnWidths(); // Only the dragged column's new width becomes its new ideal; other
// columns keep their saved ideals (so dragging while the window is
// narrow doesn't permanently shrink everything else).
saveDraggedColumnWidth(th.dataset.col, th.getBoundingClientRect().width);
}; };
document.addEventListener('mousemove', onMove); document.addEventListener('mousemove', onMove);