Skip to content
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/BootstrapBlazor/Components/Affix/Affix.razor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ public partial class Affix

private string? StyleString => CssBuilder.Default("position: sticky;")
.AddStyle("z-index", $"{ZIndex}", ZIndex.HasValue)
.AddStyle($"{Position.ToDescriptionString()}", $"{Offset}px")
.AddStyle(Position.ToDescriptionString(), $"{Offset}px")
.AddStyleFromAttributes(AdditionalAttributes)
.Build();
}
6 changes: 3 additions & 3 deletions src/BootstrapBlazor/Components/Drawer/Drawer.razor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,16 +19,16 @@ public partial class Drawer
.Build();

private string? StyleString => CssBuilder.Default()
.AddStyle("--bb-drawer-position", $"{Position}", !string.IsNullOrEmpty(Position))
.AddStyle("--bb-drawer-position", Position)
.AddStyleFromAttributes(AdditionalAttributes)
.Build();

/// <summary>
/// 获得 抽屉 Style 字符串
/// </summary>
private string? DrawerStyleString => CssBuilder.Default()
.AddStyle("--bb-drawer-width", $"{Width}", !string.IsNullOrEmpty(Width) && Placement != Placement.Top && Placement != Placement.Bottom)
.AddStyle("--bb-drawer-height", $"{Height}", !string.IsNullOrEmpty(Height) && (Placement == Placement.Top || Placement == Placement.Bottom))
.AddStyle("--bb-drawer-width", Width, Placement != Placement.Top && Placement != Placement.Bottom)
.AddStyle("--bb-drawer-height", Height, Placement == Placement.Top || Placement == Placement.Bottom)
.Build();

