Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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/BootstrapBlazor.csproj
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk.Razor">

<PropertyGroup>
<Version>11.1.0-rc.3.3</Version>
<Version>11.1.0-rc.3.4</Version>
</PropertyGroup>

<ItemGroup>
Expand Down
2 changes: 1 addition & 1 deletion src/BootstrapBlazor/Components/Table/Table.razor
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,7 @@

if (IsShowEmpty)
{
<tr>
<tr class="is-empty">
<td colspan="@GetEmptyColumnCount()">
<Empty Text="@EmptyText" Image="@EmptyImage" Template="EmptyTemplate!">
</Empty>
Expand Down
4 changes: 4 additions & 0 deletions src/BootstrapBlazor/Components/Table/Table.razor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2049,6 +2049,8 @@ private async Task OnContextMenu(MouseEventArgs e, TItem item)
/// <summary>
/// <para lang="zh">获得/设置 表格客户端状态调整回调方法</para>
/// <para lang="en">Gets or sets Table Column Client Status Changed Callback</para>
/// <para lang="zh">第一个参数为发生变化的列名称;调用 <see cref="FitAllColumnWidth"/> 批量调整时为 "*",第二个参数包含完整列状态。</para>
/// <para lang="en">The first argument is the changed column name, or "*" for a batch update by <see cref="FitAllColumnWidth"/>. The second argument contains the full column state.</para>
/// <para><version>v10.6.1</version></para>
/// </summary>
[Parameter]
Expand All @@ -2072,6 +2074,8 @@ private async Task OnContextMenu(MouseEventArgs e, TItem item)
/// <summary>
/// <para lang="zh">列宽自适应方法</para>
/// <para lang="en">Fit All Column Width Method</para>
/// <para lang="zh">启用 <see cref="AllowResizing"/> 时,按当前已渲染内容调整所有可见数据列的宽度;发生调整后统一保存列状态、触发一次回调。</para>
/// <para lang="en">When <see cref="AllowResizing"/> is enabled, fits all visible data columns to their currently rendered content, then saves the column state and invokes the callback once if widths were fitted.</para>
/// </summary>
public async Task FitAllColumnWidth()
{
Expand Down
65 changes: 47 additions & 18 deletions src/BootstrapBlazor/Components/Table/Table.razor.js
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,32 @@ export async function reset(id) {
}
}

export async function fitAllColumnWidth(id) {
const table = Data.get(id);
if (!table?.tables?.length) {
return;
}

let resized = false;
for (const col of getResizableColumns(table)) {
if (await autoFitColumnWidth(table, col, false)) {
resized = true;
}
}

if (resized) {
const state = getColumnStateObject(table);
saveColumnStateToLocalstorage(table, state);

// use wildcard to notify all columns have been resized
await table.invoke.invokeMethodAsync(
table.options.resizeColumnCallback,
"*",
state
Comment thread
sourcery-ai[bot] marked this conversation as resolved.
Resolved
);
}
}

export async function switchCardView(id) {
const table = Data.get(id);

Expand Down Expand Up @@ -471,7 +497,7 @@ const setResizeListener = table => {
let colIndex = 0
let originalX = 0

const columns = [...table.tables[0].querySelectorAll('.col-resizer')]
const columns = getResizableColumns(table);
columns.forEach(col => {
table.columns.push(col)
EventHandler.on(col, 'click', e => e.stopPropagation());
Expand Down Expand Up @@ -610,35 +636,36 @@ const getColumnName = col => getColumnHeader(col).getAttribute('data-bb-field');

const getResizableColumnWidth = col => getWidth(getColumnHeader(col)) | 0;

const getResizableColumns = table => [...table.tables[0].querySelectorAll(':scope > thead > tr > th > .col-resizer')];

const indexOfCol = col => {
const th = getColumnHeader(col);
const row = th.parentElement;
return [...row.children].indexOf(th);
}

const autoFitColumnWidth = async (table, col) => {
const autoFitColumnWidth = async (table, col, notify = true) => {
stopAutoColumnWidth(table);
const field = getColumnName(col);
const index = indexOfCol(col);
let rows = null;
let maxWidth = getColumnMaxCellWidth(table, index);

if (table.options.fitColumnWidthIncludeHeader) {
const th = getColumnHeader(col);
maxWidth = Math.max(maxWidth, getCellWidth(th));
}

if (maxWidth > 0) {
table.tables.forEach(table => {
const colEl = table.querySelectorAll('colgroup col')[index];
const colEl = table.querySelectorAll(':scope > colgroup > col')[index];
if (colEl) {
colEl.style.setProperty('width', `${maxWidth}px`);
}

const th = table.querySelectorAll('thead > tr > th')[index];
const th = table.querySelectorAll(':scope > thead > tr > th')[index];
if (th) {
const span = th.querySelector('.table-text');
span.style.removeProperty('width');
span?.style.removeProperty('width');
}

const tableWidth = getTableWidth(table);
Expand All @@ -647,26 +674,28 @@ const autoFitColumnWidth = async (table, col) => {

resetColumnWidthTips(table, col);

const state = getColumnStateObject(table);
saveColumnStateToLocalstorage(table, state);
// notify or not
if (notify) {
const state = getColumnStateObject(table);
saveColumnStateToLocalstorage(table, state);

await table.invoke.invokeMethodAsync(table.options.resizeColumnCallback, field, state);
await table.invoke.invokeMethodAsync(table.options.resizeColumnCallback, field, state);
}
return true;
}
return false;
}

const getColumnMaxCellWidth = (table, index) => {
let rows = null;
const body = table.thead ? table.tables[1] : table.tables[0];
const rows = body.querySelectorAll(':scope > tbody > tr:not(.is-detail):not(.is-empty)');
let maxWidth = 0;
if (table.thead) {
rows = [...table.tables[1].tBodies[0].rows].filter(x => !x.classList.contains('is-detail'));
}
else {
rows = [...table.tables[0].tBodies[0].rows].filter(x => !x.classList.contains('is-detail'));
}

rows.forEach(row => {
const cell = row.cells[index];
maxWidth = Math.max(maxWidth, calcCellWidth(cell));
if (cell && cell.colSpan === 1) {
maxWidth = Math.max(maxWidth, calcCellWidth(cell));
}
});

return maxWidth;
Expand Down
19 changes: 15 additions & 4 deletions test/UnitTest/Components/TableTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3153,6 +3153,7 @@ public void ShowEmpty_Ok()
});
cut.Contains("test-empty");
cut.Contains("colspan=\"1\"");
Assert.Single(cut.FindAll("tbody > tr.is-empty"));

var table = cut.FindComponent<Table<Foo>>();
table.Render(pb =>
Expand Down Expand Up @@ -9034,8 +9035,10 @@ public async Task AllowDragColumn_FixedColumn_Ok()
await cut.InvokeAsync(() => table.Instance.DragColumnCallback(1, 0));
}

[Fact]
public async Task OnTableColumnClientStatusChanged_ResizeColumn_Ok()
[Theory]
[InlineData(nameof(Foo.Address))]
[InlineData("*")]
public async Task OnTableColumnClientStatusChanged_ResizeColumn_Ok(string columnName)
{
var state = new TableColumnClientStatus();
state.TableWidth = 500;
Expand All @@ -9045,6 +9048,7 @@ public async Task OnTableColumnClientStatusChanged_ResizeColumn_Ok()
Context.JSInterop.Setup<TableColumnClientStatus>("getColumnStates", "test").SetResult(state);

var name = "";
var callbackCount = 0;
TableColumnClientStatus? clientState = null;
var localizer = Context.Services.GetRequiredService<IStringLocalizer<Foo>>();
var cut = Context.Render<BootstrapBlazorRoot>(pb =>
Expand All @@ -9057,6 +9061,7 @@ public async Task OnTableColumnClientStatusChanged_ResizeColumn_Ok()
pb.Add(a => a.FitColumnWidthIncludeHeader, true);
pb.Add(a => a.OnTableColumnClientStatusChanged, (field, state) =>
{
callbackCount++;
name = field;
clientState = state;
return Task.CompletedTask;
Expand All @@ -9082,9 +9087,15 @@ public async Task OnTableColumnClientStatusChanged_ResizeColumn_Ok()
newState.TableWidth = 100;
newState.Columns.Add(new TableColumnState() { Name = "Name", Width = 50 });
newState.Columns.Add(new TableColumnState() { Name = "Address", Width = 50 });
await cut.InvokeAsync(() => table.Instance.ResizeColumnCallback(nameof(Foo.Address), newState));
Assert.Equal("Address", name);
await cut.InvokeAsync(() => table.Instance.ResizeColumnCallback(columnName, newState));
Assert.Equal(columnName, name);
Assert.Equal(1, callbackCount);
Assert.NotNull(clientState);
Assert.Equal(100, clientState.TableWidth);
Assert.Equal(50, clientState.Columns.Single(c => c.Name == nameof(Foo.Name)).Width);
Assert.Equal(50, clientState.Columns.Single(c => c.Name == nameof(Foo.Address)).Width);
Assert.False(clientState.Columns.Single(c => c.Name == nameof(Foo.Name)).Visible);
Assert.True(clientState.Columns.Single(c => c.Name == nameof(Foo.Address)).Visible);
}

[Fact]
Expand Down
Loading