More generic keyboard event handling

This commit is contained in:
James Lyne 2021-05-28 22:31:08 +01:00
parent ace8555a09
commit 2e1426e945
3 changed files with 69 additions and 65 deletions

View File

@ -50,6 +50,7 @@ import {MutationTypes} from "@/store/mutation-types";
import "@/assets/icons/players.svg"; import "@/assets/icons/players.svg";
import "@/assets/icons/maps.svg"; import "@/assets/icons/maps.svg";
import {nextTick} from "vue"; import {nextTick} from "vue";
import {handleKeyboardEvent} from "@/util/events";
export default defineComponent({ export default defineComponent({
components: { components: {
@ -113,41 +114,8 @@ export default defineComponent({
return; return;
} }
const sectionHeadings: HTMLElement[] = Array.from(this.$el.querySelectorAll('.section__heading button')), const sectionHeadings: HTMLElement[] = Array.from(this.$el.querySelectorAll('.section__heading button'));
position = sectionHeadings.indexOf(e.target as HTMLElement); handleKeyboardEvent(e, sectionHeadings);
if(position === -1) {
return;
}
let newPosition;
switch(e.key) {
case 'ArrowDown':
newPosition = position + 1;
break;
case 'ArrowUp':
newPosition = position - 1;
break;
case 'Home':
newPosition = 0;
break;
case 'End':
newPosition = sectionHeadings.length - 1;
break;
default:
return;
}
if(newPosition >= sectionHeadings.length) {
newPosition = 0
} else if(newPosition < 0) {
newPosition = sectionHeadings.length - 1;
}
e.preventDefault();
e.stopImmediatePropagation();
sectionHeadings[newPosition].focus();
}, },
togglePlayers() { togglePlayers() {
useStore().commit(MutationTypes.TOGGLE_UI_ELEMENT_VISIBILITY, 'players'); useStore().commit(MutationTypes.TOGGLE_UI_ELEMENT_VISIBILITY, 'players');

View File

@ -21,6 +21,7 @@
<script lang="ts"> <script lang="ts">
import {defineComponent} from 'vue'; import {defineComponent} from 'vue';
import {handleKeyboardEvent} from "@/util/events";
export default defineComponent({ export default defineComponent({
name: 'RadioList', name: 'RadioList',
@ -30,36 +31,7 @@ export default defineComponent({
methods: { methods: {
onKeydown(e: KeyboardEvent) { onKeydown(e: KeyboardEvent) {
if(e.key === 'ArrowUp' || e.key === 'ArrowDown' || e.key === 'ArrowLeft' || e.key === 'ArrowRight') { handleKeyboardEvent(e, Array.from((e.currentTarget as HTMLFieldSetElement).elements) as HTMLElement[])
const fieldset = e.currentTarget as HTMLFieldSetElement,
position = Array.from(fieldset.elements).indexOf(e.target as HTMLElement);
if(position < 0) {
return;
}
let newPosition = (e.key === 'ArrowUp' || e.key === 'ArrowLeft') ? position - 1 : position + 1;
if(newPosition < 0) {
newPosition = fieldset.elements.length - 1;
} else if (newPosition >= fieldset.elements.length) {
newPosition = 0;
}
(fieldset.elements[newPosition] as HTMLElement).focus();
e.preventDefault();
} else if(e.key === 'Enter') {
if(e.target instanceof HTMLInputElement && e.target.type === 'radio') {
const mouseEvent = new MouseEvent('click', {
ctrlKey: e.ctrlKey,
shiftKey: e.shiftKey,
metaKey: e.metaKey,
altKey: e.altKey,
});
e.target.dispatchEvent(mouseEvent);
}
}
} }
} }
}); });

64
src/util/events.ts Normal file
View File

@ -0,0 +1,64 @@
const navigationKeys = new Set<string>([
'ArrowUp',
'ArrowDown',
'ArrowLeft',
'ArrowRight',
'Home',
'End'
]);
export const handleKeyboardEvent = (e: KeyboardEvent, elements: HTMLElement[]) => {
if(!e.target) {
return;
}
if(navigationKeys.has(e.key)) {
const position = elements.indexOf(e.target as HTMLElement);
if(position < 0) {
return;
}
let newPosition = position;
switch(e.key) {
case 'ArrowUp':
case 'ArrowLeft':
newPosition = position - 1;
break;
case 'ArrowDown':
case 'ArrowRight':
newPosition = position + 1;
break;
case 'Home':
newPosition = 0;
break;
case 'End':
newPosition = elements.length - 1;
break;
}
if(newPosition < 0) {
newPosition = elements.length - 1;
} else if(newPosition >= elements.length) {
newPosition = 0;
}
(elements[newPosition] as HTMLElement).focus();
e.preventDefault();
} else if(e.key === 'Enter' && e.target) {
const mouseEvent = new MouseEvent('click', {
ctrlKey: e.ctrlKey,
shiftKey: e.shiftKey,
metaKey: e.metaKey,
altKey: e.altKey,
bubbles: true,
});
e.target.dispatchEvent(mouseEvent);
e.preventDefault();
}
}