Merge pull request #15163 from calixteman/prepare_touch
[Editor] Always have an ink editor (when in ink mode)
This commit is contained in:
commit
1301b71b7c
@ -146,7 +146,11 @@ class AnnotationStorage {
|
||||
const clone = new Map();
|
||||
|
||||
for (const [key, val] of this._storage) {
|
||||
clone.set(key, val instanceof AnnotationEditor ? val.serialize() : val);
|
||||
const serialized =
|
||||
val instanceof AnnotationEditor ? val.serialize() : val;
|
||||
if (serialized) {
|
||||
clone.set(key, serialized);
|
||||
}
|
||||
}
|
||||
return clone;
|
||||
}
|
||||
|
@ -42,10 +42,10 @@ import { InkEditor } from "./ink.js";
|
||||
class AnnotationEditorLayer {
|
||||
#boundClick;
|
||||
|
||||
#boundMouseover;
|
||||
|
||||
#editors = new Map();
|
||||
|
||||
#isCleaningUp = false;
|
||||
|
||||
#uiManager;
|
||||
|
||||
static _initialized = false;
|
||||
@ -92,7 +92,6 @@ class AnnotationEditorLayer {
|
||||
this.pageIndex = options.pageIndex;
|
||||
this.div = options.div;
|
||||
this.#boundClick = this.click.bind(this);
|
||||
this.#boundMouseover = this.mouseover.bind(this);
|
||||
|
||||
for (const editor of this.#uiManager.getEditors(options.pageIndex)) {
|
||||
this.add(editor);
|
||||
@ -114,24 +113,36 @@ class AnnotationEditorLayer {
|
||||
* The mode has changed: it must be updated.
|
||||
* @param {number} mode
|
||||
*/
|
||||
updateMode(mode) {
|
||||
switch (mode) {
|
||||
case AnnotationEditorType.INK:
|
||||
// We want to have the ink editor covering all of the page without
|
||||
// having to click to create it: it must be here when we start to draw.
|
||||
this.div.addEventListener("mouseover", this.#boundMouseover);
|
||||
this.div.removeEventListener("click", this.#boundClick);
|
||||
break;
|
||||
case AnnotationEditorType.FREETEXT:
|
||||
this.div.removeEventListener("mouseover", this.#boundMouseover);
|
||||
this.div.addEventListener("click", this.#boundClick);
|
||||
break;
|
||||
default:
|
||||
this.div.removeEventListener("mouseover", this.#boundMouseover);
|
||||
this.div.removeEventListener("click", this.#boundClick);
|
||||
updateMode(mode = this.#uiManager.getMode()) {
|
||||
this.#cleanup();
|
||||
if (mode === AnnotationEditorType.INK) {
|
||||
// We always want to an ink editor ready to draw in.
|
||||
this.addInkEditorIfNeeded(false);
|
||||
}
|
||||
this.setActiveEditor(null);
|
||||
}
|
||||
|
||||
addInkEditorIfNeeded(isCommitting) {
|
||||
if (
|
||||
!isCommitting &&
|
||||
this.#uiManager.getMode() !== AnnotationEditorType.INK
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.setActiveEditor(null);
|
||||
if (!isCommitting) {
|
||||
// We're removing an editor but an empty one can already exist so in this
|
||||
// case we don't need to create a new one.
|
||||
for (const editor of this.#editors.values()) {
|
||||
if (editor.isEmpty()) {
|
||||
editor.setInBackground();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const editor = this.#createAndAddNewEditor({ offsetX: 0, offsetY: 0 });
|
||||
editor.setInBackground();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -142,25 +153,6 @@ class AnnotationEditorLayer {
|
||||
this.#uiManager.setEditingState(isEditing);
|
||||
}
|
||||
|
||||
/**
|
||||
* Mouseover callback.
|
||||
* @param {MouseEvent} event
|
||||
*/
|
||||
mouseover(event) {
|
||||
if (
|
||||
event.target === this.div &&
|
||||
event.buttons === 0 &&
|
||||
!this.#uiManager.hasActive()
|
||||
) {
|
||||
// The div is the target so there is no ink editor, hence we can
|
||||
// create a new one.
|
||||
// event.buttons === 0 is here to avoid adding a new ink editor
|
||||
// when we drop an editor.
|
||||
const editor = this.#createAndAddNewEditor(event);
|
||||
editor.setInBackground();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add some commands into the CommandManager (undo/redo stuff).
|
||||
* @param {Object} params
|
||||
@ -258,14 +250,12 @@ class AnnotationEditorLayer {
|
||||
currentActive.commitOrRemove();
|
||||
}
|
||||
|
||||
this.#uiManager.allowClick =
|
||||
this.#uiManager.getMode() === AnnotationEditorType.INK;
|
||||
if (editor) {
|
||||
this.unselectAll();
|
||||
this.div.removeEventListener("click", this.#boundClick);
|
||||
} else {
|
||||
// When in Ink mode, setting the editor to null allows the
|
||||
// user to have to make one click in order to start drawing.
|
||||
this.#uiManager.allowClick =
|
||||
this.#uiManager.getMode() === AnnotationEditorType.INK;
|
||||
this.div.addEventListener("click", this.#boundClick);
|
||||
}
|
||||
}
|
||||
@ -295,6 +285,10 @@ class AnnotationEditorLayer {
|
||||
this.setActiveEditor(null);
|
||||
this.#uiManager.allowClick = true;
|
||||
}
|
||||
|
||||
if (!this.#isCleaningUp) {
|
||||
this.addInkEditorIfNeeded(/* isCommitting = */ false);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -496,6 +490,19 @@ class AnnotationEditorLayer {
|
||||
this.#uiManager.removeLayer(this);
|
||||
}
|
||||
|
||||
#cleanup() {
|
||||
// When we're cleaning up, some editors are removed but we don't want
|
||||
// to add a new one which will induce an addition in this.#editors, hence
|
||||
// an infinite loop.
|
||||
this.#isCleaningUp = true;
|
||||
for (const editor of this.#editors.values()) {
|
||||
if (editor.isEmpty()) {
|
||||
editor.remove();
|
||||
}
|
||||
}
|
||||
this.#isCleaningUp = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the main editor.
|
||||
* @param {Object} parameters
|
||||
@ -505,6 +512,7 @@ class AnnotationEditorLayer {
|
||||
bindEvents(this, this.div, ["dragover", "drop", "keydown"]);
|
||||
this.div.addEventListener("click", this.#boundClick);
|
||||
this.setDimensions();
|
||||
this.updateMode();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -515,6 +523,7 @@ class AnnotationEditorLayer {
|
||||
this.setActiveEditor(null);
|
||||
this.viewport = parameters.viewport;
|
||||
this.setDimensions();
|
||||
this.updateMode();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -16,8 +16,12 @@
|
||||
// eslint-disable-next-line max-len
|
||||
/** @typedef {import("./annotation_editor_layer.js").AnnotationEditorLayer} AnnotationEditorLayer */
|
||||
|
||||
import {
|
||||
AnnotationEditorPrefix,
|
||||
shadow,
|
||||
unreachable,
|
||||
} from "../../shared/util.js";
|
||||
import { bindEvents, ColorManager } from "./tools.js";
|
||||
import { shadow, unreachable } from "../../shared/util.js";
|
||||
|
||||
/**
|
||||
* @typedef {Object} AnnotationEditorParameters
|
||||
@ -109,7 +113,10 @@ class AnnotationEditor {
|
||||
event.preventDefault();
|
||||
|
||||
this.commitOrRemove();
|
||||
this.parent.setActiveEditor(null);
|
||||
|
||||
if (!target?.id?.startsWith(AnnotationEditorPrefix)) {
|
||||
this.parent.setActiveEditor(null);
|
||||
}
|
||||
}
|
||||
|
||||
commitOrRemove() {
|
||||
|
@ -372,6 +372,10 @@ class FreeTextEditor extends AnnotationEditor {
|
||||
|
||||
/** @inheritdoc */
|
||||
serialize() {
|
||||
if (this.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const padding = FreeTextEditor._internalPadding * this.parent.scaleFactor;
|
||||
const rect = this.getRect(padding, padding);
|
||||
|
||||
|
@ -46,6 +46,8 @@ class InkEditor extends AnnotationEditor {
|
||||
|
||||
#disableEditing = false;
|
||||
|
||||
#isCanvasInitialized = false;
|
||||
|
||||
#observer = null;
|
||||
|
||||
#realWidth = 0;
|
||||
@ -58,11 +60,8 @@ class InkEditor extends AnnotationEditor {
|
||||
|
||||
constructor(params) {
|
||||
super({ ...params, name: "inkEditor" });
|
||||
this.color =
|
||||
params.color ||
|
||||
InkEditor._defaultColor ||
|
||||
AnnotationEditor._defaultLineColor;
|
||||
this.thickness = params.thickness || InkEditor._defaultThickness;
|
||||
this.color = params.color || null;
|
||||
this.thickness = params.thickness || null;
|
||||
this.paths = [];
|
||||
this.bezierPath2D = [];
|
||||
this.currentPath = [];
|
||||
@ -260,7 +259,6 @@ class InkEditor extends AnnotationEditor {
|
||||
/** @inheritdoc */
|
||||
onceAdded() {
|
||||
this.div.draggable = !this.isEmpty();
|
||||
this.div.focus();
|
||||
}
|
||||
|
||||
/** @inheritdoc */
|
||||
@ -303,6 +301,13 @@ class InkEditor extends AnnotationEditor {
|
||||
* @param {number} y
|
||||
*/
|
||||
#startDrawing(x, y) {
|
||||
if (!this.#isCanvasInitialized) {
|
||||
this.#isCanvasInitialized = true;
|
||||
this.#setCanvasDims();
|
||||
this.thickness ||= InkEditor._defaultThickness;
|
||||
this.color ||=
|
||||
InkEditor._defaultColor || AnnotationEditor._defaultLineColor;
|
||||
}
|
||||
this.currentPath.push([x, y]);
|
||||
this.#setStroke();
|
||||
this.ctx.beginPath();
|
||||
@ -411,6 +416,8 @@ class InkEditor extends AnnotationEditor {
|
||||
this.div.classList.add("disabled");
|
||||
|
||||
this.#fitToContent();
|
||||
|
||||
this.parent.addInkEditorIfNeeded(/* isCommitting = */ true);
|
||||
}
|
||||
|
||||
/** @inheritdoc */
|
||||
@ -496,6 +503,7 @@ class InkEditor extends AnnotationEditor {
|
||||
*/
|
||||
#createCanvas() {
|
||||
this.canvas = document.createElement("canvas");
|
||||
this.canvas.width = this.canvas.height = 0;
|
||||
this.canvas.className = "inkEditorCanvas";
|
||||
this.div.append(this.canvas);
|
||||
this.ctx = this.canvas.getContext("2d");
|
||||
@ -527,7 +535,6 @@ class InkEditor extends AnnotationEditor {
|
||||
}
|
||||
|
||||
super.render();
|
||||
this.div.classList.add("editing");
|
||||
const [x, y, w, h] = this.#getInitialBBox();
|
||||
this.setAt(x, y, 0, 0);
|
||||
this.setDims(w, h);
|
||||
@ -536,6 +543,7 @@ class InkEditor extends AnnotationEditor {
|
||||
|
||||
if (this.width) {
|
||||
// This editor was created in using copy (ctrl+c).
|
||||
this.#isCanvasInitialized = true;
|
||||
const [parentWidth, parentHeight] = this.parent.viewportBaseDimensions;
|
||||
this.setAt(
|
||||
baseX * parentWidth,
|
||||
@ -547,6 +555,9 @@ class InkEditor extends AnnotationEditor {
|
||||
this.#setCanvasDims();
|
||||
this.#redraw();
|
||||
this.div.classList.add("disabled");
|
||||
} else {
|
||||
this.div.classList.add("editing");
|
||||
this.enableEditMode();
|
||||
}
|
||||
|
||||
this.#createObserver();
|
||||
@ -555,6 +566,9 @@ class InkEditor extends AnnotationEditor {
|
||||
}
|
||||
|
||||
#setCanvasDims() {
|
||||
if (!this.#isCanvasInitialized) {
|
||||
return;
|
||||
}
|
||||
const [parentWidth, parentHeight] = this.parent.viewportBaseDimensions;
|
||||
this.canvas.width = this.width * parentWidth;
|
||||
this.canvas.height = this.height * parentHeight;
|
||||
@ -874,6 +888,10 @@ class InkEditor extends AnnotationEditor {
|
||||
|
||||
/** @inheritdoc */
|
||||
serialize() {
|
||||
if (this.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const rect = this.getRect(0, 0);
|
||||
const height =
|
||||
this.rotation % 180 === 0 ? rect[3] - rect[1] : rect[2] - rect[0];
|
||||
|
@ -779,7 +779,9 @@ class AnnotationEditorUIManager {
|
||||
const editors = Array.from(this.#allEditors.values());
|
||||
cmd = () => {
|
||||
for (const editor of editors) {
|
||||
editor.remove();
|
||||
if (!editor.isEmpty()) {
|
||||
editor.remove();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user