import * as React from "bloatless-react"; import SettingsModel from "../../Model/Global/settingsModel"; import { allTranslations, Translations } from "../../View/translations"; import StorageModel from "../../Model/Global/storageModel"; import ConnectionModel from "../../Model/Global/connectionModel"; import ChatListModel from "../../Model/Chat/chatListModel"; import FileTransferModel from "../../Model/Global/fileTransferModel"; import { v4 } from "uuid"; export default class CoreViewModel { readonly BUILD = "Build 26.04.14.H"; translations: Translations; // CONTEXT private contextStack = new Map(); get contexts(): Context[] { return [...this.contextStack.values()]; } get context(): Context | undefined { return this.contexts.pop(); } set context(context: Context) { if (this.contextStack.has(context.contextId)) return; this.contextStack.set(context.contextId, context); history.pushState({ id: context.contextId }, ""); } closeContext = (contextId: string, fromHistoryEvent: boolean = false): void => { if ( !this.contexts .map((context) => context.contextId) .includes(contextId) ) return; while (this.contexts.length > 0) { const currentContext: Context = this.context; currentContext.handleContextClose(fromHistoryEvent); this.contextStack.delete(currentContext.contextId); if (currentContext.contextId == contextId) break; } }; handleKeyDown = (e: KeyboardEvent): void => { if (CoreViewModel.checkIsKeystroke(e) == false) return; e.preventDefault(); const contexts: Context[] = this.contexts; while (contexts.length > 0) { const currentContext: Context | undefined = contexts.pop(); if (!currentContext) contexts; const isHandled: boolean = currentContext.handleKeystroke(e); if (isHandled == true) break; } }; // DRAG & DROP draggedObject: React.State = new React.State(undefined); // SUGGESTIONS // boards & tasks boardFilterStringSuggestions: React.ListState = new React.ListState(); taskCategorySuggestions: React.ListState = new React.ListState(); taskStatusSuggestions: React.ListState = new React.ListState(); // init constructor( public readonly storageModel: StorageModel, public readonly settingsModel: SettingsModel, public readonly connectionModel: ConnectionModel, public readonly chatListModel: ChatListModel, public readonly fileTransferModel: FileTransferModel, ) { this.translations = allTranslations[settingsModel.language] || allTranslations.en; document.body.addEventListener("keydown", this.handleKeyDown); window.onpopstate = () => { this.closeContext(this.context.contextId, true); } } // util static checkIsKeystroke(e: KeyboardEvent): boolean { return (e.metaKey || e.altKey) && e.ctrlKey; } } export class Context { contextId = v4(); keystrokes = new Map void>(); handleKeystroke = (e: KeyboardEvent): boolean => { const fn: (() => void) | undefined = this.keystrokes.get( e.key.toLowerCase(), ); if (!fn) return false; fn(); return true; }; close = (): void => {}; handleContextClose = (fromHistoryEvent: boolean): void => {}; registerKeyStroke = (key: string, fn: () => void): void => { this.keystrokes.set(key, fn); }; constructor(public contextDebugDescription: string) { } } export class ContextHost extends Context { coreViewModel: CoreViewModel; contexts = new Map(); currentContext = new React.State(undefined); get isOpen(): boolean { return false; } get contextSelection(): T | undefined { return undefined; } registerContext = (key: T, context: Context): void => { this.contexts.set(key, context); }; closeCurrentContext = (): void => { if (this.currentContext.value) { this.coreViewModel.closeContext( this.currentContext.value.contextId, ); } this.currentContext.value = undefined; }; updateContexts = (): void => { if (this.isOpen == false) return; const selectedContext: Context | undefined = this.contexts.get( this.contextSelection, ); if (!selectedContext) return; if (selectedContext != this.currentContext.value) { this.closeCurrentContext(); } this.coreViewModel.context = selectedContext; this.currentContext.value = selectedContext; }; }