mirror of
https://github.com/lostpaul/obsidian-folder-notes.git
synced 2026-07-22 07:40:24 +00:00
Initial commit
This commit is contained in:
parent
e9380e5873
commit
8743474075
6 changed files with 115 additions and 47 deletions
|
|
@ -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');
|
||||
});
|
||||
});
|
||||
}));
|
||||
}
|
||||
}
|
||||
49
src/main.ts
49
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('/' || '\\')));
|
||||
|
|
|
|||
|
|
@ -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 () => {
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
})
|
||||
);
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue