Skip to content

Commit

Permalink
feat(Dock): add GetLayoutConfig instance method (#2221)
Browse files Browse the repository at this point in the history
* feat: 增加 Reset 方法

* feat: 增加 Reset 方法

* refactor: 增加 Readonly 关键字

* LayoutConfig  and SaveLayoutCallback

* Update BootstrapBlazor.Shared.csproj

* 分开配置

* 更新复位功能

* GetLayout 获取面板的显示布局

* refactor: 增加销毁逻辑

* fix: 修复 layout 查找逻辑

* doc: 更新资源文件

* refactor: 更新脚本

* doc: 更新注释文档

* refactor: 移除 SaveLayoutCallback 回调方法

* refactor: 更改方法为 getLayoutConfig

* revert: 移除 Update 方法参数

* revert: 撤销布局逻辑

* feat: 移除 LayoutConfig

* refactor: 更改标题样式

* refactor: 精简代码

* feat: 增加 LayoutConfig 参数

* refactor: 支持服务器端配置

* refactor: 更新示例代码

* doc: 更新示例

---------

Co-authored-by: Argo-AscioTech <argo@live.ca>
  • Loading branch information
densen2014 and ArgoZhang authored Oct 5, 2023
1 parent 227aba8 commit 9869ee2
Show file tree
Hide file tree
Showing 11 changed files with 185 additions and 21 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -743,6 +743,11 @@ void AddDockView(DemoMenuItem item)
{
Text = Localizer["DockViewLock"],
Url = "dock-view/lock"
},
new()
{
Text = Localizer["DockViewLayout"],
Url = "dock-view/layout"
}
};
AddBadge(item, count: 1);
Expand Down
1 change: 1 addition & 0 deletions src/BootstrapBlazor.Shared/Locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -4503,6 +4503,7 @@
"DockViewComplex": "Complex",
"DockViewVisible": "Visible",
"DockViewLock": "Lock",
"DockViewLayout": "Custom",
"OtherComponents": "Others",
"MouseFollowerIntro": "MouseFollower",
"Live2DDisplayIntro": "Live2D Widget",
Expand Down
1 change: 1 addition & 0 deletions src/BootstrapBlazor.Shared/Locales/zh.json
Original file line number Diff line number Diff line change
Expand Up @@ -4503,6 +4503,7 @@
"DockViewComplex": "组合布局",
"DockViewVisible": "可见性切换",
"DockViewLock": "布局锁定",
"DockViewLayout": "布局自定义",
"OtherComponents": "其他组件",
"MouseFollowerIntro": "鼠标跟随",
"Live2DDisplayIntro": "Live2D 插件",
Expand Down
94 changes: 94 additions & 0 deletions src/BootstrapBlazor.Shared/Samples/DockViews/DockViewLayout.razor
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
@page "/dock-view/layout"
@inherits BaseDockView

<h4>自定义布局</h4>
<p>通过设置 <code>DockView</code> 的属性 <code>LayoutConfig</code> 初始化控制面板的显示布局, 方法 <code>GetLayoutConfig</code> 获取面板的显示布局</p>

<GroupBox Title="布局切换">
<Button OnClick="OnToggleLayout1" Text="布局1"></Button>
<Button OnClick="OnToggleLayout2" Text="布局2"></Button>
<Button OnClick="OnToggleLayout3" Text="布局3"></Button>
<Button OnClick="GetLayout" Text="获取布局"></Button>
<Button OnClick="Reset" Text="复位"></Button>
<code class="config">@LayoutConfigSave</code>
</GroupBox>

<div class="dock-toggle-demo">
<DockView @ref="DockView" Name="DockViewLayout" EnableLocalStorage="true" LayoutConfig="@LayoutConfig">
<DockContent Type="DockContentType.Column">
<DockComponent Title="标签一">
<Table TItem="DynamicObject" DynamicContext="DataTableDynamicContext"
IsStriped="true" IsBordered="true" IsExcel="true" ShowRefresh="false"
ShowDefaultButtons="false">
<DetailRowTemplate>
<div class="p-2 w-100">
<Table TItem="DynamicObject" DynamicContext="GetDetailDataTableDynamicContext(context)" IsStriped="true" IsBordered="true" IsExcel="true">
</Table>
</div>
</DetailRowTemplate>
</Table>
</DockComponent>
<DockComponent Title="标签二">
<Table TItem="Foo" @bind-Items="Items"
IsStriped="true" IsBordered="true" IsMultipleSelect="true"
ShowToolbar="true" ShowExtendButtons="true" ShowSkeleton="true"
OnAddAsync="@OnAddAsync">
<TableColumns>
<TableColumn @bind-Field="@context.DateTime" Width="180" />
<TableColumn @bind-Field="@context.Name" />
<TableColumn @bind-Field="@context.Address" Width="180" TextEllipsis="true" ShowTips="true" />
<TableColumn @bind-Field="@context.Education" />
<TableColumn @bind-Field="@context.Count" />
<TableColumn @bind-Field="@context.Complete" />
</TableColumns>
</Table>
</DockComponent>
<DockComponent Title="标签三">
<FetchData></FetchData>
</DockComponent>
</DockContent>
</DockView>
</div>

@code {
[NotNull]
private DockView? DockView { get; set; }

private async Task GetLayout()
{
LayoutConfigSave = await DockView.GetLayoutConfig();
}

private Task Reset() => DockView.Reset();

private void OnToggleLayout1()
{
LayoutConfig = LayoutConfig1;
}

private void OnToggleLayout2()
{
LayoutConfig = LayoutConfig2;
}

private void OnToggleLayout3()
{
LayoutConfig = LayoutConfig3;
}

string? LayoutConfig;

string? LayoutConfigSave;

string LayoutConfig1 = """"
{"root":{"type":"row","content":[{"type":"column","content":[{"type":"stack","content":[{"type":"component","content":[],"width":50,"minWidth":0,"height":50,"minHeight":0,"id":"bb_45517422","maximised":false,"isClosable":true,"reorderEnabled":true,"title":"标签三","componentType":"component","componentState":{"id":"bb_45517422","showClose":true,"class":null,"key":"标签三","lock":false}}],"width":50,"minWidth":0,"height":33.460076045627375,"minHeight":0,"id":"","isClosable":true,"maximised":false,"activeItemIndex":0},{"type":"stack","content":[{"type":"component","content":[],"width":50,"minWidth":0,"height":50,"minHeight":0,"id":"bb_42425232","maximised":false,"isClosable":true,"reorderEnabled":true,"title":"标签二","componentType":"component","componentState":{"id":"bb_42425232","showClose":true,"class":null,"key":"标签二","lock":false}}],"width":50,"minWidth":0,"height":66.53992395437263,"minHeight":0,"id":"","isClosable":true,"maximised":false,"activeItemIndex":0}],"width":50,"minWidth":50,"height":50,"minHeight":50,"id":"","isClosable":true},{"type":"stack","content":[{"type":"component","content":[],"width":50,"minWidth":0,"height":50,"minHeight":0,"id":"bb_21184535","maximised":false,"isClosable":true,"reorderEnabled":true,"title":"标签一","componentType":"component","componentState":{"id":"bb_21184535","showClose":true,"class":null,"key":"标签一","lock":false}}],"width":50,"minWidth":0,"height":50,"minHeight":0,"id":"bb_54183781","isClosable":true,"maximised":false,"activeItemIndex":0}],"width":50,"minWidth":50,"height":50,"minHeight":50,"id":"","isClosable":true},"openPopouts":[],"settings":{"constrainDragToContainer":true,"reorderEnabled":true,"popoutWholeStack":false,"blockedPopoutsThrowError":true,"closePopoutsOnUnload":true,"responsiveMode":"none","tabOverlapAllowance":0,"reorderOnTabMenuClick":true,"tabControlOffset":10,"popInOnClose":false},"dimensions":{"borderWidth":5,"borderGrabWidth":5,"minItemHeight":10,"minItemWidth":10,"headerHeight":25,"dragProxyWidth":300,"dragProxyHeight":200},"header":{"show":"top","popout":"lock/unlock","dock":"dock","close":"close","maximise":"maximise","minimise":"minimise","tabDropdown":"additional tabs"},"resolved":true}
"""";

string LayoutConfig2 = """"
{"root":{"type":"row","content":[{"type":"stack","content":[{"type":"component","content":[],"width":50,"minWidth":0,"height":50,"minHeight":0,"id":"bb_24636646","maximised":false,"isClosable":true,"reorderEnabled":true,"title":"标签三","componentType":"component","componentState":{"id":"bb_24636646","showClose":true,"class":null,"key":"标签三","lock":false}}],"width":33.333333333333336,"minWidth":0,"height":50,"minHeight":0,"id":"","isClosable":true,"maximised":false,"activeItemIndex":0},{"type":"stack","content":[{"type":"component","content":[],"width":50,"minWidth":0,"height":50,"minHeight":0,"id":"bb_60600063","maximised":false,"isClosable":true,"reorderEnabled":true,"title":"标签一","componentType":"component","componentState":{"id":"bb_60600063","showClose":true,"class":null,"key":"标签一","lock":false}}],"width":33.333333333333336,"minWidth":0,"height":50,"minHeight":0,"id":"bb_54183781","isClosable":true,"maximised":false,"activeItemIndex":0},{"type":"stack","content":[{"type":"component","content":[],"width":50,"minWidth":0,"height":50,"minHeight":0,"id":"bb_6744750","maximised":false,"isClosable":true,"reorderEnabled":true,"title":"标签二","componentType":"component","componentState":{"id":"bb_6744750","showClose":true,"class":null,"key":"标签二","lock":false}}],"width":33.33333333333333,"minWidth":0,"height":50,"minHeight":0,"id":"bb_6744750","isClosable":true,"maximised":false,"activeItemIndex":0}],"width":50,"minWidth":50,"height":50,"minHeight":50,"id":"","isClosable":true},"openPopouts":[],"settings":{"constrainDragToContainer":true,"reorderEnabled":true,"popoutWholeStack":false,"blockedPopoutsThrowError":true,"closePopoutsOnUnload":true,"responsiveMode":"none","tabOverlapAllowance":0,"reorderOnTabMenuClick":true,"tabControlOffset":10,"popInOnClose":false},"dimensions":{"borderWidth":5,"borderGrabWidth":5,"minItemHeight":10,"minItemWidth":10,"headerHeight":25,"dragProxyWidth":300,"dragProxyHeight":200},"header":{"show":"top","popout":"lock/unlock","dock":"dock","close":"close","maximise":"maximise","minimise":"minimise","tabDropdown":"additional tabs"},"resolved":true}
"""";

string LayoutConfig3 = """"
{"root":{"type":"stack","content":[{"type":"component","content":[],"width":50,"minWidth":0,"height":50,"minHeight":0,"id":"bb_24636646","maximised":false,"isClosable":true,"reorderEnabled":true,"title":"标签三","componentType":"component","componentState":{"id":"bb_24636646","showClose":true,"class":null,"key":"标签三","lock":false}},{"type":"component","content":[],"width":50,"minWidth":0,"height":50,"minHeight":0,"id":"bb_60600063","maximised":false,"isClosable":true,"reorderEnabled":true,"title":"标签一","componentType":"component","componentState":{"id":"bb_60600063","showClose":true,"class":null,"key":"标签一","lock":false}},{"type":"component","content":[],"width":50,"minWidth":0,"height":50,"minHeight":0,"id":"bb_6744750","maximised":false,"isClosable":true,"reorderEnabled":true,"title":"标签二","componentType":"component","componentState":{"id":"bb_6744750","showClose":true,"class":null,"key":"标签二","lock":false}}],"width":50,"minWidth":0,"height":50,"minHeight":0,"id":"bb_60600063","isClosable":true,"maximised":false,"activeItemIndex":1},"openPopouts":[],"settings":{"constrainDragToContainer":true,"reorderEnabled":true,"popoutWholeStack":false,"blockedPopoutsThrowError":true,"closePopoutsOnUnload":true,"responsiveMode":"none","tabOverlapAllowance":0,"reorderOnTabMenuClick":true,"tabControlOffset":10,"popInOnClose":false},"dimensions":{"borderWidth":5,"borderGrabWidth":5,"minItemHeight":10,"minItemWidth":10,"headerHeight":25,"dragProxyWidth":300,"dragProxyHeight":200},"header":{"show":"top","popout":"lock/unlock","dock":"dock","close":"close","maximise":"maximise","minimise":"minimise","tabDropdown":"additional tabs"},"resolved":true}
"""";
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
.config {
display: block;
margin-top: 1rem;
border: 1px solid var(--bs-secondary);
border-radius: var(--bs-border-radius);
padding: 0.5rem;
overflow: auto;
height: 88px;
}

.dock-toggle-demo {
height: calc(100vh - 424px);
margin-top: 1rem;
}
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
@page "/dock-view/lock"
@inherits BaseDockView

<h4 class="mt-3">锁定面板</h4>
<h4>锁定面板</h4>
<p>通过设置 <code>DockView</code> 的属性 <code>IsLock</code>,控制所有面板是否能拖动</p>
<p>通过设置 <code>DockComponent</code> 的属性 <code>IsLock</code>,控制某个面板是否能拖动</p>

<Button OnClick="OnToggleLock" Text="@LockText"></Button>

<div class="dock-lock-demo">
<DockView Name="DockViewLock" EnableLocalStorage="false" OnLockChangedCallbackAsync="OnLockChangedCallbackAsync" IsLock="@IsLock">
<DockView Name="DockViewLock" EnableLocalStorage="true" OnLockChangedCallbackAsync="OnLockChangedCallbackAsync" IsLock="@IsLock">
<DockContent Type="DockContentType.Row">
<DockComponent Title="标签一" IsLock="true">
<DockComponent Title="标签一">
<Table TItem="DynamicObject" DynamicContext="DataTableDynamicContext"
IsStriped="true" IsBordered="true" IsExcel="true" ShowRefresh="true"
ShowDefaultButtons="false" IsFixedHeader="false">
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
@page "/dock-view/visible"
@inherits BaseDockView

<h4 class="mt-3">可隐藏的面板</h4>
<h4>可隐藏的面板</h4>
<p>通过设置 <code>DockComponent</code> 的属性 <code>Visible</code> 控制面板的显示和隐藏</p>

<Button OnClick="OnToggleVisible" Text="切换标签一"></Button>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk.Razor">

<PropertyGroup>
<Version>7.0.11</Version>
<Version>7.0.12</Version>
</PropertyGroup>

<PropertyGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,12 @@ public partial class DockView
[Parameter]
public string? LocalStoragePrefix { get; set; }

/// <summary>
/// 获得/设置 布局配置
/// </summary>
[Parameter]
public string? LayoutConfig { get; set; }

private DockViewConfig Config { get; } = new();

private DockContent Content { get; } = new();
Expand Down Expand Up @@ -150,6 +156,7 @@ protected override async Task OnAfterRenderAsync(bool firstRender)
EnableLocalStorage = EnableLocalStorage,
IsLock = IsLock,
Contents = Config.Contents,
LayoutConfig = LayoutConfig,
LocalStorageKeyPrefix = $"{LocalStoragePrefix}-{Name}",
VisibleChangedCallback = nameof(VisibleChangedCallbackAsync),
InitializedCallback = nameof(InitializedCallbackAsync),
Expand Down Expand Up @@ -203,11 +210,25 @@ public async Task Lock(bool @lock)
}
}

