diff --git a/src/display/annotation_layer.js b/src/display/annotation_layer.js index b44633e11..5c576635b 100644 --- a/src/display/annotation_layer.js +++ b/src/display/annotation_layer.js @@ -601,6 +601,20 @@ class AnnotationElement { triggers.classList.add("highlightArea"); } } + + _editOnDoubleClick() { + const { + annotationEditorType: mode, + data: { id: editId }, + } = this; + this.container.addEventListener("dblclick", () => { + this.linkService.eventBus?.dispatch("switchannotationeditormode", { + source: this, + mode, + editId, + }); + }); + } } class LinkAnnotationElement extends AnnotationElement { @@ -2217,6 +2231,9 @@ class FreeTextAnnotationElement extends AnnotationElement { if (!this.data.popupRef) { this._createPopup(); } + + this._editOnDoubleClick(); + return this.container; } } diff --git a/src/display/editor/editor.js b/src/display/editor/editor.js index dff21f93d..826a70fbc 100644 --- a/src/display/editor/editor.js +++ b/src/display/editor/editor.js @@ -621,6 +621,11 @@ class AnnotationEditor { */ enableEditing() {} + /** + * The editor is about to be edited. + */ + enterInEditMode() {} + /** * Get the div which really contains the displayed content. */ diff --git a/src/display/editor/freetext.js b/src/display/editor/freetext.js index 70b2268f9..e28536f9e 100644 --- a/src/display/editor/freetext.js +++ b/src/display/editor/freetext.js @@ -403,13 +403,18 @@ class FreeTextEditor extends AnnotationEditor { return this.isInEditMode(); } + /** @inheritdoc */ + enterInEditMode() { + this.enableEditMode(); + this.editorDiv.focus(); + } + /** * ondblclick callback. * @param {MouseEvent} event */ dblclick(event) { - this.enableEditMode(); - this.editorDiv.focus(); + this.enterInEditMode(); } /** @@ -418,8 +423,7 @@ class FreeTextEditor extends AnnotationEditor { */ keydown(event) { if (event.target === this.div && event.key === "Enter") { - this.enableEditMode(); - this.editorDiv.focus(); + this.enterInEditMode(); } } diff --git a/src/display/editor/tools.js b/src/display/editor/tools.js index 988608afa..d7733ffce 100644 --- a/src/display/editor/tools.js +++ b/src/display/editor/tools.js @@ -912,17 +912,28 @@ class AnnotationEditorUIManager { /** * Change the editor mode (None, FreeText, Ink, ...) * @param {number} mode + * @param {string|null} editId */ - updateMode(mode) { + updateMode(mode, editId = null) { this.#mode = mode; if (mode === AnnotationEditorType.NONE) { this.setEditingState(false); this.#disableAll(); - } else { - this.setEditingState(true); - this.#enableAll(); - for (const layer of this.#allLayers.values()) { - layer.updateMode(mode); + return; + } + this.setEditingState(true); + this.#enableAll(); + for (const layer of this.#allLayers.values()) { + layer.updateMode(mode); + } + if (!editId) { + return; + } + for (const editor of this.#allEditors.values()) { + if (editor.annotationElementId === editId) { + this.setSelected(editor); + editor.enterInEditMode(); + break; } } } diff --git a/test/integration/freetext_editor_spec.js b/test/integration/freetext_editor_spec.js index a3c4633a5..69062ff5a 100644 --- a/test/integration/freetext_editor_spec.js +++ b/test/integration/freetext_editor_spec.js @@ -1115,6 +1115,39 @@ describe("FreeText Editor", () => { }); }); + describe("FreeText (edit existing in double clicking on it)", () => { + let pages; + + beforeAll(async () => { + pages = await loadAndWait("freetexts.pdf", ".annotationEditorLayer"); + }); + + afterAll(async () => { + await closePages(pages); + }); + + it("must move an annotation", async () => { + await Promise.all( + pages.map(async ([browserName, page]) => { + await page.click("[data-annotation-id='26R']", { clickCount: 2 }); + await page.waitForTimeout(10); + + const [focusedId, editable] = await page.evaluate(() => { + const el = document.activeElement; + return [el.id, el.contentEditable]; + }); + expect(focusedId) + .withContext(`In ${browserName}`) + .toEqual("pdfjs_internal_editor_0-editor"); + expect(editable).withContext(`In ${browserName}`).toEqual("true"); + + const editorIds = await getEditors(page, "freeText"); + expect(editorIds.length).withContext(`In ${browserName}`).toEqual(6); + }) + ); + }); + }); + describe("FreeText with popup", () => { let pages; diff --git a/web/app.js b/web/app.js index 8d233e234..b7c245b6d 100644 --- a/web/app.js +++ b/web/app.js @@ -2518,7 +2518,7 @@ function webViewerPresentationMode() { PDFViewerApplication.requestPresentationMode(); } function webViewerSwitchAnnotationEditorMode(evt) { - PDFViewerApplication.pdfViewer.annotationEditorMode = evt.mode; + PDFViewerApplication.pdfViewer.annotationEditorMode = evt; } function webViewerSwitchAnnotationEditorParams(evt) { PDFViewerApplication.pdfViewer.annotationEditorParams = evt; diff --git a/web/pdf_presentation_mode.js b/web/pdf_presentation_mode.js index 6659fbb9f..34973a242 100644 --- a/web/pdf_presentation_mode.js +++ b/web/pdf_presentation_mode.js @@ -175,7 +175,9 @@ class PDFPresentationMode { this.pdfViewer.currentScaleValue = "page-fit"; if (this.#args.annotationEditorMode !== null) { - this.pdfViewer.annotationEditorMode = AnnotationEditorType.NONE; + this.pdfViewer.annotationEditorMode = { + mode: AnnotationEditorType.NONE, + }; } }, 0); diff --git a/web/pdf_viewer.js b/web/pdf_viewer.js index f8a709058..6c4f48122 100644 --- a/web/pdf_viewer.js +++ b/web/pdf_viewer.js @@ -2203,7 +2203,7 @@ class PDFViewer { /** * @param {number} mode - AnnotationEditor mode (None, FreeText, Ink, ...) */ - set annotationEditorMode(mode) { + set annotationEditorMode({ mode, editId = null }) { if (!this.#annotationEditorUIManager) { throw new Error(`The AnnotationEditor is not enabled.`); } @@ -2222,7 +2222,7 @@ class PDFViewer { mode, }); - this.#annotationEditorUIManager.updateMode(mode); + this.#annotationEditorUIManager.updateMode(mode, editId); } // eslint-disable-next-line accessor-pairs