More generic keyboard event handling
This commit is contained in:
parent
ace8555a09
commit
2e1426e945
@ -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');
|
||||||
|
@ -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
64
src/util/events.ts
Normal 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();
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user