diff --git a/src/public/app/components/shortcut_component.ts b/src/public/app/components/shortcut_component.ts index 11c20342a..de2bded97 100644 --- a/src/public/app/components/shortcut_component.ts +++ b/src/public/app/components/shortcut_component.ts @@ -17,7 +17,7 @@ export default class ShortcutComponent extends Component implements EventListene } bindNoteShortcutHandler(labelOrRow: AttributeRow) { - const handler = () => appContext.tabManager.getActiveContext().setNote(labelOrRow.noteId); + const handler = () => appContext.tabManager.getActiveContext()?.setNote(labelOrRow.noteId); const namespace = labelOrRow.attributeId; if (labelOrRow.isDeleted) { diff --git a/src/public/app/menus/tree_context_menu.ts b/src/public/app/menus/tree_context_menu.ts index 5c2c74fe9..4cc094e0b 100644 --- a/src/public/app/menus/tree_context_menu.ts +++ b/src/public/app/menus/tree_context_menu.ts @@ -44,7 +44,7 @@ export default class TreeContextMenu implements SelectMenuItemEventListener 0) { - activeContext.setNote(parentNotePathArr.join("/")); + if (parentNotePathArr && parentNotePathArr.length > 0) { + activeContext?.setNote(parentNotePathArr.join("/")); } } diff --git a/src/public/app/services/frontend_script_api.ts b/src/public/app/services/frontend_script_api.ts index 86a793c9f..bd30a58cc 100644 --- a/src/public/app/services/frontend_script_api.ts +++ b/src/public/app/services/frontend_script_api.ts @@ -457,13 +457,13 @@ function FrontendScriptApi(this: Api, startNote: FNote, currentNote: FNote, orig this.BasicWidget = BasicWidget; this.activateNote = async (notePath) => { - await appContext.tabManager.getActiveContext().setNote(notePath); + await appContext.tabManager.getActiveContext()?.setNote(notePath); }; this.activateNewNote = async (notePath) => { await ws.waitForMaxKnownEntityChangeId(); - await appContext.tabManager.getActiveContext().setNote(notePath); + await appContext.tabManager.getActiveContext()?.setNote(notePath); await appContext.triggerEvent("focusAndSelectTitle", {}); }; @@ -480,8 +480,8 @@ function FrontendScriptApi(this: Api, startNote: FNote, currentNote: FNote, orig this.openSplitWithNote = async (notePath, activate) => { await ws.waitForMaxKnownEntityChangeId(); - const subContexts = appContext.tabManager.getActiveContext().getSubContexts(); - const { ntxId } = subContexts[subContexts.length - 1]; + const subContexts = appContext.tabManager.getActiveContext()?.getSubContexts(); + const { ntxId } = subContexts?.[subContexts.length - 1] ?? {}; await appContext.triggerCommand("openNewNoteSplit", { ntxId, notePath }); @@ -591,15 +591,48 @@ function FrontendScriptApi(this: Api, startNote: FNote, currentNote: FNote, orig this.addTextToActiveContextEditor = (text) => appContext.triggerCommand("addTextToActiveEditor", { text }); - this.getActiveContextNote = () => appContext.tabManager.getActiveContextNote(); - this.getActiveContext = () => appContext.tabManager.getActiveContext(); - this.getActiveMainContext = () => appContext.tabManager.getActiveMainContext(); + this.getActiveContextNote = (): FNote => { + const note = appContext.tabManager.getActiveContextNote(); + if (!note) { + throw new Error("No active context note found"); + } + return note; + }; + + this.getActiveContext = (): NoteContext => { + const context = appContext.tabManager.getActiveContext(); + if (!context) { + throw new Error("No active context found"); + } + return context; + }; + + this.getActiveMainContext = (): NoteContext => { + const context = appContext.tabManager.getActiveMainContext(); + if (!context) { + throw new Error("No active main context found"); + } + return context; + }; this.getNoteContexts = () => appContext.tabManager.getNoteContexts(); this.getMainNoteContexts = () => appContext.tabManager.getMainNoteContexts(); - this.getActiveContextTextEditor = () => appContext.tabManager.getActiveContext()?.getTextEditor(); - this.getActiveContextCodeEditor = () => appContext.tabManager.getActiveContext()?.getCodeEditor(); + this.getActiveContextTextEditor = () => { + const context = appContext.tabManager.getActiveContext(); + if (!context) { + throw new Error("No active context found"); + } + return context.getTextEditor(); + }; + + this.getActiveContextCodeEditor = () => { + const context = appContext.tabManager.getActiveContext(); + if (!context) { + throw new Error("No active context found"); + } + return context.getCodeEditor(); + }; this.getActiveNoteDetailWidget = () => new Promise((resolve) => appContext.triggerCommand("executeInActiveNoteDetailWidget", { callback: resolve })); this.getActiveContextNotePath = () => appContext.tabManager.getActiveContextNotePath(); @@ -665,5 +698,5 @@ function FrontendScriptApi(this: Api, startNote: FNote, currentNote: FNote, orig } export default FrontendScriptApi as any as { - new (startNote: FNote, currentNote: FNote, originEntity: Entity | null, $container: JQuery | null): Api; + new(startNote: FNote, currentNote: FNote, originEntity: Entity | null, $container: JQuery | null): Api; }; diff --git a/src/public/app/services/import.ts b/src/public/app/services/import.ts index 97cc40c94..0c6c25f11 100644 --- a/src/public/app/services/import.ts +++ b/src/public/app/services/import.ts @@ -80,7 +80,7 @@ ws.subscribeToMessages(async (message) => { toastService.showPersistent(toast); if (message.result.importedNoteId) { - await appContext.tabManager.getActiveContext().setNote(message.result.importedNoteId); + await appContext.tabManager.getActiveContext()?.setNote(message.result.importedNoteId); } } }); @@ -102,7 +102,7 @@ ws.subscribeToMessages(async (message) => { toastService.showPersistent(toast); if (message.result.parentNoteId) { - await appContext.tabManager.getActiveContext().setNote(message.result.importedNoteId, { + await appContext.tabManager.getActiveContext()?.setNote(message.result.importedNoteId, { viewScope: { viewMode: "attachments" } diff --git a/src/public/app/services/note_create.ts b/src/public/app/services/note_create.ts index 90dd94d8f..47cf02bb6 100644 --- a/src/public/app/services/note_create.ts +++ b/src/public/app/services/note_create.ts @@ -86,8 +86,8 @@ async function createNote(parentNotePath: string | undefined, options: CreateNot await ws.waitForMaxKnownEntityChangeId(); - if (options.activate) { - const activeNoteContext = appContext.tabManager.getActiveContext(); + const activeNoteContext = appContext.tabManager.getActiveContext(); + if (activeNoteContext && options.activate) { await activeNoteContext.setNote(`${parentNotePath}/${note.noteId}`); if (options.focus === "title") { @@ -152,8 +152,7 @@ async function duplicateSubtree(noteId: string, parentNotePath: string) { await ws.waitForMaxKnownEntityChangeId(); - const activeNoteContext = appContext.tabManager.getActiveContext(); - activeNoteContext.setNote(`${parentNotePath}/${note.noteId}`); + appContext.tabManager.getActiveContext()?.setNote(`${parentNotePath}/${note.noteId}`); const origNote = await froca.getNote(noteId); toastService.showMessage(t("note_create.duplicated", { title: origNote?.title })); diff --git a/src/public/app/widgets/buttons/attachments_actions.ts b/src/public/app/widgets/buttons/attachments_actions.ts index d2c0841b7..e7b82b28f 100644 --- a/src/public/app/widgets/buttons/attachments_actions.ts +++ b/src/public/app/widgets/buttons/attachments_actions.ts @@ -171,7 +171,7 @@ export default class AttachmentActionsWidget extends BasicWidget { const { note: newNote } = await server.post>(`attachments/${this.attachmentId}/convert-to-note`); toastService.showMessage(t("attachments_actions.convert_success", { title: this.attachment.title })); await ws.waitForMaxKnownEntityChangeId(); - await appContext.tabManager.getActiveContext().setNote(newNote.noteId); + await appContext.tabManager.getActiveContext()?.setNote(newNote.noteId); } async renameAttachmentCommand() { diff --git a/src/public/app/widgets/buttons/calendar.ts b/src/public/app/widgets/buttons/calendar.ts index b279e7689..131d176bf 100644 --- a/src/public/app/widgets/buttons/calendar.ts +++ b/src/public/app/widgets/buttons/calendar.ts @@ -43,8 +43,8 @@ const DROPDOWN_TPL = ` data-calendar-input="month"> @@ -149,7 +149,7 @@ export default class CalendarWidget extends RightDropdownButtonWidget { const note = await dateNoteService.getDayNote(date); if (note) { - appContext.tabManager.getActiveContext().setNote(note.noteId); + appContext.tabManager.getActiveContext()?.setNote(note.noteId); this.dropdown?.hide(); } else { toastService.showError(t("calendar.cannot_find_day_note")); @@ -189,10 +189,7 @@ export default class CalendarWidget extends RightDropdownButtonWidget { async dropdownShown() { await libraryLoader.requireLibrary(libraryLoader.CALENDAR_WIDGET); - - const activeNote = appContext.tabManager.getActiveContextNote(); - - this.init(activeNote?.getOwnedLabelValue("dateNote")); + this.init(appContext.tabManager.getActiveContextNote()?.getOwnedLabelValue("dateNote") ?? null); } init(activeDate: string | null) { diff --git a/src/public/app/widgets/buttons/launcher/note_launcher.ts b/src/public/app/widgets/buttons/launcher/note_launcher.ts index 950021091..7622df401 100644 --- a/src/public/app/widgets/buttons/launcher/note_launcher.ts +++ b/src/public/app/widgets/buttons/launcher/note_launcher.ts @@ -78,7 +78,7 @@ export default class NoteLauncher extends AbstractLauncher { } getHoistedNoteId() { - return this.launcherNote.getRelationValue("hoistedNote") || appContext.tabManager.getActiveContext().hoistedNoteId; + return this.launcherNote.getRelationValue("hoistedNote") || appContext.tabManager.getActiveContext()?.hoistedNoteId; } getTitle() { diff --git a/src/public/app/widgets/buttons/launcher/today_launcher.ts b/src/public/app/widgets/buttons/launcher/today_launcher.ts index 838fa41c2..7e203bb7b 100644 --- a/src/public/app/widgets/buttons/launcher/today_launcher.ts +++ b/src/public/app/widgets/buttons/launcher/today_launcher.ts @@ -10,6 +10,6 @@ export default class TodayLauncher extends NoteLauncher { } getHoistedNoteId() { - return appContext.tabManager.getActiveContext().hoistedNoteId; + return appContext.tabManager.getActiveContext()?.hoistedNoteId; } } diff --git a/src/public/app/widgets/buttons/note_actions.ts b/src/public/app/widgets/buttons/note_actions.ts index dc332b541..a1ecd45d9 100644 --- a/src/public/app/widgets/buttons/note_actions.ts +++ b/src/public/app/widgets/buttons/note_actions.ts @@ -228,7 +228,7 @@ export default class NoteActionsWidget extends NoteContextAwareWidget { toastService.showMessage(t("note_actions.convert_into_attachment_successful", { title: newAttachment.title })); await ws.waitForMaxKnownEntityChangeId(); - await appContext.tabManager.getActiveContext().setNote(newAttachment.ownerId, { + await appContext.tabManager.getActiveContext()?.setNote(newAttachment.ownerId, { viewScope: { viewMode: "attachments", attachmentId: newAttachment.attachmentId diff --git a/src/public/app/widgets/containers/left_pane_container.ts b/src/public/app/widgets/containers/left_pane_container.ts index bbfedaa2a..21d4b280e 100644 --- a/src/public/app/widgets/containers/left_pane_container.ts +++ b/src/public/app/widgets/containers/left_pane_container.ts @@ -24,8 +24,7 @@ export default class LeftPaneContainer extends FlexContainer { if (visible) { this.triggerEvent("focusTree", {}); } else { - const activeNoteContext = appContext.tabManager.getActiveContext(); - this.triggerEvent("focusOnDetail", { ntxId: activeNoteContext.ntxId }); + this.triggerEvent("focusOnDetail", { ntxId: appContext.tabManager.getActiveContext()?.ntxId }); } } } diff --git a/src/public/app/widgets/floating_buttons/code_buttons.ts b/src/public/app/widgets/floating_buttons/code_buttons.ts index 35c7e0af2..ca6491f76 100644 --- a/src/public/app/widgets/floating_buttons/code_buttons.ts +++ b/src/public/app/widgets/floating_buttons/code_buttons.ts @@ -65,7 +65,7 @@ export default class CodeButtonsWidget extends NoteContextAwareWidget { await ws.waitForMaxKnownEntityChangeId(); - await appContext.tabManager.getActiveContext().setNote(notePath); + await appContext.tabManager.getActiveContext()?.setNote(notePath); toastService.showMessage(t("code_buttons.sql_console_saved_message", { notePath: await treeService.getNotePathTitle(notePath) })); }); diff --git a/src/public/app/widgets/floating_buttons/help_button.ts b/src/public/app/widgets/floating_buttons/help_button.ts index 6794ddf38..d4ec6e1a3 100644 --- a/src/public/app/widgets/floating_buttons/help_button.ts +++ b/src/public/app/widgets/floating_buttons/help_button.ts @@ -60,15 +60,15 @@ export default class ContextualHelpButton extends NoteContextAwareWidget { doRender() { this.$widget = $(TPL); this.$widget.on("click", () => { - const subContexts = appContext.tabManager.getActiveContext().getSubContexts(); + const subContexts = appContext.tabManager.getActiveContext()?.getSubContexts(); const targetNote = `_help_${this.helpNoteIdToOpen}`; - const helpSubcontext = subContexts.find((s) => s.viewScope?.viewMode === "contextual-help"); + const helpSubcontext = subContexts?.find((s) => s.viewScope?.viewMode === "contextual-help"); const viewScope: ViewScope = { viewMode: "contextual-help" }; if (!helpSubcontext) { // The help is not already open, open a new split with it. - const { ntxId } = subContexts[subContexts.length - 1]; + const { ntxId } = subContexts?.[subContexts.length - 1] ?? {}; this.triggerCommand("openNewNoteSplit", { ntxId, notePath: targetNote, diff --git a/src/public/app/widgets/mobile_widgets/mobile_detail_menu.ts b/src/public/app/widgets/mobile_widgets/mobile_detail_menu.ts index 7d4fc3ddd..58039f910 100644 --- a/src/public/app/widgets/mobile_widgets/mobile_detail_menu.ts +++ b/src/public/app/widgets/mobile_widgets/mobile_detail_menu.ts @@ -28,8 +28,8 @@ class MobileDetailMenuWidget extends BasicWidget { x: e.pageX, y: e.pageY, items: [ - { title: t("mobile_detail_menu.insert_child_note"), command: "insertChildNote", uiIcon: "bx bx-plus", enabled: note.type !== "search" }, - { title: t("mobile_detail_menu.delete_this_note"), command: "delete", uiIcon: "bx bx-trash", enabled: note.noteId !== "root" } + { title: t("mobile_detail_menu.insert_child_note"), command: "insertChildNote", uiIcon: "bx bx-plus", enabled: note?.type !== "search" }, + { title: t("mobile_detail_menu.delete_this_note"), command: "delete", uiIcon: "bx bx-trash", enabled: note?.noteId !== "root" } ], selectMenuItemHandler: async ({ command }) => { if (command === "insertChildNote") { diff --git a/src/public/app/widgets/note_map.ts b/src/public/app/widgets/note_map.ts index 00855958e..45cefa1d9 100644 --- a/src/public/app/widgets/note_map.ts +++ b/src/public/app/widgets/note_map.ts @@ -322,7 +322,7 @@ export default class NoteMapWidget extends NoteContextAwareWidget { .warmupTicks(30) .onNodeClick((node) => { if (node.id) { - appContext.tabManager.getActiveContext().setNote((node as Node).id); + appContext.tabManager.getActiveContext()?.setNote((node as Node).id); } }) .onNodeRightClick((node, e) => { @@ -371,7 +371,7 @@ export default class NoteMapWidget extends NoteContextAwareWidget { if (mapRootNoteId === "hoisted") { mapRootNoteId = hoistedNoteService.getHoistedNoteId(); } else if (!mapRootNoteId) { - mapRootNoteId = appContext.tabManager.getActiveContext().parentNoteId; + mapRootNoteId = appContext.tabManager.getActiveContext()?.parentNoteId; } return mapRootNoteId ?? ""; diff --git a/src/public/app/widgets/note_tree.ts b/src/public/app/widgets/note_tree.ts index 5d2635c76..d1ec85611 100644 --- a/src/public/app/widgets/note_tree.ts +++ b/src/public/app/widgets/note_tree.ts @@ -424,10 +424,10 @@ export default class NoteTreeWidget extends NoteContextAwareWidget { const activeNoteContext = appContext.tabManager.getActiveContext(); const opts: SetNoteOpts = {}; - if (activeNoteContext.viewScope?.viewMode === "contextual-help") { + if (activeNoteContext?.viewScope?.viewMode === "contextual-help") { opts.viewScope = activeNoteContext.viewScope; } - await activeNoteContext.setNote(notePath, opts); + await activeNoteContext?.setNote(notePath, opts); }, expand: (event, data) => this.setExpanded(data.node.data.branchId, true), collapse: (event, data) => this.setExpanded(data.node.data.branchId, false), @@ -619,10 +619,10 @@ export default class NoteTreeWidget extends NoteContextAwareWidget { // TODO: Deduplicate with server's notes.ts#getAndValidateParent if (!["search", "launcher"].includes(note.type) - && !note.isOptions() - && !note.isLaunchBarConfig() - && !note.noteId.startsWith("_help") - ) { + && !note.isOptions() + && !note.isLaunchBarConfig() + && !note.noteId.startsWith("_help") + ) { const $createChildNoteButton = $(``).on( "click", cancelClickPropagation @@ -1758,6 +1758,6 @@ export default class NoteTreeWidget extends NoteContextAwareWidget { await ws.waitForMaxKnownEntityChangeId(); - appContext.tabManager.getActiveContext().setNote(resp.note.noteId); + appContext.tabManager.getActiveContext()?.setNote(resp.note.noteId); } } diff --git a/src/public/app/widgets/ribbon_widgets/search_definition.ts b/src/public/app/widgets/ribbon_widgets/search_definition.ts index 2328f996f..08df15426 100644 --- a/src/public/app/widgets/ribbon_widgets/search_definition.ts +++ b/src/public/app/widgets/ribbon_widgets/search_definition.ts @@ -246,7 +246,7 @@ export default class SearchDefinitionWidget extends NoteContextAwareWidget { await ws.waitForMaxKnownEntityChangeId(); - await appContext.tabManager.getActiveContext().setNote(notePath); + await appContext.tabManager.getActiveContext()?.setNote(notePath); // Note the {{- notePathTitle}} in json file is not typo, it's unescaping // See https://www.i18next.com/translation-function/interpolation#unescape toastService.showMessage(t("search_definition.search_note_saved", { notePathTitle: await treeService.getNotePathTitle(notePath) })); diff --git a/src/public/app/widgets/view_widgets/calendar_view.ts b/src/public/app/widgets/view_widgets/calendar_view.ts index f34469d7e..ebec32a2e 100644 --- a/src/public/app/widgets/view_widgets/calendar_view.ts +++ b/src/public/app/widgets/view_widgets/calendar_view.ts @@ -155,7 +155,7 @@ export default class CalendarView extends ViewMode { const note = await date_notes.getDayNote(e.dateStr); if (note) { - appContext.tabManager.getActiveContext().setNote(note.noteId); + appContext.tabManager.getActiveContext()?.setNote(note.noteId); } } });