diff --git a/docker/ploughshares/static/js/hotkeys.js b/docker/ploughshares/static/js/hotkeys.js index ecbcbba..98f3014 100644 --- a/docker/ploughshares/static/js/hotkeys.js +++ b/docker/ploughshares/static/js/hotkeys.js @@ -1,171 +1,6 @@ /** * Keyboard shortcuts for Project Ploughshares Transaction Management System */ -document.addEventListener('DOMContentLoaded', function() { - // Initialize hotkeys - initHotkeys(); - - // Add hotkey tooltips to elements - addHotkeyTooltips(); -}); - -/** - * Initialize keyboard shortcuts - */ -function initHotkeys() { - document.addEventListener('keydown', function(event) { - // Skip if user is typing in an input field, textarea or has a modal open - if (isUserTyping() || isModalOpen()) { - return; - } - - // Get the current page based on URL - const currentPath = window.location.pathname; - - // Global shortcuts (available on all pages) - switch (event.key) { - case 'h': // Help - Show hotkey reference - event.preventDefault(); - showHotkeyReference(); - break; - case 'g': // Go to - if (event.altKey) { - event.preventDefault(); - showGoToModal(); - } - break; - } - - // Page-specific shortcuts - if (currentPath === '/' || currentPath === '/index.html') { - // Transaction list page - handleTransactionListHotkeys(event); - } else if (currentPath.startsWith('/transaction/') && !currentPath.includes('/edit')) { - // Transaction view page - handleTransactionViewHotkeys(event); - } else if (currentPath === '/pending-approval') { - // Pending approval page - handlePendingApprovalHotkeys(event); - } - }); -} - -/** - * Handle hotkeys for the transaction list page - */ -function handleTransactionListHotkeys(event) { - switch (event.key) { - case 'n': // New transaction - event.preventDefault(); - window.location.href = '/transaction/add'; - break; - case 'p': // Pending approval - event.preventDefault(); - window.location.href = '/pending-approval'; - break; - case 'f': // Focus search - event.preventDefault(); - const searchInput = document.getElementById('searchInput'); - if (searchInput) { - searchInput.focus(); - } - break; - case 'r': // Refresh - event.preventDefault(); - window.location.reload(); - break; - } -} - -/** - * Handle hotkeys for the transaction view page - */ -function handleTransactionViewHotkeys(event) { - switch (event.key) { - case 'e': // Edit - event.preventDefault(); - const editBtn = document.querySelector('a[href^="/transaction/"][href$="/edit"]'); - if (editBtn) { - editBtn.click(); - } - break; - case 'b': // Back to list - event.preventDefault(); - window.location.href = '/'; - break; - case 'ArrowLeft': // Previous transaction - event.preventDefault(); - const prevBtn = document.querySelector('a[aria-label="Previous transaction"]'); - if (prevBtn && !prevBtn.classList.contains('disabled') && !prevBtn.hasAttribute('disabled')) { - prevBtn.click(); - } - break; - case 'ArrowRight': // Next transaction - event.preventDefault(); - const nextBtn = document.querySelector('a[aria-label="Next transaction"]'); - if (nextBtn && !nextBtn.classList.contains('disabled') && !nextBtn.hasAttribute('disabled')) { - nextBtn.click(); - } - break; - case 'a': // Approve - event.preventDefault(); - const approveBtn = document.querySelector('button[data-bs-target="#approveModal"]'); - if (approveBtn) { - approveBtn.click(); - } - break; - } -} - -/** - * Handle hotkeys for the pending approval page - */ -function handlePendingApprovalHotkeys(event) { - switch (event.key) { - case 'b': // Back to list - event.preventDefault(); - window.location.href = '/'; - break; - case 'r': // Refresh - event.preventDefault(); - window.location.reload(); - break; - // Number keys 1-9 to quickly view transactions - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - event.preventDefault(); - const index = parseInt(event.key) - 1; - const viewButtons = document.querySelectorAll('a[aria-label^="View transaction"]'); - if (viewButtons.length > index) { - viewButtons[index].click(); - } - break; - } -} - -/** - * Check if user is currently typing in an input field - */ -function isUserTyping() { - const activeElement = document.activeElement; - return activeElement.tagName === 'INPUT' || - activeElement.tagName === 'TEXTAREA' || - activeElement.isContentEditable; -} - -/** - * Check if a modal is currently open - */ -function isModalOpen() { - return document.querySelector('.modal.show') !== null; -} /** * Show a modal with hotkey reference @@ -336,6 +171,176 @@ function showGoToModal() { bsModal.show(); } +// Make functions available globally +window.showHotkeyReference = showHotkeyReference; +window.showGoToModal = showGoToModal; + +document.addEventListener('DOMContentLoaded', function() { + // Initialize hotkeys + initHotkeys(); + + // Add hotkey tooltips to elements + addHotkeyTooltips(); +}); + +/** + * Initialize keyboard shortcuts + */ +function initHotkeys() { + document.addEventListener('keydown', function(event) { + // Skip if user is typing in an input field, textarea or has a modal open + if (isUserTyping() || isModalOpen()) { + return; + } + + // Get the current page based on URL + const currentPath = window.location.pathname; + + // Global shortcuts (available on all pages) + switch (event.key) { + case 'h': // Help - Show hotkey reference + event.preventDefault(); + showHotkeyReference(); + break; + case 'g': // Go to + if (event.altKey) { + event.preventDefault(); + showGoToModal(); + } + break; + } + + // Page-specific shortcuts + if (currentPath === '/' || currentPath === '/index.html') { + // Transaction list page + handleTransactionListHotkeys(event); + } else if (currentPath.startsWith('/transaction/') && !currentPath.includes('/edit')) { + // Transaction view page + handleTransactionViewHotkeys(event); + } else if (currentPath === '/pending-approval') { + // Pending approval page + handlePendingApprovalHotkeys(event); + } + }); +} + +/** + * Handle hotkeys for the transaction list page + */ +function handleTransactionListHotkeys(event) { + switch (event.key) { + case 'n': // New transaction + event.preventDefault(); + window.location.href = '/transaction/add'; + break; + case 'p': // Pending approval + event.preventDefault(); + window.location.href = '/pending-approval'; + break; + case 'f': // Focus search + event.preventDefault(); + const searchInput = document.getElementById('searchInput'); + if (searchInput) { + searchInput.focus(); + } + break; + case 'r': // Refresh + event.preventDefault(); + window.location.reload(); + break; + } +} + +/** + * Handle hotkeys for the transaction view page + */ +function handleTransactionViewHotkeys(event) { + switch (event.key) { + case 'e': // Edit + event.preventDefault(); + const editBtn = document.querySelector('a[href^="/transaction/"][href$="/edit"]'); + if (editBtn) { + editBtn.click(); + } + break; + case 'b': // Back to list + event.preventDefault(); + window.location.href = '/'; + break; + case 'ArrowLeft': // Previous transaction + event.preventDefault(); + const prevBtn = document.querySelector('a[aria-label="Previous transaction"]'); + if (prevBtn && !prevBtn.classList.contains('disabled') && !prevBtn.hasAttribute('disabled')) { + prevBtn.click(); + } + break; + case 'ArrowRight': // Next transaction + event.preventDefault(); + const nextBtn = document.querySelector('a[aria-label="Next transaction"]'); + if (nextBtn && !nextBtn.classList.contains('disabled') && !nextBtn.hasAttribute('disabled')) { + nextBtn.click(); + } + break; + case 'a': // Approve + event.preventDefault(); + const approveBtn = document.querySelector('button[data-bs-target="#approveModal"]'); + if (approveBtn) { + approveBtn.click(); + } + break; + } +} + +/** + * Handle hotkeys for the pending approval page + */ +function handlePendingApprovalHotkeys(event) { + switch (event.key) { + case 'b': // Back to list + event.preventDefault(); + window.location.href = '/'; + break; + case 'r': // Refresh + event.preventDefault(); + window.location.reload(); + break; + // Number keys 1-9 to quickly view transactions + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + event.preventDefault(); + const index = parseInt(event.key) - 1; + const viewButtons = document.querySelectorAll('a[aria-label^="View transaction"]'); + if (viewButtons.length > index) { + viewButtons[index].click(); + } + break; + } +} + +/** + * Check if user is currently typing in an input field + */ +function isUserTyping() { + const activeElement = document.activeElement; + return activeElement.tagName === 'INPUT' || + activeElement.tagName === 'TEXTAREA' || + activeElement.isContentEditable; +} + +/** + * Check if a modal is currently open + */ +function isModalOpen() { + return document.querySelector('.modal.show') !== null; +} + /** * Add hotkey tooltips to elements */ @@ -348,12 +353,22 @@ function addHotkeyTooltips() { helpLink.className = 'position-fixed bottom-0 end-0 p-3'; helpLink.innerHTML = ` `; document.body.appendChild(helpLink); + // Add click event listener directly + document.addEventListener('DOMContentLoaded', function() { + const hotkeyHelpButton = document.getElementById('hotkeyHelpButton'); + if (hotkeyHelpButton) { + hotkeyHelpButton.addEventListener('click', function() { + showHotkeyReference(); + }); + } + }); + // Page-specific tooltips if (currentPath === '/' || currentPath === '/index.html') { // Transaction list page