From ec198ee4ebe97c8db376befa3e215d2bd43c4d13 Mon Sep 17 00:00:00 2001 From: Vanessa Date: Sat, 13 May 2023 22:16:22 +0800 Subject: [PATCH] :zap: https://github.com/siyuan-note/siyuan/issues/8248 --- app/src/menus/protyle.ts | 4 +- app/src/mobile/settings/editor.ts | 10 +- app/src/protyle/breadcrumb/action.ts | 19 +-- app/src/protyle/breadcrumb/index.ts | 16 +-- app/src/protyle/header/Title.ts | 4 +- app/src/protyle/index.ts | 170 ++++++++++++++++++--------- app/src/protyle/util/onGet.ts | 150 +++++++++++------------ 7 files changed, 202 insertions(+), 171 deletions(-) diff --git a/app/src/menus/protyle.ts b/app/src/menus/protyle.ts index 5596e1d72..2c615e0c2 100644 --- a/app/src/menus/protyle.ts +++ b/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; } diff --git a/app/src/mobile/settings/editor.ts b/app/src/mobile/settings/editor.ts index bf1c298de..d2c77f404 100644 --- a/app/src/mobile/settings/editor.ts +++ b/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(); }); }; diff --git a/app/src/protyle/breadcrumb/action.ts b/app/src/protyle/breadcrumb/action.ts index 0d9c4fb08..51764af08 100644 --- a/app/src/protyle/breadcrumb/action.ts +++ b/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 diff --git a/app/src/protyle/breadcrumb/index.ts b/app/src/protyle/breadcrumb/index.ts index 1e8d741a1..5cb3efc83 100644 --- a/app/src/protyle/breadcrumb/index.ts +++ b/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 diff --git a/app/src/protyle/header/Title.ts b/app/src/protyle/header/Title.ts index afc4d9a20..32d860774 100644 --- a/app/src/protyle/header/Title.ts +++ b/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); diff --git a/app/src/protyle/index.ts b/app/src/protyle/index.ts index e1310cc12..15cd0195e 100644 --- a/app/src/protyle/index.ts +++ b/app/src/protyle/index.ts @@ -192,70 +192,124 @@ 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); } - - // 需等待 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); - } - }); + } else { + this.getDoc(mergedOptions); + } } this.protyle.contentElement.classList.add("protyle-content--transition"); } + 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); + } + } + private init() { this.protyle.lute = setLute({ emojiSite: this.protyle.options.hint.emojiPath, diff --git a/app/src/protyle/util/onGet.ts b/app/src/protyle/util/onGet.ts index 8f014763e..01de5d2e7 100644 --- a/app/src/protyle/util/onGet.ts +++ b/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 + } +}