From 77475ac61044e2ca3e6183232eb252930301b0b7 Mon Sep 17 00:00:00 2001 From: Calixte Denizet Date: Sun, 29 Oct 2023 17:23:31 +0100 Subject: [PATCH] [Editor] Don't steal the keyboard events when editing mode is enabled --- src/display/editor/tools.js | 24 ++++++-- test/integration/freetext_editor_spec.mjs | 72 +++++++++++++++++++++++ 2 files changed, 90 insertions(+), 6 deletions(-) diff --git a/src/display/editor/tools.js b/src/display/editor/tools.js index 1b180ac8f..b8ac29c11 100644 --- a/src/display/editor/tools.js +++ b/src/display/editor/tools.js @@ -611,6 +611,14 @@ class AnnotationEditorUIManager { ); }; + const textInputChecker = (_self, { target: el }) => { + if (el instanceof HTMLInputElement) { + const { type } = el; + return type !== "text" && type !== "number"; + } + return true; + }; + const small = this.TRANSLATE_SMALL; const big = this.TRANSLATE_BIG; @@ -618,8 +626,12 @@ class AnnotationEditorUIManager { this, "_keyboardManager", new KeyboardManager([ - [["ctrl+a", "mac+meta+a"], proto.selectAll], - [["ctrl+z", "mac+meta+z"], proto.undo], + [ + ["ctrl+a", "mac+meta+a"], + proto.selectAll, + { checker: textInputChecker }, + ], + [["ctrl+z", "mac+meta+z"], proto.undo, { checker: textInputChecker }], [ // On mac, depending of the OS version, the event.key is either "z" or // "Z" when the user presses "meta+shift+z". @@ -631,6 +643,7 @@ class AnnotationEditorUIManager { "mac+meta+shift+Z", ], proto.redo, + { checker: textInputChecker }, ], [ [ @@ -647,6 +660,7 @@ class AnnotationEditorUIManager { "mac+Delete", ], proto.delete, + { checker: textInputChecker }, ], [ ["Enter", "mac+Enter"], @@ -906,13 +920,11 @@ class AnnotationEditorUIManager { #addKeyboardManager() { // The keyboard events are caught at the container level in order to be able // to execute some callbacks even if the current page doesn't have focus. - window.addEventListener("keydown", this.#boundKeydown, { capture: true }); + window.addEventListener("keydown", this.#boundKeydown); } #removeKeyboardManager() { - window.removeEventListener("keydown", this.#boundKeydown, { - capture: true, - }); + window.removeEventListener("keydown", this.#boundKeydown); } #addCopyPasteListeners() { diff --git a/test/integration/freetext_editor_spec.mjs b/test/integration/freetext_editor_spec.mjs index 412167f51..a3acdeba3 100644 --- a/test/integration/freetext_editor_spec.mjs +++ b/test/integration/freetext_editor_spec.mjs @@ -2981,4 +2981,76 @@ describe("FreeText Editor", () => { ); }); }); + + describe("Avoid to steal keyboard events", () => { + let pages; + + beforeAll(async () => { + pages = await loadAndWait("empty.pdf", ".annotationEditorLayer"); + }); + + afterAll(async () => { + await closePages(pages); + }); + + it("must check the keyboard event is limited to the input", async () => { + await Promise.all( + pages.map(async ([browserName, page]) => { + await switchToFreeText(page); + + const rect = await page.$eval(".annotationEditorLayer", el => { + // With Chrome something is wrong when serializing a DomRect, + // hence we extract the values and just return them. + const { x, y } = el.getBoundingClientRect(); + return { x, y }; + }); + + const data = "Hello PDF.js World !!"; + await page.mouse.click(rect.x + 100, rect.y + 100); + await page.waitForSelector(getEditorSelector(0), { + visible: true, + }); + await page.type(`${getEditorSelector(0)} .internal`, data); + + // Commit. + await page.keyboard.press("Escape"); + await page.waitForSelector( + `${getEditorSelector(0)} .overlay.enabled` + ); + + let promise = page.evaluate( + () => + new Promise(resolve => { + document.addEventListener("selectionchange", resolve, { + once: true, + }); + }) + ); + await page.click("#pageNumber"); + await promise; + + promise = page.evaluate( + () => + new Promise(resolve => { + document + .getElementById("pageNumber") + .addEventListener("keyup", resolve, { once: true }); + }) + ); + await page.keyboard.press("Backspace"); + await promise; + + let content = await page.$eval("#pageNumber", el => + el.innerText.trimEnd() + ); + expect(content).withContext(`In ${browserName}`).toEqual(""); + + content = await page.$eval(getEditorSelector(0), el => + el.innerText.trimEnd() + ); + expect(content).withContext(`In ${browserName}`).toEqual(data); + }) + ); + }); + }); });