diff --git a/app/electron/main.js b/app/electron/main.js index 76308e509..c0407376d 100644 --- a/app/electron/main.js +++ b/app/electron/main.js @@ -15,7 +15,19 @@ // along with this program. If not, see . const { - net, app, BrowserWindow, shell, Menu, screen, ipcMain, globalShortcut, Tray, dialog, systemPreferences, powerMonitor + net, + app, + BrowserWindow, + shell, + Menu, + MenuItem, + screen, + ipcMain, + globalShortcut, + Tray, + dialog, + systemPreferences, + powerMonitor } = require("electron"); const path = require("path"); const fs = require("fs"); @@ -381,10 +393,8 @@ const boot = () => { label: `Quit ${productName}`, role: "quit", },], }, { - role: "editMenu", - submenu: [{role: "cut"}, {role: "copy"}, {role: "paste"}, { - role: "pasteAndMatchStyle", - accelerator: "CmdOrCtrl+Shift+C" + role: "editMenu", submenu: [{role: "cut"}, {role: "copy"}, {role: "paste"}, { + role: "pasteAndMatchStyle", accelerator: "CmdOrCtrl+Shift+C" }, {role: "selectAll"},], }, { role: "windowMenu", @@ -685,7 +695,27 @@ app.whenReady().then(() => { const getWindowByContentId = (id) => { return BrowserWindow.getAllWindows().find((win) => win.webContents.id === id); }; - + ipcMain.on("siyuan-context-menu", (event, langs) => { + const template = [new MenuItem({ + role: "undo", label: langs.undo + }), new MenuItem({ + role: "redo", label: langs.redo + }), {type: "separator"}, new MenuItem({ + role: "copy", label: langs.copy + }), new MenuItem({ + role: "cut", label: langs.cut + }), new MenuItem({ + role: "delete", label: langs.delete + }), new MenuItem({ + role: "paste", label: langs.paste + }), new MenuItem({ + role: "pasteAndMatchStyle", label: langs.pasteAsPlainText + }), new MenuItem({ + role: "selectAll", label: langs.selectAll + })]; + const menu = Menu.buildFromTemplate(template) + menu.popup({window: BrowserWindow.fromWebContents(event.sender)}) + }); ipcMain.on("siyuan-open-folder", (event, filePath) => { shell.showItemInFolder(filePath); }); @@ -892,8 +922,7 @@ app.whenReady().then(() => { }); ipcMain.on("siyuan-export-pdf", (event, data) => { dialog.showOpenDialog({ - title: data.title, - properties: ["createDirectory", "openDirectory"], + title: data.title, properties: ["createDirectory", "openDirectory"], }).then((result) => { if (result.canceled) { event.sender.destroy(); diff --git a/app/src/constants.ts b/app/src/constants.ts index c316b7965..5f87f49d2 100644 --- a/app/src/constants.ts +++ b/app/src/constants.ts @@ -55,6 +55,8 @@ export abstract class Constants { public static readonly SIYUAN_EXPORT_PDF: string = "siyuan-export-pdf"; public static readonly SIYUAN_EXPORT_NEWWINDOW: string = "siyuan-export-newwindow"; + public static readonly SIYUAN_CONTEXT_MENU: string = "siyuan-context-menu"; + // custom public static readonly CUSTOM_SY_READONLY: string = "custom-sy-readonly"; public static readonly CUSTOM_SY_FULLWIDTH: string = "custom-sy-fullwidth"; diff --git a/app/src/layout/dock/index.ts b/app/src/layout/dock/index.ts index 7a4272685..92590871c 100644 --- a/app/src/layout/dock/index.ts +++ b/app/src/layout/dock/index.ts @@ -30,7 +30,7 @@ export class Dock { public resizeElement: HTMLElement; public pin = true; public data: { [key: string]: Model | boolean }; - private hideResizeTimeout:number; + private hideResizeTimeout: number; constructor(options: { app: App, diff --git a/app/src/menus/Menu.ts b/app/src/menus/Menu.ts index 461c92f4e..c0ec5fe69 100644 --- a/app/src/menus/Menu.ts +++ b/app/src/menus/Menu.ts @@ -110,9 +110,9 @@ export class Menu { this.element.classList.add("fn__none"); this.element.classList.remove("b3-menu--list", "b3-menu--fullscreen"); this.element.removeAttribute("style"); // zIndex - window.siyuan.menus.menu.element.removeAttribute("data-name"); // 标识再次点击不消失 - window.siyuan.menus.menu.element.removeAttribute("data-from"); // 标识是否在浮窗内打开 - window.siyuan.menus.menu.data = undefined; // 移除数据 + this.element.removeAttribute("data-name"); // 标识再次点击不消失 + this.element.removeAttribute("data-from"); // 标识是否在浮窗内打开 + this.data = undefined; // 移除数据 } public append(element?: HTMLElement, index?: number) { @@ -136,7 +136,7 @@ export class Menu { window.addEventListener(isMobile() ? "touchmove" : this.wheelEvent, this.preventDefault, {passive: false}); this.element.style.zIndex = (++window.siyuan.zIndex).toString(); this.element.classList.remove("fn__none"); - setPosition(this.element, options.x - (options.isLeft ? window.siyuan.menus.menu.element.clientWidth : 0), options.y, options.h, options.w); + setPosition(this.element, options.x - (options.isLeft ? this.element.clientWidth : 0), options.y, options.h, options.w); } public fullscreen(position: "bottom" | "all" = "all") { diff --git a/app/src/menus/index.ts b/app/src/menus/index.ts index 15e9ee36c..ea151aa50 100644 --- a/app/src/menus/index.ts +++ b/app/src/menus/index.ts @@ -6,9 +6,13 @@ import {initDockMenu} from "./dock"; import {initFileMenu, initNavigationMenu} from "./navigation"; import {initTabMenu} from "./tab"; /// #endif -import {Menu, MenuItem} from "./Menu"; +/// #if !BROWSER +import {ipcRenderer} from "electron"; +/// #endif +import {Menu} from "./Menu"; import {hasClosestByClassName, hasTopClosestByTag} from "../protyle/util/hasClosest"; import {App} from "../index"; +import {Constants} from "../constants"; export class Menus { @@ -25,11 +29,28 @@ export class Menus { if (hasClosestByClassName(target, "av__panel") && !hasClosestByClassName(target, "b3-menu")) { document.querySelector(".av__panel").dispatchEvent(new CustomEvent("click", {detail: "close"})); event.stopPropagation(); + event.preventDefault(); return; } + if (target.classList.contains("b3-text-field")) { + /// #if !BROWSER + ipcRenderer.send(Constants.SIYUAN_CONTEXT_MENU, { + undo: window.siyuan.languages.undo, + redo: window.siyuan.languages.redo, + copy: window.siyuan.languages.copy, + cut: window.siyuan.languages.cut, + delete: window.siyuan.languages.delete, + paste: window.siyuan.languages.paste, + pasteAsPlainText: window.siyuan.languages.pasteAsPlainText, + selectAll: window.siyuan.languages.selectAll, + }); + /// #endif + event.stopPropagation(); + } else { + event.preventDefault(); + } while (target && target.parentElement // ⌃⇥ 后点击会为空 && !target.parentElement.isEqualNode(document.querySelector("body"))) { - event.preventDefault(); const dataType = target.getAttribute("data-type"); if (dataType === "tab-header") { this.unselect(); @@ -68,52 +89,6 @@ export class Menus { initDockMenu(target).popup({x: event.clientX, y: event.clientY}); event.stopPropagation(); break; - } else if (target.classList.contains("b3-text-field")) { - window.siyuan.menus.menu.remove(); - if ((target as HTMLInputElement).selectionStart !== (target as HTMLInputElement).selectionEnd) { - window.siyuan.menus.menu.append(new MenuItem({ - icon: "iconCopy", - accelerator: "⌘C", - label: window.siyuan.languages.copy, - click: () => { - document.execCommand("copy"); - } - }).element); - window.siyuan.menus.menu.append(new MenuItem({ - icon: "iconCut", - accelerator: "⌘X", - label: window.siyuan.languages.cut, - click: () => { - document.execCommand("cut"); - } - }).element); - window.siyuan.menus.menu.append(new MenuItem({ - icon: "iconTrashcan", - accelerator: "⌫", - label: window.siyuan.languages.delete, - click: () => { - document.execCommand("delete"); - } - }).element); - } - window.siyuan.menus.menu.append(new MenuItem({ - label: window.siyuan.languages.paste, - icon: "iconPaste", - accelerator: "⌘V", - click: async () => { - document.execCommand("paste"); - } - }).element); - window.siyuan.menus.menu.append(new MenuItem({ - label: window.siyuan.languages.selectAll, - icon: "iconSelect", - accelerator: "⌘A", - click: () => { - document.execCommand("selectAll"); - } - }).element); - window.siyuan.menus.menu.popup({x: event.clientX, y: event.clientY}); - target.focus() } target = target.parentElement; }