diff --git a/src/BootstrapBlazor.Server/Components/Samples/Dialogs.razor b/src/BootstrapBlazor.Server/Components/Samples/Dialogs.razor index d2786cccd..77ad3f424 100644 --- a/src/BootstrapBlazor.Server/Components/Samples/Dialogs.razor +++ b/src/BootstrapBlazor.Server/Components/Samples/Dialogs.razor @@ -124,7 +124,8 @@ private async Task OnClick()
  • @Localizer["ModalDialogTip5"]
  • - + + diff --git a/src/BootstrapBlazor.Server/Components/Samples/Dialogs.razor.cs b/src/BootstrapBlazor.Server/Components/Samples/Dialogs.razor.cs index 674056262..b6f5e7044 100644 --- a/src/BootstrapBlazor.Server/Components/Samples/Dialogs.razor.cs +++ b/src/BootstrapBlazor.Server/Components/Samples/Dialogs.razor.cs @@ -163,6 +163,13 @@ public sealed partial class Dialogs ModalDialogLogger.Log($"The return value of the popup window is: {result} The return value of the component is: {DemoValue1}"); } + private async Task OnConfirmModalClick() + { + var result = await DialogService.ShowModal(Localizer["ConfirmDialogModalContent"], Localizer["ConfirmDialogModalTitle"]); + + ModalDialogLogger.Log($"The return value of the popup window is: {result} no component provider"); + } + private async Task OnEditDialogClick() { var option = new EditDialogOption() diff --git a/src/BootstrapBlazor.Server/Locales/en-US.json b/src/BootstrapBlazor.Server/Locales/en-US.json index e331fc1f7..58fdb1914 100644 --- a/src/BootstrapBlazor.Server/Locales/en-US.json +++ b/src/BootstrapBlazor.Server/Locales/en-US.json @@ -902,7 +902,10 @@ "ExportPdfDialogTitle": "Pop up window with export Pdf function", "ExportPdfDialogIntro": "Set ShowExportPdfButtonInHeader to display an export PDF button on the Header", "ExportPdfDialogTip": "More parameters can be set by setting ExportPdfButtonOptions", - "ExportPdfButton": "Export Pdf" + "ExportPdfButton": "Export Pdf", + "ConfirmDialogButton": "Popup Modal", + "ConfirmDialogModalTitle": "Literal Confirmation Modal", + "ConfirmDialogModalContent": "

    this is the prompt message.

    this is a danger info
    " }, "BootstrapBlazor.Server.Components.Samples.Dispatches": { "Title": "Dispatch message distribution", diff --git a/src/BootstrapBlazor.Server/Locales/zh-CN.json b/src/BootstrapBlazor.Server/Locales/zh-CN.json index 7abd68fc1..b9cbfe11d 100644 --- a/src/BootstrapBlazor.Server/Locales/zh-CN.json +++ b/src/BootstrapBlazor.Server/Locales/zh-CN.json @@ -902,7 +902,10 @@ "ExportPdfDialogTitle": "带导出 Pdf 功能的弹窗", "ExportPdfDialogIntro": "通过设置 ShowExportPdfButtonInHeader 使 Header 上显示一个导出 pdf 按钮", "ExportPdfDialogTip": "可通过设置 ExportPdfButtonOptions 对更多参数进行设置", - "ExportPdfButton": "导出 Pdf 弹窗" + "ExportPdfButton": "导出 Pdf 弹窗", + "ConfirmDialogButton": "弹出模态框", + "ConfirmDialogModalTitle": "文字确认模态框", + "ConfirmDialogModalContent": "

    这是一个文字确认模态框

    这是警告信息
    " }, "BootstrapBlazor.Server.Components.Samples.Dispatches": { "Title": "Dispatch 消息分发", diff --git a/src/BootstrapBlazor/Extensions/DialogServiceExtensions.cs b/src/BootstrapBlazor/Extensions/DialogServiceExtensions.cs index fdf05f4e3..fc3f611e0 100644 --- a/src/BootstrapBlazor/Extensions/DialogServiceExtensions.cs +++ b/src/BootstrapBlazor/Extensions/DialogServiceExtensions.cs @@ -3,6 +3,8 @@ // See the LICENSE file in the project root for more information. // Maintainer: Argo Zhang(argo@live.ca) Website: https://www.blazor.zone +using Microsoft.AspNetCore.Components.Rendering; + namespace BootstrapBlazor.Components; /// @@ -71,21 +73,23 @@ public static class DialogServiceExtensions public static async Task ShowModal(this DialogService service, ResultDialogOption option, Dialog? dialog = null) where TDialog : IComponent, IResultDialog { - IResultDialog? resultDialog = null; - option.GetDialog = () => resultDialog; - option.BodyTemplate = builder => + if (option.BodyTemplate == null) { - var index = 0; - builder.OpenComponent(index++, typeof(TDialog)); - if (option.ComponentParameters != null) + IResultDialog? resultDialog = null; + option.GetDialog = () => resultDialog; + option.BodyTemplate = builder => { - builder.AddMultipleAttributes(1, option.ComponentParameters); - } - builder.AddComponentReferenceCapture(index++, com => resultDialog = (IResultDialog)com); - builder.CloseComponent(); - }; + builder.OpenComponent(0, typeof(TDialog)); + if (option.ComponentParameters != null) + { + builder.AddMultipleAttributes(10, option.ComponentParameters); + } + builder.AddComponentReferenceCapture(30, com => resultDialog = (IResultDialog)com); + builder.CloseComponent(); + }; + } - option.FooterTemplate = BootstrapDynamicComponent.CreateComponent(new Dictionary + option.FooterTemplate ??= BootstrapDynamicComponent.CreateComponent(new Dictionary { [nameof(ResultDialogFooter.ButtonNoText)] = option.ButtonNoText, [nameof(ResultDialogFooter.ButtonYesText)] = option.ButtonYesText, @@ -105,6 +109,52 @@ public static class DialogServiceExtensions return await option.ResultTask.Task; } + /// + /// 弹出带结果的对话框 + /// + /// DialogService 服务实例 + /// 对话框标题,优先级高于 + /// 对话框 文本参数 + /// 对话框参数实例 + /// 指定弹窗组件 默认为 null 使用 组件内置弹窗组件 + public static Task ShowModal(this DialogService service, string title, string content, ResultDialogOption? option = null, Dialog? dialog = null) + { + option ??= new(); + if (!string.IsNullOrEmpty(title)) + { + option.Title = title; + } + if (!string.IsNullOrEmpty(content)) + { + IResultDialog? resultDialog = null; + option.GetDialog = () => resultDialog; + option.BodyTemplate = builder => + { + builder.OpenComponent(0, typeof(ResultDialog)); + builder.AddAttribute(20, nameof(ResultDialog.Content), content); + builder.AddComponentReferenceCapture(30, com => resultDialog = (IResultDialog)com); + builder.CloseComponent(); + }; + } + return ShowModal(service, option, dialog); + } + + private class ResultDialog : ComponentBase, IResultDialog + { + [Parameter] + public string? Content { get; set; } + + protected override void BuildRenderTree(RenderTreeBuilder builder) + { + builder.AddMarkupContent(0, Content); + } + + public Task OnClose(DialogResult result) + { + return Task.CompletedTask; + } + } + /// /// 弹出带保存按钮对话窗方法 /// diff --git a/test/UnitTest/Components/DialogTest.cs b/test/UnitTest/Components/DialogTest.cs index 70b0b4542..0de95b36a 100644 --- a/test/UnitTest/Components/DialogTest.cs +++ b/test/UnitTest/Components/DialogTest.cs @@ -7,6 +7,24 @@ namespace UnitTest.Components; public class DialogTest : BootstrapBlazorTestBase { + [Fact] + public async Task ShowModal_Ok() + { + var cut = Context.RenderComponent(pb => + { + pb.Add(a => a.EnableErrorLogger, false); + pb.AddChildContent(); + }); + var modal = cut.FindComponent(); + var dialog = cut.FindComponent().Instance.DialogService; + _ = cut.InvokeAsync(() => dialog.ShowModal("title", "test-content")); + cut.WaitForState(() => cut.Markup.Contains("btn-primary")); + + var closeButton = cut.Find(".btn-primary"); + await cut.InvokeAsync(() => closeButton.Click()); + await cut.InvokeAsync(() => modal.Instance.CloseCallback()); + } + [Fact] public async Task Show_Ok() { @@ -304,6 +322,7 @@ public class DialogTest : BootstrapBlazorTestBase // 点击的是 No 按钮 result = true; + resultOption.BodyTemplate = null; _ = cut.InvokeAsync(() => dialog.ShowModal(resultOption)); cut.WaitForState(() => cut.Markup.Contains("btn-danger")); @@ -314,6 +333,7 @@ public class DialogTest : BootstrapBlazorTestBase // 点击的是 Close 按钮 result = true; + resultOption.BodyTemplate = null; _ = cut.InvokeAsync(() => dialog.ShowModal(resultOption)); cut.WaitForState(() => cut.Markup.Contains("btn-secondary")); @@ -341,6 +361,7 @@ public class DialogTest : BootstrapBlazorTestBase await cut.InvokeAsync(() => modal.Instance.CloseCallback()); // 点击右上角关闭按钮 + resultOption.BodyTemplate = null; _ = cut.InvokeAsync(() => dialog.ShowModal(resultOption)); cut.WaitForState(() => cut.Markup.Contains("btn-close")); @@ -349,12 +370,21 @@ public class DialogTest : BootstrapBlazorTestBase await cut.InvokeAsync(() => modal.Instance.CloseCallback()); // 点击 FooterTemplate 中的 关闭 按钮 + resultOption.BodyTemplate = null; _ = cut.InvokeAsync(() => dialog.ShowModal(resultOption)); cut.WaitForState(() => cut.Markup.Contains("btn-secondary")); closeButton = cut.Find(".btn-secondary"); await cut.InvokeAsync(() => closeButton.Click()); await cut.InvokeAsync(() => modal.Instance.CloseCallback()); + + // 测试 Markup 扩展模式弹窗 + _ = cut.InvokeAsync(() => dialog.ShowModal("title", "test-content")); + cut.WaitForState(() => cut.Markup.Contains("btn-primary")); + + closeButton = cut.Find(".btn-primary"); + await cut.InvokeAsync(() => closeButton.Click()); + await cut.InvokeAsync(() => modal.Instance.CloseCallback()); #endregion #region 弹窗中的弹窗测试 diff --git a/test/UnitTest/Services/ClipboardServiceTest.cs b/test/UnitTest/Services/ClipboardServiceTest.cs index d98a0bd19..6fa2abb8e 100644 --- a/test/UnitTest/Services/ClipboardServiceTest.cs +++ b/test/UnitTest/Services/ClipboardServiceTest.cs @@ -48,5 +48,9 @@ public class ClipboardServiceTest : BootstrapBlazorTestBase items = await service.Get(); item = items[0]; Assert.Empty(item.Text); + + Context.JSInterop.Setup?>("getAllClipboardContents").SetResult(null); + items = await service.Get(); + Assert.Empty(items); } }