Exclude source note from smart folder results

This commit is contained in:
Chenyan Wang 2026-06-28 04:00:30 +08:00
parent 6bbe028b84
commit 5233e26da2
2 changed files with 38 additions and 22 deletions

29
main.js
View file

@ -442,7 +442,7 @@ var SetupModal = class extends obsidian.Modal {
if (!folders.includes(this.draft.sourceFolder)) this.draft.sourceFolder = folders[0] || "";
const templates = this.plugin.getTemplateFileOptions();
if (!templates.includes(this.draft.templateFile)) this.draft.templateFile = templates[0] || "";
const fieldOptions = this.plugin.getFieldCandidates(this.draft.sourceFolder, this.draft.templateFile);
const fieldOptions = this.plugin.getFieldCandidates(this.draft.sourceFolder, this.draft.templateFile, this.draft.sourceNotePath);
if (!fieldOptions.includes(this.draft.colorField)) this.draft.colorField = fieldOptions[0] || "";
if (!fieldOptions.includes(this.draft.sortField)) this.draft.sortField = fieldOptions[0] || "";
if (!fieldOptions.includes(this.draft.boardField)) {
@ -833,7 +833,11 @@ var SmartFolderView = class extends obsidian.ItemView {
getRenderProfile() {
if (!this.pinnedProfile) return this.plugin.getCurrentProfile();
const latest = this.plugin.data.profiles.find((p) => p.id === this.pinnedProfile.id) || this.pinnedProfile;
this.pinnedProfile = { ...latest, displayFields: [...latest.displayFields || []] };
this.pinnedProfile = {
...latest,
sourceNotePath: this.pinnedProfile.sourceNotePath || latest.sourceNotePath || "",
displayFields: [...latest.displayFields || []]
};
return this.pinnedProfile;
}
ensureState(ownerId, defaultSort, defaultViewMode) {
@ -1188,7 +1192,7 @@ var SmartFolderView = class extends obsidian.ItemView {
this.renderView();
new obsidian.Notice(this.plugin.t("refreshPreviewDone"));
});
const files = this.plugin.getFilesByFolder(profile.sourceFolder);
const files = this.plugin.getFilesByFolder(profile.sourceFolder, profile.sourceNotePath);
if (!files.length) {
container.createEl("p", { text: this.plugin.t("noFiles", { folder: profile.sourceFolder }) });
return;
@ -1779,10 +1783,10 @@ var SmartFolderPlugin = class extends obsidian.Plugin {
}
return ["", ...uniqueSorted([...set])];
}
getFilesByFolder(sourceFolder) {
getFilesByFolder(sourceFolder, excludedPath = "") {
const files = this.app.vault.getMarkdownFiles().filter((f) => {
const cache = this.app.metadataCache.getFileCache(f);
return !isLikelySmartFolderExportPath(f.path) && !isSmartFolderExportCache(cache);
return f.path !== excludedPath && !isLikelySmartFolderExportPath(f.path) && !isSmartFolderExportCache(cache);
});
if (!sourceFolder) return files;
const prefix = sourceFolder.replace(/\/$/, "") + "/";
@ -1791,10 +1795,10 @@ var SmartFolderPlugin = class extends obsidian.Plugin {
getTemplateFileOptions() {
return this.app.vault.getMarkdownFiles().map((f) => f.path);
}
getFieldCandidates(sourceFolder, templateFile) {
getFieldCandidates(sourceFolder, templateFile, excludedPath = "") {
const template = templateFile ? this.app.vault.getAbstractFileByPath(templateFile) : null;
const templateKeys = template instanceof obsidian.TFile ? getAllFrontmatterKeys([this.app.metadataCache.getFileCache(template)]) : [];
const files = this.getFilesByFolder(sourceFolder);
const files = this.getFilesByFolder(sourceFolder, excludedPath);
const caches = files.map((f) => this.app.metadataCache.getFileCache(f));
const allKeys = getAllFrontmatterKeys(caches);
const common = allKeys.filter((k) => caches.every((c) => !c?.frontmatter || k in c.frontmatter));
@ -1844,6 +1848,7 @@ var SmartFolderPlugin = class extends obsidian.Plugin {
sortOrder: raw.sortOrder === "asc" ? "asc" : "desc",
viewMode: raw.viewMode === "board" ? "board" : "timeline",
boardField: String(raw.boardField || ""),
sourceNotePath: String(raw.sourceNotePath || ""),
createdAt: typeof raw.createdAt === "number" ? raw.createdAt : Date.now(),
updatedAt: Date.now()
};
@ -1852,6 +1857,7 @@ var SmartFolderPlugin = class extends obsidian.Plugin {
async openProfileFromExport(raw, opts = {}) {
const profile = this.normalizeExportProfile(raw);
if (!profile) return false;
profile.sourceNotePath = String(opts.sourcePath || profile.sourceNotePath || "");
await this.activateView({
profile,
newLeaf: opts.newLeaf === true,
@ -1860,9 +1866,10 @@ var SmartFolderPlugin = class extends obsidian.Plugin {
});
return true;
}
async importProfileFromExport(raw) {
async importProfileFromExport(raw, opts = {}) {
const profile = this.normalizeExportProfile(raw);
if (!profile) return false;
profile.sourceNotePath = String(opts.sourcePath || profile.sourceNotePath || "");
const existing = this.data.profiles.find((p) => p.id === profile.id) || this.data.profiles.find((p) => p.name === profile.name && p.sourceFolder === profile.sourceFolder);
if (existing) {
profile.id = existing.id;
@ -1913,7 +1920,7 @@ var SmartFolderPlugin = class extends obsidian.Plugin {
async onload() {
await this.loadPluginData();
this.registerView(VIEW_TYPE, (leaf) => new SmartFolderView(leaf, this));
this.registerMarkdownCodeBlockProcessor("smart-folder-page", (source, el) => {
this.registerMarkdownCodeBlockProcessor("smart-folder-page", (source, el, ctx) => {
el.empty();
let raw;
try {
@ -1937,13 +1944,13 @@ var SmartFolderPlugin = class extends obsidian.Plugin {
openBtn.addClass("mod-cta");
openBtn.addEventListener("click", () => {
const currentLeaf = this.app.workspace.getMostRecentLeaf();
void this.openProfileFromExport(raw, { leaf: currentLeaf }).then((ok) => {
void this.openProfileFromExport(raw, { leaf: currentLeaf, sourcePath: ctx.sourcePath }).then((ok) => {
if (!ok) new obsidian.Notice(this.t("exportBlockInvalid"));
});
});
const importBtn = row.createEl("button", { text: this.t("exportBlockImport") });
importBtn.addEventListener("click", () => {
void this.importProfileFromExport(raw).then((ok) => {
void this.importProfileFromExport(raw, { sourcePath: ctx.sourcePath }).then((ok) => {
if (!ok) new obsidian.Notice(this.t("exportBlockInvalid"));
});
});

View file

@ -452,7 +452,7 @@ class SetupModal extends obsidian.Modal {
const templates = this.plugin.getTemplateFileOptions();
if (!templates.includes(this.draft.templateFile)) this.draft.templateFile = templates[0] || '';
const fieldOptions = this.plugin.getFieldCandidates(this.draft.sourceFolder, this.draft.templateFile);
const fieldOptions = this.plugin.getFieldCandidates(this.draft.sourceFolder, this.draft.templateFile, this.draft.sourceNotePath);
if (!fieldOptions.includes(this.draft.colorField)) this.draft.colorField = fieldOptions[0] || '';
if (!fieldOptions.includes(this.draft.sortField)) this.draft.sortField = fieldOptions[0] || '';
if (!fieldOptions.includes(this.draft.boardField)) {
@ -888,7 +888,11 @@ class SmartFolderView extends obsidian.ItemView {
getRenderProfile() {
if (!this.pinnedProfile) return this.plugin.getCurrentProfile();
const latest = this.plugin.data.profiles.find(p => p.id === this.pinnedProfile.id) || this.pinnedProfile;
this.pinnedProfile = { ...latest, displayFields: [...(latest.displayFields || [])] };
this.pinnedProfile = {
...latest,
sourceNotePath: this.pinnedProfile.sourceNotePath || latest.sourceNotePath || '',
displayFields: [...(latest.displayFields || [])],
};
return this.pinnedProfile;
}
@ -1288,7 +1292,7 @@ class SmartFolderView extends obsidian.ItemView {
new obsidian.Notice(this.plugin.t('refreshPreviewDone'));
});
const files = this.plugin.getFilesByFolder(profile.sourceFolder);
const files = this.plugin.getFilesByFolder(profile.sourceFolder, profile.sourceNotePath);
if (!files.length) {
container.createEl('p', { text: this.plugin.t('noFiles', { folder: profile.sourceFolder }) });
return;
@ -1983,10 +1987,12 @@ class SmartFolderPlugin extends obsidian.Plugin {
return ['', ...uniqueSorted([...set])];
}
getFilesByFolder(sourceFolder) {
getFilesByFolder(sourceFolder, excludedPath = '') {
const files = this.app.vault.getMarkdownFiles().filter(f => {
const cache = this.app.metadataCache.getFileCache(f);
return !isLikelySmartFolderExportPath(f.path) && !isSmartFolderExportCache(cache);
return f.path !== excludedPath
&& !isLikelySmartFolderExportPath(f.path)
&& !isSmartFolderExportCache(cache);
});
if (!sourceFolder) return files;
const prefix = sourceFolder.replace(/\/$/, '') + '/';
@ -1997,13 +2003,13 @@ class SmartFolderPlugin extends obsidian.Plugin {
return this.app.vault.getMarkdownFiles().map(f => f.path);
}
getFieldCandidates(sourceFolder, templateFile) {
getFieldCandidates(sourceFolder, templateFile, excludedPath = '') {
const template = templateFile ? this.app.vault.getAbstractFileByPath(templateFile) : null;
const templateKeys = (template instanceof obsidian.TFile)
? getAllFrontmatterKeys([this.app.metadataCache.getFileCache(template)])
: [];
const files = this.getFilesByFolder(sourceFolder);
const files = this.getFilesByFolder(sourceFolder, excludedPath);
const caches = files.map(f => this.app.metadataCache.getFileCache(f));
const allKeys = getAllFrontmatterKeys(caches);
const common = allKeys.filter(k => caches.every(c => !c?.frontmatter || k in c.frontmatter));
@ -2061,6 +2067,7 @@ class SmartFolderPlugin extends obsidian.Plugin {
sortOrder: raw.sortOrder === 'asc' ? 'asc' : 'desc',
viewMode: raw.viewMode === 'board' ? 'board' : 'timeline',
boardField: String(raw.boardField || ''),
sourceNotePath: String(raw.sourceNotePath || ''),
createdAt: typeof raw.createdAt === 'number' ? raw.createdAt : Date.now(),
updatedAt: Date.now(),
};
@ -2070,6 +2077,7 @@ class SmartFolderPlugin extends obsidian.Plugin {
async openProfileFromExport(raw, opts = {}) {
const profile = this.normalizeExportProfile(raw);
if (!profile) return false;
profile.sourceNotePath = String(opts.sourcePath || profile.sourceNotePath || '');
await this.activateView({
profile,
newLeaf: opts.newLeaf === true,
@ -2079,9 +2087,10 @@ class SmartFolderPlugin extends obsidian.Plugin {
return true;
}
async importProfileFromExport(raw) {
async importProfileFromExport(raw, opts = {}) {
const profile = this.normalizeExportProfile(raw);
if (!profile) return false;
profile.sourceNotePath = String(opts.sourcePath || profile.sourceNotePath || '');
const existing = this.data.profiles.find(p => p.id === profile.id)
|| this.data.profiles.find(p => p.name === profile.name && p.sourceFolder === profile.sourceFolder);
if (existing) {
@ -2144,7 +2153,7 @@ class SmartFolderPlugin extends obsidian.Plugin {
this.registerView(VIEW_TYPE, leaf => new SmartFolderView(leaf, this));
this.registerMarkdownCodeBlockProcessor('smart-folder-page', (source, el) => {
this.registerMarkdownCodeBlockProcessor('smart-folder-page', (source, el, ctx) => {
el.empty();
let raw;
try {
@ -2170,13 +2179,13 @@ class SmartFolderPlugin extends obsidian.Plugin {
openBtn.addClass('mod-cta');
openBtn.addEventListener('click', () => {
const currentLeaf = this.app.workspace.getMostRecentLeaf();
void this.openProfileFromExport(raw, { leaf: currentLeaf }).then(ok => {
void this.openProfileFromExport(raw, { leaf: currentLeaf, sourcePath: ctx.sourcePath }).then(ok => {
if (!ok) new obsidian.Notice(this.t('exportBlockInvalid'));
});
});
const importBtn = row.createEl('button', { text: this.t('exportBlockImport') });
importBtn.addEventListener('click', () => {
void this.importProfileFromExport(raw).then(ok => {
void this.importProfileFromExport(raw, { sourcePath: ctx.sourcePath }).then(ok => {
if (!ok) new obsidian.Notice(this.t('exportBlockInvalid'));
});
});