[Editor] Provide an element to render in the annotation layer after a freetext has been edited (bug 1890535)

This commit is contained in:
Calixte Denizet 2024-04-09 15:25:49 +02:00
parent 7290faf840
commit 71ea8499f0
11 changed files with 379 additions and 42 deletions

View file

@ -20,6 +20,8 @@
// eslint-disable-next-line max-len
/** @typedef {import("../../web/interfaces").IDownloadManager} IDownloadManager */
/** @typedef {import("../../web/interfaces").IPDFLinkService} IPDFLinkService */
// eslint-disable-next-line max-len
/** @typedef {import("../src/display/editor/tools.js").AnnotationEditorUIManager} AnnotationEditorUIManager */
import {
AnnotationBorderStyleType,
@ -157,6 +159,8 @@ class AnnotationElementFactory {
}
class AnnotationElement {
#updates = null;
#hasBorder = false;
constructor(
@ -197,6 +201,52 @@ class AnnotationElement {
return AnnotationElement._hasPopupData(this.data);
}
updateEdited(params) {
if (!this.container) {
return;
}
this.#updates ||= {
rect: this.data.rect.slice(0),
};
const { rect } = params;
if (rect) {
this.#setRectEdited(rect);
}
}
resetEdited() {
if (!this.#updates) {
return;
}
this.#setRectEdited(this.#updates.rect);
this.#updates = null;
}
#setRectEdited(rect) {
const {
container: { style },
data: { rect: currentRect, rotation },
parent: {
viewport: {
rawDims: { pageWidth, pageHeight, pageX, pageY },
},
},
} = this;
currentRect?.splice(0, 4, ...rect);
const { width, height } = getRectDims(rect);
style.left = `${(100 * (rect[0] - pageX)) / pageWidth}%`;
style.top = `${(100 * (pageHeight - rect[3] + pageY)) / pageHeight}%`;
if (rotation === 0) {
style.width = `${(100 * width) / pageWidth}%`;
style.height = `${(100 * height) / pageHeight}%`;
} else {
this.setRotation(rotation);
}
}
/**
* Create an empty container for the annotation's HTML element.
*
@ -216,13 +266,14 @@ class AnnotationElement {
if (!(this instanceof WidgetAnnotationElement)) {
container.tabIndex = DEFAULT_TAB_INDEX;
}
const { style } = container;
// The accessibility manager will move the annotation in the DOM in
// order to match the visual ordering.
// But if an annotation is above an other one, then we must draw it
// after the other one whatever the order is in the DOM, hence the
// use of the z-index.
container.style.zIndex = this.parent.zIndex++;
style.zIndex = this.parent.zIndex++;
if (data.popupRef) {
container.setAttribute("aria-haspopup", "dialog");
@ -236,8 +287,6 @@ class AnnotationElement {
container.classList.add("norotate");
}
const { pageWidth, pageHeight, pageX, pageY } = viewport.rawDims;
if (!data.rect || this instanceof PopupAnnotationElement) {
const { rotation } = data;
if (!data.hasOwnCanvas && rotation !== 0) {
@ -248,35 +297,26 @@ class AnnotationElement {
const { width, height } = getRectDims(data.rect);
// Do *not* modify `data.rect`, since that will corrupt the annotation
// position on subsequent calls to `_createContainer` (see issue 6804).
const rect = Util.normalizeRect([
data.rect[0],
page.view[3] - data.rect[1] + page.view[1],
data.rect[2],
page.view[3] - data.rect[3] + page.view[1],
]);
if (!ignoreBorder && data.borderStyle.width > 0) {
container.style.borderWidth = `${data.borderStyle.width}px`;
style.borderWidth = `${data.borderStyle.width}px`;
const horizontalRadius = data.borderStyle.horizontalCornerRadius;
const verticalRadius = data.borderStyle.verticalCornerRadius;
if (horizontalRadius > 0 || verticalRadius > 0) {
const radius = `calc(${horizontalRadius}px * var(--scale-factor)) / calc(${verticalRadius}px * var(--scale-factor))`;
container.style.borderRadius = radius;
style.borderRadius = radius;
} else if (this instanceof RadioButtonWidgetAnnotationElement) {
const radius = `calc(${width}px * var(--scale-factor)) / calc(${height}px * var(--scale-factor))`;
container.style.borderRadius = radius;
style.borderRadius = radius;
}
switch (data.borderStyle.style) {
case AnnotationBorderStyleType.SOLID:
container.style.borderStyle = "solid";
style.borderStyle = "solid";
break;
case AnnotationBorderStyleType.DASHED:
container.style.borderStyle = "dashed";
style.borderStyle = "dashed";
break;
case AnnotationBorderStyleType.BEVELED:
@ -288,7 +328,7 @@ class AnnotationElement {
break;
case AnnotationBorderStyleType.UNDERLINE:
container.style.borderBottomStyle = "solid";
style.borderBottomStyle = "solid";
break;
default:
@ -298,24 +338,34 @@ class AnnotationElement {
const borderColor = data.borderColor || null;
if (borderColor) {
this.#hasBorder = true;
container.style.borderColor = Util.makeHexColor(
style.borderColor = Util.makeHexColor(
borderColor[0] | 0,
borderColor[1] | 0,
borderColor[2] | 0
);
} else {
// Transparent (invisible) border, so do not draw it at all.
container.style.borderWidth = 0;
style.borderWidth = 0;
}
}
container.style.left = `${(100 * (rect[0] - pageX)) / pageWidth}%`;
container.style.top = `${(100 * (rect[1] - pageY)) / pageHeight}%`;
// Do *not* modify `data.rect`, since that will corrupt the annotation
// position on subsequent calls to `_createContainer` (see issue 6804).
const rect = Util.normalizeRect([
data.rect[0],
page.view[3] - data.rect[1] + page.view[1],
data.rect[2],
page.view[3] - data.rect[3] + page.view[1],
]);
const { pageWidth, pageHeight, pageX, pageY } = viewport.rawDims;
style.left = `${(100 * (rect[0] - pageX)) / pageWidth}%`;
style.top = `${(100 * (rect[1] - pageY)) / pageHeight}%`;
const { rotation } = data;
if (data.hasOwnCanvas || rotation === 0) {
container.style.width = `${(100 * width) / pageWidth}%`;
container.style.height = `${(100 * height) / pageHeight}%`;
style.width = `${(100 * width) / pageWidth}%`;
style.height = `${(100 * height) / pageHeight}%`;
} else {
this.setRotation(rotation, container);
}
@ -2897,6 +2947,7 @@ class FileAttachmentAnnotationElement extends AnnotationElement {
* @property {Object<string, Array<Object>> | null} [fieldObjects]
* @property {Map<string, HTMLCanvasElement>} [annotationCanvasMap]
* @property {TextAccessibilityManager} [accessibilityManager]
* @property {AnnotationEditorUIManager} [annotationEditorUIManager]
*/
/**
@ -2913,6 +2964,7 @@ class AnnotationLayer {
div,
accessibilityManager,
annotationCanvasMap,
annotationEditorUIManager,
page,
viewport,
}) {
@ -2922,6 +2974,7 @@ class AnnotationLayer {
this.page = page;
this.viewport = viewport;
this.zIndex = 0;
this._annotationEditorUIManager = annotationEditorUIManager;
if (typeof PDFJSDev !== "undefined" && PDFJSDev.test("TESTING")) {
// For testing purposes.
@ -3011,15 +3064,16 @@ class AnnotationLayer {
}
}
if (element.annotationEditorType > 0) {
this.#editableAnnotations.set(element.data.id, element);
}
const rendered = element.render();
if (data.hidden) {
rendered.style.visibility = "hidden";
}
this.#appendElement(rendered, data.id);
if (element.annotationEditorType > 0) {
this.#editableAnnotations.set(element.data.id, element);
this._annotationEditorUIManager?.renderAnnotationElement(element);
}
}
this.#setAnnotationCanvasMap();
@ -3051,13 +3105,16 @@ class AnnotationLayer {
continue;
}
canvas.className = "annotationContent";
const { firstChild } = element;
if (!firstChild) {
element.append(canvas);
} else if (firstChild.nodeName === "CANVAS") {
firstChild.replaceWith(canvas);
} else {
} else if (!firstChild.classList.contains("annotationContent")) {
firstChild.before(canvas);
} else {
firstChild.after(canvas);
}
}
this.#annotationCanvasMap.clear();