diff --git a/__tests__/newFileMenu.spec.ts b/__tests__/newFileMenu.spec.ts
index 8a7054ad..f463b6ea 100644
--- a/__tests__/newFileMenu.spec.ts
+++ b/__tests__/newFileMenu.spec.ts
@@ -1,8 +1,8 @@
-import { describe, expect, test, vi } from 'vitest'
+import { describe, expect, test, vi, afterEach } from 'vitest'
import { NewFileMenu, getNewFileMenu, type Entry } from '../lib/newFileMenu'
import logger from '../lib/utils/logger'
-import { Folder, Permission, View } from '../lib'
+import { Folder, Permission, addNewFileMenuEntry, getNewFileMenuEntries } from '../lib'
describe('NewFileMenu init', () => {
test('Initializing NewFileMenu', () => {
@@ -112,15 +112,22 @@ describe('NewFileMenu addEntry', () => {
id: 123456,
displayName: '123456',
templateName: 'New file.txt',
- iconClass: 'icon-filetype-text',
handler: () => {},
} as unknown as Entry)
- }).toThrowError('Invalid id or displayName property')
+ }).toThrowError('Invalid entry')
expect(() => {
newFileMenu.registerEntry({
- id: 'empty-file',
- displayName: 123456,
+ id: 123456,
+ displayName: '123456',
+ iconSvgInline: '',
+ } as unknown as Entry)
+ }).toThrowError('Invalid entry')
+
+ expect(() => {
+ newFileMenu.registerEntry({
+ id: 123456,
+ displayName: '123456',
templateName: 'New file.txt',
iconClass: 'icon-filetype-text',
handler: () => {},
@@ -130,12 +137,12 @@ describe('NewFileMenu addEntry', () => {
expect(() => {
newFileMenu.registerEntry({
id: 'empty-file',
- displayName: '123456',
- templateName: 123465,
+ displayName: 123456,
+ templateName: 'New file.txt',
iconClass: 'icon-filetype-text',
handler: () => {},
} as unknown as Entry)
- }).toThrowError('Invalid templateName property')
+ }).toThrowError('Invalid id or displayName property')
expect(() => {
newFileMenu.registerEntry({
@@ -163,10 +170,10 @@ describe('NewFileMenu addEntry', () => {
displayName: '123456',
templateName: 'New file.txt',
iconClass: 'icon-filetype-text',
- if: true,
+ enabled: true,
handler: () => {},
} as unknown as Entry)
- }).toThrowError('Invalid if property')
+ }).toThrowError('Invalid enabled property')
expect(() => {
newFileMenu.registerEntry({
@@ -174,17 +181,20 @@ describe('NewFileMenu addEntry', () => {
displayName: '123456',
templateName: 'New file.txt',
iconClass: 'icon-filetype-text',
- handler: 'handler',
+ order: true,
+ handler: () => {},
} as unknown as Entry)
- }).toThrowError('Invalid handler property')
+ }).toThrowError('Invalid order property')
expect(() => {
newFileMenu.registerEntry({
id: 'empty-file',
displayName: '123456',
+ templateName: 'New file.txt',
iconClass: 'icon-filetype-text',
+ handler: 'handler',
} as unknown as Entry)
- }).toThrowError('At least a templateName or a handler must be provided')
+ }).toThrowError('Invalid handler property')
})
})
@@ -245,7 +255,7 @@ describe('NewFileMenu getEntries filter', () => {
displayName: 'Create empty file',
templateName: 'New file',
iconClass: 'icon-file',
- if: folder => (folder.permissions & Permission.CREATE) !== 0,
+ enabled: folder => (folder.permissions & Permission.CREATE) !== 0,
handler: () => {},
}
newFileMenu.registerEntry(entry1)
@@ -255,7 +265,7 @@ describe('NewFileMenu getEntries filter', () => {
displayName: 'Create new markdown file',
templateName: 'New text.md',
iconClass: 'icon-filetype-text',
- if: folder => (folder.permissions & Permission.CREATE) !== 0,
+ enabled: folder => (folder.permissions & Permission.CREATE) !== 0,
handler: () => {},
}
newFileMenu.registerEntry(entry2)
@@ -281,7 +291,7 @@ describe('NewFileMenu getEntries filter', () => {
displayName: 'Create empty file',
templateName: 'New file',
iconClass: 'icon-file',
- if: folder => (folder.permissions & Permission.CREATE) !== 0,
+ enabled: folder => (folder.permissions & Permission.CREATE) !== 0,
handler: () => {},
}
newFileMenu.registerEntry(entry1)
@@ -291,7 +301,7 @@ describe('NewFileMenu getEntries filter', () => {
displayName: 'Create new markdown file',
templateName: 'New text.md',
iconClass: 'icon-filetype-text',
- if: folder => (folder.permissions & Permission.CREATE) !== 0,
+ enabled: folder => (folder.permissions & Permission.CREATE) !== 0,
handler: () => {},
}
newFileMenu.registerEntry(entry2)
@@ -324,7 +334,7 @@ describe('NewFileMenu getEntries filter', () => {
displayName: 'Create new markdown file',
templateName: 'New text.md',
iconClass: 'icon-filetype-text',
- if: folder => (folder.permissions & Permission.CREATE) !== 0,
+ enabled: folder => (folder.permissions & Permission.CREATE) !== 0,
handler: () => {},
}
newFileMenu.registerEntry(entry2)
@@ -343,3 +353,86 @@ describe('NewFileMenu getEntries filter', () => {
expect(entries[0]).toBe(entry1)
})
})
+
+describe('NewFileMenu sort test', () => {
+ afterEach(() => {
+ delete window._nc_newfilemenu
+ })
+
+ test('Specified NewFileMenu order', () => {
+ const entry1 = {
+ id: 'empty-file',
+ displayName: 'Create empty file',
+ templateName: 'New file.txt',
+ iconClass: 'icon-filetype-text',
+ order: 3,
+ handler: () => {},
+ }
+
+ const entry2 = {
+ id: 'image',
+ displayName: 'Create new image',
+ templateName: 'New drawing.png',
+ iconClass: 'icon-filetype-image',
+ order: 2,
+ handler: () => {},
+ }
+
+ const entry3 = {
+ id: 'folder',
+ displayName: 'New folder',
+ templateName: 'New folder',
+ iconClass: 'icon-folder',
+ order: 1,
+ handler: () => {},
+ }
+
+ addNewFileMenuEntry(entry1)
+ addNewFileMenuEntry(entry2)
+ addNewFileMenuEntry(entry3)
+
+ const entries = getNewFileMenuEntries()
+ expect(entries).toHaveLength(3)
+ expect(entries[0]).toBe(entry3)
+ expect(entries[1]).toBe(entry2)
+ expect(entries[2]).toBe(entry1)
+ })
+
+ test('Fallback to displayName', () => {
+ const entry1 = {
+ id: 'empty-file',
+ displayName: 'Create empty file',
+ templateName: 'New file.txt',
+ iconClass: 'icon-filetype-text',
+ handler: () => {},
+ }
+
+ const entry2 = {
+ id: 'image',
+ displayName: 'Create new image',
+ templateName: 'New drawing.png',
+ iconClass: 'icon-filetype-image',
+ order: 1,
+ handler: () => {},
+ }
+
+ const entry3 = {
+ id: 'folder',
+ displayName: 'New folder',
+ templateName: 'New folder',
+ iconClass: 'icon-folder',
+ order: 0,
+ handler: () => {},
+ }
+
+ addNewFileMenuEntry(entry1)
+ addNewFileMenuEntry(entry2)
+ addNewFileMenuEntry(entry3)
+
+ const entries = getNewFileMenuEntries()
+ expect(entries).toHaveLength(3)
+ expect(entries[0]).toBe(entry1)
+ expect(entries[1]).toBe(entry3)
+ expect(entries[2]).toBe(entry2)
+ })
+})
diff --git a/lib/index.ts b/lib/index.ts
index 88f5770f..2c280c0d 100644
--- a/lib/index.ts
+++ b/lib/index.ts
@@ -70,5 +70,10 @@ export const removeNewFileMenuEntry = function(entry: Entry | string) {
*/
export const getNewFileMenuEntries = function(context?: Folder) {
const newFileMenu = getNewFileMenu()
- return newFileMenu.getEntries(context)
+ return newFileMenu.getEntries(context).sort((a: Entry, b: Entry) => {
+ if (a.order !== undefined && b.order !== undefined) {
+ return a.order - b.order
+ }
+ return a.displayName.localeCompare(b.displayName)
+ })
}
diff --git a/lib/newFileMenu.ts b/lib/newFileMenu.ts
index b0287512..f88c310f 100644
--- a/lib/newFileMenu.ts
+++ b/lib/newFileMenu.ts
@@ -26,29 +26,35 @@ import logger from './utils/logger'
export interface Entry {
/** Unique ID */
id: string
+
/** Translatable string displayed in the menu */
displayName: string
- /** Default new file name */
- templateName?: string
+
/**
* Condition wether this entry is shown or not
- * @param {Folder} context the creation context. Usually the current folder
+ * @param context the creation context. Usually the current folder
*/
- if?: (context: Folder) => boolean
+ enabled?: (context: Folder) => boolean
+
/**
* Either iconSvgInline or iconClass must be defined
* Svg as inline string.
*/
iconSvgInline?: string
+
/**
* Existing icon css class
* @deprecated use iconSvgInline instead
*/
iconClass?: string
+
+ /** Order of the entry in the menu */
+ order?: number
+
/**
* Function to be run after creation
- * @param {Folder} context the creation context. Usually the current folder
- * @param {Node[]} content list of file/folders present in the context folder
+ * @param context the creation context. Usually the current folder
+ * @param content list of file/folders present in the context folder
*/
handler: (context: Folder, content: Node[]) => void
}
@@ -83,7 +89,7 @@ export class NewFileMenu {
public getEntries(context?: Folder): Array {
if (context) {
return this._entries
- .filter(entry => typeof entry.if === 'function' ? entry.if(context) : true)
+ .filter(entry => typeof entry.enabled === 'function' ? entry.enabled(context) : true)
}
return this._entries
}
@@ -93,7 +99,7 @@ export class NewFileMenu {
}
private validateEntry(entry: Entry) {
- if (!entry.id || !entry.displayName || !(entry.iconSvgInline || entry.iconClass || entry.handler)) {
+ if (!entry.id || !entry.displayName || !(entry.iconSvgInline || entry.iconClass) || !entry.handler) {
throw new Error('Invalid entry')
}
@@ -107,20 +113,16 @@ export class NewFileMenu {
throw new Error('Invalid icon provided')
}
- if (entry.if !== undefined && typeof entry.if !== 'function') {
- throw new Error('Invalid if property')
- }
-
- if (entry.templateName && typeof entry.templateName !== 'string') {
- throw new Error('Invalid templateName property')
+ if (entry.enabled !== undefined && typeof entry.enabled !== 'function') {
+ throw new Error('Invalid enabled property')
}
- if (entry.handler && typeof entry.handler !== 'function') {
+ if (typeof entry.handler !== 'function') {
throw new Error('Invalid handler property')
}
- if (!entry.templateName && !entry.handler) {
- throw new Error('At least a templateName or a handler must be provided')
+ if ('order' in entry && typeof entry.order !== 'number') {
+ throw new Error('Invalid order property')
}
if (this.getEntryIndex(entry.id) !== -1) {