Simplify key codes expression in Tags component (#4248)
* Simplifying this key codes expression in Tags component * Refactor KeyboardEvent keyCode to key * Simplify cyrillic letter regexp * Wrap condition in 2 lines
This commit is contained in:
parent
ae22dc93a9
commit
5e347a6f94
2 changed files with 78 additions and 21 deletions
52
app/javascript/shared/components/__tests__/tags.test.jsx
Normal file
52
app/javascript/shared/components/__tests__/tags.test.jsx
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
import { h } from 'preact';
|
||||
import { deep } from 'preact-render-spy';
|
||||
import Tags from '../tags';
|
||||
|
||||
describe('<Tags />', () => {
|
||||
beforeAll(() => {
|
||||
const publicId = document.createElement('meta');
|
||||
publicId.setAttribute('name', 'algolia-public-id');
|
||||
const publicKey = document.createElement('meta');
|
||||
publicKey.setAttribute('name', 'algolia-public-key');
|
||||
const environment = document.createElement('meta');
|
||||
environment.setAttribute('name', 'environment');
|
||||
document.body.appendChild(publicId);
|
||||
document.body.appendChild(publicKey);
|
||||
document.body.appendChild(environment);
|
||||
global.algoliasearch = () => ({
|
||||
initIndex: () => 'initIndex',
|
||||
});
|
||||
});
|
||||
|
||||
let tags;
|
||||
|
||||
beforeEach(() => {
|
||||
tags = deep(<Tags defaultValue="defaultValue" listing />);
|
||||
});
|
||||
|
||||
describe('handleKeyDown', () => {
|
||||
const preventDefaultMock = jest.fn();
|
||||
const createKeyDown = key => ({
|
||||
key,
|
||||
preventDefault: preventDefaultMock,
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
preventDefaultMock.mockClear();
|
||||
});
|
||||
|
||||
test('calls preventDefault on unused keyCode', () => {
|
||||
tags.find('#tag-input').simulate('keydown', createKeyDown('§'));
|
||||
tags.find('#tag-input').simulate('keydown', createKeyDown('1'));
|
||||
tags.find('#tag-input').simulate('keydown', createKeyDown('\\'));
|
||||
expect(preventDefaultMock).toHaveBeenCalledTimes(3);
|
||||
});
|
||||
|
||||
test('does not call preventDefault on used keyCode', () => {
|
||||
tags.find('#tag-input').simulate('keypress', createKeyDown('a'));
|
||||
tags.find('#tag-input').simulate('keypress', createKeyDown(','));
|
||||
tags.find('#tag-input').simulate('keypress', createKeyDown('Enter'));
|
||||
expect(preventDefaultMock).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
@ -2,16 +2,26 @@ import { h, Component } from 'preact';
|
|||
import PropTypes from 'prop-types';
|
||||
|
||||
const KEYS = {
|
||||
UP: 38,
|
||||
DOWN: 40,
|
||||
LEFT: 37,
|
||||
RIGHT: 39,
|
||||
TAB: 9,
|
||||
RETURN: 13,
|
||||
COMMA: 188,
|
||||
DELETE: 8,
|
||||
UP: 'ArrowUp',
|
||||
DOWN: 'ArrowDown',
|
||||
LEFT: 'ArrowLeft',
|
||||
RIGHT: 'ArrowRight',
|
||||
TAB: 'Tab',
|
||||
RETURN: 'Enter',
|
||||
COMMA: ',',
|
||||
DELETE: 'Backspace',
|
||||
};
|
||||
|
||||
const NAVIGATION_KEYS = [
|
||||
KEYS.COMMA,
|
||||
KEYS.DELETE,
|
||||
KEYS.LEFT,
|
||||
KEYS.RIGHT,
|
||||
KEYS.TAB,
|
||||
];
|
||||
|
||||
const LETTERS = /[a-z]/i;
|
||||
|
||||
/* TODO: Remove all instances of this.props.listing
|
||||
and refactor this component to be more generic */
|
||||
|
||||
|
|
@ -218,23 +228,23 @@ class Tags extends Component {
|
|||
|
||||
if (
|
||||
component.selected.length === this.props.maxTags &&
|
||||
e.keyCode === KEYS.COMMA
|
||||
e.key === KEYS.COMMA
|
||||
) {
|
||||
e.preventDefault();
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
(e.keyCode === KEYS.DOWN || e.keyCode === KEYS.TAB) &&
|
||||
(e.key === KEYS.DOWN || e.key === KEYS.TAB) &&
|
||||
!this.isBottomOfSearchResults &&
|
||||
component.props.defaultValue !== ''
|
||||
) {
|
||||
e.preventDefault();
|
||||
this.moveDownInSearchResults();
|
||||
} else if (e.keyCode === KEYS.UP && !this.isTopOfSearchResults) {
|
||||
} else if (e.key === KEYS.UP && !this.isTopOfSearchResults) {
|
||||
e.preventDefault();
|
||||
this.moveUpInSearchResults();
|
||||
} else if (e.keyCode === KEYS.RETURN && this.isSearchResultSelected) {
|
||||
} else if (e.key === KEYS.RETURN && this.isSearchResultSelected) {
|
||||
e.preventDefault();
|
||||
this.insertTag(
|
||||
component.state.searchResults[component.state.selectedIndex].name,
|
||||
|
|
@ -243,10 +253,10 @@ class Tags extends Component {
|
|||
setTimeout(() => {
|
||||
document.getElementById('tag-input').focus();
|
||||
}, 10);
|
||||
} else if (e.keyCode === KEYS.COMMA && !this.isSearchResultSelected) {
|
||||
} else if (e.key === KEYS.COMMA && !this.isSearchResultSelected) {
|
||||
this.resetSearchResults();
|
||||
this.clearSelectedSearchResult();
|
||||
} else if (e.keyCode === KEYS.DELETE) {
|
||||
} else if (e.key === KEYS.DELETE) {
|
||||
if (
|
||||
component.props.defaultValue[
|
||||
component.props.defaultValue.length - 1
|
||||
|
|
@ -255,13 +265,8 @@ class Tags extends Component {
|
|||
this.clearSelectedSearchResult();
|
||||
}
|
||||
} else if (
|
||||
(e.keyCode < 65 || e.keyCode > 90) &&
|
||||
e.keyCode != KEYS.COMMA &&
|
||||
e.keyCode != KEYS.DELETE &&
|
||||
e.keyCode != KEYS.LEFT &&
|
||||
e.keyCode != KEYS.RIGHT &&
|
||||
e.keyCode != KEYS.TAB
|
||||
) {
|
||||
!LETTERS.test(e.key) &&
|
||||
!NAVIGATION_KEYS.includes(e.key)) {
|
||||
e.preventDefault();
|
||||
}
|
||||
};
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue