Initial commit
Dieser Commit ist enthalten in:
141
frontend/js/shortcuts.js
Normale Datei
141
frontend/js/shortcuts.js
Normale Datei
@ -0,0 +1,141 @@
|
||||
/**
|
||||
* TASKMATE - Keyboard Shortcuts Module
|
||||
* =====================================
|
||||
* Global keyboard shortcuts (only non-browser-conflicting)
|
||||
*/
|
||||
|
||||
import store from './store.js';
|
||||
import { $ } from './utils.js';
|
||||
|
||||
class ShortcutsManager {
|
||||
constructor() {
|
||||
this.shortcuts = new Map();
|
||||
this.isEnabled = true;
|
||||
|
||||
this.registerDefaultShortcuts();
|
||||
this.bindEvents();
|
||||
}
|
||||
|
||||
bindEvents() {
|
||||
document.addEventListener('keydown', (e) => this.handleKeydown(e));
|
||||
}
|
||||
|
||||
handleKeydown(e) {
|
||||
// Don't handle shortcuts when typing in inputs
|
||||
if (this.isInputFocused()) return;
|
||||
|
||||
// Don't handle when modals are open (except escape)
|
||||
if (store.get('openModals').length > 0 && e.key !== 'Escape') return;
|
||||
|
||||
// Don't handle when disabled
|
||||
if (!this.isEnabled) return;
|
||||
|
||||
const combo = this.getKeyCombo(e);
|
||||
const handler = this.shortcuts.get(combo);
|
||||
|
||||
if (handler) {
|
||||
e.preventDefault();
|
||||
handler(e);
|
||||
}
|
||||
}
|
||||
|
||||
getKeyCombo(e) {
|
||||
const parts = [];
|
||||
|
||||
if (e.ctrlKey || e.metaKey) parts.push('Ctrl');
|
||||
if (e.altKey) parts.push('Alt');
|
||||
if (e.shiftKey) parts.push('Shift');
|
||||
|
||||
// Get the key
|
||||
let key = e.key;
|
||||
if (key === ' ') key = 'Space';
|
||||
if (key.length === 1) key = key.toUpperCase();
|
||||
|
||||
parts.push(key);
|
||||
|
||||
return parts.join('+');
|
||||
}
|
||||
|
||||
isInputFocused() {
|
||||
const activeElement = document.activeElement;
|
||||
const tagName = activeElement?.tagName.toLowerCase();
|
||||
const isContentEditable = activeElement?.contentEditable === 'true';
|
||||
|
||||
return ['input', 'textarea', 'select'].includes(tagName) || isContentEditable;
|
||||
}
|
||||
|
||||
// =====================
|
||||
// SHORTCUT REGISTRATION
|
||||
// =====================
|
||||
|
||||
register(combo, handler, description = '') {
|
||||
this.shortcuts.set(combo, handler);
|
||||
// Store description for help display
|
||||
handler.description = description;
|
||||
}
|
||||
|
||||
unregister(combo) {
|
||||
this.shortcuts.delete(combo);
|
||||
}
|
||||
|
||||
enable() {
|
||||
this.isEnabled = true;
|
||||
}
|
||||
|
||||
disable() {
|
||||
this.isEnabled = false;
|
||||
}
|
||||
|
||||
// =====================
|
||||
// DEFAULT SHORTCUTS
|
||||
// =====================
|
||||
|
||||
registerDefaultShortcuts() {
|
||||
// Only Escape - close modals (doesn't conflict with browser)
|
||||
this.register('Escape', () => this.handleEscape(), 'Schließen / Abbrechen');
|
||||
}
|
||||
|
||||
// =====================
|
||||
// SHORTCUT HANDLERS
|
||||
// =====================
|
||||
|
||||
handleEscape() {
|
||||
const openModals = store.get('openModals');
|
||||
|
||||
if (openModals.length > 0) {
|
||||
// Close the topmost modal
|
||||
const topModal = openModals[openModals.length - 1];
|
||||
window.dispatchEvent(new CustomEvent('modal:close', {
|
||||
detail: { modalId: topModal }
|
||||
}));
|
||||
} else {
|
||||
// Clear selection
|
||||
store.clearSelection();
|
||||
}
|
||||
}
|
||||
|
||||
showHelp() {
|
||||
// No longer needed - shortcuts removed
|
||||
}
|
||||
|
||||
// =====================
|
||||
// HELP DISPLAY
|
||||
// =====================
|
||||
|
||||
getShortcutsList() {
|
||||
// Minimal shortcuts that don't conflict with browser
|
||||
return {
|
||||
actions: {
|
||||
title: 'Aktionen',
|
||||
shortcuts: [
|
||||
{ combo: 'Escape', description: 'Dialog schließen / Auswahl aufheben' }
|
||||
]
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// Create and export singleton
|
||||
const shortcutsManager = new ShortcutsManager();
|
||||
|
||||
export default shortcutsManager;
|
||||
In neuem Issue referenzieren
Einen Benutzer sperren