feat: Implement a real-time character counter and limit validation for the rich text editor, including timer management.

This commit is contained in:
2026-02-26 17:59:50 +01:00
parent 5f2e7a9b56
commit 6b23a40196

View File

@@ -4,6 +4,7 @@
@using Microsoft.AspNetCore.Components.Forms
@namespace SZUAbsolventenverein.Module.HallOfFame
@implements IDisposable
@inherits ModuleBase
@inject IHallOfFameService HallOfFameService
@inject NavigationManager NavigationManager
@@ -42,6 +43,11 @@
{
<RichTextEditor Content="@_description" @ref="@_richTextEditorRef"
Placeholder="Beschreibe deinen Werdegang..."></RichTextEditor>
<div class="text-muted small mt-1">
Aktuell: <strong
class="@(_currentCharCount > _charLimit ? "text-danger" : "text-success")">@_currentCharCount</strong>
von maximal @_charLimit Zeichen.
</div>
}
</div>
</div>
@@ -157,9 +163,32 @@ new Stylesheet("_content/SZUAbsolventenverein.Module.HallOfFame/Module.css")
private string _modifiedby;
private DateTime _modifiedon;
private int _charLimit = 500;
private int _currentCharCount = 0;
private System.Timers.Timer _timer;
protected override async Task OnInitializedAsync()
{
_timer = new System.Timers.Timer(1000); // 1 sekunde
_timer.Elapsed += async (s, e) =>
{
if (_richTextEditorRef != null && _descriptionLoaded)
{
try
{
var html = await _richTextEditorRef.GetHtml();
var plainText = System.Text.RegularExpressions.Regex.Replace(html ?? "", "<.*?>", String.Empty);
plainText = System.Net.WebUtility.HtmlDecode(plainText);
if (_currentCharCount != plainText.Length)
{
_currentCharCount = plainText.Length;
await InvokeAsync(StateHasChanged);
}
}
catch { } // Ignore interop errors during disposal
}
};
_timer.Start();
try
{
// Load character limit setting
@@ -263,6 +292,7 @@ new Stylesheet("_content/SZUAbsolventenverein.Module.HallOfFame/Module.css")
{
try
{
ClearModuleMessage();
validated = true;
// Get the HTML content from the rich text editor
if (_richTextEditorRef != null)
@@ -273,6 +303,16 @@ new Stylesheet("_content/SZUAbsolventenverein.Module.HallOfFame/Module.css")
var interop = new Oqtane.UI.Interop(JSRuntime);
if (await interop.FormValid(form))
{
// Custom character limit validation for rich text
var plainText = System.Text.RegularExpressions.Regex.Replace(_description ?? "", "<.*?>", String.Empty);
plainText = System.Net.WebUtility.HtmlDecode(plainText);
if (plainText.Length > _charLimit)
{
AddModuleMessage($"Fehler: Die Beschreibung ist zu lang (Aktuell {plainText.Length}, Maximal {_charLimit} Zeichen).",
MessageType.Warning);
return;
}
_status = status;
if (PageState.Action == "Add")
@@ -333,4 +373,10 @@ new Stylesheet("_content/SZUAbsolventenverein.Module.HallOfFame/Module.css")
AddModuleMessage("Fehler beim Löschen des Eintrags.", MessageType.Error);
}
}
public void Dispose()
{
_timer?.Stop();
_timer?.Dispose();
}
}