diff --git a/app/src/editor/index.ts b/app/src/editor/index.ts index 2263cfbff..e6ea79ef9 100644 --- a/app/src/editor/index.ts +++ b/app/src/editor/index.ts @@ -14,7 +14,8 @@ export class Editor extends Model { tab: Tab, blockId: string, mode?: TEditorMode, - action?: string[] + action?: string[], + scrollAttr?: string }) { super({ id: options.tab.id, @@ -31,6 +32,7 @@ export class Editor extends Model { blockId: string, action?: string[] mode?: TEditorMode, + scrollAttr?: string }) { this.editor = new Protyle(this.element, { action: options.action, @@ -41,6 +43,7 @@ export class Editor extends Model { background: true, scroll: true, }, + scrollAttr: options.scrollAttr, typewriterMode: true, after: (editor) => { if (window.siyuan.config.readonly) { diff --git a/app/src/layout/util.ts b/app/src/layout/util.ts index e386b7af1..ec26cc736 100644 --- a/app/src/layout/util.ts +++ b/app/src/layout/util.ts @@ -25,6 +25,7 @@ import {getContenteditableElement} from "../protyle/wysiwyg/getBlock"; import {updatePanelByEditor} from "../editor/util"; import {Constants} from "../constants"; import {openSearch} from "../search/spread"; +import {saveScroll} from "../protyle/scroll/saveScroll"; export const setPanelFocus = (element: Element) => { if (element.classList.contains("block__icons--active") || element.classList.contains("layout__wnd--active")) { @@ -210,7 +211,8 @@ const JSONToCenter = (json: any, layout?: Layout | Wnd | Tab | Model) => { tab: (layout as Tab), blockId: json.blockId, mode: json.mode, - action: [json.action] + action: [json.action], + scrollAttr: json.scrollAttr, })); } else if (json.instance === "Asset") { (layout as Tab).addModel(new Asset({ @@ -364,6 +366,7 @@ export const layoutToJSON = (layout: Layout | Wnd | Tab | Model, json: any) => { json.mode = layout.editor.protyle.preview.element.classList.contains("fn__none") ? "wysiwyg" : "preview"; json.action = layout.editor.protyle.block.showAll ? Constants.CB_GET_ALL : ""; json.instance = "Editor"; + json.scrollAttr = saveScroll(layout.editor.protyle, true); } else if (layout instanceof Asset) { json.path = layout.path; json.instance = "Asset"; @@ -470,7 +473,8 @@ export const copyTab = (tab: Tab) => { if (tab.model instanceof Editor) { model = new Editor({ tab: newTab, - blockId: tab.model.editor.protyle.block.rootID + blockId: tab.model.editor.protyle.block.rootID, + scrollAttr: saveScroll(tab.model.editor.protyle, true) }); } else if (tab.model instanceof Asset) { model = new Asset({ diff --git a/app/src/protyle/breadcrumb/action.ts b/app/src/protyle/breadcrumb/action.ts index b05398f0b..75749018a 100644 --- a/app/src/protyle/breadcrumb/action.ts +++ b/app/src/protyle/breadcrumb/action.ts @@ -5,12 +5,15 @@ 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 {hideElements} from "../ui/hideElements"; export const netImg2LocalAssets = (protyle: IProtyle) => { if (protyle.element.querySelector(".fn__loading")) { return; } addLoading(protyle); + hideElements(["toolbar"], protyle); fetchPost("/api/format/netImg2LocalAssets", { id: protyle.block.rootID }, () => { @@ -20,7 +23,7 @@ export const netImg2LocalAssets = (protyle: IProtyle) => { mode: 0, size: Constants.SIZE_GET, }, getResponse => { - onGet(getResponse, protyle, [Constants.CB_GET_FOCUS]); + onGet(getResponse, protyle, [Constants.CB_GET_FOCUS], saveScroll(protyle, true)); }); /// #else getAllModels().editor.forEach(item => { @@ -30,7 +33,7 @@ export const netImg2LocalAssets = (protyle: IProtyle) => { mode: 0, size: Constants.SIZE_GET, }, getResponse => { - onGet(getResponse, item.editor.protyle, [Constants.CB_GET_FOCUS]); + onGet(getResponse, item.editor.protyle, [Constants.CB_GET_FOCUS], saveScroll(protyle, true)); }); } }); diff --git a/app/src/protyle/breadcrumb/index.ts b/app/src/protyle/breadcrumb/index.ts index b78582b19..dd0dbf74b 100644 --- a/app/src/protyle/breadcrumb/index.ts +++ b/app/src/protyle/breadcrumb/index.ts @@ -22,6 +22,8 @@ import {getAllModels} from "../../layout/getAll"; import {getCurrentWindow} from "@electron/remote"; /// #endif import {onGet} from "../util/onGet"; +import {saveScroll} from "../scroll/saveScroll"; +import {hideElements} from "../ui/hideElements"; export class Breadcrumb { public element: HTMLElement; @@ -218,7 +220,7 @@ export class Breadcrumb { label: window.siyuan.languages.netImg2LocalAsset, icon: "iconTransform", accelerator: window.siyuan.config.keymap.editor.general.netImg2LocalAsset.custom, - click () { + click() { netImg2LocalAssets(protyle); } }).element); @@ -226,6 +228,7 @@ export class Breadcrumb { label: window.siyuan.languages.optimizeTypography, icon: "iconFormat", click: () => { + hideElements(["toolbar"], protyle); fetchPost("/api/format/autoSpace", { id: protyle.block.rootID }, () => { @@ -235,7 +238,7 @@ export class Breadcrumb { mode: 0, size: Constants.SIZE_GET, }, getResponse => { - onGet(getResponse, protyle, [Constants.CB_GET_FOCUS]); + onGet(getResponse, protyle, [Constants.CB_GET_FOCUS], saveScroll(protyle, true)); }); /// #else getAllModels().editor.forEach(item => { @@ -245,7 +248,7 @@ export class Breadcrumb { mode: 0, size: Constants.SIZE_GET, }, getResponse => { - onGet(getResponse, item.editor.protyle, [Constants.CB_GET_FOCUS]); + onGet(getResponse, item.editor.protyle, [Constants.CB_GET_FOCUS], saveScroll(protyle, true)); }); } }); @@ -274,7 +277,7 @@ export class Breadcrumb { mode: 0, size: protyle.block.showAll ? Constants.SIZE_GET_MAX : Constants.SIZE_GET, }, getResponse => { - onGet(getResponse, protyle, protyle.block.showAll ? [Constants.CB_GET_ALL, Constants.CB_GET_FOCUS] : [Constants.CB_GET_FOCUS]); + onGet(getResponse, protyle, protyle.block.showAll ? [Constants.CB_GET_ALL, Constants.CB_GET_FOCUS] : [Constants.CB_GET_FOCUS], saveScroll(protyle, true)); }); } }).element); diff --git a/app/src/protyle/header/Title.ts b/app/src/protyle/header/Title.ts index edd08c8bc..9f4ea66e7 100644 --- a/app/src/protyle/header/Title.ts +++ b/app/src/protyle/header/Title.ts @@ -325,9 +325,9 @@ ${window.siyuan.languages.createdAt} ${dayjs(response.data.ial.id.substr(0, 14)) } } - public render(protyle: IProtyle, refresh = false, action:string[] = []) { + public render(protyle: IProtyle, refresh = false, scrollAttr?: string) { if (this.editElement.getAttribute("data-render") === "true" && !refresh) { - return; + return false; } fetchPost("/api/block/getDocInfo", { id: protyle.block.rootID @@ -360,9 +360,8 @@ ${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); + if (scrollAttr) { + restoreScroll(protyle, scrollAttr === Constants.CB_GET_SCROLL ? undefined : scrollAttr); } }); } diff --git a/app/src/protyle/index.ts b/app/src/protyle/index.ts index a4a73ba8f..3df7113d6 100644 --- a/app/src/protyle/index.ts +++ b/app/src/protyle/index.ts @@ -160,7 +160,7 @@ class Protyle { mode: (options.action && options.action.includes(Constants.CB_GET_CONTEXT)) ? 3 : 0, // 0: 仅当前 ID(默认值),1:向上 2:向下,3:上下都加载,4:加载最后 size: options.action?.includes(Constants.CB_GET_ALL) ? Constants.SIZE_GET_MAX : Constants.SIZE_GET, }, getResponse => { - onGet(getResponse, this.protyle, options.action); + onGet(getResponse, this.protyle, options.action, options.scrollAttr); if (this.protyle.model) { /// #if !MOBILE if (options.action?.includes(Constants.CB_GET_FOCUS)) { diff --git a/app/src/protyle/scroll/saveScroll.ts b/app/src/protyle/scroll/saveScroll.ts index 4b0323025..33f10bf55 100644 --- a/app/src/protyle/scroll/saveScroll.ts +++ b/app/src/protyle/scroll/saveScroll.ts @@ -3,11 +3,9 @@ import {hasClosestBlock} from "../util/hasClosest"; import {focusByOffset, getSelectionOffset} from "../util/selection"; import {fetchPost} from "../../util/fetch"; import {zoomOut} from "../../menus/protyle"; +import {preventScroll} from "./preventScroll"; -export const saveScroll = (protyle: IProtyle) => { - if (protyle.contentElement.clientHeight === protyle.contentElement.scrollHeight) { - return; - } +export const saveScroll = (protyle: IProtyle, getString = false) => { 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) { @@ -24,17 +22,20 @@ export const saveScroll = (protyle: IProtyle) => { if (protyle.block.showAll) { attr += `${Constants.ZWSP}${protyle.block.id}`; } - + if (getString) { + return attr; + } 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") +export const restoreScroll = (protyle: IProtyle, scrollAttr?: string) => { + const attr = scrollAttr || protyle.wysiwyg.element.getAttribute("scroll") if (!attr) { - return + return; } + preventScroll(protyle); 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) { diff --git a/app/src/protyle/util/onGet.ts b/app/src/protyle/util/onGet.ts index a664988f7..a039b44f9 100644 --- a/app/src/protyle/util/onGet.ts +++ b/app/src/protyle/util/onGet.ts @@ -14,8 +14,9 @@ import {pushBack} from "../../util/backForward"; import {focusBlock} from "./selection"; import {hasClosestByAttribute, hasClosestByClassName} from "./hasClosest"; import {preventScroll} from "../scroll/preventScroll"; +import {restoreScroll} from "../scroll/saveScroll"; -export const onGet = (data: IWebSocketData, protyle: IProtyle, action: string[] = []) => { +export const onGet = (data: IWebSocketData, protyle: IProtyle, action: string[] = [], scrollAttr?: string) => { const loadingElement = protyle.element.querySelector(".fn__loading"); if (loadingElement) { loadingElement.remove(); @@ -80,7 +81,8 @@ export const onGet = (data: IWebSocketData, protyle: IProtyle, action: string[] } if (protyle.options.render.title) { - protyle.title.render(protyle, false, action); + // 页签没有打开 + protyle.title.render(protyle, false, scrollAttr ? scrollAttr : (action.includes(Constants.CB_GET_SCROLL) ? Constants.CB_GET_SCROLL : null)); } else if (protyle.options.render.background) { fetchPost("/api/block/getDocInfo", { id: protyle.block.rootID @@ -94,6 +96,10 @@ export const onGet = (data: IWebSocketData, protyle: IProtyle, action: string[] content: html, action, }, protyle); + + if (scrollAttr && ((protyle.options.render.title && protyle.title.editElement.getAttribute("data-render") === "true") || !protyle.options.render.title)) { + restoreScroll(protyle, scrollAttr); + } }; const setHTML = (options: { content: string, action?: string[] }, protyle: IProtyle) => { diff --git a/app/src/protyle/wysiwyg/commonHotkey.ts b/app/src/protyle/wysiwyg/commonHotkey.ts index 69fdc168c..5a368ee2f 100644 --- a/app/src/protyle/wysiwyg/commonHotkey.ts +++ b/app/src/protyle/wysiwyg/commonHotkey.ts @@ -7,6 +7,7 @@ import {addLoading, setPadding} from "../ui/initUI"; import {Constants} from "../../constants"; import {onGet} from "../util/onGet"; import {openBacklink, openGraph, openOutline} from "../../layout/dock/util"; +import {saveScroll} from "../scroll/saveScroll"; export const commonHotkey = (protyle: IProtyle, event: KeyboardEvent) => { const target = event.target as HTMLElement; @@ -21,14 +22,14 @@ export const commonHotkey = (protyle: IProtyle, event: KeyboardEvent) => { return true; } if (matchHotKey(window.siyuan.config.keymap.editor.general.refresh.custom, event)) { - protyle.title.render(protyle, true); + protyle.title?.render(protyle, true); addLoading(protyle); fetchPost("/api/filetree/getDoc", { id: protyle.block.showAll ? protyle.block.id : protyle.block.rootID, mode: 0, size: protyle.block.showAll ? Constants.SIZE_GET_MAX : Constants.SIZE_GET, }, getResponse => { - onGet(getResponse, protyle, protyle.block.showAll ? [Constants.CB_GET_ALL, Constants.CB_GET_FOCUS] : [Constants.CB_GET_FOCUS]); + onGet(getResponse, protyle, protyle.block.showAll ? [Constants.CB_GET_ALL, Constants.CB_GET_FOCUS] : [Constants.CB_GET_FOCUS], saveScroll(protyle, true)); }); event.preventDefault(); event.stopPropagation(); diff --git a/app/src/types/protyle.d.ts b/app/src/types/protyle.d.ts index 52b885ec2..a21844ee3 100644 --- a/app/src/types/protyle.d.ts +++ b/app/src/types/protyle.d.ts @@ -346,6 +346,7 @@ interface IOptions { mode?: TEditorMode, blockId: string key?: string + scrollAttr?: string defId?: string render?: { background?: boolean