widgetizing tree WIP

This commit is contained in:
zadam 2020-01-12 11:15:23 +01:00
parent b12e38c231
commit 61474defff
13 changed files with 188 additions and 243 deletions

View File

@ -39,7 +39,7 @@ window.glob.isDesktop = utils.isDesktop;
window.glob.isMobile = utils.isMobile;
// required for CKEditor image upload plugin
window.glob.getActiveNode = treeService.getActiveNode;
window.glob.getActiveNode = () => appContext.getMainNoteTree().getActiveNode();
window.glob.getHeaders = server.getHeaders;
window.glob.showAddLinkDialog = () => import('./dialogs/add_link.js').then(d => d.showDialog());
window.glob.showIncludeNoteDialog = cb => import('./dialogs/include_note.js').then(d => d.showDialog(cb));
@ -134,11 +134,11 @@ $noteTabContainer.on("click", ".export-note-button", function () {
return;
}
import('./dialogs/export.js').then(d => d.showDialog(treeService.getActiveNode(), 'single'));
import('./dialogs/export.js').then(d => d.showDialog(appContext.getMainNoteTree().getActiveNode(), 'single'));
});
$noteTabContainer.on("click", ".import-files-button",
() => import('./dialogs/import.js').then(d => d.showDialog(treeService.getActiveNode())));
() => import('./dialogs/import.js').then(d => d.showDialog(appContext.getMainNoteTree().getActiveNode())));
async function printActiveNote() {
if ($(this).hasClass("disabled")) {

View File

@ -39,7 +39,7 @@ export async function showDialog(nodes) {
}
async function moveNotesTo(notePath) {
const targetNode = await treeService.getNodeFromPath(notePath);
const targetNode = await appContext.getMainNoteTree().getNodeFromPath(notePath);
await treeChangesService.moveToNode(movedNodes, targetNode);

View File

@ -6,6 +6,7 @@ import contextMenuWidget from "./services/context_menu.js";
import treeChangesService from "./services/branches.js";
import utils from "./services/utils.js";
import treeUtils from "./services/tree_utils.js";
import appContext from "./services/app_context.js";
window.glob.isDesktop = utils.isDesktop;
window.glob.isMobile = utils.isMobile;
@ -89,7 +90,7 @@ async function showTree() {
}
$detail.on("click", ".note-menu-button", async e => {
const node = treeService.getActiveNode();
const node = appContext.getMainNoteTree().getActiveNode();
const branch = treeCache.getBranch(node.data.branchId);
const note = await treeCache.getNote(node.data.noteId);
const parentNote = await treeCache.getNote(branch.parentNoteId);

View File

@ -17,11 +17,13 @@ class AppContext {
showWidgets() {
const $leftPane = $("#left-pane");
this.noteTreeWidget = new NoteTreeWidget(this);
this.widgets = [
new GlobalButtonsWidget(this),
new SearchBoxWidget(this),
new SearchResultsWidget(this),
new NoteTreeWidget(this)
this.noteTreeWidget
];
for (const widget of this.widgets) {
@ -30,6 +32,13 @@ class AppContext {
$leftPane.append($widget);
}
}
/**
* @return {NoteTreeWidget}
*/
getMainNoteTree() {
return this.noteTreeWidget;
}
}
const appContext = new AppContext();

View File

@ -10,6 +10,7 @@ import keyboardActionService from "./keyboard_actions.js";
import hoistedNoteService from "./hoisted_note.js";
import treeCache from "./tree_cache.js";
import server from "./server.js";
import appContext from "./app_context.js";
const NOTE_REVISIONS = "../dialogs/note_revisions.js";
const OPTIONS = "../dialogs/options.js";
@ -224,9 +225,7 @@ function registerEntrypoints() {
});
keyboardActionService.setGlobalActionHandler("CloneNotesTo", () => import(CLONE_TO).then(d => {
const activeNode = treeService.getActiveNode();
const selectedOrActiveNodes = treeService.getSelectedOrActiveNodes(activeNode);
const selectedOrActiveNodes = appContext.getMainNoteTree().getSelectedOrActiveNodes();
const noteIds = selectedOrActiveNodes.map(node => node.data.noteId);
@ -234,9 +233,7 @@ function registerEntrypoints() {
}));
keyboardActionService.setGlobalActionHandler("MoveNotesTo", () => import(MOVE_TO).then(d => {
const activeNode = treeService.getActiveNode();
const selectedOrActiveNodes = treeService.getSelectedOrActiveNodes(activeNode);
const selectedOrActiveNodes = appContext.getMainNoteTree().getSelectedOrActiveNodes();
d.showDialog(selectedOrActiveNodes);
}));
@ -259,14 +256,14 @@ function registerEntrypoints() {
});
keyboardActionService.setGlobalActionHandler("EditBranchPrefix", async () => {
const node = treeService.getActiveNode();
const node = appContext.getMainNoteTree().getActiveNode();
const editBranchPrefixDialog = await import("../dialogs/branch_prefix.js");
editBranchPrefixDialog.showDialog(node);
});
keyboardActionService.setGlobalActionHandler("ToggleNoteHoisting", async () => {
const node = treeService.getActiveNode();
const node = appContext.getMainNoteTree().getActiveNode();
hoistedNoteService.getHoistedNoteId().then(async hoistedNoteId => {
if (node.data.noteId === hoistedNoteId) {
@ -283,7 +280,7 @@ function registerEntrypoints() {
});
keyboardActionService.setGlobalActionHandler("SearchInSubtree", () => {
const node = treeService.getActiveNode();
const node = appContext.getMainNoteTree().getActiveNode();
searchNotesService.searchInSubtree(node.data.noteId);
});

View File

@ -11,6 +11,7 @@ import dateNotesService from './date_notes.js';
import StandardWidget from '../widgets/standard_widget.js';
import ws from "./ws.js";
import hoistedNoteService from "./hoisted_note.js";
import appContext from "./app_context.js";
/**
* This is the main frontend API interface for scripts. It's published in the local "api" object.
@ -49,7 +50,7 @@ function FrontendScriptApi(startNote, currentNote, originEntity = null, tabConte
*/
this.activateNote = async (notePath, noteLoadedListener) => {
await treeService.activateNote(notePath, async () => {
await treeService.scrollToActiveNote();
await appContext.getMainNoteTree().scrollToActiveNote();
if (noteLoadedListener) {
noteLoadedListener();

View File

@ -9,6 +9,7 @@ import contextMenuService from "./context_menu.js";
import treeUtils from "./tree_utils.js";
import tabRow from "./tab_row.js";
import keyboardActionService from "./keyboard_actions.js";
import appContext from "./app_context.js";
const $tabContentsContainer = $("#note-tab-container");
const $savedIndicator = $(".saved-indicator");
@ -161,22 +162,20 @@ async function showTab(tabId) {
}
}
const oldActiveNode = treeService.getActiveNode();
const oldActiveNode = appContext.getMainNoteTree().getActiveNode();
if (oldActiveNode) {
oldActiveNode.setActive(false);
}
treeService.clearSelectedNodes();
const newActiveTabContext = getActiveTabContext();
if (newActiveTabContext && newActiveTabContext.notePath) {
const newActiveNode = await treeService.getNodeFromPath(newActiveTabContext.notePath);
const newActiveNode = await appContext.getMainNoteTree().getNodeFromPath(newActiveTabContext.notePath);
if (newActiveNode) {
if (!newActiveNode.isVisible()) {
await treeService.expandToNote(newActiveTabContext.notePath);
await appContext.getMainNoteTree().expandToNote(newActiveTabContext.notePath);
}
newActiveNode.setActive(true, {noEvents: true});
@ -227,7 +226,7 @@ async function loadNoteDetail(origNotePath, options = {}) {
// this is useful when user quickly switches notes (by e.g. holding down arrow) so that we don't
// try to render all those loaded notes one after each other. This only guarantees that correct note
// will be displayed independent of timing
const currentTreeNode = treeService.getActiveNode();
const currentTreeNode = appContext.getMainNoteTree().getActiveNode();
if (!newTab && currentTreeNode && currentTreeNode.data.noteId !== loadedNote.noteId) {
return;
}

View File

@ -2,9 +2,10 @@ import treeService from './tree.js';
import treeCache from "./tree_cache.js";
import server from './server.js';
import toastService from "./toast.js";
import appContext from "./app_context.js";
async function refreshSearch() {
const activeNode = treeService.getActiveNode();
const activeNode = appContext.getMainNoteTree().getActiveNode();
activeNode.load(true);
activeNode.setExpanded(true);

View File

@ -11,50 +11,11 @@ import hoistedNoteService from '../services/hoisted_note.js';
import optionsService from "../services/options.js";
import bundle from "./bundle.js";
import keyboardActionService from "./keyboard_actions.js";
let tree;
function setTree(treeInstance) {
tree = treeInstance;
}
import appContext from "./app_context.js";
let setFrontendAsLoaded;
const frontendLoaded = new Promise(resolve => { setFrontendAsLoaded = resolve; });
/**
* focused & not active node can happen during multiselection where the node is selected but not activated
* (its content is not displayed in the detail)
* @return {FancytreeNode|null}
*/
function getFocusedNode() {
return tree.getFocusNode();
}
/**
* note that if you want to access data like noteId or isProtected, you need to go into "data" property
* @return {FancytreeNode|null}
*/
function getActiveNode() {
return tree.getActiveNode();
}
/** @return {FancytreeNode[]} */
async function getNodesByBranchId(branchId) {
utils.assertArguments(branchId);
const branch = treeCache.getBranch(branchId);
return getNodesByNoteId(branch.noteId).filter(node => node.data.branchId === branchId);
}
/** @return {FancytreeNode[]} */
function getNodesByNoteId(noteId) {
utils.assertArguments(noteId);
const list = tree.getNodesByRef(noteId);
return list ? list : []; // if no nodes with this refKey are found, fancy tree returns null
}
async function setPrefix(branchId, prefix) {
utils.assertArguments(branchId);
@ -62,7 +23,7 @@ async function setPrefix(branchId, prefix) {
branch.prefix = prefix;
for (const node of await getNodesByBranchId(branchId)) {
for (const node of await appContext.getMainNoteTree().getNodesByBranchId(branchId)) {
await setNodeTitleWithPrefix(node);
}
}
@ -78,80 +39,6 @@ async function setNodeTitleWithPrefix(node) {
node.setTitle(utils.escapeHtml(title));
}
/** @return {FancytreeNode} */
async function expandToNote(notePath, expandOpts) {
return await getNodeFromPath(notePath, true, expandOpts);
}
/** @return {FancytreeNode} */
function findChildNode(parentNode, childNoteId) {
let foundChildNode = null;
for (const childNode of parentNode.getChildren()) {
if (childNode.data.noteId === childNoteId) {
foundChildNode = childNode;
break;
}
}
return foundChildNode;
}
/** @return {FancytreeNode} */
async function getNodeFromPath(notePath, expand = false, expandOpts = {}) {
utils.assertArguments(notePath);
const hoistedNoteId = await hoistedNoteService.getHoistedNoteId();
/** @var {FancytreeNode} */
let parentNode = null;
const runPath = await getRunPath(notePath);
if (!runPath) {
console.error("Could not find run path for notePath:", notePath);
return;
}
for (const childNoteId of runPath) {
if (childNoteId === hoistedNoteId) {
// there must be exactly one node with given hoistedNoteId
parentNode = getNodesByNoteId(childNoteId)[0];
continue;
}
// we expand only after hoisted note since before then nodes are not actually present in the tree
if (parentNode) {
if (!parentNode.isLoaded()) {
await parentNode.load();
}
if (expand) {
await parentNode.setExpanded(true, expandOpts);
}
await checkFolderStatus(parentNode);
let foundChildNode = findChildNode(parentNode, childNoteId);
if (!foundChildNode) { // note might be recently created so we'll force reload and try again
await parentNode.load(true);
foundChildNode = findChildNode(parentNode, childNoteId);
if (!foundChildNode) {
ws.logError(`Can't find node for child node of noteId=${childNoteId} for parent of noteId=${parentNode.data.noteId} and hoistedNoteId=${hoistedNoteId}, requested path is ${notePath}`);
return;
}
}
parentNode = foundChildNode;
}
}
return parentNode;
}
/** @return {FancytreeNode} */
async function activateNote(notePath, noteLoadedListener) {
utils.assertArguments(notePath);
@ -180,7 +67,7 @@ async function activateNote(notePath, noteLoadedListener) {
utils.closeActiveDialog();
const node = await expandToNote(notePath);
const node = await appContext.getMainNoteTree().expandToNote(notePath);
if (noteLoadedListener) {
noteDetailService.addDetailLoadedListener(node.data.noteId, noteLoadedListener);
@ -188,8 +75,6 @@ async function activateNote(notePath, noteLoadedListener) {
await node.setActive(true);
clearSelectedNodes();
return node;
}
@ -329,23 +214,6 @@ function getSelectedNodes(stopOnParents = false) {
return tree.getSelectedNodes(stopOnParents);
}
/** @return {FancytreeNode[]} */
function getSelectedOrActiveNodes(node) {
let notes = getSelectedNodes(true);
if (notes.length === 0) {
notes.push(node);
}
return notes;
}
function clearSelectedNodes() {
for (const selectedNode of getSelectedNodes()) {
selectedNode.setSelected(false);
}
}
async function treeInitialized() {
if (noteDetailService.getTabContexts().length > 0) {
// this is just tree reload - tabs are already in place
@ -427,13 +295,15 @@ async function treeInitialized() {
async function reload() {
const notes = await loadTreeData();
const activeNotePath = getActiveNode() !== null ? await treeUtils.getNotePath(getActiveNode()) : null;
const activeNode = appContext.getMainNoteTree().getActiveNode();
await tree.reload(notes);
const activeNotePath = activeNode !== null ? await treeUtils.getNotePath(activeNode) : null;
await appContext.getMainNoteTree().reload(notes);
// reactivate originally activated node, but don't trigger note loading
if (activeNotePath) {
const node = await getNodeFromPath(activeNotePath, true);
const node = await appContext.getMainNoteTree().getNodeFromPath(activeNotePath, true);
await node.setActive(true, {noEvents: true});
}
@ -461,37 +331,8 @@ async function loadTreeData() {
return await treeBuilder.prepareTree();
}
async function collapseTree(node = null) {
if (!node) {
const hoistedNoteId = await hoistedNoteService.getHoistedNoteId();
node = getNodesByNoteId(hoistedNoteId)[0];
}
node.setExpanded(false);
node.visit(node => node.setExpanded(false));
}
function focusTree() {
tree.setFocus();
}
async function scrollToActiveNote() {
const activeContext = noteDetailService.getActiveTabContext();
if (activeContext && activeContext.notePath) {
focusTree();
const node = await expandToNote(activeContext.notePath);
await node.makeVisible({scrollIntoView: true});
node.setFocus();
}
}
function setProtected(noteId, isProtected) {
getNodesByNoteId(noteId).map(node => {
appContext.getMainNoteTree().getNodesByNoteId(noteId).map(node => {
node.data.isProtected = isProtected;
node.toggleClass("protected", isProtected);
});
@ -504,7 +345,7 @@ async function setNoteTitle(noteId, title) {
note.title = title;
for (const clone of getNodesByNoteId(noteId)) {
for (const clone of appContext.getMainNoteTree().getNodesByNoteId(noteId)) {
await setNodeTitleWithPrefix(clone);
}
}
@ -512,7 +353,7 @@ async function setNoteTitle(noteId, title) {
async function createNewTopLevelNote() {
const hoistedNoteId = await hoistedNoteService.getHoistedNoteId();
const rootNode = getNodesByNoteId(hoistedNoteId)[0];
const rootNode = appContext.getMainNoteTree().getNodesByNoteId(hoistedNoteId)[0];
await createNote(rootNode, hoistedNoteId, "into");
}
@ -605,13 +446,11 @@ async function createNote(node, parentNoteId, target, extraOptions = {}) {
await newNode.setActive(true);
}
clearSelectedNodes(); // to unmark previously active node
// need to refresh because original doesn't have methods like .getParent()
newNodeData = getNodesByNoteId(branchEntity.noteId)[0];
newNodeData = appContext.getMainNoteTree().getNodesByNoteId(branchEntity.noteId)[0];
// following for cycle will make sure that also clones of a parent are refreshed
for (const newParentNode of getNodesByNoteId(parentNoteId)) {
for (const newParentNode of appContext.getMainNoteTree().getNodesByNoteId(parentNoteId)) {
if (newParentNode.key === newNodeData.getParent().key) {
// we've added a note into this one so no need to refresh
continue;
@ -619,7 +458,7 @@ async function createNote(node, parentNoteId, target, extraOptions = {}) {
await newParentNode.load(true); // force reload to show up new note
await checkFolderStatus(newParentNode);
await appContext.getMainNoteTree().checkFolderStatus(newParentNode);
}
return {note, branch};
@ -688,7 +527,7 @@ ws.subscribeToOutsideSyncMessages(async syncData => {
});
keyboardActionService.setGlobalActionHandler('CreateNoteAfter', async () => {
const node = getActiveNode();
const node = appContext.getMainNoteTree().getActiveNode();
const parentNoteId = node.data.parentNoteId;
const isProtected = await treeUtils.getParentProtectedStatus(node);
@ -703,7 +542,7 @@ keyboardActionService.setGlobalActionHandler('CreateNoteAfter', async () => {
});
async function createNoteInto(saveSelection = false) {
const node = getActiveNode();
const node = appContext.getMainNoteTree().getActiveNode();
if (node) {
await createNote(node, node.data.noteId, 'into', {
@ -713,15 +552,6 @@ async function createNoteInto(saveSelection = false) {
}
}
async function checkFolderStatus(node) {
const note = await treeCache.getNote(node.data.noteId);
node.folder = note.type === 'search' || note.getChildNoteIds().length > 0;
node.icon = await treeBuilder.getIcon(note);
node.extraClasses = await treeBuilder.getExtraClasses(note);
node.renderTitle();
}
async function reloadNotes(noteIds, activateNotePath = null) {
if (noteIds.length === 0) {
return;
@ -734,7 +564,7 @@ async function reloadNotes(noteIds, activateNotePath = null) {
}
for (const noteId of noteIds) {
for (const node of getNodesByNoteId(noteId)) {
for (const node of appContext.getMainNoteTree().getNodesByNoteId(noteId)) {
const branch = treeCache.getBranch(node.data.branchId, true);
if (!branch) {
@ -743,13 +573,13 @@ async function reloadNotes(noteIds, activateNotePath = null) {
else {
await node.load(true);
await checkFolderStatus(node);
await appContext.getMainNoteTree().checkFolderStatus(node);
}
}
}
if (activateNotePath) {
const node = await getNodeFromPath(activateNotePath);
const node = await appContext.getMainNoteTree().getNodeFromPath(activateNotePath);
if (node && !node.isActive()) {
await node.setActive(true);
@ -763,7 +593,7 @@ keyboardActionService.setGlobalActionHandler('CutIntoNote', () => createNoteInto
keyboardActionService.setGlobalActionHandler('CreateNoteInto', createNoteInto);
keyboardActionService.setGlobalActionHandler('ScrollToActiveNote', scrollToActiveNote);
keyboardActionService.setGlobalActionHandler('ScrollToActiveNote', () => appContext.getMainNoteTree().scrollToActiveNote());
$(window).bind('hashchange', async function() {
if (isNotePathInAddress()) {
@ -784,40 +614,23 @@ async function duplicateNote(noteId, parentNoteId) {
toastService.showMessage(`Note "${origNote.title}" has been duplicated`);
}
function getNodeByKey(key) {
return tree.getNodeByKey(key);
}
frontendLoaded.then(bundle.executeStartupBundles);
export default {
reload,
collapseTree,
setProtected,
activateNote,
getFocusedNode,
getActiveNode,
setNoteTitle,
setPrefix,
createNote,
getSelectedNodes,
getSelectedOrActiveNodes,
clearSelectedNodes,
sortAlphabetically,
loadTreeData,
treeInitialized,
setExpandedToServer,
getNodesByNoteId,
checkFolderStatus,
reloadNotes,
expandToNote,
getNodeFromPath,
resolveNotePath,
getSomeNotePath,
focusTree,
scrollToActiveNote,
createNewTopLevelNote,
duplicateNote,
getNodeByKey,
setTree
getRunPath
};

View File

@ -87,7 +87,7 @@ function getTemplates(treeWidget) {
return false;
},
"AddNoteAboveToSelection": () => {
const node = treeService.getFocusedNode();
const node = treeWidget.getFocusedNode();
if (!node) {
return;

View File

@ -1,4 +1,5 @@
import BasicWidget from "./basic_widget.js";
import appContext from "../services/app_context.js";
const WIDGET_TPL = `
<style>
@ -34,7 +35,7 @@ class GlobalButtonsWidget extends BasicWidget {
$createTopLevelNoteButton.on('click', () => this.trigger('createTopLevelNote'));
$collapseTreeButton.on('click', () => this.trigger('collapseTree'));
$scrollToActiveNoteButton.on('click', () => this.trigger('scrollToActiveNote'));
$scrollToActiveNoteButton.on('click', () => appContext.getMainNoteTree().scrollToActiveNote());
$toggleSearchButton.on('click', () => this.trigger('toggleSearch'));
}
}

View File

@ -12,6 +12,7 @@ import treeCache from "../services/tree_cache.js";
import treeBuilder from "../services/tree_builder.js";
import TreeContextMenu from "../services/tree_context_menu.js";
import treeChangesService from "../services/branches.js";
import ws from "../services/ws.js";
const TPL = `
<style>
@ -47,8 +48,8 @@ export default class NoteTreeWidget extends BasicWidget {
$tree.on("click", ".unhoist-button", hoistedNoteService.unhoist);
$tree.on("click", ".refresh-search-button", searchNotesService.refreshSearch);
// this does not belong here ...
keyboardActionService.setGlobalActionHandler('CollapseTree', () => treeService.collapseTree()); // don't use shortened form since collapseTree() accepts argument
// FIXME this does not belong here ...
keyboardActionService.setGlobalActionHandler('CollapseTree', () => this.collapseTree()); // don't use shortened form since collapseTree() accepts argument
// fancytree doesn't support middle click so this is a way to support it
$widget.on('mousedown', '.fancytree-title', e => {
@ -92,7 +93,7 @@ export default class NoteTreeWidget extends BasicWidget {
else {
node.setActive();
treeService.clearSelectedNodes();
this.clearSelectedNodes();
}
return false;
@ -231,8 +232,6 @@ export default class NoteTreeWidget extends BasicWidget {
});
this.tree = $.ui.fancytree.getTree("#tree");
treeService.setTree(this.tree);
}
/** @return {FancytreeNode[]} */
@ -241,11 +240,11 @@ export default class NoteTreeWidget extends BasicWidget {
}
/** @return {FancytreeNode[]} */
getSelectedOrActiveNodes(node) {
getSelectedOrActiveNodes(node = null) {
let notes = this.getSelectedNodes(true);
if (notes.length === 0) {
notes.push(node);
notes.push(node ? node : this.getActiveNode());
}
return notes;
@ -263,6 +262,13 @@ export default class NoteTreeWidget extends BasicWidget {
node.visit(node => node.setExpanded(false));
}
/**
* @return {FancytreeNode|null}
*/
getActiveNode() {
return this.tree.getActiveNode();
}
/**
* focused & not active node can happen during multiselection where the node is selected but not activated
* (its content is not displayed in the detail)
@ -278,9 +284,125 @@ export default class NoteTreeWidget extends BasicWidget {
}
}
// FIXME since this operates on note details tab context it seems it does not really belong here
async scrollToActiveNote() {
const activeContext = noteDetailService.getActiveTabContext();
if (activeContext && activeContext.notePath) {
this.tree.setFocus();
const node = await this.expandToNote(activeContext.notePath);
await node.makeVisible({scrollIntoView: true});
node.setFocus();
}
}
/** @return {FancytreeNode} */
async getNodeFromPath(notePath, expand = false, expandOpts = {}) {
utils.assertArguments(notePath);
const hoistedNoteId = await hoistedNoteService.getHoistedNoteId();
/** @var {FancytreeNode} */
let parentNode = null;
const runPath = await treeService.getRunPath(notePath);
if (!runPath) {
console.error("Could not find run path for notePath:", notePath);
return;
}
for (const childNoteId of runPath) {
if (childNoteId === hoistedNoteId) {
// there must be exactly one node with given hoistedNoteId
parentNode = this.getNodesByNoteId(childNoteId)[0];
continue;
}
// we expand only after hoisted note since before then nodes are not actually present in the tree
if (parentNode) {
if (!parentNode.isLoaded()) {
await parentNode.load();
}
if (expand) {
await parentNode.setExpanded(true, expandOpts);
}
await this.checkFolderStatus(parentNode);
let foundChildNode = this.findChildNode(parentNode, childNoteId);
if (!foundChildNode) { // note might be recently created so we'll force reload and try again
await parentNode.load(true);
foundChildNode = this.findChildNode(parentNode, childNoteId);
if (!foundChildNode) {
ws.logError(`Can't find node for child node of noteId=${childNoteId} for parent of noteId=${parentNode.data.noteId} and hoistedNoteId=${hoistedNoteId}, requested path is ${notePath}`);
return;
}
}
parentNode = foundChildNode;
}
}
return parentNode;
}
/** @return {FancytreeNode} */
findChildNode(parentNode, childNoteId) {
let foundChildNode = null;
for (const childNode of parentNode.getChildren()) {
if (childNode.data.noteId === childNoteId) {
foundChildNode = childNode;
break;
}
}
return foundChildNode;
}
/** @return {FancytreeNode} */
async expandToNote(notePath, expandOpts) {
return this.getNodeFromPath(notePath, true, expandOpts);
}
async checkFolderStatus(node) {
const note = await treeCache.getNote(node.data.noteId);
node.folder = note.type === 'search' || note.getChildNoteIds().length > 0;
node.icon = await treeBuilder.getIcon(note);
node.extraClasses = await treeBuilder.getExtraClasses(note);
node.renderTitle();
}
/** @return {FancytreeNode[]} */
async getNodesByBranchId(branchId) {
utils.assertArguments(branchId);
const branch = treeCache.getBranch(branchId);
return this.getNodesByNoteId(branch.noteId).filter(node => node.data.branchId === branchId);
}
/** @return {FancytreeNode[]} */
getNodesByNoteId(noteId) {
utils.assertArguments(noteId);
const list = this.tree.getNodesByRef(noteId);
return list ? list : []; // if no nodes with this refKey are found, fancy tree returns null
}
async reload(notes) {
await this.tree.reload(notes);
}
createTopLevelNoteListener() { treeService.createNewTopLevelNote(); }
collapseTreeListener() { this.collapseTree(); }
scrollToActiveNoteListener() { treeService.scrollToActiveNote(); }
}

View File

@ -2,6 +2,7 @@ import BasicWidget from "./basic_widget.js";
import treeService from "../services/tree.js";
import treeCache from "../services/tree_cache.js";
import toastService from "../services/toast.js";
import appContext from "../services/app_context.js";
const helpText = `
<strong>Search tips</strong> - also see <button class="btn btn-sm" type="button" data-help-page="Search">complete help on search</button>
@ -118,7 +119,7 @@ export default class SearchBoxWidget extends BasicWidget {
return;
}
let activeNode = treeService.getActiveNode();
let activeNode = appContext.getMainNoteTree().getActiveNode();
const parentNote = await treeCache.getNote(activeNode.data.noteId);
if (parentNote.type === 'search') {