/** * Keyboard Shortcuts for Delphi Consulting Group Database System * Replicates legacy Pascal system shortcuts for user familiarity */ let keyboardShortcutsEnabled = true; function initializeKeyboardShortcuts() { document.addEventListener('keydown', handleKeyboardShortcuts); console.log('Keyboard shortcuts initialized'); } function handleKeyboardShortcuts(event) { if (!keyboardShortcutsEnabled) { return; } // Don't process shortcuts if user is typing in input fields const activeElement = document.activeElement; const isInputField = ['INPUT', 'TEXTAREA', 'SELECT'].includes(activeElement.tagName) || activeElement.contentEditable === 'true'; // Allow specific shortcuts even in input fields const allowedInInputs = ['F1', 'Escape']; const keyName = getKeyName(event); if (isInputField && !allowedInInputs.includes(keyName)) { return; } // Handle shortcuts based on key combination const shortcut = getShortcutKey(event); switch (shortcut) { // Help case 'F1': event.preventDefault(); showHelp(); break; // Navigation shortcuts case 'Alt+C': event.preventDefault(); navigateTo('/customers'); break; case 'Alt+F': event.preventDefault(); navigateTo('/files'); break; case 'Alt+L': event.preventDefault(); navigateTo('/financial'); break; case 'Alt+D': event.preventDefault(); navigateTo('/documents'); break; case 'Alt+A': event.preventDefault(); navigateTo('/admin'); break; // Global search case 'Ctrl+F': event.preventDefault(); focusGlobalSearch(); break; // Form shortcuts case 'Ctrl+N': event.preventDefault(); newRecord(); break; case 'Ctrl+S': event.preventDefault(); saveRecord(); break; case 'F9': event.preventDefault(); editMode(); break; case 'F2': event.preventDefault(); completeAction(); break; case 'F8': event.preventDefault(); clearForm(); break; case 'Delete': if (!isInputField) { event.preventDefault(); deleteRecord(); } break; case 'Escape': event.preventDefault(); cancelAction(); break; // Legacy system shortcuts case 'F10': event.preventDefault(); showMenu(); break; case 'Alt+M': event.preventDefault(); showMemo(); break; case 'Alt+T': event.preventDefault(); toggleTimer(); break; case 'Alt+B': event.preventDefault(); showBalanceSummary(); break; // Quick creation shortcuts case 'Ctrl+Shift+C': event.preventDefault(); newCustomer(); break; case 'Ctrl+Shift+F': event.preventDefault(); newFile(); break; case 'Ctrl+Shift+T': event.preventDefault(); newTransaction(); break; // Date navigation (legacy system feature) case '+': if (!isInputField && isDateField(activeElement)) { event.preventDefault(); changeDateBy(1); } break; case '-': if (!isInputField && isDateField(activeElement)) { event.preventDefault(); changeDateBy(-1); } break; // Table navigation case 'ArrowUp': if (!isInputField && isInTable()) { event.preventDefault(); navigateTable('up'); } break; case 'ArrowDown': if (!isInputField && isInTable()) { event.preventDefault(); navigateTable('down'); } break; case 'PageUp': if (!isInputField && isInTable()) { event.preventDefault(); navigateTable('pageup'); } break; case 'PageDown': if (!isInputField && isInTable()) { event.preventDefault(); navigateTable('pagedown'); } break; case 'Home': if (!isInputField && isInTable()) { event.preventDefault(); navigateTable('home'); } break; case 'End': if (!isInputField && isInTable()) { event.preventDefault(); navigateTable('end'); } break; case 'Enter': if (!isInputField && isInTable()) { event.preventDefault(); openRecord(); } break; } } function getShortcutKey(event) { const parts = []; if (event.ctrlKey) parts.push('Ctrl'); if (event.altKey) parts.push('Alt'); if (event.shiftKey) parts.push('Shift'); let key = event.key; // Handle special keys switch (event.keyCode) { case 112: key = 'F1'; break; case 113: key = 'F2'; break; case 114: key = 'F3'; break; case 115: key = 'F4'; break; case 116: key = 'F5'; break; case 117: key = 'F6'; break; case 118: key = 'F7'; break; case 119: key = 'F8'; break; case 120: key = 'F9'; break; case 121: key = 'F10'; break; case 122: key = 'F11'; break; case 123: key = 'F12'; break; case 46: key = 'Delete'; break; case 27: key = 'Escape'; break; case 33: key = 'PageUp'; break; case 34: key = 'PageDown'; break; case 35: key = 'End'; break; case 36: key = 'Home'; break; case 37: key = 'ArrowLeft'; break; case 38: key = 'ArrowUp'; break; case 39: key = 'ArrowRight'; break; case 40: key = 'ArrowDown'; break; case 13: key = 'Enter'; break; case 187: key = '+'; break; // Plus key case 189: key = '-'; break; // Minus key } parts.push(key); return parts.join('+'); } function getKeyName(event) { switch (event.keyCode) { case 112: return 'F1'; case 27: return 'Escape'; default: return event.key; } } // Navigation functions function navigateTo(url) { window.location.href = url; } function focusGlobalSearch() { const searchInput = document.querySelector('#global-search, .search-input, [name="search"]'); if (searchInput) { searchInput.focus(); searchInput.select(); } else { navigateTo('/search'); } } // Form action functions function newRecord() { const newBtn = document.querySelector('.btn-new, [data-action="new"], .btn-primary[href*="new"]'); if (newBtn) { newBtn.click(); } else { showToast('New record shortcut not available on this page', 'info'); } } function saveRecord() { const saveBtn = document.querySelector('.btn-save, [data-action="save"], .btn-success[type="submit"]'); if (saveBtn) { saveBtn.click(); } else { // Try to submit the main form const form = document.querySelector('form.main-form, form'); if (form) { form.submit(); } else { showToast('Save shortcut not available on this page', 'info'); } } } function editMode() { const editBtn = document.querySelector('.btn-edit, [data-action="edit"]'); if (editBtn) { editBtn.click(); } else { showToast('Edit mode shortcut not available on this page', 'info'); } } function completeAction() { const completeBtn = document.querySelector('.btn-complete, [data-action="complete"], .btn-primary'); if (completeBtn) { completeBtn.click(); } else { saveRecord(); // Fallback to save } } function clearForm() { const clearBtn = document.querySelector('.btn-clear, [data-action="clear"]'); if (clearBtn) { clearBtn.click(); } else { // Clear all form inputs const form = document.querySelector('form'); if (form) { form.reset(); showToast('Form cleared', 'info'); } } } function deleteRecord() { const deleteBtn = document.querySelector('.btn-delete, [data-action="delete"], .btn-danger'); if (deleteBtn) { deleteBtn.click(); } else { showToast('Delete shortcut not available on this page', 'info'); } } function cancelAction() { // Close modals first const modal = document.querySelector('.modal.show'); if (modal) { const bsModal = bootstrap.Modal.getInstance(modal); if (bsModal) { bsModal.hide(); return; } } // Then try cancel buttons const cancelBtn = document.querySelector('.btn-cancel, [data-action="cancel"], .btn-secondary'); if (cancelBtn) { cancelBtn.click(); } else { window.history.back(); } } // Legacy system specific functions function showHelp() { const helpModal = document.querySelector('#shortcutsModal'); if (helpModal) { const modal = new bootstrap.Modal(helpModal); modal.show(); } else { showToast('Press F1 to see keyboard shortcuts', 'info'); } } function showMenu() { // Toggle main navigation menu on mobile or show dropdown const navbarToggler = document.querySelector('.navbar-toggler'); if (navbarToggler && !navbarToggler.classList.contains('collapsed')) { navbarToggler.click(); } else { showToast('Menu (F10) - Use Alt+C, Alt+F, Alt+L, Alt+D for navigation', 'info'); } } function showMemo() { const memoBtn = document.querySelector('[data-action="memo"], .btn-memo'); if (memoBtn) { memoBtn.click(); } else { showToast('Memo function not available on this page', 'info'); } } function toggleTimer() { const timerBtn = document.querySelector('[data-action="timer"], .btn-timer'); if (timerBtn) { timerBtn.click(); } else { showToast('Timer function not available on this page', 'info'); } } function showBalanceSummary() { const balanceBtn = document.querySelector('[data-action="balance"], .btn-balance'); if (balanceBtn) { balanceBtn.click(); } else { showToast('Balance summary not available on this page', 'info'); } } // Quick creation functions function newCustomer() { navigateTo('/customers/new'); } function newFile() { navigateTo('/files/new'); } function newTransaction() { navigateTo('/financial/new'); } // Utility functions function isDateField(element) { if (!element) return false; return element.type === 'date' || element.classList.contains('date-field') || element.getAttribute('data-type') === 'date'; } function isInTable() { const activeElement = document.activeElement; return activeElement && ( activeElement.closest('table') || activeElement.classList.contains('table-row') || activeElement.getAttribute('role') === 'gridcell' ); } function changeDateBy(days) { const activeElement = document.activeElement; if (isDateField(activeElement)) { const currentDate = new Date(activeElement.value || Date.now()); currentDate.setDate(currentDate.getDate() + days); activeElement.value = currentDate.toISOString().split('T')[0]; activeElement.dispatchEvent(new Event('change', { bubbles: true })); } } function navigateTable(direction) { // Table navigation implementation would depend on the specific table structure showToast(`Table navigation: ${direction}`, 'info'); } function openRecord() { const activeElement = document.activeElement; const row = activeElement.closest('tr, .table-row'); if (row) { const link = row.querySelector('a, [data-action="open"]'); if (link) { link.click(); } } } function showToast(message, type = 'info') { // Create toast element const toastHtml = `