Files
moadiran/Blazor.PersianDatePicker/InputPersianDatePicker.razor
mmrbnjd 3ca7f9deb0 ...
2024-05-16 23:40:32 +03:30

403 lines
11 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

@using System.ComponentModel.DataAnnotations
@if (Visible)
{
<div class="datepicker_wrapp" style="@Style">
<input id="@Id"
name="@Name"
readonly="@ReadOnly"
disabled="@Disabled"
class="@_internalCssClass @_iconCssClass @CssClass"
placeholder="@Placeholder"
autocomplete="off"
maxlength="10"
value="@Value"
init-value="@Value"
@onchange="@Change" />
<span class="@_clearBtnCssClass" @onclick="@Clear">×</span>
</div>
}
@code
{
#nullable enable
private string? _internalCssClass;
private string? _iconCssClass;
private string? _clearBtnCssClass;
public FieldIdentifier FieldIdentifier { get; private set; }
private string? _value;
private bool _isJalaliCurrentCalendarType;
[CascadingParameter]
public EditContext? EditContext { get; set; }
[Parameter]
public virtual string? Value
{
get => _value;
set
{
if (!EqualityComparer<string>.Default.Equals(value, _value))
{
_value = value;
}
}
}
[Parameter]
public EventCallback<string> ValueChanged { get; set; }
/// <summary>
/// Html input element id attribute (Required)
/// </summary>
[Parameter, Required]
public string? Id { get; set; }
/// <summary>
/// Html input element name attribute (Optional)
/// </summary>
[Parameter]
public string? Name { get; set; }
/// <summary>
/// Control visibility of input
/// </summary>
[Parameter]
public bool Visible { get; set; } = true;
/// <summary>
/// Disabled make input disabled. Meaning only showing value and picker popup won't open
/// </summary>
[Parameter]
public bool Disabled { get; set; }
/// <summary>
/// Picker align relative to input
/// </summary>
[Parameter]
public Align PickerAlign { get; set; } = Align.Right;
/// <summary>
/// Show calendar icon on input
/// </summary>
[Parameter]
public bool ShowCalendarIcon { get; set; } = true;
/// <summary>
/// Calendar icon position relative to input
/// </summary>
[Parameter]
public IconPosition CalendarIconPosition { get; set; } = IconPosition.BasedOnAlign;
/// <summary>
/// Can be used in changing vertical position of picker popup relative to input
/// </summary>
[Parameter]
public double PickerOffsetTopPositionInPixels { get; set; } = 2;
/// <summary>
/// Initial value for input set on today
/// </summary>
[Parameter]
public bool InitialValueSetOnToday { get; set; }
/// <summary>
/// Calendar type for date picker including Dual, Single, etc
/// </summary>
[Parameter]
public Calendar CalendarType { get; set; } = Calendar.DualModeJalaliDefault;
/// <summary>
/// Control the digit type showing in input after selecting by picker
/// </summary>
[Parameter]
public DigitType DigitType { get; set; } = DigitType.BasedOnCalendar;
/// <summary>
/// Format of date to show in input after selecting by picker
/// </summary>
[Parameter]
public DateFormat DateFormat { get; set; } = DateFormat.yyyy_slash_MM_slash_dd;
/// <summary>
/// Prevent user select date before today
/// </summary>
[Parameter]
public bool MinDateSetOnToday { get; set; } = true;
[Parameter]
public string? Placeholder { get; set; }
/// <summary>
/// Set datepicker readonly
/// </summary>
[Parameter]
public bool ReadOnly { get; set; } = true;
/// <summary>
/// CSS class for input element
/// </summary>
[Parameter]
public string? CssClass { get; set; }
/// <summary>
/// Inline styles for input element
/// </summary>
[Parameter]
public string? Style { get; set; }
/// <summary>
/// Choose a theme for changing look and feel of picker
/// </summary>
[Parameter]
public PickerTheme Theme { get; set; } = PickerTheme.Default;
[Parameter]
public Expression<Func<string>>? ValueExpression { get; set; }
[Parameter]
public EventCallback<string> OnChange { get; set; }
[Parameter]
public EventCallback OnClear { get; set; }
[Inject] private IJSRuntime? JsRuntime { get; set; }
protected override async Task OnInitializedAsync()
{
if (string.IsNullOrEmpty(Id))
Id = "id" + new Random().Next(1000, 9999);
if (CalendarType == Calendar.DualModeJalaliDefault || CalendarType == Calendar.SingleModeJalali)
_isJalaliCurrentCalendarType = true;
else
_isJalaliCurrentCalendarType = false;
if (!ShowCalendarIcon)
{
_iconCssClass = "";
_clearBtnCssClass = "clear-btn right";
}
else
{
if (CalendarIconPosition == IconPosition.Left)
{
_iconCssClass = "persian-datepicker-left-icon";
_clearBtnCssClass = "clear-btn right";
}
else if (CalendarIconPosition == IconPosition.Right)
{
_iconCssClass = "persian-datepicker-right-icon";
_clearBtnCssClass = "clear-btn left";
}
else
{
if (PickerAlign == Align.Right)
{
_iconCssClass = "persian-datepicker-left-icon";
_clearBtnCssClass = "clear-btn right";
}
else
{
_iconCssClass = "persian-datepicker-right-icon";
_clearBtnCssClass = "clear-btn left";
}
}
}
if (InitialValueSetOnToday)
{
var dt = DateTime.Now;
_value = _isJalaliCurrentCalendarType
? GetPersianDateFromGregorianDate(dt)
: dt.ToString(DateFormat.GetCSharpFormat());
ModifyValueDigit();
await OnValueChanged();
}
_internalCssClass = Disabled ? "datepicker-disabled" : "blazor-datepicker";
await base.OnInitializedAsync();
}
public override Task SetParametersAsync(ParameterView parameters)
{
var result = base.SetParametersAsync(parameters);
if (EditContext != null && ValueExpression != null && FieldIdentifier.Model != EditContext.Model)
{
FieldIdentifier = FieldIdentifier.Create(ValueExpression);
EditContext.OnValidationStateChanged += ValidationStateChanged;
}
return result;
}
private void ValidationStateChanged(object? sender, ValidationStateChangedEventArgs e)
{
StateHasChanged();
}
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
var calendarType = CalendarType == Calendar.SingleModeJalali || CalendarType == Calendar.DualModeJalaliDefault
? "persian"
: "gregorian";
bool enableSwitchCalendar = CalendarType == Calendar.DualModeJalaliDefault || CalendarType == Calendar.DualModeMiladiDefault;
bool? hasExplicitDigitType = DigitType != DigitType.BasedOnCalendar;
string digitType = "float";
if (DigitType == DigitType.Persian)
digitType = "fa";
else if (DigitType == DigitType.English)
digitType = "en";
var minDate = MinDateSetOnToday ? "today" : null;
await JsRuntime!.InvokeVoidAsync("blazorReady",
DotNetObjectReference.Create(this),
Id!,
calendarType,
enableSwitchCalendar,
hasExplicitDigitType,
digitType,
InitialValueSetOnToday,
DateFormat.ToEnumDisplayName()!,
minDate ?? string.Empty,
PickerAlign.ToString().ToLower(),
PickerOffsetTopPositionInPixels,
Theme.ToEnumDisplayName()!);
await base.OnAfterRenderAsync(true);
}
await base.OnAfterRenderAsync(false);
}
protected async Task Change(ChangeEventArgs args)
{
Value = $"{args.Value}";
await ValueChanged.InvokeAsync(Value);
EditContext?.NotifyFieldChanged(FieldIdentifier);
await OnChange.InvokeAsync(Value);
}
[JSInvokable]
public async Task SetDate(long? timestamp, string elementId, bool switchingCalendar = false)
{
if (elementId != Id)
return;
if (timestamp != null)
{
var dt = new DateTime(1970, 1, 1, 0, 0, 0, 0)
.AddSeconds(Math.Round((long)timestamp / 1000d)).ToLocalTime();
_value = _isJalaliCurrentCalendarType
? GetPersianDateFromGregorianDate(dt)
: dt.ToString(DateFormat.GetCSharpFormat());
}
if (switchingCalendar)
{
_isJalaliCurrentCalendarType = !_isJalaliCurrentCalendarType;
if (_isJalaliCurrentCalendarType)
{
// Change from en to fa: 2021/04/03 => 1400/05/02
var dt = Convert.ToDateTime(_value);
_value = GetPersianDateFromGregorianDate(dt);
}
else
{
// Change from fa to en: 1400/05/05 => 2021/01/05
// Convert to Miladi
if (_value != null)
{
DateTime dt = DateTime.Parse(_value, new CultureInfo("fa-IR"));
// Get Date
_value = dt.ToString(DateFormat.GetCSharpFormat());
}
}
}
ModifyValueDigit();
await OnValueChanged();
}
[JSInvokable]
public async Task SetToday(string elementId)
{
var dt = DateTime.Today;
_value = _isJalaliCurrentCalendarType
? GetPersianDateFromGregorianDate(dt)
: dt.ToString(DateFormat.GetCSharpFormat());
ModifyValueDigit();
await OnValueChanged();
}
private void ModifyValueDigit()
{
if (DigitType == DigitType.Persian)
_value = _value?.EnglishToPersianDigits();
else if (DigitType == DigitType.English)
_value = _value?.PersianToEnglishDigits();
else if (DigitType == DigitType.BasedOnCalendar)
_value = _isJalaliCurrentCalendarType ? _value?.EnglishToPersianDigits() : _value?.PersianToEnglishDigits();
}
private async Task OnValueChanged()
{
await ValueChanged.InvokeAsync(_value);
EditContext?.NotifyFieldChanged(FieldIdentifier);
await OnChange.InvokeAsync(Value);
}
private string GetPersianDateFromGregorianDate(DateTime dt)
{
PersianCalendar pc = new PersianCalendar();
return $"{pc.GetYear(dt):D2}{DateFormat.GetSeparator()}{pc.GetMonth(dt):D2}{DateFormat.GetSeparator()}{pc.GetDayOfMonth(dt):D2}";
}
private async Task Clear()
{
await ValueChanged.InvokeAsync(string.Empty);
EditContext?.NotifyFieldChanged(FieldIdentifier);
await OnClear.InvokeAsync();
}
}