@inherits LocalizableComponentBase
@ContentLength/@MaxContentLength
@if (showPreviewButton && isPreviewOpen && MessageForm.Content is { Length: > 0 }) {
@switch (MessageForm.ContentType) { case ContentType.Markdown: @((MarkupString)Markdown.ToHtml(MessageForm.Content)) break; case ContentType.HTML:

@((MarkupString)MessageForm.Content)

break; }
}
@foreach (var media in MessageForm.Media) { switch (MessageForm.MediaType) { case MediaType.Images:
@media.AltText

@media.FileName

@media.ContentType @media.Size.GetFileSize(Localizer)

break; case MediaType.Video: case MediaType.Documents:

@media.FileName

@media.ContentType @media.Size.GetFileSize(Localizer)

break; case MediaType.Audio:

@media.FileName

@media.ContentType @media.Size.GetFileSize(Localizer)

break; } }
@* A label styled as a button opens the hidden file input. *@ @foreach (var mediaType in Enum.GetValues()) { }
@foreach (var contentType in Enum.GetValues()) { }
@if (showPreviewButton) { }
@Localizer["Post"]
@code { const int MaxContentLength = 5_000; [Inject] ILoggingService Logger { get; set; } [Parameter] public Message AnsweringMessage { get; set; } [Parameter] public EventCallback OnMessageSubmit { get; set; } MessageForm MessageForm { get; set; } = new(); List fileErrors = []; string contentError; string acceptedFilesTypes = ".jpg,.jpeg,.png,.gif"; bool showPreviewButton; bool isPreviewOpen; // Content is null until the user types: a form starts without text. int ContentLength => MessageForm.Content?.Length ?? 0; int MaximumFileCount => MessageForm.MediaType switch { MediaType.Images => 5, MediaType.Video or MediaType.Audio => 1, MediaType.Documents => 3, _ => 0 }; long MaximumFileSize => MessageForm.MediaType switch { MediaType.Images or MediaType.Documents => 3_145_728, MediaType.Audio => 5_242_880, MediaType.Video => 20_971_520, _ => 0 }; protected override void OnInitialized() { IsLoading = false; if (AnsweringMessage is null) return; MessageForm.Title = AnsweringMessage.Title; MessageForm.RootMessageId = AnsweringMessage.RootMessageId ?? AnsweringMessage.MessageId; } void UpdateMessageType(MessageType messageType) { MessageForm.MessageType = messageType; MessageForm.IsScopeOptionsOpen = false; } bool ShouldDisableUpload() => MessageForm.Media.Count >= MaximumFileCount; bool ShouldHaveMultipleUpload() => MessageForm.MediaType is MediaType.Images or MediaType.Documents; async Task OnFileChange(InputFileChangeEventArgs eventArgs) { fileErrors = []; var maximumFileCount = MaximumFileCount; if (eventArgs.FileCount + MessageForm.Media.Count > maximumFileCount) { fileErrors.Add(Localizer["The maximum number of files accepted is {0}, but {1} were supplied.", maximumFileCount, MessageForm.Media.Count + eventArgs.FileCount]); return; } var maximumFileSize = MaximumFileSize; foreach (var file in eventArgs.GetMultipleFiles(maximumFileCount)) { if (file.Name == default || file.ContentType == default || MessageForm.Media.Any(m => m.FileName == file.Name)) continue; if (file.Size > maximumFileSize) { fileErrors.Add(Localizer["Supplied file \"{0}\" with size {1} exceeds the maximum of {2}.", file.Name, file.Size.GetFileSize(Localizer), maximumFileSize.GetFileSize(Localizer)]); continue; } var uploadMedia = await ReadFile(file, maximumFileSize); if (uploadMedia is null) { fileErrors.Add(Localizer["The file \"{0}\" could not be read.", file.Name]); continue; } MessageForm.Media.Add(uploadMedia); } } /// Reads a picked file into memory; null when the browser can't read it (logged). async Task ReadFile(IBrowserFile file, long maximumFileSize, CancellationToken cancellationToken = default) { try { using var memoryStream = new MemoryStream(); await using var fileStream = file.OpenReadStream(maximumFileSize, cancellationToken); await fileStream.CopyToAsync(memoryStream, cancellationToken); var uploadMedia = new UploadMedia { FileName = file.Name, ContentType = file.ContentType, Size = file.Size, Blob = memoryStream.ToArray() }; if (MessageForm.MediaType is MediaType.Images or MediaType.Audio) uploadMedia.Base64Preview = $"data:{uploadMedia.ContentType};base64,{Convert.ToBase64String(uploadMedia.Blob)}"; return uploadMedia; } catch (Exception ex) { await Logger.ProcessError(ex, $"{nameof(MessageUpsertForm)}.{nameof(ReadFile)}:{file.Name}", cancellationToken); return default; } } void RemoveFile(UploadMedia media) { MessageForm.Media.Remove(media); } void OnTitleChanged(string value) { MessageForm.Title = value; } void OnContentTypeChanged(ContentType contentType) { MessageForm.ContentType = contentType; showPreviewButton = contentType is ContentType.Markdown or ContentType.HTML; } void OnMediaTypeChanged(MediaType mediaType) { MessageForm.MediaType = mediaType; acceptedFilesTypes = mediaType switch { MediaType.Images => ".jpg,.jpeg,.png,.gif", MediaType.Video => ".webm,.mp4,.m4v", MediaType.Audio => ".mp3,.wav,.flac,.m4a", MediaType.Documents => ".xlsx,.csv,.ppt,.odt", _ => default }; } void OnOpenClosePreview() { isPreviewOpen = !isPreviewOpen; } async Task OnValidSubmit() { contentError = default; if (string.IsNullOrWhiteSpace(MessageForm.Content) && MessageForm.Media.Count == 0) { contentError = Localizer["Missing content, either message or media"]; return; } await OnMessageSubmit.InvokeAsync(MessageForm); } }