Fix keyboard shortcuts help button in bottom right corner
ci/woodpecker/push/woodpecker Pipeline was successful
Details
ci/woodpecker/push/woodpecker Pipeline was successful
Details
This commit is contained in:
parent
f1b1daf751
commit
0179b6debf
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue