import {Layout} from "./index"; import {Wnd} from "./Wnd"; import {Tab} from "./Tab"; import {Model} from "./Model"; import {Graph} from "./dock/Graph"; import {Editor} from "../editor"; import {Files} from "./dock/Files"; import {Outline} from "./dock/Outline"; import {Bookmark} from "./dock/Bookmark"; import {Tag} from "./dock/Tag"; import {getAllModels, getAllTabs} from "./getAll"; import {Asset} from "../asset"; import {Search} from "../search"; import {Dock} from "./dock"; import {focusByOffset, focusByRange, getSelectionOffset} from "../protyle/util/selection"; import {hideElements} from "../protyle/ui/hideElements"; import {fetchPost} from "../util/fetch"; import {hasClosestBlock, hasClosestByClassName} from "../protyle/util/hasClosest"; import {getContenteditableElement} from "../protyle/wysiwyg/getBlock"; import {Constants} from "../constants"; import {saveScroll} from "../protyle/scroll/saveScroll"; import {Backlink} from "./dock/Backlink"; import {openFileById} from "../editor/util"; import {isWindow} from "../util/functions"; /// #if !BROWSER import {setTabPosition} from "../window/setHeader"; /// #endif import {showMessage} from "../dialog/message"; import {getIdZoomInByPath} from "../util/pathName"; import {Custom} from "./dock/Custom"; import {newCardModel} from "../card/newCardTab"; import {App} from "../index"; import {afterLoadPlugin} from "../plugin/loader"; import {setTitle} from "../dialog/processSystem"; import {newCenterEmptyTab, resizeTabs} from "./tabUtil"; import {setStorageVal} from "../protyle/util/compatibility"; export const setPanelFocus = (element: Element) => { if (element.getAttribute("data-type") === "wnd") { setTitle(element.querySelector('.layout-tab-bar .item--focus[data-type="tab-header"] .item__text')?.textContent || window.siyuan.languages.siyuanNote); } if (element.classList.contains("layout__tab--active") || element.classList.contains("layout__wnd--active")) { return; } document.querySelectorAll(".layout__tab--active").forEach(item => { item.classList.remove("layout__tab--active"); }); document.querySelectorAll(".dock__item--activefocus").forEach(item => { item.classList.remove("dock__item--activefocus"); }); document.querySelectorAll(".layout__wnd--active").forEach(item => { item.classList.remove("layout__wnd--active"); }); if (element.getAttribute("data-type") === "wnd") { element.classList.add("layout__wnd--active"); } else { element.classList.add("layout__tab--active"); Array.from(element.classList).find(item => { if (item.startsWith("sy__")) { document.querySelector(`.dock__item[data-type="${item.substring(4)}"]`).classList.add("dock__item--activefocus"); return true; } }); const blockElement = hasClosestBlock(document.activeElement); if (blockElement) { const editElement = getContenteditableElement(blockElement) as HTMLElement; if (editElement) { editElement.blur(); } } } }; export const switchWnd = (newWnd: Wnd, targetWnd: Wnd) => { // DOM 移动后 range 会变化 const rangeDatas: { id: string, start: number, end: number }[] = []; targetWnd.children.forEach((item) => { if (item.model instanceof Editor && item.model.editor.protyle.toolbar.range) { const blockElement = hasClosestBlock(item.model.editor.protyle.toolbar.range.startContainer); if (blockElement) { const startEnd = getSelectionOffset(blockElement, undefined, item.model.editor.protyle.toolbar.range); rangeDatas.push({ id: blockElement.getAttribute("data-node-id"), start: startEnd.start, end: startEnd.end }); } } }); newWnd.element.after(targetWnd.element); targetWnd.children.forEach((item) => { if (item.model instanceof Editor) { const rangeData = rangeDatas.splice(0, 1)[0]; if (!rangeData) { return; } const range = focusByOffset(item.model.editor.protyle.wysiwyg.element.querySelector(`[data-node-id="${rangeData.id}"]`), rangeData.start, rangeData.end); if (range) { item.model.editor.protyle.toolbar.range = range; } } }); // 分隔线 newWnd.element.after(newWnd.element.previousElementSibling); newWnd.parent.children.find((item, index) => { if (item.id === newWnd.id) { const tempResize = newWnd.parent.children[index].resize; newWnd.parent.children[index].resize = newWnd.parent.children[index - 1].resize; newWnd.parent.children[index - 1].resize = tempResize; const temp = item; newWnd.parent.children[index] = newWnd.parent.children[index - 1]; newWnd.parent.children[index - 1] = temp; return true; } }); /// #if !BROWSER setTabPosition(); /// #endif }; export const getWndByLayout: (layout: Layout) => Wnd = (layout: Layout) => { for (let i = 0; i < layout.children.length; i++) { const item = layout.children[i]; if (item instanceof Wnd) { return item; } else { return getWndByLayout(item); } } }; const dockToJSON = (dock: Dock) => { const json = []; const subDockToJSON = (index: number) => { const data: IDockTab[] = []; dock.element.querySelectorAll(`span[data-index="${index}"]`).forEach(item => { data.push({ type: item.getAttribute("data-type"), size: { height: parseInt(item.getAttribute("data-height")), width: parseInt(item.getAttribute("data-width")), }, title: item.getAttribute("data-title"), show: item.classList.contains("dock__item--active"), icon: item.querySelector("use").getAttribute("xlink:href").substring(1), hotkey: item.getAttribute("data-hotkey") || "", hotkeyLangId: item.getAttribute("data-hotkeyLangId") || "" }); }); return data; }; const data0 = subDockToJSON(0); const data2 = subDockToJSON(1); if (data0.length > 0 || data2.length > 0) { // https://github.com/siyuan-note/siyuan/issues/5641 json.push(data0); } if (data2.length > 0) { json.push(data2); } return { pin: dock.pin, data: json }; }; export const resetLayout = () => { fetchPost("/api/system/setUILayout", {layout: {}}, () => { window.siyuan.storage[Constants.LOCAL_FILEPOSITION] = {}; setStorageVal(Constants.LOCAL_FILEPOSITION, window.siyuan.storage[Constants.LOCAL_FILEPOSITION]); window.siyuan.storage[Constants.LOCAL_DIALOGPOSITION] = {}; setStorageVal(Constants.LOCAL_DIALOGPOSITION, window.siyuan.storage[Constants.LOCAL_DIALOGPOSITION]); window.location.reload(); }); }; let saveCount = 0; export const saveLayout = () => { const breakObj = {}; let layoutJSON: any = {}; if (isWindow()) { layoutJSON = { layout: {}, }; layoutToJSON(window.siyuan.layout.layout, layoutJSON.layout, breakObj); } else { const useElement = document.querySelector("#barDock use"); if (useElement) { layoutJSON = { hideDock: useElement.getAttribute("xlink:href") === "#iconDock", layout: {}, bottom: dockToJSON(window.siyuan.layout.bottomDock), left: dockToJSON(window.siyuan.layout.leftDock), right: dockToJSON(window.siyuan.layout.rightDock), }; layoutToJSON(window.siyuan.layout.layout, layoutJSON.layout, breakObj); } } if (Object.keys(breakObj).length > 0 && saveCount < 10) { saveCount++; setTimeout(() => { saveLayout(); }, Constants.TIMEOUT_LOAD * saveCount); } else { saveCount = 0; if (isWindow()) { sessionStorage.setItem("layout", JSON.stringify(layoutJSON)); } else { fetchPost("/api/system/setUILayout", { layout: layoutJSON, errorExit: false // 后台不接受该参数,用于请求发生错误时退出程序 }); } } }; export const exportLayout = (options: { cb: () => void, errorExit: boolean }) => { if (isWindow()) { const layoutJSON: any = { layout: {}, }; layoutToJSON(window.siyuan.layout.layout, layoutJSON.layout); getAllModels().editor.forEach(item => { saveScroll(item.editor.protyle); }); sessionStorage.setItem("layout", JSON.stringify(layoutJSON)); options.cb(); return; } const useElement = document.querySelector("#barDock use"); if (!useElement) { return; } const layoutJSON: any = { hideDock: useElement.getAttribute("xlink:href") === "#iconDock", layout: {}, bottom: dockToJSON(window.siyuan.layout.bottomDock), left: dockToJSON(window.siyuan.layout.leftDock), right: dockToJSON(window.siyuan.layout.rightDock), }; layoutToJSON(window.siyuan.layout.layout, layoutJSON.layout); getAllModels().editor.forEach(item => { saveScroll(item.editor.protyle); }); fetchPost("/api/system/setUILayout", { layout: layoutJSON, errorExit: options.errorExit // 后台不接受该参数,用于请求发生错误时退出程序 }, () => { options.cb(); }); }; export const getAllLayout = () => { const layoutJSON: any = { hideDock: document.querySelector("#barDock use").getAttribute("xlink:href") === "#iconDock", layout: {}, bottom: dockToJSON(window.siyuan.layout.bottomDock), left: dockToJSON(window.siyuan.layout.leftDock), right: dockToJSON(window.siyuan.layout.rightDock), }; layoutToJSON(window.siyuan.layout.layout, layoutJSON.layout); return layoutJSON; }; const initInternalDock = (dockItem: IDockTab[]) => { dockItem.forEach((existSubItem) => { if (existSubItem.hotkeyLangId) { existSubItem.title = window.siyuan.languages[existSubItem.hotkeyLangId]; existSubItem.hotkey = window.siyuan.config.keymap.general[existSubItem.hotkeyLangId].custom; } }); }; const JSONToDock = (json: any, app: App) => { json.left.data.forEach((existItem: IDockTab[]) => { initInternalDock(existItem); }); json.right.data.forEach((existItem: IDockTab[]) => { initInternalDock(existItem); }); json.bottom.data.forEach((existItem: IDockTab[]) => { initInternalDock(existItem); }); window.siyuan.layout.centerLayout = window.siyuan.layout.layout.children[0].children[1] as Layout; window.siyuan.layout.leftDock = new Dock({position: "Left", data: json.left, app}); window.siyuan.layout.rightDock = new Dock({position: "Right", data: json.right, app}); window.siyuan.layout.bottomDock = new Dock({position: "Bottom", data: json.bottom, app}); }; export const JSONToCenter = (app: App, json: ILayoutJSON, layout?: Layout | Wnd | Tab | Model) => { let child: Layout | Wnd | Tab | Model; if (json.instance === "Layout") { if (!layout) { window.siyuan.layout.layout = new Layout({ element: document.getElementById("layouts"), direction: json.direction, size: json.size, type: json.type, resize: json.resize }); } else { child = new Layout({ direction: json.direction, size: json.size, type: json.type, resize: json.resize }); (layout as Layout).addLayout(child); } } else if (json.instance === "Wnd") { child = new Wnd(app, json.resize, (layout as Layout).type); (layout as Layout).addWnd(child); if (json.width) { child.element.classList.remove("fn__flex-1"); child.element.style.width = json.width; } if (json.height) { child.element.classList.remove("fn__flex-1"); child.element.style.height = json.height; } } else if (json.instance === "Tab") { if (!json.title) { child = newCenterEmptyTab(app); } else { let title = json.title; if (json.lang) { title = window.siyuan.languages[json.lang]; } child = new Tab({ icon: json.icon, docIcon: json.docIcon, title }); } if (json.pin) { child.headElement.classList.add("item--pin"); if (json.docIcon || json.icon) { child.headElement.querySelector(".item__text").classList.add("fn__none"); } } if (json.active && child.headElement) { child.headElement.setAttribute("data-init-active", "true"); } (layout as Wnd).addTab(child, false, false); (layout as Wnd).showHeading(); } else if (json.instance === "Editor" && json.blockId) { if (window.siyuan.config.fileTree.openFilesUseCurrentTab) { (layout as Tab).headElement.classList.add("item--unupdate"); } (layout as Tab).headElement.setAttribute("data-initdata", JSON.stringify(json)); } else if (json.instance === "Asset") { (layout as Tab).addModel(new Asset({ app, tab: (layout as Tab), path: json.path, page: json.page, })); } else if (json.instance === "Backlink") { (layout as Tab).addModel(new Backlink({ app, tab: (layout as Tab), blockId: json.blockId, rootId: json.rootId, type: json.type as "pin" | "local", })); } else if (json.instance === "Bookmark") { (layout as Tab).addModel(new Bookmark(app, (layout as Tab))); } else if (json.instance === "Files") { (layout as Tab).addModel(new Files({ app, tab: (layout as Tab), })); } else if (json.instance === "Graph") { (layout as Tab).addModel(new Graph({ app, tab: (layout as Tab), blockId: json.blockId, rootId: json.rootId, type: json.type as "pin" | "local" | "global", })); } else if (json.instance === "Outline") { (layout as Tab).addModel(new Outline({ app, tab: (layout as Tab), blockId: json.blockId, type: json.type as "pin" | "local", isPreview: json.isPreview, })); } else if (json.instance === "Tag") { (layout as Tab).addModel(new Tag(app, (layout as Tab))); } else if (json.instance === "Search") { (layout as Tab).addModel(new Search({ app, tab: (layout as Tab), config: json.config })); } else if (json.instance === "Custom") { if (window.siyuan.config.fileTree.openFilesUseCurrentTab) { (layout as Tab).headElement.classList.add("item--unupdate"); } (layout as Tab).headElement.setAttribute("data-initdata", JSON.stringify(json)); } if (json.children) { if (Array.isArray(json.children)) { json.children.forEach((item: any) => { JSONToCenter(app, item, layout ? child : window.siyuan.layout.layout); }); } else { JSONToCenter(app, json.children, child); } } }; export const JSONToLayout = (app: App, isStart: boolean) => { JSONToCenter(app, window.siyuan.config.uiLayout.layout, undefined); JSONToDock(window.siyuan.config.uiLayout, app); // 启动时不打开页签,需要移除没有钉住的页签 if (window.siyuan.config.fileTree.closeTabsOnStart) { /// #if BROWSER if (!sessionStorage.getItem(Constants.LOCAL_SESSION_FIRSTLOAD)) { getAllTabs().forEach(item => { if (item.headElement && !item.headElement.classList.contains("item--pin")) { item.parent.removeTab(item.id, false, false); } }); sessionStorage.setItem(Constants.LOCAL_SESSION_FIRSTLOAD, "true"); } /// #else if (isStart) { getAllTabs().forEach(item => { if (item.headElement && !item.headElement.classList.contains("item--pin")) { item.parent.removeTab(item.id, false, false); } }); } /// #endif } app.plugins.forEach(item => { afterLoadPlugin(item); }); // 移除没有插件的 tab document.querySelectorAll('li[data-type="tab-header"]').forEach((item: HTMLElement) => { const initData = item.getAttribute("data-initdata"); if (initData) { const initDataObj = JSON.parse(initData); if (initDataObj.instance === "Custom" && initDataObj.customModelType !== "siyuan-card") { let hasPlugin = false; app.plugins.find(plugin => { if (Object.keys(plugin.models).includes(initDataObj.customModelType)) { hasPlugin = true; return true; } }); if (!hasPlugin) { const tabId = item.getAttribute("data-id"); const tab = getInstanceById(tabId) as Tab; if (tab) { tab.parent.removeTab(tabId, false, false); } } } } }); const idZoomIn = getIdZoomInByPath(); if (idZoomIn.id) { openFileById({ app, id: idZoomIn.id, action: idZoomIn.isZoomIn ? [Constants.CB_GET_ALL, Constants.CB_GET_FOCUS] : [Constants.CB_GET_FOCUS, Constants.CB_GET_CONTEXT, Constants.CB_GET_ROOTSCROLL], zoomIn: idZoomIn.isZoomIn }); } else { document.querySelectorAll('li[data-type="tab-header"][data-init-active="true"]').forEach((item: HTMLElement) => { item.removeAttribute("data-init-active"); const tab = getInstanceById(item.getAttribute("data-id")) as Tab; tab.parent.switchTab(item, false, false, true, false); }); } resizeTopBar(); }; export const layoutToJSON = (layout: Layout | Wnd | Tab | Model, json: any, breakObj?: IObject) => { if (layout instanceof Layout) { json.direction = layout.direction; if (layout.parent) { if (layout.element.classList.contains("fn__flex-1")) { json.size = "auto"; } else { json.size = (layout.parent.direction === "tb" ? layout.element.clientHeight : layout.element.clientWidth) + "px"; } } json.resize = layout.resize; json.type = layout.type; json.instance = "Layout"; } else if (layout instanceof Wnd) { json.resize = layout.resize; json.height = layout.element.style.height; json.width = layout.element.style.width; json.instance = "Wnd"; } else if (layout instanceof Tab) { if (layout.headElement) { json.title = layout.title; json.icon = layout.icon; json.docIcon = layout.docIcon; json.pin = layout.headElement.classList.contains("item--pin"); if (layout.model instanceof Files) { json.lang = "fileTree"; } else if (layout.model instanceof Backlink && layout.model.type === "pin") { json.lang = "backlinks"; } else if (layout.model instanceof Bookmark) { json.lang = "bookmark"; } else if (layout.model instanceof Graph && layout.model.type !== "local") { json.lang = "graphView"; } else if (layout.model instanceof Outline && layout.model.type !== "local") { json.lang = "outline"; } else if (layout.model instanceof Tag) { json.lang = "tag"; } if (layout.headElement.classList.contains("item--focus")) { json.active = true; } } json.instance = "Tab"; } else if (layout instanceof Editor) { if (!layout.editor.protyle.notebookId && breakObj) { breakObj.editor = "true"; } json.notebookId = layout.editor.protyle.notebookId; json.blockId = layout.editor.protyle.block.id; json.rootId = layout.editor.protyle.block.rootID; json.mode = layout.editor.protyle.preview.element.classList.contains("fn__none") ? "wysiwyg" : "preview"; json.action = layout.editor.protyle.block.showAll ? Constants.CB_GET_ALL : Constants.CB_GET_SCROLL; json.instance = "Editor"; } else if (layout instanceof Asset) { json.path = layout.path; if (layout.pdfObject) { json.page = layout.pdfObject.page; } json.instance = "Asset"; } else if (layout instanceof Backlink) { json.blockId = layout.blockId; json.rootId = layout.rootId; json.type = layout.type; json.instance = "Backlink"; } else if (layout instanceof Bookmark) { json.instance = "Bookmark"; } else if (layout instanceof Files) { json.instance = "Files"; } else if (layout instanceof Graph) { json.blockId = layout.blockId; json.rootId = layout.rootId; json.type = layout.type; json.instance = "Graph"; } else if (layout instanceof Outline) { json.blockId = layout.blockId; json.type = layout.type; json.isPreview = layout.isPreview; json.instance = "Outline"; } else if (layout instanceof Tag) { json.instance = "Tag"; } else if (layout instanceof Search) { json.instance = "Search"; json.config = layout.config; } else if (layout instanceof Custom) { json.instance = "Custom"; json.customModelType = layout.type; json.customModelData = Object.assign({}, layout.data); // https://github.com/siyuan-note/siyuan/issues/9250 delete json.customModelData.editor; } if (layout instanceof Layout || layout instanceof Wnd) { if (layout instanceof Layout && (layout.type === "bottom" || layout.type === "left" || layout.type === "right")) { // 四周布局使用默认值,清空内容,重置时使用 dock 数据 if (layout.type === "bottom") { json.children = [{ "instance": "Wnd", "children": [] }, { "instance": "Wnd", "resize": "lr", "children": [] }]; } else { json.children = [{ "instance": "Wnd", "children": [] }, { "instance": "Wnd", "resize": "tb", "children": [] }]; } } else { json.children = []; layout.children.forEach((item: Layout | Wnd | Tab) => { const itemJSON = {}; json.children.push(itemJSON); layoutToJSON(item, itemJSON, breakObj); }); } } else if (layout instanceof Tab) { if (layout.model) { json.children = {}; layoutToJSON(layout.model, json.children, breakObj); } else if (layout.headElement) { // 当前页签没有激活时编辑器没有初始化 json.children = JSON.parse(layout.headElement.getAttribute("data-initdata") || "{}"); } else { // 关闭所有页签 json.children = {}; } } }; export const resizeTopBar = () => { const toolbarElement = document.querySelector("#toolbar"); if (!toolbarElement) { return; } const dragElement = toolbarElement.querySelector("#drag") as HTMLElement; dragElement.style.padding = ""; const barMoreElement = toolbarElement.querySelector("#barMore"); barMoreElement.classList.remove("fn__none"); barMoreElement.removeAttribute("data-hideids"); Array.from(toolbarElement.querySelectorAll('[data-hide="true"]')).forEach((item) => { item.classList.remove("fn__none"); item.removeAttribute("data-hide"); }); let afterDragElement = dragElement.nextElementSibling; const hideIds: string[] = []; while (toolbarElement.scrollWidth > toolbarElement.clientWidth + 2) { hideIds.push(afterDragElement.id); afterDragElement.classList.add("fn__none"); afterDragElement.setAttribute("data-hide", "true"); afterDragElement = afterDragElement.nextElementSibling; if (afterDragElement.id === "barMore") { break; } } let beforeDragElement = dragElement.previousElementSibling; while (toolbarElement.scrollWidth > toolbarElement.clientWidth + 2) { hideIds.push(beforeDragElement.id); beforeDragElement.classList.add("fn__none"); beforeDragElement.setAttribute("data-hide", "true"); beforeDragElement = beforeDragElement.previousElementSibling; if (beforeDragElement.id === "barWorkspace") { break; } } if (hideIds.length > 0) { barMoreElement.classList.remove("fn__none"); } else { barMoreElement.classList.add("fn__none"); } barMoreElement.setAttribute("data-hideids", hideIds.join(",")); const width = dragElement.clientWidth; const dragRect = dragElement.getBoundingClientRect(); const left = dragRect.left; const right = window.innerWidth - dragRect.right; if (left > right && left - right < width / 3) { dragElement.style.paddingRight = (left - right) + "px"; } else if (left < right && right - left < width / 3) { dragElement.style.paddingLeft = (right - left) + "px"; } window.siyuan.storage[Constants.LOCAL_PLUGINTOPUNPIN].forEach((id: string) => { toolbarElement.querySelector("#" + id)?.classList.add("fn__none"); }); }; export const newModelByInitData = (app: App, tab: Tab, json: any) => { let model: Model; if (json.instance === "Custom") { if (json.customModelType === "siyuan-card") { model = newCardModel({ app, tab: tab, data: json.customModelData }); } else { app.plugins.find(item => { if (item.models[json.customModelType]) { model = item.models[json.customModelType]({ tab: tab, data: json.customModelData }); return true; } }); } } else if (json.instance === "Editor") { model = new Editor({ app, tab, rootId: json.rootId, blockId: json.blockId, mode: json.mode, action: typeof json.action === "string" ? [json.action] : json.action, }); } return model; }; export const pdfIsLoading = (element: HTMLElement) => { const isLoading = element.querySelector('.layout-tab-container > [data-loading="true"]') ? true : false; if (isLoading) { showMessage(window.siyuan.languages.pdfIsLoading); } return isLoading; }; export const getInstanceById = (id: string, layout = window.siyuan.layout.centerLayout) => { const _getInstanceById = (item: Layout | Wnd, id: string) => { if (item.id === id) { return item; } if (!item.children) { return; } let ret: Tab | Layout | Wnd; for (let i = 0; i < item.children.length; i++) { ret = _getInstanceById(item.children[i] as Layout, id) as Tab; if (ret) { return ret; } } }; return _getInstanceById(layout, id); }; export const addResize = (obj: Layout | Wnd) => { if (!obj.resize) { return; } const getMinSize = (element: HTMLElement) => { let minSize = 227; Array.from(element.querySelectorAll(".file-tree")).find((item) => { if (item.classList.contains("sy__backlink") || item.classList.contains("sy__graph") || item.classList.contains("sy__globalGraph") || item.classList.contains("sy__inbox")) { if (!item.classList.contains("fn__none") && !hasClosestByClassName(item, "fn__none")) { minSize = 320; return true; } } }); return minSize; }; const resizeWnd = (resizeElement: HTMLElement, direction: string) => { const setSize = (item: HTMLElement, direction: string) => { if (item.classList.contains("fn__flex-1")) { if (direction === "lr") { item.style.width = item.clientWidth + "px"; } else { item.style.height = item.clientHeight + "px"; } item.classList.remove("fn__flex-1"); } }; let range: Range; resizeElement.addEventListener("mousedown", (event: MouseEvent) => { getAllModels().editor.forEach((item) => { if (item.editor && item.editor.protyle && item.element.parentElement) { hideElements(["gutter"], item.editor.protyle); } }); if (getSelection().rangeCount > 0) { range = getSelection().getRangeAt(0); } const documentSelf = document; const nextElement = resizeElement.nextElementSibling as HTMLElement; const previousElement = resizeElement.previousElementSibling as HTMLElement; nextElement.style.overflow = "auto"; // 拖动时 layout__resize 会出现 https://github.com/siyuan-note/siyuan/issues/6221 previousElement.style.overflow = "auto"; if (!nextElement.nextElementSibling || nextElement.nextElementSibling.classList.contains("layout__dockresize")) { setSize(nextElement, direction); } else { setSize(previousElement, direction); } const x = event[direction === "lr" ? "clientX" : "clientY"]; const previousSize = direction === "lr" ? previousElement.clientWidth : previousElement.clientHeight; const nextSize = direction === "lr" ? nextElement.clientWidth : nextElement.clientHeight; documentSelf.ondragstart = () => { // 文件树拖拽会产生透明效果 document.querySelectorAll(".sy__file .b3-list-item").forEach((item: HTMLElement) => { if (item.style.opacity === "0.1") { item.style.opacity = ""; } }); return false; }; documentSelf.onmousemove = (moveEvent: MouseEvent) => { moveEvent.preventDefault(); moveEvent.stopPropagation(); const previousNowSize = (previousSize + (moveEvent[direction === "lr" ? "clientX" : "clientY"] - x)); const nextNowSize = (nextSize - (moveEvent[direction === "lr" ? "clientX" : "clientY"] - x)); if (previousNowSize < 8 || nextNowSize < 8) { return; } if (window.siyuan.layout.leftDock?.layout.element.isSameNode(previousElement) && previousNowSize < getMinSize(previousElement)) { return; } if (window.siyuan.layout.rightDock?.layout.element.isSameNode(nextElement) && nextNowSize < getMinSize(nextElement)) { return; } if (window.siyuan.layout.bottomDock?.layout.element.isSameNode(nextElement) && nextNowSize < 64) { return; } if (!previousElement.classList.contains("fn__flex-1")) { previousElement.style[direction === "lr" ? "width" : "height"] = previousNowSize + "px"; } if (!nextElement.classList.contains("fn__flex-1")) { nextElement.style[direction === "lr" ? "width" : "height"] = nextNowSize + "px"; } }; documentSelf.onmouseup = () => { documentSelf.onmousemove = null; documentSelf.onmouseup = null; documentSelf.ondragstart = null; documentSelf.onselectstart = null; documentSelf.onselect = null; adjustLayout(isWindow() ? window.siyuan.layout.centerLayout : undefined); resizeTabs(); if (!isWindow()) { window.siyuan.layout.leftDock.setSize(); window.siyuan.layout.bottomDock.setSize(); window.siyuan.layout.rightDock.setSize(); } if (range) { focusByRange(range); } nextElement.style.overflow = ""; previousElement.style.overflow = ""; }; }); }; const resizeElement = document.createElement("div"); if (obj.resize === "lr") { resizeElement.classList.add("layout__resize--lr"); } resizeElement.classList.add("layout__resize"); obj.element.insertAdjacentElement("beforebegin", resizeElement); resizeWnd(resizeElement, obj.resize); }; export const adjustLayout = (layout: Layout = window.siyuan.layout.centerLayout.parent) => { layout.children.forEach((item: Layout | Wnd) => { item.element.style.maxWidth = ""; if (!item.element.style.width && !item.element.classList.contains("layout__center")) { item.element.style.minWidth = "8px"; } else { item.element.style.minWidth = ""; } }); let lastItem: HTMLElement; let index = Math.floor(window.innerWidth / 24); // +2 由于某些分辨率下 scrollWidth 会大于 clientWidth while (layout.element.scrollWidth > layout.element.clientWidth + 2 && index > 0) { layout.children.find((item: Layout | Wnd) => { if (item.element.style.width && item.element.style.width !== "0px") { item.element.style.maxWidth = Math.max(Math.min(item.element.clientWidth, window.innerWidth) - 8, 64) + "px"; lastItem = item.element; } if (layout.element.scrollWidth <= layout.element.clientWidth + 2) { return true; } }); index--; } if (lastItem) { lastItem.style.maxWidth = Math.max(Math.min(lastItem.clientWidth, window.innerWidth) - 8, 64) + "px"; } layout.children.forEach((item: Layout | Wnd) => { if (item instanceof Layout && item.size !== "0px") { adjustLayout(item); } }); };