mirror of
https://github.com/lostpaul/obsidian-folder-notes.git
synced 2026-07-22 07:40:24 +00:00
Merge pull request #273 from LostPaul/code-style-changes
Code style changes
This commit is contained in:
commit
68d9b0b8d5
55 changed files with 3908 additions and 2264 deletions
|
|
@ -1,7 +0,0 @@
|
|||
npm node_modules
|
||||
build
|
||||
*.js
|
||||
*.json
|
||||
*.md
|
||||
*.css
|
||||
LICENSE
|
||||
150
.eslintrc
150
.eslintrc
|
|
@ -1,150 +0,0 @@
|
|||
{
|
||||
"root": true,
|
||||
"parser": "@typescript-eslint/parser",
|
||||
"env": {
|
||||
"node": true
|
||||
},
|
||||
"plugins": [
|
||||
"@typescript-eslint"
|
||||
],
|
||||
"extends": [
|
||||
"eslint:recommended",
|
||||
"plugin:@typescript-eslint/eslint-recommended",
|
||||
"plugin:@typescript-eslint/recommended"
|
||||
],
|
||||
"parserOptions": {
|
||||
"sourceType": "module"
|
||||
},
|
||||
"rules": {
|
||||
"no-unused-vars": "off",
|
||||
"@typescript-eslint/no-unused-vars": [
|
||||
"error",
|
||||
{
|
||||
"args": "none"
|
||||
}
|
||||
],
|
||||
"@typescript-eslint/no-explicit-any": "off",
|
||||
"@typescript-eslint/ban-ts-comment": "off",
|
||||
"no-prototype-builtins": "off",
|
||||
"@typescript-eslint/no-empty-function": "off",
|
||||
"brace-style": [
|
||||
"error",
|
||||
"1tbs",
|
||||
{
|
||||
"allowSingleLine": true
|
||||
}
|
||||
],
|
||||
"consistent-return": "off",
|
||||
"quotes": [
|
||||
"error",
|
||||
"single",
|
||||
{
|
||||
"avoidEscape": true
|
||||
}
|
||||
],
|
||||
"@typescript-eslint/ban-types": [
|
||||
"error",
|
||||
{
|
||||
"types": {
|
||||
"Function": false
|
||||
},
|
||||
"extendDefaults": true
|
||||
}
|
||||
],
|
||||
"no-mixed-spaces-and-tabs": "error",
|
||||
"indent": [
|
||||
"error",
|
||||
"tab",
|
||||
{
|
||||
"SwitchCase": 1
|
||||
}
|
||||
],
|
||||
"arrow-parens": [
|
||||
"error",
|
||||
"always"
|
||||
],
|
||||
"eol-last": [
|
||||
"error",
|
||||
"always"
|
||||
],
|
||||
"func-call-spacing": [
|
||||
"error",
|
||||
"never"
|
||||
],
|
||||
"comma-dangle": [
|
||||
"error",
|
||||
"always-multiline"
|
||||
],
|
||||
"no-multi-spaces": "error",
|
||||
"no-trailing-spaces": "error",
|
||||
"no-whitespace-before-property": "off",
|
||||
"semi": [
|
||||
"error",
|
||||
"always"
|
||||
],
|
||||
"semi-style": [
|
||||
"error",
|
||||
"last"
|
||||
],
|
||||
"space-in-parens": [
|
||||
"error",
|
||||
"never"
|
||||
],
|
||||
"block-spacing": [
|
||||
"error",
|
||||
"always"
|
||||
],
|
||||
"object-curly-spacing": [
|
||||
"error",
|
||||
"always"
|
||||
],
|
||||
"eqeqeq": [
|
||||
"error",
|
||||
"always",
|
||||
{
|
||||
"null": "ignore"
|
||||
}
|
||||
],
|
||||
"spaced-comment": [
|
||||
"error",
|
||||
"always",
|
||||
{
|
||||
"markers": [
|
||||
"!"
|
||||
]
|
||||
}
|
||||
],
|
||||
"yoda": "error",
|
||||
"prefer-destructuring": [
|
||||
"error",
|
||||
{
|
||||
"object": false,
|
||||
"array": false
|
||||
}
|
||||
],
|
||||
"operator-assignment": [
|
||||
"error",
|
||||
"always"
|
||||
],
|
||||
"no-useless-computed-key": "error",
|
||||
"no-unneeded-ternary": [
|
||||
"error",
|
||||
{
|
||||
"defaultAssignment": false
|
||||
}
|
||||
],
|
||||
"no-invalid-regexp": "error",
|
||||
"no-constant-condition": [
|
||||
"error",
|
||||
{
|
||||
"checkLoops": false
|
||||
}
|
||||
],
|
||||
"no-duplicate-imports": "error",
|
||||
"no-extra-semi": "error",
|
||||
"dot-notation": "error",
|
||||
"no-useless-escape": [
|
||||
"error"
|
||||
]
|
||||
}
|
||||
}
|
||||
163
eslint.config.mts
Normal file
163
eslint.config.mts
Normal file
|
|
@ -0,0 +1,163 @@
|
|||
import tseslint from "typescript-eslint";
|
||||
|
||||
export default [
|
||||
{
|
||||
files: ["**/*.ts"],
|
||||
languageOptions: {
|
||||
parser: tseslint.parser,
|
||||
parserOptions: {
|
||||
sourceType: "module"
|
||||
}
|
||||
},
|
||||
ignores: [
|
||||
"**/node_modules/**",
|
||||
"**/dist/**",
|
||||
],
|
||||
plugins: {
|
||||
"@typescript-eslint": tseslint.plugin
|
||||
},
|
||||
rules: {
|
||||
"no-unused-vars": "off",
|
||||
"quotes": [
|
||||
"error",
|
||||
"single",
|
||||
{
|
||||
"avoidEscape": true
|
||||
}
|
||||
],
|
||||
"no-mixed-spaces-and-tabs": "error",
|
||||
"indent": [
|
||||
"error",
|
||||
"tab",
|
||||
{
|
||||
"SwitchCase": 1
|
||||
}
|
||||
],
|
||||
"arrow-parens": [
|
||||
"error",
|
||||
"always"
|
||||
],
|
||||
"eol-last": [
|
||||
"error",
|
||||
"always"
|
||||
],
|
||||
"func-call-spacing": [
|
||||
"error",
|
||||
"never"
|
||||
],
|
||||
"comma-dangle": [
|
||||
"error",
|
||||
"always-multiline"
|
||||
],
|
||||
"no-multi-spaces": "error",
|
||||
"no-trailing-spaces": "error",
|
||||
"no-whitespace-before-property": "off",
|
||||
"semi": [
|
||||
"error",
|
||||
"always"
|
||||
],
|
||||
"semi-style": [
|
||||
"error",
|
||||
"last"
|
||||
],
|
||||
"space-in-parens": [
|
||||
"error",
|
||||
"never"
|
||||
],
|
||||
"block-spacing": [
|
||||
"error",
|
||||
"always"
|
||||
],
|
||||
"object-curly-spacing": [
|
||||
"error",
|
||||
"always"
|
||||
],
|
||||
"eqeqeq": [
|
||||
"error",
|
||||
"always",
|
||||
{
|
||||
"null": "ignore"
|
||||
}
|
||||
],
|
||||
"spaced-comment": [
|
||||
"error",
|
||||
"always",
|
||||
{
|
||||
"markers": [
|
||||
"!"
|
||||
]
|
||||
}
|
||||
],
|
||||
"yoda": "error",
|
||||
"prefer-destructuring": [
|
||||
"error",
|
||||
{
|
||||
"object": true,
|
||||
"array": false
|
||||
}
|
||||
],
|
||||
"operator-assignment": [
|
||||
"error",
|
||||
"always"
|
||||
],
|
||||
"no-useless-computed-key": "error",
|
||||
"no-unneeded-ternary": [
|
||||
"error",
|
||||
{
|
||||
"defaultAssignment": false
|
||||
}
|
||||
],
|
||||
"no-invalid-regexp": "error",
|
||||
"no-constant-condition": [
|
||||
"error",
|
||||
{
|
||||
"checkLoops": false
|
||||
}
|
||||
],
|
||||
"no-duplicate-imports": "error",
|
||||
"no-extra-semi": "error",
|
||||
"dot-notation": "error",
|
||||
"no-useless-escape": "error",
|
||||
'@typescript-eslint/no-unused-vars': ['warn', { argsIgnorePattern: '^_' }],
|
||||
'@typescript-eslint/no-explicit-any': 'warn',
|
||||
'@typescript-eslint/consistent-type-imports': 'error',
|
||||
'@typescript-eslint/consistent-type-definitions': [
|
||||
'error',
|
||||
'interface'],
|
||||
'@typescript-eslint/explicit-function-return-type': 'warn',
|
||||
'@typescript-eslint/ban-ts-comment': 'warn',
|
||||
'array-bracket-spacing': [
|
||||
'error', 'never'],
|
||||
'linebreak-style': [
|
||||
'error',
|
||||
'unix'
|
||||
],
|
||||
'no-nested-ternary': 'error',
|
||||
'no-shadow': 'error',
|
||||
'no-return-await': 'error',
|
||||
'no-else-return': 'error',
|
||||
'no-empty-function': 'warn',
|
||||
'complexity': [
|
||||
'warn',
|
||||
15
|
||||
],
|
||||
'max-len': [
|
||||
'warn', {
|
||||
code: 100,
|
||||
ignoreComments: true,
|
||||
}
|
||||
],
|
||||
'no-inline-comments': 'warn',
|
||||
'no-magic-numbers': [
|
||||
'warn', {
|
||||
ignore: [0, 1],
|
||||
enforceConst: true,
|
||||
ignoreTypeIndexes: true,
|
||||
ignoreEnums: true,
|
||||
ignoreNumericLiteralTypes: true,
|
||||
ignoreClassFieldInitialValues: true,
|
||||
}
|
||||
],
|
||||
}
|
||||
}
|
||||
];
|
||||
2115
package-lock.json
generated
2115
package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
|
@ -16,16 +16,21 @@
|
|||
"author": "Lost Paul",
|
||||
"license": "GPL-3.0-or-later",
|
||||
"devDependencies": {
|
||||
"@eslint/js": "^9.32.0",
|
||||
"@types/node": "^16.11.6",
|
||||
"@typescript-eslint/eslint-plugin": "5.29.0",
|
||||
"@typescript-eslint/parser": "5.29.0",
|
||||
"builtin-modules": "3.3.0",
|
||||
"esbuild": "0.14.47",
|
||||
"eslint": "^9.32.0",
|
||||
"front-matter-plugin-api-provider": "^0.1.4-alpha",
|
||||
"globals": "^16.3.0",
|
||||
"jiti": "^2.5.1",
|
||||
"obsidian": "latest",
|
||||
"obsidian-typings": "^2.2.0",
|
||||
"tslib": "2.4.0",
|
||||
"typescript": "4.7.4"
|
||||
"typescript": "^4.8.4",
|
||||
"typescript-eslint": "^8.38.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@popperjs/core": "^2.11.6"
|
||||
|
|
|
|||
515
src/Commands.ts
515
src/Commands.ts
|
|
@ -1,10 +1,35 @@
|
|||
import { App, TFolder, Menu, TAbstractFile, Notice, TFile, Editor, MarkdownView, Platform } from 'obsidian';
|
||||
import FolderNotesPlugin from './main';
|
||||
import { getFolderNote, createFolderNote, deleteFolderNote, turnIntoFolderNote, openFolderNote, extractFolderName, detachFolderNote } from './functions/folderNoteFunctions';
|
||||
import {
|
||||
TFolder,
|
||||
Notice,
|
||||
TFile,
|
||||
Platform,
|
||||
type App,
|
||||
type Menu,
|
||||
type TAbstractFile,
|
||||
type Editor,
|
||||
type MarkdownView,
|
||||
} from 'obsidian';
|
||||
import type FolderNotesPlugin from './main';
|
||||
import {
|
||||
getFolderNote,
|
||||
createFolderNote,
|
||||
deleteFolderNote,
|
||||
turnIntoFolderNote,
|
||||
openFolderNote,
|
||||
extractFolderName,
|
||||
detachFolderNote,
|
||||
} from './functions/folderNoteFunctions';
|
||||
import { ExcludedFolder } from './ExcludeFolders/ExcludeFolder';
|
||||
import { getFolderPathFromString, getFileExplorerActiveFolder } from './functions/utils';
|
||||
import { deleteExcludedFolder, getDetachedFolder, getExcludedFolder } from './ExcludeFolders/functions/folderFunctions';
|
||||
import { hideFolderNoteInFileExplorer, showFolderNoteInFileExplorer } from './functions/styleFunctions';
|
||||
import {
|
||||
deleteExcludedFolder,
|
||||
getDetachedFolder,
|
||||
getExcludedFolder,
|
||||
} from './ExcludeFolders/functions/folderFunctions';
|
||||
import {
|
||||
hideFolderNoteInFileExplorer,
|
||||
showFolderNoteInFileExplorer,
|
||||
} from './functions/styleFunctions';
|
||||
|
||||
|
||||
|
||||
|
|
@ -15,12 +40,13 @@ export class Commands {
|
|||
this.plugin = plugin;
|
||||
this.app = app;
|
||||
}
|
||||
registerCommands() {
|
||||
registerCommands(): void {
|
||||
this.editorCommands();
|
||||
this.fileCommands();
|
||||
this.regularCommands();
|
||||
}
|
||||
regularCommands() {
|
||||
|
||||
regularCommands(): void {
|
||||
this.plugin.addCommand({
|
||||
id: 'turn-into-folder-note',
|
||||
name: 'Use this file as the folder note for its parent folder',
|
||||
|
|
@ -51,7 +77,8 @@ export class Commands {
|
|||
if (this.plugin.app.vault.getAbstractFileByPath(newPath)) {
|
||||
return new Notice('Folder already exists');
|
||||
}
|
||||
const automaticallyCreateFolderNote = this.plugin.settings.autoCreate;
|
||||
const automaticallyCreateFolderNote =
|
||||
this.plugin.settings.autoCreate;
|
||||
this.plugin.settings.autoCreate = false;
|
||||
this.plugin.saveSettings();
|
||||
await this.plugin.app.vault.createFolder(newPath);
|
||||
|
|
@ -108,7 +135,7 @@ export class Commands {
|
|||
|
||||
// Everything is fine and not checking, let's create the folder note.
|
||||
const ext = '.' + fileType;
|
||||
const path = folder.path;
|
||||
const { path } = folder;
|
||||
createFolderNote(this.plugin, path, true, ext, false);
|
||||
},
|
||||
});
|
||||
|
|
@ -179,13 +206,14 @@ export class Commands {
|
|||
name: 'Create folder note from selection',
|
||||
editorCheckCallback: (checking: boolean, editor: Editor, view: MarkdownView) => {
|
||||
const text = editor.getSelection().trim();
|
||||
const file = view.file;
|
||||
const { file } = view;
|
||||
if (!(file instanceof TFile)) return false;
|
||||
if (text && text.trim() !== '') {
|
||||
if (checking) { return true; }
|
||||
const blacklist = ['*', '\\', '"', '/', '<', '>', '?', '|', ':'];
|
||||
for (const char of blacklist) {
|
||||
if (text.includes(char)) {
|
||||
// eslint-disable-next-line max-len
|
||||
new Notice('File name cannot contain any of the following characters: * " \\ / < > : | ?');
|
||||
return false;
|
||||
}
|
||||
|
|
@ -201,18 +229,23 @@ export class Commands {
|
|||
if (folder instanceof TFolder) {
|
||||
new Notice('Folder note already exists');
|
||||
return false;
|
||||
} else {
|
||||
this.plugin.app.vault.createFolder(text);
|
||||
createFolderNote(this.plugin, text, false);
|
||||
}
|
||||
this.plugin.app.vault.createFolder(text);
|
||||
createFolderNote(this.plugin, text, false);
|
||||
|
||||
} else {
|
||||
folder = this.plugin.app.vault.getAbstractFileByPath(folderPath + '/' + text);
|
||||
const folderFullPath = folderPath + '/' + text;
|
||||
folder = this.plugin.app.vault.getAbstractFileByPath(folderFullPath);
|
||||
if (folder instanceof TFolder) {
|
||||
new Notice('Folder note already exists');
|
||||
return false;
|
||||
}
|
||||
if (this.plugin.settings.storageLocation === 'parentFolder') {
|
||||
if (this.app.vault.getAbstractFileByPath(folderPath + '/' + text + this.plugin.settings.folderNoteType)) {
|
||||
if (
|
||||
this.app.vault.getAbstractFileByPath(
|
||||
folderPath + '/' + text + this.plugin.settings.folderNoteType,
|
||||
)
|
||||
) {
|
||||
new Notice('File already exists');
|
||||
return false;
|
||||
}
|
||||
|
|
@ -220,7 +253,9 @@ export class Commands {
|
|||
this.plugin.app.vault.createFolder(folderPath + '/' + text);
|
||||
createFolderNote(this.plugin, folderPath + '/' + text, false);
|
||||
}
|
||||
const fileName = this.plugin.settings.folderNoteName.replace('{{folder_name}}', text);
|
||||
|
||||
const { folderNoteName } = this.plugin.settings;
|
||||
const fileName = folderNoteName.replace('{{folder_name}}', text);
|
||||
if (fileName !== text) {
|
||||
editor.replaceSelection(`[[${fileName}]]`);
|
||||
} else {
|
||||
|
|
@ -233,213 +268,243 @@ export class Commands {
|
|||
});
|
||||
}
|
||||
|
||||
fileCommands() {
|
||||
this.plugin.registerEvent(this.app.workspace.on('file-menu', (menu: Menu, file: TAbstractFile) => {
|
||||
let folder: TAbstractFile | TFolder | null = file.parent;
|
||||
if (file instanceof TFile) {
|
||||
if (this.plugin.settings.storageLocation === 'insideFolder') {
|
||||
folder = file.parent;
|
||||
} else {
|
||||
const fileName = extractFolderName(this.plugin.settings.folderNoteName, file.basename);
|
||||
if (fileName) {
|
||||
if (file.parent?.path === '' || file.parent?.path === '/') {
|
||||
folder = this.plugin.app.vault.getAbstractFileByPath(fileName);
|
||||
} else {
|
||||
folder = this.plugin.app.vault.getAbstractFileByPath(file.parent?.path + '/' + fileName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (folder instanceof TFolder) {
|
||||
const folderNote = getFolderNote(this.plugin, folder.path);
|
||||
const excludedFolder = getExcludedFolder(this.plugin, folder.path, true);
|
||||
if (folderNote?.path === file.path && !excludedFolder?.detached) { return; }
|
||||
} else if (file.parent instanceof TFolder) {
|
||||
folder = file.parent;
|
||||
}
|
||||
}
|
||||
|
||||
menu.addItem(async (item) => {
|
||||
if (Platform.isDesktop && !Platform.isTablet && this.plugin.settings.useSubmenus) {
|
||||
item
|
||||
.setTitle('Folder Note Commands')
|
||||
.setIcon('folder-edit');
|
||||
}
|
||||
let subMenu: Menu;
|
||||
if (!Platform.isDesktopApp || !Platform.isDesktop || Platform.isTablet || !this.plugin.settings.useSubmenus) {
|
||||
subMenu = menu;
|
||||
item.setDisabled(true);
|
||||
} else {
|
||||
// @ts-ignore
|
||||
subMenu = item.setSubmenu() as Menu;
|
||||
}
|
||||
fileCommands(): void {
|
||||
this.plugin.registerEvent(
|
||||
this.app.workspace.on('file-menu', (menu: Menu, file: TAbstractFile) => {
|
||||
let folder: TAbstractFile | TFolder | null = file.parent;
|
||||
if (file instanceof TFile) {
|
||||
// @ts-ignore
|
||||
subMenu.addItem((item) => {
|
||||
item.setTitle('Create folder note')
|
||||
.setIcon('edit')
|
||||
.onClick(async () => {
|
||||
if (!folder) return;
|
||||
let newPath = folder.path + '/' + file.basename;
|
||||
if (folder.path === '' || folder.path === '/') {
|
||||
newPath = file.basename;
|
||||
}
|
||||
if (this.plugin.app.vault.getAbstractFileByPath(newPath)) {
|
||||
return new Notice('Folder already exists');
|
||||
}
|
||||
const automaticallyCreateFolderNote = this.plugin.settings.autoCreate;
|
||||
this.plugin.settings.autoCreate = false;
|
||||
this.plugin.saveSettings();
|
||||
await this.plugin.app.vault.createFolder(newPath);
|
||||
const newFolder = this.plugin.app.vault.getAbstractFileByPath(newPath);
|
||||
if (!(newFolder instanceof TFolder)) return;
|
||||
await createFolderNote(this.plugin, newFolder.path, true, '.' + file.extension, false, file);
|
||||
this.plugin.settings.autoCreate = automaticallyCreateFolderNote;
|
||||
this.plugin.saveSettings();
|
||||
});
|
||||
});
|
||||
if (getFolderPathFromString(file.path) === '') return;
|
||||
if (!(folder instanceof TFolder)) return;
|
||||
if (folder.path === '' || folder.path === '/') return;
|
||||
subMenu.addItem((item) => {
|
||||
item.setTitle(`Turn into folder note for ${folder?.name}`)
|
||||
.setIcon('edit')
|
||||
.onClick(() => {
|
||||
if (!folder || !(folder instanceof TFolder)) return;
|
||||
const folderNote = getFolderNote(this.plugin, folder.path);
|
||||
turnIntoFolderNote(this.plugin, file, folder, folderNote);
|
||||
});
|
||||
});
|
||||
}
|
||||
if (!(file instanceof TFolder)) return;
|
||||
const excludedFolder = getExcludedFolder(this.plugin, file.path, false);
|
||||
const detachedExcludedFolder = getDetachedFolder(this.plugin, file.path);
|
||||
if (excludedFolder && !excludedFolder.hideInSettings) {
|
||||
// I'm not sure if I'm ever going to add this because of the possibility that a folder got more than one excluded
|
||||
// subMenu.addItem((item) => {
|
||||
// item.setTitle('Manage excluded folder')
|
||||
// .setIcon('settings-2')
|
||||
// .onClick(() => {
|
||||
// if (excludedFolder instanceof ExcludedFolder) {
|
||||
// new ExcludedFolderSettings(this.plugin.app, this.plugin, excludedFolder).open();
|
||||
// } else if (excludedFolder instanceof ExcludePattern) {
|
||||
// new PatternSettings(this.plugin.app, this.plugin, excludedFolder).open();
|
||||
// }
|
||||
// })
|
||||
// })
|
||||
subMenu.addItem((item) => {
|
||||
item.setTitle('Remove folder from excluded folders')
|
||||
.setIcon('trash')
|
||||
.onClick(() => {
|
||||
this.plugin.settings.excludeFolders = this.plugin.settings.excludeFolders.filter(
|
||||
(folder) => (folder.path !== file.path) || folder.detached);
|
||||
this.plugin.saveSettings(true);
|
||||
new Notice('Successfully removed folder from excluded folders');
|
||||
});
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (detachedExcludedFolder) {
|
||||
subMenu.addItem((item) => {
|
||||
item.setTitle('Remove folder from detached folders')
|
||||
.setIcon('trash')
|
||||
.onClick(() => {
|
||||
deleteExcludedFolder(this.plugin, detachedExcludedFolder);
|
||||
});
|
||||
});
|
||||
}
|
||||
if (detachedExcludedFolder) { return; }
|
||||
subMenu.addItem((item) => {
|
||||
item.setTitle('Exclude folder from folder notes')
|
||||
.setIcon('x-circle')
|
||||
.onClick(() => {
|
||||
const excludedFolder = new ExcludedFolder(file.path, this.plugin.settings.excludeFolders.length, undefined, this.plugin);
|
||||
this.plugin.settings.excludeFolders.push(excludedFolder);
|
||||
this.plugin.saveSettings(true);
|
||||
new Notice('Successfully excluded folder from folder notes');
|
||||
});
|
||||
});
|
||||
if (!(file instanceof TFolder)) return;
|
||||
const folderNote = getFolderNote(this.plugin, file.path);
|
||||
if (folderNote instanceof TFile && !detachedExcludedFolder) {
|
||||
subMenu.addItem((item) => {
|
||||
item.setTitle('Delete folder note')
|
||||
.setIcon('trash')
|
||||
.onClick(() => {
|
||||
deleteFolderNote(this.plugin, folderNote, true);
|
||||
});
|
||||
});
|
||||
|
||||
subMenu.addItem((item) => {
|
||||
item.setTitle('Open folder note')
|
||||
.setIcon('chevron-right-square')
|
||||
.onClick(() => {
|
||||
openFolderNote(this.plugin, folderNote);
|
||||
});
|
||||
});
|
||||
|
||||
subMenu.addItem((item) => {
|
||||
item.setTitle('Detach folder note')
|
||||
.setIcon('unlink')
|
||||
.onClick(() => {
|
||||
detachFolderNote(this.plugin, folderNote);
|
||||
});
|
||||
});
|
||||
|
||||
subMenu.addItem((item) => {
|
||||
item.setTitle('Copy Obsidian URL')
|
||||
.setIcon('link')
|
||||
.onClick(() => {
|
||||
// @ts-ignore
|
||||
this.app.copyObsidianUrl(folderNote);
|
||||
});
|
||||
});
|
||||
|
||||
if (this.plugin.settings.hideFolderNote) {
|
||||
if (excludedFolder?.showFolderNote) {
|
||||
subMenu.addItem((item) => {
|
||||
item.setTitle('Hide folder note in explorer')
|
||||
.setIcon('eye-off')
|
||||
.onClick(() => {
|
||||
hideFolderNoteInFileExplorer(file.path, this.plugin);
|
||||
});
|
||||
});
|
||||
} else {
|
||||
subMenu.addItem((item) => {
|
||||
item.setTitle('Show folder note in explorer')
|
||||
.setIcon('eye')
|
||||
.onClick(() => {
|
||||
showFolderNoteInFileExplorer(file.path, this.plugin);
|
||||
});
|
||||
});
|
||||
if (this.plugin.settings.storageLocation === 'insideFolder') {
|
||||
folder = file.parent;
|
||||
} else {
|
||||
const { folderNoteName } = this.plugin.settings;
|
||||
const fileName = extractFolderName(folderNoteName, file.basename);
|
||||
if (fileName) {
|
||||
if (file.parent?.path === '' || file.parent?.path === '/') {
|
||||
folder = this.plugin.app.vault.getAbstractFileByPath(fileName);
|
||||
} else {
|
||||
folder = this.plugin.app.vault.getAbstractFileByPath(
|
||||
file.parent?.path + '/' + fileName,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
subMenu.addItem((item) => {
|
||||
item.setTitle('Create markdown folder note')
|
||||
.setIcon('edit')
|
||||
.onClick(() => {
|
||||
createFolderNote(this.plugin, file.path, true, '.md');
|
||||
});
|
||||
});
|
||||
if (folder instanceof TFolder) {
|
||||
const folderNote = getFolderNote(this.plugin, folder.path);
|
||||
const excludedFolder = getExcludedFolder(this.plugin, folder.path, true);
|
||||
if (folderNote?.path === file.path && !excludedFolder?.detached) { return; }
|
||||
} else if (file.parent instanceof TFolder) {
|
||||
folder = file.parent;
|
||||
}
|
||||
}
|
||||
|
||||
this.plugin.settings.supportedFileTypes.forEach((fileType) => {
|
||||
if (fileType === 'md') return;
|
||||
subMenu.addItem((item) => {
|
||||
item.setTitle(`Create ${fileType} folder note`)
|
||||
// eslint-disable-next-line complexity
|
||||
menu.addItem(async (menuItem) => {
|
||||
if (
|
||||
Platform.isDesktop &&
|
||||
!Platform.isTablet &&
|
||||
this.plugin.settings.useSubmenus
|
||||
) {
|
||||
menuItem
|
||||
.setTitle('Folder Note Commands')
|
||||
.setIcon('folder-edit');
|
||||
}
|
||||
let subMenu: Menu;
|
||||
if (
|
||||
!Platform.isDesktopApp ||
|
||||
!Platform.isDesktop ||
|
||||
Platform.isTablet ||
|
||||
!this.plugin.settings.useSubmenus
|
||||
) {
|
||||
subMenu = menu;
|
||||
menuItem.setDisabled(true);
|
||||
} else {
|
||||
subMenu = menuItem.setSubmenu() as Menu;
|
||||
}
|
||||
if (file instanceof TFile) {
|
||||
subMenu.addItem((subItem) => {
|
||||
subItem.setTitle('Create folder note')
|
||||
.setIcon('edit')
|
||||
.onClick(() => {
|
||||
createFolderNote(this.plugin, file.path, true, '.' + fileType);
|
||||
.onClick(async () => {
|
||||
if (!folder) return;
|
||||
let newPath = folder.path + '/' + file.basename;
|
||||
if (folder.path === '' || folder.path === '/') {
|
||||
newPath = file.basename;
|
||||
}
|
||||
if (this.plugin.app.vault.getAbstractFileByPath(newPath)) {
|
||||
return new Notice('Folder already exists');
|
||||
}
|
||||
const automaticallyCreateFolderNote =
|
||||
this.plugin.settings.autoCreate;
|
||||
this.plugin.settings.autoCreate = false;
|
||||
this.plugin.saveSettings();
|
||||
await this.plugin.app.vault.createFolder(newPath);
|
||||
const newFolder = this.plugin.app.vault
|
||||
.getAbstractFileByPath(newPath);
|
||||
if (!(newFolder instanceof TFolder)) return;
|
||||
await createFolderNote(
|
||||
this.plugin,
|
||||
newFolder.path,
|
||||
true,
|
||||
'.' + file.extension,
|
||||
false,
|
||||
file,
|
||||
);
|
||||
this.plugin.settings.autoCreate = automaticallyCreateFolderNote;
|
||||
this.plugin.saveSettings();
|
||||
});
|
||||
});
|
||||
if (getFolderPathFromString(file.path) === '') return;
|
||||
if (!(folder instanceof TFolder)) return;
|
||||
if (folder.path === '' || folder.path === '/') return;
|
||||
subMenu.addItem((item) => {
|
||||
item.setTitle(`Turn into folder note for ${folder?.name}`)
|
||||
.setIcon('edit')
|
||||
.onClick(() => {
|
||||
if (!folder || !(folder instanceof TFolder)) return;
|
||||
const folderNote = getFolderNote(this.plugin, folder.path);
|
||||
turnIntoFolderNote(this.plugin, file, folder, folderNote);
|
||||
});
|
||||
});
|
||||
}
|
||||
if (!(file instanceof TFolder)) return;
|
||||
const excludedFolder = getExcludedFolder(this.plugin, file.path, false);
|
||||
const detachedExcludedFolder = getDetachedFolder(this.plugin, file.path);
|
||||
if (excludedFolder && !excludedFolder.hideInSettings) {
|
||||
// I'm not sure if I'm ever going to add this because of the possibility that a folder got more than one excluded
|
||||
// subMenu.addItem((item) => {
|
||||
// item.setTitle('Manage excluded folder')
|
||||
// .setIcon('settings-2')
|
||||
// .onClick(() => {
|
||||
// if (excludedFolder instanceof ExcludedFolder) {
|
||||
// new ExcludedFolderSettings(this.plugin.app, this.plugin, excludedFolder).open();
|
||||
// } else if (excludedFolder instanceof ExcludePattern) {
|
||||
// new PatternSettings(this.plugin.app, this.plugin, excludedFolder).open();
|
||||
// }
|
||||
// })
|
||||
// })
|
||||
subMenu.addItem((item) => {
|
||||
item.setTitle('Remove folder from excluded folders')
|
||||
.setIcon('trash')
|
||||
.onClick(() => {
|
||||
this.plugin.settings.excludeFolders =
|
||||
this.plugin.settings.excludeFolders.filter(
|
||||
(excluded) =>
|
||||
(excluded.path !== file.path) || excluded.detached,
|
||||
);
|
||||
this.plugin.saveSettings(true);
|
||||
new Notice('Successfully removed folder from excluded folders');
|
||||
});
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (detachedExcludedFolder) {
|
||||
subMenu.addItem((item) => {
|
||||
item.setTitle('Remove folder from detached folders')
|
||||
.setIcon('trash')
|
||||
.onClick(() => {
|
||||
deleteExcludedFolder(this.plugin, detachedExcludedFolder);
|
||||
});
|
||||
});
|
||||
}
|
||||
if (detachedExcludedFolder) { return; }
|
||||
subMenu.addItem((item) => {
|
||||
item.setTitle('Exclude folder from folder notes')
|
||||
.setIcon('x-circle')
|
||||
.onClick(() => {
|
||||
const newExcludedFolder = new ExcludedFolder(
|
||||
file.path,
|
||||
this.plugin.settings.excludeFolders.length,
|
||||
undefined,
|
||||
this.plugin,
|
||||
);
|
||||
this.plugin.settings.excludeFolders.push(newExcludedFolder);
|
||||
this.plugin.saveSettings(true);
|
||||
new Notice('Successfully excluded folder from folder notes');
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
}));
|
||||
if (!(file instanceof TFolder)) return;
|
||||
const folderNote = getFolderNote(this.plugin, file.path);
|
||||
if (folderNote instanceof TFile && !detachedExcludedFolder) {
|
||||
subMenu.addItem((item) => {
|
||||
item.setTitle('Delete folder note')
|
||||
.setIcon('trash')
|
||||
.onClick(() => {
|
||||
deleteFolderNote(this.plugin, folderNote, true);
|
||||
});
|
||||
});
|
||||
|
||||
subMenu.addItem((item) => {
|
||||
item.setTitle('Open folder note')
|
||||
.setIcon('chevron-right-square')
|
||||
.onClick(() => {
|
||||
openFolderNote(this.plugin, folderNote);
|
||||
});
|
||||
});
|
||||
|
||||
subMenu.addItem((item) => {
|
||||
item.setTitle('Detach folder note')
|
||||
.setIcon('unlink')
|
||||
.onClick(() => {
|
||||
detachFolderNote(this.plugin, folderNote);
|
||||
});
|
||||
});
|
||||
|
||||
subMenu.addItem((item) => {
|
||||
item.setTitle('Copy Obsidian URL')
|
||||
.setIcon('link')
|
||||
.onClick(() => {
|
||||
this.app.copyObsidianUrl(folderNote);
|
||||
});
|
||||
});
|
||||
|
||||
if (this.plugin.settings.hideFolderNote) {
|
||||
if (excludedFolder?.showFolderNote) {
|
||||
subMenu.addItem((item) => {
|
||||
item.setTitle('Hide folder note in explorer')
|
||||
.setIcon('eye-off')
|
||||
.onClick(() => {
|
||||
hideFolderNoteInFileExplorer(file.path, this.plugin);
|
||||
});
|
||||
});
|
||||
} else {
|
||||
subMenu.addItem((item) => {
|
||||
item.setTitle('Show folder note in explorer')
|
||||
.setIcon('eye')
|
||||
.onClick(() => {
|
||||
showFolderNoteInFileExplorer(file.path, this.plugin);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
subMenu.addItem((item) => {
|
||||
item.setTitle('Create markdown folder note')
|
||||
.setIcon('edit')
|
||||
.onClick(() => {
|
||||
createFolderNote(this.plugin, file.path, true, '.md');
|
||||
});
|
||||
});
|
||||
|
||||
this.plugin.settings.supportedFileTypes.forEach((fileType) => {
|
||||
if (fileType === 'md') return;
|
||||
subMenu.addItem((item) => {
|
||||
item.setTitle(`Create ${fileType} folder note`)
|
||||
.setIcon('edit')
|
||||
.onClick(() => {
|
||||
// eslint-disable-next-line max-len
|
||||
createFolderNote(this.plugin, file.path, true, '.' + fileType);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
}));
|
||||
}
|
||||
|
||||
editorCommands() {
|
||||
editorCommands(): void {
|
||||
// eslint-disable-next-line max-len
|
||||
this.plugin.registerEvent(this.plugin.app.workspace.on('editor-menu', (menu: Menu, editor: Editor, view: MarkdownView) => {
|
||||
const text = editor.getSelection().trim();
|
||||
if (!text || text.trim() === '') return;
|
||||
|
|
@ -447,11 +512,12 @@ export class Commands {
|
|||
item.setTitle('Create folder note')
|
||||
.setIcon('edit')
|
||||
.onClick(() => {
|
||||
const file = view.file;
|
||||
const { file } = view;
|
||||
if (!(file instanceof TFile)) return;
|
||||
const blacklist = ['*', '\\', '"', '/', '<', '>', '?', '|', ':'];
|
||||
for (const char of blacklist) {
|
||||
if (text.includes(char)) {
|
||||
// eslint-disable-next-line max-len
|
||||
new Notice('File name cannot contain any of the following characters: * " \\ / < > : | ?');
|
||||
return;
|
||||
}
|
||||
|
|
@ -460,24 +526,35 @@ export class Commands {
|
|||
new Notice('File name cannot end with a dot');
|
||||
return;
|
||||
}
|
||||
|
||||
let folder: TAbstractFile | null;
|
||||
const folderPath = getFolderPathFromString(file.path);
|
||||
const fileName = this.plugin.settings.folderNoteName.replace('{{folder_name}}', text);
|
||||
const { folderNoteName } = this.plugin.settings;
|
||||
const fileName = folderNoteName.replace('{{folder_name}}', text);
|
||||
if (folderPath === '') {
|
||||
folder = this.plugin.app.vault.getAbstractFileByPath(text);
|
||||
if (folder instanceof TFolder) {
|
||||
return new Notice('Folder note already exists');
|
||||
} else {
|
||||
this.plugin.app.vault.createFolder(text);
|
||||
createFolderNote(this.plugin, text, false);
|
||||
}
|
||||
this.plugin.app.vault.createFolder(text);
|
||||
createFolderNote(this.plugin, text, false);
|
||||
|
||||
} else {
|
||||
folder = this.plugin.app.vault.getAbstractFileByPath(folderPath + '/' + text);
|
||||
folder = this.plugin.app.vault.getAbstractFileByPath(
|
||||
folderPath + '/' + text,
|
||||
);
|
||||
if (folder instanceof TFolder) {
|
||||
return new Notice('Folder note already exists');
|
||||
}
|
||||
if (this.plugin.settings.storageLocation === 'parentFolder') {
|
||||
if (this.app.vault.getAbstractFileByPath(folderPath + '/' + fileName + this.plugin.settings.folderNoteType)) {
|
||||
if (
|
||||
this.app.vault.getAbstractFileByPath(
|
||||
folderPath +
|
||||
'/' +
|
||||
fileName +
|
||||
this.plugin.settings.folderNoteType,
|
||||
)
|
||||
) {
|
||||
return new Notice('File already exists');
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import FolderNotesPlugin from '../main';
|
||||
import type FolderNotesPlugin from '../main';
|
||||
export class ExcludedFolder {
|
||||
type: string;
|
||||
id: string;
|
||||
|
|
@ -25,6 +25,7 @@ export class ExcludedFolder {
|
|||
this.disableFolderNote = plugin.settings.excludeFolderDefaultSettings.disableFolderNote;
|
||||
this.enableCollapsing = plugin.settings.excludeFolderDefaultSettings.enableCollapsing;
|
||||
this.position = position;
|
||||
// eslint-disable-next-line max-len
|
||||
this.excludeFromFolderOverview = plugin.settings.excludeFolderDefaultSettings.excludeFromFolderOverview;
|
||||
this.string = '';
|
||||
this.hideInSettings = false;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import FolderNotesPlugin from '../main';
|
||||
import type FolderNotesPlugin from '../main';
|
||||
export class ExcludePattern {
|
||||
type: string;
|
||||
id: string;
|
||||
|
|
@ -15,7 +15,12 @@ export class ExcludePattern {
|
|||
detached: boolean;
|
||||
detachedFilePath?: string;
|
||||
showFolderNote: boolean;
|
||||
constructor(pattern: string, position: number, id: string | undefined, plugin: FolderNotesPlugin) {
|
||||
constructor(
|
||||
pattern: string,
|
||||
position: number,
|
||||
id: string | undefined,
|
||||
plugin: FolderNotesPlugin,
|
||||
) {
|
||||
this.type = 'pattern';
|
||||
this.id = id || crypto.randomUUID();
|
||||
this.string = pattern;
|
||||
|
|
@ -25,6 +30,7 @@ export class ExcludePattern {
|
|||
this.disableAutoCreate = plugin.settings.excludePatternDefaultSettings.disableAutoCreate;
|
||||
this.disableFolderNote = plugin.settings.excludePatternDefaultSettings.disableFolderNote;
|
||||
this.enableCollapsing = plugin.settings.excludePatternDefaultSettings.enableCollapsing;
|
||||
// eslint-disable-next-line max-len
|
||||
this.excludeFromFolderOverview = plugin.settings.excludePatternDefaultSettings.excludeFromFolderOverview;
|
||||
this.path = '';
|
||||
this.hideInSettings = false;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import FolderNotesPlugin from '../main';
|
||||
import type FolderNotesPlugin from '../main';
|
||||
export class WhitelistedFolder {
|
||||
type: string;
|
||||
id: string;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import FolderNotesPlugin from '../main';
|
||||
import type FolderNotesPlugin from '../main';
|
||||
export class WhitelistedPattern {
|
||||
type: string;
|
||||
id: string;
|
||||
|
|
@ -13,7 +13,12 @@ export class WhitelistedPattern {
|
|||
showInFolderOverview: boolean;
|
||||
hideInFileExplorer: boolean;
|
||||
hideInSettings: boolean;
|
||||
constructor(pattern: string, position: number, id: string | undefined, plugin: FolderNotesPlugin) {
|
||||
constructor(
|
||||
pattern: string,
|
||||
position: number,
|
||||
id: string | undefined,
|
||||
plugin: FolderNotesPlugin,
|
||||
) {
|
||||
this.type = 'pattern';
|
||||
this.id = id || crypto.randomUUID();
|
||||
this.subFolders = plugin.settings.excludePatternDefaultSettings.subFolders;
|
||||
|
|
|
|||
|
|
@ -1,29 +1,39 @@
|
|||
import FolderNotesPlugin from '../../main';
|
||||
import type FolderNotesPlugin from '../../main';
|
||||
import { getFolderNameFromPathString, getFolderPathFromString } from '../../functions/utils';
|
||||
import { ExcludedFolder } from '../ExcludeFolder';
|
||||
import type { ExcludedFolder } from '../ExcludeFolder';
|
||||
import { ExcludePattern } from '../ExcludePattern';
|
||||
import { Platform, Setting } from 'obsidian';
|
||||
import { FolderSuggest } from '../../suggesters/FolderSuggester';
|
||||
import { SettingsTab } from '../../settings/SettingsTab';
|
||||
import type { SettingsTab } from '../../settings/SettingsTab';
|
||||
import ExcludedFolderSettings from '../modals/ExcludeFolderSettings';
|
||||
import { updatePattern, getExcludedFoldersByPattern, addExcludePatternListItem } from './patternFunctions';
|
||||
import {
|
||||
updatePattern,
|
||||
getExcludedFoldersByPattern,
|
||||
addExcludePatternListItem,
|
||||
} from './patternFunctions';
|
||||
import { getWhitelistedFolder } from './whitelistFolderFunctions';
|
||||
import { WhitelistedFolder } from '../WhitelistFolder';
|
||||
import { WhitelistedPattern } from '../WhitelistPattern';
|
||||
import type { WhitelistedFolder } from '../WhitelistFolder';
|
||||
import type { WhitelistedPattern } from '../WhitelistPattern';
|
||||
|
||||
export function getExcludedFolder(plugin: FolderNotesPlugin, path: string, includeDetached: boolean, pathOnly?: boolean, ignoreWhitelist?: boolean) {
|
||||
let excludedFolder = {} as ExcludedFolder | ExcludePattern | undefined;
|
||||
const whitelistedFolder = getWhitelistedFolder(plugin, path) as WhitelistedFolder | WhitelistedPattern | undefined;
|
||||
function combineExcluded(
|
||||
plugin: FolderNotesPlugin,
|
||||
path: string,
|
||||
includeDetached: boolean,
|
||||
pathOnly?: boolean,
|
||||
): Array<ExcludedFolder | ExcludePattern> {
|
||||
const folderName = getFolderNameFromPathString(path);
|
||||
let matchedPatterns = getExcludedFoldersByPattern(plugin, folderName);
|
||||
const excludedFolders = getExcludedFoldersByPath(plugin, path);
|
||||
if (pathOnly) { matchedPatterns = []; }
|
||||
let combinedExcludedFolders = [...matchedPatterns, ...excludedFolders];
|
||||
|
||||
if (!includeDetached) {
|
||||
combinedExcludedFolders = combinedExcludedFolders.filter((f) => !f.detached);
|
||||
}
|
||||
const matchedPatterns = pathOnly ? [] : getExcludedFoldersByPattern(plugin, folderName);
|
||||
const excludedByPath = getExcludedFoldersByPath(plugin, path);
|
||||
let combined = [...matchedPatterns, ...excludedByPath];
|
||||
if (!includeDetached) combined = combined.filter((f) => !f.detached);
|
||||
return combined;
|
||||
}
|
||||
|
||||
function aggregateFlags(
|
||||
combinedExcludedFolders: Array<ExcludedFolder | ExcludePattern>,
|
||||
): Partial<ExcludedFolder> | undefined {
|
||||
if (combinedExcludedFolders.length === 0) return undefined;
|
||||
const result: Partial<ExcludedFolder> = {};
|
||||
const propertiesToCopy: (keyof ExcludedFolder)[] = [
|
||||
'disableAutoCreate',
|
||||
'disableFolderNote',
|
||||
|
|
@ -35,32 +45,46 @@ export function getExcludedFolder(plugin: FolderNotesPlugin, path: string, inclu
|
|||
'id',
|
||||
'showFolderNote',
|
||||
];
|
||||
|
||||
if (combinedExcludedFolders.length > 0) {
|
||||
for (const matchedFolder of combinedExcludedFolders) {
|
||||
propertiesToCopy.forEach((property) => {
|
||||
if (matchedFolder[property] === true) {
|
||||
(excludedFolder as any)[property] = true;
|
||||
} else if (!matchedFolder[property]) {
|
||||
(excludedFolder as any)[property] = false;
|
||||
}
|
||||
});
|
||||
for (const matchedFolder of combinedExcludedFolders) {
|
||||
for (const property of propertiesToCopy) {
|
||||
const value = (matchedFolder as Partial<ExcludedFolder>)[property];
|
||||
if (value === true) {
|
||||
(result as Partial<ExcludedFolder>)[property] = true as never;
|
||||
} else if (!value) {
|
||||
(result as Partial<ExcludedFolder>)[property] = false as never;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
excludedFolder = undefined;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
if (excludedFolder?.detached) { ignoreWhitelist = true; }
|
||||
function applyWhitelistOverrides(
|
||||
excluded: Partial<ExcludedFolder>,
|
||||
whitelisted: WhitelistedFolder | WhitelistedPattern,
|
||||
): Partial<ExcludedFolder> {
|
||||
const out: Partial<ExcludedFolder> = { ...excluded };
|
||||
if (out.disableAutoCreate !== undefined) {
|
||||
out.disableAutoCreate = !whitelisted.enableAutoCreate;
|
||||
}
|
||||
if (out.disableFolderNote !== undefined) {
|
||||
out.disableFolderNote = !whitelisted.enableFolderNote;
|
||||
}
|
||||
if (out.disableSync !== undefined) {
|
||||
out.disableSync = !whitelisted.enableSync;
|
||||
}
|
||||
out.enableCollapsing = !whitelisted.disableCollapsing;
|
||||
if (out.excludeFromFolderOverview !== undefined) {
|
||||
out.excludeFromFolderOverview = !whitelisted.showInFolderOverview;
|
||||
}
|
||||
out.showFolderNote = !whitelisted.hideInFileExplorer;
|
||||
return out;
|
||||
}
|
||||
|
||||
if (whitelistedFolder && excludedFolder && !ignoreWhitelist) {
|
||||
excludedFolder.disableAutoCreate ? excludedFolder.disableAutoCreate = !whitelistedFolder.enableAutoCreate : '';
|
||||
excludedFolder.disableFolderNote ? excludedFolder.disableFolderNote = !whitelistedFolder.enableFolderNote : '';
|
||||
excludedFolder.disableSync ? excludedFolder.disableSync = !whitelistedFolder.enableSync : '';
|
||||
excludedFolder.enableCollapsing = !whitelistedFolder.disableCollapsing;
|
||||
excludedFolder.excludeFromFolderOverview ? excludedFolder.excludeFromFolderOverview = !whitelistedFolder.showInFolderOverview : '';
|
||||
excludedFolder.showFolderNote = !whitelistedFolder.hideInFileExplorer;
|
||||
} else if (excludedFolder && Object.keys(excludedFolder).length === 0) {
|
||||
excludedFolder = {
|
||||
function defaultExcludedIfEmpty(
|
||||
value: Partial<ExcludedFolder> | undefined,
|
||||
): ExcludedFolder | undefined {
|
||||
if (value && Object.keys(value).length === 0) {
|
||||
return {
|
||||
type: 'folder',
|
||||
id: '',
|
||||
path: '',
|
||||
|
|
@ -77,92 +101,153 @@ export function getExcludedFolder(plugin: FolderNotesPlugin, path: string, inclu
|
|||
showFolderNote: false,
|
||||
};
|
||||
}
|
||||
|
||||
return excludedFolder;
|
||||
return value as ExcludedFolder | undefined;
|
||||
}
|
||||
|
||||
export function getDetachedFolder(plugin: FolderNotesPlugin, path: string) {
|
||||
export function getExcludedFolder(
|
||||
plugin: FolderNotesPlugin,
|
||||
path: string,
|
||||
includeDetached: boolean,
|
||||
pathOnly?: boolean,
|
||||
ignoreWhitelist?: boolean,
|
||||
): ExcludedFolder | ExcludePattern | undefined {
|
||||
const combined = combineExcluded(plugin, path, includeDetached, pathOnly);
|
||||
let excluded = aggregateFlags(combined);
|
||||
|
||||
const whitelist = getWhitelistedFolder(
|
||||
plugin,
|
||||
path,
|
||||
) as WhitelistedFolder | WhitelistedPattern | undefined;
|
||||
|
||||
let skipWhitelist = ignoreWhitelist ?? false;
|
||||
if (excluded?.detached) skipWhitelist = true;
|
||||
|
||||
if (whitelist && excluded && !skipWhitelist) {
|
||||
excluded = applyWhitelistOverrides(excluded, whitelist);
|
||||
}
|
||||
|
||||
return defaultExcludedIfEmpty(excluded) as ExcludedFolder | ExcludePattern | undefined;
|
||||
}
|
||||
|
||||
export function getDetachedFolder(
|
||||
plugin: FolderNotesPlugin,
|
||||
path: string,
|
||||
): ExcludedFolder | undefined {
|
||||
return plugin.settings.excludeFolders.find((f) => f.path === path && f.detached);
|
||||
}
|
||||
|
||||
|
||||
export function getExcludedFolderByPath(plugin: FolderNotesPlugin, path: string) {
|
||||
export function getExcludedFolderByPath(
|
||||
plugin: FolderNotesPlugin,
|
||||
path: string,
|
||||
): ExcludedFolder | undefined {
|
||||
return plugin.settings.excludeFolders.find((excludedFolder) => {
|
||||
if (path.trim() === '' || !excludedFolder.path) { return false; }
|
||||
if (excludedFolder.path === path) { return true; }
|
||||
if (!excludedFolder.subFolders) { return false; }
|
||||
const excludedFolderPath = excludedFolder.path.includes('/') ? excludedFolder.path : excludedFolder.path + '/';
|
||||
const excludedFolderPath = excludedFolder.path.includes('/')
|
||||
? excludedFolder.path
|
||||
: `${excludedFolder.path}/`;
|
||||
let folderPath = getFolderPathFromString(path);
|
||||
folderPath = folderPath.includes('/') ? folderPath : folderPath + '/';
|
||||
folderPath = folderPath.includes('/') ? folderPath : `${folderPath}/`;
|
||||
|
||||
if (folderPath.includes('/') || folderPath.includes('\\')) {
|
||||
return folderPath.startsWith(excludedFolderPath) || folderPath === excludedFolderPath;
|
||||
} else {
|
||||
return folderPath === excludedFolderPath;
|
||||
}
|
||||
return folderPath === excludedFolderPath;
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
export function getExcludedFoldersByPath(plugin: FolderNotesPlugin, path: string) {
|
||||
export function getExcludedFoldersByPath(
|
||||
plugin: FolderNotesPlugin,
|
||||
path: string,
|
||||
): ExcludedFolder[] {
|
||||
return plugin.settings.excludeFolders.filter((excludedFolder) => {
|
||||
if (path.trim() === '' || !excludedFolder.path) { return false; }
|
||||
if (excludedFolder.path === path) { return true; }
|
||||
if (!excludedFolder.subFolders) { return false; }
|
||||
const excludedFolderPath = excludedFolder.path.includes('/') ? excludedFolder.path : excludedFolder.path + '/';
|
||||
const excludedFolderPath = excludedFolder.path.includes('/')
|
||||
? excludedFolder.path
|
||||
: `${excludedFolder.path}/`;
|
||||
let folderPath = getFolderPathFromString(path);
|
||||
folderPath = folderPath.includes('/') ? folderPath : folderPath + '/';
|
||||
folderPath = folderPath.includes('/') ? folderPath : `${folderPath}/`;
|
||||
|
||||
if (folderPath.includes('/') || folderPath.includes('\\')) {
|
||||
return folderPath.startsWith(excludedFolderPath) || folderPath === excludedFolderPath;
|
||||
} else {
|
||||
return folderPath === excludedFolderPath;
|
||||
}
|
||||
return folderPath === excludedFolderPath;
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
export function addExcludedFolder(plugin: FolderNotesPlugin, excludedFolder: ExcludedFolder, reloadStyles = true) {
|
||||
export function addExcludedFolder(
|
||||
plugin: FolderNotesPlugin,
|
||||
excludedFolder: ExcludedFolder,
|
||||
reloadStyles = true,
|
||||
): void {
|
||||
plugin.settings.excludeFolders.push(excludedFolder);
|
||||
plugin.saveSettings(reloadStyles);
|
||||
void plugin.saveSettings(reloadStyles);
|
||||
}
|
||||
|
||||
export async function deleteExcludedFolder(plugin: FolderNotesPlugin, excludedFolder: ExcludedFolder) {
|
||||
plugin.settings.excludeFolders = plugin.settings.excludeFolders.filter((folder) => folder.id !== excludedFolder.id || folder.type === 'pattern');
|
||||
plugin.saveSettings(true);
|
||||
export async function deleteExcludedFolder(
|
||||
plugin: FolderNotesPlugin,
|
||||
excludedFolder: ExcludedFolder,
|
||||
): Promise<void> {
|
||||
plugin.settings.excludeFolders = plugin.settings.excludeFolders.filter(
|
||||
(folder) => folder.id !== excludedFolder.id || folder.type === 'pattern',
|
||||
);
|
||||
await plugin.saveSettings(true);
|
||||
resyncArray(plugin);
|
||||
}
|
||||
|
||||
export function updateExcludedFolder(plugin: FolderNotesPlugin, excludedFolder: ExcludePattern, newExcludeFolder: ExcludePattern) {
|
||||
plugin.settings.excludeFolders = plugin.settings.excludeFolders.filter((folder) => folder.id !== excludedFolder.id);
|
||||
export function updateExcludedFolder(
|
||||
plugin: FolderNotesPlugin,
|
||||
excludedFolder: ExcludePattern,
|
||||
newExcludeFolder: ExcludePattern,
|
||||
): void {
|
||||
plugin.settings.excludeFolders = plugin.settings.excludeFolders.filter(
|
||||
(folder) => folder.id !== excludedFolder.id,
|
||||
);
|
||||
addExcludedFolder(plugin, newExcludeFolder);
|
||||
}
|
||||
|
||||
export function resyncArray(plugin: FolderNotesPlugin) {
|
||||
plugin.settings.excludeFolders = plugin.settings.excludeFolders.sort((a, b) => a.position - b.position);
|
||||
export function resyncArray(plugin: FolderNotesPlugin): void {
|
||||
plugin.settings.excludeFolders = plugin.settings.excludeFolders.sort(
|
||||
(a, b) => a.position - b.position,
|
||||
);
|
||||
plugin.settings.excludeFolders.forEach((folder, index) => {
|
||||
folder.position = index;
|
||||
});
|
||||
plugin.saveSettings();
|
||||
void plugin.saveSettings();
|
||||
}
|
||||
|
||||
|
||||
export function addExcludeFolderListItem(settings: SettingsTab, containerEl: HTMLElement, excludedFolder: ExcludedFolder) {
|
||||
const plugin: FolderNotesPlugin = settings.plugin;
|
||||
export function addExcludeFolderListItem(
|
||||
settings: SettingsTab,
|
||||
containerEl: HTMLElement,
|
||||
excludedFolder: ExcludedFolder,
|
||||
): void {
|
||||
const { plugin } = settings;
|
||||
const setting = new Setting(containerEl);
|
||||
setting.setClass('fn-exclude-folder-list');
|
||||
setting.addSearch((cb) => {
|
||||
new FolderSuggest(
|
||||
cb.inputEl,
|
||||
plugin,
|
||||
false
|
||||
false,
|
||||
);
|
||||
// @ts-ignore
|
||||
// @ts-expect-error Obsidian's public types don't include this property
|
||||
cb.containerEl.addClass('fn-exclude-folder-path');
|
||||
cb.setPlaceholder('Folder path');
|
||||
cb.setValue(excludedFolder.path || '');
|
||||
cb.onChange((value) => {
|
||||
if (value.startsWith('{regex}') || value.includes('*')) {
|
||||
deleteExcludedFolder(plugin, excludedFolder);
|
||||
const pattern = new ExcludePattern(value, plugin.settings.excludeFolders.length, undefined, plugin);
|
||||
const pattern = new ExcludePattern(
|
||||
value,
|
||||
plugin.settings.excludeFolders.length,
|
||||
undefined,
|
||||
plugin,
|
||||
);
|
||||
addExcludedFolder(plugin, pattern);
|
||||
addExcludePatternListItem(settings, containerEl, pattern);
|
||||
setting.clear();
|
||||
|
|
@ -190,7 +275,9 @@ export function addExcludeFolderListItem(settings: SettingsTab, containerEl: HTM
|
|||
if (excludedFolder.position === 0) { return; }
|
||||
excludedFolder.position -= 1;
|
||||
updateExcludedFolder(plugin, excludedFolder, excludedFolder);
|
||||
const oldExcludedFolder = plugin.settings.excludeFolders.find((folder) => folder.position === excludedFolder.position);
|
||||
const oldExcludedFolder = plugin.settings.excludeFolders.find(
|
||||
(folder) => folder.position === excludedFolder.position,
|
||||
);
|
||||
if (oldExcludedFolder) {
|
||||
oldExcludedFolder.position += 1;
|
||||
if (oldExcludedFolder.type === 'pattern') {
|
||||
|
|
@ -213,7 +300,9 @@ export function addExcludeFolderListItem(settings: SettingsTab, containerEl: HTM
|
|||
excludedFolder.position += 1;
|
||||
|
||||
updateExcludedFolder(plugin, excludedFolder, excludedFolder);
|
||||
const oldExcludedFolder = plugin.settings.excludeFolders.find((folder) => folder.position === excludedFolder.position);
|
||||
const oldExcludedFolder = plugin.settings.excludeFolders.find(
|
||||
(folder) => folder.position === excludedFolder.position,
|
||||
);
|
||||
if (oldExcludedFolder) {
|
||||
oldExcludedFolder.position -= 1;
|
||||
if (oldExcludedFolder.type === 'pattern') {
|
||||
|
|
|
|||
|
|
@ -1,83 +1,101 @@
|
|||
import FolderNotesPlugin from '../../main';
|
||||
import { ExcludePattern } from '../ExcludePattern';
|
||||
import type FolderNotesPlugin from '../../main';
|
||||
import type { ExcludePattern } from '../ExcludePattern';
|
||||
import { Setting, Platform } from 'obsidian';
|
||||
import { SettingsTab } from '../../settings/SettingsTab';
|
||||
import type { SettingsTab } from '../../settings/SettingsTab';
|
||||
import { addExcludedFolder, resyncArray, updateExcludedFolder } from './folderFunctions';
|
||||
import PatternSettings from '../modals/PatternSettings';
|
||||
|
||||
export function updatePattern(plugin: FolderNotesPlugin, pattern: ExcludePattern, newPattern: ExcludePattern) {
|
||||
plugin.settings.excludeFolders = plugin.settings.excludeFolders.filter((folder) => folder.id !== pattern.id);
|
||||
const REGEX_PREFIX = '{regex}';
|
||||
const STAR = '*';
|
||||
const INDEX_START = 0;
|
||||
const SLICE_START_ONE = 1;
|
||||
const SLICE_EXCLUDE_LAST = -1;
|
||||
|
||||
function matchesPatternSpec(raw: string | undefined, folderName: string): boolean {
|
||||
if (!raw) return false;
|
||||
const string = raw.trim();
|
||||
const isRegex = string.startsWith(REGEX_PREFIX);
|
||||
const hasStartStar = string.startsWith(STAR);
|
||||
const hasEndStar = string.endsWith(STAR);
|
||||
if (!isRegex && !(hasStartStar || hasEndStar)) return false;
|
||||
|
||||
if (isRegex) {
|
||||
const body = string.replace(REGEX_PREFIX, '').trim();
|
||||
if (body === '') return false;
|
||||
try {
|
||||
return new RegExp(body).test(folderName);
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (hasStartStar && hasEndStar) {
|
||||
const inner = string.slice(SLICE_START_ONE, SLICE_EXCLUDE_LAST);
|
||||
return folderName.includes(inner);
|
||||
}
|
||||
if (hasStartStar) {
|
||||
const suffix = string.slice(SLICE_START_ONE);
|
||||
return folderName.endsWith(suffix);
|
||||
}
|
||||
if (hasEndStar) {
|
||||
const prefix = string.slice(INDEX_START, SLICE_EXCLUDE_LAST);
|
||||
return folderName.startsWith(prefix);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
export function updatePattern(
|
||||
plugin: FolderNotesPlugin,
|
||||
pattern: ExcludePattern,
|
||||
newPattern: ExcludePattern,
|
||||
): void {
|
||||
plugin.settings.excludeFolders = plugin.settings.excludeFolders.filter(
|
||||
(folder) => folder.id !== pattern.id,
|
||||
);
|
||||
addExcludedFolder(plugin, newPattern);
|
||||
}
|
||||
|
||||
export function deletePattern(plugin: FolderNotesPlugin, pattern: ExcludePattern) {
|
||||
plugin.settings.excludeFolders = plugin.settings.excludeFolders.filter((folder) => folder.id !== pattern.id || folder.type === 'folder');
|
||||
plugin.saveSettings(true);
|
||||
export async function deletePattern(
|
||||
plugin: FolderNotesPlugin,
|
||||
pattern: ExcludePattern,
|
||||
): Promise<void> {
|
||||
plugin.settings.excludeFolders = plugin.settings.excludeFolders.filter(
|
||||
(folder) => folder.id !== pattern.id || folder.type === 'folder',
|
||||
);
|
||||
await plugin.saveSettings(true);
|
||||
resyncArray(plugin);
|
||||
}
|
||||
|
||||
export function getExcludedFoldersByPattern(plugin: FolderNotesPlugin, folderName: string): ExcludePattern[] {
|
||||
return plugin.settings.excludeFolders.filter((s) => s.type === 'pattern').filter((pattern) => {
|
||||
if (!pattern.string) { return false; }
|
||||
const string = pattern.string.trim();
|
||||
if (!string.startsWith('{regex}') && !(string.startsWith('*') || string.endsWith('*'))) { return false; }
|
||||
const regex = string.replace('{regex}', '').trim();
|
||||
if (string.startsWith('{regex}') && regex === '') { return false; }
|
||||
if (regex !== undefined && string.startsWith('{regex}')) {
|
||||
const match = new RegExp(regex).exec(folderName);
|
||||
if (match) {
|
||||
return true;
|
||||
}
|
||||
} else if (string.startsWith('*') && string.endsWith('*')) {
|
||||
if (folderName.includes(string.slice(1, -1))) {
|
||||
return true;
|
||||
}
|
||||
} else if (string.startsWith('*')) {
|
||||
if (folderName.endsWith(string.slice(1))) {
|
||||
return true;
|
||||
}
|
||||
} else if (string.endsWith('*')) {
|
||||
if (folderName.startsWith(string.slice(0, -1))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
});
|
||||
export function getExcludedFoldersByPattern(
|
||||
plugin: FolderNotesPlugin,
|
||||
folderName: string,
|
||||
): ExcludePattern[] {
|
||||
return plugin.settings.excludeFolders
|
||||
.filter((s) => s.type === 'pattern')
|
||||
.filter((pattern) => matchesPatternSpec(pattern.string, folderName)) as ExcludePattern[];
|
||||
}
|
||||
|
||||
export function getExcludedFolderByPattern(plugin: FolderNotesPlugin, folderName: string): ExcludePattern | undefined{
|
||||
return plugin.settings.excludeFolders.filter((s) => s.type === 'pattern').find((pattern) => {
|
||||
if (!pattern.string) { return false; }
|
||||
const string = pattern.string.trim();
|
||||
if (!string.startsWith('{regex}') && !(string.startsWith('*') || string.endsWith('*'))) { return false; }
|
||||
const regex = string.replace('{regex}', '').trim();
|
||||
if (string.startsWith('{regex}') && regex === '') { return false; }
|
||||
if (regex !== undefined && string.startsWith('{regex}')) {
|
||||
const match = new RegExp(regex).exec(folderName);
|
||||
if (match) {
|
||||
return true;
|
||||
}
|
||||
} else if (string.startsWith('*') && string.endsWith('*')) {
|
||||
if (folderName.includes(string.slice(1, -1))) {
|
||||
return true;
|
||||
}
|
||||
} else if (string.startsWith('*')) {
|
||||
if (folderName.endsWith(string.slice(1))) {
|
||||
return true;
|
||||
}
|
||||
} else if (string.endsWith('*')) {
|
||||
if (folderName.startsWith(string.slice(0, -1))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
});
|
||||
export function getExcludedFolderByPattern(
|
||||
plugin: FolderNotesPlugin,
|
||||
folderName: string,
|
||||
): ExcludePattern | undefined {
|
||||
return (
|
||||
plugin.settings.excludeFolders
|
||||
.filter((s) => s.type === 'pattern')
|
||||
.find((pattern) => matchesPatternSpec(pattern.string, folderName))
|
||||
) as ExcludePattern | undefined;
|
||||
}
|
||||
|
||||
export function addExcludePatternListItem(settings: SettingsTab, containerEl: HTMLElement, pattern: ExcludePattern) {
|
||||
const plugin: FolderNotesPlugin = settings.plugin;
|
||||
export function addExcludePatternListItem(
|
||||
settings: SettingsTab,
|
||||
containerEl: HTMLElement,
|
||||
pattern: ExcludePattern,
|
||||
): void {
|
||||
const { plugin } = settings;
|
||||
const setting = new Setting(containerEl);
|
||||
setting.setClass('fn-exclude-folder-list');
|
||||
setting.addSearch((cb) => {
|
||||
// @ts-ignore
|
||||
// @ts-expect-error Obsidian's public types don't include containerEl on this control
|
||||
cb.containerEl.addClass('fn-exclude-folder-path');
|
||||
cb.setPlaceholder('Pattern');
|
||||
cb.setValue(pattern.string);
|
||||
|
|
@ -102,11 +120,18 @@ export function addExcludePatternListItem(settings: SettingsTab, containerEl: HT
|
|||
if (pattern.position === 0) { return; }
|
||||
pattern.position -= 1;
|
||||
updatePattern(plugin, pattern, pattern);
|
||||
const oldPattern = plugin.settings.excludeFolders.find((folder) => folder.position === pattern.position);
|
||||
const oldPattern = plugin.settings.excludeFolders.find(
|
||||
(folder) => folder.position === pattern.position,
|
||||
);
|
||||
if (oldPattern) {
|
||||
oldPattern.position += 1;
|
||||
if (oldPattern.type === 'pattern') {
|
||||
updatePattern(plugin, oldPattern, oldPattern);
|
||||
const pat = oldPattern as ExcludePattern;
|
||||
updatePattern(
|
||||
plugin,
|
||||
pat,
|
||||
pat,
|
||||
);
|
||||
} else {
|
||||
updateExcludedFolder(plugin, oldPattern, oldPattern);
|
||||
}
|
||||
|
|
@ -125,11 +150,18 @@ export function addExcludePatternListItem(settings: SettingsTab, containerEl: HT
|
|||
pattern.position += 1;
|
||||
|
||||
updatePattern(plugin, pattern, pattern);
|
||||
const oldPattern = plugin.settings.excludeFolders.find((folder) => folder.position === pattern.position);
|
||||
const oldPattern = plugin.settings.excludeFolders.find(
|
||||
(folder) => folder.position === pattern.position,
|
||||
);
|
||||
if (oldPattern) {
|
||||
oldPattern.position -= 1;
|
||||
if (oldPattern.type === 'pattern') {
|
||||
updatePattern(plugin, oldPattern, oldPattern);
|
||||
const pat = oldPattern as ExcludePattern;
|
||||
updatePattern(
|
||||
plugin,
|
||||
pat,
|
||||
pat,
|
||||
);
|
||||
} else {
|
||||
updateExcludedFolder(plugin, oldPattern, oldPattern);
|
||||
}
|
||||
|
|
@ -143,7 +175,7 @@ export function addExcludePatternListItem(settings: SettingsTab, containerEl: HT
|
|||
cb.setIcon('trash-2');
|
||||
cb.setTooltip('Delete pattern');
|
||||
cb.onClick(() => {
|
||||
deletePattern(plugin, pattern);
|
||||
void deletePattern(plugin, pattern);
|
||||
setting.clear();
|
||||
setting.settingEl.remove();
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,16 +1,22 @@
|
|||
import FolderNotesPlugin from '../../main';
|
||||
import type FolderNotesPlugin from '../../main';
|
||||
import { getFolderNameFromPathString, getFolderPathFromString } from '../../functions/utils';
|
||||
import { WhitelistedFolder } from '../WhitelistFolder';
|
||||
import type { WhitelistedFolder } from '../WhitelistFolder';
|
||||
import { WhitelistedPattern } from '../WhitelistPattern';
|
||||
import { Setting, Platform, ButtonComponent } from 'obsidian';
|
||||
import { Setting, ButtonComponent } from 'obsidian';
|
||||
import { FolderSuggest } from '../../suggesters/FolderSuggester';
|
||||
import { SettingsTab } from '../../settings/SettingsTab';
|
||||
import type { SettingsTab } from '../../settings/SettingsTab';
|
||||
import WhitelistFolderSettings from '../modals/WhitelistFolderSettings';
|
||||
import { updateWhitelistedPattern, getWhitelistedFoldersByPattern, addWhitelistedPatternListItem } from './whitelistPatternFunctions';
|
||||
Platform.isMobileApp;
|
||||
import {
|
||||
updateWhitelistedPattern,
|
||||
getWhitelistedFoldersByPattern,
|
||||
addWhitelistedPatternListItem,
|
||||
} from './whitelistPatternFunctions';
|
||||
|
||||
export function getWhitelistedFolder(plugin: FolderNotesPlugin, path: string) {
|
||||
let whitelistedFolder = {} as WhitelistedFolder | WhitelistedPattern | undefined;
|
||||
export function getWhitelistedFolder(
|
||||
plugin: FolderNotesPlugin,
|
||||
path: string,
|
||||
): WhitelistedFolder | WhitelistedPattern | undefined {
|
||||
let whitelistedFolder: Partial<WhitelistedFolder> | undefined = {};
|
||||
const folderName = getFolderNameFromPathString(path);
|
||||
const matchedPatterns = getWhitelistedFoldersByPattern(plugin, folderName);
|
||||
const whitelistedFolders = getWhitelistedFoldersByPath(plugin, path);
|
||||
|
|
@ -25,21 +31,30 @@ export function getWhitelistedFolder(plugin: FolderNotesPlugin, path: string) {
|
|||
if (combinedWhitelistedFolders.length > 0) {
|
||||
for (const matchedFolder of combinedWhitelistedFolders) {
|
||||
propertiesToCopy.forEach((property) => {
|
||||
if (matchedFolder[property] === true) {
|
||||
(whitelistedFolder as any)[property] = true;
|
||||
} else if (!matchedFolder[property]) {
|
||||
(whitelistedFolder as any)[property] = false;
|
||||
const value = (matchedFolder as Partial<WhitelistedFolder>)[property];
|
||||
if (value === true) {
|
||||
(whitelistedFolder as Partial<WhitelistedFolder>)[property] = true as never;
|
||||
} else if (!value) {
|
||||
(whitelistedFolder as Partial<WhitelistedFolder>)[property] = false as never;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if ((whitelistedFolder instanceof Object) && Object.keys(whitelistedFolder).length === 0) { whitelistedFolder = undefined; }
|
||||
if (
|
||||
whitelistedFolder
|
||||
&& Object.keys(whitelistedFolder).length === 0
|
||||
) {
|
||||
whitelistedFolder = undefined;
|
||||
}
|
||||
|
||||
return whitelistedFolder;
|
||||
return whitelistedFolder as WhitelistedFolder | WhitelistedPattern | undefined;
|
||||
}
|
||||
|
||||
export function getWhitelistedFolderByPath(plugin: FolderNotesPlugin, path: string) {
|
||||
export function getWhitelistedFolderByPath(
|
||||
plugin: FolderNotesPlugin,
|
||||
path: string,
|
||||
): WhitelistedFolder | WhitelistedPattern | undefined {
|
||||
return plugin.settings.whitelistFolders.find((whitelistedFolder) => {
|
||||
if (whitelistedFolder.path === path) { return true; }
|
||||
if (!whitelistedFolder.subFolders) { return false; }
|
||||
|
|
@ -47,7 +62,10 @@ export function getWhitelistedFolderByPath(plugin: FolderNotesPlugin, path: stri
|
|||
});
|
||||
}
|
||||
|
||||
export function getWhitelistedFoldersByPath(plugin: FolderNotesPlugin, path: string) {
|
||||
export function getWhitelistedFoldersByPath(
|
||||
plugin: FolderNotesPlugin,
|
||||
path: string,
|
||||
): Array<WhitelistedFolder | WhitelistedPattern> {
|
||||
return plugin.settings.whitelistFolders.filter((whitelistedFolder) => {
|
||||
if (whitelistedFolder.path === path) { return true; }
|
||||
if (!whitelistedFolder.subFolders) { return false; }
|
||||
|
|
@ -55,52 +73,78 @@ export function getWhitelistedFoldersByPath(plugin: FolderNotesPlugin, path: str
|
|||
});
|
||||
}
|
||||
|
||||
export function addWhitelistedFolder(plugin: FolderNotesPlugin, whitelistedFolder: WhitelistedFolder) {
|
||||
export function addWhitelistedFolder(
|
||||
plugin: FolderNotesPlugin,
|
||||
whitelistedFolder: WhitelistedFolder | WhitelistedPattern,
|
||||
): void {
|
||||
plugin.settings.whitelistFolders.push(whitelistedFolder);
|
||||
plugin.saveSettings(true);
|
||||
void plugin.saveSettings(true);
|
||||
}
|
||||
|
||||
export function deleteWhitelistedFolder(plugin: FolderNotesPlugin, whitelistedFolder: WhitelistedFolder) {
|
||||
plugin.settings.whitelistFolders = plugin.settings.whitelistFolders.filter((folder) => folder.id !== whitelistedFolder.id || folder.type === 'pattern');
|
||||
plugin.saveSettings(true);
|
||||
export async function deleteWhitelistedFolder(
|
||||
plugin: FolderNotesPlugin,
|
||||
whitelistedFolder: WhitelistedFolder | WhitelistedPattern,
|
||||
): Promise<void> {
|
||||
plugin.settings.whitelistFolders = plugin.settings.whitelistFolders.filter(
|
||||
(folder) => folder.id !== whitelistedFolder.id || folder.type === 'pattern',
|
||||
);
|
||||
await plugin.saveSettings(true);
|
||||
resyncArray(plugin);
|
||||
}
|
||||
|
||||
export function updateWhitelistedFolder(plugin: FolderNotesPlugin, whitelistedFolder: WhitelistedFolder, newWhitelistFolder: WhitelistedFolder) {
|
||||
plugin.settings.whitelistFolders = plugin.settings.whitelistFolders.filter((folder) => folder.id !== whitelistedFolder.id);
|
||||
export function updateWhitelistedFolder(
|
||||
plugin: FolderNotesPlugin,
|
||||
whitelistedFolder: WhitelistedFolder,
|
||||
newWhitelistFolder: WhitelistedFolder,
|
||||
): void {
|
||||
plugin.settings.whitelistFolders = plugin.settings.whitelistFolders.filter(
|
||||
(folder) => folder.id !== whitelistedFolder.id,
|
||||
);
|
||||
addWhitelistedFolder(plugin, newWhitelistFolder);
|
||||
}
|
||||
|
||||
export function resyncArray(plugin: FolderNotesPlugin) {
|
||||
plugin.settings.whitelistFolders = plugin.settings.whitelistFolders.sort((a, b) => a.position - b.position);
|
||||
export function resyncArray(plugin: FolderNotesPlugin): void {
|
||||
plugin.settings.whitelistFolders = plugin.settings.whitelistFolders.sort(
|
||||
(a, b) => a.position - b.position,
|
||||
);
|
||||
plugin.settings.whitelistFolders.forEach((folder, index) => {
|
||||
folder.position = index;
|
||||
});
|
||||
plugin.saveSettings();
|
||||
void plugin.saveSettings();
|
||||
}
|
||||
|
||||
|
||||
export function addWhitelistFolderListItem(settings: SettingsTab, containerEl: HTMLElement, whitelistedFolder: WhitelistedFolder) {
|
||||
const plugin: FolderNotesPlugin = settings.plugin;
|
||||
export function addWhitelistFolderListItem(
|
||||
settings: SettingsTab,
|
||||
containerEl: HTMLElement,
|
||||
whitelistedFolder: WhitelistedFolder,
|
||||
): void {
|
||||
const { plugin } = settings;
|
||||
const setting = new Setting(containerEl);
|
||||
setting.setClass('fn-exclude-folder-list');
|
||||
|
||||
const inputContainer = setting.settingEl.createDiv({ cls: 'fn-whitelist-folder-input-container' });
|
||||
const inputContainer = setting.settingEl.createDiv({
|
||||
cls: 'fn-whitelist-folder-input-container',
|
||||
});
|
||||
const SearchComponent = new Setting(inputContainer);
|
||||
SearchComponent.addSearch((cb) => {
|
||||
new FolderSuggest(
|
||||
cb.inputEl,
|
||||
plugin,
|
||||
true
|
||||
true,
|
||||
);
|
||||
// @ts-ignore
|
||||
// @ts-expect-error Obsidian's public types don't include this property
|
||||
cb.containerEl.addClass('fn-exclude-folder-path');
|
||||
cb.setPlaceholder('Folder path');
|
||||
cb.setValue(whitelistedFolder.path);
|
||||
cb.onChange((value) => {
|
||||
if (value.startsWith('{regex}') || value.includes('*')) {
|
||||
deleteWhitelistedFolder(plugin, whitelistedFolder);
|
||||
const pattern = new WhitelistedPattern(value, plugin.settings.whitelistFolders.length, undefined, plugin);
|
||||
void deleteWhitelistedFolder(plugin, whitelistedFolder);
|
||||
const pattern = new WhitelistedPattern(
|
||||
value,
|
||||
plugin.settings.whitelistFolders.length,
|
||||
undefined,
|
||||
plugin,
|
||||
);
|
||||
addWhitelistedFolder(plugin, pattern);
|
||||
addWhitelistedPatternListItem(settings, containerEl, pattern);
|
||||
setting.clear();
|
||||
|
|
@ -127,7 +171,9 @@ export function addWhitelistFolderListItem(settings: SettingsTab, containerEl: H
|
|||
if (whitelistedFolder.position === 0) { return; }
|
||||
whitelistedFolder.position -= 1;
|
||||
updateWhitelistedFolder(plugin, whitelistedFolder, whitelistedFolder);
|
||||
const oldWhitelistedFolder = plugin.settings.whitelistFolders.find((folder) => folder.position === whitelistedFolder.position);
|
||||
const oldWhitelistedFolder = plugin.settings.whitelistFolders.find(
|
||||
(folder) => folder.position === whitelistedFolder.position,
|
||||
);
|
||||
if (oldWhitelistedFolder) {
|
||||
oldWhitelistedFolder.position += 1;
|
||||
if (oldWhitelistedFolder.type === 'pattern') {
|
||||
|
|
@ -149,7 +195,9 @@ export function addWhitelistFolderListItem(settings: SettingsTab, containerEl: H
|
|||
whitelistedFolder.position += 1;
|
||||
|
||||
updateWhitelistedFolder(plugin, whitelistedFolder, whitelistedFolder);
|
||||
const oldWhitelistedFolder = plugin.settings.whitelistFolders.find((folder) => folder.position === whitelistedFolder.position);
|
||||
const oldWhitelistedFolder = plugin.settings.whitelistFolders.find(
|
||||
(folder) => folder.position === whitelistedFolder.position,
|
||||
);
|
||||
if (oldWhitelistedFolder) {
|
||||
oldWhitelistedFolder.position -= 1;
|
||||
if (oldWhitelistedFolder.type === 'pattern') {
|
||||
|
|
@ -166,7 +214,7 @@ export function addWhitelistFolderListItem(settings: SettingsTab, containerEl: H
|
|||
.setIcon('trash-2')
|
||||
.setTooltip('Delete excluded folder')
|
||||
.onClick(() => {
|
||||
deleteWhitelistedFolder(plugin, whitelistedFolder);
|
||||
void deleteWhitelistedFolder(plugin, whitelistedFolder);
|
||||
setting.clear();
|
||||
setting.settingEl.remove();
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,89 +1,111 @@
|
|||
import FolderNotesPlugin from '../../main';
|
||||
import type FolderNotesPlugin from '../../main';
|
||||
import { Setting } from 'obsidian';
|
||||
import { SettingsTab } from '../../settings/SettingsTab';
|
||||
import type { SettingsTab } from '../../settings/SettingsTab';
|
||||
import { resyncArray } from './folderFunctions';
|
||||
import WhitelistPatternSettings from '../modals/WhitelistPatternSettings';
|
||||
import { WhitelistedPattern } from '../WhitelistPattern';
|
||||
import type { WhitelistedPattern } from '../WhitelistPattern';
|
||||
import { addWhitelistedFolder, updateWhitelistedFolder } from './whitelistFolderFunctions';
|
||||
|
||||
export function updateWhitelistedPattern(plugin: FolderNotesPlugin, pattern: WhitelistedPattern, newPattern: WhitelistedPattern) {
|
||||
plugin.settings.whitelistFolders = plugin.settings.whitelistFolders.filter((folder) => folder.id !== pattern.id);
|
||||
const REGEX_PREFIX = '{regex}';
|
||||
const STAR = '*';
|
||||
const SLICE_START_ONE = 1;
|
||||
const SLICE_EXCLUDE_LAST = -1;
|
||||
|
||||
function matchesPatternSpec(raw: string | undefined, folderName: string): boolean {
|
||||
if (!raw) return false;
|
||||
const string = raw.trim();
|
||||
const isRegex = string.startsWith(REGEX_PREFIX);
|
||||
const hasStartStar = string.startsWith(STAR);
|
||||
const hasEndStar = string.endsWith(STAR);
|
||||
if (!isRegex && !(hasStartStar || hasEndStar)) return false;
|
||||
|
||||
if (isRegex) {
|
||||
const body = string.replace(REGEX_PREFIX, '').trim();
|
||||
if (body === '') return false;
|
||||
try {
|
||||
return new RegExp(body).test(folderName);
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (hasStartStar && hasEndStar) {
|
||||
const inner = string.slice(SLICE_START_ONE, SLICE_EXCLUDE_LAST);
|
||||
return folderName.includes(inner);
|
||||
}
|
||||
if (hasStartStar) {
|
||||
const suffix = string.slice(SLICE_START_ONE);
|
||||
return folderName.endsWith(suffix);
|
||||
}
|
||||
if (hasEndStar) {
|
||||
const prefix = string.slice(0, SLICE_EXCLUDE_LAST);
|
||||
return folderName.startsWith(prefix);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
export function updateWhitelistedPattern(
|
||||
plugin: FolderNotesPlugin,
|
||||
pattern: WhitelistedPattern,
|
||||
newPattern: WhitelistedPattern,
|
||||
): void {
|
||||
plugin.settings.whitelistFolders = plugin.settings.whitelistFolders.filter(
|
||||
(folder) => folder.id !== pattern.id,
|
||||
);
|
||||
addWhitelistedFolder(plugin, newPattern);
|
||||
}
|
||||
|
||||
export function deletePattern(plugin: FolderNotesPlugin, pattern: WhitelistedPattern) {
|
||||
plugin.settings.whitelistFolders = plugin.settings.whitelistFolders.filter((folder) => folder.id !== pattern.id || folder.type === 'folder');
|
||||
plugin.saveSettings(true);
|
||||
export async function deletePattern(
|
||||
plugin: FolderNotesPlugin,
|
||||
pattern: WhitelistedPattern,
|
||||
): Promise<void> {
|
||||
plugin.settings.whitelistFolders = plugin.settings.whitelistFolders.filter(
|
||||
(folder) => folder.id !== pattern.id || folder.type === 'folder',
|
||||
);
|
||||
await plugin.saveSettings(true);
|
||||
resyncArray(plugin);
|
||||
}
|
||||
|
||||
export function getWhitelistedFolderByPattern(plugin: FolderNotesPlugin, folderName: string) {
|
||||
return plugin.settings.whitelistFolders.filter((s) => s.type === 'pattern').find((pattern) => {
|
||||
if (!pattern.string) { return false; }
|
||||
const string = pattern.string.trim();
|
||||
if (!string.startsWith('{regex}') && !(string.startsWith('*') || string.endsWith('*'))) { return false; }
|
||||
const regex = string.replace('{regex}', '').trim();
|
||||
if (string.startsWith('{regex}') && regex === '') { return false; }
|
||||
if (regex !== undefined && string.startsWith('{regex}')) {
|
||||
const match = new RegExp(regex).exec(folderName);
|
||||
if (match) {
|
||||
return true;
|
||||
}
|
||||
} else if (string.startsWith('*') && string.endsWith('*')) {
|
||||
if (folderName.includes(string.slice(1, -1))) {
|
||||
return true;
|
||||
}
|
||||
} else if (string.startsWith('*')) {
|
||||
if (folderName.endsWith(string.slice(1))) {
|
||||
return true;
|
||||
}
|
||||
} else if (string.endsWith('*')) {
|
||||
if (folderName.startsWith(string.slice(0, -1))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
});
|
||||
export function getWhitelistedFolderByPattern(
|
||||
plugin: FolderNotesPlugin,
|
||||
folderName: string,
|
||||
): WhitelistedPattern | undefined {
|
||||
return (
|
||||
plugin.settings.whitelistFolders
|
||||
.filter((s) => s.type === 'pattern')
|
||||
.find((pattern) => matchesPatternSpec(pattern.string, folderName))
|
||||
) as WhitelistedPattern | undefined;
|
||||
}
|
||||
|
||||
export function getWhitelistedFoldersByPattern(plugin: FolderNotesPlugin, folderName: string) {
|
||||
return plugin.settings.whitelistFolders.filter((s) => s.type === 'pattern').filter((pattern) => {
|
||||
if (!pattern.string) { return false; }
|
||||
const string = pattern.string.trim();
|
||||
if (!string.startsWith('{regex}') && !(string.startsWith('*') || string.endsWith('*'))) { return false; }
|
||||
const regex = string.replace('{regex}', '').trim();
|
||||
if (string.startsWith('{regex}') && regex === '') { return false; }
|
||||
if (regex !== undefined && string.startsWith('{regex}')) {
|
||||
const match = new RegExp(regex).exec(folderName);
|
||||
if (match) {
|
||||
return true;
|
||||
}
|
||||
} else if (string.startsWith('*') && string.endsWith('*')) {
|
||||
if (folderName.includes(string.slice(1, -1))) {
|
||||
return true;
|
||||
}
|
||||
} else if (string.startsWith('*')) {
|
||||
if (folderName.endsWith(string.slice(1))) {
|
||||
return true;
|
||||
}
|
||||
} else if (string.endsWith('*')) {
|
||||
if (folderName.startsWith(string.slice(0, -1))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
});
|
||||
export function getWhitelistedFoldersByPattern(
|
||||
plugin: FolderNotesPlugin,
|
||||
folderName: string,
|
||||
): WhitelistedPattern[] {
|
||||
return (
|
||||
plugin.settings.whitelistFolders
|
||||
.filter((s) => s.type === 'pattern')
|
||||
.filter((pattern) => matchesPatternSpec(pattern.string, folderName))
|
||||
) as WhitelistedPattern[];
|
||||
}
|
||||
|
||||
export function addWhitelistedPatternListItem(settings: SettingsTab, containerEl: HTMLElement, pattern: WhitelistedPattern) {
|
||||
const plugin: FolderNotesPlugin = settings.plugin;
|
||||
export function addWhitelistedPatternListItem(
|
||||
settings: SettingsTab,
|
||||
containerEl: HTMLElement,
|
||||
pattern: WhitelistedPattern,
|
||||
): void {
|
||||
const { plugin } = settings;
|
||||
const setting = new Setting(containerEl);
|
||||
setting.setClass('fn-exclude-folder-list');
|
||||
setting.addSearch((cb) => {
|
||||
// @ts-ignore
|
||||
// @ts-expect-error Obsidian's public types don't expose containerEl on this control
|
||||
cb.containerEl.addClass('fn-exclude-folder-path');
|
||||
cb.setPlaceholder('Pattern');
|
||||
cb.setValue(pattern.string);
|
||||
cb.onChange((value) => {
|
||||
if (plugin.settings.whitelistFolders.find((folder) => folder.string === value)) { return; }
|
||||
const exists = plugin.settings.whitelistFolders.some(
|
||||
(folder) => folder.string === value,
|
||||
);
|
||||
if (exists) { return; }
|
||||
pattern.string = value;
|
||||
updateWhitelistedPattern(plugin, pattern, pattern);
|
||||
});
|
||||
|
|
@ -103,11 +125,17 @@ export function addWhitelistedPatternListItem(settings: SettingsTab, containerEl
|
|||
if (pattern.position === 0) { return; }
|
||||
pattern.position -= 1;
|
||||
updateWhitelistedPattern(plugin, pattern, pattern);
|
||||
const oldPattern = plugin.settings.whitelistFolders.find((folder) => folder.position === pattern.position);
|
||||
const oldPattern = plugin.settings.whitelistFolders.find(
|
||||
(folder) => folder.position === pattern.position,
|
||||
);
|
||||
if (oldPattern) {
|
||||
oldPattern.position += 1;
|
||||
if (oldPattern.type === 'pattern') {
|
||||
updateWhitelistedPattern(plugin, oldPattern, oldPattern);
|
||||
updateWhitelistedPattern(
|
||||
plugin,
|
||||
oldPattern as WhitelistedPattern,
|
||||
oldPattern as WhitelistedPattern,
|
||||
);
|
||||
} else {
|
||||
updateWhitelistedFolder(plugin, oldPattern, oldPattern);
|
||||
}
|
||||
|
|
@ -126,11 +154,17 @@ export function addWhitelistedPatternListItem(settings: SettingsTab, containerEl
|
|||
pattern.position += 1;
|
||||
|
||||
updateWhitelistedPattern(plugin, pattern, pattern);
|
||||
const oldPattern = plugin.settings.whitelistFolders.find((folder) => folder.position === pattern.position);
|
||||
const oldPattern = plugin.settings.whitelistFolders.find(
|
||||
(folder) => folder.position === pattern.position,
|
||||
);
|
||||
if (oldPattern) {
|
||||
oldPattern.position -= 1;
|
||||
if (oldPattern.type === 'pattern') {
|
||||
updateWhitelistedPattern(plugin, oldPattern, oldPattern);
|
||||
updateWhitelistedPattern(
|
||||
plugin,
|
||||
oldPattern as WhitelistedPattern,
|
||||
oldPattern as WhitelistedPattern,
|
||||
);
|
||||
} else {
|
||||
updateWhitelistedFolder(plugin, oldPattern, oldPattern);
|
||||
}
|
||||
|
|
@ -143,7 +177,7 @@ export function addWhitelistedPatternListItem(settings: SettingsTab, containerEl
|
|||
cb.setIcon('trash-2');
|
||||
cb.setTooltip('Delete pattern');
|
||||
cb.onClick(() => {
|
||||
deletePattern(plugin, pattern);
|
||||
void deletePattern(plugin, pattern);
|
||||
setting.clear();
|
||||
setting.settingEl.remove();
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { App, Modal, Setting } from 'obsidian';
|
||||
import FolderNotesPlugin from '../../main';
|
||||
import { ExcludedFolder } from 'src/ExcludeFolders/ExcludeFolder';
|
||||
import { Modal, Setting, type App } from 'obsidian';
|
||||
import type FolderNotesPlugin from '../../main';
|
||||
import type { ExcludedFolder } from 'src/ExcludeFolders/ExcludeFolder';
|
||||
import { updateCSSClassesForFolder } from 'src/functions/styleFunctions';
|
||||
export default class ExcludedFolderSettings extends Modal {
|
||||
plugin: FolderNotesPlugin;
|
||||
|
|
@ -12,10 +12,10 @@ export default class ExcludedFolderSettings extends Modal {
|
|||
this.app = app;
|
||||
this.excludedFolder = excludedFolder;
|
||||
}
|
||||
onOpen() {
|
||||
onOpen(): void {
|
||||
this.display();
|
||||
}
|
||||
display() {
|
||||
display(): void {
|
||||
const { contentEl } = this;
|
||||
contentEl.empty();
|
||||
contentEl.createEl('h2', { text: 'Excluded folder settings' });
|
||||
|
|
@ -28,7 +28,7 @@ export default class ExcludedFolderSettings extends Modal {
|
|||
.onChange(async (value) => {
|
||||
this.excludedFolder.subFolders = value;
|
||||
await this.plugin.saveSettings(true);
|
||||
})
|
||||
}),
|
||||
);
|
||||
|
||||
new Setting(contentEl)
|
||||
|
|
@ -40,7 +40,7 @@ export default class ExcludedFolderSettings extends Modal {
|
|||
.onChange(async (value) => {
|
||||
this.excludedFolder.disableSync = value;
|
||||
await this.plugin.saveSettings();
|
||||
})
|
||||
}),
|
||||
);
|
||||
|
||||
new Setting(contentEl)
|
||||
|
|
@ -52,7 +52,7 @@ export default class ExcludedFolderSettings extends Modal {
|
|||
.onChange(async (value) => {
|
||||
this.excludedFolder.excludeFromFolderOverview = value;
|
||||
await this.plugin.saveSettings();
|
||||
})
|
||||
}),
|
||||
);
|
||||
|
||||
new Setting(contentEl)
|
||||
|
|
@ -66,7 +66,7 @@ export default class ExcludedFolderSettings extends Modal {
|
|||
updateCSSClassesForFolder(this.excludedFolder.path, this.plugin);
|
||||
await this.plugin.saveSettings();
|
||||
this.display();
|
||||
})
|
||||
}),
|
||||
);
|
||||
|
||||
new Setting(contentEl)
|
||||
|
|
@ -78,7 +78,7 @@ export default class ExcludedFolderSettings extends Modal {
|
|||
.onChange(async (value) => {
|
||||
this.excludedFolder.disableAutoCreate = value;
|
||||
await this.plugin.saveSettings();
|
||||
})
|
||||
}),
|
||||
);
|
||||
|
||||
new Setting(contentEl)
|
||||
|
|
@ -91,7 +91,7 @@ export default class ExcludedFolderSettings extends Modal {
|
|||
this.excludedFolder.disableFolderNote = value;
|
||||
await this.plugin.saveSettings(true);
|
||||
this.display();
|
||||
})
|
||||
}),
|
||||
);
|
||||
|
||||
if (!this.excludedFolder.disableFolderNote) {
|
||||
|
|
@ -104,12 +104,12 @@ export default class ExcludedFolderSettings extends Modal {
|
|||
.onChange(async (value) => {
|
||||
this.excludedFolder.enableCollapsing = value;
|
||||
await this.plugin.saveSettings();
|
||||
})
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
onClose() {
|
||||
|
||||
onClose(): void {
|
||||
const { contentEl } = this;
|
||||
contentEl.empty();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { App, Modal, Setting } from 'obsidian';
|
||||
import FolderNotesPlugin from '../../main';
|
||||
import { ExcludePattern } from 'src/ExcludeFolders/ExcludePattern';
|
||||
import { Modal, Setting, type App } from 'obsidian';
|
||||
import type FolderNotesPlugin from '../../main';
|
||||
import type { ExcludePattern } from 'src/ExcludeFolders/ExcludePattern';
|
||||
import { refreshAllFolderStyles } from 'src/functions/styleFunctions';
|
||||
|
||||
export default class PatternSettings extends Modal {
|
||||
|
|
@ -13,16 +13,19 @@ export default class PatternSettings extends Modal {
|
|||
this.app = app;
|
||||
this.pattern = pattern;
|
||||
}
|
||||
onOpen() {
|
||||
|
||||
onOpen(): void {
|
||||
this.display();
|
||||
}
|
||||
display() {
|
||||
|
||||
display(): void {
|
||||
const { contentEl } = this;
|
||||
contentEl.empty();
|
||||
contentEl.createEl('h2', { text: 'Pattern settings' });
|
||||
|
||||
new Setting(contentEl)
|
||||
.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')
|
||||
.addToggle((toggle) =>
|
||||
toggle
|
||||
|
|
@ -30,11 +33,12 @@ export default class PatternSettings extends Modal {
|
|||
.onChange(async (value) => {
|
||||
this.pattern.disableSync = value;
|
||||
await this.plugin.saveSettings();
|
||||
})
|
||||
}),
|
||||
);
|
||||
|
||||
new Setting(contentEl)
|
||||
.setName('Disable auto creation of folder notes in this folder')
|
||||
// eslint-disable-next-line max-len
|
||||
.setDesc('Choose if a folder note should be created when a new folder is created that matches this pattern')
|
||||
.addToggle((toggle) =>
|
||||
toggle
|
||||
|
|
@ -42,7 +46,7 @@ export default class PatternSettings extends Modal {
|
|||
.onChange(async (value) => {
|
||||
this.pattern.disableAutoCreate = value;
|
||||
await this.plugin.saveSettings();
|
||||
})
|
||||
}),
|
||||
);
|
||||
|
||||
new Setting(contentEl)
|
||||
|
|
@ -54,7 +58,7 @@ export default class PatternSettings extends Modal {
|
|||
.onChange(async (value) => {
|
||||
this.pattern.excludeFromFolderOverview = value;
|
||||
await this.plugin.saveSettings();
|
||||
})
|
||||
}),
|
||||
);
|
||||
|
||||
new Setting(contentEl)
|
||||
|
|
@ -68,7 +72,7 @@ export default class PatternSettings extends Modal {
|
|||
await this.plugin.saveSettings();
|
||||
refreshAllFolderStyles(true, this.plugin);
|
||||
this.display();
|
||||
})
|
||||
}),
|
||||
);
|
||||
|
||||
new Setting(contentEl)
|
||||
|
|
@ -81,7 +85,7 @@ export default class PatternSettings extends Modal {
|
|||
this.pattern.disableFolderNote = value;
|
||||
await this.plugin.saveSettings(true);
|
||||
this.display();
|
||||
})
|
||||
}),
|
||||
);
|
||||
|
||||
if (!this.pattern.disableFolderNote) {
|
||||
|
|
@ -94,12 +98,12 @@ export default class PatternSettings extends Modal {
|
|||
.onChange(async (value) => {
|
||||
this.pattern.enableCollapsing = value;
|
||||
await this.plugin.saveSettings();
|
||||
})
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
onClose() {
|
||||
|
||||
onClose(): void {
|
||||
const { contentEl } = this;
|
||||
contentEl.empty();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { App, Modal, Setting } from 'obsidian';
|
||||
import FolderNotesPlugin from '../../main';
|
||||
import { WhitelistedFolder } from '../WhitelistFolder';
|
||||
import { Modal, Setting, type App } from 'obsidian';
|
||||
import type FolderNotesPlugin from '../../main';
|
||||
import type { WhitelistedFolder } from '../WhitelistFolder';
|
||||
export default class WhitelistFolderSettings extends Modal {
|
||||
plugin: FolderNotesPlugin;
|
||||
app: App;
|
||||
|
|
@ -11,10 +11,12 @@ export default class WhitelistFolderSettings extends Modal {
|
|||
this.app = app;
|
||||
this.whitelistedFolder = whitelistedFolder;
|
||||
}
|
||||
onOpen() {
|
||||
|
||||
onOpen(): void {
|
||||
this.display();
|
||||
}
|
||||
display() {
|
||||
|
||||
display(): void {
|
||||
const { contentEl } = this;
|
||||
contentEl.empty();
|
||||
contentEl.createEl('h2', { text: 'Whitelisted folder settings' });
|
||||
|
|
@ -27,11 +29,12 @@ export default class WhitelistFolderSettings extends Modal {
|
|||
.onChange(async (value) => {
|
||||
this.whitelistedFolder.subFolders = value;
|
||||
await this.plugin.saveSettings(true);
|
||||
})
|
||||
}),
|
||||
);
|
||||
|
||||
new Setting(contentEl)
|
||||
.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')
|
||||
.addToggle((toggle) =>
|
||||
toggle
|
||||
|
|
@ -39,7 +42,7 @@ export default class WhitelistFolderSettings extends Modal {
|
|||
.onChange(async (value) => {
|
||||
this.whitelistedFolder.enableSync = value;
|
||||
await this.plugin.saveSettings();
|
||||
})
|
||||
}),
|
||||
);
|
||||
|
||||
new Setting(contentEl)
|
||||
|
|
@ -51,7 +54,7 @@ export default class WhitelistFolderSettings extends Modal {
|
|||
.onChange(async (value) => {
|
||||
this.whitelistedFolder.showInFolderOverview = value;
|
||||
await this.plugin.saveSettings();
|
||||
})
|
||||
}),
|
||||
);
|
||||
|
||||
new Setting(contentEl)
|
||||
|
|
@ -63,7 +66,7 @@ export default class WhitelistFolderSettings extends Modal {
|
|||
.onChange(async (value) => {
|
||||
this.whitelistedFolder.hideInFileExplorer = value;
|
||||
await this.plugin.saveSettings();
|
||||
})
|
||||
}),
|
||||
);
|
||||
|
||||
new Setting(contentEl)
|
||||
|
|
@ -74,7 +77,7 @@ export default class WhitelistFolderSettings extends Modal {
|
|||
.onChange(async (value) => {
|
||||
this.whitelistedFolder.enableAutoCreate = value;
|
||||
await this.plugin.saveSettings();
|
||||
})
|
||||
}),
|
||||
);
|
||||
|
||||
|
||||
|
|
@ -88,7 +91,7 @@ export default class WhitelistFolderSettings extends Modal {
|
|||
this.whitelistedFolder.enableFolderNote = value;
|
||||
await this.plugin.saveSettings(true);
|
||||
this.display();
|
||||
})
|
||||
}),
|
||||
);
|
||||
|
||||
if (this.whitelistedFolder.enableFolderNote) {
|
||||
|
|
@ -101,12 +104,12 @@ export default class WhitelistFolderSettings extends Modal {
|
|||
.onChange(async (value) => {
|
||||
this.whitelistedFolder.disableCollapsing = value;
|
||||
await this.plugin.saveSettings();
|
||||
})
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
onClose() {
|
||||
onClose(): void {
|
||||
const { contentEl } = this;
|
||||
contentEl.empty();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { App, Modal, Setting } from 'obsidian';
|
||||
import FolderNotesPlugin from '../../main';
|
||||
import { WhitelistedPattern } from '../WhitelistPattern';
|
||||
import { Modal, Setting, type App } from 'obsidian';
|
||||
import type FolderNotesPlugin from '../../main';
|
||||
import type { WhitelistedPattern } from '../WhitelistPattern';
|
||||
|
||||
export default class WhitelistPatternSettings extends Modal {
|
||||
plugin: FolderNotesPlugin;
|
||||
|
|
@ -12,15 +12,18 @@ export default class WhitelistPatternSettings extends Modal {
|
|||
this.app = app;
|
||||
this.pattern = pattern;
|
||||
}
|
||||
onOpen() {
|
||||
|
||||
onOpen(): void {
|
||||
this.display();
|
||||
}
|
||||
display() {
|
||||
|
||||
display(): void {
|
||||
const { contentEl } = this;
|
||||
contentEl.empty();
|
||||
contentEl.createEl('h2', { text: 'Whitelisted pattern settings' });
|
||||
new Setting(contentEl)
|
||||
.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')
|
||||
.addToggle((toggle) =>
|
||||
toggle
|
||||
|
|
@ -28,7 +31,7 @@ export default class WhitelistPatternSettings extends Modal {
|
|||
.onChange(async (value) => {
|
||||
this.pattern.enableSync = value;
|
||||
await this.plugin.saveSettings();
|
||||
})
|
||||
}),
|
||||
);
|
||||
|
||||
new Setting(contentEl)
|
||||
|
|
@ -39,7 +42,7 @@ export default class WhitelistPatternSettings extends Modal {
|
|||
.onChange(async (value) => {
|
||||
this.pattern.enableAutoCreate = value;
|
||||
await this.plugin.saveSettings();
|
||||
})
|
||||
}),
|
||||
);
|
||||
|
||||
new Setting(contentEl)
|
||||
|
|
@ -51,7 +54,7 @@ export default class WhitelistPatternSettings extends Modal {
|
|||
.onChange(async (value) => {
|
||||
this.pattern.showInFolderOverview = value;
|
||||
await this.plugin.saveSettings();
|
||||
})
|
||||
}),
|
||||
);
|
||||
|
||||
|
||||
|
|
@ -65,7 +68,7 @@ export default class WhitelistPatternSettings extends Modal {
|
|||
this.pattern.enableFolderNote = value;
|
||||
await this.plugin.saveSettings(true);
|
||||
this.display();
|
||||
})
|
||||
}),
|
||||
);
|
||||
|
||||
if (this.pattern.enableFolderNote) {
|
||||
|
|
@ -78,12 +81,12 @@ export default class WhitelistPatternSettings extends Modal {
|
|||
.onChange(async (value) => {
|
||||
this.pattern.disableCollapsing = value;
|
||||
await this.plugin.saveSettings();
|
||||
})
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
onClose() {
|
||||
|
||||
onClose(): void {
|
||||
const { contentEl } = this;
|
||||
contentEl.empty();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,11 @@
|
|||
import { App, Modal, Setting } from 'obsidian';
|
||||
import { SettingsTab } from 'src/settings/SettingsTab';
|
||||
import FolderNotesPlugin from '../../main';
|
||||
import { Modal, Setting, type App } from 'obsidian';
|
||||
import type { SettingsTab } from 'src/settings/SettingsTab';
|
||||
import type FolderNotesPlugin from '../../main';
|
||||
import { WhitelistedFolder } from '../WhitelistFolder';
|
||||
import { addWhitelistFolderListItem, addWhitelistedFolder } from '../functions/whitelistFolderFunctions';
|
||||
import {
|
||||
addWhitelistFolderListItem,
|
||||
addWhitelistedFolder,
|
||||
} from '../functions/whitelistFolderFunctions';
|
||||
import { addWhitelistedPatternListItem } from '../functions/whitelistPatternFunctions';
|
||||
|
||||
export default class WhitelistedFoldersSettings extends Modal {
|
||||
|
|
@ -15,7 +18,8 @@ export default class WhitelistedFoldersSettings extends Modal {
|
|||
this.settingsTab = settingsTab;
|
||||
this.app = settingsTab.app;
|
||||
}
|
||||
onOpen() {
|
||||
|
||||
onOpen(): void {
|
||||
|
||||
const { contentEl } = this;
|
||||
contentEl.createEl('h2', { text: 'Manage whitelisted folders' });
|
||||
|
|
@ -28,22 +32,31 @@ export default class WhitelistedFoldersSettings extends Modal {
|
|||
cb.setClass('add-exclude-folder');
|
||||
cb.setTooltip('Add whitelisted folder');
|
||||
cb.onClick(() => {
|
||||
const whitelistedFolder = new WhitelistedFolder('', this.plugin.settings.whitelistFolders.length, undefined, this.plugin);
|
||||
addWhitelistFolderListItem(this.plugin.settingsTab, contentEl, whitelistedFolder);
|
||||
const whitelistedFolder = new WhitelistedFolder(
|
||||
'', this.plugin.settings.whitelistFolders.length,
|
||||
undefined, this.plugin,
|
||||
);
|
||||
addWhitelistFolderListItem(
|
||||
this.plugin.settingsTab, contentEl, whitelistedFolder,
|
||||
);
|
||||
addWhitelistedFolder(this.plugin, whitelistedFolder);
|
||||
this.settingsTab.display();
|
||||
});
|
||||
});
|
||||
this.plugin.settings.whitelistFolders.sort((a, b) => a.position - b.position).forEach((whitelistedFolder) => {
|
||||
if (whitelistedFolder.string?.trim() !== '' && whitelistedFolder.path?.trim() === '') {
|
||||
addWhitelistedPatternListItem(this.settingsTab, contentEl, whitelistedFolder);
|
||||
} else {
|
||||
addWhitelistFolderListItem(this.settingsTab, contentEl, whitelistedFolder);
|
||||
}
|
||||
});
|
||||
|
||||
this.plugin.settings.whitelistFolders
|
||||
.sort((a, b) => a.position - b.position)
|
||||
.forEach((whitelistedFolder) => {
|
||||
if (whitelistedFolder.string?.trim() !== '' &&
|
||||
whitelistedFolder.path?.trim() === '') {
|
||||
addWhitelistedPatternListItem(this.settingsTab, contentEl, whitelistedFolder);
|
||||
} else {
|
||||
addWhitelistFolderListItem(this.settingsTab, contentEl, whitelistedFolder);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
onClose() {
|
||||
onClose(): void {
|
||||
const { contentEl } = this;
|
||||
contentEl.empty();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,20 +1,20 @@
|
|||
export class CustomEventEmitter {
|
||||
private events: { [key: string]: Array<(data?: any) => void> } = {};
|
||||
private events: { [key: string]: Array<(data?: unknown) => void> } = {};
|
||||
|
||||
on(event: string, listener: (data?: any) => void) {
|
||||
on(event: string, listener: (data?: unknown) => void): void {
|
||||
if (!this.events[event]) {
|
||||
this.events[event] = [];
|
||||
}
|
||||
this.events[event].push(listener);
|
||||
}
|
||||
|
||||
off(event: string, listener: (data?: any) => void) {
|
||||
off(event: string, listener: (data?: unknown) => void): void {
|
||||
if (!this.events[event]) return;
|
||||
|
||||
this.events[event] = this.events[event].filter((l) => l !== listener);
|
||||
}
|
||||
|
||||
emit(event: string, data?: any) {
|
||||
emit(event: string, data?: unknown): void {
|
||||
if (!this.events[event]) return;
|
||||
|
||||
this.events[event].forEach((listener) => listener(data));
|
||||
|
|
|
|||
|
|
@ -1,7 +1,28 @@
|
|||
import FolderNotesPlugin from 'src/main';
|
||||
import { getDefer, Listener, Events, ApiInterface, DeferInterface, ListenerRef, EventDispatcherInterface } from 'front-matter-plugin-api-provider';
|
||||
import { App, TFile, TFolder } from 'obsidian';
|
||||
import type FolderNotesPlugin from 'src/main';
|
||||
import {
|
||||
type Listener,
|
||||
type Events,
|
||||
type ApiInterface,
|
||||
type DeferInterface,
|
||||
type ListenerRef,
|
||||
type EventDispatcherInterface,
|
||||
getDefer,
|
||||
} from 'front-matter-plugin-api-provider';
|
||||
import { type App, TFile, TFolder } from 'obsidian';
|
||||
import { getFolder, getFolderNote } from 'src/functions/folderNoteFunctions';
|
||||
|
||||
interface UpdateData {
|
||||
id: string;
|
||||
result: boolean;
|
||||
path: string;
|
||||
pathOnly: boolean;
|
||||
breadcrumb?: HTMLElement;
|
||||
}
|
||||
|
||||
interface WrappedUpdateData {
|
||||
data: UpdateData;
|
||||
}
|
||||
|
||||
export class FrontMatterTitlePluginHandler {
|
||||
plugin: FolderNotesPlugin;
|
||||
app: App;
|
||||
|
|
@ -14,7 +35,7 @@ export class FrontMatterTitlePluginHandler {
|
|||
this.plugin = plugin;
|
||||
this.app = plugin.app;
|
||||
|
||||
(async () => {
|
||||
(async (): Promise<void> => {
|
||||
this.deffer = getDefer(this.app);
|
||||
if (this.deffer.isPluginReady()) {
|
||||
this.api = this.deffer.getApi();
|
||||
|
|
@ -33,8 +54,8 @@ export class FrontMatterTitlePluginHandler {
|
|||
}
|
||||
const event: Listener<Events, 'manager:update'> = {
|
||||
name: 'manager:update',
|
||||
cb: (data) => {
|
||||
this.fmptUpdateFileName(data as any, true);
|
||||
cb: (data): void => {
|
||||
this.fmptUpdateFileName(data as unknown as UpdateData, true);
|
||||
},
|
||||
};
|
||||
// Keep ref to remove listener
|
||||
|
|
@ -49,20 +70,18 @@ export class FrontMatterTitlePluginHandler {
|
|||
}
|
||||
})();
|
||||
}
|
||||
deleteEvent() {
|
||||
|
||||
deleteEvent(): void {
|
||||
if (this.eventRef) {
|
||||
this.dispatcher.removeListener(this.eventRef);
|
||||
}
|
||||
}
|
||||
async fmptUpdateFileName(data: {
|
||||
id: string;
|
||||
result: boolean;
|
||||
path: string;
|
||||
pathOnly: boolean;
|
||||
breadcrumb?: HTMLElement;
|
||||
}, isEvent: boolean) {
|
||||
if ((data as any).data) data = (data as any).data;
|
||||
const file = this.app.vault.getAbstractFileByPath(data.path);
|
||||
async fmptUpdateFileName(data: UpdateData, isEvent: boolean): Promise<void> {
|
||||
const hasNestedData = 'data' in (data as unknown as Record<string, unknown>);
|
||||
const actualData: UpdateData = hasNestedData
|
||||
? (data as unknown as WrappedUpdateData).data
|
||||
: data;
|
||||
const file = this.app.vault.getAbstractFileByPath(actualData.path);
|
||||
if (!(file instanceof TFile)) { return; }
|
||||
|
||||
const resolver = this.api?.getResolverFactory()?.createResolver('#feature-id#');
|
||||
|
|
@ -73,11 +92,11 @@ export class FrontMatterTitlePluginHandler {
|
|||
const folderNote = getFolderNote(this.plugin, folder.path);
|
||||
if (!folderNote) { return; }
|
||||
if (folderNote !== file) { return; }
|
||||
if (!data.pathOnly) {
|
||||
if (!actualData.pathOnly) {
|
||||
this.plugin.changeFolderNameInExplorer(folder, newName);
|
||||
}
|
||||
|
||||
const breadcrumb = data.breadcrumb;
|
||||
const { breadcrumb } = actualData;
|
||||
if (breadcrumb) {
|
||||
this.plugin.changeFolderNameInPath(folder, newName, breadcrumb);
|
||||
}
|
||||
|
|
@ -96,15 +115,12 @@ export class FrontMatterTitlePluginHandler {
|
|||
|
||||
}
|
||||
|
||||
async fmptUpdateFolderName(data: {
|
||||
id: string;
|
||||
result: boolean;
|
||||
path: string;
|
||||
pathOnly: boolean;
|
||||
breadcrumb?: HTMLElement;
|
||||
}, replacePath: boolean) {
|
||||
if ((data as any).data) data = (data as any).data;
|
||||
const folder = this.app.vault.getAbstractFileByPath(data.path);
|
||||
async fmptUpdateFolderName(data: UpdateData, _replacePath: boolean): Promise<void> {
|
||||
const hasNestedData = 'data' in (data as unknown as Record<string, unknown>);
|
||||
const actualData: UpdateData = hasNestedData
|
||||
? (data as unknown as WrappedUpdateData).data
|
||||
: data;
|
||||
const folder = this.app.vault.getAbstractFileByPath(actualData.path);
|
||||
if (!(folder instanceof TFolder)) { return; }
|
||||
const folderNote = getFolderNote(this.plugin, folder.path);
|
||||
if (!folderNote) { return; }
|
||||
|
|
@ -113,11 +129,11 @@ export class FrontMatterTitlePluginHandler {
|
|||
const newName = resolver?.resolve(folderNote?.path ?? '');
|
||||
if (!newName) return;
|
||||
|
||||
if (!data.pathOnly) {
|
||||
if (!actualData.pathOnly) {
|
||||
this.plugin.changeFolderNameInExplorer(folder, newName);
|
||||
}
|
||||
|
||||
const breadcrumb = data.breadcrumb;
|
||||
const { breadcrumb } = actualData;
|
||||
if (breadcrumb) {
|
||||
this.plugin.changeFolderNameInPath(folder, newName, breadcrumb);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { Keymap, Platform } from 'obsidian';
|
||||
import FolderNotesPlugin from 'src/main';
|
||||
import type FolderNotesPlugin from 'src/main';
|
||||
import { getFolderNote } from 'src/functions/folderNoteFunctions';
|
||||
import { handleViewHeaderClick } from './handleClick';
|
||||
import { getExcludedFolder } from 'src/ExcludeFolders/functions/folderFunctions';
|
||||
|
|
@ -7,7 +7,7 @@ import { updateCSSClassesForFolder } from 'src/functions/styleFunctions';
|
|||
|
||||
let fileExplorerMutationObserver: MutationObserver | null = null;
|
||||
|
||||
export function registerFileExplorerObserver(plugin: FolderNotesPlugin) {
|
||||
export function registerFileExplorerObserver(plugin: FolderNotesPlugin): void {
|
||||
// Run once on initial layout
|
||||
plugin.app.workspace.onLayoutReady(() => {
|
||||
initializeFolderNoteFeatures(plugin);
|
||||
|
|
@ -26,23 +26,23 @@ export function registerFileExplorerObserver(plugin: FolderNotesPlugin) {
|
|||
if (!(titleContainer instanceof HTMLElement)) return;
|
||||
|
||||
updateFolderNamesInPath(plugin, titleContainer);
|
||||
})
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
export function unregisterFileExplorerObserver() {
|
||||
export function unregisterFileExplorerObserver(): void {
|
||||
if (fileExplorerMutationObserver) {
|
||||
fileExplorerMutationObserver.disconnect();
|
||||
fileExplorerMutationObserver = null;
|
||||
}
|
||||
}
|
||||
|
||||
function initializeFolderNoteFeatures(plugin: FolderNotesPlugin) {
|
||||
function initializeFolderNoteFeatures(plugin: FolderNotesPlugin): void {
|
||||
initializeAllFolderTitles(plugin);
|
||||
observeFolderTitleMutations(plugin);
|
||||
}
|
||||
|
||||
function initializeBreadcrumbs(plugin: FolderNotesPlugin) {
|
||||
function initializeBreadcrumbs(plugin: FolderNotesPlugin): void {
|
||||
const titleContainers = document.querySelectorAll('.view-header-title-container');
|
||||
if (!titleContainers.length) return;
|
||||
titleContainers.forEach((container) => {
|
||||
|
|
@ -55,7 +55,7 @@ function initializeBreadcrumbs(plugin: FolderNotesPlugin) {
|
|||
* Observes the File Explorer for newly added folder elements and applies plugin logic (e.g., styles, event listeners)
|
||||
* automatically when folders are created, expanded, or when the File Explorer view is reopened.
|
||||
*/
|
||||
function observeFolderTitleMutations(plugin: FolderNotesPlugin) {
|
||||
function observeFolderTitleMutations(plugin: FolderNotesPlugin): void {
|
||||
if (fileExplorerMutationObserver) {
|
||||
fileExplorerMutationObserver.disconnect();
|
||||
}
|
||||
|
|
@ -71,7 +71,7 @@ function observeFolderTitleMutations(plugin: FolderNotesPlugin) {
|
|||
fileExplorerMutationObserver.observe(document, { childList: true, subtree: true });
|
||||
}
|
||||
|
||||
function initializeAllFolderTitles(plugin: FolderNotesPlugin) {
|
||||
function initializeAllFolderTitles(plugin: FolderNotesPlugin): void {
|
||||
const allTitles = document.querySelectorAll('.nav-folder-title-content');
|
||||
for (const title of Array.from(allTitles)) {
|
||||
const folderTitle = title as HTMLElement;
|
||||
|
|
@ -83,7 +83,7 @@ function initializeAllFolderTitles(plugin: FolderNotesPlugin) {
|
|||
}
|
||||
}
|
||||
|
||||
function processAddedFolders(node: HTMLElement, plugin: FolderNotesPlugin) {
|
||||
function processAddedFolders(node: HTMLElement, plugin: FolderNotesPlugin): void {
|
||||
const titles: HTMLElement[] = [];
|
||||
if (node.matches('.nav-folder-title-content')) {
|
||||
titles.push(node);
|
||||
|
|
@ -95,6 +95,7 @@ function processAddedFolders(node: HTMLElement, plugin: FolderNotesPlugin) {
|
|||
titles.forEach((folderTitle) => {
|
||||
const folderEl = folderTitle.closest('.nav-folder-title');
|
||||
const folderPath = folderEl?.getAttribute('data-path') || '';
|
||||
const RETRY_TIMEOUT = 50;
|
||||
if (!folderEl || !folderPath) {
|
||||
setTimeout(() => {
|
||||
const retryFolderEl = folderTitle.closest('.nav-folder-title');
|
||||
|
|
@ -102,14 +103,18 @@ function processAddedFolders(node: HTMLElement, plugin: FolderNotesPlugin) {
|
|||
if (retryFolderEl && retryFolderPath) {
|
||||
setupFolderTitle(folderTitle, plugin, retryFolderPath);
|
||||
}
|
||||
}, 50);
|
||||
}, RETRY_TIMEOUT);
|
||||
return;
|
||||
}
|
||||
setupFolderTitle(folderTitle, plugin, folderPath);
|
||||
});
|
||||
}
|
||||
|
||||
async function setupFolderTitle(folderTitle: HTMLElement, plugin: FolderNotesPlugin, folderPath: string) {
|
||||
async function setupFolderTitle(
|
||||
folderTitle: HTMLElement,
|
||||
plugin: FolderNotesPlugin,
|
||||
folderPath: string,
|
||||
): Promise<void> {
|
||||
if (folderTitle.dataset.initialized === 'true') return;
|
||||
if (!folderPath) return;
|
||||
|
||||
|
|
@ -117,7 +122,10 @@ async function setupFolderTitle(folderTitle: HTMLElement, plugin: FolderNotesPlu
|
|||
await updateCSSClassesForFolder(folderPath, plugin);
|
||||
|
||||
if (plugin.settings.frontMatterTitle.enabled) {
|
||||
plugin.fmtpHandler?.fmptUpdateFolderName({ id: '', result: false, path: folderPath, pathOnly: false }, false);
|
||||
plugin.fmtpHandler?.fmptUpdateFolderName(
|
||||
{ id: '', result: false, path: folderPath, pathOnly: false },
|
||||
false,
|
||||
);
|
||||
}
|
||||
|
||||
if (Platform.isMobile && plugin.settings.disableOpenFolderNoteOnClick) return;
|
||||
|
|
@ -150,21 +158,24 @@ async function setupFolderTitle(folderTitle: HTMLElement, plugin: FolderNotesPlu
|
|||
});
|
||||
}
|
||||
|
||||
async function updateFolderNamesInPath(plugin: FolderNotesPlugin, titleContainer: HTMLElement) {
|
||||
async function updateFolderNamesInPath(
|
||||
plugin: FolderNotesPlugin,
|
||||
titleContainer: HTMLElement,
|
||||
): Promise<void> {
|
||||
const headers = titleContainer.querySelectorAll('span.view-header-breadcrumb');
|
||||
let path = '';
|
||||
const TRAILING_SLASH_LENGTH = 1;
|
||||
headers.forEach(async (breadcrumb: HTMLElement) => {
|
||||
path += breadcrumb.getAttribute('old-name') ?? (breadcrumb as HTMLElement).innerText.trim();
|
||||
path += '/';
|
||||
const folderPath = path.slice(0, -1);
|
||||
const folderPath = path.slice(0, -TRAILING_SLASH_LENGTH);
|
||||
|
||||
const excludedFolder = getExcludedFolder(plugin, folderPath, true);
|
||||
if (excludedFolder?.disableFolderNote) return;
|
||||
const folderNote = getFolderNote(plugin, folderPath);
|
||||
if (!folderNote) return;
|
||||
if (folderNote) breadcrumb.classList.add('has-folder-note');
|
||||
|
||||
breadcrumb?.setAttribute('data-path', path.slice(0, -1));
|
||||
breadcrumb?.setAttribute('data-path', path.slice(0, -TRAILING_SLASH_LENGTH));
|
||||
if (!breadcrumb.onclick) {
|
||||
breadcrumb.addEventListener('click', (e) => {
|
||||
handleViewHeaderClick(e as MouseEvent, plugin);
|
||||
|
|
@ -172,7 +183,10 @@ async function updateFolderNamesInPath(plugin: FolderNotesPlugin, titleContainer
|
|||
}
|
||||
|
||||
if (plugin.settings.frontMatterTitle.enabled) {
|
||||
plugin.fmtpHandler?.fmptUpdateFolderName({ id: '', result: false, path: folderPath, pathOnly: true, breadcrumb: breadcrumb }, true);
|
||||
plugin.fmtpHandler?.fmptUpdateFolderName(
|
||||
{ id: '', result: false, path: folderPath, pathOnly: true, breadcrumb: breadcrumb },
|
||||
true,
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
@ -180,10 +194,14 @@ async function updateFolderNamesInPath(plugin: FolderNotesPlugin, titleContainer
|
|||
// Schedules a callback to run when the browser is idle, or after a timeout as a fallback.
|
||||
// - callback: The function to execute when idle or after the timeout.
|
||||
// - options: Optional object with a 'timeout' property (in milliseconds).
|
||||
function scheduleIdle(callback: () => void, options?: { timeout: number }) {
|
||||
function scheduleIdle(callback: () => void, options?: { timeout: number }): void {
|
||||
const DEFAULT_IDLE_TIMEOUT = 200;
|
||||
if ('requestIdleCallback' in window) {
|
||||
(window as any).requestIdleCallback(callback, options);
|
||||
const windowWithIdle = window as Window & {
|
||||
requestIdleCallback: (callback: () => void, options?: { timeout: number }) => void
|
||||
};
|
||||
windowWithIdle.requestIdleCallback(callback, options);
|
||||
} else {
|
||||
setTimeout(callback, options?.timeout || 200);
|
||||
setTimeout(callback, options?.timeout || DEFAULT_IDLE_TIMEOUT);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import FolderNotesPlugin from 'src/main';
|
||||
import { App, EditableFileView, TFolder } from 'obsidian';
|
||||
import type FolderNotesPlugin from 'src/main';
|
||||
import { EditableFileView, TFolder, type App } from 'obsidian';
|
||||
import { getFolder, getFolderNote } from 'src/functions/folderNoteFunctions';
|
||||
export class TabManager {
|
||||
plugin: FolderNotesPlugin;
|
||||
|
|
@ -9,19 +9,18 @@ export class TabManager {
|
|||
this.app = plugin.app;
|
||||
}
|
||||
|
||||
resetTabs() {
|
||||
resetTabs(): void {
|
||||
if (!this.isEnabled()) return;
|
||||
|
||||
this.app.workspace.iterateAllLeaves((leaf) => {
|
||||
if (!(leaf.view instanceof EditableFileView)) return;
|
||||
const file = leaf.view?.file;
|
||||
if (!file) return;
|
||||
// @ts-ignore
|
||||
leaf.tabHeaderInnerTitleEl.setText(file.basename);
|
||||
});
|
||||
}
|
||||
|
||||
updateTabs() {
|
||||
updateTabs(): void {
|
||||
if (!this.isEnabled()) return;
|
||||
this.app.workspace.iterateAllLeaves((leaf) => {
|
||||
if (!(leaf.view instanceof EditableFileView)) return;
|
||||
|
|
@ -29,12 +28,11 @@ export class TabManager {
|
|||
if (!file) return;
|
||||
const folder = getFolder(this.plugin, file);
|
||||
if (!folder) return;
|
||||
// @ts-ignore
|
||||
leaf.tabHeaderInnerTitleEl.setText(folder.name);
|
||||
});
|
||||
}
|
||||
|
||||
updateTab(folderPath: string) {
|
||||
updateTab(folderPath: string): void {
|
||||
if (!this.isEnabled()) return;
|
||||
|
||||
const folder = this.app.vault.getAbstractFileByPath(folderPath);
|
||||
|
|
@ -48,13 +46,12 @@ export class TabManager {
|
|||
const file = leaf.view?.file;
|
||||
if (!file) return;
|
||||
if (file.path === folderNote.path) {
|
||||
// @ts-ignore
|
||||
leaf.tabHeaderInnerTitleEl.setText(folder.name);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
isEnabled() {
|
||||
isEnabled(): boolean {
|
||||
if (this.plugin.settings.folderNoteName === '{{folder_name}}') return false;
|
||||
return this.plugin.settings.tabManagerEnabled;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,18 @@
|
|||
import { Keymap, Platform } from 'obsidian';
|
||||
import FolderNotesPlugin from 'src/main';
|
||||
import { Keymap, Platform, type TFile } from 'obsidian';
|
||||
import type FolderNotesPlugin from 'src/main';
|
||||
import { openFolderNote, createFolderNote, getFolderNote } from 'src/functions/folderNoteFunctions';
|
||||
import { getExcludedFolder } from 'src/ExcludeFolders/functions/folderFunctions';
|
||||
import { addCSSClassToFileExplorerEl, removeCSSClassFromFileExplorerEL } from 'src/functions/styleFunctions';
|
||||
import {
|
||||
addCSSClassToFileExplorerEl,
|
||||
removeCSSClassFromFileExplorerEL,
|
||||
} from 'src/functions/styleFunctions';
|
||||
|
||||
export async function handleViewHeaderClick(event: MouseEvent, plugin: FolderNotesPlugin) {
|
||||
|
||||
|
||||
export async function handleViewHeaderClick(
|
||||
event: MouseEvent,
|
||||
plugin: FolderNotesPlugin,
|
||||
): Promise<void> {
|
||||
if (!plugin.settings.openFolderNoteOnClickInPath) return;
|
||||
event.stopImmediatePropagation();
|
||||
event.preventDefault();
|
||||
|
|
@ -13,37 +21,61 @@ export async function handleViewHeaderClick(event: MouseEvent, plugin: FolderNot
|
|||
|
||||
const folderPath = event.target.getAttribute('data-path');
|
||||
if (!folderPath) { return; }
|
||||
const excludedFolder = getExcludedFolder(plugin, folderPath, true);
|
||||
if (excludedFolder?.disableFolderNote) {
|
||||
event.target.onclick = null;
|
||||
event.target.click();
|
||||
return;
|
||||
} else if (excludedFolder?.enableCollapsing || plugin.settings.enableCollapsing) {
|
||||
event.target.onclick = null;
|
||||
event.target.click();
|
||||
}
|
||||
|
||||
if (await isExcludedFolder(event, plugin, folderPath)) return;
|
||||
|
||||
const folderNote = getFolderNote(plugin, folderPath);
|
||||
if (folderNote) {
|
||||
await openFolderNote(plugin, folderNote, event).then(async () => {
|
||||
// @ts-ignore
|
||||
const fileExplorerPlugin = plugin.app.internalPlugins.getEnabledPluginById('file-explorer');
|
||||
if (fileExplorerPlugin && Platform.isMobile && plugin.settings.openSidebar.mobile) {
|
||||
setTimeout(() => { fileExplorerPlugin.revealInFolder(folderNote); }, 200);
|
||||
} else if (fileExplorerPlugin && Platform.isDesktop && plugin.settings.openSidebar.desktop) {
|
||||
fileExplorerPlugin.revealInFolder(folderNote);
|
||||
}
|
||||
});
|
||||
await openFolderNote(plugin, folderNote, event).then(() =>
|
||||
handleFolderNoteReveal(plugin, folderNote),
|
||||
);
|
||||
return;
|
||||
} else if (event.altKey || Keymap.isModEvent(event) === 'tab') {
|
||||
const usedCtrl = Platform.isMacOS ? event.metaKey : event.ctrlKey;
|
||||
if ((plugin.settings.altKey && event.altKey) || (usedCtrl && Keymap.isModEvent(event) === 'tab')) {
|
||||
await createFolderNote(plugin, folderPath, true, undefined, true);
|
||||
addCSSClassToFileExplorerEl(folderPath, 'has-folder-note', false, plugin);
|
||||
removeCSSClassFromFileExplorerEL(folderPath, 'has-not-folder-note', false, plugin);
|
||||
return;
|
||||
}
|
||||
if (await handleFolderNoteCreation(event, plugin, folderPath)) return;
|
||||
}
|
||||
event.target.onclick = null;
|
||||
event.target.click();
|
||||
(event.target as HTMLElement).onclick = null;
|
||||
(event.target as HTMLElement).click();
|
||||
}
|
||||
|
||||
async function isExcludedFolder(
|
||||
event: MouseEvent,
|
||||
plugin: FolderNotesPlugin,
|
||||
folderPath: string,
|
||||
): Promise<boolean> {
|
||||
const excludedFolder = getExcludedFolder(plugin, folderPath, true);
|
||||
if (excludedFolder?.disableFolderNote) {
|
||||
(event.target as HTMLElement).onclick = null;
|
||||
(event.target as HTMLElement).click();
|
||||
return true;
|
||||
} else if (excludedFolder?.enableCollapsing || plugin.settings.enableCollapsing) {
|
||||
(event.target as HTMLElement).onclick = null;
|
||||
(event.target as HTMLElement).click();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
async function handleFolderNoteReveal(plugin: FolderNotesPlugin, folderNote: TFile): Promise<void> {
|
||||
const fileExplorerPlugin = plugin.app.internalPlugins.getEnabledPluginById('file-explorer');
|
||||
if (fileExplorerPlugin && Platform.isMobile && plugin.settings.openSidebar.mobile) {
|
||||
const OPEN_SIDEBAR_DELAY = 200;
|
||||
setTimeout(() => { fileExplorerPlugin.revealInFolder(folderNote); }, OPEN_SIDEBAR_DELAY);
|
||||
} else if (fileExplorerPlugin && Platform.isDesktop && plugin.settings.openSidebar.desktop) {
|
||||
fileExplorerPlugin.revealInFolder(folderNote);
|
||||
}
|
||||
}
|
||||
|
||||
async function handleFolderNoteCreation(
|
||||
event: MouseEvent,
|
||||
plugin: FolderNotesPlugin,
|
||||
folderPath: string,
|
||||
): Promise<boolean> {
|
||||
const usedCtrl = Platform.isMacOS ? event.metaKey : event.ctrlKey;
|
||||
if ((plugin.settings.altKey && event.altKey) ||
|
||||
(usedCtrl && Keymap.isModEvent(event) === 'tab')) {
|
||||
await createFolderNote(plugin, folderPath, true, undefined, true);
|
||||
addCSSClassToFileExplorerEl(folderPath, 'has-folder-note', false, plugin);
|
||||
removeCSSClassFromFileExplorerEL(folderPath, 'has-not-folder-note', false, plugin);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,18 @@
|
|||
import { TAbstractFile, TFolder, TFile } from 'obsidian';
|
||||
import FolderNotesPlugin from 'src/main';
|
||||
import { createFolderNote, getFolder, getFolderNote, turnIntoFolderNote } from 'src/functions/folderNoteFunctions';
|
||||
import { TFolder, TFile, type TAbstractFile } from 'obsidian';
|
||||
import type FolderNotesPlugin from 'src/main';
|
||||
import {
|
||||
createFolderNote,
|
||||
getFolder,
|
||||
getFolderNote,
|
||||
turnIntoFolderNote,
|
||||
} from 'src/functions/folderNoteFunctions';
|
||||
import { getExcludedFolder } from 'src/ExcludeFolders/functions/folderFunctions';
|
||||
import { removeCSSClassFromFileExplorerEL, addCSSClassToFileExplorerEl } from 'src/functions/styleFunctions';
|
||||
import {
|
||||
removeCSSClassFromFileExplorerEL,
|
||||
addCSSClassToFileExplorerEl,
|
||||
} from 'src/functions/styleFunctions';
|
||||
|
||||
export async function handleCreate(file: TAbstractFile, plugin: FolderNotesPlugin) {
|
||||
export async function handleCreate(file: TAbstractFile, plugin: FolderNotesPlugin): Promise<void> {
|
||||
if (!plugin.app.workspace.layoutReady) return;
|
||||
|
||||
const folder = file.parent;
|
||||
|
|
@ -23,7 +31,7 @@ export async function handleCreate(file: TAbstractFile, plugin: FolderNotesPlugi
|
|||
}
|
||||
}
|
||||
|
||||
async function handleFileCreation(file: TFile, plugin: FolderNotesPlugin) {
|
||||
async function handleFileCreation(file: TFile, plugin: FolderNotesPlugin): Promise<void> {
|
||||
const folder = getFolder(plugin, file);
|
||||
|
||||
if (!(folder instanceof TFolder) && plugin.settings.autoCreateForFiles) {
|
||||
|
|
@ -50,7 +58,7 @@ async function handleFileCreation(file: TFile, plugin: FolderNotesPlugin) {
|
|||
}
|
||||
}
|
||||
|
||||
async function handleFolderCreation(folder: TFolder, plugin: FolderNotesPlugin) {
|
||||
async function handleFolderCreation(folder: TFolder, plugin: FolderNotesPlugin): Promise<void> {
|
||||
let openFile = plugin.settings.autoCreateFocusFiles;
|
||||
|
||||
const attachmentFolderPath = plugin.app.vault.getConfig('attachmentFolderPath') as string;
|
||||
|
|
|
|||
|
|
@ -1,10 +1,14 @@
|
|||
import { TAbstractFile, TFolder, TFile } from 'obsidian';
|
||||
import FolderNotesPlugin from 'src/main';
|
||||
import { TFolder, TFile, type TAbstractFile } from 'obsidian';
|
||||
import type FolderNotesPlugin from 'src/main';
|
||||
import { getFolderNote, getFolder, deleteFolderNote } from 'src/functions/folderNoteFunctions';
|
||||
import { removeCSSClassFromFileExplorerEL, addCSSClassToFileExplorerEl, hideFolderNoteInFileExplorer } from 'src/functions/styleFunctions';
|
||||
import {
|
||||
removeCSSClassFromFileExplorerEL,
|
||||
addCSSClassToFileExplorerEl,
|
||||
hideFolderNoteInFileExplorer,
|
||||
} from 'src/functions/styleFunctions';
|
||||
import { getFolderPathFromString } from 'src/functions/utils';
|
||||
|
||||
export function handleDelete(file: TAbstractFile, plugin: FolderNotesPlugin) {
|
||||
export function handleDelete(file: TAbstractFile, plugin: FolderNotesPlugin): void {
|
||||
const folder = plugin.app.vault.getAbstractFileByPath(getFolderPathFromString(file.path));
|
||||
if (folder instanceof TFolder) {
|
||||
if (plugin.isEmptyFolderNoteFolder(folder) && getFolderNote(plugin, folder.path)) {
|
||||
|
|
@ -15,13 +19,15 @@ export function handleDelete(file: TAbstractFile, plugin: FolderNotesPlugin) {
|
|||
}
|
||||
|
||||
if (file instanceof TFile) {
|
||||
const folder = getFolder(plugin, file);
|
||||
if (!folder) { return; }
|
||||
const folderNote = getFolderNote(plugin, folder.path);
|
||||
const folderNoteFolder = getFolder(plugin, file);
|
||||
if (!folderNoteFolder) { return; }
|
||||
const folderNote = getFolderNote(plugin, folderNoteFolder.path);
|
||||
if (folderNote) { return; }
|
||||
removeCSSClassFromFileExplorerEL(folder.path, 'has-folder-note', false, plugin);
|
||||
removeCSSClassFromFileExplorerEL(folder.path, 'only-has-folder-note', true, plugin);
|
||||
hideFolderNoteInFileExplorer(folder.path, plugin);
|
||||
removeCSSClassFromFileExplorerEL(folderNoteFolder.path, 'has-folder-note', false, plugin);
|
||||
removeCSSClassFromFileExplorerEL(
|
||||
folderNoteFolder.path, 'only-has-folder-note', true, plugin,
|
||||
);
|
||||
hideFolderNoteInFileExplorer(folderNoteFolder.path, plugin);
|
||||
}
|
||||
|
||||
if (!(file instanceof TFolder)) { return; }
|
||||
|
|
|
|||
|
|
@ -1,13 +1,29 @@
|
|||
import { TFile, TFolder, TAbstractFile, Notice } from 'obsidian';
|
||||
import FolderNotesPlugin from 'src/main';
|
||||
import { extractFolderName, getFolderNote, getFolderNoteFolder } from '../functions/folderNoteFunctions';
|
||||
import { getExcludedFolder, addExcludedFolder, updateExcludedFolder, deleteExcludedFolder, getDetachedFolder } from '../ExcludeFolders/functions/folderFunctions';
|
||||
import { TFile, TFolder, Notice, type TAbstractFile } from 'obsidian';
|
||||
import type FolderNotesPlugin from 'src/main';
|
||||
import {
|
||||
extractFolderName, getFolderNote, getFolderNoteFolder,
|
||||
} from '../functions/folderNoteFunctions';
|
||||
import {
|
||||
getExcludedFolder, addExcludedFolder,
|
||||
updateExcludedFolder, deleteExcludedFolder, getDetachedFolder,
|
||||
} from '../ExcludeFolders/functions/folderFunctions';
|
||||
import { ExcludedFolder } from 'src/ExcludeFolders/ExcludeFolder';
|
||||
import { removeCSSClassFromFileExplorerEL, addCSSClassToFileExplorerEl, markFileAsFolderNote, unmarkFileAsFolderNote, unmarkFolderAsFolderNote, markFolderWithFolderNoteClasses, hideFolderNoteInFileExplorer, removeActiveFolder, setActiveFolder } from 'src/functions/styleFunctions';
|
||||
import { getFolderPathFromString, removeExtension, getFileNameFromPathString } from 'src/functions/utils';
|
||||
import {
|
||||
removeCSSClassFromFileExplorerEL, addCSSClassToFileExplorerEl,
|
||||
markFileAsFolderNote, unmarkFileAsFolderNote,
|
||||
unmarkFolderAsFolderNote, markFolderWithFolderNoteClasses,
|
||||
hideFolderNoteInFileExplorer, removeActiveFolder, setActiveFolder,
|
||||
} from 'src/functions/styleFunctions';
|
||||
import {
|
||||
getFolderPathFromString, removeExtension, getFileNameFromPathString,
|
||||
} from 'src/functions/utils';
|
||||
|
||||
export function handleRename(file: TAbstractFile, oldPath: string, plugin: FolderNotesPlugin) {
|
||||
const folder = file.parent;
|
||||
export function handleRename(
|
||||
file: TAbstractFile,
|
||||
oldPath: string,
|
||||
plugin: FolderNotesPlugin,
|
||||
): void {
|
||||
let folder = file.parent;
|
||||
const oldFolder = plugin.app.vault.getAbstractFileByPath(getFolderPathFromString(oldPath));
|
||||
|
||||
if (folder instanceof TFolder) {
|
||||
|
|
@ -27,20 +43,23 @@ export function handleRename(file: TAbstractFile, oldPath: string, plugin: Folde
|
|||
}
|
||||
|
||||
if (file instanceof TFolder) {
|
||||
const folder = file;
|
||||
folder = file;
|
||||
plugin.tabManager.updateTab(folder.path);
|
||||
updateExcludedFolderPath(folder, oldPath, plugin);
|
||||
if (isFolderRename(folder, oldPath)) {
|
||||
return handleFolderRename(folder, oldPath, plugin);
|
||||
} else {
|
||||
return handleFolderMove(folder, oldPath, plugin);
|
||||
handleFolderRename(folder, oldPath, plugin);
|
||||
return;
|
||||
}
|
||||
return handleFolderMove(folder, oldPath, plugin);
|
||||
|
||||
} else if (file instanceof TFile) {
|
||||
if (isFileRename(file, oldPath)) {
|
||||
return fmptUpdateFileName(file, oldPath, plugin);
|
||||
} else {
|
||||
return handleFileMove(file, oldPath, plugin);
|
||||
handleFileRename(file, oldPath, plugin);
|
||||
return;
|
||||
}
|
||||
handleFileMove(file, oldPath, plugin);
|
||||
return;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -63,7 +82,7 @@ function isFolderRename(folder: TFolder, oldPath: string): boolean {
|
|||
return oldParent === newParent && oldName !== newName;
|
||||
}
|
||||
|
||||
export function handleFolderMove(file: TFolder, oldPath: string, plugin: FolderNotesPlugin) {
|
||||
export function handleFolderMove(file: TFolder, oldPath: string, plugin: FolderNotesPlugin): void {
|
||||
if (plugin.settings.storageLocation === 'insideFolder') { return; }
|
||||
if (!plugin.settings.syncMove) { return; }
|
||||
const folderNote = getFolderNote(plugin, oldPath, plugin.settings.storageLocation);
|
||||
|
|
@ -81,60 +100,43 @@ export function handleFolderMove(file: TFolder, oldPath: string, plugin: FolderN
|
|||
plugin.app.fileManager.renameFile(folderNote, newPath);
|
||||
}
|
||||
|
||||
export async function handleFileMove(file: TFile, oldPath: string, plugin: FolderNotesPlugin) {
|
||||
const folderName = extractFolderName(plugin.settings.folderNoteName, file.basename) || file.basename;
|
||||
const oldFileName = removeExtension(getFileNameFromPathString(oldPath));
|
||||
const newFolder = getFolderNoteFolder(plugin, file, file.basename);
|
||||
let excludedFolder = getExcludedFolder(plugin, newFolder?.path || '', true);
|
||||
const oldFolder = getFolderNoteFolder(plugin, oldPath, oldFileName);
|
||||
const folderNote = getFolderNote(plugin, oldPath, plugin.settings.storageLocation, file);
|
||||
// eslint-disable-next-line complexity
|
||||
export async function handleFileMove(
|
||||
file: TFile,
|
||||
oldPath: string,
|
||||
plugin: FolderNotesPlugin,
|
||||
): Promise<void> {
|
||||
const { folderName, oldFileName, newFolder, excludedFolder, oldFolder, folderNote } = getArgs(
|
||||
plugin, file, oldPath,
|
||||
);
|
||||
|
||||
|
||||
const isFileNowFolderNoteInNewFolder = folderName === newFolder?.name;
|
||||
const isFileMovedFromOldFolderNote = oldFolder && oldFolder.name === oldFileName && newFolder?.path !== oldFolder.path;
|
||||
const isFolderNoteInNewFolder = folderName === newFolder?.name;
|
||||
const fileMovedFromOldFolderNote = oldFolder && oldFolder.name === oldFileName
|
||||
&& newFolder?.path !== oldFolder.path;
|
||||
|
||||
// this is for turning files into folder notes for folders that already have a folder note
|
||||
// e.g. Turn into folder note for "Folder name"
|
||||
const isFileNowFolderNoteWithExistingNote = folderName === newFolder?.name && folderNote;
|
||||
const isFileWithExistingNote = folderName === newFolder?.name && folderNote;
|
||||
|
||||
if (isFileNowFolderNoteWithExistingNote) {
|
||||
let excludedFolderExisted = true;
|
||||
let disabledSync = false;
|
||||
|
||||
if (!excludedFolder) {
|
||||
excludedFolderExisted = false;
|
||||
excludedFolder = new ExcludedFolder(oldFolder?.path || '', plugin.settings.excludeFolders.length, undefined, plugin);
|
||||
addExcludedFolder(plugin, excludedFolder);
|
||||
} else if (!excludedFolder.disableSync) {
|
||||
disabledSync = false;
|
||||
excludedFolder.disableSync = true;
|
||||
updateExcludedFolder(plugin, excludedFolder, excludedFolder);
|
||||
}
|
||||
return plugin.app.fileManager.renameFile(file, oldPath).then(() => {
|
||||
if (!excludedFolder) { return; }
|
||||
if (!excludedFolderExisted) {
|
||||
deleteExcludedFolder(plugin, excludedFolder);
|
||||
} else if (!disabledSync) {
|
||||
excludedFolder.disableSync = false;
|
||||
updateExcludedFolder(plugin, excludedFolder, excludedFolder);
|
||||
}
|
||||
});
|
||||
} else if (isFileNowFolderNoteInNewFolder) {
|
||||
if (!excludedFolder?.disableFolderNote) {
|
||||
markFileAsFolderNote(file, plugin);
|
||||
if (newFolder instanceof TFolder) {
|
||||
markFolderWithFolderNoteClasses(newFolder, plugin);
|
||||
if (plugin.app.workspace.getActiveFile()?.path === file.path) {
|
||||
removeActiveFolder(plugin);
|
||||
setActiveFolder(newFolder.path, plugin);
|
||||
}
|
||||
}
|
||||
if (oldFolder instanceof TFolder) {
|
||||
hideFolderNoteInFileExplorer(oldFolder.path, plugin);
|
||||
unmarkFolderAsFolderNote(oldFolder, plugin);
|
||||
if (isFileWithExistingNote) {
|
||||
renameExistingFolderNote(
|
||||
file, oldPath, plugin, excludedFolder, oldFolder,
|
||||
);
|
||||
} else if (isFolderNoteInNewFolder) {
|
||||
if (excludedFolder?.disableFolderNote) { return; }
|
||||
markFileAsFolderNote(file, plugin);
|
||||
if (newFolder instanceof TFolder) {
|
||||
markFolderWithFolderNoteClasses(newFolder, plugin);
|
||||
if (plugin.app.workspace.getActiveFile()?.path === file.path) {
|
||||
removeActiveFolder(plugin);
|
||||
setActiveFolder(newFolder.path, plugin);
|
||||
}
|
||||
}
|
||||
} else if (isFileMovedFromOldFolderNote) {
|
||||
if (oldFolder instanceof TFolder) {
|
||||
hideFolderNoteInFileExplorer(oldFolder.path, plugin);
|
||||
unmarkFolderAsFolderNote(oldFolder, plugin);
|
||||
}
|
||||
} else if (fileMovedFromOldFolderNote) {
|
||||
unmarkFileAsFolderNote(file, plugin);
|
||||
if (oldFolder instanceof TFolder) {
|
||||
removeActiveFolder(plugin);
|
||||
|
|
@ -144,9 +146,75 @@ export async function handleFileMove(file: TFile, oldPath: string, plugin: Folde
|
|||
}
|
||||
}
|
||||
|
||||
export async function handleFolderRename(file: TFolder, oldPath: string, plugin: FolderNotesPlugin) {
|
||||
|
||||
|
||||
function getArgs(plugin: FolderNotesPlugin, file: TFile, oldPath: string): {
|
||||
folderName: string;
|
||||
oldFileName: string;
|
||||
newFolder: TAbstractFile | null;
|
||||
excludedFolder: ExcludedFolder | undefined;
|
||||
oldFolder: TAbstractFile | null;
|
||||
folderNote: TFile | null | undefined;
|
||||
} {
|
||||
const folderName = extractFolderName(plugin.settings.folderNoteName, file.basename)
|
||||
|| file.basename;
|
||||
const oldFileName = removeExtension(getFileNameFromPathString(oldPath));
|
||||
const newFolder = getFolderNoteFolder(plugin, file, file.basename);
|
||||
let excludedFolder = getExcludedFolder(plugin, newFolder?.path || '', true);
|
||||
const oldFolder = getFolderNoteFolder(plugin, oldPath, oldFileName);
|
||||
const folderNote = getFolderNote(plugin, oldPath, plugin.settings.storageLocation, file);
|
||||
|
||||
return {
|
||||
folderName,
|
||||
oldFileName,
|
||||
newFolder,
|
||||
excludedFolder,
|
||||
oldFolder,
|
||||
folderNote,
|
||||
};
|
||||
}
|
||||
|
||||
function renameExistingFolderNote(
|
||||
file: TFile, oldPath: string, plugin: FolderNotesPlugin,
|
||||
excludedFolder: ExcludedFolder | undefined,
|
||||
oldFolder: TAbstractFile | null,
|
||||
): void {
|
||||
let excludedFolderExisted = true;
|
||||
let disabledSync = false;
|
||||
|
||||
if (!excludedFolder) {
|
||||
excludedFolderExisted = false;
|
||||
excludedFolder = new ExcludedFolder(
|
||||
oldFolder?.path || '',
|
||||
plugin.settings.excludeFolders.length,
|
||||
undefined,
|
||||
plugin,
|
||||
);
|
||||
addExcludedFolder(plugin, excludedFolder);
|
||||
} else if (!excludedFolder.disableSync) {
|
||||
disabledSync = false;
|
||||
excludedFolder.disableSync = true;
|
||||
updateExcludedFolder(plugin, excludedFolder, excludedFolder);
|
||||
}
|
||||
plugin.app.fileManager.renameFile(file, oldPath).then(() => {
|
||||
if (!excludedFolder) { return; }
|
||||
if (!excludedFolderExisted) {
|
||||
deleteExcludedFolder(plugin, excludedFolder);
|
||||
} else if (!disabledSync) {
|
||||
excludedFolder.disableSync = false;
|
||||
updateExcludedFolder(plugin, excludedFolder, excludedFolder);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
export async function handleFolderRename(
|
||||
file: TFolder, oldPath: string, plugin: FolderNotesPlugin,
|
||||
): Promise<void> {
|
||||
const fileName = plugin.settings.folderNoteName.replace('{{folder_name}}', file.name);
|
||||
const oldFileName = plugin.settings.folderNoteName.replace('{{folder_name}}', getFileNameFromPathString(oldPath));
|
||||
const oldFileName = plugin.settings.folderNoteName
|
||||
.replace('{{folder_name}}', getFileNameFromPathString(oldPath));
|
||||
|
||||
if (fileName === oldFileName) { return; }
|
||||
|
||||
|
|
@ -182,50 +250,62 @@ export async function handleFolderRename(file: TFolder, oldPath: string, plugin:
|
|||
plugin.app.fileManager.renameFile(folderNote, newPath);
|
||||
}
|
||||
|
||||
export async function fmptUpdateFileName(file: TFile, oldPath: string, plugin: FolderNotesPlugin) {
|
||||
// eslint-disable-next-line complexity
|
||||
export async function handleFileRename(
|
||||
file: TFile,
|
||||
oldPath: string,
|
||||
plugin: FolderNotesPlugin,
|
||||
): Promise<void> {
|
||||
const oldFileName = removeExtension(getFileNameFromPathString(oldPath));
|
||||
const newFileName = file.basename;
|
||||
if (oldFileName === newFileName) { return; }
|
||||
|
||||
const oldFolder = getFolderNoteFolder(plugin, oldPath, oldFileName);
|
||||
const folderName = extractFolderName(plugin.settings.folderNoteName, file.basename) || file.basename;
|
||||
const oldFolderName = extractFolderName(plugin.settings.folderNoteName, oldFileName) || oldFileName;
|
||||
const folderName = extractFolderName(plugin.settings.folderNoteName, file.basename)
|
||||
|| file.basename;
|
||||
const oldFolderName = extractFolderName(plugin.settings.folderNoteName, oldFileName)
|
||||
|| oldFileName;
|
||||
const newFolder = getFolderNoteFolder(plugin, file, file.basename);
|
||||
const excludedFolder = getExcludedFolder(plugin, newFolder?.path || '', true);
|
||||
const detachedExcludedFolder = getDetachedFolder(plugin, newFolder?.path || '');
|
||||
const folderNote = getFolderNote(plugin, oldPath, plugin.settings.storageLocation, file);
|
||||
|
||||
if (!excludedFolder?.disableFolderNote && folderName === newFolder?.name && !detachedExcludedFolder) {
|
||||
addCSSClassToFileExplorerEl(file.path, 'is-folder-note', false, plugin);
|
||||
addCSSClassToFileExplorerEl(newFolder.path, 'has-folder-note', false, plugin);
|
||||
return;
|
||||
} else if (excludedFolder?.disableFolderNote || (folderName !== newFolder?.name)) {
|
||||
removeCSSClassFromFileExplorerEL(file.path, 'is-folder-note', false, plugin);
|
||||
removeCSSClassFromFileExplorerEL(newFolder?.path || '', 'has-folder-note', false, plugin);
|
||||
}
|
||||
|
||||
if (excludedFolder?.disableSync || !plugin.settings.syncFolderName) { return; }
|
||||
|
||||
|
||||
if (folderName === newFolder?.name) {
|
||||
addCSSClassToFileExplorerEl(file.path, 'is-folder-note', false, plugin);
|
||||
removeCSSClassFromFileExplorerEL(oldFolder?.path, 'has-folder-note', false, plugin);
|
||||
addCSSClassToFileExplorerEl(newFolder.path, 'has-folder-note', false, plugin);
|
||||
// Handle folder note creation
|
||||
if (shouldCreateFolderNote(excludedFolder, folderName, newFolder, detachedExcludedFolder)) {
|
||||
if (newFolder) {
|
||||
handleFolderNoteCreation(file, newFolder, plugin);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// file matched folder name before rename
|
||||
// file hasnt moved just renamed
|
||||
// Need to rename the folder
|
||||
if (!oldFolder) return;
|
||||
if (oldFolderName === oldFolder.name && newFolder?.path === oldFolder.path) {
|
||||
return renameFolderOnFileRename(file, oldPath, oldFolder, plugin);
|
||||
} else if (folderNote && oldFolderName === oldFolder.name) {
|
||||
return renameFolderOnFileRename(file, oldPath, oldFolder, plugin);
|
||||
// Handle folder note removal
|
||||
if (shouldRemoveFolderNoteClasses(excludedFolder, folderName, newFolder)) {
|
||||
handleFolderNoteRemoval(file, newFolder, plugin);
|
||||
}
|
||||
|
||||
// Early return if sync is disabled
|
||||
if (excludedFolder?.disableSync || !plugin.settings.syncFolderName) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Handle same folder rename
|
||||
if (folderName === newFolder?.name && newFolder) {
|
||||
handleSameFolderRename(file, newFolder, oldFolder, plugin);
|
||||
return;
|
||||
}
|
||||
|
||||
// Handle folder rename on file rename
|
||||
if (shouldRenameFolderOnFileRename(oldFolderName, oldFolder, newFolder, folderNote)) {
|
||||
return renameFolderOnFileRename(file, oldPath, oldFolder!, plugin);
|
||||
}
|
||||
}
|
||||
|
||||
async function renameFolderOnFileRename(file: TFile, oldPath: string, oldFolder: TAbstractFile, plugin: FolderNotesPlugin) {
|
||||
async function renameFolderOnFileRename(
|
||||
file: TFile,
|
||||
oldPath: string,
|
||||
oldFolder: TAbstractFile,
|
||||
plugin: FolderNotesPlugin,
|
||||
): Promise<void> {
|
||||
const newFolderName = extractFolderName(plugin.settings.folderNoteName, file.basename);
|
||||
if (!newFolderName) {
|
||||
removeCSSClassFromFileExplorerEL(oldFolder.path, 'has-folder-note', false, plugin);
|
||||
|
|
@ -255,14 +335,19 @@ async function renameFolderOnFileRename(file: TFile, oldPath: string, oldFolder:
|
|||
|
||||
if (plugin.app.vault.getAbstractFileByPath(newFolderPath)) {
|
||||
await plugin.app.fileManager.renameFile(file, oldPath);
|
||||
return new Notice('A folder with the same name already exists');
|
||||
new Notice('A folder with the same name already exists');
|
||||
return;
|
||||
}
|
||||
plugin.app.fileManager.renameFile(oldFolder, newFolderPath);
|
||||
}
|
||||
|
||||
function updateExcludedFolderPath(folder: TFolder, oldPath: string, plugin: FolderNotesPlugin) {
|
||||
function updateExcludedFolderPath(
|
||||
folder: TFolder,
|
||||
oldPath: string,
|
||||
plugin: FolderNotesPlugin,
|
||||
): void {
|
||||
const excludedFolders = plugin.settings.excludeFolders.filter(
|
||||
(excludedFolder) => excludedFolder.path?.includes(oldPath)
|
||||
(excludedFolder) => excludedFolder.path?.includes(oldPath),
|
||||
);
|
||||
|
||||
excludedFolders.forEach((excludedFolder) => {
|
||||
|
|
@ -281,3 +366,68 @@ function updateExcludedFolderPath(folder: TFolder, oldPath: string, plugin: Fold
|
|||
});
|
||||
plugin.saveSettings();
|
||||
}
|
||||
|
||||
|
||||
function shouldCreateFolderNote(
|
||||
excludedFolder: ExcludedFolder | undefined,
|
||||
folderName: string,
|
||||
newFolder: TAbstractFile | null,
|
||||
detachedExcludedFolder: ExcludedFolder | undefined,
|
||||
): boolean {
|
||||
return !excludedFolder?.disableFolderNote
|
||||
&& folderName === (newFolder as TFolder)?.name
|
||||
&& !detachedExcludedFolder;
|
||||
}
|
||||
|
||||
function shouldRemoveFolderNoteClasses(
|
||||
excludedFolder: ExcludedFolder | undefined,
|
||||
folderName: string,
|
||||
newFolder: TAbstractFile | null,
|
||||
): boolean {
|
||||
return excludedFolder?.disableFolderNote || (folderName !== (newFolder as TFolder)?.name);
|
||||
}
|
||||
|
||||
function handleFolderNoteCreation(
|
||||
file: TFile,
|
||||
newFolder: TAbstractFile,
|
||||
plugin: FolderNotesPlugin,
|
||||
): void {
|
||||
addCSSClassToFileExplorerEl(file.path, 'is-folder-note', false, plugin);
|
||||
addCSSClassToFileExplorerEl(newFolder.path, 'has-folder-note', false, plugin);
|
||||
}
|
||||
|
||||
function handleFolderNoteRemoval(
|
||||
file: TFile,
|
||||
newFolder: TAbstractFile | null,
|
||||
plugin: FolderNotesPlugin,
|
||||
): void {
|
||||
removeCSSClassFromFileExplorerEL(file.path, 'is-folder-note', false, plugin);
|
||||
removeCSSClassFromFileExplorerEL(newFolder?.path || '', 'has-folder-note', false, plugin);
|
||||
}
|
||||
|
||||
function handleSameFolderRename(
|
||||
file: TFile,
|
||||
newFolder: TAbstractFile,
|
||||
oldFolder: TAbstractFile | null,
|
||||
plugin: FolderNotesPlugin,
|
||||
): void {
|
||||
addCSSClassToFileExplorerEl(file.path, 'is-folder-note', false, plugin);
|
||||
removeCSSClassFromFileExplorerEL(oldFolder?.path, 'has-folder-note', false, plugin);
|
||||
addCSSClassToFileExplorerEl(newFolder.path, 'has-folder-note', false, plugin);
|
||||
}
|
||||
|
||||
function shouldRenameFolderOnFileRename(
|
||||
oldFolderName: string,
|
||||
oldFolder: TAbstractFile | null,
|
||||
newFolder: TAbstractFile | null,
|
||||
folderNote: TFile | null | undefined,
|
||||
): boolean {
|
||||
if (!oldFolder) return false;
|
||||
|
||||
const oldFolderAsFolder = oldFolder as TFolder;
|
||||
const newFolderAsFolder = newFolder as TFolder;
|
||||
|
||||
return (oldFolderName === oldFolderAsFolder.name
|
||||
&& newFolderAsFolder?.path === oldFolderAsFolder.path)
|
||||
|| (folderNote !== null && oldFolderName === oldFolderAsFolder.name);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,19 +18,19 @@ export class ListComponent {
|
|||
this.defaultValues = defaultValues;
|
||||
}
|
||||
|
||||
on(event: string, listener: (data?: any) => void) {
|
||||
on(event: string, listener: (data?: unknown) => void): void {
|
||||
this.emitter.on(event, listener);
|
||||
}
|
||||
|
||||
off(event: string, listener: (data?: any) => void) {
|
||||
off(event: string, listener: (data?: unknown) => void): void {
|
||||
this.emitter.off(event, listener);
|
||||
}
|
||||
|
||||
private emit(event: string, data?: any) {
|
||||
private emit(event: string, data?: unknown): void {
|
||||
this.emitter.emit(event, data);
|
||||
}
|
||||
|
||||
setValues(values: string[]) {
|
||||
setValues(values: string[]): void {
|
||||
this.removeElements();
|
||||
this.values = values;
|
||||
if (values.length !== 0) {
|
||||
|
|
@ -41,11 +41,11 @@ export class ListComponent {
|
|||
this.emit('update', this.values);
|
||||
}
|
||||
|
||||
removeElements() {
|
||||
removeElements(): void {
|
||||
this.listEl.empty();
|
||||
}
|
||||
|
||||
addElement(value: string) {
|
||||
addElement(value: string): void {
|
||||
this.listEl.createSpan('setting-hotkey', (span) => {
|
||||
if (value.toLocaleLowerCase() === 'md') {
|
||||
span.innerText = 'markdown';
|
||||
|
|
@ -53,35 +53,39 @@ export class ListComponent {
|
|||
span.innerText = value;
|
||||
}
|
||||
span.setAttribute('extension', value);
|
||||
// eslint-disable-next-line max-len
|
||||
const removeSpan = span.createEl('span', { cls: 'ofn-list-item-remove setting-hotkey-icon' });
|
||||
// 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 svgElement = removeSpan.createEl('span', { cls: 'ofn-list-item-remove-icon' });
|
||||
svgElement.innerHTML = svg;
|
||||
removeSpan.onClickEvent((e) => {
|
||||
removeSpan.onClickEvent(() => {
|
||||
this.removeValue(value);
|
||||
span.remove();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
async addValue(value: string) {
|
||||
async addValue(value: string): Promise<void> {
|
||||
this.values.push(value);
|
||||
this.addElement(value);
|
||||
this.emit('add', value);
|
||||
this.emit('update', this.values);
|
||||
}
|
||||
|
||||
addResetButton() {
|
||||
addResetButton(): this {
|
||||
// eslint-disable-next-line max-len
|
||||
const resetButton = this.controlEl.createEl('span', { cls: 'clickable-icon setting-restore-hotkey-button' });
|
||||
// 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>';
|
||||
resetButton.innerHTML = svg;
|
||||
resetButton.onClickEvent((e) => {
|
||||
resetButton.onClickEvent(() => {
|
||||
this.setValues(this.defaultValues);
|
||||
});
|
||||
return this;
|
||||
}
|
||||
|
||||
removeValue(value: string) {
|
||||
removeValue(value: string): void {
|
||||
this.values = this.values.filter((v) => v !== value);
|
||||
this.listEl.find(`[extension='${value}']`).remove();
|
||||
this.emit('remove', value);
|
||||
|
|
|
|||
|
|
@ -1,19 +1,36 @@
|
|||
import { WorkspaceLeaf, App } from 'obsidian';
|
||||
import type { WorkspaceLeaf, App } from 'obsidian';
|
||||
|
||||
export async function openExcalidrawView(leaf: WorkspaceLeaf) {
|
||||
const { excalidraw, excalidrawEnabled } = await getExcalidrawPlugin(this.app);
|
||||
if (excalidrawEnabled) {
|
||||
interface ExcalidrawPlugin {
|
||||
setExcalidrawView(leaf: WorkspaceLeaf): void;
|
||||
}
|
||||
|
||||
export async function openExcalidrawView(
|
||||
app: App,
|
||||
leaf: WorkspaceLeaf,
|
||||
): Promise<void> {
|
||||
const { excalidraw, excalidrawEnabled } = await getExcalidrawPlugin(app);
|
||||
if (excalidrawEnabled && excalidraw) {
|
||||
excalidraw.setExcalidrawView(leaf);
|
||||
}
|
||||
}
|
||||
|
||||
export async function getExcalidrawPlugin(app: App) {
|
||||
const excalidraw = (app as any).plugins.plugins['obsidian-excalidraw-plugin'];
|
||||
const excalidrawEnabled = (app as any).plugins.enabledPlugins.has(
|
||||
'obsidian-excalidraw-plugin'
|
||||
export async function getExcalidrawPlugin(
|
||||
app: App,
|
||||
): Promise<{ excalidraw: ExcalidrawPlugin | null; excalidrawEnabled: boolean }> {
|
||||
const { plugins: pluginManager } = app as App & {
|
||||
plugins: {
|
||||
plugins: Record<string, unknown>;
|
||||
enabledPlugins: Set<string>;
|
||||
};
|
||||
};
|
||||
const excalidraw = (
|
||||
pluginManager.plugins[
|
||||
'obsidian-excalidraw-plugin'
|
||||
] as unknown as ExcalidrawPlugin | undefined
|
||||
);
|
||||
const excalidrawEnabled = pluginManager.enabledPlugins.has('obsidian-excalidraw-plugin');
|
||||
return {
|
||||
excalidraw,
|
||||
excalidraw: excalidraw ?? null,
|
||||
excalidrawEnabled,
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,14 +1,39 @@
|
|||
import FolderNotesPlugin from '../main';
|
||||
/* eslint-disable complexity */
|
||||
/* eslint-disable max-len */
|
||||
import type FolderNotesPlugin from '../main';
|
||||
import ExistingFolderNoteModal from '../modals/ExistingNote';
|
||||
import { applyTemplate } from '../template';
|
||||
import { TFolder, TFile, TAbstractFile, Keymap } from 'obsidian';
|
||||
import {
|
||||
TFolder,
|
||||
TFile,
|
||||
Keymap,
|
||||
type TAbstractFile,
|
||||
type MarkdownView,
|
||||
type WorkspaceLeaf,
|
||||
} from 'obsidian';
|
||||
import DeleteConfirmationModal from '../modals/DeleteConfirmation';
|
||||
import { addExcludedFolder, deleteExcludedFolder, getDetachedFolder, getExcludedFolder, updateExcludedFolder } from '../ExcludeFolders/functions/folderFunctions';
|
||||
import {
|
||||
addExcludedFolder,
|
||||
deleteExcludedFolder,
|
||||
getDetachedFolder,
|
||||
getExcludedFolder,
|
||||
updateExcludedFolder,
|
||||
} from '../ExcludeFolders/functions/folderFunctions';
|
||||
import { ExcludedFolder } from '../ExcludeFolders/ExcludeFolder';
|
||||
import { openExcalidrawView } from './excalidraw';
|
||||
import { AskForExtensionModal } from 'src/modals/AskForExtension';
|
||||
import { addCSSClassToFileExplorerEl, removeCSSClassFromFileExplorerEL, removeActiveFolder, setActiveFolder } from 'src/functions/styleFunctions';
|
||||
import { getFolderNameFromPathString, getFolderPathFromString, removeExtension } from 'src/functions/utils';
|
||||
import {
|
||||
addCSSClassToFileExplorerEl,
|
||||
removeCSSClassFromFileExplorerEL,
|
||||
removeActiveFolder,
|
||||
setActiveFolder,
|
||||
} from 'src/functions/styleFunctions';
|
||||
import {
|
||||
getFolderNameFromPathString,
|
||||
getFolderPathFromString,
|
||||
removeExtension,
|
||||
} from 'src/functions/utils';
|
||||
|
||||
|
||||
const defaultExcalidrawTemplate = `---
|
||||
|
||||
|
|
@ -26,24 +51,36 @@ tags: [excalidraw]
|
|||
\`\`\`
|
||||
%%`;
|
||||
|
||||
export async function createFolderNote(plugin: FolderNotesPlugin, folderPath: string, openFile: boolean, extension?: string, displayModal?: boolean, preexistingNote?: TFile) {
|
||||
const leaf = plugin.app.workspace.getLeaf(false);
|
||||
const folderName = getFolderNameFromPathString(folderPath);
|
||||
const fileName = plugin.settings.folderNoteName.replace('{{folder_name}}', folderName);
|
||||
let folderNote = getFolderNote(plugin, folderPath);
|
||||
if (preexistingNote) {
|
||||
folderNote = preexistingNote;
|
||||
}
|
||||
let folderNoteType = extension ?? plugin.settings.folderNoteType;
|
||||
const detachedFolder = getDetachedFolder(plugin, folderPath);
|
||||
let path = '';
|
||||
export async function createFolderNote(
|
||||
plugin: FolderNotesPlugin,
|
||||
folderPath: string,
|
||||
openFile: boolean,
|
||||
extension?: string,
|
||||
displayModal?: boolean,
|
||||
preexistingNote?: TFile,
|
||||
): Promise<void> {
|
||||
let {
|
||||
leaf,
|
||||
fileName,
|
||||
folderNote,
|
||||
folderNoteType,
|
||||
detachedFolder,
|
||||
path,
|
||||
} = getArgs(plugin, folderPath, extension, preexistingNote);
|
||||
|
||||
if (folderNoteType === '.excalidraw') {
|
||||
folderNoteType = '.md';
|
||||
extension = '.excalidraw';
|
||||
} else if (folderNoteType === '.ask') {
|
||||
if (plugin.askModalCurrentlyOpen) return;
|
||||
return new AskForExtensionModal(plugin, folderPath, openFile, folderNoteType, displayModal, preexistingNote).open();
|
||||
return new AskForExtensionModal(
|
||||
plugin,
|
||||
folderPath,
|
||||
openFile,
|
||||
folderNoteType,
|
||||
displayModal,
|
||||
preexistingNote,
|
||||
).open();
|
||||
}
|
||||
|
||||
if (plugin.settings.storageLocation === 'parentFolder') {
|
||||
|
|
@ -60,27 +97,7 @@ export async function createFolderNote(plugin: FolderNotesPlugin, folderPath: st
|
|||
}
|
||||
|
||||
if (detachedFolder && folderNote?.extension !== extension && folderNote) {
|
||||
deleteExcludedFolder(plugin, detachedFolder);
|
||||
removeCSSClassFromFileExplorerEL(folderNote?.path, 'is-folder-note', false, plugin);
|
||||
const folder = plugin.app.vault.getAbstractFileByPath(folderPath) as TFolder;
|
||||
if (!folderNote || folderNote.basename !== fileName) return;
|
||||
let count = 1;
|
||||
let newName = removeExtension(folderNote.path) + ` (${count}).${folderNote.path.split('.').pop()}`;
|
||||
while (count < 100 && plugin.app.vault.getAbstractFileByPath(newName)) {
|
||||
count++;
|
||||
newName = removeExtension(folderNote.path) + ` (${count}).${folderNote.path.split('.').pop()}`;
|
||||
}
|
||||
const [excludedFolder, excludedFolderExisted, disabledSync] = await tempDisableSync(plugin, folder);
|
||||
|
||||
await plugin.app.fileManager.renameFile(folderNote, newName).then(() => {
|
||||
if (!excludedFolder) return;
|
||||
if (!excludedFolderExisted) {
|
||||
deleteExcludedFolder(plugin, excludedFolder);
|
||||
} else if (!disabledSync) {
|
||||
excludedFolder.disableSync = false;
|
||||
updateExcludedFolder(plugin, excludedFolder, excludedFolder);
|
||||
}
|
||||
});
|
||||
await handleTurnNoteIntoFolderNote(plugin, folderNote, detachedFolder, folderPath, fileName);
|
||||
}
|
||||
|
||||
if (!extension) {
|
||||
|
|
@ -88,33 +105,7 @@ export async function createFolderNote(plugin: FolderNotesPlugin, folderPath: st
|
|||
}
|
||||
|
||||
if (!folderNote) {
|
||||
let content = '';
|
||||
if (extension !== '.md' && extension) {
|
||||
if (plugin.settings.templatePath && folderNoteType.split('.').pop() === plugin.settings.templatePath.split('.').pop()) {
|
||||
const templateFile = plugin.app.vault.getAbstractFileByPath(plugin.settings.templatePath);
|
||||
if (templateFile instanceof TFile) {
|
||||
if (['md', 'canvas', 'txt'].includes(templateFile.extension)) {
|
||||
content = await plugin.app.vault.read(templateFile);
|
||||
if (extension === '.excalidraw' && !content.includes('==⚠ Switch to EXCALIDRAW VIEW in the MORE OPTIONS menu of this document. ⚠==')) {
|
||||
content = defaultExcalidrawTemplate;
|
||||
}
|
||||
} else {
|
||||
return plugin.app.vault.readBinary(templateFile).then(async (data) => {
|
||||
folderNote = await plugin.app.vault.createBinary(path, data);
|
||||
if (openFile) {
|
||||
await leaf.openFile(folderNote);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
} else if (plugin.settings.folderNoteType === '.excalidraw' || extension === '.excalidraw') {
|
||||
content = defaultExcalidrawTemplate;
|
||||
} else if (plugin.settings.folderNoteType === '.canvas') {
|
||||
content = '{}';
|
||||
}
|
||||
}
|
||||
|
||||
folderNote = await plugin.app.vault.create(path, content);
|
||||
folderNote = await handleCreateFolderNote(plugin, folderNoteType, openFile, leaf, folderNote, path, extension);
|
||||
} else {
|
||||
await plugin.app.fileManager.renameFile(folderNote, path);
|
||||
}
|
||||
|
|
@ -130,11 +121,13 @@ export async function createFolderNote(plugin: FolderNotesPlugin, folderPath: st
|
|||
}
|
||||
await leaf.openFile(folderNote);
|
||||
if (plugin.settings.folderNoteType === '.excalidraw' || extension === '.excalidraw') {
|
||||
openExcalidrawView(leaf);
|
||||
openExcalidrawView(plugin.app, leaf);
|
||||
}
|
||||
}
|
||||
|
||||
const matchingExtension = extension?.split('.').pop() === plugin.settings.templatePath.split('.').pop();
|
||||
const matchingExtension =
|
||||
extension?.split('.').pop() ===
|
||||
plugin.settings.templatePath.split('.').pop();
|
||||
if (folderNote && matchingExtension && plugin.settings.folderNoteType !== '.excalidraw') {
|
||||
applyTemplate(plugin, folderNote, leaf, plugin.settings.templatePath);
|
||||
}
|
||||
|
|
@ -145,19 +138,159 @@ export async function createFolderNote(plugin: FolderNotesPlugin, folderPath: st
|
|||
addCSSClassToFileExplorerEl(folder.path, 'has-folder-note', false, plugin);
|
||||
}
|
||||
|
||||
export async function turnIntoFolderNote(plugin: FolderNotesPlugin, file: TFile, folder: TFolder, folderNote?: TFile | null | TAbstractFile, skipConfirmation?: boolean) {
|
||||
const extension = file.extension;
|
||||
function getArgs(
|
||||
plugin: FolderNotesPlugin,
|
||||
folderPath: string,
|
||||
extension?: string,
|
||||
preexistingNote?: TFile,
|
||||
): {
|
||||
leaf: WorkspaceLeaf;
|
||||
fileName: string;
|
||||
folderNote: TFile | null | undefined;
|
||||
folderNoteType: string;
|
||||
detachedFolder: ExcludedFolder | undefined;
|
||||
path: string | '';
|
||||
} {
|
||||
const leaf = plugin.app.workspace.getLeaf(false);
|
||||
const folderName = getFolderNameFromPathString(folderPath);
|
||||
const fileName = plugin.settings.folderNoteName.replace('{{folder_name}}', folderName);
|
||||
let folderNote = getFolderNote(plugin, folderPath);
|
||||
if (preexistingNote) {
|
||||
folderNote = preexistingNote;
|
||||
}
|
||||
let folderNoteType = extension ?? plugin.settings.folderNoteType;
|
||||
const detachedFolder = getDetachedFolder(plugin, folderPath);
|
||||
let path = '';
|
||||
|
||||
return {
|
||||
leaf,
|
||||
fileName,
|
||||
folderNote,
|
||||
folderNoteType,
|
||||
detachedFolder,
|
||||
path,
|
||||
};
|
||||
}
|
||||
|
||||
async function handleCreateFolderNote(plugin: FolderNotesPlugin, folderNoteType: string, openFile: boolean, leaf: WorkspaceLeaf, folderNote: TFile | null | undefined, path: string, extension?: string): Promise<TFile> {
|
||||
let content = '';
|
||||
if (extension !== '.md' && extension) {
|
||||
if (
|
||||
plugin.settings.templatePath &&
|
||||
folderNoteType.split('.').pop() ===
|
||||
plugin.settings.templatePath.split('.').pop()
|
||||
) {
|
||||
const templateFile = plugin.app.vault.getAbstractFileByPath(
|
||||
plugin.settings.templatePath,
|
||||
);
|
||||
if (templateFile instanceof TFile) {
|
||||
if (['md', 'canvas', 'txt'].includes(templateFile.extension)) {
|
||||
content = await plugin.app.vault.read(templateFile);
|
||||
if (
|
||||
extension === '.excalidraw' &&
|
||||
!content.includes(
|
||||
'==⚠ Switch to EXCALIDRAW VIEW in the MORE OPTIONS menu of this document. ⚠==',
|
||||
)
|
||||
) {
|
||||
content = defaultExcalidrawTemplate;
|
||||
}
|
||||
} else {
|
||||
plugin.app.vault.readBinary(templateFile).then(async (data) => {
|
||||
folderNote = await plugin.app.vault.createBinary(path, data);
|
||||
if (openFile) {
|
||||
await leaf.openFile(folderNote);
|
||||
}
|
||||
return folderNote;
|
||||
});
|
||||
}
|
||||
}
|
||||
} else if (
|
||||
plugin.settings.folderNoteType === '.excalidraw' ||
|
||||
extension === '.excalidraw'
|
||||
) {
|
||||
content = defaultExcalidrawTemplate;
|
||||
} else if (plugin.settings.folderNoteType === '.canvas') {
|
||||
content = '{}';
|
||||
}
|
||||
}
|
||||
|
||||
folderNote = await plugin.app.vault.create(path, content);
|
||||
return folderNote;
|
||||
}
|
||||
|
||||
async function handleTurnNoteIntoFolderNote(
|
||||
plugin: FolderNotesPlugin,
|
||||
folderNote: TFile,
|
||||
detachedFolder: ExcludedFolder,
|
||||
folderPath: string,
|
||||
fileName: string,
|
||||
): Promise<void> {
|
||||
deleteExcludedFolder(plugin, detachedFolder);
|
||||
removeCSSClassFromFileExplorerEL(folderNote?.path, 'is-folder-note', false, plugin);
|
||||
const folder = plugin.app.vault.getAbstractFileByPath(folderPath) as TFolder;
|
||||
if (!folderNote || folderNote.basename !== fileName) return;
|
||||
let count = 1;
|
||||
const baseName = removeExtension(folderNote.path);
|
||||
const ext = folderNote.path.split('.').pop();
|
||||
let newName = `${baseName} (${count}).${ext}`;
|
||||
const MAX_FOLDER_NOTE_RENAME_ATTEMPTS = 100;
|
||||
|
||||
while (
|
||||
count < MAX_FOLDER_NOTE_RENAME_ATTEMPTS &&
|
||||
plugin.app.vault.getAbstractFileByPath(newName)
|
||||
) {
|
||||
count++;
|
||||
newName = `${baseName} (${count}).${ext}`;
|
||||
}
|
||||
const [
|
||||
excludedFolder,
|
||||
excludedFolderExisted,
|
||||
disabledSync,
|
||||
] = await tempDisableSync(plugin, folder);
|
||||
|
||||
await plugin.app.fileManager.renameFile(folderNote, newName).then(() => {
|
||||
if (!excludedFolder) return;
|
||||
if (!excludedFolderExisted) {
|
||||
deleteExcludedFolder(plugin, excludedFolder);
|
||||
} else if (!disabledSync) {
|
||||
excludedFolder.disableSync = false;
|
||||
updateExcludedFolder(plugin, excludedFolder, excludedFolder);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export async function turnIntoFolderNote(
|
||||
plugin: FolderNotesPlugin,
|
||||
file: TFile,
|
||||
folder: TFolder,
|
||||
folderNote?: TFile | null | TAbstractFile,
|
||||
skipConfirmation?: boolean,
|
||||
): Promise<void> {
|
||||
const { extension } = file;
|
||||
const detachedExcludedFolder = getDetachedFolder(plugin, folder.path);
|
||||
|
||||
if (folderNote) {
|
||||
if (plugin.settings.showRenameConfirmation && !skipConfirmation && !detachedExcludedFolder) {
|
||||
if (
|
||||
plugin.settings.showRenameConfirmation &&
|
||||
!skipConfirmation &&
|
||||
!detachedExcludedFolder
|
||||
) {
|
||||
return new ExistingFolderNoteModal(plugin.app, plugin, file, folder, folderNote).open();
|
||||
}
|
||||
removeCSSClassFromFileExplorerEL(folderNote.path, 'is-folder-note', false, plugin);
|
||||
|
||||
const [excludedFolder, excludedFolderExisted, disabledSync] = await tempDisableSync(plugin, folder);
|
||||
const [
|
||||
excludedFolder,
|
||||
excludedFolderExisted,
|
||||
disabledSync,
|
||||
] = await tempDisableSync(plugin, folder);
|
||||
|
||||
const CTIME_SLICE_START = 10;
|
||||
const RANDOM_SUFFIX_MAX = 1000;
|
||||
const randomSuffix = Math.floor(Math.random() * RANDOM_SUFFIX_MAX);
|
||||
const ctimeSuffix = file.stat.ctime.toString().slice(CTIME_SLICE_START);
|
||||
const newPath = `${folder.path}/${folder.name} (${ctimeSuffix}${randomSuffix}).${extension}`;
|
||||
|
||||
const newPath = `${folder.path}/${folder.name} (${file.stat.ctime.toString().slice(10) + Math.floor(Math.random() * 1000)}).${extension}`;
|
||||
plugin.app.fileManager.renameFile(folderNote, newPath).then(() => {
|
||||
if (!excludedFolder) return;
|
||||
if (!excludedFolderExisted) {
|
||||
|
|
@ -194,14 +327,28 @@ export async function turnIntoFolderNote(plugin: FolderNotesPlugin, file: TFile,
|
|||
setActiveFolder(folder.path, plugin);
|
||||
}
|
||||
|
||||
export async function tempDisableSync(plugin: FolderNotesPlugin, folder: TFolder): Promise<[excludedFolder: ExcludedFolder | undefined, excludedFolderExisted: boolean, disabledSync: boolean]> {
|
||||
export async function tempDisableSync(
|
||||
plugin: FolderNotesPlugin,
|
||||
folder: TFolder,
|
||||
): Promise<
|
||||
[
|
||||
excludedFolder: ExcludedFolder | undefined,
|
||||
excludedFolderExisted: boolean,
|
||||
disabledSync: boolean
|
||||
]
|
||||
> {
|
||||
let excludedFolder = getExcludedFolder(plugin, folder.path, false);
|
||||
let excludedFolderExisted = true;
|
||||
let disabledSync = false;
|
||||
|
||||
if (!excludedFolder) {
|
||||
excludedFolderExisted = false;
|
||||
excludedFolder = new ExcludedFolder(folder.path, plugin.settings.excludeFolders.length, undefined, plugin);
|
||||
excludedFolder = new ExcludedFolder(
|
||||
folder.path,
|
||||
plugin.settings.excludeFolders.length,
|
||||
undefined,
|
||||
plugin,
|
||||
);
|
||||
excludedFolder.disableSync = true;
|
||||
addExcludedFolder(plugin, excludedFolder);
|
||||
} else if (!excludedFolder.disableSync) {
|
||||
|
|
@ -213,8 +360,12 @@ export async function tempDisableSync(plugin: FolderNotesPlugin, folder: TFolder
|
|||
return [excludedFolder, excludedFolderExisted, disabledSync];
|
||||
}
|
||||
|
||||
export async function openFolderNote(plugin: FolderNotesPlugin, file: TAbstractFile, evt?: MouseEvent) {
|
||||
const path = file.path;
|
||||
export async function openFolderNote(
|
||||
plugin: FolderNotesPlugin,
|
||||
file: TAbstractFile,
|
||||
evt?: MouseEvent,
|
||||
): Promise<void> {
|
||||
const { path } = file;
|
||||
const focusExistingTab = plugin.settings.focusExistingTab && plugin.settings.openInNewTab;
|
||||
const activeFilePath = plugin.app.workspace.getActiveFile()?.path;
|
||||
|
||||
|
|
@ -229,7 +380,7 @@ export async function openFolderNote(plugin: FolderNotesPlugin, file: TAbstractF
|
|||
plugin.app.workspace.iterateAllLeaves((leaf) => {
|
||||
if (
|
||||
leaf.getViewState().type === 'markdown' &&
|
||||
(leaf.view as import('obsidian').MarkdownView).file?.path === path
|
||||
(leaf.view as MarkdownView).file?.path === path
|
||||
) {
|
||||
foundLeaf = leaf;
|
||||
}
|
||||
|
|
@ -239,14 +390,19 @@ export async function openFolderNote(plugin: FolderNotesPlugin, file: TAbstractF
|
|||
if (foundLeaf) {
|
||||
plugin.app.workspace.setActiveLeaf(foundLeaf, { focus: true });
|
||||
} else {
|
||||
const leaf = plugin.app.workspace.getLeaf(Keymap.isModEvent(evt) || plugin.settings.openInNewTab);
|
||||
const shouldOpenInNewTab = Keymap.isModEvent(evt) || plugin.settings.openInNewTab;
|
||||
const leaf = plugin.app.workspace.getLeaf(shouldOpenInNewTab);
|
||||
if (file instanceof TFile) {
|
||||
await leaf.openFile(file);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export async function deleteFolderNote(plugin: FolderNotesPlugin, file: TFile, displayModal: boolean) {
|
||||
export async function deleteFolderNote(
|
||||
plugin: FolderNotesPlugin,
|
||||
file: TFile,
|
||||
displayModal: boolean,
|
||||
): Promise<void> {
|
||||
if (plugin.settings.showDeleteConfirmation && displayModal) {
|
||||
return new DeleteConfirmationModal(plugin.app, plugin, file).open();
|
||||
}
|
||||
|
|
@ -271,7 +427,7 @@ export async function deleteFolderNote(plugin: FolderNotesPlugin, file: TFile, d
|
|||
}
|
||||
}
|
||||
|
||||
export function extractFolderName(template: string, changedFileName: string) {
|
||||
export function extractFolderName(template: string, changedFileName: string): string | null {
|
||||
const [prefix, suffix] = template.split('{{folder_name}}');
|
||||
if (prefix.trim() === '' && suffix.trim() === '') {
|
||||
return changedFileName;
|
||||
|
|
@ -287,58 +443,69 @@ export function extractFolderName(template: string, changedFileName: string) {
|
|||
return null;
|
||||
}
|
||||
|
||||
export function getFolderNote(plugin: FolderNotesPlugin, folderPath: string, storageLocation?: string, file?: TFile, oldFolderNoteName?: string) {
|
||||
if (!folderPath) return null;
|
||||
const folder = {
|
||||
path: folderPath,
|
||||
name: getFolderNameFromPathString(folderPath),
|
||||
};
|
||||
const folderNoteName = oldFolderNoteName ?? plugin.settings.folderNoteName;
|
||||
|
||||
let fileName = folderNoteName.replace('{{folder_name}}', folder.name);
|
||||
if (file) {
|
||||
fileName = folderNoteName.replace('{{folder_name}}', file.basename);
|
||||
}
|
||||
if (!fileName) return null;
|
||||
|
||||
if ((plugin.settings.storageLocation === 'parentFolder' || storageLocation === 'parentFolder') && storageLocation !== 'insideFolder') {
|
||||
folder.path = getFolderPathFromString(folderPath);
|
||||
}
|
||||
|
||||
|
||||
let path = `${folder.path}/${fileName}`;
|
||||
folder.path === '/' ? path = fileName : path = `${folder.path}/${fileName}`;
|
||||
|
||||
|
||||
let folderNoteType = plugin.settings.folderNoteType;
|
||||
if (folderNoteType === '.excalidraw') {
|
||||
folderNoteType = '.md';
|
||||
}
|
||||
|
||||
let folderNote = plugin.app.vault.getAbstractFileByPath(path + folderNoteType);
|
||||
if (folderNote instanceof TFile && plugin.settings.supportedFileTypes.includes(plugin.settings.folderNoteType.replace('.', ''))) {
|
||||
function findFolderNoteFile(
|
||||
plugin: FolderNotesPlugin,
|
||||
path: string,
|
||||
primaryType: string,
|
||||
): TFile | null {
|
||||
let folderNote = plugin.app.vault.getAbstractFileByPath(path + primaryType);
|
||||
if (
|
||||
folderNote instanceof TFile &&
|
||||
plugin.settings.supportedFileTypes.includes(primaryType.replace('.', ''))
|
||||
) {
|
||||
return folderNote;
|
||||
} else {
|
||||
const supportedFileTypes = plugin.settings.supportedFileTypes.filter((type) => type !== plugin.settings.folderNoteType.replace('.', ''));
|
||||
for (let type of supportedFileTypes) {
|
||||
if (type === 'excalidraw' || type === '.excalidraw') {
|
||||
type = '.md';
|
||||
}
|
||||
if (!type.startsWith('.')) {
|
||||
type = '.' + type;
|
||||
}
|
||||
folderNote = plugin.app.vault.getAbstractFileByPath(path + type);
|
||||
if (folderNote instanceof TFile) {
|
||||
return folderNote;
|
||||
}
|
||||
}
|
||||
|
||||
const supportedFileTypes = plugin.settings.supportedFileTypes.filter(
|
||||
(type) => type !== primaryType.replace('.', ''),
|
||||
);
|
||||
|
||||
for (let type of supportedFileTypes) {
|
||||
if (type === 'excalidraw' || type === '.excalidraw') {
|
||||
type = '.md';
|
||||
}
|
||||
if (!type.startsWith('.')) {
|
||||
type = '.' + type;
|
||||
}
|
||||
folderNote = plugin.app.vault.getAbstractFileByPath(path + type);
|
||||
if (folderNote instanceof TFile) {
|
||||
return folderNote;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
export function detachFolderNote(plugin: FolderNotesPlugin, file: TFile) {
|
||||
export function getFolderNote(
|
||||
plugin: FolderNotesPlugin,
|
||||
folderPath: string,
|
||||
storageLocation?: string,
|
||||
file?: TFile,
|
||||
oldFolderNoteName?: string,
|
||||
): TFile | null | undefined {
|
||||
const folder = getFolderInfo(folderPath);
|
||||
if (!folder) return null;
|
||||
|
||||
let fileName = resolveFileName(plugin, folder, file, oldFolderNoteName);
|
||||
if (!fileName) return null;
|
||||
|
||||
adjustFolderPathForStorage(folder, folderPath, plugin, storageLocation);
|
||||
|
||||
const path = buildFullPath(folder, fileName);
|
||||
const primaryType = normalizeFolderNoteType(plugin.settings.folderNoteType);
|
||||
|
||||
return findFolderNoteFile(plugin, path, primaryType);
|
||||
}
|
||||
|
||||
|
||||
export function detachFolderNote(plugin: FolderNotesPlugin, file: TFile): void {
|
||||
const folder = getFolder(plugin, file);
|
||||
if (!folder) return;
|
||||
const excludedFolder = new ExcludedFolder(folder.path, plugin.settings.excludeFolders.length, undefined, plugin);
|
||||
const excludedFolder = new ExcludedFolder(
|
||||
folder.path,
|
||||
plugin.settings.excludeFolders.length,
|
||||
undefined,
|
||||
plugin,
|
||||
);
|
||||
excludedFolder.hideInSettings = true;
|
||||
excludedFolder.disableFolderNote = true;
|
||||
excludedFolder.disableSync = true;
|
||||
|
|
@ -350,16 +517,28 @@ export function detachFolderNote(plugin: FolderNotesPlugin, file: TFile) {
|
|||
}
|
||||
|
||||
|
||||
export function getFolder(plugin: FolderNotesPlugin, file: TFile, storageLocation?: string) {
|
||||
export function getFolder(
|
||||
plugin: FolderNotesPlugin,
|
||||
file: TFile,
|
||||
storageLocation?: string,
|
||||
): TFolder | TAbstractFile | null {
|
||||
if (!file) return null;
|
||||
let folderName = extractFolderName(plugin.settings.folderNoteName, file.basename);
|
||||
if (plugin.settings.folderNoteName === file.basename && plugin.settings.storageLocation === 'insideFolder') {
|
||||
if (
|
||||
plugin.settings.folderNoteName === file.basename &&
|
||||
plugin.settings.storageLocation === 'insideFolder'
|
||||
) {
|
||||
folderName = file.parent?.name ?? '';
|
||||
}
|
||||
if (!folderName) return null;
|
||||
let folderPath = getFolderPathFromString(file.path);
|
||||
let folder: TFolder | TAbstractFile | null = null;
|
||||
if ((plugin.settings.storageLocation === 'parentFolder' || storageLocation === 'parentFolder') && storageLocation !== 'insideFolder') {
|
||||
|
||||
if (
|
||||
(plugin.settings.storageLocation === 'parentFolder' ||
|
||||
storageLocation === 'parentFolder') &&
|
||||
storageLocation !== 'insideFolder'
|
||||
) {
|
||||
if (folderPath.trim() === '' || folderPath === '/') {
|
||||
folderPath = folderName;
|
||||
} else {
|
||||
|
|
@ -369,11 +548,16 @@ export function getFolder(plugin: FolderNotesPlugin, file: TFile, storageLocatio
|
|||
} else {
|
||||
folder = plugin.app.vault.getAbstractFileByPath(folderPath);
|
||||
}
|
||||
|
||||
if (!folder) { return null; }
|
||||
return folder;
|
||||
}
|
||||
|
||||
export function getFolderNoteFolder(plugin: FolderNotesPlugin, folderNote: TFile | string, fileName: string) {
|
||||
export function getFolderNoteFolder(
|
||||
plugin: FolderNotesPlugin,
|
||||
folderNote: TFile | string,
|
||||
fileName: string,
|
||||
): TFolder | TAbstractFile | null {
|
||||
if (!folderNote) return null;
|
||||
let filePath = '';
|
||||
if (typeof folderNote === 'string') {
|
||||
|
|
@ -398,3 +582,46 @@ export function getFolderNoteFolder(plugin: FolderNotesPlugin, folderNote: TFile
|
|||
if (!folder) { return null; }
|
||||
return folder;
|
||||
}
|
||||
|
||||
function getFolderInfo(folderPath: string): { path: string; name: string } | null {
|
||||
if (!folderPath) return null;
|
||||
return {
|
||||
path: folderPath,
|
||||
name: getFolderNameFromPathString(folderPath),
|
||||
};
|
||||
}
|
||||
|
||||
function resolveFileName(
|
||||
plugin: FolderNotesPlugin,
|
||||
folder: { path: string; name: string },
|
||||
file?: TFile,
|
||||
oldFolderNoteName?: string,
|
||||
): string | null {
|
||||
const templateName = oldFolderNoteName ?? plugin.settings.folderNoteName;
|
||||
if (!templateName) return null;
|
||||
const nameSource = file ? file.basename : folder.name;
|
||||
return templateName.replace('{{folder_name}}', nameSource);
|
||||
}
|
||||
|
||||
function adjustFolderPathForStorage(
|
||||
folder: { path: string; name: string },
|
||||
folderPath: string,
|
||||
plugin: FolderNotesPlugin,
|
||||
storageLocation?: string,
|
||||
): void {
|
||||
if (
|
||||
(plugin.settings.storageLocation === 'parentFolder' ||
|
||||
storageLocation === 'parentFolder') &&
|
||||
storageLocation !== 'insideFolder'
|
||||
) {
|
||||
folder.path = getFolderPathFromString(folderPath);
|
||||
}
|
||||
}
|
||||
|
||||
function buildFullPath(folder: { path: string }, fileName: string): string {
|
||||
return folder.path === '/' ? fileName : `${folder.path}/${fileName}`;
|
||||
}
|
||||
|
||||
function normalizeFolderNoteType(type: string): string {
|
||||
return type === '.excalidraw' ? '.md' : type;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,15 +1,19 @@
|
|||
import { TFile, TFolder } from 'obsidian';
|
||||
import FolderNotesPlugin from '../main';
|
||||
import { getDetachedFolder, getExcludedFolder, addExcludedFolder } from 'src/ExcludeFolders/functions/folderFunctions';
|
||||
import type FolderNotesPlugin from '../main';
|
||||
import {
|
||||
getDetachedFolder,
|
||||
getExcludedFolder,
|
||||
addExcludedFolder,
|
||||
} from 'src/ExcludeFolders/functions/folderFunctions';
|
||||
import { getFolder, getFolderNote } from 'src/functions/folderNoteFunctions';
|
||||
import { getFileExplorer } from './utils';
|
||||
import { ExcludedFolder } from 'src/ExcludeFolders/ExcludeFolder';
|
||||
import FolderOverviewPlugin from 'src/obsidian-folder-overview/src/main';
|
||||
import type FolderOverviewPlugin from 'src/obsidian-folder-overview/src/main';
|
||||
|
||||
/**
|
||||
* @description Refreshes the CSS classes for all folder notes in the file explorer.
|
||||
*/
|
||||
export function refreshAllFolderStyles(forceReload = false, plugin: FolderNotesPlugin) {
|
||||
export function refreshAllFolderStyles(forceReload = false, plugin: FolderNotesPlugin): void {
|
||||
if (plugin.activeFileExplorer === getFileExplorer(plugin) && !forceReload) { return; }
|
||||
plugin.activeFileExplorer = getFileExplorer(plugin);
|
||||
plugin.app.vault.getAllLoadedFiles().forEach(async (file) => {
|
||||
|
|
@ -22,7 +26,10 @@ export function refreshAllFolderStyles(forceReload = false, plugin: FolderNotesP
|
|||
/**
|
||||
* @description Updates the CSS classes for a specific folder in the file explorer.
|
||||
*/
|
||||
export async function updateCSSClassesForFolder(folderPath: string, plugin: FolderNotesPlugin) {
|
||||
export async function updateCSSClassesForFolder(
|
||||
folderPath: string,
|
||||
plugin: FolderNotesPlugin,
|
||||
): Promise<void> {
|
||||
const folder = plugin.app.vault.getAbstractFileByPath(folderPath);
|
||||
if (!folder || !(folder instanceof TFolder)) { return; }
|
||||
|
||||
|
|
@ -64,7 +71,10 @@ export async function updateCSSClassesForFolder(folderPath: string, plugin: Fold
|
|||
/**
|
||||
* @description Updates the CSS classes for a folder note file in the file explorer and then also updates the folder it belongs to.
|
||||
*/
|
||||
export async function updateCSSClassesForFolderNote(filePath: string, plugin: FolderNotesPlugin) {
|
||||
export async function updateCSSClassesForFolderNote(
|
||||
filePath: string,
|
||||
plugin: FolderNotesPlugin,
|
||||
): Promise<void> {
|
||||
const file = plugin.app.vault.getAbstractFileByPath(filePath);
|
||||
if (!file || !(file instanceof TFile)) { return; }
|
||||
|
||||
|
|
@ -74,17 +84,25 @@ export async function updateCSSClassesForFolderNote(filePath: string, plugin: Fo
|
|||
updateCSSClassesForFolder(folder.path, plugin);
|
||||
}
|
||||
|
||||
export function markFolderAndNoteWithClasses(file: TFile, folder: TFolder, plugin: FolderNotesPlugin) {
|
||||
export function markFolderAndNoteWithClasses(
|
||||
file: TFile,
|
||||
folder: TFolder,
|
||||
plugin: FolderNotesPlugin,
|
||||
): void {
|
||||
markFileAsFolderNote(file, plugin);
|
||||
markFolderWithFolderNoteClasses(folder, plugin);
|
||||
}
|
||||
|
||||
export function clearFolderAndNoteClasses(folder: TFolder, file: TFile, plugin: FolderNotesPlugin) {
|
||||
export function clearFolderAndNoteClasses(
|
||||
folder: TFolder,
|
||||
file: TFile,
|
||||
plugin: FolderNotesPlugin,
|
||||
): void {
|
||||
unmarkFileAsFolderNote(file, plugin);
|
||||
clearFolderNoteClassesFromFolder(folder, plugin);
|
||||
}
|
||||
|
||||
export function markFolderWithFolderNoteClasses(folder: TFolder, plugin: FolderNotesPlugin) {
|
||||
export function markFolderWithFolderNoteClasses(folder: TFolder, plugin: FolderNotesPlugin): void {
|
||||
addCSSClassToFileExplorerEl(folder.path, 'has-folder-note', false, plugin);
|
||||
if (plugin.isEmptyFolderNoteFolder(folder) && getFolderNote(plugin, folder.path)) {
|
||||
addCSSClassToFileExplorerEl(folder.path, 'only-has-folder-note', true, plugin);
|
||||
|
|
@ -93,20 +111,20 @@ export function markFolderWithFolderNoteClasses(folder: TFolder, plugin: FolderN
|
|||
}
|
||||
}
|
||||
|
||||
export function markFileAsFolderNote(file: TFile, plugin: FolderNotesPlugin) {
|
||||
export function markFileAsFolderNote(file: TFile, plugin: FolderNotesPlugin): void {
|
||||
addCSSClassToFileExplorerEl(file.path, 'is-folder-note', false, plugin);
|
||||
}
|
||||
|
||||
export function unmarkFileAsFolderNote(file: TFile, plugin: FolderNotesPlugin) {
|
||||
export function unmarkFileAsFolderNote(file: TFile, plugin: FolderNotesPlugin): void {
|
||||
removeCSSClassFromFileExplorerEL(file.path, 'is-folder-note', false, plugin);
|
||||
}
|
||||
|
||||
export function unmarkFolderAsFolderNote(folder: TFolder, plugin: FolderNotesPlugin) {
|
||||
export function unmarkFolderAsFolderNote(folder: TFolder, plugin: FolderNotesPlugin): void {
|
||||
removeCSSClassFromFileExplorerEL(folder.path, 'has-folder-note', false, plugin);
|
||||
removeCSSClassFromFileExplorerEL(folder.path, 'only-has-folder-note', true, plugin);
|
||||
}
|
||||
|
||||
export function clearFolderNoteClassesFromFolder(folder: TFolder, plugin: FolderNotesPlugin) {
|
||||
export function clearFolderNoteClassesFromFolder(folder: TFolder, plugin: FolderNotesPlugin): void {
|
||||
removeCSSClassFromFileExplorerEL(folder.path, 'has-folder-note', false, plugin);
|
||||
removeCSSClassFromFileExplorerEL(folder.path, 'only-has-folder-note', true, plugin);
|
||||
}
|
||||
|
|
@ -115,11 +133,21 @@ export function clearFolderNoteClassesFromFolder(folder: TFolder, plugin: Folder
|
|||
* @param path Can be a folder or file path
|
||||
* @returns nothing
|
||||
*/
|
||||
export async function addCSSClassToFileExplorerEl(path: string, cssClass: string, parent = false, plugin: FolderNotesPlugin, waitForCreate = false, count = 0) {
|
||||
export async function addCSSClassToFileExplorerEl(
|
||||
path: string,
|
||||
cssClass: string,
|
||||
parent = false,
|
||||
plugin: FolderNotesPlugin,
|
||||
waitForCreate = false,
|
||||
count = 0,
|
||||
): Promise<void> {
|
||||
const fileExplorerItem = getFileExplorerElement(path, plugin);
|
||||
const MAX_RETRIES = 5;
|
||||
const RETRY_DELAY = 500;
|
||||
|
||||
if (!fileExplorerItem) {
|
||||
if (waitForCreate && count < 5) {
|
||||
await new Promise((r) => setTimeout(r, 500));
|
||||
if (waitForCreate && count < MAX_RETRIES) {
|
||||
await new Promise((r) => setTimeout(r, RETRY_DELAY));
|
||||
addCSSClassToFileExplorerEl(path, cssClass, parent, plugin, waitForCreate, count + 1);
|
||||
return;
|
||||
}
|
||||
|
|
@ -143,7 +171,12 @@ export async function addCSSClassToFileExplorerEl(path: string, cssClass: string
|
|||
* @param cssClass The CSS class to remove from the file explorer element
|
||||
* @returns nothing
|
||||
*/
|
||||
export function removeCSSClassFromFileExplorerEL(path: string | undefined, cssClass: string, parent: boolean, plugin: FolderNotesPlugin) {
|
||||
export function removeCSSClassFromFileExplorerEL(
|
||||
path: string | undefined,
|
||||
cssClass: string,
|
||||
parent: boolean,
|
||||
plugin: FolderNotesPlugin,
|
||||
): void {
|
||||
if (!path) return;
|
||||
const fileExplorerItem = getFileExplorerElement(path, plugin);
|
||||
document.querySelectorAll(`[data-path='${CSS.escape(path)}']`).forEach((item) => {
|
||||
|
|
@ -156,20 +189,28 @@ export function removeCSSClassFromFileExplorerEL(path: string | undefined, cssCl
|
|||
parentElement.removeClass(cssClass);
|
||||
}
|
||||
return;
|
||||
} else {
|
||||
fileExplorerItem.removeClass(cssClass);
|
||||
}
|
||||
fileExplorerItem.removeClass(cssClass);
|
||||
|
||||
}
|
||||
|
||||
export function getFileExplorerElement(path: string, plugin: FolderNotesPlugin | FolderOverviewPlugin): HTMLElement | null {
|
||||
export function getFileExplorerElement(
|
||||
path: string,
|
||||
plugin: FolderNotesPlugin | FolderOverviewPlugin,
|
||||
): HTMLElement | null {
|
||||
const fileExplorer = getFileExplorer(plugin);
|
||||
if (!fileExplorer?.view?.fileItems) { return null; }
|
||||
const fileExplorerItem = fileExplorer.view.fileItems?.[path];
|
||||
return fileExplorerItem?.selfEl ?? fileExplorerItem?.titleEl ?? null;
|
||||
}
|
||||
|
||||
export function showFolderNoteInFileExplorer(path: string, plugin: FolderNotesPlugin) {
|
||||
const excludedFolder = new ExcludedFolder(path, plugin.settings.excludeFolders.length, undefined, plugin);
|
||||
export function showFolderNoteInFileExplorer(path: string, plugin: FolderNotesPlugin): void {
|
||||
const excludedFolder = new ExcludedFolder(
|
||||
path,
|
||||
plugin.settings.excludeFolders.length,
|
||||
undefined,
|
||||
plugin,
|
||||
);
|
||||
excludedFolder.subFolders = false;
|
||||
excludedFolder.disableSync = false;
|
||||
excludedFolder.disableAutoCreate = false;
|
||||
|
|
@ -183,7 +224,7 @@ export function showFolderNoteInFileExplorer(path: string, plugin: FolderNotesPl
|
|||
updateCSSClassesForFolder(path, plugin);
|
||||
}
|
||||
|
||||
export function hideFolderNoteInFileExplorer(folderPath: string, plugin: FolderNotesPlugin) {
|
||||
export function hideFolderNoteInFileExplorer(folderPath: string, plugin: FolderNotesPlugin): void {
|
||||
plugin.settings.excludeFolders = plugin.settings.excludeFolders.filter(
|
||||
(folder) => (folder.path !== folderPath) && folder.showFolderNote);
|
||||
plugin.saveSettings(false);
|
||||
|
|
@ -191,7 +232,7 @@ export function hideFolderNoteInFileExplorer(folderPath: string, plugin: FolderN
|
|||
updateCSSClassesForFolder(folderPath, plugin);
|
||||
}
|
||||
|
||||
export function setActiveFolder(folderPath: string, plugin: FolderNotesPlugin) {
|
||||
export function setActiveFolder(folderPath: string, plugin: FolderNotesPlugin): void {
|
||||
const fileExplorerItem = getFileExplorerElement(folderPath, plugin);
|
||||
if (fileExplorerItem) {
|
||||
fileExplorerItem.addClass('fn-is-active');
|
||||
|
|
@ -199,7 +240,7 @@ export function setActiveFolder(folderPath: string, plugin: FolderNotesPlugin) {
|
|||
}
|
||||
}
|
||||
|
||||
export function removeActiveFolder(plugin: FolderNotesPlugin) {
|
||||
export function removeActiveFolder(plugin: FolderNotesPlugin): void {
|
||||
if (plugin.activeFolderDom) {
|
||||
plugin.activeFolderDom.removeClass('fn-is-active');
|
||||
plugin.activeFolderDom?.removeClass('has-focus');
|
||||
|
|
|
|||
|
|
@ -1,20 +1,21 @@
|
|||
import { TFolder, TFile, View } from 'obsidian';
|
||||
import { FileExplorerWorkspaceLeaf, FileExplorerView } from 'src/globals';
|
||||
import type { FileExplorerWorkspaceLeaf, FileExplorerView } from 'src/globals';
|
||||
import { getFolderNote } from './folderNoteFunctions';
|
||||
import FolderNotesPlugin from 'src/main';
|
||||
import { FileExplorerLeaf } from 'obsidian-typings';
|
||||
import FolderOverviewPlugin from 'src/obsidian-folder-overview/src/main';
|
||||
import type FolderNotesPlugin from 'src/main';
|
||||
import type { FileExplorerLeaf, FileTreeItem, TreeNode } from 'obsidian-typings';
|
||||
import type FolderOverviewPlugin from 'src/obsidian-folder-overview/src/main';
|
||||
|
||||
export function getFileNameFromPathString(path: string): string {
|
||||
return path.substring(path.lastIndexOf('/') >= 0 ? path.lastIndexOf('/') + 1 : 0);
|
||||
}
|
||||
|
||||
export function getFolderNameFromPathString(path: string): string {
|
||||
const PARENT_FOLDER_INDEX = -2;
|
||||
const LAST_FOLDER_INDEX = -1;
|
||||
if (path.endsWith('.md') || path.endsWith('.canvas')) {
|
||||
return path.split('/').slice(-2)[0];
|
||||
} else {
|
||||
return path.split('/').slice(-1)[0];
|
||||
return path.split('/').slice(PARENT_FOLDER_INDEX)[0];
|
||||
}
|
||||
return path.split('/').slice(LAST_FOLDER_INDEX)[0];
|
||||
}
|
||||
|
||||
export function removeExtension(name: string): string {
|
||||
|
|
@ -30,26 +31,30 @@ export function getFolderPathFromString(path: string): string {
|
|||
const folderPath = path.substring(0, subString);
|
||||
if (folderPath === '') {
|
||||
return '/';
|
||||
} else {
|
||||
return folderPath;
|
||||
}
|
||||
return folderPath;
|
||||
|
||||
}
|
||||
|
||||
export function getParentFolderPath(path: string): string {
|
||||
return this.getFolderPathFromString(this.getFolderPathFromString(path));
|
||||
}
|
||||
|
||||
export function getFileExplorer(plugin: FolderNotesPlugin | FolderOverviewPlugin) {
|
||||
return plugin.app.workspace.getLeavesOfType('file-explorer')[0] as any as FileExplorerWorkspaceLeaf;
|
||||
export function getFileExplorer(
|
||||
plugin: FolderNotesPlugin | FolderOverviewPlugin,
|
||||
): FileExplorerWorkspaceLeaf {
|
||||
// eslint-disable-next-line max-len
|
||||
const leaf = plugin.app.workspace.getLeavesOfType('file-explorer')[0] as unknown as FileExplorerWorkspaceLeaf;
|
||||
return leaf;
|
||||
}
|
||||
|
||||
export function getFileExplorerView(plugin: FolderNotesPlugin) {
|
||||
export function getFileExplorerView(plugin: FolderNotesPlugin): FileExplorerView {
|
||||
return getFileExplorer(plugin).view;
|
||||
}
|
||||
|
||||
export function getFocusedItem(plugin: FolderNotesPlugin) {
|
||||
const fileExplorer = getFileExplorer(plugin) as any as FileExplorerLeaf;
|
||||
const focusedItem = fileExplorer.view.tree.focusedItem;
|
||||
export function getFocusedItem(plugin: FolderNotesPlugin): TreeNode<FileTreeItem> | null {
|
||||
const fileExplorer = getFileExplorer(plugin) as unknown as FileExplorerLeaf;
|
||||
const { focusedItem } = fileExplorer.view.tree;
|
||||
return focusedItem;
|
||||
}
|
||||
|
||||
|
|
|
|||
4
src/globals.d.ts
vendored
4
src/globals.d.ts
vendored
|
|
@ -1,4 +1,4 @@
|
|||
import { TAbstractFile, TFile, TFolder, View, WorkspaceLeaf } from 'obsidian';
|
||||
import type { TAbstractFile, TFile, TFolder, View, WorkspaceLeaf } from 'obsidian';
|
||||
|
||||
declare module 'obsidian' {
|
||||
interface Setting {
|
||||
|
|
@ -40,7 +40,6 @@ interface FileItem {
|
|||
el: HTMLDivElement;
|
||||
file: TFile;
|
||||
fileExplorer: FileExplorerView;
|
||||
info: any;
|
||||
selfEl: HTMLDivElement;
|
||||
innerEl: HTMLDivElement;
|
||||
}
|
||||
|
|
@ -48,7 +47,6 @@ interface FileItem {
|
|||
interface FolderItem {
|
||||
el: HTMLDivElement;
|
||||
fileExplorer: FileExplorerView;
|
||||
info: any;
|
||||
selfEl: HTMLDivElement;
|
||||
innerEl: HTMLDivElement;
|
||||
file: TFolder;
|
||||
|
|
|
|||
313
src/main.ts
313
src/main.ts
|
|
@ -1,11 +1,23 @@
|
|||
|
||||
import { Plugin, TFile, TFolder, TAbstractFile, MarkdownPostProcessorContext, parseYaml, Notice, Keymap, WorkspaceLeaf, requireApiVersion, Platform, debounce } from 'obsidian';
|
||||
import { DEFAULT_SETTINGS, FolderNotesSettings, SettingsTab } from './settings/SettingsTab';
|
||||
import {
|
||||
type TAbstractFile,
|
||||
type MarkdownPostProcessorContext,
|
||||
type WorkspaceLeaf,
|
||||
Plugin, TFile, TFolder,
|
||||
parseYaml, Notice, Keymap,
|
||||
requireApiVersion, Platform, debounce,
|
||||
} from 'obsidian';
|
||||
import {
|
||||
type FolderNotesSettings, DEFAULT_SETTINGS, SettingsTab,
|
||||
} from './settings/SettingsTab';
|
||||
import { Commands } from './Commands';
|
||||
import { FileExplorerWorkspaceLeaf } from './globals';
|
||||
import { registerFileExplorerObserver, unregisterFileExplorerObserver } from './events/MutationObserver';
|
||||
import type { FileExplorerWorkspaceLeaf } from './globals';
|
||||
import {
|
||||
registerFileExplorerObserver, unregisterFileExplorerObserver,
|
||||
} from './events/MutationObserver';
|
||||
import { handleRename } from './events/handleRename';
|
||||
import { getFolderNote, getFolder, openFolderNote, createFolderNote } from './functions/folderNoteFunctions';
|
||||
import {
|
||||
getFolderNote, getFolder, openFolderNote, createFolderNote,
|
||||
} from './functions/folderNoteFunctions';
|
||||
import { handleCreate } from './events/handleCreate';
|
||||
import { FrontMatterTitlePluginHandler } from './events/FrontMatterTitle';
|
||||
import { FolderOverviewSettings } from './obsidian-folder-overview/src/modals/Settings';
|
||||
|
|
@ -13,10 +25,12 @@ import { FolderOverview } from './obsidian-folder-overview/src/FolderOverview';
|
|||
import { TabManager } from './events/TabManager';
|
||||
import './functions/ListComponent';
|
||||
import { handleDelete } from './events/handleDelete';
|
||||
import { addCSSClassToFileExplorerEl, getFileExplorerElement, removeCSSClassFromFileExplorerEL, refreshAllFolderStyles, setActiveFolder, removeActiveFolder } from './functions/styleFunctions';
|
||||
import {
|
||||
addCSSClassToFileExplorerEl, getFileExplorerElement, removeCSSClassFromFileExplorerEL,
|
||||
refreshAllFolderStyles, setActiveFolder, removeActiveFolder,
|
||||
} from './functions/styleFunctions';
|
||||
import { getExcludedFolder } from './ExcludeFolders/functions/folderFunctions';
|
||||
import { FileExplorerView, InternalPlugin } from 'obsidian-typings';
|
||||
// import { getFocusedItem } from './functions/utils';
|
||||
import type { FileExplorerView, InternalPlugin } from 'obsidian-typings';
|
||||
import { FOLDER_OVERVIEW_VIEW, FolderOverviewView } from './obsidian-folder-overview/src/view';
|
||||
import { registerOverviewCommands } from './obsidian-folder-overview/src/Commands';
|
||||
import { updateOverviewView, updateViewDropdown } from './obsidian-folder-overview/src/main';
|
||||
|
|
@ -24,7 +38,6 @@ import { FvIndexDB } from './obsidian-folder-overview/src/utils/IndexDB';
|
|||
import { updateAllOverviews } from './obsidian-folder-overview/src/utils/functions';
|
||||
|
||||
export default class FolderNotesPlugin extends Plugin {
|
||||
observer: MutationObserver;
|
||||
settings: FolderNotesSettings;
|
||||
settingsTab: SettingsTab;
|
||||
activeFolderDom: HTMLElement | null;
|
||||
|
|
@ -41,7 +54,7 @@ export default class FolderNotesPlugin extends Plugin {
|
|||
private fileExplorerPlugin!: InternalPlugin;
|
||||
private fileExplorerView!: FileExplorerView;
|
||||
|
||||
async onload() {
|
||||
async onload(): Promise<void> {
|
||||
console.log('loading folder notes plugin');
|
||||
await this.loadSettings();
|
||||
this.settingsTab = new SettingsTab(this.app, this);
|
||||
|
|
@ -52,17 +65,29 @@ export default class FolderNotesPlugin extends Plugin {
|
|||
// Add CSS Classes
|
||||
document.body.classList.add('folder-notes-plugin');
|
||||
if (this.settings.hideFolderNote) { document.body.classList.add('hide-folder-note'); }
|
||||
if (this.settings.hideCollapsingIconForEmptyFolders) { document.body.classList.add('fn-hide-empty-collapse-icon'); }
|
||||
if (this.settings.hideCollapsingIconForEmptyFolders) {
|
||||
document.body.classList.add('fn-hide-empty-collapse-icon');
|
||||
}
|
||||
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) { document.body.classList.add('folder-note-cursive-path'); }
|
||||
if (this.settings.underlineFolderInPath) { document.body.classList.add('folder-note-underline-path'); }
|
||||
if (this.settings.stopWhitespaceCollapsing) { document.body.classList.add('fn-whitespace-stop-collapsing'); }
|
||||
if (this.settings.hideCollapsingIcon) { document.body.classList.add('fn-hide-collapse-icon'); }
|
||||
if (!this.settings.highlightFolder) { document.body.classList.add('disable-folder-highlight'); }
|
||||
// document.body.classList.add('fv-hide-link-list');
|
||||
if (this.settings.cursiveNameInPath) {
|
||||
document.body.classList.add('folder-note-cursive-path');
|
||||
}
|
||||
if (this.settings.underlineFolderInPath) {
|
||||
document.body.classList.add('folder-note-underline-path');
|
||||
}
|
||||
if (this.settings.stopWhitespaceCollapsing) {
|
||||
document.body.classList.add('fn-whitespace-stop-collapsing');
|
||||
}
|
||||
if (this.settings.hideCollapsingIcon) {
|
||||
document.body.classList.add('fn-hide-collapse-icon');
|
||||
}
|
||||
if (!this.settings.highlightFolder) {
|
||||
document.body.classList.add('disable-folder-highlight');
|
||||
}
|
||||
|
||||
if (requireApiVersion('1.7.2')) {
|
||||
document.body.classList.add('version-1-7-2');
|
||||
}
|
||||
|
|
@ -72,24 +97,12 @@ export default class FolderNotesPlugin extends Plugin {
|
|||
|
||||
this.app.workspace.onLayoutReady(this.onLayoutReady.bind(this));
|
||||
|
||||
// this.observer.observe(document.body, {
|
||||
// childList: true,
|
||||
// subtree: true,
|
||||
// });
|
||||
|
||||
if (!this.settings.persistentSettingsTab.afterRestart) {
|
||||
this.settings.settingsTab = 'general';
|
||||
}
|
||||
|
||||
this.registerDomEvent(window, 'keydown', (event: KeyboardEvent) => {
|
||||
// Was a bit too buggy
|
||||
// if (event.key === 'Enter') {
|
||||
// const folderNote = getFolderNote(this, getFocusedItem(this)?.file?.path || '');
|
||||
// if (!folderNote) return;
|
||||
// openFolderNote(this, folderNote);
|
||||
// }
|
||||
|
||||
const hoveredElement = this.hoveredElement;
|
||||
const { hoveredElement } = this;
|
||||
if (this.hoverLinkTriggered) return;
|
||||
if (!hoveredElement) return;
|
||||
if (!Keymap.isModEvent(event)) return;
|
||||
|
|
@ -141,12 +154,15 @@ export default class FolderNotesPlugin extends Plugin {
|
|||
this.handleVaultChange();
|
||||
}));
|
||||
|
||||
this.registerMarkdownCodeBlockProcessor('folder-overview', (source: string, el: HTMLElement, ctx: MarkdownPostProcessorContext) => {
|
||||
this.handleOverviewBlock(source, el, ctx);
|
||||
});
|
||||
this.registerMarkdownCodeBlockProcessor(
|
||||
'folder-overview',
|
||||
(source: string, el: HTMLElement, ctx: MarkdownPostProcessorContext) => {
|
||||
this.handleOverviewBlock(source, el, ctx);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
onLayoutReady() {
|
||||
onLayoutReady(): void {
|
||||
if (!this._loaded) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -173,8 +189,9 @@ export default class FolderNotesPlugin extends Plugin {
|
|||
|
||||
const fileExplorerPlugin = this.app.internalPlugins.getEnabledPluginById('file-explorer');
|
||||
if (fileExplorerPlugin) {
|
||||
const originalRevealInFolder = fileExplorerPlugin.revealInFolder.bind(fileExplorerPlugin);
|
||||
fileExplorerPlugin.revealInFolder = (file: TAbstractFile) => {
|
||||
const originalRevealInFolder = fileExplorerPlugin.revealInFolder
|
||||
.bind(fileExplorerPlugin);
|
||||
fileExplorerPlugin.revealInFolder = (file: TAbstractFile): void => {
|
||||
if (file instanceof TFile) {
|
||||
const folder = getFolder(this, file);
|
||||
if (folder instanceof TFolder) {
|
||||
|
|
@ -184,9 +201,10 @@ export default class FolderNotesPlugin extends Plugin {
|
|||
}
|
||||
document.body.classList.remove('hide-folder-note');
|
||||
originalRevealInFolder.call(fileExplorerPlugin, folder);
|
||||
const FOLDER_REVEAL_DELAY = 100;
|
||||
setTimeout(() => {
|
||||
document.body.classList.add('hide-folder-note');
|
||||
}, 100);
|
||||
}, FOLDER_REVEAL_DELAY);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
@ -199,26 +217,29 @@ export default class FolderNotesPlugin extends Plugin {
|
|||
|
||||
if (!view) { return; }
|
||||
|
||||
// @ts-ignore
|
||||
const editMode = view.editMode ?? view.sourceMode ?? this.app.workspace.activeEditor?.editMode;
|
||||
// eslint-disable-next-line
|
||||
// @ts-expect-error use internal API
|
||||
const editMode = view.editMode ?? view.sourceMode
|
||||
// @ts-expect-error use internal API
|
||||
?? this.app.workspace.activeEditor?.editMode;
|
||||
|
||||
const plugin = this;
|
||||
if (!editMode) { return; }
|
||||
|
||||
// @ts-ignore
|
||||
const clipboardProto = editMode.clipboardManager.constructor.prototype;
|
||||
|
||||
const originalHandleDragOver = clipboardProto.handleDragOver;
|
||||
const originalHandleDrop = clipboardProto.handleDrop;
|
||||
|
||||
clipboardProto.handleDragOver = function (evt: DragEvent, ...args: any[]) {
|
||||
const dragManager = this.app.dragManager;
|
||||
clipboardProto.handleDragOver = function (evt: DragEvent, ...args: unknown[]): void {
|
||||
const { dragManager } = this.app;
|
||||
const draggable = dragManager?.draggable;
|
||||
|
||||
if (draggable?.file instanceof TFolder) {
|
||||
const folderNote = getFolderNote(plugin, draggable.file.path);
|
||||
if (folderNote) {
|
||||
dragManager.setAction(window.i18next.t('interface.drag-and-drop.insert-link-here'));
|
||||
dragManager.setAction(
|
||||
window.i18next.t('interface.drag-and-drop.insert-link-here'),
|
||||
);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
@ -226,8 +247,8 @@ export default class FolderNotesPlugin extends Plugin {
|
|||
return originalHandleDragOver.call(this, evt, ...args);
|
||||
};
|
||||
|
||||
clipboardProto.handleDrop = function (evt: DragEvent, ...args: any[]) {
|
||||
const dragManager = this.app.dragManager;
|
||||
clipboardProto.handleDrop = function (evt: DragEvent, ...args: unknown[]): void {
|
||||
const { dragManager } = this.app;
|
||||
const draggable = dragManager?.draggable;
|
||||
|
||||
if (draggable?.file instanceof TFolder) {
|
||||
|
|
@ -246,57 +267,35 @@ export default class FolderNotesPlugin extends Plugin {
|
|||
}
|
||||
}
|
||||
|
||||
handleVaultChange() {
|
||||
handleVaultChange(): void {
|
||||
if (!this.settings.fvGlobalSettings.autoUpdateLinks) return;
|
||||
const DEBOUNCE_DELAY = 2000;
|
||||
debounce(() => {
|
||||
updateAllOverviews(this);
|
||||
}, 2000, true)();
|
||||
}, DEBOUNCE_DELAY, true)();
|
||||
}
|
||||
|
||||
handleFileExplorerClick(evt: MouseEvent) {
|
||||
handleFileExplorerClick(evt: MouseEvent): void {
|
||||
const target = evt.target as HTMLElement;
|
||||
if (evt.shiftKey) return;
|
||||
if (this.isMobileClickDisabled()) return;
|
||||
|
||||
if (Platform.isMobile && this.settings.disableOpenFolderNoteOnClick) return;
|
||||
|
||||
// Check if the click is on a folder
|
||||
const folderTitleEl = target.closest('.nav-folder-title') as HTMLElement;
|
||||
const { folderTitleEl, onlyClickedOnFolderTitle } = this.getFolderTitleInfo(target);
|
||||
if (!folderTitleEl) return;
|
||||
if (this.shouldIgnoreClickByWhitespaceOrCollapse(target, onlyClickedOnFolderTitle)) return;
|
||||
|
||||
const onlyClickedOnFolderTitle = !!target.closest('.nav-folder-title-content');
|
||||
// const folderTitleContentEl = target.closest('.nav-folder-title-content') as HTMLElement;
|
||||
// if (folderTitleContentEl) {
|
||||
// const rect = folderTitleContentEl.getBoundingClientRect();
|
||||
// const clickOffsetX = evt.clientX - rect.left;
|
||||
// // Ignore clicks within the first N pixels, e.g., 20px where the icon is displayed
|
||||
// if (clickOffsetX < 20) return;
|
||||
// }
|
||||
if (!this.settings.stopWhitespaceCollapsing && !onlyClickedOnFolderTitle) return;
|
||||
|
||||
// Ignore clicks on the collapse icon
|
||||
if (target.closest('.collapse-icon')) return;
|
||||
|
||||
const folderPath = folderTitleEl.getAttribute('data-path');
|
||||
const folderPath = this.getValidFolderPath(folderTitleEl);
|
||||
if (!folderPath) return;
|
||||
|
||||
const excludedFolder = getExcludedFolder(this, folderPath, true);
|
||||
if (excludedFolder?.disableFolderNote) return;
|
||||
|
||||
const usedCtrl = Platform.isMacOS ? evt.metaKey : evt.ctrlKey;
|
||||
|
||||
const usedCtrl = this.isCtrlUsed(evt);
|
||||
const folderNote = getFolderNote(this, folderPath);
|
||||
if (!folderNote && (evt.altKey || Keymap.isModEvent(evt) === 'tab')) {
|
||||
if ((this.settings.altKey && evt.altKey) || (usedCtrl && this.settings.ctrlKey)) {
|
||||
createFolderNote(this, folderPath, true, undefined, true);
|
||||
addCSSClassToFileExplorerEl(folderPath, 'has-folder-note', false, this);
|
||||
removeCSSClassFromFileExplorerEL(folderPath, 'has-not-folder-note', false, this);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!folderNote && this.shouldCreateNote(evt, usedCtrl)) {
|
||||
this.createNoteAndMark(folderPath);
|
||||
return;
|
||||
}
|
||||
if (!(folderNote instanceof TFile)) return;
|
||||
|
||||
if (this.settings.openWithCtrl && !usedCtrl) return;
|
||||
if (this.settings.openWithAlt && !evt.altKey) return;
|
||||
if (!this.shouldOpenNote(usedCtrl, evt)) return;
|
||||
|
||||
if (!this.settings.enableCollapsing || usedCtrl) {
|
||||
evt.preventDefault();
|
||||
|
|
@ -306,7 +305,59 @@ export default class FolderNotesPlugin extends Plugin {
|
|||
openFolderNote(this, folderNote, evt);
|
||||
}
|
||||
|
||||
handleOverviewBlock(source: string, el: HTMLElement, ctx: MarkdownPostProcessorContext) {
|
||||
private isMobileClickDisabled(): boolean {
|
||||
return Platform.isMobile && this.settings.disableOpenFolderNoteOnClick;
|
||||
}
|
||||
|
||||
private getFolderTitleInfo(target: HTMLElement): {
|
||||
folderTitleEl: HTMLElement | null;
|
||||
onlyClickedOnFolderTitle: boolean;
|
||||
} {
|
||||
const folderTitleEl = target.closest('.nav-folder-title') as HTMLElement | null;
|
||||
const onlyClickedOnFolderTitle = !!target.closest('.nav-folder-title-content');
|
||||
return { folderTitleEl, onlyClickedOnFolderTitle };
|
||||
}
|
||||
|
||||
private shouldIgnoreClickByWhitespaceOrCollapse(
|
||||
target: HTMLElement,
|
||||
onlyClickedOnFolderTitle: boolean,
|
||||
): boolean {
|
||||
if (!this.settings.stopWhitespaceCollapsing && !onlyClickedOnFolderTitle) return true;
|
||||
if (target.closest('.collapse-icon')) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
private getValidFolderPath(folderTitleEl: HTMLElement): string | null {
|
||||
const folderPath = folderTitleEl.getAttribute('data-path');
|
||||
if (!folderPath) return null;
|
||||
const excludedFolder = getExcludedFolder(this, folderPath, true);
|
||||
if (excludedFolder?.disableFolderNote) return null;
|
||||
return folderPath;
|
||||
}
|
||||
|
||||
private isCtrlUsed(evt: MouseEvent): boolean {
|
||||
return Platform.isMacOS ? evt.metaKey : evt.ctrlKey;
|
||||
}
|
||||
|
||||
private shouldCreateNote(evt: MouseEvent, usedCtrl: boolean): boolean {
|
||||
const isTabMod = Keymap.isModEvent(evt) === 'tab';
|
||||
if (!(evt.altKey || isTabMod)) return false;
|
||||
return (this.settings.altKey && evt.altKey) || (usedCtrl && this.settings.ctrlKey);
|
||||
}
|
||||
|
||||
private createNoteAndMark(folderPath: string): void {
|
||||
createFolderNote(this, folderPath, true, undefined, true);
|
||||
addCSSClassToFileExplorerEl(folderPath, 'has-folder-note', false, this);
|
||||
removeCSSClassFromFileExplorerEL(folderPath, 'has-not-folder-note', false, this);
|
||||
}
|
||||
|
||||
private shouldOpenNote(usedCtrl: boolean, evt: MouseEvent): boolean {
|
||||
if (this.settings.openWithCtrl && !usedCtrl) return false;
|
||||
if (this.settings.openWithAlt && !evt.altKey) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
handleOverviewBlock(source: string, el: HTMLElement, ctx: MarkdownPostProcessorContext): void {
|
||||
const observer = new MutationObserver(() => {
|
||||
const editButton = el.parentElement?.childNodes.item(1);
|
||||
if (editButton) {
|
||||
|
|
@ -314,7 +365,14 @@ export default class FolderNotesPlugin extends Plugin {
|
|||
e.stopImmediatePropagation();
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
new FolderOverviewSettings(this.app, this, parseYaml(source), ctx, el, this.settings.defaultOverview).open();
|
||||
new FolderOverviewSettings(
|
||||
this.app,
|
||||
this,
|
||||
parseYaml(source),
|
||||
ctx,
|
||||
el,
|
||||
this.settings.defaultOverview,
|
||||
).open();
|
||||
}, { capture: true });
|
||||
}
|
||||
});
|
||||
|
|
@ -326,21 +384,35 @@ export default class FolderNotesPlugin extends Plugin {
|
|||
|
||||
try {
|
||||
if (this.app.workspace.layoutReady) {
|
||||
const folderOverview = new FolderOverview(this, ctx, source, el, this.settings.defaultOverview);
|
||||
folderOverview.create(this, parseYaml(source), el, ctx);
|
||||
const { defaultOverview } = this.settings;
|
||||
const folderOverview = new FolderOverview(
|
||||
this,
|
||||
ctx,
|
||||
source,
|
||||
el,
|
||||
defaultOverview,
|
||||
);
|
||||
folderOverview.create(this, el, ctx);
|
||||
} else {
|
||||
this.app.workspace.onLayoutReady(() => {
|
||||
const folderOverview = new FolderOverview(this, ctx, source, el, this.settings.defaultOverview);
|
||||
folderOverview.create(this, parseYaml(source), el, ctx);
|
||||
const folderOverview = new FolderOverview(
|
||||
this,
|
||||
ctx,
|
||||
source,
|
||||
el,
|
||||
this.settings.defaultOverview,
|
||||
);
|
||||
folderOverview.create(this, el, ctx);
|
||||
});
|
||||
}
|
||||
} catch (e) {
|
||||
// eslint-disable-next-line max-len
|
||||
new Notice('Error creating folder overview (folder notes plugin) - check console for more details');
|
||||
console.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
async activateOverviewView() {
|
||||
async activateOverviewView(): Promise<void> {
|
||||
const { workspace } = this.app;
|
||||
|
||||
let leaf: WorkspaceLeaf | null = null;
|
||||
|
|
@ -357,13 +429,14 @@ export default class FolderNotesPlugin extends Plugin {
|
|||
workspace.revealLeaf(leaf);
|
||||
}
|
||||
|
||||
updateOverviewView = updateOverviewView;
|
||||
updateViewDropdown = updateViewDropdown;
|
||||
updateOverviewView: typeof updateOverviewView = updateOverviewView;
|
||||
updateViewDropdown: typeof updateViewDropdown = updateViewDropdown;
|
||||
|
||||
isEmptyFolderNoteFolder(folder: TFolder): boolean {
|
||||
const attachmentFolderPath = this.app.vault.getConfig('attachmentFolderPath') as string;
|
||||
const cleanAttachmentFolderPath = attachmentFolderPath?.replace('./', '') || '';
|
||||
const attachmentsAreInRootFolder = attachmentFolderPath === './' || attachmentFolderPath === '';
|
||||
const attachmentsAreInRootFolder = attachmentFolderPath === './'
|
||||
|| attachmentFolderPath === '';
|
||||
const threshold = this.settings.storageLocation === 'insideFolder' ? 1 : 0;
|
||||
if (folder.children.length === 0) {
|
||||
addCSSClassToFileExplorerEl(folder.path, 'fn-empty-folder', false, this);
|
||||
|
|
@ -374,29 +447,39 @@ export default class FolderNotesPlugin extends Plugin {
|
|||
} else if (folder.children.length > threshold) {
|
||||
if (attachmentsAreInRootFolder) {
|
||||
return false;
|
||||
} else if (this.settings.ignoreAttachmentFolder && this.app.vault.getAbstractFileByPath(`${folder.path}/${cleanAttachmentFolderPath}`)) {
|
||||
} else if (this.settings.ignoreAttachmentFolder
|
||||
&& this.app.vault.getAbstractFileByPath(
|
||||
`${folder.path}/${cleanAttachmentFolderPath}`)) {
|
||||
const folderPath = `${folder.path}/${cleanAttachmentFolderPath}`;
|
||||
const attachmentFolder = this.app.vault.getAbstractFileByPath(folderPath);
|
||||
if (attachmentFolder instanceof TFolder && folder.children.length <= threshold + 1) {
|
||||
if (attachmentFolder instanceof TFolder
|
||||
&& folder.children.length <= threshold + 1) {
|
||||
if (!folder.collapsed) {
|
||||
getFileExplorerElement(folder.path, this)?.click();
|
||||
}
|
||||
}
|
||||
return folder.children.length <= threshold + 1;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
async changeFolderNameInExplorer(folder: TFolder, newName: string | null | undefined, waitForCreate = false, count = 0) {
|
||||
async changeFolderNameInExplorer(
|
||||
folder: TFolder,
|
||||
newName: string | null | undefined,
|
||||
waitForCreate = false,
|
||||
count = 0,
|
||||
): Promise<void> {
|
||||
const MAX_RETRY_COUNT = 5;
|
||||
const RETRY_DELAY_MS = 500;
|
||||
if (!newName) newName = folder.name;
|
||||
let fileExplorerItem = getFileExplorerElement(folder.path, this);
|
||||
if (!fileExplorerItem) {
|
||||
if (waitForCreate && count < 5) {
|
||||
await new Promise((r) => setTimeout(r, 500));
|
||||
this.changeFolderNameInExplorer(folder, newName, waitForCreate, count + 1);
|
||||
if (waitForCreate && count < MAX_RETRY_COUNT) {
|
||||
await new Promise<void>((resolve) => setTimeout(resolve, RETRY_DELAY_MS));
|
||||
void this.changeFolderNameInExplorer(folder, newName, waitForCreate, count + 1);
|
||||
return;
|
||||
}
|
||||
return;
|
||||
|
|
@ -405,15 +488,19 @@ export default class FolderNotesPlugin extends Plugin {
|
|||
fileExplorerItem = fileExplorerItem?.querySelector('div.nav-folder-title-content');
|
||||
if (!fileExplorerItem) { return; }
|
||||
if (this.settings.frontMatterTitle.explorer && this.settings.frontMatterTitle.enabled) {
|
||||
fileExplorerItem.innerText = newName;
|
||||
fileExplorerItem.setAttribute('old-name', folder.name);
|
||||
(fileExplorerItem as HTMLElement).innerText = newName;
|
||||
(fileExplorerItem as HTMLElement).setAttribute('old-name', folder.name);
|
||||
} else {
|
||||
fileExplorerItem.innerText = folder.name;
|
||||
fileExplorerItem.removeAttribute('old-name');
|
||||
(fileExplorerItem as HTMLElement).innerText = folder.name;
|
||||
(fileExplorerItem as HTMLElement).removeAttribute('old-name');
|
||||
}
|
||||
}
|
||||
|
||||
async changeFolderNameInPath(folder: TFolder, newName: string | null | undefined, breadcrumb: HTMLElement) {
|
||||
async changeFolderNameInPath(
|
||||
folder: TFolder,
|
||||
newName: string | null | undefined,
|
||||
breadcrumb: HTMLElement,
|
||||
): Promise<void> {
|
||||
if (!newName) newName = folder.name;
|
||||
|
||||
breadcrumb.textContent = folder.newName || folder.name;
|
||||
|
|
@ -424,7 +511,7 @@ export default class FolderNotesPlugin extends Plugin {
|
|||
/**
|
||||
* Updates all folder names in the path above the note editor
|
||||
*/
|
||||
updateAllBreadcrumbs(remove?: boolean) {
|
||||
updateAllBreadcrumbs(remove?: boolean): void {
|
||||
if (!this.settings.frontMatterTitle.path && !remove) { return; }
|
||||
const viewHeaderItems = document.querySelectorAll('span.view-header-breadcrumb');
|
||||
const files = this.app.vault.getAllLoadedFiles().filter((file) => file instanceof TFolder);
|
||||
|
|
@ -444,7 +531,7 @@ export default class FolderNotesPlugin extends Plugin {
|
|||
});
|
||||
}
|
||||
|
||||
onunload() {
|
||||
onunload(): void {
|
||||
unregisterFileExplorerObserver();
|
||||
document.body.classList.remove('folder-notes-plugin');
|
||||
document.body.classList.remove('folder-note-underline');
|
||||
|
|
@ -456,7 +543,7 @@ export default class FolderNotesPlugin extends Plugin {
|
|||
}
|
||||
}
|
||||
|
||||
async loadSettings() {
|
||||
async loadSettings(): Promise<void> {
|
||||
const data = await this.loadData();
|
||||
if (data) {
|
||||
if (data.allowWhitespaceCollapsing === true) {
|
||||
|
|
@ -474,12 +561,14 @@ export default class FolderNotesPlugin extends Plugin {
|
|||
}
|
||||
|
||||
if (!data) { return; }
|
||||
const overview = (data as any).defaultOverview;
|
||||
const overview = data.defaultOverview;
|
||||
if (!overview) { return; }
|
||||
this.settings.defaultOverview = Object.assign({}, DEFAULT_SETTINGS.defaultOverview, overview);
|
||||
this.settings.defaultOverview = Object.assign(
|
||||
{}, DEFAULT_SETTINGS.defaultOverview, overview,
|
||||
);
|
||||
}
|
||||
|
||||
async saveSettings(reloadStyles?: boolean) {
|
||||
async saveSettings(reloadStyles?: boolean): Promise<void> {
|
||||
await this.saveData(this.settings);
|
||||
// cleanup any css if we need too
|
||||
if ((!this.settingsOpened || reloadStyles === true) && reloadStyles !== false) {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { App, Modal, Setting, Notice, SettingTab } from 'obsidian';
|
||||
import FolderNotesPlugin from '../main';
|
||||
import { ListComponent } from 'src/functions/ListComponent';
|
||||
import { Modal, Setting, Notice, type App, type SettingTab } from 'obsidian';
|
||||
import type FolderNotesPlugin from '../main';
|
||||
import type { ListComponent } from 'src/functions/ListComponent';
|
||||
|
||||
export default class AddSupportedFileModal extends Modal {
|
||||
plugin: FolderNotesPlugin;
|
||||
|
|
@ -16,7 +16,8 @@ export default class AddSupportedFileModal extends Modal {
|
|||
this.list = list;
|
||||
this.settingsTab = settingsTab;
|
||||
}
|
||||
onOpen() {
|
||||
|
||||
onOpen(): void {
|
||||
const { contentEl } = this;
|
||||
// close when user presses enter
|
||||
contentEl.addEventListener('keydown', (e) => {
|
||||
|
|
@ -34,10 +35,10 @@ export default class AddSupportedFileModal extends Modal {
|
|||
if (value.trim() !== '') {
|
||||
this.name = value.trim();
|
||||
}
|
||||
})
|
||||
}),
|
||||
);
|
||||
}
|
||||
async onClose() {
|
||||
async onClose(): Promise<void> {
|
||||
if (this.name.toLocaleLowerCase() === 'markdown') {
|
||||
this.name = 'md';
|
||||
}
|
||||
|
|
@ -46,9 +47,9 @@ export default class AddSupportedFileModal extends Modal {
|
|||
contentEl.empty();
|
||||
this.settingsTab.display();
|
||||
} else if (this.plugin.settings.supportedFileTypes.includes(this.name.toLowerCase())) {
|
||||
return new Notice('This extension is already supported');
|
||||
new Notice('This extension is already supported');
|
||||
return;
|
||||
} else {
|
||||
// @ts-ignore
|
||||
await this.list.addValue(this.name.toLowerCase());
|
||||
this.settingsTab.display();
|
||||
this.plugin.saveSettings();
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { FuzzySuggestModal, TFile } from 'obsidian';
|
||||
import FolderNotesPlugin from 'src/main';
|
||||
import { FuzzySuggestModal, type TFile } from 'obsidian';
|
||||
import type FolderNotesPlugin from 'src/main';
|
||||
import { createFolderNote } from 'src/functions/folderNoteFunctions';
|
||||
export class AskForExtensionModal extends FuzzySuggestModal<string> {
|
||||
plugin: FolderNotesPlugin;
|
||||
|
|
@ -8,7 +8,14 @@ export class AskForExtensionModal extends FuzzySuggestModal<string> {
|
|||
openFile: boolean;
|
||||
useModal: boolean | undefined;
|
||||
existingNote: TFile | undefined;
|
||||
constructor(plugin: FolderNotesPlugin, folderPath: string, openFile: boolean, extension: string, useModal?: boolean, existingNote?: TFile) {
|
||||
constructor(
|
||||
plugin: FolderNotesPlugin,
|
||||
folderPath: string,
|
||||
openFile: boolean,
|
||||
extension: string,
|
||||
useModal?: boolean,
|
||||
existingNote?: TFile,
|
||||
) {
|
||||
super(plugin.app);
|
||||
this.plugin = plugin;
|
||||
this.folderPath = folderPath;
|
||||
|
|
@ -20,17 +27,26 @@ export class AskForExtensionModal extends FuzzySuggestModal<string> {
|
|||
}
|
||||
|
||||
getItems(): string[] {
|
||||
return this.plugin.settings.supportedFileTypes.filter((item) => item.toLowerCase() !== '.ask');
|
||||
return this.plugin.settings.supportedFileTypes.filter(
|
||||
(item) => item.toLowerCase() !== '.ask',
|
||||
);
|
||||
}
|
||||
|
||||
getItemText(item: string): string {
|
||||
return item;
|
||||
}
|
||||
|
||||
onChooseItem(item: string, evt: MouseEvent | KeyboardEvent) {
|
||||
onChooseItem(item: string, _evt: MouseEvent | KeyboardEvent): void {
|
||||
this.plugin.askModalCurrentlyOpen = false;
|
||||
this.extension = '.' + item;
|
||||
createFolderNote(this.plugin, this.folderPath, this.openFile, this.extension, this.useModal, this.existingNote);
|
||||
createFolderNote(
|
||||
this.plugin,
|
||||
this.folderPath,
|
||||
this.openFile,
|
||||
this.extension,
|
||||
this.useModal,
|
||||
this.existingNote,
|
||||
);
|
||||
this.close();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { App, Modal, TFile, Platform } from 'obsidian';
|
||||
import FolderNotesPlugin from '../main';
|
||||
import { Modal, Platform, type App, type TFile } from 'obsidian';
|
||||
import type FolderNotesPlugin from '../main';
|
||||
import { deleteFolderNote } from 'src/functions/folderNoteFunctions';
|
||||
export default class DeleteConfirmationModal extends Modal {
|
||||
plugin: FolderNotesPlugin;
|
||||
|
|
@ -11,21 +11,25 @@ export default class DeleteConfirmationModal extends Modal {
|
|||
this.app = app;
|
||||
this.file = file;
|
||||
}
|
||||
onOpen() {
|
||||
onOpen(): void {
|
||||
const { contentEl, plugin } = this;
|
||||
const modalTitle = contentEl.createDiv({ cls: 'fn-modal-title' });
|
||||
const modalContent = contentEl.createDiv({ cls: 'fn-modal-content' });
|
||||
modalTitle.createEl('h2', { text: 'Delete folder note' });
|
||||
// eslint-disable-next-line max-len
|
||||
modalContent.createEl('p', { text: `Are you sure you want to delete the folder note '${this.file.name}' ?` });
|
||||
switch (plugin.settings.deleteFilesAction) {
|
||||
case 'trash':
|
||||
modalContent.createEl('p', { text: 'It will be moved to your system trash.' });
|
||||
break;
|
||||
case 'obsidianTrash':
|
||||
// eslint-disable-next-line max-len
|
||||
modalContent.createEl('p', { text: 'It will be moved to your Obsidian trash, which is located in the ".trash" hidden folder in your vault.' });
|
||||
break;
|
||||
case 'delete':
|
||||
modalContent.createEl('p', { text: 'It will be permanently deleted.' }).setCssStyles({ color: 'red' });
|
||||
modalContent
|
||||
.createEl('p', { text: 'It will be permanently deleted.' })
|
||||
.setCssStyles({ color: 'red' });
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -46,7 +50,10 @@ export default class DeleteConfirmationModal extends Modal {
|
|||
plugin.saveSettings();
|
||||
});
|
||||
} else {
|
||||
const confirmButton = buttonContainer.createEl('button', { text: 'Delete and don\'t ask again', cls: 'mod-destructive' });
|
||||
const confirmButton = buttonContainer.createEl('button', {
|
||||
text: 'Delete and don\'t ask again',
|
||||
cls: 'mod-destructive',
|
||||
});
|
||||
confirmButton.addEventListener('click', async () => {
|
||||
plugin.settings.showDeleteConfirmation = false;
|
||||
plugin.saveSettings();
|
||||
|
|
@ -55,19 +62,25 @@ export default class DeleteConfirmationModal extends Modal {
|
|||
});
|
||||
}
|
||||
|
||||
const deleteButton = buttonContainer.createEl('button', { text: 'Delete', cls: 'mod-warning' });
|
||||
const deleteButton = buttonContainer.createEl('button', {
|
||||
text: 'Delete',
|
||||
cls: 'mod-warning',
|
||||
});
|
||||
deleteButton.addEventListener('click', async () => {
|
||||
this.close();
|
||||
deleteFolderNote(plugin, this.file, false);
|
||||
});
|
||||
deleteButton.focus();
|
||||
|
||||
const cancelButton = buttonContainer.createEl('button', { text: 'Cancel', cls: 'mod-cancel' });
|
||||
const cancelButton = buttonContainer.createEl('button', {
|
||||
text: 'Cancel',
|
||||
cls: 'mod-cancel',
|
||||
});
|
||||
cancelButton.addEventListener('click', async () => {
|
||||
this.close();
|
||||
});
|
||||
}
|
||||
onClose() {
|
||||
onClose(): void {
|
||||
const { contentEl } = this;
|
||||
contentEl.empty();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,13 @@
|
|||
import { App, Modal, Setting, TFile, Platform, TFolder, TAbstractFile } from 'obsidian';
|
||||
import FolderNotesPlugin from '../main';
|
||||
import {
|
||||
Modal,
|
||||
Setting,
|
||||
Platform,
|
||||
type App,
|
||||
type TFile,
|
||||
type TFolder,
|
||||
type TAbstractFile,
|
||||
} from 'obsidian';
|
||||
import type FolderNotesPlugin from '../main';
|
||||
import { turnIntoFolderNote } from 'src/functions/folderNoteFunctions';
|
||||
export default class ExistingFolderNoteModal extends Modal {
|
||||
plugin: FolderNotesPlugin;
|
||||
|
|
@ -7,7 +15,13 @@ export default class ExistingFolderNoteModal extends Modal {
|
|||
file: TFile;
|
||||
folder: TFolder;
|
||||
folderNote: TAbstractFile;
|
||||
constructor(app: App, plugin: FolderNotesPlugin, file: TFile, folder: TFolder, folderNote: TAbstractFile) {
|
||||
constructor(
|
||||
app: App,
|
||||
plugin: FolderNotesPlugin,
|
||||
file: TFile,
|
||||
folder: TFolder,
|
||||
folderNote: TAbstractFile,
|
||||
) {
|
||||
super(app);
|
||||
this.plugin = plugin;
|
||||
this.app = app;
|
||||
|
|
@ -15,18 +29,22 @@ export default class ExistingFolderNoteModal extends Modal {
|
|||
this.folder = folder;
|
||||
this.folderNote = folderNote;
|
||||
}
|
||||
onOpen() {
|
||||
onOpen(): void {
|
||||
const { contentEl } = this;
|
||||
contentEl.createEl('h2', { text: 'A folder note for this folder already exists' });
|
||||
const setting = new Setting(contentEl);
|
||||
// eslint-disable-next-line max-len
|
||||
setting.infoEl.createEl('p', { text: 'Are you sure you want to turn the note into a folder note and rename the existing folder note?' });
|
||||
|
||||
setting.infoEl.parentElement?.classList.add('fn-delete-confirmation-modal');
|
||||
|
||||
// Create a container for the buttons and the checkbox
|
||||
// eslint-disable-next-line max-len
|
||||
const buttonContainer = setting.infoEl.createEl('div', { cls: 'fn-delete-confirmation-modal-buttons' });
|
||||
if (Platform.isMobileApp) {
|
||||
const confirmButton = buttonContainer.createEl('button', { text: 'Rename and don\'t ask again' });
|
||||
const confirmButton = buttonContainer.createEl('button', {
|
||||
text: 'Rename and don\'t ask again',
|
||||
});
|
||||
confirmButton.classList.add('mod-warning', 'fn-confirmation-modal-button');
|
||||
confirmButton.addEventListener('click', async () => {
|
||||
this.plugin.settings.showRenameConfirmation = false;
|
||||
|
|
@ -63,7 +81,7 @@ export default class ExistingFolderNoteModal extends Modal {
|
|||
});
|
||||
|
||||
}
|
||||
onClose() {
|
||||
onClose(): void {
|
||||
const { contentEl } = this;
|
||||
contentEl.empty();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { App, Modal, Setting, TFolder } from 'obsidian';
|
||||
import FolderNotesPlugin from '../main';
|
||||
import { Modal, Setting, type App, type TFolder } from 'obsidian';
|
||||
import type FolderNotesPlugin from '../main';
|
||||
export default class FolderNameModal extends Modal {
|
||||
plugin: FolderNotesPlugin;
|
||||
app: App;
|
||||
|
|
@ -10,7 +10,8 @@ export default class FolderNameModal extends Modal {
|
|||
this.app = app;
|
||||
this.folder = folder;
|
||||
}
|
||||
onOpen() {
|
||||
|
||||
onOpen(): void {
|
||||
const { contentEl } = this;
|
||||
// close when user presses enter
|
||||
contentEl.addEventListener('keydown', (e) => {
|
||||
|
|
@ -26,14 +27,25 @@ export default class FolderNameModal extends Modal {
|
|||
.setValue(this.folder.name.replace(this.plugin.settings.folderNoteType, ''))
|
||||
.onChange(async (value) => {
|
||||
if (value.trim() !== '') {
|
||||
if (!this.app.vault.getAbstractFileByPath(this.folder.path.slice(0, this.folder.path.lastIndexOf('/') + 1) + value.trim())) {
|
||||
this.plugin.app.fileManager.renameFile(this.folder, this.folder.path.slice(0, this.folder.path.lastIndexOf('/') + 1) + value.trim());
|
||||
const parentPath = this.folder.path.slice(
|
||||
0,
|
||||
this.folder.path.lastIndexOf('/') + 1,
|
||||
);
|
||||
const newFolderPath = parentPath + value.trim();
|
||||
if (
|
||||
!this.app.vault.getAbstractFileByPath(newFolderPath)
|
||||
) {
|
||||
this.plugin.app.fileManager.renameFile(
|
||||
this.folder,
|
||||
newFolderPath,
|
||||
);
|
||||
}
|
||||
}
|
||||
})
|
||||
}),
|
||||
);
|
||||
}
|
||||
onClose() {
|
||||
|
||||
onClose(): void {
|
||||
const { contentEl } = this;
|
||||
contentEl.empty();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { App, Modal, TFolder } from 'obsidian';
|
||||
import FolderNotesPlugin from '../main';
|
||||
import { Modal, type App, type TFolder } from 'obsidian';
|
||||
import type FolderNotesPlugin from '../main';
|
||||
export default class NewFolderNameModal extends Modal {
|
||||
plugin: FolderNotesPlugin;
|
||||
app: App;
|
||||
|
|
@ -10,7 +10,8 @@ export default class NewFolderNameModal extends Modal {
|
|||
this.app = app;
|
||||
this.folder = folder;
|
||||
}
|
||||
onOpen() {
|
||||
|
||||
onOpen(): void {
|
||||
const { contentEl } = this;
|
||||
|
||||
contentEl.addEventListener('keydown', (e) => {
|
||||
|
|
@ -36,7 +37,7 @@ export default class NewFolderNameModal extends Modal {
|
|||
},
|
||||
});
|
||||
|
||||
textarea.addEventListener('focus', function() {
|
||||
textarea.addEventListener('focus', function () {
|
||||
this.select();
|
||||
});
|
||||
|
||||
|
|
@ -49,23 +50,32 @@ export default class NewFolderNameModal extends Modal {
|
|||
this.close();
|
||||
});
|
||||
|
||||
const cancelButton = buttonContainer.createEl('button', { text: 'Cancel', cls: 'mod-cancel' });
|
||||
const cancelButton = buttonContainer.createEl('button', {
|
||||
text: 'Cancel',
|
||||
cls: 'mod-cancel',
|
||||
});
|
||||
cancelButton.addEventListener('click', () => {
|
||||
this.close();
|
||||
});
|
||||
}
|
||||
onClose() {
|
||||
|
||||
onClose(): void {
|
||||
const { contentEl } = this;
|
||||
contentEl.empty();
|
||||
}
|
||||
|
||||
saveFolderName() {
|
||||
saveFolderName(): void {
|
||||
const textarea = this.contentEl.querySelector('textarea');
|
||||
if (textarea) {
|
||||
const newName = textarea.value.trim();
|
||||
if (newName.trim() !== '') {
|
||||
if (!this.app.vault.getAbstractFileByPath(this.folder.path.slice(0, this.folder.path.lastIndexOf('/') + 1) + newName.trim())) {
|
||||
this.plugin.app.fileManager.renameFile(this.folder, this.folder.path.slice(0, this.folder.path.lastIndexOf('/') + 1) + newName.trim());
|
||||
const folderBasePath = this.folder.path.slice(
|
||||
0,
|
||||
this.folder.path.lastIndexOf('/') + 1,
|
||||
);
|
||||
const newFolderPath = folderBasePath + newName.trim();
|
||||
if (!this.app.vault.getAbstractFileByPath(newFolderPath)) {
|
||||
this.plugin.app.fileManager.renameFile(this.folder, newFolderPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
Subproject commit f1d24952999f23e2912c7e6c2da4bd53325d2402
|
||||
Subproject commit 37008ed555811b06e5e9c3547079368e0cce8113
|
||||
|
|
@ -1,14 +1,17 @@
|
|||
import { addExcludeFolderListItem, addExcludedFolder } from 'src/ExcludeFolders/functions/folderFunctions';
|
||||
import {
|
||||
addExcludeFolderListItem,
|
||||
addExcludedFolder,
|
||||
} from 'src/ExcludeFolders/functions/folderFunctions';
|
||||
import { ExcludedFolder } from 'src/ExcludeFolders/ExcludeFolder';
|
||||
import { addExcludePatternListItem } from 'src/ExcludeFolders/functions/patternFunctions';
|
||||
import { Setting } from 'obsidian';
|
||||
import { SettingsTab } from './SettingsTab';
|
||||
import type { SettingsTab } from './SettingsTab';
|
||||
import ExcludedFolderSettings from 'src/ExcludeFolders/modals/ExcludeFolderSettings';
|
||||
import PatternSettings from 'src/ExcludeFolders/modals/PatternSettings';
|
||||
import WhitelistedFoldersSettings from 'src/ExcludeFolders/modals/WhitelistedFoldersSettings';
|
||||
// import ExcludedFoldersWhitelist from 'src/ExcludeFolders/modals/WhitelistModal';
|
||||
|
||||
export async function renderExcludeFolders(settingsTab: SettingsTab) {
|
||||
export async function renderExcludeFolders(settingsTab: SettingsTab): Promise<void> {
|
||||
const containerEl = settingsTab.settingsPage;
|
||||
const manageExcluded = new Setting(containerEl)
|
||||
.setHeading()
|
||||
|
|
@ -25,9 +28,12 @@ export async function renderExcludeFolders(settingsTab: SettingsTab) {
|
|||
'Use * after the folder name to exclude folders that start with the folder name.',
|
||||
);
|
||||
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.createEl('br');
|
||||
// eslint-disable-next-line max-len
|
||||
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';
|
||||
|
||||
|
||||
|
|
@ -48,7 +54,11 @@ export async function renderExcludeFolders(settingsTab: SettingsTab) {
|
|||
cb.setButtonText('Manage');
|
||||
cb.setCta();
|
||||
cb.onClick(async () => {
|
||||
new ExcludedFolderSettings(settingsTab.app, settingsTab.plugin, settingsTab.plugin.settings.excludeFolderDefaultSettings).open();
|
||||
new ExcludedFolderSettings(
|
||||
settingsTab.app,
|
||||
settingsTab.plugin,
|
||||
settingsTab.plugin.settings.excludeFolderDefaultSettings,
|
||||
).open();
|
||||
});
|
||||
});
|
||||
|
||||
|
|
@ -58,7 +68,11 @@ export async function renderExcludeFolders(settingsTab: SettingsTab) {
|
|||
cb.setButtonText('Manage');
|
||||
cb.setCta();
|
||||
cb.onClick(async () => {
|
||||
new PatternSettings(settingsTab.app, settingsTab.plugin, settingsTab.plugin.settings.excludePatternDefaultSettings).open();
|
||||
new PatternSettings(
|
||||
settingsTab.app,
|
||||
settingsTab.plugin,
|
||||
settingsTab.plugin.settings.excludePatternDefaultSettings,
|
||||
).open();
|
||||
});
|
||||
});
|
||||
|
||||
|
|
@ -71,18 +85,29 @@ export async function renderExcludeFolders(settingsTab: SettingsTab) {
|
|||
cb.setClass('add-exclude-folder');
|
||||
cb.setTooltip('Add excluded folder');
|
||||
cb.onClick(() => {
|
||||
const excludedFolder = new ExcludedFolder('', settingsTab.plugin.settings.excludeFolders.length, undefined, settingsTab.plugin);
|
||||
const excludedFolder = new ExcludedFolder(
|
||||
'',
|
||||
settingsTab.plugin.settings.excludeFolders.length,
|
||||
undefined,
|
||||
settingsTab.plugin,
|
||||
);
|
||||
addExcludeFolderListItem(settingsTab, containerEl, excludedFolder);
|
||||
addExcludedFolder(settingsTab.plugin, excludedFolder);
|
||||
settingsTab.display();
|
||||
});
|
||||
});
|
||||
|
||||
settingsTab.plugin.settings.excludeFolders.filter((folder) => !folder.hideInSettings).sort((a, b) => a.position - b.position).forEach((excludedFolder) => {
|
||||
if (excludedFolder.string?.trim() !== '' && excludedFolder.path?.trim() === '') {
|
||||
addExcludePatternListItem(settingsTab, containerEl, excludedFolder);
|
||||
} else {
|
||||
addExcludeFolderListItem(settingsTab, containerEl, excludedFolder);
|
||||
}
|
||||
});
|
||||
settingsTab.plugin.settings.excludeFolders
|
||||
.filter((folder) => !folder.hideInSettings)
|
||||
.sort((a, b) => a.position - b.position)
|
||||
.forEach((excludedFolder) => {
|
||||
if (
|
||||
excludedFolder.string?.trim() !== '' &&
|
||||
excludedFolder.path?.trim() === ''
|
||||
) {
|
||||
addExcludePatternListItem(settingsTab, containerEl, excludedFolder);
|
||||
} else {
|
||||
addExcludeFolderListItem(settingsTab, containerEl, excludedFolder);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
/* eslint-disable max-len */
|
||||
import { Setting } from 'obsidian';
|
||||
import { SettingsTab } from './SettingsTab';
|
||||
export async function renderFileExplorer(settingsTab: SettingsTab) {
|
||||
import type { SettingsTab } from './SettingsTab';
|
||||
export async function renderFileExplorer(settingsTab: SettingsTab): Promise<void> {
|
||||
const containerEl = settingsTab.settingsPage;
|
||||
|
||||
new Setting(containerEl)
|
||||
|
|
@ -18,7 +19,7 @@ export async function renderFileExplorer(settingsTab: SettingsTab) {
|
|||
document.body.classList.remove('hide-folder-note');
|
||||
}
|
||||
settingsTab.display();
|
||||
})
|
||||
}),
|
||||
);
|
||||
|
||||
const setting2 = new Setting(containerEl)
|
||||
|
|
@ -30,11 +31,12 @@ export async function renderFileExplorer(settingsTab: SettingsTab) {
|
|||
.onChange(async (value) => {
|
||||
settingsTab.plugin.settings.disableOpenFolderNoteOnClick = value;
|
||||
await settingsTab.plugin.saveSettings();
|
||||
})
|
||||
}),
|
||||
);
|
||||
|
||||
setting2.infoEl.appendText('Requires a restart to take effect');
|
||||
setting2.infoEl.style.color = settingsTab.app.vault.getConfig('accentColor') as string || '#7d5bed';
|
||||
const setting2AccentColor = settingsTab.app.vault.getConfig('accentColor') as string || '#7d5bed';
|
||||
setting2.infoEl.style.color = setting2AccentColor;
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName('Open folder notes by only clicking directly on the folder name')
|
||||
|
|
@ -50,7 +52,7 @@ export async function renderFileExplorer(settingsTab: SettingsTab) {
|
|||
}
|
||||
settingsTab.plugin.settings.stopWhitespaceCollapsing = !value;
|
||||
await settingsTab.plugin.saveSettings();
|
||||
})
|
||||
}),
|
||||
);
|
||||
|
||||
const disableSetting = new Setting(containerEl);
|
||||
|
|
@ -62,10 +64,11 @@ export async function renderFileExplorer(settingsTab: SettingsTab) {
|
|||
.onChange(async (value) => {
|
||||
settingsTab.plugin.settings.enableCollapsing = !value;
|
||||
await settingsTab.plugin.saveSettings();
|
||||
})
|
||||
}),
|
||||
);
|
||||
disableSetting.infoEl.appendText('Requires a restart to take effect');
|
||||
disableSetting.infoEl.style.color = settingsTab.app.vault.getConfig('accentColor') as string || '#7d5bed';
|
||||
const accentColor = settingsTab.app.vault.getConfig('accentColor') as string || '#7d5bed';
|
||||
disableSetting.infoEl.style.color = accentColor;
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName('Use submenus')
|
||||
|
|
@ -77,7 +80,7 @@ export async function renderFileExplorer(settingsTab: SettingsTab) {
|
|||
settingsTab.plugin.settings.useSubmenus = value;
|
||||
await settingsTab.plugin.saveSettings();
|
||||
settingsTab.display();
|
||||
})
|
||||
}),
|
||||
);
|
||||
|
||||
if (settingsTab.plugin.settings.frontMatterTitle.enabled) {
|
||||
|
|
@ -91,9 +94,17 @@ export async function renderFileExplorer(settingsTab: SettingsTab) {
|
|||
settingsTab.plugin.settings.frontMatterTitle.explorer = value;
|
||||
await settingsTab.plugin.saveSettings();
|
||||
settingsTab.plugin.app.vault.getFiles().forEach((file) => {
|
||||
settingsTab.plugin.fmtpHandler?.fmptUpdateFileName({ id: '', result: false, path: file.path, pathOnly: false }, false);
|
||||
settingsTab.plugin.fmtpHandler?.fmptUpdateFileName(
|
||||
{
|
||||
id: '',
|
||||
result: false,
|
||||
path: file.path,
|
||||
pathOnly: false,
|
||||
},
|
||||
false,
|
||||
);
|
||||
});
|
||||
})
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -113,7 +124,7 @@ export async function renderFileExplorer(settingsTab: SettingsTab) {
|
|||
document.body.classList.remove('disable-folder-highlight');
|
||||
}
|
||||
await settingsTab.plugin.saveSettings();
|
||||
})
|
||||
}),
|
||||
);
|
||||
|
||||
new Setting(containerEl)
|
||||
|
|
@ -131,7 +142,7 @@ export async function renderFileExplorer(settingsTab: SettingsTab) {
|
|||
document.body.classList.remove('fn-hide-collapse-icon');
|
||||
}
|
||||
settingsTab.display();
|
||||
})
|
||||
}),
|
||||
);
|
||||
|
||||
new Setting(containerEl)
|
||||
|
|
@ -149,7 +160,7 @@ export async function renderFileExplorer(settingsTab: SettingsTab) {
|
|||
document.body.classList.remove('fn-hide-empty-collapse-icon');
|
||||
}
|
||||
settingsTab.display();
|
||||
}
|
||||
},
|
||||
));
|
||||
|
||||
if (settingsTab.plugin.settings.hideCollapsingIcon) {
|
||||
|
|
@ -161,7 +172,7 @@ export async function renderFileExplorer(settingsTab: SettingsTab) {
|
|||
.onChange(async (value) => {
|
||||
settingsTab.plugin.settings.ignoreAttachmentFolder = value;
|
||||
await settingsTab.plugin.saveSettings();
|
||||
})
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -179,7 +190,7 @@ export async function renderFileExplorer(settingsTab: SettingsTab) {
|
|||
document.body.classList.remove('folder-note-underline');
|
||||
}
|
||||
await settingsTab.plugin.saveSettings();
|
||||
})
|
||||
}),
|
||||
);
|
||||
|
||||
new Setting(containerEl)
|
||||
|
|
@ -196,7 +207,7 @@ export async function renderFileExplorer(settingsTab: SettingsTab) {
|
|||
document.body.classList.remove('folder-note-bold');
|
||||
}
|
||||
await settingsTab.plugin.saveSettings();
|
||||
})
|
||||
}),
|
||||
);
|
||||
|
||||
new Setting(containerEl)
|
||||
|
|
@ -213,7 +224,7 @@ export async function renderFileExplorer(settingsTab: SettingsTab) {
|
|||
document.body.classList.remove('folder-note-cursive');
|
||||
}
|
||||
await settingsTab.plugin.saveSettings();
|
||||
})
|
||||
}),
|
||||
);
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
import { Setting } from 'obsidian';
|
||||
import { SettingsTab } from './SettingsTab';
|
||||
import type { SettingsTab } from './SettingsTab';
|
||||
import { createOverviewSettings } from 'src/obsidian-folder-overview/src/settings';
|
||||
|
||||
export async function renderFolderOverview(settingsTab: SettingsTab) {
|
||||
export async function renderFolderOverview(settingsTab: SettingsTab): Promise<void> {
|
||||
const { plugin } = settingsTab;
|
||||
const defaultOverviewSettings = plugin.settings.defaultOverview;
|
||||
const containerEl = settingsTab.settingsPage;
|
||||
|
|
@ -10,6 +10,7 @@ export async function renderFolderOverview(settingsTab: SettingsTab) {
|
|||
containerEl.createEl('h3', { text: 'Global settings' });
|
||||
new Setting(containerEl)
|
||||
.setName('Auto-update links without opening the overview')
|
||||
// eslint-disable-next-line max-len
|
||||
.setDesc('If enabled, the links that appear in the graph view will be updated even when you don\'t have the overview open somewhere.')
|
||||
.addToggle((toggle) =>
|
||||
toggle
|
||||
|
|
@ -22,7 +23,7 @@ export async function renderFolderOverview(settingsTab: SettingsTab) {
|
|||
} else {
|
||||
plugin.fvIndexDB.active = false;
|
||||
}
|
||||
})
|
||||
}),
|
||||
);
|
||||
|
||||
containerEl.createEl('h3', { text: 'Overviews default settings' });
|
||||
|
|
@ -35,5 +36,15 @@ export async function renderFolderOverview(settingsTab: SettingsTab) {
|
|||
span.setAttr('style', `color: ${accentColor};`);
|
||||
pEl.appendChild(span);
|
||||
|
||||
createOverviewSettings(containerEl, defaultOverviewSettings, plugin, plugin.settings.defaultOverview, settingsTab.display, undefined, undefined, undefined, settingsTab);
|
||||
createOverviewSettings(
|
||||
containerEl,
|
||||
defaultOverviewSettings,
|
||||
plugin,
|
||||
plugin.settings.defaultOverview,
|
||||
settingsTab.display,
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
settingsTab,
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
/* eslint-disable max-len */
|
||||
import { Setting, Platform } from 'obsidian';
|
||||
import { SettingsTab } from './SettingsTab';
|
||||
import type { SettingsTab } from './SettingsTab';
|
||||
import { ListComponent } from '../functions/ListComponent';
|
||||
import AddSupportedFileModal from '../modals/AddSupportedFileType';
|
||||
import { FrontMatterTitlePluginHandler } from '../events/FrontMatterTitle';
|
||||
|
|
@ -11,7 +12,8 @@ import RenameFolderNotesModal from './modals/RenameFns';
|
|||
|
||||
let debounceTimer: NodeJS.Timeout;
|
||||
|
||||
export async function renderGeneral(settingsTab: SettingsTab) {
|
||||
// eslint-disable-next-line complexity
|
||||
export async function renderGeneral(settingsTab: SettingsTab): Promise<void> {
|
||||
const containerEl = settingsTab.settingsPage;
|
||||
const nameSetting = new Setting(containerEl)
|
||||
.setName('Folder note name template')
|
||||
|
|
@ -25,6 +27,7 @@ export async function renderGeneral(settingsTab: SettingsTab) {
|
|||
await settingsTab.plugin.saveSettings();
|
||||
|
||||
clearTimeout(debounceTimer);
|
||||
const FOLDER_NOTE_NAME_DEBOUNCE_MS = 2000;
|
||||
debounceTimer = setTimeout(() => {
|
||||
if (!value.includes('{{folder_name}}')) {
|
||||
if (!settingsTab.showFolderNameInTabTitleSetting) {
|
||||
|
|
@ -37,8 +40,8 @@ export async function renderGeneral(settingsTab: SettingsTab) {
|
|||
settingsTab.showFolderNameInTabTitleSetting = false;
|
||||
}
|
||||
}
|
||||
}, 2000);
|
||||
})
|
||||
}, FOLDER_NOTE_NAME_DEBOUNCE_MS);
|
||||
}),
|
||||
)
|
||||
.addButton((button) =>
|
||||
button
|
||||
|
|
@ -52,7 +55,7 @@ export async function renderGeneral(settingsTab: SettingsTab) {
|
|||
settingsTab.renameFolderNotes,
|
||||
[])
|
||||
.open();
|
||||
})
|
||||
}),
|
||||
);
|
||||
nameSetting.infoEl.appendText('Requires a restart to take effect');
|
||||
nameSetting.infoEl.style.color = settingsTab.app.vault.getConfig('accentColor') as string || '#7d5bed';
|
||||
|
|
@ -74,7 +77,7 @@ export async function renderGeneral(settingsTab: SettingsTab) {
|
|||
settingsTab.plugin.settings.tabManagerEnabled = value;
|
||||
await settingsTab.plugin.saveSettings();
|
||||
settingsTab.display();
|
||||
})
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -91,13 +94,24 @@ export async function renderGeneral(settingsTab: SettingsTab) {
|
|||
}
|
||||
});
|
||||
|
||||
if (!settingsTab.plugin.settings.supportedFileTypes.includes(settingsTab.plugin.settings.folderNoteType.replace('.', '')) && settingsTab.plugin.settings.folderNoteType !== '.ask') {
|
||||
if (
|
||||
!settingsTab.plugin.settings.supportedFileTypes.includes(
|
||||
settingsTab.plugin.settings.folderNoteType.replace('.', ''),
|
||||
) &&
|
||||
settingsTab.plugin.settings.folderNoteType !== '.ask'
|
||||
) {
|
||||
settingsTab.plugin.settings.folderNoteType = '.md';
|
||||
settingsTab.plugin.saveSettings();
|
||||
}
|
||||
|
||||
let defaultType = settingsTab.plugin.settings.folderNoteType.startsWith('.') ? settingsTab.plugin.settings.folderNoteType : '.' + settingsTab.plugin.settings.folderNoteType;
|
||||
if (!settingsTab.plugin.settings.supportedFileTypes.includes(defaultType.replace('.', ''))) {
|
||||
let defaultType = settingsTab.plugin.settings.folderNoteType.startsWith('.')
|
||||
? settingsTab.plugin.settings.folderNoteType
|
||||
: '.' + settingsTab.plugin.settings.folderNoteType;
|
||||
if (
|
||||
!settingsTab.plugin.settings.supportedFileTypes.includes(
|
||||
defaultType.replace('.', ''),
|
||||
)
|
||||
) {
|
||||
defaultType = '.ask';
|
||||
settingsTab.plugin.settings.folderNoteType = defaultType;
|
||||
}
|
||||
|
|
@ -115,17 +129,25 @@ export async function renderGeneral(settingsTab: SettingsTab) {
|
|||
setting0.setName('Supported file types');
|
||||
const desc0 = document.createDocumentFragment();
|
||||
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.',
|
||||
);
|
||||
setting0.setDesc(desc0);
|
||||
const list = new ListComponent(setting0.settingEl, settingsTab.plugin.settings.supportedFileTypes || [], ['md', 'canvas']);
|
||||
const list = new ListComponent(
|
||||
setting0.settingEl,
|
||||
settingsTab.plugin.settings.supportedFileTypes || [],
|
||||
['md', 'canvas'],
|
||||
);
|
||||
list.on('update', async (values: string[]) => {
|
||||
settingsTab.plugin.settings.supportedFileTypes = values;
|
||||
await settingsTab.plugin.saveSettings();
|
||||
settingsTab.display();
|
||||
});
|
||||
|
||||
if (!settingsTab.plugin.settings.supportedFileTypes.includes('md') || !settingsTab.plugin.settings.supportedFileTypes.includes('canvas') || !settingsTab.plugin.settings.supportedFileTypes.includes('excalidraw')) {
|
||||
if (
|
||||
!settingsTab.plugin.settings.supportedFileTypes.includes('md') ||
|
||||
!settingsTab.plugin.settings.supportedFileTypes.includes('canvas') ||
|
||||
!settingsTab.plugin.settings.supportedFileTypes.includes('excalidraw')
|
||||
) {
|
||||
setting0.addDropdown((dropdown) => {
|
||||
const options = [
|
||||
{ value: 'md', label: 'Markdown' },
|
||||
|
|
@ -144,7 +166,12 @@ export async function renderGeneral(settingsTab: SettingsTab) {
|
|||
dropdown.setValue('+');
|
||||
dropdown.onChange(async (value) => {
|
||||
if (value === 'custom') {
|
||||
return new AddSupportedFileModal(settingsTab.app, settingsTab.plugin, settingsTab, list as ListComponent).open();
|
||||
return new AddSupportedFileModal(
|
||||
settingsTab.app,
|
||||
settingsTab.plugin,
|
||||
settingsTab,
|
||||
list as ListComponent,
|
||||
).open();
|
||||
}
|
||||
await list.addValue(value.toLowerCase());
|
||||
settingsTab.display();
|
||||
|
|
@ -157,8 +184,13 @@ export async function renderGeneral(settingsTab: SettingsTab) {
|
|||
.setButtonText('Add custom file type')
|
||||
.setCta()
|
||||
.onClick(async () => {
|
||||
new AddSupportedFileModal(settingsTab.app, settingsTab.plugin, settingsTab, list as ListComponent).open();
|
||||
})
|
||||
new AddSupportedFileModal(
|
||||
settingsTab.app,
|
||||
settingsTab.plugin,
|
||||
settingsTab,
|
||||
list as ListComponent,
|
||||
).open();
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -169,7 +201,11 @@ export async function renderGeneral(settingsTab: SettingsTab) {
|
|||
.addSearch((cb) => {
|
||||
new TemplateSuggest(cb.inputEl, settingsTab.plugin);
|
||||
cb.setPlaceholder('Template path');
|
||||
cb.setValue(settingsTab.plugin.app.vault.getAbstractFileByPath(settingsTab.plugin.settings.templatePath)?.name.replace('.md', '') || '');
|
||||
const templateFile = settingsTab.plugin.app.vault.getAbstractFileByPath(
|
||||
settingsTab.plugin.settings.templatePath,
|
||||
);
|
||||
const templateName = templateFile?.name.replace('.md', '') || '';
|
||||
cb.setValue(templateName);
|
||||
cb.onChange(async (value) => {
|
||||
if (value.trim() === '') {
|
||||
settingsTab.plugin.settings.templatePath = '';
|
||||
|
|
@ -195,7 +231,7 @@ export async function renderGeneral(settingsTab: SettingsTab) {
|
|||
await settingsTab.plugin.saveSettings();
|
||||
settingsTab.display();
|
||||
refreshAllFolderStyles(undefined, settingsTab.plugin);
|
||||
})
|
||||
}),
|
||||
)
|
||||
.addButton((button) =>
|
||||
button
|
||||
|
|
@ -213,9 +249,9 @@ export async function renderGeneral(settingsTab: SettingsTab) {
|
|||
'Switch storage location',
|
||||
'When you click on "Confirm" all folder notes will be moved to the new storage location.',
|
||||
settingsTab.switchStorageLocation,
|
||||
[oldStorageLocation]
|
||||
[oldStorageLocation],
|
||||
).open();
|
||||
})
|
||||
}),
|
||||
);
|
||||
storageLocation.infoEl.appendText('Requires a restart to take effect');
|
||||
storageLocation.infoEl.style.color = settingsTab.app.vault.getConfig('accentColor') as string || '#7d5bed';
|
||||
|
|
@ -230,8 +266,8 @@ export async function renderGeneral(settingsTab: SettingsTab) {
|
|||
.onChange(async (value) => {
|
||||
settingsTab.plugin.settings.syncDelete = value;
|
||||
await settingsTab.plugin.saveSettings();
|
||||
}
|
||||
)
|
||||
},
|
||||
),
|
||||
);
|
||||
new Setting(containerEl)
|
||||
.setName('Move folder notes when moving the folder')
|
||||
|
|
@ -242,7 +278,7 @@ export async function renderGeneral(settingsTab: SettingsTab) {
|
|||
.onChange(async (value) => {
|
||||
settingsTab.plugin.settings.syncMove = value;
|
||||
await settingsTab.plugin.saveSettings();
|
||||
})
|
||||
}),
|
||||
);
|
||||
}
|
||||
if (Platform.isDesktopApp) {
|
||||
|
|
@ -309,7 +345,7 @@ export async function renderGeneral(settingsTab: SettingsTab) {
|
|||
settingsTab.plugin.settings.showDeleteConfirmation = value;
|
||||
await settingsTab.plugin.saveSettings();
|
||||
settingsTab.display();
|
||||
})
|
||||
}),
|
||||
);
|
||||
|
||||
new Setting(containerEl)
|
||||
|
|
@ -338,7 +374,7 @@ export async function renderGeneral(settingsTab: SettingsTab) {
|
|||
settingsTab.plugin.settings.openInNewTab = value;
|
||||
await settingsTab.plugin.saveSettings();
|
||||
settingsTab.display();
|
||||
})
|
||||
}),
|
||||
);
|
||||
setting3.infoEl.appendText('Requires a restart to take effect');
|
||||
setting3.infoEl.style.color = settingsTab.app.vault.getConfig('accentColor') as string || '#7d5bed';
|
||||
|
|
@ -355,7 +391,7 @@ export async function renderGeneral(settingsTab: SettingsTab) {
|
|||
settingsTab.plugin.settings.focusExistingTab = value;
|
||||
await settingsTab.plugin.saveSettings();
|
||||
settingsTab.display();
|
||||
})
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -369,7 +405,7 @@ export async function renderGeneral(settingsTab: SettingsTab) {
|
|||
settingsTab.plugin.settings.syncFolderName = value;
|
||||
await settingsTab.plugin.saveSettings();
|
||||
settingsTab.display();
|
||||
})
|
||||
}),
|
||||
);
|
||||
|
||||
settingsTab.settingsPage.createEl('h4', { text: 'Automation settings' });
|
||||
|
|
@ -395,7 +431,7 @@ export async function renderGeneral(settingsTab: SettingsTab) {
|
|||
settingsTab.plugin.settings.autoCreate = value;
|
||||
await settingsTab.plugin.saveSettings();
|
||||
settingsTab.display();
|
||||
})
|
||||
}),
|
||||
);
|
||||
|
||||
if (settingsTab.plugin.settings.autoCreate) {
|
||||
|
|
@ -409,7 +445,7 @@ export async function renderGeneral(settingsTab: SettingsTab) {
|
|||
settingsTab.plugin.settings.autoCreateFocusFiles = value;
|
||||
await settingsTab.plugin.saveSettings();
|
||||
settingsTab.display();
|
||||
})
|
||||
}),
|
||||
);
|
||||
|
||||
new Setting(containerEl)
|
||||
|
|
@ -422,7 +458,7 @@ export async function renderGeneral(settingsTab: SettingsTab) {
|
|||
settingsTab.plugin.settings.autoCreateForAttachmentFolder = value;
|
||||
await settingsTab.plugin.saveSettings();
|
||||
settingsTab.display();
|
||||
})
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -436,7 +472,7 @@ export async function renderGeneral(settingsTab: SettingsTab) {
|
|||
settingsTab.plugin.settings.autoCreateForFiles = value;
|
||||
await settingsTab.plugin.saveSettings();
|
||||
settingsTab.display();
|
||||
})
|
||||
}),
|
||||
);
|
||||
|
||||
settingsTab.settingsPage.createEl('h3', { text: 'Integration & Compatibility' });
|
||||
|
|
@ -464,19 +500,29 @@ export async function renderGeneral(settingsTab: SettingsTab) {
|
|||
settingsTab.plugin.settings.frontMatterTitle.enabled = value;
|
||||
await settingsTab.plugin.saveSettings();
|
||||
if (value) {
|
||||
settingsTab.plugin.fmtpHandler = new FrontMatterTitlePluginHandler(settingsTab.plugin);
|
||||
settingsTab.plugin.fmtpHandler =
|
||||
new FrontMatterTitlePluginHandler(settingsTab.plugin);
|
||||
} else {
|
||||
if (settingsTab.plugin.fmtpHandler) {
|
||||
settingsTab.plugin.updateAllBreadcrumbs(true);
|
||||
}
|
||||
settingsTab.plugin.app.vault.getFiles().forEach((file) => {
|
||||
settingsTab.plugin.fmtpHandler?.fmptUpdateFileName({ id: '', result: false, path: file.path, pathOnly: false }, false);
|
||||
settingsTab.plugin.fmtpHandler?.fmptUpdateFileName(
|
||||
{
|
||||
id: '',
|
||||
result: false,
|
||||
path: file.path,
|
||||
pathOnly: false,
|
||||
},
|
||||
false,
|
||||
);
|
||||
});
|
||||
settingsTab.plugin.fmtpHandler?.deleteEvent();
|
||||
settingsTab.plugin.fmtpHandler = new FrontMatterTitlePluginHandler(settingsTab.plugin);
|
||||
settingsTab.plugin.fmtpHandler =
|
||||
new FrontMatterTitlePluginHandler(settingsTab.plugin);
|
||||
}
|
||||
settingsTab.display();
|
||||
})
|
||||
}),
|
||||
);
|
||||
fmtpSetting.infoEl.appendText('Requires a restart to take effect');
|
||||
fmtpSetting.infoEl.style.color = settingsTab.app.vault.getConfig('accentColor') as string || '#7d5bed';
|
||||
|
|
@ -493,7 +539,7 @@ export async function renderGeneral(settingsTab: SettingsTab) {
|
|||
settingsTab.plugin.settings.persistentSettingsTab.afterRestart = value;
|
||||
await settingsTab.plugin.saveSettings();
|
||||
settingsTab.display();
|
||||
})
|
||||
}),
|
||||
);
|
||||
|
||||
new Setting(containerEl)
|
||||
|
|
@ -506,6 +552,6 @@ export async function renderGeneral(settingsTab: SettingsTab) {
|
|||
settingsTab.plugin.settings.persistentSettingsTab.afterChangingTab = value;
|
||||
await settingsTab.plugin.saveSettings();
|
||||
settingsTab.display();
|
||||
})
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
/* eslint-disable max-len */
|
||||
import { Setting } from 'obsidian';
|
||||
import { SettingsTab } from './SettingsTab';
|
||||
export async function renderPath(settingsTab: SettingsTab) {
|
||||
import type { SettingsTab } from './SettingsTab';
|
||||
export async function renderPath(settingsTab: SettingsTab): Promise<void> {
|
||||
const containerEl = settingsTab.settingsPage;
|
||||
new Setting(containerEl)
|
||||
.setName('Open folder note through path')
|
||||
|
|
@ -12,7 +13,7 @@ export async function renderPath(settingsTab: SettingsTab) {
|
|||
settingsTab.plugin.settings.openFolderNoteOnClickInPath = value;
|
||||
await settingsTab.plugin.saveSettings();
|
||||
settingsTab.display();
|
||||
})
|
||||
}),
|
||||
);
|
||||
|
||||
if (settingsTab.plugin.settings.openFolderNoteOnClickInPath) {
|
||||
|
|
@ -25,7 +26,7 @@ export async function renderPath(settingsTab: SettingsTab) {
|
|||
.onChange(async (value) => {
|
||||
settingsTab.plugin.settings.openSidebar.mobile = value;
|
||||
await settingsTab.plugin.saveSettings();
|
||||
})
|
||||
}),
|
||||
);
|
||||
|
||||
new Setting(containerEl)
|
||||
|
|
@ -37,7 +38,7 @@ export async function renderPath(settingsTab: SettingsTab) {
|
|||
.onChange(async (value) => {
|
||||
settingsTab.plugin.settings.openSidebar.desktop = value;
|
||||
await settingsTab.plugin.saveSettings();
|
||||
})
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -56,7 +57,7 @@ export async function renderPath(settingsTab: SettingsTab) {
|
|||
} else {
|
||||
settingsTab.plugin.updateAllBreadcrumbs(true);
|
||||
}
|
||||
})
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -76,7 +77,7 @@ export async function renderPath(settingsTab: SettingsTab) {
|
|||
document.body.classList.remove('folder-note-underline-path');
|
||||
}
|
||||
await settingsTab.plugin.saveSettings();
|
||||
})
|
||||
}),
|
||||
);
|
||||
|
||||
new Setting(containerEl)
|
||||
|
|
@ -93,7 +94,7 @@ export async function renderPath(settingsTab: SettingsTab) {
|
|||
document.body.classList.remove('folder-note-bold-path');
|
||||
}
|
||||
await settingsTab.plugin.saveSettings();
|
||||
})
|
||||
}),
|
||||
);
|
||||
|
||||
new Setting(containerEl)
|
||||
|
|
@ -110,6 +111,6 @@ export async function renderPath(settingsTab: SettingsTab) {
|
|||
document.body.classList.remove('folder-note-cursive-path');
|
||||
}
|
||||
await settingsTab.plugin.saveSettings();
|
||||
})
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,17 +1,20 @@
|
|||
import { App, Notice, PluginSettingTab, TFile, TFolder, MarkdownPostProcessorContext } from 'obsidian';
|
||||
import FolderNotesPlugin from '../main';
|
||||
import { ExcludePattern } from 'src/ExcludeFolders/ExcludePattern';
|
||||
import { ExcludedFolder } from 'src/ExcludeFolders/ExcludeFolder';
|
||||
import {
|
||||
Notice, PluginSettingTab, TFile,
|
||||
TFolder, type App, type MarkdownPostProcessorContext,
|
||||
} from 'obsidian';
|
||||
import type FolderNotesPlugin from '../main';
|
||||
import type { ExcludePattern } from 'src/ExcludeFolders/ExcludePattern';
|
||||
import type { ExcludedFolder } from 'src/ExcludeFolders/ExcludeFolder';
|
||||
import { extractFolderName, getFolderNote } from '../functions/folderNoteFunctions';
|
||||
import { defaultOverviewSettings } from '../obsidian-folder-overview/src/FolderOverview';
|
||||
import type { defaultOverviewSettings } from '../obsidian-folder-overview/src/FolderOverview';
|
||||
import { renderGeneral } from './GeneralSettings';
|
||||
import { renderFileExplorer } from './FileExplorerSettings';
|
||||
import { renderPath } from './PathSettings';
|
||||
import { renderFolderOverview } from './FolderOverviewSettings';
|
||||
import { renderExcludeFolders } from './ExcludedFoldersSettings';
|
||||
import { getFolderPathFromString } from '../functions/utils';
|
||||
import { WhitelistedFolder } from 'src/ExcludeFolders/WhitelistFolder';
|
||||
import { WhitelistedPattern } from 'src/ExcludeFolders/WhitelistPattern';
|
||||
import type { WhitelistedFolder } from 'src/ExcludeFolders/WhitelistFolder';
|
||||
import type { WhitelistedPattern } from 'src/ExcludeFolders/WhitelistPattern';
|
||||
|
||||
export interface FolderNotesSettings {
|
||||
syncFolderName: boolean;
|
||||
|
|
@ -235,7 +238,8 @@ export class SettingsTab extends PluginSettingTab {
|
|||
id: 'path',
|
||||
},
|
||||
};
|
||||
renderSettingsPage(tabId: string) {
|
||||
|
||||
renderSettingsPage(tabId: string): void {
|
||||
this.settingsPage.empty();
|
||||
switch (tabId.toLocaleLowerCase()) {
|
||||
case this.TABS.GENERAL.id:
|
||||
|
|
@ -256,7 +260,17 @@ export class SettingsTab extends PluginSettingTab {
|
|||
}
|
||||
}
|
||||
|
||||
display(contentEl?: HTMLElement, yaml?: defaultOverviewSettings, plugin?: FolderNotesPlugin, defaultSettings?: boolean, display?: CallableFunction, el?: HTMLElement, ctx?: MarkdownPostProcessorContext, file?: TFile | null, settingsTab?: this) {
|
||||
display(
|
||||
contentEl?: HTMLElement,
|
||||
yaml?: defaultOverviewSettings,
|
||||
plugin?: FolderNotesPlugin,
|
||||
defaultSettings?: boolean,
|
||||
display?: CallableFunction,
|
||||
el?: HTMLElement,
|
||||
ctx?: MarkdownPostProcessorContext,
|
||||
file?: TFile | null,
|
||||
settingsTab?: this,
|
||||
): void {
|
||||
plugin = this?.plugin ?? plugin;
|
||||
if (plugin) {
|
||||
plugin.settingsOpened = true;
|
||||
|
|
@ -273,13 +287,17 @@ export class SettingsTab extends PluginSettingTab {
|
|||
for (const [tabId, tabInfo] of Object.entries(settingsTab.TABS)) {
|
||||
const tabEl = tabBar.createEl('div', { cls: 'fn-settings-tab' });
|
||||
tabEl.createEl('div', { cls: 'fn-settings-tab-name', text: tabInfo.name });
|
||||
if (plugin && plugin.settings.settingsTab.toLocaleLowerCase() === tabId.toLocaleLowerCase()) {
|
||||
if (
|
||||
plugin &&
|
||||
plugin.settings.settingsTab.toLocaleLowerCase() ===
|
||||
tabId.toLocaleLowerCase()
|
||||
) {
|
||||
tabEl.addClass('fn-settings-tab-active');
|
||||
}
|
||||
tabEl.addEventListener('click', () => {
|
||||
// @ts-ignore
|
||||
for (const tabEl of tabBar.children) {
|
||||
tabEl.removeClass('fn-settings-tab-active');
|
||||
// @ts-expect-error: tabBar.children may not have removeClass method, but we know it works in this context
|
||||
for (const child of tabBar.children) {
|
||||
child.removeClass('fn-settings-tab-active');
|
||||
if (!plugin) { return; }
|
||||
plugin.settings.settingsTab = tabId.toLocaleLowerCase();
|
||||
plugin.saveSettings();
|
||||
|
|
@ -299,23 +317,31 @@ export class SettingsTab extends PluginSettingTab {
|
|||
}
|
||||
}
|
||||
|
||||
renameFolderNotes() {
|
||||
renameFolderNotes(): void {
|
||||
new Notice('Starting to update folder notes...');
|
||||
const oldTemplate = this.plugin.settings.oldFolderNoteName ?? '{{folder_name}}';
|
||||
|
||||
for (const folder of this.app.vault.getAllLoadedFiles()) {
|
||||
if (folder instanceof TFolder) {
|
||||
const folderNote = getFolderNote(this.plugin, folder.path, undefined, undefined, oldTemplate);
|
||||
const folderNote = getFolderNote(
|
||||
this.plugin,
|
||||
folder.path,
|
||||
undefined,
|
||||
undefined,
|
||||
oldTemplate,
|
||||
);
|
||||
if (!(folderNote instanceof TFile)) { continue; }
|
||||
|
||||
const folderName = extractFolderName(oldTemplate, folderNote.basename) ?? '';
|
||||
const newFolderNoteName = this.plugin.settings.folderNoteName.replace('{{folder_name}}', folderName);
|
||||
const newFolderNoteName = this.plugin.settings.folderNoteName
|
||||
.replace('{{folder_name}}', folderName);
|
||||
let newPath = '';
|
||||
|
||||
if (this.plugin.settings.storageLocation === 'parentFolder') {
|
||||
if (getFolderPathFromString(folder.path).trim() === '/') {
|
||||
newPath = `${newFolderNoteName}.${folderNote.extension}`;
|
||||
} else {
|
||||
// eslint-disable-next-line max-len
|
||||
newPath = `${folderNote.parent?.path}/${newFolderNoteName}.${folderNote.extension}`;
|
||||
}
|
||||
} else if (this.plugin.settings.storageLocation === 'insideFolder') {
|
||||
|
|
@ -331,7 +357,7 @@ export class SettingsTab extends PluginSettingTab {
|
|||
new Notice('Finished updating folder notes');
|
||||
}
|
||||
|
||||
switchStorageLocation(oldMethod: string) {
|
||||
switchStorageLocation(oldMethod: string): void {
|
||||
new Notice('Starting to switch storage location...');
|
||||
this.app.vault.getAllLoadedFiles().forEach((file) => {
|
||||
if (file instanceof TFolder) {
|
||||
|
|
@ -348,10 +374,10 @@ export class SettingsTab extends PluginSettingTab {
|
|||
} else if (this.plugin.settings.storageLocation === 'insideFolder') {
|
||||
if (getFolderPathFromString(folderNote.path) === file.path) {
|
||||
return;
|
||||
} else {
|
||||
const newPath = `${file.path}/${folderNote.name}`;
|
||||
this.plugin.app.fileManager.renameFile(folderNote, newPath);
|
||||
}
|
||||
const newPath = `${file.path}/${folderNote.name}`;
|
||||
this.plugin.app.fileManager.renameFile(folderNote, newPath);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,14 +1,20 @@
|
|||
import { Modal, ButtonComponent } from 'obsidian';
|
||||
import FolderNotesPlugin from 'src/main';
|
||||
import type FolderNotesPlugin from 'src/main';
|
||||
|
||||
export default class BackupWarningModal extends Modal {
|
||||
plugin: FolderNotesPlugin;
|
||||
title: string;
|
||||
desc: string;
|
||||
callback: (...args: any[]) => void;
|
||||
args: any[];
|
||||
callback: (...args: unknown[]) => void;
|
||||
args: unknown[];
|
||||
|
||||
constructor(plugin: FolderNotesPlugin, title: string, description: string, callback: (...args: any[]) => void, args: any[] = []) {
|
||||
constructor(
|
||||
plugin: FolderNotesPlugin,
|
||||
title: string,
|
||||
description: string,
|
||||
callback: (...args: unknown[]) => void,
|
||||
args: unknown[] = [],
|
||||
) {
|
||||
super(plugin.app);
|
||||
this.plugin = plugin;
|
||||
this.title = title;
|
||||
|
|
@ -17,7 +23,7 @@ export default class BackupWarningModal extends Modal {
|
|||
this.desc = description;
|
||||
}
|
||||
|
||||
onOpen() {
|
||||
onOpen(): void {
|
||||
this.modalEl.addClass('fn-backup-warning-modal');
|
||||
const { contentEl } = this;
|
||||
|
||||
|
|
@ -25,8 +31,7 @@ export default class BackupWarningModal extends Modal {
|
|||
|
||||
contentEl.createEl('p', { text: this.desc });
|
||||
|
||||
this.insertCustomHtml();
|
||||
|
||||
// eslint-disable-next-line max-len
|
||||
contentEl.createEl('p', { text: 'Make sure to backup your vault before using this feature.' }).style.color = '#fb464c';
|
||||
|
||||
const buttonContainer = contentEl.createDiv({ cls: 'fn-modal-button-container' });
|
||||
|
|
@ -45,11 +50,7 @@ export default class BackupWarningModal extends Modal {
|
|||
});
|
||||
}
|
||||
|
||||
insertCustomHtml(): void {
|
||||
|
||||
}
|
||||
|
||||
onClose() {
|
||||
onClose(): void {
|
||||
const { contentEl } = this;
|
||||
contentEl.empty();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { App, ButtonComponent, Modal, Setting, TFolder, Notice } from 'obsidian';
|
||||
import FolderNotesPlugin from '../../main';
|
||||
import { Modal, Setting, TFolder, Notice, type App, type ButtonComponent } from 'obsidian';
|
||||
import type FolderNotesPlugin from '../../main';
|
||||
import { createFolderNote, getFolderNote } from 'src/functions/folderNoteFunctions';
|
||||
import { getTemplatePlugins } from 'src/template';
|
||||
import { getExcludedFolder } from 'src/ExcludeFolders/functions/folderFunctions';
|
||||
|
|
@ -14,7 +14,8 @@ export default class ConfirmationModal extends Modal {
|
|||
this.app = app;
|
||||
this.extension = plugin.settings.folderNoteType;
|
||||
}
|
||||
onOpen() {
|
||||
|
||||
onOpen(): void {
|
||||
this.modalEl.addClass('fn-confirmation-modal');
|
||||
let templateFolderPath: string;
|
||||
const { templateFolder, templaterPlugin } = getTemplatePlugins(this.plugin.app);
|
||||
|
|
@ -22,19 +23,29 @@ export default class ConfirmationModal extends Modal {
|
|||
templateFolderPath = '';
|
||||
}
|
||||
if (templaterPlugin) {
|
||||
templateFolderPath = templaterPlugin.plugin?.settings?.templates_folder as string;
|
||||
} else {
|
||||
templateFolderPath = (
|
||||
templaterPlugin as unknown as {
|
||||
plugin?: { settings?: { templates_folder?: string } }
|
||||
}
|
||||
).plugin?.settings?.templates_folder as string;
|
||||
} else if (templateFolder) {
|
||||
templateFolderPath = templateFolder;
|
||||
}
|
||||
|
||||
const { contentEl } = this;
|
||||
contentEl.createEl('h2', { text: 'Create folder note for every folder' });
|
||||
const setting = new Setting(contentEl);
|
||||
// eslint-disable-next-line max-len
|
||||
setting.infoEl.createEl('p', { text: 'Make sure to backup your vault before using this feature.' }).style.color = '#fb464c';
|
||||
// eslint-disable-next-line max-len
|
||||
setting.infoEl.createEl('p', { text: 'This feature will create a folder note for every folder in your vault.' });
|
||||
// eslint-disable-next-line max-len
|
||||
setting.infoEl.createEl('p', { text: 'Every folder that already has a folder note will be ignored.' });
|
||||
setting.infoEl.createEl('p', { text: 'Every excluded folder will be ignored.' });
|
||||
if (!this.plugin.settings.templatePath || this.plugin.settings.templatePath?.trim() === '') {
|
||||
if (
|
||||
!this.plugin.settings.templatePath ||
|
||||
this.plugin.settings.templatePath?.trim() === ''
|
||||
) {
|
||||
new Setting(contentEl)
|
||||
.setName('Folder note file extension')
|
||||
.setDesc('Choose the file extension for the folder notes.')
|
||||
|
|
@ -46,7 +57,7 @@ export default class ConfirmationModal extends Modal {
|
|||
cb.onChange(async (value) => {
|
||||
this.extension = value;
|
||||
});
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
new Setting(contentEl)
|
||||
|
|
@ -55,17 +66,24 @@ export default class ConfirmationModal extends Modal {
|
|||
cb.setCta();
|
||||
cb.buttonEl.focus();
|
||||
cb.onClick(async () => {
|
||||
if (this.plugin.settings.templatePath && this.plugin.settings.templatePath.trim() !== '') {
|
||||
if (
|
||||
this.plugin.settings.templatePath &&
|
||||
this.plugin.settings.templatePath.trim() !== ''
|
||||
) {
|
||||
this.extension = '.' + this.plugin.settings.templatePath.split('.').pop();
|
||||
}
|
||||
if (this.extension === '.ask') {
|
||||
return new Notice('Please choose a file extension');
|
||||
}
|
||||
this.close();
|
||||
const folders = this.app.vault.getAllLoadedFiles().filter((file) => file.parent instanceof TFolder);
|
||||
const folders = this.app.vault
|
||||
.getAllLoadedFiles()
|
||||
.filter((file) => file.parent instanceof TFolder);
|
||||
for (const folder of folders) {
|
||||
if (folder instanceof TFolder) {
|
||||
const excludedFolder = getExcludedFolder(this.plugin, folder.path, true);
|
||||
const excludedFolder = getExcludedFolder(
|
||||
this.plugin, folder.path, true,
|
||||
);
|
||||
if (excludedFolder) continue;
|
||||
if (folder.path === templateFolderPath) continue;
|
||||
const folderNote = getFolderNote(this.plugin, folder.path);
|
||||
|
|
@ -82,7 +100,8 @@ export default class ConfirmationModal extends Modal {
|
|||
});
|
||||
});
|
||||
}
|
||||
onClose() {
|
||||
|
||||
onClose(): void {
|
||||
const { contentEl } = this;
|
||||
contentEl.empty();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,15 @@
|
|||
import BackupWarningModal from './BackupWarning';
|
||||
import FolderNotesPlugin from 'src/main';
|
||||
import type FolderNotesPlugin from 'src/main';
|
||||
import { Setting } from 'obsidian';
|
||||
|
||||
export default class RenameFolderNotesModal extends BackupWarningModal {
|
||||
constructor(plugin: FolderNotesPlugin, title: string, description: string, callback: (...args: any[]) => void, args: any[] = []) {
|
||||
constructor(
|
||||
plugin: FolderNotesPlugin,
|
||||
title: string,
|
||||
description: string,
|
||||
callback: (...args: unknown[]) => void,
|
||||
args: unknown[] = [],
|
||||
) {
|
||||
super(plugin, title, description, callback, args);
|
||||
}
|
||||
|
||||
|
|
@ -11,17 +17,19 @@ export default class RenameFolderNotesModal extends BackupWarningModal {
|
|||
const { contentEl } = this;
|
||||
new Setting(contentEl)
|
||||
.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.')
|
||||
.addText((text) => text
|
||||
.setPlaceholder('Enter the old folder note name')
|
||||
.setValue(this.plugin.settings.oldFolderNoteName || '')
|
||||
.onChange(async (value) => {
|
||||
this.plugin.settings.oldFolderNoteName = value;
|
||||
})
|
||||
}),
|
||||
);
|
||||
|
||||
new Setting(contentEl)
|
||||
.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.')
|
||||
.addText((text) => text
|
||||
.setPlaceholder('Enter the new folder note name')
|
||||
|
|
@ -29,7 +37,7 @@ export default class RenameFolderNotesModal extends BackupWarningModal {
|
|||
.onChange(async (value) => {
|
||||
this.plugin.settings.folderNoteName = value;
|
||||
this.plugin.settingsTab.display();
|
||||
})
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,6 @@
|
|||
// Credits go to Liam's Periodic Notes Plugin: https://github.com/liamcain/obsidian-periodic-notes and https://github.com/SilentVoid13/Templater
|
||||
|
||||
import { TAbstractFile, TFile } from 'obsidian';
|
||||
import { type TAbstractFile, TFile } from 'obsidian';
|
||||
import { TextInputSuggest } from './Suggest';
|
||||
import FolderNotesPlugin from '../main';
|
||||
import type FolderNotesPlugin from '../main';
|
||||
export enum FileSuggestMode {
|
||||
TemplateFiles,
|
||||
ScriptFiles,
|
||||
|
|
@ -11,7 +9,7 @@ export enum FileSuggestMode {
|
|||
export class FileSuggest extends TextInputSuggest<TFile> {
|
||||
constructor(
|
||||
public inputEl: HTMLInputElement,
|
||||
plugin: FolderNotesPlugin
|
||||
plugin: FolderNotesPlugin,
|
||||
) {
|
||||
super(inputEl, plugin);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
// Credits go to Liam's Periodic Notes Plugin: https://github.com/liamcain/obsidian-periodic-notes and https://github.com/SilentVoid13/Templater
|
||||
|
||||
import { TAbstractFile, TFolder } from 'obsidian';
|
||||
import { TFolder, type TAbstractFile } from 'obsidian';
|
||||
import { TextInputSuggest } from './Suggest';
|
||||
import FolderNotesPlugin from '../main';
|
||||
import type FolderNotesPlugin from '../main';
|
||||
export enum FileSuggestMode {
|
||||
TemplateFiles,
|
||||
ScriptFiles,
|
||||
|
|
@ -35,13 +35,18 @@ export class FolderSuggest extends TextInputSuggest<TFolder> {
|
|||
if (this.folder) {
|
||||
files = this.folder.children;
|
||||
} else {
|
||||
files = this.plugin.app.vault.getAllLoadedFiles().slice(0,100);
|
||||
const MAX_FILE_SUGGESTIONS = 100;
|
||||
files = this.plugin.app.vault.getAllLoadedFiles().slice(0, MAX_FILE_SUGGESTIONS);
|
||||
}
|
||||
files.forEach((folder: TAbstractFile) => {
|
||||
if (
|
||||
folder instanceof TFolder &&
|
||||
folder.path.toLowerCase().contains(lower_input_str) &&
|
||||
(!this.plugin.settings.excludeFolders.find((f) => f.path === folder.path) || this.whitelistSuggester)
|
||||
folder.path.toLowerCase().contains(lower_input_str) &&
|
||||
(
|
||||
!this.plugin.settings.excludeFolders.find(
|
||||
(f) => f.path === folder.path,
|
||||
) || this.whitelistSuggester
|
||||
)
|
||||
) {
|
||||
folders.push(folder);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,8 @@
|
|||
// Credits go to Liam's Periodic Notes Plugin: https://github.com/liamcain/obsidian-periodic-notes and https://github.com/SilentVoid13/Templater
|
||||
|
||||
|
||||
import { ISuggestOwner, Scope } from 'obsidian';
|
||||
import { createPopper, Instance as PopperInstance } from '@popperjs/core';
|
||||
import FolderNotesPlugin from 'src/main';
|
||||
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;
|
||||
|
|
@ -20,7 +19,7 @@ class Suggest<T> {
|
|||
constructor(
|
||||
owner: ISuggestOwner<T>,
|
||||
containerEl: HTMLElement,
|
||||
scope: Scope
|
||||
scope: Scope,
|
||||
) {
|
||||
this.owner = owner;
|
||||
this.containerEl = containerEl;
|
||||
|
|
@ -28,12 +27,12 @@ class Suggest<T> {
|
|||
containerEl.on(
|
||||
'click',
|
||||
'.suggestion-item',
|
||||
this.onSuggestionClick.bind(this)
|
||||
this.onSuggestionClick.bind(this),
|
||||
);
|
||||
containerEl.on(
|
||||
'mousemove',
|
||||
'.suggestion-item',
|
||||
this.onSuggestionMouseover.bind(this)
|
||||
this.onSuggestionMouseover.bind(this),
|
||||
);
|
||||
|
||||
scope.register([], 'ArrowUp', (event) => {
|
||||
|
|
@ -71,7 +70,7 @@ class Suggest<T> {
|
|||
this.setSelectedItem(item, false);
|
||||
}
|
||||
|
||||
setSuggestions(values: T[]) {
|
||||
setSuggestions(values: T[]): void {
|
||||
this.containerEl.empty();
|
||||
const suggestionEls: HTMLDivElement[] = [];
|
||||
|
||||
|
|
@ -86,17 +85,17 @@ class Suggest<T> {
|
|||
this.setSelectedItem(0, false);
|
||||
}
|
||||
|
||||
useSelectedItem(event: MouseEvent | KeyboardEvent) {
|
||||
useSelectedItem(event: MouseEvent | KeyboardEvent): void {
|
||||
const currentValue = this.values[this.selectedItem];
|
||||
if (currentValue) {
|
||||
this.owner.selectSuggestion(currentValue, event);
|
||||
}
|
||||
}
|
||||
|
||||
setSelectedItem(selectedIndex: number, scrollIntoView: boolean) {
|
||||
setSelectedItem(selectedIndex: number, scrollIntoView: boolean): void {
|
||||
const normalizedIndex = wrapAround(
|
||||
selectedIndex,
|
||||
this.suggestions.length
|
||||
this.suggestions.length,
|
||||
);
|
||||
const prevSelectedSuggestion = this.suggestions[this.selectedItem];
|
||||
const selectedSuggestion = this.suggestions[normalizedIndex];
|
||||
|
|
@ -140,7 +139,7 @@ export abstract class TextInputSuggest<T> implements ISuggestOwner<T> {
|
|||
'.suggestion-container',
|
||||
(event: MouseEvent) => {
|
||||
event.preventDefault();
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -155,7 +154,7 @@ export abstract class TextInputSuggest<T> implements ISuggestOwner<T> {
|
|||
|
||||
if (suggestions.length > 0) {
|
||||
this.suggest.setSuggestions(suggestions);
|
||||
// @ts-ignore
|
||||
// @ts-expect-error App may not exist
|
||||
this.open(app.dom.appContainerEl, this.inputEl);
|
||||
} else {
|
||||
this.close();
|
||||
|
|
@ -163,7 +162,7 @@ export abstract class TextInputSuggest<T> implements ISuggestOwner<T> {
|
|||
}
|
||||
|
||||
open(container: HTMLElement, inputEl: HTMLElement): void {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
|
||||
this.plugin.app.keymap.pushScope(this.scope);
|
||||
|
||||
container.appendChild(this.suggestEl);
|
||||
|
|
@ -173,7 +172,7 @@ export abstract class TextInputSuggest<T> implements ISuggestOwner<T> {
|
|||
{
|
||||
name: 'sameWidth',
|
||||
enabled: true,
|
||||
fn: ({ state, instance }) => {
|
||||
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
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { TAbstractFile, TFile, TFolder, Vault, AbstractInputSuggest } from 'obsidian';
|
||||
import FolderNotesPlugin from '../main';
|
||||
import { TFile, TFolder, Vault, AbstractInputSuggest, type TAbstractFile } from 'obsidian';
|
||||
import type FolderNotesPlugin from '../main';
|
||||
import { getTemplatePlugins } from 'src/template';
|
||||
export enum FileSuggestMode {
|
||||
TemplateFiles,
|
||||
|
|
@ -9,7 +9,7 @@ export enum FileSuggestMode {
|
|||
export class TemplateSuggest extends AbstractInputSuggest<TFile> {
|
||||
constructor(
|
||||
public inputEl: HTMLInputElement,
|
||||
public plugin: FolderNotesPlugin
|
||||
public plugin: FolderNotesPlugin,
|
||||
) {
|
||||
super(plugin.app, inputEl);
|
||||
}
|
||||
|
|
@ -32,18 +32,27 @@ export class TemplateSuggest extends AbstractInputSuggest<TFile> {
|
|||
|
||||
if ((!templateFolder || templateFolder.trim() === '') && !templaterPlugin) {
|
||||
files = this.plugin.app.vault.getFiles().filter((file) =>
|
||||
file.path.toLowerCase().includes(lower_input_str)
|
||||
file.path.toLowerCase().includes(lower_input_str),
|
||||
);
|
||||
} else {
|
||||
let folder: TFolder | TAbstractFile | null = null;
|
||||
if (templaterPlugin) {
|
||||
folder = this.plugin.app.vault.getAbstractFileByPath(
|
||||
templaterPlugin.plugin?.settings?.templates_folder as string
|
||||
(templaterPlugin as unknown as {
|
||||
plugin?: { settings?: { templates_folder?: string } }
|
||||
}).plugin?.settings?.templates_folder as string,
|
||||
);
|
||||
if (!(folder instanceof TFolder)) {
|
||||
return [{ path: '', name: 'You need to set the Templates folder in the Templater settings first.' } as TFile];
|
||||
return [
|
||||
{
|
||||
path: '',
|
||||
name:
|
||||
// eslint-disable-next-line max-len
|
||||
'You need to set the Templates folder in the Templater settings first.',
|
||||
} as TFile,
|
||||
];
|
||||
}
|
||||
} else {
|
||||
} else if (templateFolder) {
|
||||
folder = this.plugin.app.vault.getAbstractFileByPath(templateFolder) as TFolder;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,12 +1,41 @@
|
|||
import { TFile, App, WorkspaceLeaf } from 'obsidian';
|
||||
import FolderNotesPlugin from './main';
|
||||
import { TFile, WorkspaceLeaf, type App } from 'obsidian';
|
||||
import type FolderNotesPlugin from './main';
|
||||
|
||||
interface TemplatesPlugin {
|
||||
enabled: boolean;
|
||||
instance: {
|
||||
options: {
|
||||
folder: string;
|
||||
};
|
||||
insertTemplate: (templateFile: TFile) => Promise<void>;
|
||||
};
|
||||
}
|
||||
|
||||
interface TemplaterPlugin {
|
||||
settings?: {
|
||||
empty_file_template?: string;
|
||||
template_folder?: string;
|
||||
};
|
||||
templater?: {
|
||||
write_template_to_file: (templateFile: TFile, targetFile: TFile) => Promise<void>;
|
||||
};
|
||||
}
|
||||
|
||||
interface TemplatePluginReturn {
|
||||
templatesPlugin: TemplatesPlugin | null;
|
||||
templatesEnabled: boolean;
|
||||
templaterPlugin: TemplaterPlugin['templater'] | null;
|
||||
templaterEnabled: boolean;
|
||||
templaterEmptyFileTemplate?: string;
|
||||
templateFolder?: string;
|
||||
}
|
||||
|
||||
export async function applyTemplate(
|
||||
plugin: FolderNotesPlugin,
|
||||
file: TFile,
|
||||
leaf?: WorkspaceLeaf | null,
|
||||
templatePath?: string
|
||||
) {
|
||||
templatePath?: string,
|
||||
): Promise<void> {
|
||||
const fileContent = await plugin.app.vault.read(file).catch((err) => {
|
||||
console.error(`Error reading file ${file.path}:`, err);
|
||||
});
|
||||
|
|
@ -25,21 +54,22 @@ export async function applyTemplate(
|
|||
templaterPlugin,
|
||||
} = getTemplatePlugins(plugin.app);
|
||||
const templateContent = await plugin.app.vault.read(templateFile);
|
||||
// eslint-disable-next-line max-len
|
||||
if (templateContent.includes('==⚠ Switch to EXCALIDRAW VIEW in the MORE OPTIONS menu of this document. ⚠==')) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Prioritize Templater if both plugins are enabled
|
||||
if (templaterEnabled) {
|
||||
if (templaterEnabled && templaterPlugin) {
|
||||
return await templaterPlugin.write_template_to_file(templateFile, file);
|
||||
} else if (templatesEnabled) {
|
||||
} else if (templatesEnabled && templatesPlugin) {
|
||||
if (leaf instanceof WorkspaceLeaf) {
|
||||
await leaf.openFile(file);
|
||||
}
|
||||
return await templatesPlugin.instance.insertTemplate(templateFile);
|
||||
} else {
|
||||
await plugin.app.vault.modify(file, templateContent);
|
||||
}
|
||||
await plugin.app.vault.modify(file, templateContent);
|
||||
|
||||
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
|
|
@ -47,23 +77,37 @@ export async function applyTemplate(
|
|||
}
|
||||
}
|
||||
|
||||
export function getTemplatePlugins(app: App) {
|
||||
const templatesPlugin = (app as any).internalPlugins.plugins.templates;
|
||||
const templatesEnabled = templatesPlugin.enabled;
|
||||
const templaterPlugin = (app as any).plugins.plugins['templater-obsidian'];
|
||||
const templaterEnabled = (app as any).plugins.enabledPlugins.has('templater-obsidian');
|
||||
export function getTemplatePlugins(app: App): TemplatePluginReturn {
|
||||
const appAsUnknown = app as unknown as {
|
||||
internalPlugins: {
|
||||
plugins: {
|
||||
templates: TemplatesPlugin;
|
||||
};
|
||||
};
|
||||
plugins: {
|
||||
plugins: {
|
||||
'templater-obsidian': TemplaterPlugin;
|
||||
};
|
||||
enabledPlugins: Set<string>;
|
||||
};
|
||||
};
|
||||
|
||||
const templatesPlugin = appAsUnknown.internalPlugins.plugins.templates;
|
||||
const templatesEnabled = templatesPlugin?.enabled ?? false;
|
||||
const templaterPlugin = appAsUnknown.plugins.plugins['templater-obsidian'];
|
||||
const templaterEnabled = appAsUnknown.plugins.enabledPlugins.has('templater-obsidian');
|
||||
|
||||
const templaterEmptyFileTemplate =
|
||||
templaterPlugin && templaterPlugin.settings?.empty_file_template;
|
||||
|
||||
const templateFolder = templatesEnabled
|
||||
? templatesPlugin.instance.options.folder
|
||||
: templaterPlugin?.settings.template_folder;
|
||||
: templaterPlugin?.settings?.template_folder;
|
||||
|
||||
return {
|
||||
templatesPlugin,
|
||||
templatesPlugin: templatesPlugin || null,
|
||||
templatesEnabled,
|
||||
templaterPlugin: templaterPlugin?.templater,
|
||||
templaterPlugin: templaterPlugin?.templater || null,
|
||||
templaterEnabled,
|
||||
templaterEmptyFileTemplate,
|
||||
templateFolder,
|
||||
|
|
|
|||
Loading…
Reference in a new issue