#74 - Integration with Bookmarks core plugin and support for indirect drag & drop arrangement

- advanced performance optimizations: bookmarks cache finetuning, switching to Obsidian sort code if the implicit bookmark-integration sorting spec is in effect for a folder and there are no bookmarked items in the folder
- unit tests for some of newly introduced functions
This commit is contained in:
SebastianMC 2023-10-04 13:19:19 +02:00
parent a4a6c93412
commit daf657721c
5 changed files with 347 additions and 29 deletions

View File

@ -0,0 +1,187 @@
import {
CustomSortGroupType,
CustomSortOrder,
CustomSortSpec
} from "./custom-sort-types";
import {
collectSortingAndGroupingTypes,
hasOnlyByBookmarkOrStandardObsidian,
HasSortingOrGrouping,
ImplicitSortspecForBookmarksIntegration
} from "./custom-sort-utils";
import {SortingSpecProcessor, SortSpecsCollection} from "./sorting-spec-processor";
type NM = number
const getHas = (gTotal?: NM, gBkmrk?: NM, gStar?: NM, gIcon?: NM, sTot?: NM, sBkmrk?: NM, sStd?: NM) => {
const has: HasSortingOrGrouping = {
grouping: {
total: gTotal ||0,
byBookmarks: gBkmrk ||0,
byStarred: gStar ||0,
byIcon: gIcon ||0
},
sorting: {
total: sTot ||0,
byBookmarks: sBkmrk ||0,
standardObsidian: sStd ||0
}
}
return has
}
describe('hasOnlyByBookmarkOrStandardObsidian and collectSortingAndGroupingTypes', () => {
it('should handle empty spec correctly', () => {
const spec: Partial<CustomSortSpec>|undefined|null = undefined
const expectedHas: HasSortingOrGrouping = getHas()
const has = collectSortingAndGroupingTypes(spec)
const hasOnly = hasOnlyByBookmarkOrStandardObsidian(has)
expect(has).toEqual(expectedHas)
expect(hasOnly).toBeTruthy()
})
it('should handle empty spec correctly (null variant)', () => {
const spec: Partial<CustomSortSpec>|undefined|null = null
const expectedHas: HasSortingOrGrouping = getHas()
const has = collectSortingAndGroupingTypes(spec)
const hasOnly = hasOnlyByBookmarkOrStandardObsidian(has)
expect(hasOnly).toBeTruthy()
expect(has).toEqual(expectedHas)
})
it('should handle spec with empty orders correctly', () => {
const spec: Partial<CustomSortSpec>|undefined = {
groups: [
{type: CustomSortGroupType.Outsiders, filesOnly: true},
{type: CustomSortGroupType.Outsiders}
]
}
const expectedHas: HasSortingOrGrouping = getHas()
const has = collectSortingAndGroupingTypes(spec as CustomSortSpec)
const hasOnly = hasOnlyByBookmarkOrStandardObsidian(has)
expect(hasOnly).toBeTruthy()
expect(has).toEqual(expectedHas)
})
it('should detect not matching default order', () => {
const spec: Partial<CustomSortSpec>|undefined = {
defaultOrder: CustomSortOrder.default,
groups: [
{
type: CustomSortGroupType.ExactName,
},
{
type: CustomSortGroupType.Outsiders,
}
]
}
const expectedHas: HasSortingOrGrouping = getHas(1, 0, 0, 0, 1, 0, 0)
const has = collectSortingAndGroupingTypes(spec as CustomSortSpec)
const hasOnly = hasOnlyByBookmarkOrStandardObsidian(has)
expect(hasOnly).toBeFalsy()
expect(has).toEqual(expectedHas)
})
it('should detect not matching default secondary order', () => {
const spec: Partial<CustomSortSpec>|undefined = {
defaultOrder: CustomSortOrder.byBookmarkOrder,
defaultSecondaryOrder: CustomSortOrder.default,
groups: [
{
type: CustomSortGroupType.BookmarkedOnly,
},
{
type: CustomSortGroupType.Outsiders,
}
]
}
const expectedHas: HasSortingOrGrouping = getHas(1, 1, 0, 0, 2, 1, 0)
const has = collectSortingAndGroupingTypes(spec as CustomSortSpec)
const hasOnly = hasOnlyByBookmarkOrStandardObsidian(has)
expect(hasOnly).toBeFalsy()
expect(has).toEqual(expectedHas)
})
it('should detect not matching order in group', () => {
const spec: Partial<CustomSortSpec>|undefined = {
defaultOrder: CustomSortOrder.byBookmarkOrder,
defaultSecondaryOrder: CustomSortOrder.standardObsidian,
groups: [
{
type: CustomSortGroupType.ExactName,
order: CustomSortOrder.byCreatedTimeReverse
},
{
type: CustomSortGroupType.Outsiders,
}
]
}
const expectedHas: HasSortingOrGrouping = getHas(1, 0, 0, 0, 3, 1, 1)
const has = collectSortingAndGroupingTypes(spec as CustomSortSpec)
const hasOnly = hasOnlyByBookmarkOrStandardObsidian(has)
expect(hasOnly).toBeFalsy()
expect(has).toEqual(expectedHas)
})
it('should detect not matching secondary order in group', () => {
const spec: Partial<CustomSortSpec>|undefined = {
defaultOrder: CustomSortOrder.byBookmarkOrder,
defaultSecondaryOrder: CustomSortOrder.standardObsidian,
groups: [
{
type: CustomSortGroupType.ExactName,
order: CustomSortOrder.byBookmarkOrderReverse,
secondaryOrder: CustomSortOrder.standardObsidian
},
{
type: CustomSortGroupType.Outsiders,
order: CustomSortOrder.byBookmarkOrder,
secondaryOrder: CustomSortOrder.alphabetical
}
]
}
const expectedHas: HasSortingOrGrouping = getHas(1, 0, 0, 0, 6, 3, 2)
const has = collectSortingAndGroupingTypes(spec as CustomSortSpec)
const hasOnly = hasOnlyByBookmarkOrStandardObsidian(has)
expect(hasOnly).toBeFalsy()
expect(has).toEqual(expectedHas)
})
it('should detect matching orders at all levels', () => {
const spec: Partial<CustomSortSpec>|undefined = {
defaultOrder: CustomSortOrder.byBookmarkOrder,
defaultSecondaryOrder: CustomSortOrder.standardObsidian,
groups: [
{
type: CustomSortGroupType.BookmarkedOnly,
order: CustomSortOrder.byBookmarkOrderReverse,
secondaryOrder: CustomSortOrder.standardObsidian
},
{
type: CustomSortGroupType.Outsiders,
order: CustomSortOrder.byBookmarkOrder,
secondaryOrder: CustomSortOrder.byBookmarkOrderReverse
}
]
}
const expectedHas: HasSortingOrGrouping = getHas(1, 1, 0, 0, 6, 4, 2)
const has = collectSortingAndGroupingTypes(spec as CustomSortSpec)
const hasOnly = hasOnlyByBookmarkOrStandardObsidian(has)
expect(hasOnly).toBeTruthy()
expect(has).toEqual(expectedHas)
})
})
describe('ImplicitSortspecForBookmarksIntegration', () => {
it('should correctly be recognized as only bookmark and obsidian standard', () => {
const processor: SortingSpecProcessor = new SortingSpecProcessor();
const inputTxtArr: Array<string> = ImplicitSortspecForBookmarksIntegration.replace(/\t/gi, '').split('\n')
const spec: SortSpecsCollection|null|undefined = processor.parseSortSpecFromText(
inputTxtArr,
'mock-folder',
'custom-name-note.md',
null,
true
)
const expectedHas: HasSortingOrGrouping = getHas(1, 1, 0, 0, 2, 1, 1)
const has = collectSortingAndGroupingTypes(spec?.sortSpecByPath!['/'])
const hasOnly = hasOnlyByBookmarkOrStandardObsidian(has)
expect(hasOnly).toBeTruthy()
expect(has).toEqual(expectedHas)
})
})
// TODO - czy tamto sprawdzanie dla itemów w rootowym filderze hasBookmarkInFolder dobrze zadziala

