mirror of
https://github.com/alberti42/obsidian-import-attachments-plus.git
synced 2026-07-22 05:11:55 +00:00
Patch file explorer
This commit is contained in:
parent
40b72d919f
commit
a9dfdb8066
5 changed files with 263 additions and 103 deletions
72
src/main.ts
72
src/main.ts
|
|
@ -43,8 +43,9 @@ import { patchOpenFile, unpatchOpenFile, addKeyListeners, removeKeyListeners } f
|
|||
import { patchFilemanager, unpatchFilemanager } from 'patchFileManager';
|
||||
|
||||
import { EditorSelection } from '@codemirror/state';
|
||||
import { patchImportFunctions, unpatchImportFunctions } from "patchImportFunctions";
|
||||
|
||||
import { patchImportFunctions, unpatchImportFunctions } from "patchImportFunctions";
|
||||
import { patchFileExplorer, unpatchFileExplorer } from "patchFileExplorer";
|
||||
import { monkeyPatchConsole, unpatchConsole } from "patchConsole";
|
||||
|
||||
// Default plugin settings
|
||||
|
|
@ -150,6 +151,7 @@ export default class ImportAttachments extends Plugin {
|
|||
|
||||
folderElements.forEach((folder: Element) => {
|
||||
if (folder.parentNode && folder.parentNode instanceof HTMLElement) {
|
||||
// console.log(folder);
|
||||
if (this.settings.hideAttachmentFolders) {
|
||||
folder.parentNode.classList.add('import-plugin-hidden');
|
||||
}
|
||||
|
|
@ -236,7 +238,7 @@ export default class ImportAttachments extends Plugin {
|
|||
this.addSettingTab(new ImportAttachmentsSettingTab(this.app, this));
|
||||
|
||||
// Set up the mutation observer for hiding folders
|
||||
this.setupObserver();
|
||||
// this.setupObserver();
|
||||
|
||||
// Monkey patches of the openFile function
|
||||
if (Platform.isDesktopApp) {
|
||||
|
|
@ -832,12 +834,31 @@ export default class ImportAttachments extends Plugin {
|
|||
}
|
||||
|
||||
async openAttachmentsFolder() {
|
||||
/*
|
||||
|
||||
// Monkey-path file explorer to hide attachment folders
|
||||
patchFileExplorer(this);
|
||||
|
||||
return;
|
||||
|
||||
|
||||
// Get the file explorer plugin
|
||||
const fileExplorer = this.app.internalPlugins.getPluginById('file-explorer');
|
||||
|
||||
// Check if the plugin is loaded and enabled
|
||||
if (fileExplorer) {
|
||||
|
||||
const leaves = this.app.workspace.getLeavesOfType('file-explorer');
|
||||
for (const leaf of leaves) {
|
||||
console.log(leaf);
|
||||
const viewInstance = leaf.view;
|
||||
if (viewInstance) {
|
||||
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
console.log(fileExplorer);
|
||||
const viewFactory = fileExplorer.views['file-explorer'];
|
||||
|
||||
// Create a new instance of the view to identify its class
|
||||
|
|
@ -847,41 +868,30 @@ export default class ImportAttachments extends Plugin {
|
|||
// Identify the class used in createItemDom
|
||||
const viewClass = viewInstance.constructor;
|
||||
|
||||
// Find the JJ class by exploring the prototype
|
||||
// console.log('viewClass:', viewClass.prototype.createItemDom);
|
||||
// Log the createItemDom method to inspect it
|
||||
console.log('viewClass createFolderDom:', viewClass.prototype.createFolderDom);
|
||||
|
||||
// Use a dummy instance to explore properties (assuming createItemDom creates JJ instances)
|
||||
const dummyItem = viewClass.prototype.createItemDom.call(viewInstance, {}); // Pass an empty object as an argument
|
||||
|
||||
// Log the dummy item to inspect it
|
||||
// console.log('dummyItem:', dummyItem);
|
||||
|
||||
// Get the JJ class from the dummy item
|
||||
const JJClass = dummyItem.constructor;
|
||||
|
||||
// Log the JJ class to ensure it's identified correctly
|
||||
console.log('JJClass:', JJClass.prototype.updateTitle);
|
||||
|
||||
// Patch the JJ class prototype
|
||||
if (JJClass.prototype.updateTitle) {
|
||||
const originalUpdateTitle = JJClass.prototype.updateTitle;
|
||||
JJClass.prototype.updateTitle = function(...args: any) {
|
||||
console.log('Custom behavior before updateTitle');
|
||||
console.log(args);
|
||||
const result = originalUpdateTitle.apply(this, args);
|
||||
console.log('Custom behavior after updateTitle');
|
||||
// Patch the createItemDom method in viewClass prototype
|
||||
if (viewClass.prototype.createFolderDom) {
|
||||
const originalCreateFolderDom = viewClass.prototype.createFolderDom;
|
||||
viewClass.prototype.createFolderDom = function(...args) {
|
||||
console.log('Custom behavior before createFolderDom');
|
||||
const result = originalCreateFolderDom.apply(this, args);
|
||||
console.log(result);
|
||||
console.log('Custom behavior after createFolderDom');
|
||||
return result;
|
||||
};
|
||||
console.log('PATCHED');
|
||||
console.log('createFolderDom PATCHED');
|
||||
} else {
|
||||
console.error('updateTitle method not found on JJ prototype');
|
||||
console.error('createFolderDom method not found on viewClass prototype');
|
||||
}
|
||||
|
||||
|
||||
} else {
|
||||
console.error('File Explorer plugin not found or not enabled');
|
||||
}
|
||||
|
||||
return;
|
||||
*/
|
||||
|
||||
|
||||
const md_active_file = this.app.workspace.getActiveFile();
|
||||
|
||||
|
|
@ -906,10 +916,6 @@ export default class ImportAttachments extends Plugin {
|
|||
|
||||
const absAttachmentsFolderPath = Utils.joinPaths(this.vaultPath,attachmentsFolderPath);
|
||||
|
||||
if(!absAttachmentsFolderPath) return;
|
||||
|
||||
// TODO: Ask whether to create an Attachment folder
|
||||
|
||||
// Open the folder in the system's default file explorer
|
||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||
const { shell } = require('electron');
|
||||
|
|
|
|||
152
src/patchFileExplorer.ts
Normal file
152
src/patchFileExplorer.ts
Normal file
|
|
@ -0,0 +1,152 @@
|
|||
// patchImportFunctions.ts
|
||||
|
||||
/* eslint-disable @typescript-eslint/no-inferrable-types */
|
||||
|
||||
import { TFolder,WorkspaceLeaf, View, FileExplorerItem } from 'obsidian';
|
||||
import ImportAttachments from 'main';
|
||||
|
||||
// Define a type for the view class with the required methods
|
||||
interface FileExplorerView extends View {
|
||||
createFolderDom(folder: TFolder): FileExplorerItem;
|
||||
}
|
||||
|
||||
// Save a reference to the original method for the monkey patch
|
||||
let originalCreateFolderDom: ((folder: TFolder) => FileExplorerItem) | null = null;
|
||||
let viewClass: { new(leaf: WorkspaceLeaf): FileExplorerView } | null = null;
|
||||
|
||||
function unpatchFileExplorer() {
|
||||
if (originalCreateFolderDom && viewClass) {
|
||||
viewClass.prototype.createFolderDom = originalCreateFolderDom;
|
||||
originalCreateFolderDom = null;
|
||||
}
|
||||
}
|
||||
|
||||
function matchesPatternWithHolder(plugin: ImportAttachments, filePath: string): boolean {
|
||||
// Check if filePath starts with startsWidth or contains /startsWidth
|
||||
const startsWithMatch = filePath.startsWith(plugin.folderPathStartsWith) || filePath.includes(`/${plugin.folderPathStartsWith}`);
|
||||
|
||||
// Check if filePath ends with endsWidth
|
||||
const endsWithMatch = filePath.endsWith(plugin.folderPathEndsWith);
|
||||
|
||||
// Return true only if both conditions are met
|
||||
return startsWithMatch && endsWithMatch;
|
||||
}
|
||||
|
||||
function matchesPatternWithoutHolder(plugin: ImportAttachments, filePath: string): boolean {
|
||||
const folderName = plugin.settings.folderPath;
|
||||
return filePath.endsWith(`/${folderName}`) || filePath === folderName;
|
||||
}
|
||||
|
||||
function patchFileExplorer(plugin: ImportAttachments) {
|
||||
if (originalCreateFolderDom) { return; }
|
||||
|
||||
const leaves = plugin.app.workspace.getLeavesOfType('file-explorer');
|
||||
for (const leaf of leaves) {
|
||||
const viewInstance = leaf.view as FileExplorerView;
|
||||
originalCreateFolderDom = viewInstance.constructor.prototype.createFolderDom;
|
||||
viewClass = viewInstance.constructor as { new(leaf: WorkspaceLeaf): FileExplorerView };
|
||||
break;
|
||||
}
|
||||
|
||||
if (!viewClass) {
|
||||
console.error("file-explorer plugin could not be patched.");
|
||||
return;
|
||||
}
|
||||
|
||||
viewClass.prototype.createFolderDom = function(this: FileExplorerView, folder: TFolder): unknown {
|
||||
if(!originalCreateFolderDom) {
|
||||
console.error('Something went wrong in patching file-explorer plugin.')
|
||||
return;
|
||||
}
|
||||
|
||||
const result = originalCreateFolderDom.apply(this, [folder]);
|
||||
console.log(result);
|
||||
if(result) {
|
||||
const folderName = result.file.name;
|
||||
let hidden = false;
|
||||
if (plugin.settings.folderPath.includes("${notename}") && matchesPatternWithHolder(plugin,folderName)) {
|
||||
console.log("FOUND",folderName);
|
||||
hidden = true;
|
||||
|
||||
} else if (matchesPatternWithoutHolder(plugin,folderName)) {
|
||||
console.log("FOUND",folderName);
|
||||
hidden = true;
|
||||
}
|
||||
|
||||
if(hidden) result.el.toggleClass("import-plugin-hidden",true);
|
||||
|
||||
console.log(result.constructor);
|
||||
console.log('Custom behavior after createFolderDom');
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
console.log("PATCHED");
|
||||
}
|
||||
|
||||
export { patchFileExplorer, unpatchFileExplorer };
|
||||
|
||||
/*
|
||||
function matchesPatternWithHolder(filePath: string): boolean {
|
||||
// Check if filePath starts with startsWidth or contains /startsWidth
|
||||
const startsWithMatch = filePath.startsWith(plugin.folderPathStartsWith) || filePath.includes(`/${plugin.folderPathStartsWith}`);
|
||||
|
||||
// Check if filePath ends with endsWidth
|
||||
const endsWithMatch = filePath.endsWith(plugin.folderPathEndsWith);
|
||||
|
||||
// Return true only if both conditions are met
|
||||
return startsWithMatch && endsWithMatch;
|
||||
}
|
||||
|
||||
function matchesPatternWithoutHolder(filePath: string): boolean {
|
||||
const folderName = plugin.settings.folderPath;
|
||||
return filePath.endsWith(`/${folderName}`) || filePath === folderName;
|
||||
}
|
||||
|
||||
Vault.prototype.onChange = function (this: Vault, eventType: string, filePath: string, oldPath?: string, stat?: FileStats) {
|
||||
if (!originalOnChange) {
|
||||
throw new Error("Could not execute the original onChange function.");
|
||||
}
|
||||
|
||||
// const fileExplorerPlugin = plugin.app.internalPlugins.getPluginById('file-explorer');
|
||||
|
||||
// if(filePath.endsWith('.xyz')) {
|
||||
// // console.log("XYZ:",eventType);
|
||||
// // console.log(originalOnChange);
|
||||
// originalOnChange.call(this, eventType, filePath, oldPath, stat);
|
||||
// return;
|
||||
// }
|
||||
|
||||
// if(filePath.endsWith('.md')) {
|
||||
// // console.log("MD:",eventType);
|
||||
// return;
|
||||
// }
|
||||
|
||||
if (eventType === 'folder-created') {
|
||||
const placeholder = "${notename}";
|
||||
|
||||
if (plugin.settings.folderPath.includes(placeholder) && matchesPatternWithHolder(filePath)) {
|
||||
// console.log("1",filePath)
|
||||
// console.log(TFolder);
|
||||
|
||||
// Handle folder creation event manually
|
||||
const newFolder = new TFolder(this, filePath);
|
||||
this.fileMap[filePath] = newFolder;
|
||||
// debugger
|
||||
this.addChild(newFolder);
|
||||
|
||||
this.trigger("create", this.fileMap[filePath]);
|
||||
return;
|
||||
} else if (matchesPatternWithoutHolder(filePath)) {
|
||||
console.log("2",filePath)
|
||||
}
|
||||
}
|
||||
|
||||
originalOnChange.call(this, eventType, filePath, oldPath, stat);
|
||||
};
|
||||
|
||||
// const fileExplorer = plugin.app.internalPlugins.getPluginById('file-explorer');
|
||||
// const xyz = fileExplorer.views['file-explorer']
|
||||
// console.log(xyz);
|
||||
|
||||
*/
|
||||
|
|
@ -8,7 +8,6 @@ import ImportAttachments from 'main';
|
|||
// Save a reference to the original method for the monkey patch
|
||||
let originalGetAvailablePathForAttachments: ((fileName: string, extension: string, currentFile: TFile | null) => Promise<string>) | null = null;
|
||||
let originalSaveAttachment: ((fileName: string, fileExtension: string, fileData: ArrayBuffer) => Promise<TFile>) | null = null;
|
||||
let originalOnChange: ((eventType: string, filePath: string, oldPath?: string, stat?: FileStats) => void) | null = null;
|
||||
let data: ArrayBuffer | null = null;
|
||||
|
||||
function unpatchImportFunctions() {
|
||||
|
|
@ -21,11 +20,6 @@ function unpatchImportFunctions() {
|
|||
App.prototype.saveAttachment = originalSaveAttachment;
|
||||
originalSaveAttachment = null;
|
||||
}
|
||||
|
||||
if(originalOnChange) {
|
||||
Vault.prototype.onChange = originalOnChange;
|
||||
originalOnChange = null;
|
||||
}
|
||||
}
|
||||
|
||||
function patchImportFunctions(plugin: ImportAttachments) {
|
||||
|
|
@ -79,12 +73,13 @@ function patchImportFunctions(plugin: ImportAttachments) {
|
|||
return newAttachmentFile;
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
/*
|
||||
if (!originalOnChange) {
|
||||
originalOnChange = Vault.prototype.onChange;
|
||||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
function matchesPatternWithHolder(filePath: string): boolean {
|
||||
// Check if filePath starts with startsWidth or contains /startsWidth
|
||||
const startsWithMatch = filePath.startsWith(plugin.folderPathStartsWith) || filePath.includes(`/${plugin.folderPathStartsWith}`);
|
||||
|
|
@ -108,44 +103,46 @@ function patchImportFunctions(plugin: ImportAttachments) {
|
|||
|
||||
// const fileExplorerPlugin = plugin.app.internalPlugins.getPluginById('file-explorer');
|
||||
|
||||
if(filePath.endsWith('.xyz')) {
|
||||
// console.log("XYZ:",eventType);
|
||||
// console.log(originalOnChange);
|
||||
originalOnChange.call(this, eventType, filePath, oldPath, stat);
|
||||
return;
|
||||
}
|
||||
|
||||
if(filePath.endsWith('.md')) {
|
||||
// console.log("MD:",eventType);
|
||||
return;
|
||||
}
|
||||
|
||||
// if (eventType === 'folder-created') {
|
||||
// const placeholder = "${notename}";
|
||||
|
||||
// if (plugin.settings.folderPath.includes(placeholder) && matchesPatternWithHolder(filePath)) {
|
||||
// // console.log("1",filePath)
|
||||
// // console.log(TFolder);
|
||||
|
||||
// // Handle folder creation event manually
|
||||
// const newFolder = new TFolder(this, filePath);
|
||||
// this.fileMap[filePath] = newFolder;
|
||||
// // debugger
|
||||
// this.addChild(newFolder);
|
||||
|
||||
// this.trigger("create", this.fileMap[filePath]);
|
||||
// return;
|
||||
// } else if (matchesPatternWithoutHolder(filePath)) {
|
||||
// console.log("2",filePath)
|
||||
// }
|
||||
// if(filePath.endsWith('.xyz')) {
|
||||
// // console.log("XYZ:",eventType);
|
||||
// // console.log(originalOnChange);
|
||||
// originalOnChange.call(this, eventType, filePath, oldPath, stat);
|
||||
// return;
|
||||
// }
|
||||
|
||||
// if(filePath.endsWith('.md')) {
|
||||
// // console.log("MD:",eventType);
|
||||
// return;
|
||||
// }
|
||||
|
||||
if (eventType === 'folder-created') {
|
||||
const placeholder = "${notename}";
|
||||
|
||||
if (plugin.settings.folderPath.includes(placeholder) && matchesPatternWithHolder(filePath)) {
|
||||
// console.log("1",filePath)
|
||||
// console.log(TFolder);
|
||||
|
||||
// Handle folder creation event manually
|
||||
const newFolder = new TFolder(this, filePath);
|
||||
this.fileMap[filePath] = newFolder;
|
||||
// debugger
|
||||
this.addChild(newFolder);
|
||||
|
||||
this.trigger("create", this.fileMap[filePath]);
|
||||
return;
|
||||
} else if (matchesPatternWithoutHolder(filePath)) {
|
||||
console.log("2",filePath)
|
||||
}
|
||||
}
|
||||
|
||||
originalOnChange.call(this, eventType, filePath, oldPath, stat);
|
||||
};
|
||||
|
||||
// const fileExplorer = plugin.app.internalPlugins.getPluginById('file-explorer');
|
||||
// const xyz = fileExplorer.views['file-explorer']
|
||||
// console.log(xyz);
|
||||
|
||||
*/
|
||||
}
|
||||
|
||||
export { patchImportFunctions, unpatchImportFunctions };
|
||||
|
|
|
|||
57
src/types/obsidian-augment.d.ts
vendored
57
src/types/obsidian-augment.d.ts
vendored
|
|
@ -4,31 +4,44 @@ import 'obsidian';
|
|||
import { EditorView } from '@codemirror/view';
|
||||
|
||||
declare module 'obsidian' {
|
||||
interface App {
|
||||
openWithDefaultApp(filepath: string): Promise<void>;
|
||||
saveAttachment(fileName: string, fileExtension: string, fileData: ArrayBuffer): Promise<TFile>;
|
||||
}
|
||||
interface App {
|
||||
openWithDefaultApp(filepath: string): Promise<void>;
|
||||
saveAttachment(fileName: string, fileExtension: string, fileData: ArrayBuffer): Promise<TFile>;
|
||||
}
|
||||
|
||||
interface Vault {
|
||||
getConfig(configName: string): unknown;
|
||||
getAvailablePathForAttachments(fileName: string, extension: string, currentFile: TFile | null): Promise<string>;
|
||||
onChange(eventType: string, filePath: string, oldPath?: string, stat?: FileStats): void;
|
||||
}
|
||||
interface Vault {
|
||||
getConfig(configName: string): unknown;
|
||||
getAvailablePathForAttachments(fileName: string, extension: string, currentFile: TFile | null): Promise<string>;
|
||||
onChange(eventType: string, filePath: string, oldPath?: string, stat?: FileStats): void;
|
||||
}
|
||||
|
||||
interface MenuItem {
|
||||
dom: HTMLElement;
|
||||
callback: () => void;
|
||||
}
|
||||
interface MenuItem {
|
||||
dom: HTMLElement;
|
||||
callback: () => void;
|
||||
}
|
||||
|
||||
interface Menu {
|
||||
items: MenuItem[];
|
||||
}
|
||||
interface Menu {
|
||||
items: MenuItem[];
|
||||
}
|
||||
|
||||
interface FileManager {
|
||||
promptForDeletion(file: TAbstractFile): Promise<void>;
|
||||
}
|
||||
interface FileManager {
|
||||
promptForDeletion(file: TAbstractFile): Promise<void>;
|
||||
}
|
||||
|
||||
interface Editor {
|
||||
cm: EditorView;
|
||||
}
|
||||
|
||||
interface FileExplorerItem {
|
||||
el: HTMLDivElement;
|
||||
selfEl: HTMLDivElement;
|
||||
innerEl: HTMLDivElement;
|
||||
coverEl: HTMLDivElement;
|
||||
childrenEl: HTMLDivElement;
|
||||
collapseEl: HTMLDivElement;
|
||||
collapsed: boolean;
|
||||
collapsible: boolean;
|
||||
file: TFile;
|
||||
}
|
||||
|
||||
interface Editor {
|
||||
cm: EditorView;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,15 +1,7 @@
|
|||
.import-plugin-hidden {
|
||||
height: 0;
|
||||
overflow: hidden;
|
||||
.nav-files-container:not(.import-plugin-hidden) .import-plugin-hidden {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/*
|
||||
.nav-files-container:not(.show-unsupported) .is-unsupported {
|
||||
text-color: red;
|
||||
display: block !important;
|
||||
}
|
||||
*/
|
||||
|
||||
.import-plugin table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
|
|
|
|||
Loading…
Reference in a new issue