浏览代码

:sparkles: https://github.com/siyuan-note/siyuan/issues/3565 折叠移除

Vanessa 2 年之前
父节点
当前提交
8b8859bc54
共有 2 个文件被更改,包括 29 次插入446 次删除
  1. 29 24
      app/src/layout/dock/Backlink.ts
  2. 0 422
      app/src/layout/dock/Backlinks.ts

+ 29 - 24
app/src/layout/dock/Backlink.ts

@@ -287,35 +287,40 @@ export class Backlink extends Model {
 
     private toggleItem(liElement: HTMLElement, isMention: boolean) {
         const svgElement = liElement.firstElementChild.firstElementChild;
+        const docId = liElement.getAttribute("data-node-id")
         if (svgElement.classList.contains("b3-list-item__arrow--open")) {
             svgElement.classList.remove("b3-list-item__arrow--open");
-            liElement.nextElementSibling?.classList.add("fn__none");
+            this.editors.find((item, index) => {
+                if (item.protyle.block.rootID === docId) {
+                    item.destroy();
+                    this.editors.splice(index, 1);
+                    return true;
+                }
+            });
+            liElement.nextElementSibling?.remove();
         } else {
             svgElement.classList.add("b3-list-item__arrow--open");
-            if (liElement.nextElementSibling && liElement.nextElementSibling.tagName === "DIV") {
-                liElement.nextElementSibling.classList.remove("fn__none");
-            } else {
-                fetchPost(isMention ? "/api/ref/getBackmentionDoc" : "/api/ref/getBacklinkDoc", {
-                    defID: this.blockId,
-                    refTreeID: liElement.getAttribute("data-node-id")
-                }, (response) => {
-                    const editorElement = document.createElement("div");
-                    editorElement.style.minHeight = "auto";
-                    liElement.after(editorElement);
-                    const editor = new Protyle(editorElement, {
-                        blockId: "",
-                        backlinkData: isMention ? response.data.backmentions : response.data.backlinks,
-                        render: {
-                            background: false,
-                            title: false,
-                            gutter: true,
-                            scroll: false,
-                            breadcrumb: false,
-                        }
-                    });
-                    this.editors.push(editor);
+            fetchPost(isMention ? "/api/ref/getBackmentionDoc" : "/api/ref/getBacklinkDoc", {
+                defID: this.blockId,
+                refTreeID: docId
+            }, (response) => {
+                const editorElement = document.createElement("div");
+                editorElement.style.minHeight = "auto";
+                liElement.after(editorElement);
+                const editor = new Protyle(editorElement, {
+                    blockId: "",
+                    backlinkData: isMention ? response.data.backmentions : response.data.backlinks,
+                    render: {
+                        background: false,
+                        title: false,
+                        gutter: true,
+                        scroll: false,
+                        breadcrumb: false,
+                    }
                 });
-            }
+                editor.protyle.block.rootID = docId
+                this.editors.push(editor);
+            });
         }
     }
 

+ 0 - 422
app/src/layout/dock/Backlinks.ts

@@ -1,422 +0,0 @@
-import {Tab} from "../Tab";
-import {Model} from "../Model";
-import {getDisplayName} from "../../util/pathName";
-import {Tree} from "../../util/Tree";
-import {hasClosestByClassName} from "../../protyle/util/hasClosest";
-import {getDockByType, setPanelFocus} from "../util";
-import {fetchPost} from "../../util/fetch";
-import {Constants} from "../../constants";
-import {getAllModels} from "../getAll";
-import {onGet} from "../../protyle/util/onGet";
-import {updateHotkeyTip} from "../../protyle/util/compatibility";
-import {openFileById} from "../../editor/util";
-import {MenuItem} from "../../menus/Menu";
-
-export class Backlinks extends Model {
-    public element: HTMLElement;
-    public inputsElement: NodeListOf<HTMLInputElement>;
-    public type: "pin" | "local";
-    public blockId: string;
-    public rootId: string; // "local" 必传
-    private tree: Tree;
-    private notebookId: string;
-    private mTree: Tree;
-    public beforeLen = 10;
-
-    constructor(options: {
-        tab: Tab,
-        blockId: string,
-        rootId?: string,
-        type: "pin" | "local"
-    }) {
-        super({
-            id: options.tab.id,
-            callback() {
-                if (this.type === "local") {
-                    fetchPost("/api/block/checkBlockExist", {id: this.blockId}, existResponse => {
-                        if (!existResponse.data) {
-                            this.parent.parent.removeTab(this.parent.id);
-                        }
-                    });
-                }
-            },
-            msgCallback(data) {
-                if (data) {
-                    switch (data.cmd) {
-                        case "rename":
-                            if (this.type === "local" && this.blockId === data.data.id) {
-                                this.parent.updateTitle(data.data.title);
-                            }
-                            break;
-                        case "unmount":
-                            if (this.notebookId === data.data.box && this.type === "local") {
-                                this.parent.parent.removeTab(this.parent.id);
-                            }
-                            break;
-                        case "remove":
-                            if (this.path?.indexOf(getDisplayName(data.data.path, false, true)) === 0 && this.type === "local") {
-                                this.parent.parent.removeTab(this.parent.id);
-                            }
-                            break;
-                    }
-                }
-            }
-        });
-        this.blockId = options.blockId;
-        this.rootId = options.rootId;
-        this.type = options.type;
-        this.element = options.tab.panelElement;
-        this.element.classList.add("fn__flex-column", "file-tree", "sy__backlink");
-        this.element.innerHTML = `<div class="block__icons">
-    <div class="block__logo">
-        <svg><use xlink:href="#iconLink"></use></svg>
-        ${window.siyuan.languages.backlinks}
-    </div>
-    <span class="counter listCount"></span>
-    <span class="fn__space"></span>
-    <label class="b3-form__icon b3-form__icon--small search__label">
-        <svg class="b3-form__icon-icon"><use xlink:href="#iconSearch"></use></svg>
-        <input class="b3-text-field b3-text-field--small b3-form__icon-input" placeholder="Enter ${window.siyuan.languages.search}" />
-    </label>
-    <span class="fn__space"></span>
-    <span data-type="refresh" class="block__icon b3-tooltips b3-tooltips__sw" aria-label="${window.siyuan.languages.refresh}"><svg><use xlink:href='#iconRefresh'></use></svg></span>
-    <span class="fn__space"></span>
-    <span data-type="more" class="block__icon b3-tooltips b3-tooltips__sw" aria-label="${window.siyuan.languages.showMore}">
-        <svg><use xlink:href="#iconAlignCenter"></use></svg>
-    </span>
-    <span class="fn__space"></span>
-    <span data-type="expand" class="block__icon b3-tooltips b3-tooltips__sw" aria-label="${window.siyuan.languages.expand} ${updateHotkeyTip(window.siyuan.config.keymap.editor.general.expand.custom)}">
-        <svg><use xlink:href="#iconFullscreen"></use></svg>
-    </span>
-    <span class="fn__space"></span>
-    <span data-type="collapse" class="block__icon b3-tooltips b3-tooltips__sw" aria-label="${window.siyuan.languages.collapse} ${updateHotkeyTip(window.siyuan.config.keymap.editor.general.collapse.custom)}">
-        <svg><use xlink:href="#iconContract"></use></svg>
-    </span>
-    <span class="${this.type === "local" ? "fn__none " : ""}fn__space"></span>
-    <span data-type="min" class="${this.type === "local" ? "fn__none " : ""}block__icon b3-tooltips b3-tooltips__sw" aria-label="${window.siyuan.languages.min} ${updateHotkeyTip(window.siyuan.config.keymap.general.closeTab.custom)}"><svg><use xlink:href='#iconMin'></use></svg></span>
-</div>
-<div class="backlinkList fn__flex-1"></div>
-<div class="block__icons">
-    <div class="block__logo">
-        <svg><use xlink:href="#iconLink"></use></svg>
-        ${window.siyuan.languages.mentions}
-    </div>
-    <span class="counter listMCount"></span>
-    <span class="fn__space"></span>
-    <label class="b3-form__icon b3-form__icon--small search__label">
-        <svg class="b3-form__icon-icon"><use xlink:href="#iconSearch"></use></svg>
-        <input class="b3-text-field b3-text-field--small b3-form__icon-input" placeholder="Enter ${window.siyuan.languages.search}" />
-    </label>
-    <span class="fn__space"></span>
-    <span data-type="mExpand" class="block__icon b3-tooltips b3-tooltips__nw" aria-label="${window.siyuan.languages.expand}">
-        <svg><use xlink:href="#iconFullscreen"></use></svg>
-    </span>
-    <span class="fn__space"></span>
-    <span data-type="mCollapse" class="block__icon b3-tooltips b3-tooltips__nw" aria-label="${window.siyuan.languages.collapse}">
-        <svg><use xlink:href="#iconContract"></use></svg>
-    </span>
-    <span class="fn__space"></span>
-    <span data-type="layout" class="block__icon b3-tooltips b3-tooltips__nw" aria-label="${window.siyuan.languages.down}">
-        <svg><use xlink:href="#iconDown"></use></svg>
-    </span>
-</div>
-<div class="backlinkMList fn__flex-1"></div>`;
-
-        this.inputsElement = this.element.querySelectorAll("input");
-        this.inputsElement.forEach((item) => {
-            item.addEventListener("keydown", (event: KeyboardEvent) => {
-                if (!event.isComposing && event.key === "Enter") {
-                    this.searchBacklinks();
-                }
-            });
-            item.addEventListener("input", (event: KeyboardEvent) => {
-                const inputElement = event.target as HTMLInputElement;
-                if (inputElement.value === "") {
-                    inputElement.classList.remove("search__input--block");
-                } else {
-                    inputElement.classList.add("search__input--block");
-                }
-            });
-        });
-
-        this.tree = new Tree({
-            element: this.element.querySelector(".backlinkList") as HTMLElement,
-            data: null,
-            click(element: HTMLElement) {
-                openFileById({
-                    id: element.getAttribute("data-node-id"),
-                    action: [Constants.CB_GET_FOCUS, Constants.CB_GET_CONTEXT]
-                });
-            },
-            ctrlClick(element: HTMLElement) {
-                openFileById({
-                    id: element.getAttribute("data-node-id"),
-                    keepCursor: true,
-                    action: [Constants.CB_GET_CONTEXT]
-                });
-            },
-            altClick(element: HTMLElement) {
-                openFileById({
-                    id: element.getAttribute("data-node-id"),
-                    position: "right",
-                    action: [Constants.CB_GET_FOCUS, Constants.CB_GET_CONTEXT]
-                });
-            },
-            shiftClick(element: HTMLElement) {
-                openFileById({
-                    id: element.getAttribute("data-node-id"),
-                    position: "bottom",
-                    action: [Constants.CB_GET_FOCUS, Constants.CB_GET_CONTEXT]
-                });
-            }
-        });
-        this.mTree = new Tree({
-            element: this.element.querySelector(".backlinkMList") as HTMLElement,
-            data: null,
-            click: (element, event) => {
-                const actionElement = hasClosestByClassName(event.target as HTMLElement, "b3-list-item__action");
-                if (actionElement) {
-                    if (actionElement.firstElementChild.classList.contains("fn__rotate")) {
-                        return;
-                    }
-                    window.siyuan.menus.menu.remove();
-                    window.siyuan.menus.menu.append(new MenuItem({
-                        label: window.siyuan.languages.turnInto + " " + window.siyuan.languages.turnToStaticRef,
-                        click: () => {
-                            this.turnToRef(element, false);
-                        }
-                    }).element);
-                    window.siyuan.menus.menu.append(new MenuItem({
-                        label: window.siyuan.languages.turnInto + " " + window.siyuan.languages.turnToDynamicRef,
-                        click: () => {
-                            this.turnToRef(element, true);
-                        }
-                    }).element);
-                    window.siyuan.menus.menu.popup({x: event.clientX, y: event.clientY});
-                } else {
-                    openFileById({
-                        id: element.getAttribute("data-node-id"),
-                        action: [Constants.CB_GET_FOCUS, Constants.CB_GET_CONTEXT]
-                    });
-                }
-            },
-            ctrlClick(element: HTMLElement) {
-                openFileById({
-                    id: element.getAttribute("data-node-id"),
-                    keepCursor: true,
-                    action: [Constants.CB_GET_CONTEXT]
-                });
-            },
-            altClick(element: HTMLElement) {
-                openFileById({
-                    id: element.getAttribute("data-node-id"),
-                    position: "right",
-                    action: [Constants.CB_GET_FOCUS, Constants.CB_GET_CONTEXT]
-                });
-            },
-            shiftClick(element: HTMLElement) {
-                openFileById({
-                    id: element.getAttribute("data-node-id"),
-                    position: "bottom",
-                    action: [Constants.CB_GET_FOCUS, Constants.CB_GET_CONTEXT]
-                });
-            },
-            blockExtHTML: `<span class="b3-list-item__action b3-tooltips b3-tooltips__nw" aria-label="${window.siyuan.languages.more}"><svg><use xlink:href="#iconMore"></use></svg></span>`
-        });
-        // 为了快捷键的 dispatch
-        this.element.querySelector('[data-type="collapse"]').addEventListener("click", () => {
-            this.tree.collapseAll();
-        });
-        this.element.querySelector('[data-type="expand"]').addEventListener("click", () => {
-            this.tree.expandAll();
-        });
-        this.element.addEventListener("click", (event) => {
-            if (this.type === "local") {
-                setPanelFocus(this.element.parentElement.parentElement);
-            } else {
-                setPanelFocus(this.element.firstElementChild);
-            }
-            let target = event.target as HTMLElement;
-            while (target && !target.isEqualNode(this.element)) {
-                if (target.classList.contains("block__icon")) {
-                    const type = target.getAttribute("data-type");
-                    switch (type) {
-                        case "refresh":
-                            this.refresh();
-                            break;
-                        case "mExpand":
-                            this.mTree.expandAll();
-                            break;
-                        case "mCollapse":
-                            this.mTree.collapseAll();
-                            break;
-                        case "min":
-                            getDockByType("backlink").toggleModel("backlink");
-                            break;
-                        case "more":
-                            if (target.classList.contains("ft__primary")) {
-                                this.searchBacklinks(this.beforeLen);
-                                target.classList.remove("ft__primary");
-                                target.parentElement.nextElementSibling.classList.remove("backlink--more");
-                            } else {
-                                this.searchBacklinks(this.beforeLen * 20);
-                                target.classList.add("ft__primary");
-                                target.parentElement.nextElementSibling.classList.add("backlink--more");
-                            }
-                            break;
-                        case "layout":
-                            if (this.mTree.element.style.flex) {
-                                if (this.mTree.element.style.height === "0px") {
-                                    this.tree.element.classList.remove("fn__none");
-                                    this.mTree.element.removeAttribute("style");
-                                    target.setAttribute("aria-label", window.siyuan.languages.up);
-                                    target.querySelector("use").setAttribute("xlink:href", "#iconUp");
-                                } else {
-                                    this.tree.element.classList.remove("fn__none");
-                                    this.mTree.element.removeAttribute("style");
-                                    target.setAttribute("aria-label", window.siyuan.languages.down);
-                                    target.querySelector("use").setAttribute("xlink:href", "#iconDown");
-                                }
-                            } else {
-                                if (target.getAttribute("aria-label") === window.siyuan.languages.down) {
-                                    this.tree.element.classList.remove("fn__none");
-                                    this.mTree.element.setAttribute("style", "flex:none;height:0px");
-                                    target.setAttribute("aria-label", window.siyuan.languages.up);
-                                    target.querySelector("use").setAttribute("xlink:href", "#iconUp");
-                                } else {
-                                    this.tree.element.classList.add("fn__none");
-                                    this.mTree.element.setAttribute("style", `flex:none;height:${this.element.clientHeight - this.tree.element.previousElementSibling.clientHeight * 2}px`);
-                                    target.setAttribute("aria-label", window.siyuan.languages.down);
-                                    target.querySelector("use").setAttribute("xlink:href", "#iconDown");
-                                }
-                            }
-                            target.setAttribute("data-clicked", "true");
-                            break;
-                    }
-                }
-                target = target.parentElement;
-            }
-        });
-
-        this.searchBacklinks();
-
-        if (this.type === "pin") {
-            setPanelFocus(this.element.firstElementChild);
-        }
-    }
-
-    private turnToRef(element: HTMLElement, isDynamic: boolean) {
-        element.querySelector(".b3-list-item__action").innerHTML = '<svg class="fn__rotate"><use xlink:href="#iconRefresh"></use></svg>';
-        this.element.querySelector('.block__icon[data-type="refresh"] svg').classList.add("fn__rotate");
-        fetchPost("/api/ref/createBacklink", {
-            refID: element.getAttribute("data-node-id"),
-            refText: decodeURIComponent(element.getAttribute("data-ref-text")),
-            defID: this.blockId,
-            pushMode: 0,
-            isDynamic
-        }, response => {
-            if (response.data.defID === this.blockId) {
-                this.searchBacklinks(undefined, true);
-            }
-            getAllModels().editor.forEach(item => {
-                if (response.data.refRootID === item.editor.protyle.block.rootID) {
-                    fetchPost("/api/filetree/getDoc", {
-                        id: item.editor.protyle.block.id,
-                        size: Constants.SIZE_GET,
-                    }, getResponse => {
-                        onGet(getResponse, item.editor.protyle);
-                    });
-                }
-            });
-        });
-    }
-
-    public refresh() {
-        fetchPost("/api/ref/refreshBacklink", {
-            id: this.blockId,
-        }, () => {
-            this.searchBacklinks();
-        });
-    }
-
-    private searchBacklinks(beforeLength?: number, ignoreClass = false) {
-        const element = this.element.querySelector('.block__icon[data-type="refresh"] svg');
-        if (element.classList.contains("fn__rotate") && !ignoreClass) {
-            return;
-        }
-        element.classList.add("fn__rotate");
-        let beforeLen;
-        if (beforeLength) {
-            beforeLen = beforeLength;
-        } else {
-            beforeLen = this.element.querySelector('.block__icon[data-type="more"]').classList.contains("ft__primary") ? this.beforeLen * 20 : this.beforeLen;
-        }
-        fetchPost("/api/ref/getBacklink", {
-            k: this.inputsElement[0].value,
-            mk: this.inputsElement[1].value,
-            beforeLen,
-            id: this.blockId,
-        }, response => {
-            this.render(response.data);
-        });
-    }
-
-    public render(data: { box: string, backlinks: IBlockTree[], backmentions: IBlockTree[], linkRefsCount: number, mentionsCount: number, k: string, mk: string }) {
-        if (!data) {
-            data = {
-                box: "",
-                backlinks: [],
-                backmentions: [],
-                linkRefsCount: 0,
-                mentionsCount: 0,
-                k: "",
-                mk: ""
-            };
-        }
-        this.element.querySelector('.block__icon[data-type="refresh"] svg').classList.remove("fn__rotate");
-        this.notebookId = data.box;
-        this.inputsElement[0].value = data.k;
-        this.inputsElement[1].value = data.mk;
-
-        this.tree.updateData(data.backlinks);
-        this.mTree.updateData(data.backmentions);
-
-        const countElement = this.element.querySelector(".listCount");
-        if (data.linkRefsCount === 0) {
-            countElement.classList.add("fn__none");
-        } else {
-            countElement.classList.remove("fn__none");
-            countElement.textContent = data.linkRefsCount.toString();
-        }
-        const mCountElement = this.element.querySelector(".listMCount");
-        if (data.mentionsCount === 0) {
-            mCountElement.classList.add("fn__none");
-        } else {
-            mCountElement.classList.remove("fn__none");
-            mCountElement.textContent = data.mentionsCount.toString();
-        }
-
-        const layoutElement = this.element.querySelector("[data-type='layout']");
-        if (layoutElement.getAttribute("data-clicked")) {
-            return;
-        }
-        if (data.mentionsCount === 0) {
-            this.tree.element.classList.remove("fn__none");
-            this.mTree.element.setAttribute("style", "flex:none;height:0px");
-            layoutElement.setAttribute("aria-label", window.siyuan.languages.up);
-            layoutElement.querySelector("use").setAttribute("xlink:href", "#iconUp");
-            return;
-        }
-        if (data.linkRefsCount === 0) {
-            this.tree.element.classList.add("fn__none");
-            this.mTree.element.setAttribute("style", `flex:none;height:${this.element.clientHeight - this.tree.element.previousElementSibling.clientHeight * 2}px`);
-            layoutElement.setAttribute("aria-label", window.siyuan.languages.down);
-            layoutElement.querySelector("use").setAttribute("xlink:href", "#iconDown");
-        } else {
-            this.tree.element.classList.remove("fn__none");
-            this.mTree.element.removeAttribute("style");
-            layoutElement.setAttribute("aria-label", window.siyuan.languages.down);
-            layoutElement.querySelector("use").setAttribute("xlink:href", "#iconDown");
-        }
-    }
-}