[Glitch] Make post/feed navigation by hotkey more robust
Port 09689103390d10d77de5146483cbbb8abb5c94c9 to glitch-soc Signed-off-by: Claire <claire.github-309c@sitedethib.com>
This commit is contained in:
parent
a147932ce6
commit
f0c48790a8
@ -89,7 +89,7 @@ import {
|
||||
Quotes,
|
||||
} from './util/async-components';
|
||||
import { ColumnsContextProvider } from './util/columns_context';
|
||||
import { focusColumn, getFocusedItemIndex, focusItemSibling, focusFirstItem } from './util/focusUtils';
|
||||
import { focusColumn, getFocusedItemIndex, focusItemSibling, focusFirstItem, getFocusedColumnIndex } from './util/focusUtils';
|
||||
import { WrappedSwitch, WrappedRoute } from './util/react_router_helpers';
|
||||
import { CustomHomepage } from 'flavours/glitch/features/custom_homepage';
|
||||
|
||||
@ -552,20 +552,18 @@ class UI extends PureComponent {
|
||||
handleMoveUp = () => {
|
||||
const currentItemIndex = getFocusedItemIndex();
|
||||
if (currentItemIndex === -1) {
|
||||
focusColumn(1);
|
||||
return focusColumn(getFocusedColumnIndex());
|
||||
} else {
|
||||
const wasHandled = focusItemSibling(currentItemIndex, -1);
|
||||
return wasHandled;
|
||||
return focusItemSibling(currentItemIndex, -1);
|
||||
}
|
||||
};
|
||||
|
||||
handleMoveDown = () => {
|
||||
const currentItemIndex = getFocusedItemIndex();
|
||||
if (currentItemIndex === -1) {
|
||||
focusColumn(1);
|
||||
return focusColumn(getFocusedColumnIndex());
|
||||
} else {
|
||||
const wasHandled = focusItemSibling(currentItemIndex, 1);
|
||||
return wasHandled;
|
||||
return focusItemSibling(currentItemIndex, 1);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@ -62,18 +62,17 @@ export function focusColumn(index = 1) {
|
||||
|
||||
function fallback() {
|
||||
focusColumnTitle(index + indexOffset, isMultiColumnLayout);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!column) {
|
||||
fallback();
|
||||
return;
|
||||
return fallback();
|
||||
}
|
||||
|
||||
const container = column.querySelector('.scrollable');
|
||||
|
||||
if (!container) {
|
||||
fallback();
|
||||
return;
|
||||
return fallback();
|
||||
}
|
||||
|
||||
const focusableItems = Array.from(
|
||||
@ -86,8 +85,7 @@ export function focusColumn(index = 1) {
|
||||
const itemToFocus = findFirstVisibleWithRect(focusableItems);
|
||||
|
||||
if (!itemToFocus) {
|
||||
fallback();
|
||||
return;
|
||||
return fallback();
|
||||
}
|
||||
|
||||
const viewportWidth =
|
||||
@ -110,6 +108,7 @@ export function focusColumn(index = 1) {
|
||||
itemToFocus.item.scrollIntoView(true);
|
||||
}
|
||||
itemToFocus.item.focus();
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -126,6 +125,18 @@ export function getFocusedItemIndex() {
|
||||
return items.indexOf(focusedItem);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the index of the column that contains the user's focus
|
||||
*/
|
||||
export function getFocusedColumnIndex() {
|
||||
const columnWithFocus = document.activeElement?.closest('.column');
|
||||
|
||||
if (!columnWithFocus) return 1;
|
||||
|
||||
const allColumns = Array.from(document.querySelectorAll('.column'));
|
||||
return allColumns.indexOf(columnWithFocus) + 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Focus the topmost item of the column that currently has focus,
|
||||
* or the first column if none
|
||||
@ -159,12 +170,7 @@ export function focusItemSibling(index: number, direction: 1 | -1) {
|
||||
);
|
||||
|
||||
if (!siblingItem) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If sibling element is empty, we skip it
|
||||
if (siblingItem.matches(':empty')) {
|
||||
return focusItemSibling(index + direction, direction);
|
||||
return focusListSibling(direction);
|
||||
}
|
||||
|
||||
// Check if the sibling is a post or a 'follow suggestions' widget
|
||||
@ -177,6 +183,52 @@ export function focusItemSibling(index: number, direction: 1 | -1) {
|
||||
targetElement = siblingItem;
|
||||
}
|
||||
|
||||
// If sibling element is empty, we skip it
|
||||
if (!targetElement || siblingItem.matches(':empty')) {
|
||||
return focusItemSibling(index + direction, direction);
|
||||
}
|
||||
|
||||
targetElement.scrollIntoView({
|
||||
block: 'start',
|
||||
});
|
||||
|
||||
targetElement.focus();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the next or previous .item-list on the page or in the column,
|
||||
* and focuses its first or last item.
|
||||
*/
|
||||
function focusListSibling(direction: 1 | -1) {
|
||||
const container = document.activeElement?.closest('.item-list');
|
||||
|
||||
if (!container) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get all item lists in the current column or page
|
||||
const currentColumn = container.closest('.column') ?? document;
|
||||
|
||||
const columnItemLists = Array.from(
|
||||
currentColumn.querySelectorAll('.item-list'),
|
||||
);
|
||||
const currentListIndex = columnItemLists.indexOf(container);
|
||||
|
||||
// Find the next or previous item-list
|
||||
const listSibling = columnItemLists[currentListIndex + direction];
|
||||
|
||||
// Depending on the direction, find the first or last focusable in the list
|
||||
let targetElement: HTMLElement | null | undefined;
|
||||
if (direction > 0) {
|
||||
targetElement = listSibling?.querySelector<HTMLElement>('.focusable');
|
||||
} else {
|
||||
const allFocusables =
|
||||
listSibling?.querySelectorAll<HTMLElement>('.focusable');
|
||||
targetElement = allFocusables?.[allFocusables.length - 1];
|
||||
}
|
||||
|
||||
if (targetElement) {
|
||||
targetElement.scrollIntoView({
|
||||
block: 'start',
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user