diff --git a/src/display/editor/draw.js b/src/display/editor/draw.js index 8e9e9641a..e63240a72 100644 --- a/src/display/editor/draw.js +++ b/src/display/editor/draw.js @@ -280,9 +280,9 @@ class DrawingEditor extends AnnotationEditor { } /** @inheritdoc */ - _onTranslating(x, y) { + _onTranslating(_x, _y) { this.parent?.drawLayer.updateProperties(this._drawId, { - bbox: this.#rotateBox(x, y), + bbox: this.#rotateBox(), }); } diff --git a/src/display/editor/editor.js b/src/display/editor/editor.js index 54703a4d0..a9f03f846 100644 --- a/src/display/editor/editor.js +++ b/src/display/editor/editor.js @@ -476,6 +476,10 @@ class AnnotationEditor { this.div.scrollIntoView({ block: "nearest" }); } + translationDone() { + this._onTranslated(this.x, this.y); + } + drag(tx, ty) { this.#initialRect ||= [this.x, this.y, this.width, this.height]; const { diff --git a/src/display/editor/tools.js b/src/display/editor/tools.js index 06a501700..01ff2050a 100644 --- a/src/display/editor/tools.js +++ b/src/display/editor/tools.js @@ -2264,6 +2264,7 @@ class AnnotationEditorUIManager { for (const editor of editors) { if (this.#allEditors.has(editor.id)) { editor.translateInPage(totalX, totalY); + editor.translationDone(); } } }, @@ -2271,6 +2272,7 @@ class AnnotationEditorUIManager { for (const editor of editors) { if (this.#allEditors.has(editor.id)) { editor.translateInPage(-totalX, -totalY); + editor.translationDone(); } } }, @@ -2280,6 +2282,7 @@ class AnnotationEditorUIManager { for (const editor of editors) { editor.translateInPage(x, y); + editor.translationDone(); } } diff --git a/test/integration/freetext_editor_spec.mjs b/test/integration/freetext_editor_spec.mjs index a14e10762..404e24eb9 100644 --- a/test/integration/freetext_editor_spec.mjs +++ b/test/integration/freetext_editor_spec.mjs @@ -40,6 +40,7 @@ import { kbSelectAll, kbUndo, loadAndWait, + moveEditor, paste, pasteFromClipboard, scrollIntoView, @@ -48,7 +49,6 @@ import { unselectEditor, waitForAnnotationEditorLayer, waitForAnnotationModeChanged, - waitForEditorMovedInDOM, waitForSelectedEditor, waitForSerialized, waitForStorageEntries, @@ -79,33 +79,6 @@ const commit = async page => { const switchToFreeText = switchToEditor.bind(null, "FreeText"); -const getXY = async (page, selector) => { - const rect = await getRect(page, selector); - return `${rect.x}::${rect.y}`; -}; - -const waitForPositionChange = (page, selector, xy) => - page.waitForFunction( - (sel, currentXY) => { - const bbox = document.querySelector(sel).getBoundingClientRect(); - return `${bbox.x}::${bbox.y}` !== currentXY; - }, - {}, - selector, - xy - ); - -const moveEditor = async (page, selector, n, pressKey) => { - let xy = await getXY(page, selector); - for (let i = 0; i < n; i++) { - const handle = await waitForEditorMovedInDOM(page); - await pressKey(); - await awaitPromise(handle); - await waitForPositionChange(page, selector, xy); - xy = await getXY(page, selector); - } -}; - const cancelFocusIn = async (page, selector) => { page.evaluate(sel => { const el = document.querySelector(sel); diff --git a/test/integration/ink_editor_spec.mjs b/test/integration/ink_editor_spec.mjs index 4abc08a7b..2e927231f 100644 --- a/test/integration/ink_editor_spec.mjs +++ b/test/integration/ink_editor_spec.mjs @@ -27,6 +27,7 @@ import { kbSelectAll, kbUndo, loadAndWait, + moveEditor, scrollIntoView, selectEditor, switchToEditor, @@ -142,6 +143,50 @@ describe("Ink Editor", () => { }) ); }); + + it("must draw and move with the keyboard", async () => { + await Promise.all( + pages.map(async ([browserName, page]) => { + await switchToInk(page); + + const rect = await getRect(page, ".annotationEditorLayer"); + + const x = rect.x + 100; + const y = rect.y + 100; + const clickHandle = await waitForPointerUp(page); + await page.mouse.move(x, y); + await page.mouse.down(); + await page.mouse.move(x + 50, y + 50); + await page.mouse.up(); + await awaitPromise(clickHandle); + + await commit(page); + + const editorSelector = getEditorSelector(0); + await page.waitForSelector(editorSelector); + const rectBefore = (await getSerialized(page, s => s.rect))[0]; + + const N = 20; + await moveEditor(page, editorSelector, N, () => + page.keyboard.press("ArrowDown") + ); + const rectAfter = (await getSerialized(page, s => s.rect))[0]; + + expect(Math.abs(rectBefore[0] - rectAfter[0])) + .withContext(`In ${browserName}`) + .toBeLessThan(1e-2); + expect(Math.abs(rectBefore[1] - N - rectAfter[1])) + .withContext(`In ${browserName}`) + .toBeLessThan(1e-2); + expect(Math.abs(rectBefore[2] - rectAfter[2])) + .withContext(`In ${browserName}`) + .toBeLessThan(1e-2); + expect(Math.abs(rectBefore[3] - N - rectAfter[3])) + .withContext(`In ${browserName}`) + .toBeLessThan(1e-2); + }) + ); + }); }); describe("with a rotated pdf", () => { diff --git a/test/integration/test_utils.mjs b/test/integration/test_utils.mjs index 5d4396d30..b89d0feae 100644 --- a/test/integration/test_utils.mjs +++ b/test/integration/test_utils.mjs @@ -849,6 +849,34 @@ async function cleanupEditing(pages, switcher) { } } +async function getXY(page, selector) { + const rect = await getRect(page, selector); + return `${rect.x}::${rect.y}`; +} + +function waitForPositionChange(page, selector, xy) { + return page.waitForFunction( + (sel, currentXY) => { + const bbox = document.querySelector(sel).getBoundingClientRect(); + return `${bbox.x}::${bbox.y}` !== currentXY; + }, + {}, + selector, + xy + ); +} + +async function moveEditor(page, selector, n, pressKey) { + let xy = await getXY(page, selector); + for (let i = 0; i < n; i++) { + const handle = await waitForEditorMovedInDOM(page); + await pressKey(); + await awaitPromise(handle); + await waitForPositionChange(page, selector, xy); + xy = await getXY(page, selector); + } +} + export { applyFunctionToEditor, awaitPromise, @@ -893,6 +921,7 @@ export { kbUndo, loadAndWait, mockClipboard, + moveEditor, paste, pasteFromClipboard, scrollIntoView,