From 9d576d5097a56ac0b394b98adadd3318a6d29ddb Mon Sep 17 00:00:00 2001 From: Calixte Denizet Date: Thu, 27 Jul 2023 20:12:38 +0200 Subject: [PATCH] [Editor] When an editor is unselected give the focus to the current page Follow-up of #16756. --- src/display/editor/editor.js | 2 +- src/display/editor/tools.js | 2 +- test/integration/freetext_editor_spec.js | 83 ++++++++++++++++++++++++ test/integration/test_utils.js | 6 +- 4 files changed, 90 insertions(+), 3 deletions(-) diff --git a/src/display/editor/editor.js b/src/display/editor/editor.js index 0ec5ce85e..c21d8c77a 100644 --- a/src/display/editor/editor.js +++ b/src/display/editor/editor.js @@ -975,7 +975,7 @@ class AnnotationEditor { if (this.div?.contains(document.activeElement)) { // Don't use this.div.blur() because we don't know where the focus will // go. - this.parent.div.focus(); + this._uiManager.currentLayer.div.focus(); } } diff --git a/src/display/editor/tools.js b/src/display/editor/tools.js index e95998bea..ca758f1bd 100644 --- a/src/display/editor/tools.js +++ b/src/display/editor/tools.js @@ -837,7 +837,7 @@ class AnnotationEditorUIManager { } this.unselectAll(); - const layer = this.#allLayers.get(this.#currentPageIndex); + const layer = this.currentLayer; try { const newEditors = []; diff --git a/test/integration/freetext_editor_spec.js b/test/integration/freetext_editor_spec.js index 88f62254d..a30241919 100644 --- a/test/integration/freetext_editor_spec.js +++ b/test/integration/freetext_editor_spec.js @@ -2025,4 +2025,87 @@ describe("FreeText Editor", () => { ); }); }); + + describe("Focus must go on the current page", () => { + let pages; + + beforeAll(async () => { + pages = await loadAndWait( + "tracemonkey.pdf", + ".annotationEditorLayer", + 100, + async page => { + await page.waitForFunction(async () => { + await window.PDFViewerApplication.initializedPromise; + return true; + }); + await page.evaluate(() => { + window.visitedPages = []; + window.PDFViewerApplication.eventBus.on( + "pagechanging", + ({ pageNumber }) => { + window.visitedPages.push(pageNumber); + } + ); + }); + } + ); + }); + + afterAll(async () => { + await closePages(pages); + }); + + it("must check that the focus is on the right page", async () => { + await Promise.all( + pages.map(async ([browserName, page]) => { + await page.click("#editorFreeText"); + await page.waitForTimeout(10); + + const rect = await page.$eval(".annotationEditorLayer", el => { + 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.waitForTimeout(10); + await page.type(`${getEditorSelector(0)} .internal`, data); + // Commit. + await page.keyboard.press("Escape"); + await page.waitForTimeout(10); + + const oneToFourteen = Array.from(new Array(14).keys(), x => x + 1); + + for (const pageNumber of oneToFourteen) { + const pageSelector = `.page[data-page-number = "${pageNumber}"]`; + + await page.evaluate(selector => { + const element = window.document.querySelector(selector); + element.scrollIntoView(); + }, pageSelector); + + const annotationLayerSelector = `${pageSelector} > .annotationEditorLayer:not([hidden])`; + await page.waitForSelector(annotationLayerSelector, { + visible: true, + timeout: 0, + }); + await page.waitForTimeout(10); + } + + const visitedPages = await page.evaluate(() => { + const p = window.visitedPages; + delete window.visitedPages; + return p; + }); + const sorted = visitedPages.slice().sort((a, b) => a - b); + + expect(visitedPages.length) + .withContext(`In ${browserName}`) + .not.toEqual(0); + expect(visitedPages).withContext(`In ${browserName}`).toEqual(sorted); + }) + ); + }); + }); }); diff --git a/test/integration/test_utils.js b/test/integration/test_utils.js index e6642b851..18dbfa4cb 100644 --- a/test/integration/test_utils.js +++ b/test/integration/test_utils.js @@ -13,7 +13,7 @@ * limitations under the License. */ -exports.loadAndWait = (filename, selector, zoom) => +exports.loadAndWait = (filename, selector, zoom, pageSetup) => Promise.all( global.integrationSessions.map(async session => { const page = await session.browser.newPage(); @@ -38,6 +38,10 @@ exports.loadAndWait = (filename, selector, zoom) => url += `#zoom=${zoom}`; } await page.goto(url); + if (pageSetup) { + await pageSetup(page); + } + await page.bringToFront(); await page.waitForSelector(selector, { timeout: 0,