diff --git a/src/public/app/dialogs/sort_child_notes.js b/src/public/app/dialogs/sort_child_notes.js index 0357dcd2b..f6a28dd5f 100644 --- a/src/public/app/dialogs/sort_child_notes.js +++ b/src/public/app/dialogs/sort_child_notes.js @@ -2,7 +2,23 @@ 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; -export async function showDialog() { utils.openDialog($dialog); + + $form.find('input:first').focus(); } diff --git a/src/public/app/widgets/note_tree.js b/src/public/app/widgets/note_tree.js index cd04c0301..9d7872d3e 100644 --- a/src/public/app/widgets/note_tree.js +++ b/src/public/app/widgets/note_tree.js @@ -1370,7 +1370,7 @@ export default class NoteTreeWidget extends TabAwareWidget { } sortChildNotesCommand({node}) { - import("../dialogs/sort_child_notes.js").then(d => d.showDialog(node)); + 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 473e5598d..8da2832ee 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/dialogs/sort_child_notes.ejs b/src/views/dialogs/sort_child_notes.ejs index 4b37941d8..36c6475e0 100644 --- a/src/views/dialogs/sort_child_notes.ejs +++ b/src/views/dialogs/sort_child_notes.ejs @@ -8,59 +8,45 @@ -
+