diff --git a/src/BootstrapBlazor.Shared/Demos/Uploads/UploadAvatar.razor b/src/BootstrapBlazor.Shared/Demos/Uploads/UploadAvatar.razor
deleted file mode 100644
index fac95fa7e80d2c0c9e8408848f9b4528fb85fb24..0000000000000000000000000000000000000000
--- a/src/BootstrapBlazor.Shared/Demos/Uploads/UploadAvatar.razor
+++ /dev/null
@@ -1,117 +0,0 @@
-@inject IStringLocalizer Localizer
-@inject ToastService ToastService
-@implements IDisposable
-
-
-
-
@Localizer["AvatarUploadTips1"]
-
-
-
-
@Localizer["AvatarUploadTips2"]
-
-
-
-
@((MarkupString)Localizer["AvatarUploadTips3"].Value)
-
-
@((MarkupString)Localizer["AvatarUploadTips5"].Value)
-
-
-
-
-
@((MarkupString)Localizer["AvatarUploadTips6"].Value)
-
-
-
-
@((MarkupString)Localizer["AvatarUploadTips7"].Value)
-
-
-
-
-
-
-
-@code {
- ///
- /// Dispose
- ///
- public void Dispose()
- {
- ReadAvatarToken?.Cancel();
- GC.SuppressFinalize(this);
- }
-
- private static long MaxFileLength => 200 * 1024 * 1024;
-
- private Person Foo { get; set; } = new Person();
-
- private List PreviewFileList { get; } = new(new[] { new UploadFile { PrevUrl = "./images/Argo.png" } });
-
- [NotNull]
- private ConsoleLogger? Logger { get; set; }
-
- private CancellationTokenSource? ReadAvatarToken { get; set; }
-
- private async Task OnAvatarUpload(UploadFile file)
- {
- // 示例代码,使用 base64 格式
- if (file != null && file.File != null)
- {
- var format = file.File.ContentType;
- if (CheckValidAvatarFormat(format))
- {
- ReadAvatarToken ??= new CancellationTokenSource();
- if (ReadAvatarToken.IsCancellationRequested)
- {
- ReadAvatarToken.Dispose();
- ReadAvatarToken = new CancellationTokenSource();
- }
-
- await file.RequestBase64ImageFileAsync(format, 640, 480, MaxFileLength, ReadAvatarToken.Token);
- }
- else
- {
- file.Code = 1;
- file.Error = Localizer["UploadsFormatError"];
- }
-
- if (file.Code != 0)
- {
- await ToastService.Error(Localizer["UploadsAvatarMsg"], $"{file.Error} {format}");
- }
- }
- }
-
- private static bool CheckValidAvatarFormat(string format)
- {
- return "jpg;png;bmp;gif;jpeg".Split(';').Any(f => format.Contains(f, StringComparison.OrdinalIgnoreCase));
- }
-
- private Task OnAvatarValidSubmit(EditContext context)
- {
- Logger.Log(Foo.Picture?.Name ?? "");
- return Task.CompletedTask;
- }
-
- private class Person
- {
- [Required]
- [StringLength(20, MinimumLength = 2)]
- public string Name { get; set; } = "Blazor";
-
- [Required]
- [FileValidation(Extensions = new string[] { ".png", ".jpg", ".jpeg" }, FileSize = 50 * 1024)]
- public IBrowserFile? Picture { get; set; }
- }
-}
diff --git a/src/BootstrapBlazor.Shared/Demos/Uploads/UploadBase64.razor b/src/BootstrapBlazor.Shared/Demos/Uploads/UploadBase64.razor
deleted file mode 100644
index 347cf6586cc6a65337a50a8cd4ba78889f1c5a31..0000000000000000000000000000000000000000
--- a/src/BootstrapBlazor.Shared/Demos/Uploads/UploadBase64.razor
+++ /dev/null
@@ -1,8 +0,0 @@
-
-
-@code {
- private List Base64FormatFileList { get; } = new List()
- {
- new UploadFile { FileName = "Test", PrevUrl = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACoAAAAkCAYAAAD/yagrAAAE60lEQVR4AWJwL/AB9GIWvI0jURz/L1NomZmZP8p9kWNmhnIbKPdomZmZGcJgO7QsWMbce55Yl11t47FbVdKTYpjOr/+H4y4Z/MpYeJVV8KVvokFRylq9osKfVtGQ/NHyPl2CbNVGwau2oOlmgUDJtDJGzxtvvIA3vRH+7IgeA0VtYhQBtKPlToFgC6RY58aggfwLNKhr0Zry2NnPrpIM2YGW2+UBG1IEmdGVJEVXE+hQXt8joKhLjdGVZHd7TSD9DHmT3J1dheroSF4fhnvUVQwbZx9UOnHSzQjkTN0tIG+8hFdbxet4PQOG4WqJwN1hFVb+xUBmCblxvxRkIE+Q+Yf0T31NSrp4/RV4FhHgoSTchQRZBK4D1+Fe2q2g8CYXU6buQyNDaiZKZhn0IYXHVwbkRQydHyawOAGGisa/o3DvI/jF3QKKiuAy+LKs5CvaXMLdeXb35wbkKTjmReDZHysCBosWJqN7r0jZ/VfgXtIlUNQnVpK7D4nNJSC5BHGi1d108Ppr8MxlF0cJqBSyFJaUfUnvHLyO4cttgaI+NhGB7HE0MaSUks/gU5vwe1gv5tfhmUmAhxME8jbIUtiEDus+fhmDJlgCRY0ylZRZhybKWtNinmYlH9NvL5puO3m9UHOkgzb3xuF5HCkDyhYiSwrYVfQPTpYChTc+E35tG9VJBjGFFNmtVlNMDnjzbx0EBpKq1eTeh2awbArBRuHadBWu6WVB4U/NITfuobYoCZl7QL//wDtr+nTmsgzQh2Kwgtz7QAZWFeGw/RI8s94Kigp1PvzZg2i9x11FDtKn/oZCoZdZxhaAXmG4/ohJKHudLE1Gyu66DOfs10BRR5CU3TKQIrtzj9BAkF991dsMslTZEClLsI+jFmANZYFAdAJl9QG03jWH9GrcFh9QTP4Of6GfJGSpsv1J2aoEKRuWCANNJNqOFAaPAW36rVRMCjVf6ZCtqYF2p6Asxg5mWK6tQamY9RCs8z1wF+FxTR5UqYT/3GC7oCkMHcjxKguq6cnl+Egf2whip3C9Yu56jk+GXXOtv1XIa8L1f3AFkHe9az83AmNanwV/bhfa5JKJ3n1slCUL8dk7CNfvVFMfySRThoxbK7fh18tTZXI2QeySLk88IRGsbHkqQj6wUJ72G5CloCXKZrdbLPgVMgVfQMq5m97bfQWOOeVbaK02nSA2ofn2y662UJE47horLZTe38oDjdxQUhmawocxa0OJ5hXjnZE4w1y0uc/iULKGfk+xNuZxI/BnjhFs+THPq4phmTsbeYPXRjFsJJ+NSMlnInHkxrwzGDjR3uBcG1/B/b/TwZkhubb6tP2oVfTAD2G4kw9vYiA2h+zy4GwYxd7S4qGOgd6oqVn6re1DTXiO4e4wPF+yQlF4ZCBfheSPIjJn+ciS/w93qjA6aZYqeQ5D3dTqvuE6GZNTkov5vqsYvLh7j8u1sWWkLIdBQR+q+XdtaKGhJCWBDpkwgSw9gRpKyoNKw6rjCLCDP4yVflSgWFwt3C0HSUo2BTFYX28fVAaWPpDx7wtwjOSSUszawnUT0KTudlfrFQwZ3WNf867CNZQhk/C8kIFUhJLt/O3Jzn62IYNwrUvA8zws4W61CGlDSfugXMz5pJgiSFYyXMYiRXdH4GmyqaR9UHLxzxG41KAwpZxRPN4kRf85Z5I4MvYfFUFGfemJG40AAAAASUVORK5CYII=" },
- };
-}
diff --git a/src/BootstrapBlazor.Shared/Demos/Uploads/UploadClickUpload.razor b/src/BootstrapBlazor.Shared/Demos/Uploads/UploadClickUpload.razor
deleted file mode 100644
index 3e14a3560c1a344b5a7a1efe53e93ac6e640704f..0000000000000000000000000000000000000000
--- a/src/BootstrapBlazor.Shared/Demos/Uploads/UploadClickUpload.razor
+++ /dev/null
@@ -1,89 +0,0 @@
-@inject IStringLocalizer Localizer
-@inject ToastService ToastService
-@inject IOptionsMonitor SiteOptions
-@implements IDisposable
-
-
-
-
@((MarkupString)Localizer["UploadClickUploadTips1"].Value)
-
-
-
-@((MarkupString)Localizer["UploadClickUploadTips2"].Value)
-
-@((MarkupString)Localizer["UploadClickUploadTips3ShowUploadList"].Value)
-
-
-@code {
- ///
- /// Dispose
- ///
- public void Dispose()
- {
- ReadToken?.Cancel();
- GC.SuppressFinalize(this);
- }
-
- private static readonly Random random = new();
-
- private async Task OnClickToUpload(UploadFile file)
- {
- // 示例代码,模拟 80% 几率保存成功
- var error = random.Next(1, 100) > 80;
- if (error)
- {
- file.Code = 1;
- file.Error = Localizer["UploadsError"];
- }
- else
- {
- await SaveToFile(file);
- }
- }
-
- private async Task OnClickToUploadNoUploadList(UploadFile file)
- {
- await ToastService.Success("Upload", $"{file.OriginFileName} uploaded success.");
- }
-
- private CancellationTokenSource? ReadToken { get; set; }
-
- private static long MaxFileLength => 200 * 1024 * 1024;
-
- private async Task SaveToFile(UploadFile file)
- {
- // Server Side 使用
- // Web Assembly 模式下必须使用 webapi 方式去保存文件到服务器或者数据库中
- // 生成写入文件名称
- var ret = false;
- if (!string.IsNullOrEmpty(SiteOptions.CurrentValue.WebRootPath))
- {
- var uploaderFolder = Path.Combine(SiteOptions.CurrentValue.WebRootPath, $"images{Path.DirectorySeparatorChar}uploader");
- file.FileName = $"{Path.GetFileNameWithoutExtension(file.OriginFileName)}-{DateTimeOffset.Now:yyyyMMddHHmmss}{Path.GetExtension(file.OriginFileName)}";
- var fileName = Path.Combine(uploaderFolder, file.FileName);
-
- ReadToken ??= new CancellationTokenSource();
- ret = await file.SaveToFileAsync(fileName, MaxFileLength, ReadToken.Token);
-
- if (ret)
- {
- // 保存成功
- file.PrevUrl = $"images/uploader/{file.FileName}";
- }
- else
- {
- var errorMessage = $"{Localizer["UploadsSaveFileError"]} {file.OriginFileName}";
- file.Code = 1;
- file.Error = errorMessage;
- await ToastService.Error(Localizer["UploadFile"], errorMessage);
- }
- }
- else
- {
- file.Code = 1;
- file.Error = Localizer["UploadsWasmError"];
- await ToastService.Information(Localizer["UploadsSaveFile"], Localizer["UploadsSaveFileMsg"]);
- }
- return ret;
- }
-}
diff --git a/src/BootstrapBlazor.Shared/Demos/Uploads/UploadFileIcon.razor b/src/BootstrapBlazor.Shared/Demos/Uploads/UploadFileIcon.razor
deleted file mode 100644
index 9ea06a4d12ff20b01f40d0a2f2526b9b6ac3b11b..0000000000000000000000000000000000000000
--- a/src/BootstrapBlazor.Shared/Demos/Uploads/UploadFileIcon.razor
+++ /dev/null
@@ -1,90 +0,0 @@
-@inject IStringLocalizer Localizer
-@inject ToastService ToastService
-@inject IOptionsMonitor SiteOptions
-@implements IDisposable
-
-
-
-@code {
- ///
- /// Dispose
- ///
- public void Dispose()
- {
- ReadToken?.Cancel();
- GC.SuppressFinalize(this);
- }
-
- private List DefaultFormatFileList { get; } = new List()
- {
- new UploadFile { FileName = "Test.xls" },
- new UploadFile { FileName = "Test.doc" },
- new UploadFile { FileName = "Test.ppt" },
- new UploadFile { FileName = "Test.mp3" },
- new UploadFile { FileName = "Test.mp4" },
- new UploadFile { FileName = "Test.pdf" },
- new UploadFile { FileName = "Test.cs" },
- new UploadFile { FileName = "Test.zip" },
- new UploadFile { FileName = "Test.txt" },
- new UploadFile { FileName = "Test.dat" }
- };
-
- private CancellationTokenSource? ReadToken { get; set; }
-
- private static long MaxFileLength => 200 * 1024 * 1024;
-
- private async Task OnCardUpload(UploadFile file)
- {
- if (file != null && file.File != null)
- {
- // 服务器端验证当文件大于 2MB 时提示文件太大信息
- if (file.Size > MaxFileLength)
- {
- await ToastService.Information(Localizer["UploadsFileMsg"], Localizer["UploadsFileError"]);
- file.Code = 1;
- file.Error = Localizer["UploadsFileError"];
- }
- else
- {
- await SaveToFile(file);
- }
- }
- }
-
- private async Task SaveToFile(UploadFile file)
- {
- // Server Side 使用
- // Web Assembly 模式下必须使用 webapi 方式去保存文件到服务器或者数据库中
- // 生成写入文件名称
- var ret = false;
- if (!string.IsNullOrEmpty(SiteOptions.CurrentValue.WebRootPath))
- {
- var uploaderFolder = Path.Combine(SiteOptions.CurrentValue.WebRootPath, $"images{Path.DirectorySeparatorChar}uploader");
- file.FileName = $"{Path.GetFileNameWithoutExtension(file.OriginFileName)}-{DateTimeOffset.Now:yyyyMMddHHmmss}{Path.GetExtension(file.OriginFileName)}";
- var fileName = Path.Combine(uploaderFolder, file.FileName);
-
- ReadToken ??= new CancellationTokenSource();
- ret = await file.SaveToFileAsync(fileName, MaxFileLength, ReadToken.Token);
-
- if (ret)
- {
- // 保存成功
- file.PrevUrl = $"images/uploader/{file.FileName}";
- }
- else
- {
- var errorMessage = $"{Localizer["UploadsSaveFileError"]} {file.OriginFileName}";
- file.Code = 1;
- file.Error = errorMessage;
- await ToastService.Error(Localizer["UploadFile"], errorMessage);
- }
- }
- else
- {
- file.Code = 1;
- file.Error = Localizer["UploadsWasmError"];
- await ToastService.Information(Localizer["UploadsSaveFile"], Localizer["UploadsSaveFileMsg"]);
- }
- return ret;
- }
-}
diff --git a/src/BootstrapBlazor.Shared/Demos/Uploads/UploadFolder.razor b/src/BootstrapBlazor.Shared/Demos/Uploads/UploadFolder.razor
deleted file mode 100644
index c81b42616ad8a07e40946be6316bf8f807b0cf11..0000000000000000000000000000000000000000
--- a/src/BootstrapBlazor.Shared/Demos/Uploads/UploadFolder.razor
+++ /dev/null
@@ -1,68 +0,0 @@
-@inject IStringLocalizer Localizer
-@inject ToastService ToastService
-@inject IOptionsMonitor SiteOptions
-@implements IDisposable
-
-
-
-@code {
- ///
- /// Dispose
- ///
- public void Dispose()
- {
- ReadToken?.Cancel();
- GC.SuppressFinalize(this);
- }
-
- private async Task OnUploadFolder(UploadFile file)
- {
- // 上传文件夹时会多次回调此方法
- await SaveToFile(file);
- }
-
- private CancellationTokenSource? ReadToken { get; set; }
-
- private static long MaxFileLength => 200 * 1024 * 1024;
-
- private async Task SaveToFile(UploadFile file)
- {
- // Server Side 使用
- // Web Assembly 模式下必须使用 webapi 方式去保存文件到服务器或者数据库中
- // 生成写入文件名称
- var ret = false;
- if (!string.IsNullOrEmpty(SiteOptions.CurrentValue.WebRootPath))
- {
- var uploaderFolder = Path.Combine(SiteOptions.CurrentValue.WebRootPath, $"images{Path.DirectorySeparatorChar}uploader");
- file.FileName = $"{Path.GetFileNameWithoutExtension(file.OriginFileName)}-{DateTimeOffset.Now:yyyyMMddHHmmss}{Path.GetExtension(file.OriginFileName)}";
- var fileName = Path.Combine(uploaderFolder, file.FileName);
-
- ReadToken ??= new CancellationTokenSource();
- ret = await file.SaveToFileAsync(fileName, MaxFileLength, ReadToken.Token);
-
- if (ret)
- {
- // 保存成功
- file.PrevUrl = $"images/uploader/{file.FileName}";
- }
- else
- {
- var errorMessage = $"{Localizer["UploadsSaveFileError"]} {file.OriginFileName}";
- file.Code = 1;
- file.Error = errorMessage;
- await ToastService.Error(Localizer["UploadFile"], errorMessage);
- }
- }
- else
- {
- file.Code = 1;
- file.Error = Localizer["UploadsWasmError"];
- await ToastService.Information(Localizer["UploadsSaveFile"], Localizer["UploadsSaveFileMsg"]);
- }
- return ret;
- }
-}
diff --git a/src/BootstrapBlazor.Shared/Demos/Uploads/UploadFormSettings.razor b/src/BootstrapBlazor.Shared/Demos/Uploads/UploadFormSettings.razor
deleted file mode 100644
index bdb94a8e45cae9fe2ac42207c48de9020b6e4dff..0000000000000000000000000000000000000000
--- a/src/BootstrapBlazor.Shared/Demos/Uploads/UploadFormSettings.razor
+++ /dev/null
@@ -1,37 +0,0 @@
-@inject IStringLocalizer Localizer
-
-
-
-
-
-@code {
- private static Task OnSubmit(EditContext context)
- {
- // 示例代码请根据业务情况自行更改
- // var fileName = Foo.Picture?.Name;
- return Task.CompletedTask;
- }
-
- private Person Foo { get; set; } = new Person();
-
- private class Person
- {
- [Required]
- [StringLength(20, MinimumLength = 2)]
- public string Name { get; set; } = "Blazor";
-
- [Required]
- [FileValidation(Extensions = new string[] { ".png", ".jpg", ".jpeg" }, FileSize = 50 * 1024)]
- public IBrowserFile? Picture { get; set; }
- }
-}
diff --git a/src/BootstrapBlazor.Shared/Demos/Uploads/UploadIconTemplate.razor b/src/BootstrapBlazor.Shared/Demos/Uploads/UploadIconTemplate.razor
deleted file mode 100644
index 942a2417d956a0215cd3264d9a5cd21e662202bb..0000000000000000000000000000000000000000
--- a/src/BootstrapBlazor.Shared/Demos/Uploads/UploadIconTemplate.razor
+++ /dev/null
@@ -1,98 +0,0 @@
-@inject IStringLocalizer Localizer
-@inject ToastService ToastService
-@inject IOptionsMonitor SiteOptions
-@implements IDisposable
-
-
-
-
-
-
-
-
-
-
-
-@code {
- ///
- /// Dispose
- ///
- public void Dispose()
- {
- ReadToken?.Cancel();
- GC.SuppressFinalize(this);
- }
-
- private List DefaultFormatFileList { get; } = new List()
- {
- new UploadFile { FileName = "Test.xls" },
- new UploadFile { FileName = "Test.doc" },
- new UploadFile { FileName = "Test.ppt" },
- new UploadFile { FileName = "Test.mp3" },
- new UploadFile { FileName = "Test.mp4" },
- new UploadFile { FileName = "Test.pdf" },
- new UploadFile { FileName = "Test.cs" },
- new UploadFile { FileName = "Test.zip" },
- new UploadFile { FileName = "Test.txt" },
- new UploadFile { FileName = "Test.dat" }
- };
-
- private CancellationTokenSource? ReadToken { get; set; }
-
- private static long MaxFileLength => 200 * 1024 * 1024;
-
- private async Task OnCardUpload(UploadFile file)
- {
- if (file != null && file.File != null)
- {
- // 服务器端验证当文件大于 2MB 时提示文件太大信息
- if (file.Size > MaxFileLength)
- {
- await ToastService.Information(Localizer["UploadsFileMsg"], Localizer["UploadsFileError"]);
- file.Code = 1;
- file.Error = Localizer["UploadsFileError"];
- }
- else
- {
- await SaveToFile(file);
- }
- }
- }
-
- private async Task SaveToFile(UploadFile file)
- {
- // Server Side 使用
- // Web Assembly 模式下必须使用 webapi 方式去保存文件到服务器或者数据库中
- // 生成写入文件名称
- var ret = false;
- if (!string.IsNullOrEmpty(SiteOptions.CurrentValue.WebRootPath))
- {
- var uploaderFolder = Path.Combine(SiteOptions.CurrentValue.WebRootPath, $"images{Path.DirectorySeparatorChar}uploader");
- file.FileName = $"{Path.GetFileNameWithoutExtension(file.OriginFileName)}-{DateTimeOffset.Now:yyyyMMddHHmmss}{Path.GetExtension(file.OriginFileName)}";
- var fileName = Path.Combine(uploaderFolder, file.FileName);
-
- ReadToken ??= new CancellationTokenSource();
- ret = await file.SaveToFileAsync(fileName, MaxFileLength, ReadToken.Token);
-
- if (ret)
- {
- // 保存成功
- file.PrevUrl = $"images/uploader/{file.FileName}";
- }
- else
- {
- var errorMessage = $"{Localizer["UploadsSaveFileError"]} {file.OriginFileName}";
- file.Code = 1;
- file.Error = errorMessage;
- await ToastService.Error(Localizer["UploadFile"], errorMessage);
- }
- }
- else
- {
- file.Code = 1;
- file.Error = Localizer["UploadsWasmError"];
- await ToastService.Information(Localizer["UploadsSaveFile"], Localizer["UploadsSaveFileMsg"]);
- }
- return ret;
- }
-}
diff --git a/src/BootstrapBlazor.Shared/Demos/Uploads/UploadNormal.razor b/src/BootstrapBlazor.Shared/Demos/Uploads/UploadNormal.razor
deleted file mode 100644
index 86dc7b9280ab0807272800b256d64e235bdf533b..0000000000000000000000000000000000000000
--- a/src/BootstrapBlazor.Shared/Demos/Uploads/UploadNormal.razor
+++ /dev/null
@@ -1,36 +0,0 @@
-@inject IStringLocalizer Localizer
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-@code {
- [NotNull]
- private ConsoleLogger? Logger { get; set; }
-
- private Task OnFileChange(UploadFile file)
- {
- // 未真正保存文件
- // file.SaveToFile()
- Logger.Log($"{file.File!.Name} {Localizer["UploadsSuccess"]}");
- return Task.FromResult("");
- }
-
- private Task OnFileDelete(UploadFile item)
- {
- Logger.Log($"{item.OriginFileName} {Localizer["UploadsRemoveMsg"]}");
- return Task.FromResult(true);
- }
-}
diff --git a/src/BootstrapBlazor.Shared/Demos/Uploads/UploadPreCardStyle.razor b/src/BootstrapBlazor.Shared/Demos/Uploads/UploadPreCardStyle.razor
deleted file mode 100644
index dfbcd97c59cbc743c1f80336f755bb9565d4c397..0000000000000000000000000000000000000000
--- a/src/BootstrapBlazor.Shared/Demos/Uploads/UploadPreCardStyle.razor
+++ /dev/null
@@ -1,85 +0,0 @@
-@inject IStringLocalizer Localizer
-@inject ToastService ToastService
-@inject IOptionsMonitor SiteOptions
-@implements IDisposable
-
-
-
-
@((MarkupString)Localizer["UploadPreCardStyleTips1"].Value)
-
-
-
-
@((MarkupString)Localizer["UploadPreCardStyleTips2"].Value)
-
-
-
-
-@code {
- ///
- /// Dispose
- ///
- public void Dispose()
- {
- ReadToken?.Cancel();
- GC.SuppressFinalize(this);
- }
-
- private CancellationTokenSource? ReadToken { get; set; }
-
- private static long MaxFileLength => 200 * 1024 * 1024;
-
- private async Task OnCardUpload(UploadFile file)
- {
- if (file != null && file.File != null)
- {
- // 服务器端验证当文件大于 2MB 时提示文件太大信息
- if (file.Size > MaxFileLength)
- {
- await ToastService.Information(Localizer["UploadsFileMsg"], Localizer["UploadsFileError"]);
- file.Code = 1;
- file.Error = Localizer["UploadsFileError"];
- }
- else
- {
- await SaveToFile(file);
- }
- }
- }
-
- private async Task SaveToFile(UploadFile file)
- {
- // Server Side 使用
- // Web Assembly 模式下必须使用 webapi 方式去保存文件到服务器或者数据库中
- // 生成写入文件名称
- var ret = false;
- if (!string.IsNullOrEmpty(SiteOptions.CurrentValue.WebRootPath))
- {
- var uploaderFolder = Path.Combine(SiteOptions.CurrentValue.WebRootPath, $"images{Path.DirectorySeparatorChar}uploader");
- file.FileName = $"{Path.GetFileNameWithoutExtension(file.OriginFileName)}-{DateTimeOffset.Now:yyyyMMddHHmmss}{Path.GetExtension(file.OriginFileName)}";
- var fileName = Path.Combine(uploaderFolder, file.FileName);
-
- ReadToken ??= new CancellationTokenSource();
- ret = await file.SaveToFileAsync(fileName, MaxFileLength, ReadToken.Token);
-
- if (ret)
- {
- // 保存成功
- file.PrevUrl = $"images/uploader/{file.FileName}";
- }
- else
- {
- var errorMessage = $"{Localizer["UploadsSaveFileError"]} {file.OriginFileName}";
- file.Code = 1;
- file.Error = errorMessage;
- await ToastService.Error(Localizer["UploadFile"], errorMessage);
- }
- }
- else
- {
- file.Code = 1;
- file.Error = Localizer["UploadsWasmError"];
- await ToastService.Information(Localizer["UploadsSaveFile"], Localizer["UploadsSaveFileMsg"]);
- }
- return ret;
- }
-}
diff --git a/src/BootstrapBlazor.Shared/Demos/Uploads/UploadedFiles.razor b/src/BootstrapBlazor.Shared/Demos/Uploads/UploadedFiles.razor
deleted file mode 100644
index 9f8d68afa76ae48ed375eae0160e264b96c941df..0000000000000000000000000000000000000000
--- a/src/BootstrapBlazor.Shared/Demos/Uploads/UploadedFiles.razor
+++ /dev/null
@@ -1,37 +0,0 @@
-@inject ToastService ToastService
-@implements IDisposable
-
-
-
-@code {
- ///
- /// Dispose
- ///
- public void Dispose()
- {
- GC.SuppressFinalize(this);
- }
-
- private async Task OnDownload(UploadFile item)
- {
- await ToastService.Success("文件下载", $"下载 {item.FileName} 成功");
- }
-
- private List DefaultFormatFileList { get; } = new List()
- {
- new UploadFile { FileName = "Test.xls" },
- new UploadFile { FileName = "Test.doc" },
- new UploadFile { FileName = "Test.ppt" },
- new UploadFile { FileName = "Test.mp3" },
- new UploadFile { FileName = "Test.mp4" },
- new UploadFile { FileName = "Test.pdf" },
- new UploadFile { FileName = "Test.cs" },
- new UploadFile { FileName = "Test.zip" },
- new UploadFile { FileName = "Test.txt" },
- new UploadFile { FileName = "Test.dat" }
- };
-}
diff --git a/src/BootstrapBlazor.Shared/Demos/VideoPlayers/VideoPlayersChangeURL.razor b/src/BootstrapBlazor.Shared/Demos/VideoPlayers/VideoPlayersChangeURL.razor
deleted file mode 100644
index cf2893481d6d7286e5a3e310fc88304f77f16fd0..0000000000000000000000000000000000000000
--- a/src/BootstrapBlazor.Shared/Demos/VideoPlayers/VideoPlayersChangeURL.razor
+++ /dev/null
@@ -1,66 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-@code {
- private string MineType = "video/mp4";
- private string Url = "//vjs.zencdn.net/v/oceans.mp4";
-
- [NotNull]
- private VideoPlayer? Player { get; set; }
-
- private List VideoList { get; } = new()
- {
- "https://rtvelivestream.akamaized.net/rtvesec/la1/la1_main.m3u8",
- "https://d2zihajmogu5jn.cloudfront.net/bipbop-advanced/bipbop_16x9_variant.m3u8",
- "https://test-streams.mux.dev/x36xhzz/x36xhzz.m3u8",
- "https://res.cloudinary.com/dannykeane/video/upload/sp_full_hd/q_80:qmax_90,ac_none/v1/dk-memoji-dark.m3u8",
- "https://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_fmp4/master.m3u8",
- "https://moctobpltc-i.akamaihd.net/hls/live/571329/eight/playlist.m3u8",
- "https://cph-p2p-msl.akamaized.net/hls/live/2000341/test/master.m3u8",
- "https://demo.unified-streaming.com/k8s/features/stable/video/tears-of-steel/tears-of-steel.mp4/.m3u8",
- "https://diceyk6a7voy4.cloudfront.net/e78752a1-2e83-43fa-85ae-3d508be29366/hls/fitfest-sample-1_Ott_Hls_Ts_Avc_Aac_16x9_1280x720p_30Hz_6.0Mbps_qvbr.m3u8"
- };
-
- private List Items { get; } = new();
-
- ///
- /// OnInitialized 方法
- ///
- protected override void OnInitialized()
- {
- base.OnInitialized();
- for (var i = 0; i < VideoList.Count; i++)
- {
- Items.Add(new SelectedItem { Text = $"TestVideo{i}", Value = VideoList[i] });
- }
- Items.Add(new SelectedItem { Text = "Mp4", Value = "//vjs.zencdn.net/v/oceans.mp4" });
- }
-
- private async Task ChangeURL(SelectedItem e)
- {
- Url = e.Value;
- MineType = e.Value.EndsWith("mp4") ? "video/mp4" : "application/x-mpegURL";
- StateHasChanged();
- await Apply();
- }
-
- private async Task Apply()
- {
- await Player.SetPoster("//vjs.zencdn.net/v/oceans.png");
- await Player.Reload(Url, MineType);
- }
-}
diff --git a/src/BootstrapBlazor.Shared/Demos/VideoPlayers/VideoPlayersNomal.razor b/src/BootstrapBlazor.Shared/Demos/VideoPlayers/VideoPlayersNomal.razor
deleted file mode 100644
index 63045e929580b2127fe7467f1f67e01ddd57ed0b..0000000000000000000000000000000000000000
--- a/src/BootstrapBlazor.Shared/Demos/VideoPlayers/VideoPlayersNomal.razor
+++ /dev/null
@@ -1,8 +0,0 @@
-
diff --git a/src/BootstrapBlazor.Shared/Locales/en.json b/src/BootstrapBlazor.Shared/Locales/en.json
index 7bc4b118de2df2557b852b7506fecf3ba8cfb699..6eba80353e2d56d3c47f32526801c1928fe7feea 100644
--- a/src/BootstrapBlazor.Shared/Locales/en.json
+++ b/src/BootstrapBlazor.Shared/Locales/en.json
@@ -5876,12 +5876,24 @@
"PdfReaderCompatibilityModeTips": "- Chrome < 97 automatically uses version 2.4.456
- Chrome < 109 automatically uses version 2.6.347
- Note: ReadOnly and Watermark cannot be used in these two compatibility modes"
},
"BootstrapBlazor.Shared.Samples.VideoPlayers": {
- "Title": "VideoPlayer",
- "BaseUsageText": "Basic usage",
- "BaseUsageIntro": "",
- "BaseUsageText2": "Switch playback resources",
- "BaseUsageIntro2": "Use the Reload method to switch playback resources",
- "Tips": "Silent mode enabled by default, this is the way for autoplay follow the modern browser standards."
+ "VideoPlayersTitle": "VideoPlayer",
+ "VideoPlayersNomalTitle": "Basic usage",
+ "VideoPlayersNomalIntro": "",
+ "VideoPlayersChangeURLTitle": "Switch playback resources",
+ "VideoPlayersChangeURLIntro": "Use the Reload method to switch playback resources",
+ "VideoPlayersTips": "Silent mode enabled by default, this is the way for autoplay follow the modern browser standards.",
+ "MineType": "MineType",
+ "ResourceUrl": "Resource Address",
+ "MineTypeDesc": "Resource types",
+ "ValueList": "(see footer)",
+ "Width": "Width",
+ "Height": "Height",
+ "ShowControls": "Displays the control bar",
+ "AutoPaly": "Autoplay",
+ "Poster": "Set the cover resource, relative or absolute path",
+ "SwitchResource": "Toggle playback resources",
+ "SetPoster": "Set the cover",
+ "OnError": "Error callback"
},
"BootstrapBlazor.Shared.Components.PackageTips": {
"Tips": "Precautions
This component relies on
{0}
, which needs to reference its component package when using this component
Nuget Install
Use nuget.org to install
{0}
component
"
diff --git a/src/BootstrapBlazor.Shared/Locales/zh.json b/src/BootstrapBlazor.Shared/Locales/zh.json
index d0f92e2a83afc2a55fd22957b439cb37e302e36b..ada3b161253a98fd6710881397afb9d91221ade0 100644
--- a/src/BootstrapBlazor.Shared/Locales/zh.json
+++ b/src/BootstrapBlazor.Shared/Locales/zh.json
@@ -5897,12 +5897,24 @@
"PdfReaderCompatibilityModeTips": "- Chrome < 97 自动使用 2.4.456 版本
- Chrome < 109 自动使用 2.6.347 版本
- 注:ReadOnly 和 Watermark 在这两种兼容模式下不能使用"
},
"BootstrapBlazor.Shared.Samples.VideoPlayers": {
- "Title": "VideoPlayer 视频播放器",
- "BaseUsageText": "基础用法",
- "BaseUsageIntro": "",
- "BaseUsageText2": "切换播放资源",
- "BaseUsageIntro2": "使用 Reload 方法切换播放资源",
- "Tips": "默认启用静音模式,只有这样自动播放功能才符合现代浏览器标准."
+ "VideoPlayersTitle": "VideoPlayer 视频播放器",
+ "VideoPlayersNomalTitle": "基础用法",
+ "VideoPlayersNomalIntro": "",
+ "VideoPlayersChangeURLTitle": "切换播放资源",
+ "VideoPlayersChangeURLIntro": "使用 Reload 方法切换播放资源",
+ "VideoPlayersTips": "默认启用静音模式,只有这样自动播放功能才符合现代浏览器标准.",
+ "MineType": "MineType 类型",
+ "ResourceUrl": "资源地址",
+ "MineTypeDesc": "资源类型,video/mp4, application/x-mpegURL, video/ogg .. ",
+ "ValueList": "(见页脚)",
+ "Width": "宽度",
+ "Height": "高度",
+ "ShowControls": "显示控制条",
+ "AutoPaly": "自动播放",
+ "Poster": "设置封面资源,相对或者绝对路径",
+ "SwitchResource": "切换播放资源",
+ "SetPoster": "设置封面",
+ "OnError": "错误回调"
},
"BootstrapBlazor.Shared.Components.PackageTips": {
"Tips": "注意事项 :
本组件依赖于
{0}
,使用本组件时需要引用其组件包
Nuget 包安装
"
diff --git a/src/BootstrapBlazor.Shared/Samples/Uploads.razor b/src/BootstrapBlazor.Shared/Samples/Uploads.razor
index 9d9ab65c37e317e4d9ba5fb226dd7c2f5d882396..df376f45d108dcb5dda1bf40339ab8e387913970 100644
--- a/src/BootstrapBlazor.Shared/Samples/Uploads.razor
+++ b/src/BootstrapBlazor.Shared/Samples/Uploads.razor
@@ -1,6 +1,8 @@
@page "/uploads"
@inject IOptionsMonitor SiteOptions
@inject IStringLocalizer Localizer
+@inject ToastService ToastService
+@implements IDisposable
@Localizer["UploadsTitle"]
@@ -12,48 +14,128 @@
+ Name="Normal">
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Name="FormSettings">
- @((MarkupString)Localizer["UploadFormSettingsLi1"].Value)
- @((MarkupString)Localizer["UploadFormSettingsLi2"].Value)
+
+
+
+ Name="ClickUpload">
+
+
+
@((MarkupString)Localizer["UploadClickUploadTips1"].Value)
+
+
+
+ @((MarkupString)Localizer["UploadClickUploadTips2"].Value)
+
+ @((MarkupString)Localizer["UploadClickUploadTips3ShowUploadList"].Value)
+
+ Name="UploadedFiles">
+
+ Name="UploadFolder">
+
+ Name="AvatarUpload">
+
+
+
@Localizer["AvatarUploadTips1"]
+
+
+
+
@Localizer["AvatarUploadTips2"]
+
+
+
+
@((MarkupString)Localizer["AvatarUploadTips3"].Value)
+
+
@((MarkupString)Localizer["AvatarUploadTips5"].Value)
+
+
+
+
+
@((MarkupString)Localizer["AvatarUploadTips6"].Value)
+
+
+
+
@((MarkupString)Localizer["AvatarUploadTips7"].Value)
+
+
+
+
+
+
+ Name="PreCardStyle">
@((MarkupString)Localizer["UploadPreCardStyleSSR"].Value)
@((MarkupString)Localizer["UploadPreCardStyleServerSide"].Value)
@@ -62,24 +144,42 @@
@((MarkupString)Localizer["UploadPreCardStyleLink", SiteOptions.CurrentValue.VideoLibUrl].Value)
@((MarkupString)Localizer["UploadPreCardStyleValidation"].Value)
+
+
+
@((MarkupString)Localizer["UploadPreCardStyleTips1"].Value)
+
+
+
+
@((MarkupString)Localizer["UploadPreCardStyleTips2"].Value)
+
+
+
+ Name="FileIcon">
+
+ Name="IconTemplate">
+
+
+
+
+
+
+
+
+
+ Name="Base64">
+
diff --git a/src/BootstrapBlazor.Shared/Samples/Uploads.razor.cs b/src/BootstrapBlazor.Shared/Samples/Uploads.razor.cs
index f4fe049be1abea0c25124a8baf4308506ac6a4ff..b1a54928b9c9b2d51de2a3cdd40fab2eff872523 100644
--- a/src/BootstrapBlazor.Shared/Samples/Uploads.razor.cs
+++ b/src/BootstrapBlazor.Shared/Samples/Uploads.razor.cs
@@ -2,6 +2,8 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
// Website: https://www.blazor.zone or https://argozhang.github.io/
+using Microsoft.AspNetCore.Components.Forms;
+
namespace BootstrapBlazor.Shared.Samples;
///
@@ -9,6 +11,198 @@ namespace BootstrapBlazor.Shared.Samples;
///
public sealed partial class Uploads
{
+ [NotNull]
+ private ConsoleLogger? Logger { get; set; }
+
+ private static readonly Random random = new();
+
+ private CancellationTokenSource? ReadToken { get; set; }
+
+ private static long MaxFileLength => 200 * 1024 * 1024;
+
+ private Person Foo { get; set; } = new Person();
+
+ private List PreviewFileList { get; } = new(new[] { new UploadFile { PrevUrl = "./images/Argo.png" } });
+
+ private CancellationTokenSource? ReadAvatarToken { get; set; }
+
+ private List DefaultFormatFileList { get; } = new List()
+{
+ new UploadFile { FileName = "Test.xls" },
+ new UploadFile { FileName = "Test.doc" },
+ new UploadFile { FileName = "Test.ppt" },
+ new UploadFile { FileName = "Test.mp3" },
+ new UploadFile { FileName = "Test.mp4" },
+ new UploadFile { FileName = "Test.pdf" },
+ new UploadFile { FileName = "Test.cs" },
+ new UploadFile { FileName = "Test.zip" },
+ new UploadFile { FileName = "Test.txt" },
+ new UploadFile { FileName = "Test.dat" }
+ };
+
+ private List Base64FormatFileList { get; } = new List()
+ {
+ new UploadFile { FileName = "Test", PrevUrl = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACoAAAAkCAYAAAD/yagrAAAE60lEQVR4AWJwL/AB9GIWvI0jURz/L1NomZmZP8p9kWNmhnIbKPdomZmZGcJgO7QsWMbce55Yl11t47FbVdKTYpjOr/+H4y4Z/MpYeJVV8KVvokFRylq9osKfVtGQ/NHyPl2CbNVGwau2oOlmgUDJtDJGzxtvvIA3vRH+7IgeA0VtYhQBtKPlToFgC6RY58aggfwLNKhr0Zry2NnPrpIM2YGW2+UBG1IEmdGVJEVXE+hQXt8joKhLjdGVZHd7TSD9DHmT3J1dheroSF4fhnvUVQwbZx9UOnHSzQjkTN0tIG+8hFdbxet4PQOG4WqJwN1hFVb+xUBmCblxvxRkIE+Q+Yf0T31NSrp4/RV4FhHgoSTchQRZBK4D1+Fe2q2g8CYXU6buQyNDaiZKZhn0IYXHVwbkRQydHyawOAGGisa/o3DvI/jF3QKKiuAy+LKs5CvaXMLdeXb35wbkKTjmReDZHysCBosWJqN7r0jZ/VfgXtIlUNQnVpK7D4nNJSC5BHGi1d108Ppr8MxlF0cJqBSyFJaUfUnvHLyO4cttgaI+NhGB7HE0MaSUks/gU5vwe1gv5tfhmUmAhxME8jbIUtiEDus+fhmDJlgCRY0ylZRZhybKWtNinmYlH9NvL5puO3m9UHOkgzb3xuF5HCkDyhYiSwrYVfQPTpYChTc+E35tG9VJBjGFFNmtVlNMDnjzbx0EBpKq1eTeh2awbArBRuHadBWu6WVB4U/NITfuobYoCZl7QL//wDtr+nTmsgzQh2Kwgtz7QAZWFeGw/RI8s94Kigp1PvzZg2i9x11FDtKn/oZCoZdZxhaAXmG4/ohJKHudLE1Gyu66DOfs10BRR5CU3TKQIrtzj9BAkF991dsMslTZEClLsI+jFmANZYFAdAJl9QG03jWH9GrcFh9QTP4Of6GfJGSpsv1J2aoEKRuWCANNJNqOFAaPAW36rVRMCjVf6ZCtqYF2p6Asxg5mWK6tQamY9RCs8z1wF+FxTR5UqYT/3GC7oCkMHcjxKguq6cnl+Egf2whip3C9Yu56jk+GXXOtv1XIa8L1f3AFkHe9az83AmNanwV/bhfa5JKJ3n1slCUL8dk7CNfvVFMfySRThoxbK7fh18tTZXI2QeySLk88IRGsbHkqQj6wUJ72G5CloCXKZrdbLPgVMgVfQMq5m97bfQWOOeVbaK02nSA2ofn2y662UJE47horLZTe38oDjdxQUhmawocxa0OJ5hXjnZE4w1y0uc/iULKGfk+xNuZxI/BnjhFs+THPq4phmTsbeYPXRjFsJJ+NSMlnInHkxrwzGDjR3uBcG1/B/b/TwZkhubb6tP2oVfTAD2G4kw9vYiA2h+zy4GwYxd7S4qGOgd6oqVn6re1DTXiO4e4wPF+yQlF4ZCBfheSPIjJn+ciS/w93qjA6aZYqeQ5D3dTqvuE6GZNTkov5vqsYvLh7j8u1sWWkLIdBQR+q+XdtaKGhJCWBDpkwgSw9gRpKyoNKw6rjCLCDP4yVflSgWFwt3C0HSUo2BTFYX28fVAaWPpDx7wtwjOSSUszawnUT0KTudlfrFQwZ3WNf867CNZQhk/C8kIFUhJLt/O3Jzn62IYNwrUvA8zws4W61CGlDSfugXMz5pJgiSFYyXMYiRXdH4GmyqaR9UHLxzxG41KAwpZxRPN4kRf85Z5I4MvYfFUFGfemJG40AAAAASUVORK5CYII=" },
+ };
+
+ private Task OnFileChange(UploadFile file)
+ {
+ // 未真正保存文件
+ // file.SaveToFile()
+ Logger.Log($"{file.File!.Name} {Localizer["UploadsSuccess"]}");
+ return Task.FromResult("");
+ }
+
+ private Task OnFileDelete(UploadFile item)
+ {
+ Logger.Log($"{item.OriginFileName} {Localizer["UploadsRemoveMsg"]}");
+ return Task.FromResult(true);
+ }
+
+ private static Task OnSubmit(EditContext context)
+ {
+ // 示例代码请根据业务情况自行更改
+ // var fileName = Foo.Picture?.Name;
+ return Task.CompletedTask;
+ }
+
+ private async Task OnClickToUpload(UploadFile file)
+ {
+ // 示例代码,模拟 80% 几率保存成功
+ var error = random.Next(1, 100) > 80;
+ if (error)
+ {
+ file.Code = 1;
+ file.Error = Localizer["UploadsError"];
+ }
+ else
+ {
+ await SaveToFile(file);
+ }
+ }
+
+ private async Task OnClickToUploadNoUploadList(UploadFile file)
+ {
+ await ToastService.Success("Upload", $"{file.OriginFileName} uploaded success.");
+ }
+
+ private async Task SaveToFile(UploadFile file)
+ {
+ // Server Side 使用
+ // Web Assembly 模式下必须使用 webapi 方式去保存文件到服务器或者数据库中
+ // 生成写入文件名称
+ var ret = false;
+ if (!string.IsNullOrEmpty(SiteOptions.CurrentValue.WebRootPath))
+ {
+ var uploaderFolder = Path.Combine(SiteOptions.CurrentValue.WebRootPath, $"images{Path.DirectorySeparatorChar}uploader");
+ file.FileName = $"{Path.GetFileNameWithoutExtension(file.OriginFileName)}-{DateTimeOffset.Now:yyyyMMddHHmmss}{Path.GetExtension(file.OriginFileName)}";
+ var fileName = Path.Combine(uploaderFolder, file.FileName);
+
+ ReadToken ??= new CancellationTokenSource();
+ ret = await file.SaveToFileAsync(fileName, MaxFileLength, ReadToken.Token);
+
+ if (ret)
+ {
+ // 保存成功
+ file.PrevUrl = $"images/uploader/{file.FileName}";
+ }
+ else
+ {
+ var errorMessage = $"{Localizer["UploadsSaveFileError"]} {file.OriginFileName}";
+ file.Code = 1;
+ file.Error = errorMessage;
+ await ToastService.Error(Localizer["UploadFile"], errorMessage);
+ }
+ }
+ else
+ {
+ file.Code = 1;
+ file.Error = Localizer["UploadsWasmError"];
+ await ToastService.Information(Localizer["UploadsSaveFile"], Localizer["UploadsSaveFileMsg"]);
+ }
+ return ret;
+ }
+
+ private async Task OnDownload(UploadFile item)
+ {
+ await ToastService.Success("文件下载", $"下载 {item.FileName} 成功");
+ }
+
+ private async Task OnUploadFolder(UploadFile file)
+ {
+ // 上传文件夹时会多次回调此方法
+ await SaveToFile(file);
+ }
+
+ private async Task OnAvatarUpload(UploadFile file)
+ {
+ // 示例代码,使用 base64 格式
+ if (file != null && file.File != null)
+ {
+ var format = file.File.ContentType;
+ if (CheckValidAvatarFormat(format))
+ {
+ ReadAvatarToken ??= new CancellationTokenSource();
+ if (ReadAvatarToken.IsCancellationRequested)
+ {
+ ReadAvatarToken.Dispose();
+ ReadAvatarToken = new CancellationTokenSource();
+ }
+
+ await file.RequestBase64ImageFileAsync(format, 640, 480, MaxFileLength, ReadAvatarToken.Token);
+ }
+ else
+ {
+ file.Code = 1;
+ file.Error = Localizer["UploadsFormatError"];
+ }
+
+ if (file.Code != 0)
+ {
+ await ToastService.Error(Localizer["UploadsAvatarMsg"], $"{file.Error} {format}");
+ }
+ }
+ }
+
+ private static bool CheckValidAvatarFormat(string format)
+ {
+ return "jpg;png;bmp;gif;jpeg".Split(';').Any(f => format.Contains(f, StringComparison.OrdinalIgnoreCase));
+ }
+
+ private Task OnAvatarValidSubmit(EditContext context)
+ {
+ Logger.Log(Foo.Picture?.Name ?? "");
+ return Task.CompletedTask;
+ }
+
+ private async Task OnCardUpload(UploadFile file)
+ {
+ if (file != null && file.File != null)
+ {
+ // 服务器端验证当文件大于 2MB 时提示文件太大信息
+ if (file.Size > MaxFileLength)
+ {
+ await ToastService.Information(Localizer["UploadsFileMsg"], Localizer["UploadsFileError"]);
+ file.Code = 1;
+ file.Error = Localizer["UploadsFileError"];
+ }
+ else
+ {
+ await SaveToFile(file);
+ }
+ }
+ }
+
+ ///
+ /// Dispose
+ ///
+ public void Dispose()
+ {
+ ReadToken?.Cancel();
+ ReadAvatarToken?.Cancel();
+ GC.SuppressFinalize(this);
+ }
+
private IEnumerable GetInputAttributes() => new AttributeItem[]
{
new AttributeItem() {
@@ -265,4 +459,15 @@ public sealed partial class Uploads
DefaultValue = " — "
}
};
+
+ private class Person
+ {
+ [Required]
+ [StringLength(20, MinimumLength = 2)]
+ public string Name { get; set; } = "Blazor";
+
+ [Required]
+ [FileValidation(Extensions = new string[] { ".png", ".jpg", ".jpeg" }, FileSize = 50 * 1024)]
+ public IBrowserFile? Picture { get; set; }
+ }
}
diff --git a/src/BootstrapBlazor.Shared/Samples/VideoPlayers.razor b/src/BootstrapBlazor.Shared/Samples/VideoPlayers.razor
index 33bf878630ec44d6f83653d38439f3fa89e22bd5..c29fa9d8f3fc14a9eefe4599fc345479e0ee0902 100644
--- a/src/BootstrapBlazor.Shared/Samples/VideoPlayers.razor
+++ b/src/BootstrapBlazor.Shared/Samples/VideoPlayers.razor
@@ -6,24 +6,46 @@
-
+
@((MarkupString)Localizer["VideoPlayersTips"].Value)
+ Name="Nomal">
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Name="ChangeURL">
+
-MineType 类型
+@Localizer["MineType"]
- opus: 'video/ogg'
- ogv: 'video/ogg'
diff --git a/src/BootstrapBlazor.Shared/Samples/VideoPlayers.razor.cs b/src/BootstrapBlazor.Shared/Samples/VideoPlayers.razor.cs
index f1b3e0bcfeb9338f67de3bc6772c799bb0b6f805..5b02a46adf1613d4c7f6b4fa896d3dd377f5d986 100644
--- a/src/BootstrapBlazor.Shared/Samples/VideoPlayers.razor.cs
+++ b/src/BootstrapBlazor.Shared/Samples/VideoPlayers.razor.cs
@@ -9,6 +9,54 @@ namespace BootstrapBlazor.Shared.Samples;
///
public partial class VideoPlayers
{
+ private string MineType = "video/mp4";
+ private string Url = "//vjs.zencdn.net/v/oceans.mp4";
+
+ [NotNull]
+ private VideoPlayer? Player { get; set; }
+
+ private List VideoList { get; } = new()
+ {
+ "https://rtvelivestream.akamaized.net/rtvesec/la1/la1_main.m3u8",
+ "https://d2zihajmogu5jn.cloudfront.net/bipbop-advanced/bipbop_16x9_variant.m3u8",
+ "https://test-streams.mux.dev/x36xhzz/x36xhzz.m3u8",
+ "https://res.cloudinary.com/dannykeane/video/upload/sp_full_hd/q_80:qmax_90,ac_none/v1/dk-memoji-dark.m3u8",
+ "https://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_fmp4/master.m3u8",
+ "https://moctobpltc-i.akamaihd.net/hls/live/571329/eight/playlist.m3u8",
+ "https://cph-p2p-msl.akamaized.net/hls/live/2000341/test/master.m3u8",
+ "https://demo.unified-streaming.com/k8s/features/stable/video/tears-of-steel/tears-of-steel.mp4/.m3u8",
+ "https://diceyk6a7voy4.cloudfront.net/e78752a1-2e83-43fa-85ae-3d508be29366/hls/fitfest-sample-1_Ott_Hls_Ts_Avc_Aac_16x9_1280x720p_30Hz_6.0Mbps_qvbr.m3u8"
+ };
+
+ private List Items { get; } = new();
+
+ ///
+ /// OnInitialized 方法
+ ///
+ protected override void OnInitialized()
+ {
+ base.OnInitialized();
+ for (var i = 0; i < VideoList.Count; i++)
+ {
+ Items.Add(new SelectedItem { Text = $"TestVideo{i}", Value = VideoList[i] });
+ }
+ Items.Add(new SelectedItem { Text = "Mp4", Value = "//vjs.zencdn.net/v/oceans.mp4" });
+ }
+
+ private async Task ChangeURL(SelectedItem e)
+ {
+ Url = e.Value;
+ MineType = e.Value.EndsWith("mp4") ? "video/mp4" : "application/x-mpegURL";
+ StateHasChanged();
+ await Apply();
+ }
+
+ private async Task Apply()
+ {
+ await Player.SetPoster("//vjs.zencdn.net/v/oceans.png");
+ await Player.Reload(Url, MineType);
+ }
+
///
/// 获得属性方法
///
@@ -18,70 +66,70 @@ public partial class VideoPlayers
// TODO: 移动到数据库中
new() {
Name = nameof(VideoPlayer.Url),
- Description = "资源地址",
+ Description = Localizer["ResourceUrl"],
Type = "string",
ValueList = " — ",
DefaultValue = " — "
},
new() {
Name = nameof(VideoPlayer.MineType),
- Description = "资源类型,video/mp4, application/x-mpegURL, video/ogg .. ",
+ Description = Localizer["MineTypeDesc"],
Type = "string?",
- ValueList = "(见页脚)",
+ ValueList = Localizer["ValueList"],
DefaultValue = "application/x-mpegURL"
},
new() {
Name = nameof(VideoPlayer.Width),
- Description = "宽度",
+ Description = Localizer["Width"],
Type = "int",
ValueList = " — ",
DefaultValue = "300"
},
new() {
Name = nameof(VideoPlayer.Height),
- Description = "高度",
+ Description = Localizer["Height"],
Type = "int",
ValueList = " — ",
DefaultValue = "200"
},
new() {
Name = nameof(VideoPlayer.Controls),
- Description = "显示控制条",
+ Description = Localizer["ShowBar"],
Type = "bool",
ValueList = "true|false",
DefaultValue = "true"
},
new() {
Name = nameof(VideoPlayer.Autoplay),
- Description = "自动播放",
+ Description = Localizer["AutoPaly"],
Type = "bool",
ValueList = "true|false",
DefaultValue = "true"
},
new() {
Name = nameof(VideoPlayer.Poster),
- Description = "设置封面资源,相对或者绝对路径",
+ Description = Localizer["Poster"],
Type = "string?",
ValueList = " — ",
DefaultValue = " — "
},
new() {
Name = "Reload(string url, string type)",
- Description = "切换播放资源",
+ Description = Localizer["SwitchResource"],
Type = "async Task",
ValueList = " — ",
DefaultValue = " — "
},
new() {
Name = "SetPoster(string poster)",
- Description = "设置封面",
+ Description = Localizer["SetPoster"],
Type = "async Task",
ValueList = " — ",
DefaultValue = " — "
},
new() {
Name = "OnError",
- Description = "错误回调",
+ Description = Localizer["OnError"],
Type = "Func?",
ValueList = " — ",
DefaultValue = " — "