@page "/" @attribute [Authorize] @using NexusReader.UI.Shared.Services @implements IAsyncDisposable @inject IQuizStateService QuizState @inject IFocusModeService FocusMode @inject IJSRuntime JS Nexus E-Reader
@code { private ReaderCanvas? readerCanvas; private string? _activeQuizBlockId; private IJSObjectReference? _interopModule; private IJSObjectReference? _keydownHandler; private DotNetObjectReference? _dotNetRef; protected override async Task OnInitializedAsync() { QuizState.OnQuizRequested += HandleQuizRequested; FocusMode.OnFocusModeChanged += StateHasChanged; await FocusMode.InitializeAsync(); } protected override async Task OnAfterRenderAsync(bool firstRender) { if (firstRender) { try { _interopModule = await JS.InvokeAsync("import", "./_content/NexusReader.UI.Shared/js/focusInterop.js"); _dotNetRef = DotNetObjectReference.Create(this); _keydownHandler = await _interopModule.InvokeAsync("attachKeyboardListener", _dotNetRef); } catch { } /* ignored dynamically */ } } [JSInvokable] public async Task OnFocusKeypressed() { await FocusMode.ToggleAsync(); StateHasChanged(); } private async Task HandleNodeSelected(string nodeId) { if (readerCanvas != null) { await readerCanvas.ScrollToNodeAsync(nodeId); } } private void HandleQuizRequested(string blockId) { _activeQuizBlockId = blockId; StateHasChanged(); } public async ValueTask DisposeAsync() { QuizState.OnQuizRequested -= HandleQuizRequested; FocusMode.OnFocusModeChanged -= StateHasChanged; if (_interopModule != null && _keydownHandler != null) { try { await _interopModule.InvokeVoidAsync("detachKeyboardListener", _keydownHandler); await _interopModule.DisposeAsync(); await _keydownHandler.DisposeAsync(); } catch { } // Circuit disconnected catch explicitly } _dotNetRef?.Dispose(); } }