insomnia/packages/insomnia-app/app/ui/components/modals/add-key-combination-modal.js
2019-03-13 00:11:02 +07:00

146 lines
4.3 KiB
JavaScript

// @flow
import React, { PureComponent } from 'react';
import autobind from 'autobind-decorator';
import classnames from 'classnames';
import Modal from '../base/modal';
import ModalHeader from '../base/modal-header';
import ModalBody from '../base/modal-body';
import type { KeyCombination } from '../../../common/hotkeys';
import { constructKeyCombinationDisplay, isModifierKeyCode } from '../../../common/hotkeys';
import { keyboardKeys } from '../../../common/keyboard-keys';
import * as misc from '../../../common/misc';
type Props = {};
type State = {
hotKeyRefId: string | null,
checkKeyCombinationDuplicate: Function,
onAddKeyCombination: Function,
pressedKeyCombination: KeyCombination | null,
};
@autobind
class AddKeyCombinationModal extends PureComponent<Props, State> {
_modal: Modal | null;
constructor(props: Props) {
super(props);
this.state = {
hotKeyRefId: null,
checkKeyCombinationDuplicate: misc.nullFn,
onAddKeyCombination: misc.nullFn,
pressedKeyCombination: null,
};
}
_setModalRef(modal: ?Modal) {
this._modal = modal;
}
_handleKeyDown(e: KeyboardEvent) {
e.preventDefault();
e.stopPropagation();
// Handle keypress without modifiers.
if (!e.ctrlKey && !e.altKey && !e.shiftKey && !e.metaKey) {
// esc key is for closing dialog, don't record it.
if (e.keyCode === keyboardKeys.esc.keyCode) {
// Hiding modal is already handled by underlying modal.
return;
}
// enter key is for saving previously entered key combination, don't record it.
if (e.keyCode === keyboardKeys.enter.keyCode) {
const {
hotKeyRefId,
checkKeyCombinationDuplicate,
onAddKeyCombination,
pressedKeyCombination,
} = this.state;
// Exit immediately if no key combination is pressed,
// pressed key code is unknown,
// or pressed key combination is incomplete (only modifiers are pressed).
if (
pressedKeyCombination == null ||
pressedKeyCombination.keyCode === 0 ||
isModifierKeyCode(pressedKeyCombination.keyCode)
) {
this.hide();
return;
}
// Reject duplicate key combination.
if (checkKeyCombinationDuplicate(pressedKeyCombination)) {
return;
}
// Accept new key combination.
onAddKeyCombination(hotKeyRefId, pressedKeyCombination);
this.hide();
return;
}
}
const pressed: KeyCombination = {
ctrl: e.ctrlKey,
alt: e.altKey,
shift: e.shiftKey,
meta: e.metaKey,
keyCode: e.keyCode,
};
this.setState({
pressedKeyCombination: pressed,
});
}
show(hotKeyRefId: string, checkKeyCombinationDuplicate: Function, onAddKeyCombination: Function) {
this.setState({
hotKeyRefId: hotKeyRefId,
checkKeyCombinationDuplicate: checkKeyCombinationDuplicate,
onAddKeyCombination: onAddKeyCombination,
pressedKeyCombination: null,
});
this._modal && this._modal.show();
}
hide() {
this._modal && this._modal.hide();
}
render() {
const { checkKeyCombinationDuplicate, pressedKeyCombination } = this.state;
let keyCombDisplay = '';
let isDuplicate = false;
if (pressedKeyCombination != null) {
keyCombDisplay = constructKeyCombinationDisplay(pressedKeyCombination, true).toLowerCase();
isDuplicate = checkKeyCombinationDuplicate(pressedKeyCombination);
}
const duplicateMessageClasses = classnames('margin-bottom margin-left faint italic txt-md', {
hidden: !isDuplicate,
});
return (
<Modal
ref={this._setModalRef}
onKeyDown={this._handleKeyDown}
className="shortcuts add-key-comb-modal">
<ModalHeader>Add Keyboard Shortcut</ModalHeader>
<ModalBody noScroll>
<div className="pad-left pad-right pad-top pad-bottom-sm">
<div className="form-control form-control--outlined">
<label>
Press desired key combination and then press ENTER.
<input type="text" className="key-comb" value={keyCombDisplay} disabled />
</label>
</div>
</div>
<div className={duplicateMessageClasses}>Duplicate key combination</div>
</ModalBody>
</Modal>
);
}
}
export default AddKeyCombinationModal;