diff --git a/app/src/boot/globalEvent/keydown.ts b/app/src/boot/globalEvent/keydown.ts index 36d3be22f..f04001716 100644 --- a/app/src/boot/globalEvent/keydown.ts +++ b/app/src/boot/globalEvent/keydown.ts @@ -71,6 +71,7 @@ import {filterHotkey} from "./commonHotkey"; import {setReadOnly} from "../../config/util/setReadOnly"; import {copyPNGByLink} from "../../menus/util"; import {globalCommand} from "./command/global"; +import {duplicateCompletely} from "../../protyle/render/av/action"; const switchDialogEvent = (app: App, event: MouseEvent) => { event.preventDefault(); diff --git a/app/src/constants.ts b/app/src/constants.ts index e4e0ecbe4..7cc47083c 100644 --- a/app/src/constants.ts +++ b/app/src/constants.ts @@ -357,19 +357,6 @@ export abstract class Constants { duplicate: {default: "⌘D", custom: "⌘D"}, expandDown: {default: "⌥⇧↓", custom: "⌥⇧↓"}, expandUp: {default: "⌥⇧↑", custom: "⌥⇧↑"}, - copyPlainText: {default: "", custom: ""}, - copyID: {default: "", custom: ""}, - copyProtocolInMd: {default: "", custom: ""}, - netImg2LocalAsset: {default: "", custom: ""}, - netAssets2LocalAssets: {default: "", custom: ""}, - optimizeTypography: {default: "", custom: ""}, - hLayout: {default: "", custom: ""}, - vLayout: {default: "", custom: ""}, - refPopover: {default: "", custom: ""}, - copyText: {default: "", custom: ""}, - exitFocus: {default: "", custom: ""}, - ai: {default: "", custom: ""}, - switchReadonly: {default: "", custom: ""}, expand: {default: "⌘↓", custom: "⌘↓"}, collapse: {default: "⌘↑", custom: "⌘↑"}, insertBottom: {default: "⌥⌘.", custom: "⌥⌘."}, @@ -406,7 +393,21 @@ export abstract class Constants { jumpToParentPrev: {default: "⇧⌘M", custom: "⇧⌘M"}, jumpToParent: {default: "⇧⌘J", custom: "⇧⌘J"}, moveToUp: {default: "⇧⌘↑", custom: "⇧⌘↑"}, - moveToDown: {default: "⇧⌘↓", custom: "⇧⌘↓"} + moveToDown: {default: "⇧⌘↓", custom: "⇧⌘↓"}, + duplicateCompletely: {default: "", custom: ""}, + copyPlainText: {default: "", custom: ""}, + copyID: {default: "", custom: ""}, + copyProtocolInMd: {default: "", custom: ""}, + netImg2LocalAsset: {default: "", custom: ""}, + netAssets2LocalAssets: {default: "", custom: ""}, + optimizeTypography: {default: "", custom: ""}, + hLayout: {default: "", custom: ""}, + vLayout: {default: "", custom: ""}, + refPopover: {default: "", custom: ""}, + copyText: {default: "", custom: ""}, + exitFocus: {default: "", custom: ""}, + ai: {default: "", custom: ""}, + switchReadonly: {default: "", custom: ""}, }, insert: { appearance: {default: "⌥⌘X", custom: "⌥⌘X"}, diff --git a/app/src/menus/commonMenuItem.ts b/app/src/menus/commonMenuItem.ts index 25a0768fb..0c45f0272 100644 --- a/app/src/menus/commonMenuItem.ts +++ b/app/src/menus/commonMenuItem.ts @@ -372,7 +372,7 @@ export const openAttr = (nodeElement: Element, focusName = "bookmark", protyle?: export const copySubMenu = (id: string, accelerator = true, focusElement?: Element) => { return [{ - icon: "iconRef", + iconHTML: "", accelerator: accelerator ? window.siyuan.config.keymap.editor.general.copyBlockRef.custom : undefined, label: window.siyuan.languages.copyBlockRef, click: () => { @@ -384,7 +384,7 @@ export const copySubMenu = (id: string, accelerator = true, focusElement?: Eleme } } }, { - icon: "iconSQL", + iconHTML: "", label: window.siyuan.languages.copyBlockEmbed, accelerator: accelerator ? window.siyuan.config.keymap.editor.general.copyBlockEmbed.custom : undefined, click: () => { @@ -394,7 +394,7 @@ export const copySubMenu = (id: string, accelerator = true, focusElement?: Eleme } } }, { - icon: "iconSiYuan", + iconHTML: "", label: window.siyuan.languages.copyProtocol, accelerator: accelerator ? window.siyuan.config.keymap.editor.general.copyProtocol.custom : undefined, click: () => { @@ -404,6 +404,7 @@ export const copySubMenu = (id: string, accelerator = true, focusElement?: Eleme } } }, { + iconHTML: "", label: window.siyuan.languages.copyProtocolInMd, accelerator: accelerator ? window.siyuan.config.keymap.editor.general.copyProtocolInMd.custom : undefined, click: () => { @@ -415,6 +416,7 @@ export const copySubMenu = (id: string, accelerator = true, focusElement?: Eleme } } }, { + iconHTML: "", label: window.siyuan.languages.copyHPath, accelerator: accelerator ? window.siyuan.config.keymap.editor.general.copyHPath.custom : undefined, click: () => { @@ -425,6 +427,7 @@ export const copySubMenu = (id: string, accelerator = true, focusElement?: Eleme }); } }, { + iconHTML: "", label: window.siyuan.languages.copyID, accelerator: accelerator ? window.siyuan.config.keymap.editor.general.copyID.custom : undefined, click: () => { diff --git a/app/src/menus/navigation.ts b/app/src/menus/navigation.ts index 47ea5c179..afcf178dd 100644 --- a/app/src/menus/navigation.ts +++ b/app/src/menus/navigation.ts @@ -424,6 +424,7 @@ export const initFileMenu = (app: App, notebookId: string, pathString: string, l type: "submenu", icon: "iconCopy", submenu: (copySubMenu(id, false) as IMenu[]).concat([{ + iconHTML: "", label: window.siyuan.languages.duplicate, accelerator: window.siyuan.config.keymap.editor.general.duplicate.custom, click() { diff --git a/app/src/protyle/gutter/index.ts b/app/src/protyle/gutter/index.ts index e3bf23bd2..7e91e4caf 100644 --- a/app/src/protyle/gutter/index.ts +++ b/app/src/protyle/gutter/index.ts @@ -52,11 +52,10 @@ import {setPosition} from "../../util/setPosition"; import {avRender} from "../render/av/render"; import {emitOpenMenu} from "../../plugin/EventBus"; import {insertAttrViewBlockAnimation} from "../render/av/row"; -import {avContextmenu} from "../render/av/action"; +import {avContextmenu, duplicateCompletely} from "../render/av/action"; import {getPlainText} from "../util/paste"; import {Menu} from "../../plugin/Menu"; import {addEditorToDatabase} from "../render/av/addToDatabase"; -import {scrollCenter} from "../../util/highlightById"; export class Gutter { public element: HTMLElement; @@ -757,6 +756,7 @@ export class Gutter { }).element); } const copyMenu: IMenu[] = [{ + iconHTML: "", label: window.siyuan.languages.copy, accelerator: "⌘C", click() { @@ -768,6 +768,7 @@ export class Gutter { document.execCommand("copy"); } }, { + iconHTML: "", label: window.siyuan.languages.copyPlainText, accelerator: window.siyuan.config.keymap.editor.general.copyPlainText.custom, click() { @@ -779,6 +780,7 @@ export class Gutter { focusBlock(selectsElement[0]); } }, { + iconHTML: "", label: window.siyuan.languages.duplicate, accelerator: window.siyuan.config.keymap.editor.general.duplicate.custom, disabled: protyle.disabled, @@ -1213,6 +1215,7 @@ export class Gutter { } const copyMenu = (copySubMenu(id, true, nodeElement) as IMenu[]).concat([{ + iconHTML: "", label: window.siyuan.languages.copyPlainText, accelerator: window.siyuan.config.keymap.editor.general.copyPlainText.custom, click() { @@ -1220,6 +1223,7 @@ export class Gutter { focusBlock(nodeElement); } }, { + iconHTML: "", label: type === "NodeAttributeView" ? window.siyuan.languages.copyMirror : window.siyuan.languages.copy, accelerator: "⌘C", click() { @@ -1231,6 +1235,7 @@ export class Gutter { document.execCommand("copy"); } }, { + iconHTML: "", label: type === "NodeAttributeView" ? window.siyuan.languages.duplicateMirror : window.siyuan.languages.duplicate, accelerator: window.siyuan.config.keymap.editor.general.duplicate.custom, disabled: protyle.disabled, @@ -1240,27 +1245,10 @@ export class Gutter { }]); if (type === "NodeAttributeView") { copyMenu.push({ + iconHTML: "", label: window.siyuan.languages.duplicateCompletely, click() { - fetchPost("/api/av/duplicateAttributeViewBlock", {avID: nodeElement.getAttribute("data-av-id")}, (response) => { - const tempElement = document.createElement("template"); - tempElement.innerHTML = protyle.lute.SpinBlockDOM(`
`) - const cloneElement = tempElement.content.firstElementChild; - nodeElement.after(cloneElement); - avRender(cloneElement, protyle, () => { - focusBlock(cloneElement); - }); - scrollCenter(protyle); - transaction(protyle, [{ - action: "insert", - data: cloneElement.outerHTML, - id: response.data.blockID, - previousID: id, - }], [{ - action: "delete", - id: response.data.blockID, - }]); - }); + duplicateCompletely(protyle, nodeElement as HTMLElement); } }); } @@ -2008,6 +1996,7 @@ export class Gutter { return false; } return { + iconHTML: "", accelerator: window.siyuan.config.keymap.editor.general.copyText.custom, label: window.siyuan.languages.copyText, click() { diff --git a/app/src/protyle/render/av/action.ts b/app/src/protyle/render/av/action.ts index f1055ab1e..6303cd602 100644 --- a/app/src/protyle/render/av/action.ts +++ b/app/src/protyle/render/av/action.ts @@ -19,7 +19,7 @@ import {deleteRow, insertRows, selectRow, setPageSize, updateHeader} from "./row import {emitOpenMenu} from "../../../plugin/EventBus"; import {openMenuPanel} from "./openMenuPanel"; import {hintRef} from "../../hint/extend"; -import {focusByRange} from "../../util/selection"; +import {focusBlock, focusByRange} from "../../util/selection"; import {showMessage} from "../../../dialog/message"; import {previewImage} from "../../preview/image"; import {unicode2Emoji} from "../../../emoji"; @@ -31,6 +31,8 @@ import {isOnlyMeta, writeText} from "../../util/compatibility"; import {openSearchAV} from "./relation"; import {Constants} from "../../../constants"; import {hideElements} from "../../ui/hideElements"; +import {fetchPost} from "../../../util/fetch"; +import {scrollCenter} from "../../../util/highlightById"; export const avClick = (protyle: IProtyle, event: MouseEvent & { target: HTMLElement }) => { if (isOnlyMeta(event)) { @@ -489,3 +491,25 @@ export const removeAttrViewColAnimation = (blockElement: Element, id: string) => item.remove(); }); }; + +export const duplicateCompletely = (protyle:IProtyle, nodeElement:HTMLElement) => { + fetchPost("/api/av/duplicateAttributeViewBlock", {avID: nodeElement.getAttribute("data-av-id")}, (response) => { + const tempElement = document.createElement("template"); + tempElement.innerHTML = protyle.lute.SpinBlockDOM(`
`) + const cloneElement = tempElement.content.firstElementChild; + nodeElement.after(cloneElement); + avRender(cloneElement, protyle, () => { + focusBlock(cloneElement); + }); + scrollCenter(protyle); + transaction(protyle, [{ + action: "insert", + data: cloneElement.outerHTML, + id: response.data.blockID, + previousID: nodeElement.dataset.nodeId, + }], [{ + action: "delete", + id: response.data.blockID, + }]); + }); +}