diff --git a/apps/client/src/widgets/note_tree.ts b/apps/client/src/widgets/note_tree.ts
index a1f477993..24e02286c 100644
--- a/apps/client/src/widgets/note_tree.ts
+++ b/apps/client/src/widgets/note_tree.ts
@@ -153,7 +153,7 @@ const TPL = /*html*/`
const MAX_SEARCH_RESULTS_IN_TREE = 100;
// this has to be hanged on the actual elements to effectively intercept and stop click event
-const cancelClickPropagation: (e: JQuery.ClickEvent) => void = (e) => e.stopPropagation();
+const cancelClickPropagation: (e: JQuery.ClickEvent | MouseEvent) => void = (e) => e.stopPropagation();
// TODO: Fix once we remove Node.js API from public
type Timeout = NodeJS.Timeout | string | number | undefined;
@@ -353,6 +353,7 @@ export default class NoteTreeWidget extends NoteContextAwareWidget {
this.$tree.fancytree({
titlesTabbable: true,
keyboard: true,
+ toggleEffect: false,
extensions: ["dnd5", "clones", "filter"],
source: treeData,
scrollOfs: {
@@ -598,102 +599,7 @@ export default class NoteTreeWidget extends NoteContextAwareWidget {
clones: {
highlightActiveClones: true
},
- async enhanceTitle (
- event: Event,
- data: {
- node: Fancytree.FancytreeNode;
- noteId: string;
- }
- ) {
- const node = data.node;
-
- if (!node.data.noteId) {
- // if there's "non-note" node, then don't enhance
- // this can happen for e.g. "Load error!" node
- return;
- }
-
- const note = await froca.getNote(node.data.noteId, true);
-
- if (!note) {
- return;
- }
-
- const activeNoteContext = appContext.tabManager.getActiveContext();
-
- const $span = $(node.span);
-
- $span.find(".tree-item-button").remove();
- $span.find(".note-indicator-icon").remove();
-
- const isHoistedNote = activeNoteContext && activeNoteContext.hoistedNoteId === note.noteId && note.noteId !== "root";
-
- if (note.hasLabel("workspace") && !isHoistedNote) {
- const $enterWorkspaceButton = $(``).on(
- "click",
- cancelClickPropagation
- );
-
- $span.append($enterWorkspaceButton);
- }
-
- if (note.type === "search") {
- const $refreshSearchButton = $(``).on(
- "click",
- cancelClickPropagation
- );
-
- $span.append($refreshSearchButton);
- }
-
- // TODO: Deduplicate with server's notes.ts#getAndValidateParent
- if (!["search", "launcher"].includes(note.type)
- && !note.isOptions()
- && !note.isLaunchBarConfig()
- && !note.noteId.startsWith("_help")
- ) {
- const $createChildNoteButton = $(``).on(
- "click",
- cancelClickPropagation
- );
-
- $span.append($createChildNoteButton);
- }
-
- if (isHoistedNote) {
- const $unhoistButton = $(``).on("click", cancelClickPropagation);
-
- $span.append($unhoistButton);
- }
-
- // Add clone indicator with tooltip if note has multiple parents
- const parentNotes = note.getParentNotes();
- const realParents = parentNotes.filter(
- (parent) => !["_share", "_lbBookmarks"].includes(parent.noteId) && parent.type !== "search"
- );
-
- if (realParents.length > 1) {
- const parentTitles = realParents.map((p) => p.title).join(", ");
- const tooltipText = realParents.length === 2
- ? t("note_tree.clone-indicator-tooltip-single", { parent: realParents[1].title })
- : t("note_tree.clone-indicator-tooltip", { count: realParents.length, parents: parentTitles });
-
- const $cloneIndicator = $(``);
- $cloneIndicator.attr("title", tooltipText);
- $span.find(".fancytree-title").append($cloneIndicator);
- }
-
- // Add shared indicator with tooltip if note is shared
- if (note.isShared()) {
- const shareId = note.getOwnedLabelValue("shareAlias") || note.noteId;
- const shareUrl = `${location.origin}${location.pathname}share/${shareId}`;
- const tooltipText = t("note_tree.shared-indicator-tooltip-with-url", { url: shareUrl });
-
- const $sharedIndicator = $(``);
- $sharedIndicator.attr("title", tooltipText);
- $span.find(".fancytree-title").append($sharedIndicator);
- }
- },
+ enhanceTitle: buildEnhanceTitle(),
// this is done to automatically lazy load all expanded notes after tree load
loadChildren: (event, data) => {
data.node.visit((subNode) => {
@@ -1886,3 +1792,100 @@ export default class NoteTreeWidget extends NoteContextAwareWidget {
return items;
}
}
+
+function buildEnhanceTitle() {
+ const createChildTemplate = document.createElement("span");
+ createChildTemplate.className = "tree-item-button tn-icon add-note-button bx bx-plus";
+ createChildTemplate.title = t("note_tree.create-child-note");
+ createChildTemplate.addEventListener("click", cancelClickPropagation);
+
+ return async function enhanceTitle(event: Event,
+ data: {
+ node: Fancytree.FancytreeNode;
+ noteId: string;
+ }) {
+ const node = data.node;
+
+ if (!node.data.noteId) {
+ // if there's "non-note" node, then don't enhance
+ // this can happen for e.g. "Load error!" node
+ return;
+ }
+
+ const note = froca.getNoteFromCache(node.data.noteId);
+ if (!note) return;
+
+ const activeNoteContext = appContext.tabManager.getActiveContext();
+
+ const $span = $(node.span);
+
+ $span.find(".tree-item-button").remove();
+ $span.find(".note-indicator-icon").remove();
+
+ const isHoistedNote = activeNoteContext && activeNoteContext.hoistedNoteId === note.noteId && note.noteId !== "root";
+
+ if (note.hasLabel("workspace") && !isHoistedNote) {
+ const $enterWorkspaceButton = $(``).on(
+ "click",
+ cancelClickPropagation
+ );
+
+ $span.append($enterWorkspaceButton);
+ }
+
+ if (note.type === "search") {
+ const $refreshSearchButton = $(``).on(
+ "click",
+ cancelClickPropagation
+ );
+
+ $span.append($refreshSearchButton);
+ }
+
+ // TODO: Deduplicate with server's notes.ts#getAndValidateParent
+ if (!["search", "launcher"].includes(note.type)
+ && !note.isOptions()
+ && !note.isLaunchBarConfig()
+ && !note.noteId.startsWith("_help")
+ ) {
+ node.span.append(createChildTemplate.cloneNode());
+ }
+
+ if (isHoistedNote) {
+ const $unhoistButton = $(``).on("click", cancelClickPropagation);
+
+ $span.append($unhoistButton);
+ }
+
+ // Add clone indicator with tooltip if note has multiple parents
+ const parentNotes = note.getParentNotes();
+ const realParents: FNote[] = [];
+ for (const parent of parentNotes) {
+ if (parent.noteId !== "_share" && parent.noteId !== "_lbBookmarks" && parent.type !== "search") {
+ realParents.push(parent);
+ }
+ }
+
+ if (realParents.length > 1) {
+ const parentTitles = realParents.map((p) => p.title).join(", ");
+ const tooltipText = realParents.length === 2
+ ? t("note_tree.clone-indicator-tooltip-single", { parent: realParents[1].title })
+ : t("note_tree.clone-indicator-tooltip", { count: realParents.length, parents: parentTitles });
+
+ const $cloneIndicator = $(``);
+ $cloneIndicator.attr("title", tooltipText);
+ $span.find(".fancytree-title").append($cloneIndicator);
+ }
+
+ // Add shared indicator with tooltip if note is shared
+ if (note.isShared()) {
+ const shareId = note.getOwnedLabelValue("shareAlias") || note.noteId;
+ const shareUrl = `${location.origin}${location.pathname}share/${shareId}`;
+ const tooltipText = t("note_tree.shared-indicator-tooltip-with-url", { url: shareUrl });
+
+ const $sharedIndicator = $(``);
+ $sharedIndicator.attr("title", tooltipText);
+ $span.find(".fancytree-title").append($sharedIndicator);
+ }
+ };
+}