Merge pull request #15186 from calixteman/freetext_commit
[Editor] Move the keyboard manager at the container level
This commit is contained in:
commit
f18a27bee9
@ -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);
|
||||
|
@ -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).
|
||||
|
@ -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,
|
||||
});
|
||||
|
@ -734,6 +734,7 @@ class BaseViewer {
|
||||
});
|
||||
|
||||
this.#annotationEditorUIManager = new AnnotationEditorUIManager(
|
||||
this.container,
|
||||
this.eventBus
|
||||
);
|
||||
if (mode !== AnnotationEditorType.NONE) {
|
||||
|
Loading…
Reference in New Issue
Block a user