Ver Fonte

:zap: https://github.com/siyuan-note/siyuan/issues/8248

Vanessa há 2 anos atrás
pai
commit
ec198ee4eb

+ 2 - 2
app/src/menus/protyle.ts

@@ -427,12 +427,12 @@ export const contentMenu = (protyle: IProtyle, nodeElement: Element) => {
     }
 };
 
-export const zoomOut = (protyle: IProtyle, id: string, focusId?: string, isPushBack = true, callback?: () => void) => {
+export const zoomOut = (protyle: IProtyle, id: string, focusId?: string, isPushBack = true, callback?: () => void, reload = false) => {
     if (protyle.options.backlinkData) {
         return;
     }
     const breadcrumbHLElement = protyle.breadcrumb?.element.querySelector(".protyle-breadcrumb__item--active");
-    if (breadcrumbHLElement && breadcrumbHLElement.getAttribute("data-node-id") === id) {
+    if (!reload && breadcrumbHLElement && breadcrumbHLElement.getAttribute("data-node-id") === id) {
         if (id === protyle.block.rootID) {
             return;
         }

+ 3 - 7
app/src/mobile/settings/editor.ts

@@ -4,12 +4,6 @@ import {reloadProtyle} from "../../protyle/util/reload";
 import {setInlineStyle} from "../../util/assets";
 import {confirmDialog} from "../../dialog/confirmDialog";
 
-const reloadEditor = (data: IEditor) => {
-    window.siyuan.config.editor = data;
-    reloadProtyle(window.siyuan.mobile.editor.protyle);
-    setInlineStyle();
-};
-
 const setEditor = (modelMainElement: Element) => {
     let dynamicLoadBlocks = parseInt((modelMainElement.querySelector("#dynamicLoadBlocks") as HTMLInputElement).value);
     if (48 > dynamicLoadBlocks) {
@@ -45,7 +39,9 @@ const setEditor = (modelMainElement: Element) => {
     window.siyuan.config.editor.generateHistoryInterval = parseInt((modelMainElement.querySelector("#generateHistoryInterval") as HTMLInputElement).value);
     window.siyuan.config.editor.historyRetentionDays = parseInt((modelMainElement.querySelector("#historyRetentionDays") as HTMLInputElement).value);
     fetchPost("/api/setting/setEditor", window.siyuan.config.editor, response => {
-        reloadEditor(response.data);
+        window.siyuan.config.editor = response.data;
+        reloadProtyle(window.siyuan.mobile.editor.protyle);
+        setInlineStyle();
     });
 };
 

+ 3 - 16
app/src/protyle/breadcrumb/action.ts

@@ -4,10 +4,9 @@ import {getAllModels} from "../../layout/getAll";
 import {addLoading, setPadding} from "../ui/initUI";
 import {fetchPost} from "../../util/fetch";
 import {Constants} from "../../constants";
-import {onGet} from "../util/onGet";
-import {saveScroll} from "../scroll/saveScroll";
 import {hideAllElements, hideElements} from "../ui/hideElements";
 import {hasClosestByClassName} from "../util/hasClosest";
+import {reloadProtyle} from "../util/reload";
 
 export const netImg2LocalAssets = (protyle: IProtyle) => {
     if (protyle.element.querySelector(".wysiwygLoading")) {
@@ -19,23 +18,11 @@ export const netImg2LocalAssets = (protyle: IProtyle) => {
         id: protyle.block.rootID
     }, () => {
         /// #if MOBILE
-        fetchPost("/api/filetree/getDoc", {
-            id: protyle.block.id,
-            mode: 0,
-            size: window.siyuan.config.editor.dynamicLoadBlocks,
-        }, getResponse => {
-            onGet(getResponse, protyle, [Constants.CB_GET_FOCUS], saveScroll(protyle, true));
-        });
+        reloadProtyle(protyle);
         /// #else
         getAllModels().editor.forEach(item => {
             if (item.editor.protyle.block.rootID === protyle.block.rootID) {
-                fetchPost("/api/filetree/getDoc", {
-                    id: item.editor.protyle.block.rootID,
-                    mode: 0,
-                    size: window.siyuan.config.editor.dynamicLoadBlocks,
-                }, getResponse => {
-                    onGet(getResponse, item.editor.protyle, [Constants.CB_GET_FOCUS], saveScroll(protyle, true));
-                });
+                reloadProtyle(item.editor.protyle)
             }
         });
         /// #endif

+ 2 - 14
app/src/protyle/breadcrumb/index.ts

@@ -245,23 +245,11 @@ export class Breadcrumb {
                             id: protyle.block.rootID
                         }, () => {
                             /// #if MOBILE
-                            fetchPost("/api/filetree/getDoc", {
-                                id: protyle.block.id,
-                                mode: 0,
-                                size: window.siyuan.config.editor.dynamicLoadBlocks,
-                            }, getResponse => {
-                                onGet(getResponse, protyle, [Constants.CB_GET_FOCUS], saveScroll(protyle, true));
-                            });
+                            reloadProtyle(protyle);
                             /// #else
                             getAllModels().editor.forEach(item => {
                                 if (item.editor.protyle.block.rootID === protyle.block.rootID) {
-                                    fetchPost("/api/filetree/getDoc", {
-                                        id: item.editor.protyle.block.rootID,
-                                        mode: 0,
-                                        size: window.siyuan.config.editor.dynamicLoadBlocks,
-                                    }, getResponse => {
-                                        onGet(getResponse, item.editor.protyle, [Constants.CB_GET_FOCUS], saveScroll(protyle, true));
-                                    });
+                                    reloadProtyle(item.editor.protyle);
                                 }
                             });
                             /// #endif

+ 2 - 2
app/src/protyle/header/Title.ts

@@ -415,8 +415,8 @@ ${window.siyuan.languages.createdAt} ${dayjs(response.data.ial.id.substr(0, 14))
         }
     }
 
-    public render(protyle: IProtyle, response: IWebSocketData, refresh = false) {
-        if (this.editElement.getAttribute("data-render") === "true" && !refresh) {
+    public render(protyle: IProtyle, response: IWebSocketData) {
+        if (this.editElement.getAttribute("data-render") === "true") {
             return false;
         }
         this.element.setAttribute("data-node-id", protyle.block.rootID);

+ 111 - 57
app/src/protyle/index.ts

@@ -192,68 +192,122 @@ export class Protyle {
                 removeLoading(this.protyle);
                 return;
             }
-            fetchPost("/api/filetree/getDoc", {
-                id: options.blockId,
-                k: options.key || "",
-                isBacklink: mergedOptions.action.includes(Constants.CB_GET_BACKLINK),
-                // 0: 仅当前 ID(默认值),1:向上 2:向下,3:上下都加载,4:加载最后
-                mode: (mergedOptions.action && mergedOptions.action.includes(Constants.CB_GET_CONTEXT)) ? 3 : 0,
-                size: mergedOptions.action?.includes(Constants.CB_GET_ALL) ? Constants.SIZE_GET_MAX : window.siyuan.config.editor.dynamicLoadBlocks,
-            }, getResponse => {
-                onGet(getResponse, this.protyle, mergedOptions.action, options.scrollAttr);
-                if (this.protyle.model) {
-                    /// #if !MOBILE
-                    if (mergedOptions.action?.includes(Constants.CB_GET_FOCUS)) {
-                        setPanelFocus(this.protyle.model.element.parentElement.parentElement);
-                    }
-                    updatePanelByEditor({
-                        protyle: this.protyle,
-                        focus: false,
-                        pushBackStack: false,
-                        reload: false,
-                        resize: false
+            if (options.scrollAttr ||
+                (mergedOptions.action.includes(Constants.CB_GET_SCROLL) && this.protyle.options.mode !== "preview")) {
+                if (!options.scrollAttr) {
+                    fetchPost("/api/block/getDocInfo", {
+                        id: options.blockId
+                    }, (response) => {
+                        if (response.data.ial.scroll) {
+                            let scrollObj;
+                            try {
+                                scrollObj = JSON.parse(response.data.ial.scroll.replace(/"/g, '"'));
+                            } catch (e) {
+                                scrollObj = undefined;
+                            }
+                            if (scrollObj) {
+                                this.getDocByScrollData(scrollObj, mergedOptions);
+                            } else {
+                                this.getDoc(mergedOptions);
+                            }
+                        }
                     });
-                    /// #endif
+                } else {
+                    this.getDocByScrollData(options.scrollAttr, mergedOptions);
                 }
+            } else {
+                this.getDoc(mergedOptions);
+            }
+        }
+        this.protyle.contentElement.classList.add("protyle-content--transition");
+    }
 
-                // 需等待 getDoc 完成后再执行,否则在无页签的时候 updatePanelByEditor 会执行2次
-                // 只能用 focusin,否则点击表格无法执行
-                this.protyle.wysiwyg.element.addEventListener("focusin", () => {
-                    /// #if !MOBILE
-                    if (this.protyle && this.protyle.model) {
-                        let needUpdate = true;
-                        if (this.protyle.model.element.parentElement.parentElement.classList.contains("layout__wnd--active") && this.protyle.model.headElement.classList.contains("item--focus")) {
-                            needUpdate = false;
-                        }
-                        if (!needUpdate) {
-                            return;
-                        }
-                        setPanelFocus(this.protyle.model.element.parentElement.parentElement);
-                        updatePanelByEditor({
-                            protyle: this.protyle,
-                            focus: false,
-                            pushBackStack: false,
-                            reload: false,
-                            resize: false,
-                        });
-                    } else {
-                        // 悬浮层应移除其余面板高亮,否则按键会被面板监听到
-                        document.querySelectorAll(".layout__tab--active").forEach(item => {
-                            item.classList.remove("layout__tab--active");
-                        });
-                        document.querySelectorAll(".layout__wnd--active").forEach(item => {
-                            item.classList.remove("layout__wnd--active");
-                        });
-                    }
-                    /// #endif
-                });
-                // 需等渲染完后再回调,用于定位搜索字段 https://github.com/siyuan-note/siyuan/issues/3171
-                if (mergedOptions.after) {
-                    mergedOptions.after(this);
-                }
+    private getDoc(mergedOptions: IOptions) {
+        fetchPost("/api/filetree/getDoc", {
+            id: mergedOptions.blockId,
+            k: mergedOptions.key || "",
+            isBacklink: mergedOptions.action.includes(Constants.CB_GET_BACKLINK),
+            // 0: 仅当前 ID(默认值),1:向上 2:向下,3:上下都加载,4:加载最后
+            mode: (mergedOptions.action && mergedOptions.action.includes(Constants.CB_GET_CONTEXT)) ? 3 : 0,
+            size: mergedOptions.action?.includes(Constants.CB_GET_ALL) ? Constants.SIZE_GET_MAX : window.siyuan.config.editor.dynamicLoadBlocks,
+        }, getResponse => {
+            onGet(getResponse, this.protyle, mergedOptions.action);
+            this.afterOnGet(mergedOptions);
+        });
+    }
+
+    private getDocByScrollData(scrollAttr: IScrollAttr, mergedOptions: IOptions) {
+        if (scrollAttr.zoomInId) {
+            fetchPost("/api/filetree/getDoc", {
+                id: scrollAttr.zoomInId,
+                size: Constants.SIZE_GET_MAX,
+            }, response => {
+                onGet(response, this.protyle, mergedOptions.action, scrollAttr);
+                this.afterOnGet(mergedOptions);
+            })
+            return;
+        }
+        fetchPost("/api/filetree/getDoc", {
+            id: scrollAttr.startId,
+            startID: scrollAttr.startId,
+            endID: scrollAttr.endId,
+        }, response => {
+            onGet(response, this.protyle, mergedOptions.action, scrollAttr);
+            this.afterOnGet(mergedOptions);
+        });
+    }
+
+    private afterOnGet(mergedOptions: IOptions) {
+        if (this.protyle.model) {
+            /// #if !MOBILE
+            if (mergedOptions.action?.includes(Constants.CB_GET_FOCUS)) {
+                setPanelFocus(this.protyle.model.element.parentElement.parentElement);
+            }
+            updatePanelByEditor({
+                protyle: this.protyle,
+                focus: false,
+                pushBackStack: false,
+                reload: false,
+                resize: false
             });
+            /// #endif
+        }
+
+        // 需等待 getDoc 完成后再执行,否则在无页签的时候 updatePanelByEditor 会执行2次
+        // 只能用 focusin,否则点击表格无法执行
+        this.protyle.wysiwyg.element.addEventListener("focusin", () => {
+            /// #if !MOBILE
+            if (this.protyle && this.protyle.model) {
+                let needUpdate = true;
+                if (this.protyle.model.element.parentElement.parentElement.classList.contains("layout__wnd--active") && this.protyle.model.headElement.classList.contains("item--focus")) {
+                    needUpdate = false;
+                }
+                if (!needUpdate) {
+                    return;
+                }
+                setPanelFocus(this.protyle.model.element.parentElement.parentElement);
+                updatePanelByEditor({
+                    protyle: this.protyle,
+                    focus: false,
+                    pushBackStack: false,
+                    reload: false,
+                    resize: false,
+                });
+            } else {
+                // 悬浮层应移除其余面板高亮,否则按键会被面板监听到
+                document.querySelectorAll(".layout__tab--active").forEach(item => {
+                    item.classList.remove("layout__tab--active");
+                });
+                document.querySelectorAll(".layout__wnd--active").forEach(item => {
+                    item.classList.remove("layout__wnd--active");
+                });
+            }
+            /// #endif
+        });
+        // 需等渲染完后再回调,用于定位搜索字段 https://github.com/siyuan-note/siyuan/issues/3171
+        if (mergedOptions.after) {
+            mergedOptions.after(this);
         }
-        this.protyle.contentElement.classList.add("protyle-content--transition");
     }
 
     private init() {

+ 78 - 72
app/src/protyle/util/onGet.ts

@@ -1,8 +1,6 @@
 import {setTitle} from "../../dialog/processSystem";
 import {Constants} from "../../constants";
 import {hideElements} from "../ui/hideElements";
-import {genEmptyElement} from "../../block/util";
-import {transaction} from "../wysiwyg/transaction";
 import {fetchPost} from "../../util/fetch";
 import {processRender} from "./processCode";
 import {highlightRender} from "../markdown/highlightRender";
@@ -11,16 +9,15 @@ import {highlightById} from "../../util/highlightById";
 /// #if !MOBILE
 import {pushBack} from "../../util/backForward";
 /// #endif
-import {focusBlock} from "./selection";
+import {focusBlock, focusByOffset} from "./selection";
 import {hasClosestByAttribute, hasClosestByClassName} from "./hasClosest";
 import {preventScroll} from "../scroll/preventScroll";
-import {restoreScroll} from "../scroll/saveScroll";
 import {removeLoading} from "../ui/initUI";
 import {isMobile} from "../../util/functions";
 import {foldPassiveType} from "../wysiwyg/renderBacklink";
 import {showMessage} from "../../dialog/message";
 
-export const onGet = (data: IWebSocketData, protyle: IProtyle, action: string[] = [], scrollAttr?: IScrollAttr, renderTitle = false) => {
+export const onGet = (data: IWebSocketData, protyle: IProtyle, action: string[] = [], scrollAttr?: IScrollAttr) => {
     protyle.wysiwyg.element.removeAttribute("data-top");
     if (data.code === 1) {
         // 其他报错
@@ -38,7 +35,7 @@ export const onGet = (data: IWebSocketData, protyle: IProtyle, action: string[]
     protyle.notebookId = data.data.box;
     protyle.path = data.data.path;
 
-    if (data.data.eof) {
+    if (data.data.eof && !scrollAttr) {
         if (action.includes(Constants.CB_GET_BEFORE)) {
             protyle.wysiwyg.element.firstElementChild.setAttribute("data-eof", "1");
         } else {
@@ -49,18 +46,6 @@ export const onGet = (data: IWebSocketData, protyle: IProtyle, action: string[]
         }
     }
     hideElements(["gutter"], protyle);
-    let html = data.data.content;
-    if (html === "" && !action) {
-        const element = genEmptyElement(false, false);
-        html = element.outerHTML;
-        transaction(protyle, [{
-            action: "insert",
-            id: element.getAttribute("data-node-id"),
-            data: html,
-            parentID: data.data.parentID
-        }]);
-    }
-
     protyle.block.parentID = data.data.parentID;
     protyle.block.parent2ID = data.data.parent2ID;
     protyle.block.rootID = data.data.rootID;
@@ -79,10 +64,10 @@ export const onGet = (data: IWebSocketData, protyle: IProtyle, action: string[]
     // 防止动态加载加载过多的内容
     if (action.includes(Constants.CB_GET_APPEND) || action.includes(Constants.CB_GET_BEFORE) || action.includes(Constants.CB_GET_HTML)) {
         setHTML({
-            content: html,
+            content: data.data.content,
             expand: data.data.isBacklinkExpand,
             action,
-            unScroll: false,
+            scrollAttr,
             isSyncing: data.data.isSyncing,
         }, protyle);
         removeLoading(protyle);
@@ -94,34 +79,20 @@ export const onGet = (data: IWebSocketData, protyle: IProtyle, action: string[]
     }, (response) => {
         if (protyle.options.render.title) {
             // 页签没有打开
-            protyle.title.render(protyle, response, renderTitle);
+            protyle.title.render(protyle, response);
         } else if (protyle.options.render.background) {
             protyle.background.render(response.data.ial, protyle.block.rootID);
             protyle.wysiwyg.renderCustom(response.data.ial);
         }
 
-        let scrollObj = scrollAttr;
-        if (!scrollObj) {
-            if (action.includes(Constants.CB_GET_SCROLL) && response.data.ial.scroll) {
-                try {
-                    scrollObj = JSON.parse(response.data.ial.scroll.replace(/"/g, '"'));
-                } catch (e) {
-                    scrollObj = undefined;
-                }
-            }
-        }
-
         setHTML({
-            content: html,
+            content: data.data.content,
             expand: data.data.isBacklinkExpand,
             action,
-            unScroll: (scrollObj && scrollObj.focusId) ? true : false,
+            scrollAttr,
             isSyncing: data.data.isSyncing,
         }, protyle);
         setTitle(response.data.ial.title);
-        if (scrollObj && protyle.options.mode !== "preview") {
-            restoreScroll(protyle, scrollObj);
-        }
         removeLoading(protyle);
     });
 };
@@ -131,7 +102,7 @@ const setHTML = (options: {
     action?: string[],
     isSyncing: boolean,
     expand: boolean,
-    unScroll?: boolean
+    scrollAttr?: IScrollAttr
 }, protyle: IProtyle) => {
     if (protyle.contentElement.classList.contains("fn__none")) {
         return;
@@ -189,7 +160,31 @@ const setHTML = (options: {
     if (protyle.options.render.scroll) {
         protyle.scroll.update(protyle);
     }
-    if (options.action.includes(Constants.CB_GET_HL) && !options.unScroll) {
+    if (options.scrollAttr) {
+        protyle.contentElement.scrollTop = options.scrollAttr.scrollTop;
+        if (options.action.includes(Constants.CB_GET_HL)) {
+            highlightById(protyle, options.scrollAttr.focusId, true);
+        } else if (options.action.includes(Constants.CB_GET_FOCUS)) {
+            if (options.scrollAttr.focusId) {
+                const range = focusByOffset(protyle.wysiwyg.element.querySelector(`[data-node-id="${options.scrollAttr.focusId}"]`), options.scrollAttr.focusStart, options.scrollAttr.focusEnd);
+                /// #if !MOBILE
+                if (!options.action.includes(Constants.CB_GET_UNUNDO)) {
+                    pushBack(protyle, range || undefined);
+                }
+                /// #endif
+            } else {
+                focusElement(protyle, options);
+            }
+        }
+        if (!protyle.scroll.element.classList.contains("fn__none")) {
+            // 使用动态滚动条定位到最后一个块,重启后无法触发滚动事件,需要再次更新 index
+            protyle.scroll.updateIndex(protyle, options.scrollAttr.startId);
+            // https://github.com/siyuan-note/siyuan/issues/8224
+            if (protyle.wysiwyg.element.clientHeight - parseInt(protyle.wysiwyg.element.style.paddingBottom) < protyle.contentElement.clientHeight) {
+                showMessage(window.siyuan.languages.scrollGetMore);
+            }
+        }
+    } else if (options.action.includes(Constants.CB_GET_HL)) {
         preventScroll(protyle); // 搜索页签滚动会导致再次请求
         const hlElement = highlightById(protyle, protyle.block.id, true);
         /// #if !MOBILE
@@ -197,39 +192,9 @@ const setHTML = (options: {
             pushBack(protyle, undefined, hlElement);
         }
         /// #endif
-    } else if (options.action.includes(Constants.CB_GET_FOCUS) && !options.unScroll) {
-        let focusElement: Element;
-        Array.from(protyle.wysiwyg.element.querySelectorAll(`[data-node-id="${protyle.block.id}"]`)).find((item: HTMLElement) => {
-            if (!hasClosestByAttribute(item, "data-type", "block-render", true)) {
-                focusElement = item;
-                return true;
-            }
-        });
-        if (protyle.block.mode === 4) {
-            preventScroll(protyle);
-            focusElement = protyle.wysiwyg.element.lastElementChild;
-        }
-        if (focusElement && !protyle.wysiwyg.element.firstElementChild.isSameNode(focusElement)) {
-            focusBlock(focusElement);
-            /// #if !MOBILE
-            if (!options.action.includes(Constants.CB_GET_UNUNDO)) {
-                pushBack(protyle, undefined, focusElement);
-            }
-            /// #endif
-            focusElement.scrollIntoView();
-            // 减少抖动 https://ld246.com/article/1654263598088
-            setTimeout(() => {
-                focusElement.scrollIntoView();
-            }, Constants.TIMEOUT_LOAD);
-        } else {
-            focusBlock(protyle.wysiwyg.element.firstElementChild);
-            /// #if !MOBILE
-            if (!options.action.includes(Constants.CB_GET_UNUNDO)) {
-                pushBack(protyle, undefined, protyle.wysiwyg.element.firstElementChild);
-            }
-            /// #endif
-        }
-    } else if (options.action.includes(Constants.CB_GET_FOCUSFIRST) && !options.unScroll) {
+    } else if (options.action.includes(Constants.CB_GET_FOCUS)) {
+        focusElement(protyle, options);
+    } else if (options.action.includes(Constants.CB_GET_FOCUSFIRST)) {
         // settimeout 时间需短一点,否则定位后快速滚动无效
         const headerHeight = protyle.wysiwyg.element.offsetTop - 16;
         preventScroll(protyle, headerHeight, 256);
@@ -355,3 +320,44 @@ export const enableProtyle = (protyle: IProtyle) => {
         }
     });
 };
+
+
+const focusElement = (protyle: IProtyle, options: {
+    content: string,
+    action?: string[],
+    isSyncing: boolean,
+    expand: boolean,
+    scrollAttr?: IScrollAttr
+}) => {
+    let focusElement: Element;
+    Array.from(protyle.wysiwyg.element.querySelectorAll(`[data-node-id="${protyle.block.id}"]`)).find((item: HTMLElement) => {
+        if (!hasClosestByAttribute(item, "data-type", "block-render", true)) {
+            focusElement = item;
+            return true;
+        }
+    });
+    if (protyle.block.mode === 4) {
+        preventScroll(protyle);
+        focusElement = protyle.wysiwyg.element.lastElementChild;
+    }
+    if (focusElement && !protyle.wysiwyg.element.firstElementChild.isSameNode(focusElement)) {
+        focusBlock(focusElement);
+        /// #if !MOBILE
+        if (!options.action.includes(Constants.CB_GET_UNUNDO)) {
+            pushBack(protyle, undefined, focusElement);
+        }
+        /// #endif
+        focusElement.scrollIntoView();
+        // 减少抖动 https://ld246.com/article/1654263598088
+        setTimeout(() => {
+            focusElement.scrollIntoView();
+        }, Constants.TIMEOUT_LOAD);
+    } else {
+        focusBlock(protyle.wysiwyg.element.firstElementChild);
+        /// #if !MOBILE
+        if (!options.action.includes(Constants.CB_GET_UNUNDO)) {
+            pushBack(protyle, undefined, protyle.wysiwyg.element.firstElementChild);
+        }
+        /// #endif
+    }
+}