This commit is contained in:
Vanessa 2023-05-30 00:27:47 +08:00
parent 52c9b5fbca
commit 4b02a8a846
11 changed files with 197 additions and 22 deletions

View file

@ -265,7 +265,7 @@
"importDataTip": "Import the exported zip archive, overwriting the <code class='fn__code'>workspace/data/</code> folder by path", "importDataTip": "Import the exported zip archive, overwriting the <code class='fn__code'>workspace/data/</code> folder by path",
"includeChildDoc": "Include child documents", "includeChildDoc": "Include child documents",
"text": "Text", "text": "Text",
"lastUsed": "Apariencia usada recientemente", "lastUsed": "Recently used appearance",
"removedNotebook": "Removed notebook", "removedNotebook": "Removed notebook",
"querySyntax": "Query Syntax", "querySyntax": "Query Syntax",
"rollback": "Rollback", "rollback": "Rollback",

View file

@ -265,7 +265,7 @@
"importDataTip": "Importar el archivo zip exportado, sobrescribiendo la carpeta <code class='fn__code'>workspace/data/</code> por la ruta", "importDataTip": "Importar el archivo zip exportado, sobrescribiendo la carpeta <code class='fn__code'>workspace/data/</code> por la ruta",
"includeChildDoc": "Incluir los documentos de los niños", "includeChildDoc": "Incluir los documentos de los niños",
"text": "Texto", "text": "Texto",
"lastUsed": "Fuentes utilizadas apariencia", "lastUsed": "Apariencia usada recientemente",
"removedNotebook": "Cuaderno de notas eliminado", "removedNotebook": "Cuaderno de notas eliminado",
"querySyntax": "Sintaxis de consulta", "querySyntax": "Sintaxis de consulta",
"rollback": "Rollback", "rollback": "Rollback",

View file

@ -265,7 +265,7 @@
"importDataTip": "将导出的 zip 压缩包导入,按路径覆盖 <code class='fn__code'>工作空间/data/</code> 文件夹", "importDataTip": "将导出的 zip 压缩包导入,按路径覆盖 <code class='fn__code'>工作空间/data/</code> 文件夹",
"includeChildDoc": "包含子文档", "includeChildDoc": "包含子文档",
"text": "文本", "text": "文本",
"lastUsed": "Recently used appearance", "lastUsed": "最近使用的外观",
"removedNotebook": "已删除的笔记本", "removedNotebook": "已删除的笔记本",
"querySyntax": "查询语法", "querySyntax": "查询语法",
"rollback": "回滚", "rollback": "回滚",

View file

