Fix eslint issues 1/2

This commit is contained in:
Paul 2026-05-15 15:40:29 +02:00
parent 2683ee1a1a
commit 1e99850592
38 changed files with 5759 additions and 648 deletions

View file

@ -31,7 +31,6 @@ esbuild.build({
'@lezer/common', '@lezer/common',
'@lezer/highlight', '@lezer/highlight',
'@lezer/lr', '@lezer/lr',
"f:/Obsidian/test/.obsidian/plugins/obsidian-folder-notes/node_modules/obsidian",
...builtins], ...builtins],
format: 'cjs', format: 'cjs',
watch: !prod, watch: !prod,

View file

@ -1,17 +1,61 @@
import tseslint from "typescript-eslint"; import tseslint from "typescript-eslint";
import obsidianmd from "eslint-plugin-obsidianmd";
import json from "@eslint/json";
export default [ export default [
...obsidianmd.configs.recommended,
{
files: ["manifest.json"],
language: "json/json",
plugins: {
json
},
rules: {
"no-irregular-whitespace": "off",
"obsidianmd/no-plugin-as-component": "off",
"obsidianmd/no-view-references-in-plugin": "off",
"obsidianmd/no-unsupported-api": "off",
"obsidianmd/prefer-file-manager-trash-file": "off",
"obsidianmd/prefer-instanceof": "off",
"obsidianmd/validate-manifest": "error"
}
},
{
files: ["package.json"],
rules: {
"no-irregular-whitespace": "off",
"depend/ban-dependencies": "off",
"obsidianmd/no-plugin-as-component": "off",
"obsidianmd/no-view-references-in-plugin": "off",
"obsidianmd/no-unsupported-api": "off",
"obsidianmd/prefer-file-manager-trash-file": "off",
"obsidianmd/prefer-instanceof": "off"
}
},
{
files: ["**/*.{js,mjs,cjs}"],
...tseslint.configs.disableTypeChecked,
rules: {
...tseslint.configs.disableTypeChecked.rules,
"obsidianmd/no-plugin-as-component": "off",
"obsidianmd/no-view-references-in-plugin": "off",
"obsidianmd/no-unsupported-api": "off",
"obsidianmd/prefer-file-manager-trash-file": "off",
"obsidianmd/prefer-instanceof": "off"
}
},
{ {
files: ["**/*.ts"], files: ["**/*.ts"],
languageOptions: { languageOptions: {
parser: tseslint.parser, parser: tseslint.parser,
parserOptions: { parserOptions: {
sourceType: "module" sourceType: "module",
project: "./tsconfig.json"
} }
}, },
ignores: [ ignores: [
"**/node_modules/**", "**/node_modules/**",
"**/dist/**", "**/dist/**"
], ],
plugins: { plugins: {
"@typescript-eslint": tseslint.plugin "@typescript-eslint": tseslint.plugin
@ -143,7 +187,7 @@ export default [
], ],
'max-len': [ 'max-len': [
'warn', { 'warn', {
code: 100, code: 110,
ignoreComments: true, ignoreComments: true,
} }
], ],

View file

@ -1,12 +1,12 @@
{ {
"id": "folder-notes", "id": "folder-notes",
"name": "Folder notes", "name": "Folder notes",
"version": "1.8.19", "version": "1.8.21",
"minAppVersion": "0.15.0", "minAppVersion": "1.4.10",
"description": "Create notes within folders that can be accessed without collapsing the folder, similar to the functionality offered in Notion.", "description": "Create notes within folders that can be accessed without collapsing the folder, similar to the functionality offered in Notion.",
"author": "Lost Paul", "author": "Lost Paul",
"authorUrl": "https://github.com/LostPaul", "authorUrl": "https://github.com/LostPaul",
"fundingUrl": "https://ko-fi.com/paul305844", "fundingUrl": "https://ko-fi.com/paul305844",
"helpUrl": "https://lostpaul.github.io/obsidian-folder-notes/", "helpUrl": "https://lostpaul.github.io/obsidian-folder-notes/",
"isDesktopOnly": false "isDesktopOnly": false
} }

5500
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -23,6 +23,7 @@
"builtin-modules": "3.3.0", "builtin-modules": "3.3.0",
"esbuild": "0.14.47", "esbuild": "0.14.47",
"eslint": "^9.32.0", "eslint": "^9.32.0",
"eslint-plugin-obsidianmd": "^0.3.0",
"front-matter-plugin-api-provider": "^0.1.4-alpha", "front-matter-plugin-api-provider": "^0.1.4-alpha",
"globals": "^16.3.0", "globals": "^16.3.0",
"jiti": "^2.5.1", "jiti": "^2.5.1",

View file

@ -8,6 +8,7 @@ import {
type TAbstractFile, type TAbstractFile,
type Editor, type Editor,
type MarkdownView, type MarkdownView,
type MarkdownFileInfo,
} from 'obsidian'; } from 'obsidian';
import type FolderNotesPlugin from './main'; import type FolderNotesPlugin from './main';
import { import {
@ -31,6 +32,7 @@ import {
showFolderNoteInFileExplorer, showFolderNoteInFileExplorer,
} from './functions/styleFunctions'; } from './functions/styleFunctions';
type MarkdownEditorContext = MarkdownView | MarkdownFileInfo;
export class Commands { export class Commands {
@ -60,7 +62,7 @@ export class Commands {
const folderNote = getFolderNote(this.plugin, folder.path); const folderNote = getFolderNote(this.plugin, folder.path);
if (folderNote instanceof TFile && folderNote === file) return false; if (folderNote instanceof TFile && folderNote === file) return false;
if (checking) return true; if (checking) return true;
turnIntoFolderNote(this.plugin, file, folder, folderNote); void turnIntoFolderNote(this.plugin, file, folder, folderNote);
}, },
}); });
@ -80,19 +82,19 @@ export class Commands {
const automaticallyCreateFolderNote = const automaticallyCreateFolderNote =
this.plugin.settings.autoCreate; this.plugin.settings.autoCreate;
this.plugin.settings.autoCreate = false; this.plugin.settings.autoCreate = false;
this.plugin.saveSettings(); void this.plugin.saveSettings();
await this.plugin.app.vault.createFolder(newPath); await this.plugin.app.vault.createFolder(newPath);
const folder = this.plugin.app.vault.getAbstractFileByPath(newPath); const folder = this.plugin.app.vault.getAbstractFileByPath(newPath);
if (!(folder instanceof TFolder)) return; if (!(folder instanceof TFolder)) return;
createFolderNote(this.plugin, folder.path, true, '.' + file.extension, false, file); await createFolderNote(this.plugin, folder.path, true, '.' + file.extension, false, file);
this.plugin.settings.autoCreate = automaticallyCreateFolderNote; this.plugin.settings.autoCreate = automaticallyCreateFolderNote;
this.plugin.saveSettings(); void this.plugin.saveSettings();
}, },
}); });
this.plugin.addCommand({ this.plugin.addCommand({
id: 'create-folder-note-for-current-folder', id: 'create-folder-note-for-current-folder',
name: 'Create markdown folder note for this folder', name: 'Create Markdown folder note for this folder',
checkCallback: (checking) => { checkCallback: (checking) => {
const file = this.app.workspace.getActiveFile(); const file = this.app.workspace.getActiveFile();
if (!(file instanceof TFile)) return false; if (!(file instanceof TFile)) return false;
@ -100,7 +102,7 @@ export class Commands {
if (!(folder instanceof TFolder)) return false; if (!(folder instanceof TFolder)) return false;
if (folder.path === '' || folder.path === '/') return false; if (folder.path === '' || folder.path === '/') return false;
if (checking) return true; if (checking) return true;
createFolderNote(this.plugin, folder.path, true, '.md', false); void createFolderNote(this.plugin, folder.path, true, '.md', false);
}, },
}); });
@ -116,7 +118,7 @@ export class Commands {
if (!(folder instanceof TFolder)) return false; if (!(folder instanceof TFolder)) return false;
if (folder.path === '' || folder.path === '/') return false; if (folder.path === '' || folder.path === '/') return false;
if (checking) return true; if (checking) return true;
createFolderNote(this.plugin, folder.path, true, '.' + fileType, false); void createFolderNote(this.plugin, folder.path, true, '.' + fileType, false);
}, },
}); });
}); });
@ -136,7 +138,7 @@ export class Commands {
// Everything is fine and not checking, let's create the folder note. // Everything is fine and not checking, let's create the folder note.
const ext = '.' + fileType; const ext = '.' + fileType;
const { path } = folder; const { path } = folder;
createFolderNote(this.plugin, path, true, ext, false); void createFolderNote(this.plugin, path, true, ext, false);
}, },
}); });
}); });
@ -152,7 +154,7 @@ export class Commands {
const folderNote = getFolderNote(this.plugin, folder.path); const folderNote = getFolderNote(this.plugin, folder.path);
if (!(folderNote instanceof TFile)) return false; if (!(folderNote instanceof TFile)) return false;
if (checking) return true; if (checking) return true;
deleteFolderNote(this.plugin, folderNote, true); void deleteFolderNote(this.plugin, folderNote, true);
}, },
}); });
@ -168,7 +170,7 @@ export class Commands {
if (checking) return true; if (checking) return true;
// Everything is fine and not checking, let's delete the folder note. // Everything is fine and not checking, let's delete the folder note.
deleteFolderNote(this.plugin, folderNote, true); void deleteFolderNote(this.plugin, folderNote, true);
}, },
}); });
this.plugin.addCommand({ this.plugin.addCommand({
@ -182,7 +184,7 @@ export class Commands {
const folderNote = getFolderNote(this.plugin, folder.path); const folderNote = getFolderNote(this.plugin, folder.path);
if (!(folderNote instanceof TFile)) return false; if (!(folderNote instanceof TFile)) return false;
if (checking) return true; if (checking) return true;
openFolderNote(this.plugin, folderNote); void openFolderNote(this.plugin, folderNote);
}, },
}); });
this.plugin.addCommand({ this.plugin.addCommand({
@ -197,14 +199,14 @@ export class Commands {
if (checking) return true; if (checking) return true;
// Everything is fine and not checking, let's open the folder note. // Everything is fine and not checking, let's open the folder note.
openFolderNote(this.plugin, folderNote); void openFolderNote(this.plugin, folderNote);
}, },
}); });
this.plugin.addCommand({ this.plugin.addCommand({
id: 'create-folder-note-from-selected-text', id: 'create-folder-note-from-selected-text',
name: 'Create folder note from selection', name: 'Create folder note from selection',
editorCheckCallback: (checking: boolean, editor: Editor, view: MarkdownView) => { editorCheckCallback: (checking: boolean, editor: Editor, view: MarkdownEditorContext) => {
const text = editor.getSelection().trim(); const text = editor.getSelection().trim();
const { file } = view; const { file } = view;
if (!(file instanceof TFile)) return false; if (!(file instanceof TFile)) return false;
@ -230,8 +232,8 @@ export class Commands {
new Notice('Folder note already exists'); new Notice('Folder note already exists');
return false; return false;
} }
this.plugin.app.vault.createFolder(text); void this.plugin.app.vault.createFolder(text);
createFolderNote(this.plugin, text, false); void createFolderNote(this.plugin, text, false);
} else { } else {
const folderFullPath = folderPath + '/' + text; const folderFullPath = folderPath + '/' + text;
@ -250,8 +252,8 @@ export class Commands {
return false; return false;
} }
} }
this.plugin.app.vault.createFolder(folderPath + '/' + text); void this.plugin.app.vault.createFolder(folderPath + '/' + text);
createFolderNote(this.plugin, folderPath + '/' + text, false); void createFolderNote(this.plugin, folderPath + '/' + text, false);
} }
const { folderNoteName } = this.plugin.settings; const { folderNoteName } = this.plugin.settings;
@ -317,7 +319,7 @@ export class Commands {
const automaticallyCreateFolderNote = const automaticallyCreateFolderNote =
this.plugin.settings.autoCreate; this.plugin.settings.autoCreate;
this.plugin.settings.autoCreate = false; this.plugin.settings.autoCreate = false;
this.plugin.saveSettings(); void this.plugin.saveSettings();
await this.plugin.app.vault.createFolder(newPath); await this.plugin.app.vault.createFolder(newPath);
const newFolder = this.plugin.app.vault const newFolder = this.plugin.app.vault
.getAbstractFileByPath(newPath); .getAbstractFileByPath(newPath);
@ -331,7 +333,7 @@ export class Commands {
file, file,
); );
this.plugin.settings.autoCreate = automaticallyCreateFolderNote; this.plugin.settings.autoCreate = automaticallyCreateFolderNote;
this.plugin.saveSettings(); void this.plugin.saveSettings();
}); });
}); });
@ -347,7 +349,7 @@ export class Commands {
item.onClick(() => { item.onClick(() => {
if (!folder || !(folder instanceof TFolder)) return; if (!folder || !(folder instanceof TFolder)) return;
const folderNote = getFolderNote(this.plugin, folder.path); const folderNote = getFolderNote(this.plugin, folder.path);
turnIntoFolderNote(this.plugin, file, folder, folderNote); void turnIntoFolderNote(this.plugin, file, folder, folderNote);
}); });
}); });
} }
@ -380,7 +382,7 @@ export class Commands {
(excluded) => (excluded) =>
(excluded.path !== file.path) || excluded.detached, (excluded.path !== file.path) || excluded.detached,
); );
this.plugin.saveSettings(true); void this.plugin.saveSettings(true);
new Notice('Successfully removed folder from excluded folders'); new Notice('Successfully removed folder from excluded folders');
}); });
}); });
@ -393,7 +395,7 @@ export class Commands {
item.setTitle('Remove folder from detached folders'); item.setTitle('Remove folder from detached folders');
item.setIcon('trash'); item.setIcon('trash');
item.onClick(() => { item.onClick(() => {
deleteExcludedFolder(this.plugin, detachedExcludedFolder); void deleteExcludedFolder(this.plugin, detachedExcludedFolder);
}); });
}); });
} }
@ -411,7 +413,7 @@ export class Commands {
this.plugin, this.plugin,
); );
this.plugin.settings.excludeFolders.push(newExcludedFolder); this.plugin.settings.excludeFolders.push(newExcludedFolder);
this.plugin.saveSettings(true); void this.plugin.saveSettings(true);
new Notice('Successfully excluded folder from folder notes'); new Notice('Successfully excluded folder from folder notes');
}); });
}); });
@ -425,7 +427,7 @@ export class Commands {
item.setTitle('Delete folder note'); item.setTitle('Delete folder note');
item.setIcon('trash'); item.setIcon('trash');
item.onClick(() => { item.onClick(() => {
deleteFolderNote(this.plugin, folderNote, true); void deleteFolderNote(this.plugin, folderNote, true);
}); });
}); });
@ -433,7 +435,7 @@ export class Commands {
item.setTitle('Open folder note'); item.setTitle('Open folder note');
item.setIcon('chevron-right-square'); item.setIcon('chevron-right-square');
item.onClick(() => { item.onClick(() => {
openFolderNote(this.plugin, folderNote); void openFolderNote(this.plugin, folderNote);
}); });
}); });
@ -474,10 +476,10 @@ export class Commands {
} }
} else { } else {
folderMenu.addItem((item) => { folderMenu.addItem((item) => {
item.setTitle('Create markdown folder note'); item.setTitle('Create Markdown folder note');
item.setIcon('edit'); item.setIcon('edit');
item.onClick(() => { item.onClick(() => {
createFolderNote(this.plugin, file.path, true, '.md'); void createFolderNote(this.plugin, file.path, true, '.md');
}); });
}); });
@ -487,7 +489,7 @@ export class Commands {
item.setTitle(`Create ${fileType} folder note`); item.setTitle(`Create ${fileType} folder note`);
item.setIcon('edit'); item.setIcon('edit');
item.onClick(() => { item.onClick(() => {
createFolderNote(this.plugin, file.path, true, '.' + fileType); void createFolderNote(this.plugin, file.path, true, '.' + fileType);
}); });
}); });
}); });
@ -500,8 +502,8 @@ export class Commands {
this.plugin.settings.useSubmenus this.plugin.settings.useSubmenus
) { ) {
menu.addItem(async (item) => { menu.addItem(async (item) => {
item.setTitle('Folder Note Commands').setIcon('folder-edit'); item.setTitle('Folder note commands').setIcon('folder-edit');
let subMenu: Menu = item.setSubmenu() as Menu; let subMenu: Menu = item.setSubmenu();
addFolderNoteActions(subMenu); addFolderNoteActions(subMenu);
}); });
} else { } else {
@ -512,7 +514,7 @@ export class Commands {
editorCommands(): void { editorCommands(): void {
// eslint-disable-next-line max-len // eslint-disable-next-line max-len
this.plugin.registerEvent(this.plugin.app.workspace.on('editor-menu', (menu: Menu, editor: Editor, view: MarkdownView) => { this.plugin.registerEvent(this.plugin.app.workspace.on('editor-menu', (menu: Menu, editor: Editor, view: MarkdownEditorContext) => {
const text = editor.getSelection().trim(); const text = editor.getSelection().trim();
if (!text || text.trim() === '') return; if (!text || text.trim() === '') return;
menu.addItem((item) => { menu.addItem((item) => {
@ -543,8 +545,8 @@ export class Commands {
if (folder instanceof TFolder) { if (folder instanceof TFolder) {
return new Notice('Folder note already exists'); return new Notice('Folder note already exists');
} }
this.plugin.app.vault.createFolder(text); void this.plugin.app.vault.createFolder(text);
createFolderNote(this.plugin, text, false); void createFolderNote(this.plugin, text, false);
} else { } else {
folder = this.plugin.app.vault.getAbstractFileByPath( folder = this.plugin.app.vault.getAbstractFileByPath(
@ -565,8 +567,8 @@ export class Commands {
return new Notice('File already exists'); return new Notice('File already exists');
} }
} }
this.plugin.app.vault.createFolder(folderPath + '/' + text); void this.plugin.app.vault.createFolder(folderPath + '/' + text);
createFolderNote(this.plugin, folderPath + '/' + text, false); void createFolderNote(this.plugin, folderPath + '/' + text, false);
} }
if (fileName !== text) { if (fileName !== text) {
editor.replaceSelection(`[[${fileName}]]`); editor.replaceSelection(`[[${fileName}]]`);

View file

@ -49,9 +49,9 @@ function aggregateFlags(
for (const property of propertiesToCopy) { for (const property of propertiesToCopy) {
const value = (matchedFolder as Partial<ExcludedFolder>)[property]; const value = (matchedFolder as Partial<ExcludedFolder>)[property];
if (value === true) { if (value === true) {
(result as Partial<ExcludedFolder>)[property] = true as never; (result)[property] = true as never;
} else if (!value) { } else if (!value) {
(result as Partial<ExcludedFolder>)[property] = false as never; (result)[property] = false as never;
} }
} }
} }
@ -117,7 +117,7 @@ export function getExcludedFolder(
const whitelist = getWhitelistedFolder( const whitelist = getWhitelistedFolder(
plugin, plugin,
path, path,
) as WhitelistedFolder | WhitelistedPattern | undefined; );
let skipWhitelist = ignoreWhitelist ?? false; let skipWhitelist = ignoreWhitelist ?? false;
if (excluded?.detached) skipWhitelist = true; if (excluded?.detached) skipWhitelist = true;

View file

@ -25,7 +25,7 @@ export default class PatternSettings extends Modal {
new Setting(contentEl) new Setting(contentEl)
.setName('Disable folder name sync') .setName('Disable folder name sync')
// eslint-disable-next-line max-len
.setDesc('Choose if the folder name should be renamed when the file name has been changed') .setDesc('Choose if the folder name should be renamed when the file name has been changed')
.addToggle((toggle) => .addToggle((toggle) =>
toggle toggle

View file

@ -34,7 +34,7 @@ export default class WhitelistFolderSettings extends Modal {
new Setting(contentEl) new Setting(contentEl)
.setName('Enable folder name sync') .setName('Enable folder name sync')
// eslint-disable-next-line max-len
.setDesc('Choose if the name of a folder note should be renamed when the folder name is changed') .setDesc('Choose if the name of a folder note should be renamed when the folder name is changed')
.addToggle((toggle) => .addToggle((toggle) =>
toggle toggle

View file

@ -23,7 +23,7 @@ export default class WhitelistPatternSettings extends Modal {
contentEl.createEl('h2', { text: 'Whitelisted pattern settings' }); contentEl.createEl('h2', { text: 'Whitelisted pattern settings' });
new Setting(contentEl) new Setting(contentEl)
.setName('Enable folder name sync') .setName('Enable folder name sync')
// eslint-disable-next-line max-len
.setDesc('Choose if the name of a folder note should be renamed when the folder name is changed') .setDesc('Choose if the name of a folder note should be renamed when the folder name is changed')
.addToggle((toggle) => .addToggle((toggle) =>
toggle toggle

View file

@ -43,10 +43,10 @@ function initializeFolderNoteFeatures(plugin: FolderNotesPlugin): void {
} }
function initializeBreadcrumbs(plugin: FolderNotesPlugin): void { function initializeBreadcrumbs(plugin: FolderNotesPlugin): void {
const titleContainers = document.querySelectorAll('.view-header-title-container'); const titleContainers = activeDocument.querySelectorAll('.view-header-title-container');
if (!titleContainers.length) return; if (!titleContainers.length) return;
titleContainers.forEach((container) => { titleContainers.forEach((container) => {
if (!(container instanceof HTMLElement)) return; if (!(container.instanceOf(HTMLElement))) return;
scheduleIdle(() => updateFolderNamesInPath(plugin, container), { timeout: 1000 }); scheduleIdle(() => updateFolderNamesInPath(plugin, container), { timeout: 1000 });
}); });
} }
@ -62,7 +62,7 @@ function observeFolderTitleMutations(plugin: FolderNotesPlugin): void {
fileExplorerMutationObserver = new MutationObserver((mutations) => { fileExplorerMutationObserver = new MutationObserver((mutations) => {
for (const mutation of mutations) { for (const mutation of mutations) {
for (const node of Array.from(mutation.addedNodes)) { for (const node of Array.from(mutation.addedNodes)) {
if (!(node instanceof HTMLElement)) continue; if (!(node.instanceOf(HTMLElement))) continue;
processAddedFolders(node, plugin); processAddedFolders(node, plugin);
} }
} }
@ -72,7 +72,7 @@ function observeFolderTitleMutations(plugin: FolderNotesPlugin): void {
} }
function initializeAllFolderTitles(plugin: FolderNotesPlugin): void { function initializeAllFolderTitles(plugin: FolderNotesPlugin): void {
const allTitles = document.querySelectorAll('.nav-folder-title-content'); const allTitles = activeDocument.querySelectorAll('.nav-folder-title-content');
for (const title of Array.from(allTitles)) { for (const title of Array.from(allTitles)) {
const folderTitle = title as HTMLElement; const folderTitle = title as HTMLElement;
const folderEl = folderTitle.closest('.nav-folder-title'); const folderEl = folderTitle.closest('.nav-folder-title');
@ -97,7 +97,7 @@ function processAddedFolders(node: HTMLElement, plugin: FolderNotesPlugin): void
const folderPath = folderEl?.getAttribute('data-path') || ''; const folderPath = folderEl?.getAttribute('data-path') || '';
const RETRY_TIMEOUT = 50; const RETRY_TIMEOUT = 50;
if (!folderEl || !folderPath) { if (!folderEl || !folderPath) {
setTimeout(() => { window.setTimeout(() => {
const retryFolderEl = folderTitle.closest('.nav-folder-title'); const retryFolderEl = folderTitle.closest('.nav-folder-title');
const retryFolderPath = retryFolderEl?.getAttribute('data-path') || ''; const retryFolderPath = retryFolderEl?.getAttribute('data-path') || '';
if (retryFolderEl && retryFolderPath) { if (retryFolderEl && retryFolderPath) {
@ -171,7 +171,7 @@ async function updateFolderNamesInPath(
} }
// eslint-disable-next-line complexity // eslint-disable-next-line complexity
titleParent?.childNodes.forEach(async (breadcrumb: HTMLElement) => { titleParent?.childNodes.forEach(async (breadcrumb: HTMLElement) => {
if (!(breadcrumb instanceof HTMLElement)) return; if (!(breadcrumb.instanceOf(HTMLElement))) return;
if (breadcrumb.classList.contains('view-header-breadcrumb-separator')) { if (breadcrumb.classList.contains('view-header-breadcrumb-separator')) {
if (breadcrumb.nextSibling === null) { if (breadcrumb.nextSibling === null) {
breadcrumb.classList.add('is-last-separator'); breadcrumb.classList.add('is-last-separator');
@ -179,7 +179,7 @@ async function updateFolderNamesInPath(
return; return;
} }
path += breadcrumb.getAttribute('old-name') ?? (breadcrumb as HTMLElement).innerText.trim(); path += breadcrumb.getAttribute('old-name') ?? (breadcrumb).innerText.trim();
path += '/'; path += '/';
const folderPath = path.slice(0, -TRAILING_SLASH_LENGTH); const folderPath = path.slice(0, -TRAILING_SLASH_LENGTH);
@ -206,7 +206,7 @@ async function updateFolderNamesInPath(
breadcrumb?.setAttribute('data-path', path.slice(0, -TRAILING_SLASH_LENGTH)); breadcrumb?.setAttribute('data-path', path.slice(0, -TRAILING_SLASH_LENGTH));
if (!breadcrumb.onclick) { if (!breadcrumb.onclick) {
breadcrumb.addEventListener('click', (e) => { breadcrumb.addEventListener('click', (e) => {
handleViewHeaderClick(e as MouseEvent, plugin); handleViewHeaderClick(e, plugin);
}, { capture: true }); }, { capture: true });
} }
@ -230,6 +230,6 @@ function scheduleIdle(callback: () => void, options?: { timeout: number }): void
}; };
windowWithIdle.requestIdleCallback(callback, options); windowWithIdle.requestIdleCallback(callback, options);
} else { } else {
setTimeout(callback, options?.timeout || DEFAULT_IDLE_TIMEOUT); window.setTimeout(callback, options?.timeout || DEFAULT_IDLE_TIMEOUT);
} }
} }

View file

@ -33,8 +33,8 @@ export async function handleViewHeaderClick(
} else if (event.altKey || Keymap.isModEvent(event) === 'tab') { } else if (event.altKey || Keymap.isModEvent(event) === 'tab') {
if (await handleFolderNoteCreation(event, plugin, folderPath)) return; if (await handleFolderNoteCreation(event, plugin, folderPath)) return;
} }
(event.target as HTMLElement).onclick = null; (event.target).onclick = null;
(event.target as HTMLElement).click(); (event.target).click();
} }
async function isExcludedFolder( async function isExcludedFolder(
@ -58,7 +58,7 @@ async function handleFolderNoteReveal(plugin: FolderNotesPlugin, folderNote: TFi
const fileExplorerPlugin = plugin.app.internalPlugins.getEnabledPluginById('file-explorer'); const fileExplorerPlugin = plugin.app.internalPlugins.getEnabledPluginById('file-explorer');
if (fileExplorerPlugin && Platform.isMobile && plugin.settings.openSidebar.mobile) { if (fileExplorerPlugin && Platform.isMobile && plugin.settings.openSidebar.mobile) {
const OPEN_SIDEBAR_DELAY = 200; const OPEN_SIDEBAR_DELAY = 200;
setTimeout(() => { fileExplorerPlugin.revealInFolder(folderNote); }, OPEN_SIDEBAR_DELAY); window.setTimeout(() => { fileExplorerPlugin.revealInFolder(folderNote); }, OPEN_SIDEBAR_DELAY);
} else if (fileExplorerPlugin && Platform.isDesktop && plugin.settings.openSidebar.desktop) { } else if (fileExplorerPlugin && Platform.isDesktop && plugin.settings.openSidebar.desktop) {
fileExplorerPlugin.revealInFolder(folderNote); fileExplorerPlugin.revealInFolder(folderNote);
} }

View file

@ -78,6 +78,6 @@ async function handleFolderCreation(folder: TFolder, plugin: FolderNotesPlugin):
const folderNote = getFolderNote(plugin, folder.path); const folderNote = getFolderNote(plugin, folder.path);
if (folderNote) return; if (folderNote) return;
createFolderNote(plugin, folder.path, openFile, undefined, true); void createFolderNote(plugin, folder.path, openFile, undefined, true);
addCSSClassToFileExplorerEl(folder.path, 'has-folder-note', false, plugin); addCSSClassToFileExplorerEl(folder.path, 'has-folder-note', false, plugin);
} }

View file

@ -4,9 +4,9 @@ export class ListComponent {
emitter: CustomEventEmitter; emitter: CustomEventEmitter;
containerEl: HTMLElement; containerEl: HTMLElement;
controlEl: HTMLElement; controlEl: HTMLElement;
emptyStateEl: HTMLElement; emptyStateEl!: HTMLElement;
listEl: HTMLElement; listEl: HTMLElement;
values: string[]; values!: string[];
defaultValues: string[]; defaultValues: string[];
constructor(containerEl: HTMLElement, values: string[] = [], defaultValues: string[] = []) { constructor(containerEl: HTMLElement, values: string[] = [], defaultValues: string[] = []) {
this.emitter = new CustomEventEmitter(); this.emitter = new CustomEventEmitter();
@ -48,17 +48,23 @@ export class ListComponent {
addElement(value: string): void { addElement(value: string): void {
this.listEl.createSpan('setting-hotkey', (span) => { this.listEl.createSpan('setting-hotkey', (span) => {
if (value.toLocaleLowerCase() === 'md') { if (value.toLocaleLowerCase() === 'md') {
span.innerText = 'markdown'; const markdown = 'markdown';
span.innerText = markdown;
} else { } else {
span.innerText = value; span.innerText = value;
} }
span.setAttribute('extension', value); span.setAttribute('extension', value);
// eslint-disable-next-line max-len
const removeSpan = span.createEl('span', { cls: 'ofn-list-item-remove setting-hotkey-icon' }); const removeSpan = span.createEl('span', { cls: 'ofn-list-item-remove setting-hotkey-icon' });
// eslint-disable-next-line max-len // eslint-disable-next-line max-len
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 lucide-x"><line x1="18" y1="6" x2="6" y2="18"></line><line x1="6" y1="6" x2="18" y2="18"></line></svg>'; 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 lucide-x"><line x1="18" y1="6" x2="6" y2="18"></line><line x1="6" y1="6" x2="18" y2="18"></line></svg>';
const svgElement = removeSpan.createEl('span', { cls: 'ofn-list-item-remove-icon' }); const svgElement = removeSpan.createEl('span', { cls: 'ofn-list-item-remove-icon' });
svgElement.innerHTML = svg; const parser = new DOMParser();
const svgDoc = parser.parseFromString(svg, 'image/svg+xml');
const svgNode = svgDoc.documentElement;
if (svgNode) {
svgElement.appendChild(activeDocument.importNode(svgNode, true));
}
removeSpan.onClickEvent(() => { removeSpan.onClickEvent(() => {
this.removeValue(value); this.removeValue(value);
span.remove(); span.remove();
@ -78,7 +84,13 @@ export class ListComponent {
const resetButton = this.controlEl.createEl('span', { cls: 'clickable-icon setting-restore-hotkey-button' }); const resetButton = this.controlEl.createEl('span', { cls: 'clickable-icon setting-restore-hotkey-button' });
// eslint-disable-next-line max-len // eslint-disable-next-line max-len
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 lucide-rotate-ccw"><path d="M3 2v6h6"></path><path d="M3 13a9 9 0 1 0 3-7.7L3 8"></path></svg>'; 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 lucide-rotate-ccw"><path d="M3 2v6h6"></path><path d="M3 13a9 9 0 1 0 3-7.7L3 8"></path></svg>';
resetButton.innerHTML = svg; const svgElement = resetButton.createEl('span', { cls: 'ofn-list-item-remove-icon' });
const parser = new DOMParser();
const svgDoc = parser.parseFromString(svg, 'image/svg+xml');
const svgNode = svgDoc.documentElement;
if (svgNode) {
svgElement.appendChild(activeDocument.importNode(svgNode, true));
}
resetButton.onClickEvent(() => { resetButton.onClickEvent(() => {
this.setValues(this.defaultValues); this.setValues(this.defaultValues);
}); });

View file

@ -176,7 +176,7 @@ async function handleCreateFolderNote(plugin: FolderNotesPlugin, folderNoteType:
if ( if (
extension === '.excalidraw' && extension === '.excalidraw' &&
!content.includes( !content.includes(
'==⚠ Switch to EXCALIDRAW VIEW in the MORE OPTIONS menu of this document. ⚠==', '==⚠ Switch to EXCALIDRAW VIEW in the MORE OPTIONS menu of this activeDocument. ⚠==',
) )
) { ) {
content = await getDefaultTemplate(plugin.app); content = await getDefaultTemplate(plugin.app);
@ -303,12 +303,12 @@ export async function turnIntoFolderNote(
} }
if (detachedExcludedFolder) { if (detachedExcludedFolder) {
deleteExcludedFolder(plugin, detachedExcludedFolder); void deleteExcludedFolder(plugin, detachedExcludedFolder);
} }
await plugin.app.fileManager.renameFile(file, path); await plugin.app.fileManager.renameFile(file, path);
addCSSClassToFileExplorerEl(path, 'is-folder-note', false, plugin, true); void addCSSClassToFileExplorerEl(path, 'is-folder-note', false, plugin, true);
addCSSClassToFileExplorerEl(folder.path, 'has-folder-note', false, plugin); void addCSSClassToFileExplorerEl(folder.path, 'has-folder-note', false, plugin);
removeActiveFolder(plugin); removeActiveFolder(plugin);
setActiveFolder(folder.path, plugin); setActiveFolder(folder.path, plugin);
@ -502,7 +502,7 @@ export function detachFolderNote(plugin: FolderNotesPlugin, file: TFile): void {
excludedFolder.detached = true; excludedFolder.detached = true;
excludedFolder.detachedFilePath = file.path; excludedFolder.detachedFilePath = file.path;
addExcludedFolder(plugin, excludedFolder); addExcludedFolder(plugin, excludedFolder);
updateCSSClassesForFolderNote(file.path, plugin); void updateCSSClassesForFolderNote(file.path, plugin);
} }

View file

@ -151,7 +151,7 @@ export async function addCSSClassToFileExplorerEl(
if (!fileExplorerItem) { if (!fileExplorerItem) {
if (waitForCreate && count < MAX_RETRIES) { if (waitForCreate && count < MAX_RETRIES) {
await new Promise((r) => setTimeout(r, RETRY_DELAY)); await new Promise((r) => window.setTimeout(r, RETRY_DELAY));
addCSSClassToFileExplorerEl(path, cssClass, parent, plugin, waitForCreate, count + 1); addCSSClassToFileExplorerEl(path, cssClass, parent, plugin, waitForCreate, count + 1);
return; return;
} }
@ -164,7 +164,7 @@ export async function addCSSClassToFileExplorerEl(
} }
} else { } else {
fileExplorerItem.addClass(cssClass); fileExplorerItem.addClass(cssClass);
document.querySelectorAll(`[data-path='${CSS.escape(path)}']`).forEach((item) => { activeDocument.querySelectorAll(`[data-path='${CSS.escape(path)}']`).forEach((item) => {
item.addClass(cssClass); item.addClass(cssClass);
}); });
} }
@ -183,7 +183,7 @@ export function removeCSSClassFromFileExplorerEL(
): void { ): void {
if (!path) return; if (!path) return;
const fileExplorerItem = getFileExplorerElement(path, plugin); const fileExplorerItem = getFileExplorerElement(path, plugin);
document.querySelectorAll(`[data-path='${CSS.escape(path)}']`).forEach((item) => { activeDocument.querySelectorAll(`[data-path='${CSS.escape(path)}']`).forEach((item) => {
item.removeClass(cssClass); item.removeClass(cssClass);
}); });
if (!fileExplorerItem) { return; } if (!fileExplorerItem) { return; }

View file

@ -80,7 +80,7 @@ export function getFileExplorerActiveFolder(): TFolder | null {
const activeFileOrFolder = const activeFileOrFolder =
fe.tree.focusedItem?.file ?? fe.activeDom?.file; fe.tree.focusedItem?.file ?? fe.activeDom?.file;
if (!(activeFileOrFolder instanceof TFolder)) return null; if (!(activeFileOrFolder instanceof TFolder)) return null;
return activeFileOrFolder as TFolder; return activeFileOrFolder;
} }
export function getFileExplorerActiveFolderNote(): TFile | null { export function getFileExplorerActiveFolderNote(): TFile | null {

View file

@ -1,5 +1,5 @@
import { import {
type TAbstractFile, type App, type TAbstractFile,
type MarkdownPostProcessorContext, type MarkdownPostProcessorContext,
type WorkspaceLeaf, type WorkspaceLeaf,
Plugin, TFile, TFolder, Plugin, TFile, TFolder,
@ -9,6 +9,7 @@ import {
import { import {
type FolderNotesSettings, DEFAULT_SETTINGS, SettingsTab, type FolderNotesSettings, DEFAULT_SETTINGS, SettingsTab,
} from './settings/SettingsTab'; } from './settings/SettingsTab';
import { FolderOverview, type defaultOverviewSettings } from './obsidian-folder-overview/src/FolderOverview';
import { Commands } from './Commands'; import { Commands } from './Commands';
import type { FileExplorerWorkspaceLeaf } from './globals'; import type { FileExplorerWorkspaceLeaf } from './globals';
import { import {
@ -21,7 +22,6 @@ import {
import { handleCreate } from './events/handleCreate'; import { handleCreate } from './events/handleCreate';
import { FrontMatterTitlePluginHandler } from './events/FrontMatterTitle'; import { FrontMatterTitlePluginHandler } from './events/FrontMatterTitle';
import { FolderOverviewSettings } from './obsidian-folder-overview/src/modals/Settings'; import { FolderOverviewSettings } from './obsidian-folder-overview/src/modals/Settings';
import { FolderOverview } from './obsidian-folder-overview/src/FolderOverview';
import { TabManager } from './events/TabManager'; import { TabManager } from './events/TabManager';
import './functions/ListComponent'; import './functions/ListComponent';
import { handleDelete } from './events/handleDelete'; import { handleDelete } from './events/handleDelete';
@ -36,26 +36,65 @@ import { updateOverviewView, updateViewDropdown } from './obsidian-folder-overvi
import { FvIndexDB } from './obsidian-folder-overview/src/utils/IndexDB'; import { FvIndexDB } from './obsidian-folder-overview/src/utils/IndexDB';
import { updateAllOverviews } from './obsidian-folder-overview/src/utils/functions'; import { updateAllOverviews } from './obsidian-folder-overview/src/utils/functions';
interface FileExplorerPluginLike extends Plugin {
revealInFolder: (file: TAbstractFile) => void;
}
interface DragManagerLike {
draggable?: {
file?: TAbstractFile;
type?: string;
} | null;
setAction(action: string): void;
}
interface ClipboardManagerLike {
app: App & {
dragManager?: DragManagerLike;
};
handleDragOver: (evt: DragEvent, ...args: unknown[]) => void;
handleDrop: (evt: DragEvent, ...args: unknown[]) => void;
}
interface EditModeLike {
clipboardManager: ClipboardManagerLike;
}
interface ViewWithEditModes {
editMode?: EditModeLike;
sourceMode?: EditModeLike;
}
interface ActiveEditorLike {
editMode?: EditModeLike;
}
type LegacySettingsData = Partial<FolderNotesSettings> & {
allowWhitespaceCollapsing?: boolean;
defaultOverview?: defaultOverviewSettings;
};
export default class FolderNotesPlugin extends Plugin { export default class FolderNotesPlugin extends Plugin {
settings: FolderNotesSettings; settings!: FolderNotesSettings;
settingsTab: SettingsTab; settingsTab!: SettingsTab;
activeFolderDom: HTMLElement | null; activeFolderDom!: HTMLElement | null;
activeFileExplorer: FileExplorerWorkspaceLeaf; activeFileExplorer!: FileExplorerWorkspaceLeaf;
fmtpHandler: FrontMatterTitlePluginHandler | null = null; fmtpHandler: FrontMatterTitlePluginHandler | null = null;
hoveredElement: HTMLElement | null = null; hoveredElement: HTMLElement | null = null;
mouseEvent: MouseEvent | null = null; mouseEvent: MouseEvent | null = null;
hoverLinkTriggered = false; hoverLinkTriggered = false;
tabManager: TabManager; tabManager!: TabManager;
settingsOpened = false; settingsOpened = false;
askModalCurrentlyOpen = false; askModalCurrentlyOpen = false;
fvIndexDB: FvIndexDB; fvIndexDB!: FvIndexDB;
async onload(): Promise<void> { async onload(): Promise<void> {
// eslint-disable-next-line obsidianmd/rule-custom-message
console.log('loading folder notes plugin'); console.log('loading folder notes plugin');
await this.loadSettings(); await this.loadSettings();
this.settingsTab = new SettingsTab(this.app, this); this.settingsTab = new SettingsTab(this.app, this);
this.addSettingTab(this.settingsTab); this.addSettingTab(this.settingsTab);
this.saveSettings(); await this.saveSettings();
this.fvIndexDB = new FvIndexDB(this); this.fvIndexDB = new FvIndexDB(this);
// Add CSS Classes // Add CSS Classes
@ -64,7 +103,7 @@ export default class FolderNotesPlugin extends Plugin {
new Commands(this.app, this).registerCommands(); new Commands(this.app, this).registerCommands();
registerOverviewCommands(this); registerOverviewCommands(this);
this.app.workspace.onLayoutReady(this.onLayoutReady.bind(this)); this.app.workspace.onLayoutReady(() => this.onLayoutReady());
if (!this.settings.persistentSettingsTab.afterRestart) { if (!this.settings.persistentSettingsTab.afterRestart) {
this.settings.settingsTab = 'general'; this.settings.settingsTab = 'general';
@ -93,7 +132,7 @@ export default class FolderNotesPlugin extends Plugin {
this.hoverLinkTriggered = true; this.hoverLinkTriggered = true;
}); });
this.registerEvent(this.app.workspace.on('file-open', async (openFile: TFile | null) => { this.registerEvent(this.app.workspace.on('file-open', (openFile: TFile | null) => {
removeActiveFolder(this); removeActiveFolder(this);
if (!openFile || !openFile.basename) { return; } if (!openFile || !openFile.basename) { return; }
@ -109,7 +148,9 @@ export default class FolderNotesPlugin extends Plugin {
})); }));
this.registerEvent(this.app.vault.on('create', (file: TAbstractFile) => { this.registerEvent(this.app.vault.on('create', (file: TAbstractFile) => {
handleCreate(file, this); handleCreate(file, this).catch((err) => {
console.error(err); new Notice('Error handling file creation');
});
this.handleVaultChange(); this.handleVaultChange();
})); }));
@ -132,39 +173,43 @@ export default class FolderNotesPlugin extends Plugin {
} }
addSettingCssClasses(): void { addSettingCssClasses(): void {
document.body.classList.add('folder-notes-plugin'); activeDocument.body.classList.add('folder-notes-plugin');
if (this.settings.hideFolderNote) { document.body.classList.add('hide-folder-note'); } if (this.settings.hideFolderNote) { activeDocument.body.classList.add('hide-folder-note'); }
if (this.settings.hideCollapsingIconForEmptyFolders) { if (this.settings.hideCollapsingIconForEmptyFolders) {
document.body.classList.add('fn-hide-empty-collapse-icon'); activeDocument.body.classList.add('fn-hide-empty-collapse-icon');
} }
if (this.settings.hideFolderNoteNameInPath) { if (this.settings.hideFolderNoteNameInPath) {
document.body.classList.add('folder-note-hide-name-path'); activeDocument.body.classList.add('folder-note-hide-name-path');
}
if (this.settings.underlineFolder) {
activeDocument.body.classList.add('folder-note-underline');
}
if (this.settings.boldName) { activeDocument.body.classList.add('folder-note-bold'); }
if (this.settings.cursiveName) { activeDocument.body.classList.add('folder-note-cursive'); }
if (this.settings.boldNameInPath) {
activeDocument.body.classList.add('folder-note-bold-path');
} }
if (this.settings.underlineFolder) { document.body.classList.add('folder-note-underline'); }
if (this.settings.boldName) { document.body.classList.add('folder-note-bold'); }
if (this.settings.cursiveName) { document.body.classList.add('folder-note-cursive'); }
if (this.settings.boldNameInPath) { document.body.classList.add('folder-note-bold-path'); }
if (this.settings.cursiveNameInPath) { if (this.settings.cursiveNameInPath) {
document.body.classList.add('folder-note-cursive-path'); activeDocument.body.classList.add('folder-note-cursive-path');
} }
if (this.settings.underlineFolderInPath) { if (this.settings.underlineFolderInPath) {
document.body.classList.add('folder-note-underline-path'); activeDocument.body.classList.add('folder-note-underline-path');
} }
if (this.settings.stopWhitespaceCollapsing) { if (this.settings.stopWhitespaceCollapsing) {
document.body.classList.add('fn-whitespace-stop-collapsing'); activeDocument.body.classList.add('fn-whitespace-stop-collapsing');
} }
if (this.settings.hideCollapsingIcon) { if (this.settings.hideCollapsingIcon) {
document.body.classList.add('fn-hide-collapse-icon'); activeDocument.body.classList.add('fn-hide-collapse-icon');
} }
if (this.settings.ignoreAttachmentFolder) { if (this.settings.ignoreAttachmentFolder) {
document.body.classList.add('fn-ignore-attachment-folder'); activeDocument.body.classList.add('fn-ignore-attachment-folder');
} }
if (!this.settings.highlightFolder) { if (!this.settings.highlightFolder) {
document.body.classList.add('disable-folder-highlight'); activeDocument.body.classList.add('disable-folder-highlight');
} }
if (requireApiVersion('1.7.2')) { if (requireApiVersion('1.7.2')) {
document.body.classList.add('version-1-7-2'); activeDocument.body.classList.add('version-1-7-2');
} }
} }
@ -188,12 +233,12 @@ export default class FolderNotesPlugin extends Plugin {
this.tabManager = new TabManager(this); this.tabManager = new TabManager(this);
this.tabManager.updateTabs(); this.tabManager.updateTabs();
this.registerDomEvent(document, 'click', (evt: MouseEvent) => { this.registerDomEvent(activeDocument, 'click', (evt: MouseEvent) => {
this.handleFileExplorerClick(evt); this.handleFileExplorerClick(evt);
}, true); }, true);
// Handle middle mouse button clicks // Handle middle mouse button clicks
this.registerDomEvent(document, 'auxclick', (evt: MouseEvent) => { this.registerDomEvent(activeDocument, 'auxclick', (evt: MouseEvent) => {
const rightClick = 2; const rightClick = 2;
if (evt.button === rightClick) return; if (evt.button === rightClick) return;
this.handleFileExplorerClick(evt); this.handleFileExplorerClick(evt);
@ -201,26 +246,32 @@ export default class FolderNotesPlugin extends Plugin {
const fileExplorerPlugin = this.app.internalPlugins.getEnabledPluginById('file-explorer'); const fileExplorerPlugin = this.app.internalPlugins.getEnabledPluginById('file-explorer');
if (fileExplorerPlugin) { if (fileExplorerPlugin) {
const originalRevealInFolder = fileExplorerPlugin.revealInFolder const fileExplorer = fileExplorerPlugin as unknown as FileExplorerPluginLike;
.bind(fileExplorerPlugin); const originalRevealInFolder =
fileExplorerPlugin.revealInFolder = (file: TAbstractFile): void => { fileExplorer.revealInFolder as unknown as FileExplorerPluginLike['revealInFolder'];
fileExplorer.revealInFolder = (file: TAbstractFile): void => {
if (file instanceof TFile) { if (file instanceof TFile) {
const folder = getFolder(this, file); const folder = getFolder(this, file);
if (folder instanceof TFolder) { if (folder instanceof TFolder) {
const folderNote = getFolderNote(this, folder.path); const folderNote = getFolderNote(this, folder.path);
if (!folderNote || folderNote.path !== file.path) { if (!folderNote || folderNote.path !== file.path) {
return originalRevealInFolder.call(fileExplorerPlugin, file); originalRevealInFolder(file);
return;
} }
document.body.classList.remove('hide-folder-note'); activeDocument.body.classList.remove('hide-folder-note');
originalRevealInFolder.call(fileExplorerPlugin, folder); originalRevealInFolder(folder);
const FOLDER_REVEAL_DELAY = 100; const FOLDER_REVEAL_DELAY = 100;
setTimeout(() => { window.setTimeout(() => {
document.body.classList.add('hide-folder-note'); activeDocument.body.classList.add('hide-folder-note');
}, FOLDER_REVEAL_DELAY); }, FOLDER_REVEAL_DELAY);
return; return;
} }
} }
return originalRevealInFolder.call(fileExplorerPlugin, file); if (file instanceof TFolder || file instanceof TFile) {
originalRevealInFolder(file);
return;
}
}; };
} }
@ -229,25 +280,27 @@ export default class FolderNotesPlugin extends Plugin {
if (!view) { return; } if (!view) { return; }
// @ts-expect-error use internal API const viewWithEditModes = view as ViewWithEditModes;
const editMode = view.editMode ?? view.sourceMode const activeEditor = this.app.workspace.activeEditor as ActiveEditorLike | undefined;
// @ts-expect-error use internal API const editMode = viewWithEditModes.editMode ?? viewWithEditModes.sourceMode
?? this.app.workspace.activeEditor?.editMode; ?? activeEditor?.editMode;
const plugin = this;
if (!editMode) { return; } if (!editMode) { return; }
const clipboardProto = editMode.clipboardManager.constructor.prototype; const { clipboardManager } = editMode;
const clipboardProto = Object.getPrototypeOf(clipboardManager) as ClipboardManagerLike;
const originalHandleDragOver = clipboardProto.handleDragOver; const originalHandleDragOver =
const originalHandleDrop = clipboardProto.handleDrop; clipboardProto.handleDragOver as unknown as ClipboardManagerLike['handleDragOver'];
const originalHandleDrop =
clipboardProto.handleDrop as unknown as ClipboardManagerLike['handleDrop'];
clipboardProto.handleDragOver = function (evt: DragEvent, ...args: unknown[]): void { clipboardProto.handleDragOver = (evt: DragEvent, ...args: unknown[]): void => {
const { dragManager } = this.app; const { dragManager } = clipboardManager.app;
const draggable = dragManager?.draggable; const draggable = dragManager?.draggable;
if (draggable?.file instanceof TFolder) { if (draggable?.file instanceof TFolder) {
const folderNote = getFolderNote(plugin, draggable.file.path); const folderNote = getFolderNote(this, draggable.file.path);
if (folderNote) { if (folderNote) {
dragManager.setAction( dragManager.setAction(
window.i18next.t('interface.drag-and-drop.insert-link-here'), window.i18next.t('interface.drag-and-drop.insert-link-here'),
@ -256,22 +309,22 @@ export default class FolderNotesPlugin extends Plugin {
} }
} }
return originalHandleDragOver.call(this, evt, ...args); originalHandleDragOver(evt, ...args);
}; };
clipboardProto.handleDrop = function (evt: DragEvent, ...args: unknown[]): void { clipboardProto.handleDrop = (evt: DragEvent, ...args: unknown[]): void => {
const { dragManager } = this.app; const { dragManager } = clipboardManager.app;
const draggable = dragManager?.draggable; const draggable = dragManager?.draggable;
if (draggable?.file instanceof TFolder) { if (draggable?.file instanceof TFolder) {
const folderNote = getFolderNote(plugin, draggable.file.path); const folderNote = getFolderNote(this, draggable.file.path);
if (folderNote) { if (folderNote) {
draggable.file = folderNote; draggable.file = folderNote;
draggable.type = 'file'; draggable.type = 'file';
} }
} }
return originalHandleDrop.call(this, evt, ...args); originalHandleDrop(evt, ...args);
}; };
if (this.settings.fvGlobalSettings.autoUpdateLinks) { if (this.settings.fvGlobalSettings.autoUpdateLinks) {
@ -283,7 +336,7 @@ export default class FolderNotesPlugin extends Plugin {
if (!this.settings.fvGlobalSettings.autoUpdateLinks) return; if (!this.settings.fvGlobalSettings.autoUpdateLinks) return;
const DEBOUNCE_DELAY = 2000; const DEBOUNCE_DELAY = 2000;
debounce(() => { debounce(() => {
updateAllOverviews(this); void updateAllOverviews(this);
}, DEBOUNCE_DELAY, true)(); }, DEBOUNCE_DELAY, true)();
} }
@ -314,7 +367,7 @@ export default class FolderNotesPlugin extends Plugin {
evt.stopImmediatePropagation(); evt.stopImmediatePropagation();
} }
openFolderNote(this, folderNote, evt); void openFolderNote(this, folderNote, evt);
} }
private isMobileClickDisabled(): boolean { private isMobileClickDisabled(): boolean {
@ -325,9 +378,12 @@ export default class FolderNotesPlugin extends Plugin {
folderTitleEl: HTMLElement | null; folderTitleEl: HTMLElement | null;
onlyClickedOnFolderTitle: boolean; onlyClickedOnFolderTitle: boolean;
} { } {
const folderTitleEl = target.closest('.nav-folder-title') as HTMLElement | null; const folderTitleEl = target.closest('.nav-folder-title');
const onlyClickedOnFolderTitle = !!target.closest('.nav-folder-title-content'); const onlyClickedOnFolderTitle = !!target.closest('.nav-folder-title-content');
return { folderTitleEl, onlyClickedOnFolderTitle }; return {
folderTitleEl: folderTitleEl instanceof HTMLElement ? folderTitleEl : null,
onlyClickedOnFolderTitle,
};
} }
private shouldIgnoreClickByWhitespaceOrCollapse( private shouldIgnoreClickByWhitespaceOrCollapse(
@ -358,9 +414,9 @@ export default class FolderNotesPlugin extends Plugin {
} }
private createNoteAndMark(folderPath: string): void { private createNoteAndMark(folderPath: string): void {
createFolderNote(this, folderPath, true, undefined, true); void createFolderNote(this, folderPath, true, undefined, true);
addCSSClassToFileExplorerEl(folderPath, 'has-folder-note', false, this); void addCSSClassToFileExplorerEl(folderPath, 'has-folder-note', false, this);
removeCSSClassFromFileExplorerEL(folderPath, 'has-not-folder-note', false, this); void removeCSSClassFromFileExplorerEL(folderPath, 'has-not-folder-note', false, this);
} }
private shouldOpenNote(usedCtrl: boolean, evt: MouseEvent): boolean { private shouldOpenNote(usedCtrl: boolean, evt: MouseEvent): boolean {
@ -380,7 +436,7 @@ export default class FolderNotesPlugin extends Plugin {
new FolderOverviewSettings( new FolderOverviewSettings(
this.app, this.app,
this, this,
parseYaml(source), parseYaml(source) as defaultOverviewSettings,
ctx, ctx,
el, el,
this.settings.defaultOverview, this.settings.defaultOverview,
@ -404,7 +460,7 @@ export default class FolderNotesPlugin extends Plugin {
el, el,
defaultOverview, defaultOverview,
); );
folderOverview.create(this, el, ctx); void folderOverview.create(this, el, ctx);
} else { } else {
this.app.workspace.onLayoutReady(() => { this.app.workspace.onLayoutReady(() => {
const folderOverview = new FolderOverview( const folderOverview = new FolderOverview(
@ -414,7 +470,7 @@ export default class FolderNotesPlugin extends Plugin {
el, el,
this.settings.defaultOverview, this.settings.defaultOverview,
); );
folderOverview.create(this, el, ctx); void folderOverview.create(this, el, ctx);
}); });
} }
} catch (e) { } catch (e) {
@ -438,7 +494,7 @@ export default class FolderNotesPlugin extends Plugin {
} }
if (!leaf) return; if (!leaf) return;
workspace.revealLeaf(leaf); void workspace.revealLeaf(leaf);
} }
updateOverviewView: typeof updateOverviewView = updateOverviewView; updateOverviewView: typeof updateOverviewView = updateOverviewView;
@ -451,12 +507,12 @@ export default class FolderNotesPlugin extends Plugin {
|| attachmentFolderPath === ''; || attachmentFolderPath === '';
const threshold = this.settings.storageLocation === 'insideFolder' ? 1 : 0; const threshold = this.settings.storageLocation === 'insideFolder' ? 1 : 0;
if (folder.children.length === 0) { if (folder.children.length === 0) {
addCSSClassToFileExplorerEl(folder.path, 'fn-empty-folder', false, this); void addCSSClassToFileExplorerEl(folder.path, 'fn-empty-folder', false, this);
} }
attachmentFolderPath = `${folder.path}/${cleanAttachmentFolderPath}`; attachmentFolderPath = `${folder.path}/${cleanAttachmentFolderPath}`;
if (folder.children.length === threshold) { if (folder.children.length === threshold) {
addCSSClassToFileExplorerEl(folder.path, 'fn-empty-folder', false, this); void addCSSClassToFileExplorerEl(folder.path, 'fn-empty-folder', false, this);
return true; return true;
} else if (folder.children.length > threshold) { } else if (folder.children.length > threshold) {
if (attachmentsAreInRootFolder) { if (attachmentsAreInRootFolder) {
@ -469,12 +525,12 @@ export default class FolderNotesPlugin extends Plugin {
attachmentFolder instanceof TFolder && attachmentFolder instanceof TFolder &&
folder.children.length <= threshold + 1 folder.children.length <= threshold + 1
) { ) {
addCSSClassToFileExplorerEl(folder.path, 'fn-empty-folder', false, this); void addCSSClassToFileExplorerEl(folder.path, 'fn-empty-folder', false, this);
addCSSClassToFileExplorerEl( void addCSSClassToFileExplorerEl(
folder.path, 'fn-has-attachment-folder', folder.path, 'fn-has-attachment-folder',
false, this, false, this,
); );
addCSSClassToFileExplorerEl( void addCSSClassToFileExplorerEl(
folder.path, 'fn-has-attachment-folder', folder.path, 'fn-has-attachment-folder',
true, this, true, this,
); );
@ -499,7 +555,7 @@ export default class FolderNotesPlugin extends Plugin {
let fileExplorerItem = getFileExplorerElement(folder.path, this); let fileExplorerItem = getFileExplorerElement(folder.path, this);
if (!fileExplorerItem) { if (!fileExplorerItem) {
if (waitForCreate && count < MAX_RETRY_COUNT) { if (waitForCreate && count < MAX_RETRY_COUNT) {
await new Promise<void>((resolve) => setTimeout(resolve, RETRY_DELAY_MS)); await new Promise<void>((resolve) => window.setTimeout(resolve, RETRY_DELAY_MS));
void this.changeFolderNameInExplorer(folder, newName, waitForCreate, count + 1); void this.changeFolderNameInExplorer(folder, newName, waitForCreate, count + 1);
return; return;
} }
@ -509,11 +565,11 @@ export default class FolderNotesPlugin extends Plugin {
fileExplorerItem = fileExplorerItem?.querySelector('div.nav-folder-title-content'); fileExplorerItem = fileExplorerItem?.querySelector('div.nav-folder-title-content');
if (!fileExplorerItem) { return; } if (!fileExplorerItem) { return; }
if (this.settings.frontMatterTitle.explorer && this.settings.frontMatterTitle.enabled) { if (this.settings.frontMatterTitle.explorer && this.settings.frontMatterTitle.enabled) {
(fileExplorerItem as HTMLElement).innerText = newName; (fileExplorerItem).innerText = newName;
(fileExplorerItem as HTMLElement).setAttribute('old-name', folder.name); (fileExplorerItem).setAttribute('old-name', folder.name);
} else { } else {
(fileExplorerItem as HTMLElement).innerText = folder.name; (fileExplorerItem).innerText = folder.name;
(fileExplorerItem as HTMLElement).removeAttribute('old-name'); (fileExplorerItem).removeAttribute('old-name');
} }
} }
@ -534,7 +590,7 @@ export default class FolderNotesPlugin extends Plugin {
*/ */
updateAllBreadcrumbs(remove?: boolean): void { updateAllBreadcrumbs(remove?: boolean): void {
if (!this.settings.frontMatterTitle.path && !remove) { return; } if (!this.settings.frontMatterTitle.path && !remove) { return; }
const viewHeaderItems = document.querySelectorAll('span.view-header-breadcrumb'); const viewHeaderItems = activeDocument.querySelectorAll('span.view-header-breadcrumb');
const files = this.app.vault.getAllLoadedFiles().filter((file) => file instanceof TFolder); const files = this.app.vault.getAllLoadedFiles().filter((file) => file instanceof TFolder);
viewHeaderItems.forEach((item) => { viewHeaderItems.forEach((item) => {
if (!item.hasAttribute('data-path')) { return; } if (!item.hasAttribute('data-path')) { return; }
@ -554,10 +610,10 @@ export default class FolderNotesPlugin extends Plugin {
onunload(): void { onunload(): void {
unregisterFileExplorerObserver(); unregisterFileExplorerObserver();
document.body.classList.remove('folder-notes-plugin'); activeDocument.body.classList.remove('folder-notes-plugin');
document.body.classList.remove('folder-note-underline'); activeDocument.body.classList.remove('folder-note-underline');
document.body.classList.remove('hide-folder-note'); activeDocument.body.classList.remove('hide-folder-note');
document.body.classList.remove('fn-whitespace-stop-collapsing'); activeDocument.body.classList.remove('fn-whitespace-stop-collapsing');
removeActiveFolder(this); removeActiveFolder(this);
if (this.fmtpHandler) { if (this.fmtpHandler) {
this.fmtpHandler.deleteEvent(); this.fmtpHandler.deleteEvent();
@ -565,7 +621,7 @@ export default class FolderNotesPlugin extends Plugin {
} }
async loadSettings(): Promise<void> { async loadSettings(): Promise<void> {
const data = await this.loadData(); const data = await this.loadData() as LegacySettingsData | null;
if (data) { if (data) {
if (data.allowWhitespaceCollapsing === true) { if (data.allowWhitespaceCollapsing === true) {
data.stopWhitespaceCollapsing = false; data.stopWhitespaceCollapsing = false;

View file

@ -38,7 +38,7 @@ export default class AddSupportedFileModal extends Modal {
}), }),
); );
} }
async onClose(): Promise<void> { onClose(): void {
if (this.name.toLocaleLowerCase() === 'markdown') { if (this.name.toLocaleLowerCase() === 'markdown') {
this.name = 'md'; this.name = 'md';
} }
@ -50,10 +50,13 @@ export default class AddSupportedFileModal extends Modal {
new Notice('This extension is already supported'); new Notice('This extension is already supported');
return; return;
} else { } else {
await this.list.addValue(this.name.toLowerCase()); // Run async operations without returning a Promise from onClose
this.settingsTab.display(); void (async (): Promise<void> => {
this.plugin.saveSettings(); await this.list.addValue(this.name.toLowerCase());
contentEl.empty(); this.settingsTab.display();
await this.plugin.saveSettings();
contentEl.empty();
})();
} }
} }
} }

View file

@ -39,7 +39,7 @@ export class AskForExtensionModal extends FuzzySuggestModal<string> {
onChooseItem(item: string, _evt: MouseEvent | KeyboardEvent): void { onChooseItem(item: string, _evt: MouseEvent | KeyboardEvent): void {
this.plugin.askModalCurrentlyOpen = false; this.plugin.askModalCurrentlyOpen = false;
this.extension = '.' + item; this.extension = '.' + item;
createFolderNote( void createFolderNote(
this.plugin, this.plugin,
this.folderPath, this.folderPath,
this.openFile, this.openFile,

View file

@ -46,9 +46,9 @@ export default class ExistingFolderNoteModal extends Modal {
text: 'Rename and don\'t ask again', text: 'Rename and don\'t ask again',
}); });
confirmButton.classList.add('mod-warning', 'fn-confirmation-modal-button'); confirmButton.classList.add('mod-warning', 'fn-confirmation-modal-button');
confirmButton.addEventListener('click', async () => { confirmButton.addEventListener('click', () => {
this.plugin.settings.showRenameConfirmation = false; this.plugin.settings.showRenameConfirmation = false;
this.plugin.saveSettings(); void this.plugin.saveSettings();
this.close(); this.close();
turnIntoFolderNote(this.plugin, this.file, this.folder, this.folderNote, true); turnIntoFolderNote(this.plugin, this.file, this.folder, this.folderNote, true);
}); });
@ -69,14 +69,14 @@ export default class ExistingFolderNoteModal extends Modal {
} }
const button = buttonContainer.createEl('button', { text: 'Rename' }); const button = buttonContainer.createEl('button', { text: 'Rename' });
button.classList.add('mod-warning', 'fn-confirmation-modal-button'); button.classList.add('mod-warning', 'fn-confirmation-modal-button');
button.addEventListener('click', async () => { button.addEventListener('click', () => {
this.plugin.saveSettings(); void this.plugin.saveSettings();
this.close(); this.close();
turnIntoFolderNote(this.plugin, this.file, this.folder, this.folderNote, true); turnIntoFolderNote(this.plugin, this.file, this.folder, this.folderNote, true);
}); });
button.focus(); button.focus();
const cancelButton = buttonContainer.createEl('button', { text: 'Cancel' }); const cancelButton = buttonContainer.createEl('button', { text: 'Cancel' });
cancelButton.addEventListener('click', async () => { cancelButton.addEventListener('click', () => {
this.close(); this.close();
}); });

View file

@ -17,7 +17,7 @@ export async function renderExcludeFolders(settingsTab: SettingsTab): Promise<vo
.setHeading() .setHeading()
.setClass('fn-excluded-folder-heading') .setClass('fn-excluded-folder-heading')
.setName('Manage excluded folders'); .setName('Manage excluded folders');
const desc3 = document.createDocumentFragment(); const desc3 = activeDocument.createDocumentFragment();
desc3.append( desc3.append(
'Add {regex} at the beginning of the folder name to use a regex pattern.', 'Add {regex} at the beginning of the folder name to use a regex pattern.',
desc3.createEl('br'), desc3.createEl('br'),
@ -28,12 +28,12 @@ export async function renderExcludeFolders(settingsTab: SettingsTab): Promise<vo
'Use * after the folder name to exclude folders that start with the folder name.', 'Use * after the folder name to exclude folders that start with the folder name.',
); );
manageExcluded.setDesc(desc3); manageExcluded.setDesc(desc3);
// eslint-disable-next-line max-len
manageExcluded.infoEl.appendText('The regexes and wildcards are only for the folder name, not the path.'); manageExcluded.infoEl.appendText('The regexes and wildcards are only for the folder name, not the path.');
manageExcluded.infoEl.createEl('br'); manageExcluded.infoEl.createEl('br');
// eslint-disable-next-line max-len
manageExcluded.infoEl.appendText('If you want to switch to a folder path delete the pattern first.'); manageExcluded.infoEl.appendText('If you want to switch to a folder path delete the pattern first.');
// eslint-disable-next-line max-len
manageExcluded.infoEl.style.color = settingsTab.app.vault.getConfig('accentColor') as string || '#7d5bed'; manageExcluded.infoEl.style.color = settingsTab.app.vault.getConfig('accentColor') as string || '#7d5bed';

View file

@ -14,9 +14,9 @@ export async function renderFileExplorer(settingsTab: SettingsTab): Promise<void
settingsTab.plugin.settings.hideFolderNote = value; settingsTab.plugin.settings.hideFolderNote = value;
await settingsTab.plugin.saveSettings(); await settingsTab.plugin.saveSettings();
if (value) { if (value) {
document.body.classList.add('hide-folder-note'); activeDocument.body.classList.add('hide-folder-note');
} else { } else {
document.body.classList.remove('hide-folder-note'); activeDocument.body.classList.remove('hide-folder-note');
} }
settingsTab.display(); settingsTab.display();
}), }),
@ -46,9 +46,9 @@ export async function renderFileExplorer(settingsTab: SettingsTab): Promise<void
.setValue(!settingsTab.plugin.settings.stopWhitespaceCollapsing) .setValue(!settingsTab.plugin.settings.stopWhitespaceCollapsing)
.onChange(async (value) => { .onChange(async (value) => {
if (!value) { if (!value) {
document.body.classList.add('fn-whitespace-stop-collapsing'); activeDocument.body.classList.add('fn-whitespace-stop-collapsing');
} else { } else {
document.body.classList.remove('fn-whitespace-stop-collapsing'); activeDocument.body.classList.remove('fn-whitespace-stop-collapsing');
} }
settingsTab.plugin.settings.stopWhitespaceCollapsing = !value; settingsTab.plugin.settings.stopWhitespaceCollapsing = !value;
await settingsTab.plugin.saveSettings(); await settingsTab.plugin.saveSettings();
@ -119,9 +119,9 @@ export async function renderFileExplorer(settingsTab: SettingsTab): Promise<void
.onChange(async (value) => { .onChange(async (value) => {
settingsTab.plugin.settings.highlightFolder = value; settingsTab.plugin.settings.highlightFolder = value;
if (!value) { if (!value) {
document.body.classList.add('disable-folder-highlight'); activeDocument.body.classList.add('disable-folder-highlight');
} else { } else {
document.body.classList.remove('disable-folder-highlight'); activeDocument.body.classList.remove('disable-folder-highlight');
} }
await settingsTab.plugin.saveSettings(); await settingsTab.plugin.saveSettings();
}), }),
@ -136,9 +136,9 @@ export async function renderFileExplorer(settingsTab: SettingsTab): Promise<void
.onChange(async (value) => { .onChange(async (value) => {
settingsTab.plugin.settings.hideCollapsingIcon = value; settingsTab.plugin.settings.hideCollapsingIcon = value;
if (value) { if (value) {
document.body.classList.add('fn-hide-collapse-icon'); activeDocument.body.classList.add('fn-hide-collapse-icon');
} else { } else {
document.body.classList.remove('fn-hide-collapse-icon'); activeDocument.body.classList.remove('fn-hide-collapse-icon');
} }
await settingsTab.plugin.saveSettings(); await settingsTab.plugin.saveSettings();
settingsTab.display(); settingsTab.display();
@ -155,9 +155,9 @@ export async function renderFileExplorer(settingsTab: SettingsTab): Promise<void
settingsTab.plugin.settings.hideCollapsingIconForEmptyFolders = value; settingsTab.plugin.settings.hideCollapsingIconForEmptyFolders = value;
await settingsTab.plugin.saveSettings(); await settingsTab.plugin.saveSettings();
if (value) { if (value) {
document.body.classList.add('fn-hide-empty-collapse-icon'); activeDocument.body.classList.add('fn-hide-empty-collapse-icon');
} else { } else {
document.body.classList.remove('fn-hide-empty-collapse-icon'); activeDocument.body.classList.remove('fn-hide-empty-collapse-icon');
} }
settingsTab.display(); settingsTab.display();
}, },
@ -171,9 +171,9 @@ export async function renderFileExplorer(settingsTab: SettingsTab): Promise<void
.setValue(settingsTab.plugin.settings.ignoreAttachmentFolder) .setValue(settingsTab.plugin.settings.ignoreAttachmentFolder)
.onChange(async (value) => { .onChange(async (value) => {
if (value) { if (value) {
document.body.classList.add('fn-ignore-attachment-folder'); activeDocument.body.classList.add('fn-ignore-attachment-folder');
} else { } else {
document.body.classList.remove('fn-ignore-attachment-folder'); activeDocument.body.classList.remove('fn-ignore-attachment-folder');
} }
settingsTab.plugin.settings.ignoreAttachmentFolder = value; settingsTab.plugin.settings.ignoreAttachmentFolder = value;
await settingsTab.plugin.saveSettings(); await settingsTab.plugin.saveSettings();
@ -190,9 +190,9 @@ export async function renderFileExplorer(settingsTab: SettingsTab): Promise<void
.onChange(async (value) => { .onChange(async (value) => {
settingsTab.plugin.settings.underlineFolder = value; settingsTab.plugin.settings.underlineFolder = value;
if (value) { if (value) {
document.body.classList.add('folder-note-underline'); activeDocument.body.classList.add('folder-note-underline');
} else { } else {
document.body.classList.remove('folder-note-underline'); activeDocument.body.classList.remove('folder-note-underline');
} }
await settingsTab.plugin.saveSettings(); await settingsTab.plugin.saveSettings();
}), }),
@ -207,9 +207,9 @@ export async function renderFileExplorer(settingsTab: SettingsTab): Promise<void
.onChange(async (value) => { .onChange(async (value) => {
settingsTab.plugin.settings.boldName = value; settingsTab.plugin.settings.boldName = value;
if (value) { if (value) {
document.body.classList.add('folder-note-bold'); activeDocument.body.classList.add('folder-note-bold');
} else { } else {
document.body.classList.remove('folder-note-bold'); activeDocument.body.classList.remove('folder-note-bold');
} }
await settingsTab.plugin.saveSettings(); await settingsTab.plugin.saveSettings();
}), }),
@ -224,9 +224,9 @@ export async function renderFileExplorer(settingsTab: SettingsTab): Promise<void
.onChange(async (value) => { .onChange(async (value) => {
settingsTab.plugin.settings.cursiveName = value; settingsTab.plugin.settings.cursiveName = value;
if (value) { if (value) {
document.body.classList.add('folder-note-cursive'); activeDocument.body.classList.add('folder-note-cursive');
} else { } else {
document.body.classList.remove('folder-note-cursive'); activeDocument.body.classList.remove('folder-note-cursive');
} }
await settingsTab.plugin.saveSettings(); await settingsTab.plugin.saveSettings();
}), }),

View file

@ -36,11 +36,12 @@ export async function renderFolderOverview(settingsTab: SettingsTab): Promise<vo
span.setAttr('style', `color: ${accentColor};`); span.setAttr('style', `color: ${accentColor};`);
pEl.appendChild(span); pEl.appendChild(span);
createOverviewSettings( void createOverviewSettings(
containerEl, containerEl,
defaultOverviewSettings, defaultOverviewSettings,
plugin, plugin,
plugin.settings.defaultOverview, plugin.settings.defaultOverview,
// eslint-disable-next-line @typescript-eslint/unbound-method
settingsTab.display, settingsTab.display,
undefined, undefined,
undefined, undefined,

View file

@ -1,3 +1,4 @@
/* eslint-disable @typescript-eslint/unbound-method */
/* eslint-disable max-len */ /* eslint-disable max-len */
import { Setting, Platform } from 'obsidian'; import { Setting, Platform } from 'obsidian';
import type { SettingsTab } from './SettingsTab'; import type { SettingsTab } from './SettingsTab';
@ -10,7 +11,7 @@ import { refreshAllFolderStyles } from '../functions/styleFunctions';
import BackupWarningModal from './modals/BackupWarning'; import BackupWarningModal from './modals/BackupWarning';
import RenameFolderNotesModal from './modals/RenameFns'; import RenameFolderNotesModal from './modals/RenameFns';
let debounceTimer: NodeJS.Timeout; let debounceTimer: ReturnType<typeof setTimeout>;
// eslint-disable-next-line complexity // eslint-disable-next-line complexity
export async function renderGeneral(settingsTab: SettingsTab): Promise<void> { export async function renderGeneral(settingsTab: SettingsTab): Promise<void> {
@ -26,9 +27,9 @@ export async function renderGeneral(settingsTab: SettingsTab): Promise<void> {
settingsTab.plugin.settings.folderNoteName = value; settingsTab.plugin.settings.folderNoteName = value;
await settingsTab.plugin.saveSettings(); await settingsTab.plugin.saveSettings();
clearTimeout(debounceTimer); window.clearTimeout(debounceTimer);
const FOLDER_NOTE_NAME_DEBOUNCE_MS = 2000; const FOLDER_NOTE_NAME_DEBOUNCE_MS = 2000;
debounceTimer = setTimeout(() => { debounceTimer = window.setTimeout(() => {
if (!value.includes('{{folder_name}}')) { if (!value.includes('{{folder_name}}')) {
if (!settingsTab.showFolderNameInTabTitleSetting) { if (!settingsTab.showFolderNameInTabTitleSetting) {
settingsTab.display(); settingsTab.display();
@ -62,8 +63,8 @@ export async function renderGeneral(settingsTab: SettingsTab): Promise<void> {
if (!settingsTab.plugin.settings.folderNoteName.includes('{{folder_name}}')) { if (!settingsTab.plugin.settings.folderNoteName.includes('{{folder_name}}')) {
new Setting(containerEl) new Setting(containerEl)
.setName('Display Folder Name in Tab Title') .setName('Display folder name in tab title')
.setDesc('Use the actual folder name in the tab title instead of the custom folder note name (e.g., "Folder Note").') .setDesc('Use the actual folder name in the tab title instead of the custom folder note name (e.g., "folder note").')
.addToggle((toggle) => .addToggle((toggle) =>
toggle toggle
.setValue(settingsTab.plugin.settings.tabManagerEnabled) .setValue(settingsTab.plugin.settings.tabManagerEnabled)
@ -83,12 +84,12 @@ export async function renderGeneral(settingsTab: SettingsTab): Promise<void> {
new Setting(containerEl) new Setting(containerEl)
.setName('Default file type for new folder notes') .setName('Default file type for new folder notes')
.setDesc('Choose the default file type (canvas, markdown, ...) used when creating new folder notes.') .setDesc('Choose the default file type (canvas, Markdown, ...) used when creating new folder notes.')
.addDropdown((dropdown) => { .addDropdown((dropdown) => {
dropdown.addOption('.ask', 'ask for file type'); dropdown.addOption('.ask', 'Ask for file type');
settingsTab.plugin.settings.supportedFileTypes.forEach((type) => { settingsTab.plugin.settings.supportedFileTypes.forEach((type) => {
if (type === '.md' || type === 'md') { if (type === '.md' || type === 'md') {
dropdown.addOption('.md', 'markdown'); dropdown.addOption('.md', 'Markdown');
} else { } else {
dropdown.addOption('.' + type, type); dropdown.addOption('.' + type, type);
} }
@ -101,7 +102,7 @@ export async function renderGeneral(settingsTab: SettingsTab): Promise<void> {
settingsTab.plugin.settings.folderNoteType !== '.ask' settingsTab.plugin.settings.folderNoteType !== '.ask'
) { ) {
settingsTab.plugin.settings.folderNoteType = '.md'; settingsTab.plugin.settings.folderNoteType = '.md';
settingsTab.plugin.saveSettings(); void settingsTab.plugin.saveSettings();
} }
let defaultType = settingsTab.plugin.settings.folderNoteType.startsWith('.') let defaultType = settingsTab.plugin.settings.folderNoteType.startsWith('.')
@ -118,16 +119,16 @@ export async function renderGeneral(settingsTab: SettingsTab): Promise<void> {
dropdown dropdown
.setValue(defaultType) .setValue(defaultType)
.onChange(async (value: '.md' | '.canvas') => { .onChange(async (value: string) => {
settingsTab.plugin.settings.folderNoteType = value; settingsTab.plugin.settings.folderNoteType = value as '.md' | '.canvas' | '.ask';
settingsTab.plugin.saveSettings(); void settingsTab.plugin.saveSettings();
settingsTab.display(); void settingsTab.display();
}); });
}); });
const setting0 = new Setting(containerEl); const setting0 = new Setting(containerEl);
setting0.setName('Supported file types'); setting0.setName('Supported file types');
const desc0 = document.createDocumentFragment(); const desc0 = activeDocument.createDocumentFragment();
desc0.append( desc0.append(
'Specify which file types are allowed as folder notes. Applies to both new and existing folders. Adding many types may affect performance.', 'Specify which file types are allowed as folder notes. Applies to both new and existing folders. Adding many types may affect performance.',
); );
@ -137,10 +138,10 @@ export async function renderGeneral(settingsTab: SettingsTab): Promise<void> {
settingsTab.plugin.settings.supportedFileTypes || [], settingsTab.plugin.settings.supportedFileTypes || [],
['md', 'canvas'], ['md', 'canvas'],
); );
list.on('update', async (values: string[]) => { list.on('update', (values: unknown) => {
settingsTab.plugin.settings.supportedFileTypes = values; settingsTab.plugin.settings.supportedFileTypes = values as string[];
await settingsTab.plugin.saveSettings(); void settingsTab.plugin.saveSettings();
settingsTab.display(); void settingsTab.display();
}); });
if ( if (
@ -170,12 +171,12 @@ export async function renderGeneral(settingsTab: SettingsTab): Promise<void> {
settingsTab.app, settingsTab.app,
settingsTab.plugin, settingsTab.plugin,
settingsTab, settingsTab,
list as ListComponent, list,
).open(); ).open();
} }
await list.addValue(value.toLowerCase()); await list.addValue(value.toLowerCase());
settingsTab.display(); void settingsTab.display();
settingsTab.plugin.saveSettings(); void settingsTab.plugin.saveSettings();
}); });
}); });
} else { } else {
@ -188,7 +189,7 @@ export async function renderGeneral(settingsTab: SettingsTab): Promise<void> {
settingsTab.app, settingsTab.app,
settingsTab.plugin, settingsTab.plugin,
settingsTab, settingsTab,
list as ListComponent, list,
).open(); ).open();
}), }),
); );
@ -226,7 +227,10 @@ export async function renderGeneral(settingsTab: SettingsTab): Promise<void> {
.addOption('insideFolder', 'Inside the folder') .addOption('insideFolder', 'Inside the folder')
.addOption('parentFolder', 'In the parent folder') .addOption('parentFolder', 'In the parent folder')
.setValue(settingsTab.plugin.settings.storageLocation) .setValue(settingsTab.plugin.settings.storageLocation)
.onChange(async (value: 'insideFolder' | 'parentFolder' | 'vaultFolder') => { .onChange(async (value: string) => {
if (value !== 'insideFolder' && value !== 'parentFolder' && value !== 'vaultFolder') {
return;
}
settingsTab.plugin.settings.storageLocation = value; settingsTab.plugin.settings.storageLocation = value;
await settingsTab.plugin.saveSettings(); await settingsTab.plugin.saveSettings();
settingsTab.display(); settingsTab.display();
@ -282,7 +286,7 @@ export async function renderGeneral(settingsTab: SettingsTab): Promise<void> {
); );
} }
if (Platform.isDesktopApp) { if (Platform.isDesktopApp) {
settingsTab.settingsPage.createEl('h3', { text: 'Keyboard Shortcuts' }); settingsTab.settingsPage.createEl('h3', { text: 'Keyboard shortcuts' });
new Setting(containerEl) new Setting(containerEl)
.setName('Key for creating folder note') .setName('Key for creating folder note')
@ -308,7 +312,7 @@ export async function renderGeneral(settingsTab: SettingsTab): Promise<void> {
.setName('Key for opening folder note') .setName('Key for opening folder note')
.setDesc('Select the combination to open a folder note') .setDesc('Select the combination to open a folder note')
.addDropdown((dropdown) => { .addDropdown((dropdown) => {
dropdown.addOption('click', 'Mouse Click'); dropdown.addOption('click', 'Mouse click');
if (!Platform.isMacOS) { if (!Platform.isMacOS) {
dropdown.addOption('ctrl', 'Ctrl + Click'); dropdown.addOption('ctrl', 'Ctrl + Click');
dropdown.addOption('alt', 'Alt + Click'); dropdown.addOption('alt', 'Alt + Click');
@ -356,8 +360,9 @@ export async function renderGeneral(settingsTab: SettingsTab): Promise<void> {
dropdown.addOption('obsidianTrash', 'Move to Obsidian trash (.trash folder)'); dropdown.addOption('obsidianTrash', 'Move to Obsidian trash (.trash folder)');
dropdown.addOption('delete', 'Delete permanently'); dropdown.addOption('delete', 'Delete permanently');
dropdown.setValue(settingsTab.plugin.settings.deleteFilesAction); dropdown.setValue(settingsTab.plugin.settings.deleteFilesAction);
dropdown.onChange(async (value: 'trash' | 'delete' | 'obsidianTrash') => { dropdown.onChange(async (value) => {
settingsTab.plugin.settings.deleteFilesAction = value; const v = value as 'trash' | 'delete' | 'obsidianTrash';
settingsTab.plugin.settings.deleteFilesAction = v;
await settingsTab.plugin.saveSettings(); await settingsTab.plugin.saveSettings();
settingsTab.display(); settingsTab.display();
}); });
@ -450,7 +455,7 @@ export async function renderGeneral(settingsTab: SettingsTab): Promise<void> {
new Setting(containerEl) new Setting(containerEl)
.setName('Auto-create for attachment folders') .setName('Auto-create for attachment folders')
.setDesc('Also automatically create folder notes for attachment folders (e.g., "Attachments", "Media", etc.).') .setDesc('Also automatically create folder notes for attachment folders (e.g., "attachments", "media", etc.).')
.addToggle((toggle) => .addToggle((toggle) =>
toggle toggle
.setValue(settingsTab.plugin.settings.autoCreateForAttachmentFolder) .setValue(settingsTab.plugin.settings.autoCreateForAttachmentFolder)
@ -475,13 +480,13 @@ export async function renderGeneral(settingsTab: SettingsTab): Promise<void> {
}), }),
); );
settingsTab.settingsPage.createEl('h3', { text: 'Integration & Compatibility' }); settingsTab.settingsPage.createEl('h3', { text: 'Integration & compatibility' });
const desc1 = document.createDocumentFragment(); const desc1 = activeDocument.createDocumentFragment();
const link = document.createElement('a'); const link = activeDocument.createElement('a');
link.href = 'https://github.com/snezhig/obsidian-front-matter-title'; link.href = 'https://github.com/snezhig/obsidian-front-matter-title';
link.textContent = 'front matter title plugin'; link.textContent = 'Front matter title plugin';
link.target = '_blank'; link.target = '_blank';
desc1.append( desc1.append(
@ -507,7 +512,7 @@ export async function renderGeneral(settingsTab: SettingsTab): Promise<void> {
settingsTab.plugin.updateAllBreadcrumbs(true); settingsTab.plugin.updateAllBreadcrumbs(true);
} }
settingsTab.plugin.app.vault.getFiles().forEach((file) => { settingsTab.plugin.app.vault.getFiles().forEach((file) => {
settingsTab.plugin.fmtpHandler?.fmptUpdateFileName( void settingsTab.plugin.fmtpHandler?.fmptUpdateFileName(
{ {
id: '', id: '',
result: false, result: false,
@ -527,7 +532,7 @@ export async function renderGeneral(settingsTab: SettingsTab): Promise<void> {
fmtpSetting.infoEl.appendText('Requires a restart to take effect'); fmtpSetting.infoEl.appendText('Requires a restart to take effect');
fmtpSetting.infoEl.style.color = settingsTab.app.vault.getConfig('accentColor') as string || '#7d5bed'; fmtpSetting.infoEl.style.color = settingsTab.app.vault.getConfig('accentColor') as string || '#7d5bed';
settingsTab.settingsPage.createEl('h3', { text: 'Session & Persistence' }); settingsTab.settingsPage.createEl('h3', { text: 'Session & persistence' });
new Setting(containerEl) new Setting(containerEl)
.setName('Persist tab after restart') .setName('Persist tab after restart')

View file

@ -18,7 +18,7 @@ export async function renderPath(settingsTab: SettingsTab): Promise<void> {
if (settingsTab.plugin.settings.openFolderNoteOnClickInPath) { if (settingsTab.plugin.settings.openFolderNoteOnClickInPath) {
new Setting(containerEl) new Setting(containerEl)
.setName('Open sidebar when opening a folder note through path (Mobile only)') .setName('Open sidebar when opening a folder note through path (mobile only)')
.setDesc('Open the sidebar when opening a folder note through the path on mobile') .setDesc('Open the sidebar when opening a folder note through the path on mobile')
.addToggle((toggle) => .addToggle((toggle) =>
toggle toggle
@ -30,7 +30,7 @@ export async function renderPath(settingsTab: SettingsTab): Promise<void> {
); );
new Setting(containerEl) new Setting(containerEl)
.setName('Open sidebar when opening a folder note through path (Desktop only)') .setName('Open sidebar when opening a folder note through path (desktop only)')
.setDesc('Open the sidebar when opening a folder note through the path on desktop') .setDesc('Open the sidebar when opening a folder note through the path on desktop')
.addToggle((toggle) => .addToggle((toggle) =>
toggle toggle
@ -72,9 +72,9 @@ export async function renderPath(settingsTab: SettingsTab): Promise<void> {
.onChange(async (value) => { .onChange(async (value) => {
settingsTab.plugin.settings.underlineFolderInPath = value; settingsTab.plugin.settings.underlineFolderInPath = value;
if (value) { if (value) {
document.body.classList.add('folder-note-underline-path'); activeDocument.body.classList.add('folder-note-underline-path');
} else { } else {
document.body.classList.remove('folder-note-underline-path'); activeDocument.body.classList.remove('folder-note-underline-path');
} }
await settingsTab.plugin.saveSettings(); await settingsTab.plugin.saveSettings();
}), }),
@ -89,9 +89,9 @@ export async function renderPath(settingsTab: SettingsTab): Promise<void> {
.onChange(async (value) => { .onChange(async (value) => {
settingsTab.plugin.settings.boldNameInPath = value; settingsTab.plugin.settings.boldNameInPath = value;
if (value) { if (value) {
document.body.classList.add('folder-note-bold-path'); activeDocument.body.classList.add('folder-note-bold-path');
} else { } else {
document.body.classList.remove('folder-note-bold-path'); activeDocument.body.classList.remove('folder-note-bold-path');
} }
await settingsTab.plugin.saveSettings(); await settingsTab.plugin.saveSettings();
}), }),
@ -106,9 +106,9 @@ export async function renderPath(settingsTab: SettingsTab): Promise<void> {
.onChange(async (value) => { .onChange(async (value) => {
settingsTab.plugin.settings.cursiveNameInPath = value; settingsTab.plugin.settings.cursiveNameInPath = value;
if (value) { if (value) {
document.body.classList.add('folder-note-cursive-path'); activeDocument.body.classList.add('folder-note-cursive-path');
} else { } else {
document.body.classList.remove('folder-note-cursive-path'); activeDocument.body.classList.remove('folder-note-cursive-path');
} }
await settingsTab.plugin.saveSettings(); await settingsTab.plugin.saveSettings();
}), }),
@ -121,7 +121,7 @@ export async function renderPath(settingsTab: SettingsTab): Promise<void> {
toggle toggle
.setValue(settingsTab.plugin.settings.hideFolderNoteNameInPath) .setValue(settingsTab.plugin.settings.hideFolderNoteNameInPath)
.onChange(async (value) => { .onChange(async (value) => {
document.body.classList.toggle('folder-note-hide-name-path', value); activeDocument.body.classList.toggle('folder-note-hide-name-path', value);
settingsTab.plugin.settings.hideFolderNoteNameInPath = value; settingsTab.plugin.settings.hideFolderNoteNameInPath = value;
await settingsTab.plugin.saveSettings(); await settingsTab.plugin.saveSettings();
}), }),

View file

@ -211,11 +211,11 @@ export const DEFAULT_SETTINGS: FolderNotesSettings = {
}; };
export class SettingsTab extends PluginSettingTab { export class SettingsTab extends PluginSettingTab {
plugin: FolderNotesPlugin; plugin!: FolderNotesPlugin;
app: App; app!: App;
excludeFolders: ExcludedFolder[]; excludeFolders!: ExcludedFolder[];
settingsPage!: HTMLElement; settingsPage!: HTMLElement;
showFolderNameInTabTitleSetting: boolean; showFolderNameInTabTitleSetting!: boolean;
constructor(app: App, plugin: FolderNotesPlugin) { constructor(app: App, plugin: FolderNotesPlugin) {
super(app, plugin); super(app, plugin);
} }
@ -246,19 +246,19 @@ export class SettingsTab extends PluginSettingTab {
this.settingsPage.empty(); this.settingsPage.empty();
switch (tabId.toLocaleLowerCase()) { switch (tabId.toLocaleLowerCase()) {
case this.TABS.GENERAL.id: case this.TABS.GENERAL.id:
renderGeneral(this); void renderGeneral(this);
break; break;
case this.TABS.FOLDER_OVERVIEW.id: case this.TABS.FOLDER_OVERVIEW.id:
renderFolderOverview(this); void renderFolderOverview(this);
break; break;
case this.TABS.EXCLUDE_FOLDERS.id: case this.TABS.EXCLUDE_FOLDERS.id:
renderExcludeFolders(this); void renderExcludeFolders(this);
break; break;
case this.TABS.FILE_EXPLORER.id: case this.TABS.FILE_EXPLORER.id:
renderFileExplorer(this); void renderFileExplorer(this);
break; break;
case this.TABS.PATH.id: case this.TABS.PATH.id:
renderPath(this); void renderPath(this);
break; break;
} }
} }
@ -298,12 +298,11 @@ export class SettingsTab extends PluginSettingTab {
tabEl.addClass('fn-settings-tab-active'); tabEl.addClass('fn-settings-tab-active');
} }
tabEl.addEventListener('click', () => { tabEl.addEventListener('click', () => {
// @ts-expect-error: tabBar.children may not have removeClass method, but we know it works in this context
for (const child of tabBar.children) { for (const child of tabBar.children) {
child.removeClass('fn-settings-tab-active'); (child as HTMLElement).classList.remove('fn-settings-tab-active');
if (!plugin) { return; } if (!plugin) { return; }
plugin.settings.settingsTab = tabId.toLocaleLowerCase(); plugin.settings.settingsTab = tabId.toLocaleLowerCase();
plugin.saveSettings(); void plugin.saveSettings();
} }
tabEl.addClass('fn-settings-tab-active'); tabEl.addClass('fn-settings-tab-active');
if (!settingsTab) { return; } if (!settingsTab) { return; }
@ -344,19 +343,19 @@ export class SettingsTab extends PluginSettingTab {
if (getFolderPathFromString(folder.path).trim() === '/') { if (getFolderPathFromString(folder.path).trim() === '/') {
newPath = `${newFolderNoteName}.${folderNote.extension}`; newPath = `${newFolderNoteName}.${folderNote.extension}`;
} else { } else {
// eslint-disable-next-line max-len
newPath = `${folderNote.parent?.path}/${newFolderNoteName}.${folderNote.extension}`; newPath = `${folderNote.parent?.path}/${newFolderNoteName}.${folderNote.extension}`;
} }
} else if (this.plugin.settings.storageLocation === 'insideFolder') { } else if (this.plugin.settings.storageLocation === 'insideFolder') {
newPath = `${folder.path}/${newFolderNoteName}.${folderNote.extension}`; newPath = `${folder.path}/${newFolderNoteName}.${folderNote.extension}`;
} }
this.app.fileManager.renameFile(folderNote, newPath); void this.app.fileManager.renameFile(folderNote, newPath);
} }
} }
this.plugin.settings.oldFolderNoteName = this.plugin.settings.folderNoteName; this.plugin.settings.oldFolderNoteName = this.plugin.settings.folderNoteName;
this.plugin.saveSettings(); void this.plugin.saveSettings();
new Notice('Finished updating folder notes'); new Notice('Finished updating folder notes');
} }
@ -373,13 +372,13 @@ export class SettingsTab extends PluginSettingTab {
} else { } else {
newPath = `${getFolderPathFromString(file.path)}/${folderNote.name}`; newPath = `${getFolderPathFromString(file.path)}/${folderNote.name}`;
} }
this.plugin.app.fileManager.renameFile(folderNote, newPath); void this.plugin.app.fileManager.renameFile(folderNote, newPath);
} else if (this.plugin.settings.storageLocation === 'insideFolder') { } else if (this.plugin.settings.storageLocation === 'insideFolder') {
if (getFolderPathFromString(folderNote.path) === file.path) { if (getFolderPathFromString(folderNote.path) === file.path) {
return; return;
} }
const newPath = `${file.path}/${folderNote.name}`; const newPath = `${file.path}/${folderNote.name}`;
this.plugin.app.fileManager.renameFile(folderNote, newPath); void this.plugin.app.fileManager.renameFile(folderNote, newPath);
} }
} }

View file

@ -32,7 +32,7 @@ export default class BackupWarningModal extends Modal {
contentEl.createEl('p', { text: this.desc }); contentEl.createEl('p', { text: this.desc });
// eslint-disable-next-line max-len // eslint-disable-next-line max-len
contentEl.createEl('p', { text: 'Make sure to backup your vault before using this feature.' }).style.color = '#fb464c'; contentEl.createEl('p', { text: 'Make sure to backup your vault before using this feature.' }).addClass('fn-warning-text');
const buttonContainer = contentEl.createDiv({ cls: 'fn-modal-button-container' }); const buttonContainer = contentEl.createDiv({ cls: 'fn-modal-button-container' });
const confirmButton = new ButtonComponent(buttonContainer); const confirmButton = new ButtonComponent(buttonContainer);

View file

@ -6,7 +6,7 @@ import { getExcludedFolder } from 'src/ExcludeFolders/functions/folderFunctions'
export default class ConfirmationModal extends Modal { export default class ConfirmationModal extends Modal {
plugin: FolderNotesPlugin; plugin: FolderNotesPlugin;
app: App; app: App;
folder: TFolder; folder!: TFolder;
extension: string; extension: string;
constructor(app: App, plugin: FolderNotesPlugin) { constructor(app: App, plugin: FolderNotesPlugin) {
super(app); super(app);
@ -36,7 +36,7 @@ export default class ConfirmationModal extends Modal {
contentEl.createEl('h2', { text: 'Create folder note for every folder' }); contentEl.createEl('h2', { text: 'Create folder note for every folder' });
const setting = new Setting(contentEl); const setting = new Setting(contentEl);
// eslint-disable-next-line max-len // eslint-disable-next-line max-len
setting.infoEl.createEl('p', { text: 'Make sure to backup your vault before using this feature.' }).style.color = '#fb464c'; setting.infoEl.createEl('p', { text: 'Make sure to backup your vault before using this feature.' }).addClass('fn-warning-text');
// eslint-disable-next-line max-len // eslint-disable-next-line max-len
setting.infoEl.createEl('p', { text: 'This feature will create a folder note for every folder in your vault.' }); setting.infoEl.createEl('p', { text: 'This feature will create a folder note for every folder in your vault.' });
// eslint-disable-next-line max-len // eslint-disable-next-line max-len

View file

@ -16,8 +16,7 @@ export default class RenameFolderNotesModal extends BackupWarningModal {
insertCustomHtml(): void { insertCustomHtml(): void {
const { contentEl } = this; const { contentEl } = this;
new Setting(contentEl) new Setting(contentEl)
.setName('Old Folder Note Name') .setName('Old folder note name')
// eslint-disable-next-line max-len
.setDesc('Every folder note that matches this name will be renamed to the new folder note name.') .setDesc('Every folder note that matches this name will be renamed to the new folder note name.')
.addText((text) => text .addText((text) => text
.setPlaceholder('Enter the old folder note name') .setPlaceholder('Enter the old folder note name')
@ -28,8 +27,7 @@ export default class RenameFolderNotesModal extends BackupWarningModal {
); );
new Setting(contentEl) new Setting(contentEl)
.setName('New Folder Note Name') .setName('New folder note name')
// eslint-disable-next-line max-len
.setDesc('Every folder note that matches the old folder note name will be renamed to this name.') .setDesc('Every folder note that matches the old folder note name will be renamed to this name.')
.addText((text) => text .addText((text) => text
.setPlaceholder('Enter the new folder note name') .setPlaceholder('Enter the new folder note name')

View file

@ -1,17 +1,19 @@
import { type TAbstractFile, TFile } from 'obsidian'; import { AbstractInputSuggest, type TAbstractFile, TFile } from 'obsidian';
import { TextInputSuggest } from './Suggest';
import type FolderNotesPlugin from '../main'; import type FolderNotesPlugin from '../main';
export enum FileSuggestMode { export enum FileSuggestMode {
TemplateFiles, TemplateFiles,
ScriptFiles, ScriptFiles,
} }
export class FileSuggest extends TextInputSuggest<TFile> { export class FileSuggest extends AbstractInputSuggest<TFile> {
plugin: FolderNotesPlugin;
constructor( constructor(
public inputEl: HTMLInputElement, public inputEl: HTMLInputElement,
plugin: FolderNotesPlugin, plugin: FolderNotesPlugin,
) { ) {
super(inputEl, plugin); super(plugin.app, inputEl);
this.plugin = plugin;
} }
get_error_msg(mode: FileSuggestMode): string { get_error_msg(mode: FileSuggestMode): string {

View file

@ -1,21 +1,23 @@
// Credits go to Liam's Periodic Notes Plugin: https://github.com/liamcain/obsidian-periodic-notes and https://github.com/SilentVoid13/Templater // Credits go to Liam's Periodic Notes Plugin: https://github.com/liamcain/obsidian-periodic-notes and https://github.com/SilentVoid13/Templater
import { TFolder, type TAbstractFile } from 'obsidian'; import { AbstractInputSuggest, TFolder, type TAbstractFile } from 'obsidian';
import { TextInputSuggest } from './Suggest';
import type FolderNotesPlugin from '../main'; import type FolderNotesPlugin from '../main';
export enum FileSuggestMode { export enum FileSuggestMode {
TemplateFiles, TemplateFiles,
ScriptFiles, ScriptFiles,
} }
export class FolderSuggest extends TextInputSuggest<TFolder> { export class FolderSuggest extends AbstractInputSuggest<TFolder> {
plugin: FolderNotesPlugin;
constructor( constructor(
public inputEl: HTMLInputElement, public inputEl: HTMLInputElement,
plugin: FolderNotesPlugin, plugin: FolderNotesPlugin,
private whitelistSuggester: boolean, private whitelistSuggester: boolean,
public folder?: TFolder, public folder?: TFolder,
) { ) {
super(inputEl, plugin); super(plugin.app, inputEl);
this.plugin = plugin;
} }

View file

@ -1,205 +0,0 @@
// Credits go to Liam's Periodic Notes Plugin: https://github.com/liamcain/obsidian-periodic-notes and https://github.com/SilentVoid13/Templater
import { Scope, type ISuggestOwner } from 'obsidian';
import { createPopper, type Instance as PopperInstance } from '@popperjs/core';
import type FolderNotesPlugin from 'src/main';
const wrapAround = (value: number, size: number): number => {
return ((value % size) + size) % size;
};
class Suggest<T> {
private owner: ISuggestOwner<T>;
private values: T[];
private suggestions: HTMLDivElement[];
private selectedItem: number;
private containerEl: HTMLElement;
plugin: FolderNotesPlugin;
constructor(
owner: ISuggestOwner<T>,
containerEl: HTMLElement,
scope: Scope,
) {
this.owner = owner;
this.containerEl = containerEl;
containerEl.on(
'click',
'.suggestion-item',
this.onSuggestionClick.bind(this),
);
containerEl.on(
'mousemove',
'.suggestion-item',
this.onSuggestionMouseover.bind(this),
);
scope.register([], 'ArrowUp', (event) => {
if (!event.isComposing) {
this.setSelectedItem(this.selectedItem - 1, true);
return false;
}
});
scope.register([], 'ArrowDown', (event) => {
if (!event.isComposing) {
this.setSelectedItem(this.selectedItem + 1, true);
return false;
}
});
scope.register([], 'Enter', (event) => {
if (!event.isComposing) {
this.useSelectedItem(event);
return false;
}
});
}
onSuggestionClick(event: MouseEvent, el: HTMLDivElement): void {
event.preventDefault();
const item = this.suggestions.indexOf(el);
this.setSelectedItem(item, false);
this.useSelectedItem(event);
}
onSuggestionMouseover(_event: MouseEvent, el: HTMLDivElement): void {
const item = this.suggestions.indexOf(el);
this.setSelectedItem(item, false);
}
setSuggestions(values: T[]): void {
this.containerEl.empty();
const suggestionEls: HTMLDivElement[] = [];
values.forEach((value) => {
const suggestionEl = this.containerEl.createDiv('suggestion-item');
this.owner.renderSuggestion(value, suggestionEl);
suggestionEls.push(suggestionEl);
});
this.values = values;
this.suggestions = suggestionEls;
this.setSelectedItem(0, false);
}
useSelectedItem(event: MouseEvent | KeyboardEvent): void {
const currentValue = this.values[this.selectedItem];
if (currentValue) {
this.owner.selectSuggestion(currentValue, event);
}
}
setSelectedItem(selectedIndex: number, scrollIntoView: boolean): void {
const normalizedIndex = wrapAround(
selectedIndex,
this.suggestions.length,
);
const prevSelectedSuggestion = this.suggestions[this.selectedItem];
const selectedSuggestion = this.suggestions[normalizedIndex];
prevSelectedSuggestion?.removeClass('is-selected');
selectedSuggestion?.addClass('is-selected');
this.selectedItem = normalizedIndex;
if (scrollIntoView) {
selectedSuggestion.scrollIntoView(false);
}
}
}
export abstract class TextInputSuggest<T> implements ISuggestOwner<T> {
protected inputEl: HTMLInputElement | HTMLTextAreaElement;
private popper: PopperInstance;
private scope: Scope;
private suggestEl: HTMLElement;
private suggest: Suggest<T>;
plugin: FolderNotesPlugin;
constructor(inputEl: HTMLInputElement | HTMLTextAreaElement, plugin: FolderNotesPlugin) {
this.inputEl = inputEl;
this.plugin = plugin;
this.scope = new Scope();
this.suggestEl = createDiv('suggestion-container');
const suggestion = this.suggestEl.createDiv('suggestion');
this.suggest = new Suggest(this, suggestion, this.scope);
this.scope.register([], 'Escape', this.close.bind(this));
this.inputEl.addEventListener('input', this.onInputChanged.bind(this));
this.inputEl.addEventListener('focus', this.onInputChanged.bind(this));
this.inputEl.addEventListener('blur', this.close.bind(this));
this.suggestEl.on(
'mousedown',
'.suggestion-container',
(event: MouseEvent) => {
event.preventDefault();
},
);
}
onInputChanged(): void {
const inputStr = this.inputEl.value;
const suggestions = this.getSuggestions(inputStr);
if (!suggestions) {
this.close();
return;
}
if (suggestions.length > 0) {
this.suggest.setSuggestions(suggestions);
// @ts-expect-error App may not exist
this.open(app.dom.appContainerEl, this.inputEl);
} else {
this.close();
}
}
open(container: HTMLElement, inputEl: HTMLElement): void {
this.plugin.app.keymap.pushScope(this.scope);
container.appendChild(this.suggestEl);
this.popper = createPopper(inputEl, this.suggestEl, {
placement: 'bottom-start',
modifiers: [
{
name: 'sameWidth',
enabled: true,
fn: ({ state, instance }): void => {
// Note: positioning needs to be calculated twice -
// first pass - positioning it according to the width of the popper
// second pass - position it with the width bound to the reference element
// we need to early exit to avoid an infinite loop
const targetWidth = `${state.rects.reference.width}px`;
if (state.styles.popper.width === targetWidth) {
return;
}
state.styles.popper.width = targetWidth;
instance.update();
},
phase: 'beforeWrite',
requires: ['computeStyles'],
},
],
});
}
close(): void {
this.plugin.app.keymap.popScope(this.scope);
this.suggest.setSuggestions([]);
if (this.popper) this.popper.destroy();
this.suggestEl.detach();
}
abstract getSuggestions(inputStr: string): T[];
abstract renderSuggestion(item: T, el: HTMLElement): void;
abstract selectSuggestion(item: T): void;
}

View file

@ -47,13 +47,13 @@ export class TemplateSuggest extends AbstractInputSuggest<TFile> {
{ {
path: '', path: '',
name: name:
// eslint-disable-next-line max-len
'You need to set the Templates folder in the Templater settings first.', 'You need to set the Templates folder in the Templater settings first.',
// eslint-disable-next-line obsidianmd/no-tfile-tfolder-cast
} as TFile, } as TFile,
]; ];
} }
} else if (templateFolder) { } else if (templateFolder) {
folder = this.plugin.app.vault.getAbstractFileByPath(templateFolder) as TFolder; folder = this.plugin.app.vault.getAbstractFileByPath(templateFolder);
} }
if (!(folder instanceof TFolder)) { if (!(folder instanceof TFolder)) {
@ -86,7 +86,7 @@ export class TemplateSuggest extends AbstractInputSuggest<TFile> {
this.inputEl.value = file.name.replace('.md', ''); this.inputEl.value = file.name.replace('.md', '');
this.inputEl.trigger('input'); this.inputEl.trigger('input');
this.plugin.settings.templatePath = file.path; this.plugin.settings.templatePath = file.path;
this.plugin.saveSettings(); void this.plugin.saveSettings();
this.close(); this.close();
} }
} }

View file

@ -55,7 +55,7 @@ export async function applyTemplate(
} = getTemplatePlugins(plugin.app); } = getTemplatePlugins(plugin.app);
const templateContent = await plugin.app.vault.read(templateFile); const templateContent = await plugin.app.vault.read(templateFile);
// eslint-disable-next-line max-len // eslint-disable-next-line max-len
if (templateContent.includes('==⚠ Switch to EXCALIDRAW VIEW in the MORE OPTIONS menu of this document. ⚠==')) { if (templateContent.includes('==⚠ Switch to EXCALIDRAW VIEW in the MORE OPTIONS menu of this activeDocument. ⚠==')) {
return; return;
} }

View file

@ -28,6 +28,10 @@
} }
.fn-warning-text {
color: #fb464c
}
/* ========================================================================== /* ==========================================================================
Tree Items Tree Items
========================================================================== */ ========================================================================== */

View file

@ -3,11 +3,11 @@
"baseUrl": ".", "baseUrl": ".",
"inlineSourceMap": true, "inlineSourceMap": true,
"inlineSources": true, "inlineSources": true,
"module": "ESNext", "module": "node16",
"target": "ES6", "target": "ES6",
"allowJs": true, "allowJs": true,
"noImplicitAny": true, "noImplicitAny": true,
"moduleResolution": "node", "moduleResolution": "node16",
"importHelpers": true, "importHelpers": true,
"isolatedModules": true, "isolatedModules": true,
"strictNullChecks": true, "strictNullChecks": true,
@ -17,7 +17,10 @@
"ES6", "ES6",
"ES7", "ES7",
"ES2021" "ES2021"
] ],
"paths": {
"@app/*": ["./src/*"]
}
}, },
"include": [ "include": [
"**/*.ts" "**/*.ts"

View file

@ -1,3 +1,4 @@
/* eslint-disable no-undef */
import { readFileSync, writeFileSync } from "fs"; import { readFileSync, writeFileSync } from "fs";
const targetVersion = process.env.npm_package_version; const targetVersion = process.env.npm_package_version;