Vanessa 2025-04-22 21:39:01 +08:00
parent b0ca44de00
commit b6527aa1c6
5 changed files with 70 additions and 31 deletions

View file

@ -464,7 +464,8 @@ export const keymap = {
let hasConflict = false; let hasConflict = false;
const isAssistKey = ["⌘", "⇧", "⌥", "⌃"].includes(keymapStr.substr(keymapStr.length - 1, 1)); const isAssistKey = ["⌘", "⇧", "⌥", "⌃"].includes(keymapStr.substr(keymapStr.length - 1, 1));
if (isAssistKey || if (isAssistKey ||
["⌘A", "⌘X", "⌘C", "⌘V", "⌘-", "⌘=", "⌘0", "⇧⌘V", "⌘/", "⇧↑", "⇧↓", "⇧→", "⇧←", "⇧⇥", "⌃D", "⇧⌘→", "⇧⌘←", "⌘Home", "⌘End", "⇧↩", "↩", "PageUp", "PageDown", "⌫", "⌦", "Escape"].includes(keymapStr) || ["⌘A", "⌘X", "⌘C", "⌘V", "⌘-", "⌘=", "⌘0", "⇧⌘V", "⌘/", "⇧↑", "⇧↓", "⇧→", "⇧←", "⇧⇥", "⌃D", "⇧⌘→",
"⇧⌘←", "⌘Home", "⌘End", "⇧↩", "⌥↩", "↩", "PageUp", "PageDown", "⌫", "⌦", "Escape"].includes(keymapStr) ||
// 跳转到下/上一个编辑页签不能包含 ctrl 否则不能监听到 keyup // 跳转到下/上一个编辑页签不能包含 ctrl 否则不能监听到 keyup
(isMac() && keys[0] === "general" && ["goToEditTabNext", "goToEditTabPrev"].includes(keys[1]) && keymapStr.includes("⌘")) (isMac() && keys[0] === "general" && ["goToEditTabNext", "goToEditTabPrev"].includes(keys[1]) && keymapStr.includes("⌘"))
) { ) {

View file

@ -343,7 +343,7 @@ export abstract class Constants {
// 冲突不使用 "⌘S/Q" // 冲突不使用 "⌘S/Q"
// "⌘", "⇧", "⌥", "⌃" // "⌘", "⇧", "⌥", "⌃"
// "⌘A", "⌘X", "⌘C", "⌘V", "⌘-", "⌘=", "⌘0", "⇧⌘V", "⌘/", "⇧↑", "⇧↓", "⇧→", "⇧←", "⇧⇥", "⌃D", "⇧⌘→", "⇧⌘←", // "⌘A", "⌘X", "⌘C", "⌘V", "⌘-", "⌘=", "⌘0", "⇧⌘V", "⌘/", "⇧↑", "⇧↓", "⇧→", "⇧←", "⇧⇥", "⌃D", "⇧⌘→", "⇧⌘←",
// "⌘Home", "⌘End", "⇧↩", "↩", "PageUp", "PageDown", "⌫", "⌦", "Escape" 不可自定义 // "⌘Home", "⌘End", "⇧↩", "⌥↩", "↩", "PageUp", "PageDown", "⌫", "⌦", "Escape" 不可自定义
public static readonly SIYUAN_KEYMAP: Config.IKeymap = { public static readonly SIYUAN_KEYMAP: Config.IKeymap = {
general: { general: {
mainMenu: {default: "⌥\\", custom: "⌥\\"}, mainMenu: {default: "⌥\\", custom: "⌥\\"},

View file

@ -15,7 +15,7 @@ import {
import {hasClosestBlock, hasClosestByAttribute, hasClosestByClassName, hasClosestByTag} from "../util/hasClosest"; import {hasClosestBlock, hasClosestByAttribute, hasClosestByClassName, hasClosestByTag} from "../util/hasClosest";
import {Link} from "./Link"; import {Link} from "./Link";
import {setPosition} from "../../util/setPosition"; import {setPosition} from "../../util/setPosition";
import {updateTransaction} from "../wysiwyg/transaction"; import {transaction, updateTransaction} from "../wysiwyg/transaction";
import {Constants} from "../../constants"; import {Constants} from "../../constants";
import {copyPlainText, openByMobile, readClipboard, setStorageVal} from "../util/compatibility"; import {copyPlainText, openByMobile, readClipboard, setStorageVal} from "../util/compatibility";
import {upDownHint} from "../../util/upDownHint"; import {upDownHint} from "../../util/upDownHint";
@ -1321,17 +1321,14 @@ export class Toolbar {
}); });
} }
public showCodeLanguage(protyle: IProtyle, languageElement: HTMLElement) { public showCodeLanguage(protyle: IProtyle, languageElements: HTMLElement[]) {
const nodeElement = hasClosestBlock(languageElement); const nodeElement = hasClosestBlock(languageElements[0]);
if (!nodeElement) { if (!nodeElement) {
return; return;
} }
hideElements(["hint"], protyle); hideElements(["hint"], protyle);
window.siyuan.menus.menu.remove(); window.siyuan.menus.menu.remove();
this.range = getEditorRange(nodeElement); this.range = getEditorRange(nodeElement);
const id = nodeElement.getAttribute("data-node-id");
let oldHtml = nodeElement.outerHTML;
let html = `<div class="b3-list-item">${window.siyuan.languages.clear}</div>`; let html = `<div class="b3-list-item">${window.siyuan.languages.clear}</div>`;
const hljsLanguages = Constants.ALIAS_CODE_LANGUAGES.concat(window.hljs?.listLanguages() ?? []).sort(); const hljsLanguages = Constants.ALIAS_CODE_LANGUAGES.concat(window.hljs?.listLanguages() ?? []).sort();
hljsLanguages.forEach((item, index) => { hljsLanguages.forEach((item, index) => {
@ -1354,7 +1351,7 @@ export class Toolbar {
} }
upDownHint(listElement, event); upDownHint(listElement, event);
if (event.key === "Enter") { if (event.key === "Enter") {
oldHtml = this.updateLanguage(languageElement, protyle, id, nodeElement, oldHtml, this.subElement.querySelector(".b3-list-item--focus").textContent); this.updateLanguage(languageElements, protyle, this.subElement.querySelector(".b3-list-item--focus").textContent);
event.preventDefault(); event.preventDefault();
event.stopPropagation(); event.stopPropagation();
return; return;
@ -1410,13 +1407,13 @@ export class Toolbar {
if (!listElement) { if (!listElement) {
return; return;
} }
oldHtml = this.updateLanguage(languageElement, protyle, id, nodeElement, oldHtml, listElement.textContent); this.updateLanguage(languageElements, protyle, listElement.textContent);
}); });
this.subElement.style.zIndex = (++window.siyuan.zIndex).toString(); this.subElement.style.zIndex = (++window.siyuan.zIndex).toString();
this.subElement.classList.remove("fn__none"); this.subElement.classList.remove("fn__none");
this.subElementCloseCB = undefined; this.subElementCloseCB = undefined;
/// #if !MOBILE /// #if !MOBILE
const nodeRect = languageElement.getBoundingClientRect(); const nodeRect = languageElements[0].getBoundingClientRect();
setPosition(this.subElement, nodeRect.left, nodeRect.bottom, nodeRect.height); setPosition(this.subElement, nodeRect.left, nodeRect.bottom, nodeRect.height);
/// #else /// #else
setPosition(this.subElement, 0, 0); setPosition(this.subElement, 0, 0);
@ -1841,28 +1838,46 @@ ${item.name}
} }
} }
private updateLanguage(languageElement: HTMLElement, protyle: IProtyle, id: string, nodeElement: HTMLElement, oldHtml: string, selectedLang: string) { private updateLanguage(languageElement: HTMLElement[], protyle: IProtyle, selectedLang: string) {
languageElement.textContent = selectedLang === window.siyuan.languages.clear ? "" : selectedLang; const currentLang = selectedLang === window.siyuan.languages.clear ? "" : selectedLang;
if (!Constants.SIYUAN_RENDER_CODE_LANGUAGES.includes(languageElement.textContent)) { if (!Constants.SIYUAN_RENDER_CODE_LANGUAGES.includes(currentLang)) {
window.siyuan.storage[Constants.LOCAL_CODELANG] = languageElement.textContent; window.siyuan.storage[Constants.LOCAL_CODELANG] = currentLang;
setStorageVal(Constants.LOCAL_CODELANG, window.siyuan.storage[Constants.LOCAL_CODELANG]); setStorageVal(Constants.LOCAL_CODELANG, window.siyuan.storage[Constants.LOCAL_CODELANG]);
} }
const editElement = getContenteditableElement(nodeElement); const doOperations: IOperation[] = [];
if (Constants.SIYUAN_RENDER_CODE_LANGUAGES.includes(languageElement.textContent)) { const undoOperations: IOperation[] = [];
nodeElement.dataset.content = editElement.textContent.trim(); languageElement.forEach(item => {
nodeElement.dataset.subtype = languageElement.textContent; const nodeElement = hasClosestBlock(item);
nodeElement.className = "render-node"; if (nodeElement) {
nodeElement.innerHTML = `<div spin="1"></div><div class="protyle-attr" contenteditable="false">${Constants.ZWSP}</div>`; const id = nodeElement.getAttribute("data-node-id");
processRender(nodeElement); undoOperations.push({
} else { id,
(editElement as HTMLElement).textContent = editElement.textContent; data: nodeElement.outerHTML,
editElement.parentElement.removeAttribute("data-render"); action: "update"
highlightRender(nodeElement); });
} item.textContent = selectedLang === window.siyuan.languages.clear ? "" : selectedLang;
nodeElement.setAttribute("updated", dayjs().format("YYYYMMDDHHmmss")); const editElement = getContenteditableElement(nodeElement);
updateTransaction(protyle, id, nodeElement.outerHTML, oldHtml); if (Constants.SIYUAN_RENDER_CODE_LANGUAGES.includes(currentLang)) {
nodeElement.dataset.content = editElement.textContent.trim();
nodeElement.dataset.subtype = currentLang;
nodeElement.className = "render-node";
nodeElement.innerHTML = `<div spin="1"></div><div class="protyle-attr" contenteditable="false">${Constants.ZWSP}</div>`;
processRender(nodeElement);
} else {
(editElement as HTMLElement).textContent = editElement.textContent;
editElement.parentElement.removeAttribute("data-render");
highlightRender(nodeElement);
}
nodeElement.setAttribute("updated", dayjs().format("YYYYMMDDHHmmss"));
doOperations.push({
id,
data: nodeElement.outerHTML,
action: "update"
});
}
});
transaction(protyle, doOperations, undoOperations);
this.subElement.classList.add("fn__none"); this.subElement.classList.add("fn__none");
focusByRange(this.range); focusByRange(this.range);
return nodeElement.outerHTML;
} }
} }

View file

@ -2506,7 +2506,7 @@ export class WYSIWYG {
const languageElement = hasClosestByClassName(event.target, "protyle-action__language"); const languageElement = hasClosestByClassName(event.target, "protyle-action__language");
if (languageElement && !protyle.disabled && !ctrlIsPressed) { if (languageElement && !protyle.disabled && !ctrlIsPressed) {
protyle.toolbar.showCodeLanguage(protyle, languageElement); protyle.toolbar.showCodeLanguage(protyle, [languageElement]);
event.stopPropagation(); event.stopPropagation();
event.preventDefault(); event.preventDefault();
return; return;

View file

@ -988,6 +988,29 @@ export const keydown = (protyle: IProtyle, editorElement: HTMLElement) => {
return; return;
} }
// 代码块语言选择 https://github.com/siyuan-note/siyuan/issues/14126
if (matchHotKey("⌥↩", event) && selectText === "") {
const selectElements = Array.from(protyle.wysiwyg.element.querySelectorAll(".protyle-wysiwyg--select"));
if (selectElements.length === 0 && nodeElement.classList.contains("code-block")) {
selectElements.push(nodeElement);
}
if (selectElements.length > 0) {
const otherElement = selectElements.find(item => {
return !item.classList.contains("code-block");
});
if (!otherElement) {
const languageElements: HTMLElement[] = [];
selectElements.forEach(item => {
languageElements.push(item.querySelector(".protyle-action__language"));
});
protyle.toolbar.showCodeLanguage(protyle, languageElements);
event.stopPropagation();
event.preventDefault();
return;
}
}
}
// 回车 // 回车
if (isNotCtrl(event) && event.key === "Enter") { if (isNotCtrl(event) && event.key === "Enter") {
if (event.altKey) { if (event.altKey) {