diff --git a/public/scripts/keyboard.js b/public/scripts/keyboard.js
index 88246bdcb..cc3c0274e 100644
--- a/public/scripts/keyboard.js
+++ b/public/scripts/keyboard.js
@@ -1,14 +1,14 @@
-/* All selectors that should act as keyboard buttons by default */
-const buttonSelectors = ['.menu_button', '.right_menu_button', '.custom_selectable_button', '.selectable_button'];
+/* All selectors that should act as interactables / keyboard buttons by default */
+const interactableSelectors = ['.menu_button', '.right_menu_button', '.custom_interactable', '.interactable'];
-const SELECTABLE_BUTTON_CLASS = 'selectable_button';
-const CUSTOM_SELECTABE_BUTTON_CLASS = 'custom_selectable_button';
+export const INTERACTABLE_CONTROL_CLASS = 'interactable';
+export const CUSTOM_INTERACTABLE_CONTROL_CLASS = 'custom_interactable';
-const NOT_FOCUSABLE_CLASS = 'not_focusable';
-const DISABLED_CLASS = 'disabled';
+export const NOT_FOCUSABLE_CONTROL_CLASS = 'not_focusable';
+export const DISABLED_CONTROL_CLASS = 'disabled';
/**
- * An observer that will check if any new buttons are added to the body
+ * An observer that will check if any new interactables are added to the body
* @type {MutationObserver}
*/
const observer = new MutationObserver(mutations => {
@@ -16,20 +16,20 @@ const observer = new MutationObserver(mutations => {
if (mutation.type === 'childList') {
mutation.addedNodes.forEach(node => {
if (node.nodeType === Node.ELEMENT_NODE && node instanceof Element) {
- // Check if the node itself is a button
- if (isKeyboardButton(node)) {
- enableKeyboardButton(node);
+ // Check if the node itself is an interactable
+ if (isKeyboardInteractable(node)) {
+ makeKeyboardInteractable(node);
}
- // Check for any descendants that might be buttons
- const newButtons = getAllButtons(node);
- enableKeyboardButton(...newButtons);
+ // Check for any descendants that might be an interactable
+ const interactables = getAllInteractables(node);
+ makeKeyboardInteractable(...interactables);
}
});
} else if (mutation.type === 'attributes') {
const target = mutation.target;
if (mutation.attributeName === 'class' && target instanceof Element) {
- if (isKeyboardButton(target)) {
- enableKeyboardButton(target);
+ if (isKeyboardInteractable(target)) {
+ makeKeyboardInteractable(target);
}
}
}
@@ -37,94 +37,94 @@ const observer = new MutationObserver(mutations => {
});
/**
- * Registers a button class (for example for an exatension) and makes it keyboard-selectable.
+ * Registers an interactable class (for example for an extension) and makes it keyboard interactable.
* Optionally apply the 'not_focusable' and 'disabled' classes if needed.
*
- * @param {string} buttonSelector - The CSS selector for the button (Supports class combinations, chained via dots like tag.actionable, and sub selectors)
- * @param {object} [options={}] - Optional settings for the button class
- * @param {boolean} [options.disabledByDefault=false] - Whether buttons of this class should be disabled by default
- * @param {boolean} [options.notFocusableByDefault=false] - Whether buttons of this class should not be focusable by default
+ * @param {string} interactableSelector - The CSS selector for the interactable (Supports class combinations, chained via dots like tag.actionable, and sub selectors)
+ * @param {object} [options={}] - Optional settings for the interactable
+ * @param {boolean} [options.disabledByDefault=false] - Whether interactables of this class should be disabled by default
+ * @param {boolean} [options.notFocusableByDefault=false] - Whether interactables of this class should not be focusable by default
*/
-export function registerKeyboardButtonClass(buttonSelector, { disabledByDefault = false, notFocusableByDefault = false } = {}) {
- buttonSelectors.push(buttonSelector);
+export function registerInteractableType(interactableSelector, { disabledByDefault = false, notFocusableByDefault = false } = {}) {
+ interactableSelectors.push(interactableSelector);
- const buttons = document.querySelectorAll(buttonSelector);
+ const interactables = document.querySelectorAll(interactableSelector);
if (disabledByDefault || notFocusableByDefault) {
- buttons.forEach(button => {
- if (disabledByDefault) button.classList.add(DISABLED_CLASS);
- if (notFocusableByDefault) button.classList.add(NOT_FOCUSABLE_CLASS);
+ interactables.forEach(interactable => {
+ if (disabledByDefault) interactable.classList.add(DISABLED_CONTROL_CLASS);
+ if (notFocusableByDefault) interactable.classList.add(NOT_FOCUSABLE_CONTROL_CLASS);
});
}
- enableKeyboardButton(...buttons);
+ makeKeyboardInteractable(...interactables);
}
/**
- * Checks if the given button is a keyboard-enabled button.
+ * Checks if the given control is a keyboard-enabled interactable.
*
- * @param {Element} button - The button element to check
- * @returns {boolean} Returns true if the button is a keyboard button, false otherwise
+ * @param {Element} control - The control element to check
+ * @returns {boolean} Returns true if the control is a keyboard interactable, false otherwise
*/
-export function isKeyboardButton(button) {
- // Check if this button matches any of the selectors
- return buttonSelectors.some(selector => button.matches(selector));
+export function isKeyboardInteractable(control) {
+ // Check if this control matches any of the selectors
+ return interactableSelectors.some(selector => control.matches(selector));
}
/**
- * Sets a
- * Adds the 'tabindex' attribute to buttons that are not marked as 'not_focusable' or 'disabled'
+ * Makes all the given controls keyboard interactable and sets their state.
+ * If the control doesn't have any of the classes, it will be set to a custom-enabled keyboard interactable.
*
- * @param {Element[]} buttons - The buttons to add the 'tabindex' attribute to
+ * @param {Element[]} interactables - The controls to make interactable and set their state
*/
-export function enableKeyboardButton(...buttons) {
- buttons.forEach(button => {
- // If this button doesn't have any of the classes, lets say the caller knows this and wants this to be a custom-enabled keyboard button.
- if (!isKeyboardButton(button)) {
- button.classList.add(CUSTOM_SELECTABE_BUTTON_CLASS);
+export function makeKeyboardInteractable(...interactables) {
+ interactables.forEach(interactable => {
+ // If this control doesn't have any of the classes, lets say the caller knows this and wants this to be a custom-enabled keyboard control.
+ if (!isKeyboardInteractable(interactable)) {
+ interactable.classList.add(CUSTOM_INTERACTABLE_CONTROL_CLASS);
}
- // Just for CSS styling and future reference, every keyboard selectable control should have a common class
- if (!button.classList.contains(SELECTABLE_BUTTON_CLASS)) {
- button.classList.add(SELECTABLE_BUTTON_CLASS);
+ // Just for CSS styling and future reference, every keyboard interactable control should have a common class
+ if (!interactable.classList.contains(INTERACTABLE_CONTROL_CLASS)) {
+ interactable.classList.add(INTERACTABLE_CONTROL_CLASS);
}
// Set/remove the tabindex accordingly to the classes. Remembering if it had a custom value.
- if (!button.classList.contains(NOT_FOCUSABLE_CLASS) && !button.classList.contains(DISABLED_CLASS)) {
- if (!button.hasAttribute('tabindex')) {
- const tabIndex = button.getAttribute('data-original-tabindex') ?? '0';
- button.setAttribute('tabindex', tabIndex);
+ if (!interactable.classList.contains(NOT_FOCUSABLE_CONTROL_CLASS) && !interactable.classList.contains(DISABLED_CONTROL_CLASS)) {
+ if (!interactable.hasAttribute('tabindex')) {
+ const tabIndex = interactable.getAttribute('data-original-tabindex') ?? '0';
+ interactable.setAttribute('tabindex', tabIndex);
}
} else {
- button.setAttribute('data-original-tabindex', button.getAttribute('tabindex'));
- button.removeAttribute('tabindex');
+ interactable.setAttribute('data-original-tabindex', interactable.getAttribute('tabindex'));
+ interactable.removeAttribute('tabindex');
}
});
}
/**
- * Initializes the focusability of buttons on the given element or the document
+ * Initializes the focusability of controls on the given element or the document
*
- * @param {Element|Document} [element=document] - The element on which to initialize the button focus. Defaults to the document
+ * @param {Element|Document} [element=document] - The element on which to initialize the interactable state. Defaults to the document.
*/
-function initializeButtonFocus(element = document) {
- const buttons = getAllButtons(element);
- enableKeyboardButton(...buttons);
+function initializeInteractables(element = document) {
+ const interactables = getAllInteractables(element);
+ makeKeyboardInteractable(...interactables);
}
/**
- * Queries all buttons within the given element based on the button selectors and returns them as an array
+ * Queries all interactables within the given element based on the given selectors and returns them as an array
*
- * @param {Element|Document} element - The element within which to query the buttons
- * @returns {HTMLElement[]} An array containing all the buttons that match the button selectors
+ * @param {Element|Document} element - The element within which to query the interactables
+ * @returns {HTMLElement[]} An array containing all the interactables that match the given selectors
*/
-function getAllButtons(element) {
- // Query each selecter individually and combine all to a big array to return
- return [].concat(...buttonSelectors.map(selector => Array.from(element.querySelectorAll(`${selector}`))));
+function getAllInteractables(element) {
+ // Query each selector individually and combine all to a big array to return
+ return [].concat(...interactableSelectors.map(selector => Array.from(element.querySelectorAll(`${selector}`))));
}
/**
- * Handles keydown events on the document to trigger click on Enter key press for buttons
+ * Handles keydown events on the document to trigger click on Enter key press for interactables
*
* @param {KeyboardEvent} event - The keyboard event
*/
@@ -133,26 +133,26 @@ function handleGlobalKeyDown(event) {
if (!(event.target instanceof HTMLElement))
return;
- // Only count enter on this button if no modifier key is pressed
+ // Only count enter on this interactable if no modifier key is pressed
if (event.altKey || event.ctrlKey || event.shiftKey)
return;
- // Traverse up the DOM tree to find the actual button element
+ // Traverse up the DOM tree to find the actual interactable element
let target = event.target;
- while (target && !isKeyboardButton(target)) {
+ while (target && !isKeyboardInteractable(target)) {
target = target.parentElement;
}
- // Trigger click if a valid button is found and it's not disabled
- if (target && !target.classList.contains(DISABLED_CLASS)) {
- console.debug('Triggering click on keyboard-focused button via Enter', target);
+ // Trigger click if a valid interactable is found and it's not disabled
+ if (target && !target.classList.contains(DISABLED_CONTROL_CLASS)) {
+ console.debug('Triggering click on keyboard-focused interactable control via Enter', target);
target.click();
}
}
}
/**
- * Initializes severial keyboard functionalities for ST
+ * Initializes several keyboard functionalities for ST
*/
export function initKeyboard() {
// Start observing the body for added elements and attribute changes
@@ -163,8 +163,8 @@ export function initKeyboard() {
attributeFilter: ['class']
});
- // Initialize tabindex for existing buttons
- initializeButtonFocus();
+ // Initialize interactable state for already existing controls
+ initializeInteractables();
// Add a global keydown listener
document.addEventListener('keydown', handleGlobalKeyDown);
diff --git a/public/scripts/tags.js b/public/scripts/tags.js
index 236948519..5b3331f82 100644
--- a/public/scripts/tags.js
+++ b/public/scripts/tags.js
@@ -22,7 +22,7 @@ import { ARGUMENT_TYPE, SlashCommandArgument, SlashCommandNamedArgument } from '
import { isMobile } from './RossAscends-mods.js';
import { POPUP_RESULT, POPUP_TYPE, callGenericPopup } from './popup.js';
import { debounce_timeout } from './constants.js';
-import { registerKeyboardButtonClass } from './keyboard.js';
+import { registerInteractableType } from './keyboard.js';
export {
TAG_FOLDER_TYPES,
@@ -1910,7 +1910,7 @@ export function initTags() {
eventSource.on(event_types.CHARACTER_DUPLICATED, copyTags);
eventSource.makeFirst(event_types.CHAT_CHANGED, () => selected_group ? applyTagsOnGroupSelect() : applyTagsOnCharacterSelect());
- registerKeyboardButtonClass('.tag.actionable');
+ registerInteractableType('.tag.actionable');
$(document).on('input', '#tag_view_list input[name="auto_sort_tags"]', (evt) => {
const toggle = $(evt.target).is(':checked');
diff --git a/public/style.css b/public/style.css
index 715b1d3bd..885238919 100644
--- a/public/style.css
+++ b/public/style.css
@@ -213,11 +213,11 @@ table.responsiveTable {
/* Keyboard/focus navigation styling */
/** Mimic the outline of keyboard navigation for most most focusable controls */
-.selectable_button {
+.interactable {
border-radius: 5px;
}
-.selectable_button:focus {
+.interactable:focus {
outline: 1px solid var(--white100);
}