Commit 2bbea72b authored by Luciano Pacheco's avatar Luciano Pacheco Committed by Commit Bot

Files app: Force focus out of <body>

When the element has the focus is hidden/removed/disabled the browser
moves the focus to <body>, in this situation user doesn't have any
visual clue where is the focus. To fix this we move the focus from
<body> to file list which is the default element when opening Files app.

Use "focusin" and "focusout" in the <body> element, because these two
events bubble from any body's child element, whereas "focus" event
doesn't. In the event handler we use requestIdleCallback() to give a
chance for any synchronous code to finish and potentially set the focus
somewhere else other than <body>.

Test: browser_tests --gtest_filter="*tabindexFocusBody*"
Bug: 1059137,957413
Change-Id: I9563294a3b6c541cf6bd2bba03470041bc8af41b
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2089444Reviewed-by: default avatarNoel Gordon <noel@chromium.org>
Reviewed-by: default avatarAlex Danilo <adanilo@chromium.org>
Commit-Queue: Noel Gordon <noel@chromium.org>
Auto-Submit: Luciano Pacheco <lucmult@chromium.org>
Cr-Commit-Position: refs/heads/master@{#748090}
parent cffa1a26
...@@ -723,6 +723,8 @@ WRAPPED_INSTANTIATE_TEST_SUITE_P( ...@@ -723,6 +723,8 @@ WRAPPED_INSTANTIATE_TEST_SUITE_P(
FilesAppBrowserTest, FilesAppBrowserTest,
::testing::Values( ::testing::Values(
TestCase("tabindexSearchBoxFocus").DisableFilesNg(), TestCase("tabindexSearchBoxFocus").DisableFilesNg(),
TestCase("tabindexFocusBody").DisableFilesNg(),
TestCase("tabindexFocusBody").FilesNg(),
TestCase("tabindexFocus").DisableFilesNg(), TestCase("tabindexFocus").DisableFilesNg(),
TestCase("tabindexFocusDownloads").DisableFilesNg(), TestCase("tabindexFocusDownloads").DisableFilesNg(),
TestCase("tabindexFocusDownloads").InGuestMode().DisableFilesNg(), TestCase("tabindexFocusDownloads").InGuestMode().DisableFilesNg(),
......
...@@ -401,6 +401,9 @@ class FileManagerUI { ...@@ -401,6 +401,9 @@ class FileManagerUI {
e.stopPropagation(); e.stopPropagation();
}); });
} }
/** @private {?number} */
this.focusBodyCallbackId_ = null;
} }
/** /**
...@@ -452,6 +455,31 @@ class FileManagerUI { ...@@ -452,6 +455,31 @@ class FileManagerUI {
if (targetElement) { if (targetElement) {
targetElement.focus(); targetElement.focus();
} }
/** If focus lands in the <body> we move to the file list. */
const focusList = () => {
if (this.focusBodyCallbackId_) {
return;
}
this.focusBodyCallbackId_ = window.requestIdleCallback(() => {
if (document.activeElement &&
document.activeElement.tagName === 'BODY') {
this.focusDefaultElement_();
}
this.focusBodyCallbackId_ = null;
});
};
document.body.addEventListener('focusin', focusList);
document.body.addEventListener('focusout', focusList);
}
/**
* Sets the focus in the default UI element.
* @private
*/
focusDefaultElement_() {
this.listContainer.currentList && this.listContainer.currentList.focus();
} }
/** /**
......
...@@ -289,3 +289,20 @@ testcase.tabindexSaveFileDialogDrive = async () => { ...@@ -289,3 +289,20 @@ testcase.tabindexSaveFileDialogDrive = async () => {
'new-folder-button', 'filename-input-textbox' 'new-folder-button', 'filename-input-textbox'
]); ]);
}; };
/**
* Tests that focus doesn't stay on <body>, it's moved to the file list.
*/
testcase.tabindexFocusBody = async () => {
// Open Files app on Downloads.
const appId = await setupAndWaitUntilReady(RootPath.DOWNLOADS);
// Check that the file list.
await remoteCall.waitForElement(appId, ['#file-list:focus']);
// Force focus on <body>.
await remoteCall.focus(appId, ['body']);
// Check that the file list.
await remoteCall.waitForElement(appId, ['#file-list:focus']);
};
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment