Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 39 additions & 0 deletions src/core/annotation.js
Original file line number Diff line number Diff line change
Expand Up @@ -702,6 +702,7 @@ class Annotation {

this.setTitle(dict.get("T"));
this.setContents(dict.get("Contents"));
this.setAnnotationName(dict.get("NM"));
this.setModificationDate(dict.get("M"));
this.setFlags(dict.get("F"));
this.setRectangle(dict.getArray("Rect"));
Expand Down Expand Up @@ -738,6 +739,7 @@ class Annotation {
contentsObj: this._contents,
hasAppearance: !!this.appearance,
id: params.id,
annotationName: this.annotationName,
modificationDate: this.modificationDate,
oc: this._oc,
rect: this.rectangle,
Expand Down Expand Up @@ -973,6 +975,37 @@ class Annotation {
this._contents = this._parseStringHelper(contents);
}

/**
* Set the subject.
*
* @public
* @memberof Annotation
* @param {string} subject - A short description of what the annotation is
* about, which viewers show beside its contents
*/
setSubject(subject) {
this._subject = this._parseStringHelper(subject);
}

/**
* Set the annotation name.
*
* Unlike `id`, which identifies the object in the file, this is the name the
* document itself gives the annotation, and the one other annotations and
* external records refer to it by.
*
* @public
* @memberof Annotation
* @param {string} annotationName - The annotation name, uniquely identifying
* the annotation among those on its page
*/
setAnnotationName(annotationName) {
this.annotationName =
typeof annotationName === "string"
? stringToPDFString(annotationName)
: null;
}

/**
* Set the modification date.
*
Expand Down Expand Up @@ -1732,6 +1765,9 @@ class MarkupAnnotation extends Annotation {
this.setContents(parent.get("Contents"));
this.data.contentsObj = this._contents;

this.setSubject(parent.get("Subj"));
this.data.subjectObj = this._subject;

if (!parent.has("CreationDate")) {
this.data.creationDate = null;
} else {
Expand All @@ -1758,6 +1794,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;

Expand Down
78 changes: 78 additions & 0 deletions test/unit/annotation_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -675,6 +675,7 @@ describe("annotation", function () {
annotationDict.set("Subtype", Name.get("Text"));
annotationDict.set("T", "ParentTitle");
annotationDict.set("Contents", "ParentText");
annotationDict.set("Subj", "ParentSubject");
annotationDict.set("CreationDate", "D:20180423");
annotationDict.set("M", "D:20190423");
annotationDict.set("C", [0, 0, 1]);
Expand All @@ -694,6 +695,7 @@ describe("annotation", function () {
replyDict.set("RT", Name.get("Group"));
replyDict.set("T", "ReplyTitle");
replyDict.set("Contents", "ReplyText");
replyDict.set("Subj", "ReplySubject");
replyDict.set("CreationDate", "D:20180523");
replyDict.set("M", "D:20190523");
replyDict.set("C", [0.4]);
Expand All @@ -717,12 +719,88 @@ describe("annotation", function () {
expect(data.replyType).toEqual("Group");
expect(data.titleObj).toEqual({ str: "ParentTitle", dir: "ltr" });
expect(data.contentsObj).toEqual({ str: "ParentText", dir: "ltr" });
expect(data.subjectObj).toEqual({ str: "ParentSubject", dir: "ltr" });
expect(data.creationDate).toEqual("D:20180423");
expect(data.modificationDate).toEqual("D:20190423");
expect(data.color).toEqual(new Uint8ClampedArray([0, 0, 255]));
expect(data.popupRef).toEqual("820R");
});

it("should parse the annotation name", async function () {
const annotationDict = new Dict();
annotationDict.set("Type", Name.get("Annot"));
annotationDict.set("Subtype", Name.get("Text"));
annotationDict.set("NM", "the-name-the-document-gives-it");

const annotationRef = Ref.get(1, 0);
const xref = new XRefMock([{ ref: annotationRef, data: annotationDict }]);

const { data } = await AnnotationFactory.create(
xref,
annotationRef,
annotationGlobalsMock,
idFactoryMock
);
expect(data.annotationName).toEqual("the-name-the-document-gives-it");
// The object id is a separate thing, and stays what it was.
expect(data.id).toEqual("1R");
});

it("should handle a missing annotation name", async function () {
const annotationDict = new Dict();
annotationDict.set("Type", Name.get("Annot"));
annotationDict.set("Subtype", Name.get("Text"));

const annotationRef = Ref.get(1, 0);
const xref = new XRefMock([{ ref: annotationRef, data: annotationDict }]);

const { data } = await AnnotationFactory.create(
xref,
annotationRef,
annotationGlobalsMock,
idFactoryMock
);
expect(data.annotationName).toEqual(null);
});

it("should parse the subject", async function () {
const annotationDict = new Dict();
annotationDict.set("Type", Name.get("Annot"));
annotationDict.set("Subtype", Name.get("Text"));
annotationDict.set("Subj", "What this is about");

const annotationRef = Ref.get(1, 0);
const xref = new XRefMock([{ ref: annotationRef, data: annotationDict }]);

const { data } = await AnnotationFactory.create(
xref,
annotationRef,
annotationGlobalsMock,
idFactoryMock
);
expect(data.subjectObj).toEqual({
str: "What this is about",
dir: "ltr",
});
});

it("should handle a missing subject", async function () {
const annotationDict = new Dict();
annotationDict.set("Type", Name.get("Annot"));
annotationDict.set("Subtype", Name.get("Text"));

const annotationRef = Ref.get(1, 0);
const xref = new XRefMock([{ ref: annotationRef, data: annotationDict }]);

const { data } = await AnnotationFactory.create(
xref,
annotationRef,
annotationGlobalsMock,
idFactoryMock
);
expect(data.subjectObj).toEqual({ str: "", dir: "ltr" });
});

it("should parse IRT/RT for a reply type", async function () {
const annotationRef = Ref.get(819, 0);
const annotationDict = new Dict();
Expand Down