🎨 The embed block of a heading supports hiding the heading itself

This commit is contained in:
Achuan-2 2025-09-25 16:54:01 +08:00 committed by GitHub
parent a6e4baee99
commit ee5eb01c52
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
23 changed files with 208 additions and 45 deletions

View file

@ -674,7 +674,11 @@
"turnToDynamic": "نص المرساة الديناميكي", "turnToDynamic": "نص المرساة الديناميكي",
"sizeLimit": "الحد الأقصى", "sizeLimit": "الحد الأقصى",
"trafficStat": "إحصاءات حركة المرور", "trafficStat": "إحصاءات حركة المرور",
"hideHeadingBelowBlocks": "إخفاء الكتل تحت العنوان", "headingEmbedMode": "إعدادات تضمين كتلة العنوان",
"headingEmbedModeTip": "تعيين نمط عرض كتلة العنوان في الكتلة المضمنة",
"showHeadingWithBlocks": "إظهار العنوان مع الكتل أدناه",
"showHeadingOnlyTitle": "إظهار العنوان فقط",
"showHeadingOnlyBlocks": "إظهار الكتل تحت العنوان فقط",
"matchDiacritics": "مطابقة علامات التشكيل", "matchDiacritics": "مطابقة علامات التشكيل",
"copyHPath": "نسخ المسار المقروء", "copyHPath": "نسخ المسار المقروء",
"justify": "محاذاة من الجانبين", "justify": "محاذاة من الجانبين",

View file

@ -674,7 +674,11 @@
"turnToDynamic": "Dynamischer Ankertext", "turnToDynamic": "Dynamischer Ankertext",
"sizeLimit": "Limit", "sizeLimit": "Limit",
"trafficStat": "Verkehrsstatistiken", "trafficStat": "Verkehrsstatistiken",
"hideHeadingBelowBlocks": "Blöcke unter der Überschrift ausblenden", "headingEmbedMode": "Überschrift-Block-Einbettungseinstellungen",
"headingEmbedModeTip": "Stellen Sie den Anzeigestil von Überschrift-Blöcken in eingebetteten Blöcken ein",
"showHeadingWithBlocks": "Überschrift mit Blöcken darunter anzeigen",
"showHeadingOnlyTitle": "Nur Überschrift anzeigen",
"showHeadingOnlyBlocks": "Nur Blöcke unter der Überschrift anzeigen",
"matchDiacritics": "Diakritika abgleichen", "matchDiacritics": "Diakritika abgleichen",
"copyHPath": "Lesbaren Pfad kopieren", "copyHPath": "Lesbaren Pfad kopieren",
"justify": "Rechtsfertigen", "justify": "Rechtsfertigen",

View file

@ -674,7 +674,11 @@
"turnToDynamic": "Dynamic anchor text", "turnToDynamic": "Dynamic anchor text",
"sizeLimit": "Limit", "sizeLimit": "Limit",
"trafficStat": "Traffic statistics", "trafficStat": "Traffic statistics",
"hideHeadingBelowBlocks": "Hide blocks below heading", "headingEmbedMode": "Heading block embed settings",
"showHeadingWithBlocks": "Show heading with blocks below",
"showHeadingOnlyTitle": "Show heading only",
"showHeadingOnlyBlocks": "Show only blocks below heading",
"headingEmbedModeTip": "Set the display style of heading blocks in embed blocks",
"matchDiacritics": "Match Diacritics", "matchDiacritics": "Match Diacritics",
"copyHPath": "Copy readable path", "copyHPath": "Copy readable path",
"justify": "Justify", "justify": "Justify",

View file

@ -674,7 +674,11 @@
"turnToDynamic": "Texto de anclaje dinámico", "turnToDynamic": "Texto de anclaje dinámico",
"sizeLimit": "Límite", "sizeLimit": "Límite",
"trafficStat": "Estadísticas de tráfico", "trafficStat": "Estadísticas de tráfico",
"hideHeadingBelowBlocks": "Ocultar bloques por debajo del encabezamiento", "headingEmbedMode": "Configuración de incrustación de bloque de encabezado",
"headingEmbedModeTip": "Establecer el estilo de visualización de los bloques de encabezado en los bloques incrustados",
"showHeadingWithBlocks": "Mostrar encabezado con bloques debajo",
"showHeadingOnlyTitle": "Mostrar solo el encabezado",
"showHeadingOnlyBlocks": "Mostrar solo bloques debajo del encabezado",
"matchDiacritics": " Hacer coincidir los diacríticos", "matchDiacritics": " Hacer coincidir los diacríticos",
"copyHPath": "Copiar ruta legible", "copyHPath": "Copiar ruta legible",
"justify": "Justificar", "justify": "Justificar",

