Skip to content

Commit

Permalink
#74 - Integration with Bookmarks core plugin and support for indirect…
Browse files Browse the repository at this point in the history
… drag & drop arrangement

- functionality completed!!!
- increased coverage of the new functionality with unit tests
- more unit tests possible
- basic manual tests done
- next step: real-life usage tests
  • Loading branch information
SebastianMC committed Oct 20, 2023
1 parent cd933cb commit b854ce1
Show file tree
Hide file tree
Showing 7 changed files with 1,508 additions and 114 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
"jest": "^28.1.1",
"monkey-around": "^2.3.0",
"obsidian": "^0.15.4",
"obsidian-1.4.11": "npm:obsidian@1.4.11",
"ts-jest": "^28.0.5",
"tslib": "2.4.0",
"typescript": "4.7.4"
Expand Down
11 changes: 7 additions & 4 deletions src/custom-sort/custom-sort.ts
Original file line number Diff line number Diff line change
Expand Up @@ -615,10 +615,8 @@ export const determineBookmarksOrderIfNeeded = (folderItems: Array<FolderItemFor
export const folderSort = function (sortingSpec: CustomSortSpec, ctx: ProcessingContext) {
let fileExplorer = this.fileExplorer

// shallow copy of groups
// shallow copy of groups and expand folder-specific macros on them
sortingSpec.groupsShadow = sortingSpec.groups?.map((group) => Object.assign({} as CustomSortGroup, group))

// expand folder-specific macros
const parentFolderName: string|undefined = this.file.name
expandMacros(sortingSpec, parentFolderName)

Expand Down Expand Up @@ -655,10 +653,15 @@ export const folderSort = function (sortingSpec: CustomSortSpec, ctx: Processing
};

// Returns a sorted copy of the input array, intentionally to keep it intact
export const sortFolderItemsForBookmarking = function (items: Array<TAbstractFile>, sortingSpec: CustomSortSpec|null|undefined, ctx: ProcessingContext, uiSortOrder: string): Array<TAbstractFile> {
export const sortFolderItemsForBookmarking = function (folder: TFolder, items: Array<TAbstractFile>, sortingSpec: CustomSortSpec|null|undefined, ctx: ProcessingContext, uiSortOrder: string): Array<TAbstractFile> {
if (sortingSpec) {
const folderItemsByPath: { [key: string]: TAbstractFile } = {}

// shallow copy of groups and expand folder-specific macros on them
sortingSpec.groupsShadow = sortingSpec.groups?.map((group) => Object.assign({} as CustomSortGroup, group))
const parentFolderName: string|undefined = folder.name
expandMacros(sortingSpec, parentFolderName)

const folderItems: Array<FolderItemForSorting> = items.map((entry: TFile | TFolder) => {
folderItemsByPath[entry.path] = entry
const itemForSorting: FolderItemForSorting = determineSortingGroup(entry, sortingSpec, ctx)
Expand Down
76 changes: 74 additions & 2 deletions src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,8 @@ import {
import {getStarredPlugin} from "./utils/StarredPluginSignature";
import {
BookmarksPluginInterface,
getBookmarksPlugin
getBookmarksPlugin,
groupNameForPath
} from "./utils/BookmarksCorePluginSignature";
import {getIconFolderPlugin} from "./utils/ObsidianIconFolderPluginSignature";
import {lastPathComponent} from "./utils/utils";
Expand Down Expand Up @@ -357,6 +358,17 @@ export default class CustomSortPlugin extends Plugin {
}
});
};
const unbookmarkThisMenuItem = (item: MenuItem) => {
item.setTitle('Custom sort: UNbookmark from sorting.');
item.setIcon('hashtag');
item.onClick(() => {
const bookmarksPlugin = getBookmarksPlugin(plugin.settings.bookmarksGroupToConsumeAsOrderingReference)
if (bookmarksPlugin) {
bookmarksPlugin.unbookmarkFolderItem(file)
bookmarksPlugin.saveDataAndUpdateBookmarkViews(true)
}
});
};
const bookmarkAllMenuItem = (item: MenuItem) => {
item.setTitle('Custom sort: bookmark+siblings for sorting.');
item.setIcon('hashtag');
Expand All @@ -369,15 +381,73 @@ export default class CustomSortPlugin extends Plugin {
}
});
};
const unbookmarkAllMenuItem = (item: MenuItem) => {
item.setTitle('Custom sort: UNbookmark+all siblings from sorting.');
item.setIcon('hashtag');
item.onClick(() => {
const bookmarksPlugin = getBookmarksPlugin(plugin.settings.bookmarksGroupToConsumeAsOrderingReference)
if (bookmarksPlugin) {
const orderedChildren: Array<TAbstractFile> = file.parent.children.map((entry: TFile | TFolder) => entry)
bookmarksPlugin.unbookmarkSiblings(orderedChildren)
bookmarksPlugin.saveDataAndUpdateBookmarkViews(true)
}
});
};

const itemAlreadyBookmarkedForSorting: boolean = bookmarksPlugin.isBookmarkedForSorting(file)
if (!itemAlreadyBookmarkedForSorting) {
menu.addItem(bookmarkThisMenuItem)
} else {
menu.addItem(unbookmarkThisMenuItem)
}
menu.addItem(bookmarkAllMenuItem)
menu.addItem(unbookmarkAllMenuItem)
})
)

