| 
									
										
										
										
											2022-12-01 13:07:23 +01:00
										 |  |  | import froca from "../services/froca.js"; | 
					
						
							|  |  |  | import bundleService from "../services/bundle.js"; | 
					
						
							| 
									
										
										
										
											2021-04-24 22:18:25 +02:00
										 |  |  | import RootCommandExecutor from "./root_command_executor.js"; | 
					
						
							| 
									
										
										
										
											2024-12-23 14:10:57 +02:00
										 |  |  | import Entrypoints, { SqlExecuteResults } from "./entrypoints.js"; | 
					
						
							| 
									
										
										
										
											2022-12-01 13:07:23 +01:00
										 |  |  | import options from "../services/options.js"; | 
					
						
							|  |  |  | import utils from "../services/utils.js"; | 
					
						
							|  |  |  | import zoomComponent from "./zoom.js"; | 
					
						
							| 
									
										
										
										
											2020-02-07 21:08:55 +01:00
										 |  |  | import TabManager from "./tab_manager.js"; | 
					
						
							| 
									
										
										
										
											2022-12-01 13:07:23 +01:00
										 |  |  | import Component from "./component.js"; | 
					
						
							|  |  |  | import keyboardActionsService from "../services/keyboard_actions.js"; | 
					
						
							| 
									
										
										
										
											2024-12-22 18:03:03 +02:00
										 |  |  | import linkService, { ViewScope } from "../services/link.js"; | 
					
						
							| 
									
										
										
										
											2024-12-23 14:21:43 +02:00
										 |  |  | import MobileScreenSwitcherExecutor, { Screen } from "./mobile_screen_switcher.js"; | 
					
						
							| 
									
										
										
										
											2020-03-17 12:28:02 +01:00
										 |  |  | import MainTreeExecutors from "./main_tree_executors.js"; | 
					
						
							| 
									
										
										
										
											2022-12-01 13:07:23 +01:00
										 |  |  | import toast from "../services/toast.js"; | 
					
						
							| 
									
										
										
										
											2022-12-01 13:24:34 +01:00
										 |  |  | import ShortcutComponent from "./shortcut_component.js"; | 
					
						
							| 
									
										
										
										
											2024-10-15 15:46:34 +08:00
										 |  |  | import { t, initLocale } from "../services/i18n.js"; | 
					
						
							| 
									
										
										
										
											2024-12-19 22:06:42 +02:00
										 |  |  | import NoteDetailWidget from "../widgets/note_detail.js"; | 
					
						
							| 
									
										
										
										
											2024-12-21 15:34:07 +02:00
										 |  |  | import { ResolveOptions } from "../widgets/dialogs/delete_notes.js"; | 
					
						
							| 
									
										
										
										
											2024-12-21 17:12:16 +02:00
										 |  |  | import { PromptDialogOptions } from "../widgets/dialogs/prompt.js"; | 
					
						
							| 
									
										
										
										
											2024-12-21 23:47:18 +02:00
										 |  |  | import { ConfirmWithMessageOptions, ConfirmWithTitleOptions } from "../widgets/dialogs/confirm.js"; | 
					
						
							| 
									
										
										
										
											2024-12-22 19:31:29 +02:00
										 |  |  | import { Node } from "../services/tree.js"; | 
					
						
							| 
									
										
										
										
											2024-12-22 21:59:08 +02:00
										 |  |  | import LoadResults from "../services/load_results.js"; | 
					
						
							|  |  |  | import { Attribute } from "../services/attribute_parser.js"; | 
					
						
							| 
									
										
										
										
											2024-12-23 14:14:38 +02:00
										 |  |  | import NoteTreeWidget from "../widgets/note_tree.js"; | 
					
						
							| 
									
										
										
										
											2024-12-23 15:16:41 +02:00
										 |  |  | import { GetTextEditorCallback } from "./note_context.js"; | 
					
						
							| 
									
										
										
										
											2020-01-11 21:19:56 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-07-25 20:55:04 +03:00
										 |  |  | interface Layout { | 
					
						
							|  |  |  |     getRootWidget: (appContext: AppContext) => RootWidget; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | interface RootWidget extends Component { | 
					
						
							| 
									
										
										
										
											2024-12-22 17:56:53 +02:00
										 |  |  |     render: () => JQuery<HTMLElement>; | 
					
						
							| 
									
										
										
										
											2024-07-25 20:55:04 +03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | interface BeforeUploadListener extends Component { | 
					
						
							|  |  |  |     beforeUnloadEvent(): boolean; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-12-22 19:31:29 +02:00
										 |  |  | /** | 
					
						
							|  |  |  |  * Base interface for the data/arguments for a given command (see {@link CommandMappings}). | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2024-12-22 21:59:08 +02:00
										 |  |  | export interface CommandData { | 
					
						
							| 
									
										
										
										
											2024-12-23 15:16:41 +02:00
										 |  |  |     ntxId?: string | null; | 
					
						
							| 
									
										
										
										
											2024-12-21 23:29:17 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-12-22 19:31:29 +02:00
										 |  |  | /** | 
					
						
							|  |  |  |  * Represents a set of commands that are triggered from the context menu, providing information such as the selected note. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | export interface ContextMenuCommandData extends CommandData { | 
					
						
							|  |  |  |     node: Node; | 
					
						
							|  |  |  |     notePath: string; | 
					
						
							|  |  |  |     noteId?: string; | 
					
						
							|  |  |  |     selectedOrActiveBranchIds: any; // TODO: Remove any once type is defined
 | 
					
						
							|  |  |  |     selectedOrActiveNoteIds: any; // TODO: Remove  any once type is defined
 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-12-23 14:10:57 +02:00
										 |  |  | export interface NoteCommandData extends CommandData { | 
					
						
							|  |  |  |     notePath: string; | 
					
						
							|  |  |  |     hoistedNoteId?: string; | 
					
						
							|  |  |  |     viewScope?: ViewScope; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-12-23 15:16:41 +02:00
										 |  |  | export interface ExecuteCommandData extends CommandData { | 
					
						
							|  |  |  |     resolve: unknown; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-12-22 19:31:29 +02:00
										 |  |  | /** | 
					
						
							|  |  |  |  * The keys represent the different commands that can be triggered via {@link AppContext#triggerCommand} (first argument), and the values represent the data or arguments definition of the given command. All data for commands must extend {@link CommandData}. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | export type CommandMappings = { | 
					
						
							| 
									
										
										
										
											2024-12-21 23:57:55 +02:00
										 |  |  |     "api-log-messages": CommandData; | 
					
						
							|  |  |  |     focusOnDetail: Required<CommandData>; | 
					
						
							|  |  |  |     searchNotes: CommandData & { | 
					
						
							|  |  |  |         searchString: string | undefined; | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  |     showDeleteNotesDialog: CommandData & { | 
					
						
							|  |  |  |         branchIdsToDelete: string[]; | 
					
						
							|  |  |  |         callback: (value: ResolveOptions) => void; | 
					
						
							|  |  |  |         forceDeleteAllClones: boolean; | 
					
						
							|  |  |  |     }; | 
					
						
							| 
									
										
										
										
											2024-12-21 23:47:18 +02:00
										 |  |  |     showConfirmDeleteNoteBoxWithNoteDialog: ConfirmWithTitleOptions; | 
					
						
							| 
									
										
										
										
											2024-12-21 23:57:55 +02:00
										 |  |  |     openedFileUpdated: CommandData & { | 
					
						
							|  |  |  |         entityType: string; | 
					
						
							|  |  |  |         entityId: string; | 
					
						
							|  |  |  |         lastModifiedMs: number; | 
					
						
							|  |  |  |         filePath: string; | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  |     focusAndSelectTitle: CommandData & { | 
					
						
							|  |  |  |         isNewNote: boolean; | 
					
						
							|  |  |  |     }; | 
					
						
							| 
									
										
										
										
											2024-12-21 23:47:18 +02:00
										 |  |  |     showPromptDialog: PromptDialogOptions; | 
					
						
							|  |  |  |     showInfoDialog: ConfirmWithMessageOptions; | 
					
						
							|  |  |  |     showConfirmDialog: ConfirmWithMessageOptions; | 
					
						
							| 
									
										
										
										
											2024-12-23 14:10:57 +02:00
										 |  |  |     openNewNoteSplit: NoteCommandData; | 
					
						
							|  |  |  |     openInWindow: NoteCommandData, | 
					
						
							| 
									
										
										
										
											2024-12-22 18:33:57 +02:00
										 |  |  |     openNoteInNewTab: CommandData; | 
					
						
							|  |  |  |     openNoteInNewSplit: CommandData; | 
					
						
							|  |  |  |     openNoteInNewWindow: CommandData; | 
					
						
							| 
									
										
										
										
											2024-12-22 19:31:29 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     openInTab: ContextMenuCommandData; | 
					
						
							|  |  |  |     openNoteInSplit: ContextMenuCommandData; | 
					
						
							|  |  |  |     toggleNoteHoisting: ContextMenuCommandData; | 
					
						
							|  |  |  |     insertNoteAfter: ContextMenuCommandData; | 
					
						
							|  |  |  |     insertChildNote: ContextMenuCommandData; | 
					
						
							|  |  |  |     protectSubtree: ContextMenuCommandData; | 
					
						
							|  |  |  |     unprotectSubtree: ContextMenuCommandData; | 
					
						
							|  |  |  |     openBulkActionsDialog: ContextMenuCommandData; | 
					
						
							|  |  |  |     editBranchPrefix: ContextMenuCommandData; | 
					
						
							|  |  |  |     convertNoteToAttachment: ContextMenuCommandData; | 
					
						
							|  |  |  |     duplicateSubtree: ContextMenuCommandData; | 
					
						
							|  |  |  |     expandSubtree: ContextMenuCommandData; | 
					
						
							|  |  |  |     collapseSubtree: ContextMenuCommandData; | 
					
						
							|  |  |  |     sortChildNotes: ContextMenuCommandData; | 
					
						
							|  |  |  |     copyNotePathToClipboard: ContextMenuCommandData; | 
					
						
							|  |  |  |     recentChangesInSubtree: ContextMenuCommandData; | 
					
						
							|  |  |  |     cutNotesToClipboard: ContextMenuCommandData; | 
					
						
							|  |  |  |     copyNotesToClipboard: ContextMenuCommandData; | 
					
						
							|  |  |  |     pasteNotesFromClipboard: ContextMenuCommandData; | 
					
						
							|  |  |  |     pasteNotesAfterFromClipboard: ContextMenuCommandData; | 
					
						
							|  |  |  |     moveNotesTo: ContextMenuCommandData; | 
					
						
							|  |  |  |     cloneNotesTo: ContextMenuCommandData; | 
					
						
							|  |  |  |     deleteNotes: ContextMenuCommandData; | 
					
						
							|  |  |  |     importIntoNote: ContextMenuCommandData; | 
					
						
							|  |  |  |     exportNote: ContextMenuCommandData; | 
					
						
							|  |  |  |     searchInSubtree: ContextMenuCommandData; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     addNoteLauncher: ContextMenuCommandData; | 
					
						
							|  |  |  |     addScriptLauncher: ContextMenuCommandData; | 
					
						
							|  |  |  |     addWidgetLauncher: ContextMenuCommandData; | 
					
						
							|  |  |  |     addSpacerLauncher: ContextMenuCommandData; | 
					
						
							|  |  |  |     moveLauncherToVisible: ContextMenuCommandData; | 
					
						
							|  |  |  |     moveLauncherToAvailable: ContextMenuCommandData; | 
					
						
							|  |  |  |     resetLauncher: ContextMenuCommandData; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-12-21 23:57:55 +02:00
										 |  |  |     executeInActiveNoteDetailWidget: CommandData & { | 
					
						
							|  |  |  |         callback: (value: NoteDetailWidget | PromiseLike<NoteDetailWidget>) => void | 
					
						
							|  |  |  |     }; | 
					
						
							| 
									
										
										
										
											2024-12-23 15:16:41 +02:00
										 |  |  |     executeWithTextEditor: CommandData & ExecuteCommandData & { | 
					
						
							|  |  |  |         callback?: GetTextEditorCallback; | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  |     executeWithCodeEditor: CommandData & ExecuteCommandData; | 
					
						
							|  |  |  |     executeWithContentElement: CommandData & ExecuteCommandData; | 
					
						
							|  |  |  |     executeWithTypeWidget: CommandData & ExecuteCommandData; | 
					
						
							| 
									
										
										
										
											2024-12-21 23:57:55 +02:00
										 |  |  |     addTextToActiveEditor: CommandData & { | 
					
						
							|  |  |  |         text: string; | 
					
						
							|  |  |  |     }; | 
					
						
							| 
									
										
										
										
											2024-12-22 18:33:57 +02:00
										 |  |  |     /** Works only in the electron context menu. */ | 
					
						
							|  |  |  |     replaceMisspelling: CommandData; | 
					
						
							| 
									
										
										
										
											2024-12-22 17:56:53 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-12-21 23:57:55 +02:00
										 |  |  |     importMarkdownInline: CommandData; | 
					
						
							|  |  |  |     showPasswordNotSet: CommandData; | 
					
						
							|  |  |  |     showProtectedSessionPasswordDialog: CommandData; | 
					
						
							|  |  |  |     closeProtectedSessionPasswordDialog: CommandData; | 
					
						
							| 
									
										
										
										
											2024-12-22 18:33:57 +02:00
										 |  |  |     copyImageReferenceToClipboard: CommandData; | 
					
						
							|  |  |  |     copyImageToClipboard: CommandData; | 
					
						
							| 
									
										
										
										
											2024-12-22 19:31:29 +02:00
										 |  |  |     updateAttributesList: { | 
					
						
							| 
									
										
										
										
											2024-12-22 21:59:08 +02:00
										 |  |  |         attributes: Attribute[]; | 
					
						
							| 
									
										
										
										
											2024-12-22 19:31:29 +02:00
										 |  |  |     }; | 
					
						
							| 
									
										
										
										
											2024-12-22 21:59:08 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     addNewLabel: CommandData; | 
					
						
							|  |  |  |     addNewRelation: CommandData; | 
					
						
							|  |  |  |     addNewLabelDefinition: CommandData; | 
					
						
							|  |  |  |     addNewRelationDefinition: CommandData; | 
					
						
							| 
									
										
										
										
											2024-12-23 14:14:38 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     cloneNoteIdsTo: CommandData & { | 
					
						
							|  |  |  |         noteIds: string[]; | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  |     moveBranchIdsTo: CommandData & { | 
					
						
							|  |  |  |         branchIds: string[]; | 
					
						
							|  |  |  |     }; | 
					
						
							| 
									
										
										
										
											2024-12-23 14:21:43 +02:00
										 |  |  |     setActiveScreen: CommandData & { | 
					
						
							|  |  |  |         screen: Screen; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2024-12-21 23:47:18 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-12-21 23:54:47 +02:00
										 |  |  | type EventMappings = { | 
					
						
							|  |  |  |     initialRenderComplete: {}; | 
					
						
							|  |  |  |     frocaReloaded: {}; | 
					
						
							|  |  |  |     protectedSessionStarted: {}; | 
					
						
							|  |  |  |     notesReloaded: { | 
					
						
							|  |  |  |         noteIds: string[]; | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  |     refreshIncludedNote: { | 
					
						
							|  |  |  |         noteId: string; | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  |     apiLogMessages: { | 
					
						
							|  |  |  |         noteId: string; | 
					
						
							|  |  |  |         messages: string[]; | 
					
						
							|  |  |  |     }; | 
					
						
							| 
									
										
										
										
											2024-12-22 21:59:08 +02:00
										 |  |  |     entitiesReloaded: { | 
					
						
							|  |  |  |         loadResults: LoadResults | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  |     addNewLabel: CommandData; | 
					
						
							|  |  |  |     addNewRelation: CommandData; | 
					
						
							| 
									
										
										
										
											2024-12-23 15:16:41 +02:00
										 |  |  |     sqlQueryResults: CommandData & { | 
					
						
							| 
									
										
										
										
											2024-12-23 14:10:57 +02:00
										 |  |  |         results: SqlExecuteResults; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2024-12-21 23:54:47 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-12-22 21:59:08 +02:00
										 |  |  | export type EventListener<T extends EventNames> = { | 
					
						
							|  |  |  |     [key in T as `${key}Event`]: (data: EventData<T>) => void | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-12-23 14:21:43 +02:00
										 |  |  | export type CommandListener<T extends CommandNames> = { | 
					
						
							|  |  |  |     [key in T as `${key}Command`]: (data: CommandListenerData<T>) => void | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | export type CommandListenerData<T extends CommandNames> = CommandMappings[T]; | 
					
						
							| 
									
										
										
										
											2024-12-22 21:59:08 +02:00
										 |  |  | export type EventData<T extends EventNames> = EventMappings[T]; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-12-21 23:54:47 +02:00
										 |  |  | type CommandAndEventMappings = (CommandMappings & EventMappings); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-12-22 19:31:29 +02:00
										 |  |  | /** | 
					
						
							|  |  |  |  * This type is a discriminated union which contains all the possible commands that can be triggered via {@link AppContext.triggerCommand}. | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2024-12-21 23:47:18 +02:00
										 |  |  | export type CommandNames = keyof CommandMappings; | 
					
						
							| 
									
										
										
										
											2024-12-21 23:54:47 +02:00
										 |  |  | type EventNames = keyof EventMappings; | 
					
						
							| 
									
										
										
										
											2024-07-25 20:55:04 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-12-22 19:31:29 +02:00
										 |  |  | type FilterByValueType<T, ValueType> = { [K in keyof T]: T[K] extends ValueType ? K : never; }[keyof T]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /** | 
					
						
							|  |  |  |  * Generic which filters {@link CommandNames} to provide only those commands that take in as data the desired implementation of {@link CommandData}. Mostly useful for contextual menu, to enforce consistency in the commands. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | export type FilteredCommandNames<T extends CommandData> = keyof Pick<CommandMappings, FilterByValueType<CommandMappings, T>>; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-16 19:21:17 +01:00
										 |  |  | class AppContext extends Component { | 
					
						
							| 
									
										
										
										
											2024-07-25 20:55:04 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  |     isMainWindow: boolean; | 
					
						
							|  |  |  |     components: Component[]; | 
					
						
							|  |  |  |     beforeUnloadListeners: WeakRef<BeforeUploadListener>[]; | 
					
						
							|  |  |  |     tabManager!: TabManager; | 
					
						
							|  |  |  |     layout?: Layout; | 
					
						
							| 
									
										
										
										
											2024-12-23 14:14:38 +02:00
										 |  |  |     noteTreeWidget?: NoteTreeWidget; | 
					
						
							| 
									
										
										
										
											2024-07-25 20:55:04 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  |     constructor(isMainWindow: boolean) { | 
					
						
							| 
									
										
										
										
											2020-04-25 23:52:13 +02:00
										 |  |  |         super(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         this.isMainWindow = isMainWindow; | 
					
						
							| 
									
										
										
										
											2022-12-01 13:07:23 +01:00
										 |  |  |         // non-widget/layout components needed for the application
 | 
					
						
							|  |  |  |         this.components = []; | 
					
						
							| 
									
										
										
										
											2021-02-27 23:39:02 +01:00
										 |  |  |         this.beforeUnloadListeners = []; | 
					
						
							| 
									
										
										
										
											2020-04-25 23:52:13 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-11 08:12:01 +03:00
										 |  |  |     /** | 
					
						
							|  |  |  |      * Must be called as soon as possible, before the creation of any components since this method is in charge of initializing the locale. Any attempts to read translation before this method is called will result in `undefined`. | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     async earlyInit() { | 
					
						
							|  |  |  |         await options.initializedPromise; | 
					
						
							| 
									
										
										
										
											2024-08-11 14:22:37 +03:00
										 |  |  |         await initLocale(); | 
					
						
							| 
									
										
										
										
											2024-08-11 08:12:01 +03:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-07-25 20:55:04 +03:00
										 |  |  |     setLayout(layout: Layout) { | 
					
						
							| 
									
										
										
										
											2020-02-06 21:47:31 +01:00
										 |  |  |         this.layout = layout; | 
					
						
							| 
									
										
										
										
											2020-01-12 19:05:09 +01:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-25 23:52:13 +02:00
										 |  |  |     async start() { | 
					
						
							| 
									
										
										
										
											2022-12-01 13:07:23 +01:00
										 |  |  |         this.initComponents(); | 
					
						
							|  |  |  |         this.renderWidgets(); | 
					
						
							| 
									
										
										
										
											2020-03-29 23:10:45 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-18 16:12:29 +01:00
										 |  |  |         await froca.initializedPromise; | 
					
						
							| 
									
										
										
										
											2022-11-22 22:45:50 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-25 23:52:13 +02:00
										 |  |  |         this.tabManager.loadTabs(); | 
					
						
							| 
									
										
										
										
											2020-02-02 22:32:44 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-18 15:09:08 -05:00
										 |  |  |         setTimeout(() => bundleService.executeStartupBundles(), 2000); | 
					
						
							| 
									
										
										
										
											2020-02-02 22:04:28 +01:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2020-01-12 19:05:09 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-01 13:07:23 +01:00
										 |  |  |     initComponents() { | 
					
						
							|  |  |  |         this.tabManager = new TabManager(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         this.components = [ | 
					
						
							|  |  |  |             this.tabManager, | 
					
						
							|  |  |  |             new RootCommandExecutor(), | 
					
						
							|  |  |  |             new Entrypoints(), | 
					
						
							| 
									
										
										
										
											2022-12-01 13:24:34 +01:00
										 |  |  |             new MainTreeExecutors(), | 
					
						
							|  |  |  |             new ShortcutComponent() | 
					
						
							| 
									
										
										
										
											2022-12-01 13:07:23 +01:00
										 |  |  |         ]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (utils.isMobile()) { | 
					
						
							|  |  |  |             this.components.push(new MobileScreenSwitcherExecutor()); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         for (const component of this.components) { | 
					
						
							|  |  |  |             this.child(component); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (utils.isElectron()) { | 
					
						
							|  |  |  |             this.child(zoomComponent); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     renderWidgets() { | 
					
						
							| 
									
										
										
										
											2024-07-25 20:55:04 +03:00
										 |  |  |         if (!this.layout) { | 
					
						
							|  |  |  |             throw new Error("Missing layout."); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-16 19:21:17 +01:00
										 |  |  |         const rootWidget = this.layout.getRootWidget(this); | 
					
						
							|  |  |  |         const $renderedWidget = rootWidget.render(); | 
					
						
							| 
									
										
										
										
											2020-01-14 21:23:32 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-16 20:09:59 +01:00
										 |  |  |         keyboardActionsService.updateDisplayedShortcuts($renderedWidget); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-09 22:31:52 +01:00
										 |  |  |         $("body").append($renderedWidget); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-05 23:58:52 +02:00
										 |  |  |         $renderedWidget.on('click', "[data-trigger-command]", function() { | 
					
						
							| 
									
										
										
										
											2023-05-07 10:43:51 +02:00
										 |  |  |             if ($(this).hasClass("disabled")) { | 
					
						
							|  |  |  |                 return; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-05 23:58:52 +02:00
										 |  |  |             const commandName = $(this).attr('data-trigger-command'); | 
					
						
							|  |  |  |             const $component = $(this).closest(".component"); | 
					
						
							|  |  |  |             const component = $component.prop("component"); | 
					
						
							| 
									
										
										
										
											2020-02-09 22:31:52 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-06 21:24:51 +02:00
										 |  |  |             component.triggerCommand(commandName, {$el: $(this)}); | 
					
						
							| 
									
										
										
										
											2020-02-09 22:31:52 +01:00
										 |  |  |         }); | 
					
						
							| 
									
										
										
										
											2020-02-05 22:08:45 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-27 10:03:14 +01:00
										 |  |  |         this.child(rootWidget); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-16 19:21:17 +01:00
										 |  |  |         this.triggerEvent('initialRenderComplete'); | 
					
						
							| 
									
										
										
										
											2020-01-11 21:19:56 +01:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-12-21 23:54:47 +02:00
										 |  |  |     // TODO: Remove ignore once all commands are mapped out.
 | 
					
						
							|  |  |  |     //@ts-ignore
 | 
					
						
							|  |  |  |     triggerEvent<K extends EventNames | CommandNames>(name: K, data: CommandAndEventMappings[K] = {}) { | 
					
						
							| 
									
										
										
										
											2020-02-29 19:43:19 +01:00
										 |  |  |         return this.handleEvent(name, data); | 
					
						
							| 
									
										
										
										
											2020-02-01 22:29:32 +01:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2020-02-15 10:41:21 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-12-22 19:31:29 +02:00
										 |  |  |     triggerCommand<K extends CommandNames>(name: K, _data?: CommandMappings[K]) { | 
					
						
							|  |  |  |         const data = _data || {}; | 
					
						
							| 
									
										
										
										
											2022-12-01 13:07:23 +01:00
										 |  |  |         for (const executor of this.components) { | 
					
						
							| 
									
										
										
										
											2024-07-25 20:55:04 +03:00
										 |  |  |             const fun = (executor as any)[`${name}Command`]; | 
					
						
							| 
									
										
										
										
											2020-02-15 10:41:21 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-29 19:43:19 +01:00
										 |  |  |             if (fun) { | 
					
						
							|  |  |  |                 return executor.callMethod(fun, data); | 
					
						
							| 
									
										
										
										
											2020-02-15 10:41:21 +01:00
										 |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-30 11:18:34 +02:00
										 |  |  |         // this might hint at error, but sometimes this is used by components which are at different places
 | 
					
						
							| 
									
										
										
										
											2020-05-05 23:58:52 +02:00
										 |  |  |         // in the component tree to communicate with each other
 | 
					
						
							| 
									
										
										
										
											2020-02-17 22:38:46 +01:00
										 |  |  |         console.debug(`Unhandled command ${name}, converting to event.`); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-12-21 23:54:47 +02:00
										 |  |  |         return this.triggerEvent(name, data as CommandAndEventMappings[K]); | 
					
						
							| 
									
										
										
										
											2020-02-15 10:41:21 +01:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-07-25 20:55:04 +03:00
										 |  |  |     getComponentByEl(el: HTMLElement) { | 
					
						
							| 
									
										
										
										
											2020-02-16 19:21:17 +01:00
										 |  |  |         return $(el).closest(".component").prop('component'); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2021-02-27 23:39:02 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-07-25 20:55:04 +03:00
										 |  |  |     addBeforeUnloadListener(obj: BeforeUploadListener) { | 
					
						
							| 
									
										
										
										
											2021-02-27 23:39:02 +01:00
										 |  |  |         if (typeof WeakRef !== "function") { | 
					
						
							|  |  |  |             // older browsers don't support WeakRef
 | 
					
						
							|  |  |  |             return; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-07-25 20:55:04 +03:00
										 |  |  |         this.beforeUnloadListeners.push(new WeakRef<BeforeUploadListener>(obj)); | 
					
						
							| 
									
										
										
										
											2021-02-27 23:39:02 +01:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2020-01-12 19:05:09 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-25 23:52:13 +02:00
										 |  |  | const appContext = new AppContext(window.glob.isMainWindow); | 
					
						
							| 
									
										
										
										
											2020-01-12 12:48:17 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-02 10:41:43 +01:00
										 |  |  | // we should save all outstanding changes before the page/app is closed
 | 
					
						
							| 
									
										
										
										
											2022-01-10 20:37:33 +01:00
										 |  |  | $(window).on('beforeunload', () => { | 
					
						
							| 
									
										
										
										
											2021-02-27 23:39:02 +01:00
										 |  |  |     let allSaved = true; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     appContext.beforeUnloadListeners = appContext.beforeUnloadListeners.filter(wr => !!wr.deref()); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     for (const weakRef of appContext.beforeUnloadListeners) { | 
					
						
							|  |  |  |         const component = weakRef.deref(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (!component) { | 
					
						
							|  |  |  |             continue; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (!component.beforeUnloadEvent()) { | 
					
						
							|  |  |  |             console.log(`Component ${component.componentId} is not finished saving its state.`); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-10-15 15:46:34 +08:00
										 |  |  |             toast.showMessage(t("app_context.please_wait_for_save"), 10000); | 
					
						
							| 
									
										
										
										
											2021-02-27 23:39:02 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |             allSaved = false; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (!allSaved) { | 
					
						
							|  |  |  |         return "some string"; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2020-02-02 10:41:43 +01:00
										 |  |  | }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-03 20:07:34 +01:00
										 |  |  | $(window).on('hashchange', function() { | 
					
						
							| 
									
										
										
										
											2023-05-07 21:18:21 +02:00
										 |  |  |     const {notePath, ntxId, viewScope} = linkService.parseNavigationStateFromUrl(window.location.href); | 
					
						
							| 
									
										
										
										
											2020-03-21 21:04:34 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-05-07 21:18:21 +02:00
										 |  |  |     if (notePath || ntxId) { | 
					
						
							| 
									
										
										
										
											2023-04-11 21:41:55 +02:00
										 |  |  |         appContext.tabManager.switchToNoteContext(ntxId, notePath, viewScope); | 
					
						
							| 
									
										
										
										
											2020-02-03 20:07:34 +01:00
										 |  |  |     } | 
					
						
							|  |  |  | }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-11 20:08:55 +02:00
										 |  |  | export default appContext; |