From 05ac6cd7569fca78ace5371decfe79cfe6f6774e Mon Sep 17 00:00:00 2001 From: Bruno Charest Date: Thu, 4 Jun 2026 16:06:39 -0400 Subject: [PATCH] =?UTF-8?q?fix:=20rewrite=20backup=20viewer=20close=20butt?= =?UTF-8?q?on=20=E2=80=94=20match=20editor-btn=20pattern?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Close button: (same HTML pattern as AdminPanel editor-btn) - Handler: addEventListener via DOM query in setBody() after innerHTML (same JS pattern as AdminPanel) - Removed all inline onclick, global capture handler, window._backupViewerClose - CSS: .backup-close-btn now matches .editor-btn style (bordered icon button) - Escape key + overlay click still work for closing --- frontend/js/backups.js | 94 +++++++++++++----------------------------- frontend/style.css | 20 ++++----- 2 files changed, 39 insertions(+), 75 deletions(-) diff --git a/frontend/js/backups.js b/frontend/js/backups.js index f6e00cf..79c0552 100644 --- a/frontend/js/backups.js +++ b/frontend/js/backups.js @@ -23,8 +23,8 @@ const state = { path: null, backups: [], overlay: null, - leftVersion: null, // timestamp of backup shown on left - rightVersion: null, // timestamp of backup shown on right, or null for current + leftVersion: null, + rightVersion: null, diffText: '', }; @@ -32,11 +32,6 @@ const state = { // Public API // --------------------------------------------------------------------------- -/** - * Open the backup/diff viewer for a file. - * @param {string} vault - Vault name - * @param {string} path - Relative file path - */ export async function openBackupViewer(vault, path) { state.vault = vault; state.path = path; @@ -45,16 +40,13 @@ export async function openBackupViewer(vault, path) { state.rightVersion = null; state.diffText = ''; - // Create and show overlay const overlay = createOverlay(); document.body.appendChild(overlay); state.overlay = overlay; requestAnimationFrame(() => overlay.classList.add('active')); - // Show loading state setBody(renderLoading()); - // Fetch backups try { const data = await api(`/api/file/${encodeURIComponent(vault)}/backups?path=${encodeURIComponent(path)}`); state.backups = data.backups || []; @@ -69,14 +61,9 @@ export async function openBackupViewer(vault, path) { return; } - // Auto-select: left = most recent, right = current state.leftVersion = state.backups[0].timestamp; state.rightVersion = null; - - // Render version selectors renderMainView(); - - // Load initial diff await loadDiff(); } @@ -84,16 +71,6 @@ export async function openBackupViewer(vault, path) { // DOM helpers // --------------------------------------------------------------------------- -// Global click handler: catches close button clicks anywhere in the document -document.addEventListener('click', function(e) { - const btn = e.target.closest ? e.target.closest('.backup-close-btn') : null; - if (btn && state.overlay) { - e.stopPropagation(); - e.preventDefault(); - close(); - } -}, true); // capture phase — fires before other handlers - function createOverlay() { const overlay = document.createElement('div'); overlay.className = 'obsigate-modal-overlay backup-viewer-overlay'; @@ -108,25 +85,33 @@ function createOverlay() { // Keyboard: Escape closes the viewer _escHandler = (e) => { - if (e.key === 'Escape' && state.overlay) { - close(); - } + if (e.key === 'Escape' && state.overlay) close(); }; document.addEventListener('keydown', _escHandler); return overlay; } +/** Replace panel content and re-bind the close button. */ function setBody(html) { const panel = document.getElementById('backup-viewer-panel'); - if (panel) panel.innerHTML = html; + if (!panel) return; + panel.innerHTML = html; + safeCreateIcons(); + // Bind close button — same pattern as AdminPanel + const closeBtn = panel.querySelector('.backup-close-btn'); + if (closeBtn) { + closeBtn.addEventListener('click', (e) => { + e.stopPropagation(); + close(); + }); + } } let _escHandler = null; function close() { if (!state.overlay) return; - // Remove keyboard listener if (_escHandler) { document.removeEventListener('keydown', _escHandler); _escHandler = null; @@ -138,18 +123,18 @@ function close() { }, 200); } -// Expose globally for inline onclick handlers -window._backupViewerClose = close; - // --------------------------------------------------------------------------- // Rendering // --------------------------------------------------------------------------- +/** Close button HTML — same pattern as AdminPanel editor-btn */ +const CLOSE_BTN = ''; + function renderLoading() { return `

Backups

- + ${CLOSE_BTN}
@@ -160,10 +145,10 @@ function renderLoading() { } function renderError(msg) { - return \` + return `

Backups

- + ${CLOSE_BTN}

${escapeHtml(msg)}

@@ -171,10 +156,10 @@ function renderError(msg) { } function renderEmpty() { - return \` + return `
-

Backups — \${escapeHtml(state.path)}

- +

Backups — ${escapeHtml(state.path)}

+ ${CLOSE_BTN}

Aucun backup disponible pour ce fichier.

@@ -205,7 +190,7 @@ function renderMainView() {
${b.length} backup${b.length > 1 ? 's' : ''} - + ${CLOSE_BTN}
@@ -234,10 +219,7 @@ function renderMainView() {
`; setBody(html); - - // Bind events bindEvents(); - safeCreateIcons(); } // --------------------------------------------------------------------------- @@ -245,17 +227,12 @@ function renderMainView() { // --------------------------------------------------------------------------- function bindEvents() { - const panel = document.getElementById('backup-viewer-panel'); - if (!panel) return; - - // Left select const leftSelect = document.getElementById('backup-left-select'); leftSelect?.addEventListener('change', async () => { state.leftVersion = parseInt(leftSelect.value); await loadDiff(); }); - // Right select const rightSelect = document.getElementById('backup-right-select'); rightSelect?.addEventListener('change', async () => { const val = rightSelect.value; @@ -263,7 +240,6 @@ function bindEvents() { await loadDiff(); }); - // Restore button const restoreBtn = document.getElementById('backup-restore-btn'); restoreBtn?.addEventListener('click', async () => { await restoreBackup(); @@ -324,10 +300,8 @@ async function restoreBackup() { if (resp && resp.success) { showToast('Fichier restauré avec succès', 'success'); - // Refresh sidebar and close await refreshSidebarTreePreservingState(); close(); - // Reload current file if open if (typeof TabManager !== 'undefined' && TabManager.reloadCurrent) { TabManager.reloadCurrent(); } @@ -360,20 +334,10 @@ function renderDiff(diffText) { for (const line of lines) { let cssClass = 'diff-context'; let prefix = ' '; - - if (line.startsWith('@@')) { - cssClass = 'diff-hunk'; - prefix = ''; - } else if (line.startsWith('+')) { - cssClass = 'diff-add'; - prefix = '+'; - } else if (line.startsWith('-')) { - cssClass = 'diff-del'; - prefix = '-'; - } else if (line.startsWith('---') || line.startsWith('+++')) { - cssClass = 'diff-header-line'; - prefix = ''; - } + if (line.startsWith('@@')) { cssClass = 'diff-hunk'; prefix = ''; } + else if (line.startsWith('+')) { cssClass = 'diff-add'; prefix = '+'; } + else if (line.startsWith('-')) { cssClass = 'diff-del'; prefix = '-'; } + else if (line.startsWith('---') || line.startsWith('+++')) { cssClass = 'diff-header-line'; prefix = ''; } html += `${prefix}
${escapeHtml(line)}
`; } diff --git a/frontend/style.css b/frontend/style.css index ce6f505..8b75480 100644 --- a/frontend/style.css +++ b/frontend/style.css @@ -7250,24 +7250,24 @@ body.popup-mode .content-area { } .backup-close-btn { - width: 32px; - height: 32px; - border: none; + width: 36px; + height: 36px; + padding: 0; + border: 1px solid var(--border); border-radius: 6px; background: transparent; - color: var(--text-muted); - font-size: 1.4rem; + color: var(--text-secondary); cursor: pointer; - display: flex; + transition: all 150ms ease; + display: inline-flex; align-items: center; justify-content: center; - line-height: 1; - transition: color 0.15s, background 0.15s; + flex: 0 0 auto; } .backup-close-btn:hover { - color: var(--text-primary); - background: var(--bg-tertiary); + color: var(--accent); + border-color: var(--accent); } .backup-toolbar {