From 075934343e9056b2e4e168a0481b69ba087b41d5 Mon Sep 17 00:00:00 2001 From: Thorsten Sommer Date: Sat, 6 Jun 2026 09:51:42 +0200 Subject: [PATCH] Fixed escape key handling --- .../Dialogs/WorkspaceSelectionDialog.razor | 90 +++++++++---------- .../Dialogs/WorkspaceSelectionDialog.razor.cs | 64 ++++++++++--- app/MindWork AI Studio/wwwroot/app.js | 27 ++++++ 3 files changed, 122 insertions(+), 59 deletions(-) diff --git a/app/MindWork AI Studio/Dialogs/WorkspaceSelectionDialog.razor b/app/MindWork AI Studio/Dialogs/WorkspaceSelectionDialog.razor index 33522b55..3e0cee72 100644 --- a/app/MindWork AI Studio/Dialogs/WorkspaceSelectionDialog.razor +++ b/app/MindWork AI Studio/Dialogs/WorkspaceSelectionDialog.razor @@ -1,63 +1,59 @@ @inherits MSGComponentBase -
- - @this.Message - - - @foreach (var workspace in this.workspaces) - { - - } - -
+ + @this.Message + + + @foreach (var workspace in this.workspaces) + { + + } +
-
- - + + + @if (this.showCreateWorkspaceForm) + { + + + + } + else + { + + @T("Create new workspace") + + } + + + + @T("Cancel") + @if (this.showCreateWorkspaceForm) { - - - + + @T("Add workspace") + } else { - - @T("Create new workspace") + + @this.ConfirmText } - - - - @T("Cancel") - - @if (this.showCreateWorkspaceForm) - { - - @T("Add workspace") - - } - else - { - - @this.ConfirmText - - } - -
+
\ No newline at end of file diff --git a/app/MindWork AI Studio/Dialogs/WorkspaceSelectionDialog.razor.cs b/app/MindWork AI Studio/Dialogs/WorkspaceSelectionDialog.razor.cs index b5020325..16374502 100644 --- a/app/MindWork AI Studio/Dialogs/WorkspaceSelectionDialog.razor.cs +++ b/app/MindWork AI Studio/Dialogs/WorkspaceSelectionDialog.razor.cs @@ -12,6 +12,9 @@ public partial class WorkspaceSelectionDialog : MSGComponentBase [CascadingParameter] private IMudDialogInstance MudDialog { get; set; } = null!; + [Inject] + private IJSRuntime JsRuntime { get; init; } = null!; + [Parameter] public string Message { get; set; } = string.Empty; @@ -22,7 +25,9 @@ public partial class WorkspaceSelectionDialog : MSGComponentBase public string ConfirmText { get; set; } = "OK"; private readonly List workspaces = []; - private MudForm createWorkspaceForm = null!; + private readonly string escapeHandlerId = $"workspace-selection-dialog-{Guid.NewGuid():N}"; + private MudForm? createWorkspaceForm; + private DotNetObjectReference? dotNetReference; private Guid selectedWorkspace; private string newWorkspaceName = string.Empty; private bool isCreatingWorkspace; @@ -44,6 +49,17 @@ public partial class WorkspaceSelectionDialog : MSGComponentBase await base.OnInitializedAsync(); } + protected override async Task OnAfterRenderAsync(bool firstRender) + { + if (firstRender) + { + this.dotNetReference = DotNetObjectReference.Create(this); + await this.JsRuntime.InvokeVoidAsync("registerEscapeHandler", this.escapeHandlerId, this.dotNetReference); + } + + await base.OnAfterRenderAsync(firstRender); + } + #endregion private string? ValidateNewWorkspaceName(string? workspaceName) @@ -80,16 +96,6 @@ public partial class WorkspaceSelectionDialog : MSGComponentBase await this.CreateWorkspaceAsync(); } - private void HandleDialogKeyDown(KeyboardEventArgs keyEvent) - { - var key = keyEvent.Key.ToLowerInvariant(); - var code = keyEvent.Code.ToLowerInvariant(); - if (key is not "escape" && code is not "escape") - return; - - this.Cancel(); - } - private void ShowCreateWorkspaceForm() { this.createWorkspaceError = null; @@ -100,6 +106,9 @@ public partial class WorkspaceSelectionDialog : MSGComponentBase private async Task CreateWorkspaceAsync() { + if (this.createWorkspaceForm is null) + return; + this.createWorkspaceError = null; this.createWorkspaceErrorName = null; await this.createWorkspaceForm.Validate(); @@ -141,9 +150,40 @@ public partial class WorkspaceSelectionDialog : MSGComponentBase this.createWorkspaceError = null; this.createWorkspaceErrorName = null; this.newWorkspaceName = string.Empty; - this.createWorkspaceForm.ResetValidation(); + this.createWorkspaceForm?.ResetValidation(); this.showCreateWorkspaceForm = false; } + + [JSInvokable] + public async Task HandleEscapeKeyAsync() + { + await this.InvokeAsync(() => + { + this.Cancel(); + this.StateHasChanged(); + }); + } private void Confirm() => this.MudDialog.Close(DialogResult.Ok(this.selectedWorkspace)); + + #region Overrides of MSGComponentBase + + protected override void DisposeResources() + { + try + { + _ = this.JsRuntime.InvokeVoidAsync("unregisterEscapeHandler", this.escapeHandlerId).AsTask(); + } + catch + { + // Ignore JS cleanup errors while the dialog is being disposed. + } + + this.dotNetReference?.Dispose(); + this.dotNetReference = null; + + base.DisposeResources(); + } + + #endregion } \ No newline at end of file diff --git a/app/MindWork AI Studio/wwwroot/app.js b/app/MindWork AI Studio/wwwroot/app.js index a2f8f967..c2845f76 100644 --- a/app/MindWork AI Studio/wwwroot/app.js +++ b/app/MindWork AI Studio/wwwroot/app.js @@ -131,3 +131,30 @@ window.formatChatInputMarkdown = function (inputId, formatType) { return nextValue } + +const escapeHandlers = new Map() + +window.registerEscapeHandler = function (id, dotNetReference) { + window.unregisterEscapeHandler(id) + + const handler = function (event) { + if (event.key !== 'Escape') + return + + event.preventDefault() + event.stopPropagation() + dotNetReference.invokeMethodAsync('HandleEscapeKeyAsync').catch(() => {}) + } + + document.addEventListener('keydown', handler, true) + escapeHandlers.set(id, handler) +} + +window.unregisterEscapeHandler = function (id) { + const handler = escapeHandlers.get(id) + if (!handler) + return + + document.removeEventListener('keydown', handler, true) + escapeHandlers.delete(id) +} \ No newline at end of file