Compare commits

..

No commits in common. "c73108afff914b78cbc5f42429a33ac16520a13e" and "1bcd7a20780c2dbccec7127b9271de65fd8bb980" have entirely different histories.

2 changed files with 16 additions and 59 deletions

View File

@ -1,6 +1,6 @@
{ {
"name": "multi-hoster-uploader", "name": "multi-hoster-uploader",
"version": "2.8.8", "version": "2.8.7",
"description": "Upload files to doodstream, voe, vidmoly, byse simultaneously", "description": "Upload files to doodstream, voe, vidmoly, byse simultaneously",
"main": "main.js", "main": "main.js",
"scripts": { "scripts": {

View File

@ -200,21 +200,13 @@ async function init() {
} }
// --- Tab switching --- // --- Tab switching ---
let _historyDirty = false;
function _isHistoryTabActive() {
const tab = document.querySelector('.tab.active');
return !!(tab && tab.dataset.view === 'history');
}
document.querySelectorAll('.tab').forEach(tab => { document.querySelectorAll('.tab').forEach(tab => {
tab.addEventListener('click', () => { tab.addEventListener('click', () => {
document.querySelectorAll('.tab').forEach(t => t.classList.remove('active')); document.querySelectorAll('.tab').forEach(t => t.classList.remove('active'));
document.querySelectorAll('.view').forEach(v => v.classList.remove('active')); document.querySelectorAll('.view').forEach(v => v.classList.remove('active'));
tab.classList.add('active'); tab.classList.add('active');
document.getElementById(`${tab.dataset.view}-view`).classList.add('active'); document.getElementById(`${tab.dataset.view}-view`).classList.add('active');
if (tab.dataset.view === 'history') { if (tab.dataset.view === 'history') loadHistory();
_historyDirty = false;
loadHistory();
}
}); });
}); });
@ -1828,25 +1820,16 @@ function handleBatchDone(summary) {
updateQueueActionButtons(); updateQueueActionButtons();
renderQueueTable(); renderQueueTable();
renderRecentUploadsPanel(); renderRecentUploadsPanel();
// History is only visible on the Verlauf tab. Mark it dirty and refresh when loadHistory();
// the user actually switches to it — skips an IPC + full table rebuild per
// batch-done when the user is watching the upload view.
_historyDirty = true;
if (_isHistoryTabActive()) loadHistory();
const removeOnDone = config.globalSettings && config.globalSettings.removeFromQueueOnDone; const removeOnDone = config.globalSettings && config.globalSettings.removeFromQueueOnDone;
if (removeOnDone) { if (removeOnDone) {
// Single pass: build the keep-list and clean up the index for removed jobs. const doneJobs = queueJobs.filter(j => j.status === 'done');
const nextJobs = []; for (const job of doneJobs) {
for (const job of queueJobs) { removeJobFromIndex(job);
if (job.status === 'done') { selectedJobIds.delete(job.id);
removeJobFromIndex(job);
selectedJobIds.delete(job.id);
} else {
nextJobs.push(job);
}
} }
queueJobs = nextJobs; queueJobs = queueJobs.filter(j => j.status !== 'done');
renderQueueTable(); renderQueueTable();
} }
@ -3232,50 +3215,24 @@ function updateRecentSortHeaders() {
let _recentListenersBound = false; let _recentListenersBound = false;
function _buildRecentRowHtml(row) {
const cls = `recent-file-row${row.isError ? ' error' : ''}${selectedRecentIds.has(row.order) ? ' selected' : ''}`;
return `<tr class="${cls}" data-order="${row.order}" data-link="${escapeAttr(row.link)}">`
+ `<td>${escapeHtml(row.date)}</td>`
+ `<td title="${escapeAttr(row.filename)}">${escapeHtml(row.filename)}</td>`
+ `<td>${escapeHtml(row.host)}</td>`
+ `<td title="${escapeAttr(row.link)}">${escapeHtml(row.link)}</td>`
+ `</tr>`;
}
// Tracks the last rendered dataset so we can append-only when the user is just
// accumulating new uploads (the default case: sort=date desc, rows only grow).
let _recentLastRenderedSig = '';
let _recentLastRenderedLen = 0;
function renderRecentUploadsPanel() { function renderRecentUploadsPanel() {
const tbody = document.getElementById('recentFilesBody'); const tbody = document.getElementById('recentFilesBody');
if (!tbody) return; if (!tbody) return;
if (!sessionFilesData.length) { if (!sessionFilesData.length) {
tbody.innerHTML = '<tr><td colspan="4" class="empty-state">Noch keine Uploads in dieser Session.</td></tr>'; tbody.innerHTML = '<tr><td colspan="4" class="empty-state">Noch keine Uploads in dieser Session.</td></tr>';
_recentLastRenderedSig = '';
_recentLastRenderedLen = 0;
return; return;
} }
const rows = sortRecentFiles(sessionFilesData); const rows = sortRecentFiles(sessionFilesData);
const sig = `${recentSortState.key}|${recentSortState.direction}`;
const dateDescAppendOnly = sig === 'date|desc'
&& _recentLastRenderedSig === sig
&& rows.length > _recentLastRenderedLen
&& tbody.querySelectorAll('.recent-file-row').length === _recentLastRenderedLen;
if (dateDescAppendOnly) { tbody.innerHTML = rows.map(row => `
// Fast path: only new rows (date desc puts newest on top) — insert them <tr class="recent-file-row${row.isError ? ' error' : ''}${selectedRecentIds.has(row.order) ? ' selected' : ''}" data-order="${row.order}" data-link="${escapeAttr(row.link)}">
// at the top without rebuilding the 5000-row tbody below. <td>${escapeHtml(row.date)}</td>
const added = rows.length - _recentLastRenderedLen; <td title="${escapeAttr(row.filename)}">${escapeHtml(row.filename)}</td>
let html = ''; <td>${escapeHtml(row.host)}</td>
for (let i = 0; i < added; i++) html += _buildRecentRowHtml(rows[i]); <td title="${escapeAttr(row.link)}">${escapeHtml(row.link)}</td>
tbody.insertAdjacentHTML('afterbegin', html); </tr>
} else { `).join('');
tbody.innerHTML = rows.map(_buildRecentRowHtml).join('');
}
_recentLastRenderedSig = sig;
_recentLastRenderedLen = rows.length;
// Event delegation bind once, not per-row // Event delegation bind once, not per-row
if (!_recentListenersBound) { if (!_recentListenersBound) {