Merge pull request #18134 from calixteman/hide_annotations
[api-minor][Editor] When switching to editing mode, redraw pages containing editable annotations (bug 1883884)
This commit is contained in:
commit
bdcc4a0feb
@ -680,6 +680,7 @@ class Annotation {
|
|||||||
hasOwnCanvas: false,
|
hasOwnCanvas: false,
|
||||||
noRotate: !!(this.flags & AnnotationFlag.NOROTATE),
|
noRotate: !!(this.flags & AnnotationFlag.NOROTATE),
|
||||||
noHTML: isLocked && isContentLocked,
|
noHTML: isLocked && isContentLocked,
|
||||||
|
isEditable: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (params.collectFields) {
|
if (params.collectFields) {
|
||||||
@ -776,6 +777,10 @@ class Annotation {
|
|||||||
return this.printable;
|
return this.printable;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mustBeViewedWhenEditing() {
|
||||||
|
return !this.data.isEditable;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @type {boolean}
|
* @type {boolean}
|
||||||
*/
|
*/
|
||||||
@ -3802,7 +3807,8 @@ class FreeTextAnnotation extends MarkupAnnotation {
|
|||||||
// It uses its own canvas in order to be hidden if edited.
|
// It uses its own canvas in order to be hidden if edited.
|
||||||
// But if it has the noHTML flag, it means that we don't want to be able
|
// But if it has the noHTML flag, it means that we don't want to be able
|
||||||
// to modify it so we can just draw it on the main canvas.
|
// to modify it so we can just draw it on the main canvas.
|
||||||
this.data.hasOwnCanvas = !this.data.noHTML;
|
this.data.hasOwnCanvas = this.data.noRotate;
|
||||||
|
this.data.isEditable = !this.data.noHTML;
|
||||||
// We want to be able to add mouse listeners to the annotation.
|
// We want to be able to add mouse listeners to the annotation.
|
||||||
this.data.noHTML = false;
|
this.data.noHTML = false;
|
||||||
|
|
||||||
|
|||||||
@ -411,6 +411,8 @@ class Page {
|
|||||||
intent,
|
intent,
|
||||||
cacheKey,
|
cacheKey,
|
||||||
annotationStorage = null,
|
annotationStorage = null,
|
||||||
|
isEditing = false,
|
||||||
|
modifiedIds = null,
|
||||||
}) {
|
}) {
|
||||||
const contentStreamPromise = this.getContentStream();
|
const contentStreamPromise = this.getContentStream();
|
||||||
const resourcesPromise = this.loadResources([
|
const resourcesPromise = this.loadResources([
|
||||||
@ -579,7 +581,9 @@ class Page {
|
|||||||
if (
|
if (
|
||||||
intentAny ||
|
intentAny ||
|
||||||
(intentDisplay &&
|
(intentDisplay &&
|
||||||
annotation.mustBeViewed(annotationStorage, renderForms)) ||
|
annotation.mustBeViewed(annotationStorage, renderForms) &&
|
||||||
|
((isEditing && annotation.mustBeViewedWhenEditing()) ||
|
||||||
|
(!isEditing && !modifiedIds?.has(annotation.data.id)))) ||
|
||||||
(intentPrint && annotation.mustBePrinted(annotationStorage))
|
(intentPrint && annotation.mustBePrinted(annotationStorage))
|
||||||
) {
|
) {
|
||||||
opListPromises.push(
|
opListPromises.push(
|
||||||
|
|||||||
@ -752,6 +752,8 @@ class WorkerMessageHandler {
|
|||||||
intent: data.intent,
|
intent: data.intent,
|
||||||
cacheKey: data.cacheKey,
|
cacheKey: data.cacheKey,
|
||||||
annotationStorage: data.annotationStorage,
|
annotationStorage: data.annotationStorage,
|
||||||
|
isEditing: data.isEditing,
|
||||||
|
modifiedIds: data.modifiedIds,
|
||||||
})
|
})
|
||||||
.then(
|
.then(
|
||||||
function (operatorListInfo) {
|
function (operatorListInfo) {
|
||||||
|
|||||||
@ -198,6 +198,10 @@ class AnnotationElement {
|
|||||||
return !!(titleObj?.str || contentsObj?.str || richText?.str);
|
return !!(titleObj?.str || contentsObj?.str || richText?.str);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get _isEditable() {
|
||||||
|
return this.data.isEditable;
|
||||||
|
}
|
||||||
|
|
||||||
get hasPopupData() {
|
get hasPopupData() {
|
||||||
return AnnotationElement._hasPopupData(this.data);
|
return AnnotationElement._hasPopupData(this.data);
|
||||||
}
|
}
|
||||||
@ -734,10 +738,6 @@ class AnnotationElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
get _isEditable() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
_editOnDoubleClick() {
|
_editOnDoubleClick() {
|
||||||
if (!this._isEditable) {
|
if (!this._isEditable) {
|
||||||
return;
|
return;
|
||||||
@ -2530,10 +2530,6 @@ class FreeTextAnnotationElement extends AnnotationElement {
|
|||||||
|
|
||||||
return this.container;
|
return this.container;
|
||||||
}
|
}
|
||||||
|
|
||||||
get _isEditable() {
|
|
||||||
return this.data.hasOwnCanvas;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class LineAnnotationElement extends AnnotationElement {
|
class LineAnnotationElement extends AnnotationElement {
|
||||||
@ -3107,6 +3103,10 @@ class AnnotationLayer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hasEditableAnnotations() {
|
||||||
|
return this.#editableAnnotations.size > 0;
|
||||||
|
}
|
||||||
|
|
||||||
#appendElement(element, id) {
|
#appendElement(element, id) {
|
||||||
const contentElement = element.firstChild || element;
|
const contentElement = element.firstChild || element;
|
||||||
contentElement.id = `${AnnotationPrefix}${id}`;
|
contentElement.id = `${AnnotationPrefix}${id}`;
|
||||||
@ -3188,7 +3188,7 @@ class AnnotationLayer {
|
|||||||
}
|
}
|
||||||
this.#appendElement(rendered, data.id);
|
this.#appendElement(rendered, data.id);
|
||||||
|
|
||||||
if (element.annotationEditorType > 0) {
|
if (element._isEditable) {
|
||||||
this.#editableAnnotations.set(element.data.id, element);
|
this.#editableAnnotations.set(element.data.id, element);
|
||||||
this._annotationEditorUIManager?.renderAnnotationElement(element);
|
this._annotationEditorUIManager?.renderAnnotationElement(element);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -13,7 +13,7 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { objectFromMap, unreachable } from "../shared/util.js";
|
import { objectFromMap, shadow, unreachable } from "../shared/util.js";
|
||||||
import { AnnotationEditor } from "./editor/editor.js";
|
import { AnnotationEditor } from "./editor/editor.js";
|
||||||
import { MurmurHash3_64 } from "../shared/murmurhash3.js";
|
import { MurmurHash3_64 } from "../shared/murmurhash3.js";
|
||||||
|
|
||||||
@ -29,6 +29,8 @@ const SerializableEmpty = Object.freeze({
|
|||||||
class AnnotationStorage {
|
class AnnotationStorage {
|
||||||
#modified = false;
|
#modified = false;
|
||||||
|
|
||||||
|
#modifiedIds = null;
|
||||||
|
|
||||||
#storage = new Map();
|
#storage = new Map();
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
@ -248,6 +250,34 @@ class AnnotationStorage {
|
|||||||
}
|
}
|
||||||
return stats;
|
return stats;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
resetModifiedIds() {
|
||||||
|
this.#modifiedIds = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns {{ids: Set<string>, hash: string}}
|
||||||
|
*/
|
||||||
|
get modifiedIds() {
|
||||||
|
if (this.#modifiedIds) {
|
||||||
|
return this.#modifiedIds;
|
||||||
|
}
|
||||||
|
const ids = [];
|
||||||
|
for (const value of this.#storage.values()) {
|
||||||
|
if (
|
||||||
|
!(value instanceof AnnotationEditor) ||
|
||||||
|
!value.annotationElementId ||
|
||||||
|
!value.serialize()
|
||||||
|
) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
ids.push(value.annotationElementId);
|
||||||
|
}
|
||||||
|
return (this.#modifiedIds = {
|
||||||
|
ids: new Set(ids),
|
||||||
|
hash: ids.join(","),
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -282,6 +312,13 @@ class PrintAnnotationStorage extends AnnotationStorage {
|
|||||||
get serializable() {
|
get serializable() {
|
||||||
return this.#serializable;
|
return this.#serializable;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get modifiedIds() {
|
||||||
|
return shadow(this, "modifiedIds", {
|
||||||
|
ids: new Set(),
|
||||||
|
hash: "",
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export { AnnotationStorage, PrintAnnotationStorage, SerializableEmpty };
|
export { AnnotationStorage, PrintAnnotationStorage, SerializableEmpty };
|
||||||
|
|||||||
@ -1227,6 +1227,7 @@ class PDFDocumentProxy {
|
|||||||
* @property {Map<string, HTMLCanvasElement>} [annotationCanvasMap] - Map some
|
* @property {Map<string, HTMLCanvasElement>} [annotationCanvasMap] - Map some
|
||||||
* annotation ids with canvases used to render them.
|
* annotation ids with canvases used to render them.
|
||||||
* @property {PrintAnnotationStorage} [printAnnotationStorage]
|
* @property {PrintAnnotationStorage} [printAnnotationStorage]
|
||||||
|
* @property {boolean} [isEditing] - Render the page in editing mode.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1248,6 +1249,7 @@ class PDFDocumentProxy {
|
|||||||
* from the {@link AnnotationStorage}-instance; useful e.g. for printing.
|
* from the {@link AnnotationStorage}-instance; useful e.g. for printing.
|
||||||
* The default value is `AnnotationMode.ENABLE`.
|
* The default value is `AnnotationMode.ENABLE`.
|
||||||
* @property {PrintAnnotationStorage} [printAnnotationStorage]
|
* @property {PrintAnnotationStorage} [printAnnotationStorage]
|
||||||
|
* @property {boolean} [isEditing] - Render the page in editing mode.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1420,13 +1422,15 @@ class PDFPageProxy {
|
|||||||
annotationCanvasMap = null,
|
annotationCanvasMap = null,
|
||||||
pageColors = null,
|
pageColors = null,
|
||||||
printAnnotationStorage = null,
|
printAnnotationStorage = null,
|
||||||
|
isEditing = false,
|
||||||
}) {
|
}) {
|
||||||
this._stats?.time("Overall");
|
this._stats?.time("Overall");
|
||||||
|
|
||||||
const intentArgs = this._transport.getRenderingIntent(
|
const intentArgs = this._transport.getRenderingIntent(
|
||||||
intent,
|
intent,
|
||||||
annotationMode,
|
annotationMode,
|
||||||
printAnnotationStorage
|
printAnnotationStorage,
|
||||||
|
isEditing
|
||||||
);
|
);
|
||||||
const { renderingIntent, cacheKey } = intentArgs;
|
const { renderingIntent, cacheKey } = intentArgs;
|
||||||
// If there was a pending destroy, cancel it so no cleanup happens during
|
// If there was a pending destroy, cancel it so no cleanup happens during
|
||||||
@ -1560,6 +1564,7 @@ class PDFPageProxy {
|
|||||||
intent = "display",
|
intent = "display",
|
||||||
annotationMode = AnnotationMode.ENABLE,
|
annotationMode = AnnotationMode.ENABLE,
|
||||||
printAnnotationStorage = null,
|
printAnnotationStorage = null,
|
||||||
|
isEditing = false,
|
||||||
} = {}) {
|
} = {}) {
|
||||||
if (typeof PDFJSDev !== "undefined" && !PDFJSDev.test("GENERIC")) {
|
if (typeof PDFJSDev !== "undefined" && !PDFJSDev.test("GENERIC")) {
|
||||||
throw new Error("Not implemented: getOperatorList");
|
throw new Error("Not implemented: getOperatorList");
|
||||||
@ -1576,6 +1581,7 @@ class PDFPageProxy {
|
|||||||
intent,
|
intent,
|
||||||
annotationMode,
|
annotationMode,
|
||||||
printAnnotationStorage,
|
printAnnotationStorage,
|
||||||
|
isEditing,
|
||||||
/* isOpList = */ true
|
/* isOpList = */ true
|
||||||
);
|
);
|
||||||
let intentState = this._intentStates.get(intentArgs.cacheKey);
|
let intentState = this._intentStates.get(intentArgs.cacheKey);
|
||||||
@ -1812,6 +1818,8 @@ class PDFPageProxy {
|
|||||||
renderingIntent,
|
renderingIntent,
|
||||||
cacheKey,
|
cacheKey,
|
||||||
annotationStorageSerializable,
|
annotationStorageSerializable,
|
||||||
|
isEditing,
|
||||||
|
modifiedIds,
|
||||||
}) {
|
}) {
|
||||||
if (typeof PDFJSDev === "undefined" || PDFJSDev.test("TESTING")) {
|
if (typeof PDFJSDev === "undefined" || PDFJSDev.test("TESTING")) {
|
||||||
assert(
|
assert(
|
||||||
@ -1828,6 +1836,8 @@ class PDFPageProxy {
|
|||||||
intent: renderingIntent,
|
intent: renderingIntent,
|
||||||
cacheKey,
|
cacheKey,
|
||||||
annotationStorage: map,
|
annotationStorage: map,
|
||||||
|
isEditing,
|
||||||
|
modifiedIds,
|
||||||
},
|
},
|
||||||
transfer
|
transfer
|
||||||
);
|
);
|
||||||
@ -2420,6 +2430,7 @@ class WorkerTransport {
|
|||||||
intent,
|
intent,
|
||||||
annotationMode = AnnotationMode.ENABLE,
|
annotationMode = AnnotationMode.ENABLE,
|
||||||
printAnnotationStorage = null,
|
printAnnotationStorage = null,
|
||||||
|
isEditing = false,
|
||||||
isOpList = false
|
isOpList = false
|
||||||
) {
|
) {
|
||||||
let renderingIntent = RenderingIntentFlag.DISPLAY; // Default value.
|
let renderingIntent = RenderingIntentFlag.DISPLAY; // Default value.
|
||||||
@ -2438,6 +2449,12 @@ class WorkerTransport {
|
|||||||
warn(`getRenderingIntent - invalid intent: ${intent}`);
|
warn(`getRenderingIntent - invalid intent: ${intent}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const annotationStorage =
|
||||||
|
renderingIntent & RenderingIntentFlag.PRINT &&
|
||||||
|
printAnnotationStorage instanceof PrintAnnotationStorage
|
||||||
|
? printAnnotationStorage
|
||||||
|
: this.annotationStorage;
|
||||||
|
|
||||||
switch (annotationMode) {
|
switch (annotationMode) {
|
||||||
case AnnotationMode.DISABLE:
|
case AnnotationMode.DISABLE:
|
||||||
renderingIntent += RenderingIntentFlag.ANNOTATIONS_DISABLE;
|
renderingIntent += RenderingIntentFlag.ANNOTATIONS_DISABLE;
|
||||||
@ -2450,12 +2467,6 @@ class WorkerTransport {
|
|||||||
case AnnotationMode.ENABLE_STORAGE:
|
case AnnotationMode.ENABLE_STORAGE:
|
||||||
renderingIntent += RenderingIntentFlag.ANNOTATIONS_STORAGE;
|
renderingIntent += RenderingIntentFlag.ANNOTATIONS_STORAGE;
|
||||||
|
|
||||||
const annotationStorage =
|
|
||||||
renderingIntent & RenderingIntentFlag.PRINT &&
|
|
||||||
printAnnotationStorage instanceof PrintAnnotationStorage
|
|
||||||
? printAnnotationStorage
|
|
||||||
: this.annotationStorage;
|
|
||||||
|
|
||||||
annotationStorageSerializable = annotationStorage.serializable;
|
annotationStorageSerializable = annotationStorage.serializable;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@ -2466,10 +2477,22 @@ class WorkerTransport {
|
|||||||
renderingIntent += RenderingIntentFlag.OPLIST;
|
renderingIntent += RenderingIntentFlag.OPLIST;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const { ids: modifiedIds, hash: modifiedIdsHash } =
|
||||||
|
annotationStorage.modifiedIds;
|
||||||
|
|
||||||
|
const cacheKeyBuf = [
|
||||||
|
renderingIntent,
|
||||||
|
annotationStorageSerializable.hash,
|
||||||
|
isEditing ? 1 : 0,
|
||||||
|
modifiedIdsHash,
|
||||||
|
];
|
||||||
|
|
||||||
return {
|
return {
|
||||||
renderingIntent,
|
renderingIntent,
|
||||||
cacheKey: `${renderingIntent}_${annotationStorageSerializable.hash}`,
|
cacheKey: cacheKeyBuf.join("_"),
|
||||||
annotationStorageSerializable,
|
annotationStorageSerializable,
|
||||||
|
isEditing,
|
||||||
|
modifiedIds,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -503,6 +503,14 @@ describe("ResetForm action", () => {
|
|||||||
it("must check that the Ink annotation has a popup", async () => {
|
it("must check that the Ink annotation has a popup", async () => {
|
||||||
await Promise.all(
|
await Promise.all(
|
||||||
pages.map(async ([browserName, page]) => {
|
pages.map(async ([browserName, page]) => {
|
||||||
|
if (browserName) {
|
||||||
|
// TODO
|
||||||
|
pending(
|
||||||
|
"Re-enable this test when the Ink annotation has been made editable."
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
await page.waitForFunction(
|
await page.waitForFunction(
|
||||||
`document.querySelector("[data-annotation-id='25R']").hidden === false`
|
`document.querySelector("[data-annotation-id='25R']").hidden === false`
|
||||||
);
|
);
|
||||||
|
|||||||
@ -45,6 +45,7 @@ import {
|
|||||||
scrollIntoView,
|
scrollIntoView,
|
||||||
switchToEditor,
|
switchToEditor,
|
||||||
waitForAnnotationEditorLayer,
|
waitForAnnotationEditorLayer,
|
||||||
|
waitForAnnotationModeChanged,
|
||||||
waitForSelectedEditor,
|
waitForSelectedEditor,
|
||||||
waitForSerialized,
|
waitForSerialized,
|
||||||
waitForStorageEntries,
|
waitForStorageEntries,
|
||||||
@ -987,6 +988,29 @@ describe("FreeText Editor", () => {
|
|||||||
pages.map(async ([browserName, page]) => {
|
pages.map(async ([browserName, page]) => {
|
||||||
await switchToFreeText(page);
|
await switchToFreeText(page);
|
||||||
|
|
||||||
|
const isEditorWhite = editorRect =>
|
||||||
|
page.evaluate(rect => {
|
||||||
|
const canvas = document.querySelector(".canvasWrapper canvas");
|
||||||
|
const ctx = canvas.getContext("2d");
|
||||||
|
rect ||= {
|
||||||
|
x: 0,
|
||||||
|
y: 0,
|
||||||
|
width: canvas.width,
|
||||||
|
height: canvas.height,
|
||||||
|
};
|
||||||
|
const { data } = ctx.getImageData(
|
||||||
|
rect.x,
|
||||||
|
rect.y,
|
||||||
|
rect.width,
|
||||||
|
rect.height
|
||||||
|
);
|
||||||
|
return data.every(x => x === 0xff);
|
||||||
|
}, editorRect);
|
||||||
|
|
||||||
|
// The page has been re-rendered but with no freetext annotations.
|
||||||
|
let isWhite = await isEditorWhite();
|
||||||
|
expect(isWhite).withContext(`In ${browserName}`).toBeTrue();
|
||||||
|
|
||||||
let editorIds = await getEditors(page, "freeText");
|
let editorIds = await getEditors(page, "freeText");
|
||||||
expect(editorIds.length).withContext(`In ${browserName}`).toEqual(6);
|
expect(editorIds.length).withContext(`In ${browserName}`).toEqual(6);
|
||||||
|
|
||||||
@ -1041,11 +1065,9 @@ describe("FreeText Editor", () => {
|
|||||||
// canvas.
|
// canvas.
|
||||||
editorIds = await getEditors(page, "freeText");
|
editorIds = await getEditors(page, "freeText");
|
||||||
expect(editorIds.length).withContext(`In ${browserName}`).toEqual(1);
|
expect(editorIds.length).withContext(`In ${browserName}`).toEqual(1);
|
||||||
const hidden = await page.$eval(
|
|
||||||
"[data-annotation-id='26R'] canvas",
|
isWhite = await isEditorWhite(editorRect);
|
||||||
el => getComputedStyle(el).display === "none"
|
expect(isWhite).withContext(`In ${browserName}`).toBeTrue();
|
||||||
);
|
|
||||||
expect(hidden).withContext(`In ${browserName}`).toBeTrue();
|
|
||||||
|
|
||||||
// Check we've now a div containing the text.
|
// Check we've now a div containing the text.
|
||||||
const newDivText = await page.$eval(
|
const newDivText = await page.$eval(
|
||||||
@ -1288,10 +1310,12 @@ describe("FreeText Editor", () => {
|
|||||||
await closePages(pages);
|
await closePages(pages);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("must move an annotation", async () => {
|
it("must edit an annotation", async () => {
|
||||||
await Promise.all(
|
await Promise.all(
|
||||||
pages.map(async ([browserName, page]) => {
|
pages.map(async ([browserName, page]) => {
|
||||||
|
const modeChangedHandle = await waitForAnnotationModeChanged(page);
|
||||||
await page.click("[data-annotation-id='26R']", { count: 2 });
|
await page.click("[data-annotation-id='26R']", { count: 2 });
|
||||||
|
await awaitPromise(modeChangedHandle);
|
||||||
await page.waitForSelector(`${getEditorSelector(0)}-editor`);
|
await page.waitForSelector(`${getEditorSelector(0)}-editor`);
|
||||||
|
|
||||||
const [focusedId, editable] = await page.evaluate(() => {
|
const [focusedId, editable] = await page.evaluate(() => {
|
||||||
@ -1347,6 +1371,7 @@ describe("FreeText Editor", () => {
|
|||||||
|
|
||||||
// TODO: remove this when we switch to BiDi.
|
// TODO: remove this when we switch to BiDi.
|
||||||
await hover(page, "[data-annotation-id='23R']");
|
await hover(page, "[data-annotation-id='23R']");
|
||||||
|
|
||||||
// Wait for the popup to be displayed.
|
// Wait for the popup to be displayed.
|
||||||
await page.waitForFunction(
|
await page.waitForFunction(
|
||||||
() =>
|
() =>
|
||||||
@ -1588,12 +1613,6 @@ describe("FreeText Editor", () => {
|
|||||||
it("must open an existing annotation and check that the position are good", async () => {
|
it("must open an existing annotation and check that the position are good", async () => {
|
||||||
await Promise.all(
|
await Promise.all(
|
||||||
pages.map(async ([browserName, page]) => {
|
pages.map(async ([browserName, page]) => {
|
||||||
await switchToFreeText(page);
|
|
||||||
|
|
||||||
await page.evaluate(() => {
|
|
||||||
document.getElementById("editorFreeTextParamsToolbar").remove();
|
|
||||||
});
|
|
||||||
|
|
||||||
const toBinary = buf => {
|
const toBinary = buf => {
|
||||||
for (let i = 0; i < buf.length; i += 4) {
|
for (let i = 0; i < buf.length; i += 4) {
|
||||||
const gray =
|
const gray =
|
||||||
@ -1646,8 +1665,12 @@ describe("FreeText Editor", () => {
|
|||||||
return null;
|
return null;
|
||||||
};
|
};
|
||||||
|
|
||||||
for (const n of [0, 1, 2, 3, 4]) {
|
const firstPixelsAnnotations = new Map();
|
||||||
const rect = await getRect(page, getEditorSelector(n));
|
|
||||||
|
// [26, 32, ...] are the annotation ids
|
||||||
|
for (const n of [26, 32, 42, 57, 35, 1]) {
|
||||||
|
const id = `${n}R`;
|
||||||
|
const rect = await getRect(page, `[data-annotation-id="${id}"]`);
|
||||||
const editorPng = await page.screenshot({
|
const editorPng = await page.screenshot({
|
||||||
clip: rect,
|
clip: rect,
|
||||||
type: "png",
|
type: "png",
|
||||||
@ -1658,33 +1681,33 @@ describe("FreeText Editor", () => {
|
|||||||
editorImage.width,
|
editorImage.width,
|
||||||
editorImage.height
|
editorImage.height
|
||||||
);
|
);
|
||||||
|
firstPixelsAnnotations.set(id, { editorFirstPix, rect });
|
||||||
|
}
|
||||||
|
|
||||||
|
await switchToFreeText(page);
|
||||||
|
|
||||||
|
await page.evaluate(() => {
|
||||||
|
document.getElementById("editorFreeTextParamsToolbar").remove();
|
||||||
|
});
|
||||||
|
|
||||||
|
for (const n of [0, 1, 2, 3, 4]) {
|
||||||
const annotationId = await page.evaluate(N => {
|
const annotationId = await page.evaluate(N => {
|
||||||
const editor = document.getElementById(
|
const editor = document.getElementById(
|
||||||
`pdfjs_internal_editor_${N}`
|
`pdfjs_internal_editor_${N}`
|
||||||
);
|
);
|
||||||
const annId = editor.getAttribute("annotation-id");
|
return editor.getAttribute("annotation-id");
|
||||||
const annotation = document.querySelector(
|
|
||||||
`[data-annotation-id="${annId}"]`
|
|
||||||
);
|
|
||||||
editor.hidden = true;
|
|
||||||
annotation.hidden = false;
|
|
||||||
return annId;
|
|
||||||
}, n);
|
}, n);
|
||||||
await page.waitForSelector(`${getEditorSelector(n)}[hidden]`);
|
const { editorFirstPix: annotationFirstPix, rect } =
|
||||||
await page.waitForSelector(
|
firstPixelsAnnotations.get(annotationId);
|
||||||
`[data-annotation-id="${annotationId}"]:not([hidden])`
|
const editorPng = await page.screenshot({
|
||||||
);
|
|
||||||
|
|
||||||
const annotationPng = await page.screenshot({
|
|
||||||
clip: rect,
|
clip: rect,
|
||||||
type: "png",
|
type: "png",
|
||||||
});
|
});
|
||||||
const annotationImage = PNG.sync.read(annotationPng);
|
const editorImage = PNG.sync.read(editorPng);
|
||||||
const annotationFirstPix = getFirstPixel(
|
const editorFirstPix = getFirstPixel(
|
||||||
annotationImage.data,
|
editorImage.data,
|
||||||
annotationImage.width,
|
editorImage.width,
|
||||||
annotationImage.height
|
editorImage.height
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(
|
expect(
|
||||||
@ -1719,12 +1742,6 @@ describe("FreeText Editor", () => {
|
|||||||
it("must open an existing rotated annotation and check that the position are good", async () => {
|
it("must open an existing rotated annotation and check that the position are good", async () => {
|
||||||
await Promise.all(
|
await Promise.all(
|
||||||
pages.map(async ([browserName, page]) => {
|
pages.map(async ([browserName, page]) => {
|
||||||
await switchToFreeText(page);
|
|
||||||
|
|
||||||
await page.evaluate(() => {
|
|
||||||
document.getElementById("editorFreeTextParamsToolbar").remove();
|
|
||||||
});
|
|
||||||
|
|
||||||
const toBinary = buf => {
|
const toBinary = buf => {
|
||||||
for (let i = 0; i < buf.length; i += 4) {
|
for (let i = 0; i < buf.length; i += 4) {
|
||||||
const gray =
|
const gray =
|
||||||
@ -1806,13 +1823,15 @@ describe("FreeText Editor", () => {
|
|||||||
return null;
|
return null;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const firstPixelsAnnotations = new Map();
|
||||||
for (const [n, start] of [
|
for (const [n, start] of [
|
||||||
[0, "BL"],
|
[17, "BL"],
|
||||||
[1, "BR"],
|
[18, "BR"],
|
||||||
[2, "TR"],
|
[19, "TR"],
|
||||||
[3, "TL"],
|
[20, "TL"],
|
||||||
]) {
|
]) {
|
||||||
const rect = await getRect(page, getEditorSelector(n));
|
const id = `${n}R`;
|
||||||
|
const rect = await getRect(page, `[data-annotation-id="${id}"]`);
|
||||||
const editorPng = await page.screenshot({
|
const editorPng = await page.screenshot({
|
||||||
clip: rect,
|
clip: rect,
|
||||||
type: "png",
|
type: "png",
|
||||||
@ -1824,33 +1843,38 @@ describe("FreeText Editor", () => {
|
|||||||
editorImage.height,
|
editorImage.height,
|
||||||
start
|
start
|
||||||
);
|
);
|
||||||
|
firstPixelsAnnotations.set(id, { editorFirstPix, rect });
|
||||||
|
}
|
||||||
|
|
||||||
|
await switchToFreeText(page);
|
||||||
|
|
||||||
|
await page.evaluate(() => {
|
||||||
|
document.getElementById("editorFreeTextParamsToolbar").remove();
|
||||||
|
});
|
||||||
|
|
||||||
|
for (const [n, start] of [
|
||||||
|
[0, "BL"],
|
||||||
|
[1, "BR"],
|
||||||
|
[2, "TR"],
|
||||||
|
[3, "TL"],
|
||||||
|
]) {
|
||||||
const annotationId = await page.evaluate(N => {
|
const annotationId = await page.evaluate(N => {
|
||||||
const editor = document.getElementById(
|
const editor = document.getElementById(
|
||||||
`pdfjs_internal_editor_${N}`
|
`pdfjs_internal_editor_${N}`
|
||||||
);
|
);
|
||||||
const annId = editor.getAttribute("annotation-id");
|
return editor.getAttribute("annotation-id");
|
||||||
const annotation = document.querySelector(
|
|
||||||
`[data-annotation-id="${annId}"]`
|
|
||||||
);
|
|
||||||
editor.hidden = true;
|
|
||||||
annotation.hidden = false;
|
|
||||||
return annId;
|
|
||||||
}, n);
|
}, n);
|
||||||
await page.waitForSelector(`${getEditorSelector(n)}[hidden]`);
|
const { editorFirstPix: annotationFirstPix, rect } =
|
||||||
await page.waitForSelector(
|
firstPixelsAnnotations.get(annotationId);
|
||||||
`[data-annotation-id="${annotationId}"]:not([hidden])`
|
const editorPng = await page.screenshot({
|
||||||
);
|
|
||||||
|
|
||||||
const annotationPng = await page.screenshot({
|
|
||||||
clip: rect,
|
clip: rect,
|
||||||
type: "png",
|
type: "png",
|
||||||
});
|
});
|
||||||
const annotationImage = PNG.sync.read(annotationPng);
|
const editorImage = PNG.sync.read(editorPng);
|
||||||
const annotationFirstPix = getFirstPixel(
|
const editorFirstPix = getFirstPixel(
|
||||||
annotationImage.data,
|
editorImage.data,
|
||||||
annotationImage.width,
|
editorImage.width,
|
||||||
annotationImage.height,
|
editorImage.height,
|
||||||
start
|
start
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -3552,13 +3576,6 @@ describe("FreeText Editor", () => {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
await page.waitForSelector("[data-annotation-id='998R'] canvas");
|
|
||||||
let hidden = await page.$eval(
|
|
||||||
"[data-annotation-id='998R'] canvas",
|
|
||||||
el => getComputedStyle(el).display === "none"
|
|
||||||
);
|
|
||||||
expect(hidden).withContext(`In ${browserName}`).toBeTrue();
|
|
||||||
|
|
||||||
// Check we've now a div containing the text.
|
// Check we've now a div containing the text.
|
||||||
await page.waitForSelector(
|
await page.waitForSelector(
|
||||||
"[data-annotation-id='998R'] div.annotationContent"
|
"[data-annotation-id='998R'] div.annotationContent"
|
||||||
@ -3571,6 +3588,24 @@ describe("FreeText Editor", () => {
|
|||||||
.withContext(`In ${browserName}`)
|
.withContext(`In ${browserName}`)
|
||||||
.toEqual("Hello World and edited in Firefox");
|
.toEqual("Hello World and edited in Firefox");
|
||||||
|
|
||||||
|
// Check that the canvas has nothing drawn at the annotation position.
|
||||||
|
await page.$eval(
|
||||||
|
"[data-annotation-id='998R']",
|
||||||
|
el => (el.hidden = true)
|
||||||
|
);
|
||||||
|
let editorPng = await page.screenshot({
|
||||||
|
clip: editorRect,
|
||||||
|
type: "png",
|
||||||
|
});
|
||||||
|
await page.$eval(
|
||||||
|
"[data-annotation-id='998R']",
|
||||||
|
el => (el.hidden = false)
|
||||||
|
);
|
||||||
|
let editorImage = PNG.sync.read(editorPng);
|
||||||
|
expect(editorImage.data.every(x => x === 0xff))
|
||||||
|
.withContext(`In ${browserName}`)
|
||||||
|
.toBeTrue();
|
||||||
|
|
||||||
const oneToThirteen = Array.from(new Array(13).keys(), n => n + 2);
|
const oneToThirteen = Array.from(new Array(13).keys(), n => n + 2);
|
||||||
for (const pageNumber of oneToThirteen) {
|
for (const pageNumber of oneToThirteen) {
|
||||||
await scrollIntoView(
|
await scrollIntoView(
|
||||||
@ -3587,6 +3622,19 @@ describe("FreeText Editor", () => {
|
|||||||
await switchToFreeText(page, /* disable = */ true);
|
await switchToFreeText(page, /* disable = */ true);
|
||||||
|
|
||||||
const thirteenToOne = Array.from(new Array(13).keys(), n => 13 - n);
|
const thirteenToOne = Array.from(new Array(13).keys(), n => 13 - n);
|
||||||
|
const handlePromise = await createPromise(page, resolve => {
|
||||||
|
const callback = e => {
|
||||||
|
if (e.source.id === 1) {
|
||||||
|
window.PDFViewerApplication.eventBus.off(
|
||||||
|
"pagerendered",
|
||||||
|
callback
|
||||||
|
);
|
||||||
|
resolve();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
window.PDFViewerApplication.eventBus.on("pagerendered", callback);
|
||||||
|
});
|
||||||
|
|
||||||
for (const pageNumber of thirteenToOne) {
|
for (const pageNumber of thirteenToOne) {
|
||||||
await scrollIntoView(
|
await scrollIntoView(
|
||||||
page,
|
page,
|
||||||
@ -3594,12 +3642,16 @@ describe("FreeText Editor", () => {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
await page.waitForSelector("[data-annotation-id='998R'] canvas");
|
await awaitPromise(handlePromise);
|
||||||
hidden = await page.$eval(
|
|
||||||
"[data-annotation-id='998R'] canvas",
|
editorPng = await page.screenshot({
|
||||||
el => getComputedStyle(el).display === "none"
|
clip: editorRect,
|
||||||
);
|
type: "png",
|
||||||
expect(hidden).withContext(`In ${browserName}`).toBeFalse();
|
});
|
||||||
|
editorImage = PNG.sync.read(editorPng);
|
||||||
|
expect(editorImage.data.every(x => x === 0xff))
|
||||||
|
.withContext(`In ${browserName}`)
|
||||||
|
.toBeFalse();
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|||||||
@ -564,14 +564,14 @@ describe("Stamp Editor", () => {
|
|||||||
for (let i = 0; i < pages1.length; i++) {
|
for (let i = 0; i < pages1.length; i++) {
|
||||||
const [, page1] = pages1[i];
|
const [, page1] = pages1[i];
|
||||||
await page1.bringToFront();
|
await page1.bringToFront();
|
||||||
await page1.click("#editorStamp");
|
await switchToStamp(page1);
|
||||||
|
|
||||||
await copyImage(page1, "../images/firefox_logo.png", 0);
|
await copyImage(page1, "../images/firefox_logo.png", 0);
|
||||||
await copy(page1);
|
await copy(page1);
|
||||||
|
|
||||||
const [, page2] = pages2[i];
|
const [, page2] = pages2[i];
|
||||||
await page2.bringToFront();
|
await page2.bringToFront();
|
||||||
await page2.click("#editorStamp");
|
await switchToStamp(page2);
|
||||||
|
|
||||||
await paste(page2);
|
await paste(page2);
|
||||||
|
|
||||||
|
|||||||
@ -447,11 +447,30 @@ function waitForAnnotationEditorLayer(page) {
|
|||||||
return createPromise(page, resolve => {
|
return createPromise(page, resolve => {
|
||||||
window.PDFViewerApplication.eventBus.on(
|
window.PDFViewerApplication.eventBus.on(
|
||||||
"annotationeditorlayerrendered",
|
"annotationeditorlayerrendered",
|
||||||
resolve
|
resolve,
|
||||||
|
{ once: true }
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function waitForAnnotationModeChanged(page) {
|
||||||
|
return createPromise(page, resolve => {
|
||||||
|
window.PDFViewerApplication.eventBus.on(
|
||||||
|
"annotationeditormodechanged",
|
||||||
|
resolve,
|
||||||
|
{ once: true }
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function waitForPageRendered(page) {
|
||||||
|
return createPromise(page, resolve => {
|
||||||
|
window.PDFViewerApplication.eventBus.on("pagerendered", resolve, {
|
||||||
|
once: true,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
async function scrollIntoView(page, selector) {
|
async function scrollIntoView(page, selector) {
|
||||||
const handle = await page.evaluateHandle(
|
const handle = await page.evaluateHandle(
|
||||||
sel => [
|
sel => [
|
||||||
@ -695,8 +714,10 @@ export {
|
|||||||
serializeBitmapDimensions,
|
serializeBitmapDimensions,
|
||||||
switchToEditor,
|
switchToEditor,
|
||||||
waitForAnnotationEditorLayer,
|
waitForAnnotationEditorLayer,
|
||||||
|
waitForAnnotationModeChanged,
|
||||||
waitForEntryInStorage,
|
waitForEntryInStorage,
|
||||||
waitForEvent,
|
waitForEvent,
|
||||||
|
waitForPageRendered,
|
||||||
waitForSandboxTrip,
|
waitForSandboxTrip,
|
||||||
waitForSelectedEditor,
|
waitForSelectedEditor,
|
||||||
waitForSerialized,
|
waitForSerialized,
|
||||||
|
|||||||
@ -182,6 +182,10 @@ class AnnotationLayerBuilder {
|
|||||||
this.div.hidden = true;
|
this.div.hidden = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hasEditableAnnotations() {
|
||||||
|
return !!this.annotationLayer?.hasEditableAnnotations();
|
||||||
|
}
|
||||||
|
|
||||||
#updatePresentationModeState(state) {
|
#updatePresentationModeState(state) {
|
||||||
if (!this.div) {
|
if (!this.div) {
|
||||||
return;
|
return;
|
||||||
|
|||||||
@ -119,6 +119,8 @@ class PDFPageView {
|
|||||||
|
|
||||||
#hasRestrictedScaling = false;
|
#hasRestrictedScaling = false;
|
||||||
|
|
||||||
|
#isEditing = false;
|
||||||
|
|
||||||
#layerProperties = null;
|
#layerProperties = null;
|
||||||
|
|
||||||
#loadingId = null;
|
#loadingId = null;
|
||||||
@ -354,6 +356,10 @@ class PDFPageView {
|
|||||||
this.pdfPage?.cleanup();
|
this.pdfPage?.cleanup();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hasEditableAnnotations() {
|
||||||
|
return !!this.annotationLayer?.hasEditableAnnotations();
|
||||||
|
}
|
||||||
|
|
||||||
get _textHighlighter() {
|
get _textHighlighter() {
|
||||||
return shadow(
|
return shadow(
|
||||||
this,
|
this,
|
||||||
@ -582,6 +588,20 @@ class PDFPageView {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
toggleEditingMode(isEditing) {
|
||||||
|
if (!this.hasEditableAnnotations()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.#isEditing = isEditing;
|
||||||
|
this.reset({
|
||||||
|
keepZoomLayer: true,
|
||||||
|
keepAnnotationLayer: true,
|
||||||
|
keepAnnotationEditorLayer: true,
|
||||||
|
keepXfaLayer: true,
|
||||||
|
keepTextLayer: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @typedef {Object} PDFPageViewUpdateParameters
|
* @typedef {Object} PDFPageViewUpdateParameters
|
||||||
* @property {number} [scale] The new scale, if specified.
|
* @property {number} [scale] The new scale, if specified.
|
||||||
@ -1037,6 +1057,7 @@ class PDFPageView {
|
|||||||
optionalContentConfigPromise: this._optionalContentConfigPromise,
|
optionalContentConfigPromise: this._optionalContentConfigPromise,
|
||||||
annotationCanvasMap: this._annotationCanvasMap,
|
annotationCanvasMap: this._annotationCanvasMap,
|
||||||
pageColors,
|
pageColors,
|
||||||
|
isEditing: this.#isEditing,
|
||||||
};
|
};
|
||||||
const renderTask = (this.renderTask = pdfPage.render(renderContext));
|
const renderTask = (this.renderTask = pdfPage.render(renderContext));
|
||||||
renderTask.onContinue = renderContinueCallback;
|
renderTask.onContinue = renderContinueCallback;
|
||||||
|
|||||||
@ -223,6 +223,10 @@ class PDFViewer {
|
|||||||
|
|
||||||
#mlManager = null;
|
#mlManager = null;
|
||||||
|
|
||||||
|
#onPageRenderedCallback = null;
|
||||||
|
|
||||||
|
#switchAnnotationEditorModeTimeoutId = null;
|
||||||
|
|
||||||
#getAllTextInProgress = false;
|
#getAllTextInProgress = false;
|
||||||
|
|
||||||
#hiddenCopyElement = null;
|
#hiddenCopyElement = null;
|
||||||
@ -1117,6 +1121,10 @@ class PDFViewer {
|
|||||||
|
|
||||||
this.#hiddenCopyElement?.remove();
|
this.#hiddenCopyElement?.remove();
|
||||||
this.#hiddenCopyElement = null;
|
this.#hiddenCopyElement = null;
|
||||||
|
|
||||||
|
this.#onPageRenderedCallback = null;
|
||||||
|
clearTimeout(this.#switchAnnotationEditorModeTimeoutId);
|
||||||
|
this.#switchAnnotationEditorModeTimeoutId = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ensurePageViewVisible() {
|
#ensurePageViewVisible() {
|
||||||
@ -1653,6 +1661,32 @@ class PDFViewer {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#switchToEditAnnotationMode() {
|
||||||
|
const visible = this._getVisiblePages();
|
||||||
|
const pagesToRefresh = [];
|
||||||
|
const { ids, views } = visible;
|
||||||
|
for (const page of views) {
|
||||||
|
const { view } = page;
|
||||||
|
if (!view.hasEditableAnnotations()) {
|
||||||
|
ids.delete(view.id);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
pagesToRefresh.push(page);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pagesToRefresh.length === 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
this.renderingQueue.renderHighestPriority({
|
||||||
|
first: pagesToRefresh[0],
|
||||||
|
last: pagesToRefresh.at(-1),
|
||||||
|
views: pagesToRefresh,
|
||||||
|
ids,
|
||||||
|
});
|
||||||
|
|
||||||
|
return ids;
|
||||||
|
}
|
||||||
|
|
||||||
containsElement(element) {
|
containsElement(element) {
|
||||||
return this.container.contains(element);
|
return this.container.contains(element);
|
||||||
}
|
}
|
||||||
@ -2259,13 +2293,56 @@ class PDFViewer {
|
|||||||
if (!this.pdfDocument) {
|
if (!this.pdfDocument) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.#annotationEditorMode = mode;
|
|
||||||
this.eventBus.dispatch("annotationeditormodechanged", {
|
|
||||||
source: this,
|
|
||||||
mode,
|
|
||||||
});
|
|
||||||
|
|
||||||
this.#annotationEditorUIManager.updateMode(mode, editId, isFromKeyboard);
|
const { eventBus } = this;
|
||||||
|
const updater = () => {
|
||||||
|
if (this.#onPageRenderedCallback) {
|
||||||
|
eventBus._off("pagerendered", this.#onPageRenderedCallback);
|
||||||
|
this.#onPageRenderedCallback = null;
|
||||||
|
}
|
||||||
|
if (this.#switchAnnotationEditorModeTimeoutId !== null) {
|
||||||
|
clearTimeout(this.#switchAnnotationEditorModeTimeoutId);
|
||||||
|
this.#switchAnnotationEditorModeTimeoutId = null;
|
||||||
|
}
|
||||||
|
this.#annotationEditorMode = mode;
|
||||||
|
eventBus.dispatch("annotationeditormodechanged", {
|
||||||
|
source: this,
|
||||||
|
mode,
|
||||||
|
});
|
||||||
|
this.#annotationEditorUIManager.updateMode(mode, editId, isFromKeyboard);
|
||||||
|
};
|
||||||
|
|
||||||
|
if (
|
||||||
|
mode === AnnotationEditorType.NONE ||
|
||||||
|
this.#annotationEditorMode === AnnotationEditorType.NONE
|
||||||
|
) {
|
||||||
|
const isEditing = mode !== AnnotationEditorType.NONE;
|
||||||
|
if (!isEditing) {
|
||||||
|
this.pdfDocument.annotationStorage.resetModifiedIds();
|
||||||
|
}
|
||||||
|
for (const pageView of this._pages) {
|
||||||
|
pageView.toggleEditingMode(isEditing);
|
||||||
|
}
|
||||||
|
// We must call #switchToEditAnnotationMode unconditionally to ensure that
|
||||||
|
// page is rendered if it's useful or not.
|
||||||
|
const idsToRefresh = this.#switchToEditAnnotationMode();
|
||||||
|
if (isEditing && editId && idsToRefresh) {
|
||||||
|
// We're editing an existing annotation so we must switch to editing
|
||||||
|
// mode when the rendering is done.
|
||||||
|
const { signal } = this.#eventAbortController;
|
||||||
|
this.#onPageRenderedCallback = ({ pageNumber }) => {
|
||||||
|
idsToRefresh.delete(pageNumber);
|
||||||
|
if (idsToRefresh.size === 0) {
|
||||||
|
eventBus._off("pagerendered", this.#onPageRenderedCallback);
|
||||||
|
this.#onPageRenderedCallback = null;
|
||||||
|
this.#switchAnnotationEditorModeTimeoutId = setTimeout(updater, 0);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
eventBus._on("pagerendered", this.#onPageRenderedCallback, { signal });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
updater();
|
||||||
}
|
}
|
||||||
|
|
||||||
// eslint-disable-next-line accessor-pairs
|
// eslint-disable-next-line accessor-pairs
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user