diff --git a/app/src/search/assets.ts b/app/src/search/assets.ts
index 5177cba35..8ee1a6eec 100644
--- a/app/src/search/assets.ts
+++ b/app/src/search/assets.ts
@@ -1,47 +1,54 @@
+/// #if !BROWSER
+import {shell} from "electron";
+import * as path from "path";
+/// #endif
import {Constants} from "../constants";
import {fetchPost} from "../util/fetch";
import {upDownHint} from "../util/upDownHint";
import {escapeHtml} from "../util/escape";
+import {setStorageVal} from "../protyle/util/compatibility";
+import {getQueryTip} from "./util";
+import {MenuItem} from "../menus/Menu";
+import {Dialog} from "../dialog";
export const openSearchAsset = (element: Element, isStick: boolean) => {
- const localSearch = window.siyuan.storage[Constants.LOCAL_SEARCHASSET] as ISearchAssetOption
- let methodText = window.siyuan.languages.keyword;
- if (localSearch.method === 1) {
- methodText = window.siyuan.languages.querySyntax;
- } else if (localSearch.method === 2) {
- methodText = "SQL";
- } else if (localSearch.method === 3) {
- methodText = window.siyuan.languages.regex;
+ window.siyuan.menus.menu.remove();
+ element.previousElementSibling.classList.add("fn__none");
+ element.classList.remove("fn__none");
+ if (element.innerHTML) {
+ (element.querySelector("#searchAssetInput") as HTMLInputElement).select();
+ return;
}
+ const localSearch = window.siyuan.storage[Constants.LOCAL_SEARCHASSET] as ISearchAssetOption
const loadingElement = element.nextElementSibling;
loadingElement.classList.remove("fn__none");
+ let enterTip = ""
+ /// #if !BROWSER
+ enterTip = `Enter/Double Click ${window.siyuan.languages.showInFolder}`
+ /// #endif
element.innerHTML = `
-
+
-
+
-
+
↑/↓ ${window.siyuan.languages.searchTip1}
- Enter/Double Click ${window.siyuan.languages.searchTip2}
+ ${enterTip}
Esc ${window.siyuan.languages.searchTip5}
`
- element.previousElementSibling.classList.add("fn__none");
- element.classList.remove("fn__none")
const searchPanelElement = element.querySelector("#searchAssetList");
if (element.querySelector("#searchAssetList").innerHTML !== "") {
return
@@ -79,42 +84,57 @@ export const openSearchAsset = (element: Element, isStick: boolean) => {
if (event.isComposing) {
return;
}
- inputEvent(localSearch, element, 1);
+ assetInputEvent(element, localSearch);
});
searchInputElement.addEventListener("input", (event: InputEvent) => {
if (event.isComposing) {
return;
}
- inputEvent(localSearch, element, 1);
+ assetInputEvent(element, localSearch);
});
searchInputElement.addEventListener("blur", () => {
- // saveKeyList("keys", searchInputElement.value);
+ if (!searchInputElement.value) {
+ return
+ }
+ let list: string[] = window.siyuan.storage[Constants.LOCAL_SEARCHASSET].keys;
+ list.splice(0, 0, searchInputElement.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_SEARCHASSET].k = searchInputElement.value;
+ window.siyuan.storage[Constants.LOCAL_SEARCHASSET].keys = list;
+ setStorageVal(Constants.LOCAL_SEARCHASSET, window.siyuan.storage[Constants.LOCAL_SEARCHASSET]);
});
const historyElement = element.querySelector("#searchAssetHistoryList")
- const lineHeight = 30;
+ const lineHeight = 28;
searchInputElement.addEventListener("keydown", (event: KeyboardEvent) => {
- let currentList: HTMLElement = searchPanelElement.querySelector(".b3-list-item--focus");
- if (!currentList || event.isComposing) {
+ if (event.isComposing) {
return;
}
+ let currentList: HTMLElement = searchPanelElement.querySelector(".b3-list-item--focus");
const isHistory = !historyElement.classList.contains("fn__none");
if (event.key === "Enter") {
if (!isHistory) {
- // TODO open folder
+ if (currentList) {
+ /// #if !BROWSER
+ shell.showItemInFolder(path.join(window.siyuan.config.system.dataDir, currentList.lastElementChild.getAttribute("aria-label")));
+ /// #endif
+ }
} else {
searchInputElement.value = historyElement.querySelector(".b3-list-item--focus").textContent.trim();
- inputEvent(localSearch, element, 1);
- toggleSearchHistory(historyElement, searchInputElement);
+ assetInputEvent(element, localSearch);
+ toggleAssetHistory(historyElement, searchInputElement);
}
event.preventDefault();
}
if (event.key === "ArrowDown" && event.altKey) {
- toggleSearchHistory(historyElement, searchInputElement);
+ toggleAssetHistory(historyElement, searchInputElement);
return;
}
if (isHistory) {
if (event.key === "Escape") {
- toggleSearchHistory(historyElement, searchInputElement);
+ toggleAssetHistory(historyElement, searchInputElement);
} else {
upDownHint(historyElement, event);
}
@@ -122,7 +142,7 @@ export const openSearchAsset = (element: Element, isStick: boolean) => {
event.preventDefault();
return;
}
- if (!isHistory) {
+ if (!currentList) {
return;
}
if (event.key === "ArrowDown") {
@@ -152,34 +172,83 @@ export const openSearchAsset = (element: Element, isStick: boolean) => {
}
event.preventDefault();
}
+ renderPreview(element.querySelector('#searchAssetPreview'), currentList.dataset.id, searchInputElement.value, localSearch.method);
});
- inputEvent(localSearch, element);
+ assetInputEvent(element, localSearch);
}
-
-const inputEvent = (localSearch: ISearchAssetOption, element: Element, page = 1) => {
- const searchInputElement = element.querySelector("#searchAssetInput") as HTMLInputElement
- fetchPost("/api/search/fullTextSearchAssetContent", {
- page,
- query: searchInputElement.value,
- types: localSearch.types,
- method: localSearch.method,
- orderBy: localSearch.sort
- }, (response) => {
- element.nextElementSibling.classList.add("fn__none")
- console.log(response)
- })
+let inputTimeout: number
+export const assetInputEvent = (element: Element, localSearch?: ISearchAssetOption, page = 1,) => {
+ element.nextElementSibling.classList.remove("fn__none")
+ clearTimeout(inputTimeout);
+ inputTimeout = window.setTimeout(() => {
+ if (!localSearch) {
+ localSearch = window.siyuan.storage[Constants.LOCAL_SEARCHASSET] as ISearchAssetOption
+ }
+ const previousElement = element.querySelector('[data-type="assetPrevious"]')
+ if (page > 1) {
+ previousElement.removeAttribute("disabled");
+ } else {
+ previousElement.setAttribute("disabled", "disabled");
+ }
+ const searchInputElement = element.querySelector("#searchAssetInput") as HTMLInputElement
+ fetchPost("/api/search/fullTextSearchAssetContent", {
+ page,
+ query: searchInputElement.value,
+ types: localSearch.types,
+ method: localSearch.method,
+ orderBy: localSearch.sort
+ }, (response) => {
+ element.nextElementSibling.classList.add("fn__none")
+ const nextElement = element.querySelector('[data-type="assetNext"]')
+ const previewElement = element.querySelector('#searchAssetPreview')
+ if (page < response.data.pageCount) {
+ nextElement.removeAttribute("disabled");
+ } else {
+ nextElement.setAttribute("disabled", "disabled");
+ }
+ let resultHTML = "";
+ response.data.assetContents.forEach((item: {
+ content: string
+ ext: string
+ id: string
+ path: string
+ name: string
+ hSize: string
+ }, index: number) => {
+ resultHTML += `
+${item.ext}
+
+${item.content}
+${item.hSize}
+${item.name}
+
`;
+ });
+ if (response.data.assetContents.length > 0) {
+ previewElement.classList.remove("fn__none");
+ element.querySelector(".search__drag").classList.remove("fn__none");
+ renderPreview(previewElement, response.data.assetContents[0].id, searchInputElement.value, localSearch.method);
+ } else {
+ previewElement.classList.add("fn__none");
+ element.querySelector(".search__drag").classList.add("fn__none");
+ }
+ element.querySelector("#searchAssetResult").innerHTML = `${page}/${response.data.pageCount || 1}
+${window.siyuan.languages.total} ${response.data.matchedAssetCount}`;
+ element.querySelector("#searchAssetList").innerHTML = resultHTML || `
+ ${window.siyuan.languages.emptyContent}
+
`
+ })
+ }, Constants.TIMEOUT_INPUT);
}
-
export const reIndexAssets = (loadingElement: HTMLElement) => {
loadingElement.classList.remove("fn__none")
fetchPost("/api/asset/fullReindexAssetContent", {}, (response) => {
- loadingElement.classList.add("fn__none")
+ // assetInputEvent()
})
}
-const toggleSearchHistory = (historyElement: Element, searchInputElement: HTMLInputElement) => {
+export const toggleAssetHistory = (historyElement: Element, searchInputElement: HTMLInputElement) => {
if (historyElement.classList.contains("fn__none")) {
const keys = window.siyuan.storage[Constants.LOCAL_SEARCHASSET].keys;
if (!keys || keys.length === 0) {
@@ -200,3 +269,120 @@ const toggleSearchHistory = (historyElement: Element, searchInputElement: HTMLIn
historyElement.classList.add("fn__none");
}
};
+
+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;
+ })
+}
+
+export const assetMethodMenu = (target: HTMLElement, cb:() => void) => {
+ const method = window.siyuan.storage[Constants.LOCAL_SEARCHASSET].method
+ if (!window.siyuan.menus.menu.element.classList.contains("fn__none") &&
+ window.siyuan.menus.menu.element.getAttribute("data-name") === "searchMethod") {
+ window.siyuan.menus.menu.remove();
+ return;
+ }
+ window.siyuan.menus.menu.remove();
+ window.siyuan.menus.menu.element.setAttribute("data-name", "searchMethod");
+ window.siyuan.menus.menu.append(new MenuItem({
+ iconHTML: Constants.ZWSP,
+ label: window.siyuan.languages.keyword,
+ current: method === 0,
+ click() {
+ window.siyuan.storage[Constants.LOCAL_SEARCHASSET].method = 0
+ cb();
+ }
+ }).element);
+ window.siyuan.menus.menu.append(new MenuItem({
+ iconHTML: Constants.ZWSP,
+ label: window.siyuan.languages.querySyntax,
+ current: method === 1,
+ click() {
+ window.siyuan.storage[Constants.LOCAL_SEARCHASSET].method = 1
+ cb();
+ }
+ }).element);
+ window.siyuan.menus.menu.append(new MenuItem({
+ iconHTML: Constants.ZWSP,
+ label: "SQL",
+ current: method === 2,
+ click() {
+ window.siyuan.storage[Constants.LOCAL_SEARCHASSET].method = 2
+ cb();
+ }
+ }).element);
+ window.siyuan.menus.menu.append(new MenuItem({
+ iconHTML: Constants.ZWSP,
+ label: window.siyuan.languages.regex,
+ current: method === 3,
+ click() {
+ window.siyuan.storage[Constants.LOCAL_SEARCHASSET].method = 3
+ cb();
+ }
+ }).element);
+ const rect = target.getBoundingClientRect();
+ window.siyuan.menus.menu.popup({x: rect.right, y: rect.bottom}, true);
+}
+
+export const assetFilterMenu = (assetsElement:Element) => {
+ const localData = window.siyuan.storage[Constants.LOCAL_SEARCHASSET].types
+ const filterDialog = new Dialog({
+ title: window.siyuan.languages.type,
+ content: `
+
+
+
+
`,
+ width: "520px",
+ height: "70vh",
+ });
+ const btnsElement = filterDialog.element.querySelectorAll(".b3-button");
+ btnsElement[0].addEventListener("click", () => {
+ filterDialog.destroy();
+ });
+ btnsElement[1].addEventListener("click", () => {
+ filterDialog.element.querySelectorAll(".b3-switch").forEach((item: HTMLInputElement) => {
+ localData[item.getAttribute("data-type")] = item.checked;
+ });
+ assetInputEvent(assetsElement);
+ setStorageVal(Constants.LOCAL_SEARCHASSET, window.siyuan.storage[Constants.LOCAL_SEARCHASSET]);
+ filterDialog.destroy();
+ });
+};
diff --git a/app/src/search/util.ts b/app/src/search/util.ts
index 13a5e16a7..94a6f017c 100644
--- a/app/src/search/util.ts
+++ b/app/src/search/util.ts
@@ -1,4 +1,8 @@
import {getAllModels} from "../layout/getAll";
+/// #if !BROWSER
+import {shell} from "electron";
+import * as path from "path";
+/// #endif
import {Constants} from "../constants";
import {escapeAttr, escapeGreat, escapeHtml} from "../util/escape";
import {fetchPost} from "../util/fetch";
@@ -19,7 +23,14 @@ import {matchHotKey} from "../protyle/util/hotKey";
import {filterMenu, getKeyByLiElement, initCriteriaMenu, moreMenu, queryMenu, saveCriterion} from "./menu";
import {App} from "../index";
import {upDownHint} from "../util/upDownHint";
-import {openSearchAsset, reIndexAssets} from "./assets";
+import {
+ assetFilterMenu,
+ assetInputEvent,
+ assetMethodMenu,
+ openSearchAsset,
+ renderPreview,
+ toggleAssetHistory
+} from "./assets";
const toggleReplaceHistory = (replaceHistoryElement: Element, historyElement: Element, replaceInputElement: HTMLInputElement) => {
if (replaceHistoryElement.classList.contains("fn__none")) {
@@ -236,7 +247,7 @@ export const genSearch = (app: App, config: ISearchOption, element: Element, clo
const replaceHistoryElement = element.querySelector("#replaceHistoryList");
const historyElement = element.querySelector("#searchHistoryList");
- const lineHeight = 30;
+ const lineHeight = 28;
const edit = new Protyle(app, element.querySelector("#searchPreview") as HTMLElement, {
blockId: "",
render: {
@@ -502,6 +513,7 @@ export const genSearch = (app: App, config: ISearchOption, element: Element, clo
event.preventDefault();
break;
} else if (target.id === "searchAssetClose") {
+ window.siyuan.menus.menu.remove();
assetsElement.classList.add("fn__none")
assetsElement.previousElementSibling.classList.remove("fn__none")
searchInputElement.select();
@@ -624,6 +636,20 @@ export const genSearch = (app: App, config: ISearchOption, element: Element, clo
event.stopPropagation();
event.preventDefault();
break;
+ } else if (target.id === "assetFilter") {
+ assetFilterMenu(assetsElement);
+ event.stopPropagation();
+ event.preventDefault();
+ break;
+ } else if (target.id === "assetSyntaxCheck") {
+ assetMethodMenu(target, () => {
+ element.querySelector("#assetSyntaxCheck").setAttribute("aria-label", getQueryTip(window.siyuan.storage[Constants.LOCAL_SEARCHASSET].method));
+ assetInputEvent(assetsElement);
+ setStorageVal(Constants.LOCAL_SEARCHASSET, window.siyuan.storage[Constants.LOCAL_SEARCHASSET]);
+ })
+ event.stopPropagation();
+ event.preventDefault();
+ break;
} else if (target.id === "searchSyntaxCheck") {
queryMenu(config, () => {
element.querySelector("#searchSyntaxCheck").setAttribute("aria-label", getQueryTip(config.method));
@@ -640,6 +666,11 @@ export const genSearch = (app: App, config: ISearchOption, element: Element, clo
event.stopPropagation();
event.preventDefault();
return;
+ } else if (target.id === "assetHistoryBtn") {
+ toggleAssetHistory(target.nextElementSibling.nextElementSibling, target.nextElementSibling as HTMLInputElement);
+ event.stopPropagation();
+ event.preventDefault();
+ return;
} else if (target.id === "replaceHistoryBtn") {
toggleReplaceHistory(replaceHistoryElement, historyElement, replaceInputElement);
event.stopPropagation();
@@ -650,8 +681,8 @@ export const genSearch = (app: App, config: ISearchOption, element: Element, clo
event.stopPropagation();
event.preventDefault();
break;
- } else if (type === "reindexAssets") {
- reIndexAssets(element.querySelector(".fn__loading--top"));
+ } else if (type === "assetRefresh") {
+ assetInputEvent(assetsElement);
event.stopPropagation();
event.preventDefault();
break;
@@ -667,65 +698,85 @@ export const genSearch = (app: App, config: ISearchOption, element: Element, clo
event.preventDefault();
break;
} else if (target.classList.contains("b3-list-item")) {
+ const searchAssetInputElement = element.querySelector("#searchAssetInput") as HTMLInputElement
if (target.parentElement.id === "searchHistoryList") {
searchInputElement.value = target.textContent;
config.page = 1;
inputTimeout = inputEvent(element, config, inputTimeout, edit, true);
+ } else if (target.parentElement.id === "searchAssetHistoryList") {
+ searchAssetInputElement.value = target.textContent;
+ assetInputEvent(assetsElement);
} else if (target.parentElement.id === "replaceHistoryList") {
replaceInputElement.value = target.textContent;
replaceHistoryElement.classList.add("fn__none");
} else if (type === "search-new") {
newFileByName(app, searchInputElement.value);
} else if (type === "search-item") {
+ const isAsset = target.dataset.id;
if (event.detail === 1) {
clickTimeout = window.setTimeout(() => {
- if (event.altKey) {
- const id = target.getAttribute("data-node-id");
- fetchPost("/api/block/checkBlockFold", {id}, (foldResponse) => {
- openFileById({
- app,
- id,
- action: foldResponse.data ? [Constants.CB_GET_FOCUS, Constants.CB_GET_ALL] : [Constants.CB_GET_FOCUS, Constants.CB_GET_CONTEXT],
- zoomIn: foldResponse.data,
- position: "right"
+ if (isAsset) {
+ if (!target.classList.contains("b3-list-item--focus")) {
+ assetsElement.querySelector(".b3-list-item--focus").classList.remove("b3-list-item--focus");
+ target.classList.add("b3-list-item--focus");
+ renderPreview(element.querySelector('#searchAssetPreview'), target.dataset.id, searchAssetInputElement.value, window.siyuan.storage[Constants.LOCAL_SEARCHASSET].method);
+ searchAssetInputElement.focus();
+ }
+ } else {
+ if (event.altKey) {
+ const id = target.getAttribute("data-node-id");
+ fetchPost("/api/block/checkBlockFold", {id}, (foldResponse) => {
+ openFileById({
+ app,
+ id,
+ action: foldResponse.data ? [Constants.CB_GET_FOCUS, Constants.CB_GET_ALL] : [Constants.CB_GET_FOCUS, Constants.CB_GET_CONTEXT],
+ zoomIn: foldResponse.data,
+ position: "right"
+ });
+ if (closeCB) {
+ closeCB();
+ }
});
- if (closeCB) {
- closeCB();
- }
- });
- } else if (!target.classList.contains("b3-list-item--focus")) {
- searchPanelElement.querySelector(".b3-list-item--focus").classList.remove("b3-list-item--focus");
- target.classList.add("b3-list-item--focus");
- getArticle({
- edit,
- id: target.getAttribute("data-node-id"),
- config,
- value: searchInputElement.value,
- });
- searchInputElement.focus();
- } else if (target.classList.contains("b3-list-item--focus")) {
- renderNextSearchMark({
- edit,
- id: target.getAttribute("data-node-id"),
- target,
- });
- searchInputElement.focus();
+ } else if (!target.classList.contains("b3-list-item--focus")) {
+ searchPanelElement.querySelector(".b3-list-item--focus").classList.remove("b3-list-item--focus");
+ target.classList.add("b3-list-item--focus");
+ getArticle({
+ edit,
+ id: target.getAttribute("data-node-id"),
+ config,
+ value: searchInputElement.value,
+ });
+ searchInputElement.focus();
+ } else if (target.classList.contains("b3-list-item--focus")) {
+ renderNextSearchMark({
+ edit,
+ id: target.getAttribute("data-node-id"),
+ target,
+ });
+ searchInputElement.focus();
+ }
}
}, Constants.TIMEOUT_DBLCLICK);
} else if (event.detail === 2 && !event.ctrlKey) {
clearTimeout(clickTimeout);
- const id = target.getAttribute("data-node-id");
- fetchPost("/api/block/checkBlockFold", {id}, (foldResponse) => {
- openFileById({
- app,
- id,
- action: foldResponse.data ? [Constants.CB_GET_FOCUS, Constants.CB_GET_ALL] : [Constants.CB_GET_FOCUS, Constants.CB_GET_CONTEXT],
- zoomIn: foldResponse.data
+ if (isAsset) {
+ /// #if !BROWSER
+ shell.showItemInFolder(path.join(window.siyuan.config.system.dataDir, target.lastElementChild.getAttribute("aria-label")));
+ /// #endif
+ } else {
+ const id = target.getAttribute("data-node-id");
+ fetchPost("/api/block/checkBlockFold", {id}, (foldResponse) => {
+ openFileById({
+ app,
+ id,
+ action: foldResponse.data ? [Constants.CB_GET_FOCUS, Constants.CB_GET_ALL] : [Constants.CB_GET_FOCUS, Constants.CB_GET_CONTEXT],
+ zoomIn: foldResponse.data
+ });
+ if (closeCB) {
+ closeCB();
+ }
});
- if (closeCB) {
- closeCB();
- }
- });
+ }
}
window.siyuan.menus.menu.remove();
} else if (target.querySelector(".b3-list-item__toggle")) {
@@ -740,6 +791,7 @@ export const genSearch = (app: App, config: ISearchOption, element: Element, clo
}
historyElement.classList.add("fn__none");
replaceHistoryElement.classList.add("fn__none");
+ element.querySelector("#searchAssetHistoryList")?.classList.add("fn__none");
}, false);
searchInputElement.addEventListener("compositionend", (event: InputEvent) => {
@@ -927,7 +979,7 @@ export const genSearch = (app: App, config: ISearchOption, element: Element, clo
return edit;
};
-const getQueryTip = (method: number) => {
+export const getQueryTip = (method: number) => {
let methodTip = window.siyuan.languages.searchMethod + " ";
switch (method) {
case 0: