[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,
|
Quotes,
|
||||||
} from './util/async-components';
|
} from './util/async-components';
|
||||||
import { ColumnsContextProvider } from './util/columns_context';
|
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 { WrappedSwitch, WrappedRoute } from './util/react_router_helpers';
|
||||||
import { CustomHomepage } from 'flavours/glitch/features/custom_homepage';
|
import { CustomHomepage } from 'flavours/glitch/features/custom_homepage';
|
||||||
|
|
||||||
@ -552,20 +552,18 @@ class UI extends PureComponent {
|
|||||||
handleMoveUp = () => {
|
handleMoveUp = () => {
|
||||||
const currentItemIndex = getFocusedItemIndex();
|
const currentItemIndex = getFocusedItemIndex();
|
||||||
if (currentItemIndex === -1) {
|
if (currentItemIndex === -1) {
|
||||||
focusColumn(1);
|
return focusColumn(getFocusedColumnIndex());
|
||||||
} else {
|
} else {
|
||||||
const wasHandled = focusItemSibling(currentItemIndex, -1);
|
return focusItemSibling(currentItemIndex, -1);
|
||||||
return wasHandled;
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
handleMoveDown = () => {
|
handleMoveDown = () => {
|
||||||
const currentItemIndex = getFocusedItemIndex();
|
const currentItemIndex = getFocusedItemIndex();
|
||||||
if (currentItemIndex === -1) {
|
if (currentItemIndex === -1) {
|
||||||
focusColumn(1);
|
return focusColumn(getFocusedColumnIndex());
|
||||||
} else {
|
} else {
|
||||||
const wasHandled = focusItemSibling(currentItemIndex, 1);
|
return focusItemSibling(currentItemIndex, 1);
|
||||||
return wasHandled;
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -62,18 +62,17 @@ export function focusColumn(index = 1) {
|
|||||||
|
|
||||||
function fallback() {
|
function fallback() {
|
||||||
focusColumnTitle(index + indexOffset, isMultiColumnLayout);
|
focusColumnTitle(index + indexOffset, isMultiColumnLayout);
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!column) {
|
if (!column) {
|
||||||
fallback();
|
return fallback();
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const container = column.querySelector('.scrollable');
|
const container = column.querySelector('.scrollable');
|
||||||
|
|
||||||
if (!container) {
|
if (!container) {
|
||||||
fallback();
|
return fallback();
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const focusableItems = Array.from(
|
const focusableItems = Array.from(
|
||||||
@ -86,8 +85,7 @@ export function focusColumn(index = 1) {
|
|||||||
const itemToFocus = findFirstVisibleWithRect(focusableItems);
|
const itemToFocus = findFirstVisibleWithRect(focusableItems);
|
||||||
|
|
||||||
if (!itemToFocus) {
|
if (!itemToFocus) {
|
||||||
fallback();
|
return fallback();
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const viewportWidth =
|
const viewportWidth =
|
||||||
@ -110,6 +108,7 @@ export function focusColumn(index = 1) {
|
|||||||
itemToFocus.item.scrollIntoView(true);
|
itemToFocus.item.scrollIntoView(true);
|
||||||
}
|
}
|
||||||
itemToFocus.item.focus();
|
itemToFocus.item.focus();
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -126,6 +125,18 @@ export function getFocusedItemIndex() {
|
|||||||
return items.indexOf(focusedItem);
|
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,
|
* Focus the topmost item of the column that currently has focus,
|
||||||
* or the first column if none
|
* or the first column if none
|
||||||
@ -159,12 +170,7 @@ export function focusItemSibling(index: number, direction: 1 | -1) {
|
|||||||
);
|
);
|
||||||
|
|
||||||
if (!siblingItem) {
|
if (!siblingItem) {
|
||||||
return false;
|
return focusListSibling(direction);
|
||||||
}
|
|
||||||
|
|
||||||
// If sibling element is empty, we skip it
|
|
||||||
if (siblingItem.matches(':empty')) {
|
|
||||||
return focusItemSibling(index + direction, direction);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if the sibling is a post or a 'follow suggestions' widget
|
// 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;
|
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) {
|
if (targetElement) {
|
||||||
targetElement.scrollIntoView({
|
targetElement.scrollIntoView({
|
||||||
block: 'start',
|
block: 'start',
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user