13 - Feature request: Sort by modification date, treating folder and files equally
- working solution - added new explicitly named sort method 'advanced modified' on top of 'modified' - unit tests to be added before merge and release
This commit is contained in:
parent
527df1a74f
commit
5aed85c0bd
|
@ -11,7 +11,9 @@ export enum CustomSortOrder {
|
|||
alphabetical = 1, // = 1 to allow: if (customSortOrder) { ...
|
||||
alphabeticalReverse,
|
||||
byModifiedTime,
|
||||
byModifiedTimeAdvanced,
|
||||
byModifiedTimeReverse,
|
||||
byModifiedTimeReverseAdvanced,
|
||||
byCreatedTime,
|
||||
byCreatedTimeReverse,
|
||||
standardObsidian, // Let the folder sorting be in hands of Obsidian, whatever user selected in the UI
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import {requireApiVersion, TFile, TFolder} from 'obsidian';
|
||||
import {requireApiVersion, TAbstractFile, TFile, TFolder} from 'obsidian';
|
||||
import {CustomSortGroup, CustomSortGroupType, CustomSortOrder, CustomSortSpec} from "./custom-sort-types";
|
||||
import {isDefined} from "../utils/utils";
|
||||
|
||||
|
@ -16,6 +16,7 @@ interface FolderItemForSorting {
|
|||
ctime: number
|
||||
mtime: number
|
||||
isFolder: boolean
|
||||
folder?: TFolder
|
||||
}
|
||||
|
||||
type SorterFn = (a: FolderItemForSorting, b: FolderItemForSorting) => number
|
||||
|
@ -24,7 +25,9 @@ let Sorters: { [key in CustomSortOrder]: SorterFn } = {
|
|||
[CustomSortOrder.alphabetical]: (a: FolderItemForSorting, b: FolderItemForSorting) => Collator(a.sortString, b.sortString),
|
||||
[CustomSortOrder.alphabeticalReverse]: (a: FolderItemForSorting, b: FolderItemForSorting) => Collator(b.sortString, a.sortString),
|
||||
[CustomSortOrder.byModifiedTime]: (a: FolderItemForSorting, b: FolderItemForSorting) => a.mtime - b.mtime,
|
||||
[CustomSortOrder.byModifiedTimeAdvanced]: (a: FolderItemForSorting, b: FolderItemForSorting) => a.mtime - b.mtime,
|
||||
[CustomSortOrder.byModifiedTimeReverse]: (a: FolderItemForSorting, b: FolderItemForSorting) => b.mtime - a.mtime,
|
||||
[CustomSortOrder.byModifiedTimeReverseAdvanced]: (a: FolderItemForSorting, b: FolderItemForSorting) => b.mtime - a.mtime,
|
||||
[CustomSortOrder.byCreatedTime]: (a: FolderItemForSorting, b: FolderItemForSorting) => a.ctime - b.ctime,
|
||||
[CustomSortOrder.byCreatedTimeReverse]: (a: FolderItemForSorting, b: FolderItemForSorting) => b.ctime - a.ctime,
|
||||
|
||||
|
@ -52,11 +55,14 @@ function compareTwoItems(itA: FolderItemForSorting, itB: FolderItemForSorting, s
|
|||
}
|
||||
}
|
||||
|
||||
const isFolder = (entry: TFile | TFolder) => {
|
||||
const isFolder = (entry: TAbstractFile) => {
|
||||
// The plain obvious 'entry instanceof TFolder' doesn't work inside Jest unit tests, hence a workaround below
|
||||
return !!((entry as any).isRoot);
|
||||
}
|
||||
|
||||
export const DEFAULT_FOLDER_MTIME: number = 0
|
||||
export const DEFAULT_FOLDER_CTIME: number = 0
|
||||
|
||||
export const determineSortingGroup = function (entry: TFile | TFolder, spec: CustomSortSpec): FolderItemForSorting {
|
||||
let groupIdx: number
|
||||
let determined: boolean = false
|
||||
|
@ -165,14 +171,37 @@ export const determineSortingGroup = function (entry: TFile | TFolder, spec: Cus
|
|||
sortString: matchedGroup ? (matchedGroup + '//' + entry.name) : entry.name,
|
||||
matchGroup: matchedGroup ?? undefined,
|
||||
isFolder: aFolder,
|
||||
folder: aFolder ? (entry as TFolder) : undefined,
|
||||
path: entry.path,
|
||||
ctime: aFile ? entryAsTFile.stat.ctime : 0,
|
||||
mtime: aFile ? entryAsTFile.stat.mtime : 0
|
||||
ctime: aFile ? entryAsTFile.stat.ctime : DEFAULT_FOLDER_CTIME,
|
||||
mtime: aFile ? entryAsTFile.stat.mtime : DEFAULT_FOLDER_MTIME
|
||||
}
|
||||
}
|
||||
|
||||
export const sortOrderNeedsFoldersMDate = (order: CustomSortOrder | undefined): boolean => {
|
||||
return order === CustomSortOrder.byModifiedTimeAdvanced || order === CustomSortOrder.byModifiedTimeReverseAdvanced
|
||||
}
|
||||
|
||||
// Syntax sugar for readability
|
||||
export type ModifiedTime = number
|
||||
|
||||
export const determineModifiedDateForFolder = (folder: TFolder): ModifiedTime => {
|
||||
let mtimeOfFolder: ModifiedTime = DEFAULT_FOLDER_MTIME
|
||||
folder.children.forEach((item) => {
|
||||
if (!isFolder(item)) {
|
||||
const file: TFile = item as TFile
|
||||
if (file.stat.mtime > mtimeOfFolder) {
|
||||
mtimeOfFolder = file.stat.mtime
|
||||
}
|
||||
}
|
||||
})
|
||||
return mtimeOfFolder
|
||||
}
|
||||
|
||||
|
||||
export const folderSort = function (sortingSpec: CustomSortSpec, order: string[]) {
|
||||
let fileExplorer = this.fileExplorer
|
||||
const sortingGroupsCardinality: {[key: number]: number} = {}
|
||||
|
||||
const folderItems: Array<FolderItemForSorting> = (sortingSpec.itemsToHide ?
|
||||
this.file.children.filter((entry: TFile | TFolder) => {
|
||||
|
@ -180,9 +209,27 @@ export const folderSort = function (sortingSpec: CustomSortSpec, order: string[]
|
|||
})
|
||||
:
|
||||
this.file.children)
|
||||
.map((entry: TFile | TFolder) =>
|
||||
determineSortingGroup(entry, sortingSpec)
|
||||
)
|
||||
.map((entry: TFile | TFolder) => {
|
||||
const itemForSorting: FolderItemForSorting = determineSortingGroup(entry, sortingSpec)
|
||||
const groupIdx: number | undefined = itemForSorting.groupIdx
|
||||
if (groupIdx !== undefined) {
|
||||
sortingGroupsCardinality[groupIdx] = 1 + (sortingGroupsCardinality[groupIdx] ?? 0)
|
||||
}
|
||||
return itemForSorting
|
||||
})
|
||||
|
||||
// Finally, for advanced sorting by modified date, for some of the folders the modified date has to be determined
|
||||
folderItems.forEach((item) => {
|
||||
const groupIdx: number | undefined = item.groupIdx
|
||||
if (groupIdx !== undefined) {
|
||||
const groupOrder: CustomSortOrder | undefined = sortingSpec.groups[groupIdx].order
|
||||
if (sortOrderNeedsFoldersMDate(groupOrder)) {
|
||||
if (item.folder) {
|
||||
item.mtime = determineModifiedDateForFolder(item.folder)
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
folderItems.sort(function (itA: FolderItemForSorting, itB: FolderItemForSorting) {
|
||||
return compareTwoItems(itA, itB, sortingSpec);
|
||||
|
|
|
@ -31,7 +31,7 @@ target-folder: tricky folder
|
|||
target-folder: /
|
||||
/: Con...
|
||||
/
|
||||
> modified
|
||||
> advanced modified
|
||||
/:
|
||||
< modified
|
||||
/: Ref...
|
||||
|
@ -78,7 +78,7 @@ target-folder: tricky folder
|
|||
target-folder: /
|
||||
/:files Con...
|
||||
/folders
|
||||
> modified
|
||||
> advanced modified
|
||||
/:files
|
||||
< modified
|
||||
/:files Ref...
|
||||
|
@ -163,7 +163,7 @@ const expectedSortSpecsExampleA: { [key: string]: CustomSortSpec } = {
|
|||
type: CustomSortGroupType.ExactPrefix
|
||||
}, {
|
||||
foldersOnly: true,
|
||||
order: CustomSortOrder.byModifiedTimeReverse,
|
||||
order: CustomSortOrder.byModifiedTimeReverseAdvanced,
|
||||
type: CustomSortGroupType.Outsiders
|
||||
}, {
|
||||
filesOnly: true,
|
||||
|
|
|
@ -86,6 +86,7 @@ const OrderLiterals: { [key: string]: CustomSortOrderAscDescPair } = {
|
|||
'a-z': {asc: CustomSortOrder.alphabetical, desc: CustomSortOrder.alphabeticalReverse},
|
||||
'created': {asc: CustomSortOrder.byCreatedTime, desc: CustomSortOrder.byCreatedTimeReverse},
|
||||
'modified': {asc: CustomSortOrder.byModifiedTime, desc: CustomSortOrder.byModifiedTimeReverse},
|
||||
'advanced modified': {asc: CustomSortOrder.byModifiedTimeAdvanced, desc: CustomSortOrder.byModifiedTimeReverseAdvanced},
|
||||
|
||||
// Advanced, for edge cases of secondary sorting, when if regexp match is the same, override the alphabetical sorting by full name
|
||||
'a-z, created': {
|
||||
|
@ -399,7 +400,7 @@ export class SortingSpecProcessor {
|
|||
lineIdx++
|
||||
this.currentEntryLine = entryLine
|
||||
this.currentEntryLineIdx = lineIdx
|
||||
this.currentSortingSpecContainerFilePath = `${folderPath}/${sortingSpecFileName}`
|
||||
this.currentSortingSpecContainerFilePath = `${folderPath === '/' ? '' : folderPath}/${sortingSpecFileName}`
|
||||
this.problemAlreadyReportedForCurrentLine = false
|
||||
|
||||
const trimmedEntryLine: string = entryLine.trim()
|
||||
|
|
Loading…
Reference in New Issue