From f23ec9f6cc2dab72b463e45977259809dc1d8180 Mon Sep 17 00:00:00 2001 From: AkshatOP Date: Sun, 26 Apr 2026 00:58:27 +0530 Subject: [PATCH 1/2] Display /Subj field in annotation popup header --- src/core/annotation.js | 19 +++++++++++++++++++ src/display/annotation_layer.js | 15 ++++++++++++++- web/comment_manager.js | 17 ++++++++++++++++- 3 files changed, 49 insertions(+), 2 deletions(-) diff --git a/src/core/annotation.js b/src/core/annotation.js index 4962e791a652c..632b795b7d48a 100644 --- a/src/core/annotation.js +++ b/src/core/annotation.js @@ -922,6 +922,16 @@ class Annotation { this._title = this._parseStringHelper(title); } + /** + * Set the subject. + * + * @param {string} subject - The subject of the annotation (PDF /Subj entry), + * displayed alongside the title in annotation popups. + */ + setSubject(subject) { + this._subject = this._parseStringHelper(subject); + } + /** * Set the contents. * @@ -1657,6 +1667,9 @@ class MarkupAnnotation extends Annotation { this.setTitle(parent.get("T")); this.data.titleObj = this._title; + this.setSubject(parent.get("Subj")); + this.data.subjectObj = this._subject; + this.setContents(parent.get("Contents")); this.data.contentsObj = this._contents; @@ -1686,6 +1699,9 @@ class MarkupAnnotation extends Annotation { } else { this.data.titleObj = this._title; + this.setSubject(dict.get("Subj")); + this.data.subjectObj = this._subject; + this.setCreationDate(dict.get("CreationDate")); this.data.creationDate = this.creationDate; @@ -3987,6 +4003,9 @@ class PopupAnnotation extends Annotation { this.setTitle(parentItem.get("T")); this.data.titleObj = this._title; + this.setSubject(parentItem.get("Subj")); + this.data.subjectObj = this._subject; + this.setContents(parentItem.get("Contents")); this.data.contentsObj = this._contents; diff --git a/src/display/annotation_layer.js b/src/display/annotation_layer.js index 59cc9dfcbd092..68031e45a2f58 100644 --- a/src/display/annotation_layer.js +++ b/src/display/annotation_layer.js @@ -750,6 +750,7 @@ class AnnotationElement { data: { color: data.color, titleObj: data.titleObj, + subjectObj: data.subjectObj, modificationDate, contentsObj, richText: data.richText, @@ -2374,6 +2375,7 @@ class PopupAnnotationElement extends AnnotationElement { container: this.container, color: this.data.color, titleObj: this.data.titleObj, + subjectObj: this.data.subjectObj, modificationDate: this.data.modificationDate || this.data.creationDate, contentsObj: this.data.contentsObj, richText: this.data.richText, @@ -2455,6 +2457,8 @@ class PopupElement { #titleObj = null; + #subjectObj = null; + #updates = null; #wasVisible = false; @@ -2468,6 +2472,7 @@ class PopupElement { color, elements, titleObj, + subjectObj, modificationDate, contentsObj, richText, @@ -2479,6 +2484,7 @@ class PopupElement { }) { this.#container = container; this.#titleObj = titleObj; + this.#subjectObj = subjectObj; this.#contentsObj = contentsObj; this.#richText = richText; this.#parent = parent; @@ -2671,6 +2677,8 @@ class PopupElement { opacity, creationDate, modificationDate, + titleObj: this.#titleObj, + subjectObj: this.#subjectObj, }; } @@ -2783,7 +2791,12 @@ class PopupElement { const title = document.createElement("span"); title.className = "title"; header.append(title); - ({ dir: title.dir, str: title.textContent } = this.#titleObj); + if (this.#subjectObj?.str) { + title.textContent = `${this.#subjectObj.str} \u2014 ${this.#titleObj.str}`; + title.dir = this.#subjectObj.dir; + } else { + ({ dir: title.dir, str: title.textContent } = this.#titleObj); + } } popup.append(header); diff --git a/web/comment_manager.js b/web/comment_manager.js index 9625c9fb90764..b8a3db0ace0b4 100644 --- a/web/comment_manager.js +++ b/web/comment_manager.js @@ -876,6 +876,8 @@ class CommentPopup { #text = null; + #title = null; + #time = null; #prevDragX = 0; @@ -939,6 +941,9 @@ class CommentPopup { const time = (this.#time = document.createElement("time")); time.className = "commentPopupTime"; + const title = (this.#title = document.createElement("span")); + title.className = "commentPopupTitle"; + const buttons = (this.#buttonsContainer = document.createElement("div")); buttons.className = "commentPopupButtons"; const edit = document.createElement("button"); @@ -999,7 +1004,7 @@ class CommentPopup { del.addEventListener("contextmenu", noContextMenu); buttons.append(edit, del); - top.append(time, buttons); + top.append(title, time, buttons); const separator = document.createElement("hr"); @@ -1137,9 +1142,19 @@ class CommentPopup { modificationDate, color, opacity, + titleObj, + subjectObj, } = editor.getData(); container.style.backgroundColor = (color && CommentManager._makeCommentColor(color, opacity)) || ""; + if (titleObj?.str) { + this.#title.textContent = subjectObj?.str + ? `${subjectObj.str} \u2014 ${titleObj.str}` + : titleObj.str; + this.#title.hidden = false; + } else { + this.#title.hidden = true; + } this.#text.replaceChildren(); const html = richText?.str && (!contentsObj?.str || richText.str === contentsObj.str) From 172e2fd77c7ce5fa1e051f08b87763344a1e0343 Mon Sep 17 00:00:00 2001 From: AkshatOP Date: Tue, 28 Apr 2026 19:49:11 +0530 Subject: [PATCH 2/2] Address review comments: remove unused class and add tests --- test/pdfs/annotation-popup-subject.pdf | Bin 0 -> 720 bytes test/test_manifest.json | 9 +++++++++ test/unit/annotation_spec.js | 6 ++++++ web/comment_manager.js | 1 - 4 files changed, 15 insertions(+), 1 deletion(-) create mode 100644 test/pdfs/annotation-popup-subject.pdf diff --git a/test/pdfs/annotation-popup-subject.pdf b/test/pdfs/annotation-popup-subject.pdf new file mode 100644 index 0000000000000000000000000000000000000000..0c10c35547b14f003aa00843a043d24f4e362e81 GIT binary patch literal 720 zcmaiy!Eb^v7{%}XE8fM#9VRV`Y>6>ZH!sUJquhvxI;z&VmOx3^{`$3rO^k;%kcQXy z_b`N{=?1vmVx4+vKLAWDSRu*P&sgvy+eIN>_c7=ss? zl}LxqzqP;7l`>%6q&vDzI#403w;=_uB9nZsYoyfrN0cI@bV~pPGo`e#jFDp?YDk^Z zoPG`P37_3mJLCIHL~XpX79R#_M8Pa0wp-X@67*-4IqCv${8QZh#!u+as{@v@Zlr}) z#@1b;pB!Zg?uz3^YK0@WpD3%{$szVqoU=ijLCWkh4F`-Jvo;}+IV+0V{9FZ2$rF2tTtj0yc)7)Q}C!X6jx5&jhFqD8kFWATkI vWVQgeI@wX!@tK0lvnc$9+{kZ%F@m+$?kcqxu{69ezRqYElV0!neMx=*ywbRA literal 0 HcmV?d00001 diff --git a/test/test_manifest.json b/test/test_manifest.json index d28f0318019d7..2f3a5a64d8294 100644 --- a/test/test_manifest.json +++ b/test/test_manifest.json @@ -8235,6 +8235,15 @@ "annotations": true, "about": "Text annotation without a separate Popup annotation" }, + { + "id": "annotation-popup-subject", + "file": "pdfs/annotation-popup-subject.pdf", + "md5": "60eb42164ccf3408d2ba495aa7c9ce9c", + "rounds": 1, + "type": "eq", + "annotations": true, + "about": "Text annotation popup showing /Subj (subject) alongside /T (author) in the header" + }, { "id": "annotation-underline", "file": "pdfs/annotation-underline.pdf", diff --git a/test/unit/annotation_spec.js b/test/unit/annotation_spec.js index cf364a521bcb0..d7eed51758fb4 100644 --- a/test/unit/annotation_spec.js +++ b/test/unit/annotation_spec.js @@ -649,6 +649,7 @@ describe("annotation", function () { annotationDict.set("Type", Name.get("Annot")); annotationDict.set("Subtype", Name.get("Text")); annotationDict.set("T", "ParentTitle"); + annotationDict.set("Subj", "ParentSubject"); annotationDict.set("Contents", "ParentText"); annotationDict.set("CreationDate", "D:20180423"); annotationDict.set("M", "D:20190423"); @@ -691,6 +692,7 @@ describe("annotation", function () { expect(data.inReplyTo).toEqual(annotationRef.toString()); expect(data.replyType).toEqual("Group"); expect(data.titleObj).toEqual({ str: "ParentTitle", dir: "ltr" }); + expect(data.subjectObj).toEqual({ str: "ParentSubject", dir: "ltr" }); expect(data.contentsObj).toEqual({ str: "ParentText", dir: "ltr" }); expect(data.creationDate).toEqual("D:20180423"); expect(data.modificationDate).toEqual("D:20190423"); @@ -723,6 +725,7 @@ describe("annotation", function () { replyDict.set("IRT", annotationRef); replyDict.set("RT", Name.get("R")); replyDict.set("T", "ReplyTitle"); + replyDict.set("Subj", "ReplySubject"); replyDict.set("Contents", "ReplyText"); replyDict.set("CreationDate", "D:20180523"); replyDict.set("M", "D:20190523"); @@ -746,6 +749,7 @@ describe("annotation", function () { expect(data.inReplyTo).toEqual(annotationRef.toString()); expect(data.replyType).toEqual("R"); expect(data.titleObj).toEqual({ str: "ReplyTitle", dir: "ltr" }); + expect(data.subjectObj).toEqual({ str: "ReplySubject", dir: "ltr" }); expect(data.contentsObj).toEqual({ str: "ReplyText", dir: "ltr" }); expect(data.creationDate).toEqual("D:20180523"); expect(data.modificationDate).toEqual("D:20190523"); @@ -4142,6 +4146,7 @@ describe("annotation", function () { annotationDict.set("Type", Name.get("Annot")); annotationDict.set("Subtype", Name.get("Text")); annotationDict.set("T", "Correct Title"); + annotationDict.set("Subj", "Correct Subject"); annotationDict.set("Contents", "Correct Text"); annotationDict.set("M", "D:20190423"); annotationDict.set("C", [0, 0, 1]); @@ -4184,6 +4189,7 @@ describe("annotation", function () { idFactoryMock ); expect(data.titleObj).toEqual({ str: "Correct Title", dir: "ltr" }); + expect(data.subjectObj).toEqual({ str: "Correct Subject", dir: "ltr" }); expect(data.contentsObj).toEqual({ str: "Correct Text", dir: "ltr" }); expect(data.modificationDate).toEqual("D:20190423"); expect(data.color).toEqual(new Uint8ClampedArray([0, 0, 255])); diff --git a/web/comment_manager.js b/web/comment_manager.js index b8a3db0ace0b4..2226a4bd3017a 100644 --- a/web/comment_manager.js +++ b/web/comment_manager.js @@ -942,7 +942,6 @@ class CommentPopup { time.className = "commentPopupTime"; const title = (this.#title = document.createElement("span")); - title.className = "commentPopupTitle"; const buttons = (this.#buttonsContainer = document.createElement("div")); buttons.className = "commentPopupButtons";