insomnia/packages/insomnia-app/app/ui/components/settings/shortcuts.js
2020-01-06 14:19:35 -05:00

179 lines
5.9 KiB
JavaScript

// @flow
import React, { PureComponent } from 'react';
import autobind from 'autobind-decorator';
import Hotkey from '../hotkey';
import type { HotKeyDefinition, HotKeyRegistry, KeyCombination } from '../../../common/hotkeys';
import {
areKeyBindingsSameAsDefault,
areSameKeyCombinations,
constructKeyCombinationDisplay,
getPlatformKeyCombinations,
hotKeyRefs,
newDefaultKeyBindings,
newDefaultRegistry,
} from '../../../common/hotkeys';
import { Dropdown, DropdownButton, DropdownDivider, DropdownItem } from '../base/dropdown';
import { showModal } from '../modals';
import AddKeyCombinationModal from '../modals/add-key-combination-modal';
import PromptButton from '../base/prompt-button';
type Props = {
hotKeyRegistry: HotKeyRegistry,
handleUpdateKeyBindings: Function,
};
const HOT_KEY_DEFS: Array<HotKeyDefinition> = Object.keys(hotKeyRefs).map(k => hotKeyRefs[k]);
@autobind
class Shortcuts extends PureComponent<Props> {
/**
* Checks whether the given key combination already existed.
* @param newKeyComb the key combination to be checked.
* @returns {boolean} true if already existed.
*/
checkKeyCombinationDuplicate(newKeyComb: KeyCombination): boolean {
const { hotKeyRegistry } = this.props;
for (const hotKeyRefId in hotKeyRegistry) {
if (!hotKeyRegistry.hasOwnProperty(hotKeyRefId)) {
continue;
}
const keyCombs = getPlatformKeyCombinations(hotKeyRegistry[hotKeyRefId]);
for (const keyComb of keyCombs) {
if (areSameKeyCombinations(keyComb, newKeyComb)) {
return true;
}
}
}
return false;
}
/**
* Registers a new key combination under a hot key.
* @param hotKeyRefId the reference id of a hot key to be given the new key combination.
* @param keyComb the new key combination.
*/
addKeyCombination(hotKeyRefId: string, keyComb: KeyCombination) {
const { hotKeyRegistry, handleUpdateKeyBindings } = this.props;
const keyCombs = getPlatformKeyCombinations(hotKeyRegistry[hotKeyRefId]);
keyCombs.push(keyComb);
handleUpdateKeyBindings(hotKeyRegistry);
}
handleAddKeyCombination(hotKeyRefId: string) {
showModal(
AddKeyCombinationModal,
hotKeyRefId,
this.checkKeyCombinationDuplicate,
this.addKeyCombination,
);
}
handleRemoveKeyCombination(toBeRemoved: Object) {
const { hotKeyRefId, keyComb } = toBeRemoved;
const { hotKeyRegistry, handleUpdateKeyBindings } = this.props;
const keyCombs = getPlatformKeyCombinations(hotKeyRegistry[hotKeyRefId]);
let toBeRemovedIndex = -1;
keyCombs.forEach((existingKeyComb, idx) => {
if (areSameKeyCombinations(existingKeyComb, keyComb)) {
toBeRemovedIndex = idx;
}
});
if (toBeRemovedIndex >= 0) {
keyCombs.splice(toBeRemovedIndex, 1);
handleUpdateKeyBindings(hotKeyRegistry);
}
}
handleResetKeyBindings(hotKeyRefId: string) {
const { hotKeyRegistry, handleUpdateKeyBindings } = this.props;
hotKeyRegistry[hotKeyRefId] = newDefaultKeyBindings(hotKeyRefId);
handleUpdateKeyBindings(hotKeyRegistry);
}
handleResetAllKeyBindings() {
const { handleUpdateKeyBindings } = this.props;
handleUpdateKeyBindings(newDefaultRegistry());
}
renderHotKey(def: HotKeyDefinition, i: number) {
const keyBindings = this.props.hotKeyRegistry[def.id];
const keyCombinations = getPlatformKeyCombinations(keyBindings);
const hasRemoveItems = keyCombinations.length > 0;
const hasResetItems = !areKeyBindingsSameAsDefault(def.id, keyBindings);
return (
<tr key={i}>
<td>{def.description}</td>
<td className="text-right">
{keyCombinations.map((keyComb: KeyCombination, idx: number) => {
return (
<code key={idx} className="margin-left-sm">
<Hotkey keyCombination={keyComb} />
</code>
);
})}
</td>
<td className="text-right options">
<Dropdown outline>
<DropdownButton className="btn btn--clicky-small">
<i className="fa fa-gear" />
</DropdownButton>
<DropdownItem value={def.id} onClick={this.handleAddKeyCombination}>
<i className="fa fa-plus-circle" />
Add keyboard shortcut
</DropdownItem>
{hasRemoveItems && <DropdownDivider>Remove existing</DropdownDivider>}
{/* Dropdown items to remove key combinations. */
keyCombinations.map((keyComb: KeyCombination) => {
const display = constructKeyCombinationDisplay(keyComb, false);
return (
<DropdownItem
key={display}
value={{ hotKeyRefId: def.id, keyComb: keyComb }}
buttonClass={PromptButton}
onClick={this.handleRemoveKeyCombination}>
<i className="fa fa-trash-o" /> {display}
</DropdownItem>
);
})}
{hasResetItems && <DropdownDivider />}
{hasResetItems && (
<DropdownItem
value={def.id}
buttonClass={PromptButton}
onClick={this.handleResetKeyBindings}>
<i className="fa fa-empty" /> Reset keyboard shortcuts
</DropdownItem>
)}
</Dropdown>
</td>
</tr>
);
}
render() {
return (
<div className="shortcuts">
<div className="row-spaced margin-bottom-xs">
<div>
<PromptButton className="btn btn--clicky" onClick={this.handleResetAllKeyBindings}>
Reset all
</PromptButton>
</div>
</div>
<table className="table--fancy">
<tbody>
{HOT_KEY_DEFS.map((def: HotKeyDefinition, idx: number) => {
return this.renderHotKey(def, idx);
})}
</tbody>
</table>
</div>
);
}
}
export default Shortcuts;