From 6d2c6cfc9f0c34ddee7fb96ae7ce7c3800f2c416 Mon Sep 17 00:00:00 2001 From: Calixte Denizet Date: Thu, 3 Jul 2025 20:04:24 +0200 Subject: [PATCH] [Editor] Allow to change the editor mode when selecting the corresponding editor (bug 1975538) For example, selecting an ink editor just after having created a freetext will switch to ink mode. --- src/display/annotation_layer.js | 1 + src/display/editor/editor.js | 4 ++ src/display/editor/tools.js | 18 +++++++- test/integration/freetext_editor_spec.mjs | 54 +++++++++++++++++++++++ web/pdf_viewer.js | 12 ++++- 5 files changed, 85 insertions(+), 4 deletions(-) diff --git a/src/display/annotation_layer.js b/src/display/annotation_layer.js index ff0d638e5..85c5b41d0 100644 --- a/src/display/annotation_layer.js +++ b/src/display/annotation_layer.js @@ -730,6 +730,7 @@ class AnnotationElement { source: this, mode, editId, + mustEnterInEditMode: true, }); }); } diff --git a/src/display/editor/editor.js b/src/display/editor/editor.js index 4714c9a78..a0153b63f 100644 --- a/src/display/editor/editor.js +++ b/src/display/editor/editor.js @@ -205,6 +205,10 @@ class AnnotationEditor { return Object.getPrototypeOf(this).constructor._type; } + get mode() { + return Object.getPrototypeOf(this).constructor._editorType; + } + static get isDrawer() { return false; } diff --git a/src/display/editor/tools.js b/src/display/editor/tools.js index 772588586..c7a78139d 100644 --- a/src/display/editor/tools.js +++ b/src/display/editor/tools.js @@ -1684,8 +1684,15 @@ class AnnotationEditorUIManager { * @param {string|null} editId * @param {boolean} [isFromKeyboard] - true if the mode change is due to a * keyboard action. + * @param {boolean} [mustEnterInEditMode] - true if the editor must enter in + * edit mode. */ - async updateMode(mode, editId = null, isFromKeyboard = false) { + async updateMode( + mode, + editId = null, + isFromKeyboard = false, + mustEnterInEditMode = false + ) { if (this.#mode === mode) { return; } @@ -1732,7 +1739,9 @@ class AnnotationEditorUIManager { for (const editor of this.#allEditors.values()) { if (editor.annotationElementId === editId || editor.id === editId) { this.setSelected(editor); - editor.enterInEditMode(); + if (mustEnterInEditMode) { + editor.enterInEditMode(); + } } else { editor.unselect(); } @@ -2036,6 +2045,11 @@ class AnnotationEditorUIManager { * @param {AnnotationEditor} editor */ setSelected(editor) { + this.updateToolbar({ + mode: editor.mode, + editId: editor.id, + }); + this.#currentDrawingSession?.commitOrRemove(); for (const ed of this.#selectedEditors) { if (ed !== editor) { diff --git a/test/integration/freetext_editor_spec.mjs b/test/integration/freetext_editor_spec.mjs index 288a77d8d..46d9580ad 100644 --- a/test/integration/freetext_editor_spec.mjs +++ b/test/integration/freetext_editor_spec.mjs @@ -49,6 +49,7 @@ import { unselectEditor, waitForAnnotationEditorLayer, waitForAnnotationModeChanged, + waitForPointerUp, waitForSelectedEditor, waitForSerialized, waitForStorageEntries, @@ -3392,5 +3393,58 @@ describe("FreeText Editor", () => { }) ); }); + + it("must check that we switch to FreeText in clicking on a FreeText annotation", async () => { + await Promise.all( + pages.map(async ([browserName, page]) => { + await switchToFreeText(page); + + const rect = await getRect(page, ".annotationEditorLayer"); + const editorSelector = getEditorSelector(0); + + const data = "Hello PDF.js World !!"; + await page.mouse.click( + rect.x + rect.width / 2, + rect.y + rect.height / 2 + ); + await page.waitForSelector(editorSelector, { visible: true }); + await page.type(`${editorSelector} .internal`, data); + await commit(page); + await waitForSerialized(page, 1); + + await switchToFreeText(page, /* disable */ true); + await switchToEditor("Ink", page); + + 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 page.keyboard.press("Escape"); + await page.waitForSelector( + ".inkEditor.selectedEditor.draggable.disabled" + ); + await waitForSerialized(page, 2); + + const modeChangedHandle = await createPromise(page, resolve => { + window.PDFViewerApplication.eventBus.on( + "annotationeditormodechanged", + resolve, + { once: true } + ); + }); + const editorRect = await getRect(page, editorSelector); + await page.mouse.click( + editorRect.x + editorRect.width / 2, + editorRect.y + editorRect.height / 2 + ); + await page.waitForSelector(".annotationEditorLayer.freetextEditing"); + await awaitPromise(modeChangedHandle); + }) + ); + }); }); }); diff --git a/web/pdf_viewer.js b/web/pdf_viewer.js index 92667c0b0..2ec876467 100644 --- a/web/pdf_viewer.js +++ b/web/pdf_viewer.js @@ -2401,12 +2401,19 @@ class PDFViewer { * @property {string|null} [editId] - ID of the existing annotation to edit. * @property {boolean} [isFromKeyboard] - True if the mode change is due to a * keyboard action. + * @property {boolean} [mustEnterInEditMode] - True if the editor must enter + * edit mode. */ /** * @param {AnnotationEditorModeOptions} options */ - set annotationEditorMode({ mode, editId = null, isFromKeyboard = false }) { + set annotationEditorMode({ + mode, + editId = null, + isFromKeyboard = false, + mustEnterInEditMode = false, + }) { if (!this.#annotationEditorUIManager) { throw new Error(`The AnnotationEditor is not enabled.`); } @@ -2428,7 +2435,8 @@ class PDFViewer { await this.#annotationEditorUIManager.updateMode( mode, editId, - isFromKeyboard + isFromKeyboard, + mustEnterInEditMode ); if ( mode !== this.#annotationEditorMode ||