#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:
parent
a4a6c93412
commit
daf657721c
|
@ -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
|
|
@ -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
|
||||||
|
}
|
60
src/main.ts
60
src/main.ts
|
@ -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)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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 => {
|
||||||
|
|
|
@ -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([
|
||||||
|
|
Loading…
Reference in New Issue