@typeparam TNode
@*
* dbMango
*
* Copyright 2025 Deutsche Bank AG
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*@
@foreach (var node in Nodes.Where(x => x != null ))
{
var nodeExpanded = Handler.IsExpanded(node);
var nodeSelected = ReferenceEquals(Handler.GetSelectedNode(), node) || (node?.Equals(Handler.GetSelectedNode()) ?? false);
var children = Handler.ChildSelector(node);
var hasChildren = children?.Any() ?? false;
@if (hasChildren)
{
OnToggleNode(node, !nodeExpanded))">
}
OnSelectNode(node))">
@if (TitleTemplate == null)
{
@node?.ToString()
}
else
{
@TitleTemplate(node)
}
@if (hasChildren && nodeExpanded)
{
}
}
@code {
public class TreeItemHandler
{
public Func GetSelectedNode { get; init; } = () => default;
public Action SetSelectedNode { get; init; } = _ => {};
public Func> ChildSelector { get; init; } = _ => Array.Empty();
public Func IsExpanded { get; init; } = _ => true;
public Func IsSelectable { get; init; } = _ => true;
public Action SetIsExpanded { get; init; } = (_, _) => {/*do nothing*/};
}
[Parameter] public IReadOnlyCollection Nodes { get; set; } = [];
[Parameter] public TreeItemHandler Handler { get; set; } = new();
[Parameter] public RenderFragment? TitleTemplate { get; set; }
[Parameter] public bool AutoExpandTransientNodes { get; set; } = true;
[Parameter] public TreeStyle Style { get; set; } = TreeStyle.Bootstrap;
public class TreeStyle
{
public static readonly TreeStyle Bootstrap = new()
{
ExpandNodeIconClass = "ui-icon-font icon-caret-right cursor-pointer",
CollapseNodeIconClass = "ui-icon-font icon-caret-down cursor-pointer",
NodeTitleClass = "list-group-item uic-tree-title_text cursor-pointer",
NodeTitleSelectedClass = "active"
};
public string? ExpandNodeIconClass { get; set; }
public string? CollapseNodeIconClass { get; set; }
public string? NodeTitleClass { get; set; }
public string? NodeTitleSelectedClass { get; set; }
}
private void OnToggleNode(TNode node, bool expand)
{
var expanded = Handler.IsExpanded(node);
if (expanded && !expand)
{
Handler.SetIsExpanded(node, false);
}
else if (!expanded && expand)
{
Handler.SetIsExpanded(node, true);
ExpandTransientChildren( node );
}
}
///Auto expand child nodes when there is only 1 child
private void ExpandTransientChildren( TNode node )
{
if ( !AutoExpandTransientNodes )
return;
while (Handler.ChildSelector(node)?.Count > 0)
{
var children = Handler.ChildSelector( node ) ?? Array.Empty();
if ( children.Count != 1 )
return;
var first = children.FirstOrDefault();
if (first == null || Handler.IsExpanded( first ) )
return;
Handler.SetIsExpanded(first, true);
node = first;
}
}
private void OnSelectNode(TNode node)
{
if (!Handler.IsSelectable(node))
return;
Handler.SetSelectedNode(node);
}
}