feat: support preview and editing in modal

This commit is contained in:
Quorafind 2023-03-17 07:58:15 +08:00
parent 8460417e93
commit 70129f71d5
4 changed files with 146 additions and 23 deletions

View file

@ -7,7 +7,7 @@ import {
WorkspaceContainer, WorkspaceItem,
WorkspaceLeaf
} from 'obsidian';
import { EmbeddedView, isDailyNoteLeaf, spawnLeafView } from "./leafView";
import { EmbeddedView, isEmebeddedLeaf, spawnLeafView } from "./leafView";
import { around } from "monkey-around";
export default class FloatSearchPlugin extends Plugin {
@ -106,12 +106,12 @@ export default class FloatSearchPlugin extends Plugin {
setPinned(old) {
return function (pinned: boolean) {
old.call(this, pinned);
if(isDailyNoteLeaf(this) && !pinned) this.setPinned(true);
if(isEmebeddedLeaf(this) && !pinned) this.setPinned(true);
}
},
openFile(old) {
return function (file: TFile, openState?: OpenViewState) {
if (isDailyNoteLeaf(this)) {
if (isEmebeddedLeaf(this)) {
setTimeout(
around(Workspace.prototype, {
recordMostRecentOpenedFile(old) {
@ -150,8 +150,13 @@ export default class FloatSearchPlugin extends Plugin {
class FloatSearchModal extends Modal {
private readonly plugin: FloatSearchPlugin;
private embeddedView: EmbeddedView;
private leaf: WorkspaceLeaf;
private searchEmbeddedView: EmbeddedView;
private fileEmbeddedView: EmbeddedView;
private searchLeaf: WorkspaceLeaf;
private fileLeaf: WorkspaceLeaf | undefined;
private searchCtnEl: HTMLElement;
private fileEl: HTMLElement;
constructor(app: App, plugin: FloatSearchPlugin) {
super(app);
@ -159,34 +164,38 @@ class FloatSearchModal extends Modal {
}
async onOpen() {
const { contentEl } = this;
const { contentEl, containerEl, modalEl } = this;
this.initCss(contentEl);
await this.initView(contentEl);
this.searchCtnEl = contentEl.createDiv({ cls: "float-search-modal-search-ctn" });
this.initCss(contentEl, modalEl, containerEl);
await this.initSearchView(this.searchCtnEl);
this.initInput();
this.initContent();
}
onClose() {
const { contentEl } = this;
this.leaf.detach();
this.embeddedView.unload();
this.searchLeaf.detach();
this.fileLeaf?.detach();
this.searchEmbeddedView.unload();
this.fileEmbeddedView?.unload();
contentEl.empty();
}
initCss(contentEl: HTMLElement) {
contentEl.classList.add("float-search-modal");
contentEl.parentElement?.classList.add("float-search-modal-parent");
contentEl.parentElement?.parentElement?.classList.add("float-search-modal-container");
initCss(contentEl: HTMLElement, modalEl: HTMLElement, containerEl: HTMLElement) {
contentEl.classList.add("float-search-modal-content");
modalEl.classList.add("float-search-modal");
containerEl.classList.add("float-search-modal-container");
}
async initView(contentEl: HTMLElement) {
async initSearchView(contentEl: HTMLElement) {
const [createdLeaf, embeddedView] = spawnLeafView(this.plugin, contentEl);
this.leaf = createdLeaf;
this.embeddedView = embeddedView;
this.searchLeaf = createdLeaf;
this.searchEmbeddedView = embeddedView;
this.leaf.setPinned(true);
await this.leaf.setViewState({
this.searchLeaf.setPinned(true);
await this.searchLeaf.setViewState({
type: "search",
});
}
@ -195,7 +204,7 @@ class FloatSearchModal extends Modal {
const inputEl = this.contentEl.getElementsByTagName("input")[0];
inputEl.focus();
inputEl.onkeydown = (e) => {
const currentView = this.leaf.view as SearchView;
const currentView = this.searchLeaf.view as SearchView;
switch (e.key) {
case "ArrowDown":
if (e.shiftKey) {
@ -225,6 +234,29 @@ class FloatSearchModal extends Modal {
this.close();
}
break;
case "Tab":
if(e.shiftKey) {
if(this.fileLeaf) {
this.fileLeaf?.detach();
this.fileLeaf = undefined;
this.fileEmbeddedView?.unload();
this.modalEl.toggleClass("float-search-width", false);
this.fileEl.detach();
break;
}
}
if(currentView.dom.focusedItem) {
const item = currentView.dom.focusedItem;
const file = item.parent.file instanceof TFile ? item.parent.file : item.file;
item.parent.file instanceof TFile ? this.initFileView(file, {match: {
content: item.content,
matches: item.matches
}}) : this.initFileView(file, undefined);
}
break;
}
}
}
@ -237,17 +269,83 @@ class FloatSearchModal extends Modal {
return;
}
if(this.fileLeaf) {
let targetElement = e.target as HTMLElement | null;
if((this.searchCtnEl as Node).contains(targetElement as Node)) {
while (targetElement) {
if (targetElement.classList.contains('tree-item')) {
console.log(targetElement);
break;
}
targetElement = targetElement.parentElement;
}
const fileInnerEl = targetElement?.getElementsByClassName("tree-item-inner")[0] as HTMLElement;
const innerText = fileInnerEl.innerText;
const file = app.metadataCache.getFirstLinkpathDest(innerText, "");
const currentView = this.searchLeaf.view as SearchView;
if(file) {
const item = currentView.dom.resultDomLookup.get(file);
console.log(item);
currentView.dom.setFocusedItem(item);
this.initFileView(file, undefined);
(this.searchLeaf.view as SearchView).searchComponent.inputEl.focus();
}
}
return;
}
console.log(e.target);
const target = e.target as HTMLElement;
const classList = target.classList;
const navElement = contentEl.getElementsByClassName('nav-header')[0];
if (e.target !== navElement && navElement.contains(e.target as Node)) {
if (e.target !== navElement && (navElement as Node).contains(e.target as Node)) {
return;
}
if(!(classList.contains("tree-item-icon") || classList.contains("float-search-modal") || classList.contains("right-triangle") || target.parentElement?.classList.contains("right-triangle") || classList.contains("search-input-container") || target?.parentElement?.classList.contains("search-input-container") || classList.contains("search-result-hover-button"))) {
const fileElement = contentEl.getElementsByClassName('float-search-modal-file-ctn')[0];
if ((fileElement as Node)?.contains(e.target as Node)) {
return;
}
if(!(classList.contains("tree-item-icon") || classList.contains("float-search-modal-content") || classList.contains("right-triangle") || target.parentElement?.classList.contains("right-triangle") || classList.contains("search-input-container") || target?.parentElement?.classList.contains("search-input-container") || classList.contains("search-result-hover-button"))) {
this.close();
}
}
}
async initFileView(file: TFile, state: any) {
if(this.fileLeaf) {
await this.fileLeaf.openFile(file, {
active: false,
eState: state
});
setTimeout(() => {
(this.searchLeaf.view as SearchView).searchComponent.inputEl.focus();
}, 0);
return;
}
const { contentEl } = this;
this.fileEl = contentEl.createDiv({ cls: "float-search-modal-file-ctn" });
this.modalEl.toggleClass("float-search-width", true);
const [createdLeaf, embeddedView] = spawnLeafView(this.plugin, this.fileEl);
this.fileLeaf = createdLeaf;
this.fileEmbeddedView = embeddedView;
this.fileLeaf.setPinned(true);
await this.fileLeaf.openFile(file, {
active: false,
eState: state
});
(this.searchLeaf.view as SearchView).searchComponent.inputEl.focus();
}
}

View file

@ -31,7 +31,7 @@ export interface EmbeddedViewParent {
const popovers = new WeakMap<Element, EmbeddedView>();
type ConstructableWorkspaceSplit = new (ws: Workspace, dir: "horizontal"|"vertical") => WorkspaceSplit;
export function isDailyNoteLeaf(leaf: WorkspaceLeaf) {
export function isEmebeddedLeaf(leaf: WorkspaceLeaf) {
// Work around missing enhance.js API by checking match condition instead of looking up parent
return leaf.containerEl.matches(".fs-block.fs-leaf-view .workspace-leaf");
}

View file

@ -154,6 +154,7 @@ declare module "obsidian" {
onKeyShowMoreBefore(e: KeyboardEvent): void;
onKeyShowMoreAfter(e: KeyboardEvent): void;
dom: any;
searchComponent: SearchComponent;
}
interface EmptyView extends View {

View file

@ -7,7 +7,27 @@ If your plugin does not need CSS, delete this file.
*/
.float-search-modal {
width: 600px;
}
.float-search-modal.float-search-width {
width: 1200px;
}
.float-search-modal-search-ctn, .float-search-modal-file-ctn {
height: 100%;
width: 100%;
}
.float-search-modal-file-ctn .view-header {
display: none;
}
.float-search-modal-content {
height: 800px;
display: flex;
align-items: center;
flex-direction: row;
}
.fs-content .workspace-split.mod-vertical {
@ -18,6 +38,10 @@ If your plugin does not need CSS, delete this file.
height: 100%;
}
.fs-content .cm-scroller {
margin-top: 20px;
}
.fs-block {
height: 100% !important;
}