mirror of
https://github.com/jacobtread/obsidian-timekeep.git
synced 2026-07-22 10:10:27 +00:00
feat: handle focusing existing leaves
Handles finding and focusing existing leaves if they are present instead of creating new ones
This commit is contained in:
parent
bc913c8218
commit
734113bce4
4 changed files with 120 additions and 20 deletions
|
|
@ -523,7 +523,18 @@ export const MockNotice = vi.fn(
|
|||
}
|
||||
);
|
||||
|
||||
export class MockMarkdownView {
|
||||
export class MockWorkspaceLeaf {
|
||||
view: unknown;
|
||||
openFile = vi.fn().mockResolvedValue(undefined);
|
||||
}
|
||||
|
||||
export class MockFileView {
|
||||
file: TFile | null = null;
|
||||
}
|
||||
|
||||
export class MockEditableFileView extends MockFileView {}
|
||||
|
||||
export class MockMarkdownView extends MockEditableFileView {
|
||||
editor = {
|
||||
setCursor: vi.fn(),
|
||||
scrollIntoView: vi.fn(),
|
||||
|
|
|
|||
|
|
@ -3,6 +3,8 @@ import { afterEach, beforeEach, vi } from "vitest";
|
|||
import {
|
||||
MockButtonComponent,
|
||||
MockComponent,
|
||||
MockEditableFileView,
|
||||
MockFileView,
|
||||
MockMarkdownView,
|
||||
MockModal,
|
||||
MockNotice,
|
||||
|
|
@ -43,5 +45,7 @@ vi.mock("obsidian", () => {
|
|||
ButtonComponent: MockButtonComponent,
|
||||
MarkdownView: MockMarkdownView,
|
||||
Platform: MockPlatform,
|
||||
FileView: MockFileView,
|
||||
EditableFileView: MockEditableFileView
|
||||
};
|
||||
});
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import moment from "moment";
|
|||
import { v4 } from "uuid";
|
||||
import { describe, vi, it, expect } from "vitest";
|
||||
|
||||
import { MockMarkdownView, MockVault } from "@/__mocks__/obsidian";
|
||||
import { MockMarkdownView, MockVault, MockWorkspaceLeaf } from "@/__mocks__/obsidian";
|
||||
import { defaultSettings, TimekeepSettings } from "@/settings";
|
||||
import { createStore } from "@/store";
|
||||
import { createCodeBlock } from "@/utils/codeblock";
|
||||
|
|
@ -761,19 +761,19 @@ describe("TimekeepRegistry", () => {
|
|||
type: TimekeepEntryItemType.FILE,
|
||||
};
|
||||
|
||||
const openFile = vi.fn().mockResolvedValue(undefined);
|
||||
const leaf = new MockWorkspaceLeaf();
|
||||
leaf.view = new MockMarkdownView();
|
||||
|
||||
const workspace = {
|
||||
getLeaf() {
|
||||
const view = new MockMarkdownView();
|
||||
(view as any).openFile = openFile;
|
||||
return view;
|
||||
return leaf;
|
||||
},
|
||||
getLeavesOfType: vi.fn(() => []),
|
||||
} as any as Workspace;
|
||||
|
||||
await TimekeepRegistry.openItemRef(workspace, ref);
|
||||
|
||||
expect(openFile).toHaveBeenCalled();
|
||||
expect(leaf.openFile).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("should attempt to open the file in a new tab", async () => {
|
||||
|
|
@ -784,21 +784,73 @@ describe("TimekeepRegistry", () => {
|
|||
type: TimekeepEntryItemType.FILE,
|
||||
};
|
||||
|
||||
const openFile = vi.fn().mockResolvedValue(undefined);
|
||||
const getLeaf = vi.fn(() => {
|
||||
const leaf = new MockWorkspaceLeaf();
|
||||
leaf.view = new MockMarkdownView();
|
||||
|
||||
const fakeLeaf = () => {
|
||||
const leaf = new MockWorkspaceLeaf();
|
||||
const view = new MockMarkdownView();
|
||||
(view as any).openFile = openFile;
|
||||
return view;
|
||||
leaf.view = view;
|
||||
return leaf;
|
||||
};
|
||||
|
||||
const getLeavesOfType = vi.fn(() => {
|
||||
return [fakeLeaf(), fakeLeaf(), fakeLeaf(), new MockMarkdownView()];
|
||||
});
|
||||
|
||||
const getLeaf = vi.fn(() => {
|
||||
return leaf;
|
||||
});
|
||||
const workspace = {
|
||||
getLeaf,
|
||||
getLeavesOfType,
|
||||
} as any as Workspace;
|
||||
|
||||
await TimekeepRegistry.openItemRef(workspace, ref, true);
|
||||
|
||||
expect(getLeaf).toHaveBeenCalledWith("tab");
|
||||
expect(openFile).toHaveBeenCalled();
|
||||
expect(leaf.openFile).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("should focus the existing file instead of opening a new tab if one is present", async () => {
|
||||
const vault = new MockVault();
|
||||
const testFile = vault.addFile("test.timekeep", "");
|
||||
const ref: TimekeepRegistryItemRef = {
|
||||
file: testFile,
|
||||
type: TimekeepEntryItemType.FILE,
|
||||
};
|
||||
|
||||
const existingLeaf = new MockWorkspaceLeaf();
|
||||
const view = new MockMarkdownView();
|
||||
view.file = testFile;
|
||||
existingLeaf.view = view;
|
||||
|
||||
const revealLeaf = vi.fn().mockResolvedValue(undefined);
|
||||
const setActiveLeaf = vi.fn().mockResolvedValue(undefined);
|
||||
const getLeaf = vi.fn(() => {
|
||||
const existingLeaf = new MockWorkspaceLeaf();
|
||||
const view = new MockMarkdownView();
|
||||
existingLeaf.view = view;
|
||||
return existingLeaf;
|
||||
});
|
||||
const getLeavesOfType = vi.fn(() => {
|
||||
return [existingLeaf];
|
||||
});
|
||||
|
||||
const workspace = {
|
||||
getLeaf,
|
||||
getLeavesOfType,
|
||||
revealLeaf,
|
||||
setActiveLeaf,
|
||||
} as any as Workspace;
|
||||
|
||||
await TimekeepRegistry.openItemRef(workspace, ref, true);
|
||||
|
||||
expect(getLeavesOfType).toHaveBeenCalledWith("timekeep");
|
||||
expect(getLeaf).not.toHaveBeenCalled();
|
||||
expect(existingLeaf.openFile).not.toHaveBeenCalled();
|
||||
expect(revealLeaf).toHaveBeenCalledWith(existingLeaf);
|
||||
expect(setActiveLeaf).toHaveBeenCalledWith(existingLeaf, { focus: true });
|
||||
});
|
||||
|
||||
it("opening a markdown entry should scroll to the specific timekeep position", async () => {
|
||||
|
|
@ -810,18 +862,19 @@ describe("TimekeepRegistry", () => {
|
|||
position: { startLine: 1, endLine: 2 },
|
||||
};
|
||||
|
||||
const openFile = vi.fn().mockResolvedValue(undefined);
|
||||
|
||||
const leaf = new MockWorkspaceLeaf();
|
||||
const view = new MockMarkdownView();
|
||||
leaf.view = view;
|
||||
|
||||
const workspace = {
|
||||
getLeaf() {
|
||||
return { view, openFile };
|
||||
return leaf;
|
||||
},
|
||||
getLeavesOfType: vi.fn(() => []),
|
||||
} as any as Workspace;
|
||||
|
||||
await TimekeepRegistry.openItemRef(workspace, ref);
|
||||
expect(openFile).toHaveBeenCalled();
|
||||
expect(leaf.openFile).toHaveBeenCalled();
|
||||
|
||||
const line = ref.position.startLine;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import type { EventRef, TAbstractFile, Vault, Workspace } from "obsidian";
|
||||
import type { EventRef, TAbstractFile, Vault, Workspace, WorkspaceLeaf } from "obsidian";
|
||||
|
||||
import moment from "moment";
|
||||
import { Component, MarkdownView, TFile } from "obsidian";
|
||||
import { EditableFileView, Component, MarkdownView, TFile } from "obsidian";
|
||||
import { limitFunction } from "p-limit";
|
||||
|
||||
import type { TimekeepSettings } from "@/settings";
|
||||
|
|
@ -380,6 +380,28 @@ export class TimekeepRegistry extends Component {
|
|||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks the workspace leaves to see if the provided timekeep item
|
||||
* ref is already open in a file
|
||||
*
|
||||
* @param workspace The workspace to check within
|
||||
* @param ref The reference to the timekeep
|
||||
* @returns The existing leaf if found
|
||||
*/
|
||||
private static getExistingRefLeaf(workspace: Workspace, ref: TimekeepRegistryItemRef) {
|
||||
const leavesType = ref.type === TimekeepEntryItemType.FILE ? "timekeep" : "markdown";
|
||||
const leaves = workspace.getLeavesOfType(leavesType);
|
||||
|
||||
for (const leaf of leaves) {
|
||||
const view = leaf.view;
|
||||
if (view instanceof EditableFileView && view.file && view.file.path === ref.file.path) {
|
||||
return leaf;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens a timekeep by reference to the file and the
|
||||
* line within the file for markdown timekeep items
|
||||
|
|
@ -392,8 +414,18 @@ export class TimekeepRegistry extends Component {
|
|||
ref: TimekeepRegistryItemRef,
|
||||
newTab: boolean = false
|
||||
) {
|
||||
const leaf = workspace.getLeaf(newTab ? "tab" : false);
|
||||
await leaf.openFile(ref.file);
|
||||
let leaf: WorkspaceLeaf | null = TimekeepRegistry.getExistingRefLeaf(workspace, ref);
|
||||
|
||||
// Focus and reveal the existing leaf if found
|
||||
if (leaf !== null) {
|
||||
workspace.setActiveLeaf(leaf, { focus: true });
|
||||
await workspace.revealLeaf(leaf);
|
||||
}
|
||||
// Open a new leaf for the ref
|
||||
else {
|
||||
leaf = workspace.getLeaf(newTab ? "tab" : false);
|
||||
await leaf.openFile(ref.file);
|
||||
}
|
||||
|
||||
const view = leaf.view;
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue