File menu context menu for file explorer overview

This commit is contained in:
Lost Paul 2024-08-12 22:27:38 +02:00
parent ca622350e4
commit 78b9838fde
6 changed files with 495 additions and 259 deletions

View file

@ -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 = '<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) => {
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,
});
}

View file

@ -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 = '<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>';
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) => {

View file

@ -0,0 +1 @@
export {}

View file

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

8
src/globals.d.ts vendored
View file

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

View file

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