Skip to content

Commit f64ece2

Browse files
authored
Merge pull request #20312 from calixteman/bug1991029
[Annotation] In reading mode with new commment stuff enabled, use the comment popup for annotations without a popup but with some contents (bug 1991029)
2 parents 9138473 + 7fc7b79 commit f64ece2

3 files changed

Lines changed: 151 additions & 57 deletions

File tree

src/display/annotation_layer.js

Lines changed: 76 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -718,9 +718,6 @@ class AnnotationElement {
718718
* @memberof AnnotationElement
719719
*/
720720
_createPopup(popupData = null) {
721-
if (this.parent._commentManager) {
722-
return;
723-
}
724721
const { data } = this;
725722

726723
let contentsObj, modificationDate;
@@ -750,13 +747,19 @@ class AnnotationElement {
750747
parent: this.parent,
751748
elements: [this],
752749
}));
753-
this.parent.div.append(popup.render());
750+
if (!this.parent._commentManager) {
751+
this.parent.div.append(popup.render());
752+
}
754753
}
755754

756755
get hasPopupElement() {
757756
return !!(this.#popupElement || this.popup || this.data.popupRef);
758757
}
759758

759+
get extraPopupElement() {
760+
return this.#popupElement;
761+
}
762+
760763
/**
761764
* Render the annotation's HTML element(s).
762765
*
@@ -2410,10 +2413,12 @@ class PopupElement {
24102413
// consistent with other viewers such as Adobe Acrobat.
24112414
this.#dateObj = PDFDateString.toDateObject(modificationDate);
24122415

2416+
// The elements that will trigger the popup.
2417+
this.trigger = elements.flatMap(e => e.getElementsToTriggerPopup());
2418+
24132419
if (commentManager) {
2414-
this.#renderCommentButton();
2420+
this.renderCommentButton();
24152421
} else {
2416-
this.trigger = elements.flatMap(e => e.getElementsToTriggerPopup());
24172422
this.#addEventListeners();
24182423

24192424
this.#container.hidden = true;
@@ -2443,8 +2448,8 @@ class PopupElement {
24432448
// Attach the event listeners to the trigger element.
24442449
for (const element of this.trigger) {
24452450
element.addEventListener("click", this.#boundToggle, { signal });
2446-
element.addEventListener("mouseenter", this.#boundShow, { signal });
2447-
element.addEventListener("mouseleave", this.#boundHide, { signal });
2451+
element.addEventListener("pointerenter", this.#boundShow, { signal });
2452+
element.addEventListener("pointerleave", this.#boundHide, { signal });
24482453
element.classList.add("popupTriggerArea");
24492454
}
24502455

@@ -2466,7 +2471,7 @@ class PopupElement {
24662471
);
24672472
}
24682473

2469-
#renderCommentButton() {
2474+
renderCommentButton() {
24702475
if (this.#commentButton) {
24712476
return;
24722477
}
@@ -2479,61 +2484,78 @@ class PopupElement {
24792484
return;
24802485
}
24812486

2482-
const button = (this.#commentButton = document.createElement("button"));
2483-
button.className = "annotationCommentButton";
2484-
const parentContainer = this.#firstElement.container;
2485-
button.style.zIndex = parentContainer.style.zIndex + 1;
2486-
button.tabIndex = 0;
2487-
button.ariaHasPopup = "dialog";
2488-
button.ariaControls = "commentPopup";
2489-
button.setAttribute("data-l10n-id", "pdfjs-show-comment-button");
2490-
24912487
const { signal } = (this.#popupAbortController = new AbortController());
2492-
button.addEventListener("keydown", this.#boundKeyDown, { signal });
2493-
button.addEventListener(
2494-
"click",
2495-
() => {
2496-
this.#commentManager.toggleCommentPopup(this, /* isSelected = */ true);
2497-
},
2498-
{ signal }
2499-
);
2500-
button.addEventListener(
2501-
"pointerenter",
2502-
() => {
2503-
this.#commentManager.toggleCommentPopup(
2504-
this,
2505-
/* isSelected = */ false,
2506-
/* visibility = */ true
2507-
);
2508-
},
2509-
{ signal }
2510-
);
2511-
button.addEventListener(
2512-
"pointerleave",
2513-
() => {
2514-
this.#commentManager.toggleCommentPopup(
2515-
this,
2516-
/* isSelected = */ false,
2517-
/* visibility = */ false
2518-
);
2519-
},
2520-
{ signal }
2521-
);
2522-
this.#updateColor();
2523-
this.#updateCommentButtonPosition();
2524-
parentContainer.after(button);
2488+
const hasOwnButton = !!this.#firstElement.extraPopupElement;
2489+
const togglePopup = () => {
2490+
this.#commentManager.toggleCommentPopup(
2491+
this,
2492+
/* isSelected = */ true,
2493+
/* visibility = */ undefined,
2494+
/* isEditable = */ !hasOwnButton
2495+
);
2496+
};
2497+
const showPopup = () => {
2498+
this.#commentManager.toggleCommentPopup(
2499+
this,
2500+
/* isSelected = */ false,
2501+
/* visibility = */ true,
2502+
/* isEditable = */ !hasOwnButton
2503+
);
2504+
};
2505+
const hidePopup = () => {
2506+
this.#commentManager.toggleCommentPopup(
2507+
this,
2508+
/* isSelected = */ false,
2509+
/* visibility = */ false
2510+
);
2511+
};
2512+
2513+
if (!hasOwnButton) {
2514+
const button = (this.#commentButton = document.createElement("button"));
2515+
button.className = "annotationCommentButton";
2516+
const parentContainer = this.#firstElement.container;
2517+
button.style.zIndex = parentContainer.style.zIndex + 1;
2518+
button.tabIndex = 0;
2519+
button.ariaHasPopup = "dialog";
2520+
button.ariaControls = "commentPopup";
2521+
button.setAttribute("data-l10n-id", "pdfjs-show-comment-button");
2522+
this.#updateColor();
2523+
this.#updateCommentButtonPosition();
2524+
button.addEventListener("keydown", this.#boundKeyDown, { signal });
2525+
button.addEventListener("click", togglePopup, { signal });
2526+
button.addEventListener("pointerenter", showPopup, { signal });
2527+
button.addEventListener("pointerleave", hidePopup, { signal });
2528+
parentContainer.after(button);
2529+
} else {
2530+
this.#commentButton = this.#firstElement.container;
2531+
for (const element of this.trigger) {
2532+
element.ariaHasPopup = "dialog";
2533+
element.ariaControls = "commentPopup";
2534+
element.addEventListener("keydown", this.#boundKeyDown, { signal });
2535+
element.addEventListener("click", togglePopup, { signal });
2536+
element.addEventListener("pointerenter", showPopup, { signal });
2537+
element.addEventListener("pointerleave", hidePopup, { signal });
2538+
element.classList.add("popupTriggerArea");
2539+
}
2540+
}
25252541
}
25262542

25272543
#updateCommentButtonPosition() {
2528-
this.#renderCommentButton();
2544+
if (this.#firstElement.extraPopupElement) {
2545+
return;
2546+
}
2547+
this.renderCommentButton();
25292548
const [x, y] = this.#commentButtonPosition;
25302549
const { style } = this.#commentButton;
25312550
style.left = `calc(${x}%)`;
25322551
style.top = `calc(${y}% - var(--comment-button-dim))`;
25332552
}
25342553

25352554
#updateColor() {
2536-
this.#renderCommentButton();
2555+
if (this.#firstElement.extraPopupElement) {
2556+
return;
2557+
}
2558+
this.renderCommentButton();
25372559
this.#commentButton.style.backgroundColor = this.commentButtonColor || "";
25382560
}
25392561

