Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(module:datepicker): validate manually entered date against format #1389

Merged
Merged
Show file tree
Hide file tree
Changes from 22 commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
403e23c
fix(module:datepicker): validate manually entered date against format
anddrzejb Apr 19, 2021
a9d006c
Merge branch 'master' into datePickerManualEntryValidation
anddrzejb Apr 19, 2021
9a5b3d5
fix(module:datepicker): keep frozen the panel until valid date entered
anddrzejb Apr 20, 2021
f8f73c0
Merge branch 'master' into datePickerManualEntryValidation
anddrzejb Apr 20, 2021
ed5ba0a
fix(module:datepicker): switch to current culture format
anddrzejb Apr 20, 2021
a845ff2
fix(module:datepicker): build fix
anddrzejb Apr 20, 2021
b268394
fix(module:datepicker): use InvariantCulture when calling ToString on…
anddrzejb Apr 22, 2021
dd21191
fix(module:datepicker): FormatAnalyzer handles also year, week, month…
anddrzejb Apr 23, 2021
e0dca0e
Merge branch 'master' into datePickerManualEntryValidation
anddrzejb Apr 23, 2021
ec6f57c
fix(module:datepicker): FormatAnalyzer broken tests
anddrzejb Apr 23, 2021
c889ca0
fix: FormatAnalyzer handles prefixes in format.
anddrzejb Apr 24, 2021
45dc8cb
fix: all modes go through format analyzing (inluding week&quarter)
anddrzejb Apr 24, 2021
b8f88e0
fix(module:datepickerbase): InternalFormat initalized properly for al…
anddrzejb Apr 24, 2021
19834f2
fix(module:rangepicker): reset opposing date when in conflict with cu…
anddrzejb Apr 24, 2021
d9934b8
Merge branch 'master' into datePickerManualEntryValidation
anddrzejb Apr 24, 2021
db3b852
fix(module:rangePicker): handle null in second part of range
anddrzejb Apr 26, 2021
69322c1
fix(module:datepicker): switch from BindConverter to partials
anddrzejb Apr 26, 2021
38959b0
tests(module:datepicker): FormatAnalyzer new tests to cover switch fr…
anddrzejb Apr 26, 2021
56ca4ca
tests(module:datepicker): missed change in tests
anddrzejb Apr 26, 2021
22aafb9
fix: focus, key events, reset value to original if not confirmed
anddrzejb Apr 27, 2021
1eaf886
Merge branch 'master' into datePickerManualEntryValidation
anddrzejb Apr 27, 2021
916a840
fix: bug fix on range & clean-up
anddrzejb Apr 27, 2021
fdf2db3
Update DatePicker.razor
ElderJames Apr 28, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions components/core/JsInterop/JSInteropConstants.cs
Expand Up @@ -103,6 +103,7 @@ public static class JSInteropConstants
public static string SetDomAttribute => $"{FUNC_PREFIX}setDomAttribute";

public static string SetSelectionStart => $"{FUNC_PREFIX}setSelectionStart";
public static string InvokeTabKey => $"{FUNC_PREFIX}invokeTabKey";

#region Draggable Modal

Expand Down
18 changes: 18 additions & 0 deletions components/core/JsInterop/interop.ts
Expand Up @@ -692,3 +692,21 @@ export function setSelectionStart(element, position) {
}
}
}

//copied from https://www.telerik.com/forums/trigger-tab-key-when-enter-key-is-pressed
export function invokeTabKey() {
var currInput = document.activeElement;
if (currInput.tagName.toLowerCase() == "input") {
var inputs = document.getElementsByTagName("input");
var currInput = document.activeElement;
for (var i = 0; i < inputs.length; i++) {
if (inputs[i] == currInput) {
var next = inputs[i + 1];
if (next && next.focus) {
next.focus();
}
break;
}
}
}
}
95 changes: 68 additions & 27 deletions components/date-picker/DatePicker.Razor.cs
@@ -1,8 +1,8 @@
using System;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Web;
using Microsoft.JSInterop;

namespace AntDesign
{
Expand Down Expand Up @@ -51,6 +51,11 @@ private void ProcessDefaults()

private async Task OnInputClick()
{
if (_duringManualInput)
{
return;
}
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)
Expand All @@ -72,6 +77,8 @@ private async Task OnInputClick()
}
}

private TValue _cacheDuringInput;

protected void OnInput(ChangeEventArgs args, int index = 0)
{
if (index != 0)
Expand All @@ -82,55 +89,68 @@ protected void OnInput(ChangeEventArgs args, int index = 0)
{
return;
}

if (BindConverter.TryConvertTo(args.Value.ToString(), CultureInfo, out TValue changeValue))
if (!_duringManualInput)
{
if (Picker == DatePickerType.Date)
{
if (IsDateStringFullDate(args.Value.ToString()))
CurrentValue = changeValue;
}
else
CurrentValue = changeValue;

_duringManualInput = true;
_cacheDuringInput = Value;
}
if (FormatAnalyzer.TryPickerStringConvert(args.Value.ToString(), out TValue changeValue, IsNullable))
{
Value = changeValue;
GetIfNotNull(changeValue, (notNullValue) =>
{
PickerValues[0] = notNullValue;
});

if (OnChange.HasDelegate)
StateHasChanged();
}

UpdateCurrentValueAsString();
}

