Compare commits

..

No commits in common. "429ec419cff309b1e61a98aee494b600dfe10fed" and "59d52ce5daddb1d176e65b58dae39fd8c3f9f4d1" have entirely different histories.

2 changed files with 8 additions and 19 deletions

View File

@ -16,7 +16,6 @@ class BackupPage {
this.taskManager = (typeof TaskManager !== 'undefined') ? new TaskManager() : null; this.taskManager = (typeof TaskManager !== 'undefined') ? new TaskManager() : null;
this.eventBound = false; this.eventBound = false;
this._taskRefreshTimer = null; this._taskRefreshTimer = null;
this._ac = new AbortController(); // dispose() aborts this to remove the document listeners on unmount
} }
async init() { async init() {
@ -295,13 +294,13 @@ class BackupPage {
this.saveSection(saveBtn.dataset.backupSave); this.saveSection(saveBtn.dataset.backupSave);
return; return;
} }
}, { signal: this._ac.signal }); });
document.addEventListener('input', (e) => { document.addEventListener('input', (e) => {
if (e.target.id === 'backup-snapshot-filter' || e.target.id === 'backup-snapshot-repo') { if (e.target.id === 'backup-snapshot-filter' || e.target.id === 'backup-snapshot-repo') {
this.renderSnapshots(); this.renderSnapshots();
} }
}, { signal: this._ac.signal }); });
// Type select changes refresh the visible connection fields inline. // Type select changes refresh the visible connection fields inline.
// Retention preset changes are handled by applyRetentionPreset, which // Retention preset changes are handled by applyRetentionPreset, which
@ -324,17 +323,7 @@ class BackupPage {
if (presetSel) { if (presetSel) {
this.applyRetentionPreset(presetSel); this.applyRetentionPreset(presetSel);
} }
}, { signal: this._ac.signal }); });
}
/* Release everything this page attached to document/window so navigating
away (kernel unmount) can't leave stale listeners firing on the live DOM
the cause of the backup sidebar "content stacks on revisit" bug. Called by
the feature module's unmount(). */
dispose() {
try { this._ac && this._ac.abort(); } catch (_) {}
try { window.taskRefresh && window.taskRefresh.unregister('backups'); } catch (_) {}
if (this._taskRefreshTimer) { clearTimeout(this._taskRefreshTimer); this._taskRefreshTimer = null; }
} }

View File

@ -46,11 +46,11 @@ LP.features.register({
}, },
async unmount(ctx) { async unmount(ctx) {
// Release the page's document listeners + task-refresh registration so a // Best-effort teardown. BackupPage self-guards stale work via
// navigation away doesn't leave stale BackupPage listeners firing on the // (window.backupPage === this), so nulling the global neutralises any
// live DOM — the backup sidebar "content stacks on revisit" bug. dispose() // pending task-refresh repaint; we also drop its coordinator registration.
// aborts the click/input/change listeners and drops the coordinator reg. // A proper dispose() (removing the leaked document listeners) lands with
try { window.backupPage && window.backupPage.dispose(); } catch (_) {} // the Phase 5 backup decomposition.
try { ctx.services.tasks.refresh && ctx.services.tasks.refresh.unregister('backups'); } catch (_) {} try { ctx.services.tasks.refresh && ctx.services.tasks.refresh.unregister('backups'); } catch (_) {}
window.backupPage = null; window.backupPage = null;
}, },