Merge branch 'master' into 74-integration-with-bookmarks-core-plugin
# Conflicts: # src/custom-sort/custom-sort.ts
This commit is contained in:
commit
5304c9d601
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"id": "custom-sort",
|
"id": "custom-sort",
|
||||||
"name": "Custom File Explorer sorting",
|
"name": "Custom File Explorer sorting",
|
||||||
"version": "1.7.2",
|
"version": "1.8.0",
|
||||||
"minAppVersion": "0.15.0",
|
"minAppVersion": "0.15.0",
|
||||||
"description": "Allows for manual and automatic, config-driven reordering and sorting of files and folders in File Explorer",
|
"description": "Allows for manual and automatic, config-driven reordering and sorting of files and folders in File Explorer",
|
||||||
"author": "SebastianMC",
|
"author": "SebastianMC",
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "obsidian-custom-sort",
|
"name": "obsidian-custom-sort",
|
||||||
"version": "1.7.2",
|
"version": "1.8.0",
|
||||||
"description": "Custom Sort plugin for Obsidian (https://obsidian.md)",
|
"description": "Custom Sort plugin for Obsidian (https://obsidian.md)",
|
||||||
"main": "main.js",
|
"main": "main.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|
|
@ -73,6 +73,8 @@ export interface CustomSortSpec {
|
||||||
defaultOrder?: CustomSortOrder
|
defaultOrder?: CustomSortOrder
|
||||||
byMetadataField?: string // for 'by-metadata:' if the defaultOrder is by metadata alphabetical or reverse
|
byMetadataField?: string // for 'by-metadata:' if the defaultOrder is by metadata alphabetical or reverse
|
||||||
groups: Array<CustomSortGroup>
|
groups: Array<CustomSortGroup>
|
||||||
|
groupsShadow?: Array<CustomSortGroup> // A shallow copy of groups, used at applying sorting for items in a folder.
|
||||||
|
// Stores folder-specific values (e.g. macros expanded with folder-specific values)
|
||||||
outsidersGroupIdx?: number
|
outsidersGroupIdx?: number
|
||||||
outsidersFilesGroupIdx?: number
|
outsidersFilesGroupIdx?: number
|
||||||
outsidersFoldersGroupIdx?: number
|
outsidersFoldersGroupIdx?: number
|
||||||
|
|
|
@ -707,6 +707,33 @@ describe('determineSortingGroup', () => {
|
||||||
path: 'Some parent folder/References.md'
|
path: 'Some parent folder/References.md'
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
|
it('should consume shadow group instead of group, if shadow is present', () => {
|
||||||
|
// given
|
||||||
|
const file: TFile = mockTFile('gs-123', 'md', 111, MOCK_TIMESTAMP + 222, MOCK_TIMESTAMP + 333);
|
||||||
|
const sortSpec: CustomSortSpec = {
|
||||||
|
targetFoldersPaths: ['/'],
|
||||||
|
groups: [{
|
||||||
|
type: CustomSortGroupType.ExactName,
|
||||||
|
exactText: 'g-123'
|
||||||
|
}],
|
||||||
|
groupsShadow: [{
|
||||||
|
type: CustomSortGroupType.ExactName,
|
||||||
|
exactText: 'gs-123'
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
// when
|
||||||
|
const result = determineSortingGroup(file, sortSpec)
|
||||||
|
|
||||||
|
// then
|
||||||
|
expect(result).toEqual({
|
||||||
|
groupIdx: 0, // This indicates match!
|
||||||
|
isFolder: false,
|
||||||
|
sortString: "gs-123.md",
|
||||||
|
ctime: MOCK_TIMESTAMP + 222,
|
||||||
|
mtime: MOCK_TIMESTAMP + 333,
|
||||||
|
path: 'Some parent folder/gs-123.md'
|
||||||
|
});
|
||||||
|
})
|
||||||
})
|
})
|
||||||
describe('CustomSortGroupType.byMetadataFieldAlphabetical', () => {
|
describe('CustomSortGroupType.byMetadataFieldAlphabetical', () => {
|
||||||
it('should ignore the file item if it has no direct metadata', () => {
|
it('should ignore the file item if it has no direct metadata', () => {
|
||||||
|
|
|
@ -23,7 +23,12 @@ import {
|
||||||
NormalizerFn,
|
NormalizerFn,
|
||||||
RegExpSpec
|
RegExpSpec
|
||||||
} from "./custom-sort-types";
|
} from "./custom-sort-types";
|
||||||
import {isDefined} from "../utils/utils";
|
import {
|
||||||
|
isDefined
|
||||||
|
} from "../utils/utils";
|
||||||
|
import {
|
||||||
|
expandMacros
|
||||||
|
} from "./macros";
|
||||||
import {
|
import {
|
||||||
BookmarksPluginInterface
|
BookmarksPluginInterface
|
||||||
} from "../utils/BookmarksCorePluginSignature";
|
} from "../utils/BookmarksCorePluginSignature";
|
||||||
|
@ -273,7 +278,7 @@ export const determineSortingGroup = function (entry: TFile | TFolder, spec: Cus
|
||||||
for (let idx = 0; idx < numOfGroupsToCheck; idx++) {
|
for (let idx = 0; idx < numOfGroupsToCheck; idx++) {
|
||||||
matchedGroup = null
|
matchedGroup = null
|
||||||
groupIdx = spec.priorityOrder ? spec.priorityOrder[idx] : idx
|
groupIdx = spec.priorityOrder ? spec.priorityOrder[idx] : idx
|
||||||
const group: CustomSortGroup = spec.groups[groupIdx];
|
const group: CustomSortGroup = spec.groupsShadow ? spec.groupsShadow[groupIdx] : spec.groups[groupIdx];
|
||||||
if (group.foldersOnly && aFile) continue;
|
if (group.foldersOnly && aFile) continue;
|
||||||
if (group.filesOnly && aFolder) continue;
|
if (group.filesOnly && aFolder) continue;
|
||||||
const nameForMatching: string = group.matchFilenameWithExt ? entry.name : basename;
|
const nameForMatching: string = group.matchFilenameWithExt ? entry.name : basename;
|
||||||
|
@ -555,6 +560,13 @@ export const determineBookmarksOrderIfNeeded = (folderItems: Array<FolderItemFor
|
||||||
export const folderSort = function (sortingSpec: CustomSortSpec, ctx: ProcessingContext) {
|
export const folderSort = function (sortingSpec: CustomSortSpec, ctx: ProcessingContext) {
|
||||||
let fileExplorer = this.fileExplorer
|
let fileExplorer = this.fileExplorer
|
||||||
|
|
||||||
|
// shallow copy of groups
|
||||||
|
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)
|
||||||
|
|
||||||
const folderItems: Array<FolderItemForSorting> = (sortingSpec.itemsToHide ?
|
const folderItems: Array<FolderItemForSorting> = (sortingSpec.itemsToHide ?
|
||||||
this.file.children.filter((entry: TFile | TFolder) => {
|
this.file.children.filter((entry: TFile | TFolder) => {
|
||||||
return !sortingSpec.itemsToHide!.has(entry.name)
|
return !sortingSpec.itemsToHide!.has(entry.name)
|
||||||
|
|
|
@ -0,0 +1,99 @@
|
||||||
|
import {expandMacros, expandMacrosInString} from "./macros";
|
||||||
|
import * as MacrosModule from './macros'
|
||||||
|
import {CustomSortGroup, CustomSortSpec} from "./custom-sort-types";
|
||||||
|
|
||||||
|
describe('expandMacrosInString', () => {
|
||||||
|
it.each([
|
||||||
|
['', ''],
|
||||||
|
['123', '123'],
|
||||||
|
[' 123 ', ' 123 '],
|
||||||
|
[' Abc{:%parent-folder-name%:}Def ', ' Abc{:%parent-folder-name%:}Def '],
|
||||||
|
['{:%parent-folder-name%:}Def ', '{:%parent-folder-name%:}Def '],
|
||||||
|
[' Abc{:%parent-folder-name%:}', ' Abc{:%parent-folder-name%:}'],
|
||||||
|
[' {:%parent-folder-name%:} xyz {:%parent-folder-name%:}', ' {:%parent-folder-name%:} xyz {:%parent-folder-name%:}'],
|
||||||
|
[' {:%unknown%:} ',' {:%unknown%:} ']
|
||||||
|
])('%s should transform to %s when no parent folder', (source: string, expanded: string) => {
|
||||||
|
const result1 = expandMacrosInString(source)
|
||||||
|
const result2 = expandMacrosInString(source, '')
|
||||||
|
expect(result1).toBe(expanded)
|
||||||
|
expect(result2).toBe(expanded)
|
||||||
|
})
|
||||||
|
it.each([
|
||||||
|
['', ''],
|
||||||
|
['123', '123'],
|
||||||
|
[' 123 ', ' 123 '],
|
||||||
|
[' Abc{:%parent-folder-name%:}Def ', ' AbcSubFolder 5Def '],
|
||||||
|
['{:%parent-folder-name%:}Def ', 'SubFolder 5Def '],
|
||||||
|
[' Abc{:%parent-folder-name%:}', ' AbcSubFolder 5'],
|
||||||
|
[' {:%parent-folder-name%:} xyz {:%parent-folder-name%:}', ' SubFolder 5 xyz {:%parent-folder-name%:}'],
|
||||||
|
[' {:%unknown%:} ',' {:%unknown%:} ']
|
||||||
|
])('%s should transform to %s when parent folder specified', (source: string, expanded: string) => {
|
||||||
|
const PARENT = 'SubFolder 5'
|
||||||
|
const result = expandMacrosInString(source, PARENT)
|
||||||
|
expect(result).toBe(expanded)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
function mockGroup(gprefix: string, group: string, prefix: string, full: string, suffix: string): CustomSortGroup {
|
||||||
|
const g: Partial<CustomSortGroup> = {
|
||||||
|
exactText: gprefix + group + full,
|
||||||
|
exactPrefix: gprefix + group + prefix,
|
||||||
|
exactSuffix: gprefix + group + suffix
|
||||||
|
}
|
||||||
|
return g as CustomSortGroup
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('expandMacros', () => {
|
||||||
|
it('should invoke expand in all relevant text fields on all groups', () => {
|
||||||
|
const sortSpec: Partial<CustomSortSpec> = {
|
||||||
|
groups: [
|
||||||
|
mockGroup('g-', '1-', 'abc', 'def', 'ghi'),
|
||||||
|
mockGroup('g-', '2-', 'abc', 'def', 'ghi'),
|
||||||
|
],
|
||||||
|
groupsShadow: [
|
||||||
|
mockGroup('gs-', '1-', 'abc', 'def', 'ghi'),
|
||||||
|
mockGroup('gs-', '2-', 'abc', 'def', 'ghi'),
|
||||||
|
]
|
||||||
|
}
|
||||||
|
const sp = jest.spyOn(MacrosModule, 'expandMacrosInString')
|
||||||
|
const ParentFolder = 'Parent folder name'
|
||||||
|
expandMacros(sortSpec as CustomSortSpec, ParentFolder)
|
||||||
|
expect(sp).toBeCalledTimes(6)
|
||||||
|
expect(sp).toHaveBeenNthCalledWith(1, 'gs-1-def', ParentFolder)
|
||||||
|
expect(sp).toHaveBeenNthCalledWith(2, 'gs-1-abc', ParentFolder)
|
||||||
|
expect(sp).toHaveBeenNthCalledWith(3, 'gs-1-ghi', ParentFolder)
|
||||||
|
expect(sp).toHaveBeenNthCalledWith(4, 'gs-2-def', ParentFolder)
|
||||||
|
expect(sp).toHaveBeenNthCalledWith(5, 'gs-2-abc', ParentFolder)
|
||||||
|
expect(sp).toHaveBeenNthCalledWith(6, 'gs-2-ghi', ParentFolder)
|
||||||
|
})
|
||||||
|
it('should expand correctly in all relevant text fields on all groups, based on shadow groups', () => {
|
||||||
|
const sortSpec: Partial<CustomSortSpec> = {
|
||||||
|
groups: [
|
||||||
|
mockGroup('g-', '1-', 'abc{:%parent-folder-name%:}', 'de{:%parent-folder-name%:}f', '{:%parent-folder-name%:}ghi'),
|
||||||
|
mockGroup('g-', '2-', '{:%parent-folder-name%:}abc', 'd{:%parent-folder-name%:}ef', 'ghi{:%parent-folder-name%:}'),
|
||||||
|
],
|
||||||
|
groupsShadow: [
|
||||||
|
mockGroup('gs-', '1-', 'abc{:%parent-folder-name%:}', 'de{:%parent-folder-name%:}f', '{:%parent-folder-name%:}ghi'),
|
||||||
|
mockGroup('gs-', '2-', '{:%parent-folder-name%:}abc', 'd{:%parent-folder-name%:}ef', 'ghi{:%parent-folder-name%:}'),
|
||||||
|
]
|
||||||
|
}
|
||||||
|
const originalSortSpec: Partial<CustomSortSpec> = {
|
||||||
|
groups: [...sortSpec.groups!],
|
||||||
|
groupsShadow: [...sortSpec.groupsShadow!]
|
||||||
|
}
|
||||||
|
const ParentFolder = 'Parent folder name'
|
||||||
|
expandMacros(sortSpec as CustomSortSpec, ParentFolder)
|
||||||
|
expect(sortSpec.groups![0].exactText).toBe(originalSortSpec.groups![0].exactText)
|
||||||
|
expect(sortSpec.groups![0].exactPrefix).toBe(originalSortSpec.groups![0].exactPrefix)
|
||||||
|
expect(sortSpec.groups![0].exactSuffix).toBe(originalSortSpec.groups![0].exactSuffix)
|
||||||
|
expect(sortSpec.groups![1].exactText).toBe(originalSortSpec.groups![1].exactText)
|
||||||
|
expect(sortSpec.groups![1].exactPrefix).toBe(originalSortSpec.groups![1].exactPrefix)
|
||||||
|
expect(sortSpec.groups![1].exactSuffix).toBe(originalSortSpec.groups![1].exactSuffix)
|
||||||
|
expect(sortSpec.groupsShadow![0].exactText).toBe('gs-1-deParent folder namef')
|
||||||
|
expect(sortSpec.groupsShadow![0].exactPrefix).toBe('gs-1-abcParent folder name')
|
||||||
|
expect(sortSpec.groupsShadow![0].exactSuffix).toBe('gs-1-Parent folder nameghi')
|
||||||
|
expect(sortSpec.groupsShadow![1].exactText).toBe('gs-2-dParent folder nameef')
|
||||||
|
expect(sortSpec.groupsShadow![1].exactPrefix).toBe('gs-2-Parent folder nameabc')
|
||||||
|
expect(sortSpec.groupsShadow![1].exactSuffix).toBe('gs-2-ghiParent folder name')
|
||||||
|
})
|
||||||
|
})
|
|
@ -0,0 +1,34 @@
|
||||||
|
import {
|
||||||
|
CustomSortSpec
|
||||||
|
} from "./custom-sort-types";
|
||||||
|
|
||||||
|
const MACRO_PREFIX: string = '{:'
|
||||||
|
const MACRO_SUFFIX: string = ':}'
|
||||||
|
|
||||||
|
const PARENT_FOLDER_NAME_PLACEHOLDER: string = '%parent-folder-name%'
|
||||||
|
|
||||||
|
const PARENT_FOLDER_NAME_MACRO: string = MACRO_PREFIX + PARENT_FOLDER_NAME_PLACEHOLDER + MACRO_SUFFIX
|
||||||
|
|
||||||
|
export const expandMacrosInString = function(source: string|undefined, parentFolderName?: string|undefined): string|undefined {
|
||||||
|
if (source && parentFolderName) {
|
||||||
|
return source.replace(PARENT_FOLDER_NAME_MACRO, parentFolderName)
|
||||||
|
} else {
|
||||||
|
return source
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const expandMacros = function(sortingSpec: CustomSortSpec, parentFolderName: string|undefined) {
|
||||||
|
sortingSpec.groupsShadow?.forEach((shadowGroup) => {
|
||||||
|
if (parentFolderName) { // root has no parent folder, ignore relevant macros for the root
|
||||||
|
if (shadowGroup.exactText) {
|
||||||
|
shadowGroup.exactText = expandMacrosInString(shadowGroup.exactText, parentFolderName)
|
||||||
|
}
|
||||||
|
if (shadowGroup.exactPrefix) {
|
||||||
|
shadowGroup.exactPrefix = expandMacrosInString(shadowGroup.exactPrefix, parentFolderName)
|
||||||
|
}
|
||||||
|
if (shadowGroup.exactSuffix) {
|
||||||
|
shadowGroup.exactSuffix = expandMacrosInString(shadowGroup.exactSuffix, parentFolderName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
|
@ -28,4 +28,5 @@
|
||||||
"1.7.0": "0.15.0",
|
"1.7.0": "0.15.0",
|
||||||
"1.7.1": "0.15.0",
|
"1.7.1": "0.15.0",
|
||||||
"1.7.2": "0.15.0"
|
"1.7.2": "0.15.0"
|
||||||
|
"1.8.0": "0.15.0"
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue