Explorar el Código

:sparkles: https://github.com/siyuan-note/siyuan/issues/4042

Vanessa hace 2 años
padre
commit
72fba69115

+ 1 - 0
app/src/constants.ts

@@ -50,6 +50,7 @@ export abstract class Constants {
     public static readonly CB_GET_SETID = "cb-get-setid"; // 重置 blockid
     public static readonly CB_GET_ALL = "cb-get-all"; // 获取所有块
     public static readonly CB_GET_UNUNDO = "cb-get-unundo"; // 不需要记录历史
+    public static readonly CB_GET_SCROLL = "cb-get-scroll"; // 滚动到指定位置
 
     // localstorage
     public static readonly LOCAL_SEARCHEDATA = "local-searchedata";

+ 4 - 0
app/src/layout/Wnd.ts

@@ -26,6 +26,7 @@ import {getAllModels} from "./getAll";
 import {fetchPost} from "../util/fetch";
 import {onGet} from "../protyle/util/onGet";
 import {countBlockWord} from "./status";
+import {saveScroll} from "../protyle/scroll/saveScroll";
 
 export class Wnd {
     public id: string;
@@ -488,6 +489,9 @@ export class Wnd {
     private removeTabAction = (id: string, closeAll = false) => {
         this.children.find((item, index) => {
             if (item.id === id) {
+                if (item.model instanceof Editor) {
+                    saveScroll(item.model.editor.protyle);
+                }
                 if (this.children.length === 1) {
                     this.destroyModel(this.children[0].model);
                     this.children = [];

+ 2 - 2
app/src/layout/dock/Files.ts

@@ -235,12 +235,12 @@ export class Files extends Model {
                                         openFileById({
                                             id: target.getAttribute("data-node-id"),
                                             position: "right",
-                                            action: [Constants.CB_GET_FOCUS]
+                                            action: [Constants.CB_GET_FOCUS, Constants.CB_GET_SCROLL]
                                         });
                                     } else {
                                         openFileById({
                                             id: target.getAttribute("data-node-id"),
-                                            action: [Constants.CB_GET_FOCUS]
+                                            action: [Constants.CB_GET_FOCUS, Constants.CB_GET_SCROLL]
                                         });
                                     }
                                 } else if (target.getAttribute("data-type") === "navigation-root") {

+ 4 - 1
app/src/menus/protyle.ts

@@ -338,7 +338,7 @@ export const contentMenu = (protyle: IProtyle, nodeElement: Element) => {
     }
 };
 
-export const zoomOut = (protyle: IProtyle, id: string, focusId?: string, isPushBack = true) => {
+export const zoomOut = (protyle: IProtyle, id: string, focusId?: string, isPushBack = true, callback?: () => void) => {
     const breadcrumbHLElement = protyle.breadcrumb.element.querySelector(".protyle-breadcrumb__item--active");
     if (breadcrumbHLElement && breadcrumbHLElement.getAttribute("data-node-id") === id) {
         if (id === protyle.block.rootID) {
@@ -393,6 +393,9 @@ export const zoomOut = (protyle: IProtyle, id: string, focusId?: string, isPushB
             updateBacklinkGraph(getAllModels(), protyle);
         }
         /// #endif
+        if (callback) {
+            callback();
+        }
     });
 };
 

+ 6 - 1
app/src/protyle/header/Title.ts

@@ -26,6 +26,7 @@ import {getNoContainerElement} from "../wysiwyg/getBlock";
 import {commonHotkey} from "../wysiwyg/commonHotkey";
 import {code160to32} from "../util/code160to32";
 import {deleteFile} from "../../editor/deleteFile";
+import {restoreScroll} from "../scroll/saveScroll";
 
 export class Title {
     public element: HTMLElement;
@@ -324,7 +325,7 @@ ${window.siyuan.languages.createdAt} ${dayjs(response.data.ial.id.substr(0, 14))
         }
     }
 
-    public render(protyle: IProtyle, refresh = false) {
+    public render(protyle: IProtyle, refresh = false, action:string[] = []) {
         if (this.editElement.getAttribute("data-render") === "true" && !refresh) {
             return;
         }
@@ -359,6 +360,10 @@ ${window.siyuan.languages.createdAt} ${dayjs(response.data.ial.id.substr(0, 14))
                 range.selectNodeContents(this.editElement);
                 focusByRange(range);
             }
+
+            if (action.includes(Constants.CB_GET_SCROLL)) {
+                restoreScroll(protyle);
+            }
         });
     }
 }

+ 59 - 0
app/src/protyle/scroll/saveScroll.ts

@@ -0,0 +1,59 @@
+import {Constants} from "../../constants";
+import {hasClosestBlock} from "../util/hasClosest";
+import {focusByOffset, getSelectionOffset} from "../util/selection";
+import {fetchPost} from "../../util/fetch";
+import {zoomOut} from "../../menus/protyle";
+
+export const saveScroll = (protyle: IProtyle) => {
+    if (protyle.contentElement.clientHeight === protyle.contentElement.scrollHeight) {
+        return;
+    }
+    let attr = `${protyle.wysiwyg.element.firstElementChild.getAttribute("data-node-id")}${Constants.ZWSP}${protyle.wysiwyg.element.lastElementChild.getAttribute("data-node-id")}${Constants.ZWSP}${protyle.contentElement.scrollTop}`;
+    let range: Range
+    if (getSelection().rangeCount > 0) {
+        range = getSelection().getRangeAt(0)
+    }
+
+    if (range && protyle.wysiwyg.element.contains(range.startContainer)) {
+        const blockElement = hasClosestBlock(range.startContainer);
+        if (blockElement) {
+            const position = getSelectionOffset(blockElement, undefined, range);
+            attr += `${Constants.ZWSP}${blockElement.getAttribute("data-node-id")}${Constants.ZWSP}${position.start}${Constants.ZWSP}${position.end}`;
+        }
+    }
+    if (protyle.block.showAll) {
+        attr += `${Constants.ZWSP}${protyle.block.id}`;
+    }
+
+    fetchPost("/api/attr/setBlockAttrs", {id: protyle.block.rootID, attrs: {scroll: attr}}, () => {
+        protyle.wysiwyg.element.setAttribute("scroll", attr);
+    });
+}
+
+export const restoreScroll = (protyle: IProtyle) => {
+    const attr = protyle.wysiwyg.element.getAttribute("scroll")
+    if (!attr) {
+        return
+    }
+    const [startId, endId, scrollTop, focusId, focusStart, focusEnd, zoomInId] = attr.split(Constants.ZWSP);
+    if (protyle.wysiwyg.element.firstElementChild.getAttribute("data-node-id") === startId &&
+        protyle.wysiwyg.element.lastElementChild.getAttribute("data-node-id") === endId) {
+        protyle.contentElement.scrollTop = parseInt(scrollTop);
+        focusByOffset(protyle.wysiwyg.element.querySelector(`[data-node-id="${focusId}"]`), parseInt(focusStart), parseInt(focusEnd));
+    } else if (zoomInId && protyle.block.id !== zoomInId) {
+        zoomOut(protyle, zoomInId, undefined, false, () => {
+            protyle.contentElement.scrollTop = parseInt(scrollTop);
+            focusByOffset(protyle.wysiwyg.element.querySelector(`[data-node-id="${focusId}"]`), parseInt(focusStart), parseInt(focusEnd));
+        });
+    } else if (!protyle.scroll.element.classList.contains("fn__none")) {
+        fetchPost("/api/filetree/getDoc", {
+            id: protyle.block.id,
+            startID: startId,
+            endID: endId,
+        }, getResponse => {
+            protyle.wysiwyg.element.innerHTML = getResponse.data.content;
+            protyle.contentElement.scrollTop = parseInt(scrollTop);
+            focusByOffset(protyle.wysiwyg.element.querySelector(`[data-node-id="${focusId}"]`), parseInt(focusStart), parseInt(focusEnd));
+        })
+    }
+}

+ 1 - 1
app/src/protyle/util/onGet.ts

@@ -80,7 +80,7 @@ export const onGet = (data: IWebSocketData, protyle: IProtyle, action: string[]
     }
 
     if (protyle.options.render.title) {
-        protyle.title.render(protyle);
+        protyle.title.render(protyle, false, action);
     } else if (protyle.options.render.background) {
         fetchPost("/api/block/getDocInfo", {
             id: protyle.block.rootID

+ 1 - 1
app/src/protyle/wysiwyg/index.ts

@@ -86,7 +86,7 @@ export class WYSIWYG {
         const ialKeys = Object.keys(ial);
         for (let i = 0; i < this.element.attributes.length; i++) {
             const oldKey = this.element.attributes[i].nodeName;
-            if (!["type", "class", "spellcheck", "contenteditable", "data-doc-type", "style"].includes(oldKey) &&
+            if (!["type", "class", "spellcheck", "contenteditable", "data-doc-type", "style", "scroll"].includes(oldKey) &&
                 !ialKeys.includes(oldKey)) {
                 this.element.removeAttribute(oldKey);
                 i--;