ant-design-blazor/components/date-picker/DatePicker.Razor.cs

308 lines
9.8 KiB
C#
Raw Normal View History

using System;
using System.Threading.Tasks;
using AntDesign.Core.Extensions;
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Web;
using Microsoft.JSInterop;
namespace AntDesign
{
public partial class DatePicker<TValue> : DatePickerBase<TValue>
{
[Parameter]
public EventCallback<DateTimeChangedEventArgs> OnChange { get; set; }
private DateTime _pickerValuesAfterInit;
protected override void OnInitialized()
{
base.OnInitialized();
ProcessDefaults();
_pickerValuesAfterInit = PickerValues[0];
}
private void ProcessDefaults()
{
UseDefaultPickerValue[0] = true;
if (DefaultPickerValue.Equals(default(TValue)))
{
if ((IsNullable && Value != null) || (!IsNullable && !Value.Equals(default(TValue))))
{
DefaultPickerValue = Value;
}
else if ((IsNullable && DefaultValue != null) || (!IsNullable && !DefaultValue.Equals(default(TValue))))
{
DefaultPickerValue = DefaultValue;
if (!DefaultValue.Equals(Value))
{
CurrentValue = DefaultValue;
}
}
else if (!IsNullable && Value.Equals(default(TValue)))
{
DefaultPickerValue = Value;
}
else
{
UseDefaultPickerValue[0] = false;
}
}
if (UseDefaultPickerValue[0])
{
PickerValues[0] = Convert.ToDateTime(DefaultPickerValue, CultureInfo);
}
}
private async Task OnInputClick()
{
if (_duringManualInput)
{
return;
}
_openingOverlay = !_dropDown.IsOverlayShow();
AutoFocus = true;
//Reset Picker to default in case it the picker value was changed
//but no value was selected (for example when a user clicks next
//month but does not select any value)
if (UseDefaultPickerValue[0] && DefaultPickerValue != null)
{
PickerValues[0] = _pickerValuesAfterInit;
}
await _dropDown.Show();
// clear status
_pickerStatus[0]._currentShowHadSelectValue = false;
if (!_inputStart.IsOnFocused && _pickerStatus[0]._hadSelectValue && !UseDefaultPickerValue[0])
{
GetIfNotNull(Value, notNullValue =>
{
ChangePickerValue(notNullValue);
});
}
}
private TValue _cacheDuringInput;
protected void OnInput(ChangeEventArgs args, int index = 0)
{
if (index != 0)
{
throw new ArgumentOutOfRangeException("DatePicker should have only single picker.");
}
if (args == null)
{
return;
}
if (!_duringManualInput)
{
_duringManualInput = true;
_cacheDuringInput = Value;
}
if (FormatAnalyzer.TryPickerStringConvert(args.Value.ToString(), out TValue changeValue, IsNullable))
{
CurrentValue = changeValue;
GetIfNotNull(changeValue, (notNullValue) =>
{
PickerValues[0] = notNullValue;
});
StateHasChanged();
}
}
protected override async Task OnBlur(int index)
{
if (_openingOverlay)
return;
if (_duringManualInput)
{
if (!Value.Equals(_cacheDuringInput))
{
//reset picker to Value
CurrentValue = _cacheDuringInput;
_pickerStatus[0]._hadSelectValue = !(Value is null && (DefaultValue is not null || DefaultPickerValue is not null));
GetIfNotNull(Value ?? DefaultValue ?? DefaultPickerValue, (notNullValue) =>
{
PickerValues[0] = notNullValue;
});
}
_duringManualInput = false;
}
AutoFocus = false;
return;
}
/// <summary>
/// Method is called via EventCallBack if the keyboard key is no longer pressed inside the Input element.
/// </summary>
/// <param name="e">Contains the key (combination) which was pressed inside the Input element</param>
protected async Task OnKeyDown(KeyboardEventArgs e)
{
if (e == null) throw new ArgumentNullException(nameof(e));
var key = e.Key.ToUpperInvariant();
if (key == "ENTER" || key == "TAB" || key == "ESCAPE")
{
_duringManualInput = false;
if (string.IsNullOrWhiteSpace(_inputStart.Value))
ClearValue();
else
await TryApplyInputValue();
if (key == "ESCAPE" && _dropDown.IsOverlayShow())
{
Close();
await Js.FocusAsync(_inputStart.Ref);
return;
}
if (key == "ENTER")
{
//needed only in wasm, details: https://github.com/dotnet/aspnetcore/issues/30070
await Task.Yield();
await Js.InvokeVoidAsync(JSInteropConstants.InvokeTabKey);
}
Close();
AutoFocus = false;
return;
}
if (key == "ARROWDOWN" && !_dropDown.IsOverlayShow())
{
await _dropDown.Show();
return;
}
if (key == "ARROWUP" && _dropDown.IsOverlayShow())
{
Close();
return;
}
}
private async Task TryApplyInputValue()
{
if (FormatAnalyzer.TryPickerStringConvert(_inputStart.Value, out TValue changeValue, IsNullable))
{
CurrentValue = changeValue;
GetIfNotNull(changeValue, (notNullValue) =>
{
PickerValues[0] = notNullValue;
});
if (OnChange.HasDelegate)
{
await OnChange.InvokeAsync(new DateTimeChangedEventArgs
{
Date = Convert.ToDateTime(changeValue, this.CultureInfo),
DateString = GetInputValue(0)
});
}
}
}
/// <summary>
/// Get value of the picker
/// </summary>
/// <param name="index"></param>
/// <returns></returns>
public override DateTime? GetIndexValue(int index = 0)
{
if (index != 0)
{
throw new ArgumentOutOfRangeException("DatePicker should have only single picker.");
}
if (_pickerStatus[0]._hadSelectValue)
{
if (Value == null)
{
return null;
}
feat(module: date-picker): support localization (#803) * start trying to add a different first day of the week based on localization. * add first day of week parameter and get weekday local from .net * fix some issues * extend demo * remove no longed needed Locale parameter * fix range for selection * add german localization * add entry for API section * remove obsolet things from the react ant documentation * add description to chart documentation * translate general configuration to english. * code cleanup * use LocalProvider to get first day of week. * use localeprovider instead of date picker localization * remove no longer used parameter * delete no longer used interface * change from enum to string due to parsing issue. * add missing formats and use culture info from localprovider * correct locales * us Sunday as a default * remove no longer used culture info parameter * adjust locales * add parameter for Locale instead of directly accessing it. * add inheritance to access locale * typo * readd culture info parameter * fixes for locale jsons * adjust demo and api * small adjustments on docs, set monday in chinese as first day of the week. * use locale in calendar as well. * adjust docs * use enum * adjust demo * adjust for different starting date. * add defaults for DatePickerLocale * add short week days to locale files * use days from locale file * code cleanup use consts instead of magic numbers, add code comment and use dayOfWeek As param instead of the whole locale object. Remove no longed used method. * not sure about the chinese translation so I remove them * Revert "not sure about the chinese translation so I remove them" This reverts commit 54017513c7b684494cf06184b4051a4dcfc43850.
2020-11-25 11:08:12 +08:00
return Convert.ToDateTime(Value, CultureInfo);
}
else if (DefaultValue != null)
{
return Convert.ToDateTime(DefaultValue, CultureInfo);
}
return null;
}
public override void ChangeValue(DateTime value, int index = 0)
{
if (index != 0)
{
throw new ArgumentOutOfRangeException("DatePicker should have only single picker.");
}
UseDefaultPickerValue[0] = false;
bool result = BindConverter.TryConvertTo<TValue>(
value.ToString(CultureInfo), CultureInfo, out var dateTime);
if (result)
{
CurrentValue = dateTime;
}
_pickerStatus[0]._hadSelectValue = true;
if (!IsShowTime && Picker != DatePickerType.Time)
{
Close();
}
if (OnChange.HasDelegate)
{
OnChange.InvokeAsync(new DateTimeChangedEventArgs
{
Date = value,
DateString = GetInputValue(0)
});
}
}
protected override void OnValueChange(TValue value)
{
base.OnValueChange(value);
_pickerStatus[0]._hadSelectValue = true;
}
public override void ClearValue(int index = 0, bool closeDropdown = true)
{
_isSetPicker = false;
if (!IsNullable && DefaultValue != null)
CurrentValue = DefaultValue;
else
CurrentValue = default;
if (closeDropdown)
Close();
if (OnClearClick.HasDelegate)
OnClearClick.InvokeAsync(null);
}
private void GetIfNotNull(TValue value, Action<DateTime> notNullAction)
{
if (!IsNullable)
{
DateTime dateTime = Convert.ToDateTime(value, CultureInfo);
if (dateTime != DateTime.MinValue)
{
notNullAction?.Invoke(dateTime);
}
}
if (IsNullable && value != null)
{
notNullAction?.Invoke(Convert.ToDateTime(value, CultureInfo));
}
}
private void OverlayVisibleChange(bool visible)
{
OnOpenChange.InvokeAsync(visible);
_openingOverlay = false;
}
}
}