@ -802,10 +802,29 @@ export const globalShortcut = (app: App) => {
} }
// 面板的操作 // 面板的操作
if (!isTabWindow && panelTreeKeydown(event)) { if (!isTabWindow && panelTreeKeydown(app, event)) {
return; return;
} }
let matchCommand = false;
app.plugins.find(item => {
item.commands.find(command => {
if (command.callback &&
!command.fileTreeCallback && !command.editorCallback&& !command.dockCallback
&& matchHotKey(command.customHotkey, event)) {
matchCommand = true;
command.callback();
return true;
}
});
if (matchCommand) {
return true;
}
});
if (matchCommand) {
return true;
}
let searchKey = ""; let searchKey = "";
if (matchHotKey(window.siyuan.config.keymap.general.replace.custom, event)) { if (matchHotKey(window.siyuan.config.keymap.general.replace.custom, event)) {
searchKey = window.siyuan.config.keymap.general.replace.custom; searchKey = window.siyuan.config.keymap.general.replace.custom;
@ -1112,6 +1131,24 @@ const fileTreeKeydown = (app: App, event: KeyboardEvent) => {
return false; return false;
} }
const files = dockFile.data.file as Files; const files = dockFile.data.file as Files;
let matchCommand = false;
app.plugins.find(item => {
item.commands.find(command => {
if (command.fileTreeCallback && matchHotKey(command.customHotkey, event)) {
matchCommand = true;
command.fileTreeCallback(files);
return true;
}
});
if (matchCommand) {
return true;
}
});
if (matchCommand) {
return true;
}
if (matchHotKey(window.siyuan.config.keymap.general.selectOpen1.custom, event)) { if (matchHotKey(window.siyuan.config.keymap.general.selectOpen1.custom, event)) {
event.preventDefault(); event.preventDefault();
const element = document.querySelector(".layout__wnd--active > .fn__flex > .layout-tab-bar > .item--focus") || const element = document.querySelector(".layout__wnd--active > .fn__flex > .layout-tab-bar > .item--focus") ||
@ -1402,7 +1439,7 @@ const fileTreeKeydown = (app: App, event: KeyboardEvent) => {
} }
}; };
const panelTreeKeydown = (event: KeyboardEvent) => { const panelTreeKeydown = (app: App, event: KeyboardEvent) => {
// 面板折叠展开操作 // 面板折叠展开操作
const target = event.target as HTMLElement; const target = event.target as HTMLElement;
if (target.tagName === "INPUT" || target.tagName === "TEXTAREA" || if (target.tagName === "INPUT" || target.tagName === "TEXTAREA" ||
@ -1451,6 +1488,23 @@ const panelTreeKeydown = (event: KeyboardEvent) => {
activePanelElement.classList.contains("sy__graph")) { activePanelElement.classList.contains("sy__graph")) {
return false; return false;
} }
let matchCommand = false;
app.plugins.find(item => {
item.commands.find(command => {
if (command.dockCallback && matchHotKey(command.customHotkey, event)) {
matchCommand = true;
command.dockCallback(activePanelElement as HTMLElement);
return true;
}
});
if (matchCommand) {
return true;
}
});
if (matchCommand) {
return true;
}
const model = (getInstanceById(activePanelElement.getAttribute("data-id"), window.siyuan.layout.layout) as Tab)?.model; const model = (getInstanceById(activePanelElement.getAttribute("data-id"), window.siyuan.layout.layout) as Tab)?.model;
if (!model) { if (!model) {
return false; return false;

View file

@ -85,6 +85,38 @@ const hasKeymap = (keymap: Record<string, IKeymapItem>, key1: "general" | "edito
return match; return match;
}; };
const mergePluginHotkey = (app: App) => {
if (!window.siyuan.config.keymap.plugin) {
window.siyuan.config.keymap.plugin = {};
}
app.plugins.forEach(plugin => {
plugin.commands.forEach(command => {
if (!window.siyuan.config.keymap.plugin[plugin.name]) {
command.customHotkey = command.hotkey;
window.siyuan.config.keymap.plugin[plugin.name] = {
[command.langKey]: {
default: command.hotkey,
custom: command.hotkey,
}
};
return
}
if (!window.siyuan.config.keymap.plugin[plugin.name][command.langKey]) {
command.customHotkey = command.hotkey;
window.siyuan.config.keymap.plugin[plugin.name][command.langKey] = {
default: command.hotkey,
custom: command.hotkey,
}
return;
}
if (window.siyuan.config.keymap.plugin[plugin.name][command.langKey]) {
command.customHotkey = window.siyuan.config.keymap.plugin[plugin.name][command.langKey].custom || command.hotkey;
window.siyuan.config.keymap.plugin[plugin.name][command.langKey]["default"] = command.hotkey
}
})
})
}
export const onGetConfig = (isStart: boolean, app: App) => { export const onGetConfig = (isStart: boolean, app: App) => {
const matchKeymap1 = matchKeymap(Constants.SIYUAN_KEYMAP.general, "general"); const matchKeymap1 = matchKeymap(Constants.SIYUAN_KEYMAP.general, "general");
const matchKeymap2 = matchKeymap(Constants.SIYUAN_KEYMAP.editor.general, "editor", "general"); const matchKeymap2 = matchKeymap(Constants.SIYUAN_KEYMAP.editor.general, "editor", "general");
@ -99,6 +131,7 @@ export const onGetConfig = (isStart: boolean, app: App) => {
const hasKeymap4 = hasKeymap(Constants.SIYUAN_KEYMAP.editor.heading, "editor", "heading"); const hasKeymap4 = hasKeymap(Constants.SIYUAN_KEYMAP.editor.heading, "editor", "heading");
const hasKeymap5 = hasKeymap(Constants.SIYUAN_KEYMAP.editor.list, "editor", "list"); const hasKeymap5 = hasKeymap(Constants.SIYUAN_KEYMAP.editor.list, "editor", "list");
const hasKeymap6 = hasKeymap(Constants.SIYUAN_KEYMAP.editor.table, "editor", "table"); const hasKeymap6 = hasKeymap(Constants.SIYUAN_KEYMAP.editor.table, "editor", "table");
mergePluginHotkey(app);
if (!window.siyuan.config.readonly && if (!window.siyuan.config.readonly &&
(!matchKeymap1 || !matchKeymap2 || !matchKeymap3 || !matchKeymap4 || !matchKeymap5 || !matchKeymap6 || (!matchKeymap1 || !matchKeymap2 || !matchKeymap3 || !matchKeymap4 || !matchKeymap5 || !matchKeymap6 ||
!hasKeymap1 || !hasKeymap2 || !hasKeymap3 || !hasKeymap4 || !hasKeymap5 || !hasKeymap6)) { !hasKeymap1 || !hasKeymap2 || !hasKeymap3 || !hasKeymap4 || !hasKeymap5 || !hasKeymap6)) {

View file

@ -48,7 +48,7 @@ export const genItemPanel = (type: string, containerElement: Element, app: App)
appearance.bindEvent(); appearance.bindEvent();
break; break;
case "keymap": case "keymap":
containerElement.innerHTML = keymap.genHTML(); containerElement.innerHTML = keymap.genHTML(app);
keymap.element = containerElement; keymap.element = containerElement;
keymap.bindEvent(); keymap.bindEvent();
break; break;

View file

@ -8,6 +8,7 @@ import {getCurrentWindow} from "@electron/remote";
import {ipcRenderer} from "electron"; import {ipcRenderer} from "electron";
/// #endif /// #endif
import {confirmDialog} from "../dialog/confirmDialog"; import {confirmDialog} from "../dialog/confirmDialog";
import {App} from "../index";
export const keymap = { export const keymap = {
element: undefined as Element, element: undefined as Element,
@ -25,13 +26,55 @@ export const keymap = {
<svg><use xlink:href="#iconTrashcan"></use></svg> <svg><use xlink:href="#iconTrashcan"></use></svg>
</span> </span>
<span data-type="update" class="config-keymap__key">${keyValue}</span> <span data-type="update" class="config-keymap__key">${keyValue}</span>
<input data-key="${keys + Constants.ZWSP + key}" data-value="${keymap[key].custom}" data-default="${keymap[key].default}" class="b3-text-field fn__none" value="${updateHotkeyTip(keymap[key].custom)}" spellcheck="false"> <input data-key="${keys + Constants.ZWSP + key}" data-value="${keymap[key].custom}" data-default="${keymap[key].default}" class="b3-text-field fn__none" value="${keyValue}" spellcheck="false">
</label>`; </label>`;
} }
}); });
return html; return html;
}, },
genHTML() { genHTML(app: App) {
let pluginHtml = ''
app.plugins.forEach(item => {
let commandHTML = ''
item.commands.forEach(command => {
const keyValue = updateHotkeyTip(command.customHotkey);
commandHTML += `<label class="b3-list-item b3-list-item--narrow b3-list-item--hide-action">
<span class="b3-list-item__text">${item.i18n[command.langKey]}</span>
<span data-type="reset" class="b3-list-item__action b3-tooltips b3-tooltips__w" aria-label="${window.siyuan.languages.reset}">
<svg><use xlink:href="#iconUndo"></use></svg>
</span>
<span data-type="clear" class="b3-list-item__action b3-tooltips b3-tooltips__w" aria-label="${window.siyuan.languages.remove}">
<svg><use xlink:href="#iconTrashcan"></use></svg>
</span>
<span data-type="update" class="config-keymap__key">${keyValue}</span>
<input data-key="plugin${Constants.ZWSP}${item.name}${Constants.ZWSP}${command.langKey}" data-value="${command.customHotkey}" data-default="${command.hotkey}" class="b3-text-field fn__none" value="${keyValue}" spellcheck="false">
</label>`;
});
if (commandHTML) {
pluginHtml += `<div class="b3-list__panel">
<div class="b3-list-item b3-list-item--narrow toggle">
<span class="b3-list-item__toggle b3-list-item__toggle--hl">
<svg class="b3-list-item__arrow"><use xlink:href="#iconRight"></use></svg>
</span>
<span class="b3-list-item__text ft__on-surface">${item.name}</span>
</div>
<div class="fn__none b3-list__panel">
${commandHTML}
</div>
</div>`
}
})
if (pluginHtml) {
pluginHtml = `<div class="b3-list b3-list--border b3-list--background">
<div class="b3-list-item b3-list-item--narrow toggle">
<span class="b3-list-item__toggle b3-list-item__toggle--hl">
<svg class="b3-list-item__arrow b3-list-item__arrow--open"><use xlink:href="#iconRight"></use></svg>
</span>
<span class="b3-list-item__text ft__on-surface">${window.siyuan.languages.plugin}</span>
</div>
${pluginHtml}
</div>`
}
return `<label class="fn__flex b3-label config__item"> return `<label class="fn__flex b3-label config__item">
<span class="fn__flex-center">${window.siyuan.languages.keymapTip}</span> <span class="fn__flex-center">${window.siyuan.languages.keymapTip}</span>
<span class="fn__flex-1"></span> <span class="fn__flex-1"></span>
@ -119,13 +162,17 @@ export const keymap = {
<div class="fn__none b3-list__panel">${keymap._genItem(window.siyuan.config.keymap.editor.table, "editor" + Constants.ZWSP + "table")}</div> <div class="fn__none b3-list__panel">${keymap._genItem(window.siyuan.config.keymap.editor.table, "editor" + Constants.ZWSP + "table")}</div>
</div> </div>
</div> </div>
${pluginHtml}
</div>`; </div>`;
}, },
_setkeymap() { _setkeymap() {
const data: IKeymap = JSON.parse(JSON.stringify(Constants.SIYUAN_KEYMAP)); const data: IKeymap = JSON.parse(JSON.stringify(Constants.SIYUAN_KEYMAP));
keymap.element.querySelectorAll("label.b3-list-item input").forEach((item) => { keymap.element.querySelectorAll("label.b3-list-item input").forEach((item) => {
const keys = item.getAttribute("data-key").split(Constants.ZWSP); const keys = item.getAttribute("data-key").split(Constants.ZWSP);
if (keys[0] === "general") { if (keys[0] === "plugin") {
window.siyuan.config.keymap.plugin[keys[1]][keys[2]].custom = item.getAttribute("data-value");
data.plugin = window.siyuan.config.keymap.plugin;
} else if (keys[0] === "general") {
data[keys[0]][keys[1]].custom = item.getAttribute("data-value"); data[keys[0]][keys[1]].custom = item.getAttribute("data-value");
} else if (keys[0] === "editor" && (keys[1] === "general" || keys[1] === "insert" || keys[1] === "heading" || keys[1] === "list" || keys[1] === "table")) { } else if (keys[0] === "editor" && (keys[1] === "general" || keys[1] === "insert" || keys[1] === "heading" || keys[1] === "list" || keys[1] === "table")) {
data[keys[0]][keys[1]][keys[2]].custom = item.getAttribute("data-value"); data[keys[0]][keys[1]][keys[2]].custom = item.getAttribute("data-value");
@ -194,6 +241,17 @@ export const keymap = {
editorKeymapElement.firstElementChild.classList.remove("fn__none"); editorKeymapElement.firstElementChild.classList.remove("fn__none");
} }
}, },
_getTip(element: HTMLElement) {
const thirdElement = element.parentElement;
let tip = thirdElement.querySelector(".b3-list-item__text").textContent.trim()
const secondElement = thirdElement.parentElement.previousElementSibling;
tip = secondElement.textContent.trim() + "-" + tip;
const firstElement = secondElement.parentElement.previousElementSibling;
if (firstElement.classList.contains("b3-list-item")) {
tip = firstElement.textContent.trim() + "-" + tip;
}
return tip
},
bindEvent() { bindEvent() {
keymap.element.querySelector("#keymapRefreshBtn").addEventListener("click", () => { keymap.element.querySelector("#keymapRefreshBtn").addEventListener("click", () => {
exportLayout({ exportLayout({
@ -309,14 +367,9 @@ export const keymap = {
if (keys[1] === "heading") { if (keys[1] === "heading") {
keys[1] = "headings"; keys[1] = "headings";
} }
let tip = `${window.siyuan.languages.keymap} [${window.siyuan.languages[keys[0]]}-${window.siyuan.languages[keys[1]]}`;
if (keys[2]) {
tip += `-${window.siyuan.languages[keys[2]]}`;
}
if (["⌘", "⇧", "⌥", "⌃"].includes(keymapStr.substr(keymapStr.length - 1, 1)) || if (["⌘", "⇧", "⌥", "⌃"].includes(keymapStr.substr(keymapStr.length - 1, 1)) ||
["⌘A", "⌘X", "⌘C", "⌘V", "⌘-", "⌘=", "⌘0", "⇧⌘V", "⌘/", "⇧↑", "⇧↓", "⇧→", "⇧←", "⇧⇥", "⇧⌘⇥", "⌃⇥", "⌘⇥", "⌃⌘⇥", "⇧⌘→", "⇧⌘←", "⌘Home", "⌘End", "⇧↩", "↩", "PageUp", "PageDown", "⌫", "⌦"].includes(keymapStr)) { ["⌘A", "⌘X", "⌘C", "⌘V", "⌘-", "⌘=", "⌘0", "⇧⌘V", "⌘/", "⇧↑", "⇧↓", "⇧→", "⇧←", "⇧⇥", "⇧⌘⇥", "⌃⇥", "⌘⇥", "⌃⌘⇥", "⇧⌘→", "⇧⌘←", "⌘Home", "⌘End", "⇧↩", "↩", "PageUp", "PageDown", "⌫", "⌦"].includes(keymapStr)) {
showMessage(tip + "] " + window.siyuan.languages.invalid); showMessage(`${window.siyuan.languages.keymap} [${keymap._getTip(this)}] ${window.siyuan.languages.invalid}`);
return; return;
} }
const hasConflict = Array.from(keymap.element.querySelectorAll("label.b3-list-item input")).find(inputItem => { const hasConflict = Array.from(keymap.element.querySelectorAll("label.b3-list-item input")).find(inputItem => {
@ -328,11 +381,7 @@ export const keymap = {
if (inputValueList[1] === "heading") { if (inputValueList[1] === "heading") {
inputValueList[1] = "headings"; inputValueList[1] = "headings";
} }
let conflictTip = `${window.siyuan.languages[inputValueList[0]]}-${window.siyuan.languages[inputValueList[1]]}`; showMessage(`${window.siyuan.languages.keymap} [${keymap._getTip(this)}] [${keymap._getTip(inputItem)}] ${window.siyuan.languages.conflict}`);
if (inputValueList[2]) {
conflictTip += `-${window.siyuan.languages[inputValueList[2]]}`;
}
showMessage(`${tip}] [${conflictTip}] ${window.siyuan.languages.conflict}`);
return true; return true;
} }
}); });

View file

@ -243,7 +243,8 @@ export abstract class Constants {
"delete-row": {default: "⌘-", custom: "⌘-"}, "delete-row": {default: "⌘-", custom: "⌘-"},
"delete-column": {default: "⇧⌘_", custom: "⇧⌘_"} "delete-column": {default: "⇧⌘_", custom: "⇧⌘_"}
} }
} },
plugin: {},
}; };
public static readonly SIYUAN_EMPTY_LAYOUT: Record<string, unknown> = { public static readonly SIYUAN_EMPTY_LAYOUT: Record<string, unknown> = {

View file

@ -18,6 +18,7 @@ export class Plugin {
public data: any = {}; public data: any = {};
public name: string; public name: string;
public topBarIcons: Element[] = []; public topBarIcons: Element[] = [];
public commands: ICommand[] = [];
public models: { public models: {
/// #if !MOBILE /// #if !MOBILE
[key: string]: (options: { tab: Tab, data: any }) => Custom [key: string]: (options: { tab: Tab, data: any }) => Custom
@ -55,6 +56,10 @@ export class Plugin {
// 布局加载完成 // 布局加载完成
} }
public addCommand(command: ICommand) {
this.commands.push(command);
}
public addIcons(svg: string) { public addIcons(svg: string) {
document.body.insertAdjacentHTML("afterbegin", `<svg style="position: absolute; width: 0; height: 0; overflow: hidden;" xmlns="http://www.w3.org/2000/svg"> document.body.insertAdjacentHTML("afterbegin", `<svg style="position: absolute; width: 0; height: 0; overflow: hidden;" xmlns="http://www.w3.org/2000/svg">
<defs>${svg}</defs></svg>`); <defs>${svg}</defs></svg>`);

View file

@ -39,8 +39,9 @@ export const commonHotkey = (app: App, protyle: IProtyle, event: KeyboardEvent)
netImg2LocalAssets(protyle); netImg2LocalAssets(protyle);
event.preventDefault(); event.preventDefault();
event.stopPropagation(); event.stopPropagation();
return; return true;
} }
if (matchHotKey(window.siyuan.config.keymap.editor.general.spaceRepetition.custom, event) || if (matchHotKey(window.siyuan.config.keymap.editor.general.spaceRepetition.custom, event) ||
matchHotKey(window.siyuan.config.keymap.general.dailyNote.custom, event)) { matchHotKey(window.siyuan.config.keymap.general.dailyNote.custom, event)) {
// 阻止输入 https://ld246.com/article/1679618995926 // 阻止输入 https://ld246.com/article/1679618995926
@ -71,6 +72,23 @@ export const commonHotkey = (app: App, protyle: IProtyle, event: KeyboardEvent)
return true; return true;
} }
} }
let matchCommand = false;
app.plugins.find(item => {
item.commands.find(command => {
if (command.editorCallback && matchHotKey(command.customHotkey, event)) {
matchCommand = true;
command.editorCallback(protyle);
return true;
}
});
if (matchCommand) {
return true;
}
});
if (matchCommand) {
return true;
}
/// #endif /// #endif
}; };

View file

@ -301,6 +301,16 @@ declare interface IDockTab {
hotkeyLangId?: string // 常量中无法存变量 hotkeyLangId?: string // 常量中无法存变量
} }
declare interface ICommand {
langKey: string, // 多语言 key
hotkey: string,
customHotkey?: string,
callback?: () => void
fileTreeCallback?: (file: import("../layout/dock/Files").Files) => void
editorCallback?: (protyle: IProtyle) => void
dockCallback?: (element: HTMLElement) => void
}
declare interface IPluginData { declare interface IPluginData {
name: string, name: string,
js: string, js: string,
@ -635,6 +645,11 @@ declare interface IGraph {
} }
declare interface IKeymap { declare interface IKeymap {
plugin: {
[key: string]: {
[key: string]: IKeymapItem
}
}
general: { [key: string]: IKeymapItem } general: { [key: string]: IKeymapItem }
editor: { editor: {
general: { [key: string]: IKeymapItem } general: { [key: string]: IKeymapItem }