Save progress

This commit is contained in:
Lost Paul 2024-09-05 17:05:58 +02:00
parent 98158cbef9
commit 4962ac5236
16 changed files with 454 additions and 300 deletions

View file

@ -1,7 +1,7 @@
{
"id": "folder-notes",
"name": "Folder notes",
"version": "1.7.23-9-beta",
"version": "1.7.23-10-beta",
"minAppVersion": "0.15.0",
"description": "Create notes within folders that can be accessed without collapsing the folder, similar to the functionality offered in Notion.",
"author": "Lost Paul",

View file

@ -4,10 +4,11 @@ import { getFolderNote, createFolderNote, deleteFolderNote, turnIntoFolderNote,
import { ExcludedFolder } from './ExcludeFolders/ExcludeFolder';
import { getFolderPathFromString } from './functions/utils';
import { getExcludedFolderByPattern } from './ExcludeFolders/functions/patternFunctions';
import { getDetachedFolder, getExcludedFolder, getExcludedFoldersByPath } from './ExcludeFolders/functions/folderFunctions';
import { addExcludedFolder, deleteExcludedFolder, getDetachedFolder, getExcludedFolder, getExcludedFoldersByPath, updateExcludedFolder } from './ExcludeFolders/functions/folderFunctions';
import ExcludedFolderSettings from './ExcludeFolders/modals/ExcludeFolderSettings'
import { ExcludePattern } from './ExcludeFolders/ExcludePattern';
import PatternSettings from './ExcludeFolders/modals/PatternSettings';
import { loadFolderClasses } from './functions/styleFunctions';
export class Commands {
plugin: FolderNotesPlugin;
@ -34,6 +35,7 @@ export class Commands {
turnIntoFolderNote(this.plugin, file, folder, folderNote);
}
});
this.plugin.addCommand({
id: 'create-folder-note',
name: 'Create folder note with a new folder for the active note in the current folder',
@ -58,6 +60,7 @@ export class Commands {
this.plugin.saveSettings();
}
})
this.plugin.addCommand({
id: 'create-folder-note-for-current-folder',
name: 'Create markdown folder note for current folder of active note',
@ -199,7 +202,7 @@ export class Commands {
}
fileCommands() {
this.plugin.registerEvent(this.app.workspace.on('file-menu', (menu: Menu, file: TAbstractFile) => {
this.plugin.registerEvent(this.app.workspace.on('file-menu', async (menu: Menu, file: TAbstractFile) => {
let folder: TAbstractFile | TFolder | null = file.parent;
if (file instanceof TFile) {
if (this.plugin.settings.storageLocation === 'insideFolder') {
@ -217,14 +220,14 @@ export class Commands {
if (folder instanceof TFolder) {
const folderNote = getFolderNote(this.plugin, folder.path);
const excludedFolder = getExcludedFolder(this.plugin, folder.path, true)
const excludedFolder = await getExcludedFolder(this.plugin, folder.path, true)
if (folderNote?.path === file.path && !excludedFolder?.detached) { return; }
} else if (file.parent instanceof TFolder) {
folder = file.parent;
}
}
menu.addItem((item) => {
menu.addItem(async (item) => {
if (Platform.isDesktop && !Platform.isTablet && this.plugin.settings.useSubmenus) {
item
.setTitle('Folder Note Commands')
@ -276,10 +279,10 @@ export class Commands {
});
}
if (!(file instanceof TFolder)) return;
const excludedFolder = getExcludedFolder(this.plugin, file.path, false)
const excludedFolder = await getExcludedFolder(this.plugin, file.path, false)
const detachedExcludedFolder = getDetachedFolder(this.plugin, file.path)
if (excludedFolder) {
if (excludedFolder && !excludedFolder.hideNote) {
// I'm not sure if I'm ever going to add this because of the possibility that a folder got more than one excluded
// subMenu.addItem((item) => {
// item.setTitle('Manage excluded folder')
@ -339,7 +342,6 @@ export class Commands {
item.setTitle('Detach folder note')
.setIcon('unlink')
.onClick(() => {
console.log('folderNote', folderNote)
detachFolderNote(this.plugin, folderNote);
});
});
@ -353,6 +355,39 @@ export class Commands {
});
});
if (this.plugin.settings.hideFolderNote) {
if (excludedFolder?.hideNote) {
subMenu.addItem((item) => {
item.setTitle('Hide folder note in explorer')
.setIcon('eye-off')
.onClick(() => {
this.plugin.settings.excludeFolders = this.plugin.settings.excludeFolders.filter(
(folder) => (folder.path !== file.path) && folder.hideNote);
this.plugin.saveSettings(false);
loadFolderClasses(true, file, this.plugin);
});
});
} else {
subMenu.addItem((item) => {
item.setTitle('Show folder note in explorer')
.setIcon('eye')
.onClick(() => {
const excludedFolder = new ExcludedFolder(file.path, this.plugin.settings.excludeFolders.length, undefined, this.plugin);
excludedFolder.hideNote = true;
excludedFolder.subFolders = false;
excludedFolder.disableSync = false;
excludedFolder.disableAutoCreate = false;
excludedFolder.disableFolderNote = false;
excludedFolder.enableCollapsing = false;
excludedFolder.excludeFromFolderOverview = false;
excludedFolder.hideInSettings = true;
addExcludedFolder(this.plugin, excludedFolder, false);
loadFolderClasses(true, file, this.plugin);
});
});
}
}
} else {
subMenu.addItem((item) => {
item.setTitle('Create markdown folder note')

View file

@ -14,6 +14,7 @@ export class ExcludedFolder {
hideInSettings: boolean;
detached: boolean;
detachedFilePath?: string;
hideNote: boolean;
constructor(path: string, position: number, id: string | undefined, plugin: FolderNotesPlugin) {
this.type = 'folder';
this.id = id || crypto.randomUUID();
@ -27,5 +28,6 @@ export class ExcludedFolder {
this.excludeFromFolderOverview = plugin.settings.excludeFolderDefaultSettings.excludeFromFolderOverview;
this.string = '';
this.hideInSettings = false;
this.hideNote = false;
}
}

View file

@ -14,6 +14,7 @@ export class ExcludePattern {
hideInSettings: boolean;
detached: boolean;
detachedFilePath?: string;
hideNote: boolean;
constructor(pattern: string, position: number, id: string | undefined, plugin: FolderNotesPlugin) {
this.type = 'pattern';
this.id = id || crypto.randomUUID();

View file

@ -11,12 +11,12 @@ import { getWhitelistedFolder } from './whitelistFolderFunctions';
import { WhitelistedFolder } from '../WhitelistFolder';
import { WhitelistedPattern } from '../WhitelistPattern';
export function getExcludedFolder(plugin: FolderNotesPlugin, path: string, includeDetached: boolean, pathOnly?: boolean, ignoreWhitelist?: boolean) {
export async function getExcludedFolder(plugin: FolderNotesPlugin, path: string, includeDetached: boolean, pathOnly?: boolean, ignoreWhitelist?: boolean) {
let excludedFolder = {} as ExcludedFolder | ExcludePattern | undefined;
const whitelistedFolder = getWhitelistedFolder(plugin, path) as WhitelistedFolder | WhitelistedPattern | undefined;
const folderName = getFolderNameFromPathString(path);
let matchedPatterns = getExcludedFoldersByPattern(plugin, folderName);
const excludedFolders = getExcludedFoldersByPath(plugin, path);
let matchedPatterns = await getExcludedFoldersByPattern(plugin, folderName);
const excludedFolders = await getExcludedFoldersByPath(plugin, path);
if (pathOnly) { matchedPatterns = []; }
let combinedExcludedFolders = [...matchedPatterns, ...excludedFolders];
@ -31,7 +31,9 @@ export function getExcludedFolder(plugin: FolderNotesPlugin, path: string, inclu
'enableCollapsing',
'excludeFromFolderOverview',
'detached',
'hideInSettings'
'hideInSettings',
'hideNote',
'id'
];
if (combinedExcludedFolders.length > 0) {
@ -51,14 +53,12 @@ export function getExcludedFolder(plugin: FolderNotesPlugin, path: string, inclu
if (excludedFolder?.detached) { ignoreWhitelist = true; }
if (whitelistedFolder && excludedFolder && !ignoreWhitelist) {
console.log('whitelistedFolder', whitelistedFolder)
excludedFolder.disableAutoCreate ? excludedFolder.disableAutoCreate = !whitelistedFolder.enableAutoCreate : '';
excludedFolder.disableFolderNote ? excludedFolder.disableFolderNote = !whitelistedFolder.enableFolderNote : '';
excludedFolder.disableSync ? excludedFolder.disableSync = !whitelistedFolder.enableSync : '';
excludedFolder.enableCollapsing = whitelistedFolder.enableCollapsing;
excludedFolder.excludeFromFolderOverview ? excludedFolder.excludeFromFolderOverview = !whitelistedFolder.showInFolderOverview : '';
} else if (excludedFolder && Object.keys(excludedFolder).length === 0) {
console.log('Hello from the other side')
excludedFolder = {
type: 'folder',
id: '',
@ -72,7 +72,8 @@ export function getExcludedFolder(plugin: FolderNotesPlugin, path: string, inclu
position: 0,
excludeFromFolderOverview: false,
hideInSettings: false,
detached: false
detached: false,
hideNote: false,
}
}
@ -118,12 +119,12 @@ export function getExcludedFoldersByPath(plugin: FolderNotesPlugin, path: string
});
}
export function addExcludedFolder(plugin: FolderNotesPlugin, excludedFolder: ExcludedFolder) {
export function addExcludedFolder(plugin: FolderNotesPlugin, excludedFolder: ExcludedFolder, reloadStyles = true) {
plugin.settings.excludeFolders.push(excludedFolder);
plugin.saveSettings(true);
plugin.saveSettings(reloadStyles);
}
export function deleteExcludedFolder(plugin: FolderNotesPlugin, excludedFolder: ExcludedFolder) {
export async function deleteExcludedFolder(plugin: FolderNotesPlugin, excludedFolder: ExcludedFolder) {
plugin.settings.excludeFolders = plugin.settings.excludeFolders.filter((folder) => folder.id !== excludedFolder.id || folder.type === 'pattern');
plugin.saveSettings(true);
resyncArray(plugin);

View file

@ -53,7 +53,7 @@ export async function addObserver(plugin: FolderNotesPlugin) {
const breadcrumbs = element.parentElement?.querySelectorAll('span.view-header-breadcrumb');
if (!breadcrumbs) return;
let path = '';
breadcrumbs.forEach((breadcrumb: HTMLElement) => {
breadcrumbs.forEach(async (breadcrumb: HTMLElement) => {
if (breadcrumb.hasAttribute('old-name')) {
path += breadcrumb.getAttribute('old-name') + '/';
} else {
@ -66,7 +66,7 @@ export async function addObserver(plugin: FolderNotesPlugin) {
breadcrumb.setAttribute('old-name', folder.name || '');
breadcrumb.innerText = folder.newName || '';
}
const excludedFolder = getExcludedFolder(plugin, folderPath, true)
const excludedFolder = await getExcludedFolder(plugin, folderPath, true)
if (excludedFolder?.disableFolderNote) return;
const folderNote = getFolderNote(plugin, folderPath);
if (folderNote) {

View file

@ -13,7 +13,7 @@ export async function handleViewHeaderClick(event: MouseEvent, plugin: FolderNot
const folderPath = event.target.getAttribute('data-path');
if (!folderPath) { return; }
const excludedFolder = getExcludedFolder(plugin, folderPath, true);
const excludedFolder = await getExcludedFolder(plugin, folderPath, true);
if (excludedFolder?.disableFolderNote) {
event.target.onclick = null;
event.target.click();
@ -38,7 +38,7 @@ export async function handleViewHeaderClick(event: MouseEvent, plugin: FolderNot
} else if (event.altKey || Keymap.isModEvent(event) === 'tab') {
if ((plugin.settings.altKey && event.altKey) || (plugin.settings.ctrlKey && Keymap.isModEvent(event) === 'tab')) {
await createFolderNote(plugin, folderPath, true, undefined, true);
addCSSClassToTitleEL(folderPath, 'has-folder-note');
addCSSClassToTitleEL(plugin, folderPath, 'has-folder-note');
removeCSSClassFromEL(folderPath, 'has-not-folder-note');
return;
}
@ -59,7 +59,7 @@ export async function handleFolderClick(event: MouseEvent, plugin: FolderNotesPl
const folderPath = event.target.parentElement?.getAttribute('data-path');
if (!folderPath) { return; }
const excludedFolder = getExcludedFolder(plugin, folderPath, true);
const excludedFolder = await getExcludedFolder(plugin, folderPath, true);
if (excludedFolder?.disableFolderNote) {
event.target.onclick = null;
event.target.click();
@ -70,7 +70,6 @@ export async function handleFolderClick(event: MouseEvent, plugin: FolderNotesPl
}
const folderNote = getFolderNote(plugin, folderPath);
console.log('folderNote', folderNote);
if (folderNote) {
if (plugin.settings.openByClick) {
@ -87,7 +86,7 @@ export async function handleFolderClick(event: MouseEvent, plugin: FolderNotesPl
} else if (event.altKey || Keymap.isModEvent(event) === 'tab') {
if ((plugin.settings.altKey && event.altKey) || (plugin.settings.ctrlKey && Keymap.isModEvent(event) === 'tab')) {
await createFolderNote(plugin, folderPath, true, undefined, true);
addCSSClassToTitleEL(folderPath, 'has-folder-note');
addCSSClassToTitleEL(plugin, folderPath, 'has-folder-note');
removeCSSClassFromEL(folderPath, 'has-not-folder-note');
return;
}

View file

@ -4,13 +4,13 @@ import { createFolderNote, getFolder, getFolderNote } from 'src/functions/folder
import { getExcludedFolder } from 'src/ExcludeFolders/functions/folderFunctions';
import { removeCSSClassFromEL, addCSSClassToTitleEL } from 'src/functions/styleFunctions';
export function handleCreate(file: TAbstractFile, plugin: FolderNotesPlugin) {
export async function handleCreate(file: TAbstractFile, plugin: FolderNotesPlugin) {
if (!plugin.app.workspace.layoutReady) return;
const folder = file.parent;
if (folder instanceof TFolder) {
if (plugin.isEmptyFolderNoteFolder(folder)) {
addCSSClassToTitleEL(folder.path, 'only-has-folder-note');
addCSSClassToTitleEL(plugin, folder.path, 'only-has-folder-note');
} else {
removeCSSClassFromEL(folder.path, 'only-has-folder-note');
}
@ -22,8 +22,8 @@ export function handleCreate(file: TAbstractFile, plugin: FolderNotesPlugin) {
const folderNote = getFolderNote(plugin, folder.path);
if (folderNote && folderNote.path === file.path) {
addCSSClassToTitleEL(folder.path, 'has-folder-note');
addCSSClassToTitleEL(file.path, 'is-folder-note');
addCSSClassToTitleEL(plugin, folder.path, 'has-folder-note');
addCSSClassToTitleEL(plugin, file.path, 'is-folder-note');
return;
}
@ -45,12 +45,12 @@ export function handleCreate(file: TAbstractFile, plugin: FolderNotesPlugin) {
openFile = false;
}
const excludedFolder = getExcludedFolder(plugin, file.path, true);
const excludedFolder = await getExcludedFolder(plugin, file.path, true);
if (excludedFolder?.disableAutoCreate) return;
const folderNote = getFolderNote(plugin, file.path);
if (folderNote) return;
createFolderNote(plugin, file.path, openFile, undefined, true);
addCSSClassToTitleEL(file.path, 'has-folder-note');
addCSSClassToTitleEL(plugin, file.path, 'has-folder-note');
}

View file

@ -12,7 +12,7 @@ export function handleRename(file: TAbstractFile, oldPath: string, plugin: Folde
const isRename = (file.parent?.path === getFolderPathFromString(oldPath))
if (folder instanceof TFolder) {
if (plugin.isEmptyFolderNoteFolder(folder)) {
addCSSClassToTitleEL(folder.path, 'only-has-folder-note');
addCSSClassToTitleEL(plugin, folder.path, 'only-has-folder-note');
} else {
removeCSSClassFromEL(folder.path, 'only-has-folder-note');
}
@ -20,7 +20,7 @@ export function handleRename(file: TAbstractFile, oldPath: string, plugin: Folde
if (oldFolder instanceof TFolder) {
if (plugin.isEmptyFolderNoteFolder(oldFolder)) {
addCSSClassToTitleEL(oldFolder.path, 'only-has-folder-note');
addCSSClassToTitleEL(plugin, oldFolder.path, 'only-has-folder-note');
} else {
removeCSSClassFromEL(oldFolder.path, 'only-has-folder-note');
}
@ -52,7 +52,7 @@ export function handleFileMove(file: TFile, oldPath: string, plugin: FolderNotes
}
export function handleFolderRename(file: TFolder, oldPath: string, plugin: FolderNotesPlugin) {
export async function handleFolderRename(file: TFolder, oldPath: string, plugin: FolderNotesPlugin) {
const fileName = plugin.settings.folderNoteName.replace('{{folder_name}}', file.name);
const oldFileName = plugin.settings.folderNoteName.replace('{{folder_name}}', getFileNameFromPathString(oldPath));
// console.log(fileName)
@ -63,7 +63,7 @@ export function handleFolderRename(file: TFolder, oldPath: string, plugin: Folde
if (!(folderNote instanceof TFile)) return;
const excludedFolder = getExcludedFolder(plugin, file.path, true);
const excludedFolder = await getExcludedFolder(plugin, file.path, true);
if (excludedFolder?.disableSync && !folderNote) {
return removeCSSClassFromEL(file.path, 'has-folder-note');
}
@ -91,7 +91,7 @@ export function handleFolderRename(file: TFolder, oldPath: string, plugin: Folde
plugin.app.fileManager.renameFile(folderNote, newPath);
}
export function handleFileRename(file: TFile, oldPath: string, plugin: FolderNotesPlugin) {
export async function handleFileRename(file: TFile, oldPath: string, plugin: FolderNotesPlugin) {
const oldFileName = removeExtension(getFileNameFromPathString(oldPath));
const newFileName = file.basename;
if (oldFileName === newFileName) { return; }
@ -100,15 +100,15 @@ export function handleFileRename(file: TFile, oldPath: string, plugin: FolderNot
const folderName = extractFolderName(plugin.settings.folderNoteName, file.basename) || file.basename;
const oldFolderName = extractFolderName(plugin.settings.folderNoteName, oldFileName) || oldFileName;
const newFolder = getFolderNoteFolder(plugin, file, file.basename);
let excludedFolder = getExcludedFolder(plugin, newFolder?.path || '', true);
let excludedFolder = await getExcludedFolder(plugin, newFolder?.path || '', true);
const detachedExcludedFolder = getDetachedFolder(plugin, newFolder?.path || '')
const folderNote = getFolderNote(plugin, oldPath, plugin.settings.storageLocation, file);
if (!excludedFolder?.disableFolderNote && folderName === newFolder?.name && !detachedExcludedFolder) {
addCSSClassToTitleEL(file.path, 'is-folder-note');
addCSSClassToTitleEL(newFolder.path, 'has-folder-note');
addCSSClassToTitleEL(plugin, file.path, 'is-folder-note');
addCSSClassToTitleEL(plugin, newFolder.path, 'has-folder-note');
return;
} else if (excludedFolder?.disableFolderNote || (folderName !== newFolder?.name)) {
removeCSSClassFromEL(file.path, 'is-folder-note');
@ -143,9 +143,9 @@ export function handleFileRename(file: TFile, oldPath: string, plugin: FolderNot
});
}
if (folderName === newFolder?.name) {
addCSSClassToTitleEL(file.path, 'is-folder-note');
addCSSClassToTitleEL(plugin, file.path, 'is-folder-note');
removeCSSClassFromEL(oldFolder?.path, 'has-folder-note');
addCSSClassToTitleEL(newFolder.path, 'has-folder-note');
addCSSClassToTitleEL(plugin, newFolder.path, 'has-folder-note');
return;
}
@ -175,8 +175,8 @@ async function renameFolderOnFileRename(file: TFile, oldPath: string, oldFolder:
removeCSSClassFromEL(file.path, 'is-folder-note');
return;
} else if (newFolderName === oldFolder.name) {
addCSSClassToTitleEL(oldFolder.path, 'has-folder-note');
addCSSClassToTitleEL(file.path, 'is-folder-note');
addCSSClassToTitleEL(plugin, oldFolder.path, 'has-folder-note');
addCSSClassToTitleEL(plugin, file.path, 'is-folder-note');
return;
}

View file

@ -9,230 +9,338 @@ import { FolderOverview, yamlSettings } from './FolderOverview';
import FolderNameModal from 'src/modals/FolderName';
import NewFolderNameModal from 'src/modals/NewFolderName';
export async function renderFileExplorer(plugin: FolderNotesPlugin, ctx: MarkdownPostProcessorContext, root: HTMLElement, yaml: yamlSettings, pathBlacklist: string[], folderOverview: FolderOverview) {
const folder = getEl(yaml.folderPath)
let folderElement = folder?.parentElement;
const source = ctx.sourcePath;
const overviewList = folderOverview.listEl;
overviewList?.empty();
if (!overviewList) return;
export class FileExplorerOverview {
plugin: FolderNotesPlugin;
folderOverview: FolderOverview;
pathBlacklist: string[];
source: string;
yaml: yamlSettings;
root: HTMLElement;
let tFolder = plugin.app.vault.getAbstractFileByPath(yaml.folderPath);
if (!tFolder && yaml.folderPath.trim() == '') {
if (ctx.sourcePath.includes('/')) {
tFolder = plugin.app.vault.getAbstractFileByPath(getFolderPathFromString(ctx.sourcePath));
} else {
yaml.folderPath = '/';
tFolder = plugin.app.vault.getAbstractFileByPath('/');
}
eventListeners: (() => void)[] = [];
constructor(plugin: FolderNotesPlugin, ctx: MarkdownPostProcessorContext, root: HTMLElement, yaml: yamlSettings, pathBlacklist: string[], folderOverview: FolderOverview) {
this.plugin = plugin;
this.folderOverview = folderOverview;
this.pathBlacklist = pathBlacklist;
this.source = ctx.sourcePath;
this.yaml = yaml;
this.root = root;
}
if (!folderElement && !tFolder) return;
disconnectListeners() {
this.eventListeners.forEach((unregister) => {
unregister();
});
this.eventListeners = [];
}
folderElement = document.querySelectorAll('.nav-files-container')[0] as HTMLElement;
if (!folderElement) return;
const newFolderElement = folderElement.cloneNode(true) as HTMLElement;
newFolderElement.querySelectorAll('div.nav-folder-title').forEach((el) => {
const folder = plugin.app.vault.getAbstractFileByPath(el.getAttribute('data-path') || '');
if (!(folder instanceof TFolder)) return;
if (yaml.storeFolderCondition) {
if (folder.collapsed) {
el.classList.add('is-collapsed');
async renderFileExplorer() {
this.disconnectListeners();
const plugin = this.plugin;
const ctx = this.folderOverview.ctx;
const root = this.folderOverview.root;
const yaml = this.folderOverview.yaml;
const folderOverview = this.folderOverview;
const folder = getEl(yaml.folderPath)
let folderElement = folder?.parentElement;
const source = ctx.sourcePath;
const overviewList = folderOverview.listEl;
overviewList?.empty();
if (!overviewList) return;
let tFolder = plugin.app.vault.getAbstractFileByPath(yaml.folderPath);
if (!tFolder && yaml.folderPath.trim() == '') {
if (ctx.sourcePath.includes('/')) {
tFolder = plugin.app.vault.getAbstractFileByPath(getFolderPathFromString(ctx.sourcePath));
} else {
el.classList.remove('is-collapsed');
yaml.folderPath = '/';
tFolder = plugin.app.vault.getAbstractFileByPath('/');
}
} else {
if (el.parentElement?.classList.contains('is-collapsed')) {
folder.collapsed = true;
}
if (!folderElement && !tFolder) return;
// wait until the file explorer is loaded
folderElement = document.querySelectorAll('.nav-files-container')[0] as HTMLElement;
console.log('folderElement', folderElement);
if (!folderElement) return;
const newFolderElement = folderElement.cloneNode(true) as HTMLElement;
console.log('newFolderElement', newFolderElement);
newFolderElement.querySelectorAll('div.nav-folder-title').forEach((el) => {
const folder = plugin.app.vault.getAbstractFileByPath(el.getAttribute('data-path') || '');
if (!(folder instanceof TFolder)) return;
if (yaml.storeFolderCondition) {
if (folder.collapsed) {
el.classList.add('is-collapsed');
} else {
el.classList.remove('is-collapsed');
}
} else {
folder.collapsed = false;
if (el.parentElement?.classList.contains('is-collapsed')) {
folder.collapsed = true;
} else {
folder.collapsed = false;
}
}
}
if (el.classList.contains('has-folder-note')) {
const folderNote = getFolderNote(plugin, folder.path);
if (folderNote) { pathBlacklist.push(folderNote.path); }
}
});
if (el.classList.contains('has-folder-note')) {
const folderNote = getFolderNote(plugin, folder.path);
if (folderNote) { folderOverview.pathBlacklist.push(folderNote.path); }
}
});
folderOverview.on('vault-change', async () => {
renderFileExplorer(plugin, ctx, root, yaml, pathBlacklist, folderOverview);
});
const debouncedRenderFileExplorer = this.debounce(() => this.renderFileExplorer(), 300);
if (tFolder instanceof TFolder) {
addFiles(tFolder.children, overviewList, folderOverview);
const handleVaultChange = () => {
debouncedRenderFileExplorer();
}
this.eventListeners.push(() => {
folderOverview.off('vault-change', handleVaultChange);
});
folderOverview.on('vault-change', handleVaultChange);
if (tFolder instanceof TFolder) {
this.addFiles(tFolder.children, overviewList, folderOverview);
}
newFolderElement.querySelectorAll('div.tree-item-icon').forEach((el) => {
if (el instanceof HTMLElement) {
el.onclick = () => {
const path = el.parentElement?.getAttribute('data-path');
if (!path) return;
const folder = plugin.app.vault.getAbstractFileByPath(path);
this.handleCollapseClick(el, plugin, yaml, this.pathBlacklist, source, folderOverview, folder);
}
}
});
}
newFolderElement.querySelectorAll('div.tree-item-icon').forEach((el) => {
if (el instanceof HTMLElement) {
el.onclick = () => {
const path = el.parentElement?.getAttribute('data-path');
if (!path) return;
const folder = plugin.app.vault.getAbstractFileByPath(path);
handleCollapseClick(el, plugin, yaml, pathBlacklist, source, folderOverview, folder);
debounce(func: Function, wait: number) {
let timeout: number | undefined;
return (...args: any[]) => {
clearTimeout(timeout);
timeout = window.setTimeout(() => func.apply(this, args), wait);
};
}
addFiles(files: TAbstractFile[], childrenElement: HTMLElement, folderOverview: FolderOverview) {
const plugin = folderOverview.plugin;
const pathBlacklist = folderOverview.pathBlacklist;
const yaml = folderOverview.yaml;
const folders = folderOverview.sortFiles(files.filter((file) => file instanceof TFolder));
const filesWithoutFolders = folderOverview.sortFiles(files.filter((file) => !(file instanceof TFolder)));
for (const child of folders) {
if (child instanceof TFolder) {
this.createFolderEL(plugin, child, folderOverview, childrenElement);
}
}
});
}
async function addFiles(files: TAbstractFile[], childrenElement: HTMLElement, folderOverview: FolderOverview) {
const plugin = folderOverview.plugin;
const pathBlacklist = folderOverview.pathBlacklist;
const yaml = folderOverview.yaml;
const folders = folderOverview.sortFiles(files.filter((file) => file instanceof TFolder));
const filesWithoutFolders = folderOverview.sortFiles(files.filter((file) => !(file instanceof TFolder)));
for (const child of filesWithoutFolders) {
if (child instanceof TFile) {
if (pathBlacklist.includes(child.path) && !yaml.showFolderNotes) { continue; }
const extension = child.extension.toLowerCase() == 'md' ? 'markdown' : child.extension.toLowerCase();
const includeTypes = yaml.includeTypes;
for (const child of folders) {
if (child instanceof TFolder) {
createFolderEL(plugin, child, folderOverview, childrenElement);
if (includeTypes.length > 0 && !includeTypes.includes('all')) {
if ((extension === 'md' || extension === 'markdown') && !includeTypes.includes('markdown')) continue;
if (extension === 'canvas' && !includeTypes.includes('canvas')) continue;
if (extension === 'pdf' && !includeTypes.includes('pdf')) continue;
const imageTypes = ['jpg', 'jpeg', 'png', 'gif', 'svg', 'webp'];
if (imageTypes.includes(extension) && !includeTypes.includes('image')) continue;
const videoTypes = ['mp4', 'webm', 'ogv', 'mov', 'mkv'];
if (videoTypes.includes(extension) && !includeTypes.includes('video')) continue;
const audioTypes = ['mp3', 'wav', 'm4a', '3gp', 'flac', 'ogg', 'oga', 'opus'];
if (audioTypes.includes(extension) && includeTypes.includes('audio')) continue;
const allTypes = ['markdown', 'md', 'canvas', 'pdf', ...imageTypes, ...videoTypes, ...audioTypes];
if (!allTypes.includes(extension) && !includeTypes.includes('other')) continue;
}
const fileElement = childrenElement.createDiv({
cls: 'tree-item nav-file',
});
const fileTitle = fileElement.createDiv({
cls: 'tree-item-self is-clickable nav-file-title pointer-cursor',
attr: {
'data-path': child.path,
'draggable': 'true'
},
})
fileTitle.addEventListener('dragover', e => {
e.preventDefault();
const { draggable } = plugin.app.dragManager;
if (draggable && draggable.file instanceof TFolder) {
plugin.app.dragManager.setAction(window.i18next.t("interface.drag-and-drop.move-into-folder", { folder: child.parent?.name || '' }));
const folderEL = folderOverview.getElFromOverview(child.parent?.path || '')
if (folderEL) {
folderEL.parentElement?.classList.add('is-being-dragged-over');
}
}
});
fileTitle.addEventListener('dragleave', e => {
const folderEL = folderOverview.getElFromOverview(child.parent?.path || '')
if (folderEL) {
folderEL.parentElement?.classList.remove('is-being-dragged-over');
}
});
fileTitle.addEventListener('drop', e => {
const { draggable } = plugin.app.dragManager;
if (draggable && draggable.file instanceof TFolder) {
plugin.app.fileManager.renameFile(draggable.file, child.parent?.path + '/' + draggable.file.name);
}
});
fileTitle.onclick = () => {
plugin.app.workspace.openLinkText(child.path, child.path, true);
}
fileTitle.oncontextmenu = (e) => {
folderOverview.fileMenu(child, e);
}
fileTitle.createDiv({
cls: 'tree-item-inner nav-file-title-content',
text: child.basename,
});
if (child.extension !== 'md' && !yaml.disableFileTag) {
fileTitle.createDiv({
cls: 'nav-file-tag',
text: child.extension
});
}
}
}
}
for (const child of filesWithoutFolders) {
if (child instanceof TFile) {
if (pathBlacklist.includes(child.path) && !yaml.showFolderNotes) { continue; }
const extension = child.extension.toLowerCase() == 'md' ? 'markdown' : child.extension.toLowerCase();
const includeTypes = yaml.includeTypes;
handleCollapseClick(el: HTMLElement, plugin: FolderNotesPlugin, yaml: yamlSettings, pathBlacklist: string[], sourcePath: string, folderOverview: FolderOverview, folder?: TFolder | undefined | null | TAbstractFile) {
el.classList.toggle('is-collapsed');
if (el.classList.contains('is-collapsed')) {
if (!(folder instanceof TFolder)) return;
folder.collapsed = true;
el.parentElement?.parentElement?.childNodes[1]?.remove();
} else {
if (!(folder instanceof TFolder)) return;
folder.collapsed = false;
const folderElement = el.parentElement?.parentElement;
if (!folderElement) return;
const childrenElement = folderElement.createDiv({ cls: 'tree-item-children nav-folder-children' });
let files = folderOverview.sortFiles(folder.children);
files = folderOverview.filterFiles(files, plugin, folder.path, yaml.depth || 1, pathBlacklist);
this.addFiles(files, childrenElement, folderOverview);
}
}
if (includeTypes.length > 0 && !includeTypes.includes('all')) {
if ((extension === 'md' || extension === 'markdown') && !includeTypes.includes('markdown')) continue;
if (extension === 'canvas' && !includeTypes.includes('canvas')) continue;
if (extension === 'pdf' && !includeTypes.includes('pdf')) continue;
const imageTypes = ['jpg', 'jpeg', 'png', 'gif', 'svg', 'webp'];
if (imageTypes.includes(extension) && !includeTypes.includes('image')) continue;
const videoTypes = ['mp4', 'webm', 'ogv', 'mov', 'mkv'];
if (videoTypes.includes(extension) && !includeTypes.includes('video')) continue;
const audioTypes = ['mp3', 'wav', 'm4a', '3gp', 'flac', 'ogg', 'oga', 'opus'];
if (audioTypes.includes(extension) && includeTypes.includes('audio')) continue;
const allTypes = ['markdown', 'md', 'canvas', 'pdf', ...imageTypes, ...videoTypes, ...audioTypes];
if (!allTypes.includes(extension) && !includeTypes.includes('other')) continue;
}
async createFolderEL(plugin: FolderNotesPlugin, child: TFolder, folderOverview: FolderOverview, childrenElement: HTMLElement) {
const pathBlacklist = folderOverview.pathBlacklist;
const source = folderOverview.source;
const folderNote = getFolderNote(plugin, child.path);
const yaml = folderOverview.yaml;
let folderTitle: HTMLElement | null = null;
let folderElement: HTMLElement | null = null;
const fileElement = childrenElement.createDiv({
cls: 'tree-item nav-file',
if (folderNote) { pathBlacklist.push(folderNote.path); }
const excludedFolder = await getExcludedFolder(plugin, child.path, true);
if (excludedFolder?.excludeFromFolderOverview) { return; }
const svg = '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="svg-icon right-triangle"><path d="M3 8L12 17L21 8"></path></svg>';
if (yaml.includeTypes.includes('folder')) {
folderElement = childrenElement.createDiv({
cls: 'tree-item nav-folder',
});
const fileTitle = fileElement.createDiv({
cls: 'tree-item-self is-clickable nav-file-title pointer-cursor',
folderTitle = folderElement.createDiv({
cls: 'tree-item-self is-clickable nav-folder-title',
attr: {
'data-path': child.path,
'draggable': 'true'
},
})
fileTitle.onclick = () => {
plugin.app.workspace.openLinkText(child.path, child.path, true);
}
fileTitle.oncontextmenu = (e) => {
folderOverview.fileMenu(child, e);
}
fileTitle.createDiv({
cls: 'tree-item-inner nav-file-title-content',
text: child.basename,
folderTitle.draggable = true;
folderTitle.addEventListener('dragstart', e => {
const dragManager = plugin.app.dragManager;
const dragData = dragManager.dragFolder(e, child);
dragManager.onDragStart(e, dragData);
folderTitle?.classList.add('is-being-dragged');
});
if (child.extension !== 'md' && !yaml.disableFileTag) {
fileTitle.createDiv({
cls: 'nav-file-tag',
text: child.extension
});
folderTitle.addEventListener('dragend', e => {
folderTitle?.classList.remove('is-being-dragged');
});
folderTitle.addEventListener('dragover', e => {
e.preventDefault();
const { draggable } = plugin.app.dragManager;
if (draggable && draggable.file instanceof TFolder) {
folderElement?.classList.add('is-being-dragged-over');
plugin.app.dragManager.setAction(window.i18next.t("interface.drag-and-drop.move-into-folder", { folder: child.name }));
}
});
folderTitle.addEventListener('dragleave', e => {
folderElement?.classList.remove('is-being-dragged-over');
});
// handle the drop event
folderTitle.addEventListener('drop', e => {
const { draggable } = plugin.app.dragManager;
if (draggable && draggable.file instanceof TFolder) {
plugin.app.fileManager.renameFile(draggable.file, child.path + '/' + draggable.file.name);
}
});
folderTitle.oncontextmenu = (e) => {
folderOverview.folderMenu(child, e);
}
}
}
}
function handleCollapseClick(el: HTMLElement, plugin: FolderNotesPlugin, yaml: yamlSettings, pathBlacklist: string[], sourcePath: string, folderOverview: FolderOverview, folder?: TFolder | undefined | null | TAbstractFile) {
console.log('el', el);
el.classList.toggle('is-collapsed');
console.log('el', el);
if (el.classList.contains('is-collapsed')) {
if (!(folder instanceof TFolder)) return;
folder.collapsed = true;
el.parentElement?.parentElement?.childNodes[1]?.remove();
} else {
if (!(folder instanceof TFolder)) return;
folder.collapsed = false;
const folderElement = el.parentElement?.parentElement;
if (!folderElement) return;
const childrenElement = folderElement.createDiv({ cls: 'tree-item-children nav-folder-children' });
let files = folderOverview.sortFiles(folder.children);
files = folderOverview.filterFiles(files, plugin, folder.path, yaml.depth || 1, pathBlacklist);
addFiles(files, childrenElement, folderOverview);
}
}
function createFolderEL(plugin: FolderNotesPlugin, child: TFolder, folderOverview: FolderOverview, childrenElement: HTMLElement) {
const pathBlacklist = folderOverview.pathBlacklist;
const source = folderOverview.source;
const folderNote = getFolderNote(plugin, child.path);
const yaml = folderOverview.yaml;
let folderTitle: HTMLElement | null = null;
let folderElement: HTMLElement | null = null;
if (folderNote) { pathBlacklist.push(folderNote.path); }
const excludedFolder = getExcludedFolder(plugin, child.path, true);
if (excludedFolder?.excludeFromFolderOverview) { return; }
const svg = '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="svg-icon right-triangle"><path d="M3 8L12 17L21 8"></path></svg>';
if (yaml.includeTypes.includes('folder')) {
folderElement = childrenElement.createDiv({
cls: 'tree-item nav-folder',
});
folderTitle = folderElement.createDiv({
cls: 'tree-item-self is-clickable nav-folder-title',
attr: {
'data-path': child.path,
'draggable': 'true'
},
})
folderTitle.oncontextmenu = (e) => {
folderOverview.folderMenu(child, e);
}
}
if (!child.collapsed) {
if (yaml.includeTypes.includes('folder')) {
folderTitle?.classList.remove('is-collapsed');
const childrenElement = folderElement?.createDiv({ cls: 'tree-item-children nav-folder-children' });
if (childrenElement) {
addFiles(child.children, childrenElement, folderOverview);
if (!child.collapsed) {
if (yaml.includeTypes.includes('folder')) {
folderTitle?.classList.remove('is-collapsed');
const childrenElement = folderElement?.createDiv({ cls: 'tree-item-children nav-folder-children' });
if (childrenElement) {
this.addFiles(child.children, childrenElement, folderOverview);
}
} else {
this.addFiles(child.children, childrenElement, folderOverview);
}
} else {
addFiles(child.children, childrenElement, folderOverview);
folderTitle?.classList.add('is-collapsed');
}
} else {
folderTitle?.classList.add('is-collapsed');
}
if (folderNote) { folderTitle?.classList.add('has-folder-note') }
if (folderNote && child.children.length === 1 && yaml.disableCollapseIcon) { folderTitle?.classList.add('fn-has-no-files') }
if (folderNote) { folderTitle?.classList.add('has-folder-note') }
if (folderNote && child.children.length === 1 && yaml.disableCollapseIcon) { folderTitle?.classList.add('fn-has-no-files') }
const collapseIcon = folderTitle?.createDiv({
cls: 'tree-item-icon collapse-icon nav-folder-collapse-indicator fn-folder-overview-collapse-icon',
});
const collapseIcon = folderTitle?.createDiv({
cls: 'tree-item-icon collapse-icon nav-folder-collapse-indicator fn-folder-overview-collapse-icon',
});
if (child.collapsed) {
collapseIcon?.classList.add('is-collapsed');
}
if (collapseIcon) {
collapseIcon.innerHTML = svg;
collapseIcon.onclick = () => {
handleCollapseClick(collapseIcon, plugin, yaml, pathBlacklist, source, folderOverview, child);
if (child.collapsed) {
collapseIcon?.classList.add('is-collapsed');
}
if (collapseIcon) {
collapseIcon.innerHTML = svg;
collapseIcon.onclick = () => {
this.handleCollapseClick(collapseIcon, plugin, yaml, pathBlacklist, source, folderOverview, child);
}
}
}
const folderTitleText = folderTitle?.createDiv({
cls: 'tree-item-inner nav-folder-title-content',
text: child.name,
});
const folderTitleText = folderTitle?.createDiv({
cls: 'tree-item-inner nav-folder-title-content',
text: child.name,
});
if (folderTitleText && !folderNote) {
folderTitleText.onclick = () => {
const collapseIcon = folderTitle?.querySelectorAll('.tree-item-icon')[0] as HTMLElement;
if (collapseIcon) {
handleCollapseClick(collapseIcon, plugin, yaml, pathBlacklist, source, folderOverview, child);
if (folderTitleText && !folderNote) {
folderTitleText.onclick = () => {
const collapseIcon = folderTitle?.querySelectorAll('.tree-item-icon')[0] as HTMLElement;
if (collapseIcon) {
this.handleCollapseClick(collapseIcon, plugin, yaml, pathBlacklist, source, folderOverview, child);
}
}
}
}

View file

@ -5,7 +5,7 @@ import { FolderOverviewSettings } from './ModalSettings';
import { getExcludedFolder } from '../ExcludeFolders/functions/folderFunctions';
import { getFolderPathFromString } from '../functions/utils';
import { getEl } from 'src/functions/styleFunctions';
import { renderFileExplorer } from './FileExplorer';
import { FileExplorerOverview } from './FileExplorer';
import { renderListOverview } from './ListStyle';
import NewFolderNameModal from 'src/modals/NewFolderName';
import { CustomEventEmitter } from 'src/events/EventEmitter';
@ -46,7 +46,7 @@ export class FolderOverview {
root: HTMLElement;
listEl: HTMLUListElement;
private eventListeners: (() => void)[] = [];
eventListeners: (() => void)[] = [];
constructor(plugin: FolderNotesPlugin, ctx: MarkdownPostProcessorContext, source: string, el: HTMLElement) {
this.emitter = new CustomEventEmitter();
let yaml: yamlSettings = parseYaml(source);
@ -216,11 +216,12 @@ export class FolderOverview {
} else if (this.yaml.style === 'list') {
renderListOverview(plugin, ctx, root, this.yaml, this.pathBlacklist, this);
} else if (this.yaml.style === 'explorer') {
const fileExplorerOverview = new FileExplorerOverview(plugin, ctx, root, this.yaml, this.pathBlacklist, this);
if (this.plugin.app.workspace.layoutReady) {
renderFileExplorer(plugin, ctx, root, this.yaml, this.pathBlacklist, this);
fileExplorerOverview.renderFileExplorer();
} else {
this.plugin.app.workspace.onLayoutReady(() => {
renderFileExplorer(plugin, ctx, root, this.yaml, this.pathBlacklist, this);
fileExplorerOverview.renderFileExplorer();
});
}
}
@ -256,12 +257,12 @@ export class FolderOverview {
}
filterFiles(files: TAbstractFile[], plugin: FolderNotesPlugin, sourceFolderPath: string, depth: number, pathBlacklist: string[]) {
return files.filter((file) => {
return files.filter(async (file) => {
if (pathBlacklist.includes(file.path) && !this.yaml.showFolderNotes) { return false; }
const folderPath = getFolderPathFromString(file.path);
if (!folderPath.startsWith(sourceFolderPath) && sourceFolderPath !== '/') { return false; }
if (file.path === this.sourceFilePath) { return false; }
const excludedFolder = getExcludedFolder(plugin, file.path, true);
const excludedFolder = await getExcludedFolder(plugin, file.path, true);
if (excludedFolder?.excludeFromFolderOverview) { return false; }
if ((file.path.split('/').length - sourceFolderPath.split('/').length) - 1 < depth) {
return true;
@ -355,7 +356,7 @@ export class FolderOverview {
fileMenu.addSeparator();
fileMenu.addItem((item) => {
item.setTitle('Rename');
item.setTitle(window.i18next.t("plugins.file-explorer.menu-opt-rename"));
item.setIcon('pencil');
item.onClick(async () => {
plugin.app.fileManager.promptForFileRename(file)
@ -363,7 +364,7 @@ export class FolderOverview {
});
fileMenu.addItem((item) => {
item.setTitle('Delete');
item.setTitle(window.i18next.t("plugins.file-explorer.menu-opt-delete"));
item.setIcon('trash');
item.dom.addClass('is-warning');
item.dom.setAttribute('data-section', 'danger')
@ -406,6 +407,13 @@ export class FolderOverview {
plugin.app.workspace.trigger('file-menu', folderMenu, folder, "folder-overview-folder-context-menu", null);
folderMenu.showAtPosition({ x: e.pageX, y: e.pageY });
}
getElFromOverview(path: string): HTMLElement | null {
const el = this.listEl.querySelector(`[data-path="${path}"]`) as HTMLElement | null;
return el;
}
}
export async function updateYaml(plugin: FolderNotesPlugin, ctx: MarkdownPostProcessorContext, el: HTMLElement, yaml: yamlSettings) {

View file

@ -62,12 +62,9 @@ export async function createFolderNote(plugin: FolderNotesPlugin, folderPath: st
const folderNote = getFolderNote(plugin, folderPath)
removeCSSClassFromEL(folderNote?.path, 'is-folder-note');
const folder = plugin.app.vault.getAbstractFileByPath(folderPath) as TFolder;
console.log('folderNote', folderNote);
console.log('fileName', fileName)
if (!folderNote || folderNote.basename !== fileName) return;
let count = 1;
let newName = removeExtension(folderNote.path) + ` (${count}).${folderNote.path.split('.').pop()}`;
console.log(newName)
while (count < 100 && plugin.app.vault.getAbstractFileByPath(newName)) {
count++;
newName = removeExtension(folderNote.path) + ` (${count}).${folderNote.path.split('.').pop()}`;
@ -90,7 +87,6 @@ export async function createFolderNote(plugin: FolderNotesPlugin, folderPath: st
if (!existingNote) {
let content = '';
if (extension !== '.md') {
console.log('create 1')
if (plugin.settings.templatePath && folderNoteType.split('.').pop() == plugin.settings.templatePath.split('.').pop()) {
const templateFile = plugin.app.vault.getAbstractFileByPath(plugin.settings.templatePath);
if (templateFile instanceof TFile) {
@ -114,8 +110,7 @@ export async function createFolderNote(plugin: FolderNotesPlugin, folderPath: st
content = '{}'
}
}
console.log('create 2')
console.log('path', path)
file = await plugin.app.vault.create(path, content);
} else {
file = existingNote;
@ -150,8 +145,8 @@ export async function createFolderNote(plugin: FolderNotesPlugin, folderPath: st
const folder = plugin.app.vault.getAbstractFileByPath(folderPath);
if (!(folder instanceof TFolder)) return;
addCSSClassToTitleEL(path, 'is-folder-note', true);
addCSSClassToTitleEL(folder.path, 'has-folder-note');
addCSSClassToTitleEL(plugin, path, 'is-folder-note', true);
addCSSClassToTitleEL(plugin, folder.path, 'has-folder-note');
}
export async function turnIntoFolderNote(plugin: FolderNotesPlugin, file: TFile, folder: TFolder, folderNote?: TFile | null | TAbstractFile, skipConfirmation?: boolean) {
@ -196,8 +191,8 @@ export async function turnIntoFolderNote(plugin: FolderNotesPlugin, file: TFile,
}
await plugin.app.fileManager.renameFile(file, path);
addCSSClassToTitleEL(path, 'is-folder-note', true);
addCSSClassToTitleEL(folder.path, 'has-folder-note');
addCSSClassToTitleEL(plugin, path, 'is-folder-note', true);
addCSSClassToTitleEL(plugin, folder.path, 'has-folder-note');
if (plugin.activeFolderDom) {
plugin.activeFolderDom.removeClass('fn-is-active');
@ -209,7 +204,7 @@ export async function turnIntoFolderNote(plugin: FolderNotesPlugin, file: TFile,
}
export async function tempDisableSync(plugin: FolderNotesPlugin, folder: TFolder): Promise<[excludedFolder: ExcludedFolder | undefined,excludedFolderExisted: boolean, disabledSync: boolean]> {
let excludedFolder = getExcludedFolder(plugin, folder.path, false);
let excludedFolder = await getExcludedFolder(plugin, folder.path, false);
let excludedFolderExisted = true;
let disabledSync = false;
@ -331,7 +326,6 @@ export function detachFolderNote(plugin: FolderNotesPlugin, file: TFile) {
excludedFolder.excludeFromFolderOverview = false;
excludedFolder.detached = true;
excludedFolder.detachedFilePath = file.path;
console.log('excludedFolder', excludedFolder);
addExcludedFolder(plugin, excludedFolder);
}

11
src/globals.d.ts vendored
View file

@ -1,17 +1,6 @@
import { Plugin, TAbstractFile, View, WorkspaceLeaf } from 'obsidian';
declare module 'obsidian' {
interface App {
internalPlugins: {
plugins: {
[pluginId: string]: Plugin & {
[pluginImplementations: string]: unknown;
};
};
enablePlugin: (id: string) => Promise<void>;
disablePlugin: (id: string) => Promise<void>;
};
}
interface Setting {
createList: (list: ListComponent | ((list: ListComponent) => void)) => ListComponent;
}

View file

@ -15,7 +15,7 @@ import './functions/ListComponent';
import { handleDelete } from './events/handleDelete';
import { addCSSClassToTitleEL, getEl, loadFileClasses, removeCSSClassFromEL } from './functions/styleFunctions';
import { getExcludedFolder } from './ExcludeFolders/functions/folderFunctions';
import { ClipBoardManager } from 'obsidian-typings'
import { ClipBoardManager, FileExplorerView, InternalPlugin, InternalPluginName, InternalPlugins } from 'obsidian-typings'
export default class FolderNotesPlugin extends Plugin {
observer: MutationObserver;
settings: FolderNotesSettings;
@ -28,6 +28,10 @@ export default class FolderNotesPlugin extends Plugin {
hoverLinkTriggered = false;
tabManager: TabManager;
settingsOpened = false;
private fileExplorerPlugin!: InternalPlugin;
private fileExplorerView!: FileExplorerView;
async onload() {
console.log('loading folder notes plugin');
await this.loadSettings();
@ -51,43 +55,7 @@ export default class FolderNotesPlugin extends Plugin {
new Commands(this.app, this).registerCommands();
this.app.workspace.onLayoutReady(() => {
if (this.settings.frontMatterTitle.enabled) {
this.fmtpHandler = new FrontMatterTitlePluginHandler(this);
}
this.tabManager = new TabManager(this);
this.tabManager.updateTabs();
const view = this.app.workspace.getLeavesOfType('markdown')[0]?.view;
if (!view) { return; }
const plugin = this;
// @ts-ignore
const originalHandleDragOver = view.editMode.clipboardManager.constructor.prototype.handleDragOver;
// @ts-ignore
view.editMode.clipboardManager.constructor.prototype.handleDragOver = function (evt, ...args) {
const { draggable } = plugin.app.dragManager;
if (draggable && draggable.file instanceof TFolder && getFolderNote(plugin, draggable.file.path)) {
plugin.app.dragManager.setAction(window.i18next.t("interface.drag-and-drop.insert-link-here"));
} else {
originalHandleDragOver.call(this, evt, ...args);
}
};
// @ts-ignore
const originalHandleDrop = view.editMode.clipboardManager.constructor.prototype.handleDrop;
// @ts-ignore
view.editMode.clipboardManager.constructor.prototype.handleDrop = function (evt, ...args) {
const { draggable } = plugin.app.dragManager;
if (draggable && draggable.file instanceof TFolder && getFolderNote(plugin, draggable.file.path)) {
const folderNote = getFolderNote(plugin, draggable.file.path);
if (draggable?.type === "folder" && draggable.file instanceof TFolder && folderNote) {
draggable.file = folderNote;
draggable.type = "file";
}
}
return originalHandleDrop.call(this, evt, ...args);
}
});
this.app.workspace.onLayoutReady(this.onLayoutReady.bind(this));
await addObserver(this);
@ -166,6 +134,48 @@ export default class FolderNotesPlugin extends Plugin {
}
}
onLayoutReady() {
if (this.settings.frontMatterTitle.enabled) {
this.fmtpHandler = new FrontMatterTitlePluginHandler(this);
}
this.tabManager = new TabManager(this);
this.tabManager.updateTabs();
const view = this.app.workspace.getLeavesOfType('markdown')[0]?.view;
if (!view) { return; }
const plugin = this;
// @ts-ignore
const originalHandleDragOver = view.editMode.clipboardManager.constructor.prototype.handleDragOver;
// @ts-ignore
view.editMode.clipboardManager.constructor.prototype.handleDragOver = function (evt, ...args) {
const { draggable } = plugin.app.dragManager;
if (draggable && draggable.file instanceof TFolder && getFolderNote(plugin, draggable.file.path)) {
plugin.app.dragManager.setAction(window.i18next.t("interface.drag-and-drop.insert-link-here"));
} else {
originalHandleDragOver.call(this, evt, ...args);
}
};
// @ts-ignore
const originalHandleDrop = view.editMode.clipboardManager.constructor.prototype.handleDrop;
// @ts-ignore
view.editMode.clipboardManager.constructor.prototype.handleDrop = function (evt, ...args) {
const { draggable } = plugin.app.dragManager;
if (draggable && draggable.file instanceof TFolder && getFolderNote(plugin, draggable.file.path)) {
const folderNote = getFolderNote(plugin, draggable.file.path);
if (draggable?.type === "folder" && draggable.file instanceof TFolder && folderNote) {
draggable.file = folderNote;
draggable.type = "file";
}
}
return originalHandleDrop.call(this, evt, ...args);
}
const fileExplorerPluginInstance = this.app.internalPlugins.getEnabledPluginById(InternalPluginName.FileExplorer);
}
handleOverviewBlock(source: string, el: HTMLElement, ctx: MarkdownPostProcessorContext) {
const observer = new MutationObserver(() => {
@ -184,8 +194,16 @@ export default class FolderNotesPlugin extends Plugin {
subtree: true,
});
try {
const folderOverview = new FolderOverview(this, ctx, source, el);
folderOverview.create(this, parseYaml(source), el, ctx);
if (this.app.workspace.layoutReady) {
const folderOverview = new FolderOverview(this, ctx, source, el);
folderOverview.create(this, parseYaml(source), el, ctx);
} else {
this.app.workspace.onLayoutReady(() => {
console.log('layout ready');
const folderOverview = new FolderOverview(this, ctx, source, el);
folderOverview.create(this, parseYaml(source), el, ctx);
});
}
} catch (e) {
new Notice('Error creating folder overview (folder notes plugin) - check console for more details');
console.error(e);

View file

@ -65,7 +65,7 @@ export default class ConfirmationModal extends Modal {
const folders = this.app.vault.getAllLoadedFiles().filter((file) => file.parent instanceof TFolder);
for (const folder of folders) {
if (folder instanceof TFolder) {
const excludedFolder = getExcludedFolder(this.plugin, folder.path, true);
const excludedFolder = await getExcludedFolder(this.plugin, folder.path, true);
if (excludedFolder) continue;
if (folder.path === templateFolderPath) continue;
const folderNote = getFolderNote(this.plugin, folder.path);

View file

@ -22,7 +22,6 @@ export default class NewFolderNameModal extends Modal {
this.modalEl.classList.add('mod-file-rename')
const modalTitle = this.modalEl.querySelector('div.modal-title')
console.log(modalTitle)
if (modalTitle) {
modalTitle.textContent = 'Folder title'
}