[Editor] Add editors with a comment in the sidebar
and add a button close to the editor. Clicking on the button will display a popup with the comment but it's for a next patch.
This commit is contained in:
parent
9855d85fb5
commit
2a459857ce
@ -643,6 +643,15 @@ class AnnotationEditorLayer {
|
|||||||
this.addCommands({ cmd, undo, mustExec: false });
|
this.addCommands({ cmd, undo, mustExec: false });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getEditorByUID(uid) {
|
||||||
|
for (const editor of this.#editors.values()) {
|
||||||
|
if (editor.uid === uid) {
|
||||||
|
return editor;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get an id for an editor.
|
* Get an id for an editor.
|
||||||
* @returns {string}
|
* @returns {string}
|
||||||
|
|||||||
@ -16,7 +16,9 @@
|
|||||||
import { noContextMenu } from "../display_utils.js";
|
import { noContextMenu } from "../display_utils.js";
|
||||||
|
|
||||||
class Comment {
|
class Comment {
|
||||||
#commentButton = null;
|
#commentStandaloneButton = null;
|
||||||
|
|
||||||
|
#commentToolbarButton = null;
|
||||||
|
|
||||||
#commentWasFromKeyBoard = false;
|
#commentWasFromKeyBoard = false;
|
||||||
|
|
||||||
@ -32,16 +34,40 @@ class Comment {
|
|||||||
|
|
||||||
constructor(editor) {
|
constructor(editor) {
|
||||||
this.#editor = editor;
|
this.#editor = editor;
|
||||||
this.toolbar = null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
renderForToolbar() {
|
||||||
|
const button = (this.#commentToolbarButton =
|
||||||
|
document.createElement("button"));
|
||||||
|
button.className = "comment";
|
||||||
|
return this.#render(button);
|
||||||
|
}
|
||||||
|
|
||||||
|
renderForStandalone() {
|
||||||
|
const button = (this.#commentStandaloneButton =
|
||||||
|
document.createElement("button"));
|
||||||
|
button.className = "annotationCommentButton";
|
||||||
|
|
||||||
|
const position = this.#editor.commentButtonPosition;
|
||||||
|
if (position) {
|
||||||
|
const { style } = button;
|
||||||
|
style.insetInlineEnd = `calc(${
|
||||||
|
100 *
|
||||||
|
(this.#editor._uiManager.direction === "ltr"
|
||||||
|
? 1 - position[0]
|
||||||
|
: position[0])
|
||||||
|
}% - var(--comment-button-dim))`;
|
||||||
|
style.top = `calc(${100 * position[1]}% - var(--comment-button-dim))`;
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.#render(button);
|
||||||
|
}
|
||||||
|
|
||||||
|
#render(comment) {
|
||||||
if (!this.#editor._uiManager.hasCommentManager()) {
|
if (!this.#editor._uiManager.hasCommentManager()) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const comment = (this.#commentButton = document.createElement("button"));
|
|
||||||
comment.className = "comment";
|
|
||||||
comment.tabIndex = "0";
|
comment.tabIndex = "0";
|
||||||
comment.setAttribute("data-l10n-id", "pdfjs-editor-edit-comment-button");
|
comment.setAttribute("data-l10n-id", "pdfjs-editor-edit-comment-button");
|
||||||
|
|
||||||
@ -57,7 +83,11 @@ class Comment {
|
|||||||
|
|
||||||
const onClick = event => {
|
const onClick = event => {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
this.edit();
|
if (comment === this.#commentToolbarButton) {
|
||||||
|
this.edit();
|
||||||
|
} else {
|
||||||
|
this.#editor._uiManager.toggleComment(this.#editor);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
comment.addEventListener("click", onClick, { capture: true, signal });
|
comment.addEventListener("click", onClick, { capture: true, signal });
|
||||||
comment.addEventListener(
|
comment.addEventListener(
|
||||||
@ -86,10 +116,12 @@ class Comment {
|
|||||||
}
|
}
|
||||||
|
|
||||||
finish() {
|
finish() {
|
||||||
if (!this.#commentButton) {
|
if (!this.#commentToolbarButton) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.#commentButton.focus({ focusVisible: this.#commentWasFromKeyBoard });
|
this.#commentToolbarButton.focus({
|
||||||
|
focusVisible: this.#commentWasFromKeyBoard,
|
||||||
|
});
|
||||||
this.#commentWasFromKeyBoard = false;
|
this.#commentWasFromKeyBoard = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -132,18 +164,13 @@ class Comment {
|
|||||||
this.data = text;
|
this.data = text;
|
||||||
}
|
}
|
||||||
|
|
||||||
toggle(enabled = false) {
|
|
||||||
if (!this.#commentButton) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.#commentButton.disabled = !enabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
shown() {}
|
shown() {}
|
||||||
|
|
||||||
destroy() {
|
destroy() {
|
||||||
this.#commentButton?.remove();
|
this.#commentToolbarButton?.remove();
|
||||||
this.#commentButton = null;
|
this.#commentToolbarButton = null;
|
||||||
|
this.#commentStandaloneButton?.remove();
|
||||||
|
this.#commentStandaloneButton = null;
|
||||||
this.#text = "";
|
this.#text = "";
|
||||||
this.#date = null;
|
this.#date = null;
|
||||||
this.#editor = null;
|
this.#editor = null;
|
||||||
|
|||||||
@ -480,6 +480,7 @@ class FreeDrawOutline extends Outline {
|
|||||||
this.#scaleFactor = scaleFactor;
|
this.#scaleFactor = scaleFactor;
|
||||||
this.#innerMargin = innerMargin;
|
this.#innerMargin = innerMargin;
|
||||||
this.#isLTR = isLTR;
|
this.#isLTR = isLTR;
|
||||||
|
this.firstPoint = [NaN, NaN];
|
||||||
this.lastPoint = [NaN, NaN];
|
this.lastPoint = [NaN, NaN];
|
||||||
this.#computeMinMax(isLTR);
|
this.#computeMinMax(isLTR);
|
||||||
|
|
||||||
@ -560,9 +561,12 @@ class FreeDrawOutline extends Outline {
|
|||||||
let lastX = outline[4];
|
let lastX = outline[4];
|
||||||
let lastY = outline[5];
|
let lastY = outline[5];
|
||||||
const minMax = [lastX, lastY, lastX, lastY];
|
const minMax = [lastX, lastY, lastX, lastY];
|
||||||
|
let firstPointX = lastX;
|
||||||
|
let firstPointY = lastY;
|
||||||
let lastPointX = lastX;
|
let lastPointX = lastX;
|
||||||
let lastPointY = lastY;
|
let lastPointY = lastY;
|
||||||
const ltrCallback = isLTR ? Math.max : Math.min;
|
const ltrCallback = isLTR ? Math.max : Math.min;
|
||||||
|
const bezierBbox = new Float32Array(4);
|
||||||
|
|
||||||
for (let i = 6, ii = outline.length; i < ii; i += 6) {
|
for (let i = 6, ii = outline.length; i < ii; i += 6) {
|
||||||
const x = outline[i + 4],
|
const x = outline[i + 4],
|
||||||
@ -571,6 +575,12 @@ class FreeDrawOutline extends Outline {
|
|||||||
if (isNaN(outline[i])) {
|
if (isNaN(outline[i])) {
|
||||||
Util.pointBoundingBox(x, y, minMax);
|
Util.pointBoundingBox(x, y, minMax);
|
||||||
|
|
||||||
|
if (firstPointY > y) {
|
||||||
|
firstPointX = x;
|
||||||
|
firstPointY = y;
|
||||||
|
} else if (firstPointY === y) {
|
||||||
|
firstPointX = ltrCallback(firstPointX, x);
|
||||||
|
}
|
||||||
if (lastPointY < y) {
|
if (lastPointY < y) {
|
||||||
lastPointX = x;
|
lastPointX = x;
|
||||||
lastPointY = y;
|
lastPointY = y;
|
||||||
@ -578,16 +588,34 @@ class FreeDrawOutline extends Outline {
|
|||||||
lastPointX = ltrCallback(lastPointX, x);
|
lastPointX = ltrCallback(lastPointX, x);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const bbox = [Infinity, Infinity, -Infinity, -Infinity];
|
bezierBbox[0] = bezierBbox[1] = Infinity;
|
||||||
Util.bezierBoundingBox(lastX, lastY, ...outline.slice(i, i + 6), bbox);
|
bezierBbox[2] = bezierBbox[3] = -Infinity;
|
||||||
|
Util.bezierBoundingBox(
|
||||||
|
lastX,
|
||||||
|
lastY,
|
||||||
|
...outline.slice(i, i + 6),
|
||||||
|
bezierBbox
|
||||||
|
);
|
||||||
|
|
||||||
Util.rectBoundingBox(...bbox, minMax);
|
Util.rectBoundingBox(
|
||||||
|
bezierBbox[0],
|
||||||
|
bezierBbox[1],
|
||||||
|
bezierBbox[2],
|
||||||
|
bezierBbox[3],
|
||||||
|
minMax
|
||||||
|
);
|
||||||
|
|
||||||
if (lastPointY < bbox[3]) {
|
if (firstPointY > bezierBbox[1]) {
|
||||||
lastPointX = bbox[2];
|
firstPointX = bezierBbox[0];
|
||||||
lastPointY = bbox[3];
|
firstPointY = bezierBbox[1];
|
||||||
} else if (lastPointY === bbox[3]) {
|
} else if (firstPointY === bezierBbox[1]) {
|
||||||
lastPointX = ltrCallback(lastPointX, bbox[2]);
|
firstPointX = ltrCallback(firstPointX, bezierBbox[0]);
|
||||||
|
}
|
||||||
|
if (lastPointY < bezierBbox[3]) {
|
||||||
|
lastPointX = bezierBbox[2];
|
||||||
|
lastPointY = bezierBbox[3];
|
||||||
|
} else if (lastPointY === bezierBbox[3]) {
|
||||||
|
lastPointX = ltrCallback(lastPointX, bezierBbox[2]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
lastX = x;
|
lastX = x;
|
||||||
@ -599,6 +627,7 @@ class FreeDrawOutline extends Outline {
|
|||||||
bbox[1] = minMax[1] - this.#innerMargin;
|
bbox[1] = minMax[1] - this.#innerMargin;
|
||||||
bbox[2] = minMax[2] - minMax[0] + 2 * this.#innerMargin;
|
bbox[2] = minMax[2] - minMax[0] + 2 * this.#innerMargin;
|
||||||
bbox[3] = minMax[3] - minMax[1] + 2 * this.#innerMargin;
|
bbox[3] = minMax[3] - minMax[1] + 2 * this.#innerMargin;
|
||||||
|
this.firstPoint = [firstPointX, firstPointY];
|
||||||
this.lastPoint = [lastPointX, lastPointY];
|
this.lastPoint = [lastPointX, lastPointY];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -20,6 +20,8 @@ import { Util } from "../../../shared/util.js";
|
|||||||
class HighlightOutliner {
|
class HighlightOutliner {
|
||||||
#box;
|
#box;
|
||||||
|
|
||||||
|
#firstPoint;
|
||||||
|
|
||||||
#lastPoint;
|
#lastPoint;
|
||||||
|
|
||||||
#verticalEdges = [];
|
#verticalEdges = [];
|
||||||
@ -63,12 +65,30 @@ class HighlightOutliner {
|
|||||||
const bboxHeight = minMax[3] - minMax[1] + 2 * innerMargin;
|
const bboxHeight = minMax[3] - minMax[1] + 2 * innerMargin;
|
||||||
const shiftedMinX = minMax[0] - innerMargin;
|
const shiftedMinX = minMax[0] - innerMargin;
|
||||||
const shiftedMinY = minMax[1] - innerMargin;
|
const shiftedMinY = minMax[1] - innerMargin;
|
||||||
|
let firstPointX = isLTR ? -Infinity : Infinity;
|
||||||
|
let firstPointY = Infinity;
|
||||||
const lastEdge = this.#verticalEdges.at(isLTR ? -1 : -2);
|
const lastEdge = this.#verticalEdges.at(isLTR ? -1 : -2);
|
||||||
const lastPoint = [lastEdge[0], lastEdge[2]];
|
const lastPoint = [lastEdge[0], lastEdge[2]];
|
||||||
|
|
||||||
// Convert the coordinates of the edges into box coordinates.
|
// Convert the coordinates of the edges into box coordinates.
|
||||||
for (const edge of this.#verticalEdges) {
|
for (const edge of this.#verticalEdges) {
|
||||||
const [x, y1, y2] = edge;
|
const [x, y1, y2, left] = edge;
|
||||||
|
if (!left && isLTR) {
|
||||||
|
if (y1 < firstPointY) {
|
||||||
|
firstPointY = y1;
|
||||||
|
firstPointX = x;
|
||||||
|
} else if (y1 === firstPointY) {
|
||||||
|
firstPointX = Math.max(firstPointX, x);
|
||||||
|
}
|
||||||
|
} else if (left && !isLTR) {
|
||||||
|
if (y1 < firstPointY) {
|
||||||
|
firstPointY = y1;
|
||||||
|
firstPointX = x;
|
||||||
|
} else if (y1 === firstPointY) {
|
||||||
|
firstPointX = Math.min(firstPointX, x);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
edge[0] = (x - shiftedMinX) / bboxWidth;
|
edge[0] = (x - shiftedMinX) / bboxWidth;
|
||||||
edge[1] = (y1 - shiftedMinY) / bboxHeight;
|
edge[1] = (y1 - shiftedMinY) / bboxHeight;
|
||||||
edge[2] = (y2 - shiftedMinY) / bboxHeight;
|
edge[2] = (y2 - shiftedMinY) / bboxHeight;
|
||||||
@ -80,6 +100,7 @@ class HighlightOutliner {
|
|||||||
bboxWidth,
|
bboxWidth,
|
||||||
bboxHeight,
|
bboxHeight,
|
||||||
]);
|
]);
|
||||||
|
this.#firstPoint = [firstPointX, firstPointY];
|
||||||
this.#lastPoint = lastPoint;
|
this.#lastPoint = lastPoint;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -170,7 +191,12 @@ class HighlightOutliner {
|
|||||||
}
|
}
|
||||||
outline.push(lastPointX, lastPointY);
|
outline.push(lastPointX, lastPointY);
|
||||||
}
|
}
|
||||||
return new HighlightOutline(outlines, this.#box, this.#lastPoint);
|
return new HighlightOutline(
|
||||||
|
outlines,
|
||||||
|
this.#box,
|
||||||
|
this.#firstPoint,
|
||||||
|
this.#lastPoint
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#binarySearch(y) {
|
#binarySearch(y) {
|
||||||
@ -264,10 +290,11 @@ class HighlightOutline extends Outline {
|
|||||||
|
|
||||||
#outlines;
|
#outlines;
|
||||||
|
|
||||||
constructor(outlines, box, lastPoint) {
|
constructor(outlines, box, firstPoint, lastPoint) {
|
||||||
super();
|
super();
|
||||||
this.#outlines = outlines;
|
this.#outlines = outlines;
|
||||||
this.#box = box;
|
this.#box = box;
|
||||||
|
this.firstPoint = firstPoint;
|
||||||
this.lastPoint = lastPoint;
|
this.lastPoint = lastPoint;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -55,6 +55,8 @@ class AnnotationEditor {
|
|||||||
|
|
||||||
#comment = null;
|
#comment = null;
|
||||||
|
|
||||||
|
#commentStandaloneButton = null;
|
||||||
|
|
||||||
#disabled = false;
|
#disabled = false;
|
||||||
|
|
||||||
#dragPointerId = null;
|
#dragPointerId = null;
|
||||||
@ -184,6 +186,7 @@ class AnnotationEditor {
|
|||||||
this._initialOptions.isCentered = parameters.isCentered;
|
this._initialOptions.isCentered = parameters.isCentered;
|
||||||
this._structTreeParentId = null;
|
this._structTreeParentId = null;
|
||||||
this.annotationElementId = parameters.annotationElementId || null;
|
this.annotationElementId = parameters.annotationElementId || null;
|
||||||
|
this.creationDate = new Date();
|
||||||
|
|
||||||
const {
|
const {
|
||||||
rotation,
|
rotation,
|
||||||
@ -313,6 +316,10 @@ class AnnotationEditor {
|
|||||||
this.div?.classList.toggle("draggable", value);
|
this.div?.classList.toggle("draggable", value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get uid() {
|
||||||
|
return this.annotationElementId || this.id;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @returns {boolean} true if the editor handles the Enter key itself.
|
* @returns {boolean} true if the editor handles the Enter key itself.
|
||||||
*/
|
*/
|
||||||
@ -1166,10 +1173,21 @@ class AnnotationEditor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
addCommentButton() {
|
addCommentButton() {
|
||||||
if (this.#comment) {
|
return (this.#comment ||= new Comment(this));
|
||||||
return this.#comment;
|
}
|
||||||
|
|
||||||
|
addStandaloneCommentButton() {
|
||||||
|
this.#comment ||= new Comment(this);
|
||||||
|
if (this.#commentStandaloneButton) {
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
return (this.#comment = new Comment(this));
|
this.#commentStandaloneButton = this.#comment.renderForStandalone();
|
||||||
|
this.div.append(this.#commentStandaloneButton);
|
||||||
|
}
|
||||||
|
|
||||||
|
removeStandaloneCommentButton() {
|
||||||
|
this.#commentStandaloneButton?.remove();
|
||||||
|
this.#commentStandaloneButton = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
get commentColor() {
|
get commentColor() {
|
||||||
@ -1204,6 +1222,10 @@ class AnnotationEditor {
|
|||||||
return this.#comment?.hasBeenEdited();
|
return this.#comment?.hasBeenEdited();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get hasComment() {
|
||||||
|
return !!this.#comment && !this.#comment.isDeleted();
|
||||||
|
}
|
||||||
|
|
||||||
async editComment() {
|
async editComment() {
|
||||||
if (!this.#comment) {
|
if (!this.#comment) {
|
||||||
this.#comment = new Comment(this);
|
this.#comment = new Comment(this);
|
||||||
@ -1211,6 +1233,8 @@ class AnnotationEditor {
|
|||||||
this.#comment.edit();
|
this.#comment.edit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
showComment() {}
|
||||||
|
|
||||||
addComment(serialized) {
|
addComment(serialized) {
|
||||||
if (this.hasEditedComment) {
|
if (this.hasEditedComment) {
|
||||||
const DEFAULT_POPUP_WIDTH = 180;
|
const DEFAULT_POPUP_WIDTH = 180;
|
||||||
@ -1581,6 +1605,17 @@ class AnnotationEditor {
|
|||||||
return this.getRect(0, 0);
|
return this.getRect(0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getData() {
|
||||||
|
return {
|
||||||
|
id: this.uid,
|
||||||
|
pageIndex: this.pageIndex,
|
||||||
|
rect: this.getPDFRect(),
|
||||||
|
contentsObj: { str: this.comment.text },
|
||||||
|
creationDate: this.creationDate,
|
||||||
|
popupRef: !this.#comment.isDeleted(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Executed once this editor has been rendered.
|
* Executed once this editor has been rendered.
|
||||||
* @param {boolean} focus - true if the editor should be focused.
|
* @param {boolean} focus - true if the editor should be focused.
|
||||||
@ -1814,6 +1849,14 @@ class AnnotationEditor {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the position of the comment button.
|
||||||
|
* @returns {Array<number>|null}
|
||||||
|
*/
|
||||||
|
get commentButtonPosition() {
|
||||||
|
return this._uiManager.direction === "ltr" ? [1, 0] : [0, 0];
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* onkeydown callback.
|
* onkeydown callback.
|
||||||
* @param {KeyboardEvent} event
|
* @param {KeyboardEvent} event
|
||||||
|
|||||||
@ -60,6 +60,8 @@ class HighlightEditor extends AnnotationEditor {
|
|||||||
|
|
||||||
#isFreeHighlight = false;
|
#isFreeHighlight = false;
|
||||||
|
|
||||||
|
#firstPoint = null;
|
||||||
|
|
||||||
#lastPoint = null;
|
#lastPoint = null;
|
||||||
|
|
||||||
#opacity;
|
#opacity;
|
||||||
@ -177,7 +179,11 @@ class HighlightEditor extends AnnotationEditor {
|
|||||||
this.#focusOutlines = outlinerForOutline.getOutlines();
|
this.#focusOutlines = outlinerForOutline.getOutlines();
|
||||||
|
|
||||||
// The last point is in the pages coordinate system.
|
// The last point is in the pages coordinate system.
|
||||||
const { lastPoint } = this.#focusOutlines;
|
const { firstPoint, lastPoint } = this.#focusOutlines;
|
||||||
|
this.#firstPoint = [
|
||||||
|
(firstPoint[0] - this.x) / this.width,
|
||||||
|
(firstPoint[1] - this.y) / this.height,
|
||||||
|
];
|
||||||
this.#lastPoint = [
|
this.#lastPoint = [
|
||||||
(lastPoint[0] - this.x) / this.width,
|
(lastPoint[0] - this.x) / this.width,
|
||||||
(lastPoint[1] - this.y) / this.height,
|
(lastPoint[1] - this.y) / this.height,
|
||||||
@ -268,7 +274,11 @@ class HighlightEditor extends AnnotationEditor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const { lastPoint } = this.#focusOutlines;
|
const { firstPoint, lastPoint } = this.#focusOutlines;
|
||||||
|
this.#firstPoint = [
|
||||||
|
(firstPoint[0] - x) / width,
|
||||||
|
(firstPoint[1] - y) / height,
|
||||||
|
];
|
||||||
this.#lastPoint = [(lastPoint[0] - x) / width, (lastPoint[1] - y) / height];
|
this.#lastPoint = [(lastPoint[0] - x) / width, (lastPoint[1] - y) / height];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -299,6 +309,11 @@ class HighlightEditor extends AnnotationEditor {
|
|||||||
return this.#lastPoint;
|
return this.#lastPoint;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @inheritdoc */
|
||||||
|
get commentButtonPosition() {
|
||||||
|
return this.#firstPoint;
|
||||||
|
}
|
||||||
|
|
||||||
/** @inheritdoc */
|
/** @inheritdoc */
|
||||||
updateParams(type, value) {
|
updateParams(type, value) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
|
|||||||
@ -162,7 +162,7 @@ class EditorToolbar {
|
|||||||
if (this.#comment) {
|
if (this.#comment) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const button = comment.render();
|
const button = comment.renderForToolbar();
|
||||||
if (!button) {
|
if (!button) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -896,6 +896,7 @@ class AnnotationEditorUIManager {
|
|||||||
this.isShiftKeyDown = false;
|
this.isShiftKeyDown = false;
|
||||||
this._editorUndoBar = editorUndoBar || null;
|
this._editorUndoBar = editorUndoBar || null;
|
||||||
this._supportsPinchToZoom = supportsPinchToZoom !== false;
|
this._supportsPinchToZoom = supportsPinchToZoom !== false;
|
||||||
|
commentManager?.setSidebarUiManager(this);
|
||||||
|
|
||||||
if (typeof PDFJSDev !== "undefined" && PDFJSDev.test("TESTING")) {
|
if (typeof PDFJSDev !== "undefined" && PDFJSDev.test("TESTING")) {
|
||||||
Object.defineProperty(this, "reset", {
|
Object.defineProperty(this, "reset", {
|
||||||
@ -1071,6 +1072,27 @@ class AnnotationEditorUIManager {
|
|||||||
this.#commentManager?.open(this, editor, position);
|
this.#commentManager?.open(this, editor, position);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
showComment(pageIndex, uid) {
|
||||||
|
const layer = this.#allLayers.get(pageIndex);
|
||||||
|
const editor = layer?.getEditorByUID(uid);
|
||||||
|
editor?.showComment();
|
||||||
|
}
|
||||||
|
|
||||||
|
async waitForPageRendered(pageNumber) {
|
||||||
|
if (this.#allLayers.has(pageNumber - 1)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const { resolve, promise } = Promise.withResolvers();
|
||||||
|
const onPageRendered = evt => {
|
||||||
|
if (evt.pageNumber === pageNumber) {
|
||||||
|
this._eventBus._off("annotationeditorlayerrendered", onPageRendered);
|
||||||
|
resolve();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
this._eventBus.on("annotationeditorlayerrendered", onPageRendered);
|
||||||
|
await promise;
|
||||||
|
}
|
||||||
|
|
||||||
getSignature(editor) {
|
getSignature(editor) {
|
||||||
this.#signatureManager?.getSignature({ uiManager: this, editor });
|
this.#signatureManager?.getSignature({ uiManager: this, editor });
|
||||||
}
|
}
|
||||||
@ -1799,6 +1821,9 @@ class AnnotationEditorUIManager {
|
|||||||
|
|
||||||
if (this.#mode === AnnotationEditorType.POPUP) {
|
if (this.#mode === AnnotationEditorType.POPUP) {
|
||||||
this.#commentManager?.hideSidebar();
|
this.#commentManager?.hideSidebar();
|
||||||
|
for (const editor of this.#allEditors.values()) {
|
||||||
|
editor.removeStandaloneCommentButton();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.#mode = mode;
|
this.#mode = mode;
|
||||||
@ -1815,13 +1840,6 @@ class AnnotationEditorUIManager {
|
|||||||
if (mode === AnnotationEditorType.SIGNATURE) {
|
if (mode === AnnotationEditorType.SIGNATURE) {
|
||||||
await this.#signatureManager?.loadSignatures();
|
await this.#signatureManager?.loadSignatures();
|
||||||
}
|
}
|
||||||
if (mode === AnnotationEditorType.POPUP) {
|
|
||||||
this.#allEditableAnnotations ||=
|
|
||||||
await this.#pdfDocument.getAnnotationsByType(
|
|
||||||
new Set(this.#editorTypes.map(editorClass => editorClass._editorType))
|
|
||||||
);
|
|
||||||
this.#commentManager?.showSidebar(this.#allEditableAnnotations);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.setEditingState(true);
|
this.setEditingState(true);
|
||||||
await this.#enableAll();
|
await this.#enableAll();
|
||||||
@ -1829,6 +1847,40 @@ class AnnotationEditorUIManager {
|
|||||||
for (const layer of this.#allLayers.values()) {
|
for (const layer of this.#allLayers.values()) {
|
||||||
layer.updateMode(mode);
|
layer.updateMode(mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (mode === AnnotationEditorType.POPUP) {
|
||||||
|
this.#allEditableAnnotations ||=
|
||||||
|
await this.#pdfDocument.getAnnotationsByType(
|
||||||
|
new Set(this.#editorTypes.map(editorClass => editorClass._editorType))
|
||||||
|
);
|
||||||
|
const elementIds = new Set();
|
||||||
|
const allComments = [];
|
||||||
|
for (const editor of this.#allEditors.values()) {
|
||||||
|
const { annotationElementId, hasComment, deleted } = editor;
|
||||||
|
if (annotationElementId) {
|
||||||
|
elementIds.add(annotationElementId);
|
||||||
|
}
|
||||||
|
if (hasComment && !deleted) {
|
||||||
|
allComments.push(editor.getData());
|
||||||
|
editor.addStandaloneCommentButton();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (const annotation of this.#allEditableAnnotations) {
|
||||||
|
const { id, popupRef, contentsObj } = annotation;
|
||||||
|
if (
|
||||||
|
popupRef &&
|
||||||
|
contentsObj?.str &&
|
||||||
|
!elementIds.has(id) &&
|
||||||
|
!this.#deletedAnnotationsElementIds.has(id)
|
||||||
|
) {
|
||||||
|
// The annotation exists in the PDF and has a comment but there
|
||||||
|
// is no editor for it (anymore).
|
||||||
|
allComments.push(annotation);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.#commentManager?.showSidebar(allComments);
|
||||||
|
}
|
||||||
|
|
||||||
if (!editId) {
|
if (!editId) {
|
||||||
if (isFromKeyboard) {
|
if (isFromKeyboard) {
|
||||||
this.addNewEditorFromKeyboard();
|
this.addNewEditorFromKeyboard();
|
||||||
|
|||||||
@ -251,7 +251,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.annotationLayer.disabled .annotationCommentButton {
|
.annotationLayer.disabled :is(.annotationCommentButton) {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -173,6 +173,10 @@ class CommentManager {
|
|||||||
overlayManager.register(dialog);
|
overlayManager.register(dialog);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setSidebarUiManager(uiManager) {
|
||||||
|
this.#sidebar.setUIManager(uiManager);
|
||||||
|
}
|
||||||
|
|
||||||
showSidebar(annotations) {
|
showSidebar(annotations) {
|
||||||
this.#sidebar.show(annotations);
|
this.#sidebar.show(annotations);
|
||||||
}
|
}
|
||||||
@ -435,6 +439,8 @@ class CommentSidebar {
|
|||||||
|
|
||||||
#idsToElements = null;
|
#idsToElements = null;
|
||||||
|
|
||||||
|
#uiManager = null;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
{
|
{
|
||||||
sidebar,
|
sidebar,
|
||||||
@ -472,12 +478,14 @@ class CommentSidebar {
|
|||||||
this.#sidebar.hidden = true;
|
this.#sidebar.hidden = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setUIManager(uiManager) {
|
||||||
|
this.#uiManager = uiManager;
|
||||||
|
}
|
||||||
|
|
||||||
show(annotations) {
|
show(annotations) {
|
||||||
this.#elementsToAnnotations = new WeakMap();
|
this.#elementsToAnnotations = new WeakMap();
|
||||||
this.#idsToElements = new Map();
|
this.#idsToElements = new Map();
|
||||||
this.#annotations = annotations = annotations.filter(
|
this.#annotations = annotations;
|
||||||
a => a.popupRef && a.contentsObj?.str
|
|
||||||
);
|
|
||||||
annotations.sort(this.#sortComments.bind(this));
|
annotations.sort(this.#sortComments.bind(this));
|
||||||
if (annotations.length !== 0) {
|
if (annotations.length !== 0) {
|
||||||
const fragment = document.createDocumentFragment();
|
const fragment = document.createDocumentFragment();
|
||||||
@ -621,6 +629,7 @@ class CommentSidebar {
|
|||||||
|
|
||||||
#createCommentElement(annotation) {
|
#createCommentElement(annotation) {
|
||||||
const {
|
const {
|
||||||
|
id,
|
||||||
creationDate,
|
creationDate,
|
||||||
modificationDate,
|
modificationDate,
|
||||||
contentsObj: { str: text },
|
contentsObj: { str: text },
|
||||||
@ -646,11 +655,11 @@ class CommentSidebar {
|
|||||||
commentItem.addEventListener("keydown", this.#boundCommentKeydown);
|
commentItem.addEventListener("keydown", this.#boundCommentKeydown);
|
||||||
|
|
||||||
this.#elementsToAnnotations.set(commentItem, annotation);
|
this.#elementsToAnnotations.set(commentItem, annotation);
|
||||||
this.#idsToElements.set(annotation.id, commentItem);
|
this.#idsToElements.set(id, commentItem);
|
||||||
return commentItem;
|
return commentItem;
|
||||||
}
|
}
|
||||||
|
|
||||||
#commentClick({ currentTarget }) {
|
async #commentClick({ currentTarget }) {
|
||||||
if (currentTarget.classList.contains("selected")) {
|
if (currentTarget.classList.contains("selected")) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -658,14 +667,18 @@ class CommentSidebar {
|
|||||||
if (!annotation) {
|
if (!annotation) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const { pageIndex, rect } = annotation;
|
const { id, pageIndex, rect } = annotation;
|
||||||
const SPACE_ABOVE_ANNOTATION = 10;
|
const SPACE_ABOVE_ANNOTATION = 10;
|
||||||
|
const pageNumber = pageIndex + 1;
|
||||||
|
const pageVisiblePromise = this.#uiManager?.waitForPageRendered(pageNumber);
|
||||||
this.#linkService?.goToXY(
|
this.#linkService?.goToXY(
|
||||||
pageIndex + 1,
|
pageNumber,
|
||||||
rect[0],
|
rect[0],
|
||||||
rect[3] + SPACE_ABOVE_ANNOTATION
|
rect[3] + SPACE_ABOVE_ANNOTATION
|
||||||
);
|
);
|
||||||
this.selectComment(currentTarget);
|
this.selectComment(currentTarget);
|
||||||
|
await pageVisiblePromise;
|
||||||
|
this.#uiManager?.showComment(pageIndex, id);
|
||||||
}
|
}
|
||||||
|
|
||||||
#commentKeydown(e) {
|
#commentKeydown(e) {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user