"use strict"; const noteTree = (function() { const treeEl = $("#tree"); const parentListEl = $("#parent-list"); let startNotePath = null; let notesTreeMap = {}; let parentToChildren = {}; let childToParents = {}; let parentChildToNoteTreeId = {}; let noteIdToTitle = {}; function getNoteTreeId(parentNoteId, childNoteId) { const key = parentNoteId + "-" + childNoteId; // this can return undefined and client code should deal with it somehow return parentChildToNoteTreeId[key]; } function getNoteTitle(noteId, parentNoteId = null) { let title = noteIdToTitle[noteId]; if (!title) { throwError("Can't find title for noteId='" + noteId + "'"); } if (parentNoteId !== null) { const noteTreeId = getNoteTreeId(parentNoteId, noteId); if (noteTreeId) { const noteTree = notesTreeMap[noteTreeId]; if (noteTree.prefix) { title = noteTree.prefix + ' - ' + title; } } } return title; } // note that if you want to access data like note_id or is_protected, you need to go into "data" property function getCurrentNode() { return treeEl.fancytree("getActiveNode"); } function getCurrentNotePath() { const node = getCurrentNode(); return treeUtils.getNotePath(node); } function getCurrentNoteId() { const node = getCurrentNode(); return node ? node.data.note_id : null; } function getCurrentClones() { const noteId = getCurrentNoteId(); if (noteId) { return getNodesByNoteId(noteId); } else { return []; } } function getNodesByNoteTreeId(noteTreeId) { const noteTree = notesTreeMap[noteTreeId]; return getNodesByNoteId(noteTree.note_id).filter(node => node.data.note_tree_id === noteTreeId); } function getNodesByNoteId(noteId) { const list = getTree().getNodesByRef(noteId); return list ? list : []; // if no nodes with this refKey are found, fancy tree returns null } function setPrefix(noteTreeId, prefix) { notesTreeMap[noteTreeId].prefix = prefix; getNodesByNoteTreeId(noteTreeId).map(node => { node.data.prefix = prefix; treeUtils.setNodeTitleWithPrefix(node); }); } function setParentChildRelation(noteTreeId, parentNoteId, childNoteId) { const key = parentNoteId + "-" + childNoteId; parentChildToNoteTreeId[key] = noteTreeId; if (!parentToChildren[parentNoteId]) { parentToChildren[parentNoteId] = []; } parentToChildren[parentNoteId].push(childNoteId); if (!childToParents[childNoteId]) { childToParents[childNoteId] = []; } childToParents[childNoteId].push(parentNoteId); } function prepareNoteTree(notes) { parentToChildren = {}; childToParents = {}; notesTreeMap = {}; for (const note of notes) { notesTreeMap[note.note_tree_id] = note; noteIdToTitle[note.note_id] = note.note_title; delete note.note_title; // this should not be used. Use noteIdToTitle instead setParentChildRelation(note.note_tree_id, note.note_pid, note.note_id); } return prepareNoteTreeInner('root'); } function getExtraClasses(note) { let extraClasses = ''; if (note.is_protected) { extraClasses += ",protected"; } if (childToParents[note.note_id].length > 1) { extraClasses += ",multiple-parents"; } if (extraClasses.startsWith(",")) { extraClasses = extraClasses.substr(1); } return extraClasses; } function prepareNoteTreeInner(parentNoteId) { const childNoteIds = parentToChildren[parentNoteId]; if (!childNoteIds) { messaging.logError("No children for " + parentNoteId + ". This shouldn't happen."); return; } const noteList = []; for (const noteId of childNoteIds) { const noteTreeId = getNoteTreeId(parentNoteId, noteId); const noteTree = notesTreeMap[noteTreeId]; const node = { note_id: noteTree.note_id, note_pid: noteTree.note_pid, note_tree_id: noteTree.note_tree_id, is_protected: noteTree.is_protected, prefix: noteTree.prefix, title: (noteTree.prefix ? (noteTree.prefix + " - ") : "") + noteIdToTitle[noteTree.note_id], extraClasses: getExtraClasses(noteTree), refKey: noteTree.note_id, expanded: noteTree.is_expanded }; if (parentToChildren[noteId] && parentToChildren[noteId].length > 0) { node.folder = true; if (node.expanded) { node.children = prepareNoteTreeInner(noteId); } else { node.lazy = true; } } noteList.push(node); } return noteList; } async function activateNode(notePath) { const runPath = getRunPath(notePath); const noteId = treeUtils.getNoteIdFromNotePath(notePath); let parentNoteId = 'root'; console.log("Run path: ", runPath); for (const childNoteId of runPath) { const node = getNodesByNoteId(childNoteId).find(node => node.data.note_pid === parentNoteId); if (childNoteId === noteId) { await node.setActive(); } else { await node.setExpanded(); } parentNoteId = childNoteId; } } /** * Accepts notePath and tries to resolve it. 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. */ function getRunPath(notePath) { const path = notePath.split("/").reverse(); path.push('root'); const effectivePath = []; let childNoteId = null; let i = 0; while (true) { if (i >= path.length) { break; } const parentNoteId = path[i++]; if (childNoteId !== null) { const parents = childToParents[childNoteId]; if (!parents) { messaging.logError("No parents found for " + childNoteId); return; } if (!parents.includes(parentNoteId)) { console.log("Did not find parent " + parentNoteId + " for child " + childNoteId); if (parents.length > 0) { const pathToRoot = getSomeNotePath(parents[0]).split("/").reverse(); for (const noteId of pathToRoot) { effectivePath.push(noteId); } break; } else { messaging.logError("No parents, can't activate node."); return; } } } if (parentNoteId === 'root') { break; } else { effectivePath.push(parentNoteId); childNoteId = parentNoteId; } } return effectivePath.reverse(); } function showParentList(noteId, node) { const parents = childToParents[noteId]; if (!parents) { throwError("Can't find parents for noteId=" + noteId); } if (parents.length <= 1) { parentListEl.hide(); } else { parentListEl.show(); parentListEl.empty(); const list = $("