mirror of
https://github.com/radzenhq/radzen-blazor.git
synced 2026-07-08 18:16:08 +00:00
V7 (#2144)
* Remove Microsoft.CodeAnalysis. Add own C# expression parser. * Popup dialog animations (#2118) * Experiment with popup and dialog animations. * Move animations to a separate _animations.scss * Remove dialog closing animation. * Support side dialog positions. Prefix keyframes. * Use --rz-transition for animation function and duration * Reset site.css. * PanelMenu animations. * Display none is toggled a bit late. * RadzenPanel animations. * More animations. * Use transitions for panel menu. * Remove old code. * Accordion uses transitions. * Panel uses transitions. * Extract expand and collapse implementation in a separate component. * Set initial expand state earlier to prevent two renders. * Add open animation to notifications. * Handle onanimationend before toggling the animation classes. * Add menu animation. * Experiment with tree animation. * Add animations to fieldset. --------- Co-authored-by: yordanov <vasil@yordanov.info> * ExpressionSerializer and tests added (#2119) * Fix failing tests. * various components RequiresUnreferencedCode attribute added (#2120) * RequiresUnreferencedCode added to ExpressionSerializer * Update premium themes * RequiresUnreferencedCode added to ExpressionParser * FormComponentWithAutoComplete RequiresUnreferencedCode removed * Revert "FormComponentWithAutoComplete RequiresUnreferencedCode removed" This reverts commitec900a4df8. * Revert "RequiresUnreferencedCode added to ExpressionParser" This reverts commitf93b3b159b. * Revert "RequiresUnreferencedCode added to ExpressionSerializer" This reverts commit06fecec9a6. * Revert "various components RequiresUnreferencedCode attribute added (#2120)" This reverts commit2ed1a6cac1. * Remove RadzenHtml. * ExpressionSerializer FormatValue updated to use InvariantCulture * Catch potential JS interop exceptions that could occur during disposing. * Revert "Remove RadzenHtml." This reverts commit319085bf49. * SelectBar made single tab stop * RadioButtonList and CheckBoxList made single tab stop * SelectBar accessibility improved * RadioButtonList accessibility improved * CheckBoxList accessibility improved * Update radio button focus styles * Update checkbox list focus styles * Update Checkbox Radio and SelectBar focus styles * SelectBar, CheckBoxList and RadioButtonList focus state improved * Check for Multiple added * Use non-rendering event handlers for transitionend. * Rename css class rz-selectbutton to rz-selectbar and improve focus states * Fix selectbar focus outline offset * Update premium themes * Selectbar item focus styles should not be visible if the item is disabled. * CheckBoxList and RadioButtonList item focus should be visible only on keyboard input * SelectBar, CheckBoxList and RadioButtonList focus logic improved * Update animations * RadzenText margin-block should be 0 if it is in RadzenStack. Resolves #2134 * RadzenText margin-block should be 0 if it is first level child in RadzenStack * CheckBoxList focused fixed * Add toggle state classes to panel menu icon. * Update accordion styles to reflect expander changes * Add animation styles to expand arrow in Menu and ProfileMenu * Use a instead of NavLink as it seems to cause performance issues. * Set @bind-Expanded. * Revert "Set @bind-Expanded." This reverts commit 994107367bdf09043950f8bbe701eb9edefec676. * Revert "Use a instead of NavLink as it seems to cause performance issues." This reverts commit 05d5bef8f421bbeb5828ba1e9c5af6793ea3d32a. * Reduce rendering of panel menu items. * Add panel menu component. * Use ChildContent to render the toggle icon of the panel menu item. * Sync panel menu item selection in the item itself. * Rename ExpandedInternal to expanded. * Move filtering to the panel menu component. * Remove the transitionend handler to avoid a second rendering pass. * Build the assets for the net9.0 framework. * Do not trigger render when Click is used. * Panel menu keyboard navigation renders only when needed. * Focus reworked to use AsNonRenderingEventHandler * Focus the first item. * Update Panel demo * Use a more robust algorithm for month view event rendering that handles overlapping of events across a week. * Use RadzenStack in RadioButtonList * Add parsing support for `&` and `|`. * Add parsing support for `^`, `>>` and `<<`. * Simplify expression parsing tests. * Use RadzenStack in RadioButtonList and CheckBoxList * Change defaults for AlignItems and JustifyContent in RadioButtonList and CheckBoxList * Update RadioButtonList and CheckBoxList demos * Add --rz-input-border-block-end css variables to improve Fluent theme styles * Removed AsNonRenderingEventHandler from RadioButtonList and HtmlEditor focus and blur * Removed AsNonRenderingEventHandler from CheckBoxList * Simplify RadzenTable rendering. * Optimize memory usage of the ClassList utility. * Refactor RadzenButton to use ClassList. * RadzenSelectBar and RadzenSplitButton use ClassList. * Refactor RadzenBadge and RadzenAlert to use ClassList. * Refactor RadzenCard and RadzenFormField to use ClassList. * Refactor RadzenCardGroup and progress components to use ClassList. * Refactor RadzenMenu to use ClassList. * Use ClassList in RadzenBody, RadzenLayout and editor rendering components. * RadzenDialog uses ClassList. * RadzenDataGrid uses ClassList. * RadzenPager uses ClassList. * RadzenColumn uses ClassList. * Fix RadzenSplitButtonItem focused state. --------- Co-authored-by: Atanas Korchev <akorchev@gmail.com> Co-authored-by: Atanas Korchev <454726+akorchev@users.noreply.github.com> Co-authored-by: yordanov <vasil@yordanov.info> Co-authored-by: Quentin H <67709967+quintushr@users.noreply.github.com>
This commit is contained in:
File diff suppressed because it is too large
Load Diff
304
Radzen.Blazor.Tests/ExpressionSerializerTests.cs
Normal file
304
Radzen.Blazor.Tests/ExpressionSerializerTests.cs
Normal file
@@ -0,0 +1,304 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using Xunit;
|
||||
|
||||
namespace Radzen.Blazor.Tests
|
||||
{
|
||||
class TestEntity
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public int Age { get; set; }
|
||||
public double Salary { get; set; }
|
||||
public float Score { get; set; }
|
||||
public decimal Balance { get; set; }
|
||||
public short Level { get; set; }
|
||||
public long Population { get; set; }
|
||||
public Status AccountStatus { get; set; }
|
||||
public DateTime CreatedAt { get; set; }
|
||||
public DateTimeOffset LastUpdated { get; set; }
|
||||
public Guid Id { get; set; }
|
||||
public TimeOnly StartTime { get; set; }
|
||||
public DateOnly BirthDate { get; set; }
|
||||
public int[] Scores { get; set; }
|
||||
public List<string> Tags { get; set; }
|
||||
public List<TestEntity> Children { get; set; }
|
||||
public Address Address { get; set; }
|
||||
public double[] Salaries { get; set; }
|
||||
public float[] Heights { get; set; }
|
||||
public decimal[] Balances { get; set; }
|
||||
public short[] Levels { get; set; }
|
||||
public long[] Populations { get; set; }
|
||||
public string[] Names { get; set; }
|
||||
public Guid[] Ids { get; set; }
|
||||
public DateTime[] CreatedDates { get; set; }
|
||||
public DateTimeOffset[] UpdatedDates { get; set; }
|
||||
public TimeOnly[] StartTimes { get; set; }
|
||||
public DateOnly[] BirthDates { get; set; }
|
||||
public Status[] Statuses { get; set; }
|
||||
}
|
||||
|
||||
enum Status
|
||||
{
|
||||
Active,
|
||||
Inactive,
|
||||
Suspended
|
||||
}
|
||||
|
||||
class Address
|
||||
{
|
||||
public string City { get; set; }
|
||||
public string Country { get; set; }
|
||||
}
|
||||
|
||||
public class ExpressionSerializerTests
|
||||
{
|
||||
private readonly ExpressionSerializer _serializer = new ExpressionSerializer();
|
||||
|
||||
[Fact]
|
||||
public void Serializes_SimpleBinaryExpression()
|
||||
{
|
||||
Expression<Func<int, bool>> expr = e => e > 10;
|
||||
Assert.Equal("e => (e > 10)", _serializer.Serialize(expr));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Serializes_StringEquality()
|
||||
{
|
||||
Expression<Func<TestEntity, bool>> expr = e => e.Name == "John";
|
||||
Assert.Equal("e => (e.Name == \"John\")", _serializer.Serialize(expr));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Serializes_IntComparison()
|
||||
{
|
||||
Expression<Func<TestEntity, bool>> expr = e => e.Age > 18;
|
||||
Assert.Equal("e => (e.Age > 18)", _serializer.Serialize(expr));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Serializes_DoubleComparison()
|
||||
{
|
||||
Expression<Func<TestEntity, bool>> expr = e => e.Salary < 50000.50;
|
||||
Assert.Equal("e => (e.Salary < 50000.5)", _serializer.Serialize(expr));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Serializes_FloatComparison()
|
||||
{
|
||||
Expression<Func<TestEntity, bool>> expr = e => e.Score >= 85.3f;
|
||||
Assert.Equal("e => (e.Score >= 85.3)", _serializer.Serialize(expr));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Serializes_DecimalComparison()
|
||||
{
|
||||
Expression<Func<TestEntity, bool>> expr = e => e.Balance <= 1000.75m;
|
||||
Assert.Equal("e => (e.Balance <= 1000.75)", _serializer.Serialize(expr));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Serializes_ShortComparison()
|
||||
{
|
||||
Expression<Func<TestEntity, bool>> expr = e => e.Level == 3;
|
||||
Assert.Equal("e => (e.Level == 3)", _serializer.Serialize(expr));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Serializes_LongComparison()
|
||||
{
|
||||
Expression<Func<TestEntity, bool>> expr = e => e.Population > 1000000L;
|
||||
Assert.Equal("e => (e.Population > 1000000)", _serializer.Serialize(expr));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Serializes_EnumComparison()
|
||||
{
|
||||
Expression<Func<TestEntity, bool>> expr = e => e.AccountStatus == Status.Inactive;
|
||||
Assert.Equal("e => (e.AccountStatus == 1)", _serializer.Serialize(expr));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Serializes_ArrayContainsValue()
|
||||
{
|
||||
Expression<Func<TestEntity, bool>> expr = e => e.Scores.Contains(100);
|
||||
Assert.Equal("e => e.Scores.Contains(100)", _serializer.Serialize(expr));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Serializes_ArrayNotContainsValue()
|
||||
{
|
||||
Expression<Func<TestEntity, bool>> expr = e => !e.Scores.Contains(100);
|
||||
Assert.Equal("e => (!e.Scores.Contains(100))", _serializer.Serialize(expr));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Serializes_ArrayInValue()
|
||||
{
|
||||
Expression<Func<TestEntity, bool>> expr = e => e.Scores.Intersect(new [] { 100 }).Any();
|
||||
Assert.Equal("e => e.Scores.Intersect(new [] { 100 }).Any()", _serializer.Serialize(expr));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Serializes_ArrayNotInValue()
|
||||
{
|
||||
Expression<Func<TestEntity, bool>> expr = e => e.Scores.Except(new[] { 100 }).Any();
|
||||
Assert.Equal("e => e.Scores.Except(new [] { 100 }).Any()", _serializer.Serialize(expr));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Serializes_ArrayInValueOposite()
|
||||
{
|
||||
Expression<Func<TestEntity, bool>> expr = e => new[] { 100 }.Intersect(e.Scores).Any();
|
||||
Assert.Equal("e => new [] { 100 }.Intersect(e.Scores).Any()", _serializer.Serialize(expr));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Serializes_ArrayNotInValueOposite()
|
||||
{
|
||||
Expression<Func<TestEntity, bool>> expr = e => new[] { 100 }.Except(e.Scores).Any();
|
||||
Assert.Equal("e => new [] { 100 }.Except(e.Scores).Any()", _serializer.Serialize(expr));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Serializes_IntArrayInValueOposite()
|
||||
{
|
||||
Expression<Func<TestEntity, bool>> expr = e => new[] { 100 }.Intersect(e.Scores).Any();
|
||||
Assert.Equal("e => new [] { 100 }.Intersect(e.Scores).Any()", _serializer.Serialize(expr));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Serializes_IntArrayNotInValueOposite()
|
||||
{
|
||||
Expression<Func<TestEntity, bool>> expr = e => !new[] { 100 }.Intersect(e.Scores).Any();
|
||||
Assert.Equal("e => (!new [] { 100 }.Intersect(e.Scores).Any())", _serializer.Serialize(expr));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Serializes_DoubleArrayInValueOposite()
|
||||
{
|
||||
Expression<Func<TestEntity, bool>> expr = e => new[] { 99.99 }.Intersect(e.Salaries).Any();
|
||||
Assert.Equal("e => new [] { 99.99 }.Intersect(e.Salaries).Any()", _serializer.Serialize(expr));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Serializes_FloatArrayInValueOposite()
|
||||
{
|
||||
Expression<Func<TestEntity, bool>> expr = e => new[] { 5.5f }.Intersect(e.Heights).Any();
|
||||
Assert.Equal("e => new [] { 5.5 }.Intersect(e.Heights).Any()", _serializer.Serialize(expr));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Serializes_DecimalArrayInValueOposite()
|
||||
{
|
||||
Expression<Func<TestEntity, bool>> expr = e => new[] { 1000.75m }.Intersect(e.Balances).Any();
|
||||
Assert.Equal("e => new [] { 1000.75 }.Intersect(e.Balances).Any()", _serializer.Serialize(expr));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Serializes_ShortArrayInValueOposite()
|
||||
{
|
||||
Expression<Func<TestEntity, bool>> expr = e => new [] { (short)3 }.Intersect(e.Levels).Any();
|
||||
Assert.Equal("e => new [] { 3 }.Intersect(e.Levels).Any()", _serializer.Serialize(expr));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Serializes_LongArrayInValueOposite()
|
||||
{
|
||||
Expression<Func<TestEntity, bool>> expr = e => new [] { 1000000L }.Intersect(e.Populations).Any();
|
||||
Assert.Equal("e => new [] { 1000000 }.Intersect(e.Populations).Any()", _serializer.Serialize(expr));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Serializes_StringArrayInValueOposite()
|
||||
{
|
||||
Expression<Func<TestEntity, bool>> expr = e => new[] { "Alice", "Bob" }.Intersect(e.Names).Any();
|
||||
Assert.Equal("e => (new [] { \"Alice\", \"Bob\" }).Intersect(e.Names).Any()", _serializer.Serialize(expr));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Serializes_GuidArrayInValueOposite()
|
||||
{
|
||||
Expression<Func<TestEntity, bool>> expr = e => new[] { Guid.Parse("12345678-1234-1234-1234-123456789abc") }.Intersect(e.Ids).Any();
|
||||
Assert.Equal("e => (new [] { Guid.Parse(\"12345678-1234-1234-1234-123456789abc\") }).Intersect(e.Ids).Any()", _serializer.Serialize(expr));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Serializes_DateTimeArrayInValueOposite()
|
||||
{
|
||||
Expression<Func<TestEntity, bool>> expr = e => new[] { DateTime.Parse("2023-01-01T00:00:00.000Z") }.Intersect(e.CreatedDates).Any();
|
||||
Assert.Equal("e => (new [] { DateTime.Parse(\"2023-01-01T00:00:00.000Z\") }).Intersect(e.CreatedDates).Any()", _serializer.Serialize(expr));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Serializes_DateTimeOffsetArrayInValueOposite()
|
||||
{
|
||||
Expression<Func<TestEntity, bool>> expr = e => new[] { DateTimeOffset.Parse("2023-01-01T10:30:00.000+00:00") }.Intersect(e.UpdatedDates).Any();
|
||||
Assert.Equal("e => (new [] { DateTimeOffset.Parse(\"2023-01-01T10:30:00.000+00:00\") }).Intersect(e.UpdatedDates).Any()", _serializer.Serialize(expr));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Serializes_TimeOnlyArrayInValueOposite()
|
||||
{
|
||||
Expression<Func<TestEntity, bool>> expr = e => new[] { TimeOnly.Parse("12:00:00") }.Intersect(e.StartTimes).Any();
|
||||
Assert.Equal("e => (new [] { TimeOnly.Parse(\"12:00:00\") }).Intersect(e.StartTimes).Any()", _serializer.Serialize(expr));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Serializes_DateOnlyArrayInValueOposite()
|
||||
{
|
||||
Expression<Func<TestEntity, bool>> expr = e => new[] { DateOnly.Parse("2000-01-01") }.Intersect(e.BirthDates).Any();
|
||||
Assert.Equal("e => (new [] { DateOnly.Parse(\"2000-01-01\") }).Intersect(e.BirthDates).Any()", _serializer.Serialize(expr));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Serializes_EnumArrayInValueOposite()
|
||||
{
|
||||
Expression<Func<TestEntity, bool>> expr = e => new[] { Status.Active, Status.Inactive }.Intersect(e.Statuses).Any();
|
||||
Assert.Equal("e => (new [] { (Radzen.Blazor.Tests.Status)0, (Radzen.Blazor.Tests.Status)1 }).Intersect(e.Statuses).Any()", _serializer.Serialize(expr));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Serializes_ListContainsValue()
|
||||
{
|
||||
Expression<Func<TestEntity, bool>> expr = e => e.Tags.Contains("VIP");
|
||||
Assert.Equal("e => e.Tags.Contains(\"VIP\")", _serializer.Serialize(expr));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Serializes_ListNotContainsValue()
|
||||
{
|
||||
Expression<Func<TestEntity, bool>> expr = e => !e.Tags.Contains("VIP");
|
||||
Assert.Equal("e => (!e.Tags.Contains(\"VIP\"))", _serializer.Serialize(expr));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Serializes_ListAnyCheck()
|
||||
{
|
||||
Expression<Func<TestEntity, bool>> expr = e => e.Children.Any(c => c.Age > 18);
|
||||
Assert.Equal("e => e.Children.Any(c => (c.Age > 18))", _serializer.Serialize(expr));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Serializes_ListNotAnyCheck()
|
||||
{
|
||||
Expression<Func<TestEntity, bool>> expr = e => !e.Children.Any(c => c.Age > 18);
|
||||
Assert.Equal("e => (!e.Children.Any(c => (c.Age > 18)))", _serializer.Serialize(expr));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Serializes_EntitySubPropertyCheck()
|
||||
{
|
||||
Expression<Func<TestEntity, bool>> expr = e => e.Address.City == "New York";
|
||||
Assert.Equal("e => (e.Address.City == \"New York\")", _serializer.Serialize(expr));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Serializes_ComplexExpressionWithProperties()
|
||||
{
|
||||
Expression<Func<TestEntity, bool>> expr = e => e.Age > 18 && e.Tags.Contains("Member") || e.Address.City == "London";
|
||||
Assert.Equal("e => (((e.Age > 18) && e.Tags.Contains(\"Member\")) || (e.Address.City == \"London\"))", _serializer.Serialize(expr));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -184,13 +184,13 @@ namespace Radzen.Blazor.Tests
|
||||
|
||||
Assert.Contains("SummaryContent", component.Markup);
|
||||
Assert.Equal(
|
||||
"",
|
||||
component.Find(".rz-fieldset-content-summary").ParentElement.Attributes.First(attr => attr.Name == "style").Value
|
||||
"false",
|
||||
component.Find(".rz-fieldset-content-summary").ParentElement.ParentElement.Attributes.First(attr => attr.Name == "aria-hidden").Value
|
||||
);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Fieldset_DontRenders_SummaryWhenOpen()
|
||||
public void Fieldset_DoesNotRender_SummaryWhenOpen()
|
||||
{
|
||||
using var ctx = new TestContext();
|
||||
var component = ctx.RenderComponent<RadzenFieldset>();
|
||||
@@ -210,8 +210,8 @@ namespace Radzen.Blazor.Tests
|
||||
|
||||
Assert.Contains("SummaryContent", component.Markup);
|
||||
Assert.Equal(
|
||||
"display: none",
|
||||
component.Find(".rz-fieldset-content-summary").ParentElement.Attributes.First(attr => attr.Name == "style").Value
|
||||
"true",
|
||||
component.Find(".rz-fieldset-content-summary").ParentElement.ParentElement.Attributes.First(attr => attr.Name == "aria-hidden").Value
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -198,14 +198,10 @@ namespace Radzen.Blazor.Tests
|
||||
});
|
||||
|
||||
Assert.Contains("SummaryContent", component.Markup);
|
||||
Assert.Equal(
|
||||
"display: block",
|
||||
component.Find(".rz-panel-content-summary").ParentElement.Attributes.First(attr => attr.Name == "style").Value
|
||||
);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Panel_DontRenders_SummaryWhenOpen()
|
||||
public void Panel_DoesNotRender_SummaryWhenOpen()
|
||||
{
|
||||
using var ctx = new TestContext();
|
||||
var component = ctx.RenderComponent<RadzenPanel>();
|
||||
@@ -225,8 +221,8 @@ namespace Radzen.Blazor.Tests
|
||||
|
||||
Assert.Contains("SummaryContent", component.Markup);
|
||||
Assert.Equal(
|
||||
"display: none",
|
||||
component.Find(".rz-panel-content-summary").ParentElement.Attributes.First(attr => attr.Name == "style").Value
|
||||
"true",
|
||||
component.Find(".rz-panel-content-summary").ParentElement.ParentElement.Attributes.First(attr => attr.Name == "aria-hidden").Value
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
56
Radzen.Blazor/DynamicTypeFactory.cs
Normal file
56
Radzen.Blazor/DynamicTypeFactory.cs
Normal file
@@ -0,0 +1,56 @@
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using System.Reflection.Emit;
|
||||
|
||||
static class DynamicTypeFactory
|
||||
{
|
||||
public static Type CreateType(string typeName, string[] propertyNames, Type[] propertyTypes)
|
||||
{
|
||||
if (propertyNames.Length != propertyTypes.Length)
|
||||
{
|
||||
throw new ArgumentException("Property names and types count mismatch.");
|
||||
}
|
||||
|
||||
var assemblyName = new AssemblyName("DynamicTypesAssembly");
|
||||
var assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run);
|
||||
var moduleBuilder = assemblyBuilder.DefineDynamicModule("DynamicTypesModule");
|
||||
|
||||
var typeBuilder = moduleBuilder.DefineType(typeName, TypeAttributes.Public | TypeAttributes.Class | TypeAttributes.Sealed);
|
||||
|
||||
for (int i = 0; i < propertyNames.Length; i++)
|
||||
{
|
||||
var fieldBuilder = typeBuilder.DefineField("_" + propertyNames[i], propertyTypes[i], FieldAttributes.Private);
|
||||
var propertyBuilder = typeBuilder.DefineProperty(propertyNames[i], PropertyAttributes.None, propertyTypes[i], null);
|
||||
|
||||
var getterMethod = typeBuilder.DefineMethod(
|
||||
"get_" + propertyNames[i],
|
||||
MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig,
|
||||
propertyTypes[i],
|
||||
Type.EmptyTypes);
|
||||
|
||||
var getterIl = getterMethod.GetILGenerator();
|
||||
getterIl.Emit(OpCodes.Ldarg_0);
|
||||
getterIl.Emit(OpCodes.Ldfld, fieldBuilder);
|
||||
getterIl.Emit(OpCodes.Ret);
|
||||
|
||||
propertyBuilder.SetGetMethod(getterMethod);
|
||||
|
||||
var setterMethod = typeBuilder.DefineMethod(
|
||||
"set_" + propertyNames[i],
|
||||
MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig,
|
||||
null,
|
||||
[propertyTypes[i]]);
|
||||
|
||||
var setterIl = setterMethod.GetILGenerator();
|
||||
setterIl.Emit(OpCodes.Ldarg_0);
|
||||
setterIl.Emit(OpCodes.Ldarg_1);
|
||||
setterIl.Emit(OpCodes.Stfld, fieldBuilder);
|
||||
setterIl.Emit(OpCodes.Ret);
|
||||
|
||||
propertyBuilder.SetSetMethod(setterMethod);
|
||||
}
|
||||
|
||||
var dynamicType = typeBuilder.CreateType();
|
||||
return dynamicType;
|
||||
}
|
||||
}
|
||||
873
Radzen.Blazor/ExpressionLexer.cs
Normal file
873
Radzen.Blazor/ExpressionLexer.cs
Normal file
@@ -0,0 +1,873 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Globalization;
|
||||
using System.Linq.Expressions;
|
||||
using System.Text;
|
||||
|
||||
namespace Radzen;
|
||||
|
||||
class Token
|
||||
{
|
||||
public TokenType Type { get; set; }
|
||||
public string Value { get; set; } = string.Empty;
|
||||
public ValueKind ValueKind { get; set; } = ValueKind.None;
|
||||
public int IntValue { get; internal set; }
|
||||
public uint UintValue { get; internal set; }
|
||||
public long LongValue { get; internal set; }
|
||||
public ulong UlongValue { get; internal set; }
|
||||
public decimal DecimalValue { get; internal set; }
|
||||
public float FloatValue { get; internal set; }
|
||||
public double DoubleValue { get; internal set; }
|
||||
|
||||
public Token(TokenType type)
|
||||
{
|
||||
Type = type;
|
||||
}
|
||||
|
||||
public Token(TokenType type, string value)
|
||||
{
|
||||
Type = type;
|
||||
Value = value;
|
||||
}
|
||||
|
||||
public ConstantExpression ToConstantExpression()
|
||||
{
|
||||
return ValueKind switch
|
||||
{
|
||||
ValueKind.Null => Expression.Constant(null),
|
||||
ValueKind.String => Expression.Constant(Value),
|
||||
ValueKind.Character => Expression.Constant(Value[0]),
|
||||
ValueKind.Int => Expression.Constant(IntValue),
|
||||
ValueKind.UInt => Expression.Constant(UintValue),
|
||||
ValueKind.Long => Expression.Constant(LongValue),
|
||||
ValueKind.ULong => Expression.Constant(UlongValue),
|
||||
ValueKind.Float => Expression.Constant(FloatValue),
|
||||
ValueKind.Double => Expression.Constant(DoubleValue),
|
||||
ValueKind.Decimal => Expression.Constant(DecimalValue),
|
||||
ValueKind.True => Expression.Constant(true),
|
||||
ValueKind.False => Expression.Constant(false),
|
||||
_ => throw new InvalidOperationException($"Unsupported value kind: {ValueKind}")
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
enum ValueKind
|
||||
{
|
||||
None,
|
||||
String,
|
||||
Int,
|
||||
Float,
|
||||
Double,
|
||||
Decimal,
|
||||
Character,
|
||||
Null,
|
||||
True,
|
||||
False,
|
||||
Long,
|
||||
UInt,
|
||||
ULong,
|
||||
}
|
||||
|
||||
|
||||
enum TokenType
|
||||
{
|
||||
None,
|
||||
Identifier,
|
||||
EqualsEquals,
|
||||
NotEquals,
|
||||
EqualsGreaterThan,
|
||||
StringLiteral,
|
||||
NumericLiteral,
|
||||
Dot,
|
||||
OpenParen,
|
||||
CloseParen,
|
||||
Comma,
|
||||
AmpersandAmpersand,
|
||||
Ampersand,
|
||||
BarBar,
|
||||
Bar,
|
||||
GreaterThan,
|
||||
LessThan,
|
||||
LessThanOrEqual,
|
||||
GreaterThanOrEqual,
|
||||
Plus,
|
||||
Minus,
|
||||
Star,
|
||||
Slash,
|
||||
CharacterLiteral,
|
||||
QuestionMark,
|
||||
QuestionMarkQuestionMark,
|
||||
Colon,
|
||||
QuestionDot,
|
||||
New,
|
||||
NullLiteral,
|
||||
TrueLiteral,
|
||||
FalseLiteral,
|
||||
OpenBracket,
|
||||
CloseBracket,
|
||||
OpenBrace,
|
||||
CloseBrace,
|
||||
ExclamationMark,
|
||||
Equals,
|
||||
Caret,
|
||||
GreaterThanGreaterThan,
|
||||
LessThanLessThan,
|
||||
}
|
||||
|
||||
static class TokenTypeExtensions
|
||||
{
|
||||
public static ExpressionType ToExpressionType(this TokenType tokenType)
|
||||
{
|
||||
return tokenType switch
|
||||
{
|
||||
TokenType.EqualsEquals => ExpressionType.Equal,
|
||||
TokenType.NotEquals => ExpressionType.NotEqual,
|
||||
TokenType.EqualsGreaterThan => ExpressionType.GreaterThanOrEqual,
|
||||
TokenType.AmpersandAmpersand => ExpressionType.AndAlso,
|
||||
TokenType.Ampersand => ExpressionType.And,
|
||||
TokenType.BarBar => ExpressionType.OrElse,
|
||||
TokenType.Bar => ExpressionType.Or,
|
||||
TokenType.GreaterThan => ExpressionType.GreaterThan,
|
||||
TokenType.LessThan => ExpressionType.LessThan,
|
||||
TokenType.LessThanOrEqual => ExpressionType.LessThanOrEqual,
|
||||
TokenType.GreaterThanOrEqual => ExpressionType.GreaterThanOrEqual,
|
||||
TokenType.Plus => ExpressionType.Add,
|
||||
TokenType.Minus => ExpressionType.Subtract,
|
||||
TokenType.Star => ExpressionType.Multiply,
|
||||
TokenType.Slash => ExpressionType.Divide,
|
||||
TokenType.Caret => ExpressionType.ExclusiveOr,
|
||||
TokenType.GreaterThanGreaterThan => ExpressionType.RightShift,
|
||||
TokenType.LessThanLessThan => ExpressionType.LeftShift,
|
||||
_ => throw new InvalidOperationException($"Unsupported token type: {tokenType}")
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
class ExpressionLexer(string expression)
|
||||
{
|
||||
private int position;
|
||||
|
||||
private char Peek(int offset = 0)
|
||||
{
|
||||
if (position + offset >= expression.Length)
|
||||
{
|
||||
return '\0';
|
||||
}
|
||||
|
||||
return expression[position + offset];
|
||||
}
|
||||
|
||||
private void Advance(int count)
|
||||
{
|
||||
position += count;
|
||||
}
|
||||
|
||||
bool TryAdvance(char expected)
|
||||
{
|
||||
if (Peek(1) == expected)
|
||||
{
|
||||
Advance(1);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private void ScanTrivia()
|
||||
{
|
||||
while (char.IsWhiteSpace(Peek()))
|
||||
{
|
||||
Advance(1);
|
||||
}
|
||||
}
|
||||
|
||||
public static List<Token> Scan(string expression)
|
||||
{
|
||||
var lexer = new ExpressionLexer(expression);
|
||||
|
||||
return [.. lexer.Scan()];
|
||||
}
|
||||
|
||||
public IEnumerable<Token> Scan()
|
||||
{
|
||||
while (position < expression.Length)
|
||||
{
|
||||
ScanTrivia();
|
||||
|
||||
var token = ScanToken();
|
||||
|
||||
if (token.Type == TokenType.None)
|
||||
{
|
||||
yield break;
|
||||
}
|
||||
|
||||
yield return token;
|
||||
}
|
||||
|
||||
yield return new Token(TokenType.None, string.Empty);
|
||||
}
|
||||
|
||||
private Token ScanToken()
|
||||
{
|
||||
var ch = Peek();
|
||||
|
||||
switch (ch)
|
||||
{
|
||||
case '"':
|
||||
return ScanStringLiteral();
|
||||
case '\'':
|
||||
return ScanCharacterLiteral();
|
||||
case '=':
|
||||
if (TryAdvance('='))
|
||||
{
|
||||
Advance(1);
|
||||
return new Token(TokenType.EqualsEquals);
|
||||
}
|
||||
|
||||
if (TryAdvance('>'))
|
||||
{
|
||||
Advance(1);
|
||||
return new Token(TokenType.EqualsGreaterThan);
|
||||
}
|
||||
|
||||
Advance(1);
|
||||
return new Token(TokenType.Equals);
|
||||
case '!':
|
||||
if (TryAdvance('='))
|
||||
{
|
||||
Advance(1);
|
||||
return new Token(TokenType.NotEquals);
|
||||
}
|
||||
Advance(1);
|
||||
return new Token(TokenType.ExclamationMark);
|
||||
case '>':
|
||||
if (TryAdvance('='))
|
||||
{
|
||||
Advance(1);
|
||||
return new Token(TokenType.GreaterThanOrEqual);
|
||||
}
|
||||
if (TryAdvance('>'))
|
||||
{
|
||||
Advance(1);
|
||||
return new Token(TokenType.GreaterThanGreaterThan);
|
||||
}
|
||||
Advance(1);
|
||||
return new Token(TokenType.GreaterThan);
|
||||
case '<':
|
||||
if (TryAdvance('<'))
|
||||
{
|
||||
Advance(1);
|
||||
return new Token(TokenType.LessThanLessThan);
|
||||
}
|
||||
if (TryAdvance('='))
|
||||
{
|
||||
Advance(1);
|
||||
return new Token(TokenType.LessThanOrEqual);
|
||||
}
|
||||
Advance(1);
|
||||
return new Token(TokenType.LessThan);
|
||||
case '+':
|
||||
Advance(1);
|
||||
return new Token(TokenType.Plus);
|
||||
case '-':
|
||||
Advance(1);
|
||||
return new Token(TokenType.Minus);
|
||||
case '*':
|
||||
Advance(1);
|
||||
return new Token(TokenType.Star);
|
||||
case '/':
|
||||
Advance(1);
|
||||
return new Token(TokenType.Slash);
|
||||
case '.':
|
||||
Advance(1);
|
||||
return new Token(TokenType.Dot);
|
||||
case '(':
|
||||
Advance(1);
|
||||
return new Token(TokenType.OpenParen);
|
||||
case ')':
|
||||
Advance(1);
|
||||
return new Token(TokenType.CloseParen);
|
||||
case '[':
|
||||
Advance(1);
|
||||
return new Token(TokenType.OpenBracket);
|
||||
case ']':
|
||||
Advance(1);
|
||||
return new Token(TokenType.CloseBracket);
|
||||
case '{':
|
||||
Advance(1);
|
||||
return new Token(TokenType.OpenBrace);
|
||||
case '}':
|
||||
Advance(1);
|
||||
return new Token(TokenType.CloseBrace);
|
||||
case ',':
|
||||
Advance(1);
|
||||
return new Token(TokenType.Comma);
|
||||
case '&':
|
||||
if (TryAdvance('&'))
|
||||
{
|
||||
Advance(1);
|
||||
return new Token(TokenType.AmpersandAmpersand);
|
||||
}
|
||||
Advance(1);
|
||||
return new Token(TokenType.Ampersand);
|
||||
case '|':
|
||||
if (TryAdvance('|'))
|
||||
{
|
||||
Advance(1);
|
||||
return new Token(TokenType.BarBar);
|
||||
}
|
||||
Advance(1);
|
||||
return new Token(TokenType.Bar);
|
||||
case '?':
|
||||
if (TryAdvance('.'))
|
||||
{
|
||||
Advance(1);
|
||||
return new Token(TokenType.QuestionDot);
|
||||
}
|
||||
|
||||
if (TryAdvance('?'))
|
||||
{
|
||||
Advance(1);
|
||||
return new Token(TokenType.QuestionMarkQuestionMark);
|
||||
}
|
||||
|
||||
Advance(1);
|
||||
return new Token(TokenType.QuestionMark);
|
||||
case ':':
|
||||
Advance(1);
|
||||
return new Token(TokenType.Colon);
|
||||
case '^':
|
||||
Advance(1);
|
||||
return new Token(TokenType.Caret);
|
||||
case >= '0' and <= '9':
|
||||
return ScanNumericLiteral();
|
||||
case '_':
|
||||
case (>= 'a' and <= 'z') or (>= 'A' and <= 'Z'):
|
||||
var token = ScanIdentifier();
|
||||
|
||||
return token.Value switch
|
||||
{
|
||||
"null" => new Token(TokenType.NullLiteral) { ValueKind = ValueKind.Null },
|
||||
"true" => new Token(TokenType.TrueLiteral) { ValueKind = ValueKind.True },
|
||||
"false" => new Token(TokenType.FalseLiteral) { ValueKind = ValueKind.False },
|
||||
"new" => new Token(TokenType.New),
|
||||
_ => token
|
||||
};
|
||||
}
|
||||
|
||||
return new Token(TokenType.None, string.Empty);
|
||||
}
|
||||
|
||||
private char ScanEscapeSequence()
|
||||
{
|
||||
var ch = Peek();
|
||||
|
||||
Advance(1);
|
||||
|
||||
switch (ch)
|
||||
{
|
||||
case '\'':
|
||||
case '"':
|
||||
case '\\':
|
||||
break;
|
||||
case '0':
|
||||
ch = '\u0000';
|
||||
break;
|
||||
case 'a':
|
||||
ch = '\u0007';
|
||||
break;
|
||||
case 'b':
|
||||
ch = '\u0008';
|
||||
break;
|
||||
case 'f':
|
||||
ch = '\u000c';
|
||||
break;
|
||||
case 'n':
|
||||
ch = '\u000a';
|
||||
break;
|
||||
case 'r':
|
||||
ch = '\u000d';
|
||||
break;
|
||||
case 't':
|
||||
ch = '\u0009';
|
||||
break;
|
||||
case 'v':
|
||||
ch = '\u000b';
|
||||
break;
|
||||
case 'u':
|
||||
case 'U':
|
||||
case 'x':
|
||||
ch = ScanUnicodeEscapeSequence(ch);
|
||||
break;
|
||||
default:
|
||||
throw new InvalidOperationException($"Invalid escape sequence '\\{ch}' at position {position}.");
|
||||
}
|
||||
|
||||
return ch;
|
||||
}
|
||||
|
||||
private char ScanUnicodeEscapeSequence(char ch)
|
||||
{
|
||||
var value = 0;
|
||||
|
||||
var count = ch == 'U' ? 8 : 4;
|
||||
|
||||
for (var i = 0; i < count; i++)
|
||||
{
|
||||
var digit = Peek();
|
||||
|
||||
int digitValue;
|
||||
|
||||
if (digit >= '0' && digit <= '9')
|
||||
{
|
||||
digitValue = digit - '0';
|
||||
}
|
||||
else if (digit >= 'a' && digit <= 'f')
|
||||
{
|
||||
digitValue = digit - 'a' + 10;
|
||||
}
|
||||
else if (digit >= 'A' && digit <= 'F')
|
||||
{
|
||||
digitValue = digit - 'A' + 10;
|
||||
}
|
||||
else if (ch != 'x')
|
||||
{
|
||||
throw new InvalidOperationException($"Invalid unicode escape sequence at position {position}.");
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
value = (value << 4) + digitValue;
|
||||
|
||||
Advance(1);
|
||||
}
|
||||
|
||||
return (char)value;
|
||||
}
|
||||
|
||||
private Token ScanCharacterLiteral()
|
||||
{
|
||||
Advance(1);
|
||||
|
||||
var buffer = new StringBuilder();
|
||||
|
||||
while (true)
|
||||
{
|
||||
var ch = Peek();
|
||||
|
||||
switch (ch)
|
||||
{
|
||||
case '\0':
|
||||
throw new InvalidOperationException($"Unexpected end of character literal at position {position}.");
|
||||
case '\\':
|
||||
Advance(1);
|
||||
buffer.Append(ScanEscapeSequence());
|
||||
break;
|
||||
case '\'':
|
||||
Advance(1);
|
||||
|
||||
return new Token(TokenType.CharacterLiteral, buffer.ToString())
|
||||
{
|
||||
ValueKind = ValueKind.Character
|
||||
};
|
||||
default:
|
||||
if (buffer.Length > 0)
|
||||
{
|
||||
throw new InvalidOperationException($"Too many characters in character literal at position {position}.");
|
||||
}
|
||||
|
||||
buffer.Append(ch);
|
||||
Advance(1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Token ScanStringLiteral()
|
||||
{
|
||||
Advance(1);
|
||||
|
||||
var buffer = new StringBuilder();
|
||||
|
||||
while (true)
|
||||
{
|
||||
var ch = Peek();
|
||||
|
||||
switch (ch)
|
||||
{
|
||||
case '\0':
|
||||
throw new InvalidOperationException($"Unexpected end of string literal at position {position}.");
|
||||
case '\\':
|
||||
Advance(1);
|
||||
buffer.Append(ScanEscapeSequence());
|
||||
break;
|
||||
case '"':
|
||||
Advance(1);
|
||||
return new Token(TokenType.StringLiteral, buffer.ToString())
|
||||
{
|
||||
ValueKind = ValueKind.String
|
||||
};
|
||||
default:
|
||||
buffer.Append(ch);
|
||||
Advance(1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Token ScanNumericLiteral()
|
||||
{
|
||||
var buffer = new StringBuilder();
|
||||
var hasDecimal = false;
|
||||
var hasFSuffix = false;
|
||||
var hasDSuffix = false;
|
||||
var hasMSuffix = false;
|
||||
var hasLSuffix = false;
|
||||
var hasExponent = false;
|
||||
var hasHex = false;
|
||||
var hasUSuffix = false;
|
||||
|
||||
while (true)
|
||||
{
|
||||
var ch = Peek();
|
||||
|
||||
if (ch == '0')
|
||||
{
|
||||
var next = Peek(1);
|
||||
|
||||
if (next == 'x' || next == 'X')
|
||||
{
|
||||
hasHex = true;
|
||||
Advance(2);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (ch >= '0' && ch <= '9')
|
||||
{
|
||||
buffer.Append(ch);
|
||||
Advance(1);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ch == '.')
|
||||
{
|
||||
if (hasDecimal)
|
||||
{
|
||||
throw new InvalidOperationException($"Unexpected character '{ch}' at position {position}.");
|
||||
}
|
||||
|
||||
hasDecimal = true;
|
||||
|
||||
buffer.Append(ch);
|
||||
|
||||
Advance(1);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ch == 'l' || ch == 'L')
|
||||
{
|
||||
if (hasLSuffix)
|
||||
{
|
||||
throw new InvalidOperationException($"Unexpected character '{ch}' at position {position}.");
|
||||
}
|
||||
|
||||
hasLSuffix = true;
|
||||
|
||||
Advance(1);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ch == 'u' || ch == 'U')
|
||||
{
|
||||
if (hasUSuffix)
|
||||
{
|
||||
throw new InvalidOperationException($"Unexpected character '{ch}' at position {position}.");
|
||||
}
|
||||
|
||||
hasUSuffix = true;
|
||||
|
||||
Advance(1);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (hasHex && ((ch >= 'a' && ch <= 'f') || (ch >= 'A' && ch <= 'F')))
|
||||
{
|
||||
buffer.Append(ch);
|
||||
Advance(1);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ch == 'e' || ch == 'E')
|
||||
{
|
||||
if (hasExponent)
|
||||
{
|
||||
throw new InvalidOperationException($"Unexpected character '{ch}' at position {position}.");
|
||||
}
|
||||
|
||||
hasExponent = true;
|
||||
buffer.Append(ch);
|
||||
Advance(1);
|
||||
|
||||
// Check for optional + or - after e/E
|
||||
ch = Peek();
|
||||
if (ch == '+' || ch == '-')
|
||||
{
|
||||
buffer.Append(ch);
|
||||
Advance(1);
|
||||
}
|
||||
|
||||
// Must have at least one digit after e/E
|
||||
ch = Peek();
|
||||
|
||||
if (ch < '0' || ch > '9')
|
||||
{
|
||||
throw new InvalidOperationException($"Expected digit after exponent at position {position}.");
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (hasDecimal || hasExponent)
|
||||
{
|
||||
switch (ch)
|
||||
{
|
||||
case 'F':
|
||||
case 'f':
|
||||
hasFSuffix = true;
|
||||
Advance(1);
|
||||
break;
|
||||
case 'D':
|
||||
case 'd':
|
||||
hasDSuffix = true;
|
||||
Advance(1);
|
||||
break;
|
||||
case 'M':
|
||||
case 'm':
|
||||
hasMSuffix = true;
|
||||
Advance(1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
var value = new Token(TokenType.NumericLiteral);
|
||||
|
||||
var valueKind = ValueKind.None;
|
||||
|
||||
if (hasDecimal || hasExponent)
|
||||
{
|
||||
valueKind = ValueKind.Double;
|
||||
}
|
||||
|
||||
if (hasFSuffix)
|
||||
{
|
||||
valueKind = ValueKind.Float;
|
||||
}
|
||||
|
||||
if (hasDSuffix)
|
||||
{
|
||||
valueKind = ValueKind.Double;
|
||||
}
|
||||
|
||||
if (hasMSuffix)
|
||||
{
|
||||
valueKind = ValueKind.Decimal;
|
||||
}
|
||||
|
||||
switch (valueKind)
|
||||
{
|
||||
case ValueKind.Float:
|
||||
value.ValueKind = ValueKind.Float;
|
||||
value.FloatValue = GetValueFloat(buffer.ToString());
|
||||
break;
|
||||
case ValueKind.Double:
|
||||
value.ValueKind = ValueKind.Double;
|
||||
value.DoubleValue = GetValueDouble(buffer.ToString());
|
||||
break;
|
||||
case ValueKind.Decimal:
|
||||
value.ValueKind = ValueKind.Decimal;
|
||||
value.DecimalValue = GetValueDecimal(buffer.ToString());
|
||||
break;
|
||||
default:
|
||||
var val = GetValueUInt64(buffer.ToString(), hasHex);
|
||||
|
||||
if (!hasUSuffix && !hasLSuffix)
|
||||
{
|
||||
if (val <= Int32.MaxValue)
|
||||
{
|
||||
value.ValueKind = ValueKind.Int;
|
||||
value.IntValue = (int)val;
|
||||
}
|
||||
else if (val <= UInt32.MaxValue)
|
||||
{
|
||||
value.ValueKind = ValueKind.UInt;
|
||||
value.UintValue = (uint)val;
|
||||
}
|
||||
else if (val <= Int64.MaxValue)
|
||||
{
|
||||
value.ValueKind = ValueKind.Long;
|
||||
value.LongValue = (long)val;
|
||||
}
|
||||
else
|
||||
{
|
||||
value.ValueKind = ValueKind.ULong;
|
||||
value.UlongValue = val;
|
||||
}
|
||||
}
|
||||
else if (hasUSuffix && !hasLSuffix)
|
||||
{
|
||||
if (val <= UInt32.MaxValue)
|
||||
{
|
||||
value.ValueKind = ValueKind.UInt;
|
||||
value.UintValue = (uint)val;
|
||||
}
|
||||
else
|
||||
{
|
||||
value.ValueKind = ValueKind.ULong;
|
||||
value.UlongValue = val;
|
||||
}
|
||||
}
|
||||
else if (!hasUSuffix & hasLSuffix)
|
||||
{
|
||||
if (val <= Int64.MaxValue)
|
||||
{
|
||||
value.ValueKind = ValueKind.Long;
|
||||
value.LongValue = (long)val;
|
||||
}
|
||||
else
|
||||
{
|
||||
value.ValueKind = ValueKind.ULong;
|
||||
value.UlongValue = val;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
value.ValueKind = ValueKind.ULong;
|
||||
value.UlongValue = val;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
private static decimal GetValueDecimal(string text)
|
||||
{
|
||||
if (!decimal.TryParse(text, NumberStyles.AllowDecimalPoint | NumberStyles.AllowExponent, CultureInfo.InvariantCulture, out var result))
|
||||
{
|
||||
throw new InvalidOperationException($"Invalid numeric literal: {text}");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private static float GetValueFloat(string text)
|
||||
{
|
||||
if (!float.TryParse(text, NumberStyles.AllowDecimalPoint | NumberStyles.AllowExponent, CultureInfo.InvariantCulture, out var result))
|
||||
{
|
||||
throw new InvalidOperationException($"Invalid numeric literal: {text}");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private static double GetValueDouble(string text)
|
||||
{
|
||||
if (!double.TryParse(text, NumberStyles.AllowDecimalPoint | NumberStyles.AllowExponent, CultureInfo.InvariantCulture, out var result))
|
||||
{
|
||||
throw new InvalidOperationException($"Invalid numeric literal: {text}");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private static ulong GetValueUInt64(string text, bool isHex)
|
||||
{
|
||||
if (!UInt64.TryParse(text, isHex ? NumberStyles.AllowHexSpecifier : NumberStyles.None, CultureInfo.InvariantCulture, out var result))
|
||||
{
|
||||
throw new InvalidOperationException($"Invalid numeric literal: {text}");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private Token ScanIdentifier()
|
||||
{
|
||||
var startOffset = position;
|
||||
|
||||
while (true)
|
||||
{
|
||||
if (position == expression.Length)
|
||||
{
|
||||
var length = position - startOffset;
|
||||
|
||||
return new Token(TokenType.Identifier, expression.Substring(startOffset, length));
|
||||
}
|
||||
|
||||
switch (Peek())
|
||||
{
|
||||
case '\0':
|
||||
case ' ':
|
||||
case '\r':
|
||||
case '\n':
|
||||
case '\t':
|
||||
case '!':
|
||||
case '%':
|
||||
case '(':
|
||||
case ')':
|
||||
case '*':
|
||||
case '+':
|
||||
case ',':
|
||||
case '-':
|
||||
case '.':
|
||||
case '/':
|
||||
case ':':
|
||||
case ';':
|
||||
case '<':
|
||||
case '=':
|
||||
case '>':
|
||||
case '?':
|
||||
case '[':
|
||||
case ']':
|
||||
case '^':
|
||||
case '{':
|
||||
case '|':
|
||||
case '}':
|
||||
case '~':
|
||||
case '"':
|
||||
case '\'':
|
||||
// All of the following characters are not valid in an
|
||||
// identifier. If we see any of them, then we know we're
|
||||
// done.
|
||||
return new Token(TokenType.Identifier, expression[startOffset..position]);
|
||||
case >= '0' and <= '9':
|
||||
if (position == startOffset)
|
||||
{
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
goto case '_';
|
||||
}
|
||||
case (>= 'a' and <= 'z') or (>= 'A' and <= 'Z'):
|
||||
case '_':
|
||||
// All of these characters are valid inside an identifier.
|
||||
// consume it and keep processing.
|
||||
Advance(1);
|
||||
continue;
|
||||
|
||||
default:
|
||||
throw new InvalidOperationException($"Unexpected character '{Peek()}' at position {position}.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
462
Radzen.Blazor/ExpressionSerializer.cs
Normal file
462
Radzen.Blazor/ExpressionSerializer.cs
Normal file
@@ -0,0 +1,462 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Text;
|
||||
|
||||
/// <summary>
|
||||
/// Serializes LINQ Expression Trees into C# string representations.
|
||||
/// </summary>
|
||||
public class ExpressionSerializer : ExpressionVisitor
|
||||
{
|
||||
private readonly StringBuilder _sb = new StringBuilder();
|
||||
|
||||
/// <summary>
|
||||
/// Serializes a given LINQ Expression into a C# string.
|
||||
/// </summary>
|
||||
/// <param name="expression">The expression to serialize.</param>
|
||||
/// <returns>A string representation of the expression.</returns>
|
||||
public string Serialize(Expression expression)
|
||||
{
|
||||
_sb.Clear();
|
||||
Visit(expression);
|
||||
return _sb.ToString();
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override Expression VisitLambda<T>(Expression<T> node)
|
||||
{
|
||||
if (node.Parameters.Count > 1)
|
||||
{
|
||||
_sb.Append("(");
|
||||
for (int i = 0; i < node.Parameters.Count; i++)
|
||||
{
|
||||
if (i > 0) _sb.Append(", ");
|
||||
_sb.Append(node.Parameters[i].Name);
|
||||
}
|
||||
_sb.Append(") => ");
|
||||
}
|
||||
else
|
||||
{
|
||||
_sb.Append(node.Parameters[0].Name);
|
||||
_sb.Append(" => ");
|
||||
}
|
||||
Visit(node.Body);
|
||||
return node;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override Expression VisitParameter(ParameterExpression node)
|
||||
{
|
||||
_sb.Append(node.Name);
|
||||
return node;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override Expression VisitMember(MemberExpression node)
|
||||
{
|
||||
if (node.Expression != null)
|
||||
{
|
||||
Visit(node.Expression);
|
||||
_sb.Append($".{node.Member.Name}");
|
||||
}
|
||||
else
|
||||
{
|
||||
_sb.Append(node.Member.Name);
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override Expression VisitMethodCall(MethodCallExpression node)
|
||||
{
|
||||
if (node.Method.IsStatic && node.Arguments.Count > 0 &&
|
||||
(node.Method.DeclaringType == typeof(Enumerable) ||
|
||||
node.Method.DeclaringType == typeof(Queryable)))
|
||||
{
|
||||
Visit(node.Arguments[0]);
|
||||
_sb.Append($".{node.Method.Name}(");
|
||||
|
||||
for (int i = 1; i < node.Arguments.Count; i++)
|
||||
{
|
||||
if (i > 1) _sb.Append(", ");
|
||||
|
||||
if (node.Arguments[i] is NewArrayExpression arrayExpr)
|
||||
{
|
||||
VisitNewArray(arrayExpr);
|
||||
}
|
||||
else
|
||||
{
|
||||
Visit(node.Arguments[i]);
|
||||
}
|
||||
}
|
||||
|
||||
_sb.Append(")");
|
||||
}
|
||||
else if (node.Method.IsStatic)
|
||||
{
|
||||
_sb.Append($"{node.Method.DeclaringType.Name}.{node.Method.Name}(");
|
||||
|
||||
for (int i = 0; i < node.Arguments.Count; i++)
|
||||
{
|
||||
if (i > 0) _sb.Append(", ");
|
||||
Visit(node.Arguments[i]);
|
||||
}
|
||||
|
||||
_sb.Append(")");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (node.Object != null)
|
||||
{
|
||||
Visit(node.Object);
|
||||
_sb.Append($".{node.Method.Name}(");
|
||||
}
|
||||
else
|
||||
{
|
||||
_sb.Append($"{node.Method.Name}(");
|
||||
}
|
||||
|
||||
for (int i = 0; i < node.Arguments.Count; i++)
|
||||
{
|
||||
if (i > 0) _sb.Append(", ");
|
||||
Visit(node.Arguments[i]);
|
||||
}
|
||||
|
||||
_sb.Append(")");
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override Expression VisitUnary(UnaryExpression node)
|
||||
{
|
||||
if (node.NodeType == ExpressionType.Not)
|
||||
{
|
||||
_sb.Append("(!");
|
||||
Visit(node.Operand);
|
||||
_sb.Append(")");
|
||||
}
|
||||
else if (node.NodeType == ExpressionType.Convert)
|
||||
{
|
||||
if (node.Operand is IndexExpression indexExpr)
|
||||
{
|
||||
_sb.Append($"({node.Type.DisplayName(true).Replace("+",".")})");
|
||||
|
||||
Visit(indexExpr.Object);
|
||||
|
||||
_sb.Append("[");
|
||||
Visit(indexExpr.Arguments[0]);
|
||||
_sb.Append("]");
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
Visit(node.Operand);
|
||||
}
|
||||
else
|
||||
{
|
||||
_sb.Append(node.NodeType switch
|
||||
{
|
||||
ExpressionType.Negate => "-",
|
||||
ExpressionType.UnaryPlus => "+",
|
||||
_ => throw new NotSupportedException($"Unsupported unary operator: {node.NodeType}")
|
||||
});
|
||||
Visit(node.Operand);
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override Expression VisitConstant(ConstantExpression node)
|
||||
{
|
||||
_sb.Append(FormatValue(node.Value));
|
||||
return node;
|
||||
}
|
||||
|
||||
private string FormatValue(object value)
|
||||
{
|
||||
if (value == null)
|
||||
return "null";
|
||||
|
||||
return value switch
|
||||
{
|
||||
string str => $"\"{str}\"",
|
||||
char c => $"'{c}'",
|
||||
bool b => b.ToString().ToLowerInvariant(),
|
||||
DateTime dt => $"DateTime.Parse(\"{dt.ToString("yyyy-MM-ddTHH:mm:ss.fffZ", CultureInfo.InvariantCulture)}\", CultureInfo.InvariantCulture)",
|
||||
DateOnly dateOnly => $"DateOnly.Parse(\"{dateOnly.ToString("yyyy-MM-dd", CultureInfo.InvariantCulture)}\", CultureInfo.InvariantCulture)",
|
||||
TimeOnly timeOnly => $"TimeOnly.Parse(\"{timeOnly.ToString("HH:mm:ss", CultureInfo.InvariantCulture)}\", CultureInfo.InvariantCulture)",
|
||||
Guid guid => $"Guid.Parse(\"{guid.ToString("D", CultureInfo.InvariantCulture)}\")",
|
||||
IEnumerable enumerable when value is not string => FormatEnumerable(enumerable),
|
||||
_ => value.GetType().IsEnum
|
||||
? $"({value.GetType().FullName.Replace("+", ".")})" + Convert.ChangeType(value, Enum.GetUnderlyingType(value.GetType()), CultureInfo.InvariantCulture).ToString()
|
||||
: Convert.ToString(value, CultureInfo.InvariantCulture)
|
||||
};
|
||||
}
|
||||
|
||||
private string FormatEnumerable(IEnumerable enumerable)
|
||||
{
|
||||
var arrayType = enumerable.AsQueryable().ElementType;
|
||||
|
||||
var items = enumerable.Cast<object>().Select(FormatValue);
|
||||
return $"new {(Nullable.GetUnderlyingType(arrayType) != null ? arrayType.DisplayName(true).Replace("+", ".") : "")}[] {{ {string.Join(", ", items)} }}";
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override Expression VisitNewArray(NewArrayExpression node)
|
||||
{
|
||||
bool needsParentheses = node.NodeType == ExpressionType.NewArrayInit &&
|
||||
(node.Expressions.Count > 1 || node.Expressions[0].NodeType != ExpressionType.Constant);
|
||||
|
||||
if (needsParentheses) _sb.Append("(");
|
||||
|
||||
_sb.Append("new [] { ");
|
||||
bool first = true;
|
||||
foreach (var expr in node.Expressions)
|
||||
{
|
||||
if (!first) _sb.Append(", ");
|
||||
first = false;
|
||||
Visit(expr);
|
||||
}
|
||||
_sb.Append(" }");
|
||||
|
||||
if (needsParentheses) _sb.Append(")");
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override Expression VisitBinary(BinaryExpression node)
|
||||
{
|
||||
_sb.Append("(");
|
||||
Visit(node.Left);
|
||||
_sb.Append($" {GetOperator(node.NodeType)} ");
|
||||
Visit(node.Right);
|
||||
_sb.Append(")");
|
||||
return node;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override Expression VisitConditional(ConditionalExpression node)
|
||||
{
|
||||
_sb.Append("(");
|
||||
Visit(node.Test);
|
||||
_sb.Append(" ? ");
|
||||
Visit(node.IfTrue);
|
||||
_sb.Append(" : ");
|
||||
Visit(node.IfFalse);
|
||||
_sb.Append(")");
|
||||
return node;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Maps an ExpressionType to its corresponding C# operator.
|
||||
/// </summary>
|
||||
/// <param name="type">The ExpressionType to map.</param>
|
||||
/// <returns>A string representation of the corresponding C# operator.</returns>
|
||||
private static string GetOperator(ExpressionType type)
|
||||
{
|
||||
return type switch
|
||||
{
|
||||
ExpressionType.Add => "+",
|
||||
ExpressionType.Subtract => "-",
|
||||
ExpressionType.Multiply => "*",
|
||||
ExpressionType.Divide => "/",
|
||||
ExpressionType.AndAlso => "&&",
|
||||
ExpressionType.OrElse => "||",
|
||||
ExpressionType.Equal => "==",
|
||||
ExpressionType.NotEqual => "!=",
|
||||
ExpressionType.LessThan => "<",
|
||||
ExpressionType.LessThanOrEqual => "<=",
|
||||
ExpressionType.GreaterThan => ">",
|
||||
ExpressionType.GreaterThanOrEqual => ">=",
|
||||
ExpressionType.Coalesce => "??",
|
||||
_ => throw new NotSupportedException($"Unsupported operator: {type}")
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Provides an extension method for displaying type names.
|
||||
/// </summary>
|
||||
public static class SharedTypeExtensions
|
||||
{
|
||||
private static readonly Dictionary<Type, string> BuiltInTypeNames = new()
|
||||
{
|
||||
{ typeof(bool), "bool" },
|
||||
{ typeof(byte), "byte" },
|
||||
{ typeof(char), "char" },
|
||||
{ typeof(decimal), "decimal" },
|
||||
{ typeof(double), "double" },
|
||||
{ typeof(float), "float" },
|
||||
{ typeof(int), "int" },
|
||||
{ typeof(long), "long" },
|
||||
{ typeof(object), "object" },
|
||||
{ typeof(sbyte), "sbyte" },
|
||||
{ typeof(short), "short" },
|
||||
{ typeof(string), "string" },
|
||||
{ typeof(uint), "uint" },
|
||||
{ typeof(ulong), "ulong" },
|
||||
{ typeof(ushort), "ushort" },
|
||||
{ typeof(void), "void" }
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Unwraps nullable type.
|
||||
/// </summary>
|
||||
public static Type UnwrapNullableType(this Type type)
|
||||
=> Nullable.GetUnderlyingType(type) ?? type;
|
||||
|
||||
/// <summary>
|
||||
/// Returns a display name for the given type.
|
||||
/// </summary>
|
||||
/// <param name="type">The type to display.</param>
|
||||
/// <param name="fullName">Indicates whether to use the full name.</param>
|
||||
/// <param name="compilable">Indicates whether to use a compilable format.</param>
|
||||
/// <returns>A string representing the type name.</returns>
|
||||
public static string DisplayName(this Type type, bool fullName = true, bool compilable = false)
|
||||
{
|
||||
var stringBuilder = new StringBuilder();
|
||||
ProcessType(stringBuilder, type, fullName, compilable);
|
||||
return stringBuilder.ToString();
|
||||
}
|
||||
|
||||
private static void ProcessType(StringBuilder builder, Type type, bool fullName, bool compilable)
|
||||
{
|
||||
if (type.IsGenericType)
|
||||
{
|
||||
var genericArguments = type.GetGenericArguments();
|
||||
ProcessGenericType(builder, type, genericArguments, genericArguments.Length, fullName, compilable);
|
||||
}
|
||||
else if (type.IsArray)
|
||||
{
|
||||
ProcessArrayType(builder, type, fullName, compilable);
|
||||
}
|
||||
else if (BuiltInTypeNames.TryGetValue(type, out var builtInName))
|
||||
{
|
||||
builder.Append(builtInName);
|
||||
}
|
||||
else if (!type.IsGenericParameter)
|
||||
{
|
||||
if (compilable)
|
||||
{
|
||||
if (type.IsNested)
|
||||
{
|
||||
ProcessType(builder, type.DeclaringType!, fullName, compilable);
|
||||
builder.Append('.');
|
||||
}
|
||||
else if (fullName)
|
||||
{
|
||||
builder.Append(type.Namespace).Append('.');
|
||||
}
|
||||
|
||||
builder.Append(type.Name);
|
||||
}
|
||||
else
|
||||
{
|
||||
builder.Append(fullName ? type.FullName : type.Name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void ProcessArrayType(StringBuilder builder, Type type, bool fullName, bool compilable)
|
||||
{
|
||||
var innerType = type;
|
||||
while (innerType.IsArray)
|
||||
{
|
||||
innerType = innerType.GetElementType()!;
|
||||
}
|
||||
|
||||
ProcessType(builder, innerType, fullName, compilable);
|
||||
|
||||
while (type.IsArray)
|
||||
{
|
||||
builder.Append('[');
|
||||
builder.Append(',', type.GetArrayRank() - 1);
|
||||
builder.Append(']');
|
||||
type = type.GetElementType()!;
|
||||
}
|
||||
}
|
||||
|
||||
private static void ProcessGenericType(
|
||||
StringBuilder builder,
|
||||
Type type,
|
||||
Type[] genericArguments,
|
||||
int length,
|
||||
bool fullName,
|
||||
bool compilable)
|
||||
{
|
||||
if (type.IsConstructedGenericType
|
||||
&& type.GetGenericTypeDefinition() == typeof(Nullable<>))
|
||||
{
|
||||
ProcessType(builder, type.UnwrapNullableType(), fullName, compilable);
|
||||
builder.Append('?');
|
||||
return;
|
||||
}
|
||||
|
||||
var offset = type.IsNested ? type.DeclaringType!.GetGenericArguments().Length : 0;
|
||||
|
||||
if (compilable)
|
||||
{
|
||||
if (type.IsNested)
|
||||
{
|
||||
ProcessType(builder, type.DeclaringType!, fullName, compilable);
|
||||
builder.Append('.');
|
||||
}
|
||||
else if (fullName)
|
||||
{
|
||||
builder.Append(type.Namespace);
|
||||
builder.Append('.');
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (fullName)
|
||||
{
|
||||
if (type.IsNested)
|
||||
{
|
||||
ProcessGenericType(builder, type.DeclaringType!, genericArguments, offset, fullName, compilable);
|
||||
builder.Append('+');
|
||||
}
|
||||
else
|
||||
{
|
||||
builder.Append(type.Namespace);
|
||||
builder.Append('.');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var genericPartIndex = type.Name.IndexOf('`');
|
||||
if (genericPartIndex <= 0)
|
||||
{
|
||||
builder.Append(type.Name);
|
||||
return;
|
||||
}
|
||||
|
||||
builder.Append(type.Name, 0, genericPartIndex);
|
||||
builder.Append('<');
|
||||
|
||||
for (var i = offset; i < length; i++)
|
||||
{
|
||||
ProcessType(builder, genericArguments[i], fullName, compilable);
|
||||
if (i + 1 == length)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
builder.Append(',');
|
||||
if (!genericArguments[i + 1].IsGenericParameter)
|
||||
{
|
||||
builder.Append(' ');
|
||||
}
|
||||
}
|
||||
|
||||
builder.Append('>');
|
||||
}
|
||||
}
|
||||
@@ -187,7 +187,7 @@ namespace Radzen.Blazor
|
||||
|
||||
if (Visible)
|
||||
{
|
||||
JSRuntime.InvokeVoidAsync("Radzen.destroyGauge", Element);
|
||||
JSRuntime.InvokeVoid("Radzen.destroyGauge", Element);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
24
Radzen.Blazor/JSRuntimeExtensions.cs
Normal file
24
Radzen.Blazor/JSRuntimeExtensions.cs
Normal file
@@ -0,0 +1,24 @@
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.JSInterop;
|
||||
|
||||
namespace Radzen;
|
||||
|
||||
static class JSRuntimeExtensions
|
||||
{
|
||||
public static void InvokeVoid(this IJSRuntime jsRuntime, string identifier, params object[] args)
|
||||
{
|
||||
_ = jsRuntime.InvokeVoidAsync(identifier, args).FireAndForget();
|
||||
}
|
||||
|
||||
private static async ValueTask FireAndForget(this ValueTask task)
|
||||
{
|
||||
try
|
||||
{
|
||||
await task;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
39
Radzen.Blazor/NonRenderingExtensions.cs
Normal file
39
Radzen.Blazor/NonRenderingExtensions.cs
Normal file
@@ -0,0 +1,39 @@
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Components;
|
||||
|
||||
namespace Radzen.Blazor;
|
||||
|
||||
static class NonRenderingExtensions
|
||||
{
|
||||
public static Action AsNonRenderingEventHandler(this ComponentBase _, Action callback)
|
||||
=> new SyncReceiver(callback).Invoke;
|
||||
public static Action<TValue> AsNonRenderingEventHandler<TValue>(this Action<TValue> callback) => new SyncReceiver<TValue>(callback).Invoke;
|
||||
public static Func<Task> AsNonRenderingEventHandler(this ComponentBase _, Func<Task> callback) => new AsyncReceiver(callback).Invoke;
|
||||
public static Func<TValue, Task> AsNonRenderingEventHandler<TValue>(this ComponentBase _, Func<TValue, Task> callback) => new AsyncReceiver<TValue>(callback).Invoke;
|
||||
|
||||
private record SyncReceiver(Action callback) : ReceiverBase
|
||||
{
|
||||
public void Invoke() => callback();
|
||||
}
|
||||
|
||||
private record SyncReceiver<T>(Action<T> callback) : ReceiverBase
|
||||
{
|
||||
public void Invoke(T arg) => callback(arg);
|
||||
}
|
||||
|
||||
private record AsyncReceiver(Func<Task> callback) : ReceiverBase
|
||||
{
|
||||
public Task Invoke() => callback();
|
||||
}
|
||||
|
||||
private record AsyncReceiver<T>(Func<T, Task> callback) : ReceiverBase
|
||||
{
|
||||
public Task Invoke(T arg) => callback(arg);
|
||||
}
|
||||
|
||||
private record ReceiverBase : IHandleEvent
|
||||
{
|
||||
public Task HandleEventAsync(EventCallbackWorkItem item, object arg) => item.InvokeAsync(arg);
|
||||
}
|
||||
}
|
||||
@@ -71,7 +71,7 @@ namespace Radzen
|
||||
var parameter = Expression.Parameter(source.ElementType, "x");
|
||||
|
||||
return GroupByMany(source,
|
||||
properties.Select(p => Expression.Lambda<Func<T, object>>(Expression.Convert(GetNestedPropertyExpression(parameter, p), typeof(object)), parameter).Compile()).ToArray(),
|
||||
properties.Select(p => Expression.Lambda<Func<T, object>>(Expression.Convert(GetNestedPropertyExpression(parameter, p), typeof(object)), parameter).Compile()).ToArray(),
|
||||
0);
|
||||
}
|
||||
|
||||
@@ -197,8 +197,8 @@ namespace Radzen
|
||||
/// <returns>An <see cref="IQueryable"/> that contains each element of the source sequence converted to the specified type.</returns>
|
||||
public static IQueryable Cast(this IQueryable source, Type type)
|
||||
{
|
||||
return source.Provider.CreateQuery(Expression.Call(null,
|
||||
typeof(Queryable).GetTypeInfo().GetDeclaredMethods(nameof(Queryable.Cast)).FirstOrDefault(mi => mi.IsGenericMethod).MakeGenericMethod(type),
|
||||
return source.Provider.CreateQuery(Expression.Call(null,
|
||||
typeof(Queryable).GetTypeInfo().GetDeclaredMethods(nameof(Queryable.Cast)).FirstOrDefault(mi => mi.IsGenericMethod).MakeGenericMethod(type),
|
||||
source.Expression));
|
||||
}
|
||||
|
||||
@@ -234,7 +234,7 @@ namespace Radzen
|
||||
/// <summary>
|
||||
/// Filters using the specified filter descriptors.
|
||||
/// </summary>
|
||||
public static IQueryable<T> Where<T>(this IQueryable<T> source, IEnumerable<FilterDescriptor> filters,
|
||||
public static IQueryable<T> Where<T>(this IQueryable<T> source, IEnumerable<FilterDescriptor> filters,
|
||||
LogicalFilterOperator logicalFilterOperator, FilterCaseSensitivity filterCaseSensitivity)
|
||||
{
|
||||
if (filters == null || !filters.Any())
|
||||
@@ -519,35 +519,6 @@ namespace Radzen
|
||||
return (IList)genericToList.Invoke(null, new[] { query });
|
||||
}
|
||||
|
||||
static string EnumerableAsString(IQueryable enumerableValue, string baseType, object value)
|
||||
{
|
||||
Func<IQueryable, IEnumerable<object>> values = (items) => {
|
||||
if (items.ElementType == typeof(string))
|
||||
{
|
||||
return items.Cast<string>().Select(i => $@"""{i}""");
|
||||
}
|
||||
else if (items.ElementType == typeof(bool) || items.ElementType == typeof(bool?))
|
||||
{
|
||||
return items.Cast<object>().Select(i => $@"{i}".ToLower());
|
||||
}
|
||||
else if (PropertyAccess.IsDate(items.ElementType))
|
||||
{
|
||||
return items.Cast<object>().Select(i => $@"DateTime.Parse(""{i}"")");
|
||||
}
|
||||
else if (PropertyAccess.IsEnum(items.ElementType) || PropertyAccess.IsNullableEnum(items.ElementType))
|
||||
{
|
||||
return items.Cast<object>().Select(i => i != null ? Convert.ChangeType(i, typeof(int)) : null);
|
||||
}
|
||||
|
||||
return items.Cast<object>();
|
||||
|
||||
};
|
||||
|
||||
var finalValues = value != null && !(IsEnumerable(value.GetType()) && !(value is string)) ? new object[] { value }.AsQueryable().Cast(value.GetType()) : enumerableValue;
|
||||
|
||||
return "new " + baseType + "[]{" + String.Join(",", values(finalValues)) + "}";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts to filterstring.
|
||||
/// </summary>
|
||||
@@ -556,203 +527,78 @@ namespace Radzen
|
||||
/// <returns>System.String.</returns>
|
||||
public static string ToFilterString<T>(this IEnumerable<RadzenDataGridColumn<T>> columns)
|
||||
{
|
||||
var columnsWithFilter = GetFilterableColumns(columns);
|
||||
Func<RadzenDataGridColumn<T>, bool> canFilter = (c) => c.Filterable && c.FilterPropertyType != null &&
|
||||
(!(c.GetFilterValue() == null || c.GetFilterValue() as string == string.Empty)
|
||||
|| c.GetFilterOperator() == FilterOperator.IsNotNull || c.GetFilterOperator() == FilterOperator.IsNull
|
||||
|| c.GetFilterOperator() == FilterOperator.IsEmpty || c.GetFilterOperator() == FilterOperator.IsNotEmpty)
|
||||
&& c.GetFilterProperty() != null;
|
||||
|
||||
if (columnsWithFilter.Any())
|
||||
Func<RadzenDataGridColumn<T>, bool> canFilterCustom = (c) => c.Filterable && c.FilterPropertyType != null &&
|
||||
(c.GetFilterOperator() == FilterOperator.Custom && c.GetCustomFilterExpression() != null)
|
||||
&& c.GetFilterProperty() != null;
|
||||
|
||||
var columnsToFilter = columns.Where(canFilter);
|
||||
var grid = columns.FirstOrDefault()?.Grid;
|
||||
var gridLogicalFilterOperator = grid != null ? grid.LogicalFilterOperator : LogicalFilterOperator.And;
|
||||
var gridFilterCaseSensitivity = grid != null ? grid.FilterCaseSensitivity : FilterCaseSensitivity.Default;
|
||||
|
||||
var serializer = new ExpressionSerializer();
|
||||
var filterExpression = "";
|
||||
|
||||
if (columnsToFilter.Any())
|
||||
{
|
||||
var gridLogicalFilterOperator = columns.FirstOrDefault()?.Grid?.LogicalFilterOperator;
|
||||
var gridBooleanOperator = gridLogicalFilterOperator == LogicalFilterOperator.And ? "&&" : "||";
|
||||
|
||||
var whereList = new List<string>();
|
||||
|
||||
foreach (var column in columnsWithFilter)
|
||||
var filters = columnsToFilter.Select(c => new FilterDescriptor()
|
||||
{
|
||||
string value = "";
|
||||
string secondValue = "";
|
||||
Property = c.Property,
|
||||
FilterProperty = c.FilterProperty,
|
||||
Type = c.FilterPropertyType,
|
||||
FilterValue = c.GetFilterValue(),
|
||||
FilterOperator = c.GetFilterOperator(),
|
||||
SecondFilterValue = c.GetSecondFilterValue(),
|
||||
SecondFilterOperator = c.GetSecondFilterOperator(),
|
||||
LogicalFilterOperator = c.GetLogicalFilterOperator()
|
||||
});
|
||||
|
||||
var v = column.GetFilterValue();
|
||||
var sv = column.GetSecondFilterValue();
|
||||
if (filters.Any())
|
||||
{
|
||||
var parameter = Expression.Parameter(typeof(T), "x");
|
||||
Expression combinedExpression = null;
|
||||
|
||||
if (column.GetFilterOperator() == FilterOperator.Custom)
|
||||
foreach (var filter in filters)
|
||||
{
|
||||
var customFilterExpression = column.GetCustomFilterExpression();
|
||||
if (!string.IsNullOrEmpty(customFilterExpression))
|
||||
{
|
||||
whereList.Add(customFilterExpression);
|
||||
}
|
||||
}
|
||||
else if (v != null && IsEnumerable(v.GetType()) && v.GetType() != typeof(string) || IsEnumerable(column.FilterPropertyType) && column.FilterPropertyType != typeof(string))
|
||||
{
|
||||
var enumerableValue = ((IEnumerable)(v != null ? v : Enumerable.Empty<object>())).AsQueryable();
|
||||
var enumerableSecondValue = ((IEnumerable)(sv != null ? sv : Enumerable.Empty<object>())).AsQueryable();
|
||||
var expression = GetExpression<T>(parameter, filter, gridFilterCaseSensitivity, filter.Type);
|
||||
if (expression == null) continue;
|
||||
|
||||
|
||||
string baseType = column.FilterPropertyType.GetGenericArguments().Count() == 1
|
||||
? column.FilterPropertyType.GetGenericArguments()[0].Name
|
||||
: "";
|
||||
|
||||
if (column.Property != column.FilterProperty)
|
||||
{
|
||||
baseType = "";
|
||||
}
|
||||
|
||||
var enumerableValueAsString = EnumerableAsString(enumerableValue, baseType, v);
|
||||
|
||||
var enumerableSecondValueAsString = EnumerableAsString(enumerableSecondValue, baseType, sv);
|
||||
|
||||
if (enumerableValue?.Cast<object>().Any() == true)
|
||||
{
|
||||
var columnFilterOperator = column.GetFilterOperator();
|
||||
var columnSecondFilterOperator = column.GetSecondFilterOperator();
|
||||
var linqOperator = LinqFilterOperators[column.GetFilterOperator()];
|
||||
if (linqOperator == null)
|
||||
{
|
||||
linqOperator = "==";
|
||||
}
|
||||
|
||||
var booleanOperator = column.LogicalFilterOperator == LogicalFilterOperator.And ? "&&" : "||";
|
||||
|
||||
var filterProperty = column.GetFilterProperty();
|
||||
var itemInstanceName = !filterProperty.Contains("[") ? "it." : "";
|
||||
var property = itemInstanceName + PropertyAccess.GetProperty(column.GetFilterProperty());
|
||||
|
||||
if (sv == null)
|
||||
{
|
||||
if (columnFilterOperator == FilterOperator.Contains || columnFilterOperator == FilterOperator.DoesNotContain)
|
||||
{
|
||||
if (column.GetFilterValue() is string && column.Property != column.FilterProperty && !string.IsNullOrEmpty(column.FilterProperty))
|
||||
{
|
||||
whereList.Add($@"{(columnFilterOperator == FilterOperator.DoesNotContain ? "! " : "")}{itemInstanceName + column.Property}.Any(i => {"i." + column.FilterProperty}.Contains(""" + column.GetFilterValue() + "\"))");
|
||||
}
|
||||
else if (IsEnumerable(column.FilterPropertyType) && column.FilterPropertyType != typeof(string) &&
|
||||
IsEnumerable(column.PropertyType) && column.PropertyType != typeof(string))
|
||||
{
|
||||
whereList.Add($@"{(columnFilterOperator == FilterOperator.DoesNotContain ? "! " : "")}({enumerableValueAsString}).Contains({property})");
|
||||
}
|
||||
else if (IsEnumerable(column.FilterPropertyType) && column.FilterPropertyType != typeof(string) &&
|
||||
column.Property != column.FilterProperty && !string.IsNullOrEmpty(column.FilterProperty))
|
||||
{
|
||||
whereList.Add($@"({property}).{(columnFilterOperator == FilterOperator.NotIn ? "Except" : "Intersect")}({enumerableValueAsString}).Any()");
|
||||
}
|
||||
else
|
||||
{
|
||||
whereList.Add($@"{(columnFilterOperator == FilterOperator.DoesNotContain ? "! " : "")}({enumerableValueAsString}).Contains({property})");
|
||||
}
|
||||
}
|
||||
else if (columnFilterOperator == FilterOperator.In || columnFilterOperator == FilterOperator.NotIn)
|
||||
{
|
||||
if (IsEnumerable(column.FilterPropertyType) && column.FilterPropertyType != typeof(string) &&
|
||||
IsEnumerable(column.PropertyType) && column.PropertyType != typeof(string))
|
||||
{
|
||||
whereList.Add($@"{(columnFilterOperator == FilterOperator.NotIn ? "!" : "")}{property}.Any(i => ({enumerableValueAsString}).Contains(i))");
|
||||
}
|
||||
else if (IsEnumerable(column.FilterPropertyType) && column.FilterPropertyType != typeof(string) &&
|
||||
column.Property != column.FilterProperty && !string.IsNullOrEmpty(column.FilterProperty))
|
||||
{
|
||||
whereList.Add($@"{(columnFilterOperator == FilterOperator.NotIn ? "!" : "")}{itemInstanceName + column.Property}.Any(i => ({enumerableValueAsString}).Contains(i.{column.FilterProperty}))");
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((columnFilterOperator == FilterOperator.Contains || columnFilterOperator == FilterOperator.DoesNotContain) &&
|
||||
(columnSecondFilterOperator == FilterOperator.Contains || columnSecondFilterOperator == FilterOperator.DoesNotContain))
|
||||
{
|
||||
whereList.Add($@"{(columnFilterOperator == FilterOperator.DoesNotContain ? "!" : "")}({enumerableValueAsString}).Contains({property}) {booleanOperator} {(columnSecondFilterOperator == FilterOperator.DoesNotContain ? "!" : "")}({enumerableSecondValueAsString}).Contains({property})");
|
||||
}
|
||||
else if ((columnFilterOperator == FilterOperator.In || columnFilterOperator == FilterOperator.NotIn) &&
|
||||
(columnSecondFilterOperator == FilterOperator.In || columnSecondFilterOperator == FilterOperator.NotIn))
|
||||
{
|
||||
whereList.Add($@"({property}).{(columnFilterOperator == FilterOperator.NotIn ? "Except" : "Intersect")}({enumerableValueAsString}).Any() {booleanOperator} ({property}).{(columnSecondFilterOperator == FilterOperator.NotIn ? "Except" : "Intersect")}({enumerableSecondValueAsString}).Any()");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (column.FilterPropertyType == typeof(TimeOnly) || column.FilterPropertyType == typeof(TimeOnly?))
|
||||
{
|
||||
value = v != null ? ((TimeOnly)v).ToString("HH:mm:ss") : "";
|
||||
secondValue = sv != null ? ((TimeOnly)sv).ToString("HH:mm:ss") : "";
|
||||
}
|
||||
else if (column.FilterPropertyType == typeof(Guid) || column.FilterPropertyType == typeof(Guid?))
|
||||
{
|
||||
value = $"{v}";
|
||||
secondValue = $"{sv}";
|
||||
}
|
||||
else if (PropertyAccess.IsDate(column.FilterPropertyType))
|
||||
{
|
||||
if (v != null)
|
||||
{
|
||||
|
||||
value =
|
||||
v is DateTime ? ((DateTime)v).ToString("yyyy-MM-ddTHH:mm:ss.fffZ", CultureInfo.InvariantCulture)
|
||||
: v is DateTimeOffset ? ((DateTimeOffset)v).UtcDateTime.ToString("yyyy-MM-ddTHH:mm:ss.fffZ", CultureInfo.InvariantCulture)
|
||||
:
|
||||
#if NET6_0_OR_GREATER
|
||||
v is DateOnly ? ((DateOnly)v).ToString("yyy-MM-dd", CultureInfo.InvariantCulture) : "";
|
||||
#else
|
||||
"";
|
||||
#endif
|
||||
}
|
||||
if (sv != null)
|
||||
{
|
||||
secondValue =
|
||||
sv is DateTime ? ((DateTime)sv).ToString("yyyy-MM-ddTHH:mm:ss.fffZ", CultureInfo.InvariantCulture)
|
||||
: sv is DateTimeOffset ? ((DateTimeOffset)sv).UtcDateTime.ToString("yyyy-MM-ddTHH:mm:ss.fffZ", CultureInfo.InvariantCulture)
|
||||
:
|
||||
#if NET6_0_OR_GREATER
|
||||
sv is DateOnly ? ((DateOnly)sv).ToString("yyy-MM-dd", CultureInfo.InvariantCulture) : "";
|
||||
#else
|
||||
"";
|
||||
#endif
|
||||
}
|
||||
}
|
||||
else if (!(v != null && IsEnumerable(v.GetType())) && (PropertyAccess.IsEnum(column.FilterPropertyType) || PropertyAccess.IsNullableEnum(column.FilterPropertyType)))
|
||||
{
|
||||
Type enumType = Enum.GetUnderlyingType(Nullable.GetUnderlyingType(column.FilterPropertyType) ?? column.FilterPropertyType);
|
||||
if (v != null)
|
||||
{
|
||||
value = Convert.ChangeType(v, enumType).ToString();
|
||||
}
|
||||
if (sv != null)
|
||||
{
|
||||
secondValue = Convert.ChangeType(sv, enumType).ToString();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
value = (string)Convert.ChangeType(column.GetFilterValue(), typeof(string), CultureInfo.InvariantCulture);
|
||||
secondValue = (string)Convert.ChangeType(column.GetSecondFilterValue(), typeof(string), CultureInfo.InvariantCulture);
|
||||
combinedExpression = combinedExpression == null
|
||||
? expression
|
||||
: gridLogicalFilterOperator == LogicalFilterOperator.And ?
|
||||
Expression.AndAlso(combinedExpression, expression) :
|
||||
Expression.OrElse(combinedExpression, expression);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(value) || column.GetFilterOperator() == FilterOperator.IsNotNull
|
||||
|| column.GetFilterOperator() == FilterOperator.IsNull
|
||||
|| column.GetFilterOperator() == FilterOperator.IsEmpty
|
||||
|| column.GetFilterOperator() == FilterOperator.IsNotEmpty)
|
||||
if (combinedExpression != null)
|
||||
{
|
||||
var linqOperator = LinqFilterOperators[column.GetFilterOperator()];
|
||||
if (linqOperator == null)
|
||||
{
|
||||
linqOperator = "==";
|
||||
}
|
||||
|
||||
var booleanOperator = column.LogicalFilterOperator == LogicalFilterOperator.And ? "&&" : "||";
|
||||
|
||||
if (string.IsNullOrEmpty(secondValue))
|
||||
{
|
||||
whereList.Add(GetColumnFilter(column, value));
|
||||
}
|
||||
else
|
||||
{
|
||||
whereList.Add($"({GetColumnFilter(column, value)} {booleanOperator} {GetColumnFilter(column, secondValue, true)})");
|
||||
}
|
||||
filterExpression = serializer.Serialize(Expression.Lambda<Func<T, bool>>(combinedExpression, parameter));
|
||||
}
|
||||
}
|
||||
|
||||
return whereList.Any() ?
|
||||
"it => " + string.Join($" {gridBooleanOperator} ", whereList.Where(i => !string.IsNullOrEmpty(i))) : "";
|
||||
}
|
||||
|
||||
return "";
|
||||
var columnsWithCustomFilter = columns.Where(canFilterCustom);
|
||||
|
||||
var customFilterExpression = "";
|
||||
|
||||
if (columnsToFilter.Any())
|
||||
{
|
||||
var expressions = columnsWithCustomFilter.Select(c => (c.GetCustomFilterExpression() ?? "").Replace(" or ", " || ").Replace(" and ", " && ")).Where(e => !string.IsNullOrEmpty(e)).ToList();
|
||||
customFilterExpression = string.Join($"{(gridLogicalFilterOperator == LogicalFilterOperator.And ? " && " : " || ")}", expressions);
|
||||
|
||||
return !string.IsNullOrEmpty(filterExpression) && !string.IsNullOrEmpty(customFilterExpression) ?
|
||||
$"{filterExpression} {(gridLogicalFilterOperator == LogicalFilterOperator.And ? " && " : " || ")} {customFilterExpression}" :
|
||||
!string.IsNullOrEmpty(customFilterExpression) ? "it => " + customFilterExpression : filterExpression;
|
||||
}
|
||||
|
||||
return filterExpression;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -764,377 +610,38 @@ namespace Radzen
|
||||
public static string ToFilterString<T>(this RadzenDataFilter<T> dataFilter)
|
||||
{
|
||||
Func<CompositeFilterDescriptor, bool> canFilter = (c) => dataFilter.properties.Where(col => col.Property == c.Property).FirstOrDefault()?.FilterPropertyType != null &&
|
||||
(!(c.FilterValue == null || c.FilterValue as string == string.Empty)
|
||||
|| c.FilterOperator == FilterOperator.IsNotNull || c.FilterOperator == FilterOperator.IsNull
|
||||
|| c.FilterOperator == FilterOperator.IsEmpty || c.FilterOperator == FilterOperator.IsNotEmpty)
|
||||
&& c.Property != null;
|
||||
(!(c.FilterValue == null || c.FilterValue as string == string.Empty)
|
||||
|| c.FilterOperator == FilterOperator.IsNotNull || c.FilterOperator == FilterOperator.IsNull
|
||||
|| c.FilterOperator == FilterOperator.IsEmpty || c.FilterOperator == FilterOperator.IsNotEmpty)
|
||||
&& c.Property != null;
|
||||
|
||||
if (dataFilter.Filters.Concat(dataFilter.Filters.SelectManyRecursive(i => i.Filters ?? Enumerable.Empty<CompositeFilterDescriptor>())).Where(canFilter).Any())
|
||||
{
|
||||
return CompositeFilterToFilterString<T>(dataFilter.Filters, dataFilter, dataFilter.LogicalFilterOperator);
|
||||
}
|
||||
return "";
|
||||
}
|
||||
var serializer = new ExpressionSerializer();
|
||||
|
||||
/// <summary>
|
||||
/// Creates a Linq-compatible filter string for a list of CompositeFilterDescriptions
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type that is being filtered</typeparam>
|
||||
/// <param name="filters">The list if filters</param>
|
||||
/// <param name="Datafilter">The RadzenDataFilter component</param>
|
||||
/// <param name="filterOperator">Whether filter elements should be and-ed or or-ed</param>
|
||||
/// <returns></returns>
|
||||
private static string CompositeFilterToFilterString<T>(IEnumerable<CompositeFilterDescriptor> filters, RadzenDataFilter<T> Datafilter, LogicalFilterOperator filterOperator)
|
||||
{
|
||||
if (filters.Any())
|
||||
{
|
||||
var LogicalFilterOperator = filterOperator;
|
||||
var BooleanOperator = LogicalFilterOperator == LogicalFilterOperator.And ? "&&" : "||";
|
||||
var filterExpressions = new List<Expression>();
|
||||
|
||||
var whereList = new List<string>();
|
||||
foreach (var column in filters)
|
||||
var parameter = Expression.Parameter(typeof(T), "x");
|
||||
|
||||
foreach (var filter in dataFilter.Filters)
|
||||
{
|
||||
if (column.Filters is not null && column.Filters.Any())
|
||||
{
|
||||
whereList.Add($"({CompositeFilterToFilterString(column.Filters, Datafilter, column.LogicalFilterOperator)})");
|
||||
}
|
||||
if (column.Property is not null)
|
||||
{
|
||||
whereList.Add($"{GetColumnFilter(Datafilter, column, Datafilter.FilterCaseSensitivity == FilterCaseSensitivity.CaseInsensitive)}");
|
||||
}
|
||||
AddWhereExpression<T>(parameter, filter, ref filterExpressions, dataFilter.FilterCaseSensitivity);
|
||||
}
|
||||
|
||||
return string.Join($" {BooleanOperator} ", whereList.Where(i => !string.IsNullOrEmpty(i)));
|
||||
}
|
||||
Expression combinedExpression = null;
|
||||
|
||||
return "";
|
||||
foreach (var expression in filterExpressions)
|
||||
{
|
||||
combinedExpression = combinedExpression == null
|
||||
? expression
|
||||
: dataFilter.LogicalFilterOperator == LogicalFilterOperator.And ?
|
||||
Expression.AndAlso(combinedExpression, expression) :
|
||||
Expression.OrElse(combinedExpression, expression);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a single linq-compatible filter string for one datafilter element (includes sub-lists)
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type that is being filtered</typeparam>
|
||||
/// <param name="dataFilter">The RadzenDataFilter component</param>
|
||||
/// <param name="column">The filter elements for which to create the filter string</param>
|
||||
/// <param name="caseSensitive">Whether filtering is case sensitive or not</param>
|
||||
/// <returns></returns>
|
||||
private static string GetColumnFilter<T>(RadzenDataFilter<T> dataFilter, CompositeFilterDescriptor column, bool caseSensitive)
|
||||
{
|
||||
var property = column.Property;
|
||||
|
||||
if (property.Contains(".", StringComparison.CurrentCulture))
|
||||
{
|
||||
property = $"({property})";
|
||||
}
|
||||
|
||||
var columnInfo = dataFilter.properties.Where(c => c.Property == column.Property).FirstOrDefault();
|
||||
if (columnInfo == null) return "";
|
||||
|
||||
var columnType = columnInfo.FilterPropertyType;
|
||||
|
||||
var columnFilterOperator = column.FilterOperator;
|
||||
|
||||
var linqOperator = LinqFilterOperators[columnFilterOperator.Value];
|
||||
linqOperator ??= "==";
|
||||
|
||||
var value = "";
|
||||
|
||||
if (columnType == typeof(string))
|
||||
{
|
||||
value = (string)Convert.ChangeType(column.FilterValue, typeof(string));
|
||||
value = value?.Replace("\"", "\\\"");
|
||||
|
||||
string filterCaseSensitivityOperator = caseSensitive ? ".ToLower()" : "";
|
||||
|
||||
if (!string.IsNullOrEmpty(value) && column.FilterOperator == FilterOperator.Contains)
|
||||
if (combinedExpression != null)
|
||||
{
|
||||
return $@"({property} == null ? """" : {property}){filterCaseSensitivityOperator}.Contains(""{value}""{filterCaseSensitivityOperator})";
|
||||
}
|
||||
else if (!string.IsNullOrEmpty(value) && columnFilterOperator == FilterOperator.DoesNotContain)
|
||||
{
|
||||
return $@"!({property} == null ? """" : {property}){filterCaseSensitivityOperator}.Contains(""{value}""{filterCaseSensitivityOperator})";
|
||||
}
|
||||
else if (!string.IsNullOrEmpty(value) && columnFilterOperator == FilterOperator.StartsWith)
|
||||
{
|
||||
return $@"({property} == null ? """" : {property}){filterCaseSensitivityOperator}.StartsWith(""{value}""{filterCaseSensitivityOperator})";
|
||||
}
|
||||
else if (!string.IsNullOrEmpty(value) && columnFilterOperator == FilterOperator.EndsWith)
|
||||
{
|
||||
return $@"({property} == null ? """" : {property}){filterCaseSensitivityOperator}.EndsWith(""{value}""{filterCaseSensitivityOperator})";
|
||||
}
|
||||
else if (!string.IsNullOrEmpty(value) && columnFilterOperator == FilterOperator.Equals)
|
||||
{
|
||||
return $@"({property} == null ? """" : {property}){filterCaseSensitivityOperator} == ""{value}""{filterCaseSensitivityOperator}";
|
||||
}
|
||||
else if (!string.IsNullOrEmpty(value) && columnFilterOperator == FilterOperator.NotEquals)
|
||||
{
|
||||
return $@"({property} == null ? """" : {property}){filterCaseSensitivityOperator} != ""{value}""{filterCaseSensitivityOperator}";
|
||||
}
|
||||
else if (columnFilterOperator == FilterOperator.IsNull)
|
||||
{
|
||||
return property + " == null";
|
||||
}
|
||||
else if (columnFilterOperator == FilterOperator.IsEmpty)
|
||||
{
|
||||
return property + @" == """"";
|
||||
}
|
||||
else if (columnFilterOperator == FilterOperator.IsNotEmpty)
|
||||
{
|
||||
return property + @" != """"";
|
||||
}
|
||||
else if (columnFilterOperator == FilterOperator.IsNotNull)
|
||||
{
|
||||
return property + @" != null";
|
||||
}
|
||||
}
|
||||
else if (PropertyAccess.IsNumeric(columnType))
|
||||
{
|
||||
value = (string)Convert.ChangeType(column.FilterValue, typeof(string));
|
||||
|
||||
if (columnFilterOperator == FilterOperator.IsNull || columnFilterOperator == FilterOperator.IsNotNull)
|
||||
{
|
||||
return $"{property} {linqOperator} null";
|
||||
}
|
||||
else if (columnFilterOperator == FilterOperator.IsEmpty || columnFilterOperator == FilterOperator.IsNotEmpty)
|
||||
{
|
||||
return $@"{property} {linqOperator} """"";
|
||||
}
|
||||
else
|
||||
{
|
||||
return $"{property} {linqOperator} {value}";
|
||||
}
|
||||
}
|
||||
else if (columnType == typeof(bool) || columnType == typeof(bool?))
|
||||
{
|
||||
value = (string)Convert.ChangeType(column.FilterValue, typeof(string));
|
||||
|
||||
return $"{property} {linqOperator} {(columnFilterOperator == FilterOperator.IsNull || columnFilterOperator == FilterOperator.IsNotNull ? "null" : value)}";
|
||||
}
|
||||
else if (PropertyAccess.IsDate(columnType))
|
||||
{
|
||||
var v = column.FilterValue;
|
||||
if (v != null)
|
||||
{
|
||||
value = $@"DateTime(""{(v is DateTime time ? time.ToString("yyyy-MM-ddTHH:mm:ss.fffZ", CultureInfo.InvariantCulture) : v is DateTimeOffset offset ? offset.UtcDateTime.ToString("yyyy-MM-ddTHH:mm:ss.fffZ", CultureInfo.InvariantCulture) : "")}"")";
|
||||
}
|
||||
}
|
||||
else if (PropertyAccess.IsEnum(columnType) || PropertyAccess.IsNullableEnum(columnType))
|
||||
{
|
||||
var v = column.FilterValue;
|
||||
if (v != null)
|
||||
{
|
||||
value = ((int)v).ToString();
|
||||
}
|
||||
}
|
||||
else if (IsEnumerable(columnType) && columnType != typeof(string))
|
||||
{
|
||||
var v = column.FilterValue;
|
||||
var enumerableValue = ((IEnumerable)(v ?? Enumerable.Empty<object>())).AsQueryable();
|
||||
|
||||
var enumerableValueAsString = "(" + String.Join(",",
|
||||
(enumerableValue.ElementType == typeof(string) ?
|
||||
enumerableValue.Cast<string>().Select(i => $@"""{i}""").Cast<object>()
|
||||
: PropertyAccess.IsDate(enumerableValue.ElementType) ?
|
||||
enumerableValue.Cast<object>().Select(i => $@"DateTime(""{i}"")").Cast<object>()
|
||||
: enumerableValue.Cast<object>())) + ")";
|
||||
|
||||
|
||||
if (enumerableValue?.Cast<object>().Any() == true)
|
||||
{
|
||||
if (property.Contains("."))
|
||||
{
|
||||
property = $"({property})";
|
||||
}
|
||||
|
||||
if (columnFilterOperator == FilterOperator.Contains || columnFilterOperator == FilterOperator.DoesNotContain)
|
||||
{
|
||||
return $@"{property} {(columnFilterOperator == FilterOperator.DoesNotContain ? "not " : "in")} {enumerableValueAsString}";
|
||||
}
|
||||
else if (columnFilterOperator == FilterOperator.In || columnFilterOperator == FilterOperator.NotIn)
|
||||
{
|
||||
return $@"({property}).{(columnFilterOperator == FilterOperator.NotIn ? "Except" : "Intersect")}({enumerableValueAsString}).Any()";
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
value = (string)Convert.ChangeType(column.FilterValue, typeof(string), CultureInfo.InvariantCulture);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(value) || column.FilterOperator == FilterOperator.IsNotNull
|
||||
|| column.FilterOperator == FilterOperator.IsNull
|
||||
|| column.FilterOperator == FilterOperator.IsEmpty
|
||||
|| column.FilterOperator == FilterOperator.IsNotEmpty)
|
||||
{
|
||||
return $"({property} {linqOperator} {(columnFilterOperator == FilterOperator.IsNull || columnFilterOperator == FilterOperator.IsNotNull ? "null" : value)})";
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the column filter.
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="column">The column.</param>
|
||||
/// <param name="value">The value.</param>
|
||||
/// <param name="second">if set to <c>true</c> [second].</param>
|
||||
/// <returns>System.String.</returns>
|
||||
private static string GetColumnFilter<T>(RadzenDataGridColumn<T> column, string value, bool second = false)
|
||||
{
|
||||
var filterProperty = column.GetFilterProperty();
|
||||
var itemInstanceName = !filterProperty.Contains("[") ? "it." : "";
|
||||
var property = itemInstanceName + PropertyAccess.GetProperty(filterProperty);
|
||||
var propertyType = !string.IsNullOrEmpty(property) ? PropertyAccess.GetPropertyType(typeof(T), property) : null;
|
||||
|
||||
string npProperty = (propertyType != null ? Nullable.GetUnderlyingType(propertyType) != null : true) ? $@"({property} ?? null)" : property;
|
||||
|
||||
var columnFilterOperator = !second ? column.GetFilterOperator() : column.GetSecondFilterOperator();
|
||||
|
||||
if (columnFilterOperator == FilterOperator.Custom)
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
var linqOperator = LinqFilterOperators[columnFilterOperator];
|
||||
if (linqOperator == null)
|
||||
{
|
||||
linqOperator = "==";
|
||||
}
|
||||
bool isDateOnly = false;
|
||||
|
||||
#if NET6_0_OR_GREATER
|
||||
if (column.FilterPropertyType == typeof(DateOnly) || column.FilterPropertyType == typeof(DateOnly?))
|
||||
{
|
||||
isDateOnly = true;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (column.FilterPropertyType == typeof(string))
|
||||
{
|
||||
string filterCaseSensitivityOperator = column.Grid.FilterCaseSensitivity == FilterCaseSensitivity.CaseInsensitive ? ".ToLower()" : "";
|
||||
value = value?.Replace("\"", "\\\"");
|
||||
|
||||
if (!string.IsNullOrEmpty(value) && columnFilterOperator == FilterOperator.Contains)
|
||||
{
|
||||
return $@"({property} == null ? """" : {property}){filterCaseSensitivityOperator}.Contains(""{value}""{filterCaseSensitivityOperator})";
|
||||
}
|
||||
else if (!string.IsNullOrEmpty(value) && columnFilterOperator == FilterOperator.DoesNotContain)
|
||||
{
|
||||
return $@"!({property} == null ? """" : {property}){filterCaseSensitivityOperator}.Contains(""{value}""{filterCaseSensitivityOperator})";
|
||||
}
|
||||
else if (!string.IsNullOrEmpty(value) && columnFilterOperator == FilterOperator.StartsWith)
|
||||
{
|
||||
return $@"({property} == null ? """" : {property}){filterCaseSensitivityOperator}.StartsWith(""{value}""{filterCaseSensitivityOperator})";
|
||||
}
|
||||
else if (!string.IsNullOrEmpty(value) && columnFilterOperator == FilterOperator.EndsWith)
|
||||
{
|
||||
return $@"({property} == null ? """" : {property}){filterCaseSensitivityOperator}.EndsWith(""{value}""{filterCaseSensitivityOperator})";
|
||||
}
|
||||
else if (!string.IsNullOrEmpty(value) && columnFilterOperator == FilterOperator.Equals)
|
||||
{
|
||||
return $@"({property} == null ? """" : {property}){filterCaseSensitivityOperator} == ""{value}""{filterCaseSensitivityOperator}";
|
||||
}
|
||||
else if (!string.IsNullOrEmpty(value) && columnFilterOperator == FilterOperator.NotEquals)
|
||||
{
|
||||
return $@"({property} == null ? """" : {property}){filterCaseSensitivityOperator} != ""{value}""{filterCaseSensitivityOperator}";
|
||||
}
|
||||
else if (columnFilterOperator == FilterOperator.IsNull)
|
||||
{
|
||||
return npProperty + " == null";
|
||||
}
|
||||
else if (columnFilterOperator == FilterOperator.IsEmpty)
|
||||
{
|
||||
return npProperty + @" == """"";
|
||||
}
|
||||
else if (columnFilterOperator == FilterOperator.IsNotEmpty)
|
||||
{
|
||||
return npProperty + @" != """"";
|
||||
}
|
||||
else if (columnFilterOperator == FilterOperator.IsNotNull)
|
||||
{
|
||||
return npProperty + @" != null";
|
||||
}
|
||||
}
|
||||
else if (PropertyAccess.IsEnum(column.FilterPropertyType) || PropertyAccess.IsNullableEnum(column.FilterPropertyType))
|
||||
{
|
||||
if (columnFilterOperator == FilterOperator.IsNull || columnFilterOperator == FilterOperator.IsNotNull)
|
||||
{
|
||||
return $"{property} {linqOperator} null";
|
||||
}
|
||||
else
|
||||
{
|
||||
return $"{property} {linqOperator} {value}";
|
||||
}
|
||||
}
|
||||
else if (PropertyAccess.IsNumeric(column.FilterPropertyType))
|
||||
{
|
||||
if (columnFilterOperator == FilterOperator.IsNull || columnFilterOperator == FilterOperator.IsNotNull)
|
||||
{
|
||||
return $"{property} {linqOperator} null";
|
||||
}
|
||||
else if (columnFilterOperator == FilterOperator.IsEmpty || columnFilterOperator == FilterOperator.IsNotEmpty)
|
||||
{
|
||||
return $@"{property} {linqOperator} """"";
|
||||
}
|
||||
else
|
||||
{
|
||||
return $"{property} {linqOperator} {value}";
|
||||
}
|
||||
}
|
||||
else if (column.FilterPropertyType == typeof(DateTime) ||
|
||||
column.FilterPropertyType == typeof(DateTime?) ||
|
||||
column.FilterPropertyType == typeof(DateTimeOffset) ||
|
||||
column.FilterPropertyType == typeof(DateTimeOffset?) || isDateOnly)
|
||||
{
|
||||
if (columnFilterOperator == FilterOperator.IsNull || columnFilterOperator == FilterOperator.IsNotNull)
|
||||
{
|
||||
return $"{property} {linqOperator} null";
|
||||
}
|
||||
else if (columnFilterOperator == FilterOperator.IsEmpty || columnFilterOperator == FilterOperator.IsNotEmpty)
|
||||
{
|
||||
return $@"{property} {linqOperator} """"";
|
||||
}
|
||||
else
|
||||
{
|
||||
var dateTimeValue = DateTime.Parse(value, CultureInfo.InvariantCulture, System.Globalization.DateTimeStyles.RoundtripKind);
|
||||
var finalDate = dateTimeValue.TimeOfDay == TimeSpan.Zero ? dateTimeValue.Date : dateTimeValue;
|
||||
var dateFormat = dateTimeValue.TimeOfDay == TimeSpan.Zero ? "yyyy-MM-dd" : "yyyy-MM-ddTHH:mm:ss.fffZ";
|
||||
|
||||
string dateFunction = "DateTime"; //fallback to datetime, if it's an offset or dateonly use that
|
||||
if (column.FilterPropertyType == typeof(DateTimeOffset) || column.FilterPropertyType == typeof(DateTimeOffset?))
|
||||
dateFunction = "DateTimeOffset";
|
||||
else
|
||||
{
|
||||
#if NET6_0_OR_GREATER
|
||||
if (column.FilterPropertyType == typeof(DateOnly) || column.FilterPropertyType == typeof(DateOnly?))
|
||||
dateFunction = "DateOnly";
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
return $@"{property} {linqOperator} {dateFunction}(""{finalDate.ToString(dateFormat, CultureInfo.InvariantCulture)}"")";
|
||||
}
|
||||
}
|
||||
else if (column.FilterPropertyType == typeof(bool) || column.FilterPropertyType == typeof(bool?))
|
||||
{
|
||||
value = $"{value}".ToLower();
|
||||
return $"{property} {linqOperator} {(columnFilterOperator == FilterOperator.IsNull || columnFilterOperator == FilterOperator.IsNotNull ? "null" : value)}";
|
||||
}
|
||||
else if (column.FilterPropertyType == typeof(Guid) || column.FilterPropertyType == typeof(Guid?))
|
||||
{
|
||||
if (columnFilterOperator == FilterOperator.IsNull || columnFilterOperator == FilterOperator.IsNotNull)
|
||||
{
|
||||
return $"{property} {linqOperator} null";
|
||||
}
|
||||
else if (columnFilterOperator == FilterOperator.IsEmpty || columnFilterOperator == FilterOperator.IsNotEmpty)
|
||||
{
|
||||
return $@"{property} {linqOperator} """"";
|
||||
}
|
||||
else
|
||||
{
|
||||
return $@"{property} {linqOperator} Guid(""{value}"")";
|
||||
return serializer.Serialize(Expression.Lambda<Func<T, bool>>(combinedExpression, parameter));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1159,7 +666,7 @@ namespace Radzen
|
||||
? null
|
||||
: (string)Convert.ChangeType(filterValue is DateTimeOffset ?
|
||||
((DateTimeOffset)filterValue).UtcDateTime : filterValue is DateOnly ?
|
||||
((DateOnly)filterValue).ToString("yyy-MM-dd", CultureInfo.InvariantCulture) :
|
||||
((DateOnly)filterValue).ToString("yyy-MM-dd", CultureInfo.InvariantCulture) :
|
||||
filterValue, typeof(string), CultureInfo.InvariantCulture);
|
||||
|
||||
if (column.Grid.FilterCaseSensitivity == FilterCaseSensitivity.CaseInsensitive && column.FilterPropertyType == typeof(string))
|
||||
@@ -1276,7 +783,7 @@ namespace Radzen
|
||||
column.FilterPropertyType == typeof(DateTime?) ||
|
||||
column.FilterPropertyType == typeof(DateTimeOffset) ||
|
||||
column.FilterPropertyType == typeof(DateTimeOffset?) ||
|
||||
column.FilterPropertyType == typeof(DateOnly) ||
|
||||
column.FilterPropertyType == typeof(DateOnly) ||
|
||||
column.FilterPropertyType == typeof(DateOnly?))
|
||||
{
|
||||
if (columnFilterOperator == FilterOperator.IsNull || columnFilterOperator == FilterOperator.IsNotNull)
|
||||
@@ -1394,16 +901,16 @@ namespace Radzen
|
||||
if (columnsToFilter.Any())
|
||||
{
|
||||
source = source.Where(columnsToFilter.Select(c => new FilterDescriptor()
|
||||
{
|
||||
Property = c.Property,
|
||||
FilterProperty = c.FilterProperty,
|
||||
Type = c.FilterPropertyType,
|
||||
FilterValue = c.GetFilterValue(),
|
||||
FilterOperator = c.GetFilterOperator(),
|
||||
SecondFilterValue = c.GetSecondFilterValue(),
|
||||
SecondFilterOperator = c.GetSecondFilterOperator(),
|
||||
LogicalFilterOperator = c.GetLogicalFilterOperator()
|
||||
}), gridLogicalFilterOperator, gridFilterCaseSensitivity);
|
||||
{
|
||||
Property = c.Property,
|
||||
FilterProperty = c.FilterProperty,
|
||||
Type = c.FilterPropertyType,
|
||||
FilterValue = c.GetFilterValue(),
|
||||
FilterOperator = c.GetFilterOperator(),
|
||||
SecondFilterValue = c.GetSecondFilterValue(),
|
||||
SecondFilterOperator = c.GetSecondFilterOperator(),
|
||||
LogicalFilterOperator = c.GetLogicalFilterOperator()
|
||||
}), gridLogicalFilterOperator, gridFilterCaseSensitivity);
|
||||
}
|
||||
|
||||
var columnsWithCustomFilter = columns.Where(canFilterCustom);
|
||||
@@ -1411,7 +918,7 @@ namespace Radzen
|
||||
if (columnsToFilter.Any())
|
||||
{
|
||||
var expressions = columnsWithCustomFilter.Select(c => (c.GetCustomFilterExpression() ?? "").Replace(" or ", " || ").Replace(" and ", " && ")).Where(e => !string.IsNullOrEmpty(e)).ToList();
|
||||
source = expressions.Any() ?
|
||||
source = expressions.Any() ?
|
||||
System.Linq.Dynamic.Core.DynamicExtensions.Where(source, "it => " + string.Join($"{(gridLogicalFilterOperator == LogicalFilterOperator.And ? " && " : " || ")}", expressions)) : source;
|
||||
}
|
||||
|
||||
@@ -1472,7 +979,7 @@ namespace Radzen
|
||||
/// <returns>IQueryable<T>.</returns>
|
||||
public static IQueryable<T> Where<T>(this IQueryable<T> source, IEnumerable<CompositeFilterDescriptor> filters, LogicalFilterOperator logicalFilterOperator, FilterCaseSensitivity filterCaseSensitivity)
|
||||
{
|
||||
Func<CompositeFilterDescriptor, bool> canFilter = (c) =>
|
||||
Func<CompositeFilterDescriptor, bool> canFilter = (c) =>
|
||||
(!(c.FilterValue == null || c.FilterValue as string == string.Empty)
|
||||
|| c.FilterOperator == FilterOperator.IsNotNull || c.FilterOperator == FilterOperator.IsNull
|
||||
|| c.FilterOperator == FilterOperator.IsEmpty || c.FilterOperator == FilterOperator.IsNotEmpty)
|
||||
@@ -1820,4 +1327,4 @@ namespace Radzen
|
||||
.ToList();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -25,7 +25,6 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.8.0" />
|
||||
<PackageReference Include="DartSassBuilder" Version="1.1.0" PrivateAssets="All" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components" Condition="'$(TargetFramework)' == 'net6.0'" Version="6.0.25" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.Web" Condition="'$(TargetFramework)' == 'net6.0'" Version="6.0.0" />
|
||||
@@ -56,10 +55,10 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Sass Include="$(MSBuildProjectDirectory)/themes/*.scss" Exclude="$(MSBuildProjectDirectory)/themes/_*.scss" Condition="'$(TargetFramework)' == 'net8.0'" />
|
||||
<Sass Include="$(MSBuildProjectDirectory)/themes/*.scss" Exclude="$(MSBuildProjectDirectory)/themes/_*.scss" Condition="'$(TargetFramework)' == 'net9.0'" />
|
||||
</ItemGroup>
|
||||
|
||||
<Target Name="Sass" BeforeTargets="BeforeBuild" Condition="'$(TargetFramework)' == 'net8.0'">
|
||||
<Target Name="Sass" BeforeTargets="BeforeBuild" Condition="'$(TargetFramework)' == 'net9.0'">
|
||||
<PropertyGroup>
|
||||
<_SassFileList>@(Sass->'"%(FullPath)"', ' ')</_SassFileList>
|
||||
<DartSassBuilderArgs>files $(_SassFileList) --outputstyle $(DartSassOutputStyle) --level $(DartSassOutputLevel)</DartSassBuilderArgs>
|
||||
@@ -68,14 +67,14 @@
|
||||
<Message Text="Converted SassFile list to argument" Importance="$(DartSassMessageLevel)" />
|
||||
</Target>
|
||||
|
||||
<Target Name="MoveCss" AfterTargets="AfterCompile" Condition="'$(TargetFramework)' == 'net8.0'">
|
||||
<Target Name="MoveCss" AfterTargets="AfterCompile" Condition="'$(TargetFramework)' == 'net9.0'">
|
||||
<ItemGroup>
|
||||
<CssFile Include="$(MSBuildProjectDirectory)/themes/*.css" />
|
||||
</ItemGroup>
|
||||
<Move SourceFiles="@(CssFile)" DestinationFolder="$(MSBuildProjectDirectory)/wwwroot/css/" />
|
||||
</Target>
|
||||
|
||||
<Target Name="MinifyTest" BeforeTargets="Build" Condition="'$(TargetFramework)' == 'net8.0'">
|
||||
<Target Name="MinifyTest" BeforeTargets="Build" Condition="'$(TargetFramework)' == 'net9.0'">
|
||||
<TerserMinify InputFile="wwwroot\Radzen.Blazor.js" OutputFile="wwwroot\Radzen.Blazor.min.js" />
|
||||
</Target>
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
@using System.Linq
|
||||
@using Radzen.Blazor.Rendering
|
||||
|
||||
@inherits RadzenComponent
|
||||
|
||||
@@ -21,14 +22,7 @@
|
||||
<div @ref="@item.Element" id="@item.GetItemId()" @attributes="item.Attributes" class="@item.GetItemCssClass()" style="@item.Style" @onkeydown:stopPropagation>
|
||||
<a @onclick="@((args) => SelectItem(item))" aria-label="@ItemAriaLabel(i, item)" title="@ItemTitle(i, item)" @onclick:preventDefault="true" role="tab"
|
||||
id="@($"rz-accordiontab-{items.IndexOf(item)}")" aria-controls="@($"rz-accordiontab-{items.IndexOf(item)}-content")" aria-expanded="true">
|
||||
@if (IsSelected(i, item))
|
||||
{
|
||||
<span class="notranslate rz-accordion-toggle-icon rzi rzi-chevron-down"></span>
|
||||
}
|
||||
else
|
||||
{
|
||||
<span class="notranslate rz-accordion-toggle-icon rzi rzi-chevron-right"></span>
|
||||
}
|
||||
<span class="@ToggleIconClass(item)">keyboard_arrow_down</span>
|
||||
@if (!string.IsNullOrEmpty(item.Icon))
|
||||
{
|
||||
<i class="notranslate rzi" style="@(!string.IsNullOrEmpty(item.IconColor) ? $"color:{item.IconColor}" : null)">@item.Icon</i>
|
||||
@@ -43,15 +37,12 @@
|
||||
}
|
||||
</a>
|
||||
</div>
|
||||
@if (IsSelected(i, item))
|
||||
{
|
||||
<div class="rz-accordion-content-wrapper" role="tabpanel"
|
||||
id="@($"rz-accordiontab-{items.IndexOf(item)}-content")" aria-hidden="false" aria-labelledby="@($"rz-accordiontab-{items.IndexOf(item)}")">
|
||||
<div class="rz-accordion-content" @onkeydown:stopPropagation>
|
||||
@item.ChildContent
|
||||
</div>
|
||||
<Expander Expanded=@item.GetSelected() role="tabpanel"
|
||||
id="@($"rz-accordiontab-{items.IndexOf(item)}-content")" aria-labelledby="@($"rz-accordiontab-{items.IndexOf(item)}")">
|
||||
<div class="rz-accordion-content" @onkeydown:stopPropagation>
|
||||
@item.ChildContent
|
||||
</div>
|
||||
}
|
||||
</Expander>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using Microsoft.AspNetCore.Components.Web;
|
||||
using Radzen.Blazor.Rendering;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
@@ -110,6 +111,11 @@ namespace Radzen.Blazor
|
||||
}
|
||||
}
|
||||
|
||||
string ToggleIconClass(RadzenAccordionItem item) => ClassList.Create("notranslate rz-accordion-toggle-icon rzi")
|
||||
.Add("rz-state-expanded", item.GetSelected())
|
||||
.Add("rz-state-collapsed", !item.GetSelected())
|
||||
.ToString();
|
||||
|
||||
/// <summary>
|
||||
/// Refreshes this instance.
|
||||
/// </summary>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using Microsoft.AspNetCore.Components.Web;
|
||||
using Radzen.Blazor.Rendering;
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
@@ -161,32 +162,23 @@ namespace Radzen.Blazor
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override string GetComponentCssClass()
|
||||
{
|
||||
return $"rz-alert rz-alert-{GetAlertSize()} rz-variant-{Enum.GetName(typeof(Variant), Variant).ToLowerInvariant()} rz-{Enum.GetName(typeof(AlertStyle), AlertStyle).ToLowerInvariant()} rz-shade-{Enum.GetName(typeof(Shade), Shade).ToLowerInvariant()}";
|
||||
}
|
||||
protected override string GetComponentCssClass() => ClassList.Create("rz-alert")
|
||||
.Add($"rz-alert-{GetAlertSize()}")
|
||||
.AddVariant(Variant)
|
||||
.Add($"rz-{Enum.GetName(typeof(AlertStyle), AlertStyle).ToLowerInvariant()}")
|
||||
.AddShade(Shade)
|
||||
.ToString();
|
||||
|
||||
string GetIcon()
|
||||
{
|
||||
if (!string.IsNullOrEmpty(Icon))
|
||||
{
|
||||
return Icon;
|
||||
}
|
||||
|
||||
switch (AlertStyle)
|
||||
{
|
||||
case AlertStyle.Success:
|
||||
return "check_circle";
|
||||
case AlertStyle.Danger:
|
||||
return "error";
|
||||
case AlertStyle.Warning:
|
||||
return "warning_amber";
|
||||
case AlertStyle.Info:
|
||||
return "info";
|
||||
default:
|
||||
return "lightbulb";
|
||||
}
|
||||
}
|
||||
string GetIcon() => !string.IsNullOrEmpty(Icon)
|
||||
? Icon
|
||||
: AlertStyle switch
|
||||
{
|
||||
AlertStyle.Success => "check_circle",
|
||||
AlertStyle.Danger => "error",
|
||||
AlertStyle.Warning => "warning_amber",
|
||||
AlertStyle.Info => "info",
|
||||
_ => "lightbulb",
|
||||
};
|
||||
|
||||
async Task OnClose()
|
||||
{
|
||||
@@ -221,4 +213,4 @@ namespace Radzen.Blazor
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -14,7 +14,7 @@
|
||||
<textarea @ref="@search" @attributes="InputAttributes" @onkeydown="@OnFilterKeyPress" value="@Value" disabled="@Disabled"
|
||||
oninput="@OpenScript()" tabindex="@(Disabled ? "-1" : $"{TabIndex}")" @onchange="@OnChange" onfocus="@(OpenOnFocus ? OpenScript() : null)"
|
||||
aria-autocomplete="list" aria-haspopup="true" autocomplete="off" role="combobox"
|
||||
class="@InputClassList" onblur="Radzen.activeElement = null"
|
||||
class=@InputClass onblur="Radzen.activeElement = null"
|
||||
id="@Name" aria-expanded="true" placeholder="@CurrentPlaceholder" maxlength="@MaxLength" />
|
||||
}
|
||||
else
|
||||
@@ -22,7 +22,7 @@
|
||||
<input @ref="@search" @attributes="InputAttributes" @onkeydown="@OnFilterKeyPress" value="@Value" disabled="@Disabled"
|
||||
oninput="@OpenScript()" tabindex="@(Disabled ? "-1" : $"{TabIndex}")" @onchange="@OnChange" onfocus="@(OpenOnFocus ? OpenScript() : null)"
|
||||
aria-autocomplete="list" aria-haspopup="true" autocomplete="off" role="combobox"
|
||||
class="@InputClassList" onblur="Radzen.activeElement = null"
|
||||
class=@InputClass onblur="Radzen.activeElement = null"
|
||||
type="@InputType" id="@Name" aria-expanded="true" placeholder="@CurrentPlaceholder" maxlength="@MaxLength" />
|
||||
}
|
||||
<div id="@PopupID" class="rz-autocomplete-panel" style="@PopupStyle">
|
||||
|
||||
@@ -279,8 +279,9 @@ namespace Radzen.Blazor
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
ClassList InputClassList => ClassList.Create("rz-inputtext rz-autocomplete-input")
|
||||
.AddDisabled(Disabled);
|
||||
string InputClass => ClassList.Create("rz-inputtext rz-autocomplete-input")
|
||||
.AddDisabled(Disabled)
|
||||
.ToString();
|
||||
|
||||
private string OpenScript()
|
||||
{
|
||||
@@ -293,10 +294,7 @@ namespace Radzen.Blazor
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override string GetComponentCssClass()
|
||||
{
|
||||
return GetClassList("rz-autocomplete").ToString();
|
||||
}
|
||||
protected override string GetComponentCssClass() => GetClassList("rz-autocomplete").ToString();
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Dispose()
|
||||
@@ -305,7 +303,7 @@ namespace Radzen.Blazor
|
||||
|
||||
if (IsJSRuntimeAvailable)
|
||||
{
|
||||
JSRuntime.InvokeVoidAsync("Radzen.destroyPopup", PopupID);
|
||||
JSRuntime.InvokeVoid("Radzen.destroyPopup", PopupID);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -364,4 +362,4 @@ namespace Radzen.Blazor
|
||||
await search.FocusAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using System.Collections.Generic;
|
||||
using Radzen.Blazor.Rendering;
|
||||
|
||||
namespace Radzen.Blazor
|
||||
{
|
||||
@@ -14,22 +14,12 @@ namespace Radzen.Blazor
|
||||
public partial class RadzenBadge : RadzenComponent
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override string GetComponentCssClass()
|
||||
{
|
||||
var classList = new List<string>();
|
||||
|
||||
classList.Add("rz-badge");
|
||||
classList.Add($"rz-badge-{BadgeStyle.ToString().ToLowerInvariant()}");
|
||||
classList.Add($"rz-variant-{Variant.ToString().ToLowerInvariant()}");
|
||||
classList.Add($"rz-shade-{Shade.ToString().ToLowerInvariant()}");
|
||||
|
||||
if (IsPill)
|
||||
{
|
||||
classList.Add("rz-badge-pill");
|
||||
}
|
||||
|
||||
return string.Join(" ", classList);
|
||||
}
|
||||
protected override string GetComponentCssClass() => ClassList.Create("rz-badge")
|
||||
.Add($"rz-badge-{BadgeStyle.ToString().ToLowerInvariant()}")
|
||||
.AddVariant(Variant)
|
||||
.AddShade(Shade)
|
||||
.Add("rz-badge-pill", IsPill)
|
||||
.ToString();
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the child content.
|
||||
@@ -73,4 +63,4 @@ namespace Radzen.Blazor
|
||||
[Parameter]
|
||||
public bool IsPill { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -24,13 +24,9 @@ namespace Radzen.Blazor
|
||||
public override string Style { get; set; } = DefaultStyle;
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override string GetComponentCssClass()
|
||||
{
|
||||
var classList = ClassList.Create("rz-body")
|
||||
.Add("rz-body-expanded", Expanded);
|
||||
|
||||
return classList.ToString();
|
||||
}
|
||||
protected override string GetComponentCssClass() => ClassList.Create("rz-body")
|
||||
.Add("rz-body-expanded", Expanded)
|
||||
.ToString();
|
||||
|
||||
/// <summary>
|
||||
/// Toggles this instance width and left margin.
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using Microsoft.AspNetCore.Components.Web;
|
||||
using Radzen.Blazor.Rendering;
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
@@ -15,11 +16,6 @@ namespace Radzen.Blazor
|
||||
/// </example>
|
||||
public partial class RadzenButton : RadzenComponent
|
||||
{
|
||||
internal string getButtonSize()
|
||||
{
|
||||
return Size == ButtonSize.Medium ? "md" : Size == ButtonSize.Large ? "lg" : Size == ButtonSize.Small ? "sm" : "xs";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the child content.
|
||||
/// </summary>
|
||||
@@ -164,9 +160,13 @@ namespace Radzen.Blazor
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override string GetComponentCssClass()
|
||||
{
|
||||
return $"rz-button rz-button-{getButtonSize()} rz-variant-{Enum.GetName(typeof(Variant), Variant).ToLowerInvariant()} rz-{Enum.GetName(typeof(ButtonStyle), ButtonStyle).ToLowerInvariant()} rz-shade-{Enum.GetName(typeof(Shade), Shade).ToLowerInvariant()}{(IsDisabled ? " rz-state-disabled" : "")}{(string.IsNullOrEmpty(Text) && !string.IsNullOrEmpty(Icon) ? " rz-button-icon-only" : "")}";
|
||||
}
|
||||
protected override string GetComponentCssClass() => ClassList.Create("rz-button")
|
||||
.AddButtonSize(Size)
|
||||
.AddVariant(Variant)
|
||||
.AddButtonStyle(ButtonStyle)
|
||||
.AddDisabled(IsDisabled)
|
||||
.AddShade(Shade)
|
||||
.Add($"rz-button-icon-only", string.IsNullOrEmpty(Text) && !string.IsNullOrEmpty(Icon))
|
||||
.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using Microsoft.AspNetCore.Components.Web;
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using System.Collections.Generic;
|
||||
using Radzen.Blazor.Rendering;
|
||||
|
||||
namespace Radzen.Blazor
|
||||
{
|
||||
@@ -12,14 +9,9 @@ namespace Radzen.Blazor
|
||||
public partial class RadzenCard : RadzenComponentWithChildren
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override string GetComponentCssClass()
|
||||
{
|
||||
var classList = new List<string>();
|
||||
classList.Add("rz-card");
|
||||
classList.Add($"rz-variant-{Variant.ToString().ToLowerInvariant()}");
|
||||
|
||||
return string.Join(" ", classList);
|
||||
}
|
||||
protected override string GetComponentCssClass() => ClassList.Create("rz-card")
|
||||
.AddVariant(Variant)
|
||||
.ToString();
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the card variant.
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using Microsoft.AspNetCore.Components.Web;
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using System.Collections.Generic;
|
||||
using Radzen.Blazor.Rendering;
|
||||
|
||||
namespace Radzen.Blazor
|
||||
{
|
||||
@@ -19,17 +16,8 @@ namespace Radzen.Blazor
|
||||
public bool Responsive { get; set; } = true;
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override string GetComponentCssClass()
|
||||
{
|
||||
var classList = new List<string>();
|
||||
classList.Add("rz-card-group");
|
||||
|
||||
if (Responsive)
|
||||
{
|
||||
classList.Add("rz-card-group-responsive");
|
||||
}
|
||||
|
||||
return string.Join(" ", classList);
|
||||
}
|
||||
protected override string GetComponentCssClass() => ClassList.Create("rz-card-group")
|
||||
.Add("rz-card-group-responsive", Responsive)
|
||||
.ToString();
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
@implements IDisposable
|
||||
@inject IJSRuntime JSRuntime
|
||||
|
||||
<li @ref="element" @attributes=@Attributes class=@ClassList tabindex="0">
|
||||
<li @ref="element" @attributes=@Attributes class=@Class tabindex="0">
|
||||
@ChildContent
|
||||
<div class="rz-carousel-snapper"></div>
|
||||
</li>
|
||||
@@ -1,5 +1,4 @@
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using Microsoft.JSInterop;
|
||||
using Radzen.Blazor.Rendering;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
@@ -16,9 +15,9 @@ namespace Radzen.Blazor
|
||||
/// Gets the class list.
|
||||
/// </summary>
|
||||
/// <value>The class list.</value>
|
||||
ClassList ClassList => ClassList.Create()
|
||||
.Add("rz-carousel-item")
|
||||
.Add(Attributes);
|
||||
string Class => ClassList.Create("rz-carousel-item")
|
||||
.Add(Attributes)
|
||||
.ToString();
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the arbitrary attributes.
|
||||
|
||||
@@ -586,7 +586,7 @@ namespace Radzen.Blazor
|
||||
|
||||
if (Visible && IsJSRuntimeAvailable)
|
||||
{
|
||||
JSRuntime.InvokeVoidAsync("Radzen.destroyChart", Element);
|
||||
JSRuntime.InvokeVoid("Radzen.destroyChart", Element);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -6,12 +6,12 @@
|
||||
@if (Visible)
|
||||
{
|
||||
<div @ref="@Element" @attributes="Attributes" class="@GetCssClass()" @onkeypress=@OnKeyPress @onkeypress:preventDefault style="@Style" tabindex="@(Disabled || ReadOnly ? "-1" : $"{TabIndex}")" id="@GetId()">
|
||||
<div class="rz-helper-hidden-accessible">
|
||||
<input type="checkbox" @onchange=@Toggle value=@CheckBoxValue name=@Name id=@Name checked=@CheckBoxChecked aria-checked="@((Value as bool? == true).ToString().ToLowerInvariant())" @attributes="InputAttributes"
|
||||
tabindex="-1" readonly="@ReadOnly">
|
||||
<div class="rz-helper-hidden-accessible">
|
||||
<input type="checkbox" @onchange=@Toggle value=@CheckBoxValue name=@Name id=@Name checked=@CheckBoxChecked aria-checked="@((Value as bool? == true).ToString().ToLowerInvariant())" @attributes="InputAttributes"
|
||||
tabindex="-1" readonly="@ReadOnly">
|
||||
</div>
|
||||
<div class=@BoxClass @onclick=@Toggle @onclick:preventDefault>
|
||||
<span class=@IconClass></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class=@BoxClassList @onclick=@Toggle @onclick:preventDefault>
|
||||
<span class=@IconClassList></span>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
@@ -31,23 +31,22 @@ namespace Radzen.Blazor
|
||||
[Parameter]
|
||||
public bool TriState { get; set; } = false;
|
||||
|
||||
ClassList BoxClassList => ClassList.Create("rz-chkbox-box")
|
||||
.Add("rz-state-active", !object.Equals(Value, false))
|
||||
.AddDisabled(Disabled);
|
||||
string BoxClass => ClassList.Create("rz-chkbox-box")
|
||||
.Add("rz-state-active", !object.Equals(Value, false))
|
||||
.AddDisabled(Disabled)
|
||||
.ToString();
|
||||
|
||||
ClassList IconClassList => ClassList.Create("notranslate rz-chkbox-icon")
|
||||
.Add("rzi rzi-check", object.Equals(Value, true))
|
||||
.Add("rzi rzi-times", object.Equals(Value, null));
|
||||
string IconClass => ClassList.Create("notranslate rz-chkbox-icon")
|
||||
.Add("rzi rzi-check", object.Equals(Value, true))
|
||||
.Add("rzi rzi-times", object.Equals(Value, null))
|
||||
.ToString();
|
||||
|
||||
string CheckBoxValue => CheckBoxChecked ? "true" : "false";
|
||||
|
||||
bool CheckBoxChecked => object.Equals(Value, true);
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override string GetComponentCssClass()
|
||||
{
|
||||
return GetClassList("rz-chkbox").ToString();
|
||||
}
|
||||
protected override string GetComponentCssClass() => GetClassList("rz-chkbox").ToString();
|
||||
|
||||
async Task OnKeyPress(KeyboardEventArgs args)
|
||||
{
|
||||
|
||||
@@ -14,7 +14,9 @@
|
||||
}
|
||||
@if (Visible)
|
||||
{
|
||||
<div @ref="@Element" style="@Style" @attributes="Attributes" class="@GetCssClass()" id="@GetId()">
|
||||
<div @ref="@Element" style="@Style" @attributes="Attributes" class="@GetCssClass()" id="@GetId()"
|
||||
role="checkboxgroup" @onfocus=@OnFocus @onblur=@OnBlur
|
||||
tabindex="@(Disabled ? "-1" : $"{TabIndex}")" @onkeydown="@(args => OnKeyPress(args))" @onkeydown:preventDefault=preventKeyPress @onkeydown:stopPropagation>
|
||||
@if (AllowSelectAll)
|
||||
{
|
||||
<div class="rz-multiselect-header rz-helper-clearfix" @onclick:preventDefault>
|
||||
@@ -23,15 +25,16 @@
|
||||
<RadzenLabel Component="SelectAll" Text="@SelectAllText" class="rz-chkbox-label" />
|
||||
</div>
|
||||
}
|
||||
<RadzenStack Orientation="@Orientation" JustifyContent="@JustifyContent" AlignItems="@AlignItems" Gap="@Gap" Wrap="@Wrap">
|
||||
@foreach (var item in allItems.Where(i => i.Visible))
|
||||
{
|
||||
<div @ref="@item.Element" id="@item.GetItemId()" @onclick="@(args => SelectItem(item))" @attributes="item.Attributes" class="@item.GetItemCssClass()" style="@item.Style">
|
||||
<div class="rz-chkbox" @onkeypress="@(args => OnKeyPress(args, SelectItem(item)))" @onkeypress:preventDefault=preventKeyPress @onkeypress:stopPropagation tabindex="@(Disabled || ReadOnly || item.Disabled || item.ReadOnly ? "-1" : $"{TabIndex}")">
|
||||
<div @ref="@item.Element" id="@item.GetItemId()" @onclick="@(args => SelectItem(item))" @attributes="item.Attributes" class="@item.GetItemCssClass()" style="@item.Style" role="checkbox" aria-checked=@(IsSelected(item)? "true" : "false") aria-label="@item.Text">
|
||||
<div class="rz-chkbox">
|
||||
<div class="rz-helper-hidden-accessible">
|
||||
<input type="checkbox" name="@Name" value="@item.Value" disabled="@Disabled" readonly="@ReadOnly" tabindex="-1" aria-label="@(item.Text + " " + item.Value)" aria-checked="@(IsSelected(item).ToString().ToLowerInvariant())">
|
||||
</div>
|
||||
<div class=@ItemClassList(item)>
|
||||
<span class=@IconClassList(item)></span>
|
||||
<div class=@ItemClass(item)>
|
||||
<span class=@IconClass(item)></span>
|
||||
</div>
|
||||
</div>
|
||||
@if (item.Template != null)
|
||||
@@ -46,5 +49,6 @@
|
||||
}
|
||||
</div>
|
||||
}
|
||||
</RadzenStack>
|
||||
</div>
|
||||
}
|
||||
|
||||
@@ -25,12 +25,15 @@ namespace Radzen.Blazor
|
||||
/// </example>
|
||||
public partial class RadzenCheckBoxList<TValue> : FormComponent<IEnumerable<TValue>>
|
||||
{
|
||||
ClassList ItemClassList(RadzenCheckBoxListItem<TValue> item) => ClassList.Create("rz-chkbox-box")
|
||||
.Add("rz-state-active", IsSelected(item))
|
||||
.AddDisabled(Disabled || item.Disabled);
|
||||
string ItemClass(RadzenCheckBoxListItem<TValue> item) => ClassList.Create("rz-chkbox-box")
|
||||
.Add("rz-state-active", IsSelected(item))
|
||||
.Add("rz-state-focused", IsFocused(item) && focused)
|
||||
.AddDisabled(Disabled || item.Disabled)
|
||||
.ToString();
|
||||
|
||||
ClassList IconClassList(RadzenCheckBoxListItem<TValue> item) => ClassList.Create("rz-chkbox-icon")
|
||||
.Add("notranslate rzi rzi-check", IsSelected(item));
|
||||
string IconClass(RadzenCheckBoxListItem<TValue> item) => ClassList.Create("rz-chkbox-icon")
|
||||
.Add("notranslate rzi rzi-check", IsSelected(item))
|
||||
.ToString();
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the value property.
|
||||
@@ -46,6 +49,34 @@ namespace Radzen.Blazor
|
||||
[Parameter]
|
||||
public string TextProperty { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the content justify.
|
||||
/// </summary>
|
||||
/// <value>The content justify.</value>
|
||||
[Parameter]
|
||||
public JustifyContent JustifyContent { get; set; } = JustifyContent.Start;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the items alignment.
|
||||
/// </summary>
|
||||
/// <value>The items alignment.</value>
|
||||
[Parameter]
|
||||
public AlignItems AlignItems { get; set; } = AlignItems.Start;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the spacing between items
|
||||
/// </summary>
|
||||
/// <value>The spacing between items.</value>
|
||||
[Parameter]
|
||||
public string Gap { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the wrap.
|
||||
/// </summary>
|
||||
/// <value>The wrap.</value>
|
||||
[Parameter]
|
||||
public FlexWrap Wrap { get; set; } = FlexWrap.Wrap;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the disabled property.
|
||||
/// </summary>
|
||||
@@ -60,31 +91,37 @@ namespace Radzen.Blazor
|
||||
[Parameter]
|
||||
public string ReadOnlyProperty { get; set; }
|
||||
|
||||
IEnumerable<RadzenCheckBoxListItem<TValue>> allItems
|
||||
void UpdateAllItems()
|
||||
{
|
||||
get
|
||||
allItems = items.Concat((Data != null ? Data.Cast<object>() : Enumerable.Empty<object>()).Select(i =>
|
||||
{
|
||||
return items.Concat((Data != null ? Data.Cast<object>() : Enumerable.Empty<object>()).Select(i =>
|
||||
var item = new RadzenCheckBoxListItem<TValue>();
|
||||
item.SetText((string)PropertyAccess.GetItemOrValueFromProperty(i, TextProperty));
|
||||
item.SetValue((TValue)PropertyAccess.GetItemOrValueFromProperty(i, ValueProperty));
|
||||
|
||||
if (DisabledProperty != null && PropertyAccess.TryGetItemOrValueFromProperty<bool>(i, DisabledProperty, out var disabledResult))
|
||||
{
|
||||
var item = new RadzenCheckBoxListItem<TValue>();
|
||||
item.SetText((string)PropertyAccess.GetItemOrValueFromProperty(i, TextProperty));
|
||||
item.SetValue((TValue)PropertyAccess.GetItemOrValueFromProperty(i, ValueProperty));
|
||||
item.SetDisabled(disabledResult);
|
||||
}
|
||||
|
||||
if (DisabledProperty != null && PropertyAccess.TryGetItemOrValueFromProperty<bool>(i, DisabledProperty, out var disabledResult))
|
||||
{
|
||||
item.SetDisabled(disabledResult);
|
||||
}
|
||||
if (ReadOnlyProperty != null && PropertyAccess.TryGetItemOrValueFromProperty<bool>(i, ReadOnlyProperty, out var readOnlyResult))
|
||||
{
|
||||
item.SetReadOnly(readOnlyResult);
|
||||
}
|
||||
|
||||
if (ReadOnlyProperty != null && PropertyAccess.TryGetItemOrValueFromProperty<bool>(i, ReadOnlyProperty, out var readOnlyResult))
|
||||
{
|
||||
item.SetReadOnly(readOnlyResult);
|
||||
}
|
||||
|
||||
return item;
|
||||
}));
|
||||
}
|
||||
return item;
|
||||
})).ToList();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void OnParametersSet()
|
||||
{
|
||||
base.OnParametersSet();
|
||||
|
||||
UpdateAllItems();
|
||||
}
|
||||
|
||||
List<RadzenCheckBoxListItem<TValue>> allItems;
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether the user can select all values. Set to <c>false</c> by default.
|
||||
/// </summary>
|
||||
@@ -171,7 +208,7 @@ namespace Radzen.Blazor
|
||||
/// <inheritdoc />
|
||||
protected override string GetComponentCssClass()
|
||||
{
|
||||
return GetClassList(Orientation == Orientation.Horizontal ? "rz-checkbox-list-horizontal" : "rz-checkbox-list-vertical").ToString();
|
||||
return GetClassList("rz-checkbox-list").Add(Orientation == Orientation.Horizontal ? "rz-checkbox-list-horizontal" : "rz-checkbox-list-vertical").ToString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -211,6 +248,7 @@ namespace Radzen.Blazor
|
||||
if (items.IndexOf(item) == -1)
|
||||
{
|
||||
items.Add(item);
|
||||
UpdateAllItems();
|
||||
StateHasChanged();
|
||||
}
|
||||
}
|
||||
@@ -224,6 +262,7 @@ namespace Radzen.Blazor
|
||||
if (items.Contains(item))
|
||||
{
|
||||
items.Remove(item);
|
||||
UpdateAllItems();
|
||||
if (!disposed)
|
||||
{
|
||||
try { InvokeAsync(StateHasChanged); } catch { }
|
||||
@@ -250,6 +289,8 @@ namespace Radzen.Blazor
|
||||
if (Disabled || item.Disabled || ReadOnly || item.ReadOnly)
|
||||
return;
|
||||
|
||||
focusedIndex = allItems.IndexOf(item);
|
||||
|
||||
List<TValue> selectedValues = new List<TValue>(Value != null ? Value : Enumerable.Empty<TValue>());
|
||||
|
||||
if (!selectedValues.Contains(item.Value))
|
||||
@@ -270,21 +311,68 @@ namespace Radzen.Blazor
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
bool focused;
|
||||
int focusedIndex = -1;
|
||||
bool preventKeyPress = true;
|
||||
async Task OnKeyPress(KeyboardEventArgs args, Task task)
|
||||
async Task OnKeyPress(KeyboardEventArgs args)
|
||||
{
|
||||
var key = args.Code != null ? args.Code : args.Key;
|
||||
|
||||
if (key == "Space" || key == "Enter")
|
||||
var item = allItems.ElementAtOrDefault(focusedIndex) ?? allItems.FirstOrDefault();
|
||||
|
||||
if (item == null) return;
|
||||
|
||||
if ((Orientation == Orientation.Horizontal && (key == "ArrowLeft" || key == "ArrowRight")) ||
|
||||
(Orientation == Orientation.Vertical && (key == "ArrowUp" || key == "ArrowDown")))
|
||||
{
|
||||
preventKeyPress = true;
|
||||
var direction = key == "ArrowLeft" || key == "ArrowUp" ? -1 : 1;
|
||||
|
||||
focusedIndex = Math.Clamp(focusedIndex + direction, 0, allItems.FindLastIndex(t => t.Visible && !t.Disabled));
|
||||
|
||||
while (allItems.ElementAtOrDefault(focusedIndex)?.Disabled == true)
|
||||
{
|
||||
focusedIndex = focusedIndex + direction;
|
||||
}
|
||||
}
|
||||
else if (key == "Home" || key == "End")
|
||||
{
|
||||
preventKeyPress = true;
|
||||
|
||||
await task;
|
||||
focusedIndex = key == "Home" ? 0 : allItems.Where(t => HasInvisibleBefore(item) ? true : t.Visible).Count() - 1;
|
||||
}
|
||||
else if (key == "Space" || key == "Enter")
|
||||
{
|
||||
preventKeyPress = true;
|
||||
|
||||
if (focusedIndex >= 0 && focusedIndex < allItems.Where(t => HasInvisibleBefore(item) ? true : t.Visible).Count())
|
||||
{
|
||||
await SelectItem(allItems.Where(t => HasInvisibleBefore(item) ? true : t.Visible).ToList()[focusedIndex]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
preventKeyPress = false;
|
||||
}
|
||||
}
|
||||
|
||||
bool HasInvisibleBefore(RadzenCheckBoxListItem<TValue> item)
|
||||
{
|
||||
return allItems.Take(allItems.IndexOf(item)).Any(t => !t.Visible && !t.Disabled);
|
||||
}
|
||||
|
||||
bool IsFocused(RadzenCheckBoxListItem<TValue> item)
|
||||
{
|
||||
return allItems.IndexOf(item) == focusedIndex;
|
||||
}
|
||||
void OnFocus()
|
||||
{
|
||||
focusedIndex = focusedIndex == -1 ? 0 : focusedIndex;
|
||||
focused = true;
|
||||
}
|
||||
void OnBlur()
|
||||
{
|
||||
focused = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,80 @@
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using Radzen.Blazor.Rendering;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace Radzen.Blazor
|
||||
{
|
||||
static class ClassListExtensions
|
||||
{
|
||||
private static int GetSize(string name, int value)
|
||||
{
|
||||
if (value < 0 || value > 12)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException($"Property {name} value should be between 0 and 12.");
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
private static string GetOrder(string name, string value)
|
||||
{
|
||||
if (int.TryParse(value, out int result))
|
||||
{
|
||||
if (result >= 0 && result <= 12)
|
||||
{
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
if (value == "first" || value == "last")
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
throw new ArgumentOutOfRangeException($"Property {name} value should be between 0 and 12 or first/last.");
|
||||
}
|
||||
|
||||
public static ClassList AddSize(this ClassList classList, string prefix, string name, string size, int? value)
|
||||
{
|
||||
if (value.HasValue)
|
||||
{
|
||||
classList.Add($"rz-{prefix}-{size}-{GetSize(name, value.Value)}");
|
||||
}
|
||||
|
||||
return classList;
|
||||
}
|
||||
|
||||
public static ClassList AddSize(this ClassList classList, string prefix, string name, int? value)
|
||||
{
|
||||
if (value.HasValue)
|
||||
{
|
||||
classList.Add($"rz-{prefix}-{GetSize(name, value.Value)}");
|
||||
}
|
||||
|
||||
return classList;
|
||||
}
|
||||
|
||||
public static ClassList AddOrder(this ClassList classList, string prefix, string name, string size, string value)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(value))
|
||||
{
|
||||
classList.Add($"rz-{prefix}-{size}-{GetOrder(name, value)}");
|
||||
}
|
||||
|
||||
return classList;
|
||||
}
|
||||
|
||||
public static ClassList AddOrder(this ClassList classList, string prefix, string name, string value)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(value))
|
||||
{
|
||||
classList.Add($"rz-{prefix}-{GetOrder(name, value)}");
|
||||
}
|
||||
|
||||
return classList;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// RadzenColumn component.
|
||||
/// </summary>
|
||||
@@ -181,65 +249,29 @@ namespace Radzen.Blazor
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override string GetComponentCssClass()
|
||||
{
|
||||
var list = new List<string>
|
||||
{
|
||||
Size != null ? $"rz-col-{GetColumnValue("Size", Size)}" : "rz-col"
|
||||
};
|
||||
|
||||
if (Offset != null)
|
||||
{
|
||||
list.Add($"rz-offset-{GetColumnValue("Offset", Offset)}");
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(Order))
|
||||
{
|
||||
list.Add($"rz-order-{GetOrderValue("Order", Order)}");
|
||||
}
|
||||
|
||||
var breakPoints = new string[] { "xs", "sm", "md", "lg", "xl", "xx" };
|
||||
|
||||
var properties = GetType().GetProperties()
|
||||
.Where(p => breakPoints.Any(bp => p.Name.ToLower().EndsWith(bp)))
|
||||
.Select(p => new { p.Name, BreakPoint = string.Concat(p.Name.ToLower().TakeLast(2)), Value = p.GetValue(this) });
|
||||
|
||||
foreach (var p in properties)
|
||||
{
|
||||
if (p.Value != null)
|
||||
{
|
||||
list.Add($"rz-{(!p.Name.StartsWith("Size") ? p.Name.ToLower().Replace(p.BreakPoint, "") + "-" : "col-")}{p.BreakPoint}-{GetColumnValue(p.Name, p.Value)}");
|
||||
}
|
||||
}
|
||||
|
||||
return string.Join(" ", list);
|
||||
}
|
||||
|
||||
string GetColumnValue(string name, object value)
|
||||
{
|
||||
if (name.StartsWith("Order"))
|
||||
{
|
||||
return GetOrderValue(name, value.ToString());
|
||||
}
|
||||
|
||||
if ((int)value < 0 || (int)value > 12)
|
||||
{
|
||||
throw new Exception($"Property {name} value should be between 0 and 12.");
|
||||
}
|
||||
|
||||
return $"{value}";
|
||||
}
|
||||
|
||||
string GetOrderValue(string name, string value)
|
||||
{
|
||||
var orders = Enumerable.Range(0, 12).Select(i => $"{i}").ToArray().Concat(new string[] { "first", "last" });
|
||||
|
||||
if (!orders.Contains(value))
|
||||
{
|
||||
throw new Exception($"Property {name} value should be between 0 and 12 or first/last.");
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
protected override string GetComponentCssClass() => ClassList.Create()
|
||||
.Add("rz-col", Size == null)
|
||||
.AddSize("col", nameof(Size), Size)
|
||||
.AddSize("col", nameof(SizeXS), "xs", SizeXS)
|
||||
.AddSize("col", nameof(SizeSM), "sm", SizeSM)
|
||||
.AddSize("col", nameof(SizeMD), "md", SizeMD)
|
||||
.AddSize("col", nameof(SizeLG), "lg", SizeLG)
|
||||
.AddSize("col", nameof(SizeXL), "xl", SizeXL)
|
||||
.AddSize("col", nameof(SizeXX), "xx", SizeXX)
|
||||
.AddSize("offset", nameof(Offset), Offset)
|
||||
.AddSize("offset", nameof(OffsetXS), "xs", OffsetXS)
|
||||
.AddSize("offset", nameof(OffsetSM), "sm", OffsetSM)
|
||||
.AddSize("offset", nameof(OffsetMD), "md", OffsetMD)
|
||||
.AddSize("offset", nameof(OffsetLG), "lg", OffsetLG)
|
||||
.AddSize("offset", nameof(OffsetXL), "xl", OffsetXL)
|
||||
.AddSize("offset", nameof(OffsetXX), "xx", OffsetXX)
|
||||
.AddOrder("order", nameof(Order), Order)
|
||||
.AddOrder("order", nameof(OrderXS), "xs", OrderXS)
|
||||
.AddOrder("order", nameof(OrderSM), "sm", OrderSM)
|
||||
.AddOrder("order", nameof(OrderMD), "md", OrderMD)
|
||||
.AddOrder("order", nameof(OrderLG), "lg", OrderLG)
|
||||
.AddOrder("order", nameof(OrderXL), "xl", OrderXL)
|
||||
.AddOrder("order", nameof(OrderXX), "xx", OrderXX)
|
||||
.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -302,17 +302,17 @@ namespace Radzen
|
||||
{
|
||||
if (ContextMenu.HasDelegate)
|
||||
{
|
||||
JSRuntime.InvokeVoidAsync("Radzen.removeContextMenu", UniqueID);
|
||||
JSRuntime.InvokeVoid("Radzen.removeContextMenu", UniqueID);
|
||||
}
|
||||
|
||||
if (MouseEnter.HasDelegate)
|
||||
{
|
||||
JSRuntime.InvokeVoidAsync("Radzen.removeMouseEnter", UniqueID);
|
||||
JSRuntime.InvokeVoid("Radzen.removeMouseEnter", UniqueID);
|
||||
}
|
||||
|
||||
if (MouseLeave.HasDelegate)
|
||||
{
|
||||
JSRuntime.InvokeVoidAsync("Radzen.removeMouseLeave", UniqueID);
|
||||
JSRuntime.InvokeVoid("Radzen.removeMouseLeave", UniqueID);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -174,7 +174,7 @@ namespace Radzen.Blazor
|
||||
|
||||
void OnNavigate()
|
||||
{
|
||||
JSRuntime.InvokeVoidAsync("Radzen.closePopup", UniqueID);
|
||||
JSRuntime.InvokeVoid("Radzen.closePopup", UniqueID);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
using Microsoft.AspNetCore.Components.Forms;
|
||||
using Microsoft.AspNetCore.Components.Web;
|
||||
using Microsoft.JSInterop;
|
||||
using Radzen.Blazor.Rendering;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
@@ -3303,32 +3304,12 @@ namespace Radzen.Blazor
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override string GetComponentCssClass()
|
||||
{
|
||||
var additionalClasses = new List<string>();
|
||||
|
||||
if (CurrentStyle.ContainsKey("height"))
|
||||
{
|
||||
additionalClasses.Add("rz-has-height");
|
||||
}
|
||||
|
||||
if (RowSelect.HasDelegate || ValueChanged.HasDelegate || SelectionMode == DataGridSelectionMode.Multiple)
|
||||
{
|
||||
additionalClasses.Add("rz-selectable");
|
||||
}
|
||||
|
||||
if (Responsive)
|
||||
{
|
||||
additionalClasses.Add("rz-datatable-reflow");
|
||||
}
|
||||
|
||||
if (Density == Density.Compact)
|
||||
{
|
||||
additionalClasses.Add("rz-density-compact");
|
||||
}
|
||||
|
||||
return $"rz-has-pager rz-datatable rz-datatable-scrollable {String.Join(" ", additionalClasses)}";
|
||||
}
|
||||
protected override string GetComponentCssClass() => ClassList.Create("rz-has-pager rz-datatable rz-datatable-scrollable")
|
||||
.Add("rz-has-height", CurrentStyle.ContainsKey("height"))
|
||||
.Add("rz-datatable-reflow", Responsive)
|
||||
.Add("rz-density-compact", Density == Density.Compact)
|
||||
.Add("rz-selectable", RowSelect.HasDelegate || ValueChanged.HasDelegate || SelectionMode == DataGridSelectionMode.Multiple)
|
||||
.ToString();
|
||||
|
||||
internal string getHeaderStyle()
|
||||
{
|
||||
@@ -3364,7 +3345,7 @@ namespace Radzen.Blazor
|
||||
{
|
||||
foreach (var column in allColumns.ToList().Where(c => c.GetVisible()))
|
||||
{
|
||||
JSRuntime.InvokeVoidAsync("Radzen.destroyPopup", $"{PopupID}{column.GetFilterProperty()}");
|
||||
JSRuntime.InvokeVoid("Radzen.destroyPopup", $"{PopupID}{column.GetFilterProperty()}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1161,8 +1161,8 @@ namespace Radzen.Blazor
|
||||
|
||||
if (IsJSRuntimeAvailable)
|
||||
{
|
||||
JSRuntime.InvokeVoidAsync("Radzen.destroyPopup", PopupID);
|
||||
JSRuntime.InvokeVoidAsync("Radzen.destroyDatePicker", UniqueID, Element);
|
||||
JSRuntime.InvokeVoid("Radzen.destroyPopup", PopupID);
|
||||
JSRuntime.InvokeVoid("Radzen.destroyDatePicker", UniqueID, Element);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -126,10 +126,28 @@
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
bool sideDialogClosing = false;
|
||||
|
||||
async Task OnSideCloseAsync()
|
||||
{
|
||||
sideDialogClosing = true;
|
||||
|
||||
StateHasChanged();
|
||||
|
||||
await Task.Delay(300);
|
||||
|
||||
isSideDialogOpen = false;
|
||||
sideDialogClosing = false;
|
||||
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
void OnSideClose(dynamic _)
|
||||
{
|
||||
isSideDialogOpen = false;
|
||||
StateHasChanged();
|
||||
if (isSideDialogOpen)
|
||||
{
|
||||
InvokeAsync(OnSideCloseAsync);
|
||||
}
|
||||
}
|
||||
|
||||
void OnOpen(string title, Type type, Dictionary<string, object> parameters, DialogOptions options)
|
||||
@@ -142,10 +160,12 @@
|
||||
Close(result).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
string GetSideDialogCssClass()
|
||||
{
|
||||
return $"rz-dialog-side rz-dialog-side-position-{sideDialogOptions.Position.ToString().ToLower()} {sideDialogOptions.CssClass}";
|
||||
}
|
||||
string GetSideDialogCssClass() => ClassList.Create("rz-dialog-side")
|
||||
.Add($"rz-dialog-side-position-{sideDialogOptions.Position.ToString().ToLower()}")
|
||||
.Add(sideDialogOptions.CssClass)
|
||||
.Add("rz-open", !sideDialogClosing)
|
||||
.Add("rz-close", sideDialogClosing)
|
||||
.ToString();
|
||||
|
||||
string GetSideDialogStyle()
|
||||
{
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
@if (Visible)
|
||||
{
|
||||
<div @ref="@Element" @attributes="Attributes" class="@GetCssClass()" onmousedown="Radzen.activeElement = null" @onclick="@(args => OpenPopup("ArrowDown", false, true))" @onclick:preventDefault @onclick:stopPropagation style="@Style" tabindex="@(Disabled ? "-1" : $"{TabIndex}")"
|
||||
@onkeydown="@((args) => OnKeyPress(args))" @onkeydown:preventDefault="@preventKeydown" id="@GetId()" @onfocus="@((args) => OnFocus(args))">
|
||||
@onkeydown="@((args) => OnKeyPress(args))" @onkeydown:preventDefault="@preventKeydown" id="@GetId()" @onfocus=@this.AsNonRenderingEventHandler(OnFocus)>
|
||||
<div class="rz-helper-hidden-accessible">
|
||||
<input disabled="@Disabled" aria-haspopup="listbox" readonly="" type="text" tabindex="-1"
|
||||
name="@Name" value="@(internalValue != null ? internalValue : "")" id="@Name"
|
||||
|
||||
@@ -102,7 +102,7 @@ namespace Radzen.Blazor
|
||||
return args;
|
||||
}
|
||||
|
||||
private async Task OnFocus(Microsoft.AspNetCore.Components.Web.FocusEventArgs args)
|
||||
private async Task OnFocus()
|
||||
{
|
||||
if (OpenOnFocus)
|
||||
{
|
||||
@@ -360,7 +360,7 @@ namespace Radzen.Blazor
|
||||
|
||||
if (IsJSRuntimeAvailable)
|
||||
{
|
||||
JSRuntime.InvokeVoidAsync("Radzen.destroyPopup", PopupID);
|
||||
JSRuntime.InvokeVoid("Radzen.destroyPopup", PopupID);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
@if (Visible)
|
||||
{
|
||||
<div @ref="@Element" @attributes="Attributes" class="@GetCssClass()" @onfocus="@((args) => OnFocus(args))"
|
||||
<div @ref="@Element" @attributes="Attributes" class="@GetCssClass()" @onfocus=@this.AsNonRenderingEventHandler(OnFocus)
|
||||
style="@Style" tabindex="@(Disabled ? "-1" : $"{TabIndex}")" id="@GetId()" @onclick="@(args => OpenPopup("ArrowDown", false, true))" @onclick:preventDefault @onclick:stopPropagation
|
||||
@onkeydown="@((args) => OnKeyPress(args))" @onkeydown:preventDefault="@preventKeydown">
|
||||
<div class="rz-helper-hidden-accessible">
|
||||
|
||||
@@ -97,7 +97,7 @@ namespace Radzen.Blazor
|
||||
[Parameter]
|
||||
public bool OpenOnFocus { get; set; }
|
||||
|
||||
private async Task OnFocus(Microsoft.AspNetCore.Components.Web.FocusEventArgs args)
|
||||
private async Task OnFocus()
|
||||
{
|
||||
if (OpenOnFocus)
|
||||
{
|
||||
@@ -994,7 +994,7 @@ namespace Radzen.Blazor
|
||||
|
||||
if (IsJSRuntimeAvailable)
|
||||
{
|
||||
JSRuntime.InvokeVoidAsync("Radzen.destroyPopup", PopupID);
|
||||
JSRuntime.InvokeVoid("Radzen.destroyPopup", PopupID);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
@inherits RadzenComponent
|
||||
@using Radzen.Blazor.Rendering
|
||||
@inherits RadzenComponent
|
||||
|
||||
@if (Visible)
|
||||
{
|
||||
@@ -6,7 +7,6 @@
|
||||
@if(AllowCollapse || !string.IsNullOrEmpty(Text) || !string.IsNullOrEmpty(Icon) || HeaderTemplate != null)
|
||||
{
|
||||
<legend class="rz-fieldset-legend" style="white-space:nowrap">
|
||||
|
||||
@if (AllowCollapse)
|
||||
{
|
||||
<a id="@(GetId() + "expc")" title="@TitleAttribute()" aria-label="@AriaLabelAttribute()" @onclick:preventDefault="true"
|
||||
@@ -46,18 +46,18 @@
|
||||
}
|
||||
</legend>
|
||||
}
|
||||
<div class="rz-fieldset-content-wrapper" role="region" id="rz-fieldset-0-content" aria-hidden="false" style="@contentStyle">
|
||||
<Expander Expanded=@(!collapsed) CssClass="rz-fieldset-content-wrapper" id="rz-fieldset-0-content">
|
||||
<div class="rz-fieldset-content">
|
||||
@ChildContent
|
||||
</div>
|
||||
</div>
|
||||
</Expander>
|
||||
@if (SummaryTemplate != null)
|
||||
{
|
||||
<div class="rz-fieldset-content-wrapper" role="region" aria-hidden="false" style="@summaryContentStyle">
|
||||
<div class="rz-fieldset-content rz-fieldset-content-summary">
|
||||
@SummaryTemplate
|
||||
</div>
|
||||
<Expander Expanded=@collapsed CssClass="rz-fieldset-content-wrapper">
|
||||
<div class="rz-fieldset-content rz-fieldset-content-summary">
|
||||
@SummaryTemplate
|
||||
</div>
|
||||
</Expander>
|
||||
}
|
||||
</fieldset>
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using Microsoft.AspNetCore.Components.Web;
|
||||
using Radzen.Blazor.Rendering;
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
@@ -26,10 +27,10 @@ namespace Radzen.Blazor
|
||||
public partial class RadzenFieldset : RadzenComponent
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override string GetComponentCssClass()
|
||||
{
|
||||
return AllowCollapse ? "rz-fieldset rz-fieldset-toggleable" : "rz-fieldset";
|
||||
}
|
||||
protected override string GetComponentCssClass() =>
|
||||
ClassList.Create("rz-fieldset")
|
||||
.Add("rz-fieldset-toggleable", AllowCollapse)
|
||||
.ToString();
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether collapsing is allowed. Set to <c>false</c> by default.
|
||||
@@ -131,14 +132,9 @@ namespace Radzen.Blazor
|
||||
[Parameter]
|
||||
public EventCallback Collapse { get; set; }
|
||||
|
||||
string contentStyle = "";
|
||||
string summaryContentStyle = "display: none";
|
||||
|
||||
async System.Threading.Tasks.Task Toggle(EventArgs args)
|
||||
async Task Toggle(EventArgs args)
|
||||
{
|
||||
collapsed = !collapsed;
|
||||
contentStyle = collapsed ? "display: none;" : "";
|
||||
summaryContentStyle = !collapsed ? "display: none" : "";
|
||||
|
||||
if (collapsed)
|
||||
{
|
||||
@@ -188,15 +184,6 @@ namespace Radzen.Blazor
|
||||
await base.SetParametersAsync(parameters);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override Task OnParametersSetAsync()
|
||||
{
|
||||
contentStyle = collapsed ? "display: none;" : "";
|
||||
summaryContentStyle = !collapsed ? "display: none" : "";
|
||||
|
||||
return base.OnParametersSetAsync();
|
||||
}
|
||||
|
||||
bool preventKeyPress = false;
|
||||
async Task OnKeyPress(KeyboardEventArgs args, Task task)
|
||||
{
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
{
|
||||
<div @ref="@Element" style="@Style" @attributes="Attributes" class="@GetCssClass()" id="@GetId()">
|
||||
<div class="rz-fileupload-buttonbar">
|
||||
<span class="@ChooseClassList" tabindex="@(Disabled ? "-1" : $"{TabIndex}")" onkeydown="if(event.keyCode == 32 || event.keyCode == 13){event.preventDefault();this.firstElementChild.click();}">
|
||||
<span class=@ChooseClass tabindex="@(Disabled ? "-1" : $"{TabIndex}")" onkeydown="if(event.keyCode == 32 || event.keyCode == 13){event.preventDefault();this.firstElementChild.click();}">
|
||||
<input id="@(Name ?? GetId())" @attributes="InputAttributes" tabindex="-1" disabled="@Disabled" @ref="@fileUpload" name="@Name" type="file" accept="@Accept" onkeydown="event.stopPropagation()"
|
||||
onchange="Radzen.uploadInputChange(event, null, false, false, true)" />
|
||||
<span class="rz-button-text">@ChooseText</span>
|
||||
@@ -43,7 +43,7 @@
|
||||
}
|
||||
</div>
|
||||
<div>
|
||||
<button disabled="@Disabled" type="button" class="@ButtonClassList" @onclick="@Remove" title="@DeleteText" tabindex="@(Disabled ? "-1" : $"{TabIndex}")">
|
||||
<button disabled="@Disabled" type="button" class=@ButtonClass @onclick="@Remove" title="@DeleteText" tabindex="@(Disabled ? "-1" : $"{TabIndex}")">
|
||||
<span class="rz-button-icon-left rz-icon-trash" style="display:block"></span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@@ -55,24 +55,15 @@ namespace Radzen.Blazor
|
||||
[Parameter]
|
||||
public string Title { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the choose class list.
|
||||
/// </summary>
|
||||
/// <value>The choose class list.</value>
|
||||
ClassList ChooseClassList => ClassList.Create("rz-fileupload-choose rz-button rz-secondary")
|
||||
.AddDisabled(Disabled);
|
||||
/// <summary>
|
||||
/// Gets the button class list.
|
||||
/// </summary>
|
||||
/// <value>The button class list.</value>
|
||||
ClassList ButtonClassList => ClassList.Create("rz-button rz-button-icon-only rz-base rz-shade-default")
|
||||
.AddDisabled(Disabled);
|
||||
string ChooseClass => ClassList.Create("rz-fileupload-choose rz-button rz-secondary")
|
||||
.AddDisabled(Disabled)
|
||||
.ToString();
|
||||
string ButtonClass => ClassList.Create("rz-button rz-button-icon-only rz-base rz-shade-default")
|
||||
.AddDisabled(Disabled)
|
||||
.ToString();
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override string GetComponentCssClass()
|
||||
{
|
||||
return GetClassList("rz-fileupload").ToString();
|
||||
}
|
||||
protected override string GetComponentCssClass() => GetClassList("rz-fileupload").ToString();
|
||||
|
||||
/// <summary>
|
||||
/// Gets file input reference.
|
||||
|
||||
@@ -167,9 +167,10 @@ namespace Radzen.Blazor
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override string GetComponentCssClass()
|
||||
{
|
||||
return ClassList.Create($"rz-form-field rz-variant-{Enum.GetName(typeof(Variant), Variant).ToLowerInvariant()}").AddDisabled(disabled).Add("rz-floating-label", AllowFloatingLabel == true).ToString();
|
||||
}
|
||||
protected override string GetComponentCssClass() => ClassList.Create("rz-form-field")
|
||||
.AddVariant(Variant)
|
||||
.AddDisabled(disabled)
|
||||
.Add("rz-floating-label", AllowFloatingLabel)
|
||||
.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -223,7 +223,7 @@ namespace Radzen.Blazor
|
||||
|
||||
if (IsJSRuntimeAvailable)
|
||||
{
|
||||
JSRuntime.InvokeVoidAsync("Radzen.destroyMap", UniqueID);
|
||||
JSRuntime.InvokeVoid("Radzen.destroyMap", UniqueID);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -432,7 +432,7 @@ namespace Radzen.Blazor
|
||||
|
||||
if (Visible && IsJSRuntimeAvailable)
|
||||
{
|
||||
JSRuntime.InvokeVoidAsync("Radzen.destroyEditor", ContentEditable);
|
||||
JSRuntime.InvokeVoid("Radzen.destroyEditor", ContentEditable);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -34,16 +34,8 @@ namespace Radzen.Blazor
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override string GetComponentCssClass()
|
||||
{
|
||||
var classList = ClassList.Create("rz-layout");
|
||||
|
||||
if (themeService != null)
|
||||
{
|
||||
classList.Add($"rz-{themeService.Theme}");
|
||||
}
|
||||
|
||||
return classList.ToString();
|
||||
}
|
||||
protected override string GetComponentCssClass() => ClassList.Create("rz-layout")
|
||||
.Add($"rz-{themeService.Theme}", themeService != null)
|
||||
.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
{
|
||||
<ul @ref=@Element style=@Style @attributes=@Attributes class=@GetCssClass() id=@GetId()
|
||||
tabindex="0" @onkeydown="@OnKeyPress" @onkeydown:preventDefault=preventKeyPress @onkeydown:stopPropagation
|
||||
@onfocus=@(args => {focusedIndex = focusedIndex == -1 ? 0: focusedIndex; currentItems = items.Where(i => i.Visible && !i.Disabled).ToList();})>
|
||||
@onfocus=@this.AsNonRenderingEventHandler(OnFocus)>
|
||||
@if (Responsive)
|
||||
{
|
||||
<li class="rz-menu-toggle-item">
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using Microsoft.AspNetCore.Components.Web;
|
||||
using Microsoft.JSInterop;
|
||||
using Radzen.Blazor.Rendering;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
@@ -40,26 +40,10 @@ namespace Radzen.Blazor
|
||||
private bool IsOpen { get; set; } = false;
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override string GetComponentCssClass()
|
||||
{
|
||||
var classList = new List<string>();
|
||||
|
||||
classList.Add("rz-menu");
|
||||
|
||||
if (Responsive)
|
||||
{
|
||||
if (IsOpen)
|
||||
{
|
||||
classList.Add("rz-menu-open");
|
||||
}
|
||||
else
|
||||
{
|
||||
classList.Add("rz-menu-closed");
|
||||
}
|
||||
}
|
||||
|
||||
return string.Join(" ", classList);
|
||||
}
|
||||
protected override string GetComponentCssClass() => ClassList.Create("rz-menu")
|
||||
.Add("rz-menu-open", Responsive && IsOpen)
|
||||
.Add("rz-menu-closed", Responsive && !IsOpen)
|
||||
.ToString();
|
||||
|
||||
void OnToggle()
|
||||
{
|
||||
@@ -73,7 +57,6 @@ namespace Radzen.Blazor
|
||||
[Parameter]
|
||||
public EventCallback<MenuItemEventArgs> Click { get; set; }
|
||||
|
||||
|
||||
[Inject]
|
||||
NavigationManager NavigationManager { get; set; }
|
||||
|
||||
@@ -244,5 +227,10 @@ namespace Radzen.Blazor
|
||||
base.Dispose();
|
||||
NavigationManager.LocationChanged -= OnLocationChanged;
|
||||
}
|
||||
|
||||
void OnFocus()
|
||||
{
|
||||
focusedIndex = focusedIndex == -1 ? 0 : focusedIndex;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,7 +5,7 @@
|
||||
{
|
||||
var classes = GetMessageCssClasses();
|
||||
|
||||
<div aria-live="polite" class="rz-notification-item-wrapper @classes.Item1" style="@(Message.Click != null || Message.CloseOnClick ? "cursor: pointer;" : "") @Style">
|
||||
<div aria-live="polite" class="rz-notification-item-wrapper rz-open @classes.Item1" style="@(Message.Click != null || Message.CloseOnClick ? "cursor: pointer;" : "") @Style">
|
||||
<div class="rz-notification-item">
|
||||
<div class="rz-notification-message-wrapper">
|
||||
<span class="notranslate rzi rz-notification-icon @classes.Item2" @onclick="NotificationClicked"></span>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
{
|
||||
<div @ref="@Element" @attributes="Attributes" class="@GetCssClass()" style="@Style" id="@GetId()"
|
||||
@onkeydown="@OnKeyDown" @onkeydown:preventDefault="preventKeyDown" @onkeydown:stopPropagation="true" tabindex=0
|
||||
@onfocus=@OnFocus>
|
||||
@onfocus=@this.AsNonRenderingEventHandler(OnFocus)>
|
||||
@if(ShowPagingSummary)
|
||||
{
|
||||
<span class="rz-pager-summary">
|
||||
|
||||
@@ -5,6 +5,7 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.JSInterop;
|
||||
using Radzen.Blazor.Rendering;
|
||||
|
||||
namespace Radzen.Blazor
|
||||
{
|
||||
@@ -18,26 +19,11 @@ namespace Radzen.Blazor
|
||||
/// </example>
|
||||
public partial class RadzenPager : RadzenComponent
|
||||
{
|
||||
static readonly IDictionary<HorizontalAlign, string> HorizontalAlignCssClasses = new Dictionary<HorizontalAlign, string>
|
||||
{
|
||||
{HorizontalAlign.Center, "rz-align-center"},
|
||||
{HorizontalAlign.Left, "rz-align-left"},
|
||||
{HorizontalAlign.Right, "rz-align-right"},
|
||||
{HorizontalAlign.Justify, "rz-align-justify"}
|
||||
};
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override string GetComponentCssClass()
|
||||
{
|
||||
var additionalClasses = new List<string>();
|
||||
|
||||
if (Density == Density.Compact)
|
||||
{
|
||||
additionalClasses.Add("rz-density-compact");
|
||||
}
|
||||
|
||||
return $"rz-pager rz-unselectable-text rz-helper-clearfix {HorizontalAlignCssClasses[HorizontalAlign]} {String.Join(" ", additionalClasses)}";
|
||||
}
|
||||
protected override string GetComponentCssClass() => ClassList.Create("rz-pager rz-unselectable-text rz-helper-clearfix")
|
||||
.Add("rz-density-compact", Density == Density.Compact)
|
||||
.AddHorizontalAlign(HorizontalAlign)
|
||||
.ToString();
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the pager's first page button's title attribute.
|
||||
@@ -550,7 +536,7 @@ namespace Radzen.Blazor
|
||||
|
||||
bool shouldFocus;
|
||||
|
||||
void OnFocus(FocusEventArgs args)
|
||||
void OnFocus()
|
||||
{
|
||||
focusedIndex = focusedIndex == -3 ? 0 : focusedIndex;
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
@inherits RadzenComponentWithChildren
|
||||
@using Radzen.Blazor.Rendering
|
||||
@inherits RadzenComponentWithChildren
|
||||
@if (Visible)
|
||||
{
|
||||
<div @ref="@Element" style="@Style" @attributes="Attributes" class="@GetCssClass()" id="@GetId()">
|
||||
@@ -27,7 +28,7 @@
|
||||
</a>
|
||||
}
|
||||
</div>
|
||||
<div class="rz-panel-content-wrapper" role="region" aria-hidden="false" style="@contentStyle">
|
||||
<Expander Expanded=@(!collapsed) CssClass="rz-panel-content-wrapper">
|
||||
<div class="rz-panel-content">
|
||||
@ChildContent
|
||||
</div>
|
||||
@@ -37,14 +38,14 @@
|
||||
@FooterTemplate
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</Expander>
|
||||
@if (SummaryTemplate != null)
|
||||
{
|
||||
<div class="rz-panel-content-wrapper" role="region" aria-hidden="false" style="@summaryContentStyle">
|
||||
<Expander Expanded=@collapsed>
|
||||
<div class="rz-panel-content rz-panel-content-summary">
|
||||
@SummaryTemplate
|
||||
</div>
|
||||
</div>
|
||||
</Expander>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using Microsoft.AspNetCore.Components.Web;
|
||||
using Radzen.Blazor.Rendering;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Radzen.Blazor
|
||||
@@ -130,14 +131,9 @@ namespace Radzen.Blazor
|
||||
[Parameter]
|
||||
public string CollapseAriaLabel { get; set; } = null;
|
||||
|
||||
string contentStyle = "display: block;";
|
||||
string summaryContentStyle = "display: none";
|
||||
|
||||
async System.Threading.Tasks.Task Toggle(MouseEventArgs args)
|
||||
async Task Toggle(MouseEventArgs args)
|
||||
{
|
||||
collapsed = !collapsed;
|
||||
contentStyle = collapsed ? "display: none;" : "display: block;";
|
||||
summaryContentStyle = !collapsed ? "display: none" : "display: block";
|
||||
|
||||
if (collapsed)
|
||||
{
|
||||
@@ -150,6 +146,15 @@ namespace Radzen.Blazor
|
||||
|
||||
StateHasChanged();
|
||||
}
|
||||
string ContentClass => ClassList.Create("rz-panel-content-wrapper")
|
||||
.Add("rz-open", !collapsed)
|
||||
.Add("rz-close", collapsed)
|
||||
.ToString();
|
||||
|
||||
string SummaryClass => ClassList.Create("rz-panel-content-wrapper")
|
||||
.Add("rz-open", collapsed)
|
||||
.Add("rz-close", !collapsed)
|
||||
.ToString();
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void OnInitialized()
|
||||
@@ -169,18 +174,6 @@ namespace Radzen.Blazor
|
||||
await base.SetParametersAsync(parameters);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called when parameters set asynchronous.
|
||||
/// </summary>
|
||||
/// <returns>Task.</returns>
|
||||
protected override Task OnParametersSetAsync()
|
||||
{
|
||||
contentStyle = collapsed ? "display: none;" : "display: block;";
|
||||
summaryContentStyle = !collapsed ? "display: none" : "display: block";
|
||||
|
||||
return base.OnParametersSetAsync();
|
||||
}
|
||||
|
||||
bool preventKeyPress = false;
|
||||
async Task OnKeyPress(KeyboardEventArgs args, Task task)
|
||||
{
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
@inherits RadzenComponentWithChildren
|
||||
@inject NavigationManager UriHelper
|
||||
|
||||
@if (Visible)
|
||||
{
|
||||
<ul @ref="@Element" style="@Style" @attributes="Attributes" class="@GetCssClass()" id="@GetId()"
|
||||
tabindex="0" @onkeydown="@OnKeyPress" @onkeydown:preventDefault=preventKeyPress @onkeydown:stopPropagation
|
||||
@onfocus=@(args => { focusedIndex = focusedIndex == -1 ? 0: focusedIndex; currentItems = currentItems != null ? currentItems : items.Where(i => i.Visible).ToList();})>
|
||||
<ul @ref=@Element style=@Style @attributes=@Attributes class=@GetCssClass() id=@GetId() tabindex="0"
|
||||
@onkeydown=@OnKeyPress
|
||||
@onkeydown:preventDefault=preventKeyPress @onkeydown:stopPropagation
|
||||
@onfocus=@this.AsNonRenderingEventHandler(OnFocus)>
|
||||
<CascadingValue Value=this>
|
||||
@ChildContent
|
||||
</CascadingValue>
|
||||
</ul>
|
||||
}
|
||||
}
|
||||
@@ -56,7 +56,6 @@ namespace Radzen.Blazor
|
||||
[Parameter]
|
||||
public bool ShowArrow { get; set; } = true;
|
||||
|
||||
|
||||
internal List<RadzenPanelMenuItem> items = new List<RadzenPanelMenuItem>();
|
||||
|
||||
/// <summary>
|
||||
@@ -65,36 +64,12 @@ namespace Radzen.Blazor
|
||||
/// <param name="item">The item.</param>
|
||||
public void AddItem(RadzenPanelMenuItem item)
|
||||
{
|
||||
if (items.IndexOf(item) == -1)
|
||||
if (!items.Contains(item))
|
||||
{
|
||||
items.Add(item);
|
||||
SelectItem(item);
|
||||
StateHasChanged();
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
UriHelper.LocationChanged += UriHelper_OnLocationChanged;
|
||||
}
|
||||
|
||||
private void UriHelper_OnLocationChanged(object sender, Microsoft.AspNetCore.Components.Routing.LocationChangedEventArgs e)
|
||||
{
|
||||
var allExpandedItems = items.Concat(items.SelectManyRecursive(i => i.ExpandedInternal ? i.items : Enumerable.Empty<RadzenPanelMenuItem>()));
|
||||
foreach (var item in allExpandedItems)
|
||||
{
|
||||
SelectItem(item);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Dispose()
|
||||
{
|
||||
base.Dispose();
|
||||
UriHelper.LocationChanged -= UriHelper_OnLocationChanged;
|
||||
}
|
||||
|
||||
internal void CollapseAll(IEnumerable<RadzenPanelMenuItem> itemsToSkip)
|
||||
{
|
||||
items.Concat(items.SelectManyRecursive(i => i.items))
|
||||
@@ -112,85 +87,6 @@ namespace Radzen.Blazor
|
||||
await base.SetParametersAsync(parameters);
|
||||
}
|
||||
|
||||
bool ShouldMatch(RadzenPanelMenuItem item)
|
||||
{
|
||||
if (string.IsNullOrEmpty(item.Path))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
var currentAbsoluteUrl = UriHelper.ToAbsoluteUri(UriHelper.Uri).AbsoluteUri;
|
||||
var absoluteUrl = UriHelper.ToAbsoluteUri(item.Path).AbsoluteUri;
|
||||
|
||||
if (EqualsHrefExactlyOrIfTrailingSlashAdded(absoluteUrl, currentAbsoluteUrl))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (item.Path == "/")
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var match = item.Match != NavLinkMatch.Prefix ? item.Match : Match;
|
||||
|
||||
if (match == NavLinkMatch.Prefix && IsStrictlyPrefixWithSeparator(currentAbsoluteUrl, absoluteUrl))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static bool EqualsHrefExactlyOrIfTrailingSlashAdded(string absoluteUrl, string currentAbsoluteUrl)
|
||||
{
|
||||
if (string.Equals(currentAbsoluteUrl, absoluteUrl, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (currentAbsoluteUrl.Length == absoluteUrl.Length - 1)
|
||||
{
|
||||
if (absoluteUrl[absoluteUrl.Length - 1] == '/'
|
||||
&& absoluteUrl.StartsWith(currentAbsoluteUrl, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static bool IsSeparator(char c)
|
||||
{
|
||||
return c == '?' || c == '/' || c == '#';
|
||||
}
|
||||
|
||||
private static bool IsStrictlyPrefixWithSeparator(string value, string prefix)
|
||||
{
|
||||
var prefixLength = prefix.Length;
|
||||
if (value.Length > prefixLength)
|
||||
{
|
||||
return value.StartsWith(prefix, StringComparison.OrdinalIgnoreCase)
|
||||
&& (
|
||||
prefixLength == 0
|
||||
|| IsSeparator(prefix[prefixLength - 1])
|
||||
|| IsSeparator(value[prefixLength])
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
internal void SelectItem(RadzenPanelMenuItem item)
|
||||
{
|
||||
var selected = ShouldMatch(item);
|
||||
item.Select(selected);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override string GetComponentCssClass()
|
||||
{
|
||||
@@ -204,14 +100,12 @@ namespace Radzen.Blazor
|
||||
List<RadzenPanelMenuItem> currentItems;
|
||||
|
||||
bool preventKeyPress = false;
|
||||
|
||||
async Task OnKeyPress(KeyboardEventArgs args)
|
||||
{
|
||||
var key = args.Code != null ? args.Code : args.Key;
|
||||
var key = args.Code ?? args.Key;
|
||||
|
||||
if (currentItems == null)
|
||||
{
|
||||
currentItems = items.Where(i => i.Visible).ToList();
|
||||
}
|
||||
currentItems ??= [.. items.Where(i => i.Visible)];
|
||||
|
||||
if (key == "ArrowUp" || key == "ArrowDown")
|
||||
{
|
||||
@@ -223,8 +117,8 @@ namespace Radzen.Blazor
|
||||
currentItems = (parentItem.ParentItem != null ? parentItem.ParentItem.items : parentItem.Parent.items).ToList();
|
||||
focusedIndex = currentItems.IndexOf(parentItem);
|
||||
}
|
||||
else if (key == "ArrowDown" && currentItems.ElementAtOrDefault(focusedIndex) != null &&
|
||||
currentItems.ElementAtOrDefault(focusedIndex).ExpandedInternal && currentItems.ElementAtOrDefault(focusedIndex).items.Any())
|
||||
else if (key == "ArrowDown" && currentItems.ElementAtOrDefault(focusedIndex) != null &&
|
||||
currentItems.ElementAtOrDefault(focusedIndex).IsExpanded && currentItems.ElementAtOrDefault(focusedIndex).items.Any())
|
||||
{
|
||||
currentItems = currentItems.ElementAtOrDefault(focusedIndex).items.Where(i => i.Visible).ToList();
|
||||
focusedIndex = 0;
|
||||
@@ -236,7 +130,7 @@ namespace Radzen.Blazor
|
||||
focusedIndex = parentItem != null ? currentItems.IndexOf(parentItem) + 1 : focusedIndex;
|
||||
}
|
||||
else if (key == "ArrowUp" && currentItems.ElementAtOrDefault(focusedIndex - 1) != null &&
|
||||
currentItems.ElementAtOrDefault(focusedIndex - 1).ExpandedInternal && currentItems.ElementAtOrDefault(focusedIndex - 1).items.Any())
|
||||
currentItems.ElementAtOrDefault(focusedIndex - 1).IsExpanded && currentItems.ElementAtOrDefault(focusedIndex - 1).items.Any())
|
||||
{
|
||||
currentItems = currentItems.ElementAtOrDefault(focusedIndex - 1).items.Where(i => i.Visible).ToList();
|
||||
focusedIndex = currentItems.Count - 1;
|
||||
@@ -261,15 +155,15 @@ namespace Radzen.Blazor
|
||||
{
|
||||
var item = currentItems[focusedIndex];
|
||||
|
||||
if (item.items.Any())
|
||||
if (item.items.Count > 0)
|
||||
{
|
||||
await item.Toggle();
|
||||
|
||||
currentItems = (item.ExpandedInternal ?
|
||||
currentItems = (item.IsExpanded ?
|
||||
item.items :
|
||||
item.ParentItem != null ? item.ParentItem.items : item.Parent.items).Where(i => i.Visible).ToList();
|
||||
|
||||
focusedIndex = item.ExpandedInternal ? 0 : currentItems.IndexOf(item);
|
||||
focusedIndex = item.IsExpanded ? 0 : currentItems.IndexOf(item);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -288,6 +182,11 @@ namespace Radzen.Blazor
|
||||
{
|
||||
preventKeyPress = false;
|
||||
}
|
||||
|
||||
if (preventKeyPress)
|
||||
{
|
||||
StateHasChanged();
|
||||
}
|
||||
}
|
||||
|
||||
internal bool IsFocused(RadzenPanelMenuItem item)
|
||||
@@ -302,5 +201,18 @@ namespace Radzen.Blazor
|
||||
focusedIndex = -1;
|
||||
currentItems = null;
|
||||
}
|
||||
|
||||
void OnFocus()
|
||||
{
|
||||
currentItems ??= [.. items.Where(i => i.Visible)];
|
||||
|
||||
if (focusedIndex == -1)
|
||||
{
|
||||
Console.WriteLine("OnFocus");
|
||||
focusedIndex = 0;
|
||||
|
||||
StateHasChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
@using Microsoft.AspNetCore.Components.Routing
|
||||
@inject NavigationManager UriHelper
|
||||
@using Radzen.Blazor.Rendering
|
||||
@using Microsoft.AspNetCore.Components.Routing
|
||||
@inherits RadzenComponent
|
||||
@if (Visible)
|
||||
{
|
||||
<li @ref="@Element" id="@GetId()" style="@Style" @attributes="Attributes" class="@GetItemCssClass()" @onclick="@OnClick" @onclick:stopPropagation>
|
||||
<div class=@(Selected ? "rz-navigation-item-wrapper rz-navigation-item-wrapper-active" : "rz-navigation-item-wrapper")>
|
||||
<li @ref=@Element id=@GetId() style=@Style @attributes=@Attributes class=@GetCssClass() @onclick=@(this.AsNonRenderingEventHandler<MouseEventArgs>(OnClick)) @onclick:stopPropagation>
|
||||
<div class=@WrapperClass>
|
||||
@if (Path != null)
|
||||
{
|
||||
<NavLink tabindex="-1" target="@Target" class=@(Selected ? "rz-navigation-item-link rz-navigation-item-link-active" : "rz-navigation-item-link") style="@(Parent?.DisplayStyle == MenuItemDisplayStyle.Icon?"margin-inline-end:0px;":"")" href="@Path" Match="@Match">
|
||||
<NavLink tabindex="-1" target="@Target" class=@LinkClass style="@(Parent?.DisplayStyle == MenuItemDisplayStyle.Icon?"margin-inline-end:0px;":"")" href="@Path" Match="@Match">
|
||||
@if (!string.IsNullOrEmpty(Icon) && (Parent?.DisplayStyle == MenuItemDisplayStyle.Icon || Parent?.DisplayStyle == MenuItemDisplayStyle.IconAndText))
|
||||
{
|
||||
<i class="notranslate rzi rz-navigation-item-icon" style="@getIconStyle()">@Icon</i>
|
||||
@@ -24,9 +24,9 @@
|
||||
{
|
||||
<span class="rz-navigation-item-text" @onclick="@Toggle">@Text</span>
|
||||
}
|
||||
@if (items.Any() && Parent?.ShowArrow == true)
|
||||
@if (ChildContent != null && Parent?.ShowArrow == true)
|
||||
{
|
||||
<i class="notranslate rzi rz-navigation-item-icon-children" style="@getStyle()" @onclick="@Toggle" @onclick:preventDefault>keyboard_arrow_down</i>
|
||||
<i class=@ToggleClass @onclick="@Toggle" @onclick:preventDefault>keyboard_arrow_down</i>
|
||||
}
|
||||
</NavLink>
|
||||
}
|
||||
@@ -49,20 +49,22 @@
|
||||
{
|
||||
<span class="rz-navigation-item-text">@Text</span>
|
||||
}
|
||||
@if (items.Any() && Parent?.ShowArrow == true)
|
||||
@if (ChildContent != null && Parent?.ShowArrow == true)
|
||||
{
|
||||
<i class="notranslate rzi rz-navigation-item-icon-children" style="@getStyle()">keyboard_arrow_down</i>
|
||||
<i class=@ToggleClass>keyboard_arrow_down</i>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
@if (ChildContent != null)
|
||||
{
|
||||
<ul class="rz-navigation-menu" style="@getItemStyle()">
|
||||
<CascadingValue Value=this>
|
||||
@ChildContent
|
||||
</CascadingValue>
|
||||
</ul>
|
||||
<Expander Expanded=@expanded>
|
||||
<ul class="rz-navigation-menu">
|
||||
<CascadingValue Value=this>
|
||||
@ChildContent
|
||||
</CascadingValue>
|
||||
</ul>
|
||||
</Expander>
|
||||
}
|
||||
</li>
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using Microsoft.AspNetCore.Components.Routing;
|
||||
using Microsoft.AspNetCore.Components.Web;
|
||||
using Microsoft.JSInterop;
|
||||
using Radzen.Blazor.Rendering;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Radzen.Blazor
|
||||
@@ -14,10 +14,9 @@ namespace Radzen.Blazor
|
||||
public partial class RadzenPanelMenuItem : RadzenComponent
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override string GetComponentCssClass()
|
||||
{
|
||||
return "rz-navigation-item";
|
||||
}
|
||||
protected override string GetComponentCssClass() => ClassList.Create("rz-navigation-item")
|
||||
.Add("rz-state-focused", Parent?.IsFocused(this) == true)
|
||||
.ToString();
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the target.
|
||||
@@ -103,7 +102,9 @@ namespace Radzen.Blazor
|
||||
[Parameter]
|
||||
public bool Expanded { get; set; }
|
||||
|
||||
internal bool ExpandedInternal { get; set; }
|
||||
private bool expanded;
|
||||
|
||||
internal bool IsExpanded => expanded;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether this <see cref="RadzenPanelMenuItem"/> is selected.
|
||||
@@ -119,9 +120,9 @@ namespace Radzen.Blazor
|
||||
[Parameter]
|
||||
public RenderFragment ChildContent { get; set; }
|
||||
|
||||
internal async System.Threading.Tasks.Task Toggle()
|
||||
internal async Task Toggle()
|
||||
{
|
||||
if (!ExpandedInternal && !Parent.Multiple)
|
||||
if (!expanded && !Parent.Multiple)
|
||||
{
|
||||
var itemsToSkip = new List<RadzenPanelMenuItem>();
|
||||
var p = ParentItem;
|
||||
@@ -134,44 +135,36 @@ namespace Radzen.Blazor
|
||||
Parent.CollapseAll(itemsToSkip);
|
||||
}
|
||||
|
||||
ExpandedInternal = !ExpandedInternal;
|
||||
await ExpandedChanged.InvokeAsync(ExpandedInternal);
|
||||
StateHasChanged();
|
||||
expanded = !expanded;
|
||||
|
||||
await ExpandedChanged.InvokeAsync(expanded);
|
||||
}
|
||||
|
||||
internal async System.Threading.Tasks.Task Collapse()
|
||||
internal async Task Collapse()
|
||||
{
|
||||
if (ExpandedInternal)
|
||||
if (expanded)
|
||||
{
|
||||
ExpandedInternal = false;
|
||||
await ExpandedChanged.InvokeAsync(ExpandedInternal);
|
||||
StateHasChanged();
|
||||
expanded = false;
|
||||
|
||||
await ExpandedChanged.InvokeAsync(expanded);
|
||||
}
|
||||
}
|
||||
|
||||
string getStyle()
|
||||
{
|
||||
string deg = ExpandedInternal ? "180" : "0";
|
||||
return $@"transform: rotate({deg}deg);";
|
||||
}
|
||||
string ToggleClass => ClassList.Create("notranslate rzi rz-navigation-item-icon-children")
|
||||
.Add("rz-state-expanded", expanded)
|
||||
.Add("rz-state-collapsed", !expanded)
|
||||
.ToString();
|
||||
|
||||
string getIconStyle()
|
||||
{
|
||||
return $"{(Parent?.DisplayStyle == MenuItemDisplayStyle.Icon ? "margin-inline-end:0px;" : "")}{(!string.IsNullOrEmpty(IconColor) ? $"color:{IconColor}" : "")}";
|
||||
}
|
||||
|
||||
string getItemStyle()
|
||||
{
|
||||
return ExpandedInternal ? "" : "display:none";
|
||||
return $"{(Parent?.DisplayStyle == MenuItemDisplayStyle.Icon ? "margin-inline-end:0px;" : "")}{(!string.IsNullOrEmpty(IconColor) ? $"color:{IconColor}" : "")}";
|
||||
}
|
||||
|
||||
void Expand()
|
||||
{
|
||||
ExpandedInternal = true;
|
||||
expanded = true;
|
||||
}
|
||||
|
||||
RadzenPanelMenu _parent;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the click callback.
|
||||
/// </summary>
|
||||
@@ -179,55 +172,19 @@ namespace Radzen.Blazor
|
||||
[Parameter]
|
||||
public EventCallback<MenuItemEventArgs> Click { get; set; }
|
||||
|
||||
RadzenPanelMenuItem _parentItem;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the parent item.
|
||||
/// </summary>
|
||||
/// <value>The parent item.</value>
|
||||
[CascadingParameter]
|
||||
public RadzenPanelMenuItem ParentItem
|
||||
{
|
||||
get
|
||||
{
|
||||
return _parentItem;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (_parentItem != value)
|
||||
{
|
||||
_parentItem = value;
|
||||
_parentItem.AddItem(this);
|
||||
|
||||
EnsureVisible();
|
||||
}
|
||||
}
|
||||
}
|
||||
public RadzenPanelMenuItem ParentItem { get; set;}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the parent.
|
||||
/// </summary>
|
||||
/// <value>The parent.</value>
|
||||
[CascadingParameter]
|
||||
public RadzenPanelMenu Parent
|
||||
{
|
||||
get
|
||||
{
|
||||
return _parent;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (_parent != value)
|
||||
{
|
||||
_parent = value;
|
||||
|
||||
if (ParentItem == null)
|
||||
{
|
||||
_parent.AddItem(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
public RadzenPanelMenu Parent { get; set; }
|
||||
|
||||
internal List<RadzenPanelMenuItem> items = new List<RadzenPanelMenuItem>();
|
||||
|
||||
@@ -237,48 +194,179 @@ namespace Radzen.Blazor
|
||||
/// <param name="item">The item.</param>
|
||||
public void AddItem(RadzenPanelMenuItem item)
|
||||
{
|
||||
if (items.IndexOf(item) == -1)
|
||||
if (!items.Contains(item))
|
||||
{
|
||||
items.Add(item);
|
||||
Parent.SelectItem(item);
|
||||
StateHasChanged();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Selects the specified item by value.
|
||||
/// </summary>
|
||||
/// <param name="value">if set to <c>true</c> [value].</param>
|
||||
public void Select(bool value)
|
||||
{
|
||||
Selected = value;
|
||||
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
void EnsureVisible()
|
||||
{
|
||||
if (Selected)
|
||||
if (selected)
|
||||
{
|
||||
var parent = ParentItem;
|
||||
|
||||
while (parent != null)
|
||||
{
|
||||
parent.Expand();
|
||||
|
||||
if (parent.ParentItem == null)
|
||||
{
|
||||
parent.StateHasChanged();
|
||||
}
|
||||
|
||||
parent = parent.ParentItem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Inject]
|
||||
NavigationManager NavigationManager { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
expanded = Expanded;
|
||||
|
||||
selected = Selected;
|
||||
|
||||
NavigationManager.LocationChanged += OnLocationChanged;
|
||||
|
||||
if (ParentItem != null)
|
||||
{
|
||||
ParentItem.AddItem(this);
|
||||
}
|
||||
else if (Parent != null)
|
||||
{
|
||||
Parent.AddItem(this);
|
||||
}
|
||||
|
||||
SyncWithNavigationManager();
|
||||
}
|
||||
|
||||
string WrapperClass => ClassList.Create("rz-navigation-item-wrapper")
|
||||
.Add("rz-navigation-item-wrapper-active", selected)
|
||||
.ToString();
|
||||
|
||||
string LinkClass => ClassList.Create("rz-navigation-item-link")
|
||||
.Add("rz-navigation-item-link-active", selected)
|
||||
.ToString();
|
||||
|
||||
private bool selected = false;
|
||||
|
||||
private void OnLocationChanged(object sender, LocationChangedEventArgs e)
|
||||
{
|
||||
SyncWithNavigationManager();
|
||||
}
|
||||
|
||||
private void SyncWithNavigationManager()
|
||||
{
|
||||
var matches = ShouldMatch();
|
||||
|
||||
if (matches != selected)
|
||||
{
|
||||
selected = matches;
|
||||
|
||||
EnsureVisible();
|
||||
|
||||
StateHasChanged();
|
||||
}
|
||||
}
|
||||
|
||||
bool ShouldMatch()
|
||||
{
|
||||
if (string.IsNullOrEmpty(Path))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var currentAbsoluteUrl = NavigationManager.ToAbsoluteUri(NavigationManager.Uri).AbsoluteUri;
|
||||
var absoluteUrl = NavigationManager.ToAbsoluteUri(Path).AbsoluteUri;
|
||||
|
||||
if (EqualsHrefExactlyOrIfTrailingSlashAdded(absoluteUrl, currentAbsoluteUrl))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (Path == "/")
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var match = Match != NavLinkMatch.Prefix ? Match : Parent.Match;
|
||||
|
||||
if (match == NavLinkMatch.Prefix && IsStrictlyPrefixWithSeparator(currentAbsoluteUrl, absoluteUrl))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static bool EqualsHrefExactlyOrIfTrailingSlashAdded(string absoluteUrl, string currentAbsoluteUrl)
|
||||
{
|
||||
if (string.Equals(currentAbsoluteUrl, absoluteUrl, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (currentAbsoluteUrl.Length == absoluteUrl.Length - 1)
|
||||
{
|
||||
if (absoluteUrl[^1] == '/' && absoluteUrl.StartsWith(currentAbsoluteUrl, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static bool IsSeparator(char c)
|
||||
{
|
||||
return c == '?' || c == '/' || c == '#';
|
||||
}
|
||||
|
||||
private static bool IsStrictlyPrefixWithSeparator(string value, string prefix)
|
||||
{
|
||||
var prefixLength = prefix.Length;
|
||||
if (value.Length > prefixLength)
|
||||
{
|
||||
return value.StartsWith(prefix, StringComparison.OrdinalIgnoreCase)
|
||||
&& (
|
||||
prefixLength == 0
|
||||
|| IsSeparator(prefix[prefixLength - 1])
|
||||
|| IsSeparator(value[prefixLength])
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override async Task SetParametersAsync(ParameterView parameters)
|
||||
{
|
||||
if (parameters.DidParameterChange(nameof(Expanded), Expanded))
|
||||
{
|
||||
ExpandedInternal = parameters.GetValueOrDefault<bool>(nameof(Expanded));
|
||||
}
|
||||
var expandedChanged = parameters.DidParameterChange(nameof(Expanded), Expanded);
|
||||
|
||||
var selectedChanged = parameters.DidParameterChange(nameof(Selected), Selected);
|
||||
|
||||
await base.SetParametersAsync(parameters);
|
||||
|
||||
if (expandedChanged)
|
||||
{
|
||||
expanded = Expanded;
|
||||
}
|
||||
|
||||
if (selectedChanged)
|
||||
{
|
||||
selected = Selected;
|
||||
|
||||
if (selected)
|
||||
{
|
||||
EnsureVisible();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -316,17 +404,12 @@ namespace Radzen.Blazor
|
||||
}
|
||||
}
|
||||
|
||||
internal string GetItemCssClass()
|
||||
{
|
||||
return $"{GetCssClass()} {(Parent.IsFocused(this) ? "rz-state-focused" : "")}".Trim();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Dispose()
|
||||
{
|
||||
base.Dispose();
|
||||
|
||||
items.Remove(this);
|
||||
NavigationManager.LocationChanged -= OnLocationChanged;
|
||||
|
||||
if (Parent != null)
|
||||
{
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
</div>
|
||||
@if (ShowIcon)
|
||||
{
|
||||
<i class="notranslate rzi rz-navigation-item-icon-children" style="@iconStyle">keyboard_arrow_down</i>
|
||||
<i class=@ToggleClass>keyboard_arrow_down</i>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -4,6 +4,7 @@ using Microsoft.JSInterop;
|
||||
using System.Collections.Generic;
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Radzen.Blazor.Rendering;
|
||||
|
||||
namespace Radzen.Blazor
|
||||
{
|
||||
@@ -50,7 +51,6 @@ namespace Radzen.Blazor
|
||||
public bool ShowIcon { get; set; } = true;
|
||||
|
||||
string contentStyle = "display:none;position:absolute;z-index:1;";
|
||||
string iconStyle = "transform: rotate(0deg);";
|
||||
|
||||
/// <summary>
|
||||
/// Toggles the menu open/close state.
|
||||
@@ -58,18 +58,23 @@ namespace Radzen.Blazor
|
||||
/// <param name="args">The <see cref="MouseEventArgs"/> instance containing the event data.</param>
|
||||
public async Task Toggle(MouseEventArgs args)
|
||||
{
|
||||
contentStyle = contentStyle.IndexOf("display:none;") != -1 ? "display:block;" : "display:none;position:absolute;z-index:1;";
|
||||
iconStyle = iconStyle.IndexOf("rotate(0deg)") != -1 ? "transform: rotate(-180deg);" : "transform: rotate(0deg);";
|
||||
contentStyle = Collapsed ? "display:block;" : "display:none;position:absolute;z-index:1;";
|
||||
await InvokeAsync(StateHasChanged);
|
||||
}
|
||||
|
||||
bool Collapsed => contentStyle.Contains("display:none;", StringComparison.CurrentCulture);
|
||||
|
||||
string ToggleClass => ClassList.Create("notranslate rzi rz-navigation-item-icon-children")
|
||||
.Add("rz-state-expanded", !Collapsed)
|
||||
.Add("rz-state-collapsed", Collapsed)
|
||||
.ToString();
|
||||
|
||||
/// <summary>
|
||||
/// Closes this instance.
|
||||
/// </summary>
|
||||
public void Close()
|
||||
{
|
||||
contentStyle = "display:none;";
|
||||
iconStyle = "transform: rotate(0deg);";
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
@@ -93,7 +98,7 @@ namespace Radzen.Blazor
|
||||
{
|
||||
preventKeyPress = true;
|
||||
|
||||
if (!contentStyle.Contains("display:none;") && focusedIndex >= 0 && focusedIndex < items.Count)
|
||||
if (!Collapsed && focusedIndex >= 0 && focusedIndex < items.Count)
|
||||
{
|
||||
var item = items[focusedIndex];
|
||||
|
||||
@@ -110,7 +115,7 @@ namespace Radzen.Blazor
|
||||
{
|
||||
await Toggle(new MouseEventArgs());
|
||||
|
||||
if (!contentStyle.Contains("display:none;"))
|
||||
if (!Collapsed)
|
||||
{
|
||||
focusedIndex = focusedIndex != -1 ? focusedIndex : 0;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using Radzen.Blazor.Rendering;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Radzen.Blazor
|
||||
{
|
||||
@@ -15,28 +15,11 @@ namespace Radzen.Blazor
|
||||
public partial class RadzenProgressBar
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override string GetComponentCssClass()
|
||||
{
|
||||
var classList = new List<string>()
|
||||
{
|
||||
"rz-progressbar"
|
||||
};
|
||||
|
||||
switch (Mode)
|
||||
{
|
||||
case ProgressBarMode.Determinate:
|
||||
classList.Add("rz-progressbar-determinate");
|
||||
break;
|
||||
case ProgressBarMode.Indeterminate:
|
||||
classList.Add("rz-progressbar-indeterminate");
|
||||
break;
|
||||
}
|
||||
|
||||
classList.Add($"rz-progressbar-{ProgressBarStyle.ToString().ToLowerInvariant()}");
|
||||
|
||||
return string.Join(" ", classList);
|
||||
}
|
||||
|
||||
protected override string GetComponentCssClass() => ClassList.Create("rz-progressbar")
|
||||
.Add("rz-progressbar-determinate", Mode == ProgressBarMode.Determinate)
|
||||
.Add("rz-progressbar-indeterminate", Mode == ProgressBarMode.Indeterminate)
|
||||
.Add($"rz-progressbar-{ProgressBarStyle.ToString().ToLowerInvariant()}")
|
||||
.ToString();
|
||||
/// <summary>
|
||||
/// Gets or sets the template.
|
||||
/// </summary>
|
||||
@@ -105,4 +88,4 @@ namespace Radzen.Blazor
|
||||
/// </summary>
|
||||
protected double NormalizedValue => Math.Min(Math.Max((Value - Min) / (Max - Min), 0), 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using System.Collections.Generic;
|
||||
using Radzen.Blazor.Rendering;
|
||||
|
||||
namespace Radzen.Blazor
|
||||
{
|
||||
@@ -14,48 +14,21 @@ namespace Radzen.Blazor
|
||||
public partial class RadzenProgressBarCircular : RadzenProgressBar
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override string GetComponentCssClass()
|
||||
protected override string GetComponentCssClass() => ClassList.Create("rz-progressbar-circular")
|
||||
.Add("rz-progressbar-determinate", Mode == ProgressBarMode.Determinate)
|
||||
.Add("rz-progressbar-indeterminate", Mode == ProgressBarMode.Indeterminate)
|
||||
.Add($"rz-progressbar-{ProgressBarStyle.ToString().ToLowerInvariant()}")
|
||||
.Add($"rz-progressbar-circular-{CircleSize}")
|
||||
.ToString();
|
||||
|
||||
string CircleSize => Size switch
|
||||
{
|
||||
var classList=new List<string>()
|
||||
{
|
||||
"rz-progressbar-circular"
|
||||
};
|
||||
|
||||
switch (Mode)
|
||||
{
|
||||
case ProgressBarMode.Determinate:
|
||||
classList.Add("rz-progressbar-determinate");
|
||||
break;
|
||||
case ProgressBarMode.Indeterminate:
|
||||
classList.Add("rz-progressbar-indeterminate");
|
||||
break;
|
||||
}
|
||||
|
||||
classList.Add($"rz-progressbar-{ProgressBarStyle.ToString().ToLowerInvariant()}");
|
||||
classList.Add($"rz-progressbar-circular-{GetCircleSize()}");
|
||||
|
||||
return string.Join(" ", classList);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the circle size.
|
||||
/// </summary>
|
||||
protected string GetCircleSize()
|
||||
{
|
||||
switch (Size)
|
||||
{
|
||||
case ProgressBarCircularSize.Medium:
|
||||
return "md";
|
||||
case ProgressBarCircularSize.Large:
|
||||
return "lg";
|
||||
case ProgressBarCircularSize.Small:
|
||||
return "sm";
|
||||
case ProgressBarCircularSize.ExtraSmall:
|
||||
return "xs";
|
||||
default:
|
||||
return string.Empty;
|
||||
}
|
||||
}
|
||||
ProgressBarCircularSize.Medium => "md",
|
||||
ProgressBarCircularSize.Large => "lg",
|
||||
ProgressBarCircularSize.Small => "sm",
|
||||
ProgressBarCircularSize.ExtraSmall => "xs",
|
||||
_ => string.Empty,
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the size.
|
||||
@@ -64,4 +37,4 @@ namespace Radzen.Blazor
|
||||
[Parameter]
|
||||
public ProgressBarCircularSize Size { get; set; } = ProgressBarCircularSize.Medium;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -14,16 +14,19 @@
|
||||
}
|
||||
@if (Visible)
|
||||
{
|
||||
<div @ref="@Element" style="@Style" @attributes="Attributes" class="@GetCssClass()" id="@GetId()">
|
||||
<div @ref="@Element" style="@Style" @attributes="Attributes" class="@GetCssClass()" id="@GetId()"
|
||||
role="radiogroup" @onfocus=@OnFocus @onblur=@OnBlur
|
||||
tabindex="@(Disabled ? "-1" : $"{TabIndex}")" @onkeydown="@(args => OnKeyPress(args))" @onkeydown:preventDefault=preventKeyPress @onkeydown:stopPropagation>
|
||||
<RadzenStack Orientation="@Orientation" JustifyContent="@JustifyContent" AlignItems="@AlignItems" Gap="@Gap" Wrap="@Wrap">
|
||||
@foreach (var item in allItems.Where(i => i.Visible))
|
||||
{
|
||||
<div @ref="@item.Element" id="@item.GetItemId()" @onclick="@(args => SelectItem(item))" @attributes="item.Attributes" class="@item.GetItemCssClass()" style="@item.Style">
|
||||
<div class="rz-radiobutton" @onkeypress="@(args => OnKeyPress(args, SelectItem(item)))" @onkeypress:preventDefault=preventKeyPress @onkeypress:stopPropagation tabindex="@(Disabled || item.Disabled ? "-1" : $"{TabIndex}")">
|
||||
<div @ref="@item.Element" id="@item.GetItemId()" @onclick="@(args => SelectItem(item))" @attributes="item.Attributes" class="@item.GetItemCssClass()" style="@item.Style" role="radio" aria-checked=@(IsSelected(item)? "true" : "false") aria-label="@item.Text">
|
||||
<div class="rz-radiobutton">
|
||||
<div class="rz-helper-hidden-accessible">
|
||||
<input type="radio" disabled="@Disabled" name="@Name" value="@item.Value" tabindex="-1" aria-label="@(item.Text + " " + item.Value)" @attributes="item.InputAttributes">
|
||||
</div>
|
||||
<div class=@ItemClassList(item)>
|
||||
<span class=@IconClassList(item)></span>
|
||||
<div class=@ItemClass(item)>
|
||||
<span class=@IconClass(item)></span>
|
||||
</div>
|
||||
</div>
|
||||
@if (item.Template != null)
|
||||
@@ -38,5 +41,6 @@
|
||||
}
|
||||
</div>
|
||||
}
|
||||
</RadzenStack>
|
||||
</div>
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using Microsoft.AspNetCore.Components.Web;
|
||||
using Radzen.Blazor.Rendering;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
@@ -24,12 +25,15 @@ namespace Radzen.Blazor
|
||||
/// </example>
|
||||
public partial class RadzenRadioButtonList<TValue> : FormComponent<TValue>
|
||||
{
|
||||
ClassList ItemClassList(RadzenRadioButtonListItem<TValue> item) => ClassList.Create("rz-radiobutton-box")
|
||||
string ItemClass(RadzenRadioButtonListItem<TValue> item) => ClassList.Create("rz-radiobutton-box")
|
||||
.Add("rz-state-active", IsSelected(item))
|
||||
.AddDisabled(Disabled || item.Disabled);
|
||||
.Add("rz-state-focused", IsFocused(item) && focused)
|
||||
.AddDisabled(Disabled || item.Disabled)
|
||||
.ToString();
|
||||
|
||||
ClassList IconClassList(RadzenRadioButtonListItem<TValue> item) => ClassList.Create("rz-radiobutton-icon")
|
||||
.Add("notranslate rzi rzi-circle-on", IsSelected(item));
|
||||
string IconClass(RadzenRadioButtonListItem<TValue> item) => ClassList.Create("rz-radiobutton-icon")
|
||||
.Add("notranslate rzi rzi-circle-on", IsSelected(item))
|
||||
.ToString();
|
||||
/// <summary>
|
||||
/// Gets or sets the value property.
|
||||
/// </summary>
|
||||
@@ -44,6 +48,34 @@ namespace Radzen.Blazor
|
||||
[Parameter]
|
||||
public string TextProperty { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the content justify.
|
||||
/// </summary>
|
||||
/// <value>The content justify.</value>
|
||||
[Parameter]
|
||||
public JustifyContent JustifyContent { get; set; } = JustifyContent.Start;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the items alignment.
|
||||
/// </summary>
|
||||
/// <value>The items alignment.</value>
|
||||
[Parameter]
|
||||
public AlignItems AlignItems { get; set; } = AlignItems.Start;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the spacing between items
|
||||
/// </summary>
|
||||
/// <value>The spacing between items.</value>
|
||||
[Parameter]
|
||||
public string Gap { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the wrap.
|
||||
/// </summary>
|
||||
/// <value>The wrap.</value>
|
||||
[Parameter]
|
||||
public FlexWrap Wrap { get; set; } = FlexWrap.Wrap;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the disabled property.
|
||||
/// </summary>
|
||||
@@ -58,29 +90,36 @@ namespace Radzen.Blazor
|
||||
[Parameter]
|
||||
public string VisibleProperty { get; set; }
|
||||
|
||||
IEnumerable<RadzenRadioButtonListItem<TValue>> allItems
|
||||
List<RadzenRadioButtonListItem<TValue>> allItems;
|
||||
|
||||
void UpdateAllItems()
|
||||
{
|
||||
get
|
||||
allItems = items.Concat((Data != null ? Data.Cast<object>() : Enumerable.Empty<object>()).Select(i =>
|
||||
{
|
||||
return items.Concat((Data != null ? Data.Cast<object>() : Enumerable.Empty<object>()).Select(i =>
|
||||
var item = new RadzenRadioButtonListItem<TValue>();
|
||||
item.SetText((string)PropertyAccess.GetItemOrValueFromProperty(i, TextProperty));
|
||||
item.SetValue((TValue)PropertyAccess.GetItemOrValueFromProperty(i, ValueProperty));
|
||||
|
||||
if (DisabledProperty != null && PropertyAccess.TryGetItemOrValueFromProperty<bool>(i, DisabledProperty, out var disabledResult))
|
||||
{
|
||||
var item = new RadzenRadioButtonListItem<TValue>();
|
||||
item.SetText((string)PropertyAccess.GetItemOrValueFromProperty(i, TextProperty));
|
||||
item.SetValue((TValue)PropertyAccess.GetItemOrValueFromProperty(i, ValueProperty));
|
||||
item.SetDisabled(disabledResult);
|
||||
}
|
||||
|
||||
if (DisabledProperty != null && PropertyAccess.TryGetItemOrValueFromProperty<bool>(i, DisabledProperty, out var disabledResult))
|
||||
{
|
||||
item.SetDisabled(disabledResult);
|
||||
}
|
||||
if (VisibleProperty != null && PropertyAccess.TryGetItemOrValueFromProperty<bool>(i, VisibleProperty, out var visibleResult))
|
||||
{
|
||||
item.SetVisible(visibleResult);
|
||||
}
|
||||
|
||||
if (VisibleProperty != null && PropertyAccess.TryGetItemOrValueFromProperty<bool>(i, VisibleProperty, out var visibleResult))
|
||||
{
|
||||
item.SetVisible(visibleResult);
|
||||
}
|
||||
return item;
|
||||
})).ToList();
|
||||
}
|
||||
|
||||
return item;
|
||||
}));
|
||||
}
|
||||
/// <inheritdoc />
|
||||
protected override void OnParametersSet()
|
||||
{
|
||||
base.OnParametersSet();
|
||||
|
||||
UpdateAllItems();
|
||||
}
|
||||
|
||||
IEnumerable _data = null;
|
||||
@@ -109,7 +148,10 @@ namespace Radzen.Blazor
|
||||
/// <inheritdoc />
|
||||
protected override string GetComponentCssClass()
|
||||
{
|
||||
return GetClassList(Orientation == Orientation.Horizontal ? "rz-radio-button-list-horizontal" : "rz-radio-button-list-vertical").ToString();
|
||||
var horizontal = Orientation == Orientation.Horizontal;
|
||||
|
||||
return $"rz-radio-button-list rz-radio-button-list-{(horizontal ? "horizontal" : "vertical")}";
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -137,6 +179,7 @@ namespace Radzen.Blazor
|
||||
if (items.IndexOf(item) == -1)
|
||||
{
|
||||
items.Add(item);
|
||||
UpdateAllItems();
|
||||
StateHasChanged();
|
||||
}
|
||||
}
|
||||
@@ -150,6 +193,7 @@ namespace Radzen.Blazor
|
||||
if (items.Contains(item))
|
||||
{
|
||||
items.Remove(item);
|
||||
UpdateAllItems();
|
||||
try
|
||||
{ InvokeAsync(StateHasChanged); }
|
||||
catch { }
|
||||
@@ -175,6 +219,8 @@ namespace Radzen.Blazor
|
||||
if (Disabled || item.Disabled)
|
||||
return;
|
||||
|
||||
focusedIndex = allItems.IndexOf(item);
|
||||
|
||||
Value = item.Value;
|
||||
|
||||
await ValueChanged.InvokeAsync(Value);
|
||||
@@ -193,21 +239,68 @@ namespace Radzen.Blazor
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
bool focused;
|
||||
int focusedIndex = -1;
|
||||
bool preventKeyPress = true;
|
||||
async Task OnKeyPress(KeyboardEventArgs args, Task task)
|
||||
async Task OnKeyPress(KeyboardEventArgs args)
|
||||
{
|
||||
var key = args.Code != null ? args.Code : args.Key;
|
||||
|
||||
if (key == "Space" || key == "Enter")
|
||||
var item = allItems.ElementAtOrDefault(focusedIndex) ?? allItems.FirstOrDefault();
|
||||
|
||||
if (item == null) return;
|
||||
|
||||
if ((Orientation == Orientation.Horizontal && (key == "ArrowLeft" || key == "ArrowRight")) ||
|
||||
(Orientation == Orientation.Vertical && (key == "ArrowUp" || key == "ArrowDown")))
|
||||
{
|
||||
preventKeyPress = true;
|
||||
var direction = key == "ArrowLeft" || key == "ArrowUp" ? -1 : 1;
|
||||
|
||||
focusedIndex = Math.Clamp(focusedIndex + direction, 0, allItems.FindLastIndex(t => t.Visible && !t.Disabled));
|
||||
|
||||
while (allItems.ElementAtOrDefault(focusedIndex)?.Disabled == true)
|
||||
{
|
||||
focusedIndex = focusedIndex + direction;
|
||||
}
|
||||
}
|
||||
else if (key == "Home" || key == "End")
|
||||
{
|
||||
preventKeyPress = true;
|
||||
|
||||
await task;
|
||||
focusedIndex = key == "Home" ? 0 : allItems.Where(t => HasInvisibleBefore(item) ? true : t.Visible).Count() - 1;
|
||||
}
|
||||
else if (key == "Space" || key == "Enter")
|
||||
{
|
||||
preventKeyPress = true;
|
||||
|
||||
if (focusedIndex >= 0 && focusedIndex < allItems.Where(t => HasInvisibleBefore(item) ? true : t.Visible).Count())
|
||||
{
|
||||
await SelectItem(allItems.Where(t => HasInvisibleBefore(item) ? true : t.Visible).ToList()[focusedIndex]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
preventKeyPress = false;
|
||||
}
|
||||
}
|
||||
|
||||
bool HasInvisibleBefore(RadzenRadioButtonListItem<TValue> item)
|
||||
{
|
||||
return allItems.Take(allItems.IndexOf(item)).Any(t => !t.Visible && !t.Disabled);
|
||||
}
|
||||
|
||||
bool IsFocused(RadzenRadioButtonListItem<TValue> item)
|
||||
{
|
||||
return allItems.IndexOf(item) == focusedIndex;
|
||||
}
|
||||
void OnFocus()
|
||||
{
|
||||
focusedIndex = focusedIndex == -1 ? 0 : focusedIndex;
|
||||
focused = true;
|
||||
}
|
||||
void OnBlur()
|
||||
{
|
||||
focused = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -705,7 +705,7 @@ namespace Radzen.Blazor
|
||||
|
||||
if (IsJSRuntimeAvailable)
|
||||
{
|
||||
JSRuntime.InvokeVoidAsync("Radzen.destroyScheduler", Element);
|
||||
JSRuntime.InvokeVoid("Radzen.destroyScheduler", Element);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -108,7 +108,7 @@ namespace Radzen.Blazor
|
||||
|
||||
if (IsJSRuntimeAvailable)
|
||||
{
|
||||
JSRuntime.InvokeVoidAsync("Radzen.destroySecurityCode", GetId(), Element);
|
||||
JSRuntime.InvokeVoid("Radzen.destroySecurityCode", GetId(), Element);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -13,12 +13,14 @@
|
||||
}
|
||||
@if (Visible)
|
||||
{
|
||||
<div @ref="@Element" style="@Style" @attributes="Attributes" class="@GetCssClass()" id="@GetId()">
|
||||
<div @ref="@Element" style="@Style" @attributes="Attributes" class="@GetCssClass()" id="@GetId()"
|
||||
role="toolbar" aria-orientation="horizontal" @onfocus=@this.AsNonRenderingEventHandler(OnFocus) @onblur=@this.AsNonRenderingEventHandler(OnBlur)
|
||||
tabindex="@(Disabled ? "-1" : $"{TabIndex}")" @onkeydown="@(args => OnKeyPress(args))" @onkeydown:preventDefault=preventKeyPress @onkeydown:stopPropagation>
|
||||
@foreach (var item in allItems.Where(i => i.Visible))
|
||||
{
|
||||
<div @ref="@item.Element" id="@item.GetItemId()"
|
||||
@onclick="@(args => SelectItem(item))" @onkeypress="@(args => OnKeyPress(args, SelectItem(item)))" @onkeypress:preventDefault=preventKeyPress @onkeypress:stopPropagation
|
||||
@attributes="item.Attributes" style="@item.Style" class=@ButtonClassList(item) aria-label="@item.Text" tabindex="@(Disabled || item.Disabled ? "-1" : $"{TabIndex}")">
|
||||
@onclick="@(args => SelectItem(item))"
|
||||
@attributes="item.Attributes" style="@item.Style" class=@ButtonClass(item) aria-label="@item.Text" aria-selected=@(IsSelected(item)? "true" : "false")>
|
||||
@if (item.Template != null)
|
||||
{
|
||||
@item.Template(item)
|
||||
|
||||
@@ -26,11 +26,6 @@ namespace Radzen.Blazor
|
||||
/// </example>
|
||||
public partial class RadzenSelectBar<TValue> : FormComponent<TValue>, IRadzenSelectBar
|
||||
{
|
||||
private string getButtonSize()
|
||||
{
|
||||
return Size == ButtonSize.Medium ? "md" : Size == ButtonSize.Large ? "lg" : Size == ButtonSize.Small ? "sm" : "xs";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the size. Set to <c>ButtonSize.Medium</c> by default.
|
||||
/// </summary>
|
||||
@@ -46,10 +41,12 @@ namespace Radzen.Blazor
|
||||
public Orientation Orientation { get; set; } = Orientation.Horizontal;
|
||||
|
||||
|
||||
ClassList ButtonClassList(RadzenSelectBarItem item)
|
||||
=> ClassList.Create($"rz-button rz-button-{getButtonSize()} rz-button-text-only")
|
||||
.Add("rz-state-active", IsSelected(item))
|
||||
.AddDisabled(Disabled || item.Disabled);
|
||||
string ButtonClass(RadzenSelectBarItem item) => ClassList.Create($"rz-button rz-button-text-only")
|
||||
.AddButtonSize(Size)
|
||||
.Add("rz-state-active", IsSelected(item))
|
||||
.Add("rz-state-focused", IsFocused(item) && focused)
|
||||
.AddDisabled(Disabled || item.Disabled)
|
||||
.ToString();
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the value property.
|
||||
@@ -65,19 +62,7 @@ namespace Radzen.Blazor
|
||||
[Parameter]
|
||||
public string TextProperty { get; set; }
|
||||
|
||||
IEnumerable<RadzenSelectBarItem> allItems
|
||||
{
|
||||
get
|
||||
{
|
||||
return items.Concat((Data != null ? Data.Cast<object>() : Enumerable.Empty<object>()).Select(i =>
|
||||
{
|
||||
var item = new RadzenSelectBarItem();
|
||||
item.SetText((string)PropertyAccess.GetItemOrValueFromProperty(i, TextProperty));
|
||||
item.SetValue(PropertyAccess.GetItemOrValueFromProperty(i, ValueProperty));
|
||||
return item;
|
||||
}));
|
||||
}
|
||||
}
|
||||
List<RadzenSelectBarItem> allItems;
|
||||
|
||||
IEnumerable _data = null;
|
||||
|
||||
@@ -103,11 +88,29 @@ namespace Radzen.Blazor
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override string GetComponentCssClass()
|
||||
=> GetClassList("rz-selectbutton rz-buttonset")
|
||||
.Add($"rz-selectbutton-{(Orientation == Orientation.Vertical ? "vertical" : "horizontal")}")
|
||||
.Add($"rz-buttonset-{items.Count}")
|
||||
.ToString();
|
||||
protected override void OnParametersSet()
|
||||
{
|
||||
base.OnParametersSet();
|
||||
|
||||
UpdateAllItems();
|
||||
}
|
||||
|
||||
void UpdateAllItems()
|
||||
{
|
||||
allItems = items.Concat((Data != null ? Data.Cast<object>() : Enumerable.Empty<object>()).Select(i =>
|
||||
{
|
||||
var item = new RadzenSelectBarItem();
|
||||
item.SetText((string)PropertyAccess.GetItemOrValueFromProperty(i, TextProperty));
|
||||
item.SetValue(PropertyAccess.GetItemOrValueFromProperty(i, ValueProperty));
|
||||
return item;
|
||||
})).ToList();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override string GetComponentCssClass() => GetClassList("rz-selectbar rz-buttonset")
|
||||
.Add($"rz-selectbar-{(Orientation == Orientation.Vertical ? "vertical" : "horizontal")}")
|
||||
.Add($"rz-buttonset-{allItems.Count}")
|
||||
.ToString();
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether this <see cref="RadzenSelectBar{TValue}"/> is multiple.
|
||||
@@ -134,6 +137,7 @@ namespace Radzen.Blazor
|
||||
if (items.IndexOf(item) == -1)
|
||||
{
|
||||
items.Add(item);
|
||||
UpdateAllItems();
|
||||
StateHasChanged();
|
||||
}
|
||||
}
|
||||
@@ -147,6 +151,7 @@ namespace Radzen.Blazor
|
||||
if (items.Contains(item))
|
||||
{
|
||||
items.Remove(item);
|
||||
UpdateAllItems();
|
||||
if (!disposed)
|
||||
{
|
||||
try { InvokeAsync(StateHasChanged); } catch { }
|
||||
@@ -192,6 +197,8 @@ namespace Radzen.Blazor
|
||||
if (Disabled || item.Disabled)
|
||||
return;
|
||||
|
||||
focusedIndex = allItems.IndexOf(item);
|
||||
|
||||
if (Multiple)
|
||||
{
|
||||
var type = typeof(TValue).IsGenericType ? typeof(TValue).GetGenericArguments()[0] : typeof(TValue);
|
||||
@@ -229,21 +236,69 @@ namespace Radzen.Blazor
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
bool focused;
|
||||
int focusedIndex = -1;
|
||||
bool preventKeyPress = true;
|
||||
async Task OnKeyPress(KeyboardEventArgs args, Task task)
|
||||
async Task OnKeyPress(KeyboardEventArgs args)
|
||||
{
|
||||
var key = args.Code != null ? args.Code : args.Key;
|
||||
|
||||
if (key == "Space" || key == "Enter")
|
||||
var item = allItems.ElementAtOrDefault(focusedIndex) ?? allItems.FirstOrDefault();
|
||||
|
||||
if (item == null) return;
|
||||
|
||||
if (key == "ArrowLeft" || key == "ArrowRight")
|
||||
{
|
||||
preventKeyPress = true;
|
||||
|
||||
await task;
|
||||
var direction = key == "ArrowLeft" ? -1 : 1;
|
||||
|
||||
focusedIndex = Math.Clamp(focusedIndex + direction, 0, allItems.FindLastIndex(t => t.Visible && !t.Disabled));
|
||||
|
||||
while (allItems.ElementAtOrDefault(focusedIndex)?.Disabled == true)
|
||||
{
|
||||
focusedIndex = focusedIndex + direction;
|
||||
}
|
||||
}
|
||||
else if (key == "Home" || key == "End")
|
||||
{
|
||||
preventKeyPress = true;
|
||||
|
||||
focusedIndex = key == "Home" ? 0 : allItems.Where(t => HasInvisibleBefore(item) ? true : t.Visible).Count() - 1;
|
||||
}
|
||||
else if (key == "Space" || key == "Enter")
|
||||
{
|
||||
preventKeyPress = true;
|
||||
|
||||
if (focusedIndex >= 0 && focusedIndex < allItems.Where(t => HasInvisibleBefore(item) ? true : t.Visible).Count())
|
||||
{
|
||||
await SelectItem(allItems.Where(t => HasInvisibleBefore(item) ? true : t.Visible).ToList()[focusedIndex]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
preventKeyPress = false;
|
||||
}
|
||||
}
|
||||
|
||||
bool HasInvisibleBefore(RadzenSelectBarItem item)
|
||||
{
|
||||
return allItems.Take(allItems.IndexOf(item)).Any(t => !t.Visible && !t.Disabled);
|
||||
}
|
||||
|
||||
bool IsFocused(RadzenSelectBarItem item)
|
||||
{
|
||||
return allItems.ToList().IndexOf(item) == focusedIndex;
|
||||
}
|
||||
|
||||
void OnFocus()
|
||||
{
|
||||
focusedIndex = focusedIndex == -1 ? 0 : focusedIndex;
|
||||
focused = true;
|
||||
}
|
||||
void OnBlur()
|
||||
{
|
||||
focused = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -104,7 +104,7 @@ namespace Radzen.Blazor
|
||||
|
||||
if (IsJSRuntimeAvailable)
|
||||
{
|
||||
JSRuntime.InvokeVoidAsync("Radzen.destroySlider", UniqueID, Element);
|
||||
JSRuntime.InvokeVoid("Radzen.destroySlider", UniqueID, Element);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
{
|
||||
<div @ref="@Element" style="@Style" @attributes="Attributes" class="@GetCssClass()" id="@GetId()"
|
||||
tabindex="@(Disabled ? -1 : TabIndex)" @onkeydown="@OnKeyPress" @onkeydown:preventDefault=preventKeyPress @onkeydown:stopPropagation>
|
||||
<button aria-label="@(ButtonAriaLabel ?? Text)" tabindex="-1" disabled="@IsDisabled" class="@getButtonCss()" type="@Enum.GetName(typeof(ButtonType), ButtonType).ToLower()" @onclick="@OnClick">
|
||||
<button aria-label="@(ButtonAriaLabel ?? Text)" tabindex="-1" disabled="@IsDisabled" class=@ButtonClass type="@Enum.GetName(typeof(ButtonType), ButtonType).ToLower()" @onclick="@OnClick">
|
||||
<span class="rz-button-box">
|
||||
@if (ButtonContent != null)
|
||||
{
|
||||
@@ -43,7 +43,7 @@
|
||||
}
|
||||
</span>
|
||||
</button>
|
||||
<button tabindex="-1" disabled="@IsDisabled" onclick="@OpenPopupScript()" class="@getPopupButtonCss()" type="button" aria-label="@OpenAriaLabel">
|
||||
<button tabindex="-1" disabled="@IsDisabled" onclick="@OpenPopupScript()" class=@PopupButtonClass type="button" aria-label="@OpenAriaLabel">
|
||||
<RadzenIcon Icon="@DropDownIcon" />
|
||||
</button>
|
||||
<div id="@PopupID" class="rz-splitbutton-menu">
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using Microsoft.AspNetCore.Components.Web;
|
||||
using Microsoft.JSInterop;
|
||||
using Radzen.Blazor.Rendering;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
@@ -23,11 +24,6 @@ namespace Radzen.Blazor
|
||||
/// </example>
|
||||
public partial class RadzenSplitButton : RadzenComponentWithChildren
|
||||
{
|
||||
private string getButtonSize()
|
||||
{
|
||||
return Size == ButtonSize.Medium ? "md" : Size == ButtonSize.Large ? "lg" : Size == ButtonSize.Small ? "sm" : "xs";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the child content.
|
||||
/// </summary>
|
||||
@@ -132,7 +128,6 @@ namespace Radzen.Blazor
|
||||
[Parameter]
|
||||
public bool AlwaysOpenPopup { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the open button aria-label attribute.
|
||||
/// </summary>
|
||||
@@ -206,15 +201,22 @@ namespace Radzen.Blazor
|
||||
}
|
||||
}
|
||||
|
||||
private string getButtonCss()
|
||||
{
|
||||
return $"rz-button rz-button-{getButtonSize()} rz-variant-{Enum.GetName(typeof(Variant), Variant).ToLowerInvariant()} rz-{Enum.GetName(typeof(ButtonStyle), ButtonStyle).ToLowerInvariant()} rz-shade-{Enum.GetName(typeof(Shade), Shade).ToLowerInvariant()} {(IsDisabled ? " rz-state-disabled" : "")}{(string.IsNullOrEmpty(Text) && !string.IsNullOrEmpty(Icon) ? " rz-button-icon-only" : "")}";
|
||||
}
|
||||
string ButtonClass => ClassList.Create("rz-button")
|
||||
.AddButtonSize(Size)
|
||||
.AddVariant(Variant)
|
||||
.AddButtonStyle(ButtonStyle)
|
||||
.AddShade(Shade)
|
||||
.Add("rz-button-icon-only", string.IsNullOrEmpty(Text) && !string.IsNullOrEmpty(Icon))
|
||||
.AddDisabled(IsDisabled)
|
||||
.ToString();
|
||||
|
||||
private string getPopupButtonCss()
|
||||
{
|
||||
return $"rz-splitbutton-menubutton rz-button rz-button-icon-only rz-button-{getButtonSize()} rz-variant-{Enum.GetName(typeof(Variant), Variant).ToLowerInvariant()} rz-{Enum.GetName(typeof(ButtonStyle), ButtonStyle).ToLowerInvariant()} rz-shade-{Enum.GetName(typeof(Shade), Shade).ToLowerInvariant()}{(IsDisabled ? " rz-state-disabled" : "")}";
|
||||
}
|
||||
string PopupButtonClass => ClassList.Create("rz-splitbutton-menubutton rz-button rz-button-icon-only")
|
||||
.AddButtonSize(Size)
|
||||
.AddVariant(Variant)
|
||||
.AddButtonStyle(ButtonStyle)
|
||||
.AddShade(Shade)
|
||||
.AddDisabled(IsDisabled)
|
||||
.ToString();
|
||||
|
||||
private string OpenPopupScript()
|
||||
{
|
||||
@@ -239,7 +241,7 @@ namespace Radzen.Blazor
|
||||
|
||||
if (IsJSRuntimeAvailable)
|
||||
{
|
||||
JSRuntime.InvokeVoidAsync("Radzen.destroyPopup", PopupID);
|
||||
JSRuntime.InvokeVoid("Radzen.destroyPopup", PopupID);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -332,4 +334,4 @@ namespace Radzen.Blazor
|
||||
[Parameter]
|
||||
public string ButtonAriaLabel { get; set; } = "Button";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
@inherits RadzenComponent
|
||||
@if (Visible)
|
||||
{
|
||||
<li class=@ItemClassList role="menuitem" @onclick="@OnClick" @attributes="Attributes" style="@Style">
|
||||
<li class=@ItemClass role="menuitem" @onclick="@OnClick" @attributes="Attributes" style="@Style">
|
||||
<a id="@(SplitButton.SplitButtonId() + GetHashCode())" class="rz-menuitem-link">
|
||||
@if (!string.IsNullOrEmpty(Icon))
|
||||
{
|
||||
|
||||
@@ -80,7 +80,10 @@ namespace Radzen.Blazor
|
||||
}
|
||||
}
|
||||
|
||||
ClassList ItemClassList => ClassList.Create("rz-menuitem").AddDisabled(Disabled).Add("rz-state-highlight", SplitButton.IsFocused(this));
|
||||
string ItemClass => ClassList.Create("rz-menuitem")
|
||||
.AddDisabled(Disabled)
|
||||
.Add("rz-state-highlight", SplitButton.IsFocused(this))
|
||||
.ToString();
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Dispose()
|
||||
|
||||
@@ -3,11 +3,7 @@
|
||||
{
|
||||
<div @ref="@Element" style="@Style" @attributes="Attributes" class="@GetCssClass()" id="@GetId()">
|
||||
<div class="rz-data-grid-data">
|
||||
<table class="@GetTableCssClass()">
|
||||
<CascadingValue Value=this>
|
||||
@ChildContent
|
||||
</CascadingValue>
|
||||
</table>
|
||||
<table class="@GetTableCssClass()">@ChildContent</table>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
@@ -1,57 +1,38 @@
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using Microsoft.AspNetCore.Components.Routing;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Components.Web;
|
||||
using Microsoft.JSInterop;
|
||||
using System;
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using Radzen.Blazor.Rendering;
|
||||
|
||||
namespace Radzen.Blazor
|
||||
namespace Radzen.Blazor;
|
||||
|
||||
/// <summary>
|
||||
/// Display a styled table with data.
|
||||
/// </summary>
|
||||
public partial class RadzenTable : RadzenComponentWithChildren
|
||||
{
|
||||
/// <summary>
|
||||
/// RadzenTable component.
|
||||
/// Gets or sets the grid lines style.
|
||||
/// </summary>
|
||||
public partial class RadzenTable : RadzenComponentWithChildren
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the grid lines.
|
||||
/// </summary>
|
||||
/// <value>The grid lines.</value>
|
||||
[Parameter]
|
||||
public DataGridGridLines GridLines { get; set; } = DataGridGridLines.Default;
|
||||
/// <value>The grid lines.</value>
|
||||
[Parameter]
|
||||
public DataGridGridLines GridLines { get; set; } = DataGridGridLines.Default;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether RadzenTable should use alternating row styles.
|
||||
/// </summary>
|
||||
/// <value><c>true</c> if RadzenTable is using alternating row styles; otherwise, <c>false</c>.</value>
|
||||
[Parameter]
|
||||
public bool AllowAlternatingRows { get; set; } = true;
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether RadzenTable should use alternating row styles.
|
||||
/// </summary>
|
||||
/// <value><c>true</c> if RadzenTable is using alternating row styles; otherwise, <c>false</c>.</value>
|
||||
[Parameter]
|
||||
public bool AllowAlternatingRows { get; set; } = true;
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override string GetComponentCssClass()
|
||||
{
|
||||
return $"rz-data-grid rz-datatable rz-datatable-scrollable {(CurrentStyle.ContainsKey("height") ? "rz-has-height" : "")}".Trim();
|
||||
}
|
||||
/// <inheritdoc />
|
||||
protected override string GetComponentCssClass() => ClassList.Create("rz-data-grid rz-datatable rz-datatable-scrollable")
|
||||
.Add("rz-has-height", CurrentStyle.ContainsKey("height"))
|
||||
.ToString();
|
||||
|
||||
/// <summary>
|
||||
/// Gets the table CSS classes.
|
||||
/// </summary>
|
||||
protected virtual string GetTableCssClass()
|
||||
{
|
||||
var styles = new List<string>(new string[] { "rz-grid-table", "rz-grid-table-fixed" });
|
||||
|
||||
if (AllowAlternatingRows)
|
||||
{
|
||||
styles.Add("rz-grid-table-striped");
|
||||
}
|
||||
|
||||
if (GridLines != DataGridGridLines.Default)
|
||||
{
|
||||
styles.Add($"rz-grid-gridlines-{Enum.GetName(typeof(DataGridGridLines), GridLines).ToLower()}");
|
||||
}
|
||||
|
||||
return string.Join(" ", styles);
|
||||
}
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Gets the table CSS classes.
|
||||
/// </summary>
|
||||
protected virtual string GetTableCssClass() => ClassList.Create("rz-grid-table rz-grid-table-fixed")
|
||||
.Add("rz-grid-table-striped", AllowAlternatingRows)
|
||||
.Add($"rz-grid-gridlines-{Enum.GetName(typeof(DataGridGridLines), GridLines).ToLowerInvariant()}", GridLines != DataGridGridLines.Default)
|
||||
.ToString();
|
||||
}
|
||||
@@ -1,9 +1,5 @@
|
||||
@inherits RadzenComponentWithChildren
|
||||
@if (Visible)
|
||||
{
|
||||
<tbody @ref="@Element" style="@Style" @attributes="Attributes" class="@GetCssClass()" id="@GetId()">
|
||||
<CascadingValue Value=this>
|
||||
@ChildContent
|
||||
</CascadingValue>
|
||||
</tbody>
|
||||
}
|
||||
<tbody @ref="@Element" style="@Style" @attributes="Attributes" class="@GetCssClass()" id="@GetId()">@ChildContent</tbody>
|
||||
}
|
||||
@@ -1,39 +1,5 @@
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Radzen.Blazor
|
||||
{
|
||||
/// <summary>
|
||||
/// RadzenTableBody component.
|
||||
/// </summary>
|
||||
public partial class RadzenTableBody : RadzenComponentWithChildren
|
||||
{
|
||||
List<RadzenTableRow> rows = new List<RadzenTableRow>();
|
||||
|
||||
/// <summary>
|
||||
/// Adds the row.
|
||||
/// </summary>
|
||||
/// <param name="row">The row.</param>
|
||||
public void AddRow(RadzenTableRow row)
|
||||
{
|
||||
if (rows.IndexOf(row) == -1)
|
||||
{
|
||||
rows.Add(row);
|
||||
StateHasChanged();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes the row.
|
||||
/// </summary>
|
||||
/// <param name="row">The row.</param>
|
||||
public void RemoveRow(RadzenTableRow row)
|
||||
{
|
||||
if (rows.IndexOf(row) != -1)
|
||||
{
|
||||
rows.Remove(row);
|
||||
StateHasChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
namespace Radzen.Blazor;
|
||||
/// <summary>
|
||||
/// RadzenTableBody component.
|
||||
/// </summary>
|
||||
public partial class RadzenTableBody : RadzenComponentWithChildren;
|
||||
@@ -2,10 +2,6 @@
|
||||
@if (Visible)
|
||||
{
|
||||
<td @ref="@Element" style="@Style" @attributes="Attributes" class="@GetCssClass()" id="@GetId()">
|
||||
<span class="rz-cell-data">
|
||||
<CascadingValue Value=this>
|
||||
@ChildContent
|
||||
</CascadingValue>
|
||||
</span>
|
||||
<span class="rz-cell-data">@ChildContent</span>
|
||||
</td>
|
||||
}
|
||||
}
|
||||
@@ -1,40 +1,10 @@
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using System.Collections.Generic;
|
||||
namespace Radzen.Blazor;
|
||||
|
||||
namespace Radzen.Blazor
|
||||
/// <summary>
|
||||
/// Represents a cell in <see cref="RadzenTable"/>
|
||||
/// </summary>
|
||||
public partial class RadzenTableCell : RadzenComponentWithChildren
|
||||
{
|
||||
/// <summary>
|
||||
/// RadzenTableRow component.
|
||||
/// </summary>
|
||||
public partial class RadzenTableCell : RadzenComponentWithChildren
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override string GetComponentCssClass()
|
||||
{
|
||||
return "rz-data-cell";
|
||||
}
|
||||
|
||||
RadzenTableRow _row;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the row.
|
||||
/// </summary>
|
||||
/// <value>The row.</value>
|
||||
[CascadingParameter]
|
||||
public RadzenTableRow Row
|
||||
{
|
||||
get
|
||||
{
|
||||
return _row;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (_row != value)
|
||||
{
|
||||
_row = value;
|
||||
_row.AddCell(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/// <inheritdoc />
|
||||
protected override string GetComponentCssClass() => "rz-data-cell";
|
||||
}
|
||||
@@ -1,9 +1,5 @@
|
||||
@inherits RadzenComponentWithChildren
|
||||
@if (Visible)
|
||||
{
|
||||
<thead @ref="@Element" style="@Style" @attributes="Attributes" class="@GetCssClass()" id="@GetId()">
|
||||
<CascadingValue Value=this>
|
||||
@ChildContent
|
||||
</CascadingValue>
|
||||
</thead>
|
||||
}
|
||||
<thead @ref="@Element" style="@Style" @attributes="Attributes" class="@GetCssClass()" id="@GetId()">@ChildContent</thead>
|
||||
}
|
||||
@@ -1,39 +1,6 @@
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using System.Collections.Generic;
|
||||
namespace Radzen.Blazor;
|
||||
|
||||
namespace Radzen.Blazor
|
||||
{
|
||||
/// <summary>
|
||||
/// RadzenTableHeader component.
|
||||
/// </summary>
|
||||
public partial class RadzenTableHeader : RadzenComponentWithChildren
|
||||
{
|
||||
List<RadzenTableHeaderRow> rows = new List<RadzenTableHeaderRow>();
|
||||
|
||||
/// <summary>
|
||||
/// Adds the row.
|
||||
/// </summary>
|
||||
/// <param name="row">The row.</param>
|
||||
public void AddRow(RadzenTableHeaderRow row)
|
||||
{
|
||||
if (rows.IndexOf(row) == -1)
|
||||
{
|
||||
rows.Add(row);
|
||||
StateHasChanged();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes the row.
|
||||
/// </summary>
|
||||
/// <param name="row">The row.</param>
|
||||
public void RemoveRow(RadzenTableHeaderRow row)
|
||||
{
|
||||
if (rows.IndexOf(row) != -1)
|
||||
{
|
||||
rows.Remove(row);
|
||||
StateHasChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// RadzenTableHeader component.
|
||||
/// </summary>
|
||||
public partial class RadzenTableHeader : RadzenComponentWithChildren;
|
||||
@@ -1,9 +1,5 @@
|
||||
@inherits RadzenComponentWithChildren
|
||||
@if (Visible)
|
||||
{
|
||||
<th @ref="@Element" style="padding: var(--rz-grid-cell-padding);@Style" @attributes="Attributes" class="@GetCssClass()" id="@GetId()">
|
||||
<CascadingValue Value=this>
|
||||
@ChildContent
|
||||
</CascadingValue>
|
||||
</th>
|
||||
}
|
||||
<th @ref="@Element" style="padding: var(--rz-grid-cell-padding);@Style" @attributes="Attributes" class="@GetCssClass()" id="@GetId()">@ChildContent</th>
|
||||
}
|
||||
@@ -1,34 +1,5 @@
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Radzen.Blazor
|
||||
{
|
||||
/// <summary>
|
||||
/// RadzenTableRow component.
|
||||
/// </summary>
|
||||
public partial class RadzenTableHeaderCell : RadzenComponentWithChildren
|
||||
{
|
||||
RadzenTableHeaderRow _row;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the row.
|
||||
/// </summary>
|
||||
/// <value>The row.</value>
|
||||
[CascadingParameter]
|
||||
public RadzenTableHeaderRow Row
|
||||
{
|
||||
get
|
||||
{
|
||||
return _row;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (_row != value)
|
||||
{
|
||||
_row = value;
|
||||
_row.AddCell(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
namespace Radzen.Blazor;
|
||||
/// <summary>
|
||||
/// RadzenTableRow component.
|
||||
/// </summary>
|
||||
public partial class RadzenTableHeaderCell : RadzenComponentWithChildren;
|
||||
|
||||
@@ -1,9 +1,5 @@
|
||||
@inherits RadzenComponentWithChildren
|
||||
@if (Visible)
|
||||
{
|
||||
<tr @ref="@Element" style="@Style" @attributes="Attributes" class="@GetCssClass()" id="@GetId()">
|
||||
<CascadingValue Value=this>
|
||||
@ChildContent
|
||||
</CascadingValue>
|
||||
</tr>
|
||||
}
|
||||
<tr @ref="@Element" style="@Style" @attributes="Attributes" class="@GetCssClass()" id="@GetId()">@ChildContent</tr>
|
||||
}
|
||||
@@ -1,62 +1,5 @@
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Radzen.Blazor
|
||||
{
|
||||
/// <summary>
|
||||
/// RadzenTableRow component.
|
||||
/// </summary>
|
||||
public partial class RadzenTableHeaderRow : RadzenComponentWithChildren
|
||||
{
|
||||
RadzenTableHeader _header;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the table body.
|
||||
/// </summary>
|
||||
/// <value>The table body.</value>
|
||||
[CascadingParameter]
|
||||
public RadzenTableHeader Header
|
||||
{
|
||||
get
|
||||
{
|
||||
return _header;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (_header != value)
|
||||
{
|
||||
_header = value;
|
||||
_header.AddRow(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
List<RadzenTableHeaderCell> cells = new List<RadzenTableHeaderCell>();
|
||||
|
||||
/// <summary>
|
||||
/// Adds the cell.
|
||||
/// </summary>
|
||||
/// <param name="cell">The cell.</param>
|
||||
public void AddCell(RadzenTableHeaderCell cell)
|
||||
{
|
||||
if (cells.IndexOf(cell) == -1)
|
||||
{
|
||||
cells.Add(cell);
|
||||
StateHasChanged();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes the cell.
|
||||
/// </summary>
|
||||
/// <param name="cell">The cell.</param>
|
||||
public void RemoveCell(RadzenTableHeaderCell cell)
|
||||
{
|
||||
if (cells.IndexOf(cell) != -1)
|
||||
{
|
||||
cells.Remove(cell);
|
||||
StateHasChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
namespace Radzen.Blazor;
|
||||
/// <summary>
|
||||
/// RadzenTableRow component.
|
||||
/// </summary>
|
||||
public partial class RadzenTableHeaderRow : RadzenComponentWithChildren;
|
||||
@@ -1,9 +1,5 @@
|
||||
@inherits RadzenComponentWithChildren
|
||||
@if (Visible)
|
||||
{
|
||||
<tr @ref="@Element" style="@Style" @attributes="Attributes" class="@GetCssClass()" id="@GetId()">
|
||||
<CascadingValue Value=this>
|
||||
@ChildContent
|
||||
</CascadingValue>
|
||||
</tr>
|
||||
}
|
||||
<tr @ref="@Element" style="@Style" @attributes="Attributes" class="@GetCssClass()" id="@GetId()">@ChildContent</tr>
|
||||
}
|
||||
@@ -1,68 +1,9 @@
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Radzen.Blazor
|
||||
namespace Radzen.Blazor;
|
||||
/// <summary>
|
||||
/// RadzenTableRow component.
|
||||
/// </summary>
|
||||
public partial class RadzenTableRow : RadzenComponentWithChildren
|
||||
{
|
||||
/// <summary>
|
||||
/// RadzenTableRow component.
|
||||
/// </summary>
|
||||
public partial class RadzenTableRow : RadzenComponentWithChildren
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override string GetComponentCssClass()
|
||||
{
|
||||
return "rz-data-row";
|
||||
}
|
||||
|
||||
RadzenTableBody _body;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the table body.
|
||||
/// </summary>
|
||||
/// <value>The table body.</value>
|
||||
[CascadingParameter]
|
||||
public RadzenTableBody Body
|
||||
{
|
||||
get
|
||||
{
|
||||
return _body;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (_body != value)
|
||||
{
|
||||
_body = value;
|
||||
_body.AddRow(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
List<RadzenTableCell> cells = new List<RadzenTableCell>();
|
||||
|
||||
/// <summary>
|
||||
/// Adds the cell.
|
||||
/// </summary>
|
||||
/// <param name="cell">The cell.</param>
|
||||
public void AddCell(RadzenTableCell cell)
|
||||
{
|
||||
if (cells.IndexOf(cell) == -1)
|
||||
{
|
||||
cells.Add(cell);
|
||||
StateHasChanged();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes the cell.
|
||||
/// </summary>
|
||||
/// <param name="cell">The cell.</param>
|
||||
public void RemoveCell(RadzenTableCell cell)
|
||||
{
|
||||
if (cells.IndexOf(cell) != -1)
|
||||
{
|
||||
cells.Remove(cell);
|
||||
StateHasChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/// <inheritdoc />
|
||||
protected override string GetComponentCssClass() => "rz-data-row";
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
@implements IDisposable
|
||||
@if (Tabs.RenderMode == TabRenderMode.Server ? Visible : true)
|
||||
{
|
||||
<li role="presentation" @attributes=@Attributes style=@getStyle() class=@ClassList>
|
||||
<li role="presentation" @attributes=@Attributes style=@getStyle() class=@Class>
|
||||
<a @onclick=@OnClick role="tab" @onclick:preventDefault="true" id="@($"{Tabs.Id}-tabpanel-{Index}-label")"
|
||||
aria-selected=@(IsSelected? "true" : "false") aria-controls="@($"{Tabs.Id}-tabpanel-{Index}")" @onkeydown:stopPropagation>
|
||||
@if (!string.IsNullOrEmpty(Icon))
|
||||
|
||||
@@ -79,11 +79,12 @@ namespace Radzen.Blazor
|
||||
/// Gets the class list.
|
||||
/// </summary>
|
||||
/// <value>The class list.</value>
|
||||
ClassList ClassList => ClassList.Create()
|
||||
.Add("rz-tabview-selected", IsSelected)
|
||||
.Add("rz-state-focused", Tabs.IsFocused(this))
|
||||
.AddDisabled(Disabled)
|
||||
.Add(Attributes);
|
||||
string Class => ClassList.Create()
|
||||
.Add("rz-tabview-selected", IsSelected)
|
||||
.Add("rz-state-focused", Tabs.IsFocused(this))
|
||||
.AddDisabled(Disabled)
|
||||
.Add(Attributes)
|
||||
.ToString();
|
||||
|
||||
/// <summary>
|
||||
/// Gets the index.
|
||||
|
||||
@@ -348,16 +348,17 @@ namespace Radzen.Blazor
|
||||
break;
|
||||
}
|
||||
|
||||
var classList = ClassList.Create(className)
|
||||
.Add(Attributes)
|
||||
.Add(alignClassName, TextAlign != TextAlign.Left);
|
||||
var @class = ClassList.Create(className)
|
||||
.Add(Attributes)
|
||||
.Add(alignClassName, TextAlign != TextAlign.Left)
|
||||
.ToString();
|
||||
|
||||
if (Visible)
|
||||
{
|
||||
builder.OpenElement(0, tagName);
|
||||
builder.AddAttribute(1, "style", Style);
|
||||
builder.AddMultipleAttributes(2, Attributes);
|
||||
builder.AddAttribute(3, "class", classList.ToString());
|
||||
builder.AddAttribute(3, "class", @class);
|
||||
builder.AddAttribute(4, "id", GetId());
|
||||
|
||||
if (!string.IsNullOrEmpty(Text))
|
||||
|
||||
@@ -231,15 +231,6 @@ namespace Radzen.Blazor
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the class list.
|
||||
/// </summary>
|
||||
/// <param name="className">Name of the class.</param>
|
||||
/// <returns>ClassList.</returns>
|
||||
protected ClassList GetClassList(string className) => ClassList.Create(className)
|
||||
.AddDisabled(Disabled)
|
||||
.Add(FieldIdentifier, EditContext);
|
||||
|
||||
/// <summary> Provides support for RadzenFormField integration. </summary>
|
||||
[CascadingParameter]
|
||||
public IFormFieldContext FormFieldContext { get; set; }
|
||||
@@ -279,22 +270,19 @@ namespace Radzen.Blazor
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override string GetComponentCssClass()
|
||||
{
|
||||
var classes = GetClassList("rz-toggle-button");
|
||||
protected override string GetComponentCssClass() => ClassList.Create("rz-button rz-toggle-button")
|
||||
.Add("rz-button-icon-only", string.IsNullOrEmpty(Text) && !string.IsNullOrEmpty(Icon))
|
||||
.AddButtonSize(Size)
|
||||
.AddVariant(Variant)
|
||||
.AddButtonStyle(CurrentButtonStyle)
|
||||
.AddShade(CurrentShade)
|
||||
.AddDisabled(IsDisabled)
|
||||
.Add(FieldIdentifier, EditContext)
|
||||
.Add("rz-state-active", HasValue)
|
||||
.ToString();
|
||||
|
||||
if (HasValue)
|
||||
{
|
||||
classes.Add("rz-state-active", Value);
|
||||
}
|
||||
|
||||
var baseClasses = HasValue ?
|
||||
$"rz-button rz-button-{getButtonSize()} rz-variant-{Enum.GetName(typeof(Variant), Variant).ToLowerInvariant()} rz-{Enum.GetName(typeof(ButtonStyle), ToggleButtonStyle).ToLowerInvariant()} rz-shade-{Enum.GetName(typeof(Shade), ToggleShade).ToLowerInvariant()}{(IsDisabled ? " rz-state-disabled" : "")}{(string.IsNullOrEmpty(Text) && !string.IsNullOrEmpty(Icon) ? " rz-button-icon-only" : "")}" :
|
||||
$"rz-button rz-button-{getButtonSize()} rz-variant-{Enum.GetName(typeof(Variant), Variant).ToLowerInvariant()} rz-{Enum.GetName(typeof(ButtonStyle), ButtonStyle).ToLowerInvariant()} rz-shade-{Enum.GetName(typeof(Shade), Shade).ToLowerInvariant()}{(IsDisabled ? " rz-state-disabled" : "")}{(string.IsNullOrEmpty(Text) && !string.IsNullOrEmpty(Icon) ? " rz-button-icon-only" : "")}";
|
||||
|
||||
|
||||
return $"{baseClasses} {classes.ToString()}";
|
||||
}
|
||||
private Shade CurrentShade => HasValue ? ToggleShade : Shade;
|
||||
private ButtonStyle CurrentButtonStyle => HasValue ? ToggleButtonStyle : ButtonStyle;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the ToggleButton style.
|
||||
|
||||
@@ -4,10 +4,10 @@
|
||||
@{var itemArgs = Tree?.ItemAttributes(this); }
|
||||
<li class="rz-treenode" @attributes="@(itemArgs.Item1.Attributes.Any() ? itemArgs.Item1.Attributes : Attributes)"
|
||||
@oncontextmenu="OnContextMenu" @oncontextmenu:preventDefault="@Tree.ItemContextMenu.HasDelegate" @oncontextmenu:stopPropagation>
|
||||
<div class=@ContentClassList @onclick="@Select">
|
||||
<div class=@ContentClass @onclick="@Select">
|
||||
@if (ChildContent != null || HasChildren)
|
||||
{
|
||||
<span class=@IconClassList @onclick="@Toggle" @onclick:stopPropagation></span>
|
||||
<span class=@IconClass @onclick="@Toggle" @onclick:stopPropagation></span>
|
||||
}
|
||||
@if(Tree != null && Tree.AllowCheckBoxes)
|
||||
{
|
||||
@@ -15,18 +15,20 @@
|
||||
}
|
||||
@if (Template != null)
|
||||
{
|
||||
<div class="@LabelClassList" @onkeydown:stopPropagation>@Template(this)</div>
|
||||
<div class=@LabelClass @onkeydown:stopPropagation>@Template(this)</div>
|
||||
} else
|
||||
{
|
||||
<label for="@(GetHashCode())" class="@LabelClassList">@Text</label>
|
||||
<label for="@(GetHashCode())" class=@LabelClass>@Text</label>
|
||||
}
|
||||
</div>
|
||||
@if (ChildContent != null && expanded)
|
||||
{
|
||||
<CascadingValue Value=this>
|
||||
<ul class="rz-treenode-children" style=@(clientExpanded ? "" : "display:none;") @onkeydown:stopPropagation>
|
||||
<Expander Expanded=@clientExpanded>
|
||||
<ul class="rz-treenode-children" @onkeydown:stopPropagation>
|
||||
@ChildContent
|
||||
</ul>
|
||||
</Expander>
|
||||
</CascadingValue>
|
||||
}
|
||||
</li>
|
||||
|
||||
@@ -21,19 +21,22 @@ namespace Radzen.Blazor
|
||||
[Parameter(CaptureUnmatchedValues = true)]
|
||||
public IReadOnlyDictionary<string, object> Attributes { get; set; }
|
||||
|
||||
ClassList ContentClassList => ClassList.Create("rz-treenode-content")
|
||||
.Add("rz-treenode-content-selected", selected)
|
||||
.Add("rz-state-focused", Tree.IsFocused(this))
|
||||
.Add(Tree.ItemContentCssClass)
|
||||
.Add(ContentCssClass);
|
||||
ClassList IconClassList => ClassList.Create("notranslate rz-tree-toggler rzi")
|
||||
.Add("rzi-caret-down", clientExpanded)
|
||||
.Add("rzi-caret-right", !clientExpanded)
|
||||
.Add(Tree.ItemIconCssClass)
|
||||
.Add(IconCssClass);
|
||||
private ClassList LabelClassList => ClassList.Create("rz-treenode-label")
|
||||
.Add(Tree.ItemLabelCssClass)
|
||||
.Add(LabelCssClass);
|
||||
string ContentClass => ClassList.Create("rz-treenode-content")
|
||||
.Add("rz-treenode-content-selected", selected)
|
||||
.Add("rz-state-focused", Tree.IsFocused(this))
|
||||
.Add(Tree.ItemContentCssClass)
|
||||
.Add(ContentCssClass)
|
||||
.ToString();
|
||||
string IconClass => ClassList.Create("notranslate rz-tree-toggler rzi")
|
||||
.Add("rzi-caret-down", clientExpanded)
|
||||
.Add("rzi-caret-right", !clientExpanded)
|
||||
.Add(Tree.ItemIconCssClass)
|
||||
.Add(IconCssClass)
|
||||
.ToString();
|
||||
string LabelClass => ClassList.Create("rz-treenode-label")
|
||||
.Add(Tree.ItemLabelCssClass)
|
||||
.Add(LabelCssClass)
|
||||
.ToString();
|
||||
/// <summary>
|
||||
/// Gets or sets the child content.
|
||||
/// </summary>
|
||||
|
||||
@@ -141,15 +141,17 @@ namespace Radzen.Blazor
|
||||
/// Gets the choose class list.
|
||||
/// </summary>
|
||||
/// <value>The choose class list.</value>
|
||||
ClassList ChooseClassList => ClassList.Create("rz-fileupload-choose rz-button")
|
||||
.AddDisabled(Disabled);
|
||||
string ChooseClassList => ClassList.Create("rz-fileupload-choose rz-button")
|
||||
.AddDisabled(Disabled)
|
||||
.ToString();
|
||||
|
||||
/// <summary>
|
||||
/// Gets the button class list.
|
||||
/// </summary>
|
||||
/// <value>The button class list.</value>
|
||||
ClassList ButtonClassList => ClassList.Create("rz-button rz-button-icon-only rz-base rz-shade-default")
|
||||
.AddDisabled(Disabled);
|
||||
string ButtonClassList => ClassList.Create("rz-button rz-button-icon-only rz-base rz-shade-default")
|
||||
.AddDisabled(Disabled)
|
||||
.ToString();
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the child content.
|
||||
|
||||
@@ -3,118 +3,169 @@ using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using Microsoft.AspNetCore.Components.Forms;
|
||||
|
||||
namespace Radzen.Blazor.Rendering
|
||||
namespace Radzen.Blazor.Rendering;
|
||||
|
||||
/// <summary>
|
||||
/// Utility for managing a list of CSS classes.
|
||||
/// </summary>
|
||||
public readonly struct ClassList
|
||||
{
|
||||
/// <summary>
|
||||
/// Class ClassList.
|
||||
/// </summary>
|
||||
public class ClassList
|
||||
private ClassList(string className = null)
|
||||
{
|
||||
/// <summary>
|
||||
/// The builder
|
||||
/// </summary>
|
||||
private readonly StringBuilder builder = new StringBuilder();
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ClassList"/> class.
|
||||
/// </summary>
|
||||
/// <param name="className">Name of the class.</param>
|
||||
private ClassList(string className = null)
|
||||
{
|
||||
Add(className);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates the specified class name.
|
||||
/// </summary>
|
||||
/// <param name="className">Name of the class.</param>
|
||||
/// <returns>ClassList.</returns>
|
||||
public static ClassList Create(string className = null) => new ClassList(className);
|
||||
|
||||
/// <summary>
|
||||
/// Adds the specified class name.
|
||||
/// </summary>
|
||||
/// <param name="className">Name of the class.</param>
|
||||
/// <param name="condition">if set to <c>true</c> [condition].</param>
|
||||
/// <returns>ClassList.</returns>
|
||||
public ClassList Add(string className, bool condition = true)
|
||||
{
|
||||
if (condition && !string.IsNullOrWhiteSpace(className))
|
||||
{
|
||||
if (builder.Length > 0)
|
||||
{
|
||||
builder.Append(" ");
|
||||
}
|
||||
|
||||
builder.Append(className);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds the specified attributes.
|
||||
/// </summary>
|
||||
/// <param name="attributes">The attributes.</param>
|
||||
/// <returns>ClassList.</returns>
|
||||
public ClassList Add(IDictionary<string, object> attributes)
|
||||
{
|
||||
if (attributes != null && attributes.TryGetValue("class", out var className) && className != null)
|
||||
{
|
||||
return Add(className.ToString());
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds the specified attributes.
|
||||
/// </summary>
|
||||
/// <param name="attributes">The attributes.</param>
|
||||
/// <returns>ClassList.</returns>
|
||||
public ClassList Add(IReadOnlyDictionary<string, object> attributes)
|
||||
{
|
||||
if (attributes != null && attributes.TryGetValue("class", out var className) && className != null)
|
||||
{
|
||||
return Add(className.ToString());
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds the specified field.
|
||||
/// </summary>
|
||||
/// <param name="field">The field.</param>
|
||||
/// <param name="context">The context.</param>
|
||||
/// <returns>ClassList.</returns>
|
||||
public ClassList Add(FieldIdentifier field, EditContext context)
|
||||
{
|
||||
if (field.FieldName != null && context != null)
|
||||
{
|
||||
return Add(context.FieldCssClass(field));
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds the disabled.
|
||||
/// </summary>
|
||||
/// <param name="condition">if set to <c>true</c> [condition].</param>
|
||||
/// <returns>ClassList.</returns>
|
||||
public ClassList AddDisabled(bool condition = true)
|
||||
{
|
||||
return Add("rz-state-disabled", condition);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a <see cref="System.String" /> that represents this instance.
|
||||
/// </summary>
|
||||
/// <returns>A <see cref="System.String" /> that represents this instance.</returns>
|
||||
public override string ToString()
|
||||
{
|
||||
return builder.ToString();
|
||||
}
|
||||
Add(className);
|
||||
}
|
||||
|
||||
private readonly StringBuilder builder = StringBuilderCache.Acquire();
|
||||
|
||||
/// <summary>
|
||||
/// Creates the specified class name.
|
||||
/// </summary>
|
||||
/// <param name="className">Name of the class.</param>
|
||||
/// <returns>ClassList.</returns>
|
||||
public static ClassList Create(string className = null) => new(className);
|
||||
|
||||
/// <summary>
|
||||
/// Adds the specified class name if the condition is true.
|
||||
/// </summary>
|
||||
/// <param name="className">Name of the class.</param>
|
||||
/// <param name="condition">if set to <c>true</c> the class name is added.</param>
|
||||
/// <remarks>
|
||||
/// The class name is added only if it is not null or empty.
|
||||
/// </remarks>
|
||||
public ClassList Add(string className, bool condition = true)
|
||||
{
|
||||
if (condition && !string.IsNullOrWhiteSpace(className))
|
||||
{
|
||||
if (builder.Length > 0)
|
||||
{
|
||||
builder.Append(' ');
|
||||
}
|
||||
|
||||
builder.Append(className);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the provided attributes contain a class name and adds it to the list.
|
||||
/// </summary>
|
||||
/// <param name="attributes">The attributes.</param>
|
||||
public ClassList Add(IDictionary<string, object> attributes)
|
||||
{
|
||||
if (attributes != null && attributes.TryGetValue("class", out var value) && value is string @class)
|
||||
{
|
||||
return Add(@class);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the provided attributes contain a class name and adds it to the list.
|
||||
/// </summary>
|
||||
/// <param name="attributes">The attributes.</param>
|
||||
public ClassList Add(IReadOnlyDictionary<string, object> attributes)
|
||||
{
|
||||
if (attributes != null && attributes.TryGetValue("class", out var value) && value is string @class)
|
||||
{
|
||||
return Add(@class);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds the class returned by the EditContext for the specified field identifier
|
||||
/// </summary>
|
||||
/// <param name="field">The field.</param>
|
||||
/// <param name="context">The context.</param>
|
||||
public ClassList Add(FieldIdentifier field, EditContext context)
|
||||
{
|
||||
if (field.FieldName != null && context != null)
|
||||
{
|
||||
return Add(context.FieldCssClass(field));
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds the disabled class if the condition is true.
|
||||
/// </summary>
|
||||
public ClassList AddDisabled(bool condition = true) => Add("rz-state-disabled", condition);
|
||||
|
||||
/// <summary>
|
||||
/// Adds the specified size as button size class.
|
||||
/// </summary>
|
||||
/// <exception cref="ArgumentOutOfRangeException"></exception>
|
||||
public ClassList AddButtonSize(ButtonSize size) => size switch {
|
||||
ButtonSize.Small => Add("rz-button-sm"),
|
||||
ButtonSize.Large => Add("rz-button-lg"),
|
||||
ButtonSize.Medium => Add("rz-button-md"),
|
||||
ButtonSize.ExtraSmall => Add("rz-button-xs"),
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(size), size, null)
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Adds the specified variant as variant CSS class.
|
||||
/// </summary>
|
||||
/// <exception cref="ArgumentOutOfRangeException"></exception>
|
||||
public ClassList AddVariant(Variant variant) => variant switch {
|
||||
Variant.Filled => Add("rz-variant-filled"),
|
||||
Variant.Flat => Add("rz-variant-flat"),
|
||||
Variant.Outlined => Add("rz-variant-outlined"),
|
||||
Variant.Text => Add("rz-variant-text"),
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(variant), variant, null)
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Adds the specified button style as shade CSS class.
|
||||
/// </summary>
|
||||
/// <param name="style"></param>
|
||||
/// <exception cref="ArgumentOutOfRangeException"></exception>
|
||||
public ClassList AddButtonStyle(ButtonStyle style) => style switch {
|
||||
ButtonStyle.Primary => Add("rz-primary"),
|
||||
ButtonStyle.Secondary => Add("rz-secondary"),
|
||||
ButtonStyle.Light => Add("rz-light"),
|
||||
ButtonStyle.Base => Add("rz-base"),
|
||||
ButtonStyle.Dark => Add("rz-dark"),
|
||||
ButtonStyle.Success => Add("rz-success"),
|
||||
ButtonStyle.Warning => Add("rz-warning"),
|
||||
ButtonStyle.Danger => Add("rz-danger"),
|
||||
ButtonStyle.Info => Add("rz-info"),
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(style), style, null)
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Adds the specified shade as a CSS class.
|
||||
/// </summary>
|
||||
/// <param name="shade"></param>
|
||||
/// <exception cref="ArgumentOutOfRangeException"></exception>
|
||||
public ClassList AddShade(Shade shade) => shade switch {
|
||||
Shade.Default => Add("rz-shade-default"),
|
||||
Shade.Light => Add("rz-shade-light"),
|
||||
Shade.Dark => Add("rz-shade-dark"),
|
||||
Shade.Lighter => Add("rz-shade-lighter"),
|
||||
Shade.Darker => Add("rz-shade-darker"),
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(shade), shade, null)
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Adds the specified horizontal alignment as a CSS class.
|
||||
/// </summary>
|
||||
/// <exception cref="ArgumentOutOfRangeException"></exception>
|
||||
public ClassList AddHorizontalAlign(HorizontalAlign alignment) => alignment switch {
|
||||
HorizontalAlign.Center => Add("rz-align-center"),
|
||||
HorizontalAlign.Left => Add("rz-align-left"),
|
||||
HorizontalAlign.Right => Add("rz-align-right"),
|
||||
HorizontalAlign.Justify => Add("rz-align-justify"),
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(alignment), alignment, null)
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Returns a <see cref="System.String" /> that represents this instance.
|
||||
/// </summary>
|
||||
/// <returns>A <see cref="System.String" /> that represents this instance.</returns>
|
||||
public override string ToString() => StringBuilderCache.GetStringAndRelease(builder);
|
||||
}
|
||||
@@ -9,7 +9,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div @ref=view class="rz-view-content" tabindex="0" @onkeydown="@(args => OnKeyPress(args))" @onkeydown:preventDefault="@preventKeyPress" @onkeydown:stopPropagation
|
||||
@onfocus=@(args => {if(CurrentDate == default(DateTime)) { CurrentDate = StartDate; }})>
|
||||
@onfocus=@this.AsNonRenderingEventHandler(OnFocus)>
|
||||
<Hours Start=@StartTime End=@EndTime TimeFormat=@TimeFormat MinutesPerSlot=@MinutesPerSlot />
|
||||
<div class="rz-slots">
|
||||
<DaySlotEvents MinutesPerSlot=@MinutesPerSlot StartDate=@StartDate EndDate=@EndDate Appointments=@Appointments CurrentDate="@CurrentDate" CurrentAppointment="@currentAppointment" AppointmentDragStart=@OnAppointmentDragStart />
|
||||
@@ -23,6 +23,14 @@
|
||||
</div>
|
||||
|
||||
@code {
|
||||
void OnFocus()
|
||||
{
|
||||
if (CurrentDate == default(DateTime))
|
||||
{
|
||||
CurrentDate = StartDate;
|
||||
}
|
||||
}
|
||||
|
||||
ElementReference view;
|
||||
|
||||
[Parameter]
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
@using System.ComponentModel
|
||||
@inject IJSRuntime JSRuntime
|
||||
@implements IDisposable
|
||||
<div class="@WrapperCssClass">
|
||||
<div @ref="dialog" class="@CssClass" role="dialog" aria-labelledby="rz-dialog-0-label" style=@Style>
|
||||
<div class=@WrapperClass>
|
||||
<div @ref="dialog" class=@Class role="dialog" aria-labelledby="rz-dialog-0-label" style=@Style>
|
||||
@if (Dialog.Options.ShowTitle)
|
||||
{
|
||||
<div class="rz-dialog-titlebar">
|
||||
@@ -26,7 +26,7 @@
|
||||
}
|
||||
</div>
|
||||
}
|
||||
<div class="@ContentCssClass">
|
||||
<div class=@ContentClass>
|
||||
@if (Dialog.Options.ChildContent != null)
|
||||
{
|
||||
@Dialog.Options.ChildContent(Service)
|
||||
@@ -49,7 +49,6 @@
|
||||
<div class="rz-dialog-mask" style="pointer-events: none;"></div>
|
||||
}
|
||||
}
|
||||
|
||||
</div>
|
||||
|
||||
@code {
|
||||
@@ -158,32 +157,17 @@
|
||||
Service.Close();
|
||||
}
|
||||
|
||||
string CssClass
|
||||
{
|
||||
get
|
||||
{
|
||||
var baseCss = "rz-dialog";
|
||||
return string.IsNullOrEmpty(Dialog.Options.CssClass) ? baseCss : $"{baseCss} {Dialog.Options.CssClass}";
|
||||
}
|
||||
}
|
||||
string Class => ClassList.Create("rz-dialog rz-open")
|
||||
.Add(Dialog.Options.CssClass)
|
||||
.ToString();
|
||||
|
||||
string WrapperCssClass
|
||||
{
|
||||
get
|
||||
{
|
||||
var baseCss = "rz-dialog-wrapper";
|
||||
return string.IsNullOrWhiteSpace(Dialog.Options.WrapperCssClass) ? baseCss : $"{baseCss} {Dialog.Options.WrapperCssClass}";
|
||||
}
|
||||
}
|
||||
string WrapperClass => ClassList.Create("rz-dialog-wrapper")
|
||||
.Add(Dialog.Options.WrapperCssClass)
|
||||
.ToString();
|
||||
|
||||
string ContentCssClass
|
||||
{
|
||||
get
|
||||
{
|
||||
var baseCss = "rz-dialog-content";
|
||||
return string.IsNullOrEmpty(Dialog.Options.ContentCssClass) ? baseCss : $"{baseCss} {Dialog.Options.ContentCssClass}";
|
||||
}
|
||||
}
|
||||
string ContentClass => ClassList.Create("rz-dialog-content")
|
||||
.Add(Dialog.Options.ContentCssClass)
|
||||
.ToString();
|
||||
|
||||
string Style
|
||||
{
|
||||
|
||||
@@ -52,20 +52,9 @@ else
|
||||
|
||||
string GetTitle() => !string.IsNullOrEmpty(Shortcut) ? $"{Title} ({Shortcut})" : Title;
|
||||
|
||||
string Class
|
||||
{
|
||||
get
|
||||
{
|
||||
var classList = new List<string>() { "rz-html-editor-button" };
|
||||
|
||||
if (Selected && !Editor.Disabled && EnabledModes.HasFlag(Editor.GetMode()))
|
||||
{
|
||||
classList.Add("rz-selected");
|
||||
}
|
||||
|
||||
return string.Join(" ", classList);
|
||||
}
|
||||
}
|
||||
string Class => ClassList.Create("rz-html-editor-button")
|
||||
.Add("rz-selected", Selected && !Editor.Disabled && EnabledModes.HasFlag(Editor.GetMode()))
|
||||
.ToString();
|
||||
|
||||
void Empty()
|
||||
{
|
||||
|
||||
@@ -75,18 +75,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
string Class
|
||||
{
|
||||
get
|
||||
{
|
||||
var classList = new List<string>() { "rz-html-editor-dropdown" };
|
||||
|
||||
if (Editor.Disabled || !EnabledModes.HasFlag(Editor.GetMode()))
|
||||
{
|
||||
classList.Add("rz-disabled");
|
||||
}
|
||||
|
||||
return string.Join(" ", classList);
|
||||
}
|
||||
}
|
||||
string Class => ClassList.Create("rz-html-editor-dropdown")
|
||||
.Add("rz-disabled", Editor.Disabled || !EnabledModes.HasFlag(Editor.GetMode()))
|
||||
.ToString();
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user