зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1593649 - Part 2: Always set focus as if using the keyboard r=rpl
Differential Revision: https://phabricator.services.mozilla.com/D55194 --HG-- extra : moz-landing-system : lando
This commit is contained in:
Родитель
415e677b84
Коммит
d2062ef28c
|
@ -677,14 +677,8 @@ class PanelList extends HTMLElement {
|
|||
let openingEvent = this.triggeringEvent;
|
||||
this.triggeringEvent = triggeringEvent;
|
||||
this.open = false;
|
||||
// Since the previously focused element (which is inside the panel) is now
|
||||
// hidden, move the focus back to the element that opened the panel if it
|
||||
// was opened with the keyboard.
|
||||
if (
|
||||
openingEvent &&
|
||||
openingEvent.target &&
|
||||
openingEvent.mozInputSource === MouseEvent.MOZ_SOURCE_KEYBOARD
|
||||
) {
|
||||
// Refocus the button that opened the menu if we have one.
|
||||
if (openingEvent && openingEvent.target) {
|
||||
openingEvent.target.focus();
|
||||
}
|
||||
}
|
||||
|
@ -945,8 +939,6 @@ class PanelList extends HTMLElement {
|
|||
}
|
||||
|
||||
async onShow() {
|
||||
let { triggeringEvent } = this;
|
||||
|
||||
this.sendEvent("showing");
|
||||
this.addHideListeners();
|
||||
await this.setAlign();
|
||||
|
@ -954,14 +946,9 @@ class PanelList extends HTMLElement {
|
|||
// Wait until the next paint for the alignment to be set and panel to be
|
||||
// visible.
|
||||
requestAnimationFrame(() => {
|
||||
// Focus the first visible panel-item if we were opened with the keyboard.
|
||||
if (
|
||||
triggeringEvent &&
|
||||
triggeringEvent.mozInputSource === MouseEvent.MOZ_SOURCE_KEYBOARD
|
||||
) {
|
||||
this.focusWalker.currentNode = this;
|
||||
this.focusWalker.nextNode();
|
||||
}
|
||||
// Focus the first focusable panel-item.
|
||||
this.focusWalker.currentNode = this;
|
||||
this.focusWalker.nextNode();
|
||||
|
||||
this.sendEvent("shown");
|
||||
});
|
||||
|
@ -1371,7 +1358,7 @@ class AddonUpdatesMessage extends HTMLElement {
|
|||
this.button = document.createElement("button");
|
||||
this.button.addEventListener("click", e => {
|
||||
if (e.button === 0) {
|
||||
loadViewFn("updates/available", e);
|
||||
loadViewFn("updates/available");
|
||||
}
|
||||
});
|
||||
this.button.hidden = true;
|
||||
|
@ -1456,7 +1443,7 @@ class AddonPageOptions extends HTMLElement {
|
|||
await this.checkForUpdates();
|
||||
break;
|
||||
case "view-recent-updates":
|
||||
loadViewFn("updates/recent", e);
|
||||
loadViewFn("updates/recent");
|
||||
break;
|
||||
case "install-from-file":
|
||||
if (XPINSTALL_ENABLED) {
|
||||
|
@ -1480,7 +1467,7 @@ class AddonPageOptions extends HTMLElement {
|
|||
await this.resetAutomaticUpdates();
|
||||
break;
|
||||
case "manage-shortcuts":
|
||||
loadViewFn("shortcuts/shortcuts", e);
|
||||
loadViewFn("shortcuts/shortcuts");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -2517,7 +2504,7 @@ class AddonCard extends HTMLElement {
|
|||
openOptionsInTab(addon.optionsURL);
|
||||
} else if (getOptionsType(addon) == "inline") {
|
||||
this.recordActionEvent("preferences", "inline");
|
||||
loadViewFn(`detail/${this.addon.id}/preferences`, e);
|
||||
loadViewFn(`detail/${this.addon.id}/preferences`);
|
||||
}
|
||||
break;
|
||||
case "remove":
|
||||
|
@ -2544,7 +2531,7 @@ class AddonCard extends HTMLElement {
|
|||
}
|
||||
break;
|
||||
case "expand":
|
||||
loadViewFn(`detail/${this.addon.id}`, e);
|
||||
loadViewFn(`detail/${this.addon.id}`);
|
||||
break;
|
||||
case "more-options":
|
||||
// Open panel on click from the keyboard.
|
||||
|
@ -2570,7 +2557,7 @@ class AddonCard extends HTMLElement {
|
|||
!this.expanded &&
|
||||
(e.target === this.addonNameEl || !e.target.closest("a"))
|
||||
) {
|
||||
loadViewFn(`detail/${this.addon.id}`, e);
|
||||
loadViewFn(`detail/${this.addon.id}`);
|
||||
} else if (
|
||||
e.target.localName == "a" &&
|
||||
e.target.getAttribute("data-telemetry-name")
|
||||
|
@ -2898,7 +2885,7 @@ class AddonCard extends HTMLElement {
|
|||
|
||||
this.appendChild(this.card);
|
||||
|
||||
if (this.expanded && this.keyboardNavigation) {
|
||||
if (this.expanded) {
|
||||
requestAnimationFrame(() => this.optionsButton.focus());
|
||||
}
|
||||
|
||||
|
@ -3076,7 +3063,7 @@ class RecommendedAddonCard extends HTMLElement {
|
|||
action: "manage",
|
||||
addon: this.discoAddon,
|
||||
});
|
||||
loadViewFn(`detail/${this.addonId}`, event);
|
||||
loadViewFn(`detail/${this.addonId}`);
|
||||
break;
|
||||
default:
|
||||
if (event.target.matches(".disco-addon-author a[href]")) {
|
||||
|
@ -3964,12 +3951,11 @@ class ListView {
|
|||
}
|
||||
|
||||
class DetailView {
|
||||
constructor({ isKeyboardNavigation, param, root }) {
|
||||
constructor({ param, root }) {
|
||||
let [id, selectedTab] = param.split("/");
|
||||
this.id = id;
|
||||
this.selectedTab = selectedTab;
|
||||
this.root = root;
|
||||
this.isKeyboardNavigation = isKeyboardNavigation;
|
||||
}
|
||||
|
||||
async render() {
|
||||
|
@ -3990,7 +3976,6 @@ class DetailView {
|
|||
|
||||
card.setAddon(addon);
|
||||
card.expand();
|
||||
card.keyboardNavigation = this.isKeyboardNavigation;
|
||||
await card.render();
|
||||
if (
|
||||
this.selectedTab === "preferences" &&
|
||||
|
@ -4132,7 +4117,7 @@ function initialize(opts) {
|
|||
* resolve once the view has been updated to conform with other about:addons
|
||||
* views.
|
||||
*/
|
||||
async function show(type, param, { isKeyboardNavigation, historyEntryId }) {
|
||||
async function show(type, param, { historyEntryId }) {
|
||||
let container = document.createElement("div");
|
||||
container.setAttribute("current-view", type);
|
||||
addonPageHeader.setViewInfo({ type, param });
|
||||
|
@ -4140,7 +4125,6 @@ async function show(type, param, { isKeyboardNavigation, historyEntryId }) {
|
|||
await new ListView({ param, root: container }).render();
|
||||
} else if (type == "detail") {
|
||||
await new DetailView({
|
||||
isKeyboardNavigation,
|
||||
param,
|
||||
root: container,
|
||||
}).render();
|
||||
|
|
|
@ -608,7 +608,7 @@ var gViewController = {
|
|||
);
|
||||
},
|
||||
|
||||
loadView(aViewId, sourceEvent) {
|
||||
loadView(aViewId) {
|
||||
var isRefresh = false;
|
||||
if (aViewId == this.currentViewId) {
|
||||
if (this.isLoading) {
|
||||
|
@ -623,14 +623,10 @@ var gViewController = {
|
|||
isRefresh = true;
|
||||
}
|
||||
|
||||
let isKeyboardNavigation =
|
||||
sourceEvent &&
|
||||
sourceEvent.mozInputSource === MouseEvent.MOZ_SOURCE_KEYBOARD;
|
||||
var state = {
|
||||
view: aViewId,
|
||||
previousView: this.currentViewId,
|
||||
historyEntryId: ++this.nextHistoryEntryId,
|
||||
isKeyboardNavigation,
|
||||
};
|
||||
if (!isRefresh) {
|
||||
gHistory.pushState(state);
|
||||
|
@ -1538,9 +1534,9 @@ const addonTypes = new Set([
|
|||
"locale",
|
||||
]);
|
||||
const htmlViewOpts = {
|
||||
loadViewFn(view, sourceEvent) {
|
||||
loadViewFn(view) {
|
||||
let viewId = `addons://${view}`;
|
||||
gViewController.loadView(viewId, sourceEvent);
|
||||
gViewController.loadView(viewId);
|
||||
},
|
||||
replaceWithDefaultViewFn() {
|
||||
gViewController.replaceView(gViewDefault);
|
||||
|
|
|
@ -99,6 +99,7 @@ skip-if = verify
|
|||
[browser_page_options_install_addon.js]
|
||||
[browser_page_options_updates.js]
|
||||
[browser_panel_item_accesskey.js]
|
||||
[browser_panel_list_accessibility.js]
|
||||
[browser_pluginprefs.js]
|
||||
[browser_reinstall.js]
|
||||
[browser_search_bar_focus.js]
|
||||
|
|
|
@ -0,0 +1,64 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
function setupPanel(win) {
|
||||
let doc = win.document;
|
||||
let panelList = doc.createElement("panel-list");
|
||||
let items = ["one", "two", "three"];
|
||||
let panelItems = items.map(item => {
|
||||
let panelItem = doc.createElement("panel-item");
|
||||
panelItem.textContent = item;
|
||||
panelList.append(panelItem);
|
||||
return panelItem;
|
||||
});
|
||||
|
||||
let anchorButton = doc.createElement("button");
|
||||
anchorButton.addEventListener("click", e => panelList.toggle(e));
|
||||
|
||||
doc.body.append(anchorButton, panelList);
|
||||
|
||||
return { anchorButton, panelList, panelItems };
|
||||
}
|
||||
|
||||
add_task(async function testItemFocusOnOpen() {
|
||||
let win = await loadInitialView("extension");
|
||||
let doc = win.document;
|
||||
|
||||
let { anchorButton, panelList, panelItems } = setupPanel(win);
|
||||
|
||||
ok(doc.activeElement, "There is an active element");
|
||||
ok(!doc.activeElement.closest("panel-list"), "Focus isn't in the list");
|
||||
|
||||
let shown = BrowserTestUtils.waitForEvent(panelList, "shown");
|
||||
EventUtils.synthesizeMouseAtCenter(anchorButton, {}, win);
|
||||
await shown;
|
||||
|
||||
is(doc.activeElement, panelItems[0], "The first item is focused");
|
||||
|
||||
let hidden = BrowserTestUtils.waitForEvent(panelList, "hidden");
|
||||
EventUtils.synthesizeKey("Escape", {}, win);
|
||||
await hidden;
|
||||
|
||||
is(doc.activeElement, anchorButton, "The anchor is focused again on close");
|
||||
|
||||
await closeView(win);
|
||||
});
|
||||
|
||||
add_task(async function testAriaAttributes() {
|
||||
let win = await loadInitialView("extension");
|
||||
|
||||
let { panelList, panelItems } = setupPanel(win);
|
||||
|
||||
is(panelList.getAttribute("role"), "menu", "The panel is a menu");
|
||||
|
||||
is(panelItems.length, 3, "There are 3 items");
|
||||
Assert.deepEqual(
|
||||
panelItems.map(panelItem => panelItem.button.getAttribute("role")),
|
||||
new Array(panelItems.length).fill("menuitem"),
|
||||
"All of the items have a menuitem button"
|
||||
);
|
||||
|
||||
await closeView(win);
|
||||
});
|
Загрузка…
Ссылка в новой задаче