Fix session close button with non-blocking confirmation modal
Replace blocking confirm() dialog with custom non-blocking modal to prevent browser warning issues when users have "don't show warnings" enabled. Changes: - Add showConfirmModal() method with Promise-based async modal - Update closeSession() to use non-blocking modal - Update deleteSession() to use non-blocking modal - Add complete CSS styling for confirmation modal - Support keyboard (Escape key) and click-outside to close - Responsive design for mobile devices - Dark theme matching existing UI Fixes issue where close button completely stopped working after browser blocked confirm() dialog and user selected "don't show warnings". Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -170,7 +170,7 @@ class SessionTabs {
|
||||
}
|
||||
|
||||
/**
|
||||
* Close a session (with confirmation)
|
||||
* Close a session (with non-blocking confirmation modal)
|
||||
*/
|
||||
async closeSession(sessionId) {
|
||||
const session = this.sessions.find(s => s.id === sessionId);
|
||||
@@ -178,8 +178,14 @@ class SessionTabs {
|
||||
|
||||
const sessionName = this.getSessionName(session);
|
||||
|
||||
// Confirm before closing
|
||||
if (!confirm(`Close session "${sessionName}"?`)) {
|
||||
// Show non-blocking confirmation modal
|
||||
const confirmed = await this.showConfirmModal(
|
||||
'Close Session',
|
||||
`Are you sure you want to close "${escapeHtml(sessionName)}"?`,
|
||||
'Close Session'
|
||||
);
|
||||
|
||||
if (!confirmed) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -287,6 +293,93 @@ class SessionTabs {
|
||||
document.getElementById('session-context-menu')?.remove();
|
||||
}
|
||||
|
||||
/**
|
||||
* Show a non-blocking confirmation modal
|
||||
* @param {string} title - Modal title
|
||||
* @param {string} message - Confirmation message
|
||||
* @param {string} confirmText - Text for confirm button (default: "Confirm")
|
||||
* @returns {Promise<boolean>} - True if confirmed, false otherwise
|
||||
*/
|
||||
showConfirmModal(title, message, confirmText = 'Confirm') {
|
||||
return new Promise((resolve) => {
|
||||
// Remove existing modal if present
|
||||
const existingModal = document.getElementById('confirm-modal-overlay');
|
||||
if (existingModal) existingModal.remove();
|
||||
|
||||
// Create overlay
|
||||
const overlay = document.createElement('div');
|
||||
overlay.id = 'confirm-modal-overlay';
|
||||
overlay.className = 'confirm-modal-overlay';
|
||||
|
||||
// Create modal
|
||||
const modal = document.createElement('div');
|
||||
modal.className = 'confirm-modal';
|
||||
modal.innerHTML = `
|
||||
<div class="confirm-modal-header">
|
||||
<h3 class="confirm-modal-title">${escapeHtml(title)}</h3>
|
||||
</div>
|
||||
<div class="confirm-modal-body">
|
||||
<p class="confirm-modal-message">${message}</p>
|
||||
</div>
|
||||
<div class="confirm-modal-footer">
|
||||
<button class="btn-confirm-cancel" id="confirm-modal-cancel">Cancel</button>
|
||||
<button class="btn-confirm-ok" id="confirm-modal-ok">${escapeHtml(confirmText)}</button>
|
||||
</div>
|
||||
`;
|
||||
|
||||
overlay.appendChild(modal);
|
||||
document.body.appendChild(overlay);
|
||||
|
||||
// Prevent body scroll
|
||||
document.body.style.overflow = 'hidden';
|
||||
|
||||
// Trigger animation
|
||||
setTimeout(() => {
|
||||
overlay.classList.add('visible');
|
||||
modal.classList.add('visible');
|
||||
}, 10);
|
||||
|
||||
// Handle confirm button
|
||||
document.getElementById('confirm-modal-ok').addEventListener('click', () => {
|
||||
closeModal(true);
|
||||
});
|
||||
|
||||
// Handle cancel button
|
||||
document.getElementById('confirm-modal-cancel').addEventListener('click', () => {
|
||||
closeModal(false);
|
||||
});
|
||||
|
||||
// Close on overlay click
|
||||
overlay.addEventListener('click', (e) => {
|
||||
if (e.target === overlay) {
|
||||
closeModal(false);
|
||||
}
|
||||
});
|
||||
|
||||
// Close on Escape key
|
||||
const escapeHandler = (e) => {
|
||||
if (e.key === 'Escape') {
|
||||
closeModal(false);
|
||||
document.removeEventListener('keydown', escapeHandler);
|
||||
}
|
||||
};
|
||||
document.addEventListener('keydown', escapeHandler);
|
||||
|
||||
// Function to close modal
|
||||
function closeModal(result) {
|
||||
overlay.classList.remove('visible');
|
||||
modal.classList.remove('visible');
|
||||
|
||||
setTimeout(() => {
|
||||
document.removeEventListener('keydown', escapeHandler);
|
||||
overlay.remove();
|
||||
document.body.style.overflow = '';
|
||||
resolve(result);
|
||||
}, 200);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Rename a session
|
||||
*/
|
||||
@@ -362,7 +455,13 @@ class SessionTabs {
|
||||
async deleteSession(session) {
|
||||
const sessionName = this.getSessionName(session);
|
||||
|
||||
if (!confirm(`Permanently delete "${sessionName}"? This cannot be undone.`)) {
|
||||
const confirmed = await this.showConfirmModal(
|
||||
'Delete Session',
|
||||
`Are you sure you want to permanently delete "${escapeHtml(sessionName)}"? This action cannot be undone.`,
|
||||
'Delete'
|
||||
);
|
||||
|
||||
if (!confirmed) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -424,4 +523,145 @@ if (document.readyState === 'loading') {
|
||||
window.sessionTabs.initialize();
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// Add CSS Styles
|
||||
// ============================================================
|
||||
|
||||
(function() {
|
||||
const style = document.createElement('style');
|
||||
style.textContent = `
|
||||
/* Confirm Modal Overlay */
|
||||
.confirm-modal-overlay {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background: rgba(0, 0, 0, 0.7);
|
||||
backdrop-filter: blur(4px);
|
||||
z-index: 10000;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 20px;
|
||||
opacity: 0;
|
||||
transition: opacity 0.2s ease;
|
||||
}
|
||||
|
||||
.confirm-modal-overlay.visible {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
/* Confirm Modal */
|
||||
.confirm-modal {
|
||||
background: #1a1a1a;
|
||||
border: 1px solid #333;
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.5);
|
||||
width: 100%;
|
||||
max-width: 400px;
|
||||
overflow: hidden;
|
||||
transform: scale(0.95);
|
||||
transition: transform 0.2s ease;
|
||||
}
|
||||
|
||||
.confirm-modal.visible {
|
||||
transform: scale(1);
|
||||
}
|
||||
|
||||
/* Header */
|
||||
.confirm-modal-header {
|
||||
padding: 20px 20px 12px 20px;
|
||||
border-bottom: 1px solid #333;
|
||||
}
|
||||
|
||||
.confirm-modal-title {
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
color: #e0e0e0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
/* Body */
|
||||
.confirm-modal-body {
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.confirm-modal-message {
|
||||
font-size: 14px;
|
||||
color: #b0b0b0;
|
||||
margin: 0;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
/* Footer */
|
||||
.confirm-modal-footer {
|
||||
padding: 12px 20px 20px 20px;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
/* Buttons */
|
||||
.btn-confirm-cancel,
|
||||
.btn-confirm-ok {
|
||||
padding: 10px 20px;
|
||||
border-radius: 8px;
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s ease;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.btn-confirm-cancel {
|
||||
background: transparent;
|
||||
border: 1px solid #333;
|
||||
color: #e0e0e0;
|
||||
}
|
||||
|
||||
.btn-confirm-cancel:hover {
|
||||
background: #252525;
|
||||
border-color: #444;
|
||||
}
|
||||
|
||||
.btn-confirm-ok {
|
||||
background: linear-gradient(135deg, #4a9eff 0%, #a78bfa 100%);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.btn-confirm-ok:hover {
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 4px 12px rgba(74, 158, 255, 0.4);
|
||||
}
|
||||
|
||||
.btn-confirm-ok:active {
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
/* Responsive */
|
||||
@media (max-width: 640px) {
|
||||
.confirm-modal {
|
||||
max-width: 90%;
|
||||
}
|
||||
|
||||
.confirm-modal-header,
|
||||
.confirm-modal-body,
|
||||
.confirm-modal-footer {
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
.confirm-modal-footer {
|
||||
flex-direction: column-reverse;
|
||||
}
|
||||
|
||||
.btn-confirm-cancel,
|
||||
.btn-confirm-ok {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
`;
|
||||
document.head.appendChild(style);
|
||||
})();
|
||||
|
||||
console.log('[SessionTabs] Module loaded');
|
||||
|
||||
Reference in New Issue
Block a user