Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Editor] - Add the ability to directly draw after selecting ink tool #15050

Merged
merged 1 commit into from
Jun 16, 2022
Merged
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
98 changes: 84 additions & 14 deletions src/display/editor/annotation_editor_layer.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ import { PixelsPerInch } from "../display_utils.js";
class AnnotationEditorLayer {
#boundClick;

#boundMouseover;

#editors = new Map();

#uiManager;
Expand Down Expand Up @@ -83,6 +85,7 @@ 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);
Expand All @@ -91,13 +94,45 @@ class AnnotationEditorLayer {
this.#uiManager.addLayer(this);
}

/**
* The mode has changed: it must be updated.
* @param {number} mode
*/
updateMode(mode) {
if (mode === 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);
} else {
this.div.removeEventListener("mouseover", this.#boundMouseover);
}
}

/**
* Mouseover callback.
* @param {MouseEvent} event
*/
mouseover(event) {
if (event.target === this.div && event.buttons === 0) {
// 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 {function} cmd
* @param {function} undo
* @param {boolean} mustExec - If true the command is executed after having
* been added.
*/
addCommands(cmd, undo) {
this.#uiManager.addCommands(cmd, undo);
addCommands(cmd, undo, mustExec) {
this.#uiManager.addCommands(cmd, undo, mustExec);
}

/**
Expand Down Expand Up @@ -178,14 +213,24 @@ class AnnotationEditorLayer {
* @param {AnnotationEditor} editor
*/
setActiveEditor(editor) {
const currentActive = this.#uiManager.getActive();
if (currentActive === editor) {
return;
}

this.#uiManager.setActiveEditor(editor);

if (currentActive && currentActive !== editor) {
currentActive.commitOrRemove();
}

if (editor) {
this.unselectAll();
this.div.removeEventListener("click", this.#boundClick);
} else {
this.#uiManager.allowClick = false;
this.div.addEventListener("click", this.#boundClick);
}
this.#uiManager.setActiveEditor(editor);
}

attach(editor) {
Expand All @@ -212,7 +257,6 @@ class AnnotationEditorLayer {
if (this.#uiManager.isActive(editor) || this.#editors.size === 0) {
this.setActiveEditor(null);
this.#uiManager.allowClick = true;
this.div.focus();
}
}

Expand Down Expand Up @@ -279,7 +323,22 @@ class AnnotationEditorLayer {
editor.remove();
};

this.addCommands(cmd, undo);
this.addCommands(cmd, undo, true);
}

/**
* Add a new editor and make this addition undoable.
* @param {AnnotationEditor} editor
*/
addUndoableEditor(editor) {
const cmd = () => {
this.addOrRebuild(editor);
};
const undo = () => {
editor.remove();
};

this.addCommands(cmd, undo, false);
}

/**
Expand All @@ -306,16 +365,11 @@ class AnnotationEditorLayer {
}

/**
* Mouseclick callback.
* Create and add a new editor.
* @param {MouseEvent} event
* @returns {undefined}
* @returns {AnnotationEditor}
*/
click(event) {
if (!this.#uiManager.allowClick) {
this.#uiManager.allowClick = true;
return;
}

#createAndAddNewEditor(event) {
const id = this.getNextId();
const editor = this.#createNewEditor({
parent: this,
Expand All @@ -324,8 +378,24 @@ class AnnotationEditorLayer {
y: event.offsetY,
});
if (editor) {
this.addANewEditor(editor);
this.add(editor);
}

return editor;
}

/**
* Mouseclick callback.
* @param {MouseEvent} event
* @returns {undefined}
*/
click(event) {
if (!this.#uiManager.allowClick) {
this.#uiManager.allowClick = true;
return;
}

this.#createAndAddNewEditor(event);
}

/**
Expand Down
21 changes: 19 additions & 2 deletions src/display/editor/editor.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,20 @@ class AnnotationEditor {
this.isAttachedToDOM = false;
}

/**
* This editor will be behind the others.
*/
setInBackground() {
this.div.classList.add("background");
}

/**
* This editor will be in the foreground.
*/
setInForeground() {
this.div.classList.remove("background");
}

/**
* onfocus callback.
*/
Expand Down Expand Up @@ -81,12 +95,16 @@ class AnnotationEditor {

event.preventDefault();

this.commitOrRemove();
this.parent.setActiveEditor(null);
}

commitOrRemove() {
if (this.isEmpty()) {
this.remove();
} else {
this.commit();
}
this.parent.setActiveEditor(null);
}

/**
Expand Down Expand Up @@ -156,7 +174,6 @@ class AnnotationEditor {
this.div = document.createElement("div");
this.div.className = this.name;
this.div.setAttribute("id", this.id);
this.div.draggable = true;
this.div.tabIndex = 100;

const [tx, ty] = this.getInitialTranslation();
Expand Down
9 changes: 9 additions & 0 deletions src/display/editor/freetext.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ class FreeTextEditor extends AnnotationEditor {

#contentHTML = "";

#hasAlreadyBeenCommitted = false;

#fontSize;

static _freeTextDefaultContent = "";
Expand Down Expand Up @@ -168,6 +170,13 @@ class FreeTextEditor extends AnnotationEditor {
* @returns {undefined}
*/
commit() {
if (!this.#hasAlreadyBeenCommitted) {
// This editor has something and it's the first time
// it's commited so we can it in the undo/redo stack.
this.#hasAlreadyBeenCommitted = true;
this.parent.addUndoableEditor(this);
}

this.disableEditMode();
this.#contentHTML = this.editorDiv.innerHTML;
this.#content = this.#extractText().trimEnd();
Expand Down
42 changes: 28 additions & 14 deletions src/display/editor/ink.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,11 @@ import { fitCurve } from "./fit_curve/fit_curve.js";
* Basic draw editor in order to generate an Ink annotation.
*/
class InkEditor extends AnnotationEditor {
#aspectRatio;
#aspectRatio = 0;

#baseHeight;
#baseHeight = 0;

#baseWidth;
#baseWidth = 0;

#boundCanvasMousemove;

Expand All @@ -35,9 +35,9 @@ class InkEditor extends AnnotationEditor {

#boundCanvasMousedown;

#disableEditing;
#disableEditing = false;

#observer;
#observer = null;

constructor(params) {
super({ ...params, name: "inkEditor" });
Expand All @@ -48,10 +48,6 @@ class InkEditor extends AnnotationEditor {
this.currentPath = [];
this.scaleFactor = 1;
this.translationX = this.translationY = 0;
this.#baseWidth = this.#baseHeight = 0;
this.#aspectRatio = 0;
this.#disableEditing = false;
this.#observer = null;
this.x = 0;
this.y = 0;

Expand Down Expand Up @@ -113,20 +109,20 @@ class InkEditor extends AnnotationEditor {
return;
}

super.remove();

// Destroy the canvas.
this.canvas.width = this.canvas.heigth = 0;
this.canvas.remove();
this.canvas = null;

this.#observer.disconnect();
this.#observer = null;

super.remove();
}

/** @inheritdoc */
enableEditMode() {
if (this.#disableEditing) {
if (this.#disableEditing || this.canvas === null) {
return;
}

Expand All @@ -145,7 +141,7 @@ class InkEditor extends AnnotationEditor {

super.disableEditMode();
this.canvas.style.cursor = "auto";
this.div.draggable = true;
this.div.draggable = !this.isEmpty();
this.div.classList.remove("editing");

this.canvas.removeEventListener("mousedown", this.#boundCanvasMousedown);
Expand All @@ -154,6 +150,7 @@ class InkEditor extends AnnotationEditor {

/** @inheritdoc */
onceAdded() {
this.div.draggable = !this.isEmpty();
this.div.focus();
}

Expand Down Expand Up @@ -238,11 +235,15 @@ class InkEditor extends AnnotationEditor {
if (this.paths.length === 0) {
this.remove();
} else {
if (!this.canvas) {
this.#createCanvas();
this.#createObserver();
}
this.#fitToContent();
}
};

this.parent.addCommands(cmd, undo);
this.parent.addCommands(cmd, undo, true);
}

/**
Expand Down Expand Up @@ -273,8 +274,12 @@ class InkEditor extends AnnotationEditor {
if (this.#disableEditing) {
return;
}

this.disableEditMode();

// This editor must be on top of the main ink editor.
this.setInForeground();

this.#disableEditing = true;
this.div.classList.add("disabled");

Expand All @@ -297,6 +302,10 @@ class InkEditor extends AnnotationEditor {
return;
}

// We want to draw on top of any other editors.
// Since it's the last child, there's no need to give it a higher z-index.
this.setInForeground();

event.stopPropagation();

this.canvas.addEventListener("mouseleave", this.#boundCanvasMouseleave);
Expand Down Expand Up @@ -324,6 +333,10 @@ class InkEditor extends AnnotationEditor {
if (this.isInEditMode() && this.currentPath.length !== 0) {
event.stopPropagation();
this.#endDrawing(event);

// Since the ink editor covers all of the page and we want to be able
// to select another editor, we just put this one in the background.
this.setInBackground();
}
}

Expand All @@ -334,6 +347,7 @@ class InkEditor extends AnnotationEditor {
*/
canvasMouseleave(event) {
this.#endDrawing(event);
this.setInBackground();
}

/**
Expand Down
Loading