Merge pull request #15782 from calixteman/15780

[api-minor][Editor] Don't use the editor parent which can be null.
This commit is contained in:
calixteman 2022-12-08 14:27:42 +01:00 committed by GitHub
commit fe3df4dcb4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 270 additions and 126 deletions

View File

@ -17,8 +17,6 @@
// eslint-disable-next-line max-len
/** @typedef {import("./tools.js").AnnotationEditorUIManager} AnnotationEditorUIManager */
// eslint-disable-next-line max-len
/** @typedef {import("../annotation_storage.js").AnnotationStorage} AnnotationStorage */
// eslint-disable-next-line max-len
/** @typedef {import("../../web/text_accessibility.js").TextAccessibilityManager} TextAccessibilityManager */
/** @typedef {import("../../web/interfaces").IL10n} IL10n */
@ -33,7 +31,6 @@ import { InkEditor } from "./ink.js";
* @property {HTMLDivElement} div
* @property {AnnotationEditorUIManager} uiManager
* @property {boolean} enabled
* @property {AnnotationStorage} annotationStorage
* @property {TextAccessibilityManager} [accessibilityManager]
* @property {number} pageIndex
* @property {IL10n} l10n
@ -73,7 +70,6 @@ class AnnotationEditorLayer {
options.uiManager.registerEditorTypes([FreeTextEditor, InkEditor]);
this.#uiManager = options.uiManager;
this.annotationStorage = options.annotationStorage;
this.pageIndex = options.pageIndex;
this.div = options.div;
this.#accessibilityManager = options.accessibilityManager;
@ -213,7 +209,6 @@ class AnnotationEditorLayer {
this.#uiManager.removeEditor(editor);
this.detach(editor);
this.annotationStorage.remove(editor.id);
editor.div.style.display = "none";
setTimeout(() => {
// When the div is removed from DOM the focus can move on the
@ -244,7 +239,6 @@ class AnnotationEditorLayer {
}
this.attach(editor);
editor.pageIndex = this.pageIndex;
editor.parent?.detach(editor);
editor.setParent(this);
if (editor.div && editor.isAttachedToDOM) {
@ -270,7 +264,7 @@ class AnnotationEditorLayer {
this.moveEditorInDOM(editor);
editor.onceAdded();
this.addToAnnotationStorage(editor);
this.#uiManager.addToAnnotationStorage(editor);
}
moveEditorInDOM(editor) {
@ -282,16 +276,6 @@ class AnnotationEditorLayer {
);
}
/**
* Add an editor in the annotation storage.
* @param {AnnotationEditor} editor
*/
addToAnnotationStorage(editor) {
if (!editor.isEmpty() && !this.annotationStorage.has(editor.id)) {
this.annotationStorage.setValue(editor.id, editor);
}
}
/**
* Add or rebuild depending if it has been removed or not.
* @param {AnnotationEditor} editor
@ -365,9 +349,9 @@ class AnnotationEditorLayer {
deserialize(data) {
switch (data.annotationType) {
case AnnotationEditorType.FREETEXT:
return FreeTextEditor.deserialize(data, this);
return FreeTextEditor.deserialize(data, this, this.#uiManager);
case AnnotationEditorType.INK:
return InkEditor.deserialize(data, this);
return InkEditor.deserialize(data, this, this.#uiManager);
}
return null;
}
@ -384,6 +368,7 @@ class AnnotationEditorLayer {
id,
x: event.offsetX,
y: event.offsetY,
uiManager: this.#uiManager,
});
if (editor) {
this.add(editor);
@ -520,8 +505,8 @@ class AnnotationEditorLayer {
for (const editor of this.#editors.values()) {
this.#accessibilityManager?.removePointerInTextLayer(editor.contentDiv);
editor.isAttachedToDOM = false;
editor.setParent(null);
editor.isAttachedToDOM = false;
editor.div.remove();
}
this.div = null;
@ -571,14 +556,6 @@ class AnnotationEditorLayer {
this.updateMode();
}
/**
* Get the scale factor from the viewport.
* @returns {number}
*/
get scaleFactor() {
return this.viewport.scale;
}
/**
* Get page dimensions.
* @returns {Object} dimensions.
@ -591,11 +568,6 @@ class AnnotationEditorLayer {
return [width, height];
}
get viewportBaseDimensions() {
const { width, height, rotation } = this.viewport;
return rotation % 180 === 0 ? [width, height] : [height, width];
}
/**
* Set the dimensions of the main div.
*/

View File

@ -15,12 +15,15 @@
// eslint-disable-next-line max-len
/** @typedef {import("./annotation_editor_layer.js").AnnotationEditorLayer} AnnotationEditorLayer */
// eslint-disable-next-line max-len
/** @typedef {import("./tools.js").AnnotationEditorUIManager} AnnotationEditorUIManager */
import { bindEvents, ColorManager } from "./tools.js";
import { FeatureTest, shadow, unreachable } from "../../shared/util.js";
/**
* @typedef {Object} AnnotationEditorParameters
* @property {AnnotationEditorUIManager} uiManager - the global manager
* @property {AnnotationEditorLayer} parent - the layer containing this editor
* @property {string} id - editor id
* @property {number} x - x-coordinate
@ -41,6 +44,8 @@ class AnnotationEditor {
#isInEditMode = false;
_uiManager = null;
#zIndex = AnnotationEditor._zIndex++;
static _colorManager = new ColorManager();
@ -61,15 +66,15 @@ class AnnotationEditor {
this.pageIndex = parameters.parent.pageIndex;
this.name = parameters.name;
this.div = null;
this._uiManager = parameters.uiManager;
const [width, height] = this.parent.viewportBaseDimensions;
this.rotation = this.parent.viewport.rotation;
this.pageDimensions = this.parent.pageDimensions;
const [width, height] = this.parentDimensions;
this.x = parameters.x / width;
this.y = parameters.y / height;
this.rotation = this.parent.viewport.rotation;
this.isAttachedToDOM = false;
this._serialized = undefined;
}
static get _defaultLineColor() {
@ -80,9 +85,16 @@ class AnnotationEditor {
);
}
setParent(parent) {
this._serialized = !parent ? this.serialize() : undefined;
this.parent = parent;
/**
* Add some commands into the CommandManager (undo/redo stuff).
* @param {Object} params
*/
addCommands(params) {
this._uiManager.addCommands(params);
}
get currentLayer() {
return this._uiManager.currentLayer;
}
/**
@ -99,6 +111,14 @@ class AnnotationEditor {
this.div.style.zIndex = this.#zIndex;
}
setParent(parent) {
if (parent !== null) {
this.pageIndex = parent.pageIndex;
this.pageDimensions = parent.pageDimensions;
}
this.parent = parent;
}
/**
* onfocus callback.
*/
@ -130,7 +150,7 @@ class AnnotationEditor {
event.preventDefault();
if (!this.parent.isMultipleSelection) {
if (!this.parent?.isMultipleSelection) {
this.commitOrRemove();
}
}
@ -147,7 +167,11 @@ class AnnotationEditor {
* Commit the data contained in this editor.
*/
commit() {
this.parent.addToAnnotationStorage(this);
this.addToAnnotationStorage();
}
addToAnnotationStorage() {
this._uiManager.addToAnnotationStorage(this);
}
/**
@ -170,7 +194,7 @@ class AnnotationEditor {
* @param {number} ty - y-translation in screen coordinates.
*/
setAt(x, y, tx, ty) {
const [width, height] = this.parent.viewportBaseDimensions;
const [width, height] = this.parentDimensions;
[tx, ty] = this.screenToPageTranslation(tx, ty);
this.x = (x + tx) / width;
@ -186,7 +210,7 @@ class AnnotationEditor {
* @param {number} y - y-translation in screen coordinates.
*/
translate(x, y) {
const [width, height] = this.parent.viewportBaseDimensions;
const [width, height] = this.parentDimensions;
[x, y] = this.screenToPageTranslation(x, y);
this.x += x / width;
@ -202,8 +226,7 @@ class AnnotationEditor {
* @param {number} y
*/
screenToPageTranslation(x, y) {
const { rotation } = this.parent.viewport;
switch (rotation) {
switch (this.parentRotation) {
case 90:
return [y, -x];
case 180:
@ -215,13 +238,27 @@ class AnnotationEditor {
}
}
get parentScale() {
return this._uiManager.viewParameters.realScale;
}
get parentRotation() {
return this._uiManager.viewParameters.rotation;
}
get parentDimensions() {
const { realScale } = this._uiManager.viewParameters;
const [pageWidth, pageHeight] = this.pageDimensions;
return [pageWidth * realScale, pageHeight * realScale];
}
/**
* Set the dimensions of this editor.
* @param {number} width
* @param {number} height
*/
setDims(width, height) {
const [parentWidth, parentHeight] = this.parent.viewportBaseDimensions;
const [parentWidth, parentHeight] = this.parentDimensions;
this.div.style.width = `${(100 * width) / parentWidth}%`;
this.div.style.height = `${(100 * height) / parentHeight}%`;
}
@ -235,7 +272,7 @@ class AnnotationEditor {
return;
}
const [parentWidth, parentHeight] = this.parent.viewportBaseDimensions;
const [parentWidth, parentHeight] = this.parentDimensions;
if (!widthPercent) {
style.width = `${(100 * parseFloat(width)) / parentWidth}%`;
}
@ -302,10 +339,10 @@ class AnnotationEditor {
}
getRect(tx, ty) {
const [parentWidth, parentHeight] = this.parent.viewportBaseDimensions;
const [pageWidth, pageHeight] = this.parent.pageDimensions;
const shiftX = (pageWidth * tx) / parentWidth;
const shiftY = (pageHeight * ty) / parentHeight;
const scale = this.parentScale;
const [pageWidth, pageHeight] = this.pageDimensions;
const shiftX = tx / scale;
const shiftY = ty / scale;
const x = this.x * pageWidth;
const y = this.y * pageHeight;
const width = this.width * pageWidth;
@ -443,16 +480,18 @@ class AnnotationEditor {
*
* @param {Object} data
* @param {AnnotationEditorLayer} parent
* @param {AnnotationEditorUIManager} uiManager
* @returns {AnnotationEditor}
*/
static deserialize(data, parent) {
static deserialize(data, parent, uiManager) {
const editor = new this.prototype.constructor({
parent,
id: parent.getNextId(),
uiManager,
});
editor.rotation = data.rotation;
const [pageWidth, pageHeight] = parent.pageDimensions;
const [pageWidth, pageHeight] = editor.pageDimensions;
const [x, y, width, height] = editor.getRectInCurrentCoords(
data.rect,
pageHeight

View File

@ -153,12 +153,12 @@ class FreeTextEditor extends AnnotationEditor {
#updateFontSize(fontSize) {
const setFontsize = size => {
this.editorDiv.style.fontSize = `calc(${size}px * var(--scale-factor))`;
this.translate(0, -(size - this.#fontSize) * this.parent.scaleFactor);
this.translate(0, -(size - this.#fontSize) * this.parentScale);
this.#fontSize = size;
this.#setEditorDimensions();
};
const savedFontsize = this.#fontSize;
this.parent.addCommands({
this.addCommands({
cmd: () => {
setFontsize(fontSize);
},
@ -178,14 +178,12 @@ class FreeTextEditor extends AnnotationEditor {
*/
#updateColor(color) {
const savedColor = this.#color;
this.parent.addCommands({
this.addCommands({
cmd: () => {
this.#color = color;
this.editorDiv.style.color = color;
this.#color = this.editorDiv.style.color = color;
},
undo: () => {
this.#color = savedColor;
this.editorDiv.style.color = savedColor;
this.#color = this.editorDiv.style.color = savedColor;
},
mustExec: true,
type: AnnotationEditorParamsType.FREETEXT_COLOR,
@ -197,10 +195,10 @@ class FreeTextEditor extends AnnotationEditor {
/** @inheritdoc */
getInitialTranslation() {
// The start of the base line is where the user clicked.
const scale = this.parentScale;
return [
-FreeTextEditor._internalPadding * this.parent.scaleFactor,
-(FreeTextEditor._internalPadding + this.#fontSize) *
this.parent.scaleFactor,
-FreeTextEditor._internalPadding * scale,
-(FreeTextEditor._internalPadding + this.#fontSize) * scale,
];
}
@ -254,9 +252,11 @@ class FreeTextEditor extends AnnotationEditor {
this.editorDiv.removeEventListener("blur", this.#boundEditorDivBlur);
this.editorDiv.removeEventListener("input", this.#boundEditorDivInput);
// On Chrome, the focus is given to <body> when contentEditable is set to
// false, hence we focus the div.
this.div.focus();
if (this.pageIndex === this._uiManager.currentPageIndex) {
// On Chrome, the focus is given to <body> when contentEditable is set to
// false, hence we focus the div.
this.div.focus();
}
// In case the blur callback hasn't been called.
this.isEditing = false;
@ -311,8 +311,22 @@ class FreeTextEditor extends AnnotationEditor {
}
#setEditorDimensions() {
const [parentWidth, parentHeight] = this.parent.viewportBaseDimensions;
const rect = this.div.getBoundingClientRect();
const [parentWidth, parentHeight] = this.parentDimensions;
let rect;
if (this.isAttachedToDOM) {
rect = this.div.getBoundingClientRect();
} else {
// This editor isn't on screen but we need to get its dimensions, so
// we just insert it in the DOM, get its bounding box and then remove it.
const { currentLayer, div } = this;
const savedDisplay = div.style.display;
div.style.display = "hidden";
currentLayer.div.append(this.div);
rect = div.getBoundingClientRect();
div.remove();
div.style.display = savedDisplay;
}
this.width = rect.width / parentWidth;
this.height = rect.height / parentHeight;
@ -323,6 +337,10 @@ class FreeTextEditor extends AnnotationEditor {
* @returns {undefined}
*/
commit() {
if (!this.isInEditMode()) {
return;
}
super.commit();
if (!this.#hasAlreadyBeenCommitted) {
// This editor has something and it's the first time
@ -435,7 +453,7 @@ class FreeTextEditor extends AnnotationEditor {
if (this.width) {
// This editor was created in using copy (ctrl+c).
const [parentWidth, parentHeight] = this.parent.viewportBaseDimensions;
const [parentWidth, parentHeight] = this.parentDimensions;
this.setAt(
baseX * parentWidth,
baseY * parentHeight,
@ -466,8 +484,8 @@ class FreeTextEditor extends AnnotationEditor {
}
/** @inheritdoc */
static deserialize(data, parent) {
const editor = super.deserialize(data, parent);
static deserialize(data, parent, uiManager) {
const editor = super.deserialize(data, parent, uiManager);
editor.#fontSize = data.fontSize;
editor.#color = Util.makeHexColor(...data.color);
@ -478,19 +496,17 @@ class FreeTextEditor extends AnnotationEditor {
/** @inheritdoc */
serialize() {
if (this._serialized !== undefined) {
return this._serialized;
}
if (this.isEmpty()) {
return null;
}
const padding = FreeTextEditor._internalPadding * this.parent.scaleFactor;
const padding = FreeTextEditor._internalPadding * this.parentScale;
const rect = this.getRect(padding, padding);
const color = AnnotationEditor._colorManager.convert(
getComputedStyle(this.editorDiv).color
this.isAttachedToDOM
? getComputedStyle(this.editorDiv).color
: this.#color
);
return {
@ -498,7 +514,7 @@ class FreeTextEditor extends AnnotationEditor {
color,
fontSize: this.#fontSize,
value: this.#content,
pageIndex: this.parent.pageIndex,
pageIndex: this.pageIndex,
rect,
rotation: this.rotation,
};

View File

@ -165,7 +165,7 @@ class InkEditor extends AnnotationEditor {
*/
#updateThickness(thickness) {
const savedThickness = this.thickness;
this.parent.addCommands({
this.addCommands({
cmd: () => {
this.thickness = thickness;
this.#fitToContent();
@ -187,7 +187,7 @@ class InkEditor extends AnnotationEditor {
*/
#updateColor(color) {
const savedColor = this.color;
this.parent.addCommands({
this.addCommands({
cmd: () => {
this.color = color;
this.#redraw();
@ -210,7 +210,7 @@ class InkEditor extends AnnotationEditor {
#updateOpacity(opacity) {
opacity /= 100;
const savedOpacity = this.opacity;
this.parent.addCommands({
this.addCommands({
cmd: () => {
this.opacity = opacity;
this.#redraw();
@ -268,6 +268,27 @@ class InkEditor extends AnnotationEditor {
super.remove();
}
setParent(parent) {
if (!this.parent && parent) {
// We've a parent hence the rescale will be handled thanks to the
// ResizeObserver.
this._uiManager.removeShouldRescale(this);
} else if (this.parent && parent === null) {
// The editor is removed from the DOM, hence we handle the rescale thanks
// to the onScaleChanging callback.
// This way, it'll be saved/printed correctly.
this._uiManager.addShouldRescale(this);
}
super.setParent(parent);
}
onScaleChanging() {
const [parentWidth, parentHeight] = this.parentDimensions;
const width = this.width * parentWidth;
const height = this.height * parentHeight;
this.setDimensions(width, height);
}
/** @inheritdoc */
enableEditMode() {
if (this.#disableEditing || this.canvas === null) {
@ -311,14 +332,17 @@ class InkEditor extends AnnotationEditor {
}
#getInitialBBox() {
const { width, height, rotation } = this.parent.viewport;
switch (rotation) {
const {
parentRotation,
parentDimensions: [width, height],
} = this;
switch (parentRotation) {
case 90:
return [0, width, width, height];
return [0, height, height, width];
case 180:
return [width, height, width, height];
case 270:
return [height, 0, width, height];
return [width, 0, height, width];
default:
return [0, 0, width, height];
}
@ -328,12 +352,12 @@ class InkEditor extends AnnotationEditor {
* Set line styles.
*/
#setStroke() {
this.ctx.lineWidth =
(this.thickness * this.parent.scaleFactor) / this.scaleFactor;
this.ctx.lineCap = "round";
this.ctx.lineJoin = "round";
this.ctx.miterLimit = 10;
this.ctx.strokeStyle = `${this.color}${opacityToHex(this.opacity)}`;
const { ctx, color, opacity, thickness, parentScale, scaleFactor } = this;
ctx.lineWidth = (thickness * parentScale) / scaleFactor;
ctx.lineCap = "round";
ctx.lineJoin = "round";
ctx.miterLimit = 10;
ctx.strokeStyle = `${color}${opacityToHex(opacity)}`;
}
/**
@ -445,7 +469,7 @@ class InkEditor extends AnnotationEditor {
}
};
this.parent.addCommands({ cmd, undo, mustExec: true });
this.addCommands({ cmd, undo, mustExec: true });
}
/**
@ -493,9 +517,11 @@ class InkEditor extends AnnotationEditor {
// When commiting, the position of this editor is changed, hence we must
// move it to the right position in the DOM.
this.parent.moveEditorInDOM(this);
// After the div has been moved in the DOM, the focus may have been stolen
// by document.body, hence we just keep it here.
this.div.focus();
if (this.pageIndex === this._uiManager.currentPageIndex) {
// After the div has been moved in the DOM, the focus may have been stolen
// by document.body, hence we just keep it here.
this.div.focus();
}
}
/** @inheritdoc */
@ -581,7 +607,7 @@ class InkEditor extends AnnotationEditor {
this.#boundCanvasPointermove
);
this.parent.addToAnnotationStorage(this);
this.addToAnnotationStorage();
}
/**
@ -649,7 +675,7 @@ class InkEditor extends AnnotationEditor {
if (this.width) {
// This editor was created in using copy (ctrl+c).
const [parentWidth, parentHeight] = this.parent.viewportBaseDimensions;
const [parentWidth, parentHeight] = this.parentDimensions;
this.setAt(
baseX * parentWidth,
baseY * parentHeight,
@ -676,7 +702,7 @@ class InkEditor extends AnnotationEditor {
if (!this.#isCanvasInitialized) {
return;
}
const [parentWidth, parentHeight] = this.parent.viewportBaseDimensions;
const [parentWidth, parentHeight] = this.parentDimensions;
this.canvas.width = Math.ceil(this.width * parentWidth);
this.canvas.height = Math.ceil(this.height * parentHeight);
this.#updateTransform();
@ -712,7 +738,7 @@ class InkEditor extends AnnotationEditor {
this.setDims(width, height);
}
const [parentWidth, parentHeight] = this.parent.viewportBaseDimensions;
const [parentWidth, parentHeight] = this.parentDimensions;
this.width = width / parentWidth;
this.height = height / parentHeight;
@ -940,7 +966,7 @@ class InkEditor extends AnnotationEditor {
*/
#getPadding() {
return this.#disableEditing
? Math.ceil(this.thickness * this.parent.scaleFactor)
? Math.ceil(this.thickness * this.parentScale)
: 0;
}
@ -967,7 +993,7 @@ class InkEditor extends AnnotationEditor {
const width = Math.ceil(padding + this.#baseWidth * this.scaleFactor);
const height = Math.ceil(padding + this.#baseHeight * this.scaleFactor);
const [parentWidth, parentHeight] = this.parent.viewportBaseDimensions;
const [parentWidth, parentHeight] = this.parentDimensions;
this.width = width / parentWidth;
this.height = height / parentHeight;
@ -1005,17 +1031,17 @@ class InkEditor extends AnnotationEditor {
}
/** @inheritdoc */
static deserialize(data, parent) {
const editor = super.deserialize(data, parent);
static deserialize(data, parent, uiManager) {
const editor = super.deserialize(data, parent, uiManager);
editor.thickness = data.thickness;
editor.color = Util.makeHexColor(...data.color);
editor.opacity = data.opacity;
const [pageWidth, pageHeight] = parent.pageDimensions;
const [pageWidth, pageHeight] = editor.pageDimensions;
const width = editor.width * pageWidth;
const height = editor.height * pageHeight;
const scaleFactor = parent.scaleFactor;
const scaleFactor = editor.parentScale;
const padding = data.thickness / 2;
editor.#aspectRatio = width / height;
@ -1058,10 +1084,6 @@ class InkEditor extends AnnotationEditor {
/** @inheritdoc */
serialize() {
if (this._serialized !== undefined) {
return this._serialized;
}
if (this.isEmpty()) {
return null;
}
@ -1078,12 +1100,12 @@ class InkEditor extends AnnotationEditor {
thickness: this.thickness,
opacity: this.opacity,
paths: this.#serializePaths(
this.scaleFactor / this.parent.scaleFactor,
this.scaleFactor / this.parentScale,
this.translationX,
this.translationY,
height
),
pageIndex: this.parent.pageIndex,
pageIndex: this.pageIndex,
rect,
rotation: this.rotation,
};

View File

@ -25,7 +25,7 @@ import {
Util,
warn,
} from "../../shared/util.js";
import { getColorValues, getRGB } from "../display_utils.js";
import { getColorValues, getRGB, PixelsPerInch } from "../display_utils.js";
function bindEvents(obj, element, names) {
for (const name of names) {
@ -350,12 +350,16 @@ class AnnotationEditorUIManager {
#allLayers = new Map();
#annotationStorage = null;
#commandManager = new CommandManager();
#currentPageIndex = 0;
#editorTypes = null;
#editorsToRescale = new Set();
#eventBus = null;
#idManager = new IdManager();
@ -378,6 +382,10 @@ class AnnotationEditorUIManager {
#boundOnPageChanging = this.onPageChanging.bind(this);
#boundOnScaleChanging = this.onScaleChanging.bind(this);
#boundOnRotationChanging = this.onRotationChanging.bind(this);
#previousStates = {
isEditing: false,
isEmpty: true,
@ -413,22 +421,32 @@ class AnnotationEditorUIManager {
[["Escape", "mac+Escape"], AnnotationEditorUIManager.prototype.unselectAll],
]);
constructor(container, eventBus) {
constructor(container, eventBus, annotationStorage) {
this.#container = container;
this.#eventBus = eventBus;
this.#eventBus._on("editingaction", this.#boundOnEditingAction);
this.#eventBus._on("pagechanging", this.#boundOnPageChanging);
this.#eventBus._on("scalechanging", this.#boundOnScaleChanging);
this.#eventBus._on("rotationchanging", this.#boundOnRotationChanging);
this.#annotationStorage = annotationStorage;
this.viewParameters = {
realScale: PixelsPerInch.PDF_TO_CSS_UNITS,
rotation: 0,
};
}
destroy() {
this.#removeKeyboardManager();
this.#eventBus._off("editingaction", this.#boundOnEditingAction);
this.#eventBus._off("pagechanging", this.#boundOnPageChanging);
this.#eventBus._off("scalechanging", this.#boundOnScaleChanging);
this.#eventBus._off("rotationchanging", this.#boundOnRotationChanging);
for (const layer of this.#allLayers.values()) {
layer.destroy();
}
this.#allLayers.clear();
this.#allEditors.clear();
this.#editorsToRescale.clear();
this.#activeEditor = null;
this.#selectedEditors.clear();
this.#commandManager.destroy();
@ -442,6 +460,41 @@ class AnnotationEditorUIManager {
this.#container.focus();
}
addShouldRescale(editor) {
this.#editorsToRescale.add(editor);
}
removeShouldRescale(editor) {
this.#editorsToRescale.delete(editor);
}
onScaleChanging({ scale }) {
this.commitOrRemove();
this.viewParameters.realScale = scale * PixelsPerInch.PDF_TO_CSS_UNITS;
for (const editor of this.#editorsToRescale) {
editor.onScaleChanging();
}
}
onRotationChanging({ pagesRotation }) {
this.commitOrRemove();
this.viewParameters.rotation = pagesRotation;
}
/**
* Add an editor in the annotation storage.
* @param {AnnotationEditor} editor
*/
addToAnnotationStorage(editor) {
if (
!editor.isEmpty() &&
this.#annotationStorage &&
!this.#annotationStorage.has(editor.id)
) {
this.#annotationStorage.setValue(editor.id, editor);
}
}
#addKeyboardManager() {
// The keyboard events are caught at the container level in order to be able
// to execute some callbacks even if the current page doesn't have focus.
@ -646,6 +699,14 @@ class AnnotationEditorUIManager {
return this.#idManager.getId();
}
get currentLayer() {
return this.#allLayers.get(this.#currentPageIndex);
}
get currentPageIndex() {
return this.#currentPageIndex;
}
/**
* Add a new layer for a page which will contains the editors.
* @param {AnnotationEditorLayer} layer
@ -783,6 +844,7 @@ class AnnotationEditorUIManager {
removeEditor(editor) {
this.#allEditors.delete(editor.id);
this.unselect(editor);
this.#annotationStorage?.remove(editor.id);
}
/**

View File

@ -599,6 +599,49 @@ describe("Editor", () => {
[0, 0, 0],
[0, 0, 0],
]);
// Increase the font size for all the annotations.
// Select all.
await page.keyboard.down("Control");
await page.keyboard.press("a");
await page.keyboard.up("Control");
await page.waitForTimeout(10);
page.evaluate(() => {
window.PDFViewerApplication.eventBus.dispatch(
"switchannotationeditorparams",
{
source: null,
type: /* AnnotationEditorParamsType.FREETEXT_SIZE */ 1,
value: 13,
}
);
});
await page.waitForTimeout(10);
expect(await serialize("fontSize"))
.withContext(`In ${browserName}`)
.toEqual([13, 13]);
// Change the colors for all the annotations.
page.evaluate(() => {
window.PDFViewerApplication.eventBus.dispatch(
"switchannotationeditorparams",
{
source: null,
type: /* AnnotationEditorParamsType.FREETEXT_COLOR */ 2,
value: "#FF0000",
}
);
});
await page.waitForTimeout(10);
expect(await serialize("color"))
.withContext(`In ${browserName}`)
.toEqual([
[255, 0, 0],
[255, 0, 0],
]);
})
);
});

View File

@ -111,9 +111,7 @@ class DefaultAnnotationEditorLayerFactory {
* @property {HTMLDivElement} pageDiv
* @property {PDFPageProxy} pdfPage
* @property {IL10n} l10n
* @property {AnnotationStorage} [annotationStorage] - Storage for annotation
* @property {TextAccessibilityManager} [accessibilityManager]
* data in forms.
*/
/**
@ -126,7 +124,6 @@ class DefaultAnnotationEditorLayerFactory {
pdfPage,
accessibilityManager = null,
l10n,
annotationStorage = null,
}) {
return new AnnotationEditorLayerBuilder({
uiManager,
@ -134,7 +131,6 @@ class DefaultAnnotationEditorLayerFactory {
pdfPage,
accessibilityManager,
l10n,
annotationStorage,
});
}
}

View File

@ -237,9 +237,7 @@ class IPDFAnnotationEditorLayerFactory {
* @property {HTMLDivElement} pageDiv
* @property {PDFPageProxy} pdfPage
* @property {IL10n} l10n
* @property {AnnotationStorage} [annotationStorage] - Storage for annotation
* @property {TextAccessibilityManager} [accessibilityManager]
* data in forms.
*/
/**
@ -251,7 +249,6 @@ class IPDFAnnotationEditorLayerFactory {
pageDiv,
pdfPage,
l10n,
annotationStorage = null,
accessibilityManager,
}) {}
}

View File

@ -730,7 +730,8 @@ class PDFViewer {
} else if (isValidAnnotationEditorMode(mode)) {
this.#annotationEditorUIManager = new AnnotationEditorUIManager(
this.container,
this.eventBus
this.eventBus,
this.pdfDocument?.annotationStorage
);
if (mode !== AnnotationEditorType.NONE) {
this.#annotationEditorUIManager.updateMode(mode);
@ -1741,9 +1742,7 @@ class PDFViewer {
* @property {HTMLDivElement} pageDiv
* @property {PDFPageProxy} pdfPage
* @property {IL10n} l10n
* @property {AnnotationStorage} [annotationStorage] - Storage for annotation
* @property {TextAccessibilityManager} [accessibilityManager]
* data in forms.
*/
/**
@ -1756,13 +1755,11 @@ class PDFViewer {
pdfPage,
accessibilityManager = null,
l10n,
annotationStorage = this.pdfDocument?.annotationStorage,
}) {
return new AnnotationEditorLayerBuilder({
uiManager,
pageDiv,
pdfPage,
annotationStorage,
accessibilityManager,
l10n,
});