Skip to content
This repository was archived by the owner on Jul 28, 2025. It is now read-only.

Commit ec26328

Browse files
committed
Merge branch '706-fr-multi-tab-support'
2 parents 77ce43a + c8170c9 commit ec26328

File tree

6 files changed

+161
-55
lines changed

6 files changed

+161
-55
lines changed

src/helpers/VaultManagement.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ export async function sourceDataviewPages(ddbbConfig: LocalSettings, folderPath:
115115
let pagesResult: DataArray<Record<string, Literal>>;
116116
switch (ddbbConfig.source_data) {
117117
case SourceDataTypes.TAG:
118-
pagesResult = DataviewService.getDataviewAPI().pages(`#${ddbbConfig.source_form_result}`);
118+
pagesResult = DataviewService.getDataviewAPI().pages(`${ddbbConfig.source_form_result.split(',').join(' OR ')}`);
119119
break;
120120
case SourceDataTypes.INCOMING_LINK:
121121
pagesResult = DataviewService.getDataviewAPI().pages(`[[${ddbbConfig.source_form_result}]]`);

src/settings/handlers/source/SourceFormHandler.ts

Lines changed: 8 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -8,17 +8,19 @@ import { Notice, Setting } from "obsidian";
88
import { DataviewService } from "services/DataviewService";
99
import { AbstractSettingsHandler, SettingHandlerResponse } from "settings/handlers/AbstractSettingHandler";
1010
import { FileSuggest } from "settings/suggesters/FileSuggester";
11-
import { FolderSuggest } from "settings/suggesters/FolderSuggester";
12-
import { StringSuggest } from "settings/suggesters/StringSuggester";
11+
import { destinationFolderSetting } from "./flavours/Helpers";
12+
import { TagSourceBuilder } from "./flavours/TagsSourceBuilder";
1313

1414
export class SourceFormHandler extends AbstractSettingsHandler {
1515
settingTitle = t("settings_source_form_title");
1616
private sourceFormResultTimeout: NodeJS.Timeout;
17+
tagsLabel: HTMLSpanElement;
18+
tagsContainer: HTMLParagraphElement;
1719
handle(settingHandlerResponse: SettingHandlerResponse): SettingHandlerResponse {
1820
const { containerEl, view, columns } = settingHandlerResponse;
1921
switch (view.diskConfig.yaml.config.source_data) {
2022
case SourceDataTypes.TAG:
21-
this.tagHandler(view, containerEl);
23+
new TagSourceBuilder(view, containerEl).build();
2224
break;
2325
case SourceDataTypes.OUTGOING_LINK:
2426
case SourceDataTypes.INCOMING_LINK:
@@ -29,39 +31,9 @@ export class SourceFormHandler extends AbstractSettingsHandler {
2931
default:
3032
//Current folder
3133
}
32-
3334
return this.goNext(settingHandlerResponse);
3435
}
3536

36-
private tagHandler(view: DatabaseView, containerEl: HTMLElement) {
37-
const tagArray: Record<string, number> = (app.metadataCache as unknown as any).getTags();
38-
if (tagArray) {
39-
const tagRecords: Record<string, string> = {};
40-
// Order tagRecord by key (tag name)
41-
Object.entries(tagArray)
42-
.sort((a, b) => a[0].localeCompare(b[0]))
43-
.forEach(([key, value]) => {
44-
tagRecords[key] = `${key}(${value})`;
45-
});
46-
const source_form_promise = async (value: string): Promise<void> => {
47-
// update settings
48-
view.diskConfig.updateConfig({ source_form_result: value.slice(1) });
49-
};
50-
new Setting(containerEl)
51-
.setName(t("settings_source_form_tag_title"))
52-
.setDesc(t("settings_source_form_tag_desc"))
53-
.addSearch((cb) => {
54-
new StringSuggest(
55-
cb.inputEl,
56-
tagRecords
57-
);
58-
cb.setPlaceholder(t("settings_source_form_tag_placeholder"))
59-
.setValue(`#${view.diskConfig.yaml.config.source_form_result}`)
60-
.onChange(source_form_promise);
61-
});
62-
this.destinationFolderHandler(view, containerEl);
63-
}
64-
}
6537

6638
private outgoingAndIncomingHandler(view: DatabaseView, containerEl: HTMLElement) {
6739
const source_form_promise = async (value: string): Promise<void> => {
@@ -80,7 +52,7 @@ export class SourceFormHandler extends AbstractSettingsHandler {
8052
.setValue(view.diskConfig.yaml.config.source_form_result)
8153
.onChange(source_form_promise);
8254
});
83-
this.destinationFolderHandler(view, containerEl);
55+
destinationFolderSetting(view, containerEl);
8456
}
8557

8658
private queryHandler(view: DatabaseView, containerEl: HTMLElement, columns: TableColumn[]) {
@@ -95,6 +67,7 @@ export class SourceFormHandler extends AbstractSettingsHandler {
9567
}, 1500);
9668

9769
};
70+
9871
new Setting(containerEl)
9972
.setName(t("settings_source_form_query_title"))
10073
.setDesc(t("settings_source_form_query_desc"))
@@ -121,25 +94,7 @@ export class SourceFormHandler extends AbstractSettingsHandler {
12194
}
12295
});
12396
});
124-
this.destinationFolderHandler(view, containerEl);
125-
}
126-
127-
private destinationFolderHandler(view: DatabaseView, containerEl: HTMLElement) {
128-
const source_form_promise = async (value: string): Promise<void> => {
129-
// update settings
130-
view.diskConfig.updateConfig({ source_destination_path: value });
131-
};
132-
new Setting(containerEl)
133-
.setName(t("settings_source_form_destination_title"))
134-
.setDesc(t("settings_source_form_destination_desc"))
135-
.addSearch((cb) => {
136-
new FolderSuggest(
137-
cb.inputEl
138-
);
139-
cb.setPlaceholder(t("settings_source_form_destination_placeholder"))
140-
.setValue(view.diskConfig.yaml.config.source_destination_path)
141-
.onChange(source_form_promise);
142-
});
97+
destinationFolderSetting(view, containerEl);
14398
}
14499
}
145100

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import { DatabaseView } from "DatabaseView";
2+
import { t } from "lang/helpers";
3+
import { Setting } from "obsidian";
4+
import { FolderSuggest } from "settings/suggesters/FolderSuggester";
5+
6+
export function destinationFolderSetting(view: DatabaseView, containerEl: HTMLElement) {
7+
const source_form_promise = async (value: string): Promise<void> => {
8+
// update settings
9+
view.diskConfig.updateConfig({ source_destination_path: value });
10+
};
11+
new Setting(containerEl)
12+
.setName(t("settings_source_form_destination_title"))
13+
.setDesc(t("settings_source_form_destination_desc"))
14+
.addSearch((cb) => {
15+
new FolderSuggest(
16+
cb.inputEl
17+
);
18+
cb.setPlaceholder(t("settings_source_form_destination_placeholder"))
19+
.setValue(view.diskConfig.yaml.config.source_destination_path)
20+
.onChange(source_form_promise);
21+
});
22+
}
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
import { DatabaseView } from "DatabaseView";
2+
import { t } from "lang/helpers";
3+
import { Setting } from "obsidian";
4+
import { StringSuggest } from "settings/suggesters/StringSuggester";
5+
import { destinationFolderSetting } from "./Helpers";
6+
7+
export class TagSourceBuilder {
8+
settingTitle = t("settings_source_form_title");
9+
tagsLabel: HTMLSpanElement;
10+
tagsContainer: HTMLParagraphElement;
11+
tagRecords: Record<string, string> = {};
12+
selectedTags: string[] = [];
13+
14+
constructor(private view: DatabaseView, private containerEl: HTMLElement) { }
15+
/**
16+
* TAGs custom settings
17+
* @param view
18+
* @param containerEl
19+
* @param columns
20+
*/
21+
public build() {
22+
this.initSuggestions();
23+
let suggester: StringSuggest;
24+
25+
new Setting(this.containerEl)
26+
.setName("Data Source Tags")
27+
.setDesc("Select the tags you want as data source. You can add multiple tags.")
28+
.addSearch((cb) => {
29+
suggester = new StringSuggest(
30+
cb.inputEl,
31+
this.tagRecords
32+
);
33+
cb.setPlaceholder("Select a tag")
34+
.onChange(async (value: string): Promise<void> => {
35+
if (value && this.tagRecords[value]) {
36+
// update settings
37+
this.selectedTags.push(value);
38+
suggester.removeSuggestion(value);
39+
cb.setValue("");
40+
await this.view.diskConfig.updateConfig(
41+
{ source_form_result: this.selectedTags.join(",") }
42+
);
43+
this.renderTags();
44+
}
45+
});
46+
47+
cb.inputEl.style.width = "auto";
48+
}).addExtraButton((button) => {
49+
button.setIcon("cross")
50+
.setTooltip("Clear all tags")
51+
.onClick(async () => {
52+
// Clear all tags
53+
this.selectedTags = [];
54+
this.initSuggestions();
55+
suggester.setSuggestions(this.tagRecords);
56+
await this.view.diskConfig.updateConfig({
57+
source_form_result: ""
58+
});
59+
this.tagsLabel.innerHTML = "None";
60+
this.tagsContainer.style.display = "none";
61+
});
62+
});
63+
this.configureTagDisplay();
64+
destinationFolderSetting(this.view, this.containerEl);
65+
}
66+
67+
private configureTagDisplay = () => {
68+
this.tagsContainer = this.containerEl.createEl("div");
69+
const label = this.containerEl.createEl("span", {
70+
text: "Selected Tags: ",
71+
});
72+
label.style.color = "#666";
73+
this.tagsContainer.appendChild(label);
74+
75+
this.tagsLabel = this.containerEl.createEl("span");
76+
this.tagsContainer.appendChild(this.tagsLabel);
77+
this.tagsContainer.style.gap = "15px";
78+
this.tagsContainer.style.marginBottom = "20px";
79+
this.renderTags();
80+
};
81+
82+
private renderTags = () => {
83+
if (this.selectedTags.length) {
84+
this.tagsLabel.innerHTML =
85+
this.selectedTags
86+
.map((v) => `<span style='color: #999;'>${v}</span>`)
87+
.join("<span style='color: #666;'> OR </span>") || "None";
88+
this.tagsContainer.style.display = "flex";
89+
} else {
90+
this.tagsContainer.style.display = "none";
91+
}
92+
};
93+
94+
private initSuggestions = () => {
95+
const tagArray: Record<string, number> = app.metadataCache.getTags();
96+
const source_form_result = this.view.diskConfig.yaml.config.source_form_result;
97+
this.selectedTags = source_form_result ? source_form_result.split(",") : [];
98+
99+
// Order tagRecord by key (tag name)
100+
Object.entries(tagArray)
101+
.sort((a, b) => a[0].localeCompare(b[0]))
102+
.filter(([key,]) => !this.selectedTags.contains(key))
103+
.forEach(([key, value]) => {
104+
this.tagRecords[key] = `${key}(${value})`;
105+
});
106+
}
107+
}
108+

src/settings/suggesters/StringSuggester.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,4 +33,14 @@ export class StringSuggest extends TextInputSuggest<String> {
3333
this.inputEl.trigger("input");
3434
this.close();
3535
}
36+
37+
setSuggestions(suggestions: Record<string, string>): StringSuggest {
38+
this.rawARecord = suggestions;
39+
return this;
40+
}
41+
42+
removeSuggestion(string: string): StringSuggest {
43+
delete this.rawARecord[string];
44+
return this;
45+
}
3646
}

src/typings/obsidian.d.ts

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,20 @@ declare module "obsidian" {
2020

2121
interface Vault {
2222
/**
23-
* TODO: This is a temporary solution. Obsidian not expose official API to get the config.
23+
* Returns internal config of Obsidian using the associated key.
24+
*
25+
* WARNING! not exposed by Obsidian, may break in future.
2426
* @param param
2527
*/
2628
getConfig(param: string): any;
2729
}
30+
31+
interface MetadataCache {
32+
/**
33+
* Obtain the tags of all the vault with their count.
34+
*
35+
* WARNING! not exposed by Obsidian, may break in future.
36+
*/
37+
getTags(): Record<string, number>;
38+
}
2839
}

0 commit comments

Comments
 (0)