import { EventSlot } from '../library-ts/browser/events/EventSlot.js'; import { FileEditorRegistry } from './FileEditorRegistry.js'; export interface DocumentOpenedEvent { path: string; content: string; editorTag: string; targetElement?: HTMLElement; } export interface DocumentPathEvent { path: string; } export class Editor { static _instance: Editor = null; static get(): Editor { if ( ! this._instance ) { this._instance = new Editor(); } return this._instance; } projectId: string = ''; projectName: string = ''; openDocs: Map = new Map(); activeDoc: string | null = null; fileEditorRegistry: FileEditorRegistry = new FileEditorRegistry(); readonly onDocumentOpened: EventSlot = new EventSlot(); readonly onDocumentDirty: EventSlot = new EventSlot(); readonly onDocumentSaved: EventSlot = new EventSlot(); readonly onFilesChanged: EventSlot = new EventSlot(); readonly onFileTypeUnknown: EventSlot = new EventSlot(); async openDocument( filePath: string ): Promise { await this.fileEditorRegistry.load( this.projectId ); const editorTag = this.fileEditorRegistry.resolve( filePath ); if ( editorTag === null ) { this.onFileTypeUnknown.dispatch( { path: filePath } ); return; } if ( ! this.openDocs.has( filePath ) ) { const res = await fetch( `/api/files/${this.projectId}/${filePath}` ); const content = await res.text(); this.openDocs.set( filePath, { content, dirty: false } ); } this.activeDoc = filePath; const entry = this.openDocs.get( filePath )!; this.onDocumentOpened.dispatch( { path: filePath, content: entry.content, editorTag } ); } markDirty( filePath: string, content: string ): void { const doc = this.openDocs.get( filePath ); if ( ! doc ) { return; } doc.content = content; doc.dirty = true; this.onDocumentDirty.dispatch( { path: filePath } ); } async openDocumentIn( filePath: string, panelElement: HTMLElement ): Promise { await this.fileEditorRegistry.load( this.projectId ); const editorTag = this.fileEditorRegistry.resolve( filePath ); if ( editorTag === null ) { this.onFileTypeUnknown.dispatch( { path: filePath } ); return; } if ( !this.openDocs.has( filePath ) ) { const res = await fetch( `/api/files/${this.projectId}/${filePath}` ); const content = await res.text(); this.openDocs.set( filePath, { content, dirty: false } ); } this.activeDoc = filePath; const entry = this.openDocs.get( filePath )!; this.onDocumentOpened.dispatch( { path: filePath, content: entry.content, editorTag, targetElement: panelElement } ); } async save( filePath: string ): Promise { const doc = this.openDocs.get( filePath ); if ( ! doc || ! doc.dirty ) { return; } await fetch( `/api/files/${this.projectId}/${filePath}`, { method: 'PUT', headers: { 'Content-Type': 'text/plain' }, body: doc.content } ); doc.dirty = false; this.onDocumentSaved.dispatch( { path: filePath } ); } }