Something went wrong. Try again.
A privacy-first, self-hosted, fully open source personal knowledge management software, written in typescript and golang. (PERSONAL FORK)
Something went wrong. Try again.
TypeScript
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046import {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, getAllWnds} 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 {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 !BROWSERimport {setTabPosition} from "../window/setHeader";/// #endifimport {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, isSaveLayout = true) => { 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"); element.querySelector(".layout-tab-bar .item--focus")?.setAttribute("data-activetime", (new Date()).getTime().toString()); if (isSaveLayout) { saveLayout(); } } 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; } }); }};
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) => { const wndsTemp: Wnd[] = []; getAllWnds(layout, wndsTemp); return wndsTemp.sort((a, b) => { if (a.element.querySelector(".fn__flex .item--focus")?.getAttribute("data-activetime") > b.element.querySelector(".fn__flex .item--focus")?.getAttribute("data-activetime")) { return -1; } })[0];};
const dockToJSON = (dock: Dock) => { const json = []; const subDockToJSON = (index: number) => { const data: Config.IUILayoutDockTab[] = []; 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 = () => { if (window.siyuan.config.readonly) { window.location.reload(); } else { 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); window.siyuan.config.uiLayout = layoutJSON; } } 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 { if (!window.siyuan.config.readonly) { fetchPost("/api/system/setUILayout", { layout: layoutJSON, errorExit: false // 后台不接受该参数,用于请求发生错误时退出程序 }); } } }};
export const exportLayout = async (options: { cb: () => void, errorExit: boolean}) => { const editors = getAllModels().editor; for (let i = 0; i < editors.length; i++) { await saveScroll(editors[i].editor.protyle); } if (isWindow()) { const layoutJSON: any = { layout: {}, }; layoutToJSON(window.siyuan.layout.layout, layoutJSON.layout); 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); if (window.siyuan.config.readonly) { options.cb(); } else { 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: Config.IUILayoutDockTab[]) => { dockItem.forEach((existSubItem, index) => { if (window.siyuan.isPublish && existSubItem.type === "inbox") { dockItem.splice(index, 1); return; } 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: Config.IUILayoutDockTab[]) => { initInternalDock(existItem); }); json.right.data.forEach((existItem: Config.IUILayoutDockTab[]) => { initInternalDock(existItem); }); json.bottom.data.forEach((existItem: Config.IUILayoutDockTab[]) => { 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});};
const removedTabs: Tab[] = [];
export const JSONToCenter = ( app: App, json: Config.TUILayoutItem, layout?: Layout | Wnd | Tab | Model,) => { let child: Layout | Wnd | Tab | Model; if (json.instance === "Layout") { // TabA 向右分屏后向下分屏,依次关闭右侧、上侧分屏无法移除 layout 嵌套,故在此解决 https://github.com/siyuan-note/siyuan/issues/12196 while (json.children.length === 1 && json.children[0].instance === "Layout" && json.children[0].type === "normal" && json.children[0].children.length === 1) { json.children = json.children[0].children; } 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, json.activeTime); } 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 ("children" in json) { if (Array.isArray(json.children)) { json.children.forEach((item: any) => { JSONToCenter(app, item, layout ? child : window.siyuan.layout.layout); }); } else if (json.children && Object.keys(json.children).length > 0) { JSONToCenter(app, json.children, child); } else if (child instanceof Tab) { removedTabs.push(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, 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, false); } }); } /// #endif } // 移除没有插件的 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, 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 { let latestTabHeaderElement: HTMLElement; document.querySelectorAll('li[data-type="tab-header"][data-init-active="true"]').forEach((item: HTMLElement) => { if (!latestTabHeaderElement) { latestTabHeaderElement = item; } else { if (item.dataset.activetime > latestTabHeaderElement.dataset.activetime) { latestTabHeaderElement = item; } } const tab = getInstanceById(item.getAttribute("data-id")) as Tab; tab.parent.switchTab(item, false, false, true, false); tab.parent.showHeading(); }); if (latestTabHeaderElement) { setPanelFocus(latestTabHeaderElement.parentElement.parentElement.parentElement, false); } // 移除没有数据的页签 https://github.com/siyuan-note/siyuan/issues/13390 removedTabs.forEach(item => { item.parent.removeTab(item.id, false, false, false); }); } // 需放在 tab.parent.switchTab 后,否则当前 tab 永远为最后一个 app.plugins.forEach(item => { afterLoadPlugin(item); }); saveLayout(); 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"; json.activeTime = layout.headElement?.getAttribute("data-activetime"); } 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 && layout.editor.protyle.block.id !== layout.editor.protyle.block.rootID) ? 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); }
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; if (!dragElement) { return; } 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"); });};
// TODO: 需支持所有页签类型,避免其他类型页签没有使用到而加载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") { if (json.rootId === json.blockId && json.action) { if (typeof json.action === "string") { json.action = json.action.replace(Constants.CB_GET_ALL, ""); } else if (typeof json.action === "object" && Array.isArray(json.action)) { json.action = json.action.filter((item: string) => item !== Constants.CB_GET_ALL); } } model = new Editor({ app, tab, rootId: json.rootId, blockId: json.blockId, mode: json.mode, scrollPosition: json.scrollPosition, action: typeof json.action === "string" ? (json.action ? [json.action, Constants.CB_GET_FOCUS] : [Constants.CB_GET_FOCUS]) : json.action.concat(Constants.CB_GET_FOCUS), }); } 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 = 232; 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"; nextElement.style.transition = "none"; previousElement.style.transition = "none"; 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.38") { 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 && window.siyuan.layout.leftDock.layout.element === previousElement && previousNowSize < getMinSize(previousElement) && // https://github.com/siyuan-note/siyuan/issues/10506 previousNowSize < previousSize) { return; } if (window.siyuan.layout.rightDock && window.siyuan.layout.rightDock.layout.element === nextElement && nextNowSize < getMinSize(nextElement) && nextNowSize < nextSize) { return; } if (window.siyuan.layout.bottomDock && window.siyuan.layout.bottomDock.layout.element === nextElement && nextNowSize < 64 && nextNowSize < nextSize) { 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 = ""; nextElement.style.transition = ""; previousElement.style.transition = ""; }; }); };
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);
resizeElement.addEventListener("dblclick", () => { const previousElement = resizeElement.previousElementSibling as HTMLElement; const nextElement = resizeElement.nextElementSibling as HTMLElement; if (previousElement && nextElement) { const bigType = ["graph", "inbox", "globalGraph", "backlink"]; let size = 232; nextElement.style.transition = "none"; previousElement.style.transition = "none"; if (resizeElement.classList.contains("layout__resize--lr")) { if (previousElement.classList.contains("layout__dockl")) { document.querySelectorAll("#dockLeft .dock__item--active").forEach(item => { if (bigType.includes(item.getAttribute("data-type"))) { size = 320; } }); previousElement.style.width = size + "px"; window.siyuan.layout.leftDock.setSize(); } else if (nextElement.classList.contains("layout__dockr")) { document.querySelectorAll("#dockRight .dock__item--active").forEach(item => { if (bigType.includes(item.getAttribute("data-type"))) { size = 320; } }); nextElement.style.width = size + "px"; window.siyuan.layout.rightDock.setSize(); } else { previousElement.style.width = ""; nextElement.style.width = ""; previousElement.classList.add("fn__flex-1"); nextElement.classList.add("fn__flex-1"); if (resizeElement.parentElement.classList.contains("layout__dockb")) { window.siyuan.layout.bottomDock.setSize(); } } } else { if (nextElement.classList.contains("layout__dockb")) { nextElement.style.height = "232px"; window.siyuan.layout.bottomDock.setSize(); } else { previousElement.style.height = ""; nextElement.style.height = ""; previousElement.classList.add("fn__flex-1"); nextElement.classList.add("fn__flex-1"); if (resizeElement.parentElement.classList.contains("layout__dockl")) { window.siyuan.layout.leftDock.setSize(); } else if (resizeElement.parentElement.classList.contains("layout__dockr")) { window.siyuan.layout.rightDock.setSize(); } } } resizeTabs(); nextElement.style.transition = ""; previousElement.style.transition = ""; } });};
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 = ""; } }); if (layout.direction === "lr" && layout.element.scrollWidth > layout.element.clientWidth + 2) { let index = Math.ceil(screen.width / 8); while (index > 0) { let width = 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"; } width += item.element.clientWidth; }); index--; if (width <= layout.element.clientWidth) { break; } } } layout.children.forEach((item: Layout | Wnd) => { if (item instanceof Layout && item.size !== "0px") { adjustLayout(item); } });};
export const fixWndFlex1 = (layout: Layout) => { if (layout.children.length < 2) { return; } if (layout.children[layout.children.length - 2].element.classList.contains("fn__flex-1")) { return; } layout.children.forEach((item, index) => { if (index !== layout.children.length - 2) { if (layout.direction === "lr") { if (item.element.classList.contains("fn__flex-1")) { item.element.style.width = item.element.clientWidth + "px"; item.element.classList.remove("fn__flex-1"); } } else { if (item.element.classList.contains("fn__flex-1")) { item.element.style.height = item.element.clientHeight + "px"; item.element.classList.remove("fn__flex-1"); } } } }); const flex1Element = layout.children[layout.children.length - 2].element; if (layout.direction === "lr") { if (flex1Element.style.width) { flex1Element.style.width = ""; flex1Element.classList.add("fn__flex-1"); } } else { if (flex1Element.style.height) { flex1Element.style.height = ""; flex1Element.classList.add("fn__flex-1"); } }};