diff --git a/package-lock.json b/package-lock.json index f6d5ea951..a03901f7f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -557,6 +557,11 @@ "resolved": "https://registry.npmjs.org/@tokenizer/token/-/token-0.1.1.tgz", "integrity": "sha512-XO6INPbZCxdprl+9qa/AAbFFOMzzwqYxpjPgLICrMD6C2FCw6qfJOPcBk6JqqPLSaZ/Qx87qn4rpPmPMwaAK6w==" }, + "@tootallnate/once": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.0.0.tgz", + "integrity": "sha512-KYyTT/T6ALPkIRd2Ge080X/BsXvy9O0hcWTtMWkPvwAwF99+vn6Dv4GzrFT/Nn1LePr+FFDbRXXlqmsy9lw2zA==" + }, "@types/color-name": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz", @@ -4850,22 +4855,13 @@ } }, "http-proxy-agent": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.0.tgz", - "integrity": "sha512-GX0FA6+IcDf4Oxc/FBWgYj4zKgo/DnZrksaG9jyuQLExs6xlX+uI5lcA8ymM3JaZTRrF/4s2UX19wJolyo7OBA==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", + "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==", "requires": { + "@tootallnate/once": "1", "agent-base": "6", "debug": "4" - }, - "dependencies": { - "agent-base": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.0.tgz", - "integrity": "sha512-j1Q7cSCqN+AwrmDd+pzgqc0/NpC655x2bUf5ZjRIO77DcNBFmh+OgRNzF6OKdCC9RSCb19fGd99+bhXFdkRNqw==", - "requires": { - "debug": "4" - } - } } }, "http-signature": { @@ -8726,9 +8722,9 @@ "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==" }, "rimraf": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.1.tgz", - "integrity": "sha512-IQ4ikL8SjBiEDZfk+DFVwqRK8md24RWMEJkdSlgNLkyyAImcjf8SWvU1qFMDOb4igBClbTQ/ugPqXcRwdFTxZw==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", "requires": { "glob": "^7.1.3" }, diff --git a/package.json b/package.json index e2b751e53..f77e1a533 100644 --- a/package.json +++ b/package.json @@ -42,7 +42,7 @@ "helmet": "3.21.2", "html": "1.0.0", "html2plaintext": "2.1.2", - "http-proxy-agent": "4.0.0", + "http-proxy-agent": "4.0.1", "https-proxy-agent": "5.0.0", "image-type": "4.1.0", "imagemin": "7.0.1", @@ -55,11 +55,10 @@ "multer": "1.4.2", "node-abi": "2.14.0", "open": "7.0.2", - "pngjs": "3.4.0", "portscanner": "2.2.0", "rand-token": "0.4.0", "rcedit": "2.1.0", - "rimraf": "3.0.1", + "rimraf": "3.0.2", "sanitize-filename": "1.6.3", "sax": "1.2.4", "semver": "7.1.2", diff --git a/src/public/javascripts/entities/branch.js b/src/public/javascripts/entities/branch.js index b9c8798e1..bbb6d312e 100644 --- a/src/public/javascripts/entities/branch.js +++ b/src/public/javascripts/entities/branch.js @@ -19,6 +19,8 @@ class Branch { this.prefix = row.prefix; /** @param {boolean} */ this.isExpanded = !!row.isExpanded; + /** @param {boolean} */ + this.isDeleted = !!row.isDeleted; } /** @returns {NoteShort} */ diff --git a/src/public/javascripts/services/branches.js b/src/public/javascripts/services/branches.js index 1e54e797a..ad385dc0d 100644 --- a/src/public/javascripts/services/branches.js +++ b/src/public/javascripts/services/branches.js @@ -6,7 +6,7 @@ import hoistedNoteService from "./hoisted_note.js"; import ws from "./ws.js"; async function moveBeforeBranch(branchIdsToMove, beforeBranchId) { - branchIdsToMove = await filterRootNote(branchIdsToMove); + branchIdsToMove = filterRootNote(branchIdsToMove); if (beforeBranchId === 'root') { alert('Cannot move notes before root note.'); @@ -24,11 +24,11 @@ async function moveBeforeBranch(branchIdsToMove, beforeBranchId) { } async function moveAfterBranch(branchIdsToMove, afterBranchId) { - branchIdsToMove = await filterRootNote(branchIdsToMove); + branchIdsToMove = filterRootNote(branchIdsToMove); const afterNote = await treeCache.getBranch(afterBranchId).getNote(); - if (afterNote.noteId === 'root' || afterNote.noteId === await hoistedNoteService.getHoistedNoteId()) { + if (afterNote.noteId === 'root' || afterNote.noteId === hoistedNoteService.getHoistedNoteId()) { alert('Cannot move notes after root note.'); return; } @@ -46,12 +46,12 @@ async function moveAfterBranch(branchIdsToMove, afterBranchId) { } async function moveToParentNote(branchIdsToMove, newParentNoteId) { - branchIdsToMove = await filterRootNote(branchIdsToMove); + branchIdsToMove = filterRootNote(branchIdsToMove); for (const branchIdToMove of branchIdsToMove) { const branchToMove = treeCache.getBranch(branchIdToMove); - if (branchToMove.noteId === await hoistedNoteService.getHoistedNoteId() + if (branchToMove.noteId === hoistedNoteService.getHoistedNoteId() || (await branchToMove.getParentNote()).type === 'search') { continue; } @@ -66,7 +66,7 @@ async function moveToParentNote(branchIdsToMove, newParentNoteId) { } async function deleteNodes(branchIdsToDelete) { - branchIdsToDelete = await filterRootNote(branchIdsToDelete); + branchIdsToDelete = filterRootNote(branchIdsToDelete); if (branchIdsToDelete.length === 0) { return false; @@ -123,8 +123,8 @@ async function deleteNodes(branchIdsToDelete) { } async function moveNodeUpInHierarchy(node) { - if (await hoistedNoteService.isRootNode(node) - || await hoistedNoteService.isTopLevelNode(node) + if (hoistedNoteService.isRootNode(node) + || hoistedNoteService.isTopLevelNode(node) || node.getParent().data.noteType === 'search') { return; } @@ -136,14 +136,14 @@ async function moveNodeUpInHierarchy(node) { return; } - if (!await hoistedNoteService.isTopLevelNode(node) && node.getParent().getChildren().length <= 1) { + if (!hoistedNoteService.isTopLevelNode(node) && node.getParent().getChildren().length <= 1) { node.getParent().folder = false; node.getParent().renderTitle(); } } -async function filterRootNote(branchIds) { - const hoistedNoteId = await hoistedNoteService.getHoistedNoteId(); +function filterRootNote(branchIds) { + const hoistedNoteId = hoistedNoteService.getHoistedNoteId(); return branchIds.filter(branchId => { const branch = treeCache.getBranch(branchId); diff --git a/src/public/javascripts/services/entrypoints.js b/src/public/javascripts/services/entrypoints.js index be8efa8a2..d2b17b24a 100644 --- a/src/public/javascripts/services/entrypoints.js +++ b/src/public/javascripts/services/entrypoints.js @@ -77,21 +77,20 @@ export default class Entrypoints extends Component { appContext.trigger('focusAndSelectTitle'); } - toggleNoteHoistingListener() { + async toggleNoteHoistingListener() { const note = appContext.tabManager.getActiveTabNote(); - hoistedNoteService.getHoistedNoteId().then(async hoistedNoteId => { - if (note.noteId === hoistedNoteId) { - hoistedNoteService.unhoist(); - } - else { - const note = await treeCache.getNote(note.noteId); + const hoistedNoteId = hoistedNoteService.getHoistedNoteId(); + if (note.noteId === hoistedNoteId) { + hoistedNoteService.unhoist(); + } + else { + const note = await treeCache.getNote(note.noteId); - if (note.type !== 'search') { - hoistedNoteService.setHoistedNoteId(note.noteId); - } + if (note.type !== 'search') { + hoistedNoteService.setHoistedNoteId(note.noteId); } - }); + } } copyWithoutFormattingListener() { diff --git a/src/public/javascripts/services/hoisted_note.js b/src/public/javascripts/services/hoisted_note.js index 3d74d1d56..cbc444cf7 100644 --- a/src/public/javascripts/services/hoisted_note.js +++ b/src/public/javascripts/services/hoisted_note.js @@ -17,14 +17,14 @@ async function unhoist() { await setHoistedNoteId('root'); } -async function isTopLevelNode(node) { - return await isRootNode(node.getParent()); +function isTopLevelNode(node) { + return isRootNode(node.getParent()); } -async function isRootNode(node) { +function isRootNode(node) { // even though check for 'root' should not be necessary, we keep it just in case return node.data.noteId === "root" - || node.data.noteId === await getHoistedNoteId(); + || node.data.noteId === getHoistedNoteId(); } async function checkNoteAccess(notePath) { @@ -37,7 +37,7 @@ async function checkNoteAccess(notePath) { return false; } - const hoistedNoteId = await getHoistedNoteId(); + const hoistedNoteId = getHoistedNoteId(); if (hoistedNoteId !== 'root' && !runNotePath.includes(hoistedNoteId)) { const confirmDialog = await import('../dialogs/confirm.js'); diff --git a/src/public/javascripts/services/note_create.js b/src/public/javascripts/services/note_create.js index d5d45e278..24501f10c 100644 --- a/src/public/javascripts/services/note_create.js +++ b/src/public/javascripts/services/note_create.js @@ -8,7 +8,7 @@ import treeCache from "./tree_cache.js"; import toastService from "./toast.js"; async function createNewTopLevelNote() { - const hoistedNoteId = await hoistedNoteService.getHoistedNoteId(); + const hoistedNoteId = hoistedNoteService.getHoistedNoteId(); await createNote(hoistedNoteId); } diff --git a/src/public/javascripts/services/tree.js b/src/public/javascripts/services/tree.js index 29f3b2e8c..05a7ca2cb 100644 --- a/src/public/javascripts/services/tree.js +++ b/src/public/javascripts/services/tree.js @@ -37,7 +37,7 @@ async function getRunPath(notePath) { path.push('root'); } - const hoistedNoteId = await hoistedNoteService.getHoistedNoteId(); + const hoistedNoteId = hoistedNoteService.getHoistedNoteId(); const effectivePath = []; let childNoteId = null; @@ -144,8 +144,8 @@ ws.subscribeToMessages(message => { } }); -async function getParentProtectedStatus(node) { - return await hoistedNoteService.isRootNode(node) ? 0 : node.getParent().data.isProtected; +function getParentProtectedStatus(node) { + return hoistedNoteService.isRootNode(node) ? 0 : node.getParent().data.isProtected; } function getNoteIdFromNotePath(notePath) { @@ -184,7 +184,7 @@ function getNoteIdAndParentIdFromNotePath(notePath) { } } -async function getNotePath(node) { +function getNotePath(node) { if (!node) { console.error("Node is null"); return ""; @@ -192,7 +192,7 @@ async function getNotePath(node) { const path = []; - while (node && !await hoistedNoteService.isRootNode(node)) { + while (node && !hoistedNoteService.isRootNode(node)) { if (node.data.noteId) { path.push(node.data.noteId); } diff --git a/src/public/javascripts/services/tree_builder.js b/src/public/javascripts/services/tree_builder.js index be9d3fd1a..896bbccea 100644 --- a/src/public/javascripts/services/tree_builder.js +++ b/src/public/javascripts/services/tree_builder.js @@ -6,7 +6,7 @@ import hoistedNoteService from "./hoisted_note.js"; async function prepareTree() { await treeCache.initializedPromise; - const hoistedNoteId = await hoistedNoteService.getHoistedNoteId(); + const hoistedNoteId = hoistedNoteService.getHoistedNoteId(); let hoistedBranch; @@ -47,7 +47,7 @@ async function getIconClass(note) { } async function getIcon(note) { - const hoistedNoteId = await hoistedNoteService.getHoistedNoteId(); + const hoistedNoteId = hoistedNoteService.getHoistedNoteId(); const iconClass = await getIconClass(note); @@ -81,7 +81,7 @@ async function prepareNode(branch) { } const title = (branch.prefix ? (branch.prefix + " - ") : "") + note.title; - const hoistedNoteId = await hoistedNoteService.getHoistedNoteId(); + const hoistedNoteId = hoistedNoteService.getHoistedNoteId(); const node = { noteId: note.noteId, diff --git a/src/public/javascripts/services/tree_context_menu.js b/src/public/javascripts/services/tree_context_menu.js index a4f1b8bfd..3a2793c99 100644 --- a/src/public/javascripts/services/tree_context_menu.js +++ b/src/public/javascripts/services/tree_context_menu.js @@ -36,7 +36,7 @@ class TreeContextMenu { const branch = treeCache.getBranch(this.node.data.branchId); const parentNote = await treeCache.getNote(branch.parentNoteId); const isNotRoot = note.noteId !== 'root'; - const isHoisted = note.noteId === await hoistedNoteService.getHoistedNoteId(); + const isHoisted = note.noteId === hoistedNoteService.getHoistedNoteId(); // some actions don't support multi-note so they are disabled when notes are selected // the only exception is when the only selected note is the one that was right-clicked, then @@ -99,7 +99,7 @@ class TreeContextMenu { async selectContextMenuItem(event, cmd) { const noteId = this.node.data.noteId; - const notePath = await treeService.getNotePath(this.node); + const notePath = treeService.getNotePath(this.node); if (cmd === 'openInTab') { const tabContext = appContext.tabManager.openEmptyTab(); @@ -188,7 +188,7 @@ class TreeContextMenu { else if (cmd === "duplicateNote") { const branch = treeCache.getBranch(this.node.data.branchId); - treeService.duplicateNote(noteId, branch.parentNoteId); + noteCreateService.duplicateNote(noteId, branch.parentNoteId); } else if (cmd === "searchInSubtree") { appContext.trigger("searchInSubtree", {noteId}); diff --git a/src/public/javascripts/services/tree_keybindings.js b/src/public/javascripts/services/tree_keybindings.js index 918d7326f..bbd77aadb 100644 --- a/src/public/javascripts/services/tree_keybindings.js +++ b/src/public/javascripts/services/tree_keybindings.js @@ -171,8 +171,8 @@ function getTemplates(treeWidget) { return false; }, - "ActivateParentNote": async node => { - if (!await hoistedNoteService.isRootNode(node)) { + "ActivateParentNote": node => { + if (!hoistedNoteService.isRootNode(node)) { node.getParent().setActive().then(treeWidget.clearSelectedNodes); } } diff --git a/src/public/javascripts/widgets/note_tree.js b/src/public/javascripts/widgets/note_tree.js index 787b1464d..bbfc42b49 100644 --- a/src/public/javascripts/widgets/note_tree.js +++ b/src/public/javascripts/widgets/note_tree.js @@ -48,12 +48,12 @@ export default class NoteTreeWidget extends TabAwareWidget { if (e.which === 2) { const node = $.ui.fancytree.getNode(e); - treeService.getNotePath(node).then(notePath => { - if (notePath) { - const tabContext = this.tabManager.openEmptyTab(); - tabContext.setNote(notePath); - } - }); + const notePath = treeService.getNotePath(node); + + if (notePath) { + const tabContext = this.tabManager.openEmptyTab(); + tabContext.setNote(notePath); + } e.stopPropagation(); e.preventDefault(); @@ -86,7 +86,8 @@ export default class NoteTreeWidget extends TabAwareWidget { } else if (event.ctrlKey) { const tabContext = this.tabManager.openEmptyTab(); - treeService.getNotePath(node).then(notePath => tabContext.setNote(notePath)); + const notePath = treeService.getNotePath(node); + tabContext.setNote(notePath); this.tabManager.activateTab(tabContext.tabId); } else { @@ -102,7 +103,7 @@ export default class NoteTreeWidget extends TabAwareWidget { // click event won't propagate so let's close context menu manually contextMenuWidget.hideContextMenu(); - const notePath = await treeService.getNotePath(data.node); + const notePath = treeService.getNotePath(data.node); const activeTabContext = this.tabManager.getActiveTabContext(); await activeTabContext.setNote(notePath); @@ -194,7 +195,7 @@ export default class NoteTreeWidget extends TabAwareWidget { const $span = $(node.span); if (node.data.noteId !== 'root' - && node.data.noteId === await hoistedNoteService.getHoistedNoteId() + && node.data.noteId === hoistedNoteService.getHoistedNoteId() && $span.find('.unhoist-button').length === 0) { const unhoistButton = $('  (unhoist)'); @@ -249,9 +250,9 @@ export default class NoteTreeWidget extends TabAwareWidget { return notes; } - async collapseTree(node = null) { + collapseTree(node = null) { if (!node) { - const hoistedNoteId = await hoistedNoteService.getHoistedNoteId(); + const hoistedNoteId = hoistedNoteService.getHoistedNoteId(); node = this.getNodesByNoteId(hoistedNoteId)[0]; } @@ -300,7 +301,7 @@ export default class NoteTreeWidget extends TabAwareWidget { async getNodeFromPath(notePath, expand = false, expandOpts = {}) { utils.assertArguments(notePath); - const hoistedNoteId = await hoistedNoteService.getHoistedNoteId(); + const hoistedNoteId = hoistedNoteService.getHoistedNoteId(); /** @var {FancytreeNode} */ let parentNode = null; @@ -457,20 +458,24 @@ export default class NoteTreeWidget extends TabAwareWidget { for (const branch of loadResults.getBranches()) { for (const node of this.getNodesByBranchId(branch.branchId)) { if (branch.isDeleted) { + node.data.toBeRemoved = true; + if (node.isActive()) { - let newActive = node.getNextSibling(); + let curNode = node; - if (!newActive) { - newActive = node.getPrevSibling(); + while (curNode.data.toBeRemoved) { + if (curNode.getNextSibling() && !curNode.getNextSibling().data.toBeRemoved) { + curNode = curNode.getNextSibling(); + } + else if (curNode.getPrevSibling() && !curNode.getPrevSibling().data.toBeRemoved) { + curNode = curNode.getPrevSibling(); + } + else { + curNode = curNode.getParent(); + } } - if (!newActive) { - newActive = node.getParent(); - } - - const notePath = await treeService.getNotePath(newActive); - - this.tabManager.getActiveTabContext().setNote(notePath); + curNode.setActive(true, {noEvents:true, noFocus:true}); } noteIdsToReload.add(branch.parentNoteId); @@ -495,6 +500,9 @@ export default class NoteTreeWidget extends TabAwareWidget { } } + const activeNode = this.getActiveNode(); + const activeNotePath = activeNode ? treeService.getNotePath(activeNode) : null; + for (const noteId of loadResults.getNoteIds()) { noteIdsToUpdate.add(noteId); } @@ -530,14 +538,8 @@ export default class NoteTreeWidget extends TabAwareWidget { } } - const activateNotePath = this.tabManager.getActiveTabNotePath(); - - if (activateNotePath) { - const node = await this.getNodeFromPath(activateNotePath); - - if (node && !node.isActive()) { - await node.setActive(true); - } + if (activeNotePath) { + this.tabManager.getActiveTabContext().setNote(activeNotePath); } } @@ -546,7 +548,7 @@ export default class NoteTreeWidget extends TabAwareWidget { const parentNoteId = node.data.parentNoteId; const isProtected = await treeService.getParentProtectedStatus(node); - if (node.data.noteId === 'root' || node.data.noteId === await hoistedNoteService.getHoistedNoteId()) { + if (node.data.noteId === 'root' || node.data.noteId === hoistedNoteService.getHoistedNoteId()) { return; } @@ -593,7 +595,7 @@ export default class NoteTreeWidget extends TabAwareWidget { const activeNode = this.getActiveNode(); - const activeNotePath = activeNode !== null ? await treeService.getNotePath(activeNode) : null; + const activeNotePath = activeNode !== null ? treeService.getNotePath(activeNode) : null; await this.reload(notes); diff --git a/src/services/ws.js b/src/services/ws.js index c0b838ac4..8ce2ca9a9 100644 --- a/src/services/ws.js +++ b/src/services/ws.js @@ -99,7 +99,7 @@ async function fillInAdditionalProperties(sync) { async function sendPing(client) { const syncRows = cls.getSyncRows() - .filter(r => r.entityName !== 'recent_notes'); // only noise ... + .filter(r => r.entityName !== 'recent_notes' && (r.entityName !== 'options' || r.entityId !== 'openTabs')); // only noise ... for (const sync of syncRows) { try {