diff --git a/public/index.html b/public/index.html
index 0653bb048..9b84047f7 100644
--- a/public/index.html
+++ b/public/index.html
@@ -4482,7 +4482,7 @@
diff --git a/public/scripts/keyboard.js b/public/scripts/keyboard.js
index 374a2dc69..d28fe243a 100644
--- a/public/scripts/keyboard.js
+++ b/public/scripts/keyboard.js
@@ -29,34 +29,43 @@ export const NOT_FOCUSABLE_CONTROL_CLASS = 'not_focusable';
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}
*/
const observer = new MutationObserver(mutations => {
mutations.forEach(mutation => {
if (mutation.type === 'childList') {
- mutation.addedNodes.forEach(node => {
- if (node.nodeType === Node.ELEMENT_NODE && node instanceof Element) {
- // Check if the node itself is an interactable
- 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') {
+ mutation.addedNodes.forEach(handleNodeChange);
+ }
+ if (mutation.type === 'attributes') {
const target = mutation.target;
if (mutation.attributeName === 'class' && target instanceof Element) {
- if (isKeyboardInteractable(target)) {
- makeKeyboardInteractable(target);
- }
+ handleNodeChange(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.
* 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
*
@@ -160,6 +168,32 @@ function getAllInteractables(element) {
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
*
@@ -200,8 +234,9 @@ export function initKeyboard() {
attributeFilter: ['class']
});
- // Initialize interactable state for already existing controls
+ // Initialize already existing controls
initializeInteractables();
+ initializeScrollResetBehaviors();
// Add a global keydown listener
document.addEventListener('keydown', handleGlobalKeyDown);
diff --git a/public/style.css b/public/style.css
index 631ee352a..c6a01502e 100644
--- a/public/style.css
+++ b/public/style.css
@@ -5164,3 +5164,24 @@ body:not(.movingUI) .drawer-content.maximized {
.regex-highlight {
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;
+}