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",
"includeChildDoc": "Include child documents",
"text": "Text",
"lastUsed": "Apariencia usada recientemente",
"lastUsed": "Recently used appearance",
"removedNotebook": "Removed notebook",
"querySyntax": "Query Syntax",
"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",
"includeChildDoc": "Incluir los documentos de los niños",
"text": "Texto",
"lastUsed": "Fuentes utilizadas apariencia",
"lastUsed": "Apariencia usada recientemente",
"removedNotebook": "Cuaderno de notas eliminado",
"querySyntax": "Sintaxis de consulta",
"rollback": "Rollback",

View file

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

View file

@ -802,10 +802,29 @@ export const globalShortcut = (app: App) => {
}
// 面板的操作
if (!isTabWindow && panelTreeKeydown(event)) {
if (!isTabWindow && panelTreeKeydown(app, event)) {
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 = "";
if (matchHotKey(window.siyuan.config.keymap.general.replace.custom, event)) {
searchKey = window.siyuan.config.keymap.general.replace.custom;
@ -1112,6 +1131,24 @@ const fileTreeKeydown = (app: App, event: KeyboardEvent) => {
return false;
}
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)) {
event.preventDefault();
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;
if (target.tagName === "INPUT" || target.tagName === "TEXTAREA" ||
@ -1451,6 +1488,23 @@ const panelTreeKeydown = (event: KeyboardEvent) => {
activePanelElement.classList.contains("sy__graph")) {
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;
if (!model) {
return false;

View file

@ -85,6 +85,38 @@ const hasKeymap = (keymap: Record<string, IKeymapItem>, key1: "general" | "edito
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) => {
const matchKeymap1 = matchKeymap(Constants.SIYUAN_KEYMAP.general, "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 hasKeymap5 = hasKeymap(Constants.SIYUAN_KEYMAP.editor.list, "editor", "list");
const hasKeymap6 = hasKeymap(Constants.SIYUAN_KEYMAP.editor.table, "editor", "table");
mergePluginHotkey(app);
if (!window.siyuan.config.readonly &&
(!matchKeymap1 || !matchKeymap2 || !matchKeymap3 || !matchKeymap4 || !matchKeymap5 || !matchKeymap6 ||
!hasKeymap1 || !hasKeymap2 || !hasKeymap3 || !hasKeymap4 || !hasKeymap5 || !hasKeymap6)) {

View file

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

View file

@ -8,6 +8,7 @@ import {getCurrentWindow} from "@electron/remote";
import {ipcRenderer} from "electron";
/// #endif
import {confirmDialog} from "../dialog/confirmDialog";
import {App} from "../index";
export const keymap = {
element: undefined as Element,
@ -25,13 +26,55 @@ export const keymap = {
<svg><use xlink:href="#iconTrashcan"></use></svg>
</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>`;
}
});
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">
<span class="fn__flex-center">${window.siyuan.languages.keymapTip}</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>
</div>
${pluginHtml}
</div>`;
},
_setkeymap() {
const data: IKeymap = JSON.parse(JSON.stringify(Constants.SIYUAN_KEYMAP));
keymap.element.querySelectorAll("label.b3-list-item input").forEach((item) => {
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");
} 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");
@ -194,6 +241,17 @@ export const keymap = {
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() {
keymap.element.querySelector("#keymapRefreshBtn").addEventListener("click", () => {
exportLayout({
@ -309,14 +367,9 @@ export const keymap = {
if (keys[1] === "heading") {
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)) ||
["⌘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;
}
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") {
inputValueList[1] = "headings";
}
let conflictTip = `${window.siyuan.languages[inputValueList[0]]}-${window.siyuan.languages[inputValueList[1]]}`;
if (inputValueList[2]) {
conflictTip += `-${window.siyuan.languages[inputValueList[2]]}`;
}
showMessage(`${tip}] [${conflictTip}] ${window.siyuan.languages.conflict}`);
showMessage(`${window.siyuan.languages.keymap} [${keymap._getTip(this)}] [${keymap._getTip(inputItem)}] ${window.siyuan.languages.conflict}`);
return true;
}
});

View file

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

View file

@ -18,6 +18,7 @@ export class Plugin {
public data: any = {};
public name: string;
public topBarIcons: Element[] = [];
public commands: ICommand[] = [];
public models: {
/// #if !MOBILE
[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) {
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>`);

View file

@ -39,8 +39,9 @@ export const commonHotkey = (app: App, protyle: IProtyle, event: KeyboardEvent)
netImg2LocalAssets(protyle);
event.preventDefault();
event.stopPropagation();
return;
return true;
}
if (matchHotKey(window.siyuan.config.keymap.editor.general.spaceRepetition.custom, event) ||
matchHotKey(window.siyuan.config.keymap.general.dailyNote.custom, event)) {
// 阻止输入 https://ld246.com/article/1679618995926
@ -71,6 +72,23 @@ export const commonHotkey = (app: App, protyle: IProtyle, event: KeyboardEvent)
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
};

View file

@ -301,6 +301,16 @@ declare interface IDockTab {
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 {
name: string,
js: string,
@ -635,6 +645,11 @@ declare interface IGraph {
}
declare interface IKeymap {
plugin: {
[key: string]: {
[key: string]: IKeymapItem
}
}
general: { [key: string]: IKeymapItem }
editor: {
general: { [key: string]: IKeymapItem }