mirror of
https://github.com/quorafind/Obsidian-Float-Search.git
synced 2026-07-22 07:30:25 +00:00
Merge a57a7bfff2 into 16fcf917a6
This commit is contained in:
commit
1d48ab93ec
1 changed files with 94 additions and 3 deletions
|
|
@ -33,6 +33,7 @@ import {
|
|||
import { EmbeddedView, isEmebeddedLeaf, spawnLeafView } from "./leafView";
|
||||
import { around } from "monkey-around";
|
||||
import { debounce } from "obsidian";
|
||||
import { EditorView } from "@codemirror/view";
|
||||
|
||||
type sortOrder =
|
||||
| "alphabetical"
|
||||
|
|
@ -92,6 +93,40 @@ const DEFAULT_SETTINGS: FloatSearchSettings = {
|
|||
cmdkQuickCreateTitleFormat: "YYYYMMDDHHmmss",
|
||||
};
|
||||
|
||||
/**
|
||||
* Scroll matched text to the top of the main editor
|
||||
* @param app - Obsidian app instance
|
||||
* @param matchOffset - Character offset of the match
|
||||
*/
|
||||
function scrollMatchToTop(app: App, matchOffset: number): void {
|
||||
setTimeout(() => {
|
||||
const leaf = app.workspace.getMostRecentLeaf();
|
||||
if (!leaf) return;
|
||||
|
||||
const view = leaf.view;
|
||||
if (!view) return;
|
||||
|
||||
const editor = (view as any).editor;
|
||||
if (!editor) return;
|
||||
|
||||
const cm = (editor as any).cm as EditorView;
|
||||
if (!cm) {
|
||||
// Fallback to Obsidian built-in API (scrolls to center)
|
||||
const pos = editor.offsetToPos(matchOffset);
|
||||
editor.scrollIntoView({ from: pos, to: pos });
|
||||
return;
|
||||
}
|
||||
|
||||
// Use CodeMirror 6 API to scroll to top
|
||||
cm.dispatch({
|
||||
effects: EditorView.scrollIntoView(matchOffset, {
|
||||
y: "start",
|
||||
yMargin: 30,
|
||||
}),
|
||||
});
|
||||
}, 150);
|
||||
}
|
||||
|
||||
const allViews: viewType[] = [
|
||||
{
|
||||
type: "modal",
|
||||
|
|
@ -285,7 +320,8 @@ export default class FloatSearchPlugin extends Plugin {
|
|||
initModal(
|
||||
state: searchState,
|
||||
stateSave: boolean = false,
|
||||
clearQuery: boolean = false
|
||||
clearQuery: boolean = false,
|
||||
fromURI: boolean = false
|
||||
) {
|
||||
if (this.modal) {
|
||||
this.modal.close();
|
||||
|
|
@ -306,6 +342,13 @@ export default class FloatSearchPlugin extends Plugin {
|
|||
{ ...state, query: clearQuery ? "" : state.query }
|
||||
);
|
||||
this.modal.open();
|
||||
|
||||
// 如果是通过URI协议打开且有查询内容,删除"建议容器"
|
||||
if (fromURI && state.query) {
|
||||
setTimeout(() => {
|
||||
document.querySelector('.suggestion-container')?.remove();
|
||||
}, 10);
|
||||
}
|
||||
}
|
||||
|
||||
patchWorkspace() {
|
||||
|
|
@ -917,7 +960,8 @@ export default class FloatSearchPlugin extends Plugin {
|
|||
current: false,
|
||||
},
|
||||
true,
|
||||
false
|
||||
false,
|
||||
true
|
||||
);
|
||||
} else {
|
||||
await initSearchViewWithLeaf(
|
||||
|
|
@ -1798,7 +1842,7 @@ class FloatSearchModal extends Modal {
|
|||
|
||||
initContent() {
|
||||
const { contentEl } = this;
|
||||
contentEl.onclick = (e) => {
|
||||
contentEl.onclick = async (e) => {
|
||||
const resultElement = contentEl.getElementsByClassName(
|
||||
"search-results-children"
|
||||
)[0];
|
||||
|
|
@ -1821,7 +1865,54 @@ class FloatSearchModal extends Modal {
|
|||
break;
|
||||
}
|
||||
if (targetElement.classList.contains("tree-item")) {
|
||||
// Get file info before closing
|
||||
const fileInnerEl = targetElement?.getElementsByClassName(
|
||||
"tree-item-inner"
|
||||
)[0] as HTMLElement;
|
||||
const innerText = fileInnerEl.innerText;
|
||||
const file = this.plugin.app.metadataCache.getFirstLinkpathDest(
|
||||
innerText,
|
||||
""
|
||||
);
|
||||
|
||||
// Get match info
|
||||
const currentView = this.searchLeaf.view as SearchView;
|
||||
const item = currentView.dom.resultDomLookup.get(file);
|
||||
|
||||
// Try to get match offset - find the specific clicked match
|
||||
let matchOffset: number | undefined = undefined;
|
||||
// Get the clicked element and find the match element
|
||||
const clickedEl = e.target as HTMLElement;
|
||||
// Try to get the actual match element (not file element)
|
||||
const matchEl = clickedEl.closest(".search-result-file-match");
|
||||
|
||||
if (matchEl && item?.vChildren?.children) {
|
||||
// Get index among siblings - filter to only match elements
|
||||
const parent = matchEl.parentElement;
|
||||
if (parent) {
|
||||
// Filter to only .search-result-file-match elements
|
||||
const siblings = Array.from(parent.children).filter(
|
||||
(el) => el.classList.contains("search-result-file-match")
|
||||
);
|
||||
const clickedIdx = siblings.indexOf(matchEl);
|
||||
if (clickedIdx >= 0 && clickedIdx < item.vChildren.children.length) {
|
||||
const child = item.vChildren.children[clickedIdx];
|
||||
const childMatch = child?.matches?.[0];
|
||||
if (Array.isArray(childMatch)) {
|
||||
matchOffset = childMatch[0];
|
||||
} else if (typeof childMatch === "number") {
|
||||
matchOffset = childMatch;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.close();
|
||||
|
||||
// Scroll to top if we have a match offset
|
||||
if (matchOffset !== undefined) {
|
||||
scrollMatchToTop(this.plugin.app, matchOffset);
|
||||
}
|
||||
break;
|
||||
}
|
||||
targetElement = targetElement.parentElement;
|
||||
|
|
|
|||
Loading…
Reference in a new issue