View File

@ -0,0 +1,80 @@
import {CustomSortGroupType, CustomSortOrder, CustomSortSpec} from "./custom-sort-types";
// Put here to allow unit tests coverage of this specific implicit sorting spec
export const ImplicitSortspecForBookmarksIntegration: string = `
target-folder: /*
bookmarked:
< by-bookmarks-order
sorting: standard
`
export interface HasSortingTypes {
byBookmarks: number
standardObsidian: number
total: number
}
export interface HasGroupingTypes {
byBookmarks: number
byStarred: number
byIcon: number
total: number
}
export interface HasSortingOrGrouping {
sorting: HasSortingTypes
grouping: HasGroupingTypes
}
export const checkByBookmark = (has: HasSortingOrGrouping, order?: CustomSortOrder, groupType?: CustomSortGroupType ) => {
groupType === CustomSortGroupType.BookmarkedOnly && has.grouping.byBookmarks++;
(order === CustomSortOrder.byBookmarkOrder || order === CustomSortOrder.byBookmarkOrderReverse) && has.sorting.byBookmarks++;
}
export const checkByStarred = (has: HasSortingOrGrouping, order?: CustomSortOrder, groupType?: CustomSortGroupType ) => {
groupType === CustomSortGroupType.StarredOnly && has.grouping.byStarred++;
}
export const checkByIcon = (has: HasSortingOrGrouping, order?: CustomSortOrder, groupType?: CustomSortGroupType ) => {
groupType === CustomSortGroupType.HasIcon && has.grouping.byIcon++;
}
export const checkStandardObsidian = (has: HasSortingOrGrouping, order?: CustomSortOrder, groupType?: CustomSortGroupType ) => {
order === CustomSortOrder.standardObsidian && has.sorting.standardObsidian++;
}
export const doCheck = (has: HasSortingOrGrouping, order?: CustomSortOrder, groupType?: CustomSortGroupType) => {
checkByBookmark(has, order, groupType)
checkByStarred(has, order, groupType)
checkByIcon(has, order, groupType)
checkStandardObsidian(has, order, groupType)
order !== undefined && has.sorting.total++
groupType !== undefined && groupType !== CustomSortGroupType.Outsiders && has.grouping.total++;
}
export const collectSortingAndGroupingTypes = (sortSpec?: CustomSortSpec|null): HasSortingOrGrouping => {
const has: HasSortingOrGrouping = {
grouping: {
byIcon: 0, byStarred: 0, byBookmarks: 0, total: 0
},
sorting: {
byBookmarks: 0, standardObsidian: 0, total: 0
}
}
if (!sortSpec) return has
doCheck(has, sortSpec.defaultOrder)
doCheck(has, sortSpec.defaultSecondaryOrder)
if (sortSpec.groups) {
for (let group of sortSpec.groups) {
doCheck(has, group.order, group.type)
doCheck(has, group.secondaryOrder)
}
}
return has
}
export const hasOnlyByBookmarkOrStandardObsidian = (has: HasSortingOrGrouping): boolean => {
return has.sorting.total === has.sorting.standardObsidian + has.sorting.byBookmarks &&
has.grouping.total === has.grouping.byBookmarks
}

