diff --git a/src/public/app/dialogs/sort_child_notes.js b/src/public/app/dialogs/sort_child_notes.js
new file mode 100644
index 000000000..f6a28dd5f
--- /dev/null
+++ b/src/public/app/dialogs/sort_child_notes.js
@@ -0,0 +1,24 @@
+import server from "../services/server.js";
+import utils from "../services/utils.js";
+
+const $dialog = $("#sort-child-notes-dialog");
+const $form = $("#sort-child-notes-form");
+
+let parentNoteId = null;
+
+$form.on('submit', async () => {
+ const sortBy = $form.find("input[name='sort-by']:checked").val();
+ const sortDirection = $form.find("input[name='sort-direction']:checked").val();
+
+ await server.put(`notes/${parentNoteId}/sort-children`, {sortBy, sortDirection});
+
+ utils.closeActiveDialog();
+});
+
+export async function showDialog(noteId) {
+ parentNoteId = noteId;
+
+ utils.openDialog($dialog);
+
+ $form.find('input:first').focus();
+}
diff --git a/src/public/app/services/tree_context_menu.js b/src/public/app/services/tree_context_menu.js
index d8ceb5028..8d39e9c5b 100644
--- a/src/public/app/services/tree_context_menu.js
+++ b/src/public/app/services/tree_context_menu.js
@@ -75,7 +75,7 @@ class TreeContextMenu {
{ title: 'Expand subtree ', command: "expandSubtree", uiIcon: "expand", enabled: noSelectedNotes },
{ title: 'Collapse subtree ', command: "collapseSubtree", uiIcon: "collapse", enabled: noSelectedNotes },
{ title: "Force note sync", command: "forceNoteSync", uiIcon: "refresh", enabled: noSelectedNotes },
- { title: 'Sort alphabetically ', command: "sortChildNotes", uiIcon: "empty", enabled: noSelectedNotes && notSearch },
+ { title: 'Sort by ... ', command: "sortChildNotes", uiIcon: "empty", enabled: noSelectedNotes && notSearch },
{ title: 'Recent changes in subtree', command: "recentChangesInSubtree", uiIcon: "history", enabled: noSelectedNotes }
] },
{ title: "----" },
diff --git a/src/public/app/widgets/note_tree.js b/src/public/app/widgets/note_tree.js
index cd81698c5..1b3f4115e 100644
--- a/src/public/app/widgets/note_tree.js
+++ b/src/public/app/widgets/note_tree.js
@@ -1366,7 +1366,7 @@ export default class NoteTreeWidget extends TabAwareWidget {
}
sortChildNotesCommand({node}) {
- treeService.sortAlphabetically(node.data.noteId);
+ import("../dialogs/sort_child_notes.js").then(d => d.showDialog(node.data.noteId));
}
async recentChangesInSubtreeCommand({node}) {
diff --git a/src/routes/api/notes.js b/src/routes/api/notes.js
index 6ebe2369d..370058eaf 100644
--- a/src/routes/api/notes.js
+++ b/src/routes/api/notes.js
@@ -4,6 +4,7 @@ const noteService = require('../../services/notes');
const treeService = require('../../services/tree');
const repository = require('../../services/repository');
const utils = require('../../services/utils');
+const log = require('../../services/log');
const TaskContext = require('../../services/task_context');
function getNote(req) {
@@ -85,10 +86,20 @@ function undeleteNote(req) {
taskContext.taskSucceeded();
}
-function sortNotes(req) {
+function sortChildNotes(req) {
const noteId = req.params.noteId;
+ const {sortBy, sortDirection} = req.body;
- treeService.sortNotesAlphabetically(noteId);
+ log.info(`Sorting ${noteId} children with ${sortBy} ${sortDirection}`);
+
+ const reverse = sortDirection === 'desc';
+
+ if (sortBy === 'title') {
+ treeService.sortNotesByTitle(noteId, false, reverse);
+ }
+ else {
+ treeService.sortNotes(noteId, sortBy, reverse);
+ }
}
function protectNote(req) {
@@ -215,7 +226,7 @@ module.exports = {
deleteNote,
undeleteNote,
createNote,
- sortNotes,
+ sortChildNotes,
protectNote,
setNoteTypeMime,
getRelationMap,
diff --git a/src/routes/routes.js b/src/routes/routes.js
index c333b61c4..006edfbe9 100644
--- a/src/routes/routes.js
+++ b/src/routes/routes.js
@@ -150,7 +150,7 @@ function register(app) {
apiRoute(DELETE, '/api/notes/:noteId', notesApiRoute.deleteNote);
apiRoute(PUT, '/api/notes/:noteId/undelete', notesApiRoute.undeleteNote);
apiRoute(POST, '/api/notes/:parentNoteId/children', notesApiRoute.createNote);
- apiRoute(PUT, '/api/notes/:noteId/sort', notesApiRoute.sortNotes);
+ apiRoute(PUT, '/api/notes/:noteId/sort-children', notesApiRoute.sortChildNotes);
apiRoute(PUT, '/api/notes/:noteId/protect/:isProtected', notesApiRoute.protectNote);
apiRoute(PUT, /\/api\/notes\/(.*)\/type\/(.*)\/mime\/(.*)/, notesApiRoute.setNoteTypeMime);
apiRoute(GET, '/api/notes/:noteId/revisions', noteRevisionsApiRoute.getNoteRevisions);
diff --git a/src/services/backend_script_api.js b/src/services/backend_script_api.js
index 476a2fbc2..fd65bc629 100644
--- a/src/services/backend_script_api.js
+++ b/src/services/backend_script_api.js
@@ -359,7 +359,7 @@ function BackendScriptApi(currentNote, apiParams) {
* @method
* @param {string} parentNoteId - this note's child notes will be sorted
*/
- this.sortNotesAlphabetically = treeService.sortNotesAlphabetically;
+ this.sortNotesByTitle = treeService.sortNotesByTitle;
/**
* This method finds note by its noteId and prefix and either sets it to the given parentNoteId
diff --git a/src/services/handlers.js b/src/services/handlers.js
index 013559851..8bef5c977 100644
--- a/src/services/handlers.js
+++ b/src/services/handlers.js
@@ -31,7 +31,7 @@ eventService.subscribe(eventService.NOTE_TITLE_CHANGED, note => {
for (const parentNote of noteFromCache.parents) {
if (parentNote.hasLabel("sorted")) {
- treeService.sortNotesAlphabetically(parentNote.noteId);
+ treeService.sortNotesByTitle(parentNote.noteId);
}
}
}
@@ -84,14 +84,14 @@ eventService.subscribe(eventService.ENTITY_CREATED, ({ entityName, entity }) =>
noteService.duplicateSubtreeWithoutRoot(templateNote.noteId, note.noteId);
}
else if (entity.type === 'label' && entity.name === 'sorted') {
- treeService.sortNotesAlphabetically(entity.noteId);
+ treeService.sortNotesByTitle(entity.noteId);
if (entity.isInheritable) {
const note = noteCache.notes[entity.noteId];
if (note) {
for (const noteId of note.subtreeNoteIds) {
- treeService.sortNotesAlphabetically(noteId);
+ treeService.sortNotesByTitle(noteId);
}
}
}
diff --git a/src/services/import/zip.js b/src/services/import/zip.js
index 1889b2708..3361b6b2a 100644
--- a/src/services/import/zip.js
+++ b/src/services/import/zip.js
@@ -463,7 +463,7 @@ async function importZip(taskContext, fileBuffer, importRootNote) {
if (!metaFile) {
// if there's no meta file then the notes are created based on the order in that tar file but that
// is usually quite random so we sort the notes in the way they would appear in the file manager
- treeService.sortNotesAlphabetically(noteId, true);
+ treeService.sortNotesByTitle(noteId, true);
}
taskContext.increaseProgressCount();
diff --git a/src/services/tree.js b/src/services/tree.js
index 16a6ac244..46c99e66a 100644
--- a/src/services/tree.js
+++ b/src/services/tree.js
@@ -106,7 +106,7 @@ function loadSubtreeNoteIds(parentNoteId, subtreeNoteIds) {
}
}
-function sortNotesAlphabetically(parentNoteId, directoriesFirst = false) {
+function sortNotesByTitle(parentNoteId, foldersFirst = false, reverse = false) {
sql.transactional(() => {
const notes = sql.getRows(
`SELECT branches.branchId, notes.noteId, title, isProtected,
@@ -120,7 +120,7 @@ function sortNotesAlphabetically(parentNoteId, directoriesFirst = false) {
protectedSessionService.decryptNotes(notes);
notes.sort((a, b) => {
- if (directoriesFirst && ((a.hasChildren && !b.hasChildren) || (!a.hasChildren && b.hasChildren))) {
+ if (foldersFirst && ((a.hasChildren && !b.hasChildren) || (!a.hasChildren && b.hasChildren))) {
// exactly one note of the two is a directory so the sorting will be done based on this status
return a.hasChildren ? -1 : 1;
}
@@ -129,6 +129,10 @@ function sortNotesAlphabetically(parentNoteId, directoriesFirst = false) {
}
});
+ if (reverse) {
+ notes.reverse();
+ }
+
let position = 10;
for (const note of notes) {
@@ -144,6 +148,33 @@ function sortNotesAlphabetically(parentNoteId, directoriesFirst = false) {
});
}
+function sortNotes(parentNoteId, sortBy, reverse = false) {
+ sql.transactional(() => {
+ const notes = repository.getNote(parentNoteId).getChildNotes();
+
+ notes.sort((a, b) => a[sortBy] < b[sortBy] ? -1 : 1);
+
+ if (reverse) {
+ notes.reverse();
+ }
+
+ let position = 10;
+
+ for (const note of notes) {
+ const branch = note.getBranches().find(b => b.parentNoteId === parentNoteId);
+
+ sql.execute("UPDATE branches SET notePosition = ? WHERE branchId = ?",
+ [position, branch.branchId]);
+
+ noteCache.branches[branch.branchId].notePosition = position;
+
+ position += 10;
+ }
+
+ entityChangesService.addNoteReorderingEntityChange(parentNoteId);
+ });
+}
+
/**
* @deprecated - this will be removed in the future
*/
@@ -194,6 +225,7 @@ function setNoteToParent(noteId, prefix, parentNoteId) {
module.exports = {
getNotes,
validateParentChild,
- sortNotesAlphabetically,
+ sortNotesByTitle,
+ sortNotes,
setNoteToParent
};
diff --git a/src/views/desktop.ejs b/src/views/desktop.ejs
index 4823a894a..3b87be91a 100644
--- a/src/views/desktop.ejs
+++ b/src/views/desktop.ejs
@@ -39,6 +39,7 @@
<%- include('dialogs/move_to.ejs') %>
<%- include('dialogs/backend_log.ejs') %>
<%- include('dialogs/include_note.ejs') %>
+<%- include('dialogs/sort_child_notes.ejs') %>