/// <summary>
Expand Down
67 changes: 39 additions & 28 deletions src/BootstrapBlazor/Components/ListView/ListView.razor
Original file line number Diff line number Diff line change
Expand Up @@ -10,43 +10,54 @@
</div>
}
<div class="@BodyClassString">
@if (BodyTemplate != null)
@if (Rows.Count > 0)
{
if (GroupName == null)
if (BodyTemplate != null)
{
foreach (var item in Rows)
if (GroupName == null)
{
<div class="listview-item" @onclick="@(e => OnClick(item))">
@BodyTemplate(item)
</div>
foreach (var item in Rows)
{
<div class="listview-item" @onclick="@(e => OnClick(item))">
@BodyTemplate(item)
</div>
}
}
}
else if (Collapsible)
{
<Collapse IsAccordion="IsAccordion" OnCollapseChanged="OnCollapseChanged!">
<CollapseItems>
@RenderCollapsibleItems(GroupName)
</CollapseItems>
</Collapse>
}
else
{
foreach (var key in GetGroupItems(GroupName))
else if (Collapsible)
{
<div @key="@key.GroupName" class="accordion-item">
<div class="accordion-header">@key.GroupName</div>
<div class="accordion-body">
@foreach (var item in key.Items)
{
<div class="listview-item" @onclick="@(e => OnClick(item))">
@BodyTemplate(item)
</div>
}
<Collapse IsAccordion="IsAccordion" OnCollapseChanged="OnCollapseChanged!">
<CollapseItems>
@RenderCollapsibleItems(GroupName)
</CollapseItems>
</Collapse>
}
else
{
foreach (var key in GetGroupItems(GroupName))
{
<div @key="@key.GroupName" class="accordion-item">
<div class="accordion-header">@key.GroupName</div>
<div class="accordion-body">
@foreach (var item in key.Items)
{
<div class="listview-item" @onclick="@(e => OnClick(item))">
@BodyTemplate(item)
</div>
}
</div>
</div>
</div>
}
}
}
}
else if (EmptyTemplate != null)
{
@EmptyTemplate
}
else
{
@EmptyText
}
</div>
@if (FooterTemplate != null || Pageable)
{
Expand Down
12 changes: 12 additions & 0 deletions src/BootstrapBlazor/Components/ListView/ListView.razor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,18 @@ public partial class ListView<TItem> : BootstrapComponentBase
[Parameter]
public string? Height { get; set; }

/// <summary>
/// 获得/设置 无数据时模板 默认 null 未设置
/// </summary>
[Parameter]
public RenderFragment? EmptyTemplate { get; set; }

/// <summary>
/// 获得/设置 无数据时显示文字 默认 null 未设置使用资源文件设置文字
/// </summary>
[Parameter]
public string? EmptyText { get; set; }

/// <summary>
/// 获得/设置 当前页码
/// </summary>
Expand Down
2 changes: 1 addition & 1 deletion src/BootstrapBlazor/Components/Validate/ValidateBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -485,7 +485,7 @@ public virtual void ToggleMessage(IEnumerable<ValidationResult> results)

private JSModule? ValidateModule { get; set; }

private Task<JSModule> LoadValidateModule() => JSRuntime.LoadModule("./_content/BootstrapBlazor/modules/validate.js");
private Task<JSModule> LoadValidateModule() => JSRuntime.LoadModuleByName("validate");

/// <summary>
/// 增加客户端 Tooltip 方法
Expand Down
10 changes: 3 additions & 7 deletions src/BootstrapBlazor/Components/WebSpeech/WebSpeechService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ namespace BootstrapBlazor.Components;
/// <summary>
/// Web Speech 服务
/// </summary>
public class WebSpeechService(IJSRuntime runtime, IComponentIdGenerator ComponentIdGenerator, ILogger<WebSpeechService> logger)
public class WebSpeechService(IJSRuntime runtime, IComponentIdGenerator ComponentIdGenerator)
{
private JSModule? SynthesisModule { get; set; }

Expand All @@ -24,9 +24,7 @@ public async Task<WebSpeechSynthesizer> CreateSynthesizerAsync()
{
if (SynthesisModule == null)
{
var moduleName = "./_content/BootstrapBlazor/modules/synthesis.js";
logger.LogInformation("load module {moduleName}", moduleName);
SynthesisModule = await runtime.LoadModule(moduleName);
SynthesisModule = await runtime.LoadModuleByName("synthesis");
}
return new WebSpeechSynthesizer(SynthesisModule, ComponentIdGenerator);
}
Expand All @@ -39,9 +37,7 @@ public async Task<WebSpeechRecognition> CreateRecognitionAsync()
{
if (RecognitionModule == null)
{
var moduleName = "./_content/BootstrapBlazor/modules/recognition.js";
logger.LogInformation("load module {moduleName}", moduleName);
RecognitionModule = await runtime.LoadModule(moduleName);
RecognitionModule = await runtime.LoadModuleByName("recognition");
}
return new WebSpeechRecognition(RecognitionModule, ComponentIdGenerator);
}
Expand Down
8 changes: 7 additions & 1 deletion src/BootstrapBlazor/Extensions/JSModuleExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,13 @@ public static class JSModuleExtensions
/// <param name="jsRuntime"></param>
/// <param name="version"></param>
/// <returns>A <see cref="Task"/><![CDATA[<]]><see cref="JSModule"/><![CDATA[>]]> 模块加载器</returns>
public static Task<JSModule> LoadUtility(this IJSRuntime jsRuntime, string? version = null) => LoadModule(jsRuntime, "./_content/BootstrapBlazor/modules/utility.js", version);
public static Task<JSModule> LoadUtility(this IJSRuntime jsRuntime, string? version = null) => LoadModuleByName(jsRuntime, "utility", version);

internal static Task<JSModule> LoadModuleByName(this IJSRuntime jsRuntime, string moduleName, string? version = null)
{
var fileName = $"./_content/BootstrapBlazor/modules/{moduleName}.js";
return LoadModule(jsRuntime, fileName, version);
}

/// <summary>
/// IJSRuntime 扩展方法 动态加载脚本 脚本目录为 modules
Expand Down
2 changes: 1 addition & 1 deletion src/BootstrapBlazor/Services/AjaxService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ public class AjaxService(IJSRuntime jSRuntime)
[NotNull]
private JSModule? _module = null;

private Task<JSModule> LoadModule() => jSRuntime.LoadModule("./_content/BootstrapBlazor/modules/ajax.js");
private Task<JSModule> LoadModule() => jSRuntime.LoadModuleByName("ajax");

/// <summary>
/// 调用Ajax方法发送请求
Expand Down
2 changes: 1 addition & 1 deletion src/BootstrapBlazor/Services/Bluetooth/DefaultBluetooth.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ public DefaultBluetooth(IJSRuntime jsRuntime)

private async Task<JSModule> LoadModule()
{
var module = await _runtime.LoadModule("./_content/BootstrapBlazor/modules/bt.js");
var module = await _runtime.LoadModuleByName("bt");

IsSupport = await module.InvokeAsync<bool>("init");
return module;
Expand Down
2 changes: 1 addition & 1 deletion src/BootstrapBlazor/Services/ClipboardService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ public class ClipboardService(IJSRuntime jSRuntime)
[NotNull]
private JSModule? _module = null;

private Task<JSModule> LoadModule() => jSRuntime.LoadModule("./_content/BootstrapBlazor/modules/utility.js");
private Task<JSModule> LoadModule() => jSRuntime.LoadUtility();

/// <summary>
/// 获取剪切板数据方法
Expand Down
4 changes: 1 addition & 3 deletions src/BootstrapBlazor/Services/DefaultBrowserFingerService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,12 @@ class DefaultBrowserFingerService(IJSRuntime jSRuntime) : IBrowserFingerService
[NotNull]
private JSModule? _module = null;

private Task<JSModule> LoadModule() => jSRuntime.LoadModule("./_content/BootstrapBlazor/modules/utility.js");

/// <summary>
/// 获取剪切板数据方法
/// </summary>
public async Task<string?> GetFingerCodeAsync(CancellationToken token = default)
{
_module ??= await LoadModule();
_module ??= await jSRuntime.LoadUtility();
return await _module.InvokeAsync<string?>("getFingerCode", token);
}
}
2 changes: 1 addition & 1 deletion src/BootstrapBlazor/Services/DefaultGeoLocationService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ public DefaultGeoLocationService(IJSRuntime jsRuntime)
Interop = DotNetObjectReference.Create(this);
}

private Task<JSModule> LoadModule() => JSRuntime.LoadModule("./_content/BootstrapBlazor/modules/geo.js");
private Task<JSModule> LoadModule() => JSRuntime.LoadModuleByName("geo");

/// <summary>
/// get the current position of the device
Expand Down
2 changes: 1 addition & 1 deletion src/BootstrapBlazor/Services/EyeDropperService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ public class EyeDropperService(IJSRuntime jSRuntime)
/// <returns></returns>
public async Task<string?> PickAsync(CancellationToken token = default)
{
_module ??= await jSRuntime.LoadModule("./_content/BootstrapBlazor/modules/eye-dropper.js");
_module ??= await jSRuntime.LoadModuleByName("eye-dropper");
return await _module.InvokeAsync<string?>("open", token);
}
}
2 changes: 1 addition & 1 deletion src/BootstrapBlazor/Services/FullScreenService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ public class FullScreenService(IJSRuntime jSRuntime)
/// <returns></returns>
public async Task Toggle(FullScreenOption? option = null, CancellationToken token = default)
{
_module ??= await jSRuntime.LoadModule("./_content/BootstrapBlazor/modules/fullscreen.js");
_module ??= await jSRuntime.LoadModuleByName("fullscreen");
await _module.InvokeVoidAsync("toggle", token, option);
}
}
2 changes: 1 addition & 1 deletion src/BootstrapBlazor/Services/NotificationService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ public NotificationService(IJSRuntime runtime, ICacheManager cache)
Interop = DotNetObjectReference.Create(this);
}

