diff --git a/app/pnpm-lock.yaml b/app/pnpm-lock.yaml
index 0a258c8a7..e4326a260 100644
--- a/app/pnpm-lock.yaml
+++ b/app/pnpm-lock.yaml
@@ -1928,10 +1928,10 @@ packages:
resolution: {integrity: sha512-m0+M53+HYMzqKxwNQZT143K7WwXEGUy9LY31l8dJphXx2P/FQod615mVbxHyqbDCG4J5bHdWm21qZ0e2DVY6CQ==}
engines: {node: '>=14.0.0'}
dependencies:
- 7zip-bin: 5.1.1
'@develar/schema-utils': 2.6.5
'@electron/universal': 1.2.1
'@malept/flatpak-bundler': 0.4.0
+ 7zip-bin: 5.1.1
async-exit-hook: 2.0.1
bluebird-lst: 1.0.9
builder-util: 23.3.3
@@ -2215,9 +2215,9 @@ packages:
/builder-util/23.3.3:
resolution: {integrity: sha512-MJZlUiq2PY5hjYv9+XNaoYdsITqvLgRDoHSFg/4nzpInbNxNjLQOolL04Zsyp+hgfcbFvMC4h0KkR1CMPHLWbA==}
dependencies:
- 7zip-bin: 5.1.1
'@types/debug': 4.1.7
'@types/fs-extra': 9.0.13
+ 7zip-bin: 5.1.1
app-builder-bin: 4.0.0
bluebird-lst: 1.0.9
builder-util-runtime: 9.0.3
diff --git a/app/src/layout/dock/Backlink.ts b/app/src/layout/dock/Backlink.ts
index a62586336..f17af1b2c 100644
--- a/app/src/layout/dock/Backlink.ts
+++ b/app/src/layout/dock/Backlink.ts
@@ -15,9 +15,9 @@ export class Backlink extends Model {
public type: "pin" | "local";
public blockId: string;
public rootId: string; // "local" 必传
- private tree: Tree;
+ public tree: Tree;
private notebookId: string;
- private mTree: Tree;
+ public mTree: Tree;
public editors: Protyle[] = [];
public status: {
[key: string]: {
@@ -143,12 +143,15 @@ export class Backlink extends Model {
data: null,
click: (element) => {
this.toggleItem(element, false);
+ this.setFocus();
+ this.mTree.element.querySelector(".b3-list-item--focus")?.classList.remove("b3-list-item--focus");
},
ctrlClick(element) {
openFileById({
id: element.getAttribute("data-node-id"),
action: [Constants.CB_GET_CONTEXT]
});
+ this.mTree.element.querySelector(".b3-list-item--focus")?.classList.remove("b3-list-item--focus");
},
altClick(element) {
openFileById({
@@ -156,6 +159,7 @@ export class Backlink extends Model {
position: "right",
action: [Constants.CB_GET_FOCUS, Constants.CB_GET_CONTEXT]
});
+ this.mTree.element.querySelector(".b3-list-item--focus")?.classList.remove("b3-list-item--focus");
},
shiftClick(element) {
openFileById({
@@ -163,9 +167,12 @@ export class Backlink extends Model {
position: "bottom",
action: [Constants.CB_GET_FOCUS, Constants.CB_GET_CONTEXT]
});
+ this.mTree.element.querySelector(".b3-list-item--focus")?.classList.remove("b3-list-item--focus");
},
toggleClick: (liElement) => {
this.toggleItem(liElement, false);
+ this.setFocus();
+ this.mTree.element.querySelector(".b3-list-item--focus")?.classList.remove("b3-list-item--focus");
}
});
this.mTree = new Tree({
@@ -173,12 +180,15 @@ export class Backlink extends Model {
data: null,
click: (element) => {
this.toggleItem(element, true);
+ this.setFocus();
+ this.tree.element.querySelector(".b3-list-item--focus")?.classList.remove("b3-list-item--focus");
},
ctrlClick(element) {
openFileById({
id: element.getAttribute("data-node-id"),
action: [Constants.CB_GET_CONTEXT]
});
+ this.tree.element.querySelector(".b3-list-item--focus")?.classList.remove("b3-list-item--focus");
},
altClick(element) {
openFileById({
@@ -186,6 +196,7 @@ export class Backlink extends Model {
position: "right",
action: [Constants.CB_GET_FOCUS, Constants.CB_GET_CONTEXT]
});
+ this.tree.element.querySelector(".b3-list-item--focus")?.classList.remove("b3-list-item--focus");
},
shiftClick(element) {
openFileById({
@@ -193,9 +204,12 @@ export class Backlink extends Model {
position: "bottom",
action: [Constants.CB_GET_FOCUS, Constants.CB_GET_CONTEXT]
});
+ this.tree.element.querySelector(".b3-list-item--focus")?.classList.remove("b3-list-item--focus");
},
toggleClick: (liElement) => {
this.toggleItem(liElement, true);
+ this.setFocus();
+ this.tree.element.querySelector(".b3-list-item--focus")?.classList.remove("b3-list-item--focus");
},
blockExtHTML: ``
});
@@ -227,11 +241,7 @@ export class Backlink extends Model {
});
});
this.element.addEventListener("click", (event) => {
- if (this.type === "local") {
- setPanelFocus(this.element.parentElement.parentElement);
- } else {
- setPanelFocus(this.element);
- }
+ this.setFocus();
let target = event.target as HTMLElement;
while (target && !target.isEqualNode(this.element)) {
if (target.classList.contains("block__icon") && target.parentElement.parentElement.isSameNode(this.element)) {
@@ -299,6 +309,14 @@ export class Backlink extends Model {
}
}
+ private setFocus() {
+ if (this.type === "local") {
+ setPanelFocus(this.element.parentElement.parentElement);
+ } else {
+ setPanelFocus(this.element);
+ }
+ }
+
private showSortMenu(type: string, sort: string) {
const clickEvent = (currentSort: string) => {
(type === "sort" ? this.tree : this.mTree).element.previousElementSibling.querySelector(`[data-type="${type}"]`).setAttribute("data-sort", currentSort);
diff --git a/app/src/layout/dock/Bookmark.ts b/app/src/layout/dock/Bookmark.ts
index 93c007ad8..e399c8a5b 100644
--- a/app/src/layout/dock/Bookmark.ts
+++ b/app/src/layout/dock/Bookmark.ts
@@ -13,7 +13,7 @@ import {escapeHtml} from "../../util/escape";
export class Bookmark extends Model {
private openNodes: string[];
- private tree: Tree;
+ public tree: Tree;
private element: Element;
constructor(tab: Tab) {
diff --git a/app/src/layout/dock/Outline.ts b/app/src/layout/dock/Outline.ts
index bccb573ed..7bfeaa324 100644
--- a/app/src/layout/dock/Outline.ts
+++ b/app/src/layout/dock/Outline.ts
@@ -13,7 +13,7 @@ import {unicode2Emoji} from "../../emoji";
import {onGet} from "../../protyle/util/onGet";
export class Outline extends Model {
- private tree: Tree;
+ public tree: Tree;
public element: HTMLElement;
public headerElement: HTMLElement;
public type: "pin" | "local";
diff --git a/app/src/layout/dock/Tag.ts b/app/src/layout/dock/Tag.ts
index 56b7b6c95..a8c486cc6 100644
--- a/app/src/layout/dock/Tag.ts
+++ b/app/src/layout/dock/Tag.ts
@@ -12,7 +12,7 @@ import {escapeHtml} from "../../util/escape";
export class Tag extends Model {
private openNodes: string[];
- private tree: Tree;
+ public tree: Tree;
private element: Element;
constructor(tab: Tab) {
diff --git a/app/src/layout/util.ts b/app/src/layout/util.ts
index 5da8ffa6e..da2f18397 100644
--- a/app/src/layout/util.ts
+++ b/app/src/layout/util.ts
@@ -541,7 +541,7 @@ export const copyTab = (tab: Tab) => {
});
};
-export const getInstanceById = (id: string) => {
+export const getInstanceById = (id: string, layout =window.siyuan.layout.centerLayout) => {
const _getInstanceById = (item: Layout | Wnd, id: string) => {
if (item.id === id) {
return item;
@@ -557,7 +557,7 @@ export const getInstanceById = (id: string) => {
}
}
};
- return _getInstanceById(window.siyuan.layout.centerLayout, id);
+ return _getInstanceById(layout, id);
};
export const addResize = (obj: Layout | Wnd) => {
diff --git a/app/src/protyle/gutter/index.ts b/app/src/protyle/gutter/index.ts
index 1c8e9c48e..1ae0ccf17 100644
--- a/app/src/protyle/gutter/index.ts
+++ b/app/src/protyle/gutter/index.ts
@@ -1842,7 +1842,8 @@ export class Gutter {
this.element.style.left = `${left}px`;
if (left < this.element.parentElement.getBoundingClientRect().left) {
this.element.style.width = "24px";
- this.element.style.left = `${rect.left - this.element.clientWidth - space / 2}px`;
+ // 需加 2,否则和折叠标题无法对齐
+ this.element.style.left = `${rect.left - this.element.clientWidth - space / 2 + 3}px`;
html = "";
Array.from(this.element.children).reverse().forEach((item, index) => {
if (index !== 0) {
diff --git a/app/src/search/util.ts b/app/src/search/util.ts
index 7064e1c09..30e539f33 100644
--- a/app/src/search/util.ts
+++ b/app/src/search/util.ts
@@ -1,5 +1,5 @@
import {getAllModels} from "../layout/getAll";
-import {getInstanceById, getWndByLayout, resizeTabs} from "../layout/util";
+import {getInstanceById, getWndByLayout, resizeTabs, setPanelFocus} from "../layout/util";
import {Tab} from "../layout/Tab";
import {Search} from "./index";
import {Wnd} from "../layout/Wnd";
@@ -78,6 +78,7 @@ export const openGlobalSearch = (text: string, replace: boolean) => {
}
});
wnd.split("lr").addTab(tab);
+ setPanelFocus(tab.panelElement);
};
export const genSearch = (config: ISearchOption, element: Element, closeCB?: () => void) => {
diff --git a/app/src/util/Tree.ts b/app/src/util/Tree.ts
index fe092b8d5..59729968b 100644
--- a/app/src/util/Tree.ts
+++ b/app/src/util/Tree.ts
@@ -11,10 +11,9 @@ export class Tree {
private blockExtHTML: string;
private topExtHTML: string;
- private click: (element: HTMLElement, event: MouseEvent) => void;
-
+ public click: (element: Element, event?: MouseEvent) => void;
private ctrlClick: (element: HTMLElement) => void;
- private toggleClick: (element: HTMLElement) => void;
+ private toggleClick: (element: Element) => void;
private shiftClick: (element: HTMLElement) => void;
private altClick: (element: HTMLElement) => void;
private rightClick: (element: HTMLElement, event: MouseEvent) => void;
@@ -83,8 +82,8 @@ data-treetype="${item.type}"
data-type="${item.nodeType}"
data-subtype="${item.subType}"
${item.label ? "data-label='" + item.label + "'" : ""}>
-
-
+
+
${iconHTML}
${item.name}
@@ -129,8 +128,8 @@ data-type="${item.type}"
data-subtype="${item.subType}"
data-treetype="${type}"
data-def-path="${item.defPath}">
-
-
+
+
${iconHTML}
${item.content}
@@ -144,7 +143,7 @@ data-def-path="${item.defPath}">
return html;
}
- private toggleBlocks(liElement: HTMLElement) {
+ public toggleBlocks(liElement: Element) {
if (this.toggleClick) {
this.toggleClick(liElement);
return;
@@ -194,7 +193,7 @@ data-def-path="${item.defPath}">
this.element.addEventListener("click", (event: MouseEvent & { target: HTMLElement }) => {
let target = event.target as HTMLElement;
while (target && !target.isEqualNode(this.element)) {
- if (target.classList.contains("b3-list-item__toggle") && !target.firstElementChild.classList.contains("fn__hidden")) {
+ if (target.classList.contains("b3-list-item__toggle") && !target.classList.contains("fn__hidden")) {
this.toggleBlocks(target.parentElement);
this.setCurrent(target.parentElement);
event.preventDefault();
diff --git a/app/src/util/globalShortcut.ts b/app/src/util/globalShortcut.ts
index e854009e0..732d9f30d 100644
--- a/app/src/util/globalShortcut.ts
+++ b/app/src/util/globalShortcut.ts
@@ -42,6 +42,8 @@ import {getStartEndElement} from "../protyle/wysiwyg/commonHotkey";
import {getNextFileLi, getPreviousFileLi} from "../protyle/wysiwyg/getBlock";
import {editor} from "../config/editor";
import {hintMoveBlock} from "../protyle/hint/extend";
+import {Outline} from "../layout/dock/Outline";
+import {Backlink} from "../layout/dock/Backlink";
const getRightBlock = (element: HTMLElement, x: number, y: number) => {
let index = 1;
@@ -599,33 +601,6 @@ export const globalShortcut = () => {
return;
}
- // 面板折叠展开操作
- if (!event.repeat && (matchHotKey(window.siyuan.config.keymap.editor.general.collapse.custom, event) || matchHotKey(window.siyuan.config.keymap.editor.general.expand.custom, event))) {
- let activePanelElement = document.querySelector(".layout__tab--active");
- if (!activePanelElement) {
- Array.from(document.querySelectorAll(".layout__wnd--active .layout-tab-container > div")).forEach(item => {
- if (!item.classList.contains("fn__none")) {
- activePanelElement = item;
- return true;
- }
- });
- }
- if (activePanelElement) {
- if (matchHotKey(window.siyuan.config.keymap.editor.general.collapse.custom, event)) {
- if (activePanelElement.querySelector('.block__icon[data-type="collapse"]')) {
- activePanelElement.querySelector('.block__icon[data-type="collapse"]').dispatchEvent(new CustomEvent("click"));
- }
- } else if (matchHotKey(window.siyuan.config.keymap.editor.general.expand.custom, event)) {
- if (activePanelElement.querySelector('.block__icon[data-type="expand"]')) {
- activePanelElement.querySelector('.block__icon[data-type="expand"]').dispatchEvent(new CustomEvent("click"));
- }
- }
- }
- event.stopPropagation();
- event.preventDefault();
- return;
- }
-
// close tab
if (matchHotKey(window.siyuan.config.keymap.general.closeTab.custom, event) && !event.repeat) {
event.preventDefault();
@@ -680,6 +655,11 @@ export const globalShortcut = () => {
return;
}
+ // 面板的操作
+ if (panelTreeKeydown(event)) {
+ return;
+ }
+
let searchKey = "";
if (matchHotKey(window.siyuan.config.keymap.general.replace.custom, event)) {
searchKey = window.siyuan.config.keymap.general.replace.custom;
@@ -1147,3 +1127,169 @@ const fileTreeKeydown = (event: KeyboardEvent) => {
return true;
}
};
+
+const panelTreeKeydown = (event: KeyboardEvent) => {
+ // 面板折叠展开操作
+ if (!matchHotKey(window.siyuan.config.keymap.editor.general.collapse.custom, event) &&
+ !matchHotKey(window.siyuan.config.keymap.editor.general.expand.custom, event) &&
+ !event.key.startsWith("Arrow") && event.key !== "Enter") {
+ return false;
+ }
+ let activePanelElement = document.querySelector(".layout__tab--active");
+ if (!activePanelElement) {
+ Array.from(document.querySelectorAll(".layout__wnd--active .layout-tab-container > div")).find(item => {
+ if (!item.classList.contains("fn__none") && item.className.indexOf("sy__") > -1) {
+ activePanelElement = item;
+ return true;
+ }
+ });
+ }
+ if (!activePanelElement) {
+ return false
+ }
+ if (activePanelElement.className.indexOf("sy__") === -1) {
+ return false;
+ }
+ if (!event.repeat && matchHotKey(window.siyuan.config.keymap.editor.general.collapse.custom, event)) {
+ const collapseElement = activePanelElement.querySelector('.block__icon[data-type="collapse"]');
+ if (collapseElement) {
+ collapseElement.dispatchEvent(new CustomEvent("click"));
+ event.preventDefault();
+ return true;
+ }
+ }
+ if (!event.repeat && matchHotKey(window.siyuan.config.keymap.editor.general.expand.custom, event)) {
+ const expandElement = activePanelElement.querySelector('.block__icon[data-type="expand"]');
+ if (expandElement) {
+ expandElement.dispatchEvent(new CustomEvent("click"));
+ event.preventDefault();
+ return true;
+ }
+ }
+ if (activePanelElement.classList.contains("sy__inbox") ||
+ activePanelElement.classList.contains("sy__globalGraph") ||
+ activePanelElement.classList.contains("sy__graph")) {
+ return false;
+ }
+ const model = (getInstanceById(activePanelElement.getAttribute("data-id"), window.siyuan.layout.layout) as Tab)?.model;
+ if (!model) {
+ return false;
+ }
+ let activeItemElement = activePanelElement.querySelector(".b3-list-item--focus")
+ if (!activeItemElement) {
+ activeItemElement = activePanelElement.querySelector(".b3-list .b3-list-item");
+ if (activeItemElement) {
+ activeItemElement.classList.add("b3-list-item--focus")
+ }
+ return false;
+ }
+
+ let tree = (model as Backlink).tree
+ if (activeItemElement.parentElement.parentElement.classList.contains("backlinkMList")) {
+ tree = (model as Backlink).mTree
+ }
+ if (event.key === "Enter") {
+ tree.click(activeItemElement);
+ event.preventDefault();
+ return true;
+ }
+ const arrowElement = activeItemElement.querySelector(".b3-list-item__arrow")
+ if ((event.key === "ArrowRight" && !arrowElement.classList.contains("b3-list-item__arrow--open") && !arrowElement.parentElement.classList.contains("fn__hidden")) ||
+ (event.key === "ArrowLeft" && arrowElement.classList.contains("b3-list-item__arrow--open") && !arrowElement.parentElement.classList.contains("fn__hidden"))) {
+ tree.toggleBlocks(activeItemElement);
+ event.preventDefault();
+ return true;
+ }
+ const ulElement = hasClosestByClassName(activeItemElement, "b3-list");
+ if (!ulElement) {
+ return false;
+ }
+ if (event.key === "ArrowLeft") {
+ let parentElement = activeItemElement.parentElement.previousElementSibling;
+ if (parentElement) {
+ if (parentElement.tagName !== "LI") {
+ parentElement = ulElement.querySelector(".b3-list-item");
+ }
+ activeItemElement.classList.remove("b3-list-item--focus");
+ parentElement.classList.add("b3-list-item--focus");
+ const parentRect = parentElement.getBoundingClientRect();
+ const scrollRect = ulElement.parentElement.getBoundingClientRect();
+ if (parentRect.top < scrollRect.top || parentRect.bottom > scrollRect.bottom) {
+ parentElement.scrollIntoView(parentRect.top < scrollRect.top);
+ }
+ }
+ event.preventDefault();
+ return true;
+ }
+ if (event.key === "ArrowDown" || event.key === "ArrowRight") {
+ let nextElement = activeItemElement;
+ while (nextElement) {
+ if (nextElement.nextElementSibling) {
+ if (nextElement.nextElementSibling.tagName === "UL") {
+ nextElement = nextElement.nextElementSibling.firstElementChild;
+ } else if (nextElement.nextElementSibling.classList.contains("protyle")) {
+ if (nextElement.nextElementSibling.nextElementSibling) {
+ nextElement = nextElement.nextElementSibling.nextElementSibling;
+ }
+ } else {
+ nextElement = nextElement.nextElementSibling;
+ }
+ break;
+ } else {
+ if (nextElement.parentElement.classList.contains("fn__flex-1")) {
+ break;
+ } else {
+ nextElement = nextElement.parentElement;
+ }
+ }
+ }
+ if (nextElement.classList.contains("b3-list-item") && !nextElement.classList.contains("b3-list-item--focus")) {
+ activeItemElement.classList.remove("b3-list-item--focus");
+ nextElement.classList.add("b3-list-item--focus");
+ const nextRect = nextElement.getBoundingClientRect();
+ const scrollRect = ulElement.parentElement.getBoundingClientRect();
+ if (nextRect.top < scrollRect.top || nextRect.bottom > scrollRect.bottom) {
+ nextElement.scrollIntoView(nextRect.top < scrollRect.top);
+ }
+ }
+ event.preventDefault();
+ return true;
+ }
+ if (event.key === "ArrowUp") {
+ let previousElement = activeItemElement;
+ while (previousElement) {
+ if (previousElement.previousElementSibling) {
+ if (previousElement.previousElementSibling.tagName === "LI") {
+ previousElement = previousElement.previousElementSibling;
+ } else if (previousElement.previousElementSibling.classList.contains("protyle")) {
+ if (previousElement.previousElementSibling.previousElementSibling) {
+ previousElement = previousElement.previousElementSibling.previousElementSibling;
+ }
+ } else {
+ const liElements = previousElement.previousElementSibling.querySelectorAll(".b3-list-item");
+ previousElement = liElements[liElements.length - 1];
+ }
+ break;
+ } else {
+ if (previousElement.parentElement.classList.contains("fn__flex-1")) {
+ break;
+ } else {
+ previousElement = previousElement.parentElement;
+ }
+ }
+ }
+ if (previousElement.classList.contains("b3-list-item") && !previousElement.classList.contains("b3-list-item--focus")) {
+ activeItemElement.classList.remove("b3-list-item--focus");
+ previousElement.classList.add("b3-list-item--focus");
+ const previousRect = previousElement.getBoundingClientRect();
+ const scrollRect = ulElement.parentElement.getBoundingClientRect();
+ if (previousRect.top < scrollRect.top || previousRect.bottom > scrollRect.bottom) {
+ previousElement.scrollIntoView(previousRect.top < scrollRect.top);
+ }
+ }
+ event.preventDefault();
+ return true;
+ }
+ return false
+}
+