@using System.ComponentModel.DataAnnotations @if (Visible) {
×
} @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.Default.Equals(value, _value)) { _value = value; } } } [Parameter] public EventCallback ValueChanged { get; set; } /// /// Html input element id attribute (Required) /// [Parameter, Required] public string? Id { get; set; } /// /// Html input element name attribute (Optional) /// [Parameter] public string? Name { get; set; } /// /// Control visibility of input /// [Parameter] public bool Visible { get; set; } = true; /// /// Disabled make input disabled. Meaning only showing value and picker popup won't open /// [Parameter] public bool Disabled { get; set; } /// /// Picker align relative to input /// [Parameter] public Align PickerAlign { get; set; } = Align.Right; /// /// Show calendar icon on input /// [Parameter] public bool ShowCalendarIcon { get; set; } = true; /// /// Calendar icon position relative to input /// [Parameter] public IconPosition CalendarIconPosition { get; set; } = IconPosition.BasedOnAlign; /// /// Can be used in changing vertical position of picker popup relative to input /// [Parameter] public double PickerOffsetTopPositionInPixels { get; set; } = 2; /// /// Initial value for input set on today /// [Parameter] public bool InitialValueSetOnToday { get; set; } /// /// Calendar type for date picker including Dual, Single, etc /// [Parameter] public Calendar CalendarType { get; set; } = Calendar.DualModeJalaliDefault; /// /// Control the digit type showing in input after selecting by picker /// [Parameter] public DigitType DigitType { get; set; } = DigitType.BasedOnCalendar; /// /// Format of date to show in input after selecting by picker /// [Parameter] public DateFormat DateFormat { get; set; } = DateFormat.yyyy_slash_MM_slash_dd; /// /// Prevent user select date before today /// [Parameter] public bool MinDateSetOnToday { get; set; } = true; [Parameter] public string? Placeholder { get; set; } /// /// Set datepicker readonly /// [Parameter] public bool ReadOnly { get; set; } = true; /// /// CSS class for input element /// [Parameter] public string? CssClass { get; set; } /// /// Inline styles for input element /// [Parameter] public string? Style { get; set; } /// /// Choose a theme for changing look and feel of picker /// [Parameter] public PickerTheme Theme { get; set; } = PickerTheme.Default; [Parameter] public Expression>? ValueExpression { get; set; } [Parameter] public EventCallback 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(); } }