Support front matter title plugin

This commit is contained in:
Lost Paul 2023-07-26 16:11:37 +02:00
parent cd943b3df4
commit 103145c45a
7 changed files with 267 additions and 51 deletions

View file

@ -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"

View 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);
}
}
}

View file

@ -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
View file

@ -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;

View file

@ -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() {

View file

@ -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

View file

@ -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;
}