Fix tabbing with hotswap multiple rows

- Add scroll-reset-container CSS class and handling
- Fix tabbing through hotswap favs by resetting position
This commit is contained in:
Wolfsblvt 2024-06-16 23:13:36 +02:00
parent 60b09a431a
commit f67ed6d22a
3 changed files with 75 additions and 19 deletions

View File

@ -4482,7 +4482,7 @@
<div class="right_menu_button fa-solid fa-list-ul" id="rm_button_characters" title="Select/Create Characters" data-i18n="[title]Select/Create Characters"></div> <div class="right_menu_button fa-solid fa-list-ul" id="rm_button_characters" title="Select/Create Characters" data-i18n="[title]Select/Create Characters"></div>
</div> </div>
<div id="HotSwapWrapper" class="alignitemscenter flex-container margin0auto wide100p"> <div id="HotSwapWrapper" class="alignitemscenter flex-container margin0auto wide100p">
<div class="hotswap avatars_inline flex-container expander" data-i18n="[no_favs]Favorite characters to add them to HotSwaps" no_favs="Favorite characters to add them to HotSwaps"></div> <div class="hotswap avatars_inline flex-container scroll-reset-container expander" data-i18n="[no_favs]Favorite characters to add them to HotSwaps" no_favs="Favorite characters to add them to HotSwaps"></div>
</div> </div>
</div> </div>
<hr> <hr>

View File

@ -29,34 +29,43 @@ export const NOT_FOCUSABLE_CONTROL_CLASS = 'not_focusable';
export const DISABLED_CONTROL_CLASS = 'disabled'; export const DISABLED_CONTROL_CLASS = 'disabled';
/** /**
* An observer that will check if any new interactables are added to the body * An observer that will check if any new interactables or scroll reset containers are added to the body
* @type {MutationObserver} * @type {MutationObserver}
*/ */
const observer = new MutationObserver(mutations => { const observer = new MutationObserver(mutations => {
mutations.forEach(mutation => { mutations.forEach(mutation => {
if (mutation.type === 'childList') { if (mutation.type === 'childList') {
mutation.addedNodes.forEach(node => { mutation.addedNodes.forEach(handleNodeChange);
if (node.nodeType === Node.ELEMENT_NODE && node instanceof Element) { }
// Check if the node itself is an interactable if (mutation.type === 'attributes') {
if (isKeyboardInteractable(node)) {
makeKeyboardInteractable(node);
}
// Check for any descendants that might be an interactable
const interactables = getAllInteractables(node);
makeKeyboardInteractable(...interactables);
}
});
} else if (mutation.type === 'attributes') {
const target = mutation.target; const target = mutation.target;
if (mutation.attributeName === 'class' && target instanceof Element) { if (mutation.attributeName === 'class' && target instanceof Element) {
if (isKeyboardInteractable(target)) { handleNodeChange(target);
makeKeyboardInteractable(target);
}
} }
} }
}); });
}); });
/**
* Function to handle node changes (added or modified nodes)
* @param {Element} node
*/
function handleNodeChange(node) {
if (node.nodeType === Node.ELEMENT_NODE && node instanceof Element) {
// Handle keyboard interactables
if (isKeyboardInteractable(node)) {
makeKeyboardInteractable(node);
}
initializeInteractables(node);
// Handle scroll reset containers
if (node.classList.contains('scroll-reset-container')) {
applyScrollResetBehavior(node);
}
initializeScrollResetBehaviors(node);
}
}
/** /**
* Registers an interactable class (for example for an extension) and makes it keyboard interactable. * Registers an interactable class (for example for an extension) and makes it keyboard interactable.
* Optionally apply the 'not_focusable' and 'disabled' classes if needed. * Optionally apply the 'not_focusable' and 'disabled' classes if needed.
@ -138,7 +147,6 @@ export function makeKeyboardInteractable(...interactables) {
}); });
} }
/** /**
* Initializes the focusability of controls on the given element or the document * Initializes the focusability of controls on the given element or the document
* *
@ -160,6 +168,32 @@ function getAllInteractables(element) {
return [].concat(...interactableSelectors.map(selector => Array.from(element.querySelectorAll(`${selector}`)))); return [].concat(...interactableSelectors.map(selector => Array.from(element.querySelectorAll(`${selector}`))));
} }
/**
* Function to apply scroll reset behavior to a container
* @param {Element} container - The container
*/
const applyScrollResetBehavior = (container) => {
container.addEventListener('focusout', (e) => {
setTimeout(() => {
const focusedElement = document.activeElement;
if (!container.contains(focusedElement)) {
container.scrollTop = 0;
container.scrollLeft = 0;
}
}, 0);
});
};
/**
* Initializes the scroll reset behavior on the given element or the document
*
* @param {Element|Document} [element=document] - The element on which to initialize the scroll reset behavior. Defaults to the document.
*/
function initializeScrollResetBehaviors(element = document) {
const scrollResetContainers = element.querySelectorAll('.scroll-reset-container');
scrollResetContainers.forEach(container => applyScrollResetBehavior(container));
}
/** /**
* Handles keydown events on the document to trigger click on Enter key press for interactables * Handles keydown events on the document to trigger click on Enter key press for interactables
* *
@ -200,8 +234,9 @@ export function initKeyboard() {
attributeFilter: ['class'] attributeFilter: ['class']
}); });
// Initialize interactable state for already existing controls // Initialize already existing controls
initializeInteractables(); initializeInteractables();
initializeScrollResetBehaviors();
// Add a global keydown listener // Add a global keydown listener
document.addEventListener('keydown', handleGlobalKeyDown); document.addEventListener('keydown', handleGlobalKeyDown);

View File

@ -5164,3 +5164,24 @@ body:not(.movingUI) .drawer-content.maximized {
.regex-highlight { .regex-highlight {
color: #FAF8F6; color: #FAF8F6;
} }
.pagination-indicators {
position: absolute;
bottom: 10px;
left: 50%;
transform: translateX(-50%);
display: flex;
gap: 5px;
}
.pagination-indicator {
width: 10px;
height: 10px;
background-color: #ddd;
border-radius: 50%;
cursor: pointer;
}
.pagination-indicator.active {
background-color: #333;
}