View file

@ -674,7 +674,11 @@
"turnToDynamic": "Texte d'ancrage dynamique", "turnToDynamic": "Texte d'ancrage dynamique",
"sizeLimit": "Limite", "sizeLimit": "Limite",
"trafficStat": "Statistiques de trafic", "trafficStat": "Statistiques de trafic",
"hideHeadingBelowBlocks": "Masquer les blocs sous l'en-tête", "headingEmbedMode": "Paramètres d'intégration de bloc de titre",
"showHeadingWithBlocks": "Afficher l'en-tête avec les blocs en dessous",
"showHeadingOnlyTitle": "Afficher uniquement l'en-tête",
"showHeadingOnlyBlocks": "Afficher uniquement les blocs sous l'en-tête",
"headingEmbedModeTip": "Définir le style d'affichage des blocs de titre dans les blocs intégrés",
"matchDiacritics": "Respecter les accents et diacritiques", "matchDiacritics": "Respecter les accents et diacritiques",
"copyHPath": "Copier le chemin lisible", "copyHPath": "Copier le chemin lisible",
"justify": "Justifier", "justify": "Justifier",

View file

@ -674,7 +674,11 @@
"turnToDynamic": "טקסט עוגן דינמי", "turnToDynamic": "טקסט עוגן דינמי",
"sizeLimit": "מגבלה", "sizeLimit": "מגבלה",
"trafficStat": "סטטיסטיקות תעבורה", "trafficStat": "סטטיסטיקות תעבורה",
"hideHeadingBelowBlocks": "החבא בלוקים מתחת לכותרת", "headingEmbedMode": "הגדרות הטמעת בלוק כותרת",
"headingEmbedModeTip": "הגדר את סגנון התצוגה של בלוקי כותרת בבלוקים מוטמעים",
"showHeadingWithBlocks": "הצג כותרת עם בלוקים מתחתיה",
"showHeadingOnlyTitle": "הצג כותרת בלבד",
"showHeadingOnlyBlocks": "הצג רק בלוקים מתחת לכותרת",
"matchDiacritics": "התאם טעמים", "matchDiacritics": "התאם טעמים",
"copyHPath": "העתק נתיב קריא", "copyHPath": "העתק נתיב קריא",
"justify": "התאם", "justify": "התאם",

View file

@ -674,7 +674,11 @@
"turnToDynamic": "Testo ancora dinamico", "turnToDynamic": "Testo ancora dinamico",
"sizeLimit": "Limite", "sizeLimit": "Limite",
"trafficStat": "Statistiche traffico", "trafficStat": "Statistiche traffico",
"hideHeadingBelowBlocks": "Nascondi blocchi sotto l'intestazione", "headingEmbedMode": "Impostazioni incorporamento blocco intestazione",
"headingEmbedModeTip": "Imposta lo stile di visualizzazione dei blocchi di intestazione nei blocchi incorporati",
"showHeadingWithBlocks": "Mostra intestazione con blocchi sottostanti",
"showHeadingOnlyTitle": "Mostra solo intestazione",
"showHeadingOnlyBlocks": "Mostra solo blocchi sotto l'intestazione",
"matchDiacritics": "Corrispondenza con diacritici", "matchDiacritics": "Corrispondenza con diacritici",
"copyHPath": "Copia percorso leggibile", "copyHPath": "Copia percorso leggibile",
"justify": "Giustifica", "justify": "Giustifica",

View file

@ -674,7 +674,11 @@
"turnToDynamic": "動的アンカーテキスト", "turnToDynamic": "動的アンカーテキスト",
"sizeLimit": "制限", "sizeLimit": "制限",
"trafficStat": "トラフィック統計", "trafficStat": "トラフィック統計",
"hideHeadingBelowBlocks": "見出し以下のブロックを非表示にする", "headingEmbedMode": "見出しブロック埋め込み設定",
"headingEmbedModeTip": "見出しブロックの埋め込みブロック内での表示スタイルを設定",
"showHeadingWithBlocks": "見出しと下のブロックを表示",
"showHeadingOnlyTitle": "見出しのみ表示",
"showHeadingOnlyBlocks": "見出し下のブロックのみ表示",
"matchDiacritics": "ダイアクリティカルマークを一致させる", "matchDiacritics": "ダイアクリティカルマークを一致させる",
"copyHPath": "パスをコピー", "copyHPath": "パスをコピー",
"justify": "両端揃え", "justify": "両端揃え",