if (requireApiVersion('1.4.11')) {
this.registerEvent(
// "files-menu" event was exposed in 1.4.11
// @ts-ignore
app.workspace.on("files-menu", (menu: Menu, files: TAbstractFile[], source: string, leaf?: WorkspaceLeaf) => {
if (!this.settings.bookmarksContextMenus) return; // Don't show the context menus at all

const bookmarksPlugin = getBookmarksPlugin(plugin.settings.bookmarksGroupToConsumeAsOrderingReference)
if (!bookmarksPlugin) return; // Don't show context menu if bookmarks plugin not available and not enabled

const bookmarkSelectedMenuItem = (item: MenuItem) => {
item.setTitle('Custom sort: bookmark selected for sorting.');
item.setIcon('hashtag');
item.onClick(() => {
const bookmarksPlugin = getBookmarksPlugin(plugin.settings.bookmarksGroupToConsumeAsOrderingReference)
if (bookmarksPlugin) {
files.forEach((file) => {
bookmarksPlugin.bookmarkFolderItem(file)
})
bookmarksPlugin.saveDataAndUpdateBookmarkViews(true)
}
});
};
const unbookmarkSelectedMenuItem = (item: MenuItem) => {
item.setTitle('Custom sort: UNbookmark selected from sorting.');
item.setIcon('hashtag');
item.onClick(() => {
const bookmarksPlugin = getBookmarksPlugin(plugin.settings.bookmarksGroupToConsumeAsOrderingReference)
if (bookmarksPlugin) {
files.forEach((file) => {
bookmarksPlugin.unbookmarkFolderItem(file)
})
bookmarksPlugin.saveDataAndUpdateBookmarkViews(true)
}
});
};

menu.addItem(bookmarkSelectedMenuItem)
menu.addItem(unbookmarkSelectedMenuItem)
})
)
}

