diff --git a/app/appearance/icons/ant/icon.js b/app/appearance/icons/ant/icon.js index eb50015bc..e8d9caa90 100644 --- a/app/appearance/icons/ant/icon.js +++ b/app/appearance/icons/ant/icon.js @@ -1,5 +1,8 @@ document.body.insertAdjacentHTML('afterbegin', ` + + + diff --git a/app/appearance/icons/ant/icon.json b/app/appearance/icons/ant/icon.json index 2a50be321..2b3753c34 100644 --- a/app/appearance/icons/ant/icon.json +++ b/app/appearance/icons/ant/icon.json @@ -2,5 +2,5 @@ "name": "ant", "author": "Vanessa", "url": "https://github.com/Vanessa219", - "version": "1.29.0" + "version": "1.30.0" } diff --git a/app/appearance/icons/index.html b/app/appearance/icons/index.html index ab6f96538..115c39a7a 100644 --- a/app/appearance/icons/index.html +++ b/app/appearance/icons/index.html @@ -34,6 +34,12 @@ iconSoftWrap +
+ + + + iconLinkOff +
diff --git a/app/appearance/icons/material/icon.js b/app/appearance/icons/material/icon.js index b42561142..ec8d9995d 100644 --- a/app/appearance/icons/material/icon.js +++ b/app/appearance/icons/material/icon.js @@ -1,5 +1,8 @@ document.body.insertAdjacentHTML('afterbegin', ` + + + diff --git a/app/appearance/icons/material/icon.json b/app/appearance/icons/material/icon.json index 0c22a99ae..65945dddc 100644 --- a/app/appearance/icons/material/icon.json +++ b/app/appearance/icons/material/icon.json @@ -2,5 +2,5 @@ "name": "material", "author": "Vanessa", "url": "https://github.com/Vanessa219", - "version": "1.29.0" + "version": "1.30.0" } diff --git a/app/src/constants.ts b/app/src/constants.ts index 76dbd7021..f519d3cdd 100644 --- a/app/src/constants.ts +++ b/app/src/constants.ts @@ -96,6 +96,7 @@ export abstract class Constants { public static readonly LOCAL_SEARCHDATA = "local-searchdata"; public static readonly LOCAL_SEARCHKEYS = "local-searchkeys"; public static readonly LOCAL_SEARCHASSET = "local-searchasset"; + public static readonly LOCAL_SEARCHUNREF = "local-searchunref"; public static readonly LOCAL_DOCINFO = "local-docinfo"; // only mobile public static readonly LOCAL_DAILYNOTEID = "local-dailynoteid"; // string public static readonly LOCAL_HISTORYNOTEID = "local-historynoteid"; // string diff --git a/app/src/protyle/util/compatibility.ts b/app/src/protyle/util/compatibility.ts index 81fc9ebbe..a3b5f7f22 100644 --- a/app/src/protyle/util/compatibility.ts +++ b/app/src/protyle/util/compatibility.ts @@ -166,6 +166,11 @@ export const getLocalStorage = (cb: () => void) => { sort: 0, k: "", }; + defaultStorage[Constants.LOCAL_SEARCHUNREF] = { + col: "", + row: "", + layout: 0, + }; Constants.SIYUAN_ASSETS_SEARCH.forEach(type => { defaultStorage[Constants.LOCAL_SEARCHASSET].types[type] = true; }); @@ -250,7 +255,8 @@ export const getLocalStorage = (cb: () => void) => { [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_SEARCHDATA, Constants.LOCAL_ZOOM, Constants.LOCAL_LAYOUTS, Constants.LOCAL_AI, - Constants.LOCAL_PLUGINTOPUNPIN, Constants.LOCAL_SEARCHASSET, Constants.LOCAL_FLASHCARD, Constants.LOCAL_DIALOGPOSITION, + Constants.LOCAL_PLUGINTOPUNPIN, Constants.LOCAL_SEARCHASSET, Constants.LOCAL_FLASHCARD, + Constants.LOCAL_DIALOGPOSITION, Constants.LOCAL_SEARCHUNREF, Constants.LOCAL_OUTLINE, Constants.LOCAL_FILEPOSITION].forEach((key) => { if (typeof response.data[key] === "string") { try { diff --git a/app/src/search/assets.ts b/app/src/search/assets.ts index 8ebe55246..a77cec64a 100644 --- a/app/src/search/assets.ts +++ b/app/src/search/assets.ts @@ -23,8 +23,7 @@ export const openSearchAsset = (element: Element, isStick: boolean) => { return; } const localSearch = window.siyuan.storage[Constants.LOCAL_SEARCHASSET] as ISearchAssetOption; - const loadingElement = element.nextElementSibling; - loadingElement.classList.remove("fn__none"); + element.parentElement.querySelector(".fn__loading--top").classList.remove("fn__none"); let enterTip = ""; /// #if !BROWSER enterTip = `Enter/Double Click ${window.siyuan.languages.showInFolder}`; @@ -171,8 +170,9 @@ export const openSearchAsset = (element: Element, isStick: boolean) => { let inputTimeout: number; export const assetInputEvent = (element: Element, localSearch?: ISearchAssetOption, page = 1) => { + const loadingElement = element.parentElement.querySelector(".fn__loading--top"); if (!isPaidUser()) { - element.nextElementSibling.classList.add("fn__none"); + loadingElement.classList.add("fn__none"); element.querySelector(".search__drag")?.classList.add("fn__none"); element.querySelector("#searchAssetPreview").classList.add("fn__none"); element.querySelector("#searchAssetList").innerHTML = `
@@ -180,7 +180,7 @@ export const assetInputEvent = (element: Element, localSearch?: ISearchAssetOpti
`; return; } - element.nextElementSibling.classList.remove("fn__none"); + loadingElement.classList.remove("fn__none"); clearTimeout(inputTimeout); inputTimeout = window.setTimeout(() => { if (!localSearch) { @@ -200,7 +200,7 @@ export const assetInputEvent = (element: Element, localSearch?: ISearchAssetOpti method: localSearch.method, orderBy: localSearch.sort }, (response) => { - element.nextElementSibling.classList.add("fn__none"); + loadingElement.classList.add("fn__none"); const nextElement = element.querySelector('[data-type="assetNext"]'); if (page < response.data.pageCount) { nextElement.removeAttribute("disabled"); @@ -528,7 +528,7 @@ export const assetMoreMenu = (target: Element, element: Element, cb: () => void) showMessage(window.siyuan.languages["_kernel"][214]); return; } - element.nextElementSibling.classList.remove("fn__none"); + element.parentElement.querySelector(".fn__loading--top").classList.remove("fn__none"); fetchPost("/api/asset/fullReindexAssetContent", {}, () => { assetInputEvent(element, localData); }); diff --git a/app/src/search/unRef.ts b/app/src/search/unRef.ts new file mode 100644 index 000000000..8e5d41dda --- /dev/null +++ b/app/src/search/unRef.ts @@ -0,0 +1,253 @@ +import {Constants} from "../constants"; +import {fetchPost} from "../util/fetch"; +import {setStorageVal, updateHotkeyTip} from "../protyle/util/compatibility"; +/// #if !MOBILE +import {getQueryTip} from "./util"; +/// #endif +import {MenuItem} from "../menus/Menu"; +import {Dialog} from "../dialog"; +import {Menu} from "../plugin/Menu"; +import {hasClosestByClassName} from "../protyle/util/hasClosest"; +import {addClearButton} from "../util/addClearButton"; +import {isPaidUser} from "../util/needSubscribe"; +import {showMessage} from "../dialog/message"; + +export const openSearchUnRef = (element: Element, isStick: boolean) => { + /// #if !MOBILE + window.siyuan.menus.menu.remove(); + element.previousElementSibling.previousElementSibling.classList.add("fn__none"); + element.classList.remove("fn__none"); + if (element.innerHTML) { + return; + } + const localSearch = window.siyuan.storage[Constants.LOCAL_SEARCHUNREF] as ISearchAssetOption; + const loadingElement = element.parentElement.querySelector(".fn__loading--top"); + loadingElement.classList.remove("fn__none"); + let enterTip = ""; + /// #if !BROWSER + enterTip = `Enter/Double Click ${window.siyuan.languages.showInFolder}`; + /// #endif + element.innerHTML = `
+ + + + + + + + + + + + + + +
+
+
+
+
+
+
+ ↑/↓/PageUp/PageDown ${window.siyuan.languages.searchTip1} + ${enterTip} + Click ${window.siyuan.languages.searchTip3} + Esc ${window.siyuan.languages.searchTip5} +
`; + if (element.querySelector("#searchUnRefList").innerHTML !== "") { + return; + } + const previewElement = element.querySelector("#searchUnRefPreview") as HTMLElement; + if (localSearch.layout === 1) { + if (localSearch.col) { + previewElement.style.width = localSearch.col; + previewElement.classList.remove("fn__flex-1"); + } + } else { + if (localSearch.row) { + previewElement.classList.remove("fn__flex-1"); + previewElement.style.height = localSearch.row; + } + } + + const dragElement = element.querySelector(".search__drag"); + dragElement.addEventListener("mousedown", (event: MouseEvent) => { + const documentSelf = document; + const nextElement = dragElement.nextElementSibling as HTMLElement; + const previousElement = dragElement.previousElementSibling as HTMLElement; + const direction = localSearch.layout === 1 ? "lr" : "tb"; + const x = event[direction === "lr" ? "clientX" : "clientY"]; + const previousSize = direction === "lr" ? previousElement.clientWidth : previousElement.clientHeight; + const nextSize = direction === "lr" ? nextElement.clientWidth : nextElement.clientHeight; + + nextElement.classList.remove("fn__flex-1"); + nextElement.style[direction === "lr" ? "width" : "height"] = nextSize + "px"; + + documentSelf.onmousemove = (moveEvent: MouseEvent) => { + moveEvent.preventDefault(); + moveEvent.stopPropagation(); + const previousNowSize = (previousSize + (moveEvent[direction === "lr" ? "clientX" : "clientY"] - x)); + const nextNowSize = (nextSize - (moveEvent[direction === "lr" ? "clientX" : "clientY"] - x)); + if (previousNowSize < 120 || nextNowSize < 120) { + return; + } + nextElement.style[direction === "lr" ? "width" : "height"] = nextNowSize + "px"; + }; + + documentSelf.onmouseup = () => { + documentSelf.onmousemove = null; + documentSelf.onmouseup = null; + documentSelf.ondragstart = null; + documentSelf.onselectstart = null; + documentSelf.onselect = null; + window.siyuan.storage[Constants.LOCAL_SEARCHUNREF][direction === "lr" ? "col" : "row"] = nextElement[direction === "lr" ? "clientWidth" : "clientHeight"] + "px"; + setStorageVal(Constants.LOCAL_SEARCHUNREF, window.siyuan.storage[Constants.LOCAL_SEARCHUNREF]); + }; + }); + /// #endif +}; + +export const renderPreview = (element: Element, id: string, query: string, queryMethod: number) => { + fetchPost("/api/search/getAssetContent", {id, query, queryMethod}, (response) => { + element.innerHTML = `

${response.data.assetContent.content}

`; + const matchElement = element.querySelector("mark"); + if (matchElement) { + matchElement.classList.add("mark--hl"); + const contentRect = element.getBoundingClientRect(); + element.scrollTop = element.scrollTop + matchElement.getBoundingClientRect().top - contentRect.top - contentRect.height / 2; + } + }); +}; + +export const renderNextAssetMark = (element: Element) => { + let matchElement; + const allMatchElements = Array.from(element.querySelectorAll("mark")); + allMatchElements.find((item, itemIndex) => { + if (item.classList.contains("mark--hl")) { + item.classList.remove("mark--hl"); + matchElement = allMatchElements[itemIndex + 1]; + return; + } + }); + if (!matchElement) { + matchElement = allMatchElements[0]; + } + if (matchElement) { + matchElement.classList.add("mark--hl"); + const contentRect = element.getBoundingClientRect(); + element.scrollTop = element.scrollTop + matchElement.getBoundingClientRect().top - contentRect.top - contentRect.height / 2; + } +}; + + +export const assetMoreMenu = (target: Element, element: Element, cb: () => void) => { + if (!window.siyuan.menus.menu.element.classList.contains("fn__none") && + window.siyuan.menus.menu.element.getAttribute("data-name") === "searchAssetMore") { + window.siyuan.menus.menu.remove(); + return; + } + window.siyuan.menus.menu.remove(); + window.siyuan.menus.menu.element.setAttribute("data-name", "searchAssetMore"); + const localData = window.siyuan.storage[Constants.LOCAL_SEARCHUNREF]; + const sortMenu = [{ + iconHTML: "", + label: window.siyuan.languages.sortByRankAsc, + current: localData.sort === 1, + click() { + localData.sort = 1; + cb(); + } + }, { + iconHTML: "", + label: window.siyuan.languages.sortByRankDesc, + current: localData.sort === 0, + click() { + localData.sort = 0; + cb(); + } + }, { + iconHTML: "", + label: window.siyuan.languages.modifiedASC, + current: localData.sort === 3, + click() { + localData.sort = 3; + cb(); + } + }, { + iconHTML: "", + label: window.siyuan.languages.modifiedDESC, + current: localData.sort === 2, + click() { + localData.sort = 2; + cb(); + } + }]; + window.siyuan.menus.menu.append(new MenuItem({ + iconHTML: "", + label: window.siyuan.languages.sort, + type: "submenu", + submenu: sortMenu, + }).element); + /// #if !MOBILE + window.siyuan.menus.menu.append(new MenuItem({ + iconHTML: "", + label: window.siyuan.languages.layout, + type: "submenu", + submenu: [{ + iconHTML: "", + label: window.siyuan.languages.topBottomLayout, + current: localData.layout === 0, + click() { + element.querySelector(".search__layout").classList.remove("search__layout--row"); + const previewElement = element.querySelector("#searchAssetPreview") as HTMLElement; + previewElement.style.width = ""; + if (localData.row) { + previewElement.style.height = localData.row; + previewElement.classList.remove("fn__flex-1"); + } else { + previewElement.classList.add("fn__flex-1"); + } + localData.layout = 0; + setStorageVal(Constants.LOCAL_SEARCHUNREF, window.siyuan.storage[Constants.LOCAL_SEARCHUNREF]); + } + }, { + iconHTML: "", + label: window.siyuan.languages.leftRightLayout, + current: localData.layout === 1, + click() { + const previewElement = element.querySelector("#searchAssetPreview") as HTMLElement; + element.querySelector(".search__layout").classList.add("search__layout--row"); + previewElement.style.height = ""; + if (localData.col) { + previewElement.style.width = localData.col; + previewElement.classList.remove("fn__flex-1"); + } else { + previewElement.classList.add("fn__flex-1"); + } + localData.layout = 1; + setStorageVal(Constants.LOCAL_SEARCHUNREF, window.siyuan.storage[Constants.LOCAL_SEARCHUNREF]); + } + }] + }).element); + /// #endif + window.siyuan.menus.menu.append(new MenuItem({ + iconHTML: "", + label: window.siyuan.languages.rebuildIndex, + click() { + if (!isPaidUser()) { + showMessage(window.siyuan.languages["_kernel"][214]); + return; + } + element.nextElementSibling.classList.remove("fn__none"); + fetchPost("/api/asset/fullReindexAssetContent", {}, () => { + assetInputEvent(element, localData); + }); + }, + }).element); + /// #if MOBILE + window.siyuan.menus.menu.fullscreen(); + /// #else + const rect = target.getBoundingClientRect(); + window.siyuan.menus.menu.popup({x: rect.right, y: rect.bottom, isLeft: true}); + /// #endif +}; diff --git a/app/src/search/util.ts b/app/src/search/util.ts index 812ddf0ea..9dae7edd2 100644 --- a/app/src/search/util.ts +++ b/app/src/search/util.ts @@ -49,6 +49,7 @@ import {resize} from "../protyle/util/resize"; import {Menu} from "../plugin/Menu"; import {addClearButton} from "../util/addClearButton"; import {checkFold} from "../util/noRelyPCFunction"; +import {openSearchUnRef} from "./unRef"; export const toggleReplaceHistory = (searchElement: Element) => { const list = window.siyuan.storage[Constants.LOCAL_SEARCHKEYS]; @@ -282,6 +283,10 @@ export const genSearch = (app: App, config: ISearchOption, element: Element, clo + + + + @@ -357,6 +362,7 @@ export const genSearch = (app: App, config: ISearchOption, element: Element, clo
+
`; const criteriaData: ISearchOption[] = []; @@ -444,6 +450,7 @@ export const genSearch = (app: App, config: ISearchOption, element: Element, clo const localSearch = window.siyuan.storage[Constants.LOCAL_SEARCHASSET] as ISearchAssetOption; const assetsElement = element.querySelector("#searchAssets"); + const unRefPanelElement = element.querySelector("#searchUnRefPanel"); element.addEventListener("click", (event: MouseEvent) => { let target = event.target as HTMLElement; const searchPathInputElement = element.querySelector("#searchPathInput"); @@ -629,7 +636,12 @@ export const genSearch = (app: App, config: ISearchOption, element: Element, clo event.stopPropagation(); event.preventDefault(); break; - } else if (target.id === "searchAsset") { + } else if (target.id === "searchUnRef") { + openSearchUnRef(unRefPanelElement, !closeCB); + event.stopPropagation(); + event.preventDefault(); + break; + } else if (target.id === "searchAsset") { openSearchAsset(assetsElement, !closeCB); event.stopPropagation(); event.preventDefault(); @@ -642,6 +654,14 @@ export const genSearch = (app: App, config: ISearchOption, element: Element, clo event.stopPropagation(); event.preventDefault(); break; + } else if (target.id === "searchUnRefClose") { + window.siyuan.menus.menu.remove(); + unRefPanelElement.classList.add("fn__none"); + assetsElement.previousElementSibling.classList.remove("fn__none"); + searchInputElement.select(); + event.stopPropagation(); + event.preventDefault(); + break; } else if (target.id === "searchOpen") { config.k = searchInputElement.value; config.r = replaceInputElement.value;