Bläddra i källkod

:art: https://github.com/siyuan-note/siyuan/issues/12335

Vanessa 7 månader sedan
förälder
incheckning
b60f84fe09

+ 9 - 0
app/src/assets/scss/component/_form.scss

@@ -19,6 +19,15 @@
       width: 16px;
       width: 16px;
     }
     }
 
 
+    &-list {
+      height: 28px;
+      width: 42px;
+      display: flex;
+      justify-content: center;
+      align-items: center;
+      position: absolute;
+    }
+
     &-input {
     &-input {
       padding-left: 35px !important;
       padding-left: 35px !important;
     }
     }

+ 1 - 0
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_PLUGIN_DOCKS = "local-plugin-docks";
     public static readonly LOCAL_IMAGES = "local-images";
     public static readonly LOCAL_IMAGES = "local-images";
     public static readonly LOCAL_EMOJIS = "local-emojis";
     public static readonly LOCAL_EMOJIS = "local-emojis";
+    public static readonly LOCAL_MOVE_PATH = "local-move-path";
 
 
     // dialog
     // dialog
     public static readonly DIALOG_CONFIRM = "dialog-confirm";
     public static readonly DIALOG_CONFIRM = "dialog-confirm";

+ 1 - 1
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) => {
 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) => {
         openSearchAV("", protyle.breadcrumb.element, (listItemElement) => {
             const avID = listItemElement.dataset.avId;
             const avID = listItemElement.dataset.avId;
             transaction(protyle, [{
             transaction(protyle, [{

+ 2 - 1
app/src/protyle/util/compatibility.ts

@@ -300,6 +300,7 @@ export const getLocalStorage = (cb: () => void) => {
             replaceTypes: Object.assign({}, Constants.SIYUAN_DEFAULT_REPLACETYPES),
             replaceTypes: Object.assign({}, Constants.SIYUAN_DEFAULT_REPLACETYPES),
         };
         };
         defaultStorage[Constants.LOCAL_ZOOM] = 1;
         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_EXPORTIMG, Constants.LOCAL_SEARCHKEYS, Constants.LOCAL_PDFTHEME, Constants.LOCAL_BAZAAR,
             Constants.LOCAL_EXPORTWORD, Constants.LOCAL_EXPORTPDF, Constants.LOCAL_DOCINFO, Constants.LOCAL_FONTSTYLES,
             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_PLUGINTOPUNPIN, Constants.LOCAL_SEARCHASSET, Constants.LOCAL_FLASHCARD,
             Constants.LOCAL_DIALOGPOSITION, Constants.LOCAL_SEARCHUNREF, Constants.LOCAL_HISTORY,
             Constants.LOCAL_DIALOGPOSITION, Constants.LOCAL_SEARCHUNREF, Constants.LOCAL_HISTORY,
             Constants.LOCAL_OUTLINE, Constants.LOCAL_FILEPOSITION, Constants.LOCAL_FILESPATHS, Constants.LOCAL_IMAGES,
             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") {
             if (typeof response.data[key] === "string") {
                 try {
                 try {
                     const parseData = JSON.parse(response.data[key]);
                     const parseData = JSON.parse(response.data[key]);

+ 105 - 3
app/src/util/pathName.ts

@@ -10,7 +10,10 @@ import {Constants} from "../constants";
 import {ipcRenderer} from "electron";
 import {ipcRenderer} from "electron";
 /// #endif
 /// #endif
 import {showMessage} from "../dialog/message";
 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) => {
 export const showFileInFolder = (filePath: string) => {
     /// #if !BROWSER
     /// #if !BROWSER
@@ -154,8 +157,11 @@ export const movePathTo = (cb: (toPath: string[], toNotebook: string[]) => void,
         title: `${title || window.siyuan.languages.move}
         title: `${title || window.siyuan.languages.move}
 <div style="max-height: 16px;overflow: auto;line-height: 14px;-webkit-mask-image: linear-gradient(to top, rgba(0, 0, 0, 0) 0, #000 6px);padding-bottom: 4px;margin-bottom: -4px" class="ft__smaller ft__on-surface fn__hidescrollbar"></div>`,
 <div style="max-height: 16px;overflow: auto;line-height: 14px;-webkit-mask-image: linear-gradient(to top, rgba(0, 0, 0, 0) 0, #000 6px);padding-bottom: 4px;margin-bottom: -4px" class="ft__smaller ft__on-surface fn__hidescrollbar"></div>`,
         content: `<div class="b3-form__icon" style="margin: 8px">
         content: `<div class="b3-form__icon" style="margin: 8px">
-    <svg class="b3-form__icon-icon"><use xlink:href="#iconSearch"></use></svg>
-    <input class="b3-text-field fn__block b3-form__icon-input" value="" placeholder="${window.siyuan.languages.search}">
+    <span data-menu="true" class="b3-form__icon-list fn__a b3-tooltips b3-tooltips__s" aria-label="${updateHotkeyTip("⌥↓")}">
+        <svg class="svg--mid"><use xlink:href="#iconSearch"></use></svg>
+        <svg class="svg--smaller"><use xlink:href="#iconDown"></use></svg>
+    </span>
+    <input class="b3-text-field fn__block" style="padding-left: 42px;" value="" placeholder="${window.siyuan.languages.search}">
 </div>
 </div>
 <ul id="foldList" class="fn__flex-1 fn__none b3-list b3-list--background${isMobile() ? " b3-list--mobile" : ""}" style="overflow: auto;position: relative"></ul>
 <ul id="foldList" class="fn__flex-1 fn__none b3-list b3-list--background${isMobile() ? " b3-list--mobile" : ""}" style="overflow: auto;position: relative"></ul>
 <div id="foldTree" class="fn__flex-1${isMobile() ? " b3-list--mobile" : ""}" style="overflow: auto;position: relative"></div>
 <div id="foldTree" class="fn__flex-1${isMobile() ? " b3-list--mobile" : ""}" style="overflow: auto;position: relative"></div>
@@ -250,6 +256,75 @@ export const movePathTo = (cb: (toPath: string[], toNotebook: string[]) => void,
             searchListElement.innerHTML = fileHTML;
             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();
     inputEvent();
     inputElement.addEventListener("compositionend", (event: InputEvent) => {
     inputElement.addEventListener("compositionend", (event: InputEvent) => {
         inputEvent(event);
         inputEvent(event);
@@ -257,11 +332,33 @@ export const movePathTo = (cb: (toPath: string[], toNotebook: string[]) => void,
     inputElement.addEventListener("input", (event: InputEvent) => {
     inputElement.addEventListener("input", (event: InputEvent) => {
         inputEvent(event);
         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;
     const lineHeight = 28;
     inputElement.addEventListener("keydown", (event: KeyboardEvent) => {
     inputElement.addEventListener("keydown", (event: KeyboardEvent) => {
         if (event.isComposing) {
         if (event.isComposing) {
             return;
             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 currentPanelElement = searchListElement.classList.contains("fn__none") ? searchTreeElement : searchListElement;
         const currentItemElements = currentPanelElement.querySelectorAll(".b3-list-item--focus");
         const currentItemElements = currentPanelElement.querySelectorAll(".b3-list-item--focus");
         if (currentItemElements.length === 0) {
         if (currentItemElements.length === 0) {
@@ -424,6 +521,11 @@ export const movePathTo = (cb: (toPath: string[], toNotebook: string[]) => void,
                 event.preventDefault();
                 event.preventDefault();
                 event.stopPropagation();
                 event.stopPropagation();
                 break;
                 break;
+            } else if (target.classList.contains("b3-form__icon-list")) {
+                toggleMovePathHistory();
+                event.preventDefault();
+                event.stopPropagation();
+                break;
             } else if (target.classList.contains("b3-button--text")) {
             } else if (target.classList.contains("b3-button--text")) {
                 const currentPanelElement = searchListElement.classList.contains("fn__none") ? searchTreeElement : searchListElement;
                 const currentPanelElement = searchListElement.classList.contains("fn__none") ? searchTreeElement : searchListElement;
                 const currentItemElements = currentPanelElement.querySelectorAll(".b3-list-item--focus");
                 const currentItemElements = currentPanelElement.querySelectorAll(".b3-list-item--focus");