using Framework.DataAccessLayer;
using Framework.Session;
using System.Collections.Generic;
using System.Linq;
namespace Framework.Json.Bulma
{
///
/// Horizontal top navbar level 0 and level 1. See also: https://bulma.io/documentation/components/navbar/
///
public class BulmaNavbar : ComponentJson
{
///
/// Constructor.
///
public BulmaNavbar(ComponentJson owner)
: base(owner, nameof(BulmaNavbar))
{
}
///
/// For example company logo.
///
public string BrandTextHtml;
[Serialize(SerializeEnum.Session)]
internal List GridList = new List();
[Serialize(SerializeEnum.Session)]
internal BulmaNavbarFilter Filter;
///
/// Add data grid to Navbar.
///
/// Data grid with Id, ParentId and TextHtml columns.
/// If true, items are placed on the right hand side of the navbar.
/// If true, currently selected row is shown on top as drop down button. Used for example for language switch.
public void GridAdd(Grid grid, bool isNavbarEnd = false, bool isSelectMode = false)
{
GridList.Add(new BulmaNavbarGrid { Grid = grid, IsNavbarEnd = isNavbarEnd, IsSelectMode = isSelectMode });
}
///
/// Add data grid search filter input element to navbar.
///
/// Data grid on which to search.
/// If true, search box is placed to the right hand side of the navbar.
public void FilterSet(Grid grid, string fieldName, bool isNavbarEnd = false)
{
Filter = new BulmaNavbarFilter { Grid = grid, FieldNameCSharp = fieldName, IsNavbarEnd = isNavbarEnd };
}
///
/// Gets ItemStartList. Items on left hand side in navbar.
///
internal List ItemStartList = new List();
///
/// Gets ItemStartList. Items on left hand side in navbar.
///
internal List ItemEndList = new List();
private static void ItemListAll(List itemList, List result)
{
if (itemList != null)
{
foreach (var navbarItem in itemList)
{
result.Add(navbarItem);
ItemListAll(navbarItem.ItemList, result);
}
}
}
///
/// Returns ItemStartList and ItemEndList recursive.
///
private List ItemListAll()
{
var result = new List();
ItemListAll(ItemStartList, result);
ItemListAll(ItemEndList, result);
return result;
}
///
/// Returns ItemStartList and ItemEndList recursive.
///
private static List ItemListAll(BulmaNavbarMenu bulmaNavbarMenu)
{
var result = new List();
ItemListAll(bulmaNavbarMenu.ItemList, result);
return result;
}
private void RowMap(BulmaNavbarRowMapArgs args, BulmaNavbarRowMapResult result, string fieldName)
{
var propertyInfo = args.Row.GetType().GetProperty(fieldName);
if (propertyInfo != null)
{
object value = propertyInfo.GetValue(args.Row);
result.GetType().GetField(fieldName).SetValue(result, value);
}
}
///
/// Override this method to custom map incoming data rows to navbar items.
///
protected virtual void RowMap(BulmaNavbarRowMapArgs args, BulmaNavbarRowMapResult result)
{
// Default row mapper
RowMap(args, result, nameof(result.Id));
RowMap(args, result, nameof(result.ParentId));
RowMap(args, result, nameof(result.TextHtml));
RowMap(args, result, nameof(result.NavigatePath));
RowMap(args, result, nameof(result.IsDivider));
RowMap(args, result, nameof(result.IsNavbarEnd));
RowMap(args, result, nameof(result.Sort));
}
private static void Render(BulmaNavbar navbar, BulmaNavbarGrid navbarGrid, BulmaNavbarMenu navbarMenu, ref int navbarItemId)
{
Grid grid = navbarGrid.Grid;
// Map all data grid rows
var rowMapList = new List();
foreach (var rowState in grid.RowStateList)
{
if (rowState.RowEnum == GridRowEnum.Index)
{
var rowMapArgs = new BulmaNavbarRowMapArgs { Row = grid.RowList[rowState.RowId.Value - 1] };
var rowMapResult = new BulmaNavbarRowMapResult { RowStateId = rowState.Id, IsSelect = rowState.IsSelect };
navbar.RowMap(rowMapArgs, rowMapResult);
if (rowMapResult.IsHide == false)
{
rowMapList.Add(rowMapResult);
}
}
}
rowMapList = rowMapList.OrderBy(item => item.Sort).ToList();
// IsSelectMode for example for language selection.
if (navbarGrid.IsSelectMode && rowMapList.Count > 0)
{
var rowMapTop = rowMapList.FirstOrDefault(item => item.RowStateId == grid.RowSelectRowStateId);
if (rowMapTop == null)
{
rowMapTop = rowMapList.First();
}
foreach (var rowMap in rowMapList)
{
if (rowMap != rowMapTop)
{
rowMap.ParentId = rowMapTop.Id;
}
}
}
// Select Path
var selectRowMapIdPathList = new List();
var selectRowMap = rowMapList.SingleOrDefault(item => item.IsSelect);
while (selectRowMap != null)
{
selectRowMapIdPathList.Add(selectRowMap.Id);
selectRowMap = rowMapList.SingleOrDefault(item => item.Id == selectRowMap.ParentId);
}
selectRowMapIdPathList.Reverse(); // Row id of Level 0, Level 1, Level 2 ...
// Level 0
Dictionary level0List = new Dictionary();
foreach (var rowMap in rowMapList)
{
if (rowMap.ParentId == null)
{
BulmaNavbarItemEnum itemEnum = BulmaNavbarItemEnum.Text;
// Level 0
var navbarItem = new BulmaNavbarItem { Id = navbarItemId += 1, ItemEnum = itemEnum, Grid = grid, RowStateId = rowMap.RowStateId, TextHtml = rowMap.TextHtml, NavigatePath = rowMap.NavigatePath, IsActive = rowMap.IsSelect };
level0List.Add(rowMap.Id, navbarItem);
bool isNavbarEnd = navbarGrid.IsNavbarEnd;
if (rowMap.IsNavbarEnd != null)
{
isNavbarEnd = rowMap.IsNavbarEnd.Value;
}
if (isNavbarEnd == false)
{
navbar.ItemStartList.Add(navbarItem);
}
else
{
navbar.ItemEndList.Add(navbarItem);
}
}
}
// Level 1
Dictionary level1List = new Dictionary();
foreach (var rowMap in rowMapList)
{
if (rowMap.ParentId != null)
{
if (level0List.TryGetValue(rowMap.ParentId.Value, out var navbarItemParent))
{
navbarItemParent.ItemEnum = BulmaNavbarItemEnum.Parent; // Item has children
BulmaNavbarItemEnum itemEnum = BulmaNavbarItemEnum.Text;
if (rowMap.IsDivider)
{
itemEnum = BulmaNavbarItemEnum.Divider;
}
// Level 1
var navbarItem = new BulmaNavbarItem { Id = navbarItemId += 1, ItemEnum = itemEnum, Grid = grid, RowStateId = rowMap.RowStateId, TextHtml = rowMap.TextHtml, NavigatePath = rowMap.NavigatePath, IsActive = rowMap.IsSelect };
level1List.Add(rowMap.Id, navbarItem);
navbarItemParent.ItemList.Add(navbarItem);
}
}
}
if (navbarMenu != null)
{
// Level 2
navbarMenu.ItemList.Clear();
Dictionary level2List = new Dictionary();
foreach (var rowMap in rowMapList)
{
if (selectRowMapIdPathList.Count >= 2 && selectRowMapIdPathList[1] == rowMap.ParentId) // Filter Level 2 items to what is selected in navigation.
{
if (rowMap.ParentId != null)
{
if (level1List.TryGetValue(rowMap.ParentId.Value, out var navbarItemParent))
{
BulmaNavbarItemEnum itemEnum = BulmaNavbarItemEnum.Text;
if (rowMap.IsDivider)
{
itemEnum = BulmaNavbarItemEnum.Divider;
}
// Level 2
var navbarItem = new BulmaNavbarItem { Id = navbarItemId += 1, ItemEnum = itemEnum, Grid = grid, RowStateId = rowMap.RowStateId, TextHtml = rowMap.TextHtml, NavigatePath = rowMap.NavigatePath, IsActive = rowMap.IsSelect };
level2List.Add(rowMap.Id, navbarItem);
navbarMenu.ItemList.Add(navbarItem);
}
}
}
}
// Level 3
foreach (var rowMap in rowMapList)
{
if (rowMap.ParentId != null)
{
if (level2List.TryGetValue(rowMap.ParentId.Value, out var navbarItemParent))
{
navbarItemParent.ItemEnum = BulmaNavbarItemEnum.Parent; // Item has children
BulmaNavbarItemEnum itemEnum = BulmaNavbarItemEnum.Text;
if (rowMap.IsDivider)
{
itemEnum = BulmaNavbarItemEnum.Divider;
}
// Level 3
var navbarItem = new BulmaNavbarItem { Id = navbarItemId += 1, ItemEnum = itemEnum, Grid = grid, RowStateId = rowMap.RowStateId, TextHtml = rowMap.TextHtml, NavigatePath = rowMap.NavigatePath, IsActive = rowMap.IsSelect };
navbarItemParent.ItemList.Add(navbarItem);
}
}
}
}
}
internal static void Render(AppJson appJson)
{
int navbarItemId = 0;
var componentListAll = appJson.ComponentListAll();
var navbarMenuList = componentListAll.OfType();
foreach (BulmaNavbar navbar in componentListAll.OfType())
{
// ItemList clear
navbar.ItemStartList.Clear();
navbar.ItemEndList.Clear();
// Add level 0 and level 1 to navbar
foreach (var navbarGrid in navbar.GridList)
{
var navbarMenu = navbarMenuList.Where(item => item.Grid == navbarGrid.Grid).SingleOrDefault();
Render(navbar, navbarGrid, navbarMenu, ref navbarItemId);
}
// Add data grid filter (input text) to navbar
if (navbar.Filter != null)
{
var filter = navbar.Filter;
var grid = filter.Grid;
// Get filter text from value store.
new GridFilter(grid).FilterValueList().TryGetValue(filter.FieldNameCSharp, out var gridFilterValue);
string filterText = gridFilterValue?.Text;
int rowSateId = grid.RowStateList.Single(item => item.RowEnum == GridRowEnum.Filter).Id;
// Filter input text box
var navbarItem = new BulmaNavbarItem { Id = navbarItemId += 1, ItemEnum = BulmaNavbarItemEnum.Filter, Grid = grid, FilterFieldNameCSharp = filter.FieldNameCSharp, RowStateId = rowSateId, FilterText = filterText, FilterPlaceholder = "Search" };
if (filter.IsNavbarEnd == false)
{
navbar.ItemStartList.Add(navbarItem);
}
else
{
navbar.ItemEndList.Add(navbarItem);
}
}
}
}
internal static void ProcessAsync(AppJson appJson)
{
// User clicked item in BulmaNavbar
if (UtilSession.Request(appJson, CommandEnum.BulmaNavbarItemIsClick, out CommandJson commandJson, out BulmaNavbar navbar))
{
var navbarItem = navbar.ItemListAll().Single(item => item.Id == commandJson.BulmaNavbarItemId);
Grid grid = navbarItem.Grid;
// User clicked navbar button
if (navbarItem.ItemEnum == BulmaNavbarItemEnum.Text)
{
appJson.IsScrollToTop = true; // Because of possible use of css class is-fixed-top.
appJson.RequestJson.CommandAdd(new CommandJson { CommandEnum = CommandEnum.GridIsClickRow, ComponentId = grid.Id, RowStateId = navbarItem.RowStateId });
}
// User changed navbar filter text
if (navbarItem.ItemEnum == BulmaNavbarItemEnum.Filter)
{
string filterText = commandJson.BulmaFilterText;
int rowStateId = navbarItem.RowStateId;
var column = grid.ColumnList.Single(item => item.FieldNameCSharp == navbarItem.FilterFieldNameCSharp);
var cell = grid.CellList.Single(item => item.RowStateId == rowStateId && item.ColumnId == column.Id && item.CellEnum == GridCellEnum.Filter);
appJson.RequestJson.CommandAdd(new CommandJson { CommandEnum = CommandEnum.GridCellIsModify, ComponentId = grid.Id, RowStateId = navbarItem.RowStateId, GridCellId = cell.Id, GridCellText = filterText });
}
}
// User clicked item in vertical BulmaNavbarMenu
if (UtilSession.Request(appJson, CommandEnum.BulmaNavbarMenuItemIsClick, out commandJson, out BulmaNavbarMenu navbarMenu))
{
var navbarItem = BulmaNavbar.ItemListAll(navbarMenu).Single(item => item.Id == commandJson.BulmaNavbarItemId);
Grid grid = navbarMenu.Grid;
// User clicked navbar button
if (navbarItem.ItemEnum == BulmaNavbarItemEnum.Text || navbarItem.ItemEnum == BulmaNavbarItemEnum.Parent)
{
appJson.IsScrollToTop = true; // Because of possible use of css class is-fixed-top.
appJson.RequestJson.CommandAdd(new CommandJson { CommandEnum = CommandEnum.GridIsClickRow, ComponentId = grid.Id, RowStateId = navbarItem.RowStateId });
}
}
}
}
///
/// Vertical left navbar level 2. See alose: https://bulma.io/documentation/components/menu/
///
public class BulmaNavbarMenu : ComponentJson
{
///
/// Constructor for vertial navbar menu.
///
public BulmaNavbarMenu(ComponentJson owner)
: base(owner, nameof(BulmaNavbarMenu))
{
}
///
/// Gets or sets Grid.
///
public Grid Grid;
///
/// Gets ItemList. Vertical items on left hand side in menu.
///
internal List ItemList = new List();
}
internal class BulmaNavbarGrid
{
public Grid Grid;
///
/// Gets or sets IsSelectMode. If true, currently selected row is shown on top as drop down button. Used for example for language switch.
///
public bool IsSelectMode;
public bool IsNavbarEnd;
}
internal class BulmaNavbarFilter
{
public Grid Grid;
public string FieldNameCSharp;
public bool IsNavbarEnd;
}
internal enum BulmaNavbarItemEnum
{
None = 0,
Text = 1,
Divider = 2,
///
/// Filter input text box.
///
Filter = 3,
Parent = 4,
}
///
/// Hierarchical dto representing menu items for Angular. Rendered as Bulma link or input html element.
///
internal class BulmaNavbarItem
{
[Serialize(SerializeEnum.Both)]
public int Id;
public BulmaNavbarItemEnum ItemEnum;
[Serialize(SerializeEnum.Session)]
public Grid Grid;
[Serialize(SerializeEnum.Session)]
public int RowStateId;
[Serialize(SerializeEnum.Client)]
public string TextHtml;
[Serialize(SerializeEnum.Both)]
public string NavigatePath;
[Serialize(SerializeEnum.Client)]
public bool IsActive;
[Serialize(SerializeEnum.Session)]
public string FilterFieldNameCSharp;
[Serialize(SerializeEnum.Client)]
public string FilterText;
[Serialize(SerializeEnum.Client)]
public string FilterPlaceholder;
[Serialize(SerializeEnum.Both)]
public List ItemList = new List();
}
public class BulmaNavbarRowMapArgs
{
public Row Row;
}
public class BulmaNavbarRowMapResult
{
public int Id;
public int? ParentId;
public bool IsHide;
///
/// Gets or sets TextHtml. Rendered by Angular as innerHtml.
///
public string TextHtml;
public string NavigatePath;
public bool IsDivider;
public bool? IsNavbarEnd;
public double? Sort;
internal int RowStateId;
internal bool IsSelect;
}
}