A privacy-first, self-hosted, fully open source personal knowledge management software, written in typescript and golang. (PERSONAL FORK)
1import {hasClosestByAttribute} from "../util/hasClosest";
2import {fetchPost, fetchSyncPost} from "../../util/fetch";
3import {processRender} from "../util/processCode";
4import {highlightRender} from "./highlightRender";
5import {genBreadcrumb, improveBreadcrumbAppearance} from "../wysiwyg/renderBacklink";
6import {avRender} from "./av/render";
7import {genRenderFrame} from "./util";
8
9export const blockRender = (protyle: IProtyle, element: Element, top?: number) => {
10 let blockElements: Element[] = [];
11 if (element.getAttribute("data-type") === "NodeBlockQueryEmbed") {
12 // 编辑器内代码块编辑渲染
13 blockElements = [element];
14 } else {
15 blockElements = Array.from(element.querySelectorAll('[data-type="NodeBlockQueryEmbed"]'));
16 }
17 if (blockElements.length === 0) {
18 return;
19 }
20 blockElements.forEach((item: HTMLElement) => {
21 if (item.getAttribute("data-render") === "true") {
22 return;
23 }
24 // 需置于请求返回前,否则快速滚动会导致重复加载 https://ld246.com/article/1666857862494?r=88250
25 item.setAttribute("data-render", "true");
26 genRenderFrame(item);
27 if (item.childElementCount > 3) {
28 item.style.height = (item.clientHeight - 4) + "px"; // 减少抖动 https://ld246.com/article/1668669380171
29 for (let i = 1; i < item.children.length - 1; i++) {
30 if (!item.children[i].classList.contains("protyle-cursor")) {
31 item.children[i].remove();
32 i--;
33 }
34 }
35 }
36 const content = Lute.UnEscapeHTMLStr(item.getAttribute("data-content"));
37 let breadcrumb: boolean | string = item.getAttribute("breadcrumb");
38 if (breadcrumb) {
39 breadcrumb = breadcrumb === "true";
40 } else {
41 breadcrumb = window.siyuan.config.editor.embedBlockBreadcrumb;
42 }
43
44 if (content.startsWith("//!js")) {
45 try {
46 const includeIDs = new Function(
47 "fetchSyncPost",
48 "item",
49 "protyle",
50 "top",
51 content)(fetchSyncPost, item, protyle, top);
52 if (includeIDs instanceof Promise) {
53 includeIDs.then((promiseIds) => {
54 if (Array.isArray(promiseIds)) {
55 fetchPost("/api/search/getEmbedBlock", {
56 embedBlockID: item.getAttribute("data-node-id"),
57 includeIDs: promiseIds,
58 headingMode: ["0", "1", "2"].includes(item.getAttribute("custom-heading-mode")) ? parseInt(item.getAttribute("custom-heading-mode")) : window.siyuan.config.editor.headingEmbedMode,
59 breadcrumb
60 }, (response) => {
61 renderEmbed(response.data.blocks || [], protyle, item, top);
62 });
63 } else {
64 return;
65 }
66 }).catch((e) => {
67 renderEmbed([], protyle, item, top, e);
68 });
69 } else if (Array.isArray(includeIDs)) {
70 fetchPost("/api/search/getEmbedBlock", {
71 embedBlockID: item.getAttribute("data-node-id"),
72 includeIDs,
73 headingMode: ["0", "1", "2"].includes(item.getAttribute("custom-heading-mode")) ? parseInt(item.getAttribute("custom-heading-mode")) : window.siyuan.config.editor.headingEmbedMode,
74 breadcrumb
75 }, (response) => {
76 renderEmbed(response.data.blocks || [], protyle, item, top);
77 });
78 } else {
79 return;
80 }
81 } catch (e) {
82 renderEmbed([], protyle, item, top, e);
83 }
84 } else {
85 fetchPost("/api/search/searchEmbedBlock", {
86 embedBlockID: item.getAttribute("data-node-id"),
87 stmt: content,
88 headingMode: ["0", "1", "2"].includes(item.getAttribute("custom-heading-mode")) ? parseInt(item.getAttribute("custom-heading-mode")) : window.siyuan.config.editor.headingEmbedMode,
89 excludeIDs: [item.getAttribute("data-node-id"), protyle.block.rootID],
90 breadcrumb
91 }, (response) => {
92 renderEmbed(response.data.blocks, protyle, item, top);
93 });
94 }
95 });
96};
97
98const renderEmbed = (blocks: {
99 block: IBlock,
100 blockPaths: IBreadcrumb[]
101}[], protyle: IProtyle, item: HTMLElement, top?: number, errorTip?: string) => {
102 const rotateElement = item.querySelector(".fn__rotate");
103 if (rotateElement) {
104 rotateElement.classList.remove("fn__rotate");
105 }
106 let html = "";
107 blocks.forEach((blocksItem) => {
108 let breadcrumbHTML = "";
109 if (blocksItem.blockPaths.length !== 0) {
110 breadcrumbHTML = genBreadcrumb(blocksItem.blockPaths, true);
111 }
112 html += `<div class="protyle-wysiwyg__embed" data-id="${blocksItem.block.id}">${breadcrumbHTML}${blocksItem.block.content}</div>`;
113 });
114 if (blocks.length > 0) {
115 item.firstElementChild.insertAdjacentHTML("afterend", html);
116 improveBreadcrumbAppearance(item.querySelector(".protyle-wysiwyg__embed"));
117 } else {
118 item.firstElementChild.insertAdjacentHTML("afterend", `<div class="protyle-wysiwyg__embed ft__smaller ft__secondary b3-form__space--small" contenteditable="false">${errorTip || window.siyuan.languages.refExpired}</div>`);
119 }
120
121 processRender(item);
122 highlightRender(item);
123 avRender(item, protyle);
124 if (top) {
125 // 前进后退定位 https://ld246.com/article/1667652729995
126 protyle.contentElement.scrollTop = top;
127 }
128 let maxDeep = 0;
129 let deepEmbedElement: false | HTMLElement = item;
130 while (maxDeep < 4 && deepEmbedElement) {
131 deepEmbedElement = hasClosestByAttribute(deepEmbedElement.parentElement, "data-type", "NodeBlockQueryEmbed");
132 maxDeep++;
133 }
134 if (maxDeep < 4) {
135 item.querySelectorAll('[data-type="NodeBlockQueryEmbed"]').forEach(embedElement => {
136 blockRender(protyle, embedElement);
137 });
138 }
139 item.style.height = "";
140};