diff --git a/src/public/app/components/app_context.ts b/src/public/app/components/app_context.ts index 549f465bf..1997315d4 100644 --- a/src/public/app/components/app_context.ts +++ b/src/public/app/components/app_context.ts @@ -24,7 +24,7 @@ interface Layout { } interface RootWidget extends Component { - render: () => JQuery; + render: () => JQuery; } interface BeforeUploadListener extends Component { @@ -61,7 +61,7 @@ type CommandMappings = { showConfirmDialog: ConfirmWithMessageOptions; openNewNoteSplit: CommandData & { ntxId: string; - notePath: string; + notePath: string; }; executeInActiveNoteDetailWidget: CommandData & { callback: (value: NoteDetailWidget | PromiseLike) => void @@ -69,11 +69,12 @@ type CommandMappings = { addTextToActiveEditor: CommandData & { text: string; }; - + importMarkdownInline: CommandData; showPasswordNotSet: CommandData; showProtectedSessionPasswordDialog: CommandData; closeProtectedSessionPasswordDialog: CommandData; + resetLauncher: CommandData; } type EventMappings = { diff --git a/src/public/app/components/events.ts b/src/public/app/components/events.ts new file mode 100644 index 000000000..bc60de92f --- /dev/null +++ b/src/public/app/components/events.ts @@ -0,0 +1,7 @@ +import { MenuCommandItem } from "../menus/context_menu.js"; + +type ListenerReturnType = void | Promise; + +export interface SelectMenuItemEventListener { + selectMenuItemHandler(item: MenuCommandItem): ListenerReturnType; +} diff --git a/src/public/app/menus/launcher_context_menu.js b/src/public/app/menus/launcher_context_menu.ts similarity index 73% rename from src/public/app/menus/launcher_context_menu.js rename to src/public/app/menus/launcher_context_menu.ts index b2fa40df8..eda0c5c14 100644 --- a/src/public/app/menus/launcher_context_menu.js +++ b/src/public/app/menus/launcher_context_menu.ts @@ -1,21 +1,28 @@ -import treeService from '../services/tree.js'; +import treeService, { Node } from '../services/tree.js'; import froca from "../services/froca.js"; -import contextMenu from "./context_menu.js"; +import contextMenu, { MenuCommandItem, MenuItem } from "./context_menu.js"; import dialogService from "../services/dialog.js"; import server from "../services/server.js"; import { t } from '../services/i18n.js'; +import type { SelectMenuItemEventListener } from '../components/events.js'; +import NoteTreeWidget from '../widgets/note_tree.js'; -export default class LauncherContextMenu { - /** - * @param {NoteTreeWidget} treeWidget - * @param {FancytreeNode} node - */ - constructor(treeWidget, node) { +interface ShowContext { + pageX: number; + pageY: number; +} + +export default class LauncherContextMenu implements SelectMenuItemEventListener { + + private treeWidget: NoteTreeWidget; + private node: Node; + + constructor(treeWidget: NoteTreeWidget, node: Node) { this.treeWidget = treeWidget; this.node = node; } - async show(e) { + async show(e: ShowContext) { contextMenu.show({ x: e.pageX, y: e.pageY, @@ -24,17 +31,17 @@ export default class LauncherContextMenu { }) } - async getMenuItems() { - const note = await froca.getNote(this.node.data.noteId); + async getMenuItems(): Promise { + const note = this.node.data.noteId ? await froca.getNote(this.node.data.noteId) : null; const parentNoteId = this.node.getParent().data.noteId; - const isVisibleRoot = note.noteId === '_lbVisibleLaunchers'; - const isAvailableRoot = note.noteId === '_lbAvailableLaunchers'; + const isVisibleRoot = note?.noteId === '_lbVisibleLaunchers'; + const isAvailableRoot = note?.noteId === '_lbAvailableLaunchers'; const isVisibleItem = parentNoteId === '_lbVisibleLaunchers'; const isAvailableItem = parentNoteId === '_lbAvailableLaunchers'; const isItem = isVisibleItem || isAvailableItem; - const canBeDeleted = !note.noteId.startsWith("_"); // fixed notes can't be deleted - const canBeReset = !canBeDeleted && note.isLaunchBarConfig(); + const canBeDeleted = !note?.noteId.startsWith("_"); // fixed notes can't be deleted + const canBeReset = !canBeDeleted && note?.isLaunchBarConfig(); return [ (isVisibleRoot || isAvailableRoot) ? { title: t("launcher_context_menu.add-note-launcher"), command: 'addNoteLauncher', uiIcon: "bx bx-note" } : null, @@ -49,14 +56,18 @@ export default class LauncherContextMenu { { title: `${t("launcher_context_menu.duplicate-launcher")} `, command: "duplicateSubtree", uiIcon: "bx bx-outline", enabled: isItem }, { title: `${t("launcher_context_menu.delete")} `, command: "deleteNotes", uiIcon: "bx bx-trash destructive-action-icon", enabled: canBeDeleted }, - + { title: "----" }, - + { title: t("launcher_context_menu.reset"), command: "resetLauncher", uiIcon: "bx bx-reset destructive-action-icon", enabled: canBeReset} ].filter(row => row !== null); } - async selectMenuItemHandler({command}) { + async selectMenuItemHandler({command}: MenuCommandItem) { + if (!command) { + return; + } + if (command === 'resetLauncher') { const confirmed = await dialogService.confirm(t("launcher_context_menu.reset_launcher_confirm", { title: this.node.title })); diff --git a/src/public/app/services/tree.ts b/src/public/app/services/tree.ts index f2490278e..090b1b362 100644 --- a/src/public/app/services/tree.ts +++ b/src/public/app/services/tree.ts @@ -5,6 +5,7 @@ import hoistedNoteService from '../services/hoisted_note.js'; import appContext from "../components/app_context.js"; export interface Node { + title: string; getParent(): Node; getChildren(): Node[]; folder: boolean; @@ -85,8 +86,8 @@ async function resolveNotePathToSegments(notePath: string, hoistedNoteId = 'root if (logErrors) { const parent = froca.getNoteFromCache(parentNoteId); - console.debug(utils.now(), `Did not find parent ${parentNoteId} (${parent ? parent.title : 'n/a'}) - for child ${childNoteId} (${child.title}), available parents: ${parents.map(p => `${p.noteId} (${p.title})`)}. + console.debug(utils.now(), `Did not find parent ${parentNoteId} (${parent ? parent.title : 'n/a'}) + for child ${childNoteId} (${child.title}), available parents: ${parents.map(p => `${p.noteId} (${p.title})`)}. You can ignore this message as it is mostly harmless.`); } @@ -294,7 +295,7 @@ async function getNoteTitleWithPathAsSuffix(notePath: string) { $titleWithPath.append(formatNotePath(path)); - + return $titleWithPath; } @@ -302,12 +303,12 @@ function formatNotePath(path: string[]) { const $notePath = $(''); if (path.length > 0) { - + $notePath.append($(` ()`)); for (let segmentIndex = 0; segmentIndex < path.length; segmentIndex++) { $notePath.append($(``).text(path[segmentIndex])); - + if (segmentIndex < path.length - 1) { $notePath.append($(``).text(" / ")); }