import ClockIcon from '../../../components/icons/ClockIcon';
import { lazyLoadComponent } from '../../../components/lazyLoadComponent';
import DeferredSpinner from '../../../components/ui/DeferredSpinner';
+import { isInput, isShortcut } from '../../../helpers/keyboardEventHelpers';
import { KeyboardKeys } from '../../../helpers/keycodes';
import { translate, translateWithParameters } from '../../../helpers/l10n';
import { scrollToElement } from '../../../helpers/scrolling';
};
handleSKeyDown = (event: KeyboardEvent) => {
- const { tagName } = event.target as HTMLElement;
- const isInput = tagName === 'INPUT' || tagName === 'SELECT' || tagName === 'TEXTAREA';
- if (event.key === KeyboardKeys.KeyS && !isInput) {
+ if (isInput(event) || isShortcut(event)) {
+ return true;
+ }
+ if (event.key === KeyboardKeys.KeyS) {
event.preventDefault();
this.focusInput();
this.openSearch();
it('should open the results when pressing key S and close it when pressing Escape', () => {
const router = mockRouter();
const form = shallowRender({ router });
+ keydown({ key: KeyboardKeys.KeyS, ctrlKey: true });
+ expect(form.state().open).toBe(false);
keydown({ key: KeyboardKeys.KeyS });
expect(form.state().open).toBe(true);
elementKeydown(form.find('SearchBox'), KeyboardKeys.Escape);
import Suggestions from '../../../components/embed-docs-modal/Suggestions';
import BackIcon from '../../../components/icons/BackIcon';
import '../../../components/search-navigator.css';
+import { isInput, isShortcut } from '../../../helpers/keyboardEventHelpers';
import { KeyboardKeys } from '../../../helpers/keycodes';
import { translate } from '../../../helpers/l10n';
import {
};
handleKeyPress = (event: KeyboardEvent) => {
- const { tagName } = event.target as HTMLElement;
- const isInput = tagName === 'INPUT' || tagName === 'SELECT' || tagName === 'TEXTAREA';
- if (isInput) {
- return false;
+ if (isInput(event) || isShortcut(event)) {
+ return true;
}
switch (event.key) {
case KeyboardKeys.LeftArrow:
import { Button } from '../../../components/controls/buttons';
import ListFooter from '../../../components/controls/ListFooter';
import { Alert } from '../../../components/ui/Alert';
+import { isInput, isShortcut } from '../../../helpers/keyboardEventHelpers';
import { KeyboardCodes } from '../../../helpers/keycodes';
import { translate, translateWithParameters } from '../../../helpers/l10n';
import { formatMeasure, isDiffMetric, isPeriodBestValue } from '../../../helpers/measures';
}
handleKeyDown = (event: KeyboardEvent) => {
+ if (isInput(event) || isShortcut(event)) {
+ return true;
+ }
if (event.code === KeyboardCodes.UpArrow) {
event.preventDefault();
this.selectPrevious();
keydown({ code: KeyboardCodes.UpArrow });
expect(handleSelect).toBeCalledWith(FILES[2]);
+ keydown({ code: KeyboardCodes.RightArrow, ctrlKey: true });
+ expect(handleOpen).not.toBeCalled();
+
keydown({ code: KeyboardCodes.RightArrow });
expect(handleOpen).toBeCalled();
});
} from '../../../helpers/branch-like';
import handleRequiredAuthentication from '../../../helpers/handleRequiredAuthentication';
import { parseIssueFromResponse } from '../../../helpers/issues';
+import { isInput, isShortcut } from '../../../helpers/keyboardEventHelpers';
import { KeyboardCodes, KeyboardKeys } from '../../../helpers/keycodes';
import { translate, translateWithParameters } from '../../../helpers/l10n';
import {
return;
}
+ if (isInput(event) || isShortcut(event)) {
+ return true;
+ }
+
if (event.key === KeyboardKeys.Alt) {
event.preventDefault();
this.setState(actions.enableLocationsNavigator);
keydown({ code: KeyboardCodes.DownArrow });
expect(wrapper.state('selected')).toBe(ISSUES[3].key);
+ keydown({ code: KeyboardCodes.RightArrow, ctrlKey: true });
+ expect(push).not.toBeCalled();
keydown({ code: KeyboardCodes.RightArrow });
expect(push).toBeCalledTimes(1);
import classNames from 'classnames';
import * as React from 'react';
import BoxedTabs from '../../../components/controls/BoxedTabs';
+import { isInput, isShortcut } from '../../../helpers/keyboardEventHelpers';
import { KeyboardCodes } from '../../../helpers/keycodes';
import { translate } from '../../../helpers/l10n';
import { sanitizeString } from '../../../helpers/sanitize';
}
handleKeyboardNavigation = (event: KeyboardEvent) => {
+ if (isInput(event) || isShortcut(event)) {
+ return true;
+ }
if (event.code === KeyboardCodes.LeftArrow) {
event.preventDefault();
this.selectNeighboringTab(-1);
});
});
+it("shouldn't navigate when ctrl or command are pressed with up and down", () => {
+ const wrapper = mount<HotspotViewerTabs>(
+ <HotspotViewerTabs codeTabContent={<div>CodeTabContent</div>} hotspot={mockHotspot()} />
+ );
+
+ wrapper.setState({ currentTab: wrapper.state().tabs[0] });
+ wrapper
+ .instance()
+ .handleKeyboardNavigation(mockEvent({ code: KeyboardCodes.LeftArrow, metaKey: true }));
+
+ expect(wrapper.state().currentTab.key).toBe(TabKeys.Code);
+});
+
it('should navigate when up and down key are pressed', () => {
const wrapper = mount<HotspotViewerTabs>(
<HotspotViewerTabs codeTabContent={<div>CodeTabContent</div>} hotspot={mockHotspot()} />
import { difference } from 'lodash';
import * as React from 'react';
import SearchBox from '../../components/controls/SearchBox';
+import { isShortcut } from '../../helpers/keyboardEventHelpers';
import { KeyboardCodes } from '../../helpers/keycodes';
import { translateWithParameters } from '../../helpers/l10n';
import MultiSelectOption from './MultiSelectOption';
};
handleKeyboard = (event: KeyboardEvent) => {
+ if (isShortcut(event)) {
+ return true;
+ }
switch (event.code) {
case KeyboardCodes.DownArrow:
event.stopPropagation();
keydown({ code: KeyboardCodes.DownArrow });
expect(onHighlight).toBeCalledWith(COMPONENTS[0]);
+ keydown({ code: KeyboardCodes.RightArrow, metaKey: true });
+ expect(onSelect).not.toBeCalled();
keydown({ code: KeyboardCodes.RightArrow });
expect(onSelect).toBeCalledWith(COMPONENTS[0]);
keydown({ code: KeyboardCodes.Enter });
expect(onSelect).toBeCalledWith(COMPONENTS[0]);
+ keydown({ code: KeyboardCodes.LeftArrow, metaKey: true });
+ expect(onGoToParent).not.toBeCalled();
keydown({ code: KeyboardCodes.LeftArrow });
expect(onGoToParent).toBeCalled();
});
import * as React from 'react';
import PageActions from '../../components/ui/PageActions';
import { getComponentMeasureUniqueKey } from '../../helpers/component';
+import { isInput, isShortcut } from '../../helpers/keyboardEventHelpers';
import { KeyboardCodes } from '../../helpers/keycodes';
import { ComponentMeasure } from '../../types/types';
import { getWrappedDisplayName } from './utils';
}
handleKeyDown = (event: KeyboardEvent) => {
+ if (isInput(event) || isShortcut(event)) {
+ return true;
+ }
if (event.code === KeyboardCodes.UpArrow) {
event.preventDefault();
return this.skipIfFile(this.handleHighlightPrevious);
*/
import * as React from 'react';
import { setIssueAssignee } from '../../api/issues';
+import { isInput, isShortcut } from '../../helpers/keyboardEventHelpers';
import { KeyboardKeys } from '../../helpers/keycodes';
import { BranchLike } from '../../types/branch-like';
import { Issue as TypeIssue } from '../../types/types';
}
handleKeyDown = (event: KeyboardEvent) => {
- const { tagName } = event.target as HTMLElement;
- const isInput = tagName === 'INPUT' || tagName === 'SELECT' || tagName === 'TEXTAREA';
- if (isInput) {
- return false;
+ if (isInput(event) || isShortcut(event)) {
+ return true;
} else if (event.key === KeyboardKeys.KeyF) {
event.preventDefault();
return this.togglePopup('transition');
});
shallowRender({ onPopupToggle, issue, onCheck });
+ keydown({ key: KeyboardKeys.KeyF, metaKey: true });
+ expect(onPopupToggle).not.toBeCalledWith(issue.key, 'transition', undefined);
+
keydown({ key: KeyboardKeys.KeyF });
expect(onPopupToggle).toBeCalledWith(issue.key, 'transition', undefined);
keydown({ key: KeyboardKeys.KeyI });
expect(onPopupToggle).toBeCalledWith(issue.key, 'set-severity', undefined);
+ keydown({ key: KeyboardKeys.KeyC, metaKey: true });
+ expect(onPopupToggle).not.toBeCalledWith(issue.key, 'comment', undefined);
+
keydown({ key: KeyboardKeys.KeyC });
expect(onPopupToggle).toBeCalledWith(issue.key, 'comment', undefined);
keydown({ key: KeyboardKeys.Escape });
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2022 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+export function isShortcut(event: KeyboardEvent): boolean {
+ return event.ctrlKey || event.metaKey;
+}
+
+export function isInput(event: KeyboardEvent): boolean {
+ const { tagName } = event.target as HTMLElement;
+ return ['INPUT', 'SELECT', 'TEXTAREA'].includes(tagName);
+}
[KeyboardCodes.DownArrow]: 'down'
};
-export function keydown(args: { code?: KeyboardCodes; key?: KeyboardKeys }): void {
+export function keydown(args: {
+ code?: KeyboardCodes;
+ key?: KeyboardKeys;
+ metaKey?: boolean;
+ ctrlKey?: boolean;
+}): void {
const event = new KeyboardEvent('keydown', args as KeyboardEventInit);
document.dispatchEvent(event);
}