From 8743474075fbf84644526b0b344e1fbfe21a1eb0 Mon Sep 17 00:00:00 2001 From: Lost Paul <70213368+LostPaul@users.noreply.github.com> Date: Sun, 19 Mar 2023 22:33:54 +0100 Subject: [PATCH] Initial commit --- src/commands.ts | 28 +++++++++++++++++++- src/main.ts | 49 ++++++++++++++++++++++++++++++----- src/modals/confirmCreation.ts | 17 +++++++----- src/modals/folderName.ts | 11 +++++++- src/settings.ts | 29 +++++++++++---------- src/template.ts | 28 +++++++------------- 6 files changed, 115 insertions(+), 47 deletions(-) diff --git a/src/commands.ts b/src/commands.ts index 5cde0c9..c67d892 100644 --- a/src/commands.ts +++ b/src/commands.ts @@ -1,5 +1,6 @@ -import { App } from 'obsidian'; +import { App, TFolder, Menu, TAbstractFile, Notice } from 'obsidian'; import FolderNotesPlugin from './main'; +import { ExcludedFolder } from './settings'; export class Commands { plugin: FolderNotesPlugin; app: App; @@ -8,5 +9,30 @@ export class Commands { this.app = app; } registerCommands() { + this.plugin.registerEvent(this.app.workspace.on('file-menu', (menu: Menu, file: TAbstractFile) => { + if (!(file instanceof TFolder)) return; + if (this.plugin.settings.excludeFolders.find((folder) => folder.path === file.path)) { + menu.addItem((item) => { + item.setTitle('Remove folder from excluded folders') + .setIcon('x') + .onClick(() => { + this.plugin.settings.excludeFolders = this.plugin.settings.excludeFolders.filter((folder) => folder.path !== file.path); + this.plugin.saveSettings(); + new Notice('Successfully removed folder from excluded folders'); + }); + }); + return; + } + menu.addItem((item) => { + item.setTitle('Exclude folder from folder notes') + .setIcon('x') + .onClick(() => { + const excludedFolder = new ExcludedFolder(file.path, this.plugin.settings.excludeFolders.length); + this.plugin.settings.excludeFolders.push(excludedFolder); + this.plugin.saveSettings(); + new Notice('Successfully excluded folder from folder notes'); + }); + }); + })); } } \ No newline at end of file diff --git a/src/main.ts b/src/main.ts index 3755bc0..57cf304 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,7 +1,8 @@ -import { Plugin, TFile, TFolder, TAbstractFile } from 'obsidian' +import { Plugin, TFile, TFolder, TAbstractFile, Notice } from 'obsidian' import { DEFAULT_SETTINGS, FolderNotesSettings, SettingsTab } from './settings' import FolderNameModal from './modals/folderName'; import { applyTemplate } from './template'; +import { Commands } from './commands'; export default class FolderNotesPlugin extends Plugin { observer: MutationObserver folders: TFolder[] = [] @@ -18,6 +19,7 @@ export default class FolderNotesPlugin extends Plugin { } else { document.body.classList.remove('hide-folder-note'); } + new Commands(this.app, this).registerCommands(); this.registerEvent(this.app.vault.on('create', (folder: TAbstractFile) => { if (!this.app.workspace.layoutReady) return; if (!this.settings.autoCreate) return; @@ -38,6 +40,7 @@ export default class FolderNotesPlugin extends Plugin { })); this.registerEvent(this.app.vault.on('rename', (file: TAbstractFile, oldPath: string) => { + console.log('rename') if (!this.settings.syncFolderName) return; if (file instanceof TFolder) { const folder = this.app.vault.getAbstractFileByPath(file?.path); @@ -47,6 +50,23 @@ export default class FolderNotesPlugin extends Plugin { (excludedFolder.path === folder.path?.slice(0, folder?.path.lastIndexOf("/") >= 0 ? folder.path?.lastIndexOf("/") : folder.path.length) && excludedFolder.subFolders)); if (excludedFolder?.disableSync) return; + const excludedFolders = this.settings.excludeFolders.filter( + (excludedFolder) => excludedFolder.path.includes(oldPath) + ); + + excludedFolders.forEach((excludedFolder) => { + const folders = excludedFolder.path.split('/'); + if (folders.length < 1) { + folders.push(excludedFolder.path); + } + + const oldName = oldPath.substring(oldPath.lastIndexOf('/' || '\\')); + console.log(oldName.replace('/', '')) + folders[folders.indexOf(oldName.replace('/', ''))] = folder.name; + excludedFolder.path = folders.join('/'); + }); + this.saveSettings(); + const oldName = oldPath.substring(oldPath.lastIndexOf('/' || '\\')); const newPath = folder?.path + '/' + folder?.name + '.md'; if (folder instanceof TFolder) { @@ -59,13 +79,26 @@ export default class FolderNotesPlugin extends Plugin { } } else if (file instanceof TFile) { const folder = this.app.vault.getAbstractFileByPath(oldPath.substring(0, oldPath.lastIndexOf('/' || '\\'))); + if (folder?.name + '.md' == file.name) return; + const oldFileName = oldPath.substring(oldPath.lastIndexOf('/' || '\\') + 1); if (!folder) return; const excludedFolder = this.settings.excludeFolders.find( (excludedFolder) => (excludedFolder.path === folder.path) || (excludedFolder.path === folder.path?.slice(0, folder?.path.lastIndexOf("/") >= 0 ? folder.path?.lastIndexOf("/") : folder.path.length) && excludedFolder.subFolders)); if (excludedFolder?.disableSync) return; - if (file.name !== folder?.name + '.md') return; + if (oldFileName !== folder?.name + '.md') return console.log('not a folder note'); + let newFolderPath = file.path.slice(0, file.path.lastIndexOf('/')) + if (newFolderPath.lastIndexOf('/') > 0) { + newFolderPath = newFolderPath.slice(0, newFolderPath.lastIndexOf('/')) + '/' + } else { + newFolderPath = '' + } + newFolderPath = newFolderPath + file.name.replace('.md', ''); + if (this.app.vault.getAbstractFileByPath(newFolderPath)) { + this.app.vault.rename(file, oldPath); + return new Notice('A folder with the same name already exists'); + } if (folder instanceof TFolder) { this.app.vault.rename(folder, folder.path.substring(0, folder.path.lastIndexOf('/' || '\\')) + '/' + file.name.substring(0, file.name.lastIndexOf('.'))); } @@ -109,7 +142,7 @@ export default class FolderNotesPlugin extends Plugin { event.target.parentElement?.parentElement?.getElementsByClassName('nav-folder-children').item(0)?.querySelectorAll('div.nav-file') .forEach((element: HTMLElement) => { if (element.innerText === (event.target as HTMLElement)?.innerText && element.classList.contains('is-folder-note')) { - element.classList.remove('is-folder-note'); + element.removeClass('is-folder-note'); } }); return; @@ -125,8 +158,8 @@ export default class FolderNotesPlugin extends Plugin { event.target.parentElement?.parentElement?.getElementsByClassName('nav-folder-children').item(0)?.querySelectorAll('div.nav-file') .forEach((element: HTMLElement) => { if (element.innerText === (event.target as HTMLElement)?.innerText && !element.classList.contains('is-folder-note')) { - console.log(element) - element.classList.add('is-folder-note'); + + element.addClass('is-folder-note'); } }); @@ -137,7 +170,7 @@ export default class FolderNotesPlugin extends Plugin { event.target.parentElement?.parentElement?.getElementsByClassName('nav-folder-children').item(0)?.querySelectorAll('div.nav-file') .forEach((element: HTMLElement) => { if (element.innerText === (event.target as HTMLElement)?.innerText && !element.classList.contains('is-folder-note')) { - element.classList.add('is-folder-note'); + element.addClass('is-folder-note'); } }); } else { @@ -156,7 +189,9 @@ export default class FolderNotesPlugin extends Plugin { if (openFile) { await leaf.openFile(file); } - applyTemplate(this, this.settings.templatePath); + if (file) { + applyTemplate(this, file, this.settings.templatePath); + } if (!this.settings.autoCreate) return; if (!useModal) return; const folder = this.app.vault.getAbstractFileByPath(path.substring(0, path.lastIndexOf('/' || '\\'))); diff --git a/src/modals/confirmCreation.ts b/src/modals/confirmCreation.ts index 9bc97d0..e7a659c 100644 --- a/src/modals/confirmCreation.ts +++ b/src/modals/confirmCreation.ts @@ -15,20 +15,25 @@ export default class ConfirmationModal extends Modal { const setting = new Setting(contentEl) setting.infoEl.createEl('p', { text: 'Make sure to backup your vault before using this feature.' }).style.color = '#fb464c'; setting.infoEl.createEl('p', { text: 'This feature will create a folder note for every folder in your vault.' }); - setting.infoEl.createEl('p', { text: 'Every folder that already has a folder note will be ignored' }); + setting.infoEl.createEl('p', { text: 'Every folder that already has a folder note will be ignored.' }); + setting.infoEl.createEl('p', { text: 'Every excluded folder will be ignored.' }); setting.infoEl.parentElement?.classList.add('fn-confirmation-modal') const button = setting.infoEl.createEl('button', { text: 'Create' }); button.classList.add('mod-warning', 'fn-confirmation-modal-button'); button.addEventListener('click', async () => { this.close(); - this.app.vault.getAllLoadedFiles().forEach(async (file) => { - if (file instanceof TFolder) { - if (this.app.vault.getAbstractFileByPath(file.path + '/' + file.name + '.md')) return; - await this.plugin.createFolderNote(file.path + '/' + file.name + '.md', false); + this.app.vault.getAllLoadedFiles().forEach(async (folder) => { + if (folder instanceof TFolder) { + const excludedFolder = this.plugin.settings.excludeFolders.find( + (excludedFolder) => (excludedFolder.path === folder.path) || + (excludedFolder.path === folder.path?.slice(0, folder?.path.lastIndexOf("/") >= 0 ? folder.path?.lastIndexOf("/") : folder.path.length) + && excludedFolder.subFolders)); + if (excludedFolder) return; + if (this.app.vault.getAbstractFileByPath(folder.path + '/' + folder.name + '.md')) return; + await this.plugin.createFolderNote(folder.path + '/' + folder.name + '.md', true); } }) }); - // focus on the button button.focus(); const cancelButton = setting.infoEl.createEl('button', { text: 'Cancel' }); cancelButton.addEventListener('click', async () => { diff --git a/src/modals/folderName.ts b/src/modals/folderName.ts index 0ce65d8..0660010 100644 --- a/src/modals/folderName.ts +++ b/src/modals/folderName.ts @@ -12,6 +12,12 @@ export default class FolderNameModal extends Modal { } onOpen() { const { contentEl } = this; + // close when user presses enter + contentEl.addEventListener('keydown', (e) => { + if (e.key === 'Enter') { + this.close(); + } + }); contentEl.createEl('h2', { text: 'Folder name' }); new Setting(contentEl) .setName('Enter the name of the folder') @@ -20,7 +26,10 @@ export default class FolderNameModal extends Modal { .setValue(this.folder.name.replace('.md', '')) .onChange(async (value) => { if (value.trim() !== "") { - this.app.vault.rename(this.folder, this.folder.path.slice(0, this.folder.path.lastIndexOf('/') + 1) + value); + if (!this.app.vault.getAbstractFileByPath(this.folder.path.slice(0, this.folder.path.lastIndexOf('/') + 1) + value.trim())) + { + this.app.vault.rename(this.folder, this.folder.path.slice(0, this.folder.path.lastIndexOf('/') + 1) + value.trim()); + } } }) ); diff --git a/src/settings.ts b/src/settings.ts index 08f2566..6f9c544 100644 --- a/src/settings.ts +++ b/src/settings.ts @@ -3,7 +3,7 @@ import FolderNotesPlugin from "./main"; import { FolderSuggest } from "./suggesters/folderSuggester"; import ExcludedFolderSettings from "./modals/exludeFolderSettings"; import { TemplateSuggest } from "./suggesters/templateSuggester"; -import ConfirmationModal from "./modals/confirmCreation"; +//import ConfirmationModal from "./modals/confirmCreation"; export interface FolderNotesSettings { syncFolderName: boolean; ctrlKey: boolean; @@ -19,7 +19,7 @@ export const DEFAULT_SETTINGS: FolderNotesSettings = { syncFolderName: true, ctrlKey: true, altKey: false, - hideFolderNote: true, + hideFolderNote: false, templatePath: '', autoCreate: false, enableCollapsing: false, @@ -125,18 +125,22 @@ export class SettingsTab extends PluginSettingTab { }); }); - new Setting(containerEl) - .setName('Create folder note for every folder') - .setDesc('Create a folder note for every folder in the vault') - .addButton((cb) => { - cb.setIcon('plus'); + // Due to issue with templater it'll be disabled for now + // If you want to try it yourself make a pr + // The issue was that it only used the first folder for all of the other folder notes + /* + new Setting(containerEl) + .setName('Create folder note for every folder') + .setDesc('Create a folder note for every folder in the vault') + .addButton((cb) => { + cb.setIcon('plus'); - cb.setTooltip('Create folder notes'); - cb.onClick(async () => { - new ConfirmationModal(this.app, this.plugin).open(); - }); + cb.setTooltip('Create folder notes'); + cb.onClick(async () => { + new ConfirmationModal(this.app, this.plugin).open(); }); - + }); + */ new Setting(containerEl) @@ -191,7 +195,6 @@ export class SettingsTab extends PluginSettingTab { cb.onClick(() => { if (excludedFolder.position === 0) return; excludedFolder.position = excludedFolder.position - 1; - console.log(excludedFolder.position); this.updateExcludedFolder(excludedFolder, excludedFolder); const oldExcludedFolder = this.plugin.settings.excludeFolders.find(folder => folder.position == excludedFolder.position) if (oldExcludedFolder) { diff --git a/src/template.ts b/src/template.ts index cec1b61..36a968b 100644 --- a/src/template.ts +++ b/src/template.ts @@ -2,10 +2,11 @@ // from where I got the template code for this plugin // https://github.com/mgmeyers/obsidian-kanban/blob/48e6c278ce9140b7e034b181432321f697d6e45e/src/components/helpers.ts -import { TFile, MarkdownView, App } from 'obsidian'; +import { TFile, App } from 'obsidian'; import FolderNotesPlugin from './main'; export async function applyTemplate( plugin: FolderNotesPlugin, + file: TFile, templatePath?: string ) { const templateFile = templatePath @@ -13,19 +14,7 @@ export async function applyTemplate( : null; if (templateFile && templateFile instanceof TFile) { - const activeView = app.workspace.getActiveViewOfType(MarkdownView); - try { - // Force the view to source mode, if needed - if (activeView?.getMode() !== 'source') { - await activeView?.setState( - { - ...activeView.getState(), - mode: 'source', - }, - {} - ); - } const { templatesEnabled, @@ -33,17 +22,17 @@ export async function applyTemplate( templatesPlugin, templaterPlugin, } = getTemplatePlugins(plugin.app); - const templateContent = await plugin.app.vault.read(templateFile); // If both plugins are enabled, attempt to detect templater first + if (templatesEnabled && templaterEnabled) { if (/<%/.test(templateContent)) { - return await templaterPlugin.append_template_to_active_file( - templateFile + return await templaterPlugin.write_template_to_file( + templateFile, + file ); } - return await templatesPlugin.instance.insertTemplate(templateFile); } @@ -52,8 +41,9 @@ export async function applyTemplate( } if (templaterEnabled) { - return await templaterPlugin.append_template_to_active_file( - templateFile + return await templaterPlugin.write_template_to_file( + templateFile, + file ); }