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

- ready for release!
- finetuned context-menus for desktop and mobile
- more unit tests
This commit is contained in:
SebastianMC 2023-10-23 11:36:50 +02:00
parent b3326e2af0
commit 85d973e700
3 changed files with 106 additions and 36 deletions

View File

@ -316,6 +316,8 @@ export default class CustomSortPlugin extends Plugin {
registerEventHandlers() { registerEventHandlers() {
const plugin: CustomSortPlugin = this const plugin: CustomSortPlugin = this
const m: boolean = Platform.isMobile
this.registerEvent( this.registerEvent(
// Keep in mind: this event is triggered once after app starts and then after each modification of _any_ metadata // Keep in mind: this event is triggered once after app starts and then after each modification of _any_ metadata
app.metadataCache.on("resolved", () => { app.metadataCache.on("resolved", () => {
@ -345,14 +347,14 @@ export default class CustomSortPlugin extends Plugin {
); );
const applyCustomSortMenuItem = (item: MenuItem) => { const applyCustomSortMenuItem = (item: MenuItem) => {
item.setTitle('Apply custom sorting'); item.setTitle(m ? 'Custom sort: apply custom sorting' : 'Apply custom sorting');
item.onClick(() => { item.onClick(() => {
plugin.switchPluginStateTo(true, true) plugin.switchPluginStateTo(true, true)
}) })
}; };
const suspendCustomSortMenuItem = (item: MenuItem) => { const suspendCustomSortMenuItem = (item: MenuItem) => {
item.setTitle('Suspend custom sorting'); item.setTitle(m ? 'Custom sort: suspend custom sorting' : 'Suspend custom sorting');
item.onClick(() => { item.onClick(() => {
plugin.switchPluginStateTo(false, true) plugin.switchPluginStateTo(false, true)
}) })
@ -360,7 +362,7 @@ export default class CustomSortPlugin extends Plugin {
const getBookmarkThisMenuItemForFile = (file: TAbstractFile): ContextMenuProvider => const getBookmarkThisMenuItemForFile = (file: TAbstractFile): ContextMenuProvider =>
(item: MenuItem) => { (item: MenuItem) => {
item.setTitle('Bookmark it for sorting.'); item.setTitle(m ? 'Bookmark it for custom sorting' : 'Bookmark it for sorting');
item.onClick(() => { item.onClick(() => {
const bookmarksPlugin = getBookmarksPlugin(plugin.settings.bookmarksGroupToConsumeAsOrderingReference) const bookmarksPlugin = getBookmarksPlugin(plugin.settings.bookmarksGroupToConsumeAsOrderingReference)
if (bookmarksPlugin) { if (bookmarksPlugin) {
@ -372,7 +374,7 @@ export default class CustomSortPlugin extends Plugin {
const getUnbookmarkThisMenuItemForFile = (file: TAbstractFile): ContextMenuProvider => const getUnbookmarkThisMenuItemForFile = (file: TAbstractFile): ContextMenuProvider =>
(item: MenuItem) => { (item: MenuItem) => {
item.setTitle('UNbookmark it from sorting.'); item.setTitle(m ? 'UNbookmark it from custom sorting' : 'UNbookmark it from sorting');
item.onClick(() => { item.onClick(() => {
const bookmarksPlugin = getBookmarksPlugin(plugin.settings.bookmarksGroupToConsumeAsOrderingReference) const bookmarksPlugin = getBookmarksPlugin(plugin.settings.bookmarksGroupToConsumeAsOrderingReference)
if (bookmarksPlugin) { if (bookmarksPlugin) {
@ -384,7 +386,7 @@ export default class CustomSortPlugin extends Plugin {
const getBookmarkAllMenuItemForFile = (file: TAbstractFile): ContextMenuProvider => const getBookmarkAllMenuItemForFile = (file: TAbstractFile): ContextMenuProvider =>
(item: MenuItem) => { (item: MenuItem) => {
item.setTitle('Bookmark it+siblings for sorting.'); item.setTitle(m ? 'Bookmark it+siblings for custom sorting' : 'Bookmark it+siblings for sorting');
item.onClick(() => { item.onClick(() => {
const bookmarksPlugin = getBookmarksPlugin(plugin.settings.bookmarksGroupToConsumeAsOrderingReference) const bookmarksPlugin = getBookmarksPlugin(plugin.settings.bookmarksGroupToConsumeAsOrderingReference)
if (bookmarksPlugin) { if (bookmarksPlugin) {
@ -397,7 +399,7 @@ export default class CustomSortPlugin extends Plugin {
const getUnbookmarkAllMenuItemForFile = (file: TAbstractFile): ContextMenuProvider => const getUnbookmarkAllMenuItemForFile = (file: TAbstractFile): ContextMenuProvider =>
(item: MenuItem) => { (item: MenuItem) => {
item.setTitle('UNbookmark it+siblings from sorting.'); item.setTitle(m ? 'UNbookmark it+siblings from custom sorting' : 'UNbookmark it+siblings from sorting');
item.onClick(() => { item.onClick(() => {
const bookmarksPlugin = getBookmarksPlugin(plugin.settings.bookmarksGroupToConsumeAsOrderingReference) const bookmarksPlugin = getBookmarksPlugin(plugin.settings.bookmarksGroupToConsumeAsOrderingReference)
if (bookmarksPlugin) { if (bookmarksPlugin) {
@ -410,7 +412,7 @@ export default class CustomSortPlugin extends Plugin {
const getBookmarkSelectedMenuItemForFiles = (files: TAbstractFile[]): ContextMenuProvider => const getBookmarkSelectedMenuItemForFiles = (files: TAbstractFile[]): ContextMenuProvider =>
(item: MenuItem) => { (item: MenuItem) => {
item.setTitle('Custom sort: bookmark selected for sorting.'); item.setTitle(m ? 'Bookmark selected for custom sorting' : 'Custom sort: bookmark selected for sorting');
item.onClick(() => { item.onClick(() => {
const bookmarksPlugin = getBookmarksPlugin(plugin.settings.bookmarksGroupToConsumeAsOrderingReference) const bookmarksPlugin = getBookmarksPlugin(plugin.settings.bookmarksGroupToConsumeAsOrderingReference)
if (bookmarksPlugin) { if (bookmarksPlugin) {
@ -424,7 +426,7 @@ export default class CustomSortPlugin extends Plugin {
const getUnbookmarkSelectedMenuItemForFiles = (files: TAbstractFile[]): ContextMenuProvider => const getUnbookmarkSelectedMenuItemForFiles = (files: TAbstractFile[]): ContextMenuProvider =>
(item: MenuItem) => { (item: MenuItem) => {
item.setTitle('Custom sort: UNbookmark selected from sorting.'); item.setTitle(m ? 'UNbookmark selected from custom sorting' : 'Custom sort: UNbookmark selected from sorting');
item.onClick(() => { item.onClick(() => {
const bookmarksPlugin = getBookmarksPlugin(plugin.settings.bookmarksGroupToConsumeAsOrderingReference) const bookmarksPlugin = getBookmarksPlugin(plugin.settings.bookmarksGroupToConsumeAsOrderingReference)
if (bookmarksPlugin) { if (bookmarksPlugin) {
@ -440,32 +442,41 @@ export default class CustomSortPlugin extends Plugin {
app.workspace.on("file-menu", (menu: Menu, file: TAbstractFile, source: string, leaf?: WorkspaceLeaf) => { app.workspace.on("file-menu", (menu: Menu, file: TAbstractFile, source: string, leaf?: WorkspaceLeaf) => {
if (!this.settings.customSortContextSubmenu) return; // Don't show the context menus at all if (!this.settings.customSortContextSubmenu) return; // Don't show the context menus at all
const customSortMenuItem = (item: MenuItem) => { const customSortMenuItem = (item?: MenuItem) => {
item.setTitle('Custom sort:'); // if parameter is empty it means mobile invocation, where submenus are not supported.
item.setIcon('hashtag'); // In that case flatten the menu.
const submenu = item.setSubmenu() let submenu: Menu|undefined
if (item) {
submenu.addItem(applyCustomSortMenuItem) item.setTitle('Custom sort:');
submenu.addSeparator() item.setIcon('hashtag');
submenu = item.setSubmenu()
}
if (!submenu) menu.addSeparator();
(submenu ?? menu).addItem(applyCustomSortMenuItem)
if (submenu) submenu.addSeparator();
if (this.settings.bookmarksContextMenus) { if (this.settings.bookmarksContextMenus) {
const bookmarksPlugin = getBookmarksPlugin(plugin.settings.bookmarksGroupToConsumeAsOrderingReference) const bookmarksPlugin = getBookmarksPlugin(plugin.settings.bookmarksGroupToConsumeAsOrderingReference)
if (bookmarksPlugin) { if (bookmarksPlugin) {
const itemAlreadyBookmarkedForSorting: boolean = bookmarksPlugin.isBookmarkedForSorting(file) const itemAlreadyBookmarkedForSorting: boolean = bookmarksPlugin.isBookmarkedForSorting(file)
if (!itemAlreadyBookmarkedForSorting) { if (!itemAlreadyBookmarkedForSorting) {
submenu.addItem(getBookmarkThisMenuItemForFile(file)) (submenu ?? menu).addItem(getBookmarkThisMenuItemForFile(file))
} else { } else {
submenu.addItem(getUnbookmarkThisMenuItemForFile(file)) (submenu ?? menu).addItem(getUnbookmarkThisMenuItemForFile(file))
} }
submenu.addItem(getBookmarkAllMenuItemForFile(file)) (submenu ?? menu).addItem(getBookmarkAllMenuItemForFile(file));
submenu.addItem(getUnbookmarkAllMenuItemForFile(file)) (submenu ?? menu).addItem(getUnbookmarkAllMenuItemForFile(file));
} }
} }
submenu.addItem(suspendCustomSortMenuItem) (submenu ?? menu).addItem(suspendCustomSortMenuItem)
}; }
menu.addItem(customSortMenuItem) if (m) {
customSortMenuItem(undefined)
} else {
menu.addItem(customSortMenuItem)
}
}) })
) )
@ -476,26 +487,34 @@ export default class CustomSortPlugin extends Plugin {
app.workspace.on("files-menu", (menu: Menu, files: TAbstractFile[], source: string, leaf?: WorkspaceLeaf) => { app.workspace.on("files-menu", (menu: Menu, files: TAbstractFile[], source: string, leaf?: WorkspaceLeaf) => {
if (!this.settings.customSortContextSubmenu) return; // Don't show the context menus at all if (!this.settings.customSortContextSubmenu) return; // Don't show the context menus at all
const customSortMenuItem = (item: MenuItem) => { const customSortMenuItem = (item?: MenuItem) => {
item.setTitle('Custom sort:'); // if parameter is empty it means mobile invocation, where submenus are not supported.
item.setIcon('hashtag'); // In that case flatten the menu.
const submenu = item.setSubmenu() let submenu: Menu|undefined
if (item) {
submenu.addItem(applyCustomSortMenuItem) item.setTitle('Custom sort:');
submenu.addSeparator() item.setIcon('hashtag');
submenu = item.setSubmenu()
}
if (!submenu) menu.addSeparator();
(submenu ?? menu).addItem(applyCustomSortMenuItem)
if (submenu) submenu.addSeparator();
if (this.settings.bookmarksContextMenus) { if (this.settings.bookmarksContextMenus) {
const bookmarksPlugin = getBookmarksPlugin(plugin.settings.bookmarksGroupToConsumeAsOrderingReference) const bookmarksPlugin = getBookmarksPlugin(plugin.settings.bookmarksGroupToConsumeAsOrderingReference)
if (bookmarksPlugin) { if (bookmarksPlugin) {
submenu.addItem(getBookmarkSelectedMenuItemForFiles(files)) (submenu ?? menu).addItem(getBookmarkSelectedMenuItemForFiles(files));
submenu.addItem(getUnbookmarkSelectedMenuItemForFiles(files)) (submenu ?? menu).addItem(getUnbookmarkSelectedMenuItemForFiles(files));
} }
} }
submenu.addItem(suspendCustomSortMenuItem) (submenu ?? menu).addItem(suspendCustomSortMenuItem);
}; };
menu.addItem(customSortMenuItem) if (m) {
customSortMenuItem(undefined)
} else {
menu.addItem(customSortMenuItem)
}
}) })
) )
} }

View File

@ -1062,6 +1062,55 @@ describe('cleanupBookmarkTreeFromTransparentEmptyGroups', () => {
"sortspec": {} "sortspec": {}
})))) }))))
}) })
it('should NOT delete not-transparent group, even after multiple invocations', () => {
const items = consumeBkMock({
"sortspec": {
"Folder to go first": {
//"March": {} <-- in test scenario in UI, this group was removed from File Explorer
},
"Folder to go second": {}
}
})
const plugin = getBookmarksMock(items)
const parentFolder1: BookmarkedParentFolder|undefined = _unitTests.findGroupForItemPathInBookmarks(
'Folder to go first/March', // <-- the 'March' subgroup was removed
false,
plugin,
'sortspec'
)
_unitTests.cleanupBookmarkTreeFromTransparentEmptyGroups(
parentFolder1,
plugin,
'sortspec'
)
expect(JSON.parse(JSON.stringify(items))).toEqual(JSON.parse(JSON.stringify(consumeBkMock({
"sortspec": {
"Folder to go first": {
//"March": {}
},
"Folder to go second": {}
}
}))))
const parentFolder2: BookmarkedParentFolder|undefined = _unitTests.findGroupForItemPathInBookmarks(
'',
false,
plugin,
'sortspec'
)
_unitTests.cleanupBookmarkTreeFromTransparentEmptyGroups(
parentFolder2,
plugin,
'sortspec'
)
expect(JSON.parse(JSON.stringify(items))).toEqual(JSON.parse(JSON.stringify(consumeBkMock({
"sortspec": {
"Folder to go first": {
//"March": {}
},
"Folder to go second": {}
}
}))))
})
}) })
describe('findGroupForItemPathInBookmarks', () =>{ describe('findGroupForItemPathInBookmarks', () =>{

View File

@ -510,7 +510,9 @@ const cleanupBookmarkTreeFromTransparentEmptyGroups = (parentGroup: BookmarkedPa
bookmarksGroup bookmarksGroup
) )
if (parentContainerOfGroup) { if (parentContainerOfGroup) {
parentContainerOfGroup.group?.items?.remove(parentGroup.group) if (isGroupTransparentForSorting(parentGroup.group.title)) {
parentContainerOfGroup.group?.items?.remove(parentGroup.group)
}
cleanupBookmarkTreeFromTransparentEmptyGroups(parentContainerOfGroup, plugin, bookmarksGroup) cleanupBookmarkTreeFromTransparentEmptyGroups(parentContainerOfGroup, plugin, bookmarksGroup)
} }
} }
@ -616,7 +618,7 @@ const updateSortingBookmarksAfterItemDeleted = (plugin: Bookmarks_PluginInstance
bookmarkEntriesToRemove.push(it) bookmarkEntriesToRemove.push(it)
} }
}) })
bookmarkEntriesToRemove.forEach((itemToRemove) =>{ bookmarkEntriesToRemove.forEach((itemToRemove: BookmarkedItem) =>{
container?.group?.items.remove(itemToRemove) container?.group?.items.remove(itemToRemove)
}) })
cleanupBookmarkTreeFromTransparentEmptyGroups(container, plugin, bookmarksGroup) cleanupBookmarkTreeFromTransparentEmptyGroups(container, plugin, bookmarksGroup)