155 lines
4.9 KiB
Plaintext
155 lines
4.9 KiB
Plaintext
@using Microsoft.JSInterop
|
|
@implements IAsyncDisposable
|
|
@inject IJSRuntime JS
|
|
@inject HttpClient Http
|
|
|
|
<div class="markdown-editor-container" style="height: @Height; width: @Width;">
|
|
<div id="@EditorId" class="milkdown-editor-wrapper"></div>
|
|
@if (ShowFetchButton)
|
|
{
|
|
<div class="editor-actions">
|
|
<button type="button" @onclick="FetchContentAsync" class="nexus-btn">
|
|
Fetch Markdown Content
|
|
</button>
|
|
</div>
|
|
}
|
|
</div>
|
|
|
|
@code {
|
|
private readonly string EditorId = $"milkdown-editor-{Guid.NewGuid():N}";
|
|
private readonly CancellationTokenSource _cts = new();
|
|
private IJSObjectReference? _module;
|
|
private DotNetObjectReference<MarkdownEditor>? _dotNetHelper;
|
|
|
|
[Parameter]
|
|
public bool ShowFetchButton { get; set; } = true;
|
|
|
|
[Parameter]
|
|
public string InitialMarkdown { get; set; } = string.Empty;
|
|
|
|
[Parameter]
|
|
public EventCallback<string> OnSave { get; set; }
|
|
|
|
[Parameter]
|
|
public string Height { get; set; } = "500px";
|
|
|
|
[Parameter]
|
|
public string Width { get; set; } = "100%";
|
|
|
|
protected override async Task OnAfterRenderAsync(bool firstRender)
|
|
{
|
|
if (firstRender)
|
|
{
|
|
_dotNetHelper = DotNetObjectReference.Create(this);
|
|
try
|
|
{
|
|
// Import the isolated JavaScript module
|
|
_module = await JS.InvokeAsync<IJSObjectReference>(
|
|
"import",
|
|
"./_content/NexusReader.UI.Shared/js/milkdownWrapper.js"
|
|
);
|
|
|
|
// Call the initialization function in the wrapper
|
|
await _module.InvokeVoidAsync("initEditor", EditorId, _dotNetHelper, InitialMarkdown);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
// Log the exception gracefully and do not crash the component
|
|
Console.WriteLine($"[MarkdownEditor] Error initializing Milkdown editor: {ex.Message}");
|
|
}
|
|
}
|
|
}
|
|
|
|
public async Task FetchContentAsync()
|
|
{
|
|
if (_module is not null)
|
|
{
|
|
try
|
|
{
|
|
// Retrieve the updated markdown from JS
|
|
var markdown = await _module.InvokeAsync<string>("getMarkdownContent", EditorId);
|
|
|
|
if (OnSave.HasDelegate)
|
|
{
|
|
await OnSave.InvokeAsync(markdown);
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Console.WriteLine($"[MarkdownEditor] Error fetching markdown content: {ex.Message}");
|
|
}
|
|
}
|
|
}
|
|
|
|
[JSInvokable]
|
|
public async Task<string> UploadImageFromJs(string filename, string contentType, byte[] fileBytes)
|
|
{
|
|
try
|
|
{
|
|
using var content = new MultipartFormDataContent();
|
|
var fileContent = new ByteArrayContent(fileBytes);
|
|
fileContent.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue(contentType);
|
|
content.Add(fileContent, "file", filename);
|
|
|
|
var response = await Http.PostAsync("/api/media/upload", content, _cts.Token);
|
|
if (response.IsSuccessStatusCode)
|
|
{
|
|
var result = await response.Content.ReadFromJsonAsync<NexusReader.Application.DTOs.Media.UploadResultDto>(
|
|
NexusReader.Application.Common.AppJsonContext.Default.UploadResultDto, _cts.Token);
|
|
return result?.Url ?? string.Empty;
|
|
}
|
|
else
|
|
{
|
|
var errorMsg = await response.Content.ReadAsStringAsync();
|
|
Console.WriteLine($"[MarkdownEditor] Image upload failed: {response.StatusCode} - {errorMsg}");
|
|
return string.Empty;
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Console.WriteLine($"[MarkdownEditor] Exception during image upload: {ex.Message}");
|
|
return string.Empty;
|
|
}
|
|
}
|
|
|
|
public async ValueTask DisposeAsync()
|
|
{
|
|
try
|
|
{
|
|
_cts.Cancel();
|
|
_cts.Dispose();
|
|
}
|
|
catch
|
|
{
|
|
// Fail silently if cancellation token disposal fails
|
|
}
|
|
|
|
try
|
|
{
|
|
if (_module is not null)
|
|
{
|
|
// Clean up the JS editor instance to prevent memory leaks
|
|
await _module.InvokeVoidAsync("destroyEditor", EditorId);
|
|
await _module.DisposeAsync();
|
|
}
|
|
}
|
|
catch (JSDisconnectedException)
|
|
{
|
|
// Fail silently during circuit disconnection
|
|
}
|
|
catch (ObjectDisposedException)
|
|
{
|
|
// Fail silently if JS runtime/module is already disposed
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
// Log other unexpected errors
|
|
Console.WriteLine($"[MarkdownEditor] Unexpected error during JS cleanup: {ex.Message}");
|
|
}
|
|
finally
|
|
{
|
|
_dotNetHelper?.Dispose();
|
|
}
|
|
}
|
|
}
|