private Task<JSModule> LoadModule() => JSRuntime.LoadModule("./_content/BootstrapBlazor/modules/noti.js");
private Task<JSModule> LoadModule() => JSRuntime.LoadModuleByName("noti");

/// <summary>
/// 检查浏览器通知权限状态
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ public DefaultSerialService(IJSRuntime jsRuntime)

private async Task<JSModule> LoadModule()
{
var module = await _runtime.LoadModule("./_content/BootstrapBlazor/modules/serial.js");
var module = await _runtime.LoadModuleByName("serial");

IsSupport = await module.InvokeAsync<bool>("init", _serialPortId);
return module;
Expand Down
2 changes: 1 addition & 1 deletion src/BootstrapBlazor/Services/TitleService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ public class TitleService(IJSRuntime jSRuntime)
/// <returns></returns>
public async Task SetTitle(string title, CancellationToken token = default)
{
_module ??= await jSRuntime.LoadModule("./_content/BootstrapBlazor/modules/utility.js");
_module ??= await jSRuntime.LoadUtility();
await _module.InvokeVoidAsync("setTitle", token, title);
}
}
3 changes: 2 additions & 1 deletion src/BootstrapBlazor/Services/WebClientService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,9 @@ public async Task<ClientInfo> GetClientInfo()
// 等待 SetData 方法执行完毕
try
{
await _taskCompletionSource.Task.WaitAsync(TimeSpan.FromSeconds(1));
await _taskCompletionSource.Task.WaitAsync(TimeSpan.FromSeconds(3));
}
catch (TimeoutException) { }
catch (Exception ex)
{
logger.LogError(ex, "method GetClientInfo failed");
Expand Down
30 changes: 28 additions & 2 deletions test/UnitTest/Components/ListViewTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ public void Items_Ok()
{
pb.Add(a => a.BodyTemplate, p => builder => builder.AddContent(0, $"{p.ImageUrl}-{p.Description}-{p.Category}"));
});
cut.Markup.Contains("listview-body");
cut.Contains("listview-body");
}

[Fact]
Expand All @@ -24,7 +24,7 @@ public void Height_Ok()
{
pb.Add(a => a.Height, "50vh");
});
cut.Markup.Contains("style=\"height: 50vh;\"");
cut.Contains("style=\"height: 50vh;\"");
}

[Fact]
Expand Down Expand Up @@ -293,6 +293,32 @@ public void OnCollapseChanged_Ok()
});
}

[Fact]
public void EmptyTemplate_Ok()
{
var cut = Context.RenderComponent<ListView<Product>>(pb =>
{
pb.Add(a => a.OnQueryAsync, option =>
{
var ret = new QueryData<Product>()
{
Items = [],
TotalCount = 0
};
return Task.FromResult(ret);
});
pb.Add(a => a.EmptyTemplate, builder => builder.AddContent(0, "empty-template"));
});
cut.Contains("empty-template");

cut.SetParametersAndRender(pb =>
{
pb.Add<RenderFragment?>(a => a.EmptyTemplate, null);
pb.Add(a => a.EmptyText, "text-empty");
});
cut.Contains("text-empty");
}

private class Product
{
public string? ImageUrl { get; set; }
Expand Down
8 changes: 7 additions & 1 deletion test/UnitTest/Services/WebClientServiceTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -59,11 +59,17 @@ public async Task WebClientOptions_Ok()
}

[Fact]
public async Task Timeout_Ok()
public async Task GetClientInfo_Error()
{
var service = Context.Services.GetRequiredService<WebClientService>();
var client = await service.GetClientInfo();

// TimeoutException
Assert.Null(client.Ip);

// Exception
Context.JSInterop.SetupVoid("ping", _ => true).SetException(new Exception("test-exception"));
client = await service.GetClientInfo();
}

[Fact]
Expand Down