Make annotations focusable (bug 1851489)

When the annotation has a popup then the popup can be toggled in using
the Enter key and hidden in using the Escape key.
This commit is contained in:
Calixte Denizet 2023-09-04 16:19:06 +02:00
parent b18a1669ac
commit 7f44f353b3
2 changed files with 83 additions and 0 deletions

View File

@ -206,6 +206,9 @@ class AnnotationElement {
const container = document.createElement("section");
container.setAttribute("data-annotation-id", data.id);
if (!(this instanceof WidgetAnnotationElement)) {
container.tabIndex = DEFAULT_TAB_INDEX;
}
// The accessibility manager will move the annotation in the DOM in
// order to match the visual ordering.
@ -1969,6 +1972,8 @@ class PopupAnnotationElement extends AnnotationElement {
class PopupElement {
#dateTimePromise = null;
#boundKeyDown = this.#keyDown.bind(this);
#boundHide = this.#hide.bind(this);
#boundShow = this.#show.bind(this);
@ -2044,6 +2049,11 @@ class PopupElement {
}
}
// Attach the event listener to toggle the popup with the keyboard.
for (const element of elements) {
element.container?.addEventListener("keydown", this.#boundKeyDown);
}
this.#container.hidden = true;
if (open) {
this.#toggle();
@ -2187,6 +2197,16 @@ class PopupElement {
return p;
}
#keyDown(event) {
if (event.altKey || event.shiftKey || event.ctrlKey || event.metaKey) {
return;
}
if (event.key === "Enter" || (event.key === "Escape" && this.#pinned)) {
this.#toggle();
}
}
/**
* Toggle the visibility of the popup.
*/
@ -2195,9 +2215,11 @@ class PopupElement {
if (this.#pinned) {
this.#show();
this.#container.addEventListener("click", this.#boundToggle);
this.#container.addEventListener("keydown", this.#boundKeyDown);
} else {
this.#hide();
this.#container.removeEventListener("click", this.#boundToggle);
this.#container.removeEventListener("keydown", this.#boundKeyDown);
}
}

View File

@ -527,4 +527,65 @@ describe("ResetForm action", () => {
});
});
});
describe("Toggle popup with keyboard", () => {
describe("tagged_stamp.pdf", () => {
let pages;
beforeAll(async () => {
pages = await loadAndWait(
"tagged_stamp.pdf",
"[data-annotation-id='20R']"
);
});
afterAll(async () => {
await closePages(pages);
});
it("must check that the popup has the correct visibility", async () => {
await Promise.all(
pages.map(async ([browserName, page]) => {
let hidden = await page.$eval(
"[data-annotation-id='21R']",
el => el.hidden
);
expect(hidden).withContext(`In ${browserName}`).toEqual(true);
await page.focus("[data-annotation-id='20R']");
await page.keyboard.press("Enter");
await page.waitForTimeout(10);
hidden = await page.$eval(
"[data-annotation-id='21R']",
el => el.hidden
);
expect(hidden).withContext(`In ${browserName}`).toEqual(false);
await page.keyboard.press("Enter");
await page.waitForTimeout(10);
hidden = await page.$eval(
"[data-annotation-id='21R']",
el => el.hidden
);
expect(hidden).withContext(`In ${browserName}`).toEqual(true);
await page.keyboard.press("Enter");
await page.waitForTimeout(10);
hidden = await page.$eval(
"[data-annotation-id='21R']",
el => el.hidden
);
expect(hidden).withContext(`In ${browserName}`).toEqual(false);
await page.keyboard.press("Escape");
await page.waitForTimeout(10);
hidden = await page.$eval(
"[data-annotation-id='21R']",
el => el.hidden
);
expect(hidden).withContext(`In ${browserName}`).toEqual(true);
})
);
});
});
});
});