View file

@ -674,7 +674,11 @@
"turnToDynamic": "Dynamiczny tekst zakotwiczenia", "turnToDynamic": "Dynamiczny tekst zakotwiczenia",
"sizeLimit": "Limit", "sizeLimit": "Limit",
"trafficStat": "Statystyki ruchu", "trafficStat": "Statystyki ruchu",
"hideHeadingBelowBlocks": "Ukryj bloki poniżej nagłówka", "headingEmbedMode": "Ustawienia osadzania bloku nagłówka",
"headingEmbedModeTip": "Ustaw styl wyświetlania bloków nagłówkowych w blokach osadzonych",
"showHeadingWithBlocks": "Pokaż nagłówek z blokami poniżej",
"showHeadingOnlyTitle": "Pokaż tylko nagłówek",
"showHeadingOnlyBlocks": "Pokaż tylko bloki poniżej nagłówka",
"matchDiacritics": "Dopasuj diakrytyki", "matchDiacritics": "Dopasuj diakrytyki",
"copyHPath": "Kopiuj czytelną ścieżkę", "copyHPath": "Kopiuj czytelną ścieżkę",
"justify": "Wyrównanie", "justify": "Wyrównanie",

View file

@ -674,7 +674,11 @@
"turnToDynamic": "Texto âncora dinâmico", "turnToDynamic": "Texto âncora dinâmico",
"sizeLimit": "Limite", "sizeLimit": "Limite",
"trafficStat": "Estatísticas de tráfego", "trafficStat": "Estatísticas de tráfego",
"hideHeadingBelowBlocks": "Ocultar blocos abaixo do título", "headingEmbedMode": "Configurações de incorporação de bloco de cabeçalho",
"headingEmbedModeTip": "Definir o estilo de exibição dos blocos de cabeçalho nos blocos incorporados",
"showHeadingWithBlocks": "Mostrar título com blocos abaixo",
"showHeadingOnlyTitle": "Mostrar apenas o título",
"showHeadingOnlyBlocks": "Mostrar apenas blocos abaixo do título",
"matchDiacritics": "Corresponder Diacríticos", "matchDiacritics": "Corresponder Diacríticos",
"copyHPath": "Copiar caminho legível", "copyHPath": "Copiar caminho legível",
"justify": "Justificar", "justify": "Justificar",

View file

@ -674,7 +674,11 @@
"turnToDynamic": "Динамический анкорный текст", "turnToDynamic": "Динамический анкорный текст",
"sizeLimit": "Лимит", "sizeLimit": "Лимит",
"trafficStat": "Статистика трафика", "trafficStat": "Статистика трафика",
"hideHeadingBelowBlocks": "Скрыть блоки ниже заголовка", "headingEmbedMode": "Настройки встраивания блока заголовка",
"headingEmbedModeTip": "Установить стиль отображения блока заголовка во встроенном блоке",
"showHeadingWithBlocks": "Показать заголовок с блоками ниже",
"showHeadingOnlyTitle": "Показать только заголовок",
"showHeadingOnlyBlocks": "Показать только блоки ниже заголовка",
"matchDiacritics": "Совпадение диакритики", "matchDiacritics": "Совпадение диакритики",
"copyHPath": "Скопировать читаемый путь", "copyHPath": "Скопировать читаемый путь",
"justify": "Выровнять", "justify": "Выровнять",

View file

@ -674,7 +674,11 @@
"turnToDynamic": "動態錨文字", "turnToDynamic": "動態錨文字",
"sizeLimit": "上限", "sizeLimit": "上限",
"trafficStat": "流量統計", "trafficStat": "流量統計",
"hideHeadingBelowBlocks": "隱藏標題下方的塊", "headingEmbedMode": "標題塊嵌入設定",
"headingEmbedModeTip": "設定標題塊在嵌入塊中的顯示樣式",
"showHeadingWithBlocks": "顯示標題與下方的區塊",
"showHeadingOnlyTitle": "僅顯示標題",
"showHeadingOnlyBlocks": "僅顯示標題下方的區塊",
"matchDiacritics": "符合變音符號", "matchDiacritics": "符合變音符號",
"copyHPath": "複製可讀路徑", "copyHPath": "複製可讀路徑",
"justify": "兩側對齊", "justify": "兩側對齊",

View file

