siyuan/app/src/util/backForward.ts

285 lines
12 KiB
TypeScript
Raw Normal View History

import {hasClosestBlock, hasClosestByAttribute} from "../protyle/util/hasClosest";
import {getContenteditableElement} from "../protyle/wysiwyg/getBlock";
import {focusByOffset, focusByRange, getSelectionOffset} from "../protyle/util/selection";
import {hideElements} from "../protyle/ui/hideElements";
import {fetchPost, fetchSyncPost} from "./fetch";
import {Constants} from "../constants";
import {Wnd} from "../layout/Wnd";
import {getInstanceById, getWndByLayout} from "../layout/util";
import {Tab} from "../layout/Tab";
import {Editor} from "../editor";
import {onGet} from "../protyle/util/onGet";
import {scrollCenter} from "./highlightById";
import {lockFile} from "../dialog/processSystem";
import {zoomOut} from "../menus/protyle";
let forwardStack: IBackStack[] = [];
let previousIsBack = false;
const focusStack = async (stack: IBackStack) => {
hideElements(["gutter", "toolbar", "hint", "util", "dialog"], stack.protyle);
let blockElement: Element;
if (!stack.protyle.element.parentElement) {
const response = await fetchSyncPost("/api/block/checkBlockExist", {id: stack.protyle.block.rootID});
if (!response.data) {
// 页签删除
return false;
}
let wnd: Wnd;
// 获取光标所在 tab
const element = document.querySelector(".layout__wnd--active");
if (element) {
wnd = getInstanceById(element.getAttribute("data-id")) as Wnd;
}
if (!wnd) {
// 中心 tab
wnd = getWndByLayout(window.siyuan.layout.centerLayout);
}
if (wnd) {
const info = await fetchSyncPost("/api/block/getBlockInfo", {id: stack.id});
if (info.code === 2) {
// 文件被锁定
lockFile(info.data);
return false;
}
const tab = new Tab({
title: info.data.rootTitle,
docIcon: info.data.rootIcon,
callback(tab) {
const editor = new Editor({
tab,
blockId: stack.id, // 忘记为什么要用 rootChildID 了,但用了会产生 https://github.com/siyuan-note/siyuan/issues/6004 问题
});
tab.addModel(editor);
}
});
if (window.siyuan.config.fileTree.openFilesUseCurrentTab) {
let unUpdateTab: Tab;
// 不能 reverse, 找到也不能提前退出循环,否则 https://github.com/siyuan-note/siyuan/issues/3271
wnd.children.forEach((item) => {
if (item.headElement && item.headElement.classList.contains("item--unupdate") && !item.headElement.classList.contains("item--pin")) {
unUpdateTab = item;
}
});
wnd.addTab(tab);
if (unUpdateTab) {
wnd.removeTab(unUpdateTab.id);
}
} else {
wnd.addTab(tab);
}
wnd.showHeading();
// 页签关闭
setTimeout(() => {
const protyle = (tab.model as Editor).editor.protyle;
forwardStack.find(item => {
if (!item.protyle.element.parentElement && item.protyle.block.rootID === protyle.block.rootID) {
item.protyle = protyle;
}
});
window.siyuan.backStack.find(item => {
if (!item.protyle.element.parentElement && item.protyle.block.rootID === protyle.block.rootID) {
item.protyle = protyle;
}
});
if (protyle.block.rootID === stack.id) {
focusByOffset(protyle.title.editElement, stack.position.start, stack.position.end);
} else {
Array.from(protyle.wysiwyg.element.querySelectorAll(`[data-node-id="${stack.id}"]`)).find(item => {
if (!hasClosestByAttribute(item, "data-type", "NodeBlockQueryEmbed")) {
blockElement = item;
return true;
}
});
focusByOffset(getContenteditableElement(blockElement), stack.position.start, stack.position.end);
scrollCenter(protyle, blockElement);
}
}, 500);
return true;
} else {
return false;
}
}
if (stack.protyle.block.rootID === stack.id) {
if (stack.protyle.title.editElement.getBoundingClientRect().height === 0) {
// 切换 tab
stack.protyle.model.parent.parent.switchTab(stack.protyle.model.parent.headElement);
}
focusByOffset(stack.protyle.title.editElement, stack.position.start, stack.position.end);
return true;
}
Array.from(stack.protyle.wysiwyg.element.querySelectorAll(`[data-node-id="${stack.id}"]`)).find(item => {
if (!hasClosestByAttribute(item, "data-type", "NodeBlockQueryEmbed")) {
blockElement = item;
return true;
}
});
if (blockElement) {
if (blockElement.getBoundingClientRect().height === 0) {
// 切换 tab
stack.protyle.model.parent.parent.switchTab(stack.protyle.model.parent.headElement);
}
if (stack.isZoom) {
zoomOut(stack.protyle, stack.id, undefined, false);
return true;
}
if (blockElement && !stack.protyle.block.showAll) {
focusByOffset(getContenteditableElement(blockElement), stack.position.start, stack.position.end);
scrollCenter(stack.protyle, blockElement, true);
return true;
}
// 缩放不一致
fetchPost("/api/filetree/getDoc", {
id: stack.id,
mode: stack.isZoom ? 0 : 3,
size: stack.isZoom ? Constants.SIZE_GET_MAX : Constants.SIZE_GET,
}, getResponse => {
onGet(getResponse, stack.protyle, [Constants.CB_GET_HTML]);
Array.from(stack.protyle.wysiwyg.element.querySelectorAll(`[data-node-id="${stack.id}"]`)).find(item => {
if (!hasClosestByAttribute(item, "data-type", "NodeBlockQueryEmbed")) {
blockElement = item;
return true;
}
});
focusByOffset(getContenteditableElement(blockElement), stack.position.start, stack.position.end);
setTimeout(() => {
// 图片、视频等加载完成后再定位
scrollCenter(stack.protyle, blockElement, true);
}, Constants.TIMEOUT_BLOCKLOAD);
});
return true;
}
if (stack.protyle.element.parentElement) {
const response = await fetchSyncPost("/api/block/checkBlockExist", {id: stack.id});
if (!response.data) {
// 块被删除
if (getSelection().rangeCount > 0) {
focusByRange(getSelection().getRangeAt(0));
}
return false;
}
fetchPost("/api/filetree/getDoc", {
id: stack.id, // 忘记为什么要用 rootChildID 了,但用了会产生 https://github.com/siyuan-note/siyuan/issues/6004 问题
mode: stack.isZoom ? 0 : 3,
size: stack.isZoom ? Constants.SIZE_GET_MAX : Constants.SIZE_GET,
}, getResponse => {
onGet(getResponse, stack.protyle, stack.isZoom ? [Constants.CB_GET_HTML, Constants.CB_GET_ALL] : [Constants.CB_GET_HTML]);
Array.from(stack.protyle.wysiwyg.element.querySelectorAll(`[data-node-id="${stack.id}"]`)).find(item => {
if (!hasClosestByAttribute(item, "data-type", "NodeBlockQueryEmbed")) {
blockElement = item;
return true;
}
});
focusByOffset(getContenteditableElement(blockElement), stack.position.start, stack.position.end);
setTimeout(() => {
scrollCenter(stack.protyle, blockElement);
}, Constants.TIMEOUT_INPUT);
});
return true;
}
};
export const goBack = async () => {
if (window.siyuan.backStack.length === 0) {
if (forwardStack.length > 0) {
await focusStack(forwardStack[forwardStack.length - 1]);
}
return;
}
document.querySelector("#barForward").classList.remove("toolbar__item--disabled");
if (!previousIsBack) {
forwardStack.push(window.siyuan.backStack.pop());
}
let stack = window.siyuan.backStack.pop();
while (stack) {
const isFocus = await focusStack(stack);
if (isFocus) {
forwardStack.push(stack);
break;
} else {
stack = window.siyuan.backStack.pop();
}
}
previousIsBack = true;
if (window.siyuan.backStack.length === 0) {
document.querySelector("#barBack").classList.add("toolbar__item--disabled");
}
};
export const goForward = async () => {
if (forwardStack.length === 0) {
if (window.siyuan.backStack.length > 0) {
await focusStack(window.siyuan.backStack[window.siyuan.backStack.length - 1]);
}
return;
}
document.querySelector("#barBack").classList.remove("toolbar__item--disabled");
if (previousIsBack) {
window.siyuan.backStack.push(forwardStack.pop());
}
let stack = forwardStack.pop();
while (stack) {
const isFocus = await focusStack(stack);
if (isFocus) {
window.siyuan.backStack.push(stack);
break;
} else {
stack = forwardStack.pop();
}
}
previousIsBack = false;
if (forwardStack.length === 0) {
document.querySelector("#barForward").classList.add("toolbar__item--disabled");
}
};
export const pushBack = (protyle: IProtyle, range?: Range, blockElement?: Element) => {
if (!protyle.model) {
return;
}
2022-08-10 11:28:57 +08:00
if (!blockElement && range) {
blockElement = hasClosestBlock(range.startContainer) as Element;
}
if (!blockElement) {
return;
}
let editElement;
if (blockElement.classList.contains("protyle-title__input")) {
editElement = blockElement;
} else {
editElement = getContenteditableElement(blockElement);
}
if (editElement) {
const position = getSelectionOffset(editElement, undefined, range);
const id = blockElement.getAttribute("data-node-id") || protyle.block.rootID;
const lastStack = window.siyuan.backStack[window.siyuan.backStack.length - 1];
const isZoom = protyle.block.showAll;
if (lastStack && lastStack.id === id && lastStack.isZoom === isZoom) {
lastStack.position = position;
} else {
if (forwardStack.length > 0) {
if (previousIsBack) {
window.siyuan.backStack.push(forwardStack.pop());
}
forwardStack = [];
document.querySelector("#barForward").classList.add("toolbar__item--disabled");
}
window.siyuan.backStack.push({
position,
id,
protyle,
isZoom
});
if (window.siyuan.backStack.length > Constants.SIZE_UNDO) {
window.siyuan.backStack.shift();
}
previousIsBack = false;
}
if (window.siyuan.backStack.length > 1) {
document.querySelector("#barBack").classList.remove("toolbar__item--disabled");
}
}
};