Merge pull request #203 from SebastianMC/202-improve-automatic-initial-application-of-custom-sorting-for-obsidian-deferred-views

202 improve automatic initial application of custom sorting for obsidian deferred views
This commit is contained in:
SebastianMC 2025-04-22 23:47:51 +02:00 committed by GitHub
commit 5bb04f41a1
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
1 changed files with 76 additions and 11 deletions

View File

@ -78,11 +78,16 @@ type MonkeyAroundUninstaller = () => void
type ContextMenuProvider = (item: MenuItem) => void
enum FileExplorerStateError {
DoesNotExist,
enum FileExplorerState {
DoesNotExist = 1,
DeferredView
}
interface FileExplorerStateError {
state: FileExplorerState
fileExplorerInDeferredState?: FileExplorerLeaf
}
type FileExplorerLeafOrError = ValueOrError<FileExplorerLeaf,FileExplorerStateError>
export default class CustomSortPlugin
@ -188,20 +193,25 @@ export default class CustomSortPlugin
if (fileExplorer) {
if (fileExplorer.isDeferred) {
return fileExplorerOrError.setError(FileExplorerStateError.DeferredView)
return fileExplorerOrError.setError({
state: FileExplorerState.DeferredView,
fileExplorerInDeferredState: fileExplorer
})
} else {
return fileExplorerOrError.setValue(fileExplorer)
}
} else {
return fileExplorerOrError.setError(FileExplorerStateError.DoesNotExist)
return fileExplorerOrError.setError({
state: FileExplorerState.DoesNotExist
})
}
}
checkFileExplorerIsAvailableAndPatchable(logWarning: boolean = true): FileExplorerLeafOrError {
let fileExplorerOrError = this.getFileExplorer()
if (fileExplorerOrError.e === FileExplorerStateError.DeferredView) {
if (fileExplorerOrError.e && fileExplorerOrError.e.state === FileExplorerState.DeferredView) {
if (logWarning) {
this.logWarningFileExplorerDeferred()
this.logDeferredFileExplorerInfo()
}
return fileExplorerOrError
}
@ -269,12 +279,17 @@ export default class CustomSortPlugin
}
}
logWarningFileExplorerDeferred() {
const msg = `${PLUGIN_ID} v${this.manifest.version}: failed to get active File Explorer view.\n`
logDeferredFileExplorerInfo() {
const msg = `${PLUGIN_ID} v${this.manifest.version}: File Explorer is not displayed yet (Obsidian deferred view detected).\n`
+ `Until the File Explorer is visible, the custom-sort plugin cannot apply the custom order.\n`
console.warn(msg)
}
logDeferredFileExplorerWatcherSetupInfo() {
const msg = `${PLUGIN_ID} v${this.manifest.version}: A watcher was set up to apply custom sort automatically when the File Explorer is displayed.\n`
console.warn(msg)
}
logWarningFileExplorerNotAvailable() {
const msg = `${PLUGIN_ID} v${this.manifest.version}: failed to locate File Explorer. The 'Files' core plugin can be disabled.\n`
+ `Some community plugins can also disable it.\n`
@ -583,7 +598,7 @@ export default class CustomSortPlugin
const plugin = this
this.app.workspace.onLayoutReady(() => {
setTimeout(() => {
plugin.initialDelayedApplicationOfCustomSorting.apply(this)
plugin.delayedApplicationOfCustomSorting.apply(this)
},
plugin.settings.delayForInitialApplication)
})
@ -682,7 +697,39 @@ export default class CustomSortPlugin
return false
}
initialDelayedApplicationOfCustomSorting() {
setWatcherForDelayedFileExplorerView(fileExplorerInDeferredState?: FileExplorerLeaf) {
const self = this
let workspaceLeafContentElementParentToObserve: HTMLElement|Element|null|undefined = fileExplorerInDeferredState?.view?.containerEl?.parentElement
if (!workspaceLeafContentElementParentToObserve) {
// Fallback for the case when DOM is not available for deferred file explorer
// (did not happen in practice, but just in case)
workspaceLeafContentElementParentToObserve = document.querySelector(".workspace");
}
if (workspaceLeafContentElementParentToObserve) {
const fullyFledgedFileExplorerElementSelector=
() => workspaceLeafContentElementParentToObserve.querySelector('[data-type="file-explorer"] .nav-files-container');
const mutationObserver = new MutationObserver((_, observerInstance) => {
const fullyFledgedFileExplorerElement = fullyFledgedFileExplorerElementSelector();
if (fullyFledgedFileExplorerElement) {
observerInstance.disconnect();
self.delayedApplicationOfCustomSorting(self.FROM_DOM_WATCHER)
}
});
mutationObserver.observe(workspaceLeafContentElementParentToObserve, {
childList: true,
subtree: false
});
}
}
// Entering this method for the first time after initial delay after plugin loaded (via setTimeout()),
// and if first attempt is unsuccessful, then entering this method again from DOM watcher, when
// the File Explorer view gets transformed from delayed view into fully-fledged active view
FROM_DOM_WATCHER: boolean = true
delayedApplicationOfCustomSorting(fromDOMwatcher?: boolean) {
if (!this?.isThePluginStillInstalledAndEnabled()) {
console.log(`${PLUGIN_ID} v${this.manifest.version} - delayed handler skipped, plugin no longer active.`)
return
@ -695,8 +742,26 @@ export default class CustomSortPlugin
return
}
if (!fromDOMwatcher) {
// Only for the first delayed invocation:
// If file explorer is delayed, configure the watcher
// NOTE: Do not configure the watcher if the file explorer is not available
let fileExplorerOrError: FileExplorerLeafOrError = this.checkFileExplorerIsAvailableAndPatchable()
if (fileExplorerOrError.e && fileExplorerOrError.e.state === FileExplorerState.DeferredView) {
this.logDeferredFileExplorerWatcherSetupInfo()
this.setWatcherForDelayedFileExplorerView(fileExplorerOrError.e.fileExplorerInDeferredState)
} else if (fileExplorerOrError.e) {
// file explorer other error - does not exist
// force the plugin switch state to report error and show the error icon
this.switchPluginStateTo(true)
}
else { // file explorer is available
this.switchPluginStateTo(true)
}
} else {
this.switchPluginStateTo(true)
}
}
setRibbonIconToEnabled() {
setIcon(this.ribbonIconEl, ICON_SORT_ENABLED_ACTIVE)