mirror of
https://github.com/siyuan-note/siyuan.git
synced 2025-12-20 16:40:13 +01:00
This commit is contained in:
parent
284d78bc27
commit
5f8c76fc87
9 changed files with 443 additions and 23 deletions
|
|
@ -429,7 +429,7 @@ export const updateBacklinkGraph = (models: IModels, protyle: IProtyle) => {
|
||||||
item.searchGraph(true, blockId);
|
item.searchGraph(true, blockId);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
models.backlinks.forEach(item => {
|
models.backlink.forEach(item => {
|
||||||
if (item.type === "local" && item.rootId !== protyle?.block?.rootID) {
|
if (item.type === "local" && item.rootId !== protyle?.block?.rootID) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -443,7 +443,7 @@ export const updateBacklinkGraph = (models: IModels, protyle: IProtyle) => {
|
||||||
item.element.querySelector('.block__icon[data-type="refresh"] svg').classList.add("fn__rotate");
|
item.element.querySelector('.block__icon[data-type="refresh"] svg').classList.add("fn__rotate");
|
||||||
fetchPost("/api/ref/getBacklink", {
|
fetchPost("/api/ref/getBacklink", {
|
||||||
id: blockId || "",
|
id: blockId || "",
|
||||||
beforeLen: item.element.querySelector('.block__icon[data-type="more"]').classList.contains("ft__primary") ? item.beforeLen * 20 : item.beforeLen,
|
beforeLen: 12,
|
||||||
k: item.inputsElement[0].value,
|
k: item.inputsElement[0].value,
|
||||||
mk: item.inputsElement[1].value,
|
mk: item.inputsElement[1].value,
|
||||||
}, response => {
|
}, response => {
|
||||||
|
|
|
||||||
400
app/src/layout/dock/Backlink.ts
Normal file
400
app/src/layout/dock/Backlink.ts
Normal file
|
|
@ -0,0 +1,400 @@
|
||||||
|
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 Backlink 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;
|
||||||
|
|
||||||
|
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 && this.type === "local") {
|
||||||
|
switch (data.cmd) {
|
||||||
|
case "rename":
|
||||||
|
if (this.blockId === data.data.id) {
|
||||||
|
this.parent.updateTitle(data.data.title);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "unmount":
|
||||||
|
if (this.notebookId === data.data.box) {
|
||||||
|
this.parent.parent.removeTab(this.parent.id);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "remove":
|
||||||
|
if (this.path?.indexOf(getDisplayName(data.data.path, false, true)) === 0) {
|
||||||
|
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="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 "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(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(reload = false) {
|
||||||
|
const element = this.element.querySelector('.block__icon[data-type="refresh"] svg');
|
||||||
|
if (element.classList.contains("fn__rotate") && !reload) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
element.classList.add("fn__rotate");
|
||||||
|
fetchPost("/api/ref/getBacklink", {
|
||||||
|
k: this.inputsElement[0].value,
|
||||||
|
mk: this.inputsElement[1].value,
|
||||||
|
beforeLen: 12,
|
||||||
|
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");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -8,11 +8,11 @@ import {getAllModels} from "../getAll";
|
||||||
import {Bookmark} from "./Bookmark";
|
import {Bookmark} from "./Bookmark";
|
||||||
import {Tag} from "./Tag";
|
import {Tag} from "./Tag";
|
||||||
import {Graph} from "./Graph";
|
import {Graph} from "./Graph";
|
||||||
import {Backlinks} from "./Backlinks";
|
|
||||||
import {Model} from "../Model";
|
import {Model} from "../Model";
|
||||||
import {getDockByType, resizeTabs, setPanelFocus} from "../util";
|
import {getDockByType, resizeTabs, setPanelFocus} from "../util";
|
||||||
import {Inbox} from "./Inbox";
|
import {Inbox} from "./Inbox";
|
||||||
import Protyle from "../../protyle";
|
import Protyle from "../../protyle";
|
||||||
|
import {Backlink} from "./Backlink";
|
||||||
|
|
||||||
export class Dock {
|
export class Dock {
|
||||||
public element: HTMLElement;
|
public element: HTMLElement;
|
||||||
|
|
@ -199,10 +199,22 @@ export class Dock {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
|
// TODO: remove
|
||||||
|
// case "backlink":
|
||||||
|
// tab = new Tab({
|
||||||
|
// callback(tab: Tab) {
|
||||||
|
// tab.addModel(new Backlinks({
|
||||||
|
// type: "pin",
|
||||||
|
// tab,
|
||||||
|
// blockId: editor?.protyle?.block?.rootID,
|
||||||
|
// }));
|
||||||
|
// }
|
||||||
|
// });
|
||||||
|
// break;
|
||||||
case "backlink":
|
case "backlink":
|
||||||
tab = new Tab({
|
tab = new Tab({
|
||||||
callback(tab: Tab) {
|
callback(tab: Tab) {
|
||||||
tab.addModel(new Backlinks({
|
tab.addModel(new Backlink({
|
||||||
type: "pin",
|
type: "pin",
|
||||||
tab,
|
tab,
|
||||||
blockId: editor?.protyle?.block?.rootID,
|
blockId: editor?.protyle?.block?.rootID,
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,12 @@
|
||||||
import {getAllModels} from "../getAll";
|
import {getAllModels} from "../getAll";
|
||||||
import {Tab} from "../Tab";
|
import {Tab} from "../Tab";
|
||||||
import {Backlinks} from "./Backlinks";
|
|
||||||
import {Graph} from "./Graph";
|
import {Graph} from "./Graph";
|
||||||
import {Outline} from "./Outline";
|
import {Outline} from "./Outline";
|
||||||
import {switchWnd} from "../util";
|
import {switchWnd} from "../util";
|
||||||
|
import {Backlink} from "./Backlink";
|
||||||
|
|
||||||
export const openBacklink = (protyle: IProtyle) => {
|
export const openBacklink = (protyle: IProtyle) => {
|
||||||
const backlink = getAllModels().backlinks.find(item => {
|
const backlink = getAllModels().backlink.find(item => {
|
||||||
if (item.blockId === protyle.block.id && item.type === "local") {
|
if (item.blockId === protyle.block.id && item.type === "local") {
|
||||||
item.parent.parent.removeTab(item.parent.id);
|
item.parent.parent.removeTab(item.parent.id);
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -20,7 +20,7 @@ export const openBacklink = (protyle: IProtyle) => {
|
||||||
icon: "iconLink",
|
icon: "iconLink",
|
||||||
title: protyle.title.editElement.textContent,
|
title: protyle.title.editElement.textContent,
|
||||||
callback(tab: Tab) {
|
callback(tab: Tab) {
|
||||||
tab.addModel(new Backlinks({
|
tab.addModel(new Backlink({
|
||||||
type: "local",
|
type: "local",
|
||||||
tab,
|
tab,
|
||||||
blockId: protyle.block.id,
|
blockId: protyle.block.id,
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ import {Tab} from "./Tab";
|
||||||
import {Editor} from "../editor";
|
import {Editor} from "../editor";
|
||||||
import {Graph} from "./dock/Graph";
|
import {Graph} from "./dock/Graph";
|
||||||
import {Outline} from "./dock/Outline";
|
import {Outline} from "./dock/Outline";
|
||||||
import {Backlinks} from "./dock/Backlinks";
|
import {Backlink} from "./dock/Backlink";
|
||||||
import {Asset} from "../asset";
|
import {Asset} from "../asset";
|
||||||
import {Search} from "../search";
|
import {Search} from "../search";
|
||||||
|
|
||||||
|
|
@ -13,7 +13,7 @@ export const getAllModels = () => {
|
||||||
graph: [],
|
graph: [],
|
||||||
asset: [],
|
asset: [],
|
||||||
outline: [],
|
outline: [],
|
||||||
backlinks: [],
|
backlink: [],
|
||||||
search: []
|
search: []
|
||||||
};
|
};
|
||||||
const getTabs = (layout: Layout) => {
|
const getTabs = (layout: Layout) => {
|
||||||
|
|
@ -27,8 +27,8 @@ export const getAllModels = () => {
|
||||||
models.graph.push(model);
|
models.graph.push(model);
|
||||||
} else if (model instanceof Outline) {
|
} else if (model instanceof Outline) {
|
||||||
models.outline.push(model);
|
models.outline.push(model);
|
||||||
} else if (model instanceof Backlinks) {
|
} else if (model instanceof Backlink) {
|
||||||
models.backlinks.push(model);
|
models.backlink.push(model);
|
||||||
} else if (model instanceof Asset) {
|
} else if (model instanceof Asset) {
|
||||||
models.asset.push(model);
|
models.asset.push(model);
|
||||||
} else if (model instanceof Search) {
|
} else if (model instanceof Search) {
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,6 @@ import {newFile} from "../util/newFile";
|
||||||
import {Outline} from "./dock/Outline";
|
import {Outline} from "./dock/Outline";
|
||||||
import {Bookmark} from "./dock/Bookmark";
|
import {Bookmark} from "./dock/Bookmark";
|
||||||
import {updateHotkeyTip} from "../protyle/util/compatibility";
|
import {updateHotkeyTip} from "../protyle/util/compatibility";
|
||||||
import {Backlinks} from "./dock/Backlinks";
|
|
||||||
import {Tag} from "./dock/Tag";
|
import {Tag} from "./dock/Tag";
|
||||||
import {getAllModels, getAllTabs} from "./getAll";
|
import {getAllModels, getAllTabs} from "./getAll";
|
||||||
import {Asset} from "../asset";
|
import {Asset} from "../asset";
|
||||||
|
|
@ -26,6 +25,7 @@ import {Constants} from "../constants";
|
||||||
import {openSearch} from "../search/spread";
|
import {openSearch} from "../search/spread";
|
||||||
import {saveScroll} from "../protyle/scroll/saveScroll";
|
import {saveScroll} from "../protyle/scroll/saveScroll";
|
||||||
import {pdfResize} from "../asset/renderAssets";
|
import {pdfResize} from "../asset/renderAssets";
|
||||||
|
import {Backlink} from "./dock/Backlink";
|
||||||
|
|
||||||
export const setPanelFocus = (element: Element) => {
|
export const setPanelFocus = (element: Element) => {
|
||||||
if (element.classList.contains("block__icons--active") || element.classList.contains("layout__wnd--active")) {
|
if (element.classList.contains("block__icons--active") || element.classList.contains("layout__wnd--active")) {
|
||||||
|
|
@ -214,8 +214,8 @@ const JSONToCenter = (json: any, layout?: Layout | Wnd | Tab | Model) => {
|
||||||
tab: (layout as Tab),
|
tab: (layout as Tab),
|
||||||
path: json.path,
|
path: json.path,
|
||||||
}));
|
}));
|
||||||
} else if (json.instance === "Backlinks") {
|
} else if (json.instance === "Backlink") {
|
||||||
(layout as Tab).addModel(new Backlinks({
|
(layout as Tab).addModel(new Backlink({
|
||||||
tab: (layout as Tab),
|
tab: (layout as Tab),
|
||||||
blockId: json.blockId,
|
blockId: json.blockId,
|
||||||
rootId: json.rootId,
|
rootId: json.rootId,
|
||||||
|
|
@ -305,7 +305,7 @@ export const layoutToJSON = (layout: Layout | Wnd | Tab | Model, json: any) => {
|
||||||
json.pin = layout.headElement.classList.contains("item--pin");
|
json.pin = layout.headElement.classList.contains("item--pin");
|
||||||
if (layout.model instanceof Files) {
|
if (layout.model instanceof Files) {
|
||||||
json.lang = "fileTree";
|
json.lang = "fileTree";
|
||||||
} else if (layout.model instanceof Backlinks && layout.model.type === "pin") {
|
} else if (layout.model instanceof Backlink && layout.model.type === "pin") {
|
||||||
json.lang = "backlinks";
|
json.lang = "backlinks";
|
||||||
} else if (layout.model instanceof Bookmark) {
|
} else if (layout.model instanceof Bookmark) {
|
||||||
json.lang = "bookmark";
|
json.lang = "bookmark";
|
||||||
|
|
@ -331,11 +331,11 @@ export const layoutToJSON = (layout: Layout | Wnd | Tab | Model, json: any) => {
|
||||||
} else if (layout instanceof Asset) {
|
} else if (layout instanceof Asset) {
|
||||||
json.path = layout.path;
|
json.path = layout.path;
|
||||||
json.instance = "Asset";
|
json.instance = "Asset";
|
||||||
} else if (layout instanceof Backlinks) {
|
} else if (layout instanceof Backlink) {
|
||||||
json.blockId = layout.blockId;
|
json.blockId = layout.blockId;
|
||||||
json.rootId = layout.rootId;
|
json.rootId = layout.rootId;
|
||||||
json.type = layout.type;
|
json.type = layout.type;
|
||||||
json.instance = "Backlinks";
|
json.instance = "Backlink";
|
||||||
} else if (layout instanceof Bookmark) {
|
} else if (layout instanceof Bookmark) {
|
||||||
json.instance = "Bookmark";
|
json.instance = "Bookmark";
|
||||||
} else if (layout instanceof Files) {
|
} else if (layout instanceof Files) {
|
||||||
|
|
@ -471,8 +471,8 @@ export const copyTab = (tab: Tab) => {
|
||||||
blockId: tab.model.blockId,
|
blockId: tab.model.blockId,
|
||||||
type: tab.model.type
|
type: tab.model.type
|
||||||
});
|
});
|
||||||
} else if (tab.model instanceof Backlinks) {
|
} else if (tab.model instanceof Backlink) {
|
||||||
model = new Backlinks({
|
model = new Backlink({
|
||||||
tab: newTab,
|
tab: newTab,
|
||||||
blockId: tab.model.blockId,
|
blockId: tab.model.blockId,
|
||||||
rootId: tab.model.rootId,
|
rootId: tab.model.rootId,
|
||||||
|
|
|
||||||
|
|
@ -665,7 +665,7 @@ export const dropEvent = (protyle: IProtyle, editorElement: HTMLElement) => {
|
||||||
if (isBacklink) {
|
if (isBacklink) {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
// 等待 drag transaction
|
// 等待 drag transaction
|
||||||
getAllModels().backlinks.forEach(item => {
|
getAllModels().backlink.forEach(item => {
|
||||||
item.refresh();
|
item.refresh();
|
||||||
});
|
});
|
||||||
}, 200);
|
}, 200);
|
||||||
|
|
|
||||||
|
|
@ -76,7 +76,6 @@ export const onGet = (data: IWebSocketData, protyle: IProtyle, action: string[]
|
||||||
protyle.block.id = data.data.id;
|
protyle.block.id = data.data.id;
|
||||||
protyle.scroll.lastScrollTop = 0;
|
protyle.scroll.lastScrollTop = 0;
|
||||||
protyle.contentElement.scrollTop = 0;
|
protyle.contentElement.scrollTop = 0;
|
||||||
preventScroll(protyle); // 聚焦返回时 protyle.contentElement.scrollTop 不等于 0,会导致滚动加载,从而导致 showAll 为 false
|
|
||||||
protyle.wysiwyg.element.setAttribute("data-doc-type", data.data.type);
|
protyle.wysiwyg.element.setAttribute("data-doc-type", data.data.type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
13
app/src/types/index.d.ts
vendored
13
app/src/types/index.d.ts
vendored
|
|
@ -1,6 +1,15 @@
|
||||||
type TLayout = "normal" | "top" | "bottom" | "left" | "right" | "center"
|
type TLayout = "normal" | "top" | "bottom" | "left" | "right" | "center"
|
||||||
type TDirection = "lr" | "tb"
|
type TDirection = "lr" | "tb"
|
||||||
type TDockType = "file" | "outline" | "bookmark" | "tag" | "graph" | "globalGraph" | "backlink" | "inbox"
|
type TDockType =
|
||||||
|
"file"
|
||||||
|
| "outline"
|
||||||
|
| "bookmark"
|
||||||
|
| "tag"
|
||||||
|
| "graph"
|
||||||
|
| "globalGraph"
|
||||||
|
| "backlink"
|
||||||
|
| "backlinkOld"
|
||||||
|
| "inbox"
|
||||||
type TDockPosition = "Left" | "Right" | "Top" | "Bottom"
|
type TDockPosition = "Left" | "Right" | "Top" | "Bottom"
|
||||||
type TWS = "main" | "filetree" | "protyle"
|
type TWS = "main" | "filetree" | "protyle"
|
||||||
type TEditorMode = "preview" | "wysiwyg"
|
type TEditorMode = "preview" | "wysiwyg"
|
||||||
|
|
@ -475,7 +484,7 @@ declare interface IModels {
|
||||||
editor: import("../editor").Editor [],
|
editor: import("../editor").Editor [],
|
||||||
graph: import("../layout/dock/Graph").Graph[],
|
graph: import("../layout/dock/Graph").Graph[],
|
||||||
outline: import("../layout/dock/Outline").Outline[]
|
outline: import("../layout/dock/Outline").Outline[]
|
||||||
backlinks: import("../layout/dock/Backlinks").Backlinks[]
|
backlink: import("../layout/dock/Backlink").Backlink[]
|
||||||
asset: import("../asset").Asset[]
|
asset: import("../asset").Asset[]
|
||||||
search: import("../search").Search[]
|
search: import("../search").Search[]
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue