diff --git a/db/main_notes.sql b/db/main_notes.sql index ec14df86e..3268d9c3c 100644 --- a/db/main_notes.sql +++ b/db/main_notes.sql @@ -1,5 +1,5 @@ INSERT INTO notes (note_id, note_title, note_text, is_protected, is_deleted, date_created, date_modified) VALUES ('root', 'root', 'root', 0, 0, '2017-12-22T11:41:07.000Z', '2017-12-22T11:41:07.000Z'); -INSERT INTO notes (note_id, note_title, note_text, is_protected, is_deleted, date_created, date_modified) VALUES ('1Heh2acXfPNt', 'Trilium Demo', '

Welcome to Trilium Notes!

 

This is initial document provided by default Trilium to showcase some of its features and also give you some ideas how you might structure your notes. You can play with it, modify note content and tree structure as you wish.

 

If you need any help, visit Trilium wesite: https://github.com/zadam/trilium

Cleanup

Once you''re finished with experimenting and want to cleanup these pages, you can simply delete them all.

Formatting

Trilium supports classic formatting like italic, bold, bold and italic. Of course you can add links like this one pointing to google.com

Lists

Ordered:

  1. First Item
  2. Second item
    1. First sub-item
    2. Second sub-item

 

Unordered:

Block quotes

Whereof one cannot speak, thereof one must be silent”

– Ludwig Wittgenstein

 

', 0, 0, '2017-12-23T00:46:39.304Z', '2017-12-23T04:08:45.445Z'); +INSERT INTO notes (note_id, note_title, note_text, is_protected, is_deleted, date_created, date_modified) VALUES ('1Heh2acXfPNt', 'Trilium Demo', '

Welcome to Trilium Notes!

 

This is initial document provided by default Trilium to showcase some of its features and also give you some ideas how you might structure your notes. You can play with it, modify note content and tree structure as you wish.

 

If you need any help, visit Trilium website: https://github.com/zadam/trilium

Cleanup

Once you''re finished with experimenting and want to cleanup these pages, you can simply delete them all.

Formatting

Trilium supports classic formatting like italic, bold, bold and italic. Of course you can add links like this one pointing to google.com

Lists

Ordered:

  1. First Item
  2. Second item
    1. First sub-item
    2. Second sub-item

 

Unordered:

Block quotes

Whereof one cannot speak, thereof one must be silent”

– Ludwig Wittgenstein

 

', 0, 0, '2017-12-23T00:46:39.304Z', '2017-12-23T04:08:45.445Z'); INSERT INTO notes (note_id, note_title, note_text, is_protected, is_deleted, date_created, date_modified) VALUES ('3RkyK9LI18dO', 'Journal', '

Expand note on the left pane to see content.

', 0, 0, '2017-12-23T01:20:04.181Z', '2017-12-23T18:07:55.377Z'); INSERT INTO notes (note_id, note_title, note_text, is_protected, is_deleted, date_created, date_modified) VALUES ('L1Ox40M1aEyy', '2016', '

No content.

 

 

 

 

', 0, 0, '2017-12-23T01:20:45.365Z', '2017-12-23T16:40:43.129Z'); INSERT INTO notes (note_id, note_title, note_text, is_protected, is_deleted, date_created, date_modified) VALUES ('HJusZTbBU494', '2017', '

No content.

', 0, 0, '2017-12-23T01:20:50.709Z', '2017-12-23T16:41:03.119Z'); diff --git a/plugins/reddit.js b/plugins/reddit.js index 600ccac77..276eb660b 100644 --- a/plugins/reddit.js +++ b/plugins/reddit.js @@ -176,8 +176,6 @@ karma: ${comment.score}, created at ${dateTimeStr}

` // if there have been no imported comments on this page, there shouldn't be any to import // on the next page since those are older if (listing.data.after && importedComments > 0) { - log.info("Reddit: Importing from next page of comments ..."); - importedComments += await importComments(accountName, listing.data.after); } diff --git a/public/javascripts/context_menu.js b/public/javascripts/context_menu.js index 7f6859958..15c659fa9 100644 --- a/public/javascripts/context_menu.js +++ b/public/javascripts/context_menu.js @@ -141,7 +141,7 @@ const contextMenu = (function() { pasteInto(node); } else if (ui.cmd === "delete") { - treeChanges.deleteNode(node); + treeChanges.deleteNodes(noteTree.getSelectedNodes(true)); } else if (ui.cmd === "collapse-sub-tree") { noteTree.collapseTree(node); diff --git a/public/javascripts/note_tree.js b/public/javascripts/note_tree.js index c4f39fe23..6e6a4c0c3 100644 --- a/public/javascripts/note_tree.js +++ b/public/javascripts/note_tree.js @@ -382,8 +382,8 @@ const noteTree = (function() { recentNotes.addRecentNote(currentNoteTreeId, currentNotePath); } - function getSelectedNodes() { - return getTree().getSelectedNodes(); + function getSelectedNodes(stopOnParents = false) { + return getTree().getSelectedNodes(stopOnParents); } function clearSelectedNodes() { @@ -403,7 +403,7 @@ const noteTree = (function() { const keybindings = { "del": node => { - treeChanges.deleteNode(node); + treeChanges.deleteNodes(getSelectedNodes(true)); }, "ctrl+up": node => { const beforeNode = node.getPrevSibling(); @@ -803,7 +803,7 @@ const noteTree = (function() { $(document).bind('keydown', 'ctrl+del', e => { const node = getCurrentNode(); - treeChanges.deleteNode(node); + treeChanges.deleteNodes([node]); e.preventDefault(); }); diff --git a/public/javascripts/tree_changes.js b/public/javascripts/tree_changes.js index 3a09f9810..960e42930 100644 --- a/public/javascripts/tree_changes.js +++ b/public/javascripts/tree_changes.js @@ -53,30 +53,27 @@ const treeChanges = (function() { } } - async function deleteNode(node) { - if (!confirm('Are you sure you want to delete note "' + node.title + '" and all its sub-notes?')) { + async function deleteNodes(nodes) { + if (nodes.length === 0 || !confirm('Are you sure you want to delete select note(s) and all the sub-notes?')) { return; } - await server.remove('tree/' + node.data.note_tree_id); - - if (!isTopLevelNode(node) && node.getParent().getChildren().length <= 1) { - node.getParent().folder = false; - node.getParent().renderTitle(); + for (const node of nodes) { + await server.remove('tree/' + node.data.note_tree_id); } - let next = node.getNextSibling(); + // following code assumes that nodes contain only top-most selected nodes - getSelectedNodes has been + // called with stopOnParent=true + let next = nodes[nodes.length - 1].getNextSibling(); if (!next) { - next = node.getPrevSibling(); + next = nodes[0].getPrevSibling(); } - if (!next && !isTopLevelNode(node)) { - next = node.getParent(); + if (!next && !isTopLevelNode(nodes[0])) { + next = nodes[0].getParent(); } - node.remove(); - if (next) { // activate next element after this one is deleted so we don't lose focus next.setActive(); @@ -86,7 +83,7 @@ const treeChanges = (function() { noteTree.reload(); - showMessage("Note has been deleted."); + showMessage("Note(s) has been deleted."); } async function moveNodeUpInHierarchy(node) { @@ -127,7 +124,7 @@ const treeChanges = (function() { moveBeforeNode, moveAfterNode, moveToNode, - deleteNode, + deleteNodes, moveNodeUpInHierarchy }; })(); \ No newline at end of file diff --git a/services/consistency_checks.js b/services/consistency_checks.js index 9c73a7422..3ce7f2ebe 100644 --- a/services/consistency_checks.js +++ b/services/consistency_checks.js @@ -121,15 +121,15 @@ async function runAllChecks() { await runCheck(` SELECT - child.note_id + child.note_tree_id FROM - notes_tree - JOIN notes AS child ON child.note_id = notes_tree.note_id - JOIN notes AS parent ON notes_tree.parent_note_id = parent.note_id + notes_tree AS child WHERE - parent.is_deleted = 1 - AND child.is_deleted = 0`, - "Parent note is deleted but child note is not for these child note IDs", errorList); + child.is_deleted = 0 + AND child.parent_note_id != 'root' + AND (SELECT COUNT(*) FROM notes_tree AS parent WHERE parent.note_id = child.parent_note_id + AND parent.is_deleted = 0) = 0`, + "All parent note trees are deleted but child note tree is not for these child note tree IDs", errorList); // we do extra JOIN to eliminate orphan notes without note tree (which are reported separately) await runCheck(` diff --git a/services/notes.js b/services/notes.js index ca6c25f3d..4e2ed933f 100644 --- a/services/notes.js +++ b/services/notes.js @@ -243,6 +243,12 @@ async function updateNote(noteId, newNote, dataKey, sourceId) { } async function deleteNote(noteTreeId, sourceId) { + const noteTree = await sql.getFirstOrNull("SELECT * FROM notes_tree WHERE note_tree_id = ?", [noteTreeId]); + + if (!noteTree || noteTree.is_deleted === 1) { + return; + } + const now = utils.nowDate(); await sql.execute("UPDATE notes_tree SET is_deleted = 1, date_modified = ? WHERE note_tree_id = ?", [now, noteTreeId]);