fix cut/copy/paste menu

This commit is contained in:
sawka 2024-06-24 17:44:31 -07:00
parent cc46cf64df
commit 997940949a
5 changed files with 55 additions and 48 deletions

View file

@ -411,25 +411,6 @@ async function createNewWaveWindow() {
electron.ipcMain.on("openNewWindow", createNewWaveWindow);
electron.ipcMain.on("context-editmenu", (_, { x, y }, opts) => {
if (opts == null) {
opts = {};
}
console.log("context-editmenu");
const menu = new electron.Menu();
if (!opts.onlyPaste) {
if (opts.showCut) {
const menuItem = new electron.MenuItem({ label: "Cut", role: "cut" });
menu.append(menuItem);
}
const menuItem = new electron.MenuItem({ label: "Copy", role: "copy" });
menu.append(menuItem);
}
const menuItem = new electron.MenuItem({ label: "Paste", role: "paste" });
menu.append(menuItem);
menu.popup({ x, y });
});
electron.ipcMain.on("contextmenu-show", (event, menuDefArr: ElectronContextMenuItem[], { x, y }) => {
if (menuDefArr == null || menuDefArr.length == 0) {
return;

View file

@ -9,7 +9,6 @@ contextBridge.exposeInMainWorld("api", {
getPlatform: () => ipcRenderer.sendSync("getPlatform"),
getCursorPoint: () => ipcRenderer.sendSync("getCursorPoint"),
openNewWindow: () => ipcRenderer.send("openNewWindow"),
contextEditMenu: (position, opts) => ipcRenderer.send("context-editmenu", position, opts),
showContextMenu: (menu, position) => ipcRenderer.send("contextmenu-show", menu, position),
onContextMenuClick: (callback) => ipcRenderer.on("contextmenu-click", callback),
});

View file

@ -4,7 +4,8 @@
import { Workspace } from "@/app/workspace/workspace";
import { getLayoutStateAtomForTab, globalLayoutTransformsMap } from "@/faraday/lib/layoutAtom";
import type { LayoutTreeState } from "@/faraday/lib/model";
import { WOS, atoms, getApi, globalStore, setBlockFocus } from "@/store/global";
import { ContextMenuModel } from "@/store/contextmenu";
import { WOS, atoms, globalStore, setBlockFocus } from "@/store/global";
import * as services from "@/store/services";
import * as keyutil from "@/util/keyutil";
import * as util from "@/util/util";
@ -27,27 +28,52 @@ const App = () => {
);
};
function handleContextMenu(e: React.MouseEvent<HTMLDivElement>) {
let isInNonTermInput = false;
const activeElem = document.activeElement;
if (activeElem != null && activeElem.nodeName == "TEXTAREA") {
if (!activeElem.classList.contains("xterm-helper-textarea")) {
isInNonTermInput = true;
}
}
if (activeElem != null && activeElem.nodeName == "INPUT" && activeElem.getAttribute("type") == "text") {
isInNonTermInput = true;
}
const opts: ContextMenuOpts = {};
if (isInNonTermInput) {
opts.showCut = true;
}
function isContentEditableBeingEdited() {
const activeElement = document.activeElement;
return (
activeElement &&
activeElement.getAttribute("contenteditable") !== null &&
activeElement.getAttribute("contenteditable") !== "false"
);
}
function canEnablePaste() {
const activeElement = document.activeElement;
return activeElement.tagName === "INPUT" || activeElement.tagName === "TEXTAREA" || isContentEditableBeingEdited();
}
function canEnableCopy() {
const sel = window.getSelection();
if (!util.isBlank(sel?.toString()) || isInNonTermInput) {
getApi().contextEditMenu({ x: e.clientX, y: e.clientY }, opts);
} else {
getApi().contextEditMenu({ x: e.clientX, y: e.clientY }, { onlyPaste: true });
return !util.isBlank(sel?.toString());
}
function canEnableCut() {
const sel = window.getSelection();
if (document.activeElement?.classList.contains("xterm-helper-textarea")) {
return false;
}
return !util.isBlank(sel?.toString()) && canEnablePaste();
}
function handleContextMenu(e: React.MouseEvent<HTMLDivElement>) {
e.preventDefault();
const canPaste = canEnablePaste();
const canCopy = canEnableCopy();
const canCut = canEnableCut();
if (!canPaste && !canCopy && !canCut) {
return;
}
let menu: ContextMenuItem[] = [];
if (canCut) {
menu.push({ label: "Cut", role: "cut" });
}
if (canCopy) {
menu.push({ label: "Copy", role: "copy" });
}
if (canPaste) {
menu.push({ label: "Paste", role: "paste" });
}
ContextMenuModel.showContextMenu(menu, e);
}
function switchTab(offset: number) {

View file

@ -131,7 +131,7 @@ function getBlockHeaderText(blockIcon: string, blockData: Block, settings: Setti
return [blockIconElem, viewString + blockIdStr];
}
function handleHeaderContextMenu(e: React.MouseEvent<HTMLDivElement>, onClose: () => void) {
function handleHeaderContextMenu(e: React.MouseEvent<HTMLDivElement>, blockData: Block, onClose: () => void) {
e.preventDefault();
e.stopPropagation();
let menu: ContextMenuItem[] = [];
@ -148,6 +148,13 @@ function handleHeaderContextMenu(e: React.MouseEvent<HTMLDivElement>, onClose: (
},
});
menu.push({ type: "separator" });
menu.push({
label: "Copy BlockId",
click: () => {
navigator.clipboard.writeText(blockData.oid);
},
});
menu.push({ type: "separator" });
menu.push({
label: "Close Block",
click: onClose,
@ -236,7 +243,7 @@ const BlockFrame_Tech = ({
<div
className="block-frame-tech-header"
ref={dragHandleRef}
onContextMenu={(e) => handleHeaderContextMenu(e, onClose)}
onContextMenu={(e) => handleHeaderContextMenu(e, blockData, onClose)}
>
{getBlockHeaderText(blockIcon, blockData, settingsConfig)}
</div>

View file

@ -6,11 +6,6 @@ declare global {
blockId: string;
};
type ContextMenuOpts = {
showCut?: boolean;
onlyPaste?: boolean;
};
type Bounds = {
x: number;
y: number;
@ -37,7 +32,6 @@ declare global {
getPlatform: () => NodeJS.Platform;
contextEditMenu: (position: { x: number; y: number }, opts: ContextMenuOpts) => void;
showContextMenu: (menu: ElectronContextMenuItem[], position: { x: number; y: number }) => void;
onContextMenuClick: (callback: (id: string) => void) => void;
};