129 lines
3.9 KiB
TypeScript
129 lines
3.9 KiB
TypeScript
/**
|
|
* Copyright since 2025 Mifos Initiative
|
|
*
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
*/
|
|
|
|
import { Component, inject } from '@angular/core';
|
|
import {
|
|
MAT_DIALOG_DATA,
|
|
MatDialogRef,
|
|
MatDialogTitle,
|
|
MatDialogContent,
|
|
MatDialogActions
|
|
} from '@angular/material/dialog';
|
|
import { KeyboardShortcutService, ShortcutItem } from '../../core/services/keyboard-shortcut.service';
|
|
import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
|
|
import { FormsModule } from '@angular/forms';
|
|
import { MatButton } from '@angular/material/button';
|
|
import { MatFormField, MatLabel, MatError } from '@angular/material/form-field';
|
|
import { MatInput } from '@angular/material/input';
|
|
import { take } from 'rxjs/operators';
|
|
|
|
@Component({
|
|
selector: 'mifosx-inline-create-shortcut-dialog',
|
|
templateUrl: './inline-create-shortcut-dialog.component.html',
|
|
styleUrls: ['../keyboard-shortcuts-dialog/keyboard-shortcuts-dialog.component.scss'],
|
|
imports: [
|
|
...STANDALONE_SHARED_IMPORTS,
|
|
MatDialogTitle,
|
|
MatDialogContent,
|
|
MatDialogActions,
|
|
MatButton,
|
|
FormsModule,
|
|
MatFormField,
|
|
MatLabel,
|
|
MatInput
|
|
]
|
|
})
|
|
export class InlineCreateShortcutDialogComponent {
|
|
dialogRef = inject<MatDialogRef<InlineCreateShortcutDialogComponent>>(MatDialogRef);
|
|
data = inject(MAT_DIALOG_DATA);
|
|
private keyboardShortcutService = inject(KeyboardShortcutService);
|
|
|
|
newShortcut: Partial<ShortcutItem> = {
|
|
title: this.data.pageName,
|
|
route: this.data.route,
|
|
action: 'navigate',
|
|
key: '',
|
|
ctrlKey: false,
|
|
shiftKey: false,
|
|
altKey: false,
|
|
custom: true,
|
|
id: 'custom_' + Date.now()
|
|
};
|
|
|
|
validationError: string | null = null;
|
|
|
|
formatShortcut(item: Partial<ShortcutItem>): string {
|
|
if (!item || (!item.key && !item.ctrlKey && !item.shiftKey && !item.altKey)) return '';
|
|
const parts = [];
|
|
if (item.ctrlKey) parts.push('Ctrl');
|
|
if (item.shiftKey) parts.push('Shift');
|
|
if (item.altKey) parts.push('Alt');
|
|
if (item.key) parts.push(item.key.toUpperCase());
|
|
return parts.join(' + ');
|
|
}
|
|
|
|
onKeyDown(event: KeyboardEvent) {
|
|
event.preventDefault();
|
|
event.stopPropagation();
|
|
|
|
// Ignore if only modifier keys are pressed
|
|
if ([
|
|
'Control',
|
|
'Shift',
|
|
'Alt',
|
|
'Meta'
|
|
].includes(event.key)) {
|
|
return;
|
|
}
|
|
|
|
this.newShortcut.ctrlKey = event.ctrlKey;
|
|
this.newShortcut.shiftKey = event.shiftKey;
|
|
this.newShortcut.altKey = event.altKey;
|
|
this.newShortcut.key = event.key.toLowerCase();
|
|
this.validationError = null;
|
|
}
|
|
|
|
save() {
|
|
if (!this.newShortcut.title || this.newShortcut.title.trim() === '') {
|
|
this.validationError = 'Shortcut Name is required';
|
|
return;
|
|
}
|
|
if (!this.newShortcut.key) {
|
|
this.validationError = 'Key combination is required';
|
|
return;
|
|
}
|
|
|
|
const keyStr = `${!!this.newShortcut.ctrlKey}-${!!this.newShortcut.shiftKey}-${!!this.newShortcut.altKey}-${this.newShortcut.key.toLowerCase()}`;
|
|
|
|
this.keyboardShortcutService.activeShortcuts$.pipe(take(1)).subscribe((shortcuts) => {
|
|
// Check for duplicates
|
|
const seen = new Set<string>();
|
|
for (const s of shortcuts) {
|
|
seen.add(`${!!s.ctrlKey}-${!!s.shiftKey}-${!!s.altKey}-${s.key.toLowerCase()}`);
|
|
}
|
|
|
|
if (seen.has(keyStr)) {
|
|
this.validationError = `Duplicate shortcut detected: ${this.formatShortcut(this.newShortcut)}`;
|
|
return;
|
|
}
|
|
|
|
// Add and save
|
|
if (this.newShortcut.route) {
|
|
this.newShortcut.route = this.keyboardShortcutService.normalizeRouteStr(this.newShortcut.route);
|
|
}
|
|
shortcuts.push(this.newShortcut as ShortcutItem);
|
|
this.keyboardShortcutService.updateShortcuts(shortcuts);
|
|
this.dialogRef.close(true);
|
|
});
|
|
}
|
|
|
|
cancel() {
|
|
this.dialogRef.close(false);
|
|
}
|
|
}
|