From f8d1d1958b2adf2a334147c2e34ab2d7df1a57e3 Mon Sep 17 00:00:00 2001 From: Vanessa Date: Sun, 14 Sep 2025 12:38:40 +0800 Subject: [PATCH] :art: https://github.com/siyuan-note/siyuan/issues/15835 --- app/src/block/util.ts | 20 ++++++++++++++++++++ app/src/protyle/ui/initUI.ts | 18 ++++++++++++------ app/src/protyle/wysiwyg/enter.ts | 8 ++++++-- app/src/protyle/wysiwyg/remove.ts | 8 ++++++++ 4 files changed, 46 insertions(+), 8 deletions(-) diff --git a/app/src/block/util.ts b/app/src/block/util.ts index 0b49ffcdf..bc0971145 100644 --- a/app/src/block/util.ts +++ b/app/src/block/util.ts @@ -150,7 +150,16 @@ export const insertEmptyBlock = (protyle: IProtyle, position: InsertPosition, id if (blockElement.getAttribute("data-type") === "NodeListItem") { newElement = genListItemElement(blockElement, 0, true) as HTMLDivElement; orderIndex = parseInt(blockElement.parentElement.firstElementChild.getAttribute("data-marker")); + } else if (position === "beforebegin" && blockElement.previousElementSibling && + blockElement.previousElementSibling.getAttribute("data-type") === "NodeHeading" && + blockElement.previousElementSibling.getAttribute("fold") === "1") { + newElement = genHeadingElement(blockElement.previousElementSibling, false, true) as HTMLDivElement; + } else if (position === "afterend" && blockElement && + blockElement.getAttribute("data-type") === "NodeHeading" && + blockElement.getAttribute("fold") === "1") { + newElement = genHeadingElement(blockElement, false, true) as HTMLDivElement; } + const parentOldHTML = blockElement.parentElement.outerHTML; const newId = newElement.getAttribute("data-node-id"); blockElement.insertAdjacentElement(position, newElement); @@ -216,6 +225,17 @@ export const genEmptyElement = (zwsp = true, wbr = true, id?: string) => { return element; }; +export const genHeadingElement = (headElement: Element, getHTML = false, addWbr = false) => { + const html = `
${addWbr ? "" : ""}
${Constants.ZWSP}
`; + if (getHTML) { + return html; + } else { + const tempElement = document.createElement("template"); + tempElement.innerHTML = html; + return tempElement.content.firstElementChild; + } +}; + export const getLangByType = (type: string) => { let lang = type; switch (type) { diff --git a/app/src/protyle/ui/initUI.ts b/app/src/protyle/ui/initUI.ts index 94e4d5365..8655bf873 100644 --- a/app/src/protyle/ui/initUI.ts +++ b/app/src/protyle/ui/initUI.ts @@ -9,7 +9,7 @@ import {lineNumberRender} from "../render/highlightRender"; import {hideMessage, showMessage} from "../../dialog/message"; import {genUUID} from "../../util/genID"; import {getContenteditableElement, getLastBlock} from "../wysiwyg/getBlock"; -import {genEmptyElement} from "../../block/util"; +import {genEmptyElement, genHeadingElement} from "../../block/util"; import {transaction} from "../wysiwyg/transaction"; import {focusByRange} from "../util/selection"; /// #if !MOBILE @@ -137,16 +137,22 @@ export const initUI = (protyle: IProtyle) => { return; } } - const lastRect = protyle.wysiwyg.element.lastElementChild.getBoundingClientRect(); + const lastElement = protyle.wysiwyg.element.lastElementChild; + const lastRect = lastElement.getBoundingClientRect(); const range = document.createRange(); if (event.y > lastRect.bottom) { - const lastEditElement = getContenteditableElement(getLastBlock(protyle.wysiwyg.element.lastElementChild)); + const lastEditElement = getContenteditableElement(getLastBlock(lastElement)); if (!protyle.options.click.preventInsetEmptyBlock && ( !lastEditElement || - (protyle.wysiwyg.element.lastElementChild.getAttribute("data-type") !== "NodeParagraph" && protyle.wysiwyg.element.getAttribute("data-doc-type") !== "NodeListItem") || - (protyle.wysiwyg.element.lastElementChild.getAttribute("data-type") === "NodeParagraph" && getContenteditableElement(lastEditElement).innerHTML !== "")) + (lastElement.getAttribute("data-type") !== "NodeParagraph" && protyle.wysiwyg.element.getAttribute("data-doc-type") !== "NodeListItem") || + (lastElement.getAttribute("data-type") === "NodeParagraph" && getContenteditableElement(lastEditElement).innerHTML !== "")) ) { - const emptyElement = genEmptyElement(false, false); + let emptyElement:Element; + if (lastElement.getAttribute("data-type") === "NodeHeading" && lastElement.getAttribute("fold") === "1") { + emptyElement = genHeadingElement(lastElement) as Element; + } else { + emptyElement = genEmptyElement(false, false); + } protyle.wysiwyg.element.insertAdjacentElement("beforeend", emptyElement); transaction(protyle, [{ action: "insert", diff --git a/app/src/protyle/wysiwyg/enter.ts b/app/src/protyle/wysiwyg/enter.ts index 60f500574..c5ca10c81 100644 --- a/app/src/protyle/wysiwyg/enter.ts +++ b/app/src/protyle/wysiwyg/enter.ts @@ -1,4 +1,4 @@ -import {genEmptyElement, insertEmptyBlock} from "../../block/util"; +import {genEmptyElement, genHeadingElement, insertEmptyBlock} from "../../block/util"; import {focusByRange, focusByWbr, getSelectionOffset, setLastNodeRange} from "../util/selection"; import { getContenteditableElement, @@ -220,7 +220,11 @@ export const enter = (blockElement: HTMLElement, range: Range, protyle: IProtyle } const id = blockElement.getAttribute("data-node-id"); const newElement = document.createElement("div"); - newElement.appendChild(genEmptyElement(false, false)); + if (blockElement.getAttribute("data-type") === "NodeHeading" && blockElement.getAttribute("fold") === "1") { + newElement.innerHTML = genHeadingElement(blockElement, true) as string; + } else { + newElement.appendChild(genEmptyElement(false, false)); + } const newEditableElement = newElement.querySelector('[contenteditable="true"]'); newEditableElement.appendChild(range.extractContents()); const selectWbrElement = newEditableElement.querySelector("wbr"); diff --git a/app/src/protyle/wysiwyg/remove.ts b/app/src/protyle/wysiwyg/remove.ts index ab474d7c5..f71ea5d62 100644 --- a/app/src/protyle/wysiwyg/remove.ts +++ b/app/src/protyle/wysiwyg/remove.ts @@ -300,6 +300,14 @@ export const removeBlock = async (protyle: IProtyle, blockElement: Element, rang return; } if (blockType === "NodeHeading") { + if ((blockElement.previousElementSibling && + blockElement.previousElementSibling.getAttribute("data-type") === "NodeHeading" && + blockElement.previousElementSibling.getAttribute("fold") === "1") || + (blockElement.getAttribute("data-type") === "NodeHeading" && + blockElement.getAttribute("fold") === "1")) { + focusBlock(blockElement.previousElementSibling, undefined, false); + return; + } turnsIntoTransaction({ protyle: protyle, selectsElement: [blockElement],