2020-09-06 14:00:25 +02:00
|
|
|
import * as React from 'react';
|
|
|
|
import { useState, useEffect, KeyboardEvent } from 'react';
|
|
|
|
|
2020-11-07 17:59:37 +02:00
|
|
|
import KeymapService from '@joplin/lib/services/KeymapService';
|
2020-09-06 14:00:25 +02:00
|
|
|
import styles_ from './styles';
|
|
|
|
|
2020-11-07 17:59:37 +02:00
|
|
|
import { _ } from '@joplin/lib/locale';
|
2020-09-06 14:00:25 +02:00
|
|
|
const keymapService = KeymapService.instance();
|
|
|
|
|
|
|
|
export interface ShortcutRecorderProps {
|
|
|
|
onSave: (event: { commandName: string, accelerator: string }) => void,
|
|
|
|
onReset: (event: { commandName: string }) => void,
|
|
|
|
onCancel: (event: { commandName: string }) => void,
|
|
|
|
onError: (event: { recorderError: Error }) => void,
|
|
|
|
initialAccelerator: string
|
|
|
|
commandName: string,
|
|
|
|
themeId: number
|
|
|
|
}
|
|
|
|
|
|
|
|
export const ShortcutRecorder = ({ onSave, onReset, onCancel, onError, initialAccelerator, commandName, themeId }: ShortcutRecorderProps) => {
|
|
|
|
const styles = styles_(themeId);
|
|
|
|
|
|
|
|
const [accelerator, setAccelerator] = useState(initialAccelerator);
|
|
|
|
const [saveAllowed, setSaveAllowed] = useState(true);
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
try {
|
|
|
|
// Only perform validations if there's an accelerator provided
|
|
|
|
// Otherwise performing a save means that it's going to be disabled
|
|
|
|
if (accelerator) {
|
|
|
|
keymapService.validateAccelerator(accelerator);
|
|
|
|
keymapService.validateKeymap({ accelerator, command: commandName });
|
|
|
|
}
|
|
|
|
|
|
|
|
// Discard previous errors
|
|
|
|
onError({ recorderError: null });
|
|
|
|
setSaveAllowed(true);
|
|
|
|
} catch (recorderError) {
|
|
|
|
onError({ recorderError });
|
|
|
|
setSaveAllowed(false);
|
|
|
|
}
|
|
|
|
}, [accelerator]);
|
|
|
|
|
2020-10-24 13:07:48 +02:00
|
|
|
const handleKeyDown = (event: KeyboardEvent<HTMLDivElement>) => {
|
2020-09-06 14:00:25 +02:00
|
|
|
event.preventDefault();
|
|
|
|
const newAccelerator = keymapService.domToElectronAccelerator(event);
|
|
|
|
|
|
|
|
switch (newAccelerator) {
|
|
|
|
case 'Enter':
|
|
|
|
if (saveAllowed) return onSave({ commandName, accelerator });
|
|
|
|
break;
|
|
|
|
case 'Escape':
|
|
|
|
return onCancel({ commandName });
|
|
|
|
case 'Backspace':
|
|
|
|
case 'Delete':
|
|
|
|
return setAccelerator('');
|
|
|
|
default:
|
|
|
|
setAccelerator(newAccelerator);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
return (
|
|
|
|
<div style={styles.recorderContainer}>
|
|
|
|
<input
|
|
|
|
value={accelerator}
|
|
|
|
placeholder={_('Press the shortcut')}
|
2020-10-24 13:07:48 +02:00
|
|
|
onKeyDown={handleKeyDown}
|
2020-09-06 14:00:25 +02:00
|
|
|
style={styles.recorderInput}
|
|
|
|
title={_('Press the shortcut and then press ENTER. Or, press BACKSPACE to clear the shortcut.')}
|
|
|
|
readOnly
|
|
|
|
autoFocus
|
|
|
|
/>
|
|
|
|
|
|
|
|
<button style={styles.inlineButton} disabled={!saveAllowed} onClick={() => onSave({ commandName, accelerator })}>
|
|
|
|
{_('Save')}
|
|
|
|
</button>
|
|
|
|
<button style={styles.inlineButton} onClick={() => onReset({ commandName })}>
|
|
|
|
{_('Restore')}
|
|
|
|
</button>
|
|
|
|
<button style={styles.inlineButton} onClick={() => onCancel({ commandName })}>
|
|
|
|
{_('Cancel')}
|
|
|
|
</button>
|
|
|
|
</div>
|
|
|
|
);
|
|
|
|
};
|