diff --git a/app/src/assets/scss/component/_form.scss b/app/src/assets/scss/component/_form.scss
index ce997c6a0..ef175612f 100644
--- a/app/src/assets/scss/component/_form.scss
+++ b/app/src/assets/scss/component/_form.scss
@@ -19,6 +19,15 @@
width: 16px;
}
+ &-list {
+ height: 28px;
+ width: 42px;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ position: absolute;
+ }
+
&-input {
padding-left: 35px !important;
}
diff --git a/app/src/constants.ts b/app/src/constants.ts
index 6107173a0..5ca1697b8 100644
--- a/app/src/constants.ts
+++ b/app/src/constants.ts
@@ -124,6 +124,7 @@ export abstract class Constants {
public static readonly LOCAL_PLUGIN_DOCKS = "local-plugin-docks";
public static readonly LOCAL_IMAGES = "local-images";
public static readonly LOCAL_EMOJIS = "local-emojis";
+ public static readonly LOCAL_MOVE_PATH = "local-move-path";
// dialog
public static readonly DIALOG_CONFIRM = "dialog-confirm";
diff --git a/app/src/protyle/render/av/addToDatabase.ts b/app/src/protyle/render/av/addToDatabase.ts
index 3254f7244..060f86861 100644
--- a/app/src/protyle/render/av/addToDatabase.ts
+++ b/app/src/protyle/render/av/addToDatabase.ts
@@ -34,7 +34,7 @@ export const addFilesToDatabase = (fileLiElements: Element[]) => {
};
export const addEditorToDatabase = (protyle: IProtyle, range: Range, type?: string) => {
- if (protyle.title?.editElement?.contains(range.startContainer) || type === "title") {
+ if ((range && protyle.title?.editElement?.contains(range.startContainer)) || type === "title") {
openSearchAV("", protyle.breadcrumb.element, (listItemElement) => {
const avID = listItemElement.dataset.avId;
transaction(protyle, [{
diff --git a/app/src/protyle/util/compatibility.ts b/app/src/protyle/util/compatibility.ts
index 223f6ffeb..c8c446a92 100644
--- a/app/src/protyle/util/compatibility.ts
+++ b/app/src/protyle/util/compatibility.ts
@@ -300,6 +300,7 @@ export const getLocalStorage = (cb: () => void) => {
replaceTypes: Object.assign({}, Constants.SIYUAN_DEFAULT_REPLACETYPES),
};
defaultStorage[Constants.LOCAL_ZOOM] = 1;
+ defaultStorage[Constants.LOCAL_MOVE_PATH] = {keys: [], k: ""};
[Constants.LOCAL_EXPORTIMG, Constants.LOCAL_SEARCHKEYS, Constants.LOCAL_PDFTHEME, Constants.LOCAL_BAZAAR,
Constants.LOCAL_EXPORTWORD, Constants.LOCAL_EXPORTPDF, Constants.LOCAL_DOCINFO, Constants.LOCAL_FONTSTYLES,
@@ -307,7 +308,7 @@ export const getLocalStorage = (cb: () => void) => {
Constants.LOCAL_PLUGINTOPUNPIN, Constants.LOCAL_SEARCHASSET, Constants.LOCAL_FLASHCARD,
Constants.LOCAL_DIALOGPOSITION, Constants.LOCAL_SEARCHUNREF, Constants.LOCAL_HISTORY,
Constants.LOCAL_OUTLINE, Constants.LOCAL_FILEPOSITION, Constants.LOCAL_FILESPATHS, Constants.LOCAL_IMAGES,
- Constants.LOCAL_PLUGIN_DOCKS, Constants.LOCAL_EMOJIS].forEach((key) => {
+ Constants.LOCAL_PLUGIN_DOCKS, Constants.LOCAL_EMOJIS, Constants.LOCAL_MOVE_PATH].forEach((key) => {
if (typeof response.data[key] === "string") {
try {
const parseData = JSON.parse(response.data[key]);
diff --git a/app/src/util/pathName.ts b/app/src/util/pathName.ts
index 2565d3740..23af451b4 100644
--- a/app/src/util/pathName.ts
+++ b/app/src/util/pathName.ts
@@ -10,7 +10,10 @@ import {Constants} from "../constants";
import {ipcRenderer} from "electron";
/// #endif
import {showMessage} from "../dialog/message";
-import {isOnlyMeta} from "../protyle/util/compatibility";
+import {isOnlyMeta, setStorageVal, updateHotkeyTip} from "../protyle/util/compatibility";
+import {matchHotKey} from "../protyle/util/hotKey";
+import {Menu} from "../plugin/Menu";
+import {hasClosestByClassName} from "../protyle/util/hasClosest";
export const showFileInFolder = (filePath: string) => {
/// #if !BROWSER
@@ -154,8 +157,11 @@ export const movePathTo = (cb: (toPath: string[], toNotebook: string[]) => void,
title: `${title || window.siyuan.languages.move}
`,
content: `
-
-
+
+
+
+
+
@@ -250,6 +256,75 @@ export const movePathTo = (cb: (toPath: string[], toNotebook: string[]) => void,
searchListElement.innerHTML = fileHTML;
});
};
+
+ const toggleMovePathHistory = () => {
+ const keys = window.siyuan.storage[Constants.LOCAL_MOVE_PATH].keys;
+ if (!keys || keys.length === 0) {
+ return;
+ }
+ const menu = new Menu("move-path-history");
+ if (menu.isOpen) {
+ return;
+ }
+ menu.element.classList.add("b3-menu--list");
+ menu.addItem({
+ iconHTML: "",
+ label: window.siyuan.languages.clearHistory,
+ click() {
+ window.siyuan.storage[Constants.LOCAL_MOVE_PATH].keys = [];
+ setStorageVal(Constants.LOCAL_MOVE_PATH, window.siyuan.storage[Constants.LOCAL_MOVE_PATH]);
+ }
+ });
+ const separatorElement = menu.addSeparator(1);
+ let current = true;
+ keys.forEach((s: string) => {
+ if (s !== inputElement.value && s) {
+ const menuItem = menu.addItem({
+ iconHTML: "",
+ label: escapeHtml(s),
+ action: "iconCloseRound",
+ bind(element) {
+ element.addEventListener("click", (itemEvent) => {
+ if (hasClosestByClassName(itemEvent.target as Element, "b3-menu__action")) {
+ keys.find((item: string, index: number) => {
+ if (item === s) {
+ keys.splice(index, 1);
+ return true;
+ }
+ });
+ window.siyuan.storage[Constants.LOCAL_MOVE_PATH].keys = keys;
+ setStorageVal(Constants.LOCAL_MOVE_PATH, window.siyuan.storage[Constants.LOCAL_MOVE_PATH]);
+ if (element.previousElementSibling?.classList.contains("b3-menu__separator") && !element.nextElementSibling) {
+ window.siyuan.menus.menu.remove();
+ } else {
+ element.remove();
+ }
+ } else {
+ inputElement.value = element.textContent;
+ inputEvent();
+ window.siyuan.menus.menu.remove();
+ }
+ itemEvent.preventDefault();
+ itemEvent.stopPropagation();
+ });
+ }
+ });
+ if (current) {
+ menuItem.classList.add("b3-menu__item--current");
+ }
+ current = false;
+ }
+ });
+ if (current) {
+ separatorElement.remove();
+ }
+ const rect = inputElement.getBoundingClientRect();
+ menu.open({
+ x: rect.left,
+ y: rect.bottom
+ });
+ }
+ inputElement.value = window.siyuan.storage[Constants.LOCAL_MOVE_PATH].k;
inputEvent();
inputElement.addEventListener("compositionend", (event: InputEvent) => {
inputEvent(event);
@@ -257,11 +332,33 @@ export const movePathTo = (cb: (toPath: string[], toNotebook: string[]) => void,
inputElement.addEventListener("input", (event: InputEvent) => {
inputEvent(event);
});
+ inputElement.addEventListener("blur", () => {
+ if (!inputElement.value) {
+ return;
+ }
+ let list: string[] = window.siyuan.storage[Constants.LOCAL_MOVE_PATH].keys;
+ list.splice(0, 0, inputElement.value);
+ list = Array.from(new Set(list));
+ if (list.length > window.siyuan.config.search.limit) {
+ list.splice(window.siyuan.config.search.limit, list.length - window.siyuan.config.search.limit);
+ }
+ window.siyuan.storage[Constants.LOCAL_MOVE_PATH].k = inputElement.value;
+ window.siyuan.storage[Constants.LOCAL_MOVE_PATH].keys = list;
+ setStorageVal(Constants.LOCAL_MOVE_PATH, window.siyuan.storage[Constants.LOCAL_MOVE_PATH]);
+ });
const lineHeight = 28;
inputElement.addEventListener("keydown", (event: KeyboardEvent) => {
if (event.isComposing) {
return;
}
+ if (matchHotKey("⌥↓", event)) {
+ event.stopPropagation();
+ toggleMovePathHistory();
+ return;
+ }
+ if (window.siyuan.menus.menu.element.getAttribute("data-name") === "move-path-history") {
+ return
+ }
const currentPanelElement = searchListElement.classList.contains("fn__none") ? searchTreeElement : searchListElement;
const currentItemElements = currentPanelElement.querySelectorAll(".b3-list-item--focus");
if (currentItemElements.length === 0) {
@@ -424,6 +521,11 @@ export const movePathTo = (cb: (toPath: string[], toNotebook: string[]) => void,
event.preventDefault();
event.stopPropagation();
break;
+ } else if (target.classList.contains("b3-form__icon-list")) {
+ toggleMovePathHistory();
+ event.preventDefault();
+ event.stopPropagation();
+ break;
} else if (target.classList.contains("b3-button--text")) {
const currentPanelElement = searchListElement.classList.contains("fn__none") ? searchTreeElement : searchListElement;
const currentItemElements = currentPanelElement.querySelectorAll(".b3-list-item--focus");