#145 - refactored the plugin integration point and sorting function invocation and wrapper(s) to work under Obsidian 1.6.0 (which introduced significant refactoring)

Remains to do:
- polish the code to remove duplication in main.js
- full testing under 1.6.0
- regression tests under latest 1.5.x (the code is backward compatible)
This commit is contained in:
SebastianMC 2024-05-13 20:14:03 +02:00
parent f5c64845ba
commit 4ab21d6ff5
2 changed files with 109 additions and 58 deletions

View File

@ -702,21 +702,45 @@ export const determineBookmarksOrderIfNeeded = (folderItems: Array<FolderItemFor
}) })
} }
export const folderSort = function (sortingSpec: CustomSortSpec, ctx: ProcessingContext) { // This function is a replacement for the Obsidian File Explorer function sort(...) up to Obsidian 1.6.0
// when a major refactoring of sorting mechanics happened
export const folderSort_vUpTo_1_6_0 = function (sortingSpec: CustomSortSpec, ctx: ProcessingContext) {
let fileExplorerView = this.fileExplorer ?? this.view // this.view replaces the former since 1.5.4 insider build const fileExplorerView = this.fileExplorer ?? this.view // this.view replaces the former since 1.5.4 insider build
const folderUnderSort = this.file as TFolder
const sortOrder = this.sortOrder
const allFileItemsCollection = fileExplorerView.fileItems
const items = folderSortCore(folderUnderSort, sortOrder, sortingSpec, allFileItemsCollection, ctx)
if (requireApiVersion && requireApiVersion("0.15.0")) {
this.vChildren.setChildren(items);
} else {
this.children = items;
}
}
// This function is a replacement for the Obsidian File Explorer function getSortedFolderItems(...)
// which first appeared in Obsidian 1.6.0 and simplified a bit the plugin integration point
export const getSortedFolderItems_vFrom_1_6_0 = function (sortedFolder: TFolder, sortingSpec: CustomSortSpec, ctx: ProcessingContext) {
const sortOrder = this.sortOrder
const allFileItemsCollection = this.fileItems
return folderSortCore(sortedFolder, sortOrder, sortingSpec, allFileItemsCollection, ctx)
}
const folderSortCore = function (sortedFolder: TFolder, sortOrder: string, sortingSpec: CustomSortSpec, allFileItemsCollection: any, ctx: ProcessingContext) {
// shallow copy of groups and expand folder-specific macros on them // shallow copy of groups and expand folder-specific macros on them
sortingSpec.groupsShadow = sortingSpec.groups?.map((group) => Object.assign({} as CustomSortGroup, group)) sortingSpec.groupsShadow = sortingSpec.groups?.map((group) => Object.assign({} as CustomSortGroup, group))
const parentFolderName: string|undefined = this.file.name const parentFolderName: string|undefined = sortedFolder.name
expandMacros(sortingSpec, parentFolderName) expandMacros(sortingSpec, parentFolderName)
const folderItems: Array<FolderItemForSorting> = (sortingSpec.itemsToHide ? const folderItems: Array<FolderItemForSorting> = (sortingSpec.itemsToHide ?
this.file.children.filter((entry: TFile | TFolder) => { sortedFolder.children.filter((entry: TFile | TFolder) => {
return !sortingSpec.itemsToHide!.has(entry.name) return !sortingSpec.itemsToHide!.has(entry.name)
}) })
: :
this.file.children) sortedFolder.children)
.map((entry: TFile | TFolder) => { .map((entry: TFile | TFolder) => {
const itemForSorting: FolderItemForSorting = determineSortingGroup(entry, sortingSpec, ctx) const itemForSorting: FolderItemForSorting = determineSortingGroup(entry, sortingSpec, ctx)
return itemForSorting return itemForSorting
@ -729,23 +753,14 @@ export const folderSort = function (sortingSpec: CustomSortSpec, ctx: Processing
determineBookmarksOrderIfNeeded(folderItems, sortingSpec, ctx.bookmarksPluginInstance) determineBookmarksOrderIfNeeded(folderItems, sortingSpec, ctx.bookmarksPluginInstance)
} }
const comparator: SorterFn = getComparator(sortingSpec, fileExplorerView.sortOrder) const comparator: SorterFn = getComparator(sortingSpec, sortOrder)
folderItems.sort(comparator) folderItems.sort(comparator)
const items = folderItems const items = folderItems
.map((item: FolderItemForSorting) => fileExplorerView.fileItems[item.path]) .map((item: FolderItemForSorting) => allFileItemsCollection[item.path])
if (requireApiVersion && requireApiVersion("0.16.0")) { return items
const scrollTop = fileExplorerView.navFileContainerEl.scrollTop
fileExplorerView.tree.infinityScroll.rootEl.vChildren.setChildren([items])
fileExplorerView.navFileContainerEl.scrollTop = scrollTop
fileExplorerView.tree.infinityScroll.compute()
} else if (requireApiVersion && requireApiVersion("0.15.0")) {
this.vChildren.setChildren(items);
} else {
this.children = items;
}
}; };
// Returns a sorted copy of the input array, intentionally to keep it intact // Returns a sorted copy of the input array, intentionally to keep it intact

View File

@ -21,7 +21,8 @@ import {
} from 'obsidian'; } from 'obsidian';
import {around} from 'monkey-around'; import {around} from 'monkey-around';
import { import {
folderSort, folderSort_vUpTo_1_6_0,
getSortedFolderItems_vFrom_1_6_0,
ObsidianStandardDefaultSortingName, ObsidianStandardDefaultSortingName,
ProcessingContext, ProcessingContext,
sortFolderItemsForBookmarking sortFolderItemsForBookmarking
@ -593,51 +594,86 @@ export default class CustomSortPlugin extends Plugin {
// That's why not showing and not logging error message here // That's why not showing and not logging error message here
patchableFileExplorer = patchableFileExplorer ?? this.checkFileExplorerIsAvailableAndPatchable(false) patchableFileExplorer = patchableFileExplorer ?? this.checkFileExplorerIsAvailableAndPatchable(false)
if (patchableFileExplorer) { if (patchableFileExplorer) {
// @ts-ignore if (requireApiVersion && requireApiVersion("1.6.0")) {
let tmpFolder = new TFolder(Vault, ""); // Starting from Obsidian 1.6.0 the sorting mechanics has been significantly refactored internally in Obsidian
let Folder = patchableFileExplorer.createFolderDom(tmpFolder).constructor; const uninstallerOfFolderSortFunctionWrapper: MonkeyAroundUninstaller = around(patchableFileExplorer.constructor.prototype, {
const uninstallerOfFolderSortFunctionWrapper: MonkeyAroundUninstaller = around(Folder.prototype, { getSortedFolderItems(old: any) {
sort(old: any) { return function (...args: any[]) {
return function (...args: any[]) { // quick check for plugin status
// quick check for plugin status if (plugin.settings.suspended) {
if (plugin.settings.suspended) { return old.call(this, ...args);
return old.call(this, ...args); }
}
if (plugin.ribbonIconStateInaccurate && plugin.ribbonIconEl) { if (plugin.ribbonIconStateInaccurate && plugin.ribbonIconEl) {
plugin.ribbonIconStateInaccurate = false plugin.ribbonIconStateInaccurate = false
setIcon(plugin.ribbonIconEl, ICON_SORT_ENABLED_ACTIVE) setIcon(plugin.ribbonIconEl, ICON_SORT_ENABLED_ACTIVE)
} }
const folder: TFolder = this.file const folder = args[0]
let sortSpec: CustomSortSpec | null | undefined = plugin.determineSortSpecForFolder(folder.path, folder.name) let sortSpec: CustomSortSpec | null | undefined = plugin.determineSortSpecForFolder(folder.path, folder.name)
// Performance optimization // Performance optimization
// Primary intention: when the implicit bookmarks integration is enabled, remain on std Obsidian, if no need to involve bookmarks // Primary intention: when the implicit bookmarks integration is enabled, remain on std Obsidian, if no need to involve bookmarks
let has: HasSortingOrGrouping = collectSortingAndGroupingTypes(sortSpec) let has: HasSortingOrGrouping = collectSortingAndGroupingTypes(sortSpec)
if (hasOnlyByBookmarkOrStandardObsidian(has)) { if (hasOnlyByBookmarkOrStandardObsidian(has)) {
const bookmarksPlugin: BookmarksPluginInterface|undefined = getBookmarksPlugin(plugin.app, plugin.settings.bookmarksGroupToConsumeAsOrderingReference, false, true) const bookmarksPlugin: BookmarksPluginInterface|undefined = getBookmarksPlugin(plugin.app, plugin.settings.bookmarksGroupToConsumeAsOrderingReference, false, true)
if ( !bookmarksPlugin?.bookmarksIncludeItemsInFolder(folder.path)) { if ( !bookmarksPlugin?.bookmarksIncludeItemsInFolder(folder.path)) {
sortSpec = null sortSpec = null
}
}
if (sortSpec) {
return getSortedFolderItems_vFrom_1_6_0.call(this, folder, sortSpec, plugin.createProcessingContextForSorting(has))
} else {
return old.call(this, ...args);
}
};
}
})
this.register(uninstallerOfFolderSortFunctionWrapper)
return true
} else {
// Up to Obsidian 1.6.0
// @ts-ignore
let tmpFolder = new TFolder(Vault, "");
let Folder = patchableFileExplorer.createFolderDom(tmpFolder).constructor;
const uninstallerOfFolderSortFunctionWrapper: MonkeyAroundUninstaller = around(Folder.prototype, {
sort(old: any) {
return function (...args: any[]) {
// quick check for plugin status
if (plugin.settings.suspended) {
return old.call(this, ...args);
} }
}
if (sortSpec) { if (plugin.ribbonIconStateInaccurate && plugin.ribbonIconEl) {
return folderSort.call(this, sortSpec, plugin.createProcessingContextForSorting(has)); plugin.ribbonIconStateInaccurate = false
} else { setIcon(plugin.ribbonIconEl, ICON_SORT_ENABLED_ACTIVE)
return old.call(this, ...args); }
}
}; const folder: TFolder = this.file
},*/ let sortSpec: CustomSortSpec | null | undefined = plugin.determineSortSpecForFolder(folder.path, folder.name)
getSortedFolderItems(old: any) {
return function (...args: any[]) { // Performance optimization
console.log(`Cuda cuda ${args?.length}`) // Primary intention: when the implicit bookmarks integration is enabled, remain on std Obsidian, if no need to involve bookmarks
return old.call(this, ...args); let has: HasSortingOrGrouping = collectSortingAndGroupingTypes(sortSpec)
}; if (hasOnlyByBookmarkOrStandardObsidian(has)) {
} const bookmarksPlugin: BookmarksPluginInterface | undefined = getBookmarksPlugin(plugin.app, plugin.settings.bookmarksGroupToConsumeAsOrderingReference, false, true)
}) if (!bookmarksPlugin?.bookmarksIncludeItemsInFolder(folder.path)) {
this.register(uninstallerOfFolderSortFunctionWrapper) sortSpec = null
return true }
}
if (sortSpec) {
return folderSort_vUpTo_1_6_0.call(this, sortSpec, plugin.createProcessingContextForSorting(has));
} else {
return old.call(this, ...args);
}
};
}
})
this.register(uninstallerOfFolderSortFunctionWrapper)
return true
}
} else { } else {
return false return false
} }