mirror of
https://github.com/lostpaul/obsidian-folder-notes.git
synced 2026-07-22 07:40:24 +00:00
Support front matter title plugin
This commit is contained in:
parent
cd943b3df4
commit
103145c45a
7 changed files with 267 additions and 51 deletions
|
|
@ -17,6 +17,7 @@
|
|||
"@typescript-eslint/parser": "5.29.0",
|
||||
"builtin-modules": "3.3.0",
|
||||
"esbuild": "0.14.47",
|
||||
"front-matter-plugin-api-provider": "^0.1.4-alpha",
|
||||
"obsidian": "latest",
|
||||
"tslib": "2.4.0",
|
||||
"typescript": "4.7.4"
|
||||
|
|
|
|||
84
src/events/frontMatterTitle.ts
Normal file
84
src/events/frontMatterTitle.ts
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
import FolderNotesPlugin from 'src/main';
|
||||
import { getDefer, Listener, Events, ApiInterface, DeferInterface, ListenerRef, EventDispatcherInterface } from 'front-matter-plugin-api-provider';
|
||||
import { App, TFile, TFolder } from 'obsidian';
|
||||
import { extractFolderName, getFolder } from 'src/functions/folderNoteFunctions';
|
||||
export class FrontMatterTitlePluginHandler {
|
||||
plugin: FolderNotesPlugin;
|
||||
app: App;
|
||||
api: ApiInterface | null = null;
|
||||
deffer: DeferInterface | null = null;
|
||||
modifiedFolders: Map<string, TFolder> = new Map();
|
||||
eventRef: ListenerRef<'manager:update'>;
|
||||
dispatcher: EventDispatcherInterface<Events>
|
||||
constructor(plugin: FolderNotesPlugin) {
|
||||
this.plugin = plugin;
|
||||
this.app = plugin.app;
|
||||
|
||||
(async () => {
|
||||
this.deffer = getDefer(this.app);
|
||||
if (this.deffer.isPluginReady()) {
|
||||
this.api = this.deffer.getApi();
|
||||
} else {
|
||||
await this.deffer.awaitPlugin();
|
||||
this.api = this.deffer.getApi();
|
||||
// if you want to wait features you can use the following chain
|
||||
if (!this.deffer.isFeaturesReady()) {
|
||||
await this.deffer.awaitFeatures();
|
||||
}
|
||||
}
|
||||
const dispatcher = this.api?.getEventDispatcher();
|
||||
if (dispatcher) {
|
||||
this.dispatcher = dispatcher;
|
||||
}
|
||||
const event: Listener<Events, 'manager:update'> = {
|
||||
name: 'manager:update',
|
||||
cb: (data) => {
|
||||
this.handleRename(data as any, true);
|
||||
},
|
||||
};
|
||||
// Keep ref to remove listener
|
||||
const ref = dispatcher?.addListener(event);
|
||||
if (ref) {
|
||||
this.eventRef = ref;
|
||||
}
|
||||
this.plugin.app.vault.getFiles().forEach((file) => {
|
||||
this.handleRename({ id: '', result: false, path: file.path }, false);
|
||||
});
|
||||
this.plugin.updateBreadcrumbs();
|
||||
})();
|
||||
}
|
||||
deleteEvent() {
|
||||
if (this.eventRef) {
|
||||
this.dispatcher.removeListener(this.eventRef);
|
||||
}
|
||||
}
|
||||
async handleRename(data: {
|
||||
id: string;
|
||||
result: boolean;
|
||||
path: string;
|
||||
}, isEvent: boolean) {
|
||||
if ((data as any).data) data = (data as any).data
|
||||
const file = this.app.vault.getAbstractFileByPath(data.path);
|
||||
if (!(file instanceof TFile)) { return; }
|
||||
|
||||
const resolver = this.api?.getResolverFactory()?.createResolver('#feature-id#');
|
||||
const newName = resolver?.resolve(file?.path ?? '')
|
||||
const folder = getFolder(this.plugin, file);
|
||||
|
||||
if ((extractFolderName(this.plugin.settings.folderNoteName, file.basename) || file.basename) !== folder?.name) { return; }
|
||||
if (!(folder instanceof TFolder)) { return; }
|
||||
if (isEvent) {
|
||||
this.plugin.changeName(folder, newName, true);
|
||||
} else {
|
||||
this.plugin.changeName(folder, newName, false);
|
||||
}
|
||||
if (newName) {
|
||||
folder.newName = newName;
|
||||
this.modifiedFolders.set(folder.path, folder);
|
||||
} else {
|
||||
folder.newName = null;
|
||||
this.modifiedFolders.delete(folder.path);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -128,7 +128,6 @@ export function createOverview(plugin: FolderNotesPlugin, source: string, el: HT
|
|||
*/
|
||||
}
|
||||
if (includeTypes.length > 1 && style !== 'grid' && (!showEmptyFolders || yaml.onlyIncludeSubfolders)) {
|
||||
console.log('depth', depth, yaml.onlyIncludeSubfolders);
|
||||
removeEmptyFolders(ul, 1, yaml);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
3
src/globals.d.ts
vendored
3
src/globals.d.ts
vendored
|
|
@ -18,6 +18,9 @@ declare module 'obsidian' {
|
|||
interface Setting {
|
||||
createList: (list: ListComponent | ((list: ListComponent) => void)) => ListComponent;
|
||||
}
|
||||
interface TFolder {
|
||||
newName: string | null;
|
||||
}
|
||||
|
||||
class ListComponent {
|
||||
containerEl: HTMLElement;
|
||||
|
|
|
|||
69
src/main.ts
69
src/main.ts
|
|
@ -6,7 +6,7 @@ import { handleViewHeaderClick, handleFolderClick } from './events/handleClick';
|
|||
import { handleFileRename, handleFolderRename } from './events/handleRename';
|
||||
import { createFolderNote, extractFolderName, getFolderNote, getFolder } from './functions/folderNoteFunctions';
|
||||
import { getExcludedFolder } from './excludedFolder';
|
||||
// import { FrontMatterTitlePluginHandler } from './events/frontMatterTitle';
|
||||
import { FrontMatterTitlePluginHandler } from './events/frontMatterTitle';
|
||||
import { createOverview as createFolderOverview } from './folderOverview';
|
||||
import { FolderOverviewSettings } from './modals/folderOverview';
|
||||
import './functions/ListComponent';
|
||||
|
|
@ -16,7 +16,7 @@ export default class FolderNotesPlugin extends Plugin {
|
|||
settingsTab: SettingsTab;
|
||||
activeFolderDom: HTMLElement | null;
|
||||
activeFileExplorer: FileExplorerWorkspaceLeaf;
|
||||
|
||||
fmtpHandler: FrontMatterTitlePluginHandler | null = null;
|
||||
async onload() {
|
||||
console.log('loading folder notes plugin');
|
||||
await this.loadSettings();
|
||||
|
|
@ -33,7 +33,9 @@ export default class FolderNotesPlugin extends Plugin {
|
|||
|
||||
new Commands(this.app, this).registerCommands();
|
||||
|
||||
// new FrontMatterTitlePluginHandler(this.app, this);
|
||||
if (this.settings.frontMatterTitle.enabled) {
|
||||
this.fmtpHandler = new FrontMatterTitlePluginHandler(this);
|
||||
}
|
||||
|
||||
this.observer = new MutationObserver((mutations: MutationRecord[]) => {
|
||||
mutations.forEach((rec) => {
|
||||
|
|
@ -50,9 +52,18 @@ export default class FolderNotesPlugin extends Plugin {
|
|||
if (!breadcrumbs) return;
|
||||
let path = '';
|
||||
breadcrumbs.forEach((breadcrumb: HTMLElement) => {
|
||||
path += breadcrumb.innerText.trim() + '/';
|
||||
if (breadcrumb.hasAttribute('old-name')) {
|
||||
path += breadcrumb.getAttribute('old-name') + '/';
|
||||
} else {
|
||||
path += breadcrumb.innerText.trim() + '/';
|
||||
}
|
||||
const folderPath = path.slice(0, -1);
|
||||
breadcrumb.setAttribute('data-path', folderPath);
|
||||
const folder = this.fmtpHandler?.modifiedFolders.get(folderPath);
|
||||
if (folder) {
|
||||
breadcrumb.setAttribute('old-name', folder.name || '');
|
||||
breadcrumb.innerText = folder.newName || '';
|
||||
}
|
||||
const folderNote = getFolderNote(this, folderPath);
|
||||
if (folderNote) {
|
||||
breadcrumb.classList.add('has-folder-note');
|
||||
|
|
@ -131,7 +142,6 @@ export default class FolderNotesPlugin extends Plugin {
|
|||
return handleFileRename(file, oldPath, this);
|
||||
}
|
||||
}));
|
||||
|
||||
this.registerEvent(this.app.vault.on('delete', (file: TAbstractFile) => {
|
||||
if (file instanceof TFile) {
|
||||
const folder = getFolder(this, file);
|
||||
|
|
@ -228,6 +238,51 @@ export default class FolderNotesPlugin extends Plugin {
|
|||
});
|
||||
}
|
||||
|
||||
async changeName(folder: TFolder, name: string | null | undefined, replacePath: boolean, waitForCreate = false, count = 0) {
|
||||
if (!name) name = folder.name;
|
||||
let fileExplorerItem = this.getEL(folder.path);
|
||||
if (!fileExplorerItem) {
|
||||
if (waitForCreate && count < 5) {
|
||||
await new Promise((r) => setTimeout(r, 500));
|
||||
this.changeName(folder, name, replacePath, waitForCreate, count + 1);
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
fileExplorerItem = fileExplorerItem.querySelector('div.nav-folder-title-content')
|
||||
if (!fileExplorerItem) { return; }
|
||||
if (this.settings.frontMatterTitle.explorer) {
|
||||
fileExplorerItem.innerText = name;
|
||||
fileExplorerItem.setAttribute('old-name', folder.name);
|
||||
} else {
|
||||
fileExplorerItem.innerText = folder.name;
|
||||
fileExplorerItem.removeAttribute('old-name');
|
||||
}
|
||||
if (replacePath) {
|
||||
this.updateBreadcrumbs();
|
||||
}
|
||||
}
|
||||
|
||||
updateBreadcrumbs(remove?: boolean) {
|
||||
if (!this.settings.frontMatterTitle.path && !remove) { return; }
|
||||
const viewHeaderItems = document.querySelectorAll('span.view-header-breadcrumb');
|
||||
const files = this.app.vault.getAllLoadedFiles().filter((file) => file instanceof TFolder);
|
||||
viewHeaderItems.forEach((item) => {
|
||||
if (!item.hasAttribute('data-path')) { return; }
|
||||
const path = item.getAttribute('data-path');
|
||||
const folder = files.find((file) => file.path === path);
|
||||
if (!(folder instanceof TFolder)) { return; }
|
||||
if (remove) {
|
||||
item.textContent = folder.name;
|
||||
item.removeAttribute('old-name');
|
||||
} else {
|
||||
item.textContent = folder.newName || folder.name;
|
||||
item.setAttribute('old-name', folder.name);
|
||||
item.setAttribute('data-path', folder.path);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
removeCSSClassFromEL(path: string | undefined, cssClass: string) {
|
||||
if (!path) return;
|
||||
const fileExplorerItem = this.getEL(path);
|
||||
|
|
@ -288,6 +343,10 @@ export default class FolderNotesPlugin extends Plugin {
|
|||
document.body.classList.remove('hide-folder-note');
|
||||
document.body.classList.remove('fn-whitespace-stop-collapsing');
|
||||
if (this.activeFolderDom) { this.activeFolderDom.removeClass('is-active'); }
|
||||
if (this.fmtpHandler) {
|
||||
this.fmtpHandler.deleteEvent();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
async loadSettings() {
|
||||
|
|
|
|||
154
src/settings.ts
154
src/settings.ts
|
|
@ -3,6 +3,7 @@ import FolderNotesPlugin from './main';
|
|||
import { TemplateSuggest } from './suggesters/templateSuggester';
|
||||
import { extractFolderName, getFolderNote } from './functions/folderNoteFunctions';
|
||||
import { addExcludeFolderListItem, ExcludedFolder, addExcludedFolder, ExcludePattern, addExcludePatternListItem } from './excludedFolder';
|
||||
import { FrontMatterTitlePluginHandler } from './events/frontMatterTitle';
|
||||
// import ConfirmationModal from "./modals/confirmCreation";
|
||||
import { yamlSettings } from './folderOverview';
|
||||
export interface FolderNotesSettings {
|
||||
|
|
@ -30,6 +31,11 @@ export interface FolderNotesSettings {
|
|||
defaultOverview: yamlSettings;
|
||||
useSubmenus: boolean;
|
||||
syncMove: boolean;
|
||||
frontMatterTitle: {
|
||||
enabled: boolean;
|
||||
explorer: boolean;
|
||||
path: boolean;
|
||||
}
|
||||
}
|
||||
|
||||
export const DEFAULT_SETTINGS: FolderNotesSettings = {
|
||||
|
|
@ -64,6 +70,11 @@ export const DEFAULT_SETTINGS: FolderNotesSettings = {
|
|||
},
|
||||
useSubmenus: true,
|
||||
syncMove: true,
|
||||
frontMatterTitle: {
|
||||
enabled: false,
|
||||
explorer: true,
|
||||
path: true,
|
||||
}
|
||||
};
|
||||
export class SettingsTab extends PluginSettingTab {
|
||||
plugin: FolderNotesPlugin;
|
||||
|
|
@ -116,6 +127,29 @@ export class SettingsTab extends PluginSettingTab {
|
|||
})
|
||||
);
|
||||
|
||||
const setting = new Setting(containerEl);
|
||||
const desc = document.createDocumentFragment();
|
||||
desc.append(
|
||||
'After setting the template path, restart Obsidian if the template folder path (from templater/templates) had been changed beforehand.',
|
||||
desc.createEl('br'),
|
||||
'Obsidian should also be restarted if the template path was removed.'
|
||||
);
|
||||
setting.setName('Template path');
|
||||
setting.setDesc(desc).descEl.style.color = this.app.vault.getConfig('accentColor') as string || '#7d5bed';
|
||||
setting.addSearch((cb) => {
|
||||
new TemplateSuggest(cb.inputEl, this.plugin);
|
||||
cb.setPlaceholder('Template path');
|
||||
cb.setValue(this.plugin.app.vault.getAbstractFileByPath(this.plugin.settings.templatePath)?.name.replace('.md', '') || '');
|
||||
cb.onChange(async (value) => {
|
||||
if (value.trim() === '') {
|
||||
this.plugin.settings.templatePath = '';
|
||||
await this.plugin.saveSettings();
|
||||
this.display();
|
||||
return;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
const storageLocation = new Setting(containerEl)
|
||||
.setName('Storage location')
|
||||
.setDesc('Choose where to store the folder notes')
|
||||
|
|
@ -195,6 +229,26 @@ export class SettingsTab extends PluginSettingTab {
|
|||
disableSetting.infoEl.appendText('Requires a restart to take effect');
|
||||
disableSetting.infoEl.style.color = this.app.vault.getConfig('accentColor') as string || '#7d5bed';
|
||||
|
||||
if (Platform.isDesktopApp) {
|
||||
new Setting(containerEl)
|
||||
.setName('Key for creating folder note')
|
||||
.setDesc('The key combination to create a folder note')
|
||||
.addDropdown((dropdown) => {
|
||||
if (!Platform.isMacOS) {
|
||||
dropdown.addOption('ctrl', 'Ctrl + Click');
|
||||
} else {
|
||||
dropdown.addOption('ctrl', 'Cmd + Click');
|
||||
}
|
||||
dropdown.addOption('alt', 'Alt + Click');
|
||||
dropdown.setValue(this.plugin.settings.ctrlKey ? 'ctrl' : 'alt');
|
||||
dropdown.onChange(async (value) => {
|
||||
this.plugin.settings.ctrlKey = value === 'ctrl';
|
||||
this.plugin.settings.altKey = value === 'alt';
|
||||
await this.plugin.saveSettings();
|
||||
this.display();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName('Only open folder notes through the name')
|
||||
|
|
@ -284,27 +338,6 @@ export class SettingsTab extends PluginSettingTab {
|
|||
})
|
||||
);
|
||||
|
||||
if (Platform.isDesktopApp) {
|
||||
new Setting(containerEl)
|
||||
.setName('Key for creating folder note')
|
||||
.setDesc('The key combination to create a folder note')
|
||||
.addDropdown((dropdown) => {
|
||||
if (!Platform.isMacOS) {
|
||||
dropdown.addOption('ctrl', 'Ctrl + Click');
|
||||
} else {
|
||||
dropdown.addOption('ctrl', 'Cmd + Click');
|
||||
}
|
||||
dropdown.addOption('alt', 'Alt + Click');
|
||||
dropdown.setValue(this.plugin.settings.ctrlKey ? 'ctrl' : 'alt');
|
||||
dropdown.onChange(async (value) => {
|
||||
this.plugin.settings.ctrlKey = value === 'ctrl';
|
||||
this.plugin.settings.altKey = value === 'alt';
|
||||
await this.plugin.saveSettings();
|
||||
this.display();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName('Add underline to folders with folder notes')
|
||||
.setDesc('Add an underline to folders that have a folder note in the file explorer')
|
||||
|
|
@ -355,28 +388,63 @@ export class SettingsTab extends PluginSettingTab {
|
|||
);
|
||||
}
|
||||
|
||||
const setting = new Setting(containerEl);
|
||||
const desc = document.createDocumentFragment();
|
||||
desc.append(
|
||||
'After setting the template path, restart Obsidian if the template folder path (from templater/templates) had been changed beforehand.',
|
||||
desc.createEl('br'),
|
||||
'Obsidian should also be restarted if the template path was removed.'
|
||||
);
|
||||
setting.setName('Template path');
|
||||
setting.setDesc(desc).descEl.style.color = this.app.vault.getConfig('accentColor') as string || '#7d5bed';
|
||||
setting.addSearch((cb) => {
|
||||
new TemplateSuggest(cb.inputEl, this.plugin);
|
||||
cb.setPlaceholder('Template path');
|
||||
cb.setValue(this.plugin.app.vault.getAbstractFileByPath(this.plugin.settings.templatePath)?.name.replace('.md', '') || '');
|
||||
cb.onChange(async (value) => {
|
||||
if (value.trim() === '') {
|
||||
this.plugin.settings.templatePath = '';
|
||||
await this.plugin.saveSettings();
|
||||
this.display();
|
||||
return;
|
||||
}
|
||||
});
|
||||
});
|
||||
new Setting(containerEl)
|
||||
.setName('Enable front matter title plugin integration')
|
||||
.setDesc('Automatically rename a folder name when the folder note is renamed')
|
||||
.addToggle((toggle) =>
|
||||
toggle
|
||||
.setValue(this.plugin.settings.frontMatterTitle.enabled)
|
||||
.onChange(async (value) => {
|
||||
this.plugin.settings.frontMatterTitle.enabled = value;
|
||||
await this.plugin.saveSettings();
|
||||
if (value) {
|
||||
this.plugin.fmtpHandler = new FrontMatterTitlePluginHandler(this.plugin);
|
||||
} else {
|
||||
if (this.plugin.fmtpHandler) {
|
||||
this.plugin.updateBreadcrumbs(true);
|
||||
}
|
||||
this.plugin.fmtpHandler?.deleteEvent();
|
||||
this.plugin.fmtpHandler = null;
|
||||
}
|
||||
this.display();
|
||||
})
|
||||
);
|
||||
|
||||
if (this.plugin.settings.frontMatterTitle.enabled) {
|
||||
new Setting(containerEl)
|
||||
.setName('Include file explorer')
|
||||
.setDesc('Automatically rename a folder name in the file explorer when the folder note is renamed')
|
||||
.addToggle((toggle) =>
|
||||
toggle
|
||||
.setValue(this.plugin.settings.frontMatterTitle.explorer)
|
||||
.onChange(async (value) => {
|
||||
this.plugin.settings.frontMatterTitle.explorer = value;
|
||||
await this.plugin.saveSettings();
|
||||
this.plugin.app.vault.getFiles().forEach((file) => {
|
||||
this.plugin.fmtpHandler?.handleRename({ id: '', result: false, path: file.path }, false);
|
||||
});
|
||||
this.display();
|
||||
})
|
||||
);
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName('Include path above note')
|
||||
.setDesc('Automatically rename a folder name in the path above a note when the folder note is renamed')
|
||||
.addToggle((toggle) =>
|
||||
toggle
|
||||
.setValue(this.plugin.settings.frontMatterTitle.path)
|
||||
.onChange(async (value) => {
|
||||
this.plugin.settings.frontMatterTitle.path = value;
|
||||
await this.plugin.saveSettings();
|
||||
if (value) {
|
||||
this.plugin.updateBreadcrumbs();
|
||||
} else {
|
||||
this.plugin.updateBreadcrumbs(true);
|
||||
}
|
||||
this.display();
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
// Due to an issue with templater it has been disabled for now
|
||||
// If you want to try it yourself make a pr
|
||||
|
|
|
|||
|
|
@ -110,10 +110,10 @@
|
|||
}
|
||||
|
||||
.folder-overview-list {
|
||||
margin-top : 0 !important;
|
||||
margin-top: 0 !important;
|
||||
margin-bottom: 0 !important;
|
||||
padding-bottom: 1.200 !important;
|
||||
padding-top: 1.200 !important;
|
||||
padding-top: 1.200 !important;
|
||||
}
|
||||
|
||||
.folder-overview-list-item {
|
||||
|
|
@ -142,9 +142,11 @@
|
|||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.folder-overview-grid-item-article a {
|
||||
text-decoration: none !important;
|
||||
}
|
||||
|
||||
.folder-overview-grid-item-article h1 {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue