2020-09-09 00:52:14 +08:00
|
|
|
|
using System;
|
2021-05-27 18:13:26 +08:00
|
|
|
|
using System.Diagnostics;
|
2021-04-03 15:22:11 +08:00
|
|
|
|
using System.Globalization;
|
2021-03-01 22:50:22 +08:00
|
|
|
|
using System.Text.Json;
|
2020-03-23 09:31:08 +08:00
|
|
|
|
using System.Threading.Tasks;
|
2020-09-09 00:52:14 +08:00
|
|
|
|
using AntDesign.JsInterop;
|
|
|
|
|
using Microsoft.AspNetCore.Components;
|
2021-03-01 22:50:22 +08:00
|
|
|
|
using Microsoft.JSInterop;
|
2020-03-23 09:31:08 +08:00
|
|
|
|
|
2020-05-29 00:33:49 +08:00
|
|
|
|
namespace AntDesign
|
2020-03-23 09:31:08 +08:00
|
|
|
|
{
|
2020-06-27 01:20:52 +08:00
|
|
|
|
public partial class TextArea : Input<string>
|
2020-03-23 09:31:08 +08:00
|
|
|
|
{
|
2020-04-16 12:05:59 +08:00
|
|
|
|
private const uint DEFAULT_MIN_ROWS = 1;
|
2020-04-24 18:32:50 +08:00
|
|
|
|
|
2021-04-17 17:42:28 +08:00
|
|
|
|
protected override string InputType => "textarea";
|
|
|
|
|
|
2020-03-31 21:23:25 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// scrollHeight of 1 row
|
|
|
|
|
/// </summary>
|
|
|
|
|
private double _rowHeight;
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
2020-04-16 12:05:59 +08:00
|
|
|
|
/// total height = row * <see cref="_rowHeight" /> + <see cref="_offsetHeight" />
|
2020-03-31 21:23:25 +08:00
|
|
|
|
/// </summary>
|
|
|
|
|
private double _offsetHeight;
|
|
|
|
|
|
2021-03-01 22:50:22 +08:00
|
|
|
|
private uint _minRows = DEFAULT_MIN_ROWS;
|
|
|
|
|
private uint _maxRows = uint.MaxValue;
|
|
|
|
|
private bool _hasMinOrMaxSet;
|
|
|
|
|
private DotNetObjectReference<TextArea> _reference;
|
2020-03-23 09:31:08 +08:00
|
|
|
|
|
|
|
|
|
[Parameter]
|
2020-03-31 21:23:25 +08:00
|
|
|
|
public bool AutoSize { get; set; }
|
2020-03-23 09:31:08 +08:00
|
|
|
|
|
2021-05-27 18:13:26 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// When `false`, value will be set to `null` when content is empty
|
|
|
|
|
/// or whitespace. When `true`, value will be set to empty string.
|
|
|
|
|
/// </summary>
|
2021-04-03 15:22:11 +08:00
|
|
|
|
[Parameter]
|
|
|
|
|
public bool DefaultToEmptyString { get; set; }
|
2021-03-01 22:50:22 +08:00
|
|
|
|
|
2021-05-27 18:13:26 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// `TextArea` will allow growing, but it will stop when visible
|
|
|
|
|
/// rows = MaxRows (will not grow further).
|
|
|
|
|
/// Default value = uint.MaxValue
|
|
|
|
|
/// </summary>
|
2020-03-23 09:31:08 +08:00
|
|
|
|
[Parameter]
|
2021-05-27 18:13:26 +08:00
|
|
|
|
public uint MaxRows
|
2020-03-31 21:23:25 +08:00
|
|
|
|
{
|
|
|
|
|
get
|
|
|
|
|
{
|
2021-05-27 18:13:26 +08:00
|
|
|
|
return _maxRows;
|
2020-03-31 21:23:25 +08:00
|
|
|
|
}
|
|
|
|
|
set
|
|
|
|
|
{
|
2021-03-01 22:50:22 +08:00
|
|
|
|
_hasMinOrMaxSet = true;
|
2021-05-27 18:13:26 +08:00
|
|
|
|
if (value >= MinRows)
|
2020-03-31 21:23:25 +08:00
|
|
|
|
{
|
2021-05-27 18:13:26 +08:00
|
|
|
|
_maxRows = value;
|
2020-03-31 21:23:25 +08:00
|
|
|
|
AutoSize = true;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2021-05-27 18:13:26 +08:00
|
|
|
|
_maxRows = uint.MaxValue;
|
|
|
|
|
Debug.WriteLine($"Value of {nameof(MaxRows)}({MaxRows}) has to be between {nameof(MinRows)}({MinRows}) and {uint.MaxValue}");
|
2020-03-31 21:23:25 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-05-27 18:13:26 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// `TextArea` will allow shrinking, but it will stop when visible
|
|
|
|
|
/// rows = MinRows (will not shrink further).
|
|
|
|
|
/// Default value = DEFAULT_MIN_ROWS = 1
|
|
|
|
|
/// </summary>
|
2020-03-31 21:23:25 +08:00
|
|
|
|
[Parameter]
|
2021-05-27 18:13:26 +08:00
|
|
|
|
public uint MinRows
|
2020-03-31 21:23:25 +08:00
|
|
|
|
{
|
|
|
|
|
get
|
|
|
|
|
{
|
2021-05-27 18:13:26 +08:00
|
|
|
|
return _minRows;
|
2020-03-31 21:23:25 +08:00
|
|
|
|
}
|
|
|
|
|
set
|
|
|
|
|
{
|
2021-03-01 22:50:22 +08:00
|
|
|
|
_hasMinOrMaxSet = true;
|
2021-05-27 18:13:26 +08:00
|
|
|
|
if (value >= DEFAULT_MIN_ROWS && value <= MaxRows)
|
2020-03-31 21:23:25 +08:00
|
|
|
|
{
|
2021-05-27 18:13:26 +08:00
|
|
|
|
_minRows = value;
|
2020-03-31 21:23:25 +08:00
|
|
|
|
AutoSize = true;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2021-05-27 18:13:26 +08:00
|
|
|
|
_minRows = DEFAULT_MIN_ROWS;
|
|
|
|
|
Debug.WriteLine($"Value of {nameof(MinRows)}({MinRows}) has to be between {DEFAULT_MIN_ROWS} and {nameof(MaxRows)}({MaxRows})");
|
2020-03-31 21:23:25 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-05-27 18:13:26 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Callback when the size changes
|
|
|
|
|
/// </summary>
|
2020-03-31 21:23:25 +08:00
|
|
|
|
[Parameter]
|
2020-07-07 12:44:10 +08:00
|
|
|
|
public EventCallback<OnResizeEventArgs> OnResize { get; set; }
|
2020-03-23 09:31:08 +08:00
|
|
|
|
|
2021-05-27 18:13:26 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Show character counting.
|
|
|
|
|
/// </summary>
|
|
|
|
|
[Parameter]
|
|
|
|
|
public bool ShowCount
|
|
|
|
|
{
|
|
|
|
|
get => _showCount && MaxLength >= 0;
|
|
|
|
|
set => _showCount = value;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private bool _showCount;
|
|
|
|
|
|
2021-03-12 17:02:11 +08:00
|
|
|
|
private ClassMapper _warpperClassMapper = new ClassMapper();
|
|
|
|
|
|
|
|
|
|
protected override void OnInitialized()
|
|
|
|
|
{
|
|
|
|
|
base.OnInitialized();
|
|
|
|
|
|
|
|
|
|
_warpperClassMapper
|
|
|
|
|
.Get(() => $"{PrefixCls}-affix-wrapper")
|
|
|
|
|
.Get(() => $"{PrefixCls}-affix-wrapper-textarea-with-clear-btn")
|
|
|
|
|
.GetIf(() => $"{PrefixCls}-affix-wrapper-rtl", () => RTL);
|
|
|
|
|
}
|
|
|
|
|
|
2020-03-31 21:23:25 +08:00
|
|
|
|
protected async override Task OnFirstAfterRenderAsync()
|
|
|
|
|
{
|
|
|
|
|
await base.OnFirstAfterRenderAsync();
|
|
|
|
|
|
|
|
|
|
if (AutoSize)
|
|
|
|
|
{
|
2021-03-01 22:50:22 +08:00
|
|
|
|
DomEventService.AddEventListener("window", "beforeunload", Reloading, false);
|
|
|
|
|
|
2020-03-31 21:23:25 +08:00
|
|
|
|
await CalculateRowHeightAsync();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-04-03 15:22:11 +08:00
|
|
|
|
protected override bool TryParseValueFromString(string value, out string result, out string validationErrorMessage)
|
|
|
|
|
{
|
|
|
|
|
if (string.IsNullOrWhiteSpace(value))
|
|
|
|
|
{
|
|
|
|
|
if (DefaultToEmptyString)
|
|
|
|
|
result = string.Empty;
|
|
|
|
|
else
|
|
|
|
|
result = default;
|
|
|
|
|
validationErrorMessage = null;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var success = BindConverter.TryConvertTo<string>(
|
|
|
|
|
value, CultureInfo.CurrentCulture, out var parsedValue);
|
|
|
|
|
|
|
|
|
|
if (success)
|
|
|
|
|
{
|
|
|
|
|
result = parsedValue;
|
|
|
|
|
validationErrorMessage = null;
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
result = default;
|
|
|
|
|
validationErrorMessage = $"{FieldIdentifier.FieldName} field isn't valid.";
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-03-23 09:31:08 +08:00
|
|
|
|
|
2021-03-01 22:50:22 +08:00
|
|
|
|
protected override void Dispose(bool disposing)
|
|
|
|
|
{
|
|
|
|
|
if (AutoSize && !_isReloading)
|
2020-03-23 09:31:08 +08:00
|
|
|
|
{
|
2021-03-01 22:50:22 +08:00
|
|
|
|
_reference?.Dispose();
|
|
|
|
|
DomEventService.RemoveEventListerner<JsonElement>("window", "beforeunload", Reloading);
|
|
|
|
|
|
|
|
|
|
_ = InvokeAsync(async () =>
|
|
|
|
|
{
|
|
|
|
|
await JsInvokeAsync(JSInteropConstants.DisposeResizeTextArea, Ref);
|
|
|
|
|
});
|
2020-03-23 09:31:08 +08:00
|
|
|
|
}
|
2021-03-01 22:50:22 +08:00
|
|
|
|
|
|
|
|
|
base.Dispose(disposing);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
2021-03-12 17:02:11 +08:00
|
|
|
|
/// Indicates that a page is being refreshed
|
2021-03-01 22:50:22 +08:00
|
|
|
|
/// </summary>
|
|
|
|
|
private bool _isReloading;
|
2021-03-12 17:02:11 +08:00
|
|
|
|
|
2021-03-01 22:50:22 +08:00
|
|
|
|
private void Reloading(JsonElement jsonElement) => _isReloading = true;
|
|
|
|
|
|
|
|
|
|
[JSInvokable]
|
|
|
|
|
public void ChangeSizeAsyncJs(float width, float height)
|
|
|
|
|
{
|
2021-05-27 18:13:26 +08:00
|
|
|
|
if (OnResize.HasDelegate)
|
|
|
|
|
OnResize.InvokeAsync(new OnResizeEventArgs { Width = width, Height = height });
|
2020-03-23 09:31:08 +08:00
|
|
|
|
}
|
|
|
|
|
|
2021-03-01 22:50:22 +08:00
|
|
|
|
private async Task CalculateRowHeightAsync()
|
2020-03-23 09:31:08 +08:00
|
|
|
|
{
|
2021-03-01 22:50:22 +08:00
|
|
|
|
if (_reference == null)
|
|
|
|
|
{
|
|
|
|
|
_reference = DotNetObjectReference.Create<TextArea>(this);
|
|
|
|
|
}
|
|
|
|
|
var textAreaInfo = await JsInvokeAsync<TextAreaInfo>(JSInteropConstants.RegisterResizeTextArea, Ref, MinRows, MaxRows, _reference);
|
2020-03-31 21:23:25 +08:00
|
|
|
|
|
2021-03-12 17:02:11 +08:00
|
|
|
|
// var textAreaInfo = await JsInvokeAsync<TextAreaInfo>(JSInteropConstants.GetTextAreaInfo, Ref);
|
2021-03-01 22:50:22 +08:00
|
|
|
|
_rowHeight = textAreaInfo.LineHeight;
|
2021-03-12 17:02:11 +08:00
|
|
|
|
_offsetHeight = textAreaInfo.PaddingTop + textAreaInfo.PaddingBottom
|
2021-03-01 22:50:22 +08:00
|
|
|
|
+ textAreaInfo.BorderTop + textAreaInfo.BorderBottom;
|
2020-03-31 21:23:25 +08:00
|
|
|
|
|
2021-03-01 22:50:22 +08:00
|
|
|
|
uint rows = (uint)(textAreaInfo.ScrollHeight / _rowHeight);
|
|
|
|
|
if (_hasMinOrMaxSet)
|
|
|
|
|
rows = Math.Max((uint)MinRows, rows);
|
2020-07-07 12:44:10 +08:00
|
|
|
|
|
2021-03-01 22:50:22 +08:00
|
|
|
|
double height = 0;
|
2020-03-31 21:23:25 +08:00
|
|
|
|
if (rows > MaxRows)
|
|
|
|
|
{
|
|
|
|
|
rows = MaxRows;
|
2020-07-07 12:44:10 +08:00
|
|
|
|
|
2021-03-01 22:50:22 +08:00
|
|
|
|
height = rows * _rowHeight + _offsetHeight;
|
2020-07-07 12:44:10 +08:00
|
|
|
|
Style = $"height: {height}px;";
|
2020-03-31 21:23:25 +08:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2021-03-01 22:50:22 +08:00
|
|
|
|
height = rows * _rowHeight + _offsetHeight;
|
2020-07-07 12:44:10 +08:00
|
|
|
|
Style = $"height: {height}px;overflow-y: hidden;";
|
2020-03-31 21:23:25 +08:00
|
|
|
|
}
|
2020-03-23 09:31:08 +08:00
|
|
|
|
}
|
|
|
|
|
|
2021-03-01 22:50:22 +08:00
|
|
|
|
private class TextAreaInfo
|
2020-07-07 12:44:10 +08:00
|
|
|
|
{
|
2021-03-01 22:50:22 +08:00
|
|
|
|
public double ScrollHeight { get; set; }
|
|
|
|
|
public double LineHeight { get; set; }
|
|
|
|
|
public double PaddingTop { get; set; }
|
|
|
|
|
public double PaddingBottom { get; set; }
|
|
|
|
|
public double BorderTop { get; set; }
|
|
|
|
|
public double BorderBottom { get; set; }
|
2020-07-07 12:44:10 +08:00
|
|
|
|
}
|
2020-03-23 09:31:08 +08:00
|
|
|
|
}
|
2021-04-17 17:42:28 +08:00
|
|
|
|
}
|