This commit is contained in:
parent
ad2510dfb5
commit
b5b46afabd
9 changed files with 124 additions and 97 deletions
|
@ -15,7 +15,7 @@ export class Editor extends Model {
|
|||
blockId: string,
|
||||
mode?: TEditorMode,
|
||||
action?: string[],
|
||||
scrollAttr?: string
|
||||
scrollAttr?: IScrollAttr
|
||||
}) {
|
||||
super({
|
||||
id: options.tab.id,
|
||||
|
@ -32,7 +32,7 @@ export class Editor extends Model {
|
|||
blockId: string,
|
||||
action?: string[]
|
||||
mode?: TEditorMode,
|
||||
scrollAttr?: string
|
||||
scrollAttr?: IScrollAttr
|
||||
}) {
|
||||
this.editor = new Protyle(this.element, {
|
||||
action: options.action,
|
||||
|
|
|
@ -271,13 +271,12 @@ export class Breadcrumb {
|
|||
accelerator: window.siyuan.config.keymap.editor.general.refresh.custom,
|
||||
label: window.siyuan.languages.refresh,
|
||||
click: () => {
|
||||
protyle.title?.render(protyle, true);
|
||||
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], saveScroll(protyle, true));
|
||||
onGet(getResponse, protyle, protyle.block.showAll ? [Constants.CB_GET_ALL, Constants.CB_GET_FOCUS] : [Constants.CB_GET_FOCUS], saveScroll(protyle, true), true);
|
||||
});
|
||||
}
|
||||
}).element);
|
||||
|
|
|
@ -325,48 +325,37 @@ ${window.siyuan.languages.createdAt} ${dayjs(response.data.ial.id.substr(0, 14))
|
|||
}
|
||||
}
|
||||
|
||||
public render(protyle: IProtyle, refresh = false, scrollAttr?: string) {
|
||||
public render(protyle: IProtyle, response: IWebSocketData, refresh = false) {
|
||||
if (this.editElement.getAttribute("data-render") === "true" && !refresh) {
|
||||
return false;
|
||||
}
|
||||
fetchPost("/api/block/getDocInfo", {
|
||||
id: protyle.block.rootID
|
||||
}, (response) => {
|
||||
setTitle(response.data.ial.title);
|
||||
protyle.background.render(response.data.ial, protyle.block.rootID);
|
||||
protyle.wysiwyg.renderCustom(response.data.ial);
|
||||
this.editElement.setAttribute("data-render", "true");
|
||||
this.setTitle(response.data.ial.title);
|
||||
let nodeAttrHTML = "";
|
||||
if (response.data.ial.bookmark) {
|
||||
nodeAttrHTML += `<div class="protyle-attr--bookmark">${Lute.EscapeHTMLStr(response.data.ial.bookmark)}</div>`;
|
||||
}
|
||||
if (response.data.ial.name) {
|
||||
nodeAttrHTML += `<div class="protyle-attr--name"><svg><use xlink:href="#iconN"></use></svg>${Lute.EscapeHTMLStr(response.data.ial.name)}</div>`;
|
||||
}
|
||||
if (response.data.ial.alias) {
|
||||
nodeAttrHTML += `<div class="protyle-attr--alias"><svg><use xlink:href="#iconA"></use></svg>${Lute.EscapeHTMLStr(response.data.ial.alias)}</div>`;
|
||||
}
|
||||
if (response.data.ial.memo) {
|
||||
nodeAttrHTML += `<div class="protyle-attr--memo b3-tooltips b3-tooltips__sw" aria-label="${Lute.EscapeHTMLStr(response.data.ial.memo)}"><svg><use xlink:href="#iconM"></use></svg></div>`;
|
||||
}
|
||||
this.element.querySelector(".protyle-attr").innerHTML = nodeAttrHTML;
|
||||
if (response.data.refCount !== 0) {
|
||||
this.element.querySelector(".protyle-attr").insertAdjacentHTML("beforeend", `<div class="protyle-attr--refcount popover__block" data-defids='${JSON.stringify([protyle.block.rootID])}' data-id='${JSON.stringify(response.data.refIDs)}'>${response.data.refCount}</div>`);
|
||||
}
|
||||
// 存在设置新建文档名模板,不能使用 Untitled 进行判断,https://ld246.com/article/1649301009888
|
||||
if (new Date().getTime() - dayjs(response.data.id.split("-")[0]).toDate().getTime() < 2000) {
|
||||
const range = this.editElement.ownerDocument.createRange();
|
||||
range.selectNodeContents(this.editElement);
|
||||
focusByRange(range);
|
||||
}
|
||||
const loadingElement = protyle.element.querySelector(".fn__loading");
|
||||
if (loadingElement) {
|
||||
loadingElement.remove();
|
||||
}
|
||||
if (scrollAttr) {
|
||||
restoreScroll(protyle, scrollAttr === Constants.CB_GET_SCROLL ? undefined : scrollAttr);
|
||||
}
|
||||
});
|
||||
setTitle(response.data.ial.title);
|
||||
protyle.background.render(response.data.ial, protyle.block.rootID);
|
||||
protyle.wysiwyg.renderCustom(response.data.ial);
|
||||
this.editElement.setAttribute("data-render", "true");
|
||||
this.setTitle(response.data.ial.title);
|
||||
let nodeAttrHTML = "";
|
||||
if (response.data.ial.bookmark) {
|
||||
nodeAttrHTML += `<div class="protyle-attr--bookmark">${Lute.EscapeHTMLStr(response.data.ial.bookmark)}</div>`;
|
||||
}
|
||||
if (response.data.ial.name) {
|
||||
nodeAttrHTML += `<div class="protyle-attr--name"><svg><use xlink:href="#iconN"></use></svg>${Lute.EscapeHTMLStr(response.data.ial.name)}</div>`;
|
||||
}
|
||||
if (response.data.ial.alias) {
|
||||
nodeAttrHTML += `<div class="protyle-attr--alias"><svg><use xlink:href="#iconA"></use></svg>${Lute.EscapeHTMLStr(response.data.ial.alias)}</div>`;
|
||||
}
|
||||
if (response.data.ial.memo) {
|
||||
nodeAttrHTML += `<div class="protyle-attr--memo b3-tooltips b3-tooltips__sw" aria-label="${Lute.EscapeHTMLStr(response.data.ial.memo)}"><svg><use xlink:href="#iconM"></use></svg></div>`;
|
||||
}
|
||||
this.element.querySelector(".protyle-attr").innerHTML = nodeAttrHTML;
|
||||
if (response.data.refCount !== 0) {
|
||||
this.element.querySelector(".protyle-attr").insertAdjacentHTML("beforeend", `<div class="protyle-attr--refcount popover__block" data-defids='${JSON.stringify([protyle.block.rootID])}' data-id='${JSON.stringify(response.data.refIDs)}'>${response.data.refCount}</div>`);
|
||||
}
|
||||
// 存在设置新建文档名模板,不能使用 Untitled 进行判断,https://ld246.com/article/1649301009888
|
||||
if (new Date().getTime() - dayjs(response.data.id.split("-")[0]).toDate().getTime() < 2000) {
|
||||
const range = this.editElement.ownerDocument.createRange();
|
||||
range.selectNodeContents(this.editElement);
|
||||
focusByRange(range);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,12 +1,16 @@
|
|||
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";
|
||||
import {preventScroll} from "./preventScroll";
|
||||
import {pushBack} from "../../util/backForward";
|
||||
|
||||
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}`;
|
||||
export const saveScroll = (protyle: IProtyle, getObject = false) => {
|
||||
const attr: IScrollAttr = {
|
||||
startId: protyle.wysiwyg.element.firstElementChild.getAttribute("data-node-id"),
|
||||
endId: protyle.wysiwyg.element.lastElementChild.getAttribute("data-node-id"),
|
||||
scrollTop: protyle.contentElement.scrollTop
|
||||
}
|
||||
let range: Range
|
||||
if (getSelection().rangeCount > 0) {
|
||||
range = getSelection().getRangeAt(0)
|
||||
|
@ -16,45 +20,58 @@ export const saveScroll = (protyle: IProtyle, getString = false) => {
|
|||
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}`;
|
||||
attr.focusId = blockElement.getAttribute("data-node-id");
|
||||
attr.focusStart = position.start
|
||||
attr.focusEnd = position.end
|
||||
|
||||
}
|
||||
}
|
||||
if (protyle.block.showAll) {
|
||||
attr += `${Constants.ZWSP}${protyle.block.id}`;
|
||||
attr.zoomInId = protyle.block.id
|
||||
}
|
||||
if (getString) {
|
||||
if (getObject) {
|
||||
return attr;
|
||||
}
|
||||
fetchPost("/api/attr/setBlockAttrs", {id: protyle.block.rootID, attrs: {scroll: attr}}, () => {
|
||||
protyle.wysiwyg.element.setAttribute("scroll", attr);
|
||||
protyle.wysiwyg.element.setAttribute("scroll", JSON.stringify(attr));
|
||||
});
|
||||
}
|
||||
|
||||
export const restoreScroll = (protyle: IProtyle, scrollAttr?: string) => {
|
||||
const attr = scrollAttr || protyle.wysiwyg.element.getAttribute("scroll")
|
||||
if (!attr) {
|
||||
return;
|
||||
}
|
||||
export const restoreScroll = (protyle: IProtyle, scrollAttr: IScrollAttr) => {
|
||||
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) {
|
||||
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));
|
||||
if (protyle.wysiwyg.element.firstElementChild.getAttribute("data-node-id") === scrollAttr.startId &&
|
||||
protyle.wysiwyg.element.lastElementChild.getAttribute("data-node-id") === scrollAttr.endId) {
|
||||
// 需等动画效果完毕,才能获得最大高度。否则尾部定位无法滚动到底部
|
||||
setTimeout(() => {
|
||||
protyle.contentElement.scrollTop = scrollAttr.scrollTop;
|
||||
}, 256);
|
||||
if (scrollAttr.focusId) {
|
||||
const range = focusByOffset(protyle.wysiwyg.element.querySelector(`[data-node-id="${scrollAttr.focusId}"]`), scrollAttr.focusStart, scrollAttr.focusEnd);
|
||||
/// #if !MOBILE
|
||||
pushBack(protyle, range || undefined);
|
||||
/// #endif
|
||||
}
|
||||
} else if (scrollAttr.zoomInId && protyle.block.id !== scrollAttr.zoomInId) {
|
||||
zoomOut(protyle, scrollAttr.zoomInId, undefined, true, () => {
|
||||
protyle.contentElement.scrollTop = scrollAttr.scrollTop;
|
||||
if (scrollAttr.focusId) {
|
||||
focusByOffset(protyle.wysiwyg.element.querySelector(`[data-node-id="${scrollAttr.focusId}"]`), scrollAttr.focusStart, scrollAttr.focusEnd);
|
||||
}
|
||||
});
|
||||
} else if (!protyle.scroll.element.classList.contains("fn__none")) {
|
||||
fetchPost("/api/filetree/getDoc", {
|
||||
id: protyle.block.id,
|
||||
startID: startId,
|
||||
endID: endId,
|
||||
startID: scrollAttr.startId,
|
||||
endID: scrollAttr.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));
|
||||
protyle.contentElement.scrollTop = scrollAttr.scrollTop;
|
||||
if (scrollAttr.focusId) {
|
||||
const range = focusByOffset(protyle.wysiwyg.element.querySelector(`[data-node-id="${scrollAttr.focusId}"]`), scrollAttr.focusStart, scrollAttr.focusEnd);
|
||||
/// #if !MOBILE
|
||||
pushBack(protyle, range || undefined);
|
||||
/// #endif
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,7 +16,7 @@ import {hasClosestByAttribute, hasClosestByClassName} from "./hasClosest";
|
|||
import {preventScroll} from "../scroll/preventScroll";
|
||||
import {restoreScroll} from "../scroll/saveScroll";
|
||||
|
||||
export const onGet = (data: IWebSocketData, protyle: IProtyle, action: string[] = [], scrollAttr?: string) => {
|
||||
export const onGet = (data: IWebSocketData, protyle: IProtyle, action: string[] = [], scrollAttr?: IScrollAttr, renderTitle = false) => {
|
||||
protyle.wysiwyg.element.removeAttribute("data-top");
|
||||
if (data.code === 1) {
|
||||
// 其他报错
|
||||
|
@ -76,35 +76,45 @@ export const onGet = (data: IWebSocketData, protyle: IProtyle, action: string[]
|
|||
protyle.wysiwyg.element.setAttribute("data-doc-type", data.data.type);
|
||||
}
|
||||
|
||||
if (protyle.options.render.title) {
|
||||
// 页签没有打开
|
||||
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
|
||||
}, (response) => {
|
||||
fetchPost("/api/block/getDocInfo", {
|
||||
id: protyle.block.rootID
|
||||
}, (response) => {
|
||||
if (protyle.options.render.title) {
|
||||
// 页签没有打开
|
||||
protyle.title.render(protyle, response, renderTitle);
|
||||
} else if (protyle.options.render.background) {
|
||||
protyle.background.render(response.data.ial, protyle.block.rootID);
|
||||
protyle.wysiwyg.renderCustom(response.data.ial);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
setHTML({
|
||||
content: html,
|
||||
action,
|
||||
}, protyle);
|
||||
let scrollObj = scrollAttr;
|
||||
if (!scrollObj) {
|
||||
if (action.includes(Constants.CB_GET_SCROLL) && response.data.ial.scroll) {
|
||||
try {
|
||||
scrollObj = JSON.parse(response.data.ial.scroll)
|
||||
} catch (e) {
|
||||
scrollObj = undefined;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ((protyle.options.render.title && protyle.title.editElement.getAttribute("data-render") === "true") || !protyle.options.render.title) {
|
||||
setHTML({
|
||||
content: html,
|
||||
action,
|
||||
unScroll: (scrollObj && scrollObj.focusId) ? true : false,
|
||||
}, protyle);
|
||||
|
||||
if (scrollObj) {
|
||||
restoreScroll(protyle, scrollObj);
|
||||
}
|
||||
const loadingElement = protyle.element.querySelector(".fn__loading");
|
||||
if (loadingElement) {
|
||||
loadingElement.remove();
|
||||
}
|
||||
if (scrollAttr) {
|
||||
restoreScroll(protyle, scrollAttr);
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const setHTML = (options: { content: string, action?: string[] }, protyle: IProtyle) => {
|
||||
const setHTML = (options: { content: string, action?: string[], unScroll?: boolean }, protyle: IProtyle) => {
|
||||
if (protyle.contentElement.classList.contains("fn__none")) {
|
||||
return;
|
||||
}
|
||||
|
@ -155,7 +165,7 @@ const setHTML = (options: { content: string, action?: string[] }, protyle: IProt
|
|||
if (protyle.options.render.scroll) {
|
||||
protyle.scroll.update(protyle.block.blockCount, protyle);
|
||||
}
|
||||
if (options.action.includes(Constants.CB_GET_HL)) {
|
||||
if (options.action.includes(Constants.CB_GET_HL) && !options.unScroll) {
|
||||
preventScroll(protyle); // 搜索页签滚动会导致再次请求
|
||||
const hlElement = highlightById(protyle, protyle.block.id, true);
|
||||
/// #if !MOBILE
|
||||
|
@ -163,7 +173,7 @@ const setHTML = (options: { content: string, action?: string[] }, protyle: IProt
|
|||
pushBack(protyle, undefined, hlElement);
|
||||
}
|
||||
/// #endif
|
||||
} else if (options.action.includes(Constants.CB_GET_FOCUS)) {
|
||||
} 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)) {
|
||||
|
@ -195,13 +205,15 @@ const setHTML = (options: { content: string, action?: string[] }, protyle: IProt
|
|||
}
|
||||
/// #endif
|
||||
}
|
||||
} else if (options.action.includes(Constants.CB_GET_FOCUSFIRST)) {
|
||||
} else if (options.action.includes(Constants.CB_GET_FOCUSFIRST) && !options.unScroll) {
|
||||
// settimeout 时间需短一点,否则定位后快速滚动无效
|
||||
preventScroll(protyle, 8, 256);
|
||||
protyle.contentElement.scrollTop = 8;
|
||||
focusBlock(protyle.wysiwyg.element.firstElementChild);
|
||||
/// #if !MOBILE
|
||||
pushBack(protyle, undefined, protyle.wysiwyg.element.firstElementChild);
|
||||
if (!options.action.includes(Constants.CB_GET_UNUNDO)) {
|
||||
pushBack(protyle, undefined, protyle.wysiwyg.element.firstElementChild);
|
||||
}
|
||||
/// #endif
|
||||
}
|
||||
if (protyle.disabled) {
|
||||
|
|
|
@ -282,7 +282,7 @@ export const setFirstNodeRange = (editElement: Element, range: Range) => {
|
|||
|
||||
export const focusByOffset = (container: Node, start: number, end: number) => {
|
||||
if (!container) {
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
let startNode;
|
||||
searchNode(container, container.firstChild, node => {
|
||||
|
@ -342,6 +342,7 @@ export const focusByOffset = (container: Node, start: number, end: number) => {
|
|||
}
|
||||
}
|
||||
focusByRange(range);
|
||||
return range;
|
||||
};
|
||||
|
||||
export const focusByWbr = (element: Element, range: Range) => {
|
||||
|
|
|
@ -22,14 +22,13 @@ 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);
|
||||
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], saveScroll(protyle, true));
|
||||
onGet(getResponse, protyle, protyle.block.showAll ? [Constants.CB_GET_ALL, Constants.CB_GET_FOCUS] : [Constants.CB_GET_FOCUS], saveScroll(protyle, true), true);
|
||||
});
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
|
|
10
app/src/types/index.d.ts
vendored
10
app/src/types/index.d.ts
vendored
|
@ -126,6 +126,16 @@ interface ISiyuan {
|
|||
dialogs: import("../dialog").Dialog[],
|
||||
}
|
||||
|
||||
interface IScrollAttr {
|
||||
startId: string,
|
||||
endId: string
|
||||
scrollTop: number,
|
||||
focusId?: string,
|
||||
focusStart?: number
|
||||
focusEnd?: number
|
||||
zoomInId?: string
|
||||
}
|
||||
|
||||
interface IOperation {
|
||||
action: TOperation, // move, delete 不需要传 data
|
||||
id: string,
|
||||
|
|
2
app/src/types/protyle.d.ts
vendored
2
app/src/types/protyle.d.ts
vendored
|
@ -346,7 +346,7 @@ interface IOptions {
|
|||
mode?: TEditorMode,
|
||||
blockId: string
|
||||
key?: string
|
||||
scrollAttr?: string
|
||||
scrollAttr?: IScrollAttr
|
||||
defId?: string
|
||||
render?: {
|
||||
background?: boolean
|
||||
|
|
Loading…
Add table
Reference in a new issue