From 9f861c39f4c902d0a6a72fd18859d9fdd3778675 Mon Sep 17 00:00:00 2001 From: Calixte Denizet Date: Mon, 5 Jun 2023 11:32:44 +0200 Subject: [PATCH] [Editor] Connect then annotation layer and the editor one --- src/display/annotation_layer.js | 33 +++++++++++++++++-- src/display/editor/annotation_editor_layer.js | 23 ++++++++++++- src/display/editor/editor.js | 10 ++++++ src/display/editor/freetext.js | 4 +++ src/display/editor/ink.js | 4 +++ web/annotation_editor_layer_builder.js | 7 ++++ web/pdf_page_view.js | 1 + 7 files changed, 79 insertions(+), 3 deletions(-) diff --git a/src/display/annotation_layer.js b/src/display/annotation_layer.js index 600e4199c..12afde2d3 100644 --- a/src/display/annotation_layer.js +++ b/src/display/annotation_layer.js @@ -20,6 +20,7 @@ import { AnnotationBorderStyleType, + AnnotationEditorType, AnnotationType, assert, FeatureTest, @@ -504,7 +505,7 @@ class AnnotationElement { * * @public * @memberof AnnotationElement - * @returns {HTMLElement|Array} A section element or + * @returns {HTMLElement|Array|undefined} A section element or * an array of section elements. */ render() { @@ -558,6 +559,18 @@ class AnnotationElement { } return fields; } + + show() { + if (this.container) { + this.container.hidden = false; + } + } + + hide() { + if (this.container) { + this.container.hidden = true; + } + } } class LinkAnnotationElement extends AnnotationElement { @@ -2048,6 +2061,7 @@ class FreeTextAnnotationElement extends AnnotationElement { ); super(parameters, { isRenderable, ignoreBorder: true }); this.textContent = parameters.data.textContent; + this.annotationEditorType = AnnotationEditorType.FREETEXT; } render() { @@ -2328,6 +2342,7 @@ class InkAnnotationElement extends AnnotationElement { // Use the polyline SVG element since it allows us to use coordinates // directly and to draw both straight lines and curves. this.svgElementName = "svg:polyline"; + this.annotationEditorType = AnnotationEditorType.INK; } render() { @@ -2596,6 +2611,9 @@ class FileAttachmentAnnotationElement extends AnnotationElement { * @property {TextAccessibilityManager} [accessibilityManager] */ +/** + * Manage the layer containing all the annotations. + */ class AnnotationLayer { #accessibilityManager = null; @@ -2603,6 +2621,8 @@ class AnnotationLayer { #div = null; + #editableAnnotations = new Set(); + constructor({ div, accessibilityManager, annotationCanvasMap }) { this.#div = div; this.#accessibilityManager = accessibilityManager; @@ -2666,6 +2686,11 @@ class AnnotationLayer { if (!element.isRenderable) { continue; } + + if (element.annotationEditorType > 0) { + this.#editableAnnotations.add(element); + } + const rendered = element.render(); if (data.hidden) { rendered.style.visibility = "hidden"; @@ -2732,6 +2757,10 @@ class AnnotationLayer { } this.#annotationCanvasMap.clear(); } + + getEditableAnnotations() { + return this.#editableAnnotations; + } } -export { AnnotationLayer }; +export { AnnotationLayer, FreeTextAnnotationElement, InkAnnotationElement }; diff --git a/src/display/editor/annotation_editor_layer.js b/src/display/editor/annotation_editor_layer.js index 261412fd5..d2fa914ed 100644 --- a/src/display/editor/annotation_editor_layer.js +++ b/src/display/editor/annotation_editor_layer.js @@ -20,6 +20,8 @@ // eslint-disable-next-line max-len /** @typedef {import("../../web/text_accessibility.js").TextAccessibilityManager} TextAccessibilityManager */ /** @typedef {import("../../web/interfaces").IL10n} IL10n */ +// eslint-disable-next-line max-len +/** @typedef {import("../src/display/annotation_layer.js").AnnotationLayer} AnnotationLayer */ import { AnnotationEditorType, FeatureTest } from "../../shared/util.js"; import { bindEvents } from "./tools.js"; @@ -36,6 +38,7 @@ import { setLayerDimensions } from "../display_utils.js"; * @property {TextAccessibilityManager} [accessibilityManager] * @property {number} pageIndex * @property {IL10n} l10n + * @property {AnnotationLayer} [annotationLayer] */ /** @@ -51,6 +54,8 @@ class AnnotationEditorLayer { #allowClick = false; + #annotationLayer = null; + #boundPointerup = this.pointerup.bind(this); #boundPointerdown = this.pointerdown.bind(this); @@ -80,6 +85,7 @@ class AnnotationEditorLayer { this.pageIndex = options.pageIndex; this.div = options.div; this.#accessibilityManager = options.accessibilityManager; + this.#annotationLayer = options.annotationLayer; this.#uiManager.addLayer(this); } @@ -169,6 +175,17 @@ class AnnotationEditorLayer { */ enable() { this.div.style.pointerEvents = "auto"; + if (this.#annotationLayer) { + const editables = this.#annotationLayer.getEditableAnnotations(); + for (const editable of editables) { + const editor = this.deserialize(editable); + if (!editor) { + continue; + } + editable.hide(); + this.addOrRebuild(editor); + } + } for (const editor of this.#editors.values()) { editor.enableEditing(); } @@ -181,6 +198,10 @@ class AnnotationEditorLayer { this.div.style.pointerEvents = "none"; for (const editor of this.#editors.values()) { editor.disableEditing(); + if (!editor.hasElementChanged()) { + editor.annotationElement.show(); + editor.remove(); + } } this.#cleanup(); if (this.isEmpty) { @@ -368,7 +389,7 @@ class AnnotationEditorLayer { * @returns {AnnotationEditor} */ deserialize(data) { - switch (data.annotationType) { + switch (data.annotationType ?? data.annotationEditorType) { case AnnotationEditorType.FREETEXT: return FreeTextEditor.deserialize(data, this, this.#uiManager); case AnnotationEditorType.INK: diff --git a/src/display/editor/editor.js b/src/display/editor/editor.js index 300d8a9d2..ce601452a 100644 --- a/src/display/editor/editor.js +++ b/src/display/editor/editor.js @@ -67,6 +67,7 @@ class AnnotationEditor { this.name = parameters.name; this.div = null; this._uiManager = parameters.uiManager; + this.annotationElement = null; const { rotation, @@ -599,6 +600,15 @@ class AnnotationEditor { this.parent.setActiveEditor(null); } } + + /** + * Check if the editor has been changed. + * @param {Object} serialized + * @returns {boolean} + */ + hasElementChanged(serialized = null) { + return false; + } } export { AnnotationEditor }; diff --git a/src/display/editor/freetext.js b/src/display/editor/freetext.js index fe6694f75..b3fe34a5c 100644 --- a/src/display/editor/freetext.js +++ b/src/display/editor/freetext.js @@ -26,6 +26,7 @@ import { } from "../../shared/util.js"; import { bindEvents, KeyboardManager } from "./tools.js"; import { AnnotationEditor } from "./editor.js"; +import { FreeTextAnnotationElement } from "../annotation_layer.js"; /** * Basic text editor in order to create a FreeTex annotation. @@ -489,6 +490,9 @@ class FreeTextEditor extends AnnotationEditor { /** @inheritdoc */ static deserialize(data, parent, uiManager) { + if (data instanceof FreeTextAnnotationElement) { + return null; + } const editor = super.deserialize(data, parent, uiManager); editor.#fontSize = data.fontSize; diff --git a/src/display/editor/ink.js b/src/display/editor/ink.js index 7072ad615..5ec0fdb1b 100644 --- a/src/display/editor/ink.js +++ b/src/display/editor/ink.js @@ -19,6 +19,7 @@ import { Util, } from "../../shared/util.js"; import { AnnotationEditor } from "./editor.js"; +import { InkAnnotationElement } from "../annotation_layer.js"; import { opacityToHex } from "./tools.js"; // The dimensions of the resizer is 15x15: @@ -1130,6 +1131,9 @@ class InkEditor extends AnnotationEditor { /** @inheritdoc */ static deserialize(data, parent, uiManager) { + if (data instanceof InkAnnotationElement) { + return null; + } const editor = super.deserialize(data, parent, uiManager); editor.thickness = data.thickness; diff --git a/web/annotation_editor_layer_builder.js b/web/annotation_editor_layer_builder.js index 085545b46..a15ffa79a 100644 --- a/web/annotation_editor_layer_builder.js +++ b/web/annotation_editor_layer_builder.js @@ -21,6 +21,8 @@ // eslint-disable-next-line max-len /** @typedef {import("./text_accessibility.js").TextAccessibilityManager} TextAccessibilityManager */ /** @typedef {import("./interfaces").IL10n} IL10n */ +// eslint-disable-next-line max-len +/** @typedef {import("../src/display/annotation_layer.js").AnnotationLayer} AnnotationLayer */ import { AnnotationEditorLayer } from "pdfjs-lib"; import { NullL10n } from "./l10n_utils.js"; @@ -32,9 +34,12 @@ import { NullL10n } from "./l10n_utils.js"; * @property {PDFPageProxy} pdfPage * @property {IL10n} [l10n] * @property {TextAccessibilityManager} [accessibilityManager] + * @property {AnnotationLayer} [annotationLayer] */ class AnnotationEditorLayerBuilder { + #annotationLayer = null; + #uiManager; /** @@ -49,6 +54,7 @@ class AnnotationEditorLayerBuilder { this.div = null; this._cancelled = false; this.#uiManager = options.uiManager; + this.#annotationLayer = options.annotationLayer || null; } /** @@ -85,6 +91,7 @@ class AnnotationEditorLayerBuilder { pageIndex: this.pdfPage.pageNumber - 1, l10n: this.l10n, viewport: clonedViewport, + annotationLayer: this.#annotationLayer, }); const parameters = { diff --git a/web/pdf_page_view.js b/web/pdf_page_view.js index e5f1e7eb0..4825d1ef7 100644 --- a/web/pdf_page_view.js +++ b/web/pdf_page_view.js @@ -979,6 +979,7 @@ class PDFPageView { pdfPage, l10n, accessibilityManager: this._accessibilityManager, + annotationLayer: this.annotationLayer?.annotationLayer, }); } this.#renderAnnotationEditorLayer();