/// <summary>
/// 获取布局配置
/// </summary>
/// <returns></returns>
public Task<string?> GetLayoutConfig() => InvokeAsync<string>("getLayoutConfig", Id);

/// <summary>
/// 重置为默认布局
/// </summary>
/// <returns></returns>
public Task Reset() => InvokeVoidAsync("reset", Id, GetOption(), Interop);
public Task Reset(string? layoutConfig = null)
{
var config = GetOption();
if (layoutConfig != null)
{
config.LayoutConfig = layoutConfig;
}
return InvokeVoidAsync("reset", Id, config);
}

/// <summary>
/// 标签页关闭回调方法 由 JavaScript 调用
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ export async function init(id, option, invoke) {
await addLink("./_content/BootstrapBlazor.Dock/css/goldenlayout-bb.css")

const eventsData = new Map()
const dock = { el, eventsData, lock: option.lock }
const dock = { el, eventsData, invoke, lock: option.lock, layoutConfig: option.layoutConfig }
Data.set(id, dock)

option.invokeVisibleChangedCallback = (title, visible) => {
Expand Down Expand Up @@ -74,7 +74,10 @@ export function update(id, option) {
const dock = Data.get(id)

if (dock) {
if (dock.lock !== option.lock) {
if (dock.layoutConfig !== option.layoutConfig) {
reset(id, option)
}
else if (dock.lock !== option.lock) {
// 处理 Lock 逻辑
dock.lock = option.lock
lockDock(dock)
Expand All @@ -92,7 +95,17 @@ export function lock(id, lock) {
lockDock(dock)
}

export function reset(id, option, invoke) {
export function getLayoutConfig(id) {
let config = "";
const dock = Data.get(id)
if (dock) {
const layout = dock.layout
config = JSON.stringify(layout.saveLayout())
}
return config;
}

export function reset(id, option) {
const dock = Data.get(id)
if (dock) {
removeConfig(option);
Expand All @@ -108,7 +121,7 @@ export function reset(id, option, invoke) {
})
dispose(id)

init(id, option, invoke)
init(id, option, dock.invoke)
}
}

Expand All @@ -122,6 +135,13 @@ export function dispose(id) {

dock.eventsData.clear()
dock.layout.destroy()

if (goldenLayout.bb_docks !== void 0) {
const index = goldenLayout.bb_docks.indexOf(dock);
if (index > 0) {
goldenLayout.bb_docks.splice(index, 1);
}
}
}

const lockDock = dock => {
Expand Down Expand Up @@ -291,21 +311,24 @@ const closeItem = (el, component) => {
}

const getConfig = option => {
let config = null
option = {
enableLocalStorage: false,
layoutConfig: null,
name: 'default',
...option
}
if (option.enableLocalStorage) {
const localConfig = localStorage.getItem(getLocalStorageKey(option));
if (localConfig) {
// 当tab全部关闭时,没有root节点
const configItem = JSON.parse(localConfig)
if (configItem.root) {
config = configItem
resetComponentId(config, option)
}

let config = null
let layoutConfig = option.layoutConfig;
if (layoutConfig === null && option.enableLocalStorage) {
layoutConfig = localStorage.getItem(getLocalStorageKey(option));
}
if (layoutConfig) {
// 当tab全部关闭时,没有root节点
const configItem = JSON.parse(layoutConfig)
if (configItem.root) {
config = configItem
resetComponentId(config, option)
}
}

Expand Down Expand Up @@ -474,7 +497,7 @@ const hackGoldenLayout = dock => {

this._closeButton.onClick = function (ev) {
// find own dock
const dock = goldenLayout.bb_docks.find(i => i.layout === this.layoutManager);
const dock = goldenLayout.bb_docks.find(i => i.layout === this._header.layoutManager);
const eventsData = dock.eventsData

const tabs = this._header.tabs.map(tab => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,4 +67,9 @@ class DockViewConfig
[JsonPropertyName("content")]
[JsonConverter(typeof(DockContentRootConverter))]
public List<DockContent> Contents { get; set; } = new();

/// <summary>
/// 获得/设置 布局配置 默认 null 未设置
/// </summary>
public string? LayoutConfig { get; set; }
}

0 comments on commit 9869ee2

Please sign in to comment.