context menu working cut/copy/paste with some smarts about where it is displayed

This commit is contained in:
sawka
2023-01-02 14:52:53 -08:00
parent 7ccd842bf7
commit 988a6c92ff
6 changed files with 53 additions and 25 deletions
+14 -13
View File
@@ -354,17 +354,6 @@ function getContextMenu() : any {
return menu;
}
function getCutCopyPasteMenu() : any {
let menu = new electron.Menu();
let menuItem = new electron.MenuItem({label: "Cut", role: "cut"});
menu.append(menuItem);
menuItem = new electron.MenuItem({label: "Copy", role: "copy"});
menu.append(menuItem);
menuItem = new electron.MenuItem({label: "Paste", role: "paste"});
menu.append(menuItem);
return menu;
}
function getFetchHeaders() {
return {
"x-authkey": GlobalAuthKey,
@@ -448,9 +437,21 @@ electron.ipcMain.on("context-screen", (event, {screenId}, {x, y}) => {
menu.popup({x, y});
});
electron.ipcMain.on("context-editmenu", (event, {x, y}) => {
electron.ipcMain.on("context-editmenu", (event, {x, y}, opts) => {
if (opts == null) {
opts = {};
}
console.log("context-editmenu");
let menu = getCutCopyPasteMenu();
let menu = new electron.Menu();
let menuItem = null;
if (opts.showCut) {
menuItem = new electron.MenuItem({label: "Cut", role: "cut"});
menu.append(menuItem);
}
menuItem = new electron.MenuItem({label: "Copy", role: "copy"});
menu.append(menuItem);
menuItem = new electron.MenuItem({label: "Paste", role: "paste"});
menu.append(menuItem);
menu.popup({x, y});
});
+29 -2
View File
@@ -9,7 +9,7 @@ import dayjs from "dayjs";
import {If, For, When, Otherwise, Choose} from "tsx-control-statements/components";
import cn from "classnames";
import {TermWrap} from "./term";
import type {SessionDataType, LineType, CmdDataType, RemoteType, RemoteStateType, RemoteInstanceType, RemotePtrType, HistoryItem, HistoryQueryOpts, RemoteEditType, FeStateType} from "./types";
import type {SessionDataType, LineType, CmdDataType, RemoteType, RemoteStateType, RemoteInstanceType, RemotePtrType, HistoryItem, HistoryQueryOpts, RemoteEditType, FeStateType, ContextMenuOpts} from "./types";
import localizedFormat from 'dayjs/plugin/localizedFormat';
import {GlobalModel, GlobalCommandRunner, Session, Cmd, Window, Screen, ScreenWindow, riToRPtr, widthToCols, termWidthFromCols, termHeightFromRows, termRowsFromHeight} from "./model";
import {isModKeyPress} from "./util";
@@ -2672,9 +2672,36 @@ class Main extends React.Component<{}, {}> {
super(props);
}
@boundMethod
handleContextMenu(e : any) {
let isInNonTermInput = false;
let 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;
}
let opts : ContextMenuOpts = {};
if (isInNonTermInput) {
opts.showCut = true;
}
let sel = window.getSelection();
if (!isBlank(sel.toString())) {
GlobalModel.contextEditMenu(e, opts);
}
else {
if (isInNonTermInput) {
GlobalModel.contextEditMenu(e, opts);
}
}
}
render() {
return (
<div id="main">
<div id="main" onContextMenu={this.handleContextMenu}>
<div className="main-content">
<MainSideBar/>
<SessionView/>
+4 -4
View File
@@ -5,7 +5,7 @@ import {debounce} from "throttle-debounce";
import {handleJsonFetchResponse, base64ToArray, genMergeData, genMergeSimpleData, boundInt, isModKeyPress} from "./util";
import {TermWrap} from "./term";
import {v4 as uuidv4} from "uuid";
import type {SessionDataType, WindowDataType, LineType, RemoteType, HistoryItem, RemoteInstanceType, RemotePtrType, CmdDataType, FeCmdPacketType, TermOptsType, RemoteStateType, ScreenDataType, ScreenWindowType, ScreenOptsType, LayoutType, PtyDataUpdateType, ModelUpdateType, UpdateMessage, InfoType, CmdLineUpdateType, UIContextType, HistoryInfoType, HistoryQueryOpts, FeInputPacketType, TermWinSize, RemoteInputPacketType, FeStateType} from "./types";
import type {SessionDataType, WindowDataType, LineType, RemoteType, HistoryItem, RemoteInstanceType, RemotePtrType, CmdDataType, FeCmdPacketType, TermOptsType, RemoteStateType, ScreenDataType, ScreenWindowType, ScreenOptsType, LayoutType, PtyDataUpdateType, ModelUpdateType, UpdateMessage, InfoType, CmdLineUpdateType, UIContextType, HistoryInfoType, HistoryQueryOpts, FeInputPacketType, TermWinSize, RemoteInputPacketType, FeStateType, ContextMenuOpts} from "./types";
import {WSControl} from "./ws";
var GlobalUser = "sawka";
@@ -107,7 +107,7 @@ type ElectronApi = {
onBracketCmd : (callback : (event : any, arg : {relative : number}, mods : KeyModsType) => void) => void,
onDigitCmd : (callback : (event : any, arg : {digit : number}, mods : KeyModsType) => void) => void,
contextScreen : (screenOpts : {screenId : string}, position : {x : number, y : number}) => void,
contextEditMenu : (position : {x : number, y : number}) => void,
contextEditMenu : (position : {x : number, y : number}, opts : ContextMenuOpts) => void,
onLocalServerStatusChange : (callback : (status : boolean, pid : number) => void) => void,
};
@@ -1658,8 +1658,8 @@ class Model {
getApi().contextScreen({screenId: screenId}, {x: e.x, y: e.y});
}
contextEditMenu(e : any) {
getApi().contextEditMenu({x: e.x, y: e.y});
contextEditMenu(e : any, opts : ContextMenuOpts) {
getApi().contextEditMenu({x: e.x, y: e.y}, opts);
}
getUIContext() : UIContextType {
+1 -1
View File
@@ -18,6 +18,6 @@ contextBridge.exposeInMainWorld("api", {
onBracketCmd: (callback) => ipcRenderer.on("bracket-cmd", callback),
onDigitCmd: (callback) => ipcRenderer.on("digit-cmd", callback),
contextScreen: (screenOpts, position) => ipcRenderer.send("context-screen", screenOpts, position),
contextEditMenu: (position) => ipcRenderer.send("context-editmenu", position),
contextEditMenu: (position, opts) => ipcRenderer.send("context-editmenu", position, opts),
onLocalServerStatusChange: (callback) => ipcRenderer.on("local-server-status-change", callback),
});
-4
View File
@@ -108,10 +108,6 @@ class TermWrap {
this.terminal.attachCustomKeyEventHandler((e) => opts.customKeyHandler(e, this));
}
this.reloadTerminal(0);
elem.addEventListener("contextmenu", (e) => {
console.log("elem-contextmenu", elem, e);
GlobalModel.contextEditMenu(e);
});
}
@boundMethod
+5 -1
View File
@@ -327,6 +327,10 @@ type HistoryQueryOpts = {
fromTs : number,
};
type ContextMenuOpts = {
showCut? : boolean,
};
type UpdateMessage = PtyDataUpdateType | ModelUpdateType;
export type {SessionDataType, LineType, RemoteType, RemoteStateType, RemoteInstanceType, WindowDataType, HistoryItem, CmdRemoteStateType, FeCmdPacketType, TermOptsType, CmdStartPacketType, CmdDataType, ScreenDataType, ScreenOptsType, ScreenWindowType, LayoutType, PtyDataUpdateType, ModelUpdateType, UpdateMessage, InfoType, CmdLineUpdateType, RemotePtrType, UIContextType, HistoryInfoType, HistoryQueryOpts, WatchScreenPacketType, TermWinSize, FeInputPacketType, RemoteInputPacketType, RemoteEditType, FeStateType};
export type {SessionDataType, LineType, RemoteType, RemoteStateType, RemoteInstanceType, WindowDataType, HistoryItem, CmdRemoteStateType, FeCmdPacketType, TermOptsType, CmdStartPacketType, CmdDataType, ScreenDataType, ScreenOptsType, ScreenWindowType, LayoutType, PtyDataUpdateType, ModelUpdateType, UpdateMessage, InfoType, CmdLineUpdateType, RemotePtrType, UIContextType, HistoryInfoType, HistoryQueryOpts, WatchScreenPacketType, TermWinSize, FeInputPacketType, RemoteInputPacketType, RemoteEditType, FeStateType, ContextMenuOpts};