this.registerEvent(
app.vault.on("rename", (file: TAbstractFile, oldPath: string) => {
const bookmarksPlugin = getBookmarksPlugin(plugin.settings.bookmarksGroupToConsumeAsOrderingReference)
Expand Down Expand Up @@ -504,6 +574,7 @@ export default class CustomSortPlugin extends Plugin {
const has: HasSortingOrGrouping = collectSortingAndGroupingTypes(sortSpec)

return sortFolderItemsForBookmarking(
folder,
folder.children,
sortSpec,
this.createProcessingContextForSorting(has),
Expand Down Expand Up @@ -669,7 +740,8 @@ class CustomSortSettingTab extends PluginSettingTab {
.setPlaceholder('e.g. Group for sorting')
.setValue(this.plugin.settings.bookmarksGroupToConsumeAsOrderingReference)
.onChange(async (value) => {
this.plugin.settings.bookmarksGroupToConsumeAsOrderingReference = value.trim() ? pathToFlatString(normalizePath(value)) : '';
value = groupNameForPath(value.trim()).trim()
this.plugin.settings.bookmarksGroupToConsumeAsOrderingReference = value ? pathToFlatString(normalizePath(value)) : '';
await this.plugin.saveSettings();
}));

Expand Down
55 changes: 55 additions & 0 deletions src/utils/Bookmarks Core Plugin integration design.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
Integration with Bookmarks core plugin:
- support two approaches _at the same time_:
- (A) structured bookmarks inside a dedicated bookmarks group, and
- (B) a flat list of bookmarks inside the dedicated bookmarks group

For (A):
- preferred
- a folder is represented by a group in bookmarks
- a file is represented by a file-with-block
- this also applied to non-md files, like jpg and others
- guarantees _'hiding'_ the bookmarks-for-sorting from regular bookmarks usage scenarios
- bookmark entries for sorting are encapsulated in the dedicated group
- they don't interfere with bookmarking of files and folders via standard bookmarking
- only exact location of file bookmark / group matches for sorting order in file explorer
- the contextual bookmark menus always work in (A) mode
- the contextual menus create / modify the bookmarks structure on-the-fly

For (B):
- discouraged, yet supported (exception for some edge cases)
- typically a result of manual bookmarks management
- for small number of items seems reasonable
- for flat vaults it could look same as for (A)
- groups don't have a 'path' attribute, their path is determined by their location
- bookmarked folders represent folders if inside the bookmarks group for sorting
- yet in this way they interfere with regular bookmarks scenario
- file bookmarks work correctly in non-interfering way thanks to the _'artificial block reference'_
- file bookmarks not having the _'artificial block ref'_ work as well
- if they are in the designated bookmarks group
- if there isn't a duplicate, which has the _'artificial block ref'_
- yet in this way they interfere with regular bookmarks scenario

-[ ] TODO: review again the 'item moved' and 'item deleted' scenarios (they look ok, check if they don't delete/move too much)
- [x] fundamental question 1: should 'move' create a bookmark entry/structure if it is not covered by bookmarks?
- Answer: the moved item is removed from bookmarks. If it is a group with descendants not transparent for sorting,
it is renamed to become transparent for sorting.
By design, the order of items is property of the parent folder (the container) and not the items
- [x] fundamental question 2: should 'move' create a bookmark entry if moved item was not bookmarked, yet is moved to a folder covered by bookmarks?
- Answer: same as for previous point.
- [x] review from (A) and (B) perspective
- Answer: scenario (A) is fully handled by 'item moved' and 'item deleted'.
scenario (B) is partially handled for 'item moved'. Details to be read from code (too complex to cover here)
- [x] consider deletion of item outside of bookmarks sorting container group
Answer: bookmark items outside of bookmarks sorting container are not manipulated by custom-sort plugin
to not interfere with standard Bookmarks scenarios
- [x] consider moving an item outside of bookmarks group
- Answer: question not relevant. Items are moved in file explorer and bookmarks only reflect that, if needed.
Hence there is no concept of 'moving an item outside of bookmarks group' - bookmarks group only exists in bookmarks
- [x] edge case: bookmarked item is a group, the deleted/moved is a file, not a folder --> what to do?
- Answer: for moved files, only file bookmarks are scanned (and handles), for moved folders, only groups are scanned (and handled).
- [x] delete all instances at any level of bookmarks structure in 'delete' handler
- Answer: only instances of (A) or (B) are deleted. Items outside of bookmarks container for sorting or
in invalid locations in bookmarks hierarchy are ignored



Loading

0 comments on commit b854ce1

Please sign in to comment.