mirror of
https://github.com/Azornes/Comfyui-LayerForge.git
synced 2026-05-06 16:36:44 -03:00
Merge pull request #28 from diodiogod/pr/comfyui-shortcut-leaks-clean
Fix ComfyUI shortcut leaks while LayerForge widget is active
This commit is contained in:
@@ -94,6 +94,16 @@ export class CanvasInteractions {
|
|||||||
this.canvas.canvas.style.border = '';
|
this.canvas.canvas.style.border = '';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
isEditableElement(target) {
|
||||||
|
if (!(target instanceof HTMLElement)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (target.isContentEditable) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
const editableSelector = 'input, textarea, select, [contenteditable="true"]';
|
||||||
|
return !!target.closest(editableSelector);
|
||||||
|
}
|
||||||
setupEventListeners() {
|
setupEventListeners() {
|
||||||
this.canvas.canvas.addEventListener('mousedown', this.onMouseDown);
|
this.canvas.canvas.addEventListener('mousedown', this.onMouseDown);
|
||||||
this.canvas.canvas.addEventListener('mousemove', this.onMouseMove);
|
this.canvas.canvas.addEventListener('mousemove', this.onMouseMove);
|
||||||
@@ -538,6 +548,9 @@ export class CanvasInteractions {
|
|||||||
this.interaction.isShiftPressed = true;
|
this.interaction.isShiftPressed = true;
|
||||||
if (e.key === 'Alt')
|
if (e.key === 'Alt')
|
||||||
this.interaction.isAltPressed = true;
|
this.interaction.isAltPressed = true;
|
||||||
|
if (this.isEditableElement(e.target) || this.isEditableElement(document.activeElement)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
// Check if canvas is focused before handling any shortcuts
|
// Check if canvas is focused before handling any shortcuts
|
||||||
const shouldHandle = this.canvas.isMouseOver ||
|
const shouldHandle = this.canvas.isMouseOver ||
|
||||||
this.canvas.canvas.contains(document.activeElement) ||
|
this.canvas.canvas.contains(document.activeElement) ||
|
||||||
|
|||||||
@@ -118,7 +118,19 @@ export class CanvasLayersPanel {
|
|||||||
this.setupControlButtons();
|
this.setupControlButtons();
|
||||||
this.setupMasterVisibilityToggle();
|
this.setupMasterVisibilityToggle();
|
||||||
// Dodaj listener dla klawiatury, aby usuwanie działało z panelu
|
// Dodaj listener dla klawiatury, aby usuwanie działało z panelu
|
||||||
|
const isEditableTarget = (target) => {
|
||||||
|
if (!(target instanceof HTMLElement)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (target.isContentEditable) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return !!target.closest('input, textarea, select, [contenteditable="true"]');
|
||||||
|
};
|
||||||
this.container.addEventListener('keydown', (e) => {
|
this.container.addEventListener('keydown', (e) => {
|
||||||
|
if (isEditableTarget(e.target)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (e.key === 'Delete' || e.key === 'Backspace') {
|
if (e.key === 'Delete' || e.key === 'Backspace') {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
|
|||||||
125
js/CanvasView.js
125
js/CanvasView.js
@@ -1,6 +1,8 @@
|
|||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
import { app } from "../../scripts/app.js";
|
import { app } from "../../scripts/app.js";
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
|
import { ChangeTracker } from "../../scripts/changeTracker.js";
|
||||||
|
// @ts-ignore
|
||||||
import { $el } from "../../scripts/ui.js";
|
import { $el } from "../../scripts/ui.js";
|
||||||
import { addStylesheet, getUrl, loadTemplate } from "./utils/ResourceManager.js";
|
import { addStylesheet, getUrl, loadTemplate } from "./utils/ResourceManager.js";
|
||||||
import { Canvas } from "./Canvas.js";
|
import { Canvas } from "./Canvas.js";
|
||||||
@@ -12,6 +14,52 @@ import { showErrorNotification, showSuccessNotification, showInfoNotification, s
|
|||||||
import { iconLoader, LAYERFORGE_TOOLS } from "./utils/IconLoader.js";
|
import { iconLoader, LAYERFORGE_TOOLS } from "./utils/IconLoader.js";
|
||||||
import { setupSAMDetectorHook } from "./SAMDetectorIntegration.js";
|
import { setupSAMDetectorHook } from "./SAMDetectorIntegration.js";
|
||||||
const log = createModuleLogger('Canvas_view');
|
const log = createModuleLogger('Canvas_view');
|
||||||
|
const LAYERFORGE_CHANGE_TRACKER_PATCH_FLAG = '__layerForgeUndoRedoPatched';
|
||||||
|
const LAYERFORGE_SHORTCUT_ACTIVE_ATTR = 'data-layerforge-shortcuts-active';
|
||||||
|
const isLayerForgeEditableElement = (target) => {
|
||||||
|
if (!(target instanceof HTMLElement)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (target.isContentEditable) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return !!target.closest('.painterMainContainer input, .painterMainContainer textarea, .painterMainContainer select, .painterMainContainer [contenteditable="true"]');
|
||||||
|
};
|
||||||
|
const isLayerForgeShortcutContextElement = (target) => {
|
||||||
|
return target instanceof HTMLElement && !!target.closest('.painterMainContainer');
|
||||||
|
};
|
||||||
|
const isLayerForgeShortcutContextActive = (event) => {
|
||||||
|
if (event && isLayerForgeShortcutContextElement(event.target)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (isLayerForgeShortcutContextElement(document.activeElement)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return !!document.querySelector(`.painterMainContainer[${LAYERFORGE_SHORTCUT_ACTIVE_ATTR}="true"]`);
|
||||||
|
};
|
||||||
|
const isLayerForgeEditableFocused = () => {
|
||||||
|
return isLayerForgeEditableElement(document.activeElement);
|
||||||
|
};
|
||||||
|
const patchLayerForgeChangeTrackerUndoRedo = () => {
|
||||||
|
const prototype = ChangeTracker?.prototype;
|
||||||
|
if (!prototype || prototype[LAYERFORGE_CHANGE_TRACKER_PATCH_FLAG] || typeof prototype.undoRedo !== 'function') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const originalUndoRedo = prototype.undoRedo;
|
||||||
|
prototype.undoRedo = async function (event) {
|
||||||
|
if (isLayerForgeShortcutContextActive(event)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return await originalUndoRedo.call(this, event);
|
||||||
|
};
|
||||||
|
Object.defineProperty(prototype, LAYERFORGE_CHANGE_TRACKER_PATCH_FLAG, {
|
||||||
|
value: true,
|
||||||
|
configurable: false,
|
||||||
|
enumerable: false,
|
||||||
|
writable: false
|
||||||
|
});
|
||||||
|
};
|
||||||
|
patchLayerForgeChangeTrackerUndoRedo();
|
||||||
async function createCanvasWidget(node, widget, app) {
|
async function createCanvasWidget(node, widget, app) {
|
||||||
const canvas = new Canvas(node, widget, {
|
const canvas = new Canvas(node, widget, {
|
||||||
onStateChange: () => updateOutput(node, canvas)
|
onStateChange: () => updateOutput(node, canvas)
|
||||||
@@ -906,6 +954,70 @@ async function createCanvasWidget(node, widget, app) {
|
|||||||
height: "100%"
|
height: "100%"
|
||||||
}
|
}
|
||||||
}, [controlPanel, canvasContainer, layersPanelContainer]);
|
}, [controlPanel, canvasContainer, layersPanelContainer]);
|
||||||
|
const stopEditableClipboardLeak = (event) => {
|
||||||
|
if (isLayerForgeEditableElement(event.target) || isLayerForgeEditableFocused()) {
|
||||||
|
event.stopPropagation();
|
||||||
|
event.stopImmediatePropagation();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
mainContainer.addEventListener('copy', stopEditableClipboardLeak);
|
||||||
|
mainContainer.addEventListener('cut', stopEditableClipboardLeak);
|
||||||
|
mainContainer.addEventListener('paste', stopEditableClipboardLeak);
|
||||||
|
const setShortcutContextActive = (active) => {
|
||||||
|
if (active) {
|
||||||
|
mainContainer.setAttribute(LAYERFORGE_SHORTCUT_ACTIVE_ATTR, 'true');
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
mainContainer.removeAttribute(LAYERFORGE_SHORTCUT_ACTIVE_ATTR);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const handleShortcutContextFocusIn = () => {
|
||||||
|
setShortcutContextActive(true);
|
||||||
|
};
|
||||||
|
const handleShortcutContextFocusOut = () => {
|
||||||
|
requestAnimationFrame(() => {
|
||||||
|
if (!mainContainer.contains(document.activeElement)) {
|
||||||
|
setShortcutContextActive(false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
const handleShortcutContextPointerEnter = () => {
|
||||||
|
setShortcutContextActive(true);
|
||||||
|
};
|
||||||
|
const handleShortcutContextPointerLeave = () => {
|
||||||
|
if (!mainContainer.contains(document.activeElement)) {
|
||||||
|
setShortcutContextActive(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const handleRootUndoRedo = (event) => {
|
||||||
|
if (isLayerForgeEditableElement(event.target)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const isPrimaryModifier = (event.ctrlKey || event.metaKey) && !event.altKey;
|
||||||
|
if (!isPrimaryModifier) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const key = event.key.toLowerCase();
|
||||||
|
const isUndo = key === 'z' && !event.shiftKey;
|
||||||
|
const isRedo = key === 'y' || (key === 'z' && event.shiftKey);
|
||||||
|
if (!isUndo && !isRedo) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
event.preventDefault();
|
||||||
|
event.stopPropagation();
|
||||||
|
event.stopImmediatePropagation();
|
||||||
|
if (isRedo) {
|
||||||
|
canvas.redo();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
canvas.undo();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
mainContainer.addEventListener('focusin', handleShortcutContextFocusIn);
|
||||||
|
mainContainer.addEventListener('focusout', handleShortcutContextFocusOut);
|
||||||
|
mainContainer.addEventListener('pointerenter', handleShortcutContextPointerEnter);
|
||||||
|
mainContainer.addEventListener('pointerleave', handleShortcutContextPointerLeave);
|
||||||
|
mainContainer.addEventListener('keydown', handleRootUndoRedo, true);
|
||||||
if (node.addDOMWidget) {
|
if (node.addDOMWidget) {
|
||||||
node.addDOMWidget("mainContainer", "widget", mainContainer);
|
node.addDOMWidget("mainContainer", "widget", mainContainer);
|
||||||
}
|
}
|
||||||
@@ -1029,7 +1141,18 @@ async function createCanvasWidget(node, widget, app) {
|
|||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
canvas: canvas,
|
canvas: canvas,
|
||||||
panel: controlPanel
|
panel: controlPanel,
|
||||||
|
destroy: () => {
|
||||||
|
mainContainer.removeEventListener('copy', stopEditableClipboardLeak);
|
||||||
|
mainContainer.removeEventListener('cut', stopEditableClipboardLeak);
|
||||||
|
mainContainer.removeEventListener('paste', stopEditableClipboardLeak);
|
||||||
|
mainContainer.removeEventListener('focusin', handleShortcutContextFocusIn);
|
||||||
|
mainContainer.removeEventListener('focusout', handleShortcutContextFocusOut);
|
||||||
|
mainContainer.removeEventListener('pointerenter', handleShortcutContextPointerEnter);
|
||||||
|
mainContainer.removeEventListener('pointerleave', handleShortcutContextPointerLeave);
|
||||||
|
mainContainer.removeEventListener('keydown', handleRootUndoRedo, true);
|
||||||
|
mainContainer.removeAttribute(LAYERFORGE_SHORTCUT_ACTIVE_ATTR);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
const canvasNodeInstances = new Map();
|
const canvasNodeInstances = new Map();
|
||||||
|
|||||||
@@ -163,6 +163,19 @@ export class CanvasInteractions {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private isEditableElement(target: EventTarget | null): boolean {
|
||||||
|
if (!(target instanceof HTMLElement)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (target.isContentEditable) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const editableSelector = 'input, textarea, select, [contenteditable="true"]';
|
||||||
|
return !!target.closest(editableSelector);
|
||||||
|
}
|
||||||
|
|
||||||
setupEventListeners(): void {
|
setupEventListeners(): void {
|
||||||
this.canvas.canvas.addEventListener('mousedown', this.onMouseDown as EventListener);
|
this.canvas.canvas.addEventListener('mousedown', this.onMouseDown as EventListener);
|
||||||
this.canvas.canvas.addEventListener('mousemove', this.onMouseMove as EventListener);
|
this.canvas.canvas.addEventListener('mousemove', this.onMouseMove as EventListener);
|
||||||
@@ -666,6 +679,10 @@ export class CanvasInteractions {
|
|||||||
if (e.key === 'Shift') this.interaction.isShiftPressed = true;
|
if (e.key === 'Shift') this.interaction.isShiftPressed = true;
|
||||||
if (e.key === 'Alt') this.interaction.isAltPressed = true;
|
if (e.key === 'Alt') this.interaction.isAltPressed = true;
|
||||||
|
|
||||||
|
if (this.isEditableElement(e.target) || this.isEditableElement(document.activeElement)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Check if canvas is focused before handling any shortcuts
|
// Check if canvas is focused before handling any shortcuts
|
||||||
const shouldHandle = this.canvas.isMouseOver ||
|
const shouldHandle = this.canvas.isMouseOver ||
|
||||||
this.canvas.canvas.contains(document.activeElement) ||
|
this.canvas.canvas.contains(document.activeElement) ||
|
||||||
|
|||||||
@@ -139,7 +139,23 @@ export class CanvasLayersPanel {
|
|||||||
this.setupMasterVisibilityToggle();
|
this.setupMasterVisibilityToggle();
|
||||||
|
|
||||||
// Dodaj listener dla klawiatury, aby usuwanie działało z panelu
|
// Dodaj listener dla klawiatury, aby usuwanie działało z panelu
|
||||||
|
const isEditableTarget = (target: EventTarget | null): boolean => {
|
||||||
|
if (!(target instanceof HTMLElement)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (target.isContentEditable) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return !!target.closest('input, textarea, select, [contenteditable="true"]');
|
||||||
|
};
|
||||||
|
|
||||||
this.container.addEventListener('keydown', (e: KeyboardEvent) => {
|
this.container.addEventListener('keydown', (e: KeyboardEvent) => {
|
||||||
|
if (isEditableTarget(e.target)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (e.key === 'Delete' || e.key === 'Backspace') {
|
if (e.key === 'Delete' || e.key === 'Backspace') {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
|
|||||||
@@ -5,6 +5,8 @@ import {api} from "../../scripts/api.js";
|
|||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
import {ComfyApp} from "../../scripts/app.js";
|
import {ComfyApp} from "../../scripts/app.js";
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
|
import {ChangeTracker} from "../../scripts/changeTracker.js";
|
||||||
|
// @ts-ignore
|
||||||
import {$el} from "../../scripts/ui.js";
|
import {$el} from "../../scripts/ui.js";
|
||||||
|
|
||||||
import { addStylesheet, getUrl, loadTemplate } from "./utils/ResourceManager.js";
|
import { addStylesheet, getUrl, loadTemplate } from "./utils/ResourceManager.js";
|
||||||
@@ -21,6 +23,66 @@ import type { ComfyNode, Layer, AddMode } from './types';
|
|||||||
|
|
||||||
const log = createModuleLogger('Canvas_view');
|
const log = createModuleLogger('Canvas_view');
|
||||||
|
|
||||||
|
const LAYERFORGE_CHANGE_TRACKER_PATCH_FLAG = '__layerForgeUndoRedoPatched';
|
||||||
|
const LAYERFORGE_SHORTCUT_ACTIVE_ATTR = 'data-layerforge-shortcuts-active';
|
||||||
|
|
||||||
|
const isLayerForgeEditableElement = (target: EventTarget | null): boolean => {
|
||||||
|
if (!(target instanceof HTMLElement)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (target.isContentEditable) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return !!target.closest('.painterMainContainer input, .painterMainContainer textarea, .painterMainContainer select, .painterMainContainer [contenteditable="true"]');
|
||||||
|
};
|
||||||
|
|
||||||
|
const isLayerForgeShortcutContextElement = (target: EventTarget | null): boolean => {
|
||||||
|
return target instanceof HTMLElement && !!target.closest('.painterMainContainer');
|
||||||
|
};
|
||||||
|
|
||||||
|
const isLayerForgeShortcutContextActive = (event?: KeyboardEvent): boolean => {
|
||||||
|
if (event && isLayerForgeShortcutContextElement(event.target)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isLayerForgeShortcutContextElement(document.activeElement)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return !!document.querySelector(`.painterMainContainer[${LAYERFORGE_SHORTCUT_ACTIVE_ATTR}="true"]`);
|
||||||
|
};
|
||||||
|
|
||||||
|
const isLayerForgeEditableFocused = (): boolean => {
|
||||||
|
return isLayerForgeEditableElement(document.activeElement);
|
||||||
|
};
|
||||||
|
|
||||||
|
const patchLayerForgeChangeTrackerUndoRedo = (): void => {
|
||||||
|
const prototype = ChangeTracker?.prototype as any;
|
||||||
|
if (!prototype || prototype[LAYERFORGE_CHANGE_TRACKER_PATCH_FLAG] || typeof prototype.undoRedo !== 'function') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const originalUndoRedo = prototype.undoRedo;
|
||||||
|
prototype.undoRedo = async function (event: KeyboardEvent) {
|
||||||
|
if (isLayerForgeShortcutContextActive(event)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return await originalUndoRedo.call(this, event);
|
||||||
|
};
|
||||||
|
|
||||||
|
Object.defineProperty(prototype, LAYERFORGE_CHANGE_TRACKER_PATCH_FLAG, {
|
||||||
|
value: true,
|
||||||
|
configurable: false,
|
||||||
|
enumerable: false,
|
||||||
|
writable: false
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
patchLayerForgeChangeTrackerUndoRedo();
|
||||||
|
|
||||||
interface CanvasWidget {
|
interface CanvasWidget {
|
||||||
canvas: Canvas;
|
canvas: Canvas;
|
||||||
panel: HTMLDivElement;
|
panel: HTMLDivElement;
|
||||||
@@ -1027,6 +1089,81 @@ $el("label.clipboard-switch.mask-switch", {
|
|||||||
}
|
}
|
||||||
}, [controlPanel, canvasContainer, layersPanelContainer]) as HTMLDivElement;
|
}, [controlPanel, canvasContainer, layersPanelContainer]) as HTMLDivElement;
|
||||||
|
|
||||||
|
const stopEditableClipboardLeak = (event: ClipboardEvent) => {
|
||||||
|
if (isLayerForgeEditableElement(event.target) || isLayerForgeEditableFocused()) {
|
||||||
|
event.stopPropagation();
|
||||||
|
event.stopImmediatePropagation();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
mainContainer.addEventListener('copy', stopEditableClipboardLeak);
|
||||||
|
mainContainer.addEventListener('cut', stopEditableClipboardLeak);
|
||||||
|
mainContainer.addEventListener('paste', stopEditableClipboardLeak);
|
||||||
|
|
||||||
|
const setShortcutContextActive = (active: boolean) => {
|
||||||
|
if (active) {
|
||||||
|
mainContainer.setAttribute(LAYERFORGE_SHORTCUT_ACTIVE_ATTR, 'true');
|
||||||
|
} else {
|
||||||
|
mainContainer.removeAttribute(LAYERFORGE_SHORTCUT_ACTIVE_ATTR);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleShortcutContextFocusIn = () => {
|
||||||
|
setShortcutContextActive(true);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleShortcutContextFocusOut = () => {
|
||||||
|
requestAnimationFrame(() => {
|
||||||
|
if (!mainContainer.contains(document.activeElement)) {
|
||||||
|
setShortcutContextActive(false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleShortcutContextPointerEnter = () => {
|
||||||
|
setShortcutContextActive(true);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleShortcutContextPointerLeave = () => {
|
||||||
|
if (!mainContainer.contains(document.activeElement)) {
|
||||||
|
setShortcutContextActive(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleRootUndoRedo = (event: KeyboardEvent) => {
|
||||||
|
if (isLayerForgeEditableElement(event.target)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const isPrimaryModifier = (event.ctrlKey || event.metaKey) && !event.altKey;
|
||||||
|
if (!isPrimaryModifier) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const key = event.key.toLowerCase();
|
||||||
|
const isUndo = key === 'z' && !event.shiftKey;
|
||||||
|
const isRedo = key === 'y' || (key === 'z' && event.shiftKey);
|
||||||
|
if (!isUndo && !isRedo) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
event.preventDefault();
|
||||||
|
event.stopPropagation();
|
||||||
|
event.stopImmediatePropagation();
|
||||||
|
|
||||||
|
if (isRedo) {
|
||||||
|
canvas.redo();
|
||||||
|
} else {
|
||||||
|
canvas.undo();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
mainContainer.addEventListener('focusin', handleShortcutContextFocusIn);
|
||||||
|
mainContainer.addEventListener('focusout', handleShortcutContextFocusOut);
|
||||||
|
mainContainer.addEventListener('pointerenter', handleShortcutContextPointerEnter);
|
||||||
|
mainContainer.addEventListener('pointerleave', handleShortcutContextPointerLeave);
|
||||||
|
mainContainer.addEventListener('keydown', handleRootUndoRedo, true);
|
||||||
|
|
||||||
if (node.addDOMWidget) {
|
if (node.addDOMWidget) {
|
||||||
node.addDOMWidget("mainContainer", "widget", mainContainer);
|
node.addDOMWidget("mainContainer", "widget", mainContainer);
|
||||||
}
|
}
|
||||||
@@ -1181,7 +1318,18 @@ $el("label.clipboard-switch.mask-switch", {
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
canvas: canvas,
|
canvas: canvas,
|
||||||
panel: controlPanel
|
panel: controlPanel,
|
||||||
|
destroy: () => {
|
||||||
|
mainContainer.removeEventListener('copy', stopEditableClipboardLeak);
|
||||||
|
mainContainer.removeEventListener('cut', stopEditableClipboardLeak);
|
||||||
|
mainContainer.removeEventListener('paste', stopEditableClipboardLeak);
|
||||||
|
mainContainer.removeEventListener('focusin', handleShortcutContextFocusIn);
|
||||||
|
mainContainer.removeEventListener('focusout', handleShortcutContextFocusOut);
|
||||||
|
mainContainer.removeEventListener('pointerenter', handleShortcutContextPointerEnter);
|
||||||
|
mainContainer.removeEventListener('pointerleave', handleShortcutContextPointerLeave);
|
||||||
|
mainContainer.removeEventListener('keydown', handleRootUndoRedo, true);
|
||||||
|
mainContainer.removeAttribute(LAYERFORGE_SHORTCUT_ACTIVE_ATTR);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user