Merge pull request #20274 from calixteman/save_comment_reading_mode

[Annotation] Save the comment changes made in reading mode (bug 1987427)
This commit is contained in:
Tim van der Meij 2025-09-15 23:32:51 +02:00 committed by GitHub
commit d85fd12437
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 113 additions and 24 deletions

View File

@ -29,6 +29,7 @@
import { import {
AnnotationBorderStyleType, AnnotationBorderStyleType,
AnnotationEditorPrefix,
AnnotationEditorType, AnnotationEditorType,
AnnotationPrefix, AnnotationPrefix,
AnnotationType, AnnotationType,
@ -242,6 +243,16 @@ class AnnotationElement {
return point; return point;
} }
get commentText() {
const { data } = this;
return (
this.annotationStorage.getRawValue(`${AnnotationEditorPrefix}${data.id}`)
?.popup?.contents ||
data.contentsObj?.str ||
""
);
}
removePopup() { removePopup() {
(this.#popupElement?.popup || this.popup)?.remove(); (this.#popupElement?.popup || this.popup)?.remove();
this.#popupElement = this.popup = null; this.#popupElement = this.popup = null;
@ -2335,6 +2346,8 @@ class PopupElement {
#firstElement = null; #firstElement = null;
#commentText = null;
constructor({ constructor({
container, container,
color, color,
@ -2495,7 +2508,16 @@ class PopupElement {
} }
getData() { getData() {
return this.#firstElement.data; const { richText, color, opacity, creationDate, modificationDate } =
this.#firstElement.data;
return {
contentsObj: { str: this.comment },
richText,
color,
opacity,
creationDate,
modificationDate,
};
} }
get elementBeforePopup() { get elementBeforePopup() {
@ -2503,22 +2525,35 @@ class PopupElement {
} }
get comment() { get comment() {
return this.#firstElement.data.contentsObj?.str || ""; this.#commentText ||= this.#firstElement.commentText;
return this.#commentText;
} }
set comment(text) { set comment(text) {
const element = this.#firstElement; const element = this.#firstElement;
if (text) { const { data } = element;
element.data.contentsObj = { str: text }; if (text === this.comment) {
// TODO: Support saving the text. return;
// element.annotationStorage.setValue(element.data.id, { }
// popup: { contents: text }, const popup = { deleted: !text, contents: text || "" };
// }); if (!element.annotationStorage.updateEditor(data.id, { popup })) {
} else { element.annotationStorage.setValue(
element.data.contentsObj = null; `${AnnotationEditorPrefix}${data.id}`,
{
id: data.id,
annotationType: data.annotationType,
pageIndex: element.parent.page._pageIndex,
popup,
popupRef: data.popupRef,
modificationDate: new Date(),
}
);
}
this.#commentText = text;
if (!text) {
element.removePopup(); element.removePopup();
} }
element.data.modificationDate = new Date();
} }
get parentBoundingClientRect() { get parentBoundingClientRect() {
@ -2707,6 +2742,10 @@ class PopupElement {
} }
updateEdited({ rect, popup, deleted }) { updateEdited({ rect, popup, deleted }) {
if (this.#commentManager) {
this.#commentText = deleted ? null : popup.text;
return;
}
if (deleted || popup?.deleted) { if (deleted || popup?.deleted) {
this.remove(); this.remove();
return; return;

View File

@ -31,6 +31,8 @@ class AnnotationStorage {
#modifiedIds = null; #modifiedIds = null;
#editorsMap = null;
#storage = new Map(); #storage = new Map();
constructor() { constructor() {
@ -83,6 +85,13 @@ class AnnotationStorage {
* @param {string} key * @param {string} key
*/ */
remove(key) { remove(key) {
const storedValue = this.#storage.get(key);
if (storedValue === undefined) {
return;
}
if (storedValue instanceof AnnotationEditor) {
this.#editorsMap.delete(storedValue.annotationElementId);
}
this.#storage.delete(key); this.#storage.delete(key);
if (this.#storage.size === 0) { if (this.#storage.size === 0) {
@ -122,13 +131,13 @@ class AnnotationStorage {
this.#setModified(); this.#setModified();
} }
if ( if (value instanceof AnnotationEditor) {
value instanceof AnnotationEditor && (this.#editorsMap ||= new Map()).set(value.annotationElementId, value);
typeof this.onAnnotationEditor === "function" if (typeof this.onAnnotationEditor === "function") {
) {
this.onAnnotationEditor(value.constructor._type); this.onAnnotationEditor(value.constructor._type);
} }
} }
}
/** /**
* Check if the storage contains the given key. * Check if the storage contains the given key.
@ -250,6 +259,15 @@ class AnnotationStorage {
this.#modifiedIds = null; this.#modifiedIds = null;
} }
updateEditor(annotationId, data) {
const value = this.#editorsMap?.get(annotationId);
if (value) {
value.updateFromAnnotationLayer(data);
return true;
}
return false;
}
/** /**
* @returns {{ids: Set<string>, hash: string}} * @returns {{ids: Set<string>, hash: string}}
*/ */
@ -258,16 +276,14 @@ class AnnotationStorage {
return this.#modifiedIds; return this.#modifiedIds;
} }
const ids = []; const ids = [];
for (const value of this.#storage.values()) { if (this.#editorsMap) {
if ( for (const value of this.#editorsMap.values()) {
!(value instanceof AnnotationEditor) || if (!value.serialize()) {
!value.annotationElementId ||
!value.serialize()
) {
continue; continue;
} }
ids.push(value.annotationElementId); ids.push(value.annotationElementId);
} }
}
return (this.#modifiedIds = { return (this.#modifiedIds = {
ids: new Set(ids), ids: new Set(ids),
hash: ids.join(","), hash: ids.join(","),

View File

@ -1243,6 +1243,16 @@ class AnnotationEditor {
} }
this.#comment ||= new Comment(this); this.#comment ||= new Comment(this);
this.#comment.setInitialText(comment, richText); this.#comment.setInitialText(comment, richText);
if (!this.annotationElementId) {
return;
}
const storedData = this._uiManager.getAndRemoveDataFromAnnotationStorage(
this.annotationElementId
);
if (storedData) {
this.updateFromAnnotationLayer(storedData);
}
} }
get hasEditedComment() { get hasEditedComment() {
@ -1288,6 +1298,10 @@ class AnnotationEditor {
} }
} }
updateFromAnnotationLayer({ popup: { contents, deleted } }) {
this.#comment.data = deleted ? null : contents;
}
get parentBoundingClientRect() { get parentBoundingClientRect() {
return this.parent.boundingClientRect; return this.parent.boundingClientRect;
} }

View File

@ -1288,6 +1288,26 @@ class AnnotationEditorUIManager {
this.#floatingToolbar.show(textLayer, boxes, this.direction === "ltr"); this.#floatingToolbar.show(textLayer, boxes, this.direction === "ltr");
} }
/**
* Some annotations may have been modified in the annotation layer
* (e.g. comments added or modified).
* So this function retrieves the data from the storage and removes
* them from the storage in order to be able to save them later.
* @param {string} annotationId
* @returns {Object|null} The data associated to the annotation or null.
*/
getAndRemoveDataFromAnnotationStorage(annotationId) {
if (!this.#annotationStorage) {
return null;
}
const key = `${AnnotationEditorPrefix}${annotationId}`;
const storedValue = this.#annotationStorage.getRawValue(key);
if (storedValue) {
this.#annotationStorage.remove(key);
}
return storedValue;
}
/** /**
* Add an editor in the annotation storage. * Add an editor in the annotation storage.
* @param {AnnotationEditor} editor * @param {AnnotationEditor} editor