From 98a5717aed981a37136c99a8749b3ed7ffbc2587 Mon Sep 17 00:00:00 2001 From: Jeffrey Chen <78434827+TCOTC@users.noreply.github.com> Date: Sun, 9 Nov 2025 17:58:47 +0800 Subject: [PATCH] Improve inserting a new item at the end of a list via `Alt+Enter` https://ld246.com/article/1762643983269 --- app/src/protyle/util/hasClosest.ts | 9 ++- app/src/protyle/wysiwyg/keydown.ts | 37 +++++++---- app/src/protyle/wysiwyg/list.ts | 103 +++++++++++++++++++++-------- 3 files changed, 106 insertions(+), 43 deletions(-) diff --git a/app/src/protyle/util/hasClosest.ts b/app/src/protyle/util/hasClosest.ts index 2d61ae7bb..71078464e 100644 --- a/app/src/protyle/util/hasClosest.ts +++ b/app/src/protyle/util/hasClosest.ts @@ -104,12 +104,19 @@ export const hasClosestByClassName = (element: Node, className: string, top = fa export const hasClosestBlock = (element: Node) => { const nodeElement = hasClosestByAttribute(element, "data-node-id", null); - if (nodeElement && nodeElement.tagName !== "BUTTON" && nodeElement.getAttribute("data-type")?.startsWith("Node")) { + if (isBlockElement(nodeElement)) { return nodeElement; } return false; }; +export const isBlockElement = (element: Element | false | undefined) => { + if (!element) { + return false; + } + return element.hasAttribute("data-node-id") && element.tagName !== "BUTTON" && (element.getAttribute("data-type")?.startsWith("Node") ?? false); +}; + export const isInEmbedBlock = (element: Element) => { const embedElement = hasTopClosestByAttribute(element, "data-type", "NodeBlockQueryEmbed"); if (embedElement) { diff --git a/app/src/protyle/wysiwyg/keydown.ts b/app/src/protyle/wysiwyg/keydown.ts index 06ab687be..52d85d2c2 100644 --- a/app/src/protyle/wysiwyg/keydown.ts +++ b/app/src/protyle/wysiwyg/keydown.ts @@ -1057,31 +1057,40 @@ export const keydown = (protyle: IProtyle, editorElement: HTMLElement) => { } // 软换行 - if (matchHotKey("⇧↩", event) && selectText === "" && softEnter(range, nodeElement, protyle)) { + if (selectText === "" && matchHotKey("⇧↩", event) && softEnter(range, nodeElement, protyle)) { event.stopPropagation(); event.preventDefault(); return; } // 代码块语言选择 https://github.com/siyuan-note/siyuan/issues/14126 - if (matchHotKey("⌥↩", event) && selectText === "") { + // 列表插入末尾子项 https://github.com/siyuan-note/siyuan/issues/11164 + if (selectText === "" && matchHotKey("⌥↩", event) && !isIncludesHotKey("⌥↩")) { const selectElements = Array.from(protyle.wysiwyg.element.querySelectorAll(".protyle-wysiwyg--select")); if (selectElements.length === 0) { selectElements.push(nodeElement); } - if (selectElements.length > 0 && !isIncludesHotKey("⌥↩")) { - const otherElement = selectElements.find(item => { - return !item.classList.contains("code-block"); + + const codeBlockElements = selectElements.filter(item => { + return item.classList.contains("code-block"); + }); + if (codeBlockElements.length > 0) { + const languageElements: HTMLElement[] = []; + codeBlockElements.forEach(item => { + languageElements.push(item.querySelector(".protyle-action__language")); }); - if (!otherElement) { - const languageElements: HTMLElement[] = []; - selectElements.forEach(item => { - languageElements.push(item.querySelector(".protyle-action__language")); - }); - protyle.toolbar.showCodeLanguage(protyle, languageElements); - } else { - addSubList(protyle, nodeElement, range); - } + protyle.toolbar.showCodeLanguage(protyle, languageElements); + event.stopPropagation(); + event.preventDefault(); + return; + } + + const liBlockElement = hasClosestByClassName(nodeElement, "li"); + if (liBlockElement) { + selectElements.forEach(item => { + item.classList.remove("protyle-wysiwyg--select"); + }); + addSubList(protyle, nodeElement, range); event.stopPropagation(); event.preventDefault(); return; diff --git a/app/src/protyle/wysiwyg/list.ts b/app/src/protyle/wysiwyg/list.ts index 3ff5beb8e..89e66a53b 100644 --- a/app/src/protyle/wysiwyg/list.ts +++ b/app/src/protyle/wysiwyg/list.ts @@ -4,7 +4,7 @@ import {genEmptyBlock} from "../../block/util"; import * as dayjs from "dayjs"; import {Constants} from "../../constants"; import {moveToPrevious, removeBlock} from "./remove"; -import {hasClosestByClassName} from "../util/hasClosest"; +import {hasClosestBlock, hasClosestByClassName, isBlockElement} from "../util/hasClosest"; import {setFold} from "../../menus/protyle"; export const updateListOrder = (listElement: Element, sIndex?: number) => { @@ -30,49 +30,96 @@ export const updateListOrder = (listElement: Element, sIndex?: number) => { }); }; -export const genListItemElement = (listItemElement: Element, offset = 0, wbr = false) => { +export const genListItemElement = (listItemElement: Element, offset = 0, wbr = false, startIndex?: number) => { const element = document.createElement("template"); - const type = listItemElement.getAttribute("data-subtype"); + const type = listItemElement.getAttribute("data-subtype") || "u"; if (type === "o") { - const index = parseInt(listItemElement.getAttribute("data-marker")) + offset; - element.innerHTML = `