From 822d3ea809979e480a79156de2b2718f1f6f35c2 Mon Sep 17 00:00:00 2001 From: calixteman Date: Mon, 27 Jul 2026 15:52:25 +0200 Subject: [PATCH] [Editor] Restore pinch-to-resize on an editor which came back from an undo `AnnotationEditor.remove()` destroys the editor's `TouchManager`, but `remove()` is also the undo half of an edit: deleting a drawing and undoing it, or undoing the drawing itself and redoing it, brings the very same editor back. --- src/display/editor/editor.js | 31 +++++++++----- test/integration/ink_editor_spec.mjs | 64 ++++++++++++++++++++++++++++ 2 files changed, 85 insertions(+), 10 deletions(-) diff --git a/src/display/editor/editor.js b/src/display/editor/editor.js index c18c4b8c3..8235254b4 100644 --- a/src/display/editor/editor.js +++ b/src/display/editor/editor.js @@ -1359,16 +1359,7 @@ class AnnotationEditor { bindEvents(this, div, ["keydown", "pointerdown", "dblclick"]); - if (this.isResizable && this._uiManager._supportsPinchToZoom) { - this.#touchManager ||= new TouchManager({ - container: div, - isPinchingDisabled: () => !this.isSelected, - onPinchStart: this.#touchPinchStartCallback.bind(this), - onPinching: this.#touchPinchCallback.bind(this), - onPinchEnd: this.#touchPinchEndCallback.bind(this), - signal: this._uiManager._signal, - }); - } + this.#addTouchManager(); this.addStandaloneCommentButton(); this._uiManager._editorUndoBar?.hide(); @@ -1803,6 +1794,25 @@ class AnnotationEditor { this.div.addEventListener("focusout", this.focusout.bind(this), { signal }); } + #addTouchManager() { + if ( + this.#touchManager || + !this.div || + !this.isResizable || + !this._uiManager._supportsPinchToZoom + ) { + return; + } + this.#touchManager = new TouchManager({ + container: this.div, + isPinchingDisabled: () => !this.isSelected, + onPinchStart: this.#touchPinchStartCallback.bind(this), + onPinching: this.#touchPinchCallback.bind(this), + onPinchEnd: this.#touchPinchEndCallback.bind(this), + signal: this._uiManager._signal, + }); + } + /** * Rebuild the editor in case it has been removed on undo. * @@ -1810,6 +1820,7 @@ class AnnotationEditor { */ rebuild() { this.#addFocusListeners(); + this.#addTouchManager(); } /** diff --git a/test/integration/ink_editor_spec.mjs b/test/integration/ink_editor_spec.mjs index c33af9504..b9d2eb9e8 100644 --- a/test/integration/ink_editor_spec.mjs +++ b/test/integration/ink_editor_spec.mjs @@ -1407,3 +1407,67 @@ describe("Ink must be committed when the document is saved", () => { ); }); }); + +describe("Pinch to resize a drawing", () => { + let pages; + + beforeEach(async () => { + pages = await loadAndWait("empty.pdf", ".annotationEditorLayer"); + }); + + afterEach(async () => { + await closePages(pages); + }); + + // Spread two fingers apart, centered on the editor. + async function pinchOut(page, selector) { + const { x, y, width, height } = await getRect(page, selector); + const centerX = x + width / 2; + const centerY = y + height / 2; + const finger0 = await page.touchscreen.touchStart(centerX - 25, centerY); + const finger1 = await page.touchscreen.touchStart(centerX + 25, centerY); + for (let i = 1; i <= 12; i++) { + const gap = 25 + i * 12; + await finger0.move(centerX - gap, centerY); + await finger1.move(centerX + gap, centerY); + } + await finger0.end(); + await finger1.end(); + } + + it("must keep resizing a drawing which came back with an undo", async () => { + await Promise.all( + pages.map(async ([browserName, page]) => { + if (browserName === "firefox") { + pending( + "Touch events are not supported on devices without touch screen in Firefox." + ); + } + await switchToInk(page); + + const rect = await getRect(page, ".annotationEditorLayer"); + await drawLine( + page, + rect.x + 200, + rect.y + 200, + rect.x + 300, + rect.y + 260 + ); + await commit(page); + + const editorSelector = getEditorSelector(0); + await clearAll(page); + await waitForNoElement(page, editorSelector); + await kbUndo(page); + await page.waitForSelector(editorSelector); + await selectEditor(page, editorSelector); + + const { width: before } = await getRect(page, editorSelector); + await pinchOut(page, editorSelector); + const { width: after } = await getRect(page, editorSelector); + + expect(after).withContext(`In ${browserName}`).toBeGreaterThan(before); + }) + ); + }); +});