Skip to content

Commit 6b1b94e

Browse files
authored
Merge pull request #20681 from calixteman/bug2016212
Correctly handle tab/page down when on a menu (bug 2016212)
2 parents 61de564 + 5290534 commit 6b1b94e

2 files changed

Lines changed: 90 additions & 2 deletions

File tree

test/integration/thumbnail_view_spec.mjs

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -355,4 +355,73 @@ describe("PDF Thumbnail View", () => {
355355
);
356356
});
357357
});
358+
359+
describe("Menu keyboard navigation with multi-character keys (bug 2016212)", () => {
360+
let pages;
361+
362+
beforeEach(async () => {
363+
pages = await loadAndWait(
364+
"page_with_number_and_link.pdf",
365+
"#viewsManagerSelectorButton",
366+
null,
367+
null,
368+
{ enableSplitMerge: true }
369+
);
370+
});
371+
372+
afterEach(async () => {
373+
await closePages(pages);
374+
});
375+
376+
it("must navigate menus with ArrowDown and Tab keys", async () => {
377+
await Promise.all(
378+
pages.map(async ([browserName, page]) => {
379+
await page.click("#viewsManagerToggleButton");
380+
await waitForThumbnailVisible(page, 1);
381+
382+
// Focus the views manager selector button
383+
await page.waitForSelector("#viewsManagerSelectorButton", {
384+
visible: true,
385+
});
386+
await page.focus("#viewsManagerSelectorButton");
387+
388+
// Open menu with Enter key
389+
await page.keyboard.press("Enter");
390+
391+
// Wait for menu to be expanded
392+
await waitForMenu(page, "#viewsManagerSelectorButton");
393+
394+
// Check that focus moved to the first menu button (pages)
395+
await page.waitForSelector("#thumbnailsViewMenu:focus", {
396+
visible: true,
397+
});
398+
399+
// Press ArrowDown to navigate to second item
400+
await page.keyboard.press("ArrowDown");
401+
402+
// Should now be on outlines button
403+
await page.waitForSelector("#outlinesViewMenu:focus", {
404+
visible: true,
405+
});
406+
407+
// Press Tab to move to the manage button (should close views menu)
408+
await page.keyboard.press("Tab");
409+
410+
// Wait for views manager menu to be collapsed
411+
await waitForMenu(page, "#viewsManagerSelectorButton", false);
412+
413+
// Focus should be on manage button
414+
await page.waitForSelector("#viewsManagerStatusActionButton:focus", {
415+
visible: true,
416+
});
417+
418+
// Open manage menu with Space key
419+
await page.keyboard.press(" ");
420+
421+
// Wait for manage menu to be expanded
422+
await waitForMenu(page, "#viewsManagerStatusActionButton");
423+
})
424+
);
425+
});
426+
});
358427
});

web/menu.js

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ class Menu {
2828

2929
#lastIndex = -1;
3030

31+
#onFocusOutBound = this.#onFocusOut.bind(this);
32+
3133
/**
3234
* Create a menu for the given button.
3335
* @param {HTMLElement} menuContainer
@@ -97,7 +99,18 @@ class Menu {
9799
},
98100
{ signal }
99101
);
100-
window.addEventListener("blur", this.#closeMenu.bind(this), { signal });
102+
const closeMenu = this.#closeMenu.bind(this);
103+
window.addEventListener("blur", closeMenu, { signal });
104+
menu.addEventListener("focusout", this.#onFocusOutBound, { signal });
105+
}
106+
107+
#onFocusOut({ relatedTarget }) {
108+
if (
109+
!this.#triggeringButton.contains(relatedTarget) &&
110+
!this.#menu.contains(relatedTarget)
111+
) {
112+
this.#closeMenu();
113+
}
101114
}
102115

103116
/**
@@ -112,6 +125,7 @@ class Menu {
112125

113126
this.#openMenu();
114127
});
128+
this.#triggeringButton.addEventListener("focusout", this.#onFocusOutBound);
115129

116130
const { signal } = this.#menuAC;
117131

@@ -148,7 +162,12 @@ class Menu {
148162
stopEvent(e);
149163
break;
150164
default:
151-
const char = e.key.toLocaleLowerCase();
165+
const { key } = e;
166+
if (!/^\p{L}$/u.test(key)) {
167+
// It isn't a single letter, so ignore it.
168+
break;
169+
}
170+
const char = key.toLocaleLowerCase();
152171
this.#goToNextItem(e.target, true, item =>
153172
item.textContent.trim().toLowerCase().startsWith(char)
154173
);

0 commit comments

Comments
 (0)