@ -674,7 +674,11 @@
"turnToDynamic": "动态锚文本", "turnToDynamic": "动态锚文本",
"sizeLimit": "上限", "sizeLimit": "上限",
"trafficStat": "流量统计", "trafficStat": "流量统计",
"hideHeadingBelowBlocks": "隐藏标题下方的块", "headingEmbedMode": "标题块嵌入设置",
"showHeadingWithBlocks": "显示标题与下方的块",
"showHeadingOnlyTitle": "仅显示标题",
"showHeadingOnlyBlocks": "仅显示标题下方的块",
"headingEmbedModeTip": "设置标题块在嵌入块中的显示样式",
"matchDiacritics": "匹配变音符号", "matchDiacritics": "匹配变音符号",
"copyHPath": "复制可读路径", "copyHPath": "复制可读路径",
"justify": "两侧对齐", "justify": "两侧对齐",

View file

@ -69,6 +69,18 @@ export const editor = {
<span class="fn__space"></span> <span class="fn__space"></span>
<input class="b3-switch fn__flex-center" id="embedBlockBreadcrumb" type="checkbox"${window.siyuan.config.editor.embedBlockBreadcrumb ? " checked" : ""}/> <input class="b3-switch fn__flex-center" id="embedBlockBreadcrumb" type="checkbox"${window.siyuan.config.editor.embedBlockBreadcrumb ? " checked" : ""}/>
</label> </label>
<div class="fn__flex b3-label config__item">
<div class="fn__flex-1">
${window.siyuan.languages.headingEmbedMode}
<div class="b3-label__text">${window.siyuan.languages.headingEmbedModeTip}</div>
</div>
<span class="fn__space"></span>
<select class="b3-select fn__flex-center fn__size200" id="headingEmbedMode">
<option value="0" ${window.siyuan.config.editor.headingEmbedMode === 0 ? "selected" : ""}>${window.siyuan.languages.showHeadingWithBlocks}</option>
<option value="1" ${window.siyuan.config.editor.headingEmbedMode === 1 ? "selected" : ""}>${window.siyuan.languages.showHeadingOnlyTitle}</option>
<option value="2" ${window.siyuan.config.editor.headingEmbedMode === 2 ? "selected" : ""}>${window.siyuan.languages.showHeadingOnlyBlocks}</option>
</select>
</div>
<label class="fn__flex b3-label"> <label class="fn__flex b3-label">
<div class="fn__flex-1"> <div class="fn__flex-1">
${window.siyuan.languages.outlineOutdent} ${window.siyuan.languages.outlineOutdent}
@ -428,6 +440,7 @@ export const editor = {
displayNetImgMark: (editor.element.querySelector("#displayNetImgMark") as HTMLInputElement).checked, displayNetImgMark: (editor.element.querySelector("#displayNetImgMark") as HTMLInputElement).checked,
codeSyntaxHighlightLineNum: (editor.element.querySelector("#codeSyntaxHighlightLineNum") as HTMLInputElement).checked, codeSyntaxHighlightLineNum: (editor.element.querySelector("#codeSyntaxHighlightLineNum") as HTMLInputElement).checked,
embedBlockBreadcrumb: (editor.element.querySelector("#embedBlockBreadcrumb") as HTMLInputElement).checked, embedBlockBreadcrumb: (editor.element.querySelector("#embedBlockBreadcrumb") as HTMLInputElement).checked,
headingEmbedMode: parseInt((editor.element.querySelector("#headingEmbedMode") as HTMLSelectElement).value),
listLogicalOutdent: (editor.element.querySelector("#listLogicalOutdent") as HTMLInputElement).checked, listLogicalOutdent: (editor.element.querySelector("#listLogicalOutdent") as HTMLInputElement).checked,
listItemDotNumberClickFocus: (editor.element.querySelector("#listItemDotNumberClickFocus") as HTMLInputElement).checked, listItemDotNumberClickFocus: (editor.element.querySelector("#listItemDotNumberClickFocus") as HTMLInputElement).checked,
spellcheck: (editor.element.querySelector("#spellcheck") as HTMLInputElement).checked, spellcheck: (editor.element.querySelector("#spellcheck") as HTMLInputElement).checked,

View file

@ -33,6 +33,7 @@ const setEditor = (modelMainElement: Element) => {
window.siyuan.config.editor.displayNetImgMark = (modelMainElement.querySelector("#displayNetImgMark") as HTMLInputElement).checked; window.siyuan.config.editor.displayNetImgMark = (modelMainElement.querySelector("#displayNetImgMark") as HTMLInputElement).checked;
window.siyuan.config.editor.codeSyntaxHighlightLineNum = (modelMainElement.querySelector("#codeSyntaxHighlightLineNum") as HTMLInputElement).checked; window.siyuan.config.editor.codeSyntaxHighlightLineNum = (modelMainElement.querySelector("#codeSyntaxHighlightLineNum") as HTMLInputElement).checked;
window.siyuan.config.editor.embedBlockBreadcrumb = (modelMainElement.querySelector("#embedBlockBreadcrumb") as HTMLInputElement).checked; window.siyuan.config.editor.embedBlockBreadcrumb = (modelMainElement.querySelector("#embedBlockBreadcrumb") as HTMLInputElement).checked;
window.siyuan.config.editor.headingEmbedMode = parseInt((modelMainElement.querySelector("#headingEmbedMode") as HTMLSelectElement).value);
window.siyuan.config.editor.listLogicalOutdent = (modelMainElement.querySelector("#listLogicalOutdent") as HTMLInputElement).checked; window.siyuan.config.editor.listLogicalOutdent = (modelMainElement.querySelector("#listLogicalOutdent") as HTMLInputElement).checked;
window.siyuan.config.editor.listItemDotNumberClickFocus = (modelMainElement.querySelector("#listItemDotNumberClickFocus") as HTMLInputElement).checked; window.siyuan.config.editor.listItemDotNumberClickFocus = (modelMainElement.querySelector("#listItemDotNumberClickFocus") as HTMLInputElement).checked;
window.siyuan.config.editor.spellcheck = (modelMainElement.querySelector("#spellcheck") as HTMLInputElement).checked; window.siyuan.config.editor.spellcheck = (modelMainElement.querySelector("#spellcheck") as HTMLInputElement).checked;
@ -115,6 +116,16 @@ export const initEditor = () => {
<span class="fn__space"></span> <span class="fn__space"></span>
<input class="b3-switch fn__flex-center" id="embedBlockBreadcrumb" type="checkbox"${window.siyuan.config.editor.embedBlockBreadcrumb ? " checked" : ""}/> <input class="b3-switch fn__flex-center" id="embedBlockBreadcrumb" type="checkbox"${window.siyuan.config.editor.embedBlockBreadcrumb ? " checked" : ""}/>
</label> </label>
<div class="b3-label">
${window.siyuan.languages.headingEmbedMode}
<span class="fn__hr"></span>
<select class="b3-select fn__block" id="headingEmbedMode">
<option value="0" ${window.siyuan.config.editor.headingEmbedMode === 0 ? "selected" : ""}>${window.siyuan.languages.showHeadingWithBlocks}</option>
<option value="1" ${window.siyuan.config.editor.headingEmbedMode === 1 ? "selected" : ""}>${window.siyuan.languages.showHeadingOnlyTitle}</option>
<option value="2" ${window.siyuan.config.editor.headingEmbedMode === 2 ? "selected" : ""}>${window.siyuan.languages.showHeadingOnlyBlocks}</option>
</select>
<div class="b3-label__text">${window.siyuan.languages.headingEmbedModeTip}</div>
</div>
<label class="fn__flex b3-label"> <label class="fn__flex b3-label">
<div class="fn__flex-1"> <div class="fn__flex-1">
${window.siyuan.languages.outlineOutdent} ${window.siyuan.languages.outlineOutdent}

View file

@ -1628,20 +1628,35 @@ export class Gutter {
}); });
} }
}, { }, {
id: "hideHeadingBelowBlocks", id: "headingEmbedMode",
label: `<div class="fn__flex" style="margin-bottom: 4px"><span>${window.siyuan.languages.hideHeadingBelowBlocks}</span><span class="fn__space fn__flex-1"></span> label: `<div class="fn__flex" style="margin-bottom: 4px">
<input type="checkbox" class="b3-switch fn__flex-center"${nodeElement.getAttribute("custom-heading-mode") === "1" ? " checked" : ""}></div>`, <span>${window.siyuan.languages.headingEmbedMode}</span>
<span class="fn__space fn__flex-1"></span>
<select class="b3-select fn__flex-center" style="margin-left: 8px;">
<option value="0"${nodeElement.getAttribute("custom-heading-mode") === "0" ? " selected" : ""}>${window.siyuan.languages.showHeadingWithBlocks}</option>
<option value="1"${nodeElement.getAttribute("custom-heading-mode") === "1" ? " selected" : ""}>${window.siyuan.languages.showHeadingOnlyTitle}</option>
<option value="2"${nodeElement.getAttribute("custom-heading-mode") === "2" ? " selected" : ""}>${window.siyuan.languages.showHeadingOnlyBlocks}</option>
<option value=""${!nodeElement.getAttribute("custom-heading-mode") ? " selected" : ""}>${window.siyuan.languages.default}</option>
</select>
</div>`,
bind(element) { bind(element) {
element.addEventListener("click", (event: MouseEvent & { target: HTMLElement }) => { element.addEventListener("change", () => {
const inputElement = element.querySelector("input"); const selectElement = element.querySelector("select") as HTMLSelectElement;
if (event.target.tagName !== "INPUT") { const value = selectElement.value;
inputElement.checked = !inputElement.checked; if (value === "") {
// 默认设置,清空 custom-heading-mode 属性
nodeElement.removeAttribute("custom-heading-mode");
fetchPost("/api/attr/setBlockAttrs", {
id,
attrs: {"custom-heading-mode": ""}
});
} else {
nodeElement.setAttribute("custom-heading-mode", value);
fetchPost("/api/attr/setBlockAttrs", {
id,
attrs: {"custom-heading-mode": value}
});
} }
nodeElement.setAttribute("custom-heading-mode", inputElement.checked ? "1" : "0");
fetchPost("/api/attr/setBlockAttrs", {
id,
attrs: {"custom-heading-mode": inputElement.checked ? "1" : "0"}
});
nodeElement.removeAttribute("data-render"); nodeElement.removeAttribute("data-render");
blockRender(protyle, nodeElement); blockRender(protyle, nodeElement);
window.siyuan.menus.menu.remove(); window.siyuan.menus.menu.remove();

View file

@ -59,7 +59,7 @@ export const blockRender = (protyle: IProtyle, element: Element, top?: number) =
fetchPost("/api/search/getEmbedBlock", { fetchPost("/api/search/getEmbedBlock", {
embedBlockID: item.getAttribute("data-node-id"), embedBlockID: item.getAttribute("data-node-id"),
includeIDs: promiseIds, includeIDs: promiseIds,
headingMode: item.getAttribute("custom-heading-mode") === "1" ? 1 : 0, headingMode: ["0", "1", "2"].includes(item.getAttribute("custom-heading-mode")) ? parseInt(item.getAttribute("custom-heading-mode")) : window.siyuan.config.editor.headingEmbedMode,
breadcrumb breadcrumb
}, (response) => { }, (response) => {
renderEmbed(response.data.blocks || [], protyle, item, top); renderEmbed(response.data.blocks || [], protyle, item, top);
@ -74,7 +74,7 @@ export const blockRender = (protyle: IProtyle, element: Element, top?: number) =
fetchPost("/api/search/getEmbedBlock", { fetchPost("/api/search/getEmbedBlock", {
embedBlockID: item.getAttribute("data-node-id"), embedBlockID: item.getAttribute("data-node-id"),
includeIDs, includeIDs,
headingMode: item.getAttribute("custom-heading-mode") === "1" ? 1 : 0, headingMode: ["0", "1", "2"].includes(item.getAttribute("custom-heading-mode")) ? parseInt(item.getAttribute("custom-heading-mode")) : window.siyuan.config.editor.headingEmbedMode,
breadcrumb breadcrumb
}, (response) => { }, (response) => {
renderEmbed(response.data.blocks || [], protyle, item, top); renderEmbed(response.data.blocks || [], protyle, item, top);
@ -89,7 +89,7 @@ export const blockRender = (protyle: IProtyle, element: Element, top?: number) =
fetchPost("/api/search/searchEmbedBlock", { fetchPost("/api/search/searchEmbedBlock", {
embedBlockID: item.getAttribute("data-node-id"), embedBlockID: item.getAttribute("data-node-id"),
stmt: content, stmt: content,
headingMode: item.getAttribute("custom-heading-mode") === "1" ? 1 : 0, headingMode: ["0", "1", "2"].includes(item.getAttribute("custom-heading-mode")) ? parseInt(item.getAttribute("custom-heading-mode")) : window.siyuan.config.editor.headingEmbedMode,
excludeIDs: [item.getAttribute("data-node-id"), protyle.block.rootID], excludeIDs: [item.getAttribute("data-node-id"), protyle.block.rootID],
breadcrumb breadcrumb
}, (response) => { }, (response) => {

View file

@ -399,6 +399,13 @@ declare namespace Config {
* Whether the embedded block displays breadcrumbs * Whether the embedded block displays breadcrumbs
*/ */
embedBlockBreadcrumb: boolean; embedBlockBreadcrumb: boolean;
/**
* Heading embed mode for embedded blocks
* - `0`: Show title with blocks below (default)
* - `1`: Show only title
* - `2`: Show only blocks below title
*/
headingEmbedMode: number;
/** /**
* Common emoji icons * Common emoji icons
*/ */

View file

@ -251,7 +251,7 @@ func getEmbedBlock(c *gin.Context) {
for _, includeID := range includeIDsArg { for _, includeID := range includeIDsArg {
includeIDs = append(includeIDs, includeID.(string)) includeIDs = append(includeIDs, includeID.(string))
} }
headingMode := 0 // 0带标题下方块 headingMode := 0 // 0显示标题与下方的块1仅显示标题2仅显示标题下方的块默认
headingModeArg := arg["headingMode"] headingModeArg := arg["headingMode"]
if nil != headingModeArg { if nil != headingModeArg {
headingMode = int(headingModeArg.(float64)) headingMode = int(headingModeArg.(float64))
@ -304,7 +304,7 @@ func searchEmbedBlock(c *gin.Context) {
for _, excludeID := range excludeIDsArg { for _, excludeID := range excludeIDsArg {
excludeIDs = append(excludeIDs, excludeID.(string)) excludeIDs = append(excludeIDs, excludeID.(string))
} }
headingMode := 0 // 0带标题下方块 headingMode := 0 // 0显示标题与下方的块1仅显示标题2仅显示标题下方的块默认
headingModeArg := arg["headingMode"] headingModeArg := arg["headingMode"]
if nil != headingModeArg { if nil != headingModeArg {
headingMode = int(headingModeArg.(float64)) headingMode = int(headingModeArg.(float64))

View file

@ -52,6 +52,7 @@ type Editor struct {
BacklinkExpandCount int `json:"backlinkExpandCount"` // 反向链接默认展开数量 BacklinkExpandCount int `json:"backlinkExpandCount"` // 反向链接默认展开数量
BackmentionExpandCount int `json:"backmentionExpandCount"` // 反链提及默认展开数量 BackmentionExpandCount int `json:"backmentionExpandCount"` // 反链提及默认展开数量
BacklinkContainChildren bool `json:"backlinkContainChildren"` // 反向链接是否包含子块进行计算 BacklinkContainChildren bool `json:"backlinkContainChildren"` // 反向链接是否包含子块进行计算
HeadingEmbedMode int `json:"headingEmbedMode"` // 标题嵌入块模式0显示标题与下方的块1仅显示标题2仅显示标题下方的块
Markdown *util.Markdown `json:"markdown"` // Markdown 配置 Markdown *util.Markdown `json:"markdown"` // Markdown 配置
} }
@ -88,6 +89,7 @@ func NewEditor() *Editor {
BacklinkExpandCount: 8, BacklinkExpandCount: 8,
BackmentionExpandCount: -1, BackmentionExpandCount: -1,
BacklinkContainChildren: true, BacklinkContainChildren: true,
HeadingEmbedMode: 0,
Markdown: util.MarkdownSettings, Markdown: util.MarkdownSettings,
} }
} }

View file

@ -1058,16 +1058,40 @@ func getEmbeddedBlock(trees map[string]*parse.Tree, sqlBlock *sql.Block, heading
for _, n := range unlinks { for _, n := range unlinks {
n.Unlink() n.Unlink()
} }
nodes = append(nodes, def) // headingMode: 0=显示标题与下方的块1=仅显示标题2=仅显示标题下方的块(默认)
if 0 == headingMode && ast.NodeHeading == def.Type && "1" != def.IALAttr("fold") { if ast.NodeHeading == def.Type {
children := treenode.HeadingChildren(def) if 1 == headingMode {
for _, c := range children { // 仅显示标题
if "1" == c.IALAttr("heading-fold") { nodes = append(nodes, def)
// 嵌入块包含折叠标题时不应该显示其下方块 https://github.com/siyuan-note/siyuan/issues/4765 } else if 2 == headingMode {
continue // 仅显示标题下方的块(去除标题)
if "1" != def.IALAttr("fold") {
children := treenode.HeadingChildren(def)
for _, c := range children {
if "1" == c.IALAttr("heading-fold") {
// 嵌入块包含折叠标题时不应该显示其下方块 https://github.com/siyuan-note/siyuan/issues/4765
continue
}
nodes = append(nodes, c)
}
}
} else {
// 0: 显示标题与下方的块
nodes = append(nodes, def)
if "1" != def.IALAttr("fold") {
children := treenode.HeadingChildren(def)
for _, c := range children {
if "1" == c.IALAttr("heading-fold") {
// 嵌入块包含折叠标题时不应该显示其下方块 https://github.com/siyuan-note/siyuan/issues/4765
continue
}
nodes = append(nodes, c)
}
} }
nodes = append(nodes, c)
} }
} else {
// 非标题块,直接添加
nodes = append(nodes, def)
} }
b := treenode.GetBlockTree(def.ID) b := treenode.GetBlockTree(def.ID)
@ -1095,7 +1119,7 @@ func getEmbeddedBlock(trees map[string]*parse.Tree, sqlBlock *sql.Block, heading
} }
if breadcrumb { if breadcrumb {
blockPaths = buildBlockBreadcrumb(def, nil, true) blockPaths = buildBlockBreadcrumb(def, nil, true, headingMode)
} }
if 1 > len(blockPaths) { if 1 > len(blockPaths) {
blockPaths = []*BlockPath{} blockPaths = []*BlockPath{}

View file

@ -495,7 +495,7 @@ func BuildBlockBreadcrumb(id string, excludeTypes []string) (ret []*BlockPath, e
return return
} }
func buildBlockBreadcrumb(node *ast.Node, excludeTypes []string, isEmbedBlock bool) (ret []*BlockPath) { func buildBlockBreadcrumb(node *ast.Node, excludeTypes []string, isEmbedBlock bool, headingMode ...int) (ret []*BlockPath) {
ret = []*BlockPath{} ret = []*BlockPath{}
if nil == node { if nil == node {
return return
@ -505,6 +505,12 @@ func buildBlockBreadcrumb(node *ast.Node, excludeTypes []string, isEmbedBlock bo
return return
} }
// 默认 headingMode 为 0
mode := 0
if len(headingMode) > 0 {
mode = headingMode[0]
}
headingLevel := 16 headingLevel := 16
maxNameLen := 1024 maxNameLen := 1024
var hPath string var hPath string
@ -564,8 +570,13 @@ func buildBlockBreadcrumb(node *ast.Node, excludeTypes []string, isEmbedBlock bo
} }
} else { } else {
if ast.NodeDocument != parent.Type { if ast.NodeDocument != parent.Type {
// 在嵌入块中隐藏最后一个非文档路径的面包屑中的文本 Hide text in breadcrumb of last non-document path in embed block https://github.com/siyuan-note/siyuan/issues/13866 // 当headingMode=2仅显示标题下方的块且当前节点是标题时保留标题名称
name = "" if 2 == mode && ast.NodeHeading == parent.Type && parent == node {
// 保留标题名称,不清空
} else {
// 在嵌入块中隐藏最后一个非文档路径的面包屑中的文本 Hide text in breadcrumb of last non-document path in embed block https://github.com/siyuan-note/siyuan/issues/13866
name = ""
}
} }
} }

View file

@ -302,9 +302,37 @@ func resolveEmbedR(n *ast.Node, blockEmbedMode int, luteEngine *lute.Lute, resol
} else if "h" == sqlBlock.Type { } else if "h" == sqlBlock.Type {
h := treenode.GetNodeInTree(subTree, sqlBlock.ID) h := treenode.GetNodeInTree(subTree, sqlBlock.ID)
var hChildren []*ast.Node var hChildren []*ast.Node
hChildren = append(hChildren, h)
hChildren = append(hChildren, treenode.HeadingChildren(h)...) // 从嵌入块的 IAL 属性中解析 custom-heading-mode默认值为 0
blockHeadingMode := 0 // 默认值
if customHeadingMode := n.IALAttr("custom-heading-mode"); "" != customHeadingMode {
if mode, err := strconv.Atoi(customHeadingMode); nil == err && (mode == 0 || mode == 1 || mode == 2) {
blockHeadingMode = mode
}
}
// 根据 blockHeadingMode 处理标题块的显示
// blockHeadingMode: 0=显示标题与下方的块1=仅显示标题2=仅显示标题下方的块(默认)
if 1 == blockHeadingMode {
// 仅显示标题
hChildren = append(hChildren, h)
} else if 2 == blockHeadingMode {
// 仅显示标题下方的块(默认行为)
if "1" != h.IALAttr("fold") {
children := treenode.HeadingChildren(h)
for _, c := range children {
if "1" == c.IALAttr("heading-fold") {
// 嵌入块包含折叠标题时不应该显示其下方块 https://github.com/siyuan-note/siyuan/issues/4765
continue
}
hChildren = append(hChildren, c)
}
}
} else {
// 0: 显示标题与下方的块
hChildren = append(hChildren, h)
hChildren = append(hChildren, treenode.HeadingChildren(h)...)
}
if 0 == blockEmbedMode { if 0 == blockEmbedMode {
embedTopLevel := 0 embedTopLevel := 0
for _, hChild := range hChildren { for _, hChild := range hChildren {