protected override Task OnBlur(int index)
{
if (_duringManualInput)
{
if (!Value.Equals(_cacheDuringInput))
{
OnChange.InvokeAsync(new DateTimeChangedEventArgs
//reset picker to Value
Value = _cacheDuringInput;
_pickerStatus[0]._hadSelectValue = !(Value is null && (DefaultValue is not null || DefaultPickerValue is not null));
GetIfNotNull(Value ?? DefaultValue ?? DefaultPickerValue, (notNullValue) =>
{
Date = Convert.ToDateTime(changeValue, this.CultureInfo),
DateString = GetInputValue(index)
PickerValues[0] = notNullValue;
});
}

StateHasChanged();
_duringManualInput = false;
}

UpdateCurrentValueAsString();
if (_dropDown.IsOverlayShow())
Close();
AutoFocus = false;
return Task.CompletedTask;
}

/// <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 OnKeyUp(KeyboardEventArgs e)
protected async Task OnKeyDown(KeyboardEventArgs e)
{
if (e == null) throw new ArgumentNullException(nameof(e));

var key = e.Key.ToUpperInvariant();
if (key == "ENTER")
if (key == "ENTER" || key == "TAB")
{
_duringManualInput = false;
if (string.IsNullOrWhiteSpace(_inputStart.Value))
ClearValue();
else
await TryApplyInputValue();

if (key == "ENTER")
{
if (BindConverter.TryConvertTo(_inputStart.Value, CultureInfo, out TValue changeValue))
Value = changeValue;
Close();
//needed only in wasm, details: https://github.com/dotnet/aspnetcore/issues/30070
await Task.Yield();
await Js.InvokeVoidAsync(JSInteropConstants.InvokeTabKey);
}
}

Expand All @@ -144,6 +164,26 @@ protected async Task OnKeyUp(KeyboardEventArgs e)
}
}

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>
Expand Down Expand Up @@ -219,15 +259,16 @@ protected override void OnValueChange(TValue value)
_pickerStatus[0]._hadSelectValue = true;
}

public override void ClearValue(int index = 0)
public override void ClearValue(int index = 0, bool closeDropdown = true)
{
_isSetPicker = false;

if (!IsNullable && DefaultValue != null)
CurrentValue = DefaultValue;
else
CurrentValue = default;
Close();
if (closeDropdown)
Close();
}

private void GetIfNotNull(TValue value, Action<DateTime> notNullAction)
Expand Down
8 changes: 5 additions & 3 deletions components/date-picker/DatePicker.razor
Expand Up @@ -9,7 +9,7 @@
IsButton="@true"
Disabled="Disabled"
PopupContainerSelector="@PopupContainerSelector"
OnVisibleChange="visible => { AutoFocus = visible; OnOpenChange.InvokeAsync(visible); }"
OnVisibleChange="visible => OnOpenChange.InvokeAsync(visible)"
OverlayEnterCls="ant-slide-up-enter ant-slide-up-enter-active ant-slide-up"
OverlayLeaveCls="ant-slide-up-leave ant-slide-up-leave-active ant-slide-up"
Trigger="new TriggerType[] { TriggerType.Click }">
Expand All @@ -33,9 +33,11 @@
Placeholder="@_placeholders[0]"
ReadOnly="@InputReadOnly"
AutoFocus="@AutoFocus"
OnClick="async e => { await OnInputClick(); }"
OnKeyUp="@OnKeyUp"
OnClick="async e => { await OnInputClick(); }"
OnKeyDown="@OnKeyDown"
OnInput="e => OnInput(e, 0)"
OnBlur="e => OnBlur(0)"
Onfocus="e => AutoFocus = true"
ShowTime="@(Picker == DatePickerType.Time)"
OnClickClear="e => ClearValue(0)"
AllowClear="@AllowClear" />
Expand Down
12 changes: 7 additions & 5 deletions components/date-picker/RangePicker.razor
Expand Up @@ -9,7 +9,7 @@
IsButton="@true"
Disabled="Disabled"
PopupContainerSelector="@PopupContainerSelector"
OnVisibleChange="visible => { AutoFocus = visible; OnOpenChange.InvokeAsync(visible); }"
OnVisibleChange="visible => OnOpenChange.InvokeAsync(visible)"
OverlayEnterCls="ant-slide-up-enter ant-slide-up-enter-active ant-slide-up ant-picker-dropdown-range"
OverlayLeaveCls="ant-slide-up-leave ant-slide-up-leave-active ant-slide-up ant-picker-dropdown-range"
Trigger="new TriggerType[] { TriggerType.Click }">
Expand Down Expand Up @@ -49,13 +49,14 @@
AutoFocus="@AutoFocus"
OnClick="async e => { await OnInputClick(0); }"
OnInput="e => OnInput(e, 0)"
OnKeyUp="e => OnKeyUp(e, 0)"
OnKeyDown="e => OnKeyDown(e, 0)"
Onfocus="() => OnFocus(0)"
OnBlur="e => OnBlur(0)"
ShowTime="@(Picker == DatePickerType.Time)"
ShowSuffixIcon="false"
IsRange="@IsRange"
AllowClear="@AllowClear"
OnClickClear="e => ClearValue(0)" />
OnClickClear="e => ClearValue(-1)" />

<div class="@(PrefixCls)-range-separator">
<span aria-label="to" class="@(PrefixCls)-separator">
Expand All @@ -73,12 +74,13 @@
AutoFocus="@AutoFocus"
OnClick="async e => { await OnInputClick(1); }"
OnInput="e => OnInput(e, 1)"
OnKeyUp="e => OnKeyUp(e, 1)"
OnKeyDown="e => OnKeyDown(e, 1)"
Onfocus="() => OnFocus(1)"
OnBlur="e => OnBlur(1)"
ShowTime="@(Picker == DatePickerType.Time)"
IsRange="@IsRange"
AllowClear="@AllowClear"
OnClickClear="e => ClearValue(0)" />
OnClickClear="e => ClearValue(-1)" />
<div class="@(PrefixCls)-active-bar" style="@_activeBarStyle"></div>
</div>
</Unbound>
Expand Down