client-ts: Port services/app/app_context

This commit is contained in:
Elian Doran 2024-07-25 20:55:04 +03:00
parent cd5ea28e14
commit b7754bcea0
No known key found for this signature in database
5 changed files with 48 additions and 21 deletions

View File

@ -14,8 +14,32 @@ import MainTreeExecutors from "./main_tree_executors.js";
import toast from "../services/toast.js";
import ShortcutComponent from "./shortcut_component.js";
interface Layout {
getRootWidget: (appContext: AppContext) => RootWidget;
}
interface RootWidget extends Component {
render: () => JQuery<HTMLElement>;
}
interface BeforeUploadListener extends Component {
beforeUnloadEvent(): boolean;
}
interface TriggerData {
noteIds?: string[];
callback?: () => void;
}
class AppContext extends Component {
constructor(isMainWindow) {
isMainWindow: boolean;
components: Component[];
beforeUnloadListeners: WeakRef<BeforeUploadListener>[];
tabManager!: TabManager;
layout?: Layout;
constructor(isMainWindow: boolean) {
super();
this.isMainWindow = isMainWindow;
@ -24,7 +48,7 @@ class AppContext extends Component {
this.beforeUnloadListeners = [];
}
setLayout(layout) {
setLayout(layout: Layout) {
this.layout = layout;
}
@ -68,6 +92,10 @@ class AppContext extends Component {
}
renderWidgets() {
if (!this.layout) {
throw new Error("Missing layout.");
}
const rootWidget = this.layout.getRootWidget(this);
const $renderedWidget = rootWidget.render();
@ -92,15 +120,13 @@ class AppContext extends Component {
this.triggerEvent('initialRenderComplete');
}
/** @returns {Promise<void>} */
triggerEvent(name, data = {}) {
triggerEvent(name: string, data: TriggerData = {}) {
return this.handleEvent(name, data);
}
/** @returns {Promise<*>} */
triggerCommand(name, data = {}) {
triggerCommand(name: string, data: TriggerData = {}) {
for (const executor of this.components) {
const fun = executor[`${name}Command`];
const fun = (executor as any)[`${name}Command`];
if (fun) {
return executor.callMethod(fun, data);
@ -114,17 +140,17 @@ class AppContext extends Component {
return this.triggerEvent(name, data);
}
getComponentByEl(el) {
getComponentByEl(el: HTMLElement) {
return $(el).closest(".component").prop('component');
}
addBeforeUnloadListener(obj) {
addBeforeUnloadListener(obj: BeforeUploadListener) {
if (typeof WeakRef !== "function") {
// older browsers don't support WeakRef
return;
}
this.beforeUnloadListeners.push(new WeakRef(obj));
this.beforeUnloadListeners.push(new WeakRef<BeforeUploadListener>(obj));
}
}

View File

@ -12,10 +12,10 @@ import utils from '../services/utils.js';
* event / command is executed in all components - by simply awaiting the `triggerEvent()`.
*/
export default class Component {
private componentId: string;
private children: Component[];
private initialized: Promise<void> | null;
private parent?: Component;
componentId: string;
children: Component[];
initialized: Promise<void> | null;
parent?: Component;
constructor() {
this.componentId = `${this.sanitizedClassName}-${utils.randomString(8)}`;
@ -64,7 +64,7 @@ export default class Component {
}
}
triggerEvent(name: string, data = {}): Promise<unknown> | undefined {
triggerEvent(name: string, data = {}): Promise<unknown> | undefined | null {
return this.parent?.triggerEvent(name, data);
}
@ -83,7 +83,7 @@ export default class Component {
return promises.length > 0 ? Promise.all(promises) : null;
}
triggerCommand(name: string, data = {}): Promise<unknown> | undefined {
triggerCommand(name: string, data = {}): Promise<unknown> | undefined | null {
const fun = (this as any)[`${name}Command`];
if (fun) {

View File

@ -31,7 +31,7 @@ interface SearchNoteResponse {
* Backend has a similar cache called Becca
*/
class FrocaImpl implements Froca {
private initializedPromise: Promise<void>;
initializedPromise: Promise<void>;
notes!: Record<string, FNote>;
branches!: Record<string, FBranch>;

View File

@ -100,10 +100,10 @@ function isCtrlKey(evt: KeyboardEvent) {
|| (isMac() && evt.metaKey);
}
function assertArguments() {
for (const i in arguments) {
if (!arguments[i]) {
console.trace(`Argument idx#${i} should not be falsy: ${arguments[i]}`);
function assertArguments(...args: string[]) {
for (const i in args) {
if (!args[i]) {
console.trace(`Argument idx#${i} should not be falsy: ${args[i]}`);
}
}
}

View File

@ -26,6 +26,7 @@ interface CustomGlobals {
baseApiUrl: string;
isProtectedSessionAvailable: boolean;
isDev: boolean;
isMainWindow: boolean;
maxEntityChangeIdAtLoad: number;
maxEntityChangeSyncIdAtLoad: number;
}