Commit a4c01f96 authored by John Lee's avatar John Lee Committed by Commit Bot

WebUI: Focus first item when action menus are opened by keyboard

Fixed: 1141545
Change-Id: I037923cd5fd45b371c8ae2af480c969dc5640e11
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2555588Reviewed-by: default avatarRebekah Potter <rbpotter@chromium.org>
Commit-Queue: John Lee <johntlee@chromium.org>
Cr-Commit-Position: refs/heads/master@{#830648}
parent 57c03ad0
...@@ -109,6 +109,7 @@ js_library("cr_action_menu_test.m") { ...@@ -109,6 +109,7 @@ js_library("cr_action_menu_test.m") {
"//ui/webui/resources/cr_elements/cr_checkbox:cr_checkbox.m", "//ui/webui/resources/cr_elements/cr_checkbox:cr_checkbox.m",
"//ui/webui/resources/js:cr.m", "//ui/webui/resources/js:cr.m",
"//ui/webui/resources/js:util.m", "//ui/webui/resources/js:util.m",
"//ui/webui/resources/js/cr/ui:focus_outline_manager.m",
] ]
externs_list = [ "$externs_path/mocha-2.5.js" ] externs_list = [ "$externs_path/mocha-2.5.js" ]
extra_deps = [ ":modulize" ] extra_deps = [ ":modulize" ]
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
// #import {getDeepActiveElement} from 'chrome://resources/js/util.m.js'; // #import {getDeepActiveElement} from 'chrome://resources/js/util.m.js';
// #import {keyDownOn} from 'chrome://resources/polymer/v3_0/iron-test-helpers/mock-interactions.js'; // #import {keyDownOn} from 'chrome://resources/polymer/v3_0/iron-test-helpers/mock-interactions.js';
// #import {isMac, isWindows} from 'chrome://resources/js/cr.m.js'; // #import {isMac, isWindows} from 'chrome://resources/js/cr.m.js';
// #import {FocusOutlineManager} from 'chrome://resources/js/cr/ui/focus_outline_manager.m.js';
// #import {Polymer, html} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; // #import {Polymer, html} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
// #import {assertEquals, assertFalse, assertNotEquals, assertTrue} from '../chai_assert.js'; // #import {assertEquals, assertFalse, assertNotEquals, assertTrue} from '../chai_assert.js';
// clang-format on // clang-format on
...@@ -45,6 +46,7 @@ suite('CrActionMenu', function() { ...@@ -45,6 +46,7 @@ suite('CrActionMenu', function() {
}); });
setup(function() { setup(function() {
cr.ui.FocusOutlineManager.forDocument(document).visible = false;
document.body.innerHTML = ` document.body.innerHTML = `
<button id="dots">...</button> <button id="dots">...</button>
<cr-action-menu> <cr-action-menu>
...@@ -608,5 +610,13 @@ suite('CrActionMenu', function() { ...@@ -608,5 +610,13 @@ suite('CrActionMenu', function() {
assertEquals(containerTop, dialog.offsetTop); assertEquals(containerTop, dialog.offsetTop);
menu.close(); menu.close();
}); });
test('FocusFirstItemWhenOpenedWithKeyboard', async () => {
cr.ui.FocusOutlineManager.forDocument(document).visible = true;
menu.showAtPosition({top: 50, left: 50});
await new Promise(resolve => requestAnimationFrame(resolve));
assertEquals(
menu.querySelector('.dropdown-item'), getDeepActiveElement());
});
}); });
}); });
...@@ -13,6 +13,7 @@ js_library("cr_action_menu") { ...@@ -13,6 +13,7 @@ js_library("cr_action_menu") {
deps = [ deps = [
"//ui/webui/resources/js:assert", "//ui/webui/resources/js:assert",
"//ui/webui/resources/js:util", "//ui/webui/resources/js:util",
"//ui/webui/resources/js/cr/ui:focus_outline_manager",
"//ui/webui/resources/js/cr/ui:focus_row", "//ui/webui/resources/js/cr/ui:focus_row",
"//ui/webui/resources/js/cr/ui:focus_without_ink", "//ui/webui/resources/js/cr/ui:focus_without_ink",
] ]
...@@ -31,6 +32,7 @@ polymer_modulizer("cr_action_menu") { ...@@ -31,6 +32,7 @@ polymer_modulizer("cr_action_menu") {
"ui/webui/resources/html/polymer.html|dom,html,Polymer", "ui/webui/resources/html/polymer.html|dom,html,Polymer",
"ui/webui/resources/html/assert.html|assert", "ui/webui/resources/html/assert.html|assert",
"ui/webui/resources/html/cr.html|isMac, isWindows", "ui/webui/resources/html/cr.html|isMac, isWindows",
"ui/webui/resources/html/cr/ui/focus_outline_manager.html|FocusOutlineManager",
"ui/webui/resources/html/cr/ui/focus_row.html|FocusRow", "ui/webui/resources/html/cr/ui/focus_row.html|FocusRow",
"ui/webui/resources/html/util.html|getDeepActiveElement, hasKeyModifiers", "ui/webui/resources/html/util.html|getDeepActiveElement, hasKeyModifiers",
] ]
...@@ -48,6 +50,7 @@ js_library("cr_action_menu.m") { ...@@ -48,6 +50,7 @@ js_library("cr_action_menu.m") {
"//ui/webui/resources/js:assert.m", "//ui/webui/resources/js:assert.m",
"//ui/webui/resources/js:cr.m", "//ui/webui/resources/js:cr.m",
"//ui/webui/resources/js:util.m", "//ui/webui/resources/js:util.m",
"//ui/webui/resources/js/cr/ui:focus_outline_manager.m",
"//ui/webui/resources/js/cr/ui:focus_row.m", "//ui/webui/resources/js/cr/ui:focus_row.m",
"//ui/webui/resources/js/cr/ui:focus_without_ink.m", "//ui/webui/resources/js/cr/ui:focus_without_ink.m",
] ]
......
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
<link rel="import" href="../../html/assert.html"> <link rel="import" href="../../html/assert.html">
<link rel="import" href="../../html/cr.html"> <link rel="import" href="../../html/cr.html">
<link rel="import" href="../../html/cr/ui/focus_outline_manager.html">
<link rel="import" href="../../html/cr/ui/focus_row.html"> <link rel="import" href="../../html/cr/ui/focus_row.html">
<link rel="import" href="../../html/cr/ui/focus_without_ink.html"> <link rel="import" href="../../html/cr/ui/focus_without_ink.html">
<link rel="import" href="../../html/util.html"> <link rel="import" href="../../html/util.html">
......
...@@ -50,6 +50,10 @@ let ShowAtConfig; ...@@ -50,6 +50,10 @@ let ShowAtConfig;
/** @const {string} */ /** @const {string} */
const DROPDOWN_ITEM_CLASS = 'dropdown-item'; const DROPDOWN_ITEM_CLASS = 'dropdown-item';
/** @const {string} */
const SELECTABLE_DROPDOWN_ITEM_QUERY =
`.${DROPDOWN_ITEM_CLASS}:not([hidden]):not([disabled])`;
(function() { (function() {
/** @const {number} */ /** @const {number} */
...@@ -254,8 +258,8 @@ Polymer({ ...@@ -254,8 +258,8 @@ Polymer({
return; return;
} }
const query = '.dropdown-item:not([disabled]):not([hidden])'; const options =
const options = Array.from(this.querySelectorAll(query)); Array.from(this.querySelectorAll(SELECTABLE_DROPDOWN_ITEM_QUERY));
if (options.length === 0) { if (options.length === 0) {
return; return;
} }
...@@ -294,8 +298,8 @@ Polymer({ ...@@ -294,8 +298,8 @@ Polymer({
* @private * @private
*/ */
onMouseover_(e) { onMouseover_(e) {
const query = '.dropdown-item:not([disabled])'; const item = e.composedPath().find(
const item = e.composedPath().find(el => el.matches && el.matches(query)); el => el.matches && el.matches(SELECTABLE_DROPDOWN_ITEM_QUERY));
(item || this.$.wrapper).focus(); (item || this.$.wrapper).focus();
}, },
...@@ -424,6 +428,19 @@ Polymer({ ...@@ -424,6 +428,19 @@ Polymer({
doc.scrollTop = scrollTop; doc.scrollTop = scrollTop;
doc.scrollLeft = scrollLeft; doc.scrollLeft = scrollLeft;
this.addListeners_(); this.addListeners_();
// Focus the first selectable item.
const openedByKey = cr.ui.FocusOutlineManager.forDocument(document).visible;
if (openedByKey) {
const firstSelectableItem =
this.querySelector(SELECTABLE_DROPDOWN_ITEM_QUERY);
if (firstSelectableItem) {
requestAnimationFrame(() => {
// Wait for the next animation frame for the dialog to become visible.
firstSelectableItem.focus();
});
}
}
}, },
/** @private */ /** @private */
......
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