mirror of
				https://github.com/zadam/trilium.git
				synced 2025-10-31 10:26:08 +01:00 
			
		
		
		
	smaller refactorings in note_tree
This commit is contained in:
		| @@ -30,16 +30,16 @@ function isRootNode(node) { | |||||||
| async function checkNoteAccess(notePath) { | async function checkNoteAccess(notePath) { | ||||||
|     // notePath argument can contain only noteId which is not good when hoisted since |     // notePath argument can contain only noteId which is not good when hoisted since | ||||||
|     // then we need to check the whole note path |     // then we need to check the whole note path | ||||||
|     const runNotePath = await treeService.getRunPath(notePath); |     const resolvedNotePath = await treeService.resolveNotePath(notePath); | ||||||
|  |  | ||||||
|     if (!runNotePath) { |     if (!resolvedNotePath) { | ||||||
|         console.log("Cannot activate " + notePath); |         console.log("Cannot activate " + notePath); | ||||||
|         return false; |         return false; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     const hoistedNoteId = getHoistedNoteId(); |     const hoistedNoteId = getHoistedNoteId(); | ||||||
|  |  | ||||||
|     if (hoistedNoteId !== 'root' && !runNotePath.includes(hoistedNoteId)) { |     if (hoistedNoteId !== 'root' && !resolvedNotePath.includes(hoistedNoteId)) { | ||||||
|         const confirmDialog = await import('../dialogs/confirm.js'); |         const confirmDialog = await import('../dialogs/confirm.js'); | ||||||
|  |  | ||||||
|         if (!await confirmDialog.confirm("Requested note is outside of hoisted note subtree and you must unhoist to access the note. Do you want to proceed with unhoisting?")) { |         if (!await confirmDialog.confirm("Requested note is outside of hoisted note subtree and you must unhoist to access the note. Do you want to proceed with unhoisting?")) { | ||||||
|   | |||||||
| @@ -38,13 +38,12 @@ async function createNoteLink(notePath, options = {}) { | |||||||
|     const $container = $("<span>").append($noteLink); |     const $container = $("<span>").append($noteLink); | ||||||
|  |  | ||||||
|     if (showNotePath) { |     if (showNotePath) { | ||||||
|         notePath = await treeService.resolveNotePath(notePath); |         const resolvedNotePathSegments = await treeService.resolveNotePathToSegments(notePath); | ||||||
|  |  | ||||||
|         if (notePath) { |         if (notePath) { | ||||||
|             const noteIds = notePath.split("/"); |             resolvedNotePathSegments.pop(); // remove last element | ||||||
|             noteIds.pop(); // remove last element |  | ||||||
|  |  | ||||||
|             const parentNotePath = noteIds.join("/").trim(); |             const parentNotePath = resolvedNotePathSegments.join("/").trim(); | ||||||
|  |  | ||||||
|             if (parentNotePath) { |             if (parentNotePath) { | ||||||
|                 $container.append($("<small>").text(" (" + await treeService.getNotePathTitle(parentNotePath) + ")")); |                 $container.append($("<small>").text(" (" + await treeService.getNotePathTitle(parentNotePath) + ")")); | ||||||
|   | |||||||
| @@ -26,25 +26,25 @@ class TabContext extends Component { | |||||||
|  |  | ||||||
|     async setNote(inputNotePath, triggerSwitchEvent = true) { |     async setNote(inputNotePath, triggerSwitchEvent = true) { | ||||||
|         const noteId = treeService.getNoteIdFromNotePath(inputNotePath); |         const noteId = treeService.getNoteIdFromNotePath(inputNotePath); | ||||||
|         let notePath; |         let resolvedNotePath; | ||||||
|  |  | ||||||
|         if ((await treeCache.getNote(noteId)).isDeleted) { |         if ((await treeCache.getNote(noteId)).isDeleted) { | ||||||
|             // no point in trying to resolve canonical notePath |             // no point in trying to resolve canonical notePath | ||||||
|             notePath = inputNotePath; |             resolvedNotePath = inputNotePath; | ||||||
|         } |         } | ||||||
|         else { |         else { | ||||||
|             notePath = await treeService.resolveNotePath(inputNotePath); |             resolvedNotePath = await treeService.resolveNotePath(inputNotePath); | ||||||
|  |  | ||||||
|             if (!notePath) { |             if (!resolvedNotePath) { | ||||||
|                 console.error(`Cannot resolve note path ${inputNotePath}`); |                 console.error(`Cannot resolve note path ${inputNotePath}`); | ||||||
|                 return; |                 return; | ||||||
|             } |             } | ||||||
|  |  | ||||||
|             if (notePath === this.notePath) { |             if (resolvedNotePath === this.notePath) { | ||||||
|                 return; |                 return; | ||||||
|             } |             } | ||||||
|  |  | ||||||
|             if (await hoistedNoteService.checkNoteAccess(notePath) === false) { |             if (await hoistedNoteService.checkNoteAccess(resolvedNotePath) === false) { | ||||||
|                 return; // note is outside of hoisted subtree and user chose not to unhoist |                 return; // note is outside of hoisted subtree and user chose not to unhoist | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| @@ -53,7 +53,7 @@ class TabContext extends Component { | |||||||
|  |  | ||||||
|         utils.closeActiveDialog(); |         utils.closeActiveDialog(); | ||||||
|  |  | ||||||
|         this.notePath = notePath; |         this.notePath = resolvedNotePath; | ||||||
|         this.noteId = noteId; |         this.noteId = noteId; | ||||||
|  |  | ||||||
|         this.autoBookDisabled = false; |         this.autoBookDisabled = false; | ||||||
| @@ -62,7 +62,7 @@ class TabContext extends Component { | |||||||
|  |  | ||||||
|         setTimeout(async () => { |         setTimeout(async () => { | ||||||
|             // we include the note into recent list only if the user stayed on the note at least 5 seconds |             // we include the note into recent list only if the user stayed on the note at least 5 seconds | ||||||
|             if (notePath && notePath === this.notePath) { |             if (resolvedNotePath && resolvedNotePath === this.notePath) { | ||||||
|                 await server.post('recent-notes', { |                 await server.post('recent-notes', { | ||||||
|                     noteId: this.note.noteId, |                     noteId: this.note.noteId, | ||||||
|                     notePath: this.notePath |                     notePath: this.notePath | ||||||
|   | |||||||
| @@ -6,25 +6,25 @@ import hoistedNoteService from '../services/hoisted_note.js'; | |||||||
| import appContext from "./app_context.js"; | import appContext from "./app_context.js"; | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * Accepts notePath which might or might not be valid and returns an existing path as close to the original |  | ||||||
|  * notePath as possible. |  | ||||||
|  * @return {string|null} |  * @return {string|null} | ||||||
|  */ |  */ | ||||||
| async function resolveNotePath(notePath) { | async function resolveNotePath(notePath) { | ||||||
|     const runPath = await getRunPath(notePath); |     const runPath = await resolveNotePathToSegments(notePath); | ||||||
|  |  | ||||||
|     return runPath ? runPath.join("/") : null; |     return runPath ? runPath.join("/") : null; | ||||||
| } | } | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * Accepts notePath and tries to resolve it. Part of the path might not be valid because of note moving (which causes |  * Accepts notePath which might or might not be valid and returns an existing path as close to the original | ||||||
|  |  * notePath as possible. Part of the path might not be valid because of note moving (which causes | ||||||
|  * path change) or other corruption, in that case this will try to get some other valid path to the correct note. |  * path change) or other corruption, in that case this will try to get some other valid path to the correct note. | ||||||
|  * |  * | ||||||
|  * @return {string[]} |  * @return {string[]} | ||||||
|  */ |  */ | ||||||
| async function getRunPath(notePath, logErrors = true) { | async function resolveNotePathToSegments(notePath, logErrors = true) { | ||||||
|     utils.assertArguments(notePath); |     utils.assertArguments(notePath); | ||||||
|  |  | ||||||
|  |     // we might get notePath with the tabId suffix, remove it if present | ||||||
|     notePath = notePath.split("-")[0].trim(); |     notePath = notePath.split("-")[0].trim(); | ||||||
|  |  | ||||||
|     if (notePath.length === 0) { |     if (notePath.length === 0) { | ||||||
| @@ -54,25 +54,23 @@ async function getRunPath(notePath, logErrors = true) { | |||||||
|             const child = await treeCache.getNote(childNoteId); |             const child = await treeCache.getNote(childNoteId); | ||||||
|  |  | ||||||
|             if (!child) { |             if (!child) { | ||||||
|                 console.log("Can't find note " + childNoteId); |                 console.log(`Can't find note ${childNoteId}`); | ||||||
|                 return; |                 return; | ||||||
|             } |             } | ||||||
|  |  | ||||||
|             const parents = child.getParentNotes(); |             const parents = child.getParentNotes(); | ||||||
|  |  | ||||||
|             if (!parents) { |             if (!parents.length) { | ||||||
|                 ws.logError("No parents found for " + childNoteId); |                 if (logErrors) { | ||||||
|  |                     ws.logError(`No parents found for ${childNoteId}`); | ||||||
|  |                 } | ||||||
|  |  | ||||||
|                 return; |                 return; | ||||||
|             } |             } | ||||||
|  |  | ||||||
|             if (!parents.some(p => p.noteId === parentNoteId)) { |             if (!parents.some(p => p.noteId === parentNoteId)) { | ||||||
|                 if (logErrors) { |                 if (logErrors) { | ||||||
|                     console.log(utils.now(), "Did not find parent " + parentNoteId + " for child " + childNoteId); |                     console.log(utils.now(), `Did not find parent ${parentNoteId} for child ${childNoteId}, available parents: ${parents}`); | ||||||
|                 } |  | ||||||
|  |  | ||||||
|                 if (parents.length > 0) { |  | ||||||
|                     if (logErrors) { |  | ||||||
|                         console.log(utils.now(), "Available parents:", parents); |  | ||||||
|                 } |                 } | ||||||
|  |  | ||||||
|                 const someNotePath = getSomeNotePath(parents[0]); |                 const someNotePath = getSomeNotePath(parents[0]); | ||||||
| @@ -89,14 +87,6 @@ async function getRunPath(notePath, logErrors = true) { | |||||||
|  |  | ||||||
|                 break; |                 break; | ||||||
|             } |             } | ||||||
|                 else { |  | ||||||
|                     if (logErrors) { |  | ||||||
|                         console.log("No parents so no run path."); |  | ||||||
|                     } |  | ||||||
|  |  | ||||||
|                     return; |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         effectivePath.push(parentNoteId); |         effectivePath.push(parentNoteId); | ||||||
| @@ -136,7 +126,7 @@ function getSomeNotePath(note) { | |||||||
| } | } | ||||||
|  |  | ||||||
| async function sortAlphabetically(noteId) { | async function sortAlphabetically(noteId) { | ||||||
|     await server.put('notes/' + noteId + '/sort'); |     await server.put(`notes/${noteId}/sort`); | ||||||
| } | } | ||||||
|  |  | ||||||
| ws.subscribeToMessages(message => { | ws.subscribeToMessages(message => { | ||||||
| @@ -238,7 +228,7 @@ async function getNoteTitle(noteId, parentNoteId = null) { | |||||||
|             const branch = treeCache.getBranch(branchId); |             const branch = treeCache.getBranch(branchId); | ||||||
|  |  | ||||||
|             if (branch && branch.prefix) { |             if (branch && branch.prefix) { | ||||||
|                 title = branch.prefix + ' - ' + title; |                 title = `${branch.prefix} - ${title}`; | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| @@ -290,8 +280,8 @@ function parseNotePath(notePath) { | |||||||
| export default { | export default { | ||||||
|     sortAlphabetically, |     sortAlphabetically, | ||||||
|     resolveNotePath, |     resolveNotePath, | ||||||
|  |     resolveNotePathToSegments, | ||||||
|     getSomeNotePath, |     getSomeNotePath, | ||||||
|     getRunPath, |  | ||||||
|     getParentProtectedStatus, |     getParentProtectedStatus, | ||||||
|     getNotePath, |     getNotePath, | ||||||
|     getNoteIdFromNotePath, |     getNoteIdFromNotePath, | ||||||
|   | |||||||
| @@ -303,12 +303,12 @@ export default class NoteTreeWidget extends TabAwareWidget { | |||||||
|         this.$tree.fancytree({ |         this.$tree.fancytree({ | ||||||
|             titlesTabbable: true, |             titlesTabbable: true, | ||||||
|             autoScroll: true, |             autoScroll: true, | ||||||
|             keyboard: false, // we takover keyboard handling in the hotkeys plugin |             keyboard: true, | ||||||
|             extensions: utils.isMobile() ? ["dnd5", "clones"] : ["hotkeys", "dnd5", "clones"], |             extensions: utils.isMobile() ? ["dnd5", "clones"] : ["hotkeys", "dnd5", "clones"], | ||||||
|             source: treeData, |             source: treeData, | ||||||
|             scrollOfs: { |             scrollOfs: { | ||||||
|                 top: 200, |                 top: 100, | ||||||
|                 bottom: 200 |                 bottom: 100 | ||||||
|             }, |             }, | ||||||
|             scrollParent: this.$tree, |             scrollParent: this.$tree, | ||||||
|             minExpandLevel: 2, // root can't be collapsed |             minExpandLevel: 2, // root can't be collapsed | ||||||
| @@ -372,10 +372,7 @@ export default class NoteTreeWidget extends TabAwareWidget { | |||||||
|                     })); |                     })); | ||||||
|  |  | ||||||
|                     data.dataTransfer.setData("text", JSON.stringify(notes)); |                     data.dataTransfer.setData("text", JSON.stringify(notes)); | ||||||
|  |                     return true; // allow dragging to start | ||||||
|                     // This function MUST be defined to enable dragging for the tree. |  | ||||||
|                     // Return false to cancel dragging of node. |  | ||||||
|                     return true; |  | ||||||
|                 }, |                 }, | ||||||
|                 dragEnter: (node, data) => true, // allow drop on any node |                 dragEnter: (node, data) => true, // allow drop on any node | ||||||
|                 dragOver: (node, data) => true, |                 dragOver: (node, data) => true, | ||||||
| @@ -528,6 +525,38 @@ export default class NoteTreeWidget extends TabAwareWidget { | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     async prepareSearchNoteChildren(note) { | ||||||
|  |         await treeCache.reloadNotes([note.noteId]); | ||||||
|  |  | ||||||
|  |         const newNote = await treeCache.getNote(note.noteId); | ||||||
|  |  | ||||||
|  |         return await this.prepareNormalNoteChildren(newNote); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     async prepareNormalNoteChildren(parentNote) { | ||||||
|  |         utils.assertArguments(parentNote); | ||||||
|  |  | ||||||
|  |         const noteList = []; | ||||||
|  |  | ||||||
|  |         const hideArchivedNotes = this.hideArchivedNotes; | ||||||
|  |  | ||||||
|  |         for (const branch of this.getChildBranches(parentNote)) { | ||||||
|  |             if (hideArchivedNotes) { | ||||||
|  |                 const note = await branch.getNote(); | ||||||
|  |  | ||||||
|  |                 if (note.hasLabel('archived')) { | ||||||
|  |                     continue; | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             const node = await this.prepareNode(branch); | ||||||
|  |  | ||||||
|  |             noteList.push(node); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return noteList; | ||||||
|  |     } | ||||||
|  |  | ||||||
|     getIconClass(note) { |     getIconClass(note) { | ||||||
|         const labels = note.getLabels('iconClass'); |         const labels = note.getLabels('iconClass'); | ||||||
|  |  | ||||||
| @@ -631,30 +660,6 @@ export default class NoteTreeWidget extends TabAwareWidget { | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     async prepareNormalNoteChildren(parentNote) { |  | ||||||
|         utils.assertArguments(parentNote); |  | ||||||
|  |  | ||||||
|         const noteList = []; |  | ||||||
|  |  | ||||||
|         const hideArchivedNotes = this.hideArchivedNotes; |  | ||||||
|  |  | ||||||
|         for (const branch of this.getChildBranches(parentNote)) { |  | ||||||
|             if (hideArchivedNotes) { |  | ||||||
|                 const note = await branch.getNote(); |  | ||||||
|  |  | ||||||
|                 if (note.hasLabel('archived')) { |  | ||||||
|                     continue; |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|             const node = await this.prepareNode(branch); |  | ||||||
|  |  | ||||||
|             noteList.push(node); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         return noteList; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     getChildBranches(parentNote) { |     getChildBranches(parentNote) { | ||||||
|         let childBranches = parentNote.getChildBranches(); |         let childBranches = parentNote.getChildBranches(); | ||||||
|  |  | ||||||
| @@ -678,14 +683,6 @@ export default class NoteTreeWidget extends TabAwareWidget { | |||||||
|         return childBranches; |         return childBranches; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     async prepareSearchNoteChildren(note) { |  | ||||||
|         await treeCache.reloadNotes([note.noteId]); |  | ||||||
|  |  | ||||||
|         const newNote = await treeCache.getNote(note.noteId); |  | ||||||
|  |  | ||||||
|         return await this.prepareNormalNoteChildren(newNote); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     getExtraClasses(note) { |     getExtraClasses(note) { | ||||||
|         utils.assertArguments(note); |         utils.assertArguments(note); | ||||||
|  |  | ||||||
| @@ -810,9 +807,9 @@ export default class NoteTreeWidget extends TabAwareWidget { | |||||||
|         /** @const {FancytreeNode} */ |         /** @const {FancytreeNode} */ | ||||||
|         let parentNode = null; |         let parentNode = null; | ||||||
|  |  | ||||||
|         const runPath = await treeService.getRunPath(notePath, logErrors); |         const resolvedNotePathSegments = await treeService.resolveNotePathToSegments(notePath, logErrors); | ||||||
|  |  | ||||||
|         if (!runPath) { |         if (!resolvedNotePathSegments) { | ||||||
|             if (logErrors) { |             if (logErrors) { | ||||||
|                 console.error("Could not find run path for notePath:", notePath); |                 console.error("Could not find run path for notePath:", notePath); | ||||||
|             } |             } | ||||||
| @@ -820,7 +817,7 @@ export default class NoteTreeWidget extends TabAwareWidget { | |||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         for (const childNoteId of runPath) { |         for (const childNoteId of resolvedNotePathSegments) { | ||||||
|             if (childNoteId === hoistedNoteId) { |             if (childNoteId === hoistedNoteId) { | ||||||
|                 // there must be exactly one node with given hoistedNoteId |                 // there must be exactly one node with given hoistedNoteId | ||||||
|                 parentNode = this.getNodesByNoteId(childNoteId)[0]; |                 parentNode = this.getNodesByNoteId(childNoteId)[0]; | ||||||
| @@ -870,16 +867,7 @@ export default class NoteTreeWidget extends TabAwareWidget { | |||||||
|  |  | ||||||
|     /** @return {FancytreeNode} */ |     /** @return {FancytreeNode} */ | ||||||
|     findChildNode(parentNode, childNoteId) { |     findChildNode(parentNode, childNoteId) { | ||||||
|         let foundChildNode = null; |         return parentNode.getChildren().find(childNode => childNode.data.noteId === childNoteId); | ||||||
|  |  | ||||||
|         for (const childNode of parentNode.getChildren()) { |  | ||||||
|             if (childNode.data.noteId === childNoteId) { |  | ||||||
|                 foundChildNode = childNode; |  | ||||||
|                 break; |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         return foundChildNode; |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /** @return {FancytreeNode} */ |     /** @return {FancytreeNode} */ | ||||||
| @@ -1154,6 +1142,9 @@ export default class NoteTreeWidget extends TabAwareWidget { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     async setExpanded(branchId, isExpanded) { |     async setExpanded(branchId, isExpanded) { | ||||||
|  |         console.log("expand", isExpanded); | ||||||
|  |  | ||||||
|  |  | ||||||
|         utils.assertArguments(branchId); |         utils.assertArguments(branchId); | ||||||
|  |  | ||||||
|         const branch = treeCache.getBranch(branchId); |         const branch = treeCache.getBranch(branchId); | ||||||
| @@ -1190,35 +1181,7 @@ export default class NoteTreeWidget extends TabAwareWidget { | |||||||
|  |  | ||||||
|     async getHotKeys() { |     async getHotKeys() { | ||||||
|         const actions = await keyboardActionsService.getActionsForScope('note-tree'); |         const actions = await keyboardActionsService.getActionsForScope('note-tree'); | ||||||
|         const hotKeyMap = { |         const hotKeyMap = {}; | ||||||
|             // code below shouldn't be necessary normally, however there's some problem with interaction with context menu plugin |  | ||||||
|             // after opening context menu, standard shortcuts don't work, but they are detected here |  | ||||||
|             // so we essentially takeover the standard handling with our implementation. |  | ||||||
|             "left": node => { |  | ||||||
|                 node.navigate($.ui.keyCode.LEFT, true); |  | ||||||
|                 this.clearSelectedNodes(); |  | ||||||
|  |  | ||||||
|                 return false; |  | ||||||
|             }, |  | ||||||
|             "right": node => { |  | ||||||
|                 node.navigate($.ui.keyCode.RIGHT, true); |  | ||||||
|                 this.clearSelectedNodes(); |  | ||||||
|  |  | ||||||
|                 return false; |  | ||||||
|             }, |  | ||||||
|             "up": node => { |  | ||||||
|                 node.navigate($.ui.keyCode.UP, true); |  | ||||||
|                 this.clearSelectedNodes(); |  | ||||||
|  |  | ||||||
|                 return false; |  | ||||||
|             }, |  | ||||||
|             "down": node => { |  | ||||||
|                 node.navigate($.ui.keyCode.DOWN, true); |  | ||||||
|                 this.clearSelectedNodes(); |  | ||||||
|  |  | ||||||
|                 return false; |  | ||||||
|             } |  | ||||||
|         }; |  | ||||||
|  |  | ||||||
|         for (const action of actions) { |         for (const action of actions) { | ||||||
|             for (const shortcut of action.effectiveShortcuts) { |             for (const shortcut of action.effectiveShortcuts) { | ||||||
|   | |||||||
| @@ -368,12 +368,12 @@ const DEFAULT_KEYBOARD_ACTIONS = [ | |||||||
|     }, |     }, | ||||||
|     { |     { | ||||||
|         actionName: "zoomOut", |         actionName: "zoomOut", | ||||||
|         defaultShortcuts: ["CommandOrControl+-"], |         defaultShortcuts: isElectron ? ["CommandOrControl+-"] : [], | ||||||
|         scope: "window" |         scope: "window" | ||||||
|     }, |     }, | ||||||
|     { |     { | ||||||
|         actionName: "zoomIn", |         actionName: "zoomIn", | ||||||
|         defaultShortcuts: ["CommandOrControl+="], |         defaultShortcuts: isElectron ? ["CommandOrControl+="] : [], | ||||||
|         scope: "window" |         scope: "window" | ||||||
|     }, |     }, | ||||||
|     { |     { | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user