Browse Source

SONAR-16008 Fix keyboad navigation conflict

tags/9.4.0.54424
Jay 2 years ago
parent
commit
7f825acb51

+ 12
- 12
server/sonar-web/src/main/js/apps/security-hotspots/components/HotspotViewerTabs.tsx View File

@@ -18,9 +18,9 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import classNames from 'classnames';
import key from 'keymaster';
import * as React from 'react';
import BoxedTabs from '../../../components/controls/BoxedTabs';
import { KeyboardCodes } from '../../../helpers/keycodes';
import { translate } from '../../../helpers/l10n';
import { sanitizeString } from '../../../helpers/sanitize';
import { Hotspot } from '../../../types/security-hotspots';
@@ -49,8 +49,6 @@ export enum TabKeys {
FixRecommendation = 'fix'
}

const HOTSPOT_KEYMASTER_SCOPE = 'hotspots-list';

export default class HotspotViewerTabs extends React.PureComponent<Props, State> {
constructor(props: Props) {
super(props);
@@ -87,20 +85,22 @@ export default class HotspotViewerTabs extends React.PureComponent<Props, State>
this.unregisterKeyboardEvents();
}

registerKeyboardEvents() {
key.setScope(HOTSPOT_KEYMASTER_SCOPE);
key('left', HOTSPOT_KEYMASTER_SCOPE, () => {
handleKeyboardNavigation = (event: KeyboardEvent) => {
if (event.code === KeyboardCodes.LeftArrow) {
event.preventDefault();
this.selectNeighboringTab(-1);
return false;
});
key('right', HOTSPOT_KEYMASTER_SCOPE, () => {
} else if (event.code === KeyboardCodes.RightArrow) {
event.preventDefault();
this.selectNeighboringTab(+1);
return false;
});
}
};

registerKeyboardEvents() {
window.addEventListener('keydown', this.handleKeyboardNavigation);
}

unregisterKeyboardEvents() {
key.deleteScope(HOTSPOT_KEYMASTER_SCOPE);
window.removeEventListener('keydown', this.handleKeyboardNavigation);
}

handleSelectTabs = (tabKey: TabKeys) => {

+ 29
- 32
server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/HotspotViewerTabs-test.tsx View File

@@ -22,29 +22,28 @@ import * as React from 'react';
import BoxedTabs, { BoxedTabsProps } from '../../../../components/controls/BoxedTabs';
import { KeyboardCodes } from '../../../../helpers/keycodes';
import { mockHotspot, mockHotspotRule } from '../../../../helpers/mocks/security-hotspots';
import { mockUser } from '../../../../helpers/testMocks';
import { KEYCODE_MAP, keydown } from '../../../../helpers/testUtils';
import { mockEvent, mockUser } from '../../../../helpers/testMocks';
import HotspotViewerTabs, { TabKeys } from '../HotspotViewerTabs';

jest.mock('keymaster', () => {
const key: any = (bindKey: string, _: string, callback: Function) => {
document.addEventListener('keydown', (event: KeyboardEvent) => {
const keymasterCode = event.code && KEYCODE_MAP[event.code as KeyboardCodes];
if (keymasterCode && bindKey.split(',').includes(keymasterCode)) {
return callback();
}
return true;
});
};
let scope = 'hotspots-list';
key.getScope = () => scope;
key.setScope = (newScope: string) => {
scope = newScope;
};
key.deleteScope = jest.fn();
return key;
const originalAddEventListener = window.addEventListener;
const originalRemoveEventListener = window.removeEventListener;
beforeEach(() => {
Object.defineProperty(window, 'addEventListener', {
value: jest.fn()
});
Object.defineProperty(window, 'removeEventListener', {
value: jest.fn()
});
});
afterEach(() => {
Object.defineProperty(window, 'addEventListener', {
value: originalAddEventListener
});
Object.defineProperty(window, 'removeEventListener', {
value: originalRemoveEventListener
});
});

it('should render correctly', () => {
@@ -146,13 +145,13 @@ describe('keyboard navigation', () => {
const wrapper = shallowRender();

it.each([
['selecting next', 0, 1, 1],
['selecting previous', 1, -1, 0],
['selecting previous, non-existent', 0, -1, 0],
['selecting next, non-existent', 3, 1, 3]
])('should work when %s', (_, start, shift, expected) => {
['selecting next', 0, KeyboardCodes.RightArrow, 1],
['selecting previous', 1, KeyboardCodes.LeftArrow, 0],
['selecting previous, non-existent', 0, KeyboardCodes.LeftArrow, 0],
['selecting next, non-existent', 3, KeyboardCodes.RightArrow, 3]
])('should work when %s', (_, start, code, expected) => {
wrapper.setState({ currentTab: wrapper.state().tabs[start] });
wrapper.instance().selectNeighboringTab(shift);
wrapper.instance().handleKeyboardNavigation(mockEvent({ code }));

expect(wrapper.state().currentTab.key).toBe(tabList[expected]);
});
@@ -163,13 +162,11 @@ it('should navigate when up and down key are pressed', () => {
<HotspotViewerTabs codeTabContent={<div>CodeTabContent</div>} hotspot={mockHotspot()} />
);

const selectNeighboringTab = jest.spyOn(wrapper.instance(), 'selectNeighboringTab');
expect(window.addEventListener).toBeCalled();

keydown({ code: KeyboardCodes.LeftArrow });
expect(selectNeighboringTab).toBeCalledWith(-1);
wrapper.unmount();

keydown({ code: KeyboardCodes.RightArrow });
expect(selectNeighboringTab).toBeCalledWith(1);
expect(window.removeEventListener).toBeCalled();
});

function shallowRender(props?: Partial<HotspotViewerTabs['props']>) {

Loading…
Cancel
Save