@@ -3792,6 +3814,7 @@ class AnnotationLayer {
37923814
rendered.style.visibility = "hidden";
37933815
}
37943816
await this.#appendElement(rendered, data.id, elementParams.elements);
3817+
element.extraPopupElement?.popup?.renderCommentButton();
37953818

37963819
if (element._isEditable) {
37973820
this.#editableAnnotations.set(element.data.id, element);

test/integration/annotation_spec.mjs

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -810,4 +810,72 @@ a dynamic compiler for JavaScript based on our`);
810810
});
811811
});
812812
});
813+
814+
describe("Annotation without popup and enableComment set to true", () => {
815+
describe("annotation-text-without-popup.pdf", () => {
816+
let pages;
817+
818+
beforeEach(async () => {
819+
pages = await loadAndWait(
820+
"annotation-text-without-popup.pdf",
821+
getAnnotationSelector("4R"),
822+
"page-fit",
823+
null,
824+
{ enableComment: true }
825+
);
826+
});
827+
828+
afterEach(async () => {
829+
await closePages(pages);
830+
});
831+
832+
it("must check that the popup is shown", async () => {
833+
await Promise.all(
834+
pages.map(async ([browserName, page]) => {
835+
const rect = await getRect(page, getAnnotationSelector("4R"));
836+
837+
// Hover the annotation, the popup should be visible.
838+
let promisePopup = page.waitForSelector("#commentPopup", {
839+
visible: true,
840+
});
841+
await page.mouse.move(
842+
rect.x + rect.width / 2,
843+
rect.y + rect.height / 2
844+
);
845+
await promisePopup;
846+
847+
// Move the mouse away, the popup should be hidden.
848+
promisePopup = page.waitForSelector("#commentPopup", {
849+
visible: false,
850+
});
851+
await page.mouse.move(
852+
rect.x - rect.width / 2,
853+
rect.y - rect.height / 2
854+
);
855+
await promisePopup;
856+
857+
// Click the annotation, the popup should be visible.
858+
promisePopup = page.waitForSelector("#commentPopup", {
859+
visible: true,
860+
});
861+
await page.mouse.click(
862+
rect.x + rect.width / 2,
863+
rect.y + rect.height / 2
864+
);
865+
await promisePopup;
866+
867+
// Click again, the popup should be hidden.
868+
promisePopup = page.waitForSelector("#commentPopup", {
869+
visible: false,
870+
});
871+
await page.mouse.click(
872+
rect.x + rect.width / 2,
873+
rect.y + rect.height / 2
874+
);
875+
await promisePopup;
876+
})
877+
);
878+
});
879+
});
880+
});
813881
});

web/comment_manager.js

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -92,11 +92,11 @@ class CommentManager {
9292
this.#sidebar.updateComment(annotation);
9393
}
9494

95-
toggleCommentPopup(editor, isSelected, visibility) {
95+
toggleCommentPopup(editor, isSelected, visibility, isEditable) {
9696
if (isSelected) {
9797
this.selectComment(editor.uid);
9898
}
99-
this.#popup.toggle(editor, isSelected, visibility);
99+
this.#popup.toggle(editor, isSelected, visibility, isEditable);
100100
}
101101

102102
destroyPopup() {
@@ -880,6 +880,8 @@ class CommentDialog {
880880
}
881881

882882
class CommentPopup {
883+
#buttonsContainer = null;
884+
883885
#commentDialog;
884886

885887
#dateFormat;
@@ -954,7 +956,7 @@ class CommentPopup {
954956
const time = (this.#time = document.createElement("time"));
955957
time.className = "commentPopupTime";
956958

957-
const buttons = document.createElement("div");
959+
const buttons = (this.#buttonsContainer = document.createElement("div"));
958960
buttons.className = "commentPopupButtons";
959961
const edit = document.createElement("button");
960962
edit.classList.add("commentPopupEdit", "toolbarButton");
@@ -1089,7 +1091,7 @@ class CommentPopup {
10891091
this.sidebar.selectComment(null);
10901092
}
10911093

1092-
toggle(editor, isSelected, visibility = undefined) {
1094+
toggle(editor, isSelected, visibility = undefined, isEditable = true) {
10931095
if (!editor) {
10941096
this.destroy();
10951097
return;
@@ -1119,6 +1121,7 @@ class CommentPopup {
11191121
}
11201122

11211123
const container = this.#createPopup();
1124+
this.#buttonsContainer.classList.toggle("hidden", !isEditable);
11221125
container.classList.toggle("hidden", false);
11231126
container.classList.toggle("selected", isSelected);
11241127
this.#selected = isSelected;

0 commit comments

Comments
 (0)