View File

@ -30,7 +30,9 @@ import {
SortingSpecProcessor, SortingSpecProcessor,
SortSpecsCollection SortSpecsCollection
} from './custom-sort/sorting-spec-processor'; } from './custom-sort/sorting-spec-processor';
import {CustomSortSpec} from './custom-sort/custom-sort-types'; import {
CustomSortSpec
} from './custom-sort/custom-sort-types';
import { import {
addIcons, addIcons,
@ -43,10 +45,17 @@ import {
} from "./custom-sort/icons"; } from "./custom-sort/icons";
import {getStarredPlugin} from "./utils/StarredPluginSignature"; import {getStarredPlugin} from "./utils/StarredPluginSignature";
import { import {
BookmarksPluginInterface,
getBookmarksPlugin getBookmarksPlugin
} from "./utils/BookmarksCorePluginSignature"; } from "./utils/BookmarksCorePluginSignature";
import {getIconFolderPlugin} from "./utils/ObsidianIconFolderPluginSignature"; import {getIconFolderPlugin} from "./utils/ObsidianIconFolderPluginSignature";
import {lastPathComponent} from "./utils/utils"; import {lastPathComponent} from "./utils/utils";
import {
collectSortingAndGroupingTypes,
hasOnlyByBookmarkOrStandardObsidian,
HasSortingOrGrouping,
ImplicitSortspecForBookmarksIntegration
} from "./custom-sort/custom-sort-utils";
interface CustomSortPluginSettings { interface CustomSortPluginSettings {
additionalSortspecFile: string additionalSortspecFile: string
@ -70,7 +79,8 @@ const DEFAULT_SETTINGS: CustomSortPluginSettings = {
bookmarksGroupToConsumeAsOrderingReference: 'sortspec' bookmarksGroupToConsumeAsOrderingReference: 'sortspec'
} }
const DEFAULT_SETTING_FOR_FRESH_INSTALL_1_2_0: Partial<CustomSortPluginSettings> = { // On API 1.2.x+ enable the bookmarks integration by default
const DEFAULT_SETTING_FOR_1_2_0_UP: Partial<CustomSortPluginSettings> = {
automaticBookmarksIntegration: true, automaticBookmarksIntegration: true,
bookmarksContextMenus: true bookmarksContextMenus: true
} }
@ -80,13 +90,6 @@ const SORTINGSPEC_YAML_KEY: string = 'sorting-spec'
const ERROR_NOTICE_TIMEOUT: number = 10000 const ERROR_NOTICE_TIMEOUT: number = 10000
const ImplicitSortspecForBookmarksIntegration: string = `
target-folder: /*
bookmarked:
< by-bookmarks-order
sorting: standard
`
// the monkey-around package doesn't export the below type // the monkey-around package doesn't export the below type
type MonkeyAroundUninstaller = () => void type MonkeyAroundUninstaller = () => void
@ -360,7 +363,7 @@ export default class CustomSortPlugin extends Plugin {
item.onClick(() => { item.onClick(() => {
const bookmarksPlugin = getBookmarksPlugin(plugin.settings.bookmarksGroupToConsumeAsOrderingReference) const bookmarksPlugin = getBookmarksPlugin(plugin.settings.bookmarksGroupToConsumeAsOrderingReference)
if (bookmarksPlugin) { if (bookmarksPlugin) {
const orderedChildren: Array<TAbstractFile> = plugin.orderedFolderItemsForBookmarking(file.parent) const orderedChildren: Array<TAbstractFile> = plugin.orderedFolderItemsForBookmarking(file.parent, bookmarksPlugin)
bookmarksPlugin.bookmarkSiblings(orderedChildren) bookmarksPlugin.bookmarkSiblings(orderedChildren)
bookmarksPlugin.saveDataAndUpdateBookmarkViews(true) bookmarksPlugin.saveDataAndUpdateBookmarkViews(true)
} }
@ -429,12 +432,12 @@ export default class CustomSortPlugin extends Plugin {
return sortSpec return sortSpec
} }
createProcessingContextForSorting(): ProcessingContext { createProcessingContextForSorting(has: HasSortingOrGrouping): ProcessingContext {
const ctx: ProcessingContext = { const ctx: ProcessingContext = {
_mCache: app.metadataCache, _mCache: app.metadataCache,
starredPluginInstance: getStarredPlugin(), starredPluginInstance: has.grouping.byStarred ? getStarredPlugin() : undefined,
bookmarksPluginInstance: getBookmarksPlugin(this.settings.bookmarksGroupToConsumeAsOrderingReference), bookmarksPluginInstance: has.grouping.byBookmarks || has.sorting.byBookmarks ? getBookmarksPlugin(this.settings.bookmarksGroupToConsumeAsOrderingReference, false, true) : undefined,
iconFolderPluginInstance: getIconFolderPlugin(), iconFolderPluginInstance: has.grouping.byIcon ? getIconFolderPlugin() : undefined,
plugin: this plugin: this
} }
return ctx return ctx
@ -466,8 +469,18 @@ export default class CustomSortPlugin extends Plugin {
const folder: TFolder = this.file const folder: TFolder = this.file
let sortSpec: CustomSortSpec | null | undefined = plugin.determineSortSpecForFolder(folder.path, folder.name) let sortSpec: CustomSortSpec | null | undefined = plugin.determineSortSpecForFolder(folder.path, folder.name)
// Performance optimization
// Primary intention: when the implicit bookmarks integration is enabled, remain on std Obsidian, if no need to involve bookmarks
let has: HasSortingOrGrouping = collectSortingAndGroupingTypes(sortSpec)
if (hasOnlyByBookmarkOrStandardObsidian(has)) {
const bookmarksPlugin: BookmarksPluginInterface|undefined = getBookmarksPlugin(plugin.settings.bookmarksGroupToConsumeAsOrderingReference, false, true)
if ( !bookmarksPlugin?.bookmarksIncludeItemsInFolder(folder.path)) {
sortSpec = null
}
}
if (sortSpec) { if (sortSpec) {
return folderSort.call(this, sortSpec, plugin.createProcessingContextForSorting()); return folderSort.call(this, sortSpec, plugin.createProcessingContextForSorting(has));
} else { } else {
return old.call(this, ...args); return old.call(this, ...args);
} }
@ -481,14 +494,21 @@ export default class CustomSortPlugin extends Plugin {
} }
} }
orderedFolderItemsForBookmarking(folder: TFolder): Array<TAbstractFile> { orderedFolderItemsForBookmarking(folder: TFolder, bookmarksPlugin: BookmarksPluginInterface): Array<TAbstractFile> {
let sortSpec: CustomSortSpec | null | undefined = undefined let sortSpec: CustomSortSpec | null | undefined = undefined
if (!this.settings.suspended) { if (!this.settings.suspended) {
sortSpec = this.determineSortSpecForFolder(folder.path, folder.name) sortSpec = this.determineSortSpecForFolder(folder.path, folder.name)
} }
let uiSortOrder: string = this.getFileExplorer()?.sortOrder || ObsidianStandardDefaultSortingName let uiSortOrder: string = this.getFileExplorer()?.sortOrder || ObsidianStandardDefaultSortingName
return sortFolderItemsForBookmarking(folder.children, sortSpec, this.createProcessingContextForSorting(), uiSortOrder) const has: HasSortingOrGrouping = collectSortingAndGroupingTypes(sortSpec)
return sortFolderItemsForBookmarking(
folder.children,
sortSpec,
this.createProcessingContextForSorting(has),
uiSortOrder
)
} }
// Credits go to https://github.com/nothingislost/obsidian-bartender // Credits go to https://github.com/nothingislost/obsidian-bartender
@ -511,10 +531,8 @@ export default class CustomSortPlugin extends Plugin {
const data: any = await this.loadData() || {} const data: any = await this.loadData() || {}
const isFreshInstall: boolean = Object.keys(data).length === 0 const isFreshInstall: boolean = Object.keys(data).length === 0
this.settings = Object.assign({}, DEFAULT_SETTINGS, data); this.settings = Object.assign({}, DEFAULT_SETTINGS, data);
if (isFreshInstall) { if (requireApiVersion('1.2.0')) {
if (requireApiVersion('1.2.0')) { this.settings = Object.assign(this.settings, DEFAULT_SETTING_FOR_1_2_0_UP)
this.settings = Object.assign(this.settings, DEFAULT_SETTING_FOR_FRESH_INSTALL_1_2_0)
}
} }
} }

View File

@ -77,6 +77,9 @@ export interface BookmarksPluginInterface {
updateSortingBookmarksAfterItemRenamed(renamedItem: TAbstractFile, oldPath: string): void updateSortingBookmarksAfterItemRenamed(renamedItem: TAbstractFile, oldPath: string): void
updateSortingBookmarksAfterItemDeleted(deletedItem: TAbstractFile): void updateSortingBookmarksAfterItemDeleted(deletedItem: TAbstractFile): void
isBookmarkedForSorting(item: TAbstractFile): boolean isBookmarkedForSorting(item: TAbstractFile): boolean
// To support performance optimization
bookmarksIncludeItemsInFolder(folderPath: string): boolean
} }
class BookmarksPluginWrapper implements BookmarksPluginInterface { class BookmarksPluginWrapper implements BookmarksPluginInterface {
@ -91,15 +94,21 @@ class BookmarksPluginWrapper implements BookmarksPluginInterface {
// undefined ==> item not found in bookmarks // undefined ==> item not found in bookmarks
// > 0 ==> item found in bookmarks at returned position // > 0 ==> item found in bookmarks at returned position
// Intentionally not returning 0 to allow simple syntax of processing the result // Intentionally not returning 0 to allow simple syntax of processing the result
determineBookmarkOrder = (path: string): number | undefined => { //
// Parameterless invocation enforces cache population, if empty
determineBookmarkOrder = (path?: string): number | undefined => {
if (!bookmarksCache) { if (!bookmarksCache) {
bookmarksCache = getOrderedBookmarks(this.plugin!, this.groupNameForSorting) [bookmarksCache, bookmarksFoldersCoverage] = getOrderedBookmarks(this.plugin!, this.groupNameForSorting)
bookmarksCacheTimestamp = Date.now() bookmarksCacheTimestamp = Date.now()
} }
const bookmarkedItemPosition: number | undefined = bookmarksCache?.[path]?.order if (path && path.length > 0) {
const bookmarkedItemPosition: number | undefined = bookmarksCache?.[path]?.order
return (bookmarkedItemPosition !== undefined && bookmarkedItemPosition >= 0) ? (bookmarkedItemPosition + 1) : undefined return (bookmarkedItemPosition !== undefined && bookmarkedItemPosition >= 0) ? (bookmarkedItemPosition + 1) : undefined
} else {
return undefined
}
} }
bookmarkFolderItem = (item: TAbstractFile) => { bookmarkFolderItem = (item: TAbstractFile) => {
@ -166,11 +175,16 @@ class BookmarksPluginWrapper implements BookmarksPluginInterface {
} }
return false return false
} }
bookmarksIncludeItemsInFolder = (folderPath: string): boolean => {
console.error(`C: for ${folderPath} is ${bookmarksFoldersCoverage?.[folderPath]}`)
return !! bookmarksFoldersCoverage?.[folderPath]
}
} }
export const BookmarksCorePluginId: string = 'bookmarks' export const BookmarksCorePluginId: string = 'bookmarks'
export const getBookmarksPlugin = (bookmarksGroupName?: string, forceFlushCache?: boolean): BookmarksPluginInterface | undefined => { export const getBookmarksPlugin = (bookmarksGroupName?: string, forceFlushCache?: boolean, ensureCachePopulated?: boolean): BookmarksPluginInterface | undefined => {
invalidateExpiredBookmarksCache(forceFlushCache) invalidateExpiredBookmarksCache(forceFlushCache)
const installedBookmarksPlugin: InstalledPlugin | undefined = app?.internalPlugins?.getPluginById(BookmarksCorePluginId) const installedBookmarksPlugin: InstalledPlugin | undefined = app?.internalPlugins?.getPluginById(BookmarksCorePluginId)
if (installedBookmarksPlugin && installedBookmarksPlugin.enabled && installedBookmarksPlugin.instance) { if (installedBookmarksPlugin && installedBookmarksPlugin.enabled && installedBookmarksPlugin.instance) {
@ -179,6 +193,9 @@ export const getBookmarksPlugin = (bookmarksGroupName?: string, forceFlushCache?
if (typeof bookmarksPluginInstance?.[BookmarksPlugin_getBookmarks_methodName] === 'function') { if (typeof bookmarksPluginInstance?.[BookmarksPlugin_getBookmarks_methodName] === 'function') {
bookmarksPlugin.plugin = bookmarksPluginInstance bookmarksPlugin.plugin = bookmarksPluginInstance
bookmarksPlugin.groupNameForSorting = bookmarksGroupName bookmarksPlugin.groupNameForSorting = bookmarksGroupName
if (ensureCachePopulated && !bookmarksCache) {
bookmarksPlugin.determineBookmarkOrder()
}
return bookmarksPlugin return bookmarksPlugin
} }
} }
@ -187,6 +204,9 @@ export const getBookmarksPlugin = (bookmarksGroupName?: string, forceFlushCache?
// cache can outlive the wrapper instances // cache can outlive the wrapper instances
let bookmarksCache: OrderedBookmarks | undefined = undefined let bookmarksCache: OrderedBookmarks | undefined = undefined
let bookmarksCacheTimestamp: number | undefined = undefined let bookmarksCacheTimestamp: number | undefined = undefined
type FolderPath = string
type FoldersCoverage = { [key: FolderPath]: boolean }
let bookmarksFoldersCoverage: FoldersCoverage | undefined = undefined
const bookmarksPlugin: BookmarksPluginWrapper = new BookmarksPluginWrapper() const bookmarksPlugin: BookmarksPluginWrapper = new BookmarksPluginWrapper()
@ -203,6 +223,7 @@ const invalidateExpiredBookmarksCache = (force?: boolean): void => {
if (flush) { if (flush) {
bookmarksCache = undefined bookmarksCache = undefined
bookmarksCacheTimestamp = undefined bookmarksCacheTimestamp = undefined
bookmarksFoldersCoverage = undefined
} }
} }
} }
@ -226,8 +247,12 @@ const bookmarkLocationAndPathOverlap = (bookmarkParentGroupPath: string, fileOrF
return fileOrFolderPath?.startsWith(bookmarkParentGroupPath) ? bookmarkParentGroupPath.length : 0 return fileOrFolderPath?.startsWith(bookmarkParentGroupPath) ? bookmarkParentGroupPath.length : 0
} }
const getOrderedBookmarks = (plugin: Bookmarks_PluginInstance, bookmarksGroupName?: string): OrderedBookmarks | undefined => { const ROOT_FOLDER_PATH = '/'
const getOrderedBookmarks = (plugin: Bookmarks_PluginInstance, bookmarksGroupName?: string): [OrderedBookmarks, FoldersCoverage] | [undefined, undefined] => {
console.log(`getOrderedBookmarks()`)
let bookmarksItems: Array<BookmarkedItem> | undefined = plugin?.[BookmarksPlugin_items_collectionName] let bookmarksItems: Array<BookmarkedItem> | undefined = plugin?.[BookmarksPlugin_items_collectionName]
let bookmarksCoveredFolders: FoldersCoverage = {}
if (bookmarksItems) { if (bookmarksItems) {
if (bookmarksGroupName) { if (bookmarksGroupName) {
// scanning only top level items because by desing the bookmarks group for sorting is a top level item // scanning only top level items because by desing the bookmarks group for sorting is a top level item
@ -249,6 +274,10 @@ const getOrderedBookmarks = (plugin: Bookmarks_PluginInstance, bookmarksGroupNam
const path = isGroup ? pathOfGroup : (item as BookmarkWithPath).path const path = isGroup ? pathOfGroup : (item as BookmarkWithPath).path
const alreadyConsumed = orderedBookmarks[path] const alreadyConsumed = orderedBookmarks[path]
const parentFolderPathOfBookmarkedItem = isGroup ? parentGroupsPath : extractParentFolderPath(path)
console.log(`Add ${path}`)
bookmarksCoveredFolders[parentFolderPathOfBookmarkedItem.length > 0 ? parentFolderPathOfBookmarkedItem : ROOT_FOLDER_PATH] = true
console.log(bookmarksCoveredFolders)
// for groups (they represent folders from sorting perspective) bookmark them unconditionally // for groups (they represent folders from sorting perspective) bookmark them unconditionally
// the idea of better match is not applicable // the idea of better match is not applicable
if (alreadyConsumed && isGroup && alreadyConsumed.group) { if (alreadyConsumed && isGroup && alreadyConsumed.group) {
@ -277,9 +306,10 @@ const getOrderedBookmarks = (plugin: Bookmarks_PluginInstance, bookmarksGroupNam
} }
traverseBookmarksCollection(bookmarksItems, consumeItem) traverseBookmarksCollection(bookmarksItems, consumeItem)
return orderedBookmarks return [orderedBookmarks, bookmarksCoveredFolders]
} }
} }
return [undefined, undefined]
} }
const createBookmarkFileEntry = (path: string): BookmarkedFile => { const createBookmarkFileEntry = (path: string): BookmarkedFile => {

View File

@ -1,4 +1,7 @@
import {lastPathComponent, extractParentFolderPath} from "./utils"; import {
lastPathComponent,
extractParentFolderPath
} from "./utils";
describe('lastPathComponent and extractParentFolderPath', () => { describe('lastPathComponent and extractParentFolderPath', () => {
it.each([ it.each([