mirror of
https://github.com/wavetermdev/waveterm
synced 2026-05-06 06:58:21 +00:00
fix cut/copy/paste menu
This commit is contained in:
parent
cc46cf64df
commit
997940949a
5 changed files with 55 additions and 48 deletions
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
});
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
6
frontend/types/custom.d.ts
vendored
6
frontend/types/custom.d.ts
vendored
|
|
@ -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;
|
||||
};
|
||||
|
|
|
|||
Loading…
Reference in a new issue