Merge pull request #15186 from calixteman/freetext_commit

[Editor] Move the keyboard manager at the container level
This commit is contained in:
calixteman 2022-07-20 12:38:31 +02:00 committed by GitHub
commit f18a27bee9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 83 additions and 105 deletions

View File

@ -21,8 +21,8 @@
/** @typedef {import("../../web/interfaces").IL10n} IL10n */
import { AnnotationEditorType, shadow } from "../../shared/util.js";
import { bindEvents, KeyboardManager } from "./tools.js";
import { binarySearchFirstItem } from "../display_utils.js";
import { bindEvents } from "./tools.js";
import { FreeTextEditor } from "./freetext.js";
import { InkEditor } from "./ink.js";
@ -61,33 +61,6 @@ class AnnotationEditorLayer {
static _initialized = false;
static _keyboardManager = new KeyboardManager([
[["ctrl+a", "mac+meta+a"], AnnotationEditorLayer.prototype.selectAll],
[["ctrl+c", "mac+meta+c"], AnnotationEditorLayer.prototype.copy],
[["ctrl+v", "mac+meta+v"], AnnotationEditorLayer.prototype.paste],
[["ctrl+x", "mac+meta+x"], AnnotationEditorLayer.prototype.cut],
[["ctrl+z", "mac+meta+z"], AnnotationEditorLayer.prototype.undo],
[
["ctrl+y", "ctrl+shift+Z", "mac+meta+shift+Z"],
AnnotationEditorLayer.prototype.redo,
],
[
[
"Backspace",
"alt+Backspace",
"ctrl+Backspace",
"shift+Backspace",
"mac+Backspace",
"mac+alt+Backspace",
"mac+ctrl+Backspace",
"Delete",
"ctrl+Delete",
"shift+Delete",
],
AnnotationEditorLayer.prototype.delete,
],
]);
/**
* @param {AnnotationEditorLayerOptions} options
*/
@ -205,62 +178,6 @@ class AnnotationEditorLayer {
this.#uiManager.addCommands(params);
}
/**
* Undo the last command.
*/
undo() {
this.#uiManager.undo();
}
/**
* Redo the last command.
*/
redo() {
this.#uiManager.redo();
}
/**
* Suppress the selected editor or all editors.
*/
delete() {
this.#uiManager.delete();
}
/**
* Copy the selected editor.
*/
copy() {
this.#uiManager.copy();
}
/**
* Cut the selected editor.
*/
cut() {
this.#uiManager.cut();
}
/**
* Paste a previously copied editor.
*/
paste() {
this.#uiManager.paste();
}
/**
* Select all the editors.
*/
selectAll() {
this.#uiManager.selectAll();
}
/**
* Unselect all the editors.
*/
unselectAll() {
this.#uiManager.unselectAll();
}
/**
* Enable pointer events on the main div in order to enable
* editor creation.
@ -299,7 +216,7 @@ class AnnotationEditorLayer {
}
if (editor) {
this.unselectAll();
this.#uiManager.unselectAll();
}
}
@ -691,16 +608,6 @@ class AnnotationEditorLayer {
event.preventDefault();
}
/**
* Keydown callback.
* @param {KeyboardEvent} event
*/
keydown(event) {
if (!this.#uiManager.getActive()?.shouldGetKeyboardEvents()) {
AnnotationEditorLayer._keyboardManager.exec(this, event);
}
}
/**
* Destroy the main editor.
*/
@ -741,7 +648,7 @@ class AnnotationEditorLayer {
*/
render(parameters) {
this.viewport = parameters.viewport;
bindEvents(this, this.div, ["dragover", "drop", "keydown"]);
bindEvents(this, this.div, ["dragover", "drop"]);
this.setDimensions();
for (const editor of this.#uiManager.getEditors(this.pageIndex)) {
this.add(editor);

View File

@ -23,13 +23,15 @@ import {
LINE_FACTOR,
Util,
} from "../../shared/util.js";
import { bindEvents, KeyboardManager } from "./tools.js";
import { AnnotationEditor } from "./editor.js";
import { bindEvents } from "./tools.js";
/**
* Basic text editor in order to create a FreeTex annotation.
*/
class FreeTextEditor extends AnnotationEditor {
#boundEditorDivKeydown = this.editorDivKeydown.bind(this);
#color;
#content = "";
@ -50,6 +52,13 @@ class FreeTextEditor extends AnnotationEditor {
static _defaultFontSize = 10;
static _keyboardManager = new KeyboardManager([
[
["ctrl+Enter", "mac+meta+Enter", "Escape", "mac+Escape"],
FreeTextEditor.prototype.commitOrRemove,
],
]);
constructor(params) {
super({ ...params, name: "freeTextEditor" });
this.#color =
@ -210,6 +219,7 @@ class FreeTextEditor extends AnnotationEditor {
this.editorDiv.contentEditable = true;
this.div.draggable = false;
this.div.removeAttribute("tabIndex");
this.editorDiv.addEventListener("keydown", this.#boundEditorDivKeydown);
}
/** @inheritdoc */
@ -220,6 +230,7 @@ class FreeTextEditor extends AnnotationEditor {
this.editorDiv.contentEditable = false;
this.div.draggable = true;
this.div.tabIndex = 0;
this.editorDiv.removeEventListener("keydown", this.#boundEditorDivKeydown);
}
/** @inheritdoc */
@ -311,13 +322,17 @@ class FreeTextEditor extends AnnotationEditor {
* onkeydown callback.
* @param {MouseEvent} event
*/
keyup(event) {
if (event.key === "Enter") {
keydown(event) {
if (event.target === this.div && event.key === "Enter") {
this.enableEditMode();
this.editorDiv.focus();
}
}
editorDivKeydown(event) {
FreeTextEditor._keyboardManager.exec(this, event);
}
/** @inheritdoc */
disableEditing() {
this.editorDiv.setAttribute("role", "comment");
@ -376,7 +391,7 @@ class FreeTextEditor extends AnnotationEditor {
// TODO: implement paste callback.
// The goal is to sanitize and have something suitable for this
// editor.
bindEvents(this, this.div, ["dblclick", "keyup"]);
bindEvents(this, this.div, ["dblclick", "keydown"]);
if (this.width) {
// This editor was created in using copy (ctrl+c).

View File

@ -261,12 +261,12 @@ class KeyboardManager {
/**
* Execute a callback, if any, for a given keyboard event.
* The page is used as `this` in the callback.
* @param {AnnotationEditorLayer} page.
* The self is used as `this` in the callback.
* @param {Object} self.
* @param {KeyboardEvent} event
* @returns
*/
exec(page, event) {
exec(self, event) {
if (!this.allKeys.has(event.key)) {
return;
}
@ -274,7 +274,7 @@ class KeyboardManager {
if (!callback) {
return;
}
callback.bind(page)();
callback.bind(self)();
event.preventDefault();
}
}
@ -422,6 +422,8 @@ class AnnotationEditorUIManager {
#previousActiveEditor = null;
#boundKeydown = this.keydown.bind(this);
#boundOnEditingAction = this.onEditingAction.bind(this);
#boundOnPageChanging = this.onPageChanging.bind(this);
@ -437,7 +439,37 @@ class AnnotationEditorUIManager {
hasSelectedEditor: false,
};
constructor(eventBus) {
#container = null;
static _keyboardManager = new KeyboardManager([
[["ctrl+a", "mac+meta+a"], AnnotationEditorUIManager.prototype.selectAll],
[["ctrl+c", "mac+meta+c"], AnnotationEditorUIManager.prototype.copy],
[["ctrl+v", "mac+meta+v"], AnnotationEditorUIManager.prototype.paste],
[["ctrl+x", "mac+meta+x"], AnnotationEditorUIManager.prototype.cut],
[["ctrl+z", "mac+meta+z"], AnnotationEditorUIManager.prototype.undo],
[
["ctrl+y", "ctrl+shift+Z", "mac+meta+shift+Z"],
AnnotationEditorUIManager.prototype.redo,
],
[
[
"Backspace",
"alt+Backspace",
"ctrl+Backspace",
"shift+Backspace",
"mac+Backspace",
"mac+alt+Backspace",
"mac+ctrl+Backspace",
"Delete",
"ctrl+Delete",
"shift+Delete",
],
AnnotationEditorUIManager.prototype.delete,
],
]);
constructor(container, eventBus) {
this.#container = container;
this.#eventBus = eventBus;
this.#eventBus._on("editingaction", this.#boundOnEditingAction);
this.#eventBus._on("pagechanging", this.#boundOnPageChanging);
@ -445,6 +477,7 @@ class AnnotationEditorUIManager {
}
destroy() {
this.#removeKeyboardManager();
this.#eventBus._off("editingaction", this.#boundOnEditingAction);
this.#eventBus._off("pagechanging", this.#boundOnPageChanging);
this.#eventBus._off("textlayerrendered", this.#boundOnTextLayerRendered);
@ -468,6 +501,26 @@ class AnnotationEditorUIManager {
layer?.onTextLayerRendered();
}
#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.
this.#container.addEventListener("keydown", this.#boundKeydown);
}
#removeKeyboardManager() {
this.#container.removeEventListener("keydown", this.#boundKeydown);
}
/**
* Keydown callback.
* @param {KeyboardEvent} event
*/
keydown(event) {
if (!this.getActive()?.shouldGetKeyboardEvents()) {
AnnotationEditorUIManager._keyboardManager.exec(this, event);
}
}
/**
* Execute an action for a given name.
* For example, the user can click on the "Undo" entry in the context menu
@ -517,6 +570,7 @@ class AnnotationEditorUIManager {
*/
setEditingState(isEditing) {
if (isEditing) {
this.#addKeyboardManager();
this.#dispatchUpdateStates({
isEditing: this.#mode !== AnnotationEditorType.NONE,
isEmpty: this.#isEmpty(),
@ -526,6 +580,7 @@ class AnnotationEditorUIManager {
hasEmptyClipboard: this.#clipboardManager.isEmpty(),
});
} else {
this.#removeKeyboardManager();
this.#dispatchUpdateStates({
isEditing: false,
});

View File

@ -734,6 +734,7 @@ class BaseViewer {
});
this.#annotationEditorUIManager = new AnnotationEditorUIManager(
this.container,
this.eventBus
);
if (mode !== AnnotationEditorType.NONE) {