mirror of
https://github.com/RetroShare/RSNewWebUI.git
synced 2026-09-12 19:50:04 +05:00
webui v154: the image preview claims to be a modal, so let it behave like one
The overlay carries role=dialog and aria-modal=true, but its Escape handler sits on the overlay itself and therefore only sees what bubbles through it. The close button is focused on open, so Escape works -- until the first tap on the picture, which moves the focus to <body>: from then on the only way out is the close button or the Back button. The handler moves to the document, in the capture phase, and is removed when the preview closes. Tab is caught there too: aria-modal promises the rest of the page is inert, and without it the focus walks straight out of the preview into the message list behind it. Closing also puts the focus back on whatever opened the preview rather than dropping it on <body>.
This commit is contained in:
parent
f716a61298
commit
e9cf4e74f3
@ -121,13 +121,25 @@ function isEmbeddedImageSrc(src) {
|
||||
// strand embedded browsers such as Android WebView without a usable Back entry.
|
||||
let chatImageViewer = null;
|
||||
let chatImageViewerPreviousOverflow = '';
|
||||
let chatImageViewerOpener = null;
|
||||
let chatImageViewerKeyHandler = null;
|
||||
const CHAT_IMAGE_VIEWER_HISTORY_KEY = 'chatImageViewer';
|
||||
|
||||
function removeChatImageViewer() {
|
||||
if (!chatImageViewer) return;
|
||||
if (chatImageViewerKeyHandler) {
|
||||
document.removeEventListener('keydown', chatImageViewerKeyHandler, true);
|
||||
chatImageViewerKeyHandler = null;
|
||||
}
|
||||
chatImageViewer.remove();
|
||||
chatImageViewer = null;
|
||||
document.body.style.overflow = chatImageViewerPreviousOverflow;
|
||||
// Put the focus back where it was taken from, so closing the preview does
|
||||
// not leave the caret on <body> with the message list scrolled away.
|
||||
if (chatImageViewerOpener && document.contains(chatImageViewerOpener)) {
|
||||
chatImageViewerOpener.focus();
|
||||
}
|
||||
chatImageViewerOpener = null;
|
||||
}
|
||||
|
||||
function closeChatImageViewer() {
|
||||
@ -168,12 +180,30 @@ function openChatImageViewer(src) {
|
||||
overlay.onclick = (event) => {
|
||||
if (event.target === overlay) closeChatImageViewer();
|
||||
};
|
||||
overlay.onkeydown = (event) => {
|
||||
if (event.key === 'Escape') closeChatImageViewer();
|
||||
|
||||
// The overlay says role=dialog and aria-modal=true, so it has to behave like
|
||||
// one. Listening on the overlay only caught what bubbled through it: tapping
|
||||
// the picture moves the focus to <body> and Escape went dead from then on.
|
||||
// Listening on the document, in the capture phase, means Escape closes the
|
||||
// preview wherever the focus has drifted, and Tab cannot walk out of it into
|
||||
// the page underneath -- the close button is the only thing to land on.
|
||||
chatImageViewerKeyHandler = (event) => {
|
||||
if (event.key === 'Escape') {
|
||||
event.preventDefault();
|
||||
closeChatImageViewer();
|
||||
} else if (event.key === 'Tab') {
|
||||
event.preventDefault();
|
||||
closeButton.focus();
|
||||
}
|
||||
};
|
||||
document.addEventListener('keydown', chatImageViewerKeyHandler, true);
|
||||
|
||||
chatImageViewerPreviousOverflow = document.body.style.overflow;
|
||||
document.body.style.overflow = 'hidden';
|
||||
// Captured before the overlay steals the focus, and restored on close.
|
||||
chatImageViewerOpener = document.activeElement instanceof HTMLElement
|
||||
? document.activeElement
|
||||
: null;
|
||||
document.body.appendChild(overlay);
|
||||
chatImageViewer = overlay;
|
||||
history.pushState({ ...(history.state || {}), [CHAT_IMAGE_VIEWER_HISTORY_KEY]: true }, '');
|
||||
|
||||
@ -116,7 +116,7 @@ const navbar = () => {
|
||||
? 'Connected to RetroShare Core'
|
||||
: 'Connection Lost',
|
||||
}),
|
||||
m('span.webui-version', { style: { fontSize: '0.7em' } }, 'v153'),
|
||||
m('span.webui-version', { style: { fontSize: '0.7em' } }, 'v154'),
|
||||
m('i.fas.fa-sync-alt.refresh-icon', {
|
||||
style: { cursor: 'pointer', fontSize: '0.8em' },
|
||||
onclick: () => window.location.reload(true),
|
||||
@ -239,7 +239,7 @@ const MobileStatus = () => {
|
||||
m('small', statusbar.formatBytes(state.totalOut)),
|
||||
]),
|
||||
]),
|
||||
m('.mobile-status-sheet__version', 'WebUI v153'),
|
||||
m('.mobile-status-sheet__version', 'WebUI v154'),
|
||||
])),
|
||||
];
|
||||
},
|
||||
|
||||
Loading…
Reference in New Issue
Block a user