Skip to content

Commit 6e55e74

Browse files
committed
Update ExplorerSort feature
1 parent 4fa8e84 commit 6e55e74

File tree

8 files changed

+51
-73
lines changed

8 files changed

+51
-73
lines changed

docs/Processor.md

+5
Original file line numberDiff line numberDiff line change
@@ -50,13 +50,18 @@ A value returned by your function will be used as shown title
5050

5151
Works same as [Function](#function), but the argument is the object instead of string;
5252
Object your function will give an argument:
53+
5354
```typescript
5455
// Object that will be given into FunctionV2 processor as an "obj" argument
56+
import {TFile} from "obsidian";
57+
5558
export type FunctionV2ObjArg = {
5659
// New file title
5760
title: string;
5861
// Path to file
5962
path: string;
63+
// Obisian's TFile
64+
file: TFile | null;
6065
};
6166
```
6267

manifest.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"id": "obsidian-front-matter-title-plugin",
33
"name": "Front Matter Title",
4-
"version": "3.11.0",
4+
"version": "3.12.0",
55
"minAppVersion": "1.7.4",
66
"description": "Lets you define a title in frontmatter to be displayed as the filename for explorer, graph, search and etc.",
77
"author": "Snezhig",

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "obsidian-front-matter-title",
3-
"version": "3.11.0",
3+
"version": "3.12.0",
44
"description": "This is a sample plugin for Obsidian (https://obsidian.md)",
55
"main": "main.js",
66
"scripts": {

src/Feature/Explorer/ExplorerManager.ts

+9-5
Original file line numberDiff line numberDiff line change
@@ -64,13 +64,19 @@ export default class ExplorerManager extends AbstractManager {
6464
this.setState(State.Disabled);
6565
}
6666

67+
private tryEnable(): void {
68+
this.sort?.start();
69+
this.setState(State.Enabled);
70+
this.logger.log("Manager enabled");
71+
}
72+
6773
private subscribe(): void {
6874
const ref = this.dispatcher.addListener({
6975
name: "active:leaf:change",
7076
cb: () => {
7177
if (this.isEnabled() && this.getExplorerView()) {
7278
this.logger.log("Catch explorer view");
73-
this.setState(State.Enabled);
79+
this.tryEnable();
7480
this.doRefresh().catch(this.logger.log);
7581
this.dispatcher.removeListener(ref);
7682
} else if (!this.isEnabled()) {
@@ -79,21 +85,19 @@ export default class ExplorerManager extends AbstractManager {
7985
}
8086
},
8187
});
88+
this.setState(State.WaitForActiveLeaf);
8289
}
8390

8491
protected doEnable() {
8592
if (!this.facade.isInternalPluginEnabled(Plugins.FileExplorer)) {
8693
this.logger.info(`internal plugin ${Plugins.FileExplorer} is not enabled`);
8794
return;
8895
}
89-
this.sort?.start();
9096
if (!this.getExplorerView()) {
9197
this.logger.log("Could not get view. Subscribe and wait for active leaf");
9298
this.subscribe();
93-
this.setState(State.WaitForActiveLeaf);
9499
} else {
95-
this.logger.log("Manager enabled");
96-
this.setState(State.Enabled);
100+
this.tryEnable();
97101
}
98102
}
99103

src/Feature/Explorer/ExplorerSort.ts

+18-33
Original file line numberDiff line numberDiff line change
@@ -9,16 +9,15 @@ import { Feature, Leaves } from "@src/Enum";
99
import ExplorerViewUndefined from "@src/Feature/Explorer/ExplorerViewUndefined";
1010
import EventDispatcherInterface from "@src/Components/EventDispatcher/Interfaces/EventDispatcherInterface";
1111
import ListenerRef from "@src/Components/EventDispatcher/Interfaces/ListenerRef";
12-
import { ResolverInterface } from "../../Resolver/Interfaces";
12+
import { ResolverInterface } from "@src/Resolver/Interfaces";
1313
import FeatureService from "../FeatureService";
14-
import { DelayerInterface } from "@src/Components/Delayer/Delayer";
15-
import { FunctionReplacerFactory } from "../../../config/inversify.factory.types";
14+
import { FunctionReplacerFactory } from "@config/inversify.factory.types";
1615

1716
@injectable()
1817
export default class ExplorerSort {
1918
private view: TFileExplorerView;
2019
private started = false;
21-
private replacer: FunctionReplacer<TFileExplorerItem, "sort", ExplorerSort>;
20+
private replacer: FunctionReplacer<TFileExplorerView, "getSortedFolderItems", ExplorerSort>;
2221
private readonly cb: (e: { id: string; result?: boolean }) => void;
2322
private refs: [ListenerRef<"manager:refresh">?, ListenerRef<"manager:update">?] = [];
2423
private resolver: ResolverInterface;
@@ -33,10 +32,12 @@ export default class ExplorerSort {
3332
private dispatcher: EventDispatcherInterface<AppEvents>,
3433
@inject(SI["feature:service"])
3534
service: FeatureService,
36-
@inject(SI.delayer)
37-
private readonly delayer: DelayerInterface,
3835
@inject(SI["factory:replacer"])
39-
private readonly replacerFactory: FunctionReplacerFactory<TFileExplorerItem, "sort", ExplorerSort>
36+
private readonly replacerFactory: FunctionReplacerFactory<
37+
TFileExplorerView,
38+
"getSortedFolderItems",
39+
ExplorerSort
40+
>
4041
) {
4142
this.resolver = service.createResolver(Feature.Explorer);
4243
const trigger = debounce(this.onManagerUpdate.bind(this), 1000);
@@ -105,20 +106,15 @@ export default class ExplorerSort {
105106
}
106107
return;
107108
}
108-
const item = this.getFolderItem();
109-
if (!item) {
110-
this.logger.log("Folder item not found. Try again in 1000 ms");
111-
this.delayer.delay(this.tryToReplaceOriginalSort.bind(this), 1000);
112-
return;
113-
}
109+
114110
this.logger.log("Init replacer");
115111

116112
this.replacer = this.replacerFactory(
117-
Object.getPrototypeOf(item),
118-
"sort",
113+
Object.getPrototypeOf(this.view),
114+
"getSortedFolderItems",
119115
this,
120-
function (args, defaultArgs, vanilla) {
121-
args.sort(this, vanilla);
116+
(feature, defaultArgs, vanilla) => {
117+
return feature.getSortedFolderItems(defaultArgs?.[0]) ?? vanilla.call(this);
122118
}
123119
);
124120
this.replacer.enable();
@@ -132,21 +128,19 @@ export default class ExplorerSort {
132128
return order === "alphabetical";
133129
}
134130

135-
private sort(item: TFileExplorerItem, vanilla: () => void) {
131+
private getSortedFolderItems(folder: TFolder): TFileExplorerItem[] | null {
136132
const sortOrder = this.view.sortOrder;
137133

138134
if (!this.isSortSupported(sortOrder)) {
139135
this.logger.log(`Sort is ${sortOrder}. Skipped.`);
140-
vanilla.call(item);
141136
return;
142137
}
143-
if (!(item.file instanceof TFolder)) {
138+
if (!(folder instanceof TFolder)) {
144139
this.logger.log("File is not TFolder. Why? Skipped.");
145-
vanilla.call(item);
146140
return;
147141
}
148-
this.logger.log("Sort by feature");
149-
const children = item.file.children.slice();
142+
143+
const children = folder.children.slice();
150144
const result = [];
151145
children.sort((a, b) => {
152146
const i = a instanceof TFolder;
@@ -169,15 +163,6 @@ export default class ExplorerSort {
169163
const f = this.view.fileItems[child.path];
170164
f && result.push(f);
171165
}
172-
173-
item.vChildren.setChildren(result);
174-
}
175-
176-
private getFolderItem(): TFileExplorerItem {
177-
for (const item of Object.values(this.view.fileItems)) {
178-
if (item.file instanceof TFolder) {
179-
return item;
180-
}
181-
}
166+
return result;
182167
}
183168
}

src/obsidian-ex.d.ts

+2
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,8 @@ declare module "obsidian" {
5959
sortOrder: string;
6060
requestSort: () => void;
6161

62+
getSortedFolderItems: (TFolder) => TFileExplorerItem[];
63+
6264
getDisplayText(): string;
6365

6466
getViewType(): string;

test/unit/Feature/Explorer/ExplorerSort.spec.ts

+13-32
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ import EventDispatcherInterface, {
99
import { AppEvents } from "@src/Types";
1010
import FeatureService from "@src/Feature/FeatureService";
1111
import { ResolverInterface } from "@src/Resolver/Interfaces";
12-
import { DelayerInterface } from "@src/Components/Delayer/Delayer";
1312
import LoggerInterface from "@src/Components/Debug/LoggerInterface";
1413
import { FunctionReplacerFactory } from "@config/inversify.factory.types";
1514
import FunctionReplacer from "../../../../src/Utils/FunctionReplacer";
@@ -21,10 +20,11 @@ let callback: Callback<AppEvents[keyof AppEvents]>;
2120
let dispatcher: MockProxy<EventDispatcherInterface<any>>;
2221
let refs: [any?, any?];
2322
let featureService: MockProxy<FeatureService>;
24-
let delayer: MockProxy<DelayerInterface>;
2523
let sort: ExplorerSort;
2624
let view: MockProxy<TFileExplorerView>;
27-
let replacerFactory: jest.Mock<ReturnType<FunctionReplacerFactory<TFileExplorerItem, "sort", ExplorerSort>>>;
25+
let replacerFactory: jest.Mock<
26+
ReturnType<FunctionReplacerFactory<TFileExplorerView, "getSortedFolderItems", ExplorerSort>>
27+
>;
2828

2929
beforeEach(() => {
3030
refs = [];
@@ -38,12 +38,11 @@ beforeEach(() => {
3838
});
3939
featureService = mock<FeatureService>();
4040
featureService.createResolver.mockReturnValue(mock<ResolverInterface>());
41-
delayer = mock<DelayerInterface>();
4241
view = mock<TFileExplorerView>();
4342
replacerFactory = jest.fn();
4443
// @ts-ignore
4544
view.requestSort = jest.fn();
46-
sort = new ExplorerSort(mock<LoggerInterface>(), facade, dispatcher, featureService, delayer, replacerFactory);
45+
sort = new ExplorerSort(mock<LoggerInterface>(), facade, dispatcher, featureService, replacerFactory);
4746
});
4847

4948
describe("ExplorerSort", () => {
@@ -58,43 +57,25 @@ describe("ExplorerSort", () => {
5857
facade.getViewsOfType.mockReturnValue([view]);
5958
});
6059

61-
test("should add listener after enabled", () => {
62-
sort.start();
63-
expect(sort.isStarted()).toBeTruthy();
64-
expect(dispatcher.addListener).toHaveBeenCalledWith({ name: "manager:update", cb: expect.anything() });
65-
expect(dispatcher.addListener).toHaveBeenCalledWith({ name: "manager:refresh", cb: expect.anything() });
66-
expect(dispatcher.addListener).toHaveBeenCalledTimes(2);
67-
});
68-
//
69-
test("should delay replace because these is not item", () => {
70-
let fn: Function;
71-
//copy delayed function to call it manually
72-
delayer.delay.mockImplementation(f => {
73-
fn = f;
74-
return 0;
75-
});
76-
//enable sort to trigger internal "tryToReplaceOriginalSort"
77-
sort.start();
78-
expect(delayer.delay).toHaveBeenCalledTimes(1);
79-
//Call delayed function
80-
fn();
81-
expect(delayer.delay).toHaveBeenCalledTimes(2);
82-
expect(replacerFactory).not.toBeCalled();
83-
});
84-
8560
describe("with explorer item", () => {
86-
let replacer: FunctionReplacer<TFileExplorerItem, "sort", ExplorerSort>;
61+
let replacer: FunctionReplacer<TFileExplorerView, "getSortedFolderItems", ExplorerSort>;
8762
let item: TFileExplorerItem;
8863
beforeEach(() => {
8964
item = mock<TFileExplorerItem>();
9065
item.file = new TFolder();
91-
replacer = mock<FunctionReplacer<TFileExplorerItem, "sort", ExplorerSort>>();
66+
replacer = mock<FunctionReplacer<TFileExplorerView, "getSortedFolderItems", ExplorerSort>>();
9267
replacerFactory.mockImplementationOnce(() => replacer);
9368
});
69+
70+
afterEach(() => {
71+
expect(dispatcher.addListener).toHaveBeenCalledWith({ name: "manager:update", cb: expect.anything() });
72+
expect(dispatcher.addListener).toHaveBeenCalledWith({ name: "manager:refresh", cb: expect.anything() });
73+
expect(dispatcher.addListener).toHaveBeenCalledTimes(2);
74+
});
75+
9476
test("Should create function replacer without delay, because there is folder item", () => {
9577
view.fileItems["mock"] = item;
9678
sort.start();
97-
expect(delayer.delay).not.toHaveBeenCalled();
9879
expect(replacerFactory).toBeCalled();
9980
expect(replacer.enable).toBeCalled();
10081
});

versions.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -55,5 +55,6 @@
5555
"3.8.4": "0.16.3",
5656
"3.9.0": "1.5.3",
5757
"3.10.0": "1.5.3",
58-
"3.11.0": "1.7.4"
58+
"3.11.0": "1.7.4",
59+
"3.12.0": "1.7.4"
5960
}

0 commit comments

Comments
 (0)