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;
const isAssistKey = ["⌘", "⇧", "⌥", "⌃"].includes(keymapStr.substr(keymapStr.length - 1, 1));
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
(isMac() && keys[0] === "general" && ["goToEditTabNext", "goToEditTabPrev"].includes(keys[1]) && keymapStr.includes("⌘"))
) {

View file

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

View file

@ -15,7 +15,7 @@ import {
import {hasClosestBlock, hasClosestByAttribute, hasClosestByClassName, hasClosestByTag} from "../util/hasClosest";
import {Link} from "./Link";
import {setPosition} from "../../util/setPosition";
import {updateTransaction} from "../wysiwyg/transaction";
import {transaction, updateTransaction} from "../wysiwyg/transaction";
import {Constants} from "../../constants";
import {copyPlainText, openByMobile, readClipboard, setStorageVal} from "../util/compatibility";
import {upDownHint} from "../../util/upDownHint";
@ -1321,17 +1321,14 @@ export class Toolbar {
});
}
public showCodeLanguage(protyle: IProtyle, languageElement: HTMLElement) {
const nodeElement = hasClosestBlock(languageElement);
public showCodeLanguage(protyle: IProtyle, languageElements: HTMLElement[]) {
const nodeElement = hasClosestBlock(languageElements[0]);
if (!nodeElement) {
return;
}
hideElements(["hint"], protyle);
window.siyuan.menus.menu.remove();
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>`;
const hljsLanguages = Constants.ALIAS_CODE_LANGUAGES.concat(window.hljs?.listLanguages() ?? []).sort();
hljsLanguages.forEach((item, index) => {
@ -1354,7 +1351,7 @@ export class Toolbar {
}
upDownHint(listElement, event);
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.stopPropagation();
return;
@ -1410,13 +1407,13 @@ export class Toolbar {
if (!listElement) {
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.classList.remove("fn__none");
this.subElementCloseCB = undefined;
/// #if !MOBILE
const nodeRect = languageElement.getBoundingClientRect();
const nodeRect = languageElements[0].getBoundingClientRect();
setPosition(this.subElement, nodeRect.left, nodeRect.bottom, nodeRect.height);
/// #else
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) {
languageElement.textContent = selectedLang === window.siyuan.languages.clear ? "" : selectedLang;
if (!Constants.SIYUAN_RENDER_CODE_LANGUAGES.includes(languageElement.textContent)) {
window.siyuan.storage[Constants.LOCAL_CODELANG] = languageElement.textContent;
private updateLanguage(languageElement: HTMLElement[], protyle: IProtyle, selectedLang: string) {
const currentLang = selectedLang === window.siyuan.languages.clear ? "" : selectedLang;
if (!Constants.SIYUAN_RENDER_CODE_LANGUAGES.includes(currentLang)) {
window.siyuan.storage[Constants.LOCAL_CODELANG] = currentLang;
setStorageVal(Constants.LOCAL_CODELANG, window.siyuan.storage[Constants.LOCAL_CODELANG]);
}
const editElement = getContenteditableElement(nodeElement);
if (Constants.SIYUAN_RENDER_CODE_LANGUAGES.includes(languageElement.textContent)) {
nodeElement.dataset.content = editElement.textContent.trim();
nodeElement.dataset.subtype = languageElement.textContent;
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"));
updateTransaction(protyle, id, nodeElement.outerHTML, oldHtml);
const doOperations: IOperation[] = [];
const undoOperations: IOperation[] = [];
languageElement.forEach(item => {
const nodeElement = hasClosestBlock(item);
if (nodeElement) {
const id = nodeElement.getAttribute("data-node-id");
undoOperations.push({
id,
data: nodeElement.outerHTML,
action: "update"
});
item.textContent = selectedLang === window.siyuan.languages.clear ? "" : selectedLang;
const editElement = getContenteditableElement(nodeElement);
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");
focusByRange(this.range);
return nodeElement.outerHTML;
}
}

View file

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

View file

@ -988,6 +988,29 @@ export const keydown = (protyle: IProtyle, editorElement: HTMLElement) => {
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 (event.altKey) {