using System.Collections.Generic; using System.Text.Json; using System.Threading.Tasks; using AntDesign.JsInterop; using Microsoft.AspNetCore.Components; using Microsoft.AspNetCore.Components.Rendering; using Microsoft.AspNetCore.Components.Web; namespace AntDesign { /// /// /// public class Input : AntInputComponentBase { protected const string PrefixCls = "ant-input"; private bool _allowClear; protected string AffixWrapperClass { get; set; } = $"{PrefixCls}-affix-wrapper"; protected string GroupWrapperClass { get; set; } = $"{PrefixCls}-group-wrapper"; //protected string ClearIconClass { get; set; } protected static readonly EventCallbackFactory CallbackFactory = new EventCallbackFactory(); protected virtual bool IgnoreOnChangeAndBlur { get; } protected virtual bool EnableOnPressEnter => OnPressEnter.HasDelegate; [Inject] public DomEventService DomEventService { get; set; } [Parameter] public string Type { get; set; } = "text"; [Parameter] public RenderFragment AddOnBefore { get; set; } [Parameter] public RenderFragment AddOnAfter { get; set; } [Parameter] public string Placeholder { get; set; } [Parameter] public bool AutoFocus { get; set; } [Parameter] public TValue DefaultValue { get; set; } [Parameter] public int MaxLength { get; set; } = -1; [Parameter] public bool Disabled { get; set; } [Parameter] public bool AllowClear { get; set; } [Parameter] public RenderFragment Prefix { get; set; } [Parameter] public RenderFragment Suffix { get; set; } [Parameter] public RenderFragment ChildContent { get; set; } [Parameter] public EventCallback OnChange { get; set; } [Parameter] public EventCallback OnPressEnter { get; set; } [Parameter] public EventCallback OnkeyUp { get; set; } [Parameter] public EventCallback OnkeyDown { get; set; } [Parameter] public EventCallback OnMouseUp { get; set; } [Parameter] public EventCallback OnInput { get; set; } [Parameter] public EventCallback OnBlur { get; set; } [Parameter] public EventCallback OnFocus { get; set; } public Dictionary Attributes { get; set; } private TValue _inputValue; private bool _compositionInputting = false; protected override void OnInitialized() { base.OnInitialized(); if (!string.IsNullOrEmpty(DefaultValue?.ToString()) && string.IsNullOrEmpty(Value?.ToString())) { Value = DefaultValue; } SetClasses(); } protected virtual void SetClasses() { AffixWrapperClass = $"{PrefixCls}-affix-wrapper"; GroupWrapperClass = $"{PrefixCls}-group-wrapper"; if (!string.IsNullOrWhiteSpace(Class)) { AffixWrapperClass = string.Join(" ", Class, AffixWrapperClass); ClassMapper.OriginalClass = ""; } ClassMapper.Clear() .Add($"{PrefixCls}") .If($"{PrefixCls}-lg", () => Size == InputSize.Large) .If($"{PrefixCls}-sm", () => Size == InputSize.Small); Attributes ??= new Dictionary(); if (MaxLength >= 0) { Attributes?.Add("maxlength", MaxLength); } if (Disabled) { // TODO: disable element AffixWrapperClass = string.Join(" ", AffixWrapperClass, $"{PrefixCls}-affix-wrapper-disabled"); ClassMapper.Add($"{PrefixCls}-disabled"); } if (AllowClear) { _allowClear = true; //ClearIconClass = $"{PrefixCls}-clear-icon"; ToggleClearBtn(); } if (Size == InputSize.Large) { AffixWrapperClass = string.Join(" ", AffixWrapperClass, $"{PrefixCls}-affix-wrapper-lg"); GroupWrapperClass = string.Join(" ", GroupWrapperClass, $"{PrefixCls}-group-wrapper-lg"); } else if (Size == InputSize.Small) { AffixWrapperClass = string.Join(" ", AffixWrapperClass, $"{PrefixCls}-affix-wrapper-sm"); GroupWrapperClass = string.Join(" ", GroupWrapperClass, $"{PrefixCls}-group-wrapper-sm"); } } protected override void OnParametersSet() { base.OnParametersSet(); SetClasses(); } public async Task Focus() { await JsInvokeAsync(JSInteropConstants.Focus, Ref); } protected virtual async Task OnChangeAsync(ChangeEventArgs args) { if (CurrentValueAsString != args?.Value?.ToString()) { if (OnChange.HasDelegate) { await OnChange.InvokeAsync(Value); } } } protected async Task OnKeyPressAsync(KeyboardEventArgs args) { if (args != null && args.Key == "Enter" && EnableOnPressEnter) { await ChangeValue(); await OnPressEnter.InvokeAsync(args); await OnPressEnterAsync(); } } protected virtual Task OnPressEnterAsync() => Task.CompletedTask; protected async Task OnKeyUpAsync(KeyboardEventArgs args) { await ChangeValue(); if (OnkeyUp.HasDelegate) await OnkeyUp.InvokeAsync(args); } protected virtual async Task OnkeyDownAsync(KeyboardEventArgs args) { if (OnkeyDown.HasDelegate) await OnkeyDown.InvokeAsync(args); } protected async Task OnMouseUpAsync(MouseEventArgs args) { await ChangeValue(); if (OnMouseUp.HasDelegate) await OnMouseUp.InvokeAsync(args); } internal virtual async Task OnBlurAsync(FocusEventArgs e) { if (_compositionInputting) { _compositionInputting = false; } await ChangeValue(); if (OnBlur.HasDelegate) { await OnBlur.InvokeAsync(e); } } internal virtual async Task OnFocusAsync(FocusEventArgs e) { if (OnFocus.HasDelegate) { await OnFocus.InvokeAsync(e); } } internal virtual void OnCompositionStart(JsonElement e) { _compositionInputting = true; } internal virtual void OnCompositionEnd(JsonElement e) { _compositionInputting = false; } private void ToggleClearBtn() { Suffix = (builder) => { builder.OpenComponent(31); builder.AddAttribute(32, "Type", "close-circle"); builder.AddAttribute(33, "Class", GetClearIconCls()); if (string.IsNullOrEmpty(Value?.ToString())) { builder.AddAttribute(34, "Style", "visibility: hidden;"); } else { builder.AddAttribute(34, "Style", "visibility: visible;"); } builder.AddAttribute(35, "OnClick", CallbackFactory.Create(this, (args) => { CurrentValue = default; if (OnChange.HasDelegate) OnChange.InvokeAsync(Value); ToggleClearBtn(); })); builder.CloseComponent(); }; } private async Task ChangeValue() { if (!_compositionInputting) { if (!EqualityComparer.Default.Equals(CurrentValue, _inputValue)) { CurrentValue = _inputValue; if (OnChange.HasDelegate) { await OnChange.InvokeAsync(Value); } } } } protected override async Task OnAfterRenderAsync(bool firstRender) { await base.OnAfterRenderAsync(firstRender); if (firstRender) { DomEventService.AddEventListener(Ref, "compositionstart", OnCompositionStart); DomEventService.AddEventListener(Ref, "compositionend", OnCompositionEnd); if (this.AutoFocus) { await this.Focus(); } } } protected override void Dispose(bool disposing) { DomEventService.RemoveEventListerner(Ref, "compositionstart", OnCompositionStart); DomEventService.RemoveEventListerner(Ref, "compositionend", OnCompositionEnd); base.Dispose(disposing); } protected virtual string GetClearIconCls() { return $"{PrefixCls}-clear-icon"; } protected override void OnValueChange(TValue value) { base.OnValueChange(value); _inputValue = value; } /// /// Invoked when user add/remove content /// /// /// protected virtual async void OnInputAsync(ChangeEventArgs args) { bool flag = !(!string.IsNullOrEmpty(Value?.ToString()) && args != null && !string.IsNullOrEmpty(args.Value.ToString())); if (TryParseValueFromString(args?.Value.ToString(), out TValue value, out var error)) { _inputValue = value; } if (_allowClear && flag) { ToggleClearBtn(); } if (OnInput.HasDelegate) { await OnInput.InvokeAsync(args); } } protected override void BuildRenderTree(RenderTreeBuilder builder) { if (builder != null) { base.BuildRenderTree(builder); string container = "input"; if (AddOnBefore != null || AddOnAfter != null) { container = "groupWrapper"; builder.OpenElement(1, "span"); builder.AddAttribute(2, "class", GroupWrapperClass); builder.AddAttribute(3, "style", Style); builder.OpenElement(4, "span"); builder.AddAttribute(5, "class", $"{PrefixCls}-wrapper {PrefixCls}-group"); } if (AddOnBefore != null) { // addOnBefore builder.OpenElement(11, "span"); builder.AddAttribute(12, "class", $"{PrefixCls}-group-addon"); builder.AddContent(13, AddOnBefore); builder.CloseElement(); } if (Prefix != null || Suffix != null) { builder.OpenElement(21, "span"); builder.AddAttribute(22, "class", AffixWrapperClass); if (container == "input") { container = "affixWrapper"; builder.AddAttribute(23, "style", Style); } } if (Prefix != null) { // prefix builder.OpenElement(31, "span"); builder.AddAttribute(32, "class", $"{PrefixCls}-prefix"); builder.AddContent(33, Prefix); builder.CloseElement(); } // input builder.OpenElement(41, "input"); builder.AddAttribute(42, "class", ClassMapper.Class); if (container == "input") { builder.AddAttribute(43, "style", Style); } if (Attributes != null) { builder.AddMultipleAttributes(44, Attributes); } if (AdditionalAttributes != null) { builder.AddMultipleAttributes(45, AdditionalAttributes); } builder.AddAttribute(50, "Id", Id); builder.AddAttribute(51, "type", Type); builder.AddAttribute(60, "placeholder", Placeholder); builder.AddAttribute(61, "value", CurrentValue); // onchange 和 onblur 事件会导致点击 OnSearch 按钮时不触发 Click 事件,暂时取消这两个事件 if (!IgnoreOnChangeAndBlur) { builder.AddAttribute(62, "onchange", CallbackFactory.Create(this, OnChangeAsync)); builder.AddAttribute(65, "onblur", CallbackFactory.Create(this, OnBlurAsync)); } builder.AddAttribute(63, "onkeypress", CallbackFactory.Create(this, OnKeyPressAsync)); builder.AddAttribute(63, "onkeydown", CallbackFactory.Create(this, OnkeyDownAsync)); builder.AddAttribute(63, "onkeyup", CallbackFactory.Create(this, OnKeyUpAsync)); builder.AddAttribute(64, "oninput", CallbackFactory.Create(this, OnInputAsync)); builder.AddAttribute(66, "onfocus", CallbackFactory.Create(this, OnFocusAsync)); builder.AddAttribute(67, "onmouseup", CallbackFactory.Create(this, OnMouseUpAsync)); builder.AddElementReferenceCapture(68, r => Ref = r); builder.CloseElement(); if (Suffix != null) { // suffix builder.OpenElement(71, "span"); builder.AddAttribute(72, "class", $"{PrefixCls}-suffix"); builder.AddContent(73, Suffix); builder.CloseElement(); } if (Prefix != null || Suffix != null) { builder.CloseElement(); } if (AddOnAfter != null) { // addOnAfter builder.OpenElement(81, "span"); builder.AddAttribute(82, "class", $"{PrefixCls}-group-addon"); builder.AddContent(83, AddOnAfter); builder.CloseElement(); } if (AddOnBefore != null || AddOnAfter != null) { builder.CloseElement(); builder.CloseElement(); } } } } }