From 78b9838fde2936bd2f8f9ff4e458693489e72d7d Mon Sep 17 00:00:00 2001
From: Lost Paul <70213368+LostPaul@users.noreply.github.com>
Date: Mon, 12 Aug 2024 22:27:38 +0200
Subject: [PATCH] File menu context menu for file explorer overview
---
src/folderOverview/FileExplorer.ts | 295 +++++++++++++++++++++++++++
src/folderOverview/FolderOverview.ts | 275 ++-----------------------
src/folderOverview/Grid.ts | 1 +
src/folderOverview/ListStyle.ts | 101 +++++++++
src/globals.d.ts | 8 +
src/modals/NewFolderName.ts | 74 +++++++
6 files changed, 495 insertions(+), 259 deletions(-)
create mode 100644 src/folderOverview/FileExplorer.ts
create mode 100644 src/folderOverview/Grid.ts
create mode 100644 src/folderOverview/ListStyle.ts
create mode 100644 src/modals/NewFolderName.ts
diff --git a/src/folderOverview/FileExplorer.ts b/src/folderOverview/FileExplorer.ts
new file mode 100644
index 0000000..872813e
--- /dev/null
+++ b/src/folderOverview/FileExplorer.ts
@@ -0,0 +1,295 @@
+import { MarkdownPostProcessorContext, parseYaml, TAbstractFile, TFolder, TFile, stringifyYaml, Notice, Menu } from 'obsidian';
+import { getFolderNote } from '../functions/folderNoteFunctions';
+import FolderNotesPlugin from '../main';
+import { FolderOverviewSettings } from './ModalSettings';
+import { getExcludedFolder } from '../ExcludeFolders/functions/folderFunctions';
+import { getFolderPathFromString } from '../functions/utils';
+import { getEl } from 'src/functions/styleFunctions';
+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 = root.querySelector('ul.folder-overview-list') as HTMLElement;
+ 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 {
+ yaml.folderPath = '/';
+ tFolder = plugin.app.vault.getAbstractFileByPath('/');
+ }
+ }
+
+ if (!folderElement && !tFolder) return;
+
+ folderElement = document.querySelector('div.nav-files-container') 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');
+ } else {
+ el.classList.remove('is-collapsed');
+ }
+ } else {
+ 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); }
+ }
+ });
+
+ function handleVaultChange(eventType: string) {
+ renderFileExplorer(plugin, ctx, root, yaml, pathBlacklist, folderOverview);
+ console.log(eventType);
+ }
+
+ plugin.app.vault.on('rename', () => handleVaultChange('renamed'));
+ plugin.app.vault.on('create', () => handleVaultChange('created'));
+ plugin.app.vault.on('delete', () => handleVaultChange('deleted'));
+
+
+ if (tFolder instanceof TFolder && !yaml.folderPath.trim().includes('/')) {
+ addFiles(tFolder.children, overviewList, folderOverview);
+ } else if (yaml.folderPath.trim() === '/') {
+ const rootFiles: TAbstractFile[] = [];
+ if (yaml.includeTypes.includes('folder')) {
+ plugin.app.vault.getAllLoadedFiles().filter(f => f instanceof TFolder).forEach((file) => {
+ if (!file.path.includes('/')) {
+ rootFiles.push(file);
+ }
+ });
+ } else {
+ rootFiles.push(...plugin.app.vault.getAllLoadedFiles());
+ }
+ addFiles(rootFiles, 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);
+ handleCollapseClick(el, plugin, yaml, pathBlacklist, source, folderOverview, folder);
+ }
+ }
+ });
+}
+
+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 folders) {
+ if (child instanceof TFolder) {
+ createFolderEL(plugin, child, folderOverview, childrenElement);
+ }
+ }
+
+ 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;
+
+ 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.onclick = () => {
+ plugin.app.workspace.openLinkText(child.path, child.path, true);
+ }
+
+ // fileTitle.oncontextmenu = (e) => {
+ // const fileMenu = new Menu();
+ // fileMenu.addSeparator();
+
+ // fileMenu.addItem((item) => {
+ // item.setTitle('Rename');
+ // item.setIcon('pencil');
+ // item.onClick(async () => {
+ // plugin.app.fileManager.promptForFileRename(child)
+ // });
+ // });
+
+ // fileMenu.addItem((item) => {
+ // item.setTitle('Delete');
+ // item.setIcon('trash');
+ // item.dom.addClass('is-warning');
+ // item.dom.setAttribute('data-section', 'danger')
+ // item.onClick(() => {
+ // plugin.app.fileManager.promptForDeletion(child)
+ // });
+ // });
+
+ // fileMenu.addSeparator();
+
+ // plugin.app.workspace.trigger('file-menu', fileMenu, child, "folder-overview-file-context-menu", null);
+ // fileMenu.showAtPosition({ x: e.pageX, y: e.pageY });
+ // }
+
+ 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
+ });
+ }
+ }
+ }
+}
+
+
+function 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);
+ 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 = '';
+ 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) => {
+ const fileMenu = new Menu();
+ fileMenu.addSeparator();
+
+ fileMenu.addItem((item) => {
+ item.setTitle('Rename');
+ item.setIcon('pencil');
+ item.onClick(async () => {
+ console.log('child', child)
+ new NewFolderNameModal(plugin.app, plugin, child).open();
+ });
+ });
+
+ fileMenu.addItem((item) => {
+ item.setTitle('Delete');
+ item.setIcon('trash');
+ item.dom.addClass('is-warning');
+ item.dom.setAttribute('data-section', 'danger')
+ item.onClick(() => {
+ plugin.app.fileManager.promptForFolderDeletion(child)
+ });
+ });
+
+ fileMenu.addSeparator();
+
+ plugin.app.workspace.trigger('file-menu', fileMenu, child, "folder-overview-file-context-menu", null);
+ fileMenu.showAtPosition({ x: e.pageX, y: e.pageY });
+ }
+ }
+
+ 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);
+ }
+ } else {
+ addFiles(child.children, childrenElement, folderOverview);
+ }
+ } 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') }
+
+ 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);
+ }
+ }
+
+ folderTitle?.createDiv({
+ cls: 'tree-item-inner nav-folder-title-content',
+ text: child.name,
+ });
+}
\ No newline at end of file
diff --git a/src/folderOverview/FolderOverview.ts b/src/folderOverview/FolderOverview.ts
index c9c3b5b..f12d680 100644
--- a/src/folderOverview/FolderOverview.ts
+++ b/src/folderOverview/FolderOverview.ts
@@ -5,6 +5,8 @@ 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 { renderListOverview } from './ListStyle';
export type includeTypes = 'folder' | 'markdown' | 'canvas' | 'other' | 'pdf' | 'image' | 'audio' | 'video' | 'all';
@@ -37,6 +39,9 @@ export class FolderOverview {
pathBlacklist: string[] = [];
folders: TFolder[] = [];
sourceFilePath: string;
+ sourceFolder: TFolder | undefined;
+ root: HTMLElement;
+ listEl: HTMLUListElement;
constructor(plugin: FolderNotesPlugin, ctx: MarkdownPostProcessorContext, source: string, el: HTMLElement) {
let yaml: yamlSettings = parseYaml(source);
if (!yaml) { yaml = {} as yamlSettings; }
@@ -46,6 +51,9 @@ export class FolderOverview {
this.source = source;
this.el = el;
this.sourceFilePath = this.ctx.sourcePath
+ console.log(this.sourceFilePath)
+ console.log(plugin.app.vault.getAbstractFileByPath(getFolderPathFromString(ctx.sourcePath)))
+ this.sourceFolder = plugin.app.vault.getAbstractFileByPath(getFolderPathFromString(ctx.sourcePath)) as TFolder;
this.yaml = {
id: yaml?.id || crypto.randomUUID(),
folderPath: yaml?.folderPath === undefined || yaml?.folderPath === null ? getFolderPathFromString(ctx.sourcePath) : yaml?.folderPath,
@@ -69,13 +77,18 @@ export class FolderOverview {
el.empty();
el.parentElement?.classList.add('folder-overview-container');
const root = el.createEl('div', { cls: 'folder-overview' });
+ this.root = root;
const titleEl = root.createEl('h1', { cls: 'folder-overview-title' });
const ul = root.createEl('ul', { cls: 'folder-overview-list' });
+ this.listEl = ul;
if (this.yaml.includeTypes.length === 0) { return this.addEditButton(root); }
let files: TAbstractFile[] = [];
const sourceFile = plugin.app.vault.getAbstractFileByPath(ctx.sourcePath);
if (!sourceFile) return;
let sourceFolderPath = this.yaml.folderPath || getFolderPathFromString(ctx.sourcePath);
+ if (!ctx.sourcePath.includes('/')) {
+ sourceFolderPath = '/';
+ }
let sourceFolder: TFolder | undefined;
if (sourceFolderPath !== '/') {
@@ -149,26 +162,13 @@ export class FolderOverview {
}
});
} else if (this.yaml.style === 'list') {
- const folders = this.sortFiles(files.filter(f => f instanceof TFolder));
- files = this.sortFiles(files.filter(f => f instanceof TFile));
- folders.forEach((file) => {
- if (file instanceof TFolder) {
- const folderItem = this.addFolderList(plugin, ul, this.pathBlacklist, file);
- if (!folderItem) { return; }
- this.goThroughFolders(plugin, folderItem, file, this.yaml.depth, sourceFolderPath, ctx, this.yaml, this.pathBlacklist, this.yaml.includeTypes, this.yaml.disableFileTag);
- }
- });
- files.forEach((file) => {
- if (file instanceof TFile) {
- this.addFileList(plugin, ul, this.pathBlacklist, file, this.yaml.includeTypes, this.yaml.disableFileTag);
- }
- });
+ renderListOverview(plugin, ctx, root, this.yaml, this.pathBlacklist, this);
} else if (this.yaml.style === 'explorer') {
if (this.plugin.app.workspace.layoutReady) {
- this.cloneFileExplorerView(plugin, ctx, root, this.yaml, this.pathBlacklist);
+ renderFileExplorer(plugin, ctx, root, this.yaml, this.pathBlacklist, this);
} else {
this.plugin.app.workspace.onLayoutReady(() => {
- this.cloneFileExplorerView(plugin, ctx, root, this.yaml, this.pathBlacklist);
+ renderFileExplorer(plugin, ctx, root, this.yaml, this.pathBlacklist, this);
});
}
}
@@ -203,209 +203,6 @@ export class FolderOverview {
}, { capture: true });
}
- cloneFileExplorerView(plugin: FolderNotesPlugin, ctx: MarkdownPostProcessorContext, root: HTMLElement, yaml: yamlSettings, pathBlacklist: string[]) {
- const folder = getEl(this.yaml.folderPath)
- let folderElement = folder?.parentElement;
- let tFolder = plugin.app.vault.getAbstractFileByPath(this.yaml.folderPath);
- if (!tFolder && yaml.folderPath.trim() == '') {
- tFolder = plugin.app.vault.getAbstractFileByPath(getFolderPathFromString(ctx.sourcePath));
- }
- if (!folderElement && yaml.folderPath.trim() !== '') return;
- folderElement = document.querySelector('div.nav-files-container') 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 (this.yaml.storeFolderCondition) {
- if (folder.collapsed) {
- el.classList.add('is-collapsed');
- } else {
- el.classList.remove('is-collapsed');
- }
- } else {
- 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) { this.pathBlacklist.push(folderNote.path); }
- }
- });
-
- if (tFolder instanceof TFolder) {
- this.addFiles(tFolder.children, root);
- } else if (yaml.folderPath.trim() === '/') {
- const rootFiles: TAbstractFile[] = [];
- plugin.app.vault.getAllLoadedFiles().filter(f => f instanceof TFolder).forEach((file) => {
- if (!file.path.includes('/')) {
- rootFiles.push(file);
- }
- });
- this.addFiles(rootFiles, root);
- }
-
- 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, pathBlacklist, this.source, folder);
- }
- }
- });
- }
-
- async addFiles(files: TAbstractFile[], childrenElement: HTMLElement) {
- const folders = this.sortFiles(files.filter((file) => file instanceof TFolder));
- const filesWithoutFolders = this.sortFiles(files.filter((file) => !(file instanceof TFolder)));
- for (const child of folders) {
- if (child instanceof TFolder) {
- const folderNote = getFolderNote(this.plugin, child.path);
- if (folderNote) { this.pathBlacklist.push(folderNote.path); }
- const excludedFolder = getExcludedFolder(this.plugin, child.path, true);
- if (excludedFolder?.excludeFromFolderOverview) { continue; }
- const svg = '';
- const folderElement = childrenElement.createDiv({
- cls: 'tree-item nav-folder',
- });
- const folderTitle = folderElement.createDiv({
- cls: 'tree-item-self is-clickable nav-folder-title',
- attr: {
- 'data-path': child.path,
- 'draggable': 'true'
- },
- })
- if (!child.collapsed) {
- folderTitle.classList.remove('is-collapsed');
- const childrenElement = folderElement?.createDiv({ cls: 'tree-item-children nav-folder-children' });
- this.addFiles(child.children, childrenElement);
- } else {
- folderTitle.classList.add('is-collapsed');
- }
- if (folderNote) { folderTitle.classList.add('has-folder-note') }
- if (folderNote && child.children.length === 1 && this.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',
- });
-
- if (child.collapsed) {
- collapseIcon.classList.add('is-collapsed');
- }
-
- collapseIcon.innerHTML = svg;
- collapseIcon.onclick = () => {
- this.handleCollapseClick(collapseIcon, this.plugin, this.yaml, this.pathBlacklist, this.source, child);
- }
-
- folderTitle.createDiv({
- cls: 'tree-item-inner nav-folder-title-content',
- text: child.name,
- });
- }
- }
- for (const child of filesWithoutFolders) {
- if (child instanceof TFile) {
- if (this.pathBlacklist.includes(child.path) && !this.yaml.showFolderNotes) { continue; }
- const extension = child.extension.toLowerCase() == 'md' ? 'markdown' : child.extension.toLowerCase();
- const includeTypes = this.yaml.includeTypes;
-
- 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.onclick = () => {
- this.plugin.app.workspace.openLinkText(child.path, child.path, true);
- }
-
- fileTitle.createDiv({
- cls: 'tree-item-inner nav-file-title-content',
- text: child.basename,
- });
-
- if (child.extension !== 'md') {
- fileTitle.createDiv({
- cls: 'nav-file-tag',
- text: child.extension
- });
- }
- }
- }
- }
-
- handleCollapseClick(el: HTMLElement, plugin: FolderNotesPlugin, yaml: yamlSettings, pathBlacklist: string[], sourcePath: string, 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 = this.sortFiles(folder.children);
- files = this.filterFiles(files, plugin, folder.path, this.yaml.depth || 1, pathBlacklist);
- this.addFiles(files, childrenElement);
- }
- }
-
-
- goThroughFolders(plugin: FolderNotesPlugin, list: HTMLLIElement | HTMLUListElement, folder: TFolder,
- depth: number, sourceFolderPath: string, ctx: MarkdownPostProcessorContext, yaml: yamlSettings,
- pathBlacklist: string[], includeTypes: string[], disableFileTag: boolean) {
- if (sourceFolderPath === '') {
- depth--;
- }
- let files = this.filterFiles(folder.children, plugin, sourceFolderPath, depth, pathBlacklist);
- files = this.sortFiles(files.filter((file) => !(file instanceof TFolder)));
- if (this.yaml.sortByAsc) {
- files = files.reverse();
- }
- const folders = this.sortFiles(files.filter((file) => file instanceof TFolder));
- const ul = list.createEl('ul', { cls: 'folder-overview-list' });
- folders.forEach((file) => {
- if (file instanceof TFolder) {
- const folderItem = this.addFolderList(plugin, ul, pathBlacklist, file);
- if (!folderItem) return;
- this.goThroughFolders(plugin, folderItem, file, depth, sourceFolderPath, ctx, yaml, pathBlacklist, includeTypes, disableFileTag);
- }
- });
- files.forEach((file) => {
- if (file instanceof TFile) {
- this.addFileList(plugin, ul, pathBlacklist, file, includeTypes, disableFileTag);
- }
- });
- }
-
filterFiles(files: TAbstractFile[], plugin: FolderNotesPlugin, sourceFolderPath: string, depth: number, pathBlacklist: string[]) {
return files.filter((file) => {
if (pathBlacklist.includes(file.path) && !this.yaml.showFolderNotes) { return false; }
@@ -486,46 +283,6 @@ export class FolderOverview {
});
}
- addFolderList(plugin: FolderNotesPlugin, list: HTMLUListElement | HTMLLIElement, pathBlacklist: string[], folder: TFolder) {
- const folderItem = list.createEl('li', { cls: 'folder-overview-list folder-list' });
- const folderNote = getFolderNote(plugin, folder.path);
- if (folderNote instanceof TFile) {
- const folderNoteLink = folderItem.createEl('a', { cls: 'folder-overview-list-item folder-name-item internal-link', href: folderNote.path });
- folderNoteLink.innerText = folder.name;
- pathBlacklist.push(folderNote.path);
- } else {
- const folderName = folderItem.createEl('span', { cls: 'folder-overview-list-item folder-name-item' });
- folderName.innerText = folder.name;
- }
- return folderItem;
- }
-
- addFileList(plugin: FolderNotesPlugin, list: HTMLUListElement | HTMLLIElement, pathBlacklist: string[], file: TFile, includeTypes: string[], disableFileTag: boolean) {
- if (includeTypes.length > 0 && !includeTypes.includes('all')) {
- if (file.extension === 'md' && !includeTypes.includes('markdown')) return;
- if (file.extension === 'canvas' && !includeTypes.includes('canvas')) return;
- if (file.extension === 'pdf' && !includeTypes.includes('pdf')) return;
- const imageTypes = ['jpg', 'jpeg', 'png', 'gif', 'svg', 'webp'];
- if (imageTypes.includes(file.extension) && !includeTypes.includes('image')) return;
- const videoTypes = ['mp4', 'webm', 'ogv', 'mov', 'mkv'];
- if (videoTypes.includes(file.extension) && !includeTypes.includes('video')) return;
- const audioTypes = ['mp3', 'wav', 'm4a', '3gp', 'flac', 'ogg', 'oga', 'opus'];
- if (audioTypes.includes(file.extension) && includeTypes.includes('audio')) return;
- const allTypes = ['md', 'canvas', 'pdf', ...imageTypes, ...videoTypes, ...audioTypes];
- if (!allTypes.includes(file.extension) && !includeTypes.includes('other')) return;
- }
- if (!this.yaml.showFolderNotes) {
- if (pathBlacklist.includes(file.path)) return;
- }
- const listItem = list.createEl('li', { cls: 'folder-overview-list file-link' });
- const nameItem = listItem.createEl('div', { cls: 'folder-overview-list-item' });
- const link = nameItem.createEl('a', { cls: 'internal-link', href: file.path });
- link.innerText = file.basename;
- if (file.extension !== 'md' && !disableFileTag) {
- nameItem.createDiv({ cls: 'nav-file-tag' }).innerText = file.extension;
- }
- }
-
getAllFiles(files: TAbstractFile[], sourceFolderPath: string, depth: number) {
const allFiles: TAbstractFile[] = [];
files.forEach((file) => {
diff --git a/src/folderOverview/Grid.ts b/src/folderOverview/Grid.ts
new file mode 100644
index 0000000..693da49
--- /dev/null
+++ b/src/folderOverview/Grid.ts
@@ -0,0 +1 @@
+export {}
\ No newline at end of file
diff --git a/src/folderOverview/ListStyle.ts b/src/folderOverview/ListStyle.ts
new file mode 100644
index 0000000..dfc4a6e
--- /dev/null
+++ b/src/folderOverview/ListStyle.ts
@@ -0,0 +1,101 @@
+import { MarkdownPostProcessorContext, parseYaml, TAbstractFile, TFolder, TFile, stringifyYaml, Notice, Menu } from 'obsidian';
+import { getFolderNote } from '../functions/folderNoteFunctions';
+import FolderNotesPlugin from '../main';
+import { FolderOverviewSettings } from './ModalSettings';
+import { getExcludedFolder } from '../ExcludeFolders/functions/folderFunctions';
+import { getFolderPathFromString } from '../functions/utils';
+import { getEl } from 'src/functions/styleFunctions';
+import { FolderOverview, yamlSettings } from './FolderOverview';
+import FolderNameModal from 'src/modals/FolderName';
+import NewFolderNameModal from 'src/modals/NewFolderName';
+
+export function renderListOverview(plugin: FolderNotesPlugin, ctx: MarkdownPostProcessorContext, root: HTMLElement, yaml: yamlSettings, pathBlacklist: string[], folderOverview: FolderOverview) {
+ if (!folderOverview.sourceFolder) { return; }
+ let files = folderOverview.sourceFolder.children;
+ if (!files) { return; }
+ const ul = folderOverview.listEl;
+ const sourceFolderPath = folderOverview.sourceFolder.path;
+
+
+ const folders = folderOverview.sortFiles(files.filter(f => f instanceof TFolder));
+ files = folderOverview.sortFiles(files.filter(f => f instanceof TFile));
+ folders.forEach((file) => {
+ if (file instanceof TFolder) {
+ const folderItem = addFolderList(plugin, ul, folderOverview.pathBlacklist, file);
+ if (!folderItem) { return; }
+ goThroughFolders(plugin, folderItem, file, folderOverview.yaml.depth, sourceFolderPath, ctx, folderOverview.yaml, folderOverview.pathBlacklist, folderOverview.yaml.includeTypes, folderOverview.yaml.disableFileTag, folderOverview);
+ }
+ });
+ files.forEach((file) => {
+ if (file instanceof TFile) {
+ addFileList(plugin, ul, folderOverview.pathBlacklist, file, folderOverview.yaml.includeTypes, folderOverview.yaml.disableFileTag, folderOverview);
+ }
+ });
+}
+
+export function addFolderList(plugin: FolderNotesPlugin, list: HTMLUListElement | HTMLLIElement, pathBlacklist: string[], folder: TFolder) {
+ const folderItem = list.createEl('li', { cls: 'folder-overview-list folder-list' });
+ const folderNote = getFolderNote(plugin, folder.path);
+ if (folderNote instanceof TFile) {
+ const folderNoteLink = folderItem.createEl('a', { cls: 'folder-overview-list-item folder-name-item internal-link', href: folderNote.path });
+ folderNoteLink.innerText = folder.name;
+ pathBlacklist.push(folderNote.path);
+ } else {
+ const folderName = folderItem.createEl('span', { cls: 'folder-overview-list-item folder-name-item' });
+ folderName.innerText = folder.name;
+ }
+ return folderItem;
+}
+
+function goThroughFolders(plugin: FolderNotesPlugin, list: HTMLLIElement | HTMLUListElement, folder: TFolder,
+ depth: number, sourceFolderPath: string, ctx: MarkdownPostProcessorContext, yaml: yamlSettings,
+ pathBlacklist: string[], includeTypes: string[], disableFileTag: boolean, folderOverview: FolderOverview) {
+ if (sourceFolderPath === '') {
+ depth--;
+ }
+ let files = folderOverview.filterFiles(folder.children, plugin, sourceFolderPath, depth, pathBlacklist);
+ files = folderOverview.sortFiles(files.filter((file) => !(file instanceof TFolder)));
+ if (folderOverview.yaml.sortByAsc) {
+ files = files.reverse();
+ }
+ const folders = folderOverview.sortFiles(files.filter((file) => file instanceof TFolder));
+ const ul = list.createEl('ul', { cls: 'folder-overview-list' });
+ folders.forEach((file) => {
+ if (file instanceof TFolder) {
+ const folderItem = addFolderList(plugin, ul, pathBlacklist, file);
+ if (!folderItem) return;
+ goThroughFolders(plugin, folderItem, file, depth, sourceFolderPath, ctx, yaml, pathBlacklist, includeTypes, disableFileTag, folderOverview);
+ }
+ });
+ files.forEach((file) => {
+ if (file instanceof TFile) {
+ addFileList(plugin, ul, pathBlacklist, file, includeTypes, disableFileTag, folderOverview);
+ }
+ });
+}
+
+function addFileList(plugin: FolderNotesPlugin, list: HTMLUListElement | HTMLLIElement, pathBlacklist: string[], file: TFile, includeTypes: string[], disableFileTag: boolean, folderOverview: FolderOverview) {
+ if (includeTypes.length > 0 && !includeTypes.includes('all')) {
+ if (file.extension === 'md' && !includeTypes.includes('markdown')) return;
+ if (file.extension === 'canvas' && !includeTypes.includes('canvas')) return;
+ if (file.extension === 'pdf' && !includeTypes.includes('pdf')) return;
+ const imageTypes = ['jpg', 'jpeg', 'png', 'gif', 'svg', 'webp'];
+ if (imageTypes.includes(file.extension) && !includeTypes.includes('image')) return;
+ const videoTypes = ['mp4', 'webm', 'ogv', 'mov', 'mkv'];
+ if (videoTypes.includes(file.extension) && !includeTypes.includes('video')) return;
+ const audioTypes = ['mp3', 'wav', 'm4a', '3gp', 'flac', 'ogg', 'oga', 'opus'];
+ if (audioTypes.includes(file.extension) && includeTypes.includes('audio')) return;
+ const allTypes = ['md', 'canvas', 'pdf', ...imageTypes, ...videoTypes, ...audioTypes];
+ if (!allTypes.includes(file.extension) && !includeTypes.includes('other')) return;
+ }
+ if (!folderOverview.yaml.showFolderNotes) {
+ if (pathBlacklist.includes(file.path)) return;
+ }
+ const listItem = list.createEl('li', { cls: 'folder-overview-list file-link' });
+ const nameItem = listItem.createEl('div', { cls: 'folder-overview-list-item' });
+ const link = nameItem.createEl('a', { cls: 'internal-link', href: file.path });
+ link.innerText = file.basename;
+ if (file.extension !== 'md' && !disableFileTag) {
+ nameItem.createDiv({ cls: 'nav-file-tag' }).innerText = file.extension;
+ }
+}
\ No newline at end of file
diff --git a/src/globals.d.ts b/src/globals.d.ts
index 95fc16a..4f5d328 100644
--- a/src/globals.d.ts
+++ b/src/globals.d.ts
@@ -22,6 +22,14 @@ declare module 'obsidian' {
newName: string | null;
collapsed: boolean;
}
+ interface MenuItem {
+ dom: HTMLElement;
+ }
+ interface FileManager {
+ promptForFileRename: (file: TAbstractFile) => void;
+ promptForDeletion: (file: TAbstractFile) => void;
+ promptForFolderDeletion: (folder: TFolder) => void;
+ }
class ListComponent {
containerEl: HTMLElement;
diff --git a/src/modals/NewFolderName.ts b/src/modals/NewFolderName.ts
new file mode 100644
index 0000000..073a4c3
--- /dev/null
+++ b/src/modals/NewFolderName.ts
@@ -0,0 +1,74 @@
+import { App, Modal, Setting, TFolder } from 'obsidian';
+import FolderNotesPlugin from '../main';
+export default class NewFolderNameModal extends Modal {
+ plugin: FolderNotesPlugin;
+ app: App;
+ folder: TFolder;
+ constructor(app: App, plugin: FolderNotesPlugin, folder: TFolder) {
+ super(app);
+ this.plugin = plugin;
+ this.app = app;
+ this.folder = folder;
+ }
+ onOpen() {
+ const { contentEl } = this;
+
+ contentEl.addEventListener('keydown', (e) => {
+ if (e.key === 'Enter') {
+ this.saveFolderName()
+ this.close();
+ }
+ });
+
+ this.modalEl.classList.add('mod-file-rename')
+ const modalTitle = this.modalEl.querySelector('div.modal-title')
+ console.log(modalTitle)
+ if (modalTitle) {
+ modalTitle.textContent = 'Folder title'
+ }
+
+ const textarea = contentEl.createEl('textarea', {
+ text: this.folder.name.replace(this.plugin.settings.folderNoteType, ''),
+ attr: {
+ placeholder: 'Enter the name of the folder',
+ rows: '1',
+ spellcheck: 'false',
+ class: 'rename-textarea'
+ }
+ })
+
+ textarea.addEventListener('focus', function() {
+ this.select();
+ });
+
+ textarea.focus()
+
+ const buttonContainer = this.modalEl.createDiv({ cls: 'modal-button-container' });
+ const saveButton = buttonContainer.createEl('button', { text: 'Save', cls: 'mod-cta' });
+ saveButton.addEventListener('click', async () => {
+ this.saveFolderName()
+ this.close()
+ })
+
+ const cancelButton = buttonContainer.createEl('button', { text: 'Cancel', cls: 'mod-cancel' });
+ cancelButton.addEventListener('click', () => {
+ this.close()
+ })
+ }
+ onClose() {
+ const { contentEl } = this;
+ contentEl.empty();
+ }
+
+ saveFolderName() {
+ const textarea = this.contentEl.querySelector('textarea')
+ if (textarea) {
+ const newName = textarea.value.trim()
+ if (newName.trim() !== '') {
+ if (!this.app.vault.getAbstractFileByPath(this.folder.path.slice(0, this.folder.path.lastIndexOf('/') + 1) + newName.trim())) {
+ this.plugin.app.fileManager.renameFile(this.folder, this.folder.path.slice(0, this.folder.path.lastIndexOf('/') + 1) + newName.trim());
+ }
+ }
+ }
+ }
+}