From 98fc482e782b51dd8c602a796526d0bc0f01a38e Mon Sep 17 00:00:00 2001 From: wz <44930227+wenlzhang@users.noreply.github.com> Date: Sat, 5 Apr 2025 11:41:46 +0200 Subject: [PATCH] Improve code quality --- src/folderSuggestModal.ts | 325 +++++++++++++++++++++----------------- 1 file changed, 176 insertions(+), 149 deletions(-) diff --git a/src/folderSuggestModal.ts b/src/folderSuggestModal.ts index 69d88f4..c55d95c 100644 --- a/src/folderSuggestModal.ts +++ b/src/folderSuggestModal.ts @@ -1,6 +1,21 @@ import { App, FuzzySuggestModal, TFolder, WorkspaceLeaf, View } from "obsidian"; import type FolderNavigatorPlugin from "./main"; +// Debug mode flag - set to false for production +const DEBUG_MODE = false; + +// Helper function for conditional logging +function log(message: string, ...args: any[]): void { + if (DEBUG_MODE) { + console.log(message, ...args); + } +} + +// Helper function for error logging (always show errors) +function logError(message: string, ...args: any[]): void { + console.error(message, ...args); +} + interface FileExplorerView extends View { fileItems: Record; } @@ -47,51 +62,63 @@ export class FolderSuggestModal extends FuzzySuggestModal { return folder.path; } + /** + * Escapes a path for use in CSS selectors + */ private escapePath(path: string): string { return CSS.escape(path); } + /** + * Find a folder element in the DOM using multiple strategies + */ + private findFolderElementInDOM(path: string): HTMLElement | null { + const escapedPath = this.escapePath(path); + + // Try common selectors first + const selectors = [ + `.nav-folder-title[data-path="${escapedPath}"]`, + `.nav-file-title[data-path="${escapedPath}"]`, + `[data-path="${escapedPath}"]` + ]; + + // Try each selector + for (const selector of selectors) { + const el = document.querySelector(selector); + if (el instanceof HTMLElement) { + log("Found folder element using selector:", selector); + return el; + } + } + + // Try to find by partial path matches if exact match failed + const allElements = document.querySelectorAll('[data-path]'); + for (const el of Array.from(allElements)) { + const elPath = el.getAttribute('data-path'); + if (elPath && (elPath === path || path.endsWith(elPath) || elPath.endsWith(path))) { + log("Found folder by partial path match:", elPath); + return el as HTMLElement; + } + } + + // If in debug mode, provide more details about what was found + if (DEBUG_MODE) { + const samplePaths = Array.from(allElements).slice(0, 5) + .map(el => el.getAttribute('data-path')); + log("Sample paths in DOM:", samplePaths); + } + + return null; + } + + /** + * Try to expand a folder using DOM manipulation as a fallback + */ private tryToExpandFolderViaDOM(path: string): void { setTimeout(() => { - console.log("Trying to expand folder via DOM:", path); - const escapedPath = this.escapePath(path); + log("Trying to expand folder via DOM:", path); - const selectors = [ - `.nav-folder-title[data-path="${escapedPath}"]`, - `.nav-file-title[data-path="${escapedPath}"]`, - `[data-path="${escapedPath}"]` - ]; - - let folderElement: HTMLElement | null = null; - - for (const selector of selectors) { - const el = document.querySelector(selector); - if (el instanceof HTMLElement) { - folderElement = el; - console.log("Found folder element using selector:", selector); - break; - } - } - - if (!folderElement) { - console.log("Folder element not found in DOM via direct selectors, trying alternative approach"); - - const allElements = document.querySelectorAll('[data-path]'); - console.log("Total elements with data-path:", allElements.length); - - const samplePaths = Array.from(allElements).slice(0, 5) - .map(el => el.getAttribute('data-path')); - console.log("Sample paths in DOM:", samplePaths); - - for (const el of Array.from(allElements)) { - const elPath = el.getAttribute('data-path'); - if (elPath && (elPath === path || path.endsWith(elPath) || elPath.endsWith(path))) { - folderElement = el as HTMLElement; - console.log("Found folder by partial path match:", elPath); - break; - } - } - } + const folderElement = this.findFolderElementInDOM(path); if (folderElement) { const collapseIndicator = folderElement.querySelector('.nav-folder-collapse-indicator'); @@ -101,147 +128,147 @@ export class FolderSuggestModal extends FuzzySuggestModal { collapseIndicator.classList.contains('is-collapsed'); if (isCollapsed) { - console.log("Clicking collapse indicator to expand folder"); + log("Clicking collapse indicator to expand folder"); collapseIndicator.click(); } else { - console.log("Folder already appears to be expanded"); + log("Folder already appears to be expanded"); } } else { - console.log("No collapse indicator found, might not be expandable"); + log("No collapse indicator found, might not be expandable"); } } else { - console.log("Could not find folder element in DOM:", path); + log("Could not find folder element in DOM:", path); } }, 100); } - onChooseItem(folder: TFolder): void { - console.log("Folder selected:", folder.path); + /** + * Apply visual highlighting to a folder + */ + private highlightFolder(folder: TFolder): void { + setTimeout(() => { + log("Looking for folder to highlight:", folder.path); + + const folderElement = this.findFolderElementInDOM(folder.path); + + if (folderElement) { + // Scroll into view + log("Scrolling folder into view"); + folderElement.scrollIntoView({ + behavior: "smooth", + block: "center", + }); + + // Add highlight class + log("Adding highlight class"); + folderElement.classList.add("nav-folder-title-highlighted"); + + // Remove after delay + setTimeout(() => { + if (folderElement) { + folderElement.classList.remove("nav-folder-title-highlighted"); + } + }, 2000); + } else { + logError("Could not find folder element to highlight"); + } + }, 300); + } + + /** + * Get the file explorer instance from Obsidian's internal APIs + */ + private getFileExplorer(): FileExplorerInstance | null { + try { + const app = this.app as ExtendedApp; + if (!app.internalPlugins?.plugins["file-explorer"]?.instance) { + logError("Could not find file explorer plugin instance"); + return null; + } + + const fileExplorer = app.internalPlugins.plugins["file-explorer"].instance; + + if (typeof fileExplorer.revealInFolder !== 'function') { + logError("revealInFolder method not found on file explorer instance"); + return null; + } + + return fileExplorer; + } catch (error) { + logError("Error accessing file explorer:", error); + return null; + } + } + + /** + * Expand all parent folders of the target folder + */ + private expandParentFolders(folder: TFolder, fileExplorer: FileExplorerInstance): void { + if (!folder.parent || !folder.parent.path) return; + log("Processing parent folders for:", folder.parent.path); + + const pathParts = folder.parent.path.split("/"); + let currentPath = ""; + + // Process each parent path + for (const part of pathParts) { + if (part) { + currentPath += (currentPath ? "/" : "") + part; + log("Processing parent path:", currentPath); + + const parentFolder = this.app.vault.getAbstractFileByPath(currentPath); + if (parentFolder instanceof TFolder) { + // Reveal in file explorer using the API + log("Revealing parent folder:", parentFolder.path); + fileExplorer.revealInFolder(parentFolder); + + // Try to expand it using DOM as a fallback + this.tryToExpandFolderViaDOM(parentFolder.path); + } + } + } + } + + onChooseItem(folder: TFolder): void { + log("Folder selected:", folder.path); + + // Get and activate file explorer leaf const fileExplorerLeaves = this.app.workspace.getLeavesOfType("file-explorer"); - console.log("File explorer leaves found:", fileExplorerLeaves.length); + log("File explorer leaves found:", fileExplorerLeaves.length); if (fileExplorerLeaves.length === 0) { - console.error("No file explorer leaf found"); + logError("No file explorer leaf found"); return; } const fileExplorerLeaf = fileExplorerLeaves[0]; - this.app.workspace.revealLeaf(fileExplorerLeaf); - console.log("File explorer leaf revealed"); + log("File explorer leaf revealed"); + + // Get file explorer and process folder + const fileExplorer = this.getFileExplorer(); + if (!fileExplorer) return; try { - const app = this.app as ExtendedApp; - if (!app.internalPlugins?.plugins["file-explorer"]?.instance) { - console.error("Could not find file explorer plugin instance"); - return; - } + // Expand parent folders first + this.expandParentFolders(folder, fileExplorer); - const fileExplorer = app.internalPlugins.plugins["file-explorer"].instance; - console.log("File explorer methods:", - Object.getOwnPropertyNames(Object.getPrototypeOf(fileExplorer)) - .filter(m => typeof (fileExplorer as any)[m] === 'function')); - - if (typeof fileExplorer.revealInFolder !== 'function') { - console.error("revealInFolder method not found"); - return; - } - - if (folder.parent && folder.parent.path) { - console.log("Processing parent folders for:", folder.parent.path); - - const pathParts = folder.parent.path.split("/"); - let currentPath = ""; - - for (const part of pathParts) { - if (part) { - currentPath += (currentPath ? "/" : "") + part; - console.log("Processing parent path:", currentPath); - - const parentFolder = this.app.vault.getAbstractFileByPath(currentPath); - if (parentFolder instanceof TFolder) { - console.log("Revealing parent folder:", parentFolder.path); - fileExplorer.revealInFolder(parentFolder); - - this.tryToExpandFolderViaDOM(parentFolder.path); - } - } - } - } - - console.log("Revealing target folder:", folder.path); + // Reveal the target folder + log("Revealing target folder:", folder.path); fileExplorer.revealInFolder(folder); + // Expand target folder if setting is enabled if (this.plugin.settings.expandTargetFolder && folder instanceof TFolder) { - console.log("Attempting to expand target folder:", folder.path); + log("Attempting to expand target folder:", folder.path); this.tryToExpandFolderViaDOM(folder.path); } - setTimeout(() => { - console.log("Looking for folder to highlight:", folder.path); - - const escapedPath = this.escapePath(folder.path); - - const selectors = [ - `.nav-folder-title[data-path="${escapedPath}"]`, - `.nav-file-title[data-path="${escapedPath}"]`, - `[data-path="${escapedPath}"]` - ]; - - let folderElement: HTMLElement | null = null; - - for (const selector of selectors) { - const el = document.querySelector(selector); - if (el instanceof HTMLElement) { - folderElement = el; - console.log("Found folder element for highlighting using selector:", selector); - break; - } - } - - if (!folderElement) { - console.log("Trying broader approach to find folder element"); - - const allElements = document.querySelectorAll('[data-path]'); - for (const el of Array.from(allElements)) { - const elPath = el.getAttribute('data-path'); - if (elPath && (elPath === folder.path || folder.path.endsWith(elPath))) { - folderElement = el as HTMLElement; - console.log("Found folder by partial match:", elPath); - break; - } - } - - if (!folderElement) { - const pathSamples = Array.from(allElements).slice(0, 10) - .map(el => el.getAttribute('data-path')); - console.log("Sample data-path values:", pathSamples); - } - } - - if (folderElement) { - console.log("Scrolling folder into view"); - folderElement.scrollIntoView({ - behavior: "smooth", - block: "center", - }); - - console.log("Adding highlight class"); - folderElement.classList.add("nav-folder-title-highlighted"); - - setTimeout(() => { - if (folderElement) { - folderElement.classList.remove("nav-folder-title-highlighted"); - } - }, 2000); - } else { - console.error("Could not find folder element to highlight"); - } - }, 300); + // Highlight the folder + this.highlightFolder(folder); } catch (error) { - console.error("Error in folder navigation:", error); + logError("Error in folder navigation:", error); } } }