Fix keyboard shortcuts help button in bottom right corner
ci/woodpecker/push/woodpecker Pipeline was successful Details

This commit is contained in:
colin 2025-07-04 22:41:29 -04:00
parent f1b1daf751
commit 0179b6debf
1 changed files with 181 additions and 166 deletions

View File

@ -1,171 +1,6 @@
/** /**
* Keyboard shortcuts for Project Ploughshares Transaction Management System * 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 * Show a modal with hotkey reference
@ -336,6 +171,176 @@ function showGoToModal() {
bsModal.show(); 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 * Add hotkey tooltips to elements
*/ */
@ -348,12 +353,22 @@ function addHotkeyTooltips() {
helpLink.className = 'position-fixed bottom-0 end-0 p-3'; helpLink.className = 'position-fixed bottom-0 end-0 p-3';
helpLink.innerHTML = ` helpLink.innerHTML = `
<button type="button" class="btn btn-sm btn-secondary" onclick="showHotkeyReference()" <button type="button" class="btn btn-sm btn-secondary" onclick="showHotkeyReference()"
title="Show Keyboard Shortcuts (H)"> title="Show Keyboard Shortcuts (H)" id="hotkeyHelpButton">
<i class="bi bi-keyboard"></i> <span class="d-none d-md-inline">Keyboard Shortcuts</span> <i class="bi bi-keyboard"></i> <span class="d-none d-md-inline">Keyboard Shortcuts</span>
</button> </button>
`; `;
document.body.appendChild(helpLink); 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 // Page-specific tooltips
if (currentPath === '/' || currentPath === '/index.html') { if (currentPath === '/' || currentPath === '/index.html') {
// Transaction list page // Transaction list page