mirror of
https://github.com/siyuan-note/siyuan.git
synced 2026-02-11 01:34:20 +01:00
This commit is contained in:
parent
2a948bbb0d
commit
a17defd902
7 changed files with 736 additions and 229 deletions
|
|
@ -5,18 +5,23 @@
|
|||
position: relative;
|
||||
border-bottom: 1px solid var(--b3-theme-surface-lighter);
|
||||
|
||||
&:hover .block__icon {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.b3-text-field--text {
|
||||
font-size: 18px;
|
||||
height: 48px;
|
||||
height: 42px;
|
||||
line-height: 32px;
|
||||
border-radius: 0;
|
||||
padding: 8px 8px 8px 48px !important;
|
||||
padding: 5px 8px 5px 44px !important;
|
||||
box-shadow: none;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.b3-form__icon-icon {
|
||||
top: 16px;
|
||||
left: 12px;
|
||||
top: 13px;
|
||||
left: 8px;
|
||||
}
|
||||
|
||||
.b3-menu {
|
||||
|
|
@ -33,8 +38,8 @@
|
|||
position: absolute;
|
||||
height: 10px;
|
||||
width: 10px;
|
||||
left: 30px;
|
||||
top: 20px;
|
||||
left: 26px;
|
||||
top: 17px;
|
||||
}
|
||||
|
||||
&__label {
|
||||
|
|
@ -60,59 +65,9 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.protyle-search {
|
||||
display: flex;
|
||||
background-color: var(--b3-theme-surface);
|
||||
transition: var(--b3-transition);
|
||||
height: 0;
|
||||
overflow: hidden;
|
||||
flex-direction: column;
|
||||
box-sizing: border-box;
|
||||
|
||||
&__item {
|
||||
margin: 8px 16px 0 16px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
&--open {
|
||||
height: 36px;
|
||||
}
|
||||
|
||||
&__mark {
|
||||
background-color: var(--b3-protyle-search-background);
|
||||
box-shadow: 0 0 1px var(--b3-protyle-search-border-color);
|
||||
|
||||
&--current {
|
||||
background-color: var(--b3-protyle-search-current-background);
|
||||
box-shadow: 0 0 1px var(--b3-theme-on-background);
|
||||
}
|
||||
}
|
||||
|
||||
&__text {
|
||||
color: var(--b3-theme-on-surface);
|
||||
font-size: 12px;
|
||||
line-height: 22px;
|
||||
height: 22px;
|
||||
padding: 0 8px 0 16px;
|
||||
}
|
||||
|
||||
.b3-tooltips {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
svg {
|
||||
cursor: pointer;
|
||||
color: var(--b3-theme-on-background);
|
||||
padding: 6px 8px;
|
||||
height: 10px;
|
||||
width: 10px;
|
||||
|
||||
&:hover {
|
||||
color: var(--b3-theme-on-surface);
|
||||
}
|
||||
&__preview {
|
||||
background-color: var(--b3-theme-background);
|
||||
border-top: 1px solid var(--b3-theme-surface-lighter);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -479,21 +479,6 @@ progressLoading: 400
|
|||
}
|
||||
}
|
||||
|
||||
.spread-search {
|
||||
&__preview {
|
||||
background-color: var(--b3-theme-background);
|
||||
border-top: 1px solid var(--b3-theme-surface-lighter);
|
||||
}
|
||||
|
||||
&__filter {
|
||||
padding: 16px;
|
||||
|
||||
.b3-label__text {
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.asset {
|
||||
overflow: auto;
|
||||
box-sizing: border-box;
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import {Constants} from "../constants";
|
|||
import {Hint} from "./hint";
|
||||
import {setLute} from "./markdown/setLute";
|
||||
import {Preview} from "./preview";
|
||||
import {initUI, setPadding} from "./ui/initUI";
|
||||
import {initUI, removeLoading, setPadding} from "./ui/initUI";
|
||||
import {Undo} from "./undo";
|
||||
import {Upload} from "./upload";
|
||||
import {Options} from "./util/Options";
|
||||
|
|
@ -161,6 +161,11 @@ export class Protyle {
|
|||
renderBacklink(this.protyle, options.backlinkData);
|
||||
return;
|
||||
}
|
||||
if (!options.blockId) {
|
||||
// 搜索页签需提前初始化
|
||||
removeLoading(this.protyle);
|
||||
return;
|
||||
}
|
||||
fetchPost("/api/filetree/getDoc", {
|
||||
id: options.blockId,
|
||||
k: options.key || "",
|
||||
|
|
|
|||
|
|
@ -4,176 +4,164 @@ import {Protyle} from "../protyle";
|
|||
import {Constants} from "../constants";
|
||||
import {getIconByType} from "../editor/getIcon";
|
||||
import {getDisplayName, getNotebookName} from "../util/pathName";
|
||||
import {setPanelFocus} from "../layout/util";
|
||||
import {escapeHtml} from "../util/escape";
|
||||
import {fetchPost} from "../util/fetch";
|
||||
import {disabledProtyle, onGet} from "../protyle/util/onGet";
|
||||
import {openFileById} from "../editor/util";
|
||||
import {addLoading} from "../protyle/ui/initUI";
|
||||
import {unicode2Emoji} from "../emoji";
|
||||
import {genSearch} from "./util";
|
||||
|
||||
export class Search extends Model {
|
||||
public text: string;
|
||||
private element: HTMLElement;
|
||||
public protyle: Protyle;
|
||||
private inputTimeout: number;
|
||||
private config: ISearchOption;
|
||||
|
||||
constructor(options: { tab: Tab, text: string }) {
|
||||
super({
|
||||
id: options.tab.id,
|
||||
});
|
||||
this.element = options.tab.panelElement as HTMLElement;
|
||||
this.text = options.text;
|
||||
options.tab.updateTitle(this.text);
|
||||
options.tab.updateTitle(options.text || "");
|
||||
genSearch({
|
||||
k: options.text,
|
||||
r: "",
|
||||
hasReplace: false,
|
||||
querySyntax: false,
|
||||
hPath: "",
|
||||
notebookId: "",
|
||||
idPath: "",
|
||||
types: {
|
||||
mathBlock: true,
|
||||
table: true,
|
||||
blockquote: true,
|
||||
superBlock: true,
|
||||
paragraph: true,
|
||||
document: true,
|
||||
heading: true,
|
||||
list: true,
|
||||
listItem: true,
|
||||
codeBlock: true,
|
||||
htmlBlock: true,
|
||||
}
|
||||
}, this.element)
|
||||
|
||||
this.element.innerHTML = `<div class="fn__flex-column" style="height: 100%">
|
||||
<div class="fn__flex-1 fn__flex-column" style="min-height: 50%;">
|
||||
<div class="fn__flex" style="padding: 4px 8px;position: relative">
|
||||
<span style="opacity: 1" class="block__icon fn__flex-center" id="searchHistoryBtn" data-menu="true">
|
||||
<svg><use xlink:href="#iconSearch"></use></svg>
|
||||
<svg style="height: 8px;"><use xlink:href="#iconDown"></use></svg>
|
||||
</span>
|
||||
<div class="fn__space"></div>
|
||||
<input class="b3-text-field fn__flex-1">
|
||||
<span class="fn__space"></span>
|
||||
<span style="opacity: 1" class="block__icon fn__flex-center b3-tooltips b3-tooltips__w" id="globalSearchReload" aria-label="${window.siyuan.languages.refresh}">
|
||||
<svg><use xlink:href="#iconRefresh"></use></svg>
|
||||
</span>
|
||||
<div id="searchHistoryList" data-close="false" class="fn__none b3-menu b3-list b3-list--background" style="position: absolute;top: 30px;max-height: 50vh;overflow: auto"></div>
|
||||
</div>
|
||||
<div id="globalSearchResult" class="b3-list-item ft__smaller ft__on-surface"></div>
|
||||
<div id="globalSearchList" class="fn__flex-1 b3-list b3-list--background"></div>
|
||||
<div class="fn__hr"></div>
|
||||
<div class="fn__loading fn__loading--top"><img width="120px" src="/stage/loading-pure.svg"></div>
|
||||
</div>
|
||||
<div class="fn__flex-1" id="searchPreview"></div>
|
||||
</div>`;
|
||||
const historyElement = this.element.querySelector("#searchHistoryList") as HTMLInputElement;
|
||||
const inputElement = this.element.querySelector(".b3-text-field") as HTMLInputElement;
|
||||
inputElement.value = this.text;
|
||||
inputElement.addEventListener("compositionend", (event: InputEvent) => {
|
||||
this.inputEvent(inputElement, event);
|
||||
});
|
||||
inputElement.addEventListener("input", (event: InputEvent) => {
|
||||
this.inputEvent(inputElement, event);
|
||||
});
|
||||
inputElement.addEventListener("blur", () => {
|
||||
this.setLocalStorage(inputElement.value);
|
||||
});
|
||||
const lineHeight = 30;
|
||||
const searchPanelElement = this.element.querySelector("#globalSearchList");
|
||||
inputElement.addEventListener("keydown", (event) => {
|
||||
let currentList: HTMLElement = searchPanelElement.querySelector(".b3-list-item--focus");
|
||||
if (!currentList || event.isComposing) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.key === "ArrowDown") {
|
||||
currentList.classList.remove("b3-list-item--focus");
|
||||
if (!currentList.nextElementSibling) {
|
||||
searchPanelElement.children[0].classList.add("b3-list-item--focus");
|
||||
} else {
|
||||
currentList.nextElementSibling.classList.add("b3-list-item--focus");
|
||||
}
|
||||
currentList = searchPanelElement.querySelector(".b3-list-item--focus");
|
||||
if (searchPanelElement.scrollTop < currentList.offsetTop - searchPanelElement.clientHeight + lineHeight ||
|
||||
searchPanelElement.scrollTop > currentList.offsetTop) {
|
||||
searchPanelElement.scrollTop = currentList.offsetTop - searchPanelElement.clientHeight + lineHeight;
|
||||
}
|
||||
this.getArticle(currentList.getAttribute("data-node-id"), inputElement.value);
|
||||
event.preventDefault();
|
||||
} else if (event.key === "ArrowUp") {
|
||||
currentList.classList.remove("b3-list-item--focus");
|
||||
if (!currentList.previousElementSibling) {
|
||||
const length = searchPanelElement.children.length;
|
||||
searchPanelElement.children[length - 1].classList.add("b3-list-item--focus");
|
||||
} else {
|
||||
currentList.previousElementSibling.classList.add("b3-list-item--focus");
|
||||
}
|
||||
currentList = searchPanelElement.querySelector(".b3-list-item--focus");
|
||||
if (searchPanelElement.scrollTop < currentList.offsetTop - searchPanelElement.clientHeight + lineHeight ||
|
||||
searchPanelElement.scrollTop > currentList.offsetTop - lineHeight * 2) {
|
||||
searchPanelElement.scrollTop = currentList.offsetTop - lineHeight * 2;
|
||||
}
|
||||
this.getArticle(currentList.getAttribute("data-node-id"), inputElement.value);
|
||||
event.preventDefault();
|
||||
}
|
||||
});
|
||||
inputElement.select();
|
||||
this.inputEvent(inputElement);
|
||||
let clickTimeout: number;
|
||||
this.element.addEventListener("click", (event: MouseEvent) => {
|
||||
setPanelFocus(this.element.parentElement.parentElement);
|
||||
let target = event.target as HTMLElement;
|
||||
let hideList = true;
|
||||
while (target && !target.isEqualNode(this.element)) {
|
||||
if (target.id === "globalSearchReload") {
|
||||
this.inputEvent(inputElement);
|
||||
} else if (target.classList.contains("b3-list-item")) {
|
||||
if (target.getAttribute("data-node-id")) {
|
||||
if (event.detail === 1) {
|
||||
clickTimeout = window.setTimeout(() => {
|
||||
if (window.siyuan.altIsPressed) {
|
||||
const id = target.getAttribute("data-node-id");
|
||||
fetchPost("/api/block/checkBlockFold", {id}, (foldResponse) => {
|
||||
openFileById({
|
||||
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",
|
||||
});
|
||||
});
|
||||
} else {
|
||||
this.element.querySelectorAll(".b3-list-item--focus").forEach((item) => {
|
||||
item.classList.remove("b3-list-item--focus");
|
||||
});
|
||||
target.classList.add("b3-list-item--focus");
|
||||
this.getArticle(target.getAttribute("data-node-id"), inputElement.value);
|
||||
}
|
||||
}, Constants.TIMEOUT_DBLCLICK);
|
||||
} else if (event.detail === 2) {
|
||||
clearTimeout(clickTimeout);
|
||||
const id = target.getAttribute("data-node-id");
|
||||
fetchPost("/api/block/checkBlockFold", {id}, (foldResponse) => {
|
||||
openFileById({
|
||||
id,
|
||||
action: foldResponse.data ? [Constants.CB_GET_FOCUS, Constants.CB_GET_ALL] : [Constants.CB_GET_FOCUS, Constants.CB_GET_CONTEXT],
|
||||
zoomIn: foldResponse.data
|
||||
});
|
||||
});
|
||||
}
|
||||
window.siyuan.menus.menu.remove();
|
||||
} else {
|
||||
this.text = target.textContent;
|
||||
this.parent.updateTitle(this.text);
|
||||
inputElement.value = this.text;
|
||||
inputElement.select();
|
||||
this.inputEvent(inputElement);
|
||||
}
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
break;
|
||||
} else if (target.id === "searchHistoryBtn") {
|
||||
hideList = false;
|
||||
let html = "";
|
||||
const data = JSON.parse(localStorage.getItem(Constants.LOCAL_SEARCHETABDATA) || "[]");
|
||||
data.forEach((s: string) => {
|
||||
if (s !== inputElement.value) {
|
||||
html += `<div class="b3-list-item">${escapeHtml(s)}</div>`;
|
||||
}
|
||||
});
|
||||
historyElement.classList.remove("fn__none");
|
||||
historyElement.innerHTML = html;
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
break;
|
||||
}
|
||||
target = target.parentElement;
|
||||
}
|
||||
if (hideList) {
|
||||
historyElement.classList.add("fn__none");
|
||||
}
|
||||
}, false);
|
||||
// const historyElement = this.element.querySelector("#searchHistoryList") as HTMLInputElement;
|
||||
// const lineHeight = 30;
|
||||
// const searchPanelElement = this.element.querySelector("#globalSearchList");
|
||||
// inputElement.addEventListener("keydown", (event) => {
|
||||
// let currentList: HTMLElement = searchPanelElement.querySelector(".b3-list-item--focus");
|
||||
// if (!currentList || event.isComposing) {
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// if (event.key === "ArrowDown") {
|
||||
// currentList.classList.remove("b3-list-item--focus");
|
||||
// if (!currentList.nextElementSibling) {
|
||||
// searchPanelElement.children[0].classList.add("b3-list-item--focus");
|
||||
// } else {
|
||||
// currentList.nextElementSibling.classList.add("b3-list-item--focus");
|
||||
// }
|
||||
// currentList = searchPanelElement.querySelector(".b3-list-item--focus");
|
||||
// if (searchPanelElement.scrollTop < currentList.offsetTop - searchPanelElement.clientHeight + lineHeight ||
|
||||
// searchPanelElement.scrollTop > currentList.offsetTop) {
|
||||
// searchPanelElement.scrollTop = currentList.offsetTop - searchPanelElement.clientHeight + lineHeight;
|
||||
// }
|
||||
// this.getArticle(currentList.getAttribute("data-node-id"), inputElement.value);
|
||||
// event.preventDefault();
|
||||
// } else if (event.key === "ArrowUp") {
|
||||
// currentList.classList.remove("b3-list-item--focus");
|
||||
// if (!currentList.previousElementSibling) {
|
||||
// const length = searchPanelElement.children.length;
|
||||
// searchPanelElement.children[length - 1].classList.add("b3-list-item--focus");
|
||||
// } else {
|
||||
// currentList.previousElementSibling.classList.add("b3-list-item--focus");
|
||||
// }
|
||||
// currentList = searchPanelElement.querySelector(".b3-list-item--focus");
|
||||
// if (searchPanelElement.scrollTop < currentList.offsetTop - searchPanelElement.clientHeight + lineHeight ||
|
||||
// searchPanelElement.scrollTop > currentList.offsetTop - lineHeight * 2) {
|
||||
// searchPanelElement.scrollTop = currentList.offsetTop - lineHeight * 2;
|
||||
// }
|
||||
// this.getArticle(currentList.getAttribute("data-node-id"), inputElement.value);
|
||||
// event.preventDefault();
|
||||
// }
|
||||
// });
|
||||
// inputElement.select();
|
||||
// this.inputEvent(inputElement);
|
||||
// let clickTimeout: number;
|
||||
// this.element.addEventListener("click", (event: MouseEvent) => {
|
||||
// setPanelFocus(this.element.parentElement.parentElement);
|
||||
// let target = event.target as HTMLElement;
|
||||
// let hideList = true;
|
||||
// while (target && !target.isEqualNode(this.element)) {
|
||||
// if (target.id === "globalSearchReload") {
|
||||
// this.inputEvent(inputElement);
|
||||
// } else if (target.classList.contains("b3-list-item")) {
|
||||
// if (target.getAttribute("data-node-id")) {
|
||||
// if (event.detail === 1) {
|
||||
// clickTimeout = window.setTimeout(() => {
|
||||
// if (window.siyuan.altIsPressed) {
|
||||
// const id = target.getAttribute("data-node-id");
|
||||
// fetchPost("/api/block/checkBlockFold", {id}, (foldResponse) => {
|
||||
// openFileById({
|
||||
// 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",
|
||||
// });
|
||||
// });
|
||||
// } else {
|
||||
// this.element.querySelectorAll(".b3-list-item--focus").forEach((item) => {
|
||||
// item.classList.remove("b3-list-item--focus");
|
||||
// });
|
||||
// target.classList.add("b3-list-item--focus");
|
||||
// this.getArticle(target.getAttribute("data-node-id"), inputElement.value);
|
||||
// }
|
||||
// }, Constants.TIMEOUT_DBLCLICK);
|
||||
// } else if (event.detail === 2) {
|
||||
// clearTimeout(clickTimeout);
|
||||
// const id = target.getAttribute("data-node-id");
|
||||
// fetchPost("/api/block/checkBlockFold", {id}, (foldResponse) => {
|
||||
// openFileById({
|
||||
// id,
|
||||
// action: foldResponse.data ? [Constants.CB_GET_FOCUS, Constants.CB_GET_ALL] : [Constants.CB_GET_FOCUS, Constants.CB_GET_CONTEXT],
|
||||
// zoomIn: foldResponse.data
|
||||
// });
|
||||
// });
|
||||
// }
|
||||
// window.siyuan.menus.menu.remove();
|
||||
// } else {
|
||||
// this.text = target.textContent;
|
||||
// this.parent.updateTitle(this.text);
|
||||
// inputElement.value = this.text;
|
||||
// inputElement.select();
|
||||
// this.inputEvent(inputElement);
|
||||
// }
|
||||
// event.preventDefault();
|
||||
// event.stopPropagation();
|
||||
// break;
|
||||
// } else if (target.id === "searchHistoryBtn") {
|
||||
// hideList = false;
|
||||
// let html = "";
|
||||
// const data = JSON.parse(localStorage.getItem(Constants.LOCAL_SEARCHETABDATA) || "[]");
|
||||
// data.forEach((s: string) => {
|
||||
// if (s !== inputElement.value) {
|
||||
// html += `<div class="b3-list-item">${escapeHtml(s)}</div>`;
|
||||
// }
|
||||
// });
|
||||
// historyElement.classList.remove("fn__none");
|
||||
// historyElement.innerHTML = html;
|
||||
// event.preventDefault();
|
||||
// event.stopPropagation();
|
||||
// break;
|
||||
// }
|
||||
// target = target.parentElement;
|
||||
// }
|
||||
// if (hideList) {
|
||||
// historyElement.classList.add("fn__none");
|
||||
// }
|
||||
// }, false);
|
||||
}
|
||||
|
||||
private getArticle(id: string, value: string) {
|
||||
|
|
|
|||
|
|
@ -141,7 +141,7 @@ export const openSearch = async (hotkey: string, key?: string, notebookId?: stri
|
|||
</span>
|
||||
</div>
|
||||
<div id="searchList" style="position:relative;height:calc(50% - 69px);overflow: auto;padding-bottom: 8px" class="b3-list b3-list--background search__list"></div>
|
||||
<div id="searchPreview" class="fn__flex-1 spread-search__preview"></div></div>
|
||||
<div id="searchPreview" class="fn__flex-1 search__preview"></div></div>
|
||||
<div id="searchFilterPanel" class="fn__none spread-search__filter">
|
||||
<label class="fn__flex">
|
||||
<div class="fn__flex-1 b3-label__text">
|
||||
|
|
|
|||
|
|
@ -3,8 +3,21 @@ import {getWndByLayout, resizeTabs} from "../layout/util";
|
|||
import {Tab} from "../layout/Tab";
|
||||
import {Search} from "./index";
|
||||
import {Wnd} from "../layout/Wnd";
|
||||
import {Constants} from "../constants";
|
||||
import {escapeHtml} from "../util/escape";
|
||||
import {fetchPost} from "../util/fetch";
|
||||
import {openFileById} from "../editor/util";
|
||||
import {showMessage} from "../dialog/message";
|
||||
import {reloadProtyle} from "../protyle/util/reload";
|
||||
import {MenuItem} from "../menus/Menu";
|
||||
import {getDisplayName, getNotebookName, movePathTo} from "../util/pathName";
|
||||
import {Protyle} from "../protyle";
|
||||
import {disabledProtyle, onGet} from "../protyle/util/onGet";
|
||||
import {addLoading} from "../protyle/ui/initUI";
|
||||
import {getIconByType} from "../editor/getIcon";
|
||||
import {unicode2Emoji} from "../emoji";
|
||||
|
||||
export const openGlobalSearch = (text: string, replace:boolean) => {
|
||||
export const openGlobalSearch = (text: string, replace: boolean) => {
|
||||
text = text.trim();
|
||||
let wnd: Wnd;
|
||||
const searchModel = getAllModels().search.find((item, index) => {
|
||||
|
|
@ -35,3 +48,539 @@ export const openGlobalSearch = (text: string, replace:boolean) => {
|
|||
});
|
||||
wnd.split("lr").addTab(tab);
|
||||
};
|
||||
|
||||
export const genSearch = (config: ISearchOption, element: Element, closeCB?: () => void) => {
|
||||
element.innerHTML = `<div class="fn__flex-column" style="height: 100%">
|
||||
<div class="b3-form__icon search__header">
|
||||
<span class="fn__a" id="searchHistoryBtn">
|
||||
<svg data-menu="true" class="b3-form__icon-icon"><use xlink:href="#iconSearch"></use></svg>
|
||||
<svg class="search__arrowdown"><use xlink:href="#iconDown"></use></svg>
|
||||
</span>
|
||||
<input id="searchInput" style="padding-right: 60px" class="b3-text-field b3-text-field--text">
|
||||
<div id="searchHistoryList" data-close="false" class="fn__none b3-menu b3-list b3-list--background"></div>
|
||||
<div class="block__icons">
|
||||
<span id="searchReplace" aria-label="${window.siyuan.languages.replace}" class="block__icon b3-tooltips b3-tooltips__w">
|
||||
<svg><use xlink:href="#iconEdit"></use></svg>
|
||||
</span>
|
||||
<span class="fn__space"></span>
|
||||
<span id="searchPath" aria-label="${window.siyuan.languages.specifyPath}" class="block__icon b3-tooltips b3-tooltips__w">
|
||||
<svg><use xlink:href="#iconFolder"></use></svg>
|
||||
</span>
|
||||
<span class="fn__space"></span>
|
||||
<span id="searchRefresh" aria-label="${window.siyuan.languages.refresh}" class="block__icon b3-tooltips b3-tooltips__w">
|
||||
<svg><use xlink:href="#iconRefresh"></use></svg>
|
||||
</span>
|
||||
<span class="fn__space"></span>
|
||||
<span id="searchFilter" aria-label="${window.siyuan.languages.type}" class="block__icon b3-tooltips b3-tooltips__w">
|
||||
<svg><use xlink:href="#iconSettings"></use></svg>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="b3-form__icon search__header${config.hasReplace ? "" : " fn__none"}">
|
||||
<span class="fn__a" id="replaceHistoryBtn">
|
||||
<svg data-menu="true" class="b3-form__icon-icon"><use xlink:href="#iconSearch"></use></svg>
|
||||
<svg class="search__arrowdown"><use xlink:href="#iconDown"></use></svg>
|
||||
</span>
|
||||
<input id="replaceInput" class="b3-text-field b3-text-field--text">
|
||||
<svg class="fn__rotate fn__none svg" style="padding: 0 8px;align-self: center;"><use xlink:href="#iconRefresh"></use></svg>
|
||||
<button id="replaceAllBtn" class="b3-button b3-button--small b3-button--outline fn__flex-center">${window.siyuan.languages.replaceAll}</button>
|
||||
<div class="fn__space"></div>
|
||||
<button id="replaceBtn" class="b3-button b3-button--small b3-button--outline fn__flex-center">${window.siyuan.languages.replace}</button>
|
||||
<div class="fn__space"></div>
|
||||
<div id="replaceHistoryList" data-close="false" class="fn__none b3-menu b3-list b3-list--background"></div>
|
||||
</div>
|
||||
<div class="fn__flex b3-form__space--small">
|
||||
<span id="searchResult" style="white-space: nowrap;"></span>
|
||||
<span class="fn__space"></span>
|
||||
<span class="fn__flex-1"></span>
|
||||
<span id="searchPathInput" class="ft__on-surface fn__flex-center ft__smaller fn__ellipsis" style="white-space: nowrap;" title="${config.hPath}">${config.hPath}</span>
|
||||
<span class="fn__space"></span>
|
||||
<button id="includeChildCheck" class="b3-button b3-button--small${(config.notebookId && config.idPath && !config.idPath.endsWith(".sy")) ? "" : " b3-button--cancel"}">${window.siyuan.languages.includeChildDoc}</button>
|
||||
<span class="fn__space"></span>
|
||||
<button id="searchSyntaxCheck" class="b3-button b3-button--small${config.querySyntax ? "" : " b3-button--cancel"}">${window.siyuan.languages.querySyntax}</button>
|
||||
</div>
|
||||
<div id="searchList" style="position:relative;height:calc(50% - 69px);overflow: auto;padding-bottom: 8px" class="b3-list b3-list--background search__list"></div>
|
||||
<div id="searchPreview" class="fn__flex-1 search__preview"></div>
|
||||
</div>
|
||||
<div class="fn__loading fn__loading--top"><img width="120px" src="/stage/loading-pure.svg"></div>`
|
||||
const searchPanelElement = element.querySelector("#searchList");
|
||||
const searchInputElement = element.querySelector("#searchInput") as HTMLInputElement;
|
||||
const replaceInputElement = element.querySelector("#replaceInput") as HTMLInputElement;
|
||||
const replaceHistoryElement = element.querySelector("#replaceHistoryList");
|
||||
const historyElement = element.querySelector("#searchHistoryList");
|
||||
|
||||
const lineHeight = 30;
|
||||
const edit = new Protyle(element.querySelector("#searchPreview") as HTMLElement, {
|
||||
blockId: "",
|
||||
render: {
|
||||
gutter: true,
|
||||
breadcrumbDocName: true
|
||||
},
|
||||
});
|
||||
let clickTimeout: number;
|
||||
let inputTimeout: number;
|
||||
|
||||
searchInputElement.value = config.k || "";
|
||||
replaceInputElement.value = config.r || "";
|
||||
searchInputElement.select();
|
||||
|
||||
element.addEventListener("click", (event: MouseEvent) => {
|
||||
let target = event.target as HTMLElement
|
||||
while (target && !target.isSameNode(element)) {
|
||||
if (target.id === "searchPath") {
|
||||
movePathTo([], undefined, (toPath) => {
|
||||
config.idPath = toPath;
|
||||
fetchPost("/api/filetree/getHPathsByPaths", {paths: [toPath]}, (response) => {
|
||||
config.hPath = escapeHtml(response.data.join(", "));
|
||||
element.querySelector("#searchPathInput").innerHTML = escapeHtml(response.data.join(", "));
|
||||
});
|
||||
inputTimeout = inputEvent(element, config, inputTimeout, edit);
|
||||
});
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
break;
|
||||
} else if (target.id === "searchReplace") {
|
||||
element.querySelector("#replaceHistoryBtn").parentElement.classList.toggle("fn__none");
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
break;
|
||||
} else if (target.id === "searchRefresh") {
|
||||
inputTimeout = inputEvent(element, config, inputTimeout, edit)
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
break;
|
||||
} else if (target.id === "searchFilter") {
|
||||
window.siyuan.menus.menu.remove();
|
||||
addConfigMenu(config, window.siyuan.languages.math, "mathBlock", edit, element);
|
||||
addConfigMenu(config, window.siyuan.languages.table, "table", edit, element);
|
||||
addConfigMenu(config, window.siyuan.languages.quote, "blockquote", edit, element);
|
||||
addConfigMenu(config, window.siyuan.languages.superBlock, "superBlock", edit, element);
|
||||
addConfigMenu(config, window.siyuan.languages.paragraph, "paragraph", edit, element);
|
||||
addConfigMenu(config, window.siyuan.languages.doc, "document", edit, element);
|
||||
addConfigMenu(config, window.siyuan.languages.headings, "heading", edit, element);
|
||||
addConfigMenu(config, window.siyuan.languages.list1, "list", edit, element);
|
||||
addConfigMenu(config, window.siyuan.languages.listItem, "listItem", edit, element);
|
||||
addConfigMenu(config, window.siyuan.languages.code, "codeBlock", edit, element);
|
||||
addConfigMenu(config, "HTML", "htmlBlock", edit, element);
|
||||
window.siyuan.menus.menu.popup({x: event.clientX - 16, y: event.clientY - 16}, true);
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
break;
|
||||
} else if (target.id === "includeChildCheck") {
|
||||
target.classList.toggle("b3-button--cancel");
|
||||
let reload = false;
|
||||
if (target.classList.contains("b3-button--cancel")) {
|
||||
if (!config.idPath.endsWith(".sy")) {
|
||||
config.idPath = config.idPath + ".sy";
|
||||
reload = true;
|
||||
}
|
||||
} else {
|
||||
if (config.hPath) {
|
||||
reload = true;
|
||||
}
|
||||
if (config.idPath.endsWith(".sy")) {
|
||||
config.idPath = config.idPath.replace(".sy", "");
|
||||
reload = true;
|
||||
}
|
||||
}
|
||||
if (reload) {
|
||||
localStorage.setItem(Constants.LOCAL_SEARCHEDATA, JSON.stringify(config));
|
||||
inputTimeout = inputEvent(element, config, inputTimeout, edit);
|
||||
}
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
break;
|
||||
} else if (target.id === "searchSyntaxCheck") {
|
||||
target.classList.toggle("b3-button--cancel");
|
||||
config.querySyntax = !target.classList.contains("b3-button--cancel");
|
||||
inputTimeout = inputEvent(element, config, inputTimeout, edit);
|
||||
localStorage.setItem(Constants.LOCAL_SEARCHEDATA, JSON.stringify(config));
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
break;
|
||||
} else if (target.id === "searchHistoryBtn") {
|
||||
let html = "";
|
||||
(config.list || []).forEach((s: string) => {
|
||||
if (s !== searchInputElement.value) {
|
||||
html += `<div class="b3-list-item">${escapeHtml(s)}</div>`;
|
||||
}
|
||||
});
|
||||
historyElement.classList.remove("fn__none");
|
||||
historyElement.innerHTML = html;
|
||||
replaceHistoryElement.classList.add("fn__none");
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
return;
|
||||
} else if (target.id === "replaceHistoryBtn") {
|
||||
let html = "";
|
||||
(config.replaceList || []).forEach((s: string) => {
|
||||
if (s !== replaceInputElement.value) {
|
||||
html += `<div class="b3-list-item">${escapeHtml(s)}</div>`;
|
||||
}
|
||||
});
|
||||
replaceHistoryElement.classList.remove("fn__none");
|
||||
replaceHistoryElement.innerHTML = html;
|
||||
historyElement.classList.add("fn__none");
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
return;
|
||||
} else if (target.id === "replaceAllBtn") {
|
||||
replace(element, config, edit, true);
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
break;
|
||||
} else if (target.id === "replaceBtn") {
|
||||
replace(element, config, edit, false);
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
break;
|
||||
} else if (target.classList.contains("b3-list-item")) {
|
||||
if (target.parentElement.id === "searchHistoryList") {
|
||||
searchInputElement.value = target.textContent;
|
||||
searchInputElement.dispatchEvent(new CustomEvent("blur"));
|
||||
inputTimeout = inputEvent(element, config, inputTimeout, edit);
|
||||
} else if (target.parentElement.id === "replaceHistoryList") {
|
||||
replaceInputElement.value = target.textContent;
|
||||
replaceHistoryElement.classList.add("fn__none");
|
||||
}
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
break;
|
||||
} else if (target.getAttribute("data-type") === "search-item") {
|
||||
if (event.detail === 1) {
|
||||
clickTimeout = window.setTimeout(() => {
|
||||
if (window.siyuan.altIsPressed) {
|
||||
const id = target.getAttribute("data-node-id");
|
||||
fetchPost("/api/block/checkBlockFold", {id}, (foldResponse) => {
|
||||
openFileById({
|
||||
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();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
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"),
|
||||
k: getKey(target)
|
||||
});
|
||||
searchInputElement.focus();
|
||||
}
|
||||
}, Constants.TIMEOUT_DBLCLICK);
|
||||
} else if (event.detail === 2) {
|
||||
clearTimeout(clickTimeout);
|
||||
const id = target.getAttribute("data-node-id");
|
||||
fetchPost("/api/block/checkBlockFold", {id}, (foldResponse) => {
|
||||
openFileById({
|
||||
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();
|
||||
}
|
||||
});
|
||||
}
|
||||
window.siyuan.menus.menu.remove();
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
break;
|
||||
}
|
||||
target = target.parentElement;
|
||||
}
|
||||
historyElement.classList.add("fn__none");
|
||||
replaceHistoryElement.classList.add("fn__none");
|
||||
}, false);
|
||||
|
||||
searchInputElement.addEventListener("compositionend", (event: InputEvent) => {
|
||||
inputTimeout = inputEvent(element, config, inputTimeout, edit, event);
|
||||
});
|
||||
searchInputElement.addEventListener("input", (event: InputEvent) => {
|
||||
inputTimeout = inputEvent(element, config, inputTimeout, edit, event);
|
||||
});
|
||||
searchInputElement.addEventListener("blur", () => {
|
||||
let searches: string[] = config.list || [];
|
||||
searches.splice(0, 0, searchInputElement.value);
|
||||
searches = Array.from(new Set(searches));
|
||||
if (searches.length > window.siyuan.config.search.limit) {
|
||||
searches.splice(window.siyuan.config.search.limit, searches.length - window.siyuan.config.search.limit);
|
||||
}
|
||||
config.list = searches;
|
||||
config.k = searchInputElement.value;
|
||||
localStorage.setItem(Constants.LOCAL_SEARCHEDATA, JSON.stringify(config));
|
||||
});
|
||||
searchInputElement.addEventListener("focus", () => {
|
||||
historyElement.classList.add("fn__none");
|
||||
replaceHistoryElement.classList.add("fn__none");
|
||||
});
|
||||
searchInputElement.addEventListener("keydown", (event: KeyboardEvent) => {
|
||||
let currentList: HTMLElement = searchPanelElement.querySelector(".b3-list-item--focus");
|
||||
if (!currentList || event.isComposing) {
|
||||
return;
|
||||
}
|
||||
if (event.key === "ArrowDown") {
|
||||
currentList.classList.remove("b3-list-item--focus");
|
||||
if (!currentList.nextElementSibling) {
|
||||
searchPanelElement.children[0].classList.add("b3-list-item--focus");
|
||||
} else {
|
||||
currentList.nextElementSibling.classList.add("b3-list-item--focus");
|
||||
}
|
||||
currentList = searchPanelElement.querySelector(".b3-list-item--focus");
|
||||
if (searchPanelElement.scrollTop < currentList.offsetTop - searchPanelElement.clientHeight + lineHeight ||
|
||||
searchPanelElement.scrollTop > currentList.offsetTop) {
|
||||
searchPanelElement.scrollTop = currentList.offsetTop - searchPanelElement.clientHeight + lineHeight;
|
||||
}
|
||||
getArticle({
|
||||
id: currentList.getAttribute("data-node-id"),
|
||||
k: getKey(currentList),
|
||||
edit
|
||||
});
|
||||
event.preventDefault();
|
||||
} else if (event.key === "ArrowUp") {
|
||||
currentList.classList.remove("b3-list-item--focus");
|
||||
if (!currentList.previousElementSibling) {
|
||||
const length = searchPanelElement.children.length;
|
||||
searchPanelElement.children[length - 1].classList.add("b3-list-item--focus");
|
||||
} else {
|
||||
currentList.previousElementSibling.classList.add("b3-list-item--focus");
|
||||
}
|
||||
currentList = searchPanelElement.querySelector(".b3-list-item--focus");
|
||||
if (searchPanelElement.scrollTop < currentList.offsetTop - searchPanelElement.clientHeight + lineHeight ||
|
||||
searchPanelElement.scrollTop > currentList.offsetTop - lineHeight * 2) {
|
||||
searchPanelElement.scrollTop = currentList.offsetTop - lineHeight * 2;
|
||||
}
|
||||
getArticle({
|
||||
id: currentList.getAttribute("data-node-id"),
|
||||
k: getKey(currentList),
|
||||
edit
|
||||
});
|
||||
event.preventDefault();
|
||||
} else if (event.key === "Enter") {
|
||||
const id = currentList.getAttribute("data-node-id");
|
||||
fetchPost("/api/block/checkBlockFold", {id}, (foldResponse) => {
|
||||
openFileById({
|
||||
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();
|
||||
}
|
||||
});
|
||||
event.preventDefault();
|
||||
}
|
||||
});
|
||||
replaceInputElement.addEventListener("focus", () => {
|
||||
historyElement.classList.add("fn__none");
|
||||
replaceHistoryElement.classList.add("fn__none");
|
||||
});
|
||||
replaceInputElement.addEventListener("keydown", (event: KeyboardEvent) => {
|
||||
if (event.isComposing || event.key !== "Enter") {
|
||||
return;
|
||||
}
|
||||
replace(element, config, edit, false);
|
||||
event.preventDefault();
|
||||
});
|
||||
inputTimeout = inputEvent(element, config, inputTimeout, edit);
|
||||
}
|
||||
|
||||
const addConfigMenu = (config: ISearchOption, lang: string, key: "mathBlock" | "table" | "blockquote" | "superBlock" | "paragraph" | "document" | "heading" | "list" | "listItem" | "codeBlock" | "htmlBlock",
|
||||
edit: Protyle, element: Element) => {
|
||||
window.siyuan.menus.menu.append(new MenuItem({
|
||||
label: `<div class="fn__flex" style="margin-bottom: 4px"><span>${lang}</span><span class="fn__space fn__flex-1"></span>
|
||||
<input type="checkbox" class="b3-switch fn__flex-center"${config.types[key] ? " checked" : ""}></div>`,
|
||||
bind(menuItemElement) {
|
||||
menuItemElement.addEventListener("click", (event: MouseEvent & { target: HTMLElement }) => {
|
||||
const inputElement = menuItemElement.querySelector("input");
|
||||
if (event.target.tagName !== "INPUT") {
|
||||
inputElement.checked = !inputElement.checked;
|
||||
}
|
||||
config.types[key] = inputElement.checked;
|
||||
inputEvent(element, config, undefined, edit);
|
||||
localStorage.setItem(Constants.LOCAL_SEARCHEDATA, JSON.stringify(config));
|
||||
window.siyuan.menus.menu.remove();
|
||||
});
|
||||
}
|
||||
}).element);
|
||||
}
|
||||
|
||||
const getKey = (element: HTMLElement) => {
|
||||
const keys: string[] = [];
|
||||
element.querySelectorAll("mark").forEach(item => {
|
||||
keys.push(item.textContent);
|
||||
});
|
||||
return [...new Set(keys)].join(" ");
|
||||
};
|
||||
|
||||
const getArticle = (options: {
|
||||
id: string,
|
||||
k: string,
|
||||
edit: Protyle
|
||||
}) => {
|
||||
console.log(options.edit);
|
||||
fetchPost("/api/block/checkBlockFold", {id: options.id}, (foldResponse) => {
|
||||
options.edit.protyle.scroll.lastScrollTop = 0;
|
||||
addLoading(options.edit.protyle);
|
||||
fetchPost("/api/filetree/getDoc", {
|
||||
id: options.id,
|
||||
k: options.k,
|
||||
mode: foldResponse.data ? 0 : 3,
|
||||
size: foldResponse.data ? Constants.SIZE_GET_MAX : window.siyuan.config.editor.dynamicLoadBlocks,
|
||||
}, getResponse => {
|
||||
onGet(getResponse, options.edit.protyle, foldResponse.data ? [Constants.CB_GET_ALL, Constants.CB_GET_HTML] : [Constants.CB_GET_HL, Constants.CB_GET_HTML]);
|
||||
const matchElement = options.edit.protyle.wysiwyg.element.querySelector(`div[data-node-id="${options.id}"] span[data-type="search-mark"]`);
|
||||
if (matchElement) {
|
||||
matchElement.scrollIntoView();
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
const replace = (element: Element, config: ISearchOption, edit: Protyle, isAll: boolean) => {
|
||||
const searchPanelElement = element.querySelector("#searchList");
|
||||
const replaceInputElement = element.querySelector("#replaceInput") as HTMLInputElement;
|
||||
|
||||
const loadElement = replaceInputElement.nextElementSibling;
|
||||
if (!loadElement.classList.contains("fn__none")) {
|
||||
return;
|
||||
}
|
||||
let searches: string[] = config.replaceList || [];
|
||||
searches.splice(0, 0, replaceInputElement.value);
|
||||
searches = Array.from(new Set(searches));
|
||||
if (searches.length > window.siyuan.config.search.limit) {
|
||||
searches.splice(window.siyuan.config.search.limit, searches.length - window.siyuan.config.search.limit);
|
||||
}
|
||||
config.replaceList = searches;
|
||||
config.r = replaceInputElement.value;
|
||||
localStorage.setItem(Constants.LOCAL_SEARCHEDATA, JSON.stringify(config));
|
||||
|
||||
let currentList: HTMLElement = searchPanelElement.querySelector(".b3-list-item--focus");
|
||||
if (!currentList) {
|
||||
return;
|
||||
}
|
||||
loadElement.classList.remove("fn__none");
|
||||
let ids: string[] = [];
|
||||
let rootIds: string[] = [];
|
||||
if (isAll) {
|
||||
searchPanelElement.querySelectorAll(".b3-list-item").forEach(item => {
|
||||
ids.push(item.getAttribute("data-node-id"));
|
||||
rootIds.push(item.getAttribute("data-root-id"));
|
||||
});
|
||||
} else {
|
||||
ids = [currentList.getAttribute("data-node-id")];
|
||||
rootIds = [currentList.getAttribute("data-root-id")];
|
||||
}
|
||||
fetchPost("/api/search/findReplace", {
|
||||
k: getKey(currentList),
|
||||
r: replaceInputElement.value,
|
||||
ids,
|
||||
types: config.types,
|
||||
}, (response) => {
|
||||
loadElement.classList.add("fn__none");
|
||||
if (response.code === 1) {
|
||||
showMessage(response.msg);
|
||||
return;
|
||||
}
|
||||
if (ids.length > 1) {
|
||||
return;
|
||||
}
|
||||
getAllModels().editor.forEach(item => {
|
||||
if (rootIds[0] === item.editor.protyle.block.rootID) {
|
||||
reloadProtyle(item.editor.protyle);
|
||||
}
|
||||
});
|
||||
if (!currentList.nextElementSibling && searchPanelElement.children[0]) {
|
||||
searchPanelElement.children[0].classList.add("b3-list-item--focus");
|
||||
} else {
|
||||
currentList.nextElementSibling.classList.add("b3-list-item--focus");
|
||||
}
|
||||
currentList.remove();
|
||||
if (searchPanelElement.childElementCount === 0) {
|
||||
searchPanelElement.innerHTML = `<div class="b3-list--empty">${window.siyuan.languages.emptyContent}</div>`;
|
||||
edit.protyle.element.classList.add("fn__none");
|
||||
return;
|
||||
}
|
||||
currentList = searchPanelElement.querySelector(".b3-list-item--focus");
|
||||
if (searchPanelElement.scrollTop < currentList.offsetTop - searchPanelElement.clientHeight + 30 ||
|
||||
searchPanelElement.scrollTop > currentList.offsetTop) {
|
||||
searchPanelElement.scrollTop = currentList.offsetTop - searchPanelElement.clientHeight + 30;
|
||||
}
|
||||
getArticle({
|
||||
edit,
|
||||
id: currentList.getAttribute("data-node-id"),
|
||||
k: getKey(currentList)
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
const inputEvent = (element: Element, config: ISearchOption, inputTimeout: number, edit: Protyle, event?: InputEvent) => {
|
||||
if (event && event.isComposing) {
|
||||
return;
|
||||
}
|
||||
const searchInputElement = element.querySelector("#searchInput") as HTMLInputElement;
|
||||
const loadingElement = element.querySelector(".fn__loading--top");
|
||||
clearTimeout(inputTimeout);
|
||||
inputTimeout = window.setTimeout(() => {
|
||||
loadingElement.classList.remove("fn__none");
|
||||
const inputValue = searchInputElement.value;
|
||||
if (inputValue === "") {
|
||||
fetchPost("/api/block/getRecentUpdatedBlocks", {}, (response) => {
|
||||
onSearch(response.data, edit, element);
|
||||
loadingElement.classList.add("fn__none");
|
||||
element.querySelector("#searchResult").innerHTML = "";
|
||||
});
|
||||
} else {
|
||||
fetchPost("/api/search/fullTextSearchBlock", {
|
||||
query: inputValue,
|
||||
querySyntax: config.querySyntax,
|
||||
types: config.types,
|
||||
path: config.hPath ? config.idPath : ""
|
||||
}, (response) => {
|
||||
onSearch(response.data.blocks, edit, element);
|
||||
element.querySelector("#searchResult").innerHTML = window.siyuan.languages.findInDoc.replace("${x}", response.data.matchedRootCount).replace("${y}", response.data.matchedBlockCount);
|
||||
loadingElement.classList.add("fn__none");
|
||||
});
|
||||
}
|
||||
}, Constants.TIMEOUT_SEARCH);
|
||||
return inputTimeout;
|
||||
};
|
||||
|
||||
const onSearch = (data: IBlock[], edit: Protyle, element: Element) => {
|
||||
let resultHTML = "";
|
||||
data.forEach((item, index) => {
|
||||
const title = escapeHtml(getNotebookName(item.box)) + getDisplayName(item.hPath, false);
|
||||
resultHTML += `<div data-type="search-item" class="b3-list-item${index === 0 ? " b3-list-item--focus" : ""}" data-node-id="${item.id}" data-root-id="${item.rootID}">
|
||||
<svg class="b3-list-item__graphic"><use xlink:href="#${getIconByType(item.type)}"></use></svg>
|
||||
<span class="b3-list-item__text">${unicode2Emoji(item.ial.icon)}${item.ial.icon ? " " : ""}${item.content}</span>
|
||||
<span class="b3-list-item__meta b3-list-item__meta--ellipsis" title="${title}">${title}</span>
|
||||
</div>`;
|
||||
});
|
||||
|
||||
if (data[0]) {
|
||||
if (edit) {
|
||||
edit.protyle.element.classList.remove("fn__none");
|
||||
} else {
|
||||
element.querySelector("#searchPreview").classList.remove("fn__none");
|
||||
}
|
||||
const contentElement = document.createElement("div");
|
||||
contentElement.innerHTML = data[0].content;
|
||||
getArticle({
|
||||
edit,
|
||||
id: data[0].id,
|
||||
k: getKey(contentElement),
|
||||
});
|
||||
} else {
|
||||
if (edit) {
|
||||
edit.protyle.element.classList.add("fn__none");
|
||||
} else {
|
||||
element.querySelector("#searchPreview").classList.add("fn__none");
|
||||
}
|
||||
}
|
||||
element.querySelector("#searchList").innerHTML = resultHTML || `<div class="b3-list--empty">${window.siyuan.languages.emptyContent}</div>`;
|
||||
};
|
||||
|
|
|
|||
25
app/src/types/index.d.ts
vendored
25
app/src/types/index.d.ts
vendored
|
|
@ -48,6 +48,31 @@ interface Window {
|
|||
hideKeyboardToolbar(): void
|
||||
}
|
||||
|
||||
interface ISearchOption {
|
||||
hasReplace: boolean,
|
||||
querySyntax: boolean,
|
||||
hPath: string
|
||||
notebookId: string
|
||||
idPath: string
|
||||
k: string
|
||||
r: string
|
||||
replaceList?: string[]
|
||||
list?: string[]
|
||||
types: {
|
||||
mathBlock: boolean
|
||||
table: boolean
|
||||
blockquote: boolean
|
||||
superBlock: boolean
|
||||
paragraph: boolean
|
||||
document: boolean
|
||||
heading: boolean
|
||||
list: boolean
|
||||
listItem: boolean
|
||||
codeBlock: boolean
|
||||
htmlBlock: boolean
|
||||
}
|
||||
}
|
||||
|
||||
interface ITextOption {
|
||||
color?: string,